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)

388 lines (387 loc) 45.5 kB
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; } function _object_spread(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === "function") { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function(key) { _define_property(target, key, source[key]); }); } return target; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function(sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _object_spread_props(target, source) { source = source != null ? source : {}; if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function(key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } import * as lrap from '../long-running-async-process'; import ioClient from 'socket.io-client'; import socketWildcard from '../socket.io-wildcard'; import { BINARY_EVENT, EVENT, RESTORE_CONNECTION_EVENT } from './common.types'; import { getClientSocketIoTransportName, sendHistory } from './common.utils'; import LoggerManager from '../../logger'; /** * A socket connection */ let StickySocketConnection = class StickySocketConnection extends lrap.RootProcess { /** * Returns native socket * @returns socket.io socket */ get socket() { return this._socket; } /** * Returns current transport name, using socket.io internals * @returns transport name, e.g. "websocket" */ get transportName() { return getClientSocketIoTransportName(this._socket); } /** * Returns first present packet index in last emit history * @returns first history index * @internal intended for tests only */ get firstHistoryIndex() { var _this__sharedState_emitHistory_front; return (_this__sharedState_emitHistory_front = this._sharedState.emitHistory.front()) === null || _this__sharedState_emitHistory_front === void 0 ? void 0 : _this__sharedState_emitHistory_front.index; } /** * @inheritdoc * @param client parent client * @param internalEvents internal event emitter */ inject(client, internalEvents) { this._client = client; this._internalEvents = internalEvents; } /** * @inheritdoc * @param url url to connect to * @param sessionId session ID * @param sharedState shared state * @param options additiona options */ initialize(url, sessionId, sharedState, options) { var _options_connection; this._options = options; this._label = (options === null || options === void 0 ? void 0 : options.label) || 'default'; this._sharedState = sharedState; this._sharedState.startCount++; let query = _object_spread_props(_object_spread({}, options === null || options === void 0 ? void 0 : (_options_connection = options.connection) === null || _options_connection === void 0 ? void 0 : _options_connection.query), { stickySocketConnectionId: sessionId }); if (sharedState.startCount > 1) { var _this__sharedState_emitHistory_front; let request = { lastReceivedIndex: sharedState.lastReceivedIndex, lastSentIndex: sharedState.lastSentIndex, firstHistoryIndex: (_this__sharedState_emitHistory_front = this._sharedState.emitHistory.front()) === null || _this__sharedState_emitHistory_front === void 0 ? void 0 : _this__sharedState_emitHistory_front.index, sessionId }; this._logger.debug(`${this._label}: restoring session`, JSON.stringify(request)); query.restoreStickyConnection = encodeURIComponent(JSON.stringify(request)); } this._socket = ioClient(url, _object_spread_props(_object_spread({}, options === null || options === void 0 ? void 0 : options.connection), { reconnection: false, autoConnect: false, query })); socketWildcard(ioClient.Manager)(this._socket); this._socket.on('*', (packet)=>{ if (packet.type === EVENT || packet.type === BINARY_EVENT) { var _this__options; let payload = packet.data[1]; if ((_this__options = this._options) === null || _this__options === void 0 ? void 0 : _this__options.useNativeSocketIoServer) { this._client.emit(packet.data[0], ...packet.data.slice(1)); return; } if ('index' in payload) { this._logger.trace(()=>`${this._label}: received packet ` + JSON.stringify({ index: payload.index })); var _this__sharedState_lastReceivedIndex; this._sharedState.lastReceivedIndex = Math.max((_this__sharedState_lastReceivedIndex = this._sharedState.lastReceivedIndex) !== null && _this__sharedState_lastReceivedIndex !== void 0 ? _this__sharedState_lastReceivedIndex : -1, payload.index); this._client.emit(packet.data[0], ...payload.data); } } }); } /** * 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__options; if ((_this__options = this._options) === null || _this__options === void 0 ? void 0 : _this__options.useNativeSocketIoServer) { this._socket.emit(event, ...args); return; } let packet = { index: ++this._sharedState.lastSentIndex, event, data: args, time: new Date() }; this._sharedState.emitHistory.push(packet); this._socket.emit(event, { index: packet.index, data: packet.data }); } /** * @inheritdoc */ start(stopPromise) { var _this = this; return _async_to_generator(function*() { try { let connectPromise = _this._connect(stopPromise); let restorePromise = _this._restoreConnectionIfNeeded(stopPromise); let [_, restored] = yield Promise.all([ connectPromise, restorePromise ]); if (restored) { _this._logger.info(`${_this._label}: restored connection session`); } } catch (err) { _this._logger.warn(`${_this._label}: failed to connect`, err); if (_this._sharedState.startCount === 1 || err instanceof RestoreRejectError) { _this._client.disconnect(err); } throw new lrap.ControlSignal({ action: 'failover', severity: 'info' }); } })(); } _connect(stopPromise) { this._socket.connect(); return new Promise((resolve, reject)=>{ stopPromise.then(()=>reject(new Error('Stopped during connection'))); this._setSocketStageListener('connect', ()=>{ // Emitting connect immediately to guarantee no data events will be received until connect event emitted this._logger.debug(`${this._label}: internal socket connected`); this._internalEvents.emit('connect'); resolve(); }); this._setSocketStageListener('disconnect', (reason)=>{ this._disconnectReason = reason; reject(new Error(`Disconnected when connecting due to ${reason}`)); }); this._setSocketStageListener('error', (err)=>reject(err)); this._setSocketStageListener('connect_error', (err)=>reject(err)); this._setSocketStageListener('connect_timeout', (err)=>reject(err)); }); } _restoreConnectionIfNeeded(stopPromise) { var _this = this; return _async_to_generator(function*() { if (_this._sharedState.startCount === 1) { return false; } let sendSinceIndex = yield new Promise((resolve, reject)=>{ stopPromise.then(()=>reject(new Error('Stopped during restoring connection'))); _this._setSocketStageListener(RESTORE_CONNECTION_EVENT, (event)=>{ event.restored ? resolve(event.sendSinceIndex) : reject(new RestoreRejectError('Cannot restore connection session')); }); _this._setSocketStageListener('disconnect', (reason)=>{ reject(new Error(`Disconnected when restoring connection due to ${reason}`)); }); _this._setSocketStageListener('error', (err)=>reject(err)); _this._setSocketStageListener('connect_error', (err)=>reject(err)); _this._setSocketStageListener('connect_timeout', (err)=>reject(err)); }); _this._logger.debug(`${_this._label}: sending history since ${sendSinceIndex} packet index`); sendHistory(_this._socket, _this._sharedState.emitHistory, sendSinceIndex); return true; })(); } /** * @inheritdoc */ run(stopPromise) { var _this = this; return _async_to_generator(function*() { var _this__options; var _this__options_emitHistoryTtlInSeconds; const historyBufferTtlInMs = 1000 * ((_this__options_emitHistoryTtlInSeconds = (_this__options = _this._options) === null || _this__options === void 0 ? void 0 : _this__options.emitHistoryTtlInSeconds) !== null && _this__options_emitHistoryTtlInSeconds !== void 0 ? _this__options_emitHistoryTtlInSeconds : 10); let clearOldHistoryInterval = setInterval(()=>_this.removeExpiredEmitHistory(), historyBufferTtlInMs); try { if (_this._disconnectReason) { if (!_this._tryDisconnectClientGracefully(_this._disconnectReason)) { throw new Error(`Disconnected due to ${_this._disconnectReason}`); } return; } _this._removePrevStageListeners(); yield Promise.race([ stopPromise, new Promise((resolve, reject)=>{ _this._setSocketStageListener('disconnect', (reason)=>{ if (!_this._tryDisconnectClientGracefully(reason)) { reject(new Error(`Disconnected due to ${reason}`)); } }); _this._setSocketStageListener('error', reject); }) ]); } catch (err) { _this._logger.warn(`${_this._label}: lost connection`, err); _this._internalEvents.emit('fail', err); throw new lrap.ControlSignal({ action: 'failover', severity: 'info' }); } finally{ _this._removePrevStageListeners(); clearInterval(clearOldHistoryInterval); } })(); } /** * Removes expired emit history */ removeExpiredEmitHistory() { var _this__options; var _this__options_emitHistoryTtlInSeconds; const historyBufferTtlInMs = 1000 * ((_this__options_emitHistoryTtlInSeconds = (_this__options = this._options) === null || _this__options === void 0 ? void 0 : _this__options.emitHistoryTtlInSeconds) !== null && _this__options_emitHistoryTtlInSeconds !== void 0 ? _this__options_emitHistoryTtlInSeconds : 10); while(this._sharedState.emitHistory.length){ if (Date.now() - this._sharedState.emitHistory.front().time.getTime() > historyBufferTtlInMs) { this._sharedState.emitHistory.shift(); } else { break; } } } _tryDisconnectClientGracefully(reason) { if (reason === 'io client disconnect' || reason === 'io server disconnect') { this._logger.info(`${this._label}: disconnecting client due to ${reason}`); this._client.disconnect(); return true; } return false; } /** * @inheritdoc */ stop() { var _this = this; return _async_to_generator(function*() { _this._socket.disconnect(); })(); } _setSocketStageListener(event, listener) { var _this__prevStageListeners, _event; (_this__prevStageListeners = this._prevStageListeners)[_event = event] || (_this__prevStageListeners[_event] = new Set()); this._prevStageListeners[event].add(listener); this._socket.on(event, listener); return listener; } _removePrevStageListeners() { for (let [event, listeners] of Object.entries(this._prevStageListeners)){ for (let listener of listeners){ this._socket.off(event, listener); } } } constructor(...args){ super(...args); _define_property(this, "_options", void 0); _define_property(this, "_socket", void 0); _define_property(this, "_client", void 0); _define_property(this, "_sharedState", void 0); _define_property(this, "_internalEvents", void 0); _define_property(this, "_disconnectReason", void 0); _define_property(this, "_logger", LoggerManager.getLogger(StickySocketConnection.name)); _define_property(this, "_prevStageListeners", {}); _define_property(this, "_label", void 0); } }; (function(StickySocketConnection) { /** Connection events */ StickySocketConnection.CONNECTION_EVENTS = [ 'connect', 'disconnect' ]; /** Sticky connection protocol events */ StickySocketConnection.PROTOCOL_EVENTS = [ RESTORE_CONNECTION_EVENT ]; /** Internal events */ StickySocketConnection.INTERNAL_EVENTS = [ 'error', 'connect_error', 'connect_timeout', 'reconnect', 'reconnect_attempt', 'reconnecting', 'reconnect_error', 'reconnect_failed', 'ping', 'pong', ...StickySocketConnection.PROTOCOL_EVENTS ]; })(StickySocketConnection || (StickySocketConnection = {})); export default StickySocketConnection; /** * Error, meaning that the server rejected the restore request. E.g. server may have already * removed old emit history, required by the client, so the restoring cannot be done */ let RestoreRejectError = class RestoreRejectError extends Error { }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBscmFwIGZyb20gJy4uL2xvbmctcnVubmluZy1hc3luYy1wcm9jZXNzJztcbmltcG9ydCBpb0NsaWVudCBmcm9tICdzb2NrZXQuaW8tY2xpZW50JztcbmltcG9ydCBDbGllbnRTdGlja3lTb2NrZXQgZnJvbSAnLi9jbGllbnRTdGlja3lTb2NrZXQnO1xuaW1wb3J0IHNvY2tldFdpbGRjYXJkIGZyb20gJy4uL3NvY2tldC5pby13aWxkY2FyZCc7XG5pbXBvcnQge1xuICBCSU5BUllfRVZFTlQsXG4gIENsaWVudFNvY2tldERpc2Nvbm5lY3RSZWFzb24sXG4gIEVWRU5ULFxuICBFbWl0SGlzdG9yeVBhY2tldCwgRW1pdFBhY2tldCwgUkVTVE9SRV9DT05ORUNUSU9OX0VWRU5ULCBSZXN0b3JlQ29ubmVjdGlvblJlcXVlc3QsIFJlc3RvcmVDb25uZWN0aW9uUmVzcG9uc2UsXG4gIFNvY2tldE9wdGlvbnNcbn0gZnJvbSAnLi9jb21tb24udHlwZXMnO1xuaW1wb3J0IHtnZXRDbGllbnRTb2NrZXRJb1RyYW5zcG9ydE5hbWUsIHNlbmRIaXN0b3J5fSBmcm9tICcuL2NvbW1vbi51dGlscyc7XG5pbXBvcnQgRXZlbnRFbWl0dGVyIGZyb20gJy4uLy4uL3Rvb2xzL2V2ZW50RW1pdHRlcic7XG5pbXBvcnQgTG9nZ2VyTWFuYWdlciBmcm9tICcuLi8uLi9sb2dnZXInO1xuaW1wb3J0IFF1ZXVlIGZyb20gJy4uLy4uL3Rvb2xzL3F1ZXVlJztcblxuLyoqXG4gKiBBIHNvY2tldCBjb25uZWN0aW9uXG4gKi9cbmNsYXNzIFN0aWNreVNvY2tldENvbm5lY3Rpb24gZXh0ZW5kcyBscmFwLlJvb3RQcm9jZXNzIHtcbiAgXG4gIHByaXZhdGUgX29wdGlvbnM/OiBTdGlja3lTb2NrZXRDb25uZWN0aW9uLk9wdGlvbnM7XG4gIHByaXZhdGUgX3NvY2tldDogU29ja2V0SU9DbGllbnQuU29ja2V0O1xuICBwcml2YXRlIF9jbGllbnQ6IENsaWVudFN0aWNreVNvY2tldDtcbiAgcHJpdmF0ZSBfc2hhcmVkU3RhdGU6IFN0aWNreVNvY2tldENvbm5lY3Rpb24uU2hhcmVkU3RhdGU7XG4gIHByaXZhdGUgX2ludGVybmFsRXZlbnRzOiBFdmVudEVtaXR0ZXI8U3RpY2t5U29ja2V0Q29ubmVjdGlvbi5TaGFyZWRFdmVudHM+O1xuICBwcml2YXRlIF9kaXNjb25uZWN0UmVhc29uPzogQ2xpZW50U29ja2V0RGlzY29ubmVjdFJlYXNvbjtcbiAgcHJpdmF0ZSBfbG9nZ2VyID0gTG9nZ2VyTWFuYWdlci5nZXRMb2dnZXIoU3RpY2t5U29ja2V0Q29ubmVjdGlvbi5uYW1lKTtcbiAgcHJpdmF0ZSBfcHJldlN0YWdlTGlzdGVuZXJzOiB7W2V2ZW50OiBzdHJpbmddOiBTZXQ8KC4uLmFyZ3M6IGFueVtdKSA9PiB2b2lkPn0gPSB7fTtcbiAgcHJpdmF0ZSBfbGFiZWw6IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyBuYXRpdmUgc29ja2V0XG4gICAqIEByZXR1cm5zIHNvY2tldC5pbyBzb2NrZXRcbiAgICovXG4gIGdldCBzb2NrZXQoKTogU29ja2V0SU9DbGllbnQuU29ja2V0IHtcbiAgICByZXR1cm4gdGhpcy5fc29ja2V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCB0cmFuc3BvcnQgbmFtZSwgdXNpbmcgc29ja2V0LmlvIGludGVybmFsc1xuICAgKiBAcmV0dXJucyB0cmFuc3BvcnQgbmFtZSwgZS5nLiBcIndlYnNvY2tldFwiXG4gICAqL1xuICBnZXQgdHJhbnNwb3J0TmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiBnZXRDbGllbnRTb2NrZXRJb1RyYW5zcG9ydE5hbWUodGhpcy5fc29ja2V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGZpcnN0IHByZXNlbnQgcGFja2V0IGluZGV4IGluIGxhc3QgZW1pdCBoaXN0b3J5XG4gICAqIEByZXR1cm5zIGZpcnN0IGhpc3RvcnkgaW5kZXhcbiAgICogQGludGVybmFsIGludGVuZGVkIGZvciB0ZXN0cyBvbmx5XG4gICAqL1xuICBnZXQgZmlyc3RIaXN0b3J5SW5kZXgoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fc2hhcmVkU3RhdGUuZW1pdEhpc3RvcnkuZnJvbnQoKT8uaW5kZXg7XG4gIH1cblxuICAvKipcbiAgICogQGluaGVyaXRkb2NcbiAgICogQHBhcmFtIGNsaWVudCBwYXJlbnQgY2xpZW50XG4gICAqIEBwYXJhbSBpbnRlcm5hbEV2ZW50cyBpbnRlcm5hbCBldmVudCBlbWl0dGVyXG4gICAqL1xuICBpbmplY3QoY2xpZW50OiBDbGllbnRTdGlja3lTb2NrZXQsIGludGVybmFsRXZlbnRzOiBFdmVudEVtaXR0ZXI8U3RpY2t5U29ja2V0Q29ubmVjdGlvbi5TaGFyZWRFdmVudHM+KTogdm9pZCB7XG4gICAgdGhpcy5fY2xpZW50ID0gY2xpZW50O1xuICAgIHRoaXMuX2ludGVybmFsRXZlbnRzID0gaW50ZXJuYWxFdmVudHM7XG4gIH1cblxuICAvKipcbiAgICogQGluaGVyaXRkb2NcbiAgICogQHBhcmFtIHVybCB1cmwgdG8gY29ubmVjdCB0b1xuICAgKiBAcGFyYW0gc2Vzc2lvbklkIHNlc3Npb24gSURcbiAgICogQHBhcmFtIHNoYXJlZFN0YXRlIHNoYXJlZCBzdGF0ZVxuICAgKiBAcGFyYW0gb3B0aW9ucyBhZGRpdGlvbmEgb3B0aW9uc1xuICAgKi9cbiAgaW5pdGlhbGl6ZShcbiAgICB1cmw6IHN0cmluZywgc2Vzc2lvbklkOiBzdHJpbmcsIHNoYXJlZFN0YXRlOiBTdGlja3lTb2NrZXRDb25uZWN0aW9uLlNoYXJlZFN0YXRlLFxuICAgIG9wdGlvbnM/OiBTdGlja3lTb2NrZXRDb25uZWN0aW9uLk9wdGlvbnNcbiAgKSB7XG4gICAgdGhpcy5fb3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5fbGFiZWwgPSBvcHRpb25zPy5sYWJlbCB8fCAnZGVmYXVsdCc7XG4gICAgdGhpcy5fc2hhcmVkU3RhdGUgPSBzaGFyZWRTdGF0ZTtcbiAgICB0aGlzLl9zaGFyZWRTdGF0ZS5zdGFydENvdW50Kys7XG4gICAgbGV0IHF1ZXJ5ID0ge1xuICAgICAgLi4ub3B0aW9ucz8uY29ubmVjdGlvbj8ucXVlcnksXG4gICAgICBzdGlja3lTb2NrZXRDb25uZWN0aW9uSWQ6IHNlc3Npb25JZFxuICAgIH0gYXMgUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICBpZiAoc2hhcmVkU3RhdGUuc3RhcnRDb3VudCA+IDEpIHtcbiAgICAgIGxldCByZXF1ZXN0OiBSZXN0b3JlQ29ubmVjdGlvblJlcXVlc3QgPSB7XG4gICAgICAgIGxhc3RSZWNlaXZlZEluZGV4OiBzaGFyZWRTdGF0ZS5sYXN0UmVjZWl2ZWRJbmRleCxcbiAgICAgICAgbGFzdFNlbnRJbmRleDogc2hhcmVkU3RhdGUubGFzdFNlbnRJbmRleCxcbiAgICAgICAgZmlyc3RIaXN0b3J5SW5kZXg6IHRoaXMuX3NoYXJlZFN0YXRlLmVtaXRIaXN0b3J5LmZyb250KCk/LmluZGV4LFxuICAgICAgICBzZXNzaW9uSWRcbiAgICAgIH07XG4gICAgICB0aGlzLl9sb2dnZXIuZGVidWcoYCR7dGhpcy5fbGFiZWx9OiByZXN0b3Jpbmcgc2Vzc2lvbmAsIEpTT04uc3RyaW5naWZ5KHJlcXVlc3QpKTtcbiAgICAgIHF1ZXJ5LnJlc3RvcmVTdGlja3lDb25uZWN0aW9uID0gZW5jb2RlVVJJQ29tcG9uZW50KEpTT04uc3RyaW5naWZ5KHJlcXVlc3QpKTtcbiAgICB9XG4gICAgdGhpcy5fc29ja2V0ID0gaW9DbGllbnQodXJsLCB7XG4gICAgICAuLi5vcHRpb25zPy5jb25uZWN0aW9uLFxuICAgICAgcmVjb25uZWN0aW9uOiBmYWxzZSxcbiAgICAgIGF1dG9Db25uZWN0OiBmYWxzZSxcbiAgICAgIHF1ZXJ5XG4gICAgfSk7XG4gICAgc29ja2V0V2lsZGNhcmQoaW9DbGllbnQuTWFuYWdlcikodGhpcy5fc29ja2V0KTtcbiAgICB0aGlzLl9zb2NrZXQub24oJyonLCBwYWNrZXQgPT4ge1xuICAgICAgaWYgKHBhY2tldC50eXBlID09PSBFVkVOVCB8fCBwYWNrZXQudHlwZSA9PT0gQklOQVJZX0VWRU5UKSB7XG4gICAgICAgIGxldCBwYXlsb2FkID0gcGFja2V0LmRhdGFbMV07XG4gICAgICAgIGlmICh0aGlzLl9vcHRpb25zPy51c2VOYXRpdmVTb2NrZXRJb1NlcnZlcikge1xuICAgICAgICAgIHRoaXMuX2NsaWVudC5lbWl0KHBhY2tldC5kYXRhWzBdLCAuLi5wYWNrZXQuZGF0YS5zbGljZSgxKSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmICgnaW5kZXgnIGluIHBheWxvYWQpIHtcbiAgICAgICAgICB0aGlzLl9sb2dnZXIudHJhY2UoKCkgPT4gYCR7dGhpcy5fbGFiZWx9OiByZWNlaXZlZCBwYWNrZXQgYCArIEpTT04uc3RyaW5naWZ5KHtpbmRleDogcGF5bG9hZC5pbmRleH0pKTtcbiAgICAgICAgICB0aGlzLl9zaGFyZWRTdGF0ZS5sYXN0UmVjZWl2ZWRJbmRleCA9IE1hdGgubWF4KHRoaXMuX3NoYXJlZFN0YXRlLmxhc3RSZWNlaXZlZEluZGV4ID8/IC0xLCBwYXlsb2FkLmluZGV4KTtcbiAgICAgICAgICB0aGlzLl9jbGllbnQuZW1pdChwYWNrZXQuZGF0YVswXSwgLi4ucGF5bG9hZC5kYXRhKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEVtaXRzIGEgZGF0YSBldmVudC4gQWxsIGV2ZW50cyBhcmUgYnVmZmVyZWQgaWYgbm8gY29ubmVjdGlvblxuICAgKiBAcGFyYW0gZXZlbnQgVGhlIGV2ZW50IHRoYXQgd2UncmUgZW1pdHRpbmdcbiAgICogQHBhcmFtIGFyZ3MgT3B0aW9uYWwgYXJndW1lbnRzIHRvIHNlbmQgd2l0aCB0aGUgZXZlbnRcbiAgICovXG4gIHNlbmQoZXZlbnQ6IHN0cmluZywgLi4uYXJnczogYW55W10pIHtcbiAgICBpZiAodGhpcy5fb3B0aW9ucz8udXNlTmF0aXZlU29ja2V0SW9TZXJ2ZXIpIHtcbiAgICAgIHRoaXMuX3NvY2tldC5lbWl0KGV2ZW50LCAuLi5hcmdzKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IHBhY2tldDogRW1pdEhpc3RvcnlQYWNrZXQgPSB7XG4gICAgICBpbmRleDogKyt0aGlzLl9zaGFyZWRTdGF0ZS5sYXN0U2VudEluZGV4LFxuICAgICAgZXZlbnQsXG4gICAgICBkYXRhOiBhcmdzLFxuICAgICAgdGltZTogbmV3IERhdGUoKVxuICAgIH07XG4gICAgdGhpcy5fc2hhcmVkU3RhdGUuZW1pdEhpc3RvcnkucHVzaChwYWNrZXQpO1xuICAgIHRoaXMuX3NvY2tldC5lbWl0KGV2ZW50LCB7XG4gICAgICBpbmRleDogcGFja2V0LmluZGV4LFxuICAgICAgZGF0YTogcGFja2V0LmRhdGFcbiAgICB9IHNhdGlzZmllcyBFbWl0UGFja2V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAaW5oZXJpdGRvY1xuICAgKi9cbiAgYXN5bmMgc3RhcnQoc3RvcFByb21pc2U6IGxyYXAuSGFuZGxlUHJvbWlzZTx2b2lkPikge1xuICAgIHRyeSB7XG4gICAgICBsZXQgY29ubmVjdFByb21pc2UgPSB0aGlzLl9jb25uZWN0KHN0b3BQcm9taXNlKTtcbiAgICAgIGxldCByZXN0b3JlUHJvbWlzZSA9IHRoaXMuX3Jlc3RvcmVDb25uZWN0aW9uSWZOZWVkZWQoc3RvcFByb21pc2UpO1xuICAgICAgbGV0IFtfLCByZXN0b3JlZF0gPSBhd2FpdCBQcm9taXNlLmFsbChbY29ubmVjdFByb21pc2UsIHJlc3RvcmVQcm9taXNlXSk7XG4gICAgICBpZiAocmVzdG9yZWQpIHtcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmluZm8oYCR7dGhpcy5fbGFiZWx9OiByZXN0b3JlZCBjb25uZWN0aW9uIHNlc3Npb25gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuX2xvZ2dlci53YXJuKGAke3RoaXMuX2xhYmVsfTogZmFpbGVkIHRvIGNvbm5lY3RgLCBlcnIpO1xuICAgICAgaWYgKHRoaXMuX3NoYXJlZFN0YXRlLnN0YXJ0Q291bnQgPT09IDEgfHwgZXJyIGluc3RhbmNlb2YgUmVzdG9yZVJlamVjdEVycm9yKSB7XG4gICAgICAgIHRoaXMuX2NsaWVudC5kaXNjb25uZWN0KGVycik7XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgbHJhcC5Db250cm9sU2lnbmFsKHthY3Rpb246ICdmYWlsb3ZlcicsIHNldmVyaXR5OiAnaW5mbyd9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9jb25uZWN0KHN0b3BQcm9taXNlOiBscmFwLkhhbmRsZVByb21pc2U8dm9pZD4pIHtcbiAgICB0aGlzLl9zb2NrZXQuY29ubmVjdCgpO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBzdG9wUHJvbWlzZS50aGVuKCgpID0+IHJlamVjdChuZXcgRXJyb3IoJ1N0b3BwZWQgZHVyaW5nIGNvbm5lY3Rpb24nKSkpO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignY29ubmVjdCcsICgpID0+IHtcbiAgICAgICAgLy8gRW1pdHRpbmcgY29ubmVjdCBpbW1lZGlhdGVseSB0byBndWFyYW50ZWUgbm8gZGF0YSBldmVudHMgd2lsbCBiZSByZWNlaXZlZCB1bnRpbCBjb25uZWN0IGV2ZW50IGVtaXR0ZWRcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKGAke3RoaXMuX2xhYmVsfTogaW50ZXJuYWwgc29ja2V0IGNvbm5lY3RlZGApO1xuICAgICAgICB0aGlzLl9pbnRlcm5hbEV2ZW50cy5lbWl0KCdjb25uZWN0Jyk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignZGlzY29ubmVjdCcsIChyZWFzb246IENsaWVudFNvY2tldERpc2Nvbm5lY3RSZWFzb24pID0+IHtcbiAgICAgICAgdGhpcy5fZGlzY29ubmVjdFJlYXNvbiA9IHJlYXNvbjtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRGlzY29ubmVjdGVkIHdoZW4gY29ubmVjdGluZyBkdWUgdG8gJHtyZWFzb259YCkpO1xuICAgICAgfSk7XG4gICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdlcnJvcicsIGVyciA9PiByZWplY3QoZXJyKSk7XG4gICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdjb25uZWN0X2Vycm9yJywgZXJyID0+IHJlamVjdChlcnIpKTtcbiAgICAgIHRoaXMuX3NldFNvY2tldFN0YWdlTGlzdGVuZXIoJ2Nvbm5lY3RfdGltZW91dCcsIGVyciA9PiByZWplY3QoZXJyKSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIF9yZXN0b3JlQ29ubmVjdGlvbklmTmVlZGVkKHN0b3BQcm9taXNlOiBscmFwLkhhbmRsZVByb21pc2U8dm9pZD4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5fc2hhcmVkU3RhdGUuc3RhcnRDb3VudCA9PT0gMSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBsZXQgc2VuZFNpbmNlSW5kZXggPSBhd2FpdCBuZXcgUHJvbWlzZTxudW1iZXI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHN0b3BQcm9taXNlLnRoZW4oKCkgPT4gcmVqZWN0KG5ldyBFcnJvcignU3RvcHBlZCBkdXJpbmcgcmVzdG9yaW5nIGNvbm5lY3Rpb24nKSkpO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcihSRVNUT1JFX0NPTk5FQ1RJT05fRVZFTlQsIChldmVudDogUmVzdG9yZUNvbm5lY3Rpb25SZXNwb25zZSkgPT4ge1xuICAgICAgICBldmVudC5yZXN0b3JlZCA/XG4gICAgICAgICAgcmVzb2x2ZShldmVudC5zZW5kU2luY2VJbmRleCkgOlxuICAgICAgICAgIHJlamVjdChuZXcgUmVzdG9yZVJlamVjdEVycm9yKCdDYW5ub3QgcmVzdG9yZSBjb25uZWN0aW9uIHNlc3Npb24nKSk7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuX3NldFNvY2tldFN0YWdlTGlzdGVuZXIoJ2Rpc2Nvbm5lY3QnLCAocmVhc29uOiBzdHJpbmcpID0+IHtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRGlzY29ubmVjdGVkIHdoZW4gcmVzdG9yaW5nIGNvbm5lY3Rpb24gZHVlIHRvICR7cmVhc29ufWApKTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignZXJyb3InLCBlcnIgPT4gcmVqZWN0KGVycikpO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignY29ubmVjdF9lcnJvcicsIGVyciA9PiByZWplY3QoZXJyKSk7XG4gICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdjb25uZWN0X3RpbWVvdXQnLCBlcnIgPT4gcmVqZWN0KGVycikpO1xuICAgIH0pO1xuICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhgJHt0aGlzLl9sYWJlbH06IHNlbmRpbmcgaGlzdG9yeSBzaW5jZSAke3NlbmRTaW5jZUluZGV4fSBwYWNrZXQgaW5kZXhgKTtcbiAgICBzZW5kSGlzdG9yeSh0aGlzLl9zb2NrZXQsIHRoaXMuX3NoYXJlZFN0YXRlLmVtaXRIaXN0b3J5LCBzZW5kU2luY2VJbmRleCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogQGluaGVyaXRkb2NcbiAgICovXG4gIGFzeW5jIHJ1bihzdG9wUHJvbWlzZTogbHJhcC5IYW5kbGVQcm9taXNlPHZvaWQ+KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaGlzdG9yeUJ1ZmZlclR0bEluTXMgPSAxMDAwICogKHRoaXMuX29wdGlvbnM/LmVtaXRIaXN0b3J5VHRsSW5TZWNvbmRzID8/IDEwKTtcbiAgICBsZXQgY2xlYXJPbGRIaXN0b3J5SW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCgoKSA9PiB0aGlzLnJlbW92ZUV4cGlyZWRFbWl0SGlzdG9yeSgpLCBoaXN0b3J5QnVmZmVyVHRsSW5Ncyk7XG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLl9kaXNjb25uZWN0UmVhc29uKSB7XG4gICAgICAgIGlmICghdGhpcy5fdHJ5RGlzY29ubmVjdENsaWVudEdyYWNlZnVsbHkodGhpcy5fZGlzY29ubmVjdFJlYXNvbikpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYERpc2Nvbm5lY3RlZCBkdWUgdG8gJHt0aGlzLl9kaXNjb25uZWN0UmVhc29ufWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMuX3JlbW92ZVByZXZTdGFnZUxpc3RlbmVycygpO1xuICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKFtzdG9wUHJvbWlzZSwgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdkaXNjb25uZWN0JywgKHJlYXNvbjogQ2xpZW50U29ja2V0RGlzY29ubmVjdFJlYXNvbikgPT4ge1xuICAgICAgICAgIGlmICghdGhpcy5fdHJ5RGlzY29ubmVjdENsaWVudEdyYWNlZnVsbHkocmVhc29uKSkge1xuICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRGlzY29ubmVjdGVkIGR1ZSB0byAke3JlYXNvbn1gKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignZXJyb3InLCByZWplY3QpO1xuICAgICAgfSldKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuX2xvZ2dlci53YXJuKGAke3RoaXMuX2xhYmVsfTogbG9zdCBjb25uZWN0aW9uYCwgZXJyKTtcbiAgICAgIHRoaXMuX2ludGVybmFsRXZlbnRzLmVtaXQoJ2ZhaWwnLCBlcnIpO1xuICAgICAgdGhyb3cgbmV3IGxyYXAuQ29udHJvbFNpZ25hbCh7YWN0aW9uOiAnZmFpbG92ZXInLCBzZXZlcml0eTogJ2luZm8nfSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuX3JlbW92ZVByZXZTdGFnZUxpc3RlbmVycygpO1xuICAgICAgY2xlYXJJbnRlcnZhbChjbGVhck9sZEhpc3RvcnlJbnRlcnZhbCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgZXhwaXJlZCBlbWl0IGhpc3RvcnlcbiAgICovXG4gIHJlbW92ZUV4cGlyZWRFbWl0SGlzdG9yeSgpIHtcbiAgICBjb25zdCBoaXN0b3J5QnVmZmVyVHRsSW5NcyA9IDEwMDAgKiAodGhpcy5fb3B0aW9ucz8uZW1pdEhpc3RvcnlUdGxJblNlY29uZHMgPz8gMTApO1xuICAgIHdoaWxlICh0aGlzLl9zaGFyZWRTdGF0ZS5lbWl0SGlzdG9yeS5sZW5ndGgpIHtcbiAgICAgIGlmIChEYXRlLm5vdygpIC0gdGhpcy5fc2hhcmVkU3RhdGUuZW1pdEhpc3RvcnkuZnJvbnQoKS50aW1lLmdldFRpbWUoKSA+IGhpc3RvcnlCdWZmZXJUdGxJbk1zKSB7XG4gICAgICAgIHRoaXMuX3NoYXJlZFN0YXRlLmVtaXRIaXN0b3J5LnNoaWZ0KCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF90cnlEaXNjb25uZWN0Q2xpZW50R3JhY2VmdWxseShyZWFzb246IENsaWVudFNvY2tldERpc2Nvbm5lY3RSZWFzb24pOiBib29sZWFuIHtcbiAgICBpZiAocmVhc29uID09PSAnaW8gY2xpZW50IGRpc2Nvbm5lY3QnIHx8IHJlYXNvbiA9PT0gJ2lvIHNlcnZlciBkaXNjb25uZWN0Jykge1xuICAgICAgdGhpcy5fbG9nZ2VyLmluZm8oYCR7dGhpcy5fbGFiZWx9OiBkaXNjb25uZWN0aW5nIGNsaWVudCBkdWUgdG8gJHtyZWFzb259YCk7XG4gICAgICB0aGlzLl9jbGllbnQuZGlzY29ubmVjdCgpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBpbmhlcml0ZG9jXG4gICAqL1xuICBhc3luYyBzdG9wKCkge1xuICAgIHRoaXMuX3NvY2tldC5kaXNjb25uZWN0KCk7XG4gIH1cblxuICBwcml2YXRlIF9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyPFQgZXh0ZW5kcyAoLi4uYXJnczogYW55W10pID0+IHZvaWQ+KGV2ZW50OiBzdHJpbmcsIGxpc3RlbmVyOiBUKTogVCB7XG4gICAgdGhpcy5fcHJldlN0YWdlTGlzdGVuZXJzW2V2ZW50XSB8fD0gbmV3IFNldCgpO1xuICAgIHRoaXMuX3ByZXZTdGFnZUxpc3RlbmVyc1tldmVudF0uYWRkKGxpc3RlbmVyKTtcbiAgICB0aGlzLl9zb2NrZXQub24oZXZlbnQsIGxpc3RlbmVyKTtcbiAgICByZXR1cm4gbGlzdGVuZXI7XG4gIH1cblxuICBwcml2YXRlIF9yZW1vdmVQcmV2U3RhZ2VMaXN0ZW5lcnMoKSB7XG4gICAgZm9yIChsZXQgW2V2ZW50LCBsaXN0ZW5lcnNdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuX3ByZXZTdGFnZUxpc3RlbmVycykpIHtcbiAgICAgIGZvciAobGV0IGxpc3RlbmVyIG9mIGxpc3RlbmVycykge1xuICAgICAgICB0aGlzLl9zb2NrZXQub2ZmKGV2ZW50LCBsaXN0ZW5lcik7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbm5hbWVzcGFjZSBTdGlja3lTb2NrZXRDb25uZWN0aW9uIHtcblxuICAvKiogT3B0aW9ucyAqL1xuICBleHBvcnQgdHlwZSBPcHRpb25zID0gU29ja2V0T3B0aW9ucyAmIHtcbiAgICAvKiogTG9nZ2luZyBsYWJlbCB0byBpZGVudGlmeSB0aGlzIGluc3RhbmNlLiBEZWZhdWx0cyB0byBgZGVmYXVsdGAgKi9cbiAgICBsYWJlbD86IHN0cmluZztcbiAgICAvKiogTmF0aXZlIHNvY2tldCBJTyBvcHRpb25zICovXG4gICAgY29ubmVjdGlvbj86IFBpY2s8XG4gICAgICBTb2NrZXRJT0NsaWVudC5Db25uZWN0T3B0cyxcbiAgICAgICdwYXRoJyB8ICd0aW1lb3V0JyB8ICdxdWVyeSdcbiAgICA+ICYge1xuICAgICAgLyoqXG4gICAgICAgKiBIZWFkZXJzIHRoYXQgd2lsbCBiZSBwYXNzZWQgZm9yIGVhY2ggcmVxdWVzdCB0byB0aGUgc2VydmVyICh2aWEgeGhyLXBvbGxpbmcgYW5kIHZpYSB3ZWJzb2NrZXRzKS4gVGhlc2UgdmFsdWVzXG4gICAgICAgKiB0aGVuIGNhbiBiZSB1c2VkIGR1cmluZyBoYW5kc2hha2Ugb3IgZm9yIHNwZWNpYWwgcHJveGllc1xuICAgICAgICovXG4gICAgICBleHRyYUhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQWRqdXN0cyBjb21wYXRpYmlsaXR5IHRvIHdvcmsgaW4gbW9kZSB3aGVuIGEgbmF0aXZlIHNvY2tldC5pbyBzZXJ2ZXIgaXMgdXNlZC4gSW4gdGhpcyBtb2RlIHRoZSBzb2NrZXQgd2lsbCBub3RcbiAgICAgKiB0cnkgdG8gcmVzdG9yZSBjb25uZWN0aW9uIGFuZCB3aWxsIHNlbmQgcGFja2V0cyBhcyBpcy4gSW50ZW5kZWQgZm9yIHRlc3RzIHdoZXJlIG5hdGl2ZSBzb2NrZXQuaW8gc2VydmVyIGlzIHVzZWRcbiAgICAgKi9cbiAgICB1c2VOYXRpdmVTb2NrZXRJb1NlcnZlcj86IGJvb2xlYW47XG4gIH07XG5cbiAgLyoqIFNoYXJlZCBzdGF0ZSAqL1xuICBleHBvcnQgdHlwZSBTaGFyZWRTdGF0ZSA9IHtcbiAgICAvKiogQ291bnQgb2YgdGltZXMgYSBjb25uZWN0aW9uIGlzIHN0YXJ0ZWQgKi9cbiAgICBzdGFydENvdW50OiBudW1iZXI7XG4gICAgLyoqIEVtaXQgKi9cbiAgICBlbWl0SGlzdG9yeTogUXVldWU8RW1pdEhpc3RvcnlQYWNrZXQ+O1xuICAgIC8qKiBMYXN0IHNlbnQgaW5kZXguIFN0YXJ0cyBmcm9tIGAwYC4gSWYgbm8gcGFja2V0cyB3ZXJlIHNlbnQgeWV0LCBkZWZhdWx0cyB0byBgLTFgICovXG4gICAgbGFzdFNlbnRJbmRleDogbnVtYmVyO1xuICAgIC8qKiBMYXN0IHJlY2VpdmVkIHBhY2tldCBpbmRleC4gU3RhcnRzIGZyb20gYDBgLiBJZiBubyBwYWNrZXRzIHdlcmUgcmVjZWl2ZWQsIGRlZmF1bHRzIHRvIGAtMWAgKi9cbiAgICBsYXN0UmVjZWl2ZWRJbmRleDogbnVtYmVyO1xuICB9O1xuXG4gIC8qKiBTaGFyZWQgZXZlbnRzIGZvciBpbnRlcm1lZGlhdGUgc3RhdGUgKi9cbiAgZXhwb3J0IHR5cGUgU2hhcmVkRXZlbnRzID0ge1xuICAgIC8qKiBDb25uZWN0ZWQgZXZlbnQgKi9cbiAgICBjb25uZWN0OiAoKSA9PiB2b2lkO1xuICAgIC8qKiBMb3N0IGNvbm5lY3Rpb24gZXZlbnQgKi9cbiAgICBmYWlsOiAoZXJyOiBFcnJvcikgPT4gdm9pZDtcbiAgfTtcblxuICAvKiogQ29ubmVjdGlvbiBldmVudHMgKi9cbiAgZXhwb3J0IGNvbnN0IENPTk5FQ1RJT05fRVZFTlRTID0gWydjb25uZWN0JywgJ2Rpc2Nvbm5lY3QnXTtcbiAgLyoqIFN0aWNreSBjb25uZWN0aW9uIHByb3RvY29sIGV2ZW50cyAqL1xuICBleHBvcnQgY29uc3QgUFJPVE9DT0xfRVZFTlRTID0gW1JFU1RPUkVfQ09OTkVDVElPTl9FVkVOVF07XG4gIC8qKiBJbnRlcm5hbCBldmVudHMgKi9cbiAgZXhwb3J0IGNvbnN0IElOVEVSTkFMX0VWRU5UUyA9IFtcbiAgICAnZXJyb3InLCAnY29ubmVjdF9lcnJvcicsICdjb25uZWN0X3RpbWVvdXQnLCAncmVjb25uZWN0JywgJ3JlY29ubmVjdF9hdHRlbXB0JywgJ3JlY29ubmVjdGluZycsICdyZWNvbm5lY3RfZXJyb3InLFxuICAgICdyZWNvbm5lY3RfZmFpbGVkJywgJ3BpbmcnLCAncG9uZycsIC4uLlBST1RPQ09MX0VWRU5UU1xuICBdO1xufVxuXG5leHBvcnQgZGVmYXVsdCBTdGlja3lTb2NrZXRDb25uZWN0aW9uO1xuXG4vKipcbiAqIEVycm9yLCBtZWFuaW5nIHRoYXQgdGhlIHNlcnZlciByZWplY3RlZCB0aGUgcmVzdG9yZSByZXF1ZXN0LiBFLmcuIHNlcnZlciBtYXkgaGF2ZSBhbHJlYWR5XG4gKiByZW1vdmVkIG9sZCBlbWl0IGhpc3RvcnksIHJlcXVpcmVkIGJ5IHRoZSBjbGllbnQsIHNvIHRoZSByZXN0b3JpbmcgY2Fubm90IGJlIGRvbmVcbiAqL1xuY2xhc3MgUmVzdG9yZVJlamVjdEVycm9yIGV4dGVuZHMgRXJyb3Ige31cbiJdLCJuYW1lcyI6WyJscmFwIiwiaW9DbGllbnQiLCJzb2NrZXRXaWxkY2FyZCIsIkJJTkFSWV9FVkVOVCIsIkVWRU5UIiwiUkVTVE9SRV9DT05ORUNUSU9OX0VWRU5UIiwiZ2V0Q2xpZW50U29ja2V0SW9UcmFuc3BvcnROYW1lIiwic2VuZEhpc3RvcnkiLCJMb2dnZXJNYW5hZ2VyIiwiU3RpY2t5U29ja2V0Q29ubmVjdGlvbiIsIlJvb3RQcm9jZXNzIiwic29ja2V0IiwiX3NvY2tldCIsInRyYW5zcG9ydE5hbWUiLCJmaXJzdEhpc3RvcnlJbmRleCIsIl9zaGFyZWRTdGF0ZSIsImVtaXRIaXN0b3J5IiwiZnJvbnQiLCJpbmRleCIsImluamVjdCIsImNsaWVudCIsImludGVybmFsRXZlbnRzIiwiX2NsaWVudCIsIl9pbnRlcm5hbEV2ZW50cyIsImluaXRpYWxpemUiLCJ1cmwiLCJzZXNzaW9uSWQiLCJzaGFyZWRTdGF0ZSIsIm9wdGlvbnMiLCJfb3B0aW9ucyIsIl9sYWJlbCIsImxhYmVsIiwic3RhcnRDb3VudCIsInF1ZXJ5IiwiY29ubmVjdGlvbiIsInN0aWNreVNvY2tldENvbm5lY3Rpb25JZCIsInJlcXVlc3QiLCJsYXN0UmVjZWl2ZWRJbmRleCIsImxhc3RTZW50SW5kZXgiLCJfbG9nZ2VyIiwiZGVidWciLCJKU09OIiwic3RyaW5naWZ5IiwicmVzdG9yZVN0aWNreUNvbm5lY3Rpb24iLCJlbmNvZGVVUklDb21wb25lbnQiLCJyZWNvbm5lY3Rpb24iLCJhdXRvQ29ubmVjdCIsIk1hbmFnZXIiLCJvbiIsInBhY2tldCIsInR5cGUiLCJwYXlsb2FkIiwiZGF0YSIsInVzZU5hdGl2ZVNvY2tldElvU2VydmVyIiwiZW1pdCIsInNsaWNlIiwidHJhY2UiLCJNYXRoIiwibWF4Iiwic2VuZCIsImV2ZW50IiwiYXJncyIsInRpbWUiLCJEYXRlIiwicHVzaCIsInN0YXJ0Iiwic3RvcFByb21pc2UiLCJjb25uZWN0UHJvbWlzZSIsIl9jb25uZWN0IiwicmVzdG9yZVByb21pc2UiLCJfcmVzdG9yZUNvbm5lY3Rpb25JZk5lZWRlZCIsIl8iLCJyZXN0b3JlZCIsIlByb21pc2UiLCJhbGwiLCJpbmZvIiwiZXJyIiwid2FybiIsIlJlc3RvcmVSZWplY3RFcnJvciIsImRpc2Nvbm5lY3QiLCJDb250cm9sU2lnbmFsIiwiYWN0aW9uIiwic2V2ZXJpdHkiLCJjb25uZWN0IiwicmVzb2x2ZSIsInJlamVjdCIsInRoZW4iLCJFcnJvciIsIl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyIiwicmVhc29uIiwiX2Rpc2Nvbm5lY3RSZWFzb24iLCJzZW5kU2luY2VJbmRleCIsInJ1biIsImhpc3RvcnlCdWZmZXJUdGxJbk1zIiwiZW1pdEhpc3RvcnlUdGxJblNlY29uZHMiLCJjbGVhck9sZEhpc3RvcnlJbnRlcnZhbCIsInNldEludGVydmFsIiwicmVtb3ZlRXhwaXJlZEVtaXRIaXN0b3J5IiwiX3RyeURpc2Nvbm5lY3RDbGllbnRHcmFjZWZ1bGx5IiwiX3JlbW92ZVByZXZTdGFnZUxpc3RlbmVycyIsInJhY2UiLCJjbGVhckludGVydmFsIiwibGVuZ3RoIiwibm93IiwiZ2V0VGltZSIsInNoaWZ0Iiwic3RvcCIsImxpc3RlbmVyIiwiX3ByZXZTdGFnZUxpc3RlbmVycyIsIlNldCIsImFkZCIsImxpc3RlbmVycyIsIk9iamVjdCIsImVudHJpZXMiLCJvZmYiLCJnZXRMb2dnZXIiLCJuYW1lIiwiQ09OTkVDVElPTl9FVkVOVFMiLCJQUk9UT0NPTF9FVkVOVFMiLCJJTlRFUk5BTF9FVkVOVFMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7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