Fix a typo

Fix a typo

# Configuration

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

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

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

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

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

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

## How GLP configuration works

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

    module.exports =

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

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

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

# Options

## root

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

      root: 'public'

## watch

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

      watch: no

## debug

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

      debug: no

## globOptions

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

      globOptions:
        default:
          options: {}

## cache

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

      cache:

The `cache.enabled` option is true by default, but can be made false if
caching isn't working as expected with your project.

        enabled: yes

## minify

Options for controlling how GLP minifies files.

      minify:

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

        enabled: no

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

        extension: '.min'

## ordering

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

      ordering: {}

## plugins

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

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

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

      plugins:

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

        cached:
          optimizeMemory: yes

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

        uglify:
          outSourceMap: yes

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

        jade:
          pretty: yes

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

## filters

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

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

      filters:

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

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

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

        scripts:
          coffee: {}

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

          jade:
            options:
              client: true

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

        stylesheets:
          sass: {}
          less: {}

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

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

          stylus:
            transforms: 'stylus'

            hints:
              use: ['nib']

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

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

        templates:
          jade:
            options:
              client: false

## concatenators

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

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

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

      concatenators: {}

## extensions

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

## minifiers

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

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

## files

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

      files:

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

        scripts:

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

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

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

Here, we are doing the same thing for *html* and *jade* files, but we are
outputting them with the `templates` file type.

        templates:
          '/': [
            'src/**/*.html'
            'src/**/*.jade'
          ]

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

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

## static

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

      static:

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

        enabled: no

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

        directories: no

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

        catchAll: null

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

        port: 3333

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

## liveReload

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

      liveReload:

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

        enabled: no

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

        port: 35729

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

        inject: yes

## tasks

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

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

      tasks:

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

        default: {}

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

        watch:
          watch: yes

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

        server:
          watch: yes

          static:
            enabled: yes

          liveReload:
            enabled: yes

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

        release:
          minify:
            enabled: yes

          plugins:
            uglify:
              outSourceMap: no

            jade:
              pretty: no

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

# Configuration

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

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

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

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

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

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

## How users configure prefer

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

    module.exports =

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

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

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

# Options

## root

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

      root: 'public'

## watch

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

      watch: no

## debug

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

      debug: no

## globOptions

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

      globOptions:
        default:
          options: {}

## cache

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

      cache:

The `cache.enabled` option is true by default, but can be made false if
caching isn't working as expected with your project.

        enabled: yes

## minify

Options for controlling how GLP minifies files.

      minify:

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

        enabled: no

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

        extension: '.min'

## ordering

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

      ordering: {}

## plugins

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

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

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

      plugins:

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

        cached:
          optimizeMemory: yes

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

        uglify:
          outSourceMap: yes

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

        jade:
          pretty: yes

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

## filters

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

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

      filters:

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

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

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

        scripts:
          coffee: {}

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

          jade:
            options:
              client: true

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

        stylesheets:
          sass: {}
          less: {}

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

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

          stylus:
            transforms: 'stylus'

            hints:
              use: ['nib']

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

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

        templates:
          jade:
            options:
              client: false

## concatenators

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

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

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

      concatenators: {}

## extensions

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

## minifiers

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

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

## files

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

      files:

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

        scripts:

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

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

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

Here, we are doing the same thing for *html* and *jade* files, but we are
outputting them with the `templates` file type.

        templates:
          '/': [
            'src/**/*.html'
            'src/**/*.jade'
          ]

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

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

## static

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

      static:

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

        enabled: no

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

        directories: no

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

        catchAll: null

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

        port: 3333

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

## liveReload

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

      liveReload:

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

        enabled: no

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

        port: 35729

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

        inject: yes

## tasks

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

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

      tasks:

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

        default: {}

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

        watch:
          watch: yes

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

        server:
          watch: yes

          static:
            enabled: yes

          liveReload:
            enabled: yes

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

        release:
          minify:
            enabled: yes

          plugins:
            uglify:
              outSourceMap: no

            jade:
              pretty: no

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


Remove a stray semicolon

Remove a stray semicolon

Keyboard Input
==============

We first collect an event stream of all keyboard events sent to the page.

    keyboardEvents = $(document).asEventStream('keydown')
                                .map('.keyCode')

We keep a map of keycodes to internal names.

    keyMap =
        48: 'view-0',
        49: 'view-1',
        50: 'view-2',
        51: 'view-3',
        52: 'view-4',
        53: 'view-5',
        54: 'view-6',
        55: 'view-7',
        56: 'view-8',
        57: 'view-9',
        75: 'kill', # k
        84: 'load-debug', # t

We then have a stream of keyboard events coming in based on that
map, discarding those that are not present as well as bounces.

    window.Keyboard = keyboardEvents.map( (k) -> keyMap[k] )
                                    .filter( (x) -> x? )
                                    .debounce(150)

Judge Selection
---------------

The keys 1-4 are used to select between display on the judge's desk.

We keep a property here to select between them.

    displayMap =
        'view-1': 'match-display'
        'view-2': 'match-sched'
        'view-3': 'league-state'
        'view-4': 'knockout-state'
        'view-5': 'next-match'
        'view-6': 'day-sched'

    window.JudgeSelection = window.Keyboard.map( (k) -> displayMap[k] )
                                           .filter( (x) -> x? )
                                           .toProperty('match-display')
                                           .skipDuplicates();


chore(server): move configuration above other routes

    require 'newrelic' if process.env.NODE_ENV is 'production'

    raven       = require 'raven'
    sentry      = require './db/sentry'
    express     = require 'express'
    compression = require 'compression'
    bodyParser  = require 'body-parser'

    auth        = require './helper/auth'

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

## Init

    app = express()

### Configuration

    app.use compression()
    app.use bodyParser.json extended: true, limit: '10mb'
    app.disable('x-powered-by')
    app.disable('etag')
    app.set 'port', process.env.APP_PORT or 8080

### Authentication

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

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

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

        req.user = user

        return next err if err

        next()

## GET /

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

## GET /favicon

    app.get '/favicon.ico', (req, res) ->
      res.set 'Content-Type': 'image/x-icon'
      res.status(200).end()

## GET /CloudHealthCheck

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

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

    app.all '/CloudHealthCheck', system.check

## GET /objekttyper

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

## ALL /{collection}

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

## ALL /{collection}/{objectid}

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

## 404 handling

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

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

### Error handling

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

    app.use raven.middleware.express sentry

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

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

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

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

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

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

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

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

## Start

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

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

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

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

    else
      module.exports = app

    require 'newrelic' if process.env.NODE_ENV is 'production'

    raven       = require 'raven'
    sentry      = require './db/sentry'
    express     = require 'express'
    compression = require 'compression'
    bodyParser  = require 'body-parser'

    auth        = require './helper/auth'

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

## Init

    app = express()

### Authentication

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

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

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

        req.user = user

        return next err if err

        next()

### Configuration

    app.use(compression())
    app.use bodyParser.json extended: true, limit: '10mb'
    app.disable('x-powered-by')
    app.disable('etag')
    app.set 'port', process.env.APP_PORT or 8080

## GET /

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

## GET /favicon

    app.get '/favicon.ico', (req, res) ->
      res.set 'Content-Type': 'image/x-icon'
      res.status(200).end()

## GET /CloudHealthCheck

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

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

    app.all '/CloudHealthCheck', system.check

## GET /objekttyper

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

## ALL /{collection}

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

## ALL /{collection}/{objectid}

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

## 404 handling

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

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

### Error handling

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

    app.use raven.middleware.express sentry

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

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

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

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

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

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

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

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

## Start

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

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

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

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

    else
      module.exports = app


Literate CofeeScript underway

Literate CofeeScript underway

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

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

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

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

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

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

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

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

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

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

  class LVar
    constructor: (@name) ->

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

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

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

  F.ignorance = new Bindings()

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

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

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

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

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

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

  # Logico
  # ------

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

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

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

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

)(this)

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

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

  # Non-determinism
  # ---------------

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

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

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

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

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

  class LVar
    constructor: (@name) ->

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

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

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

  F.ignorance = new Bindings()

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

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

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

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

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

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

  # Logico
  # ------

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

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

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

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

)(this)


remove testing stub

remove testing stub

        fill_result = (_) ->
          for result_set in _
            for result in result_set
              for key of result
                if not result[key]?
                  delete result[key]
          return _

        date_test = (test_string, answer_object...) =>
          deepEqual fill_result(this.date_machine(test_string)), [answer_object], test_string

        date_raw_test = (test_string, answer_object) =>
          deepEqual fill_result(this.date_machine(test_string)), answer_object, test_string

        test "sanity", ->
          ok 1==1, "passed!"

        test "date tests", =>

            date_test '01/1/2011',
                day: 1
                month: 1
                year: 2011

            date_test 'All day Thursday-Sunday, Sept. 20-23., Friday September 21',
                    day: 20
                    month: 9
                ,
                    day: 21
                    month: 9
                ,
                    day: 22
                    month: 9
                ,
                    day: 23
                    month: 9

            date_test '12/3/2012',
                    day: 3
                    month: 12
                    year: 2012
            date_test 'Wednesday september 12',
                    day: 12
                    month: 9
            date_test '10 pm, Friday September 21',
                    day: 21
                    month: 9
                    hour: 22
                    am_pm: 12
            date_test '9:30 pm, Friday September 2',
                    day: 2
                    month: 9
                    hour: 21
                    minute: 30
                    am_pm: 12
            date_test '10:30 pm., Wednesday September 12',
                    day: 12
                    month: 9
                    hour: 22
                    minute: 30
                    am_pm: 12
            date_raw_test 'April 7 November 17',
                [[
                    day: 7
                    month: 4
                ],[
                    day: 17
                    month: 11
                ]]
            date_test 'Sat, 09/01/2012 - 12:00pm',
                    day: 1
                    month: 9
                    year: 2012
                    hour: 12
                    minute: 0
                    am_pm: 12
            date_test '14 January 2013',
                    day: 14
                    month: 1
                    year: 2013
            date_test 'January 11',
                    day: 11
                    month: 1
            date_test '7- 9 pm Wednesday, Oct. 31',
                    month: 10
                    day: 31
                    hour: 19
                    am_pm: 12
                ,
                    timedelta: true
                    hours: 2
                    minutes: 0
                    seconds: 0
            date_test 'Sun, 06/16/2013 - 6:00pm',
                    hour: 18
                    month: 6
                    year: 2013
                    day: 16
                    minute: 0
                    am_pm: 12

        fill_result = (_) ->
          for result_set in _
            for result in result_set
              for key of result
                if not result[key]?
                  delete result[key]
          return _

        date_test = (test_string, answer_object...) =>
          deepEqual fill_result(this.date_machine(test_string)), [answer_object], test_string

        date_raw_test = (test_string, answer_object) =>
          deepEqual fill_result(this.date_machine(test_string)), answer_object, test_string

        test "sanity", ->
          ok 1==1, "passed!"

        test "date tests", =>

            ok functions["time"]

            date_test '01/1/2011',
                day: 1
                month: 1
                year: 2011

            date_test 'All day Thursday-Sunday, Sept. 20-23., Friday September 21',
                    day: 20
                    month: 9
                ,
                    day: 21
                    month: 9
                ,
                    day: 22
                    month: 9
                ,
                    day: 23
                    month: 9

            date_test '12/3/2012',
                    day: 3
                    month: 12
                    year: 2012
            date_test 'Wednesday september 12',
                    day: 12
                    month: 9
            date_test '10 pm, Friday September 21',
                    day: 21
                    month: 9
                    hour: 22
                    am_pm: 12
            date_test '9:30 pm, Friday September 2',
                    day: 2
                    month: 9
                    hour: 21
                    minute: 30
                    am_pm: 12
            date_test '10:30 pm., Wednesday September 12',
                    day: 12
                    month: 9
                    hour: 22
                    minute: 30
                    am_pm: 12
            date_raw_test 'April 7 November 17',
                [[
                    day: 7
                    month: 4
                ],[
                    day: 17
                    month: 11
                ]]
            date_test 'Sat, 09/01/2012 - 12:00pm',
                    day: 1
                    month: 9
                    year: 2012
                    hour: 12
                    minute: 0
                    am_pm: 12
            date_test '14 January 2013',
                    day: 14
                    month: 1
                    year: 2013
            date_test 'January 11',
                    day: 11
                    month: 1
            date_test '7- 9 pm Wednesday, Oct. 31',
                    month: 10
                    day: 31
                    hour: 19
                    am_pm: 12
                ,
                    timedelta: true
                    hours: 2
                    minutes: 0
                    seconds: 0
            date_test 'Sun, 06/16/2013 - 6:00pm',
                    hour: 18
                    month: 6
                    year: 2013
                    day: 16
                    minute: 0
                    am_pm: 12


minor bugfix on proper revert on container/properties dealing with unintialized states

# Property - controller of Object properties

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

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

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

## Class Property

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

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

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

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

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

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

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

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

        # 6. soft freeze this instance
        Object.preventExtensions this

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

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

### Computed Properties

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

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

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

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

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

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

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

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

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

## Instance-level methods

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

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

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

### get (key)

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

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

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

### set (value)

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

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

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

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

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

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

### merge (value)

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

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

### delete

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

### update

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

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

### commit async transaction

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

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

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

        @debug "[revert] changing back to:", @state.prior
        # XXX - don't need the below?
        # @delete opts unless @state.prior?
        @state.value = @state.prior

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

        @state.changed = false

### attach (obj, parent, opts)

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

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

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

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

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

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

### find (pattern)

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

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

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

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

### in (pattern)

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

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

### defer (value)

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

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

### error (msg)

Provides more contextual error message pertaining to the Property instance.

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

### toJSON

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

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

### inspect

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

## Export Property Class

    module.exports = Property

# Property - controller of Object properties

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

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

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

## Class Property

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

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

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

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

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

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

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

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

        # 6. soft freeze this instance
        Object.preventExtensions this

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

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

### Computed Properties

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

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

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

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

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

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

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

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

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

## Instance-level methods

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

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

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

### get (key)

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

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

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

### set (value)

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

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

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

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

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

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

### merge (value)

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

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

### delete

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

### update

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

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

### commit async transaction

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

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

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

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

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

        @state.changed = false

### attach (obj, parent, opts)

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

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

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

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

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

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

### find (pattern)

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

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

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

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

### in (pattern)

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

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

### defer (value)

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

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

### error (msg)

Provides more contextual error message pertaining to the Property instance.

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

### toJSON

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

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

### inspect

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

## Export Property Class

    module.exports = Property


Fix server if config file is missing

Fix server if config file is missing

nodePush Pushserver for Tims Chat
=================================

Copyright Information
---------------------

	"@author	Tim Düsterhus"
	"@copyright	2012-2013 Tim Düsterhus"
	"@license	BSD 3-Clause License <http://opensource.org/licenses/BSD-3-Clause>"
	"@package	be.bastelstu.wcf.nodePush"

Setup
-----

Load required namespaces.

	express = require 'express'
	http = require 'http'
	io = require 'socket.io'
	net = require 'net'
	fs = require 'fs'

Load config

	try
		config = require '../config.js'
	catch e
		config = { }

Initialize sane values.

	config.outbound ?= { }
	config.outbound.useTCP ?= true
	config.outbound.port ?= 9001
	config.outbound.host ?= '0.0.0.0'
	config.outbound.socket ?= __dirname + "/../outbound.sock"
	config.inbound ?= { }
	config.inbound.useTCP ?= false
	config.inbound.port ?= 9002
	config.inbound.host ?= '127.0.0.1'
	config.inbound.socket ?= __dirname + "/../inbound.sock"
	config.user ?= 'nobody'
	config.group ?= 'nogroup'

Prepare environment

	log = (message) ->
		console.log "[be.bastelstu.chat.nodePush] #{message}"

	thousandsSeparator = (number) ->
		String(number).replace /(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1,'

	# Ensure our namespace is present
	be = be ? {}
	be.bastelstu ?= {}
	be.bastelstu.chat ?= {}

be.bastelstu.chat.nodePush
==========================

	class be.bastelstu.chat.nodePush

Attributes
----------

Instance of express.

		app: null

Instance of http

		server: null

Instance of socket.io

		io: null

Statistics for the status page.

		stats:
			status: 0
			outbound:
				total: 0
				current: 0
			inbound: 0
			messages: { }
			bootTime: new Date()

Methods
-------
**constructor()**

		constructor: ->
			log 'Starting nodePush'
			log "PID is #{process.pid}"
			if config.inbound.useTCP
				log "Inbound: #{config.inbound.host}:#{config.inbound.port}"
			else
				log "Inbound: #{config.inbound.socket}"
			if config.outbound.useTCP
				log "Outbound: #{config.outbound.host}:#{config.outbound.port}"
			else
				log "Outbound: #{config.outbound.socket}"

			@stats.bootTime = new Date()

			@initUnixSocket()
			@initServer()

Bind shutdown function to needed events.

			process.on 'exit', @shutdown.bind @
			process.on 'uncaughtException', @shutdown.bind @
			process.on 'SIGINT', @shutdown.bind @
			process.on 'SIGTERM', @shutdown.bind @

Set nice title for PS.

			process.title = 'nodePush - Tims Chat'

**initServer()**
Initialize socket server.

		initServer: ->
			log 'Initializing outbound socket'

Start HTTP service.

			@app = express()
			@server = http.createServer @app
			@io = io.listen @server

			listenCallback = =>

Shed root privilegies.

				if process.getuid() is 0 or process.getgid() is 0
					try
						log 'Trying to shed root privilegies'
						process.setgid config.group
						process.setuid config.user
						log "New User ID: #{process.getuid()}, New Group ID: #{process.getgid()}"
					catch e
						log 'Cowardly refusing to keep the process alive as root.'
						process.exit 1

Initialize intervals for tick events. The ticks are sent every 15 / 30 / 60 / 90 / 120 seconds.

				setInterval =>
					@sendMessage 'tick15'
				, 15e3
				setInterval =>
					@sendMessage 'tick30'
				, 30e3
				setInterval =>
					@sendMessage 'tick60'
				, 60e3
				setInterval =>
					@sendMessage 'tick90'
				, 90e3
				setInterval =>
					@sendMessage 'tick120'
				, 120e3

				log "Done"

			if config.outbound.useTCP
				@server.listen config.outbound.port, config.outbound.host, null, listenCallback
			else
				@server.listen config.outbound.socket, listenCallback
				fs.chmod config.outbound.socket, '777'

Initialize production environment.

			@io.set 'log level', 1
			@io.set 'browser client etag', true
			@io.set 'browser client minification', true
			@io.set 'browser client gzip', true

Development configuration.

			@io.configure 'development', =>
				@io.set 'log level', 3
				@io.set 'browser client etag', false
				@io.set 'browser client minification', false

Record statistics for Websocket connections.

			@io.sockets.on 'connection', (socket) =>
				@stats.outbound.total++
				@stats.outbound.current++

				socket.on 'disconnect', =>
					@stats.outbound.current--

Show the status page when '/' is requested.

			@app.get '/', (req, res) =>
				res.type 'text/plain'
				@stats.status++
				reply = """
				Up since: #{@stats.bootTime}
				Status page: #{thousandsSeparator @stats.status} Requests
				Outbound: #{thousandsSeparator @stats.outbound.current} now - #{thousandsSeparator @stats.outbound.total} Total
				Inbound: #{thousandsSeparator @stats.inbound}
				Messages:
				"""
				for message, amount of @stats.messages
					reply += "\n	#{message}: #{thousandsSeparator amount}"

				res.send reply

**sendMessage(name)**
Sends a message with the given name.

		sendMessage: (name) ->
			return unless /[a-zA-Z0-9-_.]+$/.test name

			@stats.messages[name] ?= 0
			@stats.messages[name]++
			@io.sockets.send name

**initUnixSocket()**
Initialize PHP side unix socket.

		initUnixSocket: ->
			log 'Initializing inbound socket'
			socket = net.createServer (c) =>
				@stats.inbound++

Pass data to the browsers and close connection.

				c.on 'data', (data) =>
					setTimeout =>
						@sendMessage data.toString().trim()
					, 20
					c.end()

				c.on 'end', ->
					c.end()

Kill connection after 5 seconds.

				c.setTimeout 5e3, ->
					c.end()

			if config.inbound.useTCP
				socket.listen config.inbound.port, config.inbound.host
			else
				socket.listen config.inbound.socket
				fs.chmod config.inbound.socket, '777'

**shutdown()**
Performs a clean shutdown of nodePush.

		shutdown: (message) ->
			if not message
				log 'Shutting down'
			else
				log "Shutting down: #{message}"

			fs.unlinkSync config.inbound.socket unless config.inbound.useTCP
			fs.unlinkSync config.outbound.socket unless config.outbound.useTCP

			process.removeAllListeners()
			process.exit()

And finally start the service.

	new be.bastelstu.chat.nodePush()

nodePush Pushserver for Tims Chat
=================================

Copyright Information
---------------------

	"@author	Tim Düsterhus"
	"@copyright	2012-2013 Tim Düsterhus"
	"@license	BSD 3-Clause License <http://opensource.org/licenses/BSD-3-Clause>"
	"@package	be.bastelstu.wcf.nodePush"

Setup
-----

Load required namespaces.

	express = require 'express'
	http = require 'http'
	io = require 'socket.io'
	net = require 'net'
	fs = require 'fs'

Load config

	config = require '../config.js'

Initialize sane values.

	config.outbound ?= { }
	config.outbound.useTCP ?= true
	config.outbound.port ?= 9001
	config.outbound.host ?= '0.0.0.0'
	config.outbound.socket ?= __dirname + "/outbound.sock"
	config.inbound ?= { }
	config.inbound.useTCP ?= false
	config.inbound.port ?= 9002
	config.inbound.host ?= '127.0.0.1'
	config.inbound.socket ?= __dirname + "/inbound.sock"
	config.user ?= 'nobody'
	config.group ?= 'nogroup'

Prepare environment

	log = (message) ->
		console.log "[be.bastelstu.chat.nodePush] #{message}"

	thousandsSeparator = (number) ->
		String(number).replace /(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1,'

	# Ensure our namespace is present
	be = be ? {}
	be.bastelstu ?= {}
	be.bastelstu.chat ?= {}

be.bastelstu.chat.nodePush
==========================

	class be.bastelstu.chat.nodePush

Attributes
----------

Instance of express.

		app: null

Instance of http

		server: null

Instance of socket.io

		io: null

Statistics for the status page.

		stats:
			status: 0
			outbound:
				total: 0
				current: 0
			inbound: 0
			messages: { }
			bootTime: new Date()

Methods
-------
**constructor()**

		constructor: ->
			log 'Starting nodePush'
			log "PID is #{process.pid}"
			if config.inbound.useTCP
				log "Inbound: #{config.inbound.host}:#{config.inbound.port}"
			else
				log "Inbound: #{config.inbound.socket}"
			if config.outbound.useTCP
				log "Outbound: #{config.outbound.host}:#{config.outbound.port}"
			else
				log "Outbound: #{config.outbound.socket}"

			@stats.bootTime = new Date()

			@initUnixSocket()
			@initServer()

Bind shutdown function to needed events.

			process.on 'exit', @shutdown.bind @
			process.on 'uncaughtException', @shutdown.bind @
			process.on 'SIGINT', @shutdown.bind @
			process.on 'SIGTERM', @shutdown.bind @

Set nice title for PS.

			process.title = 'nodePush - Tims Chat'

**initServer()**
Initialize socket server.

		initServer: ->
			log 'Initializing outbound socket'

Start HTTP service.

			@app = express()
			@server = http.createServer @app
			@io = io.listen @server

			listenCallback = =>

Shed root privilegies.

				if process.getuid() is 0 or process.getgid() is 0
					try
						log 'Trying to shed root privilegies'
						process.setgid config.group
						process.setuid config.user
						log "New User ID: #{process.getuid()}, New Group ID: #{process.getgid()}"
					catch e
						log 'Cowardly refusing to keep the process alive as root.'
						process.exit 1

Initialize intervals for tick events. The ticks are sent every 15 / 30 / 60 / 90 / 120 seconds.

				setInterval =>
					@sendMessage 'tick15'
				, 15e3
				setInterval =>
					@sendMessage 'tick30'
				, 30e3
				setInterval =>
					@sendMessage 'tick60'
				, 60e3
				setInterval =>
					@sendMessage 'tick90'
				, 90e3
				setInterval =>
					@sendMessage 'tick120'
				, 120e3

				log "Done"

			if config.outbound.useTCP
				@server.listen config.outbound.port, config.outbound.host, null, listenCallback
			else
				@server.listen config.outbound.socket, listenCallback
				fs.chmod config.outbound.socket, '777'

Initialize production environment.

			@io.set 'log level', 1
			@io.set 'browser client etag', true
			@io.set 'browser client minification', true
			@io.set 'browser client gzip', true

Development configuration.

			@io.configure 'development', =>
				@io.set 'log level', 3
				@io.set 'browser client etag', false
				@io.set 'browser client minification', false

Record statistics for Websocket connections.

			@io.sockets.on 'connection', (socket) =>
				@stats.outbound.total++
				@stats.outbound.current++

				socket.on 'disconnect', =>
					@stats.outbound.current--

Show the status page when '/' is requested.

			@app.get '/', (req, res) =>
				res.type 'text/plain'
				@stats.status++
				reply = """
				Up since: #{@stats.bootTime}
				Status page: #{thousandsSeparator @stats.status} Requests
				Outbound: #{thousandsSeparator @stats.outbound.current} now - #{thousandsSeparator @stats.outbound.total} Total
				Inbound: #{thousandsSeparator @stats.inbound}
				Messages:
				"""
				for message, amount of @stats.messages
					reply += "\n	#{message}: #{thousandsSeparator amount}"

				res.send reply

**sendMessage(name)**
Sends a message with the given name.

		sendMessage: (name) ->
			return unless /[a-zA-Z0-9-_.]+$/.test name

			@stats.messages[name] ?= 0
			@stats.messages[name]++
			@io.sockets.send name

**initUnixSocket()**
Initialize PHP side unix socket.

		initUnixSocket: ->
			log 'Initializing inbound socket'
			socket = net.createServer (c) =>
				@stats.inbound++

Pass data to the browsers and close connection.

				c.on 'data', (data) =>
					setTimeout =>
						@sendMessage data.toString().trim()
					, 20
					c.end()

				c.on 'end', ->
					c.end()

Kill connection after 5 seconds.

				c.setTimeout 5e3, ->
					c.end()

			if config.inbound.useTCP
				socket.listen config.inbound.port, config.inbound.host
			else
				socket.listen config.inbound.socket
				fs.chmod config.inbound.socket, '777'

**shutdown()**
Performs a clean shutdown of nodePush.

		shutdown: (message) ->
			if not message
				log 'Shutting down'
			else
				log "Shutting down: #{message}"

			fs.unlinkSync config.inbound.socket unless config.inbound.useTCP
			fs.unlinkSync config.outbound.socket unless config.outbound.useTCP

			process.removeAllListeners()
			process.exit()

And finally start the service.

	new be.bastelstu.chat.nodePush()