UNPKG

metaapi.cloud-copyfactory-sdk

Version:

Javascript SDK for SDK for CopyFactory trade copying API. Can copy trades both between MetaTrader 5 (MT5) and MetaTrader 4 (MT4). (https://metaapi.cloud)

330 lines (329 loc) 39.3 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 MetaApiClient from '../metaapi.client'; import SubscriberSignalClient from './subscriberSignal.client'; import StrategySignalClient from './strategySignal.client'; import StopoutListenerManager from './streaming/stopoutListenerManager'; import UserLogListenerManager from './streaming/userLogListenerManager'; export * from './trading.client.schemas'; let TradingClient = class TradingClient extends MetaApiClient { /** * Resynchronizes the account. See * https://metaapi.cloud/docs/copyfactory/restApi/api/trading/resynchronize/ * @param {string} accountId account id * @param {Array<string>} [strategyIds] array of strategy ids to recynchronize. Default is to synchronize all * strategies * @param {Array<string>} [positionIds] array of position ids to resynchronize. Default is to synchronize all * positions * @return {Promise} promise which resolves when resynchronization is scheduled */ resynchronize(accountId, strategyIds, positionIds) { var _this = this; return _async_to_generator(function*() { if (_this._isNotJwtToken()) { return _this._handleNoAccessError('resynchronize'); } const opts = { url: `/users/current/subscribers/${accountId}/resynchronize`, method: 'POST', headers: { 'auth-token': _this._token }, params: { strategyId: strategyIds, positionId: positionIds }, json: true }; return _this._domainClient.requestCopyFactory(opts); })(); } /** * Generates an instance of signal client for a subscriber * @param {string} subscriberId subscriber account id */ getSubscriberSignalClient(subscriberId) { var _this = this; return _async_to_generator(function*() { if (_this._isNotJwtToken()) { return _this._handleNoAccessError('getSubscriberSignalClient'); } let accountData = yield _this._domainClient.getAccountInfo(subscriberId); const host = yield _this._domainClient.getSignalClientHost(accountData.regions); return new SubscriberSignalClient(accountData.id, host, _this._domainClient); })(); } /** * Generates an instance of signal client for a strategy * @param {string} strategyId strategy id */ getStrategySignalClient(strategyId) { var _this = this; return _async_to_generator(function*() { if (_this._isNotJwtToken()) { return _this._handleNoAccessError('getStrategySignalClient'); } const strategy = yield _this._configurationClient.getStrategy(strategyId); const accountData = yield _this._domainClient.getAccountInfo(strategy.accountId); const host = yield _this._domainClient.getSignalClientHost(accountData.regions); return new StrategySignalClient(accountData.id, strategyId, host, _this._domainClient); })(); } /** * Returns subscriber account stopouts. See * https://metaapi.cloud/docs/copyfactory/restApi/api/trading/getStopOuts/ * @param {string} subscriberId subscriber id * @return {Promise<Array<CopyFactoryStrategyStopout>>} promise which resolves with stopouts found */ getStopouts(subscriberId) { var _this = this; return _async_to_generator(function*() { if (_this._isNotJwtToken()) { return _this._handleNoAccessError('getStopouts'); } const opts = { url: `/users/current/subscribers/${subscriberId}/stopouts`, method: 'GET', headers: { 'auth-token': _this._token }, json: true }; return _this._domainClient.requestCopyFactory(opts); })(); } /** * Resets subscription stopouts. See * https://metaapi.cloud/docs/copyfactory/restApi/api/trading/resetSubscriptionStopOuts/ * @param {string} subscriberId subscriber id * @param {string} strategyId strategy id * @param {CopyFactoryStrategyStopoutReason} reason stopout reason to reset * yearly-equity, monthly-equity, daily-equity * @return {Promise} promise which resolves when the stopouts are reset */ resetSubscriptionStopouts(subscriberId, strategyId, reason) { if (this._isNotJwtToken()) { return this._handleNoAccessError('resetSubscriptionStopouts'); } const opts = { url: `/users/current/subscribers/${subscriberId}/subscription-strategies/` + `${strategyId}/stopouts/${reason}/reset`, method: 'POST', headers: { 'auth-token': this._token }, json: true }; return this._domainClient.requestCopyFactory(opts); } /** * Resets subscriber stopouts. See * https://metaapi.cloud/docs/copyfactory/restApi/api/trading/resetSubscriberStopOuts/ * @param {string} subscriberId subscriber id * @param {CopyFactoryStrategyStopoutReason} reason stopout reason to reset * yearly-equity, monthly-equity, daily-equity * @return {Promise} promise which resolves when the stopouts are reset */ resetSubscriberStopouts(subscriberId, reason) { if (this._isNotJwtToken()) { return this._handleNoAccessError('resetSubscriberStopouts'); } const opts = { url: `/users/current/subscribers/${subscriberId}/stopouts/${reason}/reset`, method: 'POST', headers: { 'auth-token': this._token }, json: true }; return this._domainClient.requestCopyFactory(opts); } /** * Returns copy trading user log for an account and time range. See * https://metaapi.cloud/docs/copyfactory/restApi/api/trading/getUserLog/ * @param {string} subscriberId subscriber id * @param {Date} [startTime] time to start loading data from * @param {Date} [endTime] time to stop loading data at * @param {string} [strategyId] strategy id filter * @param {string} [positionId] position id filter * @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level * @param {Number} [offset] pagination offset. Default is 0 * @param {Number} [limit] pagination limit. Default is 1000 * @return {Promise<Array<CopyFactoryUserLogMessage>>} promise which resolves with log records found */ getUserLog(subscriberId, startTime, endTime, strategyId, positionId, level, offset = 0, limit = 1000) { var _this = this; return _async_to_generator(function*() { if (_this._isNotJwtToken()) { return _this._handleNoAccessError('getUserLog'); } const opts = { url: `/users/current/subscribers/${subscriberId}/user-log`, method: 'GET', params: { startTime, endTime, strategyId, positionId, level, offset, limit }, headers: { 'auth-token': _this._token }, json: true }; let result = yield _this._domainClient.requestCopyFactory(opts, true); if (result) { result.map((r)=>r.time = new Date(r.time)); } return result; })(); } /** * Returns event log for CopyFactory strategy, sorted in reverse chronological order. See * https://metaapi.cloud/docs/copyfactory/restApi/api/trading/getStrategyLog/ * @param {string} strategyId strategy id to retrieve log for * @param {Date} [startTime] time to start loading data from * @param {Date} [endTime] time to stop loading data at * @param {string} [positionId] position id filter * @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level * @param {Number} [offset] pagination offset. Default is 0 * @param {Number} [limit] pagination limit. Default is 1000 * @return {Promise<Array<CopyFactoryUserLogMessage>>} promise which resolves with log records found */ getStrategyLog(strategyId, startTime, endTime, positionId, level, offset = 0, limit = 1000) { var _this = this; return _async_to_generator(function*() { if (_this._isNotJwtToken()) { return _this._handleNoAccessError('getStrategyLog'); } const opts = { url: `/users/current/strategies/${strategyId}/user-log`, method: 'GET', params: { startTime, endTime, positionId, level, offset, limit }, headers: { 'auth-token': _this._token }, json: true }; let result = yield _this._domainClient.requestCopyFactory(opts, true); if (result) { result.map((r)=>r.time = new Date(r.time)); } return result; })(); } /** * Adds a stopout listener and creates a job to make requests * @param {StopoutListener} listener stopout listener * @param {string} [accountId] account id * @param {string} [strategyId] strategy id * @param {Number} [sequenceNumber] sequence number * @return {string} listener id */ addStopoutListener(listener, accountId, strategyId, sequenceNumber) { return this._stopoutListenerManager.addStopoutListener(listener, accountId, strategyId, sequenceNumber); } /** * Removes stopout listener and cancels the event stream * @param {string} listenerId stopout listener id */ removeStopoutListener(listenerId) { this._stopoutListenerManager.removeStopoutListener(listenerId); } /** * Adds a strategy log listener and creates a job to make requests * @param {UserLogListener} listener user log listener * @param {string} strategyId strategy id * @param {Date} [startTime] log search start time * @param {string} [positionId] position id filter * @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level * @param {Number} [limit] log pagination limit * @return {string} listener id */ addStrategyLogListener(listener, strategyId, startTime, positionId, level, limit) { return this._userLogListenerManager.addStrategyLogListener(listener, strategyId, startTime, positionId, level, limit); } /** * Removes strategy log listener and cancels the event stream * @param {string} listenerId strategy log listener id */ removeStrategyLogListener(listenerId) { this._userLogListenerManager.removeStrategyLogListener(listenerId); } /** * Adds a subscriber log listener and creates a job to make requests * @param {UserLogListener} listener user log listener * @param {string} subscriberId subscriber id * @param {Date} [startTime] log search start time * @param {string} [strategyId] strategy id filter * @param {string} [positionId] position id filter * @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level * @param {Number} [limit] log pagination limit * @return {string} listener id */ addSubscriberLogListener(listener, subscriberId, startTime, strategyId, positionId, level, limit) { return this._userLogListenerManager.addSubscriberLogListener(listener, subscriberId, startTime, strategyId, positionId, level, limit); } /** * Removes subscriber log listener and cancels the event stream * @param {string} listenerId subscriber log listener id */ removeSubscriberLogListener(listenerId) { this._userLogListenerManager.removeSubscriberLogListener(listenerId); } /** * Constructs CopyFactory trading API client instance * @param {DomainClient} domainClient domain client * @param {ConfigurationClient} configurationClient configuration client */ constructor(domainClient, configurationClient){ super(domainClient); _define_property(this, "_configurationClient", void 0); _define_property(this, "_stopoutListenerManager", void 0); _define_property(this, "_userLogListenerManager", void 0); this._domainClient = domainClient; this._configurationClient = configurationClient; this._stopoutListenerManager = new StopoutListenerManager(domainClient); this._userLogListenerManager = new UserLogListenerManager(domainClient); } }; /** * metaapi.cloud CopyFactory trading API (trade copying trading API) client (see * https://metaapi.cloud/docs/copyfactory/) */ export { TradingClient as default }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBNZXRhQXBpQ2xpZW50IGZyb20gJy4uL21ldGFhcGkuY2xpZW50JztcbmltcG9ydCBTdWJzY3JpYmVyU2lnbmFsQ2xpZW50IGZyb20gJy4vc3Vic2NyaWJlclNpZ25hbC5jbGllbnQnO1xuaW1wb3J0IFN0cmF0ZWd5U2lnbmFsQ2xpZW50IGZyb20gJy4vc3RyYXRlZ3lTaWduYWwuY2xpZW50JztcbmltcG9ydCBTdG9wb3V0TGlzdGVuZXJNYW5hZ2VyIGZyb20gJy4vc3RyZWFtaW5nL3N0b3BvdXRMaXN0ZW5lck1hbmFnZXInO1xuaW1wb3J0IFVzZXJMb2dMaXN0ZW5lck1hbmFnZXIgZnJvbSAnLi9zdHJlYW1pbmcvdXNlckxvZ0xpc3RlbmVyTWFuYWdlcic7XG5pbXBvcnQgQ29uZmlndXJhdGlvbkNsaWVudCBmcm9tICcuL2NvbmZpZ3VyYXRpb24uY2xpZW50JztcbmltcG9ydCBEb21haW5DbGllbnQgZnJvbSAnLi4vZG9tYWluLmNsaWVudCc7XG5pbXBvcnQgU3RvcG91dExpc3RlbmVyIGZyb20gJy4vc3RyZWFtaW5nL3N0b3BvdXRMaXN0ZW5lcic7XG5pbXBvcnQgVXNlckxvZ0xpc3RlbmVyIGZyb20gJy4vc3RyZWFtaW5nL3VzZXJMb2dMaXN0ZW5lcic7XG5pbXBvcnQge1xuICBDb3B5RmFjdG9yeVN0cmF0ZWd5U3RvcG91dCwgQ29weUZhY3RvcnlTdHJhdGVneVN0b3BvdXRSZWFzb24sIENvcHlGYWN0b3J5VXNlckxvZ01lc3NhZ2Vcbn0gZnJvbSAnLi90cmFkaW5nLmNsaWVudC5zY2hlbWFzJztcblxuZXhwb3J0ICogZnJvbSAnLi90cmFkaW5nLmNsaWVudC5zY2hlbWFzJztcblxuLyoqXG4gKiBtZXRhYXBpLmNsb3VkIENvcHlGYWN0b3J5IHRyYWRpbmcgQVBJICh0cmFkZSBjb3B5aW5nIHRyYWRpbmcgQVBJKSBjbGllbnQgKHNlZVxuICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvKVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUcmFkaW5nQ2xpZW50IGV4dGVuZHMgTWV0YUFwaUNsaWVudCB7XG4gIFxuICBwcml2YXRlIF9jb25maWd1cmF0aW9uQ2xpZW50OiBDb25maWd1cmF0aW9uQ2xpZW50O1xuICBwcml2YXRlIF9zdG9wb3V0TGlzdGVuZXJNYW5hZ2VyOiBTdG9wb3V0TGlzdGVuZXJNYW5hZ2VyO1xuICBwcml2YXRlIF91c2VyTG9nTGlzdGVuZXJNYW5hZ2VyOiBVc2VyTG9nTGlzdGVuZXJNYW5hZ2VyO1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIENvcHlGYWN0b3J5IHRyYWRpbmcgQVBJIGNsaWVudCBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge0RvbWFpbkNsaWVudH0gZG9tYWluQ2xpZW50IGRvbWFpbiBjbGllbnRcbiAgICogQHBhcmFtIHtDb25maWd1cmF0aW9uQ2xpZW50fSBjb25maWd1cmF0aW9uQ2xpZW50IGNvbmZpZ3VyYXRpb24gY2xpZW50XG4gICAqL1xuICBjb25zdHJ1Y3Rvcihkb21haW5DbGllbnQ6IERvbWFpbkNsaWVudCwgY29uZmlndXJhdGlvbkNsaWVudDogQ29uZmlndXJhdGlvbkNsaWVudCkge1xuICAgIHN1cGVyKGRvbWFpbkNsaWVudCk7XG4gICAgdGhpcy5fZG9tYWluQ2xpZW50ID0gZG9tYWluQ2xpZW50O1xuICAgIHRoaXMuX2NvbmZpZ3VyYXRpb25DbGllbnQgPSBjb25maWd1cmF0aW9uQ2xpZW50O1xuICAgIHRoaXMuX3N0b3BvdXRMaXN0ZW5lck1hbmFnZXIgPSBuZXcgU3RvcG91dExpc3RlbmVyTWFuYWdlcihkb21haW5DbGllbnQpO1xuICAgIHRoaXMuX3VzZXJMb2dMaXN0ZW5lck1hbmFnZXIgPSBuZXcgVXNlckxvZ0xpc3RlbmVyTWFuYWdlcihkb21haW5DbGllbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc3luY2hyb25pemVzIHRoZSBhY2NvdW50LiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvdHJhZGluZy9yZXN5bmNocm9uaXplL1xuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBbc3RyYXRlZ3lJZHNdIGFycmF5IG9mIHN0cmF0ZWd5IGlkcyB0byByZWN5bmNocm9uaXplLiBEZWZhdWx0IGlzIHRvIHN5bmNocm9uaXplIGFsbFxuICAgKiBzdHJhdGVnaWVzXG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gW3Bvc2l0aW9uSWRzXSBhcnJheSBvZiBwb3NpdGlvbiBpZHMgdG8gcmVzeW5jaHJvbml6ZS4gRGVmYXVsdCBpcyB0byBzeW5jaHJvbml6ZSBhbGxcbiAgICogcG9zaXRpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiByZXN5bmNocm9uaXphdGlvbiBpcyBzY2hlZHVsZWRcbiAgICovXG4gIGFzeW5jIHJlc3luY2hyb25pemUoYWNjb3VudElkOiBzdHJpbmcsIHN0cmF0ZWd5SWRzPzogQXJyYXk8c3RyaW5nPiwgcG9zaXRpb25JZHM/OiBBcnJheTxzdHJpbmc+KTogUHJvbWlzZTxhbnk+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcigncmVzeW5jaHJvbml6ZScpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvc3Vic2NyaWJlcnMvJHthY2NvdW50SWR9L3Jlc3luY2hyb25pemVgLFxuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgc3RyYXRlZ3lJZDogc3RyYXRlZ3lJZHMsXG4gICAgICAgIHBvc2l0aW9uSWQ6IHBvc2l0aW9uSWRzXG4gICAgICB9LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cyk7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGFuIGluc3RhbmNlIG9mIHNpZ25hbCBjbGllbnQgZm9yIGEgc3Vic2NyaWJlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgYWNjb3VudCBpZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3Vic2NyaWJlclNpZ25hbENsaWVudChzdWJzY3JpYmVySWQ6IHN0cmluZyk6IFByb21pc2U8U3Vic2NyaWJlclNpZ25hbENsaWVudD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRTdWJzY3JpYmVyU2lnbmFsQ2xpZW50Jyk7XG4gICAgfVxuXG4gICAgbGV0IGFjY291bnREYXRhID0gYXdhaXQgdGhpcy5fZG9tYWluQ2xpZW50LmdldEFjY291bnRJbmZvKHN1YnNjcmliZXJJZCk7XG4gICAgY29uc3QgaG9zdCA9IGF3YWl0IHRoaXMuX2RvbWFpbkNsaWVudC5nZXRTaWduYWxDbGllbnRIb3N0KGFjY291bnREYXRhLnJlZ2lvbnMpO1xuICAgIHJldHVybiBuZXcgU3Vic2NyaWJlclNpZ25hbENsaWVudChhY2NvdW50RGF0YS5pZCwgaG9zdCwgdGhpcy5fZG9tYWluQ2xpZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYW4gaW5zdGFuY2Ugb2Ygc2lnbmFsIGNsaWVudCBmb3IgYSBzdHJhdGVneVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3RyYXRlZ3lTaWduYWxDbGllbnQoc3RyYXRlZ3lJZDogc3RyaW5nKTogUHJvbWlzZTxTdHJhdGVneVNpZ25hbENsaWVudD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRTdHJhdGVneVNpZ25hbENsaWVudCcpO1xuICAgIH1cblxuICAgIGNvbnN0IHN0cmF0ZWd5ID0gYXdhaXQgdGhpcy5fY29uZmlndXJhdGlvbkNsaWVudC5nZXRTdHJhdGVneShzdHJhdGVneUlkKTtcbiAgICBjb25zdCBhY2NvdW50RGF0YSA9IGF3YWl0IHRoaXMuX2RvbWFpbkNsaWVudC5nZXRBY2NvdW50SW5mbyhzdHJhdGVneS5hY2NvdW50SWQpO1xuICAgIGNvbnN0IGhvc3QgPSBhd2FpdCB0aGlzLl9kb21haW5DbGllbnQuZ2V0U2lnbmFsQ2xpZW50SG9zdChhY2NvdW50RGF0YS5yZWdpb25zKTtcbiAgICByZXR1cm4gbmV3IFN0cmF0ZWd5U2lnbmFsQ2xpZW50KGFjY291bnREYXRhLmlkLCBzdHJhdGVneUlkLCBob3N0LCB0aGlzLl9kb21haW5DbGllbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3Vic2NyaWJlciBhY2NvdW50IHN0b3BvdXRzLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvdHJhZGluZy9nZXRTdG9wT3V0cy9cbiAgICogQHBhcmFtIHtzdHJpbmd9IHN1YnNjcmliZXJJZCBzdWJzY3JpYmVyIGlkXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8Q29weUZhY3RvcnlTdHJhdGVneVN0b3BvdXQ+Pn0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aXRoIHN0b3BvdXRzIGZvdW5kXG4gICAqL1xuICBhc3luYyBnZXRTdG9wb3V0cyhzdWJzY3JpYmVySWQ6IHN0cmluZyk6IFByb21pc2U8QXJyYXk8Q29weUZhY3RvcnlTdHJhdGVneVN0b3BvdXQ+PiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ2dldFN0b3BvdXRzJyk7XG4gICAgfVxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9zdWJzY3JpYmVycy8ke3N1YnNjcmliZXJJZH0vc3RvcG91dHNgLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyBzdWJzY3JpcHRpb24gc3RvcG91dHMuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS90cmFkaW5nL3Jlc2V0U3Vic2NyaXB0aW9uU3RvcE91dHMvXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdWJzY3JpYmVySWQgc3Vic2NyaWJlciBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0NvcHlGYWN0b3J5U3RyYXRlZ3lTdG9wb3V0UmVhc29ufSByZWFzb24gc3RvcG91dCByZWFzb24gdG8gcmVzZXRcbiAgICogeWVhcmx5LWVxdWl0eSwgbW9udGhseS1lcXVpdHksIGRhaWx5LWVxdWl0eVxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHdoaWNoIHJlc29sdmVzIHdoZW4gdGhlIHN0b3BvdXRzIGFyZSByZXNldFxuICAgKi9cbiAgcmVzZXRTdWJzY3JpcHRpb25TdG9wb3V0cyhcbiAgICBzdWJzY3JpYmVySWQ6IHN0cmluZywgc3RyYXRlZ3lJZDogc3RyaW5nLCByZWFzb246IENvcHlGYWN0b3J5U3RyYXRlZ3lTdG9wb3V0UmVhc29uXG4gICk6IFByb21pc2U8YW55PiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ3Jlc2V0U3Vic2NyaXB0aW9uU3RvcG91dHMnKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L3N1YnNjcmliZXJzLyR7c3Vic2NyaWJlcklkfS9zdWJzY3JpcHRpb24tc3RyYXRlZ2llcy9gICtcbiAgICAgICAgYCR7c3RyYXRlZ3lJZH0vc3RvcG91dHMvJHtyZWFzb259L3Jlc2V0YCxcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cyk7XG4gIH1cblxuICAvKipcbiAgICogUmVzZXRzIHN1YnNjcmliZXIgc3RvcG91dHMuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS90cmFkaW5nL3Jlc2V0U3Vic2NyaWJlclN0b3BPdXRzL1xuICAgKiBAcGFyYW0ge3N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgaWRcbiAgICogQHBhcmFtIHtDb3B5RmFjdG9yeVN0cmF0ZWd5U3RvcG91dFJlYXNvbn0gcmVhc29uIHN0b3BvdXQgcmVhc29uIHRvIHJlc2V0XG4gICAqIHllYXJseS1lcXVpdHksIG1vbnRobHktZXF1aXR5LCBkYWlseS1lcXVpdHlcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHRoZSBzdG9wb3V0cyBhcmUgcmVzZXRcbiAgICovXG4gIHJlc2V0U3Vic2NyaWJlclN0b3BvdXRzKHN1YnNjcmliZXJJZDogc3RyaW5nLCByZWFzb246IENvcHlGYWN0b3J5U3RyYXRlZ3lTdG9wb3V0UmVhc29uKTogUHJvbWlzZTxhbnk+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcigncmVzZXRTdWJzY3JpYmVyU3RvcG91dHMnKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L3N1YnNjcmliZXJzLyR7c3Vic2NyaWJlcklkfS9zdG9wb3V0cy8ke3JlYXNvbn0vcmVzZXRgLFxuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGNvcHkgdHJhZGluZyB1c2VyIGxvZyBmb3IgYW4gYWNjb3VudCBhbmQgdGltZSByYW5nZS4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL3RyYWRpbmcvZ2V0VXNlckxvZy9cbiAgICogQHBhcmFtIHtzdHJpbmd9IHN1YnNjcmliZXJJZCBzdWJzY3JpYmVyIGlkXG4gICAqIEBwYXJhbSB7RGF0ZX0gW3N0YXJ0VGltZV0gdGltZSB0byBzdGFydCBsb2FkaW5nIGRhdGEgZnJvbVxuICAgKiBAcGFyYW0ge0RhdGV9IFtlbmRUaW1lXSB0aW1lIHRvIHN0b3AgbG9hZGluZyBkYXRhIGF0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbc3RyYXRlZ3lJZF0gc3RyYXRlZ3kgaWQgZmlsdGVyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcG9zaXRpb25JZF0gcG9zaXRpb24gaWQgZmlsdGVyXG4gICAqIEBwYXJhbSB7J0RFQlVHJ3wnSU5GTyd8J1dBUk4nfCdFUlJPUid9IFtsZXZlbF0gbWluaW11bSBzZXZlcml0eSBsZXZlbFxuICAgKiBAcGFyYW0ge051bWJlcn0gW29mZnNldF0gcGFnaW5hdGlvbiBvZmZzZXQuIERlZmF1bHQgaXMgMFxuICAgKiBAcGFyYW0ge051bWJlcn0gW2xpbWl0XSBwYWdpbmF0aW9uIGxpbWl0LiBEZWZhdWx0IGlzIDEwMDBcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVVzZXJMb2dNZXNzYWdlPj59IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2l0aCBsb2cgcmVjb3JkcyBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0VXNlckxvZyhcbiAgICBzdWJzY3JpYmVySWQ6IHN0cmluZywgc3RhcnRUaW1lPzogRGF0ZSwgZW5kVGltZT86IERhdGUsIHN0cmF0ZWd5SWQ/OiBzdHJpbmcsIHBvc2l0aW9uSWQ/OiBzdHJpbmcsXG4gICAgbGV2ZWw/OiAnREVCVUcnIHwgJ0lORk8nIHwgJ1dBUk4nIHwgJ0VSUk9SJywgb2Zmc2V0ID0gMCwgbGltaXQgPSAxMDAwXG4gICk6IFByb21pc2U8QXJyYXk8Q29weUZhY3RvcnlVc2VyTG9nTWVzc2FnZT4+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignZ2V0VXNlckxvZycpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvc3Vic2NyaWJlcnMvJHtzdWJzY3JpYmVySWR9L3VzZXItbG9nYCxcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgc3RhcnRUaW1lLFxuICAgICAgICBlbmRUaW1lLFxuICAgICAgICBzdHJhdGVneUlkLCBcbiAgICAgICAgcG9zaXRpb25JZCwgXG4gICAgICAgIGxldmVsLFxuICAgICAgICBvZmZzZXQsXG4gICAgICAgIGxpbWl0XG4gICAgICB9LFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cywgdHJ1ZSk7XG4gICAgaWYgKHJlc3VsdCkge1xuICAgICAgcmVzdWx0Lm1hcChyID0+IHIudGltZSA9IG5ldyBEYXRlKHIudGltZSkpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgZXZlbnQgbG9nIGZvciBDb3B5RmFjdG9yeSBzdHJhdGVneSwgc29ydGVkIGluIHJldmVyc2UgY2hyb25vbG9naWNhbCBvcmRlci4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL3RyYWRpbmcvZ2V0U3RyYXRlZ3lMb2cvIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZCB0byByZXRyaWV2ZSBsb2cgZm9yXG4gICAqIEBwYXJhbSB7RGF0ZX0gW3N0YXJ0VGltZV0gdGltZSB0byBzdGFydCBsb2FkaW5nIGRhdGEgZnJvbVxuICAgKiBAcGFyYW0ge0RhdGV9IFtlbmRUaW1lXSB0aW1lIHRvIHN0b3AgbG9hZGluZyBkYXRhIGF0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcG9zaXRpb25JZF0gcG9zaXRpb24gaWQgZmlsdGVyXG4gICAqIEBwYXJhbSB7J0RFQlVHJ3wnSU5GTyd8J1dBUk4nfCdFUlJPUid9IFtsZXZlbF0gbWluaW11bSBzZXZlcml0eSBsZXZlbFxuICAgKiBAcGFyYW0ge051bWJlcn0gW29mZnNldF0gcGFnaW5hdGlvbiBvZmZzZXQuIERlZmF1bHQgaXMgMFxuICAgKiBAcGFyYW0ge051bWJlcn0gW2xpbWl0XSBwYWdpbmF0aW9uIGxpbWl0LiBEZWZhdWx0IGlzIDEwMDBcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVVzZXJMb2dNZXNzYWdlPj59IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2l0aCBsb2cgcmVjb3JkcyBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3RyYXRlZ3lMb2coXG4gICAgc3RyYXRlZ3lJZDogc3RyaW5nLCBzdGFydFRpbWU/OiBEYXRlLCBlbmRUaW1lPzogRGF0ZSwgcG9zaXRpb25JZD86IHN0cmluZyxcbiAgICBsZXZlbD86ICdERUJVRycgfCAnSU5GTycgfCAnV0FSTicgfCAnRVJST1InLCBvZmZzZXQgPSAwLCBsaW1pdCA9IDEwMDBcbiAgKTogUHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVVzZXJMb2dNZXNzYWdlPj4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRTdHJhdGVneUxvZycpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvc3RyYXRlZ2llcy8ke3N0cmF0ZWd5SWR9L3VzZXItbG9nYCxcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgc3RhcnRUaW1lLFxuICAgICAgICBlbmRUaW1lLFxuICAgICAgICBwb3NpdGlvbklkLFxuICAgICAgICBsZXZlbCxcbiAgICAgICAgb2Zmc2V0LFxuICAgICAgICBsaW1pdFxuICAgICAgfSxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIGxldCByZXN1bHQgPSBhd2FpdCB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMsIHRydWUpO1xuICAgIGlmIChyZXN1bHQpIHtcbiAgICAgIHJlc3VsdC5tYXAociA9PiByLnRpbWUgPSBuZXcgRGF0ZShyLnRpbWUpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgc3RvcG91dCBsaXN0ZW5lciBhbmQgY3JlYXRlcyBhIGpvYiB0byBtYWtlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSB7U3RvcG91dExpc3RlbmVyfSBsaXN0ZW5lciBzdG9wb3V0IGxpc3RlbmVyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYWNjb3VudElkXSBhY2NvdW50IGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbc3RyYXRlZ3lJZF0gc3RyYXRlZ3kgaWRcbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtzZXF1ZW5jZU51bWJlcl0gc2VxdWVuY2UgbnVtYmVyXG4gICAqIEByZXR1cm4ge3N0cmluZ30gbGlzdGVuZXIgaWRcbiAgICovXG4gIGFkZFN0b3BvdXRMaXN0ZW5lcihcbiAgICBsaXN0ZW5lcjogU3RvcG91dExpc3RlbmVyLCBhY2NvdW50SWQ/OiBzdHJpbmcsIHN0cmF0ZWd5SWQ/OiBzdHJpbmcsIHNlcXVlbmNlTnVtYmVyPzogbnVtYmVyXG4gICk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3N0b3BvdXRMaXN0ZW5lck1hbmFnZXIuYWRkU3RvcG91dExpc3RlbmVyKGxpc3RlbmVyLCBhY2NvdW50SWQsIHN0cmF0ZWd5SWQsIHNlcXVlbmNlTnVtYmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHN0b3BvdXQgbGlzdGVuZXIgYW5kIGNhbmNlbHMgdGhlIGV2ZW50IHN0cmVhbVxuICAgKiBAcGFyYW0ge3N0cmluZ30gbGlzdGVuZXJJZCBzdG9wb3V0IGxpc3RlbmVyIGlkXG4gICAqL1xuICByZW1vdmVTdG9wb3V0TGlzdGVuZXIobGlzdGVuZXJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5fc3RvcG91dExpc3RlbmVyTWFuYWdlci5yZW1vdmVTdG9wb3V0TGlzdGVuZXIobGlzdGVuZXJJZCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHN0cmF0ZWd5IGxvZyBsaXN0ZW5lciBhbmQgY3JlYXRlcyBhIGpvYiB0byBtYWtlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSB7VXNlckxvZ0xpc3RlbmVyfSBsaXN0ZW5lciB1c2VyIGxvZyBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0RhdGV9IFtzdGFydFRpbWVdIGxvZyBzZWFyY2ggc3RhcnQgdGltZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3Bvc2l0aW9uSWRdIHBvc2l0aW9uIGlkIGZpbHRlclxuICAgKiBAcGFyYW0geydERUJVRyd8J0lORk8nfCdXQVJOJ3wnRVJST1InfSBbbGV2ZWxdIG1pbmltdW0gc2V2ZXJpdHkgbGV2ZWxcbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtsaW1pdF0gbG9nIHBhZ2luYXRpb24gbGltaXRcbiAgICogQHJldHVybiB7c3RyaW5nfSBsaXN0ZW5lciBpZFxuICAgKi9cbiAgYWRkU3RyYXRlZ3lMb2dMaXN0ZW5lcihcbiAgICBsaXN0ZW5lcjogVXNlckxvZ0xpc3RlbmVyLCBzdHJhdGVneUlkOiBzdHJpbmcsIHN0YXJ0VGltZT86IERhdGUsIHBvc2l0aW9uSWQ/OiBzdHJpbmcsXG4gICAgbGV2ZWw/OiAnREVCVUcnIHwgJ0lORk8nIHwgJ1dBUk4nIHwgJ0VSUk9SJywgbGltaXQ/OiBudW1iZXJcbiAgKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fdXNlckxvZ0xpc3RlbmVyTWFuYWdlci5hZGRTdHJhdGVneUxvZ0xpc3RlbmVyKFxuICAgICAgbGlzdGVuZXIsIFxuICAgICAgc3RyYXRlZ3lJZCwgXG4gICAgICBzdGFydFRpbWUsIFxuICAgICAgcG9zaXRpb25JZCwgXG4gICAgICBsZXZlbCwgXG4gICAgICBsaW1pdFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBzdHJhdGVneSBsb2cgbGlzdGVuZXIgYW5kIGNhbmNlbHMgdGhlIGV2ZW50IHN0cmVhbVxuICAgKiBAcGFyYW0ge3N0cmluZ30gbGlzdGVuZXJJZCBzdHJhdGVneSBsb2cgbGlzdGVuZXIgaWRcbiAgICovXG4gIHJlbW92ZVN0cmF0ZWd5TG9nTGlzdGVuZXIobGlzdGVuZXJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5fdXNlckxvZ0xpc3RlbmVyTWFuYWdlci5yZW1vdmVTdHJhdGVneUxvZ0xpc3RlbmVyKGxpc3RlbmVySWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBzdWJzY3JpYmVyIGxvZyBsaXN0ZW5lciBhbmQgY3JlYXRlcyBhIGpvYiB0byBtYWtlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSB7VXNlckxvZ0xpc3RlbmVyfSBsaXN0ZW5lciB1c2VyIGxvZyBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgaWRcbiAgICogQHBhcmFtIHtEYXRlfSBbc3RhcnRUaW1lXSBsb2cgc2VhcmNoIHN0YXJ0IHRpbWVcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtzdHJhdGVneUlkXSBzdHJhdGVneSBpZCBmaWx0ZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtwb3NpdGlvbklkXSBwb3NpdGlvbiBpZCBmaWx0ZXJcbiAgICogQHBhcmFtIHsnREVCVUcnfCdJTkZPJ3wnV0FSTid8J0VSUk9SJ30gW2xldmVsXSBtaW5pbXVtIHNldmVyaXR5IGxldmVsXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBbbGltaXRdIGxvZyBwYWdpbmF0aW9uIGxpbWl0XG4gICAqIEByZXR1cm4ge3N0cmluZ30gbGlzdGVuZXIgaWRcbiAgICovXG4gIGFkZFN1YnNjcmliZXJMb2dMaXN0ZW5lcihcbiAgICBsaXN0ZW5lcjogVXNlckxvZ0xpc3RlbmVyLCBzdWJzY3JpYmVySWQ6IHN0cmluZywgc3RhcnRUaW1lPzogRGF0ZSwgc3RyYXRlZ3lJZD86IHN0cmluZywgcG9zaXRpb25JZD86IHN0cmluZyxcbiAgICBsZXZlbD86ICdERUJVRycgfCAnSU5GTycgfCAnV0FSTicgfCAnRVJST1InLCBsaW1pdD86IG51bWJlclxuICApOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl91c2VyTG9nTGlzdGVuZXJNYW5hZ2VyLmFkZFN1YnNjcmliZXJMb2dMaXN0ZW5lcihcbiAgICAgIGxpc3RlbmVyLCBcbiAgICAgIHN1YnNjcmliZXJJZCwgXG4gICAgICBzdGFydFRpbWUsIFxuICAgICAgc3RyYXRlZ3lJZCwgXG4gICAgICBwb3NpdGlvbklkLCBcbiAgICAgIGxldmVsLCBcbiAgICAgIGxpbWl0XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHN1YnNjcmliZXIgbG9nIGxpc3RlbmVyIGFuZCBjYW5jZWxzIHRoZSBldmVudCBzdHJlYW1cbiAgICogQHBhcmFtIHtzdHJpbmd9IGxpc3RlbmVySWQgc3Vic2NyaWJlciBsb2cgbGlzdGVuZXIgaWRcbiAgICovXG4gIHJlbW92ZVN1YnNjcmliZXJMb2dMaXN0ZW5lcihsaXN0ZW5lcklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLl91c2VyTG9nTGlzdGVuZXJNYW5hZ2VyLnJlbW92ZVN1YnNjcmliZXJMb2dMaXN0ZW5lcihsaXN0ZW5lcklkKTtcbiAgfVxufVxuIl0sIm5hbWVzIjpbIk1ldGFBcGlDbGllbnQiLCJTdWJzY3JpYmVyU2lnbmFsQ2xpZW50IiwiU3RyYXRlZ3lTaWduYWxDbGllbnQiLCJTdG9wb3V0TGlzdGVuZXJNYW5hZ2VyIiwiVXNlckxvZ0xpc3RlbmVyTWFuYWdlciIsIlRyYWRpbmdDbGllbnQiLCJyZXN5bmNocm9uaXplIiwiYWNjb3VudElkIiwic3RyYXRlZ3lJZHMiLCJwb3NpdGlvbklkcyIsIl9pc05vdEp3dFRva2VuIiwiX2hhbmRsZU5vQWNjZXNzRXJyb3IiLCJvcHRzIiwidXJsIiwibWV0aG9kIiwiaGVhZGVycyIsIl90b2tlbiIsInBhcmFtcyIsInN0cmF0ZWd5SWQiLCJwb3NpdGlvbklkIiwianNvbiIsIl9kb21haW5DbGllbnQiLCJyZXF1ZXN0Q29weUZhY3RvcnkiLCJnZXRTdWJzY3JpYmVyU2lnbmFsQ2xpZW50Iiwic3Vic2NyaWJlcklkIiwiYWNjb3VudERhdGEiLCJnZXRBY2NvdW50SW5mbyIsImhvc3QiLCJnZXRTaWduYWxDbGllbnRIb3N0IiwicmVnaW9ucyIsImlkIiwiZ2V0U3RyYXRlZ3lTaWduYWxDbGllbnQiLCJzdHJhdGVneSIsIl9jb25maWd1cmF0aW9uQ2xpZW50IiwiZ2V0U3RyYXRlZ3kiLCJnZXRTdG9wb3V0cyIsInJlc2V0U3Vic2NyaXB0aW9uU3RvcG91dHMiLCJyZWFzb24iLCJyZXNldFN1YnNjcmliZXJTdG9wb3V0cyIsImdldFVzZXJMb2ciLCJzdGFydFRpbWUiLCJlbmRUaW1lIiwibGV2ZWwiLCJvZmZzZXQiLCJsaW1pdCIsInJlc3VsdCIsIm1hcCIsInIiLCJ0aW1lIiwiRGF0ZSIsImdldFN0cmF0ZWd5TG9nIiwiYWRkU3RvcG91dExpc3RlbmVyIiwibGlzdGVuZXIiLCJzZXF1ZW5jZU51bWJlciIsIl9zdG9wb3V0TGlzdGVuZXJNYW5hZ2VyIiwicmVtb3ZlU3RvcG91dExpc3RlbmVyIiwibGlzdGVuZXJJZCIsImFkZFN0cmF0ZWd5TG9nTGlzdGVuZXIiLCJfdXNlckxvZ0xpc3RlbmVyTWFuYWdlciIsInJlbW92ZVN0cmF0ZWd5TG9nTGlzdGVuZXIiLCJhZGRTdWJzY3JpYmVyTG9nTGlzdGVuZXIiLCJyZW1vdmVTdWJzY3JpYmVyTG9nTGlzdGVuZXIiLCJjb25zdHJ1Y3RvciIsImRvbWFpbkNsaWVudCIsImNvbmZpZ3VyYXRpb25DbGllbnQiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUEsT0FBT0EsbUJBQW1CLG9CQUFvQjtBQUM5QyxPQUFPQyw0QkFBNEIsNEJBQTRCO0FBQy9ELE9BQU9DLDBCQUEwQiwwQkFBMEI7QUFDM0QsT0FBT0MsNEJBQTRCLHFDQUFxQztBQUN4RSxPQUFPQyw0QkFBNEIscUNBQXFDO0FBU3hFLGNBQWMsMkJBQTJCO0FBTTFCLElBQUEsQUFBTUMsZ0JBQU4sTUFBTUEsc0JB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