-
-
Save ndob/4742514cd23eec7a81a3 to your computer and use it in GitHub Desktop.
| !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.io=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | |
| module.exports = _dereq_('./lib/'); | |
| },{"./lib/":2}],2:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var url = _dereq_('./url'); | |
| var parser = _dereq_('socket.io-parser'); | |
| var Manager = _dereq_('./manager'); | |
| var debug = _dereq_('debug')('socket.io-client'); | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = exports = lookup; | |
| /** | |
| * Managers cache. | |
| */ | |
| var cache = exports.managers = {}; | |
| /** | |
| * Looks up an existing `Manager` for multiplexing. | |
| * If the user summons: | |
| * | |
| * `io('http://localhost/a');` | |
| * `io('http://localhost/b');` | |
| * | |
| * We reuse the existing instance based on same scheme/port/host, | |
| * and we initialize sockets for each namespace. | |
| * | |
| * @api public | |
| */ | |
| function lookup(uri, opts) { | |
| if (typeof uri == 'object') { | |
| opts = uri; | |
| uri = undefined; | |
| } | |
| opts = opts || {}; | |
| var parsed = url(uri); | |
| var source = parsed.source; | |
| var id = parsed.id; | |
| var io; | |
| if (opts.forceNew || opts['force new connection'] || false === opts.multiplex) { | |
| debug('ignoring socket cache for %s', source); | |
| io = Manager(source, opts); | |
| } else { | |
| if (!cache[id]) { | |
| debug('new io instance for %s', source); | |
| cache[id] = Manager(source, opts); | |
| } | |
| io = cache[id]; | |
| } | |
| return io.socket(parsed.path); | |
| } | |
| /** | |
| * Protocol version. | |
| * | |
| * @api public | |
| */ | |
| exports.protocol = parser.protocol; | |
| /** | |
| * `connect`. | |
| * | |
| * @param {String} uri | |
| * @api public | |
| */ | |
| exports.connect = lookup; | |
| /** | |
| * Expose constructors for standalone build. | |
| * | |
| * @api public | |
| */ | |
| exports.Manager = _dereq_('./manager'); | |
| exports.Socket = _dereq_('./socket'); | |
| },{"./manager":3,"./socket":5,"./url":6,"debug":9,"socket.io-parser":40}],3:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var url = _dereq_('./url'); | |
| var eio = _dereq_('engine.io-client'); | |
| var Socket = _dereq_('./socket'); | |
| var Emitter = _dereq_('component-emitter'); | |
| var parser = _dereq_('socket.io-parser'); | |
| var on = _dereq_('./on'); | |
| var bind = _dereq_('component-bind'); | |
| var object = _dereq_('object-component'); | |
| var debug = _dereq_('debug')('socket.io-client:manager'); | |
| var indexOf = _dereq_('indexof'); | |
| /** | |
| * Module exports | |
| */ | |
| module.exports = Manager; | |
| /** | |
| * `Manager` constructor. | |
| * | |
| * @param {String} engine instance or engine uri/opts | |
| * @param {Object} options | |
| * @api public | |
| */ | |
| function Manager(uri, opts){ | |
| if (!(this instanceof Manager)) return new Manager(uri, opts); | |
| if (uri && ('object' == typeof uri)) { | |
| opts = uri; | |
| uri = undefined; | |
| } | |
| opts = opts || {}; | |
| opts.path = opts.path || '/socket.io'; | |
| this.nsps = {}; | |
| this.subs = []; | |
| this.opts = opts; | |
| this.reconnection(opts.reconnection !== false); | |
| this.reconnectionAttempts(opts.reconnectionAttempts || Infinity); | |
| this.reconnectionDelay(opts.reconnectionDelay || 1000); | |
| this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000); | |
| this.timeout(null == opts.timeout ? 20000 : opts.timeout); | |
| this.readyState = 'closed'; | |
| this.uri = uri; | |
| this.connected = []; | |
| this.attempts = 0; | |
| this.encoding = false; | |
| this.packetBuffer = []; | |
| this.encoder = new parser.Encoder(); | |
| this.decoder = new parser.Decoder(); | |
| this.autoConnect = opts.autoConnect !== false; | |
| if (this.autoConnect) this.open(); | |
| } | |
| /** | |
| * Propagate given event to sockets and emit on `this` | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.emitAll = function() { | |
| this.emit.apply(this, arguments); | |
| for (var nsp in this.nsps) { | |
| this.nsps[nsp].emit.apply(this.nsps[nsp], arguments); | |
| } | |
| }; | |
| /** | |
| * Mix in `Emitter`. | |
| */ | |
| Emitter(Manager.prototype); | |
| /** | |
| * Sets the `reconnection` config. | |
| * | |
| * @param {Boolean} true/false if it should automatically reconnect | |
| * @return {Manager} self or value | |
| * @api public | |
| */ | |
| Manager.prototype.reconnection = function(v){ | |
| if (!arguments.length) return this._reconnection; | |
| this._reconnection = !!v; | |
| return this; | |
| }; | |
| /** | |
| * Sets the reconnection attempts config. | |
| * | |
| * @param {Number} max reconnection attempts before giving up | |
| * @return {Manager} self or value | |
| * @api public | |
| */ | |
| Manager.prototype.reconnectionAttempts = function(v){ | |
| if (!arguments.length) return this._reconnectionAttempts; | |
| this._reconnectionAttempts = v; | |
| return this; | |
| }; | |
| /** | |
| * Sets the delay between reconnections. | |
| * | |
| * @param {Number} delay | |
| * @return {Manager} self or value | |
| * @api public | |
| */ | |
| Manager.prototype.reconnectionDelay = function(v){ | |
| if (!arguments.length) return this._reconnectionDelay; | |
| this._reconnectionDelay = v; | |
| return this; | |
| }; | |
| /** | |
| * Sets the maximum delay between reconnections. | |
| * | |
| * @param {Number} delay | |
| * @return {Manager} self or value | |
| * @api public | |
| */ | |
| Manager.prototype.reconnectionDelayMax = function(v){ | |
| if (!arguments.length) return this._reconnectionDelayMax; | |
| this._reconnectionDelayMax = v; | |
| return this; | |
| }; | |
| /** | |
| * Sets the connection timeout. `false` to disable | |
| * | |
| * @return {Manager} self or value | |
| * @api public | |
| */ | |
| Manager.prototype.timeout = function(v){ | |
| if (!arguments.length) return this._timeout; | |
| this._timeout = v; | |
| return this; | |
| }; | |
| /** | |
| * Starts trying to reconnect if reconnection is enabled and we have not | |
| * started reconnecting yet | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.maybeReconnectOnOpen = function() { | |
| // Only try to reconnect if it's the first time we're connecting | |
| if (!this.openReconnect && !this.reconnecting && this._reconnection && this.attempts === 0) { | |
| // keeps reconnection from firing twice for the same reconnection loop | |
| this.openReconnect = true; | |
| this.reconnect(); | |
| } | |
| }; | |
| /** | |
| * Sets the current transport `socket`. | |
| * | |
| * @param {Function} optional, callback | |
| * @return {Manager} self | |
| * @api public | |
| */ | |
| Manager.prototype.open = | |
| Manager.prototype.connect = function(fn){ | |
| debug('readyState %s', this.readyState); | |
| if (~this.readyState.indexOf('open')) return this; | |
| debug('opening %s', this.uri); | |
| this.engine = eio(this.uri, this.opts); | |
| var socket = this.engine; | |
| var self = this; | |
| this.readyState = 'opening'; | |
| this.skipReconnect = false; | |
| // emit `open` | |
| var openSub = on(socket, 'open', function() { | |
| self.onopen(); | |
| fn && fn(); | |
| }); | |
| // emit `connect_error` | |
| var errorSub = on(socket, 'error', function(data){ | |
| debug('connect_error'); | |
| self.cleanup(); | |
| self.readyState = 'closed'; | |
| self.emitAll('connect_error', data); | |
| if (fn) { | |
| var err = new Error('Connection error'); | |
| err.data = data; | |
| fn(err); | |
| } | |
| self.maybeReconnectOnOpen(); | |
| }); | |
| // emit `connect_timeout` | |
| if (false !== this._timeout) { | |
| var timeout = this._timeout; | |
| debug('connect attempt will timeout after %d', timeout); | |
| // set timer | |
| var timer = setTimeout(function(){ | |
| debug('connect attempt timed out after %d', timeout); | |
| openSub.destroy(); | |
| socket.close(); | |
| socket.emit('error', 'timeout'); | |
| self.emitAll('connect_timeout', timeout); | |
| }, timeout); | |
| this.subs.push({ | |
| destroy: function(){ | |
| clearTimeout(timer); | |
| } | |
| }); | |
| } | |
| this.subs.push(openSub); | |
| this.subs.push(errorSub); | |
| return this; | |
| }; | |
| /** | |
| * Called upon transport open. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.onopen = function(){ | |
| debug('open'); | |
| // clear old subs | |
| this.cleanup(); | |
| // mark as open | |
| this.readyState = 'open'; | |
| this.emit('open'); | |
| // add new subs | |
| var socket = this.engine; | |
| this.subs.push(on(socket, 'data', bind(this, 'ondata'))); | |
| this.subs.push(on(this.decoder, 'decoded', bind(this, 'ondecoded'))); | |
| this.subs.push(on(socket, 'error', bind(this, 'onerror'))); | |
| this.subs.push(on(socket, 'close', bind(this, 'onclose'))); | |
| }; | |
| /** | |
| * Called with data. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.ondata = function(data){ | |
| this.decoder.add(data); | |
| }; | |
| /** | |
| * Called when parser fully decodes a packet. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.ondecoded = function(packet) { | |
| this.emit('packet', packet); | |
| }; | |
| /** | |
| * Called upon socket error. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.onerror = function(err){ | |
| debug('error', err); | |
| this.emitAll('error', err); | |
| }; | |
| /** | |
| * Creates a new socket for the given `nsp`. | |
| * | |
| * @return {Socket} | |
| * @api public | |
| */ | |
| Manager.prototype.socket = function(nsp){ | |
| var socket = this.nsps[nsp]; | |
| if (!socket) { | |
| socket = new Socket(this, nsp); | |
| this.nsps[nsp] = socket; | |
| var self = this; | |
| socket.on('connect', function(){ | |
| if (!~indexOf(self.connected, socket)) { | |
| self.connected.push(socket); | |
| } | |
| }); | |
| } | |
| return socket; | |
| }; | |
| /** | |
| * Called upon a socket close. | |
| * | |
| * @param {Socket} socket | |
| */ | |
| Manager.prototype.destroy = function(socket){ | |
| var index = indexOf(this.connected, socket); | |
| if (~index) this.connected.splice(index, 1); | |
| if (this.connected.length) return; | |
| this.close(); | |
| }; | |
| /** | |
| * Writes a packet. | |
| * | |
| * @param {Object} packet | |
| * @api private | |
| */ | |
| Manager.prototype.packet = function(packet){ | |
| debug('writing packet %j', packet); | |
| var self = this; | |
| if (!self.encoding) { | |
| // encode, then write to engine with result | |
| self.encoding = true; | |
| this.encoder.encode(packet, function(encodedPackets) { | |
| for (var i = 0; i < encodedPackets.length; i++) { | |
| self.engine.write(encodedPackets[i]); | |
| } | |
| self.encoding = false; | |
| self.processPacketQueue(); | |
| }); | |
| } else { // add packet to the queue | |
| self.packetBuffer.push(packet); | |
| } | |
| }; | |
| /** | |
| * If packet buffer is non-empty, begins encoding the | |
| * next packet in line. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.processPacketQueue = function() { | |
| if (this.packetBuffer.length > 0 && !this.encoding) { | |
| var pack = this.packetBuffer.shift(); | |
| this.packet(pack); | |
| } | |
| }; | |
| /** | |
| * Clean up transport subscriptions and packet buffer. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.cleanup = function(){ | |
| var sub; | |
| while (sub = this.subs.shift()) sub.destroy(); | |
| this.packetBuffer = []; | |
| this.encoding = false; | |
| this.decoder.destroy(); | |
| }; | |
| /** | |
| * Close the current socket. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.close = | |
| Manager.prototype.disconnect = function(){ | |
| this.skipReconnect = true; | |
| this.readyState = 'closed'; | |
| this.engine && this.engine.close(); | |
| }; | |
| /** | |
| * Called upon engine close. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.onclose = function(reason){ | |
| debug('close'); | |
| this.cleanup(); | |
| this.readyState = 'closed'; | |
| this.emit('close', reason); | |
| if (this._reconnection && !this.skipReconnect) { | |
| this.reconnect(); | |
| } | |
| }; | |
| /** | |
| * Attempt a reconnection. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.reconnect = function(){ | |
| if (this.reconnecting || this.skipReconnect) return this; | |
| var self = this; | |
| this.attempts++; | |
| if (this.attempts > this._reconnectionAttempts) { | |
| debug('reconnect failed'); | |
| this.emitAll('reconnect_failed'); | |
| this.reconnecting = false; | |
| } else { | |
| var delay = this.attempts * this.reconnectionDelay(); | |
| delay = Math.min(delay, this.reconnectionDelayMax()); | |
| debug('will wait %dms before reconnect attempt', delay); | |
| this.reconnecting = true; | |
| var timer = setTimeout(function(){ | |
| if (self.skipReconnect) return; | |
| debug('attempting reconnect'); | |
| self.emitAll('reconnect_attempt', self.attempts); | |
| self.emitAll('reconnecting', self.attempts); | |
| // check again for the case socket closed in above events | |
| if (self.skipReconnect) return; | |
| self.open(function(err){ | |
| if (err) { | |
| debug('reconnect attempt error'); | |
| self.reconnecting = false; | |
| self.reconnect(); | |
| self.emitAll('reconnect_error', err.data); | |
| } else { | |
| debug('reconnect success'); | |
| self.onreconnect(); | |
| } | |
| }); | |
| }, delay); | |
| this.subs.push({ | |
| destroy: function(){ | |
| clearTimeout(timer); | |
| } | |
| }); | |
| } | |
| }; | |
| /** | |
| * Called upon successful reconnect. | |
| * | |
| * @api private | |
| */ | |
| Manager.prototype.onreconnect = function(){ | |
| var attempt = this.attempts; | |
| this.attempts = 0; | |
| this.reconnecting = false; | |
| this.emitAll('reconnect', attempt); | |
| }; | |
| },{"./on":4,"./socket":5,"./url":6,"component-bind":7,"component-emitter":8,"debug":9,"engine.io-client":10,"indexof":36,"object-component":37,"socket.io-parser":40}],4:[function(_dereq_,module,exports){ | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = on; | |
| /** | |
| * Helper for subscriptions. | |
| * | |
| * @param {Object|EventEmitter} obj with `Emitter` mixin or `EventEmitter` | |
| * @param {String} event name | |
| * @param {Function} callback | |
| * @api public | |
| */ | |
| function on(obj, ev, fn) { | |
| obj.on(ev, fn); | |
| return { | |
| destroy: function(){ | |
| obj.removeListener(ev, fn); | |
| } | |
| }; | |
| } | |
| },{}],5:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var parser = _dereq_('socket.io-parser'); | |
| var Emitter = _dereq_('component-emitter'); | |
| var toArray = _dereq_('to-array'); | |
| var on = _dereq_('./on'); | |
| var bind = _dereq_('component-bind'); | |
| var debug = _dereq_('debug')('socket.io-client:socket'); | |
| var hasBin = _dereq_('has-binary'); | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = exports = Socket; | |
| /** | |
| * Internal events (blacklisted). | |
| * These events can't be emitted by the user. | |
| * | |
| * @api private | |
| */ | |
| var events = { | |
| connect: 1, | |
| connect_error: 1, | |
| connect_timeout: 1, | |
| disconnect: 1, | |
| error: 1, | |
| reconnect: 1, | |
| reconnect_attempt: 1, | |
| reconnect_failed: 1, | |
| reconnect_error: 1, | |
| reconnecting: 1 | |
| }; | |
| /** | |
| * Shortcut to `Emitter#emit`. | |
| */ | |
| var emit = Emitter.prototype.emit; | |
| /** | |
| * `Socket` constructor. | |
| * | |
| * @api public | |
| */ | |
| function Socket(io, nsp){ | |
| this.io = io; | |
| this.nsp = nsp; | |
| this.json = this; // compat | |
| this.ids = 0; | |
| this.acks = {}; | |
| if (this.io.autoConnect) this.open(); | |
| this.receiveBuffer = []; | |
| this.sendBuffer = []; | |
| this.connected = false; | |
| this.disconnected = true; | |
| } | |
| /** | |
| * Mix in `Emitter`. | |
| */ | |
| Emitter(Socket.prototype); | |
| /** | |
| * Subscribe to open, close and packet events | |
| * | |
| * @api private | |
| */ | |
| Socket.prototype.subEvents = function() { | |
| if (this.subs) return; | |
| var io = this.io; | |
| this.subs = [ | |
| on(io, 'open', bind(this, 'onopen')), | |
| on(io, 'packet', bind(this, 'onpacket')), | |
| on(io, 'close', bind(this, 'onclose')) | |
| ]; | |
| }; | |
| /** | |
| * "Opens" the socket. | |
| * | |
| * @api public | |
| */ | |
| Socket.prototype.open = | |
| Socket.prototype.connect = function(){ | |
| if (this.connected) return this; | |
| this.subEvents(); | |
| this.io.open(); // ensure open | |
| if ('open' == this.io.readyState) this.onopen(); | |
| return this; | |
| }; | |
| /** | |
| * Sends a `message` event. | |
| * | |
| * @return {Socket} self | |
| * @api public | |
| */ | |
| Socket.prototype.send = function(){ | |
| var args = toArray(arguments); | |
| args.unshift('message'); | |
| this.emit.apply(this, args); | |
| return this; | |
| }; | |
| /** | |
| * Override `emit`. | |
| * If the event is in `events`, it's emitted normally. | |
| * | |
| * @param {String} event name | |
| * @return {Socket} self | |
| * @api public | |
| */ | |
| Socket.prototype.emit = function(ev){ | |
| if (events.hasOwnProperty(ev)) { | |
| emit.apply(this, arguments); | |
| return this; | |
| } | |
| var args = toArray(arguments); | |
| var parserType = parser.EVENT; // default | |
| if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary | |
| var packet = { type: parserType, data: args }; | |
| // event ack callback | |
| if ('function' == typeof args[args.length - 1]) { | |
| debug('emitting packet with ack id %d', this.ids); | |
| this.acks[this.ids] = args.pop(); | |
| packet.id = this.ids++; | |
| } | |
| if (this.connected) { | |
| this.packet(packet); | |
| } else { | |
| this.sendBuffer.push(packet); | |
| } | |
| return this; | |
| }; | |
| /** | |
| * Sends a packet. | |
| * | |
| * @param {Object} packet | |
| * @api private | |
| */ | |
| Socket.prototype.packet = function(packet){ | |
| packet.nsp = this.nsp; | |
| this.io.packet(packet); | |
| }; | |
| /** | |
| * Called upon engine `open`. | |
| * | |
| * @api private | |
| */ | |
| Socket.prototype.onopen = function(){ | |
| debug('transport is open - connecting'); | |
| // write connect packet if necessary | |
| if ('/' != this.nsp) { | |
| this.packet({ type: parser.CONNECT }); | |
| } | |
| }; | |
| /** | |
| * Called upon engine `close`. | |
| * | |
| * @param {String} reason | |
| * @api private | |
| */ | |
| Socket.prototype.onclose = function(reason){ | |
| debug('close (%s)', reason); | |
| this.connected = false; | |
| this.disconnected = true; | |
| this.emit('disconnect', reason); | |
| }; | |
| /** | |
| * Called with socket packet. | |
| * | |
| * @param {Object} packet | |
| * @api private | |
| */ | |
| Socket.prototype.onpacket = function(packet){ | |
| if (packet.nsp != this.nsp) return; | |
| switch (packet.type) { | |
| case parser.CONNECT: | |
| this.onconnect(); | |
| break; | |
| case parser.EVENT: | |
| this.onevent(packet); | |
| break; | |
| case parser.BINARY_EVENT: | |
| this.onevent(packet); | |
| break; | |
| case parser.ACK: | |
| this.onack(packet); | |
| break; | |
| case parser.BINARY_ACK: | |
| this.onack(packet); | |
| break; | |
| case parser.DISCONNECT: | |
| this.ondisconnect(); | |
| break; | |
| case parser.ERROR: | |
| this.emit('error', packet.data); | |
| break; | |
| } | |
| }; | |
| /** | |
| * Called upon a server event. | |
| * | |
| * @param {Object} packet | |
| * @api private | |
| */ | |
| Socket.prototype.onevent = function(packet){ | |
| var args = packet.data || []; | |
| debug('emitting event %j', args); | |
| if (null != packet.id) { | |
| debug('attaching ack callback to event'); | |
| args.push(this.ack(packet.id)); | |
| } | |
| if (this.connected) { | |
| emit.apply(this, args); | |
| } else { | |
| this.receiveBuffer.push(args); | |
| } | |
| }; | |
| /** | |
| * Produces an ack callback to emit with an event. | |
| * | |
| * @api private | |
| */ | |
| Socket.prototype.ack = function(id){ | |
| var self = this; | |
| var sent = false; | |
| return function(){ | |
| // prevent double callbacks | |
| if (sent) return; | |
| sent = true; | |
| var args = toArray(arguments); | |
| debug('sending ack %j', args); | |
| var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK; | |
| self.packet({ | |
| type: type, | |
| id: id, | |
| data: args | |
| }); | |
| }; | |
| }; | |
| /** | |
| * Called upon a server acknowlegement. | |
| * | |
| * @param {Object} packet | |
| * @api private | |
| */ | |
| Socket.prototype.onack = function(packet){ | |
| debug('calling ack %s with %j', packet.id, packet.data); | |
| var fn = this.acks[packet.id]; | |
| fn.apply(this, packet.data); | |
| delete this.acks[packet.id]; | |
| }; | |
| /** | |
| * Called upon server connect. | |
| * | |
| * @api private | |
| */ | |
| Socket.prototype.onconnect = function(){ | |
| this.connected = true; | |
| this.disconnected = false; | |
| this.emit('connect'); | |
| this.emitBuffered(); | |
| }; | |
| /** | |
| * Emit buffered events (received and emitted). | |
| * | |
| * @api private | |
| */ | |
| Socket.prototype.emitBuffered = function(){ | |
| var i; | |
| for (i = 0; i < this.receiveBuffer.length; i++) { | |
| emit.apply(this, this.receiveBuffer[i]); | |
| } | |
| this.receiveBuffer = []; | |
| for (i = 0; i < this.sendBuffer.length; i++) { | |
| this.packet(this.sendBuffer[i]); | |
| } | |
| this.sendBuffer = []; | |
| }; | |
| /** | |
| * Called upon server disconnect. | |
| * | |
| * @api private | |
| */ | |
| Socket.prototype.ondisconnect = function(){ | |
| debug('server disconnect (%s)', this.nsp); | |
| this.destroy(); | |
| this.onclose('io server disconnect'); | |
| }; | |
| /** | |
| * Called upon forced client/server side disconnections, | |
| * this method ensures the manager stops tracking us and | |
| * that reconnections don't get triggered for this. | |
| * | |
| * @api private. | |
| */ | |
| Socket.prototype.destroy = function(){ | |
| if (this.subs) { | |
| // clean subscriptions to avoid reconnections | |
| for (var i = 0; i < this.subs.length; i++) { | |
| this.subs[i].destroy(); | |
| } | |
| this.subs = null; | |
| } | |
| this.io.destroy(this); | |
| }; | |
| /** | |
| * Disconnects the socket manually. | |
| * | |
| * @return {Socket} self | |
| * @api public | |
| */ | |
| Socket.prototype.close = | |
| Socket.prototype.disconnect = function(){ | |
| if (this.connected) { | |
| debug('performing disconnect (%s)', this.nsp); | |
| this.packet({ type: parser.DISCONNECT }); | |
| } | |
| // remove socket from pool | |
| this.destroy(); | |
| if (this.connected) { | |
| // fire events | |
| this.onclose('io client disconnect'); | |
| } | |
| return this; | |
| }; | |
| },{"./on":4,"component-bind":7,"component-emitter":8,"debug":9,"has-binary":32,"socket.io-parser":40,"to-array":44}],6:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var parseuri = _dereq_('parseuri'); | |
| var debug = _dereq_('debug')('socket.io-client:url'); | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = url; | |
| /** | |
| * URL parser. | |
| * | |
| * @param {String} url | |
| * @param {Object} An object meant to mimic window.location. | |
| * Defaults to window.location. | |
| * @api public | |
| */ | |
| function url(uri, loc){ | |
| var obj = uri; | |
| // default to window.location | |
| var loc = loc || global.location; | |
| if (null == uri) uri = loc.protocol + '//' + loc.hostname; | |
| // relative path support | |
| if ('string' == typeof uri) { | |
| if ('/' == uri.charAt(0)) { | |
| if ('/' == uri.charAt(1)) { | |
| uri = loc.protocol + uri; | |
| } else { | |
| uri = loc.hostname + uri; | |
| } | |
| } | |
| if (!/^(https?|wss?):\/\//.test(uri)) { | |
| debug('protocol-less url %s', uri); | |
| if ('undefined' != typeof loc) { | |
| uri = loc.protocol + '//' + uri; | |
| } else { | |
| uri = 'https://' + uri; | |
| } | |
| } | |
| // parse | |
| debug('parse %s', uri); | |
| obj = parseuri(uri); | |
| } | |
| // make sure we treat `localhost:80` and `localhost` equally | |
| if (!obj.port) { | |
| if (/^(http|ws)$/.test(obj.protocol)) { | |
| obj.port = '80'; | |
| } | |
| else if (/^(http|ws)s$/.test(obj.protocol)) { | |
| obj.port = '443'; | |
| } | |
| } | |
| obj.path = obj.path || '/'; | |
| // define unique id | |
| obj.id = obj.protocol + '://' + obj.host + ':' + obj.port; | |
| // define href | |
| obj.href = obj.protocol + '://' + obj.host + (loc && loc.port == obj.port ? '' : (':' + obj.port)); | |
| return obj; | |
| } | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"debug":9,"parseuri":38}],7:[function(_dereq_,module,exports){ | |
| /** | |
| * Slice reference. | |
| */ | |
| var slice = [].slice; | |
| /** | |
| * Bind `obj` to `fn`. | |
| * | |
| * @param {Object} obj | |
| * @param {Function|String} fn or string | |
| * @return {Function} | |
| * @api public | |
| */ | |
| module.exports = function(obj, fn){ | |
| if ('string' == typeof fn) fn = obj[fn]; | |
| if ('function' != typeof fn) throw new Error('bind() requires a function'); | |
| var args = slice.call(arguments, 2); | |
| return function(){ | |
| return fn.apply(obj, args.concat(slice.call(arguments))); | |
| } | |
| }; | |
| },{}],8:[function(_dereq_,module,exports){ | |
| /** | |
| * Expose `Emitter`. | |
| */ | |
| module.exports = Emitter; | |
| /** | |
| * Initialize a new `Emitter`. | |
| * | |
| * @api public | |
| */ | |
| function Emitter(obj) { | |
| if (obj) return mixin(obj); | |
| }; | |
| /** | |
| * Mixin the emitter properties. | |
| * | |
| * @param {Object} obj | |
| * @return {Object} | |
| * @api private | |
| */ | |
| function mixin(obj) { | |
| for (var key in Emitter.prototype) { | |
| obj[key] = Emitter.prototype[key]; | |
| } | |
| return obj; | |
| } | |
| /** | |
| * Listen on the given `event` with `fn`. | |
| * | |
| * @param {String} event | |
| * @param {Function} fn | |
| * @return {Emitter} | |
| * @api public | |
| */ | |
| Emitter.prototype.on = | |
| Emitter.prototype.addEventListener = function(event, fn){ | |
| this._callbacks = this._callbacks || {}; | |
| (this._callbacks[event] = this._callbacks[event] || []) | |
| .push(fn); | |
| return this; | |
| }; | |
| /** | |
| * Adds an `event` listener that will be invoked a single | |
| * time then automatically removed. | |
| * | |
| * @param {String} event | |
| * @param {Function} fn | |
| * @return {Emitter} | |
| * @api public | |
| */ | |
| Emitter.prototype.once = function(event, fn){ | |
| var self = this; | |
| this._callbacks = this._callbacks || {}; | |
| function on() { | |
| self.off(event, on); | |
| fn.apply(this, arguments); | |
| } | |
| on.fn = fn; | |
| this.on(event, on); | |
| return this; | |
| }; | |
| /** | |
| * Remove the given callback for `event` or all | |
| * registered callbacks. | |
| * | |
| * @param {String} event | |
| * @param {Function} fn | |
| * @return {Emitter} | |
| * @api public | |
| */ | |
| Emitter.prototype.off = | |
| Emitter.prototype.removeListener = | |
| Emitter.prototype.removeAllListeners = | |
| Emitter.prototype.removeEventListener = function(event, fn){ | |
| this._callbacks = this._callbacks || {}; | |
| // all | |
| if (0 == arguments.length) { | |
| this._callbacks = {}; | |
| return this; | |
| } | |
| // specific event | |
| var callbacks = this._callbacks[event]; | |
| if (!callbacks) return this; | |
| // remove all handlers | |
| if (1 == arguments.length) { | |
| delete this._callbacks[event]; | |
| return this; | |
| } | |
| // remove specific handler | |
| var cb; | |
| for (var i = 0; i < callbacks.length; i++) { | |
| cb = callbacks[i]; | |
| if (cb === fn || cb.fn === fn) { | |
| callbacks.splice(i, 1); | |
| break; | |
| } | |
| } | |
| return this; | |
| }; | |
| /** | |
| * Emit `event` with the given args. | |
| * | |
| * @param {String} event | |
| * @param {Mixed} ... | |
| * @return {Emitter} | |
| */ | |
| Emitter.prototype.emit = function(event){ | |
| this._callbacks = this._callbacks || {}; | |
| var args = [].slice.call(arguments, 1) | |
| , callbacks = this._callbacks[event]; | |
| if (callbacks) { | |
| callbacks = callbacks.slice(0); | |
| for (var i = 0, len = callbacks.length; i < len; ++i) { | |
| callbacks[i].apply(this, args); | |
| } | |
| } | |
| return this; | |
| }; | |
| /** | |
| * Return array of callbacks for `event`. | |
| * | |
| * @param {String} event | |
| * @return {Array} | |
| * @api public | |
| */ | |
| Emitter.prototype.listeners = function(event){ | |
| this._callbacks = this._callbacks || {}; | |
| return this._callbacks[event] || []; | |
| }; | |
| /** | |
| * Check if this emitter has `event` handlers. | |
| * | |
| * @param {String} event | |
| * @return {Boolean} | |
| * @api public | |
| */ | |
| Emitter.prototype.hasListeners = function(event){ | |
| return !! this.listeners(event).length; | |
| }; | |
| },{}],9:[function(_dereq_,module,exports){ | |
| /** | |
| * Expose `debug()` as the module. | |
| */ | |
| module.exports = debug; | |
| /** | |
| * Create a debugger with the given `name`. | |
| * | |
| * @param {String} name | |
| * @return {Type} | |
| * @api public | |
| */ | |
| function debug(name) { | |
| if (!debug.enabled(name)) return function(){}; | |
| return function(fmt){ | |
| fmt = coerce(fmt); | |
| var curr = new Date; | |
| var ms = curr - (debug[name] || curr); | |
| debug[name] = curr; | |
| fmt = name | |
| + ' ' | |
| + fmt | |
| + ' +' + debug.humanize(ms); | |
| // This hackery is required for IE8 | |
| // where `console.log` doesn't have 'apply' | |
| window.console | |
| && console.log | |
| && Function.prototype.apply.call(console.log, console, arguments); | |
| } | |
| } | |
| /** | |
| * The currently active debug mode names. | |
| */ | |
| debug.names = []; | |
| debug.skips = []; | |
| /** | |
| * Enables a debug mode by name. This can include modes | |
| * separated by a colon and wildcards. | |
| * | |
| * @param {String} name | |
| * @api public | |
| */ | |
| debug.enable = function(name) { | |
| try { | |
| localStorage.debug = name; | |
| } catch(e){} | |
| var split = (name || '').split(/[\s,]+/) | |
| , len = split.length; | |
| for (var i = 0; i < len; i++) { | |
| name = split[i].replace('*', '.*?'); | |
| if (name[0] === '-') { | |
| debug.skips.push(new RegExp('^' + name.substr(1) + '$')); | |
| } | |
| else { | |
| debug.names.push(new RegExp('^' + name + '$')); | |
| } | |
| } | |
| }; | |
| /** | |
| * Disable debug output. | |
| * | |
| * @api public | |
| */ | |
| debug.disable = function(){ | |
| debug.enable(''); | |
| }; | |
| /** | |
| * Humanize the given `ms`. | |
| * | |
| * @param {Number} m | |
| * @return {String} | |
| * @api private | |
| */ | |
| debug.humanize = function(ms) { | |
| var sec = 1000 | |
| , min = 60 * 1000 | |
| , hour = 60 * min; | |
| if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; | |
| if (ms >= min) return (ms / min).toFixed(1) + 'm'; | |
| if (ms >= sec) return (ms / sec | 0) + 's'; | |
| return ms + 'ms'; | |
| }; | |
| /** | |
| * Returns true if the given mode name is enabled, false otherwise. | |
| * | |
| * @param {String} name | |
| * @return {Boolean} | |
| * @api public | |
| */ | |
| debug.enabled = function(name) { | |
| for (var i = 0, len = debug.skips.length; i < len; i++) { | |
| if (debug.skips[i].test(name)) { | |
| return false; | |
| } | |
| } | |
| for (var i = 0, len = debug.names.length; i < len; i++) { | |
| if (debug.names[i].test(name)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| }; | |
| /** | |
| * Coerce `val`. | |
| */ | |
| function coerce(val) { | |
| if (val instanceof Error) return val.stack || val.message; | |
| return val; | |
| } | |
| // persist | |
| try { | |
| if (window.localStorage) debug.enable(localStorage.debug); | |
| } catch(e){} | |
| },{}],10:[function(_dereq_,module,exports){ | |
| module.exports = _dereq_('./lib/'); | |
| },{"./lib/":11}],11:[function(_dereq_,module,exports){ | |
| module.exports = _dereq_('./socket'); | |
| /** | |
| * Exports parser | |
| * | |
| * @api public | |
| * | |
| */ | |
| module.exports.parser = _dereq_('engine.io-parser'); | |
| },{"./socket":12,"engine.io-parser":21}],12:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var transports = _dereq_('./transports'); | |
| var Emitter = _dereq_('component-emitter'); | |
| var debug = _dereq_('debug')('engine.io-client:socket'); | |
| var index = _dereq_('indexof'); | |
| var parser = _dereq_('engine.io-parser'); | |
| var parseuri = _dereq_('parseuri'); | |
| var parsejson = _dereq_('parsejson'); | |
| var parseqs = _dereq_('parseqs'); | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = Socket; | |
| /** | |
| * Noop function. | |
| * | |
| * @api private | |
| */ | |
| function noop(){} | |
| /** | |
| * 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.host = uri.host; | |
| opts.secure = uri.protocol == 'https' || uri.protocol == 'wss'; | |
| opts.port = uri.port; | |
| if (uri.query) opts.query = uri.query; | |
| } | |
| this.secure = null != opts.secure ? opts.secure : | |
| (global.location && 'https:' == location.protocol); | |
| if (opts.host) { | |
| var pieces = opts.host.split(':'); | |
| opts.hostname = pieces.shift(); | |
| if (pieces.length) opts.port = pieces.pop(); | |
| } | |
| 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.readyState = ''; | |
| this.writeBuffer = []; | |
| this.callbackBuffer = []; | |
| this.policyPort = opts.policyPort || 843; | |
| this.rememberUpgrade = opts.rememberUpgrade || false; | |
| this.open(); | |
| this.binaryType = null; | |
| this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades; | |
| } | |
| 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 = _dereq_('./transport'); | |
| Socket.transports = _dereq_('./transports'); | |
| Socket.parser = _dereq_('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; | |
| // session id if we already have one | |
| if (this.id) query.sid = this.id; | |
| var transport = new transports[name]({ | |
| agent: this.agent, | |
| hostname: this.hostname, | |
| port: this.port, | |
| secure: this.secure, | |
| path: this.path, | |
| query: query, | |
| forceJSONP: this.forceJSONP, | |
| jsonp: this.jsonp, | |
| forceBase64: this.forceBase64, | |
| enablesXDR: this.enablesXDR, | |
| timestampRequests: this.timestampRequests, | |
| timestampParam: this.timestampParam, | |
| policyPort: this.policyPort, | |
| socket: this | |
| }); | |
| 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) | |
| var transport; | |
| 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 }) | |
| , failed = false | |
| , 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) { | |
| 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(parsejson(packet.data)); | |
| break; | |
| case 'pong': | |
| this.setPing(); | |
| break; | |
| case 'error': | |
| var err = new Error('server error'); | |
| err.code = packet.data; | |
| this.emit('error', 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 public | |
| */ | |
| Socket.prototype.ping = function () { | |
| this.sendPacket('ping'); | |
| }; | |
| /** | |
| * Called on `drain` event | |
| * | |
| * @api private | |
| */ | |
| Socket.prototype.onDrain = function() { | |
| for (var i = 0; i < this.prevBufferLen; i++) { | |
| if (this.callbackBuffer[i]) { | |
| this.callbackBuffer[i](); | |
| } | |
| } | |
| this.writeBuffer.splice(0, this.prevBufferLen); | |
| this.callbackBuffer.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 (this.writeBuffer.length == 0) { | |
| 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. | |
| * @return {Socket} for chaining. | |
| * @api public | |
| */ | |
| Socket.prototype.write = | |
| Socket.prototype.send = function (msg, fn) { | |
| this.sendPacket('message', msg, fn); | |
| return this; | |
| }; | |
| /** | |
| * Sends a packet. | |
| * | |
| * @param {String} packet type. | |
| * @param {String} data. | |
| * @param {Function} callback function. | |
| * @api private | |
| */ | |
| Socket.prototype.sendPacket = function (type, data, fn) { | |
| if ('closing' == this.readyState || 'closed' == this.readyState) { | |
| return; | |
| } | |
| var packet = { type: type, data: data }; | |
| this.emit('packetCreate', packet); | |
| this.writeBuffer.push(packet); | |
| this.callbackBuffer.push(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; | |
| 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); | |
| } | |
| if (this.writeBuffer.length) { | |
| this.once('drain', function() { | |
| if (this.upgrading) { | |
| waitForUpgrade(); | |
| } else { | |
| close(); | |
| } | |
| }); | |
| } else if (this.upgrading) { | |
| waitForUpgrade(); | |
| } else { | |
| close(); | |
| } | |
| } | |
| 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); | |
| // clean buffers in next tick, so developers can still | |
| // grab the buffers on `close` event | |
| setTimeout(function() { | |
| self.writeBuffer = []; | |
| self.callbackBuffer = []; | |
| self.prevBufferLen = 0; | |
| }, 0); | |
| // 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); | |
| } | |
| }; | |
| /** | |
| * 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; | |
| }; | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"./transport":13,"./transports":14,"component-emitter":8,"debug":9,"engine.io-parser":21,"indexof":36,"parsejson":28,"parseqs":29,"parseuri":30}],13:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var parser = _dereq_('engine.io-parser'); | |
| var Emitter = _dereq_('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; | |
| } | |
| /** | |
| * Mix in `Emitter`. | |
| */ | |
| Emitter(Transport.prototype); | |
| /** | |
| * A counter used to prevent collisions in the timestamps used | |
| * for cache busting. | |
| */ | |
| Transport.timestamps = 0; | |
| /** | |
| * 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'); | |
| }; | |
| },{"component-emitter":8,"engine.io-parser":21}],14:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * Module dependencies | |
| */ | |
| var XMLHttpRequest = _dereq_('xmlhttprequest'); | |
| var XHR = _dereq_('./polling-xhr'); | |
| var JSONP = _dereq_('./polling-jsonp'); | |
| var websocket = _dereq_('./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); | |
| } | |
| } | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"./polling-jsonp":15,"./polling-xhr":16,"./websocket":18,"xmlhttprequest":19}],15:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * Module requirements. | |
| */ | |
| var Polling = _dereq_('./polling'); | |
| var inherit = _dereq_('component-inherit'); | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = JSONPPolling; | |
| /** | |
| * Cached regular expressions. | |
| */ | |
| var rNewline = /\n/g; | |
| var rEscapedNewline = /\\n/g; | |
| /** | |
| * Global JSONP callbacks. | |
| */ | |
| var callbacks; | |
| /** | |
| * Callbacks count. | |
| */ | |
| var index = 0; | |
| /** | |
| * 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; | |
| }); | |
| } | |
| } | |
| /** | |
| * 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]; | |
| insertAt.parentNode.insertBefore(script, insertAt); | |
| 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; | |
| } | |
| }; | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"./polling":17,"component-inherit":20}],16:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * Module requirements. | |
| */ | |
| var XMLHttpRequest = _dereq_('xmlhttprequest'); | |
| var Polling = _dereq_('./polling'); | |
| var Emitter = _dereq_('component-emitter'); | |
| var inherit = _dereq_('component-inherit'); | |
| var debug = _dereq_('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); | |
| 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; | |
| 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.create(); | |
| } | |
| /** | |
| * Mix in `Emitter`. | |
| */ | |
| Emitter(Request.prototype); | |
| /** | |
| * Creates the XHR object and sends the request. | |
| * | |
| * @api private | |
| */ | |
| Request.prototype.create = function(){ | |
| var xhr = this.xhr = new XMLHttpRequest({ agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR }); | |
| var self = this; | |
| try { | |
| debug('xhr open %s: %s', this.method, this.uri); | |
| xhr.open(this.method, this.uri, this.async); | |
| if (this.supportsBinary) { | |
| // This has to be done after open because Firefox is stupid | |
| // http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension | |
| xhr.responseType = 'arraybuffer'; | |
| } | |
| 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) {} | |
| } | |
| // ie6 check | |
| if ('withCredentials' in xhr) { | |
| xhr.withCredentials = true; | |
| } | |
| if (this.hasXDR()) { | |
| xhr.onload = function(){ | |
| self.onLoad(); | |
| }; | |
| xhr.onerror = function(){ | |
| self.onError(xhr.responseText); | |
| }; | |
| } else { | |
| xhr.onreadystatechange = function(){ | |
| 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(); | |
| }; | |
| /** | |
| * Cleans up house. | |
| * | |
| * @api private | |
| */ | |
| Request.prototype.cleanup = function(){ | |
| 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; | |
| } | |
| 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').split(';')[0]; | |
| } catch (e) {} | |
| if (contentType === 'application/octet-stream') { | |
| data = this.xhr.response; | |
| } else { | |
| if (!this.supportsBinary) { | |
| data = this.xhr.responseText; | |
| } else { | |
| data = 'ok'; | |
| } | |
| } | |
| } 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. | |
| */ | |
| if (global.document) { | |
| Request.requestsCount = 0; | |
| Request.requests = {}; | |
| if (global.attachEvent) { | |
| global.attachEvent('onunload', unloadHandler); | |
| } else if (global.addEventListener) { | |
| global.addEventListener('beforeunload', unloadHandler); | |
| } | |
| } | |
| function unloadHandler() { | |
| for (var i in Request.requests) { | |
| if (Request.requests.hasOwnProperty(i)) { | |
| Request.requests[i].abort(); | |
| } | |
| } | |
| } | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"./polling":17,"component-emitter":8,"component-inherit":20,"debug":9,"xmlhttprequest":19}],17:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var Transport = _dereq_('../transport'); | |
| var parseqs = _dereq_('parseqs'); | |
| var parser = _dereq_('engine.io-parser'); | |
| var inherit = _dereq_('component-inherit'); | |
| var debug = _dereq_('debug')('engine.io-client:polling'); | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = Polling; | |
| /** | |
| * Is XHR2 supported? | |
| */ | |
| var hasXHR2 = (function() { | |
| var XMLHttpRequest = _dereq_('xmlhttprequest'); | |
| 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 pending = 0; | |
| 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'); | |
| }; | |
| var self = this; | |
| 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] = +new Date + '-' + Transport.timestamps++; | |
| } | |
| if (!this.supportsBinary && !query.sid) { | |
| query.b64 = 1; | |
| } | |
| query = parseqs.encode(query); | |
| // avoid port if default for schema | |
| if (this.port && (('https' == schema && this.port != 443) || | |
| ('http' == schema && this.port != 80))) { | |
| port = ':' + this.port; | |
| } | |
| // prepend ? to query | |
| if (query.length) { | |
| query = '?' + query; | |
| } | |
| return schema + '://' + this.hostname + port + this.path + query; | |
| }; | |
| },{"../transport":13,"component-inherit":20,"debug":9,"engine.io-parser":21,"parseqs":29,"xmlhttprequest":19}],18:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var Transport = _dereq_('../transport'); | |
| var parser = _dereq_('engine.io-parser'); | |
| var parseqs = _dereq_('parseqs'); | |
| var inherit = _dereq_('component-inherit'); | |
| var debug = _dereq_('debug')('engine.io-client:websocket'); | |
| /** | |
| * `ws` exposes a WebSocket-compatible interface in | |
| * Node, or the `WebSocket` or `MozWebSocket` globals | |
| * in the browser. | |
| */ | |
| var WebSocket = require('net.iamyellow.tiws'); | |
| /** | |
| * 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; | |
| } | |
| 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(){ | |
| // TODO: Figure out and fix. This causes initial connection to time out on iOS. | |
| if (!this.check()) { | |
| // let probe timeout | |
| return; | |
| } | |
| var self = this; | |
| var uri = this.uri(); | |
| var protocols = void(0); | |
| var opts = { agent: this.agent }; | |
| this.ws = WebSocket.createWS(); | |
| if (this.ws.binaryType === undefined) { | |
| this.supportsBinary = false; | |
| } | |
| this.ws.binaryType = 'arraybuffer'; | |
| this.addEventListeners(); | |
| this.ws.open(uri); | |
| }; | |
| /** | |
| * Adds event listeners to the socket | |
| * | |
| * @api private | |
| */ | |
| WS.prototype.addEventListeners = function(){ | |
| var self = this; | |
| this.ws.addEventListener('open', function () { | |
| self.onOpen(); | |
| }); | |
| this.ws.addEventListener('close', function (ev) { | |
| self.onClose(); | |
| }); | |
| this.ws.addEventListener('message', function (ev) { | |
| self.onData(ev.data); | |
| }); | |
| this.ws.addEventListener('error', function (e) { | |
| self.onError('websocket error', e); | |
| }); | |
| }; | |
| /** | |
| * Override `onData` to use a timer on iOS. | |
| * See: https://gist.github.com/mloughran/2052006 | |
| * | |
| * @api private | |
| */ | |
| if ('undefined' != typeof navigator | |
| && /iPad|iPhone|iPod/i.test(navigator.userAgent)) { | |
| WS.prototype.onData = function(data){ | |
| var self = this; | |
| setTimeout(function(){ | |
| Transport.prototype.onData.call(self, data); | |
| }, 0); | |
| }; | |
| } | |
| /** | |
| * 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 | |
| for (var i = 0, l = packets.length; i < l; i++) { | |
| parser.encodePacket(packets[i], this.supportsBinary, function(data) { | |
| //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 { | |
| self.ws.send(data); | |
| } catch (e){ | |
| debug('websocket closed before onclose event'); | |
| } | |
| }); | |
| } | |
| function ondrain() { | |
| self.writable = true; | |
| self.emit('drain'); | |
| } | |
| // fake drain | |
| // defer to next tick to allow Socket to clear writeBuffer | |
| setTimeout(ondrain, 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 && this.port != 443) | |
| || ('ws' == schema && this.port != 80))) { | |
| port = ':' + this.port; | |
| } | |
| // append timestamp to URI | |
| if (this.timestampRequests) { | |
| query[this.timestampParam] = +new Date; | |
| } | |
| // communicate binary support capabilities | |
| if (!this.supportsBinary) { | |
| query.b64 = 1; | |
| } | |
| query = parseqs.encode(query); | |
| // prepend ? to query | |
| if (query.length) { | |
| query = '?' + query; | |
| } | |
| return schema + '://' + 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); | |
| }; | |
| },{"../transport":13,"component-inherit":20,"debug":9,"engine.io-parser":21,"parseqs":29,"ws":31}],19:[function(_dereq_,module,exports){ | |
| // browser shim for xmlhttprequest module | |
| var hasCORS = _dereq_('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 ActiveXObject('Microsoft.XMLHTTP'); | |
| } catch(e) { } | |
| } | |
| } | |
| },{"has-cors":34}],20:[function(_dereq_,module,exports){ | |
| module.exports = function(a, b){ | |
| var fn = function(){}; | |
| fn.prototype = b.prototype; | |
| a.prototype = new fn; | |
| a.prototype.constructor = a; | |
| }; | |
| },{}],21:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var keys = _dereq_('./keys'); | |
| var sliceBuffer = _dereq_('arraybuffer.slice'); | |
| var base64encoder = _dereq_('base64-arraybuffer'); | |
| var after = _dereq_('after'); | |
| var utf8 = _dereq_('utf8'); | |
| /** | |
| * Check if we are running an android browser. That requires us to use | |
| * ArrayBuffer with polling transports... | |
| * | |
| * http://ghinda.net/jpeg-blob-ajax-android/ | |
| */ | |
| var isAndroid = false; // navigator.userAgent.match(/Android/i); | |
| /** | |
| * Current protocol version. | |
| */ | |
| exports.protocol = 3; | |
| /** | |
| * Packet types. | |
| */ | |
| var packets = exports.packets = { | |
| open: 0 // non-ws | |
| , close: 1 // non-ws | |
| , ping: 2 | |
| , pong: 3 | |
| , message: 4 | |
| , upgrade: 5 | |
| , noop: 6 | |
| }; | |
| var packetslist = keys(packets); | |
| /** | |
| * Premade error packet. | |
| */ | |
| var err = { type: 'error', data: 'parser error' }; | |
| /** | |
| * Create a blob api even for blob builder when vendor prefixes exist | |
| */ | |
| var Blob = _dereq_('blob'); | |
| /** | |
| * Encodes a packet. | |
| * | |
| * <packet type id> [ <data> ] | |
| * | |
| * Example: | |
| * | |
| * 5hello world | |
| * 3 | |
| * 4 | |
| * | |
| * Binary is encoded in an identical principle | |
| * | |
| * @api private | |
| */ | |
| exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) { | |
| if ('function' == typeof supportsBinary) { | |
| callback = supportsBinary; | |
| supportsBinary = false; | |
| } | |
| if ('function' == typeof utf8encode) { | |
| callback = utf8encode; | |
| utf8encode = null; | |
| } | |
| var data = (packet.data === undefined) | |
| ? undefined | |
| : packet.data.buffer || packet.data; | |
| if (global.ArrayBuffer && data instanceof ArrayBuffer) { | |
| return encodeArrayBuffer(packet, supportsBinary, callback); | |
| } else if (Blob && data instanceof global.Blob) { | |
| return encodeBlob(packet, supportsBinary, callback); | |
| } | |
| // Sending data as a utf-8 string | |
| var encoded = packets[packet.type]; | |
| // data fragment is optional | |
| if (undefined !== packet.data) { | |
| encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data); | |
| } | |
| return callback('' + encoded); | |
| }; | |
| /** | |
| * Encode packet helpers for binary types | |
| */ | |
| function encodeArrayBuffer(packet, supportsBinary, callback) { | |
| if (!supportsBinary) { | |
| return exports.encodeBase64Packet(packet, callback); | |
| } | |
| var data = packet.data; | |
| var contentArray = new Uint8Array(data); | |
| var resultBuffer = new Uint8Array(1 + data.byteLength); | |
| resultBuffer[0] = packets[packet.type]; | |
| for (var i = 0; i < contentArray.length; i++) { | |
| resultBuffer[i+1] = contentArray[i]; | |
| } | |
| return callback(resultBuffer.buffer); | |
| } | |
| function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) { | |
| if (!supportsBinary) { | |
| return exports.encodeBase64Packet(packet, callback); | |
| } | |
| var fr = new FileReader(); | |
| fr.onload = function() { | |
| packet.data = fr.result; | |
| exports.encodePacket(packet, supportsBinary, true, callback); | |
| }; | |
| return fr.readAsArrayBuffer(packet.data); | |
| } | |
| function encodeBlob(packet, supportsBinary, callback) { | |
| if (!supportsBinary) { | |
| return exports.encodeBase64Packet(packet, callback); | |
| } | |
| if (isAndroid) { | |
| return encodeBlobAsArrayBuffer(packet, supportsBinary, callback); | |
| } | |
| var length = new Uint8Array(1); | |
| length[0] = packets[packet.type]; | |
| var blob = new Blob([length.buffer, packet.data]); | |
| return callback(blob); | |
| } | |
| /** | |
| * Encodes a packet with binary data in a base64 string | |
| * | |
| * @param {Object} packet, has `type` and `data` | |
| * @return {String} base64 encoded message | |
| */ | |
| exports.encodeBase64Packet = function(packet, callback) { | |
| var message = 'b' + exports.packets[packet.type]; | |
| if (Blob && packet.data instanceof Blob) { | |
| var fr = new FileReader(); | |
| fr.onload = function() { | |
| var b64 = fr.result.split(',')[1]; | |
| callback(message + b64); | |
| }; | |
| return fr.readAsDataURL(packet.data); | |
| } | |
| var b64data; | |
| try { | |
| b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data)); | |
| } catch (e) { | |
| // iPhone Safari doesn't let you apply with typed arrays | |
| var typed = new Uint8Array(packet.data); | |
| var basic = new Array(typed.length); | |
| for (var i = 0; i < typed.length; i++) { | |
| basic[i] = typed[i]; | |
| } | |
| b64data = String.fromCharCode.apply(null, basic); | |
| } | |
| message += global.btoa(b64data); | |
| return callback(message); | |
| }; | |
| /** | |
| * Decodes a packet. Changes format to Blob if requested. | |
| * | |
| * @return {Object} with `type` and `data` (if any) | |
| * @api private | |
| */ | |
| exports.decodePacket = function (data, binaryType, utf8decode) { | |
| // String data | |
| if (typeof data == 'string' || data === undefined) { | |
| if (data.charAt(0) == 'b') { | |
| return exports.decodeBase64Packet(data.substr(1), binaryType); | |
| } | |
| if (utf8decode) { | |
| try { | |
| data = utf8.decode(data); | |
| } catch (e) { | |
| return err; | |
| } | |
| } | |
| var type = data.charAt(0); | |
| if (Number(type) != type || !packetslist[type]) { | |
| return err; | |
| } | |
| if (data.length > 1) { | |
| return { type: packetslist[type], data: data.substring(1) }; | |
| } else { | |
| return { type: packetslist[type] }; | |
| } | |
| } | |
| var asArray = new Uint8Array(data); | |
| var type = asArray[0]; | |
| var rest = sliceBuffer(data, 1); | |
| if (Blob && binaryType === 'blob') { | |
| rest = new Blob([rest]); | |
| } | |
| return { type: packetslist[type], data: rest }; | |
| }; | |
| /** | |
| * Decodes a packet encoded in a base64 string | |
| * | |
| * @param {String} base64 encoded message | |
| * @return {Object} with `type` and `data` (if any) | |
| */ | |
| exports.decodeBase64Packet = function(msg, binaryType) { | |
| var type = packetslist[msg.charAt(0)]; | |
| if (!global.ArrayBuffer) { | |
| return { type: type, data: { base64: true, data: msg.substr(1) } }; | |
| } | |
| var data = base64encoder.decode(msg.substr(1)); | |
| if (binaryType === 'blob' && Blob) { | |
| data = new Blob([data]); | |
| } | |
| return { type: type, data: data }; | |
| }; | |
| /** | |
| * Encodes multiple messages (payload). | |
| * | |
| * <length>:data | |
| * | |
| * Example: | |
| * | |
| * 11:hello world2:hi | |
| * | |
| * If any contents are binary, they will be encoded as base64 strings. Base64 | |
| * encoded strings are marked with a b before the length specifier | |
| * | |
| * @param {Array} packets | |
| * @api private | |
| */ | |
| exports.encodePayload = function (packets, supportsBinary, callback) { | |
| if (typeof supportsBinary == 'function') { | |
| callback = supportsBinary; | |
| supportsBinary = null; | |
| } | |
| if (supportsBinary) { | |
| if (Blob && !isAndroid) { | |
| return exports.encodePayloadAsBlob(packets, callback); | |
| } | |
| return exports.encodePayloadAsArrayBuffer(packets, callback); | |
| } | |
| if (!packets.length) { | |
| return callback('0:'); | |
| } | |
| function setLengthHeader(message) { | |
| return message.length + ':' + message; | |
| } | |
| function encodeOne(packet, doneCallback) { | |
| exports.encodePacket(packet, supportsBinary, true, function(message) { | |
| doneCallback(null, setLengthHeader(message)); | |
| }); | |
| } | |
| map(packets, encodeOne, function(err, results) { | |
| return callback(results.join('')); | |
| }); | |
| }; | |
| /** | |
| * Async array map using after | |
| */ | |
| function map(ary, each, done) { | |
| var result = new Array(ary.length); | |
| var next = after(ary.length, done); | |
| var eachWithIndex = function(i, el, cb) { | |
| each(el, function(error, msg) { | |
| result[i] = msg; | |
| cb(error, result); | |
| }); | |
| }; | |
| for (var i = 0; i < ary.length; i++) { | |
| eachWithIndex(i, ary[i], next); | |
| } | |
| } | |
| /* | |
| * Decodes data when a payload is maybe expected. Possible binary contents are | |
| * decoded from their base64 representation | |
| * | |
| * @param {String} data, callback method | |
| * @api public | |
| */ | |
| exports.decodePayload = function (data, binaryType, callback) { | |
| if (typeof data != 'string') { | |
| return exports.decodePayloadAsBinary(data, binaryType, callback); | |
| } | |
| if (typeof binaryType === 'function') { | |
| callback = binaryType; | |
| binaryType = null; | |
| } | |
| var packet; | |
| if (data == '') { | |
| // parser error - ignoring payload | |
| return callback(err, 0, 1); | |
| } | |
| var length = '' | |
| , n, msg; | |
| for (var i = 0, l = data.length; i < l; i++) { | |
| var chr = data.charAt(i); | |
| if (':' != chr) { | |
| length += chr; | |
| } else { | |
| if ('' == length || (length != (n = Number(length)))) { | |
| // parser error - ignoring payload | |
| return callback(err, 0, 1); | |
| } | |
| msg = data.substr(i + 1, n); | |
| if (length != msg.length) { | |
| // parser error - ignoring payload | |
| return callback(err, 0, 1); | |
| } | |
| if (msg.length) { | |
| packet = exports.decodePacket(msg, binaryType, true); | |
| if (err.type == packet.type && err.data == packet.data) { | |
| // parser error in individual packet - ignoring payload | |
| return callback(err, 0, 1); | |
| } | |
| var ret = callback(packet, i + n, l); | |
| if (false === ret) return; | |
| } | |
| // advance cursor | |
| i += n; | |
| length = ''; | |
| } | |
| } | |
| if (length != '') { | |
| // parser error - ignoring payload | |
| return callback(err, 0, 1); | |
| } | |
| }; | |
| /** | |
| * Encodes multiple messages (payload) as binary. | |
| * | |
| * <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number | |
| * 255><data> | |
| * | |
| * Example: | |
| * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers | |
| * | |
| * @param {Array} packets | |
| * @return {ArrayBuffer} encoded payload | |
| * @api private | |
| */ | |
| exports.encodePayloadAsArrayBuffer = function(packets, callback) { | |
| if (!packets.length) { | |
| return callback(new ArrayBuffer(0)); | |
| } | |
| function encodeOne(packet, doneCallback) { | |
| exports.encodePacket(packet, true, true, function(data) { | |
| return doneCallback(null, data); | |
| }); | |
| } | |
| map(packets, encodeOne, function(err, encodedPackets) { | |
| var totalLength = encodedPackets.reduce(function(acc, p) { | |
| var len; | |
| if (typeof p === 'string'){ | |
| len = p.length; | |
| } else { | |
| len = p.byteLength; | |
| } | |
| return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2 | |
| }, 0); | |
| var resultArray = new Uint8Array(totalLength); | |
| var bufferIndex = 0; | |
| encodedPackets.forEach(function(p) { | |
| var isString = typeof p === 'string'; | |
| var ab = p; | |
| if (isString) { | |
| var view = new Uint8Array(p.length); | |
| for (var i = 0; i < p.length; i++) { | |
| view[i] = p.charCodeAt(i); | |
| } | |
| ab = view.buffer; | |
| } | |
| if (isString) { // not true binary | |
| resultArray[bufferIndex++] = 0; | |
| } else { // true binary | |
| resultArray[bufferIndex++] = 1; | |
| } | |
| var lenStr = ab.byteLength.toString(); | |
| for (var i = 0; i < lenStr.length; i++) { | |
| resultArray[bufferIndex++] = parseInt(lenStr[i]); | |
| } | |
| resultArray[bufferIndex++] = 255; | |
| var view = new Uint8Array(ab); | |
| for (var i = 0; i < view.length; i++) { | |
| resultArray[bufferIndex++] = view[i]; | |
| } | |
| }); | |
| return callback(resultArray.buffer); | |
| }); | |
| }; | |
| /** | |
| * Encode as Blob | |
| */ | |
| exports.encodePayloadAsBlob = function(packets, callback) { | |
| function encodeOne(packet, doneCallback) { | |
| exports.encodePacket(packet, true, true, function(encoded) { | |
| var binaryIdentifier = new Uint8Array(1); | |
| binaryIdentifier[0] = 1; | |
| if (typeof encoded === 'string') { | |
| var view = new Uint8Array(encoded.length); | |
| for (var i = 0; i < encoded.length; i++) { | |
| view[i] = encoded.charCodeAt(i); | |
| } | |
| encoded = view.buffer; | |
| binaryIdentifier[0] = 0; | |
| } | |
| var len = (encoded instanceof ArrayBuffer) | |
| ? encoded.byteLength | |
| : encoded.size; | |
| var lenStr = len.toString(); | |
| var lengthAry = new Uint8Array(lenStr.length + 1); | |
| for (var i = 0; i < lenStr.length; i++) { | |
| lengthAry[i] = parseInt(lenStr[i]); | |
| } | |
| lengthAry[lenStr.length] = 255; | |
| if (Blob) { | |
| var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]); | |
| doneCallback(null, blob); | |
| } | |
| }); | |
| } | |
| map(packets, encodeOne, function(err, results) { | |
| return callback(new Blob(results)); | |
| }); | |
| }; | |
| /* | |
| * Decodes data when a payload is maybe expected. Strings are decoded by | |
| * interpreting each byte as a key code for entries marked to start with 0. See | |
| * description of encodePayloadAsBinary | |
| * | |
| * @param {ArrayBuffer} data, callback method | |
| * @api public | |
| */ | |
| exports.decodePayloadAsBinary = function (data, binaryType, callback) { | |
| if (typeof binaryType === 'function') { | |
| callback = binaryType; | |
| binaryType = null; | |
| } | |
| var bufferTail = data; | |
| var buffers = []; | |
| var numberTooLong = false; | |
| while (bufferTail.byteLength > 0) { | |
| var tailArray = new Uint8Array(bufferTail); | |
| var isString = tailArray[0] === 0; | |
| var msgLength = ''; | |
| for (var i = 1; ; i++) { | |
| if (tailArray[i] == 255) break; | |
| if (msgLength.length > 310) { | |
| numberTooLong = true; | |
| break; | |
| } | |
| msgLength += tailArray[i]; | |
| } | |
| if(numberTooLong) return callback(err, 0, 1); | |
| bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length); | |
| msgLength = parseInt(msgLength); | |
| var msg = sliceBuffer(bufferTail, 0, msgLength); | |
| if (isString) { | |
| try { | |
| msg = String.fromCharCode.apply(null, new Uint8Array(msg)); | |
| } catch (e) { | |
| // iPhone Safari doesn't let you apply to typed arrays | |
| var typed = new Uint8Array(msg); | |
| msg = ''; | |
| for (var i = 0; i < typed.length; i++) { | |
| msg += String.fromCharCode(typed[i]); | |
| } | |
| } | |
| } | |
| buffers.push(msg); | |
| bufferTail = sliceBuffer(bufferTail, msgLength); | |
| } | |
| var total = buffers.length; | |
| buffers.forEach(function(buffer, i) { | |
| callback(exports.decodePacket(buffer, binaryType, true), i, total); | |
| }); | |
| }; | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"./keys":22,"after":23,"arraybuffer.slice":24,"base64-arraybuffer":25,"blob":26,"utf8":27}],22:[function(_dereq_,module,exports){ | |
| /** | |
| * Gets the keys for an object. | |
| * | |
| * @return {Array} keys | |
| * @api private | |
| */ | |
| module.exports = Object.keys || function keys (obj){ | |
| var arr = []; | |
| var has = Object.prototype.hasOwnProperty; | |
| for (var i in obj) { | |
| if (has.call(obj, i)) { | |
| arr.push(i); | |
| } | |
| } | |
| return arr; | |
| }; | |
| },{}],23:[function(_dereq_,module,exports){ | |
| module.exports = after | |
| function after(count, callback, err_cb) { | |
| var bail = false | |
| err_cb = err_cb || noop | |
| proxy.count = count | |
| return (count === 0) ? callback() : proxy | |
| function proxy(err, result) { | |
| if (proxy.count <= 0) { | |
| throw new Error('after called too many times') | |
| } | |
| --proxy.count | |
| // after first error, rest are passed to err_cb | |
| if (err) { | |
| bail = true | |
| callback(err) | |
| // future error callbacks will go to error handler | |
| callback = err_cb | |
| } else if (proxy.count === 0 && !bail) { | |
| callback(null, result) | |
| } | |
| } | |
| } | |
| function noop() {} | |
| },{}],24:[function(_dereq_,module,exports){ | |
| /** | |
| * An abstraction for slicing an arraybuffer even when | |
| * ArrayBuffer.prototype.slice is not supported | |
| * | |
| * @api public | |
| */ | |
| module.exports = function(arraybuffer, start, end) { | |
| var bytes = arraybuffer.byteLength; | |
| start = start || 0; | |
| end = end || bytes; | |
| if (arraybuffer.slice) { return arraybuffer.slice(start, end); } | |
| if (start < 0) { start += bytes; } | |
| if (end < 0) { end += bytes; } | |
| if (end > bytes) { end = bytes; } | |
| if (start >= bytes || start >= end || bytes === 0) { | |
| return new ArrayBuffer(0); | |
| } | |
| var abv = new Uint8Array(arraybuffer); | |
| var result = new Uint8Array(end - start); | |
| for (var i = start, ii = 0; i < end; i++, ii++) { | |
| result[ii] = abv[i]; | |
| } | |
| return result.buffer; | |
| }; | |
| },{}],25:[function(_dereq_,module,exports){ | |
| /* | |
| * base64-arraybuffer | |
| * https://github.com/niklasvh/base64-arraybuffer | |
| * | |
| * Copyright (c) 2012 Niklas von Hertzen | |
| * Licensed under the MIT license. | |
| */ | |
| (function(chars){ | |
| "use strict"; | |
| exports.encode = function(arraybuffer) { | |
| var bytes = new Uint8Array(arraybuffer), | |
| i, len = bytes.length, base64 = ""; | |
| for (i = 0; i < len; i+=3) { | |
| base64 += chars[bytes[i] >> 2]; | |
| base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; | |
| base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; | |
| base64 += chars[bytes[i + 2] & 63]; | |
| } | |
| if ((len % 3) === 2) { | |
| base64 = base64.substring(0, base64.length - 1) + "="; | |
| } else if (len % 3 === 1) { | |
| base64 = base64.substring(0, base64.length - 2) + "=="; | |
| } | |
| return base64; | |
| }; | |
| exports.decode = function(base64) { | |
| var bufferLength = base64.length * 0.75, | |
| len = base64.length, i, p = 0, | |
| encoded1, encoded2, encoded3, encoded4; | |
| if (base64[base64.length - 1] === "=") { | |
| bufferLength--; | |
| if (base64[base64.length - 2] === "=") { | |
| bufferLength--; | |
| } | |
| } | |
| var arraybuffer = new ArrayBuffer(bufferLength), | |
| bytes = new Uint8Array(arraybuffer); | |
| for (i = 0; i < len; i+=4) { | |
| encoded1 = chars.indexOf(base64[i]); | |
| encoded2 = chars.indexOf(base64[i+1]); | |
| encoded3 = chars.indexOf(base64[i+2]); | |
| encoded4 = chars.indexOf(base64[i+3]); | |
| bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); | |
| bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); | |
| bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); | |
| } | |
| return arraybuffer; | |
| }; | |
| })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); | |
| },{}],26:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * Create a blob builder even when vendor prefixes exist | |
| */ | |
| var BlobBuilder = global.BlobBuilder | |
| || global.WebKitBlobBuilder | |
| || global.MSBlobBuilder | |
| || global.MozBlobBuilder; | |
| /** | |
| * Check if Blob constructor is supported | |
| */ | |
| var blobSupported = (function() { | |
| try { | |
| var b = new Blob(['hi']); | |
| return b.size == 2; | |
| } catch(e) { | |
| return false; | |
| } | |
| })(); | |
| /** | |
| * Check if BlobBuilder is supported | |
| */ | |
| var blobBuilderSupported = BlobBuilder | |
| && BlobBuilder.prototype.append | |
| && BlobBuilder.prototype.getBlob; | |
| function BlobBuilderConstructor(ary, options) { | |
| options = options || {}; | |
| var bb = new BlobBuilder(); | |
| for (var i = 0; i < ary.length; i++) { | |
| bb.append(ary[i]); | |
| } | |
| return (options.type) ? bb.getBlob(options.type) : bb.getBlob(); | |
| }; | |
| module.exports = (function() { | |
| if (blobSupported) { | |
| return global.Blob; | |
| } else if (blobBuilderSupported) { | |
| return BlobBuilderConstructor; | |
| } else { | |
| return undefined; | |
| } | |
| })(); | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{}],27:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /*! http://mths.be/utf8js v2.0.0 by @mathias */ | |
| ;(function(root) { | |
| // Detect free variables `exports` | |
| var freeExports = typeof exports == 'object' && exports; | |
| // Detect free variable `module` | |
| var freeModule = typeof module == 'object' && module && | |
| module.exports == freeExports && module; | |
| // Detect free variable `global`, from Node.js or Browserified code, | |
| // and use it as `root` | |
| var freeGlobal = typeof global == 'object' && global; | |
| if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { | |
| root = freeGlobal; | |
| } | |
| /*--------------------------------------------------------------------------*/ | |
| var stringFromCharCode = String.fromCharCode; | |
| // Taken from http://mths.be/punycode | |
| function ucs2decode(string) { | |
| var output = []; | |
| var counter = 0; | |
| var length = string.length; | |
| var value; | |
| var extra; | |
| while (counter < length) { | |
| value = string.charCodeAt(counter++); | |
| if (value >= 0xD800 && value <= 0xDBFF && counter < length) { | |
| // high surrogate, and there is a next character | |
| extra = string.charCodeAt(counter++); | |
| if ((extra & 0xFC00) == 0xDC00) { // low surrogate | |
| output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); | |
| } else { | |
| // unmatched surrogate; only append this code unit, in case the next | |
| // code unit is the high surrogate of a surrogate pair | |
| output.push(value); | |
| counter--; | |
| } | |
| } else { | |
| output.push(value); | |
| } | |
| } | |
| return output; | |
| } | |
| // Taken from http://mths.be/punycode | |
| function ucs2encode(array) { | |
| var length = array.length; | |
| var index = -1; | |
| var value; | |
| var output = ''; | |
| while (++index < length) { | |
| value = array[index]; | |
| if (value > 0xFFFF) { | |
| value -= 0x10000; | |
| output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); | |
| value = 0xDC00 | value & 0x3FF; | |
| } | |
| output += stringFromCharCode(value); | |
| } | |
| return output; | |
| } | |
| /*--------------------------------------------------------------------------*/ | |
| function createByte(codePoint, shift) { | |
| return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80); | |
| } | |
| function encodeCodePoint(codePoint) { | |
| if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence | |
| return stringFromCharCode(codePoint); | |
| } | |
| var symbol = ''; | |
| if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence | |
| symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0); | |
| } | |
| else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence | |
| symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0); | |
| symbol += createByte(codePoint, 6); | |
| } | |
| else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence | |
| symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0); | |
| symbol += createByte(codePoint, 12); | |
| symbol += createByte(codePoint, 6); | |
| } | |
| symbol += stringFromCharCode((codePoint & 0x3F) | 0x80); | |
| return symbol; | |
| } | |
| function utf8encode(string) { | |
| var codePoints = ucs2decode(string); | |
| // console.log(JSON.stringify(codePoints.map(function(x) { | |
| // return 'U+' + x.toString(16).toUpperCase(); | |
| // }))); | |
| var length = codePoints.length; | |
| var index = -1; | |
| var codePoint; | |
| var byteString = ''; | |
| while (++index < length) { | |
| codePoint = codePoints[index]; | |
| byteString += encodeCodePoint(codePoint); | |
| } | |
| return byteString; | |
| } | |
| /*--------------------------------------------------------------------------*/ | |
| function readContinuationByte() { | |
| if (byteIndex >= byteCount) { | |
| throw Error('Invalid byte index'); | |
| } | |
| var continuationByte = byteArray[byteIndex] & 0xFF; | |
| byteIndex++; | |
| if ((continuationByte & 0xC0) == 0x80) { | |
| return continuationByte & 0x3F; | |
| } | |
| // If we end up here, it’s not a continuation byte | |
| throw Error('Invalid continuation byte'); | |
| } | |
| function decodeSymbol() { | |
| var byte1; | |
| var byte2; | |
| var byte3; | |
| var byte4; | |
| var codePoint; | |
| if (byteIndex > byteCount) { | |
| throw Error('Invalid byte index'); | |
| } | |
| if (byteIndex == byteCount) { | |
| return false; | |
| } | |
| // Read first byte | |
| byte1 = byteArray[byteIndex] & 0xFF; | |
| byteIndex++; | |
| // 1-byte sequence (no continuation bytes) | |
| if ((byte1 & 0x80) == 0) { | |
| return byte1; | |
| } | |
| // 2-byte sequence | |
| if ((byte1 & 0xE0) == 0xC0) { | |
| var byte2 = readContinuationByte(); | |
| codePoint = ((byte1 & 0x1F) << 6) | byte2; | |
| if (codePoint >= 0x80) { | |
| return codePoint; | |
| } else { | |
| throw Error('Invalid continuation byte'); | |
| } | |
| } | |
| // 3-byte sequence (may include unpaired surrogates) | |
| if ((byte1 & 0xF0) == 0xE0) { | |
| byte2 = readContinuationByte(); | |
| byte3 = readContinuationByte(); | |
| codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3; | |
| if (codePoint >= 0x0800) { | |
| return codePoint; | |
| } else { | |
| throw Error('Invalid continuation byte'); | |
| } | |
| } | |
| // 4-byte sequence | |
| if ((byte1 & 0xF8) == 0xF0) { | |
| byte2 = readContinuationByte(); | |
| byte3 = readContinuationByte(); | |
| byte4 = readContinuationByte(); | |
| codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) | | |
| (byte3 << 0x06) | byte4; | |
| if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) { | |
| return codePoint; | |
| } | |
| } | |
| throw Error('Invalid UTF-8 detected'); | |
| } | |
| var byteArray; | |
| var byteCount; | |
| var byteIndex; | |
| function utf8decode(byteString) { | |
| byteArray = ucs2decode(byteString); | |
| byteCount = byteArray.length; | |
| byteIndex = 0; | |
| var codePoints = []; | |
| var tmp; | |
| while ((tmp = decodeSymbol()) !== false) { | |
| codePoints.push(tmp); | |
| } | |
| return ucs2encode(codePoints); | |
| } | |
| /*--------------------------------------------------------------------------*/ | |
| var utf8 = { | |
| 'version': '2.0.0', | |
| 'encode': utf8encode, | |
| 'decode': utf8decode | |
| }; | |
| // Some AMD build optimizers, like r.js, check for specific condition patterns | |
| // like the following: | |
| if ( | |
| typeof define == 'function' && | |
| typeof define.amd == 'object' && | |
| define.amd | |
| ) { | |
| define(function() { | |
| return utf8; | |
| }); | |
| } else if (freeExports && !freeExports.nodeType) { | |
| if (freeModule) { // in Node.js or RingoJS v0.8.0+ | |
| freeModule.exports = utf8; | |
| } else { // in Narwhal or RingoJS v0.7.0- | |
| var object = {}; | |
| var hasOwnProperty = object.hasOwnProperty; | |
| for (var key in utf8) { | |
| hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]); | |
| } | |
| } | |
| } else { // in Rhino or a web browser | |
| root.utf8 = utf8; | |
| } | |
| }(this)); | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{}],28:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /** | |
| * JSON parse. | |
| * | |
| * @see Based on jQuery#parseJSON (MIT) and JSON2 | |
| * @api private | |
| */ | |
| var rvalidchars = /^[\],:{}\s]*$/; | |
| var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; | |
| var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; | |
| var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g; | |
| var rtrimLeft = /^\s+/; | |
| var rtrimRight = /\s+$/; | |
| module.exports = function parsejson(data) { | |
| if ('string' != typeof data || !data) { | |
| return null; | |
| } | |
| data = data.replace(rtrimLeft, '').replace(rtrimRight, ''); | |
| // Attempt to parse using the native JSON parser first | |
| if (global.JSON && JSON.parse) { | |
| return JSON.parse(data); | |
| } | |
| if (rvalidchars.test(data.replace(rvalidescape, '@') | |
| .replace(rvalidtokens, ']') | |
| .replace(rvalidbraces, ''))) { | |
| return (new Function('return ' + data))(); | |
| } | |
| }; | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{}],29:[function(_dereq_,module,exports){ | |
| /** | |
| * Compiles a querystring | |
| * Returns string representation of the object | |
| * | |
| * @param {Object} | |
| * @api private | |
| */ | |
| exports.encode = function (obj) { | |
| var str = ''; | |
| for (var i in obj) { | |
| if (obj.hasOwnProperty(i)) { | |
| if (str.length) str += '&'; | |
| str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]); | |
| } | |
| } | |
| return str; | |
| }; | |
| /** | |
| * Parses a simple querystring into an object | |
| * | |
| * @param {String} qs | |
| * @api private | |
| */ | |
| exports.decode = function(qs){ | |
| var qry = {}; | |
| var pairs = qs.split('&'); | |
| for (var i = 0, l = pairs.length; i < l; i++) { | |
| var pair = pairs[i].split('='); | |
| qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); | |
| } | |
| return qry; | |
| }; | |
| },{}],30:[function(_dereq_,module,exports){ | |
| /** | |
| * Parses an URI | |
| * | |
| * @author Steven Levithan <stevenlevithan.com> (MIT license) | |
| * @api private | |
| */ | |
| var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; | |
| var parts = [ | |
| 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' | |
| ]; | |
| module.exports = function parseuri(str) { | |
| var src = str, | |
| b = str.indexOf('['), | |
| e = str.indexOf(']'); | |
| if (b != -1 && e != -1) { | |
| str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length); | |
| } | |
| var m = re.exec(str || ''), | |
| uri = {}, | |
| i = 14; | |
| while (i--) { | |
| uri[parts[i]] = m[i] || ''; | |
| } | |
| if (b != -1 && e != -1) { | |
| uri.source = src; | |
| uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':'); | |
| uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':'); | |
| uri.ipv6uri = true; | |
| } | |
| return uri; | |
| }; | |
| },{}],31:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var global = (function() { return this; })(); | |
| /** | |
| * WebSocket constructor. | |
| */ | |
| var WebSocket = global.WebSocket || global.MozWebSocket; | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = WebSocket ? ws : null; | |
| /** | |
| * WebSocket constructor. | |
| * | |
| * The third `opts` options object gets ignored in web browsers, since it's | |
| * non-standard, and throws a TypeError if passed to the constructor. | |
| * See: https://github.com/einaros/ws/issues/227 | |
| * | |
| * @param {String} uri | |
| * @param {Array} protocols (optional) | |
| * @param {Object) opts (optional) | |
| * @api public | |
| */ | |
| function ws(uri, protocols, opts) { | |
| var instance; | |
| if (protocols) { | |
| instance = new WebSocket(uri, protocols); | |
| } else { | |
| instance = new WebSocket(uri); | |
| } | |
| return instance; | |
| } | |
| if (WebSocket) ws.prototype = WebSocket.prototype; | |
| },{}],32:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /* | |
| * Module requirements. | |
| */ | |
| var isArray = _dereq_('isarray'); | |
| /** | |
| * Module exports. | |
| */ | |
| module.exports = hasBinary; | |
| /** | |
| * Checks for binary data. | |
| * | |
| * Right now only Buffer and ArrayBuffer are supported.. | |
| * | |
| * @param {Object} anything | |
| * @api public | |
| */ | |
| function hasBinary(data) { | |
| function _hasBinary(obj) { | |
| if (!obj) return false; | |
| if ( (global.Buffer && global.Buffer.isBuffer(obj)) || | |
| (global.ArrayBuffer && obj instanceof ArrayBuffer) || | |
| (global.Blob && obj instanceof Blob) || | |
| (global.File && obj instanceof File) | |
| ) { | |
| return true; | |
| } | |
| if (isArray(obj)) { | |
| for (var i = 0; i < obj.length; i++) { | |
| if (_hasBinary(obj[i])) { | |
| return true; | |
| } | |
| } | |
| } else if (obj && 'object' == typeof obj) { | |
| if (obj.toJSON) { | |
| obj = obj.toJSON(); | |
| } | |
| for (var key in obj) { | |
| if (obj.hasOwnProperty(key) && _hasBinary(obj[key])) { | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| return _hasBinary(data); | |
| } | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"isarray":33}],33:[function(_dereq_,module,exports){ | |
| module.exports = Array.isArray || function (arr) { | |
| return Object.prototype.toString.call(arr) == '[object Array]'; | |
| }; | |
| },{}],34:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var global = _dereq_('global'); | |
| /** | |
| * Module exports. | |
| * | |
| * Logic borrowed from Modernizr: | |
| * | |
| * - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js | |
| */ | |
| try { | |
| module.exports = 'XMLHttpRequest' in global && | |
| 'withCredentials' in new global.XMLHttpRequest(); | |
| } catch (err) { | |
| // if XMLHttp support is disabled in IE then it will throw | |
| // when trying to create | |
| module.exports = false; | |
| } | |
| },{"global":35}],35:[function(_dereq_,module,exports){ | |
| /** | |
| * Returns `this`. Execute this without a "context" (i.e. without it being | |
| * attached to an object of the left-hand side), and `this` points to the | |
| * "global" scope of the current JS execution. | |
| */ | |
| module.exports = (function () { return this; })(); | |
| },{}],36:[function(_dereq_,module,exports){ | |
| var indexOf = [].indexOf; | |
| module.exports = function(arr, obj){ | |
| if (indexOf) return arr.indexOf(obj); | |
| for (var i = 0; i < arr.length; ++i) { | |
| if (arr[i] === obj) return i; | |
| } | |
| return -1; | |
| }; | |
| },{}],37:[function(_dereq_,module,exports){ | |
| /** | |
| * HOP ref. | |
| */ | |
| var has = Object.prototype.hasOwnProperty; | |
| /** | |
| * Return own keys in `obj`. | |
| * | |
| * @param {Object} obj | |
| * @return {Array} | |
| * @api public | |
| */ | |
| exports.keys = Object.keys || function(obj){ | |
| var keys = []; | |
| for (var key in obj) { | |
| if (has.call(obj, key)) { | |
| keys.push(key); | |
| } | |
| } | |
| return keys; | |
| }; | |
| /** | |
| * Return own values in `obj`. | |
| * | |
| * @param {Object} obj | |
| * @return {Array} | |
| * @api public | |
| */ | |
| exports.values = function(obj){ | |
| var vals = []; | |
| for (var key in obj) { | |
| if (has.call(obj, key)) { | |
| vals.push(obj[key]); | |
| } | |
| } | |
| return vals; | |
| }; | |
| /** | |
| * Merge `b` into `a`. | |
| * | |
| * @param {Object} a | |
| * @param {Object} b | |
| * @return {Object} a | |
| * @api public | |
| */ | |
| exports.merge = function(a, b){ | |
| for (var key in b) { | |
| if (has.call(b, key)) { | |
| a[key] = b[key]; | |
| } | |
| } | |
| return a; | |
| }; | |
| /** | |
| * Return length of `obj`. | |
| * | |
| * @param {Object} obj | |
| * @return {Number} | |
| * @api public | |
| */ | |
| exports.length = function(obj){ | |
| return exports.keys(obj).length; | |
| }; | |
| /** | |
| * Check if `obj` is empty. | |
| * | |
| * @param {Object} obj | |
| * @return {Boolean} | |
| * @api public | |
| */ | |
| exports.isEmpty = function(obj){ | |
| return 0 == exports.length(obj); | |
| }; | |
| },{}],38:[function(_dereq_,module,exports){ | |
| /** | |
| * Parses an URI | |
| * | |
| * @author Steven Levithan <stevenlevithan.com> (MIT license) | |
| * @api private | |
| */ | |
| var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; | |
| var parts = [ | |
| 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host' | |
| , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' | |
| ]; | |
| module.exports = function parseuri(str) { | |
| var m = re.exec(str || '') | |
| , uri = {} | |
| , i = 14; | |
| while (i--) { | |
| uri[parts[i]] = m[i] || ''; | |
| } | |
| return uri; | |
| }; | |
| },{}],39:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| /*global Blob,File*/ | |
| /** | |
| * Module requirements | |
| */ | |
| var isArray = _dereq_('isarray'); | |
| var isBuf = _dereq_('./is-buffer'); | |
| /** | |
| * Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder. | |
| * Anything with blobs or files should be fed through removeBlobs before coming | |
| * here. | |
| * | |
| * @param {Object} packet - socket.io event packet | |
| * @return {Object} with deconstructed packet and list of buffers | |
| * @api public | |
| */ | |
| exports.deconstructPacket = function(packet){ | |
| var buffers = []; | |
| var packetData = packet.data; | |
| function _deconstructPacket(data) { | |
| if (!data) return data; | |
| if (isBuf(data)) { | |
| var placeholder = { _placeholder: true, num: buffers.length }; | |
| buffers.push(data); | |
| return placeholder; | |
| } else if (isArray(data)) { | |
| var newData = new Array(data.length); | |
| for (var i = 0; i < data.length; i++) { | |
| newData[i] = _deconstructPacket(data[i]); | |
| } | |
| return newData; | |
| } else if ('object' == typeof data && !(data instanceof Date)) { | |
| var newData = {}; | |
| for (var key in data) { | |
| newData[key] = _deconstructPacket(data[key]); | |
| } | |
| return newData; | |
| } | |
| return data; | |
| } | |
| var pack = packet; | |
| pack.data = _deconstructPacket(packetData); | |
| pack.attachments = buffers.length; // number of binary 'attachments' | |
| return {packet: pack, buffers: buffers}; | |
| }; | |
| /** | |
| * Reconstructs a binary packet from its placeholder packet and buffers | |
| * | |
| * @param {Object} packet - event packet with placeholders | |
| * @param {Array} buffers - binary buffers to put in placeholder positions | |
| * @return {Object} reconstructed packet | |
| * @api public | |
| */ | |
| exports.reconstructPacket = function(packet, buffers) { | |
| var curPlaceHolder = 0; | |
| function _reconstructPacket(data) { | |
| if (data && data._placeholder) { | |
| var buf = buffers[data.num]; // appropriate buffer (should be natural order anyway) | |
| return buf; | |
| } else if (isArray(data)) { | |
| for (var i = 0; i < data.length; i++) { | |
| data[i] = _reconstructPacket(data[i]); | |
| } | |
| return data; | |
| } else if (data && 'object' == typeof data) { | |
| for (var key in data) { | |
| data[key] = _reconstructPacket(data[key]); | |
| } | |
| return data; | |
| } | |
| return data; | |
| } | |
| packet.data = _reconstructPacket(packet.data); | |
| packet.attachments = undefined; // no longer useful | |
| return packet; | |
| }; | |
| /** | |
| * Asynchronously removes Blobs or Files from data via | |
| * FileReader's readAsArrayBuffer method. Used before encoding | |
| * data as msgpack. Calls callback with the blobless data. | |
| * | |
| * @param {Object} data | |
| * @param {Function} callback | |
| * @api private | |
| */ | |
| exports.removeBlobs = function(data, callback) { | |
| function _removeBlobs(obj, curKey, containingObject) { | |
| if (!obj) return obj; | |
| // convert any blob | |
| if ((global.Blob && obj instanceof Blob) || | |
| (global.File && obj instanceof File)) { | |
| pendingBlobs++; | |
| // async filereader | |
| var fileReader = new FileReader(); | |
| fileReader.onload = function() { // this.result == arraybuffer | |
| if (containingObject) { | |
| containingObject[curKey] = this.result; | |
| } | |
| else { | |
| bloblessData = this.result; | |
| } | |
| // if nothing pending its callback time | |
| if(! --pendingBlobs) { | |
| callback(bloblessData); | |
| } | |
| }; | |
| fileReader.readAsArrayBuffer(obj); // blob -> arraybuffer | |
| } else if (isArray(obj)) { // handle array | |
| for (var i = 0; i < obj.length; i++) { | |
| _removeBlobs(obj[i], i, obj); | |
| } | |
| } else if (obj && 'object' == typeof obj && !isBuf(obj)) { // and object | |
| for (var key in obj) { | |
| _removeBlobs(obj[key], key, obj); | |
| } | |
| } | |
| } | |
| var pendingBlobs = 0; | |
| var bloblessData = data; | |
| _removeBlobs(bloblessData); | |
| if (!pendingBlobs) { | |
| callback(bloblessData); | |
| } | |
| }; | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{"./is-buffer":41,"isarray":42}],40:[function(_dereq_,module,exports){ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var debug = _dereq_('debug')('socket.io-parser'); | |
| var json = _dereq_('json3'); | |
| var isArray = _dereq_('isarray'); | |
| var Emitter = _dereq_('component-emitter'); | |
| var binary = _dereq_('./binary'); | |
| var isBuf = _dereq_('./is-buffer'); | |
| /** | |
| * Protocol version. | |
| * | |
| * @api public | |
| */ | |
| exports.protocol = 4; | |
| /** | |
| * Packet types. | |
| * | |
| * @api public | |
| */ | |
| exports.types = [ | |
| 'CONNECT', | |
| 'DISCONNECT', | |
| 'EVENT', | |
| 'BINARY_EVENT', | |
| 'ACK', | |
| 'BINARY_ACK', | |
| 'ERROR' | |
| ]; | |
| /** | |
| * Packet type `connect`. | |
| * | |
| * @api public | |
| */ | |
| exports.CONNECT = 0; | |
| /** | |
| * Packet type `disconnect`. | |
| * | |
| * @api public | |
| */ | |
| exports.DISCONNECT = 1; | |
| /** | |
| * Packet type `event`. | |
| * | |
| * @api public | |
| */ | |
| exports.EVENT = 2; | |
| /** | |
| * Packet type `ack`. | |
| * | |
| * @api public | |
| */ | |
| exports.ACK = 3; | |
| /** | |
| * Packet type `error`. | |
| * | |
| * @api public | |
| */ | |
| exports.ERROR = 4; | |
| /** | |
| * Packet type 'binary event' | |
| * | |
| * @api public | |
| */ | |
| exports.BINARY_EVENT = 5; | |
| /** | |
| * Packet type `binary ack`. For acks with binary arguments. | |
| * | |
| * @api public | |
| */ | |
| exports.BINARY_ACK = 6; | |
| /** | |
| * Encoder constructor. | |
| * | |
| * @api public | |
| */ | |
| exports.Encoder = Encoder; | |
| /** | |
| * Decoder constructor. | |
| * | |
| * @api public | |
| */ | |
| exports.Decoder = Decoder; | |
| /** | |
| * A socket.io Encoder instance | |
| * | |
| * @api public | |
| */ | |
| function Encoder() {} | |
| /** | |
| * Encode a packet as a single string if non-binary, or as a | |
| * buffer sequence, depending on packet type. | |
| * | |
| * @param {Object} obj - packet object | |
| * @param {Function} callback - function to handle encodings (likely engine.write) | |
| * @return Calls callback with Array of encodings | |
| * @api public | |
| */ | |
| Encoder.prototype.encode = function(obj, callback){ | |
| debug('encoding packet %j', obj); | |
| if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) { | |
| encodeAsBinary(obj, callback); | |
| } | |
| else { | |
| var encoding = encodeAsString(obj); | |
| callback([encoding]); | |
| } | |
| }; | |
| /** | |
| * Encode packet as string. | |
| * | |
| * @param {Object} packet | |
| * @return {String} encoded | |
| * @api private | |
| */ | |
| function encodeAsString(obj) { | |
| var str = ''; | |
| var nsp = false; | |
| // first is type | |
| str += obj.type; | |
| // attachments if we have them | |
| if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) { | |
| str += obj.attachments; | |
| str += '-'; | |
| } | |
| // if we have a namespace other than `/` | |
| // we append it followed by a comma `,` | |
| if (obj.nsp && '/' != obj.nsp) { | |
| nsp = true; | |
| str += obj.nsp; | |
| } | |
| // immediately followed by the id | |
| if (null != obj.id) { | |
| if (nsp) { | |
| str += ','; | |
| nsp = false; | |
| } | |
| str += obj.id; | |
| } | |
| // json data | |
| if (null != obj.data) { | |
| if (nsp) str += ','; | |
| str += json.stringify(obj.data); | |
| } | |
| debug('encoded %j as %s', obj, str); | |
| return str; | |
| } | |
| /** | |
| * Encode packet as 'buffer sequence' by removing blobs, and | |
| * deconstructing packet into object with placeholders and | |
| * a list of buffers. | |
| * | |
| * @param {Object} packet | |
| * @return {Buffer} encoded | |
| * @api private | |
| */ | |
| function encodeAsBinary(obj, callback) { | |
| function writeEncoding(bloblessData) { | |
| var deconstruction = binary.deconstructPacket(bloblessData); | |
| var pack = encodeAsString(deconstruction.packet); | |
| var buffers = deconstruction.buffers; | |
| buffers.unshift(pack); // add packet info to beginning of data list | |
| callback(buffers); // write all the buffers | |
| } | |
| binary.removeBlobs(obj, writeEncoding); | |
| } | |
| /** | |
| * A socket.io Decoder instance | |
| * | |
| * @return {Object} decoder | |
| * @api public | |
| */ | |
| function Decoder() { | |
| this.reconstructor = null; | |
| } | |
| /** | |
| * Mix in `Emitter` with Decoder. | |
| */ | |
| Emitter(Decoder.prototype); | |
| /** | |
| * Decodes an ecoded packet string into packet JSON. | |
| * | |
| * @param {String} obj - encoded packet | |
| * @return {Object} packet | |
| * @api public | |
| */ | |
| Decoder.prototype.add = function(obj) { | |
| var packet; | |
| if ('string' == typeof obj) { | |
| packet = decodeString(obj); | |
| if (exports.BINARY_EVENT == packet.type || exports.BINARY_ACK == packet.type) { // binary packet's json | |
| this.reconstructor = new BinaryReconstructor(packet); | |
| // no attachments, labeled binary but no binary data to follow | |
| if (this.reconstructor.reconPack.attachments == 0) { | |
| this.emit('decoded', packet); | |
| } | |
| } else { // non-binary full packet | |
| this.emit('decoded', packet); | |
| } | |
| } | |
| else if (isBuf(obj) || obj.base64) { // raw binary data | |
| if (!this.reconstructor) { | |
| throw new Error('got binary data when not reconstructing a packet'); | |
| } else { | |
| packet = this.reconstructor.takeBinaryData(obj); | |
| if (packet) { // received final buffer | |
| this.reconstructor = null; | |
| this.emit('decoded', packet); | |
| } | |
| } | |
| } | |
| else { | |
| throw new Error('Unknown type: ' + obj); | |
| } | |
| }; | |
| /** | |
| * Decode a packet String (JSON data) | |
| * | |
| * @param {String} str | |
| * @return {Object} packet | |
| * @api private | |
| */ | |
| function decodeString(str) { | |
| var p = {}; | |
| var i = 0; | |
| // look up type | |
| p.type = Number(str.charAt(0)); | |
| if (null == exports.types[p.type]) return error(); | |
| // look up attachments if type binary | |
| if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) { | |
| p.attachments = ''; | |
| while (str.charAt(++i) != '-') { | |
| p.attachments += str.charAt(i); | |
| } | |
| p.attachments = Number(p.attachments); | |
| } | |
| // look up namespace (if any) | |
| if ('/' == str.charAt(i + 1)) { | |
| p.nsp = ''; | |
| while (++i) { | |
| var c = str.charAt(i); | |
| if (',' == c) break; | |
| p.nsp += c; | |
| if (i + 1 == str.length) break; | |
| } | |
| } else { | |
| p.nsp = '/'; | |
| } | |
| // look up id | |
| var next = str.charAt(i + 1); | |
| if ('' != next && Number(next) == next) { | |
| p.id = ''; | |
| while (++i) { | |
| var c = str.charAt(i); | |
| if (null == c || Number(c) != c) { | |
| --i; | |
| break; | |
| } | |
| p.id += str.charAt(i); | |
| if (i + 1 == str.length) break; | |
| } | |
| p.id = Number(p.id); | |
| } | |
| // look up json data | |
| if (str.charAt(++i)) { | |
| try { | |
| p.data = json.parse(str.substr(i)); | |
| } catch(e){ | |
| return error(); | |
| } | |
| } | |
| debug('decoded %s as %j', str, p); | |
| return p; | |
| } | |
| /** | |
| * Deallocates a parser's resources | |
| * | |
| * @api public | |
| */ | |
| Decoder.prototype.destroy = function() { | |
| if (this.reconstructor) { | |
| this.reconstructor.finishedReconstruction(); | |
| } | |
| }; | |
| /** | |
| * A manager of a binary event's 'buffer sequence'. Should | |
| * be constructed whenever a packet of type BINARY_EVENT is | |
| * decoded. | |
| * | |
| * @param {Object} packet | |
| * @return {BinaryReconstructor} initialized reconstructor | |
| * @api private | |
| */ | |
| function BinaryReconstructor(packet) { | |
| this.reconPack = packet; | |
| this.buffers = []; | |
| } | |
| /** | |
| * Method to be called when binary data received from connection | |
| * after a BINARY_EVENT packet. | |
| * | |
| * @param {Buffer | ArrayBuffer} binData - the raw binary data received | |
| * @return {null | Object} returns null if more binary data is expected or | |
| * a reconstructed packet object if all buffers have been received. | |
| * @api private | |
| */ | |
| BinaryReconstructor.prototype.takeBinaryData = function(binData) { | |
| this.buffers.push(binData); | |
| if (this.buffers.length == this.reconPack.attachments) { // done with buffer list | |
| var packet = binary.reconstructPacket(this.reconPack, this.buffers); | |
| this.finishedReconstruction(); | |
| return packet; | |
| } | |
| return null; | |
| }; | |
| /** | |
| * Cleans up binary packet reconstruction variables. | |
| * | |
| * @api private | |
| */ | |
| BinaryReconstructor.prototype.finishedReconstruction = function() { | |
| this.reconPack = null; | |
| this.buffers = []; | |
| }; | |
| function error(data){ | |
| return { | |
| type: exports.ERROR, | |
| data: 'parser error' | |
| }; | |
| } | |
| },{"./binary":39,"./is-buffer":41,"component-emitter":8,"debug":9,"isarray":42,"json3":43}],41:[function(_dereq_,module,exports){ | |
| (function (global){ | |
| module.exports = isBuf; | |
| /** | |
| * Returns true if obj is a buffer or an arraybuffer. | |
| * | |
| * @api private | |
| */ | |
| function isBuf(obj) { | |
| return (global.Buffer && global.Buffer.isBuffer(obj)) || | |
| (global.ArrayBuffer && obj instanceof ArrayBuffer); | |
| } | |
| }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| },{}],42:[function(_dereq_,module,exports){ | |
| module.exports=_dereq_(33) | |
| },{}],43:[function(_dereq_,module,exports){ | |
| /*! JSON v3.2.6 | http://bestiejs.github.io/json3 | Copyright 2012-2013, Kit Cambridge | http://kit.mit-license.org */ | |
| ;(function (window) { | |
| // Convenience aliases. | |
| var getClass = {}.toString, isProperty, forEach, undef; | |
| // Detect the `define` function exposed by asynchronous module loaders. The | |
| // strict `define` check is necessary for compatibility with `r.js`. | |
| var isLoader = typeof define === "function" && define.amd; | |
| // Detect native implementations. | |
| var nativeJSON = typeof JSON == "object" && JSON; | |
| // Set up the JSON 3 namespace, preferring the CommonJS `exports` object if | |
| // available. | |
| var JSON3 = typeof exports == "object" && exports && !exports.nodeType && exports; | |
| if (JSON3 && nativeJSON) { | |
| // Explicitly delegate to the native `stringify` and `parse` | |
| // implementations in CommonJS environments. | |
| JSON3.stringify = nativeJSON.stringify; | |
| JSON3.parse = nativeJSON.parse; | |
| } else { | |
| // Export for web browsers, JavaScript engines, and asynchronous module | |
| // loaders, using the global `JSON` object if available. | |
| JSON3 = window.JSON = nativeJSON || {}; | |
| } | |
| // Test the `Date#getUTC*` methods. Based on work by @Yaffle. | |
| var isExtended = new Date(-3509827334573292); | |
| try { | |
| // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical | |
| // results for certain dates in Opera >= 10.53. | |
| isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 && | |
| // Safari < 2.0.2 stores the internal millisecond time value correctly, | |
| // but clips the values returned by the date methods to the range of | |
| // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]). | |
| isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708; | |
| } catch (exception) {} | |
| // Internal: Determines whether the native `JSON.stringify` and `parse` | |
| // implementations are spec-compliant. Based on work by Ken Snyder. | |
| function has(name) { | |
| if (has[name] !== undef) { | |
| // Return cached feature test result. | |
| return has[name]; | |
| } | |
| var isSupported; | |
| if (name == "bug-string-char-index") { | |
| // IE <= 7 doesn't support accessing string characters using square | |
| // bracket notation. IE 8 only supports this for primitives. | |
| isSupported = "a"[0] != "a"; | |
| } else if (name == "json") { | |
| // Indicates whether both `JSON.stringify` and `JSON.parse` are | |
| // supported. | |
| isSupported = has("json-stringify") && has("json-parse"); | |
| } else { | |
| var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'; | |
| // Test `JSON.stringify`. | |
| if (name == "json-stringify") { | |
| var stringify = JSON3.stringify, stringifySupported = typeof stringify == "function" && isExtended; | |
| if (stringifySupported) { | |
| // A test function object with a custom `toJSON` method. | |
| (value = function () { | |
| return 1; | |
| }).toJSON = value; | |
| try { | |
| stringifySupported = | |
| // Firefox 3.1b1 and b2 serialize string, number, and boolean | |
| // primitives as object literals. | |
| stringify(0) === "0" && | |
| // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object | |
| // literals. | |
| stringify(new Number()) === "0" && | |
| stringify(new String()) == '""' && | |
| // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or | |
| // does not define a canonical JSON representation (this applies to | |
| // objects with `toJSON` properties as well, *unless* they are nested | |
| // within an object or array). | |
| stringify(getClass) === undef && | |
| // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and | |
| // FF 3.1b3 pass this test. | |
| stringify(undef) === undef && | |
| // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s, | |
| // respectively, if the value is omitted entirely. | |
| stringify() === undef && | |
| // FF 3.1b1, 2 throw an error if the given value is not a number, | |
| // string, array, object, Boolean, or `null` literal. This applies to | |
| // objects with custom `toJSON` methods as well, unless they are nested | |
| // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON` | |
| // methods entirely. | |
| stringify(value) === "1" && | |
| stringify([value]) == "[1]" && | |
| // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of | |
| // `"[null]"`. | |
| stringify([undef]) == "[null]" && | |
| // YUI 3.0.0b1 fails to serialize `null` literals. | |
| stringify(null) == "null" && | |
| // FF 3.1b1, 2 halts serialization if an array contains a function: | |
| // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3 | |
| // elides non-JSON values from objects and arrays, unless they | |
| // define custom `toJSON` methods. | |
| stringify([undef, getClass, null]) == "[null,null,null]" && | |
| // Simple serialization test. FF 3.1b1 uses Unicode escape sequences | |
| // where character escape codes are expected (e.g., `\b` => `\u0008`). | |
| stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized && | |
| // FF 3.1b1 and b2 ignore the `filter` and `width` arguments. | |
| stringify(null, value) === "1" && | |
| stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" && | |
| // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly | |
| // serialize extended years. | |
| stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' && | |
| // The milliseconds are optional in ES 5, but required in 5.1. | |
| stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' && | |
| // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative | |
| // four-digit years instead of six-digit years. Credits: @Yaffle. | |
| stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' && | |
| // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond | |
| // values less than 1000. Credits: @Yaffle. | |
| stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; | |
| } catch (exception) { | |
| stringifySupported = false; | |
| } | |
| } | |
| isSupported = stringifySupported; | |
| } | |
| // Test `JSON.parse`. | |
| if (name == "json-parse") { | |
| var parse = JSON3.parse; | |
| if (typeof parse == "function") { | |
| try { | |
| // FF 3.1b1, b2 will throw an exception if a bare literal is provided. | |
| // Conforming implementations should also coerce the initial argument to | |
| // a string prior to parsing. | |
| if (parse("0") === 0 && !parse(false)) { | |
| // Simple parsing test. | |
| value = parse(serialized); | |
| var parseSupported = value["a"].length == 5 && value["a"][0] === 1; | |
| if (parseSupported) { | |
| try { | |
| // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings. | |
| parseSupported = !parse('"\t"'); | |
| } catch (exception) {} | |
| if (parseSupported) { | |
| try { | |
| // FF 4.0 and 4.0.1 allow leading `+` signs and leading | |
| // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow | |
| // certain octal literals. | |
| parseSupported = parse("01") !== 1; | |
| } catch (exception) {} | |
| } | |
| if (parseSupported) { | |
| try { | |
| // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal | |
| // points. These environments, along with FF 3.1b1 and 2, | |
| // also allow trailing commas in JSON objects and arrays. | |
| parseSupported = parse("1.") !== 1; | |
| } catch (exception) {} | |
| } | |
| } | |
| } | |
| } catch (exception) { | |
| parseSupported = false; | |
| } | |
| } | |
| isSupported = parseSupported; | |
| } | |
| } | |
| return has[name] = !!isSupported; | |
| } | |
| if (!has("json")) { | |
| // Common `[[Class]]` name aliases. | |
| var functionClass = "[object Function]"; | |
| var dateClass = "[object Date]"; | |
| var numberClass = "[object Number]"; | |
| var stringClass = "[object String]"; | |
| var arrayClass = "[object Array]"; | |
| var booleanClass = "[object Boolean]"; | |
| // Detect incomplete support for accessing string characters by index. | |
| var charIndexBuggy = has("bug-string-char-index"); | |
| // Define additional utility methods if the `Date` methods are buggy. | |
| if (!isExtended) { | |
| var floor = Math.floor; | |
| // A mapping between the months of the year and the number of days between | |
| // January 1st and the first of the respective month. | |
| var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; | |
| // Internal: Calculates the number of days between the Unix epoch and the | |
| // first day of the given month. | |
| var getDay = function (year, month) { | |
| return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400); | |
| }; | |
| } | |
| // Internal: Determines if a property is a direct property of the given | |
| // object. Delegates to the native `Object#hasOwnProperty` method. | |
| if (!(isProperty = {}.hasOwnProperty)) { | |
| isProperty = function (property) { | |
| var members = {}, constructor; | |
| if ((members.__proto__ = null, members.__proto__ = { | |
| // The *proto* property cannot be set multiple times in recent | |
| // versions of Firefox and SeaMonkey. | |
| "toString": 1 | |
| }, members).toString != getClass) { | |
| // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but | |
| // supports the mutable *proto* property. | |
| isProperty = function (property) { | |
| // Capture and break the object's prototype chain (see section 8.6.2 | |
| // of the ES 5.1 spec). The parenthesized expression prevents an | |
| // unsafe transformation by the Closure Compiler. | |
| var original = this.__proto__, result = property in (this.__proto__ = null, this); | |
| // Restore the original prototype chain. | |
| this.__proto__ = original; | |
| return result; | |
| }; | |
| } else { | |
| // Capture a reference to the top-level `Object` constructor. | |
| constructor = members.constructor; | |
| // Use the `constructor` property to simulate `Object#hasOwnProperty` in | |
| // other environments. | |
| isProperty = function (property) { | |
| var parent = (this.constructor || constructor).prototype; | |
| return property in this && !(property in parent && this[property] === parent[property]); | |
| }; | |
| } | |
| members = null; | |
| return isProperty.call(this, property); | |
| }; | |
| } | |
| // Internal: A set of primitive types used by `isHostType`. | |
| var PrimitiveTypes = { | |
| 'boolean': 1, | |
| 'number': 1, | |
| 'string': 1, | |
| 'undefined': 1 | |
| }; | |
| // Internal: Determines if the given object `property` value is a | |
| // non-primitive. | |
| var isHostType = function (object, property) { | |
| var type = typeof object[property]; | |
| return type == 'object' ? !!object[property] : !PrimitiveTypes[type]; | |
| }; | |
| // Internal: Normalizes the `for...in` iteration algorithm across | |
| // environments. Each enumerated key is yielded to a `callback` function. | |
| forEach = function (object, callback) { | |
| var size = 0, Properties, members, property; | |
| // Tests for bugs in the current environment's `for...in` algorithm. The | |
| // `valueOf` property inherits the non-enumerable flag from | |
| // `Object.prototype` in older versions of IE, Netscape, and Mozilla. | |
| (Properties = function () { | |
| this.valueOf = 0; | |
| }).prototype.valueOf = 0; | |
| // Iterate over a new instance of the `Properties` class. | |
| members = new Properties(); | |
| for (property in members) { | |
| // Ignore all properties inherited from `Object.prototype`. | |
| if (isProperty.call(members, property)) { | |
| size++; | |
| } | |
| } | |
| Properties = members = null; | |
| // Normalize the iteration algorithm. | |
| if (!size) { | |
| // A list of non-enumerable properties inherited from `Object.prototype`. | |
| members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"]; | |
| // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable | |
| // properties. | |
| forEach = function (object, callback) { | |
| var isFunction = getClass.call(object) == functionClass, property, length; | |
| var hasProperty = !isFunction && typeof object.constructor != 'function' && isHostType(object, 'hasOwnProperty') ? object.hasOwnProperty : isProperty; | |
| for (property in object) { | |
| // Gecko <= 1.0 enumerates the `prototype` property of functions under | |
| // certain conditions; IE does not. | |
| if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) { | |
| callback(property); | |
| } | |
| } | |
| // Manually invoke the callback for each non-enumerable property. | |
| for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property)); | |
| }; | |
| } else if (size == 2) { | |
| // Safari <= 2.0.4 enumerates shadowed properties twice. | |
| forEach = function (object, callback) { | |
| // Create a set of iterated properties. | |
| var members = {}, isFunction = getClass.call(object) == functionClass, property; | |
| for (property in object) { | |
| // Store each property name to prevent double enumeration. The | |
| // `prototype` property of functions is not enumerated due to cross- | |
| // environment inconsistencies. | |
| if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) { | |
| callback(property); | |
| } | |
| } | |
| }; | |
| } else { | |
| // No bugs detected; use the standard `for...in` algorithm. | |
| forEach = function (object, callback) { | |
| var isFunction = getClass.call(object) == functionClass, property, isConstructor; | |
| for (property in object) { | |
| if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) { | |
| callback(property); | |
| } | |
| } | |
| // Manually invoke the callback for the `constructor` property due to | |
| // cross-environment inconsistencies. | |
| if (isConstructor || isProperty.call(object, (property = "constructor"))) { | |
| callback(property); | |
| } | |
| }; | |
| } | |
| return forEach(object, callback); | |
| }; | |
| // Public: Serializes a JavaScript `value` as a JSON string. The optional | |
| // `filter` argument may specify either a function that alters how object and | |
| // array members are serialized, or an array of strings and numbers that | |
| // indicates which properties should be serialized. The optional `width` | |
| // argument may be either a string or number that specifies the indentation | |
| // level of the output. | |
| if (!has("json-stringify")) { | |
| // Internal: A map of control characters and their escaped equivalents. | |
| var Escapes = { | |
| 92: "\\\\", | |
| 34: '\\"', | |
| 8: "\\b", | |
| 12: "\\f", | |
| 10: "\\n", | |
| 13: "\\r", | |
| 9: "\\t" | |
| }; | |
| // Internal: Converts `value` into a zero-padded string such that its | |
| // length is at least equal to `width`. The `width` must be <= 6. | |
| var leadingZeroes = "000000"; | |
| var toPaddedString = function (width, value) { | |
| // The `|| 0` expression is necessary to work around a bug in | |
| // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`. | |
| return (leadingZeroes + (value || 0)).slice(-width); | |
| }; | |
| // Internal: Double-quotes a string `value`, replacing all ASCII control | |
| // characters (characters with code unit values between 0 and 31) with | |
| // their escaped equivalents. This is an implementation of the | |
| // `Quote(value)` operation defined in ES 5.1 section 15.12.3. | |
| var unicodePrefix = "\\u00"; | |
| var quote = function (value) { | |
| var result = '"', index = 0, length = value.length, isLarge = length > 10 && charIndexBuggy, symbols; | |
| if (isLarge) { | |
| symbols = value.split(""); | |
| } | |
| for (; index < length; index++) { | |
| var charCode = value.charCodeAt(index); | |
| // If the character is a control character, append its Unicode or | |
| // shorthand escape sequence; otherwise, append the character as-is. | |
| switch (charCode) { | |
| case 8: case 9: case 10: case 12: case 13: case 34: case 92: | |
| result += Escapes[charCode]; | |
| break; | |
| default: | |
| if (charCode < 32) { | |
| result += unicodePrefix + toPaddedString(2, charCode.toString(16)); | |
| break; | |
| } | |
| result += isLarge ? symbols[index] : charIndexBuggy ? value.charAt(index) : value[index]; | |
| } | |
| } | |
| return result + '"'; | |
| }; | |
| // Internal: Recursively serializes an object. Implements the | |
| // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations. | |
| var serialize = function (property, object, callback, properties, whitespace, indentation, stack) { | |
| var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result; | |
| try { | |
| // Necessary for host object support. | |
| value = object[property]; | |
| } catch (exception) {} | |
| if (typeof value == "object" && value) { | |
| className = getClass.call(value); | |
| if (className == dateClass && !isProperty.call(value, "toJSON")) { | |
| if (value > -1 / 0 && value < 1 / 0) { | |
| // Dates are serialized according to the `Date#toJSON` method | |
| // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15 | |
| // for the ISO 8601 date time string format. | |
| if (getDay) { | |
| // Manually compute the year, month, date, hours, minutes, | |
| // seconds, and milliseconds if the `getUTC*` methods are | |
| // buggy. Adapted from @Yaffle's `date-shim` project. | |
| date = floor(value / 864e5); | |
| for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++); | |
| for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++); | |
| date = 1 + date - getDay(year, month); | |
| // The `time` value specifies the time within the day (see ES | |
| // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used | |
| // to compute `A modulo B`, as the `%` operator does not | |
| // correspond to the `modulo` operation for negative numbers. | |
| time = (value % 864e5 + 864e5) % 864e5; | |
| // The hours, minutes, seconds, and milliseconds are obtained by | |
| // decomposing the time within the day. See section 15.9.1.10. | |
| hours = floor(time / 36e5) % 24; | |
| minutes = floor(time / 6e4) % 60; | |
| seconds = floor(time / 1e3) % 60; | |
| milliseconds = time % 1e3; | |
| } else { | |
| year = value.getUTCFullYear(); | |
| month = value.getUTCMonth(); | |
| date = value.getUTCDate(); | |
| hours = value.getUTCHours(); | |
| minutes = value.getUTCMinutes(); | |
| seconds = value.getUTCSeconds(); | |
| milliseconds = value.getUTCMilliseconds(); | |
| } | |
| // Serialize extended years correctly. | |
| value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) + | |
| "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) + | |
| // Months, dates, hours, minutes, and seconds should have two | |
| // digits; milliseconds should have three. | |
| "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) + | |
| // Milliseconds are optional in ES 5.0, but required in 5.1. | |
| "." + toPaddedString(3, milliseconds) + "Z"; | |
| } else { | |
| value = null; | |
| } | |
| } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) { | |
| // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the | |
| // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3 | |
| // ignores all `toJSON` methods on these objects unless they are | |
| // defined directly on an instance. | |
| value = value.toJSON(property); | |
| } | |
| } | |
| if (callback) { | |
| // If a replacement function was provided, call it to obtain the value | |
| // for serialization. | |
| value = callback.call(object, property, value); | |
| } | |
| if (value === null) { | |
| return "null"; | |
| } | |
| className = getClass.call(value); | |
| if (className == booleanClass) { | |
| // Booleans are represented literally. | |
| return "" + value; | |
| } else if (className == numberClass) { | |
| // JSON numbers must be finite. `Infinity` and `NaN` are serialized as | |
| // `"null"`. | |
| return value > -1 / 0 && value < 1 / 0 ? "" + value : "null"; | |
| } else if (className == stringClass) { | |
| // Strings are double-quoted and escaped. | |
| return quote("" + value); | |
| } | |
| // Recursively serialize objects and arrays. | |
| if (typeof value == "object") { | |
| // Check for cyclic structures. This is a linear search; performance | |
| // is inversely proportional to the number of unique nested objects. | |
| for (length = stack.length; length--;) { | |
| if (stack[length] === value) { | |
| // Cyclic structures cannot be serialized by `JSON.stringify`. | |
| throw TypeError(); | |
| } | |
| } | |
| // Add the object to the stack of traversed objects. | |
| stack.push(value); | |
| results = []; | |
| // Save the current indentation level and indent one additional level. | |
| prefix = indentation; | |
| indentation += whitespace; | |
| if (className == arrayClass) { | |
| // Recursively serialize array elements. | |
| for (index = 0, length = value.length; index < length; index++) { | |
| element = serialize(index, value, callback, properties, whitespace, indentation, stack); | |
| results.push(element === undef ? "null" : element); | |
| } | |
| result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]"; | |
| } else { | |
| // Recursively serialize object members. Members are selected from | |
| // either a user-specified list of property names, or the object | |
| // itself. | |
| forEach(properties || value, function (property) { | |
| var element = serialize(property, value, callback, properties, whitespace, indentation, stack); | |
| if (element !== undef) { | |
| // According to ES 5.1 section 15.12.3: "If `gap` {whitespace} | |
| // is not the empty string, let `member` {quote(property) + ":"} | |
| // be the concatenation of `member` and the `space` character." | |
| // The "`space` character" refers to the literal space | |
| // character, not the `space` {width} argument provided to | |
| // `JSON.stringify`. | |
| results.push(quote(property) + ":" + (whitespace ? " " : "") + element); | |
| } | |
| }); | |
| result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}"; | |
| } | |
| // Remove the object from the traversed object stack. | |
| stack.pop(); | |
| return result; | |
| } | |
| }; | |
| // Public: `JSON.stringify`. See ES 5.1 section 15.12.3. | |
| JSON3.stringify = function (source, filter, width) { | |
| var whitespace, callback, properties, className; | |
| if (typeof filter == "function" || typeof filter == "object" && filter) { | |
| if ((className = getClass.call(filter)) == functionClass) { | |
| callback = filter; | |
| } else if (className == arrayClass) { | |
| // Convert the property names array into a makeshift set. | |
| properties = {}; | |
| for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1)); | |
| } | |
| } | |
| if (width) { | |
| if ((className = getClass.call(width)) == numberClass) { | |
| // Convert the `width` to an integer and create a string containing | |
| // `width` number of space characters. | |
| if ((width -= width % 1) > 0) { | |
| for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " "); | |
| } | |
| } else if (className == stringClass) { | |
| whitespace = width.length <= 10 ? width : width.slice(0, 10); | |
| } | |
| } | |
| // Opera <= 7.54u2 discards the values associated with empty string keys | |
| // (`""`) only if they are used directly within an object member list | |
| // (e.g., `!("" in { "": 1})`). | |
| return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []); | |
| }; | |
| } | |
| // Public: Parses a JSON source string. | |
| if (!has("json-parse")) { | |
| var fromCharCode = String.fromCharCode; | |
| // Internal: A map of escaped control characters and their unescaped | |
| // equivalents. | |
| var Unescapes = { | |
| 92: "\\", | |
| 34: '"', | |
| 47: "/", | |
| 98: "\b", | |
| 116: "\t", | |
| 110: "\n", | |
| 102: "\f", | |
| 114: "\r" | |
| }; | |
| // Internal: Stores the parser state. | |
| var Index, Source; | |
| // Internal: Resets the parser state and throws a `SyntaxError`. | |
| var abort = function() { | |
| Index = Source = null; | |
| throw SyntaxError(); | |
| }; | |
| // Internal: Returns the next token, or `"$"` if the parser has reached | |
| // the end of the source string. A token may be a string, number, `null` | |
| // literal, or Boolean literal. | |
| var lex = function () { | |
| var source = Source, length = source.length, value, begin, position, isSigned, charCode; | |
| while (Index < length) { | |
| charCode = source.charCodeAt(Index); | |
| switch (charCode) { | |
| case 9: case 10: case 13: case 32: | |
| // Skip whitespace tokens, including tabs, carriage returns, line | |
| // feeds, and space characters. | |
| Index++; | |
| break; | |
| case 123: case 125: case 91: case 93: case 58: case 44: | |
| // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at | |
| // the current position. | |
| value = charIndexBuggy ? source.charAt(Index) : source[Index]; | |
| Index++; | |
| return value; | |
| case 34: | |
| // `"` delimits a JSON string; advance to the next character and | |
| // begin parsing the string. String tokens are prefixed with the | |
| // sentinel `@` character to distinguish them from punctuators and | |
| // end-of-string tokens. | |
| for (value = "@", Index++; Index < length;) { | |
| charCode = source.charCodeAt(Index); | |
| if (charCode < 32) { | |
| // Unescaped ASCII control characters (those with a code unit | |
| // less than the space character) are not permitted. | |
| abort(); | |
| } else if (charCode == 92) { | |
| // A reverse solidus (`\`) marks the beginning of an escaped | |
| // control character (including `"`, `\`, and `/`) or Unicode | |
| // escape sequence. | |
| charCode = source.charCodeAt(++Index); | |
| switch (charCode) { | |
| case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114: | |
| // Revive escaped control characters. | |
| value += Unescapes[charCode]; | |
| Index++; | |
| break; | |
| case 117: | |
| // `\u` marks the beginning of a Unicode escape sequence. | |
| // Advance to the first character and validate the | |
| // four-digit code point. | |
| begin = ++Index; | |
| for (position = Index + 4; Index < position; Index++) { | |
| charCode = source.charCodeAt(Index); | |
| // A valid sequence comprises four hexdigits (case- | |
| // insensitive) that form a single hexadecimal value. | |
| if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) { | |
| // Invalid Unicode escape sequence. | |
| abort(); | |
| } | |
| } | |
| // Revive the escaped character. | |
| value += fromCharCode("0x" + source.slice(begin, Index)); | |
| break; | |
| default: | |
| // Invalid escape sequence. | |
| abort(); | |
| } | |
| } else { | |
| if (charCode == 34) { | |
| // An unescaped double-quote character marks the end of the | |
| // string. | |
| break; | |
| } | |
| charCode = source.charCodeAt(Index); | |
| begin = Index; | |
| // Optimize for the common case where a string is valid. | |
| while (charCode >= 32 && charCode != 92 && charCode != 34) { | |
| charCode = source.charCodeAt(++Index); | |
| } | |
| // Append the string as-is. | |
| value += source.slice(begin, Index); | |
| } | |
| } | |
| if (source.charCodeAt(Index) == 34) { | |
| // Advance to the next character and return the revived string. | |
| Index++; | |
| return value; | |
| } | |
| // Unterminated string. | |
| abort(); | |
| default: | |
| // Parse numbers and literals. | |
| begin = Index; | |
| // Advance past the negative sign, if one is specified. | |
| if (charCode == 45) { | |
| isSigned = true; | |
| charCode = source.charCodeAt(++Index); | |
| } | |
| // Parse an integer or floating-point value. | |
| if (charCode >= 48 && charCode <= 57) { | |
| // Leading zeroes are interpreted as octal literals. | |
| if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) { | |
| // Illegal octal literal. | |
| abort(); | |
| } | |
| isSigned = false; | |
| // Parse the integer component. | |
| for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++); | |
| // Floats cannot contain a leading decimal point; however, this | |
| // case is already accounted for by the parser. | |
| if (source.charCodeAt(Index) == 46) { | |
| position = ++Index; | |
| // Parse the decimal component. | |
| for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); | |
| if (position == Index) { | |
| // Illegal trailing decimal. | |
| abort(); | |
| } | |
| Index = position; | |
| } | |
| // Parse exponents. The `e` denoting the exponent is | |
| // case-insensitive. | |
| charCode = source.charCodeAt(Index); | |
| if (charCode == 101 || charCode == 69) { | |
| charCode = source.charCodeAt(++Index); | |
| // Skip past the sign following the exponent, if one is | |
| // specified. | |
| if (charCode == 43 || charCode == 45) { | |
| Index++; | |
| } | |
| // Parse the exponential component. | |
| for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); | |
| if (position == Index) { | |
| // Illegal empty exponent. | |
| abort(); | |
| } | |
| Index = position; | |
| } | |
| // Coerce the parsed value to a JavaScript number. | |
| return +source.slice(begin, Index); | |
| } | |
| // A negative sign may only precede numbers. | |
| if (isSigned) { | |
| abort(); | |
| } | |
| // `true`, `false`, and `null` literals. | |
| if (source.slice(Index, Index + 4) == "true") { | |
| Index += 4; | |
| return true; | |
| } else if (source.slice(Index, Index + 5) == "false") { | |
| Index += 5; | |
| return false; | |
| } else if (source.slice(Index, Index + 4) == "null") { | |
| Index += 4; | |
| return null; | |
| } | |
| // Unrecognized token. | |
| abort(); | |
| } | |
| } | |
| // Return the sentinel `$` character if the parser has reached the end | |
| // of the source string. | |
| return "$"; | |
| }; | |
| // Internal: Parses a JSON `value` token. | |
| var get = function (value) { | |
| var results, hasMembers; | |
| if (value == "$") { | |
| // Unexpected end of input. | |
| abort(); | |
| } | |
| if (typeof value == "string") { | |
| if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") { | |
| // Remove the sentinel `@` character. | |
| return value.slice(1); | |
| } | |
| // Parse object and array literals. | |
| if (value == "[") { | |
| // Parses a JSON array, returning a new JavaScript array. | |
| results = []; | |
| for (;; hasMembers || (hasMembers = true)) { | |
| value = lex(); | |
| // A closing square bracket marks the end of the array literal. | |
| if (value == "]") { | |
| break; | |
| } | |
| // If the array literal contains elements, the current token | |
| // should be a comma separating the previous element from the | |
| // next. | |
| if (hasMembers) { | |
| if (value == ",") { | |
| value = lex(); | |
| if (value == "]") { | |
| // Unexpected trailing `,` in array literal. | |
| abort(); | |
| } | |
| } else { | |
| // A `,` must separate each array element. | |
| abort(); | |
| } | |
| } | |
| // Elisions and leading commas are not permitted. | |
| if (value == ",") { | |
| abort(); | |
| } | |
| results.push(get(value)); | |
| } | |
| return results; | |
| } else if (value == "{") { | |
| // Parses a JSON object, returning a new JavaScript object. | |
| results = {}; | |
| for (;; hasMembers || (hasMembers = true)) { | |
| value = lex(); | |
| // A closing curly brace marks the end of the object literal. | |
| if (value == "}") { | |
| break; | |
| } | |
| // If the object literal contains members, the current token | |
| // should be a comma separator. | |
| if (hasMembers) { | |
| if (value == ",") { | |
| value = lex(); | |
| if (value == "}") { | |
| // Unexpected trailing `,` in object literal. | |
| abort(); | |
| } | |
| } else { | |
| // A `,` must separate each object member. | |
| abort(); | |
| } | |
| } | |
| // Leading commas are not permitted, object property names must be | |
| // double-quoted strings, and a `:` must separate each property | |
| // name and value. | |
| if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") { | |
| abort(); | |
| } | |
| results[value.slice(1)] = get(lex()); | |
| } | |
| return results; | |
| } | |
| // Unexpected token encountered. | |
| abort(); | |
| } | |
| return value; | |
| }; | |
| // Internal: Updates a traversed object member. | |
| var update = function(source, property, callback) { | |
| var element = walk(source, property, callback); | |
| if (element === undef) { | |
| delete source[property]; | |
| } else { | |
| source[property] = element; | |
| } | |
| }; | |
| // Internal: Recursively traverses a parsed JSON object, invoking the | |
| // `callback` function for each value. This is an implementation of the | |
| // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2. | |
| var walk = function (source, property, callback) { | |
| var value = source[property], length; | |
| if (typeof value == "object" && value) { | |
| // `forEach` can't be used to traverse an array in Opera <= 8.54 | |
| // because its `Object#hasOwnProperty` implementation returns `false` | |
| // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`). | |
| if (getClass.call(value) == arrayClass) { | |
| for (length = value.length; length--;) { | |
| update(value, length, callback); | |
| } | |
| } else { | |
| forEach(value, function (property) { | |
| update(value, property, callback); | |
| }); | |
| } | |
| } | |
| return callback.call(source, property, value); | |
| }; | |
| // Public: `JSON.parse`. See ES 5.1 section 15.12.2. | |
| JSON3.parse = function (source, callback) { | |
| var result, value; | |
| Index = 0; | |
| Source = "" + source; | |
| result = get(lex()); | |
| // If a JSON string contains multiple tokens, it is invalid. | |
| if (lex() != "$") { | |
| abort(); | |
| } | |
| // Reset the parser state. | |
| Index = Source = null; | |
| return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result; | |
| }; | |
| } | |
| } | |
| // Export for asynchronous module loaders. | |
| if (isLoader) { | |
| define(function () { | |
| return JSON3; | |
| }); | |
| } | |
| }(this)); | |
| },{}],44:[function(_dereq_,module,exports){ | |
| module.exports = toArray | |
| function toArray(list, index) { | |
| var array = [] | |
| index = index || 0 | |
| for (var i = index || 0; i < list.length; i++) { | |
| array[i - index] = list[i] | |
| } | |
| return array | |
| } | |
| },{}]},{},[1]) | |
| (1) | |
| }); |
| diff --git a/0b9bdaf16f82daefc787a36c41a35277b7a29f84:./socket.io.js b/4c05eb5785cdbf1dc78a71a6fb388122cec4ce41:./socket.io.js | |
| index 9248e28..6f0ac98 100644 | |
| --- a/0b9bdaf16f82daefc787a36c41a35277b7a29f84:./socket.io.js | |
| +++ b/4c05eb5785cdbf1dc78a71a6fb388122cec4ce41:./socket.io.js | |
| @@ -3153,7 +3153,7 @@ var debug = _dereq_('debug')('engine.io-client:websocket'); | |
| * in the browser. | |
| */ | |
| -var WebSocket = _dereq_('ws'); | |
| +var WebSocket = require('net.iamyellow.tiws'); | |
| /** | |
| * Module exports. | |
| @@ -3203,6 +3203,7 @@ WS.prototype.supportsBinary = true; | |
| */ | |
| WS.prototype.doOpen = function(){ | |
| + // TODO: Figure out and fix. This causes initial connection to time out on iOS. | |
| if (!this.check()) { | |
| // let probe timeout | |
| return; | |
| @@ -3213,7 +3214,7 @@ WS.prototype.doOpen = function(){ | |
| var protocols = void(0); | |
| var opts = { agent: this.agent }; | |
| - this.ws = new WebSocket(uri, protocols, opts); | |
| + this.ws = WebSocket.createWS(); | |
| if (this.ws.binaryType === undefined) { | |
| this.supportsBinary = false; | |
| @@ -3221,6 +3222,7 @@ WS.prototype.doOpen = function(){ | |
| this.ws.binaryType = 'arraybuffer'; | |
| this.addEventListeners(); | |
| + this.ws.open(uri); | |
| }; | |
| /** | |
| @@ -3232,18 +3234,18 @@ WS.prototype.doOpen = function(){ | |
| WS.prototype.addEventListeners = function(){ | |
| var self = this; | |
| - this.ws.onopen = function(){ | |
| + this.ws.addEventListener('open', function () { | |
| self.onOpen(); | |
| - }; | |
| - this.ws.onclose = function(){ | |
| + }); | |
| + this.ws.addEventListener('close', function (ev) { | |
| self.onClose(); | |
| - }; | |
| - this.ws.onmessage = function(ev){ | |
| + }); | |
| + this.ws.addEventListener('message', function (ev) { | |
| self.onData(ev.data); | |
| - }; | |
| - this.ws.onerror = function(e){ | |
| + }); | |
| + this.ws.addEventListener('error', function (e) { | |
| self.onError('websocket error', e); | |
| - }; | |
| + }); | |
| }; | |
| /** | |
| @@ -3432,7 +3434,7 @@ var utf8 = _dereq_('utf8'); | |
| * http://ghinda.net/jpeg-blob-ajax-android/ | |
| */ | |
| -var isAndroid = navigator.userAgent.match(/Android/i); | |
| +var isAndroid = false; // navigator.userAgent.match(/Android/i); | |
| /** | |
| * Current protocol version. |
Great and thanks for the info!
Celso, can you provide an example of connecting to sockei.io on server ? Thanks
Thanks for updating
@DouglasHennrich using this example you can connect mobile app to server using web socket!
var socketIO = require('socket.io'); //Socket io library or path to socket io lib
var socket = socketIO.connect('http://yourdomain.com', {
transports : ['websocket'],
timeout : 20000,
reconnection : true
});
socket.io.on('connect_error', function(e) {
console.info('Socket Manager - Connect error');
});
socket.io.on('reconnect_failed', function() {
console.info('Socket Manager - Reconnect failed');
});
socket.on('connect', function() {
console.info('Socket - Connect event received from server');
});
socket.on('disconnect', function() {
console.info('Socket - Disconnection event received');
});
socket.on('error', function() {
console.info('Socket - Error while connection');
});
For implement SocketIO into your server use official SocketIO docs: http://socket.io/docs/server-api/
enjoy!
How can I use this with Titanium?
For support iOS change the function for check if can use websocket, because only web socket is supported!
WS.prototype.check = function(){
return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
};
WS.prototype.check = function(){
return true
};