matrix-react-sdk
Version:
SDK for matrix.org using React
353 lines (327 loc) • 38.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GroupedArray = exports.ArrayUtil = void 0;
exports.arrayDiff = arrayDiff;
exports.arrayFastClone = arrayFastClone;
exports.arrayFastResample = arrayFastResample;
exports.arrayHasDiff = arrayHasDiff;
exports.arrayHasOrderChange = arrayHasOrderChange;
exports.arrayIntersection = arrayIntersection;
exports.arrayRescale = arrayRescale;
exports.arraySeed = arraySeed;
exports.arraySmoothingResample = arraySmoothingResample;
exports.arrayTrimFill = arrayTrimFill;
exports.arrayUnion = arrayUnion;
exports.asyncEvery = asyncEvery;
exports.asyncSome = asyncSome;
exports.concat = void 0;
exports.filterBoolean = filterBoolean;
exports.moveElement = moveElement;
var _numbers = require("./numbers");
/*
Copyright 2024 New Vector Ltd.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
/**
* Quickly resample an array to have less/more data points. If an input which is larger
* than the desired size is provided, it will be downsampled. Similarly, if the input
* is smaller than the desired size then it will be upsampled.
* @param {number[]} input The input array to resample.
* @param {number} points The number of samples to end up with.
* @returns {number[]} The resampled array.
*/
function arrayFastResample(input, points) {
if (input.length === points) return input; // short-circuit a complicated call
// Heavily inspired by matrix-media-repo (used with permission)
// https://github.com/turt2live/matrix-media-repo/blob/abe72c87d2e29/util/util_audio/fastsample.go#L10
const samples = [];
if (input.length > points) {
// Danger: this loop can cause out of memory conditions if the input is too small.
const everyNth = Math.round(input.length / points);
for (let i = 0; i < input.length; i += everyNth) {
samples.push(input[i]);
}
} else {
// Smaller inputs mean we have to spread the values over the desired length. We
// end up overshooting the target length in doing this, but we're not looking to
// be super accurate so we'll let the sanity trims do their job.
const spreadFactor = Math.ceil(points / input.length);
for (const val of input) {
samples.push(...arraySeed(val, spreadFactor));
}
}
// Trim to size & return
return arrayTrimFill(samples, points, arraySeed(input[input.length - 1], points));
}
/**
* Attempts a smooth resample of the given array. This is functionally similar to arrayFastResample
* though can take longer due to the smoothing of data.
* @param {number[]} input The input array to resample.
* @param {number} points The number of samples to end up with.
* @returns {number[]} The resampled array.
*/
// ts-prune-ignore-next
function arraySmoothingResample(input, points) {
if (input.length === points) return input; // short-circuit a complicated call
let samples = [];
if (input.length > points) {
// We're downsampling. To preserve the curve we'll actually reduce our sample
// selection and average some points between them.
// All we're doing here is repeatedly averaging the waveform down to near our
// target value. We don't average down to exactly our target as the loop might
// never end, and we can over-average the data. Instead, we'll get as far as
// we can and do a followup fast resample (the neighbouring points will be close
// to the actual waveform, so we can get away with this safely).
while (samples.length > points * 2 || samples.length === 0) {
samples = [];
for (let i = 1; i < input.length - 1; i += 2) {
const prevPoint = input[i - 1];
const nextPoint = input[i + 1];
const currPoint = input[i];
const average = (prevPoint + nextPoint + currPoint) / 3;
samples.push(average);
}
input = samples;
}
return arrayFastResample(samples, points);
} else {
// In practice there's not much purpose in burning CPU for short arrays only to
// end up with a result that can't possibly look much different than the fast
// resample, so just skip ahead to the fast resample.
return arrayFastResample(input, points);
}
}
/**
* Rescales the input array to have values that are inclusively within the provided
* minimum and maximum.
* @param {number[]} input The array to rescale.
* @param {number} newMin The minimum value to scale to.
* @param {number} newMax The maximum value to scale to.
* @returns {number[]} The rescaled array.
*/
// ts-prune-ignore-next
function arrayRescale(input, newMin, newMax) {
const min = Math.min(...input);
const max = Math.max(...input);
return input.map(v => (0, _numbers.percentageWithin)((0, _numbers.percentageOf)(v, min, max), newMin, newMax));
}
/**
* Creates an array of the given length, seeded with the given value.
* @param {T} val The value to seed the array with.
* @param {number} length The length of the array to create.
* @returns {T[]} The array.
*/
function arraySeed(val, length) {
// Size the array up front for performance, and use `fill` to let the browser
// optimize the operation better than we can with a `for` loop, if it wants.
return new Array(length).fill(val);
}
/**
* Trims or fills the array to ensure it meets the desired length. The seed array
* given is pulled from to fill any missing slots - it is recommended that this be
* at least `len` long. The resulting array will be exactly `len` long, either
* trimmed from the source or filled with the some/all of the seed array.
* @param {T[]} a The array to trim/fill.
* @param {number} len The length to trim or fill to, as needed.
* @param {T[]} seed Values to pull from if the array needs filling.
* @returns {T[]} The resulting array of `len` length.
*/
function arrayTrimFill(a, len, seed) {
// Dev note: we do length checks because the spread operator can result in some
// performance penalties in more critical code paths. As a utility, it should be
// as fast as possible to not cause a problem for the call stack, no matter how
// critical that stack is.
if (a.length === len) return a;
if (a.length > len) return a.slice(0, len);
return a.concat(seed.slice(0, len - a.length));
}
/**
* Clones an array as fast as possible, retaining references of the array's values.
* @param a The array to clone. Must be defined.
* @returns A copy of the array.
*/
function arrayFastClone(a) {
return a.slice(0, a.length);
}
/**
* Determines if the two arrays are different either in length, contents,
* or order of those contents.
* @param a The first array. Must be defined.
* @param b The second array. Must be defined.
* @returns True if they are different, false otherwise.
*/
function arrayHasOrderChange(a, b) {
if (a.length === b.length) {
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return true;
}
return false;
} else {
return true; // like arrayHasDiff, a difference in length is a natural change
}
}
/**
* Determines if two arrays are different through a shallow comparison.
* @param a The first array. Must be defined.
* @param b The second array. Must be defined.
* @returns True if they are different, false otherwise.
*/
function arrayHasDiff(a, b) {
if (a.length === b.length) {
// When the lengths are equal, check to see if either array is missing
// an element from the other.
if (b.some(i => !a.includes(i))) return true;
if (a.some(i => !b.includes(i))) return true;
// if all the keys are common, say so
return false;
} else {
return true; // different lengths means they are naturally diverged
}
}
/**
* Performs a diff on two arrays. The result is what is different with the
* first array (`added` in the returned object means objects in B that aren't
* in A). Shallow comparisons are used to perform the diff.
* @param a The first array. Must be defined.
* @param b The second array. Must be defined.
* @returns The diff between the arrays.
*/
function arrayDiff(a, b) {
return {
added: b.filter(i => !a.includes(i)),
removed: a.filter(i => !b.includes(i))
};
}
/**
* Returns the intersection of two arrays.
* @param a The first array. Must be defined.
* @param b The second array. Must be defined.
* @returns The intersection of the arrays.
*/
function arrayIntersection(a, b) {
return a.filter(i => b.includes(i));
}
/**
* Unions arrays, deduping contents using a Set.
* @param a The arrays to merge.
* @returns The union of all given arrays.
*/
function arrayUnion(...a) {
return Array.from(a.reduce((c, v) => {
v.forEach(i => c.add(i));
return c;
}, new Set()));
}
/**
* Moves a single element from fromIndex to toIndex.
* @param {array} list the list from which to construct the new list.
* @param {number} fromIndex the index of the element to move.
* @param {number} toIndex the index of where to put the element.
* @returns {array} A new array with the requested value moved.
*/
function moveElement(list, fromIndex, toIndex) {
const result = Array.from(list);
const [removed] = result.splice(fromIndex, 1);
result.splice(toIndex, 0, removed);
return result;
}
/**
* Helper functions to perform LINQ-like queries on arrays.
*/
class ArrayUtil {
/**
* Create a new array helper.
* @param a The array to help. Can be modified in-place.
*/
constructor(a) {
this.a = a;
}
/**
* The value of this array, after all appropriate alterations.
*/
get value() {
return this.a;
}
/**
* Groups an array by keys.
* @param fn The key-finding function.
* @returns This.
*/
groupBy(fn) {
const obj = this.a.reduce((rv, val) => {
const k = fn(val);
if (!rv.has(k)) rv.set(k, []);
rv.get(k).push(val);
return rv;
}, new Map());
return new GroupedArray(obj);
}
}
/**
* Helper functions to perform LINQ-like queries on groups (maps).
*/
exports.ArrayUtil = ArrayUtil;
class GroupedArray {
/**
* Creates a new group helper.
* @param val The group to help. Can be modified in-place.
*/
constructor(val) {
this.val = val;
}
/**
* The value of this group, after all applicable alterations.
*/
get value() {
return this.val;
}
/**
* Orders the grouping into an array using the provided key order.
* @param keyOrder The key order.
* @returns An array helper of the result.
*/
orderBy(keyOrder) {
const a = [];
for (const k of keyOrder) {
if (!this.val.has(k)) continue;
a.push(...this.val.get(k));
}
return new ArrayUtil(a);
}
}
exports.GroupedArray = GroupedArray;
const concat = (...arrays) => {
return arrays.reduce((concatenatedSoFar, toBeConcatenated) => {
const concatenated = new Uint8Array(concatenatedSoFar.length + toBeConcatenated.length);
concatenated.set(concatenatedSoFar, 0);
concatenated.set(toBeConcatenated, concatenatedSoFar.length);
return concatenated;
}, new Uint8Array(0));
};
/**
* Async version of Array.every.
*/
exports.concat = concat;
async function asyncEvery(values, predicate) {
for (const value of values) {
if (!(await predicate(value))) return false;
}
return true;
}
/**
* Async version of Array.some.
*/
async function asyncSome(values, predicate) {
for (const value of values) {
if (await predicate(value)) return true;
}
return false;
}
function filterBoolean(values) {
return values.filter(Boolean);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbnVtYmVycyIsInJlcXVpcmUiLCJhcnJheUZhc3RSZXNhbXBsZSIsImlucHV0IiwicG9pbnRzIiwibGVuZ3RoIiwic2FtcGxlcyIsImV2ZXJ5TnRoIiwiTWF0aCIsInJvdW5kIiwiaSIsInB1c2giLCJzcHJlYWRGYWN0b3IiLCJjZWlsIiwidmFsIiwiYXJyYXlTZWVkIiwiYXJyYXlUcmltRmlsbCIsImFycmF5U21vb3RoaW5nUmVzYW1wbGUiLCJwcmV2UG9pbnQiLCJuZXh0UG9pbnQiLCJjdXJyUG9pbnQiLCJhdmVyYWdlIiwiYXJyYXlSZXNjYWxlIiwibmV3TWluIiwibmV3TWF4IiwibWluIiwibWF4IiwibWFwIiwidiIsInBlcmNlbnRhZ2VXaXRoaW4iLCJwZXJjZW50YWdlT2YiLCJBcnJheSIsImZpbGwiLCJhIiwibGVuIiwic2VlZCIsInNsaWNlIiwiY29uY2F0IiwiYXJyYXlGYXN0Q2xvbmUiLCJhcnJheUhhc09yZGVyQ2hhbmdlIiwiYiIsImFycmF5SGFzRGlmZiIsInNvbWUiLCJpbmNsdWRlcyIsImFycmF5RGlmZiIsImFkZGVkIiwiZmlsdGVyIiwicmVtb3ZlZCIsImFycmF5SW50ZXJzZWN0aW9uIiwiYXJyYXlVbmlvbiIsImZyb20iLCJyZWR1Y2UiLCJjIiwiZm9yRWFjaCIsImFkZCIsIlNldCIsIm1vdmVFbGVtZW50IiwibGlzdCIsImZyb21JbmRleCIsInRvSW5kZXgiLCJyZXN1bHQiLCJzcGxpY2UiLCJBcnJheVV0aWwiLCJjb25zdHJ1Y3RvciIsInZhbHVlIiwiZ3JvdXBCeSIsImZuIiwib2JqIiwicnYiLCJrIiwiaGFzIiwic2V0IiwiZ2V0IiwiTWFwIiwiR3JvdXBlZEFycmF5IiwiZXhwb3J0cyIsIm9yZGVyQnkiLCJrZXlPcmRlciIsImFycmF5cyIsImNvbmNhdGVuYXRlZFNvRmFyIiwidG9CZUNvbmNhdGVuYXRlZCIsImNvbmNhdGVuYXRlZCIsIlVpbnQ4QXJyYXkiLCJhc3luY0V2ZXJ5IiwidmFsdWVzIiwicHJlZGljYXRlIiwiYXN5bmNTb21lIiwiZmlsdGVyQm9vbGVhbiIsIkJvb2xlYW4iXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvYXJyYXlzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIwLCAyMDIxIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IHBlcmNlbnRhZ2VPZiwgcGVyY2VudGFnZVdpdGhpbiB9IGZyb20gXCIuL251bWJlcnNcIjtcblxuLyoqXG4gKiBRdWlja2x5IHJlc2FtcGxlIGFuIGFycmF5IHRvIGhhdmUgbGVzcy9tb3JlIGRhdGEgcG9pbnRzLiBJZiBhbiBpbnB1dCB3aGljaCBpcyBsYXJnZXJcbiAqIHRoYW4gdGhlIGRlc2lyZWQgc2l6ZSBpcyBwcm92aWRlZCwgaXQgd2lsbCBiZSBkb3duc2FtcGxlZC4gU2ltaWxhcmx5LCBpZiB0aGUgaW5wdXRcbiAqIGlzIHNtYWxsZXIgdGhhbiB0aGUgZGVzaXJlZCBzaXplIHRoZW4gaXQgd2lsbCBiZSB1cHNhbXBsZWQuXG4gKiBAcGFyYW0ge251bWJlcltdfSBpbnB1dCBUaGUgaW5wdXQgYXJyYXkgdG8gcmVzYW1wbGUuXG4gKiBAcGFyYW0ge251bWJlcn0gcG9pbnRzIFRoZSBudW1iZXIgb2Ygc2FtcGxlcyB0byBlbmQgdXAgd2l0aC5cbiAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIHJlc2FtcGxlZCBhcnJheS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFycmF5RmFzdFJlc2FtcGxlKGlucHV0OiBudW1iZXJbXSwgcG9pbnRzOiBudW1iZXIpOiBudW1iZXJbXSB7XG4gICAgaWYgKGlucHV0Lmxlbmd0aCA9PT0gcG9pbnRzKSByZXR1cm4gaW5wdXQ7IC8vIHNob3J0LWNpcmN1aXQgYSBjb21wbGljYXRlZCBjYWxsXG5cbiAgICAvLyBIZWF2aWx5IGluc3BpcmVkIGJ5IG1hdHJpeC1tZWRpYS1yZXBvICh1c2VkIHdpdGggcGVybWlzc2lvbilcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vdHVydDJsaXZlL21hdHJpeC1tZWRpYS1yZXBvL2Jsb2IvYWJlNzJjODdkMmUyOS91dGlsL3V0aWxfYXVkaW8vZmFzdHNhbXBsZS5nbyNMMTBcbiAgICBjb25zdCBzYW1wbGVzOiBudW1iZXJbXSA9IFtdO1xuICAgIGlmIChpbnB1dC5sZW5ndGggPiBwb2ludHMpIHtcbiAgICAgICAgLy8gRGFuZ2VyOiB0aGlzIGxvb3AgY2FuIGNhdXNlIG91dCBvZiBtZW1vcnkgY29uZGl0aW9ucyBpZiB0aGUgaW5wdXQgaXMgdG9vIHNtYWxsLlxuICAgICAgICBjb25zdCBldmVyeU50aCA9IE1hdGgucm91bmQoaW5wdXQubGVuZ3RoIC8gcG9pbnRzKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbnB1dC5sZW5ndGg7IGkgKz0gZXZlcnlOdGgpIHtcbiAgICAgICAgICAgIHNhbXBsZXMucHVzaChpbnB1dFtpXSk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICAvLyBTbWFsbGVyIGlucHV0cyBtZWFuIHdlIGhhdmUgdG8gc3ByZWFkIHRoZSB2YWx1ZXMgb3ZlciB0aGUgZGVzaXJlZCBsZW5ndGguIFdlXG4gICAgICAgIC8vIGVuZCB1cCBvdmVyc2hvb3RpbmcgdGhlIHRhcmdldCBsZW5ndGggaW4gZG9pbmcgdGhpcywgYnV0IHdlJ3JlIG5vdCBsb29raW5nIHRvXG4gICAgICAgIC8vIGJlIHN1cGVyIGFjY3VyYXRlIHNvIHdlJ2xsIGxldCB0aGUgc2FuaXR5IHRyaW1zIGRvIHRoZWlyIGpvYi5cbiAgICAgICAgY29uc3Qgc3ByZWFkRmFjdG9yID0gTWF0aC5jZWlsKHBvaW50cyAvIGlucHV0Lmxlbmd0aCk7XG4gICAgICAgIGZvciAoY29uc3QgdmFsIG9mIGlucHV0KSB7XG4gICAgICAgICAgICBzYW1wbGVzLnB1c2goLi4uYXJyYXlTZWVkKHZhbCwgc3ByZWFkRmFjdG9yKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUcmltIHRvIHNpemUgJiByZXR1cm5cbiAgICByZXR1cm4gYXJyYXlUcmltRmlsbChzYW1wbGVzLCBwb2ludHMsIGFycmF5U2VlZChpbnB1dFtpbnB1dC5sZW5ndGggLSAxXSwgcG9pbnRzKSk7XG59XG5cbi8qKlxuICogQXR0ZW1wdHMgYSBzbW9vdGggcmVzYW1wbGUgb2YgdGhlIGdpdmVuIGFycmF5LiBUaGlzIGlzIGZ1bmN0aW9uYWxseSBzaW1pbGFyIHRvIGFycmF5RmFzdFJlc2FtcGxlXG4gKiB0aG91Z2ggY2FuIHRha2UgbG9uZ2VyIGR1ZSB0byB0aGUgc21vb3RoaW5nIG9mIGRhdGEuXG4gKiBAcGFyYW0ge251bWJlcltdfSBpbnB1dCBUaGUgaW5wdXQgYXJyYXkgdG8gcmVzYW1wbGUuXG4gKiBAcGFyYW0ge251bWJlcn0gcG9pbnRzIFRoZSBudW1iZXIgb2Ygc2FtcGxlcyB0byBlbmQgdXAgd2l0aC5cbiAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIHJlc2FtcGxlZCBhcnJheS5cbiAqL1xuLy8gdHMtcHJ1bmUtaWdub3JlLW5leHRcbmV4cG9ydCBmdW5jdGlvbiBhcnJheVNtb290aGluZ1Jlc2FtcGxlKGlucHV0OiBudW1iZXJbXSwgcG9pbnRzOiBudW1iZXIpOiBudW1iZXJbXSB7XG4gICAgaWYgKGlucHV0Lmxlbmd0aCA9PT0gcG9pbnRzKSByZXR1cm4gaW5wdXQ7IC8vIHNob3J0LWNpcmN1aXQgYSBjb21wbGljYXRlZCBjYWxsXG5cbiAgICBsZXQgc2FtcGxlczogbnVtYmVyW10gPSBbXTtcbiAgICBpZiAoaW5wdXQubGVuZ3RoID4gcG9pbnRzKSB7XG4gICAgICAgIC8vIFdlJ3JlIGRvd25zYW1wbGluZy4gVG8gcHJlc2VydmUgdGhlIGN1cnZlIHdlJ2xsIGFjdHVhbGx5IHJlZHVjZSBvdXIgc2FtcGxlXG4gICAgICAgIC8vIHNlbGVjdGlvbiBhbmQgYXZlcmFnZSBzb21lIHBvaW50cyBiZXR3ZWVuIHRoZW0uXG5cbiAgICAgICAgLy8gQWxsIHdlJ3JlIGRvaW5nIGhlcmUgaXMgcmVwZWF0ZWRseSBhdmVyYWdpbmcgdGhlIHdhdmVmb3JtIGRvd24gdG8gbmVhciBvdXJcbiAgICAgICAgLy8gdGFyZ2V0IHZhbHVlLiBXZSBkb24ndCBhdmVyYWdlIGRvd24gdG8gZXhhY3RseSBvdXIgdGFyZ2V0IGFzIHRoZSBsb29wIG1pZ2h0XG4gICAgICAgIC8vIG5ldmVyIGVuZCwgYW5kIHdlIGNhbiBvdmVyLWF2ZXJhZ2UgdGhlIGRhdGEuIEluc3RlYWQsIHdlJ2xsIGdldCBhcyBmYXIgYXNcbiAgICAgICAgLy8gd2UgY2FuIGFuZCBkbyBhIGZvbGxvd3VwIGZhc3QgcmVzYW1wbGUgKHRoZSBuZWlnaGJvdXJpbmcgcG9pbnRzIHdpbGwgYmUgY2xvc2VcbiAgICAgICAgLy8gdG8gdGhlIGFjdHVhbCB3YXZlZm9ybSwgc28gd2UgY2FuIGdldCBhd2F5IHdpdGggdGhpcyBzYWZlbHkpLlxuICAgICAgICB3aGlsZSAoc2FtcGxlcy5sZW5ndGggPiBwb2ludHMgKiAyIHx8IHNhbXBsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICBzYW1wbGVzID0gW107XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IGlucHV0Lmxlbmd0aCAtIDE7IGkgKz0gMikge1xuICAgICAgICAgICAgICAgIGNvbnN0IHByZXZQb2ludCA9IGlucHV0W2kgLSAxXTtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXh0UG9pbnQgPSBpbnB1dFtpICsgMV07XG4gICAgICAgICAgICAgICAgY29uc3QgY3VyclBvaW50ID0gaW5wdXRbaV07XG4gICAgICAgICAgICAgICAgY29uc3QgYXZlcmFnZSA9IChwcmV2UG9pbnQgKyBuZXh0UG9pbnQgKyBjdXJyUG9pbnQpIC8gMztcbiAgICAgICAgICAgICAgICBzYW1wbGVzLnB1c2goYXZlcmFnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpbnB1dCA9IHNhbXBsZXM7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYXJyYXlGYXN0UmVzYW1wbGUoc2FtcGxlcywgcG9pbnRzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICAvLyBJbiBwcmFjdGljZSB0aGVyZSdzIG5vdCBtdWNoIHB1cnBvc2UgaW4gYnVybmluZyBDUFUgZm9yIHNob3J0IGFycmF5cyBvbmx5IHRvXG4gICAgICAgIC8vIGVuZCB1cCB3aXRoIGEgcmVzdWx0IHRoYXQgY2FuJ3QgcG9zc2libHkgbG9vayBtdWNoIGRpZmZlcmVudCB0aGFuIHRoZSBmYXN0XG4gICAgICAgIC8vIHJlc2FtcGxlLCBzbyBqdXN0IHNraXAgYWhlYWQgdG8gdGhlIGZhc3QgcmVzYW1wbGUuXG4gICAgICAgIHJldHVybiBhcnJheUZhc3RSZXNhbXBsZShpbnB1dCwgcG9pbnRzKTtcbiAgICB9XG59XG5cbi8qKlxuICogUmVzY2FsZXMgdGhlIGlucHV0IGFycmF5IHRvIGhhdmUgdmFsdWVzIHRoYXQgYXJlIGluY2x1c2l2ZWx5IHdpdGhpbiB0aGUgcHJvdmlkZWRcbiAqIG1pbmltdW0gYW5kIG1heGltdW0uXG4gKiBAcGFyYW0ge251bWJlcltdfSBpbnB1dCBUaGUgYXJyYXkgdG8gcmVzY2FsZS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdNaW4gVGhlIG1pbmltdW0gdmFsdWUgdG8gc2NhbGUgdG8uXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TWF4IFRoZSBtYXhpbXVtIHZhbHVlIHRvIHNjYWxlIHRvLlxuICogQHJldHVybnMge251bWJlcltdfSBUaGUgcmVzY2FsZWQgYXJyYXkuXG4gKi9cbi8vIHRzLXBydW5lLWlnbm9yZS1uZXh0XG5leHBvcnQgZnVuY3Rpb24gYXJyYXlSZXNjYWxlKGlucHV0OiBudW1iZXJbXSwgbmV3TWluOiBudW1iZXIsIG5ld01heDogbnVtYmVyKTogbnVtYmVyW10ge1xuICAgIGNvbnN0IG1pbjogbnVtYmVyID0gTWF0aC5taW4oLi4uaW5wdXQpO1xuICAgIGNvbnN0IG1heDogbnVtYmVyID0gTWF0aC5tYXgoLi4uaW5wdXQpO1xuICAgIHJldHVybiBpbnB1dC5tYXAoKHYpID0+IHBlcmNlbnRhZ2VXaXRoaW4ocGVyY2VudGFnZU9mKHYsIG1pbiwgbWF4KSwgbmV3TWluLCBuZXdNYXgpKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGFuIGFycmF5IG9mIHRoZSBnaXZlbiBsZW5ndGgsIHNlZWRlZCB3aXRoIHRoZSBnaXZlbiB2YWx1ZS5cbiAqIEBwYXJhbSB7VH0gdmFsIFRoZSB2YWx1ZSB0byBzZWVkIHRoZSBhcnJheSB3aXRoLlxuICogQHBhcmFtIHtudW1iZXJ9IGxlbmd0aCBUaGUgbGVuZ3RoIG9mIHRoZSBhcnJheSB0byBjcmVhdGUuXG4gKiBAcmV0dXJucyB7VFtdfSBUaGUgYXJyYXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcnJheVNlZWQ8VD4odmFsOiBULCBsZW5ndGg6IG51bWJlcik6IFRbXSB7XG4gICAgLy8gU2l6ZSB0aGUgYXJyYXkgdXAgZnJvbnQgZm9yIHBlcmZvcm1hbmNlLCBhbmQgdXNlIGBmaWxsYCB0byBsZXQgdGhlIGJyb3dzZXJcbiAgICAvLyBvcHRpbWl6ZSB0aGUgb3BlcmF0aW9uIGJldHRlciB0aGFuIHdlIGNhbiB3aXRoIGEgYGZvcmAgbG9vcCwgaWYgaXQgd2FudHMuXG4gICAgcmV0dXJuIG5ldyBBcnJheTxUPihsZW5ndGgpLmZpbGwodmFsKTtcbn1cblxuLyoqXG4gKiBUcmltcyBvciBmaWxscyB0aGUgYXJyYXkgdG8gZW5zdXJlIGl0IG1lZXRzIHRoZSBkZXNpcmVkIGxlbmd0aC4gVGhlIHNlZWQgYXJyYXlcbiAqIGdpdmVuIGlzIHB1bGxlZCBmcm9tIHRvIGZpbGwgYW55IG1pc3Npbmcgc2xvdHMgLSBpdCBpcyByZWNvbW1lbmRlZCB0aGF0IHRoaXMgYmVcbiAqIGF0IGxlYXN0IGBsZW5gIGxvbmcuIFRoZSByZXN1bHRpbmcgYXJyYXkgd2lsbCBiZSBleGFjdGx5IGBsZW5gIGxvbmcsIGVpdGhlclxuICogdHJpbW1lZCBmcm9tIHRoZSBzb3VyY2Ugb3IgZmlsbGVkIHdpdGggdGhlIHNvbWUvYWxsIG9mIHRoZSBzZWVkIGFycmF5LlxuICogQHBhcmFtIHtUW119IGEgVGhlIGFycmF5IHRvIHRyaW0vZmlsbC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBsZW4gVGhlIGxlbmd0aCB0byB0cmltIG9yIGZpbGwgdG8sIGFzIG5lZWRlZC5cbiAqIEBwYXJhbSB7VFtdfSBzZWVkIFZhbHVlcyB0byBwdWxsIGZyb20gaWYgdGhlIGFycmF5IG5lZWRzIGZpbGxpbmcuXG4gKiBAcmV0dXJucyB7VFtdfSBUaGUgcmVzdWx0aW5nIGFycmF5IG9mIGBsZW5gIGxlbmd0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFycmF5VHJpbUZpbGw8VD4oYTogVFtdLCBsZW46IG51bWJlciwgc2VlZDogVFtdKTogVFtdIHtcbiAgICAvLyBEZXYgbm90ZTogd2UgZG8gbGVuZ3RoIGNoZWNrcyBiZWNhdXNlIHRoZSBzcHJlYWQgb3BlcmF0b3IgY2FuIHJlc3VsdCBpbiBzb21lXG4gICAgLy8gcGVyZm9ybWFuY2UgcGVuYWx0aWVzIGluIG1vcmUgY3JpdGljYWwgY29kZSBwYXRocy4gQXMgYSB1dGlsaXR5LCBpdCBzaG91bGQgYmVcbiAgICAvLyBhcyBmYXN0IGFzIHBvc3NpYmxlIHRvIG5vdCBjYXVzZSBhIHByb2JsZW0gZm9yIHRoZSBjYWxsIHN0YWNrLCBubyBtYXR0ZXIgaG93XG4gICAgLy8gY3JpdGljYWwgdGhhdCBzdGFjayBpcy5cbiAgICBpZiAoYS5sZW5ndGggPT09IGxlbikgcmV0dXJuIGE7XG4gICAgaWYgKGEubGVuZ3RoID4gbGVuKSByZXR1cm4gYS5zbGljZSgwLCBsZW4pO1xuICAgIHJldHVybiBhLmNvbmNhdChzZWVkLnNsaWNlKDAsIGxlbiAtIGEubGVuZ3RoKSk7XG59XG5cbi8qKlxuICogQ2xvbmVzIGFuIGFycmF5IGFzIGZhc3QgYXMgcG9zc2libGUsIHJldGFpbmluZyByZWZlcmVuY2VzIG9mIHRoZSBhcnJheSdzIHZhbHVlcy5cbiAqIEBwYXJhbSBhIFRoZSBhcnJheSB0byBjbG9uZS4gTXVzdCBiZSBkZWZpbmVkLlxuICogQHJldHVybnMgQSBjb3B5IG9mIHRoZSBhcnJheS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFycmF5RmFzdENsb25lPFQ+KGE6IFRbXSk6IFRbXSB7XG4gICAgcmV0dXJuIGEuc2xpY2UoMCwgYS5sZW5ndGgpO1xufVxuXG4vKipcbiAqIERldGVybWluZXMgaWYgdGhlIHR3byBhcnJheXMgYXJlIGRpZmZlcmVudCBlaXRoZXIgaW4gbGVuZ3RoLCBjb250ZW50cyxcbiAqIG9yIG9yZGVyIG9mIHRob3NlIGNvbnRlbnRzLlxuICogQHBhcmFtIGEgVGhlIGZpcnN0IGFycmF5LiBNdXN0IGJlIGRlZmluZWQuXG4gKiBAcGFyYW0gYiBUaGUgc2Vjb25kIGFycmF5LiBNdXN0IGJlIGRlZmluZWQuXG4gKiBAcmV0dXJucyBUcnVlIGlmIHRoZXkgYXJlIGRpZmZlcmVudCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXJyYXlIYXNPcmRlckNoYW5nZShhOiBhbnlbXSwgYjogYW55W10pOiBib29sZWFuIHtcbiAgICBpZiAoYS5sZW5ndGggPT09IGIubGVuZ3RoKSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGFbaV0gIT09IGJbaV0pIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdHJ1ZTsgLy8gbGlrZSBhcnJheUhhc0RpZmYsIGEgZGlmZmVyZW5jZSBpbiBsZW5ndGggaXMgYSBuYXR1cmFsIGNoYW5nZVxuICAgIH1cbn1cblxuLyoqXG4gKiBEZXRlcm1pbmVzIGlmIHR3byBhcnJheXMgYXJlIGRpZmZlcmVudCB0aHJvdWdoIGEgc2hhbGxvdyBjb21wYXJpc29uLlxuICogQHBhcmFtIGEgVGhlIGZpcnN0IGFycmF5LiBNdXN0IGJlIGRlZmluZWQuXG4gKiBAcGFyYW0gYiBUaGUgc2Vjb25kIGFycmF5LiBNdXN0IGJlIGRlZmluZWQuXG4gKiBAcmV0dXJucyBUcnVlIGlmIHRoZXkgYXJlIGRpZmZlcmVudCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXJyYXlIYXNEaWZmKGE6IGFueVtdLCBiOiBhbnlbXSk6IGJvb2xlYW4ge1xuICAgIGlmIChhLmxlbmd0aCA9PT0gYi5sZW5ndGgpIHtcbiAgICAgICAgLy8gV2hlbiB0aGUgbGVuZ3RocyBhcmUgZXF1YWwsIGNoZWNrIHRvIHNlZSBpZiBlaXRoZXIgYXJyYXkgaXMgbWlzc2luZ1xuICAgICAgICAvLyBhbiBlbGVtZW50IGZyb20gdGhlIG90aGVyLlxuICAgICAgICBpZiAoYi5zb21lKChpKSA9PiAhYS5pbmNsdWRlcyhpKSkpIHJldHVybiB0cnVlO1xuICAgICAgICBpZiAoYS5zb21lKChpKSA9PiAhYi5pbmNsdWRlcyhpKSkpIHJldHVybiB0cnVlO1xuXG4gICAgICAgIC8vIGlmIGFsbCB0aGUga2V5cyBhcmUgY29tbW9uLCBzYXkgc29cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0cnVlOyAvLyBkaWZmZXJlbnQgbGVuZ3RocyBtZWFucyB0aGV5IGFyZSBuYXR1cmFsbHkgZGl2ZXJnZWRcbiAgICB9XG59XG5cbmV4cG9ydCB0eXBlIERpZmY8VD4gPSB7IGFkZGVkOiBUW107IHJlbW92ZWQ6IFRbXSB9O1xuXG4vKipcbiAqIFBlcmZvcm1zIGEgZGlmZiBvbiB0d28gYXJyYXlzLiBUaGUgcmVzdWx0IGlzIHdoYXQgaXMgZGlmZmVyZW50IHdpdGggdGhlXG4gKiBmaXJzdCBhcnJheSAoYGFkZGVkYCBpbiB0aGUgcmV0dXJuZWQgb2JqZWN0IG1lYW5zIG9iamVjdHMgaW4gQiB0aGF0IGFyZW4ndFxuICogaW4gQSkuIFNoYWxsb3cgY29tcGFyaXNvbnMgYXJlIHVzZWQgdG8gcGVyZm9ybSB0aGUgZGlmZi5cbiAqIEBwYXJhbSBhIFRoZSBmaXJzdCBhcnJheS4gTXVzdCBiZSBkZWZpbmVkLlxuICogQHBhcmFtIGIgVGhlIHNlY29uZCBhcnJheS4gTXVzdCBiZSBkZWZpbmVkLlxuICogQHJldHVybnMgVGhlIGRpZmYgYmV0d2VlbiB0aGUgYXJyYXlzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXJyYXlEaWZmPFQ+KGE6IFRbXSwgYjogVFtdKTogRGlmZjxUPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgYWRkZWQ6IGIuZmlsdGVyKChpKSA9PiAhYS5pbmNsdWRlcyhpKSksXG4gICAgICAgIHJlbW92ZWQ6IGEuZmlsdGVyKChpKSA9PiAhYi5pbmNsdWRlcyhpKSksXG4gICAgfTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBpbnRlcnNlY3Rpb24gb2YgdHdvIGFycmF5cy5cbiAqIEBwYXJhbSBhIFRoZSBmaXJzdCBhcnJheS4gTXVzdCBiZSBkZWZpbmVkLlxuICogQHBhcmFtIGIgVGhlIHNlY29uZCBhcnJheS4gTXVzdCBiZSBkZWZpbmVkLlxuICogQHJldHVybnMgVGhlIGludGVyc2VjdGlvbiBvZiB0aGUgYXJyYXlzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXJyYXlJbnRlcnNlY3Rpb248VD4oYTogVFtdLCBiOiBUW10pOiBUW10ge1xuICAgIHJldHVybiBhLmZpbHRlcigoaSkgPT4gYi5pbmNsdWRlcyhpKSk7XG59XG5cbi8qKlxuICogVW5pb25zIGFycmF5cywgZGVkdXBpbmcgY29udGVudHMgdXNpbmcgYSBTZXQuXG4gKiBAcGFyYW0gYSBUaGUgYXJyYXlzIHRvIG1lcmdlLlxuICogQHJldHVybnMgVGhlIHVuaW9uIG9mIGFsbCBnaXZlbiBhcnJheXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcnJheVVuaW9uPFQ+KC4uLmE6IFRbXVtdKTogVFtdIHtcbiAgICByZXR1cm4gQXJyYXkuZnJvbShcbiAgICAgICAgYS5yZWR1Y2UoKGMsIHYpID0+IHtcbiAgICAgICAgICAgIHYuZm9yRWFjaCgoaSkgPT4gYy5hZGQoaSkpO1xuICAgICAgICAgICAgcmV0dXJuIGM7XG4gICAgICAgIH0sIG5ldyBTZXQ8VD4oKSksXG4gICAgKTtcbn1cblxuLyoqXG4gKiBNb3ZlcyBhIHNpbmdsZSBlbGVtZW50IGZyb20gZnJvbUluZGV4IHRvIHRvSW5kZXguXG4gKiBAcGFyYW0ge2FycmF5fSBsaXN0IHRoZSBsaXN0IGZyb20gd2hpY2ggdG8gY29uc3RydWN0IHRoZSBuZXcgbGlzdC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBmcm9tSW5kZXggdGhlIGluZGV4IG9mIHRoZSBlbGVtZW50IHRvIG1vdmUuXG4gKiBAcGFyYW0ge251bWJlcn0gdG9JbmRleCB0aGUgaW5kZXggb2Ygd2hlcmUgdG8gcHV0IHRoZSBlbGVtZW50LlxuICogQHJldHVybnMge2FycmF5fSBBIG5ldyBhcnJheSB3aXRoIHRoZSByZXF1ZXN0ZWQgdmFsdWUgbW92ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtb3ZlRWxlbWVudDxUPihsaXN0OiBUW10sIGZyb21JbmRleDogbnVtYmVyLCB0b0luZGV4OiBudW1iZXIpOiBUW10ge1xuICAgIGNvbnN0IHJlc3VsdCA9IEFycmF5LmZyb20obGlzdCk7XG4gICAgY29uc3QgW3JlbW92ZWRdID0gcmVzdWx0LnNwbGljZShmcm9tSW5kZXgsIDEpO1xuICAgIHJlc3VsdC5zcGxpY2UodG9JbmRleCwgMCwgcmVtb3ZlZCk7XG5cbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIEhlbHBlciBmdW5jdGlvbnMgdG8gcGVyZm9ybSBMSU5RLWxpa2UgcXVlcmllcyBvbiBhcnJheXMuXG4gKi9cbmV4cG9ydCBjbGFzcyBBcnJheVV0aWw8VD4ge1xuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhIG5ldyBhcnJheSBoZWxwZXIuXG4gICAgICogQHBhcmFtIGEgVGhlIGFycmF5IHRvIGhlbHAuIENhbiBiZSBtb2RpZmllZCBpbi1wbGFjZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSBhOiBUW10pIHt9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdmFsdWUgb2YgdGhpcyBhcnJheSwgYWZ0ZXIgYWxsIGFwcHJvcHJpYXRlIGFsdGVyYXRpb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgdmFsdWUoKTogVFtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHcm91cHMgYW4gYXJyYXkgYnkga2V5cy5cbiAgICAgKiBAcGFyYW0gZm4gVGhlIGtleS1maW5kaW5nIGZ1bmN0aW9uLlxuICAgICAqIEByZXR1cm5zIFRoaXMuXG4gICAgICovXG4gICAgcHVibGljIGdyb3VwQnk8Sz4oZm46IChhOiBUKSA9PiBLKTogR3JvdXBlZEFycmF5PEssIFQ+IHtcbiAgICAgICAgY29uc3Qgb2JqID0gdGhpcy5hLnJlZHVjZSgocnY6IE1hcDxLLCBUW10+LCB2YWw6IFQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGsgPSBmbih2YWwpO1xuICAgICAgICAgICAgaWYgKCFydi5oYXMoaykpIHJ2LnNldChrLCBbXSk7XG4gICAgICAgICAgICBydi5nZXQoaykhLnB1c2godmFsKTtcbiAgICAgICAgICAgIHJldHVybiBydjtcbiAgICAgICAgfSwgbmV3IE1hcDxLLCBUW10+KCkpO1xuICAgICAgICByZXR1cm4gbmV3IEdyb3VwZWRBcnJheShvYmopO1xuICAgIH1cbn1cblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb25zIHRvIHBlcmZvcm0gTElOUS1saWtlIHF1ZXJpZXMgb24gZ3JvdXBzIChtYXBzKS5cbiAqL1xuZXhwb3J0IGNsYXNzIEdyb3VwZWRBcnJheTxLLCBUPiB7XG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIG5ldyBncm91cCBoZWxwZXIuXG4gICAgICogQHBhcmFtIHZhbCBUaGUgZ3JvdXAgdG8gaGVscC4gQ2FuIGJlIG1vZGlmaWVkIGluLXBsYWNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIHZhbDogTWFwPEssIFRbXT4pIHt9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdmFsdWUgb2YgdGhpcyBncm91cCwgYWZ0ZXIgYWxsIGFwcGxpY2FibGUgYWx0ZXJhdGlvbnMuXG4gICAgICovXG4gICAgcHVibGljIGdldCB2YWx1ZSgpOiBNYXA8SywgVFtdPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPcmRlcnMgdGhlIGdyb3VwaW5nIGludG8gYW4gYXJyYXkgdXNpbmcgdGhlIHByb3ZpZGVkIGtleSBvcmRlci5cbiAgICAgKiBAcGFyYW0ga2V5T3JkZXIgVGhlIGtleSBvcmRlci5cbiAgICAgKiBAcmV0dXJucyBBbiBhcnJheSBoZWxwZXIgb2YgdGhlIHJlc3VsdC5cbiAgICAgKi9cbiAgICBwdWJsaWMgb3JkZXJCeShrZXlPcmRlcjogS1tdKTogQXJyYXlVdGlsPFQ+IHtcbiAgICAgICAgY29uc3QgYTogVFtdID0gW107XG4gICAgICAgIGZvciAoY29uc3QgayBvZiBrZXlPcmRlcikge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnZhbC5oYXMoaykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgYS5wdXNoKC4uLnRoaXMudmFsLmdldChrKSEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgQXJyYXlVdGlsKGEpO1xuICAgIH1cbn1cblxuZXhwb3J0IGNvbnN0IGNvbmNhdCA9ICguLi5hcnJheXM6IFVpbnQ4QXJyYXlbXSk6IFVpbnQ4QXJyYXkgPT4ge1xuICAgIHJldHVybiBhcnJheXMucmVkdWNlKChjb25jYXRlbmF0ZWRTb0ZhcjogVWludDhBcnJheSwgdG9CZUNvbmNhdGVuYXRlZDogVWludDhBcnJheSkgPT4ge1xuICAgICAgICBjb25zdCBjb25jYXRlbmF0ZWQgPSBuZXcgVWludDhBcnJheShjb25jYXRlbmF0ZWRTb0Zhci5sZW5ndGggKyB0b0JlQ29uY2F0ZW5hdGVkLmxlbmd0aCk7XG4gICAgICAgIGNvbmNhdGVuYXRlZC5zZXQoY29uY2F0ZW5hdGVkU29GYXIsIDApO1xuICAgICAgICBjb25jYXRlbmF0ZWQuc2V0KHRvQmVDb25jYXRlbmF0ZWQsIGNvbmNhdGVuYXRlZFNvRmFyLmxlbmd0aCk7XG4gICAgICAgIHJldHVybiBjb25jYXRlbmF0ZWQ7XG4gICAgfSwgbmV3IFVpbnQ4QXJyYXkoMCkpO1xufTtcblxuLyoqXG4gKiBBc3luYyB2ZXJzaW9uIG9mIEFycmF5LmV2ZXJ5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXN5bmNFdmVyeTxUPih2YWx1ZXM6IEl0ZXJhYmxlPFQ+LCBwcmVkaWNhdGU6ICh2YWx1ZTogVCkgPT4gUHJvbWlzZTxib29sZWFuPik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGZvciAoY29uc3QgdmFsdWUgb2YgdmFsdWVzKSB7XG4gICAgICAgIGlmICghKGF3YWl0IHByZWRpY2F0ZSh2YWx1ZSkpKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIEFzeW5jIHZlcnNpb24gb2YgQXJyYXkuc29tZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFzeW5jU29tZTxUPih2YWx1ZXM6IEl0ZXJhYmxlPFQ+LCBwcmVkaWNhdGU6ICh2YWx1ZTogVCkgPT4gUHJvbWlzZTxib29sZWFuPik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGZvciAoY29uc3QgdmFsdWUgb2YgdmFsdWVzKSB7XG4gICAgICAgIGlmIChhd2FpdCBwcmVkaWNhdGUodmFsdWUpKSByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyQm9vbGVhbjxUPih2YWx1ZXM6IEFycmF5PFQgfCBudWxsIHwgdW5kZWZpbmVkPik6IFRbXSB7XG4gICAgcmV0dXJuIHZhbHVlcy5maWx0ZXIoQm9vbGVhbikgYXMgVFtdO1xufVxuIl0sIm1hcHBpbmdz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