socket.io-rails 0.9.11

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,22 @@
1
+ Copyright (c) 2013 Jason Chen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ # socket.io-rails
2
+
3
+ Rails asset pipeline wrapper for [socket.io.js](https://github.com/LearnBoost/socket.io-client).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'socket.io-rails'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install socket.io-rails
18
+
19
+ ## Usage
20
+
21
+ Include socket.io in your manifest files:
22
+
23
+ //= require socket.io
@@ -0,0 +1,8 @@
1
+ require "socket.io-rails/version"
2
+
3
+ module Socketio
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Socketio
2
+ module Rails
3
+ VERSION = "0.9.11"
4
+ end
5
+ end
@@ -0,0 +1,2898 @@
1
+ /*! Socket.IO.js build:0.9.11, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
2
+
3
+ var io = ('undefined' === typeof module ? {} : module.exports);
4
+ (function() {
5
+
6
+ /**
7
+ * socket.io
8
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
9
+ * MIT Licensed
10
+ */
11
+
12
+ (function (exports, global) {
13
+
14
+ /**
15
+ * IO namespace.
16
+ *
17
+ * @namespace
18
+ */
19
+
20
+ var io = exports;
21
+
22
+ /**
23
+ * Socket.IO version
24
+ *
25
+ * @api public
26
+ */
27
+
28
+ io.version = '0.9.11';
29
+
30
+ /**
31
+ * Protocol implemented.
32
+ *
33
+ * @api public
34
+ */
35
+
36
+ io.protocol = 1;
37
+
38
+ /**
39
+ * Available transports, these will be populated with the available transports
40
+ *
41
+ * @api public
42
+ */
43
+
44
+ io.transports = [];
45
+
46
+ /**
47
+ * Keep track of jsonp callbacks.
48
+ *
49
+ * @api private
50
+ */
51
+
52
+ io.j = [];
53
+
54
+ /**
55
+ * Keep track of our io.Sockets
56
+ *
57
+ * @api private
58
+ */
59
+ io.sockets = {};
60
+
61
+
62
+ /**
63
+ * Manages connections to hosts.
64
+ *
65
+ * @param {String} uri
66
+ * @Param {Boolean} force creation of new socket (defaults to false)
67
+ * @api public
68
+ */
69
+
70
+ io.connect = function (host, details) {
71
+ var uri = io.util.parseUri(host)
72
+ , uuri
73
+ , socket;
74
+
75
+ if (global && global.location) {
76
+ uri.protocol = uri.protocol || global.location.protocol.slice(0, -1);
77
+ uri.host = uri.host || (global.document
78
+ ? global.document.domain : global.location.hostname);
79
+ uri.port = uri.port || global.location.port;
80
+ }
81
+
82
+ uuri = io.util.uniqueUri(uri);
83
+
84
+ var options = {
85
+ host: uri.host
86
+ , secure: 'https' == uri.protocol
87
+ , port: uri.port || ('https' == uri.protocol ? 443 : 80)
88
+ , query: uri.query || ''
89
+ };
90
+
91
+ io.util.merge(options, details);
92
+
93
+ if (options['force new connection'] || !io.sockets[uuri]) {
94
+ socket = new io.Socket(options);
95
+ }
96
+
97
+ if (!options['force new connection'] && socket) {
98
+ io.sockets[uuri] = socket;
99
+ }
100
+
101
+ socket = socket || io.sockets[uuri];
102
+
103
+ // if path is different from '' or /
104
+ return socket.of(uri.path.length > 1 ? uri.path : '');
105
+ };
106
+
107
+ })('object' === typeof module ? module.exports : (this.io = {}), this);
108
+ /**
109
+ * socket.io
110
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
111
+ * MIT Licensed
112
+ */
113
+
114
+ (function (exports, global) {
115
+
116
+ /**
117
+ * Utilities namespace.
118
+ *
119
+ * @namespace
120
+ */
121
+
122
+ var util = exports.util = {};
123
+
124
+ /**
125
+ * Parses an URI
126
+ *
127
+ * @author Steven Levithan <stevenlevithan.com> (MIT license)
128
+ * @api public
129
+ */
130
+
131
+ var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
132
+
133
+ var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
134
+ 'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
135
+ 'anchor'];
136
+
137
+ util.parseUri = function (str) {
138
+ var m = re.exec(str || '')
139
+ , uri = {}
140
+ , i = 14;
141
+
142
+ while (i--) {
143
+ uri[parts[i]] = m[i] || '';
144
+ }
145
+
146
+ return uri;
147
+ };
148
+
149
+ /**
150
+ * Produces a unique url that identifies a Socket.IO connection.
151
+ *
152
+ * @param {Object} uri
153
+ * @api public
154
+ */
155
+
156
+ util.uniqueUri = function (uri) {
157
+ var protocol = uri.protocol
158
+ , host = uri.host
159
+ , port = uri.port;
160
+
161
+ if ('document' in global) {
162
+ host = host || document.domain;
163
+ port = port || (protocol == 'https'
164
+ && document.location.protocol !== 'https:' ? 443 : document.location.port);
165
+ } else {
166
+ host = host || 'localhost';
167
+
168
+ if (!port && protocol == 'https') {
169
+ port = 443;
170
+ }
171
+ }
172
+
173
+ return (protocol || 'http') + '://' + host + ':' + (port || 80);
174
+ };
175
+
176
+ /**
177
+ * Mergest 2 query strings in to once unique query string
178
+ *
179
+ * @param {String} base
180
+ * @param {String} addition
181
+ * @api public
182
+ */
183
+
184
+ util.query = function (base, addition) {
185
+ var query = util.chunkQuery(base || '')
186
+ , components = [];
187
+
188
+ util.merge(query, util.chunkQuery(addition || ''));
189
+ for (var part in query) {
190
+ if (query.hasOwnProperty(part)) {
191
+ components.push(part + '=' + query[part]);
192
+ }
193
+ }
194
+
195
+ return components.length ? '?' + components.join('&') : '';
196
+ };
197
+
198
+ /**
199
+ * Transforms a querystring in to an object
200
+ *
201
+ * @param {String} qs
202
+ * @api public
203
+ */
204
+
205
+ util.chunkQuery = function (qs) {
206
+ var query = {}
207
+ , params = qs.split('&')
208
+ , i = 0
209
+ , l = params.length
210
+ , kv;
211
+
212
+ for (; i < l; ++i) {
213
+ kv = params[i].split('=');
214
+ if (kv[0]) {
215
+ query[kv[0]] = kv[1];
216
+ }
217
+ }
218
+
219
+ return query;
220
+ };
221
+
222
+ /**
223
+ * Executes the given function when the page is loaded.
224
+ *
225
+ * io.util.load(function () { console.log('page loaded'); });
226
+ *
227
+ * @param {Function} fn
228
+ * @api public
229
+ */
230
+
231
+ var pageLoaded = false;
232
+
233
+ util.load = function (fn) {
234
+ if ('document' in global && document.readyState === 'complete' || pageLoaded) {
235
+ return fn();
236
+ }
237
+
238
+ util.on(global, 'load', fn, false);
239
+ };
240
+
241
+ /**
242
+ * Adds an event.
243
+ *
244
+ * @api private
245
+ */
246
+
247
+ util.on = function (element, event, fn, capture) {
248
+ if (element.attachEvent) {
249
+ element.attachEvent('on' + event, fn);
250
+ } else if (element.addEventListener) {
251
+ element.addEventListener(event, fn, capture);
252
+ }
253
+ };
254
+
255
+ /**
256
+ * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
257
+ *
258
+ * @param {Boolean} [xdomain] Create a request that can be used cross domain.
259
+ * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
260
+ * @api private
261
+ */
262
+
263
+ util.request = function (xdomain) {
264
+
265
+ if (xdomain && 'undefined' != typeof XDomainRequest && !util.ua.hasCORS) {
266
+ return new XDomainRequest();
267
+ }
268
+
269
+ if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
270
+ return new XMLHttpRequest();
271
+ }
272
+
273
+ if (!xdomain) {
274
+ try {
275
+ return new window[(['Active'].concat('Object').join('X'))]('Microsoft.XMLHTTP');
276
+ } catch(e) { }
277
+ }
278
+
279
+ return null;
280
+ };
281
+
282
+ /**
283
+ * XHR based transport constructor.
284
+ *
285
+ * @constructor
286
+ * @api public
287
+ */
288
+
289
+ /**
290
+ * Change the internal pageLoaded value.
291
+ */
292
+
293
+ if ('undefined' != typeof window) {
294
+ util.load(function () {
295
+ pageLoaded = true;
296
+ });
297
+ }
298
+
299
+ /**
300
+ * Defers a function to ensure a spinner is not displayed by the browser
301
+ *
302
+ * @param {Function} fn
303
+ * @api public
304
+ */
305
+
306
+ util.defer = function (fn) {
307
+ if (!util.ua.webkit || 'undefined' != typeof importScripts) {
308
+ return fn();
309
+ }
310
+
311
+ util.load(function () {
312
+ setTimeout(fn, 100);
313
+ });
314
+ };
315
+
316
+ /**
317
+ * Merges two objects.
318
+ *
319
+ * @api public
320
+ */
321
+
322
+ util.merge = function merge (target, additional, deep, lastseen) {
323
+ var seen = lastseen || []
324
+ , depth = typeof deep == 'undefined' ? 2 : deep
325
+ , prop;
326
+
327
+ for (prop in additional) {
328
+ if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
329
+ if (typeof target[prop] !== 'object' || !depth) {
330
+ target[prop] = additional[prop];
331
+ seen.push(additional[prop]);
332
+ } else {
333
+ util.merge(target[prop], additional[prop], depth - 1, seen);
334
+ }
335
+ }
336
+ }
337
+
338
+ return target;
339
+ };
340
+
341
+ /**
342
+ * Merges prototypes from objects
343
+ *
344
+ * @api public
345
+ */
346
+
347
+ util.mixin = function (ctor, ctor2) {
348
+ util.merge(ctor.prototype, ctor2.prototype);
349
+ };
350
+
351
+ /**
352
+ * Shortcut for prototypical and static inheritance.
353
+ *
354
+ * @api private
355
+ */
356
+
357
+ util.inherit = function (ctor, ctor2) {
358
+ function f() {};
359
+ f.prototype = ctor2.prototype;
360
+ ctor.prototype = new f;
361
+ };
362
+
363
+ /**
364
+ * Checks if the given object is an Array.
365
+ *
366
+ * io.util.isArray([]); // true
367
+ * io.util.isArray({}); // false
368
+ *
369
+ * @param Object obj
370
+ * @api public
371
+ */
372
+
373
+ util.isArray = Array.isArray || function (obj) {
374
+ return Object.prototype.toString.call(obj) === '[object Array]';
375
+ };
376
+
377
+ /**
378
+ * Intersects values of two arrays into a third
379
+ *
380
+ * @api public
381
+ */
382
+
383
+ util.intersect = function (arr, arr2) {
384
+ var ret = []
385
+ , longest = arr.length > arr2.length ? arr : arr2
386
+ , shortest = arr.length > arr2.length ? arr2 : arr;
387
+
388
+ for (var i = 0, l = shortest.length; i < l; i++) {
389
+ if (~util.indexOf(longest, shortest[i]))
390
+ ret.push(shortest[i]);
391
+ }
392
+
393
+ return ret;
394
+ };
395
+
396
+ /**
397
+ * Array indexOf compatibility.
398
+ *
399
+ * @see bit.ly/a5Dxa2
400
+ * @api public
401
+ */
402
+
403
+ util.indexOf = function (arr, o, i) {
404
+
405
+ for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
406
+ i < j && arr[i] !== o; i++) {}
407
+
408
+ return j <= i ? -1 : i;
409
+ };
410
+
411
+ /**
412
+ * Converts enumerables to array.
413
+ *
414
+ * @api public
415
+ */
416
+
417
+ util.toArray = function (enu) {
418
+ var arr = [];
419
+
420
+ for (var i = 0, l = enu.length; i < l; i++)
421
+ arr.push(enu[i]);
422
+
423
+ return arr;
424
+ };
425
+
426
+ /**
427
+ * UA / engines detection namespace.
428
+ *
429
+ * @namespace
430
+ */
431
+
432
+ util.ua = {};
433
+
434
+ /**
435
+ * Whether the UA supports CORS for XHR.
436
+ *
437
+ * @api public
438
+ */
439
+
440
+ util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
441
+ try {
442
+ var a = new XMLHttpRequest();
443
+ } catch (e) {
444
+ return false;
445
+ }
446
+
447
+ return a.withCredentials != undefined;
448
+ })();
449
+
450
+ /**
451
+ * Detect webkit.
452
+ *
453
+ * @api public
454
+ */
455
+
456
+ util.ua.webkit = 'undefined' != typeof navigator
457
+ && /webkit/i.test(navigator.userAgent);
458
+
459
+ /**
460
+ * Detect iPad/iPhone/iPod.
461
+ *
462
+ * @api public
463
+ */
464
+
465
+ util.ua.iDevice = 'undefined' != typeof navigator
466
+ && /iPad|iPhone|iPod/i.test(navigator.userAgent);
467
+
468
+ })('undefined' != typeof io ? io : module.exports, this);
469
+ /**
470
+ * socket.io
471
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
472
+ * MIT Licensed
473
+ */
474
+
475
+ (function (exports, io) {
476
+
477
+ /**
478
+ * Expose constructor.
479
+ */
480
+
481
+ exports.EventEmitter = EventEmitter;
482
+
483
+ /**
484
+ * Event emitter constructor.
485
+ *
486
+ * @api public.
487
+ */
488
+
489
+ function EventEmitter () {};
490
+
491
+ /**
492
+ * Adds a listener
493
+ *
494
+ * @api public
495
+ */
496
+
497
+ EventEmitter.prototype.on = function (name, fn) {
498
+ if (!this.$events) {
499
+ this.$events = {};
500
+ }
501
+
502
+ if (!this.$events[name]) {
503
+ this.$events[name] = fn;
504
+ } else if (io.util.isArray(this.$events[name])) {
505
+ this.$events[name].push(fn);
506
+ } else {
507
+ this.$events[name] = [this.$events[name], fn];
508
+ }
509
+
510
+ return this;
511
+ };
512
+
513
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
514
+
515
+ /**
516
+ * Adds a volatile listener.
517
+ *
518
+ * @api public
519
+ */
520
+
521
+ EventEmitter.prototype.once = function (name, fn) {
522
+ var self = this;
523
+
524
+ function on () {
525
+ self.removeListener(name, on);
526
+ fn.apply(this, arguments);
527
+ };
528
+
529
+ on.listener = fn;
530
+ this.on(name, on);
531
+
532
+ return this;
533
+ };
534
+
535
+ /**
536
+ * Removes a listener.
537
+ *
538
+ * @api public
539
+ */
540
+
541
+ EventEmitter.prototype.removeListener = function (name, fn) {
542
+ if (this.$events && this.$events[name]) {
543
+ var list = this.$events[name];
544
+
545
+ if (io.util.isArray(list)) {
546
+ var pos = -1;
547
+
548
+ for (var i = 0, l = list.length; i < l; i++) {
549
+ if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
550
+ pos = i;
551
+ break;
552
+ }
553
+ }
554
+
555
+ if (pos < 0) {
556
+ return this;
557
+ }
558
+
559
+ list.splice(pos, 1);
560
+
561
+ if (!list.length) {
562
+ delete this.$events[name];
563
+ }
564
+ } else if (list === fn || (list.listener && list.listener === fn)) {
565
+ delete this.$events[name];
566
+ }
567
+ }
568
+
569
+ return this;
570
+ };
571
+
572
+ /**
573
+ * Removes all listeners for an event.
574
+ *
575
+ * @api public
576
+ */
577
+
578
+ EventEmitter.prototype.removeAllListeners = function (name) {
579
+ if (name === undefined) {
580
+ this.$events = {};
581
+ return this;
582
+ }
583
+
584
+ if (this.$events && this.$events[name]) {
585
+ this.$events[name] = null;
586
+ }
587
+
588
+ return this;
589
+ };
590
+
591
+ /**
592
+ * Gets all listeners for a certain event.
593
+ *
594
+ * @api publci
595
+ */
596
+
597
+ EventEmitter.prototype.listeners = function (name) {
598
+ if (!this.$events) {
599
+ this.$events = {};
600
+ }
601
+
602
+ if (!this.$events[name]) {
603
+ this.$events[name] = [];
604
+ }
605
+
606
+ if (!io.util.isArray(this.$events[name])) {
607
+ this.$events[name] = [this.$events[name]];
608
+ }
609
+
610
+ return this.$events[name];
611
+ };
612
+
613
+ /**
614
+ * Emits an event.
615
+ *
616
+ * @api public
617
+ */
618
+
619
+ EventEmitter.prototype.emit = function (name) {
620
+ if (!this.$events) {
621
+ return false;
622
+ }
623
+
624
+ var handler = this.$events[name];
625
+
626
+ if (!handler) {
627
+ return false;
628
+ }
629
+
630
+ var args = Array.prototype.slice.call(arguments, 1);
631
+
632
+ if ('function' == typeof handler) {
633
+ handler.apply(this, args);
634
+ } else if (io.util.isArray(handler)) {
635
+ var listeners = handler.slice();
636
+
637
+ for (var i = 0, l = listeners.length; i < l; i++) {
638
+ listeners[i].apply(this, args);
639
+ }
640
+ } else {
641
+ return false;
642
+ }
643
+
644
+ return true;
645
+ };
646
+
647
+ })(
648
+ 'undefined' != typeof io ? io : module.exports
649
+ , 'undefined' != typeof io ? io : module.parent.exports
650
+ );
651
+
652
+ /**
653
+ * socket.io
654
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
655
+ * MIT Licensed
656
+ */
657
+
658
+ /**
659
+ * Based on JSON2 (http://www.JSON.org/js.html).
660
+ */
661
+
662
+ (function (exports, nativeJSON) {
663
+ "use strict";
664
+
665
+ // use native JSON if it's available
666
+ if (nativeJSON && nativeJSON.parse){
667
+ return exports.JSON = {
668
+ parse: nativeJSON.parse
669
+ , stringify: nativeJSON.stringify
670
+ };
671
+ }
672
+
673
+ var JSON = exports.JSON = {};
674
+
675
+ function f(n) {
676
+ // Format integers to have at least two digits.
677
+ return n < 10 ? '0' + n : n;
678
+ }
679
+
680
+ function date(d, key) {
681
+ return isFinite(d.valueOf()) ?
682
+ d.getUTCFullYear() + '-' +
683
+ f(d.getUTCMonth() + 1) + '-' +
684
+ f(d.getUTCDate()) + 'T' +
685
+ f(d.getUTCHours()) + ':' +
686
+ f(d.getUTCMinutes()) + ':' +
687
+ f(d.getUTCSeconds()) + 'Z' : null;
688
+ };
689
+
690
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
691
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
692
+ gap,
693
+ indent,
694
+ meta = { // table of character substitutions
695
+ '\b': '\\b',
696
+ '\t': '\\t',
697
+ '\n': '\\n',
698
+ '\f': '\\f',
699
+ '\r': '\\r',
700
+ '"' : '\\"',
701
+ '\\': '\\\\'
702
+ },
703
+ rep;
704
+
705
+
706
+ function quote(string) {
707
+
708
+ // If the string contains no control characters, no quote characters, and no
709
+ // backslash characters, then we can safely slap some quotes around it.
710
+ // Otherwise we must also replace the offending characters with safe escape
711
+ // sequences.
712
+
713
+ escapable.lastIndex = 0;
714
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
715
+ var c = meta[a];
716
+ return typeof c === 'string' ? c :
717
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
718
+ }) + '"' : '"' + string + '"';
719
+ }
720
+
721
+
722
+ function str(key, holder) {
723
+
724
+ // Produce a string from holder[key].
725
+
726
+ var i, // The loop counter.
727
+ k, // The member key.
728
+ v, // The member value.
729
+ length,
730
+ mind = gap,
731
+ partial,
732
+ value = holder[key];
733
+
734
+ // If the value has a toJSON method, call it to obtain a replacement value.
735
+
736
+ if (value instanceof Date) {
737
+ value = date(key);
738
+ }
739
+
740
+ // If we were called with a replacer function, then call the replacer to
741
+ // obtain a replacement value.
742
+
743
+ if (typeof rep === 'function') {
744
+ value = rep.call(holder, key, value);
745
+ }
746
+
747
+ // What happens next depends on the value's type.
748
+
749
+ switch (typeof value) {
750
+ case 'string':
751
+ return quote(value);
752
+
753
+ case 'number':
754
+
755
+ // JSON numbers must be finite. Encode non-finite numbers as null.
756
+
757
+ return isFinite(value) ? String(value) : 'null';
758
+
759
+ case 'boolean':
760
+ case 'null':
761
+
762
+ // If the value is a boolean or null, convert it to a string. Note:
763
+ // typeof null does not produce 'null'. The case is included here in
764
+ // the remote chance that this gets fixed someday.
765
+
766
+ return String(value);
767
+
768
+ // If the type is 'object', we might be dealing with an object or an array or
769
+ // null.
770
+
771
+ case 'object':
772
+
773
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
774
+ // so watch out for that case.
775
+
776
+ if (!value) {
777
+ return 'null';
778
+ }
779
+
780
+ // Make an array to hold the partial results of stringifying this object value.
781
+
782
+ gap += indent;
783
+ partial = [];
784
+
785
+ // Is the value an array?
786
+
787
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
788
+
789
+ // The value is an array. Stringify every element. Use null as a placeholder
790
+ // for non-JSON values.
791
+
792
+ length = value.length;
793
+ for (i = 0; i < length; i += 1) {
794
+ partial[i] = str(i, value) || 'null';
795
+ }
796
+
797
+ // Join all of the elements together, separated with commas, and wrap them in
798
+ // brackets.
799
+
800
+ v = partial.length === 0 ? '[]' : gap ?
801
+ '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
802
+ '[' + partial.join(',') + ']';
803
+ gap = mind;
804
+ return v;
805
+ }
806
+
807
+ // If the replacer is an array, use it to select the members to be stringified.
808
+
809
+ if (rep && typeof rep === 'object') {
810
+ length = rep.length;
811
+ for (i = 0; i < length; i += 1) {
812
+ if (typeof rep[i] === 'string') {
813
+ k = rep[i];
814
+ v = str(k, value);
815
+ if (v) {
816
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
817
+ }
818
+ }
819
+ }
820
+ } else {
821
+
822
+ // Otherwise, iterate through all of the keys in the object.
823
+
824
+ for (k in value) {
825
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
826
+ v = str(k, value);
827
+ if (v) {
828
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
829
+ }
830
+ }
831
+ }
832
+ }
833
+
834
+ // Join all of the member texts together, separated with commas,
835
+ // and wrap them in braces.
836
+
837
+ v = partial.length === 0 ? '{}' : gap ?
838
+ '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
839
+ '{' + partial.join(',') + '}';
840
+ gap = mind;
841
+ return v;
842
+ }
843
+ }
844
+
845
+ // If the JSON object does not yet have a stringify method, give it one.
846
+
847
+ JSON.stringify = function (value, replacer, space) {
848
+
849
+ // The stringify method takes a value and an optional replacer, and an optional
850
+ // space parameter, and returns a JSON text. The replacer can be a function
851
+ // that can replace values, or an array of strings that will select the keys.
852
+ // A default replacer method can be provided. Use of the space parameter can
853
+ // produce text that is more easily readable.
854
+
855
+ var i;
856
+ gap = '';
857
+ indent = '';
858
+
859
+ // If the space parameter is a number, make an indent string containing that
860
+ // many spaces.
861
+
862
+ if (typeof space === 'number') {
863
+ for (i = 0; i < space; i += 1) {
864
+ indent += ' ';
865
+ }
866
+
867
+ // If the space parameter is a string, it will be used as the indent string.
868
+
869
+ } else if (typeof space === 'string') {
870
+ indent = space;
871
+ }
872
+
873
+ // If there is a replacer, it must be a function or an array.
874
+ // Otherwise, throw an error.
875
+
876
+ rep = replacer;
877
+ if (replacer && typeof replacer !== 'function' &&
878
+ (typeof replacer !== 'object' ||
879
+ typeof replacer.length !== 'number')) {
880
+ throw new Error('JSON.stringify');
881
+ }
882
+
883
+ // Make a fake root object containing our value under the key of ''.
884
+ // Return the result of stringifying the value.
885
+
886
+ return str('', {'': value});
887
+ };
888
+
889
+ // If the JSON object does not yet have a parse method, give it one.
890
+
891
+ JSON.parse = function (text, reviver) {
892
+ // The parse method takes a text and an optional reviver function, and returns
893
+ // a JavaScript value if the text is a valid JSON text.
894
+
895
+ var j;
896
+
897
+ function walk(holder, key) {
898
+
899
+ // The walk method is used to recursively walk the resulting structure so
900
+ // that modifications can be made.
901
+
902
+ var k, v, value = holder[key];
903
+ if (value && typeof value === 'object') {
904
+ for (k in value) {
905
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
906
+ v = walk(value, k);
907
+ if (v !== undefined) {
908
+ value[k] = v;
909
+ } else {
910
+ delete value[k];
911
+ }
912
+ }
913
+ }
914
+ }
915
+ return reviver.call(holder, key, value);
916
+ }
917
+
918
+
919
+ // Parsing happens in four stages. In the first stage, we replace certain
920
+ // Unicode characters with escape sequences. JavaScript handles many characters
921
+ // incorrectly, either silently deleting them, or treating them as line endings.
922
+
923
+ text = String(text);
924
+ cx.lastIndex = 0;
925
+ if (cx.test(text)) {
926
+ text = text.replace(cx, function (a) {
927
+ return '\\u' +
928
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
929
+ });
930
+ }
931
+
932
+ // In the second stage, we run the text against regular expressions that look
933
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
934
+ // because they can cause invocation, and '=' because it can cause mutation.
935
+ // But just to be safe, we want to reject all unexpected forms.
936
+
937
+ // We split the second stage into 4 regexp operations in order to work around
938
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
939
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
940
+ // replace all simple value tokens with ']' characters. Third, we delete all
941
+ // open brackets that follow a colon or comma or that begin the text. Finally,
942
+ // we look to see that the remaining characters are only whitespace or ']' or
943
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
944
+
945
+ if (/^[\],:{}\s]*$/
946
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
947
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
948
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
949
+
950
+ // In the third stage we use the eval function to compile the text into a
951
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
952
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
953
+ // in parens to eliminate the ambiguity.
954
+
955
+ j = eval('(' + text + ')');
956
+
957
+ // In the optional fourth stage, we recursively walk the new structure, passing
958
+ // each name/value pair to a reviver function for possible transformation.
959
+
960
+ return typeof reviver === 'function' ?
961
+ walk({'': j}, '') : j;
962
+ }
963
+
964
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
965
+
966
+ throw new SyntaxError('JSON.parse');
967
+ };
968
+
969
+ })(
970
+ 'undefined' != typeof io ? io : module.exports
971
+ , typeof JSON !== 'undefined' ? JSON : undefined
972
+ );
973
+
974
+ /**
975
+ * socket.io
976
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
977
+ * MIT Licensed
978
+ */
979
+
980
+ (function (exports, io) {
981
+
982
+ /**
983
+ * Parser namespace.
984
+ *
985
+ * @namespace
986
+ */
987
+
988
+ var parser = exports.parser = {};
989
+
990
+ /**
991
+ * Packet types.
992
+ */
993
+
994
+ var packets = parser.packets = [
995
+ 'disconnect'
996
+ , 'connect'
997
+ , 'heartbeat'
998
+ , 'message'
999
+ , 'json'
1000
+ , 'event'
1001
+ , 'ack'
1002
+ , 'error'
1003
+ , 'noop'
1004
+ ];
1005
+
1006
+ /**
1007
+ * Errors reasons.
1008
+ */
1009
+
1010
+ var reasons = parser.reasons = [
1011
+ 'transport not supported'
1012
+ , 'client not handshaken'
1013
+ , 'unauthorized'
1014
+ ];
1015
+
1016
+ /**
1017
+ * Errors advice.
1018
+ */
1019
+
1020
+ var advice = parser.advice = [
1021
+ 'reconnect'
1022
+ ];
1023
+
1024
+ /**
1025
+ * Shortcuts.
1026
+ */
1027
+
1028
+ var JSON = io.JSON
1029
+ , indexOf = io.util.indexOf;
1030
+
1031
+ /**
1032
+ * Encodes a packet.
1033
+ *
1034
+ * @api private
1035
+ */
1036
+
1037
+ parser.encodePacket = function (packet) {
1038
+ var type = indexOf(packets, packet.type)
1039
+ , id = packet.id || ''
1040
+ , endpoint = packet.endpoint || ''
1041
+ , ack = packet.ack
1042
+ , data = null;
1043
+
1044
+ switch (packet.type) {
1045
+ case 'error':
1046
+ var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
1047
+ , adv = packet.advice ? indexOf(advice, packet.advice) : '';
1048
+
1049
+ if (reason !== '' || adv !== '')
1050
+ data = reason + (adv !== '' ? ('+' + adv) : '');
1051
+
1052
+ break;
1053
+
1054
+ case 'message':
1055
+ if (packet.data !== '')
1056
+ data = packet.data;
1057
+ break;
1058
+
1059
+ case 'event':
1060
+ var ev = { name: packet.name };
1061
+
1062
+ if (packet.args && packet.args.length) {
1063
+ ev.args = packet.args;
1064
+ }
1065
+
1066
+ data = JSON.stringify(ev);
1067
+ break;
1068
+
1069
+ case 'json':
1070
+ data = JSON.stringify(packet.data);
1071
+ break;
1072
+
1073
+ case 'connect':
1074
+ if (packet.qs)
1075
+ data = packet.qs;
1076
+ break;
1077
+
1078
+ case 'ack':
1079
+ data = packet.ackId
1080
+ + (packet.args && packet.args.length
1081
+ ? '+' + JSON.stringify(packet.args) : '');
1082
+ break;
1083
+ }
1084
+
1085
+ // construct packet with required fragments
1086
+ var encoded = [
1087
+ type
1088
+ , id + (ack == 'data' ? '+' : '')
1089
+ , endpoint
1090
+ ];
1091
+
1092
+ // data fragment is optional
1093
+ if (data !== null && data !== undefined)
1094
+ encoded.push(data);
1095
+
1096
+ return encoded.join(':');
1097
+ };
1098
+
1099
+ /**
1100
+ * Encodes multiple messages (payload).
1101
+ *
1102
+ * @param {Array} messages
1103
+ * @api private
1104
+ */
1105
+
1106
+ parser.encodePayload = function (packets) {
1107
+ var decoded = '';
1108
+
1109
+ if (packets.length == 1)
1110
+ return packets[0];
1111
+
1112
+ for (var i = 0, l = packets.length; i < l; i++) {
1113
+ var packet = packets[i];
1114
+ decoded += '\ufffd' + packet.length + '\ufffd' + packets[i];
1115
+ }
1116
+
1117
+ return decoded;
1118
+ };
1119
+
1120
+ /**
1121
+ * Decodes a packet
1122
+ *
1123
+ * @api private
1124
+ */
1125
+
1126
+ var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
1127
+
1128
+ parser.decodePacket = function (data) {
1129
+ var pieces = data.match(regexp);
1130
+
1131
+ if (!pieces) return {};
1132
+
1133
+ var id = pieces[2] || ''
1134
+ , data = pieces[5] || ''
1135
+ , packet = {
1136
+ type: packets[pieces[1]]
1137
+ , endpoint: pieces[4] || ''
1138
+ };
1139
+
1140
+ // whether we need to acknowledge the packet
1141
+ if (id) {
1142
+ packet.id = id;
1143
+ if (pieces[3])
1144
+ packet.ack = 'data';
1145
+ else
1146
+ packet.ack = true;
1147
+ }
1148
+
1149
+ // handle different packet types
1150
+ switch (packet.type) {
1151
+ case 'error':
1152
+ var pieces = data.split('+');
1153
+ packet.reason = reasons[pieces[0]] || '';
1154
+ packet.advice = advice[pieces[1]] || '';
1155
+ break;
1156
+
1157
+ case 'message':
1158
+ packet.data = data || '';
1159
+ break;
1160
+
1161
+ case 'event':
1162
+ try {
1163
+ var opts = JSON.parse(data);
1164
+ packet.name = opts.name;
1165
+ packet.args = opts.args;
1166
+ } catch (e) { }
1167
+
1168
+ packet.args = packet.args || [];
1169
+ break;
1170
+
1171
+ case 'json':
1172
+ try {
1173
+ packet.data = JSON.parse(data);
1174
+ } catch (e) { }
1175
+ break;
1176
+
1177
+ case 'connect':
1178
+ packet.qs = data || '';
1179
+ break;
1180
+
1181
+ case 'ack':
1182
+ var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
1183
+ if (pieces) {
1184
+ packet.ackId = pieces[1];
1185
+ packet.args = [];
1186
+
1187
+ if (pieces[3]) {
1188
+ try {
1189
+ packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
1190
+ } catch (e) { }
1191
+ }
1192
+ }
1193
+ break;
1194
+
1195
+ case 'disconnect':
1196
+ case 'heartbeat':
1197
+ break;
1198
+ };
1199
+
1200
+ return packet;
1201
+ };
1202
+
1203
+ /**
1204
+ * Decodes data payload. Detects multiple messages
1205
+ *
1206
+ * @return {Array} messages
1207
+ * @api public
1208
+ */
1209
+
1210
+ parser.decodePayload = function (data) {
1211
+ // IE doesn't like data[i] for unicode chars, charAt works fine
1212
+ if (data.charAt(0) == '\ufffd') {
1213
+ var ret = [];
1214
+
1215
+ for (var i = 1, length = ''; i < data.length; i++) {
1216
+ if (data.charAt(i) == '\ufffd') {
1217
+ ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
1218
+ i += Number(length) + 1;
1219
+ length = '';
1220
+ } else {
1221
+ length += data.charAt(i);
1222
+ }
1223
+ }
1224
+
1225
+ return ret;
1226
+ } else {
1227
+ return [parser.decodePacket(data)];
1228
+ }
1229
+ };
1230
+
1231
+ })(
1232
+ 'undefined' != typeof io ? io : module.exports
1233
+ , 'undefined' != typeof io ? io : module.parent.exports
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
+ /**
1269
+ * Indicates whether heartbeats is enabled for this transport
1270
+ *
1271
+ * @api private
1272
+ */
1273
+
1274
+ Transport.prototype.heartbeats = function () {
1275
+ return true;
1276
+ };
1277
+
1278
+ /**
1279
+ * Handles the response from the server. When a new response is received
1280
+ * it will automatically update the timeout, decode the message and
1281
+ * forwards the response to the onMessage function for further processing.
1282
+ *
1283
+ * @param {String} data Response from the server.
1284
+ * @api private
1285
+ */
1286
+
1287
+ Transport.prototype.onData = function (data) {
1288
+ this.clearCloseTimeout();
1289
+
1290
+ // If the connection in currently open (or in a reopening state) reset the close
1291
+ // timeout since we have just received data. This check is necessary so
1292
+ // that we don't reset the timeout on an explicitly disconnected connection.
1293
+ if (this.socket.connected || this.socket.connecting || this.socket.reconnecting) {
1294
+ this.setCloseTimeout();
1295
+ }
1296
+
1297
+ if (data !== '') {
1298
+ // todo: we should only do decodePayload for xhr transports
1299
+ var msgs = io.parser.decodePayload(data);
1300
+
1301
+ if (msgs && msgs.length) {
1302
+ for (var i = 0, l = msgs.length; i < l; i++) {
1303
+ this.onPacket(msgs[i]);
1304
+ }
1305
+ }
1306
+ }
1307
+
1308
+ return this;
1309
+ };
1310
+
1311
+ /**
1312
+ * Handles packets.
1313
+ *
1314
+ * @api private
1315
+ */
1316
+
1317
+ Transport.prototype.onPacket = function (packet) {
1318
+ this.socket.setHeartbeatTimeout();
1319
+
1320
+ if (packet.type == 'heartbeat') {
1321
+ return this.onHeartbeat();
1322
+ }
1323
+
1324
+ if (packet.type == 'connect' && packet.endpoint == '') {
1325
+ this.onConnect();
1326
+ }
1327
+
1328
+ if (packet.type == 'error' && packet.advice == 'reconnect') {
1329
+ this.isOpen = false;
1330
+ }
1331
+
1332
+ this.socket.onPacket(packet);
1333
+
1334
+ return this;
1335
+ };
1336
+
1337
+ /**
1338
+ * Sets close timeout
1339
+ *
1340
+ * @api private
1341
+ */
1342
+
1343
+ Transport.prototype.setCloseTimeout = function () {
1344
+ if (!this.closeTimeout) {
1345
+ var self = this;
1346
+
1347
+ this.closeTimeout = setTimeout(function () {
1348
+ self.onDisconnect();
1349
+ }, this.socket.closeTimeout);
1350
+ }
1351
+ };
1352
+
1353
+ /**
1354
+ * Called when transport disconnects.
1355
+ *
1356
+ * @api private
1357
+ */
1358
+
1359
+ Transport.prototype.onDisconnect = function () {
1360
+ if (this.isOpen) this.close();
1361
+ this.clearTimeouts();
1362
+ this.socket.onDisconnect();
1363
+ return this;
1364
+ };
1365
+
1366
+ /**
1367
+ * Called when transport connects
1368
+ *
1369
+ * @api private
1370
+ */
1371
+
1372
+ Transport.prototype.onConnect = function () {
1373
+ this.socket.onConnect();
1374
+ return this;
1375
+ };
1376
+
1377
+ /**
1378
+ * Clears close timeout
1379
+ *
1380
+ * @api private
1381
+ */
1382
+
1383
+ Transport.prototype.clearCloseTimeout = function () {
1384
+ if (this.closeTimeout) {
1385
+ clearTimeout(this.closeTimeout);
1386
+ this.closeTimeout = null;
1387
+ }
1388
+ };
1389
+
1390
+ /**
1391
+ * Clear timeouts
1392
+ *
1393
+ * @api private
1394
+ */
1395
+
1396
+ Transport.prototype.clearTimeouts = function () {
1397
+ this.clearCloseTimeout();
1398
+
1399
+ if (this.reopenTimeout) {
1400
+ clearTimeout(this.reopenTimeout);
1401
+ }
1402
+ };
1403
+
1404
+ /**
1405
+ * Sends a packet
1406
+ *
1407
+ * @param {Object} packet object.
1408
+ * @api private
1409
+ */
1410
+
1411
+ Transport.prototype.packet = function (packet) {
1412
+ this.send(io.parser.encodePacket(packet));
1413
+ };
1414
+
1415
+ /**
1416
+ * Send the received heartbeat message back to server. So the server
1417
+ * knows we are still connected.
1418
+ *
1419
+ * @param {String} heartbeat Heartbeat response from the server.
1420
+ * @api private
1421
+ */
1422
+
1423
+ Transport.prototype.onHeartbeat = function (heartbeat) {
1424
+ this.packet({ type: 'heartbeat' });
1425
+ };
1426
+
1427
+ /**
1428
+ * Called when the transport opens.
1429
+ *
1430
+ * @api private
1431
+ */
1432
+
1433
+ Transport.prototype.onOpen = function () {
1434
+ this.isOpen = true;
1435
+ this.clearCloseTimeout();
1436
+ this.socket.onOpen();
1437
+ };
1438
+
1439
+ /**
1440
+ * Notifies the base when the connection with the Socket.IO server
1441
+ * has been disconnected.
1442
+ *
1443
+ * @api private
1444
+ */
1445
+
1446
+ Transport.prototype.onClose = function () {
1447
+ var self = this;
1448
+
1449
+ /* FIXME: reopen delay causing a infinit loop
1450
+ this.reopenTimeout = setTimeout(function () {
1451
+ self.open();
1452
+ }, this.socket.options['reopen delay']);*/
1453
+
1454
+ this.isOpen = false;
1455
+ this.socket.onClose();
1456
+ this.onDisconnect();
1457
+ };
1458
+
1459
+ /**
1460
+ * Generates a connection url based on the Socket.IO URL Protocol.
1461
+ * See <https://github.com/learnboost/socket.io-node/> for more details.
1462
+ *
1463
+ * @returns {String} Connection url
1464
+ * @api private
1465
+ */
1466
+
1467
+ Transport.prototype.prepareUrl = function () {
1468
+ var options = this.socket.options;
1469
+
1470
+ return this.scheme() + '://'
1471
+ + options.host + ':' + options.port + '/'
1472
+ + options.resource + '/' + io.protocol
1473
+ + '/' + this.name + '/' + this.sessid;
1474
+ };
1475
+
1476
+ /**
1477
+ * Checks if the transport is ready to start a connection.
1478
+ *
1479
+ * @param {Socket} socket The socket instance that needs a transport
1480
+ * @param {Function} fn The callback
1481
+ * @api private
1482
+ */
1483
+
1484
+ Transport.prototype.ready = function (socket, fn) {
1485
+ fn.call(this);
1486
+ };
1487
+ })(
1488
+ 'undefined' != typeof io ? io : module.exports
1489
+ , 'undefined' != typeof io ? io : module.parent.exports
1490
+ );
1491
+ /**
1492
+ * socket.io
1493
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1494
+ * MIT Licensed
1495
+ */
1496
+
1497
+ (function (exports, io, global) {
1498
+
1499
+ /**
1500
+ * Expose constructor.
1501
+ */
1502
+
1503
+ exports.Socket = Socket;
1504
+
1505
+ /**
1506
+ * Create a new `Socket.IO client` which can establish a persistent
1507
+ * connection with a Socket.IO enabled server.
1508
+ *
1509
+ * @api public
1510
+ */
1511
+
1512
+ function Socket (options) {
1513
+ this.options = {
1514
+ port: 80
1515
+ , secure: false
1516
+ , document: 'document' in global ? document : false
1517
+ , resource: 'socket.io'
1518
+ , transports: io.transports
1519
+ , 'connect timeout': 10000
1520
+ , 'try multiple transports': true
1521
+ , 'reconnect': true
1522
+ , 'reconnection delay': 500
1523
+ , 'reconnection limit': Infinity
1524
+ , 'reopen delay': 3000
1525
+ , 'max reconnection attempts': 10
1526
+ , 'sync disconnect on unload': false
1527
+ , 'auto connect': true
1528
+ , 'flash policy port': 10843
1529
+ , 'manualFlush': false
1530
+ };
1531
+
1532
+ io.util.merge(this.options, options);
1533
+
1534
+ this.connected = false;
1535
+ this.open = false;
1536
+ this.connecting = false;
1537
+ this.reconnecting = false;
1538
+ this.namespaces = {};
1539
+ this.buffer = [];
1540
+ this.doBuffer = false;
1541
+
1542
+ if (this.options['sync disconnect on unload'] &&
1543
+ (!this.isXDomain() || io.util.ua.hasCORS)) {
1544
+ var self = this;
1545
+ io.util.on(global, 'beforeunload', function () {
1546
+ self.disconnectSync();
1547
+ }, false);
1548
+ }
1549
+
1550
+ if (this.options['auto connect']) {
1551
+ this.connect();
1552
+ }
1553
+ };
1554
+
1555
+ /**
1556
+ * Apply EventEmitter mixin.
1557
+ */
1558
+
1559
+ io.util.mixin(Socket, io.EventEmitter);
1560
+
1561
+ /**
1562
+ * Returns a namespace listener/emitter for this socket
1563
+ *
1564
+ * @api public
1565
+ */
1566
+
1567
+ Socket.prototype.of = function (name) {
1568
+ if (!this.namespaces[name]) {
1569
+ this.namespaces[name] = new io.SocketNamespace(this, name);
1570
+
1571
+ if (name !== '') {
1572
+ this.namespaces[name].packet({ type: 'connect' });
1573
+ }
1574
+ }
1575
+
1576
+ return this.namespaces[name];
1577
+ };
1578
+
1579
+ /**
1580
+ * Emits the given event to the Socket and all namespaces
1581
+ *
1582
+ * @api private
1583
+ */
1584
+
1585
+ Socket.prototype.publish = function () {
1586
+ this.emit.apply(this, arguments);
1587
+
1588
+ var nsp;
1589
+
1590
+ for (var i in this.namespaces) {
1591
+ if (this.namespaces.hasOwnProperty(i)) {
1592
+ nsp = this.of(i);
1593
+ nsp.$emit.apply(nsp, arguments);
1594
+ }
1595
+ }
1596
+ };
1597
+
1598
+ /**
1599
+ * Performs the handshake
1600
+ *
1601
+ * @api private
1602
+ */
1603
+
1604
+ function empty () { };
1605
+
1606
+ Socket.prototype.handshake = function (fn) {
1607
+ var self = this
1608
+ , options = this.options;
1609
+
1610
+ function complete (data) {
1611
+ if (data instanceof Error) {
1612
+ self.connecting = false;
1613
+ self.onError(data.message);
1614
+ } else {
1615
+ fn.apply(null, data.split(':'));
1616
+ }
1617
+ };
1618
+
1619
+ var url = [
1620
+ 'http' + (options.secure ? 's' : '') + ':/'
1621
+ , options.host + ':' + options.port
1622
+ , options.resource
1623
+ , io.protocol
1624
+ , io.util.query(this.options.query, 't=' + +new Date)
1625
+ ].join('/');
1626
+
1627
+ if (this.isXDomain() && !io.util.ua.hasCORS) {
1628
+ var insertAt = document.getElementsByTagName('script')[0]
1629
+ , script = document.createElement('script');
1630
+
1631
+ script.src = url + '&jsonp=' + io.j.length;
1632
+ insertAt.parentNode.insertBefore(script, insertAt);
1633
+
1634
+ io.j.push(function (data) {
1635
+ complete(data);
1636
+ script.parentNode.removeChild(script);
1637
+ });
1638
+ } else {
1639
+ var xhr = io.util.request();
1640
+
1641
+ xhr.open('GET', url, true);
1642
+ if (this.isXDomain()) {
1643
+ xhr.withCredentials = true;
1644
+ }
1645
+ xhr.onreadystatechange = function () {
1646
+ if (xhr.readyState == 4) {
1647
+ xhr.onreadystatechange = empty;
1648
+
1649
+ if (xhr.status == 200) {
1650
+ complete(xhr.responseText);
1651
+ } else if (xhr.status == 403) {
1652
+ self.onError(xhr.responseText);
1653
+ } else {
1654
+ self.connecting = false;
1655
+ !self.reconnecting && self.onError(xhr.responseText);
1656
+ }
1657
+ }
1658
+ };
1659
+ xhr.send(null);
1660
+ }
1661
+ };
1662
+
1663
+ /**
1664
+ * Find an available transport based on the options supplied in the constructor.
1665
+ *
1666
+ * @api private
1667
+ */
1668
+
1669
+ Socket.prototype.getTransport = function (override) {
1670
+ var transports = override || this.transports, match;
1671
+
1672
+ for (var i = 0, transport; transport = transports[i]; i++) {
1673
+ if (io.Transport[transport]
1674
+ && io.Transport[transport].check(this)
1675
+ && (!this.isXDomain() || io.Transport[transport].xdomainCheck(this))) {
1676
+ return new io.Transport[transport](this, this.sessionid);
1677
+ }
1678
+ }
1679
+
1680
+ return null;
1681
+ };
1682
+
1683
+ /**
1684
+ * Connects to the server.
1685
+ *
1686
+ * @param {Function} [fn] Callback.
1687
+ * @returns {io.Socket}
1688
+ * @api public
1689
+ */
1690
+
1691
+ Socket.prototype.connect = function (fn) {
1692
+ if (this.connecting) {
1693
+ return this;
1694
+ }
1695
+
1696
+ var self = this;
1697
+ self.connecting = true;
1698
+
1699
+ this.handshake(function (sid, heartbeat, close, transports) {
1700
+ self.sessionid = sid;
1701
+ self.closeTimeout = close * 1000;
1702
+ self.heartbeatTimeout = heartbeat * 1000;
1703
+ if(!self.transports)
1704
+ self.transports = self.origTransports = (transports ? io.util.intersect(
1705
+ transports.split(',')
1706
+ , self.options.transports
1707
+ ) : self.options.transports);
1708
+
1709
+ self.setHeartbeatTimeout();
1710
+
1711
+ function connect (transports){
1712
+ if (self.transport) self.transport.clearTimeouts();
1713
+
1714
+ self.transport = self.getTransport(transports);
1715
+ if (!self.transport) return self.publish('connect_failed');
1716
+
1717
+ // once the transport is ready
1718
+ self.transport.ready(self, function () {
1719
+ self.connecting = true;
1720
+ self.publish('connecting', self.transport.name);
1721
+ self.transport.open();
1722
+
1723
+ if (self.options['connect timeout']) {
1724
+ self.connectTimeoutTimer = setTimeout(function () {
1725
+ if (!self.connected) {
1726
+ self.connecting = false;
1727
+
1728
+ if (self.options['try multiple transports']) {
1729
+ var remaining = self.transports;
1730
+
1731
+ while (remaining.length > 0 && remaining.splice(0,1)[0] !=
1732
+ self.transport.name) {}
1733
+
1734
+ if (remaining.length){
1735
+ connect(remaining);
1736
+ } else {
1737
+ self.publish('connect_failed');
1738
+ }
1739
+ }
1740
+ }
1741
+ }, self.options['connect timeout']);
1742
+ }
1743
+ });
1744
+ }
1745
+
1746
+ connect(self.transports);
1747
+
1748
+ self.once('connect', function (){
1749
+ clearTimeout(self.connectTimeoutTimer);
1750
+
1751
+ fn && typeof fn == 'function' && fn();
1752
+ });
1753
+ });
1754
+
1755
+ return this;
1756
+ };
1757
+
1758
+ /**
1759
+ * Clears and sets a new heartbeat timeout using the value given by the
1760
+ * server during the handshake.
1761
+ *
1762
+ * @api private
1763
+ */
1764
+
1765
+ Socket.prototype.setHeartbeatTimeout = function () {
1766
+ clearTimeout(this.heartbeatTimeoutTimer);
1767
+ if(this.transport && !this.transport.heartbeats()) return;
1768
+
1769
+ var self = this;
1770
+ this.heartbeatTimeoutTimer = setTimeout(function () {
1771
+ self.transport.onClose();
1772
+ }, this.heartbeatTimeout);
1773
+ };
1774
+
1775
+ /**
1776
+ * Sends a message.
1777
+ *
1778
+ * @param {Object} data packet.
1779
+ * @returns {io.Socket}
1780
+ * @api public
1781
+ */
1782
+
1783
+ Socket.prototype.packet = function (data) {
1784
+ if (this.connected && !this.doBuffer) {
1785
+ this.transport.packet(data);
1786
+ } else {
1787
+ this.buffer.push(data);
1788
+ }
1789
+
1790
+ return this;
1791
+ };
1792
+
1793
+ /**
1794
+ * Sets buffer state
1795
+ *
1796
+ * @api private
1797
+ */
1798
+
1799
+ Socket.prototype.setBuffer = function (v) {
1800
+ this.doBuffer = v;
1801
+
1802
+ if (!v && this.connected && this.buffer.length) {
1803
+ if (!this.options['manualFlush']) {
1804
+ this.flushBuffer();
1805
+ }
1806
+ }
1807
+ };
1808
+
1809
+ /**
1810
+ * Flushes the buffer data over the wire.
1811
+ * To be invoked manually when 'manualFlush' is set to true.
1812
+ *
1813
+ * @api public
1814
+ */
1815
+
1816
+ Socket.prototype.flushBuffer = function() {
1817
+ this.transport.payload(this.buffer);
1818
+ this.buffer = [];
1819
+ };
1820
+
1821
+
1822
+ /**
1823
+ * Disconnect the established connect.
1824
+ *
1825
+ * @returns {io.Socket}
1826
+ * @api public
1827
+ */
1828
+
1829
+ Socket.prototype.disconnect = function () {
1830
+ if (this.connected || this.connecting) {
1831
+ if (this.open) {
1832
+ this.of('').packet({ type: 'disconnect' });
1833
+ }
1834
+
1835
+ // handle disconnection immediately
1836
+ this.onDisconnect('booted');
1837
+ }
1838
+
1839
+ return this;
1840
+ };
1841
+
1842
+ /**
1843
+ * Disconnects the socket with a sync XHR.
1844
+ *
1845
+ * @api private
1846
+ */
1847
+
1848
+ Socket.prototype.disconnectSync = function () {
1849
+ // ensure disconnection
1850
+ var xhr = io.util.request();
1851
+ var uri = [
1852
+ 'http' + (this.options.secure ? 's' : '') + ':/'
1853
+ , this.options.host + ':' + this.options.port
1854
+ , this.options.resource
1855
+ , io.protocol
1856
+ , ''
1857
+ , this.sessionid
1858
+ ].join('/') + '/?disconnect=1';
1859
+
1860
+ xhr.open('GET', uri, false);
1861
+ xhr.send(null);
1862
+
1863
+ // handle disconnection immediately
1864
+ this.onDisconnect('booted');
1865
+ };
1866
+
1867
+ /**
1868
+ * Check if we need to use cross domain enabled transports. Cross domain would
1869
+ * be a different port or different domain name.
1870
+ *
1871
+ * @returns {Boolean}
1872
+ * @api private
1873
+ */
1874
+
1875
+ Socket.prototype.isXDomain = function () {
1876
+
1877
+ var port = global.location.port ||
1878
+ ('https:' == global.location.protocol ? 443 : 80);
1879
+
1880
+ return this.options.host !== global.location.hostname
1881
+ || this.options.port != port;
1882
+ };
1883
+
1884
+ /**
1885
+ * Called upon handshake.
1886
+ *
1887
+ * @api private
1888
+ */
1889
+
1890
+ Socket.prototype.onConnect = function () {
1891
+ if (!this.connected) {
1892
+ this.connected = true;
1893
+ this.connecting = false;
1894
+ if (!this.doBuffer) {
1895
+ // make sure to flush the buffer
1896
+ this.setBuffer(false);
1897
+ }
1898
+ this.emit('connect');
1899
+ }
1900
+ };
1901
+
1902
+ /**
1903
+ * Called when the transport opens
1904
+ *
1905
+ * @api private
1906
+ */
1907
+
1908
+ Socket.prototype.onOpen = function () {
1909
+ this.open = true;
1910
+ };
1911
+
1912
+ /**
1913
+ * Called when the transport closes.
1914
+ *
1915
+ * @api private
1916
+ */
1917
+
1918
+ Socket.prototype.onClose = function () {
1919
+ this.open = false;
1920
+ clearTimeout(this.heartbeatTimeoutTimer);
1921
+ };
1922
+
1923
+ /**
1924
+ * Called when the transport first opens a connection
1925
+ *
1926
+ * @param text
1927
+ */
1928
+
1929
+ Socket.prototype.onPacket = function (packet) {
1930
+ this.of(packet.endpoint).onPacket(packet);
1931
+ };
1932
+
1933
+ /**
1934
+ * Handles an error.
1935
+ *
1936
+ * @api private
1937
+ */
1938
+
1939
+ Socket.prototype.onError = function (err) {
1940
+ if (err && err.advice) {
1941
+ if (err.advice === 'reconnect' && (this.connected || this.connecting)) {
1942
+ this.disconnect();
1943
+ if (this.options.reconnect) {
1944
+ this.reconnect();
1945
+ }
1946
+ }
1947
+ }
1948
+
1949
+ this.publish('error', err && err.reason ? err.reason : err);
1950
+ };
1951
+
1952
+ /**
1953
+ * Called when the transport disconnects.
1954
+ *
1955
+ * @api private
1956
+ */
1957
+
1958
+ Socket.prototype.onDisconnect = function (reason) {
1959
+ var wasConnected = this.connected
1960
+ , wasConnecting = this.connecting;
1961
+
1962
+ this.connected = false;
1963
+ this.connecting = false;
1964
+ this.open = false;
1965
+
1966
+ if (wasConnected || wasConnecting) {
1967
+ this.transport.close();
1968
+ this.transport.clearTimeouts();
1969
+ if (wasConnected) {
1970
+ this.publish('disconnect', reason);
1971
+
1972
+ if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
1973
+ this.reconnect();
1974
+ }
1975
+ }
1976
+ }
1977
+ };
1978
+
1979
+ /**
1980
+ * Called upon reconnection.
1981
+ *
1982
+ * @api private
1983
+ */
1984
+
1985
+ Socket.prototype.reconnect = function () {
1986
+ this.reconnecting = true;
1987
+ this.reconnectionAttempts = 0;
1988
+ this.reconnectionDelay = this.options['reconnection delay'];
1989
+
1990
+ var self = this
1991
+ , maxAttempts = this.options['max reconnection attempts']
1992
+ , tryMultiple = this.options['try multiple transports']
1993
+ , limit = this.options['reconnection limit'];
1994
+
1995
+ function reset () {
1996
+ if (self.connected) {
1997
+ for (var i in self.namespaces) {
1998
+ if (self.namespaces.hasOwnProperty(i) && '' !== i) {
1999
+ self.namespaces[i].packet({ type: 'connect' });
2000
+ }
2001
+ }
2002
+ self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
2003
+ }
2004
+
2005
+ clearTimeout(self.reconnectionTimer);
2006
+
2007
+ self.removeListener('connect_failed', maybeReconnect);
2008
+ self.removeListener('connect', maybeReconnect);
2009
+
2010
+ self.reconnecting = false;
2011
+
2012
+ delete self.reconnectionAttempts;
2013
+ delete self.reconnectionDelay;
2014
+ delete self.reconnectionTimer;
2015
+ delete self.redoTransports;
2016
+
2017
+ self.options['try multiple transports'] = tryMultiple;
2018
+ };
2019
+
2020
+ function maybeReconnect () {
2021
+ if (!self.reconnecting) {
2022
+ return;
2023
+ }
2024
+
2025
+ if (self.connected) {
2026
+ return reset();
2027
+ };
2028
+
2029
+ if (self.connecting && self.reconnecting) {
2030
+ return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
2031
+ }
2032
+
2033
+ if (self.reconnectionAttempts++ >= maxAttempts) {
2034
+ if (!self.redoTransports) {
2035
+ self.on('connect_failed', maybeReconnect);
2036
+ self.options['try multiple transports'] = true;
2037
+ self.transports = self.origTransports;
2038
+ self.transport = self.getTransport();
2039
+ self.redoTransports = true;
2040
+ self.connect();
2041
+ } else {
2042
+ self.publish('reconnect_failed');
2043
+ reset();
2044
+ }
2045
+ } else {
2046
+ if (self.reconnectionDelay < limit) {
2047
+ self.reconnectionDelay *= 2; // exponential back off
2048
+ }
2049
+
2050
+ self.connect();
2051
+ self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
2052
+ self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
2053
+ }
2054
+ };
2055
+
2056
+ this.options['try multiple transports'] = false;
2057
+ this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
2058
+
2059
+ this.on('connect', maybeReconnect);
2060
+ };
2061
+
2062
+ })(
2063
+ 'undefined' != typeof io ? io : module.exports
2064
+ , 'undefined' != typeof io ? io : module.parent.exports
2065
+ , this
2066
+ );
2067
+ /**
2068
+ * socket.io
2069
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2070
+ * MIT Licensed
2071
+ */
2072
+
2073
+ (function (exports, io) {
2074
+
2075
+ /**
2076
+ * Expose constructor.
2077
+ */
2078
+
2079
+ exports.SocketNamespace = SocketNamespace;
2080
+
2081
+ /**
2082
+ * Socket namespace constructor.
2083
+ *
2084
+ * @constructor
2085
+ * @api public
2086
+ */
2087
+
2088
+ function SocketNamespace (socket, name) {
2089
+ this.socket = socket;
2090
+ this.name = name || '';
2091
+ this.flags = {};
2092
+ this.json = new Flag(this, 'json');
2093
+ this.ackPackets = 0;
2094
+ this.acks = {};
2095
+ };
2096
+
2097
+ /**
2098
+ * Apply EventEmitter mixin.
2099
+ */
2100
+
2101
+ io.util.mixin(SocketNamespace, io.EventEmitter);
2102
+
2103
+ /**
2104
+ * Copies emit since we override it
2105
+ *
2106
+ * @api private
2107
+ */
2108
+
2109
+ SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
2110
+
2111
+ /**
2112
+ * Creates a new namespace, by proxying the request to the socket. This
2113
+ * allows us to use the synax as we do on the server.
2114
+ *
2115
+ * @api public
2116
+ */
2117
+
2118
+ SocketNamespace.prototype.of = function () {
2119
+ return this.socket.of.apply(this.socket, arguments);
2120
+ };
2121
+
2122
+ /**
2123
+ * Sends a packet.
2124
+ *
2125
+ * @api private
2126
+ */
2127
+
2128
+ SocketNamespace.prototype.packet = function (packet) {
2129
+ packet.endpoint = this.name;
2130
+ this.socket.packet(packet);
2131
+ this.flags = {};
2132
+ return this;
2133
+ };
2134
+
2135
+ /**
2136
+ * Sends a message
2137
+ *
2138
+ * @api public
2139
+ */
2140
+
2141
+ SocketNamespace.prototype.send = function (data, fn) {
2142
+ var packet = {
2143
+ type: this.flags.json ? 'json' : 'message'
2144
+ , data: data
2145
+ };
2146
+
2147
+ if ('function' == typeof fn) {
2148
+ packet.id = ++this.ackPackets;
2149
+ packet.ack = true;
2150
+ this.acks[packet.id] = fn;
2151
+ }
2152
+
2153
+ return this.packet(packet);
2154
+ };
2155
+
2156
+ /**
2157
+ * Emits an event
2158
+ *
2159
+ * @api public
2160
+ */
2161
+
2162
+ SocketNamespace.prototype.emit = function (name) {
2163
+ var args = Array.prototype.slice.call(arguments, 1)
2164
+ , lastArg = args[args.length - 1]
2165
+ , packet = {
2166
+ type: 'event'
2167
+ , name: name
2168
+ };
2169
+
2170
+ if ('function' == typeof lastArg) {
2171
+ packet.id = ++this.ackPackets;
2172
+ packet.ack = 'data';
2173
+ this.acks[packet.id] = lastArg;
2174
+ args = args.slice(0, args.length - 1);
2175
+ }
2176
+
2177
+ packet.args = args;
2178
+
2179
+ return this.packet(packet);
2180
+ };
2181
+
2182
+ /**
2183
+ * Disconnects the namespace
2184
+ *
2185
+ * @api private
2186
+ */
2187
+
2188
+ SocketNamespace.prototype.disconnect = function () {
2189
+ if (this.name === '') {
2190
+ this.socket.disconnect();
2191
+ } else {
2192
+ this.packet({ type: 'disconnect' });
2193
+ this.$emit('disconnect');
2194
+ }
2195
+
2196
+ return this;
2197
+ };
2198
+
2199
+ /**
2200
+ * Handles a packet
2201
+ *
2202
+ * @api private
2203
+ */
2204
+
2205
+ SocketNamespace.prototype.onPacket = function (packet) {
2206
+ var self = this;
2207
+
2208
+ function ack () {
2209
+ self.packet({
2210
+ type: 'ack'
2211
+ , args: io.util.toArray(arguments)
2212
+ , ackId: packet.id
2213
+ });
2214
+ };
2215
+
2216
+ switch (packet.type) {
2217
+ case 'connect':
2218
+ this.$emit('connect');
2219
+ break;
2220
+
2221
+ case 'disconnect':
2222
+ if (this.name === '') {
2223
+ this.socket.onDisconnect(packet.reason || 'booted');
2224
+ } else {
2225
+ this.$emit('disconnect', packet.reason);
2226
+ }
2227
+ break;
2228
+
2229
+ case 'message':
2230
+ case 'json':
2231
+ var params = ['message', packet.data];
2232
+
2233
+ if (packet.ack == 'data') {
2234
+ params.push(ack);
2235
+ } else if (packet.ack) {
2236
+ this.packet({ type: 'ack', ackId: packet.id });
2237
+ }
2238
+
2239
+ this.$emit.apply(this, params);
2240
+ break;
2241
+
2242
+ case 'event':
2243
+ var params = [packet.name].concat(packet.args);
2244
+
2245
+ if (packet.ack == 'data')
2246
+ params.push(ack);
2247
+
2248
+ this.$emit.apply(this, params);
2249
+ break;
2250
+
2251
+ case 'ack':
2252
+ if (this.acks[packet.ackId]) {
2253
+ this.acks[packet.ackId].apply(this, packet.args);
2254
+ delete this.acks[packet.ackId];
2255
+ }
2256
+ break;
2257
+
2258
+ case 'error':
2259
+ if (packet.advice){
2260
+ this.socket.onError(packet);
2261
+ } else {
2262
+ if (packet.reason == 'unauthorized') {
2263
+ this.$emit('connect_failed', packet.reason);
2264
+ } else {
2265
+ this.$emit('error', packet.reason);
2266
+ }
2267
+ }
2268
+ break;
2269
+ }
2270
+ };
2271
+
2272
+ /**
2273
+ * Flag interface.
2274
+ *
2275
+ * @api private
2276
+ */
2277
+
2278
+ function Flag (nsp, name) {
2279
+ this.namespace = nsp;
2280
+ this.name = name;
2281
+ };
2282
+
2283
+ /**
2284
+ * Send a message
2285
+ *
2286
+ * @api public
2287
+ */
2288
+
2289
+ Flag.prototype.send = function () {
2290
+ this.namespace.flags[this.name] = true;
2291
+ this.namespace.send.apply(this.namespace, arguments);
2292
+ };
2293
+
2294
+ /**
2295
+ * Emit an event
2296
+ *
2297
+ * @api public
2298
+ */
2299
+
2300
+ Flag.prototype.emit = function () {
2301
+ this.namespace.flags[this.name] = true;
2302
+ this.namespace.emit.apply(this.namespace, arguments);
2303
+ };
2304
+
2305
+ })(
2306
+ 'undefined' != typeof io ? io : module.exports
2307
+ , 'undefined' != typeof io ? io : module.parent.exports
2308
+ );
2309
+
2310
+ /**
2311
+ * socket.io
2312
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2313
+ * MIT Licensed
2314
+ */
2315
+
2316
+ (function (exports, io, global) {
2317
+
2318
+ /**
2319
+ * Expose constructor.
2320
+ */
2321
+
2322
+ exports.websocket = WS;
2323
+
2324
+ /**
2325
+ * The WebSocket transport uses the HTML5 WebSocket API to establish an
2326
+ * persistent connection with the Socket.IO server. This transport will also
2327
+ * be inherited by the FlashSocket fallback as it provides a API compatible
2328
+ * polyfill for the WebSockets.
2329
+ *
2330
+ * @constructor
2331
+ * @extends {io.Transport}
2332
+ * @api public
2333
+ */
2334
+
2335
+ function WS (socket) {
2336
+ io.Transport.apply(this, arguments);
2337
+ };
2338
+
2339
+ /**
2340
+ * Inherits from Transport.
2341
+ */
2342
+
2343
+ io.util.inherit(WS, io.Transport);
2344
+
2345
+ /**
2346
+ * Transport name
2347
+ *
2348
+ * @api public
2349
+ */
2350
+
2351
+ WS.prototype.name = 'websocket';
2352
+
2353
+ /**
2354
+ * Initializes a new `WebSocket` connection with the Socket.IO server. We attach
2355
+ * all the appropriate listeners to handle the responses from the server.
2356
+ *
2357
+ * @returns {Transport}
2358
+ * @api public
2359
+ */
2360
+
2361
+ WS.prototype.open = function () {
2362
+ var query = io.util.query(this.socket.options.query)
2363
+ , self = this
2364
+ , Socket
2365
+
2366
+
2367
+ if (!Socket) {
2368
+ Socket = global.MozWebSocket || global.WebSocket;
2369
+ }
2370
+
2371
+ this.websocket = new Socket(this.prepareUrl() + query);
2372
+
2373
+ this.websocket.onopen = function () {
2374
+ self.onOpen();
2375
+ self.socket.setBuffer(false);
2376
+ };
2377
+ this.websocket.onmessage = function (ev) {
2378
+ self.onData(ev.data);
2379
+ };
2380
+ this.websocket.onclose = function () {
2381
+ self.onClose();
2382
+ self.socket.setBuffer(true);
2383
+ };
2384
+ this.websocket.onerror = function (e) {
2385
+ self.onError(e);
2386
+ };
2387
+
2388
+ return this;
2389
+ };
2390
+
2391
+ /**
2392
+ * Send a message to the Socket.IO server. The message will automatically be
2393
+ * encoded in the correct message format.
2394
+ *
2395
+ * @returns {Transport}
2396
+ * @api public
2397
+ */
2398
+
2399
+ // Do to a bug in the current IDevices browser, we need to wrap the send in a
2400
+ // setTimeout, when they resume from sleeping the browser will crash if
2401
+ // we don't allow the browser time to detect the socket has been closed
2402
+ if (io.util.ua.iDevice) {
2403
+ WS.prototype.send = function (data) {
2404
+ var self = this;
2405
+ setTimeout(function() {
2406
+ self.websocket.send(data);
2407
+ },0);
2408
+ return this;
2409
+ };
2410
+ } else {
2411
+ WS.prototype.send = function (data) {
2412
+ this.websocket.send(data);
2413
+ return this;
2414
+ };
2415
+ }
2416
+
2417
+ /**
2418
+ * Payload
2419
+ *
2420
+ * @api private
2421
+ */
2422
+
2423
+ WS.prototype.payload = function (arr) {
2424
+ for (var i = 0, l = arr.length; i < l; i++) {
2425
+ this.packet(arr[i]);
2426
+ }
2427
+ return this;
2428
+ };
2429
+
2430
+ /**
2431
+ * Disconnect the established `WebSocket` connection.
2432
+ *
2433
+ * @returns {Transport}
2434
+ * @api public
2435
+ */
2436
+
2437
+ WS.prototype.close = function () {
2438
+ this.websocket.close();
2439
+ return this;
2440
+ };
2441
+
2442
+ /**
2443
+ * Handle the errors that `WebSocket` might be giving when we
2444
+ * are attempting to connect or send messages.
2445
+ *
2446
+ * @param {Error} e The error.
2447
+ * @api private
2448
+ */
2449
+
2450
+ WS.prototype.onError = function (e) {
2451
+ this.socket.onError(e);
2452
+ };
2453
+
2454
+ /**
2455
+ * Returns the appropriate scheme for the URI generation.
2456
+ *
2457
+ * @api private
2458
+ */
2459
+ WS.prototype.scheme = function () {
2460
+ return this.socket.options.secure ? 'wss' : 'ws';
2461
+ };
2462
+
2463
+ /**
2464
+ * Checks if the browser has support for native `WebSockets` and that
2465
+ * it's not the polyfill created for the FlashSocket transport.
2466
+ *
2467
+ * @return {Boolean}
2468
+ * @api public
2469
+ */
2470
+
2471
+ WS.check = function () {
2472
+ return ('WebSocket' in global && !('__addTask' in WebSocket))
2473
+ || 'MozWebSocket' in global;
2474
+ };
2475
+
2476
+ /**
2477
+ * Check if the `WebSocket` transport support cross domain communications.
2478
+ *
2479
+ * @returns {Boolean}
2480
+ * @api public
2481
+ */
2482
+
2483
+ WS.xdomainCheck = function () {
2484
+ return true;
2485
+ };
2486
+
2487
+ /**
2488
+ * Add the transport to your public io.transports array.
2489
+ *
2490
+ * @api private
2491
+ */
2492
+
2493
+ io.transports.push('websocket');
2494
+
2495
+ })(
2496
+ 'undefined' != typeof io ? io.Transport : module.exports
2497
+ , 'undefined' != typeof io ? io : module.parent.exports
2498
+ , this
2499
+ );
2500
+
2501
+ /**
2502
+ * socket.io
2503
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2504
+ * MIT Licensed
2505
+ */
2506
+
2507
+ (function (exports, io, global) {
2508
+
2509
+ /**
2510
+ * Expose constructor.
2511
+ *
2512
+ * @api public
2513
+ */
2514
+
2515
+ exports.XHR = XHR;
2516
+
2517
+ /**
2518
+ * XHR constructor
2519
+ *
2520
+ * @costructor
2521
+ * @api public
2522
+ */
2523
+
2524
+ function XHR (socket) {
2525
+ if (!socket) return;
2526
+
2527
+ io.Transport.apply(this, arguments);
2528
+ this.sendBuffer = [];
2529
+ };
2530
+
2531
+ /**
2532
+ * Inherits from Transport.
2533
+ */
2534
+
2535
+ io.util.inherit(XHR, io.Transport);
2536
+
2537
+ /**
2538
+ * Establish a connection
2539
+ *
2540
+ * @returns {Transport}
2541
+ * @api public
2542
+ */
2543
+
2544
+ XHR.prototype.open = function () {
2545
+ this.socket.setBuffer(false);
2546
+ this.onOpen();
2547
+ this.get();
2548
+
2549
+ // we need to make sure the request succeeds since we have no indication
2550
+ // whether the request opened or not until it succeeded.
2551
+ this.setCloseTimeout();
2552
+
2553
+ return this;
2554
+ };
2555
+
2556
+ /**
2557
+ * Check if we need to send data to the Socket.IO server, if we have data in our
2558
+ * buffer we encode it and forward it to the `post` method.
2559
+ *
2560
+ * @api private
2561
+ */
2562
+
2563
+ XHR.prototype.payload = function (payload) {
2564
+ var msgs = [];
2565
+
2566
+ for (var i = 0, l = payload.length; i < l; i++) {
2567
+ msgs.push(io.parser.encodePacket(payload[i]));
2568
+ }
2569
+
2570
+ this.send(io.parser.encodePayload(msgs));
2571
+ };
2572
+
2573
+ /**
2574
+ * Send data to the Socket.IO server.
2575
+ *
2576
+ * @param data The message
2577
+ * @returns {Transport}
2578
+ * @api public
2579
+ */
2580
+
2581
+ XHR.prototype.send = function (data) {
2582
+ this.post(data);
2583
+ return this;
2584
+ };
2585
+
2586
+ /**
2587
+ * Posts a encoded message to the Socket.IO server.
2588
+ *
2589
+ * @param {String} data A encoded message.
2590
+ * @api private
2591
+ */
2592
+
2593
+ function empty () { };
2594
+
2595
+ XHR.prototype.post = function (data) {
2596
+ var self = this;
2597
+ this.socket.setBuffer(true);
2598
+
2599
+ function stateChange () {
2600
+ if (this.readyState == 4) {
2601
+ this.onreadystatechange = empty;
2602
+ self.posting = false;
2603
+
2604
+ if (this.status == 200){
2605
+ self.socket.setBuffer(false);
2606
+ } else {
2607
+ self.onClose();
2608
+ }
2609
+ }
2610
+ }
2611
+
2612
+ function onload () {
2613
+ this.onload = empty;
2614
+ self.socket.setBuffer(false);
2615
+ };
2616
+
2617
+ this.sendXHR = this.request('POST');
2618
+
2619
+ if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
2620
+ this.sendXHR.onload = this.sendXHR.onerror = onload;
2621
+ } else {
2622
+ this.sendXHR.onreadystatechange = stateChange;
2623
+ }
2624
+
2625
+ this.sendXHR.send(data);
2626
+ };
2627
+
2628
+ /**
2629
+ * Disconnects the established `XHR` connection.
2630
+ *
2631
+ * @returns {Transport}
2632
+ * @api public
2633
+ */
2634
+
2635
+ XHR.prototype.close = function () {
2636
+ this.onClose();
2637
+ return this;
2638
+ };
2639
+
2640
+ /**
2641
+ * Generates a configured XHR request
2642
+ *
2643
+ * @param {String} url The url that needs to be requested.
2644
+ * @param {String} method The method the request should use.
2645
+ * @returns {XMLHttpRequest}
2646
+ * @api private
2647
+ */
2648
+
2649
+ XHR.prototype.request = function (method) {
2650
+ var req = io.util.request(this.socket.isXDomain())
2651
+ , query = io.util.query(this.socket.options.query, 't=' + +new Date);
2652
+
2653
+ req.open(method || 'GET', this.prepareUrl() + query, true);
2654
+
2655
+ if (method == 'POST') {
2656
+ try {
2657
+ if (req.setRequestHeader) {
2658
+ req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
2659
+ } else {
2660
+ // XDomainRequest
2661
+ req.contentType = 'text/plain';
2662
+ }
2663
+ } catch (e) {}
2664
+ }
2665
+
2666
+ return req;
2667
+ };
2668
+
2669
+ /**
2670
+ * Returns the scheme to use for the transport URLs.
2671
+ *
2672
+ * @api private
2673
+ */
2674
+
2675
+ XHR.prototype.scheme = function () {
2676
+ return this.socket.options.secure ? 'https' : 'http';
2677
+ };
2678
+
2679
+ /**
2680
+ * Check if the XHR transports are supported
2681
+ *
2682
+ * @param {Boolean} xdomain Check if we support cross domain requests.
2683
+ * @returns {Boolean}
2684
+ * @api public
2685
+ */
2686
+
2687
+ XHR.check = function (socket, xdomain) {
2688
+ try {
2689
+ var request = io.util.request(xdomain),
2690
+ usesXDomReq = (global.XDomainRequest && request instanceof XDomainRequest),
2691
+ socketProtocol = (socket && socket.options && socket.options.secure ? 'https:' : 'http:'),
2692
+ isXProtocol = (global.location && socketProtocol != global.location.protocol);
2693
+ if (request && !(usesXDomReq && isXProtocol)) {
2694
+ return true;
2695
+ }
2696
+ } catch(e) {}
2697
+
2698
+ return false;
2699
+ };
2700
+
2701
+ /**
2702
+ * Check if the XHR transport supports cross domain requests.
2703
+ *
2704
+ * @returns {Boolean}
2705
+ * @api public
2706
+ */
2707
+
2708
+ XHR.xdomainCheck = function (socket) {
2709
+ return XHR.check(socket, true);
2710
+ };
2711
+
2712
+ })(
2713
+ 'undefined' != typeof io ? io.Transport : module.exports
2714
+ , 'undefined' != typeof io ? io : module.parent.exports
2715
+ , this
2716
+ );
2717
+
2718
+ /**
2719
+ * socket.io
2720
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
2721
+ * MIT Licensed
2722
+ */
2723
+
2724
+ (function (exports, io, global) {
2725
+
2726
+ /**
2727
+ * Expose constructor.
2728
+ */
2729
+
2730
+ exports['xhr-polling'] = XHRPolling;
2731
+
2732
+ /**
2733
+ * The XHR-polling transport uses long polling XHR requests to create a
2734
+ * "persistent" connection with the server.
2735
+ *
2736
+ * @constructor
2737
+ * @api public
2738
+ */
2739
+
2740
+ function XHRPolling () {
2741
+ io.Transport.XHR.apply(this, arguments);
2742
+ };
2743
+
2744
+ /**
2745
+ * Inherits from XHR transport.
2746
+ */
2747
+
2748
+ io.util.inherit(XHRPolling, io.Transport.XHR);
2749
+
2750
+ /**
2751
+ * Merge the properties from XHR transport
2752
+ */
2753
+
2754
+ io.util.merge(XHRPolling, io.Transport.XHR);
2755
+
2756
+ /**
2757
+ * Transport name
2758
+ *
2759
+ * @api public
2760
+ */
2761
+
2762
+ XHRPolling.prototype.name = 'xhr-polling';
2763
+
2764
+ /**
2765
+ * Indicates whether heartbeats is enabled for this transport
2766
+ *
2767
+ * @api private
2768
+ */
2769
+
2770
+ XHRPolling.prototype.heartbeats = function () {
2771
+ return false;
2772
+ };
2773
+
2774
+ /**
2775
+ * Establish a connection, for iPhone and Android this will be done once the page
2776
+ * is loaded.
2777
+ *
2778
+ * @returns {Transport} Chaining.
2779
+ * @api public
2780
+ */
2781
+
2782
+ XHRPolling.prototype.open = function () {
2783
+ var self = this;
2784
+
2785
+ io.Transport.XHR.prototype.open.call(self);
2786
+ return false;
2787
+ };
2788
+
2789
+ /**
2790
+ * Starts a XHR request to wait for incoming messages.
2791
+ *
2792
+ * @api private
2793
+ */
2794
+
2795
+ function empty () {};
2796
+
2797
+ XHRPolling.prototype.get = function () {
2798
+ if (!this.isOpen) return;
2799
+
2800
+ var self = this;
2801
+
2802
+ function stateChange () {
2803
+ if (this.readyState == 4) {
2804
+ this.onreadystatechange = empty;
2805
+
2806
+ if (this.status == 200) {
2807
+ self.onData(this.responseText);
2808
+ self.get();
2809
+ } else {
2810
+ self.onClose();
2811
+ }
2812
+ }
2813
+ };
2814
+
2815
+ function onload () {
2816
+ this.onload = empty;
2817
+ this.onerror = empty;
2818
+ self.retryCounter = 1;
2819
+ self.onData(this.responseText);
2820
+ self.get();
2821
+ };
2822
+
2823
+ function onerror () {
2824
+ self.retryCounter ++;
2825
+ if(!self.retryCounter || self.retryCounter > 3) {
2826
+ self.onClose();
2827
+ } else {
2828
+ self.get();
2829
+ }
2830
+ };
2831
+
2832
+ this.xhr = this.request();
2833
+
2834
+ if (global.XDomainRequest && this.xhr instanceof XDomainRequest) {
2835
+ this.xhr.onload = onload;
2836
+ this.xhr.onerror = onerror;
2837
+ } else {
2838
+ this.xhr.onreadystatechange = stateChange;
2839
+ }
2840
+
2841
+ this.xhr.send(null);
2842
+ };
2843
+
2844
+ /**
2845
+ * Handle the unclean close behavior.
2846
+ *
2847
+ * @api private
2848
+ */
2849
+
2850
+ XHRPolling.prototype.onClose = function () {
2851
+ io.Transport.XHR.prototype.onClose.call(this);
2852
+
2853
+ if (this.xhr) {
2854
+ this.xhr.onreadystatechange = this.xhr.onload = this.xhr.onerror = empty;
2855
+ try {
2856
+ this.xhr.abort();
2857
+ } catch(e){}
2858
+ this.xhr = null;
2859
+ }
2860
+ };
2861
+
2862
+ /**
2863
+ * Webkit based browsers show a infinit spinner when you start a XHR request
2864
+ * before the browsers onload event is called so we need to defer opening of
2865
+ * the transport until the onload event is called. Wrapping the cb in our
2866
+ * defer method solve this.
2867
+ *
2868
+ * @param {Socket} socket The socket instance that needs a transport
2869
+ * @param {Function} fn The callback
2870
+ * @api private
2871
+ */
2872
+
2873
+ XHRPolling.prototype.ready = function (socket, fn) {
2874
+ var self = this;
2875
+
2876
+ io.util.defer(function () {
2877
+ fn.call(self);
2878
+ });
2879
+ };
2880
+
2881
+ /**
2882
+ * Add the transport to your public io.transports array.
2883
+ *
2884
+ * @api private
2885
+ */
2886
+
2887
+ io.transports.push('xhr-polling');
2888
+
2889
+ })(
2890
+ 'undefined' != typeof io ? io.Transport : module.exports
2891
+ , 'undefined' != typeof io ? io : module.parent.exports
2892
+ , this
2893
+ );
2894
+
2895
+ if (typeof define === "function" && define.amd) {
2896
+ define([], function () { return io; });
2897
+ }
2898
+ })();