Index: frontend/node_modules/asynckit/LICENSE
===================================================================
--- frontend/node_modules/asynckit/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Alex Indigo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
Index: frontend/node_modules/asynckit/README.md
===================================================================
--- frontend/node_modules/asynckit/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,233 @@
+# asynckit [![NPM Module](https://img.shields.io/npm/v/asynckit.svg?style=flat)](https://www.npmjs.com/package/asynckit)
+
+Minimal async jobs utility library, with streams support.
+
+[![PhantomJS Build](https://img.shields.io/travis/alexindigo/asynckit/v0.4.0.svg?label=browser&style=flat)](https://travis-ci.org/alexindigo/asynckit)
+[![Linux Build](https://img.shields.io/travis/alexindigo/asynckit/v0.4.0.svg?label=linux:0.12-6.x&style=flat)](https://travis-ci.org/alexindigo/asynckit)
+[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/asynckit/v0.4.0.svg?label=windows:0.12-6.x&style=flat)](https://ci.appveyor.com/project/alexindigo/asynckit)
+
+[![Coverage Status](https://img.shields.io/coveralls/alexindigo/asynckit/v0.4.0.svg?label=code+coverage&style=flat)](https://coveralls.io/github/alexindigo/asynckit?branch=master)
+[![Dependency Status](https://img.shields.io/david/alexindigo/asynckit/v0.4.0.svg?style=flat)](https://david-dm.org/alexindigo/asynckit)
+[![bitHound Overall Score](https://www.bithound.io/github/alexindigo/asynckit/badges/score.svg)](https://www.bithound.io/github/alexindigo/asynckit)
+
+<!-- [![Readme](https://img.shields.io/badge/readme-tested-brightgreen.svg?style=flat)](https://www.npmjs.com/package/reamde) -->
+
+AsyncKit provides harness for `parallel` and `serial` iterators over list of items represented by arrays or objects.
+Optionally it accepts abort function (should be synchronously return by iterator for each item), and terminates left over jobs upon an error event. For specific iteration order built-in (`ascending` and `descending`) and custom sort helpers also supported, via `asynckit.serialOrdered` method.
+
+It ensures async operations to keep behavior more stable and prevent `Maximum call stack size exceeded` errors, from sync iterators.
+
+| compression        |     size |
+| :----------------- | -------: |
+| asynckit.js        | 12.34 kB |
+| asynckit.min.js    |  4.11 kB |
+| asynckit.min.js.gz |  1.47 kB |
+
+
+## Install
+
+```sh
+$ npm install --save asynckit
+```
+
+## Examples
+
+### Parallel Jobs
+
+Runs iterator over provided array in parallel. Stores output in the `result` array,
+on the matching positions. In unlikely event of an error from one of the jobs,
+will terminate rest of the active jobs (if abort function is provided)
+and return error along with salvaged data to the main callback function.
+
+#### Input Array
+
+```javascript
+var parallel = require('asynckit').parallel
+  , assert   = require('assert')
+  ;
+
+var source         = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
+  , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
+  , expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ]
+  , target         = []
+  ;
+
+parallel(source, asyncJob, function(err, result)
+{
+  assert.deepEqual(result, expectedResult);
+  assert.deepEqual(target, expectedTarget);
+});
+
+// async job accepts one element from the array
+// and a callback function
+function asyncJob(item, cb)
+{
+  // different delays (in ms) per item
+  var delay = item * 25;
+
+  // pretend different jobs take different time to finish
+  // and not in consequential order
+  var timeoutId = setTimeout(function() {
+    target.push(item);
+    cb(null, item * 2);
+  }, delay);
+
+  // allow to cancel "leftover" jobs upon error
+  // return function, invoking of which will abort this job
+  return clearTimeout.bind(null, timeoutId);
+}
+```
+
+More examples could be found in [test/test-parallel-array.js](test/test-parallel-array.js).
+
+#### Input Object
+
+Also it supports named jobs, listed via object.
+
+```javascript
+var parallel = require('asynckit/parallel')
+  , assert   = require('assert')
+  ;
+
+var source         = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 }
+  , expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 }
+  , expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ]
+  , expectedKeys   = [ 'first', 'one', 'two', 'four', 'eight', 'sixteen', 'thirtyTwo', 'sixtyFour' ]
+  , target         = []
+  , keys           = []
+  ;
+
+parallel(source, asyncJob, function(err, result)
+{
+  assert.deepEqual(result, expectedResult);
+  assert.deepEqual(target, expectedTarget);
+  assert.deepEqual(keys, expectedKeys);
+});
+
+// supports full value, key, callback (shortcut) interface
+function asyncJob(item, key, cb)
+{
+  // different delays (in ms) per item
+  var delay = item * 25;
+
+  // pretend different jobs take different time to finish
+  // and not in consequential order
+  var timeoutId = setTimeout(function() {
+    keys.push(key);
+    target.push(item);
+    cb(null, item * 2);
+  }, delay);
+
+  // allow to cancel "leftover" jobs upon error
+  // return function, invoking of which will abort this job
+  return clearTimeout.bind(null, timeoutId);
+}
+```
+
+More examples could be found in [test/test-parallel-object.js](test/test-parallel-object.js).
+
+### Serial Jobs
+
+Runs iterator over provided array sequentially. Stores output in the `result` array,
+on the matching positions. In unlikely event of an error from one of the jobs,
+will not proceed to the rest of the items in the list
+and return error along with salvaged data to the main callback function.
+
+#### Input Array
+
+```javascript
+var serial = require('asynckit/serial')
+  , assert = require('assert')
+  ;
+
+var source         = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
+  , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
+  , expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ]
+  , target         = []
+  ;
+
+serial(source, asyncJob, function(err, result)
+{
+  assert.deepEqual(result, expectedResult);
+  assert.deepEqual(target, expectedTarget);
+});
+
+// extended interface (item, key, callback)
+// also supported for arrays
+function asyncJob(item, key, cb)
+{
+  target.push(key);
+
+  // it will be automatically made async
+  // even it iterator "returns" in the same event loop
+  cb(null, item * 2);
+}
+```
+
+More examples could be found in [test/test-serial-array.js](test/test-serial-array.js).
+
+#### Input Object
+
+Also it supports named jobs, listed via object.
+
+```javascript
+var serial = require('asynckit').serial
+  , assert = require('assert')
+  ;
+
+var source         = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
+  , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
+  , expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ]
+  , target         = []
+  ;
+
+var source         = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 }
+  , expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 }
+  , expectedTarget = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
+  , target         = []
+  ;
+
+
+serial(source, asyncJob, function(err, result)
+{
+  assert.deepEqual(result, expectedResult);
+  assert.deepEqual(target, expectedTarget);
+});
+
+// shortcut interface (item, callback)
+// works for object as well as for the arrays
+function asyncJob(item, cb)
+{
+  target.push(item);
+
+  // it will be automatically made async
+  // even it iterator "returns" in the same event loop
+  cb(null, item * 2);
+}
+```
+
+More examples could be found in [test/test-serial-object.js](test/test-serial-object.js).
+
+_Note: Since _object_ is an _unordered_ collection of properties,
+it may produce unexpected results with sequential iterations.
+Whenever order of the jobs' execution is important please use `serialOrdered` method._
+
+### Ordered Serial Iterations
+
+TBD
+
+For example [compare-property](compare-property) package.
+
+### Streaming interface
+
+TBD
+
+## Want to Know More?
+
+More examples can be found in [test folder](test/).
+
+Or open an [issue](https://github.com/alexindigo/asynckit/issues) with questions and/or suggestions.
+
+## License
+
+AsyncKit is licensed under the MIT license.
Index: frontend/node_modules/asynckit/bench.js
===================================================================
--- frontend/node_modules/asynckit/bench.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/bench.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,76 @@
+/* eslint no-console: "off" */
+
+var asynckit = require('./')
+  , async    = require('async')
+  , assert   = require('assert')
+  , expected = 0
+  ;
+
+var Benchmark = require('benchmark');
+var suite = new Benchmark.Suite;
+
+var source = [];
+for (var z = 1; z < 100; z++)
+{
+  source.push(z);
+  expected += z;
+}
+
+suite
+// add tests
+
+.add('async.map', function(deferred)
+{
+  var total = 0;
+
+  async.map(source,
+  function(i, cb)
+  {
+    setImmediate(function()
+    {
+      total += i;
+      cb(null, total);
+    });
+  },
+  function(err, result)
+  {
+    assert.ifError(err);
+    assert.equal(result[result.length - 1], expected);
+    deferred.resolve();
+  });
+}, {'defer': true})
+
+
+.add('asynckit.parallel', function(deferred)
+{
+  var total = 0;
+
+  asynckit.parallel(source,
+  function(i, cb)
+  {
+    setImmediate(function()
+    {
+      total += i;
+      cb(null, total);
+    });
+  },
+  function(err, result)
+  {
+    assert.ifError(err);
+    assert.equal(result[result.length - 1], expected);
+    deferred.resolve();
+  });
+}, {'defer': true})
+
+
+// add listeners
+.on('cycle', function(ev)
+{
+  console.log(String(ev.target));
+})
+.on('complete', function()
+{
+  console.log('Fastest is ' + this.filter('fastest').map('name'));
+})
+// run async
+.run({ 'async': true });
Index: frontend/node_modules/asynckit/index.js
===================================================================
--- frontend/node_modules/asynckit/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,6 @@
+module.exports =
+{
+  parallel      : require('./parallel.js'),
+  serial        : require('./serial.js'),
+  serialOrdered : require('./serialOrdered.js')
+};
Index: frontend/node_modules/asynckit/lib/abort.js
===================================================================
--- frontend/node_modules/asynckit/lib/abort.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/abort.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+// API
+module.exports = abort;
+
+/**
+ * Aborts leftover active jobs
+ *
+ * @param {object} state - current state object
+ */
+function abort(state)
+{
+  Object.keys(state.jobs).forEach(clean.bind(state));
+
+  // reset leftover jobs
+  state.jobs = {};
+}
+
+/**
+ * Cleans up leftover job by invoking abort function for the provided job id
+ *
+ * @this  state
+ * @param {string|number} key - job id to abort
+ */
+function clean(key)
+{
+  if (typeof this.jobs[key] == 'function')
+  {
+    this.jobs[key]();
+  }
+}
Index: frontend/node_modules/asynckit/lib/async.js
===================================================================
--- frontend/node_modules/asynckit/lib/async.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/async.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,34 @@
+var defer = require('./defer.js');
+
+// API
+module.exports = async;
+
+/**
+ * Runs provided callback asynchronously
+ * even if callback itself is not
+ *
+ * @param   {function} callback - callback to invoke
+ * @returns {function} - augmented callback
+ */
+function async(callback)
+{
+  var isAsync = false;
+
+  // check if async happened
+  defer(function() { isAsync = true; });
+
+  return function async_callback(err, result)
+  {
+    if (isAsync)
+    {
+      callback(err, result);
+    }
+    else
+    {
+      defer(function nextTick_callback()
+      {
+        callback(err, result);
+      });
+    }
+  };
+}
Index: frontend/node_modules/asynckit/lib/defer.js
===================================================================
--- frontend/node_modules/asynckit/lib/defer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/defer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+module.exports = defer;
+
+/**
+ * Runs provided function on next iteration of the event loop
+ *
+ * @param {function} fn - function to run
+ */
+function defer(fn)
+{
+  var nextTick = typeof setImmediate == 'function'
+    ? setImmediate
+    : (
+      typeof process == 'object' && typeof process.nextTick == 'function'
+      ? process.nextTick
+      : null
+    );
+
+  if (nextTick)
+  {
+    nextTick(fn);
+  }
+  else
+  {
+    setTimeout(fn, 0);
+  }
+}
Index: frontend/node_modules/asynckit/lib/iterate.js
===================================================================
--- frontend/node_modules/asynckit/lib/iterate.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/iterate.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,75 @@
+var async = require('./async.js')
+  , abort = require('./abort.js')
+  ;
+
+// API
+module.exports = iterate;
+
+/**
+ * Iterates over each job object
+ *
+ * @param {array|object} list - array or object (named list) to iterate over
+ * @param {function} iterator - iterator to run
+ * @param {object} state - current job status
+ * @param {function} callback - invoked when all elements processed
+ */
+function iterate(list, iterator, state, callback)
+{
+  // store current index
+  var key = state['keyedList'] ? state['keyedList'][state.index] : state.index;
+
+  state.jobs[key] = runJob(iterator, key, list[key], function(error, output)
+  {
+    // don't repeat yourself
+    // skip secondary callbacks
+    if (!(key in state.jobs))
+    {
+      return;
+    }
+
+    // clean up jobs
+    delete state.jobs[key];
+
+    if (error)
+    {
+      // don't process rest of the results
+      // stop still active jobs
+      // and reset the list
+      abort(state);
+    }
+    else
+    {
+      state.results[key] = output;
+    }
+
+    // return salvaged results
+    callback(error, state.results);
+  });
+}
+
+/**
+ * Runs iterator over provided job element
+ *
+ * @param   {function} iterator - iterator to invoke
+ * @param   {string|number} key - key/index of the element in the list of jobs
+ * @param   {mixed} item - job description
+ * @param   {function} callback - invoked after iterator is done with the job
+ * @returns {function|mixed} - job abort function or something else
+ */
+function runJob(iterator, key, item, callback)
+{
+  var aborter;
+
+  // allow shortcut if iterator expects only two arguments
+  if (iterator.length == 2)
+  {
+    aborter = iterator(item, async(callback));
+  }
+  // otherwise go with full three arguments
+  else
+  {
+    aborter = iterator(item, key, async(callback));
+  }
+
+  return aborter;
+}
Index: frontend/node_modules/asynckit/lib/readable_asynckit.js
===================================================================
--- frontend/node_modules/asynckit/lib/readable_asynckit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/readable_asynckit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,91 @@
+var streamify = require('./streamify.js')
+  , defer     = require('./defer.js')
+  ;
+
+// API
+module.exports = ReadableAsyncKit;
+
+/**
+ * Base constructor for all streams
+ * used to hold properties/methods
+ */
+function ReadableAsyncKit()
+{
+  ReadableAsyncKit.super_.apply(this, arguments);
+
+  // list of active jobs
+  this.jobs = {};
+
+  // add stream methods
+  this.destroy = destroy;
+  this._start  = _start;
+  this._read   = _read;
+}
+
+/**
+ * Destroys readable stream,
+ * by aborting outstanding jobs
+ *
+ * @returns {void}
+ */
+function destroy()
+{
+  if (this.destroyed)
+  {
+    return;
+  }
+
+  this.destroyed = true;
+
+  if (typeof this.terminator == 'function')
+  {
+    this.terminator();
+  }
+}
+
+/**
+ * Starts provided jobs in async manner
+ *
+ * @private
+ */
+function _start()
+{
+  // first argument – runner function
+  var runner = arguments[0]
+    // take away first argument
+    , args   = Array.prototype.slice.call(arguments, 1)
+      // second argument - input data
+    , input  = args[0]
+      // last argument - result callback
+    , endCb  = streamify.callback.call(this, args[args.length - 1])
+    ;
+
+  args[args.length - 1] = endCb;
+  // third argument - iterator
+  args[1] = streamify.iterator.call(this, args[1]);
+
+  // allow time for proper setup
+  defer(function()
+  {
+    if (!this.destroyed)
+    {
+      this.terminator = runner.apply(null, args);
+    }
+    else
+    {
+      endCb(null, Array.isArray(input) ? [] : {});
+    }
+  }.bind(this));
+}
+
+
+/**
+ * Implement _read to comply with Readable streams
+ * Doesn't really make sense for flowing object mode
+ *
+ * @private
+ */
+function _read()
+{
+
+}
Index: frontend/node_modules/asynckit/lib/readable_parallel.js
===================================================================
--- frontend/node_modules/asynckit/lib/readable_parallel.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/readable_parallel.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+var parallel = require('../parallel.js');
+
+// API
+module.exports = ReadableParallel;
+
+/**
+ * Streaming wrapper to `asynckit.parallel`
+ *
+ * @param   {array|object} list - array or object (named list) to iterate over
+ * @param   {function} iterator - iterator to run
+ * @param   {function} callback - invoked when all elements processed
+ * @returns {stream.Readable#}
+ */
+function ReadableParallel(list, iterator, callback)
+{
+  if (!(this instanceof ReadableParallel))
+  {
+    return new ReadableParallel(list, iterator, callback);
+  }
+
+  // turn on object mode
+  ReadableParallel.super_.call(this, {objectMode: true});
+
+  this._start(parallel, list, iterator, callback);
+}
Index: frontend/node_modules/asynckit/lib/readable_serial.js
===================================================================
--- frontend/node_modules/asynckit/lib/readable_serial.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/readable_serial.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+var serial = require('../serial.js');
+
+// API
+module.exports = ReadableSerial;
+
+/**
+ * Streaming wrapper to `asynckit.serial`
+ *
+ * @param   {array|object} list - array or object (named list) to iterate over
+ * @param   {function} iterator - iterator to run
+ * @param   {function} callback - invoked when all elements processed
+ * @returns {stream.Readable#}
+ */
+function ReadableSerial(list, iterator, callback)
+{
+  if (!(this instanceof ReadableSerial))
+  {
+    return new ReadableSerial(list, iterator, callback);
+  }
+
+  // turn on object mode
+  ReadableSerial.super_.call(this, {objectMode: true});
+
+  this._start(serial, list, iterator, callback);
+}
Index: frontend/node_modules/asynckit/lib/readable_serial_ordered.js
===================================================================
--- frontend/node_modules/asynckit/lib/readable_serial_ordered.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/readable_serial_ordered.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+var serialOrdered = require('../serialOrdered.js');
+
+// API
+module.exports = ReadableSerialOrdered;
+// expose sort helpers
+module.exports.ascending  = serialOrdered.ascending;
+module.exports.descending = serialOrdered.descending;
+
+/**
+ * Streaming wrapper to `asynckit.serialOrdered`
+ *
+ * @param   {array|object} list - array or object (named list) to iterate over
+ * @param   {function} iterator - iterator to run
+ * @param   {function} sortMethod - custom sort function
+ * @param   {function} callback - invoked when all elements processed
+ * @returns {stream.Readable#}
+ */
+function ReadableSerialOrdered(list, iterator, sortMethod, callback)
+{
+  if (!(this instanceof ReadableSerialOrdered))
+  {
+    return new ReadableSerialOrdered(list, iterator, sortMethod, callback);
+  }
+
+  // turn on object mode
+  ReadableSerialOrdered.super_.call(this, {objectMode: true});
+
+  this._start(serialOrdered, list, iterator, sortMethod, callback);
+}
Index: frontend/node_modules/asynckit/lib/state.js
===================================================================
--- frontend/node_modules/asynckit/lib/state.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/state.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+// API
+module.exports = state;
+
+/**
+ * Creates initial state object
+ * for iteration over list
+ *
+ * @param   {array|object} list - list to iterate over
+ * @param   {function|null} sortMethod - function to use for keys sort,
+ *                                     or `null` to keep them as is
+ * @returns {object} - initial state object
+ */
+function state(list, sortMethod)
+{
+  var isNamedList = !Array.isArray(list)
+    , initState =
+    {
+      index    : 0,
+      keyedList: isNamedList || sortMethod ? Object.keys(list) : null,
+      jobs     : {},
+      results  : isNamedList ? {} : [],
+      size     : isNamedList ? Object.keys(list).length : list.length
+    }
+    ;
+
+  if (sortMethod)
+  {
+    // sort array keys based on it's values
+    // sort object's keys just on own merit
+    initState.keyedList.sort(isNamedList ? sortMethod : function(a, b)
+    {
+      return sortMethod(list[a], list[b]);
+    });
+  }
+
+  return initState;
+}
Index: frontend/node_modules/asynckit/lib/streamify.js
===================================================================
--- frontend/node_modules/asynckit/lib/streamify.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/streamify.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,141 @@
+var async = require('./async.js');
+
+// API
+module.exports = {
+  iterator: wrapIterator,
+  callback: wrapCallback
+};
+
+/**
+ * Wraps iterators with long signature
+ *
+ * @this    ReadableAsyncKit#
+ * @param   {function} iterator - function to wrap
+ * @returns {function} - wrapped function
+ */
+function wrapIterator(iterator)
+{
+  var stream = this;
+
+  return function(item, key, cb)
+  {
+    var aborter
+      , wrappedCb = async(wrapIteratorCallback.call(stream, cb, key))
+      ;
+
+    stream.jobs[key] = wrappedCb;
+
+    // it's either shortcut (item, cb)
+    if (iterator.length == 2)
+    {
+      aborter = iterator(item, wrappedCb);
+    }
+    // or long format (item, key, cb)
+    else
+    {
+      aborter = iterator(item, key, wrappedCb);
+    }
+
+    return aborter;
+  };
+}
+
+/**
+ * Wraps provided callback function
+ * allowing to execute snitch function before
+ * real callback
+ *
+ * @this    ReadableAsyncKit#
+ * @param   {function} callback - function to wrap
+ * @returns {function} - wrapped function
+ */
+function wrapCallback(callback)
+{
+  var stream = this;
+
+  var wrapped = function(error, result)
+  {
+    return finisher.call(stream, error, result, callback);
+  };
+
+  return wrapped;
+}
+
+/**
+ * Wraps provided iterator callback function
+ * makes sure snitch only called once,
+ * but passes secondary calls to the original callback
+ *
+ * @this    ReadableAsyncKit#
+ * @param   {function} callback - callback to wrap
+ * @param   {number|string} key - iteration key
+ * @returns {function} wrapped callback
+ */
+function wrapIteratorCallback(callback, key)
+{
+  var stream = this;
+
+  return function(error, output)
+  {
+    // don't repeat yourself
+    if (!(key in stream.jobs))
+    {
+      callback(error, output);
+      return;
+    }
+
+    // clean up jobs
+    delete stream.jobs[key];
+
+    return streamer.call(stream, error, {key: key, value: output}, callback);
+  };
+}
+
+/**
+ * Stream wrapper for iterator callback
+ *
+ * @this  ReadableAsyncKit#
+ * @param {mixed} error - error response
+ * @param {mixed} output - iterator output
+ * @param {function} callback - callback that expects iterator results
+ */
+function streamer(error, output, callback)
+{
+  if (error && !this.error)
+  {
+    this.error = error;
+    this.pause();
+    this.emit('error', error);
+    // send back value only, as expected
+    callback(error, output && output.value);
+    return;
+  }
+
+  // stream stuff
+  this.push(output);
+
+  // back to original track
+  // send back value only, as expected
+  callback(error, output && output.value);
+}
+
+/**
+ * Stream wrapper for finishing callback
+ *
+ * @this  ReadableAsyncKit#
+ * @param {mixed} error - error response
+ * @param {mixed} output - iterator output
+ * @param {function} callback - callback that expects final results
+ */
+function finisher(error, output, callback)
+{
+  // signal end of the stream
+  // only for successfully finished streams
+  if (!error)
+  {
+    this.push(null);
+  }
+
+  // back to original track
+  callback(error, output);
+}
Index: frontend/node_modules/asynckit/lib/terminator.js
===================================================================
--- frontend/node_modules/asynckit/lib/terminator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/lib/terminator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+var abort = require('./abort.js')
+  , async = require('./async.js')
+  ;
+
+// API
+module.exports = terminator;
+
+/**
+ * Terminates jobs in the attached state context
+ *
+ * @this  AsyncKitState#
+ * @param {function} callback - final callback to invoke after termination
+ */
+function terminator(callback)
+{
+  if (!Object.keys(this.jobs).length)
+  {
+    return;
+  }
+
+  // fast forward iteration index
+  this.index = this.size;
+
+  // abort jobs
+  abort(this);
+
+  // send back results we have so far
+  async(callback)(null, this.results);
+}
Index: frontend/node_modules/asynckit/package.json
===================================================================
--- frontend/node_modules/asynckit/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,63 @@
+{
+  "name": "asynckit",
+  "version": "0.4.0",
+  "description": "Minimal async jobs utility library, with streams support",
+  "main": "index.js",
+  "scripts": {
+    "clean": "rimraf coverage",
+    "lint": "eslint *.js lib/*.js test/*.js",
+    "test": "istanbul cover --reporter=json tape -- 'test/test-*.js' | tap-spec",
+    "win-test": "tape test/test-*.js",
+    "browser": "browserify -t browserify-istanbul test/lib/browserify_adjustment.js test/test-*.js | obake --coverage | tap-spec",
+    "report": "istanbul report",
+    "size": "browserify index.js | size-table asynckit",
+    "debug": "tape test/test-*.js"
+  },
+  "pre-commit": [
+    "clean",
+    "lint",
+    "test",
+    "browser",
+    "report",
+    "size"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/alexindigo/asynckit.git"
+  },
+  "keywords": [
+    "async",
+    "jobs",
+    "parallel",
+    "serial",
+    "iterator",
+    "array",
+    "object",
+    "stream",
+    "destroy",
+    "terminate",
+    "abort"
+  ],
+  "author": "Alex Indigo <iam@alexindigo.com>",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/alexindigo/asynckit/issues"
+  },
+  "homepage": "https://github.com/alexindigo/asynckit#readme",
+  "devDependencies": {
+    "browserify": "^13.0.0",
+    "browserify-istanbul": "^2.0.0",
+    "coveralls": "^2.11.9",
+    "eslint": "^2.9.0",
+    "istanbul": "^0.4.3",
+    "obake": "^0.1.2",
+    "phantomjs-prebuilt": "^2.1.7",
+    "pre-commit": "^1.1.3",
+    "reamde": "^1.1.0",
+    "rimraf": "^2.5.2",
+    "size-table": "^0.2.0",
+    "tap-spec": "^4.1.1",
+    "tape": "^4.5.1"
+  },
+  "dependencies": {}
+}
Index: frontend/node_modules/asynckit/parallel.js
===================================================================
--- frontend/node_modules/asynckit/parallel.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/parallel.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+var iterate    = require('./lib/iterate.js')
+  , initState  = require('./lib/state.js')
+  , terminator = require('./lib/terminator.js')
+  ;
+
+// Public API
+module.exports = parallel;
+
+/**
+ * Runs iterator over provided array elements in parallel
+ *
+ * @param   {array|object} list - array or object (named list) to iterate over
+ * @param   {function} iterator - iterator to run
+ * @param   {function} callback - invoked when all elements processed
+ * @returns {function} - jobs terminator
+ */
+function parallel(list, iterator, callback)
+{
+  var state = initState(list);
+
+  while (state.index < (state['keyedList'] || list).length)
+  {
+    iterate(list, iterator, state, function(error, result)
+    {
+      if (error)
+      {
+        callback(error, result);
+        return;
+      }
+
+      // looks like it's the last one
+      if (Object.keys(state.jobs).length === 0)
+      {
+        callback(null, state.results);
+        return;
+      }
+    });
+
+    state.index++;
+  }
+
+  return terminator.bind(state, callback);
+}
Index: frontend/node_modules/asynckit/serial.js
===================================================================
--- frontend/node_modules/asynckit/serial.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/serial.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+var serialOrdered = require('./serialOrdered.js');
+
+// Public API
+module.exports = serial;
+
+/**
+ * Runs iterator over provided array elements in series
+ *
+ * @param   {array|object} list - array or object (named list) to iterate over
+ * @param   {function} iterator - iterator to run
+ * @param   {function} callback - invoked when all elements processed
+ * @returns {function} - jobs terminator
+ */
+function serial(list, iterator, callback)
+{
+  return serialOrdered(list, iterator, null, callback);
+}
Index: frontend/node_modules/asynckit/serialOrdered.js
===================================================================
--- frontend/node_modules/asynckit/serialOrdered.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/serialOrdered.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,75 @@
+var iterate    = require('./lib/iterate.js')
+  , initState  = require('./lib/state.js')
+  , terminator = require('./lib/terminator.js')
+  ;
+
+// Public API
+module.exports = serialOrdered;
+// sorting helpers
+module.exports.ascending  = ascending;
+module.exports.descending = descending;
+
+/**
+ * Runs iterator over provided sorted array elements in series
+ *
+ * @param   {array|object} list - array or object (named list) to iterate over
+ * @param   {function} iterator - iterator to run
+ * @param   {function} sortMethod - custom sort function
+ * @param   {function} callback - invoked when all elements processed
+ * @returns {function} - jobs terminator
+ */
+function serialOrdered(list, iterator, sortMethod, callback)
+{
+  var state = initState(list, sortMethod);
+
+  iterate(list, iterator, state, function iteratorHandler(error, result)
+  {
+    if (error)
+    {
+      callback(error, result);
+      return;
+    }
+
+    state.index++;
+
+    // are we there yet?
+    if (state.index < (state['keyedList'] || list).length)
+    {
+      iterate(list, iterator, state, iteratorHandler);
+      return;
+    }
+
+    // done here
+    callback(null, state.results);
+  });
+
+  return terminator.bind(state, callback);
+}
+
+/*
+ * -- Sort methods
+ */
+
+/**
+ * sort helper to sort array elements in ascending order
+ *
+ * @param   {mixed} a - an item to compare
+ * @param   {mixed} b - an item to compare
+ * @returns {number} - comparison result
+ */
+function ascending(a, b)
+{
+  return a < b ? -1 : a > b ? 1 : 0;
+}
+
+/**
+ * sort helper to sort array elements in descending order
+ *
+ * @param   {mixed} a - an item to compare
+ * @param   {mixed} b - an item to compare
+ * @returns {number} - comparison result
+ */
+function descending(a, b)
+{
+  return -1 * ascending(a, b);
+}
Index: frontend/node_modules/asynckit/stream.js
===================================================================
--- frontend/node_modules/asynckit/stream.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/asynckit/stream.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+var inherits              = require('util').inherits
+  , Readable              = require('stream').Readable
+  , ReadableAsyncKit      = require('./lib/readable_asynckit.js')
+  , ReadableParallel      = require('./lib/readable_parallel.js')
+  , ReadableSerial        = require('./lib/readable_serial.js')
+  , ReadableSerialOrdered = require('./lib/readable_serial_ordered.js')
+  ;
+
+// API
+module.exports =
+{
+  parallel      : ReadableParallel,
+  serial        : ReadableSerial,
+  serialOrdered : ReadableSerialOrdered, 
+};
+
+inherits(ReadableAsyncKit, Readable);
+
+inherits(ReadableParallel, ReadableAsyncKit);
+inherits(ReadableSerial, ReadableAsyncKit);
+inherits(ReadableSerialOrdered, ReadableAsyncKit);
