@angular/core
Version:
Angular - the core framework
265 lines • 28.3 kB
JavaScript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { assertEqual, assertLessThanOrEqual } from './assert';
/**
* Determines if the contents of two arrays is identical
*
* @param a first array
* @param b second array
* @param identityAccessor Optional function for extracting stable object identity from a value in
* the array.
*/
export function arrayEquals(a, b, identityAccessor) {
if (a.length !== b.length)
return false;
for (let i = 0; i < a.length; i++) {
let valueA = a[i];
let valueB = b[i];
if (identityAccessor) {
valueA = identityAccessor(valueA);
valueB = identityAccessor(valueB);
}
if (valueB !== valueA) {
return false;
}
}
return true;
}
/**
* Flattens an array.
*/
export function flatten(list) {
return list.flat(Number.POSITIVE_INFINITY);
}
export function deepForEach(input, fn) {
input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value));
}
export function addToArray(arr, index, value) {
// perf: array.push is faster than array.splice!
if (index >= arr.length) {
arr.push(value);
}
else {
arr.splice(index, 0, value);
}
}
export function removeFromArray(arr, index) {
// perf: array.pop is faster than array.splice!
if (index >= arr.length - 1) {
return arr.pop();
}
else {
return arr.splice(index, 1)[0];
}
}
export function newArray(size, value) {
const list = [];
for (let i = 0; i < size; i++) {
list.push(value);
}
return list;
}
/**
* Remove item from array (Same as `Array.splice()` but faster.)
*
* `Array.splice()` is not as fast because it has to allocate an array for the elements which were
* removed. This causes memory pressure and slows down code when most of the time we don't
* care about the deleted items array.
*
* https://jsperf.com/fast-array-splice (About 20x faster)
*
* @param array Array to splice
* @param index Index of element in array to remove.
* @param count Number of items to remove.
*/
export function arraySplice(array, index, count) {
const length = array.length - count;
while (index < length) {
array[index] = array[index + count];
index++;
}
while (count--) {
array.pop(); // shrink the array
}
}
/**
* Same as `Array.splice(index, 0, value)` but faster.
*
* `Array.splice()` is not fast because it has to allocate an array for the elements which were
* removed. This causes memory pressure and slows down code when most of the time we don't
* care about the deleted items array.
*
* @param array Array to splice.
* @param index Index in array where the `value` should be added.
* @param value Value to add to array.
*/
export function arrayInsert(array, index, value) {
ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
let end = array.length;
while (end > index) {
const previousEnd = end - 1;
array[end] = array[previousEnd];
end = previousEnd;
}
array[index] = value;
}
/**
* Same as `Array.splice2(index, 0, value1, value2)` but faster.
*
* `Array.splice()` is not fast because it has to allocate an array for the elements which were
* removed. This causes memory pressure and slows down code when most of the time we don't
* care about the deleted items array.
*
* @param array Array to splice.
* @param index Index in array where the `value` should be added.
* @param value1 Value to add to array.
* @param value2 Value to add to array.
*/
export function arrayInsert2(array, index, value1, value2) {
ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
let end = array.length;
if (end == index) {
// inserting at the end.
array.push(value1, value2);
}
else if (end === 1) {
// corner case when we have less items in array than we have items to insert.
array.push(value2, array[0]);
array[0] = value1;
}
else {
end--;
array.push(array[end - 1], array[end]);
while (end > index) {
const previousEnd = end - 2;
array[end] = array[previousEnd];
end--;
}
array[index] = value1;
array[index + 1] = value2;
}
}
/**
* Get an index of an `value` in a sorted `array`.
*
* NOTE:
* - This uses binary search algorithm for fast removals.
*
* @param array A sorted array to binary search.
* @param value The value to look for.
* @returns index of the value.
* - positive index if value found.
* - negative index if value not found. (`~index` to get the value where it should have been
* located)
*/
export function arrayIndexOfSorted(array, value) {
return _arrayIndexOfSorted(array, value, 0);
}
/**
* Set a `value` for a `key`.
*
* @param keyValueArray to modify.
* @param key The key to locate or create.
* @param value The value to set for a `key`.
* @returns index (always even) of where the value vas set.
*/
export function keyValueArraySet(keyValueArray, key, value) {
let index = keyValueArrayIndexOf(keyValueArray, key);
if (index >= 0) {
// if we found it set it.
keyValueArray[index | 1] = value;
}
else {
index = ~index;
arrayInsert2(keyValueArray, index, key, value);
}
return index;
}
/**
* Retrieve a `value` for a `key` (on `undefined` if not found.)
*
* @param keyValueArray to search.
* @param key The key to locate.
* @return The `value` stored at the `key` location or `undefined if not found.
*/
export function keyValueArrayGet(keyValueArray, key) {
const index = keyValueArrayIndexOf(keyValueArray, key);
if (index >= 0) {
// if we found it retrieve it.
return keyValueArray[index | 1];
}
return undefined;
}
/**
* Retrieve a `key` index value in the array or `-1` if not found.
*
* @param keyValueArray to search.
* @param key The key to locate.
* @returns index of where the key is (or should have been.)
* - positive (even) index if key found.
* - negative index if key not found. (`~index` (even) to get the index where it should have
* been inserted.)
*/
export function keyValueArrayIndexOf(keyValueArray, key) {
return _arrayIndexOfSorted(keyValueArray, key, 1);
}
/**
* Delete a `key` (and `value`) from the `KeyValueArray`.
*
* @param keyValueArray to modify.
* @param key The key to locate or delete (if exist).
* @returns index of where the key was (or should have been.)
* - positive (even) index if key found and deleted.
* - negative index if key not found. (`~index` (even) to get the index where it should have
* been.)
*/
export function keyValueArrayDelete(keyValueArray, key) {
const index = keyValueArrayIndexOf(keyValueArray, key);
if (index >= 0) {
// if we found it remove it.
arraySplice(keyValueArray, index, 2);
}
return index;
}
/**
* INTERNAL: Get an index of an `value` in a sorted `array` by grouping search by `shift`.
*
* NOTE:
* - This uses binary search algorithm for fast removals.
*
* @param array A sorted array to binary search.
* @param value The value to look for.
* @param shift grouping shift.
* - `0` means look at every location
* - `1` means only look at every other (even) location (the odd locations are to be ignored as
* they are values.)
* @returns index of the value.
* - positive index if value found.
* - negative index if value not found. (`~index` to get the value where it should have been
* inserted)
*/
function _arrayIndexOfSorted(array, value, shift) {
ngDevMode && assertEqual(Array.isArray(array), true, 'Expecting an array');
let start = 0;
let end = array.length >> shift;
while (end !== start) {
const middle = start + ((end - start) >> 1); // find the middle.
const current = array[middle << shift];
if (value === current) {
return (middle << shift);
}
else if (current > value) {
end = middle;
}
else {
start = middle + 1; // We already searched middle so make it non-inclusive by adding 1
}
}
return ~(end << shift);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXlfdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy91dGlsL2FycmF5X3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBQyxXQUFXLEVBQUUscUJBQXFCLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFFNUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQUksQ0FBTSxFQUFFLENBQU0sRUFBRSxnQkFBd0M7SUFDckYsSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQyxNQUFNO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDeEMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDakMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2xCLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsQixJQUFJLGdCQUFnQixFQUFFO1lBQ3BCLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLENBQVEsQ0FBQztZQUN6QyxNQUFNLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxDQUFRLENBQUM7U0FDMUM7UUFDRCxJQUFJLE1BQU0sS0FBSyxNQUFNLEVBQUU7WUFDckIsT0FBTyxLQUFLLENBQUM7U0FDZDtLQUNGO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsT0FBTyxDQUFDLElBQVc7SUFDakMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0FBQzdDLENBQUM7QUFFRCxNQUFNLFVBQVUsV0FBVyxDQUFJLEtBQWtCLEVBQUUsRUFBc0I7SUFDdkUsS0FBSyxDQUFDLE9B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QUksV0FBVyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsSUFBSSxFQUFFLG9CQUFvQixDQUFDLENBQUM7SUFDM0UsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ2QsSUFBSSxHQUFHLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSxLQUFLLENBQUM7SUFDaEMsT0FBTyxHQUFHLEtBQUssS0FBSyxFQUFFO1FBQ3BCLE1BQU0sTUFBTSxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUUsbUJBQW1CO1FBQ2pFLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLENBQUM7UUFDdkMsSUFBSSxLQUFLLEtBQUssT0FBTyxFQUFFO1lBQ3JCLE9BQU8sQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLENBQUM7U0FDMUI7YUFBTSxJQUFJLE9BQU8sR0FBRyxLQUFLLEVBQUU7WUFDMUIsR0FBRyxHQUFHLE1BQU0sQ0FBQztTQUNkO2FBQU07WUFDTCxLQUFLLEdBQUcsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFFLGtFQUFrRTtTQUN4RjtLQUNGO0lBQ0QsT0FBTyxDQUFDLENBQUMsR0FBRyxJQUFJLEtBQUssQ0FBQyxDQUFDO0FBQ3pCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHthc3NlcnRFcXVhbCwgYXNzZXJ0TGVzc1RoYW5PckVxdWFsfSBmcm9tICcuL2Fzc2VydCc7XG5cbi8qKlxuICogRGV0ZXJtaW5lcyBpZiB0aGUgY29udGVudHMgb2YgdHdvIGFycmF5cyBpcyBpZGVudGljYWxcbiAqXG4gKiBAcGFyYW0gYSBmaXJzdCBhcnJheVxuICogQHBhcmFtIGIgc2Vjb25kIGFycmF5XG4gKiBAcGFyYW0gaWRlbnRpdHlBY2Nlc3NvciBPcHRpb25hbCBmdW5jdGlvbiBmb3IgZXh0cmFjdGluZyBzdGFibGUgb2JqZWN0IGlkZW50aXR5IGZyb20gYSB2YWx1ZSBpblxuICogICAgIHRoZSBhcnJheS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFycmF5RXF1YWxzPFQ+KGE6IFRbXSwgYjogVFtdLCBpZGVudGl0eUFjY2Vzc29yPzogKHZhbHVlOiBUKSA9PiB1bmtub3duKTogYm9vbGVhbiB7XG4gIGlmIChhLmxlbmd0aCAhPT0gYi5sZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7XG4gICAgbGV0IHZhbHVlQSA9IGFbaV07XG4gICAgbGV0IHZhbHVlQiA9IGJbaV07XG4gICAgaWYgKGlkZW50aXR5QWNjZXNzb3IpIHtcbiAgICAgIHZhbHVlQSA9IGlkZW50aXR5QWNjZXNzb3IodmFsdWVBKSBhcyBhbnk7XG4gICAgICB2YWx1ZUIgPSBpZGVudGl0eUFjY2Vzc29yKHZhbHVlQikgYXMgYW55O1xuICAgIH1cbiAgICBpZiAodmFsdWVCICE9PSB2YWx1ZUEpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKlxuICogRmxhdHRlbnMgYW4gYXJyYXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0dGVuKGxpc3Q6IGFueVtdKTogYW55W10ge1xuICByZXR1cm4gbGlzdC5mbGF0KE51bWJlci5QT1NJVElWRV9JTkZJTklUWSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZWVwRm9yRWFjaDxUPihpbnB1dDogKFR8YW55W10pW10sIGZuOiAodmFsdWU6IFQpID0+IHZvaWQpOiB2b2lkIHtcbiAgaW5wdXQuZm9yRWFjaCh2YWx1ZSA9PiBBcnJheS5pc0FycmF5KHZhbHVlKSA/IGRlZXBGb3JFYWNoKHZhbHVlLCBmbikgOiBmbih2YWx1ZSkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYWRkVG9BcnJheShhcnI6IGFueVtdLCBpbmRleDogbnVtYmVyLCB2YWx1ZTogYW55KTogdm9pZCB7XG4gIC8vIHBlcmY6IGFycmF5LnB1c2ggaXMgZmFzdGVyIHRoYW4gYXJyYXkuc3BsaWNlIVxuICBpZiAoaW5kZXggPj0gYXJyLmxlbmd0aCkge1xuICAgIGFyci5wdXNoKHZhbHVlKTtcbiAgfSBlbHNlIHtcbiAgICBhcnIuc3BsaWNlKGluZGV4LCAwLCB2YWx1ZSk7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZUZyb21BcnJheShhcnI6IGFueVtdLCBpbmRleDogbnVtYmVyKTogYW55IHtcbiAgLy8gcGVyZjogYXJyYXkucG9wIGlzIGZhc3RlciB0aGFuIGFycmF5LnNwbGljZSFcbiAgaWYgKGluZGV4ID49IGFyci5sZW5ndGggLSAxKSB7XG4gICAgcmV0dXJuIGFyci5wb3AoKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYXJyLnNwbGljZShpbmRleCwgMSlbMF07XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5ld0FycmF5PFQgPSBhbnk+KHNpemU6IG51bWJlcik6IFRbXTtcbmV4cG9ydCBmdW5jdGlvbiBuZXdBcnJheTxUPihzaXplOiBudW1iZXIsIHZhbHVlOiBUKTogVFtdO1xuZXhwb3J0IGZ1bmN0aW9uIG5ld0FycmF5PFQ+KHNpemU6IG51bWJlciwgdmFsdWU/OiBUKTogVFtdIHtcbiAgY29uc3QgbGlzdDogVFtdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7XG4gICAgbGlzdC5wdXNoKHZhbHVlISk7XG4gIH1cbiAgcmV0dXJuIGxpc3Q7XG59XG5cbi8qKlxuICogUmVtb3ZlIGl0ZW0gZnJvbSBhcnJheSAoU2FtZSBhcyBgQXJyYXkuc3BsaWNlKClgIGJ1dCBmYXN0ZXIuKVxuICpcbiAqIGBBcnJheS5zcGxpY2UoKWAgaXMgbm90IGFzIGZhc3QgYmVjYXVzZSBpdCBoYXMgdG8gYWxsb2NhdGUgYW4gYXJyYXkgZm9yIHRoZSBlbGVtZW50cyB3aGljaCB3ZXJlXG4gKiByZW1vdmVkLiBUaGlzIGNhdXNlcyBtZW1vcnkgcHJlc3N1cmUgYW5kIHNsb3dzIGRvd24gY29kZSB3aGVuIG1vc3Qgb2YgdGhlIHRpbWUgd2UgZG9uJ3RcbiAqIGNhcmUgYWJvdXQgdGhlIGRlbGV0ZWQgaXRlbXMgYXJyYXkuXG4gKlxuICogaHR0cHM6Ly9qc3BlcmYuY29tL2Zhc3QtYXJyYXktc3BsaWNlIChBYm91dCAyMHggZmFzdGVyKVxuICpcbiAqIEBwYXJhbSBhcnJheSBBcnJheSB0byBzcGxpY2VcbiAqIEBwYXJhbSBpbmRleCBJbmRleCBvZiBlbGVtZW50IGluIGFycmF5IHRvIHJlbW92ZS5cbiAqIEBwYXJhbSBjb3VudCBOdW1iZXIgb2YgaXRlbXMgdG8gcmVtb3ZlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXJyYXlTcGxpY2UoYXJyYXk6IGFueVtdLCBpbmRleDogbnVtYmVyLCBjb3VudDogbnVtYmVyKTogdm9pZCB7XG4gIGNvbnN0IGxlbmd0aCA9IGFycmF5Lmxlbmd0aCAtIGNvdW50O1xuICB3aGlsZSAoaW5kZXggPCBsZW5ndGgpIHtcbiAgICBhcnJheVtpbmRleF0gPSBhcnJheVtpbmRleCArIGNvdW50XTtcbiAgICBpbmRleCsrO1xuICB9XG4gIHdoaWxlIChjb3VudC0tKSB7XG4gICAgYXJyYXkucG9wKCk7ICAvLyBzaHJpbmsgdGhlIGFycmF5XG4gIH1cbn1cblxuLyoqXG4gKiBTYW1lIGFzIGBBcnJheS5zcGxpY2UoaW5kZXgsIDAsIHZhbHVlKWAgYnV0IGZhc3Rlci5cbiAqXG4gKiBgQXJyYXkuc3BsaWNlKClgIGlzIG5vdCBmYXN0IGJlY2F1c2UgaXQgaGFzIHRvIGFsbG9jYXRlIGFuIGFycmF5IGZvciB0aGUgZWxlbWVudHMgd2hpY2ggd2VyZVxuICogcmVtb3ZlZC4gVGhpcyBjYXVzZXMgbWVtb3J5IHByZXNzdXJlIGFuZCBzbG93cyBkb3duIGNvZGUgd2hlbiBtb3N0IG9mIHRoZSB0aW1lIHdlIGRvbid0XG4gKiBjYXJlIGFib3V0IHRoZSBkZWxldGVkIGl0ZW1zIGFycmF5LlxuICpcbiAqIEBwYXJhbSBhcnJheSBBcnJheSB0byBzcGxpY2UuXG4gKiBAcGFyYW0gaW5kZXggSW5kZXggaW4gYXJyYXkgd2hlcmUgdGhlIGB2YWx1ZWAgc2hvdWxkIGJlIGFkZGVkLlxuICogQHBhcmFtIHZhbHVlIFZhbHVlIHRvIGFkZCB0byBhcnJheS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFycmF5SW5zZXJ0KGFycmF5OiBhbnlbXSwgaW5kZXg6IG51bWJlciwgdmFsdWU6IGFueSk6IHZvaWQge1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0TGVzc1RoYW5PckVxdWFsKGluZGV4LCBhcnJheS5sZW5ndGgsICdDYW5cXCd0IGluc2VydCBwYXN0IGFycmF5IGVuZC4nKTtcbiAgbGV0IGVuZCA9IGFycmF5Lmxlbmd0aDtcbiAgd2hpbGUgKGVuZCA+IGluZGV4KSB7XG4gICAgY29uc3QgcHJldmlvdXNFbmQgPSBlbmQgLSAxO1xuICAgIGFycmF5W2VuZF0gPSBhcnJheVtwcmV2aW91c0VuZF07XG4gICAgZW5kID0gcHJldmlvdXNFbmQ7XG4gIH1cbiAgYXJyYXlbaW5kZXhdID0gdmFsdWU7XG59XG5cbi8qKlxuICogU2FtZSBhcyBgQXJyYXkuc3BsaWNlMihpbmRleCwgMCwgdmFsdWUxLCB2YWx1ZTIpYCBidXQgZmFzdGVyLlxuICpcbiAqIGBBcnJheS5zcGxpY2UoKWAgaXMgbm90IGZhc3QgYmVjYXVzZSBpdCBoYXMgdG8gYWxsb2NhdGUgYW4gYXJyYXkgZm9yIHRoZSBlbGVtZW50cyB3aGljaCB3ZXJlXG4gKiByZW1vdmVkLiBUaGlzIGNhdXNlcyBtZW1vcnkgcHJlc3N1cmUgYW5kIHNsb3dzIGRvd24gY29kZSB3aGVuIG1vc3Qgb2YgdGhlIHRpbWUgd2UgZG9uJ3RcbiAqIGNhcmUgYWJvdXQgdGhlIGRlbGV0ZWQgaXRlbXMgYXJyYXkuXG4gKlxuICogQHBhcmFtIGFycmF5IEFycmF5IHRvIHNwbGljZS5cbiAqIEBwYXJhbSBpbmRleCBJbmRleCBpbiBhcnJheSB3aGVyZSB0aGUgYHZhbHVlYCBzaG91bGQgYmUgYWRkZWQuXG4gKiBAcGFyYW0gdmFsdWUxIFZhbHVlIHRvIGFkZCB0byBhcnJheS5cbiAqIEBwYXJhbSB2YWx1ZTIgVmFsdWUgdG8gYWRkIHRvIGFycmF5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXJyYXlJbnNlcnQyKGFycmF5OiBhbnlbXSwgaW5kZXg6IG51bWJlciwgdmFsdWUxOiBhbnksIHZhbHVlMjogYW55KTogdm9pZCB7XG4gIG5nRGV2TW9kZSAmJiBhc3NlcnRMZXNzVGhhbk9yRXF1YWwoaW5kZXgsIGFycmF5Lmxlbmd0aCwgJ0NhblxcJ3QgaW5zZXJ0IHBhc3QgYXJyYXkgZW5kLicpO1xuICBsZXQgZW5kID0gYXJyYXkubGVuZ3RoO1xuICBpZiAoZW5kID09IGluZGV4KSB7XG4gICAgLy8gaW5zZXJ0aW5nIGF0IHRoZSBlbmQuXG4gICAgYXJyYXkucHVzaCh2YWx1ZTEsIHZhbHVlMik7XG4gIH0gZWxzZSBpZiAoZW5kID09PSAxKSB7XG4gICAgLy8gY29ybmVyIGNhc2Ugd2hlbiB3ZSBoYXZlIGxlc3MgaXRlbXMgaW4gYXJyYXkgdGhhbiB3ZSBoYXZlIGl0ZW1zIHRvIGluc2VydC5cbiAgICBhcnJheS5wdXNoKHZhbHVlMiwgYXJyYXlbMF0pO1xuICAgIGFycmF5WzBdID0gdmFsdWUxO1xuICB9IGVsc2Uge1xuICAgIGVuZC0tO1xuICAgIGFycmF5LnB1c2goYXJyYXlbZW5kIC0gMV0sIGFycmF5W2VuZF0pO1xuICAgIHdoaWxlIChlbmQgPiBpbmRleCkge1xuICAgICAgY29uc3QgcHJldmlvdXNFbmQgPSBlbmQgLSAyO1xuICAgICAgYXJyYXlbZW5kXSA9IGFycmF5W3ByZXZpb3VzRW5kXTtcbiAgICAgIGVuZC0tO1xuICAgIH1cbiAgICBhcnJheVtpbmRleF0gPSB2YWx1ZTE7XG4gICAgYXJyYXlbaW5kZXggKyAxXSA9IHZhbHVlMjtcbiAgfVxufVxuXG5cbi8qKlxuICogR2V0IGFuIGluZGV4IG9mIGFuIGB2YWx1ZWAgaW4gYSBzb3J0ZWQgYGFycmF5YC5cbiAqXG4gKiBOT1RFOlxuICogLSBUaGlzIHVzZXMgYmluYXJ5IHNlYXJjaCBhbGdvcml0aG0gZm9yIGZhc3QgcmVtb3ZhbHMuXG4gKlxuICogQHBhcmFtIGFycmF5IEEgc29ydGVkIGFycmF5IHRvIGJpbmFyeSBzZWFyY2guXG4gKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIGxvb2sgZm9yLlxuICogQHJldHVybnMgaW5kZXggb2YgdGhlIHZhbHVlLlxuICogICAtIHBvc2l0aXZlIGluZGV4IGlmIHZhbHVlIGZvdW5kLlxuICogICAtIG5lZ2F0aXZlIGluZGV4IGlmIHZhbHVlIG5vdCBmb3VuZC4gKGB+aW5kZXhgIHRvIGdldCB0aGUgdmFsdWUgd2hlcmUgaXQgc2hvdWxkIGhhdmUgYmVlblxuICogICAgIGxvY2F0ZWQpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcnJheUluZGV4T2ZTb3J0ZWQoYXJyYXk6IHN0cmluZ1tdLCB2YWx1ZTogc3RyaW5nKTogbnVtYmVyIHtcbiAgcmV0dXJuIF9hcnJheUluZGV4T2ZTb3J0ZWQoYXJyYXksIHZhbHVlLCAwKTtcbn1cblxuXG4vKipcbiAqIGBLZXlWYWx1ZUFycmF5YCBpcyBhbiBhcnJheSB3aGVyZSBldmVuIHBvc2l0aW9ucyBjb250YWluIGtleXMgYW5kIG9kZCBwb3NpdGlvbnMgY29udGFpbiB2YWx1ZXMuXG4gKlxuICogYEtleVZhbHVlQXJyYXlgIHByb3ZpZGVzIGEgdmVyeSBlZmZpY2llbnQgd2F5IG9mIGl0ZXJhdGluZyBvdmVyIGl0cyBjb250ZW50cy4gRm9yIHNtYWxsXG4gKiBzZXRzICh+MTApIHRoZSBjb3N0IG9mIGJpbmFyeSBzZWFyY2hpbmcgYW4gYEtleVZhbHVlQXJyYXlgIGhhcyBhYm91dCB0aGUgc2FtZSBwZXJmb3JtYW5jZVxuICogY2hhcmFjdGVyaXN0aWNzIHRoYXQgb2YgYSBgTWFwYCB3aXRoIHNpZ25pZmljYW50bHkgYmV0dGVyIG1lbW9yeSBmb290cHJpbnQuXG4gKlxuICogSWYgdXNlZCBhcyBhIGBNYXBgIHRoZSBrZXlzIGFyZSBzdG9yZWQgaW4gYWxwaGFiZXRpY2FsIG9yZGVyIHNvIHRoYXQgdGhleSBjYW4gYmUgYmluYXJ5IHNlYXJjaGVkXG4gKiBmb3IgcmV0cmlldmFsLlxuICpcbiAqIFNlZTogYGtleVZhbHVlQXJyYXlTZXRgLCBga2V5VmFsdWVBcnJheUdldGAsIGBrZXlWYWx1ZUFycmF5SW5kZXhPZmAsIGBrZXlWYWx1ZUFycmF5RGVsZXRlYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBLZXlWYWx1ZUFycmF5PFZBTFVFPiBleHRlbmRzIEFycmF5PFZBTFVFfHN0cmluZz4ge1xuICBfX2JyYW5kX186ICdhcnJheS1tYXAnO1xufVxuXG4vKipcbiAqIFNldCBhIGB2YWx1ZWAgZm9yIGEgYGtleWAuXG4gKlxuICogQHBhcmFtIGtleVZhbHVlQXJyYXkgdG8gbW9kaWZ5LlxuICogQHBhcmFtIGtleSBUaGUga2V5IHRvIGxvY2F0ZSBvciBjcmVhdGUuXG4gKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIHNldCBmb3IgYSBga2V5YC5cbiAqIEByZXR1cm5zIGluZGV4IChhbHdheXMgZXZlbikgb2Ygd2hlcmUgdGhlIHZhbHVlIHZhcyBzZXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBrZXlWYWx1ZUFycmF5U2V0PFY+KFxuICAgIGtleVZhbHVlQXJyYXk6IEtleVZhbHVlQXJyYXk8Vj4sIGtleTogc3RyaW5nLCB2YWx1ZTogVik6IG51bWJlciB7XG4gIGxldCBpbmRleCA9IGtleVZhbHVlQXJyYXlJbmRleE9mKGtleVZhbHVlQXJyYXksIGtleSk7XG4gIGlmIChpbmRleCA+PSAwKSB7XG4gICAgLy8gaWYgd2UgZm91bmQgaXQgc2V0IGl0LlxuICAgIGtleVZhbHVlQXJyYXlbaW5kZXggfCAxXSA9IHZhbHVlO1xuICB9IGVsc2Uge1xuICAgIGluZGV4ID0gfmluZGV4O1xuICAgIGFycmF5SW5zZXJ0MihrZXlWYWx1ZUFycmF5LCBpbmRleCwga2V5LCB2YWx1ZSk7XG4gIH1cbiAgcmV0dXJuIGluZGV4O1xufVxuXG4vKipcbiAqIFJldHJpZXZlIGEgYHZhbHVlYCBmb3IgYSBga2V5YCAob24gYHVuZGVmaW5lZGAgaWYgbm90IGZvdW5kLilcbiAqXG4gKiBAcGFyYW0ga2V5VmFsdWVBcnJheSB0byBzZWFyY2guXG4gKiBAcGFyYW0ga2V5IFRoZSBrZXkgdG8gbG9jYXRlLlxuICogQHJldHVybiBUaGUgYHZhbHVlYCBzdG9yZWQgYXQgdGhlIGBrZXlgIGxvY2F0aW9uIG9yIGB1bmRlZmluZWQgaWYgbm90IGZvdW5kLlxuICovXG5leHBvcnQgZnVuY3Rpb24ga2V5VmFsdWVBcnJheUdldDxWPihrZXlWYWx1ZUFycmF5OiBLZXlWYWx1ZUFycmF5PFY+LCBrZXk6IHN0cmluZyk6IFZ8dW5kZWZpbmVkIHtcbiAgY29uc3QgaW5kZXggPSBrZXlWYWx1ZUFycmF5SW5kZXhPZihrZXlWYWx1ZUFycmF5LCBrZXkpO1xuICBpZiAoaW5kZXggPj0gMCkge1xuICAgIC8vIGlmIHdlIGZvdW5kIGl0IHJldHJpZXZlIGl0LlxuICAgIHJldHVybiBrZXlWYWx1ZUFycmF5W2luZGV4IHwgMV0gYXMgVjtcbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJldHJpZXZlIGEgYGtleWAgaW5kZXggdmFsdWUgaW4gdGhlIGFycmF5IG9yIGAtMWAgaWYgbm90IGZvdW5kLlxuICpcbiAqIEBwYXJhbSBrZXlWYWx1ZUFycmF5IHRvIHNlYXJjaC5cbiAqIEBwYXJhbSBrZXkgVGhlIGtleSB0byBsb2NhdGUuXG4gKiBAcmV0dXJucyBpbmRleCBvZiB3aGVyZSB0aGUga2V5IGlzIChvciBzaG91bGQgaGF2ZSBiZWVuLilcbiAqICAgLSBwb3NpdGl2ZSAoZXZlbikgaW5kZXggaWYga2V5IGZvdW5kLlxuICogICAtIG5lZ2F0aXZlIGluZGV4IGlmIGtleSBub3QgZm91bmQuIChgfmluZGV4YCAoZXZlbikgdG8gZ2V0IHRoZSBpbmRleCB3aGVyZSBpdCBzaG91bGQgaGF2ZVxuICogICAgIGJlZW4gaW5zZXJ0ZWQuKVxuICovXG5leHBvcnQgZnVuY3Rpb24ga2V5VmFsdWVBcnJheUluZGV4T2Y8Vj4oa2V5VmFsdWVBcnJheTogS2V5VmFsdWVBcnJheTxWPiwga2V5OiBzdHJpbmcpOiBudW1iZXIge1xuICByZXR1cm4gX2FycmF5SW5kZXhPZlNvcnRlZChrZXlWYWx1ZUFycmF5IGFzIHN0cmluZ1tdLCBrZXksIDEpO1xufVxuXG4vKipcbiAqIERlbGV0ZSBhIGBrZXlgIChhbmQgYHZhbHVlYCkgZnJvbSB0aGUgYEtleVZhbHVlQXJyYXlgLlxuICpcbiAqIEBwYXJhbSBrZXlWYWx1ZUFycmF5IHRvIG1vZGlmeS5cbiAqIEBwYXJhbSBrZXkgVGhlIGtleSB0byBsb2NhdGUgb3IgZGVsZXRlIChpZiBleGlzdCkuXG4gKiBAcmV0dXJucyBpbmRleCBvZiB3aGVyZSB0aGUga2V5IHdhcyAob3Igc2hvdWxkIGhhdmUgYmVlbi4pXG4gKiAgIC0gcG9zaXRpdmUgKGV2ZW4pIGluZGV4IGlmIGtleSBmb3VuZCBhbmQgZGVsZXRlZC5cbiAqICAgLSBuZWdhdGl2ZSBpbmRleCBpZiBrZXkgbm90IGZvdW5kLiAoYH5pbmRleGAgKGV2ZW4pIHRvIGdldCB0aGUgaW5kZXggd2hlcmUgaXQgc2hvdWxkIGhhdmVcbiAqICAgICBiZWVuLilcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtleVZhbHVlQXJyYXlEZWxldGU8Vj4oa2V5VmFsdWVBcnJheTogS2V5VmFsdWVBcnJheTxWPiwga2V5OiBzdHJpbmcpOiBudW1iZXIge1xuICBjb25zdCBpbmRleCA9IGtleVZhbHVlQXJyYXlJbmRleE9mKGtleVZhbHVlQXJyYXksIGtleSk7XG4gIGlmIChpbmRleCA+PSAwKSB7XG4gICAgLy8gaWYgd2UgZm91bmQgaXQgcmVtb3ZlIGl0LlxuICAgIGFycmF5U3BsaWNlKGtleVZhbHVlQXJyYXksIGluZGV4LCAyKTtcbiAgfVxuICByZXR1cm4gaW5kZXg7XG59XG5cblxuLyoqXG4gKiBJTlRFUk5BTDogR2V0IGFuIGluZGV4IG9mIGFuIGB2YWx1ZWAgaW4gYSBzb3J0ZWQgYGFycmF5YCBieSBncm91cGluZyBzZWFyY2ggYnkgYHNoaWZ0YC5cbiAqXG4gKiBOT1RFOlxuICogLSBUaGlzIHVzZXMgYmluYXJ5IHNlYXJjaCBhbGdvcml0aG0gZm9yIGZhc3QgcmVtb3ZhbHMuXG4gKlxuICogQHBhcmFtIGFycmF5IEEgc29ydGVkIGFycmF5IHRvIGJpbmFyeSBzZWFyY2guXG4gKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIGxvb2sgZm9yLlxuICogQHBhcmFtIHNoaWZ0IGdyb3VwaW5nIHNoaWZ0LlxuICogICAtIGAwYCBtZWFucyBsb29rIGF0IGV2ZXJ5IGxvY2F0aW9uXG4gKiAgIC0gYDFgIG1lYW5zIG9ubHkgbG9vayBhdCBldmVyeSBvdGhlciAoZXZlbikgbG9jYXRpb24gKHRoZSBvZGQgbG9jYXRpb25zIGFyZSB0byBiZSBpZ25vcmVkIGFzXG4gKiAgICAgICAgIHRoZXkgYXJlIHZhbHVlcy4pXG4gKiBAcmV0dXJucyBpbmRleCBvZiB0aGUgdmFsdWUuXG4gKiAgIC0gcG9zaXRpdmUgaW5kZXggaWYgdmFsdWUgZm91bmQuXG4gKiAgIC0gbmVnYXRpdmUgaW5kZXggaWYgdmFsdWUgbm90IGZvdW5kLiAoYH5pbmRleGAgdG8gZ2V0IHRoZSB2YWx1ZSB3aGVyZSBpdCBzaG91bGQgaGF2ZSBiZWVuXG4gKiBpbnNlcnRlZClcbiAqL1xuZnVuY3Rpb24gX2FycmF5SW5kZXhPZlNvcnRlZChhcnJheTogc3RyaW5nW10sIHZhbHVlOiBzdHJpbmcsIHNoaWZ0OiBudW1iZXIpOiBudW1iZXIge1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0RXF1YWwoQXJyYXkuaXNBcnJheShhcnJheSksIHRydWUsICdFeHBlY3RpbmcgYW4gYXJyYXknKTtcbiAgbGV0IHN0YXJ0ID0gMDtcbiAgbGV0IGVuZCA9IGFycmF5Lmxlbmd0aCA+PiBzaGlmdDtcbiAgd2hpbGUgKGVuZCAhPT0gc3RhcnQpIHtcbiAgICBjb25zdCBtaWRkbGUgPSBzdGFydCArICgoZW5kIC0gc3RhcnQpID4+IDEpOyAgLy8gZmluZCB0aGUgbWlkZGxlLlxuICAgIGNvbnN0IGN1cnJlbnQgPSBhcnJheVttaWRkbGUgPDwgc2hpZnRdO1xuICAgIGlmICh2YWx1ZSA9PT0gY3VycmVudCkge1xuICAgICAgcmV0dXJuIChtaWRkbGUgPDwgc2hpZnQpO1xuICAgIH0gZWxzZSBpZiAoY3VycmVudCA+IHZhbHVlKSB7XG4gICAgICBlbmQgPSBtaWRkbGU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN0YXJ0ID0gbWlkZGxlICsgMTsgIC8vIFdlIGFscmVhZHkgc2VhcmNoZWQgbWlkZGxlIHNvIG1ha2UgaXQgbm9uLWluY2x1c2l2ZSBieSBhZGRpbmcgMVxuICAgIH1cbiAgfVxuICByZXR1cm4gfihlbmQgPDwgc2hpZnQpO1xufVxuIl19