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)
215 lines (214 loc) • 25.7 kB
JavaScript
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
import randomstring from 'randomstring';
import * as lrap from '../long-running-async-process';
import StickySocketConnection from './stickySocketConnection';
import * as errors from '../../clients/errorHandler';
import { destroyInternalClientSocket } from './common.utils';
import { msToSeconds } from '../../helpers/convert/time';
import EventEmitter from '../../tools/eventEmitter';
import LoggerManager from '../../logger';
import Queue from '../../tools/queue';
/**
* Client sticky socket
*/ let ClientStickySocket = class ClientStickySocket extends EventEmitter {
/**
* Returns socket ID
* @returns socket ID
*/ get id() {
return this._id;
}
/**
* Returns current native socket
* @returns socket.io socket
* @internal intended for tests only
*/ get socket() {
var _this__pool_getProcess;
return (_this__pool_getProcess = this._pool.getProcess('connection')) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.socket;
}
/**
* Returns current transport name, using socket.io internals
* @returns transport name, e.g. "websocket"
* @internal intended for tests only
*/ get transportName() {
var _this__pool_getProcess;
return (_this__pool_getProcess = this._pool.getProcess('connection')) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.transportName;
}
/**
* Returns first present packet index in last emit history
* @returns first history index
* @internal intended for tests only
*/ get firstHistoryIndex() {
var _this__pool_getProcess;
return (_this__pool_getProcess = this._pool.getProcess('connection')) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.firstHistoryIndex;
}
/**
* Returns whether socket connected
* @returns is connected
*/ get connected() {
return this._connected;
}
/**
* @inheritdoc
* @remarks Socket events `ClientStickySockets.INTERNAL_EVENTS` cannot be subscribed to
* @throws `ValidationError` if attempting to subscribe to an internal event
*/ on(event, callback) {
if (ClientStickySocket.INTERNAL_EVENTS.includes(event)) {
throw new errors.ValidationError('Cannot subscribe to an internal event');
}
super.on(event, callback);
}
/**
* 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__pool_getProcess;
(_this__pool_getProcess = this._pool.getProcess('connection')) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.send(event, ...args);
}
/**
* Disconnects socket
* @param err error if disconnecting with error
* @returns promise resolving when disconnected
*/ disconnect(err) {
var _this = this;
return _async_to_generator(function*() {
clearTimeout(_this._stickyConnectionWaitTimeout);
let wasStopped = _this._stopped;
_this._stopped = true;
yield _this._pool.stop();
if (!wasStopped) {
_this._connected = false;
_this.emit('disconnect', err);
}
})();
}
/**
* Destroys underlying socket, using socket.io internals. The socket must have `websocket` transport
* @param err optional error
* @internal intended for tests only, e.g. to test connection loss
*/ destroyInternalSocket(err) {
destroyInternalClientSocket(this._pool.getProcess('connection').socket, err);
}
/**
* Removes expired emit history
* @internal intended for tests only
*/ removeExpiredEmitHistory() {
var _this__pool_getProcess;
(_this__pool_getProcess = this._pool.getProcess('connection')) === null || _this__pool_getProcess === void 0 ? void 0 : _this__pool_getProcess.removeExpiredEmitHistory();
}
/**
* Constructs instance
* @param url URL
* @param options options
*/ constructor(url, options){
super();
_define_property(this, "_logger", LoggerManager.getLogger('ClientStickySocket'));
_define_property(this, "_pool", void 0);
_define_property(this, "_stickyConnectionWaitTimeout", void 0);
_define_property(this, "_id", randomstring.generate(16));
_define_property(this, "_label", void 0);
_define_property(this, "_stopped", false);
_define_property(this, "_connected", false);
this._label = `${(options === null || options === void 0 ? void 0 : options.label) || 'connection'}:${this._id}`;
var _options_stickyConnectionTtlInSeconds;
const stickyConnectionTtlInMs = 1000 * ((_options_stickyConnectionTtlInSeconds = options === null || options === void 0 ? void 0 : options.stickyConnectionTtlInSeconds) !== null && _options_stickyConnectionTtlInSeconds !== void 0 ? _options_stickyConnectionTtlInSeconds : 10);
let internalEvents = new EventEmitter();
internalEvents.once('connect', ()=>{
this._connected = true;
this.emit('connect');
});
internalEvents.on('connect', ()=>clearTimeout(this._stickyConnectionWaitTimeout));
internalEvents.on('fail', (err)=>{
if (options === null || options === void 0 ? void 0 : options.useNativeSocketIoServer) {
this.disconnect(err);
return;
}
if (!this._stopped) {
this._stickyConnectionWaitTimeout = setTimeout(()=>{
this._logger.warn(`${this._label}: failed to restore sticky connection`);
this.disconnect(err);
}, stickyConnectionTtlInMs);
}
});
this._pool = new lrap.RootPool(StickySocketConnection, {
dependencies: [
this,
internalEvents
],
label: `clientStickySocket:${this._label}`
});
var _options_emitHistoryTtlInSeconds, _options_reconnectionDelayInMs, _options_reconnectionDelayMaxInMs, _options_reconnectionRandomizationFactor;
this._pool.scheduleProcess('connection', {
args: [
url,
this._id,
{
startCount: 0,
emitHistory: new Queue(),
lastSentIndex: -1,
lastReceivedIndex: -1
},
{
label: this._label,
connection: options === null || options === void 0 ? void 0 : options.connection,
useNativeSocketIoServer: options === null || options === void 0 ? void 0 : options.useNativeSocketIoServer,
emitHistoryTtlInSeconds: (_options_emitHistoryTtlInSeconds = options === null || options === void 0 ? void 0 : options.emitHistoryTtlInSeconds) !== null && _options_emitHistoryTtlInSeconds !== void 0 ? _options_emitHistoryTtlInSeconds : msToSeconds(stickyConnectionTtlInMs)
}
],
failoverThrottleDelay: {
mode: 'exponential',
resetDelayInMs: 0,
minDelayInMs: (_options_reconnectionDelayInMs = options === null || options === void 0 ? void 0 : options.reconnectionDelayInMs) !== null && _options_reconnectionDelayInMs !== void 0 ? _options_reconnectionDelayInMs : 1000,
maxDelayInMs: (_options_reconnectionDelayMaxInMs = options === null || options === void 0 ? void 0 : options.reconnectionDelayMaxInMs) !== null && _options_reconnectionDelayMaxInMs !== void 0 ? _options_reconnectionDelayMaxInMs : 10000,
randomizationFactor: (_options_reconnectionRandomizationFactor = options === null || options === void 0 ? void 0 : options.reconnectionRandomizationFactor) !== null && _options_reconnectionRandomizationFactor !== void 0 ? _options_reconnectionRandomizationFactor : 0.5
}
});
}
};
(function(ClientStickySocket) {
/** Connection events */ ClientStickySocket.CONNECTION_EVENTS = StickySocketConnection.CONNECTION_EVENTS;
/** Internal events */ ClientStickySocket.INTERNAL_EVENTS = StickySocketConnection.INTERNAL_EVENTS;
})(ClientStickySocket || (ClientStickySocket = {}));
export default ClientStickySocket;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcmFuZG9tc3RyaW5nIGZyb20gJ3JhbmRvbXN0cmluZyc7XG5pbXBvcnQgKiBhcyBscmFwIGZyb20gJy4uL2xvbmctcnVubmluZy1hc3luYy1wcm9jZXNzJztcbmltcG9ydCBTdGlja3lTb2NrZXRDb25uZWN0aW9uIGZyb20gJy4vc3RpY2t5U29ja2V0Q29ubmVjdGlvbic7XG5pbXBvcnQgKiBhcyBlcnJvcnMgZnJvbSAnLi4vLi4vY2xpZW50cy9lcnJvckhhbmRsZXInO1xuaW1wb3J0IHtkZXN0cm95SW50ZXJuYWxDbGllbnRTb2NrZXR9IGZyb20gJy4vY29tbW9uLnV0aWxzJztcbmltcG9ydCB7bXNUb1NlY29uZHN9IGZyb20gJy4uLy4uL2hlbHBlcnMvY29udmVydC90aW1lJztcbmltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSAnLi4vLi4vdG9vbHMvZXZlbnRFbWl0dGVyJztcbmltcG9ydCBMb2dnZXJNYW5hZ2VyIGZyb20gJy4uLy4uL2xvZ2dlcic7XG5pbXBvcnQgUXVldWUgZnJvbSAnLi4vLi4vdG9vbHMvcXVldWUnO1xuXG4vKipcbiAqIENsaWVudCBzdGlja3kgc29ja2V0XG4gKi9cbmNsYXNzIENsaWVudFN0aWNreVNvY2tldCBleHRlbmRzIEV2ZW50RW1pdHRlcjxDbGllbnRTdGlja3lTb2NrZXQuRXZlbnRzPiB7XG5cbiAgcHJpdmF0ZSBfbG9nZ2VyID0gTG9nZ2VyTWFuYWdlci5nZXRMb2dnZXIoJ0NsaWVudFN0aWNreVNvY2tldCcpO1xuICBwcml2YXRlIF9wb29sOiBscmFwLlJvb3RQb29sPFN0aWNreVNvY2tldENvbm5lY3Rpb24+O1xuICBwcml2YXRlIF9zdGlja3lDb25uZWN0aW9uV2FpdFRpbWVvdXQ/OiBOb2RlSlMuVGltZW91dDtcbiAgcHJpdmF0ZSBfaWQgPSByYW5kb21zdHJpbmcuZ2VuZXJhdGUoMTYpO1xuICBwcml2YXRlIF9sYWJlbDogc3RyaW5nO1xuICBwcml2YXRlIF9zdG9wcGVkID0gZmFsc2U7XG4gIHByaXZhdGUgX2Nvbm5lY3RlZCA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGluc3RhbmNlXG4gICAqIEBwYXJhbSB1cmwgVVJMXG4gICAqIEBwYXJhbSBvcHRpb25zIG9wdGlvbnNcbiAgICovXG4gIGNvbnN0cnVjdG9yKHVybDogc3RyaW5nLCBvcHRpb25zPzogQ2xpZW50U3RpY2t5U29ja2V0Lk9wdGlvbnMpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX2xhYmVsID0gYCR7b3B0aW9ucz8ubGFiZWwgfHwgJ2Nvbm5lY3Rpb24nfToke3RoaXMuX2lkfWA7XG4gICAgXG4gICAgY29uc3Qgc3RpY2t5Q29ubmVjdGlvblR0bEluTXMgPSAxMDAwICogKG9wdGlvbnM/LnN0aWNreUNvbm5lY3Rpb25UdGxJblNlY29uZHMgPz8gMTApO1xuICAgIGxldCBpbnRlcm5hbEV2ZW50cyA9IG5ldyBFdmVudEVtaXR0ZXI8U3RpY2t5U29ja2V0Q29ubmVjdGlvbi5TaGFyZWRFdmVudHM+KCk7XG4gICAgaW50ZXJuYWxFdmVudHMub25jZSgnY29ubmVjdCcsICgpID0+IHtcbiAgICAgIHRoaXMuX2Nvbm5lY3RlZCA9IHRydWU7XG4gICAgICB0aGlzLmVtaXQoJ2Nvbm5lY3QnKTtcbiAgICB9KTtcbiAgICBpbnRlcm5hbEV2ZW50cy5vbignY29ubmVjdCcsICgpID0+IGNsZWFyVGltZW91dCh0aGlzLl9zdGlja3lDb25uZWN0aW9uV2FpdFRpbWVvdXQpKTtcbiAgICBpbnRlcm5hbEV2ZW50cy5vbignZmFpbCcsIGVyciA9PiB7XG4gICAgICBpZiAob3B0aW9ucz8udXNlTmF0aXZlU29ja2V0SW9TZXJ2ZXIpIHtcbiAgICAgICAgdGhpcy5kaXNjb25uZWN0KGVycik7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICghdGhpcy5fc3RvcHBlZCkge1xuICAgICAgICB0aGlzLl9zdGlja3lDb25uZWN0aW9uV2FpdFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICB0aGlzLl9sb2dnZXIud2FybihgJHt0aGlzLl9sYWJlbH06IGZhaWxlZCB0byByZXN0b3JlIHN0aWNreSBjb25uZWN0aW9uYCk7XG4gICAgICAgICAgdGhpcy5kaXNjb25uZWN0KGVycik7XG4gICAgICAgIH0sIHN0aWNreUNvbm5lY3Rpb25UdGxJbk1zKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBcbiAgICB0aGlzLl9wb29sID0gbmV3IGxyYXAuUm9vdFBvb2woU3RpY2t5U29ja2V0Q29ubmVjdGlvbiwge1xuICAgICAgZGVwZW5kZW5jaWVzOiBbdGhpcywgaW50ZXJuYWxFdmVudHNdLFxuICAgICAgbGFiZWw6IGBjbGllbnRTdGlja3lTb2NrZXQ6JHt0aGlzLl9sYWJlbH1gLFxuICAgIH0pO1xuICAgIHRoaXMuX3Bvb2wuc2NoZWR1bGVQcm9jZXNzKCdjb25uZWN0aW9uJywge1xuICAgICAgYXJnczogW1xuICAgICAgICB1cmwsIHRoaXMuX2lkLFxuICAgICAgICB7XG4gICAgICAgICAgc3RhcnRDb3VudDogMCxcbiAgICAgICAgICBlbWl0SGlzdG9yeTogbmV3IFF1ZXVlKCksXG4gICAgICAgICAgbGFzdFNlbnRJbmRleDogLTEsXG4gICAgICAgICAgbGFzdFJlY2VpdmVkSW5kZXg6IC0xXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBsYWJlbDogdGhpcy5fbGFiZWwsXG4gICAgICAgICAgY29ubmVjdGlvbjogb3B0aW9ucz8uY29ubmVjdGlvbixcbiAgICAgICAgICB1c2VOYXRpdmVTb2NrZXRJb1NlcnZlcjogb3B0aW9ucz8udXNlTmF0aXZlU29ja2V0SW9TZXJ2ZXIsXG4gICAgICAgICAgZW1pdEhpc3RvcnlUdGxJblNlY29uZHM6IG9wdGlvbnM/LmVtaXRIaXN0b3J5VHRsSW5TZWNvbmRzID8/IG1zVG9TZWNvbmRzKHN0aWNreUNvbm5lY3Rpb25UdGxJbk1zKVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgZmFpbG92ZXJUaHJvdHRsZURlbGF5OiB7XG4gICAgICAgIG1vZGU6ICdleHBvbmVudGlhbCcsXG4gICAgICAgIHJlc2V0RGVsYXlJbk1zOiAwLFxuICAgICAgICBtaW5EZWxheUluTXM6IG9wdGlvbnM/LnJlY29ubmVjdGlvbkRlbGF5SW5NcyA/PyAxMDAwLFxuICAgICAgICBtYXhEZWxheUluTXM6IG9wdGlvbnM/LnJlY29ubmVjdGlvbkRlbGF5TWF4SW5NcyA/PyAxMDAwMCxcbiAgICAgICAgcmFuZG9taXphdGlvbkZhY3Rvcjogb3B0aW9ucz8ucmVjb25uZWN0aW9uUmFuZG9taXphdGlvbkZhY3RvciA/PyAwLjVcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHNvY2tldCBJRFxuICAgKiBAcmV0dXJucyBzb2NrZXQgSURcbiAgICovXG4gIGdldCBpZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9pZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGN1cnJlbnQgbmF0aXZlIHNvY2tldFxuICAgKiBAcmV0dXJucyBzb2NrZXQuaW8gc29ja2V0XG4gICAqIEBpbnRlcm5hbCBpbnRlbmRlZCBmb3IgdGVzdHMgb25seVxuICAgKi9cbiAgZ2V0IHNvY2tldCgpOiBTb2NrZXRJT0NsaWVudC5Tb2NrZXQge1xuICAgIHJldHVybiB0aGlzLl9wb29sLmdldFByb2Nlc3MoJ2Nvbm5lY3Rpb24nKT8uc29ja2V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCB0cmFuc3BvcnQgbmFtZSwgdXNpbmcgc29ja2V0LmlvIGludGVybmFsc1xuICAgKiBAcmV0dXJucyB0cmFuc3BvcnQgbmFtZSwgZS5nLiBcIndlYnNvY2tldFwiXG4gICAqIEBpbnRlcm5hbCBpbnRlbmRlZCBmb3IgdGVzdHMgb25seVxuICAgKi9cbiAgZ2V0IHRyYW5zcG9ydE5hbWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fcG9vbC5nZXRQcm9jZXNzKCdjb25uZWN0aW9uJyk/LnRyYW5zcG9ydE5hbWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIGZpcnN0IHByZXNlbnQgcGFja2V0IGluZGV4IGluIGxhc3QgZW1pdCBoaXN0b3J5XG4gICAqIEByZXR1cm5zIGZpcnN0IGhpc3RvcnkgaW5kZXhcbiAgICogQGludGVybmFsIGludGVuZGVkIGZvciB0ZXN0cyBvbmx5XG4gICAqL1xuICBnZXQgZmlyc3RIaXN0b3J5SW5kZXgoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fcG9vbC5nZXRQcm9jZXNzKCdjb25uZWN0aW9uJyk/LmZpcnN0SGlzdG9yeUluZGV4O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgd2hldGhlciBzb2NrZXQgY29ubmVjdGVkXG4gICAqIEByZXR1cm5zIGlzIGNvbm5lY3RlZFxuICAgKi9cbiAgZ2V0IGNvbm5lY3RlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fY29ubmVjdGVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEBpbmhlcml0ZG9jXG4gICAqIEByZW1hcmtzIFNvY2tldCBldmVudHMgYENsaWVudFN0aWNreVNvY2tldHMuSU5URVJOQUxfRVZFTlRTYCBjYW5ub3QgYmUgc3Vic2NyaWJlZCB0b1xuICAgKiBAdGhyb3dzIGBWYWxpZGF0aW9uRXJyb3JgIGlmIGF0dGVtcHRpbmcgdG8gc3Vic2NyaWJlIHRvIGFuIGludGVybmFsIGV2ZW50XG4gICAqL1xuICBvbjxVIGV4dGVuZHMgRXZlbnRFbWl0dGVyLkV2ZW50PENsaWVudFN0aWNreVNvY2tldC5FdmVudHM+PihldmVudDogVSwgY2FsbGJhY2s6IENsaWVudFN0aWNreVNvY2tldC5FdmVudHNbVV0pIHtcbiAgICBpZiAoQ2xpZW50U3RpY2t5U29ja2V0LklOVEVSTkFMX0VWRU5UUy5pbmNsdWRlcyhldmVudCkpIHtcbiAgICAgIHRocm93IG5ldyBlcnJvcnMuVmFsaWRhdGlvbkVycm9yKCdDYW5ub3Qgc3Vic2NyaWJlIHRvIGFuIGludGVybmFsIGV2ZW50Jyk7XG4gICAgfVxuICAgIHN1cGVyLm9uKGV2ZW50LCBjYWxsYmFjayk7XG4gIH1cblxuICAvKipcbiAgICogRW1pdHMgYSBkYXRhIGV2ZW50LiBBbGwgZXZlbnRzIGFyZSBidWZmZXJlZCBpZiBubyBjb25uZWN0aW9uXG4gICAqIEBwYXJhbSBldmVudCBUaGUgZXZlbnQgdGhhdCB3ZSdyZSBlbWl0dGluZ1xuICAgKiBAcGFyYW0gYXJncyBPcHRpb25hbCBhcmd1bWVudHMgdG8gc2VuZCB3aXRoIHRoZSBldmVudFxuICAgKi9cbiAgc2VuZChldmVudDogc3RyaW5nLCAuLi5hcmdzOiBhbnlbXSkge1xuICAgIHRoaXMuX3Bvb2wuZ2V0UHJvY2VzcygnY29ubmVjdGlvbicpPy5zZW5kKGV2ZW50LCAuLi5hcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNjb25uZWN0cyBzb2NrZXRcbiAgICogQHBhcmFtIGVyciBlcnJvciBpZiBkaXNjb25uZWN0aW5nIHdpdGggZXJyb3JcbiAgICogQHJldHVybnMgcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBkaXNjb25uZWN0ZWRcbiAgICovXG4gIGFzeW5jIGRpc2Nvbm5lY3QoZXJyPzogRXJyb3IpIHtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5fc3RpY2t5Q29ubmVjdGlvbldhaXRUaW1lb3V0KTtcbiAgICBsZXQgd2FzU3RvcHBlZCA9IHRoaXMuX3N0b3BwZWQ7XG4gICAgdGhpcy5fc3RvcHBlZCA9IHRydWU7XG4gICAgYXdhaXQgdGhpcy5fcG9vbC5zdG9wKCk7XG4gICAgaWYgKCF3YXNTdG9wcGVkKSB7XG4gICAgICB0aGlzLl9jb25uZWN0ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuZW1pdCgnZGlzY29ubmVjdCcsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlc3Ryb3lzIHVuZGVybHlpbmcgc29ja2V0LCB1c2luZyBzb2NrZXQuaW8gaW50ZXJuYWxzLiBUaGUgc29ja2V0IG11c3QgaGF2ZSBgd2Vic29ja2V0YCB0cmFuc3BvcnRcbiAgICogQHBhcmFtIGVyciBvcHRpb25hbCBlcnJvclxuICAgKiBAaW50ZXJuYWwgaW50ZW5kZWQgZm9yIHRlc3RzIG9ubHksIGUuZy4gdG8gdGVzdCBjb25uZWN0aW9uIGxvc3NcbiAgICovXG4gIGRlc3Ryb3lJbnRlcm5hbFNvY2tldChlcnI/OiBFcnJvcikge1xuICAgIGRlc3Ryb3lJbnRlcm5hbENsaWVudFNvY2tldCh0aGlzLl9wb29sLmdldFByb2Nlc3MoJ2Nvbm5lY3Rpb24nKS5zb2NrZXQsIGVycik7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBleHBpcmVkIGVtaXQgaGlzdG9yeVxuICAgKiBAaW50ZXJuYWwgaW50ZW5kZWQgZm9yIHRlc3RzIG9ubHlcbiAgICovXG4gIHJlbW92ZUV4cGlyZWRFbWl0SGlzdG9yeSgpIHtcbiAgICB0aGlzLl9wb29sLmdldFByb2Nlc3MoJ2Nvbm5lY3Rpb24nKT8ucmVtb3ZlRXhwaXJlZEVtaXRIaXN0b3J5KCk7XG4gIH1cbn1cblxubmFtZXNwYWNlIENsaWVudFN0aWNreVNvY2tldCB7XG5cbiAgLyoqIENvbnN0cnVjdGluZyBvcHRpb25zICovXG4gIGV4cG9ydCB0eXBlIE9wdGlvbnMgPSBQaWNrPFN0aWNreVNvY2tldENvbm5lY3Rpb24uT3B0aW9ucywgJ2Nvbm5lY3Rpb24nIHwgJ2xhYmVsJyB8ICd1c2VOYXRpdmVTb2NrZXRJb1NlcnZlcic+ICYge1xuICAgIC8qKlxuICAgICAqIEVtaXQgaGlzdG9yeSBidWZmZXIgVFRMLiBEZWZhdWx0cyB0byBgc3RpY2t5Q29ubmVjdGlvblR0bEluU2Vjb25kc2AgKyBgcmVjb25uZWN0VGhyb3R0bGVEZWxheUluTXNgXG4gICAgICogKGNvbnZlcnRlZCB0byBzZWNvbmRzKVxuICAgICAqL1xuICAgIGVtaXRIaXN0b3J5VHRsSW5TZWNvbmRzPzogbnVtYmVyO1xuICAgIC8qKiBUaW1lb3V0IHdpdGhpbiBvZiB3aGljaCBhIGNvbm5lY3Rpb24gY2FuIGJlIHJlc3RvcmVkIGFzIHByZXZpb3VzIG9uZS4gRGVmYXVsdHMgdG8gYDEwYCAqL1xuICAgIHN0aWNreUNvbm5lY3Rpb25UdGxJblNlY29uZHM/OiBudW1iZXI7XG4gICAgLyoqIFJlY29ubmVjdGlvbiBkZWxheS4gVGhlIGRlbGF5IHdpbGwgYmUgaW5jcmVhc2VkIGJ5IDJ4IGVhY2ggZmFpbGVkIGNvbm5lY3Rpb24gYXR0ZW1wdC4gRGVmYXVsdHMgdG8gYDEwMDBgICovXG4gICAgcmVjb25uZWN0aW9uRGVsYXlJbk1zPzogbnVtYmVyO1xuICAgIC8qKiBNYXggcmVjb25uZWN0aW9uIGRlbGF5LiBEZWZhdWx0cyB0byBgMTAwMDBgICovXG4gICAgcmVjb25uZWN0aW9uRGVsYXlNYXhJbk1zPzogbnVtYmVyO1xuICAgIC8qKiBSZWNvbm5lY3Rpb24gZGVsYXkgcmFuZG9taXphdGlvbiBmYWN0b3IgaW4gcmFuZ2UgWzA7IDFdLiBEZWZhdWx0cyB0byBgMC41YCAqL1xuICAgIHJlY29ubmVjdGlvblJhbmRvbWl6YXRpb25GYWN0b3I/OiBudW1iZXI7XG4gIH07XG5cbiAgLyoqIEV2ZW50IGxpc3RlbmVycyAqL1xuICBleHBvcnQgdHlwZSBFdmVudHMgPSB7XG4gICAgLyoqIEZpcmVkIG9ubHkgb25jZSB1cG9uIGZpcnN0IGNvbm5lY3Rpb24gKi9cbiAgICBjb25uZWN0OiAoKSA9PiB2b2lkO1xuICAgIC8qKiBGaXJlZCBvbmx5IG9uY2UgdXBvbiB0aGUgbGFzdCBkaXNjb25uZWN0aW9uLiBXaWxsIGJlIGZpcmVkIGFueXdheSwgZXZlbiBpZiB3YXMgbmV2ZXIgY29ubmVjdGVkICovXG4gICAgZGlzY29ubmVjdDogKGVycj86IEVycm9yKSA9PiB2b2lkO1xuICAgIC8qKiBDdXN0b20gc3Vic2NyaXB0aW9uIGV2ZW50cyAqL1xuICAgIFtldmVudDogc3RyaW5nXTogKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnk7XG4gIH07XG5cbiAgLyoqIENvbm5lY3Rpb24gZXZlbnRzICovXG4gIGV4cG9ydCBjb25zdCBDT05ORUNUSU9OX0VWRU5UUyA9IFN0aWNreVNvY2tldENvbm5lY3Rpb24uQ09OTkVDVElPTl9FVkVOVFM7XG4gIC8qKiBJbnRlcm5hbCBldmVudHMgKi9cbiAgZXhwb3J0IGNvbnN0IElOVEVSTkFMX0VWRU5UUyA9IFN0aWNreVNvY2tldENvbm5lY3Rpb24uSU5URVJOQUxfRVZFTlRTO1xufVxuXG5leHBvcnQgZGVmYXVsdCBDbGllbnRTdGlja3lTb2NrZXQ7XG4iXSwibmFtZXMiOlsicmFuZG9tc3RyaW5nIiwibHJhcCIsIlN0aWNreVNvY2tldENvbm5lY3Rpb24iLCJlcnJvcnMiLCJkZXN0cm95SW50ZXJuYWxDbGllbnRTb2NrZXQiLCJtc1RvU2Vjb25kcyIsIkV2ZW50RW1pdHRlciIsIkxvZ2dlck1hbmFnZXIiLCJRdWV1ZSIsIkNsaWVudFN0aWNreVNvY2tldCIsImlkIiwiX2lkIiwic29ja2V0IiwiX3Bvb2wiLCJnZXRQcm9jZXNzIiwidHJhbnNwb3J0TmFtZSIsImZpcnN0SGlzdG9yeUluZGV4IiwiY29ubmVjdGVkIiwiX2Nvbm5lY3RlZCIsIm9uIiwiZXZlbnQiLCJjYWxsYmFjayIsIklOVEVSTkFMX0VWRU5UUyIsImluY2x1ZGVzIiwiVmFsaWRhdGlvbkVycm9yIiwic2VuZCIsImFyZ3MiLCJkaXNjb25uZWN0IiwiZXJyIiwiY2xlYXJUaW1lb3V0IiwiX3N0aWNreUNvbm5lY3Rpb25XYWl0VGltZW91dCIsIndhc1N0b3BwZWQiLCJfc3RvcHBlZCIsInN0b3AiLCJlbWl0IiwiZGVzdHJveUludGVybmFsU29ja2V0IiwicmVtb3ZlRXhwaXJlZEVtaXRIaXN0b3J5IiwiY29uc3RydWN0b3IiLCJ1cmwiLCJvcHRpb25zIiwiX2xvZ2dlciIsImdldExvZ2dlciIsImdlbmVyYXRlIiwiX2xhYmVsIiwibGFiZWwiLCJzdGlja3lDb25uZWN0aW9uVHRsSW5NcyIsInN0aWNreUNvbm5lY3Rpb25UdGxJblNlY29uZHMiLCJpbnRlcm5hbEV2ZW50cyIsIm9uY2UiLCJ1c2VOYXRpdmVTb2NrZXRJb1NlcnZlciIsInNldFRpbWVvdXQiLCJ3YXJuIiwiUm9vdFBvb2wiLCJkZXBlbmRlbmNpZXMiLCJzY2hlZHVsZVByb2Nlc3MiLCJzdGFydENvdW50IiwiZW1pdEhpc3RvcnkiLCJsYXN0U2VudEluZGV4IiwibGFzdFJlY2VpdmVkSW5kZXgiLCJjb25uZWN0aW9uIiwiZW1pdEhpc3RvcnlUdGxJblNlY29uZHMiLCJmYWlsb3ZlclRocm90dGxlRGVsYXkiLCJtb2RlIiwicmVzZXREZWxheUluTXMiLCJtaW5EZWxheUluTXMiLCJyZWNvbm5lY3Rpb25EZWxheUluTXMiLCJtYXhEZWxheUluTXMiLCJyZWNvbm5lY3Rpb25EZWxheU1heEluTXMiLCJyYW5kb21pemF0aW9uRmFjdG9yIiwicmVjb25uZWN0aW9uUmFuZG9taXphdGlvbkZhY3RvciIsIkNPTk5FQ1RJT05fRVZFTlRTIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPQSxrQkFBa0IsZUFBZTtBQUN4QyxZQUFZQyxVQUFVLGdDQUFnQztBQUN0RCxPQUFPQyw0QkFBNEIsMkJBQTJCO0FBQzlELFlBQVlDLFlBQVksNkJBQTZCO0FBQ3JELFNBQVFDLDJCQUEyQixRQUFPLGlCQUFpQjtBQUMzRCxTQUFRQyxXQUFXLFFBQU8sNkJBQTZCO0FBQ3ZELE9BQU9DLGtCQUFrQiwyQkFBMkI7QUFDcEQsT0FBT0MsbUJBQW1CLGVBQWU7QUFDekMsT0FBT0MsV0FBVyxvQkFBb0I7QUFFdEM7O0NBRUMsR0FDRCxJQUFBLEFBQU1DLHFCQUFOLE1BQU1BLDJCQUEyQkg7SUFxRS9COzs7R0FHQyxHQUNELElBQUlJLEtBQWE7UUFDZixPQUFPLElBQUksQ0FBQ0MsR0FBRztJQUNqQjtJQUVBOzs7O0dBSUMsR0FDRCxJQUFJQyxTQUFnQztZQUMzQjtRQUFQLFFBQU8seUJBQUEsSUFBSSxDQUFDQyxLQUFLLENBQUNDLFVBQVUsQ0FBQywyQkFBdEIsNkNBQUEsdUJBQXFDRixNQUFNO0lBQ3BEO0lBRUE7Ozs7R0FJQyxHQUNELElBQUlHLGdCQUF3QjtZQUNuQjtRQUFQLFFBQU8seUJBQUEsSUFBSSxDQUFDRixLQUFLLENBQUNDLFVBQVUsQ0FBQywyQkFBdEIsNkNBQUEsdUJBQXFDQyxhQUFhO0lBQzNEO0lBRUE7Ozs7R0FJQyxHQUNELElBQUlDLG9CQUF3QztZQUNuQztRQUFQLFFBQU8seUJBQUEsSUFBSSxDQUFDSCxLQUFLLENBQUNDLFVBQVUsQ0FBQywyQkFBdEIsNkNBQUEsdUJBQXFDRSxpQkFBaUI7SUFDL0Q7SUFFQTs7O0dBR0MsR0FDRCxJQUFJQyxZQUFxQjtRQUN2QixPQUFPLElBQUksQ0FBQ0MsVUFBVTtJQUN4QjtJQUVBOzs7O0dBSUMsR0FDREMsR0FBNERDLEtBQVEsRUFBRUMsUUFBc0MsRUFBRTtRQUM1RyxJQUFJWixtQkFBbUJhLGVBQWUsQ0FBQ0MsUUFBUSxDQUFDSCxRQUFRO1lBQ3RELE1BQU0sSUFBSWpCLE9BQU9xQixlQUFlLENBQUM7UUFDbkM7UUFDQSxLQUFLLENBQUNMLEdBQUdDLE9BQU9DO0lBQ2xCO0lBRUE7Ozs7R0FJQyxHQUNESSxLQUFLTCxLQUFhLEVBQUUsR0FBR00sSUFBVyxFQUFFO1lBQ2xDO1NBQUEseUJBQUEsSUFBSSxDQUFDYixLQUFLLENBQUNDLFVBQVUsQ0FBQywyQkFBdEIsNkNBQUEsdUJBQXFDVyxJQUFJLENBQUNMLFVBQVVNO0lBQ3REO0lBRUE7Ozs7R0FJQyxHQUNELEFBQU1DLFdBQVdDLEdBQVc7O2VBQTVCLG9CQUFBO1lBQ0VDLGFBQWEsTUFBS0MsNEJBQTRCO1lBQzlDLElBQUlDLGFBQWEsTUFBS0MsUUFBUTtZQUM5QixNQUFLQSxRQUFRLEdBQUc7WUFDaEIsTUFBTSxNQUFLbkIsS0FBSyxDQUFDb0IsSUFBSTtZQUNyQixJQUFJLENBQUNGLFlBQVk7Z0JBQ2YsTUFBS2IsVUFBVSxHQUFHO2dCQUNsQixNQUFLZ0IsSUFBSSxDQUFDLGNBQWNOO1lBQzFCO1FBQ0Y7O0lBRUE7Ozs7R0FJQyxHQUNETyxzQkFBc0JQLEdBQVcsRUFBRTtRQUNqQ3hCLDRCQUE0QixJQUFJLENBQUNTLEtBQUssQ0FBQ0MsVUFBVSxDQUFDLGNBQWNGLE1BQU0sRUFBRWdCO0lBQzFFO0lBRUE7OztHQUdDLEdBQ0RRLDJCQUEyQjtZQUN6QjtTQUFBLHlCQUFBLElBQUksQ0FBQ3ZCLEtBQUssQ0FBQ0MsVUFBVSxDQUFDLDJCQUF0Qiw2Q0FBQSx1QkFBcUNzQix3QkFBd0I7SUFDL0Q7SUExSkE7Ozs7R0FJQyxHQUNEQyxZQUFZQyxHQUFXLEVBQUVDLE9BQW9DLENBQUU7UUFDN0QsS0FBSztRQWRQLHVCQUFRQyxXQUFVakMsY0FBY2tDLFNBQVMsQ0FBQztRQUMxQyx1QkFBUTVCLFNBQVIsS0FBQTtRQUNBLHVCQUFRaUIsZ0NBQVIsS0FBQTtRQUNBLHVCQUFRbkIsT0FBTVgsYUFBYTBDLFFBQVEsQ0FBQztRQUNwQyx1QkFBUUMsVUFBUixLQUFBO1FBQ0EsdUJBQVFYLFlBQVc7UUFDbkIsdUJBQVFkLGNBQWE7UUFTbkIsSUFBSSxDQUFDeUIsTUFBTSxHQUFHLENBQUMsRUFBRUosQ0FBQUEsb0JBQUFBLDhCQUFBQSxRQUFTSyxLQUFLLEtBQUksYUFBYSxDQUFDLEVBQUUsSUFBSSxDQUFDakMsR0FBRyxDQUFDLENBQUM7WUFFckI0QjtRQUF4QyxNQUFNTSwwQkFBMEIsT0FBUU4sQ0FBQUEsQ0FBQUEsd0NBQUFBLG9CQUFBQSw4QkFBQUEsUUFBU08sNEJBQTRCLGNBQXJDUCxtREFBQUEsd0NBQXlDLEVBQUM7UUFDbEYsSUFBSVEsaUJBQWlCLElBQUl6QztRQUN6QnlDLGVBQWVDLElBQUksQ0FBQyxXQUFXO1lBQzdCLElBQUksQ0FBQzlCLFVBQVUsR0FBRztZQUNsQixJQUFJLENBQUNnQixJQUFJLENBQUM7UUFDWjtRQUNBYSxlQUFlNUIsRUFBRSxDQUFDLFdBQVcsSUFBTVUsYUFBYSxJQUFJLENBQUNDLDRCQUE0QjtRQUNqRmlCLGVBQWU1QixFQUFFLENBQUMsUUFBUVMsQ0FBQUE7WUFDeEIsSUFBSVcsb0JBQUFBLDhCQUFBQSxRQUFTVSx1QkFBdUIsRUFBRTtnQkFDcEMsSUFBSSxDQUFDdEIsVUFBVSxDQUFDQztnQkFDaEI7WUFDRjtZQUNBLElBQUksQ0FBQyxJQUFJLENBQUNJLFFBQVEsRUFBRTtnQkFDbEIsSUFBSSxDQUFDRiw0QkFBNEIsR0FBR29CLFdBQVc7b0JBQzdDLElBQUksQ0FBQ1YsT0FBTyxDQUFDVyxJQUFJLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQ1IsTUFBTSxDQUFDLHFDQUFxQyxDQUFDO29CQUN2RSxJQUFJLENBQUNoQixVQUFVLENBQUNDO2dCQUNsQixHQUFHaUI7WUFDTDtRQUNGO1FBRUEsSUFBSSxDQUFDaEMsS0FBSyxHQUFHLElBQUlaLEtBQUttRCxRQUFRLENBQUNsRCx3QkFBd0I7WUFDckRtRCxjQUFjO2dCQUFDLElBQUk7Z0JBQUVOO2FBQWU7WUFDcENILE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLENBQUNELE1BQU0sQ0FBQyxDQUFDO1FBQzVDO1lBYytCSixrQ0FNYkEsZ0NBQ0FBLG1DQUNPQTtRQXJCekIsSUFBSSxDQUFDMUIsS0FBSyxDQUFDeUMsZUFBZSxDQUFDLGNBQWM7WUFDdkM1QixNQUFNO2dCQUNKWTtnQkFBSyxJQUFJLENBQUMzQixHQUFHO2dCQUNiO29CQUNFNEMsWUFBWTtvQkFDWkMsYUFBYSxJQUFJaEQ7b0JBQ2pCaUQsZUFBZSxDQUFDO29CQUNoQkMsbUJBQW1CLENBQUM7Z0JBQ3RCO2dCQUNBO29CQUNFZCxPQUFPLElBQUksQ0FBQ0QsTUFBTTtvQkFDbEJnQixVQUFVLEVBQUVwQixvQkFBQUEsOEJBQUFBLFFBQVNvQixVQUFVO29CQUMvQlYsdUJBQXVCLEVBQUVWLG9CQUFBQSw4QkFBQUEsUUFBU1UsdUJBQXVCO29CQUN6RFcseUJBQXlCckIsQ0FBQUEsbUNBQUFBLG9CQUFBQSw4QkFBQUEsUUFBU3FCLHVCQUF1QixjQUFoQ3JCLDhDQUFBQSxtQ0FBb0NsQyxZQUFZd0M7Z0JBQzNFO2FBQ0Q7WUFDRGdCLHVCQUF1QjtnQkFDckJDLE1BQU07Z0JBQ05DLGdCQUFnQjtnQkFDaEJDLGNBQWN6QixDQUFBQSxpQ0FBQUEsb0JBQUFBLDhCQUFBQSxRQUFTMEIscUJBQXFCLGNBQTlCMUIsNENBQUFBLGlDQUFrQztnQkFDaEQyQixjQUFjM0IsQ0FBQUEsb0NBQUFBLG9CQUFBQSw4QkFBQUEsUUFBUzRCLHdCQUF3QixjQUFqQzVCLCtDQUFBQSxvQ0FBcUM7Z0JBQ25ENkIscUJBQXFCN0IsQ0FBQUEsMkNBQUFBLG9CQUFBQSw4QkFBQUEsUUFBUzhCLCtCQUErQixjQUF4QzlCLHNEQUFBQSwyQ0FBNEM7WUFDbkU7UUFDRjtJQUNGO0FBa0dGO1VBRVU5QjtJQTZCUixzQkFBc0Isc0JBQ1Q2RCxvQkFBb0JwRSx1QkFBdUJvRSxpQkFBaUI7SUFDekUsb0JBQW9CLHNCQUNQaEQsa0JBQWtCcEIsdUJBQXVCb0IsZUFBZTtBQUN2RSxHQWpDVWIsdUJBQUFBO0FBbUNWLGVBQWVBLG1CQUFtQiJ9