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)
366 lines (365 loc) • 44.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _longrunningasyncprocess = /*#__PURE__*/ _interop_require_wildcard(require("../long-running-async-process"));
const _socketioclient = /*#__PURE__*/ _interop_require_default(require("socket.io-client"));
const _socketiowildcard = /*#__PURE__*/ _interop_require_default(require("../socket.io-wildcard"));
const _commontypes = require("./common.types");
const _commonutils = require("./common.utils");
const _logger = /*#__PURE__*/ _interop_require_default(require("../../logger"));
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* A socket connection
*/ let StickySocketConnection = class StickySocketConnection extends _longrunningasyncprocess.RootProcess {
/**
* Returns native socket
* @returns socket.io socket
*/ get socket() {
return this._socket;
}
/**
* Returns current transport name, using socket.io internals
* @returns transport name, e.g. "websocket"
*/ get transportName() {
return (0, _commonutils.getClientSocketIoTransportName)(this._socket);
}
/**
* Returns first present packet index in last emit history
* @returns first history index
* @internal intended for tests only
*/ get firstHistoryIndex() {
var _this__sharedState_emitHistory_front;
return (_this__sharedState_emitHistory_front = this._sharedState.emitHistory.front()) === null || _this__sharedState_emitHistory_front === void 0 ? void 0 : _this__sharedState_emitHistory_front.index;
}
/**
* @inheritdoc
* @param client parent client
* @param internalEvents internal event emitter
*/ inject(client, internalEvents) {
this._client = client;
this._internalEvents = internalEvents;
}
/**
* @inheritdoc
* @param url url to connect to
* @param sessionId session ID
* @param sharedState shared state
* @param options additiona options
*/ initialize(url, sessionId, sharedState, options) {
var _options_connection;
this._options = options;
this._label = (options === null || options === void 0 ? void 0 : options.label) || "default";
this._sharedState = sharedState;
this._sharedState.startCount++;
let query = {
...options === null || options === void 0 ? void 0 : (_options_connection = options.connection) === null || _options_connection === void 0 ? void 0 : _options_connection.query,
stickySocketConnectionId: sessionId
};
if (sharedState.startCount > 1) {
var _this__sharedState_emitHistory_front;
let request = {
lastReceivedIndex: sharedState.lastReceivedIndex,
lastSentIndex: sharedState.lastSentIndex,
firstHistoryIndex: (_this__sharedState_emitHistory_front = this._sharedState.emitHistory.front()) === null || _this__sharedState_emitHistory_front === void 0 ? void 0 : _this__sharedState_emitHistory_front.index,
sessionId
};
this._logger.debug(`${this._label}: restoring session`, JSON.stringify(request));
query.restoreStickyConnection = encodeURIComponent(JSON.stringify(request));
}
this._socket = (0, _socketioclient.default)(url, {
...options === null || options === void 0 ? void 0 : options.connection,
reconnection: false,
autoConnect: false,
query
});
(0, _socketiowildcard.default)(_socketioclient.default.Manager)(this._socket);
this._socket.on("*", (packet)=>{
if (packet.type === _commontypes.EVENT || packet.type === _commontypes.BINARY_EVENT) {
var _this__options;
let payload = packet.data[1];
if ((_this__options = this._options) === null || _this__options === void 0 ? void 0 : _this__options.useNativeSocketIoServer) {
this._client.emit(packet.data[0], ...packet.data.slice(1));
return;
}
if ("index" in payload) {
this._logger.trace(()=>`${this._label}: received packet ` + JSON.stringify({
index: payload.index
}));
var _this__sharedState_lastReceivedIndex;
this._sharedState.lastReceivedIndex = Math.max((_this__sharedState_lastReceivedIndex = this._sharedState.lastReceivedIndex) !== null && _this__sharedState_lastReceivedIndex !== void 0 ? _this__sharedState_lastReceivedIndex : -1, payload.index);
this._client.emit(packet.data[0], ...payload.data);
}
}
});
}
/**
* Emits a data event. All events are buffered if no connection
* @param event The event that we're emitting
* @param args Optional arguments to send with the event
*/ send(event, ...args) {
var _this__options;
if ((_this__options = this._options) === null || _this__options === void 0 ? void 0 : _this__options.useNativeSocketIoServer) {
this._socket.emit(event, ...args);
return;
}
let packet = {
index: ++this._sharedState.lastSentIndex,
event,
data: args,
time: new Date()
};
this._sharedState.emitHistory.push(packet);
this._socket.emit(event, {
index: packet.index,
data: packet.data
});
}
/**
* @inheritdoc
*/ async start(stopPromise) {
try {
let connectPromise = this._connect(stopPromise);
let restorePromise = this._restoreConnectionIfNeeded(stopPromise);
let [_, restored] = await Promise.all([
connectPromise,
restorePromise
]);
if (restored) {
this._logger.info(`${this._label}: restored connection session`);
}
} catch (err) {
this._logger.warn(`${this._label}: failed to connect`, err);
if (this._sharedState.startCount === 1 || err instanceof RestoreRejectError) {
this._client.disconnect(err);
}
throw new _longrunningasyncprocess.ControlSignal({
action: "failover",
severity: "info"
});
}
}
_connect(stopPromise) {
this._socket.connect();
return new Promise((resolve, reject)=>{
stopPromise.then(()=>reject(new Error("Stopped during connection")));
this._setSocketStageListener("connect", ()=>{
// Emitting connect immediately to guarantee no data events will be received until connect event emitted
this._logger.debug(`${this._label}: internal socket connected`);
this._internalEvents.emit("connect");
resolve();
});
this._setSocketStageListener("disconnect", (reason)=>{
this._disconnectReason = reason;
reject(new Error(`Disconnected when connecting due to ${reason}`));
});
this._setSocketStageListener("error", (err)=>reject(err));
this._setSocketStageListener("connect_error", (err)=>reject(err));
this._setSocketStageListener("connect_timeout", (err)=>reject(err));
});
}
async _restoreConnectionIfNeeded(stopPromise) {
if (this._sharedState.startCount === 1) {
return false;
}
let sendSinceIndex = await new Promise((resolve, reject)=>{
stopPromise.then(()=>reject(new Error("Stopped during restoring connection")));
this._setSocketStageListener(_commontypes.RESTORE_CONNECTION_EVENT, (event)=>{
event.restored ? resolve(event.sendSinceIndex) : reject(new RestoreRejectError("Cannot restore connection session"));
});
this._setSocketStageListener("disconnect", (reason)=>{
reject(new Error(`Disconnected when restoring connection due to ${reason}`));
});
this._setSocketStageListener("error", (err)=>reject(err));
this._setSocketStageListener("connect_error", (err)=>reject(err));
this._setSocketStageListener("connect_timeout", (err)=>reject(err));
});
this._logger.debug(`${this._label}: sending history since ${sendSinceIndex} packet index`);
(0, _commonutils.sendHistory)(this._socket, this._sharedState.emitHistory, sendSinceIndex);
return true;
}
/**
* @inheritdoc
*/ async run(stopPromise) {
var _this__options;
var _this__options_emitHistoryTtlInSeconds;
const historyBufferTtlInMs = 1000 * ((_this__options_emitHistoryTtlInSeconds = (_this__options = this._options) === null || _this__options === void 0 ? void 0 : _this__options.emitHistoryTtlInSeconds) !== null && _this__options_emitHistoryTtlInSeconds !== void 0 ? _this__options_emitHistoryTtlInSeconds : 10);
let clearOldHistoryInterval = setInterval(()=>this.removeExpiredEmitHistory(), historyBufferTtlInMs);
try {
if (this._disconnectReason) {
if (!this._tryDisconnectClientGracefully(this._disconnectReason)) {
throw new Error(`Disconnected due to ${this._disconnectReason}`);
}
return;
}
this._removePrevStageListeners();
await Promise.race([
stopPromise,
new Promise((resolve, reject)=>{
this._setSocketStageListener("disconnect", (reason)=>{
if (!this._tryDisconnectClientGracefully(reason)) {
reject(new Error(`Disconnected due to ${reason}`));
}
});
this._setSocketStageListener("error", reject);
})
]);
} catch (err) {
this._logger.warn(`${this._label}: lost connection`, err);
this._internalEvents.emit("fail", err);
throw new _longrunningasyncprocess.ControlSignal({
action: "failover",
severity: "info"
});
} finally{
this._removePrevStageListeners();
clearInterval(clearOldHistoryInterval);
}
}
/**
* Removes expired emit history
*/ removeExpiredEmitHistory() {
var _this__options;
var _this__options_emitHistoryTtlInSeconds;
const historyBufferTtlInMs = 1000 * ((_this__options_emitHistoryTtlInSeconds = (_this__options = this._options) === null || _this__options === void 0 ? void 0 : _this__options.emitHistoryTtlInSeconds) !== null && _this__options_emitHistoryTtlInSeconds !== void 0 ? _this__options_emitHistoryTtlInSeconds : 10);
while(this._sharedState.emitHistory.length){
if (Date.now() - this._sharedState.emitHistory.front().time.getTime() > historyBufferTtlInMs) {
this._sharedState.emitHistory.shift();
} else {
break;
}
}
}
_tryDisconnectClientGracefully(reason) {
if (reason === "io client disconnect" || reason === "io server disconnect") {
this._logger.info(`${this._label}: disconnecting client due to ${reason}`);
this._client.disconnect();
return true;
}
return false;
}
/**
* @inheritdoc
*/ async stop() {
this._socket.disconnect();
}
_setSocketStageListener(event, listener) {
var _this__prevStageListeners, _event;
(_this__prevStageListeners = this._prevStageListeners)[_event = event] || (_this__prevStageListeners[_event] = new Set());
this._prevStageListeners[event].add(listener);
this._socket.on(event, listener);
return listener;
}
_removePrevStageListeners() {
for (let [event, listeners] of Object.entries(this._prevStageListeners)){
for (let listener of listeners){
this._socket.off(event, listener);
}
}
}
constructor(...args){
super(...args);
_define_property(this, "_options", void 0);
_define_property(this, "_socket", void 0);
_define_property(this, "_client", void 0);
_define_property(this, "_sharedState", void 0);
_define_property(this, "_internalEvents", void 0);
_define_property(this, "_disconnectReason", void 0);
_define_property(this, "_logger", _logger.default.getLogger(StickySocketConnection.name));
_define_property(this, "_prevStageListeners", {});
_define_property(this, "_label", void 0);
}
};
(function(StickySocketConnection) {
/** Connection events */ StickySocketConnection.CONNECTION_EVENTS = [
"connect",
"disconnect"
];
/** Sticky connection protocol events */ StickySocketConnection.PROTOCOL_EVENTS = [
_commontypes.RESTORE_CONNECTION_EVENT
];
/** Internal events */ StickySocketConnection.INTERNAL_EVENTS = [
"error",
"connect_error",
"connect_timeout",
"reconnect",
"reconnect_attempt",
"reconnecting",
"reconnect_error",
"reconnect_failed",
"ping",
"pong",
...StickySocketConnection.PROTOCOL_EVENTS
];
})(StickySocketConnection || (StickySocketConnection = {}));
const _default = StickySocketConnection;
/**
* Error, meaning that the server rejected the restore request. E.g. server may have already
* removed old emit history, required by the client, so the restoring cannot be done
*/ let RestoreRejectError = class RestoreRejectError extends Error {
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBscmFwIGZyb20gJy4uL2xvbmctcnVubmluZy1hc3luYy1wcm9jZXNzJztcbmltcG9ydCBpb0NsaWVudCBmcm9tICdzb2NrZXQuaW8tY2xpZW50JztcbmltcG9ydCBDbGllbnRTdGlja3lTb2NrZXQgZnJvbSAnLi9jbGllbnRTdGlja3lTb2NrZXQnO1xuaW1wb3J0IHNvY2tldFdpbGRjYXJkIGZyb20gJy4uL3NvY2tldC5pby13aWxkY2FyZCc7XG5pbXBvcnQge1xuICBCSU5BUllfRVZFTlQsXG4gIENsaWVudFNvY2tldERpc2Nvbm5lY3RSZWFzb24sXG4gIEVWRU5ULFxuICBFbWl0SGlzdG9yeVBhY2tldCwgRW1pdFBhY2tldCwgUkVTVE9SRV9DT05ORUNUSU9OX0VWRU5ULCBSZXN0b3JlQ29ubmVjdGlvblJlcXVlc3QsIFJlc3RvcmVDb25uZWN0aW9uUmVzcG9uc2UsXG4gIFNvY2tldE9wdGlvbnNcbn0gZnJvbSAnLi9jb21tb24udHlwZXMnO1xuaW1wb3J0IHtnZXRDbGllbnRTb2NrZXRJb1RyYW5zcG9ydE5hbWUsIHNlbmRIaXN0b3J5fSBmcm9tICcuL2NvbW1vbi51dGlscyc7XG5pbXBvcnQgRXZlbnRFbWl0dGVyIGZyb20gJy4uLy4uL3Rvb2xzL2V2ZW50RW1pdHRlcic7XG5pbXBvcnQgTG9nZ2VyTWFuYWdlciBmcm9tICcuLi8uLi9sb2dnZXInO1xuaW1wb3J0IFF1ZXVlIGZyb20gJy4uLy4uL3Rvb2xzL3F1ZXVlJztcblxuLyoqXG4gKiBBIHNvY2tldCBjb25uZWN0aW9uXG4gKi9cbmNsYXNzIFN0aWNreVNvY2tldENvbm5lY3Rpb24gZXh0ZW5kcyBscmFwLlJvb3RQcm9jZXNzIHtcbiAgXG4gIHByaXZhdGUgX29wdGlvbnM/OiBTdGlja3lTb2NrZXRDb25uZWN0aW9uLk9wdGlvbnM7XG4gIHByaXZhdGUgX3NvY2tldDogU29ja2V0SU9DbGllbnQuU29ja2V0O1xuICBwcml2YXRlIF9jbGllbnQ6IENsaWVudFN0aWNreVNvY2tldDtcbiAgcHJpdmF0ZSBfc2hhcmVkU3RhdGU6IFN0aWNreVNvY2tldENvbm5lY3Rpb24uU2hhcmVkU3RhdGU7XG4gIHByaXZhdGUgX2ludGVybmFsRXZlbnRzOiBFdmVudEVtaXR0ZXI8U3RpY2t5U29ja2V0Q29ubmVjdGlvbi5TaGFyZWRFdmVudHM+O1xuICBwcml2YXRlIF9kaXNjb25uZWN0UmVhc29uPzogQ2xpZW50U29ja2V0RGlzY29ubmVjdFJlYXNvbjtcbiAgcHJpdmF0ZSBfbG9nZ2VyID0gTG9nZ2VyTWFuYWdlci5nZXRMb2dnZXIoU3RpY2t5U29ja2V0Q29ubmVjdGlvbi5uYW1lKTtcbiAgcHJpdmF0ZSBfcHJldlN0YWdlTGlzdGVuZXJzOiB7W2V2ZW50OiBzdHJpbmddOiBTZXQ8KC4uLmFyZ3M6IGFueVtdKSA9PiB2b2lkPn0gPSB7fTtcbiAgcHJpdmF0ZSBfbGFiZWw6IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyBuYXRpdmUgc29ja2V0XG4gICAqIEByZXR1cm5zIHNvY2tldC5pbyBzb2NrZXRcbiAgICovXG4gIGdldCBzb2NrZXQoKTogU29ja2V0SU9DbGllbnQuU29ja2V0IHtcbiAgICByZXR1cm4gdGhpcy5fc29ja2V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCB0cmFuc3BvcnQgbmFtZSwgdXNpbmcgc29ja2V0LmlvIGludGVybmFsc1xuICAgKiBAcmV0dXJucyB0cmFuc3BvcnQgbmFtZSwgZS5nLiBcIndlYnNvY2tldFwiXG4gICAqL1xuICBnZXQgdHJhbnNwb3J0TmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiBnZXRDbGllbnRTb2NrZXRJb1RyYW5zcG9ydE5hbWUodGhpcy5fc29ja2V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGZpcnN0IHByZXNlbnQgcGFja2V0IGluZGV4IGluIGxhc3QgZW1pdCBoaXN0b3J5XG4gICAqIEByZXR1cm5zIGZpcnN0IGhpc3RvcnkgaW5kZXhcbiAgICogQGludGVybmFsIGludGVuZGVkIGZvciB0ZXN0cyBvbmx5XG4gICAqL1xuICBnZXQgZmlyc3RIaXN0b3J5SW5kZXgoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fc2hhcmVkU3RhdGUuZW1pdEhpc3RvcnkuZnJvbnQoKT8uaW5kZXg7XG4gIH1cblxuICAvKipcbiAgICogQGluaGVyaXRkb2NcbiAgICogQHBhcmFtIGNsaWVudCBwYXJlbnQgY2xpZW50XG4gICAqIEBwYXJhbSBpbnRlcm5hbEV2ZW50cyBpbnRlcm5hbCBldmVudCBlbWl0dGVyXG4gICAqL1xuICBpbmplY3QoY2xpZW50OiBDbGllbnRTdGlja3lTb2NrZXQsIGludGVybmFsRXZlbnRzOiBFdmVudEVtaXR0ZXI8U3RpY2t5U29ja2V0Q29ubmVjdGlvbi5TaGFyZWRFdmVudHM+KTogdm9pZCB7XG4gICAgdGhpcy5fY2xpZW50ID0gY2xpZW50O1xuICAgIHRoaXMuX2ludGVybmFsRXZlbnRzID0gaW50ZXJuYWxFdmVudHM7XG4gIH1cblxuICAvKipcbiAgICogQGluaGVyaXRkb2NcbiAgICogQHBhcmFtIHVybCB1cmwgdG8gY29ubmVjdCB0b1xuICAgKiBAcGFyYW0gc2Vzc2lvbklkIHNlc3Npb24gSURcbiAgICogQHBhcmFtIHNoYXJlZFN0YXRlIHNoYXJlZCBzdGF0ZVxuICAgKiBAcGFyYW0gb3B0aW9ucyBhZGRpdGlvbmEgb3B0aW9uc1xuICAgKi9cbiAgaW5pdGlhbGl6ZShcbiAgICB1cmw6IHN0cmluZywgc2Vzc2lvbklkOiBzdHJpbmcsIHNoYXJlZFN0YXRlOiBTdGlja3lTb2NrZXRDb25uZWN0aW9uLlNoYXJlZFN0YXRlLFxuICAgIG9wdGlvbnM/OiBTdGlja3lTb2NrZXRDb25uZWN0aW9uLk9wdGlvbnNcbiAgKSB7XG4gICAgdGhpcy5fb3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5fbGFiZWwgPSBvcHRpb25zPy5sYWJlbCB8fCAnZGVmYXVsdCc7XG4gICAgdGhpcy5fc2hhcmVkU3RhdGUgPSBzaGFyZWRTdGF0ZTtcbiAgICB0aGlzLl9zaGFyZWRTdGF0ZS5zdGFydENvdW50Kys7XG4gICAgbGV0IHF1ZXJ5ID0ge1xuICAgICAgLi4ub3B0aW9ucz8uY29ubmVjdGlvbj8ucXVlcnksXG4gICAgICBzdGlja3lTb2NrZXRDb25uZWN0aW9uSWQ6IHNlc3Npb25JZFxuICAgIH0gYXMgUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICBpZiAoc2hhcmVkU3RhdGUuc3RhcnRDb3VudCA+IDEpIHtcbiAgICAgIGxldCByZXF1ZXN0OiBSZXN0b3JlQ29ubmVjdGlvblJlcXVlc3QgPSB7XG4gICAgICAgIGxhc3RSZWNlaXZlZEluZGV4OiBzaGFyZWRTdGF0ZS5sYXN0UmVjZWl2ZWRJbmRleCxcbiAgICAgICAgbGFzdFNlbnRJbmRleDogc2hhcmVkU3RhdGUubGFzdFNlbnRJbmRleCxcbiAgICAgICAgZmlyc3RIaXN0b3J5SW5kZXg6IHRoaXMuX3NoYXJlZFN0YXRlLmVtaXRIaXN0b3J5LmZyb250KCk/LmluZGV4LFxuICAgICAgICBzZXNzaW9uSWRcbiAgICAgIH07XG4gICAgICB0aGlzLl9sb2dnZXIuZGVidWcoYCR7dGhpcy5fbGFiZWx9OiByZXN0b3Jpbmcgc2Vzc2lvbmAsIEpTT04uc3RyaW5naWZ5KHJlcXVlc3QpKTtcbiAgICAgIHF1ZXJ5LnJlc3RvcmVTdGlja3lDb25uZWN0aW9uID0gZW5jb2RlVVJJQ29tcG9uZW50KEpTT04uc3RyaW5naWZ5KHJlcXVlc3QpKTtcbiAgICB9XG4gICAgdGhpcy5fc29ja2V0ID0gaW9DbGllbnQodXJsLCB7XG4gICAgICAuLi5vcHRpb25zPy5jb25uZWN0aW9uLFxuICAgICAgcmVjb25uZWN0aW9uOiBmYWxzZSxcbiAgICAgIGF1dG9Db25uZWN0OiBmYWxzZSxcbiAgICAgIHF1ZXJ5XG4gICAgfSk7XG4gICAgc29ja2V0V2lsZGNhcmQoaW9DbGllbnQuTWFuYWdlcikodGhpcy5fc29ja2V0KTtcbiAgICB0aGlzLl9zb2NrZXQub24oJyonLCBwYWNrZXQgPT4ge1xuICAgICAgaWYgKHBhY2tldC50eXBlID09PSBFVkVOVCB8fCBwYWNrZXQudHlwZSA9PT0gQklOQVJZX0VWRU5UKSB7XG4gICAgICAgIGxldCBwYXlsb2FkID0gcGFja2V0LmRhdGFbMV07XG4gICAgICAgIGlmICh0aGlzLl9vcHRpb25zPy51c2VOYXRpdmVTb2NrZXRJb1NlcnZlcikge1xuICAgICAgICAgIHRoaXMuX2NsaWVudC5lbWl0KHBhY2tldC5kYXRhWzBdLCAuLi5wYWNrZXQuZGF0YS5zbGljZSgxKSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmICgnaW5kZXgnIGluIHBheWxvYWQpIHtcbiAgICAgICAgICB0aGlzLl9sb2dnZXIudHJhY2UoKCkgPT4gYCR7dGhpcy5fbGFiZWx9OiByZWNlaXZlZCBwYWNrZXQgYCArIEpTT04uc3RyaW5naWZ5KHtpbmRleDogcGF5bG9hZC5pbmRleH0pKTtcbiAgICAgICAgICB0aGlzLl9zaGFyZWRTdGF0ZS5sYXN0UmVjZWl2ZWRJbmRleCA9IE1hdGgubWF4KHRoaXMuX3NoYXJlZFN0YXRlLmxhc3RSZWNlaXZlZEluZGV4ID8/IC0xLCBwYXlsb2FkLmluZGV4KTtcbiAgICAgICAgICB0aGlzLl9jbGllbnQuZW1pdChwYWNrZXQuZGF0YVswXSwgLi4ucGF5bG9hZC5kYXRhKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEVtaXRzIGEgZGF0YSBldmVudC4gQWxsIGV2ZW50cyBhcmUgYnVmZmVyZWQgaWYgbm8gY29ubmVjdGlvblxuICAgKiBAcGFyYW0gZXZlbnQgVGhlIGV2ZW50IHRoYXQgd2UncmUgZW1pdHRpbmdcbiAgICogQHBhcmFtIGFyZ3MgT3B0aW9uYWwgYXJndW1lbnRzIHRvIHNlbmQgd2l0aCB0aGUgZXZlbnRcbiAgICovXG4gIHNlbmQoZXZlbnQ6IHN0cmluZywgLi4uYXJnczogYW55W10pIHtcbiAgICBpZiAodGhpcy5fb3B0aW9ucz8udXNlTmF0aXZlU29ja2V0SW9TZXJ2ZXIpIHtcbiAgICAgIHRoaXMuX3NvY2tldC5lbWl0KGV2ZW50LCAuLi5hcmdzKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IHBhY2tldDogRW1pdEhpc3RvcnlQYWNrZXQgPSB7XG4gICAgICBpbmRleDogKyt0aGlzLl9zaGFyZWRTdGF0ZS5sYXN0U2VudEluZGV4LFxuICAgICAgZXZlbnQsXG4gICAgICBkYXRhOiBhcmdzLFxuICAgICAgdGltZTogbmV3IERhdGUoKVxuICAgIH07XG4gICAgdGhpcy5fc2hhcmVkU3RhdGUuZW1pdEhpc3RvcnkucHVzaChwYWNrZXQpO1xuICAgIHRoaXMuX3NvY2tldC5lbWl0KGV2ZW50LCB7XG4gICAgICBpbmRleDogcGFja2V0LmluZGV4LFxuICAgICAgZGF0YTogcGFja2V0LmRhdGFcbiAgICB9IHNhdGlzZmllcyBFbWl0UGFja2V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAaW5oZXJpdGRvY1xuICAgKi9cbiAgYXN5bmMgc3RhcnQoc3RvcFByb21pc2U6IGxyYXAuSGFuZGxlUHJvbWlzZTx2b2lkPikge1xuICAgIHRyeSB7XG4gICAgICBsZXQgY29ubmVjdFByb21pc2UgPSB0aGlzLl9jb25uZWN0KHN0b3BQcm9taXNlKTtcbiAgICAgIGxldCByZXN0b3JlUHJvbWlzZSA9IHRoaXMuX3Jlc3RvcmVDb25uZWN0aW9uSWZOZWVkZWQoc3RvcFByb21pc2UpO1xuICAgICAgbGV0IFtfLCByZXN0b3JlZF0gPSBhd2FpdCBQcm9taXNlLmFsbChbY29ubmVjdFByb21pc2UsIHJlc3RvcmVQcm9taXNlXSk7XG4gICAgICBpZiAocmVzdG9yZWQpIHtcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmluZm8oYCR7dGhpcy5fbGFiZWx9OiByZXN0b3JlZCBjb25uZWN0aW9uIHNlc3Npb25gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuX2xvZ2dlci53YXJuKGAke3RoaXMuX2xhYmVsfTogZmFpbGVkIHRvIGNvbm5lY3RgLCBlcnIpO1xuICAgICAgaWYgKHRoaXMuX3NoYXJlZFN0YXRlLnN0YXJ0Q291bnQgPT09IDEgfHwgZXJyIGluc3RhbmNlb2YgUmVzdG9yZVJlamVjdEVycm9yKSB7XG4gICAgICAgIHRoaXMuX2NsaWVudC5kaXNjb25uZWN0KGVycik7XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgbHJhcC5Db250cm9sU2lnbmFsKHthY3Rpb246ICdmYWlsb3ZlcicsIHNldmVyaXR5OiAnaW5mbyd9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9jb25uZWN0KHN0b3BQcm9taXNlOiBscmFwLkhhbmRsZVByb21pc2U8dm9pZD4pIHtcbiAgICB0aGlzLl9zb2NrZXQuY29ubmVjdCgpO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBzdG9wUHJvbWlzZS50aGVuKCgpID0+IHJlamVjdChuZXcgRXJyb3IoJ1N0b3BwZWQgZHVyaW5nIGNvbm5lY3Rpb24nKSkpO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignY29ubmVjdCcsICgpID0+IHtcbiAgICAgICAgLy8gRW1pdHRpbmcgY29ubmVjdCBpbW1lZGlhdGVseSB0byBndWFyYW50ZWUgbm8gZGF0YSBldmVudHMgd2lsbCBiZSByZWNlaXZlZCB1bnRpbCBjb25uZWN0IGV2ZW50IGVtaXR0ZWRcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKGAke3RoaXMuX2xhYmVsfTogaW50ZXJuYWwgc29ja2V0IGNvbm5lY3RlZGApO1xuICAgICAgICB0aGlzLl9pbnRlcm5hbEV2ZW50cy5lbWl0KCdjb25uZWN0Jyk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignZGlzY29ubmVjdCcsIChyZWFzb246IENsaWVudFNvY2tldERpc2Nvbm5lY3RSZWFzb24pID0+IHtcbiAgICAgICAgdGhpcy5fZGlzY29ubmVjdFJlYXNvbiA9IHJlYXNvbjtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRGlzY29ubmVjdGVkIHdoZW4gY29ubmVjdGluZyBkdWUgdG8gJHtyZWFzb259YCkpO1xuICAgICAgfSk7XG4gICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdlcnJvcicsIGVyciA9PiByZWplY3QoZXJyKSk7XG4gICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdjb25uZWN0X2Vycm9yJywgZXJyID0+IHJlamVjdChlcnIpKTtcbiAgICAgIHRoaXMuX3NldFNvY2tldFN0YWdlTGlzdGVuZXIoJ2Nvbm5lY3RfdGltZW91dCcsIGVyciA9PiByZWplY3QoZXJyKSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIF9yZXN0b3JlQ29ubmVjdGlvbklmTmVlZGVkKHN0b3BQcm9taXNlOiBscmFwLkhhbmRsZVByb21pc2U8dm9pZD4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5fc2hhcmVkU3RhdGUuc3RhcnRDb3VudCA9PT0gMSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBsZXQgc2VuZFNpbmNlSW5kZXggPSBhd2FpdCBuZXcgUHJvbWlzZTxudW1iZXI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHN0b3BQcm9taXNlLnRoZW4oKCkgPT4gcmVqZWN0KG5ldyBFcnJvcignU3RvcHBlZCBkdXJpbmcgcmVzdG9yaW5nIGNvbm5lY3Rpb24nKSkpO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcihSRVNUT1JFX0NPTk5FQ1RJT05fRVZFTlQsIChldmVudDogUmVzdG9yZUNvbm5lY3Rpb25SZXNwb25zZSkgPT4ge1xuICAgICAgICBldmVudC5yZXN0b3JlZCA/XG4gICAgICAgICAgcmVzb2x2ZShldmVudC5zZW5kU2luY2VJbmRleCkgOlxuICAgICAgICAgIHJlamVjdChuZXcgUmVzdG9yZVJlamVjdEVycm9yKCdDYW5ub3QgcmVzdG9yZSBjb25uZWN0aW9uIHNlc3Npb24nKSk7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuX3NldFNvY2tldFN0YWdlTGlzdGVuZXIoJ2Rpc2Nvbm5lY3QnLCAocmVhc29uOiBzdHJpbmcpID0+IHtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRGlzY29ubmVjdGVkIHdoZW4gcmVzdG9yaW5nIGNvbm5lY3Rpb24gZHVlIHRvICR7cmVhc29ufWApKTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignZXJyb3InLCBlcnIgPT4gcmVqZWN0KGVycikpO1xuICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignY29ubmVjdF9lcnJvcicsIGVyciA9PiByZWplY3QoZXJyKSk7XG4gICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdjb25uZWN0X3RpbWVvdXQnLCBlcnIgPT4gcmVqZWN0KGVycikpO1xuICAgIH0pO1xuICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhgJHt0aGlzLl9sYWJlbH06IHNlbmRpbmcgaGlzdG9yeSBzaW5jZSAke3NlbmRTaW5jZUluZGV4fSBwYWNrZXQgaW5kZXhgKTtcbiAgICBzZW5kSGlzdG9yeSh0aGlzLl9zb2NrZXQsIHRoaXMuX3NoYXJlZFN0YXRlLmVtaXRIaXN0b3J5LCBzZW5kU2luY2VJbmRleCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogQGluaGVyaXRkb2NcbiAgICovXG4gIGFzeW5jIHJ1bihzdG9wUHJvbWlzZTogbHJhcC5IYW5kbGVQcm9taXNlPHZvaWQ+KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaGlzdG9yeUJ1ZmZlclR0bEluTXMgPSAxMDAwICogKHRoaXMuX29wdGlvbnM/LmVtaXRIaXN0b3J5VHRsSW5TZWNvbmRzID8/IDEwKTtcbiAgICBsZXQgY2xlYXJPbGRIaXN0b3J5SW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCgoKSA9PiB0aGlzLnJlbW92ZUV4cGlyZWRFbWl0SGlzdG9yeSgpLCBoaXN0b3J5QnVmZmVyVHRsSW5Ncyk7XG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLl9kaXNjb25uZWN0UmVhc29uKSB7XG4gICAgICAgIGlmICghdGhpcy5fdHJ5RGlzY29ubmVjdENsaWVudEdyYWNlZnVsbHkodGhpcy5fZGlzY29ubmVjdFJlYXNvbikpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYERpc2Nvbm5lY3RlZCBkdWUgdG8gJHt0aGlzLl9kaXNjb25uZWN0UmVhc29ufWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMuX3JlbW92ZVByZXZTdGFnZUxpc3RlbmVycygpO1xuICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKFtzdG9wUHJvbWlzZSwgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyKCdkaXNjb25uZWN0JywgKHJlYXNvbjogQ2xpZW50U29ja2V0RGlzY29ubmVjdFJlYXNvbikgPT4ge1xuICAgICAgICAgIGlmICghdGhpcy5fdHJ5RGlzY29ubmVjdENsaWVudEdyYWNlZnVsbHkocmVhc29uKSkge1xuICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRGlzY29ubmVjdGVkIGR1ZSB0byAke3JlYXNvbn1gKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5fc2V0U29ja2V0U3RhZ2VMaXN0ZW5lcignZXJyb3InLCByZWplY3QpO1xuICAgICAgfSldKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuX2xvZ2dlci53YXJuKGAke3RoaXMuX2xhYmVsfTogbG9zdCBjb25uZWN0aW9uYCwgZXJyKTtcbiAgICAgIHRoaXMuX2ludGVybmFsRXZlbnRzLmVtaXQoJ2ZhaWwnLCBlcnIpO1xuICAgICAgdGhyb3cgbmV3IGxyYXAuQ29udHJvbFNpZ25hbCh7YWN0aW9uOiAnZmFpbG92ZXInLCBzZXZlcml0eTogJ2luZm8nfSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuX3JlbW92ZVByZXZTdGFnZUxpc3RlbmVycygpO1xuICAgICAgY2xlYXJJbnRlcnZhbChjbGVhck9sZEhpc3RvcnlJbnRlcnZhbCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgZXhwaXJlZCBlbWl0IGhpc3RvcnlcbiAgICovXG4gIHJlbW92ZUV4cGlyZWRFbWl0SGlzdG9yeSgpIHtcbiAgICBjb25zdCBoaXN0b3J5QnVmZmVyVHRsSW5NcyA9IDEwMDAgKiAodGhpcy5fb3B0aW9ucz8uZW1pdEhpc3RvcnlUdGxJblNlY29uZHMgPz8gMTApO1xuICAgIHdoaWxlICh0aGlzLl9zaGFyZWRTdGF0ZS5lbWl0SGlzdG9yeS5sZW5ndGgpIHtcbiAgICAgIGlmIChEYXRlLm5vdygpIC0gdGhpcy5fc2hhcmVkU3RhdGUuZW1pdEhpc3RvcnkuZnJvbnQoKS50aW1lLmdldFRpbWUoKSA+IGhpc3RvcnlCdWZmZXJUdGxJbk1zKSB7XG4gICAgICAgIHRoaXMuX3NoYXJlZFN0YXRlLmVtaXRIaXN0b3J5LnNoaWZ0KCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF90cnlEaXNjb25uZWN0Q2xpZW50R3JhY2VmdWxseShyZWFzb246IENsaWVudFNvY2tldERpc2Nvbm5lY3RSZWFzb24pOiBib29sZWFuIHtcbiAgICBpZiAocmVhc29uID09PSAnaW8gY2xpZW50IGRpc2Nvbm5lY3QnIHx8IHJlYXNvbiA9PT0gJ2lvIHNlcnZlciBkaXNjb25uZWN0Jykge1xuICAgICAgdGhpcy5fbG9nZ2VyLmluZm8oYCR7dGhpcy5fbGFiZWx9OiBkaXNjb25uZWN0aW5nIGNsaWVudCBkdWUgdG8gJHtyZWFzb259YCk7XG4gICAgICB0aGlzLl9jbGllbnQuZGlzY29ubmVjdCgpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBpbmhlcml0ZG9jXG4gICAqL1xuICBhc3luYyBzdG9wKCkge1xuICAgIHRoaXMuX3NvY2tldC5kaXNjb25uZWN0KCk7XG4gIH1cblxuICBwcml2YXRlIF9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyPFQgZXh0ZW5kcyAoLi4uYXJnczogYW55W10pID0+IHZvaWQ+KGV2ZW50OiBzdHJpbmcsIGxpc3RlbmVyOiBUKTogVCB7XG4gICAgdGhpcy5fcHJldlN0YWdlTGlzdGVuZXJzW2V2ZW50XSB8fD0gbmV3IFNldCgpO1xuICAgIHRoaXMuX3ByZXZTdGFnZUxpc3RlbmVyc1tldmVudF0uYWRkKGxpc3RlbmVyKTtcbiAgICB0aGlzLl9zb2NrZXQub24oZXZlbnQsIGxpc3RlbmVyKTtcbiAgICByZXR1cm4gbGlzdGVuZXI7XG4gIH1cblxuICBwcml2YXRlIF9yZW1vdmVQcmV2U3RhZ2VMaXN0ZW5lcnMoKSB7XG4gICAgZm9yIChsZXQgW2V2ZW50LCBsaXN0ZW5lcnNdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuX3ByZXZTdGFnZUxpc3RlbmVycykpIHtcbiAgICAgIGZvciAobGV0IGxpc3RlbmVyIG9mIGxpc3RlbmVycykge1xuICAgICAgICB0aGlzLl9zb2NrZXQub2ZmKGV2ZW50LCBsaXN0ZW5lcik7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbm5hbWVzcGFjZSBTdGlja3lTb2NrZXRDb25uZWN0aW9uIHtcblxuICAvKiogT3B0aW9ucyAqL1xuICBleHBvcnQgdHlwZSBPcHRpb25zID0gU29ja2V0T3B0aW9ucyAmIHtcbiAgICAvKiogTG9nZ2luZyBsYWJlbCB0byBpZGVudGlmeSB0aGlzIGluc3RhbmNlLiBEZWZhdWx0cyB0byBgZGVmYXVsdGAgKi9cbiAgICBsYWJlbD86IHN0cmluZztcbiAgICAvKiogTmF0aXZlIHNvY2tldCBJTyBvcHRpb25zICovXG4gICAgY29ubmVjdGlvbj86IFBpY2s8XG4gICAgICBTb2NrZXRJT0NsaWVudC5Db25uZWN0T3B0cyxcbiAgICAgICdwYXRoJyB8ICd0aW1lb3V0JyB8ICdxdWVyeSdcbiAgICA+ICYge1xuICAgICAgLyoqXG4gICAgICAgKiBIZWFkZXJzIHRoYXQgd2lsbCBiZSBwYXNzZWQgZm9yIGVhY2ggcmVxdWVzdCB0byB0aGUgc2VydmVyICh2aWEgeGhyLXBvbGxpbmcgYW5kIHZpYSB3ZWJzb2NrZXRzKS4gVGhlc2UgdmFsdWVzXG4gICAgICAgKiB0aGVuIGNhbiBiZSB1c2VkIGR1cmluZyBoYW5kc2hha2Ugb3IgZm9yIHNwZWNpYWwgcHJveGllc1xuICAgICAgICovXG4gICAgICBleHRyYUhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQWRqdXN0cyBjb21wYXRpYmlsaXR5IHRvIHdvcmsgaW4gbW9kZSB3aGVuIGEgbmF0aXZlIHNvY2tldC5pbyBzZXJ2ZXIgaXMgdXNlZC4gSW4gdGhpcyBtb2RlIHRoZSBzb2NrZXQgd2lsbCBub3RcbiAgICAgKiB0cnkgdG8gcmVzdG9yZSBjb25uZWN0aW9uIGFuZCB3aWxsIHNlbmQgcGFja2V0cyBhcyBpcy4gSW50ZW5kZWQgZm9yIHRlc3RzIHdoZXJlIG5hdGl2ZSBzb2NrZXQuaW8gc2VydmVyIGlzIHVzZWRcbiAgICAgKi9cbiAgICB1c2VOYXRpdmVTb2NrZXRJb1NlcnZlcj86IGJvb2xlYW47XG4gIH07XG5cbiAgLyoqIFNoYXJlZCBzdGF0ZSAqL1xuICBleHBvcnQgdHlwZSBTaGFyZWRTdGF0ZSA9IHtcbiAgICAvKiogQ291bnQgb2YgdGltZXMgYSBjb25uZWN0aW9uIGlzIHN0YXJ0ZWQgKi9cbiAgICBzdGFydENvdW50OiBudW1iZXI7XG4gICAgLyoqIEVtaXQgKi9cbiAgICBlbWl0SGlzdG9yeTogUXVldWU8RW1pdEhpc3RvcnlQYWNrZXQ+O1xuICAgIC8qKiBMYXN0IHNlbnQgaW5kZXguIFN0YXJ0cyBmcm9tIGAwYC4gSWYgbm8gcGFja2V0cyB3ZXJlIHNlbnQgeWV0LCBkZWZhdWx0cyB0byBgLTFgICovXG4gICAgbGFzdFNlbnRJbmRleDogbnVtYmVyO1xuICAgIC8qKiBMYXN0IHJlY2VpdmVkIHBhY2tldCBpbmRleC4gU3RhcnRzIGZyb20gYDBgLiBJZiBubyBwYWNrZXRzIHdlcmUgcmVjZWl2ZWQsIGRlZmF1bHRzIHRvIGAtMWAgKi9cbiAgICBsYXN0UmVjZWl2ZWRJbmRleDogbnVtYmVyO1xuICB9O1xuXG4gIC8qKiBTaGFyZWQgZXZlbnRzIGZvciBpbnRlcm1lZGlhdGUgc3RhdGUgKi9cbiAgZXhwb3J0IHR5cGUgU2hhcmVkRXZlbnRzID0ge1xuICAgIC8qKiBDb25uZWN0ZWQgZXZlbnQgKi9cbiAgICBjb25uZWN0OiAoKSA9PiB2b2lkO1xuICAgIC8qKiBMb3N0IGNvbm5lY3Rpb24gZXZlbnQgKi9cbiAgICBmYWlsOiAoZXJyOiBFcnJvcikgPT4gdm9pZDtcbiAgfTtcblxuICAvKiogQ29ubmVjdGlvbiBldmVudHMgKi9cbiAgZXhwb3J0IGNvbnN0IENPTk5FQ1RJT05fRVZFTlRTID0gWydjb25uZWN0JywgJ2Rpc2Nvbm5lY3QnXTtcbiAgLyoqIFN0aWNreSBjb25uZWN0aW9uIHByb3RvY29sIGV2ZW50cyAqL1xuICBleHBvcnQgY29uc3QgUFJPVE9DT0xfRVZFTlRTID0gW1JFU1RPUkVfQ09OTkVDVElPTl9FVkVOVF07XG4gIC8qKiBJbnRlcm5hbCBldmVudHMgKi9cbiAgZXhwb3J0IGNvbnN0IElOVEVSTkFMX0VWRU5UUyA9IFtcbiAgICAnZXJyb3InLCAnY29ubmVjdF9lcnJvcicsICdjb25uZWN0X3RpbWVvdXQnLCAncmVjb25uZWN0JywgJ3JlY29ubmVjdF9hdHRlbXB0JywgJ3JlY29ubmVjdGluZycsICdyZWNvbm5lY3RfZXJyb3InLFxuICAgICdyZWNvbm5lY3RfZmFpbGVkJywgJ3BpbmcnLCAncG9uZycsIC4uLlBST1RPQ09MX0VWRU5UU1xuICBdO1xufVxuXG5leHBvcnQgZGVmYXVsdCBTdGlja3lTb2NrZXRDb25uZWN0aW9uO1xuXG4vKipcbiAqIEVycm9yLCBtZWFuaW5nIHRoYXQgdGhlIHNlcnZlciByZWplY3RlZCB0aGUgcmVzdG9yZSByZXF1ZXN0LiBFLmcuIHNlcnZlciBtYXkgaGF2ZSBhbHJlYWR5XG4gKiByZW1vdmVkIG9sZCBlbWl0IGhpc3RvcnksIHJlcXVpcmVkIGJ5IHRoZSBjbGllbnQsIHNvIHRoZSByZXN0b3JpbmcgY2Fubm90IGJlIGRvbmVcbiAqL1xuY2xhc3MgUmVzdG9yZVJlamVjdEVycm9yIGV4dGVuZHMgRXJyb3Ige31cbiJdLCJuYW1lcyI6WyJTdGlja3lTb2NrZXRDb25uZWN0aW9uIiwibHJhcCIsIlJvb3RQcm9jZXNzIiwic29ja2V0IiwiX3NvY2tldCIsInRyYW5zcG9ydE5hbWUiLCJnZXRDbGllbnRTb2NrZXRJb1RyYW5zcG9ydE5hbWUiLCJmaXJzdEhpc3RvcnlJbmRleCIsIl9zaGFyZWRTdGF0ZSIsImVtaXRIaXN0b3J5IiwiZnJvbnQiLCJpbmRleCIsImluamVjdCIsImNsaWVudCIsImludGVybmFsRXZlbnRzIiwiX2NsaWVudCIsIl9pbnRlcm5hbEV2ZW50cyIsImluaXRpYWxpemUiLCJ1cmwiLCJzZXNzaW9uSWQiLCJzaGFyZWRTdGF0ZSIsIm9wdGlvbnMiLCJfb3B0aW9ucyIsIl9sYWJlbCIsImxhYmVsIiwic3RhcnRDb3VudCIsInF1ZXJ5IiwiY29ubmVjdGlvbiIsInN0aWNreVNvY2tldENvbm5lY3Rpb25JZCIsInJlcXVlc3QiLCJsYXN0UmVjZWl2ZWRJbmRleCIsImxhc3RTZW50SW5kZXgiLCJfbG9nZ2VyIiwiZGVidWciLCJKU09OIiwic3RyaW5naWZ5IiwicmVzdG9yZVN0aWNreUNvbm5lY3Rpb24iLCJlbmNvZGVVUklDb21wb25lbnQiLCJpb0NsaWVudCIsInJlY29ubmVjdGlvbiIsImF1dG9Db25uZWN0Iiwic29ja2V0V2lsZGNhcmQiLCJNYW5hZ2VyIiwib24iLCJwYWNrZXQiLCJ0eXBlIiwiRVZFTlQiLCJCSU5BUllfRVZFTlQiLCJwYXlsb2FkIiwiZGF0YSIsInVzZU5hdGl2ZVNvY2tldElvU2VydmVyIiwiZW1pdCIsInNsaWNlIiwidHJhY2UiLCJNYXRoIiwibWF4Iiwic2VuZCIsImV2ZW50IiwiYXJncyIsInRpbWUiLCJEYXRlIiwicHVzaCIsInN0YXJ0Iiwic3RvcFByb21pc2UiLCJjb25uZWN0UHJvbWlzZSIsIl9jb25uZWN0IiwicmVzdG9yZVByb21pc2UiLCJfcmVzdG9yZUNvbm5lY3Rpb25JZk5lZWRlZCIsIl8iLCJyZXN0b3JlZCIsIlByb21pc2UiLCJhbGwiLCJpbmZvIiwiZXJyIiwid2FybiIsIlJlc3RvcmVSZWplY3RFcnJvciIsImRpc2Nvbm5lY3QiLCJDb250cm9sU2lnbmFsIiwiYWN0aW9uIiwic2V2ZXJpdHkiLCJjb25uZWN0IiwicmVzb2x2ZSIsInJlamVjdCIsInRoZW4iLCJFcnJvciIsIl9zZXRTb2NrZXRTdGFnZUxpc3RlbmVyIiwicmVhc29uIiwiX2Rpc2Nvbm5lY3RSZWFzb24iLCJzZW5kU2luY2VJbmRleCIsIlJFU1RPUkVfQ09OTkVDVElPTl9FVkVOVCIsInNlbmRIaXN0b3J5IiwicnVuIiwiaGlzdG9yeUJ1ZmZlclR0bEluTXMiLCJlbWl0SGlzdG9yeVR0bEluU2Vjb25kcyIsImNsZWFyT2xkSGlzdG9yeUludGVydmFsIiwic2V0SW50ZXJ2YWwiLCJyZW1vdmVFeHBpcmVkRW1pdEhpc3RvcnkiLCJfdHJ5RGlzY29ubmVjdENsaWVudEdyYWNlZnVsbHkiLCJfcmVtb3ZlUHJldlN0YWdlTGlzdGVuZXJzIiwicmFjZSIsImNsZWFySW50ZXJ2YWwiLCJsZW5ndGgiLCJub3ciLCJnZXRUaW1lIiwic2hpZnQiLCJzdG9wIiwibGlzdGVuZXIiLCJfcHJldlN0YWdlTGlzdGVuZXJzIiwiU2V0IiwiYWRkIiwibGlzdGVuZXJzIiwiT2JqZWN0IiwiZW50cmllcyIsIm9mZiIsIkxvZ2dlck1hbmFnZXIiLCJnZXRMb2dnZXIiLCJuYW1lIiwiQ09OTkVDVElPTl9FVkVOVFMiLCJQUk9UT0NPTF9FVkVOVFMiLCJJTlRFUk5BTF9FVkVOVFMiXSwibWFwcGluZ3MiOiI7Ozs7K0JBaVZBOzs7ZUFBQTs7O2lGQWpWc0I7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