juggernaut 2.0.3 → 2.0.4

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