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)
399 lines (398 loc) • 53 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return ReferenceTree;
}
});
const _fuse = /*#__PURE__*/ _interop_require_default(require("fuse.js"));
const _buffer = require("buffer");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
const isNodeServer = typeof process !== "undefined" && process.release && process.release.name === "node";
const isSSR = !isBrowser && isNodeServer;
let ReferenceTree = class ReferenceTree {
/**
* Returns data by hash
* @param {string} hash records hash
* @returns {[id: string]: Object}
*/ // eslint-disable-next-line complexity
getItemsByHash(hash) {
const data = this._dataByHash[hash];
if (!data) {
return null;
} else if (!data.parentHash) {
return data.data;
} else {
/**
* If specified hash is not a base hash, build a chain of hashes
* to the base one, apply all changes and return
*/ let hashChain = [
hash
];
hashChain.unshift(data.parentHash);
let parentData = this._dataByHash[data.parentHash];
while(parentData.parentHash){
hashChain.unshift(parentData.parentHash);
parentData = this._dataByHash[parentData.parentHash];
}
const state = Object.assign({}, this._dataByHash[hashChain.shift()].data);
for (let chainHash of hashChain){
const chainData = this._dataByHash[chainHash];
Object.keys(chainData.data).forEach((id)=>{
state[id] = chainData.data[id];
});
chainData.removedItemIds.forEach((id)=>{
delete state[id];
});
}
return state;
}
}
/**
* Returns hash data by hash
* @param {string} hash records hash
* @returns {[id: string]: string}
*/ getHashesByHash(hash) {
const data = this._dataByHash[hash];
if (!data) {
return null;
} else if (!data.parentHash) {
return data.hashes;
} else {
let hashChain = [
hash
];
hashChain.unshift(data.parentHash);
let parentData = this._dataByHash[data.parentHash];
while(parentData.parentHash){
hashChain.unshift(parentData.parentHash);
parentData = this._dataByHash[parentData.parentHash];
}
const state = Object.assign({}, this._dataByHash[hashChain.shift()].hashes);
for (let chainHash of hashChain){
const chainData = this._dataByHash[chainHash];
Object.keys(chainData.hashes).forEach((id)=>{
state[id] = chainData.hashes[id];
});
chainData.removedItemIds.forEach((id)=>{
delete state[id];
});
}
return state;
}
}
/**
* Creates an entry for data and returns hash
* @param {string} categoryName category name
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {Object[]} items items to record
* @returns {string} data hash
*/ recordItems(categoryName, accountType, connectionId, instanceIndex, items) {
const region = instanceIndex.split(":")[0];
const hashDictionary = {};
const dataDictionary = {};
if (!items.length) {
return null;
}
for (let item of items){
const hash = this._terminalHashManager.getItemHash(item, this._dataType, accountType, region);
dataDictionary[item[this._idKey]] = item;
hashDictionary[item[this._idKey]] = hash;
}
const dictionaryHash = this._getArrayXor(Object.values(hashDictionary));
this._updateCategoryRecord(categoryName, dictionaryHash);
this.removeReference(connectionId, instanceIndex);
if (this._dataByHash[dictionaryHash]) {
this.addReference(dictionaryHash, connectionId, instanceIndex);
} else {
this._dataByHash[dictionaryHash] = {
hashes: hashDictionary,
data: dataDictionary,
removedItemIds: [],
parentHash: null,
childHashes: [],
lastUpdated: Date.now(),
references: {
[connectionId]: [
instanceIndex
]
}
};
}
return dictionaryHash;
}
/**
* Updates data and returns new hash
* @param {string} categoryName category name
* @param {string} accountType account type
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
* @param {Object[]} items items array
* @param {string[]} removedItemIds removed item ids
* @param {string} parentHash parent hash
* @returns {string} updated dictionary hash
*/ // eslint-disable-next-line complexity
updateItems(categoryName, accountType, connectionId, instanceIndex, items, removedItemIds, parentHash) {
if (!parentHash) {
return this.recordItems(categoryName, accountType, connectionId, instanceIndex, items);
}
const region = instanceIndex.split(":")[0];
const hashDictionary = {};
const dataDictionary = {};
let parentData = this.getHashesByHash(parentHash);
if (!parentData) {
throw Error("Parent data doesn't exist");
} else {
const parentHashDictionary = Object.assign({}, parentData);
for (let item of items){
const hash = this._terminalHashManager.getItemHash(item, this._dataType, accountType, region);
dataDictionary[item[this._idKey]] = item;
hashDictionary[item[this._idKey]] = hash;
parentHashDictionary[item[this._idKey]] = hash;
}
for (let removedId of removedItemIds){
delete parentHashDictionary[removedId];
}
const dictionaryHash = this._getArrayXor(Object.values(parentHashDictionary));
this._updateCategoryRecord(categoryName, dictionaryHash);
if (dictionaryHash !== parentHash) {
this.removeReference(connectionId, instanceIndex);
if (this._dataByHash[dictionaryHash]) {
this.addReference(dictionaryHash, connectionId, instanceIndex);
} else if (dictionaryHash) {
this._dataByHash[dictionaryHash] = {
hashes: hashDictionary,
data: dataDictionary,
parentHash,
removedItemIds,
childHashes: [],
lastUpdated: Date.now(),
references: {
[connectionId]: [
instanceIndex
]
}
};
this._dataByHash[parentHash].childHashes.push(dictionaryHash);
}
} else {
this.removeReference(connectionId, instanceIndex);
this.addReference(dictionaryHash, connectionId, instanceIndex);
}
return dictionaryHash;
}
}
/**
* Returns the list of last used records hashes
* @param {string} categoryName category name
* @returns {string[]} last used records hashes
*/ getLastUsedHashes(categoryName) {
let searchHashes = [];
const getTopHashes = (category, hashAmount)=>{
const categoryData = this._hashesByCategory[category];
if (!categoryData) {
return [];
} else {
let hashesArray = [];
if (!hashAmount) {
hashAmount = Infinity;
}
const keys = Object.keys(categoryData);
keys.sort((a, b)=>b - a);
for (let key of keys){
hashesArray = hashesArray.concat(categoryData[key]);
if (hashesArray.length > hashAmount) {
hashesArray = hashesArray.slice(0, hashAmount);
break;
}
}
return hashesArray;
}
};
if (this._useFuzzySearch) {
let results = this._getSimilarCategoryNames(categoryName);
// include all results from exact match
if (results[0] === categoryName) {
searchHashes = getTopHashes(categoryName);
results = results.slice(1);
}
// include 3 latest updated hashes from close matches
results.forEach((category)=>{
searchHashes = searchHashes.concat(getTopHashes(category, 3));
});
} else {
searchHashes = getTopHashes(categoryName, 20);
}
searchHashes = searchHashes.slice(0, 20);
return searchHashes;
}
/**
* Adds a reference from a terminal state instance index to a records hash
* @param {string} hash records hash
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ // eslint-disable-next-line complexity
addReference(hash, connectionId, instanceIndex) {
if (!this._dataByHash[hash]) {
throw Error(`Can't add reference - ${this._dataType} data for hash ${hash} doesn't exist`);
}
const references = this._dataByHash[hash].references;
if (!references[connectionId]) {
references[connectionId] = [
instanceIndex
];
} else {
if (!references[connectionId].includes(instanceIndex)) {
references[connectionId].push(instanceIndex);
}
}
this._dataByHash[hash].lastUpdated = Date.now();
}
/**
* Removes a reference from a terminal state instance index to a records hash
* @param {string} connectionId connection id
* @param {string} instanceIndex instance index
*/ removeReference(connectionId, instanceIndex) {
Object.keys(this._dataByHash).forEach((hash)=>{
const references = this._dataByHash[hash].references;
if (references[connectionId]) {
const index = references[connectionId].findIndex((instance)=>instanceIndex === instance);
if (index !== -1) {
references[connectionId].splice(index, 1);
}
if (!references[connectionId].length) {
delete references[connectionId];
}
}
});
}
_getSimilarCategoryNames(categoryName) {
const categoryNameList = Object.keys(this._hashesByCategory);
const fuse = new _fuse.default(categoryNameList, {
threshold: 0.3
});
return fuse.search(categoryName).map((result)=>result.item);
}
/**
* Calculates hash from array of hashes
* @param {String[]} hexArray array of hashes
* @returns {string} resulting hash
*/ _getArrayXor(hexArray) {
return hexArray.length ? hexArray.reduce((a, b)=>this._getHexXor(a, b)) : null;
}
_getHexXor(hex1, hex2) {
const buf1 = _buffer.Buffer.from(hex1, "hex");
const buf2 = _buffer.Buffer.from(hex2, "hex");
// eslint-disable-next-line no-bitwise
const bufResult = buf1.map((b, i)=>b ^ buf2[i]);
return isBrowser || isSSR ? Array.prototype.map.call(bufResult, (byte)=>("0" + (byte & 0xFF).toString(16)).slice(-2)).join("") : bufResult.toString("hex");
}
_updateCategoryRecord(categoryName, hash) {
if (!hash) {
return;
}
const date = Date.now();
this._removeCategoryRecord(categoryName, hash);
if (!this._hashesByCategory[categoryName]) {
this._hashesByCategory[categoryName] = {};
}
if (!this._hashesByCategory[categoryName][date]) {
this._hashesByCategory[categoryName][date] = [];
}
this._hashesByCategory[categoryName][date].push(hash);
}
_removeCategoryRecord(categoryName, hash) {
if (this._hashesByCategory[categoryName]) {
const dates = Object.keys(this._hashesByCategory[categoryName]);
dates.forEach((date)=>{
if (this._hashesByCategory[categoryName][date].includes(hash)) {
this._hashesByCategory[categoryName][date] = this._hashesByCategory[categoryName][date].filter((item)=>item !== hash);
if (this._hashesByCategory[categoryName][date].length === 0) {
delete this._hashesByCategory[categoryName][date];
}
}
});
if (Object.keys(this._hashesByCategory[categoryName]).length === 0) {
delete this._hashesByCategory[categoryName];
}
}
}
_optimizeTreesJob() {
const now = Date.now();
// eslint-disable-next-line complexity
Object.keys(this._dataByHash).forEach((hash)=>{
const data = this._dataByHash[hash];
if (data.lastUpdated <= now - this._recordExpirationTime && !Object.keys(data.references).length && data.childHashes.length < 2) {
if (data.childHashes.length === 1) {
const childHash = data.childHashes[0];
const childData = this._dataByHash[childHash];
if (data.parentHash) {
const combinedChanges = Object.assign({}, data.data, childData.data);
const combinedHashes = Object.assign({}, data.hashes, childData.hashes);
const childDataIds = Object.keys(childData.data);
let combinedRemovedIds = data.removedItemIds.filter((id)=>!childDataIds.includes(id)).concat(childData.removedItemIds);
childData.data = combinedChanges;
childData.hashes = combinedHashes;
childData.removedItemIds = combinedRemovedIds;
childData.parentHash = data.parentHash;
this._dataByHash[data.parentHash].childHashes.push(childHash);
} else {
const childItems = this.getItemsByHash(childHash);
const childHashes = this.getHashesByHash(childHash);
childData.data = childItems;
childData.hashes = childHashes;
childData.removedItemIds = [];
childData.parentHash = null;
}
}
if (data.parentHash) {
const parentData = this._dataByHash[data.parentHash];
if (parentData) {
parentData.childHashes = parentData.childHashes.filter((itemHash)=>hash !== itemHash);
}
}
delete this._dataByHash[hash];
const categories = Object.keys(this._hashesByCategory);
categories.forEach((category)=>{
this._removeCategoryRecord(category, hash);
});
}
});
}
/**
* Stops reference tree optimize job & clears interval
*/ stop() {
clearInterval(this._interval);
}
/**
* Constructs the instance of reference tree
* @param {TerminalHashManager} terminalHashManager terminal hash manager
* @param {string} idKey field name that contains the item id
* @param {string} dataType data type
* @param {boolean} [useFuzzySearch] whether to use fuzzy search on nearby categories
* @param {boolean} [keepHashTrees] if set to true, unused data will not be cleared (for use in debugging)
*/ constructor(terminalHashManager, idKey, dataType, useFuzzySearch = false, keepHashTrees = false){
this._terminalHashManager = terminalHashManager;
this._idKey = idKey;
this._dataByHash = {};
this._hashesByCategory = {};
this._dataType = dataType;
this._useFuzzySearch = useFuzzySearch;
this._recordExpirationTime = 10 * 60 * 1000;
if (!keepHashTrees) {
this._optimizeTreesJob = this._optimizeTreesJob.bind(this);
this._interval = setInterval(this._optimizeTreesJob, 5 * 60 * 1000);
}
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgRnVzZSBmcm9tICdmdXNlLmpzJztcbmltcG9ydCB7IEJ1ZmZlciB9IGZyb20gJ2J1ZmZlcic7XG5cbmNvbnN0IGlzQnJvd3NlciA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiB3aW5kb3cuZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnO1xuY29uc3QgaXNOb2RlU2VydmVyID0gdHlwZW9mIHByb2Nlc3MgIT09ICd1bmRlZmluZWQnICYmIHByb2Nlc3MucmVsZWFzZSAmJiBwcm9jZXNzLnJlbGVhc2UubmFtZSA9PT0gJ25vZGUnO1xuY29uc3QgaXNTU1IgPSAhaXNCcm93c2VyICYmIGlzTm9kZVNlcnZlcjtcblxuLyoqXG4gKiBDbGFzcyBmb3IgbWFuYWdpbmcgYSBkYXRhIHRyZWUgd2l0aCBoYXNoIHJlZmVyZW5jZXNcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUmVmZXJlbmNlVHJlZSB7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgdGhlIGluc3RhbmNlIG9mIHJlZmVyZW5jZSB0cmVlXG4gICAqIEBwYXJhbSB7VGVybWluYWxIYXNoTWFuYWdlcn0gdGVybWluYWxIYXNoTWFuYWdlciB0ZXJtaW5hbCBoYXNoIG1hbmFnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkS2V5IGZpZWxkIG5hbWUgdGhhdCBjb250YWlucyB0aGUgaXRlbSBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gZGF0YVR5cGUgZGF0YSB0eXBlXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3VzZUZ1enp5U2VhcmNoXSB3aGV0aGVyIHRvIHVzZSBmdXp6eSBzZWFyY2ggb24gbmVhcmJ5IGNhdGVnb3JpZXNcbiAgICogQHBhcmFtIHtib29sZWFufSBba2VlcEhhc2hUcmVlc10gaWYgc2V0IHRvIHRydWUsIHVudXNlZCBkYXRhIHdpbGwgbm90IGJlIGNsZWFyZWQgKGZvciB1c2UgaW4gZGVidWdnaW5nKVxuICAgKi9cbiAgY29uc3RydWN0b3IodGVybWluYWxIYXNoTWFuYWdlciwgaWRLZXksIGRhdGFUeXBlLCB1c2VGdXp6eVNlYXJjaCA9IGZhbHNlLCBrZWVwSGFzaFRyZWVzID0gZmFsc2UpIHtcbiAgICB0aGlzLl90ZXJtaW5hbEhhc2hNYW5hZ2VyID0gdGVybWluYWxIYXNoTWFuYWdlcjtcbiAgICB0aGlzLl9pZEtleSA9IGlkS2V5O1xuICAgIHRoaXMuX2RhdGFCeUhhc2ggPSB7fTtcbiAgICB0aGlzLl9oYXNoZXNCeUNhdGVnb3J5ID0ge307XG4gICAgdGhpcy5fZGF0YVR5cGUgPSBkYXRhVHlwZTtcbiAgICB0aGlzLl91c2VGdXp6eVNlYXJjaCA9IHVzZUZ1enp5U2VhcmNoO1xuICAgIHRoaXMuX3JlY29yZEV4cGlyYXRpb25UaW1lID0gMTAgKiA2MCAqIDEwMDA7XG4gICAgaWYoIWtlZXBIYXNoVHJlZXMpIHtcbiAgICAgIHRoaXMuX29wdGltaXplVHJlZXNKb2IgPSB0aGlzLl9vcHRpbWl6ZVRyZWVzSm9iLmJpbmQodGhpcyk7XG4gICAgICB0aGlzLl9pbnRlcnZhbCA9IHNldEludGVydmFsKHRoaXMuX29wdGltaXplVHJlZXNKb2IsIDUgKiA2MCAqIDEwMDApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFzaCByZWNvcmRzIGhhc2hcbiAgICogQHJldHVybnMge1tpZDogc3RyaW5nXTogT2JqZWN0fVxuICAgKi9cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgZ2V0SXRlbXNCeUhhc2goaGFzaCkge1xuICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhQnlIYXNoW2hhc2hdO1xuICAgIGlmKCFkYXRhKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9IGVsc2UgaWYoIWRhdGEucGFyZW50SGFzaCkge1xuICAgICAgcmV0dXJuIGRhdGEuZGF0YTtcbiAgICB9IGVsc2Uge1xuICAgICAgLyoqXG4gICAgICAgKiBJZiBzcGVjaWZpZWQgaGFzaCBpcyBub3QgYSBiYXNlIGhhc2gsIGJ1aWxkIGEgY2hhaW4gb2YgaGFzaGVzXG4gICAgICAgKiB0byB0aGUgYmFzZSBvbmUsIGFwcGx5IGFsbCBjaGFuZ2VzIGFuZCByZXR1cm5cbiAgICAgICAqL1xuICAgICAgbGV0IGhhc2hDaGFpbiA9IFtoYXNoXTtcbiAgICAgIGhhc2hDaGFpbi51bnNoaWZ0KGRhdGEucGFyZW50SGFzaCk7XG4gICAgICBsZXQgcGFyZW50RGF0YSA9IHRoaXMuX2RhdGFCeUhhc2hbZGF0YS5wYXJlbnRIYXNoXTtcbiAgICAgIHdoaWxlKHBhcmVudERhdGEucGFyZW50SGFzaCkge1xuICAgICAgICBoYXNoQ2hhaW4udW5zaGlmdChwYXJlbnREYXRhLnBhcmVudEhhc2gpO1xuICAgICAgICBwYXJlbnREYXRhID0gdGhpcy5fZGF0YUJ5SGFzaFtwYXJlbnREYXRhLnBhcmVudEhhc2hdO1xuICAgICAgfVxuICAgICAgY29uc3Qgc3RhdGUgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzLl9kYXRhQnlIYXNoW2hhc2hDaGFpbi5zaGlmdCgpXS5kYXRhKTtcbiAgICAgIGZvcihsZXQgY2hhaW5IYXNoIG9mIGhhc2hDaGFpbikge1xuICAgICAgICBjb25zdCBjaGFpbkRhdGEgPSB0aGlzLl9kYXRhQnlIYXNoW2NoYWluSGFzaF07XG4gICAgICAgIE9iamVjdC5rZXlzKGNoYWluRGF0YS5kYXRhKS5mb3JFYWNoKGlkID0+IHtcbiAgICAgICAgICBzdGF0ZVtpZF0gPSBjaGFpbkRhdGEuZGF0YVtpZF07XG4gICAgICAgIH0pO1xuICAgICAgICBjaGFpbkRhdGEucmVtb3ZlZEl0ZW1JZHMuZm9yRWFjaChpZCA9PiB7XG4gICAgICAgICAgZGVsZXRlIHN0YXRlW2lkXTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gc3RhdGU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgaGFzaCBkYXRhIGJ5IGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhc2ggcmVjb3JkcyBoYXNoXG4gICAqIEByZXR1cm5zIHtbaWQ6IHN0cmluZ106IHN0cmluZ31cbiAgICovXG4gIGdldEhhc2hlc0J5SGFzaChoYXNoKSB7XG4gICAgY29uc3QgZGF0YSA9IHRoaXMuX2RhdGFCeUhhc2hbaGFzaF07XG4gICAgaWYoIWRhdGEpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSBpZighZGF0YS5wYXJlbnRIYXNoKSB7XG4gICAgICByZXR1cm4gZGF0YS5oYXNoZXM7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBoYXNoQ2hhaW4gPSBbaGFzaF07XG4gICAgICBoYXNoQ2hhaW4udW5zaGlmdChkYXRhLnBhcmVudEhhc2gpO1xuICAgICAgbGV0IHBhcmVudERhdGEgPSB0aGlzLl9kYXRhQnlIYXNoW2RhdGEucGFyZW50SGFzaF07XG4gICAgICB3aGlsZShwYXJlbnREYXRhLnBhcmVudEhhc2gpIHtcbiAgICAgICAgaGFzaENoYWluLnVuc2hpZnQocGFyZW50RGF0YS5wYXJlbnRIYXNoKTtcbiAgICAgICAgcGFyZW50RGF0YSA9IHRoaXMuX2RhdGFCeUhhc2hbcGFyZW50RGF0YS5wYXJlbnRIYXNoXTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHN0YXRlID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5fZGF0YUJ5SGFzaFtoYXNoQ2hhaW4uc2hpZnQoKV0uaGFzaGVzKTtcbiAgICAgIGZvcihsZXQgY2hhaW5IYXNoIG9mIGhhc2hDaGFpbikge1xuICAgICAgICBjb25zdCBjaGFpbkRhdGEgPSB0aGlzLl9kYXRhQnlIYXNoW2NoYWluSGFzaF07XG4gICAgICAgIE9iamVjdC5rZXlzKGNoYWluRGF0YS5oYXNoZXMpLmZvckVhY2goaWQgPT4ge1xuICAgICAgICAgIHN0YXRlW2lkXSA9IGNoYWluRGF0YS5oYXNoZXNbaWRdO1xuICAgICAgICB9KTtcbiAgICAgICAgY2hhaW5EYXRhLnJlbW92ZWRJdGVtSWRzLmZvckVhY2goaWQgPT4ge1xuICAgICAgICAgIGRlbGV0ZSBzdGF0ZVtpZF07XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHN0YXRlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVudHJ5IGZvciBkYXRhIGFuZCByZXR1cm5zIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNhdGVnb3J5TmFtZSBjYXRlZ29yeSBuYW1lXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50VHlwZSBhY2NvdW50IHR5cGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqIEBwYXJhbSB7T2JqZWN0W119IGl0ZW1zIGl0ZW1zIHRvIHJlY29yZFxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBkYXRhIGhhc2hcbiAgICovXG4gIHJlY29yZEl0ZW1zKGNhdGVnb3J5TmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgaXRlbXMpIHtcbiAgICBjb25zdCByZWdpb24gPSBpbnN0YW5jZUluZGV4LnNwbGl0KCc6JylbMF07XG4gICAgY29uc3QgaGFzaERpY3Rpb25hcnkgPSB7fTtcbiAgICBjb25zdCBkYXRhRGljdGlvbmFyeSA9IHt9O1xuICAgIGlmKCFpdGVtcy5sZW5ndGgpICB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBmb3IobGV0IGl0ZW0gb2YgaXRlbXMpIHtcbiAgICAgIGNvbnN0IGhhc2ggPSB0aGlzLl90ZXJtaW5hbEhhc2hNYW5hZ2VyLmdldEl0ZW1IYXNoKGl0ZW0sIHRoaXMuX2RhdGFUeXBlLCBhY2NvdW50VHlwZSwgcmVnaW9uKTtcbiAgICAgIGRhdGFEaWN0aW9uYXJ5W2l0ZW1bdGhpcy5faWRLZXldXSA9IGl0ZW07XG4gICAgICBoYXNoRGljdGlvbmFyeVtpdGVtW3RoaXMuX2lkS2V5XV0gPSBoYXNoO1xuICAgIH1cbiAgICBjb25zdCBkaWN0aW9uYXJ5SGFzaCA9IHRoaXMuX2dldEFycmF5WG9yKE9iamVjdC52YWx1ZXMoaGFzaERpY3Rpb25hcnkpKTtcbiAgICB0aGlzLl91cGRhdGVDYXRlZ29yeVJlY29yZChjYXRlZ29yeU5hbWUsIGRpY3Rpb25hcnlIYXNoKTtcbiAgICB0aGlzLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICAgIGlmKHRoaXMuX2RhdGFCeUhhc2hbZGljdGlvbmFyeUhhc2hdKSB7XG4gICAgICB0aGlzLmFkZFJlZmVyZW5jZShkaWN0aW9uYXJ5SGFzaCwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fZGF0YUJ5SGFzaFtkaWN0aW9uYXJ5SGFzaF0gPSB7XG4gICAgICAgIGhhc2hlczogaGFzaERpY3Rpb25hcnksXG4gICAgICAgIGRhdGE6IGRhdGFEaWN0aW9uYXJ5LFxuICAgICAgICByZW1vdmVkSXRlbUlkczogW10sXG4gICAgICAgIHBhcmVudEhhc2g6IG51bGwsXG4gICAgICAgIGNoaWxkSGFzaGVzOiBbXSxcbiAgICAgICAgbGFzdFVwZGF0ZWQ6IERhdGUubm93KCksXG4gICAgICAgIHJlZmVyZW5jZXM6IHtbY29ubmVjdGlvbklkXTogW2luc3RhbmNlSW5kZXhdfVxuICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIGRpY3Rpb25hcnlIYXNoO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgZGF0YSBhbmQgcmV0dXJucyBuZXcgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gY2F0ZWdvcnlOYW1lIGNhdGVnb3J5IG5hbWUgXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50VHlwZSBhY2NvdW50IHR5cGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqIEBwYXJhbSB7T2JqZWN0W119IGl0ZW1zIGl0ZW1zIGFycmF5XG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHJlbW92ZWRJdGVtSWRzIHJlbW92ZWQgaXRlbSBpZHNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudEhhc2ggcGFyZW50IGhhc2hcbiAgICogQHJldHVybnMge3N0cmluZ30gdXBkYXRlZCBkaWN0aW9uYXJ5IGhhc2hcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG4gIHVwZGF0ZUl0ZW1zKGNhdGVnb3J5TmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgaXRlbXMsIHJlbW92ZWRJdGVtSWRzLCBwYXJlbnRIYXNoKSB7XG4gICAgaWYoIXBhcmVudEhhc2gpIHtcbiAgICAgIHJldHVybiB0aGlzLnJlY29yZEl0ZW1zKGNhdGVnb3J5TmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgaXRlbXMpO1xuICAgIH1cbiAgICBjb25zdCByZWdpb24gPSBpbnN0YW5jZUluZGV4LnNwbGl0KCc6JylbMF07XG4gICAgY29uc3QgaGFzaERpY3Rpb25hcnkgPSB7fTtcbiAgICBjb25zdCBkYXRhRGljdGlvbmFyeSA9IHt9O1xuICAgIGxldCBwYXJlbnREYXRhID0gdGhpcy5nZXRIYXNoZXNCeUhhc2gocGFyZW50SGFzaCk7XG4gICAgaWYoIXBhcmVudERhdGEpIHtcbiAgICAgIHRocm93IEVycm9yKCdQYXJlbnQgZGF0YSBkb2VzblxcJ3QgZXhpc3QnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgcGFyZW50SGFzaERpY3Rpb25hcnkgPSBPYmplY3QuYXNzaWduKHt9LCBwYXJlbnREYXRhKTtcbiAgICAgIGZvcihsZXQgaXRlbSBvZiBpdGVtcykge1xuICAgICAgICBjb25zdCBoYXNoID0gdGhpcy5fdGVybWluYWxIYXNoTWFuYWdlci5nZXRJdGVtSGFzaChpdGVtLCB0aGlzLl9kYXRhVHlwZSwgYWNjb3VudFR5cGUsIHJlZ2lvbik7XG4gICAgICAgIGRhdGFEaWN0aW9uYXJ5W2l0ZW1bdGhpcy5faWRLZXldXSA9IGl0ZW07XG4gICAgICAgIGhhc2hEaWN0aW9uYXJ5W2l0ZW1bdGhpcy5faWRLZXldXSA9IGhhc2g7XG4gICAgICAgIHBhcmVudEhhc2hEaWN0aW9uYXJ5W2l0ZW1bdGhpcy5faWRLZXldXSA9IGhhc2g7XG4gICAgICB9XG4gICAgICBmb3IobGV0IHJlbW92ZWRJZCBvZiByZW1vdmVkSXRlbUlkcykge1xuICAgICAgICBkZWxldGUgcGFyZW50SGFzaERpY3Rpb25hcnlbcmVtb3ZlZElkXTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGRpY3Rpb25hcnlIYXNoID0gdGhpcy5fZ2V0QXJyYXlYb3IoT2JqZWN0LnZhbHVlcyhwYXJlbnRIYXNoRGljdGlvbmFyeSkpO1xuICAgICAgdGhpcy5fdXBkYXRlQ2F0ZWdvcnlSZWNvcmQoY2F0ZWdvcnlOYW1lLCBkaWN0aW9uYXJ5SGFzaCk7XG4gICAgICBpZihkaWN0aW9uYXJ5SGFzaCAhPT0gcGFyZW50SGFzaCkge1xuICAgICAgICB0aGlzLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICAgICAgICBpZih0aGlzLl9kYXRhQnlIYXNoW2RpY3Rpb25hcnlIYXNoXSkge1xuICAgICAgICAgIHRoaXMuYWRkUmVmZXJlbmNlKGRpY3Rpb25hcnlIYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICAgICAgICB9IGVsc2UgaWYoZGljdGlvbmFyeUhhc2gpIHtcbiAgICAgICAgICB0aGlzLl9kYXRhQnlIYXNoW2RpY3Rpb25hcnlIYXNoXSA9IHtcbiAgICAgICAgICAgIGhhc2hlczogaGFzaERpY3Rpb25hcnksXG4gICAgICAgICAgICBkYXRhOiBkYXRhRGljdGlvbmFyeSxcbiAgICAgICAgICAgIHBhcmVudEhhc2gsXG4gICAgICAgICAgICByZW1vdmVkSXRlbUlkcyxcbiAgICAgICAgICAgIGNoaWxkSGFzaGVzOiBbXSxcbiAgICAgICAgICAgIGxhc3RVcGRhdGVkOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgcmVmZXJlbmNlczoge1tjb25uZWN0aW9uSWRdOiBbaW5zdGFuY2VJbmRleF19XG4gICAgICAgICAgfTtcbiAgICAgICAgICB0aGlzLl9kYXRhQnlIYXNoW3BhcmVudEhhc2hdLmNoaWxkSGFzaGVzLnB1c2goZGljdGlvbmFyeUhhc2gpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICAgICAgICB0aGlzLmFkZFJlZmVyZW5jZShkaWN0aW9uYXJ5SGFzaCwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBkaWN0aW9uYXJ5SGFzaDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbGlzdCBvZiBsYXN0IHVzZWQgcmVjb3JkcyBoYXNoZXNcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNhdGVnb3J5TmFtZSBjYXRlZ29yeSBuYW1lXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gbGFzdCB1c2VkIHJlY29yZHMgaGFzaGVzXG4gICAqL1xuICBnZXRMYXN0VXNlZEhhc2hlcyhjYXRlZ29yeU5hbWUpIHtcbiAgICBsZXQgc2VhcmNoSGFzaGVzID0gW107XG4gICAgY29uc3QgZ2V0VG9wSGFzaGVzID0gKGNhdGVnb3J5LCBoYXNoQW1vdW50KSA9PiB7XG4gICAgICBjb25zdCBjYXRlZ29yeURhdGEgPSB0aGlzLl9oYXNoZXNCeUNhdGVnb3J5W2NhdGVnb3J5XTtcbiAgICAgIGlmKCFjYXRlZ29yeURhdGEpIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IGhhc2hlc0FycmF5ID0gW107XG4gICAgICAgIGlmKCFoYXNoQW1vdW50KSB7XG4gICAgICAgICAgaGFzaEFtb3VudCA9IEluZmluaXR5O1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhjYXRlZ29yeURhdGEpO1xuICAgICAgICBrZXlzLnNvcnQoKGEsIGIpID0+IGIgLSBhKTtcbiAgICAgICAgZm9yKGxldCBrZXkgb2Yga2V5cykge1xuICAgICAgICAgIGhhc2hlc0FycmF5ID0gaGFzaGVzQXJyYXkuY29uY2F0KGNhdGVnb3J5RGF0YVtrZXldKTtcbiAgICAgICAgICBpZihoYXNoZXNBcnJheS5sZW5ndGggPiBoYXNoQW1vdW50KSB7XG4gICAgICAgICAgICBoYXNoZXNBcnJheSA9IGhhc2hlc0FycmF5LnNsaWNlKDAsIGhhc2hBbW91bnQpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBoYXNoZXNBcnJheTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgaWYodGhpcy5fdXNlRnV6enlTZWFyY2gpIHtcbiAgICAgIGxldCByZXN1bHRzID0gdGhpcy5fZ2V0U2ltaWxhckNhdGVnb3J5TmFtZXMoY2F0ZWdvcnlOYW1lKTtcbiAgICAgIC8vIGluY2x1ZGUgYWxsIHJlc3VsdHMgZnJvbSBleGFjdCBtYXRjaFxuICAgICAgaWYocmVzdWx0c1swXSA9PT0gY2F0ZWdvcnlOYW1lKSB7XG4gICAgICAgIHNlYXJjaEhhc2hlcyA9IGdldFRvcEhhc2hlcyhjYXRlZ29yeU5hbWUpO1xuICAgICAgICByZXN1bHRzID0gcmVzdWx0cy5zbGljZSgxKTtcbiAgICAgIH1cbiAgICAgIC8vIGluY2x1ZGUgMyBsYXRlc3QgdXBkYXRlZCBoYXNoZXMgZnJvbSBjbG9zZSBtYXRjaGVzXG4gICAgICByZXN1bHRzLmZvckVhY2goY2F0ZWdvcnkgPT4ge1xuICAgICAgICBzZWFyY2hIYXNoZXMgPSBzZWFyY2hIYXNoZXMuY29uY2F0KGdldFRvcEhhc2hlcyhjYXRlZ29yeSwgMykpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNlYXJjaEhhc2hlcyA9IGdldFRvcEhhc2hlcyhjYXRlZ29yeU5hbWUsIDIwKTtcbiAgICB9XG4gICAgICBcbiAgICBzZWFyY2hIYXNoZXMgPSBzZWFyY2hIYXNoZXMuc2xpY2UoMCwgMjApO1xuICAgIHJldHVybiBzZWFyY2hIYXNoZXM7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSByZWNvcmRzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhc2ggcmVjb3JkcyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKi9cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgYWRkUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCkge1xuICAgIGlmICghdGhpcy5fZGF0YUJ5SGFzaFtoYXNoXSkge1xuICAgICAgdGhyb3cgRXJyb3IoYENhbid0IGFkZCByZWZlcmVuY2UgLSAke3RoaXMuX2RhdGFUeXBlfSBkYXRhIGZvciBoYXNoICR7aGFzaH0gZG9lc24ndCBleGlzdGApO1xuICAgIH1cbiAgICBjb25zdCByZWZlcmVuY2VzID0gdGhpcy5fZGF0YUJ5SGFzaFtoYXNoXS5yZWZlcmVuY2VzO1xuICAgIGlmKCFyZWZlcmVuY2VzW2Nvbm5lY3Rpb25JZF0pIHtcbiAgICAgIHJlZmVyZW5jZXNbY29ubmVjdGlvbklkXSA9IFtpbnN0YW5jZUluZGV4XTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYoIXJlZmVyZW5jZXNbY29ubmVjdGlvbklkXS5pbmNsdWRlcyhpbnN0YW5jZUluZGV4KSkge1xuICAgICAgICByZWZlcmVuY2VzW2Nvbm5lY3Rpb25JZF0ucHVzaChpbnN0YW5jZUluZGV4KTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5fZGF0YUJ5SGFzaFtoYXNoXS5sYXN0VXBkYXRlZCA9IERhdGUubm93KCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSByZWNvcmRzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVSZWZlcmVuY2UoY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4KSB7XG4gICAgT2JqZWN0LmtleXModGhpcy5fZGF0YUJ5SGFzaCkuZm9yRWFjaChoYXNoID0+IHtcbiAgICAgIGNvbnN0IHJlZmVyZW5jZXMgPSB0aGlzLl9kYXRhQnlIYXNoW2hhc2hdLnJlZmVyZW5jZXM7XG4gICAgICBpZihyZWZlcmVuY2VzW2Nvbm5lY3Rpb25JZF0pIHtcbiAgICAgICAgY29uc3QgaW5kZXggPSByZWZlcmVuY2VzW2Nvbm5lY3Rpb25JZF0uZmluZEluZGV4KGluc3RhbmNlID0+IGluc3RhbmNlSW5kZXggPT09IGluc3RhbmNlKTtcbiAgICAgICAgaWYoaW5kZXggIT09IC0xKSB7XG4gICAgICAgICAgcmVmZXJlbmNlc1tjb25uZWN0aW9uSWRdLnNwbGljZShpbmRleCwgMSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYoIXJlZmVyZW5jZXNbY29ubmVjdGlvbklkXS5sZW5ndGgpIHtcbiAgICAgICAgICBkZWxldGUgcmVmZXJlbmNlc1tjb25uZWN0aW9uSWRdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBfZ2V0U2ltaWxhckNhdGVnb3J5TmFtZXMoY2F0ZWdvcnlOYW1lKSB7XG4gICAgY29uc3QgY2F0ZWdvcnlOYW1lTGlzdCA9IE9iamVjdC5rZXlzKHRoaXMuX2hhc2hlc0J5Q2F0ZWdvcnkpO1xuICAgIGNvbnN0IGZ1c2UgPSBuZXcgRnVzZShjYXRlZ29yeU5hbWVMaXN0LCB7XG4gICAgICB0aHJlc2hvbGQ6IDAuM1xuICAgIH0pO1xuICAgIHJldHVybiBmdXNlLnNlYXJjaChjYXRlZ29yeU5hbWUpLm1hcChyZXN1bHQgPT4gcmVzdWx0Lml0ZW0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZXMgaGFzaCBmcm9tIGFycmF5IG9mIGhhc2hlc1xuICAgKiBAcGFyYW0ge1N0cmluZ1tdfSBoZXhBcnJheSBhcnJheSBvZiBoYXNoZXNcbiAgICogQHJldHVybnMge3N0cmluZ30gcmVzdWx0aW5nIGhhc2hcbiAgICovXG4gIF9nZXRBcnJheVhvcihoZXhBcnJheSkge1xuICAgIHJldHVybiBoZXhBcnJheS5sZW5ndGggPyBoZXhBcnJheS5yZWR1Y2UoKGEsIGIpID0+IHRoaXMuX2dldEhleFhvcihhLCBiKSkgOiBudWxsO1xuICB9XG5cbiAgX2dldEhleFhvcihoZXgxLCBoZXgyKSB7XG4gICAgY29uc3QgYnVmMSA9IEJ1ZmZlci5mcm9tKGhleDEsICdoZXgnKTtcbiAgICBjb25zdCBidWYyID0gQnVmZmVyLmZyb20oaGV4MiwgJ2hleCcpO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1iaXR3aXNlXG4gICAgY29uc3QgYnVmUmVzdWx0ID0gYnVmMS5tYXAoKGIsIGkpID0+IGIgXiBidWYyW2ldKTtcbiAgICByZXR1cm4gKGlzQnJvd3NlciB8fCBpc1NTUilcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1iaXR3aXNlXG4gICAgICA/IEFycmF5LnByb3RvdHlwZS5tYXAuY2FsbChidWZSZXN1bHQsIGJ5dGUgPT4gKCcwJyArIChieXRlICYgMHhGRikudG9TdHJpbmcoMTYpKS5zbGljZSgtMikpLmpvaW4oJycpXG4gICAgICA6IGJ1ZlJlc3VsdC50b1N0cmluZygnaGV4Jyk7XG4gIH1cblxuICBfdXBkYXRlQ2F0ZWdvcnlSZWNvcmQoY2F0ZWdvcnlOYW1lLCBoYXNoKSB7XG4gICAgaWYoIWhhc2gpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZGF0ZSA9IERhdGUubm93KCk7XG4gICAgdGhpcy5fcmVtb3ZlQ2F0ZWdvcnlSZWNvcmQoY2F0ZWdvcnlOYW1lLCBoYXNoKTtcbiAgICBpZighdGhpcy5faGFzaGVzQnlDYXRlZ29yeVtjYXRlZ29yeU5hbWVdKSB7XG4gICAgICB0aGlzLl9oYXNoZXNCeUNhdGVnb3J5W2NhdGVnb3J5TmFtZV0gPSB7fTtcbiAgICB9XG4gICAgaWYoIXRoaXMuX2hhc2hlc0J5Q2F0ZWdvcnlbY2F0ZWdvcnlOYW1lXVtkYXRlXSkge1xuICAgICAgdGhpcy5faGFzaGVzQnlDYXRlZ29yeVtjYXRlZ29yeU5hbWVdW2RhdGVdID0gW107XG4gICAgfVxuICAgIHRoaXMuX2hhc2hlc0J5Q2F0ZWdvcnlbY2F0ZWdvcnlOYW1lXVtkYXRlXS5wdXNoKGhhc2gpO1xuICB9XG5cbiAgX3JlbW92ZUNhdGVnb3J5UmVjb3JkKGNhdGVnb3J5TmFtZSwgaGFzaCkge1xuICAgIGlmKHRoaXMuX2hhc2hlc0J5Q2F0ZWdvcnlbY2F0ZWdvcnlOYW1lXSkge1xuICAgICAgY29uc3QgZGF0ZXMgPSBPYmplY3Qua2V5cyh0aGlzLl9oYXNoZXNCeUNhdGVnb3J5W2NhdGVnb3J5TmFtZV0pO1xuICAgICAgZGF0ZXMuZm9yRWFjaChkYXRlID0+IHtcbiAgICAgICAgaWYodGhpcy5faGFzaGVzQnlDYXRlZ29yeVtjYXRlZ29yeU5hbWVdW2RhdGVdLmluY2x1ZGVzKGhhc2gpKSB7XG4gICAgICAgICAgdGhpcy5faGFzaGVzQnlDYXRlZ29yeVtjYXRlZ29yeU5hbWVdW2RhdGVdID0gXG4gICAgICAgICAgICB0aGlzLl9oYXNoZXNCeUNhdGVnb3J5W2NhdGVnb3J5TmFtZV1bZGF0ZV0uZmlsdGVyKGl0ZW0gPT4gaXRlbSAhPT0gaGFzaCk7XG4gICAgICAgICAgaWYodGhpcy5faGFzaGVzQnlDYXRlZ29yeVtjYXRlZ29yeU5hbWVdW2RhdGVdLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuX2hhc2hlc0J5Q2F0ZWdvcnlbY2F0ZWdvcnlOYW1lXVtkYXRlXTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgaWYoT2JqZWN0LmtleXModGhpcy5faGFzaGVzQnlDYXRlZ29yeVtjYXRlZ29yeU5hbWVdKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgZGVsZXRlIHRoaXMuX2hhc2hlc0J5Q2F0ZWdvcnlbY2F0ZWdvcnlOYW1lXTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBfb3B0aW1pemVUcmVlc0pvYigpIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG4gICAgT2JqZWN0LmtleXModGhpcy5fZGF0YUJ5SGFzaCkuZm9yRWFjaChoYXNoID0+IHtcbiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhQnlIYXNoW2hhc2hdO1xuICAgICAgaWYoZGF0YS5sYXN0VXBkYXRlZCA8PSBub3cgLSB0aGlzLl9yZWNvcmRFeHBpcmF0aW9uVGltZSAmJiAhT2JqZWN0LmtleXMoZGF0YS5yZWZlcmVuY2VzKS5sZW5ndGggJiZcbiAgICAgICAgICBkYXRhLmNoaWxkSGFzaGVzLmxlbmd0aCA8IDIpIHtcbiAgICAgICAgaWYgKGRhdGEuY2hpbGRIYXNoZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgY29uc3QgY2hpbGRIYXNoID0gZGF0YS5jaGlsZEhhc2hlc1swXTtcbiAgICAgICAgICBjb25zdCBjaGlsZERhdGEgPSB0aGlzLl9kYXRhQnlIYXNoW2NoaWxkSGFzaF07XG4gICAgICAgICAgaWYoZGF0YS5wYXJlbnRIYXNoKSB7XG4gICAgICAgICAgICBjb25zdCBjb21iaW5lZENoYW5nZXMgPSBPYmplY3QuYXNzaWduKHt9LCBkYXRhLmRhdGEsIGNoaWxkRGF0YS5kYXRhKTtcbiAgICAgICAgICAgIGNvbnN0IGNvbWJpbmVkSGFzaGVzID0gT2JqZWN0LmFzc2lnbih7fSwgZGF0YS5oYXNoZXMsIGNoaWxkRGF0YS5oYXNoZXMpO1xuICAgICAgICAgICAgY29uc3QgY2hpbGREYXRhSWRzID0gT2JqZWN0LmtleXMoY2hpbGREYXRhLmRhdGEpO1xuICAgICAgICAgICAgbGV0IGNvbWJpbmVkUmVtb3ZlZElkcyA9IGRhdGEucmVtb3ZlZEl0ZW1JZHMuZmlsdGVyKGlkID0+ICFjaGlsZERhdGFJZHMuaW5jbHVkZXMoaWQpKVxuICAgICAgICAgICAgICAuY29uY2F0KGNoaWxkRGF0YS5yZW1vdmVkSXRlbUlkcyk7XG4gICAgICAgICAgICBjaGlsZERhdGEuZGF0YSA9IGNvbWJpbmVkQ2hhbmdlcztcbiAgICAgICAgICAgIGNoaWxkRGF0YS5oYXNoZXMgPSBjb21iaW5lZEhhc2hlcztcbiAgICAgICAgICAgIGNoaWxkRGF0YS5yZW1vdmVkSXRlbUlkcyA9IGNvbWJpbmVkUmVtb3ZlZElkcztcbiAgICAgICAgICAgIGNoaWxkRGF0YS5wYXJlbnRIYXNoID0gZGF0YS5wYXJlbnRIYXNoO1xuICAgICAgICAgICAgdGhpcy5fZGF0YUJ5SGFzaFtkYXRhLnBhcmVudEhhc2hdLmNoaWxkSGFzaGVzLnB1c2goY2hpbGRIYXNoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgY2hpbGRJdGVtcyA9IHRoaXMuZ2V0SXRlbXNCeUhhc2goY2hpbGRIYXNoKTtcbiAgICAgICAgICAgIGNvbnN0IGNoaWxkSGFzaGVzID0gdGhpcy5nZXRIYXNoZXNCeUhhc2goY2hpbGRIYXNoKTtcbiAgICAgICAgICAgIGNoaWxkRGF0YS5kYXRhID0gY2hpbGRJdGVtcztcbiAgICAgICAgICAgIGNoaWxkRGF0YS5oYXNoZXMgPSBjaGlsZEhhc2hlcztcbiAgICAgICAgICAgIGNoaWxkRGF0YS5yZW1vdmVkSXRlbUlkcyA9IFtdO1xuICAgICAgICAgICAgY2hpbGREYXRhLnBhcmVudEhhc2ggPSBudWxsO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZihkYXRhLnBhcmVudEhhc2gpIHtcbiAgICAgICAgICBjb25zdCBwYXJlbnREYXRhID0gdGhpcy5fZGF0YUJ5SGFzaFtkYXRhLnBhcmVudEhhc2hdO1xuICAgICAgICAgIGlmKHBhcmVudERhdGEpIHtcbiAgICAgICAgICAgIHBhcmVudERhdGEuY2hpbGRIYXNoZXMgPSBwYXJlbnREYXRhLmNoaWxkSGFzaGVzLmZpbHRlcihpdGVtSGFzaCA9PiBoYXNoICE9PSBpdGVtSGFzaCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGRlbGV0ZSB0aGlzLl9kYXRhQnlIYXNoW2hhc2hdO1xuICAgICAgICBjb25zdCBjYXRlZ29yaWVzID0gT2JqZWN0LmtleXModGhpcy5faGFzaGVzQnlDYXRlZ29yeSk7XG4gICAgICAgIGNhdGVnb3JpZXMuZm9yRWFjaChjYXRlZ29yeSA9PiB7XG4gICAgICAgICAgdGhpcy5fcmVtb3ZlQ2F0ZWdvcnlSZWNvcmQoY2F0ZWdvcnksIGhhc2gpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyByZWZlcmVuY2UgdHJlZSBvcHRpbWl6ZSBqb2IgJiBjbGVhcnMgaW50ZXJ2YWxcbiAgICovXG4gIHN0b3AoKSB7XG4gICAgY2xlYXJJbnRlcnZhbCh0aGlzLl9pbnRlcnZhbCk7XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJSZWZlcmVuY2VUcmVlIiwiaXNCcm93c2VyIiwid2luZG93IiwiZG9jdW1lbnQiLCJpc05vZGVTZXJ2ZXIiLCJwcm9jZXNzIiwicmVsZWFzZSIsIm5hbWUiLCJpc1NTUiIsImdldEl0ZW1zQnlIYXNoIiwiaGFzaCIsImRhdGEiLCJfZGF0YUJ5SGFzaCIsInBhcmVudEhhc2giLCJoYXNoQ2hhaW4iLCJ1bnNoaWZ0IiwicGFyZW50RGF0YSIsInN0YXRlIiwiT2JqZWN0IiwiYXNzaWduIiwic2hpZnQiLCJjaGFpbkhhc2giLCJjaGFpbkRhdGEiLCJrZXlzIiwiZm9yRWFjaCIsImlkIiwicmVtb3ZlZEl0ZW1JZHMiLCJnZXRIYXNoZXNCeUhhc2giLCJoYXNoZXMiLCJyZWNvcmRJdGVtcyIsImNhdGVnb3J5TmFtZSIsImFjY291bnRUeXBlIiwiY29ubmVjdGlvbklkIiwiaW5zdGFuY2VJbmRleCIsIml0ZW1zIiwicmVnaW9uIiwic3BsaXQiLCJoYXNoRGljdGlvbmFyeSIsImRhdGFEaWN0aW9uYXJ5IiwibGVuZ3RoIiwiaXRlbSIsIl90ZXJtaW5hbEhhc2hNYW5hZ2VyIiwiZ2V0SXRlbUhhc2giLCJfZGF0YVR5cGUiLCJfaWRLZXkiLCJkaWN0aW9uYXJ5SGFzaCIsIl9nZXRBcnJheVhvciIsInZhbHVlcyIsIl91cGRhdGVDYXRlZ29yeVJlY29yZCIsInJlbW92ZVJlZmVyZW5jZSIsImFkZFJlZmVyZW5jZSIsImNoaWxkSGFzaGVzIiwibGFzdFVwZGF0ZWQiLCJEYXRlIiwibm93IiwicmVmZXJlbmNlcyIsInVwZGF0ZUl0ZW1zIiwiRXJyb3IiLCJwYXJlbnRIYXNoRGljdGlvbmFyeSIsInJlbW92ZWRJZCIsInB1c2giLCJnZXRMYXN0VXNlZEhhc2hlcyIsInNlYXJjaEhhc2hlcyIsImdldFRvcEhhc2hlcyIsImNhdGVnb3J5IiwiaGFzaEFtb3VudCIsImNhdGVnb3J5RGF0YSIsIl9oYXNoZXNCeUNhdGVnb3J5IiwiaGFzaGVzQXJyYXkiLCJJbmZpbml0eSIsInNvcnQiLCJhIiwiYiIsImtleSIsImNvbmNhdCIsInNsaWNlIiwiX3VzZUZ1enp5U2VhcmNoIiwicmVzdWx0cyIsIl9nZXRTaW1pbGFyQ2F0ZWdvcnlOYW1lcyIsImluY2x1ZGVzIiwiaW5kZXgiLCJmaW5kSW5kZXgiLCJpbnN0YW5jZSIsInNwbGljZSIsImNhdGVnb3J5TmFtZUxpc3QiLCJmdXNlIiwiRnVzZSIsInRocmVzaG9sZCIsInNlYXJjaCIsIm1hcCIsInJlc3VsdCIsImhleEFycmF5IiwicmVkdWNlIiwiX2dldEhleFhvciIsImhleDEiLCJoZXgyIiwiYnVmMSIsIkJ1ZmZlciIsImZyb20iLCJidWYyIiwiYnVmUmVzdWx0IiwiaSIsIkFycmF5IiwicHJvdG90eXBlIiwiY2FsbCIsImJ5dGUiLCJ0b1N0cmluZyIsImpvaW4iLCJkYXRlIiwiX3JlbW92ZUNhdGVnb3J5UmVjb3JkIiwiZGF0ZXMiLCJmaWx0ZXIiLCJfb3B0aW1pemVUcmVlc0pvYiIsIl9yZWNvcmRFeHBpcmF0aW9uVGltZSIsImNoaWxkSGFzaCIsImNoaWxkRGF0YSIsImNvbWJpbmVkQ2hhbmdlcyIsImNvbWJpbmVkSGFzaGVzIiwiY2hpbGREYXRhSWRzIiwiY29tYmluZWRSZW1vdmVkSWRzIiwiY2hpbGRJdGVtcyIsIml0ZW1IYXNoIiwiY2F0ZWdvcmllcyIsInN0b3AiLCJjbGVhckludGVydmFsIiwiX2ludGVydmFsIiwiY29uc3RydWN0b3IiLCJ0ZXJtaW5hbEhhc2hNYW5hZ2VyIiwiaWRLZXkiLCJkYXRhVHlwZSIsInVzZUZ1enp5U2VhcmNoIiwia2VlcEhhc2hUcmVlcyIsImJpbmQiLCJzZXRJbnRlcnZhbCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztlQVVxQkE7Ozs2REFWSjt3QkFDTTs7Ozs7O0FBRXZCLE1BQU1DLFlBQVksT0FBT0MsV0FBVyxlQUFlLE9BQU9BLE9BQU9DLFFBQVEsS0FBSztBQUM5RSxNQUFNQyxlQUFlLE9BQU9DLFlBQVksZUFBZUEsUUFBUUMsT0FBTyxJQUFJRCxRQUFRQyxPQUFPLENBQUNDLElBQUksS0FBSztBQUNuRyxNQUFNQyxRQUFRLENBQUNQLGFBQWFHO0FBS2IsSUFBQSxBQUFNSixnQkFBTixNQUFNQTtJQXdCbkI7Ozs7R0FJQyxHQUNELHNDQUFzQztJQUN0Q1MsZUFBZUMsSUFBSSxFQUFFO1FBQ25CLE1BQU1DLE9BQU8sSUFBSSxDQUFDQyxXQUFXLENBQUNGLEtBQUs7UUFDbkMsSUFBRyxDQUFDQyxNQUFNO1lBQ1IsT0FBTztRQUNULE9BQU8sSUFBRyxDQUFDQSxLQUFLRSxVQUFVLEVBQUU7WUFDMUIsT0FBT0YsS0FBS0EsSUFBSTtRQUNsQixPQUFPO1lBQ0w7OztP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