UNPKG

matrix-react-sdk

Version:
353 lines (327 loc) 38.9 kB
"use strict"; 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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