PageRenderTime 171ms CodeModel.GetById 5ms app.highlight 118ms RepoModel.GetById 1ms app.codeStats 2ms

/samples/web/js/socket.io-0.9.10.js

https://github.com/ADAIN/mod-socket-io
JavaScript | 3887 lines | 2935 code | 334 blank | 618 comment | 228 complexity | e3a0e79ed9f916f6c67bdfcda83edc5c MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*! Socket.IO.js build:0.9.10, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
   2
   3var io = ('undefined' === typeof module ? {} : module.exports);
   4(function() {
   5
   6	/**
   7	 * socket.io
   8	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
   9	 * MIT Licensed
  10	 */
  11
  12	(function (exports, global) {
  13
  14		/**
  15		 * IO namespace.
  16		 *
  17		 * @namespace
  18		 */
  19
  20		var io = exports;
  21
  22		/**
  23		 * Socket.IO version
  24		 *
  25		 * @api public
  26		 */
  27
  28		io.version = '0.9.10';
  29
  30		/**
  31		 * Protocol implemented.
  32		 *
  33		 * @api public
  34		 */
  35
  36		io.protocol = 1;
  37
  38		/**
  39		 * Available transports, these will be populated with the available transports
  40		 *
  41		 * @api public
  42		 */
  43
  44		io.transports = [];
  45
  46		/**
  47		 * Keep track of jsonp callbacks.
  48		 *
  49		 * @api private
  50		 */
  51
  52		io.j = [];
  53
  54		/**
  55		 * Keep track of our io.Sockets
  56		 *
  57		 * @api private
  58		 */
  59		io.sockets = {};
  60
  61
  62		/**
  63		 * Manages connections to hosts.
  64		 *
  65		 * @param {String} uri
  66		 * @Param {Boolean} force creation of new socket (defaults to false)
  67		 * @api public
  68		 */
  69
  70		io.connect = function (host, details) {
  71			var uri = io.util.parseUri(host)
  72					, uuri
  73					, socket;
  74
  75			if (global && global.location) {
  76				uri.protocol = uri.protocol || global.location.protocol.slice(0, -1);
  77				uri.host = uri.host || (global.document
  78						? global.document.domain : global.location.hostname);
  79				uri.port = uri.port || global.location.port;
  80			}
  81
  82			uuri = io.util.uniqueUri(uri);
  83
  84			var options = {
  85				host: uri.host
  86				, secure: 'https' == uri.protocol
  87				, port: uri.port || ('https' == uri.protocol ? 443 : 80)
  88				, query: uri.query || ''
  89			};
  90
  91			io.util.merge(options, details);
  92
  93			if (options['force new connection'] || !io.sockets[uuri]) {
  94				socket = new io.Socket(options);
  95			}
  96
  97			if (!options['force new connection'] && socket) {
  98				io.sockets[uuri] = socket;
  99			}
 100
 101			socket = socket || io.sockets[uuri];
 102
 103			// if path is different from '' or /
 104			return socket.of(uri.path.length > 1 ? uri.path : '');
 105		};
 106
 107	})('object' === typeof module ? module.exports : (this.io = {}), this);
 108	/**
 109	 * socket.io
 110	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 111	 * MIT Licensed
 112	 */
 113
 114	(function (exports, global) {
 115
 116		/**
 117		 * Utilities namespace.
 118		 *
 119		 * @namespace
 120		 */
 121
 122		var util = exports.util = {};
 123
 124		/**
 125		 * Parses an URI
 126		 *
 127		 * @author Steven Levithan <stevenlevithan.com> (MIT license)
 128		 * @api public
 129		 */
 130
 131		var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
 132
 133		var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
 134			'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
 135			'anchor'];
 136
 137		util.parseUri = function (str) {
 138			var m = re.exec(str || '')
 139					, uri = {}
 140					, i = 14;
 141
 142			while (i--) {
 143				uri[parts[i]] = m[i] || '';
 144			}
 145
 146			return uri;
 147		};
 148
 149		/**
 150		 * Produces a unique url that identifies a Socket.IO connection.
 151		 *
 152		 * @param {Object} uri
 153		 * @api public
 154		 */
 155
 156		util.uniqueUri = function (uri) {
 157			var protocol = uri.protocol
 158					, host = uri.host
 159					, port = uri.port;
 160
 161			if ('document' in global) {
 162				host = host || document.domain;
 163				port = port || (protocol == 'https'
 164						&& document.location.protocol !== 'https:' ? 443 : document.location.port);
 165			} else {
 166				host = host || 'localhost';
 167
 168				if (!port && protocol == 'https') {
 169					port = 443;
 170				}
 171			}
 172
 173			return (protocol || 'http') + '://' + host + ':' + (port || 80);
 174		};
 175
 176		/**
 177		 * Mergest 2 query strings in to once unique query string
 178		 *
 179		 * @param {String} base
 180		 * @param {String} addition
 181		 * @api public
 182		 */
 183
 184		util.query = function (base, addition) {
 185			var query = util.chunkQuery(base || '')
 186					, components = [];
 187
 188			util.merge(query, util.chunkQuery(addition || ''));
 189			for (var part in query) {
 190				if (query.hasOwnProperty(part)) {
 191					components.push(part + '=' + query[part]);
 192				}
 193			}
 194
 195			return components.length ? '?' + components.join('&') : '';
 196		};
 197
 198		/**
 199		 * Transforms a querystring in to an object
 200		 *
 201		 * @param {String} qs
 202		 * @api public
 203		 */
 204
 205		util.chunkQuery = function (qs) {
 206			var query = {}
 207					, params = qs.split('&')
 208					, i = 0
 209					, l = params.length
 210					, kv;
 211
 212			for (; i < l; ++i) {
 213				kv = params[i].split('=');
 214				if (kv[0]) {
 215					query[kv[0]] = kv[1];
 216				}
 217			}
 218
 219			return query;
 220		};
 221
 222		/**
 223		 * Executes the given function when the page is loaded.
 224		 *
 225		 *     io.util.load(function () { console.log('page loaded'); });
 226		 *
 227		 * @param {Function} fn
 228		 * @api public
 229		 */
 230
 231		var pageLoaded = false;
 232
 233		util.load = function (fn) {
 234			if ('document' in global && document.readyState === 'complete' || pageLoaded) {
 235				return fn();
 236			}
 237
 238			util.on(global, 'load', fn, false);
 239		};
 240
 241		/**
 242		 * Adds an event.
 243		 *
 244		 * @api private
 245		 */
 246
 247		util.on = function (element, event, fn, capture) {
 248			if (element.attachEvent) {
 249				element.attachEvent('on' + event, fn);
 250			} else if (element.addEventListener) {
 251				element.addEventListener(event, fn, capture);
 252			}
 253		};
 254
 255		/**
 256		 * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
 257		 *
 258		 * @param {Boolean} [xdomain] Create a request that can be used cross domain.
 259		 * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
 260		 * @api private
 261		 */
 262
 263		util.request = function (xdomain) {
 264
 265			if (xdomain && 'undefined' != typeof XDomainRequest) {
 266				return new XDomainRequest();
 267			}
 268
 269			if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
 270				return new XMLHttpRequest();
 271			}
 272
 273			if (!xdomain) {
 274				try {
 275					return new window[(['Active'].concat('Object').join('X'))]('Microsoft.XMLHTTP');
 276				} catch(e) { }
 277			}
 278
 279			return null;
 280		};
 281
 282		/**
 283		 * XHR based transport constructor.
 284		 *
 285		 * @constructor
 286		 * @api public
 287		 */
 288
 289		/**
 290		 * Change the internal pageLoaded value.
 291		 */
 292
 293		if ('undefined' != typeof window) {
 294			util.load(function () {
 295				pageLoaded = true;
 296			});
 297		}
 298
 299		/**
 300		 * Defers a function to ensure a spinner is not displayed by the browser
 301		 *
 302		 * @param {Function} fn
 303		 * @api public
 304		 */
 305
 306		util.defer = function (fn) {
 307			if (!util.ua.webkit || 'undefined' != typeof importScripts) {
 308				return fn();
 309			}
 310
 311			util.load(function () {
 312				setTimeout(fn, 100);
 313			});
 314		};
 315
 316		/**
 317		 * Merges two objects.
 318		 *
 319		 * @api public
 320		 */
 321
 322		util.merge = function merge (target, additional, deep, lastseen) {
 323			var seen = lastseen || []
 324					, depth = typeof deep == 'undefined' ? 2 : deep
 325					, prop;
 326
 327			for (prop in additional) {
 328				if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
 329					if (typeof target[prop] !== 'object' || !depth) {
 330						target[prop] = additional[prop];
 331						seen.push(additional[prop]);
 332					} else {
 333						util.merge(target[prop], additional[prop], depth - 1, seen);
 334					}
 335				}
 336			}
 337
 338			return target;
 339		};
 340
 341		/**
 342		 * Merges prototypes from objects
 343		 *
 344		 * @api public
 345		 */
 346
 347		util.mixin = function (ctor, ctor2) {
 348			util.merge(ctor.prototype, ctor2.prototype);
 349		};
 350
 351		/**
 352		 * Shortcut for prototypical and static inheritance.
 353		 *
 354		 * @api private
 355		 */
 356
 357		util.inherit = function (ctor, ctor2) {
 358			function f() {};
 359			f.prototype = ctor2.prototype;
 360			ctor.prototype = new f;
 361		};
 362
 363		/**
 364		 * Checks if the given object is an Array.
 365		 *
 366		 *     io.util.isArray([]); // true
 367		 *     io.util.isArray({}); // false
 368		 *
 369		 * @param Object obj
 370		 * @api public
 371		 */
 372
 373		util.isArray = Array.isArray || function (obj) {
 374			return Object.prototype.toString.call(obj) === '[object Array]';
 375		};
 376
 377		/**
 378		 * Intersects values of two arrays into a third
 379		 *
 380		 * @api public
 381		 */
 382
 383		util.intersect = function (arr, arr2) {
 384			var ret = []
 385					, longest = arr.length > arr2.length ? arr : arr2
 386					, shortest = arr.length > arr2.length ? arr2 : arr;
 387
 388			for (var i = 0, l = shortest.length; i < l; i++) {
 389				if (~util.indexOf(longest, shortest[i]))
 390					ret.push(shortest[i]);
 391			}
 392
 393			return ret;
 394		}
 395
 396		/**
 397		 * Array indexOf compatibility.
 398		 *
 399		 * @see bit.ly/a5Dxa2
 400		 * @api public
 401		 */
 402
 403		util.indexOf = function (arr, o, i) {
 404
 405			for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
 406					 i < j && arr[i] !== o; i++) {}
 407
 408			return j <= i ? -1 : i;
 409		};
 410
 411		/**
 412		 * Converts enumerables to array.
 413		 *
 414		 * @api public
 415		 */
 416
 417		util.toArray = function (enu) {
 418			var arr = [];
 419
 420			for (var i = 0, l = enu.length; i < l; i++)
 421				arr.push(enu[i]);
 422
 423			return arr;
 424		};
 425
 426		/**
 427		 * UA / engines detection namespace.
 428		 *
 429		 * @namespace
 430		 */
 431
 432		util.ua = {};
 433
 434		/**
 435		 * Whether the UA supports CORS for XHR.
 436		 *
 437		 * @api public
 438		 */
 439
 440		util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
 441			try {
 442				var a = new XMLHttpRequest();
 443			} catch (e) {
 444				return false;
 445			}
 446
 447			return a.withCredentials != undefined;
 448		})();
 449
 450		/**
 451		 * Detect webkit.
 452		 *
 453		 * @api public
 454		 */
 455
 456		util.ua.webkit = 'undefined' != typeof navigator
 457				&& /webkit/i.test(navigator.userAgent);
 458
 459		/**
 460		 * Detect iPad/iPhone/iPod.
 461		 *
 462		 * @api public
 463		 */
 464
 465		util.ua.iDevice = 'undefined' != typeof navigator
 466				&& /iPad|iPhone|iPod/i.test(navigator.userAgent);
 467
 468	})('undefined' != typeof io ? io : module.exports, this);
 469	/**
 470	 * socket.io
 471	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 472	 * MIT Licensed
 473	 */
 474
 475	(function (exports, io) {
 476
 477		/**
 478		 * Expose constructor.
 479		 */
 480
 481		exports.EventEmitter = EventEmitter;
 482
 483		/**
 484		 * Event emitter constructor.
 485		 *
 486		 * @api public.
 487		 */
 488
 489		function EventEmitter () {};
 490
 491		/**
 492		 * Adds a listener
 493		 *
 494		 * @api public
 495		 */
 496
 497		EventEmitter.prototype.on = function (name, fn) {
 498			if (!this.$events) {
 499				this.$events = {};
 500			}
 501
 502			if (!this.$events[name]) {
 503				this.$events[name] = fn;
 504			} else if (io.util.isArray(this.$events[name])) {
 505				this.$events[name].push(fn);
 506			} else {
 507				this.$events[name] = [this.$events[name], fn];
 508			}
 509
 510			return this;
 511		};
 512
 513		EventEmitter.prototype.addListener = EventEmitter.prototype.on;
 514
 515		/**
 516		 * Adds a volatile listener.
 517		 *
 518		 * @api public
 519		 */
 520
 521		EventEmitter.prototype.once = function (name, fn) {
 522			var self = this;
 523
 524			function on () {
 525				self.removeListener(name, on);
 526				fn.apply(this, arguments);
 527			};
 528
 529			on.listener = fn;
 530			this.on(name, on);
 531
 532			return this;
 533		};
 534
 535		/**
 536		 * Removes a listener.
 537		 *
 538		 * @api public
 539		 */
 540
 541		EventEmitter.prototype.removeListener = function (name, fn) {
 542			if (this.$events && this.$events[name]) {
 543				var list = this.$events[name];
 544
 545				if (io.util.isArray(list)) {
 546					var pos = -1;
 547
 548					for (var i = 0, l = list.length; i < l; i++) {
 549						if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
 550							pos = i;
 551							break;
 552						}
 553					}
 554
 555					if (pos < 0) {
 556						return this;
 557					}
 558
 559					list.splice(pos, 1);
 560
 561					if (!list.length) {
 562						delete this.$events[name];
 563					}
 564				} else if (list === fn || (list.listener && list.listener === fn)) {
 565					delete this.$events[name];
 566				}
 567			}
 568
 569			return this;
 570		};
 571
 572		/**
 573		 * Removes all listeners for an event.
 574		 *
 575		 * @api public
 576		 */
 577
 578		EventEmitter.prototype.removeAllListeners = function (name) {
 579			if (name === undefined) {
 580				this.$events = {};
 581				return this;
 582			}
 583
 584			if (this.$events && this.$events[name]) {
 585				this.$events[name] = null;
 586			}
 587
 588			return this;
 589		};
 590
 591		/**
 592		 * Gets all listeners for a certain event.
 593		 *
 594		 * @api publci
 595		 */
 596
 597		EventEmitter.prototype.listeners = function (name) {
 598			if (!this.$events) {
 599				this.$events = {};
 600			}
 601
 602			if (!this.$events[name]) {
 603				this.$events[name] = [];
 604			}
 605
 606			if (!io.util.isArray(this.$events[name])) {
 607				this.$events[name] = [this.$events[name]];
 608			}
 609
 610			return this.$events[name];
 611		};
 612
 613		/**
 614		 * Emits an event.
 615		 *
 616		 * @api public
 617		 */
 618
 619		EventEmitter.prototype.emit = function (name) {
 620			if (!this.$events) {
 621				return false;
 622			}
 623
 624			var handler = this.$events[name];
 625
 626			if (!handler) {
 627				return false;
 628			}
 629
 630			var args = Array.prototype.slice.call(arguments, 1);
 631
 632			if ('function' == typeof handler) {
 633				handler.apply(this, args);
 634			} else if (io.util.isArray(handler)) {
 635				var listeners = handler.slice();
 636
 637				for (var i = 0, l = listeners.length; i < l; i++) {
 638					listeners[i].apply(this, args);
 639				}
 640			} else {
 641				return false;
 642			}
 643
 644			return true;
 645		};
 646
 647	})(
 648			'undefined' != typeof io ? io : module.exports
 649			, 'undefined' != typeof io ? io : module.parent.exports
 650	);
 651
 652	/**
 653	 * socket.io
 654	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 655	 * MIT Licensed
 656	 */
 657
 658	/**
 659	 * Based on JSON2 (http://www.JSON.org/js.html).
 660	 */
 661
 662	(function (exports, nativeJSON) {
 663		"use strict";
 664
 665		// use native JSON if it's available
 666		if (nativeJSON && nativeJSON.parse){
 667			return exports.JSON = {
 668				parse: nativeJSON.parse
 669				, stringify: nativeJSON.stringify
 670			}
 671		}
 672
 673		var JSON = exports.JSON = {};
 674
 675		function f(n) {
 676			// Format integers to have at least two digits.
 677			return n < 10 ? '0' + n : n;
 678		}
 679
 680		function date(d, key) {
 681			return isFinite(d.valueOf()) ?
 682					d.getUTCFullYear()     + '-' +
 683							f(d.getUTCMonth() + 1) + '-' +
 684							f(d.getUTCDate())      + 'T' +
 685							f(d.getUTCHours())     + ':' +
 686							f(d.getUTCMinutes())   + ':' +
 687							f(d.getUTCSeconds())   + 'Z' : null;
 688		};
 689
 690		var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 691				escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 692				gap,
 693				indent,
 694				meta = {    // table of character substitutions
 695					'\b': '\\b',
 696					'\t': '\\t',
 697					'\n': '\\n',
 698					'\f': '\\f',
 699					'\r': '\\r',
 700					'"' : '\\"',
 701					'\\': '\\\\'
 702				},
 703				rep;
 704
 705
 706		function quote(string) {
 707
 708// If the string contains no control characters, no quote characters, and no
 709// backslash characters, then we can safely slap some quotes around it.
 710// Otherwise we must also replace the offending characters with safe escape
 711// sequences.
 712
 713			escapable.lastIndex = 0;
 714			return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
 715				var c = meta[a];
 716				return typeof c === 'string' ? c :
 717						'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
 718			}) + '"' : '"' + string + '"';
 719		}
 720
 721
 722		function str(key, holder) {
 723
 724// Produce a string from holder[key].
 725
 726			var i,          // The loop counter.
 727					k,          // The member key.
 728					v,          // The member value.
 729					length,
 730					mind = gap,
 731					partial,
 732					value = holder[key];
 733
 734// If the value has a toJSON method, call it to obtain a replacement value.
 735
 736			if (value instanceof Date) {
 737				value = date(key);
 738			}
 739
 740// If we were called with a replacer function, then call the replacer to
 741// obtain a replacement value.
 742
 743			if (typeof rep === 'function') {
 744				value = rep.call(holder, key, value);
 745			}
 746
 747// What happens next depends on the value's type.
 748
 749			switch (typeof value) {
 750				case 'string':
 751					return quote(value);
 752
 753				case 'number':
 754
 755// JSON numbers must be finite. Encode non-finite numbers as null.
 756
 757					return isFinite(value) ? String(value) : 'null';
 758
 759				case 'boolean':
 760				case 'null':
 761
 762// If the value is a boolean or null, convert it to a string. Note:
 763// typeof null does not produce 'null'. The case is included here in
 764// the remote chance that this gets fixed someday.
 765
 766					return String(value);
 767
 768// If the type is 'object', we might be dealing with an object or an array or
 769// null.
 770
 771				case 'object':
 772
 773// Due to a specification blunder in ECMAScript, typeof null is 'object',
 774// so watch out for that case.
 775
 776					if (!value) {
 777						return 'null';
 778					}
 779
 780// Make an array to hold the partial results of stringifying this object value.
 781
 782					gap += indent;
 783					partial = [];
 784
 785// Is the value an array?
 786
 787					if (Object.prototype.toString.apply(value) === '[object Array]') {
 788
 789// The value is an array. Stringify every element. Use null as a placeholder
 790// for non-JSON values.
 791
 792						length = value.length;
 793						for (i = 0; i < length; i += 1) {
 794							partial[i] = str(i, value) || 'null';
 795						}
 796
 797// Join all of the elements together, separated with commas, and wrap them in
 798// brackets.
 799
 800						v = partial.length === 0 ? '[]' : gap ?
 801								'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
 802								'[' + partial.join(',') + ']';
 803						gap = mind;
 804						return v;
 805					}
 806
 807// If the replacer is an array, use it to select the members to be stringified.
 808
 809					if (rep && typeof rep === 'object') {
 810						length = rep.length;
 811						for (i = 0; i < length; i += 1) {
 812							if (typeof rep[i] === 'string') {
 813								k = rep[i];
 814								v = str(k, value);
 815								if (v) {
 816									partial.push(quote(k) + (gap ? ': ' : ':') + v);
 817								}
 818							}
 819						}
 820					} else {
 821
 822// Otherwise, iterate through all of the keys in the object.
 823
 824						for (k in value) {
 825							if (Object.prototype.hasOwnProperty.call(value, k)) {
 826								v = str(k, value);
 827								if (v) {
 828									partial.push(quote(k) + (gap ? ': ' : ':') + v);
 829								}
 830							}
 831						}
 832					}
 833
 834// Join all of the member texts together, separated with commas,
 835// and wrap them in braces.
 836
 837					v = partial.length === 0 ? '{}' : gap ?
 838							'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
 839							'{' + partial.join(',') + '}';
 840					gap = mind;
 841					return v;
 842			}
 843		}
 844
 845// If the JSON object does not yet have a stringify method, give it one.
 846
 847		JSON.stringify = function (value, replacer, space) {
 848
 849// The stringify method takes a value and an optional replacer, and an optional
 850// space parameter, and returns a JSON text. The replacer can be a function
 851// that can replace values, or an array of strings that will select the keys.
 852// A default replacer method can be provided. Use of the space parameter can
 853// produce text that is more easily readable.
 854
 855			var i;
 856			gap = '';
 857			indent = '';
 858
 859// If the space parameter is a number, make an indent string containing that
 860// many spaces.
 861
 862			if (typeof space === 'number') {
 863				for (i = 0; i < space; i += 1) {
 864					indent += ' ';
 865				}
 866
 867// If the space parameter is a string, it will be used as the indent string.
 868
 869			} else if (typeof space === 'string') {
 870				indent = space;
 871			}
 872
 873// If there is a replacer, it must be a function or an array.
 874// Otherwise, throw an error.
 875
 876			rep = replacer;
 877			if (replacer && typeof replacer !== 'function' &&
 878					(typeof replacer !== 'object' ||
 879							typeof replacer.length !== 'number')) {
 880				throw new Error('JSON.stringify');
 881			}
 882
 883// Make a fake root object containing our value under the key of ''.
 884// Return the result of stringifying the value.
 885
 886			return str('', {'': value});
 887		};
 888
 889// If the JSON object does not yet have a parse method, give it one.
 890
 891		JSON.parse = function (text, reviver) {
 892			// The parse method takes a text and an optional reviver function, and returns
 893			// a JavaScript value if the text is a valid JSON text.
 894
 895			var j;
 896
 897			function walk(holder, key) {
 898
 899				// The walk method is used to recursively walk the resulting structure so
 900				// that modifications can be made.
 901
 902				var k, v, value = holder[key];
 903				if (value && typeof value === 'object') {
 904					for (k in value) {
 905						if (Object.prototype.hasOwnProperty.call(value, k)) {
 906							v = walk(value, k);
 907							if (v !== undefined) {
 908								value[k] = v;
 909							} else {
 910								delete value[k];
 911							}
 912						}
 913					}
 914				}
 915				return reviver.call(holder, key, value);
 916			}
 917
 918
 919			// Parsing happens in four stages. In the first stage, we replace certain
 920			// Unicode characters with escape sequences. JavaScript handles many characters
 921			// incorrectly, either silently deleting them, or treating them as line endings.
 922
 923			text = String(text);
 924			cx.lastIndex = 0;
 925			if (cx.test(text)) {
 926				text = text.replace(cx, function (a) {
 927					return '\\u' +
 928							('0000' + a.charCodeAt(0).toString(16)).slice(-4);
 929				});
 930			}
 931
 932			// In the second stage, we run the text against regular expressions that look
 933			// for non-JSON patterns. We are especially concerned with '()' and 'new'
 934			// because they can cause invocation, and '=' because it can cause mutation.
 935			// But just to be safe, we want to reject all unexpected forms.
 936
 937			// We split the second stage into 4 regexp operations in order to work around
 938			// crippling inefficiencies in IE's and Safari's regexp engines. First we
 939			// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
 940			// replace all simple value tokens with ']' characters. Third, we delete all
 941			// open brackets that follow a colon or comma or that begin the text. Finally,
 942			// we look to see that the remaining characters are only whitespace or ']' or
 943			// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
 944
 945			if (/^[\],:{}\s]*$/
 946					.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
 947					.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
 948					.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
 949
 950				// In the third stage we use the eval function to compile the text into a
 951				// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
 952				// in JavaScript: it can begin a block or an object literal. We wrap the text
 953				// in parens to eliminate the ambiguity.
 954
 955				j = eval('(' + text + ')');
 956
 957				// In the optional fourth stage, we recursively walk the new structure, passing
 958				// each name/value pair to a reviver function for possible transformation.
 959
 960				return typeof reviver === 'function' ?
 961						walk({'': j}, '') : j;
 962			}
 963
 964			// If the text is not JSON parseable, then a SyntaxError is thrown.
 965
 966			throw new SyntaxError('JSON.parse');
 967		};
 968
 969	})(
 970			'undefined' != typeof io ? io : module.exports
 971			, typeof JSON !== 'undefined' ? JSON : undefined
 972	);
 973
 974	/**
 975	 * socket.io
 976	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 977	 * MIT Licensed
 978	 */
 979
 980	(function (exports, io) {
 981
 982		/**
 983		 * Parser namespace.
 984		 *
 985		 * @namespace
 986		 */
 987
 988		var parser = exports.parser = {};
 989
 990		/**
 991		 * Packet types.
 992		 */
 993
 994		var packets = parser.packets = [
 995			'disconnect'
 996			, 'connect'
 997			, 'heartbeat'
 998			, 'message'
 999			, 'json'
1000			, 'event'
1001			, 'ack'
1002			, 'error'
1003			, 'noop'
1004		];
1005
1006		/**
1007		 * Errors reasons.
1008		 */
1009
1010		var reasons = parser.reasons = [
1011			'transport not supported'
1012			, 'client not handshaken'
1013			, 'unauthorized'
1014		];
1015
1016		/**
1017		 * Errors advice.
1018		 */
1019
1020		var advice = parser.advice = [
1021			'reconnect'
1022		];
1023
1024		/**
1025		 * Shortcuts.
1026		 */
1027
1028		var JSON = io.JSON
1029				, indexOf = io.util.indexOf;
1030
1031		/**
1032		 * Encodes a packet.
1033		 *
1034		 * @api private
1035		 */
1036
1037		parser.encodePacket = function (packet) {
1038			var type = indexOf(packets, packet.type)
1039					, id = packet.id || ''
1040					, endpoint = packet.endpoint || ''
1041					, ack = packet.ack
1042					, data = null;
1043
1044			switch (packet.type) {
1045				case 'error':
1046					var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
1047							, adv = packet.advice ? indexOf(advice, packet.advice) : '';
1048
1049					if (reason !== '' || adv !== '')
1050						data = reason + (adv !== '' ? ('+' + adv) : '');
1051
1052					break;
1053
1054				case 'message':
1055					if (packet.data !== '')
1056						data = packet.data;
1057					break;
1058
1059				case 'event':
1060					var ev = { name: packet.name };
1061
1062					if (packet.args && packet.args.length) {
1063						ev.args = packet.args;
1064					}
1065
1066					data = JSON.stringify(ev);
1067					break;
1068
1069				case 'json':
1070					data = JSON.stringify(packet.data);
1071					break;
1072
1073				case 'connect':
1074					if (packet.qs)
1075						data = packet.qs;
1076					break;
1077
1078				case 'ack':
1079					data = packet.ackId
1080							+ (packet.args && packet.args.length
1081							? '+' + JSON.stringify(packet.args) : '');
1082					break;
1083			}
1084
1085			// construct packet with required fragments
1086			var encoded = [
1087				type
1088				, id + (ack == 'data' ? '+' : '')
1089				, endpoint
1090			];
1091
1092			// data fragment is optional
1093			if (data !== null && data !== undefined)
1094				encoded.push(data);
1095
1096			return encoded.join(':');
1097		};
1098
1099		/**
1100		 * Encodes multiple messages (payload).
1101		 *
1102		 * @param {Array} messages
1103		 * @api private
1104		 */
1105
1106		parser.encodePayload = function (packets) {
1107			var decoded = '';
1108
1109			if (packets.length == 1)
1110				return packets[0];
1111
1112			for (var i = 0, l = packets.length; i < l; i++) {
1113				var packet = packets[i];
1114				decoded += '\ufffd' + packet.length + '\ufffd' + packets[i];
1115			}
1116
1117			return decoded;
1118		};
1119
1120		/**
1121		 * Decodes a packet
1122		 *
1123		 * @api private
1124		 */
1125
1126		var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
1127
1128		parser.decodePacket = function (data) {
1129			var pieces = data.match(regexp);
1130
1131			if (!pieces) return {};
1132
1133			var id = pieces[2] || ''
1134					, data = pieces[5] || ''
1135					, packet = {
1136						type: packets[pieces[1]]
1137						, endpoint: pieces[4] || ''
1138					};
1139
1140			// whether we need to acknowledge the packet
1141			if (id) {
1142				packet.id = id;
1143				if (pieces[3])
1144					packet.ack = 'data';
1145				else
1146					packet.ack = true;
1147			}
1148
1149			// handle different packet types
1150			switch (packet.type) {
1151				case 'error':
1152					var pieces = data.split('+');
1153					packet.reason = reasons[pieces[0]] || '';
1154					packet.advice = advice[pieces[1]] || '';
1155					break;
1156
1157				case 'message':
1158					packet.data = data || '';
1159					break;
1160
1161				case 'event':
1162					try {
1163						var opts = JSON.parse(data);
1164						packet.name = opts.name;
1165						packet.args = opts.args;
1166					} catch (e) { }
1167
1168					packet.args = packet.args || [];
1169					break;
1170
1171				case 'json':
1172					try {
1173						packet.data = JSON.parse(data);
1174					} catch (e) { }
1175					break;
1176
1177				case 'connect':
1178					packet.qs = data || '';
1179					break;
1180
1181				case 'ack':
1182					var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
1183					if (pieces) {
1184						packet.ackId = pieces[1];
1185						packet.args = [];
1186
1187						if (pieces[3]) {
1188							try {
1189								packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
1190							} catch (e) { }
1191						}
1192					}
1193					break;
1194
1195				case 'disconnect':
1196				case 'heartbeat':
1197					break;
1198			};
1199
1200			return packet;
1201		};
1202
1203		/**
1204		 * Decodes data payload. Detects multiple messages
1205		 *
1206		 * @return {Array} messages
1207		 * @api public
1208		 */
1209
1210		parser.decodePayload = function (data) {
1211			// IE doesn't like data[i] for unicode chars, charAt works fine
1212			if (data.charAt(0) == '\ufffd') {
1213				var ret = [];
1214
1215				for (var i = 1, length = ''; i < data.length; i++) {
1216					if (data.charAt(i) == '\ufffd') {
1217						ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
1218						i += Number(length) + 1;
1219						length = '';
1220					} else {
1221						length += data.charAt(i);
1222					}
1223				}
1224
1225				return ret;
1226			} else {
1227				return [parser.decodePacket(data)];
1228			}
1229		};
1230
1231	})(
1232			'undefined' != typeof io ? io : module.exports
1233			, 'undefined' != typeof io ? io : module.parent.exports
1234	);
1235	/**
1236	 * socket.io
1237	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1238	 * MIT Licensed
1239	 */
1240
1241	(function (exports, io) {
1242
1243		/**
1244		 * Expose constructor.
1245		 */
1246
1247		exports.Transport = Transport;
1248
1249		/**
1250		 * This is the transport template for all supported transport methods.
1251		 *
1252		 * @constructor
1253		 * @api public
1254		 */
1255
1256		function Transport (socket, sessid) {
1257			this.socket = socket;
1258			this.sessid = sessid;
1259		};
1260
1261		/**
1262		 * Apply EventEmitter mixin.
1263		 */
1264
1265		io.util.mixin(Transport, io.EventEmitter);
1266
1267
1268		/**
1269		 * Indicates whether heartbeats is enabled for this transport
1270		 *
1271		 * @api private
1272		 */
1273
1274		Transport.prototype.heartbeats = function () {
1275			return true;
1276		}
1277
1278		/**
1279		 * Handles the response from the server. When a new response is received
1280		 * it will automatically update the timeout, decode the message and
1281		 * forwards the response to the onMessage function for further processing.
1282		 *
1283		 * @param {String} data Response from the server.
1284		 * @api private
1285		 */
1286
1287		Transport.prototype.onData = function (data) {
1288			this.clearCloseTimeout();
1289
1290			// If the connection in currently open (or in a reopening state) reset the close 
1291			// timeout since we have just received data. This check is necessary so
1292			// that we don't reset the timeout on an explicitly disconnected connection.
1293			if (this.socket.connected || this.socket.connecting || this.socket.reconnecting) {
1294				this.setCloseTimeout();
1295			}
1296
1297			if (data !== '') {
1298				// todo: we should only do decodePayload for xhr transports
1299				var msgs = io.parser.decodePayload(data);
1300
1301				if (msgs && msgs.length) {
1302					for (var i = 0, l = msgs.length; i < l; i++) {
1303						this.onPacket(msgs[i]);
1304					}
1305				}
1306			}
1307
1308			return this;
1309		};
1310
1311		/**
1312		 * Handles packets.
1313		 *
1314		 * @api private
1315		 */
1316
1317		Transport.prototype.onPacket = function (packet) {
1318			this.socket.setHeartbeatTimeout();
1319
1320			if (packet.type == 'heartbeat') {
1321				return this.onHeartbeat();
1322			}
1323
1324			if (packet.type == 'connect' && packet.endpoint == '') {
1325				this.onConnect();
1326			}
1327
1328			if (packet.type == 'error' && packet.advice == 'reconnect') {
1329				this.isOpen = false;
1330			}
1331
1332			this.socket.onPacket(packet);
1333
1334			return this;
1335		};
1336
1337		/**
1338		 * Sets close timeout
1339		 *
1340		 * @api private
1341		 */
1342
1343		Transport.prototype.setCloseTimeout = function () {
1344			if (!this.closeTimeout) {
1345				var self = this;
1346
1347				this.closeTimeout = setTimeout(function () {
1348					self.onDisconnect();
1349				}, this.socket.closeTimeout);
1350			}
1351		};
1352
1353		/**
1354		 * Called when transport disconnects.
1355		 *
1356		 * @api private
1357		 */
1358
1359		Transport.prototype.onDisconnect = function () {
1360			if (this.isOpen) this.close();
1361			this.clearTimeouts();
1362			this.socket.onDisconnect();
1363			return this;
1364		};
1365
1366		/**
1367		 * Called when transport connects
1368		 *
1369		 * @api private
1370		 */
1371
1372		Transport.prototype.onConnect = function () {
1373			this.socket.onConnect();
1374			return this;
1375		}
1376
1377		/**
1378		 * Clears close timeout
1379		 *
1380		 * @api private
1381		 */
1382
1383		Transport.prototype.clearCloseTimeout = function () {
1384			if (this.closeTimeout) {
1385				clearTimeout(this.closeTimeout);
1386				this.closeTimeout = null;
1387			}
1388		};
1389
1390		/**
1391		 * Clear timeouts
1392		 *
1393		 * @api private
1394		 */
1395
1396		Transport.prototype.clearTimeouts = function () {
1397			this.clearCloseTimeout();
1398
1399			if (this.reopenTimeout) {
1400				clearTimeout(this.reopenTimeout);
1401			}
1402		};
1403
1404		/**
1405		 * Sends a packet
1406		 *
1407		 * @param {Object} packet object.
1408		 * @api private
1409		 */
1410
1411		Transport.prototype.packet = function (packet) {
1412			this.send(io.parser.encodePacket(packet));
1413		};
1414
1415		/**
1416		 * Send the received heartbeat message back to server. So the server
1417		 * knows we are still connected.
1418		 *
1419		 * @param {String} heartbeat Heartbeat response from the server.
1420		 * @api private
1421		 */
1422
1423		Transport.prototype.onHeartbeat = function (heartbeat) {
1424			this.packet({ type: 'heartbeat' });
1425		};
1426
1427		/**
1428		 * Called when the transport opens.
1429		 *
1430		 * @api private
1431		 */
1432
1433		Transport.prototype.onOpen = function () {
1434			this.isOpen = true;
1435			this.clearCloseTimeout();
1436			this.socket.onOpen();
1437		};
1438
1439		/**
1440		 * Notifies the base when the connection with the Socket.IO server
1441		 * has been disconnected.
1442		 *
1443		 * @api private
1444		 */
1445
1446		Transport.prototype.onClose = function () {
1447			var self = this;
1448
1449			/* FIXME: reopen delay causing a infinit loop
1450			 this.reopenTimeout = setTimeout(function () {
1451			 self.open();
1452			 }, this.socket.options['reopen delay']);*/
1453
1454			this.isOpen = false;
1455			this.socket.onClose();
1456			this.onDisconnect();
1457		};
1458
1459		/**
1460		 * Generates a connection url based on the Socket.IO URL Protocol.
1461		 * See <https://github.com/learnboost/socket.io-node/> for more details.
1462		 *
1463		 * @returns {String} Connection url
1464		 * @api private
1465		 */
1466
1467		Transport.prototype.prepareUrl = function () {
1468			var options = this.socket.options;
1469
1470			return this.scheme() + '://'
1471					+ options.host + ':' + options.port + '/'
1472					+ options.resource + '/' + io.protocol
1473					+ '/' + this.name + '/' + this.sessid;
1474		};
1475
1476		/**
1477		 * Checks if the transport is ready to start a connection.
1478		 *
1479		 * @param {Socket} socket The socket instance that needs a transport
1480		 * @param {Function} fn The callback
1481		 * @api private
1482		 */
1483
1484		Transport.prototype.ready = function (socket, fn) {
1485			fn.call(this);
1486		};
1487	})(
1488			'undefined' != typeof io ? io : module.exports
1489			, 'undefined' != typeof io ? io : module.parent.exports
1490	);
1491	/**
1492	 * socket.io
1493	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1494	 * MIT Licensed
1495	 */
1496
1497	(function (exports, io, global) {
1498
1499		/**
1500		 * Expose constructor.
1501		 */
1502
1503		exports.Socket = Socket;
1504
1505		/**
1506		 * Create a new `Socket.IO client` which can establish a persistent
1507		 * connection with a Socket.IO enabled server.
1508		 *
1509		 * @api public
1510		 */
1511
1512		function Socket (options) {
1513			this.options = {
1514				port: 80
1515				, secure: false
1516				, document: 'document' in global ? document : false
1517				, resource: 'socket.io'
1518				, transports: io.transports
1519				, 'connect timeout': 10000
1520				, 'try multiple transports': true
1521				, 'reconnect': true
1522				, 'reconnection delay': 500
1523				, 'reconnection limit': Infinity
1524				, 'reopen delay': 3000
1525				, 'max reconnection attempts': 10
1526				, 'sync disconnect on unload': false
1527				, 'auto connect': true
1528				, 'flash policy port': 10843
1529				, 'manualFlush': false
1530			};
1531
1532			io.util.merge(this.options, options);
1533
1534			this.connected = false;
1535			this.open = false;
1536			this.connecting = false;
1537			this.reconnecting = false;
1538			this.namespaces = {};
1539			this.buffer = [];
1540			this.doBuffer = false;
1541
1542			if (this.options['sync disconnect on unload'] &&
1543					(!this.isXDomain() || io.util.ua.hasCORS)) {
1544				var self = this;
1545				io.util.on(global, 'beforeunload', function () {
1546					self.disconnectSync();
1547				}, false);
1548			}
1549
1550			if (this.options['auto connect']) {
1551				this.connect();
1552			}
1553		};
1554
1555		/**
1556		 * Apply EventEmitter mixin.
1557		 */
1558
1559		io.util.mixin(Socket, io.EventEmitter);
1560
1561		/**
1562		 * Returns a namespace listener/emitter for this socket
1563		 *
1564		 * @api public
1565		 */
1566
1567		Socket.prototype.of = function (name) {
1568			if (!this.namespaces[name]) {
1569				this.namespaces[name] = new io.SocketNamespace(this, name);
1570
1571				if (name !== '') {
1572					this.namespaces[name].packet({ type: 'connect' });
1573				}
1574			}
1575
1576			return this.namespaces[name];
1577		};
1578
1579		/**
1580		 * Emits the given event to the Socket and all namespaces
1581		 *
1582		 * @api private
1583		 */
1584
1585		Socket.prototype.publish = function () {
1586			this.emit.apply(this, arguments);
1587
1588			var nsp;
1589
1590			for (var i in this.namespaces) {
1591				if (this.namespaces.hasOwnProperty(i)) {
1592					nsp = this.of(i);
1593					nsp.$emit.apply(nsp, arguments);
1594				}
1595			}
1596		};
1597
1598		/**
1599		 * Performs the handshake
1600		 *
1601		 * @api private
1602		 */
1603
1604		function empty () { };
1605
1606		Socket.prototype.handshake = function (fn) {
1607//			alert("Socket handshake()");
1608			var self = this
1609					, options = this.options;
1610
1611			function complete (data) {
1612//				alert("Socket handshake complete(): " + data);
1613				if (data instanceof Error) {
1614					self.connecting = false;
1615					self.onError(data.message);
1616				} else {
1617					fn.apply(null, data.split(':'));
1618				}
1619			};
1620
1621			var url = [
1622				'http' + (options.secure ? 's' : '') + ':/'
1623				, options.host + ':' + options.port
1624				, options.resource
1625				, io.protocol
1626				, io.util.query(this.options.query, 't=' + +new Date)
1627			].join('/');
1628
1629//			alert("Socket handshake(): " + url);
1630
1631			if (this.isXDomain() && !io.util.ua.hasCORS) {
1632
1633//				alert("Socket handshake isXDomain");
1634
1635				var insertAt = document.getElementsByTagName('script')[0]
1636						, script = document.createElement('script');
1637
1638				script.src = url + '&jsonp=' + io.j.length;
1639				insertAt.parentNode.insertBefore(script, insertAt);
1640//				alert("Socket io.j.push");
1641				io.j.push(function (data) {
1642//					alert("Socket handshake push() with: " + data);
1643					complete(data);
1644					script.parentNode.removeChild(script);
1645				});
1646			} else {
1647
1648//				alert("Socket handshake is not XDomain")
1649
1650				var xhr = io.util.request();
1651
1652				xhr.open('GET', url, true);
1653				if (this.isXDomain()) {
1654					xhr.withCredentials = true;
1655				}
1656				xhr.onreadystatechange = function () {
1657					if (xhr.readyState == 4) {
1658						xhr.onreadystatechange = empty;
1659
1660						if (xhr.status == 200) {
1661//							alert("Socket handshake() status 200");
1662							complete(xhr.responseText);
1663						} else if (xhr.status == 403) {
1664//							alert("Socket handshake() status 403");
1665							self.onError(xhr.responseText);
1666						} else {
1667//							alert("Socket handshake() status else");
1668							self.connecting = false;
1669							!self.reconnecting && self.onError(xhr.responseText);
1670						}
1671					}
1672				};
1673				xhr.send(null);
1674			}
1675		};
1676
1677		/**
1678		 * Find an available transport based on the options supplied in the constructor.
1679		 *
1680		 * @api private
1681		 */
1682
1683		Socket.prototype.getTransport = function (override) {
1684			var transports = override || this.transports, match;
1685
1686			for (var i = 0, transport; transport = transports[i]; i++) {
1687				if (io.Transport[transport]
1688						&& io.Transport[transport].check(this)
1689						&& (!this.isXDomain() || io.Transport[transport].xdomainCheck(this))) {
1690					return new io.Transport[transport](this, this.sessionid);
1691				}
1692			}
1693
1694			return null;
1695		};
1696
1697		/**
1698		 * Connects to the server.
1699		 *
1700		 * @param {Function} [fn] Callback.
1701		 * @returns {io.Socket}
1702		 * @api public
1703		 */
1704
1705		Socket.prototype.connect = function (fn) {
1706			if (this.connecting) {
1707				return this;
1708			}
1709
1710			var self = this;
1711			self.connecting = true;
1712
1713			this.handshake(function (sid, heartbeat, close, transports) {
1714				self.sessionid = sid;
1715				self.closeTimeout = close * 1000;
1716				self.heartbeatTimeout = heartbeat * 1000;
1717				if(!self.transports)
1718					self.transports = self.origTransports = (transports ? io.util.intersect(
1719							transports.split(',')
1720							, self.options.transports
1721					) : self.options.transports);
1722
1723				self.setHeartbeatTimeout();
1724
1725				function connect (transports){
1726					if (self.transport) self.transport.clearTimeouts();
1727
1728					self.transport = self.getTransport(transports);
1729					if (!self.transport) return self.publish('connect_failed');
1730
1731					// once the transport is ready
1732					self.transport.ready(self, function () {
1733						self.connecting = true;
1734						self.publish('connecting', self.transport.name);
1735						self.transport.open();
1736
1737						if (self.options['connect timeout']) {
1738							self.connectTimeoutTimer = setTimeout(function () {
1739								if (!self.connected) {
1740									self.connecting = false;
1741
1742									if (self.options['try multiple transports']) {
1743										var remaining = self.transports;
1744
1745										while (remaining.length > 0 && remaining.splice(0,1)[0] !=
1746												self.transport.name) {}
1747
1748										if (remaining.length){
1749											connect(remaining);
1750										} else {
1751											self.publish('connect_failed');
1752										}
1753									}
1754								}
1755							}, self.options['connect timeout']);
1756						}
1757					});
1758				}
1759
1760				connect(self.transports);
1761
1762				self.once('connect', function (){
1763					clearTimeout(self.connectTimeoutTimer);
1764
1765					fn && typeof fn == 'function' && fn();
1766				});
1767			});
1768
1769			return this;
1770		};
1771
1772		/**
1773		 * Clears and sets a new heartbeat timeout using the value given by the
1774		 * server during the handshake.
1775		 *
1776		 * @api private
1777		 */
1778
1779		Socket.prototype.setHeartbeatTimeout = function () {
1780			clearTimeout(this.heartbeatTimeoutTimer);
1781			if(this.transport && !this.transport.heartbeats()) return;
1782
1783			var self = this;
1784			this.heartbeatTimeoutTimer = setTimeout(function () {
1785				self.transport.onClose();
1786			}, this.heartbeatTimeout);
1787		};
1788
1789		/**
1790		 * Sends a message.
1791		 *
1792		 * @param {Object} data packet.
1793		 * @returns {io.Socket}
1794		 * @api public
1795		 */
1796
1797		Socket.prototype.packet = function (data) {
1798			if (this.connected && !this.doBuffer) {
1799				this.transport.packet(data);
1800			} else {
1801				this.buffer.push(data);
1802			}
1803
1804			return this;
1805		};
1806
1807		/**
1808		 * Sets buffer state
1809		 *
1810		 * @api private
1811		 */
1812
1813		Socket.prototype.setBuffer = function (v) {
1814			this.doBuffer = v;
1815
1816			if (!v && this.connected && this.buffer.length) {
1817				if (!this.options['manualFlush']) {
1818					this.flushBuffer();
1819				}
1820			}
1821		};
1822
1823		/**
1824		 * Flushes the buffer data over the wire.
1825		 * To be invoked manually when 'manualFlush' is set to true.
1826		 *
1827		 * @api public
1828		 */
1829
1830		Socket.prototype.flushBuffer = function() {
1831			this.transport.payload(this.buffer);
1832			this.buffer = [];
1833		};
1834
1835
1836		/**
1837		 * Disconnect the established connect.
1838		 *
1839		 * @returns {io.Socket}
1840		 * @api public
1841		 */
1842
1843		Socket.prototype.disconnect = function () {
1844			if (this.connected || this.connecting) {
1845				if (this.open) {
1846					this.of('').packet({ type: 'disconnect' });
1847				}
1848
1849				// handle disconnection immediately
1850				this.onDisconnect('booted');
1851			}
1852
1853			return this;
1854		};
1855
1856		/**
1857		 * Disconnects the socket with a sync XHR.
1858		 *
1859		 * @api private
1860		 */
1861
1862		Socket.prototype.disconnectSync = function () {
1863			// ensure disconnection
1864			var xhr = io.util.request();
1865			var uri = [
1866				'http' + (this.options.secure ? 's' : '') + ':/'
1867				, this.options.host + ':' + this.options.port
1868				, this.options.resource
1869				, io.protocol
1870				, ''
1871				, this.sessionid
1872			].join('/') + '/?disconnect=1';
1873
1874			xhr.open('GET', uri, false);
1875			xhr.send(null);
1876
1877			// handle disconnection immediately
1878			this.onDisconnect('booted');
1879		};
1880
1881		/**
1882		 * Check if we need to use cross domain enabled transports. Cross domain would
1883		 * be a different port or different domain name.
1884		 *
1885		 * @returns {Boolean}
1886		 * @api private
1887		 */
1888
1889		Socket.prototype.isXDomain = function () {
1890
1891			var port = global.location.port ||
1892					('https:' == global.location.protocol ? 443 : 80);
1893
1894			return this.options.host !== global.location.hostname
1895					|| this.options.port != port;
1896		};
1897
1898		/**
1899		 * Called upon handshake.
1900		 *
1901		 * @api private
1902		 */
1903
1904		Socket.prototype.onConnect = function () {
1905			if (!this.connected) {
1906				this.connected = true;
1907				this.connecting = false;
1908				if (!this.doBuffer) {
1909					// make sure to flush the buffer
1910					this.setBuffer(false);
1911				}
1912				this.emit('connect');
1913			}
1914		};
1915
1916		/**
1917		 * Called when the transport opens
1918		 *
1919		 * @api private
1920		 */
1921
1922		Socket.prototype.onOpen = function () {
1923			this.open = true;
1924		};
1925
1926		/**
1927		 * Called when the transport closes.
1928		 *
1929		 * @api private
1930		 */
1931
1932		Socket.prototype.onClose = function () {
1933			this.open = false;
1934			clearTimeout(this.heartbeatTimeoutTimer);
1935		};
1936
1937		/**
1938		 * Called when the transport first opens a connection
1939		 *
1940		 * @param text
1941		 */
1942
1943		Socket.prototype.onPacket = function (packet) {
1944			this.of(packet.endpoint).onPacket(packet);
1945		};
1946
1947		/**
1948		 * Handles an error.
1949		 *
1950		 * @api private
1951		 */
1952
1953		Socket.prototype.onError = function (err) {
1954			if (err && err.advice) {
1955				if (err.advice === 'reconnect' && (this.connected || this.connecting)) {
1956					this.disconnect();
1957					if (this.options.reconnect) {
1958						this.reconnect();
1959					}
1960				}
1961			}
1962
1963			this.publish('error', err && err.reason ? err.reason : err);
1964		};
1965
1966		/**
1967		 * Called when the transport disconnects.
1968		 *
1969		 * @api private
1970		 */
1971
1972		Socket.prototype.onDisconnect = function (reason) {
1973			var wasConnected = this.connected
1974					, wasConnecting = this.connecting;
1975
1976			this.connected = false;
1977			this.connecting = false;
1978			this.open = false;
1979
1980			if (wasConnected || wasConnecting) {
1981				this.transport.close();
1982				this.transport.clearTimeouts();
1983				if (wasConnected) {
1984					this.publish('disconnect', reason);
1985
1986					if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
1987						this.reconnect();
1988					}
1989				}
1990			}
1991		};
1992
1993		/**
1994		 * Called upon reconnection.
1995		 *
1996		 * @api private
1997		 */
1998
1999		Socket.prototype.reconnect = function () {
2000			this.reconnecting = true;
2001			this.reconnectionAttempts = 0;
2002			this.reconnectionDelay = this.options['reconnection delay'];
2003
2004			var self = this
2005					, maxAttempts = this.options['max reconnection attempts']
2006					, tryMultiple = this.options['try multiple transports']
2007					, limit = this.options['reconnection limit'];
2008
2009			function reset () {
2010				if (self.connected) {
2011					for (var i in self.namespaces) {
2012						if (self.namespaces.hasOwnProperty(i) && '' !== i) {
2013							self.namespaces[i].packet({ type: 'connect' });
2014						}
2015					}
2016					self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
2017				}
2018
2019				clearTimeout(self.reconnectionTimer);
2020
2021				self.removeListener('connect_failed', maybeReconnect);
2022				self.removeListener('connect', maybeReconnect);
2023
2024				self.reconnecting = false;
2025
2026				delete self.reconnectionAttempts;
2027				delete self.reconnectionDelay;
2028				delete self.reconnectionTimer;
2029				delete self.redoTransports;
2030
2031				self.options['try multiple transports'] = tryMultiple;
2032			};
2033
2034			function maybeReconnect () {
2035				if (!self.reconnecting) {
2036					return;
2037				}
2038
2039				if (self.connected) {
2040					return reset();
2041				};
2042
2043				if (self.connecting && self.reconnecting) {
2044					return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
2045				}
2046
2047				if (self.reconnectionAttempts++ >= maxAttempts) {
2048					if (!self.redoTransports) {
2049						self.on('connect_failed', maybeReconnect);
2050						self.options['try multiple transports'] = true;
2051						self.transports = self.origTransports;
2052						self.transport = self.getTransport();
2053						self.redoTransports = true;
2054						self.connect();
2055					} else {
2056						self.publish('reconnect_failed');
2057						reset();
2058					}
2059				} else {
2060					if (self.reconnectionDelay < limit) {
2061						self.reconnectionDelay *= 2; // exponential back off
2062					}
2063
2064					self.connect();
2065					self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
2066					self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
2067				}
2068			};
2069
2070			this.options['try multiple transports'] = false;
2071			this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
2072
2073			this.on('connect', maybeReconnect);
2074		};
2075
2076	})(
2077			'undefined' != typeof io ? io : module.exports
2078			, 'undefined' != typeof io ? io : module.parent.exports
2079			, this
2080	);
2081	/**
2082	 * socket.io
2083	 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2084	 * MIT Licensed
2085	 */
2086
2087	(function (exports, io) {
2088
2089		/**
2090		 * Expose constructor.
2091		 */
2092
2093		exports.SocketNamespace = SocketNamespace;
2094
2095		/**
2096		 * Socket namespace constructor.
2097		 *
2098		 * @constructor
2099		 * @api public
2100		 */
2101
2102		function SocketNamespace (socket, name) {
2103			this.socket = socket;
2104			this.name = name || '';
2105			this.flags = {};
2106			this.json = new Flag(this, 'json');
2107			this.ackPackets = 0;
2108			this.acks = {};
2109		};
2110
2111		/**
2112		 * Apply EventEmitter mixin.
2113		 */
2114
2115		io.util.mixin(SocketNamespace, io.EventEmitter);
2116
2117		/**
2118		 * Copies emit since we override it
2119		 *
2120		 * @api private
2121		 */
2122
2123		SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
2124
2125		/**
2126		 * Creates a new namespace, by proxying the request to the socket. This
2127		 * allows us to use the synax as we do on the server.
2128		 *
2129		 * @api public
2130		 */
2131
2132		SocketNamespace.prototype.of = function () {
2133			return this.socket.of.apply(this.socket, arguments);
2134		};
2135
2136		/**
2137		 * Sends a packet.
2138		 *
2139		 * @api private
2140		 */
2141
2142		SocketNamespace.prototype.packet = function (packet) {
2143			packet.endpoint = this.name;
2144			this.socket.packet(packet);
2145			this.flags = {};
2146			return this;
2147		};
2148
2149		/**
2150		 * Sends a message
2151		 *
2152		 * @api public
2153		 */
2154
2155		SocketNamespace.prototype.send = function (data, fn) {
2156			var packet = {
2157				type: this.flags.json ? 'json' : 'message'
2158				, data: data
2159			};
2160
2161			if ('function' == typeof fn) {
2162				packet.id = ++this.ackPackets;
2163				packet.ack = true;
2164				this.acks[packet.id] = fn;
2165			}
2166
2167			return this.packet(packet);
2168		};
2169
2170		/**
2171		 * Emits an event
2172		 *
2173		 * @api public
2174		 */
2175
2176		SocketNamespace.prototype.emit = function (name) {
2177			var args = Array.prototype.slice.call(arguments, 1)
2178					, lastArg = args[args.length - 1]
2179					, packet = {
2180						type: 'event'
2181						, name: name
2182					};
2183
2184			if ('function' == typeof lastArg) {
2185				packet.id = ++this.ackPackets;
2186				packet.ack = 'data';
2187				this.acks[packet.id] = lastArg;
2188				args = args.slice(0, args.length - 1);
2189			}
2190
2191			packet.args = args;
2192
2193			return this.packet(packet);
2194		};
2195
2196		/**
2197		 * Disconnects the namespace
2198		 *
2199		 * @api private
2200		 */
2201
2202		SocketNamespace.prototype.disconnect = function () {
2203			if (this.name === '') {
2204				this.socket.disconnect();
2205			} else {
2206				this.packet({ type: 'disconnect' });
2207				this.$emit('disconnect');
2208			}
2209
2210			return this;
2211		};
2212
2213		/**
2214		 * Handles a packet
2215		 *
2216		 * @api private
2217		 */
2218
2219		SocketNamespace.prototype.onPacket = function (packet) {
2220			var self = this;
2221
2222			function ack () {
2223				self.packet({
2224					type: 'ack'
2225					, args: io.util.toArray(arguments)
2226					, ackId: packet.id
2227				});
2228			};
2229
2230			switch (packet.type) {
2231				case 'connect':
2232					this.$emit('connect');
2233					break;
2234
2235				case 'disconnect':
2236					if (this.name === '') {
2237						this.socket.onDisconnect(packet.reason || 'booted');
2238					} else {
2239						this.$emit('disconnect', packet.reason);
2240					}
2241					break;
2242
2243				case 'message':
2244				case 'json':
2245					var params = ['message', packet.data];
2246
2247					if (packet.ack == 'data') {
2248						params.push(ack);
2249					} else if (packet.ack) {
2250						this.packet({ type: 'ack', ackId: packet.id });
2251					}
2252
2253					this.$emit.apply(this, params);
2254					break;
2255
2256				case 'event':
2257					var params = [packet.name].concat(packet.args);
2258
2259					if (packet.ack == 'data')
2260						params.push(ack);
2261
2262					this.$emit.apply(this, params);
2263					break;
2264
2265				case 'ack':
2266					if (this.acks[packet.ackId]) {
2267						this.acks[packet.ackId].apply(this, packet.args);
2268						delete this.acks[packet.ackId];
2269					}
2270					break;
2271
2272				case 'error':
2273					if (packet.advice){
2274						this.socket.onError(packet);
2275					} else {
2276						if (packet.reason == 'unauthorized') {
2277							this.$emit('connect_failed', packet.reason);
2278						} else {
2279							this.$emit('error', packet.reason);
2280						}
2281					}
2282					break;
2283			}
2284		};
2285
2286		/**
2287		 * Flag interface.
2288		 *
2289		 * @api private
2290		 */
2291
2292		function Flag (nsp, name) {
2293			this.namespace = nsp;
2294			this.name = name;
2295		};
2296
2297		/**
2298		 * Send a message
2299		 *
2300		 * @api public
2301		 */
2302
2303		Flag.prototype.send = function () {
2304			this.namespace.flags[this.name] = true;
2305			this.namespace.send.apply(this.namespace, arguments);
2306		};
2307
2308		/**
2309		 * Emit an event
2310		 *
2311		 * @api public
2312		 */
2313
2314		Flag.prototype.emit = function () {
2315			this.namespace.flags[this.name] = true;
2316	

Large files files are truncated, but you can click here to view the full file