UNPKG

95.6 kBJavaScriptView Raw
1/*! Socket.IO.js build:0.7.11, 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.11';
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 if (self.transport) self.transport.clearTimeouts();
1679
1680 self.transport = self.getTransport(transports);
1681 if (!self.transport) return self.publish('connect_failed');
1682
1683 // once the transport is ready
1684 self.transport.ready(self, function () {
1685 self.connecting = true;
1686 self.publish('connecting', self.transport.name);
1687 self.transport.open();
1688
1689 if (self.options['connect timeout']) {
1690 self.connectTimeoutTimer = setTimeout(function () {
1691 if (!self.connected) {
1692 self.connecting = false;
1693
1694 if (self.options['try multiple transports']) {
1695 if (!self.remainingTransports) {
1696 self.remainingTransports = self.transports.slice(0);
1697 }
1698
1699 var remaining = self.remainingTransports;
1700
1701 while (remaining.length > 0 && remaining.splice(0,1)[0] !=
1702 self.transport.name) {}
1703
1704 if (remaining.length){
1705 connect(remaining);
1706 } else {
1707 self.publish('connect_failed');
1708 }
1709 }
1710 }
1711 }, self.options['connect timeout']);
1712 }
1713 });
1714 }
1715
1716 connect();
1717
1718 self.once('connect', function (){
1719 clearTimeout(self.connectTimeoutTimer);
1720
1721 fn && typeof fn == 'function' && fn();
1722 });
1723 });
1724
1725 return this;
1726 };
1727
1728 /**
1729 * Sends a message.
1730 *
1731 * @param {Object} data packet.
1732 * @returns {io.Socket}
1733 * @api public
1734 */
1735
1736 Socket.prototype.packet = function (data) {
1737 if (this.connected && !this.doBuffer) {
1738 this.transport.packet(data);
1739 } else {
1740 this.buffer.push(data);
1741 }
1742
1743 return this;
1744 };
1745
1746 /**
1747 * Sets buffer state
1748 *
1749 * @api private
1750 */
1751
1752 Socket.prototype.setBuffer = function (v) {
1753 this.doBuffer = v;
1754
1755 if (!v && this.connected && this.buffer.length) {
1756 this.transport.payload(this.buffer);
1757 this.buffer = [];
1758 }
1759 };
1760
1761 /**
1762 * Disconnect the established connect.
1763 *
1764 * @returns {io.Socket}
1765 * @api public
1766 */
1767
1768 Socket.prototype.disconnect = function () {
1769 if (this.connected) {
1770 if (this.open) {
1771 this.of('').packet({ type: 'disconnect' });
1772 }
1773
1774 // handle disconnection immediately
1775 this.onDisconnect('booted');
1776 }
1777
1778 return this;
1779 };
1780
1781 /**
1782 * Disconnects the socket with a sync XHR.
1783 *
1784 * @api private
1785 */
1786
1787 Socket.prototype.disconnectSync = function () {
1788 // ensure disconnection
1789 var xhr = io.util.request()
1790 , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;
1791
1792 xhr.open('GET', uri, true);
1793
1794 // handle disconnection immediately
1795 this.onDisconnect('booted');
1796 };
1797
1798 /**
1799 * Check if we need to use cross domain enabled transports. Cross domain would
1800 * be a different port or different domain name.
1801 *
1802 * @returns {Boolean}
1803 * @api private
1804 */
1805
1806 Socket.prototype.isXDomain = function () {
1807
1808 var locPort = window.location.port || 80;
1809 return this.options.host !== document.domain || this.options.port != locPort;
1810 };
1811
1812 /**
1813 * Called upon handshake.
1814 *
1815 * @api private
1816 */
1817
1818 Socket.prototype.onConnect = function () {
1819 if (!this.connected) {
1820 this.connected = true;
1821 this.connecting = false;
1822 if (!this.doBuffer) {
1823 // make sure to flush the buffer
1824 this.setBuffer(false);
1825 }
1826 this.emit('connect');
1827 }
1828 };
1829
1830 /**
1831 * Called when the transport opens
1832 *
1833 * @api private
1834 */
1835
1836 Socket.prototype.onOpen = function () {
1837 this.open = true;
1838 };
1839
1840 /**
1841 * Called when the transport closes.
1842 *
1843 * @api private
1844 */
1845
1846 Socket.prototype.onClose = function () {
1847 this.open = false;
1848 };
1849
1850 /**
1851 * Called when the transport first opens a connection
1852 *
1853 * @param text
1854 */
1855
1856 Socket.prototype.onPacket = function (packet) {
1857 this.of(packet.endpoint).onPacket(packet);
1858 };
1859
1860 /**
1861 * Handles an error.
1862 *
1863 * @api private
1864 */
1865
1866 Socket.prototype.onError = function (err) {
1867 if (err && err.advice) {
1868 if (err.advice === 'reconnect' && this.connected) {
1869 this.disconnect();
1870 this.reconnect();
1871 }
1872 }
1873
1874 this.publish('error', err && err.reason ? err.reason : err);
1875 };
1876
1877 /**
1878 * Called when the transport disconnects.
1879 *
1880 * @api private
1881 */
1882
1883 Socket.prototype.onDisconnect = function (reason) {
1884 var wasConnected = this.connected;
1885
1886 this.connected = false;
1887 this.connecting = false;
1888 this.open = false;
1889
1890 if (wasConnected) {
1891 this.transport.close();
1892 this.transport.clearTimeouts();
1893 this.publish('disconnect', reason);
1894
1895 if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
1896 this.reconnect();
1897 }
1898 }
1899 };
1900
1901 /**
1902 * Called upon reconnection.
1903 *
1904 * @api private
1905 */
1906
1907 Socket.prototype.reconnect = function () {
1908 this.reconnecting = true;
1909 this.reconnectionAttempts = 0;
1910 this.reconnectionDelay = this.options['reconnection delay'];
1911
1912 var self = this
1913 , maxAttempts = this.options['max reconnection attempts']
1914 , tryMultiple = this.options['try multiple transports']
1915 , limit = this.options['reconnection limit'];
1916
1917 function reset () {
1918 if (self.connected) {
1919 for (var i in self.namespaces) {
1920 if (self.namespaces.hasOwnProperty(i) && '' !== i) {
1921 self.namespaces[i].packet({ type: 'connect' });
1922 }
1923 }
1924 self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
1925 }
1926
1927 self.removeListener('connect_failed', maybeReconnect);
1928 self.removeListener('connect', maybeReconnect);
1929
1930 self.reconnecting = false;
1931
1932 delete self.reconnectionAttempts;
1933 delete self.reconnectionDelay;
1934 delete self.reconnectionTimer;
1935 delete self.redoTransports;
1936
1937 self.options['try multiple transports'] = tryMultiple;
1938 };
1939
1940 function maybeReconnect () {
1941 if (!self.reconnecting) {
1942 return;
1943 }
1944
1945 if (self.connected) {
1946 return reset();
1947 };
1948
1949 if (self.connecting && self.reconnecting) {
1950 return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
1951 }
1952
1953 if (self.reconnectionAttempts++ >= maxAttempts) {
1954 if (!self.redoTransports) {
1955 self.on('connect_failed', maybeReconnect);
1956 self.options['try multiple transports'] = true;
1957 self.transport = self.getTransport();
1958 self.redoTransports = true;
1959 self.connect();
1960 } else {
1961 self.publish('reconnect_failed');
1962 reset();
1963 }
1964 } else {
1965 if (self.reconnectionDelay < limit) {
1966 self.reconnectionDelay *= 2; // exponential back off
1967 }
1968
1969 self.connect();
1970 self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
1971 self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
1972 }
1973 };
1974
1975 this.options['try multiple transports'] = false;
1976 this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
1977
1978 this.on('connect', maybeReconnect);
1979 };
1980
1981})(
1982 'undefined' != typeof io ? io : module.exports
1983 , 'undefined' != typeof io ? io : module.parent.exports
1984 , this
1985);
1986/**
1987 * socket.io
1988 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1989 * MIT Licensed
1990 */
1991
1992(function (exports, io) {
1993
1994 /**
1995 * Expose constructor.
1996 */
1997
1998 exports.SocketNamespace = SocketNamespace;
1999
2000 /**
2001 * Socket namespace constructor.
2002 *
2003 * @constructor
2004 * @api public
2005 */
2006
2007 function SocketNamespace (socket, name) {
2008 this.socket = socket;
2009 this.name = name || '';
2010 this.flags = {};
2011 this.json = new Flag(this, 'json');
2012 this.ackPackets = 0;
2013 this.acks = {};
2014 };
2015
2016 /**
2017 * Apply EventEmitter mixin.
2018 */
2019
2020 io.util.mixin(SocketNamespace, io.EventEmitter);
2021
2022 /**
2023 * Copies emit since we override it
2024 *
2025 * @api private
2026 */
2027
2028 SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
2029
2030 /**
2031 * Creates a new namespace, by proxying the request to the socket. This
2032 * allows us to use the synax as we do on the server.
2033 *
2034 * @api public
2035 */
2036
2037 SocketNamespace.prototype.of = function () {
2038 return this.socket.of.apply(this.socket, arguments);
2039 };
2040
2041 /**
2042 * Sends a packet.
2043 *
2044 * @api private
2045 */
2046
2047 SocketNamespace.prototype.packet = function (packet) {
2048 packet.endpoint = this.name;
2049 this.socket.packet(packet);
2050 this.flags = {};
2051 return this;
2052 };
2053
2054 /**
2055 * Sends a message
2056 *
2057 * @api public
2058 */
2059
2060 SocketNamespace.prototype.send = function (data, fn) {
2061 var packet = {
2062 type: this.flags.json ? 'json' : 'message'
2063 , data: data
2064 };
2065
2066 if ('function' == typeof fn) {
2067 packet.id = ++this.ackPackets;
2068 packet.ack = true;
2069 this.acks[packet.id] = fn;
2070 }
2071
2072 return this.packet(packet);
2073 };
2074
2075 /**
2076 * Emits an event
2077 *
2078 * @api public
2079 */
2080
2081 SocketNamespace.prototype.emit = function (name) {
2082 var args = Array.prototype.slice.call(arguments, 1)
2083 , lastArg = args[args.length - 1]
2084 , packet = {
2085 type: 'event'
2086 , name: name
2087 };
2088
2089 if ('function' == typeof lastArg) {
2090 packet.id = ++this.ackPackets;
2091 packet.ack = 'data';
2092 this.acks[packet.id] = lastArg;
2093 args = args.slice(0, args.length - 1);
2094 }
2095
2096 packet.args = args;
2097
2098 return this.packet(packet);
2099 };
2100
2101 /**
2102 * Disconnects the namespace
2103 *
2104 * @api private
2105 */
2106
2107 SocketNamespace.prototype.disconnect = function () {
2108 if (this.name === '') {
2109 this.socket.disconnect();
2110 } else {
2111 this.packet({ type: 'disconnect' });
2112 this.$emit('disconnect');
2113 }
2114
2115 return this;
2116 };
2117
2118 /**
2119 * Handles a packet
2120 *
2121 * @api private
2122 */
2123
2124 SocketNamespace.prototype.onPacket = function (packet) {
2125 var self = this;
2126
2127 function ack () {
2128 self.packet({
2129 type: 'ack'
2130 , args: io.util.toArray(arguments)
2131 , ackId: packet.id
2132 });
2133 };
2134
2135 switch (packet.type) {
2136 case 'connect':
2137 this.$emit('connect');
2138 break;
2139
2140 case 'disconnect':
2141 if (this.name === '') {
2142 this.socket.onDisconnect(packet.reason || 'booted');
2143 } else {
2144 this.$emit('disconnect', packet.reason);
2145 }
2146 break;
2147
2148 case 'message':
2149 case 'json':
2150 var params = ['message', packet.data];
2151
2152 if (packet.ack == 'data') {
2153 params.push(ack);
2154 } else if (packet.ack) {
2155 this.packet({ type: 'ack', ackId: packet.id });
2156 }
2157
2158 this.$emit.apply(this, params);
2159 break;
2160
2161 case 'event':
2162 var params = [packet.name].concat(packet.args);
2163
2164 if (packet.ack == 'data')
2165 params.push(ack);
2166
2167 this.$emit.apply(this, params);
2168 break;
2169
2170 case 'ack':
2171 if (this.acks[packet.ackId]) {
2172 this.acks[packet.ackId].apply(this, packet.args);
2173 delete this.acks[packet.ackId];
2174 }
2175 break;
2176
2177 case 'error':
2178 if (packet.advice){
2179 this.socket.onError(packet);
2180 } else {
2181 if (packet.reason == 'unauthorized') {
2182 this.$emit('connect_failed', packet.reason);
2183 } else {
2184 this.$emit('error', packet.reason);
2185 }
2186 }
2187 break;
2188 }
2189 };
2190
2191 /**
2192 * Flag interface.
2193 *
2194 * @api private
2195 */
2196
2197 function Flag (nsp, name) {
2198 this.namespace = nsp;
2199 this.name = name;
2200 };
2201
2202 /**
2203 * Send a message
2204 *
2205 * @api public
2206 */
2207
2208 Flag.prototype.send = function () {
2209 this.namespace.flags[this.name] = true;
2210 this.namespace.send.apply(this.namespace, arguments);
2211 };
2212
2213 /**
2214 * Emit an event
2215 *
2216 * @api public
2217 */
2218
2219 Flag.prototype.emit = function () {
2220 this.namespace.flags[this.name] = true;
2221 this.namespace.emit.apply(this.namespace, arguments);
2222 };
2223
2224})(
2225 'undefined' != typeof io ? io : module.exports
2226 , 'undefined' != typeof io ? io : module.parent.exports
2227);
2228
2229/**
2230 * socket.io
2231 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2232 * MIT Licensed
2233 */
2234
2235(function (exports, io) {
2236
2237 /**
2238 * Expose constructor.
2239 */
2240
2241 exports.websocket = WS;
2242
2243 /**
2244 * The WebSocket transport uses the HTML5 WebSocket API to establish an
2245 * persistent connection with the Socket.IO server. This transport will also
2246 * be inherited by the FlashSocket fallback as it provides a API compatible
2247 * polyfill for the WebSockets.
2248 *
2249 * @constructor
2250 * @extends {io.Transport}
2251 * @api public
2252 */
2253
2254 function WS (socket) {
2255 io.Transport.apply(this, arguments);
2256 };
2257
2258 /**
2259 * Inherits from Transport.
2260 */
2261
2262 io.util.inherit(WS, io.Transport);
2263
2264 /**
2265 * Transport name
2266 *
2267 * @api public
2268 */
2269
2270 WS.prototype.name = 'websocket';
2271
2272 /**
2273 * Initializes a new `WebSocket` connection with the Socket.IO server. We attach
2274 * all the appropriate listeners to handle the responses from the server.
2275 *
2276 * @returns {Transport}
2277 * @api public
2278 */
2279
2280 WS.prototype.open = function () {
2281 var self = this
2282 , query = io.util.query(this.socket.options.query);
2283
2284 this.websocket = new WebSocket(this.prepareUrl() + query);
2285
2286 var self = this;
2287 this.websocket.onopen = function () {
2288 self.onOpen();
2289 self.socket.setBuffer(false);
2290 };
2291 this.websocket.onmessage = function (ev) {
2292 self.onData(ev.data);
2293 };
2294 this.websocket.onclose = function () {
2295 self.onClose();
2296 self.socket.setBuffer(true);
2297 };
2298 this.websocket.onerror = function (e) {
2299 self.onError(e);
2300 };
2301
2302 return this;
2303 };
2304
2305 /**
2306 * Send a message to the Socket.IO server. The message will automatically be
2307 * encoded in the correct message format.
2308 *
2309 * @returns {Transport}
2310 * @api public
2311 */
2312
2313 WS.prototype.send = function (data) {
2314 this.websocket.send(data);
2315 return this;
2316 };
2317
2318 /**
2319 * Payload
2320 *
2321 * @api private
2322 */
2323
2324 WS.prototype.payload = function (arr) {
2325 for (var i = 0, l = arr.length; i < l; i++) {
2326 this.packet(arr[i]);
2327 }
2328 return this;
2329 };
2330
2331 /**
2332 * Disconnect the established `WebSocket` connection.
2333 *
2334 * @returns {Transport}
2335 * @api public
2336 */
2337
2338 WS.prototype.close = function () {
2339 this.websocket.close();
2340 return this;
2341 };
2342
2343 /**
2344 * Handle the errors that `WebSocket` might be giving when we
2345 * are attempting to connect or send messages.
2346 *
2347 * @param {Error} e The error.
2348 * @api private
2349 */
2350
2351 WS.prototype.onError = function (e) {
2352 this.socket.onError(e);
2353 };
2354
2355 /**
2356 * Returns the appropriate scheme for the URI generation.
2357 *
2358 * @api private
2359 */
2360 WS.prototype.scheme = function () {
2361 return this.socket.options.secure ? 'wss' : 'ws';
2362 };
2363
2364 /**
2365 * Checks if the browser has support for native `WebSockets` and that
2366 * it's not the polyfill created for the FlashSocket transport.
2367 *
2368 * @return {Boolean}
2369 * @api public
2370 */
2371
2372 WS.check = function () {
2373 return 'WebSocket' in window && !('__addTask' in WebSocket);
2374 };
2375
2376 /**
2377 * Check if the `WebSocket` transport support cross domain communications.
2378 *
2379 * @returns {Boolean}
2380 * @api public
2381 */
2382
2383 WS.xdomainCheck = function () {
2384 return true;
2385 };
2386
2387 /**
2388 * Add the transport to your public io.transports array.
2389 *
2390 * @api private
2391 */
2392
2393 io.transports.push('websocket');
2394
2395
2396})(
2397 'undefined' != typeof io ? io.Transport : module.exports
2398 , 'undefined' != typeof io ? io : module.parent.exports
2399);
2400
2401/**
2402 * socket.io
2403 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2404 * MIT Licensed
2405 */
2406
2407(function (exports, io) {
2408
2409 /**
2410 * Expose constructor.
2411 */
2412
2413 exports.flashsocket = Flashsocket;
2414
2415 /**
2416 * The FlashSocket transport. This is a API wrapper for the HTML5 WebSocket
2417 * specification. It uses a .swf file to communicate with the server. If you want
2418 * to serve the .swf file from a other server than where the Socket.IO script is
2419 * coming from you need to use the insecure version of the .swf. More information
2420 * about this can be found on the github page.
2421 *
2422 * @constructor
2423 * @extends {io.Transport.websocket}
2424 * @api public
2425 */
2426
2427 function Flashsocket () {
2428 io.Transport.websocket.apply(this, arguments);
2429 };
2430
2431 /**
2432 * Inherits from Transport.
2433 */
2434
2435 io.util.inherit(Flashsocket, io.Transport.websocket);
2436
2437 /**
2438 * Transport name
2439 *
2440 * @api public
2441 */
2442
2443 Flashsocket.prototype.name = 'flashsocket';
2444
2445 /**
2446 *Disconnect the established `FlashSocket` connection. This is done by adding a
2447 * new task to the FlashSocket. The rest will be handled off by the `WebSocket`
2448 * transport.
2449 *
2450 * @returns {Transport}
2451 * @api public
2452 */
2453
2454 Flashsocket.prototype.open = function () {
2455 var self = this
2456 , args = arguments;
2457
2458 WebSocket.__addTask(function () {
2459 io.Transport.websocket.prototype.open.apply(self, args);
2460 });
2461 return this;
2462 };
2463
2464 /**
2465 * Sends a message to the Socket.IO server. This is done by adding a new
2466 * task to the FlashSocket. The rest will be handled off by the `WebSocket`
2467 * transport.
2468 *
2469 * @returns {Transport}
2470 * @api public
2471 */
2472
2473 Flashsocket.prototype.send = function () {
2474 var self = this, args = arguments;
2475 WebSocket.__addTask(function () {
2476 io.Transport.websocket.prototype.send.apply(self, args);
2477 });
2478 return this;
2479 };
2480
2481 /**
2482 * Disconnects the established `FlashSocket` connection.
2483 *
2484 * @returns {Transport}
2485 * @api public
2486 */
2487
2488 Flashsocket.prototype.close = function () {
2489 WebSocket.__tasks.length = 0;
2490 io.Transport.websocket.prototype.close.call(this);
2491 return this;
2492 };
2493
2494 /**
2495 * The WebSocket fall back needs to append the flash container to the body
2496 * element, so we need to make sure we have access to it. Or defer the call
2497 * until we are sure there is a body element.
2498 *
2499 * @param {Socket} socket The socket instance that needs a transport
2500 * @param {Function} fn The callback
2501 * @api private
2502 */
2503
2504 Flashsocket.prototype.ready = function (socket, fn) {
2505 function init () {
2506 var options = socket.options
2507 , path = [
2508 'http' + (options.secure ? 's' : '') + ':/'
2509 , options.host + ':' + options.port
2510 , options.resource
2511 , 'static/flashsocket'
2512 , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
2513 ];
2514
2515 // Only start downloading the swf file when the checked that this browser
2516 // actually supports it
2517 if (!Flashsocket.loaded) {
2518 if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
2519 // Set the correct file based on the XDomain settings
2520 WEB_SOCKET_SWF_LOCATION = path.join('/');
2521 }
2522
2523 WebSocket.__initialize();
2524 Flashsocket.loaded = true;
2525 }
2526
2527 fn.call(self);
2528 }
2529
2530 var self = this;
2531 if (document.body) return init();
2532
2533 io.util.load(init);
2534 };
2535
2536 /**
2537 * Check if the FlashSocket transport is supported as it requires that the Adobe
2538 * Flash Player plug-in version `10.0.0` or greater is installed. And also check if
2539 * the polyfill is correctly loaded.
2540 *
2541 * @returns {Boolean}
2542 * @api public
2543 */
2544
2545 Flashsocket.check = function () {
2546 if (
2547 typeof WebSocket == 'undefined'
2548 || !('__initialize' in WebSocket) || !swfobject
2549 ) return false;
2550
2551 return swfobject.getFlashPlayerVersion().major >= 1;
2552 };
2553
2554 /**
2555 * Check if the FlashSocket transport can be used as cross domain / cross origin
2556 * transport. Because we can't see which type (secure or insecure) of .swf is used
2557 * we will just return true.
2558 *
2559 * @returns {Boolean}
2560 * @api public
2561 */
2562
2563 Flashsocket.xdomainCheck = function () {
2564 return true;
2565 };
2566
2567 /**
2568 * Disable AUTO_INITIALIZATION
2569 */
2570
2571 if (typeof window != 'undefined') {
2572 WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true;
2573 }
2574
2575 /**
2576 * Add the transport to your public io.transports array.
2577 *
2578 * @api private
2579 */
2580
2581 io.transports.push('flashsocket');
2582})(
2583 'undefined' != typeof io ? io.Transport : module.exports
2584 , 'undefined' != typeof io ? io : module.parent.exports
2585);
2586/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
2587 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
2588*/
2589var 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/>
2590// License: New BSD License
2591// Reference: http://dev.w3.org/html5/websockets/
2592// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
2593
2594(function() {
2595
2596 if (window.WebSocket) return;
2597
2598 var console = window.console;
2599 if (!console || !console.log || !console.error) {
2600 console = {log: function(){ }, error: function(){ }};
2601 }
2602
2603 if (!swfobject.hasFlashPlayerVersion("10.0.0")) {
2604 console.error("Flash Player >= 10.0.0 is required.");
2605 return;
2606 }
2607 if (location.protocol == "file:") {
2608 console.error(
2609 "WARNING: web-socket-js doesn't work in file:///... URL " +
2610 "unless you set Flash Security Settings properly. " +
2611 "Open the page via Web server i.e. http://...");
2612 }
2613
2614 /**
2615 * This class represents a faux web socket.
2616 * @param {string} url
2617 * @param {array or string} protocols
2618 * @param {string} proxyHost
2619 * @param {int} proxyPort
2620 * @param {string} headers
2621 */
2622 WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
2623 var self = this;
2624 self.__id = WebSocket.__nextId++;
2625 WebSocket.__instances[self.__id] = self;
2626 self.readyState = WebSocket.CONNECTING;
2627 self.bufferedAmount = 0;
2628 self.__events = {};
2629 if (!protocols) {
2630 protocols = [];
2631 } else if (typeof protocols == "string") {
2632 protocols = [protocols];
2633 }
2634 // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
2635 // Otherwise, when onopen fires immediately, onopen is called before it is set.
2636 setTimeout(function() {
2637 WebSocket.__addTask(function() {
2638 WebSocket.__flash.create(
2639 self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
2640 });
2641 }, 0);
2642 };
2643
2644 /**
2645 * Send data to the web socket.
2646 * @param {string} data The data to send to the socket.
2647 * @return {boolean} True for success, false for failure.
2648 */
2649 WebSocket.prototype.send = function(data) {
2650 if (this.readyState == WebSocket.CONNECTING) {
2651 throw "INVALID_STATE_ERR: Web Socket connection has not been established";
2652 }
2653 // We use encodeURIComponent() here, because FABridge doesn't work if
2654 // the argument includes some characters. We don't use escape() here
2655 // because of this:
2656 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
2657 // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
2658 // preserve all Unicode characters either e.g. "\uffff" in Firefox.
2659 // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
2660 // additional testing.
2661 var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
2662 if (result < 0) { // success
2663 return true;
2664 } else {
2665 this.bufferedAmount += result;
2666 return false;
2667 }
2668 };
2669
2670 /**
2671 * Close this web socket gracefully.
2672 */
2673 WebSocket.prototype.close = function() {
2674 if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
2675 return;
2676 }
2677 this.readyState = WebSocket.CLOSING;
2678 WebSocket.__flash.close(this.__id);
2679 };
2680
2681 /**
2682 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
2683 *
2684 * @param {string} type
2685 * @param {function} listener
2686 * @param {boolean} useCapture
2687 * @return void
2688 */
2689 WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
2690 if (!(type in this.__events)) {
2691 this.__events[type] = [];
2692 }
2693 this.__events[type].push(listener);
2694 };
2695
2696 /**
2697 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
2698 *
2699 * @param {string} type
2700 * @param {function} listener
2701 * @param {boolean} useCapture
2702 * @return void
2703 */
2704 WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
2705 if (!(type in this.__events)) return;
2706 var events = this.__events[type];
2707 for (var i = events.length - 1; i >= 0; --i) {
2708 if (events[i] === listener) {
2709 events.splice(i, 1);
2710 break;
2711 }
2712 }
2713 };
2714
2715 /**
2716 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
2717 *
2718 * @param {Event} event
2719 * @return void
2720 */
2721 WebSocket.prototype.dispatchEvent = function(event) {
2722 var events = this.__events[event.type] || [];
2723 for (var i = 0; i < events.length; ++i) {
2724 events[i](event);
2725 }
2726 var handler = this["on" + event.type];
2727 if (handler) handler(event);
2728 };
2729
2730 /**
2731 * Handles an event from Flash.
2732 * @param {Object} flashEvent
2733 */
2734 WebSocket.prototype.__handleEvent = function(flashEvent) {
2735 if ("readyState" in flashEvent) {
2736 this.readyState = flashEvent.readyState;
2737 }
2738 if ("protocol" in flashEvent) {
2739 this.protocol = flashEvent.protocol;
2740 }
2741
2742 var jsEvent;
2743 if (flashEvent.type == "open" || flashEvent.type == "error") {
2744 jsEvent = this.__createSimpleEvent(flashEvent.type);
2745 } else if (flashEvent.type == "close") {
2746 // TODO implement jsEvent.wasClean
2747 jsEvent = this.__createSimpleEvent("close");
2748 } else if (flashEvent.type == "message") {
2749 var data = decodeURIComponent(flashEvent.message);
2750 jsEvent = this.__createMessageEvent("message", data);
2751 } else {
2752 throw "unknown event type: " + flashEvent.type;
2753 }
2754
2755 this.dispatchEvent(jsEvent);
2756 };
2757
2758 WebSocket.prototype.__createSimpleEvent = function(type) {
2759 if (document.createEvent && window.Event) {
2760 var event = document.createEvent("Event");
2761 event.initEvent(type, false, false);
2762 return event;
2763 } else {
2764 return {type: type, bubbles: false, cancelable: false};
2765 }
2766 };
2767
2768 WebSocket.prototype.__createMessageEvent = function(type, data) {
2769 if (document.createEvent && window.MessageEvent && !window.opera) {
2770 var event = document.createEvent("MessageEvent");
2771 event.initMessageEvent("message", false, false, data, null, null, window, null);
2772 return event;
2773 } else {
2774 // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
2775 return {type: type, data: data, bubbles: false, cancelable: false};
2776 }
2777 };
2778
2779 /**
2780 * Define the WebSocket readyState enumeration.
2781 */
2782 WebSocket.CONNECTING = 0;
2783 WebSocket.OPEN = 1;
2784 WebSocket.CLOSING = 2;
2785 WebSocket.CLOSED = 3;
2786
2787 WebSocket.__flash = null;
2788 WebSocket.__instances = {};
2789 WebSocket.__tasks = [];
2790 WebSocket.__nextId = 0;
2791
2792 /**
2793 * Load a new flash security policy file.
2794 * @param {string} url
2795 */
2796 WebSocket.loadFlashPolicyFile = function(url){
2797 WebSocket.__addTask(function() {
2798 WebSocket.__flash.loadManualPolicyFile(url);
2799 });
2800 };
2801
2802 /**
2803 * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
2804 */
2805 WebSocket.__initialize = function() {
2806 if (WebSocket.__flash) return;
2807
2808 if (WebSocket.__swfLocation) {
2809 // For backword compatibility.
2810 window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
2811 }
2812 if (!window.WEB_SOCKET_SWF_LOCATION) {
2813 console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
2814 return;
2815 }
2816 var container = document.createElement("div");
2817 container.id = "webSocketContainer";
2818 // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
2819 // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
2820 // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
2821 // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
2822 // the best we can do as far as we know now.
2823 container.style.position = "absolute";
2824 if (WebSocket.__isFlashLite()) {
2825 container.style.left = "0px";
2826 container.style.top = "0px";
2827 } else {
2828 container.style.left = "-100px";
2829 container.style.top = "-100px";
2830 }
2831 var holder = document.createElement("div");
2832 holder.id = "webSocketFlash";
2833 container.appendChild(holder);
2834 document.body.appendChild(container);
2835 // See this article for hasPriority:
2836 // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
2837 swfobject.embedSWF(
2838 WEB_SOCKET_SWF_LOCATION,
2839 "webSocketFlash",
2840 "1" /* width */,
2841 "1" /* height */,
2842 "10.0.0" /* SWF version */,
2843 null,
2844 null,
2845 {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
2846 null,
2847 function(e) {
2848 if (!e.success) {
2849 console.error("[WebSocket] swfobject.embedSWF failed");
2850 }
2851 });
2852 };
2853
2854 /**
2855 * Called by Flash to notify JS that it's fully loaded and ready
2856 * for communication.
2857 */
2858 WebSocket.__onFlashInitialized = function() {
2859 // We need to set a timeout here to avoid round-trip calls
2860 // to flash during the initialization process.
2861 setTimeout(function() {
2862 WebSocket.__flash = document.getElementById("webSocketFlash");
2863 WebSocket.__flash.setCallerUrl(location.href);
2864 WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
2865 for (var i = 0; i < WebSocket.__tasks.length; ++i) {
2866 WebSocket.__tasks[i]();
2867 }
2868 WebSocket.__tasks = [];
2869 }, 0);
2870 };
2871
2872 /**
2873 * Called by Flash to notify WebSockets events are fired.
2874 */
2875 WebSocket.__onFlashEvent = function() {
2876 setTimeout(function() {
2877 try {
2878 // Gets events using receiveEvents() instead of getting it from event object
2879 // of Flash event. This is to make sure to keep message order.
2880 // It seems sometimes Flash events don't arrive in the same order as they are sent.
2881 var events = WebSocket.__flash.receiveEvents();
2882 for (var i = 0; i < events.length; ++i) {
2883 WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
2884 }
2885 } catch (e) {
2886 console.error(e);
2887 }
2888 }, 0);
2889 return true;
2890 };
2891
2892 // Called by Flash.
2893 WebSocket.__log = function(message) {
2894 console.log(decodeURIComponent(message));
2895 };
2896
2897 // Called by Flash.
2898 WebSocket.__error = function(message) {
2899 console.error(decodeURIComponent(message));
2900 };
2901
2902 WebSocket.__addTask = function(task) {
2903 if (WebSocket.__flash) {
2904 task();
2905 } else {
2906 WebSocket.__tasks.push(task);
2907 }
2908 };
2909
2910 /**
2911 * Test if the browser is running flash lite.
2912 * @return {boolean} True if flash lite is running, false otherwise.
2913 */
2914 WebSocket.__isFlashLite = function() {
2915 if (!window.navigator || !window.navigator.mimeTypes) {
2916 return false;
2917 }
2918 var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
2919 if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
2920 return false;
2921 }
2922 return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
2923 };
2924
2925 if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
2926 if (window.addEventListener) {
2927 window.addEventListener("load", function(){
2928 WebSocket.__initialize();
2929 }, false);
2930 } else {
2931 window.attachEvent("onload", function(){
2932 WebSocket.__initialize();
2933 });
2934 }
2935 }
2936
2937})();
2938
2939/**
2940 * socket.io
2941 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2942 * MIT Licensed
2943 */
2944
2945(function (exports, io, global) {
2946
2947 /**
2948 * Expose constructor.
2949 *
2950 * @api public
2951 */
2952
2953 exports.XHR = XHR;
2954
2955 /**
2956 * XHR constructor
2957 *
2958 * @costructor
2959 * @api public
2960 */
2961
2962 function XHR (socket) {
2963 if (!socket) return;
2964
2965 io.Transport.apply(this, arguments);
2966 this.sendBuffer = [];
2967 };
2968
2969 /**
2970 * Inherits from Transport.
2971 */
2972
2973 io.util.inherit(XHR, io.Transport);
2974
2975 /**
2976 * Establish a connection
2977 *
2978 * @returns {Transport}
2979 * @api public
2980 */
2981
2982 XHR.prototype.open = function () {
2983 this.socket.setBuffer(false);
2984 this.onOpen();
2985 this.get();
2986
2987 // we need to make sure the request succeeds since we have no indication
2988 // whether the request opened or not until it succeeded.
2989 this.setCloseTimeout();
2990
2991 return this;
2992 };
2993
2994 /**
2995 * Check if we need to send data to the Socket.IO server, if we have data in our
2996 * buffer we encode it and forward it to the `post` method.
2997 *
2998 * @api private
2999 */
3000
3001 XHR.prototype.payload = function (payload) {
3002 var msgs = [];
3003
3004 for (var i = 0, l = payload.length; i < l; i++) {
3005 msgs.push(io.parser.encodePacket(payload[i]));
3006 }
3007
3008 this.send(io.parser.encodePayload(msgs));
3009 };
3010
3011 /**
3012 * Send data to the Socket.IO server.
3013 *
3014 * @param data The message
3015 * @returns {Transport}
3016 * @api public
3017 */
3018
3019 XHR.prototype.send = function (data) {
3020 this.post(data);
3021 return this;
3022 };
3023
3024 /**
3025 * Posts a encoded message to the Socket.IO server.
3026 *
3027 * @param {String} data A encoded message.
3028 * @api private
3029 */
3030
3031 function empty () { };
3032
3033 XHR.prototype.post = function (data) {
3034 var self = this;
3035 this.socket.setBuffer(true);
3036
3037 function stateChange () {
3038 if (this.readyState == 4) {
3039 this.onreadystatechange = empty;
3040 self.posting = false;
3041
3042 if (this.status == 200){
3043 self.socket.setBuffer(false);
3044 } else {
3045 self.onClose();
3046 }
3047 }
3048 }
3049
3050 function onload () {
3051 this.onload = empty;
3052 self.socket.setBuffer(false);
3053 };
3054
3055 this.sendXHR = this.request('POST');
3056
3057 if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
3058 this.sendXHR.onload = this.sendXHR.onerror = onload;
3059 } else {
3060 this.sendXHR.onreadystatechange = stateChange;
3061 }
3062
3063 this.sendXHR.send(data);
3064 };
3065
3066 /**
3067 * Disconnects the established `XHR` connection.
3068 *
3069 * @returns {Transport}
3070 * @api public
3071 */
3072
3073 XHR.prototype.close = function () {
3074 this.onClose();
3075 return this;
3076 };
3077
3078 /**
3079 * Generates a configured XHR request
3080 *
3081 * @param {String} url The url that needs to be requested.
3082 * @param {String} method The method the request should use.
3083 * @returns {XMLHttpRequest}
3084 * @api private
3085 */
3086
3087 XHR.prototype.request = function (method) {
3088 var req = io.util.request(this.socket.isXDomain())
3089 , query = io.util.query(this.socket.options.query, 't=' + +new Date);
3090
3091 req.open(method || 'GET', this.prepareUrl() + query, true);
3092
3093 if (method == 'POST') {
3094 try {
3095 if (req.setRequestHeader) {
3096 req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
3097 } else {
3098 // XDomainRequest
3099 req.contentType = 'text/plain';
3100 }
3101 } catch (e) {}
3102 }
3103
3104 return req;
3105 };
3106
3107 /**
3108 * Returns the scheme to use for the transport URLs.
3109 *
3110 * @api private
3111 */
3112
3113 XHR.prototype.scheme = function () {
3114 return this.socket.options.secure ? 'https' : 'http';
3115 };
3116
3117 /**
3118 * Check if the XHR transports are supported
3119 *
3120 * @param {Boolean} xdomain Check if we support cross domain requests.
3121 * @returns {Boolean}
3122 * @api public
3123 */
3124
3125 XHR.check = function (socket, xdomain) {
3126 try {
3127 if (io.util.request(xdomain)) {
3128 return true;
3129 }
3130 } catch(e) {}
3131
3132 return false;
3133 };
3134
3135 /**
3136 * Check if the XHR transport supports corss domain requests.
3137 *
3138 * @returns {Boolean}
3139 * @api public
3140 */
3141
3142 XHR.xdomainCheck = function () {
3143 return XHR.check(null, true);
3144 };
3145
3146})(
3147 'undefined' != typeof io ? io.Transport : module.exports
3148 , 'undefined' != typeof io ? io : module.parent.exports
3149 , this
3150);
3151
3152/**
3153 * socket.io
3154 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
3155 * MIT Licensed
3156 */
3157
3158(function (exports, io) {
3159
3160 /**
3161 * Expose constructor.
3162 */
3163
3164 exports.htmlfile = HTMLFile;
3165
3166 /**
3167 * The HTMLFile transport creates a `forever iframe` based transport
3168 * for Internet Explorer. Regular forever iframe implementations will
3169 * continuously trigger the browsers buzy indicators. If the forever iframe
3170 * is created inside a `htmlfile` these indicators will not be trigged.
3171 *
3172 * @constructor
3173 * @extends {io.Transport.XHR}
3174 * @api public
3175 */
3176
3177 function HTMLFile (socket) {
3178 io.Transport.XHR.apply(this, arguments);
3179 };
3180
3181 /**
3182 * Inherits from XHR transport.
3183 */
3184
3185 io.util.inherit(HTMLFile, io.Transport.XHR);
3186
3187 /**
3188 * Transport name
3189 *
3190 * @api public
3191 */
3192
3193 HTMLFile.prototype.name = 'htmlfile';
3194
3195 /**
3196 * Creates a new ActiveX `htmlfile` with a forever loading iframe
3197 * that can be used to listen to messages. Inside the generated
3198 * `htmlfile` a reference will be made to the HTMLFile transport.
3199 *
3200 * @api private
3201 */
3202
3203 HTMLFile.prototype.get = function () {
3204 this.doc = new ActiveXObject('htmlfile');
3205 this.doc.open();
3206 this.doc.write('<html></html>');
3207 this.doc.close();
3208 this.doc.parentWindow.s = this;
3209
3210 var iframeC = this.doc.createElement('div');
3211 iframeC.className = 'socketio';
3212
3213 this.doc.body.appendChild(iframeC);
3214 this.iframe = this.doc.createElement('iframe');
3215
3216 iframeC.appendChild(this.iframe);
3217
3218 var self = this
3219 , query = io.util.query(this.socket.options.query, 't='+ +new Date);
3220
3221 this.iframe.src = this.prepareUrl() + query;
3222
3223 io.util.on(window, 'unload', function () {
3224 self.destroy();
3225 });
3226 };
3227
3228 /**
3229 * The Socket.IO server will write script tags inside the forever
3230 * iframe, this function will be used as callback for the incoming
3231 * information.
3232 *
3233 * @param {String} data The message
3234 * @param {document} doc Reference to the context
3235 * @api private
3236 */
3237
3238 HTMLFile.prototype._ = function (data, doc) {
3239 this.onData(data);
3240 try {
3241 var script = doc.getElementsByTagName('script')[0];
3242 script.parentNode.removeChild(script);
3243 } catch (e) { }
3244 };
3245
3246 /**
3247 * Destroy the established connection, iframe and `htmlfile`.
3248 * And calls the `CollectGarbage` function of Internet Explorer
3249 * to release the memory.
3250 *
3251 * @api private
3252 */
3253
3254 HTMLFile.prototype.destroy = function () {
3255 if (this.iframe){
3256 try {
3257 this.iframe.src = 'about:blank';
3258 } catch(e){}
3259
3260 this.doc = null;
3261 this.iframe.parentNode.removeChild(this.iframe);
3262 this.iframe = null;
3263
3264 CollectGarbage();
3265 }
3266 };
3267
3268 /**
3269 * Disconnects the established connection.
3270 *
3271 * @returns {Transport} Chaining.
3272 * @api public
3273 */
3274
3275 HTMLFile.prototype.close = function () {
3276 this.destroy();
3277 return io.Transport.XHR.prototype.close.call(this);
3278 };
3279
3280 /**
3281 * Checks if the browser supports this transport. The browser
3282 * must have an `ActiveXObject` implementation.
3283 *
3284 * @return {Boolean}
3285 * @api public
3286 */
3287
3288 HTMLFile.check = function () {
3289 if ('ActiveXObject' in window){
3290 try {
3291 var a = new ActiveXObject('htmlfile');
3292 return a && io.Transport.XHR.check();
3293 } catch(e){}
3294 }
3295 return false;
3296 };
3297
3298 /**
3299 * Check if cross domain requests are supported.
3300 *
3301 * @returns {Boolean}
3302 * @api public
3303 */
3304
3305 HTMLFile.xdomainCheck = function () {
3306 // we can probably do handling for sub-domains, we should
3307 // test that it's cross domain but a subdomain here
3308 return false;
3309 };
3310
3311 /**
3312 * Add the transport to your public io.transports array.
3313 *
3314 * @api private
3315 */
3316
3317 io.transports.push('htmlfile');
3318
3319})(
3320 'undefined' != typeof io ? io.Transport : module.exports
3321 , 'undefined' != typeof io ? io : module.parent.exports
3322);
3323
3324/**
3325 * socket.io
3326 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
3327 * MIT Licensed
3328 */
3329
3330(function (exports, io, global) {
3331
3332 /**
3333 * Expose constructor.
3334 */
3335
3336 exports['xhr-polling'] = XHRPolling;
3337
3338 /**
3339 * The XHR-polling transport uses long polling XHR requests to create a
3340 * "persistent" connection with the server.
3341 *
3342 * @constructor
3343 * @api public
3344 */
3345
3346 function XHRPolling () {
3347 io.Transport.XHR.apply(this, arguments);
3348 };
3349
3350 /**
3351 * Inherits from XHR transport.
3352 */
3353
3354 io.util.inherit(XHRPolling, io.Transport.XHR);
3355
3356 /**
3357 * Merge the properties from XHR transport
3358 */
3359
3360 io.util.merge(XHRPolling, io.Transport.XHR);
3361
3362 /**
3363 * Transport name
3364 *
3365 * @api public
3366 */
3367
3368 XHRPolling.prototype.name = 'xhr-polling';
3369
3370 /**
3371 * Establish a connection, for iPhone and Android this will be done once the page
3372 * is loaded.
3373 *
3374 * @returns {Transport} Chaining.
3375 * @api public
3376 */
3377
3378 XHRPolling.prototype.open = function () {
3379 var self = this;
3380
3381 io.Transport.XHR.prototype.open.call(self);
3382 return false;
3383 };
3384
3385 /**
3386 * Starts a XHR request to wait for incoming messages.
3387 *
3388 * @api private
3389 */
3390
3391 function empty () {};
3392
3393 XHRPolling.prototype.get = function () {
3394 if (!this.open) return;
3395
3396 var self = this;
3397
3398 function stateChange () {
3399 if (this.readyState == 4) {
3400 this.onreadystatechange = empty;
3401
3402 if (this.status == 200) {
3403 self.onData(this.responseText);
3404 self.get();
3405 } else {
3406 self.onClose();
3407 }
3408 }
3409 };
3410
3411 function onload () {
3412 this.onload = empty;
3413 self.onData(this.responseText);
3414 self.get();
3415 };
3416
3417 this.xhr = this.request();
3418
3419 if (global.XDomainRequest && this.xhr instanceof XDomainRequest) {
3420 this.xhr.onload = this.xhr.onerror = onload;
3421 } else {
3422 this.xhr.onreadystatechange = stateChange;
3423 }
3424
3425 this.xhr.send(null);
3426 };
3427
3428 /**
3429 * Handle the unclean close behavior.
3430 *
3431 * @api private
3432 */
3433
3434 XHRPolling.prototype.onClose = function () {
3435 io.Transport.XHR.prototype.onClose.call(this);
3436
3437 if (this.xhr) {
3438 this.xhr.onreadystatechange = this.xhr.onload = empty;
3439 try {
3440 this.xhr.abort();
3441 } catch(e){}
3442 this.xhr = null;
3443 }
3444 };
3445
3446 /**
3447 * Webkit based browsers show a infinit spinner when you start a XHR request
3448 * before the browsers onload event is called so we need to defer opening of
3449 * the transport until the onload event is called. Wrapping the cb in our
3450 * defer method solve this.
3451 *
3452 * @param {Socket} socket The socket instance that needs a transport
3453 * @param {Function} fn The callback
3454 * @api private
3455 */
3456
3457 XHRPolling.prototype.ready = function (socket, fn) {
3458 var self = this;
3459
3460 io.util.defer(function () {
3461 fn.call(self);
3462 });
3463 };
3464
3465 /**
3466 * Add the transport to your public io.transports array.
3467 *
3468 * @api private
3469 */
3470
3471 io.transports.push('xhr-polling');
3472
3473})(
3474 'undefined' != typeof io ? io.Transport : module.exports
3475 , 'undefined' != typeof io ? io : module.parent.exports
3476 , this
3477);
3478
3479/**
3480 * socket.io
3481 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
3482 * MIT Licensed
3483 */
3484
3485(function (exports, io) {
3486
3487 /**
3488 * Expose constructor.
3489 */
3490
3491 exports['jsonp-polling'] = JSONPPolling;
3492
3493 /**
3494 * The JSONP transport creates an persistent connection by dynamically
3495 * inserting a script tag in the page. This script tag will receive the
3496 * information of the Socket.IO server. When new information is received
3497 * it creates a new script tag for the new data stream.
3498 *
3499 * @constructor
3500 * @extends {io.Transport.xhr-polling}
3501 * @api public
3502 */
3503
3504 function JSONPPolling (socket) {
3505 io.Transport['xhr-polling'].apply(this, arguments);
3506
3507 this.index = io.j.length;
3508
3509 var self = this;
3510
3511 io.j.push(function (msg) {
3512 self._(msg);
3513 });
3514 };
3515
3516 /**
3517 * Inherits from XHR polling transport.
3518 */
3519
3520 io.util.inherit(JSONPPolling, io.Transport['xhr-polling']);
3521
3522 /**
3523 * Transport name
3524 *
3525 * @api public
3526 */
3527
3528 JSONPPolling.prototype.name = 'jsonp-polling';
3529
3530 /**
3531 * Posts a encoded message to the Socket.IO server using an iframe.
3532 * The iframe is used because script tags can create POST based requests.
3533 * The iframe is positioned outside of the view so the user does not
3534 * notice it's existence.
3535 *
3536 * @param {String} data A encoded message.
3537 * @api private
3538 */
3539
3540 JSONPPolling.prototype.post = function (data) {
3541 var self = this
3542 , query = io.util.query(
3543 this.socket.options.query
3544 , 't='+ (+new Date) + '&i=' + this.index
3545 );
3546
3547 if (!this.form) {
3548 var form = document.createElement('FORM')
3549 , area = document.createElement('TEXTAREA')
3550 , id = this.iframeId = 'socketio_iframe_' + this.index
3551 , iframe;
3552
3553 form.className = 'socketio';
3554 form.style.position = 'absolute';
3555 form.style.top = '-1000px';
3556 form.style.left = '-1000px';
3557 form.target = id;
3558 form.method = 'POST';
3559 form.setAttribute('accept-charset', 'utf-8');
3560 area.name = 'd';
3561 form.appendChild(area);
3562 document.body.appendChild(form);
3563
3564 this.form = form;
3565 this.area = area;
3566 }
3567
3568 this.form.action = this.prepareUrl() + query;
3569
3570 function complete () {
3571 initIframe();
3572 self.socket.setBuffer(false);
3573 };
3574
3575 function initIframe () {
3576 if (self.iframe) {
3577 self.form.removeChild(self.iframe);
3578 }
3579
3580 try {
3581 // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
3582 iframe = document.createElement('<iframe name="'+ self.iframeId +'">');
3583 } catch (e) {
3584 iframe = document.createElement('iframe');
3585 iframe.name = self.iframeId;
3586 }
3587
3588 iframe.id = self.iframeId;
3589
3590 self.form.appendChild(iframe);
3591 self.iframe = iframe;
3592 };
3593
3594 initIframe();
3595
3596 this.area.value = data;
3597
3598 try {
3599 this.form.submit();
3600 } catch(e) {}
3601
3602 if (this.iframe.attachEvent) {
3603 iframe.onreadystatechange = function () {
3604 if (self.iframe.readyState == 'complete') {
3605 complete();
3606 }
3607 };
3608 } else {
3609 this.iframe.onload = complete;
3610 }
3611
3612 this.socket.setBuffer(true);
3613 };
3614
3615 /**
3616 * Creates a new JSONP poll that can be used to listen
3617 * for messages from the Socket.IO server.
3618 *
3619 * @api private
3620 */
3621
3622 JSONPPolling.prototype.get = function () {
3623 var self = this
3624 , script = document.createElement('SCRIPT')
3625 , query = io.util.query(
3626 this.socket.options.query
3627 , 't='+ (+new Date) + '&i=' + this.index
3628 );
3629
3630 if (this.script) {
3631 this.script.parentNode.removeChild(this.script);
3632 this.script = null;
3633 }
3634
3635 script.async = true;
3636 script.src = this.prepareUrl() + query;
3637 script.onerror = function () {
3638 self.onClose();
3639 };
3640
3641 var insertAt = document.getElementsByTagName('script')[0]
3642 insertAt.parentNode.insertBefore(script, insertAt);
3643 this.script = script;
3644 };
3645
3646 /**
3647 * Callback function for the incoming message stream from the Socket.IO server.
3648 *
3649 * @param {String} data The message
3650 * @api private
3651 */
3652
3653 JSONPPolling.prototype._ = function (msg) {
3654 this.onData(msg);
3655 if (this.open) {
3656 this.get();
3657 }
3658 return this;
3659 };
3660
3661 /**
3662 * Checks if browser supports this transport.
3663 *
3664 * @return {Boolean}
3665 * @api public
3666 */
3667
3668 JSONPPolling.check = function () {
3669 return true;
3670 };
3671
3672 /**
3673 * Check if cross domain requests are supported
3674 *
3675 * @returns {Boolean}
3676 * @api public
3677 */
3678
3679 JSONPPolling.xdomainCheck = function () {
3680 return true;
3681 };
3682
3683 /**
3684 * Add the transport to your public io.transports array.
3685 *
3686 * @api private
3687 */
3688
3689 io.transports.push('jsonp-polling');
3690
3691})(
3692 'undefined' != typeof io ? io.Transport : module.exports
3693 , 'undefined' != typeof io ? io : module.parent.exports
3694);