]> git.r.bdr.sh - rbdr/tomato-sauce/commitdiff
Merge branch 'feature/rbdr-update-docs' into 'master'
authorRubén Beltran del Río <redacted>
Tue, 26 Jun 2018 22:00:10 +0000 (22:00 +0000)
committerRubén Beltran del Río <redacted>
Tue, 26 Jun 2018 22:00:10 +0000 (22:00 +0000)
Update Documentation

See merge request rbdr/tomato-sauce!1

20 files changed:
.eslintrc [new file with mode: 0644]
.gitlab-ci.yml [new file with mode: 0644]
CHANGELOG.md [new file with mode: 0644]
CONTRIBUTING.md [new file with mode: 0644]
README.md
bin/tomato_sauce.js
doc/README.md [new file with mode: 0644]
lib/renderers/256_colors.js
lib/renderers/ansi.js
lib/renderers/fake_color.js
lib/renderers/true_color.js
lib/screens/circle.js
lib/screens/gradients.js
lib/screens/mirrors.js
lib/screens/random.js
lib/screens/sprinkles.js
lib/tomato_sauce.js
lib/util.js
package-lock.json [new file with mode: 0644]
package.json

diff --git a/.eslintrc b/.eslintrc
new file mode 100644 (file)
index 0000000..f91f592
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,11 @@
+{
+  "extends": "eslint-config-hapi",
+  "rules": {
+    "indent": [
+      2,
+      2
+    ],
+    "no-undef": 2,
+    "require-yield": 0
+  }
+}
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..fcf1760
--- /dev/null
@@ -0,0 +1,12 @@
+image: node:8
+
+stages:
+  - lint
+
+before_script:
+    - npm install
+
+lint:
+  stage: lint
+  script:
+    - npm run lint
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..e21f2d9
--- /dev/null
@@ -0,0 +1,31 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## [Unreleased]
+### Added
+- Contributing Guide
+- This Changelog
+- Linter
+- CI Config
+- Documentation with JSDoc
+
+### Changed
+- Code style
+
+## 1.0.0 - 2016-05-09
+### Added
+- 256 color renderer
+- ANSI color renderer
+- True color renderer
+- Fake color renderer
+- Circle screen
+- Gradients screen
+- Random screen
+- Sprinkles screen
+- Mirrors screen
+- Main server
+
+[Unreleased]: https://gitlab.com/rbdr/sumo/compare/master...develop
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..81079cb
--- /dev/null
@@ -0,0 +1,20 @@
+# Contributing to Tomato Sauce
+
+This project doesn't really have much of a roadmap other than making
+more screens. If you have any new screens or would like to make
+improvements please feel free to submit changes.
+
+## The objective of Tomato Sauce
+
+Render pretty things using telnet
+
+## How to contribute
+
+Above All: Be nice, always.
+
+* Ensure the linter shows no warnings or errors
+* Don't break the CI
+* Make the PRs according to [Git Flow][gitflow]: (features go to
+  develop, hotfixes go to master)
+
+[gitflow]: https://github.com/nvie/gitflow
index 99ae4fbbbcb8153320854d193df1e3d3f30d1be5..6671109608e3c6561e7bd31914026faf1b0f8cc4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,9 +1,12 @@
-# tomato-sauce
+## Tomato Sauce
+
 Draw stuff via telnet
 
 ## How to run
 
-`npm install` and then run ``./bin/server.js`. It will listen on port 9999
+You will need [Node.js][node] installed, at least version 8. Install
+dependencies by running `npm install` from the root of the project
+and start the server by running `npm start`. It will listen on port 9999
 by default.
 
 ## Configuration variables
@@ -27,8 +30,8 @@ the width of the viewport, the height of the viewport, and a renderer
 function, and it returns a string that consists of the commands that
 will be sent to the socket.
 
-  * `TomatoSauce.IScreen(modulation <int>, width <int>, height <int>, renderer
-    <TomatoSauce.IRenderer>) -> payload <string>`
+  * `IScreen(modulation <int>, width <int>, height <int>, renderer
+    <IRenderer>) -> payload <string>`
 
 It should output the required commands that telnet needs to move the
 cursor and draw. For convenience, a renderer function is passed so
@@ -46,7 +49,7 @@ You can build your own renderer by building a function that receives a
 red, green, and blue component from 0 to 255 and returns the escape
 codes to generate the color.
 
-  * `TomatoSauce.IRenderer(red <int>, green <int>, blue <int>) ->
+  * `IRenderer(red <int>, green <int>, blue <int>) ->
     colorString <string>`
 
 ## Using as a library
@@ -62,12 +65,14 @@ const TomatoSauce = require('tomato-sauce');
 
 const tomatoSauce = new TomatoSauce(config);
 
-tomatoSauce.on('listening', function () {
+tomatoSauce.on('listening', () => {
+
   const address = event.data.server.address();
   console.log(`Tomato Sauce listening on: ${address.address}:${address.port}`);
 });
 
-tomatoSauce.on('error', function (error) {
+tomatoSauce.on('error', (error) => {
+
   console.error(error);
 });
 
@@ -86,4 +91,5 @@ optional.)
     (Defaults to 5)
   * `screens`: An array containing the screen functions (Defaults to [])
   * `renderers`: An array containing the renderer functions (Defaults to [])
-```
+
+[node]: https://nodejs.org/en/
index 5a416d5fd8a1f209312c9a055d01cfe8c5ad4f94..efe71a3939ab90a62150adb01e9edaa00e45253a 100755 (executable)
@@ -19,23 +19,30 @@ const config = {
 const screenPath = Getenv('TOMATO_SAUCE_SCREEN_PATH', Path.join(__dirname, '../lib/screens'));
 const rendererPath = Getenv('TOMATO_SAUCE_RENDERER_PATH', Path.join(__dirname, '../lib/renderers'));
 
-Util.loadFiles(screenPath).then(function (screens) {
+Util.loadFiles(screenPath).then((screens) => {
+
   config.screens = screens;
   return Util.loadFiles(rendererPath);
-}).then(function (renderers) {
-  config.renderers = renderers;
-}).then(function () {
-  let tomatoSauce = new TomatoSauce(config);
-
-  tomatoSauce.on('listening', function (event) {
-    const address = event.data.server.address();
-    console.log(`Tomato Sauce listening on: ${address.address}:${address.port}`);
-  });
+})
+  .then((renderers) => {
 
-  tomatoSauce.on('error', function (error) {
-    console.error(error.stack || error.message || error);
-    process.exit(1);
-  });
+    config.renderers = renderers;
+  })
+  .then(() => {
+
+    const tomatoSauce = new TomatoSauce(config);
+
+    tomatoSauce.on('listening', (event) => {
 
-  tomatoSauce.run();
-});
+      const address = event.data.server.address();
+      console.log(`Tomato Sauce listening on: ${address.address}:${address.port}`);
+    });
+
+    tomatoSauce.on('error', (error) => {
+
+      console.error(error.stack || error.message || error);
+      process.exit(1);
+    });
+
+    tomatoSauce.run();
+  });
diff --git a/doc/README.md b/doc/README.md
new file mode 100644 (file)
index 0000000..c1054cd
--- /dev/null
@@ -0,0 +1,261 @@
+## Classes
+
+<dl>
+<dt><a href="#TomatoSauce">TomatoSauce</a> ⇐ <code>EventEmitter</code></dt>
+<dd></dd>
+</dl>
+
+## Members
+
+<dl>
+<dt><a href="#Util">Util</a> : <code>Object</code></dt>
+<dd><p>Module containing utility functions</p>
+</dd>
+</dl>
+
+## Functions
+
+<dl>
+<dt><a href="#256ColorsRenderer">256ColorsRenderer()</a></dt>
+<dd><p>Returns a 256 color, see <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">https://en.wikipedia.org/wiki/ANSI_escape_code#Colors</a>
+for more info.</p>
+</dd>
+<dt><a href="#ANSIRenderer">ANSIRenderer()</a></dt>
+<dd><p>Returns a basic ansi color, see <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">https://en.wikipedia.org/wiki/ANSI_escape_code#Colors</a>
+for more info.</p>
+</dd>
+<dt><a href="#FakeColorRenderer">FakeColorRenderer()</a></dt>
+<dd><p>Returns a malformed 24-bit ansi color</p>
+</dd>
+<dt><a href="#TrueColorRenderer">TrueColorRenderer()</a></dt>
+<dd><p>Returns an ANSI code for 24-bit True Color, see
+<a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">https://en.wikipedia.org/wiki/ANSI_escape_code#Colors</a> and look for
+24-bit colors for more info. Only looks good in supported terminals,
+otherwise looks like FakeColor</p>
+</dd>
+<dt><a href="#CircleScreen">CircleScreen()</a></dt>
+<dd><p>Draws concentric circles. Each ring has its own color.</p>
+</dd>
+<dt><a href="#GradientsScreen">GradientsScreen()</a></dt>
+<dd><p>Draws moving gradient boxes</p>
+</dd>
+<dt><a href="#MirrorsScreen">MirrorsScreen()</a></dt>
+<dd><p>Draws small moving gradient boxes and repeats them.</p>
+</dd>
+<dt><a href="#RandomScreen">RandomScreen()</a></dt>
+<dd><p>Draws random colors</p>
+</dd>
+<dt><a href="#SprinklesScreen">SprinklesScreen()</a></dt>
+<dd><p>Draws random sprinkles in the screen each frame. Same color per
+frame.</p>
+</dd>
+</dl>
+
+## Interfaces
+
+<dl>
+<dt><a href="#IScreen">IScreen</a> ⇒ <code>String</code></dt>
+<dd><p>A function that represents a screen, it is called frequently and should
+return a string consisting of commands to run.</p>
+</dd>
+<dt><a href="#IRenderer">IRenderer</a> ⇒ <code>String</code></dt>
+<dd><p>A function that represents a renderer, it should take in a color in RGB and
+return a string with the appropriate code to colorize the terminal.</p>
+</dd>
+</dl>
+
+<a name="IScreen"></a>
+
+## IScreen ⇒ <code>String</code>
+A function that represents a screen, it is called frequently and should
+return a string consisting of commands to run.
+
+**Kind**: global interface  
+**Returns**: <code>String</code> - The commands used to render the screen elements  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| modulation | <code>Number</code> | A number between 0 and 255 representing the current step of the modulation |
+| width | <code>Number</code> | The width of the screen |
+| height | <code>Number</code> | The height of the screen |
+| renderer | [<code>IRenderer</code>](#IRenderer) | The renderer used to colorize the scfeen |
+
+<a name="IRenderer"></a>
+
+## IRenderer ⇒ <code>String</code>
+A function that represents a renderer, it should take in a color in RGB and
+return a string with the appropriate code to colorize the terminal.
+
+**Kind**: global interface  
+**Returns**: <code>String</code> - The commands used to colorize the terminal  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| red | <code>Number</code> | The red component of the color between 0 and 255 |
+| green | <code>Number</code> | The green component of the color between 0 and 255 |
+| blue | <code>Number</code> | The green component of the color between 0 and 255 |
+
+<a name="TomatoSauce"></a>
+
+## TomatoSauce ⇐ <code>EventEmitter</code>
+**Kind**: global class  
+**Extends**: <code>EventEmitter</code>  
+**Properties**
+
+| Name | Type | Default | Description |
+| --- | --- | --- | --- |
+| screens | [<code>Array.&lt;IScreen&gt;</code>](#IScreen) |  | an array of screens available to serve |
+| renderers | [<code>Array.&lt;IRenderer&gt;</code>](#IRenderer) |  | an array of renderers available to colorize |
+| [port] | <code>Number</code> | <code>9999</code> | the port to listen on |
+| [frequency] | <code>Number</code> | <code>333</code> | how often to update the screen |
+| [modulation] | <code>Number</code> | <code>5</code> | number between 0-255 depicting current modulation step |
+
+
+* [TomatoSauce](#TomatoSauce) ⇐ <code>EventEmitter</code>
+    * [new TomatoSauce(config)](#new_TomatoSauce_new)
+    * [.run()](#TomatoSauce+run)
+
+<a name="new_TomatoSauce_new"></a>
+
+### new TomatoSauce(config)
+The main application for tomato sauce. Listens for connections and serves
+random combinations of screens and renderers
+
+The main entry point is the `#run()` function.
+
+It emits a listening event that contains the server information on
+the `server` key inside the `data` property of the event.
+
+It also emits an error event that contains the error information on
+the `error` key inside the `data` property of the event.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| config | <code>object</code> | the configuration object used to extend the properties. |
+
+<a name="TomatoSauce+run"></a>
+
+### tomatoSauce.run()
+Main entry point, initializes the server and binds events for connections
+
+**Kind**: instance method of [<code>TomatoSauce</code>](#TomatoSauce)  
+<a name="Util"></a>
+
+## Util : <code>Object</code>
+Module containing utility functions
+
+**Kind**: global variable  
+
+* [Util](#Util) : <code>Object</code>
+    * [.parse16BitBuffer(buffer)](#Util.parse16BitBuffer) ⇒ <code>Number</code>
+    * [.pickRandom(array)](#Util.pickRandom) ⇒ <code>Any</code>
+    * [.loadFiles(path)](#Util.loadFiles) ⇒ <code>Array</code>
+
+<a name="Util.parse16BitBuffer"></a>
+
+### Util.parse16BitBuffer(buffer) ⇒ <code>Number</code>
+Parses a 16 bit number buffer
+
+**Kind**: static method of [<code>Util</code>](#Util)  
+**Returns**: <code>Number</code> - the parsed value  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| buffer | <code>Array.&lt;String&gt;</code> | the buffer to parse |
+
+<a name="Util.pickRandom"></a>
+
+### Util.pickRandom(array) ⇒ <code>Any</code>
+Picks a random element from an array
+
+**Kind**: static method of [<code>Util</code>](#Util)  
+**Returns**: <code>Any</code> - the picked element  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| array | <code>Array</code> | the array to use |
+
+<a name="Util.loadFiles"></a>
+
+### Util.loadFiles(path) ⇒ <code>Array</code>
+For a gi ven path, requires all of the files and returns an array
+with the results. If the directory contains any non-requireable
+files, it will fail.
+
+**Kind**: static method of [<code>Util</code>](#Util)  
+**Returns**: <code>Array</code> - the array of all the loaded modules  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| path | <code>String</code> | the path where the files are located |
+
+<a name="256ColorsRenderer"></a>
+
+## 256ColorsRenderer()
+Returns a 256 color, see https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+for more info.
+
+**Kind**: global function  
+**Implements**: [<code>IRenderer</code>](#IRenderer)  
+<a name="ANSIRenderer"></a>
+
+## ANSIRenderer()
+Returns a basic ansi color, see https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+for more info.
+
+**Kind**: global function  
+**Implements**: [<code>IRenderer</code>](#IRenderer)  
+<a name="FakeColorRenderer"></a>
+
+## FakeColorRenderer()
+Returns a malformed 24-bit ansi color
+
+**Kind**: global function  
+**Implements**: [<code>IRenderer</code>](#IRenderer)  
+<a name="TrueColorRenderer"></a>
+
+## TrueColorRenderer()
+Returns an ANSI code for 24-bit True Color, see
+https://en.wikipedia.org/wiki/ANSI_escape_code#Colors and look for
+24-bit colors for more info. Only looks good in supported terminals,
+otherwise looks like FakeColor
+
+**Kind**: global function  
+**Implements**: [<code>IRenderer</code>](#IRenderer)  
+<a name="CircleScreen"></a>
+
+## CircleScreen()
+Draws concentric circles. Each ring has its own color.
+
+**Kind**: global function  
+**Implements**: [<code>IScreen</code>](#IScreen)  
+<a name="GradientsScreen"></a>
+
+## GradientsScreen()
+Draws moving gradient boxes
+
+**Kind**: global function  
+**Implements**: [<code>IScreen</code>](#IScreen)  
+<a name="MirrorsScreen"></a>
+
+## MirrorsScreen()
+Draws small moving gradient boxes and repeats them.
+
+**Kind**: global function  
+**Implements**: [<code>IScreen</code>](#IScreen)  
+<a name="RandomScreen"></a>
+
+## RandomScreen()
+Draws random colors
+
+**Kind**: global function  
+**Implements**: [<code>IScreen</code>](#IScreen)  
+<a name="SprinklesScreen"></a>
+
+## SprinklesScreen()
+Draws random sprinkles in the screen each frame. Same color per
+frame.
+
+**Kind**: global function  
+**Implements**: [<code>IScreen</code>](#IScreen)  
index e8e6e37566c57e516ca77f62cedc79dca6a396de..f6e57d33841a604953c15aaf50c9c480301692b5 100644 (file)
@@ -1,16 +1,19 @@
 'use strict';
 
-// Returns a 256 color, see
-// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
-// under 256 colors for more info.
-const TwoFiftySixColors = function (red, blue, green) {
-  let redValue = Math.round(red * 5 / 255);
-  let blueValue = Math.round(blue * 5 / 255);
-  let greenValue = Math.round(green * 5 / 255);
+/**
+ * Returns a 256 color, see https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ * for more info.
+ *
+ * @function 256ColorsRenderer
+ * @implements IRenderer
+ */
+module.exports = function (red, blue, green) {
 
-  let colorNumber = 16 + 36 * redValue + 6 * greenValue + blueValue;
+  const redValue = Math.round(red * 5 / 255);
+  const blueValue = Math.round(blue * 5 / 255);
+  const greenValue = Math.round(green * 5 / 255);
+
+  const colorNumber = 16 + 36 * redValue + 6 * greenValue + blueValue;
 
   return `\x1B[48;5;${colorNumber}m`;
 };
-
-module.exports = TwoFiftySixColors;
index c3975da9e7ef4ae0eba0470e7be6cd3c63b0203e..b3a461d5f449f37cba1c2bac66887a11c7913c19 100644 (file)
@@ -1,13 +1,16 @@
 'use strict';
 
-// Returns a basic ANSI color. See the color table in:
-// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
-const ANSI = function (red, blue, green) {
-  let colorOffset = Math.round((red + blue + green) * 7 / (255 * 3));
+/**
+ * Returns a basic ansi color, see https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ * for more info.
+ *
+ * @function ANSIRenderer
+ * @implements IRenderer
+ */
+module.exports = function (red, blue, green) {
 
-  let colorNumber = 40 + colorOffset;
+  const colorOffset = Math.round((red + blue + green) * 7 / (255 * 3));
+  const colorNumber = 40 + colorOffset;
 
   return `\x1B[${colorNumber}m`;
 };
-
-module.exports = ANSI;
index b82bb45659507dbe0d5fac758c952aa4e2975557..b03309c365beac8ffb87b7aabcfaaa6b9d2b59c0 100644 (file)
@@ -1,8 +1,12 @@
 'use strict';
 
-// Sends malformed ANSI 24-bit color strings
-const FakeColor = function (red, blue, green) {
+/**
+ * Returns a malformed 24-bit ansi color
+ *
+ * @function FakeColorRenderer
+ * @implements IRenderer
+ */
+module.exports = function (red, blue, green) {
+
   return `\x1B[28;2;${Math.round(red)};${Math.round(green)};${Math.round(blue)}m`;
 };
-
-module.exports = FakeColor;
index 5f7725f2adf73b14fdf22f7c812836440bfe723a..811d186515d3717093388528c4d77cfce7c08d52 100644 (file)
@@ -4,8 +4,16 @@
 // https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
 // and look for 24-bit colors. Only looks good in supported terminals,
 // otherwise looks like FakeColor.
-const TrueColor = function (red, blue, green) {
+/**
+ * Returns an ANSI code for 24-bit True Color, see
+ * https://en.wikipedia.org/wiki/ANSI_escape_code#Colors and look for
+ * 24-bit colors for more info. Only looks good in supported terminals,
+ * otherwise looks like FakeColor
+ *
+ * @function TrueColorRenderer
+ * @implements IRenderer
+ */
+module.exports = function (red, blue, green) {
+
   return `\x1B[48;2;${Math.round(red)};${Math.round(green)};${Math.round(blue)}m`;
 };
-
-module.exports = TrueColor;
index d8a4d100730ad4b4c3b05732e7b2ea9abaa7c670..720e250ddd0e414ce4a9234e0681ca70a7dd0098 100644 (file)
@@ -1,26 +1,32 @@
 'use strict';
 
-// Draws concentric circles. Each ring has its own color.
-const Circle = function (modulation, width, height, renderer) {
-  let response = [];
+/**
+ * Draws concentric circles. Each ring has its own color.
+ *
+ * @function CircleScreen
+ * @implements IScreen
+ */
+module.exports = function (modulation, width, height, renderer) {
 
-  let circles = width > height ? height : width;
+  const response = [];
 
-  for (let i = 0; i < circles; i++) {
-    let centerX = Math.round(width / 2) + 1;
-    let centerY = Math.round(height / 2) + 1;
+  const circles = width > height ? height : width;
 
-    let red = Math.floor(Math.random() * 255);
-    let blue = Math.floor(Math.random() * 255);
-    let green = Math.floor(Math.random() * 255);
+  for (let i = 0; i < circles; ++i) {
+    const centerX = Math.round(width / 2) + 1;
+    const centerY = Math.round(height / 2) + 1;
 
-    for (let j = 0; j < 180; j++) {
-      let angle =  2 * j * (Math.PI / 180);
-      let x = Math.round(centerX + Math.sin(angle) * i);
-      let y = Math.round(centerY + Math.cos(angle) * i);
+    const red = Math.floor(Math.random() * 255);
+    const blue = Math.floor(Math.random() * 255);
+    const green = Math.floor(Math.random() * 255);
+
+    for (let j = 0; j < 180; ++j) {
+      const angle =  2 * j * (Math.PI / 180);
+      const x = Math.round(centerX + Math.sin(angle) * i);
+      const y = Math.round(centerY + Math.cos(angle) * i);
 
       if (x <= width && x > 0 && y <= height && y > 0) {
-        let position = `\x1B[${y};${x}H`; // Move cursor to y,x (CSI y;x H)
+        const position = `\x1B[${y};${x}H`; // Move cursor to y,x (CSI y;x H)
         response += `${position}${renderer(red, blue, green)} `;
       }
     }
@@ -28,5 +34,3 @@ const Circle = function (modulation, width, height, renderer) {
 
   return response;
 };
-
-module.exports = Circle;
index 5e63d5ba9e567c1aec5ca690a20cba8263749883..2d4a2f0b4458b3bf8c05efe7670a575802d812f2 100644 (file)
@@ -1,14 +1,20 @@
 'use strict';
 
-// Draws moving gradient boxes.
-const Gradients = function (modulation, width, height, renderer) {
+/**
+ * Draws moving gradient boxes
+ *
+ * @function GradientsScreen
+ * @implements IScreen
+ */
+module.exports = function (modulation, width, height, renderer) {
+
   let response = '';
 
-  for (let i = 0; i < height; i++) {
-    for (let j = 0; j < width; j++) {
-      let red = ((modulation + i) * 255 / height) % 255;
-      let blue = ((modulation + j) * 255 / width) % 255;
-      let green = ((modulation + i * j) * 255 / (width * height)) % 255;
+  for (let i = 0; i < height; ++i) {
+    for (let j = 0; j < width; ++j) {
+      const red = ((modulation + i) * 255 / height) % 255;
+      const blue = ((modulation + j) * 255 / width) % 255;
+      const green = ((modulation + i * j) * 255 / (width * height)) % 255;
 
       response = response + renderer(red, blue, green);
       response = response + ' ';
@@ -21,5 +27,3 @@ const Gradients = function (modulation, width, height, renderer) {
 
   return response;
 };
-
-module.exports = Gradients;
index d683fb63c2d165b7eb0b2ab84e47f9d24537ac3b..e8422177cafafef3408f09cf347792f928a59647 100644 (file)
@@ -1,30 +1,36 @@
 'use strict';
 
-// Draws small moving gradient boxes and repeats them.
-const Mirrors = function (modulation, width, height, renderer) {
-  let response = [];
-
-  let scale = 2 + Math.round(Math.random() * 4);
-  let scaledHeight = Math.floor(height / scale);
-  let scaledWidth = Math.floor(width / scale);
-
-  for (let i = 0; i < scaledHeight; i++) {
-    let row = [];
-    for (let j = 0; j < scaledWidth; j++) {
-      let red = ((modulation + i) * 255 / height) % 255;
-      let blue = ((modulation + j) * 255 / width) % 255;
-      let green = ((modulation + i * j) * 255 / (width * height)) % 255;
-
-      let cell = [renderer(red, blue, green), ' '];
+/**
+ * Draws small moving gradient boxes and repeats them.
+ *
+ * @function MirrorsScreen
+ * @implements IScreen
+ */
+module.exports = function (modulation, width, height, renderer) {
+
+  const response = [];
+
+  const scale = 2 + Math.round(Math.random() * 4);
+  const scaledHeight = Math.floor(height / scale);
+  const scaledWidth = Math.floor(width / scale);
+
+  for (let i = 0; i < scaledHeight; ++i) {
+    const row = [];
+    for (let j = 0; j < scaledWidth; ++j) {
+      const red = ((modulation + i) * 255 / height) % 255;
+      const blue = ((modulation + j) * 255 / width) % 255;
+      const green = ((modulation + i * j) * 255 / (width * height)) % 255;
+
+      const cell = [renderer(red, blue, green), ' '];
       row.push(cell.join(''));
     }
 
     let rowText = '';
-    for (let j = 0; j < scale; j++) {
+    for (let j = 0; j < scale; ++j) {
       rowText += row.reverse().join('');
     }
 
-    for (let j = 1; j < scale; j++) {
+    for (let j = 1; j < scale; ++j) {
       response[j * i] = rowText;
       response[(height - 1 - (j * i))] = rowText;
     }
@@ -32,5 +38,3 @@ const Mirrors = function (modulation, width, height, renderer) {
 
   return response.join('\n');
 };
-
-module.exports = Mirrors;
index 6ac706f039ddc5720050a2750373615c2a151073..0cacea7c20a5bd439206c2c2e931e3d00f5e7059 100644 (file)
@@ -1,14 +1,20 @@
 'use strict';
 
-// random colors
-const Random = function (modulation, width, height, renderer) {
+/**
+ * Draws random colors
+ *
+ * @function RandomScreen
+ * @implements IScreen
+ */
+module.exports = function (modulation, width, height, renderer) {
+
   let response = '';
 
-  for (let i = 0; i < height; i++) {
-    for (let j = 0; j < width; j++) {
-      let red = Math.floor(Math.random() * 255);
-      let blue = Math.floor(Math.random() * 255);
-      let green = Math.floor(Math.random() * 255);
+  for (let i = 0; i < height; ++i) {
+    for (let j = 0; j < width; ++j) {
+      const red = Math.floor(Math.random() * 255);
+      const blue = Math.floor(Math.random() * 255);
+      const green = Math.floor(Math.random() * 255);
 
       response = response + renderer(red, blue, green);
       response = response + ' ';
@@ -21,5 +27,3 @@ const Random = function (modulation, width, height, renderer) {
 
   return response;
 };
-
-module.exports = Random;
index 446f46ec9ff556695c4c6f3d77c1cb2f3abe1bbe..f12200e0fec4597282af96a0cba8b9eac73d3280 100644 (file)
@@ -1,28 +1,32 @@
 'use strict';
 
-// Places random sprinkles in the screen each frame. Same color per
-// frame.
-const Sprinkles = function (modulation, width, height, renderer) {
+/**
+ * Draws random sprinkles in the screen each frame. Same color per
+ * frame.
+ *
+ * @function SprinklesScreen
+ * @implements IScreen
+ */
+module.exports = function (modulation, width, height, renderer) {
+
   let response = '';
 
-  let maxSprinkleCount = (width * height) / 2;
-  let minSprinkleCount = (width * height) / 8;
-  let sprinkleCount = Math.round(Math.random() * (maxSprinkleCount - minSprinkleCount)) + minSprinkleCount;
+  const maxSprinkleCount = (width * height) / 2;
+  const minSprinkleCount = (width * height) / 8;
+  const sprinkleCount = Math.round(Math.random() * (maxSprinkleCount - minSprinkleCount)) + minSprinkleCount;
 
-  let red = Math.floor(Math.random() * 255);
-  let blue = Math.floor(Math.random() * 255);
-  let green = Math.floor(Math.random() * 255);
+  const red = Math.floor(Math.random() * 255);
+  const blue = Math.floor(Math.random() * 255);
+  const green = Math.floor(Math.random() * 255);
 
-  for (let i = 0; i < sprinkleCount; i++) {
-    let x = Math.round(Math.random() * (width - 1)) + 1;
-    let y = Math.round(Math.random() * (height - 1)) + 1;
+  for (let i = 0; i < sprinkleCount; ++i) {
+    const x = Math.round(Math.random() * (width - 1)) + 1;
+    const y = Math.round(Math.random() * (height - 1)) + 1;
 
-    let position = `\x1B[${y};${x}H`; // Move cursor to y,x (CSI y;x H)
+    const position = `\x1B[${y};${x}H`; // Move cursor to y,x (CSI y;x H)
 
     response += `${position}${renderer(red, blue, green)} `;
   }
 
   return response;
 };
-
-module.exports = Sprinkles;
index 0ff087a7d6f2454072897eccb4ac8298bf1b8372..f3017ea8f1789516cd618c618d85cd2b61ecccaf 100644 (file)
@@ -5,89 +5,150 @@ const EventEmitter = require('events');
 
 const Util = require('./util');
 
-// Interpret as Command Sequences.
-const kEscape = new Buffer([0xFF, 0xF4, 0XFF, 0xFD, 0x06]); // IAC IP IAC DO TIMING_MARK
-const kNAWSRequest = new Buffer([0xFF, 0xFD, 0X1F]); // IAC DO NAWS
-const kNAWSResponse = new Buffer([0xFF, 0xFB, 0X1F, 0xFF, 0xFA, 0X1F]); // IAC WILL NAWS IAC SB NAWS
-
-// Main tomato sauce class. Properties:
-// * screens <TomatoSauce.IScreen[]>
-// * renderers <TomatoSauce.IRenderer[]>
-// * port <int>
-// * frequency <int>
-// * modulation <int>
-//
-// The main entry point is the #run() function.
-//
-// It emits a listening event that contains the server information on
-// the `server` key inside the `data` property of the event.
-//
-// It also emits an error event that contains the error information on
-// the `error` key inside the `data` property of the event.
+const internals = {
+  // Interpret as Command Sequences.
+  kEscape: new Buffer([0xFF, 0xF4, 0XFF, 0xFD, 0x06]), // IAC IP IAC DO TIMING_MARK
+  kNAWSRequest: new Buffer([0xFF, 0xFD, 0X1F]), // IAC DO NAWS
+  kNAWSResponse: new Buffer([0xFF, 0xFB, 0X1F, 0xFF, 0xFA, 0X1F]) // IAC WILL NAWS IAC SB NAWS
+};
+
+/**
+ * A function that represents a screen, it is called frequently and should
+ * return a string consisting of commands to run.
+ *
+ * @interface IScreen
+ * @type function
+ * @param {Number} modulation A number between 0 and 255 representing the current
+ * step of the modulation
+ * @param {Number} width The width of the screen
+ * @param {Number} height The height of the screen
+ * @param {IRenderer} renderer The renderer used to colorize the scfeen
+ * @return {String} The commands used to render the screen elements
+ */
+
+/**
+ * A function that represents a renderer, it should take in a color in RGB and
+ * return a string with the appropriate code to colorize the terminal.
+ *
+ * @interface IRenderer
+ * @type function
+ * @param {Number} red The red component of the color between 0 and 255
+ * @param {Number} green The green component of the color between 0 and 255
+ * @param {Number} blue The green component of the color between 0 and 255
+ * @return {String} The commands used to colorize the terminal
+ */
+
+/**
+ * The main application for tomato sauce. Listens for connections and serves
+ * random combinations of screens and renderers
+ *
+ * The main entry point is the `#run()` function.
+ *
+ * It emits a listening event that contains the server information on
+ * the `server` key inside the `data` property of the event.
+ *
+ * It also emits an error event that contains the error information on
+ * the `error` key inside the `data` property of the event.
+ *
+ * @class TomatoSauce
+ * @extends EventEmitter
+ *
+ * @param {object} config the configuration object used to extend the properties.
+ *
+ * @property {Array<IScreen>} screens an array of screens available to serve
+ * @property {Array<IRenderer>} renderers an array of renderers available to colorize
+ * @property {Number} [port=9999] the port to listen on
+ * @property {Number} [frequency=333] how often to update the screen
+ * @property {Number} [modulation=5] number between 0-255 depicting current modulation step
+ */
 const TomatoSauce = class TomatoSauce extends EventEmitter {
 
-  constructor (config) {
+  constructor(config = {}) {
+
     super();
 
     this.screens = [];
     this.renderers = [];
 
-    Object.assign(this, config || {});
+    // Defaults.
+    this.port = 9999;
+    this.frequency = 333;
+    this.modulation = 5;
+
+    Object.assign(this, config);
   }
 
-  // Here's where things get started.
-  run () {
+  /**
+   * Main entry point, initializes the server and binds events for connections
+   *
+   * @function run
+   * @instance
+   * @memberof TomatoSauce
+   */
+  run() {
+
     this._startServer();
     this._bindEvents();
   }
 
   // Creates a socket, server based on the configuration. Emits the
   // listening event when ready.
-  _startServer () {
+
+  _startServer() {
+
     const server = Net.createServer();
     this.server = server;
-    server.listen(this.port, function () {
+    server.listen(this.port, () => {
+
       this.emit('listening', {
         data: {
-          server: server
+          server
         }
       });
-    }.bind(this));
+    });
   }
 
-  _bindEvents () {
+  // Binds the connection and error events
+
+  _bindEvents() {
+
     // Send the error event all the way up.
-    this.server.on('error', function (err) {
+    this.server.on('error', (error) => {
+
       this.emit('error', {
         data: {
-          error: err
+          error
         }
       });
-    }.bind(this));
+    });
 
     // Send the error event all the way up.
-    this.server.on('connection', function (socket) {
+    this.server.on('connection', (socket) => {
+
       this._renderScreen(socket);
-    }.bind(this));
+    });
   }
 
   // Obtains viewport size, and initializes a random screen with a random
   // renderer, setting the required interval to draw.
-  _renderScreen (socket) {
-    let connectionData = {
+
+  _renderScreen(socket) {
+
+    const connectionData = {
       width: null,
       height: null,
       modulation: 0,
       screen: this._getScreen(),
       renderer: this._getRenderer(),
-      socket: socket
+      socket
     };
-    let interval = null;
+    const interval = null;
+
+    socket.write(internals.kNAWSRequest);
 
-    socket.write(kNAWSRequest);
+    socket.on('data', (data) => {
 
-    socket.on('data', function (data) {
-      if (data.slice(0, 6).compare(kNAWSResponse) === 0) {
+      if (data.slice(0, 6).compare(internals.kNAWSResponse) === 0) {
         connectionData.width = Util.parse16BitBuffer(data.slice(6, 8));
         connectionData.height = Util.parse16BitBuffer(data.slice(8, 10));
 
@@ -95,35 +156,34 @@ const TomatoSauce = class TomatoSauce extends EventEmitter {
         interval = setInterval(this._writeMessage.bind(this, connectionData), this.frequency);
       }
 
-      if (data.compare(kEscape) === 0) {
+      if (data.compare(internals.kEscape) === 0) {
         socket.write('\n');
         clearInterval(interval);
         socket.end();
       }
-    }.bind(this));
+    });
   }
 
   // Resets the cursor, gets a frame and sends it to the socket.
-  _writeMessage (connectionData) {
-    let payload = connectionData.screen(connectionData.modulation, connectionData.width, connectionData.height, connectionData.renderer);
-    let message = `\x1B[1;1H${payload}`; // reset cursor position before payload
+
+  _writeMessage(connectionData) {
+
+    const payload = connectionData.screen(connectionData.modulation, connectionData.width, connectionData.height, connectionData.renderer);
+    const message = `\x1B[1;1H${payload}`; // reset cursor position before payload
 
     connectionData.modulation = (connectionData.modulation + this.modulation) % 256;
     connectionData.socket.write(message);
   }
 
-  _getScreen () {
+  _getScreen() {
+
     return Util.pickRandom(this.screens);
   }
 
-  _getRenderer () {
+  _getRenderer() {
+
     return Util.pickRandom(this.renderers);
   }
 };
 
-// Defaults.
-TomatoSauce.prototype.port = 9999;
-TomatoSauce.prototype.frequency = 333;
-TomatoSauce.prototype.modulation = 5;
-
 module.exports = TomatoSauce;
index 3234d3edbe6aa7641005db82912a023a1408a023..65f14ae005ece1023632eae7e64e4b1ca5ad311b 100644 (file)
@@ -3,38 +3,70 @@
 const Fs = require('fs');
 const Path = require('path');
 
-// Module containing utility functions.
+/**
+ * Module containing utility functions
+ *
+ * @name Util
+ * @type Object
+ */
 const Util = {
 
-  // Parses a 16 bit number buffer.
-  parse16BitBuffer: function (buffer) {
+  /**
+   * Parses a 16 bit number buffer
+   *
+   * @function parse16BitBuffer
+   * @memberof Util
+   * @param {Array<String>} buffer the buffer to parse
+   * @return {Number} the parsed value
+   */
+  parse16BitBuffer(buffer) {
+
     return buffer[0] * 256 + buffer[1];
   },
 
-  // Picks a random element from an array.
-  pickRandom: function (array) {
+  /**
+   * Picks a random element from an array
+   *
+   * @function pickRandom
+   * @memberof Util
+   * @param {Array} array the array to use
+   * @return {Any} the picked element
+   */
+  pickRandom(array) {
+
     return array[Math.floor(Math.random() * array.length)];
   },
 
-  // For a given path, requires all of the files and returns an array
-  // with the results. If the directory contains any non-requireable file,
-  // it will fail.
-  loadFiles: function (path) {
-    return new Promise(function (resolve, reject) {
-      Fs.readdir(path, function (err, files) {
+  /**
+   * For a gi ven path, requires all of the files and returns an array
+   * with the results. If the directory contains any non-requireable
+   * files, it will fail.
+   *
+   * @function loadFiles
+   * @memberof Util
+   * @param {String} path the path where the files are located
+   * @return {Array} the array of all the loaded modules
+   */
+  loadFiles(path) {
+
+    return new Promise((resolve, reject) => {
+
+      Fs.readdir(path, (err, files) => {
+
         if (err) {
           return reject(err);
         }
 
-        let loadedFiles = [];
+        const loadedFiles = [];
 
-        for (let file of files) {
-          let filePath = Path.join(path, file);
+        for (const file of files) {
+          const filePath = Path.join(path, file);
           let loadedFile;
 
           try {
             loadedFile = require(filePath);
-          } catch (err) {
+          }
+          catch (err) {
             return reject(err);
           }
 
diff --git a/package-lock.json b/package-lock.json
new file mode 100644 (file)
index 0000000..3775a55
--- /dev/null
@@ -0,0 +1,1951 @@
+{
+  "name": "tomato-sauce",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "acorn": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz",
+      "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
+      "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
+      "dev": true,
+      "requires": {
+        "acorn": "3.3.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
+          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
+          "dev": true
+        }
+      }
+    },
+    "ajv": {
+      "version": "5.5.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+      "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+      "dev": true,
+      "requires": {
+        "co": "4.6.0",
+        "fast-deep-equal": "1.1.0",
+        "fast-json-stable-stringify": "2.0.0",
+        "json-schema-traverse": "0.3.1"
+      }
+    },
+    "ajv-keywords": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
+      "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
+      "dev": true
+    },
+    "align-text": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+      "dev": true,
+      "requires": {
+        "kind-of": "3.2.2",
+        "longest": "1.0.1",
+        "repeat-string": "1.6.1"
+      }
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "dev": true
+    },
+    "ansi-escape-sequences": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.0.0.tgz",
+      "integrity": "sha512-v+0wW9Wezwsyb0uF4aBVCjmSqit3Ru7PZFziGF0o2KwTvN2zWfTi3BRLq9EkJFdg3eBbyERXGTntVpBxH1J68Q==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0"
+      }
+    },
+    "ansi-escapes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
+      "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+      "dev": true
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "1.0.3"
+      }
+    },
+    "argv-tools": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/argv-tools/-/argv-tools-0.1.1.tgz",
+      "integrity": "sha512-Cc0dBvx4dvrjjKpyDA6w8RlNAw8Su30NvZbWl/Tv9ZALEVlLVkWQiHMi84Q0xNfpVuSaiQbYkdmWK8g1PLGhKw==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "find-replace": "2.0.1"
+      }
+    },
+    "array-back": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz",
+      "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==",
+      "dev": true,
+      "requires": {
+        "typical": "2.6.1"
+      }
+    },
+    "array-union": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true,
+      "requires": {
+        "array-uniq": "1.0.3"
+      }
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+      "dev": true
+    },
+    "async": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+      "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+      "dev": true
+    },
+    "babel-code-frame": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "esutils": "2.0.2",
+        "js-tokens": "3.0.2"
+      },
+      "dependencies": {
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "2.1.1"
+          }
+        }
+      }
+    },
+    "babylon": {
+      "version": "7.0.0-beta.19",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz",
+      "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "bluebird": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+      "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
+      "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
+      "dev": true
+    },
+    "cache-point": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-0.4.1.tgz",
+      "integrity": "sha512-4TgWfe9SF+bUy5cCql8gWHqKNrviufNwSYxLjf2utB0pY4+bdcuFwMmY1hDB+67Gz/L1vmhFNhePAjJTFBtV+Q==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "fs-then-native": "2.0.0",
+        "mkdirp2": "1.0.4"
+      }
+    },
+    "caller-path": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+      "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+      "dev": true,
+      "requires": {
+        "callsites": "0.2.0"
+      }
+    },
+    "callsites": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+      "dev": true
+    },
+    "camelcase": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+      "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+      "dev": true,
+      "optional": true
+    },
+    "catharsis": {
+      "version": "0.8.9",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz",
+      "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=",
+      "dev": true,
+      "requires": {
+        "underscore-contrib": "0.3.0"
+      }
+    },
+    "center-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "align-text": "0.1.4",
+        "lazy-cache": "1.0.4"
+      }
+    },
+    "chalk": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+      "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "3.2.1",
+        "escape-string-regexp": "1.0.5",
+        "supports-color": "5.4.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.2"
+          }
+        },
+        "supports-color": {
+          "version": "5.4.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
+          "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
+          "dev": true,
+          "requires": {
+            "has-flag": "3.0.0"
+          }
+        }
+      }
+    },
+    "chardet": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
+      "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
+      "dev": true
+    },
+    "circular-json": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+      "dev": true
+    },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "dev": true,
+      "requires": {
+        "restore-cursor": "2.0.0"
+      }
+    },
+    "cli-width": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+      "dev": true
+    },
+    "cliui": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+      "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "center-align": "0.1.3",
+        "right-align": "0.1.3",
+        "wordwrap": "0.0.2"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.2",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+          "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+      "dev": true
+    },
+    "collect-all": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.3.tgz",
+      "integrity": "sha512-0y0rBgoX8IzIjBAUnO73SEtSb4Mhk3IoceWJq5zZSxb9mWORhWH8xLYo4EDSOE1jRBk1LhmfjqWFFt10h/+MEA==",
+      "dev": true,
+      "requires": {
+        "stream-connect": "1.0.2",
+        "stream-via": "1.0.4"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.2",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
+      "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.1"
+      }
+    },
+    "color-name": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
+      "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
+      "dev": true
+    },
+    "command-line-args": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.0.2.tgz",
+      "integrity": "sha512-/qPcbL8zpqg53x4rAaqMFlRV4opN3pbla7I7k9x8kyOBMQoGT6WltjN6sXZuxOXw6DgdK7Ad+ijYS5gjcr7vlA==",
+      "dev": true,
+      "requires": {
+        "argv-tools": "0.1.1",
+        "array-back": "2.0.0",
+        "find-replace": "2.0.1",
+        "lodash.camelcase": "4.3.0",
+        "typical": "2.6.1"
+      }
+    },
+    "command-line-tool": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/command-line-tool/-/command-line-tool-0.8.0.tgz",
+      "integrity": "sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==",
+      "dev": true,
+      "requires": {
+        "ansi-escape-sequences": "4.0.0",
+        "array-back": "2.0.0",
+        "command-line-args": "5.0.2",
+        "command-line-usage": "4.1.0",
+        "typical": "2.6.1"
+      }
+    },
+    "command-line-usage": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz",
+      "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==",
+      "dev": true,
+      "requires": {
+        "ansi-escape-sequences": "4.0.0",
+        "array-back": "2.0.0",
+        "table-layout": "0.4.4",
+        "typical": "2.6.1"
+      }
+    },
+    "common-sequence": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-1.0.2.tgz",
+      "integrity": "sha1-MOB/P49vf5s97oVPILLTnu4Ibeg=",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "1.1.0",
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.6",
+        "typedarray": "0.0.6"
+      }
+    },
+    "config-master": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz",
+      "integrity": "sha1-ZnZjWQUFooO/JqSE1oSJ10xUhdo=",
+      "dev": true,
+      "requires": {
+        "walk-back": "2.0.1"
+      },
+      "dependencies": {
+        "walk-back": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz",
+          "integrity": "sha1-VU4qnYdPrEeoywBr9EwvDEmYoKQ=",
+          "dev": true
+        }
+      }
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "cross-spawn": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+      "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+      "dev": true,
+      "requires": {
+        "lru-cache": "4.1.3",
+        "shebang-command": "1.2.0",
+        "which": "1.3.1"
+      }
+    },
+    "debug": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true,
+      "optional": true
+    },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "dev": true
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "del": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+      "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+      "dev": true,
+      "requires": {
+        "globby": "5.0.0",
+        "is-path-cwd": "1.0.0",
+        "is-path-in-cwd": "1.0.1",
+        "object-assign": "4.1.1",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1",
+        "rimraf": "2.6.2"
+      }
+    },
+    "dmd": {
+      "version": "3.0.12",
+      "resolved": "https://registry.npmjs.org/dmd/-/dmd-3.0.12.tgz",
+      "integrity": "sha512-79w644JdsB2TthYpVl2bDurX7i9Abaegg2E7X46Ajc135aASTMXxrHzJ9mOa5X5nbmnXwlBYiF68K+1baX+BzQ==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "cache-point": "0.4.1",
+        "common-sequence": "1.0.2",
+        "file-set": "2.0.0",
+        "handlebars": "4.0.11",
+        "marked": "0.3.19",
+        "object-get": "2.1.0",
+        "reduce-flatten": "1.0.1",
+        "reduce-unique": "1.0.0",
+        "reduce-without": "1.0.1",
+        "test-value": "3.0.0",
+        "walk-back": "3.0.0"
+      }
+    },
+    "doctrine": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "dev": true,
+      "requires": {
+        "esutils": "2.0.2"
+      }
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "eslint": {
+      "version": "4.19.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
+      "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
+      "dev": true,
+      "requires": {
+        "ajv": "5.5.2",
+        "babel-code-frame": "6.26.0",
+        "chalk": "2.4.1",
+        "concat-stream": "1.6.2",
+        "cross-spawn": "5.1.0",
+        "debug": "3.1.0",
+        "doctrine": "2.1.0",
+        "eslint-scope": "3.7.1",
+        "eslint-visitor-keys": "1.0.0",
+        "espree": "3.5.4",
+        "esquery": "1.0.1",
+        "esutils": "2.0.2",
+        "file-entry-cache": "2.0.0",
+        "functional-red-black-tree": "1.0.1",
+        "glob": "7.1.2",
+        "globals": "11.7.0",
+        "ignore": "3.3.10",
+        "imurmurhash": "0.1.4",
+        "inquirer": "3.3.0",
+        "is-resolvable": "1.1.0",
+        "js-yaml": "3.12.0",
+        "json-stable-stringify-without-jsonify": "1.0.1",
+        "levn": "0.3.0",
+        "lodash": "4.17.10",
+        "minimatch": "3.0.4",
+        "mkdirp": "0.5.1",
+        "natural-compare": "1.4.0",
+        "optionator": "0.8.2",
+        "path-is-inside": "1.0.2",
+        "pluralize": "7.0.0",
+        "progress": "2.0.0",
+        "regexpp": "1.1.0",
+        "require-uncached": "1.0.3",
+        "semver": "5.5.0",
+        "strip-ansi": "4.0.0",
+        "strip-json-comments": "2.0.1",
+        "table": "4.0.2",
+        "text-table": "0.2.0"
+      }
+    },
+    "eslint-config-hapi": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-hapi/-/eslint-config-hapi-11.1.0.tgz",
+      "integrity": "sha512-fCw0uLgkZLQBqYu/lR5MA6cXB+D4c2EEtzrVmhHbGQq3iRCFSaUEOE/N4Sujd1Qh5jkaUc0/kuB/gdv2upt5aQ==",
+      "dev": true
+    },
+    "eslint-plugin-hapi": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-hapi/-/eslint-plugin-hapi-4.1.0.tgz",
+      "integrity": "sha512-z1yUoSWArx6pXaC0FoWRFpqjbHn8QWonJiTVhJmiC14jOAT7FZKdKWCkhM4jQrgrkEK9YEv3p2HuzSf5dtWmuQ==",
+      "dev": true,
+      "requires": {
+        "hapi-capitalize-modules": "1.1.6",
+        "hapi-for-you": "1.0.0",
+        "hapi-no-var": "1.0.1",
+        "hapi-scope-start": "2.1.1",
+        "no-arrowception": "1.0.0"
+      }
+    },
+    "eslint-scope": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+      "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+      "dev": true,
+      "requires": {
+        "esrecurse": "4.2.1",
+        "estraverse": "4.2.0"
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
+      "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
+      "dev": true
+    },
+    "espree": {
+      "version": "3.5.4",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
+      "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
+      "dev": true,
+      "requires": {
+        "acorn": "5.7.1",
+        "acorn-jsx": "3.0.1"
+      }
+    },
+    "esprima": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
+      "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
+      "dev": true
+    },
+    "esquery": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+      "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+      "dev": true,
+      "requires": {
+        "estraverse": "4.2.0"
+      }
+    },
+    "esrecurse": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "dev": true,
+      "requires": {
+        "estraverse": "4.2.0"
+      }
+    },
+    "estraverse": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+      "dev": true
+    },
+    "external-editor": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
+      "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
+      "dev": true,
+      "requires": {
+        "chardet": "0.4.2",
+        "iconv-lite": "0.4.23",
+        "tmp": "0.0.33"
+      }
+    },
+    "fast-deep-equal": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
+      "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+      "dev": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+      "dev": true
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "1.0.5"
+      }
+    },
+    "file-entry-cache": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true,
+      "requires": {
+        "flat-cache": "1.3.0",
+        "object-assign": "4.1.1"
+      }
+    },
+    "file-set": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-set/-/file-set-2.0.0.tgz",
+      "integrity": "sha512-cCWXfw+nrYoIoUVmEF7Xsw91lGWuObtSnTEZ7AmdvZou1A/6Xx237HfxdQyC/ayKRvQSMbNOBwg62OjN5JxbXw==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "glob": "7.1.2"
+      }
+    },
+    "find-replace": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-2.0.1.tgz",
+      "integrity": "sha512-LzDo3Fpa30FLIBsh6DCDnMN1KW2g4QKkqKmejlImgWY67dDFPX/x9Kh/op/GK522DchQXEvDi/wD48HKW49XOQ==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "test-value": "3.0.0"
+      }
+    },
+    "flat-cache": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
+      "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
+      "dev": true,
+      "requires": {
+        "circular-json": "0.3.3",
+        "del": "2.2.2",
+        "graceful-fs": "4.1.11",
+        "write": "0.2.1"
+      }
+    },
+    "fs-then-native": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz",
+      "integrity": "sha1-GaEk2U2QwiyOBF8ujdbr6jbUjGc=",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "dev": true
+    },
+    "getenv": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/getenv/-/getenv-0.6.0.tgz",
+      "integrity": "sha1-SBo1F3RudLOPh8XXDoBuEFr1TfU="
+    },
+    "glob": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "1.0.0",
+        "inflight": "1.0.6",
+        "inherits": "2.0.3",
+        "minimatch": "3.0.4",
+        "once": "1.4.0",
+        "path-is-absolute": "1.0.1"
+      }
+    },
+    "globals": {
+      "version": "11.7.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz",
+      "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==",
+      "dev": true
+    },
+    "globby": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+      "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+      "dev": true,
+      "requires": {
+        "array-union": "1.0.2",
+        "arrify": "1.0.1",
+        "glob": "7.1.2",
+        "object-assign": "4.1.1",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+      "dev": true
+    },
+    "handlebars": {
+      "version": "4.0.11",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
+      "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
+      "dev": true,
+      "requires": {
+        "async": "1.5.2",
+        "optimist": "0.6.1",
+        "source-map": "0.4.4",
+        "uglify-js": "2.8.29"
+      }
+    },
+    "hapi-capitalize-modules": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/hapi-capitalize-modules/-/hapi-capitalize-modules-1.1.6.tgz",
+      "integrity": "sha1-eZEXFBXhXmqjIx5k3ac8gUZmUxg=",
+      "dev": true
+    },
+    "hapi-for-you": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hapi-for-you/-/hapi-for-you-1.0.0.tgz",
+      "integrity": "sha1-02L77o172pwseAHiB+WlzRoLans=",
+      "dev": true
+    },
+    "hapi-no-var": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hapi-no-var/-/hapi-no-var-1.0.1.tgz",
+      "integrity": "sha512-kk2xyyTzI+eQ/oA1rO4eVdCpYsrPHVERHa6+mTHD08XXFLaAkkaEs6reMg1VyqGh2o5xPt//DO4EhCacLx/cRA==",
+      "dev": true
+    },
+    "hapi-scope-start": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/hapi-scope-start/-/hapi-scope-start-2.1.1.tgz",
+      "integrity": "sha1-dJWnJv5yt7yo3izcwdh82M5qtPI=",
+      "dev": true
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "2.1.1"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "iconv-lite": {
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+      "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": "2.1.2"
+      }
+    },
+    "ignore": {
+      "version": "3.3.10",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
+      "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
+      "dev": true
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "1.4.0",
+        "wrappy": "1.0.2"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
+    },
+    "inquirer": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
+      "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
+      "dev": true,
+      "requires": {
+        "ansi-escapes": "3.1.0",
+        "chalk": "2.4.1",
+        "cli-cursor": "2.1.0",
+        "cli-width": "2.2.0",
+        "external-editor": "2.2.0",
+        "figures": "2.0.0",
+        "lodash": "4.17.10",
+        "mute-stream": "0.0.7",
+        "run-async": "2.3.0",
+        "rx-lite": "4.0.8",
+        "rx-lite-aggregates": "4.0.8",
+        "string-width": "2.1.1",
+        "strip-ansi": "4.0.0",
+        "through": "2.3.8"
+      }
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true
+    },
+    "is-path-cwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+      "dev": true
+    },
+    "is-path-in-cwd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+      "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+      "dev": true,
+      "requires": {
+        "is-path-inside": "1.0.1"
+      }
+    },
+    "is-path-inside": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+      "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+      "dev": true,
+      "requires": {
+        "path-is-inside": "1.0.2"
+      }
+    },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "dev": true
+    },
+    "is-resolvable": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "js-tokens": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+      "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+      "dev": true,
+      "requires": {
+        "argparse": "1.0.10",
+        "esprima": "4.0.0"
+      }
+    },
+    "js2xmlparser": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz",
+      "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=",
+      "dev": true,
+      "requires": {
+        "xmlcreate": "1.0.2"
+      }
+    },
+    "jsdoc": {
+      "version": "3.5.5",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz",
+      "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==",
+      "dev": true,
+      "requires": {
+        "babylon": "7.0.0-beta.19",
+        "bluebird": "3.5.1",
+        "catharsis": "0.8.9",
+        "escape-string-regexp": "1.0.5",
+        "js2xmlparser": "3.0.0",
+        "klaw": "2.0.0",
+        "marked": "0.3.19",
+        "mkdirp": "0.5.1",
+        "requizzle": "0.2.1",
+        "strip-json-comments": "2.0.1",
+        "taffydb": "2.6.2",
+        "underscore": "1.8.3"
+      }
+    },
+    "jsdoc-api": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-4.0.3.tgz",
+      "integrity": "sha512-dfYq9JgB+XahY0XfSEw93PmXmocjwYcvJ5aMuQUJ/OdDRGWamf2SSOk3W06Bsj8qdjp/UdefzqpP/mpwsvHuvA==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "cache-point": "0.4.1",
+        "collect-all": "1.0.3",
+        "file-set": "2.0.0",
+        "fs-then-native": "2.0.0",
+        "jsdoc": "3.5.5",
+        "object-to-spawn-args": "1.1.1",
+        "temp-path": "1.0.0",
+        "walk-back": "3.0.0"
+      }
+    },
+    "jsdoc-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-3.0.1.tgz",
+      "integrity": "sha512-btZLp4wYl90vcAfgk4hoGQbO17iBVrhh3LJRMKZNtZgniO3F8H2CjxXld0owBIB1XxN+j3bAcWZnZKMnSj3iMA==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "lodash.omit": "4.5.0",
+        "lodash.pick": "4.4.0",
+        "reduce-extract": "1.0.0",
+        "sort-array": "2.0.0",
+        "test-value": "3.0.0"
+      }
+    },
+    "jsdoc-to-markdown": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-4.0.1.tgz",
+      "integrity": "sha512-LHJRoLoLyDdxNcColgkLoB/rFG5iRP+PNJjMILI0x+95IdEAtyjSt0wJ6ZlKxRpkhBYtQXTQQ119hMqPIUZzTQ==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "command-line-tool": "0.8.0",
+        "config-master": "3.1.0",
+        "dmd": "3.0.12",
+        "jsdoc-api": "4.0.3",
+        "jsdoc-parse": "3.0.1",
+        "walk-back": "3.0.0"
+      }
+    },
+    "json-schema-traverse": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+      "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "requires": {
+        "is-buffer": "1.1.6"
+      }
+    },
+    "klaw": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz",
+      "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "4.1.11"
+      }
+    },
+    "lazy-cache": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+      "dev": true,
+      "optional": true
+    },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "1.1.2",
+        "type-check": "0.3.2"
+      }
+    },
+    "lodash": {
+      "version": "4.17.10",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+      "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+      "dev": true
+    },
+    "lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
+      "dev": true
+    },
+    "lodash.omit": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
+      "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=",
+      "dev": true
+    },
+    "lodash.padend": {
+      "version": "4.6.1",
+      "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz",
+      "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=",
+      "dev": true
+    },
+    "lodash.pick": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
+      "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=",
+      "dev": true
+    },
+    "longest": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+      "dev": true
+    },
+    "lru-cache": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
+      "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
+      "dev": true,
+      "requires": {
+        "pseudomap": "1.0.2",
+        "yallist": "2.1.2"
+      }
+    },
+    "marked": {
+      "version": "0.3.19",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz",
+      "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==",
+      "dev": true
+    },
+    "mimic-fn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "1.1.11"
+      }
+    },
+    "minimist": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+      "dev": true
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
+      "requires": {
+        "minimist": "0.0.8"
+      }
+    },
+    "mkdirp2": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp2/-/mkdirp2-1.0.4.tgz",
+      "integrity": "sha512-Q2PKB4ZR4UPtjLl76JfzlgSCUZhSV1AXQgAZa1qt5RiaALFjP/CDrGvFBrOz7Ck6McPcwMAxTsJvWOUjOU8XMw==",
+      "dev": true
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "dev": true
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "no-arrowception": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/no-arrowception/-/no-arrowception-1.0.0.tgz",
+      "integrity": "sha1-W/PpXrnEG1c4SoBTM9qjtzTuMno=",
+      "dev": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "object-get": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.0.tgz",
+      "integrity": "sha1-ciu9tgA576R8rTxtws5RqFwCxa4=",
+      "dev": true
+    },
+    "object-to-spawn-args": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-1.1.1.tgz",
+      "integrity": "sha1-d9qIJ/Bz0BHJ4bFz+JV4FHAkZ4U=",
+      "dev": true
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1.0.2"
+      }
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "1.2.0"
+      }
+    },
+    "optimist": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+      "dev": true,
+      "requires": {
+        "minimist": "0.0.8",
+        "wordwrap": "0.0.3"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.3",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+          "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+          "dev": true
+        }
+      }
+    },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true,
+      "requires": {
+        "deep-is": "0.1.3",
+        "fast-levenshtein": "2.0.6",
+        "levn": "0.3.0",
+        "prelude-ls": "1.1.2",
+        "type-check": "0.3.2",
+        "wordwrap": "1.0.0"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-is-inside": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
+      "requires": {
+        "pinkie": "2.0.4"
+      }
+    },
+    "pluralize": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+      "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
+      "dev": true
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+      "dev": true
+    },
+    "progress": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
+      "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
+      "dev": true
+    },
+    "pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+      "dev": true
+    },
+    "readable-stream": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+      "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+      "dev": true,
+      "requires": {
+        "core-util-is": "1.0.2",
+        "inherits": "2.0.3",
+        "isarray": "1.0.0",
+        "process-nextick-args": "2.0.0",
+        "safe-buffer": "5.1.2",
+        "string_decoder": "1.1.1",
+        "util-deprecate": "1.0.2"
+      }
+    },
+    "reduce-extract": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/reduce-extract/-/reduce-extract-1.0.0.tgz",
+      "integrity": "sha1-Z/I4W+2mUGG19fQxJmLosIDKFSU=",
+      "dev": true,
+      "requires": {
+        "test-value": "1.1.0"
+      },
+      "dependencies": {
+        "array-back": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz",
+          "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=",
+          "dev": true,
+          "requires": {
+            "typical": "2.6.1"
+          }
+        },
+        "test-value": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/test-value/-/test-value-1.1.0.tgz",
+          "integrity": "sha1-oJE29y7AQ9J8iTcHwrFZv6196T8=",
+          "dev": true,
+          "requires": {
+            "array-back": "1.0.4",
+            "typical": "2.6.1"
+          }
+        }
+      }
+    },
+    "reduce-flatten": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz",
+      "integrity": "sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=",
+      "dev": true
+    },
+    "reduce-unique": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/reduce-unique/-/reduce-unique-1.0.0.tgz",
+      "integrity": "sha1-flhrz4ek4ytter2Cd/rWzeyfSAM=",
+      "dev": true
+    },
+    "reduce-without": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/reduce-without/-/reduce-without-1.0.1.tgz",
+      "integrity": "sha1-aK0OrRGFXJo31OglbBW7+Hly/Iw=",
+      "dev": true,
+      "requires": {
+        "test-value": "2.1.0"
+      },
+      "dependencies": {
+        "array-back": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz",
+          "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=",
+          "dev": true,
+          "requires": {
+            "typical": "2.6.1"
+          }
+        },
+        "test-value": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz",
+          "integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=",
+          "dev": true,
+          "requires": {
+            "array-back": "1.0.4",
+            "typical": "2.6.1"
+          }
+        }
+      }
+    },
+    "regexpp": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
+      "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "require-uncached": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+      "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+      "dev": true,
+      "requires": {
+        "caller-path": "0.1.0",
+        "resolve-from": "1.0.1"
+      }
+    },
+    "requizzle": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz",
+      "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=",
+      "dev": true,
+      "requires": {
+        "underscore": "1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+          "dev": true
+        }
+      }
+    },
+    "resolve-from": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+      "dev": true
+    },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "dev": true,
+      "requires": {
+        "onetime": "2.0.1",
+        "signal-exit": "3.0.2"
+      }
+    },
+    "right-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "align-text": "0.1.4"
+      }
+    },
+    "rimraf": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "dev": true,
+      "requires": {
+        "glob": "7.1.2"
+      }
+    },
+    "run-async": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "dev": true,
+      "requires": {
+        "is-promise": "2.1.0"
+      }
+    },
+    "rx-lite": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+      "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
+      "dev": true
+    },
+    "rx-lite-aggregates": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
+      "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
+      "dev": true,
+      "requires": {
+        "rx-lite": "4.0.8"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "semver": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+      "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+      "dev": true
+    },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
+    },
+    "slice-ansi": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
+      "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "2.0.0"
+      }
+    },
+    "sort-array": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-2.0.0.tgz",
+      "integrity": "sha1-OKnG2if9fRR7QuYFVPKBGHtN9HI=",
+      "dev": true,
+      "requires": {
+        "array-back": "1.0.4",
+        "object-get": "2.1.0",
+        "typical": "2.6.1"
+      },
+      "dependencies": {
+        "array-back": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz",
+          "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=",
+          "dev": true,
+          "requires": {
+            "typical": "2.6.1"
+          }
+        }
+      }
+    },
+    "source-map": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+      "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+      "dev": true,
+      "requires": {
+        "amdefine": "1.0.1"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "stream-connect": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz",
+      "integrity": "sha1-GLyB8u2zW4tdmoAJIAqYUxRCipc=",
+      "dev": true,
+      "requires": {
+        "array-back": "1.0.4"
+      },
+      "dependencies": {
+        "array-back": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz",
+          "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=",
+          "dev": true,
+          "requires": {
+            "typical": "2.6.1"
+          }
+        }
+      }
+    },
+    "stream-via": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/stream-via/-/stream-via-1.0.4.tgz",
+      "integrity": "sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==",
+      "dev": true
+    },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "2.0.0",
+        "strip-ansi": "4.0.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "3.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        }
+      }
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true
+    },
+    "table": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
+      "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
+      "dev": true,
+      "requires": {
+        "ajv": "5.5.2",
+        "ajv-keywords": "2.1.1",
+        "chalk": "2.4.1",
+        "lodash": "4.17.10",
+        "slice-ansi": "1.0.0",
+        "string-width": "2.1.1"
+      }
+    },
+    "table-layout": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.4.tgz",
+      "integrity": "sha512-uNaR3SRMJwfdp9OUr36eyEi6LLsbcTqTO/hfTsNviKsNeyMBPICJCC7QXRF3+07bAP6FRwA8rczJPBqXDc0CkQ==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "deep-extend": "0.6.0",
+        "lodash.padend": "4.6.1",
+        "typical": "2.6.1",
+        "wordwrapjs": "3.0.0"
+      }
+    },
+    "taffydb": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
+      "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=",
+      "dev": true
+    },
+    "temp-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/temp-path/-/temp-path-1.0.0.tgz",
+      "integrity": "sha1-JLFUOXOrRCiW2a02fdnL2/r+kYs=",
+      "dev": true
+    },
+    "test-value": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz",
+      "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==",
+      "dev": true,
+      "requires": {
+        "array-back": "2.0.0",
+        "typical": "2.6.1"
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "requires": {
+        "os-tmpdir": "1.0.2"
+      }
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "1.1.2"
+      }
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "typical": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz",
+      "integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=",
+      "dev": true
+    },
+    "uglify-js": {
+      "version": "2.8.29",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+      "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "source-map": "0.5.7",
+        "uglify-to-browserify": "1.0.2",
+        "yargs": "3.10.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "uglify-to-browserify": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+      "dev": true,
+      "optional": true
+    },
+    "underscore": {
+      "version": "1.8.3",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
+      "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
+      "dev": true
+    },
+    "underscore-contrib": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz",
+      "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=",
+      "dev": true,
+      "requires": {
+        "underscore": "1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+          "dev": true
+        }
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "walk-back": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-3.0.0.tgz",
+      "integrity": "sha1-I1h4ejXakQMtrV6S+AsSNw2HlcU=",
+      "dev": true
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "requires": {
+        "isexe": "2.0.0"
+      }
+    },
+    "window-size": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+      "dev": true,
+      "optional": true
+    },
+    "wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
+    },
+    "wordwrapjs": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz",
+      "integrity": "sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==",
+      "dev": true,
+      "requires": {
+        "reduce-flatten": "1.0.1",
+        "typical": "2.6.1"
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "write": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true,
+      "requires": {
+        "mkdirp": "0.5.1"
+      }
+    },
+    "xmlcreate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz",
+      "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=",
+      "dev": true
+    },
+    "yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+      "dev": true
+    },
+    "yargs": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+      "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "camelcase": "1.2.1",
+        "cliui": "2.1.0",
+        "decamelize": "1.2.0",
+        "window-size": "0.1.0"
+      }
+    }
+  }
+}
index 908aa05c0958be1fdc2bee001095be7381cb3659..0a955d0545b57af708c17a9e2b2861d4b0403870 100644 (file)
@@ -1,10 +1,13 @@
 {
   "name": "tomato-sauce",
   "version": "1.0.0",
-  "description": "\"Telnet based drawing functions and renderers\"",
+  "description": "Telnet based drawing functions and renderers",
   "main": "lib/tomato_sauce.js",
   "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "document": "jsdoc2md -f 'lib/**/*.js' > doc/README.md",
+    "lint": "eslint lib bin",
+    "test": "I'm really really sorry! && exit 1",
+    "start": "bin/tomato_sauce.js"
   },
   "repository": {
     "type": "git",
   "homepage": "https://github.com/rbdr/tomato-sauce#readme",
   "dependencies": {
     "getenv": "^0.6.0"
+  },
+  "devDependencies": {
+    "eslint": "^4.19.1",
+    "eslint-config-hapi": "^11.0.0",
+    "eslint-plugin-hapi": "^4.1.0",
+    "jsdoc": "^3.5.5",
+    "jsdoc-to-markdown": "^4.0.1"
   }
 }