From 0d270c32be0177aa00d59ca40e19182c7cce115d Mon Sep 17 00:00:00 2001 From: Jordan Phillips Date: Mon, 8 Nov 2010 15:29:28 -0800 Subject: [PATCH] Add payload argument to connect javascript function, frame, and webhook Additional changes: - The CONNECTED frame is sent before any SUBSCRIBE frames generated by the auto_subscribe option of the connect webhook. - Only valid User options returned by the connect webhook are applied to the user, rather than all of the returned options. --- hookbox/js_src/hookbox.js | 15 ++++++++------- hookbox/protocol.py | 3 +-- hookbox/server.py | 19 ++++++++++++------- hookbox/static/hookbox.js | 2 +- hookbox/static/hookbox.min.js | 2 +- hookbox/static/hookbox.min.js.gz | Bin 14145 -> 14177 bytes hookbox/user.py | 3 +++ 7 files changed, 26 insertions(+), 18 deletions(-) diff --git a/hookbox/js_src/hookbox.js b/hookbox/js_src/hookbox.js index 8d2bbc9..227a164 100644 --- a/hookbox/js_src/hookbox.js +++ b/hookbox/js_src/hookbox.js @@ -7,11 +7,11 @@ exports.logging = logging; logger.setLevel(0); -exports.connect = function(url, cookieString) { +exports.connect = function(url, connectPayload, cookieString) { if (!url.match('/$')) { url = url + '/'; } - var p = new HookBoxProtocol(url, cookieString); + var p = new HookBoxProtocol(url, connectPayload, cookieString); if (window.WebSocket) { jsioConnect(p, 'websocket', {url: url.replace('http://', 'ws://') + 'ws' }); p.connectionLost = bind(p, '_connectionLost', 'websocket'); @@ -42,7 +42,6 @@ var Subscription = Class(function(supr) { this.onState = function(frame) {} this.frame = function(name, args) { - logger.debug('received frame', name, args); switch(name) { case 'PUBLISH': if (this.historySize) { @@ -106,13 +105,13 @@ var Subscription = Class(function(supr) { HookBoxProtocol = Class([RTJPProtocol], function(supr) { // Public api - this.onOpen = function() { } + this.onOpen = function(args) { } this.onClose = function(err, wasConnected) { } this.onError = function(args) { } this.onSubscribed = function(name, subscription) { } this.onUnsubscribed = function(subscription, args) { } this.onMessaged = function(args) {} - this.init = function(url, cookieString) { + this.init = function(url, connectPayload, cookieString) { supr(this, 'init', []); this.url = url; try { @@ -127,6 +126,7 @@ HookBoxProtocol = Class([RTJPProtocol], function(supr) { this._publishes = []; this._messages = []; this._errors = {}; + this._connectPayload = connectPayload; this.username = null; } @@ -158,10 +158,11 @@ HookBoxProtocol = Class([RTJPProtocol], function(supr) { this.connectionMade = function() { logger.debug('connectionMade'); this.transport.setEncoding('utf8'); - this.sendFrame('CONNECT', { cookie_string: this.cookieString }); + this.sendFrame('CONNECT', { cookie_string: this.cookieString, payload: JSON.stringify(this._connectPayload) }); } this.frameReceived = function(fId, fName, fArgs) { + logger.debug('received frame', fName, fArgs); switch(fName) { case 'MESSAGE': this.onMessaged(fArgs); @@ -182,7 +183,7 @@ HookBoxProtocol = Class([RTJPProtocol], function(supr) { this.message.apply(this, msg); } - this.onOpen(); + this.onOpen(fArgs); break; case 'SUBSCRIBE': if (fArgs.user == this.username) { diff --git a/hookbox/protocol.py b/hookbox/protocol.py index bb17672..7334f71 100644 --- a/hookbox/protocol.py +++ b/hookbox/protocol.py @@ -101,9 +101,8 @@ def frame_CONNECT(self, fid, fargs): self.cookie_string = fargs['cookie_string'] self.cookies = parse_cookies(fargs['cookie_string']) self.cookie_id = self.cookies.get(self.cookie_identifier, None) - self.server.connect(self) + self.server.connect(self, fargs.get('payload', 'null')) self.state = 'connected' - self.send_frame('CONNECTED', { 'name': self.user.get_name() }) def frame_SUBSCRIBE(self, fid, fargs): if self.state != 'connected': diff --git a/hookbox/server.py b/hookbox/server.py index 47adc82..ec7ed99 100644 --- a/hookbox/server.py +++ b/hookbox/server.py @@ -251,21 +251,26 @@ def http_request(self, path_name=None, cookie_string=None, form={}, full_path=No # def _webhook_error - def connect(self, conn): - form = { 'conn_id': conn.id } + def connect(self, conn, payload): + try: + decoded_payload = json.loads(payload) + except: + raise ExpectedException("Invalid json for payload") + form = { 'conn_id': conn.id, 'payload': json.dumps(decoded_payload) } success, options = self.http_request('connect', conn.get_cookie(), form, conn=conn) if not success: raise ExpectedException(options.get('error', 'Unauthorized')) - if 'name' not in options: + user_name = options.pop('name', None) + if not user_name: raise ExpectedException('Unauthorized (missing name parameter in server response)') + payload = options.pop('override_payload', payload) self.conns[conn.id] = conn - user = self.get_user(options['name']) - del options['name'] - user.update_options(**options) + user = self.get_user(user_name) + user.update_options(**user.extract_valid_options(options)) user.add_connection(conn) self.admin.user_event('connect', user.get_name(), conn.serialize()) self.admin.connection_event('connect', conn.id, conn.serialize()) - #print 'successfully connected', user.name + conn.send_frame('CONNECTED', { 'name': user.get_name(), 'payload': payload }) eventlet.spawn(self.maybe_auto_subscribe, user, options, conn=conn) def disconnect(self, conn): diff --git a/hookbox/static/hookbox.js b/hookbox/static/hookbox.js index 0c1b06b..fb0af0e 100644 --- a/hookbox/static/hookbox.js +++ b/hookbox/static/hookbox.js @@ -14,7 +14,7 @@ 'net.csp.client': {"src": "jsio('import std.base64 as base64');\njsio('import std.utf8 as utf8');\njsio('import std.uri as uri'); \njsio('import net.errors as errors');\njsio('import .transports');\njsio('import lib.Enum as Enum');\n\nvar READYSTATE = exports.READYSTATE = Enum({\n\tINITIAL: 0,\n\tCONNECTING: 1,\n\tCONNECTED: 2,\n\tDISCONNECTING: 3,\n\tDISCONNECTED: 4\n});\n\n\nexports.CometSession = Class(function(supr) {\n\tvar id = 0;\n\tvar kDefaultBackoff = 50;\n\tvar kDefaultTimeoutInterval = 45000;\n\tvar kDefaultHandshakeTimeout = 10000;\n\tthis.init = function() {\n\t\tthis._id = ++id;\n\t\tthis._url = null;\n\t\tthis.readyState = READYSTATE.INITIAL;\n\t\tthis._sessionKey = null;\n\t\tthis._transport = null;\n\t\tthis._options = null;\n\t\t\n\t\tthis._utf8ReadBuffer = \"\";\n\t\tthis._writeBuffer = \"\";\n\t\t\n\t\tthis._packetsInFlight = null;\n\t\tthis._lastEventId = null;\n\t\tthis._lastSentId = null;\n\t\t\n\t\tthis._handshakeLater = null;\n\t\tthis._handshakeBackoff = kDefaultBackoff;\n\t\tthis._handshakeRetryTimer = null;\n\t\tthis._handshakeTimeoutTimer = null;\n\n\t\tthis._timeoutTimer = null;\n\n\t\t\n\t\tthis._writeBackoff = kDefaultBackoff;\n\t\tthis._cometBackoff = kDefaultBackoff;\n\t\t\n\t\tthis._nullInBuffer = false;\n\t\tthis._nullInFlight= false;\n\t\tthis._nullSent = false;\n\t\tthis._nullReceived = false;\n\t}\n\t\n\t\n\tthis.setEncoding = function(encoding) {\n\t\tif (encoding == this._options.encoding) { \n\t\t\treturn; \n\t\t}\n\t\tif (encoding != 'utf8' && encoding != 'plain') {\n\t\t\tthrow new errors.InvalidEncodingError();\n\t\t}\n\t\tif (encoding == 'plain' && this._buffer) {\n\t\t\tvar buffer = this._utf8ReadBuffer;\n\t\t\tthis._utf8ReadBuffer = \"\";\n\t\t\tthis._doOnRead(buffer);\n\t\t}\n\t\tthis._options.encoding = encoding;\n\t}\n\n\n\tthis.connect = function(url, options) {\n\t\tthis._url = url.replace(/\\/$/,'');\n\t\tthis._options = options || {};\n\t\t\n\t\tthis._options.encoding = this._options.encoding || 'utf8';\n\t\tthis.setEncoding(this._options.encoding); // enforce encoding constraints\n\t\t\n\t\tthis._options.connectTimeout = this._options.connectTimeout || kDefaultHandshakeTimeout;\n\t\t\n\t\tvar transportClass = transports.chooseTransport(url, this._options);\n\t\tthis._transport = new transportClass();\n\t\t\n\t\tthis._transport.handshakeFailure = bind(this, this._handshakeFailure);\n\t\tthis._transport.handshakeSuccess = bind(this, this._handshakeSuccess);\n\t\t\n\t\tthis._transport.cometFailure = bind(this, this._cometFailure);\n\t\tthis._transport.cometSuccess = bind(this, this._cometSuccess);\n\t\t\n\t\tthis._transport.sendFailure = bind(this, this._writeFailure);\n\t\tthis._transport.sendSuccess = bind(this, this._writeSuccess);\n\t\tthis.readyState = READYSTATE.CONNECTING;\n\t\tthis._transport.handshake(this._url, this._options);\n\t\t\n\t\tthis._handshakeTimeoutTimer = $setTimeout(bind(this, this._handshakeTimeout), \n\t\t\tthis._options.connectTimeout);\n\t}\n\n\tthis.write = function(data, encoding) {\n\t\tif (this.readyState != READYSTATE.CONNECTED) {\n\t\t\tthrow new errors.ReadyStateError();\n\t\t}\n\t\tencoding = encoding || this._options.encoding || 'utf8';\n\t\tif (encoding == 'utf8') {\n\t\t\tdata = utf8.encode(data);\n\t\t}\n\t\tthis._writeBuffer += data;\n\t\tthis._doWrite();\n\t}\n\t\n\t// Close due to protocol error\n\tthis._protocolError = function(msg) {\n\t\tlogger.debug('_protocolError', msg);\n\t\t// Immediately fire the onclose\n\t\t// send a null packet to the server\n\t\t// don't wait for a null packet back.\n\t\tthis.readyState = READYSTATE.DISCONNECTED;\n\t\tthis._doWrite(true);\n\t\tthis._doOnDisconnect(new errors.ServerProtocolError(msg));\n\t}\n\t\n\tthis._receivedNullPacket = function() {\n\t\tlogger.debug('_receivedNullPacket');\n\t\t// send a null packet back to the server\n\t\tthis._receivedNull = true;\n\t\t\n\t\t// send our own null packet back. (maybe)\n\t\tif (!(this._nullInFlight || this._nullInBuffer || this._nullSent)) {\n\t\t\tthis.readyState = READYSTATE.DISCONNECTING;\n\t\t\tthis._doWrite(true);\n\t\t}\n\t\telse {\n\t\t\tthis.readyState = READYSTATE.DISCONNECTED;\n\t\t}\n\t\t\n\t\t// fire an onclose\n\t\tthis._doOnDisconnect(new errors.ConnectionClosedCleanly());\n\n\t}\n\t\n\tthis._sentNullPacket = function() {\n\t\tlogger.debug('_sentNullPacket');\n\t\tthis._nullSent = true;\n\t\tif (this._nullSent && this._nullReceived) {\n\t\t\tthis.readyState = READYSTATE.DISCONNECTED;\n\t\t}\n\t}\n\t\n\t\n\t// User Calls close\n\tthis.close = function(err) {\n\t\tlogger.debug('close called', err, 'readyState', this.readyState);\n\n\t\t// \n\t\tswitch(this.readyState) {\n\t\t\tcase READYSTATE.CONNECTING:\n\t\t\t\tclearTimeout(this._handshakeRetryTimer);\n\t\t\t\tclearTimeout(this._handshakeTimeoutTimer);\n\t\t\t\tthis.readyState = READYSTATE.DISCONNECTED;\n\t\t\t\tthis._doOnDisconnect(err);\n\t\t\t\tbreak;\n\t\t\tcase READYSTATE.CONNECTED:\n\t\t\t\tthis.readyState = READYSTATE.DISCONNECTING;\n\t\t\t\tthis._doWrite(true);\n\t\t\t\tclearTimeout(this._timeoutTimer);\n\t\t\t\tbreak;\n\t\t\tcase READYSTATE.DISCONNECTED:\n\t\t\t\tthrow new errors.ReadyStateError(\"Session is already disconnected\");\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tthis._sessionKey = null;\n\t\tthis._opened = false; // what is this used for???\n\t\tthis.readyState = READYSTATE.DISCONNECTED;\n\t\t\n\t\tthis._doOnDisconnect(err);\n\t}\n\n\t\n\tthis._handshakeTimeout = function() {\n\t\tlogger.debug('handshake timeout');\n\t\tthis._handshakeTimeoutTimer = null;\n\t\tthis._doOnDisconnect(new errors.ServerUnreachable());\n\t}\n\t\n\tthis._handshakeSuccess = function(data) {\n\t\tlogger.debug('handshake success', data);\n\t\tif (this.readyState != READYSTATE.CONNECTING) { \n\t\t\tlogger.debug('received handshake success in invalid readyState:', this.readyState);\n\t\t\treturn; \n\t\t}\n\t\tclearTimeout(this._handshakeTimeoutTimer);\n\t\tthis._handshakeTimeoutTimer = null;\n\t\tthis._sessionKey = data.response.session;\n\t\tthis._opened = true;\n\t\tthis.readyState = READYSTATE.CONNECTED;\n\t\tthis._doOnConnect();\n\t\tthis._doConnectComet();\n\t}\n\t\n\tthis._handshakeFailure = function(data) {\n\t\tlogger.debug('handshake failure', data);\n\t\tif (this.readyState != READYSTATE.CONNECTING) { return; }\n\t\tif (data.status == 404) {\n\t\t\tclearTimeout(this._handshakeTimeoutTimer);\n\t\t\treturn this._doOnDisconnect(new errors.ServerUnreachable());\n\t\t}\n\t\t\n\t\tlogger.debug('trying again in ', this._handshakeBackoff);\n\t\tthis._handshakeRetryTimer = $setTimeout(bind(this, function() {\n\t\t\tthis._handshakeRetryTimer = null;\n\t\t\tthis._transport.handshake(this._url, this._options);\n\t\t}), this._handshakeBackoff);\n\t\t\n\t\tthis._handshakeBackoff *= 2;\n\t}\n\t\n\tthis._writeSuccess = function() {\n\t\tif (this.readyState != READYSTATE.CONNECTED && this.readyState != READYSTATE.DISCONNECTING) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._nullInFlight) {\n\t\t\treturn this._sentNullPacket();\n\t\t}\n\t\tthis._resetTimeoutTimer();\n\t\tthis.writeBackoff = kDefaultBackoff;\n\t\tthis._packetsInFlight = null;\n\t\tif (this._writeBuffer || this._nullInBuffer) {\n\t\t\tthis._doWrite(this._nullInBuffer);\n\t\t}\n\t}\n\t\n\tthis._writeFailure = function() {\n\t\tif (this.readyState != READYSTATE.CONNECTED && this.READYSTATE != READYSTATE.DISCONNECTING) { return; }\n\t\tthis._writeTimer = $setTimeout(bind(this, function() {\n\t\t\tthis._writeTimer = null;\n\t\t\tthis.__doWrite(this._nullInBuffer);\n\t\t}), this._writeBackoff);\n\t\tthis._writeBackoff *= 2;\n\t}\t\n\n\tthis._doWrite = function(sendNull) {\n\t\tif (this._packetsInFlight) {\n\t\t\tif (sendNull) {\n\t\t\t\tthis._nullInBuffer = true;\n\t\t\t\treturn; \n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.__doWrite(sendNull);\n\t}\n\t\n\tthis.__doWrite = function(sendNull) {\n\t\tlogger.debug('_writeBuffer:', this._writeBuffer);\n\t\tif (!this._packetsInFlight && this._writeBuffer) {\n\t\t\tthis._packetsInFlight = [this._transport.encodePacket(++this._lastSentId, this._writeBuffer, this._options)];\n\t\t\tthis._writeBuffer = \"\";\n\t\t}\n\t\tif (sendNull && !this._writeBuffer) {\n\t\t\tif (!this._packetsInFlight) {\n\t\t\t\tthis._packetsInFlight = [];\n\t\t\t}\n\t\t\tthis._packetsInFlight.push([++this._lastSentId, 0, null]);\n\t\t\tthis._nullInFlight = true;\n\t\t}\n\t\tif (!this._packetsInFlight) {\n\t\t\tlogger.debug(\"no packets to send\");\n\t\t\treturn;\n\t\t}\n\t\tlogger.debug('sending packets:', JSON.stringify(this._packetsInFlight));\n\t\tthis._transport.send(this._url, this._sessionKey, this._lastEventId || 0, JSON.stringify(this._packetsInFlight), this._options);\n\t}\n\t\n\tthis._doConnectComet = function() {\n\t\tlogger.debug('_doConnectComet');\n//\t\treturn;\n\t\tthis._transport.comet(this._url, this._sessionKey, this._lastEventId || 0, this._options);\n\t}\n\n\tthis._cometFailure = function(data) {\n\t\tif (this.readyState != READYSTATE.CONNECTED) { return; }\n\t\tif (data.status == 404 && data.response == 'Session not found') {\n\t\t\treturn this.close(new errors.ExpiredSession(data));\n\t\t}\n\t\t\n\t\tthis._cometTimer = $setTimeout(bind(this, function() {\n\t\t\tthis._doConnectComet();\n\t\t}), this._cometBackoff);\n\t\tthis._cometBackoff *= 2;\n\t}\n\t\n\tthis._cometSuccess = function(data) {\n\t\tif (this.readyState != READYSTATE.CONNECTED && this.readyState != READYSTATE.DISCONNECTING) { return; }\n\t\tlogger.debug('comet Success:', data);\n\t\tthis._cometBackoff = kDefaultBackoff;\n\t\tthis._resetTimeoutTimer();\n\t\t\n\t\tvar response = data.response;\n\t\tfor (var i = 0, packet; (packet = response[i]) || i < response.length; i++) {\n\t\t\tlogger.debug('process packet:', packet);\n\t\t\tif (packet === null) {\n\t\t\t\treturn this.close(new errors.ServerProtocolError(data));\n\t\t\t}\n\t\t\tlogger.debug('process packet', packet);\n\t\t\tvar ackId = packet[0];\n\t\t\tvar encoding = packet[1];\n\t\t\tvar data = packet[2];\n\t\t\tif (typeof(this._lastEventId) == 'number' && ackId <= this._lastEventId) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (typeof(this._lastEventId) == 'number' && ackId != this._lastEventId+1) {\n\t\t\t\treturn this._protocolError(\"Ack id too high\");\n\t\t\t}\n\t\t\tthis._lastEventId = ackId;\n\t\t\tif (data == null) {\n\t\t\t\treturn this._receivedNullPacket();\n\t\t\t}\n\t\t\tif (encoding == 1) { // base64 encoding\n\t\t\t\ttry {\n\t\t\t\t\tlogger.debug('before base64 decode:', data);\n\t\t\t\t\tdata = base64.decode(data);\n\t\t\t\t\tlogger.debug('after base64 decode:', data);\n\t\t\t\t} catch(e) {\n\t\t\t\t\treturn this._protocolError(\"Unable to decode base64 payload\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._options.encoding == 'utf8') {\n\t\t\t\t// TODO: need an incremental utf8 decoder for this stuff.\n\t\t\t\tthis._utf8ReadBuffer += data;\n\t\t\t\tlogger.debug('before utf8 decode, _utf8ReadBuffer:', this._utf8ReadBuffer);\n\t\t\t\tvar result = utf8.decode(this._utf8ReadBuffer);\n\t\t\t\tdata = result[0];\n\t\t\t\tthis._utf8ReadBuffer = this._utf8ReadBuffer.slice(result[1]);\n\t\t\t\tlogger.debug('after utf8 decode, _utf8ReadBuffer:', this._utf8ReadBuffer, 'data:', data );\n\t\t\t}\n\t\t\tlogger.debug('dispatching data:', data);\n\t\t\ttry {\n\t\t\t\tthis._doOnRead(data);\n\t\t\t} catch(e) {\n\t\t\t\tlogger.error('application code threw an error. (re-throwing in timeout):', e);\n\t\t\t\t// throw the error later\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tlogger.debug('timeout fired, throwing error', e);\n\t\t\t\t\tthrow e;\n\t\t\t\t}, 0);\n\t\t\t}\n\t\t}\n\t\t// reconnect comet last, after we process all of the packet ids\n\t\tthis._doConnectComet();\n\t\t\n\t}\n\n\tthis._doOnRead = function(data) {\n\t\tif (typeof(this.onread) == 'function') {\n\t\t\tlogger.debug('call onread function', data);\n\t\t\tthis.onread(data);\n\t\t}\n\t\telse {\n\t\t\tlogger.debug('skipping onread callback (function missing)');\n\t\t}\n\t}\n\t\n\tthis._doOnDisconnect = function(err) {\n\t\tif (typeof(this.ondisconnect) == 'function') {\n\t\t\tlogger.debug('call ondisconnect function', err);\n\t\t\tthis.ondisconnect(err);\n\t\t}\n\t\telse {\n\t\t\tlogger.debug('skipping ondisconnect callback (function missing)');\n\t\t}\n\t}\n\t\n\tthis._doOnConnect = function() {\n\t\tif (typeof(this.onconnect) == 'function') {\n\t\t\tlogger.debug('call onconnect function');\n\t\t\ttry {\n\t\t\t\tthis.onconnect();\n\t\t\t} catch(e) {\n\t\t\t\tlogger.debug('onconnect caused errror', e);\n\t\t\t\t// throw error later\n\t\t\t\tsetTimeout(function() { throw e }, 0);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tlogger.debug('skipping onconnect callback (function missing)');\n\t\t}\n\t}\n\n\tthis._resetTimeoutTimer = function() {\n\t\tclearTimeout(this._timeoutTimer);\n\t\tthis._timeoutTimer = $setTimeout(bind(this, function() {\n\t\t\tlogger.debug('connection timeout expired');\n\t\t\tthis.close(new errors.ConnectionTimeout())\n\t\t}), this._getTimeoutInterval())\n\t}\n\t\n\tthis._getTimeoutInterval = function() {\n\t\treturn kDefaultTimeoutInterval;\n\t}\n\n});\n", "filePath": "jsio/net/csp/client.js"}, 'net.interfaces': {"src": "// Sort of like a twisted protocol\njsio('import net');\njsio('import lib.Enum as Enum');\n\nvar ctx = jsio.__env.global;\n\nexports.Protocol = Class(function() {\n\tthis.connectionMade = function(isReconnect) {}\n\tthis.dataReceived = function(data) {}\n\tthis.connectionLost = function(reason) {}\n});\n\nexports.Client = Class(function() {\n\tthis.init = function(protocol) {\n\t\tthis._protocol = protocol;\n\t}\n\t\n\tthis.connect = function(transportName, opts) {\n\t\tthis._remote = new this._protocol();\n\t\tthis._remote._client = this;\n\t\tnet.connect(this._remote, transportName, opts);\n\t}\n});\n\n// Sort of like a twisted factory\nexports.Server = Class(function() {\n\tthis.init = function(protocolClass) {\n\t\tthis._protocolClass = protocolClass;\n\t}\n\n\tthis.buildProtocol = function() {\n\t\treturn new this._protocolClass();\n\t}\n\t\n\tthis.listen = function(how, port) {\n\t\treturn net.listen(this, how, port);\n\t}\n});\n\nexports.Transport = Class(function() {\n\tthis._encoding = 'plain'\n\tthis.write = function(data, encoding) {\n\t\tthrow new Error(\"Not implemented\");\n\t}\n\tthis.getPeer = function() {\n\t\tthrow new Error(\"Not implemented\");\n\t}\n\tthis.setEncoding = function(encoding) {\n\t\tthis._encoding = encoding;\n\t}\n\tthis.getEncoding = function() {\n\t\treturn this._encoding;\n\t}\n});\n\nexports.Listener = Class(function() {\n\tthis.init = function(server, opts) {\n\t\tthis._server = server;\n\t\tthis._opts = opts || {};\n\t}\n\t\n\tthis.onConnect = function(transport) {\n//\t\ttry {\n\t\t\tvar p = this._server.buildProtocol();\n\t\t\tp.transport = transport;\n\t\t\tp.server = this._server;\n\t\t\ttransport.protocol = p;\n\t\t\ttransport.makeConnection(p);\n\t\t\tp.connectionMade();\n//\t\t} catch(e) {\n//\t\t\tlogger.error(e);\n//\t\t}\n\t}\n\t\n\tthis.listen = function() { throw new Error('Abstract class'); }\n\tthis.stop = function() {}\n});\n\nexports.STATE = Enum('INITIAL', 'DISCONNECTED', 'CONNECTING', 'CONNECTED');\nexports.Connector = Class(function() {\n\tthis.init = function(protocol, opts) {\n\t\tthis._protocol = protocol;\n\t\tthis._opts = opts;\n\t\tthis._state = exports.STATE.INITIAL;\n\t}\n\t\n\tthis.onConnect = function(transport) {\n\t\tthis._state = exports.STATE.CONNECTED;\n\n\t\ttransport.makeConnection(this._protocol);\n\t\tthis._protocol.transport = transport;\n\t\ttry {\n\t\t\tthis._protocol.connectionMade();\n\t\t} catch(e) {\n\t\t\tthrow logger.error(e);\n\t\t}\n\t}\n\t\n\tthis.onDisconnect = function(err) {\n\t\tvar wasConnected = this._state == exports.STATE.CONNECTED;\n\t\tthis._state = exports.STATE.DISCONNECTED;\n\t\t\n\t\ttry {\n\t\t\tthis._protocol.connectionLost(err, wasConnected);\n\t\t} catch(e) {\n\t\t\tthrow logger.error(e);\n\t\t}\n\t}\n\t\n\tthis.getProtocol = function() { return this._protocol; }\n});\n", "filePath": "jsio/net/interfaces.js"}, 'base': {"src": "exports.log = jsio.__env.log;\nexports.GLOBAL = jsio.__env.global;\n\nexports.bind = function(context, method /*, VARGS*/) {\n\tif(arguments.length > 2) {\n\t\tvar args = Array.prototype.slice.call(arguments, 2);\n\t\treturn typeof method == 'string'\n\t\t\t? function() {\n\t\t\t\tif (context[method]) {\n\t\t\t\t\treturn context[method].apply(context, args.concat(Array.prototype.slice.call(arguments, 0)));\n\t\t\t\t} else {\n\t\t\t\t\tthrow logger.error('No method:', method, 'for context', context);\n\t\t\t\t}\n\t\t\t}\n\t\t\t: function() { return method.apply(context, args.concat(Array.prototype.slice.call(arguments, 0))); }\n\t} else {\n\t\treturn typeof method == 'string'\n\t\t\t? function() {\n\t\t\t\tif (context[method]) {\n\t\t\t\t\treturn context[method].apply(context, arguments);\n\t\t\t\t} else {\n\t\t\t\t\tthrow logger.error('No method:', method, 'for context', context);\n\t\t\t\t}\n\t\t\t}\n\t\t\t: function() { return method.apply(context, arguments); }\n\t}\n}\n\nexports.Class = function(parent, proto) {\n\tif(!parent) { throw new Error('parent or prototype not provided'); }\n\tif(!proto) { proto = parent; parent = null; }\n\telse if(parent instanceof Array) { // multiple inheritance, use at your own risk =)\n\t\tproto.prototype = {};\n\t\tfor(var i = 0, p; p = parent[i]; ++i) {\n\t\t\tfor(var item in p.prototype) {\n\t\t\t\tif(!(item in proto.prototype)) {\n\t\t\t\t\tproto.prototype[item] = p.prototype[item];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tparent = parent[0]; \n\t} else {\n\t\tproto.prototype = parent.prototype;\n\t}\n\n\tvar cls = function() { if(this.init) { return this.init.apply(this, arguments); }}\n\tcls.prototype = new proto(parent ? function(context, method, args) {\n\t\tvar args = args || [];\n\t\tvar target = proto;\n\t\twhile(target = target.prototype) {\n\t\t\tif(target[method]) {\n\t\t\t\treturn target[method].apply(context, args);\n\t\t\t}\n\t\t}\n\t\tthrow new Error('method ' + method + ' does not exist');\n\t} : null);\n\tcls.prototype.constructor = cls;\n\treturn cls;\n}\n\nexports.$setTimeout = function(f, t/*, VARGS */) {\n\tvar args = Array.prototype.slice.call(arguments, 2);\n\treturn setTimeout(function() {\n\t\ttry {\n\t\t\tf.apply(this, args);\n\t\t} catch(e) {\n\t\t\t// log?\n\t\t}\n\t}, t)\n}\n\nexports.$setInterval = function(f, t/*, VARGS */) {\n\tvar args = Array.prototype.slice.call(arguments, 2);\n\treturn setInterval(function() {\n\t\ttry {\n\t\t\tf.apply(this, args);\n\t\t} catch(e) {\n\t\t\t// log?\n\t\t}\n\t}, t)\n}\n\n// node doesn't let you call clearTimeout(null)\nexports.$clearTimeout = function (timer) { return timer ? clearTimeout(timer) : null; };\nexports.$clearInterval = function (timer) { return timer ? clearInterval(timer) : null; };\n\n// keep logging local variables out of other closures in this file!\nexports.logging = (function() {\n\t\n\t// logging namespace, this is what is exported\n\tvar logging = {\n\t\t\tDEBUG: 1,\n\t\t\tLOG: 2,\n\t\t\tINFO: 3,\n\t\t\tWARN: 4,\n\t\t\tERROR: 5\n\t\t},\n\t\tloggers = {}, // effectively globals - all loggers and a global production state\n\t\tproduction = false;\n\n\tlogging.setProduction = function(prod) { production = !!prod; }\n\tlogging.get = function(name) {\n\t\treturn loggers.hasOwnProperty(name) ? loggers[name]\n\t\t\t: (loggers[name] = new Logger(name));\n\t}\n\tlogging.set = function(name, _logger) {\n\t\tloggers[name] = _logger;\n\t}\n\t\n\tlogging.getAll = function() { return loggers; }\n\n\tlogging.__create = function(pkg, ctx) { ctx.logger = logging.get(pkg); }\n\t\n\tvar Logger = exports.Class(function() {\n\t\tthis.init = function(name, level) {\n\t\t\tthis._name = name;\n\t\t\tthis._level = level || logging.LOG;\n\t\t\tthis._listener = exports.log;\n\t\t}\n\t\t\n\t\tthis.setLevel = function(level) { this._level = level; }\n\t\n\t\tvar SLICE = Array.prototype.slice;\n\t\t\n\t\tfunction makeLogFunction(level, type) {\n\t\t\treturn function() {\n\t\t\t\tif (!production && level >= this._level) {\n\t\t\t\t\treturn this._listener.apply(this._listener, [type, this._name].concat(SLICE.call(arguments)));\n\t\t\t\t}\n\t\t\t\treturn arguments[0];\n\t\t\t}\n\t\t}\n\t\n\t\tthis.setListener = function(listener) { log = listener; }\n\t\tthis.debug = makeLogFunction(logging.DEBUG, \"DEBUG\");\n\t\tthis.log = makeLogFunction(logging.LOG, \"LOG\");\n\t\tthis.info = makeLogFunction(logging.INFO, \"INFO\");\n\t\tthis.warn = makeLogFunction(logging.WARN, \"WARN\");\n\t\tthis.error = makeLogFunction(logging.ERROR, \"ERROR\");\n\t});\n\n\treturn logging;\n})();\n\nvar logger = exports.logging.get('jsiocore');\n", "filePath": "jsio/base.js"}, -'hookbox': {"src": "jsio('from net import connect as jsioConnect');\njsio('from net.protocols.rtjp import RTJPProtocol');\n\nexports.__jsio = jsio.__jsio;\nexports.logging = logging;\n\nlogger.setLevel(0);\n\n\nexports.connect = function(url, cookieString) {\n\tif (!url.match('/$')) {\n\t\turl = url + '/';\n\t}\n\tvar p = new HookBoxProtocol(url, cookieString);\n\tif (window.WebSocket) {\n\t\tjsioConnect(p, 'websocket', {url: url.replace('http://', 'ws://') + 'ws' });\n\t\tp.connectionLost = bind(p, '_connectionLost', 'websocket');\n\t}\n\telse {\n\t\tjsioConnect(p, 'csp', {url: url + 'csp'})\n\t\tp.connectionLost = bind(p, '_connectionLost', 'csp');\n\t}\n\treturn p;\n}\n\nvar Subscription = Class(function(supr) {\n\n\n\tthis.init = function(conn, args) {\n\t\tthis.channelName = args.channel_name;\n\t\tthis.history = args.history;\n\t\tthis.historySize = args.history_size;\n\t\tthis.state = args.state;\n\t\tthis.presence = args.presence;\n\t\tthis.canceled = false;\n\t\tthis.publish = bind(conn, 'publish', this.channelName);\n\t}\n\n\tthis.onPublish = function(frame) { }\n\tthis.onSubscribe = function(frame) {}\n\tthis.onUnsubscribe = function(frame) {}\n\tthis.onState = function(frame) {}\n\n\tthis.frame = function(name, args) {\n\t\tlogger.debug('received frame', name, args);\n\t\tswitch(name) {\n\t\t\tcase 'PUBLISH':\n\t\t\t\tif (this.historySize) { \n\t\t\t\t\tthis.history.push([\"PUBLISH\", { user: args.user, payload: args.payload}]) \n\t\t\t\t\twhile (this.history.length > this.historySize) { \n\t\t\t\t\t\tthis.history.shift(); \n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.onPublish(args);\n\t\t\t\tbreak;\n\t\t\tcase 'UNSUBSCRIBE':\n\t\t\t\tif (this.historySize) { \n\t\t\t\t\tthis.history.push([\"UNSUBSCRIBE\", { user: args.user}]) \n\t\t\t\t\twhile (this.history.length > this.historySize) { \n\t\t\t\t\t\tthis.history.shift(); \n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var i = 0, user; user = this.presence[i]; ++i) {\n\t\t\t\t\tif (user == args.user) {\n\t\t\t\t\t\tthis.presence.splice(i, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.onUnsubscribe(args);\n\t\t\t\tbreak;\n\t\t\tcase 'SUBSCRIBE':\n\t\t\t\tif (this.historySize) { \n\t\t\t\t\tthis.history.push([\"SUBSCRIBE\", { user: args.user}]) \n\t\t\t\t\twhile (this.history.length > this.historySize) { \n\t\t\t\t\t\tthis.history.shift(); \n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.presence.push(args.user);\n\t\t\t\tthis.onSubscribe(args);\n\t\t\t\tbreak;\n\t\t\tcase 'STATE_UPDATE':\n\t\t\t\tfor (var i = 0, key; key = args.deletes[i]; ++i) {\n\t\t\t\t\tdelete this.state[key];\n\t\t\t\t}\n\t\t\t\tfor (key in args.updates) {\n\t\t\t\t\tthis.state[key] = args.updates[key];\n\t\t\t\t}\n\t\t\t\tthis.onState(args);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tthis.cancel = function() {\n\t\tif (!this.canceled) {\n\t\t\tlogger.debug('calling this._onCancel()');\n\t\t\tthis._onCancel();\n\t\t}\n\t}\n\n\n\tthis._onCancel = function() { }\n\n\n})\n\nHookBoxProtocol = Class([RTJPProtocol], function(supr) {\n\n\tthis.onOpen = function() { }\n\tthis.onClose = function(err, wasConnected) { }\n\tthis.onError = function(args) { }\n\tthis.onSubscribed = function(name, subscription) { }\n\tthis.onUnsubscribed = function(subscription, args) { }\n\tthis.onMessaged = function(args) {}\n\tthis.init = function(url, cookieString) {\n\t\tsupr(this, 'init', []);\n\t\tthis.url = url;\n\t\ttry {\n\t\t\tthis.cookieString = cookieString || document.cookie;\n\t\t} catch(e) {\n\t\t\tthis.cookieString = \"\";\n\t\t}\n\t\tthis.connected = false;\n\n\t\tthis._subscriptions = {};\n\t\tthis._buffered_subs = [];\n\t\tthis._publishes = [];\n\t\tthis._messages = [];\n\t\tthis._errors = {};\n\t\tthis.username = null;\n\t}\n\n\tthis.subscribe = function(channel_name) {\n\t\tif (!this.connected) {\n\t\t\tthis._buffered_subs.push(channel_name);\n\t\t} else {\n\t\t\tvar fId = this.sendFrame('SUBSCRIBE', {channel_name: channel_name});\n\t\t}\n\t}\n\n\tthis.publish = function(channel_name, data) {\n\t\tif (this.connected) {\n\t\t\tthis.sendFrame('PUBLISH', { channel_name: channel_name, payload: JSON.stringify(data) });\n\t\t} else {\n\t\t\tthis._publishes.push([channel_name, data]);\n\t\t}\n\n\t}\n\t\n\tthis.message = function(name, payload) {\n\t\tif (this.connected) {\n\t\t\tthis.sendFrame('MESSAGE', { 'name': name, 'payload': JSON.stringify(payload) });\n\t\t} else {\n\t\t\tthis._messages.push([name, payload]);\n\t\t}\n\t}\n\t\n\tthis.connectionMade = function() {\n\t\tlogger.debug('connectionMade');\n\t\tthis.transport.setEncoding('utf8');\n\t\tthis.sendFrame('CONNECT', { cookie_string: this.cookieString });\n\t}\n\n\tthis.frameReceived = function(fId, fName, fArgs) {\n\t\tswitch(fName) {\n\t\t\tcase 'MESSAGE':\n\t\t\t\tthis.onMessaged(fArgs);\n\t\t\t\tbreak;\n\t\t\tcase 'CONNECTED':\n\t\t\t\tthis.connected = true;\n\t\t\t\tthis.username = fArgs.name;\n\t\t\t\twhile (this._buffered_subs.length) {\n\t\t\t\t\tvar chan = this._buffered_subs.shift();\n\t\t\t\t\tthis.sendFrame('SUBSCRIBE', {channel_name: chan});\n\t\t\t\t}\n\t\t\t\twhile (this._publishes.length) {\n\t\t\t\t\tvar pub = this._publishes.splice(0, 1)[0];\n\t\t\t\t\tthis.publish.apply(this, pub);\n\t\t\t\t}\n\t\t\t\twhile (this._messages.length) {\n\t\t\t\t\tvar msg = this._messages.splice(0, 1)[0];\n\t\t\t\t\tthis.message.apply(this, msg);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tthis.onOpen();\n\t\t\t\tbreak;\n\t\t\tcase 'SUBSCRIBE':\n\t\t\t\tif (fArgs.user == this.username) {\n\t\t\t\t\tvar s = new Subscription(this, fArgs);\n\t\t\t\t\tthis._subscriptions[fArgs.channel_name] = s;\n\t\t\t\t\ts._onCancel = bind(this, function() {\n\t\t\t\t\t\tthis.sendFrame('UNSUBSCRIBE', {\n\t\t\t\t\t\t\tchannel_name: fArgs.channel_name\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tthis.onSubscribed(fArgs.channel_name, s);\n\t\t\t\t\tK = s;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis._subscriptions[fArgs.channel_name].frame(fName, fArgs);\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 'STATE_UPDATE':\n\t\t\t\n\t\t\tcase 'PUBLISH':\n\t\t\t\n\t\t\t\tvar sub = this._subscriptions[fArgs.channel_name];\n\t\t\t\tsub.frame(fName, fArgs);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase 'UNSUBSCRIBE':\n\t\t\t\tvar sub = this._subscriptions[fArgs.channel_name];\n\t\t\t\tsub.canceled = true;\n\t\t\t\tsub.frame(fName, fArgs);\n\t\t\t\tif (fArgs.user == this.username) {\n\t\t\t\t\tdelete this._subscriptions[fArgs.channel_name];\n\t\t\t\t\tthis.onUnsubscribed(sub, fArgs);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'ERROR':\n\t\t\t\tthis.onError(fArgs);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase 'SET_COOKIE':\n\t\t\t\tdocument.cookie = fArgs.cookie;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tthis._connectionLost = function(transportName, reason, wasConnected) {\n\t\tif (!wasConnected) {\n\t\t\tlogger.debug('connectionFailed', transportName)\n\t\t\tif (transportName == 'websocket') {\n\t\t\t\tlogger.debug('retry with csp');\n\t\t\t\tthis.connectionLost = bind(this, '_connectionLost', 'csp');\n\t\t\t\tjsioConnect(this, 'csp', {url: this.url + 'csp'})\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.debug('connectionLost');\n\t\t\tthis.connected = false;\n\t\t\tthis.onClose();\n\t\t}\n\t}\n\n\tthis.disconnect = function() {\n\t\tthis.transport.loseConnection();\n\t}\n\n})\n", "filePath": "hookbox.js"}, +'hookbox': {"src": "jsio('from net import connect as jsioConnect');\njsio('from net.protocols.rtjp import RTJPProtocol');\n\nexports.__jsio = jsio.__jsio;\nexports.logging = logging;\n\nlogger.setLevel(0);\n\n\nexports.connect = function(url, connectPayload, cookieString) {\n\tif (!url.match('/$')) {\n\t\turl = url + '/';\n\t}\n\tvar p = new HookBoxProtocol(url, connectPayload, cookieString);\n\tif (window.WebSocket) {\n\t\tjsioConnect(p, 'websocket', {url: url.replace('http://', 'ws://') + 'ws' });\n\t\tp.connectionLost = bind(p, '_connectionLost', 'websocket');\n\t}\n\telse {\n\t\tjsioConnect(p, 'csp', {url: url + 'csp'})\n\t\tp.connectionLost = bind(p, '_connectionLost', 'csp');\n\t}\n\treturn p;\n}\n\nvar Subscription = Class(function(supr) {\n\n\n\tthis.init = function(conn, args) {\n\t\tthis.channelName = args.channel_name;\n\t\tthis.history = args.history;\n\t\tthis.historySize = args.history_size;\n\t\tthis.state = args.state;\n\t\tthis.presence = args.presence;\n\t\tthis.canceled = false;\n\t\tthis.publish = bind(conn, 'publish', this.channelName);\n\t}\n\n\tthis.onPublish = function(frame) { }\n\tthis.onSubscribe = function(frame) {}\n\tthis.onUnsubscribe = function(frame) {}\n\tthis.onState = function(frame) {}\n\n\tthis.frame = function(name, args) {\n\t\tswitch(name) {\n\t\t\tcase 'PUBLISH':\n\t\t\t\tif (this.historySize) { \n\t\t\t\t\tthis.history.push([\"PUBLISH\", { user: args.user, payload: args.payload}]) \n\t\t\t\t\twhile (this.history.length > this.historySize) { \n\t\t\t\t\t\tthis.history.shift(); \n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.onPublish(args);\n\t\t\t\tbreak;\n\t\t\tcase 'UNSUBSCRIBE':\n\t\t\t\tif (this.historySize) { \n\t\t\t\t\tthis.history.push([\"UNSUBSCRIBE\", { user: args.user}]) \n\t\t\t\t\twhile (this.history.length > this.historySize) { \n\t\t\t\t\t\tthis.history.shift(); \n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var i = 0, user; user = this.presence[i]; ++i) {\n\t\t\t\t\tif (user == args.user) {\n\t\t\t\t\t\tthis.presence.splice(i, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.onUnsubscribe(args);\n\t\t\t\tbreak;\n\t\t\tcase 'SUBSCRIBE':\n\t\t\t\tif (this.historySize) { \n\t\t\t\t\tthis.history.push([\"SUBSCRIBE\", { user: args.user}]) \n\t\t\t\t\twhile (this.history.length > this.historySize) { \n\t\t\t\t\t\tthis.history.shift(); \n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.presence.push(args.user);\n\t\t\t\tthis.onSubscribe(args);\n\t\t\t\tbreak;\n\t\t\tcase 'STATE_UPDATE':\n\t\t\t\tfor (var i = 0, key; key = args.deletes[i]; ++i) {\n\t\t\t\t\tdelete this.state[key];\n\t\t\t\t}\n\t\t\t\tfor (key in args.updates) {\n\t\t\t\t\tthis.state[key] = args.updates[key];\n\t\t\t\t}\n\t\t\t\tthis.onState(args);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tthis.cancel = function() {\n\t\tif (!this.canceled) {\n\t\t\tlogger.debug('calling this._onCancel()');\n\t\t\tthis._onCancel();\n\t\t}\n\t}\n\n\n\tthis._onCancel = function() { }\n\n\n})\n\nHookBoxProtocol = Class([RTJPProtocol], function(supr) {\n\n\tthis.onOpen = function(args) { }\n\tthis.onClose = function(err, wasConnected) { }\n\tthis.onError = function(args) { }\n\tthis.onSubscribed = function(name, subscription) { }\n\tthis.onUnsubscribed = function(subscription, args) { }\n\tthis.onMessaged = function(args) {}\n\tthis.init = function(url, connectPayload, cookieString) {\n\t\tsupr(this, 'init', []);\n\t\tthis.url = url;\n\t\ttry {\n\t\t\tthis.cookieString = cookieString || document.cookie;\n\t\t} catch(e) {\n\t\t\tthis.cookieString = \"\";\n\t\t}\n\t\tthis.connected = false;\n\n\t\tthis._subscriptions = {};\n\t\tthis._buffered_subs = [];\n\t\tthis._publishes = [];\n\t\tthis._messages = [];\n\t\tthis._errors = {};\n this._connectPayload = connectPayload;\n\t\tthis.username = null;\n\t}\n\n\tthis.subscribe = function(channel_name) {\n\t\tif (!this.connected) {\n\t\t\tthis._buffered_subs.push(channel_name);\n\t\t} else {\n\t\t\tvar fId = this.sendFrame('SUBSCRIBE', {channel_name: channel_name});\n\t\t}\n\t}\n\n\tthis.publish = function(channel_name, data) {\n\t\tif (this.connected) {\n\t\t\tthis.sendFrame('PUBLISH', { channel_name: channel_name, payload: JSON.stringify(data) });\n\t\t} else {\n\t\t\tthis._publishes.push([channel_name, data]);\n\t\t}\n\n\t}\n\t\n\tthis.message = function(name, payload) {\n\t\tif (this.connected) {\n\t\t\tthis.sendFrame('MESSAGE', { 'name': name, 'payload': JSON.stringify(payload) });\n\t\t} else {\n\t\t\tthis._messages.push([name, payload]);\n\t\t}\n\t}\n\t\n\tthis.connectionMade = function() {\n\t\tlogger.debug('connectionMade');\n\t\tthis.transport.setEncoding('utf8');\n\t\tthis.sendFrame('CONNECT', { cookie_string: this.cookieString, payload: JSON.stringify(this._connectPayload) });\n\t}\n\n\tthis.frameReceived = function(fId, fName, fArgs) {\n logger.debug('received frame', fName, fArgs);\n\t\tswitch(fName) {\n\t\t\tcase 'MESSAGE':\n\t\t\t\tthis.onMessaged(fArgs);\n\t\t\t\tbreak;\n\t\t\tcase 'CONNECTED':\n\t\t\t\tthis.connected = true;\n\t\t\t\tthis.username = fArgs.name;\n\t\t\t\twhile (this._buffered_subs.length) {\n\t\t\t\t\tvar chan = this._buffered_subs.shift();\n\t\t\t\t\tthis.sendFrame('SUBSCRIBE', {channel_name: chan});\n\t\t\t\t}\n\t\t\t\twhile (this._publishes.length) {\n\t\t\t\t\tvar pub = this._publishes.splice(0, 1)[0];\n\t\t\t\t\tthis.publish.apply(this, pub);\n\t\t\t\t}\n\t\t\t\twhile (this._messages.length) {\n\t\t\t\t\tvar msg = this._messages.splice(0, 1)[0];\n\t\t\t\t\tthis.message.apply(this, msg);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tthis.onOpen(fArgs);\n\t\t\t\tbreak;\n\t\t\tcase 'SUBSCRIBE':\n\t\t\t\tif (fArgs.user == this.username) {\n\t\t\t\t\tvar s = new Subscription(this, fArgs);\n\t\t\t\t\tthis._subscriptions[fArgs.channel_name] = s;\n\t\t\t\t\ts._onCancel = bind(this, function() {\n\t\t\t\t\t\tthis.sendFrame('UNSUBSCRIBE', {\n\t\t\t\t\t\t\tchannel_name: fArgs.channel_name\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tthis.onSubscribed(fArgs.channel_name, s);\n\t\t\t\t\tK = s;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis._subscriptions[fArgs.channel_name].frame(fName, fArgs);\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 'STATE_UPDATE':\n\t\t\t\n\t\t\tcase 'PUBLISH':\n\t\t\t\n\t\t\t\tvar sub = this._subscriptions[fArgs.channel_name];\n\t\t\t\tsub.frame(fName, fArgs);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase 'UNSUBSCRIBE':\n\t\t\t\tvar sub = this._subscriptions[fArgs.channel_name];\n\t\t\t\tsub.canceled = true;\n\t\t\t\tsub.frame(fName, fArgs);\n\t\t\t\tif (fArgs.user == this.username) {\n\t\t\t\t\tdelete this._subscriptions[fArgs.channel_name];\n\t\t\t\t\tthis.onUnsubscribed(sub, fArgs);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'ERROR':\n\t\t\t\tthis.onError(fArgs);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase 'SET_COOKIE':\n\t\t\t\tdocument.cookie = fArgs.cookie;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tthis._connectionLost = function(transportName, reason, wasConnected) {\n\t\tif (!wasConnected) {\n\t\t\tlogger.debug('connectionFailed', transportName)\n\t\t\tif (transportName == 'websocket') {\n\t\t\t\tlogger.debug('retry with csp');\n\t\t\t\tthis.connectionLost = bind(this, '_connectionLost', 'csp');\n\t\t\t\tjsioConnect(this, 'csp', {url: this.url + 'csp'})\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.debug('connectionLost');\n\t\t\tthis.connected = false;\n\t\t\tthis.onClose();\n\t\t}\n\t}\n\n\tthis.disconnect = function() {\n\t\tthis.transport.loseConnection();\n\t}\n\n})\n", "filePath": "hookbox.js"}, 'std.uri': {"src": "var attrs = [ \n\t\"source\",\n\t\"protocol\",\n\t\"authority\",\n\t\"userInfo\",\n\t\"user\",\n\t\"password\",\n\t\"host\",\n\t\"port\",\n\t\"relative\",\n\t\"path\",\n\t\"directory\",\n\t\"file\",\n\t\"query\",\n\t\"anchor\"\n];\n\nexports.Uri = Class(function(supr) {\n\tthis.init = function(url, isStrict) {\n\t\tvar uriData = exports.parse(url, isStrict)\n\t\tfor (attr in uriData) {\n\t\t\tthis['_' + attr] = uriData[attr];\n\t\t};\n\t};\n \n\tfor (var i = 0, attr; attr = attrs[i]; ++i) {\n\t\t(function(attr) {\n\t\t\tvar fNameSuffix = attr.charAt(0).toUpperCase() + attr.slice(1);\n\t\t\tthis['get' + fNameSuffix] = function() {\n\t\t\t\treturn this['_' + attr];\n\t\t\t};\n\t\t\tthis['set' + fNameSuffix] = function(val) {\n\t\t\t\tthis['_' + attr] = val;\n\t\t\t};\n\t\t}).call(this, attr);\n\t};\n\n\tthis.toString = this.render = function() {\n\t\t// XXX TODO: This is vaguely reasonable, but not complete. fix it...\n\t\tvar a = this._protocol ? this._protocol + \"://\" : \"\"\n\t\tvar b = this._host ? this._host + ((this._port || 80) == 80 ? \"\" : \":\" + this._port) : \"\";\n\t\tvar c = this._path;\n\t\tvar d = this._query ? '?' + this._query : '';\n\t\tvar e = this._anchor ? '#' + this._anchor : '';\n\t\treturn a + b + c + d + e;\n\t};\n});\n\nexports.buildQuery = function(kvp) {\n\tvar pairs = [];\n\tfor (key in kvp) {\n\t\tpairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(kvp[key]));\n\t}\n\treturn pairs.join('&');\n}\n\nexports.parseQuery = function(str) {\n\tvar pairs = str.split('&'),\n\t\tn = pairs.length,\n\t\tdata = {};\n\tfor (var i = 0; i < n; ++i) {\n\t\tvar pair = pairs[i].split('='),\n\t\t\tkey = decodeURIComponent(pair[0]);\n\t\tif (key) { data[key] = decodeURIComponent(pair[1]); }\n\t}\n\treturn data;\n}\n\n// Regexs are based on parseUri 1.2.2\n// Original: (c) Steven Levithan \n// Original: MIT License\n\nvar strictRegex = /^(?:([^:\\/?#]+):)?(?:\\/\\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\\/?#]*)(?::(\\d*))?))?((((?:[^?#\\/]*\\/)*)([^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/;\nvar looseRegex = /^(?:(?![^:@]+:[^:@\\/]*@)([^:\\/?#.]+):)?(?:\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;\nvar queryStringRegex = /(?:^|&)([^&=]*)=?([^&]*)/g;\n\nexports.parse = function(str, isStrict) {\n\tvar regex = isStrict ? strictRegex : looseRegex;\n\tvar result = {};\n\tvar match = regex.exec(str);\n\tfor (var i = 0, attr; attr = attrs[i]; ++i) {\n\t\tresult[attr] = match[i] || \"\";\n\t}\n\t\n\tvar qs = result['queryKey'] = {};\n\tresult['query'].replace(queryStringRegex, function(check, key, val) {\n\t\tif (check) {\n\t\t\tqs[key] = val;\n\t\t}\n\t});\n\t\n\treturn result;\n}\n\nexports.isSameDomain = function(urlA, urlB) {\n\tvar a = exports.parse(urlA);\n\tvar b = exports.parse(urlB);\n\treturn ((a.port == b.port ) && (a.host == b.host) && (a.protocol == b.protocol));\n};\n", "filePath": "jsio/std/uri.js"}, 'net.csp.transports': {"src": "jsio('import std.uri as uri'); \njsio('import std.base64 as base64');\njsio('from util.browserdetect import BrowserDetect');\n\n;(function() {\n\tvar doc;\n\texports.getDoc = function() {\n\t\tif (doc) { return doc; }\n\t\ttry {\n\t\t\tdoc = window.ActiveXObject && new ActiveXObject('htmlfile');\n\t\t\tif (doc) {\n\t\t\t\tdoc.open().write('');\n\t\t\t\tdoc.close();\n\t\t\t\twindow.attachEvent('onunload', function() {\n\t\t\t\t\ttry { doc.body.innerHTML = ''; } catch(e) {}\n\t\t\t\t\tdoc = null;\n\t\t\t\t});\n\t\t\t}\n\t\t} catch(e) {}\n\t\t\n\t\tif (!doc) { doc = document; }\n\t\treturn doc;\n\t};\n\n\texports.XHR = function() {\n\t\tvar win = window,\n\t\t\tdoc = exports.getDoc();\n\t\t//if (doc.parentWindow) { win = doc.parentWindow; }\n\t\t\n\t\treturn new (exports.XHR = win.XMLHttpRequest ? win.XMLHttpRequest\n\t\t\t: function() { return win.ActiveXObject && new win.ActiveXObject('Msxml2.XMLHTTP') || null; });\n\t}\n\t\n\texports.createXHR = function() { return new exports.XHR(); }\n\n})();\n\nfunction isLocalFile(url) { return /^file:\\/\\//.test(url); }\nfunction isWindowDomain(url) { return uri.isSameDomain(url, window.location.href); }\n\nfunction canUseXHR(url) {\n\t// always use jsonp for local files\n\tif (isLocalFile(url)) { return false; }\n\t\n\t// try to create an XHR using the same function the XHR transport uses\n\tvar xhr = new exports.XHR();\n\tif (!xhr) { return false; }\n\t\n\t// if the URL requested is the same domain as the window,\n\t// then we can use same-domain XHRs\n\tif (isWindowDomain(url)) { return true; }\n\t\n\t// if the URL requested is a different domain than the window,\n\t// then we need to check for cross-domain support\n\tif (window.XMLHttpRequest\n\t\t\t&& (xhr.__proto__ == XMLHttpRequest.prototype // WebKit Bug 25205\n\t\t\t\t|| xhr instanceof window.XMLHttpRequest)\n\t\t\t&& xhr.withCredentials !== undefined\n\t\t|| window.XDomainRequest \n\t\t\t&& xhr instanceof window.XDomainRequest) {\n\t\treturn true;\n\t}\n};\n\nvar transports = exports.transports = {};\n\nexports.chooseTransport = function(url, options) {\n\tswitch(options.preferredTransport) {\n\t\tcase 'jsonp':\n\t\t\treturn transports.jsonp;\n\t\tcase 'xhr':\n\t\tdefault:\n\t\t\tif (canUseXHR(url)) { return transports.xhr; };\n\t\t\treturn transports.jsonp;\n\t}\n};\n\n// TODO: would be nice to use these somewhere...\n\nvar PARAMS = {\n\t'xhrstream': {\"is\": \"1\", \"bs\": \"\\n\"},\n\t'xhrpoll': {\"du\": \"0\"},\n\t'xhrlongpoll': {},\n\t'sselongpoll': {\"bp\": \"data: \", \"bs\": \"\\r\\n\", \"se\": \"1\"},\n\t'ssestream': {\"bp\": \"data: \", \"bs\": \"\\r\\n\", \"se\": \"1\", \"is\": \"1\"}\n};\n\nexports.Transport = Class(function(supr) {\n\tthis.handshake = function(url, options) {\n\t\tthrow new Error(\"handshake Not Implemented\"); \n\t};\n\tthis.comet = function(url, sessionKey, lastEventId, options) { \n\t\tthrow new Error(\"comet Not Implemented\"); \n\t};\n\tthis.send = function(url, sessionKey, data, options) { \n\t\tthrow new Error(\"send Not Implemented\");\n\t};\n\tthis.encodePacket = function(packetId, data, options) { \n\t\tthrow new Error(\"encodePacket Not Implemented\"); \n\t};\n\tthis.abort = function() { \n\t\tthrow new Error(\"abort Not Implemented\"); \n\t};\n});\n\nvar baseTransport = Class(exports.Transport, function(supr) {\n\tthis.init = function() {\n\t\tthis._aborted = false;\n\t\tthis._handshakeArgs = {\n\t\t\td:'{}',\n\t\t\tct:'application/javascript'\n\t\t};\n\t};\n\t\n\tthis.handshake = function(url, options) {\n\t\tlogger.debug('handshake:', url, options);\n\t\tthis._makeRequest('send', url + '/handshake', \n\t\t\t\t\t\t this._handshakeArgs, \n\t\t\t\t\t\t this.handshakeSuccess, \n\t\t\t\t\t\t this.handshakeFailure);\n\t};\n\t\n\tthis.comet = function(url, sessionKey, lastEventId, options) {\n\t\tlogger.debug('comet:', url, sessionKey, lastEventId, options);\n\t\targs = {\n\t\t\ts: sessionKey,\n\t\t\ta: lastEventId\n\t\t};\n\t\tthis._makeRequest('comet', url + '/comet', \n\t\t\t\t\t\t args, \n\t\t\t\t\t\t this.cometSuccess, \n\t\t\t\t\t\t this.cometFailure);\n\t};\n\t\n\tthis.send = function(url, sessionKey, lastEventId, data, options) {\n\t\tlogger.debug('send:', url, sessionKey, data, options);\n\t\targs = {\n\t\t\td: data,\n\t\t\ts: sessionKey,\n\t\t\ta: lastEventId\n\t\t};\n\t\tthis._makeRequest('send', url + '/send', \n\t\t\t\t\t\t args, \n\t\t\t\t\t\t this.sendSuccess, \n\t\t\t\t\t\t this.sendFailure);\n\t};\n});\n\ntransports.xhr = Class(baseTransport, function(supr) {\n\t\n\tthis.init = function() {\n\t\tsupr(this, 'init');\n\t\n\t\tthis._xhr = {\n\t\t\t'send': new exports.XHR(),\n\t\t\t'comet': new exports.XHR()\n\t\t};\n\t};\n\n\tthis.abort = function() {\n\t\tthis._aborted = true;\n\t\tfor(var i in this._xhr) {\n\t\t\tif(this._xhr.hasOwnProperty(i)) {\n\t\t\t\tthis._abortXHR(i);\n\t\t\t}\n\t\t}\n\t};\n\t\n\tthis._abortXHR = function(type) {\n\t\tlogger.debug('aborting XHR');\n\n\t\tvar xhr = this._xhr[type];\n\t\ttry {\n\t\t\tif('onload' in xhr) {\n\t\t\t\txhr.onload = xhr.onerror = xhr.ontimeout = null;\n\t\t\t} else if('onreadystatechange' in xhr) {\n\t\t\t\txhr.onreadystatechange = null;\n\t\t\t}\n\t\t\tif(xhr.abort) { xhr.abort(); }\n\t\t} catch(e) {\n\t\t\tlogger.debug('error aborting xhr', e);\n\t\t}\n\t\t\n\t\t// do not reuse aborted XHRs\n\t\tthis._xhr[type] = new exports.XHR();\n\t};\n\t\n\tvar mustEncode = !(exports.createXHR().sendAsBinary);\n\tthis.encodePacket = function(packetId, data, options) {\n\t\t// we don't need to base64 encode things unless there's a null character in there\n\t\treturn mustEncode ? [ packetId, 1, base64.encode(data) ] : [ packetId, 0, data ];\n\t};\n\n\tthis._onReadyStateChange = function(rType, cb, eb) {\n\t\t\n\t\tvar response = '',\n\t\t\txhr = this._xhr[rType];\n\t\t\n\t\ttry {\n\t\t\tvar data = {status: xhr.status};\n\t\t} catch(e) { eb({response: 'Could not access status'}); }\n\t\t\n\t\ttry {\n\t\t\tif(xhr.readyState != 4) { return; }\n\t\t\t\n\t\t\tdata.response = eval(xhr.responseText);\n\t\t\tif(data.status != 200) { \n\t\t\t\tlogger.debug('XHR failed with status ', xhr.status);\n\t\t\t\teb(data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tlogger.debug('XHR data received');\n\t\t} catch(e) {\n\t\t\tlogger.debug('Error in XHR::onReadyStateChange', e);\n\t\t\teb(data);\n\t\t\tthis._abortXHR(rType);\n\t\t\tlogger.debug('done handling XHR error');\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tcb(data);\n\t};\n\n\t/**\n\t * even though we encode the POST body as in application/x-www-form-urlencoded\n\t */\n\tthis._makeRequest = function(rType, url, args, cb, eb) {\n\t\tif (this._aborted) {\n\t\t\treturn;\n\t\t}\n\t\tvar xhr = this._xhr[rType], data = args.d || null;\n\t\tif('d' in args) { delete args.d; }\n\t\txhr.open('POST', url + '?' + uri.buildQuery(args)); // must open XHR first\n\t\txhr.setRequestHeader('Content-Type', 'text/plain'); // avoid preflighting\n\t\tif('onload' in xhr) {\n\t\t\txhr.onload = bind(this, '_onReadyStateChange', rType, cb, eb);\n\t\t\txhr.onerror = xhr.ontimeout = eb;\n\t\t} else if('onreadystatechange' in xhr) {\n\t\t\txhr.onreadystatechange = bind(this, '_onReadyStateChange', rType, cb, eb);\n\t\t}\n\t\t// NOTE WELL: Firefox (and probably everyone else) likes to encode our nice\n\t\t//\t\t\t\t\t\tbinary strings as utf8. Don't let them! Say no to double utf8\n\t\t//\t\t\t\t\t\tencoding. Once is good, twice isn't better.\n\t\tvar supportsBinary = !!xhr.sendAsBinary;\n\t\tif (supportsBinary) {\n\t\t\t// xhr.setRequestHeader('x-CSP-SendAsBinary', 'true');\n\t\t}\n\t\tsetTimeout(bind(xhr, supportsBinary ? 'sendAsBinary' : 'send', data), 0);\n\t};\n});\n\nvar EMPTY_FUNCTION = function() {},\n\tSLICE = Array.prototype.slice;\n\ntransports.jsonp = Class(baseTransport, function(supr) {\n\tvar doc;\n\t\n\tvar createIframe = function() {\n\t\tvar doc = exports.getDoc();\n\t\tif (!doc.body) { return false; }\n\t\t\n\t\tvar i = doc.createElement(\"iframe\");\n\t\twith(i.style) { display = 'block'; width = height = border = margin = padding = '0'; overflow = visibility = 'hidden'; position = 'absolute'; top = left = '-999px'; }\n\t\ti.cbId = 0;\n\t\tdoc.body.appendChild(i);\n\t\ti.src = 'javascript:var d=document;d.open();d.write(\"\");d.close();';\n\t\treturn i;\n\t};\n\n\tvar cleanupIframe = function(ifr) {\n\t\tvar win = ifr.contentWindow, doc = win.document;\n\t\tlogger.debug('removing script tags');\n\t\t\n\t\tvar scripts = doc.getElementsByTagName('script');\n\t\tfor (var i = scripts.length - 1; i >= 0; --i) {\n\t\t\tdoc.body.removeChild(scripts[i]);\n\t\t}\n\t\t\n\t\tlogger.debug('deleting iframe callbacks');\n\t\twin['cb' + ifr.cbId] = win['eb' + ifr.cbId] = EMPTY_FUNCTION;\n\t};\n\n\tvar removeIframe = function(ifr) {\n\t\t$setTimeout(function() {\n\t\t\tif(ifr && ifr.parentNode) { ifr.parentNode.removeChild(ifr); }\n\t\t}, 60000);\n\t};\n\n\tthis.init = function() {\n\t\tsupr(this, 'init');\n\n\t\tthis._onReady = [];\n\t\tthis._isReady = false;\n\n\t\tthis._createIframes();\n\t};\n\n\tthis._createIframes = function() {\n\t\tthis._ifr = {\n\t\t\tsend: createIframe(),\n\t\t\tcomet: createIframe()\n\t\t};\n\t\t\n\t\tif(this._ifr.send === false) { return $setTimeout(bind(this, '_createIframes'), 100); }\n\t\t\n\t\tthis._isReady = true;\n\n\t\tvar readyArgs = this._onReady;\n\t\tthis._onReady = [];\n\t\tfor(var i = 0, args; args = readyArgs[i]; ++i) {\n\t\t\tthis._makeRequest.apply(this, args);\n\t\t}\n\t};\n\n\tthis.encodePacket = function(packetId, data, options) {\n\t\treturn [ packetId, 1, base64.encode(data) ];\n\t};\n\n\tthis.abort = function() {\n\t\tthis._aborted = true;\n\t\tfor(var i in this._ifr) {\n\t\t\tif(this._ifr.hasOwnProperty(i)) {\n\t\t\t\tvar ifr = this._ifr[i];\n\t\t\t\tcleanupIframe(ifr);\n\t\t\t\tremoveIframe(ifr);\n\t\t\t}\n\t\t}\n\t};\n\t\n\tthis._makeRequest = function(rType, url, args, cb, eb) {\n\t\tif(!this._isReady) { return this._onReady.push(arguments); }\n\t\t\n\t\tvar ifr = this._ifr[rType],\n\t\t\tid = ++ifr.cbId,\n\t\t\treq = {\n\t\t\t\ttype: rType,\n\t\t\t\tid: id,\n\t\t\t\tcb: cb,\n\t\t\t\teb: eb,\n\t\t\t\tcbName: 'cb' + id,\n\t\t\t\tebName: 'eb' + id,\n\t\t\t\tcompleted: false\n\t\t\t};\n\t\t\n\t\targs.n = Math.random();\t\n\t\tswitch(rType) {\n\t\t\tcase 'send': args.rs = ';'; args.rp = req.cbName; break;\n\t\t\tcase 'comet': args.bs = ';'; args.bp = req.cbName; break;\n\t\t}\n\t\t\n\t\treq.url = url + '?' + uri.buildQuery(args)\n\t\t\n\t\t$setTimeout(bind(this, '_request', req), 0);\n\t}\n\t\n\tthis._request = function(req) {\n\t\tvar ifr = this._ifr[req.type],\n\t\t\twin = ifr.contentWindow,\n\t\t\tdoc = win.document,\n\t\t\tbody = doc.body;\n\n\t\twin[req.ebName] = bind(this, checkForError, req);\n\t\twin[req.cbName] = bind(this, onSuccess, req);\n\t\t\n\t\tif(BrowserDetect.isWebKit) {\n\t\t\t// this will probably cause loading bars in Safari -- might want to rethink?\n\t\t\tdoc.open();\n\t\t\tdoc.write(''+ebName+'(false)');\n\t\t\tdoc.close();\n\t\t} else {\n\t\t\tvar s = doc.createElement('script');\n\t\t\ts.src = req.url;\n\t\t\t\n\t\t\t// IE\n\t\t\tif(s.onreadystatechange === null) { s.onreadystatechange = bind(this, onReadyStateChange, req, s); }\n\t\t\tbody.appendChild(s);\n\t\t\t\n\t\t\tif(!BrowserDetect.isIE) {\n\t\t\t\tvar s = doc.createElement('script');\n\t\t\t\ts.innerHTML = req.ebName+'(false)';\n\t\t\t\tbody.appendChild(s);\n\t\t\t}\n\t\t}\n\t\t\n\t\tkillLoadingBar();\n\t};\n\t\n\tfunction onSuccess(req, response) {\n\t\tlogger.debug('successful: ', req.url, response);\n\t\treq.completed = true;\n\t\t\n\t\tlogger.debug('calling the cb');\n\t\treq.cb.call(GLOBAL, {status: 200, response: response});\n\t\tlogger.debug('cb called');\n\t}\n\t\n\t// IE6/7 onReadyStateChange\n\tfunction onReadyStateChange(req, scriptTag) {\n\t\tif (scriptTag && scriptTag.readyState != 'loaded') { return; }\n\t\tscriptTag.onreadystatechange = function() {};\n\t\tcheckForError.call(this, req);\n\t}\n\n\tfunction checkForError(req, response) {\n\t\tcleanupIframe(this._ifr[req.type]);\n\t\t\n\t\tif (!req.completed) {\n\t\t\tvar data = {\n\t\t\t\tstatus: response ? 200 : 404,\n\t\t\t\tresponse: response || 'Unable to load resouce'\n\t\t\t};\n\t\t\t\n\t\t\tlogger.debug('error making request:', req.url, data);\n\t\t\tlogger.debug('calling eb');\n\t\t\treq.eb.call(GLOBAL, data);\n\t\t}\n\t}\n\t\n\tvar killLoadingBar = BrowserDetect.isFirefox ? function() {\n\t\tvar b = document.body;\n\t\tif (!b) { return; }\n\t\t\n\t\tif (!killLoadingBar.iframe) { killLoadingBar.iframe = document.createElement('iframe'); }\n\t\tb.insertBefore(killLoadingBar.iframe, b.firstChild);\n\t\tb.removeChild(killLoadingBar.iframe);\n\t} : function() {};\n});\n\t\n", "filePath": "jsio/net/csp/transports.js"}, 'net': {"src": "jsio('import net.env');\njsio('import std.JSON as JSON');\n\nJSON.createGlobal(); // create the global JSON object if it doesn't already exist\n\nexports.listen = function(server, transportName, opts) {\n\tif (!transportName) {\n\t\tthrow logger.error('No transport provided for net.listen');\n\t}\n\tvar listenerClass = net.env.getListener(transportName);\n\tvar listener = new listenerClass(server, opts);\n\tlistener.listen();\n\treturn listener;\n}\n\nexports.connect = function(protocolInstance, transportName, opts) {\n\tvar ctor = net.env.getConnector(transportName),\n\t\tconnector = new ctor(protocolInstance, opts);\n\t\n\tconnector.connect();\n\treturn connector;\n}\n\nexports.quickServer = function(protocolClass) {\n\tjsio('import net.interfaces');\n\treturn new net.interfaces.Server(protocolClass);\n}\n", "filePath": "jsio/net.js"}, diff --git a/hookbox/static/hookbox.min.js b/hookbox/static/hookbox.min.js index a27148f..9c5cf37 100644 --- a/hookbox/static/hookbox.min.js +++ b/hookbox/static/hookbox.min.js @@ -19,7 +19,7 @@ filePath:"jsio/net/env/browser/websocket.js"},"net.protocols.rtjp":{src:'jsio("i filePath:"jsio/net/protocols/rtjp.js"},"net.csp.client":{src:'jsio("import std.base64 as base64");jsio("import std.utf8 as utf8");jsio("import std.uri as uri");jsio("import net.errors as errors");jsio("import .transports");jsio("import lib.Enum as Enum");var READYSTATE=exports.READYSTATE=Enum({INITIAL:0,CONNECTING:1,CONNECTED:2,DISCONNECTING:3,DISCONNECTED:4});\nexports.CometSession=Class(function(){var g=0;this.init=function(){this._id=++g;this._url=null;this.readyState=READYSTATE.INITIAL;this._options=this._transport=this._sessionKey=null;this._writeBuffer=this._utf8ReadBuffer="";this._handshakeLater=this._lastSentId=this._lastEventId=this._packetsInFlight=null;this._handshakeBackoff=50;this._timeoutTimer=this._handshakeTimeoutTimer=this._handshakeRetryTimer=null;this._cometBackoff=this._writeBackoff=50;this._nullReceived=this._nullSent=this._nullInFlight=\nthis._nullInBuffer=false};this.setEncoding=function(a){if(a!=this._options.encoding){if(a!="utf8"&&a!="plain")throw new errors.InvalidEncodingError;if(a=="plain"&&this._buffer){var b=this._utf8ReadBuffer;this._utf8ReadBuffer="";this._doOnRead(b)}this._options.encoding=a}};this.connect=function(a,b){this._url=a.replace(/\\/$/,"");this._options=b||{};this._options.encoding=this._options.encoding||"utf8";this.setEncoding(this._options.encoding);this._options.connectTimeout=this._options.connectTimeout||\n1E4;this._transport=new (transports.chooseTransport(a,this._options));this._transport.handshakeFailure=bind(this,this._handshakeFailure);this._transport.handshakeSuccess=bind(this,this._handshakeSuccess);this._transport.cometFailure=bind(this,this._cometFailure);this._transport.cometSuccess=bind(this,this._cometSuccess);this._transport.sendFailure=bind(this,this._writeFailure);this._transport.sendSuccess=bind(this,this._writeSuccess);this.readyState=READYSTATE.CONNECTING;this._transport.handshake(this._url,\nthis._options);this._handshakeTimeoutTimer=$setTimeout(bind(this,this._handshakeTimeout),this._options.connectTimeout)};this.write=function(a,b){if(this.readyState!=READYSTATE.CONNECTED)throw new errors.ReadyStateError;b=b||this._options.encoding||"utf8";if(b=="utf8")a=utf8.encode(a);this._writeBuffer+=a;this._doWrite()};this._protocolError=function(a){logger.debug("_protocolError",a);this.readyState=READYSTATE.DISCONNECTED;this._doWrite(true);this._doOnDisconnect(new errors.ServerProtocolError(a))};\nthis._receivedNullPacket=function(){logger.debug("_receivedNullPacket");this._receivedNull=true;if(this._nullInFlight||this._nullInBuffer||this._nullSent)this.readyState=READYSTATE.DISCONNECTED;else{this.readyState=READYSTATE.DISCONNECTING;this._doWrite(true)}this._doOnDisconnect(new errors.ConnectionClosedCleanly)};this._sentNullPacket=function(){logger.debug("_sentNullPacket");if((this._nullSent=true)&&this._nullReceived)this.readyState=READYSTATE.DISCONNECTED};this.close=function(a){logger.debug("close called",\na,"readyState",this.readyState);switch(this.readyState){case READYSTATE.CONNECTING:clearTimeout(this._handshakeRetryTimer);clearTimeout(this._handshakeTimeoutTimer);this.readyState=READYSTATE.DISCONNECTED;this._doOnDisconnect(a);break;case READYSTATE.CONNECTED:this.readyState=READYSTATE.DISCONNECTING;this._doWrite(true);clearTimeout(this._timeoutTimer);break;case READYSTATE.DISCONNECTED:throw new errors.ReadyStateError("Session is already disconnected");}this._sessionKey=null;this._opened=false;this.readyState=\nREADYSTATE.DISCONNECTED;this._doOnDisconnect(a)};this._handshakeTimeout=function(){logger.debug("handshake timeout");this._handshakeTimeoutTimer=null;this._doOnDisconnect(new errors.ServerUnreachable)};this._handshakeSuccess=function(a){logger.debug("handshake success",a);if(this.readyState!=READYSTATE.CONNECTING)logger.debug("received handshake success in invalid readyState:",this.readyState);else{clearTimeout(this._handshakeTimeoutTimer);this._handshakeTimeoutTimer=null;this._sessionKey=a.response.session;\nthis._opened=true;this.readyState=READYSTATE.CONNECTED;this._doOnConnect();this._doConnectComet()}};this._handshakeFailure=function(a){logger.debug("handshake failure",a);if(this.readyState==READYSTATE.CONNECTING){if(a.status==404){clearTimeout(this._handshakeTimeoutTimer);return this._doOnDisconnect(new errors.ServerUnreachable)}logger.debug("trying again in ",this._handshakeBackoff);this._handshakeRetryTimer=$setTimeout(bind(this,function(){this._handshakeRetryTimer=null;this._transport.handshake(this._url,\nthis._options)}),this._handshakeBackoff);this._handshakeBackoff*=2}};this._writeSuccess=function(){if(!(this.readyState!=READYSTATE.CONNECTED&&this.readyState!=READYSTATE.DISCONNECTING)){if(this._nullInFlight)return this._sentNullPacket();this._resetTimeoutTimer();this.writeBackoff=50;this._packetsInFlight=null;if(this._writeBuffer||this._nullInBuffer)this._doWrite(this._nullInBuffer)}};this._writeFailure=function(){if(!(this.readyState!=READYSTATE.CONNECTED&&this.READYSTATE!=READYSTATE.DISCONNECTING)){this._writeTimer=\n$setTimeout(bind(this,function(){this._writeTimer=null;this.__doWrite(this._nullInBuffer)}),this._writeBackoff);this._writeBackoff*=2}};this._doWrite=function(a){if(this._packetsInFlight){if(a)this._nullInBuffer=true}else this.__doWrite(a)};this.__doWrite=function(a){logger.debug("_writeBuffer:",this._writeBuffer);if(!this._packetsInFlight&&this._writeBuffer){this._packetsInFlight=[this._transport.encodePacket(++this._lastSentId,this._writeBuffer,this._options)];this._writeBuffer=""}if(a&&!this._writeBuffer){if(!this._packetsInFlight)this._packetsInFlight=\n[];this._packetsInFlight.push([++this._lastSentId,0,null]);this._nullInFlight=true}if(this._packetsInFlight){logger.debug("sending packets:",JSON.stringify(this._packetsInFlight));this._transport.send(this._url,this._sessionKey,this._lastEventId||0,JSON.stringify(this._packetsInFlight),this._options)}else logger.debug("no packets to send")};this._doConnectComet=function(){logger.debug("_doConnectComet");this._transport.comet(this._url,this._sessionKey,this._lastEventId||0,this._options)};this._cometFailure=\nfunction(a){if(this.readyState==READYSTATE.CONNECTED){if(a.status==404&&a.response=="Session not found")return this.close(new errors.ExpiredSession(a));this._cometTimer=$setTimeout(bind(this,function(){this._doConnectComet()}),this._cometBackoff);this._cometBackoff*=2}};this._cometSuccess=function(a){if(!(this.readyState!=READYSTATE.CONNECTED&&this.readyState!=READYSTATE.DISCONNECTING)){logger.debug("comet Success:",a);this._cometBackoff=50;this._resetTimeoutTimer();for(var b=a.response,d=0,c;(c=\nb[d])||d2){var d=Array.prototype.slice.call(arguments,2);return typeof b=="string"?function(){if(a[b])return a[b].apply(a,d.concat(Array.prototype.slice.call(arguments,0)));else throw logger.error("No method:",b,"for context",a);}:function(){return b.apply(a,d.concat(Array.prototype.slice.call(arguments,0)))}}else return typeof b=="string"?function(){if(a[b])return a[b].apply(a,arguments);else throw logger.error("No method:",b,"for context",a);}:function(){return b.apply(a,\narguments)}};\nexports.Class=function(a,b){if(!a)throw Error("parent or prototype not provided");if(b)if(a instanceof Array){b.prototype={};for(var d=0,f;f=a[d];++d)for(var c in f.prototype)c in b.prototype||(b.prototype[c]=f.prototype[c]);a=a[0]}else b.prototype=a.prototype;else{b=a;a=null}d=function(){if(this.init)return this.init.apply(this,arguments)};d.prototype=new b(a?function(g,e,h){h=h||[];for(var i=b;i=i.prototype;)if(i[e])return i[e].apply(g,h);throw Error("method "+e+" does not exist");}:null);return d.prototype.constructor=\nd};exports.$setTimeout=function(a,b){var d=Array.prototype.slice.call(arguments,2);return setTimeout(function(){try{a.apply(this,d)}catch(f){}},b)};exports.$setInterval=function(a,b){var d=Array.prototype.slice.call(arguments,2);return setInterval(function(){try{a.apply(this,d)}catch(f){}},b)};exports.$clearTimeout=function(a){return a?clearTimeout(a):null};exports.$clearInterval=function(a){return a?clearInterval(a):null};\nexports.logging=function(){var a={DEBUG:1,LOG:2,INFO:3,WARN:4,ERROR:5},b={},d=false;a.setProduction=function(c){d=!!c};a.get=function(c){return b.hasOwnProperty(c)?b[c]:b[c]=new f(c)};a.set=function(c,g){b[c]=g};a.getAll=function(){return b};a.__create=function(c,g){g.logger=a.get(c)};var f=exports.Class(function(){function c(e,h){return function(){if(!d&&e>=this._level)return this._listener.apply(this._listener,[h,this._name].concat(g.call(arguments)));return arguments[0]}}this.init=function(e,h){this._name=\ne;this._level=h||a.LOG;this._listener=exports.log};this.setLevel=function(e){this._level=e};var g=Array.prototype.slice;this.setListener=function(e){log=e};this.debug=c(a.DEBUG,"DEBUG");this.log=c(a.LOG,"LOG");this.info=c(a.INFO,"INFO");this.warn=c(a.WARN,"WARN");this.error=c(a.ERROR,"ERROR")});return a}();var logger=exports.logging.get("jsiocore");\n', -filePath:"jsio/base.js"},hookbox:{src:'jsio("from net import connect as jsioConnect");jsio("from net.protocols.rtjp import RTJPProtocol");exports.__jsio=jsio.__jsio;exports.logging=logging;logger.setLevel(0);exports.connect=function(d,a){d.match("/$")||(d+="/");var b=new HookBoxProtocol(d,a);if(window.WebSocket){jsioConnect(b,"websocket",{url:d.replace("http://","ws://")+"ws"});b.connectionLost=bind(b,"_connectionLost","websocket")}else{jsioConnect(b,"csp",{url:d+"csp"});b.connectionLost=bind(b,"_connectionLost","csp")}return b};\nvar Subscription=Class(function(){this.init=function(d,a){this.channelName=a.channel_name;this.history=a.history;this.historySize=a.history_size;this.state=a.state;this.presence=a.presence;this.canceled=false;this.publish=bind(d,"publish",this.channelName)};this.onPublish=function(){};this.onSubscribe=function(){};this.onUnsubscribe=function(){};this.onState=function(){};this.frame=function(d,a){logger.debug("received frame",d,a);switch(d){case "PUBLISH":if(this.historySize)for(this.history.push(["PUBLISH",\n{user:a.user,payload:a.payload}]);this.history.length>this.historySize;)this.history.shift();this.onPublish(a);break;case "UNSUBSCRIBE":if(this.historySize)for(this.history.push(["UNSUBSCRIBE",{user:a.user}]);this.history.length>this.historySize;)this.history.shift();for(var b=0,c;c=this.presence[b];++b)if(c==a.user){this.presence.splice(b,1);break}this.onUnsubscribe(a);break;case "SUBSCRIBE":if(this.historySize)for(this.history.push(["SUBSCRIBE",{user:a.user}]);this.history.length>this.historySize;)this.history.shift();\nthis.presence.push(a.user);this.onSubscribe(a);break;case "STATE_UPDATE":for(b=0;c=a.deletes[b];++b)delete this.state[c];for(c in a.updates)this.state[c]=a.updates[c];this.onState(a);break}};this.cancel=function(){if(!this.canceled){logger.debug("calling this._onCancel()");this._onCancel()}};this._onCancel=function(){}});\nHookBoxProtocol=Class([RTJPProtocol],function(d){this.onOpen=function(){};this.onClose=function(){};this.onError=function(){};this.onSubscribed=function(){};this.onUnsubscribed=function(){};this.onMessaged=function(){};this.init=function(a,b){d(this,"init",[]);this.url=a;try{this.cookieString=b||document.cookie}catch(c){this.cookieString=""}this.connected=false;this._subscriptions={};this._buffered_subs=[];this._publishes=[];this._messages=[];this._errors={};this.username=null};this.subscribe=function(a){this.connected?\nthis.sendFrame("SUBSCRIBE",{channel_name:a}):this._buffered_subs.push(a)};this.publish=function(a,b){this.connected?this.sendFrame("PUBLISH",{channel_name:a,payload:JSON.stringify(b)}):this._publishes.push([a,b])};this.message=function(a,b){this.connected?this.sendFrame("MESSAGE",{name:a,payload:JSON.stringify(b)}):this._messages.push([a,b])};this.connectionMade=function(){logger.debug("connectionMade");this.transport.setEncoding("utf8");this.sendFrame("CONNECT",{cookie_string:this.cookieString})};\nthis.frameReceived=function(a,b,c){switch(b){case "MESSAGE":this.onMessaged(c);break;case "CONNECTED":this.connected=true;for(this.username=c.name;this._buffered_subs.length;)this.sendFrame("SUBSCRIBE",{channel_name:this._buffered_subs.shift()});for(;this._publishes.length;)this.publish.apply(this,this._publishes.splice(0,1)[0]);for(;this._messages.length;)this.message.apply(this,this._messages.splice(0,1)[0]);this.onOpen();break;case "SUBSCRIBE":if(c.user==this.username){b=new Subscription(this,\nc);this._subscriptions[c.channel_name]=b;b._onCancel=bind(this,function(){this.sendFrame("UNSUBSCRIBE",{channel_name:c.channel_name})});this.onSubscribed(c.channel_name,b);K=b}else this._subscriptions[c.channel_name].frame(b,c);break;case "STATE_UPDATE":case "PUBLISH":a=this._subscriptions[c.channel_name];a.frame(b,c);break;case "UNSUBSCRIBE":a=this._subscriptions[c.channel_name];a.canceled=true;a.frame(b,c);if(c.user==this.username){delete this._subscriptions[c.channel_name];this.onUnsubscribed(a,\nc)}break;case "ERROR":this.onError(c);break;case "SET_COOKIE":document.cookie=c.cookie;break}};this._connectionLost=function(a,b,c){if(c){logger.debug("connectionLost");this.connected=false;this.onClose()}else{logger.debug("connectionFailed",a);if(a=="websocket"){logger.debug("retry with csp");this.connectionLost=bind(this,"_connectionLost","csp");jsioConnect(this,"csp",{url:this.url+"csp"})}}};this.disconnect=function(){this.transport.loseConnection()}});\n', +filePath:"jsio/base.js"},hookbox:{src:'jsio("from net import connect as jsioConnect");jsio("from net.protocols.rtjp import RTJPProtocol");exports.__jsio=jsio.__jsio;exports.logging=logging;logger.setLevel(0);exports.connect=function(d,a,c){d.match("/$")||(d+="/");a=new HookBoxProtocol(d,a,c);if(window.WebSocket){jsioConnect(a,"websocket",{url:d.replace("http://","ws://")+"ws"});a.connectionLost=bind(a,"_connectionLost","websocket")}else{jsioConnect(a,"csp",{url:d+"csp"});a.connectionLost=bind(a,"_connectionLost","csp")}return a};\nvar Subscription=Class(function(){this.init=function(d,a){this.channelName=a.channel_name;this.history=a.history;this.historySize=a.history_size;this.state=a.state;this.presence=a.presence;this.canceled=false;this.publish=bind(d,"publish",this.channelName)};this.onPublish=function(){};this.onSubscribe=function(){};this.onUnsubscribe=function(){};this.onState=function(){};this.frame=function(d,a){switch(d){case "PUBLISH":if(this.historySize)for(this.history.push(["PUBLISH",{user:a.user,payload:a.payload}]);this.history.length>\nthis.historySize;)this.history.shift();this.onPublish(a);break;case "UNSUBSCRIBE":if(this.historySize)for(this.history.push(["UNSUBSCRIBE",{user:a.user}]);this.history.length>this.historySize;)this.history.shift();for(var c=0,b;b=this.presence[c];++c)if(b==a.user){this.presence.splice(c,1);break}this.onUnsubscribe(a);break;case "SUBSCRIBE":if(this.historySize)for(this.history.push(["SUBSCRIBE",{user:a.user}]);this.history.length>this.historySize;)this.history.shift();this.presence.push(a.user);this.onSubscribe(a);\nbreak;case "STATE_UPDATE":for(c=0;b=a.deletes[c];++c)delete this.state[b];for(b in a.updates)this.state[b]=a.updates[b];this.onState(a);break}};this.cancel=function(){if(!this.canceled){logger.debug("calling this._onCancel()");this._onCancel()}};this._onCancel=function(){}});\nHookBoxProtocol=Class([RTJPProtocol],function(d){this.onOpen=function(){};this.onClose=function(){};this.onError=function(){};this.onSubscribed=function(){};this.onUnsubscribed=function(){};this.onMessaged=function(){};this.init=function(a,c,b){d(this,"init",[]);this.url=a;try{this.cookieString=b||document.cookie}catch(e){this.cookieString=""}this.connected=false;this._subscriptions={};this._buffered_subs=[];this._publishes=[];this._messages=[];this._errors={};this._connectPayload=c;this.username=\nnull};this.subscribe=function(a){this.connected?this.sendFrame("SUBSCRIBE",{channel_name:a}):this._buffered_subs.push(a)};this.publish=function(a,c){this.connected?this.sendFrame("PUBLISH",{channel_name:a,payload:JSON.stringify(c)}):this._publishes.push([a,c])};this.message=function(a,c){this.connected?this.sendFrame("MESSAGE",{name:a,payload:JSON.stringify(c)}):this._messages.push([a,c])};this.connectionMade=function(){logger.debug("connectionMade");this.transport.setEncoding("utf8");this.sendFrame("CONNECT",\n{cookie_string:this.cookieString,payload:JSON.stringify(this._connectPayload)})};this.frameReceived=function(a,c,b){logger.debug("received frame",c,b);switch(c){case "MESSAGE":this.onMessaged(b);break;case "CONNECTED":this.connected=true;for(this.username=b.name;this._buffered_subs.length;)this.sendFrame("SUBSCRIBE",{channel_name:this._buffered_subs.shift()});for(;this._publishes.length;)this.publish.apply(this,this._publishes.splice(0,1)[0]);for(;this._messages.length;)this.message.apply(this,this._messages.splice(0,\n1)[0]);this.onOpen(b);break;case "SUBSCRIBE":if(b.user==this.username){c=new Subscription(this,b);this._subscriptions[b.channel_name]=c;c._onCancel=bind(this,function(){this.sendFrame("UNSUBSCRIBE",{channel_name:b.channel_name})});this.onSubscribed(b.channel_name,c);K=c}else this._subscriptions[b.channel_name].frame(c,b);break;case "STATE_UPDATE":case "PUBLISH":a=this._subscriptions[b.channel_name];a.frame(c,b);break;case "UNSUBSCRIBE":a=this._subscriptions[b.channel_name];a.canceled=true;a.frame(c,\nb);if(b.user==this.username){delete this._subscriptions[b.channel_name];this.onUnsubscribed(a,b)}break;case "ERROR":this.onError(b);break;case "SET_COOKIE":document.cookie=b.cookie;break}};this._connectionLost=function(a,c,b){if(b){logger.debug("connectionLost");this.connected=false;this.onClose()}else{logger.debug("connectionFailed",a);if(a=="websocket"){logger.debug("retry with csp");this.connectionLost=bind(this,"_connectionLost","csp");jsioConnect(this,"csp",{url:this.url+"csp"})}}};this.disconnect=\nfunction(){this.transport.loseConnection()}});\n', filePath:"hookbox.js"},"std.uri":{src:'var attrs=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];\nexports.Uri=Class(function(){this.init=function(a,b){var e=exports.parse(a,b);for(c in e)this["_"+c]=e[c]};for(var d=0,c;c=attrs[d];++d)(function(a){var b=a.charAt(0).toUpperCase()+a.slice(1);this["get"+b]=function(){return this["_"+a]};this["set"+b]=function(e){this["_"+a]=e}}).call(this,c);this.toString=this.render=function(){return(this._protocol?this._protocol+"://":"")+(this._host?this._host+((this._port||80)==80?"":":"+this._port):"")+this._path+(this._query?"?"+this._query:"")+(this._anchor?\n"#"+this._anchor:"")}});exports.buildQuery=function(d){var c=[];for(key in d)c.push(encodeURIComponent(key)+"="+encodeURIComponent(d[key]));return c.join("&")};exports.parseQuery=function(d){d=d.split("&");for(var c=d.length,a={},b=0;b");c.close();window.attachEvent("onunload",function(){try{c.body.innerHTML=""}catch(e){}c=null})}}catch(d){}c||(c=document);return c};exports.XHR=function(){var d=window;exports.getDoc();return new (exports.XHR=d.XMLHttpRequest?d.XMLHttpRequest:function(){return d.ActiveXObject&&new d.ActiveXObject("Msxml2.XMLHTTP")||null})};exports.createXHR=function(){return new exports.XHR}})();\nfunction isLocalFile(c){return/^file:\\/\\//.test(c)}function isWindowDomain(c){return uri.isSameDomain(c,window.location.href)}function canUseXHR(c){if(isLocalFile(c))return false;var d=new exports.XHR;if(!d)return false;if(isWindowDomain(c))return true;if(window.XMLHttpRequest&&(d.__proto__==XMLHttpRequest.prototype||d instanceof window.XMLHttpRequest)&&d.withCredentials!==undefined||window.XDomainRequest&&d instanceof window.XDomainRequest)return true}var transports=exports.transports={};\nexports.chooseTransport=function(c,d){switch(d.preferredTransport){case "jsonp":return transports.jsonp;case "xhr":default:if(canUseXHR(c))return transports.xhr;return transports.jsonp}};var PARAMS={xhrstream:{is:"1",bs:"\\n"},xhrpoll:{du:"0"},xhrlongpoll:{},sselongpoll:{bp:"data: ",bs:"\\r\\n",se:"1"},ssestream:{bp:"data: ",bs:"\\r\\n",se:"1",is:"1"}};\nexports.Transport=Class(function(){this.handshake=function(){throw Error("handshake Not Implemented");};this.comet=function(){throw Error("comet Not Implemented");};this.send=function(){throw Error("send Not Implemented");};this.encodePacket=function(){throw Error("encodePacket Not Implemented");};this.abort=function(){throw Error("abort Not Implemented");}});\nvar baseTransport=Class(exports.Transport,function(){this.init=function(){this._aborted=false;this._handshakeArgs={d:"{}",ct:"application/javascript"}};this.handshake=function(c,d){logger.debug("handshake:",c,d);this._makeRequest("send",c+"/handshake",this._handshakeArgs,this.handshakeSuccess,this.handshakeFailure)};this.comet=function(c,d,e,f){logger.debug("comet:",c,d,e,f);args={s:d,a:e};this._makeRequest("comet",c+"/comet",args,this.cometSuccess,this.cometFailure)};this.send=function(c,d,e,f,i){logger.debug("send:",\nc,d,f,i);args={d:f,s:d,a:e};this._makeRequest("send",c+"/send",args,this.sendSuccess,this.sendFailure)}});\ntransports.xhr=Class(baseTransport,function(c){this.init=function(){c(this,"init");this._xhr={send:new exports.XHR,comet:new exports.XHR}};this.abort=function(){this._aborted=true;for(var e in this._xhr)this._xhr.hasOwnProperty(e)&&this._abortXHR(e)};this._abortXHR=function(e){logger.debug("aborting XHR");var f=this._xhr[e];try{if("onload"in f)f.onload=f.onerror=f.ontimeout=null;else if("onreadystatechange"in f)f.onreadystatechange=null;f.abort&&f.abort()}catch(i){logger.debug("error aborting xhr",\ni)}this._xhr[e]=new exports.XHR};var d=!exports.createXHR().sendAsBinary;this.encodePacket=function(e,f){return d?[e,1,base64.encode(f)]:[e,0,f]};this._onReadyStateChange=function(e,f,i){var k=this._xhr[e];try{var j={status:k.status}}catch(h){i({response:"Could not access status"})}try{if(k.readyState!=4)return;j.response=eval(k.responseText);if(j.status!=200){logger.debug("XHR failed with status ",k.status);i(j);return}logger.debug("XHR data received")}catch(a){logger.debug("Error in XHR::onReadyStateChange",\na);i(j);this._abortXHR(e);logger.debug("done handling XHR error");return}f(j)};this._makeRequest=function(e,f,i,k,j){if(!this._aborted){var h=this._xhr[e],a=i.d||null;"d"in i&&delete i.d;h.open("POST",f+"?"+uri.buildQuery(i));h.setRequestHeader("Content-Type","text/plain");if("onload"in h){h.onload=bind(this,"_onReadyStateChange",e,k,j);h.onerror=h.ontimeout=j}else if("onreadystatechange"in h)h.onreadystatechange=bind(this,"_onReadyStateChange",e,k,j);setTimeout(bind(h,h.sendAsBinary?"sendAsBinary":\n"send",a),0)}}});var EMPTY_FUNCTION=function(){},SLICE=Array.prototype.slice;\ntransports.jsonp=Class(baseTransport,function(c){function d(a,b){logger.debug("successful: ",a.url,b);a.completed=true;logger.debug("calling the cb");a.cb.call(GLOBAL,{status:200,response:b});logger.debug("cb called")}function e(a,b){if(!(b&&b.readyState!="loaded")){b.onreadystatechange=function(){};f.call(this,a)}}function f(a,b){k(this._ifr[a.type]);if(!a.completed){var g={status:b?200:404,response:b||"Unable to load resouce"};logger.debug("error making request:",a.url,g);logger.debug("calling eb");\na.eb.call(GLOBAL,g)}}var i=function(){var a=exports.getDoc();if(!a.body)return false;var b=a.createElement("iframe");with(b.style){display="block";width=height=border=margin=padding="0";overflow=visibility="hidden";position="absolute";top=left="-999px"}b.cbId=0;a.body.appendChild(b);b.src=\'javascript:var d=document;d.open();d.write("");d.close();\';return b},k=function(a){var b=a.contentWindow,g=b.document;logger.debug("removing script tags");for(var m=g.getElementsByTagName("script"),\nn=m.length-1;n>=0;--n)g.body.removeChild(m[n]);logger.debug("deleting iframe callbacks");b["cb"+a.cbId]=b["eb"+a.cbId]=EMPTY_FUNCTION},j=function(a){$setTimeout(function(){a&&a.parentNode&&a.parentNode.removeChild(a)},6E4)};this.init=function(){c(this,"init");this._onReady=[];this._isReady=false;this._createIframes()};this._createIframes=function(){this._ifr={send:i(),comet:i()};if(this._ifr.send===false)return $setTimeout(bind(this,"_createIframes"),100);this._isReady=true;var a=this._onReady;this._onReady=\n[];for(var b=0,g;g=a[b];++b)this._makeRequest.apply(this,g)};this.encodePacket=function(a,b){return[a,1,base64.encode(b)]};this.abort=function(){this._aborted=true;for(var a in this._ifr)if(this._ifr.hasOwnProperty(a)){var b=this._ifr[a];k(b);j(b)}};this._makeRequest=function(a,b,g,m,n){if(!this._isReady)return this._onReady.push(arguments);var l=++this._ifr[a].cbId;l={type:a,id:l,cb:m,eb:n,cbName:"cb"+l,ebName:"eb"+l,completed:false};g.n=Math.random();switch(a){case "send":g.rs=";";g.rp=l.cbName;\nbreak;case "comet":g.bs=";";g.bp=l.cbName;break}l.url=b+"?"+uri.buildQuery(g);$setTimeout(bind(this,"_request",l),0)};this._request=function(a){var b=this._ifr[a.type].contentWindow,g=b.document,m=g.body;b[a.ebName]=bind(this,f,a);b[a.cbName]=bind(this,d,a);if(BrowserDetect.isWebKit){g.open();g.write(\'