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