;(function(){ /** * Require the given path. * * @param {String} path * @return {Object} exports * @api public */ function require(p, parent, orig){ var path = require.resolve(p) , mod = require.modules[path]; // lookup failed if (null == path) { orig = orig || p; parent = parent || 'root'; throw new Error('failed to require "' + orig + '" from "' + parent + '"'); } // perform real require() // by invoking the module's // registered function if (!mod.exports) { mod.exports = {}; mod.client = mod.component = true; mod.call(this, mod, mod.exports, require.relative(path)); } return mod.exports; } /** * Registered modules. */ require.modules = {}; /** * Registered aliases. */ require.aliases = {}; /** * Resolve `path`. * * Lookup: * * - PATH/index.js * - PATH.js * - PATH * * @param {String} path * @return {String} path or null * @api private */ require.resolve = function(path){ var orig = path , reg = path + '.js' , regJSON = path + '.json' , index = path + '/index.js' , indexJSON = path + '/index.json'; return require.modules[reg] && reg || require.modules[regJSON] && regJSON || require.modules[index] && index || require.modules[indexJSON] && indexJSON || require.modules[orig] && orig || require.aliases[index]; }; /** * Normalize `path` relative to the current path. * * @param {String} curr * @param {String} path * @return {String} * @api private */ require.normalize = function(curr, path) { var segs = []; if ('.' != path.charAt(0)) return path; curr = curr.split('/'); path = path.split('/'); for (var i = 0; i < path.length; ++i) { if ('..' == path[i]) { curr.pop(); } else if ('.' != path[i] && '' != path[i]) { segs.push(path[i]); } } return curr.concat(segs).join('/'); }; /** * Register module at `path` with callback `fn`. * * @param {String} path * @param {Function} fn * @api private */ require.register = function(path, fn){ require.modules[path] = fn; }; /** * Alias a module definition. * * @param {String} from * @param {String} to * @api private */ require.alias = function(from, to){ var fn = require.modules[from]; if (!fn) throw new Error('failed to alias "' + from + '", it does not exist'); require.aliases[to] = from; }; /** * Return a require function relative to the `parent` path. * * @param {String} parent * @return {Function} * @api private */ require.relative = function(parent) { var p = require.normalize(parent, '..'); /** * lastIndexOf helper. */ function lastIndexOf(arr, obj){ var i = arr.length; while (i--) { if (arr[i] === obj) return i; } return -1; } /** * The relative require() itself. */ function fn(path){ var orig = path; path = fn.resolve(path); return require(path, parent, orig); } /** * Resolve relative to the parent. */ fn.resolve = function(path){ // resolve deps by returning // the dep in the nearest "deps" // directory if ('.' != path.charAt(0)) { var segs = parent.split('/'); var i = lastIndexOf(segs, 'deps') + 1; if (!i) i = 0; path = segs.slice(0, i + 1).join('/') + '/deps/' + path; return path; } return require.normalize(p, path); }; /** * Check if module is defined at `path`. */ fn.exists = function(path){ return !! require.modules[fn.resolve(path)]; }; return fn; };require.register("component-emitter/index.js", function(module, exports, require){ /** * 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 = 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); } fn._off = on; 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 = function(event, fn){ this._callbacks = this._callbacks || {}; 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 i = callbacks.indexOf(fn._off || fn); if (~i) callbacks.splice(i, 1); 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; }; }); require.register("LearnBoost-engine.io-protocol/lib/index.js", function(module, exports, require){ /** * Module dependencies. */ var keys = require('./keys') /** * 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' } /** * Encodes a packet. * * [ `:` ] * * Example: * * 5:hello world * 3 * 4 * * @api private */ exports.encodePacket = function (packet) { var encoded = packets[packet.type] // data fragment is optional if (undefined !== packet.data) { encoded += String(packet.data); } return '' + encoded; }; /** * Decodes a packet. * * @return {Object} with `type` and `data` (if any) * @api private */ exports.decodePacket = function (data) { 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] }; } }; /** * Encodes multiple messages (payload). * * :data * * Example: * * 11:hello world2:hi * * @param {Array} packets * @api private */ exports.encodePayload = function (packets) { if (!packets.length) { return '0:'; } var encoded = '' , message for (var i = 0, l = packets.length; i < l; i++) { message = exports.encodePacket(packets[i]); encoded += message.length + ':' + message; } return encoded; }; /* * Decodes data when a payload is maybe expected. * * @param {String} data * @return {Array} packets * @api public */ exports.decodePayload = function (data) { if (data == '') { // parser error - ignoring payload return [err]; } var packets = [] , length = '' , n, msg, packet 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 [err]; } msg = data.substr(i + 1, n); if (length != msg.length) { // parser error - ignoring payload return [err]; } if (msg.length) { packet = exports.decodePacket(msg); if (err.type == packet.type && err.data == packet.data) { // parser error in individual packet - ignoring payload return [err]; } packets.push(packet); } // advance cursor i += n; length = '' } } if (length != '') { // parser error - ignoring payload return [err]; } return packets; }; }); require.register("LearnBoost-engine.io-protocol/lib/keys.js", function(module, exports, require){ /** * 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; }; }); require.register("visionmedia-debug/index.js", function(module, exports, require){ if ('undefined' == typeof window) { module.exports = require('./lib/debug'); } else { module.exports = require('./debug'); } }); require.register("visionmedia-debug/debug.js", function(module, exports, require){ /** * 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){ 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) { localStorage.debug = name; 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; }; // persist if (window.localStorage) debug.enable(localStorage.debug); }); require.register("engine.io/lib/index.js", function(module, exports, require){ module.exports = require('./socket'); /** * Exports parser * * @api public * */ module.exports.parser = require('engine.io-parser'); }); require.register("engine.io/lib/socket.js", function(module, exports, require){ /** * Module dependencies. */ var util = require('./util') , transports = require('./transports') , Emitter = require('./emitter') , debug = require('debug')('engine-client:socket'); /** * Module exports. */ module.exports = Socket; /** * Global reference. */ var global = util.global(); /** * 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 ('object' == typeof uri) { opts = uri; uri = null; } if (uri) { uri = util.parseUri(uri); opts.host = uri.host; opts.secure = uri.protocol == 'https' || uri.protocol == 'wss'; opts.port = uri.port; } 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.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 || {}; this.upgrade = false !== opts.upgrade; this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/'; this.forceJSONP = !!opts.forceJSONP; this.timestampParam = opts.timestampParam || 't'; this.timestampRequests = !!opts.timestampRequests; this.flashPath = opts.flashPath || ''; this.transports = opts.transports || ['polling', 'websocket', 'flashsocket']; this.readyState = ''; this.writeBuffer = []; this.policyPort = opts.policyPort || 843; this.open(); Socket.sockets.push(this); Socket.sockets.evs.emit('add', this); }; /** * Mix in `Emitter`. */ Emitter(Socket.prototype); /** * Protocol version. * * @api public */ Socket.protocol = 1; /** * Static EventEmitter. */ Socket.sockets = []; Socket.sockets.evs = new Emitter; /** * Expose deps for legacy compatibility * and standalone browser access. */ Socket.Socket = Socket; Socket.Transport = require('./transport'); Socket.Emitter = require('./emitter'); Socket.transports = require('./transports'); Socket.util = require('./util'); Socket.parser = require('engine.io-parser'); /** * Creates transport of the given type. * * @param {String} transport name * @return {Transport} * @api private */ Socket.prototype.createTransport = function (name) { debug('creating transport "%s"', name); var query = clone(this.query); query.transport = name; if (this.id) { query.sid = this.id; } var transport = new transports[name]({ hostname: this.hostname, port: this.port, secure: this.secure, path: this.path, query: query, forceJSONP: this.forceJSONP, timestampRequests: this.timestampRequests, timestampParam: this.timestampParam, flashPath: this.flashPath, policyPort: this.policyPort }); 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 () { this.readyState = 'opening'; var transport = this.createTransport(this.transports[0]); transport.open(); this.setTransport(transport); }; /** * Sets the current transport. Disables the existing one (if any). * * @api private */ Socket.prototype.setTransport = function (transport) { var self = this; if (this.transport) { debug('clearing existing transport'); this.transport.removeAllListeners(); } // set up transport this.transport = transport; // set up transport listeners transport .on('drain', function () { self.flush(); }) .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; transport.once('open', function () { 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); debug('pausing current transport "%s"', self.transport.name); self.transport.pause(function () { if (failed) return; if ('closed' == self.readyState || 'closing' == self.readyState) { return; } debug('changing transport and sending upgrade packet'); transport.removeListener('error', onerror); self.emit('upgrade', transport); self.setTransport(transport); transport.send([{ type: 'upgrade' }]); 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('error', err); } }); }); transport.once('error', onerror); function onerror(err) { if (failed) return; // Any callback called by transport should be ignored since now failed = true; var error = new Error('probe error: ' + err); error.transport = transport.name; transport.close(); transport = null; debug('probe transport "%s" failed because of error: %s', name, err); self.emit('error', error); }; transport.open(); this.once('close', function () { if (transport) { debug('socket closed prematurely - aborting probe'); failed = true; transport.close(); transport = null; } }); this.once('upgrading', function (to) { if (transport && to.name != transport.name) { debug('"%s" works - aborting "%s"', to.name, transport.name); transport.close(); transport = null; } }); }; /** * Called when connection is deemed open. * * @api public */ Socket.prototype.onOpen = function () { debug('socket open'); this.readyState = 'open'; this.emit('open'); this.onopen && this.onopen.call(this); this.flush(); // we check for `readyState` in case an `open` // listener alreay 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(util.parseJSON(packet.data)); break; case 'pong': this.ping(); 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); var event = { data: packet.data }; event.toString = function () { return packet.data; }; this.onmessage && this.onmessage.call(this, event); 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(); this.ping(); // 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.ping = function () { var self = this; clearTimeout(self.pingIntervalTimer); self.pingIntervalTimer = setTimeout(function () { debug('writing ping packet - expecting pong within %sms', self.pingTimeout); self.sendPacket('ping'); self.onHeartbeat(self.pingTimeout); }, self.pingInterval); }; /** * 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); this.writeBuffer = []; } }; /** * Sends a message. * * @param {String} message. * @return {Socket} for chaining. * @api public */ Socket.prototype.write = Socket.prototype.send = function (msg) { this.sendPacket('message', msg); return this; }; /** * Sends a packet. * * @param {String} packet type. * @param {String} data. * @api private */ Socket.prototype.sendPacket = function (type, data) { var packet = { type: type, data: data }; this.emit('packetCreate', packet); this.writeBuffer.push(packet); this.flush(); }; /** * Closes the connection. * * @api private */ Socket.prototype.close = function () { if ('opening' == this.readyState || 'open' == this.readyState) { this.onClose('forced close'); debug('socket closing - telling transport to close'); this.transport.close(); this.transport.removeAllListeners(); } return this; }; /** * Called upon transport error * * @api private */ Socket.prototype.onError = function (err) { debug('socket error %j', err); 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) { debug('socket close with reason: "%s"', reason); clearTimeout(this.pingIntervalTimer); clearTimeout(this.pingTimeoutTimer); this.readyState = 'closed'; this.emit('close', reason, desc); this.onclose && this.onclose.call(this); this.id = null; } }; /** * 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 (MIT license) * @api private */ var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; var parts = [ 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host' , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' ]; exports.parseUri = function (str) { var m = re.exec(str || '') , uri = {} , i = 14; while (i--) { uri[parts[i]] = m[i] || ''; } return uri; }; /** * Compiles a querystring * * @param {Object} * @api private */ exports.qs = function (obj) { var str = ''; for (var i in obj) { if (obj.hasOwnProperty(i)) { if (str.length) str += '&'; str += i + '=' + encodeURIComponent(obj[i]); } } return str; }; }); require.register("engine.io/lib/transports/index.js", function(module, exports, require){ /** * Module dependencies */ var XHR = require('./polling-xhr') , JSONP = require('./polling-jsonp') , websocket = require('./websocket') , flashsocket = require('./flashsocket') , util = require('../util'); /** * Export transports. */ exports.polling = polling; exports.websocket = websocket; exports.flashsocket = flashsocket; /** * Global reference. */ var global = util.global() /** * Polling transport polymorphic constructor. * Decides on xhr vs jsonp based on feature detection. * * @api private */ function polling (opts) { var xhr , xd = false , isXProtocol = false; if (global.location) { var isSSL = 'https:' == location.protocol; var port = location.port; // some user agents have empty `location.port` if (Number(port) != port) { port = isSSL ? 443 : 80; } xd = opts.host != location.hostname || port != opts.port; isXProtocol = opts.secure != isSSL; } xhr = util.request(xd); /* See #7 at http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx */ if (isXProtocol && global.XDomainRequest && xhr instanceof global.XDomainRequest) { return new JSONP(opts); } if (xhr && !opts.forceJSONP) { return new XHR(opts); } else { return new JSONP(opts); } }; }); require.register("engine.io/lib/transports/polling.js", function(module, exports, require){ /** * Module dependencies. */ var Transport = require('../transport') , util = require('../util') , parser = require('engine.io-parser') , debug = require('debug')('engine.io-client:polling'); /** * Module exports. */ module.exports = Polling; /** * Global reference. */ var global = util.global(); /** * Polling interface. * * @param {Object} opts * @api private */ function Polling(opts){ Transport.call(this, opts); } /** * Inherits from Transport. */ util.inherits(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){ debug('polling got data %s', data); // decode payload var packets = parser.decodePayload(data); for (var i = 0, l = packets.length; i < l; i++) { // if its the first message we consider the trnasport open if ('opening' == this.readyState) { this.onOpen(); } // if its a close packet, we close the ongoing requests if ('close' == packets[i].type) { this.onClose(); return; } // otherwise bypass onData and handle the message this.onPacket(packets[i]); } // 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(){ debug('sending close packet'); this.send([{ type: '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; this.doWrite(parser.encodePayload(packets), function(){ self.writable = true; self.emit('drain'); }); }; /** * 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 for IE / android / iOS6 ಠ_ಠ if (global.ActiveXObject || util.ua.android || util.ua.ios6 || this.timestampRequests) { query[this.timestampParam] = +new Date; } query = util.qs(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; }; }); require.register("engine.io/lib/transports/polling-xhr.js", function(module, exports, require){ /** * Module requirements. */ var Polling = require('./polling') , util = require('../util') , Emitter = require('../emitter') , debug = require('debug')('engine.io-client:polling-xhr'); /** * Module exports. */ module.exports = XHR; module.exports.Request = Request; /** * Global reference. */ var global = util.global(); /** * Obfuscated key for Blue Coat. */ var xobject = global[['Active'].concat('Object').join('X')]; /** * Empty function */ function empty(){} /** * XHR Polling constructor. * * @param {Object} opts * @api public */ function XHR(opts){ Polling.call(this, opts); if (global.location) { this.xd = opts.host != global.location.hostname || global.location.port != opts.port; } }; /** * Inherits from Polling. */ util.inherits(XHR, Polling); /** * Opens the socket * * @api private */ XHR.prototype.doOpen = function(){ var self = this; util.defer(function(){ Polling.prototype.doOpen.call(self); }); }; /** * Creates a request. * * @param {String} method * @api private */ XHR.prototype.request = function(opts){ opts = opts || {}; opts.uri = this.uri(); opts.xd = this.xd; 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 req = this.request({ method: 'POST', data: data }); 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.async = false !== opts.async; this.data = undefined != opts.data ? opts.data : null; 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 = util.request(this.xd); var self = this; xhr.open(this.method, this.uri, this.async); if ('POST' == this.method) { try { if (xhr.setRequestHeader) { // xmlhttprequest xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8'); } else { // xdomainrequest xhr.contentType = 'text/plain'; } } catch (e) {} } if (this.xd && global.XDomainRequest && xhr instanceof XDomainRequest) { xhr.onerror = function(e){ self.onError(e); }; xhr.onload = function(){ self.onData(xhr.responseText); }; xhr.onprogress = empty; } else { // ie6 check if ('withCredentials' in xhr) { xhr.withCredentials = true; } xhr.onreadystatechange = function(){ var data; try { if (4 != xhr.readyState) return; if (200 == xhr.status || 1223 == xhr.status) { data = xhr.responseText; } else { self.onError(xhr.status); } } catch (e) { self.onError(e); } if (undefined !== data) { self.onData(data); } }; } debug('sending xhr with url %s | data %s', this.uri, this.data); xhr.send(this.data); if (xobject) { 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(){ // xmlhttprequest this.xhr.onreadystatechange = empty; // xdomainrequest this.xhr.onload = this.xhr.onerror = empty; try { this.xhr.abort(); } catch(e) {} if (xobject) { delete Request.requests[this.index]; } this.xhr = null; }; /** * Aborts the request. * * @api public */ Request.prototype.abort = function(){ this.cleanup(); }; if (xobject) { Request.requestsCount = 0; Request.requests = {}; global.attachEvent('onunload', function(){ for (var i in Request.requests) { if (Request.requests.hasOwnProperty(i)) { Request.requests[i].abort(); } } }); } }); require.register("engine.io/lib/transports/polling-jsonp.js", function(module, exports, require){ /** * Module requirements. */ var Polling = require('./polling') , util = require('../util'); /** * Module exports. */ module.exports = JSONPPolling; /** * Global reference. */ var global = util.global(); /** * Cached regular expressions. */ var rNewline = /\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); // 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; }; /** * Inherits from Polling. */ util.inherits(JSONPPolling, Polling); /** * Opens the socket. * * @api private */ JSONPPolling.prototype.doOpen = function () { var self = this; util.defer(function () { Polling.prototype.doOpen.call(self); }); }; /** * 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; } Polling.prototype.doClose.call(this); }; /** * Starts a poll cycle. * * @api private */ JSONPPolling.prototype.doPoll = function () { var script = document.createElement('script'); if (this.script) { this.script.parentNode.removeChild(this.script); this.script = null; } script.async = true; script.src = this.uri(); var insertAt = document.getElementsByTagName('script')[0]; insertAt.parentNode.insertBefore(script, insertAt); this.script = script; if (util.ua.gecko) { 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 = '