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)
311 lines (310 loc) • 42.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return TerminalHashManager;
}
});
const _cryptojs = /*#__PURE__*/ _interop_require_default(require("crypto-js"));
const _referenceTree = /*#__PURE__*/ _interop_require_default(require("./referenceTree"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let TerminalHashManager = class TerminalHashManager {
/**
* Refreshes hashing ignored field lists
* @param {String} region account region
* @returns {Promise} promise resolving when the hashing field lists are updated.
*/ async refreshIgnoredFieldLists(region) {
await this._clientApiClient.refreshIgnoredFieldLists(region);
}
/**
* Returns specifications data by hash
* @param {string} specificationsHash specifications hash
* @returns {[id: string]: MetatraderSymbolSpecification}
*/ getSpecificationsByHash(specificationsHash) {
return this._specificationsTree.getItemsByHash(specificationsHash);
}
/**
* Returns specifications hash data by hash
* @param {string} specificationsHash specifications hash
* @returns {[id: string]: string}
*/ getSpecificationsHashesByHash(specificationsHash) {
return this._specificationsTree.getHashesByHash(specificationsHash);
}
/**
* Returns positions data by hash
* @param {string} positionsHash positions hash
* @returns {[id: string]: MetatraderPosition}
*/ getPositionsByHash(positionsHash) {
return this._positionsTree.getItemsByHash(positionsHash);
}
/**
* Returns positions hash data by hash
* @param {string} positionsHash positions hash
* @returns {[id: string]: string} dictionary of position hashes
*/ getPositionsHashesByHash(positionsHash) {
return this._positionsTree.getHashesByHash(positionsHash);
}
/**
* Returns orders data by hash
* @param {string} ordersHash orders hash
* @returns {[id: string]: MetatraderOrder} removed position ids
*/ getOrdersByHash(ordersHash) {
return this._ordersTree.getItemsByHash(ordersHash);
}
/**
* Returns orders hash data by hash
* @param {string} ordersHash orders hash
* @returns {[id: string]: string} dictionary of order hashes
*/ getOrdersHashesByHash(ordersHash) {
return this._ordersTree.getHashesByHash(ordersHash);
}
/**
* Creates an entry for specification data and returns hash
* @param {string} serverName broker server name
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {MetatraderSymbolSpecification[]} specifications specifications array
* @returns {string} dictionary hash
*/ recordSpecifications(serverName, accountType, connectionId, instanceIndex, specifications) {
return this._specificationsTree.recordItems(serverName, accountType, connectionId, instanceIndex, specifications);
}
/**
* Updates specification data
* @param {string} serverName broker server name
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {MetatraderSymbolSpecification[]} specifications specifications array
* @param {string[]} removedSymbols removed specification symbols
* @param {string} parentHash parent hash
* @returns {string} updated dictionary hash
*/ // eslint-disable-next-line complexity
updateSpecifications(serverName, accountType, connectionId, instanceIndex, specifications, removedSymbols, parentHash) {
return this._specificationsTree.updateItems(serverName, accountType, connectionId, instanceIndex, specifications, removedSymbols, parentHash);
}
/**
* Creates an entry for positions data and returns hash
* @param {string} accountId account id
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {MetatraderPosition[]} positions positions array
* @returns {string} dictionary hash
*/ recordPositions(accountId, accountType, connectionId, instanceIndex, positions) {
return this._positionsTree.recordItems(accountId, accountType, connectionId, instanceIndex, positions);
}
/**
* Updates positions data
* @param {string} accountId account id
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {MetatraderPosition[]} positions positions
* @param {string[]} removedPositions removed position ids
* @param {string} parentHash parent hash
* @returns {string} updated dictionary hash
*/ updatePositions(accountId, accountType, connectionId, instanceIndex, positions, removedPositions, parentHash) {
return this._positionsTree.updateItems(accountId, accountType, connectionId, instanceIndex, positions, removedPositions, parentHash);
}
/**
* Creates an entry for orders data and returns hash
* @param {string} accountId account id
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {Array<MetatraderOrder>} orders orders array
* @returns {string} dictionary hash
*/ recordOrders(accountId, accountType, connectionId, instanceIndex, orders) {
return this._ordersTree.recordItems(accountId, accountType, connectionId, instanceIndex, orders);
}
/**
* Updates orders data
* @param {string} accountId account id
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {MetatraderOrder[]} orders orders array
* @param {string[]} completedOrders completed order ids
* @param {string} parentHash parent hash
* @returns {string} updated dictionary hash
*/ updateOrders(accountId, accountType, connectionId, instanceIndex, orders, completedOrders, parentHash) {
return this._ordersTree.updateItems(accountId, accountType, connectionId, instanceIndex, orders, completedOrders, parentHash);
}
/**
* Returns the list of last used specification hashes, with specified server hashes prioritized
* @param {string} serverName server name
* @returns {string[]} last used specification hashes
*/ getLastUsedSpecificationHashes(serverName) {
return this._specificationsTree.getLastUsedHashes(serverName);
}
/**
* Returns the list of last used position hashes
* @param {string} accountId account id
* @returns {string[]} last used position hashes
*/ getLastUsedPositionHashes(accountId) {
return this._positionsTree.getLastUsedHashes(accountId);
}
/**
* Returns the list of last used order hashes
* @param {string} accountId account id
* @returns {string[]} last used order hashes
*/ getLastUsedOrderHashes(accountId) {
return this._ordersTree.getLastUsedHashes(accountId);
}
/**
* Removes all references for a connection
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ removeConnectionReferences(connectionId, instanceIndex) {
this.removeSpecificationReference(connectionId, instanceIndex);
this.removePositionReference(connectionId, instanceIndex);
this.removeOrderReference(connectionId, instanceIndex);
}
/**
* Adds a reference from a terminal state instance index to a specifications hash
* @param {string} hash specifications hash
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ addSpecificationReference(hash, connectionId, instanceIndex) {
this._specificationsTree.addReference(hash, connectionId, instanceIndex);
}
/**
* Removes a reference from a terminal state instance index to a specifications hash
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ removeSpecificationReference(connectionId, instanceIndex) {
this._specificationsTree.removeReference(connectionId, instanceIndex);
}
/**
* Adds a reference from a terminal state instance index to a positions hash
* @param {string} hash positions hash
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ addPositionReference(hash, connectionId, instanceIndex) {
this._positionsTree.addReference(hash, connectionId, instanceIndex);
}
/**
* Removes a reference from a terminal state instance index to a positions hash
* @param {string} accountId account id
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ removePositionReference(connectionId, instanceIndex) {
this._positionsTree.removeReference(connectionId, instanceIndex);
}
/**
* Adds a reference from a terminal state instance index to a orders hash
* @param {string} hash positions hash
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ addOrderReference(hash, connectionId, instanceIndex) {
this._ordersTree.addReference(hash, connectionId, instanceIndex);
}
/**
* Removes a reference from a terminal state instance index to a orders hash
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ removeOrderReference(connectionId, instanceIndex) {
this._ordersTree.removeReference(connectionId, instanceIndex);
}
// eslint-disable-next-line complexity
getItemHash(item, type, accountType, region) {
const hashFields = this._clientApiClient.getHashingIgnoredFieldLists(region);
item = Object.assign({}, item);
switch(type){
case "specifications":
if (accountType === "cloud-g1") {
hashFields.g1.specification.forEach((field)=>delete item[field]);
} else if (accountType === "cloud-g2") {
hashFields.g2.specification.forEach((field)=>delete item[field]);
}
return this._getHash(item, accountType, [
"digits"
]);
case "positions":
if (accountType === "cloud-g1") {
hashFields.g1.position.forEach((field)=>delete item[field]);
} else if (accountType === "cloud-g2") {
hashFields.g2.position.forEach((field)=>delete item[field]);
}
return this._getHash(item, accountType, [
"magic"
]);
case "orders":
if (accountType === "cloud-g1") {
hashFields.g1.order.forEach((field)=>delete item[field]);
} else if (accountType === "cloud-g2") {
hashFields.g2.order.forEach((field)=>delete item[field]);
}
return this._getHash(item, accountType, [
"magic"
]);
}
}
_getHash(obj, accountType, integerKeys) {
let jsonItem = "";
if (accountType === "cloud-g1") {
const stringify = (objFromJson, key)=>{
if (typeof objFromJson === "number") {
if (integerKeys.includes(key)) {
return objFromJson;
} else {
return objFromJson.toFixed(8);
}
} else if (Array.isArray(objFromJson)) {
return `[${objFromJson.map((item)=>stringify(item)).join(",")}]`;
} else if (objFromJson === null) {
return objFromJson;
} else if (typeof objFromJson !== "object" || objFromJson.getTime) {
return JSON.stringify(objFromJson);
}
let props = Object.keys(objFromJson).map((keyItem)=>`"${keyItem}":${stringify(objFromJson[keyItem], keyItem)}`).join(",");
return `{${props}}`;
};
jsonItem = stringify(obj);
} else if (accountType === "cloud-g2") {
const stringify = (objFromJson, key)=>{
if (typeof objFromJson === "number") {
if (integerKeys.includes(key)) {
return objFromJson;
} else {
return parseFloat(objFromJson.toFixed(8));
}
} else if (Array.isArray(objFromJson)) {
return `[${objFromJson.map((item)=>stringify(item)).join(",")}]`;
} else if (objFromJson === null) {
return objFromJson;
} else if (typeof objFromJson !== "object" || objFromJson.getTime) {
return JSON.stringify(objFromJson);
}
let props = Object.keys(objFromJson).map((keyItem)=>`"${keyItem}":${stringify(objFromJson[keyItem], keyItem)}`).join(",");
return `{${props}}`;
};
jsonItem = stringify(obj);
}
return _cryptojs.default.MD5(jsonItem).toString();
}
_stop() {
this._specificationsTree.stop();
this._positionsTree.stop();
this._ordersTree.stop();
}
/**
* Constructs the instance of terminal hash manager class
* @param {ClientApiClient} clientApiClient client api client
* @param {boolean} [keepHashTrees] if set to true, unused data will not be cleared (for use in debugging)
*/ constructor(clientApiClient, keepHashTrees = false){
this._clientApiClient = clientApiClient;
this._specificationsTree = new _referenceTree.default(this, "symbol", "specifications", true, keepHashTrees);
this._positionsTree = new _referenceTree.default(this, "id", "positions", false, keepHashTrees);
this._ordersTree = new _referenceTree.default(this, "id", "orders", false, keepHashTrees);
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY3J5cHRvIGZyb20gJ2NyeXB0by1qcyc7XG5pbXBvcnQgUmVmZXJlbmNlVHJlZSBmcm9tICcuL3JlZmVyZW5jZVRyZWUnO1xuXG4vKipcbiAqIFJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBwb3NpdGlvbnMsIG9yZGVycywgYW5kIHNwZWNpZmljYXRpb25zIGhhc2ggZGF0YVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUZXJtaW5hbEhhc2hNYW5hZ2VyIHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyB0aGUgaW5zdGFuY2Ugb2YgdGVybWluYWwgaGFzaCBtYW5hZ2VyIGNsYXNzXG4gICAqIEBwYXJhbSB7Q2xpZW50QXBpQ2xpZW50fSBjbGllbnRBcGlDbGllbnQgY2xpZW50IGFwaSBjbGllbnRcbiAgICogQHBhcmFtIHtib29sZWFufSBba2VlcEhhc2hUcmVlc10gaWYgc2V0IHRvIHRydWUsIHVudXNlZCBkYXRhIHdpbGwgbm90IGJlIGNsZWFyZWQgKGZvciB1c2UgaW4gZGVidWdnaW5nKVxuICAgKi9cbiAgY29uc3RydWN0b3IoY2xpZW50QXBpQ2xpZW50LCBrZWVwSGFzaFRyZWVzID0gZmFsc2UpIHtcbiAgICB0aGlzLl9jbGllbnRBcGlDbGllbnQgPSBjbGllbnRBcGlDbGllbnQ7XG4gICAgdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlID0gbmV3IFJlZmVyZW5jZVRyZWUodGhpcywgJ3N5bWJvbCcsICdzcGVjaWZpY2F0aW9ucycsIHRydWUsIGtlZXBIYXNoVHJlZXMpO1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUgPSBuZXcgUmVmZXJlbmNlVHJlZSh0aGlzLCAnaWQnLCAncG9zaXRpb25zJywgZmFsc2UsIGtlZXBIYXNoVHJlZXMpO1xuICAgIHRoaXMuX29yZGVyc1RyZWUgPSBuZXcgUmVmZXJlbmNlVHJlZSh0aGlzLCAnaWQnLCAnb3JkZXJzJywgZmFsc2UsIGtlZXBIYXNoVHJlZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZnJlc2hlcyBoYXNoaW5nIGlnbm9yZWQgZmllbGQgbGlzdHNcbiAgICogQHBhcmFtIHtTdHJpbmd9IHJlZ2lvbiBhY2NvdW50IHJlZ2lvblxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiB0aGUgaGFzaGluZyBmaWVsZCBsaXN0cyBhcmUgdXBkYXRlZC5cbiAgICovXG4gIGFzeW5jIHJlZnJlc2hJZ25vcmVkRmllbGRMaXN0cyhyZWdpb24pIHtcbiAgICBhd2FpdCB0aGlzLl9jbGllbnRBcGlDbGllbnQucmVmcmVzaElnbm9yZWRGaWVsZExpc3RzKHJlZ2lvbik7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzcGVjaWZpY2F0aW9ucyBkYXRhIGJ5IGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNwZWNpZmljYXRpb25zSGFzaCBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEByZXR1cm5zIHtbaWQ6IHN0cmluZ106IE1ldGF0cmFkZXJTeW1ib2xTcGVjaWZpY2F0aW9ufVxuICAgKi9cbiAgZ2V0U3BlY2lmaWNhdGlvbnNCeUhhc2goc3BlY2lmaWNhdGlvbnNIYXNoKXtcbiAgICByZXR1cm4gdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlLmdldEl0ZW1zQnlIYXNoKHNwZWNpZmljYXRpb25zSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzcGVjaWZpY2F0aW9ucyBoYXNoIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3BlY2lmaWNhdGlvbnNIYXNoIHNwZWNpZmljYXRpb25zIGhhc2hcbiAgICogQHJldHVybnMge1tpZDogc3RyaW5nXTogc3RyaW5nfVxuICAgKi9cbiAgZ2V0U3BlY2lmaWNhdGlvbnNIYXNoZXNCeUhhc2goc3BlY2lmaWNhdGlvbnNIYXNoKXtcbiAgICByZXR1cm4gdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlLmdldEhhc2hlc0J5SGFzaChzcGVjaWZpY2F0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcG9zaXRpb25zIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcG9zaXRpb25zSGFzaCBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcmV0dXJucyB7W2lkOiBzdHJpbmddOiBNZXRhdHJhZGVyUG9zaXRpb259XG4gICAqL1xuICBnZXRQb3NpdGlvbnNCeUhhc2gocG9zaXRpb25zSGFzaCkge1xuICAgIHJldHVybiB0aGlzLl9wb3NpdGlvbnNUcmVlLmdldEl0ZW1zQnlIYXNoKHBvc2l0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcG9zaXRpb25zIGhhc2ggZGF0YSBieSBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwb3NpdGlvbnNIYXNoIHBvc2l0aW9ucyBoYXNoXG4gICAqIEByZXR1cm5zIHtbaWQ6IHN0cmluZ106IHN0cmluZ30gZGljdGlvbmFyeSBvZiBwb3NpdGlvbiBoYXNoZXNcbiAgICovXG4gIGdldFBvc2l0aW9uc0hhc2hlc0J5SGFzaChwb3NpdGlvbnNIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUuZ2V0SGFzaGVzQnlIYXNoKHBvc2l0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgb3JkZXJzIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gb3JkZXJzSGFzaCBvcmRlcnMgaGFzaFxuICAgKiBAcmV0dXJucyB7W2lkOiBzdHJpbmddOiBNZXRhdHJhZGVyT3JkZXJ9IHJlbW92ZWQgcG9zaXRpb24gaWRzXG4gICAqL1xuICBnZXRPcmRlcnNCeUhhc2gob3JkZXJzSGFzaCl7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUuZ2V0SXRlbXNCeUhhc2gob3JkZXJzSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBvcmRlcnMgaGFzaCBkYXRhIGJ5IGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IG9yZGVyc0hhc2ggb3JkZXJzIGhhc2hcbiAgICogQHJldHVybnMge1tpZDogc3RyaW5nXTogc3RyaW5nfSBkaWN0aW9uYXJ5IG9mIG9yZGVyIGhhc2hlc1xuICAgKi9cbiAgZ2V0T3JkZXJzSGFzaGVzQnlIYXNoKG9yZGVyc0hhc2gpIHtcbiAgICByZXR1cm4gdGhpcy5fb3JkZXJzVHJlZS5nZXRIYXNoZXNCeUhhc2gob3JkZXJzSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBlbnRyeSBmb3Igc3BlY2lmaWNhdGlvbiBkYXRhIGFuZCByZXR1cm5zIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcnZlck5hbWUgYnJva2VyIHNlcnZlciBuYW1lIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJTeW1ib2xTcGVjaWZpY2F0aW9uW119IHNwZWNpZmljYXRpb25zIHNwZWNpZmljYXRpb25zIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkU3BlY2lmaWNhdGlvbnMoc2VydmVyTmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCxcbiAgICBpbnN0YW5jZUluZGV4LCBzcGVjaWZpY2F0aW9ucykge1xuICAgIHJldHVybiB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUucmVjb3JkSXRlbXMoc2VydmVyTmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCxcbiAgICAgIGluc3RhbmNlSW5kZXgsIHNwZWNpZmljYXRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHNwZWNpZmljYXRpb24gZGF0YVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2VydmVyTmFtZSBicm9rZXIgc2VydmVyIG5hbWUgXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50VHlwZSBhY2NvdW50IHR5cGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqIEBwYXJhbSB7TWV0YXRyYWRlclN5bWJvbFNwZWNpZmljYXRpb25bXX0gc3BlY2lmaWNhdGlvbnMgc3BlY2lmaWNhdGlvbnMgYXJyYXlcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gcmVtb3ZlZFN5bWJvbHMgcmVtb3ZlZCBzcGVjaWZpY2F0aW9uIHN5bWJvbHNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudEhhc2ggcGFyZW50IGhhc2hcbiAgICogQHJldHVybnMge3N0cmluZ30gdXBkYXRlZCBkaWN0aW9uYXJ5IGhhc2hcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG4gIHVwZGF0ZVNwZWNpZmljYXRpb25zKHNlcnZlck5hbWUsIGFjY291bnRUeXBlLCBjb25uZWN0aW9uSWQsXG4gICAgaW5zdGFuY2VJbmRleCwgc3BlY2lmaWNhdGlvbnMsIHJlbW92ZWRTeW1ib2xzLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3NwZWNpZmljYXRpb25zVHJlZS51cGRhdGVJdGVtcyhzZXJ2ZXJOYW1lLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgc3BlY2lmaWNhdGlvbnMsIHJlbW92ZWRTeW1ib2xzLCBwYXJlbnRIYXNoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVudHJ5IGZvciBwb3NpdGlvbnMgZGF0YSBhbmQgcmV0dXJucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJQb3NpdGlvbltdfSBwb3NpdGlvbnMgcG9zaXRpb25zIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkUG9zaXRpb25zKGFjY291bnRJZCwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUucmVjb3JkSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4LCBwb3NpdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgcG9zaXRpb25zIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJQb3NpdGlvbltdfSBwb3NpdGlvbnMgcG9zaXRpb25zXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHJlbW92ZWRQb3NpdGlvbnMgcmVtb3ZlZCBwb3NpdGlvbiBpZHNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudEhhc2ggcGFyZW50IGhhc2hcbiAgICogQHJldHVybnMge3N0cmluZ30gdXBkYXRlZCBkaWN0aW9uYXJ5IGhhc2hcbiAgICovXG4gIHVwZGF0ZVBvc2l0aW9ucyhhY2NvdW50SWQsIGFjY291bnRUeXBlLCBjb25uZWN0aW9uSWQsXG4gICAgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zLCByZW1vdmVkUG9zaXRpb25zLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUudXBkYXRlSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zLCByZW1vdmVkUG9zaXRpb25zLCBwYXJlbnRIYXNoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVudHJ5IGZvciBvcmRlcnMgZGF0YSBhbmQgcmV0dXJucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZCBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRUeXBlIGFjY291bnQgdHlwZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29ubmVjdGlvbklkIGNvbm5lY3Rpb24gaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSW5kZXggaW5zdGFuY2UgaW5kZXhcbiAgICogQHBhcmFtIHtBcnJheTxNZXRhdHJhZGVyT3JkZXI+fSBvcmRlcnMgb3JkZXJzIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkT3JkZXJzKGFjY291bnRJZCwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgb3JkZXJzKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUucmVjb3JkSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4LCBvcmRlcnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgb3JkZXJzIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJPcmRlcltdfSBvcmRlcnMgb3JkZXJzIGFycmF5XG4gICAqIEBwYXJhbSB7c3RyaW5nW119IGNvbXBsZXRlZE9yZGVycyBjb21wbGV0ZWQgb3JkZXIgaWRzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRIYXNoIHBhcmVudCBoYXNoXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IHVwZGF0ZWQgZGljdGlvbmFyeSBoYXNoXG4gICAqL1xuICB1cGRhdGVPcmRlcnMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgIGluc3RhbmNlSW5kZXgsIG9yZGVycywgY29tcGxldGVkT3JkZXJzLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUudXBkYXRlSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgb3JkZXJzLCBjb21wbGV0ZWRPcmRlcnMsIHBhcmVudEhhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGxpc3Qgb2YgbGFzdCB1c2VkIHNwZWNpZmljYXRpb24gaGFzaGVzLCB3aXRoIHNwZWNpZmllZCBzZXJ2ZXIgaGFzaGVzIHByaW9yaXRpemVkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzZXJ2ZXJOYW1lIHNlcnZlciBuYW1lXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gbGFzdCB1c2VkIHNwZWNpZmljYXRpb24gaGFzaGVzXG4gICAqL1xuICBnZXRMYXN0VXNlZFNwZWNpZmljYXRpb25IYXNoZXMoc2VydmVyTmFtZSkge1xuICAgIHJldHVybiB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuZ2V0TGFzdFVzZWRIYXNoZXMoc2VydmVyTmFtZSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBsaXN0IG9mIGxhc3QgdXNlZCBwb3NpdGlvbiBoYXNoZXNcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gbGFzdCB1c2VkIHBvc2l0aW9uIGhhc2hlc1xuICAgKi9cbiAgZ2V0TGFzdFVzZWRQb3NpdGlvbkhhc2hlcyhhY2NvdW50SWQpIHtcbiAgICByZXR1cm4gdGhpcy5fcG9zaXRpb25zVHJlZS5nZXRMYXN0VXNlZEhhc2hlcyhhY2NvdW50SWQpO1xuICB9XG4gIFxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbGlzdCBvZiBsYXN0IHVzZWQgb3JkZXIgaGFzaGVzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcmV0dXJucyB7c3RyaW5nW119IGxhc3QgdXNlZCBvcmRlciBoYXNoZXNcbiAgICovXG4gIGdldExhc3RVc2VkT3JkZXJIYXNoZXMoYWNjb3VudElkKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUuZ2V0TGFzdFVzZWRIYXNoZXMoYWNjb3VudElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGFsbCByZWZlcmVuY2VzIGZvciBhIGNvbm5lY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVDb25uZWN0aW9uUmVmZXJlbmNlcyhjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLnJlbW92ZVNwZWNpZmljYXRpb25SZWZlcmVuY2UoY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4KTtcbiAgICB0aGlzLnJlbW92ZVBvc2l0aW9uUmVmZXJlbmNlKGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gICAgdGhpcy5yZW1vdmVPcmRlclJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgc3BlY2lmaWNhdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFzaCBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKi9cbiAgYWRkU3BlY2lmaWNhdGlvblJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuYWRkUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKi9cbiAgcmVtb3ZlU3BlY2lmaWNhdGlvblJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUucmVtb3ZlUmVmZXJlbmNlKGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFzaCBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29ubmVjdGlvbklkIGNvbm5lY3Rpb24gaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSW5kZXggaW5zdGFuY2UgaW5kZXhcbiAgICovXG4gIGFkZFBvc2l0aW9uUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCkge1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUuYWRkUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVQb3NpdGlvblJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9wb3NpdGlvbnNUcmVlLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgb3JkZXJzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhc2ggcG9zaXRpb25zIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICBhZGRPcmRlclJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9vcmRlcnNUcmVlLmFkZFJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgb3JkZXJzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVPcmRlclJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9vcmRlcnNUcmVlLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgZ2V0SXRlbUhhc2goaXRlbSwgdHlwZSwgYWNjb3VudFR5cGUsIHJlZ2lvbikge1xuICAgIGNvbnN0IGhhc2hGaWVsZHMgPSB0aGlzLl9jbGllbnRBcGlDbGllbnQuZ2V0SGFzaGluZ0lnbm9yZWRGaWVsZExpc3RzKHJlZ2lvbik7XG4gICAgaXRlbSA9IE9iamVjdC5hc3NpZ24oe30sIGl0ZW0pO1xuICAgIHN3aXRjaCh0eXBlKSB7XG4gICAgY2FzZSAnc3BlY2lmaWNhdGlvbnMnOlxuICAgICAgaWYoYWNjb3VudFR5cGUgPT09ICdjbG91ZC1nMScpIHtcbiAgICAgICAgaGFzaEZpZWxkcy5nMS5zcGVjaWZpY2F0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLnNwZWNpZmljYXRpb24uZm9yRWFjaChmaWVsZCA9PiBkZWxldGUgaXRlbVtmaWVsZF0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuX2dldEhhc2goaXRlbSwgYWNjb3VudFR5cGUsIFsnZGlnaXRzJ10pO1xuICAgIGNhc2UgJ3Bvc2l0aW9ucyc6XG4gICAgICBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcxJykge1xuICAgICAgICBoYXNoRmllbGRzLmcxLnBvc2l0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLnBvc2l0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLl9nZXRIYXNoKGl0ZW0sIGFjY291bnRUeXBlLCBbJ21hZ2ljJ10pO1xuICAgIGNhc2UgJ29yZGVycyc6XG4gICAgICBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcxJykge1xuICAgICAgICBoYXNoRmllbGRzLmcxLm9yZGVyLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLm9yZGVyLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLl9nZXRIYXNoKGl0ZW0sIGFjY291bnRUeXBlLCBbJ21hZ2ljJ10pO1xuICAgIH1cbiAgfVxuXG4gIF9nZXRIYXNoKG9iaiwgYWNjb3VudFR5cGUsIGludGVnZXJLZXlzKSB7XG4gICAgbGV0IGpzb25JdGVtID0gJyc7XG4gICAgaWYoYWNjb3VudFR5cGUgPT09ICdjbG91ZC1nMScpIHtcbiAgICAgIGNvbnN0IHN0cmluZ2lmeSA9IChvYmpGcm9tSnNvbiwga2V5KSA9PiB7XG4gICAgICAgIGlmKHR5cGVvZiBvYmpGcm9tSnNvbiA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICBpZihpbnRlZ2VyS2V5cy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgICAgICByZXR1cm4gb2JqRnJvbUpzb247XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbi50b0ZpeGVkKDgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmKEFycmF5LmlzQXJyYXkob2JqRnJvbUpzb24pKSB7XG4gICAgICAgICAgcmV0dXJuIGBbJHtvYmpGcm9tSnNvbi5tYXAoaXRlbSA9PiBzdHJpbmdpZnkoaXRlbSkpLmpvaW4oJywnKX1dYDsgXG4gICAgICAgIH0gZWxzZSBpZiAob2JqRnJvbUpzb24gPT09IG51bGwpIHtcbiAgICAgICAgICByZXR1cm4gb2JqRnJvbUpzb247XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIG9iakZyb21Kc29uICE9PSAnb2JqZWN0JyB8fCBvYmpGcm9tSnNvbi5nZXRUaW1lKXtcbiAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob2JqRnJvbUpzb24pO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGxldCBwcm9wcyA9IE9iamVjdFxuICAgICAgICAgIC5rZXlzKG9iakZyb21Kc29uKVxuICAgICAgICAgIC5tYXAoa2V5SXRlbSA9PiBgXCIke2tleUl0ZW19XCI6JHtzdHJpbmdpZnkob2JqRnJvbUpzb25ba2V5SXRlbV0sIGtleUl0ZW0pfWApXG4gICAgICAgICAgLmpvaW4oJywnKTtcbiAgICAgICAgcmV0dXJuIGB7JHtwcm9wc319YDtcbiAgICAgIH07XG4gICAgXG4gICAgICBqc29uSXRlbSA9IHN0cmluZ2lmeShvYmopO1xuICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgY29uc3Qgc3RyaW5naWZ5ID0gKG9iakZyb21Kc29uLCBrZXkpID0+IHtcbiAgICAgICAgaWYodHlwZW9mIG9iakZyb21Kc29uID09PSAnbnVtYmVyJykge1xuICAgICAgICAgIGlmKGludGVnZXJLZXlzLmluY2x1ZGVzKGtleSkpIHtcbiAgICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQob2JqRnJvbUpzb24udG9GaXhlZCg4KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYoQXJyYXkuaXNBcnJheShvYmpGcm9tSnNvbikpIHtcbiAgICAgICAgICByZXR1cm4gYFske29iakZyb21Kc29uLm1hcChpdGVtID0+IHN0cmluZ2lmeShpdGVtKSkuam9pbignLCcpfV1gOyBcbiAgICAgICAgfSBlbHNlIGlmIChvYmpGcm9tSnNvbiA9PT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbjtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygb2JqRnJvbUpzb24gIT09ICdvYmplY3QnIHx8IG9iakZyb21Kc29uLmdldFRpbWUpe1xuICAgICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShvYmpGcm9tSnNvbik7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgbGV0IHByb3BzID0gT2JqZWN0XG4gICAgICAgICAgLmtleXMob2JqRnJvbUpzb24pXG4gICAgICAgICAgLm1hcChrZXlJdGVtID0+IGBcIiR7a2V5SXRlbX1cIjoke3N0cmluZ2lmeShvYmpGcm9tSnNvbltrZXlJdGVtXSwga2V5SXRlbSl9YClcbiAgICAgICAgICAuam9pbignLCcpO1xuICAgICAgICByZXR1cm4gYHske3Byb3BzfX1gO1xuICAgICAgfTtcblxuICAgICAganNvbkl0ZW0gPSBzdHJpbmdpZnkob2JqKTtcbiAgICB9XG4gICAgcmV0dXJuIGNyeXB0by5NRDUoanNvbkl0ZW0pLnRvU3RyaW5nKCk7XG4gIH1cblxuICBfc3RvcCgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuc3RvcCgpO1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUuc3RvcCgpO1xuICAgIHRoaXMuX29yZGVyc1RyZWUuc3RvcCgpO1xuICB9XG5cbn1cbiJdLCJuYW1lcyI6WyJUZXJtaW5hbEhhc2hNYW5hZ2VyIiwicmVmcmVzaElnbm9yZWRGaWVsZExpc3RzIiwicmVnaW9uIiwiX2NsaWVudEFwaUNsaWVudCIsImdldFNwZWNpZmljYXRpb25zQnlIYXNoIiwic3BlY2lmaWNhdGlvbnNIYXNoIiwiX3NwZWNpZmljYXRpb25zVHJlZSIsImdldEl0ZW1zQnlIYXNoIiwiZ2V0U3BlY2lmaWNhdGlvbnNIYXNoZXNCeUhhc2giLCJnZXRIYXNoZXNCeUhhc2giLCJnZXRQb3NpdGlvbnNCeUhhc2giLCJwb3NpdGlvbnNIYXNoIiwiX3Bvc2l0aW9uc1RyZWUiLCJnZXRQb3NpdGlvbnNIYXNoZXNCeUhhc2giLCJnZXRPcmRlcnNCeUhhc2giLCJvcmRlcnNIYXNoIiwiX29yZGVyc1RyZWUiLCJnZXRPcmRlcnNIYXNoZXNCeUhhc2giLCJyZWNvcmRTcGVjaWZpY2F0aW9ucyIsInNlcnZlck5hbWUiLCJhY2NvdW50VHlwZSIsImNvbm5lY3Rpb25JZCIsImluc3RhbmNlSW5kZXgiLCJzcGVjaWZpY2F0aW9ucyIsInJlY29yZEl0ZW1zIiwidXBkYXRlU3BlY2lmaWNhdGlvbnMiLCJyZW1vdmVkU3ltYm9scyIsInBhcmVudEhhc2giLCJ1cGRhdGVJdGVtcyIsInJlY29yZFBvc2l0aW9ucyIsImFjY291bnRJZCIsInBvc2l0aW9ucyIsInVwZGF0ZVBvc2l0aW9ucyIsInJlbW92ZWRQb3NpdGlvbnMiLCJyZWNvcmRPcmRlcnMiLCJvcmRlcnMiLCJ1cGRhdGVPcmRlcnMiLCJjb21wbGV0ZWRPcmRlcnMiLCJnZXRMYXN0VXNlZFNwZWNpZmljYXRpb25IYXNoZXMiLCJnZXRMYXN0VXNlZEhhc2hlcyIsImdldExhc3RVc2VkUG9zaXRpb25IYXNoZXMiLCJnZXRMYXN0VXNlZE9yZGVySGFzaGVzIiwicmVtb3ZlQ29ubmVjdGlvblJlZmVyZW5jZXMiLCJyZW1vdmVTcGVjaWZpY2F0aW9uUmVmZXJlbmNlIiwicmVtb3ZlUG9zaXRpb25SZWZlcmVuY2UiLCJyZW1vdmVPcmRlclJlZmVyZW5jZSIsImFkZFNwZWNpZmljYXRpb25SZWZlcmVuY2UiLCJoYXNoIiwiYWRkUmVmZXJlbmNlIiwicmVtb3ZlUmVmZXJlbmNlIiwiYWRkUG9zaXRpb25SZWZlcmVuY2UiLCJhZGRPcmRlclJlZmVyZW5jZSIsImdldEl0ZW1IYXNoIiwiaXRlbSIsInR5cGUiLCJoYXNoRmllbGRzIiwiZ2V0SGFzaGluZ0lnbm9yZWRGaWVsZExpc3RzIiwiT2JqZWN0IiwiYXNzaWduIiwiZzEiLCJzcGVjaWZpY2F0aW9uIiwiZm9yRWFjaCIsImZpZWxkIiwiZzIiLCJfZ2V0SGFzaCIsInBvc2l0aW9uIiwib3JkZXIiLCJvYmoiLCJpbnRlZ2VyS2V5cyIsImpzb25JdGVtIiwic3RyaW5naWZ5Iiwib2JqRnJvbUpzb24iLCJrZXkiLCJpbmNsdWRlcyIsInRvRml4ZWQiLCJBcnJheSIsImlzQXJyYXkiLCJtYXAiLCJqb2luIiwiZ2V0VGltZSIsIkpTT04iLCJwcm9wcyIsImtleXMiLCJrZXlJdGVtIiwicGFyc2VGbG9hdCIsImNyeXB0byIsIk1ENSIsInRvU3RyaW5nIiwiX3N0b3AiLCJzdG9wIiwiY29uc3RydWN0b3IiLCJjbGllbnRBcGlDbGllbnQiLCJrZWVwSGFzaFRyZWVzIiwiUmVmZXJlbmNlVHJlZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztlQU1xQkE7OztpRUFORjtzRUFDTzs7Ozs7O0FBS1gsSUFBQSxBQUFNQSxzQkFBTixNQUFNQTtJQWNuQjs7OztHQUlDLEdBQ0QsTUFBTUMseUJBQXlCQyxNQUFNLEVBQUU7UUFDckMsTUFBTSxJQUFJLENBQUNDLGdCQUFnQixDQUFDRix3QkFBd0IsQ0FBQ0M7SUFDdkQ7SUFFQTs7OztHQUlDLEdBQ0RFLHdCQUF3QkMsa0JBQWtCLEVBQUM7UUFDekMsT0FBTyxJQUFJLENBQUNDLG1CQUFtQixDQUFDQyxjQUFjLENBQUNGO0lBQ2pEO0lBRUE7Ozs7R0FJQyxHQUNERyw4QkFBOEJILGtCQUFrQixFQUFDO1FBQy9DLE9BQU8sSUFBSSxDQUFDQyxtQkFBbUIsQ0FBQ0csZUFBZSxDQUFDSjtJQUNsRDtJQUVBOzs7O0dBSUMsR0FDREssbUJBQW1CQyxhQUFhLEVBQUU7UUFDaEMsT0FBTyxJQUFJLENBQUNDLGNBQWMsQ0FBQ0wsY0FBYyxDQUFDSTtJQUM1QztJQUVBOzs7O0dBSUMsR0FDREUseUJBQXlCRixhQUFhLEVBQUU7UUFDdEMsT0FBTyxJQUFJLENBQUNDLGNBQWMsQ0FBQ0gsZUFBZSxDQUFDRTtJQUM3QztJQUVBOzs7O0dBSUMsR0FDREcsZ0JBQWdCQyxVQUFVLEVBQUM7UUFDekIsT0FBTyxJQUFJLENBQUNDLFdBQVcsQ0FBQ1QsY0FBYyxDQUFDUTtJQUN6QztJQUVBOzs7O0dBSUMsR0FDREUsc0JBQXNCRixVQUFVLEVBQUU7UUFDaEMsT0FBTyxJQUFJLENBQUNDLFdBQVcsQ0FBQ1AsZUFBZSxDQUFDTTtJQUMxQztJQUVBOzs7Ozs7OztHQVFDLEdBQ0RHLHFCQUFxQkMsVUFBVSxFQUFFQyxXQUFXLEVBQUVDLFlBQVksRUFDeERDLGFBQWEsRUFBRUMsY0FBYyxFQUFFO1FBQy9CLE9BQU8sSUFBSSxDQUFDakIsbUJBQW1CLENBQUNrQixXQUFXLENBQUNMLFlBQVlDLGFBQWFDLGNBQ25FQyxlQUFlQztJQUNuQjtJQUVBOzs7Ozs7Ozs7O0dBVUMsR0FDRCxzQ0FBc0M7SUFDdENFLHFCQUFxQk4sVUFBVSxFQUFFQyxXQUFXLEVBQUVDLFlBQVksRUFDeERDLGFBQWEsRUFBRUMsY0FBYyxFQUFFRyxjQUFjLEVBQUVDLFVBQVUsRUFBRTtRQUMzRCxPQUFPLElBQUksQ0FBQ3JCLG1CQUFtQixDQUFDc0IsV0FBVyxDQUFDVCxZQUFZQyxhQUFhQyxjQUNuRUMsZUFBZUMsZ0JBQWdCRyxnQkFBZ0JDO0lBQ25EO0lBRUE7Ozs7Ozs7O0dBUUMsR0FDREUsZ0JBQWdCQyxTQUFTLEVBQUVWLFdBQVcsRUFBRUMsWUFBWSxFQUFFQyxhQUFhLEVBQUVTLFNBQVMsRUFBRTtRQUM5RSxPQUFPLElBQUksQ0FBQ25CLGNBQWMsQ0FBQ1ksV0FBVyxDQUFDTSxXQUFXVixhQUFhQyxjQUFjQyxlQUFlUztJQUM5RjtJQUVBOzs7Ozs7Ozs7O0dBVUMsR0FDREMsZ0JBQWdCRixTQUFTLEVBQUVWLFdBQVcsRUFBRUMsWUFBWSxFQUNsREMsYUFBYSxFQUFFUyxTQUFTLEVBQUVFLGdCQUFnQixFQUFFTixVQUFVLEVBQUU7UUFDeEQsT0FBTyxJQUFJLENBQUNmLGNBQWMsQ0FBQ2dCLFdBQVcsQ0FBQ0UsV0FBV1YsYUFBYUMsY0FDN0RDLGVBQWVTLFdBQVdFLGtCQUFrQk47SUFDaEQ7SUFFQTs7Ozs7Ozs7R0FRQyxHQUNETyxhQUFhSixTQUFTLEVBQUVWLFdBQVcsRUFBRUMsWUFBWSxFQUFFQyxhQUFhLEVBQUVhLE1BQU0sRUFBRTtRQUN4RSxPQUFPLElBQUksQ0FBQ25CLFdBQVcsQ0FBQ1EsV0FBVyxDQUFDTSxXQUFXVixhQUFhQyxjQUFjQyxlQUFlYTtJQUMzRjtJQUVBOzs7Ozs7Ozs7O0dBVUMsR0FDREMsYUFBYU4sU0FBUyxFQUFFVixXQUFXLEVBQUVDLFlBQVksRUFDL0NDLGFBQWEsRUFBRWEsTUFBTSxFQUFFRSxlQUFlLEVBQUVWLFVBQVUsRUFBRTtRQUNwRCxPQUFPLElBQUksQ0FBQ1gsV0FBVyxDQUFDWSxXQUFXLENBQUNFLFdBQVdWLGFBQWFDLGNBQzFEQyxlQUFlYSxRQUFRRSxpQkFBaUJWO0lBQzVDO0lBRUE7Ozs7R0FJQyxHQUNEVywrQkFBK0JuQixVQUFVLEVBQUU7UUFDekMsT0FBTyxJQUFJLENBQUNiLG1CQUFtQixDQUFDaUMsaUJBQWlCLENBQUNwQjtJQUNwRDtJQUVBOzs7O0dBSUMsR0FDRHFCLDBCQUEwQlYsU0FBUyxFQUFFO1FBQ25DLE9BQU8sSUFBSSxDQUFDbEIsY0FBYyxDQUFDMkIsaUJBQWlCLENBQUNUO0lBQy9DO0lBRUE7Ozs7R0FJQyxHQUNEVyx1QkFBdUJYLFNBQVMsRUFBRTtRQUNoQyxPQUFPLElBQUksQ0FBQ2QsV0FBVyxDQUFDdUIsaUJBQWlCLENBQUNUO0lBQzVDO0lBRUE7Ozs7R0FJQyxHQUNEWSwyQkFBMkJyQixZQUFZLEVBQUVDLGFBQWEsRUFBRTtRQUN0RCxJQUFJLENBQUNxQiw0QkFBNEIsQ0FBQ3RCLGNBQWNDO1FBQ2hELElBQUksQ0FBQ3NCLHVCQUF1QixDQUFDdkIsY0FBY0M7UUFDM0MsSUFBSSxDQUFDdUIsb0JBQW9CLENBQUN4QixjQUFjQztJQUMxQztJQUVBOzs7OztHQUtDLEdBQ0R3QiwwQkFBMEJDLElBQUksRUFBRTFCLFlBQVksRUFBRUMsYUFBYSxFQUFFO1FBQzNELElBQUksQ0FBQ2hCLG1CQUFtQixDQUFDMEMsWUFBWSxDQUFDRCxNQUFNMUIsY0FBY0M7SUFDNUQ7SUFFQTs7OztHQUlDLEdBQ0RxQiw2QkFBNkJ0QixZQUFZLEVBQUVDLGFBQWEsRUFBRTtRQUN4RCxJQUFJLENBQUNoQixtQkFBbUIsQ0FBQzJDLGVBQWUsQ0FBQzVCLGNBQWNDO0lBQ3pEO0lBRUE7Ozs7O0dBS0MsR0FDRDRCLHFCQUFxQkgsSUFBSSxFQUFFMUIsWUFBWSxFQUFFQyxhQUFhLEVBQUU7UUFDdEQsSUFBSSxDQUFDVixjQUFjLENBQUNvQyxZQUFZLENBQUNELE1BQU0xQixjQUFjQztJQUN2RDtJQUVBOzs7OztHQUtDLEdBQ0RzQix3QkFBd0J2QixZQUFZLEVBQUVDLGFBQWEsRUFBRTtRQUNuRCxJQUFJLENBQUNWLGNBQWMsQ0FBQ3FDLGVBQWUsQ0FBQzVCLGNBQWNDO0lBQ3BEO0lBRUE7Ozs7O0dBS0MsR0FDRDZCLGtCQUFrQkosSUFBSSxFQUFFMUIsWUFBWSxFQUFFQyxhQUFhLEVBQUU7UUFDbkQsSUFBSSxDQUFDTixXQUFXLENBQUNnQyxZQUFZLENBQUNELE1BQU0xQixjQUFjQztJQUNwRDtJQUVBOzs7O0dBSUMsR0FDRHVCLHFCQUFxQnhCLFlBQVksRUFBRUMsYUFBYSxFQUFFO1FBQ2hELElBQUksQ0FBQ04sV0FBVyxDQUFDaUMsZUFBZSxDQUFDNUIsY0FBY0M7SUFDakQ7SUFFQSxzQ0FBc0M7SUFDdEM4QixZQUFZQyxJQUFJLEVBQUVDLElBQUksRUFBRWxDLFdBQVcsRUFBRWxCLE1BQU0sRUFBRTtRQUMzQyxNQUFNcUQsYUFBYSxJQUFJLENBQUNwRCxnQkFBZ0IsQ0FBQ3FELDJCQUEyQixDQUFDdEQ7UUFDckVtRCxPQUFPSSxPQUFPQyxNQUFNLENBQUMsQ0FBQyxHQUFHTDtRQUN6QixPQUFPQztZQUNQLEtBQUs7Z0JBQ0gsSUFBR2xDLGdCQUFnQixZQUFZO29CQUM3Qm1DLFdBQVdJLEVBQUUsQ0FBQ0MsYUFBYSxDQUFDQyxPQUFPLENBQUNDLENBQUFBLFFBQVMsT0FBT1QsSUFBSSxDQUFDUyxNQUFNO2dCQUNqRSxPQUFPLElBQUcxQyxnQkFBZ0IsWUFBWTtvQkFDcENtQyxXQUFXUSxFQUFFLENBQUNILGFBQWEsQ0FBQ0MsT0FBTyxDQUFDQyxDQUFBQSxRQUFTLE9BQU9ULElBQUksQ0FBQ1MsTUFBTTtnQkFDakU7Z0JBQ0EsT0FBTyxJQUFJLENBQUNFLFFBQVEsQ0FBQ1gsTUFBTWpDLGFBQWE7b0JBQUM7aUJBQVM7WUFDcEQsS0FBSztnQkFDSCxJQUFHQSxnQkFBZ0IsWUFBWTtvQkFDN0JtQyxXQUFXSSxFQUFFLENBQUNNLFFBQVEsQ0FBQ0osT0FBTyxDQUFDQyxDQUFBQSxRQUFTLE9BQU9ULElBQUksQ0FBQ1MsTUFBTTtnQkFDNUQsT0FBTyxJQUFHMUMsZ0JBQWdCLFlBQVk7b0JBQ3BDbUMsV0FBV1EsRUFBRSxDQUFDRSxRQUFRLENBQUNKLE9BQU8sQ0FBQ0MsQ0FBQUEsUUFBUyxPQUFPVCxJQUFJLENBQUNTLE1BQU07Z0JBQzVEO2dCQUNBLE9BQU8sSUFBSSxDQUFDRSxRQUFRLENBQUNYLE1BQU1qQyxhQUFhO29CQUFDO2lCQUFRO1lBQ25ELEtBQUs7Z0JBQ0gsSUFBR0EsZ0JBQWdCLFlBQVk7b0JBQzdCbUMsV0FBV0ksRUFBRSxDQUFDTyxLQUFLLENBQUNMLE9BQU8sQ0FBQ0MsQ0FBQUEsUUFBUyxPQUFPVCxJQUFJLENBQUNTLE1BQU07Z0JBQ3pELE9BQU8sSUFBRzFDLGdCQUFnQixZQUFZO29CQUNwQ21DLFdBQVdRLEVBQUUsQ0FBQ0csS0FBSyxDQUFDTCxPQUFPLENBQUNDLENBQUFBLFFBQVMsT0FBT1QsSUFBSSxDQUFDUyxNQUFNO2dCQUN6RDtnQkFDQSxPQUFPLElBQUksQ0FBQ0UsUUFBUSxDQUFDWCxNQUFNakMsYUFBYTtvQkFBQztpQkFBUTtRQUNuRDtJQUNGO0lBRUE0QyxTQUFTRyxHQUFHLEVBQUUvQyxXQUFXLEVBQUVnRCxXQUFXLEVBQUU7UUFDdEMsSUFBSUMsV0FBVztRQUNmLElBQUdqRCxnQkFBZ0IsWUFBWTtZQUM3QixNQUFNa0QsWUFBWSxDQUFDQyxhQUFhQztnQkFDOUIsSUFBRyxPQUFPRCxnQkFBZ0IsVUFBVTtvQkFDbEMsSUFBR0gsWUFBWUssUUFBUSxDQUFDRCxNQUFNO3dCQUM1QixPQUFPRDtvQkFDVCxPQUFPO3dCQUNMLE9BQU9BLFlBQVlHLE9BQU8sQ0FBQztvQkFDN0I7Z0JBQ0YsT0FBTyxJQUFHQyxNQUFNQyxPQUFPLENBQUNMLGNBQWM7b0JBQ3BDLE9BQU8sQ0FBQyxDQUFDLEVBQUVBLFlBQVlNLEdBQUcsQ0FBQ3hCLENBQUFBLE9BQVFpQixVQUFVakIsT0FBT3lCLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDbEUsT0FBTyxJQUFJUCxnQkFBZ0IsTUFBTTtvQkFDL0IsT0FBT0E7Z0JBQ1QsT0FBTyxJQUFJLE9BQU9BLGdCQUFnQixZQUFZQSxZQUFZUSxPQUFPLEVBQUM7b0JBQ2hFLE9BQU9DLEtBQUtWLFNBQVMsQ0FBQ0M7Z0JBQ3hCO2dCQUVBLElBQUlVLFFBQVF4QixPQUNUeUIsSUFBSSxDQUFDWCxhQUNMTSxHQUFHLENBQUNNLENBQUFBLFVBQVcsQ0FBQyxDQUFDLEVBQUVBLFFBQVEsRUFBRSxFQUFFYixVQUFVQyxXQUFXLENBQUNZLFFBQVEsRUFBRUEsU0FBUyxDQUFDLEVBQ3pFTCxJQUFJLENBQUM7Z0JBQ1IsT0FBTyxDQUFDLENBQUMsRUFBRUcsTUFBTSxDQUFDLENBQUM7WUFDckI7WUFFQVosV0FBV0MsVUFBVUg7UUFDdkIsT0FBTyxJQUFHL0MsZ0JBQWdCLFlBQVk7WUFDcEMsTUFBTWtELFlBQVksQ0FBQ0MsYUFBYUM7Z0JBQzlCLElBQUcsT0FBT0QsZ0JBQWdCLFVBQVU7b0JBQ2xDLElBQUdILFlBQVlLLFFBQVEsQ0FBQ0QsTUFBTTt3QkFDNUIsT0FBT0Q7b0JBQ1QsT0FBTzt3QkFDTCxPQUFPYSxXQUFXYixZQUFZRyxPQUFPLENBQUM7b0JBQ3hDO2dCQUNGLE9BQU8sSUFBR0MsTUFBTUMsT0FBTyxDQUFDTCxjQUFjO29CQUNwQyxPQUFPLENBQUMsQ0FBQyxFQUFFQSxZQUFZTSxHQUFHLENBQUN4QixDQUFBQSxPQUFRaUIsVUFBVWpCLE9BQU95QixJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ2xFLE9BQU8sSUFBSVAsZ0JBQWdCLE1BQU07b0JBQy9CLE9BQU9BO2dCQUNULE9BQU8sSUFBSSxPQUFPQSxnQkFBZ0IsWUFBWUEsWUFBWVEsT0FBTyxFQUFDO29CQUNoRSxPQUFPQyxLQUFLVixTQUFTLENBQUNDO2dCQUN4QjtnQkFFQSxJQUFJVSxRQUFReEIsT0FDVHlCLElBQUksQ0FBQ1gsYUFDTE0sR0FBRyxDQUFDTSxDQUFBQSxVQUFXLENBQUMsQ0FBQyxFQUFFQSxRQUFRLEVBQUUsRUFBRWIsVUFBVUMsV0FBVyxDQUFDWSxRQUFRLEVBQUVBLFNBQVMsQ0FBQyxFQUN6RUwsSUFBSSxDQUFDO2dCQUNSLE9BQU8sQ0FBQyxDQUFDLEVBQUVHLE1BQU0sQ0FBQyxDQUFDO1lBQ3JCO1lBRUFaLFdBQVdDLFVBQVVIO1FBQ3ZCO1FBQ0EsT0FBT2tCLGlCQUFNLENBQUNDLEdBQUcsQ0FBQ2pCLFVBQVVrQixRQUFRO0lBQ3RDO0lBRUFDLFFBQVE7UUFDTixJQUFJLENBQUNsRixtQkFBbUIsQ0FBQ21GLElBQUk7UUFDN0IsSUFBSSxDQUFDN0UsY0FBYyxDQUFDNkUsSUFBSTtRQUN4QixJQUFJLENBQUN6RSxXQUFXLENBQUN5RSxJQUFJO0lBQ3ZCO0lBL1ZBOzs7O0dBSUMsR0FDREMsWUFBWUMsZUFBZSxFQUFFQyxnQkFBZ0IsS0FBSyxDQUFFO1FBQ2xELElBQUksQ0FBQ3pGLGdCQUFnQixHQUFHd0Y7UUFDeEIsSUFBSSxDQUFDckYsbUJBQW1CLEdBQUcsSUFBSXVGLHNCQUFhLENBQUMsSUFBSSxFQUFFLFVBQVUsa0JBQWtCLE1BQU1EO1FBQ3JGLElBQUksQ0FBQ2hGLGNBQWMsR0FBRyxJQUFJaUYsc0JBQWEsQ0FBQyxJQUFJLEVBQUUsTUFBTSxhQUFhLE9BQU9EO1FBQ3hFLElBQUksQ0FBQzVFLFdBQVcsR0FBRyxJQUFJNkUsc0JBQWEsQ0FBQyxJQUFJLEVBQUUsTUFBTSxVQUFVLE9BQU9EO0lBQ3BFO0FBdVZGIn0=