diff --git a/README.md b/README.md index f7092c01ff..941f106b4d 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,9 @@ This library exposes two API variants. Firstly, the original (and presently the For this library version, and for all future 1.x versions, the callback-based API will be the default, and the promises-based variant will need to be explicitly selected, to avoid breaking backwards compatibility. However, a move to the promises-based variant as the default is possible at the next major release. If you are not handling promises, and want a version of the library that will not start returning promises for calls where you don't pass a callback in future versions, you can explicitly require the callback variant. -#### Version: 1.1.7 +#### Version: 1.1.8 -The latest stable version of the Ably Javascript client library is version: 1.1.7 . +The latest stable version of the Ably Javascript client library is version: 1.1.8 . For complete API documentation, see the [Ably documentation](https://www.ably.io/documentation). diff --git a/bower.json b/bower.json index 61d02f1d75..21e68f016c 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "Ably", - "version": "1.1.7", + "version": "1.1.8", "homepage": "https://www.ably.io/", "authors": [ "Paddy Byers ", diff --git a/browser/fragments/license.js b/browser/fragments/license.js index ab0871fba4..9088f7b14c 100644 --- a/browser/fragments/license.js +++ b/browser/fragments/license.js @@ -1,7 +1,7 @@ /** * @license Copyright 2019, Ably * - * Ably JavaScript Library v1.1.7 + * Ably JavaScript Library v1.1.8 * https://github.com/ably/ably-js * * Ably Realtime Messaging diff --git a/browser/static/ably-commonjs.js b/browser/static/ably-commonjs.js index 0a0fa34e3e..d8a7029e68 100644 --- a/browser/static/ably-commonjs.js +++ b/browser/static/ably-commonjs.js @@ -1,7 +1,7 @@ /** * @license Copyright 2019, Ably * - * Ably JavaScript Library v1.1.7 + * Ably JavaScript Library v1.1.8 * https://github.com/ably/ably-js * * Ably Realtime Messaging @@ -4615,7 +4615,7 @@ Defaults.TIMEOUTS = { Defaults.httpMaxRetryCount = 3; Defaults.maxMessageSize = 65536; -Defaults.version = '1.1.7'; +Defaults.version = '1.1.8'; Defaults.libstring = Platform.libver + Defaults.version; Defaults.apiVersion = '1.1'; @@ -6264,6 +6264,7 @@ var ConnectionManager = (function() { this.lastActivity = null; this.mostRecentMsgId = null; this.forceFallbackHost = false; + this.connectCounter = 0; Logger.logAction(Logger.LOG_MINOR, 'Realtime.ConnectionManager()', 'started'); Logger.logAction(Logger.LOG_MICRO, 'Realtime.ConnectionManager()', 'requested transports = [' + (options.transports || Defaults.defaultTransports) + ']'); @@ -6656,7 +6657,7 @@ var ConnectionManager = (function() { var connectionKey = connectionDetails.connectionKey; if(connectionKey && this.connectionKey != connectionKey) { - this.setConnection(connectionId, connectionDetails, connectionPosition, true); + this.setConnection(connectionId, connectionDetails, connectionPosition, true, !!error); } /* Rebroadcast any new connectionDetails from the active transport, which @@ -6760,6 +6761,7 @@ var ConnectionManager = (function() { if((wasActive && noTransportsScheduledForActivation) || (wasActive && (state === 'failed') || (state === 'closed')) || (currentProtocol === null && wasPending && this.pendingTransports.length === 0)) { + /* If we're disconnected with a 5xx we need to try fallback hosts * (RTN14d), but (a) due to how the upgrade sequence works, the * host/transport selection sequence only cares about getting to @@ -6770,16 +6772,21 @@ var ConnectionManager = (function() { * setting an instance variable to force fallback hosts to be used (if * any) here. Bit of a kludge, but no real better alternatives without * rewriting the entire thing */ - if(state === 'disconnected' && error && error.statusCode > 500) { + if(state === 'disconnected' && error && error.statusCode > 500 && this.httpHosts.length > 1) { this.unpersistTransportPreference(); this.forceFallbackHost = true; + /* and try to connect again to try a fallback host without waiting for the usual 15s disconnectedRetryTimeout */ + this.notifyState({state: state, error: error, retryImmediately: true}); + return; } + /* TODO remove below line once realtime sends token errors as DISCONNECTEDs */ - if(state === 'failed' && Auth.isTokenErr(error)) { - state = 'disconnected' - } - this.notifyState({state: state, error: error}); - } else if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { + var newConnectionState = (state === 'failed' && Auth.isTokenErr(error)) ? 'disconnected' : state; + this.notifyState({state: newConnectionState, error: error}); + return; + } + + if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { /* If we were active but there is another transport scheduled for * activation, go into to the connecting state until that transport * activates and sets us back to connected. (manually starting the @@ -6834,13 +6841,17 @@ var ConnectionManager = (function() { }); }; - ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition) { + ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition, hasConnectionError) { /* if connectionKey changes but connectionId stays the same, then just a * transport change on the same connection. If connectionId changes, we're * on a new connection, with implications for msgSerial and channel state */ var self = this; - /* If no previous connectionId, don't reset the msgSerial as it may have been set by recover data */ - if(this.connectionId && (this.connectionId !== connectionId)) { + /* If no previous connectionId, don't reset the msgSerial as it may have + * been set by recover data (unless the recover failed) */ + var prevConnId = this.connectionid, + connIdChanged = prevConnId && (prevConnId !== connectionId), + recoverFailure = !prevConnId && hasConnectionError; + if(connIdChanged || recoverFailure) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.setConnection()', 'Resetting msgSerial'); this.msgSerial = 0; } @@ -7071,6 +7082,7 @@ var ConnectionManager = (function() { var retryImmediately = (state === 'disconnected' && (this.state === this.states.connected || this.state === this.states.synchronizing || + indicated.retryImmediately || (this.state === this.states.connecting && indicated.error && Auth.isTokenErr(indicated.error) && !(this.errorReason && Auth.isTokenErr(this.errorReason))))); @@ -7177,10 +7189,21 @@ var ConnectionManager = (function() { var auth = this.realtime.auth, self = this; + /* The point of the connectCounter mechanism is to ensure that the + * connection procedure can be cancelled. We want disconnectAllTransports + * to be able to stop any in-progress connection, even before it gets to + * the stage of having a pending (or even a proposed) transport that it can + * dispose() of. So we check that it's still current after any async stage, + * up until the stage that is synchronous with instantiating a transport */ + var connectCount = ++this.connectCounter; + var connect = function() { self.checkConnectionStateFreshness(); self.getTransportParams(function(transportParams) { - self.connectImpl(transportParams); + if(connectCount !== self.connectCounter) { + return; + } + self.connectImpl(transportParams, connectCount); }); }; @@ -7192,6 +7215,9 @@ var ConnectionManager = (function() { connect(); } else { var authCb = function(err) { + if(connectCount !== self.connectCounter) { + return; + } if(err) { self.actOnErrorFromAuthorize(err); } else { @@ -7202,7 +7228,7 @@ var ConnectionManager = (function() { /* Force a refetch of a new token */ auth._forceNewToken(null, null, authCb); } else { - auth._ensureValidAuthCredentials(authCb); + auth._ensureValidAuthCredentials(false, authCb); } } }; @@ -7226,7 +7252,7 @@ var ConnectionManager = (function() { * and dispatches accordingly. After a transport has been set pending, * tryATransport calls connectImpl to see if there's another stage to be done. * */ - ConnectionManager.prototype.connectImpl = function(transportParams) { + ConnectionManager.prototype.connectImpl = function(transportParams, connectCount) { var state = this.state.state; if(state !== this.states.connecting.state && state !== this.states.connected.state) { @@ -7241,7 +7267,7 @@ var ConnectionManager = (function() { } else if(this.transports.length > 1 && this.getTransportPreference()) { this.connectPreference(transportParams); } else { - this.connectBase(transportParams); + this.connectBase(transportParams, connectCount); } }; @@ -7300,13 +7326,16 @@ var ConnectionManager = (function() { * fallback hosts if applicable. * @param transportParams */ - ConnectionManager.prototype.connectBase = function(transportParams) { + ConnectionManager.prototype.connectBase = function(transportParams, connectCount) { var self = this, giveUp = function(err) { self.notifyState({state: self.states.connecting.failState, error: err}); }, candidateHosts = this.httpHosts.slice(), hostAttemptCb = function(fatal, transport) { + if(connectCount !== self.connectCounter) { + return; + } if(!transport && !fatal) { tryFallbackHosts(); } @@ -7333,6 +7362,9 @@ var ConnectionManager = (function() { * there is a problem with the ably host, or there is a general connectivity * problem */ Http.checkConnectivity(function(err, connectivity) { + if(connectCount !== self.connectCounter) { + return; + } /* we know err won't happen but handle it here anyway */ if(err) { giveUp(err); @@ -7503,6 +7535,9 @@ var ConnectionManager = (function() { ConnectionManager.prototype.disconnectAllTransports = function(exceptActive) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting all transports' + (exceptActive ? ' except the active transport' : '')); + /* This will prevent any connection procedure in an async part of one of its early stages from continuing */ + this.connectCounter++; + Utils.safeArrForEach(this.pendingTransports, function(transport) { Logger.logAction(Logger.LOG_MICRO, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting pending transport: ' + transport); if(transport) transport.disconnect(); @@ -7826,6 +7861,7 @@ var Transport = (function() { this.format = params.format; this.isConnected = false; this.isFinished = false; + this.isDisposed = false; this.maxIdleInterval = null; this.idleTimer = null; this.lastActivity = null; @@ -7981,6 +8017,7 @@ var Transport = (function() { Transport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'Transport.dispose()', ''); + this.isDisposed = true; this.off(); }; @@ -8072,6 +8109,9 @@ var WebSocketTransport = (function() { var wsUri = wsScheme + this.wsHost + ':' + Defaults.getPort(options) + '/'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'uri: ' + wsUri); this.auth.getAuthParams(function(err, authParams) { + if(self.isDisposed) { + return; + } var paramStr = ''; for(var param in authParams) paramStr += ' ' + param + ': ' + authParams[param] + ';'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'authParams:' + paramStr + ' err: ' + err); if(err) { @@ -8167,6 +8207,7 @@ var WebSocketTransport = (function() { WebSocketTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.dispose()', ''); + this.isDisposed = true; var wsConnection = this.wsConnection; if(wsConnection) { /* Ignore any messages that come through after dispose() is called but before @@ -8230,7 +8271,6 @@ var CometTransport = (function() { this.recvRequest = null; this.pendingCallback = null; this.pendingItems = null; - this.disposed = false; } Utils.inherits(CometTransport, Transport); @@ -8256,6 +8296,9 @@ var CometTransport = (function() { self.disconnect(err); return; } + if(self.isDisposed) { + return; + } self.authParams = authParams; var connectParams = self.params.getConnectParams(authParams); if('stream' in connectParams) self.stream = connectParams.stream; @@ -8332,8 +8375,8 @@ var CometTransport = (function() { CometTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', ''); - if(!this.disposed) { - this.disposed = true; + if(!this.isDisposed) { + this.isDisposed = true; if(this.recvRequest) { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', 'aborting recv request'); this.recvRequest.abort(); @@ -8351,7 +8394,9 @@ var CometTransport = (function() { CometTransport.prototype.onConnect = function(message) { /* if this transport has been disposed whilst awaiting connection, do nothing */ - if(this.disposed) return; + if(this.isDisposed) { + return; + } /* the connectionKey in a comet connected response is really * - */ @@ -8954,10 +8999,16 @@ var Auth = (function() { !options.authUrl; } + var trId = 0; + function getTokenRequestId() { + return trId++; + } + function Auth(client, options) { this.client = client; this.tokenParams = options.defaultTokenParams || {}; - this.tokenRequestInProgress = false; + /* The id of the current token request if one is in progress, else null */ + this.currentTokenRequestId = null; this.waitingForTokenRequest = null; if(useTokenAuth(options)) { @@ -9057,7 +9108,7 @@ var Auth = (function() { /* RSA10a: authorize() call implies token auth. If a key is passed it, we * just check if it doesn't clash and assume we're generating a token from it */ - if(authOptions && authOptions.key && (this.key !== authOptions.key)) { + if(authOptions && authOptions.key && (this.authOptions.key !== authOptions.key)) { throw new ErrorInfo('Unable to update auth options with incompatible key', 40102, 401); } @@ -9109,7 +9160,7 @@ var Auth = (function() { logAndValidateTokenAuthMethod(this.authOptions); - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(true, function(err, tokenDetails) { /* RSA10g */ delete self.tokenParams.timestamp; delete self.authOptions.queryTime; @@ -9472,7 +9523,7 @@ var Auth = (function() { if(this.method == 'basic') callback(null, {key: this.key}); else - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9489,7 +9540,7 @@ var Auth = (function() { if(this.method == 'basic') { callback(null, {authorization: 'Basic ' + this.basicKey}); } else { - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9560,15 +9611,12 @@ var Auth = (function() { } }; - Auth.prototype._ensureValidAuthCredentials = function(callback) { + /* @param forceSupersede: force a new token request even if there's one in + * progress, making all pending callbacks wait for the new one */ + Auth.prototype._ensureValidAuthCredentials = function(forceSupersede, callback) { var self = this, token = this.tokenDetails; - if(this.tokenRequestInProgress) { - (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); - return; - } - if(token) { if(this._tokenClientIdMismatch(token.clientId)) { /* 403 to trigger a permanently failed client - RSA15c */ @@ -9588,21 +9636,26 @@ var Auth = (function() { this.tokenDetails = null; } + (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); + if(this.currentTokenRequestId !== null && !forceSupersede) { + return; + } + /* Request a new token */ - this.tokenRequestInProgress = true; + var tokenRequestId = this.currentTokenRequestId = getTokenRequestId(); this.requestToken(this.tokenParams, this.authOptions, function(err, tokenResponse) { - self.tokenRequestInProgress = false; - var waiting = self.waitingForTokenRequest; - if(waiting) { - waiting.push(callback); - callback = waiting; - self.waitingForTokenRequest = null; + if(self.currentTokenRequestId > tokenRequestId) { + Logger.logAction(Logger.LOG_MINOR, 'Auth._ensureValidAuthCredentials()', 'Discarding token request response; overtaken by newer one'); + return; } + self.currentTokenRequestId = null; + var callbacks = self.waitingForTokenRequest || noop; + self.waitingForTokenRequest = null; if(err) { - callback(err); + callbacks(err); return; } - callback(null, (self.tokenDetails = tokenResponse)); + callbacks(null, (self.tokenDetails = tokenResponse)); }); }; diff --git a/browser/static/ably-commonjs.noencryption.js b/browser/static/ably-commonjs.noencryption.js index f1c1904610..20f7936651 100644 --- a/browser/static/ably-commonjs.noencryption.js +++ b/browser/static/ably-commonjs.noencryption.js @@ -1,7 +1,7 @@ /** * @license Copyright 2019, Ably * - * Ably JavaScript Library v1.1.7 + * Ably JavaScript Library v1.1.8 * https://github.com/ably/ably-js * * Ably Realtime Messaging @@ -3181,7 +3181,7 @@ Defaults.TIMEOUTS = { Defaults.httpMaxRetryCount = 3; Defaults.maxMessageSize = 65536; -Defaults.version = '1.1.7'; +Defaults.version = '1.1.8'; Defaults.libstring = Platform.libver + Defaults.version; Defaults.apiVersion = '1.1'; @@ -4830,6 +4830,7 @@ var ConnectionManager = (function() { this.lastActivity = null; this.mostRecentMsgId = null; this.forceFallbackHost = false; + this.connectCounter = 0; Logger.logAction(Logger.LOG_MINOR, 'Realtime.ConnectionManager()', 'started'); Logger.logAction(Logger.LOG_MICRO, 'Realtime.ConnectionManager()', 'requested transports = [' + (options.transports || Defaults.defaultTransports) + ']'); @@ -5222,7 +5223,7 @@ var ConnectionManager = (function() { var connectionKey = connectionDetails.connectionKey; if(connectionKey && this.connectionKey != connectionKey) { - this.setConnection(connectionId, connectionDetails, connectionPosition, true); + this.setConnection(connectionId, connectionDetails, connectionPosition, true, !!error); } /* Rebroadcast any new connectionDetails from the active transport, which @@ -5326,6 +5327,7 @@ var ConnectionManager = (function() { if((wasActive && noTransportsScheduledForActivation) || (wasActive && (state === 'failed') || (state === 'closed')) || (currentProtocol === null && wasPending && this.pendingTransports.length === 0)) { + /* If we're disconnected with a 5xx we need to try fallback hosts * (RTN14d), but (a) due to how the upgrade sequence works, the * host/transport selection sequence only cares about getting to @@ -5336,16 +5338,21 @@ var ConnectionManager = (function() { * setting an instance variable to force fallback hosts to be used (if * any) here. Bit of a kludge, but no real better alternatives without * rewriting the entire thing */ - if(state === 'disconnected' && error && error.statusCode > 500) { + if(state === 'disconnected' && error && error.statusCode > 500 && this.httpHosts.length > 1) { this.unpersistTransportPreference(); this.forceFallbackHost = true; + /* and try to connect again to try a fallback host without waiting for the usual 15s disconnectedRetryTimeout */ + this.notifyState({state: state, error: error, retryImmediately: true}); + return; } + /* TODO remove below line once realtime sends token errors as DISCONNECTEDs */ - if(state === 'failed' && Auth.isTokenErr(error)) { - state = 'disconnected' - } - this.notifyState({state: state, error: error}); - } else if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { + var newConnectionState = (state === 'failed' && Auth.isTokenErr(error)) ? 'disconnected' : state; + this.notifyState({state: newConnectionState, error: error}); + return; + } + + if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { /* If we were active but there is another transport scheduled for * activation, go into to the connecting state until that transport * activates and sets us back to connected. (manually starting the @@ -5400,13 +5407,17 @@ var ConnectionManager = (function() { }); }; - ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition) { + ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition, hasConnectionError) { /* if connectionKey changes but connectionId stays the same, then just a * transport change on the same connection. If connectionId changes, we're * on a new connection, with implications for msgSerial and channel state */ var self = this; - /* If no previous connectionId, don't reset the msgSerial as it may have been set by recover data */ - if(this.connectionId && (this.connectionId !== connectionId)) { + /* If no previous connectionId, don't reset the msgSerial as it may have + * been set by recover data (unless the recover failed) */ + var prevConnId = this.connectionid, + connIdChanged = prevConnId && (prevConnId !== connectionId), + recoverFailure = !prevConnId && hasConnectionError; + if(connIdChanged || recoverFailure) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.setConnection()', 'Resetting msgSerial'); this.msgSerial = 0; } @@ -5637,6 +5648,7 @@ var ConnectionManager = (function() { var retryImmediately = (state === 'disconnected' && (this.state === this.states.connected || this.state === this.states.synchronizing || + indicated.retryImmediately || (this.state === this.states.connecting && indicated.error && Auth.isTokenErr(indicated.error) && !(this.errorReason && Auth.isTokenErr(this.errorReason))))); @@ -5743,10 +5755,21 @@ var ConnectionManager = (function() { var auth = this.realtime.auth, self = this; + /* The point of the connectCounter mechanism is to ensure that the + * connection procedure can be cancelled. We want disconnectAllTransports + * to be able to stop any in-progress connection, even before it gets to + * the stage of having a pending (or even a proposed) transport that it can + * dispose() of. So we check that it's still current after any async stage, + * up until the stage that is synchronous with instantiating a transport */ + var connectCount = ++this.connectCounter; + var connect = function() { self.checkConnectionStateFreshness(); self.getTransportParams(function(transportParams) { - self.connectImpl(transportParams); + if(connectCount !== self.connectCounter) { + return; + } + self.connectImpl(transportParams, connectCount); }); }; @@ -5758,6 +5781,9 @@ var ConnectionManager = (function() { connect(); } else { var authCb = function(err) { + if(connectCount !== self.connectCounter) { + return; + } if(err) { self.actOnErrorFromAuthorize(err); } else { @@ -5768,7 +5794,7 @@ var ConnectionManager = (function() { /* Force a refetch of a new token */ auth._forceNewToken(null, null, authCb); } else { - auth._ensureValidAuthCredentials(authCb); + auth._ensureValidAuthCredentials(false, authCb); } } }; @@ -5792,7 +5818,7 @@ var ConnectionManager = (function() { * and dispatches accordingly. After a transport has been set pending, * tryATransport calls connectImpl to see if there's another stage to be done. * */ - ConnectionManager.prototype.connectImpl = function(transportParams) { + ConnectionManager.prototype.connectImpl = function(transportParams, connectCount) { var state = this.state.state; if(state !== this.states.connecting.state && state !== this.states.connected.state) { @@ -5807,7 +5833,7 @@ var ConnectionManager = (function() { } else if(this.transports.length > 1 && this.getTransportPreference()) { this.connectPreference(transportParams); } else { - this.connectBase(transportParams); + this.connectBase(transportParams, connectCount); } }; @@ -5866,13 +5892,16 @@ var ConnectionManager = (function() { * fallback hosts if applicable. * @param transportParams */ - ConnectionManager.prototype.connectBase = function(transportParams) { + ConnectionManager.prototype.connectBase = function(transportParams, connectCount) { var self = this, giveUp = function(err) { self.notifyState({state: self.states.connecting.failState, error: err}); }, candidateHosts = this.httpHosts.slice(), hostAttemptCb = function(fatal, transport) { + if(connectCount !== self.connectCounter) { + return; + } if(!transport && !fatal) { tryFallbackHosts(); } @@ -5899,6 +5928,9 @@ var ConnectionManager = (function() { * there is a problem with the ably host, or there is a general connectivity * problem */ Http.checkConnectivity(function(err, connectivity) { + if(connectCount !== self.connectCounter) { + return; + } /* we know err won't happen but handle it here anyway */ if(err) { giveUp(err); @@ -6069,6 +6101,9 @@ var ConnectionManager = (function() { ConnectionManager.prototype.disconnectAllTransports = function(exceptActive) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting all transports' + (exceptActive ? ' except the active transport' : '')); + /* This will prevent any connection procedure in an async part of one of its early stages from continuing */ + this.connectCounter++; + Utils.safeArrForEach(this.pendingTransports, function(transport) { Logger.logAction(Logger.LOG_MICRO, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting pending transport: ' + transport); if(transport) transport.disconnect(); @@ -6392,6 +6427,7 @@ var Transport = (function() { this.format = params.format; this.isConnected = false; this.isFinished = false; + this.isDisposed = false; this.maxIdleInterval = null; this.idleTimer = null; this.lastActivity = null; @@ -6547,6 +6583,7 @@ var Transport = (function() { Transport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'Transport.dispose()', ''); + this.isDisposed = true; this.off(); }; @@ -6638,6 +6675,9 @@ var WebSocketTransport = (function() { var wsUri = wsScheme + this.wsHost + ':' + Defaults.getPort(options) + '/'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'uri: ' + wsUri); this.auth.getAuthParams(function(err, authParams) { + if(self.isDisposed) { + return; + } var paramStr = ''; for(var param in authParams) paramStr += ' ' + param + ': ' + authParams[param] + ';'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'authParams:' + paramStr + ' err: ' + err); if(err) { @@ -6733,6 +6773,7 @@ var WebSocketTransport = (function() { WebSocketTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.dispose()', ''); + this.isDisposed = true; var wsConnection = this.wsConnection; if(wsConnection) { /* Ignore any messages that come through after dispose() is called but before @@ -6796,7 +6837,6 @@ var CometTransport = (function() { this.recvRequest = null; this.pendingCallback = null; this.pendingItems = null; - this.disposed = false; } Utils.inherits(CometTransport, Transport); @@ -6822,6 +6862,9 @@ var CometTransport = (function() { self.disconnect(err); return; } + if(self.isDisposed) { + return; + } self.authParams = authParams; var connectParams = self.params.getConnectParams(authParams); if('stream' in connectParams) self.stream = connectParams.stream; @@ -6898,8 +6941,8 @@ var CometTransport = (function() { CometTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', ''); - if(!this.disposed) { - this.disposed = true; + if(!this.isDisposed) { + this.isDisposed = true; if(this.recvRequest) { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', 'aborting recv request'); this.recvRequest.abort(); @@ -6917,7 +6960,9 @@ var CometTransport = (function() { CometTransport.prototype.onConnect = function(message) { /* if this transport has been disposed whilst awaiting connection, do nothing */ - if(this.disposed) return; + if(this.isDisposed) { + return; + } /* the connectionKey in a comet connected response is really * - */ @@ -7520,10 +7565,16 @@ var Auth = (function() { !options.authUrl; } + var trId = 0; + function getTokenRequestId() { + return trId++; + } + function Auth(client, options) { this.client = client; this.tokenParams = options.defaultTokenParams || {}; - this.tokenRequestInProgress = false; + /* The id of the current token request if one is in progress, else null */ + this.currentTokenRequestId = null; this.waitingForTokenRequest = null; if(useTokenAuth(options)) { @@ -7623,7 +7674,7 @@ var Auth = (function() { /* RSA10a: authorize() call implies token auth. If a key is passed it, we * just check if it doesn't clash and assume we're generating a token from it */ - if(authOptions && authOptions.key && (this.key !== authOptions.key)) { + if(authOptions && authOptions.key && (this.authOptions.key !== authOptions.key)) { throw new ErrorInfo('Unable to update auth options with incompatible key', 40102, 401); } @@ -7675,7 +7726,7 @@ var Auth = (function() { logAndValidateTokenAuthMethod(this.authOptions); - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(true, function(err, tokenDetails) { /* RSA10g */ delete self.tokenParams.timestamp; delete self.authOptions.queryTime; @@ -8038,7 +8089,7 @@ var Auth = (function() { if(this.method == 'basic') callback(null, {key: this.key}); else - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -8055,7 +8106,7 @@ var Auth = (function() { if(this.method == 'basic') { callback(null, {authorization: 'Basic ' + this.basicKey}); } else { - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -8126,15 +8177,12 @@ var Auth = (function() { } }; - Auth.prototype._ensureValidAuthCredentials = function(callback) { + /* @param forceSupersede: force a new token request even if there's one in + * progress, making all pending callbacks wait for the new one */ + Auth.prototype._ensureValidAuthCredentials = function(forceSupersede, callback) { var self = this, token = this.tokenDetails; - if(this.tokenRequestInProgress) { - (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); - return; - } - if(token) { if(this._tokenClientIdMismatch(token.clientId)) { /* 403 to trigger a permanently failed client - RSA15c */ @@ -8154,21 +8202,26 @@ var Auth = (function() { this.tokenDetails = null; } + (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); + if(this.currentTokenRequestId !== null && !forceSupersede) { + return; + } + /* Request a new token */ - this.tokenRequestInProgress = true; + var tokenRequestId = this.currentTokenRequestId = getTokenRequestId(); this.requestToken(this.tokenParams, this.authOptions, function(err, tokenResponse) { - self.tokenRequestInProgress = false; - var waiting = self.waitingForTokenRequest; - if(waiting) { - waiting.push(callback); - callback = waiting; - self.waitingForTokenRequest = null; + if(self.currentTokenRequestId > tokenRequestId) { + Logger.logAction(Logger.LOG_MINOR, 'Auth._ensureValidAuthCredentials()', 'Discarding token request response; overtaken by newer one'); + return; } + self.currentTokenRequestId = null; + var callbacks = self.waitingForTokenRequest || noop; + self.waitingForTokenRequest = null; if(err) { - callback(err); + callbacks(err); return; } - callback(null, (self.tokenDetails = tokenResponse)); + callbacks(null, (self.tokenDetails = tokenResponse)); }); }; diff --git a/browser/static/ably-nativescript.js b/browser/static/ably-nativescript.js index 6f0da1744d..b020b0b761 100644 --- a/browser/static/ably-nativescript.js +++ b/browser/static/ably-nativescript.js @@ -1,7 +1,7 @@ /** * @license Copyright 2019, Ably * - * Ably JavaScript Library v1.1.7 + * Ably JavaScript Library v1.1.8 * https://github.com/ably/ably-js * * Ably Realtime Messaging @@ -4547,7 +4547,7 @@ Defaults.TIMEOUTS = { Defaults.httpMaxRetryCount = 3; Defaults.maxMessageSize = 65536; -Defaults.version = '1.1.7'; +Defaults.version = '1.1.8'; Defaults.libstring = Platform.libver + Defaults.version; Defaults.apiVersion = '1.1'; @@ -6196,6 +6196,7 @@ var ConnectionManager = (function() { this.lastActivity = null; this.mostRecentMsgId = null; this.forceFallbackHost = false; + this.connectCounter = 0; Logger.logAction(Logger.LOG_MINOR, 'Realtime.ConnectionManager()', 'started'); Logger.logAction(Logger.LOG_MICRO, 'Realtime.ConnectionManager()', 'requested transports = [' + (options.transports || Defaults.defaultTransports) + ']'); @@ -6588,7 +6589,7 @@ var ConnectionManager = (function() { var connectionKey = connectionDetails.connectionKey; if(connectionKey && this.connectionKey != connectionKey) { - this.setConnection(connectionId, connectionDetails, connectionPosition, true); + this.setConnection(connectionId, connectionDetails, connectionPosition, true, !!error); } /* Rebroadcast any new connectionDetails from the active transport, which @@ -6692,6 +6693,7 @@ var ConnectionManager = (function() { if((wasActive && noTransportsScheduledForActivation) || (wasActive && (state === 'failed') || (state === 'closed')) || (currentProtocol === null && wasPending && this.pendingTransports.length === 0)) { + /* If we're disconnected with a 5xx we need to try fallback hosts * (RTN14d), but (a) due to how the upgrade sequence works, the * host/transport selection sequence only cares about getting to @@ -6702,16 +6704,21 @@ var ConnectionManager = (function() { * setting an instance variable to force fallback hosts to be used (if * any) here. Bit of a kludge, but no real better alternatives without * rewriting the entire thing */ - if(state === 'disconnected' && error && error.statusCode > 500) { + if(state === 'disconnected' && error && error.statusCode > 500 && this.httpHosts.length > 1) { this.unpersistTransportPreference(); this.forceFallbackHost = true; + /* and try to connect again to try a fallback host without waiting for the usual 15s disconnectedRetryTimeout */ + this.notifyState({state: state, error: error, retryImmediately: true}); + return; } + /* TODO remove below line once realtime sends token errors as DISCONNECTEDs */ - if(state === 'failed' && Auth.isTokenErr(error)) { - state = 'disconnected' - } - this.notifyState({state: state, error: error}); - } else if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { + var newConnectionState = (state === 'failed' && Auth.isTokenErr(error)) ? 'disconnected' : state; + this.notifyState({state: newConnectionState, error: error}); + return; + } + + if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { /* If we were active but there is another transport scheduled for * activation, go into to the connecting state until that transport * activates and sets us back to connected. (manually starting the @@ -6766,13 +6773,17 @@ var ConnectionManager = (function() { }); }; - ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition) { + ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition, hasConnectionError) { /* if connectionKey changes but connectionId stays the same, then just a * transport change on the same connection. If connectionId changes, we're * on a new connection, with implications for msgSerial and channel state */ var self = this; - /* If no previous connectionId, don't reset the msgSerial as it may have been set by recover data */ - if(this.connectionId && (this.connectionId !== connectionId)) { + /* If no previous connectionId, don't reset the msgSerial as it may have + * been set by recover data (unless the recover failed) */ + var prevConnId = this.connectionid, + connIdChanged = prevConnId && (prevConnId !== connectionId), + recoverFailure = !prevConnId && hasConnectionError; + if(connIdChanged || recoverFailure) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.setConnection()', 'Resetting msgSerial'); this.msgSerial = 0; } @@ -7003,6 +7014,7 @@ var ConnectionManager = (function() { var retryImmediately = (state === 'disconnected' && (this.state === this.states.connected || this.state === this.states.synchronizing || + indicated.retryImmediately || (this.state === this.states.connecting && indicated.error && Auth.isTokenErr(indicated.error) && !(this.errorReason && Auth.isTokenErr(this.errorReason))))); @@ -7109,10 +7121,21 @@ var ConnectionManager = (function() { var auth = this.realtime.auth, self = this; + /* The point of the connectCounter mechanism is to ensure that the + * connection procedure can be cancelled. We want disconnectAllTransports + * to be able to stop any in-progress connection, even before it gets to + * the stage of having a pending (or even a proposed) transport that it can + * dispose() of. So we check that it's still current after any async stage, + * up until the stage that is synchronous with instantiating a transport */ + var connectCount = ++this.connectCounter; + var connect = function() { self.checkConnectionStateFreshness(); self.getTransportParams(function(transportParams) { - self.connectImpl(transportParams); + if(connectCount !== self.connectCounter) { + return; + } + self.connectImpl(transportParams, connectCount); }); }; @@ -7124,6 +7147,9 @@ var ConnectionManager = (function() { connect(); } else { var authCb = function(err) { + if(connectCount !== self.connectCounter) { + return; + } if(err) { self.actOnErrorFromAuthorize(err); } else { @@ -7134,7 +7160,7 @@ var ConnectionManager = (function() { /* Force a refetch of a new token */ auth._forceNewToken(null, null, authCb); } else { - auth._ensureValidAuthCredentials(authCb); + auth._ensureValidAuthCredentials(false, authCb); } } }; @@ -7158,7 +7184,7 @@ var ConnectionManager = (function() { * and dispatches accordingly. After a transport has been set pending, * tryATransport calls connectImpl to see if there's another stage to be done. * */ - ConnectionManager.prototype.connectImpl = function(transportParams) { + ConnectionManager.prototype.connectImpl = function(transportParams, connectCount) { var state = this.state.state; if(state !== this.states.connecting.state && state !== this.states.connected.state) { @@ -7173,7 +7199,7 @@ var ConnectionManager = (function() { } else if(this.transports.length > 1 && this.getTransportPreference()) { this.connectPreference(transportParams); } else { - this.connectBase(transportParams); + this.connectBase(transportParams, connectCount); } }; @@ -7232,13 +7258,16 @@ var ConnectionManager = (function() { * fallback hosts if applicable. * @param transportParams */ - ConnectionManager.prototype.connectBase = function(transportParams) { + ConnectionManager.prototype.connectBase = function(transportParams, connectCount) { var self = this, giveUp = function(err) { self.notifyState({state: self.states.connecting.failState, error: err}); }, candidateHosts = this.httpHosts.slice(), hostAttemptCb = function(fatal, transport) { + if(connectCount !== self.connectCounter) { + return; + } if(!transport && !fatal) { tryFallbackHosts(); } @@ -7265,6 +7294,9 @@ var ConnectionManager = (function() { * there is a problem with the ably host, or there is a general connectivity * problem */ Http.checkConnectivity(function(err, connectivity) { + if(connectCount !== self.connectCounter) { + return; + } /* we know err won't happen but handle it here anyway */ if(err) { giveUp(err); @@ -7435,6 +7467,9 @@ var ConnectionManager = (function() { ConnectionManager.prototype.disconnectAllTransports = function(exceptActive) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting all transports' + (exceptActive ? ' except the active transport' : '')); + /* This will prevent any connection procedure in an async part of one of its early stages from continuing */ + this.connectCounter++; + Utils.safeArrForEach(this.pendingTransports, function(transport) { Logger.logAction(Logger.LOG_MICRO, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting pending transport: ' + transport); if(transport) transport.disconnect(); @@ -7758,6 +7793,7 @@ var Transport = (function() { this.format = params.format; this.isConnected = false; this.isFinished = false; + this.isDisposed = false; this.maxIdleInterval = null; this.idleTimer = null; this.lastActivity = null; @@ -7913,6 +7949,7 @@ var Transport = (function() { Transport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'Transport.dispose()', ''); + this.isDisposed = true; this.off(); }; @@ -8004,6 +8041,9 @@ var WebSocketTransport = (function() { var wsUri = wsScheme + this.wsHost + ':' + Defaults.getPort(options) + '/'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'uri: ' + wsUri); this.auth.getAuthParams(function(err, authParams) { + if(self.isDisposed) { + return; + } var paramStr = ''; for(var param in authParams) paramStr += ' ' + param + ': ' + authParams[param] + ';'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'authParams:' + paramStr + ' err: ' + err); if(err) { @@ -8099,6 +8139,7 @@ var WebSocketTransport = (function() { WebSocketTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.dispose()', ''); + this.isDisposed = true; var wsConnection = this.wsConnection; if(wsConnection) { /* Ignore any messages that come through after dispose() is called but before @@ -8162,7 +8203,6 @@ var CometTransport = (function() { this.recvRequest = null; this.pendingCallback = null; this.pendingItems = null; - this.disposed = false; } Utils.inherits(CometTransport, Transport); @@ -8188,6 +8228,9 @@ var CometTransport = (function() { self.disconnect(err); return; } + if(self.isDisposed) { + return; + } self.authParams = authParams; var connectParams = self.params.getConnectParams(authParams); if('stream' in connectParams) self.stream = connectParams.stream; @@ -8264,8 +8307,8 @@ var CometTransport = (function() { CometTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', ''); - if(!this.disposed) { - this.disposed = true; + if(!this.isDisposed) { + this.isDisposed = true; if(this.recvRequest) { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', 'aborting recv request'); this.recvRequest.abort(); @@ -8283,7 +8326,9 @@ var CometTransport = (function() { CometTransport.prototype.onConnect = function(message) { /* if this transport has been disposed whilst awaiting connection, do nothing */ - if(this.disposed) return; + if(this.isDisposed) { + return; + } /* the connectionKey in a comet connected response is really * - */ @@ -8886,10 +8931,16 @@ var Auth = (function() { !options.authUrl; } + var trId = 0; + function getTokenRequestId() { + return trId++; + } + function Auth(client, options) { this.client = client; this.tokenParams = options.defaultTokenParams || {}; - this.tokenRequestInProgress = false; + /* The id of the current token request if one is in progress, else null */ + this.currentTokenRequestId = null; this.waitingForTokenRequest = null; if(useTokenAuth(options)) { @@ -8989,7 +9040,7 @@ var Auth = (function() { /* RSA10a: authorize() call implies token auth. If a key is passed it, we * just check if it doesn't clash and assume we're generating a token from it */ - if(authOptions && authOptions.key && (this.key !== authOptions.key)) { + if(authOptions && authOptions.key && (this.authOptions.key !== authOptions.key)) { throw new ErrorInfo('Unable to update auth options with incompatible key', 40102, 401); } @@ -9041,7 +9092,7 @@ var Auth = (function() { logAndValidateTokenAuthMethod(this.authOptions); - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(true, function(err, tokenDetails) { /* RSA10g */ delete self.tokenParams.timestamp; delete self.authOptions.queryTime; @@ -9404,7 +9455,7 @@ var Auth = (function() { if(this.method == 'basic') callback(null, {key: this.key}); else - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9421,7 +9472,7 @@ var Auth = (function() { if(this.method == 'basic') { callback(null, {authorization: 'Basic ' + this.basicKey}); } else { - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9492,15 +9543,12 @@ var Auth = (function() { } }; - Auth.prototype._ensureValidAuthCredentials = function(callback) { + /* @param forceSupersede: force a new token request even if there's one in + * progress, making all pending callbacks wait for the new one */ + Auth.prototype._ensureValidAuthCredentials = function(forceSupersede, callback) { var self = this, token = this.tokenDetails; - if(this.tokenRequestInProgress) { - (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); - return; - } - if(token) { if(this._tokenClientIdMismatch(token.clientId)) { /* 403 to trigger a permanently failed client - RSA15c */ @@ -9520,21 +9568,26 @@ var Auth = (function() { this.tokenDetails = null; } + (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); + if(this.currentTokenRequestId !== null && !forceSupersede) { + return; + } + /* Request a new token */ - this.tokenRequestInProgress = true; + var tokenRequestId = this.currentTokenRequestId = getTokenRequestId(); this.requestToken(this.tokenParams, this.authOptions, function(err, tokenResponse) { - self.tokenRequestInProgress = false; - var waiting = self.waitingForTokenRequest; - if(waiting) { - waiting.push(callback); - callback = waiting; - self.waitingForTokenRequest = null; + if(self.currentTokenRequestId > tokenRequestId) { + Logger.logAction(Logger.LOG_MINOR, 'Auth._ensureValidAuthCredentials()', 'Discarding token request response; overtaken by newer one'); + return; } + self.currentTokenRequestId = null; + var callbacks = self.waitingForTokenRequest || noop; + self.waitingForTokenRequest = null; if(err) { - callback(err); + callbacks(err); return; } - callback(null, (self.tokenDetails = tokenResponse)); + callbacks(null, (self.tokenDetails = tokenResponse)); }); }; diff --git a/browser/static/ably-reactnative.js b/browser/static/ably-reactnative.js index 4f84748925..50697e847e 100644 --- a/browser/static/ably-reactnative.js +++ b/browser/static/ably-reactnative.js @@ -1,7 +1,7 @@ /** * @license Copyright 2019, Ably * - * Ably JavaScript Library v1.1.7 + * Ably JavaScript Library v1.1.8 * https://github.com/ably/ably-js * * Ably Realtime Messaging @@ -4565,7 +4565,7 @@ Defaults.TIMEOUTS = { Defaults.httpMaxRetryCount = 3; Defaults.maxMessageSize = 65536; -Defaults.version = '1.1.7'; +Defaults.version = '1.1.8'; Defaults.libstring = Platform.libver + Defaults.version; Defaults.apiVersion = '1.1'; @@ -6214,6 +6214,7 @@ var ConnectionManager = (function() { this.lastActivity = null; this.mostRecentMsgId = null; this.forceFallbackHost = false; + this.connectCounter = 0; Logger.logAction(Logger.LOG_MINOR, 'Realtime.ConnectionManager()', 'started'); Logger.logAction(Logger.LOG_MICRO, 'Realtime.ConnectionManager()', 'requested transports = [' + (options.transports || Defaults.defaultTransports) + ']'); @@ -6606,7 +6607,7 @@ var ConnectionManager = (function() { var connectionKey = connectionDetails.connectionKey; if(connectionKey && this.connectionKey != connectionKey) { - this.setConnection(connectionId, connectionDetails, connectionPosition, true); + this.setConnection(connectionId, connectionDetails, connectionPosition, true, !!error); } /* Rebroadcast any new connectionDetails from the active transport, which @@ -6710,6 +6711,7 @@ var ConnectionManager = (function() { if((wasActive && noTransportsScheduledForActivation) || (wasActive && (state === 'failed') || (state === 'closed')) || (currentProtocol === null && wasPending && this.pendingTransports.length === 0)) { + /* If we're disconnected with a 5xx we need to try fallback hosts * (RTN14d), but (a) due to how the upgrade sequence works, the * host/transport selection sequence only cares about getting to @@ -6720,16 +6722,21 @@ var ConnectionManager = (function() { * setting an instance variable to force fallback hosts to be used (if * any) here. Bit of a kludge, but no real better alternatives without * rewriting the entire thing */ - if(state === 'disconnected' && error && error.statusCode > 500) { + if(state === 'disconnected' && error && error.statusCode > 500 && this.httpHosts.length > 1) { this.unpersistTransportPreference(); this.forceFallbackHost = true; + /* and try to connect again to try a fallback host without waiting for the usual 15s disconnectedRetryTimeout */ + this.notifyState({state: state, error: error, retryImmediately: true}); + return; } + /* TODO remove below line once realtime sends token errors as DISCONNECTEDs */ - if(state === 'failed' && Auth.isTokenErr(error)) { - state = 'disconnected' - } - this.notifyState({state: state, error: error}); - } else if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { + var newConnectionState = (state === 'failed' && Auth.isTokenErr(error)) ? 'disconnected' : state; + this.notifyState({state: newConnectionState, error: error}); + return; + } + + if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { /* If we were active but there is another transport scheduled for * activation, go into to the connecting state until that transport * activates and sets us back to connected. (manually starting the @@ -6784,13 +6791,17 @@ var ConnectionManager = (function() { }); }; - ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition) { + ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition, hasConnectionError) { /* if connectionKey changes but connectionId stays the same, then just a * transport change on the same connection. If connectionId changes, we're * on a new connection, with implications for msgSerial and channel state */ var self = this; - /* If no previous connectionId, don't reset the msgSerial as it may have been set by recover data */ - if(this.connectionId && (this.connectionId !== connectionId)) { + /* If no previous connectionId, don't reset the msgSerial as it may have + * been set by recover data (unless the recover failed) */ + var prevConnId = this.connectionid, + connIdChanged = prevConnId && (prevConnId !== connectionId), + recoverFailure = !prevConnId && hasConnectionError; + if(connIdChanged || recoverFailure) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.setConnection()', 'Resetting msgSerial'); this.msgSerial = 0; } @@ -7021,6 +7032,7 @@ var ConnectionManager = (function() { var retryImmediately = (state === 'disconnected' && (this.state === this.states.connected || this.state === this.states.synchronizing || + indicated.retryImmediately || (this.state === this.states.connecting && indicated.error && Auth.isTokenErr(indicated.error) && !(this.errorReason && Auth.isTokenErr(this.errorReason))))); @@ -7127,10 +7139,21 @@ var ConnectionManager = (function() { var auth = this.realtime.auth, self = this; + /* The point of the connectCounter mechanism is to ensure that the + * connection procedure can be cancelled. We want disconnectAllTransports + * to be able to stop any in-progress connection, even before it gets to + * the stage of having a pending (or even a proposed) transport that it can + * dispose() of. So we check that it's still current after any async stage, + * up until the stage that is synchronous with instantiating a transport */ + var connectCount = ++this.connectCounter; + var connect = function() { self.checkConnectionStateFreshness(); self.getTransportParams(function(transportParams) { - self.connectImpl(transportParams); + if(connectCount !== self.connectCounter) { + return; + } + self.connectImpl(transportParams, connectCount); }); }; @@ -7142,6 +7165,9 @@ var ConnectionManager = (function() { connect(); } else { var authCb = function(err) { + if(connectCount !== self.connectCounter) { + return; + } if(err) { self.actOnErrorFromAuthorize(err); } else { @@ -7152,7 +7178,7 @@ var ConnectionManager = (function() { /* Force a refetch of a new token */ auth._forceNewToken(null, null, authCb); } else { - auth._ensureValidAuthCredentials(authCb); + auth._ensureValidAuthCredentials(false, authCb); } } }; @@ -7176,7 +7202,7 @@ var ConnectionManager = (function() { * and dispatches accordingly. After a transport has been set pending, * tryATransport calls connectImpl to see if there's another stage to be done. * */ - ConnectionManager.prototype.connectImpl = function(transportParams) { + ConnectionManager.prototype.connectImpl = function(transportParams, connectCount) { var state = this.state.state; if(state !== this.states.connecting.state && state !== this.states.connected.state) { @@ -7191,7 +7217,7 @@ var ConnectionManager = (function() { } else if(this.transports.length > 1 && this.getTransportPreference()) { this.connectPreference(transportParams); } else { - this.connectBase(transportParams); + this.connectBase(transportParams, connectCount); } }; @@ -7250,13 +7276,16 @@ var ConnectionManager = (function() { * fallback hosts if applicable. * @param transportParams */ - ConnectionManager.prototype.connectBase = function(transportParams) { + ConnectionManager.prototype.connectBase = function(transportParams, connectCount) { var self = this, giveUp = function(err) { self.notifyState({state: self.states.connecting.failState, error: err}); }, candidateHosts = this.httpHosts.slice(), hostAttemptCb = function(fatal, transport) { + if(connectCount !== self.connectCounter) { + return; + } if(!transport && !fatal) { tryFallbackHosts(); } @@ -7283,6 +7312,9 @@ var ConnectionManager = (function() { * there is a problem with the ably host, or there is a general connectivity * problem */ Http.checkConnectivity(function(err, connectivity) { + if(connectCount !== self.connectCounter) { + return; + } /* we know err won't happen but handle it here anyway */ if(err) { giveUp(err); @@ -7453,6 +7485,9 @@ var ConnectionManager = (function() { ConnectionManager.prototype.disconnectAllTransports = function(exceptActive) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting all transports' + (exceptActive ? ' except the active transport' : '')); + /* This will prevent any connection procedure in an async part of one of its early stages from continuing */ + this.connectCounter++; + Utils.safeArrForEach(this.pendingTransports, function(transport) { Logger.logAction(Logger.LOG_MICRO, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting pending transport: ' + transport); if(transport) transport.disconnect(); @@ -7776,6 +7811,7 @@ var Transport = (function() { this.format = params.format; this.isConnected = false; this.isFinished = false; + this.isDisposed = false; this.maxIdleInterval = null; this.idleTimer = null; this.lastActivity = null; @@ -7931,6 +7967,7 @@ var Transport = (function() { Transport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'Transport.dispose()', ''); + this.isDisposed = true; this.off(); }; @@ -8022,6 +8059,9 @@ var WebSocketTransport = (function() { var wsUri = wsScheme + this.wsHost + ':' + Defaults.getPort(options) + '/'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'uri: ' + wsUri); this.auth.getAuthParams(function(err, authParams) { + if(self.isDisposed) { + return; + } var paramStr = ''; for(var param in authParams) paramStr += ' ' + param + ': ' + authParams[param] + ';'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'authParams:' + paramStr + ' err: ' + err); if(err) { @@ -8117,6 +8157,7 @@ var WebSocketTransport = (function() { WebSocketTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.dispose()', ''); + this.isDisposed = true; var wsConnection = this.wsConnection; if(wsConnection) { /* Ignore any messages that come through after dispose() is called but before @@ -8180,7 +8221,6 @@ var CometTransport = (function() { this.recvRequest = null; this.pendingCallback = null; this.pendingItems = null; - this.disposed = false; } Utils.inherits(CometTransport, Transport); @@ -8206,6 +8246,9 @@ var CometTransport = (function() { self.disconnect(err); return; } + if(self.isDisposed) { + return; + } self.authParams = authParams; var connectParams = self.params.getConnectParams(authParams); if('stream' in connectParams) self.stream = connectParams.stream; @@ -8282,8 +8325,8 @@ var CometTransport = (function() { CometTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', ''); - if(!this.disposed) { - this.disposed = true; + if(!this.isDisposed) { + this.isDisposed = true; if(this.recvRequest) { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', 'aborting recv request'); this.recvRequest.abort(); @@ -8301,7 +8344,9 @@ var CometTransport = (function() { CometTransport.prototype.onConnect = function(message) { /* if this transport has been disposed whilst awaiting connection, do nothing */ - if(this.disposed) return; + if(this.isDisposed) { + return; + } /* the connectionKey in a comet connected response is really * - */ @@ -8904,10 +8949,16 @@ var Auth = (function() { !options.authUrl; } + var trId = 0; + function getTokenRequestId() { + return trId++; + } + function Auth(client, options) { this.client = client; this.tokenParams = options.defaultTokenParams || {}; - this.tokenRequestInProgress = false; + /* The id of the current token request if one is in progress, else null */ + this.currentTokenRequestId = null; this.waitingForTokenRequest = null; if(useTokenAuth(options)) { @@ -9007,7 +9058,7 @@ var Auth = (function() { /* RSA10a: authorize() call implies token auth. If a key is passed it, we * just check if it doesn't clash and assume we're generating a token from it */ - if(authOptions && authOptions.key && (this.key !== authOptions.key)) { + if(authOptions && authOptions.key && (this.authOptions.key !== authOptions.key)) { throw new ErrorInfo('Unable to update auth options with incompatible key', 40102, 401); } @@ -9059,7 +9110,7 @@ var Auth = (function() { logAndValidateTokenAuthMethod(this.authOptions); - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(true, function(err, tokenDetails) { /* RSA10g */ delete self.tokenParams.timestamp; delete self.authOptions.queryTime; @@ -9422,7 +9473,7 @@ var Auth = (function() { if(this.method == 'basic') callback(null, {key: this.key}); else - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9439,7 +9490,7 @@ var Auth = (function() { if(this.method == 'basic') { callback(null, {authorization: 'Basic ' + this.basicKey}); } else { - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9510,15 +9561,12 @@ var Auth = (function() { } }; - Auth.prototype._ensureValidAuthCredentials = function(callback) { + /* @param forceSupersede: force a new token request even if there's one in + * progress, making all pending callbacks wait for the new one */ + Auth.prototype._ensureValidAuthCredentials = function(forceSupersede, callback) { var self = this, token = this.tokenDetails; - if(this.tokenRequestInProgress) { - (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); - return; - } - if(token) { if(this._tokenClientIdMismatch(token.clientId)) { /* 403 to trigger a permanently failed client - RSA15c */ @@ -9538,21 +9586,26 @@ var Auth = (function() { this.tokenDetails = null; } + (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); + if(this.currentTokenRequestId !== null && !forceSupersede) { + return; + } + /* Request a new token */ - this.tokenRequestInProgress = true; + var tokenRequestId = this.currentTokenRequestId = getTokenRequestId(); this.requestToken(this.tokenParams, this.authOptions, function(err, tokenResponse) { - self.tokenRequestInProgress = false; - var waiting = self.waitingForTokenRequest; - if(waiting) { - waiting.push(callback); - callback = waiting; - self.waitingForTokenRequest = null; + if(self.currentTokenRequestId > tokenRequestId) { + Logger.logAction(Logger.LOG_MINOR, 'Auth._ensureValidAuthCredentials()', 'Discarding token request response; overtaken by newer one'); + return; } + self.currentTokenRequestId = null; + var callbacks = self.waitingForTokenRequest || noop; + self.waitingForTokenRequest = null; if(err) { - callback(err); + callbacks(err); return; } - callback(null, (self.tokenDetails = tokenResponse)); + callbacks(null, (self.tokenDetails = tokenResponse)); }); }; diff --git a/browser/static/ably.js b/browser/static/ably.js index 9560b77c2b..c710817279 100644 --- a/browser/static/ably.js +++ b/browser/static/ably.js @@ -1,7 +1,7 @@ /** * @license Copyright 2019, Ably * - * Ably JavaScript Library v1.1.7 + * Ably JavaScript Library v1.1.8 * https://github.com/ably/ably-js * * Ably Realtime Messaging @@ -4626,7 +4626,7 @@ Defaults.TIMEOUTS = { Defaults.httpMaxRetryCount = 3; Defaults.maxMessageSize = 65536; -Defaults.version = '1.1.7'; +Defaults.version = '1.1.8'; Defaults.libstring = Platform.libver + Defaults.version; Defaults.apiVersion = '1.1'; @@ -6275,6 +6275,7 @@ var ConnectionManager = (function() { this.lastActivity = null; this.mostRecentMsgId = null; this.forceFallbackHost = false; + this.connectCounter = 0; Logger.logAction(Logger.LOG_MINOR, 'Realtime.ConnectionManager()', 'started'); Logger.logAction(Logger.LOG_MICRO, 'Realtime.ConnectionManager()', 'requested transports = [' + (options.transports || Defaults.defaultTransports) + ']'); @@ -6667,7 +6668,7 @@ var ConnectionManager = (function() { var connectionKey = connectionDetails.connectionKey; if(connectionKey && this.connectionKey != connectionKey) { - this.setConnection(connectionId, connectionDetails, connectionPosition, true); + this.setConnection(connectionId, connectionDetails, connectionPosition, true, !!error); } /* Rebroadcast any new connectionDetails from the active transport, which @@ -6771,6 +6772,7 @@ var ConnectionManager = (function() { if((wasActive && noTransportsScheduledForActivation) || (wasActive && (state === 'failed') || (state === 'closed')) || (currentProtocol === null && wasPending && this.pendingTransports.length === 0)) { + /* If we're disconnected with a 5xx we need to try fallback hosts * (RTN14d), but (a) due to how the upgrade sequence works, the * host/transport selection sequence only cares about getting to @@ -6781,16 +6783,21 @@ var ConnectionManager = (function() { * setting an instance variable to force fallback hosts to be used (if * any) here. Bit of a kludge, but no real better alternatives without * rewriting the entire thing */ - if(state === 'disconnected' && error && error.statusCode > 500) { + if(state === 'disconnected' && error && error.statusCode > 500 && this.httpHosts.length > 1) { this.unpersistTransportPreference(); this.forceFallbackHost = true; + /* and try to connect again to try a fallback host without waiting for the usual 15s disconnectedRetryTimeout */ + this.notifyState({state: state, error: error, retryImmediately: true}); + return; } + /* TODO remove below line once realtime sends token errors as DISCONNECTEDs */ - if(state === 'failed' && Auth.isTokenErr(error)) { - state = 'disconnected' - } - this.notifyState({state: state, error: error}); - } else if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { + var newConnectionState = (state === 'failed' && Auth.isTokenErr(error)) ? 'disconnected' : state; + this.notifyState({state: newConnectionState, error: error}); + return; + } + + if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { /* If we were active but there is another transport scheduled for * activation, go into to the connecting state until that transport * activates and sets us back to connected. (manually starting the @@ -6845,13 +6852,17 @@ var ConnectionManager = (function() { }); }; - ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition) { + ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition, hasConnectionError) { /* if connectionKey changes but connectionId stays the same, then just a * transport change on the same connection. If connectionId changes, we're * on a new connection, with implications for msgSerial and channel state */ var self = this; - /* If no previous connectionId, don't reset the msgSerial as it may have been set by recover data */ - if(this.connectionId && (this.connectionId !== connectionId)) { + /* If no previous connectionId, don't reset the msgSerial as it may have + * been set by recover data (unless the recover failed) */ + var prevConnId = this.connectionid, + connIdChanged = prevConnId && (prevConnId !== connectionId), + recoverFailure = !prevConnId && hasConnectionError; + if(connIdChanged || recoverFailure) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.setConnection()', 'Resetting msgSerial'); this.msgSerial = 0; } @@ -7082,6 +7093,7 @@ var ConnectionManager = (function() { var retryImmediately = (state === 'disconnected' && (this.state === this.states.connected || this.state === this.states.synchronizing || + indicated.retryImmediately || (this.state === this.states.connecting && indicated.error && Auth.isTokenErr(indicated.error) && !(this.errorReason && Auth.isTokenErr(this.errorReason))))); @@ -7188,10 +7200,21 @@ var ConnectionManager = (function() { var auth = this.realtime.auth, self = this; + /* The point of the connectCounter mechanism is to ensure that the + * connection procedure can be cancelled. We want disconnectAllTransports + * to be able to stop any in-progress connection, even before it gets to + * the stage of having a pending (or even a proposed) transport that it can + * dispose() of. So we check that it's still current after any async stage, + * up until the stage that is synchronous with instantiating a transport */ + var connectCount = ++this.connectCounter; + var connect = function() { self.checkConnectionStateFreshness(); self.getTransportParams(function(transportParams) { - self.connectImpl(transportParams); + if(connectCount !== self.connectCounter) { + return; + } + self.connectImpl(transportParams, connectCount); }); }; @@ -7203,6 +7226,9 @@ var ConnectionManager = (function() { connect(); } else { var authCb = function(err) { + if(connectCount !== self.connectCounter) { + return; + } if(err) { self.actOnErrorFromAuthorize(err); } else { @@ -7213,7 +7239,7 @@ var ConnectionManager = (function() { /* Force a refetch of a new token */ auth._forceNewToken(null, null, authCb); } else { - auth._ensureValidAuthCredentials(authCb); + auth._ensureValidAuthCredentials(false, authCb); } } }; @@ -7237,7 +7263,7 @@ var ConnectionManager = (function() { * and dispatches accordingly. After a transport has been set pending, * tryATransport calls connectImpl to see if there's another stage to be done. * */ - ConnectionManager.prototype.connectImpl = function(transportParams) { + ConnectionManager.prototype.connectImpl = function(transportParams, connectCount) { var state = this.state.state; if(state !== this.states.connecting.state && state !== this.states.connected.state) { @@ -7252,7 +7278,7 @@ var ConnectionManager = (function() { } else if(this.transports.length > 1 && this.getTransportPreference()) { this.connectPreference(transportParams); } else { - this.connectBase(transportParams); + this.connectBase(transportParams, connectCount); } }; @@ -7311,13 +7337,16 @@ var ConnectionManager = (function() { * fallback hosts if applicable. * @param transportParams */ - ConnectionManager.prototype.connectBase = function(transportParams) { + ConnectionManager.prototype.connectBase = function(transportParams, connectCount) { var self = this, giveUp = function(err) { self.notifyState({state: self.states.connecting.failState, error: err}); }, candidateHosts = this.httpHosts.slice(), hostAttemptCb = function(fatal, transport) { + if(connectCount !== self.connectCounter) { + return; + } if(!transport && !fatal) { tryFallbackHosts(); } @@ -7344,6 +7373,9 @@ var ConnectionManager = (function() { * there is a problem with the ably host, or there is a general connectivity * problem */ Http.checkConnectivity(function(err, connectivity) { + if(connectCount !== self.connectCounter) { + return; + } /* we know err won't happen but handle it here anyway */ if(err) { giveUp(err); @@ -7514,6 +7546,9 @@ var ConnectionManager = (function() { ConnectionManager.prototype.disconnectAllTransports = function(exceptActive) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting all transports' + (exceptActive ? ' except the active transport' : '')); + /* This will prevent any connection procedure in an async part of one of its early stages from continuing */ + this.connectCounter++; + Utils.safeArrForEach(this.pendingTransports, function(transport) { Logger.logAction(Logger.LOG_MICRO, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting pending transport: ' + transport); if(transport) transport.disconnect(); @@ -7837,6 +7872,7 @@ var Transport = (function() { this.format = params.format; this.isConnected = false; this.isFinished = false; + this.isDisposed = false; this.maxIdleInterval = null; this.idleTimer = null; this.lastActivity = null; @@ -7992,6 +8028,7 @@ var Transport = (function() { Transport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'Transport.dispose()', ''); + this.isDisposed = true; this.off(); }; @@ -8083,6 +8120,9 @@ var WebSocketTransport = (function() { var wsUri = wsScheme + this.wsHost + ':' + Defaults.getPort(options) + '/'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'uri: ' + wsUri); this.auth.getAuthParams(function(err, authParams) { + if(self.isDisposed) { + return; + } var paramStr = ''; for(var param in authParams) paramStr += ' ' + param + ': ' + authParams[param] + ';'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'authParams:' + paramStr + ' err: ' + err); if(err) { @@ -8178,6 +8218,7 @@ var WebSocketTransport = (function() { WebSocketTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.dispose()', ''); + this.isDisposed = true; var wsConnection = this.wsConnection; if(wsConnection) { /* Ignore any messages that come through after dispose() is called but before @@ -8241,7 +8282,6 @@ var CometTransport = (function() { this.recvRequest = null; this.pendingCallback = null; this.pendingItems = null; - this.disposed = false; } Utils.inherits(CometTransport, Transport); @@ -8267,6 +8307,9 @@ var CometTransport = (function() { self.disconnect(err); return; } + if(self.isDisposed) { + return; + } self.authParams = authParams; var connectParams = self.params.getConnectParams(authParams); if('stream' in connectParams) self.stream = connectParams.stream; @@ -8343,8 +8386,8 @@ var CometTransport = (function() { CometTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', ''); - if(!this.disposed) { - this.disposed = true; + if(!this.isDisposed) { + this.isDisposed = true; if(this.recvRequest) { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', 'aborting recv request'); this.recvRequest.abort(); @@ -8362,7 +8405,9 @@ var CometTransport = (function() { CometTransport.prototype.onConnect = function(message) { /* if this transport has been disposed whilst awaiting connection, do nothing */ - if(this.disposed) return; + if(this.isDisposed) { + return; + } /* the connectionKey in a comet connected response is really * - */ @@ -8965,10 +9010,16 @@ var Auth = (function() { !options.authUrl; } + var trId = 0; + function getTokenRequestId() { + return trId++; + } + function Auth(client, options) { this.client = client; this.tokenParams = options.defaultTokenParams || {}; - this.tokenRequestInProgress = false; + /* The id of the current token request if one is in progress, else null */ + this.currentTokenRequestId = null; this.waitingForTokenRequest = null; if(useTokenAuth(options)) { @@ -9068,7 +9119,7 @@ var Auth = (function() { /* RSA10a: authorize() call implies token auth. If a key is passed it, we * just check if it doesn't clash and assume we're generating a token from it */ - if(authOptions && authOptions.key && (this.key !== authOptions.key)) { + if(authOptions && authOptions.key && (this.authOptions.key !== authOptions.key)) { throw new ErrorInfo('Unable to update auth options with incompatible key', 40102, 401); } @@ -9120,7 +9171,7 @@ var Auth = (function() { logAndValidateTokenAuthMethod(this.authOptions); - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(true, function(err, tokenDetails) { /* RSA10g */ delete self.tokenParams.timestamp; delete self.authOptions.queryTime; @@ -9483,7 +9534,7 @@ var Auth = (function() { if(this.method == 'basic') callback(null, {key: this.key}); else - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9500,7 +9551,7 @@ var Auth = (function() { if(this.method == 'basic') { callback(null, {authorization: 'Basic ' + this.basicKey}); } else { - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -9571,15 +9622,12 @@ var Auth = (function() { } }; - Auth.prototype._ensureValidAuthCredentials = function(callback) { + /* @param forceSupersede: force a new token request even if there's one in + * progress, making all pending callbacks wait for the new one */ + Auth.prototype._ensureValidAuthCredentials = function(forceSupersede, callback) { var self = this, token = this.tokenDetails; - if(this.tokenRequestInProgress) { - (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); - return; - } - if(token) { if(this._tokenClientIdMismatch(token.clientId)) { /* 403 to trigger a permanently failed client - RSA15c */ @@ -9599,21 +9647,26 @@ var Auth = (function() { this.tokenDetails = null; } + (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); + if(this.currentTokenRequestId !== null && !forceSupersede) { + return; + } + /* Request a new token */ - this.tokenRequestInProgress = true; + var tokenRequestId = this.currentTokenRequestId = getTokenRequestId(); this.requestToken(this.tokenParams, this.authOptions, function(err, tokenResponse) { - self.tokenRequestInProgress = false; - var waiting = self.waitingForTokenRequest; - if(waiting) { - waiting.push(callback); - callback = waiting; - self.waitingForTokenRequest = null; + if(self.currentTokenRequestId > tokenRequestId) { + Logger.logAction(Logger.LOG_MINOR, 'Auth._ensureValidAuthCredentials()', 'Discarding token request response; overtaken by newer one'); + return; } + self.currentTokenRequestId = null; + var callbacks = self.waitingForTokenRequest || noop; + self.waitingForTokenRequest = null; if(err) { - callback(err); + callbacks(err); return; } - callback(null, (self.tokenDetails = tokenResponse)); + callbacks(null, (self.tokenDetails = tokenResponse)); }); }; diff --git a/browser/static/ably.min.js b/browser/static/ably.min.js index c49cffb3dd..59a351508a 100644 --- a/browser/static/ably.min.js +++ b/browser/static/ably.min.js @@ -2,7 +2,7 @@ /* Copyright 2019, Ably - Ably JavaScript Library v1.1.7 + Ably JavaScript Library v1.1.8 https://github.com/ably/ably-js Ably Realtime Messaging @@ -10,335 +10,336 @@ Released under the Apache Licence v2.0 */ -(function(){function ia(f){if("string"!==typeof f)throw new p("host must be a string; was a "+typeof f,4E4,400);if(!f.length)throw new p("host must not be zero-length",4E4,400);}var X=window.Ably=this,C=C||function(f,b){var d={},a=d.lib={},c=a.Base=function(){function a(){}return{extend:function(g){a.prototype=this;var c=new a;g&&c.mixIn(g);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend(); -a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var g in a)a.hasOwnProperty(g)&&(this[g]=a[g]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),q=a.WordArray=c.extend({init:function(a,g){a=this.words=a||[];this.sigBytes=g!=b?g:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var g=this.words,c=a.words,l=this.sigBytes;a=a.sigBytes;this.clamp();if(l%4)for(var e=0;e>>2]|=(c[e>>>2]>>>24-e%4*8&255)<<24-(l+e)%4*8;else if(65535>>2]=c[e>>>2];else g.push.apply(g,c);this.sigBytes+=a;return this},clamp:function(){var a=this.words,g=this.sigBytes;a[g>>>2]&=4294967295<<32-g%4*8;a.length=f.ceil(g/4)},clone:function(){var a=c.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){function g(a){var g=987654321;return function(){g=36969*(g&65535)+(g>>16)&4294967295;a=18E3*(a&65535)+(a>>16)&4294967295;return(((g<<16)+a& -4294967295)/4294967296+.5)*(.5>>2]>>>24-e%4*8&255;c.push((l>>>4).toString(16));c.push((l&15).toString(16))}return c.join("")},parse:function(a){for(var g=a.length,c=[],e=0;e>>3]|=parseInt(a.substr(e,2),16)<<24-e%8*4;return new q.init(c, -g/2)}},m=e.Latin1={stringify:function(a){var g=a.words;a=a.sigBytes;for(var c=[],e=0;e>>2]>>>24-e%4*8&255));return c.join("")},parse:function(a){for(var g=a.length,c=[],e=0;e>>2]|=(a.charCodeAt(e)&255)<<24-e%4*8;return new q.init(c,g)}},l=e.Utf8={stringify:function(a){try{return decodeURIComponent(escape(m.stringify(a)))}catch(y){throw Error("Malformed UTF-8 data");}},parse:function(a){return m.parse(unescape(encodeURIComponent(a)))}},g=a.BufferedBlockAlgorithm= -c.extend({reset:function(){this._data=new q.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=l.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var g=this._data,c=g.words,e=g.sigBytes,l=this.blockSize,d=e/(4*l);d=a?f.ceil(d):f.max((d|0)-this._minBufferSize,0);a=d*l;e=f.min(4*a,e);if(a){for(var u=0;ud;)a(g)&&(8>d&&(q[d]=c(f.pow(g,.5))),e[d]=c(f.pow(g,1/3)),d++),g++})();var n=[];d=d.SHA256=c.extend({_doReset:function(){this._hash=new a.init(q.slice(0))},_doProcessBlock:function(a,c){for(var g=this._hash.words,l=g[0],d=g[1],m=g[2],f=g[3],q=g[4], -b=g[5],k=g[6],h=g[7],I=0;64>I;I++){if(16>I)n[I]=a[c+I]|0;else{var p=n[I-15],r=n[I-2];n[I]=((p<<25|p>>>7)^(p<<14|p>>>18)^p>>>3)+n[I-7]+((r<<15|r>>>17)^(r<<13|r>>>19)^r>>>10)+n[I-16]}p=h+((q<<26|q>>>6)^(q<<21|q>>>11)^(q<<7|q>>>25))+(q&b^~q&k)+e[I]+n[I];r=((l<<30|l>>>2)^(l<<19|l>>>13)^(l<<10|l>>>22))+(l&d^l&m^d&m);h=k;k=b;b=q;q=f+p|0;f=m;m=d;d=l;l=p+r|0}g[0]=g[0]+l|0;g[1]=g[1]+d|0;g[2]=g[2]+m|0;g[3]=g[3]+f|0;g[4]=g[4]+q|0;g[5]=g[5]+b|0;g[6]=g[6]+k|0;g[7]=g[7]+h|0},_doFinalize:function(){var a=this._data, -c=a.words,g=8*this._nDataBytes,e=8*a.sigBytes;c[e>>>5]|=128<<24-e%32;c[(e+64>>>9<<4)+14]=f.floor(g/4294967296);c[(e+64>>>9<<4)+15]=g;a.sigBytes=4*c.length;this._process();return this._hash},clone:function(){var a=c.clone.call(this);a._hash=this._hash.clone();return a}});b.SHA256=c._createHelper(d);b.HmacSHA256=c._createHmacHelper(d)})(Math);(function(){var f=C,b=f.enc.Utf8;f.algo.HMAC=f.lib.Base.extend({init:function(d,a){d=this._hasher=new d.init;"string"==typeof a&&(a=b.parse(a));var c=d.blockSize, -f=4*c;a.sigBytes>f&&(a=d.finalize(a));a.clamp();for(var e=this._oKey=a.clone(),n=this._iKey=a.clone(),m=e.words,l=n.words,g=0;g>>2]>>>24-e%4*8&255)<<16|(a[e+1>>>2]>>>24-(e+1)%4*8&255)<<8|a[e+2>>>2]>>>24-(e+2)%4*8&255,m=0;4>m&&e+.75*m>>6*(3-m)&63));if(a=f.charAt(64))for(;d.length%4;)d.push(a);return d.join("")},parse:function(d){var a=d.length,c=this._map,f=c.charAt(64);f&&(f=d.indexOf(f),-1!=f&&(a=f));f=[];for(var e=0,n=0;n>>6-n%4*2;f[e>>> -2]|=(m|l)<<24-e%4*8;e++}return b.create(f,e)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();C.lib.Cipher||function(f){var b=C,d=b.lib,a=d.Base,c=d.WordArray,q=d.BufferedBlockAlgorithm,e=b.enc.Base64,n=b.algo.EvpKDF,m=d.Cipher=q.extend({cfg:a.extend(),createEncryptor:function(a,g){return this.create(this._ENC_XFORM_MODE,a,g)},createDecryptor:function(a,g){return this.create(this._DEC_XFORM_MODE,a,g)},init:function(a,g,c){this.cfg=this.cfg.extend(c);this._xformMode=a; -this._key=g;this.reset()},reset:function(){q.reset.call(this);this._doReset()},process:function(a){this._append(a);return this._process()},finalize:function(a){a&&this._append(a);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(){return function(a){return{encrypt:function(g,c,e){return("string"==typeof c?F:h).encrypt(a,g,c,e)},decrypt:function(g,c,e){return("string"==typeof c?F:h).decrypt(a,g,c,e)}}}}()});d.StreamCipher=m.extend({_doFinalize:function(){return this._process(!0)}, -blockSize:1});var l=b.mode={},g=d.BlockCipherMode=a.extend({createEncryptor:function(a,g){return this.Encryptor.create(a,g)},createDecryptor:function(a,g){return this.Decryptor.create(a,g)},init:function(a,g){this._cipher=a;this._iv=g}});l=l.CBC=function(){function a(a,g,c){var e=this._iv;e?this._iv=f:e=this._prevBlock;for(var l=0;l>>2]&255}};d.BlockCipher=m.extend({cfg:m.cfg.extend({mode:l,padding:u}),reset:function(){m.reset.call(this); -var a=this.cfg,g=a.iv;a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,this,g&&g.words)},_doProcessBlock:function(a,g){this._mode.processBlock(a,g)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var g=this._process(!0)}else g=this._process(!0),a.unpad(g);return g},blockSize:4});var v=d.CipherParams=a.extend({init:function(a){this.mixIn(a)}, -toString:function(a){return(a||this.formatter).stringify(this)}});l=(b.format={}).OpenSSL={stringify:function(a){var g=a.ciphertext;a=a.salt;return(a?c.create([1398893684,1701076831]).concat(a).concat(g):g).toString(e)},parse:function(a){a=e.parse(a);var g=a.words;if(1398893684==g[0]&&1701076831==g[1]){var l=c.create(g.slice(2,4));g.splice(0,4);a.sigBytes-=16}return v.create({ciphertext:a,salt:l})}};var h=d.SerializableCipher=a.extend({cfg:a.extend({format:l}),encrypt:function(a,g,c,e){e=this.cfg.extend(e); -var l=a.createEncryptor(c,e);g=l.finalize(g);l=l.cfg;return v.create({ciphertext:g,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:e.format})},decrypt:function(a,g,c,e){e=this.cfg.extend(e);g=this._parse(g,e.format);return a.createDecryptor(c,e).finalize(g.ciphertext)},_parse:function(a,g){return"string"==typeof a?g.parse(a,this):a}});b=(b.kdf={}).OpenSSL={execute:function(a,g,e,l){l||(l=c.random(8));a=n.create({keySize:g+e}).compute(a,l);e=c.create(a.words.slice(g), -4*e);a.sigBytes=4*g;return v.create({key:a,iv:e,salt:l})}};var F=d.PasswordBasedCipher=h.extend({cfg:h.cfg.extend({kdf:b}),encrypt:function(a,g,c,e){e=this.cfg.extend(e);c=e.kdf.execute(c,a.keySize,a.ivSize);e.iv=c.iv;a=h.encrypt.call(this,a,g,c.key,e);a.mixIn(c);return a},decrypt:function(a,g,c,e){e=this.cfg.extend(e);g=this._parse(g,e.format);c=e.kdf.execute(c,a.keySize,a.ivSize,g.salt);e.iv=c.iv;return h.decrypt.call(this,a,g,c.key,e)}})}();(function(){var f=C,b=f.lib.BlockCipher,d=f.algo,a=[], -c=[],q=[],e=[],n=[],m=[],l=[],g=[],u=[],v=[];(function(){for(var d=[],f=0;256>f;f++)d[f]=128>f?f<<1:f<<1^283;var b=0,k=0;for(f=0;256>f;f++){var h=k^k<<1^k<<2^k<<3^k<<4;h=h>>>8^h&255^99;a[b]=h;c[h]=b;var y=d[b],p=d[y],r=d[p],t=257*d[h]^16843008*h;q[b]=t<<24|t>>>8;e[b]=t<<16|t>>>16;n[b]=t<<8|t>>>24;m[b]=t;t=16843009*r^65537*p^257*y^16843008*b;l[h]=t<<24|t>>>8;g[h]=t<<16|t>>>16;u[h]=t<<8|t>>>24;v[h]=t;b?(b=y^d[d[d[r^y]]],k^=d[d[k]]):b=k=1}})();var h=[0,1,2,4,8,16,32,64,128,27,54];d=d.AES=b.extend({_doReset:function(){var c= -this._key,e=c.words,d=c.sigBytes/4;c=4*((this._nRounds=d+6)+1);for(var f=this._keySchedule=[],b=0;b>>24]<<24|a[m>>>16&255]<<16|a[m>>>8&255]<<8|a[m&255]):(m=m<<8|m>>>24,m=a[m>>>24]<<24|a[m>>>16&255]<<16|a[m>>>8&255]<<8|a[m&255],m^=h[b/d|0]<<24);f[b]=f[b-d]^m}e=this._invKeySchedule=[];for(d=0;dd||4>=b?m:l[a[m>>>24]]^g[a[m>>>16&255]]^u[a[m>>>8&255]]^v[a[m&255]]},encryptBlock:function(g,c){this._doCryptBlock(g, -c,this._keySchedule,q,e,n,m,a)},decryptBlock:function(a,e){var d=a[e+1];a[e+1]=a[e+3];a[e+3]=d;this._doCryptBlock(a,e,this._invKeySchedule,l,g,u,v,c);d=a[e+1];a[e+1]=a[e+3];a[e+3]=d},_doCryptBlock:function(a,g,c,e,l,d,f,b){for(var m=this._nRounds,u=a[g]^c[0],n=a[g+1]^c[1],q=a[g+2]^c[2],k=a[g+3]^c[3],v=4,h=1;h>>24]^l[n>>>16&255]^d[q>>>8&255]^f[k&255]^c[v++],F=e[n>>>24]^l[q>>>16&255]^d[k>>>8&255]^f[u&255]^c[v++],R=e[q>>>24]^l[k>>>16&255]^d[u>>>8&255]^f[n&255]^c[v++];k=e[k>>>24]^l[u>>> -16&255]^d[n>>>8&255]^f[q&255]^c[v++];u=y;n=F;q=R}y=(b[u>>>24]<<24|b[n>>>16&255]<<16|b[q>>>8&255]<<8|b[k&255])^c[v++];F=(b[n>>>24]<<24|b[q>>>16&255]<<16|b[k>>>8&255]<<8|b[u&255])^c[v++];R=(b[q>>>24]<<24|b[k>>>16&255]<<16|b[u>>>8&255]<<8|b[n&255])^c[v++];k=(b[k>>>24]<<24|b[u>>>16&255]<<16|b[n>>>8&255]<<8|b[q&255])^c[v++];a[g]=y;a[g+1]=F;a[g+2]=R;a[g+3]=k},keySize:8});f.AES=b._createHelper(d)})();(function(){if("undefined"!==typeof ArrayBuffer){var b=C.lib.WordArray,k=b.init;(b.init=function(d){if(d instanceof -ArrayBuffer)d=new Uint8Array(d);else if(d instanceof Int8Array||"undefined"!==typeof Uint8ClampedArray&&d instanceof Uint8ClampedArray||d instanceof Int16Array||d instanceof Uint16Array||d instanceof Int32Array||d instanceof Uint32Array||"undefined"!==typeof Float32Array&&d instanceof Float32Array||"undefined"!==typeof Float64Array&&d instanceof Float64Array)d=new Uint8Array(d.buffer,d.byteOffset,d.byteLength);if(d instanceof Uint8Array){for(var a=d.byteLength,c=[],b=0;b>>2]|=d[b]<<24- -b%4*8;k.call(this,c,a)}else k.apply(this,arguments)}).prototype=b}})();var ca=function(){function b(){}b.addListener=function(b,d,a){b.addEventListener?b.addEventListener(d,a,!1):b.attachEvent("on"+d,function(){a.apply(b,arguments)})};b.removeListener=function(b,d,a){b.removeEventListener?b.removeEventListener(d,a,!1):b.detachEvent("on"+d,function(){a.apply(b,arguments)})};b.addMessageListener=function(f,d){b.addListener(f,"message",d)};b.removeMessageListener=function(f,d){b.removeListener(f,"message", -d)};b.addUnloadListener=function(f){b.addListener(window,"unload",f)};return b}(),da=function(){function b(a,g,c){for(var e=0,l=c.length;ed)a.setUint8(g++,d>>>0&127|0);else if(2048>d)a.setUint8(g++,d>>>6&31|192),a.setUint8(g++,d>>>0&63|128);else if(65536>d)a.setUint8(g++,d>>>12&15|224),a.setUint8(g++,d>>>6&63|128),a.setUint8(g++,d>>>0&63|128);else if(1114112>d)a.setUint8(g++,d>>>18&7|240),a.setUint8(g++,d>>>12&63|128),a.setUint8(g++,d>>>6&63|128),a.setUint8(g++, -d>>>0&63|128);else throw Error("bad codepoint "+d);}}function k(a,g,c){var e="",l=g;for(g+=c;ll)g+=1;else if(2048>l)g+=2;else if(65536>l)g+=3;else if(1114112>l)g+=4;else throw Error("bad codepoint "+l);}return g}function a(a,g){this.offset=g||0;this.view=a}function c(a,g){return h.keysArray(a,!0).filter(function(c){c=a[c];return(!g||void 0!==c&&null!==c)&&("function"!==typeof c||!!c.toJSON)})}function q(a,g,e,f){var l=typeof a;if("string"===l){var n=d(a);if(32>n)return g.setUint8(e,n|160),b(g,e+1,a),1+ -n;if(256>n)return g.setUint8(e,217),g.setUint8(e+1,n),b(g,e+2,a),2+n;if(65536>n)return g.setUint8(e,218),g.setUint16(e+1,n),b(g,e+3,a),3+n;if(4294967296>n)return g.setUint8(e,219),g.setUint32(e+1,n),b(g,e+5,a),5+n}if(a instanceof ArrayBuffer){n=a.byteLength;if(256>n)return g.setUint8(e,196),g.setUint8(e+1,n),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+2),2+n;if(65536>n)return g.setUint8(e,197),g.setUint16(e+1,n),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+3),3+n;if(4294967296>n)return g.setUint8(e, -198),g.setUint32(e+1,n),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+5),5+n}if("number"===l){if(Math.floor(a)!==a)return g.setUint8(e,203),g.setFloat64(e+1,a),9;if(0<=a){if(128>a)return g.setUint8(e,a),1;if(256>a)return g.setUint8(e,204),g.setUint8(e+1,a),2;if(65536>a)return g.setUint8(e,205),g.setUint16(e+1,a),3;if(4294967296>a)return g.setUint8(e,206),g.setUint32(e+1,a),5;if(1.8446744073709552E19>a)return g.setUint8(e,207),e+=1,1.8446744073709552E19>a?(g.setUint32(e,Math.floor(a*m)),g.setInt32(e+ -4,a&-1)):(g.setUint32(e,4294967295),g.setUint32(e+4,4294967295)),9;throw Error("Number too big 0x"+a.toString(16));}if(-32<=a)return g.setInt8(e,a),1;if(-128<=a)return g.setUint8(e,208),g.setInt8(e+1,a),2;if(-32768<=a)return g.setUint8(e,209),g.setInt16(e+1,a),3;if(-2147483648<=a)return g.setUint8(e,210),g.setInt32(e+1,a),5;if(-9223372036854775808<=a)return g.setUint8(e,211),e+=1,0x7fffffffffffffff>a?(g.setInt32(e,Math.floor(a*m)),g.setInt32(e+4,a&-1)):(g.setUint32(e,2147483647),g.setUint32(e+4,2147483647)), -9;throw Error("Number too small -0x"+(-a).toString(16).substr(1));}if("undefined"===l){if(f)return 0;g.setUint8(e,212);g.setUint8(e+1,0);g.setUint8(e+2,0);return 3}if(null===a){if(f)return 0;g.setUint8(e,192);return 1}if("boolean"===l)return g.setUint8(e,a?195:194),1;if("function"===typeof a.toJSON)return q(a.toJSON(),g,e,f);if("object"===l){l=0;var u=Array.isArray(a);if(u)n=a.length;else{var k=c(a,f);n=k.length}16>n?(g.setUint8(e,n|(u?144:128)),l=1):65536>n?(g.setUint8(e,u?220:222),g.setUint16(e+ -1,n),l=3):4294967296>n&&(g.setUint8(e,u?221:223),g.setUint32(e+1,n),l=5);if(u)for(u=0;ub)return 1+b;if(256>b)return 2+b;if(65536>b)return 3+b;if(4294967296>b)return 5+b}if(a instanceof ArrayBuffer){b=a.byteLength;if(256>b)return 2+b;if(65536>b)return 3+b;if(4294967296>b)return 5+ -b}if("number"===l){if(Math.floor(a)!==a)return 9;if(0<=a){if(128>a)return 1;if(256>a)return 2;if(65536>a)return 3;if(4294967296>a)return 5;if(1.8446744073709552E19>a)return 9;throw Error("Number too big 0x"+a.toString(16));}if(-32<=a)return 1;if(-128<=a)return 2;if(-32768<=a)return 3;if(-2147483648<=a)return 5;if(-9223372036854775808<=a)return 9;throw Error("Number too small -0x"+a.toString(16).substr(1));}if("boolean"===l)return 1;if(null===a)return g?0:1;if(void 0===a)return g?0:3;if("function"=== -typeof a.toJSON)return e(a.toJSON(),g);if("object"===l){l=0;if(Array.isArray(a)){b=a.length;for(var f=0;fb)return 1+l;if(65536>b)return 3+l;if(4294967296>b)return 5+l;throw Error("Array or object too long 0x"+b.toString(16));}if("function"===l)return 0;throw Error("Unknown type "+l);}var n={inspect:function(a){if(void 0===a)return"undefined";if(a instanceof ArrayBuffer){var g="ArrayBuffer";var e= -new DataView(a)}else a instanceof DataView&&(g="DataView",e=a);if(!e)return JSON.stringify(a);for(var c=[],l=0;l"}};n.utf8Write=b;n.utf8Read=k;n.utf8ByteCount=d;n.encode=function(a,g){var c=e(a,g);if(0!=c){c=new ArrayBuffer(c);var l=new DataView(c);q(a,l,0,g);return c}};n.decode=function(e){var g=new DataView(e);g=new a(g);var c=g.parse();if(g.offset!==e.byteLength)throw Error(e.byteLength- -g.offset+" trailing bytes");return c};var m=1/4294967296;a.prototype.map=function(a){for(var g={},e=0;e>>2]|=(c[e>>>2]>>>24-e%4*8&255)<<24-(k+e)%4*8;else if(65535>>2]=c[e>>>2];else a.push.apply(a,c);this.sigBytes+=g;return this},clamp:function(){var g=this.words,a=this.sigBytes;g[a>>>2]&=4294967295<<32-a%4*8;g.length=b.ceil(a/4)},clone:function(){var g=c.clone.call(this);g.words=this.words.slice(0);return g},random:function(g){function a(g){var a=987654321;return function(){a=36969*(a&65535)+(a>>16)&4294967295;g=18E3*(g&65535)+(g>>16)&4294967295;return(((a<<16)+g& +4294967295)/4294967296+.5)*(.5>>2]>>>24-e%4*8&255;c.push((k>>>4).toString(16));c.push((k&15).toString(16))}return c.join("")},parse:function(g){for(var a=g.length,c=[],e=0;e>>3]|=parseInt(g.substr(e,2),16)<<24-e%8*4;return new n.init(c, +a/2)}},p=e.Latin1={stringify:function(g){var a=g.words;g=g.sigBytes;for(var c=[],e=0;e>>2]>>>24-e%4*8&255));return c.join("")},parse:function(g){for(var a=g.length,c=[],e=0;e>>2]|=(g.charCodeAt(e)&255)<<24-e%4*8;return new n.init(c,a)}},k=e.Utf8={stringify:function(g){try{return decodeURIComponent(escape(p.stringify(g)))}catch(C){throw Error("Malformed UTF-8 data");}},parse:function(g){return p.parse(unescape(encodeURIComponent(g)))}},g=a.BufferedBlockAlgorithm= +c.extend({reset:function(){this._data=new n.init;this._nDataBytes=0},_append:function(g){"string"==typeof g&&(g=k.parse(g));this._data.concat(g);this._nDataBytes+=g.sigBytes},_process:function(g){var a=this._data,c=a.words,e=a.sigBytes,k=this.blockSize,r=e/(4*k);r=g?b.ceil(r):b.max((r|0)-this._minBufferSize,0);g=r*k;e=b.min(4*g,e);if(g){for(var f=0;fr;)a(g)&&(8>r&&(n[r]=c(b.pow(g,.5))),e[r]=c(b.pow(g,1/3)),r++),g++})();var m=[];f=f.SHA256=c.extend({_doReset:function(){this._hash=new a.init(n.slice(0))},_doProcessBlock:function(a,c){for(var g=this._hash.words,k=g[0],f=g[1],b=g[2],n=g[3],d=g[4], +p=g[5],l=g[6],h=g[7],I=0;64>I;I++){if(16>I)m[I]=a[c+I]|0;else{var q=m[I-15],Q=m[I-2];m[I]=((q<<25|q>>>7)^(q<<14|q>>>18)^q>>>3)+m[I-7]+((Q<<15|Q>>>17)^(Q<<13|Q>>>19)^Q>>>10)+m[I-16]}q=h+((d<<26|d>>>6)^(d<<21|d>>>11)^(d<<7|d>>>25))+(d&p^~d&l)+e[I]+m[I];Q=((k<<30|k>>>2)^(k<<19|k>>>13)^(k<<10|k>>>22))+(k&f^k&b^f&b);h=l;l=p;p=d;d=n+q|0;n=b;b=f;f=k;k=q+Q|0}g[0]=g[0]+k|0;g[1]=g[1]+f|0;g[2]=g[2]+b|0;g[3]=g[3]+n|0;g[4]=g[4]+d|0;g[5]=g[5]+p|0;g[6]=g[6]+l|0;g[7]=g[7]+h|0},_doFinalize:function(){var a=this._data, +c=a.words,g=8*this._nDataBytes,e=8*a.sigBytes;c[e>>>5]|=128<<24-e%32;c[(e+64>>>9<<4)+14]=b.floor(g/4294967296);c[(e+64>>>9<<4)+15]=g;a.sigBytes=4*c.length;this._process();return this._hash},clone:function(){var a=c.clone.call(this);a._hash=this._hash.clone();return a}});d.SHA256=c._createHelper(f);d.HmacSHA256=c._createHmacHelper(f)})(Math);(function(){var b=B,d=b.enc.Utf8;b.algo.HMAC=b.lib.Base.extend({init:function(f,a){f=this._hasher=new f.init;"string"==typeof a&&(a=d.parse(a));var c=f.blockSize, +b=4*c;a.sigBytes>b&&(a=f.finalize(a));a.clamp();for(var e=this._oKey=a.clone(),m=this._iKey=a.clone(),p=e.words,k=m.words,g=0;g>>2]>>>24-e%4*8&255)<<16|(a[e+1>>>2]>>>24-(e+1)%4*8&255)<<8|a[e+2>>>2]>>>24-(e+2)%4*8&255,p=0;4>p&&e+.75*p>>6*(3-p)&63));if(a=b.charAt(64))for(;f.length%4;)f.push(a);return f.join("")},parse:function(f){var a=f.length,c=this._map,b=c.charAt(64);b&&(b=f.indexOf(b),-1!=b&&(a=b));b=[];for(var e=0,m=0;m>>6-m%4*2;b[e>>> +2]|=(p|k)<<24-e%4*8;e++}return d.create(b,e)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();B.lib.Cipher||function(b){var d=B,f=d.lib,a=f.Base,c=f.WordArray,n=f.BufferedBlockAlgorithm,e=d.enc.Base64,m=d.algo.EvpKDF,p=f.Cipher=n.extend({cfg:a.extend(),createEncryptor:function(g,a){return this.create(this._ENC_XFORM_MODE,g,a)},createDecryptor:function(g,a){return this.create(this._DEC_XFORM_MODE,g,a)},init:function(g,a,c){this.cfg=this.cfg.extend(c);this._xformMode=g; +this._key=a;this.reset()},reset:function(){n.reset.call(this);this._doReset()},process:function(g){this._append(g);return this._process()},finalize:function(g){g&&this._append(g);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(){return function(g){return{encrypt:function(a,c,e){return("string"==typeof c?F:h).encrypt(g,a,c,e)},decrypt:function(a,c,e){return("string"==typeof c?F:h).decrypt(g,a,c,e)}}}}()});f.StreamCipher=p.extend({_doFinalize:function(){return this._process(!0)}, +blockSize:1});var k=d.mode={},g=f.BlockCipherMode=a.extend({createEncryptor:function(g,a){return this.Encryptor.create(g,a)},createDecryptor:function(g,a){return this.Decryptor.create(g,a)},init:function(g,a){this._cipher=g;this._iv=a}});k=k.CBC=function(){function a(g,a,c){var e=this._iv;e?this._iv=b:e=this._prevBlock;for(var k=0;k>>2]&255}};f.BlockCipher=p.extend({cfg:p.cfg.extend({mode:k,padding:r}),reset:function(){p.reset.call(this); +var g=this.cfg,a=g.iv;g=g.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=g.createEncryptor;else c=g.createDecryptor,this._minBufferSize=1;this._mode=c.call(g,this,a&&a.words)},_doProcessBlock:function(g,a){this._mode.processBlock(g,a)},_doFinalize:function(){var g=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){g.pad(this._data,this.blockSize);var a=this._process(!0)}else a=this._process(!0),g.unpad(a);return a},blockSize:4});var v=f.CipherParams=a.extend({init:function(g){this.mixIn(g)}, +toString:function(g){return(g||this.formatter).stringify(this)}});k=(d.format={}).OpenSSL={stringify:function(g){var a=g.ciphertext;g=g.salt;return(g?c.create([1398893684,1701076831]).concat(g).concat(a):a).toString(e)},parse:function(g){g=e.parse(g);var a=g.words;if(1398893684==a[0]&&1701076831==a[1]){var k=c.create(a.slice(2,4));a.splice(0,4);g.sigBytes-=16}return v.create({ciphertext:g,salt:k})}};var h=f.SerializableCipher=a.extend({cfg:a.extend({format:k}),encrypt:function(g,a,c,e){e=this.cfg.extend(e); +var k=g.createEncryptor(c,e);a=k.finalize(a);k=k.cfg;return v.create({ciphertext:a,key:c,iv:k.iv,algorithm:g,mode:k.mode,padding:k.padding,blockSize:g.blockSize,formatter:e.format})},decrypt:function(g,a,c,e){e=this.cfg.extend(e);a=this._parse(a,e.format);return g.createDecryptor(c,e).finalize(a.ciphertext)},_parse:function(g,a){return"string"==typeof g?a.parse(g,this):g}});d=(d.kdf={}).OpenSSL={execute:function(g,a,e,k){k||(k=c.random(8));g=m.create({keySize:a+e}).compute(g,k);e=c.create(g.words.slice(a), +4*e);g.sigBytes=4*a;return v.create({key:g,iv:e,salt:k})}};var F=f.PasswordBasedCipher=h.extend({cfg:h.cfg.extend({kdf:d}),encrypt:function(g,a,c,e){e=this.cfg.extend(e);c=e.kdf.execute(c,g.keySize,g.ivSize);e.iv=c.iv;g=h.encrypt.call(this,g,a,c.key,e);g.mixIn(c);return g},decrypt:function(g,a,c,e){e=this.cfg.extend(e);a=this._parse(a,e.format);c=e.kdf.execute(c,g.keySize,g.ivSize,a.salt);e.iv=c.iv;return h.decrypt.call(this,g,a,c.key,e)}})}();(function(){var b=B,d=b.lib.BlockCipher,f=b.algo,a=[], +c=[],n=[],e=[],m=[],p=[],k=[],g=[],r=[],v=[];(function(){for(var f=[],b=0;256>b;b++)f[b]=128>b?b<<1:b<<1^283;var d=0,l=0;for(b=0;256>b;b++){var h=l^l<<1^l<<2^l<<3^l<<4;h=h>>>8^h&255^99;a[d]=h;c[h]=d;var C=f[d],q=f[C],t=f[q],G=257*f[h]^16843008*h;n[d]=G<<24|G>>>8;e[d]=G<<16|G>>>16;m[d]=G<<8|G>>>24;p[d]=G;G=16843009*t^65537*q^257*C^16843008*d;k[h]=G<<24|G>>>8;g[h]=G<<16|G>>>16;r[h]=G<<8|G>>>24;v[h]=G;d?(d=C^f[f[f[t^C]]],l^=f[f[l]]):d=l=1}})();var h=[0,1,2,4,8,16,32,64,128,27,54];f=f.AES=d.extend({_doReset:function(){var c= +this._key,e=c.words,f=c.sigBytes/4;c=4*((this._nRounds=f+6)+1);for(var b=this._keySchedule=[],d=0;d>>24]<<24|a[m>>>16&255]<<16|a[m>>>8&255]<<8|a[m&255]):(m=m<<8|m>>>24,m=a[m>>>24]<<24|a[m>>>16&255]<<16|a[m>>>8&255]<<8|a[m&255],m^=h[d/f|0]<<24);b[d]=b[d-f]^m}e=this._invKeySchedule=[];for(f=0;ff||4>=d?m:k[a[m>>>24]]^g[a[m>>>16&255]]^r[a[m>>>8&255]]^v[a[m&255]]},encryptBlock:function(g,c){this._doCryptBlock(g, +c,this._keySchedule,n,e,m,p,a)},decryptBlock:function(a,e){var f=a[e+1];a[e+1]=a[e+3];a[e+3]=f;this._doCryptBlock(a,e,this._invKeySchedule,k,g,r,v,c);f=a[e+1];a[e+1]=a[e+3];a[e+3]=f},_doCryptBlock:function(g,a,c,e,k,f,r,b){for(var d=this._nRounds,m=g[a]^c[0],n=g[a+1]^c[1],p=g[a+2]^c[2],l=g[a+3]^c[3],v=4,h=1;h>>24]^k[n>>>16&255]^f[p>>>8&255]^r[l&255]^c[v++],F=e[n>>>24]^k[p>>>16&255]^f[l>>>8&255]^r[m&255]^c[v++],T=e[p>>>24]^k[l>>>16&255]^f[m>>>8&255]^r[n&255]^c[v++];l=e[l>>>24]^k[m>>> +16&255]^f[n>>>8&255]^r[p&255]^c[v++];m=C;n=F;p=T}C=(b[m>>>24]<<24|b[n>>>16&255]<<16|b[p>>>8&255]<<8|b[l&255])^c[v++];F=(b[n>>>24]<<24|b[p>>>16&255]<<16|b[l>>>8&255]<<8|b[m&255])^c[v++];T=(b[p>>>24]<<24|b[l>>>16&255]<<16|b[m>>>8&255]<<8|b[n&255])^c[v++];l=(b[l>>>24]<<24|b[m>>>16&255]<<16|b[n>>>8&255]<<8|b[p&255])^c[v++];g[a]=C;g[a+1]=F;g[a+2]=T;g[a+3]=l},keySize:8});b.AES=d._createHelper(f)})();(function(){if("undefined"!==typeof ArrayBuffer){var b=B.lib.WordArray,d=b.init;(b.init=function(f){if(f instanceof +ArrayBuffer)f=new Uint8Array(f);else if(f instanceof Int8Array||"undefined"!==typeof Uint8ClampedArray&&f instanceof Uint8ClampedArray||f instanceof Int16Array||f instanceof Uint16Array||f instanceof Int32Array||f instanceof Uint32Array||"undefined"!==typeof Float32Array&&f instanceof Float32Array||"undefined"!==typeof Float64Array&&f instanceof Float64Array)f=new Uint8Array(f.buffer,f.byteOffset,f.byteLength);if(f instanceof Uint8Array){for(var a=f.byteLength,c=[],b=0;b>>2]|=f[b]<<24- +b%4*8;d.call(this,c,a)}else d.apply(this,arguments)}).prototype=b}})();var ea=function(){function b(){}b.addListener=function(b,f,a){b.addEventListener?b.addEventListener(f,a,!1):b.attachEvent("on"+f,function(){a.apply(b,arguments)})};b.removeListener=function(b,f,a){b.removeEventListener?b.removeEventListener(f,a,!1):b.detachEvent("on"+f,function(){a.apply(b,arguments)})};b.addMessageListener=function(d,f){b.addListener(d,"message",f)};b.removeMessageListener=function(d,f){b.removeListener(d,"message", +f)};b.addUnloadListener=function(d){b.addListener(window,"unload",d)};return b}(),fa=function(){function b(a,g,c){for(var e=0,k=c.length;ef)a.setUint8(g++,f>>>0&127|0);else if(2048>f)a.setUint8(g++,f>>>6&31|192),a.setUint8(g++,f>>>0&63|128);else if(65536>f)a.setUint8(g++,f>>>12&15|224),a.setUint8(g++,f>>>6&63|128),a.setUint8(g++,f>>>0&63|128);else if(1114112>f)a.setUint8(g++,f>>>18&7|240),a.setUint8(g++,f>>>12&63|128),a.setUint8(g++,f>>>6&63|128),a.setUint8(g++, +f>>>0&63|128);else throw Error("bad codepoint "+f);}}function d(a,g,c){var e="",k=g;for(g+=c;kk)g+=1;else if(2048>k)g+=2;else if(65536>k)g+=3;else if(1114112>k)g+=4;else throw Error("bad codepoint "+k);}return g}function a(a,g){this.offset=g||0;this.view=a}function c(a,g){return h.keysArray(a,!0).filter(function(c){c=a[c];return(!g||void 0!==c&&null!==c)&&("function"!==typeof c||!!c.toJSON)})}function n(a,g,e,d){var k=typeof a;if("string"===k){var m=f(a);if(32>m)return g.setUint8(e,m|160),b(g,e+1,a),1+ +m;if(256>m)return g.setUint8(e,217),g.setUint8(e+1,m),b(g,e+2,a),2+m;if(65536>m)return g.setUint8(e,218),g.setUint16(e+1,m),b(g,e+3,a),3+m;if(4294967296>m)return g.setUint8(e,219),g.setUint32(e+1,m),b(g,e+5,a),5+m}if(a instanceof ArrayBuffer){m=a.byteLength;if(256>m)return g.setUint8(e,196),g.setUint8(e+1,m),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+2),2+m;if(65536>m)return g.setUint8(e,197),g.setUint16(e+1,m),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+3),3+m;if(4294967296>m)return g.setUint8(e, +198),g.setUint32(e+1,m),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+5),5+m}if("number"===k){if(Math.floor(a)!==a)return g.setUint8(e,203),g.setFloat64(e+1,a),9;if(0<=a){if(128>a)return g.setUint8(e,a),1;if(256>a)return g.setUint8(e,204),g.setUint8(e+1,a),2;if(65536>a)return g.setUint8(e,205),g.setUint16(e+1,a),3;if(4294967296>a)return g.setUint8(e,206),g.setUint32(e+1,a),5;if(1.8446744073709552E19>a)return g.setUint8(e,207),e+=1,1.8446744073709552E19>a?(g.setUint32(e,Math.floor(a*p)),g.setInt32(e+ +4,a&-1)):(g.setUint32(e,4294967295),g.setUint32(e+4,4294967295)),9;throw Error("Number too big 0x"+a.toString(16));}if(-32<=a)return g.setInt8(e,a),1;if(-128<=a)return g.setUint8(e,208),g.setInt8(e+1,a),2;if(-32768<=a)return g.setUint8(e,209),g.setInt16(e+1,a),3;if(-2147483648<=a)return g.setUint8(e,210),g.setInt32(e+1,a),5;if(-9223372036854775808<=a)return g.setUint8(e,211),e+=1,0x7fffffffffffffff>a?(g.setInt32(e,Math.floor(a*p)),g.setInt32(e+4,a&-1)):(g.setUint32(e,2147483647),g.setUint32(e+4,2147483647)), +9;throw Error("Number too small -0x"+(-a).toString(16).substr(1));}if("undefined"===k){if(d)return 0;g.setUint8(e,212);g.setUint8(e+1,0);g.setUint8(e+2,0);return 3}if(null===a){if(d)return 0;g.setUint8(e,192);return 1}if("boolean"===k)return g.setUint8(e,a?195:194),1;if("function"===typeof a.toJSON)return n(a.toJSON(),g,e,d);if("object"===k){k=0;var r=Array.isArray(a);if(r)m=a.length;else{var l=c(a,d);m=l.length}16>m?(g.setUint8(e,m|(r?144:128)),k=1):65536>m?(g.setUint8(e,r?220:222),g.setUint16(e+ +1,m),k=3):4294967296>m&&(g.setUint8(e,r?221:223),g.setUint32(e+1,m),k=5);if(r)for(r=0;rb)return 1+b;if(256>b)return 2+b;if(65536>b)return 3+b;if(4294967296>b)return 5+b}if(a instanceof ArrayBuffer){b=a.byteLength;if(256>b)return 2+b;if(65536>b)return 3+b;if(4294967296>b)return 5+ +b}if("number"===k){if(Math.floor(a)!==a)return 9;if(0<=a){if(128>a)return 1;if(256>a)return 2;if(65536>a)return 3;if(4294967296>a)return 5;if(1.8446744073709552E19>a)return 9;throw Error("Number too big 0x"+a.toString(16));}if(-32<=a)return 1;if(-128<=a)return 2;if(-32768<=a)return 3;if(-2147483648<=a)return 5;if(-9223372036854775808<=a)return 9;throw Error("Number too small -0x"+a.toString(16).substr(1));}if("boolean"===k)return 1;if(null===a)return g?0:1;if(void 0===a)return g?0:3;if("function"=== +typeof a.toJSON)return e(a.toJSON(),g);if("object"===k){k=0;if(Array.isArray(a)){b=a.length;for(var d=0;db)return 1+k;if(65536>b)return 3+k;if(4294967296>b)return 5+k;throw Error("Array or object too long 0x"+b.toString(16));}if("function"===k)return 0;throw Error("Unknown type "+k);}var m={inspect:function(a){if(void 0===a)return"undefined";if(a instanceof ArrayBuffer){var g="ArrayBuffer";var e= +new DataView(a)}else a instanceof DataView&&(g="DataView",e=a);if(!e)return JSON.stringify(a);for(var c=[],k=0;k"}};m.utf8Write=b;m.utf8Read=d;m.utf8ByteCount=f;m.encode=function(a,g){var c=e(a,g);if(0!=c){c=new ArrayBuffer(c);var k=new DataView(c);n(a,k,0,g);return c}};m.decode=function(e){var g=new DataView(e);g=new a(g);var c=g.parse();if(g.offset!==e.byteLength)throw Error(e.byteLength- +g.offset+" trailing bytes");return c};var p=1/4294967296;a.prototype.map=function(a){for(var g={},e=0;e>>2]>>> -24-f%4*8&255;return e}throw Error("BufferUtils.toArrayBuffer expected a buffer");};d.toWordArray=function(c){return b(c)?c:a.create(c)};d.base64Encode=function(a){if(k(a)){var c="";a=new Uint8Array(a);var e=a.byteLength,d=e%3;e-=d;for(var g,f,q,h,F=0;F>18,f=(h&258048)>>12,q=(h&4032)>>6,h&=63,c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[g]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[f]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[q]+ -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[h];1==d?(h=a[e],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&252)>>2]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&3)<<4]+"=="):2==d&&(h=a[e]<<8|a[e+1],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&64512)>>10]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&1008)>>4]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h& -15)<<2]+"=");return c}if(b(a))return C.enc.Base64.stringify(a)};d.base64Decode=function(a){if(c&&q){a=q(a);for(var e=a.length,b=new Uint8Array(e),d=0;d=c}function a(a){var c=a.connection;return(c=c&&c.connectionManager.host)? -[c].concat(r.getFallbackHosts(a.options)):r.getHosts(a.options)}var c=Date.now||function(){return(new Date).getTime()};k._getHosts=a;k.methods=["get","delete","post","put","patch"];k.methodsWithoutBody=["get","delete"];k.methodsWithBody=h.arrSubtract(k.methods,k.methodsWithoutBody);h.arrForEach(k.methodsWithoutBody,function(a){k[a]=function(c,b,d,f,g){k["do"](a,c,b,d,null,f,g)};k[a+"Uri"]=function(c,b,d,f,g){k.doUri(a,c,b,d,null,f,g)}});h.arrForEach(k.methodsWithBody,function(a){k[a]=function(c,b, -d,f,g,q){k["do"](a,c,b,d,f,g,q)};k[a+"Uri"]=function(c,b,d,f,g,q){k.doUri(a,c,b,d,f,g,q)}});k["do"]=function(f,e,n,m,l,g,u){u=u||b;var q="function"==typeof n?n:function(a){return e.baseUri(a)+n},h=arguments,F=e._currentFallback;if(F){if(F.validUntil>c()){k.Request(f,e,q(F.host),m,g,l,function(a){a&&d(a)?(e._currentFallback=null,k["do"].apply(k,h)):u.apply(null,arguments)});return}e._currentFallback=null}F=a(e);if(1==F.length)k.doUri(f,e,q(F[0]),m,l,g,u);else{var R=function(a,b){var n=a.shift();k.doUri(f, -e,q(n),m,l,g,function(g){g&&d(g)&&a.length?R(a,!0):(b&&(e._currentFallback={host:n,validUntil:c()+e.options.timeouts.fallbackRetryTimeout}),u.apply(null,arguments))})};R(F)}};k.doUri=function(a,c,b,d,f,g,u){k.Request(a,c,b,d,g,f,u)};k.supportsAuthHeaders=!1;k.supportsLinkHeaders=!1;return k}(),la=function(){function b(){this.buffer=[]}function k(a){this._input=a;this._index=-1;this._buffer=[]}function d(a){this._input=a;this._index=-1;this._buffer=[]}b.prototype.append=function(a){this.buffer.push(a); -return this};b.prototype.toString=function(){return this.buffer.join("")};var a={codex:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(c){var d=new b,e=a.codex;for(c=new k(c);c.moveNext();){var f=c.current;c.moveNext();var m=c.current;c.moveNext();var l=c.current,g=f>>2;f=(f&3)<<4|m>>4;var u=(m&15)<<2|l>>6,h=l&63;isNaN(m)?u=h=64:isNaN(l)&&(h=64);d.append(e.charAt(g)+e.charAt(f)+e.charAt(u)+e.charAt(h))}return d.toString()},decode:function(a){var c=new b;for(a=new d(a);a.moveNext();){var e= -a.current;if(128>e)c.append(String.fromCharCode(e));else if(191e){a.moveNext();var f=a.current;c.append(String.fromCharCode((e&31)<<6|f&63))}else a.moveNext(),f=a.current,a.moveNext(),c.append(String.fromCharCode((e&15)<<12|(f&63)<<6|a.current&63))}return c.toString()}};k.prototype={current:Number.NaN,moveNext:function(){if(0=this._input.length-1)return this.current=Number.NaN,!1;var a=this._input.charCodeAt(++this._index); -13==a&&10==this._input.charCodeAt(this._index+1)&&(a=10,this._index+=2);128>a?this.current=a:(127a?this.current=a>>6|192:(this.current=a>>12|224,this._buffer.push(a>>6&63|128)),this._buffer.push(a&63|128));return!0}};d.prototype={current:64,moveNext:function(){if(0=this._input.length-1)return this.current=64,!1;var c=a.codex.indexOf(this._input.charAt(++this._index)),b=a.codex.indexOf(this._input.charAt(++this._index)), -e=a.codex.indexOf(this._input.charAt(++this._index)),d=a.codex.indexOf(this._input.charAt(++this._index)),f=(e&3)<<6|d;this.current=c<<2|b>>4;64!=e&&this._buffer.push((b&15)<<4|e>>2);64!=d&&this._buffer.push(f);return!0}};return a}();r.ENVIRONMENT="";r.REST_HOST="rest.ably.io";r.REALTIME_HOST="realtime.ably.io";r.FALLBACK_HOSTS=["A.ably-realtime.com","B.ably-realtime.com","C.ably-realtime.com","D.ably-realtime.com","E.ably-realtime.com"];r.PORT=80;r.TLS_PORT=443;r.TIMEOUTS={disconnectedRetryTimeout:15E3, -suspendedRetryTimeout:3E4,httpRequestTimeout:15E3,channelRetryTimeout:15E3,fallbackRetryTimeout:6E5,connectionStateTtl:12E4,realtimeRequestTimeout:1E4,recvTimeout:9E4,preferenceConnectTimeout:6E3,parallelUpgradeDelay:6E3};r.httpMaxRetryCount=3;r.maxMessageSize=65536;r.version="1.1.7";r.libstring=t.libver+r.version;r.apiVersion="1.1";r.getHost=function(b,k,d){return k=d?k==b.restHost&&b.realtimeHost||k||b.realtimeHost:k||b.restHost};r.getPort=function(b,k){return k||b.tls?b.tlsPort:b.port};r.getHttpScheme= -function(b){return b.tls?"https://":"http://"};r.getFallbackHosts=function(b){var f=b.fallbackHosts;b="undefined"!==typeof b.httpMaxRetryCount?b.httpMaxRetryCount:r.httpMaxRetryCount;return f?h.arrChooseN(f,b):[]};r.getHosts=function(b){return[b.restHost].concat(r.getFallbackHosts(b))};r.objectifyOptions=function(b){return"string"==typeof b?-1==b.indexOf(":")?{token:b}:{key:b}:b};r.normaliseOptions=function(f){f.host&&(b.deprecated("host","restHost"),f.restHost=f.host);f.wsHost&&(b.deprecated("wsHost", -"realtimeHost"),f.realtimeHost=f.wsHost);f.queueEvents&&(b.deprecated("queueEvents","queueMessages"),f.queueMessages=f.queueEvents);!0===f.recover&&(b.deprecated("{recover: true}","{recover: function(lastConnectionDetails, cb) { cb(true); }}"),f.recover=function(a,b){b(!0)});"function"===typeof f.recover&&!0===f.closeOnUnload&&(b.logAction(b.LOG_ERROR,"Defaults.normaliseOptions","closeOnUnload was true and a session recovery function was set - these are mutually exclusive, so unsetting the latter"), -f.recover=null);"closeOnUnload"in f||(f.closeOnUnload=!f.recover);f.transports&&h.arrIn(f.transports,"xhr")&&(b.deprecated('transports: ["xhr"]','transports: ["xhr_streaming"]'),h.arrDeleteValue(f.transports,"xhr"),f.transports.push("xhr_streaming"));"queueMessages"in f||(f.queueMessages=!0);var k=!1;if(f.restHost)f.realtimeHost=f.realtimeHost||f.restHost;else{var d=f.environment&&String(f.environment).toLowerCase()||r.ENVIRONMENT;k=!d||"production"===d;f.restHost=k?r.REST_HOST:d+"-"+r.REST_HOST; -f.realtimeHost=k?r.REALTIME_HOST:d+"-"+r.REALTIME_HOST}f.fallbackHosts=k||f.fallbackHostsUseDefault?r.FALLBACK_HOSTS:f.fallbackHosts;h.arrForEach((f.fallbackHosts||[]).concat(f.restHost,f.realtimeHost),ia);f.port=f.port||r.PORT;f.tlsPort=f.tlsPort||r.TLS_PORT;f.maxMessageSize=f.maxMessageSize||r.maxMessageSize;"tls"in f||(f.tls=!0);f.timeouts={};for(var a in r.TIMEOUTS)f.timeouts[a]=f[a]||r.TIMEOUTS[a];f.useBinaryProtocol="useBinaryProtocol"in f?t.supportsBinary&&f.useBinaryProtocol:t.preferBinary; -f.clientId&&((f.headers=f.headers||{})["X-Ably-ClientId"]=f.clientId);"idempotentRestPublishing"in f||(f.idempotentRestPublishing=!1);f.promises&&!t.Promise&&(b.logAction(b.LOG_ERROR,"Defaults.normaliseOptions","{promises: true} was specified, but no Promise constructor found; disabling promises"),f.promises=!1);return f};var B=function(){function f(){this.any=[];this.events={};this.anyOnce=[];this.eventsOnce={}}function k(a,c,d){try{c.apply(a,d)}catch(e){b.logAction(b.LOG_ERROR,"EventEmitter.emit()", -"Unexpected listener exception: "+e+"; stack = "+(e&&e.stack))}}function d(a,c,b){var e,f,m;for(m=0;m=d?null:c.slice(0,d).join("/"),b.data=f}}};f.fromResponseBody=function(d,a,c){c&&(d=h.decodeBody(d,c));for(c=0;c>>2]>>> +24-k%4*8&255;return e}throw Error("BufferUtils.toArrayBuffer expected a buffer");};f.toWordArray=function(c){return b(c)?c:a.create(c)};f.base64Encode=function(a){if(d(a)){var c="";a=new Uint8Array(a);var e=a.byteLength,f=e%3;e-=f;for(var g,n,l,h,F=0;F>18,n=(h&258048)>>12,l=(h&4032)>>6,h&=63,c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[g]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[n]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[l]+ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[h];1==f?(h=a[e],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&252)>>2]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&3)<<4]+"=="):2==f&&(h=a[e]<<8|a[e+1],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&64512)>>10]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&1008)>>4]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h& +15)<<2]+"=");return c}if(b(a))return B.enc.Base64.stringify(a)};f.base64Decode=function(a){if(c&&n){a=n(a);for(var e=a.length,b=new Uint8Array(e),f=0;f=c}function a(a){var c=a.connection;return(c=c&&c.connectionManager.host)? +[c].concat(t.getFallbackHosts(a.options)):t.getHosts(a.options)}var c=Date.now||function(){return(new Date).getTime()};d._getHosts=a;d.methods=["get","delete","post","put","patch"];d.methodsWithoutBody=["get","delete"];d.methodsWithBody=h.arrSubtract(d.methods,d.methodsWithoutBody);h.arrForEach(d.methodsWithoutBody,function(a){d[a]=function(c,b,f,k,g){d["do"](a,c,b,f,null,k,g)};d[a+"Uri"]=function(c,b,f,k,g){d.doUri(a,c,b,f,null,k,g)}});h.arrForEach(d.methodsWithBody,function(a){d[a]=function(c,b, +f,k,g,r){d["do"](a,c,b,f,k,g,r)};d[a+"Uri"]=function(c,b,f,k,g,r){d.doUri(a,c,b,f,k,g,r)}});d["do"]=function(n,e,m,p,k,g,r){r=r||b;var l="function"==typeof m?m:function(a){return e.baseUri(a)+m},h=arguments,F=e._currentFallback;if(F){if(F.validUntil>c()){d.Request(n,e,l(F.host),p,g,k,function(a){a&&f(a)?(e._currentFallback=null,d["do"].apply(d,h)):r.apply(null,arguments)});return}e._currentFallback=null}F=a(e);if(1==F.length)d.doUri(n,e,l(F[0]),p,k,g,r);else{var T=function(a,b){var m=a.shift();d.doUri(n, +e,l(m),p,k,g,function(g){g&&f(g)&&a.length?T(a,!0):(b&&(e._currentFallback={host:m,validUntil:c()+e.options.timeouts.fallbackRetryTimeout}),r.apply(null,arguments))})};T(F)}};d.doUri=function(a,c,b,f,k,g,r){d.Request(a,c,b,f,g,k,r)};d.supportsAuthHeaders=!1;d.supportsLinkHeaders=!1;return d}(),na=function(){function b(){this.buffer=[]}function d(a){this._input=a;this._index=-1;this._buffer=[]}function f(a){this._input=a;this._index=-1;this._buffer=[]}b.prototype.append=function(a){this.buffer.push(a); +return this};b.prototype.toString=function(){return this.buffer.join("")};var a={codex:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(c){var f=new b,e=a.codex;for(c=new d(c);c.moveNext();){var m=c.current;c.moveNext();var p=c.current;c.moveNext();var k=c.current,g=m>>2;m=(m&3)<<4|p>>4;var r=(p&15)<<2|k>>6,l=k&63;isNaN(p)?r=l=64:isNaN(k)&&(l=64);f.append(e.charAt(g)+e.charAt(m)+e.charAt(r)+e.charAt(l))}return f.toString()},decode:function(a){var c=new b;for(a=new f(a);a.moveNext();){var e= +a.current;if(128>e)c.append(String.fromCharCode(e));else if(191e){a.moveNext();var d=a.current;c.append(String.fromCharCode((e&31)<<6|d&63))}else a.moveNext(),d=a.current,a.moveNext(),c.append(String.fromCharCode((e&15)<<12|(d&63)<<6|a.current&63))}return c.toString()}};d.prototype={current:Number.NaN,moveNext:function(){if(0=this._input.length-1)return this.current=Number.NaN,!1;var a=this._input.charCodeAt(++this._index); +13==a&&10==this._input.charCodeAt(this._index+1)&&(a=10,this._index+=2);128>a?this.current=a:(127a?this.current=a>>6|192:(this.current=a>>12|224,this._buffer.push(a>>6&63|128)),this._buffer.push(a&63|128));return!0}};f.prototype={current:64,moveNext:function(){if(0=this._input.length-1)return this.current=64,!1;var c=a.codex.indexOf(this._input.charAt(++this._index)),b=a.codex.indexOf(this._input.charAt(++this._index)), +e=a.codex.indexOf(this._input.charAt(++this._index)),f=a.codex.indexOf(this._input.charAt(++this._index)),d=(e&3)<<6|f;this.current=c<<2|b>>4;64!=e&&this._buffer.push((b&15)<<4|e>>2);64!=f&&this._buffer.push(d);return!0}};return a}();t.ENVIRONMENT="";t.REST_HOST="rest.ably.io";t.REALTIME_HOST="realtime.ably.io";t.FALLBACK_HOSTS=["A.ably-realtime.com","B.ably-realtime.com","C.ably-realtime.com","D.ably-realtime.com","E.ably-realtime.com"];t.PORT=80;t.TLS_PORT=443;t.TIMEOUTS={disconnectedRetryTimeout:15E3, +suspendedRetryTimeout:3E4,httpRequestTimeout:15E3,channelRetryTimeout:15E3,fallbackRetryTimeout:6E5,connectionStateTtl:12E4,realtimeRequestTimeout:1E4,recvTimeout:9E4,preferenceConnectTimeout:6E3,parallelUpgradeDelay:6E3};t.httpMaxRetryCount=3;t.maxMessageSize=65536;t.version="1.1.8";t.libstring=u.libver+t.version;t.apiVersion="1.1";t.getHost=function(b,d,f){return d=f?d==b.restHost&&b.realtimeHost||d||b.realtimeHost:d||b.restHost};t.getPort=function(b,d){return d||b.tls?b.tlsPort:b.port};t.getHttpScheme= +function(b){return b.tls?"https://":"http://"};t.getFallbackHosts=function(b){var d=b.fallbackHosts;b="undefined"!==typeof b.httpMaxRetryCount?b.httpMaxRetryCount:t.httpMaxRetryCount;return d?h.arrChooseN(d,b):[]};t.getHosts=function(b){return[b.restHost].concat(t.getFallbackHosts(b))};t.objectifyOptions=function(b){return"string"==typeof b?-1==b.indexOf(":")?{token:b}:{key:b}:b};t.normaliseOptions=function(b){b.host&&(d.deprecated("host","restHost"),b.restHost=b.host);b.wsHost&&(d.deprecated("wsHost", +"realtimeHost"),b.realtimeHost=b.wsHost);b.queueEvents&&(d.deprecated("queueEvents","queueMessages"),b.queueMessages=b.queueEvents);!0===b.recover&&(d.deprecated("{recover: true}","{recover: function(lastConnectionDetails, cb) { cb(true); }}"),b.recover=function(a,b){b(!0)});"function"===typeof b.recover&&!0===b.closeOnUnload&&(d.logAction(d.LOG_ERROR,"Defaults.normaliseOptions","closeOnUnload was true and a session recovery function was set - these are mutually exclusive, so unsetting the latter"), +b.recover=null);"closeOnUnload"in b||(b.closeOnUnload=!b.recover);b.transports&&h.arrIn(b.transports,"xhr")&&(d.deprecated('transports: ["xhr"]','transports: ["xhr_streaming"]'),h.arrDeleteValue(b.transports,"xhr"),b.transports.push("xhr_streaming"));"queueMessages"in b||(b.queueMessages=!0);var l=!1;if(b.restHost)b.realtimeHost=b.realtimeHost||b.restHost;else{var f=b.environment&&String(b.environment).toLowerCase()||t.ENVIRONMENT;l=!f||"production"===f;b.restHost=l?t.REST_HOST:f+"-"+t.REST_HOST; +b.realtimeHost=l?t.REALTIME_HOST:f+"-"+t.REALTIME_HOST}b.fallbackHosts=l||b.fallbackHostsUseDefault?t.FALLBACK_HOSTS:b.fallbackHosts;h.arrForEach((b.fallbackHosts||[]).concat(b.restHost,b.realtimeHost),ka);b.port=b.port||t.PORT;b.tlsPort=b.tlsPort||t.TLS_PORT;b.maxMessageSize=b.maxMessageSize||t.maxMessageSize;"tls"in b||(b.tls=!0);b.timeouts={};for(var a in t.TIMEOUTS)b.timeouts[a]=b[a]||t.TIMEOUTS[a];b.useBinaryProtocol="useBinaryProtocol"in b?u.supportsBinary&&b.useBinaryProtocol:u.preferBinary; +b.clientId&&((b.headers=b.headers||{})["X-Ably-ClientId"]=b.clientId);"idempotentRestPublishing"in b||(b.idempotentRestPublishing=!1);b.promises&&!u.Promise&&(d.logAction(d.LOG_ERROR,"Defaults.normaliseOptions","{promises: true} was specified, but no Promise constructor found; disabling promises"),b.promises=!1);return b};var A=function(){function b(){this.any=[];this.events={};this.anyOnce=[];this.eventsOnce={}}function l(a,c,b){try{c.apply(a,b)}catch(e){d.logAction(d.LOG_ERROR,"EventEmitter.emit()", +"Unexpected listener exception: "+e+"; stack = "+(e&&e.stack))}}function f(a,c,b){var e,d,n;for(n=0;n=d?null:c.slice(0,d).join("/"),b.data=f}}};b.fromResponseBody=function(f,a,c){c&&(f=h.decodeBody(f,c));for(c=0;ch.arrIndexOf(m,b.shortName)}function d(a,b,c,e){this.options=a;this.host=b;this.mode=c;this.connectionKey=e;this.format=a.useBinaryProtocol?"msgpack":"json";this.timeSerial=this.connectionSerial=void 0}function a(c,e){B.call(this);this.realtime=c;this.options=e;var g=e.timeouts,d=this;this.states={initialized:{state:"initialized", -terminal:!1,queueEvents:!0,sendEvents:!1,failState:"disconnected"},connecting:{state:"connecting",terminal:!1,queueEvents:!0,sendEvents:!1,retryDelay:g.preferenceConnectTimeout+g.realtimeRequestTimeout,failState:"disconnected"},connected:{state:"connected",terminal:!1,queueEvents:!1,sendEvents:!0,failState:"disconnected"},synchronizing:{state:"connected",terminal:!1,queueEvents:!0,sendEvents:!1,forceQueueEvents:!0,failState:"disconnected"},disconnected:{state:"disconnected",terminal:!1,queueEvents:!0, -sendEvents:!1,retryDelay:g.disconnectedRetryTimeout,failState:"disconnected"},suspended:{state:"suspended",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:g.suspendedRetryTimeout,failState:"suspended"},closing:{state:"closing",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:g.realtimeRequestTimeout,failState:"closed"},closed:{state:"closed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"closed"},failed:{state:"failed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"failed"}};this.state= -this.states.initialized;this.errorReason=null;this.queuedMessages=new ea;this.msgSerial=0;this.connectionSerial=this.timeSerial=this.connectionKey=this.connectionId=this.connectionDetails=void 0;this.connectionStateTtl=g.connectionStateTtl;this.maxIdleInterval=null;this.transports=h.intersect(e.transports||r.defaultTransports,a.supportedTransports);this.baseTransport=h.intersect(r.baseTransportOrder,this.transports)[0];this.upgradeTransports=h.intersect(this.transports,r.upgradeTransports);this.transportPreference= -null;this.httpHosts=r.getHosts(e);this.activeProtocol=null;this.proposedTransports=[];this.pendingTransports=[];this.mostRecentMsgId=this.lastActivity=this.lastAutoReconnectAttempt=this.host=null;this.forceFallbackHost=!1;b.logAction(b.LOG_MINOR,"Realtime.ConnectionManager()","started");b.logAction(b.LOG_MICRO,"Realtime.ConnectionManager()","requested transports = ["+(e.transports||r.defaultTransports)+"]");b.logAction(b.LOG_MICRO,"Realtime.ConnectionManager()","available transports = ["+this.transports+ -"]");b.logAction(b.LOG_MICRO,"Realtime.ConnectionManager()","http hosts = ["+this.httpHosts+"]");if(!this.transports.length)throw b.logAction(b.LOG_ERROR,"realtime.ConnectionManager()","no requested transports available"),Error("no requested transports available");if(g=t.addEventListener)q&&"function"===typeof e.recover&&g("beforeunload",this.persistConnection.bind(this)),!0===e.closeOnUnload&&g("beforeunload",function(){b.logAction(b.LOG_MAJOR,"Realtime.ConnectionManager()","beforeunload event has triggered the connection to close as closeOnUnload is true"); -d.requestState({state:"closing"})}),g("online",function(){if(d.state==d.states.disconnected||d.state==d.states.suspended)b.logAction(b.LOG_MINOR,"ConnectionManager caught browser \u2018online\u2019 event","reattempting connection"),d.requestState({state:"connecting"})}),g("offline",function(){d.state==d.states.connected&&(b.logAction(b.LOG_MINOR,"ConnectionManager caught browser \u2018offline\u2019 event","disconnecting active transport"),d.disconnectAllTransports())})}var c=!("undefined"===typeof J|| -!J.get),q=!("undefined"===typeof J||!J.getSession),e=z.Action,n=fa.PendingMessage,m=r.transportPreferenceOrder,l=m[m.length-1];d.prototype.getConnectParams=function(a){a=a?h.copy(a):{};var b=this.options;switch(this.mode){case "upgrade":a.upgrade=this.connectionKey;break;case "resume":a.resume=this.connectionKey;void 0!==this.timeSerial?a.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(a.connectionSerial=this.connectionSerial);break;case "recover":var c=b.recover.split(":");c&&(a.recover= -c[0],c=c[1],isNaN(c)?a.timeSerial=c:a.connectionSerial=c)}void 0!==b.clientId&&(a.clientId=b.clientId);!1===b.echoMessages&&(a.echo="false");void 0!==this.format&&(a.format=this.format);void 0!==this.stream&&(a.stream=this.stream);void 0!==this.heartbeats&&(a.heartbeats=this.heartbeats);a.v=r.apiVersion;a.lib=r.libstring;void 0!==b.transportParams&&h.mixin(a,b.transportParams);return a};d.prototype.toString=function(){var a="[mode="+this.mode;this.host&&(a+=",host="+this.host);this.connectionKey&& -(a+=",connectionKey="+this.connectionKey);void 0!==this.connectionSerial&&(a+=",connectionSerial="+this.connectionSerial);this.timeSerial&&(a+=",timeSerial="+this.timeSerial);this.format&&(a+=",format="+this.format);return a+"]"};h.inherits(a,B);a.supportedTransports={};a.prototype.createTransportParams=function(a,b){var c=new d(this.options,a,b,this.connectionKey);this.timeSerial?c.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(c.connectionSerial=this.connectionSerial);return c};a.prototype.getTransportParams= -function(a){var c=this;(function(a){if(c.connectionKey)a("resume");else if("string"===typeof c.options.recover)a("recover");else{var g=c.options.recover,e=q&&J.getSession("ably-connection-recovery");e&&"function"===typeof g?(b.logAction(b.LOG_MINOR,"ConnectionManager.getTransportParams()","Calling clientOptions-provided recover function with last session data"),g(e,function(b){b?(c.options.recover=e.recoveryKey,a("recover")):a("clean")})):a("clean")}})(function(g){var e=c.createTransportParams(null, -g);"recover"===g?(b.logAction(b.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport recovery mode = recover; recoveryKey = "+c.options.recover),(g=c.options.recover.split(":"))&&g[2]&&(c.msgSerial=g[2])):b.logAction(b.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport params = "+e.toString());a(e)})};a.prototype.tryATransport=function(c,e,d){var g=this;b.logAction(b.LOG_MICRO,"ConnectionManager.tryATransport()","trying "+e);a.supportedTransports[e].tryConnect(this,this.realtime.auth, -c,function(a,f){var l=g.state;l==g.states.closing||l==g.states.closed||l==g.states.failed?(f&&(b.logAction(b.LOG_MINOR,"ConnectionManager.tryATransport()","connection "+l.state+" while we were attempting the transport; closing "+f),f.close()),d(!0)):a?(b.logAction(b.LOG_MINOR,"ConnectionManager.tryATransport()","transport "+e+" "+a.event+", err: "+a.error.toString()),M.isTokenErr(a.error)?g.realtime.auth._forceNewToken(null,null,function(a){a?g.actOnErrorFromAuthorize(a):g.tryATransport(c,e,d)}): -"failed"===a.event?(g.notifyState({state:"failed",error:a.error}),d(!0)):"disconnected"===a.event&&d(!1)):(b.logAction(b.LOG_MICRO,"ConnectionManager.tryATransport()","viable transport "+e+"; setting pending"),g.setTransportPending(f,c),d(null,f))})};a.prototype.setTransportPending=function(a,c){var g=c.mode;b.logAction(b.LOG_MINOR,"ConnectionManager.setTransportPending()","transport = "+a+"; mode = "+g);h.arrDeleteValue(this.proposedTransports,a);this.pendingTransports.push(a);var e=this;a.once("connected", -function(b,d,f,m){"upgrade"==g&&e.activeProtocol?a.shortName!==l&&h.arrIn(e.getUpgradePossibilities(),l)?setTimeout(function(){e.scheduleTransportActivation(b,a,d,f,m)},e.options.timeouts.parallelUpgradeDelay):e.scheduleTransportActivation(b,a,d,f,m):(e.activateTransport(b,a,d,f,m),h.nextTick(function(){e.connectImpl(c)}));"recover"===g&&e.options.recover&&(e.options.recover=null,e.unpersistConnection())});a.on(["disconnected","closed","failed"],function(b){e.deactivateTransport(a,this.event,b)}); -this.emit("transport.pending",a)};a.prototype.scheduleTransportActivation=function(a,c,e,d,f){function g(){c.disconnect();h.arrDeleteValue(l.pendingTransports,c)}var l=this,m=this.activeProtocol&&this.activeProtocol.getTransport();this.state!==this.states.connected&&this.state!==this.states.connecting?(b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+this.state.state+(this.state===this.states.synchronizing?", but with an upgrade already in progress": -"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName),g()):m&&!k(c,m)?(b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+" is no better than current active transport "+m.shortName+" - abandoning upgrade"),g()):(b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Scheduling transport upgrade; transport = "+c),this.realtime.channels.onceNopending(function(m){if(m)b.logAction(b.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()", -"Unable to activate transport; transport = "+c+"; err = "+m);else if(c.isConnected){if(l.state===l.states.connected){b.logAction(b.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()","Currently connected, so temporarily pausing events until the upgrade is complete");l.state=l.states.synchronizing;var n=l.activeProtocol}else if(l.state!==l.states.connecting){b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+l.state.state+(l.state===l.states.synchronizing? -", but with an upgrade already in progress":"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName);g();return}var h=(m=e!==l.connectionId)?f:l;m&&b.logAction(b.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Upgrade resulted in new connectionId; resetting library connection position from "+(l.timeSerial||l.connectionSerial)+" to "+(h.timeSerial||h.connectionSerial)+"; upgrade error was "+a);b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Syncing transport; transport = "+ -c);l.sync(c,h,function(g,e,f){if(g)l.state===l.states.synchronizing&&(b.logAction(b.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Unexpected error attempting to sync transport; transport = "+c+"; err = "+g),l.disconnectAllTransports());else if(g=function(){b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Activating transport; transport = "+c);l.activateTransport(a,c,e,d,f);l.state===l.states.synchronizing?(b.logAction(b.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()", -"Pre-upgrade protocol idle, sending queued messages on upgraded transport; transport = "+c),l.state=l.states.connected):b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Pre-upgrade protocol idle, but state is now "+l.state.state+", so leaving unchanged");l.state.sendEvents&&l.sendQueuedMessages()},n)n.onceIdle(g);else g()})}else b.logAction(b.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+"is no longer connected; abandoning upgrade"), -g()}))};a.prototype.activateTransport=function(a,c,e,d,f){b.logAction(b.LOG_MINOR,"ConnectionManager.activateTransport()","transport = "+c);a&&b.logAction(b.LOG_ERROR,"ConnectionManager.activateTransport()","error = "+a);e&&b.logAction(b.LOG_MICRO,"ConnectionManager.activateTransport()","connectionId = "+e);d&&b.logAction(b.LOG_MICRO,"ConnectionManager.activateTransport()","connectionDetails = "+JSON.stringify(d));f&&b.logAction(b.LOG_MICRO,"ConnectionManager.activateTransport()","serial = "+(f.timeSerial|| -f.connectionSerial));this.persistTransportPreference(c);var g=this.state,l=this.states.connected.state;b.logAction(b.LOG_MINOR,"ConnectionManager.activateTransport()","current state = "+g.state);if(g.state==this.states.closing.state||g.state==this.states.closed.state||g.state==this.states.failed.state)return b.logAction(b.LOG_MINOR,"ConnectionManager.activateTransport()","Disconnecting transport and abandoning"),c.disconnect(),!1;h.arrDeleteValue(this.pendingTransports,c);if(!c.isConnected)return b.logAction(b.LOG_MINOR, -"ConnectionManager.activateTransport()","Declining to activate transport "+c+" since it appears to no longer be connected"),!1;var m=this.activeProtocol;this.activeProtocol=new fa(c);this.host=c.params.host;var n=d.connectionKey;n&&this.connectionKey!=n&&this.setConnection(e,d,f,!0);this.onConnectionDetailsUpdate(d,c);var u=this;h.nextTick(function(){c.on("connected",function(a,b,g){u.onConnectionDetailsUpdate(g,c);u.emit("update",new T(l,l,null,a))})});g.state===this.states.connected.state?a&&(this.errorReason= -this.realtime.connection.errorReason=a,this.emit("update",new T(l,l,null,a))):(this.notifyState({state:"connected",error:a}),this.errorReason=this.realtime.connection.errorReason=a||null);this.emit("transport.active",c);m&&(0this.connectionStateTtl+this.maxIdleInterval&&(b.logAction(b.LOG_MINOR,"ConnectionManager.checkConnectionStateFreshness()", -"Last known activity from realtime was "+a+"ms ago; discarding connection state"),this.clearConnection(),this.states.connecting.failState="suspended",this.states.connecting.queueEvents=!1)}};a.prototype.persistConnection=function(){if(q){var a=this.realtime.connection.recoveryKey;a&&(a={recoveryKey:a,disconnectedAt:h.now(),location:window.location,clientId:this.realtime.auth.clientId},q&&J.setSession("ably-connection-recovery",a))}};a.prototype.unpersistConnection=function(){q&&J.removeSession("ably-connection-recovery")}; -a.prototype.getError=function(){return this.errorReason||this.getStateError()};a.prototype.getStateError=function(){return K[this.state.state]};a.prototype.activeState=function(){return this.state.queueEvents||this.state.sendEvents};a.prototype.enactStateChange=function(a){b.logAction("failed"===a.current?b.LOG_ERROR:b.LOG_MAJOR,"Connection state",a.current+(a.reason?"; reason: "+a.reason:""));b.logAction(b.LOG_MINOR,"ConnectionManager.enactStateChange","setting new state: "+a.current+"; reason = "+ -(a.reason&&a.reason.message));var c=this.state=this.states[a.current];a.reason&&(this.errorReason=a.reason,this.realtime.connection.errorReason=a.reason);(c.terminal||"suspended"===c.state)&&this.clearConnection();this.emit("connectionstate",a)};a.prototype.startTransitionTimer=function(a){b.logAction(b.LOG_MINOR,"ConnectionManager.startTransitionTimer()","transitionState: "+a.state);this.transitionTimer&&(b.logAction(b.LOG_MINOR,"ConnectionManager.startTransitionTimer()","clearing already-running timer"), -clearTimeout(this.transitionTimer));var c=this;this.transitionTimer=setTimeout(function(){c.transitionTimer&&(c.transitionTimer=null,b.logAction(b.LOG_MINOR,"ConnectionManager "+a.state+" timer expired","requesting new state: "+a.failState),c.notifyState({state:a.failState}))},a.retryDelay)};a.prototype.cancelTransitionTimer=function(){b.logAction(b.LOG_MINOR,"ConnectionManager.cancelTransitionTimer()","");this.transitionTimer&&(clearTimeout(this.transitionTimer),this.transitionTimer=null)};a.prototype.startSuspendTimer= -function(){var a=this;this.suspendTimer||(this.suspendTimer=setTimeout(function(){a.suspendTimer&&(a.suspendTimer=null,b.logAction(b.LOG_MINOR,"ConnectionManager suspend timer expired","requesting new state: suspended"),a.states.connecting.failState="suspended",a.states.connecting.queueEvents=!1,a.notifyState({state:"suspended"}))},this.connectionStateTtl))};a.prototype.checkSuspendTimer=function(a){"disconnected"!==a&&"suspended"!==a&&"connecting"!==a&&this.cancelSuspendTimer()};a.prototype.cancelSuspendTimer= -function(){this.states.connecting.failState="disconnected";this.states.connecting.queueEvents=!0;this.suspendTimer&&(clearTimeout(this.suspendTimer),this.suspendTimer=null)};a.prototype.startRetryTimer=function(a){var c=this;this.retryTimer=setTimeout(function(){b.logAction(b.LOG_MINOR,"ConnectionManager retry timer expired","retrying");c.retryTimer=null;c.requestState({state:"connecting"})},a)};a.prototype.cancelRetryTimer=function(){this.retryTimer&&(clearTimeout(this.retryTimer),this.retryTimer= -null)};a.prototype.notifyState=function(a){var c=a.state,e=this,g="disconnected"===c&&(this.state===this.states.connected||this.state===this.states.synchronizing||this.state===this.states.connecting&&a.error&&M.isTokenErr(a.error)&&!(this.errorReason&&M.isTokenErr(this.errorReason)));b.logAction(b.LOG_MINOR,"ConnectionManager.notifyState()","new state: "+c+(g?"; will retry connection immediately":""));if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(a.state), -!this.state.terminal)){var d=this.states[a.state];a=new T(this.state.state,d.state,d.retryDelay,a.error||K[d.state]);if(g){var f=function(){e.state===e.states.disconnected&&(e.lastAutoReconnectAttempt=h.now(),e.requestState({state:"connecting"}))},l=this.lastAutoReconnectAttempt&&h.now()-this.lastAutoReconnectAttempt+1;l&&1E3>l?(b.logAction(b.LOG_MICRO,"ConnectionManager.notifyState()","Last reconnect attempt was only "+l+"ms ago, waiting another "+(1E3-l)+"ms before trying again"),setTimeout(f,1E3- -l)):h.nextTick(f)}else"disconnected"!==c&&"suspended"!==c||this.startRetryTimer(d.retryDelay);("disconnected"===c&&!g||"suspended"===c||d.terminal)&&h.nextTick(function(){e.disconnectAllTransports()});"connected"!=c||this.activeProtocol||b.logAction(b.LOG_ERROR,"ConnectionManager.notifyState()","Broken invariant: attempted to go into connected state, but there is no active protocol");this.enactStateChange(a);this.state.sendEvents?this.sendQueuedMessages():this.state.queueEvents||(this.realtime.channels.propogateConnectionInterruption(c, -a.reason),this.failQueuedMessages(a.reason))}};a.prototype.requestState=function(a){var c=a.state,e=this;b.logAction(b.LOG_MINOR,"ConnectionManager.requestState()","requested state: "+c+"; current state: "+this.state.state);if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(c),"connecting"!=c||"connected"!=this.state.state)&&("closing"!=c||"closed"!=this.state.state)){var g=this.states[c];a=new T(this.state.state,g.state,null,a.error||K[g.state]); -this.enactStateChange(a);"connecting"==c&&h.nextTick(function(){e.startConnect()});"closing"==c&&this.closeImpl()}};a.prototype.startConnect=function(){if(this.state!==this.states.connecting)b.logAction(b.LOG_MINOR,"ConnectionManager.startConnect()","Must be in connecting state to connect, but was "+this.state.state);else{var a=this.realtime.auth,c=this,e=function(){c.checkConnectionStateFreshness();c.getTransportParams(function(a){c.connectImpl(a)})};b.logAction(b.LOG_MINOR,"ConnectionManager.startConnect()", -"starting connection");this.startSuspendTimer();this.startTransitionTimer(this.states.connecting);if("basic"===a.method)e();else{var d=function(a){a?c.actOnErrorFromAuthorize(a):e()};this.errorReason&&M.isTokenErr(this.errorReason)?a._forceNewToken(null,null,d):a._ensureValidAuthCredentials(d)}}};a.prototype.connectImpl=function(a){var c=this.state.state;c!==this.states.connecting.state&&c!==this.states.connected.state?b.logAction(b.LOG_MINOR,"ConnectionManager.connectImpl()","Must be in connecting state to connect (or connected to upgrade), but was "+ -c):this.pendingTransports.length?b.logAction(b.LOG_MINOR,"ConnectionManager.connectImpl()","Transports "+this.pendingTransports[0].toString()+" currently pending; taking no action"):c==this.states.connected.state?this.upgradeIfNeeded(a):1g||!h.allSame(m,"clientId")?f=!1:(f[l]=m,f=!0)}}f?(d.merged||(d.callback=Y([d.callback]),d.merged=!0),d.callback.push(c)):this.queuedMessages.push(new n(a, -c))};a.prototype.sendQueuedMessages=function(){b.logAction(b.LOG_MICRO,"ConnectionManager.sendQueuedMessages()","sending "+this.queuedMessages.count()+" queued messages");for(var a;a=this.queuedMessages.shift();)this.sendImpl(a)};a.prototype.queuePendingMessages=function(a){a&&a.length&&(b.logAction(b.LOG_MICRO,"ConnectionManager.queuePendingMessages()","queueing "+a.length+" pending messages"),this.queuedMessages.prepend(a))};a.prototype.failQueuedMessages=function(a){var c=this.queuedMessages.count(); -0=d?(a="No activity seen from realtime in "+a+"ms; assuming connection has dropped",b.logAction(b.LOG_ERROR,"Transport.onIdleTimerExpire()",a),this.disconnect(new p(a,80003,408))):this.setIdleTimer(d+ -100)};f.prototype.onAuthUpdated=function(){};return f}();(function(){function f(b,a,c){this.shortName="web_socket";c.heartbeats=t.useProtocolHeartbeats;P.call(this,b,a,c);this.wsHost=r.getHost(c.options,c.host,!0)}var k=t.WebSocket;h.inherits(f,P);f.isAvailable=function(){return!!k};f.isAvailable()&&(N.supportedTransports.web_socket=f);f.tryConnect=function(d,a,c,h){function e(a){h({event:this.event,error:a})}var n=new f(d,a,c);n.on(["failed","disconnected"],e);n.on("wsopen",function(){b.logAction(b.LOG_MINOR, -"WebSocketTransport.tryConnect()","viable transport "+n);n.off(["failed","disconnected"],e);h(null,n)});n.connect()};f.prototype.createWebSocket=function(b,a){var c=0;if(a)for(var d in a)b+=(c++?"&":"?")+d+"="+a[d];this.uri=b;return new k(b)};f.prototype.toString=function(){return"WebSocketTransport; uri="+this.uri};f.prototype.connect=function(){b.logAction(b.LOG_MINOR,"WebSocketTransport.connect()","starting");P.prototype.connect.call(this);var d=this,a=this.params,c=a.options,f=(c.tls?"wss://": -"ws://")+this.wsHost+":"+r.getPort(c)+"/";b.logAction(b.LOG_MINOR,"WebSocketTransport.connect()","uri: "+f);this.auth.getAuthParams(function(c,n){var e="",l;for(l in n)e+=" "+l+": "+n[l]+";";b.logAction(b.LOG_MINOR,"WebSocketTransport.connect()","authParams:"+e+" err: "+c);if(c)d.disconnect(c);else{e=a.getConnectParams(n);try{var g=d.wsConnection=d.createWebSocket(f,e);g.binaryType=t.binaryType;g.onopen=function(){d.onWsOpen()};g.onclose=function(a){d.onWsClose(a)};g.onmessage=function(a){d.onWsData(a.data)}; -g.onerror=function(a){d.onWsError(a)};if(g.on)g.on("ping",function(){d.onActivity()})}catch(u){b.logAction(b.LOG_ERROR,"WebSocketTransport.connect()","Unexpected exception creating websocket: err = "+(u.stack||u.message)),d.disconnect(u)}}})};f.prototype.send=function(d){var a=this.wsConnection;if(a)try{a.send(z.serialize(d,this.params.format))}catch(c){d="Exception from ws connection when trying to send: "+h.inspectError(c),b.logAction(b.LOG_ERROR,"WebSocketTransport.send()",d),this.finish("disconnected", -new p(d,5E4,500))}else b.logAction(b.LOG_ERROR,"WebSocketTransport.send()","No socket connection")};f.prototype.onWsData=function(d){b.logAction(b.LOG_MICRO,"WebSocketTransport.onWsData()","data received; length = "+d.length+"; type = "+typeof d);try{this.onProtocolMessage(z.deserialize(d,this.format))}catch(a){b.logAction(b.LOG_ERROR,"WebSocketTransport.onWsData()","Unexpected exception handing channel message: "+a.stack)}};f.prototype.onWsOpen=function(){b.logAction(b.LOG_MINOR,"WebSocketTransport.onWsOpen()", -"opened WebSocket");this.emit("wsopen")};f.prototype.onWsClose=function(d){if("object"==typeof d){var a=d.wasClean;d=d.code}else a=1E3==d;delete this.wsConnection;a?(b.logAction(b.LOG_MINOR,"WebSocketTransport.onWsClose()","Cleanly closed WebSocket"),a=new p("Websocket closed",80003,400)):(d="Unclean disconnection of WebSocket ; code = "+d,a=new p(d,80003,400),b.logAction(b.LOG_MINOR,"WebSocketTransport.onWsClose()",d));this.finish("disconnected",a);this.emit("disposed")};f.prototype.onWsError=function(d){b.logAction(b.LOG_MINOR, -"WebSocketTransport.onError()","Error from WebSocket: "+d.message);var a=this;h.nextTick(function(){a.disconnect(d)})};f.prototype.dispose=function(){b.logAction(b.LOG_MINOR,"WebSocketTransport.dispose()","");var d=this.wsConnection;d&&(d.onmessage=function(){},delete this.wsConnection,h.nextTick(function(){b.logAction(b.LOG_MICRO,"WebSocketTransport.dispose()","closing websocket");d.close()}))};return f})();var L=function(){function f(b){var a=[80015,80017,80030];return b.code&&(M.isTokenErr(b)? -0:h.arrIn(a,b.code)||4E4<=b.code&&5E4>b.code)?[z.fromValues({action:z.Action.ERROR,error:b})]:[z.fromValues({action:z.Action.DISCONNECTED,error:b})]}function k(b,a,c){c.format=void 0;c.heartbeats=!0;P.call(this,b,a,c);this.stream="stream"in c?c.stream:!0;this.pendingItems=this.pendingCallback=this.recvRequest=this.sendRequest=null;this.disposed=!1}h.inherits(k,P);k.REQ_SEND=0;k.REQ_RECV=1;k.REQ_RECV_POLL=2;k.REQ_RECV_STREAM=3;k.prototype.connect=function(){b.logAction(b.LOG_MINOR,"CometTransport.connect()", -"starting");P.prototype.connect.call(this);var d=this,a=this.params,c=a.options;a=r.getHost(c,a.host);var k=r.getPort(c);this.baseUri=(c.tls?"https://":"http://")+a+":"+k+"/comet/";var e=this.baseUri+"connect";b.logAction(b.LOG_MINOR,"CometTransport.connect()","uri: "+e);this.auth.getAuthParams(function(a,c){if(a)d.disconnect(a);else{d.authParams=c;var l=d.params.getConnectParams(c);"stream"in l&&(d.stream=l.stream);b.logAction(b.LOG_MINOR,"CometTransport.connect()","connectParams:"+h.toQueryString(l)); -var g=!1;l=d.recvRequest=d.createRequest(e,null,l,null,d.stream?3:1);l.on("data",function(a){d.recvRequest&&(g||(g=!0,d.emit("preconnect")),d.onData(a))});l.on("complete",function(a){d.recvRequest||(a=a||new p("Request cancelled",8E4,400));d.recvRequest=null;d.onActivity();if(a)if(a.code)d.onData(f(a));else d.disconnect(a);else h.nextTick(function(){d.recv()})});l.exec()}})};k.prototype.requestClose=function(){b.logAction(b.LOG_MINOR,"CometTransport.requestClose()");this._requestCloseOrDisconnect(!0)}; -k.prototype.requestDisconnect=function(){b.logAction(b.LOG_MINOR,"CometTransport.requestDisconnect()");this._requestCloseOrDisconnect(!1)};k.prototype._requestCloseOrDisconnect=function(d){var a=d?this.closeUri:this.disconnectUri;if(a){var c=this;a=this.createRequest(a,null,this.authParams,null,0);a.on("complete",function(a){a&&(b.logAction(b.LOG_ERROR,"CometTransport.request"+(d?"Close()":"Disconnect()"),"request returned err = "+h.inspectError(a)),c.finish("disconnected",a))});a.exec()}};k.prototype.dispose= -function(){b.logAction(b.LOG_MINOR,"CometTransport.dispose()","");if(!this.disposed){this.disposed=!0;this.recvRequest&&(b.logAction(b.LOG_MINOR,"CometTransport.dispose()","aborting recv request"),this.recvRequest.abort(),this.recvRequest=null);this.finish("disconnected",K.disconnected);var d=this;h.nextTick(function(){d.emit("disposed")})}};k.prototype.onConnect=function(d){if(!this.disposed){var a=d.connectionKey;P.prototype.onConnect.call(this,d);a=this.baseUri+a;b.logAction(b.LOG_MICRO,"CometTransport.onConnect()", -"baseUri = "+a+"; connectionKey = "+d.connectionKey);this.sendUri=a+"/send";this.recvUri=a+"/recv";this.closeUri=a+"/close";this.disconnectUri=a+"/disconnect"}};k.prototype.send=function(b){if(this.sendRequest)this.pendingItems=this.pendingItems||[],this.pendingItems.push(b);else{var a=this.pendingItems||[];a.push(b);this.pendingItems=null;this.sendItems(a)}};k.prototype.sendAnyPending=function(){var b=this.pendingItems;b&&(this.pendingItems=null,this.sendItems(b))};k.prototype.sendItems=function(d){var a= -this;d=this.sendRequest=a.createRequest(a.sendUri,null,a.authParams,this.encodeRequest(d),0);d.on("complete",function(c,d){c&&b.logAction(b.LOG_ERROR,"CometTransport.sendItems()","on complete: err = "+h.inspectError(c));a.sendRequest=null;if(d)a.onData(d);else if(c&&c.code)a.onData(f(c));else a.disconnect(c);a.pendingItems&&h.nextTick(function(){a.sendRequest||a.sendAnyPending()})});d.exec()};k.prototype.recv=function(){if(!this.recvRequest&&this.isConnected){var b=this,a=this.recvRequest=this.createRequest(this.recvUri, -null,this.authParams,null,b.stream?3:2);a.on("data",function(a){b.onData(a)});a.on("complete",function(a){b.recvRequest=null;b.onActivity();if(a)if(a.code)b.onData(f(a));else b.disconnect(a);else h.nextTick(function(){b.recv()})});a.exec()}};k.prototype.onData=function(d){try{var a=this.decodeResponse(d);if(a&&a.length)for(d=0;dd||300<=d?(c=f&&f.error||c,c||(c=Error("Error in unenveloping "+e),c.statusCode=d),a(c,f,n,!0,d)): -a(c,f,n,!0,d))}}}function a(a){var b=[];if(a)for(var c in a)b.push(c+"="+a[c]);return b.join("&")}function c(c,d,f,l){return function(e,m,n,k,q){e?b.logAction(b.LOG_MICRO,"Resource."+d+"()","Received Error; "+(f+(l?"?":"")+a(l))+"; Error: "+h.inspectError(e)):b.logAction(b.LOG_MICRO,"Resource."+d+"()","Received; "+(f+(l?"?":"")+a(l))+"; Headers: "+a(n)+"; StatusCode: "+q+"; Body: "+(A.isBuffer(m)?m.toString():m));c&&c(e,m,n,k,q)}}var q=t.msgpack;h.arrForEach(w.methodsWithoutBody,function(a){f[a]= -function(b,c,e,d,h,k){f["do"](a,b,c,null,e,d,h,k)}});h.arrForEach(w.methodsWithBody,function(a){f[a]=function(b,c,e,d,h,k,q){f["do"](a,b,c,e,d,h,k,q)}});f["do"]=function(e,f,m,l,g,u,v,y){function n(c,d){b.shouldLog(b.LOG_MICRO)&&b.logAction(b.LOG_MICRO,"Resource."+e+"()","Sending; "+(m+(d?"?":"")+a(d)));var v=[f,m,c,l,d,function(a,b,c,e,d){a&&M.isTokenErr(a)?f.auth.authorize(null,null,function(a){a?y(a):k(f,g,u,y,n)}):y(a,b,c,e,d)}];l||v.splice(3,1);if(b.shouldLog(b.LOG_MICRO)){var p=l;if(0<(c["content-type"]|| -"").indexOf("msgpack"))try{p=q.decode(l)}catch(I){b.logAction(b.LOG_MICRO,"Resource."+e+"()","Sending MsgPack Decoding Error: "+h.inspectError(I))}b.logAction(b.LOG_MICRO,"Resource."+e+"()","Sending; "+(m+(d?"?":"")+a(d))+"; Body: "+p)}w[e].apply(this,v)}b.shouldLog(b.LOG_MICRO)&&(y=c(y,e,m,u));v&&(y=y&&d(y,v),(u=u||{}).envelope=v);k(f,g,u,y,n)};return f}(),O=function(){function f(a,b,d,e,f,m){this.rest=a;this.path=b;this.headers=d;this.envelope=e;this.bodyHandler=f;this.useHttpPaginatedResponse= -m||!1}function k(a,b,d){this.resource=a;this.items=b;if(d){var c=this;"first"in d&&(this.first=function(a){c.get(d.first,a)});"current"in d&&(this.current=function(a){c.get(d.current,a)});this.next=function(a){"next"in d?c.get(d.next,a):a(null,null)};this.hasNext=function(){return"next"in d};this.isLast=function(){return!this.hasNext()}}}function d(a,b,d,e,f,m){k.call(this,a,b,f);this.statusCode=e;this.success=300>e&&200<=e;this.headers=d;this.errorCode=m&&m.code;this.errorMessage=m&&m.message}h.arrForEach(w.methodsWithoutBody, -function(a){f.prototype[a]=function(b,d){var c=this;H[a](c.rest,c.path,c.headers,b,c.envelope,function(a,b,e,g,f){c.handlePage(a,b,e,g,f,d)})}});h.arrForEach(w.methodsWithBody,function(a){f.prototype[a]=function(b,d,e){var c=this;H[a](c.rest,c.path,d,c.headers,b,c.envelope,function(a,b,d,f,n){e&&c.handlePage(a,b,d,f,n,e)})}});f.prototype.handlePage=function(a,c,f,e,n,m){if(!a||this.useHttpPaginatedResponse&&(c||"number"===typeof a.code)){var l,g;try{var q=this.bodyHandler(c,f,e)}catch(y){m(a||y); -return}if(f&&(l=f.Link||f.link)){c=l;"string"==typeof c&&(c=c.split(","));e={};for(l=0;l;\s*rel="(\w+)"$/)){var v;(v=(v=g[1].match(/^\.\/(\w+)\?(.*)$/))&&h.parseQueryString(v[2]))&&(e[g[2]]=v)}g=e}this.useHttpPaginatedResponse?m(null,new d(this,q,f,n,g,a)):m(null,new k(this,q,g))}else b.logAction(b.LOG_ERROR,"PaginatedResource.handlePage()","Unexpected error getting resource: err = "+h.inspectError(a)),m(a)};k.prototype.get=function(a,b){var c=this.resource; -H.get(c.rest,c.path,c.headers,a,c.envelope,function(a,d,f,l,g){c.handlePage(a,d,f,l,g,b)})};h.inherits(d,k);return f}(),M=function(){function f(){}function k(a){if(!h.isErrorInfo(a))return new p(h.inspectError(a),a.code||40170,a.statusCode||401);a.code||(403===a.statusCode?a.code=40300:(a.code=40170,a.statusCode=401));return a}function d(a){if(!a)return"";"string"==typeof a&&(a=JSON.parse(a));var b={},c=h.keysArray(a,!0);if(!c)return"";c.sort();for(var e=0;e -q){e(new p("authUrl response exceeded max permitted length",40170,401));return}try{c=JSON.parse(c)}catch(ka){e(new p("Unexpected error processing authURL response; err = "+ka.message,40170,401));return}}e(null,c)}else e(new p("authUrl responded with unacceptable content-type "+a+", should be either text/plain, application/jwt or application/json",40170,401));else e(new p("authUrl response is missing a content-type header",40170,401))}var g=h.mixin({accept:"application/json, text/plain"},c.authHeaders), -f=c.authMethod&&"post"===c.authMethod.toLowerCase();if(!f){var m=c.authUrl.indexOf("?");if(-1q&&!c.suppressMaxLengthCheck?e(new p("Token request/details object exceeded max permitted stringified size (was "+f+" bytes)",40170,401)):"issued"in d?e(null,d):"keyName"in d?g(d,function(a,c,d,g){a?(b.logAction(b.LOG_ERROR,"Auth.requestToken()","token request API call returned error; err = "+h.inspectError(a)),e(k(a))):(g||(c=JSON.parse(c)),b.logAction(b.LOG_MINOR,"Auth.getToken()","token received"),e(null,c))}):(f="Expected token request callback to call back with a token string, token request object, or token details object", -b.logAction(b.LOG_ERROR,"Auth.requestToken()",f),e(new p(f,40170,401)))})};c.prototype.createTokenRequest=function(a,c,e){"function"!=typeof a||e?"function"!=typeof c||e||(e=c,c=null):(e=a,c=a=null);if(!e&&this.client.options.promises)return h.promisify(this,"createTokenRequest",arguments);c=c||this.authOptions;a=a||h.copy(this.tokenParams);var g=c.key;if(g){g=g.split(":");var f=g[0],l=g[1];if(l)if(""===a.clientId)e(new p("clientId can\u2019t be an empty string",40012,400));else{"capability"in a&& -(a.capability=d(a.capability));var m=h.mixin({keyName:f},a),k=a.clientId||"",q=a.ttl||"",r=a.capability||"",t=this;(function(a){m.timestamp?a():t.getTimestamp(c&&c.queryTime,function(b,c){b?e(b):(m.timestamp=c,a())})})(function(){var a=m.nonce||(m.nonce=("000000"+Math.floor(1E16*Math.random())).slice(-16));a=m.keyName+"\n"+q+"\n"+r+"\n"+k+"\n"+m.timestamp+"\n"+a+"\n";m.mac=m.mac||n(a,l);b.logAction(b.LOG_MINOR,"Auth.getTokenRequest()","generated signed request");e(null,m)})}else e(new p("Invalid key specified", -40101,403))}else e(new p("No key specified",40101,403))};c.prototype.getAuthParams=function(a){"basic"==this.method?a(null,{key:this.key}):this._ensureValidAuthCredentials(function(b,c){b?a(b):a(null,{access_token:c.token})})};c.prototype.getAuthHeaders=function(a){"basic"==this.method?a(null,{authorization:"Basic "+this.basicKey}):this._ensureValidAuthCredentials(function(b,c){b?a(b):a(null,{authorization:"Bearer "+e(c.token)})})};c.prototype.getTimestamp=function(a,b){this.isTimeOffsetSet()||!a&& -!this.authOptions.queryTime?b(null,this.getTimestampUsingOffset()):this.client.time(b)};c.prototype.getTimestampUsingOffset=function(){return h.now()+(this.client.serverTimeOffset||0)};c.prototype.isTimeOffsetSet=function(){return null!==this.client.serverTimeOffset};c.prototype._saveBasicOptions=function(a){this.method="basic";this.key=a.key;this.basicKey=e(a.key);this.authOptions=a||{};"clientId"in a&&this._userSetClientId(a.clientId)};c.prototype._saveTokenOptions=function(a,b){this.method="token"; -a&&(this.tokenParams=a);b&&(b.token&&(b.tokenDetails="string"===typeof b.token?{token:b.token}:b.token),b.tokenDetails&&(this.tokenDetails=b.tokenDetails),"clientId"in b&&this._userSetClientId(b.clientId),this.authOptions=b)};c.prototype._ensureValidAuthCredentials=function(a){var c=this,e=this.tokenDetails;if(this.tokenRequestInProgress)(this.waitingForTokenRequest||(this.waitingForTokenRequest=Y())).push(a);else{if(e){if(this._tokenClientIdMismatch(e.clientId)){a(new p("Mismatch between clientId in token ("+ -e.clientId+") and current clientId ("+this.clientId+")",40102,403));return}if(!this.isTimeOffsetSet()||!e.expires||e.expires>=this.getTimestampUsingOffset()){b.logAction(b.LOG_MINOR,"Auth.getToken()","using cached token; expires = "+e.expires);a(null,e);return}b.logAction(b.LOG_MINOR,"Auth.getToken()","deleting expired token");this.tokenDetails=null}this.tokenRequestInProgress=!0;this.requestToken(this.tokenParams,this.authOptions,function(b,e){c.tokenRequestInProgress=!1;var d=c.waitingForTokenRequest; -d&&(d.push(a),a=d,c.waitingForTokenRequest=null);b?a(b):a(null,c.tokenDetails=e)})}};c.prototype._userSetClientId=function(a){if("string"!==typeof a&&null!==a)throw new p("clientId must be either a string or null",40012,400);if("*"===a)throw new p('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, instantiate the library with {defaultTokenParams: {clientId: "*"}}), or if calling authorize(), pass it in as a tokenParam: authorize({clientId: "*"}, authOptions)', -40012,400);if(a=this._uncheckedSetClientId(a))throw a;};c.prototype._uncheckedSetClientId=function(a){if(this._tokenClientIdMismatch(a)){a="Unexpected clientId mismatch: client has "+this.clientId+", requested "+a;var c=new p(a,40102,401);b.logAction(b.LOG_ERROR,"Auth._uncheckedSetClientId()",a);return c}this.clientId=this.tokenParams.clientId=a;return null};c.prototype._tokenClientIdMismatch=function(a){return this.clientId&&"*"!==this.clientId&&a&&"*"!==a&&this.clientId!==a};c.isTokenErr=function(a){return a.code&& -40140<=a.code&&40150>a.code};return c}(),D=function(){function f(){}function k(a){if(!(this instanceof k))return new k(a);if(!a){var c="no options provided";b.logAction(b.LOG_ERROR,"Rest()",c);throw Error(c);}a=r.objectifyOptions(a);a.log&&b.setLog(a.log.level,a.log.handler);b.logAction(b.LOG_MICRO,"Rest()","initialized with clientOptions "+h.inspect(a));this.options=r.normaliseOptions(a);if(a.key){c=a.key.match(/^([^:\s]+):([^:.\s]+)$/);if(!c)throw c="invalid key parameter",b.logAction(b.LOG_ERROR, -"Rest()",c),Error(c);a.keyName=c[1];a.keySecret=c[2]}if("clientId"in a){if("string"!==typeof a.clientId&&null!==a.clientId)throw new p("clientId must be either a string or null",40012,400);if("*"===a.clientId)throw new p('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, use {defaultTokenParams: {clientId: "*"}})',40012,400);}b.logAction(b.LOG_MINOR,"Rest()","started; version = "+r.libstring);this.baseUri=this.authority= -function(b){return r.getHttpScheme(a)+b+":"+r.getPort(a,!1)};this.serverTimeOffset=this._currentFallback=null;this.auth=new M(this,a);this.channels=new d(this);this.push=new na(this)}function d(a){this.rest=a;this.attached={}}var a=t.msgpack;k.prototype.stats=function(a,b){if(void 0===b)if("function"==typeof a)b=a,a=null;else{if(this.options.promises)return h.promisify(this,"stats",arguments);b=f}var c=h.defaultGetHeaders(),d=this.options.useBinaryProtocol?"msgpack":"json";d=w.supportsLinkHeaders? -void 0:d;this.options.headers&&h.mixin(c,this.options.headers);(new O(this,"/stats",c,d,function(a,b,c){a=c?a:JSON.parse(a);for(b=0;bb?k(new p("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+b+" bytes)",40009,400)):e._publish(x.serialize(n,g),u,m,k)}})};k.prototype._publish=function(a,b,d,e){H.post(this.rest,this.basePath+"/messages",a,b,d,!1,e)};return k}(),Q=function(){function f(){}function k(a,c,d){b.logAction(b.LOG_MINOR,"RealtimeChannel()","started; name = "+c);W.call(this,a,c,d);this.realtime=a;this.presence=new pa(this,a.options); -this.connectionManager=a.connection.connectionManager;this.state="initialized";this.subscriptions=new B;this.syncChannelSerial=void 0;this.properties={attachSerial:void 0};this.setOptions(d);this._mode=this._requestedFlags=this.errorReason=null}var d=z.Action;h.inherits(k,W);k.invalidStateError=function(a){return{statusCode:400,code:90001,message:"Channel operation failed as channel state is "+a}};k.progressOps={statechange:"statechange",sync:"sync"};k.processListenerArgs=function(a){a=Array.prototype.slice.call(a); -"function"===typeof a[0]&&a.unshift(null);void 0==a[a.length-1]&&a.pop();return a};k.prototype.publish=function(){var a=arguments.length,b=arguments[0],d=arguments[a-1];if("function"!==typeof d){if(this.realtime.options.promises)return h.promisify(this,"publish",arguments);d=f;++a}if(this.connectionManager.activeState()){if(2==a)if(h.isObject(b))b=[x.fromValues(b)];else if(h.isArray(b))b=x.fromValuesArray(b);else throw new p("The single-argument form of publish() expects a message object or an array of message objects", -40013,400);else b=[x.fromValues({name:arguments[0],data:arguments[1]})];var e=this,k=this.realtime.options.maxMessageSize;x.encodeArray(b,this.channelOptions,function(a){a?d(a):(a=x.getMessagesSize(b),a>k?d(new p("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+k+" bytes)",40009,400)):e._publish(b,d))})}else d(this.connectionManager.getError())};k.prototype._publish=function(a,c){b.logAction(b.LOG_MICRO,"RealtimeChannel.publish()","message count = "+a.length); -var f=this.state;switch(f){case "failed":case "suspended":c(p.fromValues(k.invalidStateError(f)));break;default:b.logAction(b.LOG_MICRO,"RealtimeChannel.publish()","sending message; channel state is "+f),f=new z,f.action=d.MESSAGE,f.channel=this.name,f.messages=a,this.sendMessage(f,c)}};k.prototype.onEvent=function(a){b.logAction(b.LOG_MICRO,"RealtimeChannel.onEvent()","received message");for(var c=this.subscriptions,d=0;db.timestamp;var c=a.parseId(),d=b.parseId();return c.msgSerial===d.msgSerial?c.index>d.index:c.msgSerial>d.msgSerial}h.inherits(a,V);a.prototype.enter=function(a,b){if(k(this))throw new p("clientId must be specified to enter a presence channel",40012,400);return this._enterOrUpdateClient(void 0,a,"enter",b)};a.prototype.update= -function(a,b){if(k(this))throw new p("clientId must be specified to update presence data",40012,400);return this._enterOrUpdateClient(void 0,a,"update",b)};a.prototype.enterClient=function(a,b,c){return this._enterOrUpdateClient(a,b,"enter",c)};a.prototype.updateClient=function(a,b,c){return this._enterOrUpdateClient(a,b,"update",c)};a.prototype._enterOrUpdateClient=function(a,c,d,l){if(!l)if("function"===typeof c)l=c,c=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"_enterOrUpdateClient", -[a,c,d]);l=f}var e=this.channel;if(e.connectionManager.activeState()){b.logAction(b.LOG_MICRO,"RealtimePresence."+d+"Client()","channel = "+e.name+", client = "+(a||"(implicit) "+this.channel.realtime.auth.clientId));var k=G.fromValues({action:d,data:c});a&&(k.clientId=a);var m=this;G.encode(k,e.channelOptions,function(a){if(a)l(a);else switch(e.state){case "attached":e.sendPresence(k,l);break;case "initialized":case "detached":e.attach();case "attaching":m.pendingPresence.push({presence:k,callback:l}); -break;default:a=new p("Unable to "+d+" presence channel (incompatible state)",90001),a.code=90001,l(a)}})}else l(e.connectionManager.getError())};a.prototype.leave=function(a,b){if(k(this))throw new p("clientId must have been specified to enter or leave a presence channel",40012,400);return this.leaveClient(void 0,a,b)};a.prototype.leaveClient=function(a,c,d){if(!d)if("function"===typeof c)d=c,c=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"leaveClient",[a,c]);d=f}var e= -this.channel;if(e.connectionManager.activeState())switch(b.logAction(b.LOG_MICRO,"RealtimePresence.leaveClient()","leaving; channel = "+this.channel.name+", client = "+a),c=G.fromValues({action:"leave",data:c}),a&&(c.clientId=a),e.state){case "attached":e.sendPresence(c,d);break;case "attaching":this.pendingPresence.push({presence:c,callback:d});break;case "initialized":case "failed":a=new p("Unable to leave presence channel (incompatible state)",90001);d(a);break;default:d(K.failed)}else d(e.connectionManager.getError())}; -a.prototype.get=function(){function a(a){l(null,c?a.list(c):a.values())}var b=Array.prototype.slice.call(arguments);1==b.length&&"function"==typeof b[0]&&b.unshift(null);var c=b[0],l=b[1],g=!c||("waitForSync"in c?c.waitForSync:!0);if(!l){if(this.channel.realtime.options.promises)return h.promisify(this,"get",b);l=f}if("suspended"===this.channel.state)g?l(p.fromValues({statusCode:400,code:91005,message:"Presence state is out of sync due to channel being in the SUSPENDED state"})):a(this.members);else{var k= -this;d(this.channel,l,function(){var b=k.members;g?b.waitSync(function(){a(b)}):a(b)})}};a.prototype.history=function(a,c){b.logAction(b.LOG_MICRO,"RealtimePresence.history()","channel = "+this.name);if(void 0===c)if("function"==typeof a)c=a,a=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"history",arguments);c=f}a&&a.untilAttach&&("attached"===this.channel.state?(delete a.untilAttach,a.from_serial=this.channel.properties.attachSerial):c(new p("option untilAttach requires the channel to be attached, was: "+ -this.channel.state,4E4,400)));V.prototype._history.call(this,a,c)};a.prototype.setPresence=function(a,c,d){b.logAction(b.LOG_MICRO,"RealtimePresence.setPresence()","received presence for "+a.length+" participants; syncChannelSerial = "+d);var e,f,h=this.members,k=this._myMembers,m=[],n=this.channel.connectionManager.connectionId;c&&(this.members.startSync(),d&&(f=d.match(/^[\w\-]+:(.*)$/))&&(e=f[1]));for(d=0;da)&&0!==t.status){if(void 0===x)if(x=t.status,1223===x&&(x=204),clearTimeout(f),E=400>x,204==x)e.complete(null,null,null,null,x);else{var b;if(b=3==e.requestMode&&E)b=t,b=b.getResponseHeader&& -(b.getResponseHeader("transfer-encoding")||!b.getResponseHeader("content-length"));C=b}if(3==a&&C)c();else if(4==a)if(C)d();else a:{try{var g=t.getResponseHeader&&t.getResponseHeader("content-type");if(g?0<=g.indexOf("application/json"):"text"==t.responseType){var l="arraybuffer"===t.responseType?A.utf8Decode(t.response):String(t.responseText);l.length&&(l=JSON.parse(l));H=!0}else l=t.response;if(void 0!==l.response){x=l.statusCode;E=400>x;var k=l.headers;l=l.response}else{var m=h.trim(t.getAllResponseHeaders()).split("\r\n"); -a={};for(g=0;ga.statusCode||h.isArray(b)?n.complete(null,b,a.headers,a.statusCode):(a=b.error||new p("Error response received from server",null,a.statusCode),n.complete(a)):n.complete(new p("Invalid server response: no envelope detected",null,500))}else n.complete(null,a)};this.timer=setTimeout(function(){n.abort()}, -this.requestMode==L.REQ_SEND?this.timeouts.httpRequestTimeout:this.timeouts.recvTimeout);q.insertBefore(d,q.firstChild)};d.prototype.complete=function(a,b,c,d){c=c||{};this.requestComplete||(this.requestComplete=!0,b&&(c["content-type"]="string"==typeof b?"text/plain":"application/json",this.emit("data",b)),this.emit("complete",a,b,c,!0,d),this.dispose())};d.prototype.abort=function(){this.dispose()};d.prototype.dispose=function(){var b=this.timer;b&&(clearTimeout(b),this.timer=null);b=this.script; -b.parentNode&&b.parentNode.removeChild(b);delete a[this.id];this.emit("disposed")};t.jsonpSupported&&!w.Request&&(w.Request=function(a,b,c,d,e,f,k){var g=n(c,d,e,f,L.REQ_SEND,b&&b.options.timeouts,a);g.once("complete",k);h.nextTick(function(){g.exec()});return g},w.checkConnectivity=function(a){var c=r.jsonpInternetUpUrl;if(e)e.push(a);else{e=[a];b.logAction(b.LOG_MICRO,"(JSONP)Http.checkConnectivity()","Sending; "+c);var f=new d("isTheInternetUp",c,null,null,null,L.REQ_SEND,r.TIMEOUTS);f.once("complete", -function(a,c){var d=!a&&c;b.logAction(b.LOG_MICRO,"(JSONP)Http.checkConnectivity()","Result: "+d);for(var f=0;fh.arrIndexOf(p,c.shortName)}function f(a,c,b,e){this.options=a;this.host=c;this.mode=b;this.connectionKey=e;this.format=a.useBinaryProtocol?"msgpack":"json";this.timeSerial=this.connectionSerial=void 0}function a(g,c){A.call(this);this.realtime=g;this.options=c;var b=c.timeouts,e=this;this.states={initialized:{state:"initialized", +terminal:!1,queueEvents:!0,sendEvents:!1,failState:"disconnected"},connecting:{state:"connecting",terminal:!1,queueEvents:!0,sendEvents:!1,retryDelay:b.preferenceConnectTimeout+b.realtimeRequestTimeout,failState:"disconnected"},connected:{state:"connected",terminal:!1,queueEvents:!1,sendEvents:!0,failState:"disconnected"},synchronizing:{state:"connected",terminal:!1,queueEvents:!0,sendEvents:!1,forceQueueEvents:!0,failState:"disconnected"},disconnected:{state:"disconnected",terminal:!1,queueEvents:!0, +sendEvents:!1,retryDelay:b.disconnectedRetryTimeout,failState:"disconnected"},suspended:{state:"suspended",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:b.suspendedRetryTimeout,failState:"suspended"},closing:{state:"closing",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:b.realtimeRequestTimeout,failState:"closed"},closed:{state:"closed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"closed"},failed:{state:"failed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"failed"}};this.state= +this.states.initialized;this.errorReason=null;this.queuedMessages=new ha;this.msgSerial=0;this.connectionSerial=this.timeSerial=this.connectionKey=this.connectionId=this.connectionDetails=void 0;this.connectionStateTtl=b.connectionStateTtl;this.maxIdleInterval=null;this.transports=h.intersect(c.transports||t.defaultTransports,a.supportedTransports);this.baseTransport=h.intersect(t.baseTransportOrder,this.transports)[0];this.upgradeTransports=h.intersect(this.transports,t.upgradeTransports);this.transportPreference= +null;this.httpHosts=t.getHosts(c);this.activeProtocol=null;this.proposedTransports=[];this.pendingTransports=[];this.mostRecentMsgId=this.lastActivity=this.lastAutoReconnectAttempt=this.host=null;this.forceFallbackHost=!1;this.connectCounter=0;d.logAction(d.LOG_MINOR,"Realtime.ConnectionManager()","started");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()","requested transports = ["+(c.transports||t.defaultTransports)+"]");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()","available transports = ["+ +this.transports+"]");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()","http hosts = ["+this.httpHosts+"]");if(!this.transports.length)throw d.logAction(d.LOG_ERROR,"realtime.ConnectionManager()","no requested transports available"),Error("no requested transports available");if(b=u.addEventListener)n&&"function"===typeof c.recover&&b("beforeunload",this.persistConnection.bind(this)),!0===c.closeOnUnload&&b("beforeunload",function(){d.logAction(d.LOG_MAJOR,"Realtime.ConnectionManager()","beforeunload event has triggered the connection to close as closeOnUnload is true"); +e.requestState({state:"closing"})}),b("online",function(){if(e.state==e.states.disconnected||e.state==e.states.suspended)d.logAction(d.LOG_MINOR,"ConnectionManager caught browser \u2018online\u2019 event","reattempting connection"),e.requestState({state:"connecting"})}),b("offline",function(){e.state==e.states.connected&&(d.logAction(d.LOG_MINOR,"ConnectionManager caught browser \u2018offline\u2019 event","disconnecting active transport"),e.disconnectAllTransports())})}var c=!("undefined"===typeof K|| +!K.get),n=!("undefined"===typeof K||!K.getSession),e=z.Action,m=ia.PendingMessage,p=t.transportPreferenceOrder,k=p[p.length-1];f.prototype.getConnectParams=function(a){a=a?h.copy(a):{};var g=this.options;switch(this.mode){case "upgrade":a.upgrade=this.connectionKey;break;case "resume":a.resume=this.connectionKey;void 0!==this.timeSerial?a.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(a.connectionSerial=this.connectionSerial);break;case "recover":var c=g.recover.split(":");c&&(a.recover= +c[0],c=c[1],isNaN(c)?a.timeSerial=c:a.connectionSerial=c)}void 0!==g.clientId&&(a.clientId=g.clientId);!1===g.echoMessages&&(a.echo="false");void 0!==this.format&&(a.format=this.format);void 0!==this.stream&&(a.stream=this.stream);void 0!==this.heartbeats&&(a.heartbeats=this.heartbeats);a.v=t.apiVersion;a.lib=t.libstring;void 0!==g.transportParams&&h.mixin(a,g.transportParams);return a};f.prototype.toString=function(){var a="[mode="+this.mode;this.host&&(a+=",host="+this.host);this.connectionKey&& +(a+=",connectionKey="+this.connectionKey);void 0!==this.connectionSerial&&(a+=",connectionSerial="+this.connectionSerial);this.timeSerial&&(a+=",timeSerial="+this.timeSerial);this.format&&(a+=",format="+this.format);return a+"]"};h.inherits(a,A);a.supportedTransports={};a.prototype.createTransportParams=function(a,c){var g=new f(this.options,a,c,this.connectionKey);this.timeSerial?g.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(g.connectionSerial=this.connectionSerial);return g};a.prototype.getTransportParams= +function(a){var c=this;(function(a){if(c.connectionKey)a("resume");else if("string"===typeof c.options.recover)a("recover");else{var g=c.options.recover,b=n&&K.getSession("ably-connection-recovery");b&&"function"===typeof g?(d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Calling clientOptions-provided recover function with last session data"),g(b,function(g){g?(c.options.recover=b.recoveryKey,a("recover")):a("clean")})):a("clean")}})(function(g){var b=c.createTransportParams(null, +g);"recover"===g?(d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport recovery mode = recover; recoveryKey = "+c.options.recover),(g=c.options.recover.split(":"))&&g[2]&&(c.msgSerial=g[2])):d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport params = "+b.toString());a(b)})};a.prototype.tryATransport=function(c,b,e){var g=this;d.logAction(d.LOG_MICRO,"ConnectionManager.tryATransport()","trying "+b);a.supportedTransports[b].tryConnect(this,this.realtime.auth, +c,function(a,f){var k=g.state;k==g.states.closing||k==g.states.closed||k==g.states.failed?(f&&(d.logAction(d.LOG_MINOR,"ConnectionManager.tryATransport()","connection "+k.state+" while we were attempting the transport; closing "+f),f.close()),e(!0)):a?(d.logAction(d.LOG_MINOR,"ConnectionManager.tryATransport()","transport "+b+" "+a.event+", err: "+a.error.toString()),N.isTokenErr(a.error)?g.realtime.auth._forceNewToken(null,null,function(a){a?g.actOnErrorFromAuthorize(a):g.tryATransport(c,b,e)}): +"failed"===a.event?(g.notifyState({state:"failed",error:a.error}),e(!0)):"disconnected"===a.event&&e(!1)):(d.logAction(d.LOG_MICRO,"ConnectionManager.tryATransport()","viable transport "+b+"; setting pending"),g.setTransportPending(f,c),e(null,f))})};a.prototype.setTransportPending=function(a,c){var g=c.mode;d.logAction(d.LOG_MINOR,"ConnectionManager.setTransportPending()","transport = "+a+"; mode = "+g);h.arrDeleteValue(this.proposedTransports,a);this.pendingTransports.push(a);var b=this;a.once("connected", +function(e,d,f,r){"upgrade"==g&&b.activeProtocol?a.shortName!==k&&h.arrIn(b.getUpgradePossibilities(),k)?setTimeout(function(){b.scheduleTransportActivation(e,a,d,f,r)},b.options.timeouts.parallelUpgradeDelay):b.scheduleTransportActivation(e,a,d,f,r):(b.activateTransport(e,a,d,f,r),h.nextTick(function(){b.connectImpl(c)}));"recover"===g&&b.options.recover&&(b.options.recover=null,b.unpersistConnection())});a.on(["disconnected","closed","failed"],function(c){b.deactivateTransport(a,this.event,c)}); +this.emit("transport.pending",a)};a.prototype.scheduleTransportActivation=function(a,c,b,e,f){function g(){c.disconnect();h.arrDeleteValue(k.pendingTransports,c)}var k=this,r=this.activeProtocol&&this.activeProtocol.getTransport();this.state!==this.states.connected&&this.state!==this.states.connecting?(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+this.state.state+(this.state===this.states.synchronizing?", but with an upgrade already in progress": +"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName),g()):r&&!l(c,r)?(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+" is no better than current active transport "+r.shortName+" - abandoning upgrade"),g()):(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Scheduling transport upgrade; transport = "+c),this.realtime.channels.onceNopending(function(r){if(r)d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()", +"Unable to activate transport; transport = "+c+"; err = "+r);else if(c.isConnected){if(k.state===k.states.connected){d.logAction(d.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()","Currently connected, so temporarily pausing events until the upgrade is complete");k.state=k.states.synchronizing;var m=k.activeProtocol}else if(k.state!==k.states.connecting){d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+k.state.state+(k.state===k.states.synchronizing? +", but with an upgrade already in progress":"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName);g();return}var h=(r=b!==k.connectionId)?f:k;r&&d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Upgrade resulted in new connectionId; resetting library connection position from "+(k.timeSerial||k.connectionSerial)+" to "+(h.timeSerial||h.connectionSerial)+"; upgrade error was "+a);d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Syncing transport; transport = "+ +c);k.sync(c,h,function(g,b,f){if(g)k.state===k.states.synchronizing&&(d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Unexpected error attempting to sync transport; transport = "+c+"; err = "+g),k.disconnectAllTransports());else if(g=function(){d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Activating transport; transport = "+c);k.activateTransport(a,c,b,e,f);k.state===k.states.synchronizing?(d.logAction(d.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()", +"Pre-upgrade protocol idle, sending queued messages on upgraded transport; transport = "+c),k.state=k.states.connected):d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Pre-upgrade protocol idle, but state is now "+k.state.state+", so leaving unchanged");k.state.sendEvents&&k.sendQueuedMessages()},m)m.onceIdle(g);else g()})}else d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+"is no longer connected; abandoning upgrade"), +g()}))};a.prototype.activateTransport=function(a,c,b,e,f){d.logAction(d.LOG_MINOR,"ConnectionManager.activateTransport()","transport = "+c);a&&d.logAction(d.LOG_ERROR,"ConnectionManager.activateTransport()","error = "+a);b&&d.logAction(d.LOG_MICRO,"ConnectionManager.activateTransport()","connectionId = "+b);e&&d.logAction(d.LOG_MICRO,"ConnectionManager.activateTransport()","connectionDetails = "+JSON.stringify(e));f&&d.logAction(d.LOG_MICRO,"ConnectionManager.activateTransport()","serial = "+(f.timeSerial|| +f.connectionSerial));this.persistTransportPreference(c);var g=this.state,k=this.states.connected.state;d.logAction(d.LOG_MINOR,"ConnectionManager.activateTransport()","current state = "+g.state);if(g.state==this.states.closing.state||g.state==this.states.closed.state||g.state==this.states.failed.state)return d.logAction(d.LOG_MINOR,"ConnectionManager.activateTransport()","Disconnecting transport and abandoning"),c.disconnect(),!1;h.arrDeleteValue(this.pendingTransports,c);if(!c.isConnected)return d.logAction(d.LOG_MINOR, +"ConnectionManager.activateTransport()","Declining to activate transport "+c+" since it appears to no longer be connected"),!1;var m=this.activeProtocol;this.activeProtocol=new ia(c);this.host=c.params.host;var r=e.connectionKey;r&&this.connectionKey!=r&&this.setConnection(b,e,f,!0,!!a);this.onConnectionDetailsUpdate(e,c);var n=this;h.nextTick(function(){c.on("connected",function(a,g,b){n.onConnectionDetailsUpdate(b,c);n.emit("update",new V(k,k,null,a))})});g.state===this.states.connected.state?a&& +(this.errorReason=this.realtime.connection.errorReason=a,this.emit("update",new V(k,k,null,a))):(this.notifyState({state:"connected",error:a}),this.errorReason=this.realtime.connection.errorReason=a||null);this.emit("transport.active",c);m&&(0this.connectionStateTtl+this.maxIdleInterval&&(d.logAction(d.LOG_MINOR,"ConnectionManager.checkConnectionStateFreshness()","Last known activity from realtime was "+a+"ms ago; discarding connection state"),this.clearConnection(),this.states.connecting.failState="suspended",this.states.connecting.queueEvents=!1)}};a.prototype.persistConnection=function(){if(n){var a=this.realtime.connection.recoveryKey;a&&(a={recoveryKey:a,disconnectedAt:h.now(),location:window.location,clientId:this.realtime.auth.clientId}, +n&&K.setSession("ably-connection-recovery",a))}};a.prototype.unpersistConnection=function(){n&&K.removeSession("ably-connection-recovery")};a.prototype.getError=function(){return this.errorReason||this.getStateError()};a.prototype.getStateError=function(){return L[this.state.state]};a.prototype.activeState=function(){return this.state.queueEvents||this.state.sendEvents};a.prototype.enactStateChange=function(a){d.logAction("failed"===a.current?d.LOG_ERROR:d.LOG_MAJOR,"Connection state",a.current+(a.reason? +"; reason: "+a.reason:""));d.logAction(d.LOG_MINOR,"ConnectionManager.enactStateChange","setting new state: "+a.current+"; reason = "+(a.reason&&a.reason.message));var c=this.state=this.states[a.current];a.reason&&(this.errorReason=a.reason,this.realtime.connection.errorReason=a.reason);(c.terminal||"suspended"===c.state)&&this.clearConnection();this.emit("connectionstate",a)};a.prototype.startTransitionTimer=function(a){d.logAction(d.LOG_MINOR,"ConnectionManager.startTransitionTimer()","transitionState: "+ +a.state);this.transitionTimer&&(d.logAction(d.LOG_MINOR,"ConnectionManager.startTransitionTimer()","clearing already-running timer"),clearTimeout(this.transitionTimer));var c=this;this.transitionTimer=setTimeout(function(){c.transitionTimer&&(c.transitionTimer=null,d.logAction(d.LOG_MINOR,"ConnectionManager "+a.state+" timer expired","requesting new state: "+a.failState),c.notifyState({state:a.failState}))},a.retryDelay)};a.prototype.cancelTransitionTimer=function(){d.logAction(d.LOG_MINOR,"ConnectionManager.cancelTransitionTimer()", +"");this.transitionTimer&&(clearTimeout(this.transitionTimer),this.transitionTimer=null)};a.prototype.startSuspendTimer=function(){var a=this;this.suspendTimer||(this.suspendTimer=setTimeout(function(){a.suspendTimer&&(a.suspendTimer=null,d.logAction(d.LOG_MINOR,"ConnectionManager suspend timer expired","requesting new state: suspended"),a.states.connecting.failState="suspended",a.states.connecting.queueEvents=!1,a.notifyState({state:"suspended"}))},this.connectionStateTtl))};a.prototype.checkSuspendTimer= +function(a){"disconnected"!==a&&"suspended"!==a&&"connecting"!==a&&this.cancelSuspendTimer()};a.prototype.cancelSuspendTimer=function(){this.states.connecting.failState="disconnected";this.states.connecting.queueEvents=!0;this.suspendTimer&&(clearTimeout(this.suspendTimer),this.suspendTimer=null)};a.prototype.startRetryTimer=function(a){var c=this;this.retryTimer=setTimeout(function(){d.logAction(d.LOG_MINOR,"ConnectionManager retry timer expired","retrying");c.retryTimer=null;c.requestState({state:"connecting"})}, +a)};a.prototype.cancelRetryTimer=function(){this.retryTimer&&(clearTimeout(this.retryTimer),this.retryTimer=null)};a.prototype.notifyState=function(a){var c=a.state,b=this,g="disconnected"===c&&(this.state===this.states.connected||this.state===this.states.synchronizing||a.retryImmediately||this.state===this.states.connecting&&a.error&&N.isTokenErr(a.error)&&!(this.errorReason&&N.isTokenErr(this.errorReason)));d.logAction(d.LOG_MINOR,"ConnectionManager.notifyState()","new state: "+c+(g?"; will retry connection immediately": +""));if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(a.state),!this.state.terminal)){var e=this.states[a.state];a=new V(this.state.state,e.state,e.retryDelay,a.error||L[e.state]);if(g){var f=function(){b.state===b.states.disconnected&&(b.lastAutoReconnectAttempt=h.now(),b.requestState({state:"connecting"}))},k=this.lastAutoReconnectAttempt&&h.now()-this.lastAutoReconnectAttempt+1;k&&1E3>k?(d.logAction(d.LOG_MICRO,"ConnectionManager.notifyState()", +"Last reconnect attempt was only "+k+"ms ago, waiting another "+(1E3-k)+"ms before trying again"),setTimeout(f,1E3-k)):h.nextTick(f)}else"disconnected"!==c&&"suspended"!==c||this.startRetryTimer(e.retryDelay);("disconnected"===c&&!g||"suspended"===c||e.terminal)&&h.nextTick(function(){b.disconnectAllTransports()});"connected"!=c||this.activeProtocol||d.logAction(d.LOG_ERROR,"ConnectionManager.notifyState()","Broken invariant: attempted to go into connected state, but there is no active protocol"); +this.enactStateChange(a);this.state.sendEvents?this.sendQueuedMessages():this.state.queueEvents||(this.realtime.channels.propogateConnectionInterruption(c,a.reason),this.failQueuedMessages(a.reason))}};a.prototype.requestState=function(a){var c=a.state,b=this;d.logAction(d.LOG_MINOR,"ConnectionManager.requestState()","requested state: "+c+"; current state: "+this.state.state);if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(c),"connecting"!=c||"connected"!= +this.state.state)&&("closing"!=c||"closed"!=this.state.state)){var g=this.states[c];a=new V(this.state.state,g.state,null,a.error||L[g.state]);this.enactStateChange(a);"connecting"==c&&h.nextTick(function(){b.startConnect()});"closing"==c&&this.closeImpl()}};a.prototype.startConnect=function(){if(this.state!==this.states.connecting)d.logAction(d.LOG_MINOR,"ConnectionManager.startConnect()","Must be in connecting state to connect, but was "+this.state.state);else{var a=this.realtime.auth,c=this,b= +++this.connectCounter,e=function(){c.checkConnectionStateFreshness();c.getTransportParams(function(a){b===c.connectCounter&&c.connectImpl(a,b)})};d.logAction(d.LOG_MINOR,"ConnectionManager.startConnect()","starting connection");this.startSuspendTimer();this.startTransitionTimer(this.states.connecting);if("basic"===a.method)e();else{var f=function(a){b===c.connectCounter&&(a?c.actOnErrorFromAuthorize(a):e())};this.errorReason&&N.isTokenErr(this.errorReason)?a._forceNewToken(null,null,f):a._ensureValidAuthCredentials(!1, +f)}}};a.prototype.connectImpl=function(a,c){var b=this.state.state;b!==this.states.connecting.state&&b!==this.states.connected.state?d.logAction(d.LOG_MINOR,"ConnectionManager.connectImpl()","Must be in connecting state to connect (or connected to upgrade), but was "+b):this.pendingTransports.length?d.logAction(d.LOG_MINOR,"ConnectionManager.connectImpl()","Transports "+this.pendingTransports[0].toString()+" currently pending; taking no action"):b==this.states.connected.state?this.upgradeIfNeeded(a): +1g||!h.allSame(n,"clientId")?f=!1:(f[k]=n,f=!0)}}f?(b.merged||(b.callback=aa([b.callback]),b.merged=!0),b.callback.push(c)):this.queuedMessages.push(new m(a,c))};a.prototype.sendQueuedMessages=function(){d.logAction(d.LOG_MICRO,"ConnectionManager.sendQueuedMessages()","sending "+this.queuedMessages.count()+ +" queued messages");for(var a;a=this.queuedMessages.shift();)this.sendImpl(a)};a.prototype.queuePendingMessages=function(a){a&&a.length&&(d.logAction(d.LOG_MICRO,"ConnectionManager.queuePendingMessages()","queueing "+a.length+" pending messages"),this.queuedMessages.prepend(a))};a.prototype.failQueuedMessages=function(a){var c=this.queuedMessages.count();0=b?(a="No activity seen from realtime in "+a+"ms; assuming connection has dropped",d.logAction(d.LOG_ERROR,"Transport.onIdleTimerExpire()",a),this.disconnect(new q(a,80003,408))):this.setIdleTimer(b+100)};b.prototype.onAuthUpdated=function(){}; +return b}();(function(){function b(b,a,c){this.shortName="web_socket";c.heartbeats=u.useProtocolHeartbeats;R.call(this,b,a,c);this.wsHost=t.getHost(c.options,c.host,!0)}var l=u.WebSocket;h.inherits(b,R);b.isAvailable=function(){return!!l};b.isAvailable()&&(O.supportedTransports.web_socket=b);b.tryConnect=function(f,a,c,h){function e(a){h({event:this.event,error:a})}var m=new b(f,a,c);m.on(["failed","disconnected"],e);m.on("wsopen",function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.tryConnect()", +"viable transport "+m);m.off(["failed","disconnected"],e);h(null,m)});m.connect()};b.prototype.createWebSocket=function(b,a){var c=0;if(a)for(var d in a)b+=(c++?"&":"?")+d+"="+a[d];this.uri=b;return new l(b)};b.prototype.toString=function(){return"WebSocketTransport; uri="+this.uri};b.prototype.connect=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","starting");R.prototype.connect.call(this);var b=this,a=this.params,c=a.options,h=(c.tls?"wss://":"ws://")+this.wsHost+":"+t.getPort(c)+ +"/";d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","uri: "+h);this.auth.getAuthParams(function(c,f){if(!b.isDisposed){var e="",k;for(k in f)e+=" "+k+": "+f[k]+";";d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","authParams:"+e+" err: "+c);if(c)b.disconnect(c);else{e=a.getConnectParams(f);try{var g=b.wsConnection=b.createWebSocket(h,e);g.binaryType=u.binaryType;g.onopen=function(){b.onWsOpen()};g.onclose=function(a){b.onWsClose(a)};g.onmessage=function(a){b.onWsData(a.data)};g.onerror= +function(a){b.onWsError(a)};if(g.on)g.on("ping",function(){b.onActivity()})}catch(r){d.logAction(d.LOG_ERROR,"WebSocketTransport.connect()","Unexpected exception creating websocket: err = "+(r.stack||r.message)),b.disconnect(r)}}}})};b.prototype.send=function(b){var a=this.wsConnection;if(a)try{a.send(z.serialize(b,this.params.format))}catch(c){b="Exception from ws connection when trying to send: "+h.inspectError(c),d.logAction(d.LOG_ERROR,"WebSocketTransport.send()",b),this.finish("disconnected", +new q(b,5E4,500))}else d.logAction(d.LOG_ERROR,"WebSocketTransport.send()","No socket connection")};b.prototype.onWsData=function(b){d.logAction(d.LOG_MICRO,"WebSocketTransport.onWsData()","data received; length = "+b.length+"; type = "+typeof b);try{this.onProtocolMessage(z.deserialize(b,this.format))}catch(a){d.logAction(d.LOG_ERROR,"WebSocketTransport.onWsData()","Unexpected exception handing channel message: "+a.stack)}};b.prototype.onWsOpen=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsOpen()", +"opened WebSocket");this.emit("wsopen")};b.prototype.onWsClose=function(b){if("object"==typeof b){var a=b.wasClean;b=b.code}else a=1E3==b;delete this.wsConnection;a?(d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsClose()","Cleanly closed WebSocket"),a=new q("Websocket closed",80003,400)):(b="Unclean disconnection of WebSocket ; code = "+b,a=new q(b,80003,400),d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsClose()",b));this.finish("disconnected",a);this.emit("disposed")};b.prototype.onWsError=function(b){d.logAction(d.LOG_MINOR, +"WebSocketTransport.onError()","Error from WebSocket: "+b.message);var a=this;h.nextTick(function(){a.disconnect(b)})};b.prototype.dispose=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.dispose()","");this.isDisposed=!0;var b=this.wsConnection;b&&(b.onmessage=function(){},delete this.wsConnection,h.nextTick(function(){d.logAction(d.LOG_MICRO,"WebSocketTransport.dispose()","closing websocket");b.close()}))};return b})();var M=function(){function b(b){var a=[80015,80017,80030];return b.code&& +(N.isTokenErr(b)?0:h.arrIn(a,b.code)||4E4<=b.code&&5E4>b.code)?[z.fromValues({action:z.Action.ERROR,error:b})]:[z.fromValues({action:z.Action.DISCONNECTED,error:b})]}function l(b,a,c){c.format=void 0;c.heartbeats=!0;R.call(this,b,a,c);this.stream="stream"in c?c.stream:!0;this.pendingItems=this.pendingCallback=this.recvRequest=this.sendRequest=null}h.inherits(l,R);l.REQ_SEND=0;l.REQ_RECV=1;l.REQ_RECV_POLL=2;l.REQ_RECV_STREAM=3;l.prototype.connect=function(){d.logAction(d.LOG_MINOR,"CometTransport.connect()", +"starting");R.prototype.connect.call(this);var f=this,a=this.params,c=a.options;a=t.getHost(c,a.host);var n=t.getPort(c);this.baseUri=(c.tls?"https://":"http://")+a+":"+n+"/comet/";var e=this.baseUri+"connect";d.logAction(d.LOG_MINOR,"CometTransport.connect()","uri: "+e);this.auth.getAuthParams(function(a,c){if(a)f.disconnect(a);else if(!f.isDisposed){f.authParams=c;var k=f.params.getConnectParams(c);"stream"in k&&(f.stream=k.stream);d.logAction(d.LOG_MINOR,"CometTransport.connect()","connectParams:"+ +h.toQueryString(k));var g=!1;k=f.recvRequest=f.createRequest(e,null,k,null,f.stream?3:1);k.on("data",function(a){f.recvRequest&&(g||(g=!0,f.emit("preconnect")),f.onData(a))});k.on("complete",function(a){f.recvRequest||(a=a||new q("Request cancelled",8E4,400));f.recvRequest=null;f.onActivity();if(a)if(a.code)f.onData(b(a));else f.disconnect(a);else h.nextTick(function(){f.recv()})});k.exec()}})};l.prototype.requestClose=function(){d.logAction(d.LOG_MINOR,"CometTransport.requestClose()");this._requestCloseOrDisconnect(!0)}; +l.prototype.requestDisconnect=function(){d.logAction(d.LOG_MINOR,"CometTransport.requestDisconnect()");this._requestCloseOrDisconnect(!1)};l.prototype._requestCloseOrDisconnect=function(b){var a=b?this.closeUri:this.disconnectUri;if(a){var c=this;a=this.createRequest(a,null,this.authParams,null,0);a.on("complete",function(a){a&&(d.logAction(d.LOG_ERROR,"CometTransport.request"+(b?"Close()":"Disconnect()"),"request returned err = "+h.inspectError(a)),c.finish("disconnected",a))});a.exec()}};l.prototype.dispose= +function(){d.logAction(d.LOG_MINOR,"CometTransport.dispose()","");if(!this.isDisposed){this.isDisposed=!0;this.recvRequest&&(d.logAction(d.LOG_MINOR,"CometTransport.dispose()","aborting recv request"),this.recvRequest.abort(),this.recvRequest=null);this.finish("disconnected",L.disconnected);var b=this;h.nextTick(function(){b.emit("disposed")})}};l.prototype.onConnect=function(b){if(!this.isDisposed){var a=b.connectionKey;R.prototype.onConnect.call(this,b);a=this.baseUri+a;d.logAction(d.LOG_MICRO, +"CometTransport.onConnect()","baseUri = "+a+"; connectionKey = "+b.connectionKey);this.sendUri=a+"/send";this.recvUri=a+"/recv";this.closeUri=a+"/close";this.disconnectUri=a+"/disconnect"}};l.prototype.send=function(b){if(this.sendRequest)this.pendingItems=this.pendingItems||[],this.pendingItems.push(b);else{var a=this.pendingItems||[];a.push(b);this.pendingItems=null;this.sendItems(a)}};l.prototype.sendAnyPending=function(){var b=this.pendingItems;b&&(this.pendingItems=null,this.sendItems(b))};l.prototype.sendItems= +function(f){var a=this;f=this.sendRequest=a.createRequest(a.sendUri,null,a.authParams,this.encodeRequest(f),0);f.on("complete",function(c,f){c&&d.logAction(d.LOG_ERROR,"CometTransport.sendItems()","on complete: err = "+h.inspectError(c));a.sendRequest=null;if(f)a.onData(f);else if(c&&c.code)a.onData(b(c));else a.disconnect(c);a.pendingItems&&h.nextTick(function(){a.sendRequest||a.sendAnyPending()})});f.exec()};l.prototype.recv=function(){if(!this.recvRequest&&this.isConnected){var d=this,a=this.recvRequest= +this.createRequest(this.recvUri,null,this.authParams,null,d.stream?3:2);a.on("data",function(a){d.onData(a)});a.on("complete",function(a){d.recvRequest=null;d.onActivity();if(a)if(a.code)d.onData(b(a));else d.disconnect(a);else h.nextTick(function(){d.recv()})});a.exec()}};l.prototype.onData=function(b){try{var a=this.decodeResponse(b);if(a&&a.length)for(b=0;bg||300<=g?(c=d&&d.error||c,c||(c=Error("Error in unenveloping "+e),c.statusCode=g),a(c,d,f,!0,g)): +a(c,d,f,!0,g))}}}function a(a){var b=[];if(a)for(var c in a)b.push(c+"="+a[c]);return b.join("&")}function c(b,c,f,k){return function(e,m,n,p,l){e?d.logAction(d.LOG_MICRO,"Resource."+c+"()","Received Error; "+(f+(k?"?":"")+a(k))+"; Error: "+h.inspectError(e)):d.logAction(d.LOG_MICRO,"Resource."+c+"()","Received; "+(f+(k?"?":"")+a(k))+"; Headers: "+a(n)+"; StatusCode: "+l+"; Body: "+(y.isBuffer(m)?m.toString():m));b&&b(e,m,n,p,l)}}var n=u.msgpack;h.arrForEach(w.methodsWithoutBody,function(a){b[a]= +function(c,e,d,g,f,h){b["do"](a,c,e,null,d,g,f,h)}});h.arrForEach(w.methodsWithBody,function(a){b[a]=function(c,e,d,g,f,h,n){b["do"](a,c,e,d,g,f,h,n)}});b["do"]=function(b,m,p,k,g,r,v,C){function e(c,f){d.shouldLog(d.LOG_MICRO)&&d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending; "+(p+(f?"?":"")+a(f)));var v=[m,p,c,k,f,function(a,b,c,d,f){a&&N.isTokenErr(a)?m.auth.authorize(null,null,function(a){a?C(a):l(m,g,r,C,e)}):C(a,b,c,d,f)}];k||v.splice(3,1);if(d.shouldLog(d.LOG_MICRO)){var q=k;if(0<(c["content-type"]|| +"").indexOf("msgpack"))try{q=n.decode(k)}catch(I){d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending MsgPack Decoding Error: "+h.inspectError(I))}d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending; "+(p+(f?"?":"")+a(f))+"; Body: "+q)}w[b].apply(this,v)}d.shouldLog(d.LOG_MICRO)&&(C=c(C,b,p,r));v&&(C=C&&f(C,v),(r=r||{}).envelope=v);l(m,g,r,C,e)};return b}(),P=function(){function b(a,b,d,e,f,h){this.rest=a;this.path=b;this.headers=d;this.envelope=e;this.bodyHandler=f;this.useHttpPaginatedResponse= +h||!1}function l(a,b,d){this.resource=a;this.items=b;if(d){var c=this;"first"in d&&(this.first=function(a){c.get(d.first,a)});"current"in d&&(this.current=function(a){c.get(d.current,a)});this.next=function(a){"next"in d?c.get(d.next,a):a(null,null)};this.hasNext=function(){return"next"in d};this.isLast=function(){return!this.hasNext()}}}function f(a,b,d,e,f,h){l.call(this,a,b,f);this.statusCode=e;this.success=300>e&&200<=e;this.headers=d;this.errorCode=h&&h.code;this.errorMessage=h&&h.message}h.arrForEach(w.methodsWithoutBody, +function(a){b.prototype[a]=function(b,d){var c=this;J[a](c.rest,c.path,c.headers,b,c.envelope,function(a,b,e,g,f){c.handlePage(a,b,e,g,f,d)})}});h.arrForEach(w.methodsWithBody,function(a){b.prototype[a]=function(b,d,e){var c=this;J[a](c.rest,c.path,d,c.headers,b,c.envelope,function(a,b,g,d,f){e&&c.handlePage(a,b,g,d,f,e)})}});b.prototype.handlePage=function(a,b,n,e,m,p){if(!a||this.useHttpPaginatedResponse&&(b||"number"===typeof a.code)){var c,g;try{var r=this.bodyHandler(b,n,e)}catch(C){p(a||C); +return}if(n&&(c=n.Link||n.link)){b=c;"string"==typeof b&&(b=b.split(","));e={};for(c=0;c;\s*rel="(\w+)"$/)){var v;(v=(v=g[1].match(/^\.\/(\w+)\?(.*)$/))&&h.parseQueryString(v[2]))&&(e[g[2]]=v)}g=e}this.useHttpPaginatedResponse?p(null,new f(this,r,n,m,g,a)):p(null,new l(this,r,g))}else d.logAction(d.LOG_ERROR,"PaginatedResource.handlePage()","Unexpected error getting resource: err = "+h.inspectError(a)),p(a)};l.prototype.get=function(a,b){var c=this.resource; +J.get(c.rest,c.path,c.headers,a,c.envelope,function(a,d,f,k,g){c.handlePage(a,d,f,k,g,b)})};h.inherits(f,l);return b}(),N=function(){function b(){}function l(a){if(!h.isErrorInfo(a))return new q(h.inspectError(a),a.code||40170,a.statusCode||401);a.code||(403===a.statusCode?a.code=40300:(a.code=40170,a.statusCode=401));return a}function f(a){if(!a)return"";"string"==typeof a&&(a=JSON.parse(a));var b={},c=h.keysArray(a,!0);if(!c)return"";c.sort();for(var e=0;en){b(new q("authUrl response exceeded max permitted length",40170,401));return}try{c=JSON.parse(c)}catch(ma){b(new q("Unexpected error processing authURL response; err = "+ma.message,40170,401));return}}b(null,c)}else b(new q("authUrl responded with unacceptable content-type "+a+", should be either text/plain, application/jwt or application/json",40170,401));else b(new q("authUrl response is missing a content-type header",40170,401))}var g=h.mixin({accept:"application/json, text/plain"}, +c.authHeaders),f=c.authMethod&&"post"===c.authMethod.toLowerCase();if(!f){var m=c.authUrl.indexOf("?");if(-1n&&!c.suppressMaxLengthCheck?e(new q("Token request/details object exceeded max permitted stringified size (was "+f+" bytes)",40170,401)):"issued"in b?e(null,b):"keyName"in b?g(b,function(a,b,c,g){a?(d.logAction(d.LOG_ERROR,"Auth.requestToken()","token request API call returned error; err = "+h.inspectError(a)),e(l(a))):(g||(b=JSON.parse(b)),d.logAction(d.LOG_MINOR,"Auth.getToken()","token received"),e(null,b))}):(f="Expected token request callback to call back with a token string, token request object, or token details object", +d.logAction(d.LOG_ERROR,"Auth.requestToken()",f),e(new q(f,40170,401)))})};c.prototype.createTokenRequest=function(a,b,c){"function"!=typeof a||c?"function"!=typeof b||c||(c=b,b=null):(c=a,b=a=null);if(!c&&this.client.options.promises)return h.promisify(this,"createTokenRequest",arguments);b=b||this.authOptions;a=a||h.copy(this.tokenParams);var e=b.key;if(e){e=e.split(":");var g=e[0],k=e[1];if(k)if(""===a.clientId)c(new q("clientId can\u2019t be an empty string",40012,400));else{"capability"in a&& +(a.capability=f(a.capability));var n=h.mixin({keyName:g},a),p=a.clientId||"",l=a.ttl||"",r=a.capability||"",t=this;(function(a){n.timestamp?a():t.getTimestamp(b&&b.queryTime,function(b,e){b?c(b):(n.timestamp=e,a())})})(function(){var a=n.nonce||(n.nonce=("000000"+Math.floor(1E16*Math.random())).slice(-16));a=n.keyName+"\n"+l+"\n"+r+"\n"+p+"\n"+n.timestamp+"\n"+a+"\n";n.mac=n.mac||m(a,k);d.logAction(d.LOG_MINOR,"Auth.getTokenRequest()","generated signed request");c(null,n)})}else c(new q("Invalid key specified", +40101,403))}else c(new q("No key specified",40101,403))};c.prototype.getAuthParams=function(a){"basic"==this.method?a(null,{key:this.key}):this._ensureValidAuthCredentials(!1,function(b,c){b?a(b):a(null,{access_token:c.token})})};c.prototype.getAuthHeaders=function(a){"basic"==this.method?a(null,{authorization:"Basic "+this.basicKey}):this._ensureValidAuthCredentials(!1,function(b,c){b?a(b):a(null,{authorization:"Bearer "+e(c.token)})})};c.prototype.getTimestamp=function(a,b){this.isTimeOffsetSet()|| +!a&&!this.authOptions.queryTime?b(null,this.getTimestampUsingOffset()):this.client.time(b)};c.prototype.getTimestampUsingOffset=function(){return h.now()+(this.client.serverTimeOffset||0)};c.prototype.isTimeOffsetSet=function(){return null!==this.client.serverTimeOffset};c.prototype._saveBasicOptions=function(a){this.method="basic";this.key=a.key;this.basicKey=e(a.key);this.authOptions=a||{};"clientId"in a&&this._userSetClientId(a.clientId)};c.prototype._saveTokenOptions=function(a,b){this.method= +"token";a&&(this.tokenParams=a);b&&(b.token&&(b.tokenDetails="string"===typeof b.token?{token:b.token}:b.token),b.tokenDetails&&(this.tokenDetails=b.tokenDetails),"clientId"in b&&this._userSetClientId(b.clientId),this.authOptions=b)};c.prototype._ensureValidAuthCredentials=function(a,c){var e=this,g=this.tokenDetails;if(g){if(this._tokenClientIdMismatch(g.clientId)){c(new q("Mismatch between clientId in token ("+g.clientId+") and current clientId ("+this.clientId+")",40102,403));return}if(!this.isTimeOffsetSet()|| +!g.expires||g.expires>=this.getTimestampUsingOffset()){d.logAction(d.LOG_MINOR,"Auth.getToken()","using cached token; expires = "+g.expires);c(null,g);return}d.logAction(d.LOG_MINOR,"Auth.getToken()","deleting expired token");this.tokenDetails=null}(this.waitingForTokenRequest||(this.waitingForTokenRequest=aa())).push(c);if(null===this.currentTokenRequestId||a){var f=this.currentTokenRequestId=p++;this.requestToken(this.tokenParams,this.authOptions,function(a,c){if(e.currentTokenRequestId>f)d.logAction(d.LOG_MINOR, +"Auth._ensureValidAuthCredentials()","Discarding token request response; overtaken by newer one");else{e.currentTokenRequestId=null;var g=e.waitingForTokenRequest||b;e.waitingForTokenRequest=null;a?g(a):g(null,e.tokenDetails=c)}})}};c.prototype._userSetClientId=function(a){if("string"!==typeof a&&null!==a)throw new q("clientId must be either a string or null",40012,400);if("*"===a)throw new q('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, instantiate the library with {defaultTokenParams: {clientId: "*"}}), or if calling authorize(), pass it in as a tokenParam: authorize({clientId: "*"}, authOptions)', +40012,400);if(a=this._uncheckedSetClientId(a))throw a;};c.prototype._uncheckedSetClientId=function(a){if(this._tokenClientIdMismatch(a)){a="Unexpected clientId mismatch: client has "+this.clientId+", requested "+a;var b=new q(a,40102,401);d.logAction(d.LOG_ERROR,"Auth._uncheckedSetClientId()",a);return b}this.clientId=this.tokenParams.clientId=a;return null};c.prototype._tokenClientIdMismatch=function(a){return this.clientId&&"*"!==this.clientId&&a&&"*"!==a&&this.clientId!==a};c.isTokenErr=function(a){return a.code&& +40140<=a.code&&40150>a.code};return c}(),D=function(){function b(){}function l(a){if(!(this instanceof l))return new l(a);if(!a){var b="no options provided";d.logAction(d.LOG_ERROR,"Rest()",b);throw Error(b);}a=t.objectifyOptions(a);a.log&&d.setLog(a.log.level,a.log.handler);d.logAction(d.LOG_MICRO,"Rest()","initialized with clientOptions "+h.inspect(a));this.options=t.normaliseOptions(a);if(a.key){b=a.key.match(/^([^:\s]+):([^:.\s]+)$/);if(!b)throw b="invalid key parameter",d.logAction(d.LOG_ERROR, +"Rest()",b),Error(b);a.keyName=b[1];a.keySecret=b[2]}if("clientId"in a){if("string"!==typeof a.clientId&&null!==a.clientId)throw new q("clientId must be either a string or null",40012,400);if("*"===a.clientId)throw new q('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, use {defaultTokenParams: {clientId: "*"}})',40012,400);}d.logAction(d.LOG_MINOR,"Rest()","started; version = "+t.libstring);this.baseUri=this.authority= +function(b){return t.getHttpScheme(a)+b+":"+t.getPort(a,!1)};this.serverTimeOffset=this._currentFallback=null;this.auth=new N(this,a);this.channels=new f(this);this.push=new pa(this)}function f(a){this.rest=a;this.attached={}}var a=u.msgpack;l.prototype.stats=function(a,d){if(void 0===d)if("function"==typeof a)d=a,a=null;else{if(this.options.promises)return h.promisify(this,"stats",arguments);d=b}var c=h.defaultGetHeaders(),f=this.options.useBinaryProtocol?"msgpack":"json";f=w.supportsLinkHeaders? +void 0:f;this.options.headers&&h.mixin(c,this.options.headers);(new P(this,"/stats",c,f,function(a,b,c){a=c?a:JSON.parse(a);for(b=0;bb?d(new q("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+b+" bytes)",40009,400)):e._publish(x.serialize(m,g),l,p,d)}})};l.prototype._publish=function(a,b,d,e){J.post(this.rest,this.basePath+"/messages",a,b,d,!1,e)};return l}(),S=function(){function b(){}function l(a,b,f){d.logAction(d.LOG_MINOR,"RealtimeChannel()","started; name = "+b);Y.call(this,a,b,f);this.realtime=a;this.presence= +new ra(this,a.options);this.connectionManager=a.connection.connectionManager;this.state="initialized";this.subscriptions=new A;this.syncChannelSerial=void 0;this.properties={attachSerial:void 0};this.setOptions(f);this._mode=this._requestedFlags=this.errorReason=null}var f=z.Action;h.inherits(l,Y);l.invalidStateError=function(a){return{statusCode:400,code:90001,message:"Channel operation failed as channel state is "+a}};l.progressOps={statechange:"statechange",sync:"sync"};l.processListenerArgs=function(a){a= +Array.prototype.slice.call(a);"function"===typeof a[0]&&a.unshift(null);void 0==a[a.length-1]&&a.pop();return a};l.prototype.publish=function(){var a=arguments.length,c=arguments[0],d=arguments[a-1];if("function"!==typeof d){if(this.realtime.options.promises)return h.promisify(this,"publish",arguments);d=b;++a}if(this.connectionManager.activeState()){if(2==a)if(h.isObject(c))c=[x.fromValues(c)];else if(h.isArray(c))c=x.fromValuesArray(c);else throw new q("The single-argument form of publish() expects a message object or an array of message objects", +40013,400);else c=[x.fromValues({name:arguments[0],data:arguments[1]})];var e=this,f=this.realtime.options.maxMessageSize;x.encodeArray(c,this.channelOptions,function(a){a?d(a):(a=x.getMessagesSize(c),a>f?d(new q("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+f+" bytes)",40009,400)):e._publish(c,d))})}else d(this.connectionManager.getError())};l.prototype._publish=function(a,b){d.logAction(d.LOG_MICRO,"RealtimeChannel.publish()","message count = "+a.length); +var c=this.state;switch(c){case "failed":case "suspended":b(q.fromValues(l.invalidStateError(c)));break;default:d.logAction(d.LOG_MICRO,"RealtimeChannel.publish()","sending message; channel state is "+c),c=new z,c.action=f.MESSAGE,c.channel=this.name,c.messages=a,this.sendMessage(c,b)}};l.prototype.onEvent=function(a){d.logAction(d.LOG_MICRO,"RealtimeChannel.onEvent()","received message");for(var b=this.subscriptions,f=0;fb.timestamp;var c=a.parseId(),d=b.parseId();return c.msgSerial===d.msgSerial?c.index>d.index:c.msgSerial>d.msgSerial}h.inherits(a,X);a.prototype.enter=function(a,b){if(l(this))throw new q("clientId must be specified to enter a presence channel",40012,400);return this._enterOrUpdateClient(void 0,a,"enter",b)};a.prototype.update= +function(a,b){if(l(this))throw new q("clientId must be specified to update presence data",40012,400);return this._enterOrUpdateClient(void 0,a,"update",b)};a.prototype.enterClient=function(a,b,c){return this._enterOrUpdateClient(a,b,"enter",c)};a.prototype.updateClient=function(a,b,c){return this._enterOrUpdateClient(a,b,"update",c)};a.prototype._enterOrUpdateClient=function(a,c,f,k){if(!k)if("function"===typeof c)k=c,c=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"_enterOrUpdateClient", +[a,c,f]);k=b}var e=this.channel;if(e.connectionManager.activeState()){d.logAction(d.LOG_MICRO,"RealtimePresence."+f+"Client()","channel = "+e.name+", client = "+(a||"(implicit) "+this.channel.realtime.auth.clientId));var m=H.fromValues({action:f,data:c});a&&(m.clientId=a);var l=this;H.encode(m,e.channelOptions,function(a){if(a)k(a);else switch(e.state){case "attached":e.sendPresence(m,k);break;case "initialized":case "detached":e.attach();case "attaching":l.pendingPresence.push({presence:m,callback:k}); +break;default:a=new q("Unable to "+f+" presence channel (incompatible state)",90001),a.code=90001,k(a)}})}else k(e.connectionManager.getError())};a.prototype.leave=function(a,b){if(l(this))throw new q("clientId must have been specified to enter or leave a presence channel",40012,400);return this.leaveClient(void 0,a,b)};a.prototype.leaveClient=function(a,c,f){if(!f)if("function"===typeof c)f=c,c=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"leaveClient",[a,c]);f=b}var e= +this.channel;if(e.connectionManager.activeState())switch(d.logAction(d.LOG_MICRO,"RealtimePresence.leaveClient()","leaving; channel = "+this.channel.name+", client = "+a),c=H.fromValues({action:"leave",data:c}),a&&(c.clientId=a),e.state){case "attached":e.sendPresence(c,f);break;case "attaching":this.pendingPresence.push({presence:c,callback:f});break;case "initialized":case "failed":a=new q("Unable to leave presence channel (incompatible state)",90001);f(a);break;default:f(L.failed)}else f(e.connectionManager.getError())}; +a.prototype.get=function(){function a(a){k(null,d?a.list(d):a.values())}var c=Array.prototype.slice.call(arguments);1==c.length&&"function"==typeof c[0]&&c.unshift(null);var d=c[0],k=c[1],g=!d||("waitForSync"in d?d.waitForSync:!0);if(!k){if(this.channel.realtime.options.promises)return h.promisify(this,"get",c);k=b}if("suspended"===this.channel.state)g?k(q.fromValues({statusCode:400,code:91005,message:"Presence state is out of sync due to channel being in the SUSPENDED state"})):a(this.members);else{var l= +this;f(this.channel,k,function(){var b=l.members;g?b.waitSync(function(){a(b)}):a(b)})}};a.prototype.history=function(a,c){d.logAction(d.LOG_MICRO,"RealtimePresence.history()","channel = "+this.name);if(void 0===c)if("function"==typeof a)c=a,a=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"history",arguments);c=b}a&&a.untilAttach&&("attached"===this.channel.state?(delete a.untilAttach,a.from_serial=this.channel.properties.attachSerial):c(new q("option untilAttach requires the channel to be attached, was: "+ +this.channel.state,4E4,400)));X.prototype._history.call(this,a,c)};a.prototype.setPresence=function(a,b,c){d.logAction(d.LOG_MICRO,"RealtimePresence.setPresence()","received presence for "+a.length+" participants; syncChannelSerial = "+c);var e,g,f=this.members,h=this._myMembers,m=[],l=this.channel.connectionManager.connectionId;b&&(this.members.startSync(),c&&(g=c.match(/^[\w\-]+:(.*)$/))&&(e=g[1]));for(c=0;ca)&&0!==u.status){if(void 0===x)if(x=u.status,1223===x&&(x=204),clearTimeout(f),G=400>x,204==x)e.complete(null,null,null,null,x);else{var d;if(d=3==e.requestMode&&G)d=u,d=d.getResponseHeader&& +(d.getResponseHeader("transfer-encoding")||!d.getResponseHeader("content-length"));B=d}if(3==a&&B)b();else if(4==a)if(B)c();else a:{try{var g=u.getResponseHeader&&u.getResponseHeader("content-type");if(g?0<=g.indexOf("application/json"):"text"==u.responseType){var k="arraybuffer"===u.responseType?y.utf8Decode(u.response):String(u.responseText);k.length&&(k=JSON.parse(k));H=!0}else k=u.response;if(void 0!==k.response){x=k.statusCode;G=400>x;var l=k.headers;k=k.response}else{var m=h.trim(u.getAllResponseHeaders()).split("\r\n"); +a={};for(g=0;ga.statusCode||h.isArray(b)?m.complete(null,b,a.headers,a.statusCode):(a=b.error||new q("Error response received from server",null,a.statusCode),m.complete(a)):m.complete(new q("Invalid server response: no envelope detected",null,500))}else m.complete(null,a)};this.timer=setTimeout(function(){m.abort()}, +this.requestMode==M.REQ_SEND?this.timeouts.httpRequestTimeout:this.timeouts.recvTimeout);n.insertBefore(c,n.firstChild)};f.prototype.complete=function(a,b,c,d){c=c||{};this.requestComplete||(this.requestComplete=!0,b&&(c["content-type"]="string"==typeof b?"text/plain":"application/json",this.emit("data",b)),this.emit("complete",a,b,c,!0,d),this.dispose())};f.prototype.abort=function(){this.dispose()};f.prototype.dispose=function(){var b=this.timer;b&&(clearTimeout(b),this.timer=null);b=this.script; +b.parentNode&&b.parentNode.removeChild(b);delete a[this.id];this.emit("disposed")};u.jsonpSupported&&!w.Request&&(w.Request=function(a,b,c,d,e,f,l){var g=m(c,d,e,f,M.REQ_SEND,b&&b.options.timeouts,a);g.once("complete",l);h.nextTick(function(){g.exec()});return g},w.checkConnectivity=function(a){var b=t.jsonpInternetUpUrl;if(e)e.push(a);else{e=[a];d.logAction(d.LOG_MICRO,"(JSONP)Http.checkConnectivity()","Sending; "+b);var c=new f("isTheInternetUp",b,null,null,null,M.REQ_SEND,t.TIMEOUTS);c.once("complete", +function(a,b){var c=!a&&b;d.logAction(d.LOG_MICRO,"(JSONP)Http.checkConnectivity()","Result: "+c);for(var f=0;f 500) { + if(state === 'disconnected' && error && error.statusCode > 500 && this.httpHosts.length > 1) { this.unpersistTransportPreference(); this.forceFallbackHost = true; + /* and try to connect again to try a fallback host without waiting for the usual 15s disconnectedRetryTimeout */ + this.notifyState({state: state, error: error, retryImmediately: true}); + return; } + /* TODO remove below line once realtime sends token errors as DISCONNECTEDs */ - if(state === 'failed' && Auth.isTokenErr(error)) { - state = 'disconnected' - } - this.notifyState({state: state, error: error}); - } else if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { + var newConnectionState = (state === 'failed' && Auth.isTokenErr(error)) ? 'disconnected' : state; + this.notifyState({state: newConnectionState, error: error}); + return; + } + + if(wasActive && (state === 'disconnected') && (this.state !== this.states.synchronizing)) { /* If we were active but there is another transport scheduled for * activation, go into to the connecting state until that transport * activates and sets us back to connected. (manually starting the @@ -5411,13 +5418,17 @@ var ConnectionManager = (function() { }); }; - ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition) { + ConnectionManager.prototype.setConnection = function(connectionId, connectionDetails, connectionPosition, forceSetPosition, hasConnectionError) { /* if connectionKey changes but connectionId stays the same, then just a * transport change on the same connection. If connectionId changes, we're * on a new connection, with implications for msgSerial and channel state */ var self = this; - /* If no previous connectionId, don't reset the msgSerial as it may have been set by recover data */ - if(this.connectionId && (this.connectionId !== connectionId)) { + /* If no previous connectionId, don't reset the msgSerial as it may have + * been set by recover data (unless the recover failed) */ + var prevConnId = this.connectionid, + connIdChanged = prevConnId && (prevConnId !== connectionId), + recoverFailure = !prevConnId && hasConnectionError; + if(connIdChanged || recoverFailure) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.setConnection()', 'Resetting msgSerial'); this.msgSerial = 0; } @@ -5648,6 +5659,7 @@ var ConnectionManager = (function() { var retryImmediately = (state === 'disconnected' && (this.state === this.states.connected || this.state === this.states.synchronizing || + indicated.retryImmediately || (this.state === this.states.connecting && indicated.error && Auth.isTokenErr(indicated.error) && !(this.errorReason && Auth.isTokenErr(this.errorReason))))); @@ -5754,10 +5766,21 @@ var ConnectionManager = (function() { var auth = this.realtime.auth, self = this; + /* The point of the connectCounter mechanism is to ensure that the + * connection procedure can be cancelled. We want disconnectAllTransports + * to be able to stop any in-progress connection, even before it gets to + * the stage of having a pending (or even a proposed) transport that it can + * dispose() of. So we check that it's still current after any async stage, + * up until the stage that is synchronous with instantiating a transport */ + var connectCount = ++this.connectCounter; + var connect = function() { self.checkConnectionStateFreshness(); self.getTransportParams(function(transportParams) { - self.connectImpl(transportParams); + if(connectCount !== self.connectCounter) { + return; + } + self.connectImpl(transportParams, connectCount); }); }; @@ -5769,6 +5792,9 @@ var ConnectionManager = (function() { connect(); } else { var authCb = function(err) { + if(connectCount !== self.connectCounter) { + return; + } if(err) { self.actOnErrorFromAuthorize(err); } else { @@ -5779,7 +5805,7 @@ var ConnectionManager = (function() { /* Force a refetch of a new token */ auth._forceNewToken(null, null, authCb); } else { - auth._ensureValidAuthCredentials(authCb); + auth._ensureValidAuthCredentials(false, authCb); } } }; @@ -5803,7 +5829,7 @@ var ConnectionManager = (function() { * and dispatches accordingly. After a transport has been set pending, * tryATransport calls connectImpl to see if there's another stage to be done. * */ - ConnectionManager.prototype.connectImpl = function(transportParams) { + ConnectionManager.prototype.connectImpl = function(transportParams, connectCount) { var state = this.state.state; if(state !== this.states.connecting.state && state !== this.states.connected.state) { @@ -5818,7 +5844,7 @@ var ConnectionManager = (function() { } else if(this.transports.length > 1 && this.getTransportPreference()) { this.connectPreference(transportParams); } else { - this.connectBase(transportParams); + this.connectBase(transportParams, connectCount); } }; @@ -5877,13 +5903,16 @@ var ConnectionManager = (function() { * fallback hosts if applicable. * @param transportParams */ - ConnectionManager.prototype.connectBase = function(transportParams) { + ConnectionManager.prototype.connectBase = function(transportParams, connectCount) { var self = this, giveUp = function(err) { self.notifyState({state: self.states.connecting.failState, error: err}); }, candidateHosts = this.httpHosts.slice(), hostAttemptCb = function(fatal, transport) { + if(connectCount !== self.connectCounter) { + return; + } if(!transport && !fatal) { tryFallbackHosts(); } @@ -5910,6 +5939,9 @@ var ConnectionManager = (function() { * there is a problem with the ably host, or there is a general connectivity * problem */ Http.checkConnectivity(function(err, connectivity) { + if(connectCount !== self.connectCounter) { + return; + } /* we know err won't happen but handle it here anyway */ if(err) { giveUp(err); @@ -6080,6 +6112,9 @@ var ConnectionManager = (function() { ConnectionManager.prototype.disconnectAllTransports = function(exceptActive) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting all transports' + (exceptActive ? ' except the active transport' : '')); + /* This will prevent any connection procedure in an async part of one of its early stages from continuing */ + this.connectCounter++; + Utils.safeArrForEach(this.pendingTransports, function(transport) { Logger.logAction(Logger.LOG_MICRO, 'ConnectionManager.disconnectAllTransports()', 'Disconnecting pending transport: ' + transport); if(transport) transport.disconnect(); @@ -6403,6 +6438,7 @@ var Transport = (function() { this.format = params.format; this.isConnected = false; this.isFinished = false; + this.isDisposed = false; this.maxIdleInterval = null; this.idleTimer = null; this.lastActivity = null; @@ -6558,6 +6594,7 @@ var Transport = (function() { Transport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'Transport.dispose()', ''); + this.isDisposed = true; this.off(); }; @@ -6649,6 +6686,9 @@ var WebSocketTransport = (function() { var wsUri = wsScheme + this.wsHost + ':' + Defaults.getPort(options) + '/'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'uri: ' + wsUri); this.auth.getAuthParams(function(err, authParams) { + if(self.isDisposed) { + return; + } var paramStr = ''; for(var param in authParams) paramStr += ' ' + param + ': ' + authParams[param] + ';'; Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.connect()', 'authParams:' + paramStr + ' err: ' + err); if(err) { @@ -6744,6 +6784,7 @@ var WebSocketTransport = (function() { WebSocketTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'WebSocketTransport.dispose()', ''); + this.isDisposed = true; var wsConnection = this.wsConnection; if(wsConnection) { /* Ignore any messages that come through after dispose() is called but before @@ -6807,7 +6848,6 @@ var CometTransport = (function() { this.recvRequest = null; this.pendingCallback = null; this.pendingItems = null; - this.disposed = false; } Utils.inherits(CometTransport, Transport); @@ -6833,6 +6873,9 @@ var CometTransport = (function() { self.disconnect(err); return; } + if(self.isDisposed) { + return; + } self.authParams = authParams; var connectParams = self.params.getConnectParams(authParams); if('stream' in connectParams) self.stream = connectParams.stream; @@ -6909,8 +6952,8 @@ var CometTransport = (function() { CometTransport.prototype.dispose = function() { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', ''); - if(!this.disposed) { - this.disposed = true; + if(!this.isDisposed) { + this.isDisposed = true; if(this.recvRequest) { Logger.logAction(Logger.LOG_MINOR, 'CometTransport.dispose()', 'aborting recv request'); this.recvRequest.abort(); @@ -6928,7 +6971,9 @@ var CometTransport = (function() { CometTransport.prototype.onConnect = function(message) { /* if this transport has been disposed whilst awaiting connection, do nothing */ - if(this.disposed) return; + if(this.isDisposed) { + return; + } /* the connectionKey in a comet connected response is really * - */ @@ -7531,10 +7576,16 @@ var Auth = (function() { !options.authUrl; } + var trId = 0; + function getTokenRequestId() { + return trId++; + } + function Auth(client, options) { this.client = client; this.tokenParams = options.defaultTokenParams || {}; - this.tokenRequestInProgress = false; + /* The id of the current token request if one is in progress, else null */ + this.currentTokenRequestId = null; this.waitingForTokenRequest = null; if(useTokenAuth(options)) { @@ -7634,7 +7685,7 @@ var Auth = (function() { /* RSA10a: authorize() call implies token auth. If a key is passed it, we * just check if it doesn't clash and assume we're generating a token from it */ - if(authOptions && authOptions.key && (this.key !== authOptions.key)) { + if(authOptions && authOptions.key && (this.authOptions.key !== authOptions.key)) { throw new ErrorInfo('Unable to update auth options with incompatible key', 40102, 401); } @@ -7686,7 +7737,7 @@ var Auth = (function() { logAndValidateTokenAuthMethod(this.authOptions); - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(true, function(err, tokenDetails) { /* RSA10g */ delete self.tokenParams.timestamp; delete self.authOptions.queryTime; @@ -8049,7 +8100,7 @@ var Auth = (function() { if(this.method == 'basic') callback(null, {key: this.key}); else - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -8066,7 +8117,7 @@ var Auth = (function() { if(this.method == 'basic') { callback(null, {authorization: 'Basic ' + this.basicKey}); } else { - this._ensureValidAuthCredentials(function(err, tokenDetails) { + this._ensureValidAuthCredentials(false, function(err, tokenDetails) { if(err) { callback(err); return; @@ -8137,15 +8188,12 @@ var Auth = (function() { } }; - Auth.prototype._ensureValidAuthCredentials = function(callback) { + /* @param forceSupersede: force a new token request even if there's one in + * progress, making all pending callbacks wait for the new one */ + Auth.prototype._ensureValidAuthCredentials = function(forceSupersede, callback) { var self = this, token = this.tokenDetails; - if(this.tokenRequestInProgress) { - (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); - return; - } - if(token) { if(this._tokenClientIdMismatch(token.clientId)) { /* 403 to trigger a permanently failed client - RSA15c */ @@ -8165,21 +8213,26 @@ var Auth = (function() { this.tokenDetails = null; } + (this.waitingForTokenRequest || (this.waitingForTokenRequest = Multicaster())).push(callback); + if(this.currentTokenRequestId !== null && !forceSupersede) { + return; + } + /* Request a new token */ - this.tokenRequestInProgress = true; + var tokenRequestId = this.currentTokenRequestId = getTokenRequestId(); this.requestToken(this.tokenParams, this.authOptions, function(err, tokenResponse) { - self.tokenRequestInProgress = false; - var waiting = self.waitingForTokenRequest; - if(waiting) { - waiting.push(callback); - callback = waiting; - self.waitingForTokenRequest = null; + if(self.currentTokenRequestId > tokenRequestId) { + Logger.logAction(Logger.LOG_MINOR, 'Auth._ensureValidAuthCredentials()', 'Discarding token request response; overtaken by newer one'); + return; } + self.currentTokenRequestId = null; + var callbacks = self.waitingForTokenRequest || noop; + self.waitingForTokenRequest = null; if(err) { - callback(err); + callbacks(err); return; } - callback(null, (self.tokenDetails = tokenResponse)); + callbacks(null, (self.tokenDetails = tokenResponse)); }); }; diff --git a/browser/static/ably.noencryption.min.js b/browser/static/ably.noencryption.min.js index 342ebd5bb8..2bcb22dc33 100644 --- a/browser/static/ably.noencryption.min.js +++ b/browser/static/ably.noencryption.min.js @@ -2,7 +2,7 @@ /* Copyright 2019, Ably - Ably JavaScript Library v1.1.7 + Ably JavaScript Library v1.1.8 https://github.com/ably/ably-js Ably Realtime Messaging @@ -10,315 +10,316 @@ Released under the Apache Licence v2.0 */ -(function(){function ea(b){if("string"!==typeof b)throw new p("host must be a string; was a "+typeof b,4E4,400);if(!b.length)throw new p("host must not be zero-length",4E4,400);}var U=window.Ably=this,D=D||function(b,d){var f={},a=f.lib={},c=a.Base=function(){function g(){}return{extend:function(a){g.prototype=this;var c=new g;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var g=this.extend(); -g.init.apply(g,arguments);return g},init:function(){},mixIn:function(g){for(var a in g)g.hasOwnProperty(a)&&(this[a]=g[a]);g.hasOwnProperty("toString")&&(this.toString=g.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),q=a.WordArray=c.extend({init:function(g,a){g=this.words=g||[];this.sigBytes=a!=d?a:4*g.length},toString:function(g){return(g||n).stringify(this)},concat:function(g){var a=this.words,c=g.words,e=this.sigBytes;g=g.sigBytes;this.clamp();if(e%4)for(var k=0;k>>2]|=(c[k>>>2]>>>24-k%4*8&255)<<24-(e+k)%4*8;else if(65535>>2]=c[k>>>2];else a.push.apply(a,c);this.sigBytes+=g;return this},clamp:function(){var g=this.words,a=this.sigBytes;g[a>>>2]&=4294967295<<32-a%4*8;g.length=b.ceil(a/4)},clone:function(){var g=c.clone.call(this);g.words=this.words.slice(0);return g},random:function(g){function a(g){var a=987654321;return function(){a=36969*(a&65535)+(a>>16)&4294967295;g=18E3*(g&65535)+(g>>16)&4294967295;return(((a<<16)+g& -4294967295)/4294967296+.5)*(.5>>2]>>>24-e%4*8&255;c.push((k>>>4).toString(16));c.push((k&15).toString(16))}return c.join("")},parse:function(g){for(var a=g.length,c=[],e=0;e>>3]|=parseInt(g.substr(e,2),16)<<24-e%8*4;return new q.init(c, -a/2)}},m=e.Latin1={stringify:function(g){var a=g.words;g=g.sigBytes;for(var c=[],e=0;e>>2]>>>24-e%4*8&255));return c.join("")},parse:function(g){for(var a=g.length,c=[],e=0;e>>2]|=(g.charCodeAt(e)&255)<<24-e%4*8;return new q.init(c,a)}},k=e.Utf8={stringify:function(g){try{return decodeURIComponent(escape(m.stringify(g)))}catch(F){throw Error("Malformed UTF-8 data");}},parse:function(g){return m.parse(unescape(encodeURIComponent(g)))}},g=a.BufferedBlockAlgorithm= -c.extend({reset:function(){this._data=new q.init;this._nDataBytes=0},_append:function(g){"string"==typeof g&&(g=k.parse(g));this._data.concat(g);this._nDataBytes+=g.sigBytes},_process:function(g){var a=this._data,c=a.words,e=a.sigBytes,k=this.blockSize,u=e/(4*k);u=g?b.ceil(u):b.max((u|0)-this._minBufferSize,0);g=u*k;e=b.min(4*g,e);if(g){for(var f=0;fu;)a(g)&&(8>u&&(q[u]=c(b.pow(g,.5))),e[u]=c(b.pow(g,1/3)),u++),g++})();var n=[];f=f.SHA256=c.extend({_doReset:function(){this._hash=new a.init(q.slice(0))},_doProcessBlock:function(a,c){for(var g=this._hash.words,k=g[0],f=g[1],b=g[2],d=g[3],q=g[4], -m=g[5],l=g[6],h=g[7],p=0;64>p;p++){if(16>p)n[p]=a[c+p]|0;else{var r=n[p-15],t=n[p-2];n[p]=((r<<25|r>>>7)^(r<<14|r>>>18)^r>>>3)+n[p-7]+((t<<15|t>>>17)^(t<<13|t>>>19)^t>>>10)+n[p-16]}r=h+((q<<26|q>>>6)^(q<<21|q>>>11)^(q<<7|q>>>25))+(q&m^~q&l)+e[p]+n[p];t=((k<<30|k>>>2)^(k<<19|k>>>13)^(k<<10|k>>>22))+(k&f^k&b^f&b);h=l;l=m;m=q;q=d+r|0;d=b;b=f;f=k;k=r+t|0}g[0]=g[0]+k|0;g[1]=g[1]+f|0;g[2]=g[2]+b|0;g[3]=g[3]+d|0;g[4]=g[4]+q|0;g[5]=g[5]+m|0;g[6]=g[6]+l|0;g[7]=g[7]+h|0},_doFinalize:function(){var a=this._data, -c=a.words,g=8*this._nDataBytes,e=8*a.sigBytes;c[e>>>5]|=128<<24-e%32;c[(e+64>>>9<<4)+14]=b.floor(g/4294967296);c[(e+64>>>9<<4)+15]=g;a.sigBytes=4*c.length;this._process();return this._hash},clone:function(){var a=c.clone.call(this);a._hash=this._hash.clone();return a}});d.SHA256=c._createHelper(f);d.HmacSHA256=c._createHmacHelper(f)})(Math);(function(){var b=D,d=b.enc.Utf8;b.algo.HMAC=b.lib.Base.extend({init:function(f,a){f=this._hasher=new f.init;"string"==typeof a&&(a=d.parse(a));var c=f.blockSize, -b=4*c;a.sigBytes>b&&(a=f.finalize(a));a.clamp();for(var e=this._oKey=a.clone(),n=this._iKey=a.clone(),m=e.words,k=n.words,g=0;g>>2]>>>24-e%4*8&255)<<16|(a[e+1>>>2]>>>24-(e+1)%4*8&255)<<8|a[e+2>>>2]>>>24-(e+2)%4*8&255,m=0;4>m&&e+.75*m>>6*(3-m)&63));if(a=b.charAt(64))for(;f.length%4;)f.push(a);return f.join("")},parse:function(f){var a=f.length,c=this._map,b=c.charAt(64);b&&(b=f.indexOf(b),-1!=b&&(a=b));b=[];for(var e=0,n=0;n>>6-n%4*2;b[e>>> -2]|=(m|k)<<24-e%4*8;e++}return d.create(b,e)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();var Z=function(){function b(){}b.addListener=function(b,f,a){b.addEventListener?b.addEventListener(f,a,!1):b.attachEvent("on"+f,function(){a.apply(b,arguments)})};b.removeListener=function(b,f,a){b.removeEventListener?b.removeEventListener(f,a,!1):b.detachEvent("on"+f,function(){a.apply(b,arguments)})};b.addMessageListener=function(d,f){b.addListener(d,"message",f)};b.removeMessageListener= -function(d,f){b.removeListener(d,"message",f)};b.addUnloadListener=function(d){b.addListener(window,"unload",d)};return b}(),aa=function(){function b(a,g,c){for(var e=0,k=c.length;eb)a.setUint8(g++,b>>>0&127|0);else if(2048>b)a.setUint8(g++,b>>>6&31|192),a.setUint8(g++,b>>>0&63|128);else if(65536>b)a.setUint8(g++,b>>>12&15|224),a.setUint8(g++,b>>>6&63|128),a.setUint8(g++,b>>>0&63|128);else if(1114112>b)a.setUint8(g++,b>>>18&7|240),a.setUint8(g++,b>>>12&63|128), -a.setUint8(g++,b>>>6&63|128),a.setUint8(g++,b>>>0&63|128);else throw Error("bad codepoint "+b);}}function d(a,g,c){var e="",k=g;for(g+=c;kk)g+=1;else if(2048>k)g+=2;else if(65536>k)g+=3;else if(1114112>k)g+=4;else throw Error("bad codepoint "+k);}return g}function a(a,g){this.offset=g||0;this.view=a}function c(a,g){return h.keysArray(a,!0).filter(function(c){c=a[c];return(!g||void 0!==c&&null!==c)&&("function"!==typeof c||!!c.toJSON)})}function q(a,g,e,d){var k=typeof a;if("string"===k){var n= -f(a);if(32>n)return g.setUint8(e,n|160),b(g,e+1,a),1+n;if(256>n)return g.setUint8(e,217),g.setUint8(e+1,n),b(g,e+2,a),2+n;if(65536>n)return g.setUint8(e,218),g.setUint16(e+1,n),b(g,e+3,a),3+n;if(4294967296>n)return g.setUint8(e,219),g.setUint32(e+1,n),b(g,e+5,a),5+n}if(a instanceof ArrayBuffer){n=a.byteLength;if(256>n)return g.setUint8(e,196),g.setUint8(e+1,n),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+2),2+n;if(65536>n)return g.setUint8(e,197),g.setUint16(e+1,n),(new Uint8Array(g.buffer)).set(new Uint8Array(a), -e+3),3+n;if(4294967296>n)return g.setUint8(e,198),g.setUint32(e+1,n),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+5),5+n}if("number"===k){if(Math.floor(a)!==a)return g.setUint8(e,203),g.setFloat64(e+1,a),9;if(0<=a){if(128>a)return g.setUint8(e,a),1;if(256>a)return g.setUint8(e,204),g.setUint8(e+1,a),2;if(65536>a)return g.setUint8(e,205),g.setUint16(e+1,a),3;if(4294967296>a)return g.setUint8(e,206),g.setUint32(e+1,a),5;if(1.8446744073709552E19>a)return g.setUint8(e,207),e+=1,1.8446744073709552E19> -a?(g.setUint32(e,Math.floor(a*m)),g.setInt32(e+4,a&-1)):(g.setUint32(e,4294967295),g.setUint32(e+4,4294967295)),9;throw Error("Number too big 0x"+a.toString(16));}if(-32<=a)return g.setInt8(e,a),1;if(-128<=a)return g.setUint8(e,208),g.setInt8(e+1,a),2;if(-32768<=a)return g.setUint8(e,209),g.setInt16(e+1,a),3;if(-2147483648<=a)return g.setUint8(e,210),g.setInt32(e+1,a),5;if(-9223372036854775808<=a)return g.setUint8(e,211),e+=1,0x7fffffffffffffff>a?(g.setInt32(e,Math.floor(a*m)),g.setInt32(e+4,a&-1)): -(g.setUint32(e,2147483647),g.setUint32(e+4,2147483647)),9;throw Error("Number too small -0x"+(-a).toString(16).substr(1));}if("undefined"===k){if(d)return 0;g.setUint8(e,212);g.setUint8(e+1,0);g.setUint8(e+2,0);return 3}if(null===a){if(d)return 0;g.setUint8(e,192);return 1}if("boolean"===k)return g.setUint8(e,a?195:194),1;if("function"===typeof a.toJSON)return q(a.toJSON(),g,e,d);if("object"===k){k=0;var u=Array.isArray(a);if(u)n=a.length;else{var l=c(a,d);n=l.length}16>n?(g.setUint8(e,n|(u?144:128)), -k=1):65536>n?(g.setUint8(e,u?220:222),g.setUint16(e+1,n),k=3):4294967296>n&&(g.setUint8(e,u?221:223),g.setUint32(e+1,n),k=5);if(u)for(u=0;ub)return 1+b;if(256>b)return 2+b;if(65536>b)return 3+b;if(4294967296>b)return 5+b}if(a instanceof ArrayBuffer){b=a.byteLength;if(256>b)return 2+ +4294967295)/4294967296+.5)*(.5>>2]>>>24-e%4*8&255;c.push((k>>>4).toString(16));c.push((k&15).toString(16))}return c.join("")},parse:function(g){for(var a=g.length,c=[],e=0;e>>3]|=parseInt(g.substr(e,2),16)<<24-e%8*4;return new n.init(c, +a/2)}},t=e.Latin1={stringify:function(g){var a=g.words;g=g.sigBytes;for(var c=[],e=0;e>>2]>>>24-e%4*8&255));return c.join("")},parse:function(g){for(var a=g.length,c=[],e=0;e>>2]|=(g.charCodeAt(e)&255)<<24-e%4*8;return new n.init(c,a)}},k=e.Utf8={stringify:function(g){try{return decodeURIComponent(escape(t.stringify(g)))}catch(O){throw Error("Malformed UTF-8 data");}},parse:function(g){return t.parse(unescape(encodeURIComponent(g)))}},g=a.BufferedBlockAlgorithm= +c.extend({reset:function(){this._data=new n.init;this._nDataBytes=0},_append:function(g){"string"==typeof g&&(g=k.parse(g));this._data.concat(g);this._nDataBytes+=g.sigBytes},_process:function(g){var a=this._data,c=a.words,e=a.sigBytes,k=this.blockSize,p=e/(4*k);p=g?b.ceil(p):b.max((p|0)-this._minBufferSize,0);g=p*k;e=b.min(4*g,e);if(g){for(var f=0;fp;)a(g)&&(8>p&&(n[p]=c(b.pow(g,.5))),e[p]=c(b.pow(g,1/3)),p++),g++})();var m=[];f=f.SHA256=c.extend({_doReset:function(){this._hash=new a.init(n.slice(0))},_doProcessBlock:function(a,c){for(var g=this._hash.words,k=g[0],f=g[1],b=g[2],d=g[3],n=g[4], +t=g[5],l=g[6],h=g[7],q=0;64>q;q++){if(16>q)m[q]=a[c+q]|0;else{var A=m[q-15],r=m[q-2];m[q]=((A<<25|A>>>7)^(A<<14|A>>>18)^A>>>3)+m[q-7]+((r<<15|r>>>17)^(r<<13|r>>>19)^r>>>10)+m[q-16]}A=h+((n<<26|n>>>6)^(n<<21|n>>>11)^(n<<7|n>>>25))+(n&t^~n&l)+e[q]+m[q];r=((k<<30|k>>>2)^(k<<19|k>>>13)^(k<<10|k>>>22))+(k&f^k&b^f&b);h=l;l=t;t=n;n=d+A|0;d=b;b=f;f=k;k=A+r|0}g[0]=g[0]+k|0;g[1]=g[1]+f|0;g[2]=g[2]+b|0;g[3]=g[3]+d|0;g[4]=g[4]+n|0;g[5]=g[5]+t|0;g[6]=g[6]+l|0;g[7]=g[7]+h|0},_doFinalize:function(){var a=this._data, +c=a.words,g=8*this._nDataBytes,e=8*a.sigBytes;c[e>>>5]|=128<<24-e%32;c[(e+64>>>9<<4)+14]=b.floor(g/4294967296);c[(e+64>>>9<<4)+15]=g;a.sigBytes=4*c.length;this._process();return this._hash},clone:function(){var a=c.clone.call(this);a._hash=this._hash.clone();return a}});d.SHA256=c._createHelper(f);d.HmacSHA256=c._createHmacHelper(f)})(Math);(function(){var b=F,d=b.enc.Utf8;b.algo.HMAC=b.lib.Base.extend({init:function(f,a){f=this._hasher=new f.init;"string"==typeof a&&(a=d.parse(a));var c=f.blockSize, +b=4*c;a.sigBytes>b&&(a=f.finalize(a));a.clamp();for(var e=this._oKey=a.clone(),m=this._iKey=a.clone(),t=e.words,k=m.words,g=0;g>>2]>>>24-e%4*8&255)<<16|(a[e+1>>>2]>>>24-(e+1)%4*8&255)<<8|a[e+2>>>2]>>>24-(e+2)%4*8&255,t=0;4>t&&e+.75*t>>6*(3-t)&63));if(a=b.charAt(64))for(;f.length%4;)f.push(a);return f.join("")},parse:function(f){var a=f.length,c=this._map,b=c.charAt(64);b&&(b=f.indexOf(b),-1!=b&&(a=b));b=[];for(var e=0,m=0;m>>6-m%4*2;b[e>>> +2]|=(t|k)<<24-e%4*8;e++}return d.create(b,e)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();var ba=function(){function b(){}b.addListener=function(b,f,a){b.addEventListener?b.addEventListener(f,a,!1):b.attachEvent("on"+f,function(){a.apply(b,arguments)})};b.removeListener=function(b,f,a){b.removeEventListener?b.removeEventListener(f,a,!1):b.detachEvent("on"+f,function(){a.apply(b,arguments)})};b.addMessageListener=function(d,f){b.addListener(d,"message",f)};b.removeMessageListener= +function(d,f){b.removeListener(d,"message",f)};b.addUnloadListener=function(d){b.addListener(window,"unload",d)};return b}(),ca=function(){function b(a,g,c){for(var e=0,k=c.length;ep)a.setUint8(g++,p>>>0&127|0);else if(2048>p)a.setUint8(g++,p>>>6&31|192),a.setUint8(g++,p>>>0&63|128);else if(65536>p)a.setUint8(g++,p>>>12&15|224),a.setUint8(g++,p>>>6&63|128),a.setUint8(g++,p>>>0&63|128);else if(1114112>p)a.setUint8(g++,p>>>18&7|240),a.setUint8(g++,p>>>12&63|128), +a.setUint8(g++,p>>>6&63|128),a.setUint8(g++,p>>>0&63|128);else throw Error("bad codepoint "+p);}}function d(a,g,c){var e="",k=g;for(g+=c;kk)g+=1;else if(2048>k)g+=2;else if(65536>k)g+=3;else if(1114112>k)g+=4;else throw Error("bad codepoint "+k);}return g}function a(a,g){this.offset=g||0;this.view=a}function c(a,g){return h.keysArray(a,!0).filter(function(c){c=a[c];return(!g||void 0!==c&&null!==c)&&("function"!==typeof c||!!c.toJSON)})}function n(a,g,e,d){var k=typeof a;if("string"===k){var p= +f(a);if(32>p)return g.setUint8(e,p|160),b(g,e+1,a),1+p;if(256>p)return g.setUint8(e,217),g.setUint8(e+1,p),b(g,e+2,a),2+p;if(65536>p)return g.setUint8(e,218),g.setUint16(e+1,p),b(g,e+3,a),3+p;if(4294967296>p)return g.setUint8(e,219),g.setUint32(e+1,p),b(g,e+5,a),5+p}if(a instanceof ArrayBuffer){p=a.byteLength;if(256>p)return g.setUint8(e,196),g.setUint8(e+1,p),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+2),2+p;if(65536>p)return g.setUint8(e,197),g.setUint16(e+1,p),(new Uint8Array(g.buffer)).set(new Uint8Array(a), +e+3),3+p;if(4294967296>p)return g.setUint8(e,198),g.setUint32(e+1,p),(new Uint8Array(g.buffer)).set(new Uint8Array(a),e+5),5+p}if("number"===k){if(Math.floor(a)!==a)return g.setUint8(e,203),g.setFloat64(e+1,a),9;if(0<=a){if(128>a)return g.setUint8(e,a),1;if(256>a)return g.setUint8(e,204),g.setUint8(e+1,a),2;if(65536>a)return g.setUint8(e,205),g.setUint16(e+1,a),3;if(4294967296>a)return g.setUint8(e,206),g.setUint32(e+1,a),5;if(1.8446744073709552E19>a)return g.setUint8(e,207),e+=1,1.8446744073709552E19> +a?(g.setUint32(e,Math.floor(a*t)),g.setInt32(e+4,a&-1)):(g.setUint32(e,4294967295),g.setUint32(e+4,4294967295)),9;throw Error("Number too big 0x"+a.toString(16));}if(-32<=a)return g.setInt8(e,a),1;if(-128<=a)return g.setUint8(e,208),g.setInt8(e+1,a),2;if(-32768<=a)return g.setUint8(e,209),g.setInt16(e+1,a),3;if(-2147483648<=a)return g.setUint8(e,210),g.setInt32(e+1,a),5;if(-9223372036854775808<=a)return g.setUint8(e,211),e+=1,0x7fffffffffffffff>a?(g.setInt32(e,Math.floor(a*t)),g.setInt32(e+4,a&-1)): +(g.setUint32(e,2147483647),g.setUint32(e+4,2147483647)),9;throw Error("Number too small -0x"+(-a).toString(16).substr(1));}if("undefined"===k){if(d)return 0;g.setUint8(e,212);g.setUint8(e+1,0);g.setUint8(e+2,0);return 3}if(null===a){if(d)return 0;g.setUint8(e,192);return 1}if("boolean"===k)return g.setUint8(e,a?195:194),1;if("function"===typeof a.toJSON)return n(a.toJSON(),g,e,d);if("object"===k){k=0;var m=Array.isArray(a);if(m)p=a.length;else{var l=c(a,d);p=l.length}16>p?(g.setUint8(e,p|(m?144:128)), +k=1):65536>p?(g.setUint8(e,m?220:222),g.setUint16(e+1,p),k=3):4294967296>p&&(g.setUint8(e,m?221:223),g.setUint32(e+1,p),k=5);if(m)for(m=0;mb)return 1+b;if(256>b)return 2+b;if(65536>b)return 3+b;if(4294967296>b)return 5+b}if(a instanceof ArrayBuffer){b=a.byteLength;if(256>b)return 2+ b;if(65536>b)return 3+b;if(4294967296>b)return 5+b}if("number"===k){if(Math.floor(a)!==a)return 9;if(0<=a){if(128>a)return 1;if(256>a)return 2;if(65536>a)return 3;if(4294967296>a)return 5;if(1.8446744073709552E19>a)return 9;throw Error("Number too big 0x"+a.toString(16));}if(-32<=a)return 1;if(-128<=a)return 2;if(-32768<=a)return 3;if(-2147483648<=a)return 5;if(-9223372036854775808<=a)return 9;throw Error("Number too small -0x"+a.toString(16).substr(1));}if("boolean"===k)return 1;if(null===a)return g? -0:1;if(void 0===a)return g?0:3;if("function"===typeof a.toJSON)return e(a.toJSON(),g);if("object"===k){k=0;if(Array.isArray(a)){b=a.length;for(var d=0;db)return 1+k;if(65536>b)return 3+k;if(4294967296>b)return 5+k;throw Error("Array or object too long 0x"+b.toString(16));}if("function"===k)return 0;throw Error("Unknown type "+k);}var n={inspect:function(a){if(void 0===a)return"undefined";if(a instanceof -ArrayBuffer){var g="ArrayBuffer";var e=new DataView(a)}else a instanceof DataView&&(g="DataView",e=a);if(!e)return JSON.stringify(a);for(var c=[],b=0;b"}};n.utf8Write=b;n.utf8Read=d;n.utf8ByteCount=f;n.encode=function(a,g){var c=e(a,g);if(0!=c){c=new ArrayBuffer(c);var b=new DataView(c);q(a,b,0,g);return c}};n.decode=function(e){var g=new DataView(e);g=new a(g); -var c=g.parse();if(g.offset!==e.byteLength)throw Error(e.byteLength-g.offset+" trailing bytes");return c};var m=1/4294967296;a.prototype.map=function(a){for(var g={},e=0;eb)return 1+k;if(65536>b)return 3+k;if(4294967296>b)return 5+k;throw Error("Array or object too long 0x"+b.toString(16));}if("function"===k)return 0;throw Error("Unknown type "+k);}var m={inspect:function(a){if(void 0===a)return"undefined";if(a instanceof +ArrayBuffer){var g="ArrayBuffer";var e=new DataView(a)}else a instanceof DataView&&(g="DataView",e=a);if(!e)return JSON.stringify(a);for(var c=[],k=0;k"}};m.utf8Write=b;m.utf8Read=d;m.utf8ByteCount=f;m.encode=function(a,g){var c=e(a,g);if(0!=c){c=new ArrayBuffer(c);var k=new DataView(c);n(a,k,0,g);return c}};m.decode=function(e){var g=new DataView(e);g=new a(g); +var c=g.parse();if(g.offset!==e.byteLength)throw Error(e.byteLength-g.offset+" trailing bytes");return c};var t=1/4294967296;a.prototype.map=function(a){for(var g={},e=0;e>>2]>>>24-q%4*8&255;return e}throw Error("BufferUtils.toArrayBuffer expected a buffer");};f.toWordArray=function(c){return b(c)?c:a.create(c)};f.base64Encode=function(a){if(d(a)){var c="";a=new Uint8Array(a);var e=a.byteLength,f=e%3;e-=f;for(var g,q,l,h,G=0;G> -18,q=(h&258048)>>12,l=(h&4032)>>6,h&=63,c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[g]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[q]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[l]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[h];1==f?(h=a[e],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&252)>>2]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&3)<<4]+"=="): -2==f&&(h=a[e]<<8|a[e+1],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&64512)>>10]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&1008)>>4]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&15)<<2]+"=");return c}if(b(a))return D.enc.Base64.stringify(a)};f.base64Decode=function(a){if(c&&q){a=q(a);for(var e=a.length,b=new Uint8Array(e),d=0;d>>2]>>>24-n%4*8&255;return e}throw Error("BufferUtils.toArrayBuffer expected a buffer");};f.toWordArray=function(c){return b(c)?c:a.create(c)};f.base64Encode=function(a){if(d(a)){var c="";a=new Uint8Array(a);var e=a.byteLength,f=e%3;e-=f;for(var g,n,l,h,G=0;G> +18,n=(h&258048)>>12,l=(h&4032)>>6,h&=63,c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[g]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[n]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[l]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[h];1==f?(h=a[e],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&252)>>2]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&3)<<4]+"=="): +2==f&&(h=a[e]<<8|a[e+1],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&64512)>>10]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&1008)>>4]+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(h&15)<<2]+"=");return c}if(b(a))return F.enc.Base64.stringify(a)};f.base64Decode=function(a){if(c&&n){a=n(a);for(var e=a.length,b=new Uint8Array(e),d=0;d=c}function a(a){var c=a.connection;return(c=c&&c.connectionManager.host)?[c].concat(r.getFallbackHosts(a.options)):r.getHosts(a.options)}var c=Date.now||function(){return(new Date).getTime()};d._getHosts=a;d.methods=["get","delete","post","put","patch"];d.methodsWithoutBody= -["get","delete"];d.methodsWithBody=h.arrSubtract(d.methods,d.methodsWithoutBody);h.arrForEach(d.methodsWithoutBody,function(a){d[a]=function(c,b,f,k,g){d["do"](a,c,b,f,null,k,g)};d[a+"Uri"]=function(c,b,f,k,g){d.doUri(a,c,b,f,null,k,g)}});h.arrForEach(d.methodsWithBody,function(a){d[a]=function(c,b,f,k,g,q){d["do"](a,c,b,f,k,g,q)};d[a+"Uri"]=function(c,b,f,k,g,q){d.doUri(a,c,b,f,k,g,q)}});d["do"]=function(q,e,n,m,k,g,u){u=u||b;var l="function"==typeof n?n:function(a){return e.baseUri(a)+n},h=arguments, -G=e._currentFallback;if(G){if(G.validUntil>c()){d.Request(q,e,l(G.host),m,g,k,function(a){a&&f(a)?(e._currentFallback=null,d["do"].apply(d,h)):u.apply(null,arguments)});return}e._currentFallback=null}G=a(e);if(1==G.length)d.doUri(q,e,l(G[0]),m,k,g,u);else{var p=function(a,b){var n=a.shift();d.doUri(q,e,l(n),m,k,g,function(g){g&&f(g)&&a.length?p(a,!0):(b&&(e._currentFallback={host:n,validUntil:c()+e.options.timeouts.fallbackRetryTimeout}),u.apply(null,arguments))})};p(G)}};d.doUri=function(a,c,b,f, -k,g,u){d.Request(a,c,b,f,g,k,u)};d.supportsAuthHeaders=!1;d.supportsLinkHeaders=!1;return d}(),ha=function(){function b(){this.buffer=[]}function d(a){this._input=a;this._index=-1;this._buffer=[]}function f(a){this._input=a;this._index=-1;this._buffer=[]}b.prototype.append=function(a){this.buffer.push(a);return this};b.prototype.toString=function(){return this.buffer.join("")};var a={codex:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(c){var f=new b,e=a.codex; -for(c=new d(c);c.moveNext();){var n=c.current;c.moveNext();var m=c.current;c.moveNext();var k=c.current,g=n>>2;n=(n&3)<<4|m>>4;var u=(m&15)<<2|k>>6,l=k&63;isNaN(m)?u=l=64:isNaN(k)&&(l=64);f.append(e.charAt(g)+e.charAt(n)+e.charAt(u)+e.charAt(l))}return f.toString()},decode:function(a){var c=new b;for(a=new f(a);a.moveNext();){var e=a.current;if(128>e)c.append(String.fromCharCode(e));else if(191e){a.moveNext();var d=a.current;c.append(String.fromCharCode((e&31)<<6|d&63))}else a.moveNext(), +["get","delete"];d.methodsWithBody=h.arrSubtract(d.methods,d.methodsWithoutBody);h.arrForEach(d.methodsWithoutBody,function(a){d[a]=function(c,b,f,k,g){d["do"](a,c,b,f,null,k,g)};d[a+"Uri"]=function(c,b,f,k,g){d.doUri(a,c,b,f,null,k,g)}});h.arrForEach(d.methodsWithBody,function(a){d[a]=function(c,b,f,k,g,p){d["do"](a,c,b,f,k,g,p)};d[a+"Uri"]=function(c,b,f,k,g,p){d.doUri(a,c,b,f,k,g,p)}});d["do"]=function(n,e,m,t,k,g,p){p=p||b;var l="function"==typeof m?m:function(a){return e.baseUri(a)+m},h=arguments, +G=e._currentFallback;if(G){if(G.validUntil>c()){d.Request(n,e,l(G.host),t,g,k,function(a){a&&f(a)?(e._currentFallback=null,d["do"].apply(d,h)):p.apply(null,arguments)});return}e._currentFallback=null}G=a(e);if(1==G.length)d.doUri(n,e,l(G[0]),t,k,g,p);else{var aa=function(a,b){var m=a.shift();d.doUri(n,e,l(m),t,k,g,function(g){g&&f(g)&&a.length?aa(a,!0):(b&&(e._currentFallback={host:m,validUntil:c()+e.options.timeouts.fallbackRetryTimeout}),p.apply(null,arguments))})};aa(G)}};d.doUri=function(a,c, +b,f,k,g,p){d.Request(a,c,b,f,g,k,p)};d.supportsAuthHeaders=!1;d.supportsLinkHeaders=!1;return d}(),ja=function(){function b(){this.buffer=[]}function d(a){this._input=a;this._index=-1;this._buffer=[]}function f(a){this._input=a;this._index=-1;this._buffer=[]}b.prototype.append=function(a){this.buffer.push(a);return this};b.prototype.toString=function(){return this.buffer.join("")};var a={codex:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(c){var f=new b,e=a.codex; +for(c=new d(c);c.moveNext();){var m=c.current;c.moveNext();var t=c.current;c.moveNext();var k=c.current,g=m>>2;m=(m&3)<<4|t>>4;var p=(t&15)<<2|k>>6,l=k&63;isNaN(t)?p=l=64:isNaN(k)&&(l=64);f.append(e.charAt(g)+e.charAt(m)+e.charAt(p)+e.charAt(l))}return f.toString()},decode:function(a){var c=new b;for(a=new f(a);a.moveNext();){var e=a.current;if(128>e)c.append(String.fromCharCode(e));else if(191e){a.moveNext();var d=a.current;c.append(String.fromCharCode((e&31)<<6|d&63))}else a.moveNext(), d=a.current,a.moveNext(),c.append(String.fromCharCode((e&15)<<12|(d&63)<<6|a.current&63))}return c.toString()}};d.prototype={current:Number.NaN,moveNext:function(){if(0=this._input.length-1)return this.current=Number.NaN,!1;var a=this._input.charCodeAt(++this._index);13==a&&10==this._input.charCodeAt(this._index+1)&&(a=10,this._index+=2);128>a?this.current=a:(127a?this.current=a>>6|192:(this.current=a>>12|224, this._buffer.push(a>>6&63|128)),this._buffer.push(a&63|128));return!0}};f.prototype={current:64,moveNext:function(){if(0=this._input.length-1)return this.current=64,!1;var c=a.codex.indexOf(this._input.charAt(++this._index)),b=a.codex.indexOf(this._input.charAt(++this._index)),e=a.codex.indexOf(this._input.charAt(++this._index)),d=a.codex.indexOf(this._input.charAt(++this._index)),f=(e&3)<<6|d;this.current=c<<2|b>>4;64!= e&&this._buffer.push((b&15)<<4|e>>2);64!=d&&this._buffer.push(f);return!0}};return a}();r.ENVIRONMENT="";r.REST_HOST="rest.ably.io";r.REALTIME_HOST="realtime.ably.io";r.FALLBACK_HOSTS=["A.ably-realtime.com","B.ably-realtime.com","C.ably-realtime.com","D.ably-realtime.com","E.ably-realtime.com"];r.PORT=80;r.TLS_PORT=443;r.TIMEOUTS={disconnectedRetryTimeout:15E3,suspendedRetryTimeout:3E4,httpRequestTimeout:15E3,channelRetryTimeout:15E3,fallbackRetryTimeout:6E5,connectionStateTtl:12E4,realtimeRequestTimeout:1E4, -recvTimeout:9E4,preferenceConnectTimeout:6E3,parallelUpgradeDelay:6E3};r.httpMaxRetryCount=3;r.maxMessageSize=65536;r.version="1.1.7";r.libstring=t.libver+r.version;r.apiVersion="1.1";r.getHost=function(b,d,f){return d=f?d==b.restHost&&b.realtimeHost||d||b.realtimeHost:d||b.restHost};r.getPort=function(b,d){return d||b.tls?b.tlsPort:b.port};r.getHttpScheme=function(b){return b.tls?"https://":"http://"};r.getFallbackHosts=function(b){var d=b.fallbackHosts;b="undefined"!==typeof b.httpMaxRetryCount? +recvTimeout:9E4,preferenceConnectTimeout:6E3,parallelUpgradeDelay:6E3};r.httpMaxRetryCount=3;r.maxMessageSize=65536;r.version="1.1.8";r.libstring=u.libver+r.version;r.apiVersion="1.1";r.getHost=function(b,d,f){return d=f?d==b.restHost&&b.realtimeHost||d||b.realtimeHost:d||b.restHost};r.getPort=function(b,d){return d||b.tls?b.tlsPort:b.port};r.getHttpScheme=function(b){return b.tls?"https://":"http://"};r.getFallbackHosts=function(b){var d=b.fallbackHosts;b="undefined"!==typeof b.httpMaxRetryCount? b.httpMaxRetryCount:r.httpMaxRetryCount;return d?h.arrChooseN(d,b):[]};r.getHosts=function(b){return[b.restHost].concat(r.getFallbackHosts(b))};r.objectifyOptions=function(b){return"string"==typeof b?-1==b.indexOf(":")?{token:b}:{key:b}:b};r.normaliseOptions=function(b){b.host&&(d.deprecated("host","restHost"),b.restHost=b.host);b.wsHost&&(d.deprecated("wsHost","realtimeHost"),b.realtimeHost=b.wsHost);b.queueEvents&&(d.deprecated("queueEvents","queueMessages"),b.queueMessages=b.queueEvents);!0=== b.recover&&(d.deprecated("{recover: true}","{recover: function(lastConnectionDetails, cb) { cb(true); }}"),b.recover=function(a,b){b(!0)});"function"===typeof b.recover&&!0===b.closeOnUnload&&(d.logAction(d.LOG_ERROR,"Defaults.normaliseOptions","closeOnUnload was true and a session recovery function was set - these are mutually exclusive, so unsetting the latter"),b.recover=null);"closeOnUnload"in b||(b.closeOnUnload=!b.recover);b.transports&&h.arrIn(b.transports,"xhr")&&(d.deprecated('transports: ["xhr"]', 'transports: ["xhr_streaming"]'),h.arrDeleteValue(b.transports,"xhr"),b.transports.push("xhr_streaming"));"queueMessages"in b||(b.queueMessages=!0);var l=!1;if(b.restHost)b.realtimeHost=b.realtimeHost||b.restHost;else{var f=b.environment&&String(b.environment).toLowerCase()||r.ENVIRONMENT;l=!f||"production"===f;b.restHost=l?r.REST_HOST:f+"-"+r.REST_HOST;b.realtimeHost=l?r.REALTIME_HOST:f+"-"+r.REALTIME_HOST}b.fallbackHosts=l||b.fallbackHostsUseDefault?r.FALLBACK_HOSTS:b.fallbackHosts;h.arrForEach((b.fallbackHosts|| -[]).concat(b.restHost,b.realtimeHost),ea);b.port=b.port||r.PORT;b.tlsPort=b.tlsPort||r.TLS_PORT;b.maxMessageSize=b.maxMessageSize||r.maxMessageSize;"tls"in b||(b.tls=!0);b.timeouts={};for(var a in r.TIMEOUTS)b.timeouts[a]=b[a]||r.TIMEOUTS[a];b.useBinaryProtocol="useBinaryProtocol"in b?t.supportsBinary&&b.useBinaryProtocol:t.preferBinary;b.clientId&&((b.headers=b.headers||{})["X-Ably-ClientId"]=b.clientId);"idempotentRestPublishing"in b||(b.idempotentRestPublishing=!1);b.promises&&!t.Promise&&(d.logAction(d.LOG_ERROR, -"Defaults.normaliseOptions","{promises: true} was specified, but no Promise constructor found; disabling promises"),b.promises=!1);return b};var y=function(){function b(){this.any=[];this.events={};this.anyOnce=[];this.eventsOnce={}}function l(a,c,b){try{c.apply(a,b)}catch(e){d.logAction(d.LOG_ERROR,"EventEmitter.emit()","Unexpected listener exception: "+e+"; stack = "+(e&&e.stack))}}function f(a,c,b){var e,d,m;for(m=0;m=d?null:c.slice(0,d).join("/"),b.data=f}}};b.fromResponseBody=function(f,a,c){c&&(f= -h.decodeBody(f,c));for(c=0;c=d?null:c.slice(0,d).join("/"),b.data=f}}};b.fromResponseBody=function(f,a,c){c&&(f= +h.decodeBody(f,c));for(c=0;ch.arrIndexOf(m,c.shortName)}function f(a,c,b,d){this.options=a;this.host=c;this.mode=b;this.connectionKey=d;this.format=a.useBinaryProtocol?"msgpack":"json";this.timeSerial=this.connectionSerial=void 0}function a(c,b){y.call(this);this.realtime=c;this.options=b;var g=b.timeouts,e=this;this.states={initialized:{state:"initialized",terminal:!1,queueEvents:!0,sendEvents:!1,failState:"disconnected"}, -connecting:{state:"connecting",terminal:!1,queueEvents:!0,sendEvents:!1,retryDelay:g.preferenceConnectTimeout+g.realtimeRequestTimeout,failState:"disconnected"},connected:{state:"connected",terminal:!1,queueEvents:!1,sendEvents:!0,failState:"disconnected"},synchronizing:{state:"connected",terminal:!1,queueEvents:!0,sendEvents:!1,forceQueueEvents:!0,failState:"disconnected"},disconnected:{state:"disconnected",terminal:!1,queueEvents:!0,sendEvents:!1,retryDelay:g.disconnectedRetryTimeout,failState:"disconnected"}, -suspended:{state:"suspended",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:g.suspendedRetryTimeout,failState:"suspended"},closing:{state:"closing",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:g.realtimeRequestTimeout,failState:"closed"},closed:{state:"closed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"closed"},failed:{state:"failed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"failed"}};this.state=this.states.initialized;this.errorReason=null;this.queuedMessages=new ba; -this.msgSerial=0;this.connectionSerial=this.timeSerial=this.connectionKey=this.connectionId=this.connectionDetails=void 0;this.connectionStateTtl=g.connectionStateTtl;this.maxIdleInterval=null;this.transports=h.intersect(b.transports||r.defaultTransports,a.supportedTransports);this.baseTransport=h.intersect(r.baseTransportOrder,this.transports)[0];this.upgradeTransports=h.intersect(this.transports,r.upgradeTransports);this.transportPreference=null;this.httpHosts=r.getHosts(b);this.activeProtocol= -null;this.proposedTransports=[];this.pendingTransports=[];this.mostRecentMsgId=this.lastActivity=this.lastAutoReconnectAttempt=this.host=null;this.forceFallbackHost=!1;d.logAction(d.LOG_MINOR,"Realtime.ConnectionManager()","started");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()","requested transports = ["+(b.transports||r.defaultTransports)+"]");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()","available transports = ["+this.transports+"]");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()", -"http hosts = ["+this.httpHosts+"]");if(!this.transports.length)throw d.logAction(d.LOG_ERROR,"realtime.ConnectionManager()","no requested transports available"),Error("no requested transports available");if(g=t.addEventListener)q&&"function"===typeof b.recover&&g("beforeunload",this.persistConnection.bind(this)),!0===b.closeOnUnload&&g("beforeunload",function(){d.logAction(d.LOG_MAJOR,"Realtime.ConnectionManager()","beforeunload event has triggered the connection to close as closeOnUnload is true"); -e.requestState({state:"closing"})}),g("online",function(){if(e.state==e.states.disconnected||e.state==e.states.suspended)d.logAction(d.LOG_MINOR,"ConnectionManager caught browser \u2018online\u2019 event","reattempting connection"),e.requestState({state:"connecting"})}),g("offline",function(){e.state==e.states.connected&&(d.logAction(d.LOG_MINOR,"ConnectionManager caught browser \u2018offline\u2019 event","disconnecting active transport"),e.disconnectAllTransports())})}var c=!("undefined"===typeof I|| -!I.get),q=!("undefined"===typeof I||!I.getSession),e=w.Action,n=ca.PendingMessage,m=r.transportPreferenceOrder,k=m[m.length-1];f.prototype.getConnectParams=function(a){a=a?h.copy(a):{};var c=this.options;switch(this.mode){case "upgrade":a.upgrade=this.connectionKey;break;case "resume":a.resume=this.connectionKey;void 0!==this.timeSerial?a.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(a.connectionSerial=this.connectionSerial);break;case "recover":var b=c.recover.split(":");b&&(a.recover= -b[0],b=b[1],isNaN(b)?a.timeSerial=b:a.connectionSerial=b)}void 0!==c.clientId&&(a.clientId=c.clientId);!1===c.echoMessages&&(a.echo="false");void 0!==this.format&&(a.format=this.format);void 0!==this.stream&&(a.stream=this.stream);void 0!==this.heartbeats&&(a.heartbeats=this.heartbeats);a.v=r.apiVersion;a.lib=r.libstring;void 0!==c.transportParams&&h.mixin(a,c.transportParams);return a};f.prototype.toString=function(){var a="[mode="+this.mode;this.host&&(a+=",host="+this.host);this.connectionKey&& -(a+=",connectionKey="+this.connectionKey);void 0!==this.connectionSerial&&(a+=",connectionSerial="+this.connectionSerial);this.timeSerial&&(a+=",timeSerial="+this.timeSerial);this.format&&(a+=",format="+this.format);return a+"]"};h.inherits(a,y);a.supportedTransports={};a.prototype.createTransportParams=function(a,c){var b=new f(this.options,a,c,this.connectionKey);this.timeSerial?b.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(b.connectionSerial=this.connectionSerial);return b};a.prototype.getTransportParams= -function(a){var c=this;(function(a){if(c.connectionKey)a("resume");else if("string"===typeof c.options.recover)a("recover");else{var b=c.options.recover,g=q&&I.getSession("ably-connection-recovery");g&&"function"===typeof b?(d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Calling clientOptions-provided recover function with last session data"),b(g,function(b){b?(c.options.recover=g.recoveryKey,a("recover")):a("clean")})):a("clean")}})(function(b){var g=c.createTransportParams(null, -b);"recover"===b?(d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport recovery mode = recover; recoveryKey = "+c.options.recover),(b=c.options.recover.split(":"))&&b[2]&&(c.msgSerial=b[2])):d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport params = "+g.toString());a(g)})};a.prototype.tryATransport=function(c,b,e){var g=this;d.logAction(d.LOG_MICRO,"ConnectionManager.tryATransport()","trying "+b);a.supportedTransports[b].tryConnect(this,this.realtime.auth, +c==l.PRESENCE};return b}(),M=function(){function b(){}function l(a,c){return h.arrIndexOf(t,a.shortName)>h.arrIndexOf(t,c.shortName)}function f(a,c,b,d){this.options=a;this.host=c;this.mode=b;this.connectionKey=d;this.format=a.useBinaryProtocol?"msgpack":"json";this.timeSerial=this.connectionSerial=void 0}function a(g,c){x.call(this);this.realtime=g;this.options=c;var b=c.timeouts,e=this;this.states={initialized:{state:"initialized",terminal:!1,queueEvents:!0,sendEvents:!1,failState:"disconnected"}, +connecting:{state:"connecting",terminal:!1,queueEvents:!0,sendEvents:!1,retryDelay:b.preferenceConnectTimeout+b.realtimeRequestTimeout,failState:"disconnected"},connected:{state:"connected",terminal:!1,queueEvents:!1,sendEvents:!0,failState:"disconnected"},synchronizing:{state:"connected",terminal:!1,queueEvents:!0,sendEvents:!1,forceQueueEvents:!0,failState:"disconnected"},disconnected:{state:"disconnected",terminal:!1,queueEvents:!0,sendEvents:!1,retryDelay:b.disconnectedRetryTimeout,failState:"disconnected"}, +suspended:{state:"suspended",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:b.suspendedRetryTimeout,failState:"suspended"},closing:{state:"closing",terminal:!1,queueEvents:!1,sendEvents:!1,retryDelay:b.realtimeRequestTimeout,failState:"closed"},closed:{state:"closed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"closed"},failed:{state:"failed",terminal:!0,queueEvents:!1,sendEvents:!1,failState:"failed"}};this.state=this.states.initialized;this.errorReason=null;this.queuedMessages=new da; +this.msgSerial=0;this.connectionSerial=this.timeSerial=this.connectionKey=this.connectionId=this.connectionDetails=void 0;this.connectionStateTtl=b.connectionStateTtl;this.maxIdleInterval=null;this.transports=h.intersect(c.transports||r.defaultTransports,a.supportedTransports);this.baseTransport=h.intersect(r.baseTransportOrder,this.transports)[0];this.upgradeTransports=h.intersect(this.transports,r.upgradeTransports);this.transportPreference=null;this.httpHosts=r.getHosts(c);this.activeProtocol= +null;this.proposedTransports=[];this.pendingTransports=[];this.mostRecentMsgId=this.lastActivity=this.lastAutoReconnectAttempt=this.host=null;this.forceFallbackHost=!1;this.connectCounter=0;d.logAction(d.LOG_MINOR,"Realtime.ConnectionManager()","started");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()","requested transports = ["+(c.transports||r.defaultTransports)+"]");d.logAction(d.LOG_MICRO,"Realtime.ConnectionManager()","available transports = ["+this.transports+"]");d.logAction(d.LOG_MICRO, +"Realtime.ConnectionManager()","http hosts = ["+this.httpHosts+"]");if(!this.transports.length)throw d.logAction(d.LOG_ERROR,"realtime.ConnectionManager()","no requested transports available"),Error("no requested transports available");if(b=u.addEventListener)n&&"function"===typeof c.recover&&b("beforeunload",this.persistConnection.bind(this)),!0===c.closeOnUnload&&b("beforeunload",function(){d.logAction(d.LOG_MAJOR,"Realtime.ConnectionManager()","beforeunload event has triggered the connection to close as closeOnUnload is true"); +e.requestState({state:"closing"})}),b("online",function(){if(e.state==e.states.disconnected||e.state==e.states.suspended)d.logAction(d.LOG_MINOR,"ConnectionManager caught browser \u2018online\u2019 event","reattempting connection"),e.requestState({state:"connecting"})}),b("offline",function(){e.state==e.states.connected&&(d.logAction(d.LOG_MINOR,"ConnectionManager caught browser \u2018offline\u2019 event","disconnecting active transport"),e.disconnectAllTransports())})}var c=!("undefined"===typeof I|| +!I.get),n=!("undefined"===typeof I||!I.getSession),e=w.Action,m=ea.PendingMessage,t=r.transportPreferenceOrder,k=t[t.length-1];f.prototype.getConnectParams=function(a){a=a?h.copy(a):{};var c=this.options;switch(this.mode){case "upgrade":a.upgrade=this.connectionKey;break;case "resume":a.resume=this.connectionKey;void 0!==this.timeSerial?a.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(a.connectionSerial=this.connectionSerial);break;case "recover":var g=c.recover.split(":");g&&(a.recover= +g[0],g=g[1],isNaN(g)?a.timeSerial=g:a.connectionSerial=g)}void 0!==c.clientId&&(a.clientId=c.clientId);!1===c.echoMessages&&(a.echo="false");void 0!==this.format&&(a.format=this.format);void 0!==this.stream&&(a.stream=this.stream);void 0!==this.heartbeats&&(a.heartbeats=this.heartbeats);a.v=r.apiVersion;a.lib=r.libstring;void 0!==c.transportParams&&h.mixin(a,c.transportParams);return a};f.prototype.toString=function(){var a="[mode="+this.mode;this.host&&(a+=",host="+this.host);this.connectionKey&& +(a+=",connectionKey="+this.connectionKey);void 0!==this.connectionSerial&&(a+=",connectionSerial="+this.connectionSerial);this.timeSerial&&(a+=",timeSerial="+this.timeSerial);this.format&&(a+=",format="+this.format);return a+"]"};h.inherits(a,x);a.supportedTransports={};a.prototype.createTransportParams=function(a,c){var g=new f(this.options,a,c,this.connectionKey);this.timeSerial?g.timeSerial=this.timeSerial:void 0!==this.connectionSerial&&(g.connectionSerial=this.connectionSerial);return g};a.prototype.getTransportParams= +function(a){var c=this;(function(a){if(c.connectionKey)a("resume");else if("string"===typeof c.options.recover)a("recover");else{var g=c.options.recover,b=n&&I.getSession("ably-connection-recovery");b&&"function"===typeof g?(d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Calling clientOptions-provided recover function with last session data"),g(b,function(g){g?(c.options.recover=b.recoveryKey,a("recover")):a("clean")})):a("clean")}})(function(g){var b=c.createTransportParams(null, +g);"recover"===g?(d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport recovery mode = recover; recoveryKey = "+c.options.recover),(g=c.options.recover.split(":"))&&g[2]&&(c.msgSerial=g[2])):d.logAction(d.LOG_MINOR,"ConnectionManager.getTransportParams()","Transport params = "+b.toString());a(b)})};a.prototype.tryATransport=function(c,b,e){var g=this;d.logAction(d.LOG_MICRO,"ConnectionManager.tryATransport()","trying "+b);a.supportedTransports[b].tryConnect(this,this.realtime.auth, c,function(a,f){var k=g.state;k==g.states.closing||k==g.states.closed||k==g.states.failed?(f&&(d.logAction(d.LOG_MINOR,"ConnectionManager.tryATransport()","connection "+k.state+" while we were attempting the transport; closing "+f),f.close()),e(!0)):a?(d.logAction(d.LOG_MINOR,"ConnectionManager.tryATransport()","transport "+b+" "+a.event+", err: "+a.error.toString()),L.isTokenErr(a.error)?g.realtime.auth._forceNewToken(null,null,function(a){a?g.actOnErrorFromAuthorize(a):g.tryATransport(c,b,e)}): -"failed"===a.event?(g.notifyState({state:"failed",error:a.error}),e(!0)):"disconnected"===a.event&&e(!1)):(d.logAction(d.LOG_MICRO,"ConnectionManager.tryATransport()","viable transport "+b+"; setting pending"),g.setTransportPending(f,c),e(null,f))})};a.prototype.setTransportPending=function(a,c){var b=c.mode;d.logAction(d.LOG_MINOR,"ConnectionManager.setTransportPending()","transport = "+a+"; mode = "+b);h.arrDeleteValue(this.proposedTransports,a);this.pendingTransports.push(a);var g=this;a.once("connected", -function(d,e,f,m){"upgrade"==b&&g.activeProtocol?a.shortName!==k&&h.arrIn(g.getUpgradePossibilities(),k)?setTimeout(function(){g.scheduleTransportActivation(d,a,e,f,m)},g.options.timeouts.parallelUpgradeDelay):g.scheduleTransportActivation(d,a,e,f,m):(g.activateTransport(d,a,e,f,m),h.nextTick(function(){g.connectImpl(c)}));"recover"===b&&g.options.recover&&(g.options.recover=null,g.unpersistConnection())});a.on(["disconnected","closed","failed"],function(c){g.deactivateTransport(a,this.event,c)}); -this.emit("transport.pending",a)};a.prototype.scheduleTransportActivation=function(a,c,b,e,f){function g(){c.disconnect();h.arrDeleteValue(k.pendingTransports,c)}var k=this,m=this.activeProtocol&&this.activeProtocol.getTransport();this.state!==this.states.connected&&this.state!==this.states.connecting?(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+this.state.state+(this.state===this.states.synchronizing?", but with an upgrade already in progress": -"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName),g()):m&&!l(c,m)?(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+" is no better than current active transport "+m.shortName+" - abandoning upgrade"),g()):(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Scheduling transport upgrade; transport = "+c),this.realtime.channels.onceNopending(function(m){if(m)d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()", -"Unable to activate transport; transport = "+c+"; err = "+m);else if(c.isConnected){if(k.state===k.states.connected){d.logAction(d.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()","Currently connected, so temporarily pausing events until the upgrade is complete");k.state=k.states.synchronizing;var n=k.activeProtocol}else if(k.state!==k.states.connecting){d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+k.state.state+(k.state===k.states.synchronizing? -", but with an upgrade already in progress":"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName);g();return}var u=(m=b!==k.connectionId)?f:k;m&&d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Upgrade resulted in new connectionId; resetting library connection position from "+(k.timeSerial||k.connectionSerial)+" to "+(u.timeSerial||u.connectionSerial)+"; upgrade error was "+a);d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Syncing transport; transport = "+ -c);k.sync(c,u,function(b,g,f){if(b)k.state===k.states.synchronizing&&(d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Unexpected error attempting to sync transport; transport = "+c+"; err = "+b),k.disconnectAllTransports());else if(b=function(){d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Activating transport; transport = "+c);k.activateTransport(a,c,g,e,f);k.state===k.states.synchronizing?(d.logAction(d.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()", -"Pre-upgrade protocol idle, sending queued messages on upgraded transport; transport = "+c),k.state=k.states.connected):d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Pre-upgrade protocol idle, but state is now "+k.state.state+", so leaving unchanged");k.state.sendEvents&&k.sendQueuedMessages()},n)n.onceIdle(b);else b()})}else d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+"is no longer connected; abandoning upgrade"), +"failed"===a.event?(g.notifyState({state:"failed",error:a.error}),e(!0)):"disconnected"===a.event&&e(!1)):(d.logAction(d.LOG_MICRO,"ConnectionManager.tryATransport()","viable transport "+b+"; setting pending"),g.setTransportPending(f,c),e(null,f))})};a.prototype.setTransportPending=function(a,c){var g=c.mode;d.logAction(d.LOG_MINOR,"ConnectionManager.setTransportPending()","transport = "+a+"; mode = "+g);h.arrDeleteValue(this.proposedTransports,a);this.pendingTransports.push(a);var b=this;a.once("connected", +function(d,e,f,p){"upgrade"==g&&b.activeProtocol?a.shortName!==k&&h.arrIn(b.getUpgradePossibilities(),k)?setTimeout(function(){b.scheduleTransportActivation(d,a,e,f,p)},b.options.timeouts.parallelUpgradeDelay):b.scheduleTransportActivation(d,a,e,f,p):(b.activateTransport(d,a,e,f,p),h.nextTick(function(){b.connectImpl(c)}));"recover"===g&&b.options.recover&&(b.options.recover=null,b.unpersistConnection())});a.on(["disconnected","closed","failed"],function(c){b.deactivateTransport(a,this.event,c)}); +this.emit("transport.pending",a)};a.prototype.scheduleTransportActivation=function(a,c,b,e,f){function g(){c.disconnect();h.arrDeleteValue(k.pendingTransports,c)}var k=this,p=this.activeProtocol&&this.activeProtocol.getTransport();this.state!==this.states.connected&&this.state!==this.states.connecting?(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+this.state.state+(this.state===this.states.synchronizing?", but with an upgrade already in progress": +"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName),g()):p&&!l(c,p)?(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+" is no better than current active transport "+p.shortName+" - abandoning upgrade"),g()):(d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Scheduling transport upgrade; transport = "+c),this.realtime.channels.onceNopending(function(p){if(p)d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()", +"Unable to activate transport; transport = "+c+"; err = "+p);else if(c.isConnected){if(k.state===k.states.connected){d.logAction(d.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()","Currently connected, so temporarily pausing events until the upgrade is complete");k.state=k.states.synchronizing;var m=k.activeProtocol}else if(k.state!==k.states.connecting){d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Current connection state ("+k.state.state+(k.state===k.states.synchronizing? +", but with an upgrade already in progress":"")+") is not valid to upgrade in; abandoning upgrade to "+c.shortName);g();return}var n=(p=b!==k.connectionId)?f:k;p&&d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Upgrade resulted in new connectionId; resetting library connection position from "+(k.timeSerial||k.connectionSerial)+" to "+(n.timeSerial||n.connectionSerial)+"; upgrade error was "+a);d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Syncing transport; transport = "+ +c);k.sync(c,n,function(g,b,f){if(g)k.state===k.states.synchronizing&&(d.logAction(d.LOG_ERROR,"ConnectionManager.scheduleTransportActivation()","Unexpected error attempting to sync transport; transport = "+c+"; err = "+g),k.disconnectAllTransports());else if(g=function(){d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Activating transport; transport = "+c);k.activateTransport(a,c,b,e,f);k.state===k.states.synchronizing?(d.logAction(d.LOG_MICRO,"ConnectionManager.scheduleTransportActivation()", +"Pre-upgrade protocol idle, sending queued messages on upgraded transport; transport = "+c),k.state=k.states.connected):d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Pre-upgrade protocol idle, but state is now "+k.state.state+", so leaving unchanged");k.state.sendEvents&&k.sendQueuedMessages()},m)m.onceIdle(g);else g()})}else d.logAction(d.LOG_MINOR,"ConnectionManager.scheduleTransportActivation()","Proposed transport "+c.shortName+"is no longer connected; abandoning upgrade"), g()}))};a.prototype.activateTransport=function(a,c,b,e,f){d.logAction(d.LOG_MINOR,"ConnectionManager.activateTransport()","transport = "+c);a&&d.logAction(d.LOG_ERROR,"ConnectionManager.activateTransport()","error = "+a);b&&d.logAction(d.LOG_MICRO,"ConnectionManager.activateTransport()","connectionId = "+b);e&&d.logAction(d.LOG_MICRO,"ConnectionManager.activateTransport()","connectionDetails = "+JSON.stringify(e));f&&d.logAction(d.LOG_MICRO,"ConnectionManager.activateTransport()","serial = "+(f.timeSerial|| f.connectionSerial));this.persistTransportPreference(c);var g=this.state,k=this.states.connected.state;d.logAction(d.LOG_MINOR,"ConnectionManager.activateTransport()","current state = "+g.state);if(g.state==this.states.closing.state||g.state==this.states.closed.state||g.state==this.states.failed.state)return d.logAction(d.LOG_MINOR,"ConnectionManager.activateTransport()","Disconnecting transport and abandoning"),c.disconnect(),!1;h.arrDeleteValue(this.pendingTransports,c);if(!c.isConnected)return d.logAction(d.LOG_MINOR, -"ConnectionManager.activateTransport()","Declining to activate transport "+c+" since it appears to no longer be connected"),!1;var m=this.activeProtocol;this.activeProtocol=new ca(c);this.host=c.params.host;var n=e.connectionKey;n&&this.connectionKey!=n&&this.setConnection(b,e,f,!0);this.onConnectionDetailsUpdate(e,c);var u=this;h.nextTick(function(){c.on("connected",function(a,b,g){u.onConnectionDetailsUpdate(g,c);u.emit("update",new Q(k,k,null,a))})});g.state===this.states.connected.state?a&&(this.errorReason= -this.realtime.connection.errorReason=a,this.emit("update",new Q(k,k,null,a))):(this.notifyState({state:"connected",error:a}),this.errorReason=this.realtime.connection.errorReason=a||null);this.emit("transport.active",c);m&&(0this.connectionStateTtl+this.maxIdleInterval&&(d.logAction(d.LOG_MINOR,"ConnectionManager.checkConnectionStateFreshness()", -"Last known activity from realtime was "+a+"ms ago; discarding connection state"),this.clearConnection(),this.states.connecting.failState="suspended",this.states.connecting.queueEvents=!1)}};a.prototype.persistConnection=function(){if(q){var a=this.realtime.connection.recoveryKey;a&&(a={recoveryKey:a,disconnectedAt:h.now(),location:window.location,clientId:this.realtime.auth.clientId},q&&I.setSession("ably-connection-recovery",a))}};a.prototype.unpersistConnection=function(){q&&I.removeSession("ably-connection-recovery")}; -a.prototype.getError=function(){return this.errorReason||this.getStateError()};a.prototype.getStateError=function(){return J[this.state.state]};a.prototype.activeState=function(){return this.state.queueEvents||this.state.sendEvents};a.prototype.enactStateChange=function(a){d.logAction("failed"===a.current?d.LOG_ERROR:d.LOG_MAJOR,"Connection state",a.current+(a.reason?"; reason: "+a.reason:""));d.logAction(d.LOG_MINOR,"ConnectionManager.enactStateChange","setting new state: "+a.current+"; reason = "+ -(a.reason&&a.reason.message));var c=this.state=this.states[a.current];a.reason&&(this.errorReason=a.reason,this.realtime.connection.errorReason=a.reason);(c.terminal||"suspended"===c.state)&&this.clearConnection();this.emit("connectionstate",a)};a.prototype.startTransitionTimer=function(a){d.logAction(d.LOG_MINOR,"ConnectionManager.startTransitionTimer()","transitionState: "+a.state);this.transitionTimer&&(d.logAction(d.LOG_MINOR,"ConnectionManager.startTransitionTimer()","clearing already-running timer"), -clearTimeout(this.transitionTimer));var c=this;this.transitionTimer=setTimeout(function(){c.transitionTimer&&(c.transitionTimer=null,d.logAction(d.LOG_MINOR,"ConnectionManager "+a.state+" timer expired","requesting new state: "+a.failState),c.notifyState({state:a.failState}))},a.retryDelay)};a.prototype.cancelTransitionTimer=function(){d.logAction(d.LOG_MINOR,"ConnectionManager.cancelTransitionTimer()","");this.transitionTimer&&(clearTimeout(this.transitionTimer),this.transitionTimer=null)};a.prototype.startSuspendTimer= -function(){var a=this;this.suspendTimer||(this.suspendTimer=setTimeout(function(){a.suspendTimer&&(a.suspendTimer=null,d.logAction(d.LOG_MINOR,"ConnectionManager suspend timer expired","requesting new state: suspended"),a.states.connecting.failState="suspended",a.states.connecting.queueEvents=!1,a.notifyState({state:"suspended"}))},this.connectionStateTtl))};a.prototype.checkSuspendTimer=function(a){"disconnected"!==a&&"suspended"!==a&&"connecting"!==a&&this.cancelSuspendTimer()};a.prototype.cancelSuspendTimer= -function(){this.states.connecting.failState="disconnected";this.states.connecting.queueEvents=!0;this.suspendTimer&&(clearTimeout(this.suspendTimer),this.suspendTimer=null)};a.prototype.startRetryTimer=function(a){var c=this;this.retryTimer=setTimeout(function(){d.logAction(d.LOG_MINOR,"ConnectionManager retry timer expired","retrying");c.retryTimer=null;c.requestState({state:"connecting"})},a)};a.prototype.cancelRetryTimer=function(){this.retryTimer&&(clearTimeout(this.retryTimer),this.retryTimer= -null)};a.prototype.notifyState=function(a){var c=a.state,b=this,g="disconnected"===c&&(this.state===this.states.connected||this.state===this.states.synchronizing||this.state===this.states.connecting&&a.error&&L.isTokenErr(a.error)&&!(this.errorReason&&L.isTokenErr(this.errorReason)));d.logAction(d.LOG_MINOR,"ConnectionManager.notifyState()","new state: "+c+(g?"; will retry connection immediately":""));if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(a.state), -!this.state.terminal)){var e=this.states[a.state];a=new Q(this.state.state,e.state,e.retryDelay,a.error||J[e.state]);if(g){var f=function(){b.state===b.states.disconnected&&(b.lastAutoReconnectAttempt=h.now(),b.requestState({state:"connecting"}))},k=this.lastAutoReconnectAttempt&&h.now()-this.lastAutoReconnectAttempt+1;k&&1E3>k?(d.logAction(d.LOG_MICRO,"ConnectionManager.notifyState()","Last reconnect attempt was only "+k+"ms ago, waiting another "+(1E3-k)+"ms before trying again"),setTimeout(f,1E3- -k)):h.nextTick(f)}else"disconnected"!==c&&"suspended"!==c||this.startRetryTimer(e.retryDelay);("disconnected"===c&&!g||"suspended"===c||e.terminal)&&h.nextTick(function(){b.disconnectAllTransports()});"connected"!=c||this.activeProtocol||d.logAction(d.LOG_ERROR,"ConnectionManager.notifyState()","Broken invariant: attempted to go into connected state, but there is no active protocol");this.enactStateChange(a);this.state.sendEvents?this.sendQueuedMessages():this.state.queueEvents||(this.realtime.channels.propogateConnectionInterruption(c, -a.reason),this.failQueuedMessages(a.reason))}};a.prototype.requestState=function(a){var c=a.state,b=this;d.logAction(d.LOG_MINOR,"ConnectionManager.requestState()","requested state: "+c+"; current state: "+this.state.state);if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(c),"connecting"!=c||"connected"!=this.state.state)&&("closing"!=c||"closed"!=this.state.state)){var g=this.states[c];a=new Q(this.state.state,g.state,null,a.error||J[g.state]); -this.enactStateChange(a);"connecting"==c&&h.nextTick(function(){b.startConnect()});"closing"==c&&this.closeImpl()}};a.prototype.startConnect=function(){if(this.state!==this.states.connecting)d.logAction(d.LOG_MINOR,"ConnectionManager.startConnect()","Must be in connecting state to connect, but was "+this.state.state);else{var a=this.realtime.auth,c=this,b=function(){c.checkConnectionStateFreshness();c.getTransportParams(function(a){c.connectImpl(a)})};d.logAction(d.LOG_MINOR,"ConnectionManager.startConnect()", -"starting connection");this.startSuspendTimer();this.startTransitionTimer(this.states.connecting);if("basic"===a.method)b();else{var e=function(a){a?c.actOnErrorFromAuthorize(a):b()};this.errorReason&&L.isTokenErr(this.errorReason)?a._forceNewToken(null,null,e):a._ensureValidAuthCredentials(e)}}};a.prototype.connectImpl=function(a){var c=this.state.state;c!==this.states.connecting.state&&c!==this.states.connected.state?d.logAction(d.LOG_MINOR,"ConnectionManager.connectImpl()","Must be in connecting state to connect (or connected to upgrade), but was "+ -c):this.pendingTransports.length?d.logAction(d.LOG_MINOR,"ConnectionManager.connectImpl()","Transports "+this.pendingTransports[0].toString()+" currently pending; taking no action"):c==this.states.connected.state?this.upgradeIfNeeded(a):1g||!h.allSame(m,"clientId")?f=!1:(f[k]=m,f=!0)}}f?(b.merged||(b.callback=V([b.callback]),b.merged=!0),b.callback.push(c)):this.queuedMessages.push(new n(a, -c))};a.prototype.sendQueuedMessages=function(){d.logAction(d.LOG_MICRO,"ConnectionManager.sendQueuedMessages()","sending "+this.queuedMessages.count()+" queued messages");for(var a;a=this.queuedMessages.shift();)this.sendImpl(a)};a.prototype.queuePendingMessages=function(a){a&&a.length&&(d.logAction(d.LOG_MICRO,"ConnectionManager.queuePendingMessages()","queueing "+a.length+" pending messages"),this.queuedMessages.prepend(a))};a.prototype.failQueuedMessages=function(a){var c=this.queuedMessages.count(); -0=b?(a="No activity seen from realtime in "+a+"ms; assuming connection has dropped",d.logAction(d.LOG_ERROR,"Transport.onIdleTimerExpire()",a),this.disconnect(new p(a,80003,408))):this.setIdleTimer(b+ -100)};b.prototype.onAuthUpdated=function(){};return b}();(function(){function b(b,a,c){this.shortName="web_socket";c.heartbeats=t.useProtocolHeartbeats;O.call(this,b,a,c);this.wsHost=r.getHost(c.options,c.host,!0)}var l=t.WebSocket;h.inherits(b,O);b.isAvailable=function(){return!!l};b.isAvailable()&&(M.supportedTransports.web_socket=b);b.tryConnect=function(f,a,c,h){function e(a){h({event:this.event,error:a})}var n=new b(f,a,c);n.on(["failed","disconnected"],e);n.on("wsopen",function(){d.logAction(d.LOG_MINOR, -"WebSocketTransport.tryConnect()","viable transport "+n);n.off(["failed","disconnected"],e);h(null,n)});n.connect()};b.prototype.createWebSocket=function(b,a){var c=0;if(a)for(var d in a)b+=(c++?"&":"?")+d+"="+a[d];this.uri=b;return new l(b)};b.prototype.toString=function(){return"WebSocketTransport; uri="+this.uri};b.prototype.connect=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","starting");O.prototype.connect.call(this);var b=this,a=this.params,c=a.options,h=(c.tls?"wss://": -"ws://")+this.wsHost+":"+r.getPort(c)+"/";d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","uri: "+h);this.auth.getAuthParams(function(c,f){var e="",k;for(k in f)e+=" "+k+": "+f[k]+";";d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","authParams:"+e+" err: "+c);if(c)b.disconnect(c);else{e=a.getConnectParams(f);try{var g=b.wsConnection=b.createWebSocket(h,e);g.binaryType=t.binaryType;g.onopen=function(){b.onWsOpen()};g.onclose=function(a){b.onWsClose(a)};g.onmessage=function(a){b.onWsData(a.data)}; -g.onerror=function(a){b.onWsError(a)};if(g.on)g.on("ping",function(){b.onActivity()})}catch(u){d.logAction(d.LOG_ERROR,"WebSocketTransport.connect()","Unexpected exception creating websocket: err = "+(u.stack||u.message)),b.disconnect(u)}}})};b.prototype.send=function(b){var a=this.wsConnection;if(a)try{a.send(w.serialize(b,this.params.format))}catch(c){b="Exception from ws connection when trying to send: "+h.inspectError(c),d.logAction(d.LOG_ERROR,"WebSocketTransport.send()",b),this.finish("disconnected", -new p(b,5E4,500))}else d.logAction(d.LOG_ERROR,"WebSocketTransport.send()","No socket connection")};b.prototype.onWsData=function(b){d.logAction(d.LOG_MICRO,"WebSocketTransport.onWsData()","data received; length = "+b.length+"; type = "+typeof b);try{this.onProtocolMessage(w.deserialize(b,this.format))}catch(a){d.logAction(d.LOG_ERROR,"WebSocketTransport.onWsData()","Unexpected exception handing channel message: "+a.stack)}};b.prototype.onWsOpen=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsOpen()", -"opened WebSocket");this.emit("wsopen")};b.prototype.onWsClose=function(b){if("object"==typeof b){var a=b.wasClean;b=b.code}else a=1E3==b;delete this.wsConnection;a?(d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsClose()","Cleanly closed WebSocket"),a=new p("Websocket closed",80003,400)):(b="Unclean disconnection of WebSocket ; code = "+b,a=new p(b,80003,400),d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsClose()",b));this.finish("disconnected",a);this.emit("disposed")};b.prototype.onWsError=function(b){d.logAction(d.LOG_MINOR, -"WebSocketTransport.onError()","Error from WebSocket: "+b.message);var a=this;h.nextTick(function(){a.disconnect(b)})};b.prototype.dispose=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.dispose()","");var b=this.wsConnection;b&&(b.onmessage=function(){},delete this.wsConnection,h.nextTick(function(){d.logAction(d.LOG_MICRO,"WebSocketTransport.dispose()","closing websocket");b.close()}))};return b})();var K=function(){function b(b){var a=[80015,80017,80030];return b.code&&(L.isTokenErr(b)? -0:h.arrIn(a,b.code)||4E4<=b.code&&5E4>b.code)?[w.fromValues({action:w.Action.ERROR,error:b})]:[w.fromValues({action:w.Action.DISCONNECTED,error:b})]}function l(b,a,c){c.format=void 0;c.heartbeats=!0;O.call(this,b,a,c);this.stream="stream"in c?c.stream:!0;this.pendingItems=this.pendingCallback=this.recvRequest=this.sendRequest=null;this.disposed=!1}h.inherits(l,O);l.REQ_SEND=0;l.REQ_RECV=1;l.REQ_RECV_POLL=2;l.REQ_RECV_STREAM=3;l.prototype.connect=function(){d.logAction(d.LOG_MINOR,"CometTransport.connect()", -"starting");O.prototype.connect.call(this);var f=this,a=this.params,c=a.options;a=r.getHost(c,a.host);var q=r.getPort(c);this.baseUri=(c.tls?"https://":"http://")+a+":"+q+"/comet/";var e=this.baseUri+"connect";d.logAction(d.LOG_MINOR,"CometTransport.connect()","uri: "+e);this.auth.getAuthParams(function(a,c){if(a)f.disconnect(a);else{f.authParams=c;var k=f.params.getConnectParams(c);"stream"in k&&(f.stream=k.stream);d.logAction(d.LOG_MINOR,"CometTransport.connect()","connectParams:"+h.toQueryString(k)); -var g=!1;k=f.recvRequest=f.createRequest(e,null,k,null,f.stream?3:1);k.on("data",function(a){f.recvRequest&&(g||(g=!0,f.emit("preconnect")),f.onData(a))});k.on("complete",function(a){f.recvRequest||(a=a||new p("Request cancelled",8E4,400));f.recvRequest=null;f.onActivity();if(a)if(a.code)f.onData(b(a));else f.disconnect(a);else h.nextTick(function(){f.recv()})});k.exec()}})};l.prototype.requestClose=function(){d.logAction(d.LOG_MINOR,"CometTransport.requestClose()");this._requestCloseOrDisconnect(!0)}; +"ConnectionManager.activateTransport()","Declining to activate transport "+c+" since it appears to no longer be connected"),!1;var p=this.activeProtocol;this.activeProtocol=new ea(c);this.host=c.params.host;var m=e.connectionKey;m&&this.connectionKey!=m&&this.setConnection(b,e,f,!0,!!a);this.onConnectionDetailsUpdate(e,c);var n=this;h.nextTick(function(){c.on("connected",function(a,g,b){n.onConnectionDetailsUpdate(b,c);n.emit("update",new R(k,k,null,a))})});g.state===this.states.connected.state?a&& +(this.errorReason=this.realtime.connection.errorReason=a,this.emit("update",new R(k,k,null,a))):(this.notifyState({state:"connected",error:a}),this.errorReason=this.realtime.connection.errorReason=a||null);this.emit("transport.active",c);p&&(0this.connectionStateTtl+this.maxIdleInterval&&(d.logAction(d.LOG_MINOR,"ConnectionManager.checkConnectionStateFreshness()","Last known activity from realtime was "+a+"ms ago; discarding connection state"),this.clearConnection(),this.states.connecting.failState="suspended",this.states.connecting.queueEvents=!1)}};a.prototype.persistConnection=function(){if(n){var a=this.realtime.connection.recoveryKey;a&&(a={recoveryKey:a,disconnectedAt:h.now(),location:window.location,clientId:this.realtime.auth.clientId}, +n&&I.setSession("ably-connection-recovery",a))}};a.prototype.unpersistConnection=function(){n&&I.removeSession("ably-connection-recovery")};a.prototype.getError=function(){return this.errorReason||this.getStateError()};a.prototype.getStateError=function(){return J[this.state.state]};a.prototype.activeState=function(){return this.state.queueEvents||this.state.sendEvents};a.prototype.enactStateChange=function(a){d.logAction("failed"===a.current?d.LOG_ERROR:d.LOG_MAJOR,"Connection state",a.current+(a.reason? +"; reason: "+a.reason:""));d.logAction(d.LOG_MINOR,"ConnectionManager.enactStateChange","setting new state: "+a.current+"; reason = "+(a.reason&&a.reason.message));var c=this.state=this.states[a.current];a.reason&&(this.errorReason=a.reason,this.realtime.connection.errorReason=a.reason);(c.terminal||"suspended"===c.state)&&this.clearConnection();this.emit("connectionstate",a)};a.prototype.startTransitionTimer=function(a){d.logAction(d.LOG_MINOR,"ConnectionManager.startTransitionTimer()","transitionState: "+ +a.state);this.transitionTimer&&(d.logAction(d.LOG_MINOR,"ConnectionManager.startTransitionTimer()","clearing already-running timer"),clearTimeout(this.transitionTimer));var c=this;this.transitionTimer=setTimeout(function(){c.transitionTimer&&(c.transitionTimer=null,d.logAction(d.LOG_MINOR,"ConnectionManager "+a.state+" timer expired","requesting new state: "+a.failState),c.notifyState({state:a.failState}))},a.retryDelay)};a.prototype.cancelTransitionTimer=function(){d.logAction(d.LOG_MINOR,"ConnectionManager.cancelTransitionTimer()", +"");this.transitionTimer&&(clearTimeout(this.transitionTimer),this.transitionTimer=null)};a.prototype.startSuspendTimer=function(){var a=this;this.suspendTimer||(this.suspendTimer=setTimeout(function(){a.suspendTimer&&(a.suspendTimer=null,d.logAction(d.LOG_MINOR,"ConnectionManager suspend timer expired","requesting new state: suspended"),a.states.connecting.failState="suspended",a.states.connecting.queueEvents=!1,a.notifyState({state:"suspended"}))},this.connectionStateTtl))};a.prototype.checkSuspendTimer= +function(a){"disconnected"!==a&&"suspended"!==a&&"connecting"!==a&&this.cancelSuspendTimer()};a.prototype.cancelSuspendTimer=function(){this.states.connecting.failState="disconnected";this.states.connecting.queueEvents=!0;this.suspendTimer&&(clearTimeout(this.suspendTimer),this.suspendTimer=null)};a.prototype.startRetryTimer=function(a){var c=this;this.retryTimer=setTimeout(function(){d.logAction(d.LOG_MINOR,"ConnectionManager retry timer expired","retrying");c.retryTimer=null;c.requestState({state:"connecting"})}, +a)};a.prototype.cancelRetryTimer=function(){this.retryTimer&&(clearTimeout(this.retryTimer),this.retryTimer=null)};a.prototype.notifyState=function(a){var c=a.state,b=this,g="disconnected"===c&&(this.state===this.states.connected||this.state===this.states.synchronizing||a.retryImmediately||this.state===this.states.connecting&&a.error&&L.isTokenErr(a.error)&&!(this.errorReason&&L.isTokenErr(this.errorReason)));d.logAction(d.LOG_MINOR,"ConnectionManager.notifyState()","new state: "+c+(g?"; will retry connection immediately": +""));if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(a.state),!this.state.terminal)){var e=this.states[a.state];a=new R(this.state.state,e.state,e.retryDelay,a.error||J[e.state]);if(g){var f=function(){b.state===b.states.disconnected&&(b.lastAutoReconnectAttempt=h.now(),b.requestState({state:"connecting"}))},k=this.lastAutoReconnectAttempt&&h.now()-this.lastAutoReconnectAttempt+1;k&&1E3>k?(d.logAction(d.LOG_MICRO,"ConnectionManager.notifyState()", +"Last reconnect attempt was only "+k+"ms ago, waiting another "+(1E3-k)+"ms before trying again"),setTimeout(f,1E3-k)):h.nextTick(f)}else"disconnected"!==c&&"suspended"!==c||this.startRetryTimer(e.retryDelay);("disconnected"===c&&!g||"suspended"===c||e.terminal)&&h.nextTick(function(){b.disconnectAllTransports()});"connected"!=c||this.activeProtocol||d.logAction(d.LOG_ERROR,"ConnectionManager.notifyState()","Broken invariant: attempted to go into connected state, but there is no active protocol"); +this.enactStateChange(a);this.state.sendEvents?this.sendQueuedMessages():this.state.queueEvents||(this.realtime.channels.propogateConnectionInterruption(c,a.reason),this.failQueuedMessages(a.reason))}};a.prototype.requestState=function(a){var c=a.state,b=this;d.logAction(d.LOG_MINOR,"ConnectionManager.requestState()","requested state: "+c+"; current state: "+this.state.state);if(c!=this.state.state&&(this.cancelTransitionTimer(),this.cancelRetryTimer(),this.checkSuspendTimer(c),"connecting"!=c||"connected"!= +this.state.state)&&("closing"!=c||"closed"!=this.state.state)){var g=this.states[c];a=new R(this.state.state,g.state,null,a.error||J[g.state]);this.enactStateChange(a);"connecting"==c&&h.nextTick(function(){b.startConnect()});"closing"==c&&this.closeImpl()}};a.prototype.startConnect=function(){if(this.state!==this.states.connecting)d.logAction(d.LOG_MINOR,"ConnectionManager.startConnect()","Must be in connecting state to connect, but was "+this.state.state);else{var a=this.realtime.auth,c=this,b= +++this.connectCounter,e=function(){c.checkConnectionStateFreshness();c.getTransportParams(function(a){b===c.connectCounter&&c.connectImpl(a,b)})};d.logAction(d.LOG_MINOR,"ConnectionManager.startConnect()","starting connection");this.startSuspendTimer();this.startTransitionTimer(this.states.connecting);if("basic"===a.method)e();else{var f=function(a){b===c.connectCounter&&(a?c.actOnErrorFromAuthorize(a):e())};this.errorReason&&L.isTokenErr(this.errorReason)?a._forceNewToken(null,null,f):a._ensureValidAuthCredentials(!1, +f)}}};a.prototype.connectImpl=function(a,c){var b=this.state.state;b!==this.states.connecting.state&&b!==this.states.connected.state?d.logAction(d.LOG_MINOR,"ConnectionManager.connectImpl()","Must be in connecting state to connect (or connected to upgrade), but was "+b):this.pendingTransports.length?d.logAction(d.LOG_MINOR,"ConnectionManager.connectImpl()","Transports "+this.pendingTransports[0].toString()+" currently pending; taking no action"):b==this.states.connected.state?this.upgradeIfNeeded(a): +1g||!h.allSame(p,"clientId")?f=!1:(f[k]=p,f=!0)}}f?(b.merged||(b.callback=W([b.callback]),b.merged=!0),b.callback.push(c)):this.queuedMessages.push(new m(a,c))};a.prototype.sendQueuedMessages=function(){d.logAction(d.LOG_MICRO,"ConnectionManager.sendQueuedMessages()","sending "+this.queuedMessages.count()+ +" queued messages");for(var a;a=this.queuedMessages.shift();)this.sendImpl(a)};a.prototype.queuePendingMessages=function(a){a&&a.length&&(d.logAction(d.LOG_MICRO,"ConnectionManager.queuePendingMessages()","queueing "+a.length+" pending messages"),this.queuedMessages.prepend(a))};a.prototype.failQueuedMessages=function(a){var c=this.queuedMessages.count();0=b?(a="No activity seen from realtime in "+a+"ms; assuming connection has dropped",d.logAction(d.LOG_ERROR,"Transport.onIdleTimerExpire()",a),this.disconnect(new q(a,80003,408))):this.setIdleTimer(b+100)};b.prototype.onAuthUpdated=function(){}; +return b}();(function(){function b(b,a,c){this.shortName="web_socket";c.heartbeats=u.useProtocolHeartbeats;P.call(this,b,a,c);this.wsHost=r.getHost(c.options,c.host,!0)}var l=u.WebSocket;h.inherits(b,P);b.isAvailable=function(){return!!l};b.isAvailable()&&(M.supportedTransports.web_socket=b);b.tryConnect=function(f,a,c,h){function e(a){h({event:this.event,error:a})}var m=new b(f,a,c);m.on(["failed","disconnected"],e);m.on("wsopen",function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.tryConnect()", +"viable transport "+m);m.off(["failed","disconnected"],e);h(null,m)});m.connect()};b.prototype.createWebSocket=function(b,a){var c=0;if(a)for(var d in a)b+=(c++?"&":"?")+d+"="+a[d];this.uri=b;return new l(b)};b.prototype.toString=function(){return"WebSocketTransport; uri="+this.uri};b.prototype.connect=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","starting");P.prototype.connect.call(this);var b=this,a=this.params,c=a.options,h=(c.tls?"wss://":"ws://")+this.wsHost+":"+r.getPort(c)+ +"/";d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","uri: "+h);this.auth.getAuthParams(function(c,f){if(!b.isDisposed){var e="",k;for(k in f)e+=" "+k+": "+f[k]+";";d.logAction(d.LOG_MINOR,"WebSocketTransport.connect()","authParams:"+e+" err: "+c);if(c)b.disconnect(c);else{e=a.getConnectParams(f);try{var g=b.wsConnection=b.createWebSocket(h,e);g.binaryType=u.binaryType;g.onopen=function(){b.onWsOpen()};g.onclose=function(a){b.onWsClose(a)};g.onmessage=function(a){b.onWsData(a.data)};g.onerror= +function(a){b.onWsError(a)};if(g.on)g.on("ping",function(){b.onActivity()})}catch(p){d.logAction(d.LOG_ERROR,"WebSocketTransport.connect()","Unexpected exception creating websocket: err = "+(p.stack||p.message)),b.disconnect(p)}}}})};b.prototype.send=function(b){var a=this.wsConnection;if(a)try{a.send(w.serialize(b,this.params.format))}catch(c){b="Exception from ws connection when trying to send: "+h.inspectError(c),d.logAction(d.LOG_ERROR,"WebSocketTransport.send()",b),this.finish("disconnected", +new q(b,5E4,500))}else d.logAction(d.LOG_ERROR,"WebSocketTransport.send()","No socket connection")};b.prototype.onWsData=function(b){d.logAction(d.LOG_MICRO,"WebSocketTransport.onWsData()","data received; length = "+b.length+"; type = "+typeof b);try{this.onProtocolMessage(w.deserialize(b,this.format))}catch(a){d.logAction(d.LOG_ERROR,"WebSocketTransport.onWsData()","Unexpected exception handing channel message: "+a.stack)}};b.prototype.onWsOpen=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsOpen()", +"opened WebSocket");this.emit("wsopen")};b.prototype.onWsClose=function(b){if("object"==typeof b){var a=b.wasClean;b=b.code}else a=1E3==b;delete this.wsConnection;a?(d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsClose()","Cleanly closed WebSocket"),a=new q("Websocket closed",80003,400)):(b="Unclean disconnection of WebSocket ; code = "+b,a=new q(b,80003,400),d.logAction(d.LOG_MINOR,"WebSocketTransport.onWsClose()",b));this.finish("disconnected",a);this.emit("disposed")};b.prototype.onWsError=function(b){d.logAction(d.LOG_MINOR, +"WebSocketTransport.onError()","Error from WebSocket: "+b.message);var a=this;h.nextTick(function(){a.disconnect(b)})};b.prototype.dispose=function(){d.logAction(d.LOG_MINOR,"WebSocketTransport.dispose()","");this.isDisposed=!0;var b=this.wsConnection;b&&(b.onmessage=function(){},delete this.wsConnection,h.nextTick(function(){d.logAction(d.LOG_MICRO,"WebSocketTransport.dispose()","closing websocket");b.close()}))};return b})();var K=function(){function b(b){var a=[80015,80017,80030];return b.code&& +(L.isTokenErr(b)?0:h.arrIn(a,b.code)||4E4<=b.code&&5E4>b.code)?[w.fromValues({action:w.Action.ERROR,error:b})]:[w.fromValues({action:w.Action.DISCONNECTED,error:b})]}function l(b,a,c){c.format=void 0;c.heartbeats=!0;P.call(this,b,a,c);this.stream="stream"in c?c.stream:!0;this.pendingItems=this.pendingCallback=this.recvRequest=this.sendRequest=null}h.inherits(l,P);l.REQ_SEND=0;l.REQ_RECV=1;l.REQ_RECV_POLL=2;l.REQ_RECV_STREAM=3;l.prototype.connect=function(){d.logAction(d.LOG_MINOR,"CometTransport.connect()", +"starting");P.prototype.connect.call(this);var f=this,a=this.params,c=a.options;a=r.getHost(c,a.host);var n=r.getPort(c);this.baseUri=(c.tls?"https://":"http://")+a+":"+n+"/comet/";var e=this.baseUri+"connect";d.logAction(d.LOG_MINOR,"CometTransport.connect()","uri: "+e);this.auth.getAuthParams(function(a,c){if(a)f.disconnect(a);else if(!f.isDisposed){f.authParams=c;var k=f.params.getConnectParams(c);"stream"in k&&(f.stream=k.stream);d.logAction(d.LOG_MINOR,"CometTransport.connect()","connectParams:"+ +h.toQueryString(k));var g=!1;k=f.recvRequest=f.createRequest(e,null,k,null,f.stream?3:1);k.on("data",function(a){f.recvRequest&&(g||(g=!0,f.emit("preconnect")),f.onData(a))});k.on("complete",function(a){f.recvRequest||(a=a||new q("Request cancelled",8E4,400));f.recvRequest=null;f.onActivity();if(a)if(a.code)f.onData(b(a));else f.disconnect(a);else h.nextTick(function(){f.recv()})});k.exec()}})};l.prototype.requestClose=function(){d.logAction(d.LOG_MINOR,"CometTransport.requestClose()");this._requestCloseOrDisconnect(!0)}; l.prototype.requestDisconnect=function(){d.logAction(d.LOG_MINOR,"CometTransport.requestDisconnect()");this._requestCloseOrDisconnect(!1)};l.prototype._requestCloseOrDisconnect=function(b){var a=b?this.closeUri:this.disconnectUri;if(a){var c=this;a=this.createRequest(a,null,this.authParams,null,0);a.on("complete",function(a){a&&(d.logAction(d.LOG_ERROR,"CometTransport.request"+(b?"Close()":"Disconnect()"),"request returned err = "+h.inspectError(a)),c.finish("disconnected",a))});a.exec()}};l.prototype.dispose= -function(){d.logAction(d.LOG_MINOR,"CometTransport.dispose()","");if(!this.disposed){this.disposed=!0;this.recvRequest&&(d.logAction(d.LOG_MINOR,"CometTransport.dispose()","aborting recv request"),this.recvRequest.abort(),this.recvRequest=null);this.finish("disconnected",J.disconnected);var b=this;h.nextTick(function(){b.emit("disposed")})}};l.prototype.onConnect=function(b){if(!this.disposed){var a=b.connectionKey;O.prototype.onConnect.call(this,b);a=this.baseUri+a;d.logAction(d.LOG_MICRO,"CometTransport.onConnect()", -"baseUri = "+a+"; connectionKey = "+b.connectionKey);this.sendUri=a+"/send";this.recvUri=a+"/recv";this.closeUri=a+"/close";this.disconnectUri=a+"/disconnect"}};l.prototype.send=function(b){if(this.sendRequest)this.pendingItems=this.pendingItems||[],this.pendingItems.push(b);else{var a=this.pendingItems||[];a.push(b);this.pendingItems=null;this.sendItems(a)}};l.prototype.sendAnyPending=function(){var b=this.pendingItems;b&&(this.pendingItems=null,this.sendItems(b))};l.prototype.sendItems=function(f){var a= -this;f=this.sendRequest=a.createRequest(a.sendUri,null,a.authParams,this.encodeRequest(f),0);f.on("complete",function(c,f){c&&d.logAction(d.LOG_ERROR,"CometTransport.sendItems()","on complete: err = "+h.inspectError(c));a.sendRequest=null;if(f)a.onData(f);else if(c&&c.code)a.onData(b(c));else a.disconnect(c);a.pendingItems&&h.nextTick(function(){a.sendRequest||a.sendAnyPending()})});f.exec()};l.prototype.recv=function(){if(!this.recvRequest&&this.isConnected){var d=this,a=this.recvRequest=this.createRequest(this.recvUri, -null,this.authParams,null,d.stream?3:2);a.on("data",function(a){d.onData(a)});a.on("complete",function(a){d.recvRequest=null;d.onActivity();if(a)if(a.code)d.onData(b(a));else d.disconnect(a);else h.nextTick(function(){d.recv()})});a.exec()}};l.prototype.onData=function(b){try{var a=this.decodeResponse(b);if(a&&a.length)for(b=0;be||300<=e?(c=f&&f.error||c,c||(c=Error("Error in unenveloping "+d),c.statusCode=e),a(c,f,n,!0,e)): -a(c,f,n,!0,e))}}}function a(a){var b=[];if(a)for(var c in a)b.push(c+"="+a[c]);return b.join("&")}function c(b,c,f,k){return function(e,m,n,q,l){e?d.logAction(d.LOG_MICRO,"Resource."+c+"()","Received Error; "+(f+(k?"?":"")+a(k))+"; Error: "+h.inspectError(e)):d.logAction(d.LOG_MICRO,"Resource."+c+"()","Received; "+(f+(k?"?":"")+a(k))+"; Headers: "+a(n)+"; StatusCode: "+l+"; Body: "+(z.isBuffer(m)?m.toString():m));b&&b(e,m,n,q,l)}}var q=t.msgpack;h.arrForEach(v.methodsWithoutBody,function(a){b[a]= -function(c,d,e,g,f,h){b["do"](a,c,d,null,e,g,f,h)}});h.arrForEach(v.methodsWithBody,function(a){b[a]=function(c,d,e,g,f,h,q){b["do"](a,c,d,e,g,f,h,q)}});b["do"]=function(b,n,m,k,g,u,p,F){function e(c,f){d.shouldLog(d.LOG_MICRO)&&d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending; "+(m+(f?"?":"")+a(f)));var p=[n,m,c,k,f,function(a,b,c,d,f){a&&L.isTokenErr(a)?n.auth.authorize(null,null,function(a){a?F(a):l(n,g,u,F,e)}):F(a,b,c,d,f)}];k||p.splice(3,1);if(d.shouldLog(d.LOG_MICRO)){var H=k;if(0<(c["content-type"]|| -"").indexOf("msgpack"))try{H=q.decode(k)}catch(fa){d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending MsgPack Decoding Error: "+h.inspectError(fa))}d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending; "+(m+(f?"?":"")+a(f))+"; Body: "+H)}v[b].apply(this,p)}d.shouldLog(d.LOG_MICRO)&&(F=c(F,b,m,u));p&&(F=F&&f(F,p),(u=u||{}).envelope=p);l(n,g,u,F,e)};return b}(),N=function(){function b(a,b,d,e,f,m){this.rest=a;this.path=b;this.headers=d;this.envelope=e;this.bodyHandler=f;this.useHttpPaginatedResponse= -m||!1}function l(a,b,d){this.resource=a;this.items=b;if(d){var c=this;"first"in d&&(this.first=function(a){c.get(d.first,a)});"current"in d&&(this.current=function(a){c.get(d.current,a)});this.next=function(a){"next"in d?c.get(d.next,a):a(null,null)};this.hasNext=function(){return"next"in d};this.isLast=function(){return!this.hasNext()}}}function f(a,b,d,e,f,m){l.call(this,a,b,f);this.statusCode=e;this.success=300>e&&200<=e;this.headers=d;this.errorCode=m&&m.code;this.errorMessage=m&&m.message}h.arrForEach(v.methodsWithoutBody, -function(a){b.prototype[a]=function(b,d){var c=this;E[a](c.rest,c.path,c.headers,b,c.envelope,function(a,b,e,g,f){c.handlePage(a,b,e,g,f,d)})}});h.arrForEach(v.methodsWithBody,function(a){b.prototype[a]=function(b,d,e){var c=this;E[a](c.rest,c.path,d,c.headers,b,c.envelope,function(a,b,d,f,n){e&&c.handlePage(a,b,d,f,n,e)})}});b.prototype.handlePage=function(a,b,q,e,n,m){if(!a||this.useHttpPaginatedResponse&&(b||"number"===typeof a.code)){var c,g;try{var u=this.bodyHandler(b,q,e)}catch(F){m(a||F); -return}if(q&&(c=q.Link||q.link)){b=c;"string"==typeof b&&(b=b.split(","));e={};for(c=0;c;\s*rel="(\w+)"$/)){var p;(p=(p=g[1].match(/^\.\/(\w+)\?(.*)$/))&&h.parseQueryString(p[2]))&&(e[g[2]]=p)}g=e}this.useHttpPaginatedResponse?m(null,new f(this,u,q,n,g,a)):m(null,new l(this,u,g))}else d.logAction(d.LOG_ERROR,"PaginatedResource.handlePage()","Unexpected error getting resource: err = "+h.inspectError(a)),m(a)};l.prototype.get=function(a,b){var c=this.resource; -E.get(c.rest,c.path,c.headers,a,c.envelope,function(a,d,f,k,g){c.handlePage(a,d,f,k,g,b)})};h.inherits(f,l);return b}(),L=function(){function b(){}function l(a){if(!h.isErrorInfo(a))return new p(h.inspectError(a),a.code||40170,a.statusCode||401);a.code||(403===a.statusCode?a.code=40300:(a.code=40170,a.statusCode=401));return a}function f(a){if(!a)return"";"string"==typeof a&&(a=JSON.parse(a));var b={},c=h.keysArray(a,!0);if(!c)return"";c.sort();for(var d=0;de||300<=e?(c=f&&f.error||c,c||(c=Error("Error in unenveloping "+d),c.statusCode=e),a(c,f,m,!0,e)): +a(c,f,m,!0,e))}}}function a(a){var b=[];if(a)for(var c in a)b.push(c+"="+a[c]);return b.join("&")}function c(b,c,f,k){return function(e,m,n,t,l){e?d.logAction(d.LOG_MICRO,"Resource."+c+"()","Received Error; "+(f+(k?"?":"")+a(k))+"; Error: "+h.inspectError(e)):d.logAction(d.LOG_MICRO,"Resource."+c+"()","Received; "+(f+(k?"?":"")+a(k))+"; Headers: "+a(n)+"; StatusCode: "+l+"; Body: "+(y.isBuffer(m)?m.toString():m));b&&b(e,m,n,t,l)}}var n=u.msgpack;h.arrForEach(v.methodsWithoutBody,function(a){b[a]= +function(c,d,e,g,f,h){b["do"](a,c,d,null,e,g,f,h)}});h.arrForEach(v.methodsWithBody,function(a){b[a]=function(c,d,e,g,f,h,n){b["do"](a,c,d,e,g,f,h,n)}});b["do"]=function(b,m,t,k,g,p,D,q){function e(c,f){d.shouldLog(d.LOG_MICRO)&&d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending; "+(t+(f?"?":"")+a(f)));var D=[m,t,c,k,f,function(a,b,c,d,f){a&&L.isTokenErr(a)?m.auth.authorize(null,null,function(a){a?q(a):l(m,g,p,q,e)}):q(a,b,c,d,f)}];k||D.splice(3,1);if(d.shouldLog(d.LOG_MICRO)){var O=k;if(0<(c["content-type"]|| +"").indexOf("msgpack"))try{O=n.decode(k)}catch(ia){d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending MsgPack Decoding Error: "+h.inspectError(ia))}d.logAction(d.LOG_MICRO,"Resource."+b+"()","Sending; "+(t+(f?"?":"")+a(f))+"; Body: "+O)}v[b].apply(this,D)}d.shouldLog(d.LOG_MICRO)&&(q=c(q,b,t,p));D&&(q=q&&f(q,D),(p=p||{}).envelope=D);l(m,g,p,q,e)};return b}(),N=function(){function b(a,b,d,e,f,h){this.rest=a;this.path=b;this.headers=d;this.envelope=e;this.bodyHandler=f;this.useHttpPaginatedResponse= +h||!1}function l(a,b,d){this.resource=a;this.items=b;if(d){var c=this;"first"in d&&(this.first=function(a){c.get(d.first,a)});"current"in d&&(this.current=function(a){c.get(d.current,a)});this.next=function(a){"next"in d?c.get(d.next,a):a(null,null)};this.hasNext=function(){return"next"in d};this.isLast=function(){return!this.hasNext()}}}function f(a,b,d,e,f,h){l.call(this,a,b,f);this.statusCode=e;this.success=300>e&&200<=e;this.headers=d;this.errorCode=h&&h.code;this.errorMessage=h&&h.message}h.arrForEach(v.methodsWithoutBody, +function(a){b.prototype[a]=function(b,d){var c=this;H[a](c.rest,c.path,c.headers,b,c.envelope,function(a,b,e,g,f){c.handlePage(a,b,e,g,f,d)})}});h.arrForEach(v.methodsWithBody,function(a){b.prototype[a]=function(b,d,e){var c=this;H[a](c.rest,c.path,d,c.headers,b,c.envelope,function(a,b,d,f,h){e&&c.handlePage(a,b,d,f,h,e)})}});b.prototype.handlePage=function(a,b,n,e,m,t){if(!a||this.useHttpPaginatedResponse&&(b||"number"===typeof a.code)){var c,g;try{var p=this.bodyHandler(b,n,e)}catch(O){t(a||O); +return}if(n&&(c=n.Link||n.link)){b=c;"string"==typeof b&&(b=b.split(","));e={};for(c=0;c;\s*rel="(\w+)"$/)){var D;(D=(D=g[1].match(/^\.\/(\w+)\?(.*)$/))&&h.parseQueryString(D[2]))&&(e[g[2]]=D)}g=e}this.useHttpPaginatedResponse?t(null,new f(this,p,n,m,g,a)):t(null,new l(this,p,g))}else d.logAction(d.LOG_ERROR,"PaginatedResource.handlePage()","Unexpected error getting resource: err = "+h.inspectError(a)),t(a)};l.prototype.get=function(a,b){var c=this.resource; +H.get(c.rest,c.path,c.headers,a,c.envelope,function(a,d,f,k,g){c.handlePage(a,d,f,k,g,b)})};h.inherits(f,l);return b}(),L=function(){function b(){}function l(a){if(!h.isErrorInfo(a))return new q(h.inspectError(a),a.code||40170,a.statusCode||401);a.code||(403===a.statusCode?a.code=40300:(a.code=40170,a.statusCode=401));return a}function f(a){if(!a)return"";"string"==typeof a&&(a=JSON.parse(a));var b={},c=h.keysArray(a,!0);if(!c)return"";c.sort();for(var d=0;d -q){b(new p("authUrl response exceeded max permitted length",40170,401));return}try{c=JSON.parse(c)}catch(ka){b(new p("Unexpected error processing authURL response; err = "+ka.message,40170,401));return}}b(null,c)}else b(new p("authUrl responded with unacceptable content-type "+a+", should be either text/plain, application/jwt or application/json",40170,401));else b(new p("authUrl response is missing a content-type header",40170,401))}var g=h.mixin({accept:"application/json, text/plain"},c.authHeaders), -f=c.authMethod&&"post"===c.authMethod.toLowerCase();if(!f){var m=c.authUrl.indexOf("?");if(-1q&&!c.suppressMaxLengthCheck?e(new p("Token request/details object exceeded max permitted stringified size (was "+f+" bytes)",40170,401)):"issued"in b?e(null,b):"keyName"in b?g(b,function(a,b,c,g){a?(d.logAction(d.LOG_ERROR,"Auth.requestToken()","token request API call returned error; err = "+h.inspectError(a)),e(l(a))):(g||(b=JSON.parse(b)),d.logAction(d.LOG_MINOR,"Auth.getToken()","token received"),e(null,b))}):(f="Expected token request callback to call back with a token string, token request object, or token details object", -d.logAction(d.LOG_ERROR,"Auth.requestToken()",f),e(new p(f,40170,401)))})};c.prototype.createTokenRequest=function(a,b,c){"function"!=typeof a||c?"function"!=typeof b||c||(c=b,b=null):(c=a,b=a=null);if(!c&&this.client.options.promises)return h.promisify(this,"createTokenRequest",arguments);b=b||this.authOptions;a=a||h.copy(this.tokenParams);var e=b.key;if(e){e=e.split(":");var g=e[0],k=e[1];if(k)if(""===a.clientId)c(new p("clientId can\u2019t be an empty string",40012,400));else{"capability"in a&& -(a.capability=f(a.capability));var m=h.mixin({keyName:g},a),q=a.clientId||"",l=a.ttl||"",r=a.capability||"",t=this;(function(a){m.timestamp?a():t.getTimestamp(b&&b.queryTime,function(b,d){b?c(b):(m.timestamp=d,a())})})(function(){var a=m.nonce||(m.nonce=("000000"+Math.floor(1E16*Math.random())).slice(-16));a=m.keyName+"\n"+l+"\n"+r+"\n"+q+"\n"+m.timestamp+"\n"+a+"\n";m.mac=m.mac||n(a,k);d.logAction(d.LOG_MINOR,"Auth.getTokenRequest()","generated signed request");c(null,m)})}else c(new p("Invalid key specified", -40101,403))}else c(new p("No key specified",40101,403))};c.prototype.getAuthParams=function(a){"basic"==this.method?a(null,{key:this.key}):this._ensureValidAuthCredentials(function(b,c){b?a(b):a(null,{access_token:c.token})})};c.prototype.getAuthHeaders=function(a){"basic"==this.method?a(null,{authorization:"Basic "+this.basicKey}):this._ensureValidAuthCredentials(function(b,c){b?a(b):a(null,{authorization:"Bearer "+e(c.token)})})};c.prototype.getTimestamp=function(a,b){this.isTimeOffsetSet()||!a&& -!this.authOptions.queryTime?b(null,this.getTimestampUsingOffset()):this.client.time(b)};c.prototype.getTimestampUsingOffset=function(){return h.now()+(this.client.serverTimeOffset||0)};c.prototype.isTimeOffsetSet=function(){return null!==this.client.serverTimeOffset};c.prototype._saveBasicOptions=function(a){this.method="basic";this.key=a.key;this.basicKey=e(a.key);this.authOptions=a||{};"clientId"in a&&this._userSetClientId(a.clientId)};c.prototype._saveTokenOptions=function(a,b){this.method="token"; -a&&(this.tokenParams=a);b&&(b.token&&(b.tokenDetails="string"===typeof b.token?{token:b.token}:b.token),b.tokenDetails&&(this.tokenDetails=b.tokenDetails),"clientId"in b&&this._userSetClientId(b.clientId),this.authOptions=b)};c.prototype._ensureValidAuthCredentials=function(a){var b=this,c=this.tokenDetails;if(this.tokenRequestInProgress)(this.waitingForTokenRequest||(this.waitingForTokenRequest=V())).push(a);else{if(c){if(this._tokenClientIdMismatch(c.clientId)){a(new p("Mismatch between clientId in token ("+ -c.clientId+") and current clientId ("+this.clientId+")",40102,403));return}if(!this.isTimeOffsetSet()||!c.expires||c.expires>=this.getTimestampUsingOffset()){d.logAction(d.LOG_MINOR,"Auth.getToken()","using cached token; expires = "+c.expires);a(null,c);return}d.logAction(d.LOG_MINOR,"Auth.getToken()","deleting expired token");this.tokenDetails=null}this.tokenRequestInProgress=!0;this.requestToken(this.tokenParams,this.authOptions,function(c,d){b.tokenRequestInProgress=!1;var e=b.waitingForTokenRequest; -e&&(e.push(a),a=e,b.waitingForTokenRequest=null);c?a(c):a(null,b.tokenDetails=d)})}};c.prototype._userSetClientId=function(a){if("string"!==typeof a&&null!==a)throw new p("clientId must be either a string or null",40012,400);if("*"===a)throw new p('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, instantiate the library with {defaultTokenParams: {clientId: "*"}}), or if calling authorize(), pass it in as a tokenParam: authorize({clientId: "*"}, authOptions)', -40012,400);if(a=this._uncheckedSetClientId(a))throw a;};c.prototype._uncheckedSetClientId=function(a){if(this._tokenClientIdMismatch(a)){a="Unexpected clientId mismatch: client has "+this.clientId+", requested "+a;var b=new p(a,40102,401);d.logAction(d.LOG_ERROR,"Auth._uncheckedSetClientId()",a);return b}this.clientId=this.tokenParams.clientId=a;return null};c.prototype._tokenClientIdMismatch=function(a){return this.clientId&&"*"!==this.clientId&&a&&"*"!==a&&this.clientId!==a};c.isTokenErr=function(a){return a.code&& -40140<=a.code&&40150>a.code};return c}(),x=function(){function b(){}function l(a){if(!(this instanceof l))return new l(a);if(!a){var b="no options provided";d.logAction(d.LOG_ERROR,"Rest()",b);throw Error(b);}a=r.objectifyOptions(a);a.log&&d.setLog(a.log.level,a.log.handler);d.logAction(d.LOG_MICRO,"Rest()","initialized with clientOptions "+h.inspect(a));this.options=r.normaliseOptions(a);if(a.key){b=a.key.match(/^([^:\s]+):([^:.\s]+)$/);if(!b)throw b="invalid key parameter",d.logAction(d.LOG_ERROR, -"Rest()",b),Error(b);a.keyName=b[1];a.keySecret=b[2]}if("clientId"in a){if("string"!==typeof a.clientId&&null!==a.clientId)throw new p("clientId must be either a string or null",40012,400);if("*"===a.clientId)throw new p('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, use {defaultTokenParams: {clientId: "*"}})',40012,400);}d.logAction(d.LOG_MINOR,"Rest()","started; version = "+r.libstring);this.baseUri=this.authority= -function(b){return r.getHttpScheme(a)+b+":"+r.getPort(a,!1)};this.serverTimeOffset=this._currentFallback=null;this.auth=new L(this,a);this.channels=new f(this);this.push=new la(this)}function f(a){this.rest=a;this.attached={}}var a=t.msgpack;l.prototype.stats=function(a,d){if(void 0===d)if("function"==typeof a)d=a,a=null;else{if(this.options.promises)return h.promisify(this,"stats",arguments);d=b}var c=h.defaultGetHeaders(),f=this.options.useBinaryProtocol?"msgpack":"json";f=v.supportsLinkHeaders? -void 0:f;this.options.headers&&h.mixin(c,this.options.headers);(new N(this,"/stats",c,f,function(a,b,c){a=c?a:JSON.parse(a);for(b=0;bn){b(new q("authUrl response exceeded max permitted length",40170,401));return}try{c=JSON.parse(c)}catch(ma){b(new q("Unexpected error processing authURL response; err = "+ma.message,40170,401));return}}b(null,c)}else b(new q("authUrl responded with unacceptable content-type "+a+", should be either text/plain, application/jwt or application/json",40170,401));else b(new q("authUrl response is missing a content-type header",40170,401))}var g=h.mixin({accept:"application/json, text/plain"}, +c.authHeaders),f=c.authMethod&&"post"===c.authMethod.toLowerCase();if(!f){var m=c.authUrl.indexOf("?");if(-1n&&!c.suppressMaxLengthCheck?e(new q("Token request/details object exceeded max permitted stringified size (was "+f+" bytes)",40170,401)):"issued"in b?e(null,b):"keyName"in b?g(b,function(a,b,c,g){a?(d.logAction(d.LOG_ERROR,"Auth.requestToken()","token request API call returned error; err = "+h.inspectError(a)),e(l(a))):(g||(b=JSON.parse(b)),d.logAction(d.LOG_MINOR,"Auth.getToken()","token received"),e(null,b))}):(f="Expected token request callback to call back with a token string, token request object, or token details object", +d.logAction(d.LOG_ERROR,"Auth.requestToken()",f),e(new q(f,40170,401)))})};c.prototype.createTokenRequest=function(a,b,c){"function"!=typeof a||c?"function"!=typeof b||c||(c=b,b=null):(c=a,b=a=null);if(!c&&this.client.options.promises)return h.promisify(this,"createTokenRequest",arguments);b=b||this.authOptions;a=a||h.copy(this.tokenParams);var e=b.key;if(e){e=e.split(":");var g=e[0],k=e[1];if(k)if(""===a.clientId)c(new q("clientId can\u2019t be an empty string",40012,400));else{"capability"in a&& +(a.capability=f(a.capability));var n=h.mixin({keyName:g},a),t=a.clientId||"",p=a.ttl||"",l=a.capability||"",r=this;(function(a){n.timestamp?a():r.getTimestamp(b&&b.queryTime,function(b,d){b?c(b):(n.timestamp=d,a())})})(function(){var a=n.nonce||(n.nonce=("000000"+Math.floor(1E16*Math.random())).slice(-16));a=n.keyName+"\n"+p+"\n"+l+"\n"+t+"\n"+n.timestamp+"\n"+a+"\n";n.mac=n.mac||m(a,k);d.logAction(d.LOG_MINOR,"Auth.getTokenRequest()","generated signed request");c(null,n)})}else c(new q("Invalid key specified", +40101,403))}else c(new q("No key specified",40101,403))};c.prototype.getAuthParams=function(a){"basic"==this.method?a(null,{key:this.key}):this._ensureValidAuthCredentials(!1,function(b,c){b?a(b):a(null,{access_token:c.token})})};c.prototype.getAuthHeaders=function(a){"basic"==this.method?a(null,{authorization:"Basic "+this.basicKey}):this._ensureValidAuthCredentials(!1,function(b,c){b?a(b):a(null,{authorization:"Bearer "+e(c.token)})})};c.prototype.getTimestamp=function(a,b){this.isTimeOffsetSet()|| +!a&&!this.authOptions.queryTime?b(null,this.getTimestampUsingOffset()):this.client.time(b)};c.prototype.getTimestampUsingOffset=function(){return h.now()+(this.client.serverTimeOffset||0)};c.prototype.isTimeOffsetSet=function(){return null!==this.client.serverTimeOffset};c.prototype._saveBasicOptions=function(a){this.method="basic";this.key=a.key;this.basicKey=e(a.key);this.authOptions=a||{};"clientId"in a&&this._userSetClientId(a.clientId)};c.prototype._saveTokenOptions=function(a,b){this.method= +"token";a&&(this.tokenParams=a);b&&(b.token&&(b.tokenDetails="string"===typeof b.token?{token:b.token}:b.token),b.tokenDetails&&(this.tokenDetails=b.tokenDetails),"clientId"in b&&this._userSetClientId(b.clientId),this.authOptions=b)};c.prototype._ensureValidAuthCredentials=function(a,c){var e=this,g=this.tokenDetails;if(g){if(this._tokenClientIdMismatch(g.clientId)){c(new q("Mismatch between clientId in token ("+g.clientId+") and current clientId ("+this.clientId+")",40102,403));return}if(!this.isTimeOffsetSet()|| +!g.expires||g.expires>=this.getTimestampUsingOffset()){d.logAction(d.LOG_MINOR,"Auth.getToken()","using cached token; expires = "+g.expires);c(null,g);return}d.logAction(d.LOG_MINOR,"Auth.getToken()","deleting expired token");this.tokenDetails=null}(this.waitingForTokenRequest||(this.waitingForTokenRequest=W())).push(c);if(null===this.currentTokenRequestId||a){var f=this.currentTokenRequestId=t++;this.requestToken(this.tokenParams,this.authOptions,function(a,c){if(e.currentTokenRequestId>f)d.logAction(d.LOG_MINOR, +"Auth._ensureValidAuthCredentials()","Discarding token request response; overtaken by newer one");else{e.currentTokenRequestId=null;var g=e.waitingForTokenRequest||b;e.waitingForTokenRequest=null;a?g(a):g(null,e.tokenDetails=c)}})}};c.prototype._userSetClientId=function(a){if("string"!==typeof a&&null!==a)throw new q("clientId must be either a string or null",40012,400);if("*"===a)throw new q('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, instantiate the library with {defaultTokenParams: {clientId: "*"}}), or if calling authorize(), pass it in as a tokenParam: authorize({clientId: "*"}, authOptions)', +40012,400);if(a=this._uncheckedSetClientId(a))throw a;};c.prototype._uncheckedSetClientId=function(a){if(this._tokenClientIdMismatch(a)){a="Unexpected clientId mismatch: client has "+this.clientId+", requested "+a;var b=new q(a,40102,401);d.logAction(d.LOG_ERROR,"Auth._uncheckedSetClientId()",a);return b}this.clientId=this.tokenParams.clientId=a;return null};c.prototype._tokenClientIdMismatch=function(a){return this.clientId&&"*"!==this.clientId&&a&&"*"!==a&&this.clientId!==a};c.isTokenErr=function(a){return a.code&& +40140<=a.code&&40150>a.code};return c}(),B=function(){function b(){}function l(a){if(!(this instanceof l))return new l(a);if(!a){var b="no options provided";d.logAction(d.LOG_ERROR,"Rest()",b);throw Error(b);}a=r.objectifyOptions(a);a.log&&d.setLog(a.log.level,a.log.handler);d.logAction(d.LOG_MICRO,"Rest()","initialized with clientOptions "+h.inspect(a));this.options=r.normaliseOptions(a);if(a.key){b=a.key.match(/^([^:\s]+):([^:.\s]+)$/);if(!b)throw b="invalid key parameter",d.logAction(d.LOG_ERROR, +"Rest()",b),Error(b);a.keyName=b[1];a.keySecret=b[2]}if("clientId"in a){if("string"!==typeof a.clientId&&null!==a.clientId)throw new q("clientId must be either a string or null",40012,400);if("*"===a.clientId)throw new q('Can\u2019t use "*" as a clientId as that string is reserved. (To change the default token request behaviour to use a wildcard clientId, use {defaultTokenParams: {clientId: "*"}})',40012,400);}d.logAction(d.LOG_MINOR,"Rest()","started; version = "+r.libstring);this.baseUri=this.authority= +function(b){return r.getHttpScheme(a)+b+":"+r.getPort(a,!1)};this.serverTimeOffset=this._currentFallback=null;this.auth=new L(this,a);this.channels=new f(this);this.push=new na(this)}function f(a){this.rest=a;this.attached={}}var a=u.msgpack;l.prototype.stats=function(a,d){if(void 0===d)if("function"==typeof a)d=a,a=null;else{if(this.options.promises)return h.promisify(this,"stats",arguments);d=b}var c=h.defaultGetHeaders(),f=this.options.useBinaryProtocol?"msgpack":"json";f=v.supportsLinkHeaders? +void 0:f;this.options.headers&&h.mixin(c,this.options.headers);(new N(this,"/stats",c,f,function(a,b,c){a=c?a:JSON.parse(a);for(b=0;bb?d(new p("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+ -b+" bytes)",40009,400)):e._publish(A.serialize(n,g),l,m,d)}})};l.prototype._publish=function(a,b,d,e){E.post(this.rest,this.basePath+"/messages",a,b,d,!1,e)};return l}(),P=function(){function b(){}function l(a,b,f){d.logAction(d.LOG_MINOR,"RealtimeChannel()","started; name = "+b);T.call(this,a,b,f);this.realtime=a;this.presence=new na(this,a.options);this.connectionManager=a.connection.connectionManager;this.state="initialized";this.subscriptions=new y;this.syncChannelSerial=void 0;this.properties= -{attachSerial:void 0};this.setOptions(f);this._mode=this._requestedFlags=this.errorReason=null}var f=w.Action;h.inherits(l,T);l.invalidStateError=function(a){return{statusCode:400,code:90001,message:"Channel operation failed as channel state is "+a}};l.progressOps={statechange:"statechange",sync:"sync"};l.processListenerArgs=function(a){a=Array.prototype.slice.call(a);"function"===typeof a[0]&&a.unshift(null);void 0==a[a.length-1]&&a.pop();return a};l.prototype.publish=function(){var a=arguments.length, -c=arguments[0],d=arguments[a-1];if("function"!==typeof d){if(this.realtime.options.promises)return h.promisify(this,"publish",arguments);d=b;++a}if(this.connectionManager.activeState()){if(2==a)if(h.isObject(c))c=[A.fromValues(c)];else if(h.isArray(c))c=A.fromValuesArray(c);else throw new p("The single-argument form of publish() expects a message object or an array of message objects",40013,400);else c=[A.fromValues({name:arguments[0],data:arguments[1]})];var e=this,f=this.realtime.options.maxMessageSize; -A.encodeArray(c,this.channelOptions,function(a){a?d(a):(a=A.getMessagesSize(c),a>f?d(new p("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+f+" bytes)",40009,400)):e._publish(c,d))})}else d(this.connectionManager.getError())};l.prototype._publish=function(a,b){d.logAction(d.LOG_MICRO,"RealtimeChannel.publish()","message count = "+a.length);var c=this.state;switch(c){case "failed":case "suspended":b(p.fromValues(l.invalidStateError(c)));break;default:d.logAction(d.LOG_MICRO, +"detaching","suspended"],d={closing:"detached",closed:"detached",failed:"failed",suspended:"suspended"}[b],e;for(e in this.all){var f=this.all[e];h.arrIn(c,f.state)&&f.notifyState(d,a)}};l.prototype.get=function(b,a){b=String(b);var c=this.all[b];c?a&&c.setOptions(a):c=this.all[b]=new Q(this.realtime,b,a);return c};l.prototype.release=function(b){this.all[b]&&delete this.all[b]};l.prototype.setInProgress=function(b,a,c){this.inProgress[b.name]=this.inProgress[b.name]||{};this.inProgress[b.name][a]= +c;!c&&this.hasNopending()&&this.emit("nopending")};l.prototype.onceNopending=function(b){if(this.hasNopending())b();else this.once("nopending",b)};l.prototype.hasNopending=function(){return h.arrEvery(h.valuesArray(this.inProgress,!0),function(b){return!h.containsValue(b,!0)})};return b}();C.Promise=function(b){b=r.objectifyOptions(b);b.promises=!0;return new C(b)};C.Callbacks=C;var R=function(){return function(b,d,f,a){this.previous=b;this.current=d;f&&(this.retryIn=f);a&&(this.reason=a)}}(),Y=function(){return function(b, +d,f,a){this.previous=b;this.current=d;"attached"===d&&(this.resumed=f);a&&(this.reason=a)}}(),oa=function(){function b(){}function l(b,a){x.call(this);this.ably=b;this.connectionManager=new M(b,a);this.state=this.connectionManager.state.state;this.recoveryKey=this.timeSerial=this.serial=this.id=this.key=void 0;this.errorReason=null;var c=this;this.connectionManager.on("connectionstate",function(a){var b=c.state=a.current;h.nextTick(function(){c.emit(b,a)})});this.connectionManager.on("update",function(a){h.nextTick(function(){c.emit("update", +a)})})}h.inherits(l,x);l.prototype.whenState=function(b,a){x.prototype.whenState.call(this,b,this.state,a,new R(void 0,b))};l.prototype.connect=function(){d.logAction(d.LOG_MINOR,"Connection.connect()","");this.connectionManager.requestState({state:"connecting"})};l.prototype.ping=function(f){d.logAction(d.LOG_MINOR,"Connection.ping()","");if(!f){if(this.ably.options.promises)return h.promisify(this,"ping",arguments);f=b}this.connectionManager.ping(null,f)};l.prototype.close=function(){d.logAction(d.LOG_MINOR, +"Connection.close()","connectionKey = "+this.key);this.connectionManager.requestState({state:"closing"})};return l}(),na=function(){function b(){}function d(b){this.rest=b;this.deviceRegistrations=new f(b);this.channelSubscriptions=new a(b)}function f(a){this.rest=a}function a(a){this.rest=a}d.prototype.publish=function(a,d,e){var c=this.rest,f=c.options.useBinaryProtocol?"msgpack":"json",k=h.mixin({recipient:a},d),g=h.defaultPostHeaders(f),n={};if("function"!==typeof e){if(this.rest.options.promises)return h.promisify(this, +"publish",arguments);e=b}c.options.headers&&h.mixin(g,c.options.headers);c.options.pushFullWait&&h.mixin(n,{fullWait:"true"});k=h.encodeBody(k,f);H.post(c,"/push/publish",k,g,n,!1,function(a){e(a)})};f.prototype.save=function(a,d){var c=this.rest,f=c.options.useBinaryProtocol?"msgpack":"json",n=S.fromValues(a),k=h.defaultPostHeaders(f),g={};if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"save",arguments);d=b}c.options.headers&&h.mixin(k,c.options.headers);c.options.pushFullWait&& +h.mixin(g,{fullWait:"true"});n=h.encodeBody(n,f);H.put(c,"/push/deviceRegistrations/"+encodeURIComponent(a.id),n,k,g,!1,function(a,b,c,e){d(a,!a&&S.fromResponseBody(b,!e&&f))})};f.prototype.get=function(a,d){var c=this.rest,f=c.options.useBinaryProtocol?"msgpack":"json",n=h.defaultGetHeaders(f),k=a.id||a;if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"get",arguments);d=b}"string"===typeof k&&k.length?(c.options.headers&&h.mixin(n,c.options.headers),H.get(c,"/push/deviceRegistrations/"+ +encodeURIComponent(k),n,{},!1,function(a,b,c,e){d(a,!a&&S.fromResponseBody(b,!e&&f))})):d(new q("First argument to DeviceRegistrations#get must be a deviceId string or DeviceDetails",4E4,400))};f.prototype.list=function(a,d){var c=this.rest,f=c.options.useBinaryProtocol?"msgpack":"json",n=v.supportsLinkHeaders?void 0:f,k=h.defaultGetHeaders(f);if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"list",arguments);d=b}c.options.headers&&h.mixin(k,c.options.headers);(new N(c, +"/push/deviceRegistrations",k,n,function(a,b,c){return S.fromResponseBody(a,!c&&f)})).get(a,d)};f.prototype.remove=function(a,d){var c=this.rest,f=h.defaultGetHeaders(c.options.useBinaryProtocol?"msgpack":"json"),n={},k=a.id||a;if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"remove",arguments);d=b}"string"===typeof k&&k.length?(c.options.headers&&h.mixin(f,c.options.headers),c.options.pushFullWait&&h.mixin(n,{fullWait:"true"}),H["delete"](c,"/push/deviceRegistrations/"+ +encodeURIComponent(k),f,n,!1,function(a){d(a)})):d(new q("First argument to DeviceRegistrations#remove must be a deviceId string or DeviceDetails",4E4,400))};f.prototype.removeWhere=function(a,d){var c=this.rest,f=h.defaultGetHeaders(c.options.useBinaryProtocol?"msgpack":"json");if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"removeWhere",arguments);d=b}c.options.headers&&h.mixin(f,c.options.headers);c.options.pushFullWait&&h.mixin(a,{fullWait:"true"});H["delete"](c, +"/push/deviceRegistrations",f,a,!1,function(a){d(a)})};a.prototype.save=function(a,d){var c=this.rest,f=c.options.useBinaryProtocol?"msgpack":"json",n=X.fromValues(a),k=h.defaultPostHeaders(f),g={};if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"save",arguments);d=b}c.options.headers&&h.mixin(k,c.options.headers);c.options.pushFullWait&&h.mixin(g,{fullWait:"true"});n=h.encodeBody(n,f);H.post(c,"/push/channelSubscriptions",n,k,g,!1,function(a,b,c,e){d(a,!a&&X.fromResponseBody(b, +!e&&f))})};a.prototype.list=function(a,d){var c=this.rest,f=c.options.useBinaryProtocol?"msgpack":"json",n=v.supportsLinkHeaders?void 0:f,k=h.defaultGetHeaders(f);if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"list",arguments);d=b}c.options.headers&&h.mixin(k,c.options.headers);(new N(c,"/push/channelSubscriptions",k,n,function(a,b,c){return X.fromResponseBody(a,!c&&f)})).get(a,d)};a.prototype.removeWhere=function(a,d){var c=this.rest,f=h.defaultGetHeaders(c.options.useBinaryProtocol? +"msgpack":"json");if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"removeWhere",arguments);d=b}c.options.headers&&h.mixin(f,c.options.headers);c.options.pushFullWait&&h.mixin(a,{fullWait:"true"});H["delete"](c,"/push/channelSubscriptions",f,a,!1,function(a){d(a)})};a.prototype.remove=a.prototype.removeWhere;a.prototype.listChannels=function(a,d){var c=this.rest,f=c.options.useBinaryProtocol?"msgpack":"json",n=v.supportsLinkHeaders?void 0:f,k=h.defaultGetHeaders(f); +if("function"!==typeof d){if(this.rest.options.promises)return h.promisify(this,"listChannels",arguments);d=b}c.options.headers&&h.mixin(k,c.options.headers);c.options.pushFullWait&&h.mixin(a,{fullWait:"true"});(new N(c,"/push/channels",k,n,function(a,b,c){!c&&f&&(a=h.decodeBody(a,f));for(b=0;bb?d(new q("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+ +b+" bytes)",40009,400)):e._publish(z.serialize(m,g),l,t,d)}})};l.prototype._publish=function(a,b,d,e){H.post(this.rest,this.basePath+"/messages",a,b,d,!1,e)};return l}(),Q=function(){function b(){}function l(a,b,f){d.logAction(d.LOG_MINOR,"RealtimeChannel()","started; name = "+b);U.call(this,a,b,f);this.realtime=a;this.presence=new pa(this,a.options);this.connectionManager=a.connection.connectionManager;this.state="initialized";this.subscriptions=new x;this.syncChannelSerial=void 0;this.properties= +{attachSerial:void 0};this.setOptions(f);this._mode=this._requestedFlags=this.errorReason=null}var f=w.Action;h.inherits(l,U);l.invalidStateError=function(a){return{statusCode:400,code:90001,message:"Channel operation failed as channel state is "+a}};l.progressOps={statechange:"statechange",sync:"sync"};l.processListenerArgs=function(a){a=Array.prototype.slice.call(a);"function"===typeof a[0]&&a.unshift(null);void 0==a[a.length-1]&&a.pop();return a};l.prototype.publish=function(){var a=arguments.length, +c=arguments[0],d=arguments[a-1];if("function"!==typeof d){if(this.realtime.options.promises)return h.promisify(this,"publish",arguments);d=b;++a}if(this.connectionManager.activeState()){if(2==a)if(h.isObject(c))c=[z.fromValues(c)];else if(h.isArray(c))c=z.fromValuesArray(c);else throw new q("The single-argument form of publish() expects a message object or an array of message objects",40013,400);else c=[z.fromValues({name:arguments[0],data:arguments[1]})];var e=this,f=this.realtime.options.maxMessageSize; +z.encodeArray(c,this.channelOptions,function(a){a?d(a):(a=z.getMessagesSize(c),a>f?d(new q("Maximum size of messages that can be published at once exceeded ( was "+a+" bytes; limit is "+f+" bytes)",40009,400)):e._publish(c,d))})}else d(this.connectionManager.getError())};l.prototype._publish=function(a,b){d.logAction(d.LOG_MICRO,"RealtimeChannel.publish()","message count = "+a.length);var c=this.state;switch(c){case "failed":case "suspended":b(q.fromValues(l.invalidStateError(c)));break;default:d.logAction(d.LOG_MICRO, "RealtimeChannel.publish()","sending message; channel state is "+c),c=new w,c.action=f.MESSAGE,c.channel=this.name,c.messages=a,this.sendMessage(c,b)}};l.prototype.onEvent=function(a){d.logAction(d.LOG_MICRO,"RealtimeChannel.onEvent()","received message");for(var b=this.subscriptions,f=0;fb.timestamp;var c=a.parseId(),d=b.parseId();return c.msgSerial===d.msgSerial?c.index>d.index:c.msgSerial>d.msgSerial}h.inherits(a,S);a.prototype.enter=function(a,b){if(l(this))throw new p("clientId must be specified to enter a presence channel",40012,400);return this._enterOrUpdateClient(void 0,a,"enter",b)};a.prototype.update=function(a,b){if(l(this))throw new p("clientId must be specified to update presence data",40012,400);return this._enterOrUpdateClient(void 0, +this.realtime.options.timeouts.channelRetryTimeout))};l.prototype.cancelRetryTimer=function(){this.retryTimer&&(clearTimeout(this.retryTimer),this.suspendTimer=null)};l.prototype.setInProgress=function(a,b){this.rest.channels.setInProgress(this,a,b)};l.prototype.history=function(a,c){d.logAction(d.LOG_MICRO,"RealtimeChannel.history()","channel = "+this.name);void 0===c&&("function"==typeof a?(c=a,a=null):c=b);if(a&&a.untilAttach){if("attached"!==this.state){c(new q("option untilAttach requires the channel to be attached", +4E4,400));return}if(!this.properties.attachSerial){c(new q("untilAttach was specified and channel is attached, but attachSerial is not defined",4E4,400));return}delete a.untilAttach;a.from_serial=this.properties.attachSerial}U.prototype._history.call(this,a,c)};l.prototype.whenState=function(a,b){x.prototype.whenState.call(this,a,this.state,b)};return l}(),pa=function(){function b(){}function l(a){a=a.channel.realtime;var b=a.auth.clientId;return(!b||"*"===b)&&"connected"===a.connection.state}function f(a, +b,c){switch(a.state){case "attached":case "suspended":c();break;case "initialized":case "detached":case "detaching":case "attaching":a.attach(function(a){a?b(a):c()});break;default:b(q.fromValues(Q.invalidStateError(a.state)))}}function a(a){T.call(this,a);this.syncComplete=!1;this.members=new c(this);this._myMembers=new c(this);this.subscriptions=new x;this.pendingPresence=[]}function c(a){x.call(this);this.presence=a;this.map={};this.syncInProgress=!1;this.residualMembers=null}function n(a,b){if(a.isSynthesized()|| +b.isSynthesized())return a.timestamp>b.timestamp;var c=a.parseId(),d=b.parseId();return c.msgSerial===d.msgSerial?c.index>d.index:c.msgSerial>d.msgSerial}h.inherits(a,T);a.prototype.enter=function(a,b){if(l(this))throw new q("clientId must be specified to enter a presence channel",40012,400);return this._enterOrUpdateClient(void 0,a,"enter",b)};a.prototype.update=function(a,b){if(l(this))throw new q("clientId must be specified to update presence data",40012,400);return this._enterOrUpdateClient(void 0, a,"update",b)};a.prototype.enterClient=function(a,b,c){return this._enterOrUpdateClient(a,b,"enter",c)};a.prototype.updateClient=function(a,b,c){return this._enterOrUpdateClient(a,b,"update",c)};a.prototype._enterOrUpdateClient=function(a,c,f,k){if(!k)if("function"===typeof c)k=c,c=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"_enterOrUpdateClient",[a,c,f]);k=b}var e=this.channel;if(e.connectionManager.activeState()){d.logAction(d.LOG_MICRO,"RealtimePresence."+f+"Client()", -"channel = "+e.name+", client = "+(a||"(implicit) "+this.channel.realtime.auth.clientId));var m=C.fromValues({action:f,data:c});a&&(m.clientId=a);var n=this;C.encode(m,e.channelOptions,function(a){if(a)k(a);else switch(e.state){case "attached":e.sendPresence(m,k);break;case "initialized":case "detached":e.attach();case "attaching":n.pendingPresence.push({presence:m,callback:k});break;default:a=new p("Unable to "+f+" presence channel (incompatible state)",90001),a.code=90001,k(a)}})}else k(e.connectionManager.getError())}; -a.prototype.leave=function(a,b){if(l(this))throw new p("clientId must have been specified to enter or leave a presence channel",40012,400);return this.leaveClient(void 0,a,b)};a.prototype.leaveClient=function(a,c,f){if(!f)if("function"===typeof c)f=c,c=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"leaveClient",[a,c]);f=b}var e=this.channel;if(e.connectionManager.activeState())switch(d.logAction(d.LOG_MICRO,"RealtimePresence.leaveClient()","leaving; channel = "+this.channel.name+ -", client = "+a),c=C.fromValues({action:"leave",data:c}),a&&(c.clientId=a),e.state){case "attached":e.sendPresence(c,f);break;case "attaching":this.pendingPresence.push({presence:c,callback:f});break;case "initialized":case "failed":a=new p("Unable to leave presence channel (incompatible state)",90001);f(a);break;default:f(J.failed)}else f(e.connectionManager.getError())};a.prototype.get=function(){function a(a){k(null,d?a.list(d):a.values())}var c=Array.prototype.slice.call(arguments);1==c.length&& -"function"==typeof c[0]&&c.unshift(null);var d=c[0],k=c[1],g=!d||("waitForSync"in d?d.waitForSync:!0);if(!k){if(this.channel.realtime.options.promises)return h.promisify(this,"get",c);k=b}if("suspended"===this.channel.state)g?k(p.fromValues({statusCode:400,code:91005,message:"Presence state is out of sync due to channel being in the SUSPENDED state"})):a(this.members);else{var l=this;f(this.channel,k,function(){var b=l.members;g?b.waitSync(function(){a(b)}):a(b)})}};a.prototype.history=function(a, -c){d.logAction(d.LOG_MICRO,"RealtimePresence.history()","channel = "+this.name);if(void 0===c)if("function"==typeof a)c=a,a=null;else{if(this.channel.realtime.options.promises)return h.promisify(this,"history",arguments);c=b}a&&a.untilAttach&&("attached"===this.channel.state?(delete a.untilAttach,a.from_serial=this.channel.properties.attachSerial):c(new p("option untilAttach requires the channel to be attached, was: "+this.channel.state,4E4,400)));S.prototype._history.call(this,a,c)};a.prototype.setPresence= -function(a,b,c){d.logAction(d.LOG_MICRO,"RealtimePresence.setPresence()","received presence for "+a.length+" participants; syncChannelSerial = "+c);var e,g,f=this.members,h=this._myMembers,m=[],n=this.channel.connectionManager.connectionId;b&&(this.members.startSync(),c&&(g=c.match(/^[\w\-]+:(.*)$/))&&(e=g[1]));for(c=0;ca)&&0!==t.status){if(void 0===x)if(x=t.status,1223===x&&(x=204),clearTimeout(f),C=400>x,204==x)e.complete(null,null,null,null,x);else{var d;if(d=3==e.requestMode&&C)d=t,d=d.getResponseHeader&&(d.getResponseHeader("transfer-encoding")||!d.getResponseHeader("content-length")); -A=d}if(3==a&&A)b();else if(4==a)if(A)c();else a:{try{var g=t.getResponseHeader&&t.getResponseHeader("content-type");if(g?0<=g.indexOf("application/json"):"text"==t.responseType){var k="arraybuffer"===t.responseType?z.utf8Decode(t.response):String(t.responseText);k.length&&(k=JSON.parse(k));E=!0}else k=t.response;if(void 0!==k.response){x=k.statusCode;C=400>x;var l=k.headers;k=k.response}else{var m=h.trim(t.getAllResponseHeaders()).split("\r\n");a={};for(g=0;ga.statusCode||h.isArray(b)?n.complete(null,b,a.headers,a.statusCode):(a=b.error||new p("Error response received from server",null,a.statusCode),n.complete(a)):n.complete(new p("Invalid server response: no envelope detected",null,500))}else n.complete(null,a)};this.timer=setTimeout(function(){n.abort()},this.requestMode==K.REQ_SEND?this.timeouts.httpRequestTimeout: -this.timeouts.recvTimeout);q.insertBefore(c,q.firstChild)};f.prototype.complete=function(a,b,c,d){c=c||{};this.requestComplete||(this.requestComplete=!0,b&&(c["content-type"]="string"==typeof b?"text/plain":"application/json",this.emit("data",b)),this.emit("complete",a,b,c,!0,d),this.dispose())};f.prototype.abort=function(){this.dispose()};f.prototype.dispose=function(){var b=this.timer;b&&(clearTimeout(b),this.timer=null);b=this.script;b.parentNode&&b.parentNode.removeChild(b);delete a[this.id]; -this.emit("disposed")};t.jsonpSupported&&!v.Request&&(v.Request=function(a,b,c,d,e,f,l){var g=n(c,d,e,f,K.REQ_SEND,b&&b.options.timeouts,a);g.once("complete",l);h.nextTick(function(){g.exec()});return g},v.checkConnectivity=function(a){var b=r.jsonpInternetUpUrl;if(e)e.push(a);else{e=[a];d.logAction(d.LOG_MICRO,"(JSONP)Http.checkConnectivity()","Sending; "+b);var c=new f("isTheInternetUp",b,null,null,null,K.REQ_SEND,r.TIMEOUTS);c.once("complete",function(a,b){var c=!a&&b;d.logAction(d.LOG_MICRO,"(JSONP)Http.checkConnectivity()", -"Result: "+c);for(var f=0;fa)&&0!==u.status){if(void 0===A)if(A=u.status,1223===A&&(A=204),clearTimeout(f),C=400>A,204==A)e.complete(null,null,null,null,A);else{var d;if(d=3==e.requestMode&&C)d=u,d=d.getResponseHeader&&(d.getResponseHeader("transfer-encoding")||!d.getResponseHeader("content-length")); +z=d}if(3==a&&z)b();else if(4==a)if(z)c();else a:{try{var g=u.getResponseHeader&&u.getResponseHeader("content-type");if(g?0<=g.indexOf("application/json"):"text"==u.responseType){var k="arraybuffer"===u.responseType?y.utf8Decode(u.response):String(u.responseText);k.length&&(k=JSON.parse(k));F=!0}else k=u.response;if(void 0!==k.response){A=k.statusCode;C=400>A;var l=k.headers;k=k.response}else{var m=h.trim(u.getAllResponseHeaders()).split("\r\n");a={};for(g=0;ga.statusCode||h.isArray(b)?m.complete(null,b,a.headers,a.statusCode):(a=b.error||new q("Error response received from server",null,a.statusCode),m.complete(a)):m.complete(new q("Invalid server response: no envelope detected",null,500))}else m.complete(null,a)};this.timer=setTimeout(function(){m.abort()},this.requestMode==K.REQ_SEND?this.timeouts.httpRequestTimeout: +this.timeouts.recvTimeout);n.insertBefore(c,n.firstChild)};f.prototype.complete=function(a,b,c,d){c=c||{};this.requestComplete||(this.requestComplete=!0,b&&(c["content-type"]="string"==typeof b?"text/plain":"application/json",this.emit("data",b)),this.emit("complete",a,b,c,!0,d),this.dispose())};f.prototype.abort=function(){this.dispose()};f.prototype.dispose=function(){var b=this.timer;b&&(clearTimeout(b),this.timer=null);b=this.script;b.parentNode&&b.parentNode.removeChild(b);delete a[this.id]; +this.emit("disposed")};u.jsonpSupported&&!v.Request&&(v.Request=function(a,b,c,d,e,f,l){var g=m(c,d,e,f,K.REQ_SEND,b&&b.options.timeouts,a);g.once("complete",l);h.nextTick(function(){g.exec()});return g},v.checkConnectivity=function(a){var b=r.jsonpInternetUpUrl;if(e)e.push(a);else{e=[a];d.logAction(d.LOG_MICRO,"(JSONP)Http.checkConnectivity()","Sending; "+b);var c=new f("isTheInternetUp",b,null,null,null,K.REQ_SEND,r.TIMEOUTS);c.once("complete",function(a,b){var c=!a&&b;d.logAction(d.LOG_MICRO,"(JSONP)Http.checkConnectivity()", +"Result: "+c);for(var f=0;f