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)

239 lines (238 loc) 26.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return _default; } }); const _randomstring = /*#__PURE__*/ _interop_require_default(require("randomstring")); const _longrunningasyncprocess = /*#__PURE__*/ _interop_require_wildcard(require("../long-running-async-process")); const _stickySocketConnection = /*#__PURE__*/ _interop_require_default(require("./stickySocketConnection")); const _errorHandler = /*#__PURE__*/ _interop_require_wildcard(require("../../clients/errorHandler")); const _commonutils = require("./common.utils"); const _time = require("../../helpers/convert/time"); const _eventEmitter = /*#__PURE__*/ _interop_require_default(require("../../tools/eventEmitter")); const _logger = /*#__PURE__*/ _interop_require_default(require("../../logger")); const _queue = /*#__PURE__*/ _interop_require_default(require("../../tools/queue")); 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; } function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interop_require_wildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = { __proto__: null }; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * Client sticky socket */ let ClientStickySocket = class ClientStickySocket extends _eventEmitter.default { /** * Returns socket ID * @returns socket ID */ get id() { return this._id; } /** * Returns current native socket * @returns socket.io socket * @internal intended for tests only */ get socket() { var _this__pool_getProcess; return (_this__pool_getProcess = this._pool.getProcess("connection")) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.socket; } /** * Returns current transport name, using socket.io internals * @returns transport name, e.g. "websocket" * @internal intended for tests only */ get transportName() { var _this__pool_getProcess; return (_this__pool_getProcess = this._pool.getProcess("connection")) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.transportName; } /** * Returns first present packet index in last emit history * @returns first history index * @internal intended for tests only */ get firstHistoryIndex() { var _this__pool_getProcess; return (_this__pool_getProcess = this._pool.getProcess("connection")) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.firstHistoryIndex; } /** * Returns whether socket connected * @returns is connected */ get connected() { return this._connected; } /** * @inheritdoc * @remarks Socket events `ClientStickySockets.INTERNAL_EVENTS` cannot be subscribed to * @throws `ValidationError` if attempting to subscribe to an internal event */ on(event, callback) { if (ClientStickySocket.INTERNAL_EVENTS.includes(event)) { throw new _errorHandler.ValidationError("Cannot subscribe to an internal event"); } super.on(event, callback); } /** * Emits a data event. All events are buffered if no connection * @param event The event that we're emitting * @param args Optional arguments to send with the event */ send(event, ...args) { var _this__pool_getProcess; (_this__pool_getProcess = this._pool.getProcess("connection")) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.send(event, ...args); } /** * Disconnects socket * @param err error if disconnecting with error * @returns promise resolving when disconnected */ async disconnect(err) { clearTimeout(this._stickyConnectionWaitTimeout); let wasStopped = this._stopped; this._stopped = true; await this._pool.stop(); if (!wasStopped) { this._connected = false; this.emit("disconnect", err); } } /** * Destroys underlying socket, using socket.io internals. The socket must have `websocket` transport * @param err optional error * @internal intended for tests only, e.g. to test connection loss */ destroyInternalSocket(err) { (0, _commonutils.destroyInternalClientSocket)(this._pool.getProcess("connection").socket, err); } /** * Removes expired emit history * @internal intended for tests only */ removeExpiredEmitHistory() { var _this__pool_getProcess; (_this__pool_getProcess = this._pool.getProcess("connection")) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.removeExpiredEmitHistory(); } /** * Constructs instance * @param url URL * @param options options */ constructor(url, options){ super(); _define_property(this, "_logger", _logger.default.getLogger("ClientStickySocket")); _define_property(this, "_pool", void 0); _define_property(this, "_stickyConnectionWaitTimeout", void 0); _define_property(this, "_id", _randomstring.default.generate(16)); _define_property(this, "_label", void 0); _define_property(this, "_stopped", false); _define_property(this, "_connected", false); this._label = `${(options === null || options === void 0 ? void 0 : options.label) || "connection"}:${this._id}`; var _options_stickyConnectionTtlInSeconds; const stickyConnectionTtlInMs = 1000 * ((_options_stickyConnectionTtlInSeconds = options === null || options === void 0 ? void 0 : options.stickyConnectionTtlInSeconds) !== null && _options_stickyConnectionTtlInSeconds !== void 0 ? _options_stickyConnectionTtlInSeconds : 10); let internalEvents = new _eventEmitter.default(); internalEvents.once("connect", ()=>{ this._connected = true; this.emit("connect"); }); internalEvents.on("connect", ()=>clearTimeout(this._stickyConnectionWaitTimeout)); internalEvents.on("fail", (err)=>{ if (options === null || options === void 0 ? void 0 : options.useNativeSocketIoServer) { this.disconnect(err); return; } if (!this._stopped) { this._stickyConnectionWaitTimeout = setTimeout(()=>{ this._logger.warn(`${this._label}: failed to restore sticky connection`); this.disconnect(err); }, stickyConnectionTtlInMs); } }); this._pool = new _longrunningasyncprocess.RootPool(_stickySocketConnection.default, { dependencies: [ this, internalEvents ], label: `clientStickySocket:${this._label}` }); var _options_emitHistoryTtlInSeconds, _options_reconnectionDelayInMs, _options_reconnectionDelayMaxInMs, _options_reconnectionRandomizationFactor; this._pool.scheduleProcess("connection", { args: [ url, this._id, { startCount: 0, emitHistory: new _queue.default(), lastSentIndex: -1, lastReceivedIndex: -1 }, { label: this._label, connection: options === null || options === void 0 ? void 0 : options.connection, useNativeSocketIoServer: options === null || options === void 0 ? void 0 : options.useNativeSocketIoServer, emitHistoryTtlInSeconds: (_options_emitHistoryTtlInSeconds = options === null || options === void 0 ? void 0 : options.emitHistoryTtlInSeconds) !== null && _options_emitHistoryTtlInSeconds !== void 0 ? _options_emitHistoryTtlInSeconds : (0, _time.msToSeconds)(stickyConnectionTtlInMs) } ], failoverThrottleDelay: { mode: "exponential", resetDelayInMs: 0, minDelayInMs: (_options_reconnectionDelayInMs = options === null || options === void 0 ? void 0 : options.reconnectionDelayInMs) !== null && _options_reconnectionDelayInMs !== void 0 ? _options_reconnectionDelayInMs : 1000, maxDelayInMs: (_options_reconnectionDelayMaxInMs = options === null || options === void 0 ? void 0 : options.reconnectionDelayMaxInMs) !== null && _options_reconnectionDelayMaxInMs !== void 0 ? _options_reconnectionDelayMaxInMs : 10000, randomizationFactor: (_options_reconnectionRandomizationFactor = options === null || options === void 0 ? void 0 : options.reconnectionRandomizationFactor) !== null && _options_reconnectionRandomizationFactor !== void 0 ? _options_reconnectionRandomizationFactor : 0.5 } }); } }; (function(ClientStickySocket) { /** Connection events */ ClientStickySocket.CONNECTION_EVENTS = _stickySocketConnection.default.CONNECTION_EVENTS; /** Internal events */ ClientStickySocket.INTERNAL_EVENTS = _stickySocketConnection.default.INTERNAL_EVENTS; })(ClientStickySocket || (ClientStickySocket = {})); const _default = ClientStickySocket; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcmFuZG9tc3RyaW5nIGZyb20gJ3JhbmRvbXN0cmluZyc7XG5pbXBvcnQgKiBhcyBscmFwIGZyb20gJy4uL2xvbmctcnVubmluZy1hc3luYy1wcm9jZXNzJztcbmltcG9ydCBTdGlja3lTb2NrZXRDb25uZWN0aW9uIGZyb20gJy4vc3RpY2t5U29ja2V0Q29ubmVjdGlvbic7XG5pbXBvcnQgKiBhcyBlcnJvcnMgZnJvbSAnLi4vLi4vY2xpZW50cy9lcnJvckhhbmRsZXInO1xuaW1wb3J0IHtkZXN0cm95SW50ZXJuYWxDbGllbnRTb2NrZXR9IGZyb20gJy4vY29tbW9uLnV0aWxzJztcbmltcG9ydCB7bXNUb1NlY29uZHN9IGZyb20gJy4uLy4uL2hlbHBlcnMvY29udmVydC90aW1lJztcbmltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSAnLi4vLi4vdG9vbHMvZXZlbnRFbWl0dGVyJztcbmltcG9ydCBMb2dnZXJNYW5hZ2VyIGZyb20gJy4uLy4uL2xvZ2dlcic7XG5pbXBvcnQgUXVldWUgZnJvbSAnLi4vLi4vdG9vbHMvcXVldWUnO1xuXG4vKipcbiAqIENsaWVudCBzdGlja3kgc29ja2V0XG4gKi9cbmNsYXNzIENsaWVudFN0aWNreVNvY2tldCBleHRlbmRzIEV2ZW50RW1pdHRlcjxDbGllbnRTdGlja3lTb2NrZXQuRXZlbnRzPiB7XG5cbiAgcHJpdmF0ZSBfbG9nZ2VyID0gTG9nZ2VyTWFuYWdlci5nZXRMb2dnZXIoJ0NsaWVudFN0aWNreVNvY2tldCcpO1xuICBwcml2YXRlIF9wb29sOiBscmFwLlJvb3RQb29sPFN0aWNreVNvY2tldENvbm5lY3Rpb24+O1xuICBwcml2YXRlIF9zdGlja3lDb25uZWN0aW9uV2FpdFRpbWVvdXQ/OiBOb2RlSlMuVGltZW91dDtcbiAgcHJpdmF0ZSBfaWQgPSByYW5kb21zdHJpbmcuZ2VuZXJhdGUoMTYpO1xuICBwcml2YXRlIF9sYWJlbDogc3RyaW5nO1xuICBwcml2YXRlIF9zdG9wcGVkID0gZmFsc2U7XG4gIHByaXZhdGUgX2Nvbm5lY3RlZCA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGluc3RhbmNlXG4gICAqIEBwYXJhbSB1cmwgVVJMXG4gICAqIEBwYXJhbSBvcHRpb25zIG9wdGlvbnNcbiAgICovXG4gIGNvbnN0cnVjdG9yKHVybDogc3RyaW5nLCBvcHRpb25zPzogQ2xpZW50U3RpY2t5U29ja2V0Lk9wdGlvbnMpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX2xhYmVsID0gYCR7b3B0aW9ucz8ubGFiZWwgfHwgJ2Nvbm5lY3Rpb24nfToke3RoaXMuX2lkfWA7XG4gICAgXG4gICAgY29uc3Qgc3RpY2t5Q29ubmVjdGlvblR0bEluTXMgPSAxMDAwICogKG9wdGlvbnM/LnN0aWNreUNvbm5lY3Rpb25UdGxJblNlY29uZHMgPz8gMTApO1xuICAgIGxldCBpbnRlcm5hbEV2ZW50cyA9IG5ldyBFdmVudEVtaXR0ZXI8U3RpY2t5U29ja2V0Q29ubmVjdGlvbi5TaGFyZWRFdmVudHM+KCk7XG4gICAgaW50ZXJuYWxFdmVudHMub25jZSgnY29ubmVjdCcsICgpID0+IHtcbiAgICAgIHRoaXMuX2Nvbm5lY3RlZCA9IHRydWU7XG4gICAgICB0aGlzLmVtaXQoJ2Nvbm5lY3QnKTtcbiAgICB9KTtcbiAgICBpbnRlcm5hbEV2ZW50cy5vbignY29ubmVjdCcsICgpID0+IGNsZWFyVGltZW91dCh0aGlzLl9zdGlja3lDb25uZWN0aW9uV2FpdFRpbWVvdXQpKTtcbiAgICBpbnRlcm5hbEV2ZW50cy5vbignZmFpbCcsIGVyciA9PiB7XG4gICAgICBpZiAob3B0aW9ucz8udXNlTmF0aXZlU29ja2V0SW9TZXJ2ZXIpIHtcbiAgICAgICAgdGhpcy5kaXNjb25uZWN0KGVycik7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICghdGhpcy5fc3RvcHBlZCkge1xuICAgICAgICB0aGlzLl9zdGlja3lDb25uZWN0aW9uV2FpdFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICB0aGlzLl9sb2dnZXIud2FybihgJHt0aGlzLl9sYWJlbH06IGZhaWxlZCB0byByZXN0b3JlIHN0aWNreSBjb25uZWN0aW9uYCk7XG4gICAgICAgICAgdGhpcy5kaXNjb25uZWN0KGVycik7XG4gICAgICAgIH0sIHN0aWNreUNvbm5lY3Rpb25UdGxJbk1zKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBcbiAgICB0aGlzLl9wb29sID0gbmV3IGxyYXAuUm9vdFBvb2woU3RpY2t5U29ja2V0Q29ubmVjdGlvbiwge1xuICAgICAgZGVwZW5kZW5jaWVzOiBbdGhpcywgaW50ZXJuYWxFdmVudHNdLFxuICAgICAgbGFiZWw6IGBjbGllbnRTdGlja3lTb2NrZXQ6JHt0aGlzLl9sYWJlbH1gLFxuICAgIH0pO1xuICAgIHRoaXMuX3Bvb2wuc2NoZWR1bGVQcm9jZXNzKCdjb25uZWN0aW9uJywge1xuICAgICAgYXJnczogW1xuICAgICAgICB1cmwsIHRoaXMuX2lkLFxuICAgICAgICB7XG4gICAgICAgICAgc3RhcnRDb3VudDogMCxcbiAgICAgICAgICBlbWl0SGlzdG9yeTogbmV3IFF1ZXVlKCksXG4gICAgICAgICAgbGFzdFNlbnRJbmRleDogLTEsXG4gICAgICAgICAgbGFzdFJlY2VpdmVkSW5kZXg6IC0xXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBsYWJlbDogdGhpcy5fbGFiZWwsXG4gICAgICAgICAgY29ubmVjdGlvbjogb3B0aW9ucz8uY29ubmVjdGlvbixcbiAgICAgICAgICB1c2VOYXRpdmVTb2NrZXRJb1NlcnZlcjogb3B0aW9ucz8udXNlTmF0aXZlU29ja2V0SW9TZXJ2ZXIsXG4gICAgICAgICAgZW1pdEhpc3RvcnlUdGxJblNlY29uZHM6IG9wdGlvbnM/LmVtaXRIaXN0b3J5VHRsSW5TZWNvbmRzID8/IG1zVG9TZWNvbmRzKHN0aWNreUNvbm5lY3Rpb25UdGxJbk1zKVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgZmFpbG92ZXJUaHJvdHRsZURlbGF5OiB7XG4gICAgICAgIG1vZGU6ICdleHBvbmVudGlhbCcsXG4gICAgICAgIHJlc2V0RGVsYXlJbk1zOiAwLFxuICAgICAgICBtaW5EZWxheUluTXM6IG9wdGlvbnM/LnJlY29ubmVjdGlvbkRlbGF5SW5NcyA/PyAxMDAwLFxuICAgICAgICBtYXhEZWxheUluTXM6IG9wdGlvbnM/LnJlY29ubmVjdGlvbkRlbGF5TWF4SW5NcyA/PyAxMDAwMCxcbiAgICAgICAgcmFuZG9taXphdGlvbkZhY3Rvcjogb3B0aW9ucz8ucmVjb25uZWN0aW9uUmFuZG9taXphdGlvbkZhY3RvciA/PyAwLjVcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHNvY2tldCBJRFxuICAgKiBAcmV0dXJucyBzb2NrZXQgSURcbiAgICovXG4gIGdldCBpZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9pZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGN1cnJlbnQgbmF0aXZlIHNvY2tldFxuICAgKiBAcmV0dXJucyBzb2NrZXQuaW8gc29ja2V0XG4gICAqIEBpbnRlcm5hbCBpbnRlbmRlZCBmb3IgdGVzdHMgb25seVxuICAgKi9cbiAgZ2V0IHNvY2tldCgpOiBTb2NrZXRJT0NsaWVudC5Tb2NrZXQge1xuICAgIHJldHVybiB0aGlzLl9wb29sLmdldFByb2Nlc3MoJ2Nvbm5lY3Rpb24nKT8uc29ja2V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCB0cmFuc3BvcnQgbmFtZSwgdXNpbmcgc29ja2V0LmlvIGludGVybmFsc1xuICAgKiBAcmV0dXJucyB0cmFuc3BvcnQgbmFtZSwgZS5nLiBcIndlYnNvY2tldFwiXG4gICAqIEBpbnRlcm5hbCBpbnRlbmRlZCBmb3IgdGVzdHMgb25seVxuICAgKi9cbiAgZ2V0IHRyYW5zcG9ydE5hbWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fcG9vbC5nZXRQcm9jZXNzKCdjb25uZWN0aW9uJyk/LnRyYW5zcG9ydE5hbWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIGZpcnN0IHByZXNlbnQgcGFja2V0IGluZGV4IGluIGxhc3QgZW1pdCBoaXN0b3J5XG4gICAqIEByZXR1cm5zIGZpcnN0IGhpc3RvcnkgaW5kZXhcbiAgICogQGludGVybmFsIGludGVuZGVkIGZvciB0ZXN0cyBvbmx5XG4gICAqL1xuICBnZXQgZmlyc3RIaXN0b3J5SW5kZXgoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fcG9vbC5nZXRQcm9jZXNzKCdjb25uZWN0aW9uJyk/LmZpcnN0SGlzdG9yeUluZGV4O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgd2hldGhlciBzb2NrZXQgY29ubmVjdGVkXG4gICAqIEByZXR1cm5zIGlzIGNvbm5lY3RlZFxuICAgKi9cbiAgZ2V0IGNvbm5lY3RlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fY29ubmVjdGVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEBpbmhlcml0ZG9jXG4gICAqIEByZW1hcmtzIFNvY2tldCBldmVudHMgYENsaWVudFN0aWNreVNvY2tldHMuSU5URVJOQUxfRVZFTlRTYCBjYW5ub3QgYmUgc3Vic2NyaWJlZCB0b1xuICAgKiBAdGhyb3dzIGBWYWxpZGF0aW9uRXJyb3JgIGlmIGF0dGVtcHRpbmcgdG8gc3Vic2NyaWJlIHRvIGFuIGludGVybmFsIGV2ZW50XG4gICAqL1xuICBvbjxVIGV4dGVuZHMgRXZlbnRFbWl0dGVyLkV2ZW50PENsaWVudFN0aWNreVNvY2tldC5FdmVudHM+PihldmVudDogVSwgY2FsbGJhY2s6IENsaWVudFN0aWNreVNvY2tldC5FdmVudHNbVV0pIHtcbiAgICBpZiAoQ2xpZW50U3RpY2t5U29ja2V0LklOVEVSTkFMX0VWRU5UUy5pbmNsdWRlcyhldmVudCkpIHtcbiAgICAgIHRocm93IG5ldyBlcnJvcnMuVmFsaWRhdGlvbkVycm9yKCdDYW5ub3Qgc3Vic2NyaWJlIHRvIGFuIGludGVybmFsIGV2ZW50Jyk7XG4gICAgfVxuICAgIHN1cGVyLm9uKGV2ZW50LCBjYWxsYmFjayk7XG4gIH1cblxuICAvKipcbiAgICogRW1pdHMgYSBkYXRhIGV2ZW50LiBBbGwgZXZlbnRzIGFyZSBidWZmZXJlZCBpZiBubyBjb25uZWN0aW9uXG4gICAqIEBwYXJhbSBldmVudCBUaGUgZXZlbnQgdGhhdCB3ZSdyZSBlbWl0dGluZ1xuICAgKiBAcGFyYW0gYXJncyBPcHRpb25hbCBhcmd1bWVudHMgdG8gc2VuZCB3aXRoIHRoZSBldmVudFxuICAgKi9cbiAgc2VuZChldmVudDogc3RyaW5nLCAuLi5hcmdzOiBhbnlbXSkge1xuICAgIHRoaXMuX3Bvb2wuZ2V0UHJvY2VzcygnY29ubmVjdGlvbicpPy5zZW5kKGV2ZW50LCAuLi5hcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNjb25uZWN0cyBzb2NrZXRcbiAgICogQHBhcmFtIGVyciBlcnJvciBpZiBkaXNjb25uZWN0aW5nIHdpdGggZXJyb3JcbiAgICogQHJldHVybnMgcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBkaXNjb25uZWN0ZWRcbiAgICovXG4gIGFzeW5jIGRpc2Nvbm5lY3QoZXJyPzogRXJyb3IpIHtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5fc3RpY2t5Q29ubmVjdGlvbldhaXRUaW1lb3V0KTtcbiAgICBsZXQgd2FzU3RvcHBlZCA9IHRoaXMuX3N0b3BwZWQ7XG4gICAgdGhpcy5fc3RvcHBlZCA9IHRydWU7XG4gICAgYXdhaXQgdGhpcy5fcG9vbC5zdG9wKCk7XG4gICAgaWYgKCF3YXNTdG9wcGVkKSB7XG4gICAgICB0aGlzLl9jb25uZWN0ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuZW1pdCgnZGlzY29ubmVjdCcsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlc3Ryb3lzIHVuZGVybHlpbmcgc29ja2V0LCB1c2luZyBzb2NrZXQuaW8gaW50ZXJuYWxzLiBUaGUgc29ja2V0IG11c3QgaGF2ZSBgd2Vic29ja2V0YCB0cmFuc3BvcnRcbiAgICogQHBhcmFtIGVyciBvcHRpb25hbCBlcnJvclxuICAgKiBAaW50ZXJuYWwgaW50ZW5kZWQgZm9yIHRlc3RzIG9ubHksIGUuZy4gdG8gdGVzdCBjb25uZWN0aW9uIGxvc3NcbiAgICovXG4gIGRlc3Ryb3lJbnRlcm5hbFNvY2tldChlcnI/OiBFcnJvcikge1xuICAgIGRlc3Ryb3lJbnRlcm5hbENsaWVudFNvY2tldCh0aGlzLl9wb29sLmdldFByb2Nlc3MoJ2Nvbm5lY3Rpb24nKS5zb2NrZXQsIGVycik7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBleHBpcmVkIGVtaXQgaGlzdG9yeVxuICAgKiBAaW50ZXJuYWwgaW50ZW5kZWQgZm9yIHRlc3RzIG9ubHlcbiAgICovXG4gIHJlbW92ZUV4cGlyZWRFbWl0SGlzdG9yeSgpIHtcbiAgICB0aGlzLl9wb29sLmdldFByb2Nlc3MoJ2Nvbm5lY3Rpb24nKT8ucmVtb3ZlRXhwaXJlZEVtaXRIaXN0b3J5KCk7XG4gIH1cbn1cblxubmFtZXNwYWNlIENsaWVudFN0aWNreVNvY2tldCB7XG5cbiAgLyoqIENvbnN0cnVjdGluZyBvcHRpb25zICovXG4gIGV4cG9ydCB0eXBlIE9wdGlvbnMgPSBQaWNrPFN0aWNreVNvY2tldENvbm5lY3Rpb24uT3B0aW9ucywgJ2Nvbm5lY3Rpb24nIHwgJ2xhYmVsJyB8ICd1c2VOYXRpdmVTb2NrZXRJb1NlcnZlcic+ICYge1xuICAgIC8qKlxuICAgICAqIEVtaXQgaGlzdG9yeSBidWZmZXIgVFRMLiBEZWZhdWx0cyB0byBgc3RpY2t5Q29ubmVjdGlvblR0bEluU2Vjb25kc2AgKyBgcmVjb25uZWN0VGhyb3R0bGVEZWxheUluTXNgXG4gICAgICogKGNvbnZlcnRlZCB0byBzZWNvbmRzKVxuICAgICAqL1xuICAgIGVtaXRIaXN0b3J5VHRsSW5TZWNvbmRzPzogbnVtYmVyO1xuICAgIC8qKiBUaW1lb3V0IHdpdGhpbiBvZiB3aGljaCBhIGNvbm5lY3Rpb24gY2FuIGJlIHJlc3RvcmVkIGFzIHByZXZpb3VzIG9uZS4gRGVmYXVsdHMgdG8gYDEwYCAqL1xuICAgIHN0aWNreUNvbm5lY3Rpb25UdGxJblNlY29uZHM/OiBudW1iZXI7XG4gICAgLyoqIFJlY29ubmVjdGlvbiBkZWxheS4gVGhlIGRlbGF5IHdpbGwgYmUgaW5jcmVhc2VkIGJ5IDJ4IGVhY2ggZmFpbGVkIGNvbm5lY3Rpb24gYXR0ZW1wdC4gRGVmYXVsdHMgdG8gYDEwMDBgICovXG4gICAgcmVjb25uZWN0aW9uRGVsYXlJbk1zPzogbnVtYmVyO1xuICAgIC8qKiBNYXggcmVjb25uZWN0aW9uIGRlbGF5LiBEZWZhdWx0cyB0byBgMTAwMDBgICovXG4gICAgcmVjb25uZWN0aW9uRGVsYXlNYXhJbk1zPzogbnVtYmVyO1xuICAgIC8qKiBSZWNvbm5lY3Rpb24gZGVsYXkgcmFuZG9taXphdGlvbiBmYWN0b3IgaW4gcmFuZ2UgWzA7IDFdLiBEZWZhdWx0cyB0byBgMC41YCAqL1xuICAgIHJlY29ubmVjdGlvblJhbmRvbWl6YXRpb25GYWN0b3I/OiBudW1iZXI7XG4gIH07XG5cbiAgLyoqIEV2ZW50IGxpc3RlbmVycyAqL1xuICBleHBvcnQgdHlwZSBFdmVudHMgPSB7XG4gICAgLyoqIEZpcmVkIG9ubHkgb25jZSB1cG9uIGZpcnN0IGNvbm5lY3Rpb24gKi9cbiAgICBjb25uZWN0OiAoKSA9PiB2b2lkO1xuICAgIC8qKiBGaXJlZCBvbmx5IG9uY2UgdXBvbiB0aGUgbGFzdCBkaXNjb25uZWN0aW9uLiBXaWxsIGJlIGZpcmVkIGFueXdheSwgZXZlbiBpZiB3YXMgbmV2ZXIgY29ubmVjdGVkICovXG4gICAgZGlzY29ubmVjdDogKGVycj86IEVycm9yKSA9PiB2b2lkO1xuICAgIC8qKiBDdXN0b20gc3Vic2NyaXB0aW9uIGV2ZW50cyAqL1xuICAgIFtldmVudDogc3RyaW5nXTogKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnk7XG4gIH07XG5cbiAgLyoqIENvbm5lY3Rpb24gZXZlbnRzICovXG4gIGV4cG9ydCBjb25zdCBDT05ORUNUSU9OX0VWRU5UUyA9IFN0aWNreVNvY2tldENvbm5lY3Rpb24uQ09OTkVDVElPTl9FVkVOVFM7XG4gIC8qKiBJbnRlcm5hbCBldmVudHMgKi9cbiAgZXhwb3J0IGNvbnN0IElOVEVSTkFMX0VWRU5UUyA9IFN0aWNreVNvY2tldENvbm5lY3Rpb24uSU5URVJOQUxfRVZFTlRTO1xufVxuXG5leHBvcnQgZGVmYXVsdCBDbGllbnRTdGlja3lTb2NrZXQ7XG4iXSwibmFtZXMiOlsiQ2xpZW50U3RpY2t5U29ja2V0IiwiRXZlbnRFbWl0dGVyIiwiaWQiLCJfaWQiLCJzb2NrZXQiLCJfcG9vbCIsImdldFByb2Nlc3MiLCJ0cmFuc3BvcnROYW1lIiwiZmlyc3RIaXN0b3J5SW5kZXgiLCJjb25uZWN0ZWQiLCJfY29ubmVjdGVkIiwib24iLCJldmVudCIsImNhbGxiYWNrIiwiSU5URVJOQUxfRVZFTlRTIiwiaW5jbHVkZXMiLCJlcnJvcnMiLCJWYWxpZGF0aW9uRXJyb3IiLCJzZW5kIiwiYXJncyIsImRpc2Nvbm5lY3QiLCJlcnIiLCJjbGVhclRpbWVvdXQiLCJfc3RpY2t5Q29ubmVjdGlvbldhaXRUaW1lb3V0Iiwid2FzU3RvcHBlZCIsIl9zdG9wcGVkIiwic3RvcCIsImVtaXQiLCJkZXN0cm95SW50ZXJuYWxTb2NrZXQiLCJkZXN0cm95SW50ZXJuYWxDbGllbnRTb2NrZXQiLCJyZW1vdmVFeHBpcmVkRW1pdEhpc3RvcnkiLCJjb25zdHJ1Y3RvciIsInVybCIsIm9wdGlvbnMiLCJfbG9nZ2VyIiwiTG9nZ2VyTWFuYWdlciIsImdldExvZ2dlciIsInJhbmRvbXN0cmluZyIsImdlbmVyYXRlIiwiX2xhYmVsIiwibGFiZWwiLCJzdGlja3lDb25uZWN0aW9uVHRsSW5NcyIsInN0aWNreUNvbm5lY3Rpb25UdGxJblNlY29uZHMiLCJpbnRlcm5hbEV2ZW50cyIsIm9uY2UiLCJ1c2VOYXRpdmVTb2NrZXRJb1NlcnZlciIsInNldFRpbWVvdXQiLCJ3YXJuIiwibHJhcCIsIlJvb3RQb29sIiwiU3RpY2t5U29ja2V0Q29ubmVjdGlvbiIsImRlcGVuZGVuY2llcyIsInNjaGVkdWxlUHJvY2VzcyIsInN0YXJ0Q291bnQiLCJlbWl0SGlzdG9yeSIsIlF1ZXVlIiwibGFzdFNlbnRJbmRleCIsImxhc3RSZWNlaXZlZEluZGV4IiwiY29ubmVjdGlvbiIsImVtaXRIaXN0b3J5VHRsSW5TZWNvbmRzIiwibXNUb1NlY29uZHMiLCJmYWlsb3ZlclRocm90dGxlRGVsYXkiLCJtb2RlIiwicmVzZXREZWxheUluTXMiLCJtaW5EZWxheUluTXMiLCJyZWNvbm5lY3Rpb25EZWxheUluTXMiLCJtYXhEZWxheUluTXMiLCJyZWNvbm5lY3Rpb25EZWxheU1heEluTXMiLCJyYW5kb21pemF0aW9uRmFjdG9yIiwicmVjb25uZWN0aW9uUmFuZG9taXphdGlvbkZhY3RvciIsIkNPTk5FQ1RJT05fRVZFTlRTIl0sIm1hcHBpbmdzIjoiOzs7OytCQXVOQTs7O2VBQUE7OztxRUF2TnlCO2lGQUNIOytFQUNhO3NFQUNYOzZCQUNrQjtzQkFDaEI7cUVBQ0Q7K0RBQ0M7OERBQ1I7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVsQjs7Q0FFQyxHQUNELElBQUEsQUFBTUEscUJBQU4sTUFBTUEsMkJBQTJCQyxxQkFBWTtJQXFFM0M7OztHQUdDLEdBQ0QsSUFBSUMsS0FBYTtRQUNmLE9BQU8sSUFBSSxDQUFDQyxHQUFHO0lBQ2pCO0lBRUE7Ozs7R0FJQyxHQUNELElBQUlDLFNBQWdDO1lBQzNCO1FBQVAsUUFBTyx5QkFBQSxJQUFJLENBQUNDLEtBQUssQ0FBQ0MsVUFBVSxDQUFDLDJCQUF0Qiw2Q0FBQSx1QkFBcUNGLE1BQU07SUFDcEQ7SUFFQTs7OztHQUlDLEdBQ0QsSUFBSUcsZ0JBQXdCO1lBQ25CO1FBQVAsUUFBTyx5QkFBQSxJQUFJLENBQUNGLEtBQUssQ0FBQ0MsVUFBVSxDQUFDLDJCQUF0Qiw2Q0FBQSx1QkFBcUNDLGFBQWE7SUFDM0Q7SUFFQTs7OztHQUlDLEdBQ0QsSUFBSUMsb0JBQXdDO1lBQ25DO1FBQVAsUUFBTyx5QkFBQSxJQUFJLENBQUNI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