UNPKG

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