Index: frontend/node_modules/select-hose/.jscsrc
===================================================================
--- frontend/node_modules/select-hose/.jscsrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/.jscsrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+{
+  "disallowKeywordsOnNewLine": [ "else" ],
+  "disallowMixedSpacesAndTabs": true,
+  "disallowMultipleLineStrings": true,
+  "disallowMultipleVarDecl": true,
+  "disallowNewlineBeforeBlockStatements": true,
+  "disallowQuotedKeysInObjects": true,
+  "disallowSpaceAfterObjectKeys": true,
+  "disallowSpaceAfterPrefixUnaryOperators": true,
+  "disallowSpaceBeforePostfixUnaryOperators": true,
+  "disallowSpacesInCallExpression": true,
+  "disallowTrailingComma": true,
+  "disallowTrailingWhitespace": true,
+  "disallowYodaConditions": true,
+
+  "requireCommaBeforeLineBreak": true,
+  "requireOperatorBeforeLineBreak": true,
+  "requireSpaceAfterBinaryOperators": true,
+  "requireSpaceAfterKeywords": [ "if", "for", "while", "else", "try", "catch" ],
+  "requireSpaceAfterLineComment": true,
+  "requireSpaceBeforeBinaryOperators": true,
+  "requireSpaceBeforeBlockStatements": true,
+  "requireSpaceBeforeKeywords": [ "else", "catch" ],
+  "requireSpaceBeforeObjectValues": true,
+  "requireSpaceBetweenArguments": true,
+  "requireSpacesInAnonymousFunctionExpression": {
+    "beforeOpeningCurlyBrace": true
+  },
+  "requireSpacesInFunctionDeclaration": {
+    "beforeOpeningCurlyBrace": true
+  },
+  "requireSpacesInFunctionExpression": {
+    "beforeOpeningCurlyBrace": true
+  },
+  "requireSpacesInConditionalExpression": true,
+  "requireSpacesInForStatement": true,
+  "requireSpacesInsideArrayBrackets": "all",
+  "requireSpacesInsideObjectBrackets": "all",
+  "requireDotNotation": true,
+
+  "maximumLineLength": 80,
+  "validateIndentation": 2,
+  "validateLineBreaks": "LF",
+  "validateParameterSeparator": ", ",
+  "validateQuoteMarks": "'"
+}
Index: frontend/node_modules/select-hose/.jshintrc
===================================================================
--- frontend/node_modules/select-hose/.jshintrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/.jshintrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,89 @@
+{
+    // JSHint Default Configuration File (as on JSHint website)
+    // See http://jshint.com/docs/ for more details
+
+    "maxerr"        : 50,       // {int} Maximum error before stopping
+
+    // Enforcing
+    "bitwise"       : false,     // true: Prohibit bitwise operators (&, |, ^, etc.)
+    "camelcase"     : false,     // true: Identifiers must be in camelCase
+    "curly"         : false,     // true: Require {} for every new block or scope
+    "eqeqeq"        : true,     // true: Require triple equals (===) for comparison
+    "forin"         : true,     // true: Require filtering for..in loops with obj.hasOwnProperty()
+    "freeze"        : true,     // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
+    "immed"         : false,    // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
+    "indent"        : 2,        // {int} Number of spaces to use for indentation
+    "latedef"       : true,     // true: Require variables/functions to be defined before being used
+    "newcap"        : true,     // true: Require capitalization of all constructor functions e.g. `new F()`
+    "noarg"         : true,     // true: Prohibit use of `arguments.caller` and `arguments.callee`
+    "noempty"       : false,    // true: Prohibit use of empty blocks
+    "nonbsp"        : true,     // true: Prohibit "non-breaking whitespace" characters.
+    "nonew"         : false,    // true: Prohibit use of constructors for side-effects (without assignment)
+    "plusplus"      : false,    // true: Prohibit use of `++` & `--`
+    "quotmark"      : "single", // Quotation mark consistency:
+                                //   false    : do nothing (default)
+                                //   true     : ensure whatever is used is consistent
+                                //   "single" : require single quotes
+                                //   "double" : require double quotes
+    "undef"         : true,     // true: Require all non-global variables to be declared (prevents global leaks)
+    "unused"        : true,     // true: Require all defined variables be used
+    "strict"        : true,     // true: Requires all functions run in ES5 Strict Mode
+    "maxparams"     : false,    // {int} Max number of formal params allowed per function
+    "maxdepth"      : 3,        // {int} Max depth of nested blocks (within functions)
+    "maxstatements" : false,    // {int} Max number statements per function
+    "maxcomplexity" : false,    // {int} Max cyclomatic complexity per function
+    "maxlen"        : false,    // {int} Max number of characters per line
+
+    // Relaxing
+    "asi"           : false,     // true: Tolerate Automatic Semicolon Insertion (no semicolons)
+    "boss"          : false,     // true: Tolerate assignments where comparisons would be expected
+    "debug"         : false,     // true: Allow debugger statements e.g. browser breakpoints.
+    "eqnull"        : false,     // true: Tolerate use of `== null`
+    "es5"           : false,     // true: Allow ES5 syntax (ex: getters and setters)
+    "esnext"        : false,     // true: Allow ES.next (ES6) syntax (ex: `const`)
+    "moz"           : false,     // true: Allow Mozilla specific syntax (extends and overrides esnext features)
+                                 // (ex: `for each`, multiple try/catch, function expression…)
+    "evil"          : false,     // true: Tolerate use of `eval` and `new Function()`
+    "expr"          : false,     // true: Tolerate `ExpressionStatement` as Programs
+    "funcscope"     : false,     // true: Tolerate defining variables inside control statements
+    "globalstrict"  : false,     // true: Allow global "use strict" (also enables 'strict')
+    "iterator"      : false,     // true: Tolerate using the `__iterator__` property
+    "lastsemic"     : false,     // true: Tolerate omitting a semicolon for the last statement of a 1-line block
+    "laxbreak"      : false,     // true: Tolerate possibly unsafe line breakings
+    "laxcomma"      : false,     // true: Tolerate comma-first style coding
+    "loopfunc"      : false,     // true: Tolerate functions being defined in loops
+    "multistr"      : false,     // true: Tolerate multi-line strings
+    "noyield"       : false,     // true: Tolerate generator functions with no yield statement in them.
+    "notypeof"      : false,     // true: Tolerate invalid typeof operator values
+    "proto"         : false,     // true: Tolerate using the `__proto__` property
+    "scripturl"     : false,     // true: Tolerate script-targeted URLs
+    "shadow"        : true,      // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
+    "sub"           : false,     // true: Tolerate using `[]` notation when it can still be expressed in dot notation
+    "supernew"      : false,     // true: Tolerate `new function () { ... };` and `new Object;`
+    "validthis"     : false,     // true: Tolerate using this in a non-constructor function
+
+    // Environments
+    "browser"       : true,     // Web Browser (window, document, etc)
+    "browserify"    : true,     // Browserify (node.js code in the browser)
+    "couch"         : false,    // CouchDB
+    "devel"         : true,     // Development/debugging (alert, confirm, etc)
+    "dojo"          : false,    // Dojo Toolkit
+    "jasmine"       : false,    // Jasmine
+    "jquery"        : false,    // jQuery
+    "mocha"         : true,     // Mocha
+    "mootools"      : false,    // MooTools
+    "node"          : true,     // Node.js
+    "nonstandard"   : false,    // Widely adopted globals (escape, unescape, etc)
+    "prototypejs"   : false,    // Prototype and Scriptaculous
+    "qunit"         : false,    // QUnit
+    "rhino"         : false,    // Rhino
+    "shelljs"       : false,    // ShellJS
+    "worker"        : false,    // Web Workers
+    "wsh"           : false,    // Windows Scripting Host
+    "yui"           : false,    // Yahoo User Interface
+
+    // Custom Globals
+    "globals"       : {
+        "module": true
+    }        // additional predefined global variables
+}
Index: frontend/node_modules/select-hose/.npmignore
===================================================================
--- frontend/node_modules/select-hose/.npmignore	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/.npmignore	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,2 @@
+node_modules/
+npm-debug.log
Index: frontend/node_modules/select-hose/.travis.yml
===================================================================
--- frontend/node_modules/select-hose/.travis.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/.travis.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+  - "0.10"
+  - "0.12"
+  - "iojs"
Index: frontend/node_modules/select-hose/README.md
===================================================================
--- frontend/node_modules/select-hose/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+# Select Hose
+
+[![Build Status](https://secure.travis-ci.org/indutny/select-hose.png)](http://travis-ci.org/indutny/select-hose)
+[![NPM version](https://badge.fury.io/js/select-hose.svg)](http://badge.fury.io/js/select-hose)
+
+Hose the data to the handler
+
+## LICENSE
+
+This software is licensed under the MIT License.
+
+Copyright Fedor Indutny, 2015.
+
+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/select-hose/lib/hose.js
===================================================================
--- frontend/node_modules/select-hose/lib/hose.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/lib/hose.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,101 @@
+'use strict';
+
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+function Hose(socket, options, filter) {
+  EventEmitter.call(this);
+
+  if (typeof options === 'function') {
+    filter = options;
+    options = {};
+  }
+
+  this.socket = socket;
+  this.options = options;
+  this.filter = filter;
+
+  this.buffer = null;
+
+  var self = this;
+  this.listeners = {
+    error: function(err) {
+      return self.onError(err);
+    },
+    data: function(chunk) {
+      return self.onData(chunk);
+    },
+    end: function() {
+      return self.onEnd();
+    }
+  };
+
+  this.socket.on('error', this.listeners.error);
+  this.socket.on('data', this.listeners.data);
+  this.socket.on('end', this.listeners.end);
+}
+util.inherits(Hose, EventEmitter);
+module.exports = Hose;
+
+Hose.create = function create(socket, options, filter) {
+  return new Hose(socket, options, filter);
+};
+
+Hose.prototype.detach = function detach() {
+  // Stop the flow
+  this.socket.pause();
+
+  this.socket.removeListener('error', this.listeners.error);
+  this.socket.removeListener('data', this.listeners.data);
+  this.socket.removeListener('end', this.listeners.end);
+};
+
+Hose.prototype.reemit = function reemit() {
+  var buffer = this.buffer;
+  this.buffer = null;
+
+  // Modern age
+  if (this.socket.unshift) {
+    this.socket.unshift(buffer);
+    if (this.socket.listeners('data').length > 0)
+      this.socket.resume();
+    return;
+  }
+
+  // Rusty node v0.8
+  if (this.socket.ondata)
+    this.socket.ondata(buffer, 0, buffer.length);
+  this.socket.emit('data', buffer);
+  this.socket.resume();
+};
+
+Hose.prototype.onError = function onError(err) {
+  this.detach();
+  this.emit('error', err);
+};
+
+Hose.prototype.onData = function onData(chunk) {
+  if (this.buffer)
+    this.buffer = Buffer.concat([ this.buffer, chunk ]);
+  else
+    this.buffer = chunk;
+
+  var self = this;
+  this.filter(this.buffer, function(err, protocol) {
+    if (err)
+      return self.onError(err);
+
+    // No protocol selected yet
+    if (!protocol)
+      return;
+
+    self.detach();
+    self.emit('select', protocol, self.socket);
+    self.reemit();
+  });
+};
+
+Hose.prototype.onEnd = function onEnd() {
+  this.detach();
+  this.emit('error', new Error('Not enough data to recognize protocol'));
+};
Index: frontend/node_modules/select-hose/package.json
===================================================================
--- frontend/node_modules/select-hose/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+{
+  "name": "select-hose",
+  "version": "2.0.0",
+  "description": "Select protocol using first bytes of incoming data and hose stuff to the handler",
+  "main": "lib/hose.js",
+  "scripts": {
+    "test": "jscs lib/*.js test/*.js && jshint lib/*.js && mocha --reporter=spec test/*-test.js"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/indutny/select-hose.git"
+  },
+  "keywords": [
+    "hose",
+    "select",
+    "balance"
+  ],
+  "author": "Fedor Indutny <fedor@indutny.com>",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/indutny/select-hose/issues"
+  },
+  "homepage": "https://github.com/indutny/select-hose#readme",
+  "devDependencies": {
+    "handle-thing": "^1.2.0",
+    "jscs": "^1.13.1",
+    "jshint": "^2.8.0",
+    "mocha": "^2.2.5",
+    "stream-pair": "^1.0.3"
+  }
+}
Index: frontend/node_modules/select-hose/test/api-test.js
===================================================================
--- frontend/node_modules/select-hose/test/api-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/test/api-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,111 @@
+var assert = require('assert');
+var net = require('net');
+var streamPair = require('stream-pair');
+var thing = require('handle-thing');
+var Buffer = require('buffer').Buffer;
+
+var fixtures = require('./fixtures');
+
+var hose = require('../');
+
+describe('Select Hose', function() {
+  var pair;
+  var socket;
+  beforeEach(function() {
+    pair = streamPair.create();
+
+    var handle = thing.create(pair.other);
+    socket = new net.Socket({ handle: handle });
+
+    // For v0.8
+    socket.readable = true;
+    socket.writable = true;
+  });
+
+  it('should select handler using first byte', function(done) {
+    var filter = hose.create(socket, function filter(data, callback) {
+      if (data[0] === 0x80)
+        return callback(null, 'spdy');
+      else
+        return callback(null, 'http');
+    });
+
+    filter.on('select', function(protocol, socket) {
+      assert.equal(protocol, 'spdy');
+      socket.on('data', function(chunk) {
+        assert.equal(chunk.toString('hex'), '80030001');
+        done();
+      });
+    });
+
+    pair.write(new Buffer('80030001', 'hex'));
+  });
+
+  it('should select handler using two packets', function(done) {
+    var filter = hose.create(socket, function filter(data, callback) {
+      if (data.length < 2)
+        return;
+
+      if (data[0] === 0x80 && data[1] === 0x03)
+        return callback(null, 'spdy');
+      else
+        return callback(null, 'http');
+    });
+
+    filter.on('select', function(protocol, socket) {
+      assert.equal(protocol, 'spdy');
+      socket.on('data', function(chunk) {
+        assert.equal(chunk.toString('hex'), '80030001');
+        done();
+      });
+    });
+
+    pair.write(new Buffer('80', 'hex'));
+    setTimeout(function() {
+      pair.write(new Buffer('030001', 'hex'));
+    }, 20);
+  });
+
+  it('should read excessive packets', function(done) {
+    var filter = hose.create(socket, function filter(data, callback) {
+      if (data.length < 2)
+        return;
+
+      if (data[0] === 0x61 && data[1] === 0x62)
+        return callback(null, 'spdy');
+      else
+        return callback(null, 'http');
+    });
+
+    filter.on('select', function(protocol, socket) {
+      assert.equal(protocol, 'spdy');
+      fixtures.expectData(socket, 'abcd', done);
+    });
+
+    pair.write('a');
+    setTimeout(function() {
+      pair.write('b');
+      setTimeout(function() {
+        pair.end('cd');
+      }, 20);
+    }, 20);
+  });
+
+  it('should re-emit errors', function(done) {
+    var filter = hose.create(socket, function filter(data, callback) {
+      if (data.length < 2)
+        return;
+
+      if (data[0] === 0x61 && data[1] === 0x62)
+        return callback(null, 'spdy');
+      else
+        return callback(null, 'http');
+    });
+
+    filter.on('error', function(err) {
+      done();
+    });
+
+    socket.emit('error', new Error(123));
+  });
+});
Index: frontend/node_modules/select-hose/test/fixtures.js
===================================================================
--- frontend/node_modules/select-hose/test/fixtures.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/select-hose/test/fixtures.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,14 @@
+var assert = require('assert');
+
+function expectData(stream, expected, callback) {
+  var actual = '';
+
+  stream.on('data', function(chunk) {
+    actual += chunk;
+  });
+  stream.on('end', function() {
+    assert.equal(actual, expected);
+    callback();
+  });
+}
+exports.expectData = expectData;
