fixed typo in documentation

fixed typo in documentation

V1.Backbone
===========

A simple backbone adapter for V1 queries.

Base Setup
----------

Establish and import some required global objects.

    V1 = if exports? then exports else this.V1 or (this.V1 = {})
    _ = if !this?._? then (if require? then require('underscore') else throw "Unable to load/find underscore") else this._
    Backbone = if !this?.Backbone? then (if require? then require('backbone') else throw "Unable to load/find backbone") else this.Backbone

Create a `property` helper bound to a specified property.

This returns a function which can be invoked with one or more objects.
It will loop through though arguments and return value from the first object
which has the desired property. A `defaultValue` can be specified if no matching
property can not be found.

The returned function also provides a `safe()` getter which will throw an
exception if value cannot be found -- rather than returning `defaultValue`.

The returned function also provides a `set()` function for setting the
underlying default value.

    createProperty = (property, defaultValue) ->
      getter = () ->
        for arg in arguments
          return arg[property] if arg?[property]?
        defaultValue

      _(getter).tap (getter) ->
        getter.safe = () ->
          val = getter.apply(this, arguments)
          throw "A "+property+" is required" unless val?
          val

        getter.set = (val) -> defaultValue = val

Create property getters for the `retriever` and the `persister`.

    defaultRetriever = createProperty("retriever")
    defaultPersister = createProperty("persister")

This is the default `sync` method for all `V1.Backbone` objects. This
method proxies most of its work into the configured `retriever` and
`persister`. Which are usually instances of `V1.Backbone.JsonRetiever` and
`V1.Backbone.RestPersister` respectively.

    sync = do ->
      methods = do ->
        syncToPersisterMethod = (method) ->
          (ctx, options) ->
            persister = defaultPersister.safe(this.queryOptions, options)

            xhr = persister[method](ctx, options)
              .fail(options.error)
              .done(options.success)

            ctx.trigger('request', ctx, xhr, options);
            xhr

        readFromRetriever = (model, options) ->
          retriever = defaultRetriever.safe(this.queryOptions, options)

          xhr = retriever.into(model, options)
            .done(options.success).fail(options.error)

          model.trigger('request', model, xhr, options);
          xhr

        read: readFromRetriever
        create: syncToPersisterMethod("send")
        update: syncToPersisterMethod("send")
        delete: syncToPersisterMethod("delete")

      (method, model, options) ->
        throw "Unsupported sync method: \"#{method}\"" unless methods[method]
        methods[method].call(this, model, options)

Helpers
-------

These are helper methods for determining types.

    isModel = (type) ->
      type::isV1 and (type is Backbone.Model or type.prototype instanceof Backbone.Model)

    isCollection = (type) ->
      type::isV1 and (type is Backbone.Collection or type.prototype instanceof Backbone.Collection)

    isAcceptable = (type) ->
      isModel(type) or isCollection(type)

A utility function to mix `V1.Backbone` functionality into an existing `Backbone.Model` or
`Backbone.Collection`. This can be useful for enviroments where the `V1.Backbone` dependancy
is not available at object construction time, you can use this to mix in the `V1.Backbone`
extensions at a later time.

    mixInTo = (cls) ->
      _(cls).tap (cls) ->
        cls::sync = sync
        cls::isV1 = true
        cls::idAttribute = "_oid" if cls::idAttribute?

Main
----

This is the main `V1.Backbone` namespace.

    V1.Backbone =

Set the *global* default retriever options.

      setDefaultRetriever: (options) ->
        defaultRetriever.set(new V1.Backbone.JsonRetriever(options))

Clear the *global* default retriever -- useful for test contexts.

      clearDefaultRetriever: -> defaultRetriever.set(undefined)

Set the *global* default persister options.

      setDefaultPersister: (options) ->
        defaultPersister.set(new V1.Backbone.RestPersister(options))

Clear the *global* default persister -- useful for test contexts.

      clearDefaultPersister: -> defaultPersister.set(undefined)

Begin a batch transaction. You can queue up multiple queries during one HTTP request
with this method.

> Note: Be sure to remember to wait for the deferred object to be
resolved before attempting to use the data.

      begin: (options) ->
        options = _.extend({}, defaultRetriever()?.options, options, {batch: true})
        new V1.Backbone.JsonRetriever(options)

Export the `mixInTo` helper.

      mixInTo: mixInTo

      Model: mixInTo Backbone.Model.extend()
      Collection: mixInTo Backbone.Collection.extend()

Retrieval
--------

    class V1.Backbone.JsonRetriever
      defaultOptions =
        fetch: () -> $.post.apply($, arguments)
        defer: () -> $.Deferred.apply($, arguments)

      validQueryOptions = ["find", "filter", "where", "with"]

      getQueryFor = (type, attribute) ->
        throw "Unsupported type" unless isAcceptable(type)

        protoModel = type.prototype if isModel(type)
        protoModel = type::model.prototype if isCollection(type)

        queryOptions = protoModel.queryOptions

        assetType = queryOptions.assetType or attribute

        query = from: if attribute then "#{attribute} as #{assetType}" else assetType
        addSelectTokens(queryOptions.schema, query)
        addFilterTokens(type, query)
        addFindInTokens(type, query)

        type.prototype.queryMucker?(query) if isCollection(type)

        query

      addRelation = (relation) ->
        subQuery = getQueryFor(relation.type, relation.attribute)
        _.extend(subQuery, _.pick(relation, validQueryOptions))

      safeConcat = (set, newArray) ->
          newArray = if _.isString(newArray) then [newArray] else newArray
          set = set.concat(newArray) if _.isArray(newArray) and newArray.length > 0
          set

      addFilterTokens = (type, query) ->
        filter = []
        filter = safeConcat(filter, type::queryOptions?.filter)
        filter = safeConcat(filter, type::model::queryOptions?.filter) if isCollection(type)

        query.filter = filter if filter.length > 0

      addFindInTokens = (type, query) ->
        findIn = []
        findIn = safeConcat(findIn, type::queryOptions?.findIn)

        query.findIn = findIn if findIn.length > 0

      addSelectTokens = (schema, query) ->
        return query.select = [schema] if _.isString(schema)
        return unless schema? and schema.length > 0
        query.select = _(schema).map (item) ->
          return addRelation(item) if item instanceof Relation
          return item.attribute if item instanceof Alias
          return item if _.isString(item)

      constructor: (options) ->
        throw "url required" unless options?.url?

        @options = _.extend({}, defaultOptions, options)

        @clear()

      for: (type) ->
        @batchInto(type, getQueryFor(type), @queries.length)
          .pipe (aliasedRows) -> new type(aliasedRows)

      fetch: (instance, options) ->
        options = _.extend({}, options, { retriever: this })
        instance.fetch(options)

      into: (instance, options) ->
        type = instance.constructor
        query = getQueryFor(type)

        _.extend(query, _.pick(options, validQueryOptions))

        instance.queryMucker?(query) if instance.queryMucker? and instance.queryMucker != type.prototype.queryMucker

        if isModel(type)
          throw "`id` is required" unless instance.id
          query.where = _.extend(query.where or {}, ID: instance.id)

        return @batchInto(type, query, @queries.length) if @options.batch

        data = JSON.stringify(query)

        xhr = @options.fetch(@options.url, data)

        deferred = xhr.pipe (data) -> prepareResultFor(data[0], type)
        deferred.abort = _.bind(xhr.abort, xhr) if xhr.abort? and !deferred.abort?

        deferred

      findOrCreateBatch: ->
        @currentBatch = @options.defer() unless @currentBatch?
        @currentBatch

      batchInto: (type, query, index) ->
        @queries[index] = query

        @findOrCreateBatch()
          .pipe((results) -> prepareResultFor(results[index], type))

      exec: ->
        return unless @currentBatch

        data = _(this.queries)
          .map((q) -> JSON.stringify(q))
          .join("\n---\n");

        @options.fetch(@options.url, data)
          .done(@resolveBatch)

      resolveBatch: (data) =>
        @currentBatch.resolve(data)
        @clear()

      clear: =>
        @queries = []
        @currentBatch = undefined

      prepareResultFor = (data, type) ->
        rows = aliasRows(data, type)
        return rows if isCollection(type)
        return rows[0] if isModel(type)

      aliasRows = (rows, type) ->
        schema = if isModel(type)
        then type::queryOptions?.schema
        else type::model::queryOptions?.schema

        schema = [schema] if _.isString(schema)

        _(rows).map (row) ->
          transformedRow = { "_oid": row["_oid"] }
          _(schema).each (item) ->
            if(_.isString(item))
              transformedRow[item] = row[item]
            else if(item instanceof Alias)
              if(item instanceof Relation)
                children = aliasRows(row[item.attribute], item.type)
                transformedRow[item.alias] = new item.type(children[0]) if item.isSingle() && children[0]?
                transformedRow[item.alias] = new item.type(children) if item.isMulti()
              else
                transformedRow[item.alias] = row[item.attribute]

          transformedRow

Persistance
-----------

    class V1.Backbone.RestPersister
      urlTmpl = _.template("<%= baseUrl %>/<%= assetType %><% if(typeof(id) != \"undefined\") { %>/<%= id %><% } %>")

      toAttribute = (attribute, value) ->
        "<Attribute name=\"#{_.escape(attribute)}\" act=\"set\">#{_.escape(value)}</Attribute>"

      toSingleRelation = (attribute, oid) ->
        "<Relation name=\"#{_.escape(attribute)}\" act=\"set\"><Asset idref=\"#{_.escape(oid)}\" /></Relation>"

      defaultOptions =
        post: (url, data) ->
          $.ajax
            type: "POST"
            url: url,
            data: data,
            dataType: "text"

        defer: () -> $.Deferred.apply($, arguments)

      url: (assetType, oid) =>
        oidParts = if oid? then oid.split(":") else []
        urlTmpl({baseUrl: @options.url, assetType: oidParts[0] or assetType, id: oidParts[1]})

      constructor: (options) ->
        throw "url required" unless options?.url?
        @options = _.extend({}, defaultOptions, options)

      delete: (ctx, options) ->
        throw "Unsupported context" unless isModel(ctx.constructor)
        options = options || {}
        attr = options.attrs || ctx.toJSON(options)
        @options.post(@url(ctx.queryOptions.assetType, ctx.id)+"?op=Delete")

      send: (ctx, options) ->
        send = if options.patch is yes then @sendPatch else @sendAll
        send.apply(this, arguments)

      sendPatch: (ctx, options) ->
        schema = _.indexBy ctx.queryOptions.schema, (val) ->
          if (val instanceof Alias) then val.alias else val

        toXml = (val, key) ->
          item = schema[key] || key
          return toSingleRelation(item.attribute, attr[item.alias].id) if item instanceof Relation and item.isSingle() and attr[item.alias]?
          return if item instanceof Relation
          return toAttribute(item.attribute, val) if item instanceof Alias
          return toAttribute(item, val) if _.isString(item)

        attrXml = _.map(ctx.changedAttributes(), toXml).join("")
        asset = "<Asset>#{attrXml}</Asset>"
        url = @url(ctx.queryOptions.assetType, ctx.id)
        @options.post(url, asset)

      sendAll: (ctx, options) ->
        throw "Unsupported context" unless isModel(ctx.constructor)
        options = options || {}
        attr = options.attrs || ctx.toJSON(options)

        toXml = (item) ->
          return toSingleRelation(item.attribute, attr[item.alias].id) if item instanceof Relation and item.isSingle() and attr[item.alias]?
          return if item instanceof Relation
          return toAttribute(item.attribute, attr[item.alias]) if item instanceof Alias
          return toAttribute(item, attr[item]) if _.isString(item)

        attrXml = _.map(ctx.queryOptions.schema, toXml).join("")

        asset = "<Asset>#{attrXml}</Asset>"
        url = @url(ctx.queryOptions.assetType, ctx.id)
        @options.post(url, asset)
          .done((data) -> ctx.id = result[1] if result = /id="(\w+:\d+):\d+"/.exec(data))

Relation Helpers
----------------

    aug = do ->
      fn = (target, action) ->
        Dup = ->
        Dup.prototype = target
        _(new Dup()).tap(action || ->)

      _(fn).tap (fn) ->
        fn.extend = (target, props) ->
          aug target, (augmentedResult) -> _.extend(augmentedResult, props)

        fn.add = (target, property, values) ->
          aug target, (augmentedResult) ->
            augmentedResult[property] = if _.isArray(target[property]) then target[property].concat(values) else values

        fn.merge = (target, props) ->
          aug target, (augmentedResult) ->
            _(props).each (val, key) -> target[key] = _.extend(val, target[key])

Alias Helper
------------

    class Alias
      constructor: (@attribute) ->
        @alias = @attribute

      as: (alias) ->
        aug.extend(this, {alias})

Export a simple constructor as `V1.Backbone.alias`

    V1.Backbone.alias = (attribute) -> new Alias(attribute)

Relation Helper
---------------

    class Relation extends Alias
      constructor: (@attribute) ->
        super(@attribute)
        @type = V1.Backbone.Collection

      isMulti: ->
        isCollection(@type)

      isSingle: ->
        isModel(@type)

      of: (type) ->
        throw "Unsupported type must be a V1.Backbone.Model or a V1.Backbone.Collection" unless isAcceptable(type)
        aug.extend(this, {type})

      addFilter: (filters...) ->
        aug.add(this, "filter", filters)

      addWhere: (where) ->
        aug.merge(this, {where})

      addWith: (newWith) ->
        aug.merge(this, {newWith})

Export a simple constructor as `V1.Backbone.relation`

    V1.Backbone.relation = (attribute) -> new Relation(attribute)

V1.Backbone
===========

A simple backbone adapter for V1 queries.

Base Setup
----------

Establish and import some required global objects.

    V1 = if exports? then exports else this.V1 or (this.V1 = {})
    _ = if !this?._? then (if require? then require('underscore') else throw "Unable to load/find underscore") else this._
    Backbone = if !this?.Backbone? then (if require? then require('backbone') else throw "Unable to load/find backbone") else this.Backbone

Create a `property` helper bound to a specified property.

This returns a function which can be invoked with one or more objects.
It will loop through though arguments and return value from the first object
which has the desired property. A `defaultValue` can be specified if no matching
property can not be found.

The returned function also provides a `safe()` getter which will throw an
exception if value cannot be found -- rather than returning `defaultValue`.

The returned function also provides a `set()` function for setting the
underlying default value.

    createProperty = (property, defaultValue) ->
      getter = () ->
        for arg in arguments
          return arg[property] if arg?[property]?
        defaultValue

      _(getter).tap (getter) ->
        getter.safe = () ->
          val = getter.apply(this, arguments)
          throw "A "+property+" is required" unless val?
          val

        getter.set = (val) -> defaultValue = val

Create property getters for the `retriever` and the `persister`.

    defaultRetriever = createProperty("retriever")
    defaultPersister = createProperty("persister")

This is the default `sync` method for all `V1.Backbone` objects. This
method proxies most of its work into the configured `retriever` and
`persister`. Which are usually instances of `V1.Backbone.JsonRetiever` and
`V1.Backbone.RestPersister` respectively.

    sync = do ->
      methods = do ->
        syncToPersisterMethod = (method) ->
          (ctx, options) ->
            persister = defaultPersister.safe(this.queryOptions, options)

            xhr = persister[method](ctx, options)
              .fail(options.error)
              .done(options.success)

            ctx.trigger('request', ctx, xhr, options);
            xhr

        readFromRetriever = (model, options) ->
          retriever = defaultRetriever.safe(this.queryOptions, options)

          xhr = retriever.into(model, options)
            .done(options.success).fail(options.error)

          model.trigger('request', model, xhr, options);
          xhr

        read: readFromRetriever
        create: syncToPersisterMethod("send")
        update: syncToPersisterMethod("send")
        delete: syncToPersisterMethod("delete")

      (method, model, options) ->
        throw "Unsupported sync method: \"#{method}\"" unless methods[method]
        methods[method].call(this, model, options)

Helpers
-------

These are helper methods for determining types.

    isModel = (type) ->
      type::isV1 and (type is Backbone.Model or type.prototype instanceof Backbone.Model)

    isCollection = (type) ->
      type::isV1 and (type is Backbone.Collection or type.prototype instanceof Backbone.Collection)

    isAcceptable = (type) ->
      isModel(type) or isCollection(type)

A utility function to mix `V1.Backbone` functionality into an existing `Backbone.Model` or
`Backbone.Collection`. This can be useful for enviroments where the `V1.Backbone` dependancy
is not available at object construction time, you can use this to mix in the `V1.Backbone`
extensions at a later time.

    mixInTo = (cls) ->
      _(cls).tap (cls) ->
        cls::sync = sync
        cls::isV1 = true
        cls::idAttribute = "_oid" if cls::idAttribute?

Main
----

This is the main `V1.Backbone` namespace.

    V1.Backbone =

Set the *global* default retriever options.

      setDefaultRetriever: (options) ->
        defaultRetriever.set(new V1.Backbone.JsonRetriever(options))

Clear the *global* default retriever -- useful for test contexts.

      clearDefaultRetriever: -> defaultRetriever.set(undefined)

Set the *global* default persister options.

      setDefaultPersister: (options) ->
        defaultPersister.set(new V1.Backbone.RestPersister(options))

Clear the *global* default persister -- useful for test contexts.

      clearDefaultPersister: -> defaultPersister.set(undefined)

Begin a batch transaction. You can queue up multiple queries during one HTTP request
with this method.

> Note: Be sure to remember to wait for the deferred object to be
resolved before attempting to use the data.

      begin: (options) ->
        options = _.extend({}, defaultRetriever()?.options, options, {batch: true})
        new V1.Backbone.JsonRetriever(options)

Export the `mixInTo` helper.

      mixInTo: mixInTo

      Model: mixInTo Backbone.Model.extend()
      Collection: mixInTo Backbone.Collection.extend()

Retrival
--------

    class V1.Backbone.JsonRetriever
      defaultOptions =
        fetch: () -> $.post.apply($, arguments)
        defer: () -> $.Deferred.apply($, arguments)

      validQueryOptions = ["find", "filter", "where", "with"]

      getQueryFor = (type, attribute) ->
        throw "Unsupported type" unless isAcceptable(type)

        protoModel = type.prototype if isModel(type)
        protoModel = type::model.prototype if isCollection(type)

        queryOptions = protoModel.queryOptions

        assetType = queryOptions.assetType or attribute

        query = from: if attribute then "#{attribute} as #{assetType}" else assetType
        addSelectTokens(queryOptions.schema, query)
        addFilterTokens(type, query)
        addFindInTokens(type, query)

        type.prototype.queryMucker?(query) if isCollection(type)

        query

      addRelation = (relation) ->
        subQuery = getQueryFor(relation.type, relation.attribute)
        _.extend(subQuery, _.pick(relation, validQueryOptions))

      safeConcat = (set, newArray) ->
          newArray = if _.isString(newArray) then [newArray] else newArray
          set = set.concat(newArray) if _.isArray(newArray) and newArray.length > 0
          set

      addFilterTokens = (type, query) ->
        filter = []
        filter = safeConcat(filter, type::queryOptions?.filter)
        filter = safeConcat(filter, type::model::queryOptions?.filter) if isCollection(type)

        query.filter = filter if filter.length > 0

      addFindInTokens = (type, query) ->
        findIn = []
        findIn = safeConcat(findIn, type::queryOptions?.findIn)

        query.findIn = findIn if findIn.length > 0

      addSelectTokens = (schema, query) ->
        return query.select = [schema] if _.isString(schema)
        return unless schema? and schema.length > 0
        query.select = _(schema).map (item) ->
          return addRelation(item) if item instanceof Relation
          return item.attribute if item instanceof Alias
          return item if _.isString(item)

      constructor: (options) ->
        throw "url required" unless options?.url?

        @options = _.extend({}, defaultOptions, options)

        @clear()

      for: (type) ->
        @batchInto(type, getQueryFor(type), @queries.length)
          .pipe (aliasedRows) -> new type(aliasedRows)

      fetch: (instance, options) ->
        options = _.extend({}, options, { retriever: this })
        instance.fetch(options)

      into: (instance, options) ->
        type = instance.constructor
        query = getQueryFor(type)

        _.extend(query, _.pick(options, validQueryOptions))

        instance.queryMucker?(query) if instance.queryMucker? and instance.queryMucker != type.prototype.queryMucker

        if isModel(type)
          throw "`id` is required" unless instance.id
          query.where = _.extend(query.where or {}, ID: instance.id)

        return @batchInto(type, query, @queries.length) if @options.batch

        data = JSON.stringify(query)

        xhr = @options.fetch(@options.url, data)

        deferred = xhr.pipe (data) -> prepareResultFor(data[0], type)
        deferred.abort = _.bind(xhr.abort, xhr) if xhr.abort? and !deferred.abort?

        deferred

      findOrCreateBatch: ->
        @currentBatch = @options.defer() unless @currentBatch?
        @currentBatch

      batchInto: (type, query, index) ->
        @queries[index] = query

        @findOrCreateBatch()
          .pipe((results) -> prepareResultFor(results[index], type))

      exec: ->
        return unless @currentBatch

        data = _(this.queries)
          .map((q) -> JSON.stringify(q))
          .join("\n---\n");

        @options.fetch(@options.url, data)
          .done(@resolveBatch)

      resolveBatch: (data) =>
        @currentBatch.resolve(data)
        @clear()

      clear: =>
        @queries = []
        @currentBatch = undefined

      prepareResultFor = (data, type) ->
        rows = aliasRows(data, type)
        return rows if isCollection(type)
        return rows[0] if isModel(type)

      aliasRows = (rows, type) ->
        schema = if isModel(type)
        then type::queryOptions?.schema
        else type::model::queryOptions?.schema

        schema = [schema] if _.isString(schema)

        _(rows).map (row) ->
          transformedRow = { "_oid": row["_oid"] }
          _(schema).each (item) ->
            if(_.isString(item))
              transformedRow[item] = row[item]
            else if(item instanceof Alias)
              if(item instanceof Relation)
                children = aliasRows(row[item.attribute], item.type)
                transformedRow[item.alias] = new item.type(children[0]) if item.isSingle() && children[0]?
                transformedRow[item.alias] = new item.type(children) if item.isMulti()
              else
                transformedRow[item.alias] = row[item.attribute]

          transformedRow

Persistance
-----------

    class V1.Backbone.RestPersister
      urlTmpl = _.template("<%= baseUrl %>/<%= assetType %><% if(typeof(id) != \"undefined\") { %>/<%= id %><% } %>")

      toAttribute = (attribute, value) ->
        "<Attribute name=\"#{_.escape(attribute)}\" act=\"set\">#{_.escape(value)}</Attribute>"

      toSingleRelation = (attribute, oid) ->
        "<Relation name=\"#{_.escape(attribute)}\" act=\"set\"><Asset idref=\"#{_.escape(oid)}\" /></Relation>"

      defaultOptions =
        post: (url, data) ->
          $.ajax
            type: "POST"
            url: url,
            data: data,
            dataType: "text"

        defer: () -> $.Deferred.apply($, arguments)

      url: (assetType, oid) =>
        oidParts = if oid? then oid.split(":") else []
        urlTmpl({baseUrl: @options.url, assetType: oidParts[0] or assetType, id: oidParts[1]})

      constructor: (options) ->
        throw "url required" unless options?.url?
        @options = _.extend({}, defaultOptions, options)

      delete: (ctx, options) ->
        throw "Unsupported context" unless isModel(ctx.constructor)
        options = options || {}
        attr = options.attrs || ctx.toJSON(options)
        @options.post(@url(ctx.queryOptions.assetType, ctx.id)+"?op=Delete")

      send: (ctx, options) ->
        send = if options.patch is yes then @sendPatch else @sendAll
        send.apply(this, arguments)

      sendPatch: (ctx, options) ->
        schema = _.indexBy ctx.queryOptions.schema, (val) ->
          if (val instanceof Alias) then val.alias else val

        toXml = (val, key) ->
          item = schema[key] || key
          return toSingleRelation(item.attribute, attr[item.alias].id) if item instanceof Relation and item.isSingle() and attr[item.alias]?
          return if item instanceof Relation
          return toAttribute(item.attribute, val) if item instanceof Alias
          return toAttribute(item, val) if _.isString(item)

        attrXml = _.map(ctx.changedAttributes(), toXml).join("")
        asset = "<Asset>#{attrXml}</Asset>"
        url = @url(ctx.queryOptions.assetType, ctx.id)
        @options.post(url, asset)

      sendAll: (ctx, options) ->
        throw "Unsupported context" unless isModel(ctx.constructor)
        options = options || {}
        attr = options.attrs || ctx.toJSON(options)

        toXml = (item) ->
          return toSingleRelation(item.attribute, attr[item.alias].id) if item instanceof Relation and item.isSingle() and attr[item.alias]?
          return if item instanceof Relation
          return toAttribute(item.attribute, attr[item.alias]) if item instanceof Alias
          return toAttribute(item, attr[item]) if _.isString(item)

        attrXml = _.map(ctx.queryOptions.schema, toXml).join("")

        asset = "<Asset>#{attrXml}</Asset>"
        url = @url(ctx.queryOptions.assetType, ctx.id)
        @options.post(url, asset)
          .done((data) -> ctx.id = result[1] if result = /id="(\w+:\d+):\d+"/.exec(data))

Relation Helpers
----------------

    aug = do ->
      fn = (target, action) ->
        Dup = ->
        Dup.prototype = target
        _(new Dup()).tap(action || ->)

      _(fn).tap (fn) ->
        fn.extend = (target, props) ->
          aug target, (augmentedResult) -> _.extend(augmentedResult, props)

        fn.add = (target, property, values) ->
          aug target, (augmentedResult) ->
            augmentedResult[property] = if _.isArray(target[property]) then target[property].concat(values) else values

        fn.merge = (target, props) ->
          aug target, (augmentedResult) ->
            _(props).each (val, key) -> target[key] = _.extend(val, target[key])

Alias Helper
------------

    class Alias
      constructor: (@attribute) ->
        @alias = @attribute

      as: (alias) ->
        aug.extend(this, {alias})

Export a simple constructor as `V1.Backbone.alias`

    V1.Backbone.alias = (attribute) -> new Alias(attribute)

Relation Helper
---------------

    class Relation extends Alias
      constructor: (@attribute) ->
        super(@attribute)
        @type = V1.Backbone.Collection

      isMulti: ->
        isCollection(@type)

      isSingle: ->
        isModel(@type)

      of: (type) ->
        throw "Unsupported type must be a V1.Backbone.Model or a V1.Backbone.Collection" unless isAcceptable(type)
        aug.extend(this, {type})

      addFilter: (filters...) ->
        aug.add(this, "filter", filters)

      addWhere: (where) ->
        aug.merge(this, {where})

      addWith: (newWith) ->
        aug.merge(this, {newWith})

Export a simple constructor as `V1.Backbone.relation`

    V1.Backbone.relation = (attribute) -> new Relation(attribute)


fix issue with method (rpc/action) binding called as an object property, see yang-swagger issue #5

# Method - controller of functions

## Class Method

    Property = require('./property')

    class Method extends Property
      logger: require('debug')('yang:method')

      @property 'data',
        set: (value) -> @set value, { force: true }
        get: -> switch
          when @binding? then @do.bind this
          else @value

### do ()

A convenience wrap to a Property instance that holds a function to
perform a Promise-based execution.

Always returns a Promise.

      do: (input={}, opts={}) ->
        unless (@binding instanceof Function) or (@data instanceof Function)
          return Promise.reject @error "cannot perform action on a property without function"
        @debug "[do] executing method: #{@name}"
        @debug input
        ctx = @parent?.context ? @context
        ctx = ctx.with opts, path: @path
        try
          # calling context is the parent node of the method
          input = @schema.input.apply input, this, force: true

          # first apply schema bound function (if availble), otherwise
          # execute assigned function (if available and not 'missing')
          if @binding?
            @debug "[do] calling bound function with: #{Object.keys(input)}" if typeof input is 'object'
            @debug @binding.toString()
            output = @binding? ctx, input
          else
            @debug "[do] calling assigned function: #{@data.name}"
            @debug => @value
            @debug => @data
            output = @data.call @parent.data, input, ctx

          output = await output
          { output } = @schema.output.eval { output }, this, force: true
          return output
        catch e
          @debug e
          return Promise.reject(e)

      update: (value, opts) ->
        super value, opts unless value instanceof Property

### toJSON

This call always returns undefined for the Method node.

      toJSON: (key) ->
        value = undefined
        value = "#{@name}": value if key is true
        return value

    module.exports = Method

# Method - controller of functions

## Class Method

    Property = require('./property')

    class Method extends Property
      logger: require('debug')('yang:method')

      get: (pattern) -> switch
        when pattern? then super arguments...
        when @binding? then @do.bind this
        else @data

### do ()

A convenience wrap to a Property instance that holds a function to
perform a Promise-based execution.

Always returns a Promise.

      do: (input={}, opts={}) ->
        unless (@binding instanceof Function) or (@data instanceof Function)
          return Promise.reject @error "cannot perform action on a property without function"
        @debug "[do] executing method: #{@name}"
        @debug input
        ctx = @parent?.context ? @context
        ctx = ctx.with opts, path: @path
        try
          # calling context is the parent node of the method
          input = @schema.input.apply input, this, force: true

          # first apply schema bound function (if availble), otherwise
          # execute assigned function (if available and not 'missing')
          if @binding?
            @debug "[do] calling bound function with: #{Object.keys(input)}" if typeof input is 'object'
            @debug @binding.toString()
            output = @binding? ctx, input
          else
            @debug "[do] calling assigned function: #{@data.name}"
            @debug => @value
            @debug => @data
            output = @data.call @parent.data, input, ctx

          output = await output
          { output } = @schema.output.eval { output }, this, force: true
          return output
        catch e
          @debug e
          return Promise.reject(e)

      update: (value, opts) ->
        super value, opts unless value instanceof Property

### toJSON

This call always returns undefined for the Method node.

      toJSON: (key) ->
        value = undefined
        value = "#{@name}": value if key is true
        return value

    module.exports = Method


Fix for unexpected errors with app.cookies

# App

    'use strict'

    utils = require 'src/utils'
    log = require 'src/log'
    signal = require 'src/signal'
    db = require 'src/db'
    assert = require 'src/assert'
    Schema = require 'src/schema'
    Networking = require 'src/networking'
    Document = require 'src/document'
    Renderer = require 'src/renderer'
    Styles = require 'src/styles'
    Resources = require 'src/resources'
    Dict = require 'src/dict'

    AppRoute = require './route'

    if utils.isNode
        bootstrapRoute = require './bootstrap/route.node'

    `//<development>`
    pkg = require 'package.json'
    `//</development>`

    BASE_FILE_NAME_RE = /(.+)\.(?:node|server|client|browser|ios|android|native)/
    DEFAULT_CONFIG =
        title: 'Neft.io Application'
        protocol: 'http'
        port: 3000
        host: 'localhost'
        language: 'en'
        type: 'app'

    exports = module.exports = (opts = {}, extraOpts = {}) ->
        # Welcome log also for release mode
        log.ok "Welcome! Neft.io v#{pkg.version}; Feedback appreciated"

        `//<development>`
        log.warn "Use this bundle only in development; type --release when it's ready"
        `//</development>`

        config = utils.clone DEFAULT_CONFIG
        config = utils.mergeAll config, opts.config, extraOpts

        app = new Dict

## *Object* app.config = `{}`

Config object from the *package.json* file.

Can be overriden in the *init.js* file.

### type

The `app` type (the default one) uses renderer on the client side.

The `game` type uses special renderer (if exists) focused on more performance goals.

The `text` type always return HTML document with no renderer on the client side.
It's used for the crawlers (e.g. GoogleBot) or browsers with no javascript support.

```javascript
// package.json
{
    "name": "neft.io app",
    "version": "0.1.0",
    "config": {
        "title": "My first application!",
        "protocol": "http",
        "port": 3000,
        "host": "localhost",
        "language": "en",
        "type": "app"
    }
}
// init.js
module.exports = function(NeftApp) {
    var app = NeftApp({ title: "Overridden title" });
    console.log(app.config);
    // {title: "My first application!", protocol: "http", port: ....}
};
```

        app.config = config

## *Networking* app.networking

Standard Networking instance used to communicate
with the server and to create local requests.

All routes created by the *App.Route* uses this networking.

HTTP protocol is used by default with the data specified in the *package.json*.

        app.networking = new Networking
            type: Networking.HTTP
            protocol: config.protocol
            port: parseInt(config.port, 10)
            host: config.host
            url: config.url
            language: config.language

## *Object* app.models = `{}`

Files from the *models* folder with objects returned by their exported functions.

```javascript
// models/user/permission.js
module.exports = function(app) {
    return {
        getPermission: function(id){}
    };
};
// controllers/user.js
module.exports = function(app) {
    return {
        get: function(req, res, callback) {
            var data = app.models['user/permission'].getPermission(req.params.userId);
            callback(null, data);
        }
    }
};
```

        app.models = {}

## *Object* app.routes = `{}`

Files from the *routes* folder with objects returned by their exported functions.

        app.routes = {}

## *Object* app.styles = `{}`

Files from the *styles* folder as *Function*s
ready to create new *Item*s.

        app.styles = {}

## *Object* app.views = `{}`

Files from the *views* folder as the *Document* instances.

        app.views = {}

## *Resources* app.resources

        app.resources = do ->
            if opts.resources
                Resources.fromJSON(opts.resources)
            else
                new Resources

## *Signal* app.onReady()

Called when all modules, views, styled etc. have been loaded.

        signal.create app, 'onReady'

        # config.type
        config.type ?= 'app'
        assert.ok utils.has(['app', 'game', 'text'], config.type), "Unexpected app.config.type value. Accepted app/game/text, but '#{config.type}' got."

        app.Route = AppRoute app

## *Dict* app.cookies

On the client side, this object refers to the last received cookies
from the networking request.

On the server side, this cookies object are added into the each networking response.

By default, client has *clientId* and *sessionId* hashes.

```javascript
app.cookies.onChange(function(key){
    console.log('cookie changed', key, this[key]);
});
```

```xml
<h1>Your clientId</h1>
<em>${context.app.cookies.clientId}</em>
```

        # cookies
        COOKIES_KEY = '__neft_cookies'
        app.cookies = Dict()
        onCookiesReady = (dict) ->
            app.cookies = dict
            if utils.isClient
                dict.set 'sessionId', utils.uid(16)
        db.get COOKIES_KEY, db.OBSERVABLE, (err, dict) ->
            if dict
                onCookiesReady dict
            else
                if utils.isClient
                    cookies = {clientId: utils.uid(16)}
                else
                    cookies = {}
                db.set COOKIES_KEY, cookies, (err) ->
                    db.get COOKIES_KEY, db.OBSERVABLE, (err, dict) ->
                        if dict
                            onCookiesReady dict
        app.networking.onRequest (req, res) ->
            if utils.isClient
                utils.merge req.cookies, app.cookies
            else
                utils.merge res.cookies, app.cookies
            req.onLoadEnd.listeners.unshift ->
                if utils.isClient
                    for key, val of res.cookies
                        unless utils.isEqual(app.cookies[key], val)
                            app.cookies.set key, val
                return
            , null
            return

        # propagate data
        Renderer.resources = app.resources
        Renderer.serverUrl = app.networking.url
        Renderer.onLinkUri (uri) ->
            app.networking.createLocalRequest
                method: Networking.Request.GET
                type: Networking.Request.HTML_TYPE
                uri: uri
        Document.Scripts.scripts = utils.arrayToObject opts.scripts,
            (index, elem) -> elem.name,
            (index, elem) -> elem.file

        # set styles window item
        if opts.styles?
            for style in opts.styles
                if style.name in ['view', '__view__']
                    style.file._init app: app, view: null
                    windowStyle = style.file._main.getComponent()
                    break

        windowStyleItem = windowStyle?.item
        assert.ok windowStyleItem, '__view__ style must be defined'
        Renderer.window = windowStyleItem

        if opts.styles?
            stylesInitObject =
                app: app
                view: windowStyleItem

            # initialize styles
            for style in opts.styles when style.name?
                if style.name isnt 'view'
                    style.file._init stylesInitObject
                app.styles[style.name] = style.file

        # load styles
        Styles
            windowStyle: windowStyle
            styles: app.styles
            queries: opts.styleQueries
            resources: app.resources

        # load bootstrap
        if utils.isNode
            bootstrapRoute app

        # loading files helper
        init = (files, target) ->
            for file in files when file.name?
                if typeof file.file isnt 'function'
                    continue

                fileObj = file.file app
                target[file.name] = fileObj

                if baseNameMatch = BASE_FILE_NAME_RE.exec(file.name)
                    [_, baseName] = baseNameMatch
                    if target[baseName]?
                        if utils.isPlainObject(target[baseName]) and utils.isPlainObject(fileObj)
                            fileObj = utils.merge Object.create(target[baseName]), fileObj
                    target[baseName] = fileObj

            return

        # load app extensions
        if utils.isObject(opts.extensions)
            for ext in opts.extensions
                ext app

        # exports app classes
        exports.app =
            Route: app.Route

        # load views
        for view in opts.views when view.name?
            app.views[view.name] = Document.fromJSON view.file

        # load files
        init opts.models, app.models
        init opts.routes, app.routes

        for path, obj of app.routes
            r = {}
            if utils.isObject(obj) and not (obj instanceof app.Route)
                for method, opts of obj
                    if utils.isObject(opts)
                        route = new app.Route method, opts
                        r[route.name] = route
                    else
                        r[method] = opts
            app.routes[path] = r

        # provide default index route
        unless app.routes.index
            app.routes.index = new app.Route 'get /', {}

        # emit ready signal
        app.onReady.emit()

        app

# App

    'use strict'

    utils = require 'src/utils'
    log = require 'src/log'
    signal = require 'src/signal'
    db = require 'src/db'
    assert = require 'src/assert'
    Schema = require 'src/schema'
    Networking = require 'src/networking'
    Document = require 'src/document'
    Renderer = require 'src/renderer'
    Styles = require 'src/styles'
    Resources = require 'src/resources'
    Dict = require 'src/dict'

    AppRoute = require './route'

    if utils.isNode
        bootstrapRoute = require './bootstrap/route.node'

    `//<development>`
    pkg = require 'package.json'
    `//</development>`

    BASE_FILE_NAME_RE = /(.+)\.(?:node|server|client|browser|ios|android|native)/
    DEFAULT_CONFIG =
        title: 'Neft.io Application'
        protocol: 'http'
        port: 3000
        host: 'localhost'
        language: 'en'
        type: 'app'

    exports = module.exports = (opts = {}, extraOpts = {}) ->
        # Welcome log also for release mode
        log.ok "Welcome! Neft.io v#{pkg.version}; Feedback appreciated"

        `//<development>`
        log.warn "Use this bundle only in development; type --release when it's ready"
        `//</development>`

        config = utils.clone DEFAULT_CONFIG
        config = utils.mergeAll config, opts.config, extraOpts

        app = new Dict

## *Object* app.config = `{}`

Config object from the *package.json* file.

Can be overriden in the *init.js* file.

### type

The `app` type (the default one) uses renderer on the client side.

The `game` type uses special renderer (if exists) focused on more performance goals.

The `text` type always return HTML document with no renderer on the client side.
It's used for the crawlers (e.g. GoogleBot) or browsers with no javascript support.

```javascript
// package.json
{
    "name": "neft.io app",
    "version": "0.1.0",
    "config": {
        "title": "My first application!",
        "protocol": "http",
        "port": 3000,
        "host": "localhost",
        "language": "en",
        "type": "app"
    }
}
// init.js
module.exports = function(NeftApp) {
    var app = NeftApp({ title: "Overridden title" });
    console.log(app.config);
    // {title: "My first application!", protocol: "http", port: ....}
};
```

        app.config = config

## *Networking* app.networking

Standard Networking instance used to communicate
with the server and to create local requests.

All routes created by the *App.Route* uses this networking.

HTTP protocol is used by default with the data specified in the *package.json*.

        app.networking = new Networking
            type: Networking.HTTP
            protocol: config.protocol
            port: parseInt(config.port, 10)
            host: config.host
            url: config.url
            language: config.language

## *Object* app.models = `{}`

Files from the *models* folder with objects returned by their exported functions.

```javascript
// models/user/permission.js
module.exports = function(app) {
    return {
        getPermission: function(id){}
    };
};
// controllers/user.js
module.exports = function(app) {
    return {
        get: function(req, res, callback) {
            var data = app.models['user/permission'].getPermission(req.params.userId);
            callback(null, data);
        }
    }
};
```

        app.models = {}

## *Object* app.routes = `{}`

Files from the *routes* folder with objects returned by their exported functions.

        app.routes = {}

## *Object* app.styles = `{}`

Files from the *styles* folder as *Function*s
ready to create new *Item*s.

        app.styles = {}

## *Object* app.views = `{}`

Files from the *views* folder as the *Document* instances.

        app.views = {}

## *Resources* app.resources

        app.resources = do ->
            if opts.resources
                Resources.fromJSON(opts.resources)
            else
                new Resources

## *Signal* app.onReady()

Called when all modules, views, styled etc. have been loaded.

        signal.create app, 'onReady'

        # config.type
        config.type ?= 'app'
        assert.ok utils.has(['app', 'game', 'text'], config.type), "Unexpected app.config.type value. Accepted app/game/text, but '#{config.type}' got."

        app.Route = AppRoute app

## *Dict* app.cookies

On the client side, this object refers to the last received cookies
from the networking request.

On the server side, this cookies object are added into the each networking response.

By default, client has *clientId* and *sessionId* hashes.

```javascript
app.cookies.onChange(function(key){
    console.log('cookie changed', key, this[key]);
});
```

```xml
<h1>Your clientId</h1>
<em>${context.app.cookies.clientId}</em>
```

        # cookies
        COOKIES_KEY = '__neft_cookies'
        app.cookies = {}
        onCookiesReady = (dict) ->
            app.cookies = dict
            if utils.isClient
                dict.set 'sessionId', utils.uid(16)
        db.get COOKIES_KEY, db.OBSERVABLE, (err, dict) ->
            if dict
                onCookiesReady dict
            else
                if utils.isClient
                    cookies = {clientId: utils.uid(16)}
                else
                    cookies = {}
                db.set COOKIES_KEY, cookies, (err) ->
                    db.get COOKIES_KEY, db.OBSERVABLE, (err, dict) ->
                        if dict
                            onCookiesReady dict
        app.networking.onRequest (req, res) ->
            if utils.isClient
                utils.merge req.cookies, app.cookies
            else
                utils.merge res.cookies, app.cookies
            req.onLoadEnd.listeners.unshift ->
                if utils.isClient
                    for key, val of res.cookies
                        unless utils.isEqual(app.cookies[key], val)
                            app.cookies.set key, val
                return
            , null
            return

        # propagate data
        Renderer.resources = app.resources
        Renderer.serverUrl = app.networking.url
        Renderer.onLinkUri (uri) ->
            app.networking.createLocalRequest
                method: Networking.Request.GET
                type: Networking.Request.HTML_TYPE
                uri: uri
        Document.Scripts.scripts = utils.arrayToObject opts.scripts,
            (index, elem) -> elem.name,
            (index, elem) -> elem.file

        # set styles window item
        if opts.styles?
            for style in opts.styles
                if style.name in ['view', '__view__']
                    style.file._init app: app, view: null
                    windowStyle = style.file._main.getComponent()
                    break

        windowStyleItem = windowStyle?.item
        assert.ok windowStyleItem, '__view__ style must be defined'
        Renderer.window = windowStyleItem

        if opts.styles?
            stylesInitObject =
                app: app
                view: windowStyleItem

            # initialize styles
            for style in opts.styles when style.name?
                if style.name isnt 'view'
                    style.file._init stylesInitObject
                app.styles[style.name] = style.file

        # load styles
        Styles
            windowStyle: windowStyle
            styles: app.styles
            queries: opts.styleQueries
            resources: app.resources

        # load bootstrap
        if utils.isNode
            bootstrapRoute app

        # loading files helper
        init = (files, target) ->
            for file in files when file.name?
                if typeof file.file isnt 'function'
                    continue

                fileObj = file.file app
                target[file.name] = fileObj

                if baseNameMatch = BASE_FILE_NAME_RE.exec(file.name)
                    [_, baseName] = baseNameMatch
                    if target[baseName]?
                        if utils.isPlainObject(target[baseName]) and utils.isPlainObject(fileObj)
                            fileObj = utils.merge Object.create(target[baseName]), fileObj
                    target[baseName] = fileObj

            return

        # load app extensions
        if utils.isObject(opts.extensions)
            for ext in opts.extensions
                ext app

        # exports app classes
        exports.app =
            Route: app.Route

        # load views
        for view in opts.views when view.name?
            app.views[view.name] = Document.fromJSON view.file

        # load files
        init opts.models, app.models
        init opts.routes, app.routes

        for path, obj of app.routes
            r = {}
            if utils.isObject(obj) and not (obj instanceof app.Route)
                for method, opts of obj
                    if utils.isObject(opts)
                        route = new app.Route method, opts
                        r[route.name] = route
                    else
                        r[method] = opts
            app.routes[path] = r

        # provide default index route
        unless app.routes.index
            app.routes.index = new app.Route 'get /', {}

        # emit ready signal
        app.onReady.emit()

        app


Improve the documentation in ReactMaybeMatchers

# React Maybe Matchers for Jasmine

Tests using the React test utilities directly are both difficult to read
and inconvenient to type. These matchers are intended to to make it
easier to write tests and to understand what they are doing later.

One of the biggest problems with writing Jasmine matchers for React is that
you often have to search through Reacts tree to find the things you want
to test.  In Rspec (in Ruby) you can often chain matchers together to create
complex and readable tests.  Alas, this is not possible for Jasmine.

To compensate for this we will make a [Maybe monad](monad.md#what-is-a-monad)
which will allow us to chain a series of filters.  People often get flustered
about monads, but their use is very straight forward.

## DSL for React tests

These matchers will allow us to write tests like:

```coffee
  expect(component).toBeAComponent (which) ->
    which.contains.tags("div")
         .with.cssClass("my-class")
         .and.text("contents")
         .exactly(2).times
         .result()
```

In the example above, `toBeAComponent` accepts a callback, which it will call,
funishing a monad called `which`.  We can then chain a series of tests.

The chain in this example means that I am expecting my component to contain a DOM `div`
with the class `my-css-class`.  This `div` should contain the text, `contents`.
There should be exactly 2 such `divs` in my tree.  The `result()` at the
end simply means, "I'm done with my testing, please calculate the results".

The Maybe monad is a special kind of monad that only processes when
the data is valid.  In this case, if there are no `div` elements, then it
wont bother trying to figure out the cssClass, etc.  It will ignore
everything until it gets to the `result`.  Its a useful technique when
you dont want to constantly check return values for errors.

### Requirements

The main matcher interface will return a
[ComponentQuery](./ComponentQuery.litcoffee).  This is a
[JasmineMonad](./JasmineMonad.litcoffee)
that allows you to take a single React component and make queries
of it, often generating a [ComponentFilter](./ComponentFilter.litcoffee)
or [DomComponentFilter](./DomComponentFilter.litcoffee)

    ComponentQuery = require("./ComponentQuery.litcoffee")

### Using ReactMaybeMatchers

The matchers need to use the React test utils in order to
inspect the React/DOM tree for components.  `@reactUtils`
here is the result of `require("react-addons-test-utils")`

    class ReactMaybeMatchers
      constructor: (@reactUtils) ->

In order to use ReactMaybeMatchers, you have to add
the matchers to the jasmine instance.

      addTo: (jasmine) ->
        jasmine.addMatchers(this)

Here is the typical way to set up the matchers in a spec:

```coffee
React = require("react")
ReactTestUtils = require('react-addons-test-utils')
ReactMaybeMatchers = require("../src/ReactMaybeMatchers.litcoffee")

describe "some wonderful thing", ->
  beforeEach ->
    new ReactMaybeMatchers(ReactTestUtils).addTo(jasmine)
```

### Main Matcher Interface

We actually only require one main method in our matchers interface because
all of our matchers are actually implemented as methods on our monads.

      # The matcher gets called with a different `this` pointer,
      # so we need to use a fat arrow here.
      toBeAComponent: (util, testers) =>
        compare: (component, func) =>
          filter = new ComponentQuery(@reactUtils, component, util, testers)
          func(filter)

### Exported Classes

    module.exports = ReactMaybeMatchers

# React Maybe Matchers for Jasmine

Tests using the React test utilities directly are both difficult to read
and inconvenient to type. These matchers are intended to to make it
easier to write tests and to understand what they are doing later.

One of the biggest problems with writing Jasmine matchers for React is that
you often have to search through Reacts tree to find the things you want
to test.  In Rspec (in Ruby) you can often chain matchers together to create
complex and readable tests.  Alas, this is not possible for Jasmine.

To compensate for this we will make a [Maybe monad](monad.md#what-is-a-monad)
which will allow us to chain a series of filters.  People often get flustered
about monads, but their use is very straight forward.

## DSL for React tests

These matchers will allow us to write tests like:

```coffee
  expect(component).toBeAComponent (which) ->
    which.contains.tags("div")
         .with.cssClass("my-class")
         .and.text("contents")
         .exactly(2).times
         .result()
```

In the example above, `toBeAComponent` accepts a callback, which it will call,
funishing a monad called `which`.  We can then chain a series of tests.

The chain in this example means that I am expecting my component to contain a DOM `div`
with the class `my-css-class`.  This `div` should contain the text, `contents`.
There should be exactly 2 such `divs` in my tree.  The `result()` at the
end simply means, "I'm done with my testing, please calculate the results".

The Maybe monad is a special kind of monad that only processes when
the data is valid.  In this case, if there are no `div` elements, then it
wont bother trying to figure out the cssClass, etc.  It will ignore
everything until it gets to the `result`.  Its a useful technique when
you dont want to constantly check return values for errors.

## Requirements

The [ComponentQuery](./ComponentQuery.litcoffee) is a
[JasmineMonad](./JasmineMonad.litcoffee)
that allows you to take a single React component and make queries
of it, often generating a [ComponentFilter](./ComponentFilter.litcoffee).

    ComponentQuery = require("./ComponentQuery.litcoffee")

### Main matcher interface

We actually only require one main method in our matchers interface because
all of our matchers are actually implemented as methods on our monads.

    class ReactMaybeMatchers
      constructor: (@reactUtils) ->

      addTo: (jasmine) ->
        jasmine.addMatchers(this)

The matcher gets called with a different `this` pointer, so we need to use
a fat arrow here.

      toBeAComponent: (util, testers) =>
        compare: (component, func) =>
          filter = new ComponentQuery(@reactUtils, component, util, testers)
          func(filter)

Export our matchers from this file.

    module.exports = ReactMaybeMatchers


interpret boxed bound- and fixed-function objects as methods

## [StateExpression](#state-expression)

A **state expression** is a data structure that formalizes a definition of
a state’s contents.

States are declared by calling the module’s exported `state()` function and
passing it a descriptive plain object map. This input may be expressed in a
shorthand format, in which case it is rewritten into an unambiguous long form
that is used internally to create `State` instances.

    State::Expression = class StateExpression

      { isNumber, isPlainObject, assign, edit, clone, invert } = O
      { NORMAL } = STATE_ATTRIBUTES

      attributeMap = do ->
        for key, value of object = assign STATE_ATTRIBUTE_MODIFIERS
          object[ key ] = key.toUpperCase()
        object

      attributeFlags = do ->
        for key, value of object = invert STATE_ATTRIBUTES
          object[ key ] = value.toLowerCase()
        object

      categoryMap  = assign STATE_EXPRESSION_CATEGORIES
      eventTypes   = assign STATE_EVENT_TYPES
      guardActions = assign GUARD_ACTIONS

### [Constructor](#state-expression--constructor)

      constructor: ( attributes, map ) ->
        if typeof attributes is 'string' then map or = {}
        else unless map
          map = attributes; attributes = undefined

        map = interpret map unless map instanceof StateExpression
        edit 'deep all', this, map

        if attributes?
          attributes = encodeAttributes attributes unless isNumber attributes
        else { attributes } = map if map

        @attributes = attributes or NORMAL

### [Private functions](#state-expression--private)

#### [interpret](#state-expression--private--interpret)

Transforms a plain object map into a well-formed `StateExpression`, making the
appropriate type inferences for any shorthand notation encountered.

      interpret = ( map ) ->

Start with a null-valued map keyed with the category names.

        result = assign STATE_EXPRESSION_CATEGORIES, null

        for own key, value of map

If `value` is just a reference to the exported `state` function, interpret that
as an empty state expression.

          value = new StateExpression if value is state

###### Categorization

**Priority 1:** Do a nominative type match for explicit expression instances.

          category =
            if value instanceof StateExpression then 'states'
            else if value instanceof TransitionExpression then 'transitions'
          if category
            item = result[ category ] or = {}
            item[ key ] = value

**Priority 2:** Recognize an explicitly named category object.

          else if key of result and value
            result[ key ] = clone result[ key ], value

**Priority 3:** Use keys and value types to infer implicit categorization.

          else
            category =
              if key of eventTypes or typeof value is 'string'
                'events'
              else if key of guardActions
                'guards'
              else if typeof value is 'function' or ( type = value?.type ) and
                  ( type is 'state-bound-function' or
                    type is 'state-fixed-function' )
                'methods'
              else if value is NIL or isPlainObject value
                'states'
            if category
              item = result[ category ] or = {}
              item[ key ] = value

###### Coersion

Event values are coerced into an array.

        for own key, value of object = result.events
          if typeof value is 'function' or typeof value is 'string'
            object[ key ] = [ value ]

Guards are represented as an object keyed by selector, so non-object values are
coerced into a single-element object with the value keyed to the wildcard
selector `*`.

        for own key, value of object = result.guards
          object[ key ] = '*': value unless isPlainObject value

Transition values must be a `TransitionExpression`.

        for own key, value of object = result.transitions
          unless value is NIL or value instanceof TransitionExpression
            object[ key ] = new TransitionExpression value

State values must resolve to a `StateExpression`. They may be supplied as a
plain object, or as a live `State` instance, which is automatically `express`ed
to a formal `StateExpression`.

        for own key, value of object = result.states
          if value instanceof State
            object[ key ] = value.express true
          else unless value is NIL or value instanceof StateExpression
            object[ key ] = new StateExpression value

        result

### [Class methods](#state-expression--class-methods)

#### [encodeAttributes](#state-expression--class--encode-attributes)

Returns the bit-field integer represented by the provided set of `attributes`.

      @encodeAttributes = encodeAttributes = ( attributes ) ->
        attributes = assign attributes if typeof attributes is 'string'
        result = NORMAL
        for own key, value of attributes when key of attributeMap
          result |= STATE_ATTRIBUTES[ attributeMap[ key ] ]
        result

#### [decodeAttributes](#state-expression--class--decode-attributes)

Returns the space-delimited set of attribute names represented by the provided
bit-field integer `number`.

      @decodeAttributes = decodeAttributes = ( number ) ->
        ( value for key, value of attributeFlags when number & key ).join ' '

#### [untype](#state-expression--class-methods--untype)

Returns the `StateExpression` provided by `expr` as a plain-`Object`.

      @untype = untype = ( expr ) ->
        result = {}
        result[ key ] = value for own key, value of expr
        s[ name ] = untype subexpr for name, subexpr of s = result.states
        result

## [StateExpression](#state-expression)

A **state expression** is a data structure that formalizes a definition of
a state’s contents.

States are declared by calling the module’s exported `state()` function and
passing it a descriptive plain object map. This input may be expressed in a
shorthand format, in which case it is rewritten into an unambiguous long form
that is used internally to create `State` instances.

    State::Expression = class StateExpression

      { isNumber, isPlainObject, assign, edit, clone, invert } = O
      { NORMAL } = STATE_ATTRIBUTES

      attributeMap = do ->
        for key, value of object = assign STATE_ATTRIBUTE_MODIFIERS
          object[ key ] = key.toUpperCase()
        object

      attributeFlags = do ->
        for key, value of object = invert STATE_ATTRIBUTES
          object[ key ] = value.toLowerCase()
        object

      categoryMap  = assign STATE_EXPRESSION_CATEGORIES
      eventTypes   = assign STATE_EVENT_TYPES
      guardActions = assign GUARD_ACTIONS

### [Constructor](#state-expression--constructor)

      constructor: ( attributes, map ) ->
        if typeof attributes is 'string' then map or = {}
        else unless map
          map = attributes; attributes = undefined

        map = interpret map unless map instanceof StateExpression
        edit 'deep all', this, map

        if attributes?
          attributes = encodeAttributes attributes unless isNumber attributes
        else { attributes } = map if map

        @attributes = attributes or NORMAL

### [Private functions](#state-expression--private)

#### [interpret](#state-expression--private--interpret)

Transforms a plain object map into a well-formed `StateExpression`, making the
appropriate type inferences for any shorthand notation encountered.

      interpret = ( map ) ->

Start with a null-valued map keyed with the category names.

        result = assign STATE_EXPRESSION_CATEGORIES, null

        for own key, value of map

If `value` is just a reference to the exported `state` function, interpret that
as an empty state expression.

          value = new StateExpression if value is state

###### Categorization

**Priority 1:** Do a nominative type match for explicit expression instances.

          category =
            if value instanceof StateExpression then 'states'
            else if value instanceof TransitionExpression then 'transitions'
          if category
            item = result[ category ] or = {}
            item[ key ] = value

**Priority 2:** Recognize an explicitly named category object.

          else if key of result and value
            result[ key ] = clone result[ key ], value

**Priority 3:** Use keys and value types to infer implicit categorization.

          else
            category =
              if key of eventTypes or typeof value is 'string'
                'events'
              else if key of guardActions
                'guards'
              else if value is NIL or isPlainObject value
                'states'
              else if typeof value is 'function'
                'methods'
            if category
              item = result[ category ] or = {}
              item[ key ] = value

###### Coersion

Event values are coerced into an array.

        for own key, value of object = result.events
          if typeof value is 'function' or typeof value is 'string'
            object[ key ] = [ value ]

Guards are represented as an object keyed by selector, so non-object values are
coerced into a single-element object with the value keyed to the wildcard
selector `*`.

        for own key, value of object = result.guards
          object[ key ] = '*': value unless isPlainObject value

Transition values must be a `TransitionExpression`.

        for own key, value of object = result.transitions
          unless value is NIL or value instanceof TransitionExpression
            object[ key ] = new TransitionExpression value

State values must resolve to a `StateExpression`. They may be supplied as a
plain object, or as a live `State` instance, which is automatically `express`ed
to a formal `StateExpression`.

        for own key, value of object = result.states
          if value instanceof State
            object[ key ] = value.express true
          else unless value is NIL or value instanceof StateExpression
            object[ key ] = new StateExpression value

        result

### [Class methods](#state-expression--class-methods)

#### [encodeAttributes](#state-expression--class--encode-attributes)

Returns the bit-field integer represented by the provided set of `attributes`.

      @encodeAttributes = encodeAttributes = ( attributes ) ->
        attributes = assign attributes if typeof attributes is 'string'
        result = NORMAL
        for own key, value of attributes when key of attributeMap
          result |= STATE_ATTRIBUTES[ attributeMap[ key ] ]
        result

#### [decodeAttributes](#state-expression--class--decode-attributes)

Returns the space-delimited set of attribute names represented by the provided
bit-field integer `number`.

      @decodeAttributes = decodeAttributes = ( number ) ->
        ( value for key, value of attributeFlags when number & key ).join ' '

#### [untype](#state-expression--class-methods--untype)

Returns the `StateExpression` provided by `expr` as a plain-`Object`.

      @untype = untype = ( expr ) ->
        result = {}
        result[ key ] = value for own key, value of expr
        s[ name ] = untype subexpr for name, subexpr of s = result.states
        result


Fix server on non Posix OS

Fix server on non Posix OS

nodePush Pushserver for Tims Chat
=================================

Copyright Information
---------------------

	"@author	Tim Düsterhus"
	"@copyright	2012-2013 Tim Düsterhus"
	"@license	BSD 3-Clause License <http://opensource.org/licenses/BSD-3-Clause>"
	"@package	be.bastelstu.wcf.nodePush"

Setup
-----

Load required namespaces.

	express = require 'express'
	http = require 'http'
	io = require 'socket.io'
	net = require 'net'
	fs = require 'fs'

Load config

	try
		config = require '../config.js'
	catch e
		config = { }

Initialize sane values.

	config.outbound ?= { }
	config.outbound.useTCP ?= true
	config.outbound.port ?= 9001
	config.outbound.host ?= '0.0.0.0'
	config.outbound.socket ?= __dirname + "/../outbound.sock"
	config.inbound ?= { }
	config.inbound.useTCP ?= false
	config.inbound.port ?= 9002
	config.inbound.host ?= '127.0.0.1'
	config.inbound.socket ?= __dirname + "/../inbound.sock"
	config.user ?= 'nobody'
	config.group ?= 'nogroup'

Prepare environment

	log = (message) ->
		console.log "[be.bastelstu.chat.nodePush] #{message}"

	thousandsSeparator = (number) ->
		String(number).replace /(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1,'

	# Ensure our namespace is present
	be = be ? {}
	be.bastelstu ?= {}
	be.bastelstu.chat ?= {}

be.bastelstu.chat.nodePush
==========================

	class be.bastelstu.chat.nodePush

Attributes
----------

Instance of express.

		app: null

Instance of http

		server: null

Instance of socket.io

		io: null

Statistics for the status page.

		stats:
			status: 0
			outbound:
				total: 0
				current: 0
			inbound: 0
			messages: { }
			bootTime: new Date()

Methods
-------
**constructor()**

		constructor: ->
			log 'Starting nodePush'
			log "PID is #{process.pid}"
			if config.inbound.useTCP
				log "Inbound: #{config.inbound.host}:#{config.inbound.port}"
			else
				log "Inbound: #{config.inbound.socket}"
			if config.outbound.useTCP
				log "Outbound: #{config.outbound.host}:#{config.outbound.port}"
			else
				log "Outbound: #{config.outbound.socket}"

			@stats.bootTime = new Date()

			@initUnixSocket()
			@initServer()

Bind shutdown function to needed events.

			process.on 'exit', @shutdown.bind @
			process.on 'uncaughtException', @shutdown.bind @
			process.on 'SIGINT', @shutdown.bind @
			process.on 'SIGTERM', @shutdown.bind @

Set nice title for PS.

			process.title = 'nodePush - Tims Chat'

**initServer()**
Initialize socket server.

		initServer: ->
			log 'Initializing outbound socket'

Start HTTP service.

			@app = express()
			@server = http.createServer @app
			@io = io.listen @server

			listenCallback = =>

Shed root privilegies.

				if process.getuid? and (process.getuid() is 0 or process.getgid() is 0)
					try
						log 'Trying to shed root privilegies'
						process.setgid config.group
						process.setuid config.user
						log "New User ID: #{process.getuid()}, New Group ID: #{process.getgid()}"
					catch e
						log 'Cowardly refusing to keep the process alive as root.'
						process.exit 1

Initialize intervals for tick events. The ticks are sent every 15 / 30 / 60 / 90 / 120 seconds.

				setInterval =>
					@sendMessage 'tick15'
				, 15e3
				setInterval =>
					@sendMessage 'tick30'
				, 30e3
				setInterval =>
					@sendMessage 'tick60'
				, 60e3
				setInterval =>
					@sendMessage 'tick90'
				, 90e3
				setInterval =>
					@sendMessage 'tick120'
				, 120e3

				log "Done"

			if config.outbound.useTCP
				@server.listen config.outbound.port, config.outbound.host, null, listenCallback
			else
				@server.listen config.outbound.socket, listenCallback
				fs.chmod config.outbound.socket, '777'

Initialize production environment.

			@io.set 'log level', 1
			@io.set 'browser client etag', true
			@io.set 'browser client minification', true
			@io.set 'browser client gzip', true

Development configuration.

			@io.configure 'development', =>
				@io.set 'log level', 3
				@io.set 'browser client etag', false
				@io.set 'browser client minification', false

Record statistics for Websocket connections.

			@io.sockets.on 'connection', (socket) =>
				@stats.outbound.total++
				@stats.outbound.current++

				socket.on 'disconnect', =>
					@stats.outbound.current--

Show the status page when '/' is requested.

			@app.get '/', (req, res) =>
				res.charset = 'utf-8';
				res.type 'txt'

				@stats.status++
				reply = """
				Up since: #{@stats.bootTime}
				Status page: #{thousandsSeparator @stats.status} Requests
				Outbound: #{thousandsSeparator @stats.outbound.current} now - #{thousandsSeparator @stats.outbound.total} Total
				Inbound: #{thousandsSeparator @stats.inbound}
				Messages:
				"""
				for message, amount of @stats.messages
					reply += "\n	#{message}: #{thousandsSeparator amount}"

				res.send reply

**sendMessage(name)**
Sends a message with the given name.

		sendMessage: (name) ->
			return unless /[a-zA-Z0-9-_.]+$/.test name

			@stats.messages[name] ?= 0
			@stats.messages[name]++
			@io.sockets.send name

**initUnixSocket()**
Initialize PHP side unix socket.

		initUnixSocket: ->
			log 'Initializing inbound socket'
			socket = net.createServer (c) =>
				@stats.inbound++

Pass data to the browsers and close connection.

				c.on 'data', (data) =>
					setTimeout =>
						@sendMessage data.toString().trim()
					, 20
					c.end()

				c.on 'end', ->
					c.end()

Kill connection after 5 seconds.

				c.setTimeout 5e3, ->
					c.end()

			if config.inbound.useTCP
				socket.listen config.inbound.port, config.inbound.host
			else
				socket.listen config.inbound.socket
				fs.chmod config.inbound.socket, '777'

**shutdown()**
Performs a clean shutdown of nodePush.

		shutdown: (message) ->
			if not message
				log 'Shutting down'
			else
				log "Shutting down: #{message}"

			fs.unlinkSync config.inbound.socket if not config.inbound.useTCP and fs.existsSync config.inbound.socket
			fs.unlinkSync config.outbound.socket if not config.outbound.useTCP and fs.existsSync config.outbound.socket

			process.removeAllListeners()
			process.exit()

And finally start the service.

	new be.bastelstu.chat.nodePush()

nodePush Pushserver for Tims Chat
=================================

Copyright Information
---------------------

	"@author	Tim Düsterhus"
	"@copyright	2012-2013 Tim Düsterhus"
	"@license	BSD 3-Clause License <http://opensource.org/licenses/BSD-3-Clause>"
	"@package	be.bastelstu.wcf.nodePush"

Setup
-----

Load required namespaces.

	express = require 'express'
	http = require 'http'
	io = require 'socket.io'
	net = require 'net'
	fs = require 'fs'

Load config

	try
		config = require '../config.js'
	catch e
		config = { }

Initialize sane values.

	config.outbound ?= { }
	config.outbound.useTCP ?= true
	config.outbound.port ?= 9001
	config.outbound.host ?= '0.0.0.0'
	config.outbound.socket ?= __dirname + "/../outbound.sock"
	config.inbound ?= { }
	config.inbound.useTCP ?= false
	config.inbound.port ?= 9002
	config.inbound.host ?= '127.0.0.1'
	config.inbound.socket ?= __dirname + "/../inbound.sock"
	config.user ?= 'nobody'
	config.group ?= 'nogroup'

Prepare environment

	log = (message) ->
		console.log "[be.bastelstu.chat.nodePush] #{message}"

	thousandsSeparator = (number) ->
		String(number).replace /(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1,'

	# Ensure our namespace is present
	be = be ? {}
	be.bastelstu ?= {}
	be.bastelstu.chat ?= {}

be.bastelstu.chat.nodePush
==========================

	class be.bastelstu.chat.nodePush

Attributes
----------

Instance of express.

		app: null

Instance of http

		server: null

Instance of socket.io

		io: null

Statistics for the status page.

		stats:
			status: 0
			outbound:
				total: 0
				current: 0
			inbound: 0
			messages: { }
			bootTime: new Date()

Methods
-------
**constructor()**

		constructor: ->
			log 'Starting nodePush'
			log "PID is #{process.pid}"
			if config.inbound.useTCP
				log "Inbound: #{config.inbound.host}:#{config.inbound.port}"
			else
				log "Inbound: #{config.inbound.socket}"
			if config.outbound.useTCP
				log "Outbound: #{config.outbound.host}:#{config.outbound.port}"
			else
				log "Outbound: #{config.outbound.socket}"

			@stats.bootTime = new Date()

			@initUnixSocket()
			@initServer()

Bind shutdown function to needed events.

			process.on 'exit', @shutdown.bind @
			process.on 'uncaughtException', @shutdown.bind @
			process.on 'SIGINT', @shutdown.bind @
			process.on 'SIGTERM', @shutdown.bind @

Set nice title for PS.

			process.title = 'nodePush - Tims Chat'

**initServer()**
Initialize socket server.

		initServer: ->
			log 'Initializing outbound socket'

Start HTTP service.

			@app = express()
			@server = http.createServer @app
			@io = io.listen @server

			listenCallback = =>

Shed root privilegies.

				if process.getuid() is 0 or process.getgid() is 0
					try
						log 'Trying to shed root privilegies'
						process.setgid config.group
						process.setuid config.user
						log "New User ID: #{process.getuid()}, New Group ID: #{process.getgid()}"
					catch e
						log 'Cowardly refusing to keep the process alive as root.'
						process.exit 1

Initialize intervals for tick events. The ticks are sent every 15 / 30 / 60 / 90 / 120 seconds.

				setInterval =>
					@sendMessage 'tick15'
				, 15e3
				setInterval =>
					@sendMessage 'tick30'
				, 30e3
				setInterval =>
					@sendMessage 'tick60'
				, 60e3
				setInterval =>
					@sendMessage 'tick90'
				, 90e3
				setInterval =>
					@sendMessage 'tick120'
				, 120e3

				log "Done"

			if config.outbound.useTCP
				@server.listen config.outbound.port, config.outbound.host, null, listenCallback
			else
				@server.listen config.outbound.socket, listenCallback
				fs.chmod config.outbound.socket, '777'

Initialize production environment.

			@io.set 'log level', 1
			@io.set 'browser client etag', true
			@io.set 'browser client minification', true
			@io.set 'browser client gzip', true

Development configuration.

			@io.configure 'development', =>
				@io.set 'log level', 3
				@io.set 'browser client etag', false
				@io.set 'browser client minification', false

Record statistics for Websocket connections.

			@io.sockets.on 'connection', (socket) =>
				@stats.outbound.total++
				@stats.outbound.current++

				socket.on 'disconnect', =>
					@stats.outbound.current--

Show the status page when '/' is requested.

			@app.get '/', (req, res) =>
				res.charset = 'utf-8';
				res.type 'txt'

				@stats.status++
				reply = """
				Up since: #{@stats.bootTime}
				Status page: #{thousandsSeparator @stats.status} Requests
				Outbound: #{thousandsSeparator @stats.outbound.current} now - #{thousandsSeparator @stats.outbound.total} Total
				Inbound: #{thousandsSeparator @stats.inbound}
				Messages:
				"""
				for message, amount of @stats.messages
					reply += "\n	#{message}: #{thousandsSeparator amount}"

				res.send reply

**sendMessage(name)**
Sends a message with the given name.

		sendMessage: (name) ->
			return unless /[a-zA-Z0-9-_.]+$/.test name

			@stats.messages[name] ?= 0
			@stats.messages[name]++
			@io.sockets.send name

**initUnixSocket()**
Initialize PHP side unix socket.

		initUnixSocket: ->
			log 'Initializing inbound socket'
			socket = net.createServer (c) =>
				@stats.inbound++

Pass data to the browsers and close connection.

				c.on 'data', (data) =>
					setTimeout =>
						@sendMessage data.toString().trim()
					, 20
					c.end()

				c.on 'end', ->
					c.end()

Kill connection after 5 seconds.

				c.setTimeout 5e3, ->
					c.end()

			if config.inbound.useTCP
				socket.listen config.inbound.port, config.inbound.host
			else
				socket.listen config.inbound.socket
				fs.chmod config.inbound.socket, '777'

**shutdown()**
Performs a clean shutdown of nodePush.

		shutdown: (message) ->
			if not message
				log 'Shutting down'
			else
				log "Shutting down: #{message}"

			fs.unlinkSync config.inbound.socket if not config.inbound.useTCP and fs.existsSync config.inbound.socket
			fs.unlinkSync config.outbound.socket if not config.outbound.useTCP and fs.existsSync config.outbound.socket

			process.removeAllListeners()
			process.exit()

And finally start the service.

	new be.bastelstu.chat.nodePush()