UNPKG

91.9 kBJavaScriptView Raw
1/*! Socket.IO.js build:0.7.4, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
2
3/**
4 * socket.io
5 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
6 * MIT Licensed
7 */
8
9(function (exports) {
10
11 /**
12 * IO namespace.
13 *
14 * @namespace
15 */
16
17 var io = exports;
18
19 /**
20 * Socket.IO version
21 *
22 * @api public
23 */
24
25 io.version = '0.7.4';
26
27 /**
28 * Protocol implemented.
29 *
30 * @api public
31 */
32
33 io.protocol = 1;
34
35 /**
36 * Available transports, these will be populated with the available transports
37 *
38 * @api public
39 */
40
41 io.transports = [];
42
43 /**
44 * Keep track of jsonp callbacks.
45 *
46 * @api private
47 */
48
49 io.j = [];
50
51 /**
52 * Keep track of our io.Sockets
53 *
54 * @api private
55 */
56 io.sockets = {};
57
58
59 /**
60 * Manages connections to hosts.
61 *
62 * @param {String} uri
63 * @Param {Boolean} force creation of new socket (defaults to false)
64 * @api public
65 */
66
67 io.connect = function (host, details) {
68 var uri = io.util.parseUri(host)
69 , uuri
70 , socket;
71
72 if ('undefined' != typeof document) {
73 uri.protocol = uri.protocol || document.location.protocol.slice(0, -1);
74 uri.host = uri.host || document.domain;
75 uri.port = uri.port || document.location.port;
76 }
77
78 uuri = io.util.uniqueUri(uri);
79
80 var options = {
81 host: uri.host
82 , secure: uri.protocol == 'https'
83 , port: uri.port || 80
84 };
85 io.util.merge(options, details);
86
87 if (options['force new connection'] || !io.sockets[uuri]) {
88 socket = new io.Socket(options);
89 }
90
91 if (!options['force new connection'] && socket) {
92 io.sockets[uuri] = socket;
93 }
94
95 socket = socket || io.sockets[uuri];
96
97 // if path is different from '' or /
98 return socket.of(uri.path.length > 1 ? uri.path : '');
99 };
100
101})('object' === typeof module ? module.exports : (window.io = {}));
102
103/**
104 * socket.io
105 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
106 * MIT Licensed
107 */
108
109(function (exports) {
110
111 /**
112 * Utilities namespace.
113 *
114 * @namespace
115 */
116
117 var util = exports.util = {};
118
119 /**
120 * Parses an URI
121 *
122 * @author Steven Levithan <stevenlevithan.com> (MIT license)
123 * @api public
124 */
125
126 var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
127
128 var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
129 'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
130 'anchor'];
131
132 util.parseUri = function (str) {
133 var m = re.exec(str || '')
134 , uri = {}
135 , i = 14;
136
137 while (i--) {
138 uri[parts[i]] = m[i] || '';
139 }
140
141 return uri;
142 };
143
144 /**
145 * Produces a unique url that identifies a Socket.IO connection.
146 *
147 * @param {Object} uri
148 * @api public
149 */
150
151 util.uniqueUri = function (uri) {
152 var protocol = uri.protocol
153 , host = uri.host
154 , port = uri.port;
155
156 if ('undefined' != typeof document) {
157 host = host || document.domain;
158 port = port || (protocol == 'https'
159 && document.location.protocol !== 'https:' ? 443 : document.location.port);
160 } else {
161 host = host || 'localhost';
162
163 if (!port && protocol == 'https') {
164 port = 443;
165 }
166 }
167
168 return (protocol || 'http') + '://' + host + ':' + (port || 80);
169 };
170
171 /**
172 * Executes the given function when the page is loaded.
173 *
174 * io.util.load(function () { console.log('page loaded'); });
175 *
176 * @param {Function} fn
177 * @api public
178 */
179
180 var pageLoaded = false;
181
182 util.load = function (fn) {
183 if (document.readyState === 'complete' || pageLoaded) {
184 return fn();
185 }
186
187 util.on(window, 'load', fn, false);
188 };
189
190 /**
191 * Adds an event.
192 *
193 * @api private
194 */
195
196 util.on = function (element, event, fn, capture) {
197 if (element.attachEvent) {
198 element.attachEvent('on' + event, fn);
199 } else {
200 element.addEventListener(event, fn, capture);
201 }
202 };
203
204 /**
205 * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
206 *
207 * @param {Boolean} [xdomain] Create a request that can be used cross domain.
208 * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
209 * @api private
210 */
211
212 util.request = function (xdomain) {
213 if ('undefined' != typeof window) {
214 if (xdomain && window.XDomainRequest) {
215 return new XDomainRequest();
216 };
217
218 if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
219 return new XMLHttpRequest();
220 };
221
222 if (!xdomain) {
223 try {
224 return new window.ActiveXObject('Microsoft.XMLHTTP');
225 } catch(e) { }
226 }
227 }
228
229 return null;
230 };
231
232 /**
233 * XHR based transport constructor.
234 *
235 * @constructor
236 * @api public
237 */
238
239 /**
240 * Change the internal pageLoaded value.
241 */
242
243 if ('undefined' != typeof window) {
244 util.load(function () {
245 pageLoaded = true;
246 });
247 }
248
249 /**
250 * Defers a function to ensure a spinner is not displayed by the browser
251 *
252 * @param {Function} fn
253 * @api public
254 */
255
256 util.defer = function (fn) {
257 if (!util.ua.webkit) {
258 return fn();
259 }
260
261 util.load(function () {
262 setTimeout(fn, 100);
263 });
264 };
265
266 /**
267 * Merges two objects.
268 *
269 * @api public
270 */
271
272 util.merge = function merge (target, additional, deep, lastseen) {
273 var seen = lastseen || []
274 , depth = typeof deep == 'undefined' ? 2 : deep
275 , prop;
276
277 for (prop in additional) {
278 if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
279 if (typeof target[prop] !== 'object' || !depth) {
280 target[prop] = additional[prop];
281 seen.push(additional[prop]);
282 } else {
283 util.merge(target[prop], additional[prop], depth - 1, seen);
284 }
285 }
286 }
287
288 return target;
289 };
290
291 /**
292 * Merges prototypes from objects
293 *
294 * @api public
295 */
296
297 util.mixin = function (ctor, ctor2) {
298 util.merge(ctor.prototype, ctor2.prototype);
299 };
300
301 /**
302 * Shortcut for prototypical and static inheritance.
303 *
304 * @api private
305 */
306
307 util.inherit = function (ctor, ctor2) {
308 ctor.prototype = new ctor2;
309 util.merge(ctor, ctor2);
310 };
311
312 /**
313 * Checks if the given object is an Array.
314 *
315 * io.util.isArray([]); // true
316 * io.util.isArray({}); // false
317 *
318 * @param Object obj
319 * @api public
320 */
321
322 util.isArray = Array.isArray || function (obj) {
323 return Object.prototype.toString.call(obj) === '[object Array]';
324 };
325
326 /**
327 * Intersects values of two arrays into a third
328 *
329 * @api public
330 */
331
332 util.intersect = function (arr, arr2) {
333 var ret = []
334 , longest = arr.length > arr2.length ? arr : arr2
335 , shortest = arr.length > arr2.length ? arr2 : arr
336
337 for (var i = 0, l = shortest.length; i < l; i++) {
338 if (~util.indexOf(longest, shortest[i]))
339 ret.push(shortest[i]);
340 }
341
342 return ret;
343 }
344
345 /**
346 * Array indexOf compatibility.
347 *
348 * @see bit.ly/a5Dxa2
349 * @api public
350 */
351
352 util.indexOf = function (arr, o, i) {
353 if (Array.prototype.indexOf) {
354 return Array.prototype.indexOf.call(arr, o, i);
355 }
356
357 for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
358 ; i < j && arr[i] !== o; i++);
359
360 return j <= i ? -1 : i;
361 };
362
363 /**
364 * Converts enumerables to array.
365 *
366 * @api public
367 */
368
369 util.toArray = function (enu) {
370 var arr = [];
371
372 for (var i = 0, l = enu.length; i < l; i++)
373 arr.push(enu[i]);
374
375 return arr;
376 };
377
378 /**
379 * UA / engines detection namespace.
380 *
381 * @namespace
382 */
383
384 util.ua = {};
385
386 /**
387 * Whether the UA supports CORS for XHR.
388 *
389 * @api public
390 */
391
392 util.ua.hasCORS = 'undefined' != typeof window && window.XMLHttpRequest &&
393 (function () {
394 try {
395 var a = new XMLHttpRequest();
396 } catch (e) {
397 return false;
398 }
399
400 return a.withCredentials != undefined;
401 })();
402
403 /**
404 * Detect webkit.
405 *
406 * @api public
407 */
408
409 util.ua.webkit = 'undefined' != typeof navigator
410 && /webkit/i.test(navigator.userAgent);
411
412})('undefined' != typeof window ? io : module.exports);
413
414/**
415 * socket.io
416 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
417 * MIT Licensed
418 */
419
420(function (exports, io) {
421
422 /**
423 * Expose constructor.
424 */
425
426 exports.EventEmitter = EventEmitter;
427
428 /**
429 * Event emitter constructor.
430 *
431 * @api public.
432 */
433
434 function EventEmitter () {};
435
436 /**
437 * Adds a listener
438 *
439 * @api public
440 */
441
442 EventEmitter.prototype.on = function (name, fn) {
443 if (!this.$events) {
444 this.$events = {};
445 }
446
447 if (!this.$events[name]) {
448 this.$events[name] = fn;
449 } else if (io.util.isArray(this.$events[name])) {
450 this.$events[name].push(fn);
451 } else {
452 this.$events[name] = [this.$events[name], fn];
453 }
454
455 return this;
456 };
457
458 EventEmitter.prototype.addListener = EventEmitter.prototype.on;
459
460 /**
461 * Adds a volatile listener.
462 *
463 * @api public
464 */
465
466 EventEmitter.prototype.once = function (name, fn) {
467 var self = this;
468
469 function on () {
470 self.removeListener(name, on);
471 fn.apply(this, arguments);
472 };
473
474 on.listener = fn;
475 this.on(name, on);
476
477 return this;
478 };
479
480 /**
481 * Removes a listener.
482 *
483 * @api public
484 */
485
486 EventEmitter.prototype.removeListener = function (name, fn) {
487 if (this.$events && this.$events[name]) {
488 var list = this.$events[name];
489
490 if (io.util.isArray(list)) {
491 var pos = -1;
492
493 for (var i = 0, l = list.length; i < l; i++) {
494 if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
495 pos = i;
496 break;
497 }
498 }
499
500 if (pos < 0) {
501 return this;
502 }
503
504 list.splice(pos, 1);
505
506 if (!list.length) {
507 delete this.$events[name];
508 }
509 } else if (list === fn || (list.listener && list.listener === fn)) {
510 delete this.$events[name];
511 }
512 }
513
514 return this;
515 };
516
517 /**
518 * Removes all listeners for an event.
519 *
520 * @api public
521 */
522
523 EventEmitter.prototype.removeAllListeners = function (name) {
524 // TODO: enable this when node 0.5 is stable
525 //if (name === undefined) {
526 //this.$events = {};
527 //return this;
528 //}
529
530 if (this.$events && this.$events[name]) {
531 this.$events[name] = null;
532 }
533
534 return this;
535 };
536
537 /**
538 * Gets all listeners for a certain event.
539 *
540 * @api publci
541 */
542
543 EventEmitter.prototype.listeners = function (name) {
544 if (!this.$events) {
545 this.$events = {};
546 }
547
548 if (!this.$events[name]) {
549 this.$events[name] = [];
550 }
551
552 if (!io.util.isArray(this.$events[name])) {
553 this.$events[name] = [this.$events[name]];
554 }
555
556 return this.$events[name];
557 };
558
559 /**
560 * Emits an event.
561 *
562 * @api public
563 */
564
565 EventEmitter.prototype.emit = function (name) {
566 if (!this.$events) {
567 return false;
568 }
569
570 var handler = this.$events[name];
571
572 if (!handler) {
573 return false;
574 }
575
576 var args = Array.prototype.slice.call(arguments, 1);
577
578 if ('function' == typeof handler) {
579 handler.apply(this, args);
580 } else if (io.util.isArray(handler)) {
581 var listeners = handler.slice();
582
583 for (var i = 0, l = listeners.length; i < l; i++) {
584 listeners[i].apply(this, args);
585 }
586 } else {
587 return false;
588 }
589
590 return true;
591 };
592
593})(
594 'undefined' != typeof io ? io : module.exports
595 , 'undefined' != typeof io ? io : module.parent.exports
596);
597
598/**
599 * socket.io
600 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
601 * MIT Licensed
602 */
603
604/**
605 * Based on JSON2 (http://www.JSON.org/js.html).
606 */
607
608(function (exports, nativeJSON) {
609 "use strict";
610
611 // use native JSON if it's available
612 if (nativeJSON && nativeJSON.parse){
613 return exports.JSON = {
614 parse: nativeJSON.parse
615 , stringify: nativeJSON.stringify
616 }
617 }
618
619 var JSON = exports.JSON = {};
620
621 function f(n) {
622 // Format integers to have at least two digits.
623 return n < 10 ? '0' + n : n;
624 }
625
626 function date(d, key) {
627 return isFinite(d.valueOf()) ?
628 d.getUTCFullYear() + '-' +
629 f(d.getUTCMonth() + 1) + '-' +
630 f(d.getUTCDate()) + 'T' +
631 f(d.getUTCHours()) + ':' +
632 f(d.getUTCMinutes()) + ':' +
633 f(d.getUTCSeconds()) + 'Z' : null;
634 };
635
636 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
637 escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
638 gap,
639 indent,
640 meta = { // table of character substitutions
641 '\b': '\\b',
642 '\t': '\\t',
643 '\n': '\\n',
644 '\f': '\\f',
645 '\r': '\\r',
646 '"' : '\\"',
647 '\\': '\\\\'
648 },
649 rep;
650
651
652 function quote(string) {
653
654// If the string contains no control characters, no quote characters, and no
655// backslash characters, then we can safely slap some quotes around it.
656// Otherwise we must also replace the offending characters with safe escape
657// sequences.
658
659 escapable.lastIndex = 0;
660 return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
661 var c = meta[a];
662 return typeof c === 'string' ? c :
663 '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
664 }) + '"' : '"' + string + '"';
665 }
666
667
668 function str(key, holder) {
669
670// Produce a string from holder[key].
671
672 var i, // The loop counter.
673 k, // The member key.
674 v, // The member value.
675 length,
676 mind = gap,
677 partial,
678 value = holder[key];
679
680// If the value has a toJSON method, call it to obtain a replacement value.
681
682 if (value instanceof Date) {
683 value = date(key);
684 }
685
686// If we were called with a replacer function, then call the replacer to
687// obtain a replacement value.
688
689 if (typeof rep === 'function') {
690 value = rep.call(holder, key, value);
691 }
692
693// What happens next depends on the value's type.
694
695 switch (typeof value) {
696 case 'string':
697 return quote(value);
698
699 case 'number':
700
701// JSON numbers must be finite. Encode non-finite numbers as null.
702
703 return isFinite(value) ? String(value) : 'null';
704
705 case 'boolean':
706 case 'null':
707
708// If the value is a boolean or null, convert it to a string. Note:
709// typeof null does not produce 'null'. The case is included here in
710// the remote chance that this gets fixed someday.
711
712 return String(value);
713
714// If the type is 'object', we might be dealing with an object or an array or
715// null.
716
717 case 'object':
718
719// Due to a specification blunder in ECMAScript, typeof null is 'object',
720// so watch out for that case.
721
722 if (!value) {
723 return 'null';
724 }
725
726// Make an array to hold the partial results of stringifying this object value.
727
728 gap += indent;
729 partial = [];
730
731// Is the value an array?
732
733 if (Object.prototype.toString.apply(value) === '[object Array]') {
734
735// The value is an array. Stringify every element. Use null as a placeholder
736// for non-JSON values.
737
738 length = value.length;
739 for (i = 0; i < length; i += 1) {
740 partial[i] = str(i, value) || 'null';
741 }
742
743// Join all of the elements together, separated with commas, and wrap them in
744// brackets.
745
746 v = partial.length === 0 ? '[]' : gap ?
747 '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
748 '[' + partial.join(',') + ']';
749 gap = mind;
750 return v;
751 }
752
753// If the replacer is an array, use it to select the members to be stringified.
754
755 if (rep && typeof rep === 'object') {
756 length = rep.length;
757 for (i = 0; i < length; i += 1) {
758 if (typeof rep[i] === 'string') {
759 k = rep[i];
760 v = str(k, value);
761 if (v) {
762 partial.push(quote(k) + (gap ? ': ' : ':') + v);
763 }
764 }
765 }
766 } else {
767
768// Otherwise, iterate through all of the keys in the object.
769
770 for (k in value) {
771 if (Object.prototype.hasOwnProperty.call(value, k)) {
772 v = str(k, value);
773 if (v) {
774 partial.push(quote(k) + (gap ? ': ' : ':') + v);
775 }
776 }
777 }
778 }
779
780// Join all of the member texts together, separated with commas,
781// and wrap them in braces.
782
783 v = partial.length === 0 ? '{}' : gap ?
784 '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
785 '{' + partial.join(',') + '}';
786 gap = mind;
787 return v;
788 }
789 }
790
791// If the JSON object does not yet have a stringify method, give it one.
792
793 JSON.stringify = function (value, replacer, space) {
794
795// The stringify method takes a value and an optional replacer, and an optional
796// space parameter, and returns a JSON text. The replacer can be a function
797// that can replace values, or an array of strings that will select the keys.
798// A default replacer method can be provided. Use of the space parameter can
799// produce text that is more easily readable.
800
801 var i;
802 gap = '';
803 indent = '';
804
805// If the space parameter is a number, make an indent string containing that
806// many spaces.
807
808 if (typeof space === 'number') {
809 for (i = 0; i < space; i += 1) {
810 indent += ' ';
811 }
812
813// If the space parameter is a string, it will be used as the indent string.
814
815 } else if (typeof space === 'string') {
816 indent = space;
817 }
818
819// If there is a replacer, it must be a function or an array.
820// Otherwise, throw an error.
821
822 rep = replacer;
823 if (replacer && typeof replacer !== 'function' &&
824 (typeof replacer !== 'object' ||
825 typeof replacer.length !== 'number')) {
826 throw new Error('JSON.stringify');
827 }
828
829// Make a fake root object containing our value under the key of ''.
830// Return the result of stringifying the value.
831
832 return str('', {'': value});
833 };
834
835// If the JSON object does not yet have a parse method, give it one.
836
837 JSON.parse = function (text, reviver) {
838 // The parse method takes a text and an optional reviver function, and returns
839 // a JavaScript value if the text is a valid JSON text.
840
841 var j;
842
843 function walk(holder, key) {
844
845 // The walk method is used to recursively walk the resulting structure so
846 // that modifications can be made.
847
848 var k, v, value = holder[key];
849 if (value && typeof value === 'object') {
850 for (k in value) {
851 if (Object.prototype.hasOwnProperty.call(value, k)) {
852 v = walk(value, k);
853 if (v !== undefined) {
854 value[k] = v;
855 } else {
856 delete value[k];
857 }
858 }
859 }
860 }
861 return reviver.call(holder, key, value);
862 }
863
864
865 // Parsing happens in four stages. In the first stage, we replace certain
866 // Unicode characters with escape sequences. JavaScript handles many characters
867 // incorrectly, either silently deleting them, or treating them as line endings.
868
869 text = String(text);
870 cx.lastIndex = 0;
871 if (cx.test(text)) {
872 text = text.replace(cx, function (a) {
873 return '\\u' +
874 ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
875 });
876 }
877
878 // In the second stage, we run the text against regular expressions that look
879 // for non-JSON patterns. We are especially concerned with '()' and 'new'
880 // because they can cause invocation, and '=' because it can cause mutation.
881 // But just to be safe, we want to reject all unexpected forms.
882
883 // We split the second stage into 4 regexp operations in order to work around
884 // crippling inefficiencies in IE's and Safari's regexp engines. First we
885 // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
886 // replace all simple value tokens with ']' characters. Third, we delete all
887 // open brackets that follow a colon or comma or that begin the text. Finally,
888 // we look to see that the remaining characters are only whitespace or ']' or
889 // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
890
891 if (/^[\],:{}\s]*$/
892 .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
893 .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
894 .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
895
896 // In the third stage we use the eval function to compile the text into a
897 // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
898 // in JavaScript: it can begin a block or an object literal. We wrap the text
899 // in parens to eliminate the ambiguity.
900
901 j = eval('(' + text + ')');
902
903 // In the optional fourth stage, we recursively walk the new structure, passing
904 // each name/value pair to a reviver function for possible transformation.
905
906 return typeof reviver === 'function' ?
907 walk({'': j}, '') : j;
908 }
909
910 // If the text is not JSON parseable, then a SyntaxError is thrown.
911
912 throw new SyntaxError('JSON.parse');
913 };
914
915})(
916 'undefined' != typeof io ? io : module.exports
917 , typeof JSON !== 'undefined' ? JSON : undefined
918);
919
920/**
921 * socket.io
922 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
923 * MIT Licensed
924 */
925
926(function (exports, io) {
927
928 /**
929 * Parser namespace.
930 *
931 * @namespace
932 */
933
934 var parser = exports.parser = {};
935
936 /**
937 * Packet types.
938 */
939
940 var packets = parser.packets = [
941 'disconnect'
942 , 'connect'
943 , 'heartbeat'
944 , 'message'
945 , 'json'
946 , 'event'
947 , 'ack'
948 , 'error'
949 , 'noop'
950 ];
951
952 /**
953 * Errors reasons.
954 */
955
956 var reasons = parser.reasons = [
957 'transport not supported'
958 , 'client not handshaken'
959 , 'unauthorized'
960 ];
961
962 /**
963 * Errors advice.
964 */
965
966 var advice = parser.advice = [
967 'reconnect'
968 ];
969
970 /**
971 * Shortcuts.
972 */
973
974 var JSON = io.JSON
975 , indexOf = io.util.indexOf;
976
977 /**
978 * Encodes a packet.
979 *
980 * @api private
981 */
982
983 parser.encodePacket = function (packet) {
984 var type = indexOf(packets, packet.type)
985 , id = packet.id || ''
986 , endpoint = packet.endpoint || ''
987 , ack = packet.ack
988 , data = null;
989
990 switch (packet.type) {
991 case 'error':
992 var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
993 , adv = packet.advice ? indexOf(advice, packet.advice) : ''
994
995 if (reason !== '' || adv !== '')
996 data = reason + (adv !== '' ? ('+' + adv) : '')
997
998 break;
999
1000 case 'message':
1001 if (packet.data !== '')
1002 data = packet.data;
1003 break;
1004
1005 case 'event':
1006 var ev = { name: packet.name };
1007
1008 if (packet.args && packet.args.length) {
1009 ev.args = packet.args;
1010 }
1011
1012 data = JSON.stringify(ev);
1013 break;
1014
1015 case 'json':
1016 data = JSON.stringify(packet.data);
1017 break;
1018
1019 case 'connect':
1020 if (packet.qs)
1021 data = packet.qs;
1022 break;
1023
1024 case 'ack':
1025 data = packet.ackId
1026 + (packet.args && packet.args.length
1027 ? '+' + JSON.stringify(packet.args) : '');
1028 break;
1029 }
1030
1031 // construct packet with required fragments
1032 var encoded = [
1033 type
1034 , id + (ack == 'data' ? '+' : '')
1035 , endpoint
1036 ];
1037
1038 // data fragment is optional
1039 if (data !== null && data !== undefined)
1040 encoded.push(data);
1041
1042 return encoded.join(':');
1043 };
1044
1045 /**
1046 * Encodes multiple messages (payload).
1047 *
1048 * @param {Array} messages
1049 * @api private
1050 */
1051
1052 parser.encodePayload = function (packets) {
1053 var decoded = '';
1054
1055 if (packets.length == 1)
1056 return packets[0];
1057
1058 for (var i = 0, l = packets.length; i < l; i++) {
1059 var packet = packets[i];
1060 decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
1061 }
1062
1063 return decoded;
1064 };
1065
1066 /**
1067 * Decodes a packet
1068 *
1069 * @api private
1070 */
1071
1072 var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
1073
1074 parser.decodePacket = function (data) {
1075 var pieces = data.match(regexp);
1076
1077 if (!pieces) return {};
1078
1079 var id = pieces[2] || ''
1080 , data = pieces[5] || ''
1081 , packet = {
1082 type: packets[pieces[1]]
1083 , endpoint: pieces[4] || ''
1084 };
1085
1086 // whether we need to acknowledge the packet
1087 if (id) {
1088 packet.id = id;
1089 if (pieces[3])
1090 packet.ack = 'data';
1091 else
1092 packet.ack = true;
1093 }
1094
1095 // handle different packet types
1096 switch (packet.type) {
1097 case 'error':
1098 var pieces = data.split('+');
1099 packet.reason = reasons[pieces[0]] || '';
1100 packet.advice = advice[pieces[1]] || '';
1101 break;
1102
1103 case 'message':
1104 packet.data = data || '';
1105 break;
1106
1107 case 'event':
1108 try {
1109 var opts = JSON.parse(data);
1110 packet.name = opts.name;
1111 packet.args = opts.args;
1112 } catch (e) { }
1113
1114 packet.args = packet.args || [];
1115 break;
1116
1117 case 'json':
1118 try {
1119 packet.data = JSON.parse(data);
1120 } catch (e) { }
1121 break;
1122
1123 case 'connect':
1124 packet.qs = data || '';
1125 break;
1126
1127 case 'ack':
1128 var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
1129 if (pieces) {
1130 packet.ackId = pieces[1];
1131 packet.args = [];
1132
1133 if (pieces[3]) {
1134 try {
1135 packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
1136 } catch (e) { }
1137 }
1138 }
1139 break;
1140
1141 case 'disconnect':
1142 case 'heartbeat':
1143 break;
1144 };
1145
1146 return packet;
1147 };
1148
1149 /**
1150 * Decodes data payload. Detects multiple messages
1151 *
1152 * @return {Array} messages
1153 * @api public
1154 */
1155
1156 parser.decodePayload = function (data) {
1157 // IE doesn't like data[i] for unicode chars, charAt works fine
1158 if (data.charAt(0) == '\ufffd') {
1159 var ret = [];
1160
1161 for (var i = 1, length = ''; i < data.length; i++) {
1162 if (data.charAt(i) == '\ufffd') {
1163 ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
1164 i += Number(length) + 1;
1165 length = '';
1166 } else {
1167 length += data.charAt(i);
1168 }
1169 }
1170
1171 return ret;
1172 } else {
1173 return [parser.decodePacket(data)];
1174 }
1175 };
1176
1177})(
1178 'undefined' != typeof io ? io : module.exports
1179 , 'undefined' != typeof io ? io : module.parent.exports
1180);
1181
1182/**
1183 * socket.io
1184 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1185 * MIT Licensed
1186 */
1187
1188(function (exports, io) {
1189
1190 /**
1191 * Expose constructor.
1192 */
1193
1194 exports.Transport = Transport;
1195
1196 /**
1197 * This is the transport template for all supported transport methods.
1198 *
1199 * @constructor
1200 * @api public
1201 */
1202
1203 function Transport (socket, sessid) {
1204 this.socket = socket;
1205 this.sessid = sessid;
1206 };
1207
1208 /**
1209 * Apply EventEmitter mixin.
1210 */
1211
1212 io.util.mixin(Transport, io.EventEmitter);
1213
1214 /**
1215 * Handles the response from the server. When a new response is received
1216 * it will automatically update the timeout, decode the message and
1217 * forwards the response to the onMessage function for further processing.
1218 *
1219 * @param {String} data Response from the server.
1220 * @api private
1221 */
1222
1223 Transport.prototype.onData = function (data) {
1224 this.clearCloseTimeout();
1225 this.setCloseTimeout();
1226
1227 if (data !== '') {
1228 // todo: we should only do decodePayload for xhr transports
1229 var msgs = io.parser.decodePayload(data);
1230
1231 if (msgs && msgs.length) {
1232 for (var i = 0, l = msgs.length; i < l; i++) {
1233 this.onPacket(msgs[i]);
1234 }
1235 }
1236 }
1237
1238 return this;
1239 };
1240
1241 /**
1242 * Handles packets.
1243 *
1244 * @api private
1245 */
1246
1247 Transport.prototype.onPacket = function (packet) {
1248 if (packet.type == 'heartbeat') {
1249 return this.onHeartbeat();
1250 }
1251
1252 if (packet.type == 'connect' && packet.endpoint == '') {
1253 this.onConnect();
1254 }
1255
1256 this.socket.onPacket(packet);
1257
1258 return this;
1259 };
1260
1261 /**
1262 * Sets close timeout
1263 *
1264 * @api private
1265 */
1266
1267 Transport.prototype.setCloseTimeout = function () {
1268 if (!this.closeTimeout) {
1269 var self = this;
1270
1271 this.closeTimeout = setTimeout(function () {
1272 self.onDisconnect();
1273 }, this.socket.closeTimeout);
1274 }
1275 };
1276
1277 /**
1278 * Called when transport disconnects.
1279 *
1280 * @api private
1281 */
1282
1283 Transport.prototype.onDisconnect = function () {
1284 if (this.close) this.close();
1285 this.clearTimeouts();
1286 this.socket.onDisconnect();
1287 return this;
1288 };
1289
1290 /**
1291 * Called when transport connects
1292 *
1293 * @api private
1294 */
1295
1296 Transport.prototype.onConnect = function () {
1297 this.socket.onConnect();
1298 return this;
1299 }
1300
1301 /**
1302 * Clears close timeout
1303 *
1304 * @api private
1305 */
1306
1307 Transport.prototype.clearCloseTimeout = function () {
1308 if (this.closeTimeout) {
1309 clearTimeout(this.closeTimeout);
1310 this.closeTimeout = null;
1311 }
1312 };
1313
1314 /**
1315 * Clear timeouts
1316 *
1317 * @api private
1318 */
1319
1320 Transport.prototype.clearTimeouts = function () {
1321 this.clearCloseTimeout();
1322
1323 if (this.reopenTimeout) {
1324 clearTimeout(this.reopenTimeout);
1325 }
1326 };
1327
1328 /**
1329 * Sends a packet
1330 *
1331 * @param {Object} packet object.
1332 * @api private
1333 */
1334
1335 Transport.prototype.packet = function (packet) {
1336 this.send(io.parser.encodePacket(packet));
1337 };
1338
1339 /**
1340 * Send the received heartbeat message back to server. So the server
1341 * knows we are still connected.
1342 *
1343 * @param {String} heartbeat Heartbeat response from the server.
1344 * @api private
1345 */
1346
1347 Transport.prototype.onHeartbeat = function (heartbeat) {
1348 this.packet({ type: 'heartbeat' });
1349 };
1350
1351 /**
1352 * Called when the transport opens.
1353 *
1354 * @api private
1355 */
1356
1357 Transport.prototype.onOpen = function () {
1358 this.open = true;
1359 this.clearCloseTimeout();
1360 this.socket.onOpen();
1361 };
1362
1363 /**
1364 * Notifies the base when the connection with the Socket.IO server
1365 * has been disconnected.
1366 *
1367 * @api private
1368 */
1369
1370 Transport.prototype.onClose = function () {
1371 var self = this;
1372
1373 /* FIXME: reopen delay causing a infinit loop
1374 this.reopenTimeout = setTimeout(function () {
1375 self.open();
1376 }, this.socket.options['reopen delay']);*/
1377
1378 this.open = false;
1379 this.setCloseTimeout();
1380 this.socket.onClose();
1381 };
1382
1383 /**
1384 * Generates a connection url based on the Socket.IO URL Protocol.
1385 * See <https://github.com/learnboost/socket.io-node/> for more details.
1386 *
1387 * @returns {String} Connection url
1388 * @api private
1389 */
1390
1391 Transport.prototype.prepareUrl = function () {
1392 var options = this.socket.options;
1393
1394 return this.scheme() + '://'
1395 + options.host + ':' + options.port + '/'
1396 + options.resource + '/' + io.protocol
1397 + '/' + this.name + '/' + this.sessid;
1398 };
1399})(
1400 'undefined' != typeof io ? io : module.exports
1401 , 'undefined' != typeof io ? io : module.parent.exports
1402);
1403
1404/**
1405 * socket.io
1406 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1407 * MIT Licensed
1408 */
1409
1410(function (exports, io) {
1411
1412 /**
1413 * Expose constructor.
1414 */
1415
1416 exports.Socket = Socket;
1417
1418 /**
1419 * Create a new `Socket.IO client` which can establish a persisent
1420 * connection with a Socket.IO enabled server.
1421 *
1422 * @api public
1423 */
1424
1425 function Socket (options) {
1426 this.options = {
1427 port: 80
1428 , secure: false
1429 , document: document
1430 , resource: 'socket.io'
1431 , transports: io.transports
1432 , 'connect timeout': 10000
1433 , 'try multiple transports': true
1434 , 'reconnect': true
1435 , 'reconnection delay': 500
1436 , 'reopen delay': 3000
1437 , 'max reconnection attempts': 10
1438 , 'sync disconnect on unload': true
1439 , 'auto connect': true
1440 };
1441
1442 io.util.merge(this.options, options);
1443
1444 this.connected = false;
1445 this.open = false;
1446 this.connecting = false;
1447 this.reconnecting = false;
1448 this.namespaces = {};
1449 this.buffer = [];
1450 this.doBuffer = false;
1451
1452 if (this.options['sync disconnect on unload'] &&
1453 (!this.isXDomain() || io.util.ua.hasCORS)) {
1454 var self = this;
1455
1456 io.util.on(window, 'beforeunload', function () {
1457 self.disconnectSync();
1458 }, false);
1459 }
1460
1461 if (this.options['auto connect']) {
1462 this.connect();
1463 }
1464};
1465
1466 /**
1467 * Apply EventEmitter mixin.
1468 */
1469
1470 io.util.mixin(Socket, io.EventEmitter);
1471
1472 /**
1473 * Returns a namespace listener/emitter for this socket
1474 *
1475 * @api public
1476 */
1477
1478 Socket.prototype.of = function (name) {
1479 if (!this.namespaces[name]) {
1480 this.namespaces[name] = new io.SocketNamespace(this, name);
1481
1482 if (name !== '') {
1483 this.namespaces[name].packet({ type: 'connect' });
1484 }
1485 }
1486
1487 return this.namespaces[name];
1488 };
1489
1490 /**
1491 * Emits the given event to the Socket and all namespaces
1492 *
1493 * @api private
1494 */
1495
1496 Socket.prototype.publish = function () {
1497 this.emit.apply(this, arguments);
1498
1499 var nsp;
1500
1501 for (var i in this.namespaces) {
1502 if (this.namespaces.hasOwnProperty(i)) {
1503 nsp = this.of(i);
1504 nsp.$emit.apply(nsp, arguments);
1505 }
1506 }
1507 };
1508
1509 /**
1510 * Performs the handshake
1511 *
1512 * @api private
1513 */
1514
1515 function empty () { };
1516
1517 Socket.prototype.handshake = function (fn) {
1518 var self = this
1519 , options = this.options;
1520
1521 function complete (data) {
1522 if (data instanceof Error) {
1523 self.onError(data.message);
1524 } else {
1525 fn.apply(null, data.split(':'));
1526 }
1527 };
1528
1529 var url = [
1530 'http' + (options.secure ? 's' : '') + ':/'
1531 , options.host + ':' + options.port
1532 , this.options.resource
1533 , io.protocol
1534 , '?t=' + + new Date
1535 ].join('/');
1536
1537 if (this.isXDomain()) {
1538 var insertAt = document.getElementsByTagName('script')[0]
1539 , script = document.createElement('SCRIPT');
1540
1541 script.src = url + '&jsonp=' + io.j.length;
1542 insertAt.parentNode.insertBefore(script, insertAt);
1543
1544 io.j.push(function (data) {
1545 complete(data);
1546 script.parentNode.removeChild(script);
1547 });
1548 } else {
1549 var xhr = io.util.request();
1550
1551 xhr.open('GET', url);
1552 xhr.onreadystatechange = function () {
1553 if (xhr.readyState == 4) {
1554 xhr.onreadystatechange = empty;
1555
1556 if (xhr.status == 200) {
1557 complete(xhr.responseText);
1558 } else {
1559 !self.reconnecting && self.onError(xhr.responseText);
1560 }
1561 }
1562 };
1563 xhr.send(null);
1564 }
1565 };
1566
1567 /**
1568 * Find an available transport based on the options supplied in the constructor.
1569 *
1570 * @api private
1571 */
1572
1573 Socket.prototype.getTransport = function (override) {
1574 var transports = override || this.transports, match;
1575
1576 for (var i = 0, transport; transport = transports[i]; i++) {
1577 if (io.Transport[transport]
1578 && io.Transport[transport].check(this)
1579 && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
1580 return new io.Transport[transport](this, this.sessionid);
1581 }
1582 }
1583
1584 return null;
1585 };
1586
1587 /**
1588 * Connects to the server.
1589 *
1590 * @param {Function} [fn] Callback.
1591 * @returns {io.Socket}
1592 * @api public
1593 */
1594
1595 Socket.prototype.connect = function (fn) {
1596 if (this.connecting) {
1597 return this;
1598 }
1599
1600 var self = this;
1601
1602 this.handshake(function (sid, heartbeat, close, transports) {
1603 self.sessionid = sid;
1604 self.closeTimeout = close * 1000;
1605 self.heartbeatTimeout = heartbeat * 1000;
1606 self.transports = io.util.intersect(
1607 transports.split(',')
1608 , self.options.transports
1609 );
1610
1611 function connect (transports){
1612 self.transport = self.getTransport(transports);
1613 if (!self.transport) return self.publish('connect_failed');
1614
1615 self.connecting = true;
1616 self.publish('connecting', self.transport.name);
1617 self.transport.open();
1618
1619 if (self.options['connect timeout']) {
1620 self.connectTimeoutTimer = setTimeout(function () {
1621 if (!self.connected) {
1622 self.connecting = false;
1623
1624 if (self.options['try multiple transports']) {
1625 if (!self.remainingTransports) {
1626 self.remainingTransports = self.transports.slice(0);
1627 }
1628
1629 var remaining = self.remainingTransports;
1630
1631 while (remaining.length > 0 && remaining.splice(0,1)[0] !=
1632 self.transport.name) {}
1633
1634 if (remaining.length){
1635 connect(remaining);
1636 } else {
1637 self.publish('connect_failed');
1638 }
1639 }
1640 }
1641 }, self.options['connect timeout']);
1642 }
1643 }
1644
1645 connect();
1646
1647 self.once('connect', function (){
1648 clearTimeout(self.connectTimeoutTimer);
1649
1650 fn && typeof fn == 'function' && fn();
1651 });
1652 });
1653
1654 return this;
1655 };
1656
1657 /**
1658 * Sends a message.
1659 *
1660 * @param {Object} data packet.
1661 * @returns {io.Socket}
1662 * @api public
1663 */
1664
1665 Socket.prototype.packet = function (data) {
1666 if (this.connected && !this.doBuffer) {
1667 this.transport.packet(data);
1668 } else {
1669 this.buffer.push(data);
1670 }
1671
1672 return this;
1673 };
1674
1675 /**
1676 * Sets buffer state
1677 *
1678 * @api private
1679 */
1680
1681 Socket.prototype.setBuffer = function (v) {
1682 this.doBuffer = v;
1683
1684 if (!v && this.connected && this.buffer.length) {
1685 this.transport.payload(this.buffer);
1686 this.buffer = [];
1687 }
1688 };
1689
1690 /**
1691 * Disconnect the established connect.
1692 *
1693 * @returns {io.Socket}
1694 * @api public
1695 */
1696
1697 Socket.prototype.disconnect = function () {
1698 if (this.connected) {
1699 if (this.open) {
1700 this.of('').packet({ type: 'disconnect' });
1701 }
1702
1703 // handle disconnection immediately
1704 this.onDisconnect('booted');
1705 }
1706
1707 return this;
1708 };
1709
1710 /**
1711 * Disconnects the socket with a sync XHR.
1712 *
1713 * @api private
1714 */
1715
1716 Socket.prototype.disconnectSync = function () {
1717 // ensure disconnection
1718 var xhr = io.util.request()
1719 , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;
1720
1721 xhr.open('GET', uri, true);
1722
1723 // handle disconnection immediately
1724 this.onDisconnect('booted');
1725 };
1726
1727 /**
1728 * Check if we need to use cross domain enabled transports. Cross domain would
1729 * be a different port or different domain name.
1730 *
1731 * @returns {Boolean}
1732 * @api private
1733 */
1734
1735 Socket.prototype.isXDomain = function () {
1736 var locPort = window.location.port || 80;
1737 return this.options.host !== document.domain || this.options.port != locPort;
1738 };
1739
1740 /**
1741 * Called upon handshake.
1742 *
1743 * @api private
1744 */
1745
1746 Socket.prototype.onConnect = function () {
1747 this.connected = true;
1748 this.connecting = false;
1749 if (!this.doBuffer) {
1750 // make sure to flush the buffer
1751 this.setBuffer(false);
1752 }
1753 this.emit('connect');
1754 };
1755
1756 /**
1757 * Called when the transport opens
1758 *
1759 * @api private
1760 */
1761
1762 Socket.prototype.onOpen = function () {
1763 this.open = true;
1764 };
1765
1766 /**
1767 * Called when the transport closes.
1768 *
1769 * @api private
1770 */
1771
1772 Socket.prototype.onClose = function () {
1773 this.open = false;
1774 };
1775
1776 /**
1777 * Called when the transport first opens a connection
1778 *
1779 * @param text
1780 */
1781
1782 Socket.prototype.onPacket = function (packet) {
1783 this.of(packet.endpoint).onPacket(packet);
1784 };
1785
1786 /**
1787 * Handles an error.
1788 *
1789 * @api private
1790 */
1791
1792 Socket.prototype.onError = function (err) {
1793 if (err && err.advice) {
1794 if (err.advice === 'reconnect' && this.connected) {
1795 this.disconnect();
1796 this.reconnect();
1797 }
1798 }
1799
1800 this.publish('error', err && err.reason ? err.reason : err);
1801 };
1802
1803 /**
1804 * Called when the transport disconnects.
1805 *
1806 * @api private
1807 */
1808
1809 Socket.prototype.onDisconnect = function (reason) {
1810 var wasConnected = this.connected;
1811
1812 this.connected = false;
1813 this.connecting = false;
1814 this.open = false;
1815
1816 if (wasConnected) {
1817 this.transport.close();
1818 this.transport.clearTimeouts();
1819 this.publish('disconnect', reason);
1820
1821 if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
1822 this.reconnect();
1823 }
1824 }
1825 };
1826
1827 /**
1828 * Called upon reconnection.
1829 *
1830 * @api private
1831 */
1832
1833 Socket.prototype.reconnect = function () {
1834 this.reconnecting = true;
1835 this.reconnectionAttempts = 0;
1836 this.reconnectionDelay = this.options['reconnection delay'];
1837
1838 var self = this
1839 , maxAttempts = this.options['max reconnection attempts']
1840 , tryMultiple = this.options['try multiple transports']
1841
1842 function reset () {
1843 if (self.connected) {
1844 self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
1845 }
1846
1847 self.removeListener('connect_failed', maybeReconnect);
1848 self.removeListener('connect', maybeReconnect);
1849
1850 self.reconnecting = false;
1851
1852 delete self.reconnectionAttempts;
1853 delete self.reconnectionDelay;
1854 delete self.reconnectionTimer;
1855 delete self.redoTransports;
1856
1857 self.options['try multiple transports'] = tryMultiple;
1858 };
1859
1860 function maybeReconnect () {
1861 if (!self.reconnecting) {
1862 return;
1863 }
1864
1865 if (self.connected) {
1866 return reset();
1867 };
1868
1869 if (self.connecting && self.reconnecting) {
1870 return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
1871 }
1872
1873 if (self.reconnectionAttempts++ >= maxAttempts) {
1874 if (!self.redoTransports) {
1875 self.on('connect_failed', maybeReconnect);
1876 self.options['try multiple transports'] = true;
1877 self.transport = self.getTransport();
1878 self.redoTransports = true;
1879 self.connect();
1880 } else {
1881 self.publish('reconnect_failed');
1882 reset();
1883 }
1884 } else {
1885 self.reconnectionDelay *= 2; // exponential back off
1886 self.connect();
1887 self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
1888 self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
1889 }
1890 };
1891
1892 this.options['try multiple transports'] = false;
1893 this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
1894
1895 this.on('connect', maybeReconnect);
1896 };
1897
1898})(
1899 'undefined' != typeof io ? io : module.exports
1900 , 'undefined' != typeof io ? io : module.parent.exports
1901);
1902/**
1903 * socket.io
1904 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1905 * MIT Licensed
1906 */
1907
1908(function (exports, io) {
1909
1910 /**
1911 * Expose constructor.
1912 */
1913
1914 exports.SocketNamespace = SocketNamespace;
1915
1916 /**
1917 * Socket namespace constructor.
1918 *
1919 * @constructor
1920 * @api public
1921 */
1922
1923 function SocketNamespace (socket, name) {
1924 this.socket = socket;
1925 this.name = name || '';
1926 this.flags = {};
1927 this.json = new Flag(this, 'json');
1928 this.ackPackets = 0;
1929 this.acks = {};
1930 };
1931
1932 /**
1933 * Apply EventEmitter mixin.
1934 */
1935
1936 io.util.mixin(SocketNamespace, io.EventEmitter);
1937
1938 /**
1939 * Copies emit since we override it
1940 *
1941 * @api private
1942 */
1943
1944 SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
1945
1946 /**
1947 * Creates a new namespace, by proxying the request to the socket. This
1948 * allows us to use the synax as we do on the server.
1949 *
1950 * @api public
1951 */
1952
1953 SocketNamespace.prototype.of = function () {
1954 return this.socket.of.apply(this.socket, arguments);
1955 };
1956
1957 /**
1958 * Sends a packet.
1959 *
1960 * @api private
1961 */
1962
1963 SocketNamespace.prototype.packet = function (packet) {
1964 packet.endpoint = this.name;
1965 this.socket.packet(packet);
1966 this.flags = {};
1967 return this;
1968 };
1969
1970 /**
1971 * Sends a message
1972 *
1973 * @api public
1974 */
1975
1976 SocketNamespace.prototype.send = function (data, fn) {
1977 var packet = {
1978 type: this.flags.json ? 'json' : 'message'
1979 , data: data
1980 };
1981
1982 if ('function' == typeof fn) {
1983 packet.id = ++this.ackPackets;
1984 packet.ack = true;
1985 this.acks[packet.id] = fn;
1986 }
1987
1988 return this.packet(packet);
1989 };
1990
1991 /**
1992 * Emits an event
1993 *
1994 * @api public
1995 */
1996
1997 SocketNamespace.prototype.emit = function (name) {
1998 var args = Array.prototype.slice.call(arguments, 1)
1999 , lastArg = args[args.length - 1]
2000 , packet = {
2001 type: 'event'
2002 , name: name
2003 };
2004
2005 if ('function' == typeof lastArg) {
2006 packet.id = ++this.ackPackets;
2007 packet.ack = 'data';
2008 this.acks[packet.id] = lastArg;
2009 args = args.slice(0, args.length - 1);
2010 }
2011
2012 packet.args = args;
2013
2014 return this.packet(packet);
2015 };
2016
2017 /**
2018 * Disconnects the namespace
2019 *
2020 * @api private
2021 */
2022
2023 SocketNamespace.prototype.disconnect = function () {
2024 if (this.name === '') {
2025 this.socket.disconnect();
2026 } else {
2027 this.packet({ type: 'disconnect' });
2028 this.$emit('disconnect');
2029 }
2030
2031 return this;
2032 };
2033
2034 /**
2035 * Handles a packet
2036 *
2037 * @api private
2038 */
2039
2040 SocketNamespace.prototype.onPacket = function (packet) {
2041 var self = this;
2042
2043 function ack () {
2044 self.packet({
2045 type: 'ack'
2046 , args: io.util.toArray(arguments)
2047 , ackId: packet.id
2048 });
2049 };
2050
2051 switch (packet.type) {
2052 case 'connect':
2053 this.$emit('connect');
2054 break;
2055
2056 case 'disconnect':
2057 if (this.name === '') {
2058 this.socket.onDisconnect(packet.reason || 'booted');
2059 } else {
2060 this.$emit('disconnect', packet.reason);
2061 }
2062 break;
2063
2064 case 'message':
2065 case 'json':
2066 var params = ['message', packet.data];
2067
2068 if (packet.ack == 'data') {
2069 params.push(ack);
2070 } else if (packet.ack) {
2071 this.packet({ type: 'ack', ackId: packet.id });
2072 }
2073
2074 this.$emit.apply(this, params);
2075 break;
2076
2077 case 'event':
2078 var params = [packet.name].concat(packet.args);
2079
2080 if (packet.ack == 'data')
2081 params.push(ack);
2082
2083 this.$emit.apply(this, params);
2084 break;
2085
2086 case 'ack':
2087 if (this.acks[packet.ackId]) {
2088 this.acks[packet.ackId].apply(this, packet.args);
2089 delete this.acks[packet.ackId];
2090 }
2091 break;
2092
2093 case 'error':
2094 if (packet.advice){
2095 this.socket.onError(packet);
2096 } else {
2097 if (packet.reason == 'unauthorized') {
2098 this.$emit('connect_failed', packet.reason);
2099 } else {
2100 this.$emit('error', packet.reason);
2101 }
2102 }
2103 break;
2104 }
2105 };
2106
2107 /**
2108 * Flag interface.
2109 *
2110 * @api private
2111 */
2112
2113 function Flag (nsp, name) {
2114 this.namespace = nsp;
2115 this.name = name;
2116 };
2117
2118 /**
2119 * Send a message
2120 *
2121 * @api public
2122 */
2123
2124 Flag.prototype.send = function () {
2125 this.namespace.flags[this.name] = true;
2126 this.namespace.send.apply(this.namespace, arguments);
2127 };
2128
2129 /**
2130 * Emit an event
2131 *
2132 * @api public
2133 */
2134
2135 Flag.prototype.emit = function () {
2136 this.namespace.flags[this.name] = true;
2137 this.namespace.emit.apply(this.namespace, arguments);
2138 };
2139
2140})(
2141 'undefined' != typeof io ? io : module.exports
2142 , 'undefined' != typeof io ? io : module.parent.exports
2143);
2144
2145/**
2146 * socket.io
2147 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2148 * MIT Licensed
2149 */
2150
2151(function (exports, io) {
2152
2153 /**
2154 * Expose constructor.
2155 */
2156
2157 exports.websocket = WS;
2158
2159 /**
2160 * The WebSocket transport uses the HTML5 WebSocket API to establish an
2161 * persistent connection with the Socket.IO server. This transport will also
2162 * be inherited by the FlashSocket fallback as it provides a API compatible
2163 * polyfill for the WebSockets.
2164 *
2165 * @constructor
2166 * @extends {io.Transport}
2167 * @api public
2168 */
2169
2170 function WS (socket) {
2171 io.Transport.apply(this, arguments);
2172 };
2173
2174 /**
2175 * Inherits from Transport.
2176 */
2177
2178 io.util.inherit(WS, io.Transport);
2179
2180 /**
2181 * Transport name
2182 *
2183 * @api public
2184 */
2185
2186 WS.prototype.name = 'websocket';
2187
2188 /**
2189 * Initializes a new `WebSocket` connection with the Socket.IO server. We attach
2190 * all the appropriate listeners to handle the responses from the server.
2191 *
2192 * @returns {Transport}
2193 * @api public
2194 */
2195
2196 WS.prototype.open = function () {
2197 this.websocket = new WebSocket(this.prepareUrl());
2198
2199 var self = this;
2200 this.websocket.onopen = function () {
2201 self.onOpen();
2202 self.socket.setBuffer(false);
2203 };
2204 this.websocket.onmessage = function (ev) {
2205 self.onData(ev.data);
2206 };
2207 this.websocket.onclose = function () {
2208 self.onClose();
2209 self.socket.setBuffer(true);
2210 };
2211 this.websocket.onerror = function (e) {
2212 self.onError(e);
2213 };
2214
2215 return this;
2216 };
2217
2218 /**
2219 * Send a message to the Socket.IO server. The message will automatically be
2220 * encoded in the correct message format.
2221 *
2222 * @returns {Transport}
2223 * @api public
2224 */
2225
2226 WS.prototype.send = function (data) {
2227 this.websocket.send(data);
2228 return this;
2229 };
2230
2231 /**
2232 * Payload
2233 *
2234 * @api private
2235 */
2236
2237 WS.prototype.payload = function (arr) {
2238 for (var i = 0, l = arr.length; i < l; i++) {
2239 this.packet(arr[i]);
2240 }
2241 return this;
2242 };
2243
2244 /**
2245 * Disconnect the established `WebSocket` connection.
2246 *
2247 * @returns {Transport}
2248 * @api public
2249 */
2250
2251 WS.prototype.close = function () {
2252 this.websocket.close();
2253 return this;
2254 };
2255
2256 /**
2257 * Handle the errors that `WebSocket` might be giving when we
2258 * are attempting to connect or send messages.
2259 *
2260 * @param {Error} e The error.
2261 * @api private
2262 */
2263
2264 WS.prototype.onError = function (e) {
2265 this.socket.onError(e);
2266 };
2267
2268 /**
2269 * Returns the appropriate scheme for the URI generation.
2270 *
2271 * @api private
2272 */
2273 WS.prototype.scheme = function () {
2274 return this.socket.options.secure ? 'wss' : 'ws';
2275 };
2276
2277 /**
2278 * Checks if the browser has support for native `WebSockets` and that
2279 * it's not the polyfill created for the FlashSocket transport.
2280 *
2281 * @return {Boolean}
2282 * @api public
2283 */
2284
2285 WS.check = function () {
2286 return 'WebSocket' in window && !('__addTask' in WebSocket);
2287 };
2288
2289 /**
2290 * Check if the `WebSocket` transport support cross domain communications.
2291 *
2292 * @returns {Boolean}
2293 * @api public
2294 */
2295
2296 WS.xdomainCheck = function () {
2297 return true;
2298 };
2299
2300 /**
2301 * Add the transport to your public io.transports array.
2302 *
2303 * @api private
2304 */
2305
2306 io.transports.push('websocket');
2307
2308})(
2309 'undefined' != typeof io ? io.Transport : module.exports
2310 , 'undefined' != typeof io ? io : module.parent.exports
2311);
2312
2313/**
2314 * socket.io
2315 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2316 * MIT Licensed
2317 */
2318
2319(function (exports, io) {
2320
2321 /**
2322 * Expose constructor.
2323 */
2324
2325 exports.flashsocket = Flashsocket;
2326
2327 /**
2328 * The Flashsocket transport. This is a API wrapper for the HTML5 WebSocket
2329 * specification. It uses a .swf file to communicate with the server. If you want
2330 * to serve the .swf file from a other server than where the Socket.IO script is
2331 * coming from you need to use the insecure version of the .swf. More information
2332 * about this can be found on the github page.
2333 *
2334 * @constructor
2335 * @extends {io.Transport.websocket}
2336 * @api public
2337 */
2338
2339 function Flashsocket () {
2340 io.Transport.websocket.apply(this, arguments);
2341 };
2342
2343 /**
2344 * Inherits from Transport.
2345 */
2346
2347 io.util.inherit(Flashsocket, io.Transport.websocket);
2348
2349 /**
2350 * Transport name
2351 *
2352 * @api public
2353 */
2354
2355 Flashsocket.prototype.name = 'flashsocket';
2356
2357 /**
2358 *Disconnect the established `Flashsocket` connection. This is done by adding a
2359 * new task to the Flashsocket. The rest will be handled off by the `WebSocket`
2360 * transport.
2361 *
2362 * @returns {Transport}
2363 * @api public
2364 */
2365
2366 Flashsocket.prototype.open = function () {
2367 var self = this, args = arguments;
2368 WebSocket.__addTask(function () {
2369 io.Transport.websocket.prototype.open.apply(self, args);
2370 });
2371 return this;
2372 };
2373
2374 /**
2375 * Sends a message to the Socket.IO server. This is done by adding a new
2376 * task to the Flashsocket. The rest will be handled off by the `WebSocket`
2377 * transport.
2378 *
2379 * @returns {Transport}
2380 * @api public
2381 */
2382
2383 Flashsocket.prototype.send = function () {
2384 var self = this, args = arguments;
2385 WebSocket.__addTask(function () {
2386 io.Transport.websocket.prototype.send.apply(self, args);
2387 });
2388 return this;
2389 };
2390
2391 /**
2392 * Disconnects the established `Flashsocket` connection.
2393 *
2394 * @returns {Transport}
2395 * @api public
2396 */
2397
2398 Flashsocket.prototype.close = function () {
2399 WebSocket.__tasks.length = 0;
2400 io.Transport.websocket.prototype.close.call(this);
2401 return this;
2402 };
2403
2404 /**
2405 * Check if the Flashsocket transport is supported as it requires that the Adobe
2406 * Flash Player plugin version `10.0.0` or greater is installed. And also check if
2407 * the polyfill is correctly loaded.
2408 *
2409 * @returns {Boolean}
2410 * @api public
2411 */
2412
2413 Flashsocket.check = function (socket) {
2414 if (
2415 typeof WebSocket == 'undefined'
2416 || !('__initialize' in WebSocket) || !swfobject
2417 ) return false;
2418
2419 var supported = swfobject.getFlashPlayerVersion().major >= 10
2420 , options = socket.options
2421 , path = [
2422 'http' + (options.secure ? 's' : '') + ':/'
2423 , options.host + ':' + options.port
2424 , options.resource
2425 , 'static/flashsocket'
2426 , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
2427 ];
2428
2429 // Only start downloading the swf file when the checked that this browser
2430 // actually supports it
2431 if (supported && !Flashsocket.loaded) {
2432 if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
2433 // Set the correct file based on the XDomain settings
2434 WEB_SOCKET_SWF_LOCATION = path.join('/');
2435 }
2436
2437 WebSocket.__initialize();
2438 Flashsocket.loaded = true;
2439 }
2440
2441 return supported;
2442 };
2443
2444 /**
2445 * Check if the Flashsocket transport can be used as cross domain / cross origin
2446 * transport. Because we can't see which type (secure or insecure) of .swf is used
2447 * we will just return true.
2448 *
2449 * @returns {Boolean}
2450 * @api public
2451 */
2452
2453 Flashsocket.xdomainCheck = function () {
2454 return true;
2455 };
2456
2457 /**
2458 * Disable AUTO_INITIALIZATION
2459 */
2460
2461 if (typeof window != 'undefined') {
2462 WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true;
2463 }
2464
2465 /**
2466 * Add the transport to your public io.transports array.
2467 *
2468 * @api private
2469 */
2470
2471 io.transports.push('flashsocket');
2472})(
2473 'undefined' != typeof io ? io.Transport : module.exports
2474 , 'undefined' != typeof io ? io : module.parent.exports
2475);
2476/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
2477 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
2478*/
2479var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
2480// License: New BSD License
2481// Reference: http://dev.w3.org/html5/websockets/
2482// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
2483
2484(function() {
2485
2486 if (window.WebSocket) return;
2487
2488 var console = window.console;
2489 if (!console || !console.log || !console.error) {
2490 console = {log: function(){ }, error: function(){ }};
2491 }
2492
2493 if (!swfobject.hasFlashPlayerVersion("10.0.0")) {
2494 console.error("Flash Player >= 10.0.0 is required.");
2495 return;
2496 }
2497 if (location.protocol == "file:") {
2498 console.error(
2499 "WARNING: web-socket-js doesn't work in file:///... URL " +
2500 "unless you set Flash Security Settings properly. " +
2501 "Open the page via Web server i.e. http://...");
2502 }
2503
2504 /**
2505 * This class represents a faux web socket.
2506 * @param {string} url
2507 * @param {array or string} protocols
2508 * @param {string} proxyHost
2509 * @param {int} proxyPort
2510 * @param {string} headers
2511 */
2512 WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
2513 var self = this;
2514 self.__id = WebSocket.__nextId++;
2515 WebSocket.__instances[self.__id] = self;
2516 self.readyState = WebSocket.CONNECTING;
2517 self.bufferedAmount = 0;
2518 self.__events = {};
2519 if (!protocols) {
2520 protocols = [];
2521 } else if (typeof protocols == "string") {
2522 protocols = [protocols];
2523 }
2524 // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
2525 // Otherwise, when onopen fires immediately, onopen is called before it is set.
2526 setTimeout(function() {
2527 WebSocket.__addTask(function() {
2528 WebSocket.__flash.create(
2529 self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
2530 });
2531 }, 0);
2532 };
2533
2534 /**
2535 * Send data to the web socket.
2536 * @param {string} data The data to send to the socket.
2537 * @return {boolean} True for success, false for failure.
2538 */
2539 WebSocket.prototype.send = function(data) {
2540 if (this.readyState == WebSocket.CONNECTING) {
2541 throw "INVALID_STATE_ERR: Web Socket connection has not been established";
2542 }
2543 // We use encodeURIComponent() here, because FABridge doesn't work if
2544 // the argument includes some characters. We don't use escape() here
2545 // because of this:
2546 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
2547 // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
2548 // preserve all Unicode characters either e.g. "\uffff" in Firefox.
2549 // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
2550 // additional testing.
2551 var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
2552 if (result < 0) { // success
2553 return true;
2554 } else {
2555 this.bufferedAmount += result;
2556 return false;
2557 }
2558 };
2559
2560 /**
2561 * Close this web socket gracefully.
2562 */
2563 WebSocket.prototype.close = function() {
2564 if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
2565 return;
2566 }
2567 this.readyState = WebSocket.CLOSING;
2568 WebSocket.__flash.close(this.__id);
2569 };
2570
2571 /**
2572 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
2573 *
2574 * @param {string} type
2575 * @param {function} listener
2576 * @param {boolean} useCapture
2577 * @return void
2578 */
2579 WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
2580 if (!(type in this.__events)) {
2581 this.__events[type] = [];
2582 }
2583 this.__events[type].push(listener);
2584 };
2585
2586 /**
2587 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
2588 *
2589 * @param {string} type
2590 * @param {function} listener
2591 * @param {boolean} useCapture
2592 * @return void
2593 */
2594 WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
2595 if (!(type in this.__events)) return;
2596 var events = this.__events[type];
2597 for (var i = events.length - 1; i >= 0; --i) {
2598 if (events[i] === listener) {
2599 events.splice(i, 1);
2600 break;
2601 }
2602 }
2603 };
2604
2605 /**
2606 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
2607 *
2608 * @param {Event} event
2609 * @return void
2610 */
2611 WebSocket.prototype.dispatchEvent = function(event) {
2612 var events = this.__events[event.type] || [];
2613 for (var i = 0; i < events.length; ++i) {
2614 events[i](event);
2615 }
2616 var handler = this["on" + event.type];
2617 if (handler) handler(event);
2618 };
2619
2620 /**
2621 * Handles an event from Flash.
2622 * @param {Object} flashEvent
2623 */
2624 WebSocket.prototype.__handleEvent = function(flashEvent) {
2625 if ("readyState" in flashEvent) {
2626 this.readyState = flashEvent.readyState;
2627 }
2628 if ("protocol" in flashEvent) {
2629 this.protocol = flashEvent.protocol;
2630 }
2631
2632 var jsEvent;
2633 if (flashEvent.type == "open" || flashEvent.type == "error") {
2634 jsEvent = this.__createSimpleEvent(flashEvent.type);
2635 } else if (flashEvent.type == "close") {
2636 // TODO implement jsEvent.wasClean
2637 jsEvent = this.__createSimpleEvent("close");
2638 } else if (flashEvent.type == "message") {
2639 var data = decodeURIComponent(flashEvent.message);
2640 jsEvent = this.__createMessageEvent("message", data);
2641 } else {
2642 throw "unknown event type: " + flashEvent.type;
2643 }
2644
2645 this.dispatchEvent(jsEvent);
2646 };
2647
2648 WebSocket.prototype.__createSimpleEvent = function(type) {
2649 if (document.createEvent && window.Event) {
2650 var event = document.createEvent("Event");
2651 event.initEvent(type, false, false);
2652 return event;
2653 } else {
2654 return {type: type, bubbles: false, cancelable: false};
2655 }
2656 };
2657
2658 WebSocket.prototype.__createMessageEvent = function(type, data) {
2659 if (document.createEvent && window.MessageEvent && !window.opera) {
2660 var event = document.createEvent("MessageEvent");
2661 event.initMessageEvent("message", false, false, data, null, null, window, null);
2662 return event;
2663 } else {
2664 // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
2665 return {type: type, data: data, bubbles: false, cancelable: false};
2666 }
2667 };
2668
2669 /**
2670 * Define the WebSocket readyState enumeration.
2671 */
2672 WebSocket.CONNECTING = 0;
2673 WebSocket.OPEN = 1;
2674 WebSocket.CLOSING = 2;
2675 WebSocket.CLOSED = 3;
2676
2677 WebSocket.__flash = null;
2678 WebSocket.__instances = {};
2679 WebSocket.__tasks = [];
2680 WebSocket.__nextId = 0;
2681
2682 /**
2683 * Load a new flash security policy file.
2684 * @param {string} url
2685 */
2686 WebSocket.loadFlashPolicyFile = function(url){
2687 WebSocket.__addTask(function() {
2688 WebSocket.__flash.loadManualPolicyFile(url);
2689 });
2690 };
2691
2692 /**
2693 * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
2694 */
2695 WebSocket.__initialize = function() {
2696 if (WebSocket.__flash) return;
2697
2698 if (WebSocket.__swfLocation) {
2699 // For backword compatibility.
2700 window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
2701 }
2702 if (!window.WEB_SOCKET_SWF_LOCATION) {
2703 console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
2704 return;
2705 }
2706 var container = document.createElement("div");
2707 container.id = "webSocketContainer";
2708 // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
2709 // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
2710 // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
2711 // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
2712 // the best we can do as far as we know now.
2713 container.style.position = "absolute";
2714 if (WebSocket.__isFlashLite()) {
2715 container.style.left = "0px";
2716 container.style.top = "0px";
2717 } else {
2718 container.style.left = "-100px";
2719 container.style.top = "-100px";
2720 }
2721 var holder = document.createElement("div");
2722 holder.id = "webSocketFlash";
2723 container.appendChild(holder);
2724 document.body.appendChild(container);
2725 // See this article for hasPriority:
2726 // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
2727 swfobject.embedSWF(
2728 WEB_SOCKET_SWF_LOCATION,
2729 "webSocketFlash",
2730 "1" /* width */,
2731 "1" /* height */,
2732 "10.0.0" /* SWF version */,
2733 null,
2734 null,
2735 {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
2736 null,
2737 function(e) {
2738 if (!e.success) {
2739 console.error("[WebSocket] swfobject.embedSWF failed");
2740 }
2741 });
2742 };
2743
2744 /**
2745 * Called by Flash to notify JS that it's fully loaded and ready
2746 * for communication.
2747 */
2748 WebSocket.__onFlashInitialized = function() {
2749 // We need to set a timeout here to avoid round-trip calls
2750 // to flash during the initialization process.
2751 setTimeout(function() {
2752 WebSocket.__flash = document.getElementById("webSocketFlash");
2753 WebSocket.__flash.setCallerUrl(location.href);
2754 WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
2755 for (var i = 0; i < WebSocket.__tasks.length; ++i) {
2756 WebSocket.__tasks[i]();
2757 }
2758 WebSocket.__tasks = [];
2759 }, 0);
2760 };
2761
2762 /**
2763 * Called by Flash to notify WebSockets events are fired.
2764 */
2765 WebSocket.__onFlashEvent = function() {
2766 setTimeout(function() {
2767 try {
2768 // Gets events using receiveEvents() instead of getting it from event object
2769 // of Flash event. This is to make sure to keep message order.
2770 // It seems sometimes Flash events don't arrive in the same order as they are sent.
2771 var events = WebSocket.__flash.receiveEvents();
2772 for (var i = 0; i < events.length; ++i) {
2773 WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
2774 }
2775 } catch (e) {
2776 console.error(e);
2777 }
2778 }, 0);
2779 return true;
2780 };
2781
2782 // Called by Flash.
2783 WebSocket.__log = function(message) {
2784 console.log(decodeURIComponent(message));
2785 };
2786
2787 // Called by Flash.
2788 WebSocket.__error = function(message) {
2789 console.error(decodeURIComponent(message));
2790 };
2791
2792 WebSocket.__addTask = function(task) {
2793 if (WebSocket.__flash) {
2794 task();
2795 } else {
2796 WebSocket.__tasks.push(task);
2797 }
2798 };
2799
2800 /**
2801 * Test if the browser is running flash lite.
2802 * @return {boolean} True if flash lite is running, false otherwise.
2803 */
2804 WebSocket.__isFlashLite = function() {
2805 if (!window.navigator || !window.navigator.mimeTypes) {
2806 return false;
2807 }
2808 var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
2809 if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
2810 return false;
2811 }
2812 return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
2813 };
2814
2815 if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
2816 if (window.addEventListener) {
2817 window.addEventListener("load", function(){
2818 WebSocket.__initialize();
2819 }, false);
2820 } else {
2821 window.attachEvent("onload", function(){
2822 WebSocket.__initialize();
2823 });
2824 }
2825 }
2826
2827})();
2828
2829/**
2830 * socket.io
2831 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2832 * MIT Licensed
2833 */
2834
2835(function (exports, io) {
2836
2837 /**
2838 * Expose constructor.
2839 *
2840 * @api public
2841 */
2842
2843 exports.XHR = XHR;
2844
2845 /**
2846 * XHR constructor
2847 *
2848 * @costructor
2849 * @api public
2850 */
2851
2852 function XHR (socket) {
2853 if (!socket) return;
2854
2855 io.Transport.apply(this, arguments);
2856 this.sendBuffer = [];
2857 };
2858
2859 /**
2860 * Inherits from Transport.
2861 */
2862
2863 io.util.inherit(XHR, io.Transport);
2864
2865 /**
2866 * Establish a connection
2867 *
2868 * @returns {Transport}
2869 * @api public
2870 */
2871
2872 XHR.prototype.open = function () {
2873 this.socket.setBuffer(false);
2874 this.onOpen();
2875 this.get();
2876
2877 // we need to make sure the request succeeds since we have no indication
2878 // whether the request opened or not until it succeeded.
2879 this.setCloseTimeout();
2880
2881 return this;
2882 };
2883
2884 /**
2885 * Check if we need to send data to the Socket.IO server, if we have data in our
2886 * buffer we encode it and forward it to the `post` method.
2887 *
2888 * @api private
2889 */
2890
2891 XHR.prototype.payload = function (payload) {
2892 var msgs = [];
2893
2894 for (var i = 0, l = payload.length; i < l; i++) {
2895 msgs.push(io.parser.encodePacket(payload[i]));
2896 }
2897
2898 this.send(io.parser.encodePayload(msgs));
2899 };
2900
2901 /**
2902 * Send data to the Socket.IO server.
2903 *
2904 * @param data The message
2905 * @returns {Transport}
2906 * @api public
2907 */
2908
2909 XHR.prototype.send = function (data) {
2910 this.post(data);
2911 return this;
2912 };
2913
2914 /**
2915 * Posts a encoded message to the Socket.IO server.
2916 *
2917 * @param {String} data A encoded message.
2918 * @api private
2919 */
2920
2921 function empty () { };
2922
2923 XHR.prototype.post = function (data) {
2924 var self = this;
2925 this.socket.setBuffer(true);
2926
2927 function stateChange () {
2928 if (this.readyState == 4) {
2929 this.onreadystatechange = empty;
2930 self.posting = false;
2931
2932 if (this.status == 200){
2933 self.socket.setBuffer(false);
2934 } else {
2935 self.onClose();
2936 }
2937 }
2938 }
2939
2940 function onload () {
2941 this.onload = empty;
2942 self.socket.setBuffer(false);
2943 };
2944
2945 this.sendXHR = this.request('POST');
2946
2947 if (window.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
2948 this.sendXHR.onload = this.sendXHR.onerror = onload;
2949 } else {
2950 this.sendXHR.onreadystatechange = stateChange;
2951 }
2952
2953 this.sendXHR.send(data);
2954 };
2955
2956 /**
2957 * Disconnects the established `XHR` connection.
2958 *
2959 * @returns {Transport}
2960 * @api public
2961 */
2962
2963 XHR.prototype.close = function () {
2964 this.onClose();
2965 return this;
2966 };
2967
2968 /**
2969 * Generates a configured XHR request
2970 *
2971 * @param {String} url The url that needs to be requested.
2972 * @param {String} method The method the request should use.
2973 * @returns {XMLHttpRequest}
2974 * @api private
2975 */
2976
2977 XHR.prototype.request = function (method) {
2978 var req = io.util.request(this.socket.isXDomain());
2979 req.open(method || 'GET', this.prepareUrl() + '?t' + (+ new Date));
2980
2981 if (method == 'POST') {
2982 try {
2983 if (req.setRequestHeader) {
2984 req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
2985 } else {
2986 // XDomainRequest
2987 req.contentType = 'text/plain';
2988 }
2989 } catch (e) {}
2990 }
2991
2992 return req;
2993 };
2994
2995 /**
2996 * Returns the scheme to use for the transport URLs.
2997 *
2998 * @api private
2999 */
3000
3001 XHR.prototype.scheme = function () {
3002 return this.socket.options.secure ? 'https' : 'http';
3003 };
3004
3005 /**
3006 * Check if the XHR transports are supported
3007 *
3008 * @param {Boolean} xdomain Check if we support cross domain requests.
3009 * @returns {Boolean}
3010 * @api public
3011 */
3012
3013 XHR.check = function (socket, xdomain) {
3014 try {
3015 if (io.util.request(xdomain)) {
3016 return true;
3017 }
3018 } catch(e) {}
3019
3020 return false;
3021 };
3022
3023 /**
3024 * Check if the XHR transport supports corss domain requests.
3025 *
3026 * @returns {Boolean}
3027 * @api public
3028 */
3029
3030 XHR.xdomainCheck = function () {
3031 return XHR.check(null, true);
3032 };
3033
3034})(
3035 'undefined' != typeof io ? io.Transport : module.exports
3036 , 'undefined' != typeof io ? io : module.parent.exports
3037);
3038
3039/**
3040 * socket.io
3041 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
3042 * MIT Licensed
3043 */
3044
3045(function (exports, io) {
3046
3047 /**
3048 * Expose constructor.
3049 */
3050
3051 exports.htmlfile = HTMLFile;
3052
3053 /**
3054 * The HTMLFile transport creates a `forever iframe` based transport
3055 * for Internet Explorer. Regular forever iframe implementations will
3056 * continuously trigger the browsers buzy indicators. If the forever iframe
3057 * is created inside a `htmlfile` these indicators will not be trigged.
3058 *
3059 * @constructor
3060 * @extends {io.Transport.XHR}
3061 * @api public
3062 */
3063
3064 function HTMLFile (socket) {
3065 io.Transport.XHR.apply(this, arguments);
3066 };
3067
3068 /**
3069 * Inherits from XHR transport.
3070 */
3071
3072 io.util.inherit(HTMLFile, io.Transport.XHR);
3073
3074 /**
3075 * Transport name
3076 *
3077 * @api public
3078 */
3079
3080 HTMLFile.prototype.name = 'htmlfile';
3081
3082 /**
3083 * Creates a new ActiveX `htmlfile` with a forever loading iframe
3084 * that can be used to listen to messages. Inside the generated
3085 * `htmlfile` a reference will be made to the HTMLFile transport.
3086 *
3087 * @api private
3088 */
3089
3090 HTMLFile.prototype.get = function () {
3091 this.doc = new ActiveXObject('htmlfile');
3092 this.doc.open();
3093 this.doc.write('<html></html>');
3094 this.doc.close();
3095 this.doc.parentWindow.s = this;
3096
3097 var iframeC = this.doc.createElement('div');
3098 iframeC.className = 'socketio';
3099
3100 this.doc.body.appendChild(iframeC);
3101 this.iframe = this.doc.createElement('iframe');
3102
3103 iframeC.appendChild(this.iframe);
3104
3105 this.iframe.src = this.prepareUrl() + '/?t=' + (+ new Date);
3106
3107 var self = this;
3108
3109 io.util.on(window, 'unload', function () {
3110 self.destroy();
3111 });
3112 };
3113
3114 /**
3115 * The Socket.IO server will write script tags inside the forever
3116 * iframe, this function will be used as callback for the incoming
3117 * information.
3118 *
3119 * @param {String} data The message
3120 * @param {document} doc Reference to the context
3121 * @api private
3122 */
3123
3124 HTMLFile.prototype._ = function (data, doc) {
3125 this.onData(data);
3126 try {
3127 var script = doc.getElementsByTagName('script')[0];
3128 script.parentNode.removeChild(script);
3129 } catch (e) { }
3130 };
3131
3132 /**
3133 * Destroy the established connection, iframe and `htmlfile`.
3134 * And calls the `CollectGarbage` function of Internet Explorer
3135 * to release the memory.
3136 *
3137 * @api private
3138 */
3139
3140 HTMLFile.prototype.destroy = function () {
3141 if (this.iframe){
3142 try {
3143 this.iframe.src = 'about:blank';
3144 } catch(e){}
3145
3146 this.doc = null;
3147 this.iframe.parentNode.removeChild(this.iframe);
3148 this.iframe = null;
3149
3150 CollectGarbage();
3151 }
3152 };
3153
3154 /**
3155 * Disconnects the established connection.
3156 *
3157 * @returns {Transport} Chaining.
3158 * @api public
3159 */
3160
3161 HTMLFile.prototype.close = function () {
3162 this.destroy();
3163 return io.Transport.XHR.prototype.close.call(this);
3164 };
3165
3166 /**
3167 * Checks if the browser supports this transport. The browser
3168 * must have an `ActiveXObject` implementation.
3169 *
3170 * @return {Boolean}
3171 * @api public
3172 */
3173
3174 HTMLFile.check = function () {
3175 if ('ActiveXObject' in window){
3176 try {
3177 var a = new ActiveXObject('htmlfile');
3178 return a && io.Transport.XHR.check();
3179 } catch(e){}
3180 }
3181 return false;
3182 };
3183
3184 /**
3185 * Check if cross domain requests are supported.
3186 *
3187 * @returns {Boolean}
3188 * @api public
3189 */
3190
3191 HTMLFile.xdomainCheck = function () {
3192 // we can probably do handling for sub-domains, we should
3193 // test that it's cross domain but a subdomain here
3194 return false;
3195 };
3196
3197 /**
3198 * Add the transport to your public io.transports array.
3199 *
3200 * @api private
3201 */
3202
3203 io.transports.push('htmlfile');
3204
3205})(
3206 'undefined' != typeof io ? io.Transport : module.exports
3207 , 'undefined' != typeof io ? io : module.parent.exports
3208);
3209
3210/**
3211 * socket.io
3212 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
3213 * MIT Licensed
3214 */
3215
3216(function (exports, io) {
3217
3218 /**
3219 * Expose constructor.
3220 */
3221
3222 exports['xhr-polling'] = XHRPolling;
3223
3224 /**
3225 * The XHR-polling transport uses long polling XHR requests to create a
3226 * "persistent" connection with the server.
3227 *
3228 * @constructor
3229 * @api public
3230 */
3231
3232 function XHRPolling () {
3233 io.Transport.XHR.apply(this, arguments);
3234 };
3235
3236 /**
3237 * Inherits from XHR transport.
3238 */
3239
3240 io.util.inherit(XHRPolling, io.Transport.XHR);
3241
3242 /**
3243 * Transport name
3244 *
3245 * @api public
3246 */
3247
3248 XHRPolling.prototype.name = 'xhr-polling';
3249
3250 /**
3251 * Establish a connection, for iPhone and Android this will be done once the page
3252 * is loaded.
3253 *
3254 * @returns {Transport} Chaining.
3255 * @api public
3256 */
3257
3258 XHRPolling.prototype.open = function () {
3259 var self = this;
3260
3261 io.util.defer(function () {
3262 io.Transport.XHR.prototype.open.call(self);
3263 });
3264
3265 return false;
3266 };
3267
3268 /**
3269 * Starts a XHR request to wait for incoming messages.
3270 *
3271 * @api private
3272 */
3273
3274 function empty () {};
3275
3276 XHRPolling.prototype.get = function () {
3277 if (!this.open) return;
3278
3279 var self = this;
3280
3281 function stateChange () {
3282 if (this.readyState == 4) {
3283 this.onreadystatechange = empty;
3284
3285 if (this.status == 200) {
3286 self.onData(this.responseText);
3287 self.get();
3288 } else {
3289 self.onClose();
3290 }
3291 }
3292 };
3293
3294 function onload () {
3295 this.onload = empty;
3296 self.onData(this.responseText);
3297 self.get();
3298 };
3299
3300 this.xhr = this.request();
3301
3302 if (window.XDomainRequest && this.xhr instanceof XDomainRequest) {
3303 this.xhr.onload = this.xhr.onerror = onload;
3304 } else {
3305 this.xhr.onreadystatechange = stateChange;
3306 }
3307
3308 this.xhr.send(null);
3309 };
3310
3311 /**
3312 * Handle the unclean close behavior.
3313 *
3314 * @api private
3315 */
3316
3317 XHRPolling.prototype.onClose = function () {
3318 io.Transport.XHR.prototype.onClose.call(this);
3319
3320 if (this.xhr) {
3321 this.xhr.onreadystatechange = this.xhr.onload = empty;
3322 try {
3323 this.xhr.abort();
3324 } catch(e){}
3325 this.xhr = null;
3326 }
3327 };
3328
3329 /**
3330 * Add the transport to your public io.transports array.
3331 *
3332 * @api private
3333 */
3334
3335 io.transports.push('xhr-polling');
3336
3337})(
3338 'undefined' != typeof io ? io.Transport : module.exports
3339 , 'undefined' != typeof io ? io : module.parent.exports
3340);
3341
3342/**
3343 * socket.io
3344 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
3345 * MIT Licensed
3346 */
3347
3348(function (exports, io) {
3349
3350 /**
3351 * Expose constructor.
3352 */
3353
3354 exports['jsonp-polling'] = JSONPPolling;
3355
3356 /**
3357 * The JSONP transport creates an persistent connection by dynamically
3358 * inserting a script tag in the page. This script tag will receive the
3359 * information of the Socket.IO server. When new information is received
3360 * it creates a new script tag for the new data stream.
3361 *
3362 * @constructor
3363 * @extends {io.Transport.xhr-polling}
3364 * @api public
3365 */
3366
3367 function JSONPPolling (socket) {
3368 io.Transport['xhr-polling'].apply(this, arguments);
3369
3370 this.index = io.j.length;
3371
3372 var self = this;
3373
3374 io.j.push(function (msg) {
3375 self._(msg);
3376 });
3377 };
3378
3379 /**
3380 * Inherits from XHR polling transport.
3381 */
3382
3383 io.util.inherit(JSONPPolling, io.Transport['xhr-polling']);
3384
3385 /**
3386 * Transport name
3387 *
3388 * @api public
3389 */
3390
3391 JSONPPolling.prototype.name = 'jsonp-polling';
3392
3393 /**
3394 * Posts a encoded message to the Socket.IO server using an iframe.
3395 * The iframe is used because script tags can create POST based requests.
3396 * The iframe is positioned outside of the view so the user does not
3397 * notice it's existence.
3398 *
3399 * @param {String} data A encoded message.
3400 * @api private
3401 */
3402
3403 JSONPPolling.prototype.post = function (data) {
3404 var self = this;
3405
3406 if (!this.form) {
3407 var form = document.createElement('FORM')
3408 , area = document.createElement('TEXTAREA')
3409 , id = this.iframeId = 'socketio_iframe_' + this.index
3410 , iframe;
3411
3412 form.className = 'socketio';
3413 form.style.position = 'absolute';
3414 form.style.top = '-1000px';
3415 form.style.left = '-1000px';
3416 form.target = id;
3417 form.method = 'POST';
3418 area.name = 'd';
3419 form.appendChild(area);
3420 document.body.appendChild(form);
3421
3422 this.form = form;
3423 this.area = area;
3424 }
3425
3426 this.form.action = this.prepareUrl() + '?t=' + (+new Date) + '&i=' + this.index;
3427
3428 function complete () {
3429 initIframe();
3430 self.socket.setBuffer(false);
3431 };
3432
3433 function initIframe () {
3434 if (self.iframe) {
3435 self.form.removeChild(self.iframe);
3436 }
3437
3438 try {
3439 // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
3440 iframe = document.createElement('<iframe name="'+ self.iframeId +'">');
3441 } catch (e) {
3442 iframe = document.createElement('iframe');
3443 iframe.name = self.iframeId;
3444 }
3445
3446 iframe.id = self.iframeId;
3447
3448 self.form.appendChild(iframe);
3449 self.iframe = iframe;
3450 };
3451
3452 initIframe();
3453
3454 this.area.value = data;
3455
3456 try {
3457 this.form.submit();
3458 } catch(e) {}
3459
3460 if (this.iframe.attachEvent) {
3461 iframe.onreadystatechange = function () {
3462 if (self.iframe.readyState == 'complete') {
3463 complete();
3464 }
3465 };
3466 } else {
3467 this.iframe.onload = complete;
3468 }
3469 };
3470
3471 /**
3472 * Creates a new JSONP poll that can be used to listen
3473 * for messages from the Socket.IO server.
3474 *
3475 * @api private
3476 */
3477
3478 JSONPPolling.prototype.get = function () {
3479 var self = this
3480 , script = document.createElement('SCRIPT');
3481
3482 if (this.script) {
3483 this.script.parentNode.removeChild(this.script);
3484 this.script = null;
3485 }
3486
3487 script.async = true;
3488 script.src = this.prepareUrl() + '/?t=' + (+new Date) + '&i=' + this.index;
3489 script.onerror = function () {
3490 self.onClose();
3491 };
3492
3493 var insertAt = document.getElementsByTagName('script')[0]
3494 insertAt.parentNode.insertBefore(script, insertAt);
3495 this.script = script;
3496 };
3497
3498 /**
3499 * Callback function for the incoming message stream from the Socket.IO server.
3500 *
3501 * @param {String} data The message
3502 * @api private
3503 */
3504
3505 JSONPPolling.prototype._ = function (msg) {
3506 this.onData(msg);
3507 if (this.open) {
3508 this.get();
3509 }
3510 return this;
3511 };
3512
3513 /**
3514 * Checks if browser supports this transport.
3515 *
3516 * @return {Boolean}
3517 * @api public
3518 */
3519
3520 JSONPPolling.check = function () {
3521 return true;
3522 };
3523
3524 /**
3525 * Check if cross domain requests are supported
3526 *
3527 * @returns {Boolean}
3528 * @api public
3529 */
3530
3531 JSONPPolling.xdomainCheck = function () {
3532 return true;
3533 };
3534
3535 /**
3536 * Add the transport to your public io.transports array.
3537 *
3538 * @api private
3539 */
3540
3541 io.transports.push('jsonp-polling');
3542
3543})(
3544 'undefined' != typeof io ? io.Transport : module.exports
3545 , 'undefined' != typeof io ? io : module.parent.exports
3546);