@nova-ui/dashboards
Version:
Nova Dashboards is a framework designed to provide feature developers with a common solution for presenting data coming from various sources within a single view, as well as a set of predefined widget visualizations that are 100% configuration-driven and
220 lines • 31.5 kB
JavaScript
// © 2022 SolarWinds Worldwide, LLC. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Based on org.apache.commons.math.analysis.interpolation.LoessInterpolator
// from http://commons.apache.org/math/
// Extracted from https://github.com/jasondavies/science.js
export function loess() {
let bandwidth = 0.3, robustnessIters = 2, accuracy = 1e-12;
function smooth(xval, yval, weights) {
let n = xval.length, i;
if (n !== yval.length) {
throw new Error("Mismatched array lengths");
}
if (n === 0) {
throw new Error("At least one point required.");
}
if (arguments.length < 3) {
weights = [];
i = -1;
while (++i < n) {
weights[i] = 1;
}
}
science_stats_loessFiniteReal(xval);
science_stats_loessFiniteReal(yval);
science_stats_loessFiniteReal(weights);
science_stats_loessStrictlyIncreasing(xval);
if (n === 1) {
return [yval[0]];
}
if (n === 2) {
return [yval[0], yval[1]];
}
const bandwidthInPoints = Math.floor(bandwidth * n);
if (bandwidthInPoints < 2) {
throw new Error("Bandwidth too small.");
}
const res = [], residuals = [], robustnessWeights = [];
// Do an initial fit and 'robustnessIters' robustness iterations.
// This is equivalent to doing 'robustnessIters+1' robustness iterations
// starting with all robustness weights set to 1.
i = -1;
while (++i < n) {
res[i] = 0;
residuals[i] = 0;
robustnessWeights[i] = 1;
}
let iter = -1;
while (++iter <= robustnessIters) {
const bandwidthInterval = [0, bandwidthInPoints - 1];
// At each x, compute a local weighted linear regression
let x;
i = -1;
while (++i < n) {
x = xval[i];
// Find out the interval of source points on which
// a regression is to be made.
if (i > 0) {
science_stats_loessUpdateBandwidthInterval(xval, weights, i, bandwidthInterval);
}
const ileft = bandwidthInterval[0], iright = bandwidthInterval[1];
// Compute the point of the bandwidth interval that is
// farthest from x
const edge = xval[i] - xval[ileft] > xval[iright] - xval[i]
? ileft
: iright;
// Compute a least-squares linear fit weighted by
// the product of robustness weights and the tricube
// weight function.
// See http://en.wikipedia.org/wiki/Linear_regression
// (section "Univariate linear case")
// and http://en.wikipedia.org/wiki/Weighted_least_squares
// (section "Weighted least squares")
let sumWeights = 0, sumX = 0, sumXSquared = 0, sumY = 0, sumXY = 0, denom = Math.abs(1 / (xval[edge] - x));
for (let k = ileft; k <= iright; ++k) {
const xk = xval[k], yk = yval[k], dist = k < i ? x - xk : xk - x, w = science_stats_loessTricube(dist * denom) *
robustnessWeights[k] *
weights[k], xkw = xk * w;
sumWeights += w;
sumX += xkw;
sumXSquared += xk * xkw;
sumY += yk * w;
sumXY += yk * xkw;
}
const meanX = sumX / sumWeights, meanY = sumY / sumWeights, meanXY = sumXY / sumWeights, meanXSquared = sumXSquared / sumWeights;
const beta = Math.sqrt(Math.abs(meanXSquared - meanX * meanX)) < accuracy
? 0
: (meanXY - meanX * meanY) /
(meanXSquared - meanX * meanX);
const alpha = meanY - beta * meanX;
res[i] = beta * x + alpha;
residuals[i] = Math.abs(yval[i] - res[i]);
}
// No need to recompute the robustness weights at the last
// iteration, they won't be needed anymore
if (iter === robustnessIters) {
break;
}
// Recompute the robustness weights.
// Find the median residual.
const medianResidual = median(residuals);
if (Math.abs(medianResidual) < accuracy) {
break;
}
let arg, w;
i = -1;
while (++i < n) {
arg = residuals[i] / (6 * medianResidual);
robustnessWeights[i] = arg >= 1 ? 0 : (w = 1 - arg * arg) * w;
}
}
return res;
}
smooth.bandwidth = function (x) {
if (!arguments.length) {
return x;
}
bandwidth = x;
return smooth;
};
smooth.robustnessIterations = function (x) {
if (!arguments.length) {
return x;
}
robustnessIters = x;
return smooth;
};
smooth.accuracy = function (x) {
if (!arguments.length) {
return x;
}
accuracy = x;
return smooth;
};
return smooth;
}
function science_stats_loessFiniteReal(values) {
let n = values.length, i = -1;
while (++i < n) {
if (!isFinite(values[i])) {
return false;
}
}
return true;
}
function science_stats_loessStrictlyIncreasing(xval) {
// eslint-disable-next-line prefer-const
let n = xval.length, i = 0;
while (++i < n) {
if (xval[i - 1] >= xval[i]) {
return false;
}
}
return true;
}
// Compute the tricube weight function.
// http://en.wikipedia.org/wiki/Local_regression#Weight_function
function science_stats_loessTricube(x) {
return (x = 1 - x * x * x) * x * x;
}
// Given an index interval into xval that embraces a certain number of
// points closest to xval[i-1], update the interval so that it embraces
// the same number of points closest to xval[i], ignoring zero weights.
function science_stats_loessUpdateBandwidthInterval(xval, weights, i, bandwidthInterval) {
const left = bandwidthInterval[0], right = bandwidthInterval[1];
// The right edge should be adjusted if the next point to the right
// is closer to xval[i] than the leftmost point of the current interval
const nextRight = science_stats_loessNextNonzero(weights, right);
if (nextRight < xval.length &&
xval[nextRight] - xval[i] < xval[i] - xval[left]) {
const nextLeft = science_stats_loessNextNonzero(weights, left);
bandwidthInterval[0] = nextLeft;
bandwidthInterval[1] = nextRight;
}
}
function science_stats_loessNextNonzero(weights, i) {
let j = i + 1;
while (j < weights.length && weights[j] === 0) {
j++;
}
return j;
}
function median(x) {
return quantiles(x, [0.5])[0];
}
// Uses R's quantile algorithm type=7.
function quantiles(d, quantiles) {
d = d.slice().sort(ascending);
const n1 = d.length - 1;
return quantiles.map(function (q) {
if (q === 0) {
return d[0];
}
else if (q === 1) {
return d[n1];
}
const index = 1 + q * n1, lo = Math.floor(index), h = index - lo, a = d[lo - 1];
return h === 0 ? a : a + h * (d[lo] - a);
});
}
function ascending(a, b) {
return a - b;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9lc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvdGltZXNlcmllcy13aWRnZXQvdHJhbnNmb3JtZXIvbG9lc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseURBQXlEO0FBQ3pELEVBQUU7QUFDRiwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLDhFQUE4RTtBQUM5RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLDREQUE0RDtBQUM1RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLDRFQUE0RTtBQUM1RSwrRUFBK0U7QUFDL0UsMEVBQTBFO0FBQzFFLGlGQUFpRjtBQUNqRiw2RUFBNkU7QUFDN0UsaUJBQWlCO0FBRWpCLDRFQUE0RTtBQUM1RSx1Q0FBdUM7QUFFdkMsMkRBQTJEO0FBRTNELE1BQU0sVUFBVSxLQUFLO0lBQ2pCLElBQUksU0FBUyxHQUFHLEdBQUcsRUFDZixlQUFlLEdBQUcsQ0FBQyxFQUNuQixRQUFRLEdBQUcsS0FBSyxDQUFDO0lBRXJCLFNBQVMsTUFBTSxDQUFDLElBQWMsRUFBRSxJQUFjLEVBQUUsT0FBaUI7UUFDN0QsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFDZixDQUFDLENBQUM7UUFFTixJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQztTQUMvQztRQUNELElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNULE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztTQUNuRDtRQUVELElBQUksU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDdEIsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUNQLE9BQU8s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U0FBUyxDQUFDLENBQVMsRUFBRSxDQUFTO0lBQ25DLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNqQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbi8vIEJhc2VkIG9uIG9yZy5hcGFjaGUuY29tbW9ucy5tYXRoLmFuYWx5c2lzLmludGVycG9sYXRpb24uTG9lc3NJbnRlcnBvbGF0b3Jcbi8vIGZyb20gaHR0cDovL2NvbW1vbnMuYXBhY2hlLm9yZy9tYXRoL1xuXG4vLyBFeHRyYWN0ZWQgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vamFzb25kYXZpZXMvc2NpZW5jZS5qc1xuXG5leHBvcnQgZnVuY3Rpb24gbG9lc3MoKSB7XG4gICAgbGV0IGJhbmR3aWR0aCA9IDAuMyxcbiAgICAgICAgcm9idXN0bmVzc0l0ZXJzID0gMixcbiAgICAgICAgYWNjdXJhY3kgPSAxZS0xMjtcblxuICAgIGZ1bmN0aW9uIHNtb290aCh4dmFsOiBudW1iZXJbXSwgeXZhbDogbnVtYmVyW10sIHdlaWdodHM6IG51bWJlcltdKSB7XG4gICAgICAgIGxldCBuID0geHZhbC5sZW5ndGgsXG4gICAgICAgICAgICBpO1xuXG4gICAgICAgIGlmIChuICE9PSB5dmFsLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTWlzbWF0Y2hlZCBhcnJheSBsZW5ndGhzXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChuID09PSAwKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBdCBsZWFzdCBvbmUgcG9pbnQgcmVxdWlyZWQuXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPCAzKSB7XG4gICAgICAgICAgICB3ZWlnaHRzID0gW107XG4gICAgICAgICAgICBpID0gLTE7XG4gICAgICAgICAgICB3aGlsZSAoKytpIDwgbikge1xuICAgICAgICAgICAgICAgIHdlaWdodHNbaV0gPSAxO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgc2NpZW5jZV9zdGF0c19sb2Vzc0Zpbml0ZVJlYWwoeHZhbCk7XG4gICAgICAgIHNjaWVuY2Vfc3RhdHNfbG9lc3NGaW5pdGVSZWFsKHl2YWwpO1xuICAgICAgICBzY2llbmNlX3N0YXRzX2xvZXNzRmluaXRlUmVhbCh3ZWlnaHRzKTtcbiAgICAgICAgc2NpZW5jZV9zdGF0c19sb2Vzc1N0cmljdGx5SW5jcmVhc2luZyh4dmFsKTtcblxuICAgICAgICBpZiAobiA9PT0gMSkge1xuICAgICAgICAgICAgcmV0dXJuIFt5dmFsWzBdXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobiA9PT0gMikge1xuICAgICAgICAgICAgcmV0dXJuIFt5dmFsWzBdLCB5dmFsWzFdXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJhbmR3aWR0aEluUG9pbnRzID0gTWF0aC5mbG9vcihiYW5kd2lkdGggKiBuKTtcblxuICAgICAgICBpZiAoYmFuZHdpZHRoSW5Qb2ludHMgPCAyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJCYW5kd2lkdGggdG9vIHNtYWxsLlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlcyA9IFtdLFxuICAgICAgICAgICAgcmVzaWR1YWxzID0gW10sXG4gICAgICAgICAgICByb2J1c3RuZXNzV2VpZ2h0cyA9IFtdO1xuXG4gICAgICAgIC8vIERvIGFuIGluaXRpYWwgZml0IGFuZCAncm9idXN0bmVzc0l0ZXJzJyByb2J1c3RuZXNzIGl0ZXJhdGlvbnMuXG4gICAgICAgIC8vIFRoaXMgaXMgZXF1aXZhbGVudCB0byBkb2luZyAncm9idXN0bmVzc0l0ZXJzKzEnIHJvYnVzdG5lc3MgaXRlcmF0aW9uc1xuICAgICAgICAvLyBzdGFydGluZyB3aXRoIGFsbCByb2J1c3RuZXNzIHdlaWdodHMgc2V0IHRvIDEuXG4gICAgICAgIGkgPSAtMTtcbiAgICAgICAgd2hpbGUgKCsraSA8IG4pIHtcbiAgICAgICAgICAgIHJlc1tpXSA9IDA7XG4gICAgICAgICAgICByZXNpZHVhbHNbaV0gPSAwO1xuICAgICAgICAgICAgcm9idXN0bmVzc1dlaWdodHNbaV0gPSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGl0ZXIgPSAtMTtcbiAgICAgICAgd2hpbGUgKCsraXRlciA8PSByb2J1c3RuZXNzSXRlcnMpIHtcbiAgICAgICAgICAgIGNvbnN0IGJhbmR3aWR0aEludGVydmFsID0gWzAsIGJhbmR3aWR0aEluUG9pbnRzIC0gMV07XG4gICAgICAgICAgICAvLyBBdCBlYWNoIHgsIGNvbXB1dGUgYSBsb2NhbCB3ZWlnaHRlZCBsaW5lYXIgcmVncmVzc2lvblxuICAgICAgICAgICAgbGV0IHg7XG4gICAgICAgICAgICBpID0gLTE7XG4gICAgICAgICAgICB3aGlsZSAoKytpIDwgbikge1xuICAgICAgICAgICAgICAgIHggPSB4dmFsW2ldO1xuXG4gICAgICAgICAgICAgICAgLy8gRmluZCBvdXQgdGhlIGludGVydmFsIG9mIHNvdXJjZSBwb2ludHMgb24gd2hpY2hcbiAgICAgICAgICAgICAgICAvLyBhIHJlZ3Jlc3Npb24gaXMgdG8gYmUgbWFkZS5cbiAgICAgICAgICAgICAgICBpZiAoaSA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgc2NpZW5jZV9zdGF0c19sb2Vzc1VwZGF0ZUJhbmR3aWR0aEludGVydmFsKFxuICAgICAgICAgICAgICAgICAgICAgICAgeHZhbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBpLFxuICAgICAgICAgICAgICAgICAgICAgICAgYmFuZHdpZHRoSW50ZXJ2YWxcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjb25zdCBpbGVmdCA9IGJhbmR3aWR0aEludGVydmFsWzBdLFxuICAgICAgICAgICAgICAgICAgICBpcmlnaHQgPSBiYW5kd2lkdGhJbnRlcnZhbFsxXTtcblxuICAgICAgICAgICAgICAgIC8vIENvbXB1dGUgdGhlIHBvaW50IG9mIHRoZSBiYW5kd2lkdGggaW50ZXJ2YWwgdGhhdCBpc1xuICAgICAgICAgICAgICAgIC8vIGZhcnRoZXN0IGZyb20geFxuICAgICAgICAgICAgICAgIGNvbnN0IGVkZ2UgPVxuICAgICAgICAgICAgICAgICAgICB4dmFsW2ldIC0geHZhbFtpbGVmdF0gPiB4dmFsW2lyaWdodF0gLSB4dmFsW2ldXG4gICAgICAgICAgICAgICAgICAgICAgICA/IGlsZWZ0XG4gICAgICAgICAgICAgICAgICAgICAgICA6IGlyaWdodDtcblxuICAgICAgICAgICAgICAgIC8vIENvbXB1dGUgYSBsZWFzdC1zcXVhcmVzIGxpbmVhciBmaXQgd2VpZ2h0ZWQgYnlcbiAgICAgICAgICAgICAgICAvLyB0aGUgcHJvZHVjdCBvZiByb2J1c3RuZXNzIHdlaWdodHMgYW5kIHRoZSB0cmljdWJlXG4gICAgICAgICAgICAgICAgLy8gd2VpZ2h0IGZ1bmN0aW9uLlxuICAgICAgICAgICAgICAgIC8vIFNlZSBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xpbmVhcl9yZWdyZXNzaW9uXG4gICAgICAgICAgICAgICAgLy8gKHNlY3Rpb24gXCJVbml2YXJpYXRlIGxpbmVhciBjYXNlXCIpXG4gICAgICAgICAgICAgICAgLy8gYW5kIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvV2VpZ2h0ZWRfbGVhc3Rfc3F1YXJlc1xuICAgICAgICAgICAgICAgIC8vIChzZWN0aW9uIFwiV2VpZ2h0ZWQgbGVhc3Qgc3F1YXJlc1wiKVxuICAgICAgICAgICAgICAgIGxldCBzdW1XZWlnaHRzID0gMCxcbiAgICAgICAgICAgICAgICAgICAgc3VtWCA9IDAsXG4gICAgICAgICAgICAgICAgICAgIHN1bVhTcXVhcmVkID0gMCxcbiAgICAgICAgICAgICAgICAgICAgc3VtWSA9IDAsXG4gICAgICAgICAgICAgICAgICAgIHN1bVhZID0gMCxcbiAgICAgICAgICAgICAgICAgICAgZGVub20gPSBNYXRoLmFicygxIC8gKHh2YWxbZWRnZV0gLSB4KSk7XG5cbiAgICAgICAgICAgICAgICBmb3IgKGxldCBrID0gaWxlZnQ7IGsgPD0gaXJpZ2h0OyArK2spIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgeGsgPSB4dmFsW2tdLFxuICAgICAgICAgICAgICAgICAgICAgICAgeWsgPSB5dmFsW2tdLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGlzdCA9IGsgPCBpID8geCAtIHhrIDogeGsgLSB4LFxuICAgICAgICAgICAgICAgICAgICAgICAgdyA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NpZW5jZV9zdGF0c19sb2Vzc1RyaWN1YmUoZGlzdCAqIGRlbm9tKSAqXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9idXN0bmVzc1dlaWdodHNba10gKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodHNba10sXG4gICAgICAgICAgICAgICAgICAgICAgICB4a3cgPSB4ayAqIHc7XG4gICAgICAgICAgICAgICAgICAgIHN1bVdlaWdodHMgKz0gdztcbiAgICAgICAgICAgICAgICAgICAgc3VtWCArPSB4a3c7XG4gICAgICAgICAgICAgICAgICAgIHN1bVhTcXVhcmVkICs9IHhrICogeGt3O1xuICAgICAgICAgICAgICAgICAgICBzdW1ZICs9IHlrICogdztcbiAgICAgICAgICAgICAgICAgICAgc3VtWFkgKz0geWsgKiB4a3c7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgbWVhblggPSBzdW1YIC8gc3VtV2VpZ2h0cyxcbiAgICAgICAgICAgICAgICAgICAgbWVhblkgPSBzdW1ZIC8gc3VtV2VpZ2h0cyxcbiAgICAgICAgICAgICAgICAgICAgbWVhblhZID0gc3VtWFkgLyBzdW1XZWlnaHRzLFxuICAgICAgICAgICAgICAgICAgICBtZWFuWFNxdWFyZWQgPSBzdW1YU3F1YXJlZCAvIHN1bVdlaWdodHM7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBiZXRhID1cbiAgICAgICAgICAgICAgICAgICAgTWF0aC5zcXJ0KE1hdGguYWJzKG1lYW5YU3F1YXJlZCAtIG1lYW5YICogbWVhblgpKSA8IGFjY3VyYWN5XG4gICAgICAgICAgICAgICAgICAgICAgICA/IDBcbiAgICAgICAgICAgICAgICAgICAgICAgIDogKG1lYW5YWSAtIG1lYW5YICogbWVhblkpIC9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgKG1lYW5YU3F1YXJlZCAtIG1lYW5YICogbWVhblgpO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgYWxwaGEgPSBtZWFuWSAtIGJldGEgKiBtZWFuWDtcblxuICAgICAgICAgICAgICAgIHJlc1tpXSA9IGJldGEgKiB4ICsgYWxwaGE7XG4gICAgICAgICAgICAgICAgcmVzaWR1YWxzW2ldID0gTWF0aC5hYnMoeXZhbFtpXSAtIHJlc1tpXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIE5vIG5lZWQgdG8gcmVjb21wdXRlIHRoZSByb2J1c3RuZXNzIHdlaWdodHMgYXQgdGhlIGxhc3RcbiAgICAgICAgICAgIC8vIGl0ZXJhdGlvbiwgdGhleSB3b24ndCBiZSBuZWVkZWQgYW55bW9yZVxuICAgICAgICAgICAgaWYgKGl0ZXIgPT09IHJvYnVzdG5lc3NJdGVycykge1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBSZWNvbXB1dGUgdGhlIHJvYnVzdG5lc3Mgd2VpZ2h0cy5cblxuICAgICAgICAgICAgLy8gRmluZCB0aGUgbWVkaWFuIHJlc2lkdWFsLlxuICAgICAgICAgICAgY29uc3QgbWVkaWFuUmVzaWR1YWwgPSBtZWRpYW4ocmVzaWR1YWxzKTtcblxuICAgICAgICAgICAgaWYgKE1hdGguYWJzKG1lZGlhblJlc2lkdWFsKSA8IGFjY3VyYWN5KSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBhcmcsIHc7XG4gICAgICAgICAgICBpID0gLTE7XG4gICAgICAgICAgICB3aGlsZSAoKytpIDwgbikge1xuICAgICAgICAgICAgICAgIGFyZyA9IHJlc2lkdWFsc1tpXSAvICg2ICogbWVkaWFuUmVzaWR1YWwpO1xuICAgICAgICAgICAgICAgIHJvYnVzdG5lc3NXZWlnaHRzW2ldID0gYXJnID49IDEgPyAwIDogKHcgPSAxIC0gYXJnICogYXJnKSAqIHc7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIHNtb290aC5iYW5kd2lkdGggPSBmdW5jdGlvbiAoeDogYW55KSB7XG4gICAgICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuIHg7XG4gICAgICAgIH1cbiAgICAgICAgYmFuZHdpZHRoID0geDtcbiAgICAgICAgcmV0dXJuIHNtb290aDtcbiAgICB9O1xuXG4gICAgc21vb3RoLnJvYnVzdG5lc3NJdGVyYXRpb25zID0gZnVuY3Rpb24gKHg6IGFueSkge1xuICAgICAgICBpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICB9XG4gICAgICAgIHJvYnVzdG5lc3NJdGVycyA9IHg7XG4gICAgICAgIHJldHVybiBzbW9vdGg7XG4gICAgfTtcblxuICAgIHNtb290aC5hY2N1cmFjeSA9IGZ1bmN0aW9uICh4OiBhbnkpIHtcbiAgICAgICAgaWYgKCFhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4geDtcbiAgICAgICAgfVxuICAgICAgICBhY2N1cmFjeSA9IHg7XG4gICAgICAgIHJldHVybiBzbW9vdGg7XG4gICAgfTtcblxuICAgIHJldHVybiBzbW9vdGg7XG59XG5cbmZ1bmN0aW9uIHNjaWVuY2Vfc3RhdHNfbG9lc3NGaW5pdGVSZWFsKHZhbHVlczogbnVtYmVyW10pIHtcbiAgICBsZXQgbiA9IHZhbHVlcy5sZW5ndGgsXG4gICAgICAgIGkgPSAtMTtcblxuICAgIHdoaWxlICgrK2kgPCBuKSB7XG4gICAgICAgIGlmICghaXNGaW5pdGUodmFsdWVzW2ldKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59XG5cbmZ1bmN0aW9uIHNjaWVuY2Vfc3RhdHNfbG9lc3NTdHJpY3RseUluY3JlYXNpbmcoeHZhbDogbnVtYmVyW10pIHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJlZmVyLWNvbnN0XG4gICAgbGV0IG4gPSB4dmFsLmxlbmd0aCxcbiAgICAgICAgaSA9IDA7XG5cbiAgICB3aGlsZSAoKytpIDwgbikge1xuICAgICAgICBpZiAoeHZhbFtpIC0gMV0gPj0geHZhbFtpXSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59XG5cbi8vIENvbXB1dGUgdGhlIHRyaWN1YmUgd2VpZ2h0IGZ1bmN0aW9uLlxuLy8gaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Mb2NhbF9yZWdyZXNzaW9uI1dlaWdodF9mdW5jdGlvblxuZnVuY3Rpb24gc2NpZW5jZV9zdGF0c19sb2Vzc1RyaWN1YmUoeDogbnVtYmVyKSB7XG4gICAgcmV0dXJuICh4ID0gMSAtIHggKiB4ICogeCkgKiB4ICogeDtcbn1cblxuLy8gR2l2ZW4gYW4gaW5kZXggaW50ZXJ2YWwgaW50byB4dmFsIHRoYXQgZW1icmFjZXMgYSBjZXJ0YWluIG51bWJlciBvZlxuLy8gcG9pbnRzIGNsb3Nlc3QgdG8geHZhbFtpLTFdLCB1cGRhdGUgdGhlIGludGVydmFsIHNvIHRoYXQgaXQgZW1icmFjZXNcbi8vIHRoZSBzYW1lIG51bWJlciBvZiBwb2ludHMgY2xvc2VzdCB0byB4dmFsW2ldLCBpZ25vcmluZyB6ZXJvIHdlaWdodHMuXG5mdW5jdGlvbiBzY2llbmNlX3N0YXRzX2xvZXNzVXBkYXRlQmFuZHdpZHRoSW50ZXJ2YWwoXG4gICAgeHZhbDogbnVtYmVyW10sXG4gICAgd2VpZ2h0czogbnVtYmVyW10sXG4gICAgaTogbnVtYmVyLFxuICAgIGJhbmR3aWR0aEludGVydmFsOiBudW1iZXJbXVxuKSB7XG4gICAgY29uc3QgbGVmdCA9IGJhbmR3aWR0aEludGVydmFsWzBdLFxuICAgICAgICByaWdodCA9IGJhbmR3aWR0aEludGVydmFsWzFdO1xuXG4gICAgLy8gVGhlIHJpZ2h0IGVkZ2Ugc2hvdWxkIGJlIGFkanVzdGVkIGlmIHRoZSBuZXh0IHBvaW50IHRvIHRoZSByaWdodFxuICAgIC8vIGlzIGNsb3NlciB0byB4dmFsW2ldIHRoYW4gdGhlIGxlZnRtb3N0IHBvaW50IG9mIHRoZSBjdXJyZW50IGludGVydmFsXG4gICAgY29uc3QgbmV4dFJpZ2h0ID0gc2NpZW5jZV9zdGF0c19sb2Vzc05leHROb256ZXJvKHdlaWdodHMsIHJpZ2h0KTtcbiAgICBpZiAoXG4gICAgICAgIG5leHRSaWdodCA8IHh2YWwubGVuZ3RoICYmXG4gICAgICAgIHh2YWxbbmV4dFJpZ2h0XSAtIHh2YWxbaV0gPCB4dmFsW2ldIC0geHZhbFtsZWZ0XVxuICAgICkge1xuICAgICAgICBjb25zdCBuZXh0TGVmdCA9IHNjaWVuY2Vfc3RhdHNfbG9lc3NOZXh0Tm9uemVybyh3ZWlnaHRzLCBsZWZ0KTtcbiAgICAgICAgYmFuZHdpZHRoSW50ZXJ2YWxbMF0gPSBuZXh0TGVmdDtcbiAgICAgICAgYmFuZHdpZHRoSW50ZXJ2YWxbMV0gPSBuZXh0UmlnaHQ7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBzY2llbmNlX3N0YXRzX2xvZXNzTmV4dE5vbnplcm8od2VpZ2h0czogbnVtYmVyW10sIGk6IG51bWJlcikge1xuICAgIGxldCBqID0gaSArIDE7XG4gICAgd2hpbGUgKGogPCB3ZWlnaHRzLmxlbmd0aCAmJiB3ZWlnaHRzW2pdID09PSAwKSB7XG4gICAgICAgIGorKztcbiAgICB9XG4gICAgcmV0dXJuIGo7XG59XG5cbmZ1bmN0aW9uIG1lZGlhbih4OiBudW1iZXJbXSkge1xuICAgIHJldHVybiBxdWFudGlsZXMoeCwgWzAuNV0pWzBdO1xufVxuXG4vLyBVc2VzIFIncyBxdWFudGlsZSBhbGdvcml0aG0gdHlwZT03LlxuZnVuY3Rpb24gcXVhbnRpbGVzKGQ6IG51bWJlcltdLCBxdWFudGlsZXM6IG51bWJlcltdKSB7XG4gICAgZCA9IGQuc2xpY2UoKS5zb3J0KGFzY2VuZGluZyk7XG4gICAgY29uc3QgbjEgPSBkLmxlbmd0aCAtIDE7XG4gICAgcmV0dXJuIHF1YW50aWxlcy5tYXAoZnVuY3Rpb24gKHEpIHtcbiAgICAgICAgaWYgKHEgPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBkWzBdO1xuICAgICAgICB9IGVsc2UgaWYgKHEgPT09IDEpIHtcbiAgICAgICAgICAgIHJldHVybiBkW24xXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGluZGV4ID0gMSArIHEgKiBuMSxcbiAgICAgICAgICAgIGxvID0gTWF0aC5mbG9vcihpbmRleCksXG4gICAgICAgICAgICBoID0gaW5kZXggLSBsbyxcbiAgICAgICAgICAgIGEgPSBkW2xvIC0gMV07XG5cbiAgICAgICAgcmV0dXJuIGggPT09IDAgPyBhIDogYSArIGggKiAoZFtsb10gLSBhKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gYXNjZW5kaW5nKGE6IG51bWJlciwgYjogbnVtYmVyKSB7XG4gICAgcmV0dXJuIGEgLSBiO1xufVxuIl19