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)

316 lines (315 loc) 39.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return MemoryHistoryStorage; } }); const _historyStorage = /*#__PURE__*/ _interop_require_default(require("./historyStorage")); const _index = /*#__PURE__*/ _interop_require_default(require("./historyDatabase/index")); const _avltree = require("../binary-search-tree/avltree"); const _logger = /*#__PURE__*/ _interop_require_default(require("../logger")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } let MemoryHistoryStorage = class MemoryHistoryStorage extends _historyStorage.default { /** * Initializes the storage and loads required data from a persistent storage * @param {string} accountId account id * @param {string} [application] application. Default is MetaApi */ async initialize(accountId, application = "MetaApi") { await super.initialize(accountId, application); let { deals, historyOrders } = await this._historyDatabase.loadHistory(accountId, application); for (let deal of deals){ await this._addDeal(deal, true); } for (let historyOrder of historyOrders){ await this._addHistoryOrder(historyOrder, true); } } /** * Resets the storage. Intended for use in tests * @returns {Promise} promise when the history is removed */ async clear() { this._reset(); await this._historyDatabase.clear(this._accountId, this._application); } /** * Returns the time of the last history order record stored in the history storage * @param {Number} [instanceNumber] index of an account instance connected * @returns {Date} the time of the last history order record stored in the history storage */ lastHistoryOrderTime(instanceNumber) { return this._maxHistoryOrderTime; } /** * Returns the time of the last history deal record stored in the history storage * @param {Number} [instanceNumber] index of an account instance connected * @returns {Date} the time of the last history deal record stored in the history storage */ lastDealTime(instanceNumber) { return this._maxDealTime; } /** * Invoked when a new MetaTrader history order is added * @param {String} instanceIndex index of an account instance connected * @param {MetatraderOrder} historyOrder new MetaTrader history order */ async onHistoryOrderAdded(instanceIndex, historyOrder) { await this._addHistoryOrder(historyOrder); } /** * Invoked when a new MetaTrader history deal is added * @param {String} instanceIndex index of an account instance connected * @param {MetatraderDeal} deal new MetaTrader history deal */ async onDealAdded(instanceIndex, deal) { await this._addDeal(deal); } /** * Returns all deals * @returns {Array<MetatraderDeal>} all deals */ get deals() { return this.getDealsByTimeRange(new Date(0), new Date(8640000000000000)); } /** * Returns deals by ticket id * @param {string} id ticket id * @returns {Array<MetatraderDeal>} deals found */ getDealsByTicket(id) { let deals = Object.values(this._dealsByTicket[id] || {}); deals.sort(this._dealsComparator); return deals; } /** * Returns deals by position id * @param {string} positionId position id * @returns {Array<MetatraderDeal>} deals found */ getDealsByPosition(positionId) { let deals = Object.values(this._dealsByPosition[positionId] || {}); deals.sort(this._dealsComparator); return deals; } /** * Returns deals by time range * @param startTime start time, inclusive * @param endTime end time, inclusive * @returns {Array<MetatraderDeal>} deals found */ getDealsByTimeRange(startTime, endTime) { let deals = this._dealsByTime.betweenBounds({ $gte: { time: startTime, id: 0, entryType: "" }, $lte: { time: endTime, id: Number.MAX_VALUE, entryType: "" } }); return deals; } /** * Returns all history orders * @returns {Array<MetatraderOrder>} all history orders */ get historyOrders() { return this.getHistoryOrdersByTimeRange(new Date(0), new Date(8640000000000000)); } /** * Returns history orders by ticket id * @param {string} id ticket id * @returns {Array<MetatraderOrder>} history orders found */ getHistoryOrdersByTicket(id) { let historyOrders = Object.values(this._historyOrdersByTicket[id] || {}); historyOrders.sort(this._historyOrdersComparator); return historyOrders; } /** * Returns history orders by position id * @param {string} positionId position id * @returns {Array<MetatraderOrder>} history orders found */ getHistoryOrdersByPosition(positionId) { let historyOrders = Object.values(this._historyOrdersByPosition[positionId] || {}); historyOrders.sort(this._historyOrdersComparator); return historyOrders; } /** * Returns history orders by time range * @param startTime start time, inclusive * @param endTime end time, inclusive * @returns {Array<MetatraderOrder>} hisotry orders found */ getHistoryOrdersByTimeRange(startTime, endTime) { let historyOrders = this._historyOrdersByTime.betweenBounds({ $gte: { doneTime: startTime, id: 0, type: "", state: "" }, $lte: { doneTime: endTime, id: Number.MAX_VALUE, type: "", state: "" } }); return historyOrders; } /** * Invoked when a synchronization of history deals on a MetaTrader account have finished to indicate progress of an * initial terminal state synchronization * @param {String} instanceIndex index of an account instance connected * @param {String} synchronizationId synchronization request id * @return {Promise} promise which resolves when the asynchronous event is processed */ async onDealsSynchronized(instanceIndex, synchronizationId) { await this._flushDatabase(); await super.onDealsSynchronized(instanceIndex, synchronizationId); } _reset() { this._orderSynchronizationFinished = {}; this._dealSynchronizationFinished = {}; this._dealsByTicket = {}; this._dealsByPosition = {}; this._historyOrdersByTicket = {}; this._historyOrdersByPosition = {}; // eslint-disable-next-line complexity this._historyOrdersComparator = (o1, o2)=>{ let timeDiff = (o1.doneTime || new Date(0)).getTime() - (o2.doneTime || new Date(0)).getTime(); if (timeDiff === 0) { let idDiff = o1.id - o2.id; if (idDiff === 0) { if (o1.type > o2.type) { return 1; } else if (o1.type < o2.type) { return -1; } else { if (o1.state > o2.state) { return 1; } else if (o1.state < o2.state) { return -1; } else { return 0; } } } else { return idDiff; } } else { return timeDiff; } }; this._historyOrdersByTime = new _avltree.AVLTree({ compareKeys: this._historyOrdersComparator }); this._dealsComparator = (d1, d2)=>{ let timeDiff = (d1.time || new Date(0)).getTime() - (d2.time || new Date(0)).getTime(); if (timeDiff === 0) { let idDiff = d1.id - d2.id; if (idDiff === 0) { if (d1.entryType > d2.entryType) { return 1; } else if (d1.entryType < d2.entryType) { return -1; } else { return 0; } } else { return idDiff; } } else { return timeDiff; } }; this._dealsByTime = new _avltree.AVLTree({ compareKeys: this._dealsComparator }); this._maxHistoryOrderTime = new Date(0); this._maxDealTime = new Date(0); this._newHistoryOrders = []; this._newDeals = []; clearTimeout(this._flushTimeout); delete this._flushTimeout; } // eslint-disable-next-line complexity async _addDeal(deal, existing) { let key = this._getDealKey(deal); this._dealsByTicket[deal.id] = this._dealsByTicket[deal.id] || {}; let newDeal = !existing && !this._dealsByTicket[deal.id][key]; this._dealsByTicket[deal.id][key] = deal; if (deal.positionId) { this._dealsByPosition[deal.positionId] = this._dealsByPosition[deal.positionId] || {}; this._dealsByPosition[deal.positionId][key] = deal; } this._dealsByTime.delete(deal); this._dealsByTime.insert(deal, deal); if (deal.time && (!this._maxDealTime || this._maxDealTime.getTime() < deal.time.getTime())) { this._maxDealTime = deal.time; } if (newDeal) { this._newDeals.push(deal); clearTimeout(this._flushTimeout); this._flushTimeout = setTimeout(this._flushDatabase.bind(this), 5000); } } _getDealKey(deal) { return (deal.time || new Date(0)).toISOString() + ":" + deal.id + ":" + deal.entryType; } // eslint-disable-next-line complexity async _addHistoryOrder(historyOrder, existing) { let key = this._getHistoryOrderKey(historyOrder); this._historyOrdersByTicket[historyOrder.id] = this._historyOrdersByTicket[historyOrder.id] || {}; let newHistoryOrder = !existing && !this._historyOrdersByTicket[historyOrder.id][key]; this._historyOrdersByTicket[historyOrder.id][key] = historyOrder; if (historyOrder.positionId) { this._historyOrdersByPosition[historyOrder.positionId] = this._historyOrdersByPosition[historyOrder.positionId] || {}; this._historyOrdersByPosition[historyOrder.positionId][key] = historyOrder; } this._historyOrdersByTime.delete(historyOrder); this._historyOrdersByTime.insert(historyOrder, historyOrder); if (historyOrder.doneTime && (!this._maxHistoryOrderTime || this._maxHistoryOrderTime.getTime() < historyOrder.doneTime.getTime())) { this._maxHistoryOrderTime = historyOrder.doneTime; } if (newHistoryOrder) { this._newHistoryOrders.push(historyOrder); clearTimeout(this._flushTimeout); this._flushTimeout = setTimeout(this._flushDatabase.bind(this), 5000); } } _getHistoryOrderKey(historyOrder) { return (historyOrder.doneTime || new Date(0)).toISOString() + ":" + historyOrder.id + ":" + historyOrder.type + ":" + historyOrder.state; } async _flushDatabase() { if (this._flushPromise) { await this._flushPromise; } if (this._flushRunning) { return; } this._flushRunning = true; let resolve; this._flushPromise = new Promise((res)=>resolve = res); try { await this._historyDatabase.flush(this._accountId, this._application, this._newHistoryOrders, this._newDeals); this._newHistoryOrders = []; this._newDeals = []; this._logger.debug(`${this._accountId}: flushed history db`); } catch (err) { this._logger.warn(`${this._accountId}: error flushing history db`, err); this._flushTimeout = setTimeout(this._flushDatabase.bind(this), 15000); } finally{ resolve(); this._flushRunning = false; } } /** * Constructs the in-memory history store instance */ constructor(){ super(); this._historyDatabase = _index.default.getInstance(); this._reset(); this._logger = _logger.default.getLogger("MemoryHistoryStorage"); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBIaXN0b3J5U3RvcmFnZSBmcm9tICcuL2hpc3RvcnlTdG9yYWdlJztcbmltcG9ydCBIaXN0b3J5RGF0YWJhc2UgZnJvbSAnLi9oaXN0b3J5RGF0YWJhc2UvaW5kZXgnO1xuaW1wb3J0IHsgQVZMVHJlZSB9IGZyb20gJy4uL2JpbmFyeS1zZWFyY2gtdHJlZS9hdmx0cmVlJ1xuaW1wb3J0IExvZ2dlck1hbmFnZXIgZnJvbSAnLi4vbG9nZ2VyJztcblxuLyoqXG4gKiBIaXN0b3J5IHN0b3JhZ2Ugd2hpY2ggc3RvcmVzIE1ldGFUcmFkZXIgaGlzdG9yeSBpbiBSQU1cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTWVtb3J5SGlzdG9yeVN0b3JhZ2UgZXh0ZW5kcyBIaXN0b3J5U3RvcmFnZSB7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgdGhlIGluLW1lbW9yeSBoaXN0b3J5IHN0b3JlIGluc3RhbmNlXG4gICAqL1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX2hpc3RvcnlEYXRhYmFzZSA9IEhpc3RvcnlEYXRhYmFzZS5nZXRJbnN0YW5jZSgpO1xuICAgIHRoaXMuX3Jlc2V0KCk7XG4gICAgdGhpcy5fbG9nZ2VyID0gTG9nZ2VyTWFuYWdlci5nZXRMb2dnZXIoJ01lbW9yeUhpc3RvcnlTdG9yYWdlJyk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIHN0b3JhZ2UgYW5kIGxvYWRzIHJlcXVpcmVkIGRhdGEgZnJvbSBhIHBlcnNpc3RlbnQgc3RvcmFnZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcHBsaWNhdGlvbl0gYXBwbGljYXRpb24uIERlZmF1bHQgaXMgTWV0YUFwaVxuICAgKi9cbiAgYXN5bmMgaW5pdGlhbGl6ZShhY2NvdW50SWQsIGFwcGxpY2F0aW9uID0gJ01ldGFBcGknKSB7XG4gICAgYXdhaXQgc3VwZXIuaW5pdGlhbGl6ZShhY2NvdW50SWQsIGFwcGxpY2F0aW9uKTtcbiAgICBsZXQge2RlYWxzLCBoaXN0b3J5T3JkZXJzfSA9IGF3YWl0IHRoaXMuX2hpc3RvcnlEYXRhYmFzZS5sb2FkSGlzdG9yeShhY2NvdW50SWQsIGFwcGxpY2F0aW9uKTtcbiAgICBmb3IgKGxldCBkZWFsIG9mIGRlYWxzKSB7XG4gICAgICBhd2FpdCB0aGlzLl9hZGREZWFsKGRlYWwsIHRydWUpO1xuICAgIH1cbiAgICBmb3IgKGxldCBoaXN0b3J5T3JkZXIgb2YgaGlzdG9yeU9yZGVycykge1xuICAgICAgYXdhaXQgdGhpcy5fYWRkSGlzdG9yeU9yZGVyKGhpc3RvcnlPcmRlciwgdHJ1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyB0aGUgc3RvcmFnZS4gSW50ZW5kZWQgZm9yIHVzZSBpbiB0ZXN0c1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSB3aGVuIHRoZSBoaXN0b3J5IGlzIHJlbW92ZWRcbiAgICovXG4gIGFzeW5jIGNsZWFyKCkge1xuICAgIHRoaXMuX3Jlc2V0KCk7XG4gICAgYXdhaXQgdGhpcy5faGlzdG9yeURhdGFiYXNlLmNsZWFyKHRoaXMuX2FjY291bnRJZCwgdGhpcy5fYXBwbGljYXRpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHRpbWUgb2YgdGhlIGxhc3QgaGlzdG9yeSBvcmRlciByZWNvcmQgc3RvcmVkIGluIHRoZSBoaXN0b3J5IHN0b3JhZ2VcbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtpbnN0YW5jZU51bWJlcl0gaW5kZXggb2YgYW4gYWNjb3VudCBpbnN0YW5jZSBjb25uZWN0ZWRcbiAgICogQHJldHVybnMge0RhdGV9IHRoZSB0aW1lIG9mIHRoZSBsYXN0IGhpc3Rvcnkgb3JkZXIgcmVjb3JkIHN0b3JlZCBpbiB0aGUgaGlzdG9yeSBzdG9yYWdlXG4gICAqL1xuICBsYXN0SGlzdG9yeU9yZGVyVGltZShpbnN0YW5jZU51bWJlcikge1xuICAgIHJldHVybiB0aGlzLl9tYXhIaXN0b3J5T3JkZXJUaW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHRpbWUgb2YgdGhlIGxhc3QgaGlzdG9yeSBkZWFsIHJlY29yZCBzdG9yZWQgaW4gdGhlIGhpc3Rvcnkgc3RvcmFnZVxuICAgKiBAcGFyYW0ge051bWJlcn0gW2luc3RhbmNlTnVtYmVyXSBpbmRleCBvZiBhbiBhY2NvdW50IGluc3RhbmNlIGNvbm5lY3RlZFxuICAgKiBAcmV0dXJucyB7RGF0ZX0gdGhlIHRpbWUgb2YgdGhlIGxhc3QgaGlzdG9yeSBkZWFsIHJlY29yZCBzdG9yZWQgaW4gdGhlIGhpc3Rvcnkgc3RvcmFnZVxuICAgKi9cbiAgbGFzdERlYWxUaW1lKGluc3RhbmNlTnVtYmVyKSB7XG4gICAgcmV0dXJuIHRoaXMuX21heERlYWxUaW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIEludm9rZWQgd2hlbiBhIG5ldyBNZXRhVHJhZGVyIGhpc3Rvcnkgb3JkZXIgaXMgYWRkZWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGluc3RhbmNlSW5kZXggaW5kZXggb2YgYW4gYWNjb3VudCBpbnN0YW5jZSBjb25uZWN0ZWRcbiAgICogQHBhcmFtIHtNZXRhdHJhZGVyT3JkZXJ9IGhpc3RvcnlPcmRlciBuZXcgTWV0YVRyYWRlciBoaXN0b3J5IG9yZGVyXG4gICAqL1xuICBhc3luYyBvbkhpc3RvcnlPcmRlckFkZGVkKGluc3RhbmNlSW5kZXgsIGhpc3RvcnlPcmRlcikge1xuICAgIGF3YWl0IHRoaXMuX2FkZEhpc3RvcnlPcmRlcihoaXN0b3J5T3JkZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEludm9rZWQgd2hlbiBhIG5ldyBNZXRhVHJhZGVyIGhpc3RvcnkgZGVhbCBpcyBhZGRlZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5zdGFuY2VJbmRleCBpbmRleCBvZiBhbiBhY2NvdW50IGluc3RhbmNlIGNvbm5lY3RlZFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJEZWFsfSBkZWFsIG5ldyBNZXRhVHJhZGVyIGhpc3RvcnkgZGVhbFxuICAgKi9cbiAgYXN5bmMgb25EZWFsQWRkZWQoaW5zdGFuY2VJbmRleCwgZGVhbCkge1xuICAgIGF3YWl0IHRoaXMuX2FkZERlYWwoZGVhbCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhbGwgZGVhbHNcbiAgICogQHJldHVybnMge0FycmF5PE1ldGF0cmFkZXJEZWFsPn0gYWxsIGRlYWxzXG4gICAqL1xuICBnZXQgZGVhbHMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0RGVhbHNCeVRpbWVSYW5nZShuZXcgRGF0ZSgwKSwgbmV3IERhdGUoODY0MDAwMDAwMDAwMDAwMCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgZGVhbHMgYnkgdGlja2V0IGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCB0aWNrZXQgaWRcbiAgICogQHJldHVybnMge0FycmF5PE1ldGF0cmFkZXJEZWFsPn0gZGVhbHMgZm91bmRcbiAgICovXG4gIGdldERlYWxzQnlUaWNrZXQoaWQpIHtcbiAgICBsZXQgZGVhbHMgPSBPYmplY3QudmFsdWVzKHRoaXMuX2RlYWxzQnlUaWNrZXRbaWRdIHx8IHt9KTtcbiAgICBkZWFscy5zb3J0KHRoaXMuX2RlYWxzQ29tcGFyYXRvcik7XG4gICAgcmV0dXJuIGRlYWxzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgZGVhbHMgYnkgcG9zaXRpb24gaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBvc2l0aW9uSWQgcG9zaXRpb24gaWRcbiAgICogQHJldHVybnMge0FycmF5PE1ldGF0cmFkZXJEZWFsPn0gZGVhbHMgZm91bmRcbiAgICovXG4gIGdldERlYWxzQnlQb3NpdGlvbihwb3NpdGlvbklkKSB7XG4gICAgbGV0IGRlYWxzID0gT2JqZWN0LnZhbHVlcyh0aGlzLl9kZWFsc0J5UG9zaXRpb25bcG9zaXRpb25JZF0gfHwge30pO1xuICAgIGRlYWxzLnNvcnQodGhpcy5fZGVhbHNDb21wYXJhdG9yKTtcbiAgICByZXR1cm4gZGVhbHM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBkZWFscyBieSB0aW1lIHJhbmdlXG4gICAqIEBwYXJhbSBzdGFydFRpbWUgc3RhcnQgdGltZSwgaW5jbHVzaXZlXG4gICAqIEBwYXJhbSBlbmRUaW1lIGVuZCB0aW1lLCBpbmNsdXNpdmVcbiAgICogQHJldHVybnMge0FycmF5PE1ldGF0cmFkZXJEZWFsPn0gZGVhbHMgZm91bmRcbiAgICovXG4gIGdldERlYWxzQnlUaW1lUmFuZ2Uoc3RhcnRUaW1lLCBlbmRUaW1lKSB7XG4gICAgbGV0IGRlYWxzID0gdGhpcy5fZGVhbHNCeVRpbWUuYmV0d2VlbkJvdW5kcyh7XG4gICAgICAkZ3RlOiB7dGltZTogc3RhcnRUaW1lLCBpZDogMCwgZW50cnlUeXBlOiAnJ30sXG4gICAgICAkbHRlOiB7dGltZTogZW5kVGltZSwgaWQ6IE51bWJlci5NQVhfVkFMVUUsIGVudHJ5VHlwZTogJyd9XG4gICAgfSk7XG4gICAgcmV0dXJuIGRlYWxzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWxsIGhpc3Rvcnkgb3JkZXJzXG4gICAqIEByZXR1cm5zIHtBcnJheTxNZXRhdHJhZGVyT3JkZXI+fSBhbGwgaGlzdG9yeSBvcmRlcnNcbiAgICovXG4gIGdldCBoaXN0b3J5T3JkZXJzKCkge1xuICAgIHJldHVybiB0aGlzLmdldEhpc3RvcnlPcmRlcnNCeVRpbWVSYW5nZShuZXcgRGF0ZSgwKSwgbmV3IERhdGUoODY0MDAwMDAwMDAwMDAwMCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgaGlzdG9yeSBvcmRlcnMgYnkgdGlja2V0IGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCB0aWNrZXQgaWRcbiAgICogQHJldHVybnMge0FycmF5PE1ldGF0cmFkZXJPcmRlcj59IGhpc3Rvcnkgb3JkZXJzIGZvdW5kXG4gICAqL1xuICBnZXRIaXN0b3J5T3JkZXJzQnlUaWNrZXQoaWQpIHtcbiAgICBsZXQgaGlzdG9yeU9yZGVycyA9IE9iamVjdC52YWx1ZXModGhpcy5faGlzdG9yeU9yZGVyc0J5VGlja2V0W2lkXSB8fCB7fSk7XG4gICAgaGlzdG9yeU9yZGVycy5zb3J0KHRoaXMuX2hpc3RvcnlPcmRlcnNDb21wYXJhdG9yKTtcbiAgICByZXR1cm4gaGlzdG9yeU9yZGVycztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGhpc3Rvcnkgb3JkZXJzIGJ5IHBvc2l0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwb3NpdGlvbklkIHBvc2l0aW9uIGlkXG4gICAqIEByZXR1cm5zIHtBcnJheTxNZXRhdHJhZGVyT3JkZXI+fSBoaXN0b3J5IG9yZGVycyBmb3VuZFxuICAgKi9cbiAgZ2V0SGlzdG9yeU9yZGVyc0J5UG9zaXRpb24ocG9zaXRpb25JZCkge1xuICAgIGxldCBoaXN0b3J5T3JkZXJzID0gT2JqZWN0LnZhbHVlcyh0aGlzLl9oaXN0b3J5T3JkZXJzQnlQb3NpdGlvbltwb3NpdGlvbklkXSB8fCB7fSk7XG4gICAgaGlzdG9yeU9yZGVycy5zb3J0KHRoaXMuX2hpc3RvcnlPcmRlcnNDb21wYXJhdG9yKTtcbiAgICByZXR1cm4gaGlzdG9yeU9yZGVycztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGhpc3Rvcnkgb3JkZXJzIGJ5IHRpbWUgcmFuZ2VcbiAgICogQHBhcmFtIHN0YXJ0VGltZSBzdGFydCB0aW1lLCBpbmNsdXNpdmVcbiAgICogQHBhcmFtIGVuZFRpbWUgZW5kIHRpbWUsIGluY2x1c2l2ZVxuICAgKiBAcmV0dXJucyB7QXJyYXk8TWV0YXRyYWRlck9yZGVyPn0gaGlzb3RyeSBvcmRlcnMgZm91bmRcbiAgICovXG4gIGdldEhpc3RvcnlPcmRlcnNCeVRpbWVSYW5nZShzdGFydFRpbWUsIGVuZFRpbWUpIHtcbiAgICBsZXQgaGlzdG9yeU9yZGVycyA9IHRoaXMuX2hpc3RvcnlPcmRlcnNCeVRpbWUuYmV0d2VlbkJvdW5kcyh7XG4gICAgICAkZ3RlOiB7ZG9uZVRpbWU6IHN0YXJ0VGltZSwgaWQ6IDAsIHR5cGU6ICcnLCBzdGF0ZTogJyd9LFxuICAgICAgJGx0ZToge2RvbmVUaW1lOiBlbmRUaW1lLCBpZDogTnVtYmVyLk1BWF9WQUxVRSwgdHlwZTogJycsIHN0YXRlOiAnJ31cbiAgICB9KTtcbiAgICByZXR1cm4gaGlzdG9yeU9yZGVycztcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gYSBzeW5jaHJvbml6YXRpb24gb2YgaGlzdG9yeSBkZWFscyBvbiBhIE1ldGFUcmFkZXIgYWNjb3VudCBoYXZlIGZpbmlzaGVkIHRvIGluZGljYXRlIHByb2dyZXNzIG9mIGFuXG4gICAqIGluaXRpYWwgdGVybWluYWwgc3RhdGUgc3luY2hyb25pemF0aW9uXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBpbnN0YW5jZUluZGV4IGluZGV4IG9mIGFuIGFjY291bnQgaW5zdGFuY2UgY29ubmVjdGVkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzeW5jaHJvbml6YXRpb25JZCBzeW5jaHJvbml6YXRpb24gcmVxdWVzdCBpZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHdoaWNoIHJlc29sdmVzIHdoZW4gdGhlIGFzeW5jaHJvbm91cyBldmVudCBpcyBwcm9jZXNzZWRcbiAgICovXG4gIGFzeW5jIG9uRGVhbHNTeW5jaHJvbml6ZWQoaW5zdGFuY2VJbmRleCwgc3luY2hyb25pemF0aW9uSWQpIHtcbiAgICBhd2FpdCB0aGlzLl9mbHVzaERhdGFiYXNlKCk7XG4gICAgYXdhaXQgc3VwZXIub25EZWFsc1N5bmNocm9uaXplZChpbnN0YW5jZUluZGV4LCBzeW5jaHJvbml6YXRpb25JZCk7XG4gIH1cblxuICBfcmVzZXQoKSB7XG4gICAgdGhpcy5fb3JkZXJTeW5jaHJvbml6YXRpb25GaW5pc2hlZCA9IHt9O1xuICAgIHRoaXMuX2RlYWxTeW5jaHJvbml6YXRpb25GaW5pc2hlZCA9IHt9O1xuICAgIHRoaXMuX2RlYWxzQnlUaWNrZXQgPSB7fTtcbiAgICB0aGlzLl9kZWFsc0J5UG9zaXRpb24gPSB7fTtcbiAgICB0aGlzLl9oaXN0b3J5T3JkZXJzQnlUaWNrZXQgPSB7fTtcbiAgICB0aGlzLl9oaXN0b3J5T3JkZXJzQnlQb3NpdGlvbiA9IHt9O1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG4gICAgdGhpcy5faGlzdG9yeU9yZGVyc0NvbXBhcmF0b3IgPSAobzEsIG8yKSA9PiB7XG4gICAgICBsZXQgdGltZURpZmYgPSAobzEuZG9uZVRpbWUgfHwgbmV3IERhdGUoMCkpLmdldFRpbWUoKSAtIChvMi5kb25lVGltZSB8fCBuZXcgRGF0ZSgwKSkuZ2V0VGltZSgpO1xuICAgICAgaWYgKHRpbWVEaWZmID09PSAwKSB7XG4gICAgICAgIGxldCBpZERpZmYgPSBvMS5pZCAtIG8yLmlkO1xuICAgICAgICBpZiAoaWREaWZmID09PSAwKSB7XG4gICAgICAgICAgaWYgKG8xLnR5cGUgPiBvMi50eXBlKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICB9IGVsc2UgaWYgKG8xLnR5cGUgPCBvMi50eXBlKSB7XG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChvMS5zdGF0ZSA+IG8yLnN0YXRlKSB7XG4gICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvMS5zdGF0ZSA8IG8yLnN0YXRlKSB7XG4gICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gaWREaWZmO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGltZURpZmY7XG4gICAgICB9XG4gICAgfTtcbiAgICB0aGlzLl9oaXN0b3J5T3JkZXJzQnlUaW1lID0gbmV3IEFWTFRyZWUoe2NvbXBhcmVLZXlzOiB0aGlzLl9oaXN0b3J5T3JkZXJzQ29tcGFyYXRvcn0pO1xuICAgIHRoaXMuX2RlYWxzQ29tcGFyYXRvciA9IChkMSwgZDIpID0+IHtcbiAgICAgIGxldCB0aW1lRGlmZiA9IChkMS50aW1lIHx8IG5ldyBEYXRlKDApKS5nZXRUaW1lKCkgLSAoZDIudGltZSB8fCBuZXcgRGF0ZSgwKSkuZ2V0VGltZSgpO1xuICAgICAgaWYgKHRpbWVEaWZmID09PSAwKSB7XG4gICAgICAgIGxldCBpZERpZmYgPSBkMS5pZCAtIGQyLmlkO1xuICAgICAgICBpZiAoaWREaWZmID09PSAwKSB7XG4gICAgICAgICAgaWYgKGQxLmVudHJ5VHlwZSA+IGQyLmVudHJ5VHlwZSkge1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgfSBlbHNlIGlmIChkMS5lbnRyeVR5cGUgPCBkMi5lbnRyeVR5cGUpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBpZERpZmY7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0aW1lRGlmZjtcbiAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMuX2RlYWxzQnlUaW1lID0gbmV3IEFWTFRyZWUoe2NvbXBhcmVLZXlzOiB0aGlzLl9kZWFsc0NvbXBhcmF0b3J9KTtcbiAgICB0aGlzLl9tYXhIaXN0b3J5T3JkZXJUaW1lID0gbmV3IERhdGUoMCk7XG4gICAgdGhpcy5fbWF4RGVhbFRpbWUgPSBuZXcgRGF0ZSgwKTtcbiAgICB0aGlzLl9uZXdIaXN0b3J5T3JkZXJzID0gW107XG4gICAgdGhpcy5fbmV3RGVhbHMgPSBbXTtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5fZmx1c2hUaW1lb3V0KTtcbiAgICBkZWxldGUgdGhpcy5fZmx1c2hUaW1lb3V0O1xuICB9XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgYXN5bmMgX2FkZERlYWwoZGVhbCwgZXhpc3RpbmcpIHtcbiAgICBsZXQga2V5ID0gdGhpcy5fZ2V0RGVhbEtleShkZWFsKTtcbiAgICB0aGlzLl9kZWFsc0J5VGlja2V0W2RlYWwuaWRdID0gdGhpcy5fZGVhbHNCeVRpY2tldFtkZWFsLmlkXSB8fCB7fTtcbiAgICBsZXQgbmV3RGVhbCA9ICFleGlzdGluZyAmJiAhdGhpcy5fZGVhbHNCeVRpY2tldFtkZWFsLmlkXVtrZXldO1xuICAgIHRoaXMuX2RlYWxzQnlUaWNrZXRbZGVhbC5pZF1ba2V5XSA9IGRlYWw7XG4gICAgaWYgKGRlYWwucG9zaXRpb25JZCkge1xuICAgICAgdGhpcy5fZGVhbHNCeVBvc2l0aW9uW2RlYWwucG9zaXRpb25JZF0gPSB0aGlzLl9kZWFsc0J5UG9zaXRpb25bZGVhbC5wb3NpdGlvbklkXSB8fCB7fTtcbiAgICAgIHRoaXMuX2RlYWxzQnlQb3NpdGlvbltkZWFsLnBvc2l0aW9uSWRdW2tleV0gPSBkZWFsO1xuICAgIH1cbiAgICB0aGlzLl9kZWFsc0J5VGltZS5kZWxldGUoZGVhbCk7XG4gICAgdGhpcy5fZGVhbHNCeVRpbWUuaW5zZXJ0KGRlYWwsIGRlYWwpO1xuICAgIGlmIChkZWFsLnRpbWUgJiYgKCF0aGlzLl9tYXhEZWFsVGltZSB8fCB0aGlzLl9tYXhEZWFsVGltZS5nZXRUaW1lKCkgPCBkZWFsLnRpbWUuZ2V0VGltZSgpKSkge1xuICAgICAgdGhpcy5fbWF4RGVhbFRpbWUgPSBkZWFsLnRpbWU7XG4gICAgfVxuICAgIGlmIChuZXdEZWFsKSB7XG4gICAgICB0aGlzLl9uZXdEZWFscy5wdXNoKGRlYWwpO1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuX2ZsdXNoVGltZW91dCk7XG4gICAgICB0aGlzLl9mbHVzaFRpbWVvdXQgPSBzZXRUaW1lb3V0KHRoaXMuX2ZsdXNoRGF0YWJhc2UuYmluZCh0aGlzKSwgNTAwMCk7XG4gICAgfVxuICB9XG5cbiAgX2dldERlYWxLZXkoZGVhbCkge1xuICAgIHJldHVybiAoZGVhbC50aW1lIHx8IG5ldyBEYXRlKDApKS50b0lTT1N0cmluZygpICsgJzonICsgZGVhbC5pZCArICc6JyArIGRlYWwuZW50cnlUeXBlO1xuICB9XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgYXN5bmMgX2FkZEhpc3RvcnlPcmRlcihoaXN0b3J5T3JkZXIsIGV4aXN0aW5nKSB7XG4gICAgbGV0IGtleSA9IHRoaXMuX2dldEhpc3RvcnlPcmRlcktleShoaXN0b3J5T3JkZXIpO1xuICAgIHRoaXMuX2hpc3RvcnlPcmRlcnNCeVRpY2tldFtoaXN0b3J5T3JkZXIuaWRdID0gdGhpcy5faGlzdG9yeU9yZGVyc0J5VGlja2V0W2hpc3RvcnlPcmRlci5pZF0gfHwge307XG4gICAgbGV0IG5ld0hpc3RvcnlPcmRlciA9ICFleGlzdGluZyAmJiAhdGhpcy5faGlzdG9yeU9yZGVyc0J5VGlja2V0W2hpc3RvcnlPcmRlci5pZF1ba2V5XTtcbiAgICB0aGlzLl9oaXN0b3J5T3JkZXJzQnlUaWNrZXRbaGlzdG9yeU9yZGVyLmlkXVtrZXldID0gaGlzdG9yeU9yZGVyO1xuICAgIGlmIChoaXN0b3J5T3JkZXIucG9zaXRpb25JZCkge1xuICAgICAgdGhpcy5faGlzdG9yeU9yZGVyc0J5UG9zaXRpb25baGlzdG9yeU9yZGVyLnBvc2l0aW9uSWRdID0gdGhpcy5faGlzdG9yeU9yZGVyc0J5UG9zaXRpb25baGlzdG9yeU9yZGVyLnBvc2l0aW9uSWRdIHx8XG4gICAgICAgIHt9O1xuICAgICAgdGhpcy5faGlzdG9yeU9yZGVyc0J5UG9zaXRpb25baGlzdG9yeU9yZGVyLnBvc2l0aW9uSWRdW2tleV0gPSBoaXN0b3J5T3JkZXI7XG4gICAgfVxuICAgIHRoaXMuX2hpc3RvcnlPcmRlcnNCeVRpbWUuZGVsZXRlKGhpc3RvcnlPcmRlcik7XG4gICAgdGhpcy5faGlzdG9yeU9yZGVyc0J5VGltZS5pbnNlcnQoaGlzdG9yeU9yZGVyLCBoaXN0b3J5T3JkZXIpO1xuICAgIGlmIChoaXN0b3J5T3JkZXIuZG9uZVRpbWUgJiYgKCF0aGlzLl9tYXhIaXN0b3J5T3JkZXJUaW1lIHx8XG4gICAgICAgIHRoaXMuX21heEhpc3RvcnlPcmRlclRpbWUuZ2V0VGltZSgpIDwgaGlzdG9yeU9yZGVyLmRvbmVUaW1lLmdldFRpbWUoKSkpIHtcbiAgICAgIHRoaXMuX21heEhpc3RvcnlPcmRlclRpbWUgPSBoaXN0b3J5T3JkZXIuZG9uZVRpbWU7XG4gICAgfVxuICAgIGlmIChuZXdIaXN0b3J5T3JkZXIpIHtcbiAgICAgIHRoaXMuX25ld0hpc3RvcnlPcmRlcnMucHVzaChoaXN0b3J5T3JkZXIpO1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuX2ZsdXNoVGltZW91dCk7XG4gICAgICB0aGlzLl9mbHVzaFRpbWVvdXQgPSBzZXRUaW1lb3V0KHRoaXMuX2ZsdXNoRGF0YWJhc2UuYmluZCh0aGlzKSwgNTAwMCk7XG4gICAgfVxuICB9XG5cbiAgX2dldEhpc3RvcnlPcmRlcktleShoaXN0b3J5T3JkZXIpIHtcbiAgICByZXR1cm4gKGhpc3RvcnlPcmRlci5kb25lVGltZSB8fCBuZXcgRGF0ZSgwKSkudG9JU09TdHJpbmcoKSArICc6JyArIGhpc3RvcnlPcmRlci5pZCArICc6JyArXG4gICAgICBoaXN0b3J5T3JkZXIudHlwZSArICc6JyArIGhpc3RvcnlPcmRlci5zdGF0ZTtcbiAgfVxuXG4gIGFzeW5jIF9mbHVzaERhdGFiYXNlKCkge1xuICAgIGlmICh0aGlzLl9mbHVzaFByb21pc2UpIHtcbiAgICAgIGF3YWl0IHRoaXMuX2ZsdXNoUHJvbWlzZTtcbiAgICB9XG4gICAgaWYgKHRoaXMuX2ZsdXNoUnVubmluZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLl9mbHVzaFJ1bm5pbmcgPSB0cnVlO1xuICAgIGxldCByZXNvbHZlO1xuICAgIHRoaXMuX2ZsdXNoUHJvbWlzZSA9IG5ldyBQcm9taXNlKHJlcyA9PiByZXNvbHZlID0gcmVzKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5faGlzdG9yeURhdGFiYXNlLmZsdXNoKHRoaXMuX2FjY291bnRJZCwgdGhpcy5fYXBwbGljYXRpb24sIHRoaXMuX25ld0hpc3RvcnlPcmRlcnMsIHRoaXMuX25ld0RlYWxzKTtcbiAgICAgIHRoaXMuX25ld0hpc3RvcnlPcmRlcnMgPSBbXTtcbiAgICAgIHRoaXMuX25ld0RlYWxzID0gW107XG4gICAgICB0aGlzLl9sb2dnZXIuZGVidWcoYCR7dGhpcy5fYWNjb3VudElkfTogZmx1c2hlZCBoaXN0b3J5IGRiYCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLl9sb2dnZXIud2FybihgJHt0aGlzLl9hY2NvdW50SWR9OiBlcnJvciBmbHVzaGluZyBoaXN0b3J5IGRiYCwgZXJyKTtcbiAgICAgIHRoaXMuX2ZsdXNoVGltZW91dCA9IHNldFRpbWVvdXQodGhpcy5fZmx1c2hEYXRhYmFzZS5iaW5kKHRoaXMpLCAxNTAwMCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHJlc29sdmUoKTtcbiAgICAgIHRoaXMuX2ZsdXNoUnVubmluZyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG59XG4iXSwibmFtZXMiOlsiTWVtb3J5SGlzdG9yeVN0b3JhZ2UiLCJIaXN0b3J5U3RvcmFnZSIsImluaXRpYWxpemUiLCJhY2NvdW50SWQiLCJhcHBsaWNhdGlvbiIsImRlYWxzIiwiaGlzdG9yeU9yZGVycyIsIl9oaXN0b3J5RGF0YWJhc2UiLCJsb2FkSGlzdG9yeSIsImRlYWwiLCJfYWRkRGVhbCIsImhpc3RvcnlPcmRlciIsIl9hZGRIaXN0b3J5T3JkZXIiLCJjbGVhciIsIl9yZXNldCIsIl9hY2NvdW50SWQiLCJfYXBwbGljYXRpb24iLCJsYXN0SGlzdG9yeU9yZGVyVGltZSIsImluc3RhbmNlTnVtYmVyIiwiX21heEhpc3RvcnlPcmRlclRpbWUiLCJsYXN0RGVhbFRpbWUiLCJfbWF4RGVhbFRpbWUiLCJvbkhpc3RvcnlPcmRlckFkZGVkIiwiaW5zdGFuY2VJbmRleCIsIm9uRGVhbEFkZGVkIiwiZ2V0RGVhbHNCeVRpbWVSYW5nZSIsIkRhdGUiLCJnZXREZWFsc0J5VGlja2V0IiwiaWQiLCJPYmplY3QiLCJ2YWx1ZXMiLCJfZGVhbHNCeVRpY2tldCIsInNvcnQiLCJfZGVhbHNDb21wYXJhdG9yIiwiZ2V0RGVhbHNCeVBvc2l0aW9uIiwicG9zaXRpb25JZCIsIl9kZWFsc0J5UG9zaXRpb24iLCJzdGFydFRpbWUiLCJlbmRUaW1lIiwiX2RlYWxzQnlUaW1lIiwiYmV0d2VlbkJvdW5kcyIsIiRndGUiLCJ0aW1lIiwiZW50cnlUeXBlIiwiJGx0ZSIsIk51bWJlciIsIk1BWF9WQUxVRSIsImdldEhpc3RvcnlPcmRlcnNCeVRpbWVSYW5nZSIsImdldEhpc3RvcnlPcmRlcnNCeVRpY2tldCIsIl9oaXN0b3J5T3JkZXJzQnlUaWNrZXQiLCJfaGlzdG9yeU9yZGVyc0NvbXBhcmF0b3IiLCJnZXRIaXN0b3J5T3JkZXJzQnlQb3NpdGlvbiIsIl9oaXN0b3J5T3JkZXJzQnlQb3NpdGlvbiIsIl9oaXN0b3J5T3JkZXJzQnlUaW1lIiwiZG9uZVRpbWUiLCJ0eXBlIiwic3RhdGUiLCJvbkRlYWxzU3luY2hyb25pemVkIiwic3luY2hyb25pemF0aW9uSWQiLCJfZmx1c2hEYXRhYmFzZSIsIl9vcmRlclN5bmNocm9uaXphdGlvbkZpbmlzaGVkIiwiX2RlYWxTeW5jaHJvbml6YXRpb25GaW5pc2hlZCIsIm8xIiwibzIiLCJ0aW1lRGlmZiIsImdldFRpbWUiLCJpZERpZmYiLCJBVkxUcmVlIiwiY29tcGFyZUtleXMiLCJkMSIsImQyIiwiX25ld0hpc3RvcnlPcmRlcnMiLCJfbmV3RGVhbHMiLCJjbGVhclRpbWVvdXQiLCJfZmx1c2hUaW1lb3V0IiwiZXhpc3RpbmciLCJrZXkiLCJfZ2V0RGVhbEtleSIsIm5ld0RlYWwiLCJkZWxldGUiLCJpbnNlcnQiLCJwdXNoIiwic2V0VGltZW91dCIsImJpbmQiLCJ0b0lTT1N0cmluZyIsIl9nZXRIaXN0b3J5T3JkZXJLZXkiLCJuZXdIaXN0b3J5T3JkZXIiLCJfZmx1c2hQcm9taXNlIiwiX2ZsdXNoUnVubmluZyIsInJlc29sdmUiLCJQcm9taXNlIiwicmVzIiwiZmx1c2giLCJfbG9nZ2VyIiwiZGVidWciLCJlcnIiLCJ3YXJuIiwiY29uc3RydWN0b3IiLCJIaXN0b3J5RGF0YWJhc2UiLCJnZXRJbnN0YW5jZSIsIkxvZ2dlck1hbmFnZXIiLCJnZXRMb2dnZXIiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O2VBVXFCQTs7O3VFQVJNOzhEQUNDO3lCQUNKOytEQUNFOzs7Ozs7QUFLWCxJQUFBLEFBQU1BLHVCQUFOLE1BQU1BLDZCQUE2QkMsdUJBQWM7SUFZOUQ7Ozs7R0FJQyxHQUNELE1BQU1DLFdBQVdDLFNBQVMsRUFBRUMsY0FBYyxTQUFTLEVBQUU7UUFDbkQsTUFBTSxLQUFLLENBQUNGLFdBQVdDLFdBQVdDO1FBQ2xDLElBQUksRUFBQ0MsS0FBSyxFQUFFQyxhQUFhLEVBQUMsR0FBRyxNQUFNLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUNDLFdBQVcsQ0FBQ0wsV0FBV0M7UUFDaEYsS0FBSyxJQUFJSyxRQUFRSixNQUFPO1lBQ3RCLE1BQU0sSUFBSSxDQUFDSyxRQUFRLENBQUNELE1BQU07UUFDNUI7UUFDQSxLQUFLLElBQUlFLGdCQUFnQkwsY0FBZTtZQUN0QyxNQUFNLElBQUksQ0FBQ00sZ0JBQWdCLENBQUNELGNBQWM7UUFDNUM7SUFDRjtJQUVBOzs7R0FHQyxHQUNELE1BQU1FLFFBQVE7UUFDWixJQUFJLENBQUNDLE1BQU07UUFDWCxNQUFNLElBQUksQ0FBQ1AsZ0JBQWdCLENBQUNNLEtBQUssQ0FBQyxJQUFJLENBQUNFLFVBQVUsRUFBRSxJQUFJLENBQUNDLFlBQVk7SUFDdEU7SUFFQTs7OztHQUlDLEdBQ0RDLHFCQUFxQkMsY0FBYyxFQUFFO1FBQ25DLE9BQU8sSUFBSSxDQUFDQyxvQkFBb0I7SUFDbEM7SUFFQTs7OztHQUlDLEdBQ0RDLGFBQWFGLGNBQWMsRUFBRTtRQUMzQixPQUFPLElBQUksQ0FBQ0csWUFBWTtJQUMxQjtJQUVBOzs7O0dBSUMsR0FDRCxNQUFNQyxvQkFBb0JDLGFBQWEsRUFBRVosWUFBWSxFQUFFO1FBQ3JELE1BQU0sSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ0Q7SUFDOUI7SUFFQTs7OztHQUlDLEdBQ0QsTUFBTWEsWUFBWUQsYUFBYSxFQUFFZCxJQUFJLEVBQUU7UUFDckMsTUFBTSxJQUFJLENBQUNDLFFBQVEsQ0FBQ0Q7SUFDdEI7SUFFQTs7O0dBR0MsR0FDRCxJQUFJSixRQUFRO1FBQ1YsT0FBTyxJQUFJLENBQUNvQixtQkFBbUIsQ0FBQyxJQUFJQyxLQUFLLElBQUksSUFBSUEsS0FBSztJQUN4RDtJQUVBOzs7O0dBSUMsR0FDREMsaUJBQWlCQyxFQUFFLEVBQUU7UUFDbkIsSUFBSXZCLFFBQVF3QixPQUFPQyxNQUFNLENBQUMsSUFBSSxDQUFDQyxjQUFjLENBQUNILEdBQUcsSUFBSSxDQUFDO1FBQ3REdkIsTUFBTTJCLElBQUksQ0FBQyxJQUFJLENBQUNDLGdCQUFnQjtRQUNoQyxPQUFPNUI7SUFDVDtJQUVBOzs7O0dBSUMsR0FDRDZCLG1CQUFtQkMsVUFBVSxFQUFFO1FBQzdCLElBQUk5QixRQUFRd0IsT0FBT0MsTUFBTSxDQUFDLElBQUksQ0FBQ00sZ0JBQWdCLENBQUNELFdBQVcsSUFBSSxDQUFDO1FBQ2hFOUIsTUFBTTJCLElBQUksQ0FBQyxJQUFJLENBQUNDLGdCQUFnQjtRQUNoQyxPQUFPNUI7SUFDVDtJQUVBOzs7OztHQUtDLEdBQ0RvQixvQkFBb0JZLFNBQVMsRUFBRUMsT0FBTyxFQUFFO1FBQ3RDLElBQUlqQyxRQUFRLElBQUksQ0FBQ2tDLFlBQVksQ0FBQ0MsYUFBYSxDQUFDO1lBQzFDQyxNQUFNO2dCQUFDQyxNQUFNTDtnQkFBV1QsSUFBSTtnQkFBR2UsV0FBVztZQUFFO1lBQzVDQyxNQUFNO2dCQUFDRixNQUFNSjtnQkFBU1YsSUFBSWlCLE9BQU9DLFNBQVM7Z0JBQUVILFdBQVc7WUFBRTtRQUMzRDtRQUNBLE9BQU90QztJQUNUO0lBRUE7OztHQUdDLEdBQ0QsSUFBSUMsZ0JBQWdCO1FBQ2xCLE9BQU8sSUFBSSxDQUFDeUMsMkJBQTJCLENBQUMsSUFBSXJCLEtBQUssSUFBSSxJQUFJQSxLQUFLO0lBQ2hFO0lBRUE7Ozs7R0FJQyxHQUNEc0IseUJBQXlCcEIsRUFBRSxFQUFFO1FBQzNCLElBQUl0QixnQkFBZ0J1QixPQUFPQyxNQUFNLENBQUMsSUFBSSxDQUFDbUIsc0JBQXNCLENBQUNyQixHQUFHLElBQUksQ0FBQztRQUN0RXRCLGNBQWMwQixJQUFJLENBQUMsSUFBSSxDQUFDa0Isd0JBQXdCO1FBQ2hELE9BQU81QztJQUNUO0lBRUE7Ozs7R0FJQyxHQUNENkMsMkJBQTJCaEIsVUFBVSxFQUFFO1FBQ3JDLElBQUk3QixnQkFBZ0J1QixPQUFPQyxNQUFNLENBQUMsSUFBSSxDQUFDc0Isd0JBQXdCLENBQUNqQixXQUFXLElBQUksQ0FBQztRQUNoRjdCLGNBQWMwQixJQUFJLENBQUMsSUFBSSxDQUFDa0Isd0JBQXdCO1FBQ2hELE9BQU81QztJQUNUO0lBRUE7Ozs7O0dBS0MsR0FDRHlDLDRCQUE0QlYsU0FBUyxFQUFFQyxPQUFPLEVBQUU7UUFDOUMsSUFBSWhDLGdCQUFnQixJQUFJLENBQUMrQyxvQkFBb0IsQ0FBQ2IsYUFBYSxDQUFDO1lBQzFEQyxNQUFNO2dCQUFDYSxVQUFVakI7Z0JBQVdULElBQUk7Z0JBQUcyQixNQUFNO2dCQUFJQyxPQUFPO1lBQUU7WUFDdERaLE1BQU07Z0JBQUNVLFVBQVVoQjtnQkFBU1YsSUFBSWlCLE9BQU9DLFNBQVM7Z0JBQUVTLE1BQU07Z0JBQUlDLE9BQU87WUFBRTtRQUNyRTtRQUNBLE9BQU9sRDtJQUNUO0lBRUE7Ozs7OztHQU1DLEdBQ0QsTUFBTW1ELG9CQUFvQmxDLGFBQWEsRUFBRW1DLGlCQUFpQixFQUFFO1FBQzFELE1BQU0sSUFBSSxDQUFDQyxjQUFjO1FBQ3pCLE1BQU0sS0FBSyxDQUFDRixvQkFBb0JsQyxlQUFlbUM7SUFDakQ7SUFFQTVDLFNBQVM7UUFDUCxJQUFJLENBQUM4Qyw2QkFBNkIsR0FBRyxDQUFDO1FBQ3RDLElBQUksQ0FBQ0MsNEJBQTRCLEdBQUcsQ0FBQztRQUNyQyxJQUFJLENBQUM5QixjQUFjLEdBQUcsQ0FBQztRQUN2QixJQUFJLENBQUNLLGdCQUFnQixHQUFHLENBQUM7UUFDekIsSUFBSSxDQUFDYSxzQkFBc0IsR0FBRyxDQUFDO1FBQy9CLElBQUksQ0FBQ0csd0JBQXdCLEdBQUcsQ0FBQztRQUNqQyxzQ0FBc0M7UUFDdEMsSUFBSSxDQUFDRix3QkFBd0IsR0FBRyxDQUFDWSxJQUFJQztZQUNuQyxJQUFJQyxXQUFXLEFBQUNGLENBQUFBLEdBQUdSLFFBQVEsSUFBSSxJQUFJNUIsS0FBSyxFQUFDLEVBQUd1QyxPQUFPLEtBQUssQUFBQ0YsQ0FBQUEsR0FBR1QsUUFBUSxJQUFJLElBQUk1QixLQUFLLEVBQUMsRUFBR3VDLE9BQU87WUFDNUYsSUFBSUQsYUFBYSxHQUFHO2dCQUNsQixJQUFJRSxTQUFTSixHQUFHbEMsRUFBRSxHQUFHbUMsR0FBR25DLEVBQUU7Z0JBQzFCLElBQUlzQyxXQUFXLEdBQUc7b0JBQ2hCLElBQUlKLEdBQUdQLElBQUksR0FBR1EsR0FBR1IsSUFBSSxFQUFFO3dCQUNyQixPQUFPO29CQUNULE9BQU8sSUFBSU8sR0FBR1AsSUFBSSxHQUFHUSxHQUFHUixJQUFJLEVBQUU7d0JBQzVCLE9BQU8sQ0FBQztvQkFDVixPQUFPO3dCQUNMLElBQUlPLEdBQUdOLEtBQUssR0FBR08sR0FBR1AsS0FBSyxFQUFFOzRCQUN2QixPQUFPO3dCQUNULE9BQU8sSUFBSU0sR0FBR04sS0FBSyxHQUFHTyxHQUFHUCxLQUFLLEVBQUU7NEJBQzlCLE9BQU8sQ0FBQzt3QkFDVixPQUFPOzRCQUNMLE9BQU87d0JBQ1Q7b0JBQ0Y7Z0JBQ0YsT0FBTztvQkFDTCxPQUFPVTtnQkFDVDtZQUNGLE9BQU87Z0JBQ0wsT0FBT0Y7WUFDVDtRQUNGO1FBQ0EsSUFBSSxDQUFDWCxvQkFBb0IsR0FBRyxJQUFJYyxnQkFBTyxDQUFDO1lBQUNDLGFBQWEsSUFBSSxDQUFDbEIsd0JBQXdCO1FBQUE7UUFDbkYsSUFBSSxDQUFDakIsZ0JBQWdCLEdBQUcsQ0FBQ29DLElBQUlDO1lBQzNCLElBQUlOLFdBQVcsQUFBQ0ssQ0FBQUEsR0FBRzNCLElBQUksSUFBSSxJQUFJaEIsS0FBSyxFQUFDLEVBQUd1QyxPQUFPLEtBQUssQUFBQ0ssQ0FBQUEsR0FBRzVCLElBQUksSUFBSSxJQUFJaEIsS0FBSyxFQUFDLEVBQUd1QyxPQUFPO1lBQ3BGLElBQUlELGFBQWEsR0FBRztnQkFDbEIsSUFBSUUsU0FBU0csR0FBR3pDLEVBQUUsR0FBRzBDLEdBQUcxQyxFQUFFO2dCQUMxQixJQUFJc0MsV0FBVyxHQUFHO29CQUNoQixJQUFJRyxHQUFHMUIsU0FBUyxHQUFHMkIsR0FBRzNCLFNBQVMsRUFBRTt3QkFDL0IsT0FBTztvQkFDVCxPQUFPLElBQUkwQixHQUFHMUIsU0FBUyxHQUFHMkIsR0FBRzNCLFNBQVMsRUFBRTt3QkFDdEMsT0FBTyxDQUFDO29CQUNWLE9BQU87d0JBQ0wsT0FBTztvQkFDVDtnQkFDRixPQUFPO29CQUNMLE9BQU91QjtnQkFDVDtZQUNGLE9BQU87Z0JBQ0wsT0FBT0Y7WUFDVDtRQUNGO1FBQ0EsSUFBSSxDQUFDekIsWUFBWSxHQUFHLElBQUk0QixnQkFBTyxDQUFDO1lBQUNDLGFBQWEsSUFBSSxDQUFDbkMsZ0JBQWdCO1FBQUE7UUFDbkUsSUFBSSxDQUFDZCxvQkFBb0IsR0FBRyxJQUFJTyxLQUFLO1FBQ3JDLElBQUksQ0FBQ0wsWUFBWSxHQUFHLElBQUlLLEtBQUs7UUFDN0IsSUFBSSxDQUFDNkMsaUJBQWlCLEdBQUcsRUFBRTtRQUMzQixJQUFJLENBQUNDLFNBQVMsR0FBRyxFQUFFO1FBQ25CQyxhQUFhLElBQUksQ0FBQ0MsYUFBYTtRQUMvQixPQUFPLElBQUksQ0FBQ0EsYUFBYTtJQUMzQjtJQUVBLHNDQUFzQztJQUN0QyxNQUFNaEUsU0FBU0QsSUFBSSxFQUFFa0UsUUFBUSxFQUFFO1FBQzdCLElBQUlDLE1BQU0sSUFBSSxDQUFDQyxXQUFXLENBQUNwRTtRQUMzQixJQUFJLENBQUNzQixjQUFjLENBQUN0QixLQUFLbUIsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDRyxjQUFjLENBQUN0QixLQUFLbUIsRUFBRSxDQUFDLElBQUksQ0FBQztRQUNoRSxJQUFJa0QsVUFBVSxDQUFDSCxZQUFZLENBQUMsSUFBSSxDQUFDNUMsY0FBYyxDQUFDdEIsS0FBS21CLEVBQUUsQ0FBQyxDQUFDZ0QsSUFBSTtRQUM3RCxJQUFJLENBQUM3QyxjQUFjLENBQUN0QixLQUFLbUIsRUFBRSxDQUFDLENBQUNnRCxJQUFJLEdBQUduRTtRQUNwQyxJQUFJQSxLQUFLMEIsVUFBVSxFQUFFO1lBQ25CLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUMzQixLQUFLMEIsVUFBVSxDQUFDLEdBQUcsSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQzNCLEtBQUswQixVQUFVLENBQUMsSUFBSSxDQUFDO1lBQ3BGLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUMzQixLQUFLMEIsVUFBVSxDQUFDLENBQUN5QyxJQUFJLEdBQUduRTtRQUNoRDtRQUNBLElBQUksQ0FBQzhCLFlBQVksQ0FBQ3dDLE1BQU0sQ0FBQ3RFO1FBQ3pCLElBQUksQ0FBQzhCLFlBQVksQ0FBQ3lDLE1BQU0sQ0FBQ3ZFLE1BQU1BO1FBQy9CLElBQUlBLEtBQUtpQyxJQUFJLElBQUssQ0FBQSxDQUFDLElBQUksQ0FBQ3JCLFlBQVksSUFBSSxJQUFJLENBQUNBLFlBQVksQ0FBQzRDLE9BQU8sS0FBS3hELEtBQUtpQyxJQUFJLENBQUN1QixPQUFPLEVBQUMsR0FBSTtZQUMxRixJQUFJLENBQUM1QyxZQUFZLEdBQUdaLEtBQUtpQyxJQUFJO1FBQy9CO1FBQ0EsSUFBSW9DLFNBQVM7WUFDWCxJQUFJLENBQUNOLFNBQVMsQ0FBQ1MsSUFBSSxDQUFDeEU7WUFDcEJnRSxhQUFhLElBQUksQ0FBQ0MsYUFBYTtZQUMvQixJQUFJLENBQUNBLGFBQWEsR0FBR1EsV0FBVyxJQUFJLENBQUN2QixjQUFjLENBQUN3QixJQUFJLENBQUMsSUFBSSxHQUFHO1FBQ2xFO0lBQ0Y7SUFFQU4sWUFBWXBFLElBQUksRUFBRTtRQUNoQixPQUFPLEFBQUNBLENBQUFBLEtBQUtpQyxJQUFJLElBQUksSUFBSWhCLEtBQUssRUFBQyxFQUFHMEQsV0FBVyxLQUFLLE1BQU0zRSxLQUFLbUIsRUFBRSxHQUFHLE1BQU1uQixLQUFLa0MsU0FBUztJQUN4RjtJQUVBLHNDQUFzQztJQUN0QyxNQUFNL0IsaUJBQWlCRCxZQUFZLEVBQUVnRSxRQUFRLEVBQUU7UUFDN0MsSUFBSUMsTUFBTSxJQUFJLENBQUNTLG1CQUFtQixDQUFDMUU7UUFDbkMsSUFBSSxDQUFDc0Msc0JBQXNCLENBQUN0QyxhQUFhaUIsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDcUIsc0JBQXNCLENBQUN0QyxhQUFhaUIsRUFBRSxDQUFDLElBQUksQ0FBQztRQUNoRyxJQUFJMEQsa0JBQWtCLENBQUNYLFlBQVksQ0FBQyxJQUFJLENBQUMxQixzQkFBc0IsQ0FBQ3RDLGFBQWFpQixFQUFFLENBQUMsQ0FBQ2dELElBQUk7UUFDckYsSUFBSSxDQUFDM0Isc0JBQXNCLENBQUN0QyxhQUFhaUIsRUFBRSxDQUFDLENBQUNnRCxJQUFJLEdBQUdqRTtRQUNwRCxJQUFJQSxhQUFhd0IsVUFBVSxFQUFFO1lBQzNCLElBQUksQ0FBQ2lCLHdCQUF3QixDQUFDekMsYUFBYXdCLFVBQVUsQ0FBQyxHQUFHLElBQUksQ0FBQ2lCLHdCQUF3QixDQUFDekMsYUFBYXdCLFVBQVUsQ0FBQyxJQUM3RyxDQUFDO1lBQ0gsSUFBSSxDQUFDaUIsd0JBQXdCLENBQUN6QyxhQUFhd0IsVUFBVSxDQUFDLENBQUN5QyxJQUFJLEdBQUdqRTtRQUNoRTtRQUNBLElBQUksQ0FBQzBDLG9CQUFvQixDQUFDMEIsTUFBTSxDQUFDcEU7UUFDakMsSUFBSSxDQUFDMEMsb0JBQW9CLENBQUMyQixNQUFNLENBQUNyRSxjQUFjQTtRQUMvQyxJQUFJQSxhQUFhMkMsUUFBUSxJQUFLLENBQUEsQ0FBQyxJQUFJLENBQUNuQyxvQkFBb0IsSUFDcEQsSUFBSSxDQUFDQSxvQkFBb0IsQ0FBQzhDLE9BQU8sS0FBS3RELGFBQWEyQyxRQUFRLENBQUNXLE9BQU8sRUFBQyxHQUFJO1lBQzFFLElBQUksQ0FBQzlDLG9CQUFvQixHQUFHUixhQUFhMkMsUUFBUTtRQUNuRDtRQUNBLElBQUlnQyxpQkFBaUI7WUFDbkIsSUFBSSxDQUFDZixpQkFBaUIsQ0FBQ1UsSUFBSSxDQUFDdEU7WUFDNUI4RCxhQUFhLElBQUksQ0FBQ0MsYUFBYTtZQUMvQixJQUFJLENBQUNBLGFBQWEsR0FBR1EsV0FBVyxJQUFJLENBQUN2QixjQUFjLENBQUN3QixJQUFJLENBQUMsSUFBSSxHQUFHO1FBQ2xFO0lBQ0Y7SUFFQUUsb0JBQW9CMUUsWUFBWSxFQUFFO1FBQ2hDLE9BQU8sQUFBQ0EsQ0FBQUEsYUFBYTJDLFFBQVEsSUFBSSxJQUFJNUIsS0FBSyxFQUFDLEVBQUcwRCxXQUFXLEtBQUssTUFBTXpFLGFBQWFpQixFQUFFLEdBQUcsTUFDcEZqQixhQUFhNEMsSUFBSSxHQUFHLE1BQU01QyxhQUFhNkMsS0FBSztJQUNoRDtJQUVBLE1BQU1HLGlCQUFpQjtRQUNyQixJQUFJLElBQUksQ0FBQzRCLGFBQWEsRUFBRTtZQUN0QixNQUFNLElBQUksQ0FBQ0EsYUFBYTtRQUMxQjtRQUNBLElBQUksSUFBSSxDQUFDQyxhQUFhLEVBQUU7WUFDdEI7UUFDRjtRQUNBLElBQUksQ0FBQ0EsYUFBYSxHQUFHO1FBQ3JCLElBQUlDO1FBQ0osSUFBSSxDQUFDRixhQUFhLEdBQUcsSUFBSUcsUUFBUUMsQ0FBQUEsTUFBT0YsVUFBVUU7UUFDbEQsSUFBSTtZQUNGLE1BQU0sSUFBSSxDQUFDcEYsZ0JBQWdCLENBQUNxRixLQUFLLENBQUMsSUFBSSxDQUFDN0UsVUFBVSxFQUFFLElBQUksQ0FBQ0MsWUFBWSxFQUFFLElBQUksQ0FBQ3VELGlCQUFpQixFQUFFLElBQUksQ0FBQ0MsU0FBUztZQUM1RyxJQUFJLENBQUNELGlCQUFpQixHQUFHLEVBQUU7WUFDM0IsSUFBSSxDQUFDQyxTQUFTLEdBQUcsRUFBRTtZQUNuQixJQUFJLENBQUNxQixPQUFPLENBQUNDLEtBQUssQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDL0UsVUFBVSxDQUFDLG9CQUFvQixDQUFDO1FBQzdELEVBQUUsT0FBT2dGLEtBQUs7WUFDWixJQUFJLENBQUNGLE9BQU8sQ0FBQ0csSUFBSSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUNqRixVQUFVLENBQUMsMkJBQTJCLENBQUMsRUFBRWdGO1lBQ25FLElBQUksQ0FBQ3JCLGFBQWEsR0FBR1EsV0FBVyxJQUFJLENBQUN2QixjQUFjLENBQUN3QixJQUFJLENBQUMsSUFBSSxHQUFHO1FBQ2xFLFNBQVU7WUFDUk07WUFDQSxJQUFJLENBQUNELGFBQWEsR0FBRztRQUN2QjtJQUNGO0lBdFRBOztHQUVDLEdBQ0RTLGFBQWM7UUFDWixLQUFLO1FBQ0wsSUFBSSxDQUFDMUYsZ0JBQWdCLEdBQUcyRixjQUFlLENBQUNDLFdBQVc7UUFDbkQsSUFBSSxDQUFDckYsTUFBTTtRQUNYLElBQUksQ0FBQytFLE9BQU8sR0FBR08sZUFBYSxDQUFDQyxTQUFTLENBQUM7SUFDekM7QUFnVEYifQ==