Server side PluginInterface ported into the browser
[KiwiIRC.git] / client / assets / libs / engine.io.js
CommitLineData
a74c0f0c 1;(function(){
d99e7823 2
f8e5fb60 3/**
a74c0f0c
D
4 * Require the given path.
5 *
6 * @param {String} path
7 * @return {Object} exports
8 * @api public
f8e5fb60 9 */
d99e7823 10
a74c0f0c
D
11function require(path, parent, orig) {
12 var resolved = require.resolve(path);
d99e7823 13
a74c0f0c
D
14 // lookup failed
15 if (null == resolved) {
16 orig = orig || path;
17 parent = parent || 'root';
18 var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
19 err.path = orig;
20 err.parent = parent;
21 err.require = true;
22 throw err;
23 }
d99e7823 24
a74c0f0c
D
25 var module = require.modules[resolved];
26
27 // perform real require()
28 // by invoking the module's
29 // registered function
30 if (!module.exports) {
31 module.exports = {};
32 module.client = module.component = true;
33 module.call(this, module.exports, require.relative(resolved), module);
34 }
35
36 return module.exports;
37}
d99e7823
D
38
39/**
a74c0f0c 40 * Registered modules.
d99e7823
D
41 */
42
a74c0f0c 43require.modules = {};
d99e7823
D
44
45/**
a74c0f0c 46 * Registered aliases.
d99e7823
D
47 */
48
a74c0f0c 49require.aliases = {};
d99e7823
D
50
51/**
a74c0f0c 52 * Resolve `path`.
d99e7823 53 *
a74c0f0c
D
54 * Lookup:
55 *
56 * - PATH/index.js
57 * - PATH.js
58 * - PATH
59 *
60 * @param {String} path
61 * @return {String} path or null
62 * @api private
d99e7823
D
63 */
64
a74c0f0c
D
65require.resolve = function(path) {
66 if (path.charAt(0) === '/') path = path.slice(1);
67 var index = path + '/index.js';
d99e7823 68
a74c0f0c
D
69 var paths = [
70 path,
71 path + '.js',
72 path + '.json',
73 path + '/index.js',
74 path + '/index.json'
75 ];
d99e7823 76
a74c0f0c
D
77 for (var i = 0; i < paths.length; i++) {
78 var path = paths[i];
79 if (require.modules.hasOwnProperty(path)) return path;
80 }
81
82 if (require.aliases.hasOwnProperty(index)) {
83 return require.aliases[index];
84 }
85};
d99e7823
D
86
87/**
a74c0f0c 88 * Normalize `path` relative to the current path.
d99e7823 89 *
a74c0f0c
D
90 * @param {String} curr
91 * @param {String} path
92 * @return {String}
93 * @api private
d99e7823
D
94 */
95
a74c0f0c
D
96require.normalize = function(curr, path) {
97 var segs = [];
d99e7823 98
a74c0f0c 99 if ('.' != path.charAt(0)) return path;
d99e7823 100
a74c0f0c
D
101 curr = curr.split('/');
102 path = path.split('/');
d99e7823 103
a74c0f0c
D
104 for (var i = 0; i < path.length; ++i) {
105 if ('..' == path[i]) {
106 curr.pop();
107 } else if ('.' != path[i] && '' != path[i]) {
108 segs.push(path[i]);
109 }
110 }
111
112 return curr.concat(segs).join('/');
113};
d99e7823
D
114
115/**
a74c0f0c
D
116 * Register module at `path` with callback `definition`.
117 *
118 * @param {String} path
119 * @param {Function} definition
120 * @api private
d99e7823
D
121 */
122
a74c0f0c
D
123require.register = function(path, definition) {
124 require.modules[path] = definition;
125};
d99e7823
D
126
127/**
a74c0f0c 128 * Alias a module definition.
d99e7823 129 *
a74c0f0c
D
130 * @param {String} from
131 * @param {String} to
d99e7823
D
132 * @api private
133 */
134
a74c0f0c
D
135require.alias = function(from, to) {
136 if (!require.modules.hasOwnProperty(from)) {
137 throw new Error('Failed to alias "' + from + '", it does not exist');
138 }
139 require.aliases[to] = from;
140};
d99e7823
D
141
142/**
a74c0f0c 143 * Return a require function relative to the `parent` path.
d99e7823 144 *
a74c0f0c
D
145 * @param {String} parent
146 * @return {Function}
147 * @api private
d99e7823
D
148 */
149
a74c0f0c
D
150require.relative = function(parent) {
151 var p = require.normalize(parent, '..');
d99e7823 152
a74c0f0c
D
153 /**
154 * lastIndexOf helper.
155 */
d99e7823 156
a74c0f0c
D
157 function lastIndexOf(arr, obj) {
158 var i = arr.length;
159 while (i--) {
160 if (arr[i] === obj) return i;
161 }
162 return -1;
d99e7823
D
163 }
164
a74c0f0c
D
165 /**
166 * The relative require() itself.
167 */
168
169 function localRequire(path) {
170 var resolved = localRequire.resolve(path);
171 return require(resolved, parent, path);
d99e7823
D
172 }
173
a74c0f0c
D
174 /**
175 * Resolve relative to the parent.
176 */
d99e7823 177
a74c0f0c
D
178 localRequire.resolve = function(path) {
179 var c = path.charAt(0);
180 if ('/' == c) return path.slice(1);
181 if ('.' == c) return require.normalize(p, path);
d99e7823 182
a74c0f0c
D
183 // resolve deps by returning
184 // the dep in the nearest "deps"
185 // directory
186 var segs = parent.split('/');
187 var i = lastIndexOf(segs, 'deps') + 1;
188 if (!i) i = 0;
189 path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
190 return path;
191 };
d99e7823 192
a74c0f0c
D
193 /**
194 * Check if module is defined at `path`.
195 */
d99e7823 196
a74c0f0c
D
197 localRequire.exists = function(path) {
198 return require.modules.hasOwnProperty(localRequire.resolve(path));
199 };
200
201 return localRequire;
202};
203require.register("component-emitter/index.js", function(exports, require, module){
d99e7823
D
204
205/**
a74c0f0c 206 * Expose `Emitter`.
d99e7823
D
207 */
208
a74c0f0c 209module.exports = Emitter;
d99e7823
D
210
211/**
a74c0f0c
D
212 * Initialize a new `Emitter`.
213 *
214 * @api public
f8e5fb60
JA
215 */
216
a74c0f0c
D
217function Emitter(obj) {
218 if (obj) return mixin(obj);
219};
f8e5fb60
JA
220
221/**
a74c0f0c 222 * Mixin the emitter properties.
d99e7823 223 *
a74c0f0c
D
224 * @param {Object} obj
225 * @return {Object}
d99e7823
D
226 * @api private
227 */
228
a74c0f0c
D
229function mixin(obj) {
230 for (var key in Emitter.prototype) {
231 obj[key] = Emitter.prototype[key];
d99e7823 232 }
a74c0f0c 233 return obj;
d99e7823
D
234}
235
236/**
a74c0f0c 237 * Listen on the given `event` with `fn`.
d99e7823 238 *
a74c0f0c
D
239 * @param {String} event
240 * @param {Function} fn
241 * @return {Emitter}
242 * @api public
d99e7823
D
243 */
244
a74c0f0c
D
245Emitter.prototype.on = function(event, fn){
246 this._callbacks = this._callbacks || {};
247 (this._callbacks[event] = this._callbacks[event] || [])
248 .push(fn);
249 return this;
d99e7823
D
250};
251
252/**
a74c0f0c
D
253 * Adds an `event` listener that will be invoked a single
254 * time then automatically removed.
d99e7823 255 *
a74c0f0c
D
256 * @param {String} event
257 * @param {Function} fn
258 * @return {Emitter}
259 * @api public
d99e7823
D
260 */
261
a74c0f0c 262Emitter.prototype.once = function(event, fn){
d99e7823 263 var self = this;
a74c0f0c 264 this._callbacks = this._callbacks || {};
d99e7823 265
a74c0f0c
D
266 function on() {
267 self.off(event, on);
268 fn.apply(this, arguments);
d99e7823
D
269 }
270
a74c0f0c
D
271 fn._off = on;
272 this.on(event, on);
273 return this;
d99e7823
D
274};
275
276/**
a74c0f0c
D
277 * Remove the given callback for `event` or all
278 * registered callbacks.
d99e7823 279 *
a74c0f0c
D
280 * @param {String} event
281 * @param {Function} fn
282 * @return {Emitter}
283 * @api public
d99e7823
D
284 */
285
a74c0f0c
D
286Emitter.prototype.off =
287Emitter.prototype.removeListener =
288Emitter.prototype.removeAllListeners = function(event, fn){
289 this._callbacks = this._callbacks || {};
d99e7823 290
a74c0f0c
D
291 // all
292 if (0 == arguments.length) {
293 this._callbacks = {};
294 return this;
295 }
d99e7823 296
a74c0f0c
D
297 // specific event
298 var callbacks = this._callbacks[event];
299 if (!callbacks) return this;
d99e7823 300
a74c0f0c
D
301 // remove all handlers
302 if (1 == arguments.length) {
303 delete this._callbacks[event];
304 return this;
305 }
d99e7823 306
a74c0f0c
D
307 // remove specific handler
308 var i = callbacks.indexOf(fn._off || fn);
309 if (~i) callbacks.splice(i, 1);
310 return this;
311};
d99e7823 312
a74c0f0c
D
313/**
314 * Emit `event` with the given args.
315 *
316 * @param {String} event
317 * @param {Mixed} ...
318 * @return {Emitter}
319 */
d99e7823 320
a74c0f0c
D
321Emitter.prototype.emit = function(event){
322 this._callbacks = this._callbacks || {};
323 var args = [].slice.call(arguments, 1)
324 , callbacks = this._callbacks[event];
d99e7823 325
a74c0f0c
D
326 if (callbacks) {
327 callbacks = callbacks.slice(0);
328 for (var i = 0, len = callbacks.length; i < len; ++i) {
329 callbacks[i].apply(this, args);
330 }
d99e7823 331 }
d99e7823 332
a74c0f0c
D
333 return this;
334};
d99e7823 335
a74c0f0c
D
336/**
337 * Return array of callbacks for `event`.
338 *
339 * @param {String} event
340 * @return {Array}
341 * @api public
342 */
f8e5fb60 343
a74c0f0c
D
344Emitter.prototype.listeners = function(event){
345 this._callbacks = this._callbacks || {};
346 return this._callbacks[event] || [];
d99e7823
D
347};
348
349/**
a74c0f0c 350 * Check if this emitter has `event` handlers.
d99e7823 351 *
a74c0f0c
D
352 * @param {String} event
353 * @return {Boolean}
d99e7823
D
354 * @api public
355 */
356
a74c0f0c
D
357Emitter.prototype.hasListeners = function(event){
358 return !! this.listeners(event).length;
359};
d99e7823 360
a74c0f0c
D
361});
362require.register("component-indexof/index.js", function(exports, require, module){
363
364var indexOf = [].indexOf;
365
366module.exports = function(arr, obj){
367 if (indexOf) return arr.indexOf(obj);
368 for (var i = 0; i < arr.length; ++i) {
369 if (arr[i] === obj) return i;
d99e7823 370 }
a74c0f0c 371 return -1;
d99e7823 372};
a74c0f0c
D
373});
374require.register("LearnBoost-engine.io-protocol/lib/index.js", function(exports, require, module){
d99e7823 375/**
a74c0f0c 376 * Module dependencies.
d99e7823
D
377 */
378
a74c0f0c 379var keys = require('./keys');
d99e7823 380
a74c0f0c
D
381/**
382 * Current protocol version.
383 */
384exports.protocol = 2;
d99e7823 385
a74c0f0c
D
386/**
387 * Packet types.
388 */
d99e7823 389
a74c0f0c
D
390var packets = exports.packets = {
391 open: 0 // non-ws
392 , close: 1 // non-ws
393 , ping: 2
394 , pong: 3
395 , message: 4
396 , upgrade: 5
397 , noop: 6
398};
d99e7823 399
a74c0f0c 400var packetslist = keys(packets);
d99e7823 401
a74c0f0c
D
402/**
403 * Premade error packet.
404 */
d99e7823 405
a74c0f0c 406var err = { type: 'error', data: 'parser error' };
d99e7823
D
407
408/**
a74c0f0c
D
409 * Encodes a packet.
410 *
411 * <packet type id> [ `:` <data> ]
412 *
413 * Example:
414 *
415 * 5:hello world
416 * 3
417 * 4
f8e5fb60 418 *
f8e5fb60 419 * @api private
d99e7823
D
420 */
421
a74c0f0c
D
422exports.encodePacket = function (packet) {
423 var encoded = packets[packet.type];
f8e5fb60 424
a74c0f0c
D
425 // data fragment is optional
426 if (undefined !== packet.data) {
427 encoded += String(packet.data);
428 }
429
430 return '' + encoded;
f8e5fb60 431};
d99e7823
D
432
433/**
a74c0f0c 434 * Decodes a packet.
d99e7823 435 *
a74c0f0c 436 * @return {Object} with `type` and `data` (if any)
f8e5fb60 437 * @api private
d99e7823
D
438 */
439
a74c0f0c
D
440exports.decodePacket = function (data) {
441 var type = data.charAt(0);
442
443 if (Number(type) != type || !packetslist[type]) {
444 return err;
445 }
446
447 if (data.length > 1) {
448 return { type: packetslist[type], data: data.substring(1) };
449 } else {
450 return { type: packetslist[type] };
451 }
f8e5fb60 452};
d99e7823
D
453
454/**
a74c0f0c
D
455 * Encodes multiple messages (payload).
456 *
457 * <length>:data
f8e5fb60 458 *
a74c0f0c
D
459 * Example:
460 *
461 * 11:hello world2:hi
462 *
463 * @param {Array} packets
f8e5fb60 464 * @api private
d99e7823
D
465 */
466
a74c0f0c
D
467exports.encodePayload = function (packets) {
468 if (!packets.length) {
469 return '0:';
470 }
471
472 var encoded = '';
473 var message;
474
475 for (var i = 0, l = packets.length; i < l; i++) {
476 message = exports.encodePacket(packets[i]);
477 encoded += message.length + ':' + message;
478 }
479
480 return encoded;
f8e5fb60 481};
d99e7823 482
a74c0f0c
D
483/*
484 * Decodes data when a payload is maybe expected.
485 *
486 * @param {String} data, callback method
487 * @api public
488 */
489
490exports.decodePayload = function (data, callback) {
491 var packet;
492 if (data == '') {
493 // parser error - ignoring payload
494 return callback(err, 0, 1);
495 }
496
497 var length = ''
498 , n, msg;
499
500 for (var i = 0, l = data.length; i < l; i++) {
501 var chr = data.charAt(i);
502
503 if (':' != chr) {
504 length += chr;
505 } else {
506 if ('' == length || (length != (n = Number(length)))) {
507 // parser error - ignoring payload
508 return callback(err, 0, 1);
509 }
510
511 msg = data.substr(i + 1, n);
512
513 if (length != msg.length) {
514 // parser error - ignoring payload
515 return callback(err, 0, 1);
516 }
517
518 if (msg.length) {
519 packet = exports.decodePacket(msg);
520
521 if (err.type == packet.type && err.data == packet.data) {
522 // parser error in individual packet - ignoring payload
523 return callback(err, 0, 1);
524 }
525
526 var ret = callback(packet, i + n, l);
527 if (false === ret) return;
528 }
529
530 // advance cursor
531 i += n;
532 length = '';
533 }
534 }
535
536 if (length != '') {
537 // parser error - ignoring payload
538 return callback(err, 0, 1);
539 }
d99e7823 540
f8e5fb60 541};
d99e7823 542
a74c0f0c
D
543});
544require.register("LearnBoost-engine.io-protocol/lib/keys.js", function(exports, require, module){
545
d99e7823 546/**
a74c0f0c 547 * Gets the keys for an object.
d99e7823 548 *
a74c0f0c 549 * @return {Array} keys
d99e7823
D
550 * @api private
551 */
552
a74c0f0c
D
553module.exports = Object.keys || function keys (obj){
554 var arr = [];
555 var has = Object.prototype.hasOwnProperty;
556
557 for (var i in obj) {
558 if (has.call(obj, i)) {
559 arr.push(i);
f8e5fb60
JA
560 }
561 }
a74c0f0c
D
562 return arr;
563};
d99e7823 564
a74c0f0c
D
565});
566require.register("visionmedia-debug/index.js", function(exports, require, module){
567if ('undefined' == typeof window) {
568 module.exports = require('./lib/debug');
569} else {
570 module.exports = require('./debug');
571}
d99e7823 572
a74c0f0c
D
573});
574require.register("visionmedia-debug/debug.js", function(exports, require, module){
d99e7823 575
a74c0f0c
D
576/**
577 * Expose `debug()` as the module.
578 */
579
580module.exports = debug;
d99e7823 581
f8e5fb60 582/**
a74c0f0c 583 * Create a debugger with the given `name`.
f8e5fb60 584 *
a74c0f0c
D
585 * @param {String} name
586 * @return {Type}
587 * @api public
f8e5fb60 588 */
d99e7823 589
a74c0f0c
D
590function debug(name) {
591 if (!debug.enabled(name)) return function(){};
592
593 return function(fmt){
594 fmt = coerce(fmt);
595
596 var curr = new Date;
597 var ms = curr - (debug[name] || curr);
598 debug[name] = curr;
599
600 fmt = name
601 + ' '
602 + fmt
603 + ' +' + debug.humanize(ms);
604
605 // This hackery is required for IE8
606 // where `console.log` doesn't have 'apply'
607 window.console
608 && console.log
609 && Function.prototype.apply.call(console.log, console, arguments);
f8e5fb60 610 }
a74c0f0c 611}
d99e7823 612
f8e5fb60 613/**
a74c0f0c
D
614 * The currently active debug mode names.
615 */
616
617debug.names = [];
618debug.skips = [];
619
620/**
621 * Enables a debug mode by name. This can include modes
622 * separated by a colon and wildcards.
f8e5fb60 623 *
a74c0f0c 624 * @param {String} name
f8e5fb60
JA
625 * @api public
626 */
627
a74c0f0c
D
628debug.enable = function(name) {
629 try {
630 localStorage.debug = name;
631 } catch(e){}
632
633 var split = (name || '').split(/[\s,]+/)
634 , len = split.length;
635
636 for (var i = 0; i < len; i++) {
637 name = split[i].replace('*', '.*?');
638 if (name[0] === '-') {
639 debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
640 }
641 else {
642 debug.names.push(new RegExp('^' + name + '$'));
643 }
644 }
f8e5fb60 645};
d99e7823
D
646
647/**
a74c0f0c 648 * Disable debug output.
d99e7823 649 *
a74c0f0c 650 * @api public
d99e7823
D
651 */
652
a74c0f0c
D
653debug.disable = function(){
654 debug.enable('');
d99e7823
D
655};
656
657/**
a74c0f0c 658 * Humanize the given `ms`.
d99e7823 659 *
a74c0f0c
D
660 * @param {Number} m
661 * @return {String}
d99e7823
D
662 * @api private
663 */
664
a74c0f0c
D
665debug.humanize = function(ms) {
666 var sec = 1000
667 , min = 60 * 1000
668 , hour = 60 * min;
d99e7823 669
a74c0f0c
D
670 if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
671 if (ms >= min) return (ms / min).toFixed(1) + 'm';
672 if (ms >= sec) return (ms / sec | 0) + 's';
673 return ms + 'ms';
f8e5fb60 674};
d99e7823 675
f8e5fb60 676/**
a74c0f0c 677 * Returns true if the given mode name is enabled, false otherwise.
f8e5fb60 678 *
a74c0f0c
D
679 * @param {String} name
680 * @return {Boolean}
681 * @api public
f8e5fb60
JA
682 */
683
a74c0f0c
D
684debug.enabled = function(name) {
685 for (var i = 0, len = debug.skips.length; i < len; i++) {
686 if (debug.skips[i].test(name)) {
687 return false;
688 }
689 }
690 for (var i = 0, len = debug.names.length; i < len; i++) {
691 if (debug.names[i].test(name)) {
692 return true;
693 }
694 }
695 return false;
d99e7823
D
696};
697
698/**
a74c0f0c 699 * Coerce `val`.
d99e7823
D
700 */
701
a74c0f0c
D
702function coerce(val) {
703 if (val instanceof Error) return val.stack || val.message;
704 return val;
705}
d99e7823 706
a74c0f0c 707// persist
f8e5fb60 708
a74c0f0c 709if (window.localStorage) debug.enable(localStorage.debug);
f8e5fb60 710
a74c0f0c
D
711});
712require.register("engine.io/lib/index.js", function(exports, require, module){
f8e5fb60 713
a74c0f0c 714module.exports = require('./socket');
f8e5fb60
JA
715
716/**
a74c0f0c 717 * Exports parser
f8e5fb60 718 *
a74c0f0c 719 * @api public
f8e5fb60
JA
720 *
721 */
a74c0f0c 722module.exports.parser = require('engine.io-parser');
d99e7823 723
a74c0f0c
D
724});
725require.register("engine.io/lib/socket.js", function(exports, require, module){
f8e5fb60
JA
726/**
727 * Module dependencies.
728 */
d99e7823 729
a74c0f0c
D
730var util = require('./util')
731 , transports = require('./transports')
732 , Emitter = require('./emitter')
733 , debug = require('debug')('engine-client:socket')
734 , index = require('indexof')
735 , parser = require('engine.io-parser');
d99e7823 736
f8e5fb60
JA
737/**
738 * Module exports.
739 */
d99e7823 740
a74c0f0c 741module.exports = Socket;
d99e7823 742
f8e5fb60 743/**
a74c0f0c 744 * Global reference.
f8e5fb60 745 */
d99e7823 746
a74c0f0c 747var global = util.global();
d99e7823 748
f8e5fb60 749/**
a74c0f0c
D
750 * Noop function.
751 *
752 * @api private
f8e5fb60
JA
753 */
754
a74c0f0c 755function noop () {};
d99e7823
D
756
757/**
a74c0f0c 758 * Socket constructor.
d99e7823 759 *
a74c0f0c
D
760 * @param {String|Object} uri or options
761 * @param {Object} options
d99e7823
D
762 * @api public
763 */
764
a74c0f0c
D
765function Socket(uri, opts){
766 if (!(this instanceof Socket)) return new Socket(uri, opts);
767
768 opts = opts || {};
769
770 if ('object' == typeof uri) {
771 opts = uri;
772 uri = null;
773 }
774
775 if (uri) {
776 uri = util.parseUri(uri);
777 opts.host = uri.host;
778 opts.secure = uri.protocol == 'https' || uri.protocol == 'wss';
779 opts.port = uri.port;
780 if (uri.query) opts.query = uri.query;
781 }
782
783 this.secure = null != opts.secure ? opts.secure :
784 (global.location && 'https:' == location.protocol);
785
786 if (opts.host) {
787 var pieces = opts.host.split(':');
788 opts.hostname = pieces.shift();
789 if (pieces.length) opts.port = pieces.pop();
790 }
791
792 this.hostname = opts.hostname ||
793 (global.location ? location.hostname : 'localhost');
794 this.port = opts.port || (global.location && location.port ?
795 location.port :
796 (this.secure ? 443 : 80));
797 this.query = opts.query || {};
798 if ('string' == typeof this.query) this.query = util.qsParse(this.query);
799 this.upgrade = false !== opts.upgrade;
800 this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
801 this.forceJSONP = !!opts.forceJSONP;
802 this.timestampParam = opts.timestampParam || 't';
803 this.timestampRequests = !!opts.timestampRequests;
804 this.flashPath = opts.flashPath || '';
805 this.transports = opts.transports || ['polling', 'websocket', 'flashsocket'];
806 this.readyState = '';
807 this.writeBuffer = [];
808 this.callbackBuffer = [];
809 this.policyPort = opts.policyPort || 843;
810 this.open();
811
812 Socket.sockets.push(this);
813 Socket.sockets.evs.emit('add', this);
f8e5fb60 814};
d99e7823 815
f8e5fb60 816/**
a74c0f0c
D
817 * Mix in `Emitter`.
818 */
819
820Emitter(Socket.prototype);
821
822/**
823 * Protocol version.
f8e5fb60
JA
824 *
825 * @api public
826 */
827
a74c0f0c 828Socket.protocol = parser.protocol; // this is an int
d99e7823
D
829
830/**
a74c0f0c 831 * Static EventEmitter.
d99e7823
D
832 */
833
a74c0f0c
D
834Socket.sockets = [];
835Socket.sockets.evs = new Emitter;
d99e7823 836
a74c0f0c
D
837/**
838 * Expose deps for legacy compatibility
839 * and standalone browser access.
840 */
841
842Socket.Socket = Socket;
843Socket.Transport = require('./transport');
844Socket.Emitter = require('./emitter');
845Socket.transports = require('./transports');
846Socket.util = require('./util');
847Socket.parser = require('engine.io-parser');
d99e7823 848
f8e5fb60 849/**
a74c0f0c 850 * Creates transport of the given type.
f8e5fb60 851 *
a74c0f0c
D
852 * @param {String} transport name
853 * @return {Transport}
f8e5fb60
JA
854 * @api private
855 */
d99e7823 856
a74c0f0c
D
857Socket.prototype.createTransport = function (name) {
858 debug('creating transport "%s"', name);
859 var query = clone(this.query);
860
861 // append engine.io protocol identifier
862 query.EIO = parser.protocol;
863
864 // transport name
865 query.transport = name;
866
867 // session id if we already have one
868 if (this.id) query.sid = this.id;
869
870 var transport = new transports[name]({
871 hostname: this.hostname,
872 port: this.port,
873 secure: this.secure,
874 path: this.path,
875 query: query,
876 forceJSONP: this.forceJSONP,
877 timestampRequests: this.timestampRequests,
878 timestampParam: this.timestampParam,
879 flashPath: this.flashPath,
880 policyPort: this.policyPort
881 });
882
883 return transport;
d99e7823
D
884};
885
a74c0f0c
D
886function clone (obj) {
887 var o = {};
888 for (var i in obj) {
889 if (obj.hasOwnProperty(i)) {
890 o[i] = obj[i];
891 }
892 }
893 return o;
894}
895
d99e7823 896/**
a74c0f0c 897 * Initializes transport to use and starts probe.
d99e7823 898 *
d99e7823
D
899 * @api private
900 */
901
a74c0f0c
D
902Socket.prototype.open = function () {
903 this.readyState = 'opening';
904 var transport = this.createTransport(this.transports[0]);
905 transport.open();
906 this.setTransport(transport);
d99e7823
D
907};
908
909/**
a74c0f0c 910 * Sets the current transport. Disables the existing one (if any).
d99e7823
D
911 *
912 * @api private
913 */
914
a74c0f0c
D
915Socket.prototype.setTransport = function (transport) {
916 var self = this;
d99e7823 917
a74c0f0c
D
918 if (this.transport) {
919 debug('clearing existing transport');
920 this.transport.removeAllListeners();
921 }
f8e5fb60 922
a74c0f0c
D
923 // set up transport
924 this.transport = transport;
925
926 // set up transport listeners
927 transport
928 .on('drain', function () {
929 self.onDrain();
930 })
931 .on('packet', function (packet) {
932 self.onPacket(packet);
933 })
934 .on('error', function (e) {
935 self.onError(e);
936 })
937 .on('close', function () {
938 self.onClose('transport close');
939 });
f8e5fb60
JA
940};
941
942/**
a74c0f0c 943 * Probes a transport.
d99e7823 944 *
a74c0f0c 945 * @param {String} transport name
d99e7823
D
946 * @api private
947 */
948
a74c0f0c
D
949Socket.prototype.probe = function (name) {
950 debug('probing transport "%s"', name);
951 var transport = this.createTransport(name, { probe: 1 })
952 , failed = false
953 , self = this;
f8e5fb60 954
a74c0f0c
D
955 transport.once('open', function () {
956 if (failed) return;
d99e7823 957
a74c0f0c
D
958 debug('probe transport "%s" opened', name);
959 transport.send([{ type: 'ping', data: 'probe' }]);
960 transport.once('packet', function (msg) {
961 if (failed) return;
962 if ('pong' == msg.type && 'probe' == msg.data) {
963 debug('probe transport "%s" pong', name);
964 self.upgrading = true;
965 self.emit('upgrading', transport);
d99e7823 966
a74c0f0c
D
967 debug('pausing current transport "%s"', self.transport.name);
968 self.transport.pause(function () {
969 if (failed) return;
970 if ('closed' == self.readyState || 'closing' == self.readyState) {
971 return;
972 }
973 debug('changing transport and sending upgrade packet');
974 transport.removeListener('error', onerror);
975 self.emit('upgrade', transport);
976 self.setTransport(transport);
977 transport.send([{ type: 'upgrade' }]);
978 transport = null;
979 self.upgrading = false;
980 self.flush();
981 });
982 } else {
983 debug('probe transport "%s" failed', name);
984 var err = new Error('probe error');
985 err.transport = transport.name;
986 self.emit('error', err);
987 }
988 });
989 });
d99e7823 990
a74c0f0c
D
991 transport.once('error', onerror);
992 function onerror(err) {
993 if (failed) return;
d99e7823 994
a74c0f0c
D
995 // Any callback called by transport should be ignored since now
996 failed = true;
d99e7823 997
a74c0f0c
D
998 var error = new Error('probe error: ' + err);
999 error.transport = transport.name;
d99e7823 1000
a74c0f0c
D
1001 transport.close();
1002 transport = null;
f8e5fb60 1003
a74c0f0c 1004 debug('probe transport "%s" failed because of error: %s', name, err);
f8e5fb60 1005
a74c0f0c
D
1006 self.emit('error', error);
1007 };
f8e5fb60 1008
a74c0f0c 1009 transport.open();
d99e7823 1010
a74c0f0c
D
1011 this.once('close', function () {
1012 if (transport) {
1013 debug('socket closed prematurely - aborting probe');
1014 failed = true;
1015 transport.close();
1016 transport = null;
1017 }
1018 });
d99e7823 1019
a74c0f0c
D
1020 this.once('upgrading', function (to) {
1021 if (transport && to.name != transport.name) {
1022 debug('"%s" works - aborting "%s"', to.name, transport.name);
1023 transport.close();
1024 transport = null;
1025 }
1026 });
1027};
d99e7823
D
1028
1029/**
a74c0f0c 1030 * Called when connection is deemed open.
d99e7823 1031 *
d99e7823
D
1032 * @api public
1033 */
1034
a74c0f0c
D
1035Socket.prototype.onOpen = function () {
1036 debug('socket open');
1037 this.readyState = 'open';
1038 this.emit('open');
1039 this.onopen && this.onopen.call(this);
1040 this.flush();
1041
1042 // we check for `readyState` in case an `open`
1043 // listener alreay closed the socket
1044 if ('open' == this.readyState && this.upgrade && this.transport.pause) {
1045 debug('starting upgrade probes');
1046 for (var i = 0, l = this.upgrades.length; i < l; i++) {
1047 this.probe(this.upgrades[i]);
1048 }
1049 }
1050};
d99e7823
D
1051
1052/**
a74c0f0c 1053 * Handles a packet.
d99e7823 1054 *
a74c0f0c 1055 * @api private
d99e7823
D
1056 */
1057
a74c0f0c
D
1058Socket.prototype.onPacket = function (packet) {
1059 if ('opening' == this.readyState || 'open' == this.readyState) {
1060 debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
f8e5fb60 1061
a74c0f0c 1062 this.emit('packet', packet);
f8e5fb60 1063
a74c0f0c
D
1064 // Socket is live - any packet counts
1065 this.emit('heartbeat');
f8e5fb60 1066
a74c0f0c
D
1067 switch (packet.type) {
1068 case 'open':
1069 this.onHandshake(util.parseJSON(packet.data));
1070 break;
f8e5fb60 1071
a74c0f0c
D
1072 case 'pong':
1073 this.setPing();
1074 break;
f8e5fb60 1075
a74c0f0c
D
1076 case 'error':
1077 var err = new Error('server error');
1078 err.code = packet.data;
1079 this.emit('error', err);
1080 break;
f8e5fb60 1081
a74c0f0c
D
1082 case 'message':
1083 this.emit('data', packet.data);
1084 this.emit('message', packet.data);
1085 var event = { data: packet.data };
1086 event.toString = function () {
1087 return packet.data;
1088 };
1089 this.onmessage && this.onmessage.call(this, event);
1090 break;
1091 }
1092 } else {
1093 debug('packet received with socket readyState "%s"', this.readyState);
1094 }
d99e7823
D
1095};
1096
1097/**
a74c0f0c 1098 * Called upon handshake completion.
d99e7823 1099 *
a74c0f0c 1100 * @param {Object} handshake obj
d99e7823
D
1101 * @api private
1102 */
1103
a74c0f0c
D
1104Socket.prototype.onHandshake = function (data) {
1105 this.emit('handshake', data);
1106 this.id = data.sid;
1107 this.transport.query.sid = data.sid;
1108 this.upgrades = this.filterUpgrades(data.upgrades);
1109 this.pingInterval = data.pingInterval;
1110 this.pingTimeout = data.pingTimeout;
1111 this.onOpen();
1112 this.setPing();
1113
1114 // Prolong liveness of socket on heartbeat
1115 this.removeListener('heartbeat', this.onHeartbeat);
1116 this.on('heartbeat', this.onHeartbeat);
d99e7823
D
1117};
1118
1119/**
a74c0f0c 1120 * Resets ping timeout.
d99e7823
D
1121 *
1122 * @api private
1123 */
1124
a74c0f0c
D
1125Socket.prototype.onHeartbeat = function (timeout) {
1126 clearTimeout(this.pingTimeoutTimer);
1127 var self = this;
1128 self.pingTimeoutTimer = setTimeout(function () {
1129 if ('closed' == self.readyState) return;
1130 self.onClose('ping timeout');
1131 }, timeout || (self.pingInterval + self.pingTimeout));
d99e7823
D
1132};
1133
1134/**
a74c0f0c
D
1135 * Pings server every `this.pingInterval` and expects response
1136 * within `this.pingTimeout` or closes connection.
d99e7823
D
1137 *
1138 * @api private
1139 */
1140
a74c0f0c 1141Socket.prototype.setPing = function () {
f8e5fb60 1142 var self = this;
a74c0f0c
D
1143 clearTimeout(self.pingIntervalTimer);
1144 self.pingIntervalTimer = setTimeout(function () {
1145 debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
1146 self.ping();
1147 self.onHeartbeat(self.pingTimeout);
1148 }, self.pingInterval);
1149};
f8e5fb60 1150
a74c0f0c
D
1151/**
1152* Sends a ping packet.
1153*
1154* @api public
1155*/
1156
1157Socket.prototype.ping = function () {
1158 this.sendPacket('ping');
d99e7823
D
1159};
1160
1161/**
a74c0f0c 1162 * Called on `drain` event
d99e7823 1163 *
a74c0f0c 1164 * @api private
d99e7823
D
1165 */
1166
a74c0f0c
D
1167 Socket.prototype.onDrain = function() {
1168 for (var i = 0; i < this.prevBufferLen; i++) {
1169 if (this.callbackBuffer[i]) {
1170 this.callbackBuffer[i]();
1171 }
d99e7823 1172 }
d99e7823 1173
a74c0f0c
D
1174 this.writeBuffer.splice(0, this.prevBufferLen);
1175 this.callbackBuffer.splice(0, this.prevBufferLen);
d99e7823 1176
a74c0f0c
D
1177 // setting prevBufferLen = 0 is very important
1178 // for example, when upgrading, upgrade packet is sent over,
1179 // and a nonzero prevBufferLen could cause problems on `drain`
1180 this.prevBufferLen = 0;
1181
1182 if (this.writeBuffer.length == 0) {
1183 this.emit('drain');
f8e5fb60 1184 } else {
a74c0f0c 1185 this.flush();
f8e5fb60 1186 }
f8e5fb60 1187};
d99e7823
D
1188
1189/**
a74c0f0c 1190 * Flush write buffers.
d99e7823 1191 *
d99e7823
D
1192 * @api private
1193 */
1194
a74c0f0c
D
1195Socket.prototype.flush = function () {
1196 if ('closed' != this.readyState && this.transport.writable &&
1197 !this.upgrading && this.writeBuffer.length) {
1198 debug('flushing %d packets in socket', this.writeBuffer.length);
1199 this.transport.send(this.writeBuffer);
1200 // keep track of current length of writeBuffer
1201 // splice writeBuffer and callbackBuffer on `drain`
1202 this.prevBufferLen = this.writeBuffer.length;
1203 this.emit('flush');
1204 }
1205};
d99e7823
D
1206
1207/**
a74c0f0c 1208 * Sends a message.
d99e7823 1209 *
a74c0f0c
D
1210 * @param {String} message.
1211 * @param {Function} callback function.
1212 * @return {Socket} for chaining.
1213 * @api public
d99e7823
D
1214 */
1215
a74c0f0c
D
1216Socket.prototype.write =
1217Socket.prototype.send = function (msg, fn) {
1218 this.sendPacket('message', msg, fn);
1219 return this;
1220};
f8e5fb60
JA
1221
1222/**
a74c0f0c
D
1223 * Sends a packet.
1224 *
1225 * @param {String} packet type.
1226 * @param {String} data.
1227 * @param {Function} callback function.
1228 * @api private
f8e5fb60
JA
1229 */
1230
a74c0f0c
D
1231Socket.prototype.sendPacket = function (type, data, fn) {
1232 var packet = { type: type, data: data };
1233 this.emit('packetCreate', packet);
1234 this.writeBuffer.push(packet);
1235 this.callbackBuffer.push(fn);
1236 this.flush();
1237};
d99e7823
D
1238
1239/**
a74c0f0c
D
1240 * Closes the connection.
1241 *
1242 * @api private
d99e7823
D
1243 */
1244
a74c0f0c
D
1245Socket.prototype.close = function () {
1246 if ('opening' == this.readyState || 'open' == this.readyState) {
1247 this.onClose('forced close');
1248 debug('socket closing - telling transport to close');
1249 this.transport.close();
1250 }
1251
1252 return this;
1253};
d99e7823 1254
f8e5fb60 1255/**
a74c0f0c
D
1256 * Called upon transport error
1257 *
1258 * @api private
f8e5fb60
JA
1259 */
1260
a74c0f0c
D
1261Socket.prototype.onError = function (err) {
1262 debug('socket error %j', err);
1263 this.emit('error', err);
1264 this.onerror && this.onerror.call(this, err);
1265 this.onClose('transport error', err);
1266};
d99e7823
D
1267
1268/**
a74c0f0c 1269 * Called upon transport close.
d99e7823 1270 *
d99e7823
D
1271 * @api private
1272 */
1273
a74c0f0c
D
1274Socket.prototype.onClose = function (reason, desc) {
1275 if ('opening' == this.readyState || 'open' == this.readyState) {
1276 debug('socket close with reason: "%s"', reason);
1277 var self = this;
f8e5fb60 1278
a74c0f0c
D
1279 // clear timers
1280 clearTimeout(this.pingIntervalTimer);
1281 clearTimeout(this.pingTimeoutTimer);
f8e5fb60 1282
a74c0f0c
D
1283 // clean buffers in next tick, so developers can still
1284 // grab the buffers on `close` event
1285 setTimeout(function() {
1286 self.writeBuffer = [];
1287 self.callbackBuffer = [];
1288 }, 0);
1289
1290 // ignore further transport communication
1291 this.transport.removeAllListeners();
f8e5fb60 1292
a74c0f0c
D
1293 // set ready state
1294 var prev = this.readyState;
1295 this.readyState = 'closed';
f8e5fb60 1296
a74c0f0c
D
1297 // clear session id
1298 this.id = null;
f8e5fb60 1299
a74c0f0c
D
1300 // emit events
1301 if (prev == 'open') {
1302 this.emit('close', reason, desc);
1303 this.onclose && this.onclose.call(this);
1304 }
d99e7823
D
1305 }
1306};
1307
1308/**
a74c0f0c
D
1309 * Filters upgrades, returning only those matching client transports.
1310 *
1311 * @param {Array} server upgrades
1312 * @api private
1313 *
d99e7823
D
1314 */
1315
a74c0f0c
D
1316Socket.prototype.filterUpgrades = function (upgrades) {
1317 var filteredUpgrades = [];
1318 for (var i = 0, j = upgrades.length; i<j; i++) {
1319 if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]);
1320 }
1321 return filteredUpgrades;
1322};
d99e7823 1323
a74c0f0c
D
1324});
1325require.register("engine.io/lib/transport.js", function(exports, require, module){
d99e7823
D
1326
1327/**
a74c0f0c 1328 * Module dependencies.
d99e7823
D
1329 */
1330
a74c0f0c
D
1331var util = require('./util')
1332 , parser = require('engine.io-parser')
1333 , Emitter = require('./emitter');
d99e7823
D
1334
1335/**
a74c0f0c 1336 * Module exports.
d99e7823
D
1337 */
1338
a74c0f0c 1339module.exports = Transport;
d99e7823
D
1340
1341/**
a74c0f0c
D
1342 * Transport abstract constructor.
1343 *
1344 * @param {Object} options.
1345 * @api private
d99e7823
D
1346 */
1347
a74c0f0c
D
1348function Transport (opts) {
1349 this.path = opts.path;
1350 this.hostname = opts.hostname;
1351 this.port = opts.port;
1352 this.secure = opts.secure;
1353 this.query = opts.query;
1354 this.timestampParam = opts.timestampParam;
1355 this.timestampRequests = opts.timestampRequests;
1356 this.readyState = '';
1357};
d99e7823
D
1358
1359/**
a74c0f0c 1360 * Mix in `Emitter`.
d99e7823
D
1361 */
1362
a74c0f0c 1363Emitter(Transport.prototype);
d99e7823
D
1364
1365/**
a74c0f0c
D
1366 * Emits an error.
1367 *
1368 * @param {String} str
1369 * @return {Transport} for chaining
1370 * @api public
d99e7823
D
1371 */
1372
a74c0f0c
D
1373Transport.prototype.onError = function (msg, desc) {
1374 var err = new Error(msg);
1375 err.type = 'TransportError';
1376 err.description = desc;
1377 this.emit('error', err);
1378 return this;
1379};
d99e7823
D
1380
1381/**
a74c0f0c 1382 * Opens the transport.
d99e7823
D
1383 *
1384 * @api public
1385 */
1386
a74c0f0c
D
1387Transport.prototype.open = function () {
1388 if ('closed' == this.readyState || '' == this.readyState) {
1389 this.readyState = 'opening';
1390 this.doOpen();
f8e5fb60 1391 }
d99e7823 1392
a74c0f0c
D
1393 return this;
1394};
d99e7823
D
1395
1396/**
a74c0f0c 1397 * Closes the transport.
d99e7823
D
1398 *
1399 * @api private
1400 */
1401
a74c0f0c
D
1402Transport.prototype.close = function () {
1403 if ('opening' == this.readyState || 'open' == this.readyState) {
1404 this.doClose();
1405 this.onClose();
f8e5fb60
JA
1406 }
1407
a74c0f0c 1408 return this;
d99e7823
D
1409};
1410
1411/**
a74c0f0c 1412 * Sends multiple packets.
d99e7823 1413 *
a74c0f0c 1414 * @param {Array} packets
d99e7823
D
1415 * @api private
1416 */
1417
a74c0f0c
D
1418Transport.prototype.send = function(packets){
1419 if ('open' == this.readyState) {
1420 this.write(packets);
1421 } else {
1422 throw new Error('Transport not open');
f8e5fb60 1423 }
d99e7823
D
1424};
1425
1426/**
a74c0f0c 1427 * Called upon open
f8e5fb60 1428 *
f8e5fb60 1429 * @api private
d99e7823
D
1430 */
1431
a74c0f0c
D
1432Transport.prototype.onOpen = function () {
1433 this.readyState = 'open';
1434 this.writable = true;
1435 this.emit('open');
1436};
f8e5fb60 1437
a74c0f0c
D
1438/**
1439 * Called with data.
1440 *
1441 * @param {String} data
1442 * @api private
1443 */
f8e5fb60 1444
a74c0f0c
D
1445Transport.prototype.onData = function (data) {
1446 this.onPacket(parser.decodePacket(data));
1447};
f8e5fb60 1448
a74c0f0c
D
1449/**
1450 * Called with a decoded packet.
1451 */
f8e5fb60 1452
a74c0f0c
D
1453Transport.prototype.onPacket = function (packet) {
1454 this.emit('packet', packet);
1455};
f8e5fb60 1456
a74c0f0c
D
1457/**
1458 * Called upon close.
1459 *
1460 * @api private
1461 */
f8e5fb60 1462
a74c0f0c
D
1463Transport.prototype.onClose = function () {
1464 this.readyState = 'closed';
1465 this.emit('close');
d99e7823
D
1466};
1467
a74c0f0c
D
1468});
1469require.register("engine.io/lib/emitter.js", function(exports, require, module){
1470
d99e7823 1471/**
a74c0f0c 1472 * Module dependencies.
d99e7823
D
1473 */
1474
a74c0f0c 1475var Emitter = require('emitter');
d99e7823
D
1476
1477/**
f8e5fb60 1478 * Module exports.
d99e7823
D
1479 */
1480
a74c0f0c 1481module.exports = Emitter;
d99e7823
D
1482
1483/**
a74c0f0c
D
1484 * Compatibility with `WebSocket#addEventListener`.
1485 *
1486 * @api public
d99e7823
D
1487 */
1488
a74c0f0c 1489Emitter.prototype.addEventListener = Emitter.prototype.on;
d99e7823
D
1490
1491/**
a74c0f0c
D
1492 * Compatibility with `WebSocket#removeEventListener`.
1493 *
1494 * @api public
d99e7823
D
1495 */
1496
a74c0f0c 1497Emitter.prototype.removeEventListener = Emitter.prototype.off;
d99e7823
D
1498
1499/**
a74c0f0c
D
1500 * Node-compatible `EventEmitter#removeListener`
1501 *
1502 * @api public
d99e7823
D
1503 */
1504
a74c0f0c
D
1505Emitter.prototype.removeListener = Emitter.prototype.off;
1506
1507});
1508require.register("engine.io/lib/util.js", function(exports, require, module){
1509/**
1510 * Status of page load.
1511 */
1512
1513var pageLoaded = false;
d99e7823 1514
f8e5fb60 1515/**
a74c0f0c 1516 * Returns the global object
f8e5fb60 1517 *
a74c0f0c 1518 * @api private
f8e5fb60 1519 */
d99e7823 1520
a74c0f0c
D
1521exports.global = function () {
1522 return 'undefined' != typeof window ? window : global;
1523};
d99e7823 1524
a74c0f0c
D
1525/**
1526 * Inheritance.
1527 *
1528 * @param {Function} ctor a
1529 * @param {Function} ctor b
1530 * @api private
1531 */
d99e7823 1532
a74c0f0c
D
1533exports.inherits = function inherits (a, b) {
1534 function c () { }
1535 c.prototype = b.prototype;
1536 a.prototype = new c;
1537};
d99e7823 1538
a74c0f0c
D
1539/**
1540 * Object.keys
1541 */
1542
1543exports.keys = Object.keys || function (obj) {
1544 var ret = [];
1545 var has = Object.prototype.hasOwnProperty;
1546
1547 for (var i in obj) {
1548 if (has.call(obj, i)) {
1549 ret.push(i);
1550 }
d99e7823 1551 }
a74c0f0c
D
1552
1553 return ret;
1554};
d99e7823
D
1555
1556/**
a74c0f0c
D
1557 * Adds an event.
1558 *
1559 * @api private
d99e7823
D
1560 */
1561
a74c0f0c
D
1562exports.on = function (element, event, fn, capture) {
1563 if (element.attachEvent) {
1564 element.attachEvent('on' + event, fn);
1565 } else if (element.addEventListener) {
1566 element.addEventListener(event, fn, capture);
1567 }
1568};
d99e7823
D
1569
1570/**
a74c0f0c 1571 * Load utility.
d99e7823
D
1572 *
1573 * @api private
1574 */
1575
a74c0f0c
D
1576exports.load = function (fn) {
1577 var global = exports.global();
1578 if (global.document && document.readyState === 'complete' || pageLoaded) {
1579 return fn();
1580 }
1581
1582 exports.on(global, 'load', fn, false);
f8e5fb60 1583};
d99e7823
D
1584
1585/**
a74c0f0c
D
1586 * Change the internal pageLoaded value.
1587 */
1588
1589if ('undefined' != typeof window) {
1590 exports.load(function () {
1591 pageLoaded = true;
1592 });
1593}
1594
1595/**
1596 * Defers a function to ensure a spinner is not displayed by the browser.
d99e7823 1597 *
a74c0f0c 1598 * @param {Function} fn
d99e7823
D
1599 * @api private
1600 */
1601
a74c0f0c
D
1602exports.defer = function (fn) {
1603 if (!exports.ua.webkit || 'undefined' != typeof importScripts) {
1604 return fn();
1605 }
1606
1607 exports.load(function () {
1608 setTimeout(fn, 100);
f8e5fb60 1609 });
f8e5fb60 1610};
d99e7823
D
1611
1612/**
a74c0f0c 1613 * JSON parse.
d99e7823 1614 *
a74c0f0c 1615 * @see Based on jQuery#parseJSON (MIT) and JSON2
d99e7823
D
1616 * @api private
1617 */
1618
a74c0f0c
D
1619var rvalidchars = /^[\],:{}\s]*$/;
1620var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
1621var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
1622var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
1623var rtrimLeft = /^\s+/;
1624var rtrimRight = /\s+$/;
1625
1626exports.parseJSON = function (data) {
1627 var global = exports.global();
1628
1629 if ('string' != typeof data || !data) {
1630 return null;
1631 }
1632
1633 data = data.replace(rtrimLeft, '').replace(rtrimRight, '');
1634
1635 // Attempt to parse using the native JSON parser first
1636 if (global.JSON && JSON.parse) {
1637 return JSON.parse(data);
1638 }
1639
1640 if (rvalidchars.test(data.replace(rvalidescape, '@')
1641 .replace(rvalidtokens, ']')
1642 .replace(rvalidbraces, ''))) {
1643 return (new Function('return ' + data))();
1644 }
f8e5fb60 1645};
d99e7823
D
1646
1647/**
a74c0f0c 1648 * UA / engines detection namespace.
f8e5fb60 1649 *
a74c0f0c 1650 * @namespace
d99e7823
D
1651 */
1652
a74c0f0c 1653exports.ua = {};
d99e7823
D
1654
1655/**
a74c0f0c
D
1656 * Whether the UA supports CORS for XHR.
1657 *
1658 * @api private
d99e7823
D
1659 */
1660
a74c0f0c
D
1661exports.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
1662 var a;
1663 try {
1664 a = new XMLHttpRequest();
1665 } catch (e) {
1666 return false;
1667 }
1668
1669 return a.withCredentials != undefined;
1670})();
d99e7823
D
1671
1672/**
a74c0f0c 1673 * Detect webkit.
d99e7823 1674 *
d99e7823
D
1675 * @api private
1676 */
1677
a74c0f0c
D
1678exports.ua.webkit = 'undefined' != typeof navigator &&
1679 /webkit/i.test(navigator.userAgent);
d99e7823 1680
a74c0f0c
D
1681/**
1682 * Detect gecko.
1683 *
1684 * @api private
1685 */
d99e7823 1686
a74c0f0c
D
1687exports.ua.gecko = 'undefined' != typeof navigator &&
1688 /gecko/i.test(navigator.userAgent);
d99e7823 1689
a74c0f0c
D
1690/**
1691 * Detect android;
1692 */
d99e7823 1693
a74c0f0c
D
1694exports.ua.android = 'undefined' != typeof navigator &&
1695 /android/i.test(navigator.userAgent);
d99e7823 1696
a74c0f0c
D
1697/**
1698 * Detect iOS.
1699 */
d99e7823 1700
a74c0f0c
D
1701exports.ua.ios = 'undefined' != typeof navigator &&
1702 /^(iPad|iPhone|iPod)$/.test(navigator.platform);
1703exports.ua.ios6 = exports.ua.ios && /OS 6_/.test(navigator.userAgent);
d99e7823 1704
a74c0f0c
D
1705/**
1706 * XHR request helper.
1707 *
1708 * @param {Boolean} whether we need xdomain
1709 * @api private
1710 */
1711
1712exports.request = function request (xdomain) {
1713 try {
1714 var _XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
1715 return new _XMLHttpRequest();
1716 } catch (e) {}
1717
1718 if (xdomain && 'undefined' != typeof XDomainRequest && !exports.ua.hasCORS) {
1719 return new XDomainRequest();
d99e7823 1720 }
f8e5fb60 1721
a74c0f0c
D
1722 // XMLHttpRequest can be disabled on IE
1723 try {
1724 if ('undefined' != typeof XMLHttpRequest && (!xdomain || exports.ua.hasCORS)) {
1725 return new XMLHttpRequest();
1726 }
1727 } catch (e) { }
1728
1729 if (!xdomain) {
1730 try {
1731 return new ActiveXObject('Microsoft.XMLHTTP');
1732 } catch(e) { }
d99e7823 1733 }
d99e7823
D
1734};
1735
d99e7823 1736/**
a74c0f0c 1737 * Parses an URI
f8e5fb60 1738 *
a74c0f0c 1739 * @author Steven Levithan <stevenlevithan.com> (MIT license)
f8e5fb60 1740 * @api private
d99e7823
D
1741 */
1742
a74c0f0c
D
1743var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
1744
1745var parts = [
1746 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host'
1747 , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
1748];
1749
1750exports.parseUri = function (str) {
1751 var m = re.exec(str || '')
1752 , uri = {}
1753 , i = 14;
1754
1755 while (i--) {
1756 uri[parts[i]] = m[i] || '';
1757 }
1758
1759 return uri;
f8e5fb60 1760};
d99e7823
D
1761
1762/**
a74c0f0c 1763 * Compiles a querystring
f8e5fb60 1764 *
a74c0f0c 1765 * @param {Object}
f8e5fb60 1766 * @api private
d99e7823
D
1767 */
1768
a74c0f0c
D
1769exports.qs = function (obj) {
1770 var str = '';
1771
1772 for (var i in obj) {
1773 if (obj.hasOwnProperty(i)) {
1774 if (str.length) str += '&';
1775 str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
1776 }
1777 }
1778
1779 return str;
f8e5fb60 1780};
d99e7823
D
1781
1782/**
a74c0f0c 1783 * Parses a simple querystring.
f8e5fb60 1784 *
a74c0f0c 1785 * @param {String} qs
f8e5fb60 1786 * @api private
d99e7823
D
1787 */
1788
a74c0f0c
D
1789exports.qsParse = function(qs){
1790 var qry = {};
1791 var pairs = qs.split('&');
1792 for (var i = 0, l = pairs.length; i < l; i++) {
1793 var pair = pairs[i].split('=');
1794 qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
1795 }
1796 return qry;
f8e5fb60 1797};
d99e7823 1798
a74c0f0c
D
1799});
1800require.register("engine.io/lib/transports/index.js", function(exports, require, module){
1801
d99e7823 1802/**
a74c0f0c 1803 * Module dependencies
d99e7823
D
1804 */
1805
a74c0f0c
D
1806var XHR = require('./polling-xhr')
1807 , JSONP = require('./polling-jsonp')
1808 , websocket = require('./websocket')
1809 , flashsocket = require('./flashsocket')
1810 , util = require('../util');
d99e7823 1811
a74c0f0c
D
1812/**
1813 * Export transports.
1814 */
d99e7823 1815
a74c0f0c
D
1816exports.polling = polling;
1817exports.websocket = websocket;
1818exports.flashsocket = flashsocket;
d99e7823 1819
f8e5fb60 1820/**
a74c0f0c 1821 * Global reference.
f8e5fb60
JA
1822 */
1823
a74c0f0c 1824var global = util.global()
d99e7823 1825
f8e5fb60 1826/**
a74c0f0c
D
1827 * Polling transport polymorphic constructor.
1828 * Decides on xhr vs jsonp based on feature detection.
1829 *
1830 * @api private
f8e5fb60
JA
1831 */
1832
a74c0f0c
D
1833function polling (opts) {
1834 var xhr
1835 , xd = false
1836 , isXProtocol = false;
f8e5fb60 1837
a74c0f0c
D
1838 if (global.location) {
1839 var isSSL = 'https:' == location.protocol;
1840 var port = location.port;
1841
1842 // some user agents have empty `location.port`
1843 if (Number(port) !== port) {
1844 port = isSSL ? 443 : 80;
f8e5fb60 1845 }
f8e5fb60 1846
a74c0f0c
D
1847 xd = opts.hostname != location.hostname || port != opts.port;
1848 isXProtocol = opts.secure != isSSL;
1849 }
1850
1851 xhr = util.request(xd);
1852 /* See #7 at http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx */
1853 if (isXProtocol && global.XDomainRequest && xhr instanceof global.XDomainRequest) {
1854 return new JSONP(opts);
1855 }
1856
1857 if (xhr && !opts.forceJSONP) {
1858 return new XHR(opts);
1859 } else {
1860 return new JSONP(opts);
1861 }
1862};
1863
1864});
1865require.register("engine.io/lib/transports/polling.js", function(exports, require, module){
d99e7823
D
1866/**
1867 * Module dependencies.
1868 */
1869
a74c0f0c
D
1870var Transport = require('../transport')
1871 , util = require('../util')
1872 , parser = require('engine.io-parser')
1873 , debug = require('debug')('engine.io-client:polling');
d99e7823
D
1874
1875/**
1876 * Module exports.
1877 */
1878
1879module.exports = Polling;
1880
1881/**
1882 * Global reference.
1883 */
1884
a74c0f0c 1885var global = util.global();
d99e7823
D
1886
1887/**
1888 * Polling interface.
1889 *
1890 * @param {Object} opts
1891 * @api private
1892 */
1893
1894function Polling(opts){
1895 Transport.call(this, opts);
1896}
1897
1898/**
1899 * Inherits from Transport.
1900 */
1901
1902util.inherits(Polling, Transport);
1903
1904/**
1905 * Transport name.
1906 */
1907
1908Polling.prototype.name = 'polling';
1909
1910/**
1911 * Opens the socket (triggers polling). We write a PING message to determine
1912 * when the transport is open.
1913 *
1914 * @api private
1915 */
1916
1917Polling.prototype.doOpen = function(){
1918 this.poll();
1919};
1920
1921/**
1922 * Pauses polling.
1923 *
1924 * @param {Function} callback upon buffers are flushed and transport is paused
1925 * @api private
1926 */
1927
1928Polling.prototype.pause = function(onPause){
1929 var pending = 0;
1930 var self = this;
1931
1932 this.readyState = 'pausing';
1933
1934 function pause(){
1935 debug('paused');
1936 self.readyState = 'paused';
1937 onPause();
1938 }
1939
1940 if (this.polling || !this.writable) {
1941 var total = 0;
1942
1943 if (this.polling) {
1944 debug('we are currently polling - waiting to pause');
1945 total++;
1946 this.once('pollComplete', function(){
1947 debug('pre-pause polling complete');
1948 --total || pause();
1949 });
1950 }
1951
1952 if (!this.writable) {
1953 debug('we are currently writing - waiting to pause');
1954 total++;
1955 this.once('drain', function(){
1956 debug('pre-pause writing complete');
1957 --total || pause();
1958 });
1959 }
1960 } else {
1961 pause();
1962 }
1963};
1964
1965/**
1966 * Starts polling cycle.
1967 *
1968 * @api public
1969 */
1970
1971Polling.prototype.poll = function(){
1972 debug('polling');
1973 this.polling = true;
1974 this.doPoll();
1975 this.emit('poll');
1976};
1977
1978/**
1979 * Overloads onData to detect payloads.
1980 *
1981 * @api private
1982 */
1983
1984Polling.prototype.onData = function(data){
1985 var self = this;
1986 debug('polling got data %s', data);
1987
1988 // decode payload
1989 parser.decodePayload(data, function(packet, index, total) {
1990 // if its the first message we consider the transport open
1991 if ('opening' == self.readyState) {
1992 self.onOpen();
1993 }
1994
1995 // if its a close packet, we close the ongoing requests
1996 if ('close' == packet.type) {
1997 self.onClose();
1998 return false;
1999 }
2000
2001 // otherwise bypass onData and handle the message
2002 self.onPacket(packet);
2003 });
2004
2005 // if an event did not trigger closing
2006 if ('closed' != this.readyState) {
2007 // if we got data we're not polling
2008 this.polling = false;
2009 this.emit('pollComplete');
2010
2011 if ('open' == this.readyState) {
2012 this.poll();
2013 } else {
2014 debug('ignoring poll - transport state "%s"', this.readyState);
2015 }
2016 }
2017};
2018
2019/**
2020 * For polling, send a close packet.
2021 *
2022 * @api private
2023 */
2024
2025Polling.prototype.doClose = function(){
2026 var self = this;
2027
2028 function close(){
2029 debug('writing close packet');
2030 self.write([{ type: 'close' }]);
2031 }
2032
a74c0f0c 2033 if (this.open) {
d99e7823
D
2034 debug('transport open - closing');
2035 close();
2036 } else {
2037 // in case we're trying to close while
2038 // handshaking is in progress (GH-164)
a74c0f0c 2039 debug('transport not open - defering close');
d99e7823
D
2040 this.once('open', close);
2041 }
2042};
2043
2044/**
2045 * Writes a packets payload.
2046 *
2047 * @param {Array} data packets
2048 * @param {Function} drain callback
2049 * @api private
2050 */
2051
2052Polling.prototype.write = function(packets){
2053 var self = this;
2054 this.writable = false;
2055 this.doWrite(parser.encodePayload(packets), function(){
2056 self.writable = true;
2057 self.emit('drain');
2058 });
2059};
2060
2061/**
2062 * Generates uri for connection.
2063 *
2064 * @api private
2065 */
2066
2067Polling.prototype.uri = function(){
2068 var query = this.query || {};
2069 var schema = this.secure ? 'https' : 'http';
2070 var port = '';
2071
2072 // cache busting is forced for IE / android / iOS6 ಠ_ಠ
a74c0f0c
D
2073 if (global.ActiveXObject || util.ua.android || util.ua.ios6 ||
2074 this.timestampRequests) {
2075 query[this.timestampParam] = +new Date;
d99e7823
D
2076 }
2077
2078 query = util.qs(query);
2079
2080 // avoid port if default for schema
2081 if (this.port && (('https' == schema && this.port != 443) ||
2082 ('http' == schema && this.port != 80))) {
2083 port = ':' + this.port;
2084 }
2085
2086 // prepend ? to query
2087 if (query.length) {
2088 query = '?' + query;
2089 }
2090
2091 return schema + '://' + this.hostname + port + this.path + query;
2092};
2093
a74c0f0c
D
2094});
2095require.register("engine.io/lib/transports/polling-xhr.js", function(exports, require, module){
d99e7823 2096/**
a74c0f0c 2097 * Module requirements.
d99e7823
D
2098 */
2099
a74c0f0c
D
2100var Polling = require('./polling')
2101 , util = require('../util')
2102 , Emitter = require('../emitter')
2103 , debug = require('debug')('engine.io-client:polling-xhr');
d99e7823
D
2104
2105/**
f8e5fb60 2106 * Module exports.
d99e7823
D
2107 */
2108
a74c0f0c
D
2109module.exports = XHR;
2110module.exports.Request = Request;
d99e7823
D
2111
2112/**
f8e5fb60 2113 * Global reference.
d99e7823
D
2114 */
2115
a74c0f0c
D
2116var global = util.global();
2117
d99e7823
D
2118
2119/**
a74c0f0c 2120 * Obfuscated key for Blue Coat.
d99e7823
D
2121 */
2122
a74c0f0c 2123var xobject = global[['Active'].concat('Object').join('X')];
d99e7823
D
2124
2125/**
a74c0f0c 2126 * Empty function
d99e7823
D
2127 */
2128
a74c0f0c 2129function empty(){}
d99e7823
D
2130
2131/**
a74c0f0c 2132 * XHR Polling constructor.
d99e7823 2133 *
a74c0f0c 2134 * @param {Object} opts
f8e5fb60 2135 * @api public
d99e7823
D
2136 */
2137
a74c0f0c
D
2138function XHR(opts){
2139 Polling.call(this, opts);
2140
2141 if (global.location) {
2142 var isSSL = 'https:' == location.protocol;
2143 var port = location.port;
2144
2145 // some user agents have empty `location.port`
2146 if (Number(port) !== port) {
2147 port = isSSL ? 443 : 80;
2148 }
2149
2150 this.xd = opts.hostname != global.location.hostname ||
2151 port != opts.port;
2152 }
2153};
d99e7823
D
2154
2155/**
a74c0f0c
D
2156 * Inherits from Polling.
2157 */
2158
2159util.inherits(XHR, Polling);
2160
2161/**
2162 * Opens the socket
d99e7823 2163 *
d99e7823
D
2164 * @api private
2165 */
2166
a74c0f0c 2167XHR.prototype.doOpen = function(){
d99e7823 2168 var self = this;
a74c0f0c
D
2169 util.defer(function(){
2170 Polling.prototype.doOpen.call(self);
2171 });
d99e7823
D
2172};
2173
2174/**
a74c0f0c 2175 * Creates a request.
d99e7823 2176 *
a74c0f0c 2177 * @param {String} method
f8e5fb60
JA
2178 * @api private
2179 */
d99e7823 2180
a74c0f0c
D
2181XHR.prototype.request = function(opts){
2182 opts = opts || {};
2183 opts.uri = this.uri();
2184 opts.xd = this.xd;
2185 return new Request(opts);
d99e7823
D
2186};
2187
2188/**
a74c0f0c 2189 * Sends data.
d99e7823 2190 *
a74c0f0c
D
2191 * @param {String} data to send.
2192 * @param {Function} called upon flush.
d99e7823
D
2193 * @api private
2194 */
2195
a74c0f0c
D
2196XHR.prototype.doWrite = function(data, fn){
2197 var req = this.request({ method: 'POST', data: data });
2198 var self = this;
2199 req.on('success', fn);
2200 req.on('error', function(err){
2201 self.onError('xhr post error', err);
2202 });
2203 this.sendXhr = req;
2204};
f8e5fb60
JA
2205
2206/**
a74c0f0c 2207 * Starts a poll cycle.
f8e5fb60 2208 *
f8e5fb60
JA
2209 * @api private
2210 */
2211
a74c0f0c
D
2212XHR.prototype.doPoll = function(){
2213 debug('xhr poll');
2214 var req = this.request();
f8e5fb60 2215 var self = this;
a74c0f0c
D
2216 req.on('data', function(data){
2217 self.onData(data);
2218 });
2219 req.on('error', function(err){
2220 self.onError('xhr poll error', err);
2221 });
2222 this.pollXhr = req;
d99e7823
D
2223};
2224
2225/**
a74c0f0c 2226 * Request constructor
d99e7823 2227 *
a74c0f0c
D
2228 * @param {Object} options
2229 * @api public
d99e7823
D
2230 */
2231
a74c0f0c
D
2232function Request(opts){
2233 this.method = opts.method || 'GET';
2234 this.uri = opts.uri;
2235 this.xd = !!opts.xd;
2236 this.async = false !== opts.async;
2237 this.data = undefined != opts.data ? opts.data : null;
2238 this.create();
2239}
d99e7823
D
2240
2241/**
a74c0f0c 2242 * Mix in `Emitter`.
d99e7823
D
2243 */
2244
a74c0f0c 2245Emitter(Request.prototype);
d99e7823
D
2246
2247/**
a74c0f0c 2248 * Creates the XHR object and sends the request.
d99e7823
D
2249 *
2250 * @api private
2251 */
2252
a74c0f0c
D
2253Request.prototype.create = function(){
2254 var xhr = this.xhr = util.request(this.xd);
2255 var self = this;
f8e5fb60 2256
a74c0f0c 2257 xhr.open(this.method, this.uri, this.async);
d99e7823 2258
a74c0f0c
D
2259 if ('POST' == this.method) {
2260 try {
2261 if (xhr.setRequestHeader) {
2262 // xmlhttprequest
2263 xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
2264 } else {
2265 // xdomainrequest
2266 xhr.contentType = 'text/plain';
2267 }
2268 } catch (e) {}
f8e5fb60 2269 }
d99e7823 2270
a74c0f0c
D
2271 if (this.xd && global.XDomainRequest && xhr instanceof XDomainRequest) {
2272 xhr.onerror = function(e){
2273 self.onError(e);
2274 };
2275 xhr.onload = function(){
2276 self.onData(xhr.responseText);
2277 };
2278 xhr.onprogress = empty;
2279 } else {
2280 // ie6 check
2281 if ('withCredentials' in xhr) {
2282 xhr.withCredentials = true;
2283 }
d99e7823 2284
a74c0f0c
D
2285 xhr.onreadystatechange = function(){
2286 var data;
2287
2288 try {
2289 if (4 != xhr.readyState) return;
2290 if (200 == xhr.status || 1223 == xhr.status) {
2291 data = xhr.responseText;
2292 } else {
2293 self.onError(xhr.status);
2294 }
2295 } catch (e) {
2296 self.onError(e);
2297 }
2298
2299 if (undefined !== data) {
2300 self.onData(data);
2301 }
2302 };
d99e7823
D
2303 }
2304
a74c0f0c
D
2305 debug('sending xhr with url %s | data %s', this.uri, this.data);
2306 xhr.send(this.data);
2307
2308 if (xobject) {
2309 this.index = Request.requestsCount++;
2310 Request.requests[this.index] = this;
2311 }
d99e7823
D
2312};
2313
2314/**
a74c0f0c 2315 * Called upon successful response.
d99e7823 2316 *
a74c0f0c 2317 * @api private
d99e7823
D
2318 */
2319
a74c0f0c
D
2320Request.prototype.onSuccess = function(){
2321 this.emit('success');
2322 this.cleanup();
d99e7823
D
2323};
2324
f8e5fb60 2325/**
a74c0f0c
D
2326 * Called if we have data.
2327 *
2328 * @api private
f8e5fb60
JA
2329 */
2330
a74c0f0c
D
2331Request.prototype.onData = function(data){
2332 this.emit('data', data);
2333 this.onSuccess();
2334};
d99e7823
D
2335
2336/**
a74c0f0c 2337 * Called upon error.
f8e5fb60 2338 *
f8e5fb60 2339 * @api private
d99e7823
D
2340 */
2341
a74c0f0c
D
2342Request.prototype.onError = function(err){
2343 this.emit('error', err);
2344 this.cleanup();
f8e5fb60 2345};
d99e7823
D
2346
2347/**
a74c0f0c
D
2348 * Cleans up house.
2349 *
2350 * @api private
d99e7823
D
2351 */
2352
a74c0f0c
D
2353Request.prototype.cleanup = function(){
2354 if ('undefined' == typeof this.xhr ) {
2355 return;
f8e5fb60 2356 }
a74c0f0c
D
2357 // xmlhttprequest
2358 this.xhr.onreadystatechange = empty;
f8e5fb60 2359
a74c0f0c
D
2360 // xdomainrequest
2361 this.xhr.onload = this.xhr.onerror = empty;
d99e7823 2362
a74c0f0c
D
2363 try {
2364 this.xhr.abort();
2365 } catch(e) {}
d99e7823 2366
a74c0f0c
D
2367 if (xobject) {
2368 delete Request.requests[this.index];
f8e5fb60 2369 }
a74c0f0c
D
2370
2371 this.xhr = null;
f8e5fb60 2372};
d99e7823
D
2373
2374/**
a74c0f0c 2375 * Aborts the request.
f8e5fb60 2376 *
a74c0f0c 2377 * @api public
d99e7823
D
2378 */
2379
a74c0f0c
D
2380Request.prototype.abort = function(){
2381 this.cleanup();
f8e5fb60 2382};
d99e7823 2383
a74c0f0c
D
2384if (xobject) {
2385 Request.requestsCount = 0;
2386 Request.requests = {};
d99e7823 2387
a74c0f0c
D
2388 global.attachEvent('onunload', function(){
2389 for (var i in Request.requests) {
2390 if (Request.requests.hasOwnProperty(i)) {
2391 Request.requests[i].abort();
2392 }
2393 }
f8e5fb60
JA
2394 });
2395}
d99e7823 2396
a74c0f0c
D
2397});
2398require.register("engine.io/lib/transports/polling-jsonp.js", function(exports, require, module){
2399
d99e7823 2400/**
a74c0f0c 2401 * Module requirements.
d99e7823
D
2402 */
2403
a74c0f0c
D
2404var Polling = require('./polling')
2405 , util = require('../util');
f8e5fb60 2406
a74c0f0c
D
2407/**
2408 * Module exports.
2409 */
f8e5fb60 2410
a74c0f0c 2411module.exports = JSONPPolling;
f8e5fb60 2412
a74c0f0c
D
2413/**
2414 * Global reference.
2415 */
f8e5fb60 2416
a74c0f0c 2417var global = util.global();
d99e7823
D
2418
2419/**
a74c0f0c 2420 * Cached regular expressions.
d99e7823
D
2421 */
2422
a74c0f0c 2423var rNewline = /\n/g;
d99e7823
D
2424
2425/**
a74c0f0c 2426 * Global JSONP callbacks.
d99e7823
D
2427 */
2428
a74c0f0c 2429var callbacks;
d99e7823 2430
f8e5fb60 2431/**
a74c0f0c 2432 * Callbacks count.
f8e5fb60 2433 */
d99e7823 2434
a74c0f0c 2435var index = 0;
d99e7823 2436
f8e5fb60 2437/**
a74c0f0c 2438 * Noop.
f8e5fb60
JA
2439 */
2440
a74c0f0c 2441function empty () { }
f8e5fb60
JA
2442
2443/**
a74c0f0c
D
2444 * JSONP Polling constructor.
2445 *
2446 * @param {Object} opts.
2447 * @api public
f8e5fb60 2448 */
d99e7823 2449
a74c0f0c
D
2450function JSONPPolling (opts) {
2451 Polling.call(this, opts);
2452
2453 // define global callbacks array if not present
2454 // we do this here (lazily) to avoid unneeded global pollution
2455 if (!callbacks) {
2456 // we need to consider multiple engines in the same page
2457 if (!global.___eio) global.___eio = [];
2458 callbacks = global.___eio;
2459 }
2460
2461 // callback identifier
2462 this.index = callbacks.length;
2463
2464 // add callback to jsonp global
2465 var self = this;
2466 callbacks.push(function (msg) {
2467 self.onData(msg);
2468 });
2469
2470 // append to query string
2471 this.query.j = this.index;
2472};
d99e7823
D
2473
2474/**
a74c0f0c 2475 * Inherits from Polling.
d99e7823
D
2476 */
2477
a74c0f0c 2478util.inherits(JSONPPolling, Polling);
d99e7823
D
2479
2480/**
a74c0f0c 2481 * Opens the socket.
d99e7823
D
2482 *
2483 * @api private
2484 */
2485
a74c0f0c
D
2486JSONPPolling.prototype.doOpen = function () {
2487 var self = this;
2488 util.defer(function () {
2489 Polling.prototype.doOpen.call(self);
2490 });
d99e7823
D
2491};
2492
2493/**
a74c0f0c 2494 * Closes the socket
d99e7823
D
2495 *
2496 * @api private
2497 */
2498
a74c0f0c
D
2499JSONPPolling.prototype.doClose = function () {
2500 if (this.script) {
2501 this.script.parentNode.removeChild(this.script);
2502 this.script = null;
2503 }
d99e7823 2504
a74c0f0c
D
2505 if (this.form) {
2506 this.form.parentNode.removeChild(this.form);
2507 this.form = null;
d99e7823
D
2508 }
2509
a74c0f0c 2510 Polling.prototype.doClose.call(this);
d99e7823
D
2511};
2512
2513/**
a74c0f0c 2514 * Starts a poll cycle.
d99e7823
D
2515 *
2516 * @api private
2517 */
2518
a74c0f0c
D
2519JSONPPolling.prototype.doPoll = function () {
2520 var self = this;
2521 var script = document.createElement('script');
2522
2523 if (this.script) {
2524 this.script.parentNode.removeChild(this.script);
2525 this.script = null;
d99e7823
D
2526 }
2527
a74c0f0c
D
2528 script.async = true;
2529 script.src = this.uri();
2530 script.onerror = function(e){
2531 self.onError('jsonp poll error',e);
2532 }
d99e7823 2533
a74c0f0c
D
2534 var insertAt = document.getElementsByTagName('script')[0];
2535 insertAt.parentNode.insertBefore(script, insertAt);
2536 this.script = script;
d99e7823
D
2537
2538
a74c0f0c
D
2539 if (util.ua.gecko) {
2540 setTimeout(function () {
2541 var iframe = document.createElement('iframe');
2542 document.body.appendChild(iframe);
2543 document.body.removeChild(iframe);
2544 }, 100);
d99e7823 2545 }
a74c0f0c 2546};
f8e5fb60
JA
2547
2548/**
a74c0f0c 2549 * Writes with a hidden iframe.
d99e7823 2550 *
a74c0f0c
D
2551 * @param {String} data to send
2552 * @param {Function} called upon flush.
2553 * @api private
d99e7823
D
2554 */
2555
a74c0f0c
D
2556JSONPPolling.prototype.doWrite = function (data, fn) {
2557 var self = this;
d99e7823 2558
a74c0f0c
D
2559 if (!this.form) {
2560 var form = document.createElement('form');
2561 var area = document.createElement('textarea');
2562 var id = this.iframeId = 'eio_iframe_' + this.index;
2563 var iframe;
d99e7823 2564
a74c0f0c
D
2565 form.className = 'socketio';
2566 form.style.position = 'absolute';
2567 form.style.top = '-1000px';
2568 form.style.left = '-1000px';
2569 form.target = id;
2570 form.method = 'POST';
2571 form.setAttribute('accept-charset', 'utf-8');
2572 area.name = 'd';
2573 form.appendChild(area);
2574 document.body.appendChild(form);
f8e5fb60 2575
a74c0f0c
D
2576 this.form = form;
2577 this.area = area;
d99e7823 2578 }
d99e7823 2579
a74c0f0c 2580 this.form.action = this.uri();
d99e7823 2581
a74c0f0c
D
2582 function complete () {
2583 initIframe();
2584 fn();
2585 };
d99e7823 2586
a74c0f0c
D
2587 function initIframe () {
2588 if (self.iframe) {
2589 try {
2590 self.form.removeChild(self.iframe);
2591 } catch (e) {
2592 self.onError('jsonp polling iframe removal error', e);
2593 }
f8e5fb60 2594 }
d99e7823 2595
a74c0f0c
D
2596 try {
2597 // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
2598 var html = '<iframe src="javascript:0" name="'+ self.iframeId +'">';
2599 iframe = document.createElement(html);
2600 } catch (e) {
2601 iframe = document.createElement('iframe');
2602 iframe.name = self.iframeId;
2603 iframe.src = 'javascript:0';
2604 }
d99e7823 2605
a74c0f0c 2606 iframe.id = self.iframeId;
d99e7823 2607
a74c0f0c
D
2608 self.form.appendChild(iframe);
2609 self.iframe = iframe;
2610 };
d99e7823 2611
a74c0f0c 2612 initIframe();
f8e5fb60 2613
a74c0f0c
D
2614 // escape \n to prevent it from being converted into \r\n by some UAs
2615 this.area.value = data.replace(rNewline, '\\n');
d99e7823 2616
a74c0f0c
D
2617 try {
2618 this.form.submit();
2619 } catch(e) {}
d99e7823 2620
a74c0f0c
D
2621 if (this.iframe.attachEvent) {
2622 this.iframe.onreadystatechange = function(){
2623 if (self.iframe.readyState == 'complete') {
2624 complete();
2625 }
2626 };
2627 } else {
2628 this.iframe.onload = complete;
f8e5fb60 2629 }
f8e5fb60 2630};
d99e7823 2631
a74c0f0c
D
2632});
2633require.register("engine.io/lib/transports/websocket.js", function(exports, require, module){
d99e7823 2634/**
a74c0f0c 2635 * Module dependencies.
d99e7823
D
2636 */
2637
a74c0f0c
D
2638var Transport = require('../transport')
2639 , parser = require('engine.io-parser')
2640 , util = require('../util')
2641 , debug = require('debug')('engine.io-client:websocket');
f8e5fb60 2642
a74c0f0c
D
2643/**
2644 * Module exports.
2645 */
d99e7823 2646
a74c0f0c
D
2647module.exports = WS;
2648
2649/**
2650 * Global reference.
2651 */
d99e7823 2652
a74c0f0c 2653var global = util.global();
d99e7823
D
2654
2655/**
a74c0f0c
D
2656 * WebSocket transport constructor.
2657 *
2658 * @api {Object} connection options
2659 * @api public
d99e7823
D
2660 */
2661
a74c0f0c
D
2662function WS(opts){
2663 Transport.call(this, opts);
2664};
d99e7823
D
2665
2666/**
a74c0f0c 2667 * Inherits from Transport.
d99e7823
D
2668 */
2669
a74c0f0c 2670util.inherits(WS, Transport);
d99e7823
D
2671
2672/**
a74c0f0c 2673 * Transport name.
d99e7823
D
2674 *
2675 * @api public
2676 */
2677
a74c0f0c 2678WS.prototype.name = 'websocket';
d99e7823
D
2679
2680/**
a74c0f0c 2681 * Opens socket.
d99e7823
D
2682 *
2683 * @api private
2684 */
2685
a74c0f0c
D
2686WS.prototype.doOpen = function(){
2687 if (!this.check()) {
2688 // let probe timeout
2689 return;
d99e7823 2690 }
a74c0f0c
D
2691
2692 var self = this;
2693
2694 this.socket = new (ws())(this.uri());
2695 this.socket.onopen = function(){
2696 self.onOpen();
2697 };
2698 this.socket.onclose = function(){
2699 self.onClose();
2700 };
2701 this.socket.onmessage = function(ev){
2702 self.onData(ev.data);
2703 };
2704 this.socket.onerror = function(e){
2705 self.onError('websocket error', e);
2706 };
2707};
d99e7823
D
2708
2709/**
a74c0f0c
D
2710 * Override `onData` to use a timer on iOS.
2711 * See: https://gist.github.com/mloughran/2052006
d99e7823 2712 *
a74c0f0c 2713 * @api private
d99e7823
D
2714 */
2715
a74c0f0c
D
2716if ('undefined' != typeof navigator
2717 && /iPad|iPhone|iPod/i.test(navigator.userAgent)) {
2718 WS.prototype.onData = function(data){
2719 var self = this;
2720 setTimeout(function(){
2721 Transport.prototype.onData.call(self, data);
2722 }, 0);
2723 };
2724}
d99e7823
D
2725
2726/**
a74c0f0c 2727 * Writes data to socket.
d99e7823 2728 *
a74c0f0c
D
2729 * @param {Array} array of packets.
2730 * @api private
d99e7823
D
2731 */
2732
a74c0f0c 2733WS.prototype.write = function(packets){
d99e7823 2734 var self = this;
a74c0f0c
D
2735 this.writable = false;
2736 // encodePacket efficient as it uses WS framing
2737 // no need for encodePayload
2738 for (var i = 0, l = packets.length; i < l; i++) {
2739 this.socket.send(parser.encodePacket(packets[i]));
2740 }
2741 function ondrain() {
2742 self.writable = true;
2743 self.emit('drain');
2744 }
2745 // check periodically if we're done sending
2746 if ('bufferedAmount' in this.socket) {
2747 this.bufferedAmountId = setInterval(function() {
2748 if (self.socket.bufferedAmount == 0) {
2749 clearInterval(self.bufferedAmountId);
2750 ondrain();
2751 }
2752 }, 50);
2753 } else {
2754 // fake drain
2755 // defer to next tick to allow Socket to clear writeBuffer
2756 setTimeout(ondrain, 0);
d99e7823
D
2757 }
2758};
2759
2760/**
a74c0f0c 2761 * Called upon close
d99e7823 2762 *
a74c0f0c 2763 * @api private
d99e7823
D
2764 */
2765
a74c0f0c
D
2766WS.prototype.onClose = function(){
2767 // stop checking to see if websocket is done sending buffer
2768 clearInterval(this.bufferedAmountId);
2769 Transport.prototype.onClose.call(this);
2770};
d99e7823 2771
a74c0f0c
D
2772/**
2773 * Closes socket.
2774 *
2775 * @api private
2776 */
f8e5fb60 2777
a74c0f0c
D
2778WS.prototype.doClose = function(){
2779 if (typeof this.socket !== 'undefined') {
2780 this.socket.close();
d99e7823
D
2781 }
2782};
2783
2784/**
a74c0f0c 2785 * Generates uri for connection.
d99e7823 2786 *
a74c0f0c 2787 * @api private
d99e7823
D
2788 */
2789
a74c0f0c
D
2790WS.prototype.uri = function(){
2791 var query = this.query || {};
2792 var schema = this.secure ? 'wss' : 'ws';
2793 var port = '';
d99e7823 2794
a74c0f0c
D
2795 // avoid port if default for schema
2796 if (this.port && (('wss' == schema && this.port != 443)
2797 || ('ws' == schema && this.port != 80))) {
2798 port = ':' + this.port;
d99e7823
D
2799 }
2800
a74c0f0c
D
2801 // append timestamp to URI
2802 if (this.timestampRequests) {
2803 query[this.timestampParam] = +new Date;
2804 }
2805
2806 query = util.qs(query);
2807
2808 // prepend ? to query
2809 if (query.length) {
2810 query = '?' + query;
2811 }
2812
2813 return schema + '://' + this.hostname + port + this.path + query;
d99e7823
D
2814};
2815
2816/**
a74c0f0c 2817 * Feature detection for WebSocket.
d99e7823 2818 *
a74c0f0c 2819 * @return {Boolean} whether this transport is available.
d99e7823
D
2820 * @api public
2821 */
2822
a74c0f0c
D
2823WS.prototype.check = function(){
2824 var websocket = ws();
2825 return !!websocket && !('__initialize' in websocket && this.name === WS.prototype.name);
d99e7823
D
2826};
2827
2828/**
a74c0f0c 2829 * Getter for WS constructor.
d99e7823 2830 *
a74c0f0c 2831 * @api private
d99e7823
D
2832 */
2833
a74c0f0c
D
2834function ws(){
2835 if ('undefined' == typeof window) {
2836 return require('ws');
2837 }
d99e7823 2838
a74c0f0c
D
2839 return global.WebSocket || global.MozWebSocket;
2840}
f8e5fb60 2841
a74c0f0c
D
2842});
2843require.register("engine.io/lib/transports/flashsocket.js", function(exports, require, module){
d99e7823
D
2844/**
2845 * Module dependencies.
2846 */
2847
a74c0f0c
D
2848var WS = require('./websocket')
2849 , util = require('../util')
2850 , debug = require('debug')('engine.io-client:flashsocket');
d99e7823 2851
f8e5fb60 2852/**
a74c0f0c 2853 * Module exports.
f8e5fb60
JA
2854 */
2855
a74c0f0c 2856module.exports = FlashWS;
d99e7823
D
2857
2858/**
a74c0f0c 2859 * Global reference.
d99e7823
D
2860 */
2861
a74c0f0c 2862var global = util.global()
d99e7823
D
2863
2864/**
a74c0f0c 2865 * Obfuscated key for Blue Coat.
d99e7823
D
2866 */
2867
a74c0f0c 2868var xobject = global[['Active'].concat('Object').join('X')];
d99e7823
D
2869
2870/**
a74c0f0c 2871 * FlashWS constructor.
d99e7823 2872 *
a74c0f0c 2873 * @api public
d99e7823
D
2874 */
2875
a74c0f0c
D
2876function FlashWS (options) {
2877 WS.call(this, options);
2878 this.flashPath = options.flashPath;
2879 this.policyPort = options.policyPort;
f8e5fb60 2880};
d99e7823
D
2881
2882/**
a74c0f0c 2883 * Inherits from WebSocket.
d99e7823
D
2884 */
2885
a74c0f0c 2886util.inherits(FlashWS, WS);
f8e5fb60 2887
a74c0f0c
D
2888/**
2889 * Transport name.
2890 *
2891 * @api public
2892 */
f8e5fb60 2893
a74c0f0c 2894FlashWS.prototype.name = 'flashsocket';
f8e5fb60 2895
a74c0f0c
D
2896/**
2897 * Opens the transport.
d99e7823
D
2898 *
2899 * @api public
2900 */
2901
a74c0f0c
D
2902FlashWS.prototype.doOpen = function () {
2903 if (!this.check()) {
2904 // let the probe timeout
2905 return;
d99e7823
D
2906 }
2907
a74c0f0c
D
2908 // instrument websocketjs logging
2909 function log (type) {
2910 return function(){
2911 var str = Array.prototype.join.call(arguments, ' ');
2912 debug('[websocketjs %s] %s', type, str);
2913 };
2914 };
d99e7823 2915
a74c0f0c
D
2916 WEB_SOCKET_LOGGER = { log: log('debug'), error: log('error') };
2917 WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;
2918 WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true;
d99e7823 2919
a74c0f0c
D
2920 if ('undefined' == typeof WEB_SOCKET_SWF_LOCATION) {
2921 WEB_SOCKET_SWF_LOCATION = this.flashPath + 'WebSocketMainInsecure.swf';
2922 }
d99e7823 2923
a74c0f0c
D
2924 // dependencies
2925 var deps = [this.flashPath + 'web_socket.js'];
d99e7823 2926
a74c0f0c
D
2927 if ('undefined' == typeof swfobject) {
2928 deps.unshift(this.flashPath + 'swfobject.js');
2929 }
d99e7823 2930
a74c0f0c 2931 var self = this;
d99e7823 2932
a74c0f0c
D
2933 load(deps, function () {
2934 self.ready(function () {
2935 WebSocket.__addTask(function () {
2936 WS.prototype.doOpen.call(self);
2937 });
2938 });
2939 });
2940};
d99e7823 2941
a74c0f0c
D
2942/**
2943 * Override to prevent closing uninitialized flashsocket.
2944 *
2945 * @api private
2946 */
d99e7823 2947
a74c0f0c
D
2948FlashWS.prototype.doClose = function () {
2949 if (!this.socket) return;
2950 var self = this;
2951 WebSocket.__addTask(function() {
2952 WS.prototype.doClose.call(self);
2953 });
2954};
d99e7823 2955
a74c0f0c
D
2956/**
2957 * Writes to the Flash socket.
2958 *
2959 * @api private
2960 */
d99e7823 2961
a74c0f0c
D
2962FlashWS.prototype.write = function() {
2963 var self = this, args = arguments;
2964 WebSocket.__addTask(function () {
2965 WS.prototype.write.apply(self, args);
2966 });
d99e7823
D
2967};
2968
2969/**
a74c0f0c 2970 * Called upon dependencies are loaded.
d99e7823
D
2971 *
2972 * @api private
2973 */
2974
a74c0f0c
D
2975FlashWS.prototype.ready = function (fn) {
2976 if (typeof WebSocket == 'undefined' ||
2977 !('__initialize' in WebSocket) || !swfobject) {
2978 return;
d99e7823
D
2979 }
2980
a74c0f0c
D
2981 if (swfobject.getFlashPlayerVersion().major < 10) {
2982 return;
2983 }
d99e7823 2984
a74c0f0c
D
2985 function init () {
2986 // Only start downloading the swf file when the checked that this browser
2987 // actually supports it
2988 if (!FlashWS.loaded) {
2989 if (843 != self.policyPort) {
2990 WebSocket.loadFlashPolicyFile('xmlsocket://' + self.host + ':' + self.policyPort);
2991 }
d99e7823 2992
a74c0f0c
D
2993 WebSocket.__initialize();
2994 FlashWS.loaded = true;
2995 }
d99e7823 2996
a74c0f0c
D
2997 fn.call(self);
2998 }
d99e7823 2999
a74c0f0c
D
3000 var self = this;
3001 if (document.body) {
3002 return init();
3003 }
f8e5fb60 3004
a74c0f0c
D
3005 util.load(init);
3006};
d99e7823
D
3007
3008/**
a74c0f0c 3009 * Feature detection for flashsocket.
f8e5fb60 3010 *
a74c0f0c
D
3011 * @return {Boolean} whether this transport is available.
3012 * @api public
d99e7823
D
3013 */
3014
a74c0f0c
D
3015FlashWS.prototype.check = function () {
3016 if ('undefined' == typeof window) {
3017 return false;
3018 }
d99e7823 3019
a74c0f0c
D
3020 if (typeof WebSocket != 'undefined' && !('__initialize' in WebSocket)) {
3021 return false;
3022 }
d99e7823 3023
a74c0f0c
D
3024 if (xobject) {
3025 var control = null;
3026 try {
3027 control = new xobject('ShockwaveFlash.ShockwaveFlash');
3028 } catch (e) { }
3029 if (control) {
3030 return true;
3031 }
3032 } else {
3033 for (var i = 0, l = navigator.plugins.length; i < l; i++) {
3034 for (var j = 0, m = navigator.plugins[i].length; j < m; j++) {
3035 if (navigator.plugins[i][j].description == 'Shockwave Flash') {
3036 return true;
3037 }
3038 }
3039 }
f8e5fb60 3040 }
a74c0f0c
D
3041
3042 return false;
d99e7823
D
3043};
3044
3045/**
a74c0f0c
D
3046 * Lazy loading of scripts.
3047 * Based on $script by Dustin Diaz - MIT
d99e7823
D
3048 */
3049
a74c0f0c 3050var scripts = {};
d99e7823
D
3051
3052/**
a74c0f0c
D
3053 * Injects a script. Keeps tracked of injected ones.
3054 *
3055 * @param {String} path
3056 * @param {Function} callback
3057 * @api private
d99e7823
D
3058 */
3059
a74c0f0c
D
3060function create (path, fn) {
3061 if (scripts[path]) return fn();
d99e7823 3062
a74c0f0c
D
3063 var el = document.createElement('script');
3064 var loaded = false;
3065
3066 debug('loading "%s"', path);
3067 el.onload = el.onreadystatechange = function () {
3068 if (loaded || scripts[path]) return;
3069 var rs = el.readyState;
3070 if (!rs || 'loaded' == rs || 'complete' == rs) {
3071 debug('loaded "%s"', path);
3072 el.onload = el.onreadystatechange = null;
3073 loaded = true;
3074 scripts[path] = true;
3075 fn();
3076 }
3077 };
3078
3079 el.async = 1;
3080 el.src = path;
d99e7823 3081
a74c0f0c
D
3082 var head = document.getElementsByTagName('head')[0];
3083 head.insertBefore(el, head.firstChild);
3084};
d99e7823
D
3085
3086/**
a74c0f0c 3087 * Loads scripts and fires a callback.
f8e5fb60 3088 *
a74c0f0c
D
3089 * @param {Array} paths
3090 * @param {Function} callback
d99e7823
D
3091 */
3092
a74c0f0c
D
3093function load (arr, fn) {
3094 function process (i) {
3095 if (!arr[i]) return fn();
3096 create(arr[i], function () {
3097 process(++i);
3098 });
3099 };
d99e7823 3100
a74c0f0c
D
3101 process(0);
3102};
d99e7823
D
3103
3104});
a74c0f0c
D
3105require.alias("component-emitter/index.js", "engine.io/deps/emitter/index.js");
3106require.alias("component-emitter/index.js", "emitter/index.js");
3107
3108require.alias("component-indexof/index.js", "engine.io/deps/indexof/index.js");
3109require.alias("component-indexof/index.js", "indexof/index.js");
3110
3111require.alias("LearnBoost-engine.io-protocol/lib/index.js", "engine.io/deps/engine.io-parser/lib/index.js");
3112require.alias("LearnBoost-engine.io-protocol/lib/keys.js", "engine.io/deps/engine.io-parser/lib/keys.js");
3113require.alias("LearnBoost-engine.io-protocol/lib/index.js", "engine.io/deps/engine.io-parser/index.js");
3114require.alias("LearnBoost-engine.io-protocol/lib/index.js", "engine.io-parser/index.js");
3115require.alias("LearnBoost-engine.io-protocol/lib/index.js", "LearnBoost-engine.io-protocol/index.js");
3116
3117require.alias("visionmedia-debug/index.js", "engine.io/deps/debug/index.js");
3118require.alias("visionmedia-debug/debug.js", "engine.io/deps/debug/debug.js");
3119require.alias("visionmedia-debug/index.js", "debug/index.js");
3120
3121require.alias("engine.io/lib/index.js", "engine.io/index.js");
3122
3123if (typeof exports == "object") {
3124 module.exports = require("engine.io");
3125} else if (typeof define == "function" && define.amd) {
3126 define(function(){ return require("engine.io"); });
3127} else {
3128 this["eio"] = require("engine.io");
3129}})();