UNPKG

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