vue使用远程在线更新代码
一、main.js
1 import Vue from 'vue' 2 import App from './App' 3 import router from './router' 4 import Vuex from 'vuex' 5 import store from './store' 6 import axios from 'axios' 7 import VueAwesomeSwiper from 'vue-awesome-swiper' 8 import 'swiper/dist/css/swiper.css' 9 // import VueSocketio from 'vue-socket.io' 10 11 Vue.config.productionTip = false 12 Vue.use(Vuex) 13 // Vue.use(VueSocketio) 14 15 16 var ls_mac = "_ioBox_mac_code_key_"; 17 var ls_proid = "_io_ioBox_pro_id_key_"; 18 var ls_protitle = "_io_ioBox_title_key_"; 19 20 //检查mac地址缓存 21 var macCode = localStorage.getItem(ls_mac); 22 console.log("macCode",macCode) 23 if(!macCode){ 24 console.log("macCode222",macCode) 25 //没有则生成mac,提交设备号 26 NWBridge && NWBridge.getMac((mac) => { 27 //alert(str); 28 macCode = mac; 29 localStorage.setItem(ls_mac,macCode); 30 ini && ini.setString('',macCode,()=>{},ini.fileName.macCode); 31 var zipFormData = new FormData(); 32 console.log("macCode333",macCode) 33 zipFormData.append('mac',macCode); 34 zipFormData.append('title',"北京65box(抽奖)"); 35 36 return axios.post('http://iboxmanager.ioart.cn/Api/add/module/device/key/dac509bd90a82719a3569291e12c24a6f1af4bac/',zipFormData).then((res) => { 37 console.log("macCode444",res.data.error_code) 38 console.log("macCode555",res.data.error_code == 0) 39 if (res.data.error_code == 0) { 40 41 NWBridge.checkUpdate(); 42 //增加监听 43 autoUpdateSocket(macCode); 44 } 45 }).catch(function (error) { 46 console.log(error); 47 }) 48 49 } 50 ); 51 }else{ 52 //检查更新 53 NWBridge.checkUpdate(); 54 //增加监听 55 autoUpdateSocket(macCode); 56 } 57 58 59 function autoUpdateSocket(mac) { 60 //监听 用于自动升级处理 61 var socket = io('http://msgsender.ioart.cn:2120'); 62 //建立连接后 63 socket.on('connect', function() { 64 socket.emit('login',mac); 65 }); 66 //接收通信 67 socket.on('coffeeorder', function(msg){ 68 NWBridge.checkUpdate(); 69 }); 70 } 71 72 73 /* eslint-disable no-new */ 74 new Vue({ 75 el: '#app', 76 router, 77 store, 78 components: { App }, 79 template: '<App/>' 80 })
二、index.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width,initial-scale=1.0"> 6 <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" /> 7 <title>my-project</title> 8 </head> 9 <body style="overflow:hidden;"> 10 11 <script src="../static/js/md5.min.js?v=1547962386444"></script> 12 <script src="../static/js/ini.js?v=1547962386444"></script> 13 <script src="../static/js/NWBridge.js?v=1547962386444"></script> 14 <script src="../static/js/socket.io.js?v=<%= htmlWebpackPlugin.options.version %>"></script> 15 <div id="app"></div> 16 <!-- built files will be auto injected --> 17 </body> 18 </html>
三、ini.js (直接引入)
1 var ini = (function () { 2 var that; 3 /*将ini文件更新到res目录统计,防止更新时覆盖此文件*/ 4 var fs = require && require("fs") || null; 5 var obj = function () { 6 that = this; 7 that.fileName = { 8 config: '../config.ini', 9 macCode: '../macCode.txt' 10 }; 11 }; 12 obj.prototype = { 13 set: function (key, value, callback, file) { 14 var cf = this._readFile(file || that.fileName.config); 15 cf[key] = value; 16 17 fs.writeFile(file || that.fileName.config, JSON.stringify(cf), function (err) { 18 if (err) throw err; 19 20 if (typeof callback == "function") callback(); 21 }); 22 }, 23 24 setString: function (key, value, callback, file) { 25 var cf = this._readFile(file, true); 26 cf[key] = value; 27 fs && fs.writeFile(file || that.fileName.config, value, function (err) { 28 if (err) throw err; 29 if (typeof callback == "function") callback(); 30 }); 31 }, 32 33 setSync: function (key, value, callback, file) { 34 var cf = this._readFile(file || that.fileName.config); 35 cf[key] = value; 36 fs && fs.writeFileSync(file || that.fileName.config, JSON.stringify(cf)); 37 }, 38 39 get: function (key, file) { 40 var cf = this._readFile(file || that.fileName.config); 41 return cf[key] || ''; 42 }, 43 getString: function (key, file) { 44 var cf = this._readFile(file || that.fileName.config, true); 45 return cf[key] || ''; 46 }, 47 getAll: function (file) { 48 var cf = this._readFile(file || that.fileName.config); 49 return cf; 50 }, 51 52 _readFile: function (file, defaultValue) { 53 //file = file || fileName; 54 55 if (file) { 56 return this._writeFile(file, defaultValue); 57 } else { 58 for (var i = 0; i < that.fileName.length; i++) { 59 this._writeFile(that.fileName.config, defaultValue); 60 } 61 } 62 }, 63 _writeFile: function (file, defaultValue) { 64 if (!fs) return ''; 65 if (!fs.existsSync(file)) { 66 fs.writeFile(file, (!defaultValue ? '{}' : ''), function (err) { 67 if (err) throw err; 68 }); 69 return {}; 70 } 71 72 var str = fs.readFileSync(file); 73 try { 74 return JSON.parse(str); 75 } catch (e) { 76 return {}; 77 } 78 } 79 }; 80 81 return new obj(); 82 })();
四、md5.min.js(直接引入)
1 !function(a){"use strict";function b(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c}function c(a,b){return a<<b|a>>>32-b}function d(a,d,e,f,g,h){return b(c(b(b(d,a),b(f,h)),g),e)}function e(a,b,c,e,f,g,h){return d(b&c|~b&e,a,b,f,g,h)}function f(a,b,c,e,f,g,h){return d(b&e|c&~e,a,b,f,g,h)}function g(a,b,c,e,f,g,h){return d(b^c^e,a,b,f,g,h)}function h(a,b,c,e,f,g,h){return d(c^(b|~e),a,b,f,g,h)}function i(a,c){a[c>>5]|=128<<c%32,a[(c+64>>>9<<4)+14]=c;var d,i,j,k,l,m=1732584193,n=-271733879,o=-1732584194,p=271733878;for(d=0;d<a.length;d+=16)i=m,j=n,k=o,l=p,m=e(m,n,o,p,a[d],7,-680876936),p=e(p,m,n,o,a[d+1],12,-389564586),o=e(o,p,m,n,a[d+2],17,606105819),n=e(n,o,p,m,a[d+3],22,-1044525330),m=e(m,n,o,p,a[d+4],7,-176418897),p=e(p,m,n,o,a[d+5],12,1200080426),o=e(o,p,m,n,a[d+6],17,-1473231341),n=e(n,o,p,m,a[d+7],22,-45705983),m=e(m,n,o,p,a[d+8],7,1770035416),p=e(p,m,n,o,a[d+9],12,-1958414417),o=e(o,p,m,n,a[d+10],17,-42063),n=e(n,o,p,m,a[d+11],22,-1990404162),m=e(m,n,o,p,a[d+12],7,1804603682),p=e(p,m,n,o,a[d+13],12,-40341101),o=e(o,p,m,n,a[d+14],17,-1502002290),n=e(n,o,p,m,a[d+15],22,1236535329),m=f(m,n,o,p,a[d+1],5,-165796510),p=f(p,m,n,o,a[d+6],9,-1069501632),o=f(o,p,m,n,a[d+11],14,643717713),n=f(n,o,p,m,a[d],20,-373897302),m=f(m,n,o,p,a[d+5],5,-701558691),p=f(p,m,n,o,a[d+10],9,38016083),o=f(o,p,m,n,a[d+15],14,-660478335),n=f(n,o,p,m,a[d+4],20,-405537848),m=f(m,n,o,p,a[d+9],5,568446438),p=f(p,m,n,o,a[d+14],9,-1019803690),o=f(o,p,m,n,a[d+3],14,-187363961),n=f(n,o,p,m,a[d+8],20,1163531501),m=f(m,n,o,p,a[d+13],5,-1444681467),p=f(p,m,n,o,a[d+2],9,-51403784),o=f(o,p,m,n,a[d+7],14,1735328473),n=f(n,o,p,m,a[d+12],20,-1926607734),m=g(m,n,o,p,a[d+5],4,-378558),p=g(p,m,n,o,a[d+8],11,-2022574463),o=g(o,p,m,n,a[d+11],16,1839030562),n=g(n,o,p,m,a[d+14],23,-35309556),m=g(m,n,o,p,a[d+1],4,-1530992060),p=g(p,m,n,o,a[d+4],11,1272893353),o=g(o,p,m,n,a[d+7],16,-155497632),n=g(n,o,p,m,a[d+10],23,-1094730640),m=g(m,n,o,p,a[d+13],4,681279174),p=g(p,m,n,o,a[d],11,-358537222),o=g(o,p,m,n,a[d+3],16,-722521979),n=g(n,o,p,m,a[d+6],23,76029189),m=g(m,n,o,p,a[d+9],4,-640364487),p=g(p,m,n,o,a[d+12],11,-421815835),o=g(o,p,m,n,a[d+15],16,530742520),n=g(n,o,p,m,a[d+2],23,-995338651),m=h(m,n,o,p,a[d],6,-198630844),p=h(p,m,n,o,a[d+7],10,1126891415),o=h(o,p,m,n,a[d+14],15,-1416354905),n=h(n,o,p,m,a[d+5],21,-57434055),m=h(m,n,o,p,a[d+12],6,1700485571),p=h(p,m,n,o,a[d+3],10,-1894986606),o=h(o,p,m,n,a[d+10],15,-1051523),n=h(n,o,p,m,a[d+1],21,-2054922799),m=h(m,n,o,p,a[d+8],6,1873313359),p=h(p,m,n,o,a[d+15],10,-30611744),o=h(o,p,m,n,a[d+6],15,-1560198380),n=h(n,o,p,m,a[d+13],21,1309151649),m=h(m,n,o,p,a[d+4],6,-145523070),p=h(p,m,n,o,a[d+11],10,-1120210379),o=h(o,p,m,n,a[d+2],15,718787259),n=h(n,o,p,m,a[d+9],21,-343485551),m=b(m,i),n=b(n,j),o=b(o,k),p=b(p,l);return[m,n,o,p]}function j(a){var b,c="";for(b=0;b<32*a.length;b+=8)c+=String.fromCharCode(a[b>>5]>>>b%32&255);return c}function k(a){var b,c=[];for(c[(a.length>>2)-1]=void 0,b=0;b<c.length;b+=1)c[b]=0;for(b=0;b<8*a.length;b+=8)c[b>>5]|=(255&a.charCodeAt(b/8))<<b%32;return c}function l(a){return j(i(k(a),8*a.length))}function m(a,b){var c,d,e=k(a),f=[],g=[];for(f[15]=g[15]=void 0,e.length>16&&(e=i(e,8*a.length)),c=0;16>c;c+=1)f[c]=909522486^e[c],g[c]=1549556828^e[c];return d=i(f.concat(k(b)),512+8*b.length),j(i(g.concat(d),640))}function n(a){var b,c,d="0123456789abcdef",e="";for(c=0;c<a.length;c+=1)b=a.charCodeAt(c),e+=d.charAt(b>>>4&15)+d.charAt(15&b);return e}function o(a){return unescape(encodeURIComponent(a))}function p(a){return l(o(a))}function q(a){return n(p(a))}function r(a,b){return m(o(a),o(b))}function s(a,b){return n(r(a,b))}function t(a,b,c){return b?c?r(b,a):s(b,a):c?p(a):q(a)}"function"==typeof define&&define.amd?define(function(){return t}):a.md5=t}(this);
五、NWBridge.js(直接引入)
1 /** 2 * Created by Administrator on 2017/10/17 0017. 3 */ 4 var NWBridge = (function (){ 5 var that; 6 var obj = function () { 7 that = this; 8 if (top.require) { 9 that.http = top.require('http'); 10 that.https = top.require('https'); 11 that.mac = top.require("getmac"); 12 that.nodePath = top.require('path'); 13 that.exec = top.require('child_process').exec; 14 that.spawn = top.require('child_process').spawn; 15 } 16 }; 17 obj.prototype = { 18 getMac: (callback) => { 19 that.mac && that.mac.getMac(function (err, macAddress) { 20 if (err) throw err; 21 var macCode = md5(macAddress); 22 callback(macCode); 23 }); 24 }, 25 checkAutoUpdaterTwo: (callback) => { 26 if ( !top.require) return; 27 var fs = top.require('fs'); 28 var pathParent = that.nodePath.dirname(process.cwd()); 29 fs.exists(pathParent + '\\autoUpdate2.exe', (exists) => { 30 if (exists) { 31 var unlinkName = '\\autoUpdate.exe'; 32 fs.exists(pathParent + unlinkName, (flag) => { 33 if (flag) { 34 fs.unlink(pathParent + unlinkName, (err) =>{ 35 if ( err ) console.log('ERROR: ' + err); 36 fs.rename(pathParent + '\\autoUpdate2.exe', pathParent + '\\autoUpdate.exe', (err) =>{ 37 if ( err ) console.log('ERROR: ' + err); 38 callback && callback(); 39 }); 40 }); 41 } else { 42 callback && callback(); 43 } 44 }); 45 } else { 46 callback && callback(); 47 } 48 }); 49 }, 50 checkUpdate: (callback) => { 51 // 加 "" 是因为 直接执行路径有空格时会抛异常 所以需要加双引号当成一个字符串 52 that.lsUpdate = that.exec('"' + that.nodePath.dirname(process.cwd()) + '\\autoUpdate.exe' + '"', 53 (error, stdout, stderr) => { 54 console.log('stdout: ' + stdout); 55 console.log('stderr: ' + stderr); 56 if (error !== null) { 57 console.log('exec error: ' + error); 58 } 59 }); 60 that.lsUpdate.stdout.on('data', (data) => { 61 if (data) { 62 if (eval(data)) { 63 setTimeout( () =>{ 64 var gui = top.require('nw.gui'); 65 gui.Window.get().close(); 66 }, 2000); 67 } else { 68 callback && callback(); 69 } 70 } else { 71 callback && callback(); 72 } 73 }); 74 75 that.lsUpdate.stderr.on('data', (data) => { 76 that.lsUpdate.kill(); 77 console.error('stderr: ' + data); 78 }); 79 80 that.lsUpdate.on('close',(code) =>{ 81 that.lsUpdate.kill(); 82 callback && callback(); 83 }); 84 return that.lsUpdate; 85 } 86 }; 87 return new obj(); 88 })();
六、socket.io.js(直接引入)
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.io=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ 2 3 module.exports = _dereq_('./lib/'); 4 5 },{"./lib/":2}],2:[function(_dereq_,module,exports){ 6 7 /** 8 * Module dependencies. 9 */ 10 11 var url = _dereq_('./url'); 12 var parser = _dereq_('socket.io-parser'); 13 var Manager = _dereq_('./manager'); 14 var debug = _dereq_('debug')('socket.io-client'); 15 16 /** 17 * Module exports. 18 */ 19 20 module.exports = exports = lookup; 21 22 /** 23 * Managers cache. 24 */ 25 26 var cache = exports.managers = {}; 27 28 /** 29 * Looks up an existing `Manager` for multiplexing. 30 * If the user summons: 31 * 32 * `io('http://localhost/a');` 33 * `io('http://localhost/b');` 34 * 35 * We reuse the existing instance based on same scheme/port/host, 36 * and we initialize sockets for each namespace. 37 * 38 * @api public 39 */ 40 41 function lookup(uri, opts) { 42 if (typeof uri == 'object') { 43 opts = uri; 44 uri = undefined; 45 } 46 47 opts = opts || {}; 48 49 var parsed = url(uri); 50 var source = parsed.source; 51 var id = parsed.id; 52 var io; 53 54 if (opts.forceNew || opts['force new connection'] || false === opts.multiplex) { 55 debug('ignoring socket cache for %s', source); 56 io = Manager(source, opts); 57 } else { 58 if (!cache[id]) { 59 debug('new io instance for %s', source); 60 cache[id] = Manager(source, opts); 61 } 62 io = cache[id]; 63 } 64 65 return io.socket(parsed.path); 66 } 67 68 /** 69 * Protocol version. 70 * 71 * @api public 72 */ 73 74 exports.protocol = parser.protocol; 75 76 /** 77 * `connect`. 78 * 79 * @param {String} uri 80 * @api public 81 */ 82 83 exports.connect = lookup; 84 85 /** 86 * Expose constructors for standalone build. 87 * 88 * @api public 89 */ 90 91 exports.Manager = _dereq_('./manager'); 92 exports.Socket = _dereq_('./socket'); 93 94 },{"./manager":3,"./socket":5,"./url":6,"debug":10,"socket.io-parser":44}],3:[function(_dereq_,module,exports){ 95 96 /** 97 * Module dependencies. 98 */ 99 100 var url = _dereq_('./url'); 101 var eio = _dereq_('engine.io-client'); 102 var Socket = _dereq_('./socket'); 103 var Emitter = _dereq_('component-emitter'); 104 var parser = _dereq_('socket.io-parser'); 105 var on = _dereq_('./on'); 106 var bind = _dereq_('component-bind'); 107 var object = _dereq_('object-component'); 108 var debug = _dereq_('debug')('socket.io-client:manager'); 109 var indexOf = _dereq_('indexof'); 110 var Backoff = _dereq_('backo2'); 111 112 /** 113 * Module exports 114 */ 115 116 module.exports = Manager; 117 118 /** 119 * `Manager` constructor. 120 * 121 * @param {String} engine instance or engine uri/opts 122 * @param {Object} options 123 * @api public 124 */ 125 126 function Manager(uri, opts){ 127 if (!(this instanceof Manager)) return new Manager(uri, opts); 128 if (uri && ('object' == typeof uri)) { 129 opts = uri; 130 uri = undefined; 131 } 132 opts = opts || {}; 133 134 opts.path = opts.path || '/socket.io'; 135 this.nsps = {}; 136 this.subs = []; 137 this.opts = opts; 138 this.reconnection(opts.reconnection !== false); 139 this.reconnectionAttempts(opts.reconnectionAttempts || Infinity); 140 this.reconnectionDelay(opts.reconnectionDelay || 1000); 141 this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000); 142 this.randomizationFactor(opts.randomizationFactor || 0.5); 143 this.backoff = new Backoff({ 144 min: this.reconnectionDelay(), 145 max: this.reconnectionDelayMax(), 146 jitter: this.randomizationFactor() 147 }); 148 this.timeout(null == opts.timeout ? 20000 : opts.timeout); 149 this.readyState = 'closed'; 150 this.uri = uri; 151 this.connected = []; 152 this.encoding = false; 153 this.packetBuffer = []; 154 this.encoder = new parser.Encoder(); 155 this.decoder = new parser.Decoder(); 156 this.autoConnect = opts.autoConnect !== false; 157 if (this.autoConnect) this.open(); 158 } 159 160 /** 161 * Propagate given event to sockets and emit on `this` 162 * 163 * @api private 164 */ 165 166 Manager.prototype.emitAll = function() { 167 this.emit.apply(this, arguments); 168 for (var nsp in this.nsps) { 169 this.nsps[nsp].emit.apply(this.nsps[nsp], arguments); 170 } 171 }; 172 173 /** 174 * Update `socket.id` of all sockets 175 * 176 * @api private 177 */ 178 179 Manager.prototype.updateSocketIds = function(){ 180 for (var nsp in this.nsps) { 181 this.nsps[nsp].id = this.engine.id; 182 } 183 }; 184 185 /** 186 * Mix in `Emitter`. 187 */ 188 189 Emitter(Manager.prototype); 190 191 /** 192 * Sets the `reconnection` config. 193 * 194 * @param {Boolean} true/false if it should automatically reconnect 195 * @return {Manager} self or value 196 * @api public 197 */ 198 199 Manager.prototype.reconnection = function(v){ 200 if (!arguments.length) return this._reconnection; 201 this._reconnection = !!v; 202 return this; 203 }; 204 205 /** 206 * Sets the reconnection attempts config. 207 * 208 * @param {Number} max reconnection attempts before giving up 209 * @return {Manager} self or value 210 * @api public 211 */ 212 213 Manager.prototype.reconnectionAttempts = function(v){ 214 if (!arguments.length) return this._reconnectionAttempts; 215 this._reconnectionAttempts = v; 216 return this; 217 }; 218 219 /** 220 * Sets the delay between reconnections. 221 * 222 * @param {Number} delay 223 * @return {Manager} self or value 224 * @api public 225 */ 226 227 Manager.prototype.reconnectionDelay = function(v){ 228 if (!arguments.length) return this._reconnectionDelay; 229 this._reconnectionDelay = v; 230 this.backoff && this.backoff.setMin(v); 231 return this; 232 }; 233 234 Manager.prototype.randomizationFactor = function(v){ 235 if (!arguments.length) return this._randomizationFactor; 236 this._randomizationFactor = v; 237 this.backoff && this.backoff.setJitter(v); 238 return this; 239 }; 240 241 /** 242 * Sets the maximum delay between reconnections. 243 * 244 * @param {Number} delay 245 * @return {Manager} self or value 246 * @api public 247 */ 248 249 Manager.prototype.reconnectionDelayMax = function(v){ 250 if (!arguments.length) return this._reconnectionDelayMax; 251 this._reconnectionDelayMax = v; 252 this.backoff && this.backoff.setMax(v); 253 return this; 254 }; 255 256 /** 257 * Sets the connection timeout. `false` to disable 258 * 259 * @return {Manager} self or value 260 * @api public 261 */ 262 263 Manager.prototype.timeout = function(v){ 264 if (!arguments.length) return this._timeout; 265 this._timeout = v; 266 return this; 267 }; 268 269 /** 270 * Starts trying to reconnect if reconnection is enabled and we have not 271 * started reconnecting yet 272 * 273 * @api private 274 */ 275 276 Manager.prototype.maybeReconnectOnOpen = function() { 277 // Only try to reconnect if it's the first time we're connecting 278 if (!this.reconnecting && this._reconnection && this.backoff.attempts === 0) { 279 // keeps reconnection from firing twice for the same reconnection loop 280 this.reconnect(); 281 } 282 }; 283 284 285 /** 286 * Sets the current transport `socket`. 287 * 288 * @param {Function} optional, callback 289 * @return {Manager} self 290 * @api public 291 */ 292 293 Manager.prototype.open = 294 Manager.prototype.connect = function(fn){ 295 debug('readyState %s', this.readyState); 296 if (~this.readyState.indexOf('open')) return this; 297 298 debug('opening %s', this.uri); 299 this.engine = eio(this.uri, this.opts); 300 var socket = this.engine; 301 var self = this; 302 this.readyState = 'opening'; 303 this.skipReconnect = false; 304 305 // emit `open` 306 var openSub = on(socket, 'open', function() { 307 self.onopen(); 308 fn && fn(); 309 }); 310 311 // emit `connect_error` 312 var errorSub = on(socket, 'error', function(data){ 313 debug('connect_error'); 314 self.cleanup(); 315 self.readyState = 'closed'; 316 self.emitAll('connect_error', data); 317 if (fn) { 318 var err = new Error('Connection error'); 319 err.data = data; 320 fn(err); 321 } else { 322 // Only do this if there is no fn to handle the error 323 self.maybeReconnectOnOpen(); 324 } 325 }); 326 327 // emit `connect_timeout` 328 if (false !== this._timeout) { 329 var timeout = this._timeout; 330 debug('connect attempt will timeout after %d', timeout); 331 332 // set timer 333 var timer = setTimeout(function(){ 334 debug('connect attempt timed out after %d', timeout); 335 openSub.destroy(); 336 socket.close(); 337 socket.emit('error', 'timeout'); 338 self.emitAll('connect_timeout', timeout); 339 }, timeout); 340 341 this.subs.push({ 342 destroy: function(){ 343 clearTimeout(timer); 344 } 345 }); 346 } 347 348 this.subs.push(openSub); 349 this.subs.push(errorSub); 350 351 return this; 352 }; 353 354 /** 355 * Called upon transport open. 356 * 357 * @api private 358 */ 359 360 Manager.prototype.onopen = function(){ 361 debug('open'); 362 363 // clear old subs 364 this.cleanup(); 365 366 // mark as open 367 this.readyState = 'open'; 368 this.emit('open'); 369 370 // add new subs 371 var socket = this.engine; 372 this.subs.push(on(socket, 'data', bind(this, 'ondata'))); 373 this.subs.push(on(this.decoder, 'decoded', bind(this, 'ondecoded'))); 374 this.subs.push(on(socket, 'error', bind(this, 'onerror'))); 375 this.subs.push(on(socket, 'close', bind(this, 'onclose'))); 376 }; 377 378 /** 379 * Called with data. 380 * 381 * @api private 382 */ 383 384 Manager.prototype.ondata = function(data){ 385 this.decoder.add(data); 386 }; 387 388 /** 389 * Called when parser fully decodes a packet. 390 * 391 * @api private 392 */ 393 394 Manager.prototype.ondecoded = function(packet) { 395 this.emit('packet', packet); 396 }; 397 398 /** 399 * Called upon socket error. 400 * 401 * @api private 402 */ 403 404 Manager.prototype.onerror = function(err){ 405 debug('error', err); 406 this.emitAll('error', err); 407 }; 408 409 /** 410 * Creates a new socket for the given `nsp`. 411 * 412 * @return {Socket} 413 * @api public 414 */ 415 416 Manager.prototype.socket = function(nsp){ 417 var socket = this.nsps[nsp]; 418 if (!socket) { 419 socket = new Socket(this, nsp); 420 this.nsps[nsp] = socket; 421 var self = this; 422 socket.on('connect', function(){ 423 socket.id = self.engine.id; 424 if (!~indexOf(self.connected, socket)) { 425 self.connected.push(socket); 426 } 427 }); 428 } 429 return socket; 430 }; 431 432 /** 433 * Called upon a socket close. 434 * 435 * @param {Socket} socket 436 */ 437 438 Manager.prototype.destroy = function(socket){ 439 var index = indexOf(this.connected, socket); 440 if (~index) this.connected.splice(index, 1); 441 if (this.connected.length) return; 442 443 this.close(); 444 }; 445 446 /** 447 * Writes a packet. 448 * 449 * @param {Object} packet 450 * @api private 451 */ 452 453 Manager.prototype.packet = function(packet){ 454 debug('writing packet %j', packet); 455 var self = this; 456 457 if (!self.encoding) { 458 // encode, then write to engine with result 459 self.encoding = true; 460 this.encoder.encode(packet, function(encodedPackets) { 461 for (var i = 0; i < encodedPackets.length; i++) { 462 self.engine.write(encodedPackets[i]); 463 } 464 self.encoding = false; 465 self.processPacketQueue(); 466 }); 467 } else { // add packet to the queue 468 self.packetBuffer.push(packet); 469 } 470 }; 471 472 /** 473 * If packet buffer is non-empty, begins encoding the 474 * next packet in line. 475 * 476 * @api private 477 */ 478 479 Manager.prototype.processPacketQueue = function() { 480 if (this.packetBuffer.length > 0 && !this.encoding) { 481 var pack = this.packetBuffer.shift(); 482 this.packet(pack); 483 } 484 }; 485 486 /** 487 * Clean up transport subscriptions and packet buffer. 488 * 489 * @api private 490 */ 491 492 Manager.prototype.cleanup = function(){ 493 var sub; 494 while (sub = this.subs.shift()) sub.destroy(); 495 496 this.packetBuffer = []; 497 this.encoding = false; 498 499 this.decoder.destroy(); 500 }; 501 502 /** 503 * Close the current socket. 504 * 505 * @api private 506 */ 507 508 Manager.prototype.close = 509 Manager.prototype.disconnect = function(){ 510 this.skipReconnect = true; 511 this.backoff.reset(); 512 this.readyState = 'closed'; 513 this.engine && this.engine.close(); 514 }; 515 516 /** 517 * Called upon engine close. 518 * 519 * @api private 520 */ 521 522 Manager.prototype.onclose = function(reason){ 523 debug('close'); 524 this.cleanup(); 525 this.backoff.reset(); 526 this.readyState = 'closed'; 527 this.emit('close', reason); 528 if (this._reconnection && !this.skipReconnect) { 529 this.reconnect(); 530 } 531 }; 532 533 /** 534 * Attempt a reconnection. 535 * 536 * @api private 537 */ 538 539 Manager.prototype.reconnect = function(){ 540 if (this.reconnecting || this.skipReconnect) return this; 541 542 var self = this; 543 544 if (this.backoff.attempts >= this._reconnectionAttempts) { 545 debug('reconnect failed'); 546 this.backoff.reset(); 547 this.emitAll('reconnect_failed'); 548 this.reconnecting = false; 549 } else { 550 var delay = this.backoff.duration(); 551 debug('will wait %dms before reconnect attempt', delay); 552 553 this.reconnecting = true; 554 var timer = setTimeout(function(){ 555 if (self.skipReconnect) return; 556 557 debug('attempting reconnect'); 558 self.emitAll('reconnect_attempt', self.backoff.attempts); 559 self.emitAll('reconnecting', self.backoff.attempts); 560 561 // check again for the case socket closed in above events 562 if (self.skipReconnect) return; 563 564 self.open(function(err){ 565 if (err) { 566 debug('reconnect attempt error'); 567 self.reconnecting = false; 568 self.reconnect(); 569 self.emitAll('reconnect_error', err.data); 570 } else { 571 debug('reconnect success'); 572 self.onreconnect(); 573 } 574 }); 575 }, delay); 576 577 this.subs.push({ 578 destroy: function(){ 579 clearTimeout(timer); 580 } 581 }); 582 } 583 }; 584 585 /** 586 * Called upon successful reconnect. 587 * 588 * @api private 589 */ 590 591 Manager.prototype.onreconnect = function(){ 592 var attempt = this.backoff.attempts; 593 this.reconnecting = false; 594 this.backoff.reset(); 595 this.updateSocketIds(); 596 this.emitAll('reconnect', attempt); 597 }; 598 599 },{"./on":4,"./socket":5,"./url":6,"backo2":7,"component-bind":8,"component-emitter":9,"debug":10,"engine.io-client":11,"indexof":40,"object-component":41,"socket.io-parser":44}],4:[function(_dereq_,module,exports){ 600 601 /** 602 * Module exports. 603 */ 604 605 module.exports = on; 606 607 /** 608 * Helper for subscriptions. 609 * 610 * @param {Object|EventEmitter} obj with `Emitter` mixin or `EventEmitter` 611 * @param {String} event name 612 * @param {Function} callback 613 * @api public 614 */ 615 616 function on(obj, ev, fn) { 617 obj.on(ev, fn); 618 return { 619 destroy: function(){ 620 obj.removeListener(ev, fn); 621 } 622 }; 623 } 624 625 },{}],5:[function(_dereq_,module,exports){ 626 627 /** 628 * Module dependencies. 629 */ 630 631 var parser = _dereq_('socket.io-parser'); 632 var Emitter = _dereq_('component-emitter'); 633 var toArray = _dereq_('to-array'); 634 var on = _dereq_('./on'); 635 var bind = _dereq_('component-bind'); 636 var debug = _dereq_('debug')('socket.io-client:socket'); 637 var hasBin = _dereq_('has-binary'); 638 639 /** 640 * Module exports. 641 */ 642 643 module.exports = exports = Socket; 644 645 /** 646 * Internal events (blacklisted). 647 * These events can't be emitted by the user. 648 * 649 * @api private 650 */ 651 652 var events = { 653 connect: 1, 654 connect_error: 1, 655 connect_timeout: 1, 656 disconnect: 1, 657 error: 1, 658 reconnect: 1, 659 reconnect_attempt: 1, 660 reconnect_failed: 1, 661 reconnect_error: 1, 662 reconnecting: 1 663 }; 664 665 /** 666 * Shortcut to `Emitter#emit`. 667 */ 668 669 var emit = Emitter.prototype.emit; 670 671 /** 672 * `Socket` constructor. 673 * 674 * @api public 675 */ 676 677 function Socket(io, nsp){ 678 this.io = io; 679 this.nsp = nsp; 680 this.json = this; // compat 681 this.ids = 0; 682 this.acks = {}; 683 if (this.io.autoConnect) this.open(); 684 this.receiveBuffer = []; 685 this.sendBuffer = []; 686 this.connected = false; 687 this.disconnected = true; 688 } 689 690 /** 691 * Mix in `Emitter`. 692 */ 693 694 Emitter(Socket.prototype); 695 696 /** 697 * Subscribe to open, close and packet events 698 * 699 * @api private 700 */ 701 702 Socket.prototype.subEvents = function() { 703 if (this.subs) return; 704 705 var io = this.io; 706 this.subs = [ 707 on(io, 'open', bind(this, 'onopen')), 708 on(io, 'packet', bind(this, 'onpacket')), 709 on(io, 'close', bind(this, 'onclose')) 710 ]; 711 }; 712 713 /** 714 * "Opens" the socket. 715 * 716 * @api public 717 */ 718 719 Socket.prototype.open = 720 Socket.prototype.connect = function(){ 721 if (this.connected) return this; 722 723 this.subEvents(); 724 this.io.open(); // ensure open 725 if ('open' == this.io.readyState) this.onopen(); 726 return this; 727 }; 728 729 /** 730 * Sends a `message` event. 731 * 732 * @return {Socket} self 733 * @api public 734 */ 735 736 Socket.prototype.send = function(){ 737 var args = toArray(arguments); 738 args.unshift('message'); 739 this.emit.apply(this, args); 740 return this; 741 }; 742 743 /** 744 * Override `emit`. 745 * If the event is in `events`, it's emitted normally. 746 * 747 * @param {String} event name 748 * @return {Socket} self 749 * @api public 750 */ 751 752 Socket.prototype.emit = function(ev){ 753 if (events.hasOwnProperty(ev)) { 754 emit.apply(this, arguments); 755 return this; 756 } 757 758 var args = toArray(arguments); 759 var parserType = parser.EVENT; // default 760 if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary 761 var packet = { type: parserType, data: args }; 762 763 // event ack callback 764 if ('function' == typeof args[args.length - 1]) { 765 debug('emitting packet with ack id %d', this.ids); 766 this.acks[this.ids] = args.pop(); 767 packet.id = this.ids++; 768 } 769 770 if (this.connected) { 771 this.packet(packet); 772 } else { 773 this.sendBuffer.push(packet); 774 } 775 776 return this; 777 }; 778 779 /** 780 * Sends a packet. 781 * 782 * @param {Object} packet 783 * @api private 784 */ 785 786 Socket.prototype.packet = function(packet){ 787 packet.nsp = this.nsp; 788 this.io.packet(packet); 789 }; 790 791 /** 792 * Called upon engine `open`. 793 * 794 * @api private 795 */ 796 797 Socket.prototype.onopen = function(){ 798 debug('transport is open - connecting'); 799 800 // write connect packet if necessary 801 if ('/' != this.nsp) { 802 this.packet({ type: parser.CONNECT }); 803 } 804 }; 805 806 /** 807 * Called upon engine `close`. 808 * 809 * @param {String} reason 810 * @api private 811 */ 812 813 Socket.prototype.onclose = function(reason){ 814 debug('close (%s)', reason); 815 this.connected = false; 816 this.disconnected = true; 817 delete this.id; 818 this.emit('disconnect', reason); 819 }; 820 821 /** 822 * Called with socket packet. 823 * 824 * @param {Object} packet 825 * @api private 826 */ 827 828 Socket.prototype.onpacket = function(packet){ 829 if (packet.nsp != this.nsp) return; 830 831 switch (packet.type) { 832 case parser.CONNECT: 833 this.onconnect(); 834 break; 835 836 case parser.EVENT: 837 this.onevent(packet); 838 break; 839 840 case parser.BINARY_EVENT: 841 this.onevent(packet); 842 break; 843 844 case parser.ACK: 845 this.onack(packet); 846 break; 847 848 case parser.BINARY_ACK: 849 this.onack(packet); 850 break; 851 852 case parser.DISCONNECT: 853 this.ondisconnect(); 854 break; 855 856 case parser.ERROR: 857 this.emit('error', packet.data); 858 break; 859 } 860 }; 861 862 /** 863 * Called upon a server event. 864 * 865 * @param {Object} packet 866 * @api private 867 */ 868 869 Socket.prototype.onevent = function(packet){ 870 var args = packet.data || []; 871 debug('emitting event %j', args); 872 873 if (null != packet.id) { 874 debug('attaching ack callback to event'); 875 args.push(this.ack(packet.id)); 876 } 877 878 if (this.connected) { 879 emit.apply(this, args); 880 } else { 881 this.receiveBuffer.push(args); 882 } 883 }; 884 885 /** 886 * Produces an ack callback to emit with an event. 887 * 888 * @api private 889 */ 890 891 Socket.prototype.ack = function(id){ 892 var self = this; 893 var sent = false; 894 return function(){ 895 // prevent double callbacks 896 if (sent) return; 897 sent = true; 898 var args = toArray(arguments); 899 debug('sending ack %j', args); 900 901 var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK; 902 self.packet({ 903 type: type, 904 id: id, 905 data: args 906 }); 907 }; 908 }; 909 910 /** 911 * Called upon a server acknowlegement. 912 * 913 * @param {Object} packet 914 * @api private 915 */ 916 917 Socket.prototype.onack = function(packet){ 918 debug('calling ack %s with %j', packet.id, packet.data); 919 var fn = this.acks[packet.id]; 920 fn.apply(this, packet.data); 921 delete this.acks[packet.id]; 922 }; 923 924 /** 925 * Called upon server connect. 926 * 927 * @api private 928 */ 929 930 Socket.prototype.onconnect = function(){ 931 this.connected = true; 932 this.disconnected = false; 933 this.emit('connect'); 934 this.emitBuffered(); 935 }; 936 937 /** 938 * Emit buffered events (received and emitted). 939 * 940 * @api private 941 */ 942 943 Socket.prototype.emitBuffered = function(){ 944 var i; 945 for (i = 0; i < this.receiveBuffer.length; i++) { 946 emit.apply(this, this.receiveBuffer[i]); 947 } 948 this.receiveBuffer = []; 949 950 for (i = 0; i < this.sendBuffer.length; i++) { 951 this.packet(this.sendBuffer[i]); 952 } 953 this.sendBuffer = []; 954 }; 955 956 /** 957 * Called upon server disconnect. 958 * 959 * @api private 960 */ 961 962 Socket.prototype.ondisconnect = function(){ 963 debug('server disconnect (%s)', this.nsp); 964 this.destroy(); 965 this.onclose('io server disconnect'); 966 }; 967 968 /** 969 * Called upon forced client/server side disconnections, 970 * this method ensures the manager stops tracking us and 971 * that reconnections don't get triggered for this. 972 * 973 * @api private. 974 */ 975 976 Socket.prototype.destroy = function(){ 977 if (this.subs) { 978 // clean subscriptions to avoid reconnections 979 for (var i = 0; i < this.subs.length; i++) { 980 this.subs[i].destroy(); 981 } 982 this.subs = null; 983 } 984 985 this.io.destroy(this); 986 }; 987 988 /** 989 * Disconnects the socket manually. 990 * 991 * @return {Socket} self 992 * @api public 993 */ 994 995 Socket.prototype.close = 996 Socket.prototype.disconnect = function(){ 997 if (this.connected) { 998 debug('performing disconnect (%s)', this.nsp); 999 this.packet({ type: parser.DISCONNECT }); 1000 } 1001 1002 // remove socket from pool 1003 this.destroy(); 1004 1005 if (this.connected) { 1006 // fire events 1007 this.onclose('io client disconnect'); 1008 } 1009 return this; 1010 }; 1011 1012 },{"./on":4,"component-bind":8,"component-emitter":9,"debug":10,"has-binary":36,"socket.io-parser":44,"to-array":48}],6:[function(_dereq_,module,exports){ 1013 (function (global){ 1014 1015 /** 1016 * Module dependencies. 1017 */ 1018 1019 var parseuri = _dereq_('parseuri'); 1020 var debug = _dereq_('debug')('socket.io-client:url'); 1021 1022 /** 1023 * Module exports. 1024 */ 1025 1026 module.exports = url; 1027 1028 /** 1029 * URL parser. 1030 * 1031 * @param {String} url 1032 * @param {Object} An object meant to mimic window.location. 1033 * Defaults to window.location. 1034 * @api public 1035 */ 1036 1037 function url(uri, loc){ 1038 var obj = uri; 1039 1040 // default to window.location 1041 var loc = loc || global.location; 1042 if (null == uri) uri = loc.protocol + '//' + loc.host; 1043 1044 // relative path support 1045 if ('string' == typeof uri) { 1046 if ('/' == uri.charAt(0)) { 1047 if ('/' == uri.charAt(1)) { 1048 uri = loc.protocol + uri; 1049 } else { 1050 uri = loc.hostname + uri; 1051 } 1052 } 1053 1054 if (!/^(https?|wss?):\/\//.test(uri)) { 1055 debug('protocol-less url %s', uri); 1056 if ('undefined' != typeof loc) { 1057 uri = loc.protocol + '//' + uri; 1058 } else { 1059 uri = 'https://' + uri; 1060 } 1061 } 1062 1063 // parse 1064 debug('parse %s', uri); 1065 obj = parseuri(uri); 1066 } 1067 1068 // make sure we treat `localhost:80` and `localhost` equally 1069 if (!obj.port) { 1070 if (/^(http|ws)$/.test(obj.protocol)) { 1071 obj.port = '80'; 1072 } 1073 else if (/^(http|ws)s$/.test(obj.protocol)) { 1074 obj.port = '443'; 1075 } 1076 } 1077 1078 obj.path = obj.path || '/'; 1079 1080 // define unique id 1081 obj.id = obj.protocol + '://' + obj.host + ':' + obj.port; 1082 // define href 1083 obj.href = obj.protocol + '://' + obj.host + (loc && loc.port == obj.port ? '' : (':' + obj.port)); 1084 1085 return obj; 1086 } 1087 1088 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 1089 },{"debug":10,"parseuri":42}],7:[function(_dereq_,module,exports){ 1090 1091 /** 1092 * Expose `Backoff`. 1093 */ 1094 1095 module.exports = Backoff; 1096 1097 /** 1098 * Initialize backoff timer with `opts`. 1099 * 1100 * - `min` initial timeout in milliseconds [100] 1101 * - `max` max timeout [10000] 1102 * - `jitter` [0] 1103 * - `factor` [2] 1104 * 1105 * @param {Object} opts 1106 * @api public 1107 */ 1108 1109 function Backoff(opts) { 1110 opts = opts || {}; 1111 this.ms = opts.min || 100; 1112 this.max = opts.max || 10000; 1113 this.factor = opts.factor || 2; 1114 this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0; 1115 this.attempts = 0; 1116 } 1117 1118 /** 1119 * Return the backoff duration. 1120 * 1121 * @return {Number} 1122 * @api public 1123 */ 1124 1125 Backoff.prototype.duration = function(){ 1126 var ms = this.ms * Math.pow(this.factor, this.attempts++); 1127 if (this.jitter) { 1128 var rand = Math.random(); 1129 var deviation = Math.floor(rand * this.jitter * ms); 1130 ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation; 1131 } 1132 return Math.min(ms, this.max) | 0; 1133 }; 1134 1135 /** 1136 * Reset the number of attempts. 1137 * 1138 * @api public 1139 */ 1140 1141 Backoff.prototype.reset = function(){ 1142 this.attempts = 0; 1143 }; 1144 1145 /** 1146 * Set the minimum duration 1147 * 1148 * @api public 1149 */ 1150 1151 Backoff.prototype.setMin = function(min){ 1152 this.ms = min; 1153 }; 1154 1155 /** 1156 * Set the maximum duration 1157 * 1158 * @api public 1159 */ 1160 1161 Backoff.prototype.setMax = function(max){ 1162 this.max = max; 1163 }; 1164 1165 /** 1166 * Set the jitter 1167 * 1168 * @api public 1169 */ 1170 1171 Backoff.prototype.setJitter = function(jitter){ 1172 this.jitter = jitter; 1173 }; 1174 1175 1176 },{}],8:[function(_dereq_,module,exports){ 1177 /** 1178 * Slice reference. 1179 */ 1180 1181 var slice = [].slice; 1182 1183 /** 1184 * Bind `obj` to `fn`. 1185 * 1186 * @param {Object} obj 1187 * @param {Function|String} fn or string 1188 * @return {Function} 1189 * @api public 1190 */ 1191 1192 module.exports = function(obj, fn){ 1193 if ('string' == typeof fn) fn = obj[fn]; 1194 if ('function' != typeof fn) throw new Error('bind() requires a function'); 1195 var args = slice.call(arguments, 2); 1196 return function(){ 1197 return fn.apply(obj, args.concat(slice.call(arguments))); 1198 } 1199 }; 1200 1201 },{}],9:[function(_dereq_,module,exports){ 1202 1203 /** 1204 * Expose `Emitter`. 1205 */ 1206 1207 module.exports = Emitter; 1208 1209 /** 1210 * Initialize a new `Emitter`. 1211 * 1212 * @api public 1213 */ 1214 1215 function Emitter(obj) { 1216 if (obj) return mixin(obj); 1217 }; 1218 1219 /** 1220 * Mixin the emitter properties. 1221 * 1222 * @param {Object} obj 1223 * @return {Object} 1224 * @api private 1225 */ 1226 1227 function mixin(obj) { 1228 for (var key in Emitter.prototype) { 1229 obj[key] = Emitter.prototype[key]; 1230 } 1231 return obj; 1232 } 1233 1234 /** 1235 * Listen on the given `event` with `fn`. 1236 * 1237 * @param {String} event 1238 * @param {Function} fn 1239 * @return {Emitter} 1240 * @api public 1241 */ 1242 1243 Emitter.prototype.on = 1244 Emitter.prototype.addEventListener = function(event, fn){ 1245 this._callbacks = this._callbacks || {}; 1246 (this._callbacks[event] = this._callbacks[event] || []) 1247 .push(fn); 1248 return this; 1249 }; 1250 1251 /** 1252 * Adds an `event` listener that will be invoked a single 1253 * time then automatically removed. 1254 * 1255 * @param {String} event 1256 * @param {Function} fn 1257 * @return {Emitter} 1258 * @api public 1259 */ 1260 1261 Emitter.prototype.once = function(event, fn){ 1262 var self = this; 1263 this._callbacks = this._callbacks || {}; 1264 1265 function on() { 1266 self.off(event, on); 1267 fn.apply(this, arguments); 1268 } 1269 1270 on.fn = fn; 1271 this.on(event, on); 1272 return this; 1273 }; 1274 1275 /** 1276 * Remove the given callback for `event` or all 1277 * registered callbacks. 1278 * 1279 * @param {String} event 1280 * @param {Function} fn 1281 * @return {Emitter} 1282 * @api public 1283 */ 1284 1285 Emitter.prototype.off = 1286 Emitter.prototype.removeListener = 1287 Emitter.prototype.removeAllListeners = 1288 Emitter.prototype.removeEventListener = function(event, fn){ 1289 this._callbacks = this._callbacks || {}; 1290 1291 // all 1292 if (0 == arguments.length) { 1293 this._callbacks = {}; 1294 return this; 1295 } 1296 1297 // specific event 1298 var callbacks = this._callbacks[event]; 1299 if (!callbacks) return this; 1300 1301 // remove all handlers 1302 if (1 == arguments.length) { 1303 delete this._callbacks[event]; 1304 return this; 1305 } 1306 1307 // remove specific handler 1308 var cb; 1309 for (var i = 0; i < callbacks.length; i++) { 1310 cb = callbacks[i]; 1311 if (cb === fn || cb.fn === fn) { 1312 callbacks.splice(i, 1); 1313 break; 1314 } 1315 } 1316 return this; 1317 }; 1318 1319 /** 1320 * Emit `event` with the given args. 1321 * 1322 * @param {String} event 1323 * @param {Mixed} ... 1324 * @return {Emitter} 1325 */ 1326 1327 Emitter.prototype.emit = function(event){ 1328 this._callbacks = this._callbacks || {}; 1329 var args = [].slice.call(arguments, 1) 1330 , callbacks = this._callbacks[event]; 1331 1332 if (callbacks) { 1333 callbacks = callbacks.slice(0); 1334 for (var i = 0, len = callbacks.length; i < len; ++i) { 1335 callbacks[i].apply(this, args); 1336 } 1337 } 1338 1339 return this; 1340 }; 1341 1342 /** 1343 * Return array of callbacks for `event`. 1344 * 1345 * @param {String} event 1346 * @return {Array} 1347 * @api public 1348 */ 1349 1350 Emitter.prototype.listeners = function(event){ 1351 this._callbacks = this._callbacks || {}; 1352 return this._callbacks[event] || []; 1353 }; 1354 1355 /** 1356 * Check if this emitter has `event` handlers. 1357 * 1358 * @param {String} event 1359 * @return {Boolean} 1360 * @api public 1361 */ 1362 1363 Emitter.prototype.hasListeners = function(event){ 1364 return !! this.listeners(event).length; 1365 }; 1366 1367 },{}],10:[function(_dereq_,module,exports){ 1368 1369 /** 1370 * Expose `debug()` as the module. 1371 */ 1372 1373 module.exports = debug; 1374 1375 /** 1376 * Create a debugger with the given `name`. 1377 * 1378 * @param {String} name 1379 * @return {Type} 1380 * @api public 1381 */ 1382 1383 function debug(name) { 1384 if (!debug.enabled(name)) return function(){}; 1385 1386 return function(fmt){ 1387 fmt = coerce(fmt); 1388 1389 var curr = new Date; 1390 var ms = curr - (debug[name] || curr); 1391 debug[name] = curr; 1392 1393 fmt = name 1394 + ' ' 1395 + fmt 1396 + ' +' + debug.humanize(ms); 1397 1398 // This hackery is required for IE8 1399 // where `console.log` doesn't have 'apply' 1400 window.console 1401 && console.log 1402 && Function.prototype.apply.call(console.log, console, arguments); 1403 } 1404 } 1405 1406 /** 1407 * The currently active debug mode names. 1408 */ 1409 1410 debug.names = []; 1411 debug.skips = []; 1412 1413 /** 1414 * Enables a debug mode by name. This can include modes 1415 * separated by a colon and wildcards. 1416 * 1417 * @param {String} name 1418 * @api public 1419 */ 1420 1421 debug.enable = function(name) { 1422 try { 1423 localStorage.debug = name; 1424 } catch(e){} 1425 1426 var split = (name || '').split(/[\s,]+/) 1427 , len = split.length; 1428 1429 for (var i = 0; i < len; i++) { 1430 name = split[i].replace('*', '.*?'); 1431 if (name[0] === '-') { 1432 debug.skips.push(new RegExp('^' + name.substr(1) + '$')); 1433 } 1434 else { 1435 debug.names.push(new RegExp('^' + name + '$')); 1436 } 1437 } 1438 }; 1439 1440 /** 1441 * Disable debug output. 1442 * 1443 * @api public 1444 */ 1445 1446 debug.disable = function(){ 1447 debug.enable(''); 1448 }; 1449 1450 /** 1451 * Humanize the given `ms`. 1452 * 1453 * @param {Number} m 1454 * @return {String} 1455 * @api private 1456 */ 1457 1458 debug.humanize = function(ms) { 1459 var sec = 1000 1460 , min = 60 * 1000 1461 , hour = 60 * min; 1462 1463 if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; 1464 if (ms >= min) return (ms / min).toFixed(1) + 'm'; 1465 if (ms >= sec) return (ms / sec | 0) + 's'; 1466 return ms + 'ms'; 1467 }; 1468 1469 /** 1470 * Returns true if the given mode name is enabled, false otherwise. 1471 * 1472 * @param {String} name 1473 * @return {Boolean} 1474 * @api public 1475 */ 1476 1477 debug.enabled = function(name) { 1478 for (var i = 0, len = debug.skips.length; i < len; i++) { 1479 if (debug.skips[i].test(name)) { 1480 return false; 1481 } 1482 } 1483 for (var i = 0, len = debug.names.length; i < len; i++) { 1484 if (debug.names[i].test(name)) { 1485 return true; 1486 } 1487 } 1488 return false; 1489 }; 1490 1491 /** 1492 * Coerce `val`. 1493 */ 1494 1495 function coerce(val) { 1496 if (val instanceof Error) return val.stack || val.message; 1497 return val; 1498 } 1499 1500 // persist 1501 1502 try { 1503 if (window.localStorage) debug.enable(localStorage.debug); 1504 } catch(e){} 1505 1506 },{}],11:[function(_dereq_,module,exports){ 1507 1508 module.exports = _dereq_('./lib/'); 1509 1510 },{"./lib/":12}],12:[function(_dereq_,module,exports){ 1511 1512 module.exports = _dereq_('./socket'); 1513 1514 /** 1515 * Exports parser 1516 * 1517 * @api public 1518 * 1519 */ 1520 module.exports.parser = _dereq_('engine.io-parser'); 1521 1522 },{"./socket":13,"engine.io-parser":25}],13:[function(_dereq_,module,exports){ 1523 (function (global){ 1524 /** 1525 * Module dependencies. 1526 */ 1527 1528 var transports = _dereq_('./transports'); 1529 var Emitter = _dereq_('component-emitter'); 1530 var debug = _dereq_('debug')('engine.io-client:socket'); 1531 var index = _dereq_('indexof'); 1532 var parser = _dereq_('engine.io-parser'); 1533 var parseuri = _dereq_('parseuri'); 1534 var parsejson = _dereq_('parsejson'); 1535 var parseqs = _dereq_('parseqs'); 1536 1537 /** 1538 * Module exports. 1539 */ 1540 1541 module.exports = Socket; 1542 1543 /** 1544 * Noop function. 1545 * 1546 * @api private 1547 */ 1548 1549 function noop(){} 1550 1551 /** 1552 * Socket constructor. 1553 * 1554 * @param {String|Object} uri or options 1555 * @param {Object} options 1556 * @api public 1557 */ 1558 1559 function Socket(uri, opts){ 1560 if (!(this instanceof Socket)) return new Socket(uri, opts); 1561 1562 opts = opts || {}; 1563 1564 if (uri && 'object' == typeof uri) { 1565 opts = uri; 1566 uri = null; 1567 } 1568 1569 if (uri) { 1570 uri = parseuri(uri); 1571 opts.host = uri.host; 1572 opts.secure = uri.protocol == 'https' || uri.protocol == 'wss'; 1573 opts.port = uri.port; 1574 if (uri.query) opts.query = uri.query; 1575 } 1576 1577 this.secure = null != opts.secure ? opts.secure : 1578 (global.location && 'https:' == location.protocol); 1579 1580 if (opts.host) { 1581 var pieces = opts.host.split(':'); 1582 opts.hostname = pieces.shift(); 1583 if (pieces.length) { 1584 opts.port = pieces.pop(); 1585 } else if (!opts.port) { 1586 // if no port is specified manually, use the protocol default 1587 opts.port = this.secure ? '443' : '80'; 1588 } 1589 } 1590 1591 this.agent = opts.agent || false; 1592 this.hostname = opts.hostname || 1593 (global.location ? location.hostname : 'localhost'); 1594 this.port = opts.port || (global.location && location.port ? 1595 location.port : 1596 (this.secure ? 443 : 80)); 1597 this.query = opts.query || {}; 1598 if ('string' == typeof this.query) this.query = parseqs.decode(this.query); 1599 this.upgrade = false !== opts.upgrade; 1600 this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/'; 1601 this.forceJSONP = !!opts.forceJSONP; 1602 this.jsonp = false !== opts.jsonp; 1603 this.forceBase64 = !!opts.forceBase64; 1604 this.enablesXDR = !!opts.enablesXDR; 1605 this.timestampParam = opts.timestampParam || 't'; 1606 this.timestampRequests = opts.timestampRequests; 1607 this.transports = opts.transports || ['polling', 'websocket']; 1608 this.readyState = ''; 1609 this.writeBuffer = []; 1610 this.callbackBuffer = []; 1611 this.policyPort = opts.policyPort || 843; 1612 this.rememberUpgrade = opts.rememberUpgrade || false; 1613 this.binaryType = null; 1614 this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades; 1615 1616 // SSL options for Node.js client 1617 this.pfx = opts.pfx || null; 1618 this.key = opts.key || null; 1619 this.passphrase = opts.passphrase || null; 1620 this.cert = opts.cert || null; 1621 this.ca = opts.ca || null; 1622 this.ciphers = opts.ciphers || null; 1623 this.rejectUnauthorized = opts.rejectUnauthorized || null; 1624 1625 this.open(); 1626 } 1627 1628 Socket.priorWebsocketSuccess = false; 1629 1630 /** 1631 * Mix in `Emitter`. 1632 */ 1633 1634 Emitter(Socket.prototype); 1635 1636 /** 1637 * Protocol version. 1638 * 1639 * @api public 1640 */ 1641 1642 Socket.protocol = parser.protocol; // this is an int 1643 1644 /** 1645 * Expose deps for legacy compatibility 1646 * and standalone browser access. 1647 */ 1648 1649 Socket.Socket = Socket; 1650 Socket.Transport = _dereq_('./transport'); 1651 Socket.transports = _dereq_('./transports'); 1652 Socket.parser = _dereq_('engine.io-parser'); 1653 1654 /** 1655 * Creates transport of the given type. 1656 * 1657 * @param {String} transport name 1658 * @return {Transport} 1659 * @api private 1660 */ 1661 1662 Socket.prototype.createTransport = function (name) { 1663 debug('creating transport "%s"', name); 1664 var query = clone(this.query); 1665 1666 // append engine.io protocol identifier 1667 query.EIO = parser.protocol; 1668 1669 // transport name 1670 query.transport = name; 1671 1672 // session id if we already have one 1673 if (this.id) query.sid = this.id; 1674 1675 var transport = new transports[name]({ 1676 agent: this.agent, 1677 hostname: this.hostname, 1678 port: this.port, 1679 secure: this.secure, 1680 path: this.path, 1681 query: query, 1682 forceJSONP: this.forceJSONP, 1683 jsonp: this.jsonp, 1684 forceBase64: this.forceBase64, 1685 enablesXDR: this.enablesXDR, 1686 timestampRequests: this.timestampRequests, 1687 timestampParam: this.timestampParam, 1688 policyPort: this.policyPort, 1689 socket: this, 1690 pfx: this.pfx, 1691 key: this.key, 1692 passphrase: this.passphrase, 1693 cert: this.cert, 1694 ca: this.ca, 1695 ciphers: this.ciphers, 1696 rejectUnauthorized: this.rejectUnauthorized 1697 }); 1698 1699 return transport; 1700 }; 1701 1702 function clone (obj) { 1703 var o = {}; 1704 for (var i in obj) { 1705 if (obj.hasOwnProperty(i)) { 1706 o[i] = obj[i]; 1707 } 1708 } 1709 return o; 1710 } 1711 1712 /** 1713 * Initializes transport to use and starts probe. 1714 * 1715 * @api private 1716 */ 1717 Socket.prototype.open = function () { 1718 var transport; 1719 if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) { 1720 transport = 'websocket'; 1721 } else if (0 == this.transports.length) { 1722 // Emit error on next tick so it can be listened to 1723 var self = this; 1724 setTimeout(function() { 1725 self.emit('error', 'No transports available'); 1726 }, 0); 1727 return; 1728 } else { 1729 transport = this.transports[0]; 1730 } 1731 this.readyState = 'opening'; 1732 1733 // Retry with the next transport if the transport is disabled (jsonp: false) 1734 var transport; 1735 try { 1736 transport = this.createTransport(transport); 1737 } catch (e) { 1738 this.transports.shift(); 1739 this.open(); 1740 return; 1741 } 1742 1743 transport.open(); 1744 this.setTransport(transport); 1745 }; 1746 1747 /** 1748 * Sets the current transport. Disables the existing one (if any). 1749 * 1750 * @api private 1751 */ 1752 1753 Socket.prototype.setTransport = function(transport){ 1754 debug('setting transport %s', transport.name); 1755 var self = this; 1756 1757 if (this.transport) { 1758 debug('clearing existing transport %s', this.transport.name); 1759 this.transport.removeAllListeners(); 1760 } 1761 1762 // set up transport 1763 this.transport = transport; 1764 1765 // set up transport listeners 1766 transport 1767 .on('drain', function(){ 1768 self.onDrain(); 1769 }) 1770 .on('packet', function(packet){ 1771 self.onPacket(packet); 1772 }) 1773 .on('error', function(e){ 1774 self.onError(e); 1775 }) 1776 .on('close', function(){ 1777 self.onClose('transport close'); 1778 }); 1779 }; 1780 1781 /** 1782 * Probes a transport. 1783 * 1784 * @param {String} transport name 1785 * @api private 1786 */ 1787 1788 Socket.prototype.probe = function (name) { 1789 debug('probing transport "%s"', name); 1790 var transport = this.createTransport(name, { probe: 1 }) 1791 , failed = false 1792 , self = this; 1793 1794 Socket.priorWebsocketSuccess = false; 1795 1796 function onTransportOpen(){ 1797 if (self.onlyBinaryUpgrades) { 1798 var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary; 1799 failed = failed || upgradeLosesBinary; 1800 } 1801 if (failed) return; 1802 1803 debug('probe transport "%s" opened', name); 1804 transport.send([{ type: 'ping', data: 'probe' }]); 1805 transport.once('packet', function (msg) { 1806 if (failed) return; 1807 if ('pong' == msg.type && 'probe' == msg.data) { 1808 debug('probe transport "%s" pong', name); 1809 self.upgrading = true; 1810 self.emit('upgrading', transport); 1811 if (!transport) return; 1812 Socket.priorWebsocketSuccess = 'websocket' == transport.name; 1813 1814 debug('pausing current transport "%s"', self.transport.name); 1815 self.transport.pause(function () { 1816 if (failed) return; 1817 if ('closed' == self.readyState) return; 1818 debug('changing transport and sending upgrade packet'); 1819 1820 cleanup(); 1821 1822 self.setTransport(transport); 1823 transport.send([{ type: 'upgrade' }]); 1824 self.emit('upgrade', transport); 1825 transport = null; 1826 self.upgrading = false; 1827 self.flush(); 1828 }); 1829 } else { 1830 debug('probe transport "%s" failed', name); 1831 var err = new Error('probe error'); 1832 err.transport = transport.name; 1833 self.emit('upgradeError', err); 1834 } 1835 }); 1836 } 1837 1838 function freezeTransport() { 1839 if (failed) return; 1840 1841 // Any callback called by transport should be ignored since now 1842 failed = true; 1843 1844 cleanup(); 1845 1846 transport.close(); 1847 transport = null; 1848 } 1849 1850 //Handle any error that happens while probing 1851 function onerror(err) { 1852 var error = new Error('probe error: ' + err); 1853 error.transport = transport.name; 1854 1855 freezeTransport(); 1856 1857 debug('probe transport "%s" failed because of error: %s', name, err); 1858 1859 self.emit('upgradeError', error); 1860 } 1861 1862 function onTransportClose(){ 1863 onerror("transport closed"); 1864 } 1865 1866 //When the socket is closed while we're probing 1867 function onclose(){ 1868 onerror("socket closed"); 1869 } 1870 1871 //When the socket is upgraded while we're probing 1872 function onupgrade(to){ 1873 if (transport && to.name != transport.name) { 1874 debug('"%s" works - aborting "%s"', to.name, transport.name); 1875 freezeTransport(); 1876 } 1877 } 1878 1879 //Remove all listeners on the transport and on self 1880 function cleanup(){ 1881 transport.removeListener('open', onTransportOpen); 1882 transport.removeListener('error', onerror); 1883 transport.removeListener('close', onTransportClose); 1884 self.removeListener('close', onclose); 1885 self.removeListener('upgrading', onupgrade); 1886 } 1887 1888 transport.once('open', onTransportOpen); 1889 transport.once('error', onerror); 1890 transport.once('close', onTransportClose); 1891 1892 this.once('close', onclose); 1893 this.once('upgrading', onupgrade); 1894 1895 transport.open(); 1896 1897 }; 1898 1899 /** 1900 * Called when connection is deemed open. 1901 * 1902 * @api public 1903 */ 1904 1905 Socket.prototype.onOpen = function () { 1906 debug('socket open'); 1907 this.readyState = 'open'; 1908 Socket.priorWebsocketSuccess = 'websocket' == this.transport.name; 1909 this.emit('open'); 1910 this.flush(); 1911 1912 // we check for `readyState` in case an `open` 1913 // listener already closed the socket 1914 if ('open' == this.readyState && this.upgrade && this.transport.pause) { 1915 debug('starting upgrade probes'); 1916 for (var i = 0, l = this.upgrades.length; i < l; i++) { 1917 this.probe(this.upgrades[i]); 1918 } 1919 } 1920 }; 1921 1922 /** 1923 * Handles a packet. 1924 * 1925 * @api private 1926 */ 1927 1928 Socket.prototype.onPacket = function (packet) { 1929 if ('opening' == this.readyState || 'open' == this.readyState) { 1930 debug('socket receive: type "%s", data "%s"', packet.type, packet.data); 1931 1932 this.emit('packet', packet); 1933 1934 // Socket is live - any packet counts 1935 this.emit('heartbeat'); 1936 1937 switch (packet.type) { 1938 case 'open': 1939 this.onHandshake(parsejson(packet.data)); 1940 break; 1941 1942 case 'pong': 1943 this.setPing(); 1944 break; 1945 1946 case 'error': 1947 var err = new Error('server error'); 1948 err.code = packet.data; 1949 this.emit('error', err); 1950 break; 1951 1952 case 'message': 1953 this.emit('data', packet.data); 1954 this.emit('message', packet.data); 1955 break; 1956 } 1957 } else { 1958 debug('packet received with socket readyState "%s"', this.readyState); 1959 } 1960 }; 1961 1962 /** 1963 * Called upon handshake completion. 1964 * 1965 * @param {Object} handshake obj 1966 * @api private 1967 */ 1968 1969 Socket.prototype.onHandshake = function (data) { 1970 this.emit('handshake', data); 1971 this.id = data.sid; 1972 this.transport.query.sid = data.sid; 1973 this.upgrades = this.filterUpgrades(data.upgrades); 1974 this.pingInterval = data.pingInterval; 1975 this.pingTimeout = data.pingTimeout; 1976 this.onOpen(); 1977 // In case open handler closes socket 1978 if ('closed' == this.readyState) return; 1979 this.setPing(); 1980 1981 // Prolong liveness of socket on heartbeat 1982 this.removeListener('heartbeat', this.onHeartbeat); 1983 this.on('heartbeat', this.onHeartbeat); 1984 }; 1985 1986 /** 1987 * Resets ping timeout. 1988 * 1989 * @api private 1990 */ 1991 1992 Socket.prototype.onHeartbeat = function (timeout) { 1993 clearTimeout(this.pingTimeoutTimer); 1994 var self = this; 1995 self.pingTimeoutTimer = setTimeout(function () { 1996 if ('closed' == self.readyState) return; 1997 self.onClose('ping timeout'); 1998 }, timeout || (self.pingInterval + self.pingTimeout)); 1999 }; 2000 2001 /** 2002 * Pings server every `this.pingInterval` and expects response 2003 * within `this.pingTimeout` or closes connection. 2004 * 2005 * @api private 2006 */ 2007 2008 Socket.prototype.setPing = function () { 2009 var self = this; 2010 clearTimeout(self.pingIntervalTimer); 2011 self.pingIntervalTimer = setTimeout(function () { 2012 debug('writing ping packet - expecting pong within %sms', self.pingTimeout); 2013 self.ping(); 2014 self.onHeartbeat(self.pingTimeout); 2015 }, self.pingInterval); 2016 }; 2017 2018 /** 2019 * Sends a ping packet. 2020 * 2021 * @api public 2022 */ 2023 2024 Socket.prototype.ping = function () { 2025 this.sendPacket('ping'); 2026 }; 2027 2028 /** 2029 * Called on `drain` event 2030 * 2031 * @api private 2032 */ 2033 2034 Socket.prototype.onDrain = function() { 2035 for (var i = 0; i < this.prevBufferLen; i++) { 2036 if (this.callbackBuffer[i]) { 2037 this.callbackBuffer[i](); 2038 } 2039 } 2040 2041 this.writeBuffer.splice(0, this.prevBufferLen); 2042 this.callbackBuffer.splice(0, this.prevBufferLen); 2043 2044 // setting prevBufferLen = 0 is very important 2045 // for example, when upgrading, upgrade packet is sent over, 2046 // and a nonzero prevBufferLen could cause problems on `drain` 2047 this.prevBufferLen = 0; 2048 2049 if (this.writeBuffer.length == 0) { 2050 this.emit('drain'); 2051 } else { 2052 this.flush(); 2053 } 2054 }; 2055 2056 /** 2057 * Flush write buffers. 2058 * 2059 * @api private 2060 */ 2061 2062 Socket.prototype.flush = function () { 2063 if ('closed' != this.readyState && this.transport.writable && 2064 !this.upgrading && this.writeBuffer.length) { 2065 debug('flushing %d packets in socket', this.writeBuffer.length); 2066 this.transport.send(this.writeBuffer); 2067 // keep track of current length of writeBuffer 2068 // splice writeBuffer and callbackBuffer on `drain` 2069 this.prevBufferLen = this.writeBuffer.length; 2070 this.emit('flush'); 2071 } 2072 }; 2073 2074 /** 2075 * Sends a message. 2076 * 2077 * @param {String} message. 2078 * @param {Function} callback function. 2079 * @return {Socket} for chaining. 2080 * @api public 2081 */ 2082 2083 Socket.prototype.write = 2084 Socket.prototype.send = function (msg, fn) { 2085 this.sendPacket('message', msg, fn); 2086 return this; 2087 }; 2088 2089 /** 2090 * Sends a packet. 2091 * 2092 * @param {String} packet type. 2093 * @param {String} data. 2094 * @param {Function} callback function. 2095 * @api private 2096 */ 2097 2098 Socket.prototype.sendPacket = function (type, data, fn) { 2099 if ('closing' == this.readyState || 'closed' == this.readyState) { 2100 return; 2101 } 2102 2103 var packet = { type: type, data: data }; 2104 this.emit('packetCreate', packet); 2105 this.writeBuffer.push(packet); 2106 this.callbackBuffer.push(fn); 2107 this.flush(); 2108 }; 2109 2110 /** 2111 * Closes the connection. 2112 * 2113 * @api private 2114 */ 2115 2116 Socket.prototype.close = function () { 2117 if ('opening' == this.readyState || 'open' == this.readyState) { 2118 this.readyState = 'closing'; 2119 2120 var self = this; 2121 2122 function close() { 2123 self.onClose('forced close'); 2124 debug('socket closing - telling transport to close'); 2125 self.transport.close(); 2126 } 2127 2128 function cleanupAndClose() { 2129 self.removeListener('upgrade', cleanupAndClose); 2130 self.removeListener('upgradeError', cleanupAndClose); 2131 close(); 2132 } 2133 2134 function waitForUpgrade() { 2135 // wait for upgrade to finish since we can't send packets while pausing a transport 2136 self.once('upgrade', cleanupAndClose); 2137 self.once('upgradeError', cleanupAndClose); 2138 } 2139 2140 if (this.writeBuffer.length) { 2141 this.once('drain', function() { 2142 if (this.upgrading) { 2143 waitForUpgrade(); 2144 } else { 2145 close(); 2146 } 2147 }); 2148 } else if (this.upgrading) { 2149 waitForUpgrade(); 2150 } else { 2151 close(); 2152 } 2153 } 2154 2155 return this; 2156 }; 2157 2158 /** 2159 * Called upon transport error 2160 * 2161 * @api private 2162 */ 2163 2164 Socket.prototype.onError = function (err) { 2165 debug('socket error %j', err); 2166 Socket.priorWebsocketSuccess = false; 2167 this.emit('error', err); 2168 this.onClose('transport error', err); 2169 }; 2170 2171 /** 2172 * Called upon transport close. 2173 * 2174 * @api private 2175 */ 2176 2177 Socket.prototype.onClose = function (reason, desc) { 2178 if ('opening' == this.readyState || 'open' == this.readyState || 'closing' == this.readyState) { 2179 debug('socket close with reason: "%s"', reason); 2180 var self = this; 2181 2182 // clear timers 2183 clearTimeout(this.pingIntervalTimer); 2184 clearTimeout(this.pingTimeoutTimer); 2185 2186 // clean buffers in next tick, so developers can still 2187 // grab the buffers on `close` event 2188 setTimeout(function() { 2189 self.writeBuffer = []; 2190 self.callbackBuffer = []; 2191 self.prevBufferLen = 0; 2192 }, 0); 2193 2194 // stop event from firing again for transport 2195 this.transport.removeAllListeners('close'); 2196 2197 // ensure transport won't stay open 2198 this.transport.close(); 2199 2200 // ignore further transport communication 2201 this.transport.removeAllListeners(); 2202 2203 // set ready state 2204 this.readyState = 'closed'; 2205 2206 // clear session id 2207 this.id = null; 2208 2209 // emit close event 2210 this.emit('close', reason, desc); 2211 } 2212 }; 2213 2214 /** 2215 * Filters upgrades, returning only those matching client transports. 2216 * 2217 * @param {Array} server upgrades 2218 * @api private 2219 * 2220 */ 2221 2222 Socket.prototype.filterUpgrades = function (upgrades) { 2223 var filteredUpgrades = []; 2224 for (var i = 0, j = upgrades.length; i<j; i++) { 2225 if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]); 2226 } 2227 return filteredUpgrades; 2228 }; 2229 2230 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 2231 },{"./transport":14,"./transports":15,"component-emitter":9,"debug":22,"engine.io-parser":25,"indexof":40,"parsejson":32,"parseqs":33,"parseuri":34}],14:[function(_dereq_,module,exports){ 2232 /** 2233 * Module dependencies. 2234 */ 2235 2236 var parser = _dereq_('engine.io-parser'); 2237 var Emitter = _dereq_('component-emitter'); 2238 2239 /** 2240 * Module exports. 2241 */ 2242 2243 module.exports = Transport; 2244 2245 /** 2246 * Transport abstract constructor. 2247 * 2248 * @param {Object} options. 2249 * @api private 2250 */ 2251 2252 function Transport (opts) { 2253 this.path = opts.path; 2254 this.hostname = opts.hostname; 2255 this.port = opts.port; 2256 this.secure = opts.secure; 2257 this.query = opts.query; 2258 this.timestampParam = opts.timestampParam; 2259 this.timestampRequests = opts.timestampRequests; 2260 this.readyState = ''; 2261 this.agent = opts.agent || false; 2262 this.socket = opts.socket; 2263 this.enablesXDR = opts.enablesXDR; 2264 2265 // SSL options for Node.js client 2266 this.pfx = opts.pfx; 2267 this.key = opts.key; 2268 this.passphrase = opts.passphrase; 2269 this.cert = opts.cert; 2270 this.ca = opts.ca; 2271 this.ciphers = opts.ciphers; 2272 this.rejectUnauthorized = opts.rejectUnauthorized; 2273 } 2274 2275 /** 2276 * Mix in `Emitter`. 2277 */ 2278 2279 Emitter(Transport.prototype); 2280 2281 /** 2282 * A counter used to prevent collisions in the timestamps used 2283 * for cache busting. 2284 */ 2285 2286 Transport.timestamps = 0; 2287 2288 /** 2289 * Emits an error. 2290 * 2291 * @param {String} str 2292 * @return {Transport} for chaining 2293 * @api public 2294 */ 2295 2296 Transport.prototype.onError = function (msg, desc) { 2297 var err = new Error(msg); 2298 err.type = 'TransportError'; 2299 err.description = desc; 2300 this.emit('error', err); 2301 return this; 2302 }; 2303 2304 /** 2305 * Opens the transport. 2306 * 2307 * @api public 2308 */ 2309 2310 Transport.prototype.open = function () { 2311 if ('closed' == this.readyState || '' == this.readyState) { 2312 this.readyState = 'opening'; 2313 this.doOpen(); 2314 } 2315 2316 return this; 2317 }; 2318 2319 /** 2320 * Closes the transport. 2321 * 2322 * @api private 2323 */ 2324 2325 Transport.prototype.close = function () { 2326 if ('opening' == this.readyState || 'open' == this.readyState) { 2327 this.doClose(); 2328 this.onClose(); 2329 } 2330 2331 return this; 2332 }; 2333 2334 /** 2335 * Sends multiple packets. 2336 * 2337 * @param {Array} packets 2338 * @api private 2339 */ 2340 2341 Transport.prototype.send = function(packets){ 2342 if ('open' == this.readyState) { 2343 this.write(packets); 2344 } else { 2345 throw new Error('Transport not open'); 2346 } 2347 }; 2348 2349 /** 2350 * Called upon open 2351 * 2352 * @api private 2353 */ 2354 2355 Transport.prototype.onOpen = function () { 2356 this.readyState = 'open'; 2357 this.writable = true; 2358 this.emit('open'); 2359 }; 2360 2361 /** 2362 * Called with data. 2363 * 2364 * @param {String} data 2365 * @api private 2366 */ 2367 2368 Transport.prototype.onData = function(data){ 2369 var packet = parser.decodePacket(data, this.socket.binaryType); 2370 this.onPacket(packet); 2371 }; 2372 2373 /** 2374 * Called with a decoded packet. 2375 */ 2376 2377 Transport.prototype.onPacket = function (packet) { 2378 this.emit('packet', packet); 2379 }; 2380 2381 /** 2382 * Called upon close. 2383 * 2384 * @api private 2385 */ 2386 2387 Transport.prototype.onClose = function () { 2388 this.readyState = 'closed'; 2389 this.emit('close'); 2390 }; 2391 2392 },{"component-emitter":9,"engine.io-parser":25}],15:[function(_dereq_,module,exports){ 2393 (function (global){ 2394 /** 2395 * Module dependencies 2396 */ 2397 2398 var XMLHttpRequest = _dereq_('xmlhttprequest'); 2399 var XHR = _dereq_('./polling-xhr'); 2400 var JSONP = _dereq_('./polling-jsonp'); 2401 var websocket = _dereq_('./websocket'); 2402 2403 /** 2404 * Export transports. 2405 */ 2406 2407 exports.polling = polling; 2408 exports.websocket = websocket; 2409 2410 /** 2411 * Polling transport polymorphic constructor. 2412 * Decides on xhr vs jsonp based on feature detection. 2413 * 2414 * @api private 2415 */ 2416 2417 function polling(opts){ 2418 var xhr; 2419 var xd = false; 2420 var xs = false; 2421 var jsonp = false !== opts.jsonp; 2422 2423 if (global.location) { 2424 var isSSL = 'https:' == location.protocol; 2425 var port = location.port; 2426 2427 // some user agents have empty `location.port` 2428 if (!port) { 2429 port = isSSL ? 443 : 80; 2430 } 2431 2432 xd = opts.hostname != location.hostname || port != opts.port; 2433 xs = opts.secure != isSSL; 2434 } 2435 2436 opts.xdomain = xd; 2437 opts.xscheme = xs; 2438 xhr = new XMLHttpRequest(opts); 2439 2440 if ('open' in xhr && !opts.forceJSONP) { 2441 return new XHR(opts); 2442 } else { 2443 if (!jsonp) throw new Error('JSONP disabled'); 2444 return new JSONP(opts); 2445 } 2446 } 2447 2448 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 2449 },{"./polling-jsonp":16,"./polling-xhr":17,"./websocket":19,"xmlhttprequest":20}],16:[function(_dereq_,module,exports){ 2450 (function (global){ 2451 2452 /** 2453 * Module requirements. 2454 */ 2455 2456 var Polling = _dereq_('./polling'); 2457 var inherit = _dereq_('component-inherit'); 2458 2459 /** 2460 * Module exports. 2461 */ 2462 2463 module.exports = JSONPPolling; 2464 2465 /** 2466 * Cached regular expressions. 2467 */ 2468 2469 var rNewline = /\n/g; 2470 var rEscapedNewline = /\\n/g; 2471 2472 /** 2473 * Global JSONP callbacks. 2474 */ 2475 2476 var callbacks; 2477 2478 /** 2479 * Callbacks count. 2480 */ 2481 2482 var index = 0; 2483 2484 /** 2485 * Noop. 2486 */ 2487 2488 function empty () { } 2489 2490 /** 2491 * JSONP Polling constructor. 2492 * 2493 * @param {Object} opts. 2494 * @api public 2495 */ 2496 2497 function JSONPPolling (opts) { 2498 Polling.call(this, opts); 2499 2500 this.query = this.query || {}; 2501 2502 // define global callbacks array if not present 2503 // we do this here (lazily) to avoid unneeded global pollution 2504 if (!callbacks) { 2505 // we need to consider multiple engines in the same page 2506 if (!global.___eio) global.___eio = []; 2507 callbacks = global.___eio; 2508 } 2509 2510 // callback identifier 2511 this.index = callbacks.length; 2512 2513 // add callback to jsonp global 2514 var self = this; 2515 callbacks.push(function (msg) { 2516 self.onData(msg); 2517 }); 2518 2519 // append to query string 2520 this.query.j = this.index; 2521 2522 // prevent spurious errors from being emitted when the window is unloaded 2523 if (global.document && global.addEventListener) { 2524 global.addEventListener('beforeunload', function () { 2525 if (self.script) self.script.onerror = empty; 2526 }, false); 2527 } 2528 } 2529 2530 /** 2531 * Inherits from Polling. 2532 */ 2533 2534 inherit(JSONPPolling, Polling); 2535 2536 /* 2537 * JSONP only supports binary as base64 encoded strings 2538 */ 2539 2540 JSONPPolling.prototype.supportsBinary = false; 2541 2542 /** 2543 * Closes the socket. 2544 * 2545 * @api private 2546 */ 2547 2548 JSONPPolling.prototype.doClose = function () { 2549 if (this.script) { 2550 this.script.parentNode.removeChild(this.script); 2551 this.script = null; 2552 } 2553 2554 if (this.form) { 2555 this.form.parentNode.removeChild(this.form); 2556 this.form = null; 2557 this.iframe = null; 2558 } 2559 2560 Polling.prototype.doClose.call(this); 2561 }; 2562 2563 /** 2564 * Starts a poll cycle. 2565 * 2566 * @api private 2567 */ 2568 2569 JSONPPolling.prototype.doPoll = function () { 2570 var self = this; 2571 var script = document.createElement('script'); 2572 2573 if (this.script) { 2574 this.script.parentNode.removeChild(this.script); 2575 this.script = null; 2576 } 2577 2578 script.async = true; 2579 script.src = this.uri(); 2580 script.onerror = function(e){ 2581 self.onError('jsonp poll error',e); 2582 }; 2583 2584 var insertAt = document.getElementsByTagName('script')[0]; 2585 insertAt.parentNode.insertBefore(script, insertAt); 2586 this.script = script; 2587 2588 var isUAgecko = 'undefined' != typeof navigator && /gecko/i.test(navigator.userAgent); 2589 2590 if (isUAgecko) { 2591 setTimeout(function () { 2592 var iframe = document.createElement('iframe'); 2593 document.body.appendChild(iframe); 2594 document.body.removeChild(iframe); 2595 }, 100); 2596 } 2597 }; 2598 2599 /** 2600 * Writes with a hidden iframe. 2601 * 2602 * @param {String} data to send 2603 * @param {Function} called upon flush. 2604 * @api private 2605 */ 2606 2607 JSONPPolling.prototype.doWrite = function (data, fn) { 2608 var self = this; 2609 2610 if (!this.form) { 2611 var form = document.createElement('form'); 2612 var area = document.createElement('textarea'); 2613 var id = this.iframeId = 'eio_iframe_' + this.index; 2614 var iframe; 2615 2616 form.className = 'socketio'; 2617 form.style.position = 'absolute'; 2618 form.style.top = '-1000px'; 2619 form.style.left = '-1000px'; 2620 form.target = id; 2621 form.method = 'POST'; 2622 form.setAttribute('accept-charset', 'utf-8'); 2623 area.name = 'd'; 2624 form.appendChild(area); 2625 document.body.appendChild(form); 2626 2627 this.form = form; 2628 this.area = area; 2629 } 2630 2631 this.form.action = this.uri(); 2632 2633 function complete () { 2634 initIframe(); 2635 fn(); 2636 } 2637 2638 function initIframe () { 2639 if (self.iframe) { 2640 try { 2641 self.form.removeChild(self.iframe); 2642 } catch (e) { 2643 self.onError('jsonp polling iframe removal error', e); 2644 } 2645 } 2646 2647 try { 2648 // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) 2649 var html = '<iframe src="javascript:0" name="'+ self.iframeId +'">'; 2650 iframe = document.createElement(html); 2651 } catch (e) { 2652 iframe = document.createElement('iframe'); 2653 iframe.name = self.iframeId; 2654 iframe.src = 'javascript:0'; 2655 } 2656 2657 iframe.id = self.iframeId; 2658 2659 self.form.appendChild(iframe); 2660 self.iframe = iframe; 2661 } 2662 2663 initIframe(); 2664 2665 // escape \n to prevent it from being converted into \r\n by some UAs 2666 // double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side 2667 data = data.replace(rEscapedNewline, '\\\n'); 2668 this.area.value = data.replace(rNewline, '\\n'); 2669 2670 try { 2671 this.form.submit(); 2672 } catch(e) {} 2673 2674 if (this.iframe.attachEvent) { 2675 this.iframe.onreadystatechange = function(){ 2676 if (self.iframe.readyState == 'complete') { 2677 complete(); 2678 } 2679 }; 2680 } else { 2681 this.iframe.onload = complete; 2682 } 2683 }; 2684 2685 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 2686 },{"./polling":18,"component-inherit":21}],17:[function(_dereq_,module,exports){ 2687 (function (global){ 2688 /** 2689 * Module requirements. 2690 */ 2691 2692 var XMLHttpRequest = _dereq_('xmlhttprequest'); 2693 var Polling = _dereq_('./polling'); 2694 var Emitter = _dereq_('component-emitter'); 2695 var inherit = _dereq_('component-inherit'); 2696 var debug = _dereq_('debug')('engine.io-client:polling-xhr'); 2697 2698 /** 2699 * Module exports. 2700 */ 2701 2702 module.exports = XHR; 2703 module.exports.Request = Request; 2704 2705 /** 2706 * Empty function 2707 */ 2708 2709 function empty(){} 2710 2711 /** 2712 * XHR Polling constructor. 2713 * 2714 * @param {Object} opts 2715 * @api public 2716 */ 2717 2718 function XHR(opts){ 2719 Polling.call(this, opts); 2720 2721 if (global.location) { 2722 var isSSL = 'https:' == location.protocol; 2723 var port = location.port; 2724 2725 // some user agents have empty `location.port` 2726 if (!port) { 2727 port = isSSL ? 443 : 80; 2728 } 2729 2730 this.xd = opts.hostname != global.location.hostname || 2731 port != opts.port; 2732 this.xs = opts.secure != isSSL; 2733 } 2734 } 2735 2736 /** 2737 * Inherits from Polling. 2738 */ 2739 2740 inherit(XHR, Polling); 2741 2742 /** 2743 * XHR supports binary 2744 */ 2745 2746 XHR.prototype.supportsBinary = true; 2747 2748 /** 2749 * Creates a request. 2750 * 2751 * @param {String} method 2752 * @api private 2753 */ 2754 2755 XHR.prototype.request = function(opts){ 2756 opts = opts || {}; 2757 opts.uri = this.uri(); 2758 opts.xd = this.xd; 2759 opts.xs = this.xs; 2760 opts.agent = this.agent || false; 2761 opts.supportsBinary = this.supportsBinary; 2762 opts.enablesXDR = this.enablesXDR; 2763 2764 // SSL options for Node.js client 2765 opts.pfx = this.pfx; 2766 opts.key = this.key; 2767 opts.passphrase = this.passphrase; 2768 opts.cert = this.cert; 2769 opts.ca = this.ca; 2770 opts.ciphers = this.ciphers; 2771 opts.rejectUnauthorized = this.rejectUnauthorized; 2772 2773 return new Request(opts); 2774 }; 2775 2776 /** 2777 * Sends data. 2778 * 2779 * @param {String} data to send. 2780 * @param {Function} called upon flush. 2781 * @api private 2782 */ 2783 2784 XHR.prototype.doWrite = function(data, fn){ 2785 var isBinary = typeof data !== 'string' && data !== undefined; 2786 var req = this.request({ method: 'POST', data: data, isBinary: isBinary }); 2787 var self = this; 2788 req.on('success', fn); 2789 req.on('error', function(err){ 2790 self.onError('xhr post error', err); 2791 }); 2792 this.sendXhr = req; 2793 }; 2794 2795 /** 2796 * Starts a poll cycle. 2797 * 2798 * @api private 2799 */ 2800 2801 XHR.prototype.doPoll = function(){ 2802 debug('xhr poll'); 2803 var req = this.request(); 2804 var self = this; 2805 req.on('data', function(data){ 2806 self.onData(data); 2807 }); 2808 req.on('error', function(err){ 2809 self.onError('xhr poll error', err); 2810 }); 2811 this.pollXhr = req; 2812 }; 2813 2814 /** 2815 * Request constructor 2816 * 2817 * @param {Object} options 2818 * @api public 2819 */ 2820 2821 function Request(opts){ 2822 this.method = opts.method || 'GET'; 2823 this.uri = opts.uri; 2824 this.xd = !!opts.xd; 2825 this.xs = !!opts.xs; 2826 this.async = false !== opts.async; 2827 this.data = undefined != opts.data ? opts.data : null; 2828 this.agent = opts.agent; 2829 this.isBinary = opts.isBinary; 2830 this.supportsBinary = opts.supportsBinary; 2831 this.enablesXDR = opts.enablesXDR; 2832 2833 // SSL options for Node.js client 2834 this.pfx = opts.pfx; 2835 this.key = opts.key; 2836 this.passphrase = opts.passphrase; 2837 this.cert = opts.cert; 2838 this.ca = opts.ca; 2839 this.ciphers = opts.ciphers; 2840 this.rejectUnauthorized = opts.rejectUnauthorized; 2841 2842 this.create(); 2843 } 2844 2845 /** 2846 * Mix in `Emitter`. 2847 */ 2848 2849 Emitter(Request.prototype); 2850 2851 /** 2852 * Creates the XHR object and sends the request. 2853 * 2854 * @api private 2855 */ 2856 2857 Request.prototype.create = function(){ 2858 var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR }; 2859 2860 // SSL options for Node.js client 2861 opts.pfx = this.pfx; 2862 opts.key = this.key; 2863 opts.passphrase = this.passphrase; 2864 opts.cert = this.cert; 2865 opts.ca = this.ca; 2866 opts.ciphers = this.ciphers; 2867 opts.rejectUnauthorized = this.rejectUnauthorized; 2868 2869 var xhr = this.xhr = new XMLHttpRequest(opts); 2870 var self = this; 2871 2872 try { 2873 debug('xhr open %s: %s', this.method, this.uri); 2874 xhr.open(this.method, this.uri, this.async); 2875 if (this.supportsBinary) { 2876 // This has to be done after open because Firefox is stupid 2877 // http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension 2878 xhr.responseType = 'arraybuffer'; 2879 } 2880 2881 if ('POST' == this.method) { 2882 try { 2883 if (this.isBinary) { 2884 xhr.setRequestHeader('Content-type', 'application/octet-stream'); 2885 } else { 2886 xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8'); 2887 } 2888 } catch (e) {} 2889 } 2890 2891 // ie6 check 2892 if ('withCredentials' in xhr) { 2893 xhr.withCredentials = true; 2894 } 2895 2896 if (this.hasXDR()) { 2897 xhr.onload = function(){ 2898 self.onLoad(); 2899 }; 2900 xhr.onerror = function(){ 2901 self.onError(xhr.responseText); 2902 }; 2903 } else { 2904 xhr.onreadystatechange = function(){ 2905 if (4 != xhr.readyState) return; 2906 if (200 == xhr.status || 1223 == xhr.status) { 2907 self.onLoad(); 2908 } else { 2909 // make sure the `error` event handler that's user-set 2910 // does not throw in the same tick and gets caught here 2911 setTimeout(function(){ 2912 self.onError(xhr.status); 2913 }, 0); 2914 } 2915 }; 2916 } 2917 2918 debug('xhr data %s', this.data); 2919 xhr.send(this.data); 2920 } catch (e) { 2921 // Need to defer since .create() is called directly fhrom the constructor 2922 // and thus the 'error' event can only be only bound *after* this exception 2923 // occurs. Therefore, also, we cannot throw here at all. 2924 setTimeout(function() { 2925 self.onError(e); 2926 }, 0); 2927 return; 2928 } 2929 2930 if (global.document) { 2931 this.index = Request.requestsCount++; 2932 Request.requests[this.index] = this; 2933 } 2934 }; 2935 2936 /** 2937 * Called upon successful response. 2938 * 2939 * @api private 2940 */ 2941 2942 Request.prototype.onSuccess = function(){ 2943 this.emit('success'); 2944 this.cleanup(); 2945 }; 2946 2947 /** 2948 * Called if we have data. 2949 * 2950 * @api private 2951 */ 2952 2953 Request.prototype.onData = function(data){ 2954 this.emit('data', data); 2955 this.onSuccess(); 2956 }; 2957 2958 /** 2959 * Called upon error. 2960 * 2961 * @api private 2962 */ 2963 2964 Request.prototype.onError = function(err){ 2965 this.emit('error', err); 2966 this.cleanup(true); 2967 }; 2968 2969 /** 2970 * Cleans up house. 2971 * 2972 * @api private 2973 */ 2974 2975 Request.prototype.cleanup = function(fromError){ 2976 if ('undefined' == typeof this.xhr || null === this.xhr) { 2977 return; 2978 } 2979 // xmlhttprequest 2980 if (this.hasXDR()) { 2981 this.xhr.onload = this.xhr.onerror = empty; 2982 } else { 2983 this.xhr.onreadystatechange = empty; 2984 } 2985 2986 if (fromError) { 2987 try { 2988 this.xhr.abort(); 2989 } catch(e) {} 2990 } 2991 2992 if (global.document) { 2993 delete Request.requests[this.index]; 2994 } 2995 2996 this.xhr = null; 2997 }; 2998 2999 /** 3000 * Called upon load. 3001 * 3002 * @api private 3003 */ 3004 3005 Request.prototype.onLoad = function(){ 3006 var data; 3007 try { 3008 var contentType; 3009 try { 3010 contentType = this.xhr.getResponseHeader('Content-Type').split(';')[0]; 3011 } catch (e) {} 3012 if (contentType === 'application/octet-stream') { 3013 data = this.xhr.response; 3014 } else { 3015 if (!this.supportsBinary) { 3016 data = this.xhr.responseText; 3017 } else { 3018 data = 'ok'; 3019 } 3020 } 3021 } catch (e) { 3022 this.onError(e); 3023 } 3024 if (null != data) { 3025 this.onData(data); 3026 } 3027 }; 3028 3029 /** 3030 * Check if it has XDomainRequest. 3031 * 3032 * @api private 3033 */ 3034 3035 Request.prototype.hasXDR = function(){ 3036 return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR; 3037 }; 3038 3039 /** 3040 * Aborts the request. 3041 * 3042 * @api public 3043 */ 3044 3045 Request.prototype.abort = function(){ 3046 this.cleanup(); 3047 }; 3048 3049 /** 3050 * Aborts pending requests when unloading the window. This is needed to prevent 3051 * memory leaks (e.g. when using IE) and to ensure that no spurious error is 3052 * emitted. 3053 */ 3054 3055 if (global.document) { 3056 Request.requestsCount = 0; 3057 Request.requests = {}; 3058 if (global.attachEvent) { 3059 global.attachEvent('onunload', unloadHandler); 3060 } else if (global.addEventListener) { 3061 global.addEventListener('beforeunload', unloadHandler, false); 3062 } 3063 } 3064 3065 function unloadHandler() { 3066 for (var i in Request.requests) { 3067 if (Request.requests.hasOwnProperty(i)) { 3068 Request.requests[i].abort(); 3069 } 3070 } 3071 } 3072 3073 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 3074 },{"./polling":18,"component-emitter":9,"component-inherit":21,"debug":22,"xmlhttprequest":20}],18:[function(_dereq_,module,exports){ 3075 /** 3076 * Module dependencies. 3077 */ 3078 3079 var Transport = _dereq_('../transport'); 3080 var parseqs = _dereq_('parseqs'); 3081 var parser = _dereq_('engine.io-parser'); 3082 var inherit = _dereq_('component-inherit'); 3083 var debug = _dereq_('debug')('engine.io-client:polling'); 3084 3085 /** 3086 * Module exports. 3087 */ 3088 3089 module.exports = Polling; 3090 3091 /** 3092 * Is XHR2 supported? 3093 */ 3094 3095 var hasXHR2 = (function() { 3096 var XMLHttpRequest = _dereq_('xmlhttprequest'); 3097 var xhr = new XMLHttpRequest({ xdomain: false }); 3098 return null != xhr.responseType; 3099 })(); 3100 3101 /** 3102 * Polling interface. 3103 * 3104 * @param {Object} opts 3105 * @api private 3106 */ 3107 3108 function Polling(opts){ 3109 var forceBase64 = (opts && opts.forceBase64); 3110 if (!hasXHR2 || forceBase64) { 3111 this.supportsBinary = false; 3112 } 3113 Transport.call(this, opts); 3114 } 3115 3116 /** 3117 * Inherits from Transport. 3118 */ 3119 3120 inherit(Polling, Transport); 3121 3122 /** 3123 * Transport name. 3124 */ 3125 3126 Polling.prototype.name = 'polling'; 3127 3128 /** 3129 * Opens the socket (triggers polling). We write a PING message to determine 3130 * when the transport is open. 3131 * 3132 * @api private 3133 */ 3134 3135 Polling.prototype.doOpen = function(){ 3136 this.poll(); 3137 }; 3138 3139 /** 3140 * Pauses polling. 3141 * 3142 * @param {Function} callback upon buffers are flushed and transport is paused 3143 * @api private 3144 */ 3145 3146 Polling.prototype.pause = function(onPause){ 3147 var pending = 0; 3148 var self = this; 3149 3150 this.readyState = 'pausing'; 3151 3152 function pause(){ 3153 debug('paused'); 3154 self.readyState = 'paused'; 3155 onPause(); 3156 } 3157 3158 if (this.polling || !this.writable) { 3159 var total = 0; 3160 3161 if (this.polling) { 3162 debug('we are currently polling - waiting to pause'); 3163 total++; 3164 this.once('pollComplete', function(){ 3165 debug('pre-pause polling complete'); 3166 --total || pause(); 3167 }); 3168 } 3169 3170 if (!this.writable) { 3171 debug('we are currently writing - waiting to pause'); 3172 total++; 3173 this.once('drain', function(){ 3174 debug('pre-pause writing complete'); 3175 --total || pause(); 3176 }); 3177 } 3178 } else { 3179 pause(); 3180 } 3181 }; 3182 3183 /** 3184 * Starts polling cycle. 3185 * 3186 * @api public 3187 */ 3188 3189 Polling.prototype.poll = function(){ 3190 debug('polling'); 3191 this.polling = true; 3192 this.doPoll(); 3193 this.emit('poll'); 3194 }; 3195 3196 /** 3197 * Overloads onData to detect payloads. 3198 * 3199 * @api private 3200 */ 3201 3202 Polling.prototype.onData = function(data){ 3203 var self = this; 3204 debug('polling got data %s', data); 3205 var callback = function(packet, index, total) { 3206 // if its the first message we consider the transport open 3207 if ('opening' == self.readyState) { 3208 self.onOpen(); 3209 } 3210 3211 // if its a close packet, we close the ongoing requests 3212 if ('close' == packet.type) { 3213 self.onClose(); 3214 return false; 3215 } 3216 3217 // otherwise bypass onData and handle the message 3218 self.onPacket(packet); 3219 }; 3220 3221 // decode payload 3222 parser.decodePayload(data, this.socket.binaryType, callback); 3223 3224 // if an event did not trigger closing 3225 if ('closed' != this.readyState) { 3226 // if we got data we're not polling 3227 this.polling = false; 3228 this.emit('pollComplete'); 3229 3230 if ('open' == this.readyState) { 3231 this.poll(); 3232 } else { 3233 debug('ignoring poll - transport state "%s"', this.readyState); 3234 } 3235 } 3236 }; 3237 3238 /** 3239 * For polling, send a close packet. 3240 * 3241 * @api private 3242 */ 3243 3244 Polling.prototype.doClose = function(){ 3245 var self = this; 3246 3247 function close(){ 3248 debug('writing close packet'); 3249 self.write([{ type: 'close' }]); 3250 } 3251 3252 if ('open' == this.readyState) { 3253 debug('transport open - closing'); 3254 close(); 3255 } else { 3256 // in case we're trying to close while 3257 // handshaking is in progress (GH-164) 3258 debug('transport not open - deferring close'); 3259 this.once('open', close); 3260 } 3261 }; 3262 3263 /** 3264 * Writes a packets payload. 3265 * 3266 * @param {Array} data packets 3267 * @param {Function} drain callback 3268 * @api private 3269 */ 3270 3271 Polling.prototype.write = function(packets){ 3272 var self = this; 3273 this.writable = false; 3274 var callbackfn = function() { 3275 self.writable = true; 3276 self.emit('drain'); 3277 }; 3278 3279 var self = this; 3280 parser.encodePayload(packets, this.supportsBinary, function(data) { 3281 self.doWrite(data, callbackfn); 3282 }); 3283 }; 3284 3285 /** 3286 * Generates uri for connection. 3287 * 3288 * @api private 3289 */ 3290 3291 Polling.prototype.uri = function(){ 3292 var query = this.query || {}; 3293 var schema = this.secure ? 'https' : 'http'; 3294 var port = ''; 3295 3296 // cache busting is forced 3297 if (false !== this.timestampRequests) { 3298 query[this.timestampParam] = +new Date + '-' + Transport.timestamps++; 3299 } 3300 3301 if (!this.supportsBinary && !query.sid) { 3302 query.b64 = 1; 3303 } 3304 3305 query = parseqs.encode(query); 3306 3307 // avoid port if default for schema 3308 if (this.port && (('https' == schema && this.port != 443) || 3309 ('http' == schema && this.port != 80))) { 3310 port = ':' + this.port; 3311 } 3312 3313 // prepend ? to query 3314 if (query.length) { 3315 query = '?' + query; 3316 } 3317 3318 return schema + '://' + this.hostname + port + this.path + query; 3319 }; 3320 3321 },{"../transport":14,"component-inherit":21,"debug":22,"engine.io-parser":25,"parseqs":33,"xmlhttprequest":20}],19:[function(_dereq_,module,exports){ 3322 /** 3323 * Module dependencies. 3324 */ 3325 3326 var Transport = _dereq_('../transport'); 3327 var parser = _dereq_('engine.io-parser'); 3328 var parseqs = _dereq_('parseqs'); 3329 var inherit = _dereq_('component-inherit'); 3330 var debug = _dereq_('debug')('engine.io-client:websocket'); 3331 3332 /** 3333 * `ws` exposes a WebSocket-compatible interface in 3334 * Node, or the `WebSocket` or `MozWebSocket` globals 3335 * in the browser. 3336 */ 3337 3338 var WebSocket = _dereq_('ws'); 3339 3340 /** 3341 * Module exports. 3342 */ 3343 3344 module.exports = WS; 3345 3346 /** 3347 * WebSocket transport constructor. 3348 * 3349 * @api {Object} connection options 3350 * @api public 3351 */ 3352 3353 function WS(opts){ 3354 var forceBase64 = (opts && opts.forceBase64); 3355 if (forceBase64) { 3356 this.supportsBinary = false; 3357 } 3358 Transport.call(this, opts); 3359 } 3360 3361 /** 3362 * Inherits from Transport. 3363 */ 3364 3365 inherit(WS, Transport); 3366 3367 /** 3368 * Transport name. 3369 * 3370 * @api public 3371 */ 3372 3373 WS.prototype.name = 'websocket'; 3374 3375 /* 3376 * WebSockets support binary 3377 */ 3378 3379 WS.prototype.supportsBinary = true; 3380 3381 /** 3382 * Opens socket. 3383 * 3384 * @api private 3385 */ 3386 3387 WS.prototype.doOpen = function(){ 3388 if (!this.check()) { 3389 // let probe timeout 3390 return; 3391 } 3392 3393 var self = this; 3394 var uri = this.uri(); 3395 var protocols = void(0); 3396 var opts = { agent: this.agent }; 3397 3398 // SSL options for Node.js client 3399 opts.pfx = this.pfx; 3400 opts.key = this.key; 3401 opts.passphrase = this.passphrase; 3402 opts.cert = this.cert; 3403 opts.ca = this.ca; 3404 opts.ciphers = this.ciphers; 3405 opts.rejectUnauthorized = this.rejectUnauthorized; 3406 3407 this.ws = new WebSocket(uri, protocols, opts); 3408 3409 if (this.ws.binaryType === undefined) { 3410 this.supportsBinary = false; 3411 } 3412 3413 this.ws.binaryType = 'arraybuffer'; 3414 this.addEventListeners(); 3415 }; 3416 3417 /** 3418 * Adds event listeners to the socket 3419 * 3420 * @api private 3421 */ 3422 3423 WS.prototype.addEventListeners = function(){ 3424 var self = this; 3425 3426 this.ws.onopen = function(){ 3427 self.onOpen(); 3428 }; 3429 this.ws.onclose = function(){ 3430 self.onClose(); 3431 }; 3432 this.ws.onmessage = function(ev){ 3433 self.onData(ev.data); 3434 }; 3435 this.ws.onerror = function(e){ 3436 self.onError('websocket error', e); 3437 }; 3438 }; 3439 3440 /** 3441 * Override `onData` to use a timer on iOS. 3442 * See: https://gist.github.com/mloughran/2052006 3443 * 3444 * @api private 3445 */ 3446 3447 if ('undefined' != typeof navigator 3448 && /iPad|iPhone|iPod/i.test(navigator.userAgent)) { 3449 WS.prototype.onData = function(data){ 3450 var self = this; 3451 setTimeout(function(){ 3452 Transport.prototype.onData.call(self, data); 3453 }, 0); 3454 }; 3455 } 3456 3457 /** 3458 * Writes data to socket. 3459 * 3460 * @param {Array} array of packets. 3461 * @api private 3462 */ 3463 3464 WS.prototype.write = function(packets){ 3465 var self = this; 3466 this.writable = false; 3467 // encodePacket efficient as it uses WS framing 3468 // no need for encodePayload 3469 for (var i = 0, l = packets.length; i < l; i++) { 3470 parser.encodePacket(packets[i], this.supportsBinary, function(data) { 3471 //Sometimes the websocket has already been closed but the browser didn't 3472 //have a chance of informing us about it yet, in that case send will 3473 //throw an error 3474 try { 3475 self.ws.send(data); 3476 } catch (e){ 3477 debug('websocket closed before onclose event'); 3478 } 3479 }); 3480 } 3481 3482 function ondrain() { 3483 self.writable = true; 3484 self.emit('drain'); 3485 } 3486 // fake drain 3487 // defer to next tick to allow Socket to clear writeBuffer 3488 setTimeout(ondrain, 0); 3489 }; 3490 3491 /** 3492 * Called upon close 3493 * 3494 * @api private 3495 */ 3496 3497 WS.prototype.onClose = function(){ 3498 Transport.prototype.onClose.call(this); 3499 }; 3500 3501 /** 3502 * Closes socket. 3503 * 3504 * @api private 3505 */ 3506 3507 WS.prototype.doClose = function(){ 3508 if (typeof this.ws !== 'undefined') { 3509 this.ws.close(); 3510 } 3511 }; 3512 3513 /** 3514 * Generates uri for connection. 3515 * 3516 * @api private 3517 */ 3518 3519 WS.prototype.uri = function(){ 3520 var query = this.query || {}; 3521 var schema = this.secure ? 'wss' : 'ws'; 3522 var port = ''; 3523 3524 // avoid port if default for schema 3525 if (this.port && (('wss' == schema && this.port != 443) 3526 || ('ws' == schema && this.port != 80))) { 3527 port = ':' + this.port; 3528 } 3529 3530 // append timestamp to URI 3531 if (this.timestampRequests) { 3532 query[this.timestampParam] = +new Date; 3533 } 3534 3535 // communicate binary support capabilities 3536 if (!this.supportsBinary) { 3537 query.b64 = 1; 3538 } 3539 3540 query = parseqs.encode(query); 3541 3542 // prepend ? to query 3543 if (query.length) { 3544 query = '?' + query; 3545 } 3546 3547 return schema + '://' + this.hostname + port + this.path + query; 3548 }; 3549 3550 /** 3551 * Feature detection for WebSocket. 3552 * 3553 * @return {Boolean} whether this transport is available. 3554 * @api public 3555 */ 3556 3557 WS.prototype.check = function(){ 3558 return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name); 3559 }; 3560 3561 },{"../transport":14,"component-inherit":21,"debug":22,"engine.io-parser":25,"parseqs":33,"ws":35}],20:[function(_dereq_,module,exports){ 3562 // browser shim for xmlhttprequest module 3563 var hasCORS = _dereq_('has-cors'); 3564 3565 module.exports = function(opts) { 3566 var xdomain = opts.xdomain; 3567 3568 // scheme must be same when usign XDomainRequest 3569 // http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx 3570 var xscheme = opts.xscheme; 3571 3572 // XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default. 3573 // https://github.com/Automattic/engine.io-client/pull/217 3574 var enablesXDR = opts.enablesXDR; 3575 3576 // XMLHttpRequest can be disabled on IE 3577 try { 3578 if ('undefined' != typeof XMLHttpRequest && (!xdomain || hasCORS)) { 3579 return new XMLHttpRequest(); 3580 } 3581 } catch (e) { } 3582 3583 // Use XDomainRequest for IE8 if enablesXDR is true 3584 // because loading bar keeps flashing when using jsonp-polling 3585 // https://github.com/yujiosaka/socke.io-ie8-loading-example 3586 try { 3587 if ('undefined' != typeof XDomainRequest && !xscheme && enablesXDR) { 3588 return new XDomainRequest(); 3589 } 3590 } catch (e) { } 3591 3592 if (!xdomain) { 3593 try { 3594 return new ActiveXObject('Microsoft.XMLHTTP'); 3595 } catch(e) { } 3596 } 3597 } 3598 3599 },{"has-cors":38}],21:[function(_dereq_,module,exports){ 3600 3601 module.exports = function(a, b){ 3602 var fn = function(){}; 3603 fn.prototype = b.prototype; 3604 a.prototype = new fn; 3605 a.prototype.constructor = a; 3606 }; 3607 },{}],22:[function(_dereq_,module,exports){ 3608 3609 /** 3610 * This is the web browser implementation of `debug()`. 3611 * 3612 * Expose `debug()` as the module. 3613 */ 3614 3615 exports = module.exports = _dereq_('./debug'); 3616 exports.log = log; 3617 exports.formatArgs = formatArgs; 3618 exports.save = save; 3619 exports.load = load; 3620 exports.useColors = useColors; 3621 3622 /** 3623 * Colors. 3624 */ 3625 3626 exports.colors = [ 3627 'lightseagreen', 3628 'forestgreen', 3629 'goldenrod', 3630 'dodgerblue', 3631 'darkorchid', 3632 'crimson' 3633 ]; 3634 3635 /** 3636 * Currently only WebKit-based Web Inspectors, Firefox >= v31, 3637 * and the Firebug extension (any Firefox version) are known 3638 * to support "%c" CSS customizations. 3639 * 3640 * TODO: add a `localStorage` variable to explicitly enable/disable colors 3641 */ 3642 3643 function useColors() { 3644 // is webkit? http://stackoverflow.com/a/16459606/376773 3645 return ('WebkitAppearance' in document.documentElement.style) || 3646 // is firebug? http://stackoverflow.com/a/398120/376773 3647 (window.console && (console.firebug || (console.exception && console.table))) || 3648 // is firefox >= v31? 3649 // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages 3650 (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31); 3651 } 3652 3653 /** 3654 * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. 3655 */ 3656 3657 exports.formatters.j = function(v) { 3658 return JSON.stringify(v); 3659 }; 3660 3661 3662 /** 3663 * Colorize log arguments if enabled. 3664 * 3665 * @api public 3666 */ 3667 3668 function formatArgs() { 3669 var args = arguments; 3670 var useColors = this.useColors; 3671 3672 args[0] = (useColors ? '%c' : '') 3673 + this.namespace 3674 + (useColors ? ' %c' : ' ') 3675 + args[0] 3676 + (useColors ? '%c ' : ' ') 3677 + '+' + exports.humanize(this.diff); 3678 3679 if (!useColors) return args; 3680 3681 var c = 'color: ' + this.color; 3682 args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1)); 3683 3684 // the final "%c" is somewhat tricky, because there could be other 3685 // arguments passed either before or after the %c, so we need to 3686 // figure out the correct index to insert the CSS into 3687 var index = 0; 3688 var lastC = 0; 3689 args[0].replace(/%[a-z%]/g, function(match) { 3690 if ('%%' === match) return; 3691 index++; 3692 if ('%c' === match) { 3693 // we only are interested in the *last* %c 3694 // (the user may have provided their own) 3695 lastC = index; 3696 } 3697 }); 3698 3699 args.splice(lastC, 0, c); 3700 return args; 3701 } 3702 3703 /** 3704 * Invokes `console.log()` when available. 3705 * No-op when `console.log` is not a "function". 3706 * 3707 * @api public 3708 */ 3709 3710 function log() { 3711 // This hackery is required for IE8, 3712 // where the `console.log` function doesn't have 'apply' 3713 return 'object' == typeof console 3714 && 'function' == typeof console.log 3715 && Function.prototype.apply.call(console.log, console, arguments); 3716 } 3717 3718 /** 3719 * Save `namespaces`. 3720 * 3721 * @param {String} namespaces 3722 * @api private 3723 */ 3724 3725 function save(namespaces) { 3726 try { 3727 if (null == namespaces) { 3728 localStorage.removeItem('debug'); 3729 } else { 3730 localStorage.debug = namespaces; 3731 } 3732 } catch(e) {} 3733 } 3734 3735 /** 3736 * Load `namespaces`. 3737 * 3738 * @return {String} returns the previously persisted debug modes 3739 * @api private 3740 */ 3741 3742 function load() { 3743 var r; 3744 try { 3745 r = localStorage.debug; 3746 } catch(e) {} 3747 return r; 3748 } 3749 3750 /** 3751 * Enable namespaces listed in `localStorage.debug` initially. 3752 */ 3753 3754 exports.enable(load()); 3755 3756 },{"./debug":23}],23:[function(_dereq_,module,exports){ 3757 3758 /** 3759 * This is the common logic for both the Node.js and web browser 3760 * implementations of `debug()`. 3761 * 3762 * Expose `debug()` as the module. 3763 */ 3764 3765 exports = module.exports = debug; 3766 exports.coerce = coerce; 3767 exports.disable = disable; 3768 exports.enable = enable; 3769 exports.enabled = enabled; 3770 exports.humanize = _dereq_('ms'); 3771 3772 /** 3773 * The currently active debug mode names, and names to skip. 3774 */ 3775 3776 exports.names = []; 3777 exports.skips = []; 3778 3779 /** 3780 * Map of special "%n" handling functions, for the debug "format" argument. 3781 * 3782 * Valid key names are a single, lowercased letter, i.e. "n". 3783 */ 3784 3785 exports.formatters = {}; 3786 3787 /** 3788 * Previously assigned color. 3789 */ 3790 3791 var prevColor = 0; 3792 3793 /** 3794 * Previous log timestamp. 3795 */ 3796 3797 var prevTime; 3798 3799 /** 3800 * Select a color. 3801 * 3802 * @return {Number} 3803 * @api private 3804 */ 3805 3806 function selectColor() { 3807 return exports.colors[prevColor++ % exports.colors.length]; 3808 } 3809 3810 /** 3811 * Create a debugger with the given `namespace`. 3812 * 3813 * @param {String} namespace 3814 * @return {Function} 3815 * @api public 3816 */ 3817 3818 function debug(namespace) { 3819 3820 // define the `disabled` version 3821 function disabled() { 3822 } 3823 disabled.enabled = false; 3824 3825 // define the `enabled` version 3826 function enabled() { 3827 3828 var self = enabled; 3829 3830 // set `diff` timestamp 3831 var curr = +new Date(); 3832 var ms = curr - (prevTime || curr); 3833 self.diff = ms; 3834 self.prev = prevTime; 3835 self.curr = curr; 3836 prevTime = curr; 3837 3838 // add the `color` if not set 3839 if (null == self.useColors) self.useColors = exports.useColors(); 3840 if (null == self.color && self.useColors) self.color = selectColor(); 3841 3842 var args = Array.prototype.slice.call(arguments); 3843 3844 args[0] = exports.coerce(args[0]); 3845 3846 if ('string' !== typeof args[0]) { 3847 // anything else let's inspect with %o 3848 args = ['%o'].concat(args); 3849 } 3850 3851 // apply any `formatters` transformations 3852 var index = 0; 3853 args[0] = args[0].replace(/%([a-z%])/g, function(match, format) { 3854 // if we encounter an escaped % then don't increase the array index 3855 if (match === '%%') return match; 3856 index++; 3857 var formatter = exports.formatters[format]; 3858 if ('function' === typeof formatter) { 3859 var val = args[index]; 3860 match = formatter.call(self, val); 3861 3862 // now we need to remove `args[index]` since it's inlined in the `format` 3863 args.splice(index, 1); 3864 index--; 3865 } 3866 return match; 3867 }); 3868 3869 if ('function' === typeof exports.formatArgs) { 3870 args = exports.formatArgs.apply(self, args); 3871 } 3872 var logFn = enabled.log || exports.log || console.log.bind(console); 3873 logFn.apply(self, args); 3874 } 3875 enabled.enabled = true; 3876 3877 var fn = exports.enabled(namespace) ? enabled : disabled; 3878 3879 fn.namespace = namespace; 3880 3881 return fn; 3882 } 3883 3884 /** 3885 * Enables a debug mode by namespaces. This can include modes 3886 * separated by a colon and wildcards. 3887 * 3888 * @param {String} namespaces 3889 * @api public 3890 */ 3891 3892 function enable(namespaces) { 3893 exports.save(namespaces); 3894 3895 var split = (namespaces || '').split(/[\s,]+/); 3896 var len = split.length; 3897 3898 for (var i = 0; i < len; i++) { 3899 if (!split[i]) continue; // ignore empty strings 3900 namespaces = split[i].replace(/\*/g, '.*?'); 3901 if (namespaces[0] === '-') { 3902 exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); 3903 } else { 3904 exports.names.push(new RegExp('^' + namespaces + '$')); 3905 } 3906 } 3907 } 3908 3909 /** 3910 * Disable debug output. 3911 * 3912 * @api public 3913 */ 3914 3915 function disable() { 3916 exports.enable(''); 3917 } 3918 3919 /** 3920 * Returns true if the given mode name is enabled, false otherwise. 3921 * 3922 * @param {String} name 3923 * @return {Boolean} 3924 * @api public 3925 */ 3926 3927 function enabled(name) { 3928 var i, len; 3929 for (i = 0, len = exports.skips.length; i < len; i++) { 3930 if (exports.skips[i].test(name)) { 3931 return false; 3932 } 3933 } 3934 for (i = 0, len = exports.names.length; i < len; i++) { 3935 if (exports.names[i].test(name)) { 3936 return true; 3937 } 3938 } 3939 return false; 3940 } 3941 3942 /** 3943 * Coerce `val`. 3944 * 3945 * @param {Mixed} val 3946 * @return {Mixed} 3947 * @api private 3948 */ 3949 3950 function coerce(val) { 3951 if (val instanceof Error) return val.stack || val.message; 3952 return val; 3953 } 3954 3955 },{"ms":24}],24:[function(_dereq_,module,exports){ 3956 /** 3957 * Helpers. 3958 */ 3959 3960 var s = 1000; 3961 var m = s * 60; 3962 var h = m * 60; 3963 var d = h * 24; 3964 var y = d * 365.25; 3965 3966 /** 3967 * Parse or format the given `val`. 3968 * 3969 * Options: 3970 * 3971 * - `long` verbose formatting [false] 3972 * 3973 * @param {String|Number} val 3974 * @param {Object} options 3975 * @return {String|Number} 3976 * @api public 3977 */ 3978 3979 module.exports = function(val, options){ 3980 options = options || {}; 3981 if ('string' == typeof val) return parse(val); 3982 return options.long 3983 ? long(val) 3984 : short(val); 3985 }; 3986 3987 /** 3988 * Parse the given `str` and return milliseconds. 3989 * 3990 * @param {String} str 3991 * @return {Number} 3992 * @api private 3993 */ 3994 3995 function parse(str) { 3996 var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); 3997 if (!match) return; 3998 var n = parseFloat(match[1]); 3999 var type = (match[2] || 'ms').toLowerCase(); 4000 switch (type) { 4001 case 'years': 4002 case 'year': 4003 case 'y': 4004 return n * y; 4005 case 'days': 4006 case 'day': 4007 case 'd': 4008 return n * d; 4009 case 'hours': 4010 case 'hour': 4011 case 'h': 4012 return n * h; 4013 case 'minutes': 4014 case 'minute': 4015 case 'm': 4016 return n * m; 4017 case 'seconds': 4018 case 'second': 4019 case 's': 4020 return n * s; 4021 case 'ms': 4022 return n; 4023 } 4024 } 4025 4026 /** 4027 * Short format for `ms`. 4028 * 4029 * @param {Number} ms 4030 * @return {String} 4031 * @api private 4032 */ 4033 4034 function short(ms) { 4035 if (ms >= d) return Math.round(ms / d) + 'd'; 4036 if (ms >= h) return Math.round(ms / h) + 'h'; 4037 if (ms >= m) return Math.round(ms / m) + 'm'; 4038 if (ms >= s) return Math.round(ms / s) + 's'; 4039 return ms + 'ms'; 4040 } 4041 4042 /** 4043 * Long format for `ms`. 4044 * 4045 * @param {Number} ms 4046 * @return {String} 4047 * @api private 4048 */ 4049 4050 function long(ms) { 4051 return plural(ms, d, 'day') 4052 || plural(ms, h, 'hour') 4053 || plural(ms, m, 'minute') 4054 || plural(ms, s, 'second') 4055 || ms + ' ms'; 4056 } 4057 4058 /** 4059 * Pluralization helper. 4060 */ 4061 4062 function plural(ms, n, name) { 4063 if (ms < n) return; 4064 if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; 4065 return Math.ceil(ms / n) + ' ' + name + 's'; 4066 } 4067 4068 },{}],25:[function(_dereq_,module,exports){ 4069 (function (global){ 4070 /** 4071 * Module dependencies. 4072 */ 4073 4074 var keys = _dereq_('./keys'); 4075 var hasBinary = _dereq_('has-binary'); 4076 var sliceBuffer = _dereq_('arraybuffer.slice'); 4077 var base64encoder = _dereq_('base64-arraybuffer'); 4078 var after = _dereq_('after'); 4079 var utf8 = _dereq_('utf8'); 4080 4081 /** 4082 * Check if we are running an android browser. That requires us to use 4083 * ArrayBuffer with polling transports... 4084 * 4085 * http://ghinda.net/jpeg-blob-ajax-android/ 4086 */ 4087 4088 var isAndroid = navigator.userAgent.match(/Android/i); 4089 4090 /** 4091 * Check if we are running in PhantomJS. 4092 * Uploading a Blob with PhantomJS does not work correctly, as reported here: 4093 * https://github.com/ariya/phantomjs/issues/11395 4094 * @type boolean 4095 */ 4096 var isPhantomJS = /PhantomJS/i.test(navigator.userAgent); 4097 4098 /** 4099 * When true, avoids using Blobs to encode payloads. 4100 * @type boolean 4101 */ 4102 var dontSendBlobs = isAndroid || isPhantomJS; 4103 4104 /** 4105 * Current protocol version. 4106 */ 4107 4108 exports.protocol = 3; 4109 4110 /** 4111 * Packet types. 4112 */ 4113 4114 var packets = exports.packets = { 4115 open: 0 // non-ws 4116 , close: 1 // non-ws 4117 , ping: 2 4118 , pong: 3 4119 , message: 4 4120 , upgrade: 5 4121 , noop: 6 4122 }; 4123 4124 var packetslist = keys(packets); 4125 4126 /** 4127 * Premade error packet. 4128 */ 4129 4130 var err = { type: 'error', data: 'parser error' }; 4131 4132 /** 4133 * Create a blob api even for blob builder when vendor prefixes exist 4134 */ 4135 4136 var Blob = _dereq_('blob'); 4137 4138 /** 4139 * Encodes a packet. 4140 * 4141 * <packet type id> [ <data> ] 4142 * 4143 * Example: 4144 * 4145 * 5hello world 4146 * 3 4147 * 4 4148 * 4149 * Binary is encoded in an identical principle 4150 * 4151 * @api private 4152 */ 4153 4154 exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) { 4155 if ('function' == typeof supportsBinary) { 4156 callback = supportsBinary; 4157 supportsBinary = false; 4158 } 4159 4160 if ('function' == typeof utf8encode) { 4161 callback = utf8encode; 4162 utf8encode = null; 4163 } 4164 4165 var data = (packet.data === undefined) 4166 ? undefined 4167 : packet.data.buffer || packet.data; 4168 4169 if (global.ArrayBuffer && data instanceof ArrayBuffer) { 4170 return encodeArrayBuffer(packet, supportsBinary, callback); 4171 } else if (Blob && data instanceof global.Blob) { 4172 return encodeBlob(packet, supportsBinary, callback); 4173 } 4174 4175 // might be an object with { base64: true, data: dataAsBase64String } 4176 if (data && data.base64) { 4177 return encodeBase64Object(packet, callback); 4178 } 4179 4180 // Sending data as a utf-8 string 4181 var encoded = packets[packet.type]; 4182 4183 // data fragment is optional 4184 if (undefined !== packet.data) { 4185 encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data); 4186 } 4187 4188 return callback('' + encoded); 4189 4190 }; 4191 4192 function encodeBase64Object(packet, callback) { 4193 // packet data is an object { base64: true, data: dataAsBase64String } 4194 var message = 'b' + exports.packets[packet.type] + packet.data.data; 4195 return callback(message); 4196 } 4197 4198 /** 4199 * Encode packet helpers for binary types 4200 */ 4201 4202 function encodeArrayBuffer(packet, supportsBinary, callback) { 4203 if (!supportsBinary) { 4204 return exports.encodeBase64Packet(packet, callback); 4205 } 4206 4207 var data = packet.data; 4208 var contentArray = new Uint8Array(data); 4209 var resultBuffer = new Uint8Array(1 + data.byteLength); 4210 4211 resultBuffer[0] = packets[packet.type]; 4212 for (var i = 0; i < contentArray.length; i++) { 4213 resultBuffer[i+1] = contentArray[i]; 4214 } 4215 4216 return callback(resultBuffer.buffer); 4217 } 4218 4219 function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) { 4220 if (!supportsBinary) { 4221 return exports.encodeBase64Packet(packet, callback); 4222 } 4223 4224 var fr = new FileReader(); 4225 fr.onload = function() { 4226 packet.data = fr.result; 4227 exports.encodePacket(packet, supportsBinary, true, callback); 4228 }; 4229 return fr.readAsArrayBuffer(packet.data); 4230 } 4231 4232 function encodeBlob(packet, supportsBinary, callback) { 4233 if (!supportsBinary) { 4234 return exports.encodeBase64Packet(packet, callback); 4235 } 4236 4237 if (dontSendBlobs) { 4238 return encodeBlobAsArrayBuffer(packet, supportsBinary, callback); 4239 } 4240 4241 var length = new Uint8Array(1); 4242 length[0] = packets[packet.type]; 4243 var blob = new Blob([length.buffer, packet.data]); 4244 4245 return callback(blob); 4246 } 4247 4248 /** 4249 * Encodes a packet with binary data in a base64 string 4250 * 4251 * @param {Object} packet, has `type` and `data` 4252 * @return {String} base64 encoded message 4253 */ 4254 4255 exports.encodeBase64Packet = function(packet, callback) { 4256 var message = 'b' + exports.packets[packet.type]; 4257 if (Blob && packet.data instanceof Blob) { 4258 var fr = new FileReader(); 4259 fr.onload = function() { 4260 var b64 = fr.result.split(',')[1]; 4261 callback(message + b64); 4262 }; 4263 return fr.readAsDataURL(packet.data); 4264 } 4265 4266 var b64data; 4267 try { 4268 b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data)); 4269 } catch (e) { 4270 // iPhone Safari doesn't let you apply with typed arrays 4271 var typed = new Uint8Array(packet.data); 4272 var basic = new Array(typed.length); 4273 for (var i = 0; i < typed.length; i++) { 4274 basic[i] = typed[i]; 4275 } 4276 b64data = String.fromCharCode.apply(null, basic); 4277 } 4278 message += global.btoa(b64data); 4279 return callback(message); 4280 }; 4281 4282 /** 4283 * Decodes a packet. Changes format to Blob if requested. 4284 * 4285 * @return {Object} with `type` and `data` (if any) 4286 * @api private 4287 */ 4288 4289 exports.decodePacket = function (data, binaryType, utf8decode) { 4290 // String data 4291 if (typeof data == 'string' || data === undefined) { 4292 if (data.charAt(0) == 'b') { 4293 return exports.decodeBase64Packet(data.substr(1), binaryType); 4294 } 4295 4296 if (utf8decode) { 4297 try { 4298 data = utf8.decode(data); 4299 } catch (e) { 4300 return err; 4301 } 4302 } 4303 var type = data.charAt(0); 4304 4305 if (Number(type) != type || !packetslist[type]) { 4306 return err; 4307 } 4308 4309 if (data.length > 1) { 4310 return { type: packetslist[type], data: data.substring(1) }; 4311 } else { 4312 return { type: packetslist[type] }; 4313 } 4314 } 4315 4316 var asArray = new Uint8Array(data); 4317 var type = asArray[0]; 4318 var rest = sliceBuffer(data, 1); 4319 if (Blob && binaryType === 'blob') { 4320 rest = new Blob([rest]); 4321 } 4322 return { type: packetslist[type], data: rest }; 4323 }; 4324 4325 /** 4326 * Decodes a packet encoded in a base64 string 4327 * 4328 * @param {String} base64 encoded message 4329 * @return {Object} with `type` and `data` (if any) 4330 */ 4331 4332 exports.decodeBase64Packet = function(msg, binaryType) { 4333 var type = packetslist[msg.charAt(0)]; 4334 if (!global.ArrayBuffer) { 4335 return { type: type, data: { base64: true, data: msg.substr(1) } }; 4336 } 4337 4338 var data = base64encoder.decode(msg.substr(1)); 4339 4340 if (binaryType === 'blob' && Blob) { 4341 data = new Blob([data]); 4342 } 4343 4344 return { type: type, data: data }; 4345 }; 4346 4347 /** 4348 * Encodes multiple messages (payload). 4349 * 4350 * <length>:data 4351 * 4352 * Example: 4353 * 4354 * 11:hello world2:hi 4355 * 4356 * If any contents are binary, they will be encoded as base64 strings. Base64 4357 * encoded strings are marked with a b before the length specifier 4358 * 4359 * @param {Array} packets 4360 * @api private 4361 */ 4362 4363 exports.encodePayload = function (packets, supportsBinary, callback) { 4364 if (typeof supportsBinary == 'function') { 4365 callback = supportsBinary; 4366 supportsBinary = null; 4367 } 4368 4369 var isBinary = hasBinary(packets); 4370 4371 if (supportsBinary && isBinary) { 4372 if (Blob && !dontSendBlobs) { 4373 return exports.encodePayloadAsBlob(packets, callback); 4374 } 4375 4376 return exports.encodePayloadAsArrayBuffer(packets, callback); 4377 } 4378 4379 if (!packets.length) { 4380 return callback('0:'); 4381 } 4382 4383 function setLengthHeader(message) { 4384 return message.length + ':' + message; 4385 } 4386 4387 function encodeOne(packet, doneCallback) { 4388 exports.encodePacket(packet, !isBinary ? false : supportsBinary, true, function(message) { 4389 doneCallback(null, setLengthHeader(message)); 4390 }); 4391 } 4392 4393 map(packets, encodeOne, function(err, results) { 4394 return callback(results.join('')); 4395 }); 4396 }; 4397 4398 /** 4399 * Async array map using after 4400 */ 4401 4402 function map(ary, each, done) { 4403 var result = new Array(ary.length); 4404 var next = after(ary.length, done); 4405 4406 var eachWithIndex = function(i, el, cb) { 4407 each(el, function(error, msg) { 4408 result[i] = msg; 4409 cb(error, result); 4410 }); 4411 }; 4412 4413 for (var i = 0; i < ary.length; i++) { 4414 eachWithIndex(i, ary[i], next); 4415 } 4416 } 4417 4418 /* 4419 * Decodes data when a payload is maybe expected. Possible binary contents are 4420 * decoded from their base64 representation 4421 * 4422 * @param {String} data, callback method 4423 * @api public 4424 */ 4425 4426 exports.decodePayload = function (data, binaryType, callback) { 4427 if (typeof data != 'string') { 4428 return exports.decodePayloadAsBinary(data, binaryType, callback); 4429 } 4430 4431 if (typeof binaryType === 'function') { 4432 callback = binaryType; 4433 binaryType = null; 4434 } 4435 4436 var packet; 4437 if (data == '') { 4438 // parser error - ignoring payload 4439 return callback(err, 0, 1); 4440 } 4441 4442 var length = '' 4443 , n, msg; 4444 4445 for (var i = 0, l = data.length; i < l; i++) { 4446 var chr = data.charAt(i); 4447 4448 if (':' != chr) { 4449 length += chr; 4450 } else { 4451 if ('' == length || (length != (n = Number(length)))) { 4452 // parser error - ignoring payload 4453 return callback(err, 0, 1); 4454 } 4455 4456 msg = data.substr(i + 1, n); 4457 4458 if (length != msg.length) { 4459 // parser error - ignoring payload 4460 return callback(err, 0, 1); 4461 } 4462 4463 if (msg.length) { 4464 packet = exports.decodePacket(msg, binaryType, true); 4465 4466 if (err.type == packet.type && err.data == packet.data) { 4467 // parser error in individual packet - ignoring payload 4468 return callback(err, 0, 1); 4469 } 4470 4471 var ret = callback(packet, i + n, l); 4472 if (false === ret) return; 4473 } 4474 4475 // advance cursor 4476 i += n; 4477 length = ''; 4478 } 4479 } 4480 4481 if (length != '') { 4482 // parser error - ignoring payload 4483 return callback(err, 0, 1); 4484 } 4485 4486 }; 4487 4488 /** 4489 * Encodes multiple messages (payload) as binary. 4490 * 4491 * <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number 4492 * 255><data> 4493 * 4494 * Example: 4495 * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers 4496 * 4497 * @param {Array} packets 4498 * @return {ArrayBuffer} encoded payload 4499 * @api private 4500 */ 4501 4502 exports.encodePayloadAsArrayBuffer = function(packets, callback) { 4503 if (!packets.length) { 4504 return callback(new ArrayBuffer(0)); 4505 } 4506 4507 function encodeOne(packet, doneCallback) { 4508 exports.encodePacket(packet, true, true, function(data) { 4509 return doneCallback(null, data); 4510 }); 4511 } 4512 4513 map(packets, encodeOne, function(err, encodedPackets) { 4514 var totalLength = encodedPackets.reduce(function(acc, p) { 4515 var len; 4516 if (typeof p === 'string'){ 4517 len = p.length; 4518 } else { 4519 len = p.byteLength; 4520 } 4521 return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2 4522 }, 0); 4523 4524 var resultArray = new Uint8Array(totalLength); 4525 4526 var bufferIndex = 0; 4527 encodedPackets.forEach(function(p) { 4528 var isString = typeof p === 'string'; 4529 var ab = p; 4530 if (isString) { 4531 var view = new Uint8Array(p.length); 4532 for (var i = 0; i < p.length; i++) { 4533 view[i] = p.charCodeAt(i); 4534 } 4535 ab = view.buffer; 4536 } 4537 4538 if (isString) { // not true binary 4539 resultArray[bufferIndex++] = 0; 4540 } else { // true binary 4541 resultArray[bufferIndex++] = 1; 4542 } 4543 4544 var lenStr = ab.byteLength.toString(); 4545 for (var i = 0; i < lenStr.length; i++) { 4546 resultArray[bufferIndex++] = parseInt(lenStr[i]); 4547 } 4548 resultArray[bufferIndex++] = 255; 4549 4550 var view = new Uint8Array(ab); 4551 for (var i = 0; i < view.length; i++) { 4552 resultArray[bufferIndex++] = view[i]; 4553 } 4554 }); 4555 4556 return callback(resultArray.buffer); 4557 }); 4558 }; 4559 4560 /** 4561 * Encode as Blob 4562 */ 4563 4564 exports.encodePayloadAsBlob = function(packets, callback) { 4565 function encodeOne(packet, doneCallback) { 4566 exports.encodePacket(packet, true, true, function(encoded) { 4567 var binaryIdentifier = new Uint8Array(1); 4568 binaryIdentifier[0] = 1; 4569 if (typeof encoded === 'string') { 4570 var view = new Uint8Array(encoded.length); 4571 for (var i = 0; i < encoded.length; i++) { 4572 view[i] = encoded.charCodeAt(i); 4573 } 4574 encoded = view.buffer; 4575 binaryIdentifier[0] = 0; 4576 } 4577 4578 var len = (encoded instanceof ArrayBuffer) 4579 ? encoded.byteLength 4580 : encoded.size; 4581 4582 var lenStr = len.toString(); 4583 var lengthAry = new Uint8Array(lenStr.length + 1); 4584 for (var i = 0; i < lenStr.length; i++) { 4585 lengthAry[i] = parseInt(lenStr[i]); 4586 } 4587 lengthAry[lenStr.length] = 255; 4588 4589 if (Blob) { 4590 var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]); 4591 doneCallback(null, blob); 4592 } 4593 }); 4594 } 4595 4596 map(packets, encodeOne, function(err, results) { 4597 return callback(new Blob(results)); 4598 }); 4599 }; 4600 4601 /* 4602 * Decodes data when a payload is maybe expected. Strings are decoded by 4603 * interpreting each byte as a key code for entries marked to start with 0. See 4604 * description of encodePayloadAsBinary 4605 * 4606 * @param {ArrayBuffer} data, callback method 4607 * @api public 4608 */ 4609 4610 exports.decodePayloadAsBinary = function (data, binaryType, callback) { 4611 if (typeof binaryType === 'function') { 4612 callback = binaryType; 4613 binaryType = null; 4614 } 4615 4616 var bufferTail = data; 4617 var buffers = []; 4618 4619 var numberTooLong = false; 4620 while (bufferTail.byteLength > 0) { 4621 var tailArray = new Uint8Array(bufferTail); 4622 var isString = tailArray[0] === 0; 4623 var msgLength = ''; 4624 4625 for (var i = 1; ; i++) { 4626 if (tailArray[i] == 255) break; 4627 4628 if (msgLength.length > 310) { 4629 numberTooLong = true; 4630 break; 4631 } 4632 4633 msgLength += tailArray[i]; 4634 } 4635 4636 if(numberTooLong) return callback(err, 0, 1); 4637 4638 bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length); 4639 msgLength = parseInt(msgLength); 4640 4641 var msg = sliceBuffer(bufferTail, 0, msgLength); 4642 if (isString) { 4643 try { 4644 msg = String.fromCharCode.apply(null, new Uint8Array(msg)); 4645 } catch (e) { 4646 // iPhone Safari doesn't let you apply to typed arrays 4647 var typed = new Uint8Array(msg); 4648 msg = ''; 4649 for (var i = 0; i < typed.length; i++) { 4650 msg += String.fromCharCode(typed[i]); 4651 } 4652 } 4653 } 4654 4655 buffers.push(msg); 4656 bufferTail = sliceBuffer(bufferTail, msgLength); 4657 } 4658 4659 var total = buffers.length; 4660 buffers.forEach(function(buffer, i) { 4661 callback(exports.decodePacket(buffer, binaryType, true), i, total); 4662 }); 4663 }; 4664 4665 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 4666 },{"./keys":26,"after":27,"arraybuffer.slice":28,"base64-arraybuffer":29,"blob":30,"has-binary":36,"utf8":31}],26:[function(_dereq_,module,exports){ 4667 4668 /** 4669 * Gets the keys for an object. 4670 * 4671 * @return {Array} keys 4672 * @api private 4673 */ 4674 4675 module.exports = Object.keys || function keys (obj){ 4676 var arr = []; 4677 var has = Object.prototype.hasOwnProperty; 4678 4679 for (var i in obj) { 4680 if (has.call(obj, i)) { 4681 arr.push(i); 4682 } 4683 } 4684 return arr; 4685 }; 4686 4687 },{}],27:[function(_dereq_,module,exports){ 4688 module.exports = after 4689 4690 function after(count, callback, err_cb) { 4691 var bail = false 4692 err_cb = err_cb || noop 4693 proxy.count = count 4694 4695 return (count === 0) ? callback() : proxy 4696 4697 function proxy(err, result) { 4698 if (proxy.count <= 0) { 4699 throw new Error('after called too many times') 4700 } 4701 --proxy.count 4702 4703 // after first error, rest are passed to err_cb 4704 if (err) { 4705 bail = true 4706 callback(err) 4707 // future error callbacks will go to error handler 4708 callback = err_cb 4709 } else if (proxy.count === 0 && !bail) { 4710 callback(null, result) 4711 } 4712 } 4713 } 4714 4715 function noop() {} 4716 4717 },{}],28:[function(_dereq_,module,exports){ 4718 /** 4719 * An abstraction for slicing an arraybuffer even when 4720 * ArrayBuffer.prototype.slice is not supported 4721 * 4722 * @api public 4723 */ 4724 4725 module.exports = function(arraybuffer, start, end) { 4726 var bytes = arraybuffer.byteLength; 4727 start = start || 0; 4728 end = end || bytes; 4729 4730 if (arraybuffer.slice) { return arraybuffer.slice(start, end); } 4731 4732 if (start < 0) { start += bytes; } 4733 if (end < 0) { end += bytes; } 4734 if (end > bytes) { end = bytes; } 4735 4736 if (start >= bytes || start >= end || bytes === 0) { 4737 return new ArrayBuffer(0); 4738 } 4739 4740 var abv = new Uint8Array(arraybuffer); 4741 var result = new Uint8Array(end - start); 4742 for (var i = start, ii = 0; i < end; i++, ii++) { 4743 result[ii] = abv[i]; 4744 } 4745 return result.buffer; 4746 }; 4747 4748 },{}],29:[function(_dereq_,module,exports){ 4749 /* 4750 * base64-arraybuffer 4751 * https://github.com/niklasvh/base64-arraybuffer 4752 * 4753 * Copyright (c) 2012 Niklas von Hertzen 4754 * Licensed under the MIT license. 4755 */ 4756 (function(chars){ 4757 "use strict"; 4758 4759 exports.encode = function(arraybuffer) { 4760 var bytes = new Uint8Array(arraybuffer), 4761 i, len = bytes.length, base64 = ""; 4762 4763 for (i = 0; i < len; i+=3) { 4764 base64 += chars[bytes[i] >> 2]; 4765 base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; 4766 base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; 4767 base64 += chars[bytes[i + 2] & 63]; 4768 } 4769 4770 if ((len % 3) === 2) { 4771 base64 = base64.substring(0, base64.length - 1) + "="; 4772 } else if (len % 3 === 1) { 4773 base64 = base64.substring(0, base64.length - 2) + "=="; 4774 } 4775 4776 return base64; 4777 }; 4778 4779 exports.decode = function(base64) { 4780 var bufferLength = base64.length * 0.75, 4781 len = base64.length, i, p = 0, 4782 encoded1, encoded2, encoded3, encoded4; 4783 4784 if (base64[base64.length - 1] === "=") { 4785 bufferLength--; 4786 if (base64[base64.length - 2] === "=") { 4787 bufferLength--; 4788 } 4789 } 4790 4791 var arraybuffer = new ArrayBuffer(bufferLength), 4792 bytes = new Uint8Array(arraybuffer); 4793 4794 for (i = 0; i < len; i+=4) { 4795 encoded1 = chars.indexOf(base64[i]); 4796 encoded2 = chars.indexOf(base64[i+1]); 4797 encoded3 = chars.indexOf(base64[i+2]); 4798 encoded4 = chars.indexOf(base64[i+3]); 4799 4800 bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); 4801 bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); 4802 bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); 4803 } 4804 4805 return arraybuffer; 4806 }; 4807 })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); 4808 4809 },{}],30:[function(_dereq_,module,exports){ 4810 (function (global){ 4811 /** 4812 * Create a blob builder even when vendor prefixes exist 4813 */ 4814 4815 var BlobBuilder = global.BlobBuilder 4816 || global.WebKitBlobBuilder 4817 || global.MSBlobBuilder 4818 || global.MozBlobBuilder; 4819 4820 /** 4821 * Check if Blob constructor is supported 4822 */ 4823 4824 var blobSupported = (function() { 4825 try { 4826 var a = new Blob(['hi']); 4827 return a.size === 2; 4828 } catch(e) { 4829 return false; 4830 } 4831 })(); 4832 4833 /** 4834 * Check if Blob constructor supports ArrayBufferViews 4835 * Fails in Safari 6, so we need to map to ArrayBuffers there. 4836 */ 4837 4838 var blobSupportsArrayBufferView = blobSupported && (function() { 4839 try { 4840 var b = new Blob([new Uint8Array([1,2])]); 4841 return b.size === 2; 4842 } catch(e) { 4843 return false; 4844 } 4845 })(); 4846 4847 /** 4848 * Check if BlobBuilder is supported 4849 */ 4850 4851 var blobBuilderSupported = BlobBuilder 4852 && BlobBuilder.prototype.append 4853 && BlobBuilder.prototype.getBlob; 4854 4855 /** 4856 * Helper function that maps ArrayBufferViews to ArrayBuffers 4857 * Used by BlobBuilder constructor and old browsers that didn't 4858 * support it in the Blob constructor. 4859 */ 4860 4861 function mapArrayBufferViews(ary) { 4862 for (var i = 0; i < ary.length; i++) { 4863 var chunk = ary[i]; 4864 if (chunk.buffer instanceof ArrayBuffer) { 4865 var buf = chunk.buffer; 4866 4867 // if this is a subarray, make a copy so we only 4868 // include the subarray region from the underlying buffer 4869 if (chunk.byteLength !== buf.byteLength) { 4870 var copy = new Uint8Array(chunk.byteLength); 4871 copy.set(new Uint8Array(buf, chunk.byteOffset, chunk.byteLength)); 4872 buf = copy.buffer; 4873 } 4874 4875 ary[i] = buf; 4876 } 4877 } 4878 } 4879 4880 function BlobBuilderConstructor(ary, options) { 4881 options = options || {}; 4882 4883 var bb = new BlobBuilder(); 4884 mapArrayBufferViews(ary); 4885 4886 for (var i = 0; i < ary.length; i++) { 4887 bb.append(ary[i]); 4888 } 4889 4890 return (options.type) ? bb.getBlob(options.type) : bb.getBlob(); 4891 }; 4892 4893 function BlobConstructor(ary, options) { 4894 mapArrayBufferViews(ary); 4895 return new Blob(ary, options || {}); 4896 }; 4897 4898 module.exports = (function() { 4899 if (blobSupported) { 4900 return blobSupportsArrayBufferView ? global.Blob : BlobConstructor; 4901 } else if (blobBuilderSupported) { 4902 return BlobBuilderConstructor; 4903 } else { 4904 return undefined; 4905 } 4906 })(); 4907 4908 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 4909 },{}],31:[function(_dereq_,module,exports){ 4910 (function (global){ 4911 /*! https://mths.be/utf8js v2.0.0 by @mathias */ 4912 ;(function(root) { 4913 4914 // Detect free variables `exports` 4915 var freeExports = typeof exports == 'object' && exports; 4916 4917 // Detect free variable `module` 4918 var freeModule = typeof module == 'object' && module && 4919 module.exports == freeExports && module; 4920 4921 // Detect free variable `global`, from Node.js or Browserified code, 4922 // and use it as `root` 4923 var freeGlobal = typeof global == 'object' && global; 4924 if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { 4925 root = freeGlobal; 4926 } 4927 4928 /*--------------------------------------------------------------------------*/ 4929 4930 var stringFromCharCode = String.fromCharCode; 4931 4932 // Taken from https://mths.be/punycode 4933 function ucs2decode(string) { 4934 var output = []; 4935 var counter = 0; 4936 var length = string.length; 4937 var value; 4938 var extra; 4939 while (counter < length) { 4940 value = string.charCodeAt(counter++); 4941 if (value >= 0xD800 && value <= 0xDBFF && counter < length) { 4942 // high surrogate, and there is a next character 4943 extra = string.charCodeAt(counter++); 4944 if ((extra & 0xFC00) == 0xDC00) { // low surrogate 4945 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); 4946 } else { 4947 // unmatched surrogate; only append this code unit, in case the next 4948 // code unit is the high surrogate of a surrogate pair 4949 output.push(value); 4950 counter--; 4951 } 4952 } else { 4953 output.push(value); 4954 } 4955 } 4956 return output; 4957 } 4958 4959 // Taken from https://mths.be/punycode 4960 function ucs2encode(array) { 4961 var length = array.length; 4962 var index = -1; 4963 var value; 4964 var output = ''; 4965 while (++index < length) { 4966 value = array[index]; 4967 if (value > 0xFFFF) { 4968 value -= 0x10000; 4969 output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); 4970 value = 0xDC00 | value & 0x3FF; 4971 } 4972 output += stringFromCharCode(value); 4973 } 4974 return output; 4975 } 4976 4977 function checkScalarValue(codePoint) { 4978 if (codePoint >= 0xD800 && codePoint <= 0xDFFF) { 4979 throw Error( 4980 'Lone surrogate U+' + codePoint.toString(16).toUpperCase() + 4981 ' is not a scalar value' 4982 ); 4983 } 4984 } 4985 /*--------------------------------------------------------------------------*/ 4986 4987 function createByte(codePoint, shift) { 4988 return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80); 4989 } 4990 4991 function encodeCodePoint(codePoint) { 4992 if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence 4993 return stringFromCharCode(codePoint); 4994 } 4995 var symbol = ''; 4996 if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence 4997 symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0); 4998 } 4999 else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence 5000 checkScalarValue(codePoint); 5001 symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0); 5002 symbol += createByte(codePoint, 6); 5003 } 5004 else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence 5005 symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0); 5006 symbol += createByte(codePoint, 12); 5007 symbol += createByte(codePoint, 6); 5008 } 5009 symbol += stringFromCharCode((codePoint & 0x3F) | 0x80); 5010 return symbol; 5011 } 5012 5013 function utf8encode(string) { 5014 var codePoints = ucs2decode(string); 5015 var length = codePoints.length; 5016 var index = -1; 5017 var codePoint; 5018 var byteString = ''; 5019 while (++index < length) { 5020 codePoint = codePoints[index]; 5021 byteString += encodeCodePoint(codePoint); 5022 } 5023 return byteString; 5024 } 5025 5026 /*--------------------------------------------------------------------------*/ 5027 5028 function readContinuationByte() { 5029 if (byteIndex >= byteCount) { 5030 throw Error('Invalid byte index'); 5031 } 5032 5033 var continuationByte = byteArray[byteIndex] & 0xFF; 5034 byteIndex++; 5035 5036 if ((continuationByte & 0xC0) == 0x80) { 5037 return continuationByte & 0x3F; 5038 } 5039 5040 // If we end up here, it’s not a continuation byte 5041 throw Error('Invalid continuation byte'); 5042 } 5043 5044 function decodeSymbol() { 5045 var byte1; 5046 var byte2; 5047 var byte3; 5048 var byte4; 5049 var codePoint; 5050 5051 if (byteIndex > byteCount) { 5052 throw Error('Invalid byte index'); 5053 } 5054 5055 if (byteIndex == byteCount) { 5056 return false; 5057 } 5058 5059 // Read first byte 5060 byte1 = byteArray[byteIndex] & 0xFF; 5061 byteIndex++; 5062 5063 // 1-byte sequence (no continuation bytes) 5064 if ((byte1 & 0x80) == 0) { 5065 return byte1; 5066 } 5067 5068 // 2-byte sequence 5069 if ((byte1 & 0xE0) == 0xC0) { 5070 var byte2 = readContinuationByte(); 5071 codePoint = ((byte1 & 0x1F) << 6) | byte2; 5072 if (codePoint >= 0x80) { 5073 return codePoint; 5074 } else { 5075 throw Error('Invalid continuation byte'); 5076 } 5077 } 5078 5079 // 3-byte sequence (may include unpaired surrogates) 5080 if ((byte1 & 0xF0) == 0xE0) { 5081 byte2 = readContinuationByte(); 5082 byte3 = readContinuationByte(); 5083 codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3; 5084 if (codePoint >= 0x0800) { 5085 checkScalarValue(codePoint); 5086 return codePoint; 5087 } else { 5088 throw Error('Invalid continuation byte'); 5089 } 5090 } 5091 5092 // 4-byte sequence 5093 if ((byte1 & 0xF8) == 0xF0) { 5094 byte2 = readContinuationByte(); 5095 byte3 = readContinuationByte(); 5096 byte4 = readContinuationByte(); 5097 codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) | 5098 (byte3 << 0x06) | byte4; 5099 if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) { 5100 return codePoint; 5101 } 5102 } 5103 5104 throw Error('Invalid UTF-8 detected'); 5105 } 5106 5107 var byteArray; 5108 var byteCount; 5109 var byteIndex; 5110 function utf8decode(byteString) { 5111 byteArray = ucs2decode(byteString); 5112 byteCount = byteArray.length; 5113 byteIndex = 0; 5114 var codePoints = []; 5115 var tmp; 5116 while ((tmp = decodeSymbol()) !== false) { 5117 codePoints.push(tmp); 5118 } 5119 return ucs2encode(codePoints); 5120 } 5121 5122 /*--------------------------------------------------------------------------*/ 5123 5124 var utf8 = { 5125 'version': '2.0.0', 5126 'encode': utf8encode, 5127 'decode': utf8decode 5128 }; 5129 5130 // Some AMD build optimizers, like r.js, check for specific condition patterns 5131 // like the following: 5132 if ( 5133 typeof define == 'function' && 5134 typeof define.amd == 'object' && 5135 define.amd 5136 ) { 5137 define(function() { 5138 return utf8; 5139 }); 5140 } else if (freeExports && !freeExports.nodeType) { 5141 if (freeModule) { // in Node.js or RingoJS v0.8.0+ 5142 freeModule.exports = utf8; 5143 } else { // in Narwhal or RingoJS v0.7.0- 5144 var object = {}; 5145 var hasOwnProperty = object.hasOwnProperty; 5146 for (var key in utf8) { 5147 hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]); 5148 } 5149 } 5150 } else { // in Rhino or a web browser 5151 root.utf8 = utf8; 5152 } 5153 5154 }(this)); 5155 5156 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 5157 },{}],32:[function(_dereq_,module,exports){ 5158 (function (global){ 5159 /** 5160 * JSON parse. 5161 * 5162 * @see Based on jQuery#parseJSON (MIT) and JSON2 5163 * @api private 5164 */ 5165 5166 var rvalidchars = /^[\],:{}\s]*$/; 5167 var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; 5168 var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; 5169 var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g; 5170 var rtrimLeft = /^\s+/; 5171 var rtrimRight = /\s+$/; 5172 5173 module.exports = function parsejson(data) { 5174 if ('string' != typeof data || !data) { 5175 return null; 5176 } 5177 5178 data = data.replace(rtrimLeft, '').replace(rtrimRight, ''); 5179 5180 // Attempt to parse using the native JSON parser first 5181 if (global.JSON && JSON.parse) { 5182 return JSON.parse(data); 5183 } 5184 5185 if (rvalidchars.test(data.replace(rvalidescape, '@') 5186 .replace(rvalidtokens, ']') 5187 .replace(rvalidbraces, ''))) { 5188 return (new Function('return ' + data))(); 5189 } 5190 }; 5191 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 5192 },{}],33:[function(_dereq_,module,exports){ 5193 /** 5194 * Compiles a querystring 5195 * Returns string representation of the object 5196 * 5197 * @param {Object} 5198 * @api private 5199 */ 5200 5201 exports.encode = function (obj) { 5202 var str = ''; 5203 5204 for (var i in obj) { 5205 if (obj.hasOwnProperty(i)) { 5206 if (str.length) str += '&'; 5207 str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]); 5208 } 5209 } 5210 5211 return str; 5212 }; 5213 5214 /** 5215 * Parses a simple querystring into an object 5216 * 5217 * @param {String} qs 5218 * @api private 5219 */ 5220 5221 exports.decode = function(qs){ 5222 var qry = {}; 5223 var pairs = qs.split('&'); 5224 for (var i = 0, l = pairs.length; i < l; i++) { 5225 var pair = pairs[i].split('='); 5226 qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); 5227 } 5228 return qry; 5229 }; 5230 5231 },{}],34:[function(_dereq_,module,exports){ 5232 /** 5233 * Parses an URI 5234 * 5235 * @author Steven Levithan <stevenlevithan.com> (MIT license) 5236 * @api private 5237 */ 5238 5239 var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; 5240 5241 var parts = [ 5242 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' 5243 ]; 5244 5245 module.exports = function parseuri(str) { 5246 var src = str, 5247 b = str.indexOf('['), 5248 e = str.indexOf(']'); 5249 5250 if (b != -1 && e != -1) { 5251 str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length); 5252 } 5253 5254 var m = re.exec(str || ''), 5255 uri = {}, 5256 i = 14; 5257 5258 while (i--) { 5259 uri[parts[i]] = m[i] || ''; 5260 } 5261 5262 if (b != -1 && e != -1) { 5263 uri.source = src; 5264 uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':'); 5265 uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':'); 5266 uri.ipv6uri = true; 5267 } 5268 5269 return uri; 5270 }; 5271 5272 },{}],35:[function(_dereq_,module,exports){ 5273 5274 /** 5275 * Module dependencies. 5276 */ 5277 5278 var global = (function() { return this; })(); 5279 5280 /** 5281 * WebSocket constructor. 5282 */ 5283 5284 var WebSocket = global.WebSocket || global.MozWebSocket; 5285 5286 /** 5287 * Module exports. 5288 */ 5289 5290 module.exports = WebSocket ? ws : null; 5291 5292 /** 5293 * WebSocket constructor. 5294 * 5295 * The third `opts` options object gets ignored in web browsers, since it's 5296 * non-standard, and throws a TypeError if passed to the constructor. 5297 * See: https://github.com/einaros/ws/issues/227 5298 * 5299 * @param {String} uri 5300 * @param {Array} protocols (optional) 5301 * @param {Object) opts (optional) 5302 * @api public 5303 */ 5304 5305 function ws(uri, protocols, opts) { 5306 var instance; 5307 if (protocols) { 5308 instance = new WebSocket(uri, protocols); 5309 } else { 5310 instance = new WebSocket(uri); 5311 } 5312 return instance; 5313 } 5314 5315 if (WebSocket) ws.prototype = WebSocket.prototype; 5316 5317 },{}],36:[function(_dereq_,module,exports){ 5318 (function (global){ 5319 5320 /* 5321 * Module requirements. 5322 */ 5323 5324 var isArray = _dereq_('isarray'); 5325 5326 /** 5327 * Module exports. 5328 */ 5329 5330 module.exports = hasBinary; 5331 5332 /** 5333 * Checks for binary data. 5334 * 5335 * Right now only Buffer and ArrayBuffer are supported.. 5336 * 5337 * @param {Object} anything 5338 * @api public 5339 */ 5340 5341 function hasBinary(data) { 5342 5343 function _hasBinary(obj) { 5344 if (!obj) return false; 5345 5346 if ( (global.Buffer && global.Buffer.isBuffer(obj)) || 5347 (global.ArrayBuffer && obj instanceof ArrayBuffer) || 5348 (global.Blob && obj instanceof Blob) || 5349 (global.File && obj instanceof File) 5350 ) { 5351 return true; 5352 } 5353 5354 if (isArray(obj)) { 5355 for (var i = 0; i < obj.length; i++) { 5356 if (_hasBinary(obj[i])) { 5357 return true; 5358 } 5359 } 5360 } else if (obj && 'object' == typeof obj) { 5361 if (obj.toJSON) { 5362 obj = obj.toJSON(); 5363 } 5364 5365 for (var key in obj) { 5366 if (Object.prototype.hasOwnProperty.call(obj, key) && _hasBinary(obj[key])) { 5367 return true; 5368 } 5369 } 5370 } 5371 5372 return false; 5373 } 5374 5375 return _hasBinary(data); 5376 } 5377 5378 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 5379 },{"isarray":37}],37:[function(_dereq_,module,exports){ 5380 module.exports = Array.isArray || function (arr) { 5381 return Object.prototype.toString.call(arr) == '[object Array]'; 5382 }; 5383 5384 },{}],38:[function(_dereq_,module,exports){ 5385 5386 /** 5387 * Module dependencies. 5388 */ 5389 5390 var global = _dereq_('global'); 5391 5392 /** 5393 * Module exports. 5394 * 5395 * Logic borrowed from Modernizr: 5396 * 5397 * - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js 5398 */ 5399 5400 try { 5401 module.exports = 'XMLHttpRequest' in global && 5402 'withCredentials' in new global.XMLHttpRequest(); 5403 } catch (err) { 5404 // if XMLHttp support is disabled in IE then it will throw 5405 // when trying to create 5406 module.exports = false; 5407 } 5408 5409 },{"global":39}],39:[function(_dereq_,module,exports){ 5410 5411 /** 5412 * Returns `this`. Execute this without a "context" (i.e. without it being 5413 * attached to an object of the left-hand side), and `this` points to the 5414 * "global" scope of the current JS execution. 5415 */ 5416 5417 module.exports = (function () { return this; })(); 5418 5419 },{}],40:[function(_dereq_,module,exports){ 5420 5421 var indexOf = [].indexOf; 5422 5423 module.exports = function(arr, obj){ 5424 if (indexOf) return arr.indexOf(obj); 5425 for (var i = 0; i < arr.length; ++i) { 5426 if (arr[i] === obj) return i; 5427 } 5428 return -1; 5429 }; 5430 },{}],41:[function(_dereq_,module,exports){ 5431 5432 /** 5433 * HOP ref. 5434 */ 5435 5436 var has = Object.prototype.hasOwnProperty; 5437 5438 /** 5439 * Return own keys in `obj`. 5440 * 5441 * @param {Object} obj 5442 * @return {Array} 5443 * @api public 5444 */ 5445 5446 exports.keys = Object.keys || function(obj){ 5447 var keys = []; 5448 for (var key in obj) { 5449 if (has.call(obj, key)) { 5450 keys.push(key); 5451 } 5452 } 5453 return keys; 5454 }; 5455 5456 /** 5457 * Return own values in `obj`. 5458 * 5459 * @param {Object} obj 5460 * @return {Array} 5461 * @api public 5462 */ 5463 5464 exports.values = function(obj){ 5465 var vals = []; 5466 for (var key in obj) { 5467 if (has.call(obj, key)) { 5468 vals.push(obj[key]); 5469 } 5470 } 5471 return vals; 5472 }; 5473 5474 /** 5475 * Merge `b` into `a`. 5476 * 5477 * @param {Object} a 5478 * @param {Object} b 5479 * @return {Object} a 5480 * @api public 5481 */ 5482 5483 exports.merge = function(a, b){ 5484 for (var key in b) { 5485 if (has.call(b, key)) { 5486 a[key] = b[key]; 5487 } 5488 } 5489 return a; 5490 }; 5491 5492 /** 5493 * Return length of `obj`. 5494 * 5495 * @param {Object} obj 5496 * @return {Number} 5497 * @api public 5498 */ 5499 5500 exports.length = function(obj){ 5501 return exports.keys(obj).length; 5502 }; 5503 5504 /** 5505 * Check if `obj` is empty. 5506 * 5507 * @param {Object} obj 5508 * @return {Boolean} 5509 * @api public 5510 */ 5511 5512 exports.isEmpty = function(obj){ 5513 return 0 == exports.length(obj); 5514 }; 5515 },{}],42:[function(_dereq_,module,exports){ 5516 /** 5517 * Parses an URI 5518 * 5519 * @author Steven Levithan <stevenlevithan.com> (MIT license) 5520 * @api private 5521 */ 5522 5523 var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; 5524 5525 var parts = [ 5526 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host' 5527 , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' 5528 ]; 5529 5530 module.exports = function parseuri(str) { 5531 var m = re.exec(str || '') 5532 , uri = {} 5533 , i = 14; 5534 5535 while (i--) { 5536 uri[parts[i]] = m[i] || ''; 5537 } 5538 5539 return uri; 5540 }; 5541 5542 },{}],43:[function(_dereq_,module,exports){ 5543 (function (global){ 5544 /*global Blob,File*/ 5545 5546 /** 5547 * Module requirements 5548 */ 5549 5550 var isArray = _dereq_('isarray'); 5551 var isBuf = _dereq_('./is-buffer'); 5552 5553 /** 5554 * Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder. 5555 * Anything with blobs or files should be fed through removeBlobs before coming 5556 * here. 5557 * 5558 * @param {Object} packet - socket.io event packet 5559 * @return {Object} with deconstructed packet and list of buffers 5560 * @api public 5561 */ 5562 5563 exports.deconstructPacket = function(packet){ 5564 var buffers = []; 5565 var packetData = packet.data; 5566 5567 function _deconstructPacket(data) { 5568 if (!data) return data; 5569 5570 if (isBuf(data)) { 5571 var placeholder = { _placeholder: true, num: buffers.length }; 5572 buffers.push(data); 5573 return placeholder; 5574 } else if (isArray(data)) { 5575 var newData = new Array(data.length); 5576 for (var i = 0; i < data.length; i++) { 5577 newData[i] = _deconstructPacket(data[i]); 5578 } 5579 return newData; 5580 } else if ('object' == typeof data && !(data instanceof Date)) { 5581 var newData = {}; 5582 for (var key in data) { 5583 newData[key] = _deconstructPacket(data[key]); 5584 } 5585 return newData; 5586 } 5587 return data; 5588 } 5589 5590 var pack = packet; 5591 pack.data = _deconstructPacket(packetData); 5592 pack.attachments = buffers.length; // number of binary 'attachments' 5593 return {packet: pack, buffers: buffers}; 5594 }; 5595 5596 /** 5597 * Reconstructs a binary packet from its placeholder packet and buffers 5598 * 5599 * @param {Object} packet - event packet with placeholders 5600 * @param {Array} buffers - binary buffers to put in placeholder positions 5601 * @return {Object} reconstructed packet 5602 * @api public 5603 */ 5604 5605 exports.reconstructPacket = function(packet, buffers) { 5606 var curPlaceHolder = 0; 5607 5608 function _reconstructPacket(data) { 5609 if (data && data._placeholder) { 5610 var buf = buffers[data.num]; // appropriate buffer (should be natural order anyway) 5611 return buf; 5612 } else if (isArray(data)) { 5613 for (var i = 0; i < data.length; i++) { 5614 data[i] = _reconstructPacket(data[i]); 5615 } 5616 return data; 5617 } else if (data && 'object' == typeof data) { 5618 for (var key in data) { 5619 data[key] = _reconstructPacket(data[key]); 5620 } 5621 return data; 5622 } 5623 return data; 5624 } 5625 5626 packet.data = _reconstructPacket(packet.data); 5627 packet.attachments = undefined; // no longer useful 5628 return packet; 5629 }; 5630 5631 /** 5632 * Asynchronously removes Blobs or Files from data via 5633 * FileReader's readAsArrayBuffer method. Used before encoding 5634 * data as msgpack. Calls callback with the blobless data. 5635 * 5636 * @param {Object} data 5637 * @param {Function} callback 5638 * @api private 5639 */ 5640 5641 exports.removeBlobs = function(data, callback) { 5642 function _removeBlobs(obj, curKey, containingObject) { 5643 if (!obj) return obj; 5644 5645 // convert any blob 5646 if ((global.Blob && obj instanceof Blob) || 5647 (global.File && obj instanceof File)) { 5648 pendingBlobs++; 5649 5650 // async filereader 5651 var fileReader = new FileReader(); 5652 fileReader.onload = function() { // this.result == arraybuffer 5653 if (containingObject) { 5654 containingObject[curKey] = this.result; 5655 } 5656 else { 5657 bloblessData = this.result; 5658 } 5659 5660 // if nothing pending its callback time 5661 if(! --pendingBlobs) { 5662 callback(bloblessData); 5663 } 5664 }; 5665 5666 fileReader.readAsArrayBuffer(obj); // blob -> arraybuffer 5667 } else if (isArray(obj)) { // handle array 5668 for (var i = 0; i < obj.length; i++) { 5669 _removeBlobs(obj[i], i, obj); 5670 } 5671 } else if (obj && 'object' == typeof obj && !isBuf(obj)) { // and object 5672 for (var key in obj) { 5673 _removeBlobs(obj[key], key, obj); 5674 } 5675 } 5676 } 5677 5678 var pendingBlobs = 0; 5679 var bloblessData = data; 5680 _removeBlobs(bloblessData); 5681 if (!pendingBlobs) { 5682 callback(bloblessData); 5683 } 5684 }; 5685 5686 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 5687 },{"./is-buffer":45,"isarray":46}],44:[function(_dereq_,module,exports){ 5688 5689 /** 5690 * Module dependencies. 5691 */ 5692 5693 var debug = _dereq_('debug')('socket.io-parser'); 5694 var json = _dereq_('json3'); 5695 var isArray = _dereq_('isarray'); 5696 var Emitter = _dereq_('component-emitter'); 5697 var binary = _dereq_('./binary'); 5698 var isBuf = _dereq_('./is-buffer'); 5699 5700 /** 5701 * Protocol version. 5702 * 5703 * @api public 5704 */ 5705 5706 exports.protocol = 4; 5707 5708 /** 5709 * Packet types. 5710 * 5711 * @api public 5712 */ 5713 5714 exports.types = [ 5715 'CONNECT', 5716 'DISCONNECT', 5717 'EVENT', 5718 'BINARY_EVENT', 5719 'ACK', 5720 'BINARY_ACK', 5721 'ERROR' 5722 ]; 5723 5724 /** 5725 * Packet type `connect`. 5726 * 5727 * @api public 5728 */ 5729 5730 exports.CONNECT = 0; 5731 5732 /** 5733 * Packet type `disconnect`. 5734 * 5735 * @api public 5736 */ 5737 5738 exports.DISCONNECT = 1; 5739 5740 /** 5741 * Packet type `event`. 5742 * 5743 * @api public 5744 */ 5745 5746 exports.EVENT = 2; 5747 5748 /** 5749 * Packet type `ack`. 5750 * 5751 * @api public 5752 */ 5753 5754 exports.ACK = 3; 5755 5756 /** 5757 * Packet type `error`. 5758 * 5759 * @api public 5760 */ 5761 5762 exports.ERROR = 4; 5763 5764 /** 5765 * Packet type 'binary event' 5766 * 5767 * @api public 5768 */ 5769 5770 exports.BINARY_EVENT = 5; 5771 5772 /** 5773 * Packet type `binary ack`. For acks with binary arguments. 5774 * 5775 * @api public 5776 */ 5777 5778 exports.BINARY_ACK = 6; 5779 5780 /** 5781 * Encoder constructor. 5782 * 5783 * @api public 5784 */ 5785 5786 exports.Encoder = Encoder; 5787 5788 /** 5789 * Decoder constructor. 5790 * 5791 * @api public 5792 */ 5793 5794 exports.Decoder = Decoder; 5795 5796 /** 5797 * A socket.io Encoder instance 5798 * 5799 * @api public 5800 */ 5801 5802 function Encoder() {} 5803 5804 /** 5805 * Encode a packet as a single string if non-binary, or as a 5806 * buffer sequence, depending on packet type. 5807 * 5808 * @param {Object} obj - packet object 5809 * @param {Function} callback - function to handle encodings (likely engine.write) 5810 * @return Calls callback with Array of encodings 5811 * @api public 5812 */ 5813 5814 Encoder.prototype.encode = function(obj, callback){ 5815 debug('encoding packet %j', obj); 5816 5817 if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) { 5818 encodeAsBinary(obj, callback); 5819 } 5820 else { 5821 var encoding = encodeAsString(obj); 5822 callback([encoding]); 5823 } 5824 }; 5825 5826 /** 5827 * Encode packet as string. 5828 * 5829 * @param {Object} packet 5830 * @return {String} encoded 5831 * @api private 5832 */ 5833 5834 function encodeAsString(obj) { 5835 var str = ''; 5836 var nsp = false; 5837 5838 // first is type 5839 str += obj.type; 5840 5841 // attachments if we have them 5842 if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) { 5843 str += obj.attachments; 5844 str += '-'; 5845 } 5846 5847 // if we have a namespace other than `/` 5848 // we append it followed by a comma `,` 5849 if (obj.nsp && '/' != obj.nsp) { 5850 nsp = true; 5851 str += obj.nsp; 5852 } 5853 5854 // immediately followed by the id 5855 if (null != obj.id) { 5856 if (nsp) { 5857 str += ','; 5858 nsp = false; 5859 } 5860 str += obj.id; 5861 } 5862 5863 // json data 5864 if (null != obj.data) { 5865 if (nsp) str += ','; 5866 str += json.stringify(obj.data); 5867 } 5868 5869 debug('encoded %j as %s', obj, str); 5870 return str; 5871 } 5872 5873 /** 5874 * Encode packet as 'buffer sequence' by removing blobs, and 5875 * deconstructing packet into object with placeholders and 5876 * a list of buffers. 5877 * 5878 * @param {Object} packet 5879 * @return {Buffer} encoded 5880 * @api private 5881 */ 5882 5883 function encodeAsBinary(obj, callback) { 5884 5885 function writeEncoding(bloblessData) { 5886 var deconstruction = binary.deconstructPacket(bloblessData); 5887 var pack = encodeAsString(deconstruction.packet); 5888 var buffers = deconstruction.buffers; 5889 5890 buffers.unshift(pack); // add packet info to beginning of data list 5891 callback(buffers); // write all the buffers 5892 } 5893 5894 binary.removeBlobs(obj, writeEncoding); 5895 } 5896 5897 /** 5898 * A socket.io Decoder instance 5899 * 5900 * @return {Object} decoder 5901 * @api public 5902 */ 5903 5904 function Decoder() { 5905 this.reconstructor = null; 5906 } 5907 5908 /** 5909 * Mix in `Emitter` with Decoder. 5910 */ 5911 5912 Emitter(Decoder.prototype); 5913 5914 /** 5915 * Decodes an ecoded packet string into packet JSON. 5916 * 5917 * @param {String} obj - encoded packet 5918 * @return {Object} packet 5919 * @api public 5920 */ 5921 5922 Decoder.prototype.add = function(obj) { 5923 var packet; 5924 if ('string' == typeof obj) { 5925 packet = decodeString(obj); 5926 if (exports.BINARY_EVENT == packet.type || exports.BINARY_ACK == packet.type) { // binary packet's json 5927 this.reconstructor = new BinaryReconstructor(packet); 5928 5929 // no attachments, labeled binary but no binary data to follow 5930 if (this.reconstructor.reconPack.attachments === 0) { 5931 this.emit('decoded', packet); 5932 } 5933 } else { // non-binary full packet 5934 this.emit('decoded', packet); 5935 } 5936 } 5937 else if (isBuf(obj) || obj.base64) { // raw binary data 5938 if (!this.reconstructor) { 5939 throw new Error('got binary data when not reconstructing a packet'); 5940 } else { 5941 packet = this.reconstructor.takeBinaryData(obj); 5942 if (packet) { // received final buffer 5943 this.reconstructor = null; 5944 this.emit('decoded', packet); 5945 } 5946 } 5947 } 5948 else { 5949 throw new Error('Unknown type: ' + obj); 5950 } 5951 }; 5952 5953 /** 5954 * Decode a packet String (JSON data) 5955 * 5956 * @param {String} str 5957 * @return {Object} packet 5958 * @api private 5959 */ 5960 5961 function decodeString(str) { 5962 var p = {}; 5963 var i = 0; 5964 5965 // look up type 5966 p.type = Number(str.charAt(0)); 5967 if (null == exports.types[p.type]) return error(); 5968 5969 // look up attachments if type binary 5970 if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) { 5971 var buf = ''; 5972 while (str.charAt(++i) != '-') { 5973 buf += str.charAt(i); 5974 if (i == str.length) break; 5975 } 5976 if (buf != Number(buf) || str.charAt(i) != '-') { 5977 throw new Error('Illegal attachments'); 5978 } 5979 p.attachments = Number(buf); 5980 } 5981 5982 // look up namespace (if any) 5983 if ('/' == str.charAt(i + 1)) { 5984 p.nsp = ''; 5985 while (++i) { 5986 var c = str.charAt(i); 5987 if (',' == c) break; 5988 p.nsp += c; 5989 if (i == str.length) break; 5990 } 5991 } else { 5992 p.nsp = '/'; 5993 } 5994 5995 // look up id 5996 var next = str.charAt(i + 1); 5997 if ('' !== next && Number(next) == next) { 5998 p.id = ''; 5999 while (++i) { 6000 var c = str.charAt(i); 6001 if (null == c || Number(c) != c) { 6002 --i; 6003 break; 6004 } 6005 p.id += str.charAt(i); 6006 if (i == str.length) break; 6007 } 6008 p.id = Number(p.id); 6009 } 6010 6011 // look up json data 6012 if (str.charAt(++i)) { 6013 try { 6014 p.data = json.parse(str.substr(i)); 6015 } catch(e){ 6016 return error(); 6017 } 6018 } 6019 6020 debug('decoded %s as %j', str, p); 6021 return p; 6022 } 6023 6024 /** 6025 * Deallocates a parser's resources 6026 * 6027 * @api public 6028 */ 6029 6030 Decoder.prototype.destroy = function() { 6031 if (this.reconstructor) { 6032 this.reconstructor.finishedReconstruction(); 6033 } 6034 }; 6035 6036 /** 6037 * A manager of a binary event's 'buffer sequence'. Should 6038 * be constructed whenever a packet of type BINARY_EVENT is 6039 * decoded. 6040 * 6041 * @param {Object} packet 6042 * @return {BinaryReconstructor} initialized reconstructor 6043 * @api private 6044 */ 6045 6046 function BinaryReconstructor(packet) { 6047 this.reconPack = packet; 6048 this.buffers = []; 6049 } 6050 6051 /** 6052 * Method to be called when binary data received from connection 6053 * after a BINARY_EVENT packet. 6054 * 6055 * @param {Buffer | ArrayBuffer} binData - the raw binary data received 6056 * @return {null | Object} returns null if more binary data is expected or 6057 * a reconstructed packet object if all buffers have been received. 6058 * @api private 6059 */ 6060 6061 BinaryReconstructor.prototype.takeBinaryData = function(binData) { 6062 this.buffers.push(binData); 6063 if (this.buffers.length == this.reconPack.attachments) { // done with buffer list 6064 var packet = binary.reconstructPacket(this.reconPack, this.buffers); 6065 this.finishedReconstruction(); 6066 return packet; 6067 } 6068 return null; 6069 }; 6070 6071 /** 6072 * Cleans up binary packet reconstruction variables. 6073 * 6074 * @api private 6075 */ 6076 6077 BinaryReconstructor.prototype.finishedReconstruction = function() { 6078 this.reconPack = null; 6079 this.buffers = []; 6080 }; 6081 6082 function error(data){ 6083 return { 6084 type: exports.ERROR, 6085 data: 'parser error' 6086 }; 6087 } 6088 6089 },{"./binary":43,"./is-buffer":45,"component-emitter":9,"debug":10,"isarray":46,"json3":47}],45:[function(_dereq_,module,exports){ 6090 (function (global){ 6091 6092 module.exports = isBuf; 6093 6094 /** 6095 * Returns true if obj is a buffer or an arraybuffer. 6096 * 6097 * @api private 6098 */ 6099 6100 function isBuf(obj) { 6101 return (global.Buffer && global.Buffer.isBuffer(obj)) || 6102 (global.ArrayBuffer && obj instanceof ArrayBuffer); 6103 } 6104 6105 }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 6106 },{}],46:[function(_dereq_,module,exports){ 6107 module.exports=_dereq_(37) 6108 },{}],47:[function(_dereq_,module,exports){ 6109 /*! JSON v3.2.6 | http://bestiejs.github.io/json3 | Copyright 2012-2013, Kit Cambridge | http://kit.mit-license.org */ 6110 ;(function (window) { 6111 // Convenience aliases. 6112 var getClass = {}.toString, isProperty, forEach, undef; 6113 6114 // Detect the `define` function exposed by asynchronous module loaders. The 6115 // strict `define` check is necessary for compatibility with `r.js`. 6116 var isLoader = typeof define === "function" && define.amd; 6117 6118 // Detect native implementations. 6119 var nativeJSON = typeof JSON == "object" && JSON; 6120 6121 // Set up the JSON 3 namespace, preferring the CommonJS `exports` object if 6122 // available. 6123 var JSON3 = typeof exports == "object" && exports && !exports.nodeType && exports; 6124 6125 if (JSON3 && nativeJSON) { 6126 // Explicitly delegate to the native `stringify` and `parse` 6127 // implementations in CommonJS environments. 6128 JSON3.stringify = nativeJSON.stringify; 6129 JSON3.parse = nativeJSON.parse; 6130 } else { 6131 // Export for web browsers, JavaScript engines, and asynchronous module 6132 // loaders, using the global `JSON` object if available. 6133 JSON3 = window.JSON = nativeJSON || {}; 6134 } 6135 6136 // Test the `Date#getUTC*` methods. Based on work by @Yaffle. 6137 var isExtended = new Date(-3509827334573292); 6138 try { 6139 // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical 6140 // results for certain dates in Opera >= 10.53. 6141 isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 && 6142 // Safari < 2.0.2 stores the internal millisecond time value correctly, 6143 // but clips the values returned by the date methods to the range of 6144 // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]). 6145 isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708; 6146 } catch (exception) {} 6147 6148 // Internal: Determines whether the native `JSON.stringify` and `parse` 6149 // implementations are spec-compliant. Based on work by Ken Snyder. 6150 function has(name) { 6151 if (has[name] !== undef) { 6152 // Return cached feature test result. 6153 return has[name]; 6154 } 6155 6156 var isSupported; 6157 if (name == "bug-string-char-index") { 6158 // IE <= 7 doesn't support accessing string characters using square 6159 // bracket notation. IE 8 only supports this for primitives. 6160 isSupported = "a"[0] != "a"; 6161 } else if (name == "json") { 6162 // Indicates whether both `JSON.stringify` and `JSON.parse` are 6163 // supported. 6164 isSupported = has("json-stringify") && has("json-parse"); 6165 } else { 6166 var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'; 6167 // Test `JSON.stringify`. 6168 if (name == "json-stringify") { 6169 var stringify = JSON3.stringify, stringifySupported = typeof stringify == "function" && isExtended; 6170 if (stringifySupported) { 6171 // A test function object with a custom `toJSON` method. 6172 (value = function () { 6173 return 1; 6174 }).toJSON = value; 6175 try { 6176 stringifySupported = 6177 // Firefox 3.1b1 and b2 serialize string, number, and boolean 6178 // primitives as object literals. 6179 stringify(0) === "0" && 6180 // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object 6181 // literals. 6182 stringify(new Number()) === "0" && 6183 stringify(new String()) == '""' && 6184 // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or 6185 // does not define a canonical JSON representation (this applies to 6186 // objects with `toJSON` properties as well, *unless* they are nested 6187 // within an object or array). 6188 stringify(getClass) === undef && 6189 // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and 6190 // FF 3.1b3 pass this test. 6191 stringify(undef) === undef && 6192 // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s, 6193 // respectively, if the value is omitted entirely. 6194 stringify() === undef && 6195 // FF 3.1b1, 2 throw an error if the given value is not a number, 6196 // string, array, object, Boolean, or `null` literal. This applies to 6197 // objects with custom `toJSON` methods as well, unless they are nested 6198 // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON` 6199 // methods entirely. 6200 stringify(value) === "1" && 6201 stringify([value]) == "[1]" && 6202 // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of 6203 // `"[null]"`. 6204 stringify([undef]) == "[null]" && 6205 // YUI 3.0.0b1 fails to serialize `null` literals. 6206 stringify(null) == "null" && 6207 // FF 3.1b1, 2 halts serialization if an array contains a function: 6208 // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3 6209 // elides non-JSON values from objects and arrays, unless they 6210 // define custom `toJSON` methods. 6211 stringify([undef, getClass, null]) == "[null,null,null]" && 6212 // Simple serialization test. FF 3.1b1 uses Unicode escape sequences 6213 // where character escape codes are expected (e.g., `\b` => `\u0008`). 6214 stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized && 6215 // FF 3.1b1 and b2 ignore the `filter` and `width` arguments. 6216 stringify(null, value) === "1" && 6217 stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" && 6218 // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly 6219 // serialize extended years. 6220 stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' && 6221 // The milliseconds are optional in ES 5, but required in 5.1. 6222 stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' && 6223 // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative 6224 // four-digit years instead of six-digit years. Credits: @Yaffle. 6225 stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' && 6226 // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond 6227 // values less than 1000. Credits: @Yaffle. 6228 stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; 6229 } catch (exception) { 6230 stringifySupported = false; 6231 } 6232 } 6233 isSupported = stringifySupported; 6234 } 6235 // Test `JSON.parse`. 6236 if (name == "json-parse") { 6237 var parse = JSON3.parse; 6238 if (typeof parse == "function") { 6239 try { 6240 // FF 3.1b1, b2 will throw an exception if a bare literal is provided. 6241 // Conforming implementations should also coerce the initial argument to 6242 // a string prior to parsing. 6243 if (parse("0") === 0 && !parse(false)) { 6244 // Simple parsing test. 6245 value = parse(serialized); 6246 var parseSupported = value["a"].length == 5 && value["a"][0] === 1; 6247 if (parseSupported) { 6248 try { 6249 // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings. 6250 parseSupported = !parse('"\t"'); 6251 } catch (exception) {} 6252 if (parseSupported) { 6253 try { 6254 // FF 4.0 and 4.0.1 allow leading `+` signs and leading 6255 // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow 6256 // certain octal literals. 6257 parseSupported = parse("01") !== 1; 6258 } catch (exception) {} 6259 } 6260 if (parseSupported) { 6261 try { 6262 // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal 6263 // points. These environments, along with FF 3.1b1 and 2, 6264 // also allow trailing commas in JSON objects and arrays. 6265 parseSupported = parse("1.") !== 1; 6266 } catch (exception) {} 6267 } 6268 } 6269 } 6270 } catch (exception) { 6271 parseSupported = false; 6272 } 6273 } 6274 isSupported = parseSupported; 6275 } 6276 } 6277 return has[name] = !!isSupported; 6278 } 6279 6280 if (!has("json")) { 6281 // Common `[[Class]]` name aliases. 6282 var functionClass = "[object Function]"; 6283 var dateClass = "[object Date]"; 6284 var numberClass = "[object Number]"; 6285 var stringClass = "[object String]"; 6286 var arrayClass = "[object Array]"; 6287 var booleanClass = "[object Boolean]"; 6288 6289 // Detect incomplete support for accessing string characters by index. 6290 var charIndexBuggy = has("bug-string-char-index"); 6291 6292 // Define additional utility methods if the `Date` methods are buggy. 6293 if (!isExtended) { 6294 var floor = Math.floor; 6295 // A mapping between the months of the year and the number of days between 6296 // January 1st and the first of the respective month. 6297 var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; 6298 // Internal: Calculates the number of days between the Unix epoch and the 6299 // first day of the given month. 6300 var getDay = function (year, month) { 6301 return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400); 6302 }; 6303 } 6304 6305 // Internal: Determines if a property is a direct property of the given 6306 // object. Delegates to the native `Object#hasOwnProperty` method. 6307 if (!(isProperty = {}.hasOwnProperty)) { 6308 isProperty = function (property) { 6309 var members = {}, constructor; 6310 if ((members.__proto__ = null, members.__proto__ = { 6311 // The *proto* property cannot be set multiple times in recent 6312 // versions of Firefox and SeaMonkey. 6313 "toString": 1 6314 }, members).toString != getClass) { 6315 // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but 6316 // supports the mutable *proto* property. 6317 isProperty = function (property) { 6318 // Capture and break the object's prototype chain (see section 8.6.2 6319 // of the ES 5.1 spec). The parenthesized expression prevents an 6320 // unsafe transformation by the Closure Compiler. 6321 var original = this.__proto__, result = property in (this.__proto__ = null, this); 6322 // Restore the original prototype chain. 6323 this.__proto__ = original; 6324 return result; 6325 }; 6326 } else { 6327 // Capture a reference to the top-level `Object` constructor. 6328 constructor = members.constructor; 6329 // Use the `constructor` property to simulate `Object#hasOwnProperty` in 6330 // other environments. 6331 isProperty = function (property) { 6332 var parent = (this.constructor || constructor).prototype; 6333 return property in this && !(property in parent && this[property] === parent[property]); 6334 }; 6335 } 6336 members = null; 6337 return isProperty.call(this, property); 6338 }; 6339 } 6340 6341 // Internal: A set of primitive types used by `isHostType`. 6342 var PrimitiveTypes = { 6343 'boolean': 1, 6344 'number': 1, 6345 'string': 1, 6346 'undefined': 1 6347 }; 6348 6349 // Internal: Determines if the given object `property` value is a 6350 // non-primitive. 6351 var isHostType = function (object, property) { 6352 var type = typeof object[property]; 6353 return type == 'object' ? !!object[property] : !PrimitiveTypes[type]; 6354 }; 6355 6356 // Internal: Normalizes the `for...in` iteration algorithm across 6357 // environments. Each enumerated key is yielded to a `callback` function. 6358 forEach = function (object, callback) { 6359 var size = 0, Properties, members, property; 6360 6361 // Tests for bugs in the current environment's `for...in` algorithm. The 6362 // `valueOf` property inherits the non-enumerable flag from 6363 // `Object.prototype` in older versions of IE, Netscape, and Mozilla. 6364 (Properties = function () { 6365 this.valueOf = 0; 6366 }).prototype.valueOf = 0; 6367 6368 // Iterate over a new instance of the `Properties` class. 6369 members = new Properties(); 6370 for (property in members) { 6371 // Ignore all properties inherited from `Object.prototype`. 6372 if (isProperty.call(members, property)) { 6373 size++; 6374 } 6375 } 6376 Properties = members = null; 6377 6378 // Normalize the iteration algorithm. 6379 if (!size) { 6380 // A list of non-enumerable properties inherited from `Object.prototype`. 6381 members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"]; 6382 // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable 6383 // properties. 6384 forEach = function (object, callback) { 6385 var isFunction = getClass.call(object) == functionClass, property, length; 6386 var hasProperty = !isFunction && typeof object.constructor != 'function' && isHostType(object, 'hasOwnProperty') ? object.hasOwnProperty : isProperty; 6387 for (property in object) { 6388 // Gecko <= 1.0 enumerates the `prototype` property of functions under 6389 // certain conditions; IE does not. 6390 if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) { 6391 callback(property); 6392 } 6393 } 6394 // Manually invoke the callback for each non-enumerable property. 6395 for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property)); 6396 }; 6397 } else if (size == 2) { 6398 // Safari <= 2.0.4 enumerates shadowed properties twice. 6399 forEach = function (object, callback) { 6400 // Create a set of iterated properties. 6401 var members = {}, isFunction = getClass.call(object) == functionClass, property; 6402 for (property in object) { 6403 // Store each property name to prevent double enumeration. The 6404 // `prototype` property of functions is not enumerated due to cross- 6405 // environment inconsistencies. 6406 if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) { 6407 callback(property); 6408 } 6409 } 6410 }; 6411 } else { 6412 // No bugs detected; use the standard `for...in` algorithm. 6413 forEach = function (object, callback) { 6414 var isFunction = getClass.call(object) == functionClass, property, isConstructor; 6415 for (property in object) { 6416 if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) { 6417 callback(property); 6418 } 6419 } 6420 // Manually invoke the callback for the `constructor` property due to 6421 // cross-environment inconsistencies. 6422 if (isConstructor || isProperty.call(object, (property = "constructor"))) { 6423 callback(property); 6424 } 6425 }; 6426 } 6427 return forEach(object, callback); 6428 }; 6429 6430 // Public: Serializes a JavaScript `value` as a JSON string. The optional 6431 // `filter` argument may specify either a function that alters how object and 6432 // array members are serialized, or an array of strings and numbers that 6433 // indicates which properties should be serialized. The optional `width` 6434 // argument may be either a string or number that specifies the indentation 6435 // level of the output. 6436 if (!has("json-stringify")) { 6437 // Internal: A map of control characters and their escaped equivalents. 6438 var Escapes = { 6439 92: "\\\\", 6440 34: '\\"', 6441 8: "\\b", 6442 12: "\\f", 6443 10: "\\n", 6444 13: "\\r", 6445 9: "\\t" 6446 }; 6447 6448 // Internal: Converts `value` into a zero-padded string such that its 6449 // length is at least equal to `width`. The `width` must be <= 6. 6450 var leadingZeroes = "000000"; 6451 var toPaddedString = function (width, value) { 6452 // The `|| 0` expression is necessary to work around a bug in 6453 // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`. 6454 return (leadingZeroes + (value || 0)).slice(-width); 6455 }; 6456 6457 // Internal: Double-quotes a string `value`, replacing all ASCII control 6458 // characters (characters with code unit values between 0 and 31) with 6459 // their escaped equivalents. This is an implementation of the 6460 // `Quote(value)` operation defined in ES 5.1 section 15.12.3. 6461 var unicodePrefix = "\\u00"; 6462 var quote = function (value) { 6463 var result = '"', index = 0, length = value.length, isLarge = length > 10 && charIndexBuggy, symbols; 6464 if (isLarge) { 6465 symbols = value.split(""); 6466 } 6467 for (; index < length; index++) { 6468 var charCode = value.charCodeAt(index); 6469 // If the character is a control character, append its Unicode or 6470 // shorthand escape sequence; otherwise, append the character as-is. 6471 switch (charCode) { 6472 case 8: case 9: case 10: case 12: case 13: case 34: case 92: 6473 result += Escapes[charCode]; 6474 break; 6475 default: 6476 if (charCode < 32) { 6477 result += unicodePrefix + toPaddedString(2, charCode.toString(16)); 6478 break; 6479 } 6480 result += isLarge ? symbols[index] : charIndexBuggy ? value.charAt(index) : value[index]; 6481 } 6482 } 6483 return result + '"'; 6484 }; 6485 6486 // Internal: Recursively serializes an object. Implements the 6487 // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations. 6488 var serialize = function (property, object, callback, properties, whitespace, indentation, stack) { 6489 var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result; 6490 try { 6491 // Necessary for host object support. 6492 value = object[property]; 6493 } catch (exception) {} 6494 if (typeof value == "object" && value) { 6495 className = getClass.call(value); 6496 if (className == dateClass && !isProperty.call(value, "toJSON")) { 6497 if (value > -1 / 0 && value < 1 / 0) { 6498 // Dates are serialized according to the `Date#toJSON` method 6499 // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15 6500 // for the ISO 8601 date time string format. 6501 if (getDay) { 6502 // Manually compute the year, month, date, hours, minutes, 6503 // seconds, and milliseconds if the `getUTC*` methods are 6504 // buggy. Adapted from @Yaffle's `date-shim` project. 6505 date = floor(value / 864e5); 6506 for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++); 6507 for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++); 6508 date = 1 + date - getDay(year, month); 6509 // The `time` value specifies the time within the day (see ES 6510 // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used 6511 // to compute `A modulo B`, as the `%` operator does not 6512 // correspond to the `modulo` operation for negative numbers. 6513 time = (value % 864e5 + 864e5) % 864e5; 6514 // The hours, minutes, seconds, and milliseconds are obtained by 6515 // decomposing the time within the day. See section 15.9.1.10. 6516 hours = floor(time / 36e5) % 24; 6517 minutes = floor(time / 6e4) % 60; 6518 seconds = floor(time / 1e3) % 60; 6519 milliseconds = time % 1e3; 6520 } else { 6521 year = value.getUTCFullYear(); 6522 month = value.getUTCMonth(); 6523 date = value.getUTCDate(); 6524 hours = value.getUTCHours(); 6525 minutes = value.getUTCMinutes(); 6526 seconds = value.getUTCSeconds(); 6527 milliseconds = value.getUTCMilliseconds(); 6528 } 6529 // Serialize extended years correctly. 6530 value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) + 6531 "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) + 6532 // Months, dates, hours, minutes, and seconds should have two 6533 // digits; milliseconds should have three. 6534 "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) + 6535 // Milliseconds are optional in ES 5.0, but required in 5.1. 6536 "." + toPaddedString(3, milliseconds) + "Z"; 6537 } else { 6538 value = null; 6539 } 6540 } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) { 6541 // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the 6542 // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3 6543 // ignores all `toJSON` methods on these objects unless they are 6544 // defined directly on an instance. 6545 value = value.toJSON(property); 6546 } 6547 } 6548 if (callback) { 6549 // If a replacement function was provided, call it to obtain the value 6550 // for serialization. 6551 value = callback.call(object, property, value); 6552 } 6553 if (value === null) { 6554 return "null"; 6555 } 6556 className = getClass.call(value); 6557 if (className == booleanClass) { 6558 // Booleans are represented literally. 6559 return "" + value; 6560 } else if (className == numberClass) { 6561 // JSON numbers must be finite. `Infinity` and `NaN` are serialized as 6562 // `"null"`. 6563 return value > -1 / 0 && value < 1 / 0 ? "" + value : "null"; 6564 } else if (className == stringClass) { 6565 // Strings are double-quoted and escaped. 6566 return quote("" + value); 6567 } 6568 // Recursively serialize objects and arrays. 6569 if (typeof value == "object") { 6570 // Check for cyclic structures. This is a linear search; performance 6571 // is inversely proportional to the number of unique nested objects. 6572 for (length = stack.length; length--;) { 6573 if (stack[length] === value) { 6574 // Cyclic structures cannot be serialized by `JSON.stringify`. 6575 throw TypeError(); 6576 } 6577 } 6578 // Add the object to the stack of traversed objects. 6579 stack.push(value); 6580 results = []; 6581 // Save the current indentation level and indent one additional level. 6582 prefix = indentation; 6583 indentation += whitespace; 6584 if (className == arrayClass) { 6585 // Recursively serialize array elements. 6586 for (index = 0, length = value.length; index < length; index++) { 6587 element = serialize(index, value, callback, properties, whitespace, indentation, stack); 6588 results.push(element === undef ? "null" : element); 6589 } 6590 result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]"; 6591 } else { 6592 // Recursively serialize object members. Members are selected from 6593 // either a user-specified list of property names, or the object 6594 // itself. 6595 forEach(properties || value, function (property) { 6596 var element = serialize(property, value, callback, properties, whitespace, indentation, stack); 6597 if (element !== undef) { 6598 // According to ES 5.1 section 15.12.3: "If `gap` {whitespace} 6599 // is not the empty string, let `member` {quote(property) + ":"} 6600 // be the concatenation of `member` and the `space` character." 6601 // The "`space` character" refers to the literal space 6602 // character, not the `space` {width} argument provided to 6603 // `JSON.stringify`. 6604 results.push(quote(property) + ":" + (whitespace ? " " : "") + element); 6605 } 6606 }); 6607 result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}"; 6608 } 6609 // Remove the object from the traversed object stack. 6610 stack.pop(); 6611 return result; 6612 } 6613 }; 6614 6615 // Public: `JSON.stringify`. See ES 5.1 section 15.12.3. 6616 JSON3.stringify = function (source, filter, width) { 6617 var whitespace, callback, properties, className; 6618 if (typeof filter == "function" || typeof filter == "object" && filter) { 6619 if ((className = getClass.call(filter)) == functionClass) { 6620 callback = filter; 6621 } else if (className == arrayClass) { 6622 // Convert the property names array into a makeshift set. 6623 properties = {}; 6624 for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1)); 6625 } 6626 } 6627 if (width) { 6628 if ((className = getClass.call(width)) == numberClass) { 6629 // Convert the `width` to an integer and create a string containing 6630 // `width` number of space characters. 6631 if ((width -= width % 1) > 0) { 6632 for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " "); 6633 } 6634 } else if (className == stringClass) { 6635 whitespace = width.length <= 10 ? width : width.slice(0, 10); 6636 } 6637 } 6638 // Opera <= 7.54u2 discards the values associated with empty string keys 6639 // (`""`) only if they are used directly within an object member list 6640 // (e.g., `!("" in { "": 1})`). 6641 return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []); 6642 }; 6643 } 6644 6645 // Public: Parses a JSON source string. 6646 if (!has("json-parse")) { 6647 var fromCharCode = String.fromCharCode; 6648 6649 // Internal: A map of escaped control characters and their unescaped 6650 // equivalents. 6651 var Unescapes = { 6652 92: "\\", 6653 34: '"', 6654 47: "/", 6655 98: "\b", 6656 116: "\t", 6657 110: "\n", 6658 102: "\f", 6659 114: "\r" 6660 }; 6661 6662 // Internal: Stores the parser state. 6663 var Index, Source; 6664 6665 // Internal: Resets the parser state and throws a `SyntaxError`. 6666 var abort = function() { 6667 Index = Source = null; 6668 throw SyntaxError(); 6669 }; 6670 6671 // Internal: Returns the next token, or `"$"` if the parser has reached 6672 // the end of the source string. A token may be a string, number, `null` 6673 // literal, or Boolean literal. 6674 var lex = function () { 6675 var source = Source, length = source.length, value, begin, position, isSigned, charCode; 6676 while (Index < length) { 6677 charCode = source.charCodeAt(Index); 6678 switch (charCode) { 6679 case 9: case 10: case 13: case 32: 6680 // Skip whitespace tokens, including tabs, carriage returns, line 6681 // feeds, and space characters. 6682 Index++; 6683 break; 6684 case 123: case 125: case 91: case 93: case 58: case 44: 6685 // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at 6686 // the current position. 6687 value = charIndexBuggy ? source.charAt(Index) : source[Index]; 6688 Index++; 6689 return value; 6690 case 34: 6691 // `"` delimits a JSON string; advance to the next character and 6692 // begin parsing the string. String tokens are prefixed with the 6693 // sentinel `@` character to distinguish them from punctuators and 6694 // end-of-string tokens. 6695 for (value = "@", Index++; Index < length;) { 6696 charCode = source.charCodeAt(Index); 6697 if (charCode < 32) { 6698 // Unescaped ASCII control characters (those with a code unit 6699 // less than the space character) are not permitted. 6700 abort(); 6701 } else if (charCode == 92) { 6702 // A reverse solidus (`\`) marks the beginning of an escaped 6703 // control character (including `"`, `\`, and `/`) or Unicode 6704 // escape sequence. 6705 charCode = source.charCodeAt(++Index); 6706 switch (charCode) { 6707 case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114: 6708 // Revive escaped control characters. 6709 value += Unescapes[charCode]; 6710 Index++; 6711 break; 6712 case 117: 6713 // `\u` marks the beginning of a Unicode escape sequence. 6714 // Advance to the first character and validate the 6715 // four-digit code point. 6716 begin = ++Index; 6717 for (position = Index + 4; Index < position; Index++) { 6718 charCode = source.charCodeAt(Index); 6719 // A valid sequence comprises four hexdigits (case- 6720 // insensitive) that form a single hexadecimal value. 6721 if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) { 6722 // Invalid Unicode escape sequence. 6723 abort(); 6724 } 6725 } 6726 // Revive the escaped character. 6727 value += fromCharCode("0x" + source.slice(begin, Index)); 6728 break; 6729 default: 6730 // Invalid escape sequence. 6731 abort(); 6732 } 6733 } else { 6734 if (charCode == 34) { 6735 // An unescaped double-quote character marks the end of the 6736 // string. 6737 break; 6738 } 6739 charCode = source.charCodeAt(Index); 6740 begin = Index; 6741 // Optimize for the common case where a string is valid. 6742 while (charCode >= 32 && charCode != 92 && charCode != 34) { 6743 charCode = source.charCodeAt(++Index); 6744 } 6745 // Append the string as-is. 6746 value += source.slice(begin, Index); 6747 } 6748 } 6749 if (source.charCodeAt(Index) == 34) { 6750 // Advance to the next character and return the revived string. 6751 Index++; 6752 return value; 6753 } 6754 // Unterminated string. 6755 abort(); 6756 default: 6757 // Parse numbers and literals. 6758 begin = Index; 6759 // Advance past the negative sign, if one is specified. 6760 if (charCode == 45) { 6761 isSigned = true; 6762 charCode = source.charCodeAt(++Index); 6763 } 6764 // Parse an integer or floating-point value. 6765 if (charCode >= 48 && charCode <= 57) { 6766 // Leading zeroes are interpreted as octal literals. 6767 if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) { 6768 // Illegal octal literal. 6769 abort(); 6770 } 6771 isSigned = false; 6772 // Parse the integer component. 6773 for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++); 6774 // Floats cannot contain a leading decimal point; however, this 6775 // case is already accounted for by the parser. 6776 if (source.charCodeAt(Index) == 46) { 6777 position = ++Index; 6778 // Parse the decimal component. 6779 for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); 6780 if (position == Index) { 6781 // Illegal trailing decimal. 6782 abort(); 6783 } 6784 Index = position; 6785 } 6786 // Parse exponents. The `e` denoting the exponent is 6787 // case-insensitive. 6788 charCode = source.charCodeAt(Index); 6789 if (charCode == 101 || charCode == 69) { 6790 charCode = source.charCodeAt(++Index); 6791 // Skip past the sign following the exponent, if one is 6792 // specified. 6793 if (charCode == 43 || charCode == 45) { 6794 Index++; 6795 } 6796 // Parse the exponential component. 6797 for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); 6798 if (position == Index) { 6799 // Illegal empty exponent. 6800 abort(); 6801 } 6802 Index = position; 6803 } 6804 // Coerce the parsed value to a JavaScript number. 6805 return +source.slice(begin, Index); 6806 } 6807 // A negative sign may only precede numbers. 6808 if (isSigned) { 6809 abort(); 6810 } 6811 // `true`, `false`, and `null` literals. 6812 if (source.slice(Index, Index + 4) == "true") { 6813 Index += 4; 6814 return true; 6815 } else if (source.slice(Index, Index + 5) == "false") { 6816 Index += 5; 6817 return false; 6818 } else if (source.slice(Index, Index + 4) == "null") { 6819 Index += 4; 6820 return null; 6821 } 6822 // Unrecognized token. 6823 abort(); 6824 } 6825 } 6826 // Return the sentinel `$` character if the parser has reached the end 6827 // of the source string. 6828 return "$"; 6829 }; 6830 6831 // Internal: Parses a JSON `value` token. 6832 var get = function (value) { 6833 var results, hasMembers; 6834 if (value == "$") { 6835 // Unexpected end of input. 6836 abort(); 6837 } 6838 if (typeof value == "string") { 6839 if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") { 6840 // Remove the sentinel `@` character. 6841 return value.slice(1); 6842 } 6843 // Parse object and array literals. 6844 if (value == "[") { 6845 // Parses a JSON array, returning a new JavaScript array. 6846 results = []; 6847 for (;; hasMembers || (hasMembers = true)) { 6848 value = lex(); 6849 // A closing square bracket marks the end of the array literal. 6850 if (value == "]") { 6851 break; 6852 } 6853 // If the array literal contains elements, the current token 6854 // should be a comma separating the previous element from the 6855 // next. 6856 if (hasMembers) { 6857 if (value == ",") { 6858 value = lex(); 6859 if (value == "]") { 6860 // Unexpected trailing `,` in array literal. 6861 abort(); 6862 } 6863 } else { 6864 // A `,` must separate each array element. 6865 abort(); 6866 } 6867 } 6868 // Elisions and leading commas are not permitted. 6869 if (value == ",") { 6870 abort(); 6871 } 6872 results.push(get(value)); 6873 } 6874 return results; 6875 } else if (value == "{") { 6876 // Parses a JSON object, returning a new JavaScript object. 6877 results = {}; 6878 for (;; hasMembers || (hasMembers = true)) { 6879 value = lex(); 6880 // A closing curly brace marks the end of the object literal. 6881 if (value == "}") { 6882 break; 6883 } 6884 // If the object literal contains members, the current token 6885 // should be a comma separator. 6886 if (hasMembers) { 6887 if (value == ",") { 6888 value = lex(); 6889 if (value == "}") { 6890 // Unexpected trailing `,` in object literal. 6891 abort(); 6892 } 6893 } else { 6894 // A `,` must separate each object member. 6895 abort(); 6896 } 6897 } 6898 // Leading commas are not permitted, object property names must be 6899 // double-quoted strings, and a `:` must separate each property 6900 // name and value. 6901 if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") { 6902 abort(); 6903 } 6904 results[value.slice(1)] = get(lex()); 6905 } 6906 return results; 6907 } 6908 // Unexpected token encountered. 6909 abort(); 6910 } 6911 return value; 6912 }; 6913 6914 // Internal: Updates a traversed object member. 6915 var update = function(source, property, callback) { 6916 var element = walk(source, property, callback); 6917 if (element === undef) { 6918 delete source[property]; 6919 } else { 6920 source[property] = element; 6921 } 6922 }; 6923 6924 // Internal: Recursively traverses a parsed JSON object, invoking the 6925 // `callback` function for each value. This is an implementation of the 6926 // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2. 6927 var walk = function (source, property, callback) { 6928 var value = source[property], length; 6929 if (typeof value == "object" && value) { 6930 // `forEach` can't be used to traverse an array in Opera <= 8.54 6931 // because its `Object#hasOwnProperty` implementation returns `false` 6932 // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`). 6933 if (getClass.call(value) == arrayClass) { 6934 for (length = value.length; length--;) { 6935 update(value, length, callback); 6936 } 6937 } else { 6938 forEach(value, function (property) { 6939 update(value, property, callback); 6940 }); 6941 } 6942 } 6943 return callback.call(source, property, value); 6944 }; 6945 6946 // Public: `JSON.parse`. See ES 5.1 section 15.12.2. 6947 JSON3.parse = function (source, callback) { 6948 var result, value; 6949 Index = 0; 6950 Source = "" + source; 6951 result = get(lex()); 6952 // If a JSON string contains multiple tokens, it is invalid. 6953 if (lex() != "$") { 6954 abort(); 6955 } 6956 // Reset the parser state. 6957 Index = Source = null; 6958 return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result; 6959 }; 6960 } 6961 } 6962 6963 // Export for asynchronous module loaders. 6964 if (isLoader) { 6965 define(function () { 6966 return JSON3; 6967 }); 6968 } 6969 }(this)); 6970 6971 },{}],48:[function(_dereq_,module,exports){ 6972 module.exports = toArray 6973 6974 function toArray(list, index) { 6975 var array = [] 6976 6977 index = index || 0 6978 6979 for (var i = index || 0; i < list.length; i++) { 6980 array[i - index] = list[i] 6981 } 6982 6983 return array 6984 } 6985 6986 },{}]},{},[1]) 6987 (1) 6988 });
项目结构如下图: