make new instance of 'opts' for dealing with include dependency during import, see #59

# Yang - evaluable schema expression

This module provides support for basic set of YANG schema modeling
language by using the built-in *extension* syntax to define additional
schema language constructs. The actual YANG language [RFC
6020](http://tools.ietf.org/html/rfc6020) specifications are loaded
inside the [main module](./main.coffee).

This module is the **primary interface** for consumers of this
library.

## Dependencies

    debug  = require('debug')('yang:schema') if process.env.DEBUG?
    fs     = require 'fs'
    path   = require 'path'
    parser = require 'yang-parser'
    indent = require 'indent-string'

    Expression = require './expression'

## Class Yang

    class Yang extends Expression
      @scope:
        extension: '0..n'
        typedef:   '0..n'
        module:    '0..n'
        submodule: '0..n'

## Class-level methods

      @clear: ->
        @module.splice(0,@module.length) if @module?
        @submodule.splice(0,@submodule.length) if @submodule?

### parse (schema)

This class-level routine performs recursive parsing of passed in
statement and sub-statements. It provides syntactic, semantic and
contextual validations on the provided schema and returns the final JS
object tree structure as hierarchical Yang expression instances.

If any validation errors are encountered, it will throw the
appropriate error along with the context information regarding the
error.

      @parse: (schema, opts={}) ->
        opts.compile ?= true
        try
          schema = parser.parse schema if typeof schema is 'string'
        catch e
          e.offset = 50 unless e.offset > 50
          offender = schema.slice e.offset-50, e.offset+50
          offender = offender.replace /\s\s+/g, ' '
          throw @error "invalid YANG syntax detected around: '#{offender}'", offender

        unless schema instanceof Object
          throw @error "must pass in valid YANG schema", schema

        kind = switch
          when !!schema.prf then "#{schema.prf}:#{schema.kw}"
          else schema.kw
        tag = schema.arg if !!schema.arg

        schema = (new this kind, tag).extends schema.substmts.map (x) => @parse x, compile: false
        # perform final scoped constraint validation
        for kind, constraint of schema.scope when constraint in [ '1', '1..n' ]
          unless schema.hasOwnProperty kind
            throw schema.error "constraint violation for required '#{kind}' = #{constraint}"
        schema.compile() if opts.compile
        return schema

For comprehensive overview on currently supported YANG statements,
please refer to
[Compliance Report](../test/yang-compliance-coverage.md) for the latest
[RFC 6020](http://tools.ietf.org/html/rfc6020) YANG specification
compliance.

### compose (data [, opts={}])

This call *accepts* any arbitrary JS object and it will attempt to
convert it into a structural `Yang` expression instance. It will
analyze the passed in JS data and perform best match mapping to an
appropriate YANG schema representation to describe the input
data. This method will not be able to determine conditionals or any
meta-data to further constrain the data, but it should provide a good
starting point with the resulting `Yang` expression instance.

      @compose: (data, opts={}) ->
        unless data?
          throw @error "must supply input 'data' to compose"

        # explict compose
        if opts.kind?
          ext = Yang::lookup.call this, 'extension', opts.kind
          unless ext instanceof Expression
            throw @error "unable to find requested '#{opts.kind}' extension"
          return ext.compose? data, opts

        # implicit compose (dynamic discovery)
        for ext in @extension when ext.compose instanceof Function
          debug? "checking data if #{ext.tag}"
          res = ext.compose data, opts
          return res if res instanceof Yang

This facility is a powerful construct to dynamically generate `Yang`
schema from ordinary JS objects. For additional usage examples, please
refer to [Dynamic Composition](../TUTORIAL.md#dynamic-composition)
section in the [Getting Started Guide](../TUTORIAL.md).

### resolve (from..., name)

This call is internally used by [import](#import-name-opts) to
perform a search within the local filesystem to locate a given YANG
schema module by `name`. It will first check the calling code's local
[package.json](../package.json) to look for a `models: {}`
configuration section to identify where the target module can be
found. If there is an entry defined, it will then follow that
reference - which may be a JS file, YANG schema text file, or another
NPM module. If it is not found within the `models: {}` configuration
block or it fails to load the referenced dependency, it will then
fallback to attempt to locate a YANG schema text file in the same
folder that the `resolve` request was made: `#{name}.yang`.

      @resolve: (from..., name) ->
        return null unless typeof name is 'string'
        dir = from = switch
          when from.length then from[0]
          else path.resolve()
        while not found? and dir not in [ '/', '.' ]
          target = "#{dir}/package.json"
          debug? "[resolve] #{name} in #{target}"
          try
            pkginfo = require(target)
            found = pkginfo.models[name]
          if found?
            dir = path.dirname require.resolve(target)
            debug? "[resolve] #{name} check #{found} in #{dir}"
            unless !!path.extname found
              from = switch
                when found of pkginfo.dependencies
                  path.resolve dir, 'node_modules', found
                else path.resolve dir, found
              if fs.existsSync from
                return @resolve from, name
              else
                found = @resolve found, name
          if not found? and pkginfo?.name is name
            found = path.dirname require.resolve(target)
          dir = path.dirname dir unless found?
        file = switch
          when not found? then path.resolve from, "#{name}.yang"
          else path.resolve dir, found
        debug? "[resolve] checking if #{file} exists"
        return if fs.existsSync file then file else null

### import (name [, opts={}])

This call provides a convenience mechanism for dealing with YANG
schema module dependencies. It performs parsing of the YANG schema
content from the specified `name` and saves the generated `Yang`
expression inside the internal registry. The `name` can be a YANG
module name or a *filename* to the actual schema content (JS or YANG).

Once a given YANG module has been saved inside the registry,
subsequent [parse](#parse-schema) of YANG schema that *import* the
saved module will successfully resolve.

Typical usage scenario for this pattern is to internally define common
modules such as `ietf-yang-types` which can then be *imported* by
other schemas.

It will also return the new `Yang` expression instance (to do with as
you please).

      @require: ->
        console.warn "DEPRECATION: please use .import() instead"
        @import arguments...

      @import: (name, opts={}) ->
        return unless name?
        opts.basedir ?= ''
        extname  = path.extname name
        filename = path.resolve opts.basedir, name
        basedir  = path.dirname filename

        unless !!extname
          return (Yang::match.call this, 'module', name) ? @import (@resolve name), opts

        unless extname is '.yang'
          res = require filename
          unless res instanceof Yang
            throw @error "unable to import '#{name}' from '#{filename}' (not Yang expression)", res
          return res

        try return @use (@parse (fs.readFileSync filename, 'utf-8'), opts)
        catch e
          unless opts.compile and e.name is 'ExpressionError' and e.context.kind in [ 'include', 'import' ]
            console.error "unable to #{e.context.kind} '#{name}' YANG module from '#{filename}'"
            throw e
          if e.context.kind is 'include'
            opts = Object.assign {}, opts
            opts.compile = false

          # try to find the dependency module for import
          dependency = @import (@resolve basedir, e.context.tag), opts
          unless dependency?
            e.message = "unable to auto-resolve '#{e.context.tag}' dependency module"
            throw e

          # retry the original request
          debug? "retrying import(#{name})"
          return @import arguments...

Please note that this method will look for the `name` in current
working directory of the script execution if the `name` is a relative
path. It utilizes the [resolve](#resolve-from-name) method and will
attempt to **recursively** resolve any failed `import` dependencies.

While this is a convenient abstraction, it is **recommended** to
directly use the Node.js built-in `require` mechanism (if
available). Using native `require` instead of `Yang.import` will
allow package bundlers such as `browserify` to capture the
dependencies as part of the produced bundle.  It also allows you to
directly load YANG schema files from other NPM modules.

By default, loading the [yang-js](./main.coffee) module will attempt
to associate `.yang` extension inside `require` facility. If
available, it will allow you to `require('./some-dependency.yang')`
and get back a parsed `Yang expression` instance.

## Main constructor

This method can be called directly without the use of `new` keyword
and will internally parse the provided schema and return a `bound
function` which will invoke [eval](#eval-data-opts) when called.

      constructor: (kind, tag, extension) ->
        unless this instanceof Yang
          [ schema, bindings ] = arguments
          schema = Yang.parse schema unless schema instanceof Yang
          return schema.bind bindings

        extension ?= (@lookup 'extension', kind)
        self = super kind, tag, extension
        unless extension instanceof Expression
          @debug "defer processing of custom extension #{kind}"
          @once 'compile:before', (->
            @debug "processing deferred extension #{kind}"
            extension = (@lookup 'extension', kind)
            unless extension instanceof Yang
              throw @error "encountered unknown extension '#{kind}'"
            { @source, @argument } = extension
          ).bind self
        return self

      @property 'datakey',
        get: -> switch
          when @parent instanceof Yang and @parent.kind is 'module' then "#{@parent.tag}:#{@tag}"
          when @parent instanceof Yang and @parent.kind is 'submodule'
            "#{@parent['belongs-to'].tag}:#{@tag}"
          else @tag ? @kind

      @property 'datapath',
        get: -> switch
          when @parent not instanceof Yang then ''
          when @node then @parent.datapath + "/#{@datakey}"
          else @parent.datapath

      error: (msg, context) -> super "[#{@trail}] #{msg}", context

      emit: (event, args...) ->
        @emitter.emit arguments...
        @root.emit event, this if event is 'change' and this isnt @root

## Instance-level methods

### bind (obj)

Every instance of `Yang` expression can be *bound* with control logic
which will be used during [eval](#eval-data-opts) to produce schema
infused **adaptive data object**. This routine is *inherited* from
[Class Expression](./expression.coffee).

This facility can be used to associate default behaviors for any
element in the configuration tree, as well as handler logic for
various YANG statements such as *rpc*, *feature*, etc.

This call will return the original `Yang` expression instance with the
new bindings registered within the `Yang` expression hierarchy.

      # bind() is inherited from Expression

Please refer to [Schema Binding](../TUTORIAL.md#schema-binding)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

### eval (data, opts={})

Every instance of `Yang` expression can be [eval](#eval-data-opts)
with arbitrary JS data input which will apply the schema against the
provided data and return a schema infused **adaptive** data object.

This is an extremely useful construct which brings out the true power
of YANG for defining and governing arbitrary JS data structures.

Basically, the input `data` will be YANG schema validated and
converted to a schema infused *adaptive data model* that dynamically
defines properties according to the schema expressions.

It currently supports the `opts.adaptive` parameter (default `false`)
which establishes a persistent binding relationship with the governing
`Yang` expression instance. This allows the generated model to
dynamically **adapt** to any changes to the governing `Yang`
expression instance. Refer to below [extends](#extends-schema) section
for additional info on how the schema can be programmatically
modified.

      eval: (data, opts={}) ->
        if opts.adaptive is true
          # TODO: this will break for 'module' which will return Model?
          @once 'change', arguments.callee.bind(this, data, opts)
        super

Please refer to [Working with Models](../TUTORIAL.md#working-with-models)
section of the [Getting Started Guide](../TUTORIAL.md) for special
usage examples for `module` schemas.

### extends (schema...)

Every instance of `Yang` expression can be `extends` with additional
YANG schema string(s) and it will automatically perform
[parse](#parse-schema) of the provided schema text and update itself
accordingly.

This action also triggers an event emitter which will *retroactively*
adapt any previously [eval](#eval-data-opts) produced adaptive data
model instances to react accordingly to the newly changed underlying
schema expression(s).

      # extends() is inherited from Element

      merge: (elem) ->
        unless elem instanceof Yang
          throw @error "cannot merge invalid element into Yang", elem

        switch elem.kind
          when 'type'     then super elem, append: true
          when 'argument' then super elem, replace: true
          else super

Please refer to [Schema Extension](../TUTORIAL.md#schema-extension)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

      normalizePath: (ypath) ->
        lastPrefix = null
        prefix2module = (root, prefix) ->
          return unless root.kind is 'module'
          switch
            when root.tag is prefix then prefix
            when root.prefix.tag is prefix then root.tag
            else
              for m in root.import ? [] when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              modules = root.lookup 'module'
              for m in modules when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              return prefix # return as-is...

        normalizeEntry = (x) =>
          return x unless x? and !!x
          match = x.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
          unless match?
            throw @error "invalid path expression '#{x}' found in #{ypath}"
          [ prefix, target ] = [ match[1], match[2] ]
          return switch
            when not prefix? then target
            when prefix is lastPrefix then target
            else
              lastPrefix = prefix
              mname = prefix2module @root, prefix
              "#{mname}:#{target}"
        ypath = ypath.replace /\s/g, ''
        ypath
          .split('/')
          .map normalizeEntry
          .join('/')

### locate (ypath)

This is an internal helper facility used to locate a given schema node
within the `Yang` schema expression tree hierarchy. It supports a
limited version of XPATH-like expression to locate an explicit
element.

      locate: (ypath) ->
        # TODO: figure out how to eliminate duplicate code-block section
        # shared with Element
        return unless ypath?

        @debug "locate enter for '#{ypath}'"
        if typeof ypath is 'string'
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = @normalizePath(ypath).split('/').filter (e) -> !!e
        else
          [ key, rest... ] = ypath
        return this unless key? and key isnt '.'

        if key is '..'
          return @parent?.locate rest

        match = key.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
        [ prefix, target ] = [ match[1], match[2] ]
        if prefix? and this is @root
          search = [target].concat(rest)
          if (@tag is prefix) or (@lookup 'prefix', prefix)
            @debug "locate (local) '/#{prefix}:#{search.join('/')}'"
            return super search
          for m in @import ? [] when m.tag is prefix or m.prefix.tag is prefix
            @debug "locate (external) '/#{prefix}:#{search.join('/')}'"
            return m.module.locate search
          m = @lookup 'module', prefix
          return m?.locate search

        switch
          when /^{.+}$/.test(target)
            kind = 'grouping'
            tag  = target.replace /^{(.+)}$/, '$1'
          when /^\[.+\]$/.test(target)
            kind = 'feature'
            tag  = target.replace /^\[(.+)\]$/, '$1'
          when /^[^(]+\([^)]*\)$/.test(target)
            target = target.match /^([^(]+)\((.*)\)$/
            [ kind, tag ] = [ target[1], target[2] ]
            tag = undefined unless !!tag
          when /^\<.+\>$/.test(target)
            target = target.replace /^\<(.+)\>$/, '$1'
            [ kind..., tag ]  = target.split ':'
            [ tag, selector ] = tag.split '='
            kind = kind[0] if kind?.length
          else return super [key].concat rest

        match = @match kind, tag
        return switch
          when rest.length is 0 then match
          else match?.locate rest

### match (kind, tag)

This is an internal helper facility used by [locate](#locate-ypath) and
[lookup](./element.litcoffee#lookup-kind-tag) to test whether a given
entity exists in the local schema tree.

      # Yang Expression can support 'tag' with prefix to another module
      # (or itself).
      match: (kind, tag) ->
        return super unless kind? and tag? and typeof tag is 'string'
        res = super
        return res if res?

        [ prefix..., arg ] = tag.split ':'
        return unless prefix.length

        debug? "[match] with #{kind} #{tag}"

        prefix = prefix[0]
        debug? "[match] check if current module's prefix"
        if @root.tag is prefix or @root.prefix?.tag is prefix
          return @root.match kind, arg

        debug? "[match] checking if submodule's parent"
        ctx = @lookup 'belongs-to'
        if ctx?.prefix.tag is prefix
          return ctx.module.match kind, arg

        debug? "[match] check if one of current module's imports"
        imports = @root?.import ? []
        for m in imports when m.prefix.tag is prefix
          debug? m.module
          return m.module.match kind, arg

### toString (opts={})

The current `Yang` expression will covert back to the equivalent YANG
schema text format.

At first glance, this may not seem like a useful facility since YANG
schema text is *generally known* before [parse](#parse-schema) but it
becomes highly relevant when you consider a given `Yang` expression
programatically changing via [extends](#extends-schema).

Currently it supports `space` parameter which can be used to specify
number of spaces to use for indenting YANG statement blocks.  It
defaults to **2** but when set to **0**, the generated output will
omit newlines and other spacing for a more compact YANG output.

      toString: (opts={ space: 2 }) ->
        s = @kind
        if @source.argument?
          s += ' ' + switch @source.argument
            when 'value' then "'#{@tag}'"
            when 'text'
              "\n" + (indent '"'+@tag+'"', ' ', opts.space)
            else @tag
        sub =
          @elements
            .filter (x) => x.parent is this
            .map (x) -> x.toString opts
            .join "\n"
        if !!sub
          s += " {\n" + (indent sub, ' ', opts.space) + "\n}"
        else
          s += ';'
        return s

### toJSON

The current `Yang` expression will convert into a simple JS object
format.

      # toJSON() is inherited from Element

### valueOf

The current 'Yang' expression will convert into a primitive form for
comparision purposes.

      valueOf: ->
        switch @source.argument
          when 'value','text' then @tag.valueOf()
          else this

Please refer to [Schema Conversion](../TUTORIAL.md#schema-conversion)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

## Export Yang Class

    module.exports = Yang

# Yang - evaluable schema expression

This module provides support for basic set of YANG schema modeling
language by using the built-in *extension* syntax to define additional
schema language constructs. The actual YANG language [RFC
6020](http://tools.ietf.org/html/rfc6020) specifications are loaded
inside the [main module](./main.coffee).

This module is the **primary interface** for consumers of this
library.

## Dependencies

    debug  = require('debug')('yang:schema') if process.env.DEBUG?
    fs     = require 'fs'
    path   = require 'path'
    parser = require 'yang-parser'
    indent = require 'indent-string'

    Expression = require './expression'

## Class Yang

    class Yang extends Expression
      @scope:
        extension: '0..n'
        typedef:   '0..n'
        module:    '0..n'
        submodule: '0..n'

## Class-level methods

      @clear: ->
        @module.splice(0,@module.length) if @module?
        @submodule.splice(0,@submodule.length) if @submodule?

### parse (schema)

This class-level routine performs recursive parsing of passed in
statement and sub-statements. It provides syntactic, semantic and
contextual validations on the provided schema and returns the final JS
object tree structure as hierarchical Yang expression instances.

If any validation errors are encountered, it will throw the
appropriate error along with the context information regarding the
error.

      @parse: (schema, opts={}) ->
        opts.compile ?= true
        try
          schema = parser.parse schema if typeof schema is 'string'
        catch e
          e.offset = 50 unless e.offset > 50
          offender = schema.slice e.offset-50, e.offset+50
          offender = offender.replace /\s\s+/g, ' '
          throw @error "invalid YANG syntax detected around: '#{offender}'", offender

        unless schema instanceof Object
          throw @error "must pass in valid YANG schema", schema

        kind = switch
          when !!schema.prf then "#{schema.prf}:#{schema.kw}"
          else schema.kw
        tag = schema.arg if !!schema.arg

        schema = (new this kind, tag).extends schema.substmts.map (x) => @parse x, false
        # perform final scoped constraint validation
        for kind, constraint of schema.scope when constraint in [ '1', '1..n' ]
          unless schema.hasOwnProperty kind
            throw schema.error "constraint violation for required '#{kind}' = #{constraint}"
        schema.compile() if opts.compile
        return schema

For comprehensive overview on currently supported YANG statements,
please refer to
[Compliance Report](../test/yang-compliance-coverage.md) for the latest
[RFC 6020](http://tools.ietf.org/html/rfc6020) YANG specification
compliance.

### compose (data [, opts={}])

This call *accepts* any arbitrary JS object and it will attempt to
convert it into a structural `Yang` expression instance. It will
analyze the passed in JS data and perform best match mapping to an
appropriate YANG schema representation to describe the input
data. This method will not be able to determine conditionals or any
meta-data to further constrain the data, but it should provide a good
starting point with the resulting `Yang` expression instance.

      @compose: (data, opts={}) ->
        unless data?
          throw @error "must supply input 'data' to compose"

        # explict compose
        if opts.kind?
          ext = Yang::lookup.call this, 'extension', opts.kind
          unless ext instanceof Expression
            throw @error "unable to find requested '#{opts.kind}' extension"
          return ext.compose? data, opts

        # implicit compose (dynamic discovery)
        for ext in @extension when ext.compose instanceof Function
          debug? "checking data if #{ext.tag}"
          res = ext.compose data, opts
          return res if res instanceof Yang

This facility is a powerful construct to dynamically generate `Yang`
schema from ordinary JS objects. For additional usage examples, please
refer to [Dynamic Composition](../TUTORIAL.md#dynamic-composition)
section in the [Getting Started Guide](../TUTORIAL.md).

### resolve (from..., name)

This call is internally used by [import](#import-name-opts) to
perform a search within the local filesystem to locate a given YANG
schema module by `name`. It will first check the calling code's local
[package.json](../package.json) to look for a `models: {}`
configuration section to identify where the target module can be
found. If there is an entry defined, it will then follow that
reference - which may be a JS file, YANG schema text file, or another
NPM module. If it is not found within the `models: {}` configuration
block or it fails to load the referenced dependency, it will then
fallback to attempt to locate a YANG schema text file in the same
folder that the `resolve` request was made: `#{name}.yang`.

      @resolve: (from..., name) ->
        return null unless typeof name is 'string'
        dir = from = switch
          when from.length then from[0]
          else path.resolve()
        while not found? and dir not in [ '/', '.' ]
          target = "#{dir}/package.json"
          debug? "[resolve] #{name} in #{target}"
          try
            pkginfo = require(target)
            found = pkginfo.models[name]
          if found?
            dir = path.dirname require.resolve(target)
            debug? "[resolve] #{name} check #{found} in #{dir}"
            unless !!path.extname found
              from = switch
                when found of pkginfo.dependencies
                  path.resolve dir, 'node_modules', found
                else path.resolve dir, found
              if fs.existsSync from
                return @resolve from, name
              else
                found = @resolve found, name
          if not found? and pkginfo?.name is name
            found = path.dirname require.resolve(target)
          dir = path.dirname dir unless found?
        file = switch
          when not found? then path.resolve from, "#{name}.yang"
          else path.resolve dir, found
        debug? "[resolve] checking if #{file} exists"
        return if fs.existsSync file then file else null

### import (name [, opts={}])

This call provides a convenience mechanism for dealing with YANG
schema module dependencies. It performs parsing of the YANG schema
content from the specified `name` and saves the generated `Yang`
expression inside the internal registry. The `name` can be a YANG
module name or a *filename* to the actual schema content (JS or YANG).

Once a given YANG module has been saved inside the registry,
subsequent [parse](#parse-schema) of YANG schema that *import* the
saved module will successfully resolve.

Typical usage scenario for this pattern is to internally define common
modules such as `ietf-yang-types` which can then be *imported* by
other schemas.

It will also return the new `Yang` expression instance (to do with as
you please).

      @require: ->
        console.warn "DEPRECATION: please use .import() instead"
        @import arguments...

      @import: (name, opts={}) ->
        return unless name?
        opts.basedir ?= ''
        extname  = path.extname name
        filename = path.resolve opts.basedir, name
        basedir  = path.dirname filename

        unless !!extname
          return (Yang::match.call this, 'module', name) ? @import (@resolve name), opts

        unless extname is '.yang'
          res = require filename
          unless res instanceof Yang
            throw @error "unable to import '#{name}' from '#{filename}' (not Yang expression)", res
          return res

        try return @use (@parse (fs.readFileSync filename, 'utf-8'), opts)
        catch e
          unless opts.compile and e.name is 'ExpressionError' and e.context.kind in [ 'include', 'import' ]
            console.error "unable to import '#{name}' YANG module from '#{filename}'"
            throw e
          opts.compile = false if e.context.kind is 'include'

          # try to find the dependency module for import
          dependency = @import (@resolve basedir, e.context.tag), opts
          unless dependency?
            e.message = "unable to auto-resolve '#{e.context.tag}' dependency module"
            throw e

          # retry the original request
          debug? "retrying import(#{name})"
          return @import arguments...

Please note that this method will look for the `name` in current
working directory of the script execution if the `name` is a relative
path. It utilizes the [resolve](#resolve-from-name) method and will
attempt to **recursively** resolve any failed `import` dependencies.

While this is a convenient abstraction, it is **recommended** to
directly use the Node.js built-in `require` mechanism (if
available). Using native `require` instead of `Yang.import` will
allow package bundlers such as `browserify` to capture the
dependencies as part of the produced bundle.  It also allows you to
directly load YANG schema files from other NPM modules.

By default, loading the [yang-js](./main.coffee) module will attempt
to associate `.yang` extension inside `require` facility. If
available, it will allow you to `require('./some-dependency.yang')`
and get back a parsed `Yang expression` instance.

## Main constructor

This method can be called directly without the use of `new` keyword
and will internally parse the provided schema and return a `bound
function` which will invoke [eval](#eval-data-opts) when called.

      constructor: (kind, tag, extension) ->
        unless this instanceof Yang
          [ schema, bindings ] = arguments
          schema = Yang.parse schema unless schema instanceof Yang
          return schema.bind bindings

        extension ?= (@lookup 'extension', kind)
        self = super kind, tag, extension
        unless extension instanceof Expression
          @debug "defer processing of custom extension #{kind}"
          @once 'compile:before', (->
            @debug "processing deferred extension #{kind}"
            extension = (@lookup 'extension', kind)
            unless extension instanceof Yang
              throw @error "encountered unknown extension '#{kind}'"
            { @source, @argument } = extension
          ).bind self
        return self

      @property 'datakey',
        get: -> switch
          when @parent instanceof Yang and @parent.kind is 'module' then "#{@parent.tag}:#{@tag}"
          when @parent instanceof Yang and @parent.kind is 'submodule'
            "#{@parent['belongs-to'].tag}:#{@tag}"
          else @tag ? @kind

      @property 'datapath',
        get: -> switch
          when @parent not instanceof Yang then ''
          when @node then @parent.datapath + "/#{@datakey}"
          else @parent.datapath

      error: (msg, context) -> super "[#{@trail}] #{msg}", context

      emit: (event, args...) ->
        @emitter.emit arguments...
        @root.emit event, this if event is 'change' and this isnt @root

## Instance-level methods

### bind (obj)

Every instance of `Yang` expression can be *bound* with control logic
which will be used during [eval](#eval-data-opts) to produce schema
infused **adaptive data object**. This routine is *inherited* from
[Class Expression](./expression.coffee).

This facility can be used to associate default behaviors for any
element in the configuration tree, as well as handler logic for
various YANG statements such as *rpc*, *feature*, etc.

This call will return the original `Yang` expression instance with the
new bindings registered within the `Yang` expression hierarchy.

      # bind() is inherited from Expression

Please refer to [Schema Binding](../TUTORIAL.md#schema-binding)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

### eval (data, opts={})

Every instance of `Yang` expression can be [eval](#eval-data-opts)
with arbitrary JS data input which will apply the schema against the
provided data and return a schema infused **adaptive** data object.

This is an extremely useful construct which brings out the true power
of YANG for defining and governing arbitrary JS data structures.

Basically, the input `data` will be YANG schema validated and
converted to a schema infused *adaptive data model* that dynamically
defines properties according to the schema expressions.

It currently supports the `opts.adaptive` parameter (default `false`)
which establishes a persistent binding relationship with the governing
`Yang` expression instance. This allows the generated model to
dynamically **adapt** to any changes to the governing `Yang`
expression instance. Refer to below [extends](#extends-schema) section
for additional info on how the schema can be programmatically
modified.

      eval: (data, opts={}) ->
        if opts.adaptive is true
          # TODO: this will break for 'module' which will return Model?
          @once 'change', arguments.callee.bind(this, data, opts)
        super

Please refer to [Working with Models](../TUTORIAL.md#working-with-models)
section of the [Getting Started Guide](../TUTORIAL.md) for special
usage examples for `module` schemas.

### extends (schema...)

Every instance of `Yang` expression can be `extends` with additional
YANG schema string(s) and it will automatically perform
[parse](#parse-schema) of the provided schema text and update itself
accordingly.

This action also triggers an event emitter which will *retroactively*
adapt any previously [eval](#eval-data-opts) produced adaptive data
model instances to react accordingly to the newly changed underlying
schema expression(s).

      # extends() is inherited from Element

      merge: (elem) ->
        unless elem instanceof Yang
          throw @error "cannot merge invalid element into Yang", elem

        switch elem.kind
          when 'type'     then super elem, append: true
          when 'argument' then super elem, replace: true
          else super

Please refer to [Schema Extension](../TUTORIAL.md#schema-extension)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

      normalizePath: (ypath) ->
        lastPrefix = null
        prefix2module = (root, prefix) ->
          return unless root.kind is 'module'
          switch
            when root.tag is prefix then prefix
            when root.prefix.tag is prefix then root.tag
            else
              for m in root.import ? [] when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              modules = root.lookup 'module'
              for m in modules when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              return prefix # return as-is...

        normalizeEntry = (x) =>
          return x unless x? and !!x
          match = x.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
          unless match?
            throw @error "invalid path expression '#{x}' found in #{ypath}"
          [ prefix, target ] = [ match[1], match[2] ]
          return switch
            when not prefix? then target
            when prefix is lastPrefix then target
            else
              lastPrefix = prefix
              mname = prefix2module @root, prefix
              "#{mname}:#{target}"
        ypath = ypath.replace /\s/g, ''
        ypath
          .split('/')
          .map normalizeEntry
          .join('/')

### locate (ypath)

This is an internal helper facility used to locate a given schema node
within the `Yang` schema expression tree hierarchy. It supports a
limited version of XPATH-like expression to locate an explicit
element.

      locate: (ypath) ->
        # TODO: figure out how to eliminate duplicate code-block section
        # shared with Element
        return unless ypath?

        @debug "locate enter for '#{ypath}'"
        if typeof ypath is 'string'
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = @normalizePath(ypath).split('/').filter (e) -> !!e
        else
          [ key, rest... ] = ypath
        return this unless key? and key isnt '.'

        if key is '..'
          return @parent?.locate rest

        match = key.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
        [ prefix, target ] = [ match[1], match[2] ]
        if prefix? and this is @root
          search = [target].concat(rest)
          if (@tag is prefix) or (@lookup 'prefix', prefix)
            @debug "locate (local) '/#{prefix}:#{search.join('/')}'"
            return super search
          for m in @import ? [] when m.tag is prefix or m.prefix.tag is prefix
            @debug "locate (external) '/#{prefix}:#{search.join('/')}'"
            return m.module.locate search
          m = @lookup 'module', prefix
          return m?.locate search

        switch
          when /^{.+}$/.test(target)
            kind = 'grouping'
            tag  = target.replace /^{(.+)}$/, '$1'
          when /^\[.+\]$/.test(target)
            kind = 'feature'
            tag  = target.replace /^\[(.+)\]$/, '$1'
          when /^[^(]+\([^)]*\)$/.test(target)
            target = target.match /^([^(]+)\((.*)\)$/
            [ kind, tag ] = [ target[1], target[2] ]
            tag = undefined unless !!tag
          when /^\<.+\>$/.test(target)
            target = target.replace /^\<(.+)\>$/, '$1'
            [ kind..., tag ]  = target.split ':'
            [ tag, selector ] = tag.split '='
            kind = kind[0] if kind?.length
          else return super [key].concat rest

        match = @match kind, tag
        return switch
          when rest.length is 0 then match
          else match?.locate rest

### match (kind, tag)

This is an internal helper facility used by [locate](#locate-ypath) and
[lookup](./element.litcoffee#lookup-kind-tag) to test whether a given
entity exists in the local schema tree.

      # Yang Expression can support 'tag' with prefix to another module
      # (or itself).
      match: (kind, tag) ->
        return super unless kind? and tag? and typeof tag is 'string'
        res = super
        return res if res?

        [ prefix..., arg ] = tag.split ':'
        return unless prefix.length

        debug? "[match] with #{kind} #{tag}"

        prefix = prefix[0]
        debug? "[match] check if current module's prefix"
        if @root.tag is prefix or @root.prefix?.tag is prefix
          return @root.match kind, arg

        debug? "[match] checking if submodule's parent"
        ctx = @lookup 'belongs-to'
        if ctx?.prefix.tag is prefix
          return ctx.module.match kind, arg

        debug? "[match] check if one of current module's imports"
        imports = @root?.import ? []
        for m in imports when m.prefix.tag is prefix
          debug? m.module
          return m.module.match kind, arg

### toString (opts={})

The current `Yang` expression will covert back to the equivalent YANG
schema text format.

At first glance, this may not seem like a useful facility since YANG
schema text is *generally known* before [parse](#parse-schema) but it
becomes highly relevant when you consider a given `Yang` expression
programatically changing via [extends](#extends-schema).

Currently it supports `space` parameter which can be used to specify
number of spaces to use for indenting YANG statement blocks.  It
defaults to **2** but when set to **0**, the generated output will
omit newlines and other spacing for a more compact YANG output.

      toString: (opts={ space: 2 }) ->
        s = @kind
        if @source.argument?
          s += ' ' + switch @source.argument
            when 'value' then "'#{@tag}'"
            when 'text'
              "\n" + (indent '"'+@tag+'"', ' ', opts.space)
            else @tag
        sub =
          @elements
            .filter (x) => x.parent is this
            .map (x) -> x.toString opts
            .join "\n"
        if !!sub
          s += " {\n" + (indent sub, ' ', opts.space) + "\n}"
        else
          s += ';'
        return s

### toJSON

The current `Yang` expression will convert into a simple JS object
format.

      # toJSON() is inherited from Element

### valueOf

The current 'Yang' expression will convert into a primitive form for
comparision purposes.

      valueOf: ->
        switch @source.argument
          when 'value','text' then @tag.valueOf()
          else this

Please refer to [Schema Conversion](../TUTORIAL.md#schema-conversion)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

## Export Yang Class

    module.exports = Yang


Remove the identity transmission from data

This is going in a separate module shortly.

Primary Data Sources
====================

This API presents the primary data sources to the system, from which
all other data are derived.

These primary data sources come in two categories: *local* and *global*.

Items in the *local* category apply *only* to the current screen. Presently,
they are:

* Mode,
* Override HTML.

The former refers to a centrally-controlled option defining what the screen will
be showing, and the latter is a facility for *directly* sending raw HTML to be
displayed.

Items in the *global* category refer to state shared by all screens from compd,
in particular:

* Teams,
* Day schedule,
* Match schedule,
* The *kill* state.

Internal Buses
--------------

We create a bus for each of the primary data source, into which we internally
inject events. The public APIs are the *toProperty* equivalents of these.

    mode = new Bacon.Bus
    overrideText = new Bacon.Bus

    teams = new Bacon.Bus
    daySchedule = new Bacon.Bus
    matchSchedule = new Bacon.Bus
    killState = new Bacon.Bus

Message Dispatch
----------------

We subscribe to the message stream from *WS*, handling any data updates which
are relevant to us.

    WS.message.onValue (msg) ->
        switch msg.type

The first case we handle is that of the *mode* message, containing a new mode
for us to enter.

            when "mode" then mode.push msg.mode

The *teams* message contains an updated teams information object, which we
simply republish verbatim.

            when "teams" then teams.push msg.teams

Similarly for the day and match schedules.

            when "day" then daySchedule.push msg.schedule
            when "matches" then matchSchedule.push msg.schedule

For the override text, we are able to do something similar. Note, however, that
the override text, while normally a string, is nullable, with the null value
indicating that this screen should not be overridden.

            when "override" then overrideText.push msg.override

Finally, we handle the *kill* state. The *kill* state is controlled via two
messages rather than one: the *kill* message, indicating that the kill mode has
been triggered and containing the screen ID of the source as its argument, and
the *kill-end* message, indicating that the kill mode has been administratively
cleared.

            when "kill" then killState.push msg.source
            when "kill-end" then killState.push null

Public API
----------

We publish properties for each of the primary data sources, each of which has a
sensible default value.

    window.Data =

The *mode* property contains the initial startup mode, *default*, which shows
the Student Robotics logo as well as a clock.

        mode: mode.toProperty 'default'

The *teams* property contains an empty team mapping.

        teams: teams.toProperty {}

The *daySchedule* and *matchSchedule* properties similarly contain empty
schedules as their initial values.

        daySchedule: daySchedule.toProperty []
        matchSchedule: matchSchedule.toProperty []

The *overrideText* and *killState* properties are nullable, and are both given
null as their initial values.

        overrideText: overrideText.toProperty null
        killState: killState.toProperty null

Primary Data Sources
====================

This API presents the primary data sources to the system, from which
all other data are derived.

These primary data sources come in two categories: *local* and *global*.

Items in the *local* category apply *only* to the current screen. Presently,
they are:

* Mode,
* Override HTML.

The former refers to a centrally-controlled option defining what the screen will
be showing, and the latter is a facility for *directly* sending raw HTML to be
displayed.

Items in the *global* category refer to state shared by all screens from compd,
in particular:

* Teams,
* Day schedule,
* Match schedule,
* The *kill* state.

Screen ID Transmission
----------------------

First, we transmit the screen ID to the server, using the *iam* message. In
future, this will be derived from user input in some fashion; for the time
being, it is a constant string, for testing purposes.

    WS.send 'iam', screen: 'example'

Internal Buses
--------------

We create a bus for each of the primary data source, into which we internally
inject events. The public APIs are the *toProperty* equivalents of these.

    mode = new Bacon.Bus
    overrideText = new Bacon.Bus

    teams = new Bacon.Bus
    daySchedule = new Bacon.Bus
    matchSchedule = new Bacon.Bus
    killState = new Bacon.Bus

Message Dispatch
----------------

We subscribe to the message stream from *WS*, handling any data updates which
are relevant to us.

    WS.message.onValue (msg) ->
        switch msg.type

The first case we handle is that of the *mode* message, containing a new mode
for us to enter.

            when "mode" then mode.push msg.mode

The *teams* message contains an updated teams information object, which we
simply republish verbatim.

            when "teams" then teams.push msg.teams

Similarly for the day and match schedules.

            when "day" then daySchedule.push msg.schedule
            when "matches" then matchSchedule.push msg.schedule

For the override text, we are able to do something similar. Note, however, that
the override text, while normally a string, is nullable, with the null value
indicating that this screen should not be overridden.

            when "override" then overrideText.push msg.override

Finally, we handle the *kill* state. The *kill* state is controlled via two
messages rather than one: the *kill* message, indicating that the kill mode has
been triggered and containing the screen ID of the source as its argument, and
the *kill-end* message, indicating that the kill mode has been administratively
cleared.

            when "kill" then killState.push msg.source
            when "kill-end" then killState.push null

Public API
----------

We publish properties for each of the primary data sources, each of which has a
sensible default value.

    window.Data =

The *mode* property contains the initial startup mode, *default*, which shows
the Student Robotics logo as well as a clock.

        mode: mode.toProperty 'default'

The *teams* property contains an empty team mapping.

        teams: teams.toProperty {}

The *daySchedule* and *matchSchedule* properties similarly contain empty
schedules as their initial values.

        daySchedule: daySchedule.toProperty []
        matchSchedule: matchSchedule.toProperty []

The *overrideText* and *killState* properties are nullable, and are both given
null as their initial values.

        overrideText: overrideText.toProperty null
        killState: killState.toProperty null


Update functions.litcoffee

Update functions.litcoffee

### This file

The logic in this file builds the date object.

If you compare this file to the ```python/functions.py``` file
you'll notice they are very similiar. That's intentional,
this file was ported over and kept such that it would be somewhat
easy to port changes back and forth.

### Terminology

Because it's so confusing here is a list of the different levels to refer to:

- Groups
  -- This is the capture groups. The lowest level. ```([0-9])``` etc.
  "Day", "Month", etc.
- Expressions
  -- This is an expression with multiple capture groups. They're usually named
  after the person that wrote them. "Greg Burns", etc.

  In Python, Expressions functions have nice named arguments, def expr(Day, Month, Year),
  but Javascript doesn't support this.
- Type
  -- This is a collection of expressions with a common goal.
  Months (Jan, 0-12, January, etc.).
- Patterns
  -- This is a collection of types ```<Month>/<Day>/<Year>```

### Warning

A note about the above list. Types and Groups are commonly mixed up.
I think groups SHOULD be the lowest
(because they are the actual capture *groups* in regular expressions)
but a group of expressions also makes sense.

It's so confusing that there are at least a couple places here that I've
also mixed myself up and probably in the documentation for RE|PARSE as well.

---

I use named tuples in python, and ```_replace``` mirrors the functionality of
```date._replace```.. that is that it returns a copy of the date with only
certain things changed and leaves the old well enough alone.

        _replace = (_old, _new) ->
            year:   if _new.year? then _new.year else _old.year
            month:  if _new.month? then _new.month else _old.month
            day:    if _new.day? then _new.day  else _old.day
            hour:   if _new.hour? then _new.hour else _old.hour
            minute: if _new.minute? then _new.minute else _old.minute
            second: if _new.second? then _new.second else _old.second
            am_pm:  if _new.am_pm? then _new.am_pm else _old.am_pm

I represent lengths of dates (i.e. Thursday, 1-2pm) with a timedelta that goes right
after the date hash in the result array.

In Javascript, I'm just going to represent a timedelta with a hash.
I make a pretty dumb assumption that timedelta will only cross hour/minutes/second boundaries.

        timedelta_from_Date = (start_time, end_time) ->
            seconds_difference = 0
            if start_time.hour? and end_time.hour?
              seconds_difference += 60*60*(end_time.hour - start_time.hour)

              if start_time.minute? and end_time.minute?
                seconds_difference += 60*(end_time.minute - start_time.minute)

                if start_time.second? and end_time.second?
                  seconds_difference += end_time.second - start_time.second

            hours = Math.floor(seconds_difference/60/60)
            minutes = Math.floor(seconds_difference/60) - (hours * 60)
            seconds = seconds_difference - (minutes * 60) - (hours * 60 * 60)

            return {
               timedelta: true
               hours: hours
               minutes: minutes
               seconds: seconds
            }

This is just a helper function

        in_array = (arr, _) -> arr.indexOf(_) != -1

```progressive_match``` is useful for matching abbreviations
and full spellings. Functions like this could be useful
to help parse fuzzy matches in the future (i.e. misspellings of months).

        progressive_match = (string, possibilities) ->
            part = ""
            if not string? then return
            for character in string.toLowerCase()
                part += character
                matches = []
                for month, value of possibilities
                    if month.indexOf(part) > -1
                        matches.push(month)
                if matches.length == 1
                    return possibilities[matches[0]]
### Types

        month_to_number = (month_string) ->
          months =
              "january": 1
              "february": 2
              "march": 3
              "april": 4
              "may": 5
              "june": 6
              "july": 7
              "august": 8
              "september": 9
              "october": 10
              "november": 11
              "december": 12
           return progressive_match(month_string, months)

        weekday_to_number = (WeekdayString ) ->
            weekday_list = {
                "monday": 0,
                "tuesday": 1,
                "wednesday": 2,
                "thursday": 3,
                "friday": 4,
                "saturday": 5,
                "sunday": 6,
            }
            return progressive_match(WeekdayString, weekday_list)

I serialize am_pm by converting the hours to milliary/24-hour time format.
I also include ```am_pm: 'pm'``` in the date format to show that that transformation
was done. Making that clear helpful because if you get a time like 1, with no ```am_pm```
designation you might want to assume pm and add 12. This is not done in the libary because
date_machine strives for honesty, not guesswork.

        am_pm = (input) ->
            if not input?
              return
            if input.toLowerCase() == "am" then 0
            else if input.toLowerCase() == "pm" then 12

I try not to repeat logic and use other functions when possible.
I could put ```"Steve Valaitis2": time_expression``` to avoid this,
but I wrote it out to show that nothing special happens with 24-hour/military time.

        military_time = (MilHour, MilMinute, MilSecond ) ->
            return time_expression(MilHour, MilMinute, MilSecond, undefined)

Here is the am/pm conversion. I omit returns when the expressions are simple,
but later on I want to use them as much as possible to make my intentions clear.

        noon = (hour, AMPM) -> hour == 12 and AMPM == 12
        midnight = (hour, AMPM) -> hour == 12 and AMPM == 0

This function gets called pretty often, I'd consider it the bulk
of the output logic.

        time_expression = (Hour, Minute, Second, AMPM, SpecialTimeText ) ->
            if not Hour? and not Minute? and not Second? and not AMPM? and not SpecialTimeText?
                return
            if SpecialTimeText
                if SpecialTimeText.toLowerCase() == "noon"
                    return {hour: 12}
                if SpecialTimeText.toLowerCase() == "midnight"
                    return {hour: 0}
            d = {}
            if Hour
                d.hour = Number(Hour)
            if Minute
                d.minute = Number(Minute)
            if Second
                d.second = Number(Second)
            if AMPM?
                if d.hour
                    if noon(d.hour, AMPM)
                        d.hour = 12
                    else if midnight(d.hour, AMPM)
                        d.hour = 0
                    else
                        d.hour = d.hour + AMPM
                d.am_pm = AMPM
            if [d.hour, d.minute, d.second] == [undefined, undefined, undefined]
                return undefined
            return d

        time_and_time = (Hour, Minute, AMPM1, Hour2, Minute2, AMPM2) ->
            if AMPM2?
                AMPM2 = am_pm(AMPM2)
            if not AMPM1? and not AMPM2?
                return [time_expression(Hour, Minute), time_expression(Hour2, Minute2)]
            else if not AMPM1?
                return [time_expression(Hour, Minute, undefined, AMPM2),
                        time_expression(Hour2, Minute2, undefined, AMPM2)]
            else if not AMPM2?
                return [time_expression(Hour, Minute, undefined, AMPM1),
                        time_expression(Hour2, Minute2, undefined, AMPM1)]

        month_type = (input...) ->
            for value in input
                if value?
                    return Number(value)

        date_number = (Day, Abbr) -> if Day? then Number(Day)

        month_number = (MonthNum) -> Number(MonthNum)

        month_num_type = (input) -> Number(input)

        year = (Year) -> if Year? then Number(Year)

Sometimes the value is ```[undefined, undefined, <value>]```,
so I need to search for it and find it. There's enough
of these smaller expressions scattered around that moving them
all to one place might be good.

        get_first_defined = (_) ->
          for item in _
            if item?
              return item

### Patterns

There's a some unwrapping values out of arrays here.
Because there's no named-arguments, functions receive a lot more
arrays here then in Python and so they need to be unwrapped.

        weekday_range_with_time = (time1, time2, [weekday1], [weekday2], MonthRange) ->
            output = []

            # Get first undefined value
            # Since only one value in list will be defined (if any)
            time1 = get_first_defined(time1)
            time2 = get_first_defined(time2)

            if time1?
                for date in MonthRange
                    output.push(_replace(date, time1))
                    if time2?
                        output.push(_replace(date, time2))
            return output

        weekday_range_with_extra = ( time, and_time, weekday_start, weekday_end, extra_time, extra_weekday, MonthRange) ->
            output = []
            if time?
                for date in MonthRange
                    if date.weekday?
                        if date.weekday in [weekday_start .. weekday_end]
                            output.push(_replace(date, time))
                            if and_time?
                                output.push(_replace(date, and_time))
                        if date.weekday == extra_weekday
                            output.push(_replace(date, extra_time))
            return output

        weekday_range_with_extra_backwards = (extra_time, extra_weekday, time, weekday_start, weekday_end, MonthRange ) ->
            return weekday_range_with_extra(time[0], time[1], weekday_start, weekday_end, extra_time, extra_weekday, MonthRange )

        reverse_basic_text = (time, day, month, year) ->
            return basic_text(time, undefined, undefined, month, day, year)

        basic_text = (time, first_second, weekday, month, day, year) ->
            if not day?
                day = 1
            if (day instanceof Array) and day.length == 1
              day = day[0]
            if (year instanceof Array) and year.length == 1
              year = year[0]
            if not time?
                return {year: year, month: month, day: day}
            else
                year: year
                month: month
                day: day
                hour: time.hour
                minute: time.minute
                second: time.second
                am_pm: time.am_pm

        slash = (month, day, year, time) ->
            return basic_text(time, undefined, undefined, month, day, year)

        month_range = (month, date_a, date_b) ->
            output = []
            for day in [date_a .. date_b]
                output.push(basic_text(undefined, undefined, undefined, month, day, undefined))
            return output

        multi_time = (time1, BasicText) ->
            output = []
            if time1? and BasicText?
                output.push(_replace(BasicText, time1))
                output.push(BasicText)
                return output

        large_repeat_words = ->
            return undefined

        weekday_range_with_time_range = (time1, weekday_range) ->
            output = []
            if time1? and weekday_range?
                range = timedelta_from_Date(_replace(weekday_range[0], time1), weekday_range[0])
                for weekday in weekday_range
                    output.push(_replace(weekday, {hour:time1.hour, minute:time1.minute, am_pm:time1.am_pm}))
                    output.push(range)
                return output

        time_range = (unstrict_time, strict_time, date, reverse) ->
            endtime = date
            starttime = endtime
            if unstrict_time
                starttime = _replace(starttime, {hour:Number(unstrict_time[0])})
                if date.am_pm
                    starttime = _replace(starttime, {hour: starttime.hour + date.am_pm, am_pm:date.am_pm})
            else
                starttime = _replace(starttime, {hour: strict_time.hour, minute: strict_time.minute})

            time_range = timedelta_from_Date(starttime, endtime)
            if reverse
                time_range = timedelta_from_Date(endtime, starttime)
            return [starttime, time_range]

        alt_time_range = (first_second, weekday, month, day, year, time, unstrict_time, strict_time) ->
            return time_range(unstrict_time, strict_time, basic_text(time, first_second, weekday, month, day, year), reverse)

        until_range = (date1, date2) ->
            if date1 and date2
                return [date1, timedelta_from_Date(date1, date2)]

        through_range = (time, weekday1, weekday2, month, date, beginning) ->
            output = []
            if month and date and beginning and weekday1
                ending =
                    month: month
                    day: date
                for day in [beginning.day .. ending.day]
                    temp =
                        month: month
                        day: date
                    if temp.weekday and in_array([weekday1 .. weekday2], temp.weekday)
                        if time
                            output.push(_replace(temp, time))
                        else
                            output.push(temp)
                return output

### The function list

This hash/object matches all the functions with a
string that represents it in the parse tree.

        functions =
            # Groups
            "MonthString": month_to_number,
            "AMPM": am_pm,
            # Expressions
            "Chase Year": year,
            "Chase Date": date_number,
            "Chase Month": month_number,
            "Steve Valaitis": time_expression,
            "Greg Burns": (hour, am_pm) -> time_expression(hour, null, null, am_pm, null),
            "Greg Burns UnstrictTime:": time_expression,
            "Steve Valaitis2": military_time,
            "Steve Valaitis And Time": time_and_time,
            "Text Parts": time_expression,
            "Michael Ash10": weekday_to_number,
            # Types
            "Month": month_type,
            "MonthNum": month_num_type,
            # Patterns
            "LargeRepeatWords": large_repeat_words,
            "BasicText": basic_text,
            "ReverseBasicText": reverse_basic_text,
            "Slash": slash,
            "MonthRange": month_range,
            "MultiTime": multi_time,
            "WeekdayRangeWithTime": weekday_range_with_time,
            "WeekdayRangeWithExtra": weekday_range_with_extra,
            "WeekdayRangeWithExtraBackwards": weekday_range_with_extra_backwards,
            "WeekdayRangeWithTimeRange": weekday_range_with_time_range,
            "UntilRange": until_range,
            "ThroughRange": through_range,
            "TimeRange": time_range,
            "AltTimeRange": alt_time_range,

This is default expression or pattern. ```any``` means
if value is defined, and there is array with even a single defined value then return true.

            "_default": (_) ->
                if any(_) then _ else undefined

```Type``` there is used to mean collection of expressions.
I know that because only one will match, so you just have to find
it and return it.

            "_default_type": (_...) ->
                if _?
                    for item in _
                         if item?
                             return item

            "_default_group": (_...) -> if _[0]? then _[0]

### This file

The logic in this file builds the date object.

If you compare this file to the ```python/functions.py``` file
you'll notice they are very similiar. That's intentional,
this file was ported over and kept such that it would be somewhat
easy to port changes back and forth.

### Terminology

Because it's so confusing here is a list of the different levels to refer to:

- Groups
  -- This is the capture groups. The lowest level. ```([0-9])``` etc.
  "Day", "Month", etc.
- Expressions
  -- This is an expression with multiple capture groups. They're usually named
  after the person that wrote them. "Greg Burns", etc.

  In Python, Expressions functions have nice named arguments, def expr(Day, Month, Year),
  but Javascript doesn't support this.
- Type
  -- This is a collection of expressions with a common goal.
  Months (Jan, 0-12, January, etc.).
- Patterns
  -- This is a collection of types ```<Month>/<Day>/<Year>```

### Warning

A note about the above list. Types and Groups are commonly mixed up.
I think groups SHOULD be the lowest
(because they are the actual capture *groups* in regular expressions)
but a group of expressions also makes sense.

It's so confusing that there are at least a couple places here that I've
also mixed myself up and probably in the documentation for RE|PARSE as well.

---

I use named tuples in python, and ```_replace``` mirrors the functionality of
```date._replace```.. that is that it returns a copy of the date with only
certain things changed and leaves the old well enough alone.

        _replace = (_old, _new) ->
            year:   if _new.year? then _new.year else _old.year
            month:  if _new.month? then _new.month else _old.month
            day:    if _new.day? then _new.day  else _old.day
            hour:   if _new.hour? then _new.hour else _old.hour
            minute: if _new.minute? then _new.minute else _old.minute
            second: if _new.second? then _new.second else _old.second
            am_pm:  if _new.am_pm? then _new.am_pm else _old.am_pm

I represent lengths of dates (i.e. Thursday, 1-2pm) with a timedelta that goes right
after the date hash in the result array.

In Javascript, I'm just going to represent a timedelta with a hash.
I make a pretty dumb assumption that timedelta will only cross hour/minutes/second boundaries.

        timedelta_from_Date = (start_time, end_time) ->
            seconds_difference = 0
            if start_time.hour? and end_time.hour?
              seconds_difference += 60*60*(end_time.hour - start_time.hour)

              if start_time.minute? and end_time.minute?
                seconds_difference += 60*(end_time.minute - start_time.minute)

                if start_time.second? and end_time.second?
                  seconds_difference += end_time.second - start_time.second

            hours = Math.floor(seconds_difference/60/60)
            minutes = Math.floor(seconds_difference/60) - (hours * 60)
            seconds = seconds_difference - (minutes * 60) - (hours * 60 * 60)

            return {
               timedelta: true
               hours: hours
               minutes: minutes
               seconds: seconds
            }

This is just a helper function

        in_array = (arr, _) -> arr.indexOf(_) != -1

```progressive_match``` is useful for matching abbreviations
and full spellings. Functions like this could be useful
to help parse fuzzy matches in the future (i.e. misspellings of months).

        progressive_match = (string, possibilities) ->
            part = ""
            if not string? then return
            for character in string.toLowerCase()
                part += character
                matches = []
                for month, value of possibilities
                    if month.indexOf(part) > -1
                        matches.push(month)
                if matches.length == 1
                    return possibilities[matches[0]]
### Types

        month_to_number = (month_string) ->
          months =
              "january": 1
              "february": 2
              "march": 3
              "april": 4
              "may": 5
              "june": 6
              "july": 7
              "august": 8
              "september": 9
              "october": 10
              "november": 11
              "december": 12
           return progressive_match(month_string, months)

        weekday_to_number = (WeekdayString ) ->
            weekday_list = {
                "monday": 0,
                "tuesday": 1,
                "wednesday": 2,
                "thursday": 3,
                "friday": 4,
                "saturday": 5,
                "sunday": 6,
            }
            return progressive_match(WeekdayString, weekday_list)

I serialize am_pm by converting the hours to milliary/24-hour time format.
I also include ```am_pm: 'pm'``` in the date format to show that that transformation
was done. Making that clear helpful because if you get a time like 1, with no ```am_pm```
designation you might want to assume pm and add 12. This is not done in the libary because
date_machine strives for honesty, not guesswork.

        am_pm = (input) ->
            if not input?
              return
            if input.toLowerCase() == "am" then 0
            else if input.toLowerCase() == "pm" then 12

You can see in this function that I try not to repeat logic and use other
functions. In this case I might have been able to simply put time_expression
in the functions hash/object, but in python it makes a difference due to named arguments.
I'm going to leave it as-is for clarity.

        military_time = (MilHour, MilMinute, MilSecond ) ->
            return time_expression(MilHour, MilMinute, MilSecond, undefined)

Here is the ampm conversion. I omit returns when the expressions are simple,
but later on I want to use them as much as possible to make my intentions clear.

        noon = (hour, AMPM) -> hour == 12 and AMPM == 12
        midnight = (hour, AMPM) -> hour == 12 and AMPM == 0

        time_expression = (Hour, Minute, Second, AMPM, SpecialTimeText ) ->
            if not Hour? and not Minute? and not Second? and not AMPM? and not SpecialTimeText?
                return
            if SpecialTimeText
                if SpecialTimeText.toLowerCase() == "noon"
                    return {hour: 12}
                if SpecialTimeText.toLowerCase() == "midnight"
                    return {hour: 0}
            d = {}
            if Hour
                d.hour = Number(Hour)
            if Minute
                d.minute = Number(Minute)
            if Second
                d.second = Number(Second)
            if AMPM?
                if d.hour
                    if noon(d.hour, AMPM)
                        d.hour = 12
                    else if midnight(d.hour, AMPM)
                        d.hour = 0
                    else
                        d.hour = d.hour + AMPM
                d.am_pm = AMPM
            if [d.hour, d.minute, d.second] == [undefined, undefined, undefined]
                return undefined
            return d

        time_and_time = (Hour, Minute, AMPM1, Hour2, Minute2, AMPM2) ->
            if AMPM2?
                AMPM2 = am_pm(AMPM2)
            if not AMPM1? and not AMPM2?
                return [time_expression(Hour, Minute), time_expression(Hour2, Minute2)]
            else if not AMPM1?
                return [time_expression(Hour, Minute, undefined, AMPM2),
                        time_expression(Hour2, Minute2, undefined, AMPM2)]
            else if not AMPM2?
                return [time_expression(Hour, Minute, undefined, AMPM1),
                        time_expression(Hour2, Minute2, undefined, AMPM1)]

        month_type = (input...) ->
            for value in input
                if value?
                    return Number(value)

        date_number = (Day, Abbr) -> if Day? then Number(Day)

        month_number = (MonthNum) -> Number(MonthNum)

        month_num_type = (input) -> Number(input)

        year = (Year) -> if Year? then Number(Year)

Sometimes the value is [undefined, undefined, <value>],
so I need to search for it and find it.

        get_first_defined = (_) ->
          for item in _
            if item?
              return item

### Patterns

There's a some unwrapping values out of arrays here.
Because of the namedarguments issue functions receive a lot more
arrays then in Python and so they need to be unwrapped.

        weekday_range_with_time = (time1, time2, [weekday1], [weekday2], MonthRange) ->
            output = []

            # Get first undefined value
            # Since only one value in list will be defined (if any)
            time1 = get_first_defined(time1)
            time2 = get_first_defined(time2)

            if time1?
                for date in MonthRange
                    output.push(_replace(date, time1))
                    if time2?
                        output.push(_replace(date, time2))
            return output

        weekday_range_with_extra = ( time, and_time, weekday_start, weekday_end, extra_time, extra_weekday, MonthRange) ->
            output = []
            if time?
                for date in MonthRange
                    if date.weekday?
                        if date.weekday in [weekday_start .. weekday_end]
                            output.push(_replace(date, time))
                            if and_time?
                                output.push(_replace(date, and_time))
                        if date.weekday == extra_weekday
                            output.push(_replace(date, extra_time))
            return output

        weekday_range_with_extra_backwards = (extra_time, extra_weekday, time, weekday_start, weekday_end, MonthRange ) ->
            return weekday_range_with_extra(time[0], time[1], weekday_start, weekday_end, extra_time, extra_weekday, MonthRange )

        reverse_basic_text = (time, day, month, year) ->
            return basic_text(time, undefined, undefined, month, day, year)

        basic_text = (time, first_second, weekday, month, day, year) ->
            if not day?
                day = 1
            if (day instanceof Array) and day.length == 1
              day = day[0]
            if (year instanceof Array) and year.length == 1
              year = year[0]
            if not time?
                return {year: year, month: month, day: day}
            else
                year: year
                month: month
                day: day
                hour: time.hour
                minute: time.minute
                second: time.second
                am_pm: time.am_pm

        slash = (month, day, year, time) ->
            return basic_text(time, undefined, undefined, month, day, year)

        month_range = (month, date_a, date_b) ->
            output = []
            for day in [date_a .. date_b]
                output.push(basic_text(undefined, undefined, undefined, month, day, undefined))
            return output

        multi_time = (time1, BasicText) ->
            output = []
            if time1? and BasicText?
                output.push(_replace(BasicText, time1))
                output.push(BasicText)
                return output

        large_repeat_words = ->
            return undefined

        weekday_range_with_time_range = (time1, weekday_range) ->
            output = []
            if time1? and weekday_range?
                range = timedelta_from_Date(_replace(weekday_range[0], time1), weekday_range[0])
                for weekday in weekday_range
                    output.push(_replace(weekday, {hour:time1.hour, minute:time1.minute, am_pm:time1.am_pm}))
                    output.push(range)
                return output

        time_range = (unstrict_time, strict_time, date, reverse) ->
            endtime = date
            starttime = endtime
            if unstrict_time
                starttime = _replace(starttime, {hour:Number(unstrict_time[0])})
                if date.am_pm
                    starttime = _replace(starttime, {hour: starttime.hour + date.am_pm, am_pm:date.am_pm})
            else
                starttime = _replace(starttime, {hour: strict_time.hour, minute: strict_time.minute})

            time_range = timedelta_from_Date(starttime, endtime)
            if reverse
                time_range = timedelta_from_Date(endtime, starttime)
            return [starttime, time_range]

        alt_time_range = (first_second, weekday, month, day, year, time, unstrict_time, strict_time) ->
            return time_range(unstrict_time, strict_time, basic_text(time, first_second, weekday, month, day, year), reverse)

        until_range = (date1, date2) ->
            if date1 and date2
                return [date1, timedelta_from_Date(date1, date2)]

        through_range = (time, weekday1, weekday2, month, date, beginning) ->
            output = []
            if month and date and beginning and weekday1
                ending =
                    month: month
                    day: date
                for day in [beginning.day .. ending.day]
                    temp =
                        month: month
                        day: date
                    if temp.weekday and in_array([weekday1 .. weekday2], temp.weekday)
                        if time
                            output.push(_replace(temp, time))
                        else
                            output.push(temp)
                return output

### The function list

This hash/object matches all the functions with a
string that represents it in the parse tree.

        functions =
            # Groups
            "MonthString": month_to_number,
            "AMPM": am_pm,
            # Expressions
            "Chase Year": year,
            "Chase Date": date_number,
            "Chase Month": month_number,
            "Steve Valaitis": time_expression,
            "Greg Burns": (hour, am_pm) -> time_expression(hour, null, null, am_pm, null),
            "Greg Burns UnstrictTime:": time_expression,
            "Steve Valaitis2": military_time,
            "Steve Valaitis And Time": time_and_time,
            "Text Parts": time_expression,
            "Michael Ash10": weekday_to_number,
            # Types
            "Month": month_type,
            "MonthNum": month_num_type,
            # Patterns
            "LargeRepeatWords": large_repeat_words,
            "BasicText": basic_text,
            "ReverseBasicText": reverse_basic_text,
            "Slash": slash,
            "MonthRange": month_range,
            "MultiTime": multi_time,
            "WeekdayRangeWithTime": weekday_range_with_time,
            "WeekdayRangeWithExtra": weekday_range_with_extra,
            "WeekdayRangeWithExtraBackwards": weekday_range_with_extra_backwards,
            "WeekdayRangeWithTimeRange": weekday_range_with_time_range,
            "UntilRange": until_range,
            "ThroughRange": through_range,
            "TimeRange": time_range,
            "AltTimeRange": alt_time_range,

This is default expression or pattern. ```any``` means
if value is defined, and there is array with even a single defined value then return true.

            "_default": (_) ->
                if any(_) then _ else undefined

```Type``` there is used to mean collection of expressions.
I know that because only one will match, so you just have to find
it and return it.

            "_default_type": (_...) ->
                if _?
                    for item in _
                         if item?
                             return item

            "_default_group": (_...) -> if _[0]? then _[0]


simplify global plugin management

simplify global plugin management

## API

this is used to populate the listed singleton plugins with their single instance

other plugins may access this instance through requiring the module.

### Example

```coffeescript
require ["pluginPath"], (plugin) -> plugin.getInstance().foo()`
```

### Example Usage

Now in your `main` coffeescript file, you can do something like this.

```coffeescript
requirejs ["celestrium"], (Celestrium) ->
  Celestrium.init
    "core/workspace":
      "el": document.querySelector "#workspace"
```

only plugins which instantiate the `singleton` class should be used with `init`

## Code

Load the global libraries contained within celestrium here.
This offloads this responsibility from the user.

    globalLibs = [
      'lib/jquery',
      'lib/jquery.typeahead',
      'lib/underscore',
      'lib/backbone',
      'lib/d3',
    ]

The actual module returns only an object with an init method.

Load the above libraries so they are now available globally.

This is probably bad practice and less modular, but is practical.

    define globalLibs, () -> init: (singletonPlugins, callback) ->

Now actually require the different plugins.
Note that, they should all be required at once and the callback called within the require callback so as to ensure the callback is only call onced these plugin instances have been initialized.

        pluginPaths = _.keys(singletonPlugins)
        require pluginPaths, (plugins...) ->
          i = 0
          for plugin in plugins
            args = singletonPlugins[pluginPaths[i]]
            plugin.init args
            i += 1
          callback()

## API

this is used to populate the listed singleton plugins with their single instance

other plugins may access this instance through requiring the module.

### Example

```coffeescript
require ["pluginPath"], (plugin) -> plugin.getInstance().foo()`
```

### Example Usage

Now in your `main` coffeescript file, you can do something like this.

```coffeescript
requirejs ["celestrium"], (Celestrium) ->
  Celestrium.init
    "core/workspace":
      "el": document.querySelector "#workspace"
```

only plugins which instantiate the `singleton` class should be used with `init`

## Code

Load the global libraries contained within celestrium here.
This offloads this responsibility from the user.

    globalLibs = [
      'lib/jquery',
      'lib/jquery.typeahead',
      'lib/underscore',
      'lib/backbone',
      'lib/d3',
    ]

The actual module returns only an object with an init method.

    define [], () -> init: (singletonPlugins, callback) ->

Include this nested require call so as to load the above libraries.
Now, these libraries are available globally per the norm.

This is probably bad practice and less modular, but is practical.

      require globalLibs, () ->

Now actually require the different plugins.
Note that, they should all be required at once and the callback called within the require callback so as to ensure the callback is only call onced these plugin instances have been initialized.

        pluginPaths = _.keys(singletonPlugins)
        require pluginPaths, (plugins...) ->
          i = 0
          for plugin in plugins
            args = singletonPlugins[pluginPaths[i]]
            plugin.init args
            i += 1
          callback()


User login form uses new API

User login form uses new API

# User login

    config = require 'config'

    {TransmittableError} = require 'errors'

    exports.pkgmanRegister = (registrar) ->

#### Implements hook `shrubTransmittableErrors`.

      registrar.registerHook 'shrubTransmittableErrors', exports.shrubTransmittableErrors

#### Implements hook `shrubAngularRoutes`.

      registrar.registerHook 'shrubAngularRoutes', ->

        routes = []

        if 'e2e' is config.get 'packageConfig:shrub-core:testMode'

          routes.push

            path: 'e2e/user/login/:destination'

            controller: [
              '$location', '$routeParams', 'shrub-rpc', 'shrub-socket', 'shrub-user'
              ($location, {destination}, rpc, socket, user) ->

                user.fakeLogin('cha0s').then ->
                  $location.path "/user/#{destination}"

            ]

        routes.push

          path: 'user/login'
          title: 'Sign in'

          controller: [
            '$location', '$scope', 'shrub-ui/messages', 'shrub-user'
            ($location, $scope, messages, user) ->
              return $location.path '/' if user.isLoggedIn()

              $scope.form =

                key: 'shrub-user-login'

###### TODO: Use rpc submission with a hidden 'method' field.

                submits: [

                  (values) ->

                    user.login(
                      'local'
                      values.username
                      values.password
                    ).then ->

                      messages.add(
                        class: 'alert-success'
                        text: 'Logged in successfully.'
                      )

                      $location.path '/'

                ]

                fields:

                  username:
                    type: 'text'
                    label: 'Username'
                    required: true

                  password:
                    type: 'password'
                    label: 'Password'
                    required: true

                  submit:
                    type: 'submit'
                    value: 'Sign in'

                  forgot:
                    type: 'markup'
                    value: 'Forgot your password?'

          ]

          template: '''

    '''

        return routes

Transmittable login error.

    class LoginError extends TransmittableError

      key: 'login'
      template: 'No such username/password.'

    exports.shrubTransmittableErrors = -> [
      LoginError
    ]

# User login

    config = require 'config'

    {TransmittableError} = require 'errors'

    exports.pkgmanRegister = (registrar) ->

#### Implements hook `shrubTransmittableErrors`.

      registrar.registerHook 'shrubTransmittableErrors', exports.shrubTransmittableErrors

#### Implements hook `shrubAngularRoutes`.

      registrar.registerHook 'shrubAngularRoutes', ->

        routes = []

        if 'e2e' is config.get 'packageConfig:shrub-core:testMode'

          routes.push

            path: 'e2e/user/login/:destination'

            controller: [
              '$location', '$routeParams', 'shrub-rpc', 'shrub-socket', 'shrub-user'
              ($location, {destination}, rpc, socket, user) ->

                user.fakeLogin('cha0s').then ->
                  $location.path "/user/#{destination}"

            ]

        routes.push

          path: 'user/login'
          title: 'Sign in'

          controller: [
            '$location', '$scope', 'shrub-ui/messages', 'shrub-user'
            ($location, $scope, messages, user) ->
              return $location.path '/' if user.isLoggedIn()

              $scope.form =

                key: 'shrub-user-login'

###### TODO: Use rpc submission with a hidden 'method' field.

                submits: [

                  (values) ->

                    user.login(
                      'local'
                      values.username
                      values.password
                    ).then ->

                      messages.add(
                        class: 'alert-success'
                        text: 'Logged in successfully.'
                      )

                      $location.path '/'

                ]

                fields:

                  username:
                    type: 'text'
                    label: 'Username'
                    required: true

                  password:
                    type: 'password'
                    label: 'Password'
                    required: true

                  submit:
                    type: 'submit'
                    value: 'Sign in'

          ]

          template: '''

    Forgot your password?

    '''

        return routes

Transmittable login error.

    class LoginError extends TransmittableError

      key: 'login'
      template: 'No such username/password.'

    exports.shrubTransmittableErrors = -> [
      LoginError
    ]


Add unix timestamp support to ?after

Add unix timestamp support to ?after

    ObjectID    = require('mongodb').ObjectID
    stringify   = require('JSONStream').stringify
    createHash  = require('crypto').createHash

    Document    = require './model/Document'

    mongo       = require './db/mongo'

## PARAM {collection}

    exports.param = (req, res, next, col) ->
      if col not in ['turer', 'steder', 'grupper', 'områder', 'bilder', 'arrangementer']
        return res.json 404, message: 'Objekttype ikke funnet'

      req.type = col
      req.db   = col: mongo[col]

      next()

## OPTIONS /{collection}

    exports.options = (req, res, next) ->
      res.setHeader 'Access-Control-Expose-Headers', [
        'ETag', 'Location', 'Last-Modified', 'Count-Return', 'Count-Total'
      ].join(', ')
      res.setHeader 'Access-Control-Max-Age', 86400
      res.setHeader 'Access-Control-Allow-Headers', 'Content-Type'
      res.setHeader 'Access-Control-Allow-Methods', 'HEAD, GET, POST'
      res.send 204

## HEAD /{collection}
## GET /{collection}

    exports.get = (req, res, next) ->
      query = {}

### ?tag=`String`

      if typeof req.query.tag is 'string' and req.query.tag isnt ''
        if req.query.tag.charAt(0) is '!' and req.query.tag.length > 1
          query['tags.0'] = $ne: req.query.tag.substr(1)
        else
          query['tags.0'] = req.query.tag

### ?grupper=`String`

      if typeof req.query.gruppe is 'string' and req.query.gruppe isnt ''
        query['grupper'] = req.query.gruppe

### ?after=`Mixed`

      if typeof req.query.after is 'string' and req.query.after isnt ''
        time = req.query.after

        if not isNaN time
          # Make unix timestamp into milliseconds
          time = time + '000' if (time + '').length is 10
          time = parseInt time

        time = new Date time

        if time.toString() isnt 'Invalid Date'
          query.endret = $gte: time.toISOString()

### ?bbox=`min_lng`,`min_lat`,`max_lng`,`max_lat`

      if typeof req.query.bbox is 'string' and req.query.bbox.split(',').length is 4
        bbox = req.query.bbox.split(',')
        bbox[i] = parseFloat(val) for val, i in bbox

        query.geojson =
          '$geoWithin':
            '$geometry':
              type: 'Polygon'
              coordinates: [[
                [bbox[0], bbox[1]]
                [bbox[2], bbox[1]]
                [bbox[2], bbox[3]]
                [bbox[0], bbox[3]]
                [bbox[0], bbox[1]]
              ]]

### ?privat.`String`=`String`

This allows the user to filter documents based on private document properties.
This will autumaticly limit returned documents to those owned by the current
user.

#### ToDo

 * Limit number of private fields?
 * Limit depth of private fields?

`NB` This section is looping through all of the url query parameters and hence
should take the queries from above sections into concideration so we don't need
to do double amount of work.

      for key, val of req.query when key.substr(0,7) is 'privat.'
        if /^[a-zæøåA-ZÆØÅ0-9_.]+$/.test key
          val = parseFloat(val) if not isNaN val # @TODO(starefossen) is this acceptable?
          query.tilbyder = req.usr
          query[key] = val

Limit queries to own documents or public documents i.e. where `doc.status` is
`Offentlig` if not `query.tilbyder` is set.

      query['$or'] = [{status: 'Offentlig'}, {tilbyder: req.usr}] if not query.tilbyder

Only project a few fields to since lists are mostly used intermediate before
fetching the entire document.

      fields = tilbyder: true, endret: true, status: true, navn: true

Set up MongoDB options.

      options =
        limit: Math.min((parseInt(req.query.limit, 10) or 20), 50)
        skip: parseInt(req.query.skip, 10) or 0
        sort: 'endret'

Retrive matching documents from MongoDB.

      cursor = req.db.col.find(query, fields, options)
      cursor.count (err, total) ->
        return next err if err
        res.set 'Count-Return', Math.min(options.limit, total)
        res.set 'Count-Total', total
        return res.send 204 if req.method is 'HEAD'
        return res.json documents: [], count: 0, total: 0 if total is 0
        res.set 'Content-Type', 'application/json; charset=utf-8'

Calculate number of rows returned since we don't know that in advanced (due to
the nature of streaming).

        count = Math.min(options.limit, Math.max(total - options.skip, 0))

Stream documents user in order to prevent loading them into memory.

        op = '{"documents":['
        cl = '],"count":' + count + ',"total":' + total + '}'

        cursor.stream().pipe(stringify(op, ',', cl)).pipe(res)

## POST /{collection}

    exports.post = (req, res, next) ->
      return res.json 400, message: 'Body is missing' if Object.keys(req.body).length is 0
      return res.json 422, message: 'Body should be a JSON Hash' if req.body instanceof Array

      req.body.tilbyder = req.usr

      new Document(req.type, null).once('error', next).once 'ready', ->
        @insert req.body, (err, warn, data) ->
          if err
            return next(err) if err.name isnt 'ValidationError'
            return res.json 422,
              document: req.body
              message: 'Validation Failed'
              errors: err.details #TODO(starefossen) document this

          res.set 'ETag', "\"#{data.checksum}\""
          res.set 'Last-Modified', new Date(data.endret).toUTCString()
          # res.set 'Location', req.get 'host'

          return res.json 201,
            document: data
            message: 'Validation Warnings' if warn.length > 0
            warnings: warn if warn.length > 0

    ObjectID    = require('mongodb').ObjectID
    stringify   = require('JSONStream').stringify
    createHash  = require('crypto').createHash

    Document    = require './model/Document'

    mongo       = require './db/mongo'

## PARAM {collection}

    exports.param = (req, res, next, col) ->
      if col not in ['turer', 'steder', 'grupper', 'områder', 'bilder', 'arrangementer']
        return res.json 404, message: 'Objekttype ikke funnet'

      req.type = col
      req.db   = col: mongo[col]

      next()

## OPTIONS /{collection}

    exports.options = (req, res, next) ->
      res.setHeader 'Access-Control-Expose-Headers', [
        'ETag', 'Location', 'Last-Modified', 'Count-Return', 'Count-Total'
      ].join(', ')
      res.setHeader 'Access-Control-Max-Age', 86400
      res.setHeader 'Access-Control-Allow-Headers', 'Content-Type'
      res.setHeader 'Access-Control-Allow-Methods', 'HEAD, GET, POST'
      res.send 204

## HEAD /{collection}
## GET /{collection}

    exports.get = (req, res, next) ->
      query = {}

### ?tag=`String`

      if typeof req.query.tag is 'string' and req.query.tag isnt ''
        if req.query.tag.charAt(0) is '!' and req.query.tag.length > 1
          query['tags.0'] = $ne: req.query.tag.substr(1)
        else
          query['tags.0'] = req.query.tag

### ?grupper=`String`

      if typeof req.query.gruppe is 'string' and req.query.gruppe isnt ''
        query['grupper'] = req.query.gruppe

### ?after=`Mixed`

      if typeof req.query.after is 'string' and req.query.after isnt ''
        if not isNaN(req.query.after)
          req.query.after = new Date(parseInt(req.query.after, 10)).toISOString()
        query.endret = {$gte:req.query.after}

### ?bbox=`min_lng`,`min_lat`,`max_lng`,`max_lat`

      if typeof req.query.bbox is 'string' and req.query.bbox.split(',').length is 4
        bbox = req.query.bbox.split(',')
        bbox[i] = parseFloat(val) for val, i in bbox

        query.geojson =
          '$geoWithin':
            '$geometry':
              type: 'Polygon'
              coordinates: [[
                [bbox[0], bbox[1]]
                [bbox[2], bbox[1]]
                [bbox[2], bbox[3]]
                [bbox[0], bbox[3]]
                [bbox[0], bbox[1]]
              ]]

### ?privat.`String`=`String`

This allows the user to filter documents based on private document properties.
This will autumaticly limit returned documents to those owned by the current
user.

#### ToDo

 * Limit number of private fields?
 * Limit depth of private fields?

`NB` This section is looping through all of the url query parameters and hence
should take the queries from above sections into concideration so we don't need
to do double amount of work.

      for key, val of req.query when key.substr(0,7) is 'privat.'
        if /^[a-zæøåA-ZÆØÅ0-9_.]+$/.test key
          val = parseFloat(val) if not isNaN val # @TODO(starefossen) is this acceptable?
          query.tilbyder = req.usr
          query[key] = val

Limit queries to own documents or public documents i.e. where `doc.status` is
`Offentlig` if not `query.tilbyder` is set.

      query['$or'] = [{status: 'Offentlig'}, {tilbyder: req.usr}] if not query.tilbyder

Only project a few fields to since lists are mostly used intermediate before
fetching the entire document.

      fields = tilbyder: true, endret: true, status: true, navn: true

Set up MongoDB options.

      options =
        limit: Math.min((parseInt(req.query.limit, 10) or 20), 50)
        skip: parseInt(req.query.skip, 10) or 0
        sort: 'endret'

Retrive matching documents from MongoDB.

      cursor = req.db.col.find(query, fields, options)
      cursor.count (err, total) ->
        return next err if err
        res.set 'Count-Return', Math.min(options.limit, total)
        res.set 'Count-Total', total
        return res.send 204 if req.method is 'HEAD'
        return res.json documents: [], count: 0, total: 0 if total is 0
        res.set 'Content-Type', 'application/json; charset=utf-8'

Calculate number of rows returned since we don't know that in advanced (due to
the nature of streaming).

        count = Math.min(options.limit, Math.max(total - options.skip, 0))

Stream documents user in order to prevent loading them into memory.

        op = '{"documents":['
        cl = '],"count":' + count + ',"total":' + total + '}'

        cursor.stream().pipe(stringify(op, ',', cl)).pipe(res)

## POST /{collection}

    exports.post = (req, res, next) ->
      return res.json 400, message: 'Body is missing' if Object.keys(req.body).length is 0
      return res.json 422, message: 'Body should be a JSON Hash' if req.body instanceof Array

      req.body.tilbyder = req.usr

      new Document(req.type, null).once('error', next).once 'ready', ->
        @insert req.body, (err, warn, data) ->
          if err
            return next(err) if err.name isnt 'ValidationError'
            return res.json 422,
              document: req.body
              message: 'Validation Failed'
              errors: err.details #TODO(starefossen) document this

          res.set 'ETag', "\"#{data.checksum}\""
          res.set 'Last-Modified', new Date(data.endret).toUTCString()
          # res.set 'Location', req.get 'host'

          return res.json 201,
            document: data
            message: 'Validation Warnings' if warn.length > 0
            warnings: warn if warn.length > 0