Added a little comment about conso.  Need to make a distinction between JS _.cons and Scheme cons

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

For convenience I'll add a couple of readily accessible logic variables:

    F.$x = F.lvar("x")
    F.$y = F.lvar("y")

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), but I'll use a more common name:

      F.membero = F.choice

Now I can write a very primitive program: find an element that is common in two lists:

    F.commono = (l, r) ->
      $x = F.lvar("x")
      F.conj(F.choice($x, l),
             F.choice($x, r))

Now for something a little different.

    F.conso = ($a, $b, list) -> F.goal(_.cons($a, $b), list)

`conso` is a goal that succeeds if in the current state of the world, `_.cons($a, $b)` is the same as `l`.  That may, at first, sound like the meaning of cons. However, the declarative formulation is more powerful, because `$a`, `$b`, or `l` might be logic variables.

    F.joino = ($a, $b, list) -> F.goal([$a, $b], list)

TODO - more examples

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

For convenience I'll add a couple of readily accessible logic variables:

    F.$x = F.lvar("x")
    F.$y = F.lvar("y")

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), but I'll use a more common name:

      F.membero = F.choice

Now I can write a very primitive program: find an element that is common in two lists:

    F.commono = (l, r) ->
      $x = F.lvar("x")
      F.conj(F.choice($x, l),
             F.choice($x, r))

    F.conso = ($a, $b, list) -> F.goal(_.cons($a, $b), list)

    F.joino = ($a, $b, list) -> F.goal([$a, $b], list)

TODO - more examples

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

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

	)(this)


Move coco to fit docs.

Move coco to fit docs.

# Configuration

GLP is configured using a specific grammar for explaining how to build a gulp
project. This grammar allows you to easily explain both simple and complicated
build processes in a single configuration file.

The file should be named **glp.yml** and can be placed in your project's root
directory, or it can be placed in an `etc` directory if preferred. You can
also include the configuration in your standard user-level or system-wide
configuration directories.

This document aims to provide a descriptive explanation of all configuration
and best practices for configuration options available to users of GLP.

GLP configuration options can be split up into the following high level
categories:

- **root** tells GLP where to place it's output files.
- **files** with *named groups* and where to find them
- **filters** for introducing new ways to transform files in *file group*
- **plugins** options for changing the way that glp uses them for each *file group*
- **concatenators** for defining which plugins are used for joining files in a *file group*
- **minifiers** for changing how a *file group* is minified
- **extensions** for defining the suffix of output files for each *file group*.
- **liveReload** options for defining changes affect your browser after compiling.
- **static** options for defining routing of built files to a local web server
- **tasks** to overlay different groupings of options based on command-line arguments

The following document will walk you step-by-step through GLP's default
configuration. It should help increase familiarity with all features, and how
to get started with building your own software using GLP and your favorite
programming languages.

## How GLP configuration works

This is a `.litcoffee` file, so we will be using the default configuration as a
practical example of what you can do when writing a configuration file. The
documented values are exactly what is exported to the compiler in GLP.

    module.exports =

These defaults are always overridden with any user-specific settings. When a
configuration file is loaded, GLP will run [lodash.merge][lodashmerge] in order
to merge the user's configuration data over the defaults. Once this is done,
the current *task* is merged in order to define commands which change behavior.

The one exception to this rule is the *files* option, which will be completely
overriden if provided by a user instead of being merged into the default
configuration. The *files* option will still be merged (instead of replaced) if
modified by *tasks*.

Don't  feel discouraged if this seems confusing. It will make more sense as you
read through this document and develop a better understanding of GLP's options.

# Options

## root

This should be a string that contains the name of the directory where you would
like GLP to put build output files.

      root: 'public'

## watch

This should be a boolean. When true, GLP will continue watching for changes to
files after tasks finish. Otherwise, it will not watch for any changes to files.

      watch: no

## debug

If this is set to true, then GLP will provide you with an exhaustive amount of
information describing the build process.

      debug: no

## globOptions

This can be an object which describes the options that should be passed to the
`gulp,watch` and `gulp.src` functions. The keys of the object should be the
name of the task that the options are used with. The value for each task should
be the options as [documented here][gulpsrcopts]. If no options are defined for
the currently active task, then the 'default' options will be used.

      globOptions:
        default:
          options: {}

## cache

Options for controlling how GLP caches files for faster compiling while watching
files for changes.

      cache:

The `cache.enabled` option is false by default, but can be made true if caching
happens to be working as expected with your project. This feature is disabled
by default because it is still experimental.

        enabled: no

## minify

Options for controlling how GLP minifies files.

      minify:

The `minify.enabled` option is false by default. You can set it to true
if you would like to minify built files.

        enabled: no

The `minify.extension` option  can be changed if you'd like to use a custom
prefix extension. For instance, files with the extension **.js** will be
converted to **.min.js** when minification is turned on. If you set
`minify.extension` to an empty string, it will then be converted into.

        extension: '.min'

## ordering

Ordering is disabled by default, but if ordering looks wrong (this shouldn't
ever happen) then you can use this in order to map specific file types to the
ordering you'd want the files to be in. This supports the globbing same format
which is supported by `gulp.src` and `gulp.watch` which is more thoroughly
[documented here][gulpsrcopts].

      ordering: {}

## plugins

The plugins option allows users to define options for gulp all plugins which
are used in the build process. In order to do this, you provide an object
where plugin names are *keys* and the options object is what will be passed
to the related gulp plugin.

Whenever referring to gulp plugins in GLP, you can optionally omit the `gulp-`
prefix. For instance, telling GLP to use a plugin called *cached* is the same
as telling it to use *gulp-cached*. The plugins are standard gulp plugins, so
any standard gulp plugin should work with GLP.

GLP has verify flexible support for easily configuring plugins to be used
through gulp, and tries to be as transparent as possible without sacrificing
usability in the process.

      plugins:

By default, we ask the [gulp-cached][gulpcached] plugin to optimize memory by
storing the files as MD5 instead of the entire file contents.

        cached:
          optimizeMemory: yes

We also want [gulp-uglify][gulpuglify] to output source maps.

        uglify:
          outSourceMap: yes

And while we're developing, we want our templates to be readable. So, we tell
jade to render pretty files instead of spitting them out in a single line.

        jade:
          pretty: yes

We'll also want source maps, so let's enabled those.

        coffee:
          sourceMap: yes

The options provided here can also be overridden per-file-type with the
*filters* option as described in the next section. Every setting can be
overriden on a per-task basis as well. This means that we can tell GLP to not
output source maps, pretty templates, or any other option via the *tasks*
option as will also be defined later.

## filters

It's important to remember that you can use any gulp plugin with GLP by
installing it into your project with [npm][npm]. In order to let users define
arbitrary ways of transforming files, we have filters.

The *filters* option provide a way to transform file contents for different
types of files. Each type of file can be given a number of filters which can
be passed through by defining them with this option.

      filters:

For instance, scripts can be compiled as *coffee*. This example is the least
verbose way to define a new filter. Since an empty settings object is being
mapped to the *coffee* type, GLP will automatically transform using a plugin
called [gulp-coffee][gulpcoffee] and match this plugin against a glob which
will automatically be generated with the filter name. In this case, the glob
pattern would be `\*\*/\*.coffee`.

It's worth noting here that you can install **any** gulp plugin into your
project, and GLP will support it when you just add a new filter option for it.

It is possible that the most powerful feature of GLP is it's ability to let you
configure it for any type of file without needing to touch any source code in
the process. This configuration file is all that you will need.

        scripts:
          coffee: {}

Scripts can also be compiled from jade templates. Since we have grouped
filters with the *scripts* file group, we also know that we want the compiled
files to become scripts in the end. So, we can use the `options` key to
forward options to [gulp-jade][gulpjade] in this case.

          jade:
            options:
              client: true

Some more default formats are provided here:

          handlebars:
            matches: '**/*.hbs'

          coco:
            matches: '**/*.co'

For the stylesheets group, we set up *sass* and *less* so that they will be
bound to files with matching extensions. We have no special options in these
cases, so we can just assign an empty object to them and let GLP assign
defaults as described before.

        stylesheets:
          sass: {}
          less: {}

There are more specific cases for stylus, though. We want to use the
[gulp-stylus][gulpstylus] module and match it against both *.styl* and
*.stylus* file extensions. A more specific case is that we also want to use the
'nib' module by default, but still allow users to override that choice with the
global *plugins* option. That's what the *hints* option is for.

By default, the *options* in a filter override global *plugins* options. The
*hints* option provides the opposite, where the *plugins* options act as an
override. This isn't an extremely useful feature, but it's helpful here for
users that might not want to use *nib* with their stylus files. They could just
set `use` to an empty array in the *plugins* option to prevent it.

          stylus:
            transforms: 'stylus'

            hints:
              use: ['nib']

            matches: [
              '**/*.styl'
              '**/*.stylus'
            ]

Here we redefine jade, but this time we are defining it as a template. The
reason that we have to define this twice is because we want to give different
options to [gulp-jade][gulpjade] for templates instead of scripts. This allows
us to render *templates* as *HTML* files, but jade files in *scripts* will be
rendered as *js* files as  described previously.

        templates:
          jade:
            options:
              client: false

Some more default formats are provided here:

          haml: {}
          ejs: {}
          mustache: {}

          markdown:
            matches: ['**/*.md', '**/*.markdown']

## concatenators

If you need to use custom concatenation rules, you can define them here. This
can be set to an object which maps types of files to a plugin name. It can also
be set to an array if you need to use multiple concatenators. They will be
streamed through plugins in the order that they are provided.

When a plugin isn't defined in the *concatenators* option for a specific type,
GLP will set it to 'concat' as the default value. GLP will automatically prefix
plugin names with *gulp-*, so you don't need to do that. So, the default
concatenator could be found in [NPM][npm] as [gulp-concat][gulpconcat]

As an example use case, some users might want to compile all of their scripts
to [gulp-commonjs][gulpcommonjs] files and then pass the commonjs output to
[gulp-concat][gulpconcat] afterward. That could be done simply by adding a new
key to *concatenators*, such as: `scripts: ['commonjs', 'concat']` followed by
installing the necessary NPM plugins in your project directory.

      concatenators: {}

## extensions

      extensions:
        scripts: 'js'
        stylesheets: 'css'
        templates: 'html'

## minifiers

The minifiers option tells GLP how to minify files with different file
extensions. As an example, the default would use the [gulp-uglify][gulpuglify]
plugin for *js* files, and the [gulp-minify-css][gulpminifycss] plugin for css
files.

      minifiers:
        js: 'uglify'
        css: 'minify-css'

## files

Options for defining what types of files exist, where they are located, and
where they are placed after they have finished being built. The default
configuration will build many types of files from a directory called `src`,
and place them into the **root** directory (the default root is *public* as
described above) after they have been built.

      files:

Each type of file that needs built is given a name. The names can be whatever
you like, and any number of named types can be created. For instance, the
following files are called *scripts*:

        scripts:

Each type is an object which maps a path to a list of files. If a path ends
with a slash, then the files will be copied into a **directory** containing
an output file for every source file that was built. If the path does not
end with a slash, then the  *concatenators* for this type will be used.

In this case, we are building all files ending with `.js`, `.coffee` and a few
other extensions. After they are built, the resulting files will be placed in
the directory specified by the **root** function as separate files. If the
output file was not a **directory** (as denoted by the ending slash) then the
files would also be concatenated and the resulting file would be given the
*extension* which corresponds to this type of file.

          '/': [
            'src/**/*.js'
            'src/**/*.coffee'
            'src/**/*.co'
            'src/**/*.hbs'
          ]

Here, we are doing the same thing for *html*, *jade*, and some other file
extensions. This time we are outputting them with the `templates` file type.

        templates:
          '/': [
            'src/**/*.html'
            'src/**/*.jade'
            'src/**/*.md'
            'src/**/*.markdown'
            'src/**/*.haml'
            'src/**/*.ejs'
            'src/**/*.mustache'
          ]

We are doing the same thing here but using different files and associating
them to the *stylesheets* file type.

        stylesheets:
          '/': [
            'src/**/*.css'
            'src/**/*.less'
            'src/**/*.sass'
            'src/**/*.stylus'
          ]

## static

GLP can optionally run a static server. If this is enabled, then the path
specified by the *root* option will be server on the provided static server
port.

      static:

The `static.enabled` function can be true or false. If it is true, then glp
will run it's static server. If false, then the server will not be run.

        enabled: no

The `static.directories` option can be set to true if you want to server
directory indexes, but defaults to false in order to prevent accidental
exposure of file listenings.

        directories: no

The `static.catchAll` option can be set to a string containing a filename. If
set, then all URLs that don't have a static file ready on the server will be
redirected to the given filename. This allows HTML5-style routing without
needing to define every possible route through GLP.

        catchAll: null

The `static.port` option tells GLP what port to serve it's static server on. By
default, the [local server][localserver] will be on port `3333`.

        port: 3333

**NOTE:** Remember that the *watch* option is separated from the *static*
option, so that glp's static server isn't limited to only development
environments.  If *watch* is set to false, then the server will not reflect
your changes until the next time you rebuild the files being served.

## liveReload

The `liveReload` options allow you to change the way that your browser responds
when files are changed.

      liveReload:

You can enable or disable liveReload by setting the `liveReload.enabled` option
to true, or disable it with a value of false.

        enabled: no

You can set the `liveReload.port` to whichever port you want the `liveReload`
server to be listening on if the default value of 35729 is not sufficient.

        port: 35729

If you have `liveReload.enabled` set to a truthy value, you're using the GLP
static server, and you set `liveReload.inject` to a truthy value, then GLP will
automatically inject *livereload.js* into the app from within the static
server. This means that you don't need to change your templates or install any
browser addons in order to get instant feedback of changes in your browser.

        inject: yes

## tasks

Every action in GLP is ran via a *task*. For instance, when you run `glp` you
are actually running the *default* task. This can also be ran with the `glp
default` command if you feel like typing extra. GLP allows you to define any
arbitrary task that you would like.

All tasks can optionally be set to a configuration object. When a configuration
option is provided for a task *it will override* the previously defined
options. Some examples:

      tasks:

You could define a task that is exactly the same as the default task by
providing no option overrides, for instance. This is how the default task
is defined:

        default: {}

You could also request GLP to watch all of your files by overriding the *watch*
option and setting it to yes. This is how the `glp watch` command works:

        watch:
          watch: yes

You could extend this even further by watching files *and* running a static
server with liveReload enabled. Under the hood, this is how the `glp server`
command works:

        server:
          watch: yes

          static:
            enabled: yes

          liveReload:
            enabled: yes

Maybe you don't want to run any servers or watch any files, but you may still
like to make sure that a specific build process outputs it's files in a
different way. This is exactly how `glp release` works:

        release:
          minify:
            enabled: yes

          plugins:
            coffee:
              sourceMap: no

            uglify:
              outSourceMap: no

            jade:
              pretty: no

[npm]: https://www.npmjs.org/
[gulpsrcopts]: https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpsrcglobs-options
[gulpcoffee]: https://www.npmjs.org/package/gulp-coffee
[gulpjade]: https://www.npmjs.org/package/gulp-jade
[gulpstylus]: https://www.npmjs.org/package/gulp-stylus
[gulpconcat]: https://github.com/wearefractal/gulp-concat
[gulpuglify]: https://www.npmjs.org/package/gulp-uglify
[gulpminifycss]: https://www.npmjs.org/package/gulp-minify-css
[gulpcached]: https://www.npmjs.org/package/gulp-cached
[localserver]: http://localhost:3333/
[lodashmerge]: http://lodash.com/docs#merge

# Configuration

GLP is configured using a specific grammar for explaining how to build a gulp
project. This grammar allows you to easily explain both simple and complicated
build processes in a single configuration file.

The file should be named **glp.yml** and can be placed in your project's root
directory, or it can be placed in an `etc` directory if preferred. You can
also include the configuration in your standard user-level or system-wide
configuration directories.

This document aims to provide a descriptive explanation of all configuration
and best practices for configuration options available to users of GLP.

GLP configuration options can be split up into the following high level
categories:

- **root** tells GLP where to place it's output files.
- **files** with *named groups* and where to find them
- **filters** for introducing new ways to transform files in *file group*
- **plugins** options for changing the way that glp uses them for each *file group*
- **concatenators** for defining which plugins are used for joining files in a *file group*
- **minifiers** for changing how a *file group* is minified
- **extensions** for defining the suffix of output files for each *file group*.
- **liveReload** options for defining changes affect your browser after compiling.
- **static** options for defining routing of built files to a local web server
- **tasks** to overlay different groupings of options based on command-line arguments

The following document will walk you step-by-step through GLP's default
configuration. It should help increase familiarity with all features, and how
to get started with building your own software using GLP and your favorite
programming languages.

## How GLP configuration works

This is a `.litcoffee` file, so we will be using the default configuration as a
practical example of what you can do when writing a configuration file. The
documented values are exactly what is exported to the compiler in GLP.

    module.exports =

These defaults are always overridden with any user-specific settings. When a
configuration file is loaded, GLP will run [lodash.merge][lodashmerge] in order
to merge the user's configuration data over the defaults. Once this is done,
the current *task* is merged in order to define commands which change behavior.

The one exception to this rule is the *files* option, which will be completely
overriden if provided by a user instead of being merged into the default
configuration. The *files* option will still be merged (instead of replaced) if
modified by *tasks*.

Don't  feel discouraged if this seems confusing. It will make more sense as you
read through this document and develop a better understanding of GLP's options.

# Options

## root

This should be a string that contains the name of the directory where you would
like GLP to put build output files.

      root: 'public'

## watch

This should be a boolean. When true, GLP will continue watching for changes to
files after tasks finish. Otherwise, it will not watch for any changes to files.

      watch: no

## debug

If this is set to true, then GLP will provide you with an exhaustive amount of
information describing the build process.

      debug: no

## globOptions

This can be an object which describes the options that should be passed to the
`gulp,watch` and `gulp.src` functions. The keys of the object should be the
name of the task that the options are used with. The value for each task should
be the options as [documented here][gulpsrcopts]. If no options are defined for
the currently active task, then the 'default' options will be used.

      globOptions:
        default:
          options: {}

## cache

Options for controlling how GLP caches files for faster compiling while watching
files for changes.

      cache:

The `cache.enabled` option is false by default, but can be made true if caching
happens to be working as expected with your project. This feature is disabled
by default because it is still experimental.

        enabled: no

## minify

Options for controlling how GLP minifies files.

      minify:

The `minify.enabled` option is false by default. You can set it to true
if you would like to minify built files.

        enabled: no

The `minify.extension` option  can be changed if you'd like to use a custom
prefix extension. For instance, files with the extension **.js** will be
converted to **.min.js** when minification is turned on. If you set
`minify.extension` to an empty string, it will then be converted into.

        extension: '.min'

## ordering

Ordering is disabled by default, but if ordering looks wrong (this shouldn't
ever happen) then you can use this in order to map specific file types to the
ordering you'd want the files to be in. This supports the globbing same format
which is supported by `gulp.src` and `gulp.watch` which is more thoroughly
[documented here][gulpsrcopts].

      ordering: {}

## plugins

The plugins option allows users to define options for gulp all plugins which
are used in the build process. In order to do this, you provide an object
where plugin names are *keys* and the options object is what will be passed
to the related gulp plugin.

Whenever referring to gulp plugins in GLP, you can optionally omit the `gulp-`
prefix. For instance, telling GLP to use a plugin called *cached* is the same
as telling it to use *gulp-cached*. The plugins are standard gulp plugins, so
any standard gulp plugin should work with GLP.

GLP has verify flexible support for easily configuring plugins to be used
through gulp, and tries to be as transparent as possible without sacrificing
usability in the process.

      plugins:

By default, we ask the [gulp-cached][gulpcached] plugin to optimize memory by
storing the files as MD5 instead of the entire file contents.

        cached:
          optimizeMemory: yes

We also want [gulp-uglify][gulpuglify] to output source maps.

        uglify:
          outSourceMap: yes

And while we're developing, we want our templates to be readable. So, we tell
jade to render pretty files instead of spitting them out in a single line.

        jade:
          pretty: yes

We'll also want source maps, so let's enabled those.

        coffee:
          sourceMap: yes

The options provided here can also be overridden per-file-type with the
*filters* option as described in the next section. Every setting can be
overriden on a per-task basis as well. This means that we can tell GLP to not
output source maps, pretty templates, or any other option via the *tasks*
option as will also be defined later.

## filters

It's important to remember that you can use any gulp plugin with GLP by
installing it into your project with [npm][npm]. In order to let users define
arbitrary ways of transforming files, we have filters.

The *filters* option provide a way to transform file contents for different
types of files. Each type of file can be given a number of filters which can
be passed through by defining them with this option.

      filters:

For instance, scripts can be compiled as *coffee*. This example is the least
verbose way to define a new filter. Since an empty settings object is being
mapped to the *coffee* type, GLP will automatically transform using a plugin
called [gulp-coffee][gulpcoffee] and match this plugin against a glob which
will automatically be generated with the filter name. In this case, the glob
pattern would be `\*\*/\*.coffee`.

It's worth noting here that you can install **any** gulp plugin into your
project, and GLP will support it when you just add a new filter option for it.

It is possible that the most powerful feature of GLP is it's ability to let you
configure it for any type of file without needing to touch any source code in
the process. This configuration file is all that you will need.

        scripts:
          coffee: {}
          coco:
            matches: '**/*.co'

Scripts can also be compiled from jade templates. Since we have grouped
filters with the *scripts* file group, we also know that we want the compiled
files to become scripts in the end. So, we can use the `options` key to
forward options to [gulp-jade][gulpjade] in this case.

          jade:
            options:
              client: true

Some more default formats are provided here:

          handlebars:
            matches: '**/*.hbs'

For the stylesheets group, we set up *sass* and *less* so that they will be
bound to files with matching extensions. We have no special options in these
cases, so we can just assign an empty object to them and let GLP assign
defaults as described before.

        stylesheets:
          sass: {}
          less: {}

There are more specific cases for stylus, though. We want to use the
[gulp-stylus][gulpstylus] module and match it against both *.styl* and
*.stylus* file extensions. A more specific case is that we also want to use the
'nib' module by default, but still allow users to override that choice with the
global *plugins* option. That's what the *hints* option is for.

By default, the *options* in a filter override global *plugins* options. The
*hints* option provides the opposite, where the *plugins* options act as an
override. This isn't an extremely useful feature, but it's helpful here for
users that might not want to use *nib* with their stylus files. They could just
set `use` to an empty array in the *plugins* option to prevent it.

          stylus:
            transforms: 'stylus'

            hints:
              use: ['nib']

            matches: [
              '**/*.styl'
              '**/*.stylus'
            ]

Here we redefine jade, but this time we are defining it as a template. The
reason that we have to define this twice is because we want to give different
options to [gulp-jade][gulpjade] for templates instead of scripts. This allows
us to render *templates* as *HTML* files, but jade files in *scripts* will be
rendered as *js* files as  described previously.

        templates:
          jade:
            options:
              client: false

Some more default formats are provided here:

          haml: {}
          ejs: {}
          mustache: {}

          markdown:
            matches: ['**/*.md', '**/*.markdown']

## concatenators

If you need to use custom concatenation rules, you can define them here. This
can be set to an object which maps types of files to a plugin name. It can also
be set to an array if you need to use multiple concatenators. They will be
streamed through plugins in the order that they are provided.

When a plugin isn't defined in the *concatenators* option for a specific type,
GLP will set it to 'concat' as the default value. GLP will automatically prefix
plugin names with *gulp-*, so you don't need to do that. So, the default
concatenator could be found in [NPM][npm] as [gulp-concat][gulpconcat]

As an example use case, some users might want to compile all of their scripts
to [gulp-commonjs][gulpcommonjs] files and then pass the commonjs output to
[gulp-concat][gulpconcat] afterward. That could be done simply by adding a new
key to *concatenators*, such as: `scripts: ['commonjs', 'concat']` followed by
installing the necessary NPM plugins in your project directory.

      concatenators: {}

## extensions

      extensions:
        scripts: 'js'
        stylesheets: 'css'
        templates: 'html'

## minifiers

The minifiers option tells GLP how to minify files with different file
extensions. As an example, the default would use the [gulp-uglify][gulpuglify]
plugin for *js* files, and the [gulp-minify-css][gulpminifycss] plugin for css
files.

      minifiers:
        js: 'uglify'
        css: 'minify-css'

## files

Options for defining what types of files exist, where they are located, and
where they are placed after they have finished being built. The default
configuration will build many types of files from a directory called `src`,
and place them into the **root** directory (the default root is *public* as
described above) after they have been built.

      files:

Each type of file that needs built is given a name. The names can be whatever
you like, and any number of named types can be created. For instance, the
following files are called *scripts*:

        scripts:

Each type is an object which maps a path to a list of files. If a path ends
with a slash, then the files will be copied into a **directory** containing
an output file for every source file that was built. If the path does not
end with a slash, then the  *concatenators* for this type will be used.

In this case, we are building all files ending with `.js`, `.coffee` and a few
other extensions. After they are built, the resulting files will be placed in
the directory specified by the **root** function as separate files. If the
output file was not a **directory** (as denoted by the ending slash) then the
files would also be concatenated and the resulting file would be given the
*extension* which corresponds to this type of file.

          '/': [
            'src/**/*.js'
            'src/**/*.coffee'
            'src/**/*.co'
            'src/**/*.hbs'
          ]

Here, we are doing the same thing for *html*, *jade*, and some other file
extensions. This time we are outputting them with the `templates` file type.

        templates:
          '/': [
            'src/**/*.html'
            'src/**/*.jade'
            'src/**/*.md'
            'src/**/*.markdown'
            'src/**/*.haml'
            'src/**/*.ejs'
            'src/**/*.mustache'
          ]

We are doing the same thing here but using different files and associating
them to the *stylesheets* file type.

        stylesheets:
          '/': [
            'src/**/*.css'
            'src/**/*.less'
            'src/**/*.sass'
            'src/**/*.stylus'
          ]

## static

GLP can optionally run a static server. If this is enabled, then the path
specified by the *root* option will be server on the provided static server
port.

      static:

The `static.enabled` function can be true or false. If it is true, then glp
will run it's static server. If false, then the server will not be run.

        enabled: no

The `static.directories` option can be set to true if you want to server
directory indexes, but defaults to false in order to prevent accidental
exposure of file listenings.

        directories: no

The `static.catchAll` option can be set to a string containing a filename. If
set, then all URLs that don't have a static file ready on the server will be
redirected to the given filename. This allows HTML5-style routing without
needing to define every possible route through GLP.

        catchAll: null

The `static.port` option tells GLP what port to serve it's static server on. By
default, the [local server][localserver] will be on port `3333`.

        port: 3333

**NOTE:** Remember that the *watch* option is separated from the *static*
option, so that glp's static server isn't limited to only development
environments.  If *watch* is set to false, then the server will not reflect
your changes until the next time you rebuild the files being served.

## liveReload

The `liveReload` options allow you to change the way that your browser responds
when files are changed.

      liveReload:

You can enable or disable liveReload by setting the `liveReload.enabled` option
to true, or disable it with a value of false.

        enabled: no

You can set the `liveReload.port` to whichever port you want the `liveReload`
server to be listening on if the default value of 35729 is not sufficient.

        port: 35729

If you have `liveReload.enabled` set to a truthy value, you're using the GLP
static server, and you set `liveReload.inject` to a truthy value, then GLP will
automatically inject *livereload.js* into the app from within the static
server. This means that you don't need to change your templates or install any
browser addons in order to get instant feedback of changes in your browser.

        inject: yes

## tasks

Every action in GLP is ran via a *task*. For instance, when you run `glp` you
are actually running the *default* task. This can also be ran with the `glp
default` command if you feel like typing extra. GLP allows you to define any
arbitrary task that you would like.

All tasks can optionally be set to a configuration object. When a configuration
option is provided for a task *it will override* the previously defined
options. Some examples:

      tasks:

You could define a task that is exactly the same as the default task by
providing no option overrides, for instance. This is how the default task
is defined:

        default: {}

You could also request GLP to watch all of your files by overriding the *watch*
option and setting it to yes. This is how the `glp watch` command works:

        watch:
          watch: yes

You could extend this even further by watching files *and* running a static
server with liveReload enabled. Under the hood, this is how the `glp server`
command works:

        server:
          watch: yes

          static:
            enabled: yes

          liveReload:
            enabled: yes

Maybe you don't want to run any servers or watch any files, but you may still
like to make sure that a specific build process outputs it's files in a
different way. This is exactly how `glp release` works:

        release:
          minify:
            enabled: yes

          plugins:
            coffee:
              sourceMap: no

            uglify:
              outSourceMap: no

            jade:
              pretty: no

[npm]: https://www.npmjs.org/
[gulpsrcopts]: https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpsrcglobs-options
[gulpcoffee]: https://www.npmjs.org/package/gulp-coffee
[gulpjade]: https://www.npmjs.org/package/gulp-jade
[gulpstylus]: https://www.npmjs.org/package/gulp-stylus
[gulpconcat]: https://github.com/wearefractal/gulp-concat
[gulpuglify]: https://www.npmjs.org/package/gulp-uglify
[gulpminifycss]: https://www.npmjs.org/package/gulp-minify-css
[gulpcached]: https://www.npmjs.org/package/gulp-cached
[localserver]: http://localhost:3333/
[lodashmerge]: http://lodash.com/docs#merge


ensure that changed state is preserved across multiple set/merge operations on a property before commit even if new value is same as previous value

# Property - controller of Object properties

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

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

property | type | mapping | description
--- | --- | --- | ---
name   | string | direct | name of the property
schema | object | direct | a schema instance (usually [Yang](./src/yang.listcoffee))
state  | object | direct | *private* object holding internal state
configurable | boolean | getter(state) | defines whether this property can be redefined
enumerable   | boolean | getter(state) | defines whether this property is enumerable
content | any | computed | getter/setter for `state.value`
context | object | computed | dynamically generated using [context](./src/context.coffee)
root  | [Property](./src/property.litcoffee) | computed | dynamically returns the root Property instance
path  | [XPath](./src/xpath.coffee) | computed | dynamically generate XPath for this Property from root

## Class Property

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

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

      constructor: (spec={}) ->
        # NOTE: ES6/CS2 does not support below
        # unless this instanceof Property then return new Property arguments...

        # 1. parse if spec is YANG definition (string)
        spec = Yang.parse spec if typeof spec is 'string'

        # 2. assign if spec is an instance of Yang schema
        schema = spec if spec instanceof Yang

        # 3. destructure spec as an object if not schema as instance
        { name, schema } = spec unless schema?

        # 4. parse if schema is YANG definition (string)
        schema = Yang.parse schema if typeof schema is 'string'
        schema ?= kind: 'anydata'

        # 5. initialize property instance
        @name = name ? schema.datakey
        @schema = schema
        @state =
          parent:    null
          strict:    false
          private:   false
          mutable:   `schema.config != false`
          attached:  false
          changed:   false
          prior:     undefined
          value:     undefined

        # 6. soft freeze this instance
        Object.preventExtensions this

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

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

### Computed Properties

      @property 'value',
        get: -> @state.value

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

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

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

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

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

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

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

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

## Instance-level methods

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

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

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

### get (key)

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

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

      get: (key) -> switch
        when key?
          try match = @find key
          return unless match? and match.length
          switch
            when match.length is 1 then match[0].data
            when match.length > 1  then match.map (x) -> x.data
            else undefined
        else @data

### set (value)

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

      set: (value, opts={}) ->
        opts.origin ?= this

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

        if not opts.force and @binding?.set?
          try value = @binding.set @context.with(opts), value
          catch e
            throw @error "failed executing set() binding: #{e.message}", e

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

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

### merge (value)

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

      merge: (value, opts={}) ->
        opts.origin ?= this
        return @delete opts if value is null
        return @set value, opts

### delete

      delete: (opts={}) ->
        opts.origin ?= this
        return this if @state.value is null
        if not opts.force and @binding?.delete?
          try @binding.delete @context.with(opts), null
          catch e
            throw @error "failed executing delete() binding: #{e.message}", e
        @update null, opts

### update

Updates the value to the data model. Called *once* for each node that
is part of the change branch.

      update: (value, opts={}) ->
        opts.origin ?= this
        @state.prior ?= @state.value
        @state.changed = @state.changed or (@state.value isnt value)
        @state.value = value
        @parent?.update this, opts # unless opts.suppress
        return this

### commit async transaction

Commits the changes to the data model. Called *once* for each node that
is part of the change branch.

      commit: (opts={}) ->
        opts.origin ?= this
        return true unless @changed
        try
          unless opts.sync
            # 1. perform save binding
            @debug "[commit] execute binding..."
            await @binding?.commit? @context.with(opts)
            # 2. if has parent, then wait for parent commited before updating changed state
            promise = @parent?.commit? opts
              .then (ok) =>
                @state.changed = false if ok
          unless promise?
            @state.changed = false
        catch err
          @debug "[commit] revert due to #{err.message}"
          await @revert opts
          throw @error err
        return true

      revert: (opts={}) ->
        return unless @changed

        @delete opts unless @state.prior?
        @state.value = @state.prior

        @debug "[revert] execute binding..."
        try await @binding?.commit? @context.with(opts) unless opts.sync
        catch err
          @debug "[revert] failed due to #{err.message}"
          throw @error err

        @state.changed = false

### attach (obj, parent, opts)

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

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

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

          @set obj[name], Object.assign {}, opts, inner: true, suppress: true

        unless opts.preserve
          try Object.defineProperty obj, @name,
              configurable: true
              enumerable: @enumerable
              get: (args...) => @get args...
              set: (args...) => @set args...

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

### find (pattern)

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

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

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

      find: (pattern='.', opts={}) ->
        @debug "[find] #{pattern}"
        pattern = XPath.parse pattern, @schema
        switch
          when pattern.tag is '/'  and this isnt @root then @root.find(pattern)
          when pattern.tag is '..' then @parent?.find pattern.xpath
          else pattern.apply(this) ? []

### in (pattern)

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

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

### defer (value)

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

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

### error (msg)

Provides more contextual error message pertaining to the Property instance.

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

### toJSON

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

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

### inspect

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

## Export Property Class

    module.exports = Property

# Property - controller of Object properties

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

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

property | type | mapping | description
--- | --- | --- | ---
name   | string | direct | name of the property
schema | object | direct | a schema instance (usually [Yang](./src/yang.listcoffee))
state  | object | direct | *private* object holding internal state
configurable | boolean | getter(state) | defines whether this property can be redefined
enumerable   | boolean | getter(state) | defines whether this property is enumerable
content | any | computed | getter/setter for `state.value`
context | object | computed | dynamically generated using [context](./src/context.coffee)
root  | [Property](./src/property.litcoffee) | computed | dynamically returns the root Property instance
path  | [XPath](./src/xpath.coffee) | computed | dynamically generate XPath for this Property from root

## Class Property

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

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

      constructor: (spec={}) ->
        # NOTE: ES6/CS2 does not support below
        # unless this instanceof Property then return new Property arguments...

        # 1. parse if spec is YANG definition (string)
        spec = Yang.parse spec if typeof spec is 'string'

        # 2. assign if spec is an instance of Yang schema
        schema = spec if spec instanceof Yang

        # 3. destructure spec as an object if not schema as instance
        { name, schema } = spec unless schema?

        # 4. parse if schema is YANG definition (string)
        schema = Yang.parse schema if typeof schema is 'string'
        schema ?= kind: 'anydata'

        # 5. initialize property instance
        @name = name ? schema.datakey
        @schema = schema
        @state =
          parent:    null
          strict:    false
          private:   false
          mutable:   `schema.config != false`
          attached:  false
          changed:   false
          prior:     undefined
          value:     undefined

        # 6. soft freeze this instance
        Object.preventExtensions this

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

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

### Computed Properties

      @property 'value',
        get: -> @state.value

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

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

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

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

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

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

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

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

## Instance-level methods

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

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

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

### get (key)

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

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

      get: (key) -> switch
        when key?
          try match = @find key
          return unless match? and match.length
          switch
            when match.length is 1 then match[0].data
            when match.length > 1  then match.map (x) -> x.data
            else undefined
        else @data

### set (value)

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

      set: (value, opts={}) ->
        opts.origin ?= this

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

        if not opts.force and @binding?.set?
          try value = @binding.set @context.with(opts), value
          catch e
            throw @error "failed executing set() binding: #{e.message}", e

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

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

### merge (value)

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

      merge: (value, opts={}) ->
        opts.origin ?= this
        return @delete opts if value is null
        return @set value, opts

### delete

      delete: (opts={}) ->
        opts.origin ?= this
        return this if @state.value is null
        if not opts.force and @binding?.delete?
          try @binding.delete @context.with(opts), null
          catch e
            throw @error "failed executing delete() binding: #{e.message}", e
        @update null, opts

### update

Updates the value to the data model. Called *once* for each node that
is part of the change branch.

      update: (value, opts={}) ->
        opts.origin ?= this
        @state.prior ?= @state.value
        @state.changed = @state.value isnt value
        @state.value = value
        @parent?.update this, opts # unless opts.suppress
        return this

### commit async transaction

Commits the changes to the data model. Called *once* for each node that
is part of the change branch.

      commit: (opts={}) ->
        opts.origin ?= this
        return true unless @changed
        try
          unless opts.sync
            # 1. perform save binding
            @debug "[commit] execute binding..."
            await @binding?.commit? @context.with(opts)
            # 2. if has parent, then wait for parent commited before updating changed state
            promise = @parent?.commit? opts
              .then (ok) =>
                @state.changed = false if ok
          unless promise?
            @state.changed = false
        catch err
          @debug "[commit] revert due to #{err.message}"
          await @revert opts
          throw @error err
        return true

      revert: (opts={}) ->
        return unless @changed

        @delete opts unless @state.prior? # XXX - prior not good indicator
        @state.value = @state.prior

        @debug "[revert] execute binding..."
        try await @binding?.commit? @context.with(opts) unless opts.sync
        catch err
          @debug "[revert] failed due to #{err.message}"
          throw @error err

        @state.changed = false

### attach (obj, parent, opts)

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

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

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

          @set obj[name], Object.assign {}, opts, inner: true, suppress: true

        unless opts.preserve
          try Object.defineProperty obj, @name,
              configurable: true
              enumerable: @enumerable
              get: (args...) => @get args...
              set: (args...) => @set args...

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

### find (pattern)

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

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

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

      find: (pattern='.', opts={}) ->
        @debug "[find] #{pattern}"
        pattern = XPath.parse pattern, @schema
        switch
          when pattern.tag is '/'  and this isnt @root then @root.find(pattern)
          when pattern.tag is '..' then @parent?.find pattern.xpath
          else pattern.apply(this) ? []

### in (pattern)

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

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

### defer (value)

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

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

### error (msg)

Provides more contextual error message pertaining to the Property instance.

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

### toJSON

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

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

### inspect

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

## Export Property Class

    module.exports = Property