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)

177 lines (176 loc) 23.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return StreamingMetaApiConnectionInstance; } }); const _logger = /*#__PURE__*/ _interop_require_default(require("../logger")); const _metaApiConnectionInstance = /*#__PURE__*/ _interop_require_default(require("./metaApiConnectionInstance")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } let StreamingMetaApiConnectionInstance = class StreamingMetaApiConnectionInstance extends _metaApiConnectionInstance.default { /** * Opens the connection. Can only be called the first time, next calls will be ignored. * @return {Promise} promise resolving when the connection is opened */ async connect() { if (!this._opened) { this._opened = true; try { await this._metaApiConnection.connect(this.instanceId); } catch (err) { await this.close(); throw err; } } } /** * Clears the order and transaction history of a specified application and removes application * @return {Promise} promise resolving when the history is cleared and application is removed */ removeApplication() { return this._metaApiConnection.removeApplication(); } /** * Subscribes on market data of specified symbol (see * https://metaapi.cloud/docs/client/websocket/marketDataStreaming/subscribeToMarketData/). * @param {String} symbol symbol (e.g. currency pair or an index) * @param {Array<MarketDataSubscription>} subscriptions array of market data subscription to create or update. Please * note that this feature is not fully implemented on server-side yet * @param {number} [timeoutInSeconds] timeout to wait for prices in seconds, default is 30 * @param {boolean} [waitForQuote] if set to false, the method will resolve without waiting for the first quote to * arrive. Default is to wait for quote if quotes subscription is requested. * @returns {Promise} promise which resolves when subscription request was processed */ async subscribeToMarketData(symbol, subscriptions, timeoutInSeconds, waitForQuote = true) { this._checkIsConnectionActive(); return this._metaApiConnection.subscribeToMarketData(symbol, subscriptions, timeoutInSeconds, waitForQuote); } /** * Unsubscribes from market data of specified symbol (see * https://metaapi.cloud/docs/client/websocket/marketDataStreaming/unsubscribeFromMarketData/). * @param {String} symbol symbol (e.g. currency pair or an index) * @param {Array<MarketDataUnsubscription>} subscriptions array of subscriptions to cancel * @returns {Promise} promise which resolves when unsubscription request was processed */ unsubscribeFromMarketData(symbol, subscriptions) { this._checkIsConnectionActive(); return this._metaApiConnection.unsubscribeFromMarketData(symbol, subscriptions); } /** * Returns list of the symbols connection is subscribed to * @returns {Array<String>} list of the symbols connection is subscribed to */ get subscribedSymbols() { return this._metaApiConnection.subscribedSymbols; } /** * Returns subscriptions for a symbol * @param {string} symbol symbol to retrieve subscriptions for * @returns {Array<MarketDataSubscription>} list of market data subscriptions for the symbol */ subscriptions(symbol) { return this._metaApiConnection.subscriptions(symbol); } /** * Sends client uptime stats to the server. * @param {Object} uptime uptime statistics to send to the server * @returns {Promise} promise which resolves when uptime statistics is submitted */ saveUptime(uptime) { this._checkIsConnectionActive(); return this._websocketClient.saveUptime(this._metaApiConnection.account.id, uptime); } /** * Returns local copy of terminal state * @returns {TerminalState} local copy of terminal state */ get terminalState() { return this._metaApiConnection.terminalState; } /** * Returns local history storage * @returns {HistoryStorage} local history storage */ get historyStorage() { return this._metaApiConnection.historyStorage; } /** * Adds synchronization listener * @param {SynchronizationListener} listener synchronization listener to add */ addSynchronizationListener(listener) { this._synchronizationListeners.push(listener); this._websocketClient.addSynchronizationListener(this._metaApiConnection.account.id, listener); } /** * Removes synchronization listener for specific account * @param {SynchronizationListener} listener synchronization listener to remove */ removeSynchronizationListener(listener) { this._synchronizationListeners = this._synchronizationListeners.filter((l)=>l !== listener); this._websocketClient.removeSynchronizationListener(this._metaApiConnection.account.id, listener); } /** * @typedef {Object} SynchronizationOptions * @property {String} [applicationPattern] application regular expression pattern, default is .* * @property {String} [synchronizationId] synchronization id, last synchronization request id will be used by * default * @property {Number} [instanceIndex] index of an account instance to ensure synchronization on, default is to wait * for the first instance to synchronize * @property {Number} [timeoutInSeconds] wait timeout in seconds, default is 5m * @property {Number} [intervalInMilliseconds] interval between account reloads while waiting for a change, default is 1s */ /** * Waits until synchronization to MetaTrader terminal is completed * @param {SynchronizationOptions} opts synchronization options * @return {Promise} promise which resolves when synchronization to MetaTrader terminal is completed * @throws {TimeoutError} if application failed to synchronize with the teminal within timeout allowed */ // eslint-disable-next-line complexity async waitSynchronized(opts) { this._checkIsConnectionActive(); return this._metaApiConnection.waitSynchronized(opts); } /** * Queues an event for processing among other synchronization events within same account * @param {String} name event label name * @param {Function} callable async or regular function to execute */ queueEvent(name, callable) { this._websocketClient.queueEvent(this._metaApiConnection.account.id, name, callable); } /** * Closes the connection. The instance of the class should no longer be used after this method is invoked. */ async close() { if (!this._closed) { for (let listener of this._synchronizationListeners){ this._websocketClient.removeSynchronizationListener(this._metaApiConnection.account.id, listener); } this._closed = true; await this._metaApiConnection.close(this.instanceId); } } /** * Returns synchronization status * @return {boolean} synchronization status */ get synchronized() { return this._metaApiConnection.synchronized; } /** * Returns MetaApi account * @return {MetatraderAccount} MetaApi account */ get account() { return this._metaApiConnection.account; } /** * Returns connection health monitor instance * @return {ConnectionHealthMonitor} connection health monitor instance */ get healthMonitor() { return this._metaApiConnection.healthMonitor; } /** * Constructs MetaApi MetaTrader streaming Api connection instance * @param {MetaApiWebsocketClient} websocketClient MetaApi websocket client * @param {StreamingMetaApiConnection} metaApiConnection streaming MetaApi connection */ constructor(websocketClient, metaApiConnection){ super(websocketClient, metaApiConnection); this._metaApiConnection = metaApiConnection; this._synchronizationListeners = []; this._logger = _logger.default.getLogger("StreamingMetaApiConnectionInstance"); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBUZXJtaW5hbFN0YXRlIGZyb20gJy4vdGVybWluYWxTdGF0ZSc7XG5pbXBvcnQgQ29ubmVjdGlvbkhlYWx0aE1vbml0b3IgZnJvbSAnLi9jb25uZWN0aW9uSGVhbHRoTW9uaXRvcic7XG5pbXBvcnQgTG9nZ2VyTWFuYWdlciBmcm9tICcuLi9sb2dnZXInO1xuaW1wb3J0IE1ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2UgZnJvbSAnLi9tZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlJztcblxuLyoqXG4gKiBFeHBvc2VzIE1ldGFBcGkgTWV0YVRyYWRlciBzdHJlYW1pbmcgQVBJIGNvbm5lY3Rpb24gaW5zdGFuY2UgdG8gY29uc3VtZXJzXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFN0cmVhbWluZ01ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2UgZXh0ZW5kcyBNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlIHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBNZXRhQXBpIE1ldGFUcmFkZXIgc3RyZWFtaW5nIEFwaSBjb25uZWN0aW9uIGluc3RhbmNlXG4gICAqIEBwYXJhbSB7TWV0YUFwaVdlYnNvY2tldENsaWVudH0gd2Vic29ja2V0Q2xpZW50IE1ldGFBcGkgd2Vic29ja2V0IGNsaWVudFxuICAgKiBAcGFyYW0ge1N0cmVhbWluZ01ldGFBcGlDb25uZWN0aW9ufSBtZXRhQXBpQ29ubmVjdGlvbiBzdHJlYW1pbmcgTWV0YUFwaSBjb25uZWN0aW9uXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih3ZWJzb2NrZXRDbGllbnQsIG1ldGFBcGlDb25uZWN0aW9uKSB7XG4gICAgc3VwZXIod2Vic29ja2V0Q2xpZW50LCBtZXRhQXBpQ29ubmVjdGlvbik7XG4gICAgdGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24gPSBtZXRhQXBpQ29ubmVjdGlvbjtcbiAgICB0aGlzLl9zeW5jaHJvbml6YXRpb25MaXN0ZW5lcnMgPSBbXTtcbiAgICB0aGlzLl9sb2dnZXIgPSBMb2dnZXJNYW5hZ2VyLmdldExvZ2dlcignU3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZScpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9wZW5zIHRoZSBjb25uZWN0aW9uLiBDYW4gb25seSBiZSBjYWxsZWQgdGhlIGZpcnN0IHRpbWUsIG5leHQgY2FsbHMgd2lsbCBiZSBpZ25vcmVkLlxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIHRoZSBjb25uZWN0aW9uIGlzIG9wZW5lZFxuICAgKi9cbiAgYXN5bmMgY29ubmVjdCgpIHtcbiAgICBpZiAoIXRoaXMuX29wZW5lZCkge1xuICAgICAgdGhpcy5fb3BlbmVkID0gdHJ1ZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmNvbm5lY3QodGhpcy5pbnN0YW5jZUlkKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBhd2FpdCB0aGlzLmNsb3NlKCk7XG4gICAgICAgIHRocm93IGVycjtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXJzIHRoZSBvcmRlciBhbmQgdHJhbnNhY3Rpb24gaGlzdG9yeSBvZiBhIHNwZWNpZmllZCBhcHBsaWNhdGlvbiBhbmQgcmVtb3ZlcyBhcHBsaWNhdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIHRoZSBoaXN0b3J5IGlzIGNsZWFyZWQgYW5kIGFwcGxpY2F0aW9uIGlzIHJlbW92ZWRcbiAgICovXG4gIHJlbW92ZUFwcGxpY2F0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5yZW1vdmVBcHBsaWNhdGlvbigpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZXMgb24gbWFya2V0IGRhdGEgb2Ygc3BlY2lmaWVkIHN5bWJvbCAoc2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NsaWVudC93ZWJzb2NrZXQvbWFya2V0RGF0YVN0cmVhbWluZy9zdWJzY3JpYmVUb01hcmtldERhdGEvKS5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBzeW1ib2wgKGUuZy4gY3VycmVuY3kgcGFpciBvciBhbiBpbmRleClcbiAgICogQHBhcmFtIHtBcnJheTxNYXJrZXREYXRhU3Vic2NyaXB0aW9uPn0gc3Vic2NyaXB0aW9ucyBhcnJheSBvZiBtYXJrZXQgZGF0YSBzdWJzY3JpcHRpb24gdG8gY3JlYXRlIG9yIHVwZGF0ZS4gUGxlYXNlXG4gICAqIG5vdGUgdGhhdCB0aGlzIGZlYXR1cmUgaXMgbm90IGZ1bGx5IGltcGxlbWVudGVkIG9uIHNlcnZlci1zaWRlIHlldFxuICAgKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRJblNlY29uZHNdIHRpbWVvdXQgdG8gd2FpdCBmb3IgcHJpY2VzIGluIHNlY29uZHMsIGRlZmF1bHQgaXMgMzBcbiAgICogQHBhcmFtIHtib29sZWFufSBbd2FpdEZvclF1b3RlXSBpZiBzZXQgdG8gZmFsc2UsIHRoZSBtZXRob2Qgd2lsbCByZXNvbHZlIHdpdGhvdXQgd2FpdGluZyBmb3IgdGhlIGZpcnN0IHF1b3RlIHRvXG4gICAqIGFycml2ZS4gRGVmYXVsdCBpcyB0byB3YWl0IGZvciBxdW90ZSBpZiBxdW90ZXMgc3Vic2NyaXB0aW9uIGlzIHJlcXVlc3RlZC5cbiAgICogQHJldHVybnMge1Byb21pc2V9IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiBzdWJzY3JpcHRpb24gcmVxdWVzdCB3YXMgcHJvY2Vzc2VkXG4gICAqL1xuICBhc3luYyBzdWJzY3JpYmVUb01hcmtldERhdGEoc3ltYm9sLCBzdWJzY3JpcHRpb25zLCB0aW1lb3V0SW5TZWNvbmRzLCB3YWl0Rm9yUXVvdGUgPSB0cnVlKSB7XG4gICAgdGhpcy5fY2hlY2tJc0Nvbm5lY3Rpb25BY3RpdmUoKTtcbiAgICByZXR1cm4gdGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uc3Vic2NyaWJlVG9NYXJrZXREYXRhKHN5bWJvbCwgc3Vic2NyaXB0aW9ucywgdGltZW91dEluU2Vjb25kcywgd2FpdEZvclF1b3RlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVbnN1YnNjcmliZXMgZnJvbSBtYXJrZXQgZGF0YSBvZiBzcGVjaWZpZWQgc3ltYm9sIChzZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY2xpZW50L3dlYnNvY2tldC9tYXJrZXREYXRhU3RyZWFtaW5nL3Vuc3Vic2NyaWJlRnJvbU1hcmtldERhdGEvKS5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBzeW1ib2wgKGUuZy4gY3VycmVuY3kgcGFpciBvciBhbiBpbmRleClcbiAgICogQHBhcmFtIHtBcnJheTxNYXJrZXREYXRhVW5zdWJzY3JpcHRpb24+fSBzdWJzY3JpcHRpb25zIGFycmF5IG9mIHN1YnNjcmlwdGlvbnMgdG8gY2FuY2VsXG4gICAqIEByZXR1cm5zIHtQcm9taXNlfSBwcm9taXNlIHdoaWNoIHJlc29sdmVzIHdoZW4gdW5zdWJzY3JpcHRpb24gcmVxdWVzdCB3YXMgcHJvY2Vzc2VkXG4gICAqL1xuICB1bnN1YnNjcmliZUZyb21NYXJrZXREYXRhKHN5bWJvbCwgc3Vic2NyaXB0aW9ucykge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLnVuc3Vic2NyaWJlRnJvbU1hcmtldERhdGEoc3ltYm9sLCBzdWJzY3JpcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGxpc3Qgb2YgdGhlIHN5bWJvbHMgY29ubmVjdGlvbiBpcyBzdWJzY3JpYmVkIHRvXG4gICAqIEByZXR1cm5zIHtBcnJheTxTdHJpbmc+fSBsaXN0IG9mIHRoZSBzeW1ib2xzIGNvbm5lY3Rpb24gaXMgc3Vic2NyaWJlZCB0b1xuICAgKi9cbiAgZ2V0IHN1YnNjcmliZWRTeW1ib2xzKCkge1xuICAgIHJldHVybiB0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5zdWJzY3JpYmVkU3ltYm9scztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHN1YnNjcmlwdGlvbnMgZm9yIGEgc3ltYm9sXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzeW1ib2wgc3ltYm9sIHRvIHJldHJpZXZlIHN1YnNjcmlwdGlvbnMgZm9yXG4gICAqIEByZXR1cm5zIHtBcnJheTxNYXJrZXREYXRhU3Vic2NyaXB0aW9uPn0gbGlzdCBvZiBtYXJrZXQgZGF0YSBzdWJzY3JpcHRpb25zIGZvciB0aGUgc3ltYm9sXG4gICAqL1xuICBzdWJzY3JpcHRpb25zKHN5bWJvbCkge1xuICAgIHJldHVybiB0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5zdWJzY3JpcHRpb25zKHN5bWJvbCk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZHMgY2xpZW50IHVwdGltZSBzdGF0cyB0byB0aGUgc2VydmVyLlxuICAgKiBAcGFyYW0ge09iamVjdH0gdXB0aW1lIHVwdGltZSBzdGF0aXN0aWNzIHRvIHNlbmQgdG8gdGhlIHNlcnZlclxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHVwdGltZSBzdGF0aXN0aWNzIGlzIHN1Ym1pdHRlZFxuICAgKi9cbiAgc2F2ZVVwdGltZSh1cHRpbWUpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuc2F2ZVVwdGltZSh0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5hY2NvdW50LmlkLCB1cHRpbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgbG9jYWwgY29weSBvZiB0ZXJtaW5hbCBzdGF0ZVxuICAgKiBAcmV0dXJucyB7VGVybWluYWxTdGF0ZX0gbG9jYWwgY29weSBvZiB0ZXJtaW5hbCBzdGF0ZVxuICAgKi9cbiAgZ2V0IHRlcm1pbmFsU3RhdGUoKSB7XG4gICAgcmV0dXJuIHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLnRlcm1pbmFsU3RhdGU7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBsb2NhbCBoaXN0b3J5IHN0b3JhZ2VcbiAgICogQHJldHVybnMge0hpc3RvcnlTdG9yYWdlfSBsb2NhbCBoaXN0b3J5IHN0b3JhZ2VcbiAgICovXG4gIGdldCBoaXN0b3J5U3RvcmFnZSgpIHtcbiAgICByZXR1cm4gdGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uaGlzdG9yeVN0b3JhZ2U7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBzeW5jaHJvbml6YXRpb24gbGlzdGVuZXJcbiAgICogQHBhcmFtIHtTeW5jaHJvbml6YXRpb25MaXN0ZW5lcn0gbGlzdGVuZXIgc3luY2hyb25pemF0aW9uIGxpc3RlbmVyIHRvIGFkZFxuICAgKi9cbiAgYWRkU3luY2hyb25pemF0aW9uTGlzdGVuZXIobGlzdGVuZXIpIHtcbiAgICB0aGlzLl9zeW5jaHJvbml6YXRpb25MaXN0ZW5lcnMucHVzaChsaXN0ZW5lcik7XG4gICAgdGhpcy5fd2Vic29ja2V0Q2xpZW50LmFkZFN5bmNocm9uaXphdGlvbkxpc3RlbmVyKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIGxpc3RlbmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHN5bmNocm9uaXphdGlvbiBsaXN0ZW5lciBmb3Igc3BlY2lmaWMgYWNjb3VudFxuICAgKiBAcGFyYW0ge1N5bmNocm9uaXphdGlvbkxpc3RlbmVyfSBsaXN0ZW5lciBzeW5jaHJvbml6YXRpb24gbGlzdGVuZXIgdG8gcmVtb3ZlXG4gICAqL1xuICByZW1vdmVTeW5jaHJvbml6YXRpb25MaXN0ZW5lcihsaXN0ZW5lcikge1xuICAgIHRoaXMuX3N5bmNocm9uaXphdGlvbkxpc3RlbmVycyA9IHRoaXMuX3N5bmNocm9uaXphdGlvbkxpc3RlbmVycy5maWx0ZXIobCA9PiBsICE9PSBsaXN0ZW5lcik7XG4gICAgdGhpcy5fd2Vic29ja2V0Q2xpZW50LnJlbW92ZVN5bmNocm9uaXphdGlvbkxpc3RlbmVyKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIGxpc3RlbmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBTeW5jaHJvbml6YXRpb25PcHRpb25zXG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBbYXBwbGljYXRpb25QYXR0ZXJuXSBhcHBsaWNhdGlvbiByZWd1bGFyIGV4cHJlc3Npb24gcGF0dGVybiwgZGVmYXVsdCBpcyAuKlxuICAgKiBAcHJvcGVydHkge1N0cmluZ30gW3N5bmNocm9uaXphdGlvbklkXSBzeW5jaHJvbml6YXRpb24gaWQsIGxhc3Qgc3luY2hyb25pemF0aW9uIHJlcXVlc3QgaWQgd2lsbCBiZSB1c2VkIGJ5XG4gICAqIGRlZmF1bHRcbiAgICogQHByb3BlcnR5IHtOdW1iZXJ9IFtpbnN0YW5jZUluZGV4XSBpbmRleCBvZiBhbiBhY2NvdW50IGluc3RhbmNlIHRvIGVuc3VyZSBzeW5jaHJvbml6YXRpb24gb24sIGRlZmF1bHQgaXMgdG8gd2FpdFxuICAgKiBmb3IgdGhlIGZpcnN0IGluc3RhbmNlIHRvIHN5bmNocm9uaXplXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbdGltZW91dEluU2Vjb25kc10gd2FpdCB0aW1lb3V0IGluIHNlY29uZHMsIGRlZmF1bHQgaXMgNW1cbiAgICogQHByb3BlcnR5IHtOdW1iZXJ9IFtpbnRlcnZhbEluTWlsbGlzZWNvbmRzXSBpbnRlcnZhbCBiZXR3ZWVuIGFjY291bnQgcmVsb2FkcyB3aGlsZSB3YWl0aW5nIGZvciBhIGNoYW5nZSwgZGVmYXVsdCBpcyAxc1xuICAgKi9cblxuICAvKipcbiAgICogV2FpdHMgdW50aWwgc3luY2hyb25pemF0aW9uIHRvIE1ldGFUcmFkZXIgdGVybWluYWwgaXMgY29tcGxldGVkXG4gICAqIEBwYXJhbSB7U3luY2hyb25pemF0aW9uT3B0aW9uc30gb3B0cyBzeW5jaHJvbml6YXRpb24gb3B0aW9uc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHdoaWNoIHJlc29sdmVzIHdoZW4gc3luY2hyb25pemF0aW9uIHRvIE1ldGFUcmFkZXIgdGVybWluYWwgaXMgY29tcGxldGVkXG4gICAqIEB0aHJvd3Mge1RpbWVvdXRFcnJvcn0gaWYgYXBwbGljYXRpb24gZmFpbGVkIHRvIHN5bmNocm9uaXplIHdpdGggdGhlIHRlbWluYWwgd2l0aGluIHRpbWVvdXQgYWxsb3dlZFxuICAgKi9cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgYXN5bmMgd2FpdFN5bmNocm9uaXplZChvcHRzKSB7XG4gICAgdGhpcy5fY2hlY2tJc0Nvbm5lY3Rpb25BY3RpdmUoKTtcbiAgICByZXR1cm4gdGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24ud2FpdFN5bmNocm9uaXplZChvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWV1ZXMgYW4gZXZlbnQgZm9yIHByb2Nlc3NpbmcgYW1vbmcgb3RoZXIgc3luY2hyb25pemF0aW9uIGV2ZW50cyB3aXRoaW4gc2FtZSBhY2NvdW50XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIGV2ZW50IGxhYmVsIG5hbWVcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGFibGUgYXN5bmMgb3IgcmVndWxhciBmdW5jdGlvbiB0byBleGVjdXRlXG4gICAqL1xuICBxdWV1ZUV2ZW50KG5hbWUsIGNhbGxhYmxlKSB7XG4gICAgdGhpcy5fd2Vic29ja2V0Q2xpZW50LnF1ZXVlRXZlbnQodGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uYWNjb3VudC5pZCwgbmFtZSwgY2FsbGFibGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlcyB0aGUgY29ubmVjdGlvbi4gVGhlIGluc3RhbmNlIG9mIHRoZSBjbGFzcyBzaG91bGQgbm8gbG9uZ2VyIGJlIHVzZWQgYWZ0ZXIgdGhpcyBtZXRob2QgaXMgaW52b2tlZC5cbiAgICovXG4gIGFzeW5jIGNsb3NlKCkge1xuICAgIGlmICghdGhpcy5fY2xvc2VkKXtcbiAgICAgIGZvciAobGV0IGxpc3RlbmVyIG9mIHRoaXMuX3N5bmNocm9uaXphdGlvbkxpc3RlbmVycykge1xuICAgICAgICB0aGlzLl93ZWJzb2NrZXRDbGllbnQucmVtb3ZlU3luY2hyb25pemF0aW9uTGlzdGVuZXIodGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uYWNjb3VudC5pZCwgbGlzdGVuZXIpO1xuICAgICAgfVxuICAgICAgdGhpcy5fY2xvc2VkID0gdHJ1ZTtcbiAgICAgIGF3YWl0IHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmNsb3NlKHRoaXMuaW5zdGFuY2VJZCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3luY2hyb25pemF0aW9uIHN0YXR1c1xuICAgKiBAcmV0dXJuIHtib29sZWFufSBzeW5jaHJvbml6YXRpb24gc3RhdHVzXG4gICAqL1xuICBnZXQgc3luY2hyb25pemVkKCkge1xuICAgIHJldHVybiB0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5zeW5jaHJvbml6ZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBNZXRhQXBpIGFjY291bnRcbiAgICogQHJldHVybiB7TWV0YXRyYWRlckFjY291bnR9IE1ldGFBcGkgYWNjb3VudFxuICAgKi9cbiAgZ2V0IGFjY291bnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBjb25uZWN0aW9uIGhlYWx0aCBtb25pdG9yIGluc3RhbmNlXG4gICAqIEByZXR1cm4ge0Nvbm5lY3Rpb25IZWFsdGhNb25pdG9yfSBjb25uZWN0aW9uIGhlYWx0aCBtb25pdG9yIGluc3RhbmNlXG4gICAqL1xuICBnZXQgaGVhbHRoTW9uaXRvcigpIHtcbiAgICByZXR1cm4gdGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uaGVhbHRoTW9uaXRvcjtcbiAgfVxuXG59XG4iXSwibmFtZXMiOlsiU3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSIsIk1ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2UiLCJjb25uZWN0IiwiX29wZW5lZCIsIl9tZXRhQXBpQ29ubmVjdGlvbiIsImluc3RhbmNlSWQiLCJlcnIiLCJjbG9zZSIsInJlbW92ZUFwcGxpY2F0aW9uIiwic3Vic2NyaWJlVG9NYXJrZXREYXRhIiwic3ltYm9sIiwic3Vic2NyaXB0aW9ucyIsInRpbWVvdXRJblNlY29uZHMiLCJ3YWl0Rm9yUXVvdGUiLCJfY2hlY2tJc0Nvbm5lY3Rpb25BY3RpdmUiLCJ1bnN1YnNjcmliZUZyb21NYXJrZXREYXRhIiwic3Vic2NyaWJlZFN5bWJvbHMiLCJzYXZlVXB0aW1lIiwidXB0aW1lIiwiX3dlYnNvY2tldENsaWVudCIsImFjY291bnQiLCJpZCIsInRlcm1pbmFsU3RhdGUiLCJoaXN0b3J5U3RvcmFnZSIsImFkZFN5bmNocm9uaXphdGlvbkxpc3RlbmVyIiwibGlzdGVuZXIiLCJfc3luY2hyb25pemF0aW9uTGlzdGVuZXJzIiwicHVzaCIsInJlbW92ZVN5bmNocm9uaXphdGlvbkxpc3RlbmVyIiwiZmlsdGVyIiwibCIsIndhaXRTeW5jaHJvbml6ZWQiLCJvcHRzIiwicXVldWVFdmVudCIsIm5hbWUiLCJjYWxsYWJsZSIsIl9jbG9zZWQiLCJzeW5jaHJvbml6ZWQiLCJoZWFsdGhNb25pdG9yIiwiY29uc3RydWN0b3IiLCJ3ZWJzb2NrZXRDbGllbnQiLCJtZXRhQXBpQ29ubmVjdGlvbiIsIl9sb2dnZXIiLCJMb2dnZXJNYW5hZ2VyIiwiZ2V0TG9nZ2VyIl0sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztlQVVxQkE7OzsrREFOSztrRkFDWTs7Ozs7O0FBS3ZCLElBQUEsQUFBTUEscUNBQU4sTUFBTUEsMkNBQTJDQyxrQ0FBeUI7SUFjdkY7OztHQUdDLEdBQ0QsTUFBTUMsVUFBVTtRQUNkLElBQUksQ0FBQyxJQUFJLENBQUNDLE9BQU8sRUFBRTtZQUNqQixJQUFJLENBQUNBLE9BQU8sR0FBRztZQUNmLElBQUk7Z0JBQ0YsTUFBTSxJQUFJLENBQUNDLGtCQUFrQixDQUFDRixPQUFPLENB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