Workaround LibreJS parser bug.
[KiwiIRC.git] / client / assets / libs / engine.io.js
1 !function(e){if("object"==typeof exports&&"undefined"!=typeof mod)mod.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.eio=e()}}(function(){var define,mod,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find mod '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,mod,exports){
2
3 mod.exports = _dereq_('./lib/');
4
5 },{"./lib/":2}],2:[function(_dereq_,mod,exports){
6
7 mod.exports = _dereq_('./socket');
8
9 /**
10 * Exports parser
11 *
12 * @api public
13 *
14 */
15 mod.exports.parser = _dereq_('engine.io-parser');
16
17 },{"./socket":3,"engine.io-parser":15}],3:[function(_dereq_,mod,exports){
18 (function (global){
19 /**
20 * Mod dependencies.
21 */
22
23 var transports = _dereq_('./transports');
24 var Emitter = _dereq_('component-emitter');
25 var debug = _dereq_('debug')('engine.io-client:socket');
26 var index = _dereq_('indexof');
27 var parser = _dereq_('engine.io-parser');
28 var parseuri = _dereq_('parseuri');
29 var parsejson = _dereq_('parsejson');
30 var parseqs = _dereq_('parseqs');
31
32 /**
33 * Mod exports.
34 */
35
36 mod.exports = Socket;
37
38 /**
39 * Noop function.
40 *
41 * @api private
42 */
43
44 function noop(){}
45
46 /**
47 * Socket constructor.
48 *
49 * @param {String|Object} uri or options
50 * @param {Object} options
51 * @api public
52 */
53
54 function Socket(uri, opts){
55 if (!(this instanceof Socket)) return new Socket(uri, opts);
56
57 opts = opts || {};
58
59 if (uri && 'object' == typeof uri) {
60 opts = uri;
61 uri = null;
62 }
63
64 if (uri) {
65 uri = parseuri(uri);
66 opts.host = uri.host;
67 opts.secure = uri.protocol == 'https' || uri.protocol == 'wss';
68 opts.port = uri.port;
69 if (uri.query) opts.query = uri.query;
70 }
71
72 this.secure = null != opts.secure ? opts.secure :
73 (global.location && 'https:' == location.protocol);
74
75 if (opts.host) {
76 var pieces = opts.host.split(':');
77 opts.hostname = pieces.shift();
78 if (pieces.length) opts.port = pieces.pop();
79 }
80
81 this.agent = opts.agent || false;
82 this.hostname = opts.hostname ||
83 (global.location ? location.hostname : 'localhost');
84 this.port = opts.port || (global.location && location.port ?
85 location.port :
86 (this.secure ? 443 : 80));
87 this.query = opts.query || {};
88 if ('string' == typeof this.query) this.query = parseqs.decode(this.query);
89 this.upgrade = false !== opts.upgrade;
90 this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
91 this.forceJSONP = !!opts.forceJSONP;
92 this.jsonp = false !== opts.jsonp;
93 this.forceBase64 = !!opts.forceBase64;
94 this.enablesXDR = !!opts.enablesXDR;
95 this.timestampParam = opts.timestampParam || 't';
96 this.timestampRequests = opts.timestampRequests;
97 this.transports = opts.transports || ['polling', 'websocket'];
98 this.readyState = '';
99 this.writeBuffer = [];
100 this.callbackBuffer = [];
101 this.policyPort = opts.policyPort || 843;
102 this.rememberUpgrade = opts.rememberUpgrade || false;
103 this.open();
104 this.binaryType = null;
105 this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades;
106 }
107
108 Socket.priorWebsocketSuccess = false;
109
110 /**
111 * Mix in `Emitter`.
112 */
113
114 Emitter(Socket.prototype);
115
116 /**
117 * Protocol version.
118 *
119 * @api public
120 */
121
122 Socket.protocol = parser.protocol; // this is an int
123
124 /**
125 * Expose deps for legacy compatibility
126 * and standalone browser access.
127 */
128
129 Socket.Socket = Socket;
130 Socket.Transport = _dereq_('./transport');
131 Socket.transports = _dereq_('./transports');
132 Socket.parser = _dereq_('engine.io-parser');
133
134 /**
135 * Creates transport of the given type.
136 *
137 * @param {String} transport name
138 * @return {Transport}
139 * @api private
140 */
141
142 Socket.prototype.createTransport = function (name) {
143 debug('creating transport "%s"', name);
144 var query = clone(this.query);
145
146 // append engine.io protocol identifier
147 query.EIO = parser.protocol;
148
149 // transport name
150 query.transport = name;
151
152 // session id if we already have one
153 if (this.id) query.sid = this.id;
154
155 var transport = new transports[name]({
156 agent: this.agent,
157 hostname: this.hostname,
158 port: this.port,
159 secure: this.secure,
160 path: this.path,
161 query: query,
162 forceJSONP: this.forceJSONP,
163 jsonp: this.jsonp,
164 forceBase64: this.forceBase64,
165 enablesXDR: this.enablesXDR,
166 timestampRequests: this.timestampRequests,
167 timestampParam: this.timestampParam,
168 policyPort: this.policyPort,
169 socket: this
170 });
171
172 return transport;
173 };
174
175 function clone (obj) {
176 var o = {};
177 for (var i in obj) {
178 if (obj.hasOwnProperty(i)) {
179 o[i] = obj[i];
180 }
181 }
182 return o;
183 }
184
185 /**
186 * Initializes transport to use and starts probe.
187 *
188 * @api private
189 */
190 Socket.prototype.open = function () {
191 var transport;
192 if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) {
193 transport = 'websocket';
194 } else if (0 == this.transports.length) {
195 // Emit error on next tick so it can be listened to
196 var self = this;
197 setTimeout(function() {
198 self.emit('error', 'No transports available');
199 }, 0);
200 return;
201 } else {
202 transport = this.transports[0];
203 }
204 this.readyState = 'opening';
205
206 // Retry with the next transport if the transport is disabled (jsonp: false)
207 var transport;
208 try {
209 transport = this.createTransport(transport);
210 } catch (e) {
211 this.transports.shift();
212 this.open();
213 return;
214 }
215
216 transport.open();
217 this.setTransport(transport);
218 };
219
220 /**
221 * Sets the current transport. Disables the existing one (if any).
222 *
223 * @api private
224 */
225
226 Socket.prototype.setTransport = function(transport){
227 debug('setting transport %s', transport.name);
228 var self = this;
229
230 if (this.transport) {
231 debug('clearing existing transport %s', this.transport.name);
232 this.transport.removeAllListeners();
233 }
234
235 // set up transport
236 this.transport = transport;
237
238 // set up transport listeners
239 transport
240 .on('drain', function(){
241 self.onDrain();
242 })
243 .on('packet', function(packet){
244 self.onPacket(packet);
245 })
246 .on('error', function(e){
247 self.onError(e);
248 })
249 .on('close', function(){
250 self.onClose('transport close');
251 });
252 };
253
254 /**
255 * Probes a transport.
256 *
257 * @param {String} transport name
258 * @api private
259 */
260
261 Socket.prototype.probe = function (name) {
262 debug('probing transport "%s"', name);
263 var transport = this.createTransport(name, { probe: 1 })
264 , failed = false
265 , self = this;
266
267 Socket.priorWebsocketSuccess = false;
268
269 function onTransportOpen(){
270 if (self.onlyBinaryUpgrades) {
271 var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary;
272 failed = failed || upgradeLosesBinary;
273 }
274 if (failed) return;
275
276 debug('probe transport "%s" opened', name);
277 transport.send([{ type: 'ping', data: 'probe' }]);
278 transport.once('packet', function (msg) {
279 if (failed) return;
280 if ('pong' == msg.type && 'probe' == msg.data) {
281 debug('probe transport "%s" pong', name);
282 self.upgrading = true;
283 self.emit('upgrading', transport);
284 Socket.priorWebsocketSuccess = 'websocket' == transport.name;
285
286 debug('pausing current transport "%s"', self.transport.name);
287 self.transport.pause(function () {
288 if (failed) return;
289 if ('closed' == self.readyState || 'closing' == self.readyState) {
290 return;
291 }
292 debug('changing transport and sending upgrade packet');
293
294 cleanup();
295
296 self.setTransport(transport);
297 transport.send([{ type: 'upgrade' }]);
298 self.emit('upgrade', transport);
299 transport = null;
300 self.upgrading = false;
301 self.flush();
302 });
303 } else {
304 debug('probe transport "%s" failed', name);
305 var err = new Error('probe error');
306 err.transport = transport.name;
307 self.emit('upgradeError', err);
308 }
309 });
310 }
311
312 function freezeTransport() {
313 if (failed) return;
314
315 // Any callback called by transport should be ignored since now
316 failed = true;
317
318 cleanup();
319
320 transport.close();
321 transport = null;
322 }
323
324 //Handle any error that happens while probing
325 function onerror(err) {
326 var error = new Error('probe error: ' + err);
327 error.transport = transport.name;
328
329 freezeTransport();
330
331 debug('probe transport "%s" failed because of error: %s', name, err);
332
333 self.emit('upgradeError', error);
334 }
335
336 function onTransportClose(){
337 onerror("transport closed");
338 }
339
340 //When the socket is closed while we're probing
341 function onclose(){
342 onerror("socket closed");
343 }
344
345 //When the socket is upgraded while we're probing
346 function onupgrade(to){
347 if (transport && to.name != transport.name) {
348 debug('"%s" works - aborting "%s"', to.name, transport.name);
349 freezeTransport();
350 }
351 }
352
353 //Remove all listeners on the transport and on self
354 function cleanup(){
355 transport.removeListener('open', onTransportOpen);
356 transport.removeListener('error', onerror);
357 transport.removeListener('close', onTransportClose);
358 self.removeListener('close', onclose);
359 self.removeListener('upgrading', onupgrade);
360 }
361
362 transport.once('open', onTransportOpen);
363 transport.once('error', onerror);
364 transport.once('close', onTransportClose);
365
366 this.once('close', onclose);
367 this.once('upgrading', onupgrade);
368
369 transport.open();
370
371 };
372
373 /**
374 * Called when connection is deemed open.
375 *
376 * @api public
377 */
378
379 Socket.prototype.onOpen = function () {
380 debug('socket open');
381 this.readyState = 'open';
382 Socket.priorWebsocketSuccess = 'websocket' == this.transport.name;
383 this.emit('open');
384 this.flush();
385
386 // we check for `readyState` in case an `open`
387 // listener already closed the socket
388 if ('open' == this.readyState && this.upgrade && this.transport.pause) {
389 debug('starting upgrade probes');
390 for (var i = 0, l = this.upgrades.length; i < l; i++) {
391 this.probe(this.upgrades[i]);
392 }
393 }
394 };
395
396 /**
397 * Handles a packet.
398 *
399 * @api private
400 */
401
402 Socket.prototype.onPacket = function (packet) {
403 if ('opening' == this.readyState || 'open' == this.readyState) {
404 debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
405
406 this.emit('packet', packet);
407
408 // Socket is live - any packet counts
409 this.emit('heartbeat');
410
411 switch (packet.type) {
412 case 'open':
413 this.onHandshake(parsejson(packet.data));
414 break;
415
416 case 'pong':
417 this.setPing();
418 break;
419
420 case 'error':
421 var err = new Error('server error');
422 err.code = packet.data;
423 this.emit('error', err);
424 break;
425
426 case 'message':
427 this.emit('data', packet.data);
428 this.emit('message', packet.data);
429 break;
430 }
431 } else {
432 debug('packet received with socket readyState "%s"', this.readyState);
433 }
434 };
435
436 /**
437 * Called upon handshake completion.
438 *
439 * @param {Object} handshake obj
440 * @api private
441 */
442
443 Socket.prototype.onHandshake = function (data) {
444 this.emit('handshake', data);
445 this.id = data.sid;
446 this.transport.query.sid = data.sid;
447 this.upgrades = this.filterUpgrades(data.upgrades);
448 this.pingInterval = data.pingInterval;
449 this.pingTimeout = data.pingTimeout;
450 this.onOpen();
451 // In case open handler closes socket
452 if ('closed' == this.readyState) return;
453 this.setPing();
454
455 // Prolong liveness of socket on heartbeat
456 this.removeListener('heartbeat', this.onHeartbeat);
457 this.on('heartbeat', this.onHeartbeat);
458 };
459
460 /**
461 * Resets ping timeout.
462 *
463 * @api private
464 */
465
466 Socket.prototype.onHeartbeat = function (timeout) {
467 clearTimeout(this.pingTimeoutTimer);
468 var self = this;
469 self.pingTimeoutTimer = setTimeout(function () {
470 if ('closed' == self.readyState) return;
471 self.onClose('ping timeout');
472 }, timeout || (self.pingInterval + self.pingTimeout));
473 };
474
475 /**
476 * Pings server every `this.pingInterval` and expects response
477 * within `this.pingTimeout` or closes connection.
478 *
479 * @api private
480 */
481
482 Socket.prototype.setPing = function () {
483 var self = this;
484 clearTimeout(self.pingIntervalTimer);
485 self.pingIntervalTimer = setTimeout(function () {
486 debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
487 self.ping();
488 self.onHeartbeat(self.pingTimeout);
489 }, self.pingInterval);
490 };
491
492 /**
493 * Sends a ping packet.
494 *
495 * @api public
496 */
497
498 Socket.prototype.ping = function () {
499 this.sendPacket('ping');
500 };
501
502 /**
503 * Called on `drain` event
504 *
505 * @api private
506 */
507
508 Socket.prototype.onDrain = function() {
509 for (var i = 0; i < this.prevBufferLen; i++) {
510 if (this.callbackBuffer[i]) {
511 this.callbackBuffer[i]();
512 }
513 }
514
515 this.writeBuffer.splice(0, this.prevBufferLen);
516 this.callbackBuffer.splice(0, this.prevBufferLen);
517
518 // setting prevBufferLen = 0 is very important
519 // for example, when upgrading, upgrade packet is sent over,
520 // and a nonzero prevBufferLen could cause problems on `drain`
521 this.prevBufferLen = 0;
522
523 if (this.writeBuffer.length == 0) {
524 this.emit('drain');
525 } else {
526 this.flush();
527 }
528 };
529
530 /**
531 * Flush write buffers.
532 *
533 * @api private
534 */
535
536 Socket.prototype.flush = function () {
537 if ('closed' != this.readyState && this.transport.writable &&
538 !this.upgrading && this.writeBuffer.length) {
539 debug('flushing %d packets in socket', this.writeBuffer.length);
540 this.transport.send(this.writeBuffer);
541 // keep track of current length of writeBuffer
542 // splice writeBuffer and callbackBuffer on `drain`
543 this.prevBufferLen = this.writeBuffer.length;
544 this.emit('flush');
545 }
546 };
547
548 /**
549 * Sends a message.
550 *
551 * @param {String} message.
552 * @param {Function} callback function.
553 * @return {Socket} for chaining.
554 * @api public
555 */
556
557 Socket.prototype.write =
558 Socket.prototype.send = function (msg, fn) {
559 this.sendPacket('message', msg, fn);
560 return this;
561 };
562
563 /**
564 * Sends a packet.
565 *
566 * @param {String} packet type.
567 * @param {String} data.
568 * @param {Function} callback function.
569 * @api private
570 */
571
572 Socket.prototype.sendPacket = function (type, data, fn) {
573 var packet = { type: type, data: data };
574 this.emit('packetCreate', packet);
575 this.writeBuffer.push(packet);
576 this.callbackBuffer.push(fn);
577 this.flush();
578 };
579
580 /**
581 * Closes the connection.
582 *
583 * @api private
584 */
585
586 Socket.prototype.close = function () {
587 if ('opening' == this.readyState || 'open' == this.readyState) {
588 this.onClose('forced close');
589 debug('socket closing - telling transport to close');
590 this.transport.close();
591 }
592
593 return this;
594 };
595
596 /**
597 * Called upon transport error
598 *
599 * @api private
600 */
601
602 Socket.prototype.onError = function (err) {
603 debug('socket error %j', err);
604 Socket.priorWebsocketSuccess = false;
605 this.emit('error', err);
606 this.onClose('transport error', err);
607 };
608
609 /**
610 * Called upon transport close.
611 *
612 * @api private
613 */
614
615 Socket.prototype.onClose = function (reason, desc) {
616 if ('opening' == this.readyState || 'open' == this.readyState) {
617 debug('socket close with reason: "%s"', reason);
618 var self = this;
619
620 // clear timers
621 clearTimeout(this.pingIntervalTimer);
622 clearTimeout(this.pingTimeoutTimer);
623
624 // clean buffers in next tick, so developers can still
625 // grab the buffers on `close` event
626 setTimeout(function() {
627 self.writeBuffer = [];
628 self.callbackBuffer = [];
629 self.prevBufferLen = 0;
630 }, 0);
631
632 // stop event from firing again for transport
633 this.transport.removeAllListeners('close');
634
635 // ensure transport won't stay open
636 this.transport.close();
637
638 // ignore further transport communication
639 this.transport.removeAllListeners();
640
641 // set ready state
642 this.readyState = 'closed';
643
644 // clear session id
645 this.id = null;
646
647 // emit close event
648 this.emit('close', reason, desc);
649 }
650 };
651
652 /**
653 * Filters upgrades, returning only those matching client transports.
654 *
655 * @param {Array} server upgrades
656 * @api private
657 *
658 */
659
660 Socket.prototype.filterUpgrades = function (upgrades) {
661 var filteredUpgrades = [];
662 for (var i = 0, j = upgrades.length; i<j; i++) {
663 if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]);
664 }
665 return filteredUpgrades;
666 };
667
668 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
669 },{"./transport":4,"./transports":5,"component-emitter":12,"debug":14,"engine.io-parser":15,"indexof":23,"parsejson":24,"parseqs":25,"parseuri":26}],4:[function(_dereq_,mod,exports){
670 /**
671 * Mod dependencies.
672 */
673
674 var parser = _dereq_('engine.io-parser');
675 var Emitter = _dereq_('component-emitter');
676
677 /**
678 * Mod exports.
679 */
680
681 mod.exports = Transport;
682
683 /**
684 * Transport abstract constructor.
685 *
686 * @param {Object} options.
687 * @api private
688 */
689
690 function Transport (opts) {
691 this.path = opts.path;
692 this.hostname = opts.hostname;
693 this.port = opts.port;
694 this.secure = opts.secure;
695 this.query = opts.query;
696 this.timestampParam = opts.timestampParam;
697 this.timestampRequests = opts.timestampRequests;
698 this.readyState = '';
699 this.agent = opts.agent || false;
700 this.socket = opts.socket;
701 this.enablesXDR = opts.enablesXDR;
702 }
703
704 /**
705 * Mix in `Emitter`.
706 */
707
708 Emitter(Transport.prototype);
709
710 /**
711 * A counter used to prevent collisions in the timestamps used
712 * for cache busting.
713 */
714
715 Transport.timestamps = 0;
716
717 /**
718 * Emits an error.
719 *
720 * @param {String} str
721 * @return {Transport} for chaining
722 * @api public
723 */
724
725 Transport.prototype.onError = function (msg, desc) {
726 var err = new Error(msg);
727 err.type = 'TransportError';
728 err.description = desc;
729 this.emit('error', err);
730 return this;
731 };
732
733 /**
734 * Opens the transport.
735 *
736 * @api public
737 */
738
739 Transport.prototype.open = function () {
740 if ('closed' == this.readyState || '' == this.readyState) {
741 this.readyState = 'opening';
742 this.doOpen();
743 }
744
745 return this;
746 };
747
748 /**
749 * Closes the transport.
750 *
751 * @api private
752 */
753
754 Transport.prototype.close = function () {
755 if ('opening' == this.readyState || 'open' == this.readyState) {
756 this.doClose();
757 this.onClose();
758 }
759
760 return this;
761 };
762
763 /**
764 * Sends multiple packets.
765 *
766 * @param {Array} packets
767 * @api private
768 */
769
770 Transport.prototype.send = function(packets){
771 if ('open' == this.readyState) {
772 this.write(packets);
773 } else {
774 throw new Error('Transport not open');
775 }
776 };
777
778 /**
779 * Called upon open
780 *
781 * @api private
782 */
783
784 Transport.prototype.onOpen = function () {
785 this.readyState = 'open';
786 this.writable = true;
787 this.emit('open');
788 };
789
790 /**
791 * Called with data.
792 *
793 * @param {String} data
794 * @api private
795 */
796
797 Transport.prototype.onData = function(data){
798 var packet = parser.decodePacket(data, this.socket.binaryType);
799 this.onPacket(packet);
800 };
801
802 /**
803 * Called with a decoded packet.
804 */
805
806 Transport.prototype.onPacket = function (packet) {
807 this.emit('packet', packet);
808 };
809
810 /**
811 * Called upon close.
812 *
813 * @api private
814 */
815
816 Transport.prototype.onClose = function () {
817 this.readyState = 'closed';
818 this.emit('close');
819 };
820
821 },{"component-emitter":12,"engine.io-parser":15}],5:[function(_dereq_,mod,exports){
822 (function (global){
823 /**
824 * Mod dependencies
825 */
826
827 var XMLHttpRequest = _dereq_('xmlhttprequest');
828 var XHR = _dereq_('./polling-xhr');
829 var JSONP = _dereq_('./polling-jsonp');
830 var websocket = _dereq_('./websocket');
831
832 /**
833 * Export transports.
834 */
835
836 exports.polling = polling;
837 exports.websocket = websocket;
838
839 /**
840 * Polling transport polymorphic constructor.
841 * Decides on xhr vs jsonp based on feature detection.
842 *
843 * @api private
844 */
845
846 function polling(opts){
847 var xhr;
848 var xd = false;
849 var xs = false;
850 var jsonp = false !== opts.jsonp;
851
852 if (global.location) {
853 var isSSL = 'https:' == location.protocol;
854 var port = location.port;
855
856 // some user agents have empty `location.port`
857 if (!port) {
858 port = isSSL ? 443 : 80;
859 }
860
861 xd = opts.hostname != location.hostname || port != opts.port;
862 xs = opts.secure != isSSL;
863 }
864
865 opts.xdomain = xd;
866 opts.xscheme = xs;
867 xhr = new XMLHttpRequest(opts);
868
869 if ('open' in xhr && !opts.forceJSONP) {
870 return new XHR(opts);
871 } else {
872 if (!jsonp) throw new Error('JSONP disabled');
873 return new JSONP(opts);
874 }
875 }
876
877 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
878 },{"./polling-jsonp":6,"./polling-xhr":7,"./websocket":9,"xmlhttprequest":10}],6:[function(_dereq_,mod,exports){
879 (function (global){
880
881 /**
882 * Mod requirements.
883 */
884
885 var Polling = _dereq_('./polling');
886 var inherit = _dereq_('component-inherit');
887
888 /**
889 * Mod exports.
890 */
891
892 mod.exports = JSONPPolling;
893
894 /**
895 * Cached regular expressions.
896 */
897
898 var rNewline = /\n/g;
899 var rEscapedNewline = /\\n/g;
900
901 /**
902 * Global JSONP callbacks.
903 */
904
905 var callbacks;
906
907 /**
908 * Callbacks count.
909 */
910
911 var index = 0;
912
913 /**
914 * Noop.
915 */
916
917 function empty () { }
918
919 /**
920 * JSONP Polling constructor.
921 *
922 * @param {Object} opts.
923 * @api public
924 */
925
926 function JSONPPolling (opts) {
927 Polling.call(this, opts);
928
929 this.query = this.query || {};
930
931 // define global callbacks array if not present
932 // we do this here (lazily) to avoid unneeded global pollution
933 if (!callbacks) {
934 // we need to consider multiple engines in the same page
935 if (!global.___eio) global.___eio = [];
936 callbacks = global.___eio;
937 }
938
939 // callback identifier
940 this.index = callbacks.length;
941
942 // add callback to jsonp global
943 var self = this;
944 callbacks.push(function (msg) {
945 self.onData(msg);
946 });
947
948 // append to query string
949 this.query.j = this.index;
950
951 // prevent spurious errors from being emitted when the window is unloaded
952 if (global.document && global.addEventListener) {
953 global.addEventListener('beforeunload', function () {
954 if (self.script) self.script.onerror = empty;
955 });
956 }
957 }
958
959 /**
960 * Inherits from Polling.
961 */
962
963 inherit(JSONPPolling, Polling);
964
965 /*
966 * JSONP only supports binary as base64 encoded strings
967 */
968
969 JSONPPolling.prototype.supportsBinary = false;
970
971 /**
972 * Closes the socket.
973 *
974 * @api private
975 */
976
977 JSONPPolling.prototype.doClose = function () {
978 if (this.script) {
979 this.script.parentNode.removeChild(this.script);
980 this.script = null;
981 }
982
983 if (this.form) {
984 this.form.parentNode.removeChild(this.form);
985 this.form = null;
986 }
987
988 Polling.prototype.doClose.call(this);
989 };
990
991 /**
992 * Starts a poll cycle.
993 *
994 * @api private
995 */
996
997 JSONPPolling.prototype.doPoll = function () {
998 var self = this;
999 var script = document.createElement('script');
1000
1001 if (this.script) {
1002 this.script.parentNode.removeChild(this.script);
1003 this.script = null;
1004 }
1005
1006 script.async = true;
1007 script.src = this.uri();
1008 script.onerror = function(e){
1009 self.onError('jsonp poll error',e);
1010 };
1011
1012 var insertAt = document.getElementsByTagName('script')[0];
1013 insertAt.parentNode.insertBefore(script, insertAt);
1014 this.script = script;
1015
1016 var isUAgecko = 'undefined' != typeof navigator && /gecko/i.test(navigator.userAgent);
1017
1018 if (isUAgecko) {
1019 setTimeout(function () {
1020 var iframe = document.createElement('iframe');
1021 document.body.appendChild(iframe);
1022 document.body.removeChild(iframe);
1023 }, 100);
1024 }
1025 };
1026
1027 /**
1028 * Writes with a hidden iframe.
1029 *
1030 * @param {String} data to send
1031 * @param {Function} called upon flush.
1032 * @api private
1033 */
1034
1035 JSONPPolling.prototype.doWrite = function (data, fn) {
1036 var self = this;
1037
1038 if (!this.form) {
1039 var form = document.createElement('form');
1040 var area = document.createElement('textarea');
1041 var id = this.iframeId = 'eio_iframe_' + this.index;
1042 var iframe;
1043
1044 form.className = 'socketio';
1045 form.style.position = 'absolute';
1046 form.style.top = '-1000px';
1047 form.style.left = '-1000px';
1048 form.target = id;
1049 form.method = 'POST';
1050 form.setAttribute('accept-charset', 'utf-8');
1051 area.name = 'd';
1052 form.appendChild(area);
1053 document.body.appendChild(form);
1054
1055 this.form = form;
1056 this.area = area;
1057 }
1058
1059 this.form.action = this.uri();
1060
1061 function complete () {
1062 initIframe();
1063 fn();
1064 }
1065
1066 function initIframe () {
1067 if (self.iframe) {
1068 try {
1069 self.form.removeChild(self.iframe);
1070 } catch (e) {
1071 self.onError('jsonp polling iframe removal error', e);
1072 }
1073 }
1074
1075 try {
1076 // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
1077 var html = '<iframe src="javascript:0" name="'+ self.iframeId +'">';
1078 iframe = document.createElement(html);
1079 } catch (e) {
1080 iframe = document.createElement('iframe');
1081 iframe.name = self.iframeId;
1082 iframe.src = 'javascript:0';
1083 }
1084
1085 iframe.id = self.iframeId;
1086
1087 self.form.appendChild(iframe);
1088 self.iframe = iframe;
1089 }
1090
1091 initIframe();
1092
1093 // escape \n to prevent it from being converted into \r\n by some UAs
1094 // double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side
1095 data = data.replace(rEscapedNewline, '\\\n');
1096 this.area.value = data.replace(rNewline, '\\n');
1097
1098 try {
1099 this.form.submit();
1100 } catch(e) {}
1101
1102 if (this.iframe.attachEvent) {
1103 this.iframe.onreadystatechange = function(){
1104 if (self.iframe.readyState == 'complete') {
1105 complete();
1106 }
1107 };
1108 } else {
1109 this.iframe.onload = complete;
1110 }
1111 };
1112
1113 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1114 },{"./polling":8,"component-inherit":13}],7:[function(_dereq_,mod,exports){
1115 (function (global){
1116 /**
1117 * Mod requirements.
1118 */
1119
1120 var XMLHttpRequest = _dereq_('xmlhttprequest');
1121 var Polling = _dereq_('./polling');
1122 var Emitter = _dereq_('component-emitter');
1123 var inherit = _dereq_('component-inherit');
1124 var debug = _dereq_('debug')('engine.io-client:polling-xhr');
1125
1126 /**
1127 * Mod exports.
1128 */
1129
1130 mod.exports = XHR;
1131 mod.exports.Request = Request;
1132
1133 /**
1134 * Empty function
1135 */
1136
1137 function empty(){}
1138
1139 /**
1140 * XHR Polling constructor.
1141 *
1142 * @param {Object} opts
1143 * @api public
1144 */
1145
1146 function XHR(opts){
1147 Polling.call(this, opts);
1148
1149 if (global.location) {
1150 var isSSL = 'https:' == location.protocol;
1151 var port = location.port;
1152
1153 // some user agents have empty `location.port`
1154 if (!port) {
1155 port = isSSL ? 443 : 80;
1156 }
1157
1158 this.xd = opts.hostname != global.location.hostname ||
1159 port != opts.port;
1160 this.xs = opts.secure != isSSL;
1161 }
1162 }
1163
1164 /**
1165 * Inherits from Polling.
1166 */
1167
1168 inherit(XHR, Polling);
1169
1170 /**
1171 * XHR supports binary
1172 */
1173
1174 XHR.prototype.supportsBinary = true;
1175
1176 /**
1177 * Creates a request.
1178 *
1179 * @param {String} method
1180 * @api private
1181 */
1182
1183 XHR.prototype.request = function(opts){
1184 opts = opts || {};
1185 opts.uri = this.uri();
1186 opts.xd = this.xd;
1187 opts.xs = this.xs;
1188 opts.agent = this.agent || false;
1189 opts.supportsBinary = this.supportsBinary;
1190 opts.enablesXDR = this.enablesXDR;
1191 return new Request(opts);
1192 };
1193
1194 /**
1195 * Sends data.
1196 *
1197 * @param {String} data to send.
1198 * @param {Function} called upon flush.
1199 * @api private
1200 */
1201
1202 XHR.prototype.doWrite = function(data, fn){
1203 var isBinary = typeof data !== 'string' && data !== undefined;
1204 var req = this.request({ method: 'POST', data: data, isBinary: isBinary });
1205 var self = this;
1206 req.on('success', fn);
1207 req.on('error', function(err){
1208 self.onError('xhr post error', err);
1209 });
1210 this.sendXhr = req;
1211 };
1212
1213 /**
1214 * Starts a poll cycle.
1215 *
1216 * @api private
1217 */
1218
1219 XHR.prototype.doPoll = function(){
1220 debug('xhr poll');
1221 var req = this.request();
1222 var self = this;
1223 req.on('data', function(data){
1224 self.onData(data);
1225 });
1226 req.on('error', function(err){
1227 self.onError('xhr poll error', err);
1228 });
1229 this.pollXhr = req;
1230 };
1231
1232 /**
1233 * Request constructor
1234 *
1235 * @param {Object} options
1236 * @api public
1237 */
1238
1239 function Request(opts){
1240 this.method = opts.method || 'GET';
1241 this.uri = opts.uri;
1242 this.xd = !!opts.xd;
1243 this.xs = !!opts.xs;
1244 this.async = false !== opts.async;
1245 this.data = undefined != opts.data ? opts.data : null;
1246 this.agent = opts.agent;
1247 this.isBinary = opts.isBinary;
1248 this.supportsBinary = opts.supportsBinary;
1249 this.enablesXDR = opts.enablesXDR;
1250 this.create();
1251 }
1252
1253 /**
1254 * Mix in `Emitter`.
1255 */
1256
1257 Emitter(Request.prototype);
1258
1259 /**
1260 * Creates the XHR object and sends the request.
1261 *
1262 * @api private
1263 */
1264
1265 Request.prototype.create = function(){
1266 var xhr = this.xhr = new XMLHttpRequest({ agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR });
1267 var self = this;
1268
1269 try {
1270 debug('xhr open %s: %s', this.method, this.uri);
1271 xhr.open(this.method, this.uri, this.async);
1272 if (this.supportsBinary) {
1273 // This has to be done after open because Firefox is stupid
1274 // http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
1275 xhr.responseType = 'arraybuffer';
1276 }
1277
1278 if ('POST' == this.method) {
1279 try {
1280 if (this.isBinary) {
1281 xhr.setRequestHeader('Content-type', 'application/octet-stream');
1282 } else {
1283 xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
1284 }
1285 } catch (e) {}
1286 }
1287
1288 // ie6 check
1289 if ('withCredentials' in xhr) {
1290 xhr.withCredentials = true;
1291 }
1292
1293 if (this.hasXDR()) {
1294 xhr.onload = function(){
1295 self.onLoad();
1296 };
1297 xhr.onerror = function(){
1298 self.onError(xhr.responseText);
1299 };
1300 } else {
1301 xhr.onreadystatechange = function(){
1302 if (4 != xhr.readyState) return;
1303 if (200 == xhr.status || 1223 == xhr.status) {
1304 self.onLoad();
1305 } else {
1306 // make sure the `error` event handler that's user-set
1307 // does not throw in the same tick and gets caught here
1308 setTimeout(function(){
1309 self.onError(xhr.status);
1310 }, 0);
1311 }
1312 };
1313 }
1314
1315 debug('xhr data %s', this.data);
1316 xhr.send(this.data);
1317 } catch (e) {
1318 // Need to defer since .create() is called directly fhrom the constructor
1319 // and thus the 'error' event can only be only bound *after* this exception
1320 // occurs. Therefore, also, we cannot throw here at all.
1321 setTimeout(function() {
1322 self.onError(e);
1323 }, 0);
1324 return;
1325 }
1326
1327 if (global.document) {
1328 this.index = Request.requestsCount++;
1329 Request.requests[this.index] = this;
1330 }
1331 };
1332
1333 /**
1334 * Called upon successful response.
1335 *
1336 * @api private
1337 */
1338
1339 Request.prototype.onSuccess = function(){
1340 this.emit('success');
1341 this.cleanup();
1342 };
1343
1344 /**
1345 * Called if we have data.
1346 *
1347 * @api private
1348 */
1349
1350 Request.prototype.onData = function(data){
1351 this.emit('data', data);
1352 this.onSuccess();
1353 };
1354
1355 /**
1356 * Called upon error.
1357 *
1358 * @api private
1359 */
1360
1361 Request.prototype.onError = function(err){
1362 this.emit('error', err);
1363 this.cleanup();
1364 };
1365
1366 /**
1367 * Cleans up house.
1368 *
1369 * @api private
1370 */
1371
1372 Request.prototype.cleanup = function(){
1373 if ('undefined' == typeof this.xhr || null === this.xhr) {
1374 return;
1375 }
1376 // xmlhttprequest
1377 if (this.hasXDR()) {
1378 this.xhr.onload = this.xhr.onerror = empty;
1379 } else {
1380 this.xhr.onreadystatechange = empty;
1381 }
1382
1383 try {
1384 this.xhr.abort();
1385 } catch(e) {}
1386
1387 if (global.document) {
1388 delete Request.requests[this.index];
1389 }
1390
1391 this.xhr = null;
1392 };
1393
1394 /**
1395 * Called upon load.
1396 *
1397 * @api private
1398 */
1399
1400 Request.prototype.onLoad = function(){
1401 var data;
1402 try {
1403 var contentType;
1404 try {
1405 contentType = this.xhr.getResponseHeader('Content-Type');
1406 } catch (e) {}
1407 if (contentType === 'application/octet-stream') {
1408 data = this.xhr.response;
1409 } else {
1410 if (!this.supportsBinary) {
1411 data = this.xhr.responseText;
1412 } else {
1413 data = 'ok';
1414 }
1415 }
1416 } catch (e) {
1417 this.onError(e);
1418 }
1419 if (null != data) {
1420 this.onData(data);
1421 }
1422 };
1423
1424 /**
1425 * Check if it has XDomainRequest.
1426 *
1427 * @api private
1428 */
1429
1430 Request.prototype.hasXDR = function(){
1431 return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR;
1432 };
1433
1434 /**
1435 * Aborts the request.
1436 *
1437 * @api public
1438 */
1439
1440 Request.prototype.abort = function(){
1441 this.cleanup();
1442 };
1443
1444 /**
1445 * Aborts pending requests when unloading the window. This is needed to prevent
1446 * memory leaks (e.g. when using IE) and to ensure that no spurious error is
1447 * emitted.
1448 */
1449
1450 if (global.document) {
1451 Request.requestsCount = 0;
1452 Request.requests = {};
1453 if (global.attachEvent) {
1454 global.attachEvent('onunload', unloadHandler);
1455 } else if (global.addEventListener) {
1456 global.addEventListener('beforeunload', unloadHandler);
1457 }
1458 }
1459
1460 function unloadHandler() {
1461 for (var i in Request.requests) {
1462 if (Request.requests.hasOwnProperty(i)) {
1463 Request.requests[i].abort();
1464 }
1465 }
1466 }
1467
1468 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1469 },{"./polling":8,"component-emitter":12,"component-inherit":13,"debug":14,"xmlhttprequest":10}],8:[function(_dereq_,mod,exports){
1470 /**
1471 * Mod dependencies.
1472 */
1473
1474 var Transport = _dereq_('../transport');
1475 var parseqs = _dereq_('parseqs');
1476 var parser = _dereq_('engine.io-parser');
1477 var inherit = _dereq_('component-inherit');
1478 var debug = _dereq_('debug')('engine.io-client:polling');
1479
1480 /**
1481 * Mod exports.
1482 */
1483
1484 mod.exports = Polling;
1485
1486 /**
1487 * Is XHR2 supported?
1488 */
1489
1490 var hasXHR2 = (function() {
1491 var XMLHttpRequest = _dereq_('xmlhttprequest');
1492 var xhr = new XMLHttpRequest({ agent: this.agent, xdomain: false });
1493 return null != xhr.responseType;
1494 })();
1495
1496 /**
1497 * Polling interface.
1498 *
1499 * @param {Object} opts
1500 * @api private
1501 */
1502
1503 function Polling(opts){
1504 var forceBase64 = (opts && opts.forceBase64);
1505 if (!hasXHR2 || forceBase64) {
1506 this.supportsBinary = false;
1507 }
1508 Transport.call(this, opts);
1509 }
1510
1511 /**
1512 * Inherits from Transport.
1513 */
1514
1515 inherit(Polling, Transport);
1516
1517 /**
1518 * Transport name.
1519 */
1520
1521 Polling.prototype.name = 'polling';
1522
1523 /**
1524 * Opens the socket (triggers polling). We write a PING message to determine
1525 * when the transport is open.
1526 *
1527 * @api private
1528 */
1529
1530 Polling.prototype.doOpen = function(){
1531 this.poll();
1532 };
1533
1534 /**
1535 * Pauses polling.
1536 *
1537 * @param {Function} callback upon buffers are flushed and transport is paused
1538 * @api private
1539 */
1540
1541 Polling.prototype.pause = function(onPause){
1542 var pending = 0;
1543 var self = this;
1544
1545 this.readyState = 'pausing';
1546
1547 function pause(){
1548 debug('paused');
1549 self.readyState = 'paused';
1550 onPause();
1551 }
1552
1553 if (this.polling || !this.writable) {
1554 var total = 0;
1555
1556 if (this.polling) {
1557 debug('we are currently polling - waiting to pause');
1558 total++;
1559 this.once('pollComplete', function(){
1560 debug('pre-pause polling complete');
1561 --total || pause();
1562 });
1563 }
1564
1565 if (!this.writable) {
1566 debug('we are currently writing - waiting to pause');
1567 total++;
1568 this.once('drain', function(){
1569 debug('pre-pause writing complete');
1570 --total || pause();
1571 });
1572 }
1573 } else {
1574 pause();
1575 }
1576 };
1577
1578 /**
1579 * Starts polling cycle.
1580 *
1581 * @api public
1582 */
1583
1584 Polling.prototype.poll = function(){
1585 debug('polling');
1586 this.polling = true;
1587 this.doPoll();
1588 this.emit('poll');
1589 };
1590
1591 /**
1592 * Overloads onData to detect payloads.
1593 *
1594 * @api private
1595 */
1596
1597 Polling.prototype.onData = function(data){
1598 var self = this;
1599 debug('polling got data %s', data);
1600 var callback = function(packet, index, total) {
1601 // if its the first message we consider the transport open
1602 if ('opening' == self.readyState) {
1603 self.onOpen();
1604 }
1605
1606 // if its a close packet, we close the ongoing requests
1607 if ('close' == packet.type) {
1608 self.onClose();
1609 return false;
1610 }
1611
1612 // otherwise bypass onData and handle the message
1613 self.onPacket(packet);
1614 };
1615
1616 // decode payload
1617 parser.decodePayload(data, this.socket.binaryType, callback);
1618
1619 // if an event did not trigger closing
1620 if ('closed' != this.readyState) {
1621 // if we got data we're not polling
1622 this.polling = false;
1623 this.emit('pollComplete');
1624
1625 if ('open' == this.readyState) {
1626 this.poll();
1627 } else {
1628 debug('ignoring poll - transport state "%s"', this.readyState);
1629 }
1630 }
1631 };
1632
1633 /**
1634 * For polling, send a close packet.
1635 *
1636 * @api private
1637 */
1638
1639 Polling.prototype.doClose = function(){
1640 var self = this;
1641
1642 function close(){
1643 debug('writing close packet');
1644 self.write([{ type: 'close' }]);
1645 }
1646
1647 if ('open' == this.readyState) {
1648 debug('transport open - closing');
1649 close();
1650 } else {
1651 // in case we're trying to close while
1652 // handshaking is in progress (GH-164)
1653 debug('transport not open - deferring close');
1654 this.once('open', close);
1655 }
1656 };
1657
1658 /**
1659 * Writes a packets payload.
1660 *
1661 * @param {Array} data packets
1662 * @param {Function} drain callback
1663 * @api private
1664 */
1665
1666 Polling.prototype.write = function(packets){
1667 var self = this;
1668 this.writable = false;
1669 var callbackfn = function() {
1670 self.writable = true;
1671 self.emit('drain');
1672 };
1673
1674 var self = this;
1675 parser.encodePayload(packets, this.supportsBinary, function(data) {
1676 self.doWrite(data, callbackfn);
1677 });
1678 };
1679
1680 /**
1681 * Generates uri for connection.
1682 *
1683 * @api private
1684 */
1685
1686 Polling.prototype.uri = function(){
1687 var query = this.query || {};
1688 var schema = this.secure ? 'https' : 'http';
1689 var port = '';
1690
1691 // cache busting is forced
1692 if (false !== this.timestampRequests) {
1693 query[this.timestampParam] = +new Date + '-' + Transport.timestamps++;
1694 }
1695
1696 if (!this.supportsBinary && !query.sid) {
1697 query.b64 = 1;
1698 }
1699
1700 query = parseqs.encode(query);
1701
1702 // avoid port if default for schema
1703 if (this.port && (('https' == schema && this.port != 443) ||
1704 ('http' == schema && this.port != 80))) {
1705 port = ':' + this.port;
1706 }
1707
1708 // prepend ? to query
1709 if (query.length) {
1710 query = '?' + query;
1711 }
1712
1713 return schema + '://' + this.hostname + port + this.path + query;
1714 };
1715
1716 },{"../transport":4,"component-inherit":13,"debug":14,"engine.io-parser":15,"parseqs":25,"xmlhttprequest":10}],9:[function(_dereq_,mod,exports){
1717 /**
1718 * Mod dependencies.
1719 */
1720
1721 var Transport = _dereq_('../transport');
1722 var parser = _dereq_('engine.io-parser');
1723 var parseqs = _dereq_('parseqs');
1724 var inherit = _dereq_('component-inherit');
1725 var debug = _dereq_('debug')('engine.io-client:websocket');
1726
1727 /**
1728 * `ws` exposes a WebSocket-compatible interface in
1729 * Node, or the `WebSocket` or `MozWebSocket` globals
1730 * in the browser.
1731 */
1732
1733 var WebSocket = _dereq_('ws');
1734
1735 /**
1736 * Mod exports.
1737 */
1738
1739 mod.exports = WS;
1740
1741 /**
1742 * WebSocket transport constructor.
1743 *
1744 * @api {Object} connection options
1745 * @api public
1746 */
1747
1748 function WS(opts){
1749 var forceBase64 = (opts && opts.forceBase64);
1750 if (forceBase64) {
1751 this.supportsBinary = false;
1752 }
1753 Transport.call(this, opts);
1754 }
1755
1756 /**
1757 * Inherits from Transport.
1758 */
1759
1760 inherit(WS, Transport);
1761
1762 /**
1763 * Transport name.
1764 *
1765 * @api public
1766 */
1767
1768 WS.prototype.name = 'websocket';
1769
1770 /*
1771 * WebSockets support binary
1772 */
1773
1774 WS.prototype.supportsBinary = true;
1775
1776 /**
1777 * Opens socket.
1778 *
1779 * @api private
1780 */
1781
1782 WS.prototype.doOpen = function(){
1783 if (!this.check()) {
1784 // let probe timeout
1785 return;
1786 }
1787
1788 var self = this;
1789 var uri = this.uri();
1790 var protocols = void(0);
1791 var opts = { agent: this.agent };
1792
1793 this.ws = new WebSocket(uri, protocols, opts);
1794
1795 if (this.ws.binaryType === undefined) {
1796 this.supportsBinary = false;
1797 }
1798
1799 this.ws.binaryType = 'arraybuffer';
1800 this.addEventListeners();
1801 };
1802
1803 /**
1804 * Adds event listeners to the socket
1805 *
1806 * @api private
1807 */
1808
1809 WS.prototype.addEventListeners = function(){
1810 var self = this;
1811
1812 this.ws.onopen = function(){
1813 self.onOpen();
1814 };
1815 this.ws.onclose = function(){
1816 self.onClose();
1817 };
1818 this.ws.onmessage = function(ev){
1819 self.onData(ev.data);
1820 };
1821 this.ws.onerror = function(e){
1822 self.onError('websocket error', e);
1823 };
1824 };
1825
1826 /**
1827 * Override `onData` to use a timer on iOS.
1828 * See: https://gist.github.com/mloughran/2052006
1829 *
1830 * @api private
1831 */
1832
1833 if ('undefined' != typeof navigator
1834 && /iPad|iPhone|iPod/i.test(navigator.userAgent)) {
1835 WS.prototype.onData = function(data){
1836 var self = this;
1837 setTimeout(function(){
1838 Transport.prototype.onData.call(self, data);
1839 }, 0);
1840 };
1841 }
1842
1843 /**
1844 * Writes data to socket.
1845 *
1846 * @param {Array} array of packets.
1847 * @api private
1848 */
1849
1850 WS.prototype.write = function(packets){
1851 var self = this;
1852 this.writable = false;
1853 // encodePacket efficient as it uses WS framing
1854 // no need for encodePayload
1855 for (var i = 0, l = packets.length; i < l; i++) {
1856 parser.encodePacket(packets[i], this.supportsBinary, function(data) {
1857 //Sometimes the websocket has already been closed but the browser didn't
1858 //have a chance of informing us about it yet, in that case send will
1859 //throw an error
1860 try {
1861 self.ws.send(data);
1862 } catch (e){
1863 debug('websocket closed before onclose event');
1864 }
1865 });
1866 }
1867
1868 function ondrain() {
1869 self.writable = true;
1870 self.emit('drain');
1871 }
1872 // fake drain
1873 // defer to next tick to allow Socket to clear writeBuffer
1874 setTimeout(ondrain, 0);
1875 };
1876
1877 /**
1878 * Called upon close
1879 *
1880 * @api private
1881 */
1882
1883 WS.prototype.onClose = function(){
1884 Transport.prototype.onClose.call(this);
1885 };
1886
1887 /**
1888 * Closes socket.
1889 *
1890 * @api private
1891 */
1892
1893 WS.prototype.doClose = function(){
1894 if (typeof this.ws !== 'undefined') {
1895 this.ws.close();
1896 }
1897 };
1898
1899 /**
1900 * Generates uri for connection.
1901 *
1902 * @api private
1903 */
1904
1905 WS.prototype.uri = function(){
1906 var query = this.query || {};
1907 var schema = this.secure ? 'wss' : 'ws';
1908 var port = '';
1909
1910 // avoid port if default for schema
1911 if (this.port && (('wss' == schema && this.port != 443)
1912 || ('ws' == schema && this.port != 80))) {
1913 port = ':' + this.port;
1914 }
1915
1916 // append timestamp to URI
1917 if (this.timestampRequests) {
1918 query[this.timestampParam] = +new Date;
1919 }
1920
1921 // communicate binary support capabilities
1922 if (!this.supportsBinary) {
1923 query.b64 = 1;
1924 }
1925
1926 query = parseqs.encode(query);
1927
1928 // prepend ? to query
1929 if (query.length) {
1930 query = '?' + query;
1931 }
1932
1933 return schema + '://' + this.hostname + port + this.path + query;
1934 };
1935
1936 /**
1937 * Feature detection for WebSocket.
1938 *
1939 * @return {Boolean} whether this transport is available.
1940 * @api public
1941 */
1942
1943 WS.prototype.check = function(){
1944 return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
1945 };
1946
1947 },{"../transport":4,"component-inherit":13,"debug":14,"engine.io-parser":15,"parseqs":25,"ws":27}],10:[function(_dereq_,mod,exports){
1948 // browser shim for xmlhttprequest mod
1949 var hasCORS = _dereq_('has-cors');
1950
1951 mod.exports = function(opts) {
1952 var xdomain = opts.xdomain;
1953
1954 // scheme must be same when usign XDomainRequest
1955 // http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
1956 var xscheme = opts.xscheme;
1957
1958 // XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default.
1959 // https://github.com/Automattic/engine.io-client/pull/217
1960 var enablesXDR = opts.enablesXDR;
1961
1962 // Use XDomainRequest for IE8 if enablesXDR is true
1963 // because loading bar keeps flashing when using jsonp-polling
1964 // https://github.com/yujiosaka/socke.io-ie8-loading-example
1965 try {
1966 if ('undefined' != typeof XDomainRequest && !xscheme && enablesXDR) {
1967 return new XDomainRequest();
1968 }
1969 } catch (e) { }
1970
1971 // XMLHttpRequest can be disabled on IE
1972 try {
1973 if ('undefined' != typeof XMLHttpRequest && (!xdomain || hasCORS)) {
1974 return new XMLHttpRequest();
1975 }
1976 } catch (e) { }
1977
1978 if (!xdomain) {
1979 try {
1980 return new ActiveXObject('Microsoft.XMLHTTP');
1981 } catch(e) { }
1982 }
1983 }
1984
1985 },{"has-cors":21}],11:[function(_dereq_,mod,exports){
1986 (function (global){
1987 /**
1988 * Create a blob builder even when vendor prefixes exist
1989 */
1990
1991 var BlobBuilder = global.BlobBuilder
1992 || global.WebKitBlobBuilder
1993 || global.MSBlobBuilder
1994 || global.MozBlobBuilder;
1995
1996 /**
1997 * Check if Blob constructor is supported
1998 */
1999
2000 var blobSupported = (function() {
2001 try {
2002 var b = new Blob(['hi']);
2003 return b.size == 2;
2004 } catch(e) {
2005 return false;
2006 }
2007 })();
2008
2009 /**
2010 * Check if BlobBuilder is supported
2011 */
2012
2013 var blobBuilderSupported = BlobBuilder
2014 && BlobBuilder.prototype.append
2015 && BlobBuilder.prototype.getBlob;
2016
2017 function BlobBuilderConstructor(ary, options) {
2018 options = options || {};
2019
2020 var bb = new BlobBuilder();
2021 for (var i = 0; i < ary.length; i++) {
2022 bb.append(ary[i]);
2023 }
2024 return (options.type) ? bb.getBlob(options.type) : bb.getBlob();
2025 };
2026
2027 mod.exports = (function() {
2028 if (blobSupported) {
2029 return global.Blob;
2030 } else if (blobBuilderSupported) {
2031 return BlobBuilderConstructor;
2032 } else {
2033 return undefined;
2034 }
2035 })();
2036
2037 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2038 },{}],12:[function(_dereq_,mod,exports){
2039
2040 /**
2041 * Expose `Emitter`.
2042 */
2043
2044 mod.exports = Emitter;
2045
2046 /**
2047 * Initialize a new `Emitter`.
2048 *
2049 * @api public
2050 */
2051
2052 function Emitter(obj) {
2053 if (obj) return mixin(obj);
2054 };
2055
2056 /**
2057 * Mixin the emitter properties.
2058 *
2059 * @param {Object} obj
2060 * @return {Object}
2061 * @api private
2062 */
2063
2064 function mixin(obj) {
2065 for (var key in Emitter.prototype) {
2066 obj[key] = Emitter.prototype[key];
2067 }
2068 return obj;
2069 }
2070
2071 /**
2072 * Listen on the given `event` with `fn`.
2073 *
2074 * @param {String} event
2075 * @param {Function} fn
2076 * @return {Emitter}
2077 * @api public
2078 */
2079
2080 Emitter.prototype.on =
2081 Emitter.prototype.addEventListener = function(event, fn){
2082 this._callbacks = this._callbacks || {};
2083 (this._callbacks[event] = this._callbacks[event] || [])
2084 .push(fn);
2085 return this;
2086 };
2087
2088 /**
2089 * Adds an `event` listener that will be invoked a single
2090 * time then automatically removed.
2091 *
2092 * @param {String} event
2093 * @param {Function} fn
2094 * @return {Emitter}
2095 * @api public
2096 */
2097
2098 Emitter.prototype.once = function(event, fn){
2099 var self = this;
2100 this._callbacks = this._callbacks || {};
2101
2102 function on() {
2103 self.off(event, on);
2104 fn.apply(this, arguments);
2105 }
2106
2107 on.fn = fn;
2108 this.on(event, on);
2109 return this;
2110 };
2111
2112 /**
2113 * Remove the given callback for `event` or all
2114 * registered callbacks.
2115 *
2116 * @param {String} event
2117 * @param {Function} fn
2118 * @return {Emitter}
2119 * @api public
2120 */
2121
2122 Emitter.prototype.off =
2123 Emitter.prototype.removeListener =
2124 Emitter.prototype.removeAllListeners =
2125 Emitter.prototype.removeEventListener = function(event, fn){
2126 this._callbacks = this._callbacks || {};
2127
2128 // all
2129 if (0 == arguments.length) {
2130 this._callbacks = {};
2131 return this;
2132 }
2133
2134 // specific event
2135 var callbacks = this._callbacks[event];
2136 if (!callbacks) return this;
2137
2138 // remove all handlers
2139 if (1 == arguments.length) {
2140 delete this._callbacks[event];
2141 return this;
2142 }
2143
2144 // remove specific handler
2145 var cb;
2146 for (var i = 0; i < callbacks.length; i++) {
2147 cb = callbacks[i];
2148 if (cb === fn || cb.fn === fn) {
2149 callbacks.splice(i, 1);
2150 break;
2151 }
2152 }
2153 return this;
2154 };
2155
2156 /**
2157 * Emit `event` with the given args.
2158 *
2159 * @param {String} event
2160 * @param {Mixed} ...
2161 * @return {Emitter}
2162 */
2163
2164 Emitter.prototype.emit = function(event){
2165 this._callbacks = this._callbacks || {};
2166 var args = [].slice.call(arguments, 1)
2167 , callbacks = this._callbacks[event];
2168
2169 if (callbacks) {
2170 callbacks = callbacks.slice(0);
2171 for (var i = 0, len = callbacks.length; i < len; ++i) {
2172 callbacks[i].apply(this, args);
2173 }
2174 }
2175
2176 return this;
2177 };
2178
2179 /**
2180 * Return array of callbacks for `event`.
2181 *
2182 * @param {String} event
2183 * @return {Array}
2184 * @api public
2185 */
2186
2187 Emitter.prototype.listeners = function(event){
2188 this._callbacks = this._callbacks || {};
2189 return this._callbacks[event] || [];
2190 };
2191
2192 /**
2193 * Check if this emitter has `event` handlers.
2194 *
2195 * @param {String} event
2196 * @return {Boolean}
2197 * @api public
2198 */
2199
2200 Emitter.prototype.hasListeners = function(event){
2201 return !! this.listeners(event).length;
2202 };
2203
2204 },{}],13:[function(_dereq_,mod,exports){
2205
2206 mod.exports = function(a, b){
2207 var fn = function(){};
2208 fn.prototype = b.prototype;
2209 a.prototype = new fn;
2210 a.prototype.constructor = a;
2211 };
2212 },{}],14:[function(_dereq_,mod,exports){
2213
2214 /**
2215 * Expose `debug()` as the mod.
2216 */
2217
2218 mod.exports = debug;
2219
2220 /**
2221 * Create a debugger with the given `name`.
2222 *
2223 * @param {String} name
2224 * @return {Type}
2225 * @api public
2226 */
2227
2228 function debug(name) {
2229 if (!debug.enabled(name)) return function(){};
2230
2231 return function(fmt){
2232 fmt = coerce(fmt);
2233
2234 var curr = new Date;
2235 var ms = curr - (debug[name] || curr);
2236 debug[name] = curr;
2237
2238 fmt = name
2239 + ' '
2240 + fmt
2241 + ' +' + debug.humanize(ms);
2242
2243 // This hackery is required for IE8
2244 // where `console.log` doesn't have 'apply'
2245 window.console
2246 && console.log
2247 && Function.prototype.apply.call(console.log, console, arguments);
2248 }
2249 }
2250
2251 /**
2252 * The currently active debug mode names.
2253 */
2254
2255 debug.names = [];
2256 debug.skips = [];
2257
2258 /**
2259 * Enables a debug mode by name. This can include modes
2260 * separated by a colon and wildcards.
2261 *
2262 * @param {String} name
2263 * @api public
2264 */
2265
2266 debug.enable = function(name) {
2267 try {
2268 localStorage.debug = name;
2269 } catch(e){}
2270
2271 var split = (name || '').split(/[\s,]+/)
2272 , len = split.length;
2273
2274 for (var i = 0; i < len; i++) {
2275 name = split[i].replace('*', '.*?');
2276 if (name[0] === '-') {
2277 debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
2278 }
2279 else {
2280 debug.names.push(new RegExp('^' + name + '$'));
2281 }
2282 }
2283 };
2284
2285 /**
2286 * Disable debug output.
2287 *
2288 * @api public
2289 */
2290
2291 debug.disable = function(){
2292 debug.enable('');
2293 };
2294
2295 /**
2296 * Humanize the given `ms`.
2297 *
2298 * @param {Number} m
2299 * @return {String}
2300 * @api private
2301 */
2302
2303 debug.humanize = function(ms) {
2304 var sec = 1000
2305 , min = 60 * 1000
2306 , hour = 60 * min;
2307
2308 if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
2309 if (ms >= min) return (ms / min).toFixed(1) + 'm';
2310 if (ms >= sec) return (ms / sec | 0) + 's';
2311 return ms + 'ms';
2312 };
2313
2314 /**
2315 * Returns true if the given mode name is enabled, false otherwise.
2316 *
2317 * @param {String} name
2318 * @return {Boolean}
2319 * @api public
2320 */
2321
2322 debug.enabled = function(name) {
2323 for (var i = 0, len = debug.skips.length; i < len; i++) {
2324 if (debug.skips[i].test(name)) {
2325 return false;
2326 }
2327 }
2328 for (var i = 0, len = debug.names.length; i < len; i++) {
2329 if (debug.names[i].test(name)) {
2330 return true;
2331 }
2332 }
2333 return false;
2334 };
2335
2336 /**
2337 * Coerce `val`.
2338 */
2339
2340 function coerce(val) {
2341 if (val instanceof Error) return val.stack || val.message;
2342 return val;
2343 }
2344
2345 // persist
2346
2347 try {
2348 if (window.localStorage) debug.enable(localStorage.debug);
2349 } catch(e){}
2350
2351 },{}],15:[function(_dereq_,mod,exports){
2352 (function (global){
2353 /**
2354 * Mod dependencies.
2355 */
2356
2357 var keys = _dereq_('./keys');
2358 var sliceBuffer = _dereq_('arraybuffer.slice');
2359 var base64encoder = _dereq_('base64-arraybuffer');
2360 var after = _dereq_('after');
2361 var utf8 = _dereq_('utf8');
2362
2363 /**
2364 * Check if we are running an android browser. That requires us to use
2365 * ArrayBuffer with polling transports...
2366 *
2367 * http://ghinda.net/jpeg-blob-ajax-android/
2368 */
2369
2370 var isAndroid = navigator.userAgent.match(/Android/i);
2371
2372 /**
2373 * Current protocol version.
2374 */
2375
2376 exports.protocol = 3;
2377
2378 /**
2379 * Packet types.
2380 */
2381
2382 var packets = exports.packets = {
2383 open: 0 // non-ws
2384 , close: 1 // non-ws
2385 , ping: 2
2386 , pong: 3
2387 , message: 4
2388 , upgrade: 5
2389 , noop: 6
2390 };
2391
2392 var packetslist = keys(packets);
2393
2394 /**
2395 * Premade error packet.
2396 */
2397
2398 var err = { type: 'error', data: 'parser error' };
2399
2400 /**
2401 * Create a blob api even for blob builder when vendor prefixes exist
2402 */
2403
2404 var Blob = _dereq_('blob');
2405
2406 /**
2407 * Encodes a packet.
2408 *
2409 * <packet type id> [ <data> ]
2410 *
2411 * Example:
2412 *
2413 * 5hello world
2414 * 3
2415 * 4
2416 *
2417 * Binary is encoded in an identical principle
2418 *
2419 * @api private
2420 */
2421
2422 exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
2423 if ('function' == typeof supportsBinary) {
2424 callback = supportsBinary;
2425 supportsBinary = false;
2426 }
2427
2428 if ('function' == typeof utf8encode) {
2429 callback = utf8encode;
2430 utf8encode = null;
2431 }
2432
2433 var data = (packet.data === undefined)
2434 ? undefined
2435 : packet.data.buffer || packet.data;
2436
2437 if (global.ArrayBuffer && data instanceof ArrayBuffer) {
2438 return encodeArrayBuffer(packet, supportsBinary, callback);
2439 } else if (Blob && data instanceof global.Blob) {
2440 return encodeBlob(packet, supportsBinary, callback);
2441 }
2442
2443 // Sending data as a utf-8 string
2444 var encoded = packets[packet.type];
2445
2446 // data fragment is optional
2447 if (undefined !== packet.data) {
2448 encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
2449 }
2450
2451 return callback('' + encoded);
2452
2453 };
2454
2455 /**
2456 * Encode packet helpers for binary types
2457 */
2458
2459 function encodeArrayBuffer(packet, supportsBinary, callback) {
2460 if (!supportsBinary) {
2461 return exports.encodeBase64Packet(packet, callback);
2462 }
2463
2464 var data = packet.data;
2465 var contentArray = new Uint8Array(data);
2466 var resultBuffer = new Uint8Array(1 + data.byteLength);
2467
2468 resultBuffer[0] = packets[packet.type];
2469 for (var i = 0; i < contentArray.length; i++) {
2470 resultBuffer[i+1] = contentArray[i];
2471 }
2472
2473 return callback(resultBuffer.buffer);
2474 }
2475
2476 function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) {
2477 if (!supportsBinary) {
2478 return exports.encodeBase64Packet(packet, callback);
2479 }
2480
2481 var fr = new FileReader();
2482 fr.onload = function() {
2483 packet.data = fr.result;
2484 exports.encodePacket(packet, supportsBinary, true, callback);
2485 };
2486 return fr.readAsArrayBuffer(packet.data);
2487 }
2488
2489 function encodeBlob(packet, supportsBinary, callback) {
2490 if (!supportsBinary) {
2491 return exports.encodeBase64Packet(packet, callback);
2492 }
2493
2494 if (isAndroid) {
2495 return encodeBlobAsArrayBuffer(packet, supportsBinary, callback);
2496 }
2497
2498 var length = new Uint8Array(1);
2499 length[0] = packets[packet.type];
2500 var blob = new Blob([length.buffer, packet.data]);
2501
2502 return callback(blob);
2503 }
2504
2505 /**
2506 * Encodes a packet with binary data in a base64 string
2507 *
2508 * @param {Object} packet, has `type` and `data`
2509 * @return {String} base64 encoded message
2510 */
2511
2512 exports.encodeBase64Packet = function(packet, callback) {
2513 var message = 'b' + exports.packets[packet.type];
2514 if (Blob && packet.data instanceof Blob) {
2515 var fr = new FileReader();
2516 fr.onload = function() {
2517 var b64 = fr.result.split(',')[1];
2518 callback(message + b64);
2519 };
2520 return fr.readAsDataURL(packet.data);
2521 }
2522
2523 var b64data;
2524 try {
2525 b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data));
2526 } catch (e) {
2527 // iPhone Safari doesn't let you apply with typed arrays
2528 var typed = new Uint8Array(packet.data);
2529 var basic = new Array(typed.length);
2530 for (var i = 0; i < typed.length; i++) {
2531 basic[i] = typed[i];
2532 }
2533 b64data = String.fromCharCode.apply(null, basic);
2534 }
2535 message += global.btoa(b64data);
2536 return callback(message);
2537 };
2538
2539 /**
2540 * Decodes a packet. Changes format to Blob if requested.
2541 *
2542 * @return {Object} with `type` and `data` (if any)
2543 * @api private
2544 */
2545
2546 exports.decodePacket = function (data, binaryType, utf8decode) {
2547 // String data
2548 if (typeof data == 'string' || data === undefined) {
2549 if (data.charAt(0) == 'b') {
2550 return exports.decodeBase64Packet(data.substr(1), binaryType);
2551 }
2552
2553 if (utf8decode) {
2554 try {
2555 data = utf8.decode(data);
2556 } catch (e) {
2557 return err;
2558 }
2559 }
2560 var type = data.charAt(0);
2561
2562 if (Number(type) != type || !packetslist[type]) {
2563 return err;
2564 }
2565
2566 if (data.length > 1) {
2567 return { type: packetslist[type], data: data.substring(1) };
2568 } else {
2569 return { type: packetslist[type] };
2570 }
2571 }
2572
2573 var asArray = new Uint8Array(data);
2574 var type = asArray[0];
2575 var rest = sliceBuffer(data, 1);
2576 if (Blob && binaryType === 'blob') {
2577 rest = new Blob([rest]);
2578 }
2579 return { type: packetslist[type], data: rest };
2580 };
2581
2582 /**
2583 * Decodes a packet encoded in a base64 string
2584 *
2585 * @param {String} base64 encoded message
2586 * @return {Object} with `type` and `data` (if any)
2587 */
2588
2589 exports.decodeBase64Packet = function(msg, binaryType) {
2590 var type = packetslist[msg.charAt(0)];
2591 if (!global.ArrayBuffer) {
2592 return { type: type, data: { base64: true, data: msg.substr(1) } };
2593 }
2594
2595 var data = base64encoder.decode(msg.substr(1));
2596
2597 if (binaryType === 'blob' && Blob) {
2598 data = new Blob([data]);
2599 }
2600
2601 return { type: type, data: data };
2602 };
2603
2604 /**
2605 * Encodes multiple messages (payload).
2606 *
2607 * <length>:data
2608 *
2609 * Example:
2610 *
2611 * 11:hello world2:hi
2612 *
2613 * If any contents are binary, they will be encoded as base64 strings. Base64
2614 * encoded strings are marked with a b before the length specifier
2615 *
2616 * @param {Array} packets
2617 * @api private
2618 */
2619
2620 exports.encodePayload = function (packets, supportsBinary, callback) {
2621 if (typeof supportsBinary == 'function') {
2622 callback = supportsBinary;
2623 supportsBinary = null;
2624 }
2625
2626 if (supportsBinary) {
2627 if (Blob && !isAndroid) {
2628 return exports.encodePayloadAsBlob(packets, callback);
2629 }
2630
2631 return exports.encodePayloadAsArrayBuffer(packets, callback);
2632 }
2633
2634 if (!packets.length) {
2635 return callback('0:');
2636 }
2637
2638 function setLengthHeader(message) {
2639 return message.length + ':' + message;
2640 }
2641
2642 function encodeOne(packet, doneCallback) {
2643 exports.encodePacket(packet, supportsBinary, true, function(message) {
2644 doneCallback(null, setLengthHeader(message));
2645 });
2646 }
2647
2648 map(packets, encodeOne, function(err, results) {
2649 return callback(results.join(''));
2650 });
2651 };
2652
2653 /**
2654 * Async array map using after
2655 */
2656
2657 function map(ary, each, done) {
2658 var result = new Array(ary.length);
2659 var next = after(ary.length, done);
2660
2661 var eachWithIndex = function(i, el, cb) {
2662 each(el, function(error, msg) {
2663 result[i] = msg;
2664 cb(error, result);
2665 });
2666 };
2667
2668 for (var i = 0; i < ary.length; i++) {
2669 eachWithIndex(i, ary[i], next);
2670 }
2671 }
2672
2673 /*
2674 * Decodes data when a payload is maybe expected. Possible binary contents are
2675 * decoded from their base64 representation
2676 *
2677 * @param {String} data, callback method
2678 * @api public
2679 */
2680
2681 exports.decodePayload = function (data, binaryType, callback) {
2682 if (typeof data != 'string') {
2683 return exports.decodePayloadAsBinary(data, binaryType, callback);
2684 }
2685
2686 if (typeof binaryType === 'function') {
2687 callback = binaryType;
2688 binaryType = null;
2689 }
2690
2691 var packet;
2692 if (data == '') {
2693 // parser error - ignoring payload
2694 return callback(err, 0, 1);
2695 }
2696
2697 var length = ''
2698 , n, msg;
2699
2700 for (var i = 0, l = data.length; i < l; i++) {
2701 var chr = data.charAt(i);
2702
2703 if (':' != chr) {
2704 length += chr;
2705 } else {
2706 if ('' == length || (length != (n = Number(length)))) {
2707 // parser error - ignoring payload
2708 return callback(err, 0, 1);
2709 }
2710
2711 msg = data.substr(i + 1, n);
2712
2713 if (length != msg.length) {
2714 // parser error - ignoring payload
2715 return callback(err, 0, 1);
2716 }
2717
2718 if (msg.length) {
2719 packet = exports.decodePacket(msg, binaryType, true);
2720
2721 if (err.type == packet.type && err.data == packet.data) {
2722 // parser error in individual packet - ignoring payload
2723 return callback(err, 0, 1);
2724 }
2725
2726 var ret = callback(packet, i + n, l);
2727 if (false === ret) return;
2728 }
2729
2730 // advance cursor
2731 i += n;
2732 length = '';
2733 }
2734 }
2735
2736 if (length != '') {
2737 // parser error - ignoring payload
2738 return callback(err, 0, 1);
2739 }
2740
2741 };
2742
2743 /**
2744 * Encodes multiple messages (payload) as binary.
2745 *
2746 * <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
2747 * 255><data>
2748 *
2749 * Example:
2750 * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
2751 *
2752 * @param {Array} packets
2753 * @return {ArrayBuffer} encoded payload
2754 * @api private
2755 */
2756
2757 exports.encodePayloadAsArrayBuffer = function(packets, callback) {
2758 if (!packets.length) {
2759 return callback(new ArrayBuffer(0));
2760 }
2761
2762 function encodeOne(packet, doneCallback) {
2763 exports.encodePacket(packet, true, true, function(data) {
2764 return doneCallback(null, data);
2765 });
2766 }
2767
2768 map(packets, encodeOne, function(err, encodedPackets) {
2769 var totalLength = encodedPackets.reduce(function(acc, p) {
2770 var len;
2771 if (typeof p === 'string'){
2772 len = p.length;
2773 } else {
2774 len = p.byteLength;
2775 }
2776 return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2
2777 }, 0);
2778
2779 var resultArray = new Uint8Array(totalLength);
2780
2781 var bufferIndex = 0;
2782 encodedPackets.forEach(function(p) {
2783 var isString = typeof p === 'string';
2784 var ab = p;
2785 if (isString) {
2786 var view = new Uint8Array(p.length);
2787 for (var i = 0; i < p.length; i++) {
2788 view[i] = p.charCodeAt(i);
2789 }
2790 ab = view.buffer;
2791 }
2792
2793 if (isString) { // not true binary
2794 resultArray[bufferIndex++] = 0;
2795 } else { // true binary
2796 resultArray[bufferIndex++] = 1;
2797 }
2798
2799 var lenStr = ab.byteLength.toString();
2800 for (var i = 0; i < lenStr.length; i++) {
2801 resultArray[bufferIndex++] = parseInt(lenStr[i]);
2802 }
2803 resultArray[bufferIndex++] = 255;
2804
2805 var view = new Uint8Array(ab);
2806 for (var i = 0; i < view.length; i++) {
2807 resultArray[bufferIndex++] = view[i];
2808 }
2809 });
2810
2811 return callback(resultArray.buffer);
2812 });
2813 };
2814
2815 /**
2816 * Encode as Blob
2817 */
2818
2819 exports.encodePayloadAsBlob = function(packets, callback) {
2820 function encodeOne(packet, doneCallback) {
2821 exports.encodePacket(packet, true, true, function(encoded) {
2822 var binaryIdentifier = new Uint8Array(1);
2823 binaryIdentifier[0] = 1;
2824 if (typeof encoded === 'string') {
2825 var view = new Uint8Array(encoded.length);
2826 for (var i = 0; i < encoded.length; i++) {
2827 view[i] = encoded.charCodeAt(i);
2828 }
2829 encoded = view.buffer;
2830 binaryIdentifier[0] = 0;
2831 }
2832
2833 var len = (encoded instanceof ArrayBuffer)
2834 ? encoded.byteLength
2835 : encoded.size;
2836
2837 var lenStr = len.toString();
2838 var lengthAry = new Uint8Array(lenStr.length + 1);
2839 for (var i = 0; i < lenStr.length; i++) {
2840 lengthAry[i] = parseInt(lenStr[i]);
2841 }
2842 lengthAry[lenStr.length] = 255;
2843
2844 if (Blob) {
2845 var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]);
2846 doneCallback(null, blob);
2847 }
2848 });
2849 }
2850
2851 map(packets, encodeOne, function(err, results) {
2852 return callback(new Blob(results));
2853 });
2854 };
2855
2856 /*
2857 * Decodes data when a payload is maybe expected. Strings are decoded by
2858 * interpreting each byte as a key code for entries marked to start with 0. See
2859 * description of encodePayloadAsBinary
2860 *
2861 * @param {ArrayBuffer} data, callback method
2862 * @api public
2863 */
2864
2865 exports.decodePayloadAsBinary = function (data, binaryType, callback) {
2866 if (typeof binaryType === 'function') {
2867 callback = binaryType;
2868 binaryType = null;
2869 }
2870
2871 var bufferTail = data;
2872 var buffers = [];
2873
2874 var numberTooLong = false;
2875 while (bufferTail.byteLength > 0) {
2876 var tailArray = new Uint8Array(bufferTail);
2877 var isString = tailArray[0] === 0;
2878 var msgLength = '';
2879
2880 for (var i = 1; ; i++) {
2881 if (tailArray[i] == 255) break;
2882
2883 if (msgLength.length > 310) {
2884 numberTooLong = true;
2885 break;
2886 }
2887
2888 msgLength += tailArray[i];
2889 }
2890
2891 if(numberTooLong) return callback(err, 0, 1);
2892
2893 bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length);
2894 msgLength = parseInt(msgLength);
2895
2896 var msg = sliceBuffer(bufferTail, 0, msgLength);
2897 if (isString) {
2898 try {
2899 msg = String.fromCharCode.apply(null, new Uint8Array(msg));
2900 } catch (e) {
2901 // iPhone Safari doesn't let you apply to typed arrays
2902 var typed = new Uint8Array(msg);
2903 msg = '';
2904 for (var i = 0; i < typed.length; i++) {
2905 msg += String.fromCharCode(typed[i]);
2906 }
2907 }
2908 }
2909
2910 buffers.push(msg);
2911 bufferTail = sliceBuffer(bufferTail, msgLength);
2912 }
2913
2914 var total = buffers.length;
2915 buffers.forEach(function(buffer, i) {
2916 callback(exports.decodePacket(buffer, binaryType, true), i, total);
2917 });
2918 };
2919
2920 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2921 },{"./keys":16,"after":17,"arraybuffer.slice":18,"base64-arraybuffer":19,"blob":11,"utf8":20}],16:[function(_dereq_,mod,exports){
2922
2923 /**
2924 * Gets the keys for an object.
2925 *
2926 * @return {Array} keys
2927 * @api private
2928 */
2929
2930 mod.exports = Object.keys || function keys (obj){
2931 var arr = [];
2932 var has = Object.prototype.hasOwnProperty;
2933
2934 for (var i in obj) {
2935 if (has.call(obj, i)) {
2936 arr.push(i);
2937 }
2938 }
2939 return arr;
2940 };
2941
2942 },{}],17:[function(_dereq_,mod,exports){
2943 mod.exports = after
2944
2945 function after(count, callback, err_cb) {
2946 var bail = false
2947 err_cb = err_cb || noop
2948 proxy.count = count
2949
2950 return (count === 0) ? callback() : proxy
2951
2952 function proxy(err, result) {
2953 if (proxy.count <= 0) {
2954 throw new Error('after called too many times')
2955 }
2956 --proxy.count
2957
2958 // after first error, rest are passed to err_cb
2959 if (err) {
2960 bail = true
2961 callback(err)
2962 // future error callbacks will go to error handler
2963 callback = err_cb
2964 } else if (proxy.count === 0 && !bail) {
2965 callback(null, result)
2966 }
2967 }
2968 }
2969
2970 function noop() {}
2971
2972 },{}],18:[function(_dereq_,mod,exports){
2973 /**
2974 * An abstraction for slicing an arraybuffer even when
2975 * ArrayBuffer.prototype.slice is not supported
2976 *
2977 * @api public
2978 */
2979
2980 mod.exports = function(arraybuffer, start, end) {
2981 var bytes = arraybuffer.byteLength;
2982 start = start || 0;
2983 end = end || bytes;
2984
2985 if (arraybuffer.slice) { return arraybuffer.slice(start, end); }
2986
2987 if (start < 0) { start += bytes; }
2988 if (end < 0) { end += bytes; }
2989 if (end > bytes) { end = bytes; }
2990
2991 if (start >= bytes || start >= end || bytes === 0) {
2992 return new ArrayBuffer(0);
2993 }
2994
2995 var abv = new Uint8Array(arraybuffer);
2996 var result = new Uint8Array(end - start);
2997 for (var i = start, ii = 0; i < end; i++, ii++) {
2998 result[ii] = abv[i];
2999 }
3000 return result.buffer;
3001 };
3002
3003 },{}],19:[function(_dereq_,mod,exports){
3004 /*
3005 * base64-arraybuffer
3006 * https://github.com/niklasvh/base64-arraybuffer
3007 *
3008 * Copyright (c) 2012 Niklas von Hertzen
3009 * Licensed under the MIT license.
3010 */
3011 (function(chars){
3012 "use strict";
3013
3014 exports.encode = function(arraybuffer) {
3015 var bytes = new Uint8Array(arraybuffer),
3016 i, len = bytes.length, base64 = "";
3017
3018 for (i = 0; i < len; i+=3) {
3019 base64 += chars[bytes[i] >> 2];
3020 base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
3021 base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
3022 base64 += chars[bytes[i + 2] & 63];
3023 }
3024
3025 if ((len % 3) === 2) {
3026 base64 = base64.substring(0, base64.length - 1) + "=";
3027 } else if (len % 3 === 1) {
3028 base64 = base64.substring(0, base64.length - 2) + "==";
3029 }
3030
3031 return base64;
3032 };
3033
3034 exports.decode = function(base64) {
3035 var bufferLength = base64.length * 0.75,
3036 len = base64.length, i, p = 0,
3037 encoded1, encoded2, encoded3, encoded4;
3038
3039 if (base64[base64.length - 1] === "=") {
3040 bufferLength--;
3041 if (base64[base64.length - 2] === "=") {
3042 bufferLength--;
3043 }
3044 }
3045
3046 var arraybuffer = new ArrayBuffer(bufferLength),
3047 bytes = new Uint8Array(arraybuffer);
3048
3049 for (i = 0; i < len; i+=4) {
3050 encoded1 = chars.indexOf(base64[i]);
3051 encoded2 = chars.indexOf(base64[i+1]);
3052 encoded3 = chars.indexOf(base64[i+2]);
3053 encoded4 = chars.indexOf(base64[i+3]);
3054
3055 bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
3056 bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
3057 bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
3058 }
3059
3060 return arraybuffer;
3061 };
3062 })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
3063
3064 },{}],20:[function(_dereq_,mod,exports){
3065 (function (global){
3066 /*! http://mths.be/utf8js v2.0.0 by @mathias */
3067 ;(function(root) {
3068
3069 // Detect free variables `exports`
3070 var freeExports = typeof exports == 'object' && exports;
3071
3072 // Detect free variable `mod`
3073 var freeMod = typeof mod == 'object' && mod &&
3074 mod.exports == freeExports && mod;
3075
3076 // Detect free variable `global`, from Node.js or Browserified code,
3077 // and use it as `root`
3078 var freeGlobal = typeof global == 'object' && global;
3079 if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
3080 root = freeGlobal;
3081 }
3082
3083 /*--------------------------------------------------------------------------*/
3084
3085 var stringFromCharCode = String.fromCharCode;
3086
3087 // Taken from http://mths.be/punycode
3088 function ucs2decode(string) {
3089 var output = [];
3090 var counter = 0;
3091 var length = string.length;
3092 var value;
3093 var extra;
3094 while (counter < length) {
3095 value = string.charCodeAt(counter++);
3096 if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
3097 // high surrogate, and there is a next character
3098 extra = string.charCodeAt(counter++);
3099 if ((extra & 0xFC00) == 0xDC00) { // low surrogate
3100 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
3101 } else {
3102 // unmatched surrogate; only append this code unit, in case the next
3103 // code unit is the high surrogate of a surrogate pair
3104 output.push(value);
3105 counter--;
3106 }
3107 } else {
3108 output.push(value);
3109 }
3110 }
3111 return output;
3112 }
3113
3114 // Taken from http://mths.be/punycode
3115 function ucs2encode(array) {
3116 var length = array.length;
3117 var index = -1;
3118 var value;
3119 var output = '';
3120 while (++index < length) {
3121 value = array[index];
3122 if (value > 0xFFFF) {
3123 value -= 0x10000;
3124 output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
3125 value = 0xDC00 | value & 0x3FF;
3126 }
3127 output += stringFromCharCode(value);
3128 }
3129 return output;
3130 }
3131
3132 /*--------------------------------------------------------------------------*/
3133
3134 function createByte(codePoint, shift) {
3135 return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
3136 }
3137
3138 function encodeCodePoint(codePoint) {
3139 if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
3140 return stringFromCharCode(codePoint);
3141 }
3142 var symbol = '';
3143 if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
3144 symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
3145 }
3146 else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
3147 symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
3148 symbol += createByte(codePoint, 6);
3149 }
3150 else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
3151 symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
3152 symbol += createByte(codePoint, 12);
3153 symbol += createByte(codePoint, 6);
3154 }
3155 symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
3156 return symbol;
3157 }
3158
3159 function utf8encode(string) {
3160 var codePoints = ucs2decode(string);
3161
3162 // console.log(JSON.stringify(codePoints.map(function(x) {
3163 // return 'U+' + x.toString(16).toUpperCase();
3164 // })));
3165
3166 var length = codePoints.length;
3167 var index = -1;
3168 var codePoint;
3169 var byteString = '';
3170 while (++index < length) {
3171 codePoint = codePoints[index];
3172 byteString += encodeCodePoint(codePoint);
3173 }
3174 return byteString;
3175 }
3176
3177 /*--------------------------------------------------------------------------*/
3178
3179 function readContinuationByte() {
3180 if (byteIndex >= byteCount) {
3181 throw Error('Invalid byte index');
3182 }
3183
3184 var continuationByte = byteArray[byteIndex] & 0xFF;
3185 byteIndex++;
3186
3187 if ((continuationByte & 0xC0) == 0x80) {
3188 return continuationByte & 0x3F;
3189 }
3190
3191 // If we end up here, it’s not a continuation byte
3192 throw Error('Invalid continuation byte');
3193 }
3194
3195 function decodeSymbol() {
3196 var byte1;
3197 var byte2;
3198 var byte3;
3199 var byte4;
3200 var codePoint;
3201
3202 if (byteIndex > byteCount) {
3203 throw Error('Invalid byte index');
3204 }
3205
3206 if (byteIndex == byteCount) {
3207 return false;
3208 }
3209
3210 // Read first byte
3211 byte1 = byteArray[byteIndex] & 0xFF;
3212 byteIndex++;
3213
3214 // 1-byte sequence (no continuation bytes)
3215 if ((byte1 & 0x80) == 0) {
3216 return byte1;
3217 }
3218
3219 // 2-byte sequence
3220 if ((byte1 & 0xE0) == 0xC0) {
3221 var byte2 = readContinuationByte();
3222 codePoint = ((byte1 & 0x1F) << 6) | byte2;
3223 if (codePoint >= 0x80) {
3224 return codePoint;
3225 } else {
3226 throw Error('Invalid continuation byte');
3227 }
3228 }
3229
3230 // 3-byte sequence (may include unpaired surrogates)
3231 if ((byte1 & 0xF0) == 0xE0) {
3232 byte2 = readContinuationByte();
3233 byte3 = readContinuationByte();
3234 codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
3235 if (codePoint >= 0x0800) {
3236 return codePoint;
3237 } else {
3238 throw Error('Invalid continuation byte');
3239 }
3240 }
3241
3242 // 4-byte sequence
3243 if ((byte1 & 0xF8) == 0xF0) {
3244 byte2 = readContinuationByte();
3245 byte3 = readContinuationByte();
3246 byte4 = readContinuationByte();
3247 codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
3248 (byte3 << 0x06) | byte4;
3249 if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
3250 return codePoint;
3251 }
3252 }
3253
3254 throw Error('Invalid UTF-8 detected');
3255 }
3256
3257 var byteArray;
3258 var byteCount;
3259 var byteIndex;
3260 function utf8decode(byteString) {
3261 byteArray = ucs2decode(byteString);
3262 byteCount = byteArray.length;
3263 byteIndex = 0;
3264 var codePoints = [];
3265 var tmp;
3266 while ((tmp = decodeSymbol()) !== false) {
3267 codePoints.push(tmp);
3268 }
3269 return ucs2encode(codePoints);
3270 }
3271
3272 /*--------------------------------------------------------------------------*/
3273
3274 var utf8 = {
3275 'version': '2.0.0',
3276 'encode': utf8encode,
3277 'decode': utf8decode
3278 };
3279
3280 // Some AMD build optimizers, like r.js, check for specific condition patterns
3281 // like the following:
3282 if (
3283 typeof define == 'function' &&
3284 typeof define.amd == 'object' &&
3285 define.amd
3286 ) {
3287 define(function() {
3288 return utf8;
3289 });
3290 } else if (freeExports && !freeExports.nodeType) {
3291 if (freeMod) { // in Node.js or RingoJS v0.8.0+
3292 freeMod.exports = utf8;
3293 } else { // in Narwhal or RingoJS v0.7.0-
3294 var object = {};
3295 var hasOwnProperty = object.hasOwnProperty;
3296 for (var key in utf8) {
3297 hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
3298 }
3299 }
3300 } else { // in Rhino or a web browser
3301 root.utf8 = utf8;
3302 }
3303
3304 }(this));
3305
3306 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3307 },{}],21:[function(_dereq_,mod,exports){
3308
3309 /**
3310 * Mod dependencies.
3311 */
3312
3313 var global = _dereq_('global');
3314
3315 /**
3316 * Mod exports.
3317 *
3318 * Logic borrowed from Modernizr:
3319 *
3320 * - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js
3321 */
3322
3323 try {
3324 mod.exports = 'XMLHttpRequest' in global &&
3325 'withCredentials' in new global.XMLHttpRequest();
3326 } catch (err) {
3327 // if XMLHttp support is disabled in IE then it will throw
3328 // when trying to create
3329 mod.exports = false;
3330 }
3331
3332 },{"global":22}],22:[function(_dereq_,mod,exports){
3333
3334 /**
3335 * Returns `this`. Execute this without a "context" (i.e. without it being
3336 * attached to an object of the left-hand side), and `this` points to the
3337 * "global" scope of the current JS execution.
3338 */
3339
3340 mod.exports = (function () { return this; })();
3341
3342 },{}],23:[function(_dereq_,mod,exports){
3343
3344 var indexOf = [].indexOf;
3345
3346 mod.exports = function(arr, obj){
3347 if (indexOf) return arr.indexOf(obj);
3348 for (var i = 0; i < arr.length; ++i) {
3349 if (arr[i] === obj) return i;
3350 }
3351 return -1;
3352 };
3353 },{}],24:[function(_dereq_,mod,exports){
3354 (function (global){
3355 /**
3356 * JSON parse.
3357 *
3358 * @see Based on jQuery#parseJSON (MIT) and JSON2
3359 * @api private
3360 */
3361
3362 var rvalidchars = /^[\],:{}\s]*$/;
3363 var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
3364 var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
3365 var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
3366 var rtrimLeft = /^\s+/;
3367 var rtrimRight = /\s+$/;
3368
3369 mod.exports = function parsejson(data) {
3370 if ('string' != typeof data || !data) {
3371 return null;
3372 }
3373
3374 data = data.replace(rtrimLeft, '').replace(rtrimRight, '');
3375
3376 // Attempt to parse using the native JSON parser first
3377 if (global.JSON && JSON.parse) {
3378 return JSON.parse(data);
3379 }
3380
3381 if (rvalidchars.test(data.replace(rvalidescape, '@')
3382 .replace(rvalidtokens, ']')
3383 .replace(rvalidbraces, ''))) {
3384 return (new Function('return ' + data))();
3385 }
3386 };
3387 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3388 },{}],25:[function(_dereq_,mod,exports){
3389 /**
3390 * Compiles a querystring
3391 * Returns string representation of the object
3392 *
3393 * @param {Object}
3394 * @api private
3395 */
3396
3397 exports.encode = function (obj) {
3398 var str = '';
3399
3400 for (var i in obj) {
3401 if (obj.hasOwnProperty(i)) {
3402 if (str.length) str += '&';
3403 str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
3404 }
3405 }
3406
3407 return str;
3408 };
3409
3410 /**
3411 * Parses a simple querystring into an object
3412 *
3413 * @param {String} qs
3414 * @api private
3415 */
3416
3417 exports.decode = function(qs){
3418 var qry = {};
3419 var pairs = qs.split('&');
3420 for (var i = 0, l = pairs.length; i < l; i++) {
3421 var pair = pairs[i].split('=');
3422 qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
3423 }
3424 return qry;
3425 };
3426
3427 },{}],26:[function(_dereq_,mod,exports){
3428 /**
3429 * Parses an URI
3430 *
3431 * @author Steven Levithan <stevenlevithan.com> (MIT license)
3432 * @api private
3433 */
3434
3435 var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
3436
3437 var parts = [
3438 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
3439 ];
3440
3441 mod.exports = function parseuri(str) {
3442 var src = str,
3443 b = str.indexOf('['),
3444 e = str.indexOf(']');
3445
3446 if (b != -1 && e != -1) {
3447 str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);
3448 }
3449
3450 var m = re.exec(str || ''),
3451 uri = {},
3452 i = 14;
3453
3454 while (i--) {
3455 uri[parts[i]] = m[i] || '';
3456 }
3457
3458 if (b != -1 && e != -1) {
3459 uri.source = src;
3460 uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');
3461 uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');
3462 uri.ipv6uri = true;
3463 }
3464
3465 return uri;
3466 };
3467
3468 },{}],27:[function(_dereq_,mod,exports){
3469
3470 /**
3471 * Mod dependencies.
3472 */
3473
3474 var global = (function() { return this; })();
3475
3476 /**
3477 * WebSocket constructor.
3478 */
3479
3480 var WebSocket = global.WebSocket || global.MozWebSocket;
3481
3482 /**
3483 * Module exports.
3484 */
3485
3486 mod.exports = WebSocket ? ws : null;
3487
3488 /**
3489 * WebSocket constructor.
3490 *
3491 * The third `opts` options object gets ignored in web browsers, since it's
3492 * non-standard, and throws a TypeError if passed to the constructor.
3493 * See: https://github.com/einaros/ws/issues/227
3494 *
3495 * @param {String} uri
3496 * @param {Array} protocols (optional)
3497 * @param {Object) opts (optional)
3498 * @api public
3499 */
3500
3501 function ws(uri, protocols, opts) {
3502 var instance;
3503 if (protocols) {
3504 instance = new WebSocket(uri, protocols);
3505 } else {
3506 instance = new WebSocket(uri);
3507 }
3508 return instance;
3509 }
3510
3511 if (WebSocket) ws.prototype = WebSocket.prototype;
3512
3513 },{}]},{},[1])
3514 (1)
3515 });