add LoopbackInfo section to README

add LoopbackInfo section to README

# loopback-with-admin

run loopback server with admin and push notification features.

# install

```bash
npm install loopback-with-admin
```

# usage
## simplest run

    # model definitions
    # see "models" section for more detail
    models =
        'user':
            base: 'User'

    require('loopback-with-admin').run(models).then (lbInfo) ->

        # see "LoopbackInfo" section for more detail
        console.log lbInfo.getURL()         # loopback api root
        console.log lbInfo.getAccessToken() # access token of admin

## run with config dir

before running, you can prepare a directory which contains custom config information.

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
`-- production
    `-- datasources.coffee
```

    lbWithAdmin = require 'loopback-with-admin'

    configDir = '/path/to/config-dir'

    lbWithAdmin.run(models, configDir).then ->
        # loopback started

## run with config

    lbWithAdmin = require 'loopback-with-admin'

    lbWithAdmin.run(models, server: port: 3001).then ->

## passing custom environment with argument

    env = 'production'

    require('loopback-with-admin').run(models, configDir, env)

env is defined as

```coffee
    env ?= process.env.NODE_ENV or 'development'
```
- use custom value if passed
- use NODE\_ENV if exists
- default value is 'development'

```bash
$ NODE_ENV=production node app.js
```

when your config dir is

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
|-- local
|   `-- datasources.coffee
|-- production
|   `-- datasources.coffee
```

and launching script like

```bash
$ NODE_ENV=local node app.js
```
then, loopback-with-admin selects configs in "local" directory.

# model definitions

    models =
        player: # model name
            base: 'User'
            aclType: 'admin' # specific for this system

        instrument:
            aclType: 'owner-read'

the same format as [loopback model definition](http://docs.strongloop.com/display/public/LB/Customizing+models)
except "aclType" value.
name is automatically set from definition information.
plural is set to the same value as name if not set manually.

## aclType
loopback-with-admin generates acls from aclType.

three types are available.

 aclType     | meaning
-------------|-----------------------------------------------------
 admin       | only admin can CRUD the model (_default_)
 owner       | admin and the owner of the model can CRUD
 public-read | everyone can READ the model and admin can CRUD
 none        | everyone can CRUD the model

# configs

these are the config names.

- admin
- datasources
- middleware
- server
- push-credentials

see JSON files in "default-values/non-model-configs" directory.
you can set the same properties as these JSONs.

## admin

 config key  | meaning
-------------|-----------------------
 accessToken | accessToken for admin

## datasources

 config key  | meaning
-------------|---------------------------------
 memory      | on memory datasource
 db          | datasource for custom entities

Each datasource name has its connectors.

### available loopback connectors

available datasources are
- mongodb
- memory
- memory-idstr

"memory-idstr" is the default connector, which stores data only in memory,
and id type is string whereas id type of "memory" is number.

## server

 config key  | meaning       | default
-------------|---------------|----------------
 restApiRoot | REST api root | /api
 port        | port number   | 3000

## push-credentials

 config key      | meaning
-----------------|-------------------------------------------
 gcmServerApiKey | api key for Google Cloud Messaging (GCM)
 apnsCertData    | certificate pem contents for APNs
 apnsKeyData     | key pem contents for APNs

# LoopbackInfo
    require('loopback-with-admin').run().then (lbInfo) ->
        lbInfo instanceof LoopbackInfo # true

instance of LoopbackInfo is obtained after loopback is launched

## getURL()
returns hosting URL

    lbInfo.getURL() # e.g. localhost:3000/api

## getEnv()
returns environment name where loopback launched

    lbInfo.getEnv() # development|production or other custom environments

## getAccessToken()
returns access token of admin

    lbInfo.getAccessToken()

## config
contains all config values used to build loopback.

- admin
- datasources
- middleware
- server
- push-credentials

see configs section above.

## models
contains model definitions used to build loopback

see models section above.

# admin
(coming soon)

# push notification
(coming soon)

# loopback-with-admin

run loopback server with admin and push notification features.

# install

```bash
npm install loopback-with-admin
```

# usage
## simplest run

    # model definitions
    # see "models" section for more detail
    models =
        'user':
            base: 'User'

    require('loopback-with-admin').run(models).then (lbInfo) ->

        # see "LoopbackInfo" section for more detail
        console.log lbInfo.getURL()         # loopback api root
        console.log lbInfo.getAccessToken() # access token of admin

## run with config dir

before running, you can prepare a directory which contains custom config information.

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
`-- production
    `-- datasources.coffee
```

    lbWithAdmin = require 'loopback-with-admin'

    configDir = '/path/to/config-dir'

    lbWithAdmin.run(models, configDir).then ->
        # loopback started

## run with config

    lbWithAdmin = require 'loopback-with-admin'

    lbWithAdmin.run(models, server: port: 3001).then ->

## passing custom environment with argument

    env = 'production'

    require('loopback-with-admin').run(models, configDir, env)

env is defined as

```coffee
    env ?= process.env.NODE_ENV or 'development'
```
- use custom value if passed
- use NODE\_ENV if exists
- default value is 'development'

```bash
$ NODE_ENV=production node app.js
```

when your config dir is

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
|-- local
|   `-- datasources.coffee
|-- production
|   `-- datasources.coffee
```

and launching script like

```bash
$ NODE_ENV=local node app.js
```
then, loopback-with-admin selects configs in "local" directory.

# model definitions

    models =
        player: # model name
            base: 'User'
            aclType: 'admin' # specific for this system

        instrument:
            aclType: 'owner-read'

the same format as [loopback model definition](http://docs.strongloop.com/display/public/LB/Customizing+models)
except "aclType" value.
name is automatically set from definition information.
plural is set to the same value as name if not set manually.

## aclType
loopback-with-admin generates acls from aclType.

three types are available.

 aclType     | meaning
-------------|-----------------------------------------------------
 admin       | only admin can CRUD the model (_default_)
 owner       | admin and the owner of the model can CRUD
 public-read | everyone can READ the model and admin can CRUD
 none        | everyone can CRUD the model

# configs

these are the config names.

- admin
- datasources
- middleware
- server
- push-credentials

see JSON files in "default-values/non-model-configs" directory.
you can set the same properties as these JSONs.

## admin

 config key  | meaning
-------------|-----------------------
 accessToken | accessToken for admin

## datasources

 config key  | meaning
-------------|---------------------------------
 memory      | on memory datasource
 db          | datasource for custom entities

Each datasource name has its connectors.

### available loopback connectors

available datasources are
- mongodb
- memory
- memory-idstr

"memory-idstr" is the default connector, which stores data only in memory,
and id type is string whereas id type of "memory" is number.

## server

 config key  | meaning       | default
-------------|---------------|----------------
 restApiRoot | REST api root | /api
 port        | port number   | 3000

## push-credentials

 config key      | meaning
-----------------|-------------------------------------------
 gcmServerApiKey | api key for Google Cloud Messaging (GCM)
 apnsCertData    | certificate pem contents for APNs
 apnsKeyData     | key pem contents for APNs

# admin
(coming soon)

# push notification
(coming soon)


update README

update README

# loopback-with-domain

run loopback server with "domain"

domain is in this context business logic, the same as Domain-Driven Design (DDD).

connection with [base-domain](https://github.com/CureApp/base-domain)

also, this loopback extends original [loopback](https://github.com/strongloop/loopback).

- admin
- push notification

follow these section to see how to use admin and push notification

# install

```bash
npm install loopback-with-domain
```

# simplest run, without domain

you can just run loopback without domain information by

    require('loopback-with-domain').runWithoutDomain().then (lbInfo) ->

        console.log lbInfo.getURL()         # loopback api root
        console.log lbInfo.getAccessToken() # access token of admin

then loopback server (with admin, push-notification function) runs

# run with domain

before running, you can prepare a directory which contains custom config information.

```text
(config-dir) # any name is acceptable
|-- model-definitions.coffee
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
`-- production
    `-- datasources.coffee
```

    lbWithDomain = require 'loopback-with-domain'

    configDir = '/path/to/config-dir'

    domain = require('base-domain').createInstance(dirname: 'domain')

    lbWithDomain.runWithDomain(domain, configDir).then ->
        # loopback started

# admin
(coming soon)

# push notification
(coming soon)

# configs

these are the config names.

- admin
- datasources
- middleware
- server
- push-credentials

see JSON files in "default-values/non-model-configs" directory.
you can set the same properties as these JSONs.

## admin

 config key  | meaning
-------------|-----------------------
 accessToken | accessToken for admin

## datasources

 config key  | meaning
-------------|-----------------------
 memory      | on memory datasource
 db          | datasource for domain entities

## server

 config key  | meaning       | default
-------------|---------------|----------------
 restApiRoot | REST api root | /api
 port        | port number   | 3000

## push-credentials

 config key      | meaning
-----------------|-------------------------------------------
 gcmServerApiKey | api key for Google Cloud Messaging (GCM)
 apnsCertData    | certificate pem contents for APNs
 apnsKeyData     | key pem contents for APNs

# model definitions

    module.exports =
        player: # model name
            base: 'User'  # the same as loopback model settings.base
            aclType: 'admin' # specific for this system

        instrument:
            aclType: 'owner-read'

the same format as [loopback model definition](http://docs.strongloop.com/display/public/LB/Customizing+models)
except "aclType" value.
name, base, relations and properties are automatically set from domain information.

## aclType
loopback-with-domain generates acls from aclType.

three types are available.

 aclType     | meaning
-------------|-----------------------------------------------------
 admin       | only admin can CRUD the model
 owner       | admin and the owner of the model can CRUD
 public-read | everyone can READ the model and admin can CRUD

# switching environment

running script with environment variable "NODE\_ENV" like

```bash
$ NODE_ENV=production node app.js
```

"development" is selected by default.

when your config dir is

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
|-- local
|   `-- datasources.coffee
|-- production
|   `-- datasources.coffee
```

and launching script like

```bash
$ NODE_ENV=local node app.js
```
then, loopback-with-domain selects configs in "local" directory.

## passing custom environment with argument

    env = 'production'

    lbWithDomain.runWithDomain(domain, configDir, env)

env is prior to NODE\_ENV settings.

# modified loopback-datasource-juggler

using [CureApp/loopback-datasource-juggler](https://github.com/CureApp/loopback-datasource-juggler).

this repository is almost the same as original one except 'memory' connector handles id as string
(orignally integer).

# loopback-with-domain

run loopback server with "domain"

domain is in this context business logic, the same as Domain-Driven Design (DDD).

connection with [base-domain](https://github.com/CureApp/base-domain)

# install

```bash
npm install loopback-with-domain
```

# run

before running, you can prepare a directory which contains custom config information.

```text
(config-dir) # any name is acceptable
|-- model-definitions.coffee
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
`-- production
    `-- datasources.coffee
```

    lbWithDomain = require 'loopback-with-domain'

    configDir = '/path/to/config-dir'

    domain = require('base-domain').createInstance(dirname: 'domain')

    lbWithDomain.runWithDomain(domain, configDir).then ->
        # loopback started

# configs

these are the config names.

- admin
- datasources
- middleware
- server
- push-credentials

see JSON files in "default-values/non-model-configs" directory.
you can set the same properties as these JSONs.

## admin

 config key  | meaning
-------------|-----------------------
 accessToken | accessToken for admin

## datasources

 config key  | meaning
-------------|-----------------------
 memory      | on memory datasource
 db          | datasource for domain entities

## server

 config key  | meaning       | default
-------------|---------------|----------------
 restApiRoot | REST api root | /api
 port        | port number   | 3000

## push-credentials

 config key      | meaning
-----------------|-------------------------------------------
 gcmServerApiKey | api key for Google Cloud Messaging (GCM)
 apnsCertData    | certificate pem contents for APNs
 apnsKeyData     | key pem contents for APNs

# model definitions

    module.exports =
        player: # model name
            base: 'User'  # the same as loopback model settings.base
            aclType: 'admin' # specific for this system

        instrument:
            aclType: 'owner-read'

the same format as [loopback model definition](http://docs.strongloop.com/display/public/LB/Customizing+models)
except "aclType" value.
name, base, relations and properties are automatically set from domain information.

## aclType
loopback-with-domain generates acls from aclType.

three types are available.

 aclType     | meaning
-------------|-----------------------------------------------------
 admin       | only admin can CRUD the model
 owner       | admin and the owner of the model can CRUD
 public-read | everyone can READ the model and admin can CRUD

# switching environment

running script with environment variable "NODE\_ENV" like

```bash
$ NODE_ENV=production node app.js
```

"development" is selected by default.

when your config dir is

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
|-- local
|   `-- datasources.coffee
|-- production
|   `-- datasources.coffee
```

and launching script like

```bash
$ NODE_ENV=local node app.js
```
then, loopback-with-domain selects configs in "local" directory.

## passing custom environment with argument

    env = 'production'

    lbWithDomain.runWithDomain(domain, configDir, env)

env is prior to NODE\_ENV settings.

# modified loopback-datasource-juggler

using [CureApp/loopback-datasource-juggler](https://github.com/CureApp/loopback-datasource-juggler).

this repository is almost the same as original one except 'memory' connector handles id as string
(orignally integer).


Refactored computeLimb and corrected the orientation of the two clouds being wrong outside of very simplistic scenarios.

Given:

- A vector locating the start of the limb.
- A vector locating the end of the limb.
- The length of the limb when fully extended.
- A vector pointing perpendicular to the bend direction.
- A matrix to store the transform for the start half of the limb.
- A matrix to store the transform for the end half of the limb.

Writes to the output matrices to generate transforms for the top and bottom
halves of a limb to fill the gap between the start and end locations.

    matrix = require "./matrix.litcoffee"
    vector = require "./vector.litcoffee"

    startEndDifference = []
    startEndNormal = []
    bendNormal = []
    midpoint = []
    joint = []
    sideNormal2 = []

    lookAt = (start, end, sideNormal, transform) ->
        vector.subtract.vector end, start, startEndDifference
        vector.normalize startEndDifference, startEndNormal
        vector.cross startEndNormal, sideNormal, bendNormal
        vector.normalize bendNormal, bendNormal
        vector.cross bendNormal, startEndNormal, sideNormal2
        vector.normalize sideNormal2, sideNormal2

        matrix.identity transform
        transform[0] = sideNormal2[0]
        transform[4] = sideNormal2[1]
        transform[8] = sideNormal2[2]
        transform[1] = bendNormal[0]
        transform[5] = bendNormal[1]
        transform[9] = bendNormal[2]
        transform[2] = startEndNormal[0]
        transform[6] = startEndNormal[1]
        transform[10] = startEndNormal[2]
        matrix.translate start, transform

    module.exports = (start, end, targetLength, sideNormal, startTransform, endTransform) ->
        vector.subtract.vector end, start, startEndDifference
        vector.cross startEndDifference, sideNormal, bendNormal
        realLength = vector.normalize startEndDifference, startEndNormal
        vector.normalize bendNormal, bendNormal

        # The two halves of the limb form a pair of square-based triangles.
        # Work out how far the bend should go based on Pythagoras' theorem.
        alongBend = Math.sqrt (Math.max 0, (((targetLength / 2) * (targetLength / 2)) - ((realLength / 2) * (realLength / 2))))

        vector.interpolate start, end, 0.5, midpoint
        vector.multiply.byScalar bendNormal, alongBend, joint
        vector.add.vector joint, midpoint, joint

        lookAt start, joint, sideNormal, startTransform
        lookAt joint, end, sideNormal, endTransform

Given:

- A vector locating the start of the limb.
- A vector locating the end of the limb.
- The length of the limb when fully extended.
- A vector pointing perpendicular to the bend direction.
- A matrix to store the transform for the start half of the limb.
- A matrix to store the transform for the end half of the limb.

Writes to the output matrices to generate transforms for the top and bottom
halves of a limb to fill the gap between the start and end locations.

    matrix = require "./matrix.litcoffee"
    vector = require "./vector.litcoffee"

    startEndDifference = []
    startEndNormal = []
    bendNormal = []
    midpoint = []
    joint = []
    sideNormal2 = []
    module.exports = (start, end, targetLength, sideNormal, startTransform, endTransform) ->
        vector.subtract.vector end, start, startEndDifference
        vector.cross startEndDifference, sideNormal, bendNormal
        realLength = vector.normalize startEndDifference, startEndNormal
        vector.normalize bendNormal, bendNormal

        # The two halves of the limb form a pair of square-based triangles.
        # Work out how far the bend should go based on Pythagoras' theorem.
        alongBend = Math.sqrt (Math.max 0, (((targetLength / 2) * (targetLength / 2)) - ((realLength / 2) * (realLength / 2))))

        vector.interpolate start, end, 0.5, midpoint
        vector.multiply.byScalar bendNormal, alongBend, joint
        vector.add.vector joint, midpoint, joint

        vector.subtract.vector end, joint, startEndDifference
        vector.normalize startEndDifference, startEndNormal
        vector.cross sideNormal, startEndDifference, bendNormal
        vector.normalize bendNormal, bendNormal
        vector.cross bendNormal, startEndDifference, sideNormal2
        vector.normalize sideNormal2, sideNormal2

        matrix.identity endTransform
        endTransform[0] = -sideNormal2[0]
        endTransform[1] = -sideNormal2[1]
        endTransform[2] = sideNormal2[2]
        endTransform[4] = -bendNormal[0]
        endTransform[5] = -bendNormal[1]
        endTransform[6] = bendNormal[2]
        endTransform[8] = -startEndNormal[0]
        endTransform[9] = -startEndNormal[1]
        endTransform[10] = startEndNormal[2]
        matrix.translate joint, endTransform

        vector.subtract.vector joint, start, startEndDifference
        vector.normalize startEndDifference, startEndNormal
        vector.cross sideNormal, startEndDifference, bendNormal
        vector.normalize bendNormal, bendNormal
        vector.cross bendNormal, startEndDifference, sideNormal2
        vector.normalize sideNormal2, sideNormal2

        matrix.identity startTransform
        startTransform[0] = -sideNormal2[0]
        startTransform[1] = -sideNormal2[1]
        startTransform[2] = sideNormal2[2]
        startTransform[4] = -bendNormal[0]
        startTransform[5] = -bendNormal[1]
        startTransform[6] = bendNormal[2]
        startTransform[8] = -startEndNormal[0]
        startTransform[9] = -startEndNormal[1]
        startTransform[10] = startEndNormal[2]
        matrix.translate start, startTransform


Added unify fixes to literate version

Added unify fixes to literate version

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

We build more complex non-deterministic functions by combining the existing ones with the help of the following two combinators.

`(disjunction l r)` returns all the results of `l` and all the results of `r`, or returns no results only if neither `l` nor `r` returned any.  In that sense, it is analogous to the logical disjunctionunction.

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

`(conjunction l r)` looks like a functional composition of `r` and `l`.  Only `(l x)` may return several results, so we have to apply `r` to each of them.  Obviously `(conjunction fail f)` and `(conjunction f fail)` are both equivalent to `fail`: they return no results, ever. It that sense, `conjunction` is analogous to the logical conjunction.

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

JavaScript allows you to pass any number of arguments to a function.  Therefore, we can make a function `disj` that takes any number of arguments and performs a logical disjunction over each.  This makes this version of Sokuza Kanren a bit more flexible in that it allows you to nest any number of relations therein.

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

Likewise, the `conj` function accepts any number of clauses, nit just two as in the original Sokuza.

    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))

And that's all that there is for the built-in non-deterministic functions.

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

One may think of regular variables as "certain knowledge": they give  names to definite values.  A logic variable then stands for "improvable ignorance".  An unbound logic variable represents no  knowledge at all; in other words, it represents the result of a measurement *before* we have done the measurement. A logic variable may be associated with a definite value, like 10. That means definite knowledge.  A logic variable may be associated with a semi-definite value, like `[$X]` where `$X` is an unbound variable. We know something about the original variable: it is associated with the array of one element.  We can't say though what that element is. A logic variable can be associated with another, unbound logic variable. In that case, we still don't know what precisely the original variable stands for. However, we can say that it represents the same thing as the other variable. So, our uncertainty is reduced.

I've chosen to represent logic variables with their own simple type.

    class LVar
      constructor: (@name) ->

I've also created a couple of helper functions for creating new variables and checking "variableness" to decouple the representation a bit.

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

I implement associations of logic variables and their values (aka, *bindings*) as a class holding a simple JavaScript object.  One may say that a substitution represents our current knowledge of the world.

    class Bindings
      constructor: (seed = {}) ->
        @binds = _.merge({}, seed)

There are actually two ways of implementing substitutions as associative list. If the variable `$x` is associated with `$y` and `$y` is associated with `1`, we could represent this knowledge as `{$x: 1, $y 1}`. It is easy to lookup the value associated with the variable then, via a simple access. OTH, if we have the binding `{$x:  $y}` and we wish to add the bindings of `$y` to `1`, we have to make rearrangements so to produce `{$x: 1, $y 1}`, or make the traversal on lookup (which we defer to `find` below).

However, if we use an association-list-like structure (arrays of pairs) then we can just record the associations as we learn them, without modifying the previous ones. If originally we knew `[[$x, $y]]` and later we learned that `$y` is associated with `1`, we can simply prepend the latter association, obtaining `[[$y, 1], [$x, $y]]`. So, adding new knowledge becomes fast. The lookup procedure becomes more complex though, as we have to chase the chains of variables. To obtain the value associated with `$x` in the latter substitution, we first lookup `$x`, obtain `$y` (another logic variable), then lookup `$y` finally obtaining `1`.  I prefer the object-representation since it's more idiomatic, but using an a-list provides an intuitively incremental way of representing knowledge: it is easier to backtrack if we later find out our knowledge leads to a contradiction.

      extend: (lvar, value) ->
        o = {}
        o[lvar.name] = value
        new Bindings(_.merge(@binds, o))
      has: (lvar) ->
        @binds.hasOwnProperty(lvar.name)

Find the value associated with `lvar` in the `Bindings` instance.  Return `lvar` itself if it is unbound. In miniKanren, this function is called `walk`.

    lookup: (lvar) ->
        return lvar if !F.isLVar(lvar)
        return this.lookup(@binds[lvar.name]) if this.has(lvar)
        lvar

Starting with an empty binding is akin to saying that we start with zero knowledge.

    F.ignorance = new Bindings()

As mentioned, because we overwrite bindings as we discover them the lookup logic is a little pernicious in the face of logic variables bound to other logic variables.

    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

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

Unification is the process of improving knowledge: or, the process of measurement. That measurement may uncover a contradiction though (things are not what we thought them to be). To be precise, the unification is the statement that two terms are the same. For example, unification of `1` and `1` is successful -- `1` is indeed the same as `1`. That doesn't add however to our knowledge of the world. If the logic variable `$x` is associated with `1` in the current bindings, the unification of `$x` with `2` yields a contradiction (the new measurement is not consistent with the previous measurements / hypotheses). Unification of an unbound logic variable `$x` and `1` improves our knowledge: the "measurement" found that `$x` is actually `1`. We record that fact in the new substitution.

Return the new bindings, or `null` on contradiction:

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

Find out what `l` actually is given our knowledge contained in `bindings`:

      t1 = bindings.lookup(l)

Find out what `r` actually is given our knowledge contained in `bindings`:

      t2 = bindings.lookup(r)

If `l` and `r` are the same; no new knowledge:

      if _.isEqual(t1, t2)
        return bindings

`l` is an unbound variable:

      if F.isLVar(t1)
        return bindings.extend(t1, t2)

`r` is an unbound variable:

      if F.isLVar(t2)
        return bindings.extend(t2, t1)

If t1 is a pair, so must be `r`.  This means that I can only unify arrays of nested arrays bottoming out on values or objects.  I cannot unify objects at the moment.

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

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

Now we can combine non-deterministic functions (Part 1) and the representation of knowledge (Part 2) into a logic system.  We introduce a `goal` -- a non-deterministic function that takes a substitution and produces 0, 1 or more other bindings (new knowledge). In case the goal produces 0 bindings, we say that the goal failed. We will call any result produced by the goal an "outcome".

The functions `succeed` and `fail` defined earlier are obviously  goals.  The latter is the failing goal. OTH, `succeed` is the trivial successful goal, a tautology that doesn't improve our knowledge of the world. We can now add another primitive goal, the result of a "measurement".  The quantum-mechanical connotations of "the measurement" must be obvious by now.

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

We also need a way to 'run' a goal, to see what knowledge we can obtain starting from sheer ignorance

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

# Logic programs
# --------------

We can build more complex goals using lambda-abstractions and previously defined combinators, `conj` and `disj`.  For example, we can define the function `choice` such that `choice(t1, array)` is a goal that succeeds if `t1` is an element of `array`.

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

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

The name `choice` should evoke [The Axiom of Choice](http://en.wikipedia.org/wiki/Axiom_of_choice)...

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

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

We build more complex non-deterministic functions by combining the existing ones with the help of the following two combinators.

`(disjunction l r)` returns all the results of `l` and all the results of `r`, or returns no results only if neither `l` nor `r` returned any.  In that sense, it is analogous to the logical disjunctionunction.

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

`(conjunction l r)` looks like a functional composition of `r` and `l`.  Only `(l x)` may return several results, so we have to apply `r` to each of them.  Obviously `(conjunction fail f)` and `(conjunction f fail)` are both equivalent to `fail`: they return no results, ever. It that sense, `conjunction` is analogous to the logical conjunction.

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

JavaScript allows you to pass any number of arguments to a function.  Therefore, we can make a function `disj` that takes any number of arguments and performs a logical disjunction over each.  This makes this version of Sokuza Kanren a bit more flexible in that it allows you to nest any number of relations therein.

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

Likewise, the `conj` function accepts any number of clauses, nit just two as in the original Sokuza.

    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))

And that's all that there is for the built-in non-deterministic functions.

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

One may think of regular variables as "certain knowledge": they give  names to definite values.  A logic variable then stands for "improvable ignorance".  An unbound logic variable represents no  knowledge at all; in other words, it represents the result of a measurement *before* we have done the measurement. A logic variable may be associated with a definite value, like 10. That means definite knowledge.  A logic variable may be associated with a semi-definite value, like `[$X]` where `$X` is an unbound variable. We know something about the original variable: it is associated with the array of one element.  We can't say though what that element is. A logic variable can be associated with another, unbound logic variable. In that case, we still don't know what precisely the original variable stands for. However, we can say that it represents the same thing as the other variable. So, our uncertainty is reduced.

I've chosen to represent logic variables with their own simple type.

    class LVar
      constructor: (@name) ->

I've also created a couple of helper functions for creating new variables and checking "variableness" to decouple the representation a bit.

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

I implement associations of logic variables and their values (aka, *bindings*) as a class holding a simple JavaScript object.  One may say that a substitution represents our current knowledge of the world.

    class Bindings
      constructor: (seed = {}) ->
        @binds = _.merge({}, seed)

There are actually two ways of implementing substitutions as associative list. If the variable `$x` is associated with `$y` and `$y` is associated with `1`, we could represent this knowledge as `{$x: 1, $y 1}`. It is easy to lookup the value associated with the variable then, via a simple access. OTH, if we have the binding `{$x:  $y}` and we wish to add the bindings of `$y` to `1`, we have to make rearrangements so to produce `{$x: 1, $y 1}`, or make the traversal on lookup (which we defer to `find` below).

However, if we use an association-list-like structure (arrays of pairs) then we can just record the associations as we learn them, without modifying the previous ones. If originally we knew `[[$x, $y]]` and later we learned that `$y` is associated with `1`, we can simply prepend the latter association, obtaining `[[$y, 1], [$x, $y]]`. So, adding new knowledge becomes fast. The lookup procedure becomes more complex though, as we have to chase the chains of variables. To obtain the value associated with `$x` in the latter substitution, we first lookup `$x`, obtain `$y` (another logic variable), then lookup `$y` finally obtaining `1`.  I prefer the object-representation since it's more idiomatic, but using an a-list provides an intuitively incremental way of representing knowledge: it is easier to backtrack if we later find out our knowledge leads to a contradiction.

      extend: (lvar, value) ->
        o = {}
        o[lvar.name] = value
        new Bindings(_.merge(@binds, o))
      has: (lvar) ->
        @binds.hasOwnProperty(lvar.name)

Find the value associated with `lvar` in the `Bindings` instance.  Return `lvar` itself if it is unbound. In miniKanren, this function is called `walk`.

    lookup: (lvar) ->
        return lvar if !F.isLVar(lvar)
        return this.lookup(@binds[lvar.name]) if this.has(lvar)
        lvar

Starting with an empty binding is akin to saying that we start with zero knowledge.

    F.ignorance = new Bindings()

As mentioned, because we overwrite bindings as we discover them the lookup logic is a little pernicious in the face of logic variables bound to other logic variables.

    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

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

Unification is the process of improving knowledge: or, the process of measurement. That measurement may uncover a contradiction though (things are not what we thought them to be). To be precise, the unification is the statement that two terms are the same. For example, unification of `1` and `1` is successful -- `1` is indeed the same as `1`. That doesn't add however to our knowledge of the world. If the logic variable `$x` is associated with `1` in the current bindings, the unification of `$x` with `2` yields a contradiction (the new measurement is not consistent with the previous measurements / hypotheses). Unification of an unbound logic variable `$x` and `1` improves our knowledge: the "measurement" found that `$x` is actually `1`. We record that fact in the new substitution.

Return the new bindings, or `null` on contradiction:

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

Find out what `l` actually is given our knowledge contained in `bindings`:

      t1 = bindings.lookup(l)

Find out what `r` actually is given our knowledge contained in `bindings`:

      t2 = bindings.lookup(r)

If `l` and `r` are the same; no new knowledge:

      if _.isEqual(t1, t2)
        return s

`l` is an unbound variable:

      if F.isLVar(t1)
        return bindings.extend(t1, t2)

`r` is an unbound variable:

      if F.isLVar(t2)
        return bindings.extend(t2, t1)

If t1 is a pair, so must be `r`.  This means that I can only unify arrays of nested arrays bottoming out on values or objects.  I cannot unify objects at the moment.

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

Now we can combine non-deterministic functions (Part 1) and the representation of knowledge (Part 2) into a logic system.  We introduce a `goal` -- a non-deterministic function that takes a substitution and produces 0, 1 or more other bindings (new knowledge). In case the goal produces 0 bindings, we say that the goal failed. We will call any result produced by the goal an "outcome".

The functions `succeed` and `fail` defined earlier are obviously  goals.  The latter is the failing goal. OTH, `succeed` is the trivial successful goal, a tautology that doesn't improve our knowledge of the world. We can now add another primitive goal, the result of a "measurement".  The quantum-mechanical connotations of "the measurement" must be obvious by now.

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

We also need a way to 'run' a goal, to see what knowledge we can obtain starting from sheer ignorance

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

# Logic programs
# --------------

We can build more complex goals using lambda-abstractions and previously defined combinators, `conj` and `disj`.  For example, we can define the function `choice` such that `choice(t1, array)` is a goal that succeeds if `t1` is an element of `array`.

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

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

The name `choice` should evoke [The Axiom of Choice](http://en.wikipedia.org/wiki/Axiom_of_choice)...

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

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

	)(this)


Add preview snapshot

Add preview snapshot

Dependencies
============

    _      = require "underscore"
    fs     = require "fs"
    path   = require "path"
    colors = require "cli-color"

VOSCO
=====

    script =

Setup
-----

      'install': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        if isInstalled then process.exit 1
        await @vosco.install defer(error)

      'uninstall': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.uninstall defer(error)

Repository
----------

      'get-status': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getStatus defer(error, status)
        getType = (file) -> file.type
        getPath = (file) -> colors.xterm(240)("  #{file.path}")
        groups  = _.groupBy status, getType
        for group, paths of groups
          console.log """
          #{group}
          #{paths.map(getPath).join("\n")}
          """

      'get-history': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getHistory defer(error, history)
        for commit in history
          hash = commit.hash.substr(0, 7)
          date = new Date(commit.date).toDateString()
          msg  = commit.message
          console.log colors.xterm(240)("  #{hash}  #{date}  #{msg}")

      'get-content-history': (path) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        # show warning if file doesn"t exist
        console.log "content history"

Snapshots
---------

      'preview-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        hash = hash or 'HEAD'
        await @vosco.previewSnapshot hash, defer(error, diff)
        console.log diff

      'create-snapshot': (message) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "creating snapshot"

      'rollback-to-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "rollback to snapshot"

Branches
--------

      'list-branches': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "branches list"

      'select-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "select branch"

      'create-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "create new branch"

      'delete-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "delete branch"

Export Module
-------------

    module.exports = (vosco) ->
      script.vosco = vosco
      return script

Dependencies
============

    _      = require "underscore"
    fs     = require "fs"
    path   = require "path"
    colors = require "cli-color"

VOSCO
=====

    script =

Setup
-----

      'install': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        if isInstalled then process.exit 1
        await @vosco.install defer(error)

      'uninstall': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.uninstall defer(error)

Repository
----------

      'get-status': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getStatus defer(error, status)
        getType = (file) -> file.type
        getPath = (file) -> colors.xterm(240)("  #{file.path}")
        groups  = _.groupBy status, getType
        for group, paths of groups
          console.log """
          #{group}
          #{paths.map(getPath).join("\n")}
          """

      'get-history': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getHistory defer(error, history)
        for commit in history
          hash = commit.hash.substr(0, 7)
          date = new Date(commit.date).toDateString()
          msg  = commit.message
          console.log colors.xterm(240)("  #{hash}  #{date}  #{msg}")

      'get-content-history': (path) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        # show warning if file doesn"t exist
        console.log "content history"

Snapshots
---------

      'preview-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "preview snapshot"

      'create-snapshot': (message) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "creating snapshot"

      'rollback-to-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "rollback to snapshot"

Branches
--------

      'list-branches': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "branches list"

      'select-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "select branch"

      'create-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "create new branch"

      'delete-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "delete branch"

Export Module
-------------

    module.exports = (vosco) ->
      script.vosco = vosco
      return script


AJAX port default domain

AJAX port default domain

    _self = this

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

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

    POLL_TYPE =
     progress: true

##Response class

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

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

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

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

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

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

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @queue.shift()
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @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'
       #Handled by caller
       throw new Error "No callback registered #{@method} #{options.status}"
      self = this
      setTimeout (-> self.callbacks[options.status] data, options), 0

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

##Port base class

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

     isStreaming: true

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

      @callsCache = {}

      @errorCallback msg, options

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

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

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

###Send RPC call

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

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

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

###Respond to a RPC call

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

      @_respond (@_createResponse response, status, data, options), portOptions, callback
      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]?
       @onHandleError "Unknown method: #{data.method}", data, options
       return
      @responses[data.id] = new Response data, this, options
      @handlers[data.method] data.data, data, @responses[data.id]

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

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

##WorkerPort class
Used for browser and worker

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

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

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

##SocketPort class

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

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

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

##ServerSocketPort class

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

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

##AJAX class

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

     isStreaming: false

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

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

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

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

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

##NodeHttpPort class

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

     isStreaming: false

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

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

       @_handleMessage jsonData, response: res

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

      res.write data
      res.end()

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

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       callbacks.fail? 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]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      if not call.handle data.data, data
       params =
        type: 'poll'
        id: call.id
       params[k] = v for k, v of call.options
       @_send params, call.callbacks

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http) ->
      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
        @errorCallback 'ParseError', e
        return

       @_handleMessage jsonData, response: res

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

      res.write data
      res.end()

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

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

#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

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

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

    POLL_TYPE =
     progress: true

##Response class

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

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

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

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

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

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

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @queue.shift()
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @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'
       #Handled by caller
       throw new Error "No callback registered #{@method} #{options.status}"
      self = this
      setTimeout (-> self.callbacks[options.status] data, options), 0

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

##Port base class

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

     isStreaming: true

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

      @callsCache = {}

      @errorCallback msg, options

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

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

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

###Send RPC call

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

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

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

###Respond to a RPC call

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

      @_respond (@_createResponse response, status, data, options), portOptions, callback
      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]?
       @onHandleError "Unknown method: #{data.method}", data, options
       return
      @responses[data.id] = new Response data, this, options
      @handlers[data.method] data.data, data, @responses[data.id]

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

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

##WorkerPort class
Used for browser and worker

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

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

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

##SocketPort class

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

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

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

##ServerSocketPort class

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

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

##AJAX class

    class AjaxHttpPort extends Port
     constructor: (options) ->
      super()
      @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? and xhr.responseText != '') or
          (status >= 200 and status < 300) or
          (status is 304))
       try
        jsonData = JSON.parse xhr.responseText
       catch e
        @onCallError 'ParseError', e
        return

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

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

     _send: (data) ->
      data = JSON.stringify data
      xhr = new XMLHttpRequest
      xhr.open 'POST', "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]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      try
       if call.handle data.data, data
        delete @callsCache[data.id]
       else
        params =
         type: 'poll'
         id: call.id
        params[k] = v for k, v of call.options
        @_send params
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

##NodeHttpPort class

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

     isStreaming: false

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

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

       @_handleMessage jsonData, response: res

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

      res.write data
      res.end()

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

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       callbacks.fail? 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]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      if not call.handle data.data, data
       params =
        type: 'poll'
        id: call.id
       params[k] = v for k, v of call.options
       @_send params, call.callbacks

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http) ->
      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
        @errorCallback 'ParseError', e
        return

       @_handleMessage jsonData, response: res

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

      res.write data
      res.end()

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

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

#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


Add get branches

Add get branches

Dependencies
============

    _      = require "underscore"
    fs     = require "fs"
    path   = require "path"
    colors = require "cli-color"

VOSCO
=====

    script =

Setup
-----

      'install': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        if isInstalled then process.exit 1
        await @vosco.install defer(error)

      'uninstall': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.uninstall defer(error)

Repository
----------

      'get-status': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getStatus defer(error, status)
        getType = (file) -> file.type
        getPath = (file) -> colors.xterm(240)("  #{file.path}")
        groups  = _.groupBy status, getType
        for group, paths of groups
          console.log """
          #{group}
          #{paths.map(getPath).join("\n")}
          """

      'get-history': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getHistory defer(error, history)
        for commit in history
          hash = commit.hash.substr(0, 7)
          date = new Date(commit.date).toDateString()
          msg  = commit.message
          console.log colors.xterm(240)("  #{hash}  #{date}  #{msg}")

      'get-content-history': (path) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        # show warning if file doesn"t exist
        console.log "content history"

Snapshots
---------

      'preview-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        hash = hash or 'HEAD'
        await @vosco.previewSnapshot hash, defer(error, diff)
        console.log diff

      'create-snapshot': (message) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        message = message or 'Untitled Snapshot'
        await @vosco.createSnapshot message, defer(error)

      'rollback-to-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.rollbackToSnapshot hash, defer(error)

Branches
--------

      'get-branches': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getBranches defer(error, branches, current)
        for branch in branches
          branch = if branch is current then "* #{branch}" else
            colors.xterm(240)("  #{branch}")
          console.log "#{branch}"

      'create-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "create new branch"

      'select-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "select branch"

      'delete-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "delete branch"

Export Module
-------------

    module.exports = (vosco) ->
      script.vosco = vosco
      return script

Dependencies
============

    _      = require "underscore"
    fs     = require "fs"
    path   = require "path"
    colors = require "cli-color"

VOSCO
=====

    script =

Setup
-----

      'install': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        if isInstalled then process.exit 1
        await @vosco.install defer(error)

      'uninstall': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.uninstall defer(error)

Repository
----------

      'get-status': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getStatus defer(error, status)
        getType = (file) -> file.type
        getPath = (file) -> colors.xterm(240)("  #{file.path}")
        groups  = _.groupBy status, getType
        for group, paths of groups
          console.log """
          #{group}
          #{paths.map(getPath).join("\n")}
          """

      'get-history': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getHistory defer(error, history)
        for commit in history
          hash = commit.hash.substr(0, 7)
          date = new Date(commit.date).toDateString()
          msg  = commit.message
          console.log colors.xterm(240)("  #{hash}  #{date}  #{msg}")

      'get-content-history': (path) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        # show warning if file doesn"t exist
        console.log "content history"

Snapshots
---------

      'preview-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        hash = hash or 'HEAD'
        await @vosco.previewSnapshot hash, defer(error, diff)
        console.log diff

      'create-snapshot': (message) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        message = message or 'Untitled Snapshot'
        await @vosco.createSnapshot message, defer(error)

      'rollback-to-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.rollbackToSnapshot hash, defer(error)

Branches
--------

      'get-branches': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "branches list"

      'create-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "create new branch"

      'select-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "select branch"

      'delete-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "delete branch"

Export Module
-------------

    module.exports = (vosco) ->
      script.vosco = vosco
      return script


progress

progress

## Interface

### Compile:

String jtmpl(String template, AnyType model)

### Compile and bind (browser only):

void jtmpl(DOMElement target, String template, AnyType model)

`target` and `template` can be Strings in the format "#element-id".

    root = this
    jtmpl = root.jtmpl = (target, template, model, options) ->

      # Deprecated. `jtmpl(selector)`?
      if (target is null or typeof target is 'string') and not template?

        if not document?
          throw ':( this API is only available in a browser'

        return Array.prototype.slice.call(document.querySelectorAll(target))

      # `jtmpl(template, model)`?
      if typeof target is 'string' and
        typeof template in ['number', 'string', 'boolean', 'object'] and
        model is undefined

        options = model
        model = template
        template = target
        target = undefined

      # `jtmpl('#element-id', ...)`?
      if typeof target is 'string' and target.match(RE_IDENTIFIER)
        target = document.getElementById(target.substring(1))

      if not model?
        throw ':( no model'

      # `jtmpl('#template-id', ...)` or `jtmpl(element, '#template-id', ...)`
      template = document.getElementById(template.substring(1)).innerHTML
        if template.match and template.match(RE_IDENTIFIER)

      # options
      options = options or {}

      # string-separated opening and closing delimiter
      options.delimiters = (options.delimiters or '{{ }}').split(' ')
      # delimiters are changed in the generated HTML comment-enclosed section prototype
      # to avoid double-parsing
      options.compiledDelimiters = (options.compiledDelimiters or '<<< >>>').split(' ')

      # sections not enclosed in HTML tag are automatically enclosed
      options.defaultSection = options.defaultSectionTag or 'div'
      # default for section items
      options.defaultSectionItem = options.defaultSectionItem or 'div'
      # default for section items
      options.defaultVar = options.defaultVar or 'span'

      # default target tag
      options.defaultTargetTag = options.defaultTargetTag or 'div'

      # Compile template
      html = jtmpl.compile(template, model, 0, null, false, options)

## Rules

jtmpl is a processor of rules. There are two sequences,
one for each stage, compilation and binding.

Rules in each sequence are in increasing specificity order.

Both stages can be extended with new rules:
`jtmpl.compileRules.push({ ... })`, `jtmpl.bindRules.push({ ... })`

### Regular expression atoms

Used in various matchers

    RE_IDENTIFIER = '[\\w\\.\\-]+'
    RE_ANYTHING = '[\\s\\S]*?'

### Compile rules

Delimiters in `pattern`s are replaced with escaped options.delimiters, whitespace - stripped

Signatures:

String `replaceWith` (String for each group in pattern, AnyType model, Object context)

String `context.recurFunc` (AnyType model, String property, Boolean echoMode)

void `context.setWrapperAttr` (String attrName, String attrValue)

    jtmpl.compileRules = [

      { # {{var}}
        pattern: "{{ (#{ RE_IDENTIFIER }) }}"
        defaultWrapper: 'defaultVar'
        replaceWith: (prop, model) -> escapeHTML(model[prop])
      }

      { # {{unescaped_var}}
        pattern: "{{ & (#{ RE_IDENTIFIER }) }}"
        defaultWrapper: 'defaultVar'
        replaceWith: (prop, model) -> model[prop]
      }

      { # {{#block}}
        pattern: "{{ \\# (#{ RE_IDENTIFIER }) }}"
        defaultWrapper: 'defaultSection'
        replaceWith: (prop, model, context) ->
          val = model[prop]

          # Sequence?
          if Array.isArray(val)
            # template as HTML comment
            "<!-- # #{ context.recurFunc(null, prop, true) } -->"
            +
            # Render body for each item
            (context.recurFunc(item, prop) for item in val).join('')

          # Context?
          else if typeof val is 'object'
            # Render body using context
            context.recurFunc(val, prop)

          else
            # hide if falsy value
            if not val then context.setWrapperAttr('style', 'display:none')
            # Render body using model
            context.recurFunc(model, prop)
      }

      { # {{^block}}
        pattern: "{{ \\^ (#{ RE_IDENTIFIER }) }}"
        defaultWrapper: 'defaultSection'
        replaceWith: (prop, model, context) ->
          val = model[prop]

          # Sequence?
          if Array.isArray(val)
            # template as HTML comment
            "<!-- ^ #{ context.recurFunc(null, prop, true) } -->"
            +
            # Render body if array empty
            if not val.length then context.recurFunc(model, prop) else ''

          else
            # hide if truthy value
            if val then context.setWrapperAttr('style', 'display:none')
            # Render body using model
            context.recurFunc(model, prop)
      }

      { # class="...{{booleanVar}}
        pattern: "(class=\"? #{ RE_ANYTHING }) {{ (#{ RE_IDENTIFIER }) }}"
        replaceWith: (pre, prop, model) ->
          val = model[prop]
          # Emit match, and class name if true
          pre + (typeof val is 'boolean' and val and prop or '')
      }
    ]

### Bind rules

Matching is done on tokenized data-jt items

Signatures:

Function AnyType (AnyType val) `react`
(DOMElement node, String for each pattern group, AnyType model)

    bindRules = [

      { # var
        pattern: "#{ RE_IDENTIFIER }",
        react: (node) ->
          (val) -> node.innerHTML = val
      }

      { # attr=var
        pattern: "(#{ RE_IDENTIFIER }) = #{ RE_IDENTIFIER }",
        react: (node, attr) ->
          (val) -> if node[attr] isnt val then node[attr] = val
      }

      { # class=var
        pattern: "class = (#{ RE_IDENTIFIER })",
        react: (node, prop, model) ->
          (val) -> (val and addClass or removeClass)(node, prop)
      }

      { # value/checked/selected=var
        pattern: "(value | checked | selected) = (#{ RE_IDENTIFIER })",
        react: (node, attr, prop, model) ->
          (val) -> if node[attr] isnt val then node[attr] = val
      }

    ]

## Compile rules processor

Tokenize template and apply each rule

    jtmpl.compile = (template, model, position, openTag, echoMode, options) ->

      tokenizer = regexp("{{ (#{ RE_ANYTHING }) }}", options)

      while (token = tokenizer.exec(template))

        slice = template.slice(0, tokenizer.lastIndex)

        # Process rules in reverse order, most specific to least specific
        for rule in jtmpl.compileRules by -1

          match = regexp(rule.pattern).match(slice)
          if match
            return

## Bind rules processor

Walk DOM and setup reactors between model and nodes.

## Supporting code

### Array shortcuts

    ap = Array.prototype
    apslice = -> ap.slice

### Functional utilities

Function curry(Function f, AnyType frozenArg1, AnyType frozenArg2, ...)

    curry = ->
      args = apslice.call(arguments)
      ->
        args2 = apslice.call(arguments)
        args[0].apply(@, args.slice(1).concat(args2))

Function compose(Function f, Function g)

    compose = (f, g) -> -> f(g.apply(@, apslice.call(arguments)))

### Regular expression utilities

String escapeRE(String s)

Escape regular expression characters

    escapeRE = (s) -> (s + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1')

RegExp regexp(String src)

Replace mustaches with current delimiters, strip whitespace, return RegExp

    regexp = (src, options) ->
      new RegExp(src
        # triple mustache to alt non-escaped var output
        .replace('{{{', escapeRE(options.delimiters[0]) + '&')
        .replace('}}}', escapeRE(options.delimiters[1]))
        .replace('{{',  escapeRE(options.delimiters[0]))
        .replace('}}',  escapeRE(options.delimiters[1]))
        .replace(/\s+/g, '')
      )

### String utilities

String escapeHTML(String val)

Replace HTML special characters

    escapeHTML = (val) ->
      (val? and val or '')
        .toString()
        .replace /[&\"<>\\]/g, (s) ->
          switch s
            when '&' then '&'
            when '\\'then '\\\\'
            when '"' then '\"'
            when '<' then '<'
            when '>' then '>'
            else s

## Interface

    root = this
    root.jtmpl = (target, template, model, options) ->
      reId = /^\#[\w-]+$/

      # Deprecated. `jtmpl(selector)`?
      if (target is null or typeof target is 'string') and not template?
        if not document?
          throw ':( this API is only available in a browser'
        return Array.prototype.slice.call(document.querySelectorAll(target))

      # `jtmpl(template, model)`?
      if typeof target is 'string' and typeof template in ['number', 'string', 'boolean', 'object'] and model is undefined
        options = model
        model = template
        template = target
        target = undefined

      # `jtmpl('#element-id', ...)`?
      if typeof target is 'string' and target.match(reId)
        target = document.getElementById(target.substring(1))

      if not model?
        throw ':( no model'

      # `jtmpl('#template-id', ...)` or `jtmpl(element, '#template-id', ...)`
      template = document.getElementById(template.substring(1)).innerHTML if template.match and template.match(reId)

## Rules

jtmpl is a processor of rules. There are two sequences,
one for each stage, compilation and binding.

Rules in each sequence are in increasing specificity order.

Both stages can be extended with new rules:
`jtmpl.compileRules.push({ ... })`, `jtmpl.bindRules.push({ ... })`

### Regular expression atoms

Used in various matchers

    RE_IDENTIFIER = '[\\w\\.\\-]+'
    RE_ANYTHING = '[\\s\\S]*?'

### Compile rules

Delimiters in `pattern`s are replaced with escaped options.delimiters, whitespace - stripped

`replaceWith` signature
return: String
params: String for each group in pattern, AnyType model, Object context

    jtmpl.compileRules = [

      { # {{var}}
        pattern: "{{ (#{ RE_IDENTIFIER }) }}"
        defaultWrapper: 'defaultVar'
        replaceWith: (prop, model) -> model[prop]
      }

      { # {{#block}}
        pattern: "{{ \\# (#{ RE_IDENTIFIER }) }}"
        defaultWrapper: 'defaultSection'
        replaceWith: (prop, model, context) ->
          val = model[prop]

          # Sequence?
          if Array.isArray(val)
            # template as HTML comment
            "<!-- # #{ context.recurFunc(null, prop, true) } -->"
            +
            # Render body for each item
            (context.recurFunc(item, prop) for item in val).join('')

          # Context?
          else if typeof val is 'object'
            # Render body using context
            context.recurFunc(val, prop)

          else
            # hide if falsy value
            if not val then context.setWrapperAttr('style', 'display:none')
            # Render body using model
            context.recurFunc(model, prop)
      }

      { # {{^block}}
        pattern: "{{ \\^ (#{ RE_IDENTIFIER }) }}"
        defaultWrapper: 'defaultSection'
        replaceWith: (prop, model, context) ->
          val = model[prop]

          # Sequence?
          if Array.isArray(val)
            # template as HTML comment
            "<!-- ^ #{ context.recurFunc(null, prop, true) } -->"
            +
            # Render body if array empty
            if not val.length then context.recurFunc(model, prop) else ''

          else
            # hide if truthy value
            if val then context.setWrapperAttr('style', 'display:none')
            # Render body using model
            context.recurFunc(model, prop)
      }

      { # class="...{{booleanVar}}
        pattern: "(class=\"? #{ RE_ANYTHING }) {{ (#{ RE_IDENTIFIER }) }}"
        replaceWith: (pre, prop, model) ->
          val = model[prop]
          # Emit match, and class name if true
          pre + (typeof val is 'boolean' and val and prop or '')
      }
    ]

### Bind rules

Matching is done on tokenized data-jt items

`react` signature
return: function (AnyType val), to be called on prop change
params: DOMElement node, String for each pattern group, AnyType model

    bindRules = [

      { # var
        pattern: "#{ RE_IDENTIFIER }",
        react: (node) ->
          (val) -> node.innerHTML = val
      }

      { # attr=var
        pattern: "(#{ RE_IDENTIFIER }) = #{ RE_IDENTIFIER }",
        react: (node, attr) ->
          (val) -> if node[attr] isnt val then node[attr] = val
      }

      { # class=var
        pattern: "class = (#{ RE_IDENTIFIER })",
        react: (node, prop, model) ->
          (val) -> (val and addClass or removeClass)(node, prop)
      }

      { # value/checked/selected=var
        pattern: "(value | checked | selected) = (#{ RE_IDENTIFIER })",
        react: (node, attr, prop, model) ->
          (val) -> if node[attr] isnt val then node[attr] = val
      }

    ]

## Compile rules processor

Tokenize template and apply each rule

    jtmpl.compile = (template, model, position, openTag, echoMode) ->

      tokenizer = jtmpl.regexp("{{ (#{ RE_ANYTHING }) }}")

      while (token = tokenizer.exec(template))

        slice = template.slice(0, tokenizer.lastIndex)

        # Process rules in reverse order, most specific to least specific
        for i in [jtmpl.compileRules.length - 1..0] by -1

          rule = jtmpl.compileRules[i]
          match = rule.pattern.match(slice)

## Utility functions

Replace mustaches with current delimiters, strip whitespace, return RegExp

    jtmpl.regexp = (re) ->