style

style

# Batman.App

`Batman.App` is the central object in any Batman application. It manages the routing table and the current URL parameters, as well as the initial start of the application. It should also be used as a namespace for models and views so that other objects can find them. Batman assumes that there will only ever be one `Batman.App` in use at once.

## Batman.currentApp

A Batman-wide reference to the currently running `Batman.App`.

## @run() : App

`App.run` is the central entry point for a Batman application. `@run` takes these steps to initialize a Batman application:

 1. Instantiate a `Dispatcher`, an internal object for mananging action dispatch to controllers.
 2. Instantiate a `Navigator`, an internal object for managing the URL via pushState or hashbangs.
 3. Instantiate the `layout` view according to the `layout` property on the `App`.
 4. Wait for the layout view to fire it's `ready` event.
 5. Start the first action dispatch by telling the `Navigator` to begin monitoring the URL.

_Note_: `@run` emits the `run` class event on the `App`, but not necessarily as soon as `@run` is called. Because the `layout` View renders asynchronously and may need to fetch other components, the `run` event can and often does fire long after `@run` is called. If you need to execute code as soon as the `App` has started running, add a listener to the `run` event on the `App` class. If you need to execute code as soon as the layout has rendered, you can use the `ready` event on the `App` class.

`@run` can be called before or on the `load` DOMEvent of the window. `@run` will return the App if the commencement was successful and complete, or `false` if the App must wait for the `layout` to render or if the `App` has already run.

#### starting an application with DOMEvents
```coffeescript
window.addEventListener 'load', ->
  MyApp.run()
```

#### starting an application with jQuery
```coffeescript
$ ->
  MyApp.run()
```

## @stop() : App

`@stop` stops the `App` it's called upon. The URL will stop being monitored and no more actions will be dispatched. In usual Batman development you shouldn't have to call this.

## @routes

`@routes` is a class level property referencing the root level `NamedRouteQuery` which allows for binding to routes on objects. See `data-route` bindings for more information.

## @controllers

`@controllers` is a class level property containing the singleton `Batman.Controller` instances for each subclass in the application. This `controllers` directory puts these instances at the lowercase name of the controller. For example, the `TodosController` would be found at `controllers.todos`. `@controllers` ideally should never be bound to, but it is very useful for debugging in the console and other such workarounds.

    test "App.controllers references a directory of controller instances", ->
      class Alfred extends Batman.App
      class Alfred.TodosController extends Batman.Controller
      controller = Alfred.get('controllers.todos')
      equal Batman._functionName(controller.constructor), "TodosController"

    test "Multi-word controller names have a lowercase first letter", ->
      class Alfred extends Batman.App
      class Alfred.ReminderEmailsController extends Batman.Controller
      controller = Alfred.get('controllers.reminderEmails')
      equal Batman._functionName(controller.constructor), "ReminderEmailsController"

## @layout

`@layout` is the base view of the entire view hierarchy. By default, it will parse any data-* attributes in the entire document, excluding any `data-yield`'s, when `App.run()` is called. Use `MyApp.layout = null` to disable the creation of this default view.

## @currentParams

`@currentParams` contains the URL parameters for the current request, including the path relative to the app's base path (`Batman.config.pathToApp`). Some interesting parts to look at: `@currentParams.controller`, `@currentParams.action`.

## @paramsManager
## @paramsPusher

## 'run' class event

The `run` class event is fired once the app has run. This indeterminately but often happens before the app's layout has finished rendering.

## 'ready' class event

The `ready` class event is fired once the app's layout is rendered.

# Batman.App Routing

The `Batman` routing DSL is similar to Rails 3's routing DSL. It is oriented around the notion of a resource:

## @route

`@route` defines a custom route and can be pointed to a controller action directly. For example:

```coffeescript
class window.Example extends Batman.App
  @route 'comments', 'pages#comments'

class Example.PagesController extends Batman.Controller
  comments: ->
```

Would result in `/comments` being added to the routing map, pointed to `PagesController#comments`.

## @resources(resourceName : String[, otherResourceNames... : String][, options : Object][, scopedCallback : Function])

`@resources` is modeled after the Rails routing `resources` method. It automatically defines some routes and matches them to controller actions. For example,

```coffeescript
class App extends Batman.App
  @resources 'pages'

class App.PagesController extends Batman.Controller
  index: ->
    # ...
  new: ->
    # ...
  show: (params) ->
    App.Page.find params.id, (err, page) ->
      @set('currentPage', page)
  edit: (params) ->
    App.Page.find params.id, (err, page) ->
      @set('currentPage', page)
```

Will set up these routes:

Path | Controller Action | View binding
-- | -- | -- |
/pages | App.PagesController#index | `data-route="routes.pages"`
/pages/new | App.PagesController#new | `data-route="routes.pages.new"`
/pages/:id | App.PagesController#show | `data-route="routes.pages[currentPage]"`
/pages/:id/edit | App.PagesController#edit | `data-route="routes.pages[currentPage].edit"`

Of course, `destroy`, `update`, and `create` are not performed by controller actions in Batman. Instead, call `save` or `destroy` on your records.

### Nested Resources

You may also nest resources, as in Rails:

```coffeescript
class App extends Batman.App
  @resources 'pages', ->
    @resources 'comments'
```

Will set up these routes for `App.Comment`:

Path | Controller Action | View binding
-- | -- | -- |
/pages/:page_id/comments | App.CommentsController#index | `data-route="routes.pages[currentPage].comments"`
/pages/:page_id/comments/new | App.CommentsController#new | `data-route="routes.pages[currentPage].comments.new"`
/pages/:page_id/comments/:id | App.CommentsController#show | `data-route="routes.pages[currentPage].comments[currentComment]"`
/pages/:page_id/comments/:id/edit | App.CommentsController#edit | `data-route="routes.pages[currentPage].comments[currentComment].edit"`

## @member

`@member` defines a routable action you can call on a specific instance of a member of a collection resource. For example, if you have a collection of `Page` resources, and a user can post a comment on a specific page:

```coffeescript
class window.Example extends Batman.App
  @resources 'pages', ->
    @member 'comment'

class Example.PagesController extends Batman.Controller
  comment: (params) ->
```

Would result in `/pages/:id/comment` being added to the routing map, pointed to `PagesController#comment`.

## @collection

`@collection` is similar to `@member` in that it adds routable actions to a `@resources` set of routes. In this case the action would apply to the entire collection. For example, if you have a list of spam comments made across _all_ your `Page` resources:

```coffeescript
class window.Example extends Batman.App
  @resources 'pages', ->
    @collection 'spam_comments'

class Example.PagesController extends Batman.Controller
  comments: ->
```

Would result in `/pages/spam_comments` being added to the routing map, pointed to `PagesController#spam_comments`.

## @root

`@root` defines the root controller and action to be used when visiting the base application URL. For example:

```coffeescript
class window.Example extends Batman.App
  @root 'pages#index'

class Example.PagesController extends Batman.Controller
  index: ->
```

Would result in `/` being pointed to `PagesController#index`.

# Batman.App

`Batman.App` is the central object in any Batman application. It manages the routing table and the current URL parameters, as well as the initial start of the application. It should also be used as a namespace for models and views so that other objects can find them. Batman assumes that there will only ever be one `Batman.App` in use at once.

## Batman.currentApp

A Batman-wide reference to the currently running `Batman.App`.

## @run() : App

`App.run` is the central entry point for a Batman application. `@run` takes these steps to initialize a Batman application:

 1. Instantiate a `Dispatcher`, an internal object for mananging action dispatch to controllers.
 2. Instantiate a `Navigator`, an internal object for managing the URL via pushState or hashbangs.
 3. Instantiate the `layout` view according to the `layout` property on the `App`.
 4. Wait for the layout view to fire it's `ready` event.
 5. Start the first action dispatch by telling the `Navigator` to begin monitoring the URL.

_Note_: `@run` emits the `run` class event on the `App`, but not necessarily as soon as `@run` is called. Because the `layout` View renders asynchronously and may need to fetch other components, the `run` event can and often does fire long after `@run` is called. If you need to execute code as soon as the `App` has started running, add a listener to the `run` event on the `App` class. If you need to execute code as soon as the layout has rendered, you can use the `ready` event on the `App` class.

`@run` can be called before or on the `load` DOMEvent of the window. `@run` will return the App if the commencement was successful and complete, or `false` if the App must wait for the `layout` to render or if the `App` has already run.

#### starting an application with DOMEvents
```coffeescript
window.addEventListener 'load', ->
  MyApp.run()
```

#### starting an application with jQuery
```coffeescript
$ ->
  MyApp.run()
```

## @stop() : App

`@stop` stops the `App` it's called upon. The URL will stop being monitored and no more actions will be dispatched. In usual Batman development you shouldn't have to call this.

## @routes

`@routes` is a class level property referencing the root level `NamedRouteQuery` which allows for binding to routes on objects. See `data-route` bindings for more information.

## @controllers

`@controllers` is a class level property containing the singleton `Batman.Controller` instances for each subclass in the application. This `controllers` directory puts these instances at the lowercase name of the controller. For example, the `TodosController` would be found at `controllers.todos`. `@controllers` ideally should never be bound to, but it is very useful for debugging in the console and other such workarounds.

    test "App.controllers references a directory of controller instances", ->
      class Alfred extends Batman.App
      class Alfred.TodosController extends Batman.Controller
      controller = Alfred.get('controllers.todos')
      equal Batman._functionName(controller.constructor), "TodosController"

    test "Multi-word controller names have a lowercase first letter", ->
      class Alfred extends Batman.App
      class Alfred.ReminderEmailsController extends Batman.Controller
      controller = Alfred.get('controllers.reminderEmails')
      equal Batman._functionName(controller.constructor), "ReminderEmailsController"

## @layout

`@layout` is the base view of the entire view hierarchy. By default, it will parse any data-* attributes in the entire document, excluding any `data-yield`'s, when `App.run()` is called. Use `MyApp.layout = null` to disable the creation of this default view.

## @currentParams

`@currentParams` contains the URL parameters for the current request, including the path relative to the app's base path (`Batman.config.pathToApp`). Some interesting parts to look at: `@currentParams.controller`, `@currentParams.action`.

## @paramsManager
## @paramsPusher

## 'run' class event

The `run` class event is fired once the app has run. This indeterminately but often happens before the app's layout has finished rendering.

## 'ready' class event

The `ready` class event is fired once the app's layout is rendered.

# Batman.App Routing

The `Batman` routing DSL is similar to Rails 3's routing DSL. It is oriented around the notion of a resource:

## @route

`@route` defines a custom route and can be pointed to a controller action directly. For example:

```coffeescript
class window.Example extends Batman.App
  @route 'comments', 'pages#comments'

class Example.PagesController extends Batman.Controller
  comments: ->
```

Would result in `/comments` being added to the routing map, pointed to `PagesController#comments`.

## @resources(resourceName : String[, otherResourceNames... : String][, options : Object][, scopedCallback : Function])

`@resources` is modeled after the Rails routing `resources` method. It automatically defines some routes (and matches them to controller actions) for you. For example,

```coffeescript
class App extends Batman.App
  @resources 'pages'

class App.PagesController extends Batman.Controller
  index: ->
    # ...
  new: ->
    # ...
  show: (params) ->
    App.Page.find params.id, (err, page) ->
      @set('currentPage', page)
  edit: (params) ->
    App.Page.find params.id, (err, page) ->
      @set('currentPage', page)
```

Will set up these routes:

Path | Controller Action | View binding
-- | -- | -- |
/pages | App.PagesController#index | `data-route="routes.pages"`
/pages/new | App.PagesController#new | `data-route="routes.pages.new"`
/pages/:id | App.PagesController#show | `data-route="routes.pages[currentPage]"`
/pages/:id/edit | App.PagesController#edit | `data-route="routes.pages[currentPage].edit"`

Of course, `destroy`, `update`, and `create` are not performed by controller actions in Batman. Instead, call `save` or `destroy` on your records.

### Nested Resources

You may also nest resources, as in Rails:

```coffeescript
class App extends Batman.App
  @resources 'pages', ->
    @resources 'comments'
```

Will set up these routes for `App.Comment`:

Path | Controller Action | View binding
-- | -- | -- |
/pages/:page_id/comments | App.CommentsController#index | `data-route="routes.pages[currentPage].comments"`
/pages/:page_id/comments/new | App.CommentsController#new | `data-route="routes.pages[currentPage].comments.new"`
/pages/:page_id/comments/:id | App.CommentsController#show | `data-route="routes.pages[currentPage].comments[currentComment]"`
/pages/:page_id/comments/:id/edit | App.CommentsController#edit | `data-route="routes.pages[currentPage].comments[currentComment].edit"`

## @member

`@member` defines a routable action you can call on a specific instance of a member of a collection resource. For example, if you have a collection of `Page` resources, and a user can post a comment on a specific page:

```coffeescript
class window.Example extends Batman.App
  @resources 'pages', ->
    @member 'comment'

class Example.PagesController extends Batman.Controller
  comment: (params) ->
```

Would result in `/pages/:id/comment` being added to the routing map, pointed to `PagesController#comment`.

## @collection

`@collection` is similar to `@member` in that it adds routable actions to a `@resources` set of routes. In this case the action would apply to the entire collection. For example, if you have a list of spam comments made across _all_ your `Page` resources:

```coffeescript
class window.Example extends Batman.App
  @resources 'pages', ->
    @collection 'spam_comments'

class Example.PagesController extends Batman.Controller
  comments: ->
```

Would result in `/pages/spam_comments` being added to the routing map, pointed to `PagesController#spam_comments`.

## @root

`@root` defines the root controller and action to be used when visiting the base application URL. For example:

```coffeescript
class window.Example extends Batman.App
  @root 'pages#index'

class Example.PagesController extends Batman.Controller
  index: ->
```

Would result in `/` being pointed to `PagesController#index`.


throw errors if no onerror

throw errors if no onerror

    _self = this

    if console?.log?
     LOG = console.log.bind console
    else
     LOG = -> null

    if console?.error?
     ERROR_LOG = console.error.bind console
    else
     ERROR_LOG = -> null

    POLL_TYPE =
     progress: true

##Response class

    class Response
     constructor: (data, port, options) ->
      @id = data.id
      @port = port
      @options = options
      @queue = []
      @fresh = true

     progress: (progress, data, callback) ->
      @queue.push
       method: 'progress'
       data: data
       options: {progress: progress}
       callback: callback
      @_handleQueue()

     success: (data) ->
      @queue.push method: 'success', data: data, options: {}
      @_handleQueue()

     fail: (data) ->
      @queue.push method: 'fail', data: data, options: {}
      @_handleQueue()

     setOptions: (options) ->
      @options = options
      @fresh = true
      @_handleQueue()

     _multipleResponse: ->
      responseList = []
      callbacks = []
      for d in @queue
       responseList.push
        status: d.method
        data: d.data
        options: d.options
       if d.callback?
        callbacks.push d.callback

      done = ->
       for callback in callbacks
        callback()

      if @port.isStreaming
       @port.respondMultiple this, responseList, @options, done
      else if @fresh
       @port.respondMultiple this, responseList, @options, done
       @fresh = false

      @queue = []

     _handleQueue: ->
      return unless @queue.length > 0
      return if not @queue.isStreaming and not @fresh

      if @queue.length > 1
       return @_multipleResponse()

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options, d.callback
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @fresh = false

      @queue = []

##Call class

    class Call
     constructor: (@id, @method, @data, @callbacks, @options, @port) -> null

     handle: (data, options) ->
      if not @callbacks[options.status]?
       return if options.status is 'progress'
       #Handled by caller
       throw new Error "No callback registered #{@method} #{options.status}"
      self = this
      setTimeout ->
       try
        self.callbacks[options.status] data, options
       catch e
        if self.port.onerror?
         self.port.onerror e
        else
         throw e
      , 0

      if POLL_TYPE[options.status]?
       return false
      else
       return true

##Port base class

    class Port
     constructor: ->
      @handlers = {}
      @callsCache = {}
      @callsCounter = 0
      @id = parseInt Math.random() * 1000
      @responses = {}
      @wrappers =
       send: []
       respond: []
       handleCall: []
       handleResponse: []

     isStreaming: true

     onCallError: (msg, options) ->
      callsCache = @callsCache
      @callsCache = {}
      for id, call of callsCache
       if not call.callbacks.fail?
        ERROR_LOG 'fail callback not registered', call.method, call.data
       else
        call.callbacks.fail error: 'connectionError', msg: msg, options: options, {}

      @errorCallback msg, options

     onHandleError: (msg, data, options) ->
      @errorCallback msg, data
      response = new Response data, this, options
      response.fail msg

     errorCallback: (msg, options) ->
      ERROR_LOG msg, options

     wrap: (wrapper) ->
      for key, f of wrapper
       if @wrappers[key]?
        @wrappers[key].push f
       else
        this[key] = f

###Send RPC call

     send: (method, data, callbacks, options = {}) ->
      if (typeof callbacks) is 'function'
       callbacks =
        success: callbacks

      for f in @wrappers.send
       return unless f.apply this, [method, data, callbacks, options]

      params = @_createCall method, data, callbacks, options
      @_send params, callbacks

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}, callback = null) ->
      if not POLL_TYPE[status]?
       delete @responses[response.id]

      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions, callback

     respondMultiple: (response, list, portOptions = {}, callback = null) ->
      for d in list
       if not POLL_TYPE[d.status]?
        delete @responses[response.id]
        break

      data = []
      for d in list
       cancel = false
       d.options ?= {}
       for f in @wrappers.respond
        r = f.apply this, [response, d.status, d.data, d.options, portOptions]
        if not r
         cancel = true
         break

        continue if cancel

       data.push @_createResponse response, d.status, d.data, d.options

      return if data.length is 0

      data =
       type: 'list'
       list: data

      @_respond data, portOptions, callback

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call "#{@id}-#{@callsCounter}",
                      method
                      data
                      callbacks
                      options
                      this
      @callsCounter++
      @callsCache[call.id] = call

      params =
       type: 'call'
       id: call.id
       method: call.method
       data: call.data

      params[k] = v for k, v of options
      return params

###Create Response object

     _createResponse: (response, status, data, options) ->
      params =
       type: 'response'
       id: response.id
       status: status
       data: data

      params[k] = v for k, v of options

      return params

###Add handler

     on: (method, callback) ->
      @handlers[method] = callback

###Handle incoming message

     _handleMessage: (data, options, last = true) ->
      switch data.type
       when 'list'
        for d, i in data.list
         @_handleMessage d, options, (last and i + 1 is data.list.length)
       when 'response'
        try
         @_handleResponse data, options, last
        catch e
         @onerror? e
       when 'call'
        try
         @_handleCall data, options, last
        catch e
         @onerror? e
       when 'poll'
        try
         @_handlePoll data, options, last
        catch e
         @onerror? e

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @handlers[data.method]?
       @onHandleError "Unknown method: #{data.method}", data, options
       return
      @responses[data.id] = new Response data, this, options
      @handlers[data.method] data.data, data, @responses[data.id]

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       #Cannot reply
       @errorCallback "Response without call: #{data.id}", data
       return
      try
       if @callsCache[data.id].handle data.data, data
        delete @callsCache[data.id]
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

     _handlePoll: (data, options) ->
      @onHandleError "Poll not implemented", data, options

##WorkerPort class
Used for browser and worker

    class WorkerPort extends Port
     constructor: (worker) ->
      super()
      @worker = worker
      @worker.onmessage = @_onMessage.bind this
      #@worker.onerror = @onCallError.bind this

     _send: (data) ->
      @worker.postMessage data

     _respond: (data, options, callback) ->
      @worker.postMessage data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##FramePort class
Used for browser and worker

    class FramePort extends Port
     constructor: (source, dest) ->
      super()
      @source = source
      @dest = dest
      @source.addEventListener 'message', @_onMessage.bind this

     _send: (data) ->
      @dest.postMessage data, '*'

     _respond: (data, options, callback) ->
      @dest.postMessage data, '*'
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##SocketPort class

    class SocketPort extends Port
     constructor: (socket) ->
      super()
      @socket = socket
      @socket.on 'message', @_onMessage.bind this

     _send: (data) ->  @socket.emit 'message', data
     _respond: (data, options, callback) ->
      @worker.emit 'message', data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##ServerSocketPort class

    class ServerSocketPort extends Port
     constructor: (server) ->
      super()
      @server = server
      @server.on 'connection', @_onConnection.bind this

     _onConnection: (socket) ->
      new SocketPort handlers: @handlers, socket

##AJAX class

    class AjaxHttpPort extends Port
     constructor: (options) ->
      super()
      @protocol = options.protocol
      @host = options.host
      @port = options.port
      @path = options.path ? '/'
      @url = @path
      if @protocol?
       if @host? and not @port?
        @url = "#{@protocol}://#{@host}#{@path}"
       else if @host? and @port?
        @url = "#{@protocol}://#{@host}:#{@port}#{@path}"
      else
       if @host? and not @port?
        @url = "//#{@host}#{@path}"
       else if @host? and @port?
        @url = "//#{@host}:#{@port}#{@path}"

     isStreaming: false

     _onRequest: (xhr) ->
      return unless xhr.readyState is 4
      status = xhr.status
      if ((not status and xhr.responseText? and xhr.responseText != '') or
          (status >= 200 and status < 300) or
          (status is 304))
       try
        jsonData = JSON.parse xhr.responseText
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, xhr: xhr
      else
       @onCallError 'Cannot connect to server'

     _respond: (data, options, callback) ->
      @errorCallback 'AJAX cannot respond', data
      callback?()

     _send: (data) ->
      data = JSON.stringify data
      xhr = new XMLHttpRequest
      xhr.open 'POST', @url
      xhr.onreadystatechange = =>
       @_onRequest xhr
      xhr.setRequestHeader 'Accept', 'application/json'
      #xhr.setRequestHeader 'Content-Type', 'application/json'
      xhr.send data

     _handleResponse: (data, options, last = true) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      try
       if call.handle data.data, data
        delete @callsCache[data.id]
       else if last
        params =
         type: 'poll'
         id: call.id
        params[k] = v for k, v of call.options
        @_send params
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

##NodeHttpPort class

    class NodeHttpPort extends Port
     constructor: (options, http) ->
      super()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'
      @http = http
      @_createHttpOptions()

     isStreaming: false

     _createHttpOptions: ->
      @httpOptions =
       hostname: @host
       port: @port
       path: @path
       method: 'POST'
       agent: false
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

     _onRequest: (res) ->
      data = ''
      #LOG 'STATUS: ' + res.statusCode
      #LOG 'HEADERS: ' + JSON.stringify res.headers
      res.setEncoding 'utf8'
      res.on 'data', (chunk) ->
       data += chunk
      #LOG 'result', res
      res.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options, callback) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', Buffer.byteLength data, 'utf8'
      if callback?
       res.once 'finish', ->
        callback()
       res.once 'close', ->
        callback()

      res.write data
      res.end()

     _send: (data, callbacks) ->
      data = JSON.stringify data
      options = @httpOptions
      options.headers['content-length'] = Buffer.byteLength data, 'utf8'

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) =>
       try
        callbacks.fail? e
       catch err
        @onerror? err

      req.write data
      req.end()

     _handleResponse: (data, options, last = true) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      if not call.handle data.data, data
       return if not last
       params =
        type: 'poll'
        id: call.id
       params[k] = v for k, v of call.options
       @_send params, call.callbacks

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http, zlib = null) ->
      super()
      @port = options.port
      @http = http
      @zlib = zlib
      @allowOrigin = options.allowOrigin

     isStreaming: false

     _onRequest: (req, res) ->
      data = ''
      res.setHeader 'content-type', 'application/json'

      req.on 'data', (chunk) ->
       data += chunk
      req.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @errorCallback 'ParseError', e
        return

       @_handleMessage jsonData, response: res, request: req

     _respond: (data, options, callback) ->
      if @allowOrigin?
       options.response.setHeader 'Access-Control-Allow-Origin', @allowOrigin

      accept = options.request.headers['accept-encoding']
      accept ?= ''
      if not @zlib?
       accept = ''

      data = JSON.stringify data
      buffer = new Buffer data, 'utf8'
      if accept.match /\bgzip\b/
       options.response.setHeader 'content-encoding', 'gzip'
       @zlib.gzip buffer, (err, result) =>
        if err?
         return @errorCallback 'GZipeError', e
        @_sendBuffer result, options.response, callback
      else if accept.match /\bdeflate\b/
       options.response.setHeader 'content-encoding', 'deflate'
       @zlib.deflate buffer, (err, result) =>
        if err?
         return @errorCallback 'DeflateError', e
        @_sendBuffer result, options.response, callback
      else
       @_sendBuffer buffer, options.response, callback

     _sendBuffer: (buf, res, callback) ->
       res.setHeader 'content-length', buf.length
       if callback?
        res.once 'finish', ->
         callback()
        res.once 'close', ->
         callback()

       res.write buf
       res.end()

     listen: ->
      @server = @http.createServer @_onRequest.bind this
      @server.listen @port

     _handlePoll: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @responses[data.id]?
       @onHandleError "Poll without response: #{data.id}", data, options
       return
      @responses[data.id].setOptions options

##NodeHttpsServerPort class

    class NodeHttpsServerPort extends NodeHttpServerPort
     constructor: (options, http) ->
      super options, http
      @_key = options.key
      @_cert = options.cert

     listen: ->
      options =
       key: @_key
       cert: @_cert

      @server = @http.createServer options, @_onRequest.bind this
      @server.listen @port

#IO Module

    IO =
     addPort: (name, port) ->
      IO[name] = port

     ports:
      WorkerPort: WorkerPort
      FramePort: FramePort
      SocketPort: SocketPort
      AjaxHttpPort: AjaxHttpPort
      NodeHttpPort: NodeHttpPort
      NodeHttpServerPort: NodeHttpServerPort
      NodeHttpsServerPort: NodeHttpsServerPort
      ServerSocketPort: ServerSocketPort

     Helpers:
      progress: (from, to, func) ->
       (progress, data) ->
        func? progress * (to - from) + from, data

     setup_____: (options) ->
      options.workers ?= []
      switch options.platform
       when 'ui'
        for worker in options.workers
         IO.addPort worker.name, new WorkerPort worker.js
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'node'
        for socket in options.listenSockets
         IO.addPort socket.name, new SocketListenPort socket.port
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'worker'
        IO.addPort 'UI', new WorkerListenPort _self

    if exports?
     module.exports = IO
    else
     _self.IO = IO

    _self = this

    if console?.log?
     LOG = console.log.bind console
    else
     LOG = -> null

    if console?.error?
     ERROR_LOG = console.error.bind console
    else
     ERROR_LOG = -> null

    POLL_TYPE =
     progress: true

##Response class

    class Response
     constructor: (data, port, options) ->
      @id = data.id
      @port = port
      @options = options
      @queue = []
      @fresh = true

     progress: (progress, data, callback) ->
      @queue.push
       method: 'progress'
       data: data
       options: {progress: progress}
       callback: callback
      @_handleQueue()

     success: (data) ->
      @queue.push method: 'success', data: data, options: {}
      @_handleQueue()

     fail: (data) ->
      @queue.push method: 'fail', data: data, options: {}
      @_handleQueue()

     setOptions: (options) ->
      @options = options
      @fresh = true
      @_handleQueue()

     _multipleResponse: ->
      responseList = []
      callbacks = []
      for d in @queue
       responseList.push
        status: d.method
        data: d.data
        options: d.options
       if d.callback?
        callbacks.push d.callback

      done = ->
       for callback in callbacks
        callback()

      if @port.isStreaming
       @port.respondMultiple this, responseList, @options, done
      else if @fresh
       @port.respondMultiple this, responseList, @options, done
       @fresh = false

      @queue = []

     _handleQueue: ->
      return unless @queue.length > 0
      return if not @queue.isStreaming and not @fresh

      if @queue.length > 1
       return @_multipleResponse()

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options, d.callback
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @fresh = false

      @queue = []

##Call class

    class Call
     constructor: (@id, @method, @data, @callbacks, @options, @port) -> null

     handle: (data, options) ->
      if not @callbacks[options.status]?
       return if options.status is 'progress'
       #Handled by caller
       throw new Error "No callback registered #{@method} #{options.status}"
      self = this
      setTimeout ->
       try
        self.callbacks[options.status] data, options
       catch e
        self.port.onerror? e
      , 0

      if POLL_TYPE[options.status]?
       return false
      else
       return true

##Port base class

    class Port
     constructor: ->
      @handlers = {}
      @callsCache = {}
      @callsCounter = 0
      @id = parseInt Math.random() * 1000
      @responses = {}
      @wrappers =
       send: []
       respond: []
       handleCall: []
       handleResponse: []

     isStreaming: true

     onCallError: (msg, options) ->
      callsCache = @callsCache
      @callsCache = {}
      for id, call of callsCache
       if not call.callbacks.fail?
        ERROR_LOG 'fail callback not registered', call.method, call.data
       else
        call.callbacks.fail error: 'connectionError', msg: msg, options: options, {}

      @errorCallback msg, options

     onHandleError: (msg, data, options) ->
      @errorCallback msg, data
      response = new Response data, this, options
      response.fail msg

     errorCallback: (msg, options) ->
      ERROR_LOG msg, options

     wrap: (wrapper) ->
      for key, f of wrapper
       if @wrappers[key]?
        @wrappers[key].push f
       else
        this[key] = f

###Send RPC call

     send: (method, data, callbacks, options = {}) ->
      if (typeof callbacks) is 'function'
       callbacks =
        success: callbacks

      for f in @wrappers.send
       return unless f.apply this, [method, data, callbacks, options]

      params = @_createCall method, data, callbacks, options
      @_send params, callbacks

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}, callback = null) ->
      if not POLL_TYPE[status]?
       delete @responses[response.id]

      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions, callback

     respondMultiple: (response, list, portOptions = {}, callback = null) ->
      for d in list
       if not POLL_TYPE[d.status]?
        delete @responses[response.id]
        break

      data = []
      for d in list
       cancel = false
       d.options ?= {}
       for f in @wrappers.respond
        r = f.apply this, [response, d.status, d.data, d.options, portOptions]
        if not r
         cancel = true
         break

        continue if cancel

       data.push @_createResponse response, d.status, d.data, d.options

      return if data.length is 0

      data =
       type: 'list'
       list: data

      @_respond data, portOptions, callback

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call "#{@id}-#{@callsCounter}",
                      method
                      data
                      callbacks
                      options
                      this
      @callsCounter++
      @callsCache[call.id] = call

      params =
       type: 'call'
       id: call.id
       method: call.method
       data: call.data

      params[k] = v for k, v of options
      return params

###Create Response object

     _createResponse: (response, status, data, options) ->
      params =
       type: 'response'
       id: response.id
       status: status
       data: data

      params[k] = v for k, v of options

      return params

###Add handler

     on: (method, callback) ->
      @handlers[method] = callback

###Handle incoming message

     _handleMessage: (data, options, last = true) ->
      switch data.type
       when 'list'
        for d, i in data.list
         @_handleMessage d, options, (last and i + 1 is data.list.length)
       when 'response'
        try
         @_handleResponse data, options, last
        catch e
         @onerror? e
       when 'call'
        try
         @_handleCall data, options, last
        catch e
         @onerror? e
       when 'poll'
        try
         @_handlePoll data, options, last
        catch e
         @onerror? e

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @handlers[data.method]?
       @onHandleError "Unknown method: #{data.method}", data, options
       return
      @responses[data.id] = new Response data, this, options
      @handlers[data.method] data.data, data, @responses[data.id]

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       #Cannot reply
       @errorCallback "Response without call: #{data.id}", data
       return
      try
       if @callsCache[data.id].handle data.data, data
        delete @callsCache[data.id]
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

     _handlePoll: (data, options) ->
      @onHandleError "Poll not implemented", data, options

##WorkerPort class
Used for browser and worker

    class WorkerPort extends Port
     constructor: (worker) ->
      super()
      @worker = worker
      @worker.onmessage = @_onMessage.bind this
      #@worker.onerror = @onCallError.bind this

     _send: (data) ->
      @worker.postMessage data

     _respond: (data, options, callback) ->
      @worker.postMessage data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##FramePort class
Used for browser and worker

    class FramePort extends Port
     constructor: (source, dest) ->
      super()
      @source = source
      @dest = dest
      @source.addEventListener 'message', @_onMessage.bind this

     _send: (data) ->
      @dest.postMessage data, '*'

     _respond: (data, options, callback) ->
      @dest.postMessage data, '*'
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##SocketPort class

    class SocketPort extends Port
     constructor: (socket) ->
      super()
      @socket = socket
      @socket.on 'message', @_onMessage.bind this

     _send: (data) ->  @socket.emit 'message', data
     _respond: (data, options, callback) ->
      @worker.emit 'message', data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##ServerSocketPort class

    class ServerSocketPort extends Port
     constructor: (server) ->
      super()
      @server = server
      @server.on 'connection', @_onConnection.bind this

     _onConnection: (socket) ->
      new SocketPort handlers: @handlers, socket

##AJAX class

    class AjaxHttpPort extends Port
     constructor: (options) ->
      super()
      @protocol = options.protocol
      @host = options.host
      @port = options.port
      @path = options.path ? '/'
      @url = @path
      if @protocol?
       if @host? and not @port?
        @url = "#{@protocol}://#{@host}#{@path}"
       else if @host? and @port?
        @url = "#{@protocol}://#{@host}:#{@port}#{@path}"
      else
       if @host? and not @port?
        @url = "//#{@host}#{@path}"
       else if @host? and @port?
        @url = "//#{@host}:#{@port}#{@path}"

     isStreaming: false

     _onRequest: (xhr) ->
      return unless xhr.readyState is 4
      status = xhr.status
      if ((not status and xhr.responseText? and xhr.responseText != '') or
          (status >= 200 and status < 300) or
          (status is 304))
       try
        jsonData = JSON.parse xhr.responseText
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, xhr: xhr
      else
       @onCallError 'Cannot connect to server'

     _respond: (data, options, callback) ->
      @errorCallback 'AJAX cannot respond', data
      callback?()

     _send: (data) ->
      data = JSON.stringify data
      xhr = new XMLHttpRequest
      xhr.open 'POST', @url
      xhr.onreadystatechange = =>
       @_onRequest xhr
      xhr.setRequestHeader 'Accept', 'application/json'
      #xhr.setRequestHeader 'Content-Type', 'application/json'
      xhr.send data

     _handleResponse: (data, options, last = true) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      try
       if call.handle data.data, data
        delete @callsCache[data.id]
       else if last
        params =
         type: 'poll'
         id: call.id
        params[k] = v for k, v of call.options
        @_send params
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

##NodeHttpPort class

    class NodeHttpPort extends Port
     constructor: (options, http) ->
      super()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'
      @http = http
      @_createHttpOptions()

     isStreaming: false

     _createHttpOptions: ->
      @httpOptions =
       hostname: @host
       port: @port
       path: @path
       method: 'POST'
       agent: false
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

     _onRequest: (res) ->
      data = ''
      #LOG 'STATUS: ' + res.statusCode
      #LOG 'HEADERS: ' + JSON.stringify res.headers
      res.setEncoding 'utf8'
      res.on 'data', (chunk) ->
       data += chunk
      #LOG 'result', res
      res.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options, callback) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', Buffer.byteLength data, 'utf8'
      if callback?
       res.once 'finish', ->
        callback()
       res.once 'close', ->
        callback()

      res.write data
      res.end()

     _send: (data, callbacks) ->
      data = JSON.stringify data
      options = @httpOptions
      options.headers['content-length'] = Buffer.byteLength data, 'utf8'

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) =>
       try
        callbacks.fail? e
       catch err
        @onerror? err

      req.write data
      req.end()

     _handleResponse: (data, options, last = true) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      if not call.handle data.data, data
       return if not last
       params =
        type: 'poll'
        id: call.id
       params[k] = v for k, v of call.options
       @_send params, call.callbacks

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http, zlib = null) ->
      super()
      @port = options.port
      @http = http
      @zlib = zlib
      @allowOrigin = options.allowOrigin

     isStreaming: false

     _onRequest: (req, res) ->
      data = ''
      res.setHeader 'content-type', 'application/json'

      req.on 'data', (chunk) ->
       data += chunk
      req.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @errorCallback 'ParseError', e
        return

       @_handleMessage jsonData, response: res, request: req

     _respond: (data, options, callback) ->
      if @allowOrigin?
       options.response.setHeader 'Access-Control-Allow-Origin', @allowOrigin

      accept = options.request.headers['accept-encoding']
      accept ?= ''
      if not @zlib?
       accept = ''

      data = JSON.stringify data
      buffer = new Buffer data, 'utf8'
      if accept.match /\bgzip\b/
       options.response.setHeader 'content-encoding', 'gzip'
       @zlib.gzip buffer, (err, result) =>
        if err?
         return @errorCallback 'GZipeError', e
        @_sendBuffer result, options.response, callback
      else if accept.match /\bdeflate\b/
       options.response.setHeader 'content-encoding', 'deflate'
       @zlib.deflate buffer, (err, result) =>
        if err?
         return @errorCallback 'DeflateError', e
        @_sendBuffer result, options.response, callback
      else
       @_sendBuffer buffer, options.response, callback

     _sendBuffer: (buf, res, callback) ->
       res.setHeader 'content-length', buf.length
       if callback?
        res.once 'finish', ->
         callback()
        res.once 'close', ->
         callback()

       res.write buf
       res.end()

     listen: ->
      @server = @http.createServer @_onRequest.bind this
      @server.listen @port

     _handlePoll: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @responses[data.id]?
       @onHandleError "Poll without response: #{data.id}", data, options
       return
      @responses[data.id].setOptions options

##NodeHttpsServerPort class

    class NodeHttpsServerPort extends NodeHttpServerPort
     constructor: (options, http) ->
      super options, http
      @_key = options.key
      @_cert = options.cert

     listen: ->
      options =
       key: @_key
       cert: @_cert

      @server = @http.createServer options, @_onRequest.bind this
      @server.listen @port

#IO Module

    IO =
     addPort: (name, port) ->
      IO[name] = port

     ports:
      WorkerPort: WorkerPort
      FramePort: FramePort
      SocketPort: SocketPort
      AjaxHttpPort: AjaxHttpPort
      NodeHttpPort: NodeHttpPort
      NodeHttpServerPort: NodeHttpServerPort
      NodeHttpsServerPort: NodeHttpsServerPort
      ServerSocketPort: ServerSocketPort

     Helpers:
      progress: (from, to, func) ->
       (progress, data) ->
        func? progress * (to - from) + from, data

     setup_____: (options) ->
      options.workers ?= []
      switch options.platform
       when 'ui'
        for worker in options.workers
         IO.addPort worker.name, new WorkerPort worker.js
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'node'
        for socket in options.listenSockets
         IO.addPort socket.name, new SocketListenPort socket.port
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'worker'
        IO.addPort 'UI', new WorkerListenPort _self

    if exports?
     module.exports = IO
    else
     _self.IO = IO


minor commenting change

minor commenting change

# Property - controller of Object properties

The `Property` class is the *secretive shadowy* element that governs
`Object` behavior and are bound to the `Object` via
`Object.defineProperty`. It acts like a shadow `Proxy/Reflector` to
the `Object` instance and provides tight control via the
`Getter/Setter` interfaces.

The `Property` instances attach themselves to the `Object[Symbol.for('property')]` property
and are rarely accessed directly - but they are the **fundamental**
actors that *actualize* YANG schema compliance into ordinary JS
objects.

Below are list of properties available to every instance of `Property`:

property | type | mapping | description
--- | --- | --- | ---
name   | string | direct | name of the property
schema | object | direct | a schema instance (usually [Yang](./src/yang.listcoffee))
state  | object | direct | *private* object holding internal state
container | object | access(state) | reference to object containing this property
configurable | boolean | getter(state) | defines whether this property can be redefined
enumerable   | boolean | getter(state) | defines whether this property is enumerable
content | any | computed | getter/setter for `state.value`
context | object | computed | dynamically generated using [context](./src/context.coffee)
root  | [Property](./src/property.litcoffee) | computed | dynamically returns the root Property instance
props | array(Property) | computed | returns children Property instances
key   | string/number | computed | conditionally returns unique key for Property if a list item
path  | [XPath](./src/xpath.coffee) | computed | dynamically generate XPath for this Property from root

## Class Property

    debug    = require('debug')('yang:property') # if process.env.DEBUG?
    co       = require 'co'
    delegate = require 'delegates'
    clone    = require 'clone'
    Emitter  = require('events').EventEmitter
    context  = require './context'
    XPath    = require './xpath'
    kProp    = Symbol.for('property')

    class Property

      @property: (prop, desc) ->
        Object.defineProperty @prototype, prop, desc

      constructor: (@name, @schema={}) ->
        unless this instanceof Property then return new Property arguments...

        @state =
          value: null
          container: null
          configurable: true
          enumerable: @binding?
          mutable: @schema.config?.valueOf() isnt false
        Object.setPrototypeOf @state, Emitter.prototype

        @schema.kind ?= 'anydata'

        # Bind the get/set functions to call with 'this' bound to this
        # Property instance.  This is needed since native Object
        # Getter/Setter uses the Object itself as 'this'
        @set = @set.bind this
        @get = @get.bind this
        # expose the BoundThis for the set/get
        @set.bound = @get.bound = this

        # soft freeze this instance
        Object.preventExtensions this

      delegate @prototype, 'state'
        .method 'once'
        .method 'on'
        .access 'container'
        .getter 'configurable'
        .getter 'enumerable'
        .getter 'mutable'
        .getter 'prev'

      delegate @prototype, 'schema'
        .getter 'kind'
        .getter 'type'
        .getter 'default'
        .getter 'binding'

### Computed Properties

      @property 'content',
        get: -> @state.value
        set: (value) -> @set value, { force: true, suppress: true }

      @property 'context',
        get: ->
          ctx = Object.create(context)
          ctx.state = {}
          ctx.property = this
          Object.preventExtensions ctx
          return ctx

      @property 'parent', get: -> @container?[kProp]

      @property 'root',
        get: ->
          return this if @kind is 'module'
          root = switch
            when @parent is this then this
            when @parent instanceof Property then @parent.root
            else this
          @state.path = undefined unless @state.root is root
          return @state.root = root

      @property 'children',
        get: ->
          return [] unless @content instanceof Object
          children = []
          for own k of @content
            desc = Object.getOwnPropertyDescriptor(@content, k)
            children.push desc.get.bound if desc?.get?.bound instanceof Property
          return children

      @property 'key',
        get: ->
          return unless @schema is @parent?.schema
          switch
            when @content not instanceof Object  then @name + 1
            when @content.hasOwnProperty('@key') then @content['@key']
            when Array.isArray @container
              for idx, item of @container when item is @content
                idx = Number(idx) unless (Number.isNaN (Number idx))
                return idx+1
              return undefined

      @property 'path',
        get: ->
          if this is @root
            entity = switch
              when @kind is 'module' then '/'
              else '.'
            return XPath.parse entity, @schema
          key = @key
          return @state.path if @state.path? and not key?
          @debug "[path] #{@kind}(#{@name}) has #{key} #{typeof key}"
          entity = switch typeof key
            when 'number' then ".[#{key}]"
            when 'string' then ".[key('#{key}')]"
            else switch
              when @kind is 'list' then @schema.datakey
              else @name
          @debug "[path] #{@parent.name} + #{entity}"
          return @state.path = @parent.path.clone().append entity

## Instance-level methods

      clone: ->
        @debug "[clone] cloning with #{@children.length} properties"
        copy = (new @constructor @name, @schema)
        copy.state[k] = v for k, v of @state
        return copy

      emit: (event) ->
        @state.emit arguments...
        unless this is @root
          @debug "[emit] '#{event}' to '#{@root.name}'"
          @root.emit arguments...

### join (obj)

This call is the primary mechanism via which the `Property` instance
attaches itself to the provided target `obj`. It defines itself in the
target `obj` via `Object.defineProperty`.

      join: (obj, opts={ replace: false, suppress: false, force: false }) ->
        return obj unless obj instanceof Object

        detached = true unless @container?
        @container = obj

        if Array.isArray(obj) and Array.isArray(@content)
          @debug @content
          throw @error "cannot join array property into list container"
        if @kind is 'list' and not Array.isArray(obj) and @content? and not Array.isArray(@content)
          throw @error "cannot join non-list array property into containing object"

        # if joining for the first time, apply existing data unless explicit replace
        exists = obj[@name]
        if detached and opts.replace isnt true
          @debug "[join] applying existing data for #{@name} to:"
          @debug obj
          opts.suppress = true
          @set exists, opts

        # TODO: should produce meaningful warning?
        try Object.defineProperty obj, @name, this
        @debug "[join] attached into #{obj.constructor.name} container"
        return obj

### get (pattern)

This is the main `Getter` for the target object's property value. When
called with optional `pattern` it will perform an internal
[find](#find-xpath) operation to traverse/locate that value being
requested instead of returning its own `@content`.

It also provides special handling based on different types of
`@content` currently held.

When `@content` is a function, it will call it with the current
`@context` instance as the bound context for the function being
called.

      get: (pattern, prop=false) -> switch
        when pattern? and prop then @in pattern
        when pattern?
          try match = @find pattern
          return unless match? and match.length
          switch
            when match.length is 1 then match[0].content
            when match.length > 1  then match.map (x) -> x.content
            else undefined
        when @kind in [ 'rpc', 'action' ] then switch
          when @binding? then @do.bind this
          else @content
        else
          if @binding? and not (@kind is 'list' and @key?)
            try return @binding.call @context
            catch e
              throw @error "issue executing registered function binding during get(): #{e.message}", e
          @content

### set (value)

This is the main `Setter` for the target object's property value.  It
utilizes internal `@schema` attribute if available to enforce schema
validations.

      set: (value, opts={ force: false, suppress: false }) ->
        @debug "[set] enter with:"
        @debug value
        #@debug opts
        return this if value is @content and not opts.force

        unless @mutable or not value? or opts.force
          throw @error "cannot set data on read-only element"

        try
          unless value instanceof Function
            if value[kProp] instanceof Property and value[kProp] isnt this
              @debug "[set] cloning existing property for assignment"
              value = clone(value)
            value = Object.create(value) unless Object.isExtensible(value)
          Object.defineProperty value, kProp, configurable: true, value: this

        value = switch
          when @schema.apply?
            @schema.apply value, @context.with(opts)
          else value
        return this if value instanceof Error
        try
          Object.defineProperty value, kProp, value: this
          Object.defineProperty value, '$', value: @get.bind(this)
          if @schema.nodes.length and @kind isnt 'module'
            for own k of value
              desc = Object.getOwnPropertyDescriptor value, k
              if desc.writable is true and not @schema.locate(k)?
                @debug "[set] hiding non-schema defined property: #{k}"
                Object.defineProperty value, k, enumerable: false

        @state.prev = @state.value
        @state.enumerable = value? or @binding?

        if @binding?.length is 1 and not opts.force and @kind not in [ 'action', 'rpc' ]
          try @binding.call @context, value
          catch e
            @debug e
            throw @error "issue executing registered function binding during set(): #{e.message}", e
        else
          @state.value = value

        try Object.defineProperty @container, @name,
          configurable: true
          enumerable: @state.enumerable

        @emit 'update', this if this is @root or not opts.suppress
        @debug "[set] completed"
        return this

### merge (value)

Performs a granular merge of `value` into existing `@content` if
available, otherwise performs [set](#set-value) operation.

      merge: (value, opts={ replace: true, suppress: false }) ->
        opts.replace ?= true
        unless @content instanceof Object and @kind is 'list'
          opts.replace = false
          return @set value, opts

        value = value[@name] if value? and value.hasOwnProperty? @name
        return this unless value instanceof Object

        if Array.isArray @content
          length = @content.length
          @debug "[merge] merging into existing Array(#{length}) for #{@name}"
          @debug value
          # here we clone this Property and update with only the newly merged values
          # XXX - this logic needs refinement, it doesn't handle min-elements condition properly
          value = [ value ] unless Array.isArray value
          copy = @clone()
          copy.set value, force: opts.force, suppress: true
          @debug "[merge] combining and applying schema"
          if @schema.key? and opts.replace
            exists = {}
            @content.forEach (item) ->
              key = item['@key']
              exists[key] = item
            @debug "[merge] reducing existing keys"
            conflicts = 0
            newitems = copy.content.reduce ((a, item) ->
              key = item['@key']
              item[kProp].name -= conflicts
              if key of exists
                conflicts++
                exists[key][kProp].merge item, opts
              else
                a.push item
              return a
            ), []
            combine = @content.concat newitems
          else
            newitems = copy.content
            combine = @content.concat newitems
          attr.apply combine, @context.with(opts) for attr in @schema.attrs
          newitems.forEach (item) =>
            item[kProp].name += length
            item[kProp].join @content, opts
          @emit 'update', this unless opts.suppress
          return copy
        else
          @debug "[merge] merging into existing Object(#{Object.keys(@content).length}) for #{@name}"
          # TODO: protect this as a transaction?
          @in(k)?.merge(v, opts) for own k, v of value when @content.hasOwnProperty k
          # TODO: need to reapply schema to self
          return this

### create (value)

A simple convenience wrap around the above [merge](#merge-value) operation.

      create: (value) ->
        if not @content? and @kind is 'list' and not Array.isArray value
          value = [ value ]
        res = @merge value, replace: false
        @emit 'create', res
        return res

### remove

The reverse of [join](#join-obj), it will detach itself from the
`@container` parent object.

      remove: ->
        return this unless @container?
        if @key?
          #@container.splice @name, 1
          delete @container[@name]
        else
          @state.enumerable = false
          @state.value = undefined unless @kind is 'list'
          Object.defineProperty @container, @name, enumerable: false
        @emit 'update', @parent if @parent?
        @emit 'delete', this
        return this

### find (pattern)

This helper routine can be used to allow traversal to other elements
in the data tree from the relative location of the current `Property`
instance. It returns matching `Property` instances based on the
provided `pattern` in the form of XPATH or YPATH.

It is internally used via [get](#get) and generally used inside
controller logic bound inside the [Yang expression](./yang.litcoffee)
as well as event handler listening on [Model](./model.litcoffee)
events.

It *always* returns an array (empty to denote no match) unless it
encounters an error, in which case it will throw an Error.

      find: (pattern='.', opts={}) ->
        @debug "[find] #{pattern}"
        unless pattern instanceof XPath
          if /^\.\.\//.test(pattern) and @parent?
            return @parent.find pattern.replace(/^\.\.\//, ''), opts
          if /^\//.test(pattern) and this isnt @root
            return @root.find pattern, opts
          pattern = XPath.parse pattern, @schema

        @debug "[find] using #{pattern}"
        if opts.root or not @container? or pattern.tag not in [ '/', '..' ]
          @debug "[find] apply #{pattern}"
          @debug @content
          pattern.apply(@content).props ? []
        else switch
          when pattern.tag is '/'  and @parent? then @parent.find pattern, opts
          when pattern.tag is '..' and @parent? then @parent.find pattern.xpath, opts
          else []

### in (pattern)

A convenience routine to locate one or more matching Property
instances based on `pattern` (XPATH or YPATH) from this Model.

      in: (pattern) ->
        try props = @find pattern
        return unless props? and props.length
        return switch
          when props.length > 1 then props
          else props[0]

### do ()

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

Always returns a Promise.

      invoke: ->
        console.warn "DEPRECATION: please use .do() instead"
        @do arguments...

      do: (input={}) ->
        unless (@binding instanceof Function) or (@content instanceof Function)
          return Promise.reject @error "cannot perform action on a property without function"
        transaction = true if @root.kind is 'module' and @root.transactable isnt true
        try
          @debug "[do] executing method: #{@name}"
          @debug input
          @root.transactable = true if transaction
          ctx = @context
          ctx.state[kProp] = this
          @schema.input?.eval  ctx.state, {}
          @schema.output?.eval ctx.state, {}
          ctx.input = input
          # 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)}"
            @debug @binding.toString()
            res = @binding.call ctx, input
            ctx.output ?= res
          else
            @debug "[do] calling assigned function: #{@content.name}"
            @debug @content.toString()
            ctx.output = @content.call @container, input
          return co =>
            @debug "[do] evaluating output schema"
            ctx.output = yield Promise.resolve ctx.output
            @debug "[do] finish setting output"
            @emit 'done', ctx
            if transaction
              @root.save()
              @root.transactable = false
            return ctx.output
        catch e
          @debug e
          if transaction
            @root.rollback()
            @root.transactable = false
          return Promise.reject e

### error (msg)

Provides more contextual error message pertaining to the Property instance.

      error: (msg, ctx=this) ->
        at = "#{@path}"
        at += @name if at is '/'
        err = new Error "[#{at}] #{msg}"
        err.name = 'PropertyError'
        err.context = ctx
        @emit 'error', err, this
        return err

      debug: (msg) ->
        if debug? then switch typeof msg
          when 'object' then debug msg
          else
            node = this
            prefix = [ @name ]
            prefix.unshift node.name while (node = node.parent)
            debug "[#{prefix.join('/')}] #{msg}"

### inspect

      inspect: ->
        return {
          name:   @schema.tag ? @name
          kind:   @schema.kind
          key:    @key
          xpath:  @path.toString()
          schema: @schema.toJSON tag: false, extended: true
          active: @enumerable
          readonly: not @mutable
        }

### toJSON

This call creates a new copy of the current `Property.content`
completely detached/unbound to the underlying data schema. It's main
utility is to represent the current data state for subsequent
serialization/transmission. It accepts optional argument `tag` which
when called with `false` will not tag the produced object with the
current property's `@name`.

      toJSON: (tag=true) ->
        copy = (src) ->
          return unless src? and typeof src isnt 'function'
          if typeof src is 'object'
            try res = new src.constructor
            catch then res = {}
            for own k, v of src when typeof v isnt 'function'
              res[k] = copy v
            return res
          src.constructor.call src, src
        value = copy @get()
        value ?= [] if @kind is 'list'
        if tag
          name = switch
            when @kind is 'list' then @schema.datakey
            else @name
          "#{name}": value
        else value

## Export Property Class

    module.exports = Property

# Property - controller of Object properties

The `Property` class is the *secretive shadowy* element that governs
`Object` behavior and are bound to the `Object` via
`Object.defineProperty`. It acts like a shadow `Proxy/Reflector` to
the `Object` instance and provides tight control via the
`Getter/Setter` interfaces.

The `Property` instances attach themselves to the `Object[Symbol.for('property')]` property
and are rarely accessed directly - but they are the **fundamental**
actors that *actualize* YANG schema compliance into ordinary JS
objects.

Below are list of properties available to every instance of `Property`:

property | type | mapping | description
--- | --- | --- | ---
name   | string | direct | name of the property
schema | object | direct | a schema instance (usually [Yang](./src/yang.listcoffee))
state  | object | direct | *private* object holding internal state
container | object | access(state) | reference to object containing this property
configurable | boolean | getter(state) | defines whether this property can be redefined
enumerable   | boolean | getter(state) | defines whether this property is enumerable
content | any | computed | getter/setter for `state.value`
context | object | computed | dynamically generated using [context](./src/context.coffee)
root  | [Property](./src/property.litcoffee) | computed | dynamically returns the root Property instance
props | array(Property) | computed | returns children Property instances
key   | string/number | computed | conditionally returns unique key for Property if a list item
path  | [XPath](./src/xpath.coffee) | computed | dynamically generate XPath for this Property from root

## Class Property

    debug    = require('debug')('yang:property') # if process.env.DEBUG?
    co       = require 'co'
    delegate = require 'delegates'
    clone    = require 'clone'
    Emitter  = require('events').EventEmitter
    context  = require './context'
    XPath    = require './xpath'
    kProp    = Symbol.for('property')

    class Property

      @property: (prop, desc) ->
        Object.defineProperty @prototype, prop, desc

      constructor: (@name, @schema={}) ->
        unless this instanceof Property then return new Property arguments...

        @state =
          value: null
          container: null
          configurable: true
          enumerable: @binding?
          mutable: @schema.config?.valueOf() isnt false
        Object.setPrototypeOf @state, Emitter.prototype

        @schema.kind ?= 'anydata'

        # Bind the get/set functions to call with 'this' bound to this
        # Property instance.  This is needed since native Object
        # Getter/Setter uses the Object itself as 'this'
        @set = @set.bind this
        @get = @get.bind this
        # expose the BoundThis for the set/get
        @set.bound = @get.bound = this

        # soft freeze this instance
        Object.preventExtensions this

      delegate @prototype, 'state'
        .method 'once'
        .method 'on'
        .access 'container'
        .getter 'configurable'
        .getter 'enumerable'
        .getter 'mutable'
        .getter 'prev'

      delegate @prototype, 'schema'
        .getter 'kind'
        .getter 'type'
        .getter 'default'
        .getter 'binding'

### Computed Properties

      @property 'content',
        get: -> @state.value
        set: (value) -> @set value, { force: true, suppress: true }

      @property 'context',
        get: ->
          ctx = Object.create(context)
          ctx.state = {}
          ctx.property = this
          Object.preventExtensions ctx
          return ctx

      @property 'parent', get: -> @container?[kProp]

      @property 'root',
        get: ->
          return this if @kind is 'module'
          root = switch
            when @parent is this then this
            when @parent instanceof Property then @parent.root
            else this
          @state.path = undefined unless @state.root is root
          return @state.root = root

      @property 'children',
        get: ->
          return [] unless @content instanceof Object
          children = []
          for own k of @content
            desc = Object.getOwnPropertyDescriptor(@content, k)
            children.push desc.get.bound if desc?.get?.bound instanceof Property
          return children

      @property 'key',
        get: ->
          return unless @schema is @parent?.schema
          switch
            when @content not instanceof Object  then @name + 1
            when @content.hasOwnProperty('@key') then @content['@key']
            when Array.isArray @container
              for idx, item of @container when item is @content
                idx = Number(idx) unless (Number.isNaN (Number idx))
                return idx+1
              return undefined

      @property 'path',
        get: ->
          if this is @root
            entity = switch
              when @kind is 'module' then '/'
              else '.'
            return XPath.parse entity, @schema
          key = @key
          return @state.path if @state.path? and not key?
          @debug "[path] #{@kind}(#{@name}) has #{key} #{typeof key}"
          entity = switch typeof key
            when 'number' then ".[#{key}]"
            when 'string' then ".[key('#{key}')]"
            else switch
              when @kind is 'list' then @schema.datakey
              else @name
          @debug "[path] #{@parent.name} + #{entity}"
          return @state.path = @parent.path.clone().append entity

## Instance-level methods

      clone: ->
        @debug "[clone] cloning with #{@children.length} properties"
        copy = (new @constructor @name, @schema)
        copy.state[k] = v for k, v of @state
        return copy

      emit: (event) ->
        @state.emit arguments...
        unless this is @root
          @debug "[emit] '#{event}' to '#{@root.name}'"
          @root.emit arguments...

### join (obj)

This call is the primary mechanism via which the `Property` instance
attaches itself to the provided target `obj`. It defines itself in the
target `obj` via `Object.defineProperty`.

      join: (obj, opts={ replace: false, suppress: false, force: false }) ->
        return obj unless obj instanceof Object

        detached = true unless @container?
        @container = obj

        if Array.isArray(obj) and Array.isArray(@content)
          @debug @content
          throw @error "cannot join array property into list container"
        if @kind is 'list' and not Array.isArray(obj) and @content? and not Array.isArray(@content)
          throw @error "cannot join non-list array property into containing object"

        # if joining for the first time, apply existing data unless explicit replace
        exists = obj[@name]
        if detached and opts.replace isnt true
          @debug "[join] applying existing data for #{@name} to:"
          @debug obj
          opts.suppress = true
          @set exists, opts

        # TODO: should produce meaningful warning?
        try Object.defineProperty obj, @name, this
        @debug "[join] attached into #{obj.constructor.name} container"
        return obj

### get (pattern)

This is the main `Getter` for the target object's property value. When
called with optional `pattern` it will perform an internal
[find](#find-xpath) operation to traverse/locate that value being
requested instead of returning its own `@content`.

It also provides special handling based on different types of
`@content` currently held.

When `@content` is a function, it will call it with the current
`@context` instance as the bound context for the function being
called.

      get: (pattern, prop=false) -> switch
        when pattern? and prop then @in pattern
        when pattern?
          try match = @find pattern
          return unless match? and match.length
          switch
            when match.length is 1 then match[0].content
            when match.length > 1  then match.map (x) -> x.content
            else undefined
        when @kind in [ 'rpc', 'action' ] then switch
          when @binding? then @do.bind this
          else @content
        else
          if @binding? and not (@kind is 'list' and @key?)
            try return @binding.call @context
            catch e
              throw @error "issue executing registered function binding during get(): #{e.message}", e
          @content

### set (value)

This is the main `Setter` for the target object's property value.  It
utilizes internal `@schema` attribute if available to enforce schema
validations.

      set: (value, opts={ force: false, suppress: false }) ->
        @debug "[set] enter with:"
        @debug value
        #@debug opts
        return this if value is @content and not opts.force

        unless @mutable or not value? or opts.force
          throw @error "cannot set data on read-only element"

        try
          unless value instanceof Function
            if value[kProp] instanceof Property and value[kProp] isnt this
              @debug "[set] cloning existing property for assignment"
              value = clone(value)
            value = Object.create(value) unless Object.isExtensible(value)
          Object.defineProperty value, kProp, configurable: true, value: this

        value = switch
          when @schema.apply?
            @schema.apply value, @context.with(opts)
          else value
        return this if value instanceof Error
        try
          Object.defineProperty value, kProp, value: this
          Object.defineProperty value, '$', value: @get.bind(this)
          if @schema.nodes.length and @kind isnt 'module'
            for own k of value
              desc = Object.getOwnPropertyDescriptor value, k
              if desc.writable is true and not @schema.locate(k)?
                @debug "[set] hiding non-schema defined property: #{k}"
                Object.defineProperty value, k, enumerable: false

        @state.prev = @state.value
        @state.enumerable = value? or @binding?

        if @binding?.length is 1 and not opts.force and @kind not in [ 'action', 'rpc' ]
          try @binding.call @context, value
          catch e
            @debug e
            throw @error "issue executing registered function binding during set(): #{e.message}", e
        else
          @state.value = value

        try Object.defineProperty @container, @name,
          configurable: true
          enumerable: @state.enumerable

        @emit 'update', this if this is @root or not opts.suppress
        @debug "[set] completed"
        return this

### merge (value)

Performs a granular merge of `value` into existing `@content` if
available, otherwise performs [set](#set-value) operation.

      merge: (value, opts={ replace: true, suppress: false }) ->
        opts.replace ?= true
        unless @content instanceof Object and @kind is 'list'
          opts.replace = false
          return @set value, opts

        value = value[@name] if value? and value.hasOwnProperty? @name
        return this unless value instanceof Object

        if Array.isArray @content
          length = @content.length
          @debug "[merge] merging into existing Array(#{length}) for #{@name}"
          @debug value
          # here we clone this Property and update with only the newly merged values
          # XXX - this logic needs refinement, it doesn't handle min-elements condition properly
          value = [ value ] unless Array.isArray value
          copy = @clone()
          copy.set value, force: opts.force, suppress: true
          @debug "[merge] combining and applying schema"
          if @schema.key? and opts.replace
            exists = {}
            @content.forEach (item) ->
              key = item['@key']
              exists[key] = item
            @debug "[merge] reducing existing keys"
            conflicts = 0
            newitems = copy.content.reduce ((a, item) ->
              key = item['@key']
              item[kProp].name -= conflicts
              if key of exists
                conflicts++
                exists[key][kProp].merge item, opts
              else
                a.push item
              return a
            ), []
            combine = @content.concat newitems
          else
            newitems = copy.content
            combine = @content.concat newitems
          attr.apply combine, @context.with(opts) for attr in @schema.attrs
          newitems.forEach (item) =>
            item[kProp].name += length
            item[kProp].join @content, opts
          @emit 'update', this unless opts.suppress
          return copy
        else
          @debug "[merge] merging into existing Object(#{Object.keys(@content).length}) for #{@name}"
          # TODO: protect this as a transaction?
          @in(k)?.merge(v, opts) for own k, v of value when @content.hasOwnProperty k
          # TODO: need to reapply schema to self
          return this

### create (value)

A simple convenience wrap around the above [merge](#merge-value) operation.

      create: (value) ->
        if not @content? and @kind is 'list' and not Array.isArray value
          value = [ value ]
        res = @merge value, replace: false
        @emit 'create', res
        return res

### remove

The reverse of [join](#join-obj), it will detach itself from the
`@container` parent object.

      remove: ->
        return this unless @container?
        if @key?
          #@container.splice @name, 1
          delete @container[@name]
        else
          @state.enumerable = false
          @state.value = undefined unless @kind is 'list'
          Object.defineProperty @container, @name, enumerable: false
        @emit 'update', @parent if @parent?
        @emit 'delete', this
        return this

### find (pattern)

This helper routine can be used to allow traversal to other elements
in the data tree from the relative location of the current `Property`
instance. It returns matching `Property` instances based on the
provided `pattern` in the form of XPATH or YPATH.

It is internally used via [get](#get) and generally used inside
controller logic bound inside the [Yang expression](./yang.litcoffee)
as well as event handler listening on [Model](./model.litcoffee)
events.

It *always* returns an array (empty to denote no match) unless it
encounters an error, in which case it will throw an Error.

      find: (pattern='.', opts={}) ->
        @debug "[find] #{pattern}"
        unless pattern instanceof XPath
          if /^\.\.\//.test(pattern) and @parent?
            return @parent.find pattern.replace(/^\.\.\//, ''), opts
          if /^\//.test(pattern) and this isnt @root
            return @root.find pattern, opts
          pattern = XPath.parse pattern, @schema

        @debug "[find] using #{pattern}"
        if opts.root or not @container? or pattern.tag not in [ '/', '..' ]
          @debug "[find] apply #{pattern}"
          @debug @content
          pattern.apply(@content).props ? []
        else switch
          when pattern.tag is '/'  and @parent? then @parent.find pattern, opts
          when pattern.tag is '..' and @parent? then @parent.find pattern.xpath, opts
          else []

### in (pattern)

A convenience routine to locate one or more matching Property
instances based on `pattern` (XPATH or YPATH) from this Model.

      in: (pattern) ->
        try props = @find pattern
        return unless props? and props.length
        return switch
          when props.length > 1 then props
          else props[0]

### do ()

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

Always returns a Promise.

      invoke: ->
        console.warn "DEPRECATION: please use .do() instead"
        @do arguments...

      do: (input={}) ->
        unless (@binding instanceof Function) or (@content instanceof Function)
          return Promise.reject @error "cannot perform action on a property without function"
        transaction = true if @root.kind is 'module' and @root.transactable isnt true
        try
          @debug "[do] executing method: #{@name}"
          @debug input
          @root.transactable = true if transaction
          ctx = @context
          ctx.state[kProp] = this
          @schema.input?.eval  ctx.state, {}
          @schema.output?.eval ctx.state, {}
          ctx.input = input
          # first apply schema bound function (if availble), then
          # execute assigned function (if available and not 'missing')
          if @binding?
            @debug "[do] calling bound function with: #{Object.keys(input)}"
            @debug @binding.toString()
            res = @binding.call ctx, input
            ctx.output ?= res
          else
            @debug "[do] calling assigned function: #{@content.name}"
            @debug @content.toString()
            ctx.output = @content.call @container, input
          return co =>
            @debug "[do] evaluating output schema"
            ctx.output = yield Promise.resolve ctx.output
            @debug "[do] finish setting output"
            @emit 'done', ctx
            if transaction
              @root.save()
              @root.transactable = false
            return ctx.output
        catch e
          @debug e
          if transaction
            @root.rollback()
            @root.transactable = false
          return Promise.reject e

### error (msg)

Provides more contextual error message pertaining to the Property instance.

      error: (msg, ctx=this) ->
        at = "#{@path}"
        at += @name if at is '/'
        err = new Error "[#{at}] #{msg}"
        err.name = 'PropertyError'
        err.context = ctx
        @emit 'error', err, this
        return err

      debug: (msg) ->
        if debug? then switch typeof msg
          when 'object' then debug msg
          else
            node = this
            prefix = [ @name ]
            prefix.unshift node.name while (node = node.parent)
            debug "[#{prefix.join('/')}] #{msg}"

### inspect

      inspect: ->
        return {
          name:   @schema.tag ? @name
          kind:   @schema.kind
          key:    @key
          xpath:  @path.toString()
          schema: @schema.toJSON tag: false, extended: true
          active: @enumerable
          readonly: not @mutable
        }

### toJSON

This call creates a new copy of the current `Property.content`
completely detached/unbound to the underlying data schema. It's main
utility is to represent the current data state for subsequent
serialization/transmission. It accepts optional argument `tag` which
when called with `false` will not tag the produced object with the
current property's `@name`.

      toJSON: (tag=true) ->
        copy = (src) ->
          return unless src? and typeof src isnt 'function'
          if typeof src is 'object'
            try res = new src.constructor
            catch then res = {}
            for own k, v of src when typeof v isnt 'function'
              res[k] = copy v
            return res
          src.constructor.call src, src
        value = copy @get()
        value ?= [] if @kind is 'list'
        if tag
          name = switch
            when @kind is 'list' then @schema.datakey
            else @name
          "#{name}": value
        else value

## Export Property Class

    module.exports = Property


Fix path

Fix path

Deploy Script for mySugr Bootstrap
==================================
The primary purpose of this script is to provide a well-defined location for the mySugr Bootstrap css file while cache-busting the contents on updates.

## Installing

```
$ npm install
```

## Running

The following environment variables need to be set:

  * `AWS_ACCESS_KEY_ID`
  * `AWS_SECRET_ACCESS_KEY`
  * `AWS_REGION`

```
$ gulp
```

will upload the newest `bootstrap.css` to `mysugr-elements.com`.

## Using

```
<link rel="stylesheet" href="//mysugr-elements.com/bootstrap.css">
```

## Technical Implementation Strategy
We provide a CSS-files with non-caching headers, namely `bootstrap.css`. This file `@import`s the actual CSS file, which has a hash appended to its filename (for caching) and long expiry headers.

```
@import "bootstrap-87fa525a.css"
```

### Implementation

    gulp = require 'gulp'
    gutil= require 'gulp-util'
    rev  = require 'gulp-rev'
    s3   = require 'gulp-s3'

    s3Credentials =
      key:    process.env.AWS_ACCESS_KEY_ID
      secret: process.env.AWS_SECRET_ACCESS_KEY
      region: process.env.AWS_REGION
      bucket: 'mysugr-elements.com'

    s3CacheLong =
      headers:'cache-control': 'max-age=315360000, no-transform, public'

    s3CacheOff =
      headers:'cache-control': 'private, max-age=0, no-cache, must-revalidate'

    string_src = (filename, contents)->
      src = require('stream').Readable objectMode:true
      src._read = ()->
        @push new gutil.File cwd: '', base: '', path: filename, contents: new Buffer contents
        @push null
      return src

    gulp.task 'deploy:minify',->
      minifyCss = require 'gulp-minify-css'
      rename    = require 'gulp-rename'

      gulp.src 'dist/css/bootstrap.css'
      .pipe minifyCss()
      .pipe rename suffix:'.min'
      .pipe gulp.dest 'dist/css/'

    gulp.task 'deploy:rev',['deploy:minify'],->
      gulp.src 'dist/css/bootstrap.min.css'
        .pipe rev()
        .pipe gulp.dest 'dist/s3'
        .pipe s3 s3Credentials, s3CacheLong
        .pipe rev.manifest()
        .pipe gulp.dest 'dist/s3'

    gulp.task 'deploy:css', ['deploy:rev'],->
      rev = require './dist/s3/rev-manifest.json'
      importClause = """
        /* This file was generated automatically on #{(new Date()).toISOString()} */
        @import \"#{rev['bootstrap.min.css']}\"
      """

      string_src 'bootstrap.css', importClause
        .pipe gulp.dest 'dist/s3'
        .pipe s3 s3Credentials, s3CacheOff

    gulp.task 'default', ['deploy:css']

Deploy Script for mySugr Bootstrap
==================================
The primary purpose of this script is to provide a well-defined location for the mySugr Bootstrap css file while cache-busting the contents on updates.

## Installing

```
$ npm install
```

## Running

The following environment variables need to be set:

  * `AWS_ACCESS_KEY_ID`
  * `AWS_SECRET_ACCESS_KEY`
  * `AWS_REGION`

```
$ gulp
```

will upload the newest `bootstrap.css` to `mysugr-elements.com`.

## Using

```
<link rel="stylesheet" href="//mysugr-elements.com/bootstrap.css">
```

## Technical Implementation Strategy
We provide a CSS-files with non-caching headers, namely `bootstrap.css`. This file `@import`s the actual CSS file, which has a hash appended to its filename (for caching) and long expiry headers.

```
@import "bootstrap-87fa525a.css"
```

### Implementation

    gulp = require 'gulp'
    gutil= require 'gulp-util'
    rev  = require 'gulp-rev'
    s3   = require 'gulp-s3'

    s3Credentials =
      key:    process.env.AWS_ACCESS_KEY_ID
      secret: process.env.AWS_SECRET_ACCESS_KEY
      region: process.env.AWS_REGION
      bucket: 'mysugr-elements.com'

    s3CacheLong =
      headers:'cache-control': 'max-age=315360000, no-transform, public'

    s3CacheOff =
      headers:'cache-control': 'private, max-age=0, no-cache, must-revalidate'

    string_src = (filename, contents)->
      src = require('stream').Readable objectMode:true
      src._read = ()->
        @push new gutil.File cwd: '', base: '', path: filename, contents: new Buffer contents
        @push null
      return src

    gulp.task 'deploy:minify',->
      minifyCss = require 'gulp-minify-css'
      rename    = require 'gulp-rename'

      gulp.src 'dist/css/bootstrap.css'
      .pipe minifyCss()
      .pipe rename suffix:'.min'
      .pipe gulp.dest 'dist/css/'

    gulp.task 'deploy:rev',['deploy:minify'],->
      gulp.src 'dist/css/bootstrap.min.css'
        .pipe rev()
        .pipe gulp.dest 'dist/s3'
        .pipe s3 s3Credentials, s3CacheLong
        .pipe rev.manifest()
        .pipe gulp.dest 'dist/s3'

    gulp.task 'deploy:css', ['deploy:rev'],->
      rev = require 'dist/s3/rev-manifest.json'
      importClause = """
        /* This file was generated automatically on #{(new Date()).toISOString()} */
        @import \"#{rev['bootstrap.min.css']}\"
      """

      string_src 'bootstrap.css', importClause
        .pipe gulp.dest 'dist/s3'
        .pipe s3 s3Credentials, s3CacheOff

    gulp.task 'default', ['deploy:css']