UNPKG

metaapi.cloud-sdk

Version:

SDK for MetaApi, a professional cloud forex API which includes MetaTrader REST API and MetaTrader websocket API. Supports both MetaTrader 5 (MT5) and MetaTrader 4 (MT4). CopyFactory copy trading API included. (https://metaapi.cloud)

229 lines (228 loc) 27.4 kB
'use strict'; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _async_to_generator(fn) { return function() { var self = this, args = arguments; return new Promise(function(resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _define_property(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import SynchronizationListener from '../clients/metaApi/synchronizationListener'; import LoggerManager from '../logger'; let MetaApiConnection = class MetaApiConnection extends SynchronizationListener { /** * Opens the connection. Can only be called the first time, next calls will be ignored. * @param {string} instanceId connection instance id * @return {Promise} promise resolving when the connection is opened */ connect(instanceId) { return _async_to_generator(function*() {})(); } /** * Closes the connection. The instance of the class should no longer be used after this method is invoked. * @param {string} instanceId connection instance id */ close(instanceId) { return _async_to_generator(function*() {})(); } /** * Returns MetaApi account * @return {MetatraderAccount} MetaApi account */ get account() { return this._account; } /** * Returns connection application * @return {String} connection application */ get application() { return this._application; } /** * Schedules the refresh task * @param {string} region replica region */ scheduleRefresh(region) { if (!this._refreshTasks[region]) { var _this__options_connections; var _this__options_connections_refreshReplicasMaxDelayInMs; const delay = Math.random() * ((_this__options_connections_refreshReplicasMaxDelayInMs = (_this__options_connections = this._options.connections) === null || _this__options_connections === void 0 ? void 0 : _this__options_connections.refreshReplicasMaxDelayInMs) !== null && _this__options_connections_refreshReplicasMaxDelayInMs !== void 0 ? _this__options_connections_refreshReplicasMaxDelayInMs : 6 * 60 * 60 * 1000); this._refreshTasks[region] = setTimeout(this._refreshReplicas, delay); } } /** * Cancels the scheduled refresh task * @param {string} region replica region */ cancelRefresh(region) { clearTimeout(this._refreshTasks[region]); delete this._refreshTasks[region]; } /** * Refreshes account replicas */ _refreshReplicas() { var _this = this; return _async_to_generator(function*() { Object.values(_this._refreshTasks).forEach((task)=>clearTimeout(task)); _this._refreshTasks = {}; const oldReplicas = {}; _this._account.replicas.forEach((replica)=>oldReplicas[replica.region] = replica.id); const newReplicas = {}; let isAccountUpdated = false; try { yield _this._account.reload(); isAccountUpdated = true; _this._account.replicas.forEach((replica)=>newReplicas[replica.region] = replica.id); } catch (error) { if (error.name === 'NotFoundError') { if (_this._connectionRegistry) { _this._connectionRegistry.closeAllInstances(_this._account.id); } } } if (isAccountUpdated) { const deletedReplicas = {}; const addedReplicas = {}; Object.keys(oldReplicas).forEach((key)=>{ if (newReplicas[key] !== oldReplicas[key]) { deletedReplicas[key] = oldReplicas[key]; } }); Object.keys(newReplicas).forEach((key)=>{ if (newReplicas[key] !== oldReplicas[key]) { addedReplicas[key] = newReplicas[key]; } }); if (Object.keys(deletedReplicas).length) { Object.values(deletedReplicas).forEach((replicaId)=>_this._websocketClient.onAccountDeleted(replicaId)); } if (Object.keys(deletedReplicas).length || Object.keys(addedReplicas).length) { newReplicas[_this._account.region] = _this._account.id; _this._websocketClient.updateAccountCache(_this._account.id, newReplicas); Object.entries(_this._account.accountRegions).forEach(([region, instance])=>{ if (!_this._options.region || _this._options.region === region) { _this._websocketClient.ensureSubscribe(instance, 0); _this._websocketClient.ensureSubscribe(instance, 1); } }); } } })(); } _ensureSynchronized(instanceIndex, key) { var _this = this; return _async_to_generator(function*() { let state = _this._getState(instanceIndex); if (state && !_this._closed) { try { const synchronizationResult = yield _this.synchronize(instanceIndex); if (synchronizationResult) { state.synchronized = true; state.synchronizationRetryIntervalInSeconds = 1; } } catch (err) { const level = _this._latencyService.getSynchronizedAccountInstances(_this._account.id).length ? 'debug' : 'error'; _this._logger[level]('MetaApi websocket client for account ' + _this._account.id + ':' + instanceIndex + ' failed to synchronize', err); if (state.shouldSynchronize === key) { setTimeout(_this._ensureSynchronized.bind(_this, instanceIndex, key), state.synchronizationRetryIntervalInSeconds * 1000); state.synchronizationRetryIntervalInSeconds = Math.min(state.synchronizationRetryIntervalInSeconds * 2, 300); } } } })(); } synchronize(instanceIndex) { return undefined; } _getState(instanceIndex) { if (!this._stateByInstanceIndex['' + instanceIndex]) { this._stateByInstanceIndex['' + instanceIndex] = { instanceIndex, ordersSynchronized: {}, dealsSynchronized: {}, shouldSynchronize: undefined, synchronizationRetryIntervalInSeconds: 1, synchronized: false, lastDisconnectedSynchronizationId: undefined, lastSynchronizationId: undefined, disconnected: false }; } return this._stateByInstanceIndex['' + instanceIndex]; } _checkIsConnectionActive() { if (!this._opened) { throw new Error('This connection has not been initialized yet, please invoke await connection.connect()'); } if (this._closed) { throw new Error('This connection has been closed, please create a new connection'); } } /** * @typedef Config MetaApi options for connections * @property {Options} [connections] MetaApi connections options. Only for tests. Will be ignored when set in SDK */ /** * @typedef Options MetaApiConnection options * @property {number} [refreshReplicasMaxDelayInMs = 6 * 60 * 60 * 1000] max delay before refreshing replicas delay */ /** * Constructs MetaApi MetaTrader Api connection * @param {MetaApiOpts & Config} options MetaApi options * @param {MetaApiWebsocketClient} websocketClient MetaApi websocket client * @param {MetatraderAccount} account MetaTrader account id to connect to * @param {String} [application] application to use */ constructor(options, websocketClient, account, application){ super(); _define_property(this, "_options", void 0); _define_property(this, "_websocketClient", void 0); _define_property(this, "_latencyService", void 0); _define_property(this, "_account", void 0); _define_property(this, "_logger", void 0); _define_property(this, "_application", void 0); _define_property(this, "_refreshTasks", void 0); _define_property(this, "_connectionRegistry", void 0); _define_property(this, "_closed", void 0); _define_property(this, "_stateByInstanceIndex", void 0); _define_property(this, "_opened", void 0); this._options = options; this._websocketClient = websocketClient; this._latencyService = websocketClient.latencyService; this._account = account; this._logger = LoggerManager.getLogger('MetaApiConnection'); this._application = application; this._refreshReplicas = this._refreshReplicas.bind(this); this._refreshTasks = {}; } }; /** * Exposes MetaApi MetaTrader API connection to consumers */ export { MetaApiConnection as default }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBNZXRhQXBpV2Vic29ja2V0Q2xpZW50IGZyb20gJy4uL2NsaWVudHMvbWV0YUFwaS9tZXRhQXBpV2Vic29ja2V0LmNsaWVudCc7XG5pbXBvcnQgU3luY2hyb25pemF0aW9uTGlzdGVuZXIgZnJvbSAnLi4vY2xpZW50cy9tZXRhQXBpL3N5bmNocm9uaXphdGlvbkxpc3RlbmVyJztcbmltcG9ydCBMb2dnZXJNYW5hZ2VyLCB7TG9nZ2VyfSBmcm9tICcuLi9sb2dnZXInO1xuaW1wb3J0IE1ldGF0cmFkZXJBY2NvdW50IGZyb20gJy4vbWV0YXRyYWRlckFjY291bnQnO1xuXG4vKipcbiAqIEV4cG9zZXMgTWV0YUFwaSBNZXRhVHJhZGVyIEFQSSBjb25uZWN0aW9uIHRvIGNvbnN1bWVyc1xuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNZXRhQXBpQ29ubmVjdGlvbiBleHRlbmRzIFN5bmNocm9uaXphdGlvbkxpc3RlbmVyIHtcbiAgXG4gIHByb3RlY3RlZCBfb3B0aW9uczogYW55O1xuICBwcm90ZWN0ZWQgX3dlYnNvY2tldENsaWVudDogTWV0YUFwaVdlYnNvY2tldENsaWVudDtcbiAgcHJvdGVjdGVkIF9sYXRlbmN5U2VydmljZTogYW55O1xuICBwcm90ZWN0ZWQgX2FjY291bnQ6IE1ldGF0cmFkZXJBY2NvdW50O1xuICBwcm90ZWN0ZWQgX2xvZ2dlcjogTG9nZ2VyO1xuICBwcm90ZWN0ZWQgX2FwcGxpY2F0aW9uOiBhbnk7XG4gIHByb3RlY3RlZCBfcmVmcmVzaFRhc2tzOiB7fTtcbiAgcHJvdGVjdGVkIF9jb25uZWN0aW9uUmVnaXN0cnk6IGFueTtcbiAgcHJvdGVjdGVkIF9jbG9zZWQ6IGFueTtcbiAgcHJvdGVjdGVkIF9zdGF0ZUJ5SW5zdGFuY2VJbmRleDogYW55O1xuICBwcm90ZWN0ZWQgX29wZW5lZDogYW55O1xuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiBDb25maWcgTWV0YUFwaSBvcHRpb25zIGZvciBjb25uZWN0aW9uc1xuICAgKiBAcHJvcGVydHkge09wdGlvbnN9IFtjb25uZWN0aW9uc10gTWV0YUFwaSBjb25uZWN0aW9ucyBvcHRpb25zLiBPbmx5IGZvciB0ZXN0cy4gV2lsbCBiZSBpZ25vcmVkIHdoZW4gc2V0IGluIFNES1xuICAgKi9cblxuICAvKipcbiAgICogQHR5cGVkZWYgT3B0aW9ucyBNZXRhQXBpQ29ubmVjdGlvbiBvcHRpb25zXG4gICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBbcmVmcmVzaFJlcGxpY2FzTWF4RGVsYXlJbk1zID0gNiAqIDYwICogNjAgKiAxMDAwXSBtYXggZGVsYXkgYmVmb3JlIHJlZnJlc2hpbmcgcmVwbGljYXMgZGVsYXlcbiAgICovXG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgTWV0YUFwaSBNZXRhVHJhZGVyIEFwaSBjb25uZWN0aW9uXG4gICAqIEBwYXJhbSB7TWV0YUFwaU9wdHMgJiBDb25maWd9IG9wdGlvbnMgTWV0YUFwaSBvcHRpb25zXG4gICAqIEBwYXJhbSB7TWV0YUFwaVdlYnNvY2tldENsaWVudH0gd2Vic29ja2V0Q2xpZW50IE1ldGFBcGkgd2Vic29ja2V0IGNsaWVudFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50fSBhY2NvdW50IE1ldGFUcmFkZXIgYWNjb3VudCBpZCB0byBjb25uZWN0IHRvXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBbYXBwbGljYXRpb25dIGFwcGxpY2F0aW9uIHRvIHVzZVxuICAgKi9cbiAgY29uc3RydWN0b3Iob3B0aW9ucywgd2Vic29ja2V0Q2xpZW50LCBhY2NvdW50LCBhcHBsaWNhdGlvbj8pIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX29wdGlvbnMgPSBvcHRpb25zO1xuICAgIHRoaXMuX3dlYnNvY2tldENsaWVudCA9IHdlYnNvY2tldENsaWVudDtcbiAgICB0aGlzLl9sYXRlbmN5U2VydmljZSA9IHdlYnNvY2tldENsaWVudC5sYXRlbmN5U2VydmljZTtcbiAgICB0aGlzLl9hY2NvdW50ID0gYWNjb3VudDtcbiAgICB0aGlzLl9sb2dnZXIgPSBMb2dnZXJNYW5hZ2VyLmdldExvZ2dlcignTWV0YUFwaUNvbm5lY3Rpb24nKTtcbiAgICB0aGlzLl9hcHBsaWNhdGlvbiA9IGFwcGxpY2F0aW9uO1xuICAgIHRoaXMuX3JlZnJlc2hSZXBsaWNhcyA9IHRoaXMuX3JlZnJlc2hSZXBsaWNhcy5iaW5kKHRoaXMpO1xuICAgIHRoaXMuX3JlZnJlc2hUYXNrcyA9IHt9O1xuICB9XG5cbiAgLyoqXG4gICAqIE9wZW5zIHRoZSBjb25uZWN0aW9uLiBDYW4gb25seSBiZSBjYWxsZWQgdGhlIGZpcnN0IHRpbWUsIG5leHQgY2FsbHMgd2lsbCBiZSBpZ25vcmVkLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJZCBjb25uZWN0aW9uIGluc3RhbmNlIGlkXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gdGhlIGNvbm5lY3Rpb24gaXMgb3BlbmVkXG4gICAqL1xuICBhc3luYyBjb25uZWN0KGluc3RhbmNlSWQpIHt9XG5cbiAgLyoqXG4gICAqIENsb3NlcyB0aGUgY29ubmVjdGlvbi4gVGhlIGluc3RhbmNlIG9mIHRoZSBjbGFzcyBzaG91bGQgbm8gbG9uZ2VyIGJlIHVzZWQgYWZ0ZXIgdGhpcyBtZXRob2QgaXMgaW52b2tlZC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSWQgY29ubmVjdGlvbiBpbnN0YW5jZSBpZFxuICAgKi9cbiAgYXN5bmMgY2xvc2UoaW5zdGFuY2VJZCkge31cblxuICAvKipcbiAgICogUmV0dXJucyBNZXRhQXBpIGFjY291bnRcbiAgICogQHJldHVybiB7TWV0YXRyYWRlckFjY291bnR9IE1ldGFBcGkgYWNjb3VudFxuICAgKi9cbiAgZ2V0IGFjY291bnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2FjY291bnQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBjb25uZWN0aW9uIGFwcGxpY2F0aW9uXG4gICAqIEByZXR1cm4ge1N0cmluZ30gY29ubmVjdGlvbiBhcHBsaWNhdGlvblxuICAgKi9cbiAgZ2V0IGFwcGxpY2F0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLl9hcHBsaWNhdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTY2hlZHVsZXMgdGhlIHJlZnJlc2ggdGFza1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVnaW9uIHJlcGxpY2EgcmVnaW9uXG4gICAqL1xuICBzY2hlZHVsZVJlZnJlc2gocmVnaW9uKSB7XG4gICAgaWYgKCF0aGlzLl9yZWZyZXNoVGFza3NbcmVnaW9uXSkge1xuICAgICAgY29uc3QgZGVsYXkgPSBNYXRoLnJhbmRvbSgpICogKHRoaXMuX29wdGlvbnMuY29ubmVjdGlvbnM/LnJlZnJlc2hSZXBsaWNhc01heERlbGF5SW5NcyA/PyA2ICogNjAgKiA2MCAqIDEwMDApO1xuICAgICAgdGhpcy5fcmVmcmVzaFRhc2tzW3JlZ2lvbl0gPSBzZXRUaW1lb3V0KHRoaXMuX3JlZnJlc2hSZXBsaWNhcywgZGVsYXkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDYW5jZWxzIHRoZSBzY2hlZHVsZWQgcmVmcmVzaCB0YXNrXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWdpb24gcmVwbGljYSByZWdpb25cbiAgICovXG4gIGNhbmNlbFJlZnJlc2gocmVnaW9uKSB7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuX3JlZnJlc2hUYXNrc1tyZWdpb25dKTtcbiAgICBkZWxldGUgdGhpcy5fcmVmcmVzaFRhc2tzW3JlZ2lvbl07XG4gIH1cblxuICAvKipcbiAgICogUmVmcmVzaGVzIGFjY291bnQgcmVwbGljYXNcbiAgICovXG4gIGFzeW5jIF9yZWZyZXNoUmVwbGljYXMoKSB7XG4gICAgT2JqZWN0LnZhbHVlczxhbnk+KHRoaXMuX3JlZnJlc2hUYXNrcykuZm9yRWFjaCh0YXNrID0+IGNsZWFyVGltZW91dCh0YXNrKSk7XG4gICAgdGhpcy5fcmVmcmVzaFRhc2tzID0ge307XG4gICAgY29uc3Qgb2xkUmVwbGljYXM6IE1ldGF0cmFkZXJBY2NvdW50LkFjY291bnRzQnlSZWdpb24gPSB7fTtcbiAgICB0aGlzLl9hY2NvdW50LnJlcGxpY2FzLmZvckVhY2gocmVwbGljYSA9PiBvbGRSZXBsaWNhc1tyZXBsaWNhLnJlZ2lvbl0gPSByZXBsaWNhLmlkKTtcbiAgICBjb25zdCBuZXdSZXBsaWNhczogTWV0YXRyYWRlckFjY291bnQuQWNjb3VudHNCeVJlZ2lvbiA9IHt9O1xuICAgIGxldCBpc0FjY291bnRVcGRhdGVkID0gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuX2FjY291bnQucmVsb2FkKCk7XG4gICAgICBpc0FjY291bnRVcGRhdGVkID0gdHJ1ZTtcbiAgICAgIHRoaXMuX2FjY291bnQucmVwbGljYXMuZm9yRWFjaChyZXBsaWNhID0+IG5ld1JlcGxpY2FzW3JlcGxpY2EucmVnaW9uXSA9IHJlcGxpY2EuaWQpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoZXJyb3IubmFtZSA9PT0gJ05vdEZvdW5kRXJyb3InKSB7XG4gICAgICAgIGlmICh0aGlzLl9jb25uZWN0aW9uUmVnaXN0cnkpIHtcbiAgICAgICAgICB0aGlzLl9jb25uZWN0aW9uUmVnaXN0cnkuY2xvc2VBbGxJbnN0YW5jZXModGhpcy5fYWNjb3VudC5pZCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGlzQWNjb3VudFVwZGF0ZWQpIHtcbiAgICAgIGNvbnN0IGRlbGV0ZWRSZXBsaWNhcyA9IHt9O1xuICAgICAgY29uc3QgYWRkZWRSZXBsaWNhcyA9IHt9O1xuICAgICAgT2JqZWN0LmtleXMob2xkUmVwbGljYXMpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgaWYgKG5ld1JlcGxpY2FzW2tleV0gIT09IG9sZFJlcGxpY2FzW2tleV0pIHtcbiAgICAgICAgICBkZWxldGVkUmVwbGljYXNba2V5XSA9IG9sZFJlcGxpY2FzW2tleV07XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgT2JqZWN0LmtleXMobmV3UmVwbGljYXMpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgaWYgKG5ld1JlcGxpY2FzW2tleV0gIT09IG9sZFJlcGxpY2FzW2tleV0pIHtcbiAgICAgICAgICBhZGRlZFJlcGxpY2FzW2tleV0gPSBuZXdSZXBsaWNhc1trZXldO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGlmIChPYmplY3Qua2V5cyhkZWxldGVkUmVwbGljYXMpLmxlbmd0aCkge1xuICAgICAgICBPYmplY3QudmFsdWVzKGRlbGV0ZWRSZXBsaWNhcykuZm9yRWFjaChyZXBsaWNhSWQgPT4gXG4gICAgICAgICAgdGhpcy5fd2Vic29ja2V0Q2xpZW50Lm9uQWNjb3VudERlbGV0ZWQocmVwbGljYUlkKSk7XG4gICAgICB9XG4gICAgICBpZiAoT2JqZWN0LmtleXMoZGVsZXRlZFJlcGxpY2FzKS5sZW5ndGggfHwgT2JqZWN0LmtleXMoYWRkZWRSZXBsaWNhcykubGVuZ3RoKSB7XG4gICAgICAgIG5ld1JlcGxpY2FzW3RoaXMuX2FjY291bnQucmVnaW9uXSA9IHRoaXMuX2FjY291bnQuaWQ7XG4gICAgICAgIHRoaXMuX3dlYnNvY2tldENsaWVudC51cGRhdGVBY2NvdW50Q2FjaGUodGhpcy5fYWNjb3VudC5pZCwgbmV3UmVwbGljYXMpO1xuICAgICAgICBPYmplY3QuZW50cmllcyh0aGlzLl9hY2NvdW50LmFjY291bnRSZWdpb25zKS5mb3JFYWNoKChbcmVnaW9uLCBpbnN0YW5jZV0pID0+IHtcbiAgICAgICAgICBpZiAoIXRoaXMuX29wdGlvbnMucmVnaW9uIHx8IHRoaXMuX29wdGlvbnMucmVnaW9uID09PSByZWdpb24pIHtcbiAgICAgICAgICAgIHRoaXMuX3dlYnNvY2tldENsaWVudC5lbnN1cmVTdWJzY3JpYmUoaW5zdGFuY2UsIDApO1xuICAgICAgICAgICAgdGhpcy5fd2Vic29ja2V0Q2xpZW50LmVuc3VyZVN1YnNjcmliZShpbnN0YW5jZSwgMSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBhc3luYyBfZW5zdXJlU3luY2hyb25pemVkKGluc3RhbmNlSW5kZXgsIGtleSkge1xuICAgIGxldCBzdGF0ZSA9IHRoaXMuX2dldFN0YXRlKGluc3RhbmNlSW5kZXgpO1xuICAgIGlmIChzdGF0ZSAmJiAhdGhpcy5fY2xvc2VkKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzeW5jaHJvbml6YXRpb25SZXN1bHQgPSBhd2FpdCB0aGlzLnN5bmNocm9uaXplKGluc3RhbmNlSW5kZXgpO1xuICAgICAgICBpZiAoc3luY2hyb25pemF0aW9uUmVzdWx0KSB7XG4gICAgICAgICAgc3RhdGUuc3luY2hyb25pemVkID0gdHJ1ZTtcbiAgICAgICAgICBzdGF0ZS5zeW5jaHJvbml6YXRpb25SZXRyeUludGVydmFsSW5TZWNvbmRzID0gMTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnN0IGxldmVsID0gdGhpcy5fbGF0ZW5jeVNlcnZpY2UuZ2V0U3luY2hyb25pemVkQWNjb3VudEluc3RhbmNlcyh0aGlzLl9hY2NvdW50LmlkKS5sZW5ndGggPyAnZGVidWcnIDogJ2Vycm9yJztcbiAgICAgICAgdGhpcy5fbG9nZ2VyW2xldmVsXSgnTWV0YUFwaSB3ZWJzb2NrZXQgY2xpZW50IGZvciBhY2NvdW50ICcgKyB0aGlzLl9hY2NvdW50LmlkICtcbiAgICAgICAgICAnOicgKyBpbnN0YW5jZUluZGV4ICsgJyBmYWlsZWQgdG8gc3luY2hyb25pemUnLCBlcnIpO1xuICAgICAgICBpZiAoc3RhdGUuc2hvdWxkU3luY2hyb25pemUgPT09IGtleSkge1xuICAgICAgICAgIHNldFRpbWVvdXQodGhpcy5fZW5zdXJlU3luY2hyb25pemVkLmJpbmQodGhpcywgaW5zdGFuY2VJbmRleCwga2V5KSxcbiAgICAgICAgICAgIHN0YXRlLnN5bmNocm9uaXphdGlvblJldHJ5SW50ZXJ2YWxJblNlY29uZHMgKiAxMDAwKTtcbiAgICAgICAgICBzdGF0ZS5zeW5jaHJvbml6YXRpb25SZXRyeUludGVydmFsSW5TZWNvbmRzID0gTWF0aC5taW4oc3RhdGUuc3luY2hyb25pemF0aW9uUmV0cnlJbnRlcnZhbEluU2Vjb25kcyAqIDIsIDMwMCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIHN5bmNocm9uaXplKGluc3RhbmNlSW5kZXg6IGFueSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBfZ2V0U3RhdGUoaW5zdGFuY2VJbmRleCkge1xuICAgIGlmICghdGhpcy5fc3RhdGVCeUluc3RhbmNlSW5kZXhbJycgKyBpbnN0YW5jZUluZGV4XSkge1xuICAgICAgdGhpcy5fc3RhdGVCeUluc3RhbmNlSW5kZXhbJycgKyBpbnN0YW5jZUluZGV4XSA9IHtcbiAgICAgICAgaW5zdGFuY2VJbmRleCxcbiAgICAgICAgb3JkZXJzU3luY2hyb25pemVkOiB7fSxcbiAgICAgICAgZGVhbHNTeW5jaHJvbml6ZWQ6IHt9LFxuICAgICAgICBzaG91bGRTeW5jaHJvbml6ZTogdW5kZWZpbmVkLFxuICAgICAgICBzeW5jaHJvbml6YXRpb25SZXRyeUludGVydmFsSW5TZWNvbmRzOiAxLFxuICAgICAgICBzeW5jaHJvbml6ZWQ6IGZhbHNlLFxuICAgICAgICBsYXN0RGlzY29ubmVjdGVkU3luY2hyb25pemF0aW9uSWQ6IHVuZGVmaW5lZCxcbiAgICAgICAgbGFzdFN5bmNocm9uaXphdGlvbklkOiB1bmRlZmluZWQsXG4gICAgICAgIGRpc2Nvbm5lY3RlZDogZmFsc2VcbiAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9zdGF0ZUJ5SW5zdGFuY2VJbmRleFsnJyArIGluc3RhbmNlSW5kZXhdO1xuICB9XG5cbiAgX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCkge1xuICAgIGlmICghdGhpcy5fb3BlbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RoaXMgY29ubmVjdGlvbiBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWQgeWV0LCBwbGVhc2UgaW52b2tlIGF3YWl0IGNvbm5lY3Rpb24uY29ubmVjdCgpJyk7XG4gICAgfVxuICAgIGlmICh0aGlzLl9jbG9zZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVGhpcyBjb25uZWN0aW9uIGhhcyBiZWVuIGNsb3NlZCwgcGxlYXNlIGNyZWF0ZSBhIG5ldyBjb25uZWN0aW9uJyk7XG4gICAgfVxuICB9XG5cbn1cbiJdLCJuYW1lcyI6WyJTeW5jaHJvbml6YXRpb25MaXN0ZW5lciIsIkxvZ2dlck1hbmFnZXIiLCJNZXRhQXBpQ29ubmVjdGlvbiIsImNvbm5lY3QiLCJpbnN0YW5jZUlkIiwiY2xvc2UiLCJhY2NvdW50IiwiX2FjY291bnQiLCJhcHBsaWNhdGlvbiIsIl9hcHBsaWNhdGlvbiIsInNjaGVkdWxlUmVmcmVzaCIsInJlZ2lvbiIsIl9yZWZyZXNoVGFza3MiLCJkZWxheSIsIk1hdGgiLCJyYW5kb20iLCJfb3B0aW9ucyIsImNvbm5lY3Rpb25zIiwicmVmcmVzaFJlcGxpY2FzTWF4RGVsYXlJbk1zIiwic2V0VGltZW91dCIsIl9yZWZyZXNoUmVwbGljYXMiLCJjYW5jZWxSZWZyZXNoIiwiY2xlYXJUaW1lb3V0IiwiT2JqZWN0IiwidmFsdWVzIiwiZm9yRWFjaCIsInRhc2siLCJvbGRSZXBsaWNhcyIsInJlcGxpY2FzIiwicmVwbGljYSIsImlkIiwibmV3UmVwbGljYXMiLCJpc0FjY291bnRVcGRhdGVkIiwicmVsb2FkIiwiZXJyb3IiLCJuYW1lIiwiX2Nvbm5lY3Rpb25SZWdpc3RyeSIsImNsb3NlQWxsSW5zdGFuY2VzIiwiZGVsZXRlZFJlcGxpY2FzIiwiYWRkZWRSZXBsaWNhcyIsImtleXMiLCJrZXkiLCJsZW5ndGgiLCJyZXBsaWNhSWQiLCJfd2Vic29ja2V0Q2xpZW50Iiwib25BY2NvdW50RGVsZXRlZCIsInVwZGF0ZUFjY291bnRDYWNoZSIsImVudHJpZXMiLCJhY2NvdW50UmVnaW9ucyIsImluc3RhbmNlIiwiZW5zdXJlU3Vic2NyaWJlIiwiX2Vuc3VyZVN5bmNocm9uaXplZCIsImluc3RhbmNlSW5kZXgiLCJzdGF0ZSIsIl9nZXRTdGF0ZSIsIl9jbG9zZWQiLCJzeW5jaHJvbml6YXRpb25SZXN1bHQiLCJzeW5jaHJvbml6ZSIsInN5bmNocm9uaXplZCIsInN5bmNocm9uaXphdGlvblJldHJ5SW50ZXJ2YWxJblNlY29uZHMiLCJlcnIiLCJsZXZlbCIsIl9sYXRlbmN5U2VydmljZSIsImdldFN5bmNocm9uaXplZEFjY291bnRJbnN0YW5jZXMiLCJfbG9nZ2VyIiwic2hvdWxkU3luY2hyb25pemUiLCJiaW5kIiwibWluIiwidW5kZWZpbmVkIiwiX3N0YXRlQnlJbnN0YW5jZUluZGV4Iiwib3JkZXJzU3luY2hyb25pemVkIiwiZGVhbHNTeW5jaHJvbml6ZWQiLCJsYXN0RGlzY29ubmVjdGVkU3luY2hyb25pemF0aW9uSWQiLCJsYXN0U3luY2hyb25pemF0aW9uSWQiLCJkaXNjb25uZWN0ZWQiLCJfY2hlY2tJc0Nvbm5lY3Rpb25BY3RpdmUiLCJfb3BlbmVkIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsIm9wdGlvbnMiLCJ3ZWJzb2NrZXRDbGllbnQiLCJsYXRlbmN5U2VydmljZSIsImdldExvZ2dlciJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFHQSxPQUFPQSw2QkFBNkIsNkNBQTZDO0FBQ2pGLE9BQU9DLG1CQUE2QixZQUFZO0FBTWpDLElBQUEsQUFBTUMsb0JBQU4sTUFBTUEsMEJBQTBCRjtJQTJDN0M7Ozs7R0FJQyxHQUNELEFBQU1HLFFBQVFDLFVBQVU7ZUFBeEIsb0JBQUEsYUFBMkI7O0lBRTNCOzs7R0FHQyxHQUNELEFBQU1DLE1BQU1ELFVBQVU7ZUFBdEIsb0JBQUEsYUFBeUI7O0lBRXpCOzs7R0FHQyxHQUNELElBQUlFLFVBQVU7UUFDWixPQUFPLElBQUksQ0FBQ0MsUUFBUTtJQUN0QjtJQUVBOzs7R0FHQyxHQUNELElBQUlDLGNBQWM7UUFDaEIsT0FBTyxJ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