commit f08a3a0e4920afe64074d3808c6029b3914bffae Author: Joshua Seigler Date: Tue Sep 12 13:13:10 2017 -0400 publish: :tv: Add github pages deploy task generated from commit 1d0caf22b3685926f688aca5831bcdec0d37572b diff --git a/assets/Dash-logo.svg b/assets/Dash-logo.svg new file mode 100644 index 0000000..e999cc9 --- /dev/null +++ b/assets/Dash-logo.svg @@ -0,0 +1,2 @@ + +image/svg+xml diff --git a/assets/bell.mp3 b/assets/bell.mp3 new file mode 100644 index 0000000..9afb2cf Binary files /dev/null and b/assets/bell.mp3 differ diff --git a/assets/creek.mp3 b/assets/creek.mp3 new file mode 100644 index 0000000..204712d Binary files /dev/null and b/assets/creek.mp3 differ diff --git a/assets/metallophone.mp3 b/assets/metallophone.mp3 new file mode 100644 index 0000000..8ca64d9 Binary files /dev/null and b/assets/metallophone.mp3 differ diff --git a/assets/splash-big.mp3 b/assets/splash-big.mp3 new file mode 100644 index 0000000..e3d91d5 Binary files /dev/null and b/assets/splash-big.mp3 differ diff --git a/assets/splash-medium.mp3 b/assets/splash-medium.mp3 new file mode 100644 index 0000000..49653e7 Binary files /dev/null and b/assets/splash-medium.mp3 differ diff --git a/assets/splash-tiny.mp3 b/assets/splash-tiny.mp3 new file mode 100644 index 0000000..438dd89 Binary files /dev/null and b/assets/splash-tiny.mp3 differ diff --git a/assets/whoosh.mp3 b/assets/whoosh.mp3 new file mode 100644 index 0000000..d3492c2 Binary files /dev/null and b/assets/whoosh.mp3 differ diff --git a/assets/wood-hit-glass.mp3 b/assets/wood-hit-glass.mp3 new file mode 100644 index 0000000..1888ef4 Binary files /dev/null and b/assets/wood-hit-glass.mp3 differ diff --git a/bundle.css b/bundle.css new file mode 100644 index 0000000..6a592bf --- /dev/null +++ b/bundle.css @@ -0,0 +1,159 @@ +body { + padding: 0; + margin: 0; + box-sizing: border-box; + font-family: sans-serif; + font-size: 140%; + background-image: url('assets/Dash-logo.svg'), linear-gradient(to bottom right, #1e73be, #073a66); + background-size: 50vmin auto, cover; + background-position: center; + background-attachment: fixed; + background-repeat: no-repeat; + background-color: #1e73be; + color: white; + min-height: 100vh; +} +* { + box-sizing: inherit; +} +a { + color: inherit; + text-decoration: none; +} +#transactionList { + padding: 1em 0 0; + mix-blend-mode: screen; + opacity: 0.75; + height: 100vh; + overflow: hidden; +} +#transactionList:after { + content: ''; + position: fixed; + bottom: 0; + height: 8em; + left: 0; + right: 0; + background-image: linear-gradient(to top, black, transparent); + z-index: 2; + pointer-events: none; +} +#connectionStatus.is-connected ~ #transactionList:empty:before { + content: 'Waiting for first transaction...'; + display: block; + text-align: center; + font-size: 2em; + opacity: 0.5; +} +.tx { + position: relative; + margin: 3px auto; + width: 20em; + min-width: 80%; + max-width: 100%; + z-index: 1; +} +.txValue { + display: none; + flex: 0 0 auto; + line-height: 1.25; +} +.txOutputs { + display: flex; + flex-wrap: nowrap; + flex-direction: row; + align-content: stretch; +} +.txOut { + position: relative; + flex: 1 1 auto; + background-color: white; +} +.txOut:first { + border-left: 3px solid black; +} +.txOut:after { + content: ''; + width: 3px; + background: black; + position: absolute; + right: 0; + top: 0; + bottom: 0; +} +.blockDivider { + display: block; + margin: 1em -1em -1.5em; + background: linear-gradient(to top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.125)); + padding: 0.125em 1em 1.5em; + color: rgba(0, 0, 0, 0); + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.blockDivider:hover, +.blockDivider:focus { + color: inherit; +} +#muteToggle, +#connectionStatus { + position: fixed; + top: 0; + width: 8em; + background: white; + border: solid black; + padding: 0.5em; + font-size: 0.8em; + text-transform: uppercase; + font-weight: bold; + text-align: center; + color: black; +} +#muteToggle { + left: 0; + border-radius: 0 0 0.5em 0; + border-width: 0 0.1em 0.1em 0; + transition: opacity 0.5s; + transition-delay: 1s; + opacity: 0; + cursor: pointer; + z-index: 100; +} +#muteToggle:hover { + opacity: 1; + transition-delay: 0s; +} +#muteToggle:before { + content: 'Mute'; +} +#muteToggle.is-muted:before { + content: 'Un-mute'; +} +#connectionStatus { + right: 0; + border-radius: 0 0 0 0.5em; + border-width: 0 0 0.1em 0.1em; + transition: transform 0.5s; + transform: none; +} +#connectionStatus.is-disconnected:before { + content: 'Disconnected'; + color: red; +} +#connectionStatus.is-connecting:before { + content: 'Connecting...'; + color: black; +} +#connectionStatus.is-connected:before { + content: 'Connected'; + color: green; +} +#connectionStatus.is-connected { + transition: transform 0.5s; + transition-delay: 2s; + transform: translate3d(0, -100%, 0); +} + + +/*# sourceMappingURL=bundle.css.map*/ \ No newline at end of file diff --git a/bundle.css.map b/bundle.css.map new file mode 100644 index 0000000..5be8ace --- /dev/null +++ b/bundle.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["app/styles/main.less"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"public/bundle.css","sourcesContent":["body {\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n font-family: sans-serif;\n font-size: 140%;\n background-image: url('assets/Dash-logo.svg'), linear-gradient(to bottom right, #1e73be, #073a66);\n background-size: 50vmin auto, cover;\n background-position: center;\n background-attachment: fixed;\n background-repeat: no-repeat;\n background-color: #1e73be;\n color: white;\n min-height: 100vh;\n}\n* {\n box-sizing: inherit;\n}\na {\n color: inherit;\n text-decoration: none;\n}\n#transactionList {\n padding: 1em 0 0;\n mix-blend-mode: screen;\n opacity: 0.75;\n height: 100vh;\n overflow: hidden;\n}\n#transactionList:after {\n content: '';\n position: fixed;\n bottom: 0;\n height: 8em;\n left: 0;\n right: 0;\n background-image: linear-gradient(to top, black, transparent);\n z-index: 2;\n pointer-events: none;\n}\n#connectionStatus.is-connected ~ #transactionList:empty:before {\n content: 'Waiting for first transaction...';\n display: block;\n text-align: center;\n font-size: 2em;\n opacity: 0.5;\n}\n.tx {\n position: relative;\n margin: 3px auto;\n width: 20em;\n min-width: 80%;\n max-width: 100%;\n z-index: 1;\n}\n.txValue {\n display: none;\n flex: 0 0 auto;\n line-height: 1.25;\n}\n.txOutputs {\n display: flex;\n flex-wrap: nowrap;\n flex-direction: row;\n align-content: stretch;\n}\n.txOut {\n position: relative;\n flex: 1 1 auto;\n background-color: white;\n}\n.txOut:first {\n border-left: 3px solid black;\n}\n.txOut:after {\n content: '';\n width: 3px;\n background: black;\n position: absolute;\n right: 0;\n top: 0;\n bottom: 0;\n}\n.blockDivider {\n display: block;\n margin: 1em -1em -1.5em;\n background: linear-gradient(to top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.125));\n padding: 0.125em 1em 1.5em;\n color: rgba(0, 0, 0, 0);\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.blockDivider:hover,\n.blockDivider:focus {\n color: inherit;\n}\n#muteToggle,\n#connectionStatus {\n position: fixed;\n top: 0;\n width: 8em;\n background: white;\n border: solid black;\n padding: 0.5em;\n font-size: 0.8em;\n text-transform: uppercase;\n font-weight: bold;\n text-align: center;\n color: black;\n}\n#muteToggle {\n left: 0;\n border-radius: 0 0 0.5em 0;\n border-width: 0 0.1em 0.1em 0;\n transition: opacity 0.5s;\n transition-delay: 1s;\n opacity: 0;\n cursor: pointer;\n z-index: 100;\n}\n#muteToggle:hover {\n opacity: 1;\n transition-delay: 0s;\n}\n#muteToggle:before {\n content: 'Mute';\n}\n#muteToggle.is-muted:before {\n content: 'Un-mute';\n}\n#connectionStatus {\n right: 0;\n border-radius: 0 0 0 0.5em;\n border-width: 0 0 0.1em 0.1em;\n transition: transform 0.5s;\n transform: none;\n}\n#connectionStatus.is-disconnected:before {\n content: 'Disconnected';\n color: red;\n}\n#connectionStatus.is-connecting:before {\n content: 'Connecting...';\n color: black;\n}\n#connectionStatus.is-connected:before {\n content: 'Connected';\n color: green;\n}\n#connectionStatus.is-connected {\n transition: transform 0.5s;\n transition-delay: 2s;\n transform: translate3d(0, -100%, 0);\n}\n"]} \ No newline at end of file diff --git a/bundle.js b/bundle.js new file mode 100644 index 0000000..7dc11e1 --- /dev/null +++ b/bundle.js @@ -0,0 +1,6904 @@ +(function() { + 'use strict'; + + var globals = typeof global === 'undefined' ? self : global; + if (typeof globals.require === 'function') return; + + var modules = {}; + var cache = {}; + var aliases = {}; + var has = {}.hasOwnProperty; + + var expRe = /^\.\.?(\/|$)/; + var expand = function(root, name) { + var results = [], part; + var parts = (expRe.test(name) ? root + '/' + name : name).split('/'); + for (var i = 0, length = parts.length; i < length; i++) { + part = parts[i]; + if (part === '..') { + results.pop(); + } else if (part !== '.' && part !== '') { + results.push(part); + } + } + return results.join('/'); + }; + + var dirname = function(path) { + return path.split('/').slice(0, -1).join('/'); + }; + + var localRequire = function(path) { + return function expanded(name) { + var absolute = expand(dirname(path), name); + return globals.require(absolute, path); + }; + }; + + var initModule = function(name, definition) { + var hot = hmr && hmr.createHot(name); + var module = {id: name, exports: {}, hot: hot}; + cache[name] = module; + definition(module.exports, localRequire(name), module); + return module.exports; + }; + + var expandAlias = function(name) { + return aliases[name] ? expandAlias(aliases[name]) : name; + }; + + var _resolve = function(name, dep) { + return expandAlias(expand(dirname(name), dep)); + }; + + var require = function(name, loaderPath) { + if (loaderPath == null) loaderPath = '/'; + var path = expandAlias(name); + + if (has.call(cache, path)) return cache[path].exports; + if (has.call(modules, path)) return initModule(path, modules[path]); + + throw new Error("Cannot find module '" + name + "' from '" + loaderPath + "'"); + }; + + require.alias = function(from, to) { + aliases[to] = from; + }; + + var extRe = /\.[^.\/]+$/; + var indexRe = /\/index(\.[^\/]+)?$/; + var addExtensions = function(bundle) { + if (extRe.test(bundle)) { + var alias = bundle.replace(extRe, ''); + if (!has.call(aliases, alias) || aliases[alias].replace(extRe, '') === alias + '/index') { + aliases[alias] = bundle; + } + } + + if (indexRe.test(bundle)) { + var iAlias = bundle.replace(indexRe, ''); + if (!has.call(aliases, iAlias)) { + aliases[iAlias] = bundle; + } + } + }; + + require.register = require.define = function(bundle, fn) { + if (bundle && typeof bundle === 'object') { + for (var key in bundle) { + if (has.call(bundle, key)) { + require.register(key, bundle[key]); + } + } + } else { + modules[bundle] = fn; + delete cache[bundle]; + addExtensions(bundle); + } + }; + + require.list = function() { + var list = []; + for (var item in modules) { + if (has.call(modules, item)) { + list.push(item); + } + } + return list; + }; + + var hmr = globals._hmr && new globals._hmr(_resolve, require, modules, cache); + require._cache = cache; + require.hmr = hmr && hmr.wrap; + require.brunch = true; + globals.require = require; +})(); + +(function() { +var global = typeof window === 'undefined' ? this : window; +var process; +var __makeRelativeRequire = function(require, mappings, pref) { + var none = {}; + var tryReq = function(name, pref) { + var val; + try { + val = require(pref + '/node_modules/' + name); + return val; + } catch (e) { + if (e.toString().indexOf('Cannot find module') === -1) { + throw e; + } + + if (pref.indexOf('node_modules') !== -1) { + var s = pref.split('/'); + var i = s.lastIndexOf('node_modules'); + var newPref = s.slice(0, i).join('/'); + return tryReq(name, newPref); + } + } + return none; + }; + return function(name) { + if (name in mappings) name = mappings[name]; + if (!name) return; + if (name[0] !== '.' && pref) { + var val = tryReq(name, pref); + if (val !== none) return val; + } + return require(name); + } +}; + +require.register("after/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "after"); + (function() { + module.exports = after + +function after(count, callback, err_cb) { + var bail = false + err_cb = err_cb || noop + proxy.count = count + + return (count === 0) ? callback() : proxy + + function proxy(err, result) { + if (proxy.count <= 0) { + throw new Error('after called too many times') + } + --proxy.count + + // after first error, rest are passed to err_cb + if (err) { + bail = true + callback(err) + // future error callbacks will go to error handler + callback = err_cb + } else if (proxy.count === 0 && !bail) { + callback(null, result) + } + } +} + +function noop() {} + })(); +}); + +require.register("arraybuffer.slice/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "arraybuffer.slice"); + (function() { + /** + * An abstraction for slicing an arraybuffer even when + * ArrayBuffer.prototype.slice is not supported + * + * @api public + */ + +module.exports = function(arraybuffer, start, end) { + var bytes = arraybuffer.byteLength; + start = start || 0; + end = end || bytes; + + if (arraybuffer.slice) { return arraybuffer.slice(start, end); } + + if (start < 0) { start += bytes; } + if (end < 0) { end += bytes; } + if (end > bytes) { end = bytes; } + + if (start >= bytes || start >= end || bytes === 0) { + return new ArrayBuffer(0); + } + + var abv = new Uint8Array(arraybuffer); + var result = new Uint8Array(end - start); + for (var i = start, ii = 0; i < end; i++, ii++) { + result[ii] = abv[i]; + } + return result.buffer; +}; + })(); +}); + +require.register("backo2/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "backo2"); + (function() { + /** + * Expose `Backoff`. + */ + +module.exports = Backoff; + +/** + * Initialize backoff timer with `opts`. + * + * - `min` initial timeout in milliseconds [100] + * - `max` max timeout [10000] + * - `jitter` [0] + * - `factor` [2] + * + * @param {Object} opts + * @api public + */ + +function Backoff(opts) { + opts = opts || {}; + this.ms = opts.min || 100; + this.max = opts.max || 10000; + this.factor = opts.factor || 2; + this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0; + this.attempts = 0; +} + +/** + * Return the backoff duration. + * + * @return {Number} + * @api public + */ + +Backoff.prototype.duration = function(){ + var ms = this.ms * Math.pow(this.factor, this.attempts++); + if (this.jitter) { + var rand = Math.random(); + var deviation = Math.floor(rand * this.jitter * ms); + ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation; + } + return Math.min(ms, this.max) | 0; +}; + +/** + * Reset the number of attempts. + * + * @api public + */ + +Backoff.prototype.reset = function(){ + this.attempts = 0; +}; + +/** + * Set the minimum duration + * + * @api public + */ + +Backoff.prototype.setMin = function(min){ + this.ms = min; +}; + +/** + * Set the maximum duration + * + * @api public + */ + +Backoff.prototype.setMax = function(max){ + this.max = max; +}; + +/** + * Set the jitter + * + * @api public + */ + +Backoff.prototype.setJitter = function(jitter){ + this.jitter = jitter; +}; + })(); +}); + +require.register("base64-arraybuffer/lib/base64-arraybuffer.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "base64-arraybuffer"); + (function() { + /* + * base64-arraybuffer + * https://github.com/niklasvh/base64-arraybuffer + * + * Copyright (c) 2012 Niklas von Hertzen + * Licensed under the MIT license. + */ +(function(){ + "use strict"; + + var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + // Use a lookup table to find the index. + var lookup = new Uint8Array(256); + for (var i = 0; i < chars.length; i++) { + lookup[chars.charCodeAt(i)] = i; + } + + exports.encode = function(arraybuffer) { + var bytes = new Uint8Array(arraybuffer), + i, len = bytes.length, base64 = ""; + + for (i = 0; i < len; i+=3) { + base64 += chars[bytes[i] >> 2]; + base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; + base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; + base64 += chars[bytes[i + 2] & 63]; + } + + if ((len % 3) === 2) { + base64 = base64.substring(0, base64.length - 1) + "="; + } else if (len % 3 === 1) { + base64 = base64.substring(0, base64.length - 2) + "=="; + } + + return base64; + }; + + exports.decode = function(base64) { + var bufferLength = base64.length * 0.75, + len = base64.length, i, p = 0, + encoded1, encoded2, encoded3, encoded4; + + if (base64[base64.length - 1] === "=") { + bufferLength--; + if (base64[base64.length - 2] === "=") { + bufferLength--; + } + } + + var arraybuffer = new ArrayBuffer(bufferLength), + bytes = new Uint8Array(arraybuffer); + + for (i = 0; i < len; i+=4) { + encoded1 = lookup[base64.charCodeAt(i)]; + encoded2 = lookup[base64.charCodeAt(i+1)]; + encoded3 = lookup[base64.charCodeAt(i+2)]; + encoded4 = lookup[base64.charCodeAt(i+3)]; + + bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); + bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); + bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); + } + + return arraybuffer; + }; +})(); + })(); +}); + +require.register("blob/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "blob"); + (function() { + /** + * Create a blob builder even when vendor prefixes exist + */ + +var BlobBuilder = global.BlobBuilder + || global.WebKitBlobBuilder + || global.MSBlobBuilder + || global.MozBlobBuilder; + +/** + * Check if Blob constructor is supported + */ + +var blobSupported = (function() { + try { + var a = new Blob(['hi']); + return a.size === 2; + } catch(e) { + return false; + } +})(); + +/** + * Check if Blob constructor supports ArrayBufferViews + * Fails in Safari 6, so we need to map to ArrayBuffers there. + */ + +var blobSupportsArrayBufferView = blobSupported && (function() { + try { + var b = new Blob([new Uint8Array([1,2])]); + return b.size === 2; + } catch(e) { + return false; + } +})(); + +/** + * Check if BlobBuilder is supported + */ + +var blobBuilderSupported = BlobBuilder + && BlobBuilder.prototype.append + && BlobBuilder.prototype.getBlob; + +/** + * Helper function that maps ArrayBufferViews to ArrayBuffers + * Used by BlobBuilder constructor and old browsers that didn't + * support it in the Blob constructor. + */ + +function mapArrayBufferViews(ary) { + for (var i = 0; i < ary.length; i++) { + var chunk = ary[i]; + if (chunk.buffer instanceof ArrayBuffer) { + var buf = chunk.buffer; + + // if this is a subarray, make a copy so we only + // include the subarray region from the underlying buffer + if (chunk.byteLength !== buf.byteLength) { + var copy = new Uint8Array(chunk.byteLength); + copy.set(new Uint8Array(buf, chunk.byteOffset, chunk.byteLength)); + buf = copy.buffer; + } + + ary[i] = buf; + } + } +} + +function BlobBuilderConstructor(ary, options) { + options = options || {}; + + var bb = new BlobBuilder(); + mapArrayBufferViews(ary); + + for (var i = 0; i < ary.length; i++) { + bb.append(ary[i]); + } + + return (options.type) ? bb.getBlob(options.type) : bb.getBlob(); +}; + +function BlobConstructor(ary, options) { + mapArrayBufferViews(ary); + return new Blob(ary, options || {}); +}; + +module.exports = (function() { + if (blobSupported) { + return blobSupportsArrayBufferView ? global.Blob : BlobConstructor; + } else if (blobBuilderSupported) { + return BlobBuilderConstructor; + } else { + return undefined; + } +})(); + })(); +}); + +require.register("browser-resolve/empty.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "browser-resolve"); + (function() { + + })(); +}); + +require.register("component-bind/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "component-bind"); + (function() { + /** + * Slice reference. + */ + +var slice = [].slice; + +/** + * Bind `obj` to `fn`. + * + * @param {Object} obj + * @param {Function|String} fn or string + * @return {Function} + * @api public + */ + +module.exports = function(obj, fn){ + if ('string' == typeof fn) fn = obj[fn]; + if ('function' != typeof fn) throw new Error('bind() requires a function'); + var args = slice.call(arguments, 2); + return function(){ + return fn.apply(obj, args.concat(slice.call(arguments))); + } +}; + })(); +}); + +require.register("component-emitter/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "component-emitter"); + (function() { + /** + * Expose `Emitter`. + */ + +if (typeof module !== 'undefined') { + module.exports = Emitter; +} + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +}; + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = +Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks['$' + event] = this._callbacks['$' + event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + function on() { + this.off(event, on); + fn.apply(this, arguments); + } + + on.fn = fn; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = +Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks['$' + event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks['$' + event]; + return this; + } + + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; + } + } + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks['$' + event]; + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks['$' + event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; + })(); +}); + +require.register("component-inherit/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "component-inherit"); + (function() { + module.exports = function(a, b){ + var fn = function(){}; + fn.prototype = b.prototype; + a.prototype = new fn; + a.prototype.constructor = a; +}; + })(); +}); + +require.register("debug/src/browser.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "debug"); + (function() { + /** + * This is the web browser implementation of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = require('./debug'); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); + +/** + * Colors. + */ + +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; + } + + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } +}; + + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + var useColors = this.useColors; + + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); + + if (!useColors) return; + + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') + + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ + +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); +} + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ + +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + return window.localStorage; + } catch (e) {} +} + })(); +}); + +require.register("debug/src/debug.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {}, "debug"); + (function() { + /** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = require('ms'); + +/** + * The currently active debug mode names, and names to skip. + */ + +exports.names = []; +exports.skips = []; + +/** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + +exports.formatters = {}; + +/** + * Previous log timestamp. + */ + +var prevTime; + +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ + +function selectColor(namespace) { + var hash = 0, i; + + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return exports.colors[Math.abs(hash) % exports.colors.length]; +} + +/** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + +function createDebug(namespace) { + + function debug() { + // disabled? + if (!debug.enabled) return; + + var self = debug; + + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + args[0] = exports.coerce(args[0]); + + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); + } + + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); + + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); + + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); + } + + return debug; +} + +/** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + +function enable(namespaces) { + exports.save(namespaces); + + exports.names = []; + exports.skips = []; + + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} + +/** + * Disable debug output. + * + * @api public + */ + +function disable() { + exports.enable(''); +} + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } + } + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } + } + return false; +} + +/** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + })(); +}); + +require.register("engine.io-client/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {"ws":false,"xmlhttprequest-ssl":"engine.io-client/lib/xmlhttprequest"}, "engine.io-client"); + (function() { + module.exports = require('./lib/index'); + })(); +}); + +require.register("engine.io-client/lib/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {"ws":false,"xmlhttprequest-ssl":"engine.io-client/lib/xmlhttprequest"}, "engine.io-client"); + (function() { + module.exports = require('./socket'); + +/** + * Exports parser + * + * @api public + * + */ +module.exports.parser = require('engine.io-parser'); + })(); +}); + +require.register("engine.io-client/lib/socket.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {"ws":false,"xmlhttprequest-ssl":"engine.io-client/lib/xmlhttprequest"}, "engine.io-client"); + (function() { + /** + * Module dependencies. + */ + +var transports = require('./transports/index'); +var Emitter = require('component-emitter'); +var debug = require('debug')('engine.io-client:socket'); +var index = require('indexof'); +var parser = require('engine.io-parser'); +var parseuri = require('parseuri'); +var parsejson = require('parsejson'); +var parseqs = require('parseqs'); + +/** + * Module exports. + */ + +module.exports = Socket; + +/** + * Socket constructor. + * + * @param {String|Object} uri or options + * @param {Object} options + * @api public + */ + +function Socket (uri, opts) { + if (!(this instanceof Socket)) return new Socket(uri, opts); + + opts = opts || {}; + + if (uri && 'object' === typeof uri) { + opts = uri; + uri = null; + } + + if (uri) { + uri = parseuri(uri); + opts.hostname = uri.host; + opts.secure = uri.protocol === 'https' || uri.protocol === 'wss'; + opts.port = uri.port; + if (uri.query) opts.query = uri.query; + } else if (opts.host) { + opts.hostname = parseuri(opts.host).host; + } + + this.secure = null != opts.secure ? opts.secure + : (global.location && 'https:' === location.protocol); + + if (opts.hostname && !opts.port) { + // if no port is specified manually, use the protocol default + opts.port = this.secure ? '443' : '80'; + } + + this.agent = opts.agent || false; + this.hostname = opts.hostname || + (global.location ? location.hostname : 'localhost'); + this.port = opts.port || (global.location && location.port + ? location.port + : (this.secure ? 443 : 80)); + this.query = opts.query || {}; + if ('string' === typeof this.query) this.query = parseqs.decode(this.query); + this.upgrade = false !== opts.upgrade; + this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/'; + this.forceJSONP = !!opts.forceJSONP; + this.jsonp = false !== opts.jsonp; + this.forceBase64 = !!opts.forceBase64; + this.enablesXDR = !!opts.enablesXDR; + this.timestampParam = opts.timestampParam || 't'; + this.timestampRequests = opts.timestampRequests; + this.transports = opts.transports || ['polling', 'websocket']; + this.transportOptions = opts.transportOptions || {}; + this.readyState = ''; + this.writeBuffer = []; + this.prevBufferLen = 0; + this.policyPort = opts.policyPort || 843; + this.rememberUpgrade = opts.rememberUpgrade || false; + this.binaryType = null; + this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades; + this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || {}) : false; + + if (true === this.perMessageDeflate) this.perMessageDeflate = {}; + if (this.perMessageDeflate && null == this.perMessageDeflate.threshold) { + this.perMessageDeflate.threshold = 1024; + } + + // SSL options for Node.js client + this.pfx = opts.pfx || null; + this.key = opts.key || null; + this.passphrase = opts.passphrase || null; + this.cert = opts.cert || null; + this.ca = opts.ca || null; + this.ciphers = opts.ciphers || null; + this.rejectUnauthorized = opts.rejectUnauthorized === undefined ? true : opts.rejectUnauthorized; + this.forceNode = !!opts.forceNode; + + // other options for Node.js client + var freeGlobal = typeof global === 'object' && global; + if (freeGlobal.global === freeGlobal) { + if (opts.extraHeaders && Object.keys(opts.extraHeaders).length > 0) { + this.extraHeaders = opts.extraHeaders; + } + + if (opts.localAddress) { + this.localAddress = opts.localAddress; + } + } + + // set on handshake + this.id = null; + this.upgrades = null; + this.pingInterval = null; + this.pingTimeout = null; + + // set on heartbeat + this.pingIntervalTimer = null; + this.pingTimeoutTimer = null; + + this.open(); +} + +Socket.priorWebsocketSuccess = false; + +/** + * Mix in `Emitter`. + */ + +Emitter(Socket.prototype); + +/** + * Protocol version. + * + * @api public + */ + +Socket.protocol = parser.protocol; // this is an int + +/** + * Expose deps for legacy compatibility + * and standalone browser access. + */ + +Socket.Socket = Socket; +Socket.Transport = require('./transport'); +Socket.transports = require('./transports/index'); +Socket.parser = require('engine.io-parser'); + +/** + * Creates transport of the given type. + * + * @param {String} transport name + * @return {Transport} + * @api private + */ + +Socket.prototype.createTransport = function (name) { + debug('creating transport "%s"', name); + var query = clone(this.query); + + // append engine.io protocol identifier + query.EIO = parser.protocol; + + // transport name + query.transport = name; + + // per-transport options + var options = this.transportOptions[name] || {}; + + // session id if we already have one + if (this.id) query.sid = this.id; + + var transport = new transports[name]({ + query: query, + socket: this, + agent: options.agent || this.agent, + hostname: options.hostname || this.hostname, + port: options.port || this.port, + secure: options.secure || this.secure, + path: options.path || this.path, + forceJSONP: options.forceJSONP || this.forceJSONP, + jsonp: options.jsonp || this.jsonp, + forceBase64: options.forceBase64 || this.forceBase64, + enablesXDR: options.enablesXDR || this.enablesXDR, + timestampRequests: options.timestampRequests || this.timestampRequests, + timestampParam: options.timestampParam || this.timestampParam, + policyPort: options.policyPort || this.policyPort, + pfx: options.pfx || this.pfx, + key: options.key || this.key, + passphrase: options.passphrase || this.passphrase, + cert: options.cert || this.cert, + ca: options.ca || this.ca, + ciphers: options.ciphers || this.ciphers, + rejectUnauthorized: options.rejectUnauthorized || this.rejectUnauthorized, + perMessageDeflate: options.perMessageDeflate || this.perMessageDeflate, + extraHeaders: options.extraHeaders || this.extraHeaders, + forceNode: options.forceNode || this.forceNode, + localAddress: options.localAddress || this.localAddress, + requestTimeout: options.requestTimeout || this.requestTimeout, + protocols: options.protocols || void (0) + }); + + return transport; +}; + +function clone (obj) { + var o = {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + o[i] = obj[i]; + } + } + return o; +} + +/** + * Initializes transport to use and starts probe. + * + * @api private + */ +Socket.prototype.open = function () { + var transport; + if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') !== -1) { + transport = 'websocket'; + } else if (0 === this.transports.length) { + // Emit error on next tick so it can be listened to + var self = this; + setTimeout(function () { + self.emit('error', 'No transports available'); + }, 0); + return; + } else { + transport = this.transports[0]; + } + this.readyState = 'opening'; + + // Retry with the next transport if the transport is disabled (jsonp: false) + try { + transport = this.createTransport(transport); + } catch (e) { + this.transports.shift(); + this.open(); + return; + } + + transport.open(); + this.setTransport(transport); +}; + +/** + * Sets the current transport. Disables the existing one (if any). + * + * @api private + */ + +Socket.prototype.setTransport = function (transport) { + debug('setting transport %s', transport.name); + var self = this; + + if (this.transport) { + debug('clearing existing transport %s', this.transport.name); + this.transport.removeAllListeners(); + } + + // set up transport + this.transport = transport; + + // set up transport listeners + transport + .on('drain', function () { + self.onDrain(); + }) + .on('packet', function (packet) { + self.onPacket(packet); + }) + .on('error', function (e) { + self.onError(e); + }) + .on('close', function () { + self.onClose('transport close'); + }); +}; + +/** + * Probes a transport. + * + * @param {String} transport name + * @api private + */ + +Socket.prototype.probe = function (name) { + debug('probing transport "%s"', name); + var transport = this.createTransport(name, { probe: 1 }); + var failed = false; + var self = this; + + Socket.priorWebsocketSuccess = false; + + function onTransportOpen () { + if (self.onlyBinaryUpgrades) { + var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary; + failed = failed || upgradeLosesBinary; + } + if (failed) return; + + debug('probe transport "%s" opened', name); + transport.send([{ type: 'ping', data: 'probe' }]); + transport.once('packet', function (msg) { + if (failed) return; + if ('pong' === msg.type && 'probe' === msg.data) { + debug('probe transport "%s" pong', name); + self.upgrading = true; + self.emit('upgrading', transport); + if (!transport) return; + Socket.priorWebsocketSuccess = 'websocket' === transport.name; + + debug('pausing current transport "%s"', self.transport.name); + self.transport.pause(function () { + if (failed) return; + if ('closed' === self.readyState) return; + debug('changing transport and sending upgrade packet'); + + cleanup(); + + self.setTransport(transport); + transport.send([{ type: 'upgrade' }]); + self.emit('upgrade', transport); + transport = null; + self.upgrading = false; + self.flush(); + }); + } else { + debug('probe transport "%s" failed', name); + var err = new Error('probe error'); + err.transport = transport.name; + self.emit('upgradeError', err); + } + }); + } + + function freezeTransport () { + if (failed) return; + + // Any callback called by transport should be ignored since now + failed = true; + + cleanup(); + + transport.close(); + transport = null; + } + + // Handle any error that happens while probing + function onerror (err) { + var error = new Error('probe error: ' + err); + error.transport = transport.name; + + freezeTransport(); + + debug('probe transport "%s" failed because of error: %s', name, err); + + self.emit('upgradeError', error); + } + + function onTransportClose () { + onerror('transport closed'); + } + + // When the socket is closed while we're probing + function onclose () { + onerror('socket closed'); + } + + // When the socket is upgraded while we're probing + function onupgrade (to) { + if (transport && to.name !== transport.name) { + debug('"%s" works - aborting "%s"', to.name, transport.name); + freezeTransport(); + } + } + + // Remove all listeners on the transport and on self + function cleanup () { + transport.removeListener('open', onTransportOpen); + transport.removeListener('error', onerror); + transport.removeListener('close', onTransportClose); + self.removeListener('close', onclose); + self.removeListener('upgrading', onupgrade); + } + + transport.once('open', onTransportOpen); + transport.once('error', onerror); + transport.once('close', onTransportClose); + + this.once('close', onclose); + this.once('upgrading', onupgrade); + + transport.open(); +}; + +/** + * Called when connection is deemed open. + * + * @api public + */ + +Socket.prototype.onOpen = function () { + debug('socket open'); + this.readyState = 'open'; + Socket.priorWebsocketSuccess = 'websocket' === this.transport.name; + this.emit('open'); + this.flush(); + + // we check for `readyState` in case an `open` + // listener already closed the socket + if ('open' === this.readyState && this.upgrade && this.transport.pause) { + debug('starting upgrade probes'); + for (var i = 0, l = this.upgrades.length; i < l; i++) { + this.probe(this.upgrades[i]); + } + } +}; + +/** + * Handles a packet. + * + * @api private + */ + +Socket.prototype.onPacket = function (packet) { + if ('opening' === this.readyState || 'open' === this.readyState || + 'closing' === this.readyState) { + debug('socket receive: type "%s", data "%s"', packet.type, packet.data); + + this.emit('packet', packet); + + // Socket is live - any packet counts + this.emit('heartbeat'); + + switch (packet.type) { + case 'open': + this.onHandshake(parsejson(packet.data)); + break; + + case 'pong': + this.setPing(); + this.emit('pong'); + break; + + case 'error': + var err = new Error('server error'); + err.code = packet.data; + this.onError(err); + break; + + case 'message': + this.emit('data', packet.data); + this.emit('message', packet.data); + break; + } + } else { + debug('packet received with socket readyState "%s"', this.readyState); + } +}; + +/** + * Called upon handshake completion. + * + * @param {Object} handshake obj + * @api private + */ + +Socket.prototype.onHandshake = function (data) { + this.emit('handshake', data); + this.id = data.sid; + this.transport.query.sid = data.sid; + this.upgrades = this.filterUpgrades(data.upgrades); + this.pingInterval = data.pingInterval; + this.pingTimeout = data.pingTimeout; + this.onOpen(); + // In case open handler closes socket + if ('closed' === this.readyState) return; + this.setPing(); + + // Prolong liveness of socket on heartbeat + this.removeListener('heartbeat', this.onHeartbeat); + this.on('heartbeat', this.onHeartbeat); +}; + +/** + * Resets ping timeout. + * + * @api private + */ + +Socket.prototype.onHeartbeat = function (timeout) { + clearTimeout(this.pingTimeoutTimer); + var self = this; + self.pingTimeoutTimer = setTimeout(function () { + if ('closed' === self.readyState) return; + self.onClose('ping timeout'); + }, timeout || (self.pingInterval + self.pingTimeout)); +}; + +/** + * Pings server every `this.pingInterval` and expects response + * within `this.pingTimeout` or closes connection. + * + * @api private + */ + +Socket.prototype.setPing = function () { + var self = this; + clearTimeout(self.pingIntervalTimer); + self.pingIntervalTimer = setTimeout(function () { + debug('writing ping packet - expecting pong within %sms', self.pingTimeout); + self.ping(); + self.onHeartbeat(self.pingTimeout); + }, self.pingInterval); +}; + +/** +* Sends a ping packet. +* +* @api private +*/ + +Socket.prototype.ping = function () { + var self = this; + this.sendPacket('ping', function () { + self.emit('ping'); + }); +}; + +/** + * Called on `drain` event + * + * @api private + */ + +Socket.prototype.onDrain = function () { + this.writeBuffer.splice(0, this.prevBufferLen); + + // setting prevBufferLen = 0 is very important + // for example, when upgrading, upgrade packet is sent over, + // and a nonzero prevBufferLen could cause problems on `drain` + this.prevBufferLen = 0; + + if (0 === this.writeBuffer.length) { + this.emit('drain'); + } else { + this.flush(); + } +}; + +/** + * Flush write buffers. + * + * @api private + */ + +Socket.prototype.flush = function () { + if ('closed' !== this.readyState && this.transport.writable && + !this.upgrading && this.writeBuffer.length) { + debug('flushing %d packets in socket', this.writeBuffer.length); + this.transport.send(this.writeBuffer); + // keep track of current length of writeBuffer + // splice writeBuffer and callbackBuffer on `drain` + this.prevBufferLen = this.writeBuffer.length; + this.emit('flush'); + } +}; + +/** + * Sends a message. + * + * @param {String} message. + * @param {Function} callback function. + * @param {Object} options. + * @return {Socket} for chaining. + * @api public + */ + +Socket.prototype.write = +Socket.prototype.send = function (msg, options, fn) { + this.sendPacket('message', msg, options, fn); + return this; +}; + +/** + * Sends a packet. + * + * @param {String} packet type. + * @param {String} data. + * @param {Object} options. + * @param {Function} callback function. + * @api private + */ + +Socket.prototype.sendPacket = function (type, data, options, fn) { + if ('function' === typeof data) { + fn = data; + data = undefined; + } + + if ('function' === typeof options) { + fn = options; + options = null; + } + + if ('closing' === this.readyState || 'closed' === this.readyState) { + return; + } + + options = options || {}; + options.compress = false !== options.compress; + + var packet = { + type: type, + data: data, + options: options + }; + this.emit('packetCreate', packet); + this.writeBuffer.push(packet); + if (fn) this.once('flush', fn); + this.flush(); +}; + +/** + * Closes the connection. + * + * @api private + */ + +Socket.prototype.close = function () { + if ('opening' === this.readyState || 'open' === this.readyState) { + this.readyState = 'closing'; + + var self = this; + + if (this.writeBuffer.length) { + this.once('drain', function () { + if (this.upgrading) { + waitForUpgrade(); + } else { + close(); + } + }); + } else if (this.upgrading) { + waitForUpgrade(); + } else { + close(); + } + } + + function close () { + self.onClose('forced close'); + debug('socket closing - telling transport to close'); + self.transport.close(); + } + + function cleanupAndClose () { + self.removeListener('upgrade', cleanupAndClose); + self.removeListener('upgradeError', cleanupAndClose); + close(); + } + + function waitForUpgrade () { + // wait for upgrade to finish since we can't send packets while pausing a transport + self.once('upgrade', cleanupAndClose); + self.once('upgradeError', cleanupAndClose); + } + + return this; +}; + +/** + * Called upon transport error + * + * @api private + */ + +Socket.prototype.onError = function (err) { + debug('socket error %j', err); + Socket.priorWebsocketSuccess = false; + this.emit('error', err); + this.onClose('transport error', err); +}; + +/** + * Called upon transport close. + * + * @api private + */ + +Socket.prototype.onClose = function (reason, desc) { + if ('opening' === this.readyState || 'open' === this.readyState || 'closing' === this.readyState) { + debug('socket close with reason: "%s"', reason); + var self = this; + + // clear timers + clearTimeout(this.pingIntervalTimer); + clearTimeout(this.pingTimeoutTimer); + + // stop event from firing again for transport + this.transport.removeAllListeners('close'); + + // ensure transport won't stay open + this.transport.close(); + + // ignore further transport communication + this.transport.removeAllListeners(); + + // set ready state + this.readyState = 'closed'; + + // clear session id + this.id = null; + + // emit close event + this.emit('close', reason, desc); + + // clean buffers after, so users can still + // grab the buffers on `close` event + self.writeBuffer = []; + self.prevBufferLen = 0; + } +}; + +/** + * Filters upgrades, returning only those matching client transports. + * + * @param {Array} server upgrades + * @api private + * + */ + +Socket.prototype.filterUpgrades = function (upgrades) { + var filteredUpgrades = []; + for (var i = 0, j = upgrades.length; i < j; i++) { + if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]); + } + return filteredUpgrades; +}; + })(); +}); + +require.register("engine.io-client/lib/transport.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {"ws":false,"xmlhttprequest-ssl":"engine.io-client/lib/xmlhttprequest"}, "engine.io-client"); + (function() { + /** + * Module dependencies. + */ + +var parser = require('engine.io-parser'); +var Emitter = require('component-emitter'); + +/** + * Module exports. + */ + +module.exports = Transport; + +/** + * Transport abstract constructor. + * + * @param {Object} options. + * @api private + */ + +function Transport (opts) { + this.path = opts.path; + this.hostname = opts.hostname; + this.port = opts.port; + this.secure = opts.secure; + this.query = opts.query; + this.timestampParam = opts.timestampParam; + this.timestampRequests = opts.timestampRequests; + this.readyState = ''; + this.agent = opts.agent || false; + this.socket = opts.socket; + this.enablesXDR = opts.enablesXDR; + + // SSL options for Node.js client + this.pfx = opts.pfx; + this.key = opts.key; + this.passphrase = opts.passphrase; + this.cert = opts.cert; + this.ca = opts.ca; + this.ciphers = opts.ciphers; + this.rejectUnauthorized = opts.rejectUnauthorized; + this.forceNode = opts.forceNode; + + // other options for Node.js client + this.extraHeaders = opts.extraHeaders; + this.localAddress = opts.localAddress; +} + +/** + * Mix in `Emitter`. + */ + +Emitter(Transport.prototype); + +/** + * Emits an error. + * + * @param {String} str + * @return {Transport} for chaining + * @api public + */ + +Transport.prototype.onError = function (msg, desc) { + var err = new Error(msg); + err.type = 'TransportError'; + err.description = desc; + this.emit('error', err); + return this; +}; + +/** + * Opens the transport. + * + * @api public + */ + +Transport.prototype.open = function () { + if ('closed' === this.readyState || '' === this.readyState) { + this.readyState = 'opening'; + this.doOpen(); + } + + return this; +}; + +/** + * Closes the transport. + * + * @api private + */ + +Transport.prototype.close = function () { + if ('opening' === this.readyState || 'open' === this.readyState) { + this.doClose(); + this.onClose(); + } + + return this; +}; + +/** + * Sends multiple packets. + * + * @param {Array} packets + * @api private + */ + +Transport.prototype.send = function (packets) { + if ('open' === this.readyState) { + this.write(packets); + } else { + throw new Error('Transport not open'); + } +}; + +/** + * Called upon open + * + * @api private + */ + +Transport.prototype.onOpen = function () { + this.readyState = 'open'; + this.writable = true; + this.emit('open'); +}; + +/** + * Called with data. + * + * @param {String} data + * @api private + */ + +Transport.prototype.onData = function (data) { + var packet = parser.decodePacket(data, this.socket.binaryType); + this.onPacket(packet); +}; + +/** + * Called with a decoded packet. + */ + +Transport.prototype.onPacket = function (packet) { + this.emit('packet', packet); +}; + +/** + * Called upon close. + * + * @api private + */ + +Transport.prototype.onClose = function () { + this.readyState = 'closed'; + this.emit('close'); +}; + })(); +}); + +require.register("engine.io-client/lib/transports/index.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {"ws":false,"xmlhttprequest-ssl":"engine.io-client/lib/xmlhttprequest"}, "engine.io-client"); + (function() { + /** + * Module dependencies + */ + +var XMLHttpRequest = require('xmlhttprequest-ssl'); +var XHR = require('./polling-xhr'); +var JSONP = require('./polling-jsonp'); +var websocket = require('./websocket'); + +/** + * Export transports. + */ + +exports.polling = polling; +exports.websocket = websocket; + +/** + * Polling transport polymorphic constructor. + * Decides on xhr vs jsonp based on feature detection. + * + * @api private + */ + +function polling (opts) { + var xhr; + var xd = false; + var xs = false; + var jsonp = false !== opts.jsonp; + + if (global.location) { + var isSSL = 'https:' === location.protocol; + var port = location.port; + + // some user agents have empty `location.port` + if (!port) { + port = isSSL ? 443 : 80; + } + + xd = opts.hostname !== location.hostname || port !== opts.port; + xs = opts.secure !== isSSL; + } + + opts.xdomain = xd; + opts.xscheme = xs; + xhr = new XMLHttpRequest(opts); + + if ('open' in xhr && !opts.forceJSONP) { + return new XHR(opts); + } else { + if (!jsonp) throw new Error('JSONP disabled'); + return new JSONP(opts); + } +} + })(); +}); + +require.register("engine.io-client/lib/transports/polling-jsonp.js", function(exports, require, module) { + require = __makeRelativeRequire(require, {"ws":false,"xmlhttprequest-ssl":"engine.io-client/lib/xmlhttprequest"}, "engine.io-client"); + (function() { + /** + * Module requirements. + */ + +var Polling = require('./polling'); +var inherit = require('component-inherit'); + +/** + * Module exports. + */ + +module.exports = JSONPPolling; + +/** + * Cached regular expressions. + */ + +var rNewline = /\n/g; +var rEscapedNewline = /\\n/g; + +/** + * Global JSONP callbacks. + */ + +var callbacks; + +/** + * Noop. + */ + +function empty () { } + +/** + * JSONP Polling constructor. + * + * @param {Object} opts. + * @api public + */ + +function JSONPPolling (opts) { + Polling.call(this, opts); + + this.query = this.query || {}; + + // define global callbacks array if not present + // we do this here (lazily) to avoid unneeded global pollution + if (!callbacks) { + // we need to consider multiple engines in the same page + if (!global.___eio) global.___eio = []; + callbacks = global.___eio; + } + + // callback identifier + this.index = callbacks.length; + + // add callback to jsonp global + var self = this; + callbacks.push(function (msg) { + self.onData(msg); + }); + + // append to query string + this.query.j = this.index; + + // prevent spurious errors from being emitted when the window is unloaded + if (global.document && global.addEventListener) { + global.addEventListener('beforeunload', function () { + if (self.script) self.script.onerror = empty; + }, false); + } +} + +/** + * Inherits from Polling. + */ + +inherit(JSONPPolling, Polling); + +/* + * JSONP only supports binary as base64 encoded strings + */ + +JSONPPolling.prototype.supportsBinary = false; + +/** + * Closes the socket. + * + * @api private + */ + +JSONPPolling.prototype.doClose = function () { + if (this.script) { + this.script.parentNode.removeChild(this.script); + this.script = null; + } + + if (this.form) { + this.form.parentNode.removeChild(this.form); + this.form = null; + this.iframe = null; + } + + Polling.prototype.doClose.call(this); +}; + +/** + * Starts a poll cycle. + * + * @api private + */ + +JSONPPolling.prototype.doPoll = function () { + var self = this; + var script = document.createElement('script'); + + if (this.script) { + this.script.parentNode.removeChild(this.script); + this.script = null; + } + + script.async = true; + script.src = this.uri(); + script.onerror = function (e) { + self.onError('jsonp poll error', e); + }; + + var insertAt = document.getElementsByTagName('script')[0]; + if (insertAt) { + insertAt.parentNode.insertBefore(script, insertAt); + } else { + (document.head || document.body).appendChild(script); + } + this.script = script; + + var isUAgecko = 'undefined' !== typeof navigator && /gecko/i.test(navigator.userAgent); + + if (isUAgecko) { + setTimeout(function () { + var iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + document.body.removeChild(iframe); + }, 100); + } +}; + +/** + * Writes with a hidden iframe. + * + * @param {String} data to send + * @param {Function} called upon flush. + * @api private + */ + +JSONPPolling.prototype.doWrite = function (data, fn) { + var self = this; + + if (!this.form) { + var form = document.createElement('form'); + var area = document.createElement('textarea'); + var id = this.iframeId = 'eio_iframe_' + this.index; + var iframe; + + form.className = 'socketio'; + form.style.position = 'absolute'; + form.style.top = '-1000px'; + form.style.left = '-1000px'; + form.target = id; + form.method = 'POST'; + form.setAttribute('accept-charset', 'utf-8'); + area.name = 'd'; + form.appendChild(area); + document.body.appendChild(form); + + this.form = form; + this.area = area; + } + + this.form.action = this.uri(); + + function complete () { + initIframe(); + fn(); + } + + function initIframe () { + if (self.iframe) { + try { + self.form.removeChild(self.iframe); + } catch (e) { + self.onError('jsonp polling iframe removal error', e); + } + } + + try { + // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) + var html = '