Disable auto-etaging

Disable auto-etaging

    raven       = require 'raven'
    sentry      = require './db/sentry'
    express     = require 'express'

    auth        = require './helper/auth'

    system      = require './system'
    collection  = require './collection'
    document    = require './document'

## Init

    app = express()

### Authentication

This routine is called for all request to the API. It is reponsible for
authenticating the user by validating the `api\_key`. It then sets some request
session variables so they become accessible throughout the entire system during
the rquest.

    app.use '/', (req, res, next) ->
      return next() if req.originalUrl.substr(0, 17) is '/CloudHealthCheck'

      auth.check req.query.api_key, (err, user) ->
        if user
          res.set 'X-RateLimit-Limit', user.limit
          res.set 'X-RateLimit-Remaining', user.remaining
          res.set 'X-RateLimit-Reset', user.reset

        req.user = user

        return next err if err

        next()

### Configuration

    app.use(express.favicon())
    app.use(express.logger(':date :remote-addr - :method :url :status :res[content-length] - :response-time ms')) if not process.env.SILENT
    app.use(express.compress())
    app.use(express.json())
    app.disable('x-powered-by')
    app.disable('etag')
    app.set 'port', process.env.APP_PORT or 8080
    app.use(app.router)

### Error handling

Before handling the error ours self make sure that it is propperly logged in
Sentry by using the express/connect middleware.

    app.use raven.middleware.express sentry

All errors passed to `next` or exceptions ends up here. We set the status code
to `500` if it is not already defined in the `Error` object. We then print the
error mesage and stack trace to the console for debug purposes.

Log 401 Unauthorized (warning) and 403 Forbidden (notice) errors to Sentry to
enhance debugging and oversight as Nasjonal Turbase gets more used.

Before returning a response to the user the request method is check. HEAD
requests shall not contain any body – this applies for errors as well.

    app.use (err, req, res, next) ->
      res.status err.status or 500

      if res.statusCode is 401
        sentry.captureMessage "Invalid API-key #{req.query.api_key}",
          level: 'warning'
          extra: sentry.parseRequest req, user: req.user

      if res.statusCode is 403
        sentry.captureMessage "Rate limit exceeded for #{req.user.tilbyder}",
          level: 'notice'
          extra: sentry.parseRequest req, user: req.user

      if res.statusCode >= 500
        console.error err.message
        console.error err.stack

      return res.end() if req.method is 'HEAD'
      return res.json message: err.message or 'Ukjent feil'

This the fmous 404 Not Found handler. If no route configuration for the request
is found, it ends up here. We don't do much fancy about it – just a standard
error message and HTTP status code.

    app.use (req, res) -> res.json 404, message: "Resurs ikke funnet"

## GET /

    app.get '/', (req, res) ->
      res.json message: 'Here be dragons'

## GET /CloudHealthCheck

> So...You’re seeing the dotCloud active health check looking to make sure that
> your service is up. There is no way for you to disable it, but you can prevent
> it and you can handle it [1]!

[1] [dotCloud](http://docs.dotcloud.com/tutorials/more/cloud-health-check/)

    app.all '/CloudHealthCheck', system.check

## GET /objekttyper

    app.get '/objekttyper', (req, res, next) ->
      res.json 200, ['turer', 'steder', 'områder', 'grupper', 'arrangementer', 'bilder']

## ALL /{collection}

    app.param 'collection', collection.param
    app.all '/:collection', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then collection.options req, res, next
        when 'HEAD', 'GET' then collection.get req, res, next
        when 'POST' then collection.post req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## ALL /{collection}/{objectid}

    app.param 'objectid', document.param
    app.options '/:collection/:ojectid', document.options
    app.all '/:collection/:objectid', document.all, (req, res, next) ->
      switch req.method
        when 'HEAD', 'GET' then document.get req, res, next
        when 'PUT' then document.put req, res, next
        when 'PATCH' then document.patch req, res, next
        when 'DELETE' then document.delete req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## Start

Ok, so if the server is running in stand-alone mode i.e. there is not
`module.parent` then continue with starting the databse and listening to a port.

    if not module.parent
      require('./db/redis')
      require('./db/mongo').once 'ready', ->
        console.log 'Database is open...'

        app.listen app.get('port'), ->
          console.log "Server is listening on port #{app.get('port')}"

However, if there is a `module.parent` don't do all the stuff above. This means
that there is some program that is including the server from it, e.g a test, and
hence it should not listen to a port for incomming connections and rather just
return the application instance so that we can do some testing on it.

    else
      module.exports = app

    raven       = require 'raven'
    sentry      = require './db/sentry'
    express     = require 'express'

    auth        = require './helper/auth'

    system      = require './system'
    collection  = require './collection'
    document    = require './document'

## Init

    app = express()

### Authentication

This routine is called for all request to the API. It is reponsible for
authenticating the user by validating the `api\_key`. It then sets some request
session variables so they become accessible throughout the entire system during
the rquest.

    app.use '/', (req, res, next) ->
      return next() if req.originalUrl.substr(0, 17) is '/CloudHealthCheck'

      auth.check req.query.api_key, (err, user) ->
        if user
          res.set 'X-RateLimit-Limit', user.limit
          res.set 'X-RateLimit-Remaining', user.remaining
          res.set 'X-RateLimit-Reset', user.reset

        req.user = user

        return next err if err

        next()

### Configuration

    app.use(express.favicon())
    app.use(express.logger(':date :remote-addr - :method :url :status :res[content-length] - :response-time ms')) if not process.env.SILENT
    app.use(express.compress())
    app.use(express.json())
    app.disable('x-powered-by')
    app.set 'port', process.env.APP_PORT or 8080
    app.use(app.router)

### Error handling

Before handling the error ours self make sure that it is propperly logged in
Sentry by using the express/connect middleware.

    app.use raven.middleware.express sentry

All errors passed to `next` or exceptions ends up here. We set the status code
to `500` if it is not already defined in the `Error` object. We then print the
error mesage and stack trace to the console for debug purposes.

Log 401 Unauthorized (warning) and 403 Forbidden (notice) errors to Sentry to
enhance debugging and oversight as Nasjonal Turbase gets more used.

Before returning a response to the user the request method is check. HEAD
requests shall not contain any body – this applies for errors as well.

    app.use (err, req, res, next) ->
      res.status err.status or 500

      if res.statusCode is 401
        sentry.captureMessage "Invalid API-key #{req.query.api_key}",
          level: 'warning'
          extra: sentry.parseRequest req, user: req.user

      if res.statusCode is 403
        sentry.captureMessage "Rate limit exceeded for #{req.user.tilbyder}",
          level: 'notice'
          extra: sentry.parseRequest req, user: req.user

      if res.statusCode >= 500
        console.error err.message
        console.error err.stack

      return res.end() if req.method is 'HEAD'
      return res.json message: err.message or 'Ukjent feil'

This the fmous 404 Not Found handler. If no route configuration for the request
is found, it ends up here. We don't do much fancy about it – just a standard
error message and HTTP status code.

    app.use (req, res) -> res.json 404, message: "Resurs ikke funnet"

## GET /

    app.get '/', (req, res) ->
      res.json message: 'Here be dragons'

## GET /CloudHealthCheck

> So...You’re seeing the dotCloud active health check looking to make sure that
> your service is up. There is no way for you to disable it, but you can prevent
> it and you can handle it [1]!

[1] [dotCloud](http://docs.dotcloud.com/tutorials/more/cloud-health-check/)

    app.all '/CloudHealthCheck', system.check

## GET /objekttyper

    app.get '/objekttyper', (req, res, next) ->
      res.json 200, ['turer', 'steder', 'områder', 'grupper', 'arrangementer', 'bilder']

## ALL /{collection}

    app.param 'collection', collection.param
    app.all '/:collection', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then collection.options req, res, next
        when 'HEAD', 'GET' then collection.get req, res, next
        when 'POST' then collection.post req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## ALL /{collection}/{objectid}

    app.param 'objectid', document.param
    app.options '/:collection/:ojectid', document.options
    app.all '/:collection/:objectid', document.all, (req, res, next) ->
      switch req.method
        when 'HEAD', 'GET' then document.get req, res, next
        when 'PUT' then document.put req, res, next
        when 'PATCH' then document.patch req, res, next
        when 'DELETE' then document.delete req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## Start

Ok, so if the server is running in stand-alone mode i.e. there is not
`module.parent` then continue with starting the databse and listening to a port.

    if not module.parent
      require('./db/redis')
      require('./db/mongo').once 'ready', ->
        console.log 'Database is open...'

        app.listen app.get('port'), ->
          console.log "Server is listening on port #{app.get('port')}"

However, if there is a `module.parent` don't do all the stuff above. This means
that there is some program that is including the server from it, e.g a test, and
hence it should not listen to a port for incomming connections and rather just
return the application instance so that we can do some testing on it.

    else
      module.exports = app


Only print 5xx errors to console

Only print 5xx errors to console

    raven       = require 'raven'
    sentry      = require './db/sentry'
    express     = require 'express'

    auth        = require './helper/auth'

    system      = require './system'
    collection  = require './collection'
    document    = require './document'

## Init

    app = express()

### Authentication

This routine is called for all request to the API. It is reponsible for
authenticating the user by validating the `api\_key`. It then sets some request
session variables so they become accessible throughout the entire system during
the rquest.

    app.use '/', (req, res, next) ->
      return next() if req.originalUrl.substr(0, 17) is '/CloudHealthCheck'

      auth.check req.query.api_key, (err, user) ->
        if user
          res.set 'X-RateLimit-Limit', user.limit
          res.set 'X-RateLimit-Remaining', user.remaining
          res.set 'X-RateLimit-Reset', user.reset

        req.user = user

        return next err if err

        next()

### Configuration

    app.use(express.favicon())
    app.use(express.logger(':date :remote-addr - :method :url :status :res[content-length] - :response-time ms')) if not process.env.SILENT
    app.set('json spaces', 0) if app.get('env') isnt 'testing'
    app.use(express.compress())
    app.use(express.json())
    app.disable('x-powered-by')
    app.set 'port', process.env.PORT_WWW or 8080
    app.use(app.router)

### Error handling

Before handling the error ours self make sure that it is propperly logged in
Sentry by using the express/connect middleware.

    app.use raven.middleware.express sentry

All errors passed to `next` or exceptions ends up here. We set the status code
to `500` if it is not already defined in the `Error` object. We then print the
error mesage and stack trace to the console for debug purposes.

Before returning a response to the user the request method is check. HEAD
requests shall not contain any body – this applies for errors as well.

    app.use (err, req, res, next) ->
      res.status err.status or 500

      if res.status >= 500
        console.error err.message
        console.error err.stack

      return res.end() if req.method is 'HEAD'
      return res.json message: err.message or 'Ukjent feil'

This the fmous 404 Not Found handler. If no route configuration for the request
is found, it ends up here. We don't do much fancy about it – just a standard
error message and HTTP status code.

    app.use (req, res) -> res.json 404, message: "Resurs ikke funnet"

## GET /

    app.get '/', (req, res) ->
      res.json message: 'Here be dragons'

## GET /CloudHealthCheck

> So...You’re seeing the dotCloud active health check looking to make sure that
> your service is up. There is no way for you to disable it, but you can prevent
> it and you can handle it [1]!

[1] [dotCloud](http://docs.dotcloud.com/tutorials/more/cloud-health-check/)

    app.get '/CloudHealthCheck', system.check

## GET /objekttyper

    app.get '/objekttyper', (req, res, next) ->
      res.json 200, ['turer', 'steder', 'områder', 'grupper', 'arrangementer', 'bilder']

## ALL /{collection}

    app.param 'collection', collection.param
    app.all '/:collection', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then collection.options req, res, next
        when 'HEAD', 'GET' then collection.get req, res, next
        when 'POST' then collection.post req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## ALL /{collection}/{objectid}

    app.param 'objectid', document.param
    app.options '/:collection/:ojectid', document.options
    app.all '/:collection/:objectid', document.all, (req, res, next) ->
      switch req.method
        when 'HEAD', 'GET' then document.get req, res, next
        when 'PUT' then document.put req, res, next
        when 'PATCH' then document.patch req, res, next
        when 'DELETE' then document.delete req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## Start

Ok, so if the server is running in stand-alone mode i.e. there is not
`module.parent` then continue with starting the databse and listening to a port.

    if not module.parent
      require('./db/redis')
      require('./db/mongo').once 'ready', ->
        console.log 'Database is open...'

        app.listen app.get('port'), ->
          console.log "Server is listening on port #{app.get('port')}"

However, if there is a `module.parent` don't do all the stuff above. This means
that there is some program that is including the server from it, e.g a test, and
hence it should not listen to a port for incomming connections and rather just
return the application instance so that we can do some testing on it.

    else
      module.exports = app

    raven       = require 'raven'
    sentry      = require './db/sentry'
    express     = require 'express'

    auth        = require './helper/auth'

    system      = require './system'
    collection  = require './collection'
    document    = require './document'

## Init

    app = express()

### Authentication

This routine is called for all request to the API. It is reponsible for
authenticating the user by validating the `api\_key`. It then sets some request
session variables so they become accessible throughout the entire system during
the rquest.

    app.use '/', (req, res, next) ->
      return next() if req.originalUrl.substr(0, 17) is '/CloudHealthCheck'

      auth.check req.query.api_key, (err, user) ->
        if user
          res.set 'X-RateLimit-Limit', user.limit
          res.set 'X-RateLimit-Remaining', user.remaining
          res.set 'X-RateLimit-Reset', user.reset

        req.user = user

        return next err if err

        next()

### Configuration

    app.use(express.favicon())
    app.use(express.logger(':date :remote-addr - :method :url :status :res[content-length] - :response-time ms')) if not process.env.SILENT
    app.set('json spaces', 0) if app.get('env') isnt 'testing'
    app.use(express.compress())
    app.use(express.json())
    app.disable('x-powered-by')
    app.set 'port', process.env.PORT_WWW or 8080
    app.use(app.router)

### Error handling

Before handling the error ours self make sure that it is propperly logged in
Sentry by using the express/connect middleware.

    app.use raven.middleware.express sentry

All errors passed to `next` or exceptions ends up here. We set the status code
to `500` if it is not already defined in the `Error` object. We then print the
error mesage and stack trace to the console for debug purposes.

Before returning a response to the user the request method is check. HEAD
requests shall not contain any body – this applies for errors as well.

    app.use (err, req, res, next) ->
      res.status(err.status or 500)

      console.error err.message
      console.error err.stack

      return res.end() if req.method is 'HEAD'
      return res.json message: err.message or 'Ukjent feil'

This the fmous 404 Not Found handler. If no route configuration for the request
is found, it ends up here. We don't do much fancy about it – just a standard
error message and HTTP status code.

    app.use (req, res) -> res.json 404, message: "Resurs ikke funnet"

## GET /

    app.get '/', (req, res) ->
      res.json message: 'Here be dragons'

## GET /CloudHealthCheck

> So...You’re seeing the dotCloud active health check looking to make sure that
> your service is up. There is no way for you to disable it, but you can prevent
> it and you can handle it [1]!

[1] [dotCloud](http://docs.dotcloud.com/tutorials/more/cloud-health-check/)

    app.get '/CloudHealthCheck', system.check

## GET /objekttyper

    app.get '/objekttyper', (req, res, next) ->
      res.json 200, ['turer', 'steder', 'områder', 'grupper', 'arrangementer', 'bilder']

## ALL /{collection}

    app.param 'collection', collection.param
    app.all '/:collection', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then collection.options req, res, next
        when 'HEAD', 'GET' then collection.get req, res, next
        when 'POST' then collection.post req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## ALL /{collection}/{objectid}

    app.param 'objectid', document.param
    app.options '/:collection/:ojectid', document.options
    app.all '/:collection/:objectid', document.all, (req, res, next) ->
      switch req.method
        when 'HEAD', 'GET' then document.get req, res, next
        when 'PUT' then document.put req, res, next
        when 'PATCH' then document.patch req, res, next
        when 'DELETE' then document.delete req, res, next
        else res.json 405, message: "HTTP Method #{req.method.toUpperCase()} Not Allowed"

## Start

Ok, so if the server is running in stand-alone mode i.e. there is not
`module.parent` then continue with starting the databse and listening to a port.

    if not module.parent
      require('./db/redis')
      require('./db/mongo').once 'ready', ->
        console.log 'Database is open...'

        app.listen app.get('port'), ->
          console.log "Server is listening on port #{app.get('port')}"

However, if there is a `module.parent` don't do all the stuff above. This means
that there is some program that is including the server from it, e.g a test, and
hence it should not listen to a port for incomming connections and rather just
return the application instance so that we can do some testing on it.

    else
      module.exports = app


Literate CofeeScript underway

Literate CofeeScript underway

We always start with the JavaScript-like magic scoping mojo!

    ((root) ->
      root = this
      _ = root._ || require 'underscore'
      F = {}

Non-determinism
---------------

Non-deterministic functions are functions that can have more (or less) than one result.  As known from logic, a binary relation xRy (where x ∈ X, y ∈ Y) can be represented by a *function*  `X -> PowerSet{Y}`. As usual in computer science, we interpret the set `PowerSet{Y}` as a multi-set (realized as a regular scheme list). Compare with SQL, which likewise uses multisets and sequences were sets are properly called for. Also compare with [Wadler's "representing failure as a list of successes."](http://citeseer.uark.edu:8080/citeseerx/showciting;jsessionid=FF5F5EAA9D94B1A8618C49C37451D762?cid=377301).

Thus, we represent a 'relation' (aka `non-deterministic function') as a regular CoffeeScript function that returns an array of possible results.

First, we define two primitive non-deterministic functions; one of them yields no result whatsoever for any argument; the other merely returns its argument as the sole result.

    F.succeed = (result) -> [result]
    F.fail = _.always []

  disjunction = (l, r) ->
    (x) -> _.cat(l(x), r(x))
  conjunction = (l, r) ->
    (x) -> _.mapcat(l(x), r)

  F.disj = () ->
    return F.fail if _.isEmpty(arguments)
    disjunction(_.first(arguments), F.disj.apply(this, _.rest(arguments)))

  F.conj = () ->
    clauses = _.toArray(arguments)
    return F.succeed if _.isEmpty(clauses)
    return _.first(clauses) if _.size(clauses) is 1
    conjunction(_.first(clauses),
                (s) -> F.conj.apply(null, _.rest(clauses))(s))

  # Knowledge representation
  # ------------------------

  class LVar
    constructor: (@name) ->

  F.lvar = (name) -> new LVar(name)
  F.isLVar = (v) -> (v instanceof LVar)

  find = (v, bindings) ->
    lvar = bindings.lookup(v)
    return lvar if F.isLVar(v)
    if _.isArray(lvar)
      if _.isEmpty(lvar)
        return lvar
      else
        return _.cons(find(_.first(lvar), bindings), find(_.rest(lvar), bindings))
    lvar

  class Bindings
    constructor: (seed = {}) ->
      @binds = _.merge({}, seed)
    extend: (lvar, value) ->
      o = {}
      o[lvar.name] = value
      new Bindings(_.merge(@binds, o))
    has: (lvar) ->
      @binds.hasOwnProperty(lvar.name)
    lookup: (lvar) ->
      return lvar if !F.isLVar(lvar)
      return this.lookup(@binds[lvar.name]) if this.has(lvar)
      lvar

  F.ignorance = new Bindings()

  # Unification
  # -----------

  F.unify = (l, r, bindings) ->
    t1 = bindings.lookup(l)
    t2 = bindings.lookup(r)

    if _.isEqual(t1, t2)
      return s
    if F.isLVar(t1)
      return bindings.extend(t1, t2)
    if F.isLVar(t2)
      return bindings.extend(t2, t1)
    if _.isArray(t1) && _.isArray(t2)
      s = F.unify(_.first(t1), _.first(t2), bindings)
      s = if (s isnt null) then F.unify(_.rest(t1), _.rest(t2), bindings) else s
      return s
    return null

  # Operational logic
  # -----------------

  F.goal = (l, r) ->
    (bindings) ->
      result = F.unify(l, r, bindings)
      return F.succeed(result) if result isnt null
      return F.fail(bindings)

  F.run = (goal) ->
    goal(F.ignorance)

  # Logico
  # ------

  F.choice = ($v, list) ->
    return F.fail if _.isEmpty(list)

    F.disj(F.goal($v, _.first(list)),
                  F.choice($v, _.rest(list)))

  # Exports and sundries
  # --------------------

  if module?
    module.exports = F
  else
    root.F = F

)(this)

We always start with the JavaScript-like magic scoping mojo!

    ((root) ->
      root = this
      _ = root._ || require 'underscore'
      F = {}

Non-determinism
---------------

Non-deterministic functions are functions that can have more (or less) than one result.  As known from logic, a binary relation xRy (where x ∈ X, y ∈ Y) can be represented by a *function*  `X -> PowerSet{Y}`. As usual in computer science, we interpret the set `PowerSet{Y}` as a multi-set (realized as a regular scheme list). Compare with SQL, which likewise uses multisets and sequences were sets are properly called for. Also compare with [Wadler's "representing failure as a list of successes."](http://citeseer.uark.edu:8080/citeseerx/showciting;jsessionid=FF5F5EAA9D94B1A8618C49C37451D762?cid=377301).

Thus, we represent a 'relation' (aka `non-deterministic function') as a regular CoffeeScript function that returns an array of possible results.

  F.succeed = (result) -> [result]
  F.fail = _.always []

  disjunction = (l, r) ->
    (x) -> _.cat(l(x), r(x))
  conjunction = (l, r) ->
    (x) -> _.mapcat(l(x), r)

  F.disj = () ->
    return F.fail if _.isEmpty(arguments)
    disjunction(_.first(arguments), F.disj.apply(this, _.rest(arguments)))

  F.conj = () ->
    clauses = _.toArray(arguments)
    return F.succeed if _.isEmpty(clauses)
    return _.first(clauses) if _.size(clauses) is 1
    conjunction(_.first(clauses),
                (s) -> F.conj.apply(null, _.rest(clauses))(s))

  # Knowledge representation
  # ------------------------

  class LVar
    constructor: (@name) ->

  F.lvar = (name) -> new LVar(name)
  F.isLVar = (v) -> (v instanceof LVar)

  find = (v, bindings) ->
    lvar = bindings.lookup(v)
    return lvar if F.isLVar(v)
    if _.isArray(lvar)
      if _.isEmpty(lvar)
        return lvar
      else
        return _.cons(find(_.first(lvar), bindings), find(_.rest(lvar), bindings))
    lvar

  class Bindings
    constructor: (seed = {}) ->
      @binds = _.merge({}, seed)
    extend: (lvar, value) ->
      o = {}
      o[lvar.name] = value
      new Bindings(_.merge(@binds, o))
    has: (lvar) ->
      @binds.hasOwnProperty(lvar.name)
    lookup: (lvar) ->
      return lvar if !F.isLVar(lvar)
      return this.lookup(@binds[lvar.name]) if this.has(lvar)
      lvar

  F.ignorance = new Bindings()

  # Unification
  # -----------

  F.unify = (l, r, bindings) ->
    t1 = bindings.lookup(l)
    t2 = bindings.lookup(r)

    if _.isEqual(t1, t2)
      return s
    if F.isLVar(t1)
      return bindings.extend(t1, t2)
    if F.isLVar(t2)
      return bindings.extend(t2, t1)
    if _.isArray(t1) && _.isArray(t2)
      s = F.unify(_.first(t1), _.first(t2), bindings)
      s = if (s isnt null) then F.unify(_.rest(t1), _.rest(t2), bindings) else s
      return s
    return null

  # Operational logic
  # -----------------

  F.goal = (l, r) ->
    (bindings) ->
      result = F.unify(l, r, bindings)
      return F.succeed(result) if result isnt null
      return F.fail(bindings)

  F.run = (goal) ->
    goal(F.ignorance)

  # Logico
  # ------

  F.choice = ($v, list) ->
    return F.fail if _.isEmpty(list)

    F.disj(F.goal($v, _.first(list)),
                  F.choice($v, _.rest(list)))

  # Exports and sundries
  # --------------------

  if module?
    module.exports = F
  else
    root.F = F

)(this)


log.time leaks support

log.time leaks support

# Log

Access it with:
```javascript
const { log } = Neft;
```

    'use strict'

    utils = require 'src/utils'
    assert = require 'src/assert'

    {bind} = Function
    {isArray} = Array
    {unshift} = Array::

    linesPrefix = ''

    fromArgs = (args) ->
        str = ''
        str += "#{arg} → " for arg in args
        str = str.substring 0, str.length - 3

        lines = str.split '\n'
        str = ''
        for line in lines
            str += "#{linesPrefix}#{line}\n"
        str = str.slice 0, -1

        str

    callOnce = do ->
        usedMessages = Object.create null
        ->
            msg = fromArgs arguments
            if usedMessages[msg]
                return -1
            usedMessages[msg] = true
            @ arguments...

## **Class** Log

    class Log
        @LOGS_METHODS = ['log', 'info', 'warn', 'error', 'time', 'ok']

        @MARKERS =
            white: (str) -> "LOG: #{str}"
            green: (str) -> "OK: #{str}"
            gray: (str) -> "#{str}"
            blue: (str) -> "INFO: #{str}"
            yellow: (str) -> "WARN: #{str}"
            red: (str) -> "ERROR: #{str}"

        @setGlobalLinesPrefix = (prefix) ->
            linesPrefix = prefix

        @time = Date.now
        @timeDiff = (since) -> Log.time() - since

        constructor: (prefixes = [], @parentScope) ->
            @prefixes = prefixes
            assert.isArray prefixes

            # bind all logs methods
            args = utils.clone(prefixes)
            args.unshift @

            for name in @constructor.LOGS_METHODS
                @[name] = bind.apply @[name], args
                @[name].once = callOnce

            @[key] = value for key, value of @
            if typeof @['lo' + 'g'] is 'function'
                func = =>
                    @log.apply func, arguments
                func.once = callOnce
                func.constructor = @constructor
                return utils.merge func, @

        _write: console?['lo' + 'g'].bind(console) or (->)
        _writeError: console?['erro' + 'r'].bind(console) or (->)

### *Integer* log.LOG

### *Integer* log.INFO

### *Integer* log.OK

### *Integer* log.WARN

### *Integer* log.ERROR

### *Integer* log.TIME

### *Integer* log.ALL

        i = 0
        LOG: 1<<i++
        INFO: 1<<i++
        OK: 1<<i++
        WARN: 1<<i++
        ERROR: 1<<i++
        TIME: 1<<i++
        ALL: (1<<i++) - 1

### *Integer* enabled = log.ALL

Bitmask of the `log.LOG`, `INFO`, `OK`, `WARN`, `ERROR` and `TIME`.

        enabled: @::ALL

        isEnabled = (log, type) ->
            unless log.enabled & type
                false
            else if log.parentScope
                isEnabled log.parentScope, type
            else
                true

### log([*Any* messages...])

Prints the given messages into the console.

```javascript
log("Log me now!");

log("setName()", "db time");
// will be logged as "setName() → db time"
```

        @::['log'] = ->
            if isEnabled(@, @LOG)
                @_write @constructor.MARKERS.white fromArgs arguments
            return

### log.info([*Any* messages...])

Prints the given messages into the console with a blue color.

        info: ->
            if isEnabled(@, @INFO)
                @_write @constructor.MARKERS.blue fromArgs arguments
            return

### log.ok([*Any* messages...])

Prints the given messages into the console with a green color.

```javascript
log.ok("Data has been successfully sent!");
```

        ok: ->
            if isEnabled(@, @OK)
                @_write @constructor.MARKERS.green fromArgs arguments
            return

### log.warn([*Any* messages...])

Prints the given messages into the console with a yellow color.

```javascript
log.warn("Example warning with some recommendations");
```

        warn: ->
            if isEnabled(@, @WARN)
                @_write @constructor.MARKERS.yellow fromArgs arguments
            return

### log.error([*Any* messages...])

Prints the given messages into the console with a red color.

```javascript
log.error("Error occurs, ... in file ...");
```

        error: ->
            if isEnabled(@, @ERROR)
                @_writeError @constructor.MARKERS.red fromArgs arguments
            return

### *Array* log.time()

Returns an id used to measure execution time by the `log.end()` function.

```javascript
function findPath(){
  var logtime = log.time('findPath()');

  // ... some complex algorithm ...

  log.end(logtime);
}

findPath();
```

        time: ->
            unless isEnabled(@, @TIME)
                return -1

            [@constructor.time(), fromArgs(arguments)]

### log.end(*Array* logTime)

Prints an information about the execution time for the given timer id.

        end: (logTime) ->
            diff = @constructor.timeDiff logTime[0]
            diff = diff.toFixed 2

            str = "#{logTime[1]}: #{diff} ms"
            @_write @constructor.MARKERS.gray str

            logTime[0] = 0
            return

### log.scope([*Any* names...])

Returns a new `log` function.

All prints will be prefixed by the given names.

```javascript
var log = log.scope("Example file");

log("hello");
// "Example file → hello"
```

        scope: (args...) ->
            if @prefixes
                unshift.apply args, @prefixes

            new @constructor args, @

    # implementation
    impl = switch true
        when utils.isNode
            require './impls/node/index.coffee'
        when utils.isBrowser
            require './impls/browser/index.coffee'

    LogImpl = if typeof impl is 'function' then impl Log else Log
    exports = module.exports = new LogImpl
    exports.Log = Log

# Log

Access it with:
```javascript
const { log } = Neft;
```

    'use strict'

    utils = require 'src/utils'
    assert = require 'src/assert'

    {bind} = Function
    {isArray} = Array
    {unshift} = Array::

    linesPrefix = ''

    fromArgs = (args) ->
        str = ''
        str += "#{arg} → " for arg in args
        str = str.substring 0, str.length - 3

        lines = str.split '\n'
        str = ''
        for line in lines
            str += "#{linesPrefix}#{line}\n"
        str = str.slice 0, -1

        str

    callOnce = do ->
        usedMessages = Object.create null
        ->
            msg = fromArgs arguments
            if usedMessages[msg]
                return -1
            usedMessages[msg] = true
            @ arguments...

## **Class** Log

    class Log
        @LOGS_METHODS = ['log', 'info', 'warn', 'error', 'time', 'ok']

        @TIMES_LEN = 50

        @MARKERS =
            white: (str) -> "LOG: #{str}"
            green: (str) -> "OK: #{str}"
            gray: (str) -> "#{str}"
            blue: (str) -> "INFO: #{str}"
            yellow: (str) -> "WARN: #{str}"
            red: (str) -> "ERROR: #{str}"

        @setGlobalLinesPrefix = (prefix) ->
            linesPrefix = prefix

        @time = Date.now
        @timeDiff = (since) -> Log.time() - since
        @times = new Array Log.TIMES_LEN

        for _, i in @times
            @times[i] = [0, '']

        constructor: (prefixes = [], @parentScope) ->
            @prefixes = prefixes
            assert.isArray prefixes

            # bind all logs methods
            args = utils.clone(prefixes)
            args.unshift @

            for name in @constructor.LOGS_METHODS
                @[name] = bind.apply @[name], args
                @[name].once = callOnce

            @[key] = value for key, value of @
            if typeof @['lo' + 'g'] is 'function'
                func = =>
                    @log.apply func, arguments
                func.once = callOnce
                func.constructor = @constructor
                return utils.merge func, @

        _write: console?['lo' + 'g'].bind(console) or (->)
        _writeError: console?['erro' + 'r'].bind(console) or (->)

### *Integer* log.LOG

### *Integer* log.INFO

### *Integer* log.OK

### *Integer* log.WARN

### *Integer* log.ERROR

### *Integer* log.TIME

### *Integer* log.ALL

        i = 0
        LOG: 1<<i++
        INFO: 1<<i++
        OK: 1<<i++
        WARN: 1<<i++
        ERROR: 1<<i++
        TIME: 1<<i++
        ALL: (1<<i++) - 1

### *Integer* enabled = log.ALL

Bitmask of the `log.LOG`, `INFO`, `OK`, `WARN`, `ERROR` and `TIME`.

        enabled: @::ALL

        isEnabled = (log, type) ->
            unless log.enabled & type
                false
            else if log.parentScope
                isEnabled log.parentScope, type
            else
                true

### log([*Any* messages...])

Prints the given messages into the console.

```javascript
log("Log me now!");

log("setName()", "db time");
// will be logged as "setName() → db time"
```

        @::['log'] = ->
            if isEnabled(@, @LOG)
                @_write @constructor.MARKERS.white fromArgs arguments
            return

### log.info([*Any* messages...])

Prints the given messages into the console with a blue color.

        info: ->
            if isEnabled(@, @INFO)
                @_write @constructor.MARKERS.blue fromArgs arguments
            return

### log.ok([*Any* messages...])

Prints the given messages into the console with a green color.

```javascript
log.ok("Data has been successfully sent!");
```

        ok: ->
            if isEnabled(@, @OK)
                @_write @constructor.MARKERS.green fromArgs arguments
            return

### log.warn([*Any* messages...])

Prints the given messages into the console with a yellow color.

```javascript
log.warn("Example warning with some recommendations");
```

        warn: ->
            if isEnabled(@, @WARN)
                @_write @constructor.MARKERS.yellow fromArgs arguments
            return

### log.error([*Any* messages...])

Prints the given messages into the console with a red color.

```javascript
log.error("Error occurs, ... in file ...");
```

        error: ->
            if isEnabled(@, @ERROR)
                @_writeError @constructor.MARKERS.red fromArgs arguments
            return

### *Integer* log.time()

Returns an id used to measure execution time by the `log.end()` function.

```javascript
function findPath(){
  var logtime = log.time('findPath()');

  // ... some complex algorithm ...

  log.end(logtime);
}

findPath();
```

        time: ->
            unless isEnabled(@, @TIME)
                return -1

            {times} = @constructor

            # get time id and set current time
            for v, i in times when not v[0]
                id = i
                times[i][0] = @constructor.time()
                times[i][1] = fromArgs arguments
                break

            assert id?, 'Log times out of range'

            id

### log.end(*Integer* id)

Prints an information about the execution time for the given timer id.

        end: (id) ->
            if id is -1
                return

            time = @constructor.times[id]
            diff = @constructor.timeDiff time[0]
            diff = diff.toFixed 2

            str = "#{time[1]}: #{diff} ms"
            @_write @constructor.MARKERS.gray str

            time[0] = 0
            return

### log.scope([*Any* names...])

Returns a new `log` function.

All prints will be prefixed by the given names.

```javascript
var log = log.scope("Example file");

log("hello");
// "Example file → hello"
```

        scope: (args...) ->
            if @prefixes
                unshift.apply args, @prefixes

            new @constructor args, @

    # implementation
    impl = switch true
        when utils.isNode
            require './impls/node/index.coffee'
        when utils.isBrowser
            require './impls/browser/index.coffee'

    LogImpl = if typeof impl is 'function' then impl Log else Log
    exports = module.exports = new LogImpl
    exports.Log = Log


progress helper

progress helper

    _self = this

    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) ->
      @queue.push method: 'progress', data: data, options: {progress: progress}
      @_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()

     _handleQueue: ->
      return unless @queue.length > 0

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options
       @queue.shift()
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options
       @queue.shift()
       @fresh = false

##Call class

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

     handle: (data, options) ->
      if not @callbacks[options.status]?
       return if options.status is 'progress'
       throw new Error "No callback registered #{@method} #{options.status}"
      @callbacks[options.status] data, options

##Port base class

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

     isStreaming: true

     onerror: (msg, options) ->
      console.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]

      @_send @_createCall method, data, callbacks, options

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}) ->
      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions
      if not POLL_TYPE[status]?
       delete @responses[response.id]

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call "#{@id}-#{@callsCounter}", method, data, callbacks, options
      @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) ->
      switch data.type
       when 'response'
        @_handleResponse data, options
       when 'call'
        @_handleCall data, options
       when 'poll'
        @_handlePoll data, options

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @handlers[data.method]?
       throw new Error "Unknown method: #{data.method}"
      @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]?
       throw new Error "Response without call: #{data.id}"
      @callsCache[data.id].handle data.data, data

     _handlePoll: (data, options) ->
      throw new Error "Poll not implemented"

##WorkerPort class
Used for browser and worker

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

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

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

     _onError: (e) -> console.log e

##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) -> @worker.emit 'message', data

     _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()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'

     isStreaming: false

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

       @_handleMessage jsonData, xhr: xhr
      else
       @onerror 'xhr error'

     _respond: (data, options) ->
      throw new Error 'AJAX cannot respond'

     _send: (data) ->
      data = JSON.stringify data
      xhr = new XMLHttpRequest
      xhr.open 'POST', "http://#{@host}:#{@port}#{@path}"
      xhr.onreadystatechange = =>
       @_onRequest xhr
      xhr.setRequestHeader 'Accept', 'application/json'
      #xhr.setRequestHeader 'Content-Type', 'application/json'
      xhr.send data

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

##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'
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

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

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      res.end()

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

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       console.log 'error', e

      req.write data
      req.end()

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

##NodeHttpServerPort class

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

     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
        console.log 'ParseError', e, data
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      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]?
       throw new Error "Poll without response: #{data.id}"
      @responses[data.id].setOptions options

#IO Module

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

     ports:
      WorkerPort: WorkerPort
      SocketPort: SocketPort
      AjaxHttpPort: AjaxHttpPort
      NodeHttpPort: NodeHttpPort
      NodeHttpServerPort: NodeHttpServerPort
      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

    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) ->
      @queue.push method: 'progress', data: data, options: {progress: progress}
      @_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()

     _handleQueue: ->
      return unless @queue.length > 0

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options
       @queue.shift()
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options
       @queue.shift()
       @fresh = false

##Call class

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

     handle: (data, options) ->
      if not @callbacks[options.status]?
       return if options.status is 'progress'
       throw new Error "No callback registered #{@method} #{options.status}"
      @callbacks[options.status] data, options

##Port base class

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

     isStreaming: true

     onerror: (msg, options) ->
      console.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]

      @_send @_createCall method, data, callbacks, options

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}) ->
      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions
      if not POLL_TYPE[status]?
       delete @responses[response.id]

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call "#{@id}-#{@callsCounter}", method, data, callbacks, options
      @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) ->
      switch data.type
       when 'response'
        @_handleResponse data, options
       when 'call'
        @_handleCall data, options
       when 'poll'
        @_handlePoll data, options

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @handlers[data.method]?
       throw new Error "Unknown method: #{data.method}"
      @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]?
       throw new Error "Response without call: #{data.id}"
      @callsCache[data.id].handle data.data, data

     _handlePoll: (data, options) ->
      throw new Error "Poll not implemented"

##WorkerPort class
Used for browser and worker

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

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

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

     _onError: (e) -> console.log e

##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) -> @worker.emit 'message', data

     _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()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'

     isStreaming: false

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

       @_handleMessage jsonData, xhr: xhr
      else
       @onerror 'xhr error'

     _respond: (data, options) ->
      throw new Error 'AJAX cannot respond'

     _send: (data) ->
      data = JSON.stringify data
      xhr = new XMLHttpRequest
      xhr.open 'POST', "http://#{@host}:#{@port}#{@path}"
      xhr.onreadystatechange = =>
       @_onRequest xhr
      xhr.setRequestHeader 'Accept', 'application/json'
      #xhr.setRequestHeader 'Content-Type', 'application/json'
      xhr.send data

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

##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'
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

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

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      res.end()

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

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       console.log 'error', e

      req.write data
      req.end()

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

##NodeHttpServerPort class

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

     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
        console.log 'ParseError', e, data
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      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]?
       throw new Error "Poll without response: #{data.id}"
      @responses[data.id].setOptions options

#IO Module

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

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

     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


zones were still lurking

zones were still lurking

# CLASS: Shape
* Extends: [Element][Element]
* Parent: [Index][Parent]

A drawable shape. Manages **regions**.

---

    module.exports = class Shape extends require './element'

## CONSTRUCTOR

### new Shape(args)

Creates Shape instance.

      constructor: ->
        super

Copy the element regions if they were set from named arguments

        if regions = @regions
          @regions = {}
          @regions[name] = region for name, region of regions

#### PARAMETERS
* **args** - named arguments

---

## PROPERTIES
### #regions
* Type: [Object][Object] - region name/value pairs
* **{REGION NAME}**
    * Type: [Array][Array] - [x, y, width, height]

---

## METHODS
### #draw(context, args)
* Returns: [Shape][Shape]

A draw method stub

      draw: -> this

---

### #getEventRegions(event)
* Returns: [Object][Object] - named set of matching regions

Helper method, to get element regions that match the event.

      getEventRegions: (event) ->
        result = null

Proceed only if event coordinates are localized

        if event and (x = event.localX)? and (y = event.localY)?

Walk through the element regions

          for name, $ of @regions

and add the region to the result if event localized coordinates are within
the region rectangle.

            if $[0] <= x <= ($[0] + $[2]) and $[1] <= y <= ($[1] + $[3])

Initialize result only if at least one region matches

              result or= {}
              result[name] = $

        return result

---

## LISTENERS

### #mousemoveCaptureListener(event)
* Returns: [Shape][Shape]

Capture **mousemove** events passing through this shape

      mousemoveCaptureListener: (event) ->
        super

        if regions = @getEventRegions event

Get shape regions that match the event and store them in the event.

          event.regions = regions

Set the shape state to the first matching region name in order.

          for name in ['active', 'hover', 'normal'] when regions[name]
            state = name
            break

If any state was set then make this shape a target of the event.
Reset the state if no region was found.

          if (@state = state or null) then event.target = this

        return this

#### PARAMETERS
**event**
* Type: [Event][Event] - captured event

---

### #mousedownCaptureListener(event)
* Returns: [Shape][Shape]

Capture **mousedown** events passing through this shape

      mousedownCaptureListener: (event) ->
        super

        if regions = @getEventRegions event

Get shape regions that match the event and store them in the event.

          event.regions = regions

Set the shape state to the first matching region name in order

          for name in ['active', 'hover', 'normal'] when regions[name]
            state = name
            break

If any state was set then make this shape a target of the event.
Reset the state if no region was found.

          if (@state = state or null) then event.target = this

        return this

#### PARAMETERS
**event**
* Type: [Event][Event] - captured event

---

### #mouseupCaptureListener(event)
* Returns: [Event][Event]

Capture **mouseup** events passing through this shape

      mouseupCaptureListener: (event) ->
        super

        if regions = @getEventRegions event

Get shape regions that match the event and store them in the event.

          event.regions = regions

Set the shape state to the first matching region name in order

          for name in ['active', 'hover', 'normal'] when regions[name]
            state = name
            break

If any state was set then make this shape a target of the event.
Reset the state if no region was found.

          if (@state = state or null) then event.target = this

        return this

#### PARAMETERS
**event**
* Type: [Event][Event] - captured event

[Shape]: ./shape.litcoffee
[Element]: ./element.litcoffee
[Event]: ./event.litcoffee
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object

# CLASS: Shape
* Extends: [Element][Element]
* Parent: [Index][Parent]

A drawable shape. Manages **regions**.

---

    module.exports = class Shape extends require './element'

## CONSTRUCTOR

### new Shape(args)

Creates Shape instance.

      constructor: ->
        super

Copy the element regions if they were set from named arguments

        if regions = @regions
          @regions = {}
          @regions[name] = region for name, region of regions

#### PARAMETERS
* **args** - named arguments

---

## PROPERTIES
### #regions
* Type: [Object][Object] - region name/value pairs
* **{REGION NAME}**
    * Type: [Array][Array] - [x, y, width, height]

---

## METHODS
### #draw(context, args)
* Returns: [Shape][Shape]

A draw method stub

      draw: -> this

---

### #getEventRegions(event)
* Returns: [Object][Object] - named set of matching regions

Helper method, to get element regions that match the event.

      getEventRegions: (event) ->
        result = null

Proceed only if event coordinates are localized

        if event and (x = event.localX)? and (y = event.localY)?

Walk through the element regions

          for name, $ of @regions

and add the region to the result if event localized coordinates are within
the region rectangle.

            if $[0] <= x <= ($[0] + $[2]) and $[1] <= y <= ($[1] + $[3])

Initialize result only if at least one region matches

              result or= {}
              result[name] = $

        return result

---

## LISTENERS

### #mousemoveCaptureListener(event)
* Returns: [Shape][Shape]

Capture **mousemove** events passing through this shape

      mousemoveCaptureListener: (event) ->
        super

        if regions = @getEventRegions event

Get shape regions that match the event and store them in the event.

          event.regions = regions

Set the shape state to the first matching region name in order.

          for name in ['active', 'hover', 'normal'] when regions[name]
            state = name
            break

If any state was set then make this shape a target of the event.
Reset the state if no region was found.

          if (@state = state or null) then event.target = this

        return this

#### PARAMETERS
**event**
* Type: [Event][Event] - captured event

---

### #mousedownCaptureListener(event)
* Returns: [Shape][Shape]

Capture **mousedown** events passing through this shape

      mousedownCaptureListener: (event) ->
        super

        if regions = @getEventRegions event

Get shape regions that match the event and store them in the event.

          event.regions = regions

Set the shape state to the first matching region name in order

          for name in ['active', 'hover', 'normal'] when zones[name]
            state = name
            break

If any state was set then make this shape a target of the event.
Reset the state if no region was found.

          if (@state = state or null) then event.target = this

        return this

#### PARAMETERS
**event**
* Type: [Event][Event] - captured event

---

### #mouseupCaptureListener(event)
* Returns: [Event][Event]

Capture **mouseup** events passing through this shape

      mouseupCaptureListener: (event) ->
        super

        if regions = @getEventRegions event

Get shape regions that match the event and store them in the event.

          event.regions = regions

Set the shape state to the first matching region name in order

          for name in ['active', 'hover', 'normal'] when zones[name]
            state = name
            break

If any state was set then make this shape a target of the event.
Reset the state if no region was found.

          if (@state = state or null) then event.target = this

        return this

#### PARAMETERS
**event**
* Type: [Event][Event] - captured event

[Shape]: ./shape.litcoffee
[Element]: ./element.litcoffee
[Event]: ./event.litcoffee
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object


improve property.inspect

improve property.inspect

# 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.

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
path  | [XPath](./src/xpath.coffee) | computed | dynamically generate XPath for this Property from root

## Class Property

    debug    = require('debug')('yang:property')
    delegate = require 'delegates'
    context  = require './context'
    XPath    = require './xpath'

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

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

        @state =
          value: undefined
          parent: null
          container: null
          private: false
          mutable: @schema.config?.valueOf() isnt false
          attached: false
          changed: false

        @schema.kind ?= 'anydata'

        # soft freeze this instance
        Object.preventExtensions this

      debug: -> debug @uri, arguments...

      delegate @prototype, 'state'
        .access 'container'
        .access 'parent'
        .access 'strict'
        .getter 'mutable'
        .getter 'private'
        .getter 'prev'
        .getter 'value'
        .getter 'changed'
        .getter 'attached'

      delegate @prototype, 'schema'
        .getter 'tag'
        .getter 'kind'
        .getter 'type'
        .getter 'default'
        .getter 'external'
        .getter 'binding'
        .method 'locate'
        .method 'lookup'

### Computed Properties

      @property 'enumerable',
        get: -> not @private and (@value? or @binding?)

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

      @property 'active',
        get: -> @enumerable and @value?

      @property 'change',
        get: -> switch
          when @changed and not @active then null
          when @changed then @content

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

      @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 'path',
        get: ->
          if this is @root
            entity = switch
              when @kind is 'module' then '/'
              else '.'
            return XPath.parse entity, @schema
          @state.path ?= @parent.path.clone().append @name
          return @state.path

      @property 'uri',
        get: -> @schema.datapath ? @schema.uri

## Instance-level methods

      clone: (state = {}) ->
        throw @error 'must clone with state typeof object' unless typeof state is 'object'
        copy = new @constructor @name, @schema
        copy.state = Object.assign(Object.create(@state), state, origin: this)
        return copy

      emit: -> @parent?.emit? arguments...

      clean: -> @state.changed = false

      equals: (a, b) -> switch @kind
        when 'leaf-list'
          return false unless a and b
          a = Array.from(new Set([].concat(a)))
          b = Array.from(new Set([].concat(b)))
          return false unless a.length is b.length
          a.every (x) => b.some (y) => x is y
        else a is b

### get (key)

This is the main `Getter` for the target object's property value. When
called with optional `key` 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: (key) -> switch
        when key?
          try match = @find key
          return unless match? and match.length
          switch
            when match.length is 1 then match[0].get()
            when match.length > 1  then match.map (x) -> x.get()
            else undefined
        when @binding?
          try @binding.call @context
          catch e
            throw @error e, 'getter'
        else @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={}) ->
        @state.changed = false
        # @debug "[set] enter..."

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

        if @binding?.length is 1 and not opts.force
          try value = @binding.call @context, value
          catch e
            throw @error e, 'setter'

        return this if value? and @equals value, @value

        @state.prev = @value
        bypass = opts.bypass and @kind in ["leaf", "leaf-list"]
        # @debug "[set] applying schema..."
        value = switch
          when @schema.apply? and not bypass
            @schema.apply value, this, Object.assign {}, opts, suppress: true
          else value
        # @debug "[set] done applying schema...", value
        return this if value instanceof Error or @equals value, @prev

        @state.value = value
        @state.changed = true

        # update enumerable state on every set operation
        try Object.defineProperty @container, @name, configurable: true, enumerable: true if @attached

        @commit opts
        # @debug "[set] completed"
        return this

### delete

      delete: (opts={}) ->
        if @binding?.length is 1 and not opts.force
          try @binding.call @context, null
          catch e
            throw @error "failed executing delete() binding: #{e.message}", e
        @state.prev = @value
        @state.value = null

        @parent?.remove? this, opts # remove from parent

        # update enumerable state on every set operation
        try Object.defineProperty @container, @name, enumerable: false if @attached

        @state.changed = true
        @commit opts
        return this

### merge (value)

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

      merge: (value, opts) ->
        return @delete opts if value is null
        @set value, Object.assign {}, opts, merge: true

### commit (opts)

Commits the changes to the data to the data model

      commit: (opts={}) ->
        return unless @changed
        if @attached and @parent?
          @parent.changes.add this
          @parent.commit suppress: true

        { suppress = false, inner = false, actor } = opts
        return if suppress
        unless inner
          try @emit 'update', this, actor
          catch error
            # console.warn('commit error, rolling back!');
            @rollback()
            throw error
        @emit 'change', this, actor if @attached

      rollback: ->
        @state.value = @prev
        @clean()
        return this

### attach (obj, parent, opts)

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`.

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

        detached = true unless @container?
        @container = obj
        @parent = parent

        # if joining for the first time, apply existing data unless explicit replace
        if detached and opts.replace isnt true
          # @debug "[join] applying existing data for #{@name} (external: #{@external}) to:"
          # @debug obj
          name = switch
            when @parent?.external and @tag of obj then @tag
            when @external then @name
            when @name of obj then @name
            else "#{@root.name}:#{@name}" # should we ensure root is kind = module?
          @set obj[name], Object.assign {}, opts, suppress: true

        @parent?.add? this, opts # add to parent

        try Object.defineProperty obj, @name,
            configurable: true
            enumerable: @enumerable
            get: => @get arguments...
            set: => @set arguments...

        @state.attached = true
        # @debug "[join] attached into #{obj.constructor.name} container"
        @emit 'attach', this
        return obj

### 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}"
        pattern = XPath.parse pattern, @schema
        switch
          when pattern.tag is '/'  and this isnt @root then @root.find(pattern)
          when pattern.tag is '..' then @parent?.find pattern.xpath
          else pattern.apply(this) ? []

### 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]

### defer (value)

Optionally defer setting the value to the property until root has been updated.

      defer: (value) ->
        @debug "deferring '#{@kind}(#{@name})' until update at #{@root.name}"
        @root.once 'update', =>
          @debug "applying deferred data (#{typeof value})"
          @content = value
        return value

### error (msg)

Provides more contextual error message pertaining to the Property instance.

      error: (err, ctx=this) ->
        err = new Error err unless err instanceof Error
        err.uri = @uri
        err.src = this
        err.ctx = ctx
        return err

### throw (msg)

      throw: (err) -> throw @error(err)

### 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 `true` will tag the produced object with the current
property's `@name`.

      toJSON: (key, state = true) ->
        value = switch
          when @kind is 'anydata' then undefined
          when state isnt true and not @mutable then undefined
          else @value
        value = "#{@name}": value if key is true
        return value

### inspect

      inspect: ->
        return {
          name:   @tag ? @name
          kind:   @kind
          path:   @path.toString()
          schema: switch
            when @schema.uri?
              uri:      @schema.uri
              summary:  @schema.description?.tag
              datakey:  @schema.datakey
              datapath: @schema.datapath
              external: @schema.external
              children: @schema.children
            else false
          active:  @active
          changed: @changed
          mutable: @mutable
          content: @toJSON()
        }

## 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.

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
path  | [XPath](./src/xpath.coffee) | computed | dynamically generate XPath for this Property from root

## Class Property

    debug    = require('debug')('yang:property')
    delegate = require 'delegates'
    context  = require './context'
    XPath    = require './xpath'

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

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

        @state =
          value: undefined
          parent: null
          container: null
          private: false
          mutable: @schema.config?.valueOf() isnt false
          attached: false
          changed: false

        @schema.kind ?= 'anydata'

        # soft freeze this instance
        Object.preventExtensions this

      debug: -> debug @uri, arguments...

      delegate @prototype, 'state'
        .access 'container'
        .access 'parent'
        .access 'strict'
        .getter 'mutable'
        .getter 'private'
        .getter 'prev'
        .getter 'value'
        .getter 'changed'
        .getter 'attached'

      delegate @prototype, 'schema'
        .getter 'tag'
        .getter 'kind'
        .getter 'type'
        .getter 'default'
        .getter 'external'
        .getter 'binding'
        .method 'locate'
        .method 'lookup'

### Computed Properties

      @property 'enumerable',
        get: -> not @private and (@value? or @binding?)

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

      @property 'active',
        get: -> @enumerable and @value?

      @property 'change',
        get: -> switch
          when @changed and not @active then null
          when @changed then @content

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

      @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 'path',
        get: ->
          if this is @root
            entity = switch
              when @kind is 'module' then '/'
              else '.'
            return XPath.parse entity, @schema
          @state.path ?= @parent.path.clone().append @name
          return @state.path

      @property 'uri',
        get: -> @schema.datapath ? @schema.uri

## Instance-level methods

      clone: (state = {}) ->
        throw @error 'must clone with state typeof object' unless typeof state is 'object'
        copy = new @constructor @name, @schema
        copy.state = Object.assign(Object.create(@state), state, origin: this)
        return copy

      emit: -> @parent?.emit? arguments...

      clean: -> @state.changed = false

      equals: (a, b) -> switch @kind
        when 'leaf-list'
          return false unless a and b
          a = Array.from(new Set([].concat(a)))
          b = Array.from(new Set([].concat(b)))
          return false unless a.length is b.length
          a.every (x) => b.some (y) => x is y
        else a is b

### get (key)

This is the main `Getter` for the target object's property value. When
called with optional `key` 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: (key) -> switch
        when key?
          try match = @find key
          return unless match? and match.length
          switch
            when match.length is 1 then match[0].get()
            when match.length > 1  then match.map (x) -> x.get()
            else undefined
        when @binding?
          try @binding.call @context
          catch e
            throw @error e, 'getter'
        else @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={}) ->
        @state.changed = false
        # @debug "[set] enter..."

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

        if @binding?.length is 1 and not opts.force
          try value = @binding.call @context, value
          catch e
            throw @error e, 'setter'

        return this if value? and @equals value, @value

        @state.prev = @value
        bypass = opts.bypass and @kind in ["leaf", "leaf-list"]
        # @debug "[set] applying schema..."
        value = switch
          when @schema.apply? and not bypass
            @schema.apply value, this, Object.assign {}, opts, suppress: true
          else value
        # @debug "[set] done applying schema...", value
        return this if value instanceof Error or @equals value, @prev

        @state.value = value
        @state.changed = true

        # update enumerable state on every set operation
        try Object.defineProperty @container, @name, configurable: true, enumerable: true if @attached

        @commit opts
        # @debug "[set] completed"
        return this

### delete

      delete: (opts={}) ->
        if @binding?.length is 1 and not opts.force
          try @binding.call @context, null
          catch e
            throw @error "failed executing delete() binding: #{e.message}", e
        @state.prev = @value
        @state.value = null

        @parent?.remove? this, opts # remove from parent

        # update enumerable state on every set operation
        try Object.defineProperty @container, @name, enumerable: false if @attached

        @state.changed = true
        @commit opts
        return this

### merge (value)

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

      merge: (value, opts) ->
        return @delete opts if value is null
        @set value, Object.assign {}, opts, merge: true

### commit (opts)

Commits the changes to the data to the data model

      commit: (opts={}) ->
        return unless @changed
        if @attached and @parent?
          @parent.changes.add this
          @parent.commit suppress: true

        { suppress = false, inner = false, actor } = opts
        return if suppress
        unless inner
          try @emit 'update', this, actor
          catch error
            # console.warn('commit error, rolling back!');
            @rollback()
            throw error
        @emit 'change', this, actor if @attached

      rollback: ->
        @state.value = @prev
        @clean()
        return this

### attach (obj, parent, opts)

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`.

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

        detached = true unless @container?
        @container = obj
        @parent = parent

        # if joining for the first time, apply existing data unless explicit replace
        if detached and opts.replace isnt true
          # @debug "[join] applying existing data for #{@name} (external: #{@external}) to:"
          # @debug obj
          name = switch
            when @parent?.external and @tag of obj then @tag
            when @external then @name
            when @name of obj then @name
            else "#{@root.name}:#{@name}" # should we ensure root is kind = module?
          @set obj[name], Object.assign {}, opts, suppress: true

        @parent?.add? this, opts # add to parent

        try Object.defineProperty obj, @name,
            configurable: true
            enumerable: @enumerable
            get: => @get arguments...
            set: => @set arguments...

        @state.attached = true
        # @debug "[join] attached into #{obj.constructor.name} container"
        @emit 'attach', this
        return obj

### 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}"
        pattern = XPath.parse pattern, @schema
        switch
          when pattern.tag is '/'  and this isnt @root then @root.find(pattern)
          when pattern.tag is '..' then @parent?.find pattern.xpath
          else pattern.apply(this) ? []

### 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]

### defer (value)

Optionally defer setting the value to the property until root has been updated.

      defer: (value) ->
        @debug "deferring '#{@kind}(#{@name})' until update at #{@root.name}"
        @root.once 'update', =>
          @debug "applying deferred data (#{typeof value})"
          @content = value
        return value

### error (msg)

Provides more contextual error message pertaining to the Property instance.

      error: (err, ctx=this) ->
        err = new Error err unless err instanceof Error
        err.uri = @uri
        err.src = this
        err.ctx = ctx
        return err

### throw (msg)

      throw: (err) -> throw @error(err)

### 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 `true` will tag the produced object with the current
property's `@name`.

      toJSON: (key, state = true) ->
        value = switch
          when @kind is 'anydata' then undefined
          when state isnt true and not @mutable then undefined
          else @value
        value = "#{@name}": value if key is true
        return value

### inspect

      inspect: ->
        return {
          name:    @tag ? @name
          kind:    @kind
          path:    @path.toString()
          schema:  @schema.toJSON? tag: false, extended: true
          active:  @active
          changed: @changed
          mutable: @mutable
          content: @toJSON()
        }

## Export Property Class

    module.exports = Property


Use to path data structure (no row/col - now it's x/y)

    PngRenderer = require './png_renderer'

    class PngBlocks extends PngRenderer

      do_render: (ctx, path) =>
        width  = @config.width
        height = @config.height

        for step in path
          ctx.fillStyle = @config.block.fill_color

          ctx.beginPath()
          ctx.rect width * step.x, height * step.y, width, height
          ctx.fill()

    module.exports = PngBlocks

    PngRenderer = require './png_renderer'

    class PngBlocks extends PngRenderer

      do_render: (ctx, path) =>
        width  = @config.width
        height = @config.height

        for step in path
          ctx.fillStyle = @config.block.fill_color

          ctx.beginPath()
          ctx.rect width * step.col, height * step.row, width, height
          ctx.fill()

    module.exports = PngBlocks