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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.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){
3 module.exports = _dereq_('./lib/');
5 },{"./lib/":2}],2:[function(_dereq_,module,exports){
7 module.exports = _dereq_('./socket');
9 /**
10 * Exports parser
11 *
12 * @api public
13 *
14 */
15 module.exports.parser = _dereq_('engine.io-parser');
17 },{"./socket":3,"engine.io-parser":20}],3:[function(_dereq_,module,exports){
18 (function (global){
19 /**
20 * Module dependencies.
21 */
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');
32 /**
33 * Module exports.
34 */
36 module.exports = Socket;
38 /**
39 * Noop function.
40 *
41 * @api private
42 */
44 function noop(){}
46 /**
47 * Socket constructor.
48 *
49 * @param {String|Object} uri or options
50 * @param {Object} options
51 * @api public
52 */
54 function Socket(uri, opts){
55 if (!(this instanceof Socket)) return new Socket(uri, opts);
57 opts = opts || {};
59 if (uri && 'object' == typeof uri) {
60 opts = uri;
61 uri = null;
62 }
64 if (uri) {
65 uri = parseuri(uri);
66 opts.hostname = 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 } else if (opts.host) {
71 opts.hostname = parseuri(opts.host).host;
72 }
74 this.secure = null != opts.secure ? opts.secure :
75 (global.location && 'https:' == location.protocol);
77 if (opts.hostname && !opts.port) {
78 // if no port is specified manually, use the protocol default
79 opts.port = this.secure ? '443' : '80';
80 }
82 this.agent = opts.agent || false;
83 this.hostname = opts.hostname ||
84 (global.location ? location.hostname : 'localhost');
85 this.port = opts.port || (global.location && location.port ?
86 location.port :
87 (this.secure ? 443 : 80));
88 this.query = opts.query || {};
89 if ('string' == typeof this.query) this.query = parseqs.decode(this.query);
90 this.upgrade = false !== opts.upgrade;
91 this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
92 this.forceJSONP = !!opts.forceJSONP;
93 this.jsonp = false !== opts.jsonp;
94 this.forceBase64 = !!opts.forceBase64;
95 this.enablesXDR = !!opts.enablesXDR;
96 this.timestampParam = opts.timestampParam || 't';
97 this.timestampRequests = opts.timestampRequests;
98 this.transports = opts.transports || ['polling', 'websocket'];
99 this.readyState = '';
100 this.writeBuffer = [];
101 this.policyPort = opts.policyPort || 843;
102 this.rememberUpgrade = opts.rememberUpgrade || false;
103 this.binaryType = null;
104 this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades;
105 this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || {}) : false;
107 if (true === this.perMessageDeflate) this.perMessageDeflate = {};
108 if (this.perMessageDeflate && null == this.perMessageDeflate.threshold) {
109 this.perMessageDeflate.threshold = 1024;
110 }
112 // SSL options for Node.js client
113 this.pfx = opts.pfx || null;
114 this.key = opts.key || null;
115 this.passphrase = opts.passphrase || null;
116 this.cert = opts.cert || null;
117 this.ca = opts.ca || null;
118 this.ciphers = opts.ciphers || null;
119 this.rejectUnauthorized = opts.rejectUnauthorized === undefined ? null : opts.rejectUnauthorized;
121 // other options for Node.js client
122 var freeGlobal = typeof global == 'object' && global;
123 if (freeGlobal.global === freeGlobal) {
124 if (opts.extraHeaders && Object.keys(opts.extraHeaders).length > 0) {
125 this.extraHeaders = opts.extraHeaders;
126 }
127 }
129 this.open();
130 }
132 Socket.priorWebsocketSuccess = false;
134 /**
135 * Mix in `Emitter`.
136 */
138 Emitter(Socket.prototype);
140 /**
141 * Protocol version.
142 *
143 * @api public
144 */
146 Socket.protocol = parser.protocol; // this is an int
148 /**
149 * Expose deps for legacy compatibility
150 * and standalone browser access.
151 */
153 Socket.Socket = Socket;
154 Socket.Transport = _dereq_('./transport');
155 Socket.transports = _dereq_('./transports');
156 Socket.parser = _dereq_('engine.io-parser');
158 /**
159 * Creates transport of the given type.
160 *
161 * @param {String} transport name
162 * @return {Transport}
163 * @api private
164 */
166 Socket.prototype.createTransport = function (name) {
167 debug('creating transport "%s"', name);
168 var query = clone(this.query);
170 // append engine.io protocol identifier
171 query.EIO = parser.protocol;
173 // transport name
174 query.transport = name;
176 // session id if we already have one
177 if (this.id) query.sid = this.id;
179 var transport = new transports[name]({
180 agent: this.agent,
181 hostname: this.hostname,
182 port: this.port,
183 secure: this.secure,
184 path: this.path,
185 query: query,
186 forceJSONP: this.forceJSONP,
187 jsonp: this.jsonp,
188 forceBase64: this.forceBase64,
189 enablesXDR: this.enablesXDR,
190 timestampRequests: this.timestampRequests,
191 timestampParam: this.timestampParam,
192 policyPort: this.policyPort,
193 socket: this,
194 pfx: this.pfx,
195 key: this.key,
196 passphrase: this.passphrase,
197 cert: this.cert,
198 ca: this.ca,
199 ciphers: this.ciphers,
200 rejectUnauthorized: this.rejectUnauthorized,
201 perMessageDeflate: this.perMessageDeflate,
202 extraHeaders: this.extraHeaders
203 });
205 return transport;
206 };
208 function clone (obj) {
209 var o = {};
210 for (var i in obj) {
211 if (obj.hasOwnProperty(i)) {
212 o[i] = obj[i];
213 }
214 }
215 return o;
216 }
218 /**
219 * Initializes transport to use and starts probe.
220 *
221 * @api private
222 */
223 Socket.prototype.open = function () {
224 var transport;
225 if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) {
226 transport = 'websocket';
227 } else if (0 === this.transports.length) {
228 // Emit error on next tick so it can be listened to
229 var self = this;
230 setTimeout(function() {
231 self.emit('error', 'No transports available');
232 }, 0);
233 return;
234 } else {
235 transport = this.transports[0];
236 }
237 this.readyState = 'opening';
239 // Retry with the next transport if the transport is disabled (jsonp: false)
240 try {
241 transport = this.createTransport(transport);
242 } catch (e) {
243 this.transports.shift();
244 this.open();
245 return;
246 }
248 transport.open();
249 this.setTransport(transport);
250 };
252 /**
253 * Sets the current transport. Disables the existing one (if any).
254 *
255 * @api private
256 */
258 Socket.prototype.setTransport = function(transport){
259 debug('setting transport %s', transport.name);
260 var self = this;
262 if (this.transport) {
263 debug('clearing existing transport %s', this.transport.name);
264 this.transport.removeAllListeners();
265 }
267 // set up transport
268 this.transport = transport;
270 // set up transport listeners
271 transport
272 .on('drain', function(){
273 self.onDrain();
274 })
275 .on('packet', function(packet){
276 self.onPacket(packet);
277 })
278 .on('error', function(e){
279 self.onError(e);
280 })
281 .on('close', function(){
282 self.onClose('transport close');
283 });
284 };
286 /**
287 * Probes a transport.
288 *
289 * @param {String} transport name
290 * @api private
291 */
293 Socket.prototype.probe = function (name) {
294 debug('probing transport "%s"', name);
295 var transport = this.createTransport(name, { probe: 1 })
296 , failed = false
297 , self = this;
299 Socket.priorWebsocketSuccess = false;
301 function onTransportOpen(){
302 if (self.onlyBinaryUpgrades) {
303 var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary;
304 failed = failed || upgradeLosesBinary;
305 }
306 if (failed) return;
308 debug('probe transport "%s" opened', name);
309 transport.send([{ type: 'ping', data: 'probe' }]);
310 transport.once('packet', function (msg) {
311 if (failed) return;
312 if ('pong' == msg.type && 'probe' == msg.data) {
313 debug('probe transport "%s" pong', name);
314 self.upgrading = true;
315 self.emit('upgrading', transport);
316 if (!transport) return;
317 Socket.priorWebsocketSuccess = 'websocket' == transport.name;
319 debug('pausing current transport "%s"', self.transport.name);
320 self.transport.pause(function () {
321 if (failed) return;
322 if ('closed' == self.readyState) return;
323 debug('changing transport and sending upgrade packet');
325 cleanup();
327 self.setTransport(transport);
328 transport.send([{ type: 'upgrade' }]);
329 self.emit('upgrade', transport);
330 transport = null;
331 self.upgrading = false;
332 self.flush();
333 });
334 } else {
335 debug('probe transport "%s" failed', name);
336 var err = new Error('probe error');
337 err.transport = transport.name;
338 self.emit('upgradeError', err);
339 }
340 });
341 }
343 function freezeTransport() {
344 if (failed) return;
346 // Any callback called by transport should be ignored since now
347 failed = true;
349 cleanup();
351 transport.close();
352 transport = null;
353 }
355 //Handle any error that happens while probing
356 function onerror(err) {
357 var error = new Error('probe error: ' + err);
358 error.transport = transport.name;
360 freezeTransport();
362 debug('probe transport "%s" failed because of error: %s', name, err);
364 self.emit('upgradeError', error);
365 }
367 function onTransportClose(){
368 onerror("transport closed");
369 }
371 //When the socket is closed while we're probing
372 function onclose(){
373 onerror("socket closed");
374 }
376 //When the socket is upgraded while we're probing
377 function onupgrade(to){
378 if (transport && to.name != transport.name) {
379 debug('"%s" works - aborting "%s"', to.name, transport.name);
380 freezeTransport();
381 }
382 }
384 //Remove all listeners on the transport and on self
385 function cleanup(){
386 transport.removeListener('open', onTransportOpen);
387 transport.removeListener('error', onerror);
388 transport.removeListener('close', onTransportClose);
389 self.removeListener('close', onclose);
390 self.removeListener('upgrading', onupgrade);
391 }
393 transport.once('open', onTransportOpen);
394 transport.once('error', onerror);
395 transport.once('close', onTransportClose);
397 this.once('close', onclose);
398 this.once('upgrading', onupgrade);
400 transport.open();
402 };
404 /**
405 * Called when connection is deemed open.
406 *
407 * @api public
408 */
410 Socket.prototype.onOpen = function () {
411 debug('socket open');
412 this.readyState = 'open';
413 Socket.priorWebsocketSuccess = 'websocket' == this.transport.name;
414 this.emit('open');
415 this.flush();
417 // we check for `readyState` in case an `open`
418 // listener already closed the socket
419 if ('open' == this.readyState && this.upgrade && this.transport.pause) {
420 debug('starting upgrade probes');
421 for (var i = 0, l = this.upgrades.length; i < l; i++) {
422 this.probe(this.upgrades[i]);
423 }
424 }
425 };
427 /**
428 * Handles a packet.
429 *
430 * @api private
431 */
433 Socket.prototype.onPacket = function (packet) {
434 if ('opening' == this.readyState || 'open' == this.readyState) {
435 debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
437 this.emit('packet', packet);
439 // Socket is live - any packet counts
440 this.emit('heartbeat');
442 switch (packet.type) {
443 case 'open':
444 this.onHandshake(parsejson(packet.data));
445 break;
447 case 'pong':
448 this.setPing();
449 this.emit('pong');
450 break;
452 case 'error':
453 var err = new Error('server error');
454 err.code = packet.data;
455 this.onError(err);
456 break;
458 case 'message':
459 this.emit('data', packet.data);
460 this.emit('message', packet.data);
461 break;
462 }
463 } else {
464 debug('packet received with socket readyState "%s"', this.readyState);
465 }
466 };
468 /**
469 * Called upon handshake completion.
470 *
471 * @param {Object} handshake obj
472 * @api private
473 */
475 Socket.prototype.onHandshake = function (data) {
476 this.emit('handshake', data);
477 this.id = data.sid;
478 this.transport.query.sid = data.sid;
479 this.upgrades = this.filterUpgrades(data.upgrades);
480 this.pingInterval = data.pingInterval;
481 this.pingTimeout = data.pingTimeout;
482 this.onOpen();
483 // In case open handler closes socket
484 if ('closed' == this.readyState) return;
485 this.setPing();
487 // Prolong liveness of socket on heartbeat
488 this.removeListener('heartbeat', this.onHeartbeat);
489 this.on('heartbeat', this.onHeartbeat);
490 };
492 /**
493 * Resets ping timeout.
494 *
495 * @api private
496 */
498 Socket.prototype.onHeartbeat = function (timeout) {
499 clearTimeout(this.pingTimeoutTimer);
500 var self = this;
501 self.pingTimeoutTimer = setTimeout(function () {
502 if ('closed' == self.readyState) return;
503 self.onClose('ping timeout');
504 }, timeout || (self.pingInterval + self.pingTimeout));
505 };
507 /**
508 * Pings server every `this.pingInterval` and expects response
509 * within `this.pingTimeout` or closes connection.
510 *
511 * @api private
512 */
514 Socket.prototype.setPing = function () {
515 var self = this;
516 clearTimeout(self.pingIntervalTimer);
517 self.pingIntervalTimer = setTimeout(function () {
518 debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
519 self.ping();
520 self.onHeartbeat(self.pingTimeout);
521 }, self.pingInterval);
522 };
524 /**
525 * Sends a ping packet.
526 *
527 * @api private
528 */
530 Socket.prototype.ping = function () {
531 var self = this;
532 this.sendPacket('ping', function(){
533 self.emit('ping');
534 });
535 };
537 /**
538 * Called on `drain` event
539 *
540 * @api private
541 */
543 Socket.prototype.onDrain = function() {
544 this.writeBuffer.splice(0, this.prevBufferLen);
546 // setting prevBufferLen = 0 is very important
547 // for example, when upgrading, upgrade packet is sent over,
548 // and a nonzero prevBufferLen could cause problems on `drain`
549 this.prevBufferLen = 0;
551 if (0 === this.writeBuffer.length) {
552 this.emit('drain');
553 } else {
554 this.flush();
555 }
556 };
558 /**
559 * Flush write buffers.
560 *
561 * @api private
562 */
564 Socket.prototype.flush = function () {
565 if ('closed' != this.readyState && this.transport.writable &&
566 !this.upgrading && this.writeBuffer.length) {
567 debug('flushing %d packets in socket', this.writeBuffer.length);
568 this.transport.send(this.writeBuffer);
569 // keep track of current length of writeBuffer
570 // splice writeBuffer and callbackBuffer on `drain`
571 this.prevBufferLen = this.writeBuffer.length;
572 this.emit('flush');
573 }
574 };
576 /**
577 * Sends a message.
578 *
579 * @param {String} message.
580 * @param {Function} callback function.
581 * @param {Object} options.
582 * @return {Socket} for chaining.
583 * @api public
584 */
586 Socket.prototype.write =
587 Socket.prototype.send = function (msg, options, fn) {
588 this.sendPacket('message', msg, options, fn);
589 return this;
590 };
592 /**
593 * Sends a packet.
594 *
595 * @param {String} packet type.
596 * @param {String} data.
597 * @param {Object} options.
598 * @param {Function} callback function.
599 * @api private
600 */
602 Socket.prototype.sendPacket = function (type, data, options, fn) {
603 if('function' == typeof data) {
604 fn = data;
605 data = undefined;
606 }
608 if ('function' == typeof options) {
609 fn = options;
610 options = null;
611 }
613 if ('closing' == this.readyState || 'closed' == this.readyState) {
614 return;
615 }
617 options = options || {};
618 options.compress = false !== options.compress;
620 var packet = {
621 type: type,
622 data: data,
623 options: options
624 };
625 this.emit('packetCreate', packet);
626 this.writeBuffer.push(packet);
627 if (fn) this.once('flush', fn);
628 this.flush();
629 };
631 /**
632 * Closes the connection.
633 *
634 * @api private
635 */
637 Socket.prototype.close = function () {
638 if ('opening' == this.readyState || 'open' == this.readyState) {
639 this.readyState = 'closing';
641 var self = this;
643 if (this.writeBuffer.length) {
644 this.once('drain', function() {
645 if (this.upgrading) {
646 waitForUpgrade();
647 } else {
648 close();
649 }
650 });
651 } else if (this.upgrading) {
652 waitForUpgrade();
653 } else {
654 close();
655 }
656 }
658 function close() {
659 self.onClose('forced close');
660 debug('socket closing - telling transport to close');
661 self.transport.close();
662 }
664 function cleanupAndClose() {
665 self.removeListener('upgrade', cleanupAndClose);
666 self.removeListener('upgradeError', cleanupAndClose);
667 close();
668 }
670 function waitForUpgrade() {
671 // wait for upgrade to finish since we can't send packets while pausing a transport
672 self.once('upgrade', cleanupAndClose);
673 self.once('upgradeError', cleanupAndClose);
674 }
676 return this;
677 };
679 /**
680 * Called upon transport error
681 *
682 * @api private
683 */
685 Socket.prototype.onError = function (err) {
686 debug('socket error %j', err);
687 Socket.priorWebsocketSuccess = false;
688 this.emit('error', err);
689 this.onClose('transport error', err);
690 };
692 /**
693 * Called upon transport close.
694 *
695 * @api private
696 */
698 Socket.prototype.onClose = function (reason, desc) {
699 if ('opening' == this.readyState || 'open' == this.readyState || 'closing' == this.readyState) {
700 debug('socket close with reason: "%s"', reason);
701 var self = this;
703 // clear timers
704 clearTimeout(this.pingIntervalTimer);
705 clearTimeout(this.pingTimeoutTimer);
707 // stop event from firing again for transport
708 this.transport.removeAllListeners('close');
710 // ensure transport won't stay open
711 this.transport.close();
713 // ignore further transport communication
714 this.transport.removeAllListeners();
716 // set ready state
717 this.readyState = 'closed';
719 // clear session id
720 this.id = null;
722 // emit close event
723 this.emit('close', reason, desc);
725 // clean buffers after, so users can still
726 // grab the buffers on `close` event
727 self.writeBuffer = [];
728 self.prevBufferLen = 0;
729 }
730 };
732 /**
733 * Filters upgrades, returning only those matching client transports.
734 *
735 * @param {Array} server upgrades
736 * @api private
737 *
738 */
740 Socket.prototype.filterUpgrades = function (upgrades) {
741 var filteredUpgrades = [];
742 for (var i = 0, j = upgrades.length; i<j; i++) {
743 if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]);
744 }
745 return filteredUpgrades;
746 };
748 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
749 },{"./transport":4,"./transports":5,"component-emitter":16,"debug":18,"engine.io-parser":20,"indexof":24,"parsejson":27,"parseqs":28,"parseuri":29}],4:[function(_dereq_,module,exports){
750 /**
751 * Module dependencies.
752 */
754 var parser = _dereq_('engine.io-parser');
755 var Emitter = _dereq_('component-emitter');
757 /**
758 * Module exports.
759 */
761 module.exports = Transport;
763 /**
764 * Transport abstract constructor.
765 *
766 * @param {Object} options.
767 * @api private
768 */
770 function Transport (opts) {
771 this.path = opts.path;
772 this.hostname = opts.hostname;
773 this.port = opts.port;
774 this.secure = opts.secure;
775 this.query = opts.query;
776 this.timestampParam = opts.timestampParam;
777 this.timestampRequests = opts.timestampRequests;
778 this.readyState = '';
779 this.agent = opts.agent || false;
780 this.socket = opts.socket;
781 this.enablesXDR = opts.enablesXDR;
783 // SSL options for Node.js client
784 this.pfx = opts.pfx;
785 this.key = opts.key;
786 this.passphrase = opts.passphrase;
787 this.cert = opts.cert;
788 this.ca = opts.ca;
789 this.ciphers = opts.ciphers;
790 this.rejectUnauthorized = opts.rejectUnauthorized;
792 // other options for Node.js client
793 this.extraHeaders = opts.extraHeaders;
794 }
796 /**
797 * Mix in `Emitter`.
798 */
800 Emitter(Transport.prototype);
802 /**
803 * Emits an error.
804 *
805 * @param {String} str
806 * @return {Transport} for chaining
807 * @api public
808 */
810 Transport.prototype.onError = function (msg, desc) {
811 var err = new Error(msg);
812 err.type = 'TransportError';
813 err.description = desc;
814 this.emit('error', err);
815 return this;
816 };
818 /**
819 * Opens the transport.
820 *
821 * @api public
822 */
824 Transport.prototype.open = function () {
825 if ('closed' == this.readyState || '' == this.readyState) {
826 this.readyState = 'opening';
827 this.doOpen();
828 }
830 return this;
831 };
833 /**
834 * Closes the transport.
835 *
836 * @api private
837 */
839 Transport.prototype.close = function () {
840 if ('opening' == this.readyState || 'open' == this.readyState) {
841 this.doClose();
842 this.onClose();
843 }
845 return this;
846 };
848 /**
849 * Sends multiple packets.
850 *
851 * @param {Array} packets
852 * @api private
853 */
855 Transport.prototype.send = function(packets){
856 if ('open' == this.readyState) {
857 this.write(packets);
858 } else {
859 throw new Error('Transport not open');
860 }
861 };
863 /**
864 * Called upon open
865 *
866 * @api private
867 */
869 Transport.prototype.onOpen = function () {
870 this.readyState = 'open';
871 this.writable = true;
872 this.emit('open');
873 };
875 /**
876 * Called with data.
877 *
878 * @param {String} data
879 * @api private
880 */
882 Transport.prototype.onData = function(data){
883 var packet = parser.decodePacket(data, this.socket.binaryType);
884 this.onPacket(packet);
885 };
887 /**
888 * Called with a decoded packet.
889 */
891 Transport.prototype.onPacket = function (packet) {
892 this.emit('packet', packet);
893 };
895 /**
896 * Called upon close.
897 *
898 * @api private
899 */
901 Transport.prototype.onClose = function () {
902 this.readyState = 'closed';
903 this.emit('close');
904 };
906 },{"component-emitter":16,"engine.io-parser":20}],5:[function(_dereq_,module,exports){
907 (function (global){
908 /**
909 * Module dependencies
910 */
912 var XMLHttpRequest = _dereq_('xmlhttprequest-ssl');
913 var XHR = _dereq_('./polling-xhr');
914 var JSONP = _dereq_('./polling-jsonp');
915 var websocket = _dereq_('./websocket');
917 /**
918 * Export transports.
919 */
921 exports.polling = polling;
922 exports.websocket = websocket;
924 /**
925 * Polling transport polymorphic constructor.
926 * Decides on xhr vs jsonp based on feature detection.
927 *
928 * @api private
929 */
931 function polling(opts){
932 var xhr;
933 var xd = false;
934 var xs = false;
935 var jsonp = false !== opts.jsonp;
937 if (global.location) {
938 var isSSL = 'https:' == location.protocol;
939 var port = location.port;
941 // some user agents have empty `location.port`
942 if (!port) {
943 port = isSSL ? 443 : 80;
944 }
946 xd = opts.hostname != location.hostname || port != opts.port;
947 xs = opts.secure != isSSL;
948 }
950 opts.xdomain = xd;
951 opts.xscheme = xs;
952 xhr = new XMLHttpRequest(opts);
954 if ('open' in xhr && !opts.forceJSONP) {
955 return new XHR(opts);
956 } else {
957 if (!jsonp) throw new Error('JSONP disabled');
958 return new JSONP(opts);
959 }
960 }
962 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
963 },{"./polling-jsonp":6,"./polling-xhr":7,"./websocket":9,"xmlhttprequest-ssl":10}],6:[function(_dereq_,module,exports){
964 (function (global){
966 /**
967 * Module requirements.
968 */
970 var Polling = _dereq_('./polling');
971 var inherit = _dereq_('component-inherit');
973 /**
974 * Module exports.
975 */
977 module.exports = JSONPPolling;
979 /**
980 * Cached regular expressions.
981 */
983 var rNewline = /\n/g;
984 var rEscapedNewline = /\\n/g;
986 /**
987 * Global JSONP callbacks.
988 */
990 var callbacks;
992 /**
993 * Callbacks count.
994 */
996 var index = 0;
998 /**
999 * Noop.
1000 */
1002 function empty () { }
1004 /**
1005 * JSONP Polling constructor.
1006 *
1007 * @param {Object} opts.
1008 * @api public
1009 */
1011 function JSONPPolling (opts) {
1012 Polling.call(this, opts);
1014 this.query = this.query || {};
1016 // define global callbacks array if not present
1017 // we do this here (lazily) to avoid unneeded global pollution
1018 if (!callbacks) {
1019 // we need to consider multiple engines in the same page
1020 if (!global.___eio) global.___eio = [];
1021 callbacks = global.___eio;
1022 }
1024 // callback identifier
1025 this.index = callbacks.length;
1027 // add callback to jsonp global
1028 var self = this;
1029 callbacks.push(function (msg) {
1030 self.onData(msg);
1031 });
1033 // append to query string
1034 this.query.j = this.index;
1036 // prevent spurious errors from being emitted when the window is unloaded
1037 if (global.document && global.addEventListener) {
1038 global.addEventListener('beforeunload', function () {
1039 if (self.script) self.script.onerror = empty;
1040 }, false);
1041 }
1042 }
1044 /**
1045 * Inherits from Polling.
1046 */
1048 inherit(JSONPPolling, Polling);
1050 /*
1051 * JSONP only supports binary as base64 encoded strings
1052 */
1054 JSONPPolling.prototype.supportsBinary = false;
1056 /**
1057 * Closes the socket.
1058 *
1059 * @api private
1060 */
1062 JSONPPolling.prototype.doClose = function () {
1063 if (this.script) {
1064 this.script.parentNode.removeChild(this.script);
1065 this.script = null;
1066 }
1068 if (this.form) {
1069 this.form.parentNode.removeChild(this.form);
1070 this.form = null;
1071 this.iframe = null;
1072 }
1074 Polling.prototype.doClose.call(this);
1075 };
1077 /**
1078 * Starts a poll cycle.
1079 *
1080 * @api private
1081 */
1083 JSONPPolling.prototype.doPoll = function () {
1084 var self = this;
1085 var script = document.createElement('script');
1087 if (this.script) {
1088 this.script.parentNode.removeChild(this.script);
1089 this.script = null;
1090 }
1092 script.async = true;
1093 script.src = this.uri();
1094 script.onerror = function(e){
1095 self.onError('jsonp poll error',e);
1096 };
1098 var insertAt = document.getElementsByTagName('script')[0];
1099 if (insertAt) {
1100 insertAt.parentNode.insertBefore(script, insertAt);
1101 }
1102 else {
1103 (document.head || document.body).appendChild(script);
1104 }
1105 this.script = script;
1107 var isUAgecko = 'undefined' != typeof navigator && /gecko/i.test(navigator.userAgent);
1109 if (isUAgecko) {
1110 setTimeout(function () {
1111 var iframe = document.createElement('iframe');
1112 document.body.appendChild(iframe);
1113 document.body.removeChild(iframe);
1114 }, 100);
1115 }
1116 };
1118 /**
1119 * Writes with a hidden iframe.
1120 *
1121 * @param {String} data to send
1122 * @param {Function} called upon flush.
1123 * @api private
1124 */
1126 JSONPPolling.prototype.doWrite = function (data, fn) {
1127 var self = this;
1129 if (!this.form) {
1130 var form = document.createElement('form');
1131 var area = document.createElement('textarea');
1132 var id = this.iframeId = 'eio_iframe_' + this.index;
1133 var iframe;
1135 form.className = 'socketio';
1136 form.style.position = 'absolute';
1137 form.style.top = '-1000px';
1138 form.style.left = '-1000px';
1139 form.target = id;
1140 form.method = 'POST';
1141 form.setAttribute('accept-charset', 'utf-8');
1142 area.name = 'd';
1143 form.appendChild(area);
1144 document.body.appendChild(form);
1146 this.form = form;
1147 this.area = area;
1148 }
1150 this.form.action = this.uri();
1152 function complete () {
1153 initIframe();
1154 fn();
1155 }
1157 function initIframe () {
1158 if (self.iframe) {
1159 try {
1160 self.form.removeChild(self.iframe);
1161 } catch (e) {
1162 self.onError('jsonp polling iframe removal error', e);
1163 }
1164 }
1166 try {
1167 // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
1168 var html = '<iframe src="javascript:0" name="'+ self.iframeId +'">';
1169 iframe = document.createElement(html);
1170 } catch (e) {
1171 iframe = document.createElement('iframe');
1172 iframe.name = self.iframeId;
1173 iframe.src = 'javascript:0';
1174 }
1176 iframe.id = self.iframeId;
1178 self.form.appendChild(iframe);
1179 self.iframe = iframe;
1180 }
1182 initIframe();
1184 // escape \n to prevent it from being converted into \r\n by some UAs
1185 // double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side
1186 data = data.replace(rEscapedNewline, '\\\n');
1187 this.area.value = data.replace(rNewline, '\\n');
1189 try {
1190 this.form.submit();
1191 } catch(e) {}
1193 if (this.iframe.attachEvent) {
1194 this.iframe.onreadystatechange = function(){
1195 if (self.iframe.readyState == 'complete') {
1196 complete();
1197 }
1198 };
1199 } else {
1200 this.iframe.onload = complete;
1201 }
1202 };
1204 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
1205 },{"./polling":8,"component-inherit":17}],7:[function(_dereq_,module,exports){
1206 (function (global){
1207 /**
1208 * Module requirements.
1209 */
1211 var XMLHttpRequest = _dereq_('xmlhttprequest-ssl');
1212 var Polling = _dereq_('./polling');
1213 var Emitter = _dereq_('component-emitter');
1214 var inherit = _dereq_('component-inherit');
1215 var debug = _dereq_('debug')('engine.io-client:polling-xhr');
1217 /**
1218 * Module exports.
1219 */
1221 module.exports = XHR;
1222 module.exports.Request = Request;
1224 /**
1225 * Empty function
1226 */
1228 function empty(){}
1230 /**
1231 * XHR Polling constructor.
1232 *
1233 * @param {Object} opts
1234 * @api public
1235 */
1237 function XHR(opts){
1238 Polling.call(this, opts);
1240 if (global.location) {
1241 var isSSL = 'https:' == location.protocol;
1242 var port = location.port;
1244 // some user agents have empty `location.port`
1245 if (!port) {
1246 port = isSSL ? 443 : 80;
1247 }
1249 this.xd = opts.hostname != global.location.hostname ||
1250 port != opts.port;
1251 this.xs = opts.secure != isSSL;
1252 } else {
1253 this.extraHeaders = opts.extraHeaders;
1254 }
1255 }
1257 /**
1258 * Inherits from Polling.
1259 */
1261 inherit(XHR, Polling);
1263 /**
1264 * XHR supports binary
1265 */
1267 XHR.prototype.supportsBinary = true;
1269 /**
1270 * Creates a request.
1271 *
1272 * @param {String} method
1273 * @api private
1274 */
1276 XHR.prototype.request = function(opts){
1277 opts = opts || {};
1278 opts.uri = this.uri();
1279 opts.xd = this.xd;
1280 opts.xs = this.xs;
1281 opts.agent = this.agent || false;
1282 opts.supportsBinary = this.supportsBinary;
1283 opts.enablesXDR = this.enablesXDR;
1285 // SSL options for Node.js client
1286 opts.pfx = this.pfx;
1287 opts.key = this.key;
1288 opts.passphrase = this.passphrase;
1289 opts.cert = this.cert;
1290 opts.ca = this.ca;
1291 opts.ciphers = this.ciphers;
1292 opts.rejectUnauthorized = this.rejectUnauthorized;
1294 // other options for Node.js client
1295 opts.extraHeaders = this.extraHeaders;
1297 return new Request(opts);
1298 };
1300 /**
1301 * Sends data.
1302 *
1303 * @param {String} data to send.
1304 * @param {Function} called upon flush.
1305 * @api private
1306 */
1308 XHR.prototype.doWrite = function(data, fn){
1309 var isBinary = typeof data !== 'string' && data !== undefined;
1310 var req = this.request({ method: 'POST', data: data, isBinary: isBinary });
1311 var self = this;
1312 req.on('success', fn);
1313 req.on('error', function(err){
1314 self.onError('xhr post error', err);
1315 });
1316 this.sendXhr = req;
1317 };
1319 /**
1320 * Starts a poll cycle.
1321 *
1322 * @api private
1323 */
1325 XHR.prototype.doPoll = function(){
1326 debug('xhr poll');
1327 var req = this.request();
1328 var self = this;
1329 req.on('data', function(data){
1330 self.onData(data);
1331 });
1332 req.on('error', function(err){
1333 self.onError('xhr poll error', err);
1334 });
1335 this.pollXhr = req;
1336 };
1338 /**
1339 * Request constructor
1340 *
1341 * @param {Object} options
1342 * @api public
1343 */
1345 function Request(opts){
1346 this.method = opts.method || 'GET';
1347 this.uri = opts.uri;
1348 this.xd = !!opts.xd;
1349 this.xs = !!opts.xs;
1350 this.async = false !== opts.async;
1351 this.data = undefined != opts.data ? opts.data : null;
1352 this.agent = opts.agent;
1353 this.isBinary = opts.isBinary;
1354 this.supportsBinary = opts.supportsBinary;
1355 this.enablesXDR = opts.enablesXDR;
1357 // SSL options for Node.js client
1358 this.pfx = opts.pfx;
1359 this.key = opts.key;
1360 this.passphrase = opts.passphrase;
1361 this.cert = opts.cert;
1362 this.ca = opts.ca;
1363 this.ciphers = opts.ciphers;
1364 this.rejectUnauthorized = opts.rejectUnauthorized;
1366 // other options for Node.js client
1367 this.extraHeaders = opts.extraHeaders;
1369 this.create();
1370 }
1372 /**
1373 * Mix in `Emitter`.
1374 */
1376 Emitter(Request.prototype);
1378 /**
1379 * Creates the XHR object and sends the request.
1380 *
1381 * @api private
1382 */
1384 Request.prototype.create = function(){
1385 var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR };
1387 // SSL options for Node.js client
1388 opts.pfx = this.pfx;
1389 opts.key = this.key;
1390 opts.passphrase = this.passphrase;
1391 opts.cert = this.cert;
1392 opts.ca = this.ca;
1393 opts.ciphers = this.ciphers;
1394 opts.rejectUnauthorized = this.rejectUnauthorized;
1396 var xhr = this.xhr = new XMLHttpRequest(opts);
1397 var self = this;
1399 try {
1400 debug('xhr open %s: %s', this.method, this.uri);
1401 xhr.open(this.method, this.uri, this.async);
1402 try {
1403 if (this.extraHeaders) {
1404 xhr.setDisableHeaderCheck(true);
1405 for (var i in this.extraHeaders) {
1406 if (this.extraHeaders.hasOwnProperty(i)) {
1407 xhr.setRequestHeader(i, this.extraHeaders[i]);
1408 }
1409 }
1410 }
1411 } catch (e) {}
1412 if (this.supportsBinary) {
1413 // This has to be done after open because Firefox is stupid
1414 // http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
1415 xhr.responseType = 'arraybuffer';
1416 }
1418 if ('POST' == this.method) {
1419 try {
1420 if (this.isBinary) {
1421 xhr.setRequestHeader('Content-type', 'application/octet-stream');
1422 } else {
1423 xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
1424 }
1425 } catch (e) {}
1426 }
1428 // ie6 check
1429 if ('withCredentials' in xhr) {
1430 xhr.withCredentials = true;
1431 }
1433 if (this.hasXDR()) {
1434 xhr.onload = function(){
1435 self.onLoad();
1436 };
1437 xhr.onerror = function(){
1438 self.onError(xhr.responseText);
1439 };
1440 } else {
1441 xhr.onreadystatechange = function(){
1442 if (4 != xhr.readyState) return;
1443 if (200 == xhr.status || 1223 == xhr.status) {
1444 self.onLoad();
1445 } else {
1446 // make sure the `error` event handler that's user-set
1447 // does not throw in the same tick and gets caught here
1448 setTimeout(function(){
1449 self.onError(xhr.status);
1450 }, 0);
1451 }
1452 };
1453 }
1455 debug('xhr data %s', this.data);
1456 xhr.send(this.data);
1457 } catch (e) {
1458 // Need to defer since .create() is called directly fhrom the constructor
1459 // and thus the 'error' event can only be only bound *after* this exception
1460 // occurs. Therefore, also, we cannot throw here at all.
1461 setTimeout(function() {
1462 self.onError(e);
1463 }, 0);
1464 return;
1465 }
1467 if (global.document) {
1468 this.index = Request.requestsCount++;
1469 Request.requests[this.index] = this;
1470 }
1471 };
1473 /**
1474 * Called upon successful response.
1475 *
1476 * @api private
1477 */
1479 Request.prototype.onSuccess = function(){
1480 this.emit('success');
1481 this.cleanup();
1482 };
1484 /**
1485 * Called if we have data.
1486 *
1487 * @api private
1488 */
1490 Request.prototype.onData = function(data){
1491 this.emit('data', data);
1492 this.onSuccess();
1493 };
1495 /**
1496 * Called upon error.
1497 *
1498 * @api private
1499 */
1501 Request.prototype.onError = function(err){
1502 this.emit('error', err);
1503 this.cleanup(true);
1504 };
1506 /**
1507 * Cleans up house.
1508 *
1509 * @api private
1510 */
1512 Request.prototype.cleanup = function(fromError){
1513 if ('undefined' == typeof this.xhr || null === this.xhr) {
1514 return;
1515 }
1516 // xmlhttprequest
1517 if (this.hasXDR()) {
1518 this.xhr.onload = this.xhr.onerror = empty;
1519 } else {
1520 this.xhr.onreadystatechange = empty;
1521 }
1523 if (fromError) {
1524 try {
1525 this.xhr.abort();
1526 } catch(e) {}
1527 }
1529 if (global.document) {
1530 delete Request.requests[this.index];
1531 }
1533 this.xhr = null;
1534 };
1536 /**
1537 * Called upon load.
1538 *
1539 * @api private
1540 */
1542 Request.prototype.onLoad = function(){
1543 var data;
1544 try {
1545 var contentType;
1546 try {
1547 contentType = this.xhr.getResponseHeader('Content-Type').split(';')[0];
1548 } catch (e) {}
1549 if (contentType === 'application/octet-stream') {
1550 data = this.xhr.response;
1551 } else {
1552 if (!this.supportsBinary) {
1553 data = this.xhr.responseText;
1554 } else {
1555 try {
1556 data = String.fromCharCode.apply(null, new Uint8Array(this.xhr.response));
1557 } catch (e) {
1558 var ui8Arr = new Uint8Array(this.xhr.response);
1559 var dataArray = [];
1560 for (var idx = 0, length = ui8Arr.length; idx < length; idx++) {
1561 dataArray.push(ui8Arr[idx]);
1562 }
1564 data = String.fromCharCode.apply(null, dataArray);
1565 }
1566 }
1567 }
1568 } catch (e) {
1569 this.onError(e);
1570 }
1571 if (null != data) {
1572 this.onData(data);
1573 }
1574 };
1576 /**
1577 * Check if it has XDomainRequest.
1578 *
1579 * @api private
1580 */
1582 Request.prototype.hasXDR = function(){
1583 return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR;
1584 };
1586 /**
1587 * Aborts the request.
1588 *
1589 * @api public
1590 */
1592 Request.prototype.abort = function(){
1593 this.cleanup();
1594 };
1596 /**
1597 * Aborts pending requests when unloading the window. This is needed to prevent
1598 * memory leaks (e.g. when using IE) and to ensure that no spurious error is
1599 * emitted.
1600 */
1602 if (global.document) {
1603 Request.requestsCount = 0;
1604 Request.requests = {};
1605 if (global.attachEvent) {
1606 global.attachEvent('onunload', unloadHandler);
1607 } else if (global.addEventListener) {
1608 global.addEventListener('beforeunload', unloadHandler, false);
1609 }
1610 }
1612 function unloadHandler() {
1613 for (var i in Request.requests) {
1614 if (Request.requests.hasOwnProperty(i)) {
1615 Request.requests[i].abort();
1616 }
1617 }
1618 }
1620 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
1621 },{"./polling":8,"component-emitter":16,"component-inherit":17,"debug":18,"xmlhttprequest-ssl":10}],8:[function(_dereq_,module,exports){
1622 /**
1623 * Module dependencies.
1624 */
1626 var Transport = _dereq_('../transport');
1627 var parseqs = _dereq_('parseqs');
1628 var parser = _dereq_('engine.io-parser');
1629 var inherit = _dereq_('component-inherit');
1630 var yeast = _dereq_('yeast');
1631 var debug = _dereq_('debug')('engine.io-client:polling');
1633 /**
1634 * Module exports.
1635 */
1637 module.exports = Polling;
1639 /**
1640 * Is XHR2 supported?
1641 */
1643 var hasXHR2 = (function() {
1644 var XMLHttpRequest = _dereq_('xmlhttprequest-ssl');
1645 var xhr = new XMLHttpRequest({ xdomain: false });
1646 return null != xhr.responseType;
1647 })();
1649 /**
1650 * Polling interface.
1651 *
1652 * @param {Object} opts
1653 * @api private
1654 */
1656 function Polling(opts){
1657 var forceBase64 = (opts && opts.forceBase64);
1658 if (!hasXHR2 || forceBase64) {
1659 this.supportsBinary = false;
1660 }
1661 Transport.call(this, opts);
1662 }
1664 /**
1665 * Inherits from Transport.
1666 */
1668 inherit(Polling, Transport);
1670 /**
1671 * Transport name.
1672 */
1674 Polling.prototype.name = 'polling';
1676 /**
1677 * Opens the socket (triggers polling). We write a PING message to determine
1678 * when the transport is open.
1679 *
1680 * @api private
1681 */
1683 Polling.prototype.doOpen = function(){
1684 this.poll();
1685 };
1687 /**
1688 * Pauses polling.
1689 *
1690 * @param {Function} callback upon buffers are flushed and transport is paused
1691 * @api private
1692 */
1694 Polling.prototype.pause = function(onPause){
1695 var pending = 0;
1696 var self = this;
1698 this.readyState = 'pausing';
1700 function pause(){
1701 debug('paused');
1702 self.readyState = 'paused';
1703 onPause();
1704 }
1706 if (this.polling || !this.writable) {
1707 var total = 0;
1709 if (this.polling) {
1710 debug('we are currently polling - waiting to pause');
1711 total++;
1712 this.once('pollComplete', function(){
1713 debug('pre-pause polling complete');
1714 --total || pause();
1715 });
1716 }
1718 if (!this.writable) {
1719 debug('we are currently writing - waiting to pause');
1720 total++;
1721 this.once('drain', function(){
1722 debug('pre-pause writing complete');
1723 --total || pause();
1724 });
1725 }
1726 } else {
1727 pause();
1728 }
1729 };
1731 /**
1732 * Starts polling cycle.
1733 *
1734 * @api public
1735 */
1737 Polling.prototype.poll = function(){
1738 debug('polling');
1739 this.polling = true;
1740 this.doPoll();
1741 this.emit('poll');
1742 };
1744 /**
1745 * Overloads onData to detect payloads.
1746 *
1747 * @api private
1748 */
1750 Polling.prototype.onData = function(data){
1751 var self = this;
1752 debug('polling got data %s', data);
1753 var callback = function(packet, index, total) {
1754 // if its the first message we consider the transport open
1755 if ('opening' == self.readyState) {
1756 self.onOpen();
1757 }
1759 // if its a close packet, we close the ongoing requests
1760 if ('close' == packet.type) {
1761 self.onClose();
1762 return false;
1763 }
1765 // otherwise bypass onData and handle the message
1766 self.onPacket(packet);
1767 };
1769 // decode payload
1770 parser.decodePayload(data, this.socket.binaryType, callback);
1772 // if an event did not trigger closing
1773 if ('closed' != this.readyState) {
1774 // if we got data we're not polling
1775 this.polling = false;
1776 this.emit('pollComplete');
1778 if ('open' == this.readyState) {
1779 this.poll();
1780 } else {
1781 debug('ignoring poll - transport state "%s"', this.readyState);
1782 }
1783 }
1784 };
1786 /**
1787 * For polling, send a close packet.
1788 *
1789 * @api private
1790 */
1792 Polling.prototype.doClose = function(){
1793 var self = this;
1795 function close(){
1796 debug('writing close packet');
1797 self.write([{ type: 'close' }]);
1798 }
1800 if ('open' == this.readyState) {
1801 debug('transport open - closing');
1802 close();
1803 } else {
1804 // in case we're trying to close while
1805 // handshaking is in progress (GH-164)
1806 debug('transport not open - deferring close');
1807 this.once('open', close);
1808 }
1809 };
1811 /**
1812 * Writes a packets payload.
1813 *
1814 * @param {Array} data packets
1815 * @param {Function} drain callback
1816 * @api private
1817 */
1819 Polling.prototype.write = function(packets){
1820 var self = this;
1821 this.writable = false;
1822 var callbackfn = function() {
1823 self.writable = true;
1824 self.emit('drain');
1825 };
1827 var self = this;
1828 parser.encodePayload(packets, this.supportsBinary, function(data) {
1829 self.doWrite(data, callbackfn);
1830 });
1831 };
1833 /**
1834 * Generates uri for connection.
1835 *
1836 * @api private
1837 */
1839 Polling.prototype.uri = function(){
1840 var query = this.query || {};
1841 var schema = this.secure ? 'https' : 'http';
1842 var port = '';
1844 // cache busting is forced
1845 if (false !== this.timestampRequests) {
1846 query[this.timestampParam] = yeast();
1847 }
1849 if (!this.supportsBinary && !query.sid) {
1850 query.b64 = 1;
1851 }
1853 query = parseqs.encode(query);
1855 // avoid port if default for schema
1856 if (this.port && (('https' == schema && this.port != 443) ||
1857 ('http' == schema && this.port != 80))) {
1858 port = ':' + this.port;
1859 }
1861 // prepend ? to query
1862 if (query.length) {
1863 query = '?' + query;
1864 }
1866 var ipv6 = this.hostname.indexOf(':') !== -1;
1867 return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
1868 };
1870 },{"../transport":4,"component-inherit":17,"debug":18,"engine.io-parser":20,"parseqs":28,"xmlhttprequest-ssl":10,"yeast":31}],9:[function(_dereq_,module,exports){
1871 (function (global){
1872 /**
1873 * Module dependencies.
1874 */
1876 var Transport = _dereq_('../transport');
1877 var parser = _dereq_('engine.io-parser');
1878 var parseqs = _dereq_('parseqs');
1879 var inherit = _dereq_('component-inherit');
1880 var yeast = _dereq_('yeast');
1881 var debug = _dereq_('debug')('engine.io-client:websocket');
1882 var BrowserWebSocket = global.WebSocket || global.MozWebSocket;
1884 /**
1885 * Get either the `WebSocket` or `MozWebSocket` globals
1886 * in the browser or try to resolve WebSocket-compatible
1887 * interface exposed by `ws` for Node-like environment.
1888 */
1890 var WebSocket = BrowserWebSocket;
1891 if (!WebSocket && typeof window === 'undefined') {
1892 try {
1893 WebSocket = _dereq_('ws');
1894 } catch (e) { }
1895 }
1897 /**
1898 * Module exports.
1899 */
1901 module.exports = WS;
1903 /**
1904 * WebSocket transport constructor.
1905 *
1906 * @api {Object} connection options
1907 * @api public
1908 */
1910 function WS(opts){
1911 var forceBase64 = (opts && opts.forceBase64);
1912 if (forceBase64) {
1913 this.supportsBinary = false;
1914 }
1915 this.perMessageDeflate = opts.perMessageDeflate;
1916 Transport.call(this, opts);
1917 }
1919 /**
1920 * Inherits from Transport.
1921 */
1923 inherit(WS, Transport);
1925 /**
1926 * Transport name.
1927 *
1928 * @api public
1929 */
1931 WS.prototype.name = 'websocket';
1933 /*
1934 * WebSockets support binary
1935 */
1937 WS.prototype.supportsBinary = true;
1939 /**
1940 * Opens socket.
1941 *
1942 * @api private
1943 */
1945 WS.prototype.doOpen = function(){
1946 if (!this.check()) {
1947 // let probe timeout
1948 return;
1949 }
1951 var self = this;
1952 var uri = this.uri();
1953 var protocols = void(0);
1954 var opts = {
1955 agent: this.agent,
1956 perMessageDeflate: this.perMessageDeflate
1957 };
1959 // SSL options for Node.js client
1960 opts.pfx = this.pfx;
1961 opts.key = this.key;
1962 opts.passphrase = this.passphrase;
1963 opts.cert = this.cert;
1964 opts.ca = this.ca;
1965 opts.ciphers = this.ciphers;
1966 opts.rejectUnauthorized = this.rejectUnauthorized;
1967 if (this.extraHeaders) {
1968 opts.headers = this.extraHeaders;
1969 }
1971 this.ws = BrowserWebSocket ? new WebSocket(uri) : new WebSocket(uri, protocols, opts);
1973 if (this.ws.binaryType === undefined) {
1974 this.supportsBinary = false;
1975 }
1977 if (this.ws.supports && this.ws.supports.binary) {
1978 this.supportsBinary = true;
1979 this.ws.binaryType = 'buffer';
1980 } else {
1981 this.ws.binaryType = 'arraybuffer';
1982 }
1984 this.addEventListeners();
1985 };
1987 /**
1988 * Adds event listeners to the socket
1989 *
1990 * @api private
1991 */
1993 WS.prototype.addEventListeners = function(){
1994 var self = this;
1996 this.ws.onopen = function(){
1997 self.onOpen();
1998 };
1999 this.ws.onclose = function(){
2000 self.onClose();
2001 };
2002 this.ws.onmessage = function(ev){
2003 self.onData(ev.data);
2004 };
2005 this.ws.onerror = function(e){
2006 self.onError('websocket error', e);
2007 };
2008 };
2010 /**
2011 * Override `onData` to use a timer on iOS.
2012 * See: https://gist.github.com/mloughran/2052006
2013 *
2014 * @api private
2015 */
2017 if ('undefined' != typeof navigator
2018 && /iPad|iPhone|iPod/i.test(navigator.userAgent)) {
2019 WS.prototype.onData = function(data){
2020 var self = this;
2021 setTimeout(function(){
2022 Transport.prototype.onData.call(self, data);
2023 }, 0);
2024 };
2025 }
2027 /**
2028 * Writes data to socket.
2029 *
2030 * @param {Array} array of packets.
2031 * @api private
2032 */
2034 WS.prototype.write = function(packets){
2035 var self = this;
2036 this.writable = false;
2038 // encodePacket efficient as it uses WS framing
2039 // no need for encodePayload
2040 var total = packets.length;
2041 for (var i = 0, l = total; i < l; i++) {
2042 (function(packet) {
2043 parser.encodePacket(packet, self.supportsBinary, function(data) {
2044 if (!BrowserWebSocket) {
2045 // always create a new object (GH-437)
2046 var opts = {};
2047 if (packet.options) {
2048 opts.compress = packet.options.compress;
2049 }
2051 if (self.perMessageDeflate) {
2052 var len = 'string' == typeof data ? global.Buffer.byteLength(data) : data.length;
2053 if (len < self.perMessageDeflate.threshold) {
2054 opts.compress = false;
2055 }
2056 }
2057 }
2059 //Sometimes the websocket has already been closed but the browser didn't
2060 //have a chance of informing us about it yet, in that case send will
2061 //throw an error
2062 try {
2063 if (BrowserWebSocket) {
2064 // TypeError is thrown when passing the second argument on Safari
2065 self.ws.send(data);
2066 } else {
2067 self.ws.send(data, opts);
2068 }
2069 } catch (e){
2070 debug('websocket closed before onclose event');
2071 }
2073 --total || done();
2074 });
2075 })(packets[i]);
2076 }
2078 function done(){
2079 self.emit('flush');
2081 // fake drain
2082 // defer to next tick to allow Socket to clear writeBuffer
2083 setTimeout(function(){
2084 self.writable = true;
2085 self.emit('drain');
2086 }, 0);
2087 }
2088 };
2090 /**
2091 * Called upon close
2092 *
2093 * @api private
2094 */
2096 WS.prototype.onClose = function(){
2097 Transport.prototype.onClose.call(this);
2098 };
2100 /**
2101 * Closes socket.
2102 *
2103 * @api private
2104 */
2106 WS.prototype.doClose = function(){
2107 if (typeof this.ws !== 'undefined') {
2108 this.ws.close();
2109 }
2110 };
2112 /**
2113 * Generates uri for connection.
2114 *
2115 * @api private
2116 */
2118 WS.prototype.uri = function(){
2119 var query = this.query || {};
2120 var schema = this.secure ? 'wss' : 'ws';
2121 var port = '';
2123 // avoid port if default for schema
2124 if (this.port && (('wss' == schema && this.port != 443)
2125 || ('ws' == schema && this.port != 80))) {
2126 port = ':' + this.port;
2127 }
2129 // append timestamp to URI
2130 if (this.timestampRequests) {
2131 query[this.timestampParam] = yeast();
2132 }
2134 // communicate binary support capabilities
2135 if (!this.supportsBinary) {
2136 query.b64 = 1;
2137 }
2139 query = parseqs.encode(query);
2141 // prepend ? to query
2142 if (query.length) {
2143 query = '?' + query;
2144 }
2146 var ipv6 = this.hostname.indexOf(':') !== -1;
2147 return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
2148 };
2150 /**
2151 * Feature detection for WebSocket.
2152 *
2153 * @return {Boolean} whether this transport is available.
2154 * @api public
2155 */
2157 WS.prototype.check = function(){
2158 return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
2159 };
2161 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
2162 },{"../transport":4,"component-inherit":17,"debug":18,"engine.io-parser":20,"parseqs":28,"ws":15,"yeast":31}],10:[function(_dereq_,module,exports){
2163 // browser shim for xmlhttprequest module
2164 var hasCORS = _dereq_('has-cors');
2166 module.exports = function(opts) {
2167 var xdomain = opts.xdomain;
2169 // scheme must be same when usign XDomainRequest
2170 // http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
2171 var xscheme = opts.xscheme;
2173 // XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default.
2174 // https://github.com/Automattic/engine.io-client/pull/217
2175 var enablesXDR = opts.enablesXDR;
2177 // XMLHttpRequest can be disabled on IE
2178 try {
2179 if ('undefined' != typeof XMLHttpRequest && (!xdomain || hasCORS)) {
2180 return new XMLHttpRequest();
2181 }
2182 } catch (e) { }
2184 // Use XDomainRequest for IE8 if enablesXDR is true
2185 // because loading bar keeps flashing when using jsonp-polling
2186 // https://github.com/yujiosaka/socke.io-ie8-loading-example
2187 try {
2188 if ('undefined' != typeof XDomainRequest && !xscheme && enablesXDR) {
2189 return new XDomainRequest();
2190 }
2191 } catch (e) { }
2193 if (!xdomain) {
2194 try {
2195 return new ActiveXObject('Microsoft.XMLHTTP');
2196 } catch(e) { }
2197 }
2198 }
2200 },{"has-cors":23}],11:[function(_dereq_,module,exports){
2201 module.exports = after
2203 function after(count, callback, err_cb) {
2204 var bail = false
2205 err_cb = err_cb || noop
2206 proxy.count = count
2208 return (count === 0) ? callback() : proxy
2210 function proxy(err, result) {
2211 if (proxy.count <= 0) {
2212 throw new Error('after called too many times')
2213 }
2214 --proxy.count
2216 // after first error, rest are passed to err_cb
2217 if (err) {
2218 bail = true
2219 callback(err)
2220 // future error callbacks will go to error handler
2221 callback = err_cb
2222 } else if (proxy.count === 0 && !bail) {
2223 callback(null, result)
2224 }
2225 }
2226 }
2228 function noop() {}
2230 },{}],12:[function(_dereq_,module,exports){
2231 /**
2232 * An abstraction for slicing an arraybuffer even when
2233 * ArrayBuffer.prototype.slice is not supported
2234 *
2235 * @api public
2236 */
2238 module.exports = function(arraybuffer, start, end) {
2239 var bytes = arraybuffer.byteLength;
2240 start = start || 0;
2241 end = end || bytes;
2243 if (arraybuffer.slice) { return arraybuffer.slice(start, end); }
2245 if (start < 0) { start += bytes; }
2246 if (end < 0) { end += bytes; }
2247 if (end > bytes) { end = bytes; }
2249 if (start >= bytes || start >= end || bytes === 0) {
2250 return new ArrayBuffer(0);
2251 }
2253 var abv = new Uint8Array(arraybuffer);
2254 var result = new Uint8Array(end - start);
2255 for (var i = start, ii = 0; i < end; i++, ii++) {
2256 result[ii] = abv[i];
2257 }
2258 return result.buffer;
2259 };
2261 },{}],13:[function(_dereq_,module,exports){
2262 /*
2263 * base64-arraybuffer
2264 * https://github.com/niklasvh/base64-arraybuffer
2265 *
2266 * Copyright (c) 2012 Niklas von Hertzen
2267 * Licensed under the MIT license.
2268 */
2269 (function(chars){
2270 "use strict";
2272 exports.encode = function(arraybuffer) {
2273 var bytes = new Uint8Array(arraybuffer),
2274 i, len = bytes.length, base64 = "";
2276 for (i = 0; i < len; i+=3) {
2277 base64 += chars[bytes[i] >> 2];
2278 base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
2279 base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
2280 base64 += chars[bytes[i + 2] & 63];
2281 }
2283 if ((len % 3) === 2) {
2284 base64 = base64.substring(0, base64.length - 1) + "=";
2285 } else if (len % 3 === 1) {
2286 base64 = base64.substring(0, base64.length - 2) + "==";
2287 }
2289 return base64;
2290 };
2292 exports.decode = function(base64) {
2293 var bufferLength = base64.length * 0.75,
2294 len = base64.length, i, p = 0,
2295 encoded1, encoded2, encoded3, encoded4;
2297 if (base64[base64.length - 1] === "=") {
2298 bufferLength--;
2299 if (base64[base64.length - 2] === "=") {
2300 bufferLength--;
2301 }
2302 }
2304 var arraybuffer = new ArrayBuffer(bufferLength),
2305 bytes = new Uint8Array(arraybuffer);
2307 for (i = 0; i < len; i+=4) {
2308 encoded1 = chars.indexOf(base64[i]);
2309 encoded2 = chars.indexOf(base64[i+1]);
2310 encoded3 = chars.indexOf(base64[i+2]);
2311 encoded4 = chars.indexOf(base64[i+3]);
2313 bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
2314 bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
2315 bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
2316 }
2318 return arraybuffer;
2319 };
2320 })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
2322 },{}],14:[function(_dereq_,module,exports){
2323 (function (global){
2324 /**
2325 * Create a blob builder even when vendor prefixes exist
2326 */
2328 var BlobBuilder = global.BlobBuilder
2329 || global.WebKitBlobBuilder
2330 || global.MSBlobBuilder
2331 || global.MozBlobBuilder;
2333 /**
2334 * Check if Blob constructor is supported
2335 */
2337 var blobSupported = (function() {
2338 try {
2339 var a = new Blob(['hi']);
2340 return a.size === 2;
2341 } catch(e) {
2342 return false;
2343 }
2344 })();
2346 /**
2347 * Check if Blob constructor supports ArrayBufferViews
2348 * Fails in Safari 6, so we need to map to ArrayBuffers there.
2349 */
2351 var blobSupportsArrayBufferView = blobSupported && (function() {
2352 try {
2353 var b = new Blob([new Uint8Array([1,2])]);
2354 return b.size === 2;
2355 } catch(e) {
2356 return false;
2357 }
2358 })();
2360 /**
2361 * Check if BlobBuilder is supported
2362 */
2364 var blobBuilderSupported = BlobBuilder
2365 && BlobBuilder.prototype.append
2366 && BlobBuilder.prototype.getBlob;
2368 /**
2369 * Helper function that maps ArrayBufferViews to ArrayBuffers
2370 * Used by BlobBuilder constructor and old browsers that didn't
2371 * support it in the Blob constructor.
2372 */
2374 function mapArrayBufferViews(ary) {
2375 for (var i = 0; i < ary.length; i++) {
2376 var chunk = ary[i];
2377 if (chunk.buffer instanceof ArrayBuffer) {
2378 var buf = chunk.buffer;
2380 // if this is a subarray, make a copy so we only
2381 // include the subarray region from the underlying buffer
2382 if (chunk.byteLength !== buf.byteLength) {
2383 var copy = new Uint8Array(chunk.byteLength);
2384 copy.set(new Uint8Array(buf, chunk.byteOffset, chunk.byteLength));
2385 buf = copy.buffer;
2386 }
2388 ary[i] = buf;
2389 }
2390 }
2391 }
2393 function BlobBuilderConstructor(ary, options) {
2394 options = options || {};
2396 var bb = new BlobBuilder();
2397 mapArrayBufferViews(ary);
2399 for (var i = 0; i < ary.length; i++) {
2400 bb.append(ary[i]);
2401 }
2403 return (options.type) ? bb.getBlob(options.type) : bb.getBlob();
2404 };
2406 function BlobConstructor(ary, options) {
2407 mapArrayBufferViews(ary);
2408 return new Blob(ary, options || {});
2409 };
2411 module.exports = (function() {
2412 if (blobSupported) {
2413 return blobSupportsArrayBufferView ? global.Blob : BlobConstructor;
2414 } else if (blobBuilderSupported) {
2415 return BlobBuilderConstructor;
2416 } else {
2417 return undefined;
2418 }
2419 })();
2421 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
2422 },{}],15:[function(_dereq_,module,exports){
2424 },{}],16:[function(_dereq_,module,exports){
2426 /**
2427 * Expose `Emitter`.
2428 */
2430 module.exports = Emitter;
2432 /**
2433 * Initialize a new `Emitter`.
2434 *
2435 * @api public
2436 */
2438 function Emitter(obj) {
2439 if (obj) return mixin(obj);
2440 };
2442 /**
2443 * Mixin the emitter properties.
2444 *
2445 * @param {Object} obj
2446 * @return {Object}
2447 * @api private
2448 */
2450 function mixin(obj) {
2451 for (var key in Emitter.prototype) {
2452 obj[key] = Emitter.prototype[key];
2453 }
2454 return obj;
2455 }
2457 /**
2458 * Listen on the given `event` with `fn`.
2459 *
2460 * @param {String} event
2461 * @param {Function} fn
2462 * @return {Emitter}
2463 * @api public
2464 */
2466 Emitter.prototype.on =
2467 Emitter.prototype.addEventListener = function(event, fn){
2468 this._callbacks = this._callbacks || {};
2469 (this._callbacks[event] = this._callbacks[event] || [])
2470 .push(fn);
2471 return this;
2472 };
2474 /**
2475 * Adds an `event` listener that will be invoked a single
2476 * time then automatically removed.
2477 *
2478 * @param {String} event
2479 * @param {Function} fn
2480 * @return {Emitter}
2481 * @api public
2482 */
2484 Emitter.prototype.once = function(event, fn){
2485 var self = this;
2486 this._callbacks = this._callbacks || {};
2488 function on() {
2489 self.off(event, on);
2490 fn.apply(this, arguments);
2491 }
2493 on.fn = fn;
2494 this.on(event, on);
2495 return this;
2496 };
2498 /**
2499 * Remove the given callback for `event` or all
2500 * registered callbacks.
2501 *
2502 * @param {String} event
2503 * @param {Function} fn
2504 * @return {Emitter}
2505 * @api public
2506 */
2508 Emitter.prototype.off =
2509 Emitter.prototype.removeListener =
2510 Emitter.prototype.removeAllListeners =
2511 Emitter.prototype.removeEventListener = function(event, fn){
2512 this._callbacks = this._callbacks || {};
2514 // all
2515 if (0 == arguments.length) {
2516 this._callbacks = {};
2517 return this;
2518 }
2520 // specific event
2521 var callbacks = this._callbacks[event];
2522 if (!callbacks) return this;
2524 // remove all handlers
2525 if (1 == arguments.length) {
2526 delete this._callbacks[event];
2527 return this;
2528 }
2530 // remove specific handler
2531 var cb;
2532 for (var i = 0; i < callbacks.length; i++) {
2533 cb = callbacks[i];
2534 if (cb === fn || cb.fn === fn) {
2535 callbacks.splice(i, 1);
2536 break;
2537 }
2538 }
2539 return this;
2540 };
2542 /**
2543 * Emit `event` with the given args.
2544 *
2545 * @param {String} event
2546 * @param {Mixed} ...
2547 * @return {Emitter}
2548 */
2550 Emitter.prototype.emit = function(event){
2551 this._callbacks = this._callbacks || {};
2552 var args = [].slice.call(arguments, 1)
2553 , callbacks = this._callbacks[event];
2555 if (callbacks) {
2556 callbacks = callbacks.slice(0);
2557 for (var i = 0, len = callbacks.length; i < len; ++i) {
2558 callbacks[i].apply(this, args);
2559 }
2560 }
2562 return this;
2563 };
2565 /**
2566 * Return array of callbacks for `event`.
2567 *
2568 * @param {String} event
2569 * @return {Array}
2570 * @api public
2571 */
2573 Emitter.prototype.listeners = function(event){
2574 this._callbacks = this._callbacks || {};
2575 return this._callbacks[event] || [];
2576 };
2578 /**
2579 * Check if this emitter has `event` handlers.
2580 *
2581 * @param {String} event
2582 * @return {Boolean}
2583 * @api public
2584 */
2586 Emitter.prototype.hasListeners = function(event){
2587 return !! this.listeners(event).length;
2588 };
2590 },{}],17:[function(_dereq_,module,exports){
2592 module.exports = function(a, b){
2593 var fn = function(){};
2594 fn.prototype = b.prototype;
2595 a.prototype = new fn;
2596 a.prototype.constructor = a;
2597 };
2598 },{}],18:[function(_dereq_,module,exports){
2600 /**
2601 * This is the web browser implementation of `debug()`.
2602 *
2603 * Expose `debug()` as the module.
2604 */
2606 exports = module.exports = _dereq_('./debug');
2607 exports.log = log;
2608 exports.formatArgs = formatArgs;
2609 exports.save = save;
2610 exports.load = load;
2611 exports.useColors = useColors;
2612 exports.storage = 'undefined' != typeof chrome
2613 && 'undefined' != typeof chrome.storage
2614 ? chrome.storage.local
2615 : localstorage();
2617 /**
2618 * Colors.
2619 */
2621 exports.colors = [
2622 'lightseagreen',
2623 'forestgreen',
2624 'goldenrod',
2625 'dodgerblue',
2626 'darkorchid',
2627 'crimson'
2628 ];
2630 /**
2631 * Currently only WebKit-based Web Inspectors, Firefox >= v31,
2632 * and the Firebug extension (any Firefox version) are known
2633 * to support "%c" CSS customizations.
2634 *
2635 * TODO: add a `localStorage` variable to explicitly enable/disable colors
2636 */
2638 function useColors() {
2639 // is webkit? http://stackoverflow.com/a/16459606/376773
2640 return ('WebkitAppearance' in document.documentElement.style) ||
2641 // is firebug? http://stackoverflow.com/a/398120/376773
2642 (window.console && (console.firebug || (console.exception && console.table))) ||
2643 // is firefox >= v31?
2644 // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
2645 (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
2646 }
2648 /**
2649 * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
2650 */
2652 exports.formatters.j = function(v) {
2653 return JSON.stringify(v);
2654 };
2657 /**
2658 * Colorize log arguments if enabled.
2659 *
2660 * @api public
2661 */
2663 function formatArgs() {
2664 var args = arguments;
2665 var useColors = this.useColors;
2667 args[0] = (useColors ? '%c' : '')
2668 + this.namespace
2669 + (useColors ? ' %c' : ' ')
2670 + args[0]
2671 + (useColors ? '%c ' : ' ')
2672 + '+' + exports.humanize(this.diff);
2674 if (!useColors) return args;
2676 var c = 'color: ' + this.color;
2677 args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
2679 // the final "%c" is somewhat tricky, because there could be other
2680 // arguments passed either before or after the %c, so we need to
2681 // figure out the correct index to insert the CSS into
2682 var index = 0;
2683 var lastC = 0;
2684 args[0].replace(/%[a-z%]/g, function(match) {
2685 if ('%%' === match) return;
2686 index++;
2687 if ('%c' === match) {
2688 // we only are interested in the *last* %c
2689 // (the user may have provided their own)
2690 lastC = index;
2691 }
2692 });
2694 args.splice(lastC, 0, c);
2695 return args;
2696 }
2698 /**
2699 * Invokes `console.log()` when available.
2700 * No-op when `console.log` is not a "function".
2701 *
2702 * @api public
2703 */
2705 function log() {
2706 // this hackery is required for IE8/9, where
2707 // the `console.log` function doesn't have 'apply'
2708 return 'object' === typeof console
2709 && console.log
2710 && Function.prototype.apply.call(console.log, console, arguments);
2711 }
2713 /**
2714 * Save `namespaces`.
2715 *
2716 * @param {String} namespaces
2717 * @api private
2718 */
2720 function save(namespaces) {
2721 try {
2722 if (null == namespaces) {
2723 exports.storage.removeItem('debug');
2724 } else {
2725 exports.storage.debug = namespaces;
2726 }
2727 } catch(e) {}
2728 }
2730 /**
2731 * Load `namespaces`.
2732 *
2733 * @return {String} returns the previously persisted debug modes
2734 * @api private
2735 */
2737 function load() {
2738 var r;
2739 try {
2740 r = exports.storage.debug;
2741 } catch(e) {}
2742 return r;
2743 }
2745 /**
2746 * Enable namespaces listed in `localStorage.debug` initially.
2747 */
2749 exports.enable(load());
2751 /**
2752 * Localstorage attempts to return the localstorage.
2753 *
2754 * This is necessary because safari throws
2755 * when a user disables cookies/localstorage
2756 * and you attempt to access it.
2757 *
2758 * @return {LocalStorage}
2759 * @api private
2760 */
2762 function localstorage(){
2763 try {
2764 return window.localStorage;
2765 } catch (e) {}
2766 }
2768 },{"./debug":19}],19:[function(_dereq_,module,exports){
2770 /**
2771 * This is the common logic for both the Node.js and web browser
2772 * implementations of `debug()`.
2773 *
2774 * Expose `debug()` as the module.
2775 */
2777 exports = module.exports = debug;
2778 exports.coerce = coerce;
2779 exports.disable = disable;
2780 exports.enable = enable;
2781 exports.enabled = enabled;
2782 exports.humanize = _dereq_('ms');
2784 /**
2785 * The currently active debug mode names, and names to skip.
2786 */
2788 exports.names = [];
2789 exports.skips = [];
2791 /**
2792 * Map of special "%n" handling functions, for the debug "format" argument.
2793 *
2794 * Valid key names are a single, lowercased letter, i.e. "n".
2795 */
2797 exports.formatters = {};
2799 /**
2800 * Previously assigned color.
2801 */
2803 var prevColor = 0;
2805 /**
2806 * Previous log timestamp.
2807 */
2809 var prevTime;
2811 /**
2812 * Select a color.
2813 *
2814 * @return {Number}
2815 * @api private
2816 */
2818 function selectColor() {
2819 return exports.colors[prevColor++ % exports.colors.length];
2820 }
2822 /**
2823 * Create a debugger with the given `namespace`.
2824 *
2825 * @param {String} namespace
2826 * @return {Function}
2827 * @api public
2828 */
2830 function debug(namespace) {
2832 // define the `disabled` version
2833 function disabled() {
2834 }
2835 disabled.enabled = false;
2837 // define the `enabled` version
2838 function enabled() {
2840 var self = enabled;
2842 // set `diff` timestamp
2843 var curr = +new Date();
2844 var ms = curr - (prevTime || curr);
2845 self.diff = ms;
2846 self.prev = prevTime;
2847 self.curr = curr;
2848 prevTime = curr;
2850 // add the `color` if not set
2851 if (null == self.useColors) self.useColors = exports.useColors();
2852 if (null == self.color && self.useColors) self.color = selectColor();
2854 var args = Array.prototype.slice.call(arguments);
2856 args[0] = exports.coerce(args[0]);
2858 if ('string' !== typeof args[0]) {
2859 // anything else let's inspect with %o
2860 args = ['%o'].concat(args);
2861 }
2863 // apply any `formatters` transformations
2864 var index = 0;
2865 args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
2866 // if we encounter an escaped % then don't increase the array index
2867 if (match === '%%') return match;
2868 index++;
2869 var formatter = exports.formatters[format];
2870 if ('function' === typeof formatter) {
2871 var val = args[index];
2872 match = formatter.call(self, val);
2874 // now we need to remove `args[index]` since it's inlined in the `format`
2875 args.splice(index, 1);
2876 index--;
2877 }
2878 return match;
2879 });
2881 if ('function' === typeof exports.formatArgs) {
2882 args = exports.formatArgs.apply(self, args);
2883 }
2884 var logFn = enabled.log || exports.log || console.log.bind(console);
2885 logFn.apply(self, args);
2886 }
2887 enabled.enabled = true;
2889 var fn = exports.enabled(namespace) ? enabled : disabled;
2891 fn.namespace = namespace;
2893 return fn;
2894 }
2896 /**
2897 * Enables a debug mode by namespaces. This can include modes
2898 * separated by a colon and wildcards.
2899 *
2900 * @param {String} namespaces
2901 * @api public
2902 */
2904 function enable(namespaces) {
2905 exports.save(namespaces);
2907 var split = (namespaces || '').split(/[\s,]+/);
2908 var len = split.length;
2910 for (var i = 0; i < len; i++) {
2911 if (!split[i]) continue; // ignore empty strings
2912 namespaces = split[i].replace(/\*/g, '.*?');
2913 if (namespaces[0] === '-') {
2914 exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
2915 } else {
2916 exports.names.push(new RegExp('^' + namespaces + '$'));
2917 }
2918 }
2919 }
2921 /**
2922 * Disable debug output.
2923 *
2924 * @api public
2925 */
2927 function disable() {
2928 exports.enable('');
2929 }
2931 /**
2932 * Returns true if the given mode name is enabled, false otherwise.
2933 *
2934 * @param {String} name
2935 * @return {Boolean}
2936 * @api public
2937 */
2939 function enabled(name) {
2940 var i, len;
2941 for (i = 0, len = exports.skips.length; i < len; i++) {
2942 if (exports.skips[i].test(name)) {
2943 return false;
2944 }
2945 }
2946 for (i = 0, len = exports.names.length; i < len; i++) {
2947 if (exports.names[i].test(name)) {
2948 return true;
2949 }
2950 }
2951 return false;
2952 }
2954 /**
2955 * Coerce `val`.
2956 *
2957 * @param {Mixed} val
2958 * @return {Mixed}
2959 * @api private
2960 */
2962 function coerce(val) {
2963 if (val instanceof Error) return val.stack || val.message;
2964 return val;
2965 }
2967 },{"ms":26}],20:[function(_dereq_,module,exports){
2968 (function (global){
2969 /**
2970 * Module dependencies.
2971 */
2973 var keys = _dereq_('./keys');
2974 var hasBinary = _dereq_('has-binary');
2975 var sliceBuffer = _dereq_('arraybuffer.slice');
2976 var base64encoder = _dereq_('base64-arraybuffer');
2977 var after = _dereq_('after');
2978 var utf8 = _dereq_('utf8');
2980 /**
2981 * Check if we are running an android browser. That requires us to use
2982 * ArrayBuffer with polling transports...
2983 *
2984 * http://ghinda.net/jpeg-blob-ajax-android/
2985 */
2987 var isAndroid = navigator.userAgent.match(/Android/i);
2989 /**
2990 * Check if we are running in PhantomJS.
2991 * Uploading a Blob with PhantomJS does not work correctly, as reported here:
2992 * https://github.com/ariya/phantomjs/issues/11395
2993 * @type boolean
2994 */
2995 var isPhantomJS = /PhantomJS/i.test(navigator.userAgent);
2997 /**
2998 * When true, avoids using Blobs to encode payloads.
2999 * @type boolean
3000 */
3001 var dontSendBlobs = isAndroid || isPhantomJS;
3003 /**
3004 * Current protocol version.
3005 */
3007 exports.protocol = 3;
3009 /**
3010 * Packet types.
3011 */
3013 var packets = exports.packets = {
3014 open: 0 // non-ws
3015 , close: 1 // non-ws
3016 , ping: 2
3017 , pong: 3
3018 , message: 4
3019 , upgrade: 5
3020 , noop: 6
3021 };
3023 var packetslist = keys(packets);
3025 /**
3026 * Premade error packet.
3027 */
3029 var err = { type: 'error', data: 'parser error' };
3031 /**
3032 * Create a blob api even for blob builder when vendor prefixes exist
3033 */
3035 var Blob = _dereq_('blob');
3037 /**
3038 * Encodes a packet.
3039 *
3040 * <packet type id> [ <data> ]
3041 *
3042 * Example:
3043 *
3044 * 5hello world
3045 * 3
3046 * 4
3047 *
3048 * Binary is encoded in an identical principle
3049 *
3050 * @api private
3051 */
3053 exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
3054 if ('function' == typeof supportsBinary) {
3055 callback = supportsBinary;
3056 supportsBinary = false;
3057 }
3059 if ('function' == typeof utf8encode) {
3060 callback = utf8encode;
3061 utf8encode = null;
3062 }
3064 var data = (packet.data === undefined)
3065 ? undefined
3066 : packet.data.buffer || packet.data;
3068 if (global.ArrayBuffer && data instanceof ArrayBuffer) {
3069 return encodeArrayBuffer(packet, supportsBinary, callback);
3070 } else if (Blob && data instanceof global.Blob) {
3071 return encodeBlob(packet, supportsBinary, callback);
3072 }
3074 // might be an object with { base64: true, data: dataAsBase64String }
3075 if (data && data.base64) {
3076 return encodeBase64Object(packet, callback);
3077 }
3079 // Sending data as a utf-8 string
3080 var encoded = packets[packet.type];
3082 // data fragment is optional
3083 if (undefined !== packet.data) {
3084 encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
3085 }
3087 return callback('' + encoded);
3089 };
3091 function encodeBase64Object(packet, callback) {
3092 // packet data is an object { base64: true, data: dataAsBase64String }
3093 var message = 'b' + exports.packets[packet.type] + packet.data.data;
3094 return callback(message);
3095 }
3097 /**
3098 * Encode packet helpers for binary types
3099 */
3101 function encodeArrayBuffer(packet, supportsBinary, callback) {
3102 if (!supportsBinary) {
3103 return exports.encodeBase64Packet(packet, callback);
3104 }
3106 var data = packet.data;
3107 var contentArray = new Uint8Array(data);
3108 var resultBuffer = new Uint8Array(1 + data.byteLength);
3110 resultBuffer[0] = packets[packet.type];
3111 for (var i = 0; i < contentArray.length; i++) {
3112 resultBuffer[i+1] = contentArray[i];
3113 }
3115 return callback(resultBuffer.buffer);
3116 }
3118 function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) {
3119 if (!supportsBinary) {
3120 return exports.encodeBase64Packet(packet, callback);
3121 }
3123 var fr = new FileReader();
3124 fr.onload = function() {
3125 packet.data = fr.result;
3126 exports.encodePacket(packet, supportsBinary, true, callback);
3127 };
3128 return fr.readAsArrayBuffer(packet.data);
3129 }
3131 function encodeBlob(packet, supportsBinary, callback) {
3132 if (!supportsBinary) {
3133 return exports.encodeBase64Packet(packet, callback);
3134 }
3136 if (dontSendBlobs) {
3137 return encodeBlobAsArrayBuffer(packet, supportsBinary, callback);
3138 }
3140 var length = new Uint8Array(1);
3141 length[0] = packets[packet.type];
3142 var blob = new Blob([length.buffer, packet.data]);
3144 return callback(blob);
3145 }
3147 /**
3148 * Encodes a packet with binary data in a base64 string
3149 *
3150 * @param {Object} packet, has `type` and `data`
3151 * @return {String} base64 encoded message
3152 */
3154 exports.encodeBase64Packet = function(packet, callback) {
3155 var message = 'b' + exports.packets[packet.type];
3156 if (Blob && packet.data instanceof global.Blob) {
3157 var fr = new FileReader();
3158 fr.onload = function() {
3159 var b64 = fr.result.split(',')[1];
3160 callback(message + b64);
3161 };
3162 return fr.readAsDataURL(packet.data);
3163 }
3165 var b64data;
3166 try {
3167 b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data));
3168 } catch (e) {
3169 // iPhone Safari doesn't let you apply with typed arrays
3170 var typed = new Uint8Array(packet.data);
3171 var basic = new Array(typed.length);
3172 for (var i = 0; i < typed.length; i++) {
3173 basic[i] = typed[i];
3174 }
3175 b64data = String.fromCharCode.apply(null, basic);
3176 }
3177 message += global.btoa(b64data);
3178 return callback(message);
3179 };
3181 /**
3182 * Decodes a packet. Changes format to Blob if requested.
3183 *
3184 * @return {Object} with `type` and `data` (if any)
3185 * @api private
3186 */
3188 exports.decodePacket = function (data, binaryType, utf8decode) {
3189 // String data
3190 if (typeof data == 'string' || data === undefined) {
3191 if (data.charAt(0) == 'b') {
3192 return exports.decodeBase64Packet(data.substr(1), binaryType);
3193 }
3195 if (utf8decode) {
3196 try {
3197 data = utf8.decode(data);
3198 } catch (e) {
3199 return err;
3200 }
3201 }
3202 var type = data.charAt(0);
3204 if (Number(type) != type || !packetslist[type]) {
3205 return err;
3206 }
3208 if (data.length > 1) {
3209 return { type: packetslist[type], data: data.substring(1) };
3210 } else {
3211 return { type: packetslist[type] };
3212 }
3213 }
3215 var asArray = new Uint8Array(data);
3216 var type = asArray[0];
3217 var rest = sliceBuffer(data, 1);
3218 if (Blob && binaryType === 'blob') {
3219 rest = new Blob([rest]);
3220 }
3221 return { type: packetslist[type], data: rest };
3222 };
3224 /**
3225 * Decodes a packet encoded in a base64 string
3226 *
3227 * @param {String} base64 encoded message
3228 * @return {Object} with `type` and `data` (if any)
3229 */
3231 exports.decodeBase64Packet = function(msg, binaryType) {
3232 var type = packetslist[msg.charAt(0)];
3233 if (!global.ArrayBuffer) {
3234 return { type: type, data: { base64: true, data: msg.substr(1) } };
3235 }
3237 var data = base64encoder.decode(msg.substr(1));
3239 if (binaryType === 'blob' && Blob) {
3240 data = new Blob([data]);
3241 }
3243 return { type: type, data: data };
3244 };
3246 /**
3247 * Encodes multiple messages (payload).
3248 *
3249 * <length>:data
3250 *
3251 * Example:
3252 *
3253 * 11:hello world2:hi
3254 *
3255 * If any contents are binary, they will be encoded as base64 strings. Base64
3256 * encoded strings are marked with a b before the length specifier
3257 *
3258 * @param {Array} packets
3259 * @api private
3260 */
3262 exports.encodePayload = function (packets, supportsBinary, callback) {
3263 if (typeof supportsBinary == 'function') {
3264 callback = supportsBinary;
3265 supportsBinary = null;
3266 }
3268 var isBinary = hasBinary(packets);
3270 if (supportsBinary && isBinary) {
3271 if (Blob && !dontSendBlobs) {
3272 return exports.encodePayloadAsBlob(packets, callback);
3273 }
3275 return exports.encodePayloadAsArrayBuffer(packets, callback);
3276 }
3278 if (!packets.length) {
3279 return callback('0:');
3280 }
3282 function setLengthHeader(message) {
3283 return message.length + ':' + message;
3284 }
3286 function encodeOne(packet, doneCallback) {
3287 exports.encodePacket(packet, !isBinary ? false : supportsBinary, true, function(message) {
3288 doneCallback(null, setLengthHeader(message));
3289 });
3290 }
3292 map(packets, encodeOne, function(err, results) {
3293 return callback(results.join(''));
3294 });
3295 };
3297 /**
3298 * Async array map using after
3299 */
3301 function map(ary, each, done) {
3302 var result = new Array(ary.length);
3303 var next = after(ary.length, done);
3305 var eachWithIndex = function(i, el, cb) {
3306 each(el, function(error, msg) {
3307 result[i] = msg;
3308 cb(error, result);
3309 });
3310 };
3312 for (var i = 0; i < ary.length; i++) {
3313 eachWithIndex(i, ary[i], next);
3314 }
3315 }
3317 /*
3318 * Decodes data when a payload is maybe expected. Possible binary contents are
3319 * decoded from their base64 representation
3320 *
3321 * @param {String} data, callback method
3322 * @api public
3323 */
3325 exports.decodePayload = function (data, binaryType, callback) {
3326 if (typeof data != 'string') {
3327 return exports.decodePayloadAsBinary(data, binaryType, callback);
3328 }
3330 if (typeof binaryType === 'function') {
3331 callback = binaryType;
3332 binaryType = null;
3333 }
3335 var packet;
3336 if (data == '') {
3337 // parser error - ignoring payload
3338 return callback(err, 0, 1);
3339 }
3341 var length = ''
3342 , n, msg;
3344 for (var i = 0, l = data.length; i < l; i++) {
3345 var chr = data.charAt(i);
3347 if (':' != chr) {
3348 length += chr;
3349 } else {
3350 if ('' == length || (length != (n = Number(length)))) {
3351 // parser error - ignoring payload
3352 return callback(err, 0, 1);
3353 }
3355 msg = data.substr(i + 1, n);
3357 if (length != msg.length) {
3358 // parser error - ignoring payload
3359 return callback(err, 0, 1);
3360 }
3362 if (msg.length) {
3363 packet = exports.decodePacket(msg, binaryType, true);
3365 if (err.type == packet.type && err.data == packet.data) {
3366 // parser error in individual packet - ignoring payload
3367 return callback(err, 0, 1);
3368 }
3370 var ret = callback(packet, i + n, l);
3371 if (false === ret) return;
3372 }
3374 // advance cursor
3375 i += n;
3376 length = '';
3377 }
3378 }
3380 if (length != '') {
3381 // parser error - ignoring payload
3382 return callback(err, 0, 1);
3383 }
3385 };
3387 /**
3388 * Encodes multiple messages (payload) as binary.
3389 *
3390 * <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
3391 * 255><data>
3392 *
3393 * Example:
3394 * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
3395 *
3396 * @param {Array} packets
3397 * @return {ArrayBuffer} encoded payload
3398 * @api private
3399 */
3401 exports.encodePayloadAsArrayBuffer = function(packets, callback) {
3402 if (!packets.length) {
3403 return callback(new ArrayBuffer(0));
3404 }
3406 function encodeOne(packet, doneCallback) {
3407 exports.encodePacket(packet, true, true, function(data) {
3408 return doneCallback(null, data);
3409 });
3410 }
3412 map(packets, encodeOne, function(err, encodedPackets) {
3413 var totalLength = encodedPackets.reduce(function(acc, p) {
3414 var len;
3415 if (typeof p === 'string'){
3416 len = p.length;
3417 } else {
3418 len = p.byteLength;
3419 }
3420 return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2
3421 }, 0);
3423 var resultArray = new Uint8Array(totalLength);
3425 var bufferIndex = 0;
3426 encodedPackets.forEach(function(p) {
3427 var isString = typeof p === 'string';
3428 var ab = p;
3429 if (isString) {
3430 var view = new Uint8Array(p.length);
3431 for (var i = 0; i < p.length; i++) {
3432 view[i] = p.charCodeAt(i);
3433 }
3434 ab = view.buffer;
3435 }
3437 if (isString) { // not true binary
3438 resultArray[bufferIndex++] = 0;
3439 } else { // true binary
3440 resultArray[bufferIndex++] = 1;
3441 }
3443 var lenStr = ab.byteLength.toString();
3444 for (var i = 0; i < lenStr.length; i++) {
3445 resultArray[bufferIndex++] = parseInt(lenStr[i]);
3446 }
3447 resultArray[bufferIndex++] = 255;
3449 var view = new Uint8Array(ab);
3450 for (var i = 0; i < view.length; i++) {
3451 resultArray[bufferIndex++] = view[i];
3452 }
3453 });
3455 return callback(resultArray.buffer);
3456 });
3457 };
3459 /**
3460 * Encode as Blob
3461 */
3463 exports.encodePayloadAsBlob = function(packets, callback) {
3464 function encodeOne(packet, doneCallback) {
3465 exports.encodePacket(packet, true, true, function(encoded) {
3466 var binaryIdentifier = new Uint8Array(1);
3467 binaryIdentifier[0] = 1;
3468 if (typeof encoded === 'string') {
3469 var view = new Uint8Array(encoded.length);
3470 for (var i = 0; i < encoded.length; i++) {
3471 view[i] = encoded.charCodeAt(i);
3472 }
3473 encoded = view.buffer;
3474 binaryIdentifier[0] = 0;
3475 }
3477 var len = (encoded instanceof ArrayBuffer)
3478 ? encoded.byteLength
3479 : encoded.size;
3481 var lenStr = len.toString();
3482 var lengthAry = new Uint8Array(lenStr.length + 1);
3483 for (var i = 0; i < lenStr.length; i++) {
3484 lengthAry[i] = parseInt(lenStr[i]);
3485 }
3486 lengthAry[lenStr.length] = 255;
3488 if (Blob) {
3489 var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]);
3490 doneCallback(null, blob);
3491 }
3492 });
3493 }
3495 map(packets, encodeOne, function(err, results) {
3496 return callback(new Blob(results));
3497 });
3498 };
3500 /*
3501 * Decodes data when a payload is maybe expected. Strings are decoded by
3502 * interpreting each byte as a key code for entries marked to start with 0. See
3503 * description of encodePayloadAsBinary
3504 *
3505 * @param {ArrayBuffer} data, callback method
3506 * @api public
3507 */
3509 exports.decodePayloadAsBinary = function (data, binaryType, callback) {
3510 if (typeof binaryType === 'function') {
3511 callback = binaryType;
3512 binaryType = null;
3513 }
3515 var bufferTail = data;
3516 var buffers = [];
3518 var numberTooLong = false;
3519 while (bufferTail.byteLength > 0) {
3520 var tailArray = new Uint8Array(bufferTail);
3521 var isString = tailArray[0] === 0;
3522 var msgLength = '';
3524 for (var i = 1; ; i++) {
3525 if (tailArray[i] == 255) break;
3527 if (msgLength.length > 310) {
3528 numberTooLong = true;
3529 break;
3530 }
3532 msgLength += tailArray[i];
3533 }
3535 if(numberTooLong) return callback(err, 0, 1);
3537 bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length);
3538 msgLength = parseInt(msgLength);
3540 var msg = sliceBuffer(bufferTail, 0, msgLength);
3541 if (isString) {
3542 try {
3543 msg = String.fromCharCode.apply(null, new Uint8Array(msg));
3544 } catch (e) {
3545 // iPhone Safari doesn't let you apply to typed arrays
3546 var typed = new Uint8Array(msg);
3547 msg = '';
3548 for (var i = 0; i < typed.length; i++) {
3549 msg += String.fromCharCode(typed[i]);
3550 }
3551 }
3552 }
3554 buffers.push(msg);
3555 bufferTail = sliceBuffer(bufferTail, msgLength);
3556 }
3558 var total = buffers.length;
3559 buffers.forEach(function(buffer, i) {
3560 callback(exports.decodePacket(buffer, binaryType, true), i, total);
3561 });
3562 };
3564 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
3565 },{"./keys":21,"after":11,"arraybuffer.slice":12,"base64-arraybuffer":13,"blob":14,"has-binary":22,"utf8":30}],21:[function(_dereq_,module,exports){
3567 /**
3568 * Gets the keys for an object.
3569 *
3570 * @return {Array} keys
3571 * @api private
3572 */
3574 module.exports = Object.keys || function keys (obj){
3575 var arr = [];
3576 var has = Object.prototype.hasOwnProperty;
3578 for (var i in obj) {
3579 if (has.call(obj, i)) {
3580 arr.push(i);
3581 }
3582 }
3583 return arr;
3584 };
3586 },{}],22:[function(_dereq_,module,exports){
3587 (function (global){
3589 /*
3590 * Module requirements.
3591 */
3593 var isArray = _dereq_('isarray');
3595 /**
3596 * Module exports.
3597 */
3599 module.exports = hasBinary;
3601 /**
3602 * Checks for binary data.
3603 *
3604 * Right now only Buffer and ArrayBuffer are supported..
3605 *
3606 * @param {Object} anything
3607 * @api public
3608 */
3610 function hasBinary(data) {
3612 function _hasBinary(obj) {
3613 if (!obj) return false;
3615 if ( (global.Buffer && global.Buffer.isBuffer(obj)) ||
3616 (global.ArrayBuffer && obj instanceof ArrayBuffer) ||
3617 (global.Blob && obj instanceof Blob) ||
3618 (global.File && obj instanceof File)
3619 ) {
3620 return true;
3621 }
3623 if (isArray(obj)) {
3624 for (var i = 0; i < obj.length; i++) {
3625 if (_hasBinary(obj[i])) {
3626 return true;
3627 }
3628 }
3629 } else if (obj && 'object' == typeof obj) {
3630 if (obj.toJSON) {
3631 obj = obj.toJSON();
3632 }
3634 for (var key in obj) {
3635 if (Object.prototype.hasOwnProperty.call(obj, key) && _hasBinary(obj[key])) {
3636 return true;
3637 }
3638 }
3639 }
3641 return false;
3642 }
3644 return _hasBinary(data);
3645 }
3647 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
3648 },{"isarray":25}],23:[function(_dereq_,module,exports){
3650 /**
3651 * Module exports.
3652 *
3653 * Logic borrowed from Modernizr:
3654 *
3655 * - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js
3656 */
3658 try {
3659 module.exports = typeof XMLHttpRequest !== 'undefined' &&
3660 'withCredentials' in new XMLHttpRequest();
3661 } catch (err) {
3662 // if XMLHttp support is disabled in IE then it will throw
3663 // when trying to create
3664 module.exports = false;
3665 }
3667 },{}],24:[function(_dereq_,module,exports){
3669 var indexOf = [].indexOf;
3671 module.exports = function(arr, obj){
3672 if (indexOf) return arr.indexOf(obj);
3673 for (var i = 0; i < arr.length; ++i) {
3674 if (arr[i] === obj) return i;
3675 }
3676 return -1;
3677 };
3678 },{}],25:[function(_dereq_,module,exports){
3679 module.exports = Array.isArray || function (arr) {
3680 return Object.prototype.toString.call(arr) == '[object Array]';
3681 };
3683 },{}],26:[function(_dereq_,module,exports){
3684 /**
3685 * Helpers.
3686 */
3688 var s = 1000;
3689 var m = s * 60;
3690 var h = m * 60;
3691 var d = h * 24;
3692 var y = d * 365.25;
3694 /**
3695 * Parse or format the given `val`.
3696 *
3697 * Options:
3698 *
3699 * - `long` verbose formatting [false]
3700 *
3701 * @param {String|Number} val
3702 * @param {Object} options
3703 * @return {String|Number}
3704 * @api public
3705 */
3707 module.exports = function(val, options){
3708 options = options || {};
3709 if ('string' == typeof val) return parse(val);
3710 return options.long
3711 ? long(val)
3712 : short(val);
3713 };
3715 /**
3716 * Parse the given `str` and return milliseconds.
3717 *
3718 * @param {String} str
3719 * @return {Number}
3720 * @api private
3721 */
3723 function parse(str) {
3724 str = '' + str;
3725 if (str.length > 10000) return;
3726 var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
3727 if (!match) return;
3728 var n = parseFloat(match[1]);
3729 var type = (match[2] || 'ms').toLowerCase();
3730 switch (type) {
3731 case 'years':
3732 case 'year':
3733 case 'yrs':
3734 case 'yr':
3735 case 'y':
3736 return n * y;
3737 case 'days':
3738 case 'day':
3739 case 'd':
3740 return n * d;
3741 case 'hours':
3742 case 'hour':
3743 case 'hrs':
3744 case 'hr':
3745 case 'h':
3746 return n * h;
3747 case 'minutes':
3748 case 'minute':
3749 case 'mins':
3750 case 'min':
3751 case 'm':
3752 return n * m;
3753 case 'seconds':
3754 case 'second':
3755 case 'secs':
3756 case 'sec':
3757 case 's':
3758 return n * s;
3759 case 'milliseconds':
3760 case 'millisecond':
3761 case 'msecs':
3762 case 'msec':
3763 case 'ms':
3764 return n;
3765 }
3766 }
3768 /**
3769 * Short format for `ms`.
3770 *
3771 * @param {Number} ms
3772 * @return {String}
3773 * @api private
3774 */
3776 function short(ms) {
3777 if (ms >= d) return Math.round(ms / d) + 'd';
3778 if (ms >= h) return Math.round(ms / h) + 'h';
3779 if (ms >= m) return Math.round(ms / m) + 'm';
3780 if (ms >= s) return Math.round(ms / s) + 's';
3781 return ms + 'ms';
3782 }
3784 /**
3785 * Long format for `ms`.
3786 *
3787 * @param {Number} ms
3788 * @return {String}
3789 * @api private
3790 */
3792 function long(ms) {
3793 return plural(ms, d, 'day')
3794 || plural(ms, h, 'hour')
3795 || plural(ms, m, 'minute')
3796 || plural(ms, s, 'second')
3797 || ms + ' ms';
3798 }
3800 /**
3801 * Pluralization helper.
3802 */
3804 function plural(ms, n, name) {
3805 if (ms < n) return;
3806 if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
3807 return Math.ceil(ms / n) + ' ' + name + 's';
3808 }
3810 },{}],27:[function(_dereq_,module,exports){
3811 (function (global){
3812 /**
3813 * JSON parse.
3814 *
3815 * @see Based on jQuery#parseJSON (MIT) and JSON2
3816 * @api private
3817 */
3819 var rvalidchars = /^[\],:{}\s]*$/;
3820 var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
3821 var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
3822 var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
3823 var rtrimLeft = /^\s+/;
3824 var rtrimRight = /\s+$/;
3826 module.exports = function parsejson(data) {
3827 if ('string' != typeof data || !data) {
3828 return null;
3829 }
3831 data = data.replace(rtrimLeft, '').replace(rtrimRight, '');
3833 // Attempt to parse using the native JSON parser first
3834 if (global.JSON && JSON.parse) {
3835 return JSON.parse(data);
3836 }
3838 if (rvalidchars.test(data.replace(rvalidescape, '@')
3839 .replace(rvalidtokens, ']')
3840 .replace(rvalidbraces, ''))) {
3841 return (new Function('return ' + data))();
3842 }
3843 };
3844 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
3845 },{}],28:[function(_dereq_,module,exports){
3846 /**
3847 * Compiles a querystring
3848 * Returns string representation of the object
3849 *
3850 * @param {Object}
3851 * @api private
3852 */
3854 exports.encode = function (obj) {
3855 var str = '';
3857 for (var i in obj) {
3858 if (obj.hasOwnProperty(i)) {
3859 if (str.length) str += '&';
3860 str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
3861 }
3862 }
3864 return str;
3865 };
3867 /**
3868 * Parses a simple querystring into an object
3869 *
3870 * @param {String} qs
3871 * @api private
3872 */
3874 exports.decode = function(qs){
3875 var qry = {};
3876 var pairs = qs.split('&');
3877 for (var i = 0, l = pairs.length; i < l; i++) {
3878 var pair = pairs[i].split('=');
3879 qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
3880 }
3881 return qry;
3882 };
3884 },{}],29:[function(_dereq_,module,exports){
3885 /**
3886 * Parses an URI
3887 *
3888 * @author Steven Levithan <stevenlevithan.com> (MIT license)
3889 * @api private
3890 */
3892 var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
3894 var parts = [
3895 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
3896 ];
3898 module.exports = function parseuri(str) {
3899 var src = str,
3900 b = str.indexOf('['),
3901 e = str.indexOf(']');
3903 if (b != -1 && e != -1) {
3904 str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);
3905 }
3907 var m = re.exec(str || ''),
3908 uri = {},
3909 i = 14;
3911 while (i--) {
3912 uri[parts[i]] = m[i] || '';
3913 }
3915 if (b != -1 && e != -1) {
3916 uri.source = src;
3917 uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');
3918 uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');
3919 uri.ipv6uri = true;
3920 }
3922 return uri;
3923 };
3925 },{}],30:[function(_dereq_,module,exports){
3926 (function (global){
3927 /*! https://mths.be/utf8js v2.0.0 by @mathias */
3928 ;(function(root) {
3930 // Detect free variables `exports`
3931 var freeExports = typeof exports == 'object' && exports;
3933 // Detect free variable `module`
3934 var freeModule = typeof module == 'object' && module &&
3935 module.exports == freeExports && module;
3937 // Detect free variable `global`, from Node.js or Browserified code,
3938 // and use it as `root`
3939 var freeGlobal = typeof global == 'object' && global;
3940 if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
3941 root = freeGlobal;
3942 }
3944 /*--------------------------------------------------------------------------*/
3946 var stringFromCharCode = String.fromCharCode;
3948 // Taken from https://mths.be/punycode
3949 function ucs2decode(string) {
3950 var output = [];
3951 var counter = 0;
3952 var length = string.length;
3953 var value;
3954 var extra;
3955 while (counter < length) {
3956 value = string.charCodeAt(counter++);
3957 if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
3958 // high surrogate, and there is a next character
3959 extra = string.charCodeAt(counter++);
3960 if ((extra & 0xFC00) == 0xDC00) { // low surrogate
3961 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
3962 } else {
3963 // unmatched surrogate; only append this code unit, in case the next
3964 // code unit is the high surrogate of a surrogate pair
3965 output.push(value);
3966 counter--;
3967 }
3968 } else {
3969 output.push(value);
3970 }
3971 }
3972 return output;
3973 }
3975 // Taken from https://mths.be/punycode
3976 function ucs2encode(array) {
3977 var length = array.length;
3978 var index = -1;
3979 var value;
3980 var output = '';
3981 while (++index < length) {
3982 value = array[index];
3983 if (value > 0xFFFF) {
3984 value -= 0x10000;
3985 output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
3986 value = 0xDC00 | value & 0x3FF;
3987 }
3988 output += stringFromCharCode(value);
3989 }
3990 return output;
3991 }
3993 function checkScalarValue(codePoint) {
3994 if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
3995 throw Error(
3996 'Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
3997 ' is not a scalar value'
3998 );
3999 }
4000 }
4001 /*--------------------------------------------------------------------------*/
4003 function createByte(codePoint, shift) {
4004 return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
4005 }
4007 function encodeCodePoint(codePoint) {
4008 if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
4009 return stringFromCharCode(codePoint);
4010 }
4011 var symbol = '';
4012 if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
4013 symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
4014 }
4015 else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
4016 checkScalarValue(codePoint);
4017 symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
4018 symbol += createByte(codePoint, 6);
4019 }
4020 else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
4021 symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
4022 symbol += createByte(codePoint, 12);
4023 symbol += createByte(codePoint, 6);
4024 }
4025 symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
4026 return symbol;
4027 }
4029 function utf8encode(string) {
4030 var codePoints = ucs2decode(string);
4031 var length = codePoints.length;
4032 var index = -1;
4033 var codePoint;
4034 var byteString = '';
4035 while (++index < length) {
4036 codePoint = codePoints[index];
4037 byteString += encodeCodePoint(codePoint);
4038 }
4039 return byteString;
4040 }
4042 /*--------------------------------------------------------------------------*/
4044 function readContinuationByte() {
4045 if (byteIndex >= byteCount) {
4046 throw Error('Invalid byte index');
4047 }
4049 var continuationByte = byteArray[byteIndex] & 0xFF;
4050 byteIndex++;
4052 if ((continuationByte & 0xC0) == 0x80) {
4053 return continuationByte & 0x3F;
4054 }
4056 // If we end up here, it’s not a continuation byte
4057 throw Error('Invalid continuation byte');
4058 }
4060 function decodeSymbol() {
4061 var byte1;
4062 var byte2;
4063 var byte3;
4064 var byte4;
4065 var codePoint;
4067 if (byteIndex > byteCount) {
4068 throw Error('Invalid byte index');
4069 }
4071 if (byteIndex == byteCount) {
4072 return false;
4073 }
4075 // Read first byte
4076 byte1 = byteArray[byteIndex] & 0xFF;
4077 byteIndex++;
4079 // 1-byte sequence (no continuation bytes)
4080 if ((byte1 & 0x80) == 0) {
4081 return byte1;
4082 }
4084 // 2-byte sequence
4085 if ((byte1 & 0xE0) == 0xC0) {
4086 var byte2 = readContinuationByte();
4087 codePoint = ((byte1 & 0x1F) << 6) | byte2;
4088 if (codePoint >= 0x80) {
4089 return codePoint;
4090 } else {
4091 throw Error('Invalid continuation byte');
4092 }
4093 }
4095 // 3-byte sequence (may include unpaired surrogates)
4096 if ((byte1 & 0xF0) == 0xE0) {
4097 byte2 = readContinuationByte();
4098 byte3 = readContinuationByte();
4099 codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
4100 if (codePoint >= 0x0800) {
4101 checkScalarValue(codePoint);
4102 return codePoint;
4103 } else {
4104 throw Error('Invalid continuation byte');
4105 }
4106 }
4108 // 4-byte sequence
4109 if ((byte1 & 0xF8) == 0xF0) {
4110 byte2 = readContinuationByte();
4111 byte3 = readContinuationByte();
4112 byte4 = readContinuationByte();
4113 codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
4114 (byte3 << 0x06) | byte4;
4115 if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
4116 return codePoint;
4117 }
4118 }
4120 throw Error('Invalid UTF-8 detected');
4121 }
4123 var byteArray;
4124 var byteCount;
4125 var byteIndex;
4126 function utf8decode(byteString) {
4127 byteArray = ucs2decode(byteString);
4128 byteCount = byteArray.length;
4129 byteIndex = 0;
4130 var codePoints = [];
4131 var tmp;
4132 while ((tmp = decodeSymbol()) !== false) {
4133 codePoints.push(tmp);
4134 }
4135 return ucs2encode(codePoints);
4136 }
4138 /*--------------------------------------------------------------------------*/
4140 var utf8 = {
4141 'version': '2.0.0',
4142 'encode': utf8encode,
4143 'decode': utf8decode
4144 };
4146 // Some AMD build optimizers, like r.js, check for specific condition patterns
4147 // like the following:
4148 if (
4149 typeof define == 'function' &&
4150 typeof define.amd == 'object' &&
4151 define.amd
4152 ) {
4153 define(function() {
4154 return utf8;
4155 });
4156 } else if (freeExports && !freeExports.nodeType) {
4157 if (freeModule) { // in Node.js or RingoJS v0.8.0+
4158 freeModule.exports = utf8;
4159 } else { // in Narwhal or RingoJS v0.7.0-
4160 var object = {};
4161 var hasOwnProperty = object.hasOwnProperty;
4162 for (var key in utf8) {
4163 hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
4164 }
4165 }
4166 } else { // in Rhino or a web browser
4167 root.utf8 = utf8;
4168 }
4170 }(this));
4172 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {})
4173 },{}],31:[function(_dereq_,module,exports){
4174 'use strict';
4176 var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split('')
4177 , length = 64
4178 , map = {}
4179 , seed = 0
4180 , i = 0
4181 , prev;
4183 /**
4184 * Return a string representing the specified number.
4185 *
4186 * @param {Number} num The number to convert.
4187 * @returns {String} The string representation of the number.
4188 * @api public
4189 */
4190 function encode(num) {
4191 var encoded = '';
4193 do {
4194 encoded = alphabet[num % length] + encoded;
4195 num = Math.floor(num / length);
4196 } while (num > 0);
4198 return encoded;
4199 }
4201 /**
4202 * Return the integer value specified by the given string.
4203 *
4204 * @param {String} str The string to convert.
4205 * @returns {Number} The integer value represented by the string.
4206 * @api public
4207 */
4208 function decode(str) {
4209 var decoded = 0;
4211 for (i = 0; i < str.length; i++) {
4212 decoded = decoded * length + map[str.charAt(i)];
4213 }
4215 return decoded;
4216 }
4218 /**
4219 * Yeast: A tiny growing id generator.
4220 *
4221 * @returns {String} A unique id.
4222 * @api public
4223 */
4224 function yeast() {
4225 var now = encode(+new Date());
4227 if (now !== prev) return seed = 0, prev = now;
4228 return now +'.'+ encode(seed++);
4229 }
4231 //
4232 // Map each character to its index.
4233 //
4234 for (; i < length; i++) map[alphabet[i]] = i;
4236 //
4237 // Expose the `yeast`, `encode` and `decode` functions.
4238 //
4239 yeast.encode = encode;
4240 yeast.decode = decode;
4241 module.exports = yeast;
4243 },{}]},{},[1])(1)
4244 });