diff --git a/lib/engine.io.js b/lib/engine.io.js index 2a211c2b2..6fe013880 100644 --- a/lib/engine.io.js +++ b/lib/engine.io.js @@ -2,7 +2,8 @@ * Module dependencies. */ -var http = require('http'); +const http = require('http'); +const Server = require('./server'); /** * Invoking the library as a function delegates to attach if the first argument @@ -25,7 +26,7 @@ exports = module.exports = function () { } // if first argument is not an http server, then just make a regular eio server - return exports.Server.apply(null, arguments); + return new Server(arguments); }; /** @@ -42,7 +43,7 @@ exports.protocol = 1; * @api public */ -exports.Server = require('./server'); +exports.Server = Server; /** * Expose Socket constructor. @@ -94,13 +95,13 @@ function listen (port, options, fn) { options = {}; } - var server = http.createServer(function (req, res) { + const server = http.createServer(function (req, res) { res.writeHead(501); res.end('Not Implemented'); }); // create engine server - var engine = exports.attach(server, options); + const engine = exports.attach(server, options); engine.httpServer = server; server.listen(port, fn); @@ -120,7 +121,7 @@ function listen (port, options, fn) { exports.attach = attach; function attach (server, options) { - var engine = new exports.Server(options); + const engine = new Server(options); engine.attach(server, options); return engine; } diff --git a/lib/server.js b/lib/server.js index 2d9a45c7a..2922c6323 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1,239 +1,432 @@ +const qs = require('querystring'); +const parse = require('url').parse; +const base64id = require('base64id'); +const transports = require('./transports'); +const EventEmitter = require('events').EventEmitter; +const Socket = require('./socket'); +const debug = require('debug')('engine'); +const cookieMod = require('cookie'); + +class Server extends EventEmitter { + /** + * Server constructor. + * + * @param {Object} options + * @api public + */ + constructor (opts) { + super(); + + this.clients = {}; + this.clientsCount = 0; + + opts = opts || {}; + + this.wsEngine = opts.wsEngine || process.env.EIO_WS_ENGINE || 'ws'; + this.pingTimeout = opts.pingTimeout || 5000; + this.pingInterval = opts.pingInterval || 25000; + this.upgradeTimeout = opts.upgradeTimeout || 10000; + this.maxHttpBufferSize = opts.maxHttpBufferSize || 10E7; + this.transports = opts.transports || Object.keys(transports); + this.allowUpgrades = false !== opts.allowUpgrades; + this.allowRequest = opts.allowRequest; + this.cookie = false !== opts.cookie ? (opts.cookie || 'io') : false; + this.cookiePath = false !== opts.cookiePath ? (opts.cookiePath || '/') : false; + this.cookieHttpOnly = false !== opts.cookieHttpOnly; + this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || true) : false; + this.httpCompression = false !== opts.httpCompression ? (opts.httpCompression || {}) : false; + this.initialPacket = opts.initialPacket; + + // initialize compression options + ['perMessageDeflate', 'httpCompression'].forEach((type) => { + let compression = this[type]; + if (true === compression) this[type] = compression = {}; + if (compression && null == compression.threshold) { + compression.threshold = 1024; + } + }); -/** - * Module dependencies. - */ + this.init(); + } -var qs = require('querystring'); -var parse = require('url').parse; -var base64id = require('base64id'); -var transports = require('./transports'); -var EventEmitter = require('events').EventEmitter; -var Socket = require('./socket'); -var util = require('util'); -var debug = require('debug')('engine'); -var cookieMod = require('cookie'); + /** + * Initialize websocket server + * + * @api private + */ + init () { + if (!~this.transports.indexOf('websocket')) return; + + if (this.ws) this.ws.close(); + + let wsModule; + switch (this.wsEngine) { + case 'uws': wsModule = require('uws'); break; + case 'ws': wsModule = require('ws'); break; + default: throw new Error('unknown wsEngine'); + } + this.ws = new wsModule.Server({ + noServer: true, + clientTracking: false, + perMessageDeflate: this.perMessageDeflate, + maxPayload: this.maxHttpBufferSize + }); + } -/** - * Module exports. - */ + /** + * Returns a list of available transports for upgrade given a certain transport. + * + * @return {Array} + * @api public + */ + upgrades (transport) { + if (!this.allowUpgrades) return []; + return transports[transport].upgradesTo || []; + } -module.exports = Server; + /** + * Verifies a request. + * + * @param {http.IncomingMessage} + * @return {Boolean} whether the request is valid + * @api private + */ + verify (req, upgrade, fn) { + // transport check + const transport = req._query.transport; + if (!~this.transports.indexOf(transport)) { + debug('unknown transport "%s"', transport); + return fn(Server.errors.UNKNOWN_TRANSPORT, false); + } -/** - * Server constructor. - * - * @param {Object} options - * @api public - */ + // 'Origin' header check + const isOriginInvalid = checkInvalidHeaderChar(req.headers.origin); + if (isOriginInvalid) { + req.headers.origin = null; + debug('origin header invalid'); + return fn(Server.errors.BAD_REQUEST, false); + } + + // sid check + const sid = req._query.sid; + if (sid) { + if (!this.clients.hasOwnProperty(sid)) { + debug('unknown sid "%s"', sid); + return fn(Server.errors.UNKNOWN_SID, false); + } + if (!upgrade && this.clients[sid].transport.name !== transport) { + debug('bad request: unexpected transport without upgrade'); + return fn(Server.errors.BAD_REQUEST, false); + } + } else { + // handshake is GET only + if ('GET' !== req.method) return fn(Server.errors.BAD_HANDSHAKE_METHOD, false); + if (!this.allowRequest) return fn(null, true); + return this.allowRequest(req, fn); + } -function Server (opts) { - if (!(this instanceof Server)) { - return new Server(opts); + fn(null, true); } - this.clients = {}; - this.clientsCount = 0; - - opts = opts || {}; - - this.wsEngine = opts.wsEngine || process.env.EIO_WS_ENGINE || 'ws'; - this.pingTimeout = opts.pingTimeout || 5000; - this.pingInterval = opts.pingInterval || 25000; - this.upgradeTimeout = opts.upgradeTimeout || 10000; - this.maxHttpBufferSize = opts.maxHttpBufferSize || 10E7; - this.transports = opts.transports || Object.keys(transports); - this.allowUpgrades = false !== opts.allowUpgrades; - this.allowRequest = opts.allowRequest; - this.cookie = false !== opts.cookie ? (opts.cookie || 'io') : false; - this.cookiePath = false !== opts.cookiePath ? (opts.cookiePath || '/') : false; - this.cookieHttpOnly = false !== opts.cookieHttpOnly; - this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || true) : false; - this.httpCompression = false !== opts.httpCompression ? (opts.httpCompression || {}) : false; - this.initialPacket = opts.initialPacket; - - var self = this; - - // initialize compression options - ['perMessageDeflate', 'httpCompression'].forEach(function (type) { - var compression = self[type]; - if (true === compression) self[type] = compression = {}; - if (compression && null == compression.threshold) { - compression.threshold = 1024; + /** + * Prepares a request by processing the query string. + * + * @api private + */ + prepare (req) { + // try to leverage pre-existing `req._query` (e.g: from connect) + if (!req._query) { + req._query = ~req.url.indexOf('?') ? qs.parse(parse(req.url).query) : {}; } - }); + } - this.init(); -} + /** + * Closes all clients. + * + * @api public + */ + close () { + debug('closing all open clients'); + for (let i in this.clients) { + if (this.clients.hasOwnProperty(i)) { + this.clients[i].close(true); + } + } + if (this.ws) { + debug('closing webSocketServer'); + this.ws.close(); + // don't delete this.ws because it can be used again if the http server starts listening again + } + return this; + } -/** - * Protocol errors mappings. - */ + /** + * Handles an Engine.IO HTTP request. + * + * @param {http.IncomingMessage} request + * @param {http.ServerResponse|http.OutgoingMessage} response + * @api public + */ + handleRequest (req, res) { + debug('handling "%s" http request "%s"', req.method, req.url); + this.prepare(req); + req.res = res; + + const self = this; + this.verify(req, false, function (err, success) { + if (!success) { + sendErrorMessage(req, res, err); + return; + } -Server.errors = { - UNKNOWN_TRANSPORT: 0, - UNKNOWN_SID: 1, - BAD_HANDSHAKE_METHOD: 2, - BAD_REQUEST: 3, - FORBIDDEN: 4 -}; + if (req._query.sid) { + debug('setting new request for existing client'); + self.clients[req._query.sid].transport.onRequest(req); + } else { + self.handshake(req._query.transport, req); + } + }); + } -Server.errorMessages = { - 0: 'Transport unknown', - 1: 'Session ID unknown', - 2: 'Bad handshake method', - 3: 'Bad request', - 4: 'Forbidden' -}; + /** + * generate a socket id. + * Overwrite this method to generate your custom socket id + * + * @param {Object} request object + * @api public + */ + generateId (req) { + return base64id.generateId(); + } -/** - * Inherits from EventEmitter. - */ + /** + * Handshakes a new client. + * + * @param {String} transport name + * @param {Object} request object + * @api private + */ + handshake (transportName, req) { + const id = this.generateId(req); + + debug('handshaking client "%s"', id); + + try { + var transport = new transports[transportName](req); + if ('polling' === transportName) { + transport.maxHttpBufferSize = this.maxHttpBufferSize; + transport.httpCompression = this.httpCompression; + } else if ('websocket' === transportName) { + transport.perMessageDeflate = this.perMessageDeflate; + } -util.inherits(Server, EventEmitter); + if (req._query && req._query.b64) { + transport.supportsBinary = false; + } else { + transport.supportsBinary = true; + } + } catch (e) { + debug('error handshaking to transport "%s"', transportName); + sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST); + return; + } + const socket = new Socket(id, this, transport, req); + const self = this; + + if (false !== this.cookie) { + transport.on('headers', function (headers) { + headers['Set-Cookie'] = cookieMod.serialize(self.cookie, id, + { + path: self.cookiePath, + httpOnly: self.cookiePath ? self.cookieHttpOnly : false + }); + }); + } -/** - * Initialize websocket server - * - * @api private - */ + transport.onRequest(req); -Server.prototype.init = function () { - if (!~this.transports.indexOf('websocket')) return; + this.clients[id] = socket; + this.clientsCount++; - if (this.ws) this.ws.close(); + socket.once('close', function () { + delete self.clients[id]; + self.clientsCount--; + }); - var wsModule; - switch (this.wsEngine) { - case 'uws': wsModule = require('uws'); break; - case 'ws': wsModule = require('ws'); break; - default: throw new Error('unknown wsEngine'); + this.emit('connection', socket); } - this.ws = new wsModule.Server({ - noServer: true, - clientTracking: false, - perMessageDeflate: this.perMessageDeflate, - maxPayload: this.maxHttpBufferSize - }); -}; -/** - * Returns a list of available transports for upgrade given a certain transport. - * - * @return {Array} - * @api public - */ - -Server.prototype.upgrades = function (transport) { - if (!this.allowUpgrades) return []; - return transports[transport].upgradesTo || []; -}; + /** + * Handles an Engine.IO HTTP Upgrade. + * + * @api public + */ + handleUpgrade (req, socket, upgradeHead) { + this.prepare(req); + + const self = this; + this.verify(req, true, function (err, success) { + if (!success) { + abortConnection(socket, err); + return; + } -/** - * Verifies a request. - * - * @param {http.IncomingMessage} - * @return {Boolean} whether the request is valid - * @api private - */ + const head = Buffer.from(upgradeHead); // eslint-disable-line node/no-deprecated-api + upgradeHead = null; -Server.prototype.verify = function (req, upgrade, fn) { - // transport check - var transport = req._query.transport; - if (!~this.transports.indexOf(transport)) { - debug('unknown transport "%s"', transport); - return fn(Server.errors.UNKNOWN_TRANSPORT, false); + // delegate to ws + self.ws.handleUpgrade(req, socket, head, function (conn) { + self.onWebSocket(req, conn); + }); + }); } - // 'Origin' header check - var isOriginInvalid = checkInvalidHeaderChar(req.headers.origin); - if (isOriginInvalid) { - req.headers.origin = null; - debug('origin header invalid'); - return fn(Server.errors.BAD_REQUEST, false); - } + /** + * Called upon a ws.io connection. + * + * @param {ws.Socket} websocket + * @api private + */ + onWebSocket (req, socket) { + socket.on('error', onUpgradeError); + + if (transports[req._query.transport] !== undefined && !transports[req._query.transport].prototype.handlesUpgrades) { + debug('transport doesnt handle upgraded requests'); + socket.close(); + return; + } - // sid check - var sid = req._query.sid; - if (sid) { - if (!this.clients.hasOwnProperty(sid)) { - debug('unknown sid "%s"', sid); - return fn(Server.errors.UNKNOWN_SID, false); + // get client id + const id = req._query.sid; + + // keep a reference to the ws.Socket + req.websocket = socket; + + if (id) { + const client = this.clients[id]; + if (!client) { + debug('upgrade attempt for closed client'); + socket.close(); + } else if (client.upgrading) { + debug('transport has already been trying to upgrade'); + socket.close(); + } else if (client.upgraded) { + debug('transport had already been upgraded'); + socket.close(); + } else { + debug('upgrading existing transport'); + + // transport error handling takes over + socket.removeListener('error', onUpgradeError); + + const transport = new transports[req._query.transport](req); + if (req._query && req._query.b64) { + transport.supportsBinary = false; + } else { + transport.supportsBinary = true; + } + transport.perMessageDeflate = this.perMessageDeflate; + client.maybeUpgrade(transport); + } + } else { + // transport error handling takes over + socket.removeListener('error', onUpgradeError); + + this.handshake(req._query.transport, req); } - if (!upgrade && this.clients[sid].transport.name !== transport) { - debug('bad request: unexpected transport without upgrade'); - return fn(Server.errors.BAD_REQUEST, false); + + function onUpgradeError () { + debug('websocket error before upgrade'); + // socket.close() not needed } - } else { - // handshake is GET only - if ('GET' !== req.method) return fn(Server.errors.BAD_HANDSHAKE_METHOD, false); - if (!this.allowRequest) return fn(null, true); - return this.allowRequest(req, fn); } - fn(null, true); -}; - -/** - * Prepares a request by processing the query string. - * - * @api private - */ + /** + * Captures upgrade requests for a http.Server. + * + * @param {http.Server} server + * @param {Object} options + * @api public + */ + attach (server, options) { + const self = this; + options = options || {}; + let path = (options.path || '/engine.io').replace(/\/$/, ''); + + const destroyUpgradeTimeout = options.destroyUpgradeTimeout || 1000; + + // normalize path + path += '/'; + + function check (req) { + if ('OPTIONS' === req.method && false === options.handlePreflightRequest) { + return false; + } + return path === req.url.substr(0, path.length); + } -Server.prototype.prepare = function (req) { - // try to leverage pre-existing `req._query` (e.g: from connect) - if (!req._query) { - req._query = ~req.url.indexOf('?') ? qs.parse(parse(req.url).query) : {}; - } -}; + // cache and clean up listeners + const listeners = server.listeners('request').slice(0); + server.removeAllListeners('request'); + server.on('close', self.close.bind(self)); + server.on('listening', self.init.bind(self)); -/** - * Closes all clients. - * - * @api public - */ + // add request handler + server.on('request', function (req, res) { + if (check(req)) { + debug('intercepting request for path "%s"', path); + if ('OPTIONS' === req.method && 'function' === typeof options.handlePreflightRequest) { + options.handlePreflightRequest.call(server, req, res); + } else { + self.handleRequest(req, res); + } + } else { + let i = 0; + const l = listeners.length; + for (; i < l; i++) { + listeners[i].call(server, req, res); + } + } + }); -Server.prototype.close = function () { - debug('closing all open clients'); - for (var i in this.clients) { - if (this.clients.hasOwnProperty(i)) { - this.clients[i].close(true); + if (~self.transports.indexOf('websocket')) { + server.on('upgrade', function (req, socket, head) { + if (check(req)) { + self.handleUpgrade(req, socket, head); + } else if (false !== options.destroyUpgrade) { + // default node behavior is to disconnect when no handlers + // but by adding a handler, we prevent that + // and if no eio thing handles the upgrade + // then the socket needs to die! + setTimeout(function () { + if (socket.writable && socket.bytesWritten <= 0) { + return socket.end(); + } + }, destroyUpgradeTimeout); + } + }); } } - if (this.ws) { - debug('closing webSocketServer'); - this.ws.close(); - // don't delete this.ws because it can be used again if the http server starts listening again - } - return this; -}; +} /** - * Handles an Engine.IO HTTP request. - * - * @param {http.IncomingMessage} request - * @param {http.ServerResponse|http.OutgoingMessage} response - * @api public + * Protocol errors mappings. */ -Server.prototype.handleRequest = function (req, res) { - debug('handling "%s" http request "%s"', req.method, req.url); - this.prepare(req); - req.res = res; - - var self = this; - this.verify(req, false, function (err, success) { - if (!success) { - sendErrorMessage(req, res, err); - return; - } +Server.errors = { + UNKNOWN_TRANSPORT: 0, + UNKNOWN_SID: 1, + BAD_HANDSHAKE_METHOD: 2, + BAD_REQUEST: 3, + FORBIDDEN: 4 +}; - if (req._query.sid) { - debug('setting new request for existing client'); - self.clients[req._query.sid].transport.onRequest(req); - } else { - self.handshake(req._query.transport, req); - } - }); +Server.errorMessages = { + 0: 'Transport unknown', + 1: 'Session ID unknown', + 2: 'Bad handshake method', + 3: 'Bad request', + 4: 'Forbidden' }; /** @@ -245,9 +438,9 @@ Server.prototype.handleRequest = function (req, res) { */ function sendErrorMessage (req, res, code) { - var headers = { 'Content-Type': 'application/json' }; + const headers = {'Content-Type': 'application/json'}; - var isForbidden = !Server.errorMessages.hasOwnProperty(code); + const isForbidden = !Server.errorMessages.hasOwnProperty(code); if (isForbidden) { res.writeHead(403, headers); res.end(JSON.stringify({ @@ -271,229 +464,6 @@ function sendErrorMessage (req, res, code) { } } -/** - * generate a socket id. - * Overwrite this method to generate your custom socket id - * - * @param {Object} request object - * @api public - */ - -Server.prototype.generateId = function (req) { - return base64id.generateId(); -}; - -/** - * Handshakes a new client. - * - * @param {String} transport name - * @param {Object} request object - * @api private - */ - -Server.prototype.handshake = function (transportName, req) { - var id = this.generateId(req); - - debug('handshaking client "%s"', id); - - try { - var transport = new transports[transportName](req); - if ('polling' === transportName) { - transport.maxHttpBufferSize = this.maxHttpBufferSize; - transport.httpCompression = this.httpCompression; - } else if ('websocket' === transportName) { - transport.perMessageDeflate = this.perMessageDeflate; - } - - if (req._query && req._query.b64) { - transport.supportsBinary = false; - } else { - transport.supportsBinary = true; - } - } catch (e) { - debug('error handshaking to transport "%s"', transportName); - sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST); - return; - } - var socket = new Socket(id, this, transport, req); - var self = this; - - if (false !== this.cookie) { - transport.on('headers', function (headers) { - headers['Set-Cookie'] = cookieMod.serialize(self.cookie, id, - { - path: self.cookiePath, - httpOnly: self.cookiePath ? self.cookieHttpOnly : false - }); - }); - } - - transport.onRequest(req); - - this.clients[id] = socket; - this.clientsCount++; - - socket.once('close', function () { - delete self.clients[id]; - self.clientsCount--; - }); - - this.emit('connection', socket); -}; - -/** - * Handles an Engine.IO HTTP Upgrade. - * - * @api public - */ - -Server.prototype.handleUpgrade = function (req, socket, upgradeHead) { - this.prepare(req); - - var self = this; - this.verify(req, true, function (err, success) { - if (!success) { - abortConnection(socket, err); - return; - } - - var head = Buffer.from(upgradeHead); // eslint-disable-line node/no-deprecated-api - upgradeHead = null; - - // delegate to ws - self.ws.handleUpgrade(req, socket, head, function (conn) { - self.onWebSocket(req, conn); - }); - }); -}; - -/** - * Called upon a ws.io connection. - * - * @param {ws.Socket} websocket - * @api private - */ - -Server.prototype.onWebSocket = function (req, socket) { - socket.on('error', onUpgradeError); - - if (transports[req._query.transport] !== undefined && !transports[req._query.transport].prototype.handlesUpgrades) { - debug('transport doesnt handle upgraded requests'); - socket.close(); - return; - } - - // get client id - var id = req._query.sid; - - // keep a reference to the ws.Socket - req.websocket = socket; - - if (id) { - var client = this.clients[id]; - if (!client) { - debug('upgrade attempt for closed client'); - socket.close(); - } else if (client.upgrading) { - debug('transport has already been trying to upgrade'); - socket.close(); - } else if (client.upgraded) { - debug('transport had already been upgraded'); - socket.close(); - } else { - debug('upgrading existing transport'); - - // transport error handling takes over - socket.removeListener('error', onUpgradeError); - - var transport = new transports[req._query.transport](req); - if (req._query && req._query.b64) { - transport.supportsBinary = false; - } else { - transport.supportsBinary = true; - } - transport.perMessageDeflate = this.perMessageDeflate; - client.maybeUpgrade(transport); - } - } else { - // transport error handling takes over - socket.removeListener('error', onUpgradeError); - - this.handshake(req._query.transport, req); - } - - function onUpgradeError () { - debug('websocket error before upgrade'); - // socket.close() not needed - } -}; - -/** - * Captures upgrade requests for a http.Server. - * - * @param {http.Server} server - * @param {Object} options - * @api public - */ - -Server.prototype.attach = function (server, options) { - var self = this; - options = options || {}; - var path = (options.path || '/engine.io').replace(/\/$/, ''); - - var destroyUpgradeTimeout = options.destroyUpgradeTimeout || 1000; - - // normalize path - path += '/'; - - function check (req) { - if ('OPTIONS' === req.method && false === options.handlePreflightRequest) { - return false; - } - return path === req.url.substr(0, path.length); - } - - // cache and clean up listeners - var listeners = server.listeners('request').slice(0); - server.removeAllListeners('request'); - server.on('close', self.close.bind(self)); - server.on('listening', self.init.bind(self)); - - // add request handler - server.on('request', function (req, res) { - if (check(req)) { - debug('intercepting request for path "%s"', path); - if ('OPTIONS' === req.method && 'function' === typeof options.handlePreflightRequest) { - options.handlePreflightRequest.call(server, req, res); - } else { - self.handleRequest(req, res); - } - } else { - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].call(server, req, res); - } - } - }); - - if (~self.transports.indexOf('websocket')) { - server.on('upgrade', function (req, socket, head) { - if (check(req)) { - self.handleUpgrade(req, socket, head); - } else if (false !== options.destroyUpgrade) { - // default node behavior is to disconnect when no handlers - // but by adding a handler, we prevent that - // and if no eio thing handles the upgrade - // then the socket needs to die! - setTimeout(function () { - if (socket.writable && socket.bytesWritten <= 0) { - return socket.end(); - } - }, destroyUpgradeTimeout); - } - }); - } -}; - /** * Closes the connection * @@ -504,8 +474,8 @@ Server.prototype.attach = function (server, options) { function abortConnection (socket, code) { if (socket.writable) { - var message = Server.errorMessages.hasOwnProperty(code) ? Server.errorMessages[code] : String(code || ''); - var length = Buffer.byteLength(message); + const message = Server.errorMessages.hasOwnProperty(code) ? Server.errorMessages[code] : String(code || ''); + const length = Buffer.byteLength(message); socket.write( 'HTTP/1.1 400 Bad Request\r\n' + 'Connection: close\r\n' + @@ -518,6 +488,8 @@ function abortConnection (socket, code) { socket.destroy(); } +module.exports = Server; + /* eslint-disable */ /** @@ -532,7 +504,7 @@ function abortConnection (socket, code) { * so take care when making changes to the implementation so that the source * code size does not exceed v8's default max_inlined_source_size setting. **/ -var validHdrChars = [ +const validHdrChars = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0 - 15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32 - 47 @@ -549,7 +521,7 @@ var validHdrChars = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // ... 255 -]; +] function checkInvalidHeaderChar(val) { val += ''; @@ -577,7 +549,7 @@ function checkInvalidHeaderChar(val) { debug('invalid header, index 3, char "%s"', val.charCodeAt(3)); return true; } - for (var i = 4; i < val.length; ++i) { + for (let i = 4; i < val.length; ++i) { if (!validHdrChars[val.charCodeAt(i)]) { debug('invalid header, index "%i", char "%s"', i, val.charCodeAt(i)); return true; diff --git a/lib/socket.js b/lib/socket.js index 177b25c69..415a65a1d 100644 --- a/lib/socket.js +++ b/lib/socket.js @@ -1,486 +1,465 @@ -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter; -var util = require('util'); -var debug = require('debug')('engine:socket'); +const EventEmitter = require('events'); +const debug = require('debug')('engine:socket'); + +class Socket extends EventEmitter { + /** + * Client class (abstract). + * + * @api private + */ + constructor (id, server, transport, req) { + super(); + this.id = id; + this.server = server; + this.upgrading = false; + this.upgraded = false; + this.readyState = 'opening'; + this.writeBuffer = []; + this.packetsFn = []; + this.sentCallbackFn = []; + this.cleanupFn = []; + this.request = req; -/** - * Module exports. - */ + // Cache IP since it might not be in the req later + if (req.websocket && req.websocket._socket) { + this.remoteAddress = req.websocket._socket.remoteAddress; + } else { + this.remoteAddress = req.connection.remoteAddress; + } -module.exports = Socket; + this.checkIntervalTimer = null; + this.upgradeTimeoutTimer = null; + this.pingTimeoutTimer = null; -/** - * Client class (abstract). - * - * @api private - */ - -function Socket (id, server, transport, req) { - this.id = id; - this.server = server; - this.upgrading = false; - this.upgraded = false; - this.readyState = 'opening'; - this.writeBuffer = []; - this.packetsFn = []; - this.sentCallbackFn = []; - this.cleanupFn = []; - this.request = req; - - // Cache IP since it might not be in the req later - if (req.websocket && req.websocket._socket) { - this.remoteAddress = req.websocket._socket.remoteAddress; - } else { - this.remoteAddress = req.connection.remoteAddress; + this.setTransport(transport); + this.onOpen(); } - this.checkIntervalTimer = null; - this.upgradeTimeoutTimer = null; - this.pingTimeoutTimer = null; - - this.setTransport(transport); - this.onOpen(); -} - -/** - * Inherits from EventEmitter. - */ + /** + * Called upon transport considered open. + * + * @api private + */ + onOpen () { + this.readyState = 'open'; + + // sends an `open` packet + this.transport.sid = this.id; + this.sendPacket('open', JSON.stringify({ + sid: this.id, + upgrades: this.getAvailableUpgrades(), + pingInterval: this.server.pingInterval, + pingTimeout: this.server.pingTimeout + })); + + if (this.server.initialPacket) { + this.sendPacket('message', this.server.initialPacket); + } -util.inherits(Socket, EventEmitter); + this.emit('open'); + this.setPingTimeout(); + } -/** - * Called upon transport considered open. - * - * @api private - */ + /** + * Called upon transport packet. + * + * @param {Object} packet + * @api private + */ + onPacket (packet) { + if ('open' === this.readyState) { + // export packet event + debug('packet'); + this.emit('packet', packet); + + // Reset ping timeout on any packet, incoming data is a good sign of + // other side's liveness + this.setPingTimeout(); + + switch (packet.type) { + case 'ping': + debug('got ping'); + this.sendPacket('pong'); + this.emit('heartbeat'); + break; + + case 'error': + this.onClose('parse error'); + break; + + case 'message': + this.emit('data', packet.data); + this.emit('message', packet.data); + break; + } + } else { + debug('packet received with closed socket'); + } + } -Socket.prototype.onOpen = function () { - this.readyState = 'open'; + /** + * Called upon transport error. + * + * @param {Error} error object + * @api private + */ + onError (err) { + debug('transport error'); + this.onClose('transport error', err); + } - // sends an `open` packet - this.transport.sid = this.id; - this.sendPacket('open', JSON.stringify({ - sid: this.id, - upgrades: this.getAvailableUpgrades(), - pingInterval: this.server.pingInterval, - pingTimeout: this.server.pingTimeout - })); + /** + * Sets and resets ping timeout timer based on client pings. + * + * @api private + */ + setPingTimeout () { + clearTimeout(this.pingTimeoutTimer); + this.pingTimeoutTimer = setTimeout(() => { + this.onClose('ping timeout'); + }, this.server.pingInterval + this.server.pingTimeout); + } - if (this.server.initialPacket) { - this.sendPacket('message', this.server.initialPacket); + /** + * Attaches handlers for the given transport. + * + * @param {Transport} transport + * @api private + */ + setTransport (transport) { + const onError = this.onError.bind(this); + const onPacket = this.onPacket.bind(this); + const flush = this.flush.bind(this); + const onClose = this.onClose.bind(this, 'transport close'); + + this.transport = transport; + this.transport.once('error', onError); + this.transport.on('packet', onPacket); + this.transport.on('drain', flush); + this.transport.once('close', onClose); + // this function will manage packet events (also message callbacks) + this.setupSendCallback(); + + this.cleanupFn.push(function () { + transport.removeListener('error', onError); + transport.removeListener('packet', onPacket); + transport.removeListener('drain', flush); + transport.removeListener('close', onClose); + }); } - this.emit('open'); - this.setPingTimeout(); -}; - -/** - * Called upon transport packet. - * - * @param {Object} packet - * @api private - */ - -Socket.prototype.onPacket = function (packet) { - if ('open' === this.readyState) { - // export packet event - debug('packet'); - this.emit('packet', packet); - - // Reset ping timeout on any packet, incoming data is a good sign of - // other side's liveness - this.setPingTimeout(); + /** + * Upgrades socket to the given transport + * + * @param {Transport} transport + * @api private + */ + maybeUpgrade (transport) { + debug('might upgrade socket transport from "%s" to "%s"' + , this.transport.name, transport.name); - switch (packet.type) { - case 'ping': - debug('got ping'); - this.sendPacket('pong'); - this.emit('heartbeat'); - break; - - case 'error': - this.onClose('parse error'); - break; - - case 'message': - this.emit('data', packet.data); - this.emit('message', packet.data); - break; - } - } else { - debug('packet received with closed socket'); - } -}; - -/** - * Called upon transport error. - * - * @param {Error} error object - * @api private - */ - -Socket.prototype.onError = function (err) { - debug('transport error'); - this.onClose('transport error', err); -}; - -/** - * Sets and resets ping timeout timer based on client pings. - * - * @api private - */ - -Socket.prototype.setPingTimeout = function () { - var self = this; - clearTimeout(self.pingTimeoutTimer); - self.pingTimeoutTimer = setTimeout(function () { - self.onClose('ping timeout'); - }, self.server.pingInterval + self.server.pingTimeout); -}; - -/** - * Attaches handlers for the given transport. - * - * @param {Transport} transport - * @api private - */ - -Socket.prototype.setTransport = function (transport) { - var onError = this.onError.bind(this); - var onPacket = this.onPacket.bind(this); - var flush = this.flush.bind(this); - var onClose = this.onClose.bind(this, 'transport close'); - - this.transport = transport; - this.transport.once('error', onError); - this.transport.on('packet', onPacket); - this.transport.on('drain', flush); - this.transport.once('close', onClose); - // this function will manage packet events (also message callbacks) - this.setupSendCallback(); - - this.cleanupFn.push(function () { - transport.removeListener('error', onError); - transport.removeListener('packet', onPacket); - transport.removeListener('drain', flush); - transport.removeListener('close', onClose); - }); -}; - -/** - * Upgrades socket to the given transport - * - * @param {Transport} transport - * @api private - */ - -Socket.prototype.maybeUpgrade = function (transport) { - debug('might upgrade socket transport from "%s" to "%s"' - , this.transport.name, transport.name); - - this.upgrading = true; - - var self = this; - - // set transport upgrade timer - self.upgradeTimeoutTimer = setTimeout(function () { - debug('client did not complete upgrade - closing transport'); - cleanup(); - if ('open' === transport.readyState) { - transport.close(); - } - }, this.server.upgradeTimeout); + this.upgrading = true; - function onPacket (packet) { - if ('ping' === packet.type && 'probe' === packet.data) { - transport.send([{ type: 'pong', data: 'probe' }]); - self.emit('upgrading', transport); - clearInterval(self.checkIntervalTimer); - self.checkIntervalTimer = setInterval(check, 100); - } else if ('upgrade' === packet.type && self.readyState !== 'closed') { - debug('got upgrade packet - upgrading'); + const self = this; + + // set transport upgrade timer + self.upgradeTimeoutTimer = setTimeout(function () { + debug('client did not complete upgrade - closing transport'); cleanup(); - self.transport.discard(); - self.upgraded = true; - self.clearTransport(); - self.setTransport(transport); - self.emit('upgrade', transport); - self.setPingTimeout(); - self.flush(); - if (self.readyState === 'closing') { - transport.close(function () { - self.onClose('forced close'); - }); + if ('open' === transport.readyState) { + transport.close(); + } + }, this.server.upgradeTimeout); + + function onPacket (packet) { + if ('ping' === packet.type && 'probe' === packet.data) { + transport.send([{ type: 'pong', data: 'probe' }]); + self.emit('upgrading', transport); + clearInterval(self.checkIntervalTimer); + self.checkIntervalTimer = setInterval(check, 100); + } else if ('upgrade' === packet.type && self.readyState !== 'closed') { + debug('got upgrade packet - upgrading'); + cleanup(); + self.transport.discard(); + self.upgraded = true; + self.clearTransport(); + self.setTransport(transport); + self.emit('upgrade', transport); + self.setPingTimeout(); + self.flush(); + if (self.readyState === 'closing') { + transport.close(function () { + self.onClose('forced close'); + }); + } + } else { + cleanup(); + transport.close(); } - } else { - cleanup(); - transport.close(); } - } - // we force a polling cycle to ensure a fast upgrade - function check () { - if ('polling' === self.transport.name && self.transport.writable) { - debug('writing a noop packet to polling for fast upgrade'); - self.transport.send([{ type: 'noop' }]); + // we force a polling cycle to ensure a fast upgrade + function check () { + if ('polling' === self.transport.name && self.transport.writable) { + debug('writing a noop packet to polling for fast upgrade'); + self.transport.send([{ type: 'noop' }]); + } } - } - function cleanup () { - self.upgrading = false; + function cleanup () { + self.upgrading = false; - clearInterval(self.checkIntervalTimer); - self.checkIntervalTimer = null; - - clearTimeout(self.upgradeTimeoutTimer); - self.upgradeTimeoutTimer = null; + clearInterval(self.checkIntervalTimer); + self.checkIntervalTimer = null; - transport.removeListener('packet', onPacket); - transport.removeListener('close', onTransportClose); - transport.removeListener('error', onError); - self.removeListener('close', onClose); - } + clearTimeout(self.upgradeTimeoutTimer); + self.upgradeTimeoutTimer = null; - function onError (err) { - debug('client did not complete upgrade - %s', err); - cleanup(); - transport.close(); - transport = null; - } + transport.removeListener('packet', onPacket); + transport.removeListener('close', onTransportClose); + transport.removeListener('error', onError); + self.removeListener('close', onClose); + } - function onTransportClose () { - onError('transport closed'); - } + function onError (err) { + debug('client did not complete upgrade - %s', err); + cleanup(); + transport.close(); + transport = null; + } - function onClose () { - onError('socket closed'); - } + function onTransportClose () { + onError('transport closed'); + } - transport.on('packet', onPacket); - transport.once('close', onTransportClose); - transport.once('error', onError); + function onClose () { + onError('socket closed'); + } - self.once('close', onClose); -}; + transport.on('packet', onPacket); + transport.once('close', onTransportClose); + transport.once('error', onError); -/** - * Clears listeners and timers associated with current transport. - * - * @api private - */ + self.once('close', onClose); + } -Socket.prototype.clearTransport = function () { - var cleanup; + /** + * Clears listeners and timers associated with current transport. + * + * @api private + */ + clearTransport () { + let cleanup; - var toCleanUp = this.cleanupFn.length; + const toCleanUp = this.cleanupFn.length; - for (var i = 0; i < toCleanUp; i++) { - cleanup = this.cleanupFn.shift(); - cleanup(); - } + for (let i = 0; i < toCleanUp; i++) { + cleanup = this.cleanupFn.shift(); + cleanup(); + } - // silence further transport errors and prevent uncaught exceptions - this.transport.on('error', function () { - debug('error triggered by discarded transport'); - }); + // silence further transport errors and prevent uncaught exceptions + this.transport.on('error', function () { + debug('error triggered by discarded transport'); + }); - // ensure transport won't stay open - this.transport.close(); + // ensure transport won't stay open + this.transport.close(); - clearTimeout(this.pingTimeoutTimer); -}; + clearTimeout(this.pingTimeoutTimer); + } -/** - * Called upon transport considered closed. - * Possible reasons: `ping timeout`, `client error`, `parse error`, - * `transport error`, `server close`, `transport close` - */ + /** + * Called upon transport considered closed. + * Possible reasons: `ping timeout`, `client error`, `parse error`, + * `transport error`, `server close`, `transport close` + */ + onClose (reason, description) { + if ('closed' !== this.readyState) { + this.readyState = 'closed'; + clearTimeout(this.pingTimeoutTimer); + clearInterval(this.checkIntervalTimer); + this.checkIntervalTimer = null; + clearTimeout(this.upgradeTimeoutTimer); + const self = this; + // clean writeBuffer in next tick, so developers can still + // grab the writeBuffer on 'close' event + process.nextTick(function () { + self.writeBuffer = []; + }); + this.packetsFn = []; + this.sentCallbackFn = []; + this.clearTransport(); + this.emit('close', reason, description); + } + } -Socket.prototype.onClose = function (reason, description) { - if ('closed' !== this.readyState) { - this.readyState = 'closed'; - clearTimeout(this.pingTimeoutTimer); - clearInterval(this.checkIntervalTimer); - this.checkIntervalTimer = null; - clearTimeout(this.upgradeTimeoutTimer); - var self = this; - // clean writeBuffer in next tick, so developers can still - // grab the writeBuffer on 'close' event - process.nextTick(function () { - self.writeBuffer = []; + /** + * Setup and manage send callback + * + * @api private + */ + setupSendCallback () { + const self = this; + this.transport.on('drain', onDrain); + + this.cleanupFn.push(function () { + self.transport.removeListener('drain', onDrain); }); - this.packetsFn = []; - this.sentCallbackFn = []; - this.clearTransport(); - this.emit('close', reason, description); - } -}; - -/** - * Setup and manage send callback - * - * @api private - */ - -Socket.prototype.setupSendCallback = function () { - var self = this; - this.transport.on('drain', onDrain); - - this.cleanupFn.push(function () { - self.transport.removeListener('drain', onDrain); - }); - - // the message was sent successfully, execute the callback - function onDrain () { - if (self.sentCallbackFn.length > 0) { - var seqFn = self.sentCallbackFn.splice(0, 1)[0]; - if ('function' === typeof seqFn) { - debug('executing send callback'); - seqFn(self.transport); - } else if (Array.isArray(seqFn)) { - debug('executing batch send callback'); - for (var l = seqFn.length, i = 0; i < l; i++) { - if ('function' === typeof seqFn[i]) { - seqFn[i](self.transport); + + // the message was sent successfully, execute the callback + function onDrain () { + if (self.sentCallbackFn.length > 0) { + const seqFn = self.sentCallbackFn.splice(0, 1)[0]; + if ('function' === typeof seqFn) { + debug('executing send callback'); + seqFn(self.transport); + } else if (Array.isArray(seqFn)) { + debug('executing batch send callback'); + const l = seqFn.length; + let i = 0; + for (; i < l; i++) { + if ('function' === typeof seqFn[i]) { + seqFn[i](self.transport); + } } } } } } -}; - -/** - * Sends a message packet. - * - * @param {String} message - * @param {Object} options - * @param {Function} callback - * @return {Socket} for chaining - * @api public - */ - -Socket.prototype.send = -Socket.prototype.write = function (data, options, callback) { - this.sendPacket('message', data, options, callback); - return this; -}; - -/** - * Sends a packet. - * - * @param {String} packet type - * @param {String} optional, data - * @param {Object} options - * @api private - */ - -Socket.prototype.sendPacket = function (type, data, options, callback) { - if ('function' === typeof options) { - callback = options; - options = null; + + /** + * Sends a message packet. + * + * @param {String} message + * @param {Object} options + * @param {Function} callback + * @return {Socket} for chaining + * @api public + */ + send (data, options, callback) { + this.sendPacket('message', data, options, callback); + return this; } - options = options || {}; - options.compress = false !== options.compress; + write (data, options, callback) { + this.sendPacket('message', data, options, callback); + return this; + } - if ('closing' !== this.readyState && 'closed' !== this.readyState) { - debug('sending packet "%s" (%s)', type, data); + /** + * Sends a packet. + * + * @param {String} packet type + * @param {String} optional, data + * @param {Object} options + * @api private + */ + sendPacket (type, data, options, callback) { + if ('function' === typeof options) { + callback = options; + options = null; + } - var packet = { - type: type, - options: options - }; - if (data) packet.data = data; + options = options || {}; + options.compress = false !== options.compress; - // exports packetCreate event - this.emit('packetCreate', packet); + if ('closing' !== this.readyState && 'closed' !== this.readyState) { + debug('sending packet "%s" (%s)', type, data); - this.writeBuffer.push(packet); + const packet = { + type: type, + options: options + }; + if (data) packet.data = data; - // add send callback to object, if defined - if (callback) this.packetsFn.push(callback); + // exports packetCreate event + this.emit('packetCreate', packet); - this.flush(); - } -}; - -/** - * Attempts to flush the packets buffer. - * - * @api private - */ - -Socket.prototype.flush = function () { - if ('closed' !== this.readyState && - this.transport.writable && - this.writeBuffer.length) { - debug('flushing buffer to transport'); - this.emit('flush', this.writeBuffer); - this.server.emit('flush', this, this.writeBuffer); - var wbuf = this.writeBuffer; - this.writeBuffer = []; - if (!this.transport.supportsFraming) { - this.sentCallbackFn.push(this.packetsFn); - } else { - this.sentCallbackFn.push.apply(this.sentCallbackFn, this.packetsFn); + this.writeBuffer.push(packet); + + // add send callback to object, if defined + if (callback) this.packetsFn.push(callback); + + this.flush(); } - this.packetsFn = []; - this.transport.send(wbuf); - this.emit('drain'); - this.server.emit('drain', this); } -}; - -/** - * Get available upgrades for this socket. - * - * @api private - */ - -Socket.prototype.getAvailableUpgrades = function () { - var availableUpgrades = []; - var allUpgrades = this.server.upgrades(this.transport.name); - for (var i = 0, l = allUpgrades.length; i < l; ++i) { - var upg = allUpgrades[i]; - if (this.server.transports.indexOf(upg) !== -1) { - availableUpgrades.push(upg); + + /** + * Attempts to flush the packets buffer. + * + * @api private + */ + flush () { + if ('closed' !== this.readyState && + this.transport.writable && + this.writeBuffer.length) { + debug('flushing buffer to transport'); + this.emit('flush', this.writeBuffer); + this.server.emit('flush', this, this.writeBuffer); + const wbuf = this.writeBuffer; + this.writeBuffer = []; + if (!this.transport.supportsFraming) { + this.sentCallbackFn.push(this.packetsFn); + } else { + this.sentCallbackFn.push.apply(this.sentCallbackFn, this.packetsFn); + } + this.packetsFn = []; + this.transport.send(wbuf); + this.emit('drain'); + this.server.emit('drain', this); } } - return availableUpgrades; -}; - -/** - * Closes the socket and underlying transport. - * - * @param {Boolean} optional, discard - * @return {Socket} for chaining - * @api public - */ -Socket.prototype.close = function (discard) { - if ('open' !== this.readyState) return; + /** + * Get available upgrades for this socket. + * + * @api private + */ + getAvailableUpgrades () { + const availableUpgrades = []; + const allUpgrades = this.server.upgrades(this.transport.name); + let i = 0; + const l = allUpgrades.length; + for (; i < l; ++i) { + const upg = allUpgrades[i]; + if (this.server.transports.indexOf(upg) !== -1) { + availableUpgrades.push(upg); + } + } + return availableUpgrades; + } - this.readyState = 'closing'; + /** + * Closes the socket and underlying transport. + * + * @param {Boolean} optional, discard + * @return {Socket} for chaining + * @api public + */ + close (discard) { + if ('open' !== this.readyState) return; + + this.readyState = 'closing'; + + if (this.writeBuffer.length) { + this.once('drain', this.closeTransport.bind(this, discard)); + return; + } - if (this.writeBuffer.length) { - this.once('drain', this.closeTransport.bind(this, discard)); - return; + this.closeTransport(discard); } - this.closeTransport(discard); -}; - -/** - * Closes the underlying transport. - * - * @param {Boolean} discard - * @api private - */ + /** + * Closes the underlying transport. + * + * @param {Boolean} discard + * @api private + */ + closeTransport (discard) { + if (discard) this.transport.discard(); + this.transport.close(this.onClose.bind(this, 'forced close')); + } +} -Socket.prototype.closeTransport = function (discard) { - if (discard) this.transport.discard(); - this.transport.close(this.onClose.bind(this, 'forced close')); -}; +module.exports = Socket; diff --git a/lib/transport.js b/lib/transport.js index 933dad5bb..0beed0a04 100644 --- a/lib/transport.js +++ b/lib/transport.js @@ -1,18 +1,6 @@ - -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter; -var parser = require('engine.io-parser'); -var util = require('util'); -var debug = require('debug')('engine:transport'); - -/** - * Expose the constructor. - */ - -module.exports = Transport; +const EventEmitter = require('events'); +const parser = require('engine.io-parser'); +const debug = require('debug')('engine:transport'); /** * Noop function. @@ -22,107 +10,98 @@ module.exports = Transport; function noop () {} -/** - * Transport constructor. - * - * @param {http.IncomingMessage} request - * @api public - */ - -function Transport (req) { - this.readyState = 'open'; - this.discarded = false; -} - -/** - * Inherits from EventEmitter. - */ - -util.inherits(Transport, EventEmitter); - -/** - * Flags the transport as discarded. - * - * @api private - */ - -Transport.prototype.discard = function () { - this.discarded = true; -}; - -/** - * Called with an incoming HTTP request. - * - * @param {http.IncomingMessage} request - * @api private - */ - -Transport.prototype.onRequest = function (req) { - debug('setting request'); - this.req = req; -}; - -/** - * Closes the transport. - * - * @api private - */ +class Transport extends EventEmitter { + /** + * Transport constructor. + * + * @param {http.IncomingMessage} request + * @api public + */ + constructor (req) { + super(); + this.readyState = 'open'; + this.discarded = false; + } -Transport.prototype.close = function (fn) { - if ('closed' === this.readyState || 'closing' === this.readyState) return; + /** + * Flags the transport as discarded. + * + * @api private + */ + discard () { + this.discarded = true; + } - this.readyState = 'closing'; - this.doClose(fn || noop); -}; + /** + * Called with an incoming HTTP request. + * + * @param {http.IncomingMessage} request + * @api private + */ + onRequest (req) { + debug('setting request'); + this.req = req; + } -/** - * Called with a transport error. - * - * @param {String} message error - * @param {Object} error description - * @api private - */ + /** + * Closes the transport. + * + * @api private + */ + close (fn) { + if ('closed' === this.readyState || 'closing' === this.readyState) return; -Transport.prototype.onError = function (msg, desc) { - if (this.listeners('error').length) { - var err = new Error(msg); - err.type = 'TransportError'; - err.description = desc; - this.emit('error', err); - } else { - debug('ignored transport error %s (%s)', msg, desc); + this.readyState = 'closing'; + this.doClose(fn || noop); } -}; - -/** - * Called with parsed out a packets from the data stream. - * - * @param {Object} packet - * @api private - */ -Transport.prototype.onPacket = function (packet) { - this.emit('packet', packet); -}; + /** + * Called with a transport error. + * + * @param {String} message error + * @param {Object} error description + * @api private + */ + onError (msg, desc) { + if (this.listeners('error').length) { + const err = new Error(msg); + err.type = 'TransportError'; + err.description = desc; + this.emit('error', err); + } else { + debug('ignored transport error %s (%s)', msg, desc); + } + } -/** - * Called with the encoded packet data. - * - * @param {String} data - * @api private - */ + /** + * Called with parsed out a packets from the data stream. + * + * @param {Object} packet + * @api private + */ + onPacket (packet) { + this.emit('packet', packet); + } -Transport.prototype.onData = function (data) { - this.onPacket(parser.decodePacket(data)); -}; + /** + * Called with the encoded packet data. + * + * @param {String} data + * @api private + */ + onData (data) { + this.onPacket(parser.decodePacket(data)); + } -/** - * Called upon transport close. - * - * @api private - */ + /** + * Called upon transport close. + * + * @api private + */ + onClose () { + this.readyState = 'closed'; + this.emit('close'); + } +} -Transport.prototype.onClose = function () { - this.readyState = 'closed'; - this.emit('close'); -}; +module.exports = Transport; diff --git a/lib/transports/index.js b/lib/transports/index.js index fcff3223a..0b6a40b42 100644 --- a/lib/transports/index.js +++ b/lib/transports/index.js @@ -1,10 +1,5 @@ - -/** - * Module dependencies. - */ - -var XHR = require('./polling-xhr'); -var JSONP = require('./polling-jsonp'); +const XHR = require('./polling-xhr'); +const JSONP = require('./polling-jsonp'); /** * Export transports. diff --git a/lib/transports/polling-jsonp.js b/lib/transports/polling-jsonp.js index 62e66e779..de3de36e7 100644 --- a/lib/transports/polling-jsonp.js +++ b/lib/transports/polling-jsonp.js @@ -1,75 +1,58 @@ - -/** - * Module dependencies. - */ - -var Polling = require('./polling'); -var qs = require('querystring'); -var rDoubleSlashes = /\\\\n/g; -var rSlashes = /(\\)?\\n/g; -var util = require('util'); - -/** - * Module exports. - */ - -module.exports = JSONP; - -/** - * JSON-P polling transport. - * - * @api public - */ - -function JSONP (req) { - Polling.call(this, req); - - this.head = '___eio[' + (req._query.j || '').replace(/[^0-9]/g, '') + ']('; - this.foot = ');'; -} - -/** - * Inherits from Polling. - */ - -util.inherits(JSONP, Polling); - -/** - * Handles incoming data. - * Due to a bug in \n handling by browsers, we expect a escaped string. - * - * @api private - */ - -JSONP.prototype.onData = function (data) { - // we leverage the qs module so that we get built-in DoS protection - // and the fast alternative to decodeURIComponent - data = qs.parse(data).d; - if ('string' === typeof data) { - // client will send already escaped newlines as \\\\n and newlines as \\n - // \\n must be replaced with \n and \\\\n with \\n - data = data.replace(rSlashes, function (match, slashes) { - return slashes ? match : '\n'; - }); - Polling.prototype.onData.call(this, data.replace(rDoubleSlashes, '\\n')); +const Polling = require('./polling'); +const qs = require('querystring'); +const rDoubleSlashes = /\\\\n/g; +const rSlashes = /(\\)?\\n/g; + +class JSONP extends Polling { + /** + * JSON-P polling transport. + * + * @api public + */ + constructor (req) { + super(req); + + this.head = '___eio[' + (req._query.j || '').replace(/[^0-9]/g, '') + ']('; + this.foot = ');'; } -}; - -/** - * Performs the write. - * - * @api private - */ -JSONP.prototype.doWrite = function (data, options, callback) { - // we must output valid javascript, not valid json - // see: http://timelessrepo.com/json-isnt-a-javascript-subset - var js = JSON.stringify(data) - .replace(/\u2028/g, '\\u2028') - .replace(/\u2029/g, '\\u2029'); + /** + * Handles incoming data. + * Due to a bug in \n handling by browsers, we expect a escaped string. + * + * @api private + */ + onData (data) { + // we leverage the qs module so that we get built-in DoS protection + // and the fast alternative to decodeURIComponent + data = qs.parse(data).d; + if ('string' === typeof data) { + // client will send already escaped newlines as \\\\n and newlines as \\n + // \\n must be replaced with \n and \\\\n with \\n + data = data.replace(rSlashes, function (match, slashes) { + return slashes ? match : '\n'; + }); + super.onData(data.replace(rDoubleSlashes, '\\n')); + } + } - // prepare response - data = this.head + js + this.foot; + /** + * Performs the write. + * + * @api private + */ + doWrite (data, options, callback) { + // we must output valid javascript, not valid json + // see: http://timelessrepo.com/json-isnt-a-javascript-subset + const js = JSON.stringify(data) + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029'); + + // prepare response + data = this.head + js + this.foot; + + super.doWrite(data, options, callback); + } +} - Polling.prototype.doWrite.call(this, data, options, callback); -}; +module.exports = JSONP; diff --git a/lib/transports/polling-xhr.js b/lib/transports/polling-xhr.js index 3562524e1..977e3c16d 100644 --- a/lib/transports/polling-xhr.js +++ b/lib/transports/polling-xhr.js @@ -1,69 +1,43 @@ - -/** - * Module dependencies. - */ - -var Polling = require('./polling'); -var util = require('util'); - -/** - * Module exports. - */ - -module.exports = XHR; - -/** - * Ajax polling transport. - * - * @api public - */ - -function XHR (req) { - Polling.call(this, req); -} - -/** - * Inherits from Polling. - */ - -util.inherits(XHR, Polling); - -/** - * Overrides `onRequest` to handle `OPTIONS`.. - * - * @param {http.IncomingMessage} - * @api private - */ - -XHR.prototype.onRequest = function (req) { - if ('OPTIONS' === req.method) { - var res = req.res; - var headers = this.headers(req); - headers['Access-Control-Allow-Headers'] = 'Content-Type'; - res.writeHead(200, headers); - res.end(); - } else { - Polling.prototype.onRequest.call(this, req); +const Polling = require('./polling'); + +class XHR extends Polling { + /** + * Overrides `onRequest` to handle `OPTIONS`.. + * + * @param {http.IncomingMessage} + * @api private + */ + onRequest (req) { + if ('OPTIONS' === req.method) { + const res = req.res; + const headers = this.headers(req); + headers['Access-Control-Allow-Headers'] = 'Content-Type'; + res.writeHead(200, headers); + res.end(); + } else { + super.onRequest(req); + } } -}; -/** - * Returns headers for a response. - * - * @param {http.IncomingMessage} request - * @param {Object} extra headers - * @api private - */ - -XHR.prototype.headers = function (req, headers) { - headers = headers || {}; - - if (req.headers.origin) { - headers['Access-Control-Allow-Credentials'] = 'true'; - headers['Access-Control-Allow-Origin'] = req.headers.origin; - } else { - headers['Access-Control-Allow-Origin'] = '*'; + /** + * Returns headers for a response. + * + * @param {http.IncomingMessage} request + * @param {Object} extra headers + * @api private + */ + headers (req, headers) { + headers = headers || {}; + + if (req.headers.origin) { + headers['Access-Control-Allow-Credentials'] = 'true'; + headers['Access-Control-Allow-Origin'] = req.headers.origin; + } else { + headers['Access-Control-Allow-Origin'] = '*'; + } + + return super.headers(req, headers); } +} - return Polling.prototype.headers.call(this, req, headers); -}; +module.exports = XHR; diff --git a/lib/transports/polling.js b/lib/transports/polling.js index 7c29c29ea..063360aaf 100644 --- a/lib/transports/polling.js +++ b/lib/transports/polling.js @@ -1,407 +1,380 @@ +const Transport = require('../transport'); +const parser = require('engine.io-parser'); +const zlib = require('zlib'); +const accepts = require('accepts'); +const debug = require('debug')('engine:polling'); -/** - * Module requirements. - */ - -var Transport = require('../transport'); -var parser = require('engine.io-parser'); -var zlib = require('zlib'); -var accepts = require('accepts'); -var util = require('util'); -var debug = require('debug')('engine:polling'); - -var compressionMethods = { +const compressionMethods = { gzip: zlib.createGzip, deflate: zlib.createDeflate }; -/** - * Exports the constructor. - */ - -module.exports = Polling; - -/** - * HTTP polling constructor. - * - * @api public. - */ - -function Polling (req) { - Transport.call(this, req); - - this.closeTimeout = 30 * 1000; - this.maxHttpBufferSize = null; - this.httpCompression = null; -} +class Polling extends Transport { + /** + * HTTP polling constructor. + * + * @api public. + */ + constructor (req) { + super(req); + + this.closeTimeout = 30 * 1000; + this.maxHttpBufferSize = null; + this.httpCompression = null; + } -/** - * Inherits from Transport. - * - * @api public. - */ - -util.inherits(Polling, Transport); - -/** - * Transport name - * - * @api public - */ - -Polling.prototype.name = 'polling'; - -/** - * Overrides onRequest. - * - * @param {http.IncomingMessage} - * @api private - */ - -Polling.prototype.onRequest = function (req) { - var res = req.res; - - if ('GET' === req.method) { - this.onPollRequest(req, res); - } else if ('POST' === req.method) { - this.onDataRequest(req, res); - } else { - res.writeHead(500); - res.end(); + /** + * Transport name + * + * @api public + */ + get name () { + return 'polling'; } -}; -/** - * The client sends a request awaiting for us to send data. - * - * @api private - */ - -Polling.prototype.onPollRequest = function (req, res) { - if (this.req) { - debug('request overlap'); - // assert: this.res, '.req and .res should be (un)set together' - this.onError('overlap from client'); - res.writeHead(500); - res.end(); - return; + /** + * Overrides onRequest. + * + * @param {http.IncomingMessage} + * @api private + */ + onRequest (req) { + const res = req.res; + + if ('GET' === req.method) { + this.onPollRequest(req, res); + } else if ('POST' === req.method) { + this.onDataRequest(req, res); + } else { + res.writeHead(500); + res.end(); + } } - debug('setting request'); + /** + * The client sends a request awaiting for us to send data. + * + * @api private + */ + onPollRequest (req, res) { + if (this.req) { + debug('request overlap'); + // assert: this.res, '.req and .res should be (un)set together' + this.onError('overlap from client'); + res.writeHead(500); + res.end(); + return; + } - this.req = req; - this.res = res; + debug('setting request'); - var self = this; + this.req = req; + this.res = res; - function onClose () { - self.onError('poll connection closed prematurely'); - } + const self = this; - function cleanup () { - req.removeListener('close', onClose); - self.req = self.res = null; - } + function onClose () { + self.onError('poll connection closed prematurely'); + } - req.cleanup = cleanup; - req.on('close', onClose); + function cleanup () { + req.removeListener('close', onClose); + self.req = self.res = null; + } - this.writable = true; - this.emit('drain'); + req.cleanup = cleanup; + req.on('close', onClose); - // if we're still writable but had a pending close, trigger an empty send - if (this.writable && this.shouldClose) { - debug('triggering empty send to append close packet'); - this.send([{ type: 'noop' }]); - } -}; + this.writable = true; + this.emit('drain'); -/** - * The client sends a request with data. - * - * @api private - */ - -Polling.prototype.onDataRequest = function (req, res) { - if (this.dataReq) { - // assert: this.dataRes, '.dataReq and .dataRes should be (un)set together' - this.onError('data request overlap from client'); - res.writeHead(500); - res.end(); - return; + // if we're still writable but had a pending close, trigger an empty send + if (this.writable && this.shouldClose) { + debug('triggering empty send to append close packet'); + this.send([{ type: 'noop' }]); + } } - var isBinary = 'application/octet-stream' === req.headers['content-type']; - - this.dataReq = req; - this.dataRes = res; + /** + * The client sends a request with data. + * + * @api private + */ + onDataRequest (req, res) { + if (this.dataReq) { + // assert: this.dataRes, '.dataReq and .dataRes should be (un)set together' + this.onError('data request overlap from client'); + res.writeHead(500); + res.end(); + return; + } - var chunks = isBinary ? Buffer.concat([]) : ''; - var self = this; + const isBinary = 'application/octet-stream' === req.headers['content-type']; - function cleanup () { - req.removeListener('data', onData); - req.removeListener('end', onEnd); - req.removeListener('close', onClose); - self.dataReq = self.dataRes = chunks = null; - } + this.dataReq = req; + this.dataRes = res; - function onClose () { - cleanup(); - self.onError('data request connection closed prematurely'); - } + let chunks = isBinary ? Buffer.concat([]) : ''; + const self = this; - function onData (data) { - var contentLength; - if (isBinary) { - chunks = Buffer.concat([chunks, data]); - contentLength = chunks.length; - } else { - chunks += data; - contentLength = Buffer.byteLength(chunks); + function cleanup () { + req.removeListener('data', onData); + req.removeListener('end', onEnd); + req.removeListener('close', onClose); + self.dataReq = self.dataRes = chunks = null; } - if (contentLength > self.maxHttpBufferSize) { - chunks = isBinary ? Buffer.concat([]) : ''; - req.connection.destroy(); + function onClose () { + cleanup(); + self.onError('data request connection closed prematurely'); } - } - function onEnd () { - self.onData(chunks); - - var headers = { - // text/html is required instead of text/plain to avoid an - // unwanted download dialog on certain user-agents (GH-43) - 'Content-Type': 'text/html', - 'Content-Length': 2 - }; + function onData (data) { + let contentLength; + if (isBinary) { + chunks = Buffer.concat([chunks, data]); + contentLength = chunks.length; + } else { + chunks += data; + contentLength = Buffer.byteLength(chunks); + } + + if (contentLength > self.maxHttpBufferSize) { + chunks = isBinary ? Buffer.concat([]) : ''; + req.connection.destroy(); + } + } - res.writeHead(200, self.headers(req, headers)); - res.end('ok'); - cleanup(); - } + function onEnd () { + self.onData(chunks); - req.on('close', onClose); - if (!isBinary) req.setEncoding('utf8'); - req.on('data', onData); - req.on('end', onEnd); -}; + const headers = { + // text/html is required instead of text/plain to avoid an + // unwanted download dialog on certain user-agents (GH-43) + 'Content-Type': 'text/html', + 'Content-Length': 2 + }; -/** - * Processes the incoming data payload. - * - * @param {String} encoded payload - * @api private - */ - -Polling.prototype.onData = function (data) { - debug('received "%s"', data); - var self = this; - var callback = function (packet) { - if ('close' === packet.type) { - debug('got xhr close packet'); - self.onClose(); - return false; + res.writeHead(200, self.headers(req, headers)); + res.end('ok'); + cleanup(); } - self.onPacket(packet); - }; - - parser.decodePayload(data, callback); -}; + req.on('close', onClose); + if (!isBinary) req.setEncoding('utf8'); + req.on('data', onData); + req.on('end', onEnd); + } -/** - * Overrides onClose. - * - * @api private - */ + /** + * Processes the incoming data payload. + * + * @param {String} encoded payload + * @api private + */ + onData (data) { + debug('received "%s"', data); + const self = this; + const callback = function (packet) { + if ('close' === packet.type) { + debug('got xhr close packet'); + self.onClose(); + return false; + } + + self.onPacket(packet); + }; -Polling.prototype.onClose = function () { - if (this.writable) { - // close pending poll request - this.send([{ type: 'noop' }]); + parser.decodePayload(data, callback); } - Transport.prototype.onClose.call(this); -}; -/** - * Writes a packet payload. - * - * @param {Object} packet - * @api private - */ - -Polling.prototype.send = function (packets) { - this.writable = false; - - if (this.shouldClose) { - debug('appending close packet to payload'); - packets.push({ type: 'close' }); - this.shouldClose(); - this.shouldClose = null; + /** + * Overrides onClose. + * + * @api private + */ + onClose () { + if (this.writable) { + // close pending poll request + this.send([{ type: 'noop' }]); + } + super.onClose(); } - var self = this; - parser.encodePayload(packets, this.supportsBinary, function (data) { - var compress = packets.some(function (packet) { - return packet.options && packet.options.compress; - }); - self.write(data, { compress: compress }); - }); -}; - -/** - * Writes data as response to poll request. - * - * @param {String} data - * @param {Object} options - * @api private - */ - -Polling.prototype.write = function (data, options) { - debug('writing "%s"', data); - var self = this; - this.doWrite(data, options, function () { - self.req.cleanup(); - }); -}; - -/** - * Performs the write. - * - * @api private - */ - -Polling.prototype.doWrite = function (data, options, callback) { - var self = this; - - // explicit UTF-8 is required for pages not served under utf - var isString = typeof data === 'string'; - var contentType = isString - ? 'text/plain; charset=UTF-8' - : 'application/octet-stream'; - - var headers = { - 'Content-Type': contentType - }; + /** + * Writes a packet payload. + * + * @param {Object} packet + * @api private + */ + send (packets) { + this.writable = false; + + if (this.shouldClose) { + debug('appending close packet to payload'); + packets.push({ type: 'close' }); + this.shouldClose(); + this.shouldClose = null; + } - if (!this.httpCompression || !options.compress) { - respond(data); - return; + const self = this; + parser.encodePayload(packets, this.supportsBinary, function (data) { + const compress = packets.some(function (packet) { + return packet.options && packet.options.compress; + }); + self.write(data, { compress: compress }); + }); } - var len = isString ? Buffer.byteLength(data) : data.length; - if (len < this.httpCompression.threshold) { - respond(data); - return; + /** + * Writes data as response to poll request. + * + * @param {String} data + * @param {Object} options + * @api private + */ + write (data, options) { + debug('writing "%s"', data); + const self = this; + this.doWrite(data, options, function () { + self.req.cleanup(); + }); } - var encoding = accepts(this.req).encodings(['gzip', 'deflate']); - if (!encoding) { - respond(data); - return; - } + /** + * Performs the write. + * + * @api private + */ + doWrite (data, options, callback) { + const self = this; + + // explicit UTF-8 is required for pages not served under utf + const isString = typeof data === 'string'; + const contentType = isString + ? 'text/plain; charset=UTF-8' + : 'application/octet-stream'; + + const headers = { + 'Content-Type': contentType + }; + + if (!this.httpCompression || !options.compress) { + respond(data); + return; + } + + const len = isString ? Buffer.byteLength(data) : data.length; + if (len < this.httpCompression.threshold) { + respond(data); + return; + } - this.compress(data, encoding, function (err, data) { - if (err) { - self.res.writeHead(500); - self.res.end(); - callback(err); + const encoding = accepts(this.req).encodings(['gzip', 'deflate']); + if (!encoding) { + respond(data); return; } - headers['Content-Encoding'] = encoding; - respond(data); - }); + this.compress(data, encoding, function (err, data) { + if (err) { + self.res.writeHead(500); + self.res.end(); + callback(err); + return; + } + + headers['Content-Encoding'] = encoding; + respond(data); + }); - function respond (data) { - headers['Content-Length'] = 'string' === typeof data ? Buffer.byteLength(data) : data.length; - self.res.writeHead(200, self.headers(self.req, headers)); - self.res.end(data); - callback(); + function respond (data) { + headers['Content-Length'] = 'string' === typeof data ? Buffer.byteLength(data) : data.length; + self.res.writeHead(200, self.headers(self.req, headers)); + self.res.end(data); + callback(); + } } -}; -/** - * Compresses data. - * - * @api private - */ - -Polling.prototype.compress = function (data, encoding, callback) { - debug('compressing'); - - var buffers = []; - var nread = 0; - - compressionMethods[encoding](this.httpCompression) - .on('error', callback) - .on('data', function (chunk) { - buffers.push(chunk); - nread += chunk.length; - }) - .on('end', function () { - callback(null, Buffer.concat(buffers, nread)); - }) - .end(data); -}; + /** + * Compresses data. + * + * @api private + */ + compress (data, encoding, callback) { + debug('compressing'); + + const buffers = []; + let nread = 0; + + compressionMethods[encoding](this.httpCompression) + .on('error', callback) + .on('data', function (chunk) { + buffers.push(chunk); + nread += chunk.length; + }) + .on('end', function () { + callback(null, Buffer.concat(buffers, nread)); + }) + .end(data); + } -/** - * Closes the transport. - * - * @api private - */ + /** + * Closes the transport. + * + * @api private + */ + doClose (fn) { + debug('closing'); -Polling.prototype.doClose = function (fn) { - debug('closing'); + const self = this; + let closeTimeoutTimer; - var self = this; - var closeTimeoutTimer; + if (this.dataReq) { + debug('aborting ongoing data request'); + this.dataReq.destroy(); + } - if (this.dataReq) { - debug('aborting ongoing data request'); - this.dataReq.destroy(); - } + if (this.writable) { + debug('transport writable - closing right away'); + this.send([{ type: 'close' }]); + onClose(); + } else if (this.discarded) { + debug('transport discarded - closing right away'); + onClose(); + } else { + debug('transport not writable - buffering orderly close'); + this.shouldClose = onClose; + closeTimeoutTimer = setTimeout(onClose, this.closeTimeout); + } - if (this.writable) { - debug('transport writable - closing right away'); - this.send([{ type: 'close' }]); - onClose(); - } else if (this.discarded) { - debug('transport discarded - closing right away'); - onClose(); - } else { - debug('transport not writable - buffering orderly close'); - this.shouldClose = onClose; - closeTimeoutTimer = setTimeout(onClose, this.closeTimeout); + function onClose () { + clearTimeout(closeTimeoutTimer); + fn(); + self.onClose(); + } } - function onClose () { - clearTimeout(closeTimeoutTimer); - fn(); - self.onClose(); - } -}; + /** + * Returns headers for a response. + * + * @param {http.IncomingMessage} request + * @param {Object} extra headers + * @api private + */ + headers (req, headers) { + headers = headers || {}; + + // prevent XSS warnings on IE + // https://github.com/LearnBoost/socket.io/pull/1333 + const ua = req.headers['user-agent']; + if (ua && (~ua.indexOf(';MSIE') || ~ua.indexOf('Trident/'))) { + headers['X-XSS-Protection'] = '0'; + } -/** - * Returns headers for a response. - * - * @param {http.IncomingMessage} request - * @param {Object} extra headers - * @api private - */ - -Polling.prototype.headers = function (req, headers) { - headers = headers || {}; - - // prevent XSS warnings on IE - // https://github.com/LearnBoost/socket.io/pull/1333 - var ua = req.headers['user-agent']; - if (ua && (~ua.indexOf(';MSIE') || ~ua.indexOf('Trident/'))) { - headers['X-XSS-Protection'] = '0'; + this.emit('headers', headers); + return headers; } +} - this.emit('headers', headers); - return headers; -}; +module.exports = Polling; diff --git a/lib/transports/websocket.js b/lib/transports/websocket.js index 7d5511b1d..ee228e9ee 100644 --- a/lib/transports/websocket.js +++ b/lib/transports/websocket.js @@ -1,134 +1,116 @@ - -/** - * Module dependencies. - */ - -var Transport = require('../transport'); -var parser = require('engine.io-parser'); -var util = require('util'); -var debug = require('debug')('engine:ws'); - -/** - * Export the constructor. - */ - -module.exports = WebSocket; - -/** - * WebSocket transport - * - * @param {http.IncomingMessage} - * @api public - */ - -function WebSocket (req) { - Transport.call(this, req); - var self = this; - this.socket = req.websocket; - this.socket.on('message', this.onData.bind(this)); - this.socket.once('close', this.onClose.bind(this)); - this.socket.on('error', this.onError.bind(this)); - this.socket.on('headers', onHeaders); - this.writable = true; - this.perMessageDeflate = null; - - function onHeaders (headers) { - self.emit('headers', headers); +const Transport = require('../transport'); +const parser = require('engine.io-parser'); +const debug = require('debug')('engine:ws'); + +class WebSocket extends Transport { + /** + * WebSocket transport + * + * @param {http.IncomingMessage} + * @api public + */ + constructor (req) { + super(req); + this.socket = req.websocket; + this.socket.on('message', this.onData.bind(this)); + this.socket.once('close', this.onClose.bind(this)); + this.socket.on('error', this.onError.bind(this)); + this.socket.on('headers', (headers) => { + this.emit('headers', headers); + }); + this.writable = true; + this.perMessageDeflate = null; } -} - -/** - * Inherits from Transport. - */ - -util.inherits(WebSocket, Transport); - -/** - * Transport name - * - * @api public - */ - -WebSocket.prototype.name = 'websocket'; - -/** - * Advertise upgrade support. - * - * @api public - */ -WebSocket.prototype.handlesUpgrades = true; - -/** - * Advertise framing support. - * - * @api public - */ + /** + * Transport name + * + * @api public + */ + get name () { + return 'websocket'; + } -WebSocket.prototype.supportsFraming = true; + /** + * Advertise upgrade support. + * + * @api public + */ + get handlesUpgrades () { + return true; + } -/** - * Processes the incoming data. - * - * @param {String} encoded packet - * @api private - */ + /** + * Advertise framing support. + * + * @api public + */ + get supportsFraming () { + return true; + } -WebSocket.prototype.onData = function (data) { - debug('received "%s"', data); - Transport.prototype.onData.call(this, data); -}; + /** + * Processes the incoming data. + * + * @param {String} encoded packet + * @api private + */ + onData (data) { + debug('received "%s"', data); + super.onData(data); + } -/** - * Writes a packet payload. - * - * @param {Array} packets - * @api private - */ + /** + * Writes a packet payload. + * + * @param {Array} packets + * @api private + */ + send (packets) { + var self = this; + + for (var i = 0; i < packets.length; i++) { + var packet = packets[i]; + parser.encodePacket(packet, self.supportsBinary, send); + } -WebSocket.prototype.send = function (packets) { - var self = this; + function send (data) { + debug('writing "%s"', data); - for (var i = 0; i < packets.length; i++) { - var packet = packets[i]; - parser.encodePacket(packet, self.supportsBinary, send); - } + // always creates a new object since ws modifies it + var opts = {}; + if (packet.options) { + opts.compress = packet.options.compress; + } - function send (data) { - debug('writing "%s"', data); + if (self.perMessageDeflate) { + var len = 'string' === typeof data ? Buffer.byteLength(data) : data.length; + if (len < self.perMessageDeflate.threshold) { + opts.compress = false; + } + } - // always creates a new object since ws modifies it - var opts = {}; - if (packet.options) { - opts.compress = packet.options.compress; + self.writable = false; + self.socket.send(data, opts, onEnd); } - if (self.perMessageDeflate) { - var len = 'string' === typeof data ? Buffer.byteLength(data) : data.length; - if (len < self.perMessageDeflate.threshold) { - opts.compress = false; - } + function onEnd (err) { + if (err) return self.onError('write error', err.stack); + self.writable = true; + self.emit('drain'); } - - self.writable = false; - self.socket.send(data, opts, onEnd); } - function onEnd (err) { - if (err) return self.onError('write error', err.stack); - self.writable = true; - self.emit('drain'); + /** + * Closes the transport. + * + * @api private + */ + doClose (fn) { + debug('closing'); + this.socket.close(); + fn && fn(); } -}; - -/** - * Closes the transport. - * - * @api private - */ +} -WebSocket.prototype.doClose = function (fn) { - debug('closing'); - this.socket.close(); - fn && fn(); -}; +module.exports = WebSocket; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..542c3b12f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2780 @@ +{ + "name": "engine.io", + "version": "3.4.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "@babel/generator": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz", + "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44", + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-function-name": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz", + "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "7.0.0-beta.44", + "@babel/template": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz", + "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz", + "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "@babel/template": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", + "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "lodash": "^4.2.0" + } + }, + "@babel/traverse": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz", + "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/generator": "7.0.0-beta.44", + "@babel/helper-function-name": "7.0.0-beta.44", + "@babel/helper-split-export-declaration": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "debug": "^3.1.0", + "globals": "^11.1.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@babel/types": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz", + "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "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.0.4" + }, + "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 + } + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "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.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "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 + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "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": "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.0" + } + }, + "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.2" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "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": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "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.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "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 + } + } + }, + "babel-eslint": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", + "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/traverse": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "^0.10.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.24.1", + "babel-plugin-transform-es2015-classes": "^6.24.1", + "babel-plugin-transform-es2015-computed-properties": "^6.24.1", + "babel-plugin-transform-es2015-destructuring": "^6.22.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", + "babel-plugin-transform-es2015-for-of": "^6.22.0", + "babel-plugin-transform-es2015-function-name": "^6.24.1", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-umd": "^6.24.1", + "babel-plugin-transform-es2015-object-super": "^6.24.1", + "babel-plugin-transform-es2015-parameters": "^6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", + "babel-plugin-transform-regenerator": "^6.24.1" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + }, + "dependencies": { + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + } + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + } + } + }, + "babylon": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", + "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", + "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 + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, + "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" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "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" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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 + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "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.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "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.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "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 + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "dev": true + }, + "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" + } + }, + "engine.io-client": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz", + "integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", + "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", + "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.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.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "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.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "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.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.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 + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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" + } + } + } + }, + "eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", + "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.1.tgz", + "integrity": "sha512-GcNwsYv8MfoEBSbAmV+PSVn2RlhpCShbLImtNviAYa/LE0PgNqxH5tLi1Ld9yeFwdjHsarXK+7G9vsyddmB6dw==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz", + "integrity": "sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", + "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", + "dev": true, + "requires": { + "ignore": "^3.3.6", + "minimatch": "^3.0.4", + "resolve": "^1.3.3", + "semver": "5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz", + "integrity": "sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ==", + "dev": true + }, + "eslint-plugin-standard": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", + "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", + "dev": true + }, + "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.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "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.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "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.0.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.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "expect.js": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/expect.js/-/expect.js-0.3.1.tgz", + "integrity": "sha1-sKWaDS7/VDdUTr8M6qYBWEHQm1s=", + "dev": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "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.0", + "iconv-lite": "^0.4.17", + "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.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "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.2.1", + "object-assign": "^4.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", + "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 + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "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 + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "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 + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "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.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "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.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + }, + "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-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" + } + } + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "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-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-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "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 + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "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.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "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 + }, + "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" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" + }, + "mime-types": { + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", + "requires": { + "mime-db": "1.42.0" + } + }, + "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.7" + } + }, + "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" + } + }, + "mocha": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", + "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "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" + } + }, + "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.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "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 + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "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-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "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.0.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "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", + "word-wrap": "~1.2.3" + } + }, + "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 + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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 + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "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 + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "qs": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "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.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "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.0" + } + }, + "resolve": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", + "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "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": "*" + } + }, + "s": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/s/-/s-0.1.1.tgz", + "integrity": "sha1-bfd3XSqyF2/xMZE/Qn7dtDAvrAw=", + "dev": true + }, + "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.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "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" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "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" + }, + "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-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" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "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.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.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "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 + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "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.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.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" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "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 + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uws": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", + "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "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" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "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" + } + }, + "ws": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz", + "integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==", + "requires": { + "async-limiter": "^1.0.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + } + } +}