aboutsummaryrefslogtreecommitdiffhomepage
path: root/node_modules/engine.io-client/lib
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/engine.io-client/lib')
-rw-r--r--node_modules/engine.io-client/lib/index.js10
-rw-r--r--node_modules/engine.io-client/lib/socket.js743
-rw-r--r--node_modules/engine.io-client/lib/transport.js157
-rw-r--r--node_modules/engine.io-client/lib/transports/index.js53
-rw-r--r--node_modules/engine.io-client/lib/transports/polling-jsonp.js231
-rw-r--r--node_modules/engine.io-client/lib/transports/polling-xhr.js413
-rw-r--r--node_modules/engine.io-client/lib/transports/polling.js245
-rw-r--r--node_modules/engine.io-client/lib/transports/websocket.js286
-rw-r--r--node_modules/engine.io-client/lib/xmlhttprequest.js37
9 files changed, 2175 insertions, 0 deletions
diff --git a/node_modules/engine.io-client/lib/index.js b/node_modules/engine.io-client/lib/index.js
new file mode 100644
index 0000000..0bf4058
--- /dev/null
+++ b/node_modules/engine.io-client/lib/index.js
@@ -0,0 +1,10 @@
+
+module.exports = require('./socket');
+
+/**
+ * Exports parser
+ *
+ * @api public
+ *
+ */
+module.exports.parser = require('engine.io-parser');
diff --git a/node_modules/engine.io-client/lib/socket.js b/node_modules/engine.io-client/lib/socket.js
new file mode 100644
index 0000000..d2eb44c
--- /dev/null
+++ b/node_modules/engine.io-client/lib/socket.js
@@ -0,0 +1,743 @@
+/**
+ * Module dependencies.
+ */
+
+var transports = require('./transports/index');
+var Emitter = require('component-emitter');
+var debug = require('debug')('engine.io-client:socket');
+var index = require('indexof');
+var parser = require('engine.io-parser');
+var parseuri = require('parseuri');
+var parseqs = require('parseqs');
+
+/**
+ * Module exports.
+ */
+
+module.exports = Socket;
+
+/**
+ * Socket constructor.
+ *
+ * @param {String|Object} uri or options
+ * @param {Object} options
+ * @api public
+ */
+
+function Socket (uri, opts) {
+ if (!(this instanceof Socket)) return new Socket(uri, opts);
+
+ opts = opts || {};
+
+ if (uri && 'object' === typeof uri) {
+ opts = uri;
+ uri = null;
+ }
+
+ if (uri) {
+ uri = parseuri(uri);
+ opts.hostname = uri.host;
+ opts.secure = uri.protocol === 'https' || uri.protocol === 'wss';
+ opts.port = uri.port;
+ if (uri.query) opts.query = uri.query;
+ } else if (opts.host) {
+ opts.hostname = parseuri(opts.host).host;
+ }
+
+ this.secure = null != opts.secure ? opts.secure
+ : (global.location && 'https:' === location.protocol);
+
+ if (opts.hostname && !opts.port) {
+ // if no port is specified manually, use the protocol default
+ opts.port = this.secure ? '443' : '80';
+ }
+
+ this.agent = opts.agent || false;
+ this.hostname = opts.hostname ||
+ (global.location ? location.hostname : 'localhost');
+ this.port = opts.port || (global.location && location.port
+ ? location.port
+ : (this.secure ? 443 : 80));
+ this.query = opts.query || {};
+ if ('string' === typeof this.query) this.query = parseqs.decode(this.query);
+ this.upgrade = false !== opts.upgrade;
+ this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
+ this.forceJSONP = !!opts.forceJSONP;
+ this.jsonp = false !== opts.jsonp;
+ this.forceBase64 = !!opts.forceBase64;
+ this.enablesXDR = !!opts.enablesXDR;
+ this.timestampParam = opts.timestampParam || 't';
+ this.timestampRequests = opts.timestampRequests;
+ this.transports = opts.transports || ['polling', 'websocket'];
+ this.transportOptions = opts.transportOptions || {};
+ this.readyState = '';
+ this.writeBuffer = [];
+ this.prevBufferLen = 0;
+ this.policyPort = opts.policyPort || 843;
+ this.rememberUpgrade = opts.rememberUpgrade || false;
+ this.binaryType = null;
+ this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades;
+ this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || {}) : false;
+
+ if (true === this.perMessageDeflate) this.perMessageDeflate = {};
+ if (this.perMessageDeflate && null == this.perMessageDeflate.threshold) {
+ this.perMessageDeflate.threshold = 1024;
+ }
+
+ // SSL options for Node.js client
+ this.pfx = opts.pfx || null;
+ this.key = opts.key || null;
+ this.passphrase = opts.passphrase || null;
+ this.cert = opts.cert || null;
+ this.ca = opts.ca || null;
+ this.ciphers = opts.ciphers || null;
+ this.rejectUnauthorized = opts.rejectUnauthorized === undefined ? true : opts.rejectUnauthorized;
+ this.forceNode = !!opts.forceNode;
+
+ // other options for Node.js client
+ var freeGlobal = typeof global === 'object' && global;
+ if (freeGlobal.global === freeGlobal) {
+ if (opts.extraHeaders && Object.keys(opts.extraHeaders).length > 0) {
+ this.extraHeaders = opts.extraHeaders;
+ }
+
+ if (opts.localAddress) {
+ this.localAddress = opts.localAddress;
+ }
+ }
+
+ // set on handshake
+ this.id = null;
+ this.upgrades = null;
+ this.pingInterval = null;
+ this.pingTimeout = null;
+
+ // set on heartbeat
+ this.pingIntervalTimer = null;
+ this.pingTimeoutTimer = null;
+
+ this.open();
+}
+
+Socket.priorWebsocketSuccess = false;
+
+/**
+ * Mix in `Emitter`.
+ */
+
+Emitter(Socket.prototype);
+
+/**
+ * Protocol version.
+ *
+ * @api public
+ */
+
+Socket.protocol = parser.protocol; // this is an int
+
+/**
+ * Expose deps for legacy compatibility
+ * and standalone browser access.
+ */
+
+Socket.Socket = Socket;
+Socket.Transport = require('./transport');
+Socket.transports = require('./transports/index');
+Socket.parser = require('engine.io-parser');
+
+/**
+ * Creates transport of the given type.
+ *
+ * @param {String} transport name
+ * @return {Transport}
+ * @api private
+ */
+
+Socket.prototype.createTransport = function (name) {
+ debug('creating transport "%s"', name);
+ var query = clone(this.query);
+
+ // append engine.io protocol identifier
+ query.EIO = parser.protocol;
+
+ // transport name
+ query.transport = name;
+
+ // per-transport options
+ var options = this.transportOptions[name] || {};
+
+ // session id if we already have one
+ if (this.id) query.sid = this.id;
+
+ var transport = new transports[name]({
+ query: query,
+ socket: this,
+ agent: options.agent || this.agent,
+ hostname: options.hostname || this.hostname,
+ port: options.port || this.port,
+ secure: options.secure || this.secure,
+ path: options.path || this.path,
+ forceJSONP: options.forceJSONP || this.forceJSONP,
+ jsonp: options.jsonp || this.jsonp,
+ forceBase64: options.forceBase64 || this.forceBase64,
+ enablesXDR: options.enablesXDR || this.enablesXDR,
+ timestampRequests: options.timestampRequests || this.timestampRequests,
+ timestampParam: options.timestampParam || this.timestampParam,
+ policyPort: options.policyPort || this.policyPort,
+ pfx: options.pfx || this.pfx,
+ key: options.key || this.key,
+ passphrase: options.passphrase || this.passphrase,
+ cert: options.cert || this.cert,
+ ca: options.ca || this.ca,
+ ciphers: options.ciphers || this.ciphers,
+ rejectUnauthorized: options.rejectUnauthorized || this.rejectUnauthorized,
+ perMessageDeflate: options.perMessageDeflate || this.perMessageDeflate,
+ extraHeaders: options.extraHeaders || this.extraHeaders,
+ forceNode: options.forceNode || this.forceNode,
+ localAddress: options.localAddress || this.localAddress,
+ requestTimeout: options.requestTimeout || this.requestTimeout,
+ protocols: options.protocols || void (0)
+ });
+
+ return transport;
+};
+
+function clone (obj) {
+ var o = {};
+ for (var i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ o[i] = obj[i];
+ }
+ }
+ return o;
+}
+
+/**
+ * Initializes transport to use and starts probe.
+ *
+ * @api private
+ */
+Socket.prototype.open = function () {
+ var transport;
+ if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') !== -1) {
+ transport = 'websocket';
+ } else if (0 === this.transports.length) {
+ // Emit error on next tick so it can be listened to
+ var self = this;
+ setTimeout(function () {
+ self.emit('error', 'No transports available');
+ }, 0);
+ return;
+ } else {
+ transport = this.transports[0];
+ }
+ this.readyState = 'opening';
+
+ // Retry with the next transport if the transport is disabled (jsonp: false)
+ try {
+ transport = this.createTransport(transport);
+ } catch (e) {
+ this.transports.shift();
+ this.open();
+ return;
+ }
+
+ transport.open();
+ this.setTransport(transport);
+};
+
+/**
+ * Sets the current transport. Disables the existing one (if any).
+ *
+ * @api private
+ */
+
+Socket.prototype.setTransport = function (transport) {
+ debug('setting transport %s', transport.name);
+ var self = this;
+
+ if (this.transport) {
+ debug('clearing existing transport %s', this.transport.name);
+ this.transport.removeAllListeners();
+ }
+
+ // set up transport
+ this.transport = transport;
+
+ // set up transport listeners
+ transport
+ .on('drain', function () {
+ self.onDrain();
+ })
+ .on('packet', function (packet) {
+ self.onPacket(packet);
+ })
+ .on('error', function (e) {
+ self.onError(e);
+ })
+ .on('close', function () {
+ self.onClose('transport close');
+ });
+};
+
+/**
+ * Probes a transport.
+ *
+ * @param {String} transport name
+ * @api private
+ */
+
+Socket.prototype.probe = function (name) {
+ debug('probing transport "%s"', name);
+ var transport = this.createTransport(name, { probe: 1 });
+ var failed = false;
+ var self = this;
+
+ Socket.priorWebsocketSuccess = false;
+
+ function onTransportOpen () {
+ if (self.onlyBinaryUpgrades) {
+ var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary;
+ failed = failed || upgradeLosesBinary;
+ }
+ if (failed) return;
+
+ debug('probe transport "%s" opened', name);
+ transport.send([{ type: 'ping', data: 'probe' }]);
+ transport.once('packet', function (msg) {
+ if (failed) return;
+ if ('pong' === msg.type && 'probe' === msg.data) {
+ debug('probe transport "%s" pong', name);
+ self.upgrading = true;
+ self.emit('upgrading', transport);
+ if (!transport) return;
+ Socket.priorWebsocketSuccess = 'websocket' === transport.name;
+
+ debug('pausing current transport "%s"', self.transport.name);
+ self.transport.pause(function () {
+ if (failed) return;
+ if ('closed' === self.readyState) return;
+ debug('changing transport and sending upgrade packet');
+
+ cleanup();
+
+ self.setTransport(transport);
+ transport.send([{ type: 'upgrade' }]);
+ self.emit('upgrade', transport);
+ transport = null;
+ self.upgrading = false;
+ self.flush();
+ });
+ } else {
+ debug('probe transport "%s" failed', name);
+ var err = new Error('probe error');
+ err.transport = transport.name;
+ self.emit('upgradeError', err);
+ }
+ });
+ }
+
+ function freezeTransport () {
+ if (failed) return;
+
+ // Any callback called by transport should be ignored since now
+ failed = true;
+
+ cleanup();
+
+ transport.close();
+ transport = null;
+ }
+
+ // Handle any error that happens while probing
+ function onerror (err) {
+ var error = new Error('probe error: ' + err);
+ error.transport = transport.name;
+
+ freezeTransport();
+
+ debug('probe transport "%s" failed because of error: %s', name, err);
+
+ self.emit('upgradeError', error);
+ }
+
+ function onTransportClose () {
+ onerror('transport closed');
+ }
+
+ // When the socket is closed while we're probing
+ function onclose () {
+ onerror('socket closed');
+ }
+
+ // When the socket is upgraded while we're probing
+ function onupgrade (to) {
+ if (transport && to.name !== transport.name) {
+ debug('"%s" works - aborting "%s"', to.name, transport.name);
+ freezeTransport();
+ }
+ }
+
+ // Remove all listeners on the transport and on self
+ function cleanup () {
+ transport.removeListener('open', onTransportOpen);
+ transport.removeListener('error', onerror);
+ transport.removeListener('close', onTransportClose);
+ self.removeListener('close', onclose);
+ self.removeListener('upgrading', onupgrade);
+ }
+
+ transport.once('open', onTransportOpen);
+ transport.once('error', onerror);
+ transport.once('close', onTransportClose);
+
+ this.once('close', onclose);
+ this.once('upgrading', onupgrade);
+
+ transport.open();
+};
+
+/**
+ * Called when connection is deemed open.
+ *
+ * @api public
+ */
+
+Socket.prototype.onOpen = function () {
+ debug('socket open');
+ this.readyState = 'open';
+ Socket.priorWebsocketSuccess = 'websocket' === this.transport.name;
+ this.emit('open');
+ this.flush();
+
+ // we check for `readyState` in case an `open`
+ // listener already closed the socket
+ if ('open' === this.readyState && this.upgrade && this.transport.pause) {
+ debug('starting upgrade probes');
+ for (var i = 0, l = this.upgrades.length; i < l; i++) {
+ this.probe(this.upgrades[i]);
+ }
+ }
+};
+
+/**
+ * Handles a packet.
+ *
+ * @api private
+ */
+
+Socket.prototype.onPacket = function (packet) {
+ if ('opening' === this.readyState || 'open' === this.readyState ||
+ 'closing' === this.readyState) {
+ debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
+
+ this.emit('packet', packet);
+
+ // Socket is live - any packet counts
+ this.emit('heartbeat');
+
+ switch (packet.type) {
+ case 'open':
+ this.onHandshake(JSON.parse(packet.data));
+ break;
+
+ case 'pong':
+ this.setPing();
+ this.emit('pong');
+ break;
+
+ case 'error':
+ var err = new Error('server error');
+ err.code = packet.data;
+ this.onError(err);
+ break;
+
+ case 'message':
+ this.emit('data', packet.data);
+ this.emit('message', packet.data);
+ break;
+ }
+ } else {
+ debug('packet received with socket readyState "%s"', this.readyState);
+ }
+};
+
+/**
+ * Called upon handshake completion.
+ *
+ * @param {Object} handshake obj
+ * @api private
+ */
+
+Socket.prototype.onHandshake = function (data) {
+ this.emit('handshake', data);
+ this.id = data.sid;
+ this.transport.query.sid = data.sid;
+ this.upgrades = this.filterUpgrades(data.upgrades);
+ this.pingInterval = data.pingInterval;
+ this.pingTimeout = data.pingTimeout;
+ this.onOpen();
+ // In case open handler closes socket
+ if ('closed' === this.readyState) return;
+ this.setPing();
+
+ // Prolong liveness of socket on heartbeat
+ this.removeListener('heartbeat', this.onHeartbeat);
+ this.on('heartbeat', this.onHeartbeat);
+};
+
+/**
+ * Resets ping timeout.
+ *
+ * @api private
+ */
+
+Socket.prototype.onHeartbeat = function (timeout) {
+ clearTimeout(this.pingTimeoutTimer);
+ var self = this;
+ self.pingTimeoutTimer = setTimeout(function () {
+ if ('closed' === self.readyState) return;
+ self.onClose('ping timeout');
+ }, timeout || (self.pingInterval + self.pingTimeout));
+};
+
+/**
+ * Pings server every `this.pingInterval` and expects response
+ * within `this.pingTimeout` or closes connection.
+ *
+ * @api private
+ */
+
+Socket.prototype.setPing = function () {
+ var self = this;
+ clearTimeout(self.pingIntervalTimer);
+ self.pingIntervalTimer = setTimeout(function () {
+ debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
+ self.ping();
+ self.onHeartbeat(self.pingTimeout);
+ }, self.pingInterval);
+};
+
+/**
+* Sends a ping packet.
+*
+* @api private
+*/
+
+Socket.prototype.ping = function () {
+ var self = this;
+ this.sendPacket('ping', function () {
+ self.emit('ping');
+ });
+};
+
+/**
+ * Called on `drain` event
+ *
+ * @api private
+ */
+
+Socket.prototype.onDrain = function () {
+ this.writeBuffer.splice(0, this.prevBufferLen);
+
+ // setting prevBufferLen = 0 is very important
+ // for example, when upgrading, upgrade packet is sent over,
+ // and a nonzero prevBufferLen could cause problems on `drain`
+ this.prevBufferLen = 0;
+
+ if (0 === this.writeBuffer.length) {
+ this.emit('drain');
+ } else {
+ this.flush();
+ }
+};
+
+/**
+ * Flush write buffers.
+ *
+ * @api private
+ */
+
+Socket.prototype.flush = function () {
+ if ('closed' !== this.readyState && this.transport.writable &&
+ !this.upgrading && this.writeBuffer.length) {
+ debug('flushing %d packets in socket', this.writeBuffer.length);
+ this.transport.send(this.writeBuffer);
+ // keep track of current length of writeBuffer
+ // splice writeBuffer and callbackBuffer on `drain`
+ this.prevBufferLen = this.writeBuffer.length;
+ this.emit('flush');
+ }
+};
+
+/**
+ * Sends a message.
+ *
+ * @param {String} message.
+ * @param {Function} callback function.
+ * @param {Object} options.
+ * @return {Socket} for chaining.
+ * @api public
+ */
+
+Socket.prototype.write =
+Socket.prototype.send = function (msg, options, fn) {
+ this.sendPacket('message', msg, options, fn);
+ return this;
+};
+
+/**
+ * Sends a packet.
+ *
+ * @param {String} packet type.
+ * @param {String} data.
+ * @param {Object} options.
+ * @param {Function} callback function.
+ * @api private
+ */
+
+Socket.prototype.sendPacket = function (type, data, options, fn) {
+ if ('function' === typeof data) {
+ fn = data;
+ data = undefined;
+ }
+
+ if ('function' === typeof options) {
+ fn = options;
+ options = null;
+ }
+
+ if ('closing' === this.readyState || 'closed' === this.readyState) {
+ return;
+ }
+
+ options = options || {};
+ options.compress = false !== options.compress;
+
+ var packet = {
+ type: type,
+ data: data,
+ options: options
+ };
+ this.emit('packetCreate', packet);
+ this.writeBuffer.push(packet);
+ if (fn) this.once('flush', fn);
+ this.flush();
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+Socket.prototype.close = function () {
+ if ('opening' === this.readyState || 'open' === this.readyState) {
+ this.readyState = 'closing';
+
+ var self = this;
+
+ if (this.writeBuffer.length) {
+ this.once('drain', function () {
+ if (this.upgrading) {
+ waitForUpgrade();
+ } else {
+ close();
+ }
+ });
+ } else if (this.upgrading) {
+ waitForUpgrade();
+ } else {
+ close();
+ }
+ }
+
+ function close () {
+ self.onClose('forced close');
+ debug('socket closing - telling transport to close');
+ self.transport.close();
+ }
+
+ function cleanupAndClose () {
+ self.removeListener('upgrade', cleanupAndClose);
+ self.removeListener('upgradeError', cleanupAndClose);
+ close();
+ }
+
+ function waitForUpgrade () {
+ // wait for upgrade to finish since we can't send packets while pausing a transport
+ self.once('upgrade', cleanupAndClose);
+ self.once('upgradeError', cleanupAndClose);
+ }
+
+ return this;
+};
+
+/**
+ * Called upon transport error
+ *
+ * @api private
+ */
+
+Socket.prototype.onError = function (err) {
+ debug('socket error %j', err);
+ Socket.priorWebsocketSuccess = false;
+ this.emit('error', err);
+ this.onClose('transport error', err);
+};
+
+/**
+ * Called upon transport close.
+ *
+ * @api private
+ */
+
+Socket.prototype.onClose = function (reason, desc) {
+ if ('opening' === this.readyState || 'open' === this.readyState || 'closing' === this.readyState) {
+ debug('socket close with reason: "%s"', reason);
+ var self = this;
+
+ // clear timers
+ clearTimeout(this.pingIntervalTimer);
+ clearTimeout(this.pingTimeoutTimer);
+
+ // stop event from firing again for transport
+ this.transport.removeAllListeners('close');
+
+ // ensure transport won't stay open
+ this.transport.close();
+
+ // ignore further transport communication
+ this.transport.removeAllListeners();
+
+ // set ready state
+ this.readyState = 'closed';
+
+ // clear session id
+ this.id = null;
+
+ // emit close event
+ this.emit('close', reason, desc);
+
+ // clean buffers after, so users can still
+ // grab the buffers on `close` event
+ self.writeBuffer = [];
+ self.prevBufferLen = 0;
+ }
+};
+
+/**
+ * Filters upgrades, returning only those matching client transports.
+ *
+ * @param {Array} server upgrades
+ * @api private
+ *
+ */
+
+Socket.prototype.filterUpgrades = function (upgrades) {
+ var filteredUpgrades = [];
+ for (var i = 0, j = upgrades.length; i < j; i++) {
+ if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]);
+ }
+ return filteredUpgrades;
+};
diff --git a/node_modules/engine.io-client/lib/transport.js b/node_modules/engine.io-client/lib/transport.js
new file mode 100644
index 0000000..f2a90a4
--- /dev/null
+++ b/node_modules/engine.io-client/lib/transport.js
@@ -0,0 +1,157 @@
+/**
+ * Module dependencies.
+ */
+
+var parser = require('engine.io-parser');
+var Emitter = require('component-emitter');
+
+/**
+ * Module exports.
+ */
+
+module.exports = Transport;
+
+/**
+ * Transport abstract constructor.
+ *
+ * @param {Object} options.
+ * @api private
+ */
+
+function Transport (opts) {
+ this.path = opts.path;
+ this.hostname = opts.hostname;
+ this.port = opts.port;
+ this.secure = opts.secure;
+ this.query = opts.query;
+ this.timestampParam = opts.timestampParam;
+ this.timestampRequests = opts.timestampRequests;
+ this.readyState = '';
+ this.agent = opts.agent || false;
+ this.socket = opts.socket;
+ this.enablesXDR = opts.enablesXDR;
+
+ // SSL options for Node.js client
+ this.pfx = opts.pfx;
+ this.key = opts.key;
+ this.passphrase = opts.passphrase;
+ this.cert = opts.cert;
+ this.ca = opts.ca;
+ this.ciphers = opts.ciphers;
+ this.rejectUnauthorized = opts.rejectUnauthorized;
+ this.forceNode = opts.forceNode;
+
+ // other options for Node.js client
+ this.extraHeaders = opts.extraHeaders;
+ this.localAddress = opts.localAddress;
+}
+
+/**
+ * Mix in `Emitter`.
+ */
+
+Emitter(Transport.prototype);
+
+/**
+ * Emits an error.
+ *
+ * @param {String} str
+ * @return {Transport} for chaining
+ * @api public
+ */
+
+Transport.prototype.onError = function (msg, desc) {
+ var err = new Error(msg);
+ err.type = 'TransportError';
+ err.description = desc;
+ this.emit('error', err);
+ return this;
+};
+
+/**
+ * Opens the transport.
+ *
+ * @api public
+ */
+
+Transport.prototype.open = function () {
+ if ('closed' === this.readyState || '' === this.readyState) {
+ this.readyState = 'opening';
+ this.doOpen();
+ }
+
+ return this;
+};
+
+/**
+ * Closes the transport.
+ *
+ * @api private
+ */
+
+Transport.prototype.close = function () {
+ if ('opening' === this.readyState || 'open' === this.readyState) {
+ this.doClose();
+ this.onClose();
+ }
+
+ return this;
+};
+
+/**
+ * Sends multiple packets.
+ *
+ * @param {Array} packets
+ * @api private
+ */
+
+Transport.prototype.send = function (packets) {
+ if ('open' === this.readyState) {
+ this.write(packets);
+ } else {
+ throw new Error('Transport not open');
+ }
+};
+
+/**
+ * Called upon open
+ *
+ * @api private
+ */
+
+Transport.prototype.onOpen = function () {
+ this.readyState = 'open';
+ this.writable = true;
+ this.emit('open');
+};
+
+/**
+ * Called with data.
+ *
+ * @param {String} data
+ * @api private
+ */
+
+Transport.prototype.onData = function (data) {
+ var packet = parser.decodePacket(data, this.socket.binaryType);
+ this.onPacket(packet);
+};
+
+/**
+ * Called with a decoded packet.
+ */
+
+Transport.prototype.onPacket = function (packet) {
+ this.emit('packet', packet);
+};
+
+/**
+ * Called upon close.
+ *
+ * @api private
+ */
+
+Transport.prototype.onClose = function () {
+ this.readyState = 'closed';
+ this.emit('close');
+};
diff --git a/node_modules/engine.io-client/lib/transports/index.js b/node_modules/engine.io-client/lib/transports/index.js
new file mode 100644
index 0000000..df68fb9
--- /dev/null
+++ b/node_modules/engine.io-client/lib/transports/index.js
@@ -0,0 +1,53 @@
+/**
+ * Module dependencies
+ */
+
+var XMLHttpRequest = require('xmlhttprequest-ssl');
+var XHR = require('./polling-xhr');
+var JSONP = require('./polling-jsonp');
+var websocket = require('./websocket');
+
+/**
+ * Export transports.
+ */
+
+exports.polling = polling;
+exports.websocket = websocket;
+
+/**
+ * Polling transport polymorphic constructor.
+ * Decides on xhr vs jsonp based on feature detection.
+ *
+ * @api private
+ */
+
+function polling (opts) {
+ var xhr;
+ var xd = false;
+ var xs = false;
+ var jsonp = false !== opts.jsonp;
+
+ if (global.location) {
+ var isSSL = 'https:' === location.protocol;
+ var port = location.port;
+
+ // some user agents have empty `location.port`
+ if (!port) {
+ port = isSSL ? 443 : 80;
+ }
+
+ xd = opts.hostname !== location.hostname || port !== opts.port;
+ xs = opts.secure !== isSSL;
+ }
+
+ opts.xdomain = xd;
+ opts.xscheme = xs;
+ xhr = new XMLHttpRequest(opts);
+
+ if ('open' in xhr && !opts.forceJSONP) {
+ return new XHR(opts);
+ } else {
+ if (!jsonp) throw new Error('JSONP disabled');
+ return new JSONP(opts);
+ }
+}
diff --git a/node_modules/engine.io-client/lib/transports/polling-jsonp.js b/node_modules/engine.io-client/lib/transports/polling-jsonp.js
new file mode 100644
index 0000000..8ba4833
--- /dev/null
+++ b/node_modules/engine.io-client/lib/transports/polling-jsonp.js
@@ -0,0 +1,231 @@
+
+/**
+ * Module requirements.
+ */
+
+var Polling = require('./polling');
+var inherit = require('component-inherit');
+
+/**
+ * Module exports.
+ */
+
+module.exports = JSONPPolling;
+
+/**
+ * Cached regular expressions.
+ */
+
+var rNewline = /\n/g;
+var rEscapedNewline = /\\n/g;
+
+/**
+ * Global JSONP callbacks.
+ */
+
+var callbacks;
+
+/**
+ * Noop.
+ */
+
+function empty () { }
+
+/**
+ * JSONP Polling constructor.
+ *
+ * @param {Object} opts.
+ * @api public
+ */
+
+function JSONPPolling (opts) {
+ Polling.call(this, opts);
+
+ this.query = this.query || {};
+
+ // define global callbacks array if not present
+ // we do this here (lazily) to avoid unneeded global pollution
+ if (!callbacks) {
+ // we need to consider multiple engines in the same page
+ if (!global.___eio) global.___eio = [];
+ callbacks = global.___eio;
+ }
+
+ // callback identifier
+ this.index = callbacks.length;
+
+ // add callback to jsonp global
+ var self = this;
+ callbacks.push(function (msg) {
+ self.onData(msg);
+ });
+
+ // append to query string
+ this.query.j = this.index;
+
+ // prevent spurious errors from being emitted when the window is unloaded
+ if (global.document && global.addEventListener) {
+ global.addEventListener('beforeunload', function () {
+ if (self.script) self.script.onerror = empty;
+ }, false);
+ }
+}
+
+/**
+ * Inherits from Polling.
+ */
+
+inherit(JSONPPolling, Polling);
+
+/*
+ * JSONP only supports binary as base64 encoded strings
+ */
+
+JSONPPolling.prototype.supportsBinary = false;
+
+/**
+ * Closes the socket.
+ *
+ * @api private
+ */
+
+JSONPPolling.prototype.doClose = function () {
+ if (this.script) {
+ this.script.parentNode.removeChild(this.script);
+ this.script = null;
+ }
+
+ if (this.form) {
+ this.form.parentNode.removeChild(this.form);
+ this.form = null;
+ this.iframe = null;
+ }
+
+ Polling.prototype.doClose.call(this);
+};
+
+/**
+ * Starts a poll cycle.
+ *
+ * @api private
+ */
+
+JSONPPolling.prototype.doPoll = function () {
+ var self = this;
+ var script = document.createElement('script');
+
+ if (this.script) {
+ this.script.parentNode.removeChild(this.script);
+ this.script = null;
+ }
+
+ script.async = true;
+ script.src = this.uri();
+ script.onerror = function (e) {
+ self.onError('jsonp poll error', e);
+ };
+
+ var insertAt = document.getElementsByTagName('script')[0];
+ if (insertAt) {
+ insertAt.parentNode.insertBefore(script, insertAt);
+ } else {
+ (document.head || document.body).appendChild(script);
+ }
+ this.script = script;
+
+ var isUAgecko = 'undefined' !== typeof navigator && /gecko/i.test(navigator.userAgent);
+
+ if (isUAgecko) {
+ setTimeout(function () {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ document.body.removeChild(iframe);
+ }, 100);
+ }
+};
+
+/**
+ * Writes with a hidden iframe.
+ *
+ * @param {String} data to send
+ * @param {Function} called upon flush.
+ * @api private
+ */
+
+JSONPPolling.prototype.doWrite = function (data, fn) {
+ var self = this;
+
+ if (!this.form) {
+ var form = document.createElement('form');
+ var area = document.createElement('textarea');
+ var id = this.iframeId = 'eio_iframe_' + this.index;
+ var iframe;
+
+ form.className = 'socketio';
+ form.style.position = 'absolute';
+ form.style.top = '-1000px';
+ form.style.left = '-1000px';
+ form.target = id;
+ form.method = 'POST';
+ form.setAttribute('accept-charset', 'utf-8');
+ area.name = 'd';
+ form.appendChild(area);
+ document.body.appendChild(form);
+
+ this.form = form;
+ this.area = area;
+ }
+
+ this.form.action = this.uri();
+
+ function complete () {
+ initIframe();
+ fn();
+ }
+
+ function initIframe () {
+ if (self.iframe) {
+ try {
+ self.form.removeChild(self.iframe);
+ } catch (e) {
+ self.onError('jsonp polling iframe removal error', e);
+ }
+ }
+
+ try {
+ // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
+ var html = '<iframe src="javascript:0" name="' + self.iframeId + '">';
+ iframe = document.createElement(html);
+ } catch (e) {
+ iframe = document.createElement('iframe');
+ iframe.name = self.iframeId;
+ iframe.src = 'javascript:0';
+ }
+
+ iframe.id = self.iframeId;
+
+ self.form.appendChild(iframe);
+ self.iframe = iframe;
+ }
+
+ initIframe();
+
+ // escape \n to prevent it from being converted into \r\n by some UAs
+ // double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side
+ data = data.replace(rEscapedNewline, '\\\n');
+ this.area.value = data.replace(rNewline, '\\n');
+
+ try {
+ this.form.submit();
+ } catch (e) {}
+
+ if (this.iframe.attachEvent) {
+ this.iframe.onreadystatechange = function () {
+ if (self.iframe.readyState === 'complete') {
+ complete();
+ }
+ };
+ } else {
+ this.iframe.onload = complete;
+ }
+};
diff --git a/node_modules/engine.io-client/lib/transports/polling-xhr.js b/node_modules/engine.io-client/lib/transports/polling-xhr.js
new file mode 100644
index 0000000..297bac5
--- /dev/null
+++ b/node_modules/engine.io-client/lib/transports/polling-xhr.js
@@ -0,0 +1,413 @@
+/**
+ * Module requirements.
+ */
+
+var XMLHttpRequest = require('xmlhttprequest-ssl');
+var Polling = require('./polling');
+var Emitter = require('component-emitter');
+var inherit = require('component-inherit');
+var debug = require('debug')('engine.io-client:polling-xhr');
+
+/**
+ * Module exports.
+ */
+
+module.exports = XHR;
+module.exports.Request = Request;
+
+/**
+ * Empty function
+ */
+
+function empty () {}
+
+/**
+ * XHR Polling constructor.
+ *
+ * @param {Object} opts
+ * @api public
+ */
+
+function XHR (opts) {
+ Polling.call(this, opts);
+ this.requestTimeout = opts.requestTimeout;
+ this.extraHeaders = opts.extraHeaders;
+
+ if (global.location) {
+ var isSSL = 'https:' === location.protocol;
+ var port = location.port;
+
+ // some user agents have empty `location.port`
+ if (!port) {
+ port = isSSL ? 443 : 80;
+ }
+
+ this.xd = opts.hostname !== global.location.hostname ||
+ port !== opts.port;
+ this.xs = opts.secure !== isSSL;
+ }
+}
+
+/**
+ * Inherits from Polling.
+ */
+
+inherit(XHR, Polling);
+
+/**
+ * XHR supports binary
+ */
+
+XHR.prototype.supportsBinary = true;
+
+/**
+ * Creates a request.
+ *
+ * @param {String} method
+ * @api private
+ */
+
+XHR.prototype.request = function (opts) {
+ opts = opts || {};
+ opts.uri = this.uri();
+ opts.xd = this.xd;
+ opts.xs = this.xs;
+ opts.agent = this.agent || false;
+ opts.supportsBinary = this.supportsBinary;
+ opts.enablesXDR = this.enablesXDR;
+
+ // SSL options for Node.js client
+ opts.pfx = this.pfx;
+ opts.key = this.key;
+ opts.passphrase = this.passphrase;
+ opts.cert = this.cert;
+ opts.ca = this.ca;
+ opts.ciphers = this.ciphers;
+ opts.rejectUnauthorized = this.rejectUnauthorized;
+ opts.requestTimeout = this.requestTimeout;
+
+ // other options for Node.js client
+ opts.extraHeaders = this.extraHeaders;
+
+ return new Request(opts);
+};
+
+/**
+ * Sends data.
+ *
+ * @param {String} data to send.
+ * @param {Function} called upon flush.
+ * @api private
+ */
+
+XHR.prototype.doWrite = function (data, fn) {
+ var isBinary = typeof data !== 'string' && data !== undefined;
+ var req = this.request({ method: 'POST', data: data, isBinary: isBinary });
+ var self = this;
+ req.on('success', fn);
+ req.on('error', function (err) {
+ self.onError('xhr post error', err);
+ });
+ this.sendXhr = req;
+};
+
+/**
+ * Starts a poll cycle.
+ *
+ * @api private
+ */
+
+XHR.prototype.doPoll = function () {
+ debug('xhr poll');
+ var req = this.request();
+ var self = this;
+ req.on('data', function (data) {
+ self.onData(data);
+ });
+ req.on('error', function (err) {
+ self.onError('xhr poll error', err);
+ });
+ this.pollXhr = req;
+};
+
+/**
+ * Request constructor
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+function Request (opts) {
+ this.method = opts.method || 'GET';
+ this.uri = opts.uri;
+ this.xd = !!opts.xd;
+ this.xs = !!opts.xs;
+ this.async = false !== opts.async;
+ this.data = undefined !== opts.data ? opts.data : null;
+ this.agent = opts.agent;
+ this.isBinary = opts.isBinary;
+ this.supportsBinary = opts.supportsBinary;
+ this.enablesXDR = opts.enablesXDR;
+ this.requestTimeout = opts.requestTimeout;
+
+ // SSL options for Node.js client
+ this.pfx = opts.pfx;
+ this.key = opts.key;
+ this.passphrase = opts.passphrase;
+ this.cert = opts.cert;
+ this.ca = opts.ca;
+ this.ciphers = opts.ciphers;
+ this.rejectUnauthorized = opts.rejectUnauthorized;
+
+ // other options for Node.js client
+ this.extraHeaders = opts.extraHeaders;
+
+ this.create();
+}
+
+/**
+ * Mix in `Emitter`.
+ */
+
+Emitter(Request.prototype);
+
+/**
+ * Creates the XHR object and sends the request.
+ *
+ * @api private
+ */
+
+Request.prototype.create = function () {
+ var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR };
+
+ // SSL options for Node.js client
+ opts.pfx = this.pfx;
+ opts.key = this.key;
+ opts.passphrase = this.passphrase;
+ opts.cert = this.cert;
+ opts.ca = this.ca;
+ opts.ciphers = this.ciphers;
+ opts.rejectUnauthorized = this.rejectUnauthorized;
+
+ var xhr = this.xhr = new XMLHttpRequest(opts);
+ var self = this;
+
+ try {
+ debug('xhr open %s: %s', this.method, this.uri);
+ xhr.open(this.method, this.uri, this.async);
+ try {
+ if (this.extraHeaders) {
+ xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true);
+ for (var i in this.extraHeaders) {
+ if (this.extraHeaders.hasOwnProperty(i)) {
+ xhr.setRequestHeader(i, this.extraHeaders[i]);
+ }
+ }
+ }
+ } catch (e) {}
+
+ if ('POST' === this.method) {
+ try {
+ if (this.isBinary) {
+ xhr.setRequestHeader('Content-type', 'application/octet-stream');
+ } else {
+ xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
+ }
+ } catch (e) {}
+ }
+
+ try {
+ xhr.setRequestHeader('Accept', '*/*');
+ } catch (e) {}
+
+ // ie6 check
+ if ('withCredentials' in xhr) {
+ xhr.withCredentials = true;
+ }
+
+ if (this.requestTimeout) {
+ xhr.timeout = this.requestTimeout;
+ }
+
+ if (this.hasXDR()) {
+ xhr.onload = function () {
+ self.onLoad();
+ };
+ xhr.onerror = function () {
+ self.onError(xhr.responseText);
+ };
+ } else {
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 2) {
+ var contentType;
+ try {
+ contentType = xhr.getResponseHeader('Content-Type');
+ } catch (e) {}
+ if (contentType === 'application/octet-stream') {
+ xhr.responseType = 'arraybuffer';
+ }
+ }
+ if (4 !== xhr.readyState) return;
+ if (200 === xhr.status || 1223 === xhr.status) {
+ self.onLoad();
+ } else {
+ // make sure the `error` event handler that's user-set
+ // does not throw in the same tick and gets caught here
+ setTimeout(function () {
+ self.onError(xhr.status);
+ }, 0);
+ }
+ };
+ }
+
+ debug('xhr data %s', this.data);
+ xhr.send(this.data);
+ } catch (e) {
+ // Need to defer since .create() is called directly fhrom the constructor
+ // and thus the 'error' event can only be only bound *after* this exception
+ // occurs. Therefore, also, we cannot throw here at all.
+ setTimeout(function () {
+ self.onError(e);
+ }, 0);
+ return;
+ }
+
+ if (global.document) {
+ this.index = Request.requestsCount++;
+ Request.requests[this.index] = this;
+ }
+};
+
+/**
+ * Called upon successful response.
+ *
+ * @api private
+ */
+
+Request.prototype.onSuccess = function () {
+ this.emit('success');
+ this.cleanup();
+};
+
+/**
+ * Called if we have data.
+ *
+ * @api private
+ */
+
+Request.prototype.onData = function (data) {
+ this.emit('data', data);
+ this.onSuccess();
+};
+
+/**
+ * Called upon error.
+ *
+ * @api private
+ */
+
+Request.prototype.onError = function (err) {
+ this.emit('error', err);
+ this.cleanup(true);
+};
+
+/**
+ * Cleans up house.
+ *
+ * @api private
+ */
+
+Request.prototype.cleanup = function (fromError) {
+ if ('undefined' === typeof this.xhr || null === this.xhr) {
+ return;
+ }
+ // xmlhttprequest
+ if (this.hasXDR()) {
+ this.xhr.onload = this.xhr.onerror = empty;
+ } else {
+ this.xhr.onreadystatechange = empty;
+ }
+
+ if (fromError) {
+ try {
+ this.xhr.abort();
+ } catch (e) {}
+ }
+
+ if (global.document) {
+ delete Request.requests[this.index];
+ }
+
+ this.xhr = null;
+};
+
+/**
+ * Called upon load.
+ *
+ * @api private
+ */
+
+Request.prototype.onLoad = function () {
+ var data;
+ try {
+ var contentType;
+ try {
+ contentType = this.xhr.getResponseHeader('Content-Type');
+ } catch (e) {}
+ if (contentType === 'application/octet-stream') {
+ data = this.xhr.response || this.xhr.responseText;
+ } else {
+ data = this.xhr.responseText;
+ }
+ } catch (e) {
+ this.onError(e);
+ }
+ if (null != data) {
+ this.onData(data);
+ }
+};
+
+/**
+ * Check if it has XDomainRequest.
+ *
+ * @api private
+ */
+
+Request.prototype.hasXDR = function () {
+ return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR;
+};
+
+/**
+ * Aborts the request.
+ *
+ * @api public
+ */
+
+Request.prototype.abort = function () {
+ this.cleanup();
+};
+
+/**
+ * Aborts pending requests when unloading the window. This is needed to prevent
+ * memory leaks (e.g. when using IE) and to ensure that no spurious error is
+ * emitted.
+ */
+
+Request.requestsCount = 0;
+Request.requests = {};
+
+if (global.document) {
+ if (global.attachEvent) {
+ global.attachEvent('onunload', unloadHandler);
+ } else if (global.addEventListener) {
+ global.addEventListener('beforeunload', unloadHandler, false);
+ }
+}
+
+function unloadHandler () {
+ for (var i in Request.requests) {
+ if (Request.requests.hasOwnProperty(i)) {
+ Request.requests[i].abort();
+ }
+ }
+}
diff --git a/node_modules/engine.io-client/lib/transports/polling.js b/node_modules/engine.io-client/lib/transports/polling.js
new file mode 100644
index 0000000..970313e
--- /dev/null
+++ b/node_modules/engine.io-client/lib/transports/polling.js
@@ -0,0 +1,245 @@
+/**
+ * Module dependencies.
+ */
+
+var Transport = require('../transport');
+var parseqs = require('parseqs');
+var parser = require('engine.io-parser');
+var inherit = require('component-inherit');
+var yeast = require('yeast');
+var debug = require('debug')('engine.io-client:polling');
+
+/**
+ * Module exports.
+ */
+
+module.exports = Polling;
+
+/**
+ * Is XHR2 supported?
+ */
+
+var hasXHR2 = (function () {
+ var XMLHttpRequest = require('xmlhttprequest-ssl');
+ var xhr = new XMLHttpRequest({ xdomain: false });
+ return null != xhr.responseType;
+})();
+
+/**
+ * Polling interface.
+ *
+ * @param {Object} opts
+ * @api private
+ */
+
+function Polling (opts) {
+ var forceBase64 = (opts && opts.forceBase64);
+ if (!hasXHR2 || forceBase64) {
+ this.supportsBinary = false;
+ }
+ Transport.call(this, opts);
+}
+
+/**
+ * Inherits from Transport.
+ */
+
+inherit(Polling, Transport);
+
+/**
+ * Transport name.
+ */
+
+Polling.prototype.name = 'polling';
+
+/**
+ * Opens the socket (triggers polling). We write a PING message to determine
+ * when the transport is open.
+ *
+ * @api private
+ */
+
+Polling.prototype.doOpen = function () {
+ this.poll();
+};
+
+/**
+ * Pauses polling.
+ *
+ * @param {Function} callback upon buffers are flushed and transport is paused
+ * @api private
+ */
+
+Polling.prototype.pause = function (onPause) {
+ var self = this;
+
+ this.readyState = 'pausing';
+
+ function pause () {
+ debug('paused');
+ self.readyState = 'paused';
+ onPause();
+ }
+
+ if (this.polling || !this.writable) {
+ var total = 0;
+
+ if (this.polling) {
+ debug('we are currently polling - waiting to pause');
+ total++;
+ this.once('pollComplete', function () {
+ debug('pre-pause polling complete');
+ --total || pause();
+ });
+ }
+
+ if (!this.writable) {
+ debug('we are currently writing - waiting to pause');
+ total++;
+ this.once('drain', function () {
+ debug('pre-pause writing complete');
+ --total || pause();
+ });
+ }
+ } else {
+ pause();
+ }
+};
+
+/**
+ * Starts polling cycle.
+ *
+ * @api public
+ */
+
+Polling.prototype.poll = function () {
+ debug('polling');
+ this.polling = true;
+ this.doPoll();
+ this.emit('poll');
+};
+
+/**
+ * Overloads onData to detect payloads.
+ *
+ * @api private
+ */
+
+Polling.prototype.onData = function (data) {
+ var self = this;
+ debug('polling got data %s', data);
+ var callback = function (packet, index, total) {
+ // if its the first message we consider the transport open
+ if ('opening' === self.readyState) {
+ self.onOpen();
+ }
+
+ // if its a close packet, we close the ongoing requests
+ if ('close' === packet.type) {
+ self.onClose();
+ return false;
+ }
+
+ // otherwise bypass onData and handle the message
+ self.onPacket(packet);
+ };
+
+ // decode payload
+ parser.decodePayload(data, this.socket.binaryType, callback);
+
+ // if an event did not trigger closing
+ if ('closed' !== this.readyState) {
+ // if we got data we're not polling
+ this.polling = false;
+ this.emit('pollComplete');
+
+ if ('open' === this.readyState) {
+ this.poll();
+ } else {
+ debug('ignoring poll - transport state "%s"', this.readyState);
+ }
+ }
+};
+
+/**
+ * For polling, send a close packet.
+ *
+ * @api private
+ */
+
+Polling.prototype.doClose = function () {
+ var self = this;
+
+ function close () {
+ debug('writing close packet');
+ self.write([{ type: 'close' }]);
+ }
+
+ if ('open' === this.readyState) {
+ debug('transport open - closing');
+ close();
+ } else {
+ // in case we're trying to close while
+ // handshaking is in progress (GH-164)
+ debug('transport not open - deferring close');
+ this.once('open', close);
+ }
+};
+
+/**
+ * Writes a packets payload.
+ *
+ * @param {Array} data packets
+ * @param {Function} drain callback
+ * @api private
+ */
+
+Polling.prototype.write = function (packets) {
+ var self = this;
+ this.writable = false;
+ var callbackfn = function () {
+ self.writable = true;
+ self.emit('drain');
+ };
+
+ parser.encodePayload(packets, this.supportsBinary, function (data) {
+ self.doWrite(data, callbackfn);
+ });
+};
+
+/**
+ * Generates uri for connection.
+ *
+ * @api private
+ */
+
+Polling.prototype.uri = function () {
+ var query = this.query || {};
+ var schema = this.secure ? 'https' : 'http';
+ var port = '';
+
+ // cache busting is forced
+ if (false !== this.timestampRequests) {
+ query[this.timestampParam] = yeast();
+ }
+
+ if (!this.supportsBinary && !query.sid) {
+ query.b64 = 1;
+ }
+
+ query = parseqs.encode(query);
+
+ // avoid port if default for schema
+ if (this.port && (('https' === schema && Number(this.port) !== 443) ||
+ ('http' === schema && Number(this.port) !== 80))) {
+ port = ':' + this.port;
+ }
+
+ // prepend ? to query
+ if (query.length) {
+ query = '?' + query;
+ }
+
+ var ipv6 = this.hostname.indexOf(':') !== -1;
+ return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
+};
diff --git a/node_modules/engine.io-client/lib/transports/websocket.js b/node_modules/engine.io-client/lib/transports/websocket.js
new file mode 100644
index 0000000..de14ba0
--- /dev/null
+++ b/node_modules/engine.io-client/lib/transports/websocket.js
@@ -0,0 +1,286 @@
+/**
+ * Module dependencies.
+ */
+
+var Transport = require('../transport');
+var parser = require('engine.io-parser');
+var parseqs = require('parseqs');
+var inherit = require('component-inherit');
+var yeast = require('yeast');
+var debug = require('debug')('engine.io-client:websocket');
+var BrowserWebSocket = global.WebSocket || global.MozWebSocket;
+var NodeWebSocket;
+if (typeof window === 'undefined') {
+ try {
+ NodeWebSocket = require('ws');
+ } catch (e) { }
+}
+
+/**
+ * Get either the `WebSocket` or `MozWebSocket` globals
+ * in the browser or try to resolve WebSocket-compatible
+ * interface exposed by `ws` for Node-like environment.
+ */
+
+var WebSocket = BrowserWebSocket;
+if (!WebSocket && typeof window === 'undefined') {
+ WebSocket = NodeWebSocket;
+}
+
+/**
+ * Module exports.
+ */
+
+module.exports = WS;
+
+/**
+ * WebSocket transport constructor.
+ *
+ * @api {Object} connection options
+ * @api public
+ */
+
+function WS (opts) {
+ var forceBase64 = (opts && opts.forceBase64);
+ if (forceBase64) {
+ this.supportsBinary = false;
+ }
+ this.perMessageDeflate = opts.perMessageDeflate;
+ this.usingBrowserWebSocket = BrowserWebSocket && !opts.forceNode;
+ this.protocols = opts.protocols;
+ if (!this.usingBrowserWebSocket) {
+ WebSocket = NodeWebSocket;
+ }
+ Transport.call(this, opts);
+}
+
+/**
+ * Inherits from Transport.
+ */
+
+inherit(WS, Transport);
+
+/**
+ * Transport name.
+ *
+ * @api public
+ */
+
+WS.prototype.name = 'websocket';
+
+/*
+ * WebSockets support binary
+ */
+
+WS.prototype.supportsBinary = true;
+
+/**
+ * Opens socket.
+ *
+ * @api private
+ */
+
+WS.prototype.doOpen = function () {
+ if (!this.check()) {
+ // let probe timeout
+ return;
+ }
+
+ var uri = this.uri();
+ var protocols = this.protocols;
+ var opts = {
+ agent: this.agent,
+ perMessageDeflate: this.perMessageDeflate
+ };
+
+ // SSL options for Node.js client
+ opts.pfx = this.pfx;
+ opts.key = this.key;
+ opts.passphrase = this.passphrase;
+ opts.cert = this.cert;
+ opts.ca = this.ca;
+ opts.ciphers = this.ciphers;
+ opts.rejectUnauthorized = this.rejectUnauthorized;
+ if (this.extraHeaders) {
+ opts.headers = this.extraHeaders;
+ }
+ if (this.localAddress) {
+ opts.localAddress = this.localAddress;
+ }
+
+ try {
+ this.ws = this.usingBrowserWebSocket ? (protocols ? new WebSocket(uri, protocols) : new WebSocket(uri)) : new WebSocket(uri, protocols, opts);
+ } catch (err) {
+ return this.emit('error', err);
+ }
+
+ if (this.ws.binaryType === undefined) {
+ this.supportsBinary = false;
+ }
+
+ if (this.ws.supports && this.ws.supports.binary) {
+ this.supportsBinary = true;
+ this.ws.binaryType = 'nodebuffer';
+ } else {
+ this.ws.binaryType = 'arraybuffer';
+ }
+
+ this.addEventListeners();
+};
+
+/**
+ * Adds event listeners to the socket
+ *
+ * @api private
+ */
+
+WS.prototype.addEventListeners = function () {
+ var self = this;
+
+ this.ws.onopen = function () {
+ self.onOpen();
+ };
+ this.ws.onclose = function () {
+ self.onClose();
+ };
+ this.ws.onmessage = function (ev) {
+ self.onData(ev.data);
+ };
+ this.ws.onerror = function (e) {
+ self.onError('websocket error', e);
+ };
+};
+
+/**
+ * Writes data to socket.
+ *
+ * @param {Array} array of packets.
+ * @api private
+ */
+
+WS.prototype.write = function (packets) {
+ var self = this;
+ this.writable = false;
+
+ // encodePacket efficient as it uses WS framing
+ // no need for encodePayload
+ var total = packets.length;
+ for (var i = 0, l = total; i < l; i++) {
+ (function (packet) {
+ parser.encodePacket(packet, self.supportsBinary, function (data) {
+ if (!self.usingBrowserWebSocket) {
+ // always create a new object (GH-437)
+ var opts = {};
+ if (packet.options) {
+ opts.compress = packet.options.compress;
+ }
+
+ if (self.perMessageDeflate) {
+ var len = 'string' === typeof data ? global.Buffer.byteLength(data) : data.length;
+ if (len < self.perMessageDeflate.threshold) {
+ opts.compress = false;
+ }
+ }
+ }
+
+ // Sometimes the websocket has already been closed but the browser didn't
+ // have a chance of informing us about it yet, in that case send will
+ // throw an error
+ try {
+ if (self.usingBrowserWebSocket) {
+ // TypeError is thrown when passing the second argument on Safari
+ self.ws.send(data);
+ } else {
+ self.ws.send(data, opts);
+ }
+ } catch (e) {
+ debug('websocket closed before onclose event');
+ }
+
+ --total || done();
+ });
+ })(packets[i]);
+ }
+
+ function done () {
+ self.emit('flush');
+
+ // fake drain
+ // defer to next tick to allow Socket to clear writeBuffer
+ setTimeout(function () {
+ self.writable = true;
+ self.emit('drain');
+ }, 0);
+ }
+};
+
+/**
+ * Called upon close
+ *
+ * @api private
+ */
+
+WS.prototype.onClose = function () {
+ Transport.prototype.onClose.call(this);
+};
+
+/**
+ * Closes socket.
+ *
+ * @api private
+ */
+
+WS.prototype.doClose = function () {
+ if (typeof this.ws !== 'undefined') {
+ this.ws.close();
+ }
+};
+
+/**
+ * Generates uri for connection.
+ *
+ * @api private
+ */
+
+WS.prototype.uri = function () {
+ var query = this.query || {};
+ var schema = this.secure ? 'wss' : 'ws';
+ var port = '';
+
+ // avoid port if default for schema
+ if (this.port && (('wss' === schema && Number(this.port) !== 443) ||
+ ('ws' === schema && Number(this.port) !== 80))) {
+ port = ':' + this.port;
+ }
+
+ // append timestamp to URI
+ if (this.timestampRequests) {
+ query[this.timestampParam] = yeast();
+ }
+
+ // communicate binary support capabilities
+ if (!this.supportsBinary) {
+ query.b64 = 1;
+ }
+
+ query = parseqs.encode(query);
+
+ // prepend ? to query
+ if (query.length) {
+ query = '?' + query;
+ }
+
+ var ipv6 = this.hostname.indexOf(':') !== -1;
+ return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
+};
+
+/**
+ * Feature detection for WebSocket.
+ *
+ * @return {Boolean} whether this transport is available.
+ * @api public
+ */
+
+WS.prototype.check = function () {
+ return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
+};
diff --git a/node_modules/engine.io-client/lib/xmlhttprequest.js b/node_modules/engine.io-client/lib/xmlhttprequest.js
new file mode 100644
index 0000000..d76d9c7
--- /dev/null
+++ b/node_modules/engine.io-client/lib/xmlhttprequest.js
@@ -0,0 +1,37 @@
+// browser shim for xmlhttprequest module
+
+var hasCORS = require('has-cors');
+
+module.exports = function (opts) {
+ var xdomain = opts.xdomain;
+
+ // scheme must be same when usign XDomainRequest
+ // http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
+ var xscheme = opts.xscheme;
+
+ // XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default.
+ // https://github.com/Automattic/engine.io-client/pull/217
+ var enablesXDR = opts.enablesXDR;
+
+ // XMLHttpRequest can be disabled on IE
+ try {
+ if ('undefined' !== typeof XMLHttpRequest && (!xdomain || hasCORS)) {
+ return new XMLHttpRequest();
+ }
+ } catch (e) { }
+
+ // Use XDomainRequest for IE8 if enablesXDR is true
+ // because loading bar keeps flashing when using jsonp-polling
+ // https://github.com/yujiosaka/socke.io-ie8-loading-example
+ try {
+ if ('undefined' !== typeof XDomainRequest && !xscheme && enablesXDR) {
+ return new XDomainRequest();
+ }
+ } catch (e) { }
+
+ if (!xdomain) {
+ try {
+ return new global[['Active'].concat('Object').join('X')]('Microsoft.XMLHTTP');
+ } catch (e) { }
+ }
+};