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)
252 lines (251 loc) • 34.2 kB
JavaScript
'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);
});
};
}
import LoggerManager from '../logger';
import MetaApiConnectionInstance from './metaApiConnectionInstance';
let RpcMetaApiConnectionInstance = class RpcMetaApiConnectionInstance extends MetaApiConnectionInstance {
/**
* Opens the connection. Can only be called the first time, next calls will be ignored.
* @return {Promise} promise resolving when the connection is opened
*/ connect() {
var _this = this;
return _async_to_generator(function*() {
if (!_this._opened) {
_this._opened = true;
_this._metaApiConnection.connect(_this.instanceId);
}
})();
}
/**
* Closes the connection. The instance of the class should no longer be used after this method is invoked.
*/ close() {
var _this = this;
return _async_to_generator(function*() {
if (!_this._closed) {
_this._metaApiConnection.close(_this.instanceId);
_this._closed = true;
}
})();
}
/**
* Returns account information
* @param {GetAccountInformationOptions} [options] additional request options
* @returns {Promise<MetatraderAccountInformation>} promise resolving with account information
*/ getAccountInformation(options) {
this._checkIsConnectionActive();
return this._websocketClient.getAccountInformation(this._metaApiConnection.account.id, options);
}
/**
* Returns positions
* @param {GetPositionsOptions} [options] additional request options
* @returns {Promise<Array<MetatraderPosition>} promise resolving with array of open positions
*/ getPositions(options) {
this._checkIsConnectionActive();
return this._websocketClient.getPositions(this._metaApiConnection.account.id, options);
}
/**
* Returns specific position
* @param {String} positionId position id
* @param {GetPositionOptions} [options] additional request options
* @return {Promise<MetatraderPosition>} promise resolving with MetaTrader position found
*/ getPosition(positionId, options) {
this._checkIsConnectionActive();
return this._websocketClient.getPosition(this._metaApiConnection.account.id, positionId, options);
}
/**
* Returns open orders
* @param {GetOrdersOptions} [options] additional request options
* @return {Promise<Array<MetatraderOrder>>} promise resolving with open MetaTrader orders
*/ getOrders(options) {
this._checkIsConnectionActive();
return this._websocketClient.getOrders(this._metaApiConnection.account.id, options);
}
/**
* Returns specific open order
* @param {String} orderId order id (ticket number)
* @param {GetOrderOptions} [options] additional request options
* @return {Promise<MetatraderOrder>} promise resolving with metatrader order found
*/ getOrder(orderId, options) {
this._checkIsConnectionActive();
return this._websocketClient.getOrder(this._metaApiConnection.account.id, orderId, options);
}
/**
* Returns the history of completed orders for a specific ticket number
* @param {String} ticket ticket number (order id)
* @returns {Promise<MetatraderHistoryOrders>} promise resolving with request results containing history orders found
*/ getHistoryOrdersByTicket(ticket) {
this._checkIsConnectionActive();
return this._websocketClient.getHistoryOrdersByTicket(this._metaApiConnection.account.id, ticket);
}
/**
* Returns the history of completed orders for a specific position id
* @param {String} positionId position id
* @returns {Promise<MetatraderHistoryOrders>} promise resolving with request results containing history orders found
*/ getHistoryOrdersByPosition(positionId) {
this._checkIsConnectionActive();
return this._websocketClient.getHistoryOrdersByPosition(this._metaApiConnection.account.id, positionId);
}
/**
* Returns the history of completed orders for a specific time range
* @param {Date} startTime start of time range, inclusive
* @param {Date} endTime end of time range, exclusive
* @param {Number} offset pagination offset, default is 0
* @param {Number} limit pagination limit, default is 1000
* @returns {Promise<MetatraderHistoryOrders>} promise resolving with request results containing history orders found
*/ getHistoryOrdersByTimeRange(startTime, endTime, offset = 0, limit = 1000) {
this._checkIsConnectionActive();
return this._websocketClient.getHistoryOrdersByTimeRange(this._metaApiConnection.account.id, startTime, endTime, offset, limit);
}
/**
* Returns history deals with a specific ticket number
* @param {String} ticket ticket number (deal id for MT5 or order id for MT4)
* @returns {Promise<MetatraderDeals>} promise resolving with request results containing deals found
*/ getDealsByTicket(ticket) {
this._checkIsConnectionActive();
return this._websocketClient.getDealsByTicket(this._metaApiConnection.account.id, ticket);
}
/**
* Returns history deals for a specific position id
* @param {String} positionId position id
* @returns {Promise<MetatraderDeals>} promise resolving with request results containing deals found
*/ getDealsByPosition(positionId) {
this._checkIsConnectionActive();
return this._websocketClient.getDealsByPosition(this._metaApiConnection.account.id, positionId);
}
/**
* Returns history deals with for a specific time range
* @param {Date} startTime start of time range, inclusive
* @param {Date} endTime end of time range, exclusive
* @param {Number} offset pagination offset, default is 0
* @param {Number} limit pagination limit, default is 1000
* @returns {Promise<MetatraderDeals>} promise resolving with request results containing deals found
*/ getDealsByTimeRange(startTime, endTime, offset = 0, limit = 1000) {
this._checkIsConnectionActive();
return this._websocketClient.getDealsByTimeRange(this._metaApiConnection.account.id, startTime, endTime, offset, limit);
}
/**
* Retrieves available symbols for an account
* @param {String} symbol symbol to retrieve symbols for
* @returns {Promise<Array<string>>} promise which resolves when symbols are retrieved
*/ getSymbols() {
this._checkIsConnectionActive();
return this._websocketClient.getSymbols(this._metaApiConnection.account.id);
}
/**
* Retrieves specification for a symbol
* @param {String} symbol symbol to retrieve specification for
* @returns {Promise<MetatraderSymbolSpecification>} promise which resolves when specification is retrieved
*/ getSymbolSpecification(symbol) {
this._checkIsConnectionActive();
return this._websocketClient.getSymbolSpecification(this._metaApiConnection.account.id, symbol);
}
/**
* Retrieves latest price for a symbol
* @param {String} symbol symbol to retrieve price for
* @param {boolean} keepSubscription if set to true, the account will get a long-term subscription to symbol market
* data. Long-term subscription means that on subsequent calls you will get updated value faster. If set to false or
* not set, the subscription will be set to expire in 12 minutes.
* @returns {Promise<MetatraderSymbolPrice>} promise which resolves when price is retrieved
*/ getSymbolPrice(symbol, keepSubscription) {
this._checkIsConnectionActive();
return this._websocketClient.getSymbolPrice(this._metaApiConnection.account.id, symbol, keepSubscription);
}
/**
* Retrieves latest candle for a symbol and timeframe
* @param {String} symbol symbol to retrieve candle for
* @param {string} timeframe defines the timeframe according to which the candle must be generated. Allowed values for
* MT5 are 1m, 2m, 3m, 4m, 5m, 6m, 10m, 12m, 15m, 20m, 30m, 1h, 2h, 3h, 4h, 6h, 8h, 12h, 1d, 1w, 1mn. Allowed values
* for MT4 are 1m, 5m, 15m 30m, 1h, 4h, 1d, 1w, 1mn
* @param {boolean} keepSubscription if set to true, the account will get a long-term subscription to symbol market
* data. Long-term subscription means that on subsequent calls you will get updated value faster. If set to false or
* not set, the subscription will be set to expire in 12 minutes.
* @returns {Promise<MetatraderCandle>} promise which resolves when candle is retrieved
*/ getCandle(symbol, timeframe, keepSubscription = false) {
this._checkIsConnectionActive();
return this._websocketClient.getCandle(this._metaApiConnection.account.id, symbol, timeframe, keepSubscription);
}
/**
* Retrieves latest tick for a symbol. MT4 G1 accounts do not support this API
* @param {String} symbol symbol to retrieve tick for
* @param {boolean} keepSubscription if set to true, the account will get a long-term subscription to symbol market
* data. Long-term subscription means that on subsequent calls you will get updated value faster. If set to false or
* not set, the subscription will be set to expire in 12 minutes.
* @returns {Promise<MetatraderTick>} promise which resolves when tick is retrieved
*/ getTick(symbol, keepSubscription = false) {
this._checkIsConnectionActive();
return this._websocketClient.getTick(this._metaApiConnection.account.id, symbol, keepSubscription);
}
/**
* Retrieves latest order book for a symbol. MT4 accounts do not support this API
* @param {string} symbol symbol to retrieve order book for
* @param {boolean} keepSubscription if set to true, the account will get a long-term subscription to symbol market
* data. Long-term subscription means that on subsequent calls you will get updated value faster. If set to false or
* not set, the subscription will be set to expire in 12 minutes.
* @returns {Promise<MetatraderTick>} promise which resolves when order book is retrieved
*/ getBook(symbol, keepSubscription = false) {
this._checkIsConnectionActive();
return this._websocketClient.getBook(this._metaApiConnection.account.id, symbol, keepSubscription);
}
/**
* Returns server time for a specified MetaTrader account
* @returns {Promise<ServerTime>} promise resolving with server time
*/ getServerTime() {
var _this = this;
return _async_to_generator(function*() {
_this._checkIsConnectionActive();
return _this._websocketClient.getServerTime(_this._metaApiConnection.account.id);
})();
}
/**
* Waits until synchronization to RPC application is completed
* @param {Number} timeoutInSeconds synchronization timeout in seconds
* @return {Promise} promise which resolves when synchronization to RPC application is completed
* @throws {TimeoutError} if application failed to synchronize with the teminal within timeout allowed
*/ waitSynchronized(timeoutInSeconds = 300) {
var _this = this;
return _async_to_generator(function*() {
_this._checkIsConnectionActive();
return _this._metaApiConnection.waitSynchronized(timeoutInSeconds);
})();
}
/**
* Constructs MetaApi MetaTrader RPC Api connection instance
* @param {MetaApiWebsocketClient} websocketClient MetaApi websocket client
* @param {StreamingMetaApiConnection} metaApiConnection RPC MetaApi connection
*/ constructor(websocketClient, metaApiConnection){
super(websocketClient, metaApiConnection);
this._metaApiConnection = metaApiConnection;
this._logger = LoggerManager.getLogger('RpcMetaApiConnectionInstance');
}
};
/**
* Exposes MetaApi MetaTrader RPC API connection instance to consumers
*/ export { RpcMetaApiConnectionInstance as default };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBMb2dnZXJNYW5hZ2VyIGZyb20gJy4uL2xvZ2dlcic7XG5pbXBvcnQgTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSBmcm9tICcuL21ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2UnO1xuXG4vKipcbiAqIEV4cG9zZXMgTWV0YUFwaSBNZXRhVHJhZGVyIFJQQyBBUEkgY29ubmVjdGlvbiBpbnN0YW5jZSB0byBjb25zdW1lcnNcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUnBjTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSBleHRlbmRzIE1ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2Uge1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIE1ldGFBcGkgTWV0YVRyYWRlciBSUEMgQXBpIGNvbm5lY3Rpb24gaW5zdGFuY2VcbiAgICogQHBhcmFtIHtNZXRhQXBpV2Vic29ja2V0Q2xpZW50fSB3ZWJzb2NrZXRDbGllbnQgTWV0YUFwaSB3ZWJzb2NrZXQgY2xpZW50XG4gICAqIEBwYXJhbSB7U3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb259IG1ldGFBcGlDb25uZWN0aW9uIFJQQyBNZXRhQXBpIGNvbm5lY3Rpb25cbiAgICovXG4gIGNvbnN0cnVjdG9yKHdlYnNvY2tldENsaWVudCwgbWV0YUFwaUNvbm5lY3Rpb24pIHtcbiAgICBzdXBlcih3ZWJzb2NrZXRDbGllbnQsIG1ldGFBcGlDb25uZWN0aW9uKTtcbiAgICB0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbiA9IG1ldGFBcGlDb25uZWN0aW9uO1xuICAgIHRoaXMuX2xvZ2dlciA9IExvZ2dlck1hbmFnZXIuZ2V0TG9nZ2VyKCdScGNNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlJyk7XG4gIH1cblxuICAvKipcbiAgICogT3BlbnMgdGhlIGNvbm5lY3Rpb24uIENhbiBvbmx5IGJlIGNhbGxlZCB0aGUgZmlyc3QgdGltZSwgbmV4dCBjYWxscyB3aWxsIGJlIGlnbm9yZWQuXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gdGhlIGNvbm5lY3Rpb24gaXMgb3BlbmVkXG4gICAqL1xuICBhc3luYyBjb25uZWN0KCkge1xuICAgIGlmICghdGhpcy5fb3BlbmVkKSB7XG4gICAgICB0aGlzLl9vcGVuZWQgPSB0cnVlO1xuICAgICAgdGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uY29ubmVjdCh0aGlzLmluc3RhbmNlSWQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDbG9zZXMgdGhlIGNvbm5lY3Rpb24uIFRoZSBpbnN0YW5jZSBvZiB0aGUgY2xhc3Mgc2hvdWxkIG5vIGxvbmdlciBiZSB1c2VkIGFmdGVyIHRoaXMgbWV0aG9kIGlzIGludm9rZWQuXG4gICAqL1xuICBhc3luYyBjbG9zZSgpIHtcbiAgICBpZiAoIXRoaXMuX2Nsb3NlZCkge1xuICAgICAgdGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uY2xvc2UodGhpcy5pbnN0YW5jZUlkKTtcbiAgICAgIHRoaXMuX2Nsb3NlZCA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWNjb3VudCBpbmZvcm1hdGlvblxuICAgKiBAcGFyYW0ge0dldEFjY291bnRJbmZvcm1hdGlvbk9wdGlvbnN9IFtvcHRpb25zXSBhZGRpdGlvbmFsIHJlcXVlc3Qgb3B0aW9uc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNZXRhdHJhZGVyQWNjb3VudEluZm9ybWF0aW9uPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBhY2NvdW50IGluZm9ybWF0aW9uXG4gICAqL1xuICBnZXRBY2NvdW50SW5mb3JtYXRpb24ob3B0aW9ucykge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXRBY2NvdW50SW5mb3JtYXRpb24odGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uYWNjb3VudC5pZCwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBwb3NpdGlvbnNcbiAgICogQHBhcmFtIHtHZXRQb3NpdGlvbnNPcHRpb25zfSBbb3B0aW9uc10gYWRkaXRpb25hbCByZXF1ZXN0IG9wdGlvbnNcbiAgICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8TWV0YXRyYWRlclBvc2l0aW9uPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBhcnJheSBvZiBvcGVuIHBvc2l0aW9uc1xuICAgKi9cbiAgZ2V0UG9zaXRpb25zKG9wdGlvbnMpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0UG9zaXRpb25zKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3BlY2lmaWMgcG9zaXRpb25cbiAgICogQHBhcmFtIHtTdHJpbmd9IHBvc2l0aW9uSWQgcG9zaXRpb24gaWRcbiAgICogQHBhcmFtIHtHZXRQb3NpdGlvbk9wdGlvbnN9IFtvcHRpb25zXSBhZGRpdGlvbmFsIHJlcXVlc3Qgb3B0aW9uc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1ldGF0cmFkZXJQb3NpdGlvbj59IHByb21pc2UgcmVzb2x2aW5nIHdpdGggTWV0YVRyYWRlciBwb3NpdGlvbiBmb3VuZFxuICAgKi9cbiAgZ2V0UG9zaXRpb24ocG9zaXRpb25JZCwgb3B0aW9ucykge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXRQb3NpdGlvbih0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5hY2NvdW50LmlkLCBwb3NpdGlvbklkLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIG9wZW4gb3JkZXJzXG4gICAqIEBwYXJhbSB7R2V0T3JkZXJzT3B0aW9uc30gW29wdGlvbnNdIGFkZGl0aW9uYWwgcmVxdWVzdCBvcHRpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8TWV0YXRyYWRlck9yZGVyPj59IHByb21pc2UgcmVzb2x2aW5nIHdpdGggb3BlbiBNZXRhVHJhZGVyIG9yZGVyc1xuICAgKi9cbiAgZ2V0T3JkZXJzKG9wdGlvbnMpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0T3JkZXJzKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3BlY2lmaWMgb3BlbiBvcmRlclxuICAgKiBAcGFyYW0ge1N0cmluZ30gb3JkZXJJZCBvcmRlciBpZCAodGlja2V0IG51bWJlcilcbiAgICogQHBhcmFtIHtHZXRPcmRlck9wdGlvbnN9IFtvcHRpb25zXSBhZGRpdGlvbmFsIHJlcXVlc3Qgb3B0aW9uc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1ldGF0cmFkZXJPcmRlcj59IHByb21pc2UgcmVzb2x2aW5nIHdpdGggbWV0YXRyYWRlciBvcmRlciBmb3VuZFxuICAgKi9cbiAgZ2V0T3JkZXIob3JkZXJJZCwgb3B0aW9ucykge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXRPcmRlcih0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5hY2NvdW50LmlkLCBvcmRlcklkLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBoaXN0b3J5IG9mIGNvbXBsZXRlZCBvcmRlcnMgZm9yIGEgc3BlY2lmaWMgdGlja2V0IG51bWJlclxuICAgKiBAcGFyYW0ge1N0cmluZ30gdGlja2V0IHRpY2tldCBudW1iZXIgKG9yZGVyIGlkKVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNZXRhdHJhZGVySGlzdG9yeU9yZGVycz59IHByb21pc2UgcmVzb2x2aW5nIHdpdGggcmVxdWVzdCByZXN1bHRzIGNvbnRhaW5pbmcgaGlzdG9yeSBvcmRlcnMgZm91bmRcbiAgICovXG4gIGdldEhpc3RvcnlPcmRlcnNCeVRpY2tldCh0aWNrZXQpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0SGlzdG9yeU9yZGVyc0J5VGlja2V0KHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIHRpY2tldCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgaGlzdG9yeSBvZiBjb21wbGV0ZWQgb3JkZXJzIGZvciBhIHNwZWNpZmljIHBvc2l0aW9uIGlkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwb3NpdGlvbklkIHBvc2l0aW9uIGlkXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1ldGF0cmFkZXJIaXN0b3J5T3JkZXJzPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCByZXF1ZXN0IHJlc3VsdHMgY29udGFpbmluZyBoaXN0b3J5IG9yZGVycyBmb3VuZFxuICAgKi9cbiAgZ2V0SGlzdG9yeU9yZGVyc0J5UG9zaXRpb24ocG9zaXRpb25JZCkge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXRIaXN0b3J5T3JkZXJzQnlQb3NpdGlvbih0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5hY2NvdW50LmlkLCBwb3NpdGlvbklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBoaXN0b3J5IG9mIGNvbXBsZXRlZCBvcmRlcnMgZm9yIGEgc3BlY2lmaWMgdGltZSByYW5nZVxuICAgKiBAcGFyYW0ge0RhdGV9IHN0YXJ0VGltZSBzdGFydCBvZiB0aW1lIHJhbmdlLCBpbmNsdXNpdmVcbiAgICogQHBhcmFtIHtEYXRlfSBlbmRUaW1lIGVuZCBvZiB0aW1lIHJhbmdlLCBleGNsdXNpdmVcbiAgICogQHBhcmFtIHtOdW1iZXJ9IG9mZnNldCBwYWdpbmF0aW9uIG9mZnNldCwgZGVmYXVsdCBpcyAwXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBsaW1pdCBwYWdpbmF0aW9uIGxpbWl0LCBkZWZhdWx0IGlzIDEwMDBcbiAgICogQHJldHVybnMge1Byb21pc2U8TWV0YXRyYWRlckhpc3RvcnlPcmRlcnM+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIHJlcXVlc3QgcmVzdWx0cyBjb250YWluaW5nIGhpc3Rvcnkgb3JkZXJzIGZvdW5kXG4gICAqL1xuICBnZXRIaXN0b3J5T3JkZXJzQnlUaW1lUmFuZ2Uoc3RhcnRUaW1lLCBlbmRUaW1lLCBvZmZzZXQgPSAwLCBsaW1pdCA9IDEwMDApIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0SGlzdG9yeU9yZGVyc0J5VGltZVJhbmdlKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIFxuICAgICAgc3RhcnRUaW1lLCBlbmRUaW1lLCBvZmZzZXQsIGxpbWl0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGhpc3RvcnkgZGVhbHMgd2l0aCBhIHNwZWNpZmljIHRpY2tldCBudW1iZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IHRpY2tldCB0aWNrZXQgbnVtYmVyIChkZWFsIGlkIGZvciBNVDUgb3Igb3JkZXIgaWQgZm9yIE1UNClcbiAgICogQHJldHVybnMge1Byb21pc2U8TWV0YXRyYWRlckRlYWxzPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCByZXF1ZXN0IHJlc3VsdHMgY29udGFpbmluZyBkZWFscyBmb3VuZFxuICAgKi9cbiAgZ2V0RGVhbHNCeVRpY2tldCh0aWNrZXQpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0RGVhbHNCeVRpY2tldCh0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5hY2NvdW50LmlkLCB0aWNrZXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgaGlzdG9yeSBkZWFscyBmb3IgYSBzcGVjaWZpYyBwb3NpdGlvbiBpZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gcG9zaXRpb25JZCBwb3NpdGlvbiBpZFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNZXRhdHJhZGVyRGVhbHM+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIHJlcXVlc3QgcmVzdWx0cyBjb250YWluaW5nIGRlYWxzIGZvdW5kXG4gICAqL1xuICBnZXREZWFsc0J5UG9zaXRpb24ocG9zaXRpb25JZCkge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXREZWFsc0J5UG9zaXRpb24odGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uYWNjb3VudC5pZCwgcG9zaXRpb25JZCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBoaXN0b3J5IGRlYWxzIHdpdGggZm9yIGEgc3BlY2lmaWMgdGltZSByYW5nZVxuICAgKiBAcGFyYW0ge0RhdGV9IHN0YXJ0VGltZSBzdGFydCBvZiB0aW1lIHJhbmdlLCBpbmNsdXNpdmVcbiAgICogQHBhcmFtIHtEYXRlfSBlbmRUaW1lIGVuZCBvZiB0aW1lIHJhbmdlLCBleGNsdXNpdmVcbiAgICogQHBhcmFtIHtOdW1iZXJ9IG9mZnNldCBwYWdpbmF0aW9uIG9mZnNldCwgZGVmYXVsdCBpcyAwXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBsaW1pdCBwYWdpbmF0aW9uIGxpbWl0LCBkZWZhdWx0IGlzIDEwMDBcbiAgICogQHJldHVybnMge1Byb21pc2U8TWV0YXRyYWRlckRlYWxzPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCByZXF1ZXN0IHJlc3VsdHMgY29udGFpbmluZyBkZWFscyBmb3VuZFxuICAgKi9cbiAgZ2V0RGVhbHNCeVRpbWVSYW5nZShzdGFydFRpbWUsIGVuZFRpbWUsIG9mZnNldCA9IDAsIGxpbWl0ID0gMTAwMCkge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXREZWFsc0J5VGltZVJhbmdlKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIFxuICAgICAgc3RhcnRUaW1lLCBlbmRUaW1lLCBvZmZzZXQsIGxpbWl0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYXZhaWxhYmxlIHN5bWJvbHMgZm9yIGFuIGFjY291bnRcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBzeW1ib2wgdG8gcmV0cmlldmUgc3ltYm9scyBmb3JcbiAgICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8c3RyaW5nPj59IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiBzeW1ib2xzIGFyZSByZXRyaWV2ZWRcbiAgICovXG4gIGdldFN5bWJvbHMoKSB7XG4gICAgdGhpcy5fY2hlY2tJc0Nvbm5lY3Rpb25BY3RpdmUoKTtcbiAgICByZXR1cm4gdGhpcy5fd2Vic29ja2V0Q2xpZW50LmdldFN5bWJvbHModGhpcy5fbWV0YUFwaUNvbm5lY3Rpb24uYWNjb3VudC5pZCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHNwZWNpZmljYXRpb24gZm9yIGEgc3ltYm9sXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzeW1ib2wgc3ltYm9sIHRvIHJldHJpZXZlIHNwZWNpZmljYXRpb24gZm9yXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1ldGF0cmFkZXJTeW1ib2xTcGVjaWZpY2F0aW9uPn0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHNwZWNpZmljYXRpb24gaXMgcmV0cmlldmVkXG4gICAqL1xuICBnZXRTeW1ib2xTcGVjaWZpY2F0aW9uKHN5bWJvbCkge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXRTeW1ib2xTcGVjaWZpY2F0aW9uKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIHN5bWJvbCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGxhdGVzdCBwcmljZSBmb3IgYSBzeW1ib2xcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBzeW1ib2wgdG8gcmV0cmlldmUgcHJpY2UgZm9yXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0ga2VlcFN1YnNjcmlwdGlvbiBpZiBzZXQgdG8gdHJ1ZSwgdGhlIGFjY291bnQgd2lsbCBnZXQgYSBsb25nLXRlcm0gc3Vic2NyaXB0aW9uIHRvIHN5bWJvbCBtYXJrZXRcbiAgICogZGF0YS4gTG9uZy10ZXJtIHN1YnNjcmlwdGlvbiBtZWFucyB0aGF0IG9uIHN1YnNlcXVlbnQgY2FsbHMgeW91IHdpbGwgZ2V0IHVwZGF0ZWQgdmFsdWUgZmFzdGVyLiBJZiBzZXQgdG8gZmFsc2Ugb3JcbiAgICogbm90IHNldCwgdGhlIHN1YnNjcmlwdGlvbiB3aWxsIGJlIHNldCB0byBleHBpcmUgaW4gMTIgbWludXRlcy5cbiAgICogQHJldHVybnMge1Byb21pc2U8TWV0YXRyYWRlclN5bWJvbFByaWNlPn0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHByaWNlIGlzIHJldHJpZXZlZFxuICAgKi9cbiAgZ2V0U3ltYm9sUHJpY2Uoc3ltYm9sLCBrZWVwU3Vic2NyaXB0aW9uKSB7XG4gICAgdGhpcy5fY2hlY2tJc0Nvbm5lY3Rpb25BY3RpdmUoKTtcbiAgICByZXR1cm4gdGhpcy5fd2Vic29ja2V0Q2xpZW50LmdldFN5bWJvbFByaWNlKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIHN5bWJvbCwga2VlcFN1YnNjcmlwdGlvbik7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGxhdGVzdCBjYW5kbGUgZm9yIGEgc3ltYm9sIGFuZCB0aW1lZnJhbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBzeW1ib2wgdG8gcmV0cmlldmUgY2FuZGxlIGZvclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGltZWZyYW1lIGRlZmluZXMgdGhlIHRpbWVmcmFtZSBhY2NvcmRpbmcgdG8gd2hpY2ggdGhlIGNhbmRsZSBtdXN0IGJlIGdlbmVyYXRlZC4gQWxsb3dlZCB2YWx1ZXMgZm9yXG4gICAqIE1UNSBhcmUgMW0sIDJtLCAzbSwgNG0sIDVtLCA2bSwgMTBtLCAxMm0sIDE1bSwgMjBtLCAzMG0sIDFoLCAyaCwgM2gsIDRoLCA2aCwgOGgsIDEyaCwgMWQsIDF3LCAxbW4uIEFsbG93ZWQgdmFsdWVzXG4gICAqIGZvciBNVDQgYXJlIDFtLCA1bSwgMTVtIDMwbSwgMWgsIDRoLCAxZCwgMXcsIDFtblxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGtlZXBTdWJzY3JpcHRpb24gaWYgc2V0IHRvIHRydWUsIHRoZSBhY2NvdW50IHdpbGwgZ2V0IGEgbG9uZy10ZXJtIHN1YnNjcmlwdGlvbiB0byBzeW1ib2wgbWFya2V0XG4gICAqIGRhdGEuIExvbmctdGVybSBzdWJzY3JpcHRpb24gbWVhbnMgdGhhdCBvbiBzdWJzZXF1ZW50IGNhbGxzIHlvdSB3aWxsIGdldCB1cGRhdGVkIHZhbHVlIGZhc3Rlci4gSWYgc2V0IHRvIGZhbHNlIG9yXG4gICAqIG5vdCBzZXQsIHRoZSBzdWJzY3JpcHRpb24gd2lsbCBiZSBzZXQgdG8gZXhwaXJlIGluIDEyIG1pbnV0ZXMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1ldGF0cmFkZXJDYW5kbGU+fSBwcm9taXNlIHdoaWNoIHJlc29sdmVzIHdoZW4gY2FuZGxlIGlzIHJldHJpZXZlZFxuICAgKi9cbiAgZ2V0Q2FuZGxlKHN5bWJvbCwgdGltZWZyYW1lLCBrZWVwU3Vic2NyaXB0aW9uID0gZmFsc2UpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0Q2FuZGxlKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIHN5bWJvbCwgdGltZWZyYW1lLCBrZWVwU3Vic2NyaXB0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgbGF0ZXN0IHRpY2sgZm9yIGEgc3ltYm9sLiBNVDQgRzEgYWNjb3VudHMgZG8gbm90IHN1cHBvcnQgdGhpcyBBUElcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBzeW1ib2wgdG8gcmV0cmlldmUgdGljayBmb3JcbiAgICogQHBhcmFtIHtib29sZWFufSBrZWVwU3Vic2NyaXB0aW9uIGlmIHNldCB0byB0cnVlLCB0aGUgYWNjb3VudCB3aWxsIGdldCBhIGxvbmctdGVybSBzdWJzY3JpcHRpb24gdG8gc3ltYm9sIG1hcmtldFxuICAgKiBkYXRhLiBMb25nLXRlcm0gc3Vic2NyaXB0aW9uIG1lYW5zIHRoYXQgb24gc3Vic2VxdWVudCBjYWxscyB5b3Ugd2lsbCBnZXQgdXBkYXRlZCB2YWx1ZSBmYXN0ZXIuIElmIHNldCB0byBmYWxzZSBvclxuICAgKiBub3Qgc2V0LCB0aGUgc3Vic2NyaXB0aW9uIHdpbGwgYmUgc2V0IHRvIGV4cGlyZSBpbiAxMiBtaW51dGVzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNZXRhdHJhZGVyVGljaz59IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiB0aWNrIGlzIHJldHJpZXZlZFxuICAgKi9cbiAgZ2V0VGljayhzeW1ib2wsIGtlZXBTdWJzY3JpcHRpb24gPSBmYWxzZSkge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX3dlYnNvY2tldENsaWVudC5nZXRUaWNrKHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLmFjY291bnQuaWQsIHN5bWJvbCwga2VlcFN1YnNjcmlwdGlvbik7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGxhdGVzdCBvcmRlciBib29rIGZvciBhIHN5bWJvbC4gTVQ0IGFjY291bnRzIGRvIG5vdCBzdXBwb3J0IHRoaXMgQVBJXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzeW1ib2wgc3ltYm9sIHRvIHJldHJpZXZlIG9yZGVyIGJvb2sgZm9yXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0ga2VlcFN1YnNjcmlwdGlvbiBpZiBzZXQgdG8gdHJ1ZSwgdGhlIGFjY291bnQgd2lsbCBnZXQgYSBsb25nLXRlcm0gc3Vic2NyaXB0aW9uIHRvIHN5bWJvbCBtYXJrZXRcbiAgICogZGF0YS4gTG9uZy10ZXJtIHN1YnNjcmlwdGlvbiBtZWFucyB0aGF0IG9uIHN1YnNlcXVlbnQgY2FsbHMgeW91IHdpbGwgZ2V0IHVwZGF0ZWQgdmFsdWUgZmFzdGVyLiBJZiBzZXQgdG8gZmFsc2Ugb3JcbiAgICogbm90IHNldCwgdGhlIHN1YnNjcmlwdGlvbiB3aWxsIGJlIHNldCB0byBleHBpcmUgaW4gMTIgbWludXRlcy5cbiAgICogQHJldHVybnMge1Byb21pc2U8TWV0YXRyYWRlclRpY2s+fSBwcm9taXNlIHdoaWNoIHJlc29sdmVzIHdoZW4gb3JkZXIgYm9vayBpcyByZXRyaWV2ZWRcbiAgICovXG4gIGdldEJvb2soc3ltYm9sLCBrZWVwU3Vic2NyaXB0aW9uID0gZmFsc2UpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0Qm9vayh0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5hY2NvdW50LmlkLCBzeW1ib2wsIGtlZXBTdWJzY3JpcHRpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc2VydmVyIHRpbWUgZm9yIGEgc3BlY2lmaWVkIE1ldGFUcmFkZXIgYWNjb3VudFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTZXJ2ZXJUaW1lPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBzZXJ2ZXIgdGltZVxuICAgKi9cbiAgYXN5bmMgZ2V0U2VydmVyVGltZSgpIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuZ2V0U2VydmVyVGltZSh0aGlzLl9tZXRhQXBpQ29ubmVjdGlvbi5hY2NvdW50LmlkKTtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIFdhaXRzIHVudGlsIHN5bmNocm9uaXphdGlvbiB0byBSUEMgYXBwbGljYXRpb24gaXMgY29tcGxldGVkXG4gICAqIEBwYXJhbSB7TnVtYmVyfSB0aW1lb3V0SW5TZWNvbmRzIHN5bmNocm9uaXphdGlvbiB0aW1lb3V0IGluIHNlY29uZHNcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHN5bmNocm9uaXphdGlvbiB0byBSUEMgYXBwbGljYXRpb24gaXMgY29tcGxldGVkXG4gICAqIEB0aHJvd3Mge1RpbWVvdXRFcnJvcn0gaWYgYXBwbGljYXRpb24gZmFpbGVkIHRvIHN5bmNocm9uaXplIHdpdGggdGhlIHRlbWluYWwgd2l0aGluIHRpbWVvdXQgYWxsb3dlZFxuICAgKi9cbiAgYXN5bmMgd2FpdFN5bmNocm9uaXplZCh0aW1lb3V0SW5TZWNvbmRzPTMwMCkge1xuICAgIHRoaXMuX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX21ldGFBcGlDb25uZWN0aW9uLndhaXRTeW5jaHJvbml6ZWQodGltZW91dEluU2Vjb25kcyk7XG4gIH1cblxufVxuIl0sIm5hbWVzIjpbIkxvZ2dlck1hbmFnZXIiLCJNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlIiwiUnBjTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSIsImNvbm5lY3QiLCJfb3BlbmVkIiwiX21ldGFBcGlDb25uZWN0aW9uIiwiaW5zdGFuY2VJZCIsImNsb3NlIiwiX2Nsb3NlZCIsImdldEFjY291bnRJbmZvcm1hdGlvbiIsIm9wdGlvbnMiLCJfY2hlY2tJc0Nvbm5lY3Rpb25BY3RpdmUiLCJfd2Vic29ja2V0Q2xpZW50IiwiYWNjb3VudCIsImlkIiwiZ2V0UG9zaXRpb25zIiwiZ2V0UG9zaXRpb24iLCJwb3NpdGlvbklkIiwiZ2V0T3JkZXJzIiwiZ2V0T3JkZXIiLCJvcmRlcklkIiwiZ2V0SGlzdG9yeU9yZGVyc0J5VGlja2V0IiwidGlja2V0IiwiZ2V0SGlzdG9yeU9yZGVyc0J5UG9zaXRpb24iLCJnZXRIaXN0b3J5T3JkZXJzQnlUaW1lUmFuZ2UiLCJzdGFydFRpbWUiLCJlbmRUaW1lIiwib2Zmc2V0IiwibGltaXQiLCJnZXREZWFsc0J5VGlja2V0IiwiZ2V0RGVhbHNCeVBvc2l0aW9uIiwiZ2V0RGVhbHNCeVRpbWVSYW5nZSIsImdldFN5bWJvbHMiLCJnZXRTeW1ib2xTcGVjaWZpY2F0aW9uIiwic3ltYm9sIiwiZ2V0U3ltYm9sUHJpY2UiLCJrZWVwU3Vic2NyaXB0aW9uIiwiZ2V0Q2FuZGxlIiwidGltZWZyYW1lIiwiZ2V0VGljayIsImdldEJvb2siLCJnZXRTZXJ2ZXJUaW1lIiwid2FpdFN5bmNocm9uaXplZCIsInRpbWVvdXRJblNlY29uZHMiLCJjb25zdHJ1Y3RvciIsIndlYnNvY2tldENsaWVudCIsIm1ldGFBcGlDb25uZWN0aW9uIiwiX2xvZ2dlciIsImdldExvZ2dlciJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLE9BQU9BLG1CQUFtQixZQUFZO0FBQ3RDLE9BQU9DLCtCQUErQiw4QkFBOEI7QUFLckQsSUFBQSxBQUFNQywrQkFBTixNQUFNQSxxQ0FBcUNEO0lBYXhEOzs7R0FHQyxHQUNELEFBQU1FOztlQUFOLG9CQUFBO1lBQ0UsSUFBSSxDQUFDLE1BQUtDLE9BQU8sRUFBRTtnQkFDakIsTUFBS0EsT0FBTyxHQUFHO2dCQUNmLE1BQUtDLGtCQUFrQixDQUFDRixPQUFPLENBQUMsTUFBS0csVUFBVTtZQUNqRDtRQUNGOztJQUVBOztHQUVDLEdBQ0QsQUFBTUM7O2VBQU4sb0JBQUE7WUFDRSxJQUFJLENBQUMsTUFBS0MsT0FBTyxFQUFFO2dCQUNqQixNQUFLSCxrQkFBa0IsQ0FBQ0UsS0FBSyxDQUFDLE1BQUtELFVBQVU7Z0JBQzdDLE1BQUtFLE9BQU8sR0FBRztZQUNqQjtRQUNGOztJQUVBOzs7O0dBSUMsR0FDREMsc0JBQXNCQyxPQUFPLEVBQUU7UUFDN0IsSUFBSSxDQUFDQyx3QkFBd0I7UUFDN0IsT0FBTyxJQUFJLENBQUNDLGdCQUFnQixDQUFDSCxxQkFBcUIsQ0FBQyxJQUFJLENBQUNKLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRUo7SUFDekY7SUFFQTs7OztHQUlDLEdBQ0RLLGFBQWFMLE9BQU8sRUFBRTtRQUNwQixJQUFJLENBQUNDLHdCQUF3QjtRQUM3QixPQUFPLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUNHLFlBQVksQ0FBQyxJQUFJLENBQUNWLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRUo7SUFDaEY7SUFFQTs7Ozs7R0FLQyxHQUNETSxZQUFZQyxVQUFVLEVBQUVQLE9BQU8sRUFBRTtRQUMvQixJQUFJLENBQUNDLHdCQUF3QjtRQUM3QixPQUFPLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUNJLFdBQVcsQ0FBQyxJQUFJLENBQUNYLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRUcsWUFBWVA7SUFDM0Y7SUFFQTs7OztHQUlDLEdBQ0RRLFVBQVVSLE9BQU8sRUFBRTtRQUNqQixJQUFJLENBQUNDLHdCQUF3QjtRQUM3QixPQUFPLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUNNLFNBQVMsQ0FBQyxJQUFJLENBQUNiLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRUo7SUFDN0U7SUFFQTs7Ozs7R0FLQyxHQUNEUyxTQUFTQyxPQUFPLEVBQUVWLE9BQU8sRUFBRTtRQUN6QixJQUFJLENBQUNDLHdCQUF3QjtRQUM3QixPQUFPLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUNPLFFBQVEsQ0FBQyxJQUFJLENBQUNkLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRU0sU0FBU1Y7SUFDckY7SUFFQTs7OztHQUlDLEdBQ0RXLHlCQUF5QkMsTUFBTSxFQUFFO1FBQy9CLElBQUksQ0FBQ1gsd0JBQXdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ1Msd0JBQXdCLENBQUMsSUFBSSxDQUFDaEIsa0JBQWtCLENBQUNRLE9BQU8sQ0FBQ0MsRUFBRSxFQUFFUTtJQUM1RjtJQUVBOzs7O0dBSUMsR0FDREMsMkJBQTJCTixVQUFVLEVBQUU7UUFDckMsSUFBSSxDQUFDTix3QkFBd0I7UUFDN0IsT0FBTyxJQUFJLENBQUNDLGdCQUFnQixDQUFDVywwQkFBMEIsQ0FBQyxJQUFJLENBQUNsQixrQkFBa0IsQ0FBQ1EsT0FBTyxDQUFDQyxFQUFFLEVBQUVHO0lBQzlGO0lBRUE7Ozs7Ozs7R0FPQyxHQUNETyw0QkFBNEJDLFNBQVMsRUFBRUMsT0FBTyxFQUFFQyxTQUFTLENBQUMsRUFBRUMsUUFBUSxJQUFJLEVBQUU7UUFDeEUsSUFBSSxDQUFDakIsd0JBQXdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ1ksMkJBQTJCLENBQUMsSUFBSSxDQUFDbkIsa0JBQWtCLENBQUNRLE9BQU8sQ0FBQ0MsRUFBRSxFQUN6RlcsV0FBV0MsU0FBU0MsUUFBUUM7SUFDaEM7SUFFQTs7OztHQUlDLEdBQ0RDLGlCQUFpQlAsTUFBTSxFQUFFO1FBQ3ZCLElBQUksQ0FBQ1gsd0JBQXdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ2lCLGdCQUFnQixDQUFDLElBQUksQ0FBQ3hCLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRVE7SUFDcEY7SUFFQTs7OztHQUlDLEdBQ0RRLG1CQUFtQmIsVUFBVSxFQUFFO1FBQzdCLElBQUksQ0FBQ04sd0JBQXdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ2tCLGtCQUFrQixDQUFDLElBQUksQ0FBQ3pCLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRUc7SUFDdEY7SUFFQTs7Ozs7OztHQU9DLEdBQ0RjLG9CQUFvQk4sU0FBUyxFQUFFQyxPQUFPLEVBQUVDLFNBQVMsQ0FBQyxFQUFFQyxRQUFRLElBQUksRUFBRTtRQUNoRSxJQUFJLENBQUNqQix3QkFBd0I7UUFDN0IsT0FBTyxJQUFJLENBQUNDLGdCQUFnQixDQUFDbUIsbUJBQW1CLENBQUMsSUFBSSxDQUFDMUIsa0JBQWtCLENBQUNRLE9BQU8sQ0FBQ0MsRUFBRSxFQUNqRlcsV0FBV0MsU0FBU0MsUUFBUUM7SUFDaEM7SUFFQTs7OztHQUlDLEdBQ0RJLGFBQWE7UUFDWCxJQUFJLENBQUNyQix3QkFBd0I7UUFDN0IsT0FBTyxJQUFJLENBQUNDLGdCQUFnQixDQUFDb0IsVUFBVSxDQUFDLElBQUksQ0FBQzNCLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUU7SUFDNUU7SUFFQTs7OztHQUlDLEdBQ0RtQix1QkFBdUJDLE1BQU0sRUFBRTtRQUM3QixJQUFJLENBQUN2Qix3QkFBd0I7UUFDN0IsT0FBTyxJQUFJLENBQUNDLGdCQUFnQixDQUFDcUIsc0JBQXNCLENBQUMsSUFBSSxDQUFDNUIsa0JBQWtCLENBQUNRLE9BQU8sQ0FBQ0MsRUFBRSxFQUFFb0I7SUFDMUY7SUFFQTs7Ozs7OztHQU9DLEdBQ0RDLGVBQWVELE1BQU0sRUFBRUUsZ0JBQWdCLEVBQUU7UUFDdkMsSUFBSSxDQUFDekIsd0JBQXdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ3VCLGNBQWMsQ0FBQyxJQUFJLENBQUM5QixrQkFBa0IsQ0FBQ1EsT0FBTyxDQUFDQyxFQUFFLEVBQUVvQixRQUFRRTtJQUMxRjtJQUVBOzs7Ozs7Ozs7O0dBVUMsR0FDREMsVUFBVUgsTUFBTSxFQUFFSSxTQUFTLEVBQUVGLG1CQUFtQixLQUFLLEVBQUU7UUFDckQsSUFBSSxDQUFDekIsd0JBQXdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ3lCLFNBQVMsQ0FBQyxJQUFJLENBQUNoQyxrQkFBa0IsQ0FBQ1EsT0FBTyxDQUFDQyxFQUFFLEVBQUVvQixRQUFRSSxXQUFXRjtJQUNoRztJQUVBOzs7Ozs7O0dBT0MsR0FDREcsUUFBUUwsTUFBTSxFQUFFRSxtQkFBbUIsS0FBSyxFQUFFO1FBQ3hDLElBQUksQ0FBQ3pCLHdCQUF3QjtRQUM3QixPQUFPLElBQUksQ0FBQ0MsZ0JBQWdCLENBQUMyQixPQUFPLENBQUMsSUFBSSxDQUFDbEMsa0JBQWtCLENBQUNRLE9BQU8sQ0FBQ0MsRUFBRSxFQUFFb0IsUUFBUUU7SUFDbkY7SUFFQTs7Ozs7OztHQU9DLEdBQ0RJLFFBQVFOLE1BQU0sRUFBRUUsbUJBQW1CLEtBQUssRUFBRTtRQUN4QyxJQUFJLENBQUN6Qix3QkFBd0I7UUFDN0IsT0FBTyxJQUFJLENBQUNDLGdCQUFnQixDQUFDNEIsT0FBTyxDQUFDLElBQUksQ0FBQ25DLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUUsRUFBRW9CLFFBQVFFO0lBQ25GO0lBRUE7OztHQUdDLEdBQ0QsQUFBTUs7O2VBQU4sb0JBQUE7WUFDRSxNQUFLOUIsd0JBQXdCO1lBQzdCLE9BQU8sTUFBS0MsZ0JBQWdCLENBQUM2QixhQUFhLENBQUMsTUFBS3BDLGtCQUFrQixDQUFDUSxPQUFPLENBQUNDLEVBQUU7UUFDL0U7O0lBR0E7Ozs7O0dBS0MsR0FDRCxBQUFNNEIsaUJBQWlCQyxtQkFBaUIsR0FBRzs7ZUFBM0Msb0JBQUE7WUFDRSxNQUFLaEMsd0JBQXdCO1lBQzdCLE9BQU8sTUFBS04sa0JBQWtCLENBQUNxQyxnQkFBZ0IsQ0FBQ0M7UUFDbEQ7O0lBdFBBOzs7O0dBSUMsR0FDREMsWUFBWUMsZUFBZSxFQUFFQyxpQkFBaUIsQ0FBRTtRQUM5QyxLQUFLLENBQUNELGlCQUFpQkM7UUFDdkIsSUFBSSxDQUFDekMsa0JBQWtCLEdBQUd5QztRQUMxQixJQUFJLENBQUNDLE9BQU8sR0FBRy9DLGNBQWNnRCxTQUFTLENBQUM7SUFDekM7QUErT0Y7QUE3UEE7O0NBRUMsR0FDRCxTQUFxQjlDLDBDQTBQcEIifQ==