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)
229 lines (228 loc) • 26.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _avlTree = /*#__PURE__*/ _interop_require_default(require("./avlTree"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
/* jscs:disable */ /* eslint-disable */ const Reservoir = function() {
var switchToAlgorithmZConstant = 22;
var debug = "none";
/**
* Statistical reservoir of a fixed size capable calculating percentile
* This reservoir taken from https://www.npmjs.com/package/reservoir
* This reservoir has been modified by avl tree (https://www.npmjs.com/package/avl-sorted-list)
* Array which contains all data was removed and instead of it add tree
*/ function _Reservoir(reservoirSize, storagePeriodInMilliseconds, randomNumberGen) {
let interval = storagePeriodInMilliseconds;
var rng = randomNumberGen || Math.random;
var reservoirSize = Math.max(1, Math.floor(reservoirSize) >> 0 || 1);
var totalItemCount = 0;
var lastDeletedIndex = -1;
var numToSkip = -1;
var currentAlgorithm = algorithmX;
var switchThreshold = switchToAlgorithmZConstant * reservoirSize;
if (debug === "R") {
currentAlgorithm = algorithmR;
} else if (debug === "X") {
switchThreshold = Infinity;
} else if (debug === "Z") {
currentAlgorithm = algorithmZ;
}
var algorithmXCount = 0;
var W = Math.exp(-Math.log(rng()) / reservoirSize);
var evictNext = null;
let indexTree = new _avlTree.default(function(a, b) {
return a.index - b.index;
});
let valueTree = new _avlTree.default(function(a, b) {
return a - b;
});
let initialIndex = 0;
indexTree.removeOldRecords = function() {
while(true){
let element = this.at(0);
if (element !== null && Date.now() > element.time + interval) {
this.removeAt(0);
var deletedIndexDiff = element.index - lastDeletedIndex;
lastDeletedIndex = element.index;
valueTree.remove(element.data);
totalItemCount -= deletedIndexDiff;
algorithmXCount = Math.max(0, algorithmXCount - deletedIndexDiff);
} else {
break;
}
}
};
indexTree.getPercentile = function() {
let percent = arguments[0];
this.removeOldRecords();
const index = (this.size() - 1) * percent / 100;
const lower = Math.floor(index);
const fractionPart = index - lower;
let percentile = valueTree.at(lower);
if (fractionPart > 0) {
percentile += fractionPart * (valueTree.at(lower + 1) - valueTree.at(lower));
}
return parseFloat(percentile);
};
indexTree.pushSome = function() {
let len = Math.min(this.size(), reservoirSize);
for(var i = 0; i < arguments.length; i++){
this.removeOldRecords();
var value = {
index: initialIndex,
time: Date.now(),
data: arguments[i]
};
addSample.call(this, value);
initialIndex++;
}
return len;
};
indexTree.fromPlainObject = function() {
let len = Math.min(this.size(), reservoirSize);
for(var i = 0; i < arguments.length; i++){
var value = {
index: arguments[i].index,
time: arguments[i].time,
data: arguments[i].data
};
addSample.call(this, value);
initialIndex++;
}
return len;
};
var addSample = function(sample) {
if (this.size() < reservoirSize) {
this.insert(sample);
valueTree.insert(sample.data);
} else {
if (numToSkip < 0) {
numToSkip = currentAlgorithm();
}
if (numToSkip === 0) {
replaceRandomSample(sample, this);
}
numToSkip--;
}
totalItemCount++;
return this;
};
function replaceRandomSample(sample, reservoir) {
var randomIndex;
if (evictNext !== null) {
randomIndex = evictNext;
evictNext = null;
} else {
randomIndex = Math.floor(rng() * reservoirSize);
}
let value = reservoir.at(randomIndex);
reservoir.removeAt(randomIndex);
valueTree.remove(value.data);
valueTree.insert(sample.data);
reservoir.insert(sample);
}
/**
* "Algorithm R"
* Selects random elements from an unknown-length input.
* Has a time-complexity of: O(N)
* Number of random numbers required:
* N - n
* Where:
* n = the size of the reservoir
* N = the size of the input
*/ function algorithmR() {
var localItemCount = totalItemCount + 1, randomValue = Math.floor(rng() * localItemCount), toSkip = 0;
while(randomValue >= reservoirSize){
toSkip++;
localItemCount++;
randomValue = Math.floor(rng() * localItemCount);
}
evictNext = randomValue;
return toSkip;
}
/** "Algorithm X"
* Selects random elements from an unknown-length input.
* Has a time-complexity of: O(N)
* Number of random numbers required:
* 2 * n * ln( N / n )
* Where:
* n = the size of the reservoir
* N = the size of the input
*/ function algorithmX() {
var localItemCount = totalItemCount, randomValue = rng(), toSkip = 0, quotient;
if (totalItemCount <= switchThreshold) {
localItemCount++;
algorithmXCount++;
quotient = algorithmXCount / localItemCount;
while(quotient > randomValue){
toSkip++;
localItemCount++;
algorithmXCount++;
quotient = quotient * algorithmXCount / localItemCount;
}
return toSkip;
} else {
currentAlgorithm = algorithmZ;
return currentAlgorithm();
}
}
/** "Algorithm Z"
* Selects random elements from an unknown-length input.
* Has a time-complexity of:
* O(n(1 + log (N / n)))
* Number of random numbers required:
* 2 * n * ln( N / n )
* Where:
* n = the size of the reservoir
* N = the size of the input
*/ function algorithmZ() {
var term = totalItemCount - reservoirSize + 1, denom, numer, numer_lim;
while(true){
var randomValue = rng();
var x = totalItemCount * (W - 1);
var toSkip = Math.floor(x);
var subterm = (totalItemCount + 1) / term;
subterm *= subterm;
var termSkip = term + toSkip;
var lhs = Math.exp(Math.log(randomValue * subterm * termSkip / (totalItemCount + x)) / reservoirSize);
var rhs = (totalItemCount + x) / termSkip * term / totalItemCount;
if (lhs <= rhs) {
W = rhs / lhs;
break;
}
var y = randomValue * (totalItemCount + 1) / term * (totalItemCount + toSkip + 1) / (totalItemCount + x);
if (reservoirSize < toSkip) {
denom = totalItemCount;
numer_lim = term + toSkip;
} else {
denom = totalItemCount - reservoirSize + toSkip;
numer_lim = totalItemCount + 1;
}
for(numer = totalItemCount + toSkip; numer >= numer_lim; numer--){
y = y * numer / denom;
denom--;
}
W = Math.exp(-Math.log(rng()) / reservoirSize);
if (Math.exp(Math.log(y) / reservoirSize) <= (totalItemCount + x) / totalItemCount) {
break;
}
}
return toSkip;
}
return indexTree;
}
return _Reservoir;
}();
const _default = Reservoir;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBBdmxUcmVlIGZyb20gJy4vYXZsVHJlZSc7XG5cbi8qIGpzY3M6ZGlzYWJsZSAqL1xuLyogZXNsaW50LWRpc2FibGUgKi9cbmNvbnN0IFJlc2Vydm9pciA9IChmdW5jdGlvbiAoKSB7XG5cbiAgdmFyIHN3aXRjaFRvQWxnb3JpdGhtWkNvbnN0YW50ID0gMjI7XG4gIHZhciBkZWJ1ZyA9ICdub25lJztcblxuICAvKipcbiAgICogU3RhdGlzdGljYWwgcmVzZXJ2b2lyIG9mIGEgZml4ZWQgc2l6ZSBjYXBhYmxlIGNhbGN1bGF0aW5nIHBlcmNlbnRpbGVcbiAgICogVGhpcyByZXNlcnZvaXIgdGFrZW4gZnJvbSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9yZXNlcnZvaXJcbiAgICogVGhpcyByZXNlcnZvaXIgaGFzIGJlZW4gbW9kaWZpZWQgYnkgYXZsIHRyZWUgKGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL2F2bC1zb3J0ZWQtbGlzdClcbiAgICogQXJyYXkgd2hpY2ggY29udGFpbnMgYWxsIGRhdGEgd2FzIHJlbW92ZWQgYW5kIGluc3RlYWQgb2YgaXQgYWRkIHRyZWVcbiAgICovXG4gIGZ1bmN0aW9uIF9SZXNlcnZvaXIocmVzZXJ2b2lyU2l6ZSwgc3RvcmFnZVBlcmlvZEluTWlsbGlzZWNvbmRzLCByYW5kb21OdW1iZXJHZW4pIHtcbiAgICBsZXQgaW50ZXJ2YWwgPSBzdG9yYWdlUGVyaW9kSW5NaWxsaXNlY29uZHM7XG4gICAgdmFyIHJuZyA9IHJhbmRvbU51bWJlckdlbiB8fCBNYXRoLnJhbmRvbTtcbiAgICB2YXIgcmVzZXJ2b2lyU2l6ZSA9IE1hdGgubWF4KDEsIChNYXRoLmZsb29yKHJlc2Vydm9pclNpemUpID4+IDApIHx8IDEpO1xuICAgIHZhciB0b3RhbEl0ZW1Db3VudCA9IDA7XG4gICAgdmFyIGxhc3REZWxldGVkSW5kZXggPSAtMTtcbiAgICB2YXIgbnVtVG9Ta2lwID0gLTE7XG4gICAgdmFyIGN1cnJlbnRBbGdvcml0aG0gPSBhbGdvcml0aG1YO1xuICAgIHZhciBzd2l0Y2hUaHJlc2hvbGQgPVxuICAgICAgc3dpdGNoVG9BbGdvcml0aG1aQ29uc3RhbnQgKiByZXNlcnZvaXJTaXplO1xuXG4gICAgaWYgKGRlYnVnID09PSAnUicpIHtcbiAgICAgIGN1cnJlbnRBbGdvcml0aG0gPSBhbGdvcml0aG1SO1xuICAgIH0gZWxzZSBpZiAoZGVidWcgPT09ICdYJykge1xuICAgICAgc3dpdGNoVGhyZXNob2xkID0gSW5maW5pdHk7XG4gICAgfSBlbHNlIGlmIChkZWJ1ZyA9PT0gJ1onKSB7XG4gICAgICBjdXJyZW50QWxnb3JpdGhtID0gYWxnb3JpdGhtWjtcbiAgICB9XG5cbiAgICB2YXIgYWxnb3JpdGhtWENvdW50ID0gMDtcbiAgICB2YXIgVyA9IE1hdGguZXhwKC1NYXRoLmxvZyhybmcoKSkgLyByZXNlcnZvaXJTaXplKTtcbiAgICB2YXIgZXZpY3ROZXh0ID0gbnVsbDtcblxuICAgIGxldCBpbmRleFRyZWUgPSBuZXcgQXZsVHJlZShmdW5jdGlvbiAoYSwgYikge1xuICAgICAgcmV0dXJuIGEuaW5kZXggLSBiLmluZGV4O1xuICAgIH0pO1xuXG4gICAgbGV0IHZhbHVlVHJlZSA9IG5ldyBBdmxUcmVlKGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICByZXR1cm4gYSAtIGI7XG4gICAgfSk7XG4gICAgbGV0IGluaXRpYWxJbmRleCA9IDA7XG5cbiAgICBpbmRleFRyZWUucmVtb3ZlT2xkUmVjb3JkcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGxldCBlbGVtZW50ID0gdGhpcy5hdCgwKTtcbiAgICAgICAgaWYgKGVsZW1lbnQgIT09IG51bGwgJiYgRGF0ZS5ub3coKSA+IGVsZW1lbnQudGltZSArIGludGVydmFsKSB7XG4gICAgICAgICAgdGhpcy5yZW1vdmVBdCgwKTtcbiAgICAgICAgICB2YXIgZGVsZXRlZEluZGV4RGlmZiA9IGVsZW1lbnQuaW5kZXggLSBsYXN0RGVsZXRlZEluZGV4O1xuICAgICAgICAgIGxhc3REZWxldGVkSW5kZXggPSBlbGVtZW50LmluZGV4O1xuICAgICAgICAgIHZhbHVlVHJlZS5yZW1vdmUoZWxlbWVudC5kYXRhKTtcbiAgICAgICAgICB0b3RhbEl0ZW1Db3VudCAtPSBkZWxldGVkSW5kZXhEaWZmO1xuICAgICAgICAgIGFsZ29yaXRobVhDb3VudCA9IE1hdGgubWF4KDAsIGFsZ29yaXRobVhDb3VudCAtIGRlbGV0ZWRJbmRleERpZmYpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIGluZGV4VHJlZS5nZXRQZXJjZW50aWxlID0gZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHBlcmNlbnQgPSBhcmd1bWVudHNbMF07XG4gICAgICB0aGlzLnJlbW92ZU9sZFJlY29yZHMoKTtcbiAgICAgIGNvbnN0IGluZGV4ID0gKHRoaXMuc2l6ZSgpIC0gMSkgKiBwZXJjZW50IC8gMTAwO1xuICAgICAgY29uc3QgbG93ZXIgPSBNYXRoLmZsb29yKGluZGV4KTtcbiAgICAgIGNvbnN0IGZyYWN0aW9uUGFydCA9IGluZGV4IC0gbG93ZXI7XG4gICAgICBsZXQgcGVyY2VudGlsZSA9IHZhbHVlVHJlZS5hdChsb3dlcik7XG4gICAgICBpZiAoZnJhY3Rpb25QYXJ0ID4gMCkge1xuICAgICAgICBwZXJjZW50aWxlICs9IGZyYWN0aW9uUGFydCAqICh2YWx1ZVRyZWUuYXQobG93ZXIgKyAxKSAtIHZhbHVlVHJlZS5hdChsb3dlcikpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHBhcnNlRmxvYXQocGVyY2VudGlsZSk7XG4gICAgfTtcblxuICAgIGluZGV4VHJlZS5wdXNoU29tZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBsZW4gPSBNYXRoLm1pbih0aGlzLnNpemUoKSwgcmVzZXJ2b2lyU2l6ZSk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLnJlbW92ZU9sZFJlY29yZHMoKTtcbiAgICAgICAgdmFyIHZhbHVlID0ge2luZGV4OiBpbml0aWFsSW5kZXgsIHRpbWU6IERhdGUubm93KCksIGRhdGE6IGFyZ3VtZW50c1tpXX07XG4gICAgICAgIGFkZFNhbXBsZS5jYWxsKHRoaXMsIHZhbHVlKTtcbiAgICAgICAgaW5pdGlhbEluZGV4Kys7XG4gICAgICB9XG4gICAgICByZXR1cm4gbGVuO1xuICAgIH07XG5cbiAgICBpbmRleFRyZWUuZnJvbVBsYWluT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGxlbiA9IE1hdGgubWluKHRoaXMuc2l6ZSgpLCByZXNlcnZvaXJTaXplKTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB2YWx1ZSA9IHtpbmRleDogYXJndW1lbnRzW2ldLmluZGV4LCB0aW1lOiBhcmd1bWVudHNbaV0udGltZSwgZGF0YTogYXJndW1lbnRzW2ldLmRhdGF9O1xuICAgICAgICBhZGRTYW1wbGUuY2FsbCh0aGlzLCB2YWx1ZSk7XG4gICAgICAgIGluaXRpYWxJbmRleCsrO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGxlbjtcbiAgICB9O1xuXG4gICAgdmFyIGFkZFNhbXBsZSA9IGZ1bmN0aW9uIChzYW1wbGUpIHtcbiAgICAgIGlmICh0aGlzLnNpemUoKSA8IHJlc2Vydm9pclNpemUpIHtcbiAgICAgICAgdGhpcy5pbnNlcnQoc2FtcGxlKTtcbiAgICAgICAgdmFsdWVUcmVlLmluc2VydChzYW1wbGUuZGF0YSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAobnVtVG9Ta2lwIDwgMCkge1xuICAgICAgICAgIG51bVRvU2tpcCA9IGN1cnJlbnRBbGdvcml0aG0oKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobnVtVG9Ta2lwID09PSAwKSB7XG4gICAgICAgICAgcmVwbGFjZVJhbmRvbVNhbXBsZShzYW1wbGUsIHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIG51bVRvU2tpcC0tO1xuICAgICAgfVxuICAgICAgdG90YWxJdGVtQ291bnQrKztcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiByZXBsYWNlUmFuZG9tU2FtcGxlKHNhbXBsZSwgcmVzZXJ2b2lyKSB7XG4gICAgICB2YXIgcmFuZG9tSW5kZXg7XG4gICAgICBpZiAoZXZpY3ROZXh0ICE9PSBudWxsKSB7XG4gICAgICAgIHJhbmRvbUluZGV4ID0gZXZpY3ROZXh0O1xuICAgICAgICBldmljdE5leHQgPSBudWxsO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmFuZG9tSW5kZXggPSBNYXRoLmZsb29yKHJuZygpICogcmVzZXJ2b2lyU2l6ZSk7XG4gICAgICB9XG4gICAgICBsZXQgdmFsdWUgPSByZXNlcnZvaXIuYXQocmFuZG9tSW5kZXgpO1xuICAgICAgcmVzZXJ2b2lyLnJlbW92ZUF0KHJhbmRvbUluZGV4KTtcbiAgICAgIHZhbHVlVHJlZS5yZW1vdmUodmFsdWUuZGF0YSk7XG4gICAgICB2YWx1ZVRyZWUuaW5zZXJ0KHNhbXBsZS5kYXRhKTtcbiAgICAgIHJlc2Vydm9pci5pbnNlcnQoc2FtcGxlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBcIkFsZ29yaXRobSBSXCJcbiAgICAgKiBTZWxlY3RzIHJhbmRvbSBlbGVtZW50cyBmcm9tIGFuIHVua25vd24tbGVuZ3RoIGlucHV0LlxuICAgICAqIEhhcyBhIHRpbWUtY29tcGxleGl0eSBvZjogTyhOKVxuICAgICAqIE51bWJlciBvZiByYW5kb20gbnVtYmVycyByZXF1aXJlZDpcbiAgICAgKiBOIC0gblxuICAgICAqIFdoZXJlOlxuICAgICAqIG4gPSB0aGUgc2l6ZSBvZiB0aGUgcmVzZXJ2b2lyXG4gICAgICogTiA9IHRoZSBzaXplIG9mIHRoZSBpbnB1dFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGFsZ29yaXRobVIoKSB7XG4gICAgICB2YXIgbG9jYWxJdGVtQ291bnQgPSB0b3RhbEl0ZW1Db3VudCArIDEsXG4gICAgICAgIHJhbmRvbVZhbHVlID0gTWF0aC5mbG9vcihybmcoKSAqIGxvY2FsSXRlbUNvdW50KSxcbiAgICAgICAgdG9Ta2lwID0gMDtcblxuICAgICAgd2hpbGUgKHJhbmRvbVZhbHVlID49IHJlc2Vydm9pclNpemUpIHtcbiAgICAgICAgdG9Ta2lwKys7XG4gICAgICAgIGxvY2FsSXRlbUNvdW50Kys7XG4gICAgICAgIHJhbmRvbVZhbHVlID0gTWF0aC5mbG9vcihybmcoKSAqIGxvY2FsSXRlbUNvdW50KTtcbiAgICAgIH1cbiAgICAgIGV2aWN0TmV4dCA9IHJhbmRvbVZhbHVlO1xuICAgICAgcmV0dXJuIHRvU2tpcDtcbiAgICB9XG5cbiAgICAvKiogXCJBbGdvcml0aG0gWFwiXG4gICAgICogU2VsZWN0cyByYW5kb20gZWxlbWVudHMgZnJvbSBhbiB1bmtub3duLWxlbmd0aCBpbnB1dC5cbiAgICAgKiBIYXMgYSB0aW1lLWNvbXBsZXhpdHkgb2Y6IE8oTilcbiAgICAgKiBOdW1iZXIgb2YgcmFuZG9tIG51bWJlcnMgcmVxdWlyZWQ6XG4gICAgICogIDIgKiBuICogbG4oIE4gLyBuIClcbiAgICAgKiBXaGVyZTpcbiAgICAgKiAgbiA9IHRoZSBzaXplIG9mIHRoZSByZXNlcnZvaXJcbiAgICAgKiAgTiA9IHRoZSBzaXplIG9mIHRoZSBpbnB1dFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGFsZ29yaXRobVgoKSB7XG4gICAgICB2YXIgbG9jYWxJdGVtQ291bnQgPSB0b3RhbEl0ZW1Db3VudCxcbiAgICAgICAgcmFuZG9tVmFsdWUgPSBybmcoKSxcbiAgICAgICAgdG9Ta2lwID0gMCxcbiAgICAgICAgcXVvdGllbnQ7XG5cbiAgICAgIGlmICh0b3RhbEl0ZW1Db3VudCA8PSBzd2l0Y2hUaHJlc2hvbGQpIHtcbiAgICAgICAgbG9jYWxJdGVtQ291bnQrKztcbiAgICAgICAgYWxnb3JpdGhtWENvdW50Kys7XG4gICAgICAgIHF1b3RpZW50ID0gYWxnb3JpdGhtWENvdW50IC8gbG9jYWxJdGVtQ291bnQ7XG5cbiAgICAgICAgd2hpbGUgKHF1b3RpZW50ID4gcmFuZG9tVmFsdWUpIHtcbiAgICAgICAgICB0b1NraXArKztcbiAgICAgICAgICBsb2NhbEl0ZW1Db3VudCsrO1xuICAgICAgICAgIGFsZ29yaXRobVhDb3VudCsrO1xuICAgICAgICAgIHF1b3RpZW50ID0gKHF1b3RpZW50ICogYWxnb3JpdGhtWENvdW50KSAvIGxvY2FsSXRlbUNvdW50O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0b1NraXA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjdXJyZW50QWxnb3JpdGhtID0gYWxnb3JpdGhtWjtcbiAgICAgICAgcmV0dXJuIGN1cnJlbnRBbGdvcml0aG0oKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogXCJBbGdvcml0aG0gWlwiXG4gICAgICogU2VsZWN0cyByYW5kb20gZWxlbWVudHMgZnJvbSBhbiB1bmtub3duLWxlbmd0aCBpbnB1dC5cbiAgICAgKiBIYXMgYSB0aW1lLWNvbXBsZXhpdHkgb2Y6XG4gICAgICogIE8obigxICsgbG9nIChOIC8gbikpKVxuICAgICAqIE51bWJlciBvZiByYW5kb20gbnVtYmVycyByZXF1aXJlZDpcbiAgICAgKiAgMiAqIG4gKiBsbiggTiAvIG4gKVxuICAgICAqIFdoZXJlOlxuICAgICAqICBuID0gdGhlIHNpemUgb2YgdGhlIHJlc2Vydm9pclxuICAgICAqICBOID0gdGhlIHNpemUgb2YgdGhlIGlucHV0XG4gICAgICovXG4gICAgZnVuY3Rpb24gYWxnb3JpdGhtWigpIHtcbiAgICAgIHZhciB0ZXJtID0gdG90YWxJdGVtQ291bnQgLSByZXNlcnZvaXJTaXplICsgMSxcbiAgICAgICAgZGVub20sXG4gICAgICAgIG51bWVyLFxuICAgICAgICBudW1lcl9saW07XG5cbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIHZhciByYW5kb21WYWx1ZSA9IHJuZygpO1xuICAgICAgICB2YXIgeCA9IHRvdGFsSXRlbUNvdW50ICogKFcgLSAxKTtcbiAgICAgICAgdmFyIHRvU2tpcCA9IE1hdGguZmxvb3IoeCk7XG5cbiAgICAgICAgdmFyIHN1YnRlcm0gPSAoKHRvdGFsSXRlbUNvdW50ICsgMSkgLyB0ZXJtKTtcbiAgICAgICAgc3VidGVybSAqPSBzdWJ0ZXJtO1xuICAgICAgICB2YXIgdGVybVNraXAgPSB0ZXJtICsgdG9Ta2lwO1xuICAgICAgICB2YXIgbGhzID0gTWF0aC5leHAoTWF0aC5sb2coKChyYW5kb21WYWx1ZSAqIHN1YnRlcm0pICogdGVybVNraXApIC8gKHRvdGFsSXRlbUNvdW50ICsgeCkpIC8gcmVzZXJ2b2lyU2l6ZSk7XG4gICAgICAgIHZhciByaHMgPSAoKCh0b3RhbEl0ZW1Db3VudCArIHgpIC8gdGVybVNraXApICogdGVybSkgLyB0b3RhbEl0ZW1Db3VudDtcblxuICAgICAgICBpZiAobGhzIDw9IHJocykge1xuICAgICAgICAgIFcgPSByaHMgLyBsaHM7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgeSA9ICgoKHJhbmRvbVZhbHVlICogKHRvdGFsSXRlbUNvdW50ICsgMSkpIC8gdGVybSkgKiAodG90YWxJdGVtQ291bnQgKyB0b1NraXAgKyAxKSkgLyAodG90YWxJdGVtQ291bnQgKyB4KTtcblxuICAgICAgICBpZiAocmVzZXJ2b2lyU2l6ZSA8IHRvU2tpcCkge1xuICAgICAgICAgIGRlbm9tID0gdG90YWxJdGVtQ291bnQ7XG4gICAgICAgICAgbnVtZXJfbGltID0gdGVybSArIHRvU2tpcDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBkZW5vbSA9IHRvdGFsSXRlbUNvdW50IC0gcmVzZXJ2b2lyU2l6ZSArIHRvU2tpcDtcbiAgICAgICAgICBudW1lcl9saW0gPSB0b3RhbEl0ZW1Db3VudCArIDE7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKG51bWVyID0gdG90YWxJdGVtQ291bnQgKyB0b1NraXA7IG51bWVyID49IG51bWVyX2xpbTsgbnVtZXItLSkge1xuICAgICAgICAgIHkgPSAoeSAqIG51bWVyKSAvIGRlbm9tO1xuICAgICAgICAgIGRlbm9tLS07XG4gICAgICAgIH1cblxuICAgICAgICBXID0gTWF0aC5leHAoLU1hdGgubG9nKHJuZygpKSAvIHJlc2Vydm9pclNpemUpO1xuXG4gICAgICAgIGlmIChNYXRoLmV4cChNYXRoLmxvZyh5KSAvIHJlc2Vydm9pclNpemUpIDw9ICh0b3RhbEl0ZW1Db3VudCArIHgpIC8gdG90YWxJdGVtQ291bnQpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHRvU2tpcDtcbiAgICB9XG4gICAgcmV0dXJuIGluZGV4VHJlZTtcbiAgfVxuICByZXR1cm4gX1Jlc2Vydm9pcjtcbn0oKSk7XG5cbmV4cG9ydCBkZWZhdWx0IFJlc2Vydm9pcjtcbiJdLCJuYW1lcyI6WyJSZXNlcnZvaXIiLCJzd2l0Y2hUb0FsZ29yaXRobVpDb25zdGFudCIsImRlYnVnIiwiX1Jlc2Vydm9pciIsInJlc2Vydm9pclNpemUiLCJzdG9yYWdlUGVyaW9kSW5NaWxsaXNlY29uZHMiLCJyYW5kb21OdW1iZXJHZW4iLCJpbnRlcnZhbCIsInJuZyIsIk1hdGgiLCJyYW5kb20iLCJtYXgiLCJmbG9vciIsInRvdGFsSXRlbUNvdW50IiwibGFzdERlbGV0ZWRJbmRleCIsIm51bVRvU2tpcCIsImN1cnJlbnRBbGdvcml0aG0iLCJhbGdvcml0aG1YIiwic3dpdGNoVGhyZXNob2xkIiwiYWxnb3JpdGhtUiIsIkluZmluaXR5IiwiYWxnb3JpdGhtWiIsImFsZ29yaXRobVhDb3VudCIsIlciLCJleHAiLCJsb2ciLCJldmljdE5leHQiLCJpbmRleFRyZWUiLCJBdmxUcmVlIiwiYSIsImIiLCJpbmRleCIsInZhbHVlVHJlZSIsImluaXRpYWxJbmRleCIsInJlbW92ZU9sZFJlY29yZHMiLCJlbGVtZW50IiwiYXQiLCJEYXRlIiwibm93IiwidGltZSIsInJlbW92ZUF0IiwiZGVsZXRlZEluZGV4RGlmZiIsInJlbW92ZSIsImRhdGEiLCJnZXRQZXJjZW50aWxlIiwicGVyY2VudCIsImFyZ3VtZW50cyIsInNpemUiLCJsb3dlciIsImZyYWN0aW9uUGFydCIsInBlcmNlbnRpbGUiLCJwYXJzZUZsb2F0IiwicHVzaFNvbWUiLCJsZW4iLCJtaW4iLCJpIiwibGVuZ3RoIiwidmFsdWUiLCJhZGRTYW1wbGUiLCJjYWxsIiwiZnJvbVBsYWluT2JqZWN0Iiwic2FtcGxlIiwiaW5zZXJ0IiwicmVwbGFjZVJhbmRvbVNhbXBsZSIsInJlc2Vydm9pciIsInJhbmRvbUluZGV4IiwibG9jYWxJdGVtQ291bnQiLCJyYW5kb21WYWx1ZSIsInRvU2tpcCIsInF1b3RpZW50IiwidGVybSIsImRlbm9tIiwibnVtZXIiLCJudW1lcl9saW0iLCJ4Iiwic3VidGVybSIsInRlcm1Ta2lwIiwibGhzIiwicmhzIiwieSJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7K0JBd1BBOzs7ZUFBQTs7O2dFQXRQb0I7Ozs7OztBQUVwQixnQkFBZ0IsR0FDaEIsa0JBQWtCLEdBQ2xCLE1BQU1BLFlBQWE7SUFFakIsSUFBSUMsNkJBQTZCO0lBQ2pDLElBQUlDLFFBQVE7SUFFWjs7Ozs7R0FLQyxHQUNELFNBQVNDLFdBQVdDLGFBQWEsRUFBRUMsMkJBQTJCLEVBQUVDLGVBQWU7UUFDN0UsSUFBSUMsV0FBV0Y7UUFDZixJQUFJRyxNQUFNRixtQkFBbUJHLEtBQUtDLE1BQU07UUFDeEMsSUFBSU4sZ0JBQWdCSyxLQUFLRSxHQUFHLENBQUMsR0FBRyxBQUFDRixLQUFLRyxLQUFLLENBQUNSLGtCQUFrQixLQUFNO1FBQ3BFLElBQUlTLGlCQUFpQjtRQUNyQixJQUFJQyxtQkFBbUIsQ0FBQztRQUN4QixJQUFJQyxZQUFZLENBQUM7UUFDakIsSUFBSUMsbUJBQW1CQztRQUN2QixJQUFJQyxrQkFDRmpCLDZCQUE2Qkc7UUFFL0IsSUFBSUYsVUFBVSxLQUFLO1lBQ2pCYyxtQkFBbUJHO1FBQ3JCLE9BQU8sSUFBSWpCLFVBQVUsS0FBSztZQUN4QmdCLGtCQUFrQkU7UUFDcEIsT0FBTyxJQUFJbEIsVUFBVSxLQUFLO1lBQ3hCYyxtQkFBbUJLO1FBQ3JCO1FBRUEsSUFBSUMsa0JBQWtCO1FBQ3RCLElBQUlDLElBQUlkLEtBQUtlLEdBQUcsQ0FBQyxDQUFDZixLQUFLZ0IsR0FBRyxDQUFDakIsU0FBU0o7UUFDcEMsSUFBSXNCLFlBQVk7UUFFaEIsSUFBSUMsWUFBWSxJQUFJQyxnQkFBTyxDQUFDLFNBQVVDLENBQUMsRUFBRUMsQ0FBQztZQUN4QyxPQUFPRCxFQUFFRSxLQUFLLEdBQUdELEVBQUVDLEtBQUs7UUFDMUI7UUFFQSxJQUFJQyxZQUFZLElBQUlKLGdCQUFPLENBQUMsU0FBVUMsQ0FBQyxFQUFFQyxDQUFDO1lBQ3hDLE9BQU9ELElBQUlDO1FBQ2I7UUFDQSxJQUFJRyxlQUFlO1FBRW5CTixVQUFVTyxnQkFBZ0IsR0FBRztZQUMzQixNQUFPLEtBQU07Z0JBQ1gsSUFBSUMsVUFBVSxJQUFJLENBQUNDLEVBQUUsQ0FBQztnQkFDdEIsSUFBSUQsWUFBWSxRQUFRRSxLQUFLQyxHQUFHLEtBQUtILFFBQVFJLElBQUksR0FBR2hDLFVBQVU7b0JBQzVELElBQUksQ0FBQ2lDLFFBQVEsQ0FBQztvQkFDZCxJQUFJQyxtQkFBbUJOLFFBQVFKLEtBQUssR0FBR2pCO29CQUN2Q0EsbUJBQW1CcUIsUUFBUUosS0FBSztvQkFDaENDLFVBQVVVLE1BQU0sQ0FBQ1AsUUFBUVEsSUFBSTtvQkFDN0I5QixrQkFBa0I0QjtvQkFDbEJuQixrQkFBa0JiLEtBQUtFLEdBQUcsQ0FBQyxHQUFHVyxrQkFBa0JtQjtnQkFDbEQsT0FBTztvQkFDTDtnQkFDRjtZQUNGO1FBQ0Y7UUFFQWQsVUFBVWlCLGFBQWEsR0FBRztZQUN4QixJQUFJQyxVQUFVQyxTQUFTLENBQUMsRUFBRTtZQUMxQixJQUFJLENBQUNaLGdCQUFnQjtZQUNyQixNQUFNSCxRQUFRLEFBQUMsQ0FBQSxJQUFJLENBQUNnQixJQUFJLEtBQUssQ0FBQSxJQUFLRixVQUFVO1lBQzVDLE1BQU1HLFFBQVF2QyxLQUFLRyxLQUFLLENBQUNtQjtZQUN6QixNQUFNa0IsZUFBZWxCLFFBQVFpQjtZQUM3QixJQUFJRSxhQUFhbEIsVUFBVUksRUFBRSxDQUFDWTtZQUM5QixJQUFJQyxlQUFlLEdBQUc7Z0JBQ3BCQyxjQUFjRCxlQUFnQmpCLENBQUFBLFVBQVVJLEVBQUUsQ0FBQ1ksUUFBUSxLQUFLaEIsVUFBVUksRUFBRSxDQUFDWSxNQUFLO1lBQzVFO1lBQ0EsT0FBT0csV0FBV0Q7UUFDcEI7UUFFQXZCLFVBQVV5QixRQUFRLEdBQUc7WUFDbkIsSUFBSUMsTUFBTTVDLEtBQUs2QyxHQUFHLENBQUMsSUFBSSxDQUFDUCxJQUFJLElBQUkzQztZQUNoQyxJQUFLLElBQUltRCxJQUFJLEdBQUdBLElBQUlULFVBQVVVLE1BQU0sRUFBRUQsSUFBSztnQkFDekMsSUFBSSxDQUFDckIsZ0JBQWdCO2dCQUNyQixJQUFJdUIsUUFBUTtvQkFBQzFCLE9BQU9FO29CQUFjTSxNQUFNRixLQUFLQyxHQUFHO29CQUFJSyxNQUFNRyxTQUFTLENBQUNTLEVBQUU7Z0JBQUE7Z0JBQ3RFRyxVQUFVQyxJQUFJLENBQUMsSUFBSSxFQUFFRjtnQkFDckJ4QjtZQUNGO1lBQ0EsT0FBT29CO1FBQ1Q7UUFFQTFCLFVBQVVpQyxlQUFlLEdBQUc7WUFDMUIsSUFBSVAsTUFBTTVDLEtBQUs2QyxHQUFHLENBQUMsSUFBSSxDQUFDUCxJQUFJLElBQUkzQztZQUNoQyxJQUFLLElBQUltRCxJQUFJLEdBQUdBLElBQUlULFVBQVVVLE1BQU0sRUFBRUQsSUFBSztnQkFDekMsSUFBSUUsUUFBUTtvQkFBQzFCLE9BQU9lLFNBQVMsQ0FBQ1MsRUFBRSxDQUFDeEIsS0FBSztvQkFBRVEsTUFBTU8sU0FBUyxDQUFDUyxFQUFFLENBQUNoQixJQUFJO29CQUFFSSxNQUFNRyxTQUFTLENBQUNTLEVBQUUsQ0FBQ1osSUFBSTtnQkFBQTtnQkFDeEZlLFVBQVVDLElBQUksQ0FBQyxJQUFJLEVBQUVGO2dCQUNyQnhCO1lBQ0Y7WUFDQSxPQUFPb0I7UUFDVDtRQUVBLElBQUlLLFlBQVksU0FBVUcsTUFBTTtZQUM5QixJQUFJLElBQUksQ0FBQ2QsSUFBSSxLQUFLM0MsZUFBZTtnQkFDL0IsSUFBSSxDQUFDMEQsTUFBTSxDQUFDRDtnQkFDWjdCLFVBQVU4QixNQUFNLENBQUNELE9BQU9sQixJQUFJO1lBQzlCLE9BQU87Z0JBQ0wsSUFBSTVCLFlBQVksR0FBRztvQkFDakJBLFlBQVlDO2dCQUNkO2dCQUNBLElBQUlELGNBQWMsR0FBRztvQkFDbkJnRCxvQkFBb0JGLFFBQVEsSUFBSTtnQkFDbEM7Z0JBQ0E5QztZQUNGO1lBQ0FGO1lBQ0EsT0FBTyxJQUFJO1FBQ2I7UUFFQSxTQUFTa0Qsb0JBQW9CRixNQUFNLEVBQUVHLFNBQVM7WUFDNUMsSUFBSUM7WUFDSixJQUFJdkMsY0FBYyxNQUFNO2dCQUN0QnVDLGNBQWN2QztnQkFDZEEsWUFBWTtZQUNkLE9BQU87Z0JBQ0x1QyxjQUFjeEQsS0FBS0csS0FBSyxDQUFDSixRQUFRSjtZQUNuQztZQUNBLElBQUlxRCxRQUFRTyxVQUFVNUIsRUFBRSxDQUFDNkI7WUFDekJELFVBQVV4QixRQUFRLENBQUN5QjtZQUNuQmpDLFVBQVVVLE1BQU0sQ0FBQ2UsTUFBTWQsSUFBSTtZQUMzQlgsVUFBVThCLE1BQU0sQ0FBQ0QsT0FBT2xCLElBQUk7WUFDNUJxQixVQUFVRixNQUFNLENBQUNEO1FBQ25CO1FBRUE7Ozs7Ozs7OztLQVNDLEdBQ0QsU0FBUzFDO1lBQ1AsSUFBSStDLGlCQUFpQnJELGlCQUFpQixHQUNwQ3NELGNBQWMxRCxLQUFLRyxLQUFLLENBQUNKLFFBQVEwRCxpQkFDakNFLFNBQVM7WUFFWCxNQUFPRCxlQUFlL0QsY0FBZTtnQkFDbkNnRTtnQkFDQUY7Z0JBQ0FDLGNBQWMxRCxLQUFLRyxLQUFLLENBQUNKLFFBQVEwRDtZQUNuQztZQUNBeEMsWUFBWXlDO1lBQ1osT0FBT0M7UUFDVDtRQUVBOzs7Ozs7OztLQVFDLEdBQ0QsU0FBU25EO1lBQ1AsSUFBSWlELGlCQUFpQnJELGdCQUNuQnNELGNBQWMzRCxPQUNkNEQsU0FBUyxHQUNUQztZQUVGLElBQUl4RCxrQkFBa0JLLGlCQUFpQjtnQkFDckNnRDtnQkFDQTVDO2dCQUNBK0MsV0FBVy9DLGtCQUFrQjRDO2dCQUU3QixNQUFPRyxXQUFXRixZQUFhO29CQUM3QkM7b0JBQ0FGO29CQUNBNUM7b0JBQ0ErQyxXQUFXLEFBQUNBLFdBQVcvQyxrQkFBbUI0QztnQkFDNUM7Z0JBQ0EsT0FBT0U7WUFDVCxPQUFPO2dCQUNMcEQsbUJBQW1CSztnQkFDbkIsT0FBT0w7WUFDVDtRQUNGO1FBRUE7Ozs7Ozs7OztLQVNDLEdBQ0QsU0FBU0s7WUFDUCxJQUFJaUQsT0FBT3pELGlCQUFpQlQsZ0JBQWdCLEdBQzFDbUUsT0FDQUMsT0FDQUM7WUFFRixNQUFPLEtBQU07Z0JBQ1gsSUFBSU4sY0FBYzNEO2dCQUNsQixJQUFJa0UsSUFBSTdELGlCQUFrQlUsQ0FBQUEsSUFBSSxDQUFBO2dCQUM5QixJQUFJNkMsU0FBUzNELEtBQUtHLEtBQUssQ0FBQzhEO2dCQUV4QixJQUFJQyxVQUFXLEFBQUM5RCxDQUFBQSxpQkFBaUIsQ0FBQSxJQUFLeUQ7Z0JBQ3RDSyxXQUFXQTtnQkFDWCxJQUFJQyxXQUFXTixPQUFPRjtnQkFDdEIsSUFBSVMsTUFBTXBFLEtBQUtlLEdBQUcsQ0FBQ2YsS0FBS2dCLEdBQUcsQ0FBQyxBQUFFMEMsY0FBY1EsVUFBV0MsV0FBYS9ELENBQUFBLGlCQUFpQjZELENBQUFBLEtBQU10RTtnQkFDM0YsSUFBSTBFLE1BQU0sQUFBR2pFLENBQUFBLGlCQUFpQjZELENBQUFBLElBQUtFLFdBQVlOLE9BQVF6RDtnQkFFdkQsSUFBSWdFLE9BQU9DLEtBQUs7b0JBQ2R2RCxJQUFJdUQsTUFBTUQ7b0JBQ1Y7Z0JBQ0Y7Z0JBRUEsSUFBSUUsSUFBSSxBQUFHWixjQUFldEQsQ0FBQUEsaUJBQWlCLENBQUEsSUFBTXlELE9BQVN6RCxDQUFBQSxpQkFBaUJ1RCxTQUFTLENBQUEsSUFBT3ZELENBQUFBLGlCQUFpQjZELENBQUFBO2dCQUU1RyxJQUFJdEUsZ0JBQWdCZ0UsUUFBUTtvQkFDMUJHLFFBQVExRDtvQkFDUjRELFlBQVlILE9BQU9GO2dCQUNyQixPQUFPO29CQUNMRyxRQUFRMUQsaUJBQWlCVCxnQkFBZ0JnRTtvQkFDekNLLFlBQVk1RCxpQkFBaUI7Z0JBQy9CO2dCQUVBLElBQUsyRCxRQUFRM0QsaUJBQWlCdUQsUUFBUUksU0FBU0MsV0FBV0QsUUFBUztvQkFDakVPLElBQUksQUFBQ0EsSUFBSVAsUUFBU0Q7b0JBQ2xCQTtnQkFDRjtnQkFFQWhELElBQUlkLEtBQUtlLEdBQUcsQ0FBQyxDQUFDZixLQUFLZ0IsR0FBRyxDQUFDakIsU0FBU0o7Z0JBRWhDLElBQUlLLEtBQUtlLEdBQUcsQ0FBQ2YsS0FBS2dCLEdBQUcsQ0FBQ3NELEtBQUszRSxrQkFBa0IsQUFBQ1MsQ0FBQUEsaUJBQWlCNkQsQ0FBQUEsSUFBSzdELGdCQUFnQjtvQkFDbEY7Z0JBQ0Y7WUFDRjtZQUNBLE9BQU91RDtRQUNUO1FBQ0EsT0FBT3pDO0lBQ1Q7SUFDQSxPQUFPeEI7QUFDVDtNQUVBLFdBQWVIIn0=