extra-lists
Version:
A collection of functions for operating upon Lists.<br>
1,073 lines • 95.1 kB
JavaScript
import { IDENTITY, COMPARE } from "@nodef/extra-function";
import * as xiterable from "@nodef/extra-iterable";
import * as xarray from "@nodef/extra-array";
import * as xentries from "@nodef/extra-entries";
import * as xmap from "@nodef/extra-map";
// METHODS
// =======
// ABOUT
// -----
/**
* Check if value is lists.
* @param v value
* @returns v is lists?
*/ export function is(v) {
return Array.isArray(v) && v.length === 2 && Array.isArray(v[0]) && Array.isArray(v[1]);
}
/**
* Get all keys.
* @param x lists
* @returns [k₀, k₁, ...] | kᵢ ∈ x[0]
*/ export function keys(x) {
return x[0];
}
/**
* Get all values.
* @param x lists
* @returns [v₀, v₁, ...] | vᵢ ∈ x[1]
*/ export function values(x) {
return x[1];
}
/**
* Obtain all key-value pairs.
* @param x lists
* @returns [[k₀, v₀], [k₁, v₁], ...] | kᵢ ∈ x[0]; vᵢ ∈ x[1]
*/ export function entries(x) {
const a = [];
const xk = x[0], xv = x[1];
const X = xk.length;
for(let i = 0; i < X; ++i)a.push([
xk[i],
xv[i]
]);
return a;
}
// GENERATE
// --------
/**
* Convert map to lists.
* @param x map
* @returns x as lists
*/ export function fromMap(x) {
return [
Array.from(x.keys()),
Array.from(x.values())
];
}
/**
* Convert entries to lists.
* @param x entries
* @returns x as lists
*/ export function fromEntries(x) {
const ak = [];
const av = [];
for (const [k, v] of x){
ak.push(k);
av.push(v);
}
return [
ak,
av
];
}
// CLONE
// -----
/**
* Shallow clone lists.
* @param x lists
* @returns shallow clone of x
*/ export function shallowClone(x) {
return [
x[0].slice(),
x[1].slice()
];
}
export { shallowClone as shallowCopy };
export { shallowClone as clone };
export { shallowClone as copy };
/**
* Deep clone lists.
* @param x lists
* @returns deep clone of x
*/ export function deepClone(x) {
return structuredClone(x);
}
export { deepClone as structuredClone };
export { deepClone as deepCopy };
// SIZE
// ----
/**
* Find the size of lists.
* @param x lists
* @returns |x|
*/ export function size(x) {
return x[0].length;
}
export { size as length };
/**
* Check if lists is empty.
* @param x lists
* @returns |x| = 0?
*/ export function isEmpty(x) {
return x[0].length === 0;
}
// COMPARE
// -------
/**
* Compare two lists.
* @param x lists
* @param y another lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns x=y: 0, otherwise: -ve/+ve
*/ export function compare(x, y, fc = null, fm = null) {
return xmap.compare(xmap.fromLists(x), xmap.fromLists(y), fc, fm);
}
/**
* Check if two lists are equal.
* @param x lists
* @param y another lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns x=y?
*/ export function isEqual(x, y, fc = null, fm = null) {
return compare(x, y, fc, fm) === 0;
}
// GET/SET
// -------
/**
* Get key at index.
* @param x lists
* @param i index
* @returns k₀ | kᵢ = x[0][i]
*/ export function keyAt(x, i) {
return x[0][i];
}
/**
* Get value at index.
* @param x lists
* @param i index
* @returns v₀ | vᵢ = x[1][i]
*/ export function valueAt(x, i) {
return x[1][i];
}
/**
* Get entry at index.
* @param x lists
* @param i index
* @returns [k₀, v₀] | kᵢ = x[0][i]; vᵢ = x[1][i]
*/ export function entryAt(x, i) {
return [
x[0][i],
x[1][i]
];
}
/**
* Obtain value at key.
* @param x lists
* @param k key
* @returns x[k]
*/ export function get(x, k) {
const i = x[0].indexOf(k);
return i >= 0 ? x[1][i] : undefined;
}
/**
* Obtain values at keys.
* @param x lists
* @param ks keys
* @returns [x[k₀], x[k₁], ...] | [k₀, k₁, ...] = ks
*/ export function getAll(x, ks) {
const a = [];
for (const k of ks)a.push(get(x, k));
return a;
}
/**
* Obtain value at path in nested lists.
* @param x nested lists
* @param p path
* @returns x[k₀][k₁][...] | [k₀, k₁, ...] = p
*/ export function getPath(x, p) {
let xany = x;
for (const k of p)xany = is(xany) ? get(xany, k) : undefined;
return xany;
}
/**
* Check if nested lists has a path.
* @param x nested lists
* @param p search path
* @returns x[k₀][k₁][...] exists? | [k₀, k₁, ...] = p
*/ export function hasPath(x, p) {
return getPath(x, p) !== undefined;
}
/**
* Set value at key.
* @param x lists (updated!)
* @param k key
* @param v value
* @returns x | x[k] = v
*/ export function set$(x, k, v) {
const i = x[0].indexOf(k);
if (i >= 0) x[1][i] = v;
else {
x[0].push(k);
x[1].push(v);
}
return x;
}
/**
* Set value at key.
* @param x lists
* @param k key
* @param v value
* @returns x' | x' = x; x'[k] = v
*/ export function set(x, k, v) {
return set$(shallowClone(x), k, v);
}
/**
* Exchange two values.
* @param x lists (updated!)
* @param k a key
* @param l another key
* @returns x | x[k] ⇔ x[l]
*/ export function swap$(x, k, l) {
const i = x[0].indexOf(k);
const j = x[0].indexOf(l);
if (i >= 0 && j >= 0) {
const t = x[1][i];
x[1][i] = x[1][j];
x[1][j] = t;
}
return x;
}
/**
* Exchange two values.
* @param x lists
* @param k a key
* @param l another key
* @returns x' | x' = x; x'[k] = x[l]; x'[l] = x[k]
*/ export function swap(x, k, l) {
return swap$(shallowClone(x), k, l);
}
/**
* Remove value at key.
* @param x lists (updated!)
* @param k key
* @returns x | x = x \\ \{[k, *]\}
*/ export function remove$(x, k) {
const i = x[0].indexOf(k);
if (i >= 0) {
x[0].splice(i, 1);
x[1].splice(i, 1);
}
return x;
}
/**
* Remove value at key.
* @param x lists
* @param k key
* @returns x \\ \{[k, *]\}
*/ export function remove(x, k) {
return remove$(shallowClone(x), k);
}
// PART
// ----
/**
* Get first entry from lists.
* @param x lists
* @param ed default entry
* @returns [k₀, v₀] if x ≠ Φ else ed | [k₀, v₀] ∈ x
*/ export function head(x, ed = []) {
return x[0].length > 0 ? [
x[0][0],
x[1][0]
] : ed;
}
/**
* Obtain lists without its first entry.
* @param x lists
* @returns x \\ \{[k₀, v₀]\} if x ≠ Φ else x | [k₀, v₀] ∈ x
*/ export function tail(x) {
return slice(x, 1);
}
/**
* Obtain all but the last entry from lists.
* @param x lists
* @returns x \\ \{[kᵢ, vᵢ]\} if x ≠ Φ else x | [kᵢ, vᵢ] ∈ x; i = |x| - 1
*/ export function init(x) {
return slice(x, 0, -1);
}
/**
* Get last entry from lists.
* @param x lists
* @param ed default entry
* @returns [kᵢ, vᵢ] if x ≠ Φ else ed | [kᵢ, vᵢ] ∈ x; i = |x| - 1
*/ export function last(x, ed = []) {
const i = x[0].length - 1;
return i >= 0 ? [
x[0][i],
x[1][i]
] : ed;
}
/**
* Obtain a portion of lists (shallow).
* @param x lists (updated!)
* @param i start index [0]
* @param I end index (exclusive) [|x|]
* @returns x | x = \{[kᵢ, vᵢ], [kᵢ₊₁, vᵢ₊₁], ...\} | [kⱼ, vⱼ] ∈ x and i ≤ j < I
*/ export function slice$(x, i = 0, I = x[0].length) {
const X = x[0].length;
i = i < 0 ? Math.max(X + i, 0) : i;
I = I < 0 ? Math.max(X + I, 0) : I;
x[0].length = I;
x[1].length = I;
x[0].splice(0, i);
x[0].splice(0, i);
return x;
}
/**
* Obtain a portion of lists (shallow).
* @param x lists
* @param i start index [0]
* @param I end index (exclusive) [|x|]
* @returns \{[kᵢ, vᵢ], [kᵢ₊₁, vᵢ₊₁], ...\} | [kⱼ, vⱼ] ∈ x and i ≤ j < I
*/ export function slice(x, i = 0, I = x[0].length) {
return [
x[0].slice(i, I),
x[1].slice(i, I)
];
}
/**
* Change contents of lists by removing existing entries and/or adding new ones.
* @param x lists (updated!)
* @param i start index [0]
* @param n number of entries to remove [|x|-i]
* @param es entries to add [Φ]
* @returns x | x = \{[k₀, v₀], ..., [kᵢ₋₁, vᵢ₋₁], [kᵢ₊ₙ, vᵢ₊ₙ], ...\} | [kⱼ, vⱼ] ∈ x and j ∈ [0, i) ∪ [i+n, |x|)
*/ export function splice$(x, i = 0, n = x[0].length, ...es) {
const X = x[0].length;
i = i < 0 ? Math.max(X + i, 0) : i;
n = Math.max(n, 0);
const ks = [], vs = [];
for (const [k, v] of es){
ks.push(k);
vs.push(v);
}
x[0].splice(i, n, ...ks);
x[1].splice(i, n, ...vs);
return x;
}
/**
* Change contents of lists by removing existing entries and/or adding new ones.
* @param x lists
* @param i start index [0]
* @param n number of entries to remove [|x|-i]
* @param es entries to add [Φ]
* @returns \{[k₀, v₀], ..., [kᵢ₋₁, vᵢ₋₁], [kᵢ₊ₙ, vᵢ₊ₙ], ...\} | [kⱼ, vⱼ] ∈ x and j ∈ [0, i) ∪ [i+n, |x|)
*/ export function splice(x, i = 0, n = x[0].length, ...es) {
const ks = [], vs = [];
for (const [k, v] of es){
ks.push(k);
vs.push(v);
}
const xk = x[0].slice(0, i).concat(ks, x[0].slice(i + n));
const xv = x[1].slice(0, i).concat(vs, x[1].slice(i + n));
return [
xk,
xv
];
}
/**
* Keep first n entries only.
* @param x lists (updated!)
* @param n number of entries [1]
* @returns x | x = \{[k₀, v₀], [k₁, v₁], ...\} | [kᵢ, vᵢ] ∈ x and |\{[k₀, v₀], [k₁, v₁], ...\}| ≤ n
*/ export function take$(x, n = 1) {
return slice$(x, 0, n);
}
/**
* Keep first n entries only.
* @param x lists
* @param n number of entries [1]
* @returns \{[k₀, v₀], [k₁, v₁], ...\} | [kᵢ, vᵢ] ∈ x and |\{[k₀, v₀], [k₁, v₁], ...\}| ≤ n
*/ export function take(x, n = 1) {
return slice(x, 0, n);
}
/**
* Remove first n entries.
* @param x lists (updated!)
* @param n number of entries [1]
* @returns x | x = \{[kₙ, vₙ], [kₙ₊₁, vₙ₊₁], ...\} | [kᵢ, vᵢ] ∈ x and |\{[kₙ, vₙ], [kₙ₊₁, vₙ₊₁], ...\}| ≤ max(|x| - n, 0)
*/ export function drop$(x, n = 1) {
return slice$(x, n);
}
/**
* Remove first n entries.
* @param x a map
* @param n number of entries [1]
* @returns \{[kₙ, vₙ], [kₙ₊₁, vₙ₊₁], ...\} | [kᵢ, vᵢ] ∈ x and |\{[kₙ, vₙ], [kₙ₊₁, vₙ₊₁], ...\}| ≤ max(|x| - n, 0)
*/ export function drop(x, n = 1) {
return slice(x, n);
}
// PROPERTY
// --------
/**
* Count values which satisfy a test.
* @param x lists
* @param ft test function (v, k, x)
* @returns Σtᵢ | tᵢ = 1 if ft(vᵢ) else 0; [kᵢ, vᵢ] ∈ x
*/ export function count(x, ft) {
let a = 0;
const xk = x[0], xv = x[1];
const X = xk.length;
for(let i = 0; i < X; ++i)if (ft(xv[i], xk[i], x)) ++a;
return a;
}
/**
* Count occurrences of values.
* @param x lists
* @param fm map function (v, k, x)
* @returns Map \{value ⇒ count\}
*/ export function countAs(x, fm = null) {
fm = fm || IDENTITY;
const xk = x[0], xv = x[1];
const a = new Map();
const X = xk.length;
for(let i = 0; i < X; ++i){
const w = fm(xv[i], xk[i], x);
a.set(w, (a.get(w) || 0) + 1);
}
return a;
}
/**
* Find smallest value.
* @param x lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns v | v ≤ vᵢ; [kᵢ, vᵢ] ∈ x
*/ export function min(x, fc = null, fm = null) {
return rangeEntries(x, fc, fm)[0][1];
}
/**
* Find smallest entry.
* @param x lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns [min_key, min_value]
*/ export function minEntry(x, fc = null, fm = null) {
return rangeEntries(x, fc, fm)[0];
}
/**
* Find largest value.
* @param x lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns v | v ≥ vᵢ; [kᵢ, vᵢ] ∈ x
*/ export function max(x, fc = null, fm = null) {
return rangeEntries(x, fc, fm)[1][1];
}
/**
* Find largest entry.
* @param x lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns [max_key, max_value]
*/ export function maxEntry(x, fc = null, fm = null) {
return rangeEntries(x, fc, fm)[1];
}
/**
* Find smallest and largest values.
* @param x lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns [min_value, max_value]
*/ export function range(x, fc = null, fm = null) {
const [a, b] = rangeEntries(x, fc, fm);
return [
a[1],
b[1]
];
}
/**
* Find smallest and largest entries.
* @param x lists
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns [min_entry, max_entry]
*/ export function rangeEntries(x, fc = null, fm = null) {
fc = fc || COMPARE;
fm = fm || IDENTITY;
const xk = x[0], xv = x[1];
let mk = xk[0], mv = xv[0], mw = fm(mv, mk, x);
let nk = xk[0], nv = xv[0], nw = mw;
const X = x[0].length;
for(let i = 1; i < X; ++i){
const w = fm(xv[i], xk[i], x);
if (fc(w, mw) < 0) {
mk = xk[i];
mv = xv[i];
mw = w;
}
if (fc(w, nw) > 0) {
nk = xk[i];
nv = xv[i];
nw = w;
}
}
return [
[
mk,
mv
],
[
nk,
nv
]
];
}
// ARRANGEMENTS
// ------------
/**
* List all possible subsets.
* @param x lists
* @param n number of entries in each subset [-1 ⇒ any]
* @returns entries selected by bit from 0..2^|x| if n<0; only of length n otherwise
*/ export function* subsets(x, n = -1) {
for (const a of xmap.subsets(xmap.fromLists(x), n))yield [
[
...a.keys()
],
[
...a.values()
]
];
}
/**
* Pick an arbitrary key.
* @param x lists
* @param fr random number generator ([0, 1))
* @returns kᵢ | kᵢ ∈ x[0]
*/ export function randomKey(x, fr = Math.random) {
return xarray.randomValue([
...keys(x)
], fr);
}
export { randomKey as key };
/**
* Pick an arbitrary value.
* @param x lists
* @param fr random number generator ([0, 1))
* @returns vᵢ | vᵢ ∈ x[1]
*/ export function randomValue(x, fr = Math.random) {
return xarray.randomValue([
...values(x)
], fr);
}
export { randomValue as value };
/**
* Pick an arbitrary entry.
* @param x lists
* @param fr random number generator ([0, 1))
* @returns [kᵢ, vᵢ] | kᵢ ∈ x[0]; vᵢ ∈ x[1]
*/ export function randomEntry(x, fr = Math.random) {
return xarray.randomValue([
...entries(x)
], fr);
}
export { randomEntry as entry };
/**
* Pick an arbitrary subset.
* @param x lists
* @param n number of entries [-1 ⇒ any]
* @param fr random number generator ([0, 1))
* @returns [[kᵢ, kⱼ, ...], [vᵢ, vⱼ, ...]] | kᵢ, kⱼ, ... ∈ x[0]; vᵢ, vⱼ, ... ∈ x[1]; |[kᵢ, kⱼ, , ...]| = |x| if n<0 else n
*/ export function randomSubset(x, n = -1, fr = Math.random) {
const a = xmap.randomSubset(xmap.fromLists(x), n, fr);
return [
[
...a.keys()
],
[
...a.values()
]
];
}
export { randomSubset as subset };
// FIND
// ----
/**
* Check if lists has a key.
* @param x lists
* @param k search key
* @returns k ∈ keys(x)?
*/ export function hasKey(x, k) {
return x[0].includes(k);
}
export { hasKey as has };
/**
* Check if lists has a value.
* @param x lists
* @param v search value
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns v ∈ values(x)?
*/ export function hasValue(x, v, fc = null, fm = null) {
if (!fc && !fm) return x[1].includes(v);
return searchValue(x, v, fc, fm) !== undefined;
}
/**
* Check if lists has an entry.
* @param x lists
* @param e search entry
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns k ∈ x[0]; v ∈ x[1]; k ⇒ v? | [k, v] = e
*/ export function hasEntry(x, e, fc = null, fm = null) {
fc = fc || COMPARE;
fm = fm || IDENTITY;
const [k, v] = e, u = get(x, k);
const u1 = fm(u, k, x);
const v1 = fm(v, k, x);
return fc(u1, v1) === 0;
}
/**
* Check if lists has a subset.
* @param x lists
* @param y search subset
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns y ⊆ x?
*/ export function hasSubset(x, y, fc = null, fm = null) {
return xmap.hasSubset(xmap.fromLists(x), xmap.fromLists(y), fc, fm);
}
/**
* Find first value passing a test (default order).
* @param x lists
* @param ft test function (v, k, x)
* @returns first v | ft(v) = true; [k, v] ∈ x
*/ export function find(x, ft) {
return xentries.find(entries(x), ft);
}
/**
* Find values passing a test.
* @param x lists
* @param ft test function (v, k, x)
* @returns v₀, v₁, ... | ft(vᵢ) = true; [kᵢ, vᵢ] ∈ x
*/ export function findAll(x, ft) {
return xentries.findAll(entries(x), ft);
}
/**
* Finds key of an entry passing a test.
* @param x lists
* @param ft test function (v, k, x)
* @returns key of entry
*/ export function search(x, ft) {
return xentries.search(entries(x), ft);
}
/**
* Find keys of entries passing a test.
* @param x lists
* @param ft test function (v, k, x)
* @returns keys of entries
*/ export function searchAll(x, ft) {
return xentries.searchAll(entries(x), ft);
}
/**
* Find a key with given value.
* @param x lists
* @param v search value
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns key of value
*/ export function searchValue(x, v, fc = null, fm = null) {
return xentries.searchValue(entries(x), v, fc, fm);
}
/**
* Find keys with given value.
* @param x lists
* @param v search value
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns keys of value
*/ export function searchValueAll(x, v, fc = null, fm = null) {
return xentries.searchValueAll(entries(x), v, fc, fm);
}
// FUNCTIONAL
// ----------
/**
* Call a function for each value.
* @param x lists
* @param fp process function (v, k, x)
*/ export function forEach(x, fc) {
xentries.forEach(entries(x), fc);
}
/**
* Check if any value satisfies a test.
* @param x lists
* @param ft test function (v, k, x)
* @returns true if ft(vᵢ) = true for some [kᵢ, vᵢ] ∈ x
*/ export function some(x, ft = null) {
return xentries.some(entries(x), ft);
}
/**
* Check if all values satisfy a test.
* @param x entries
* @param ft test function (v, k, x)
* @returns true if ft(vᵢ) = true for every [kᵢ, vᵢ] ∈ x
*/ export function every(x, ft) {
return xentries.every(entries(x), ft);
}
/**
* Transform values of entries.
* @param x lists
* @param fm map function (v, k, x)
* @returns [k₀, fm(v₀)], [k₁, fm(v₁)], ... | [kᵢ, vᵢ] ∈ x
*/ export function map(x, fm) {
const ks = [], vs = [];
for (const [k, v] of entries(x)){
ks.push(k);
vs.push(fm(v, k, x));
}
return [
ks,
vs
];
}
/**
* Reduce values of entries to a single value.
* @param x lists
* @param fr reduce function (acc, v, k, x)
* @param acc initial value
* @returns fr(fr(acc, v₀), v₁)... | fr(acc, v₀) = v₀ if acc not given
*/ export function reduce(x, fr, acc) {
const A = arguments.length, es = entries(x);
return A > 2 ? xentries.reduce(es, fr, acc) : xentries.reduce(es, fr);
}
/**
* Keep entries which pass a test.
* @param x lists
* @param ft test function (v, k, x)
* @returns [k₀, v₀], [k₁, v₁], ... | ft(vᵢ) = true; [kᵢ, vᵢ] ∈ x
*/ export function filter(x, ft) {
const ks = [], vs = [];
for (const [k, v] of entries(x))if (ft(v, k, x)) {
ks.push(k);
vs.push(v);
}
return [
ks,
vs
];
}
/**
* Keep entries with given keys.
* @param x lists
* @param ks keys
* @returns [k₀, v₀], [k₁, v₁], ... | kᵢ ∈ ks; [kᵢ, vᵢ] ∈ x
*/ export function filterAt(x, ks) {
const js = [], us = [];
for (const [k, v] of entries(x))if (ks.includes(k)) {
js.push(k);
us.push(v);
}
return [
js,
us
];
}
/**
* Discard entries which pass a test.
* @param x lists
* @param ft test function (v, k, x)
* @returns [k₀, v₀], [k₁, v₁], ... | ft(vᵢ) = false; [kᵢ, vᵢ] ∈ x
*/ export function reject(x, ft) {
const ks = [], vs = [];
for (const [k, v] of entries(x))if (!ft(v, k, x)) {
ks.push(k);
vs.push(v);
}
return [
ks,
vs
];
}
/**
* Discard entries with given keys.
* @param x lists
* @param ks keys
* @returns [k₀, v₀], [k₁, v₁], ... | kᵢ ∉ ks; [kᵢ, vᵢ] ∈ x
*/ export function rejectAt(x, ks) {
const js = [], us = [];
for (const [k, v] of entries(x))if (!ks.includes(k)) {
js.push(k);
us.push(v);
}
return [
js,
us
];
}
/**
* Flatten nested lists to given depth.
* @param x nested lists
* @param n maximum depth [-1 ⇒ all]
* @param fm map function (v, k, x)
* @param ft test function for flatten (v, k, x) [is]
* @returns flat lists
*/ export function flat(x, n = -1, fm = null, ft = null) {
fm = fm || IDENTITY;
ft = ft || is;
const a = flatTo$(new Map(), x, n, fm, ft);
return [
[
...a.keys()
],
[
...a.values()
]
];
}
function flatTo$(a, x, n, fm, ft) {
for (const [k, v] of entries(x)){
const v1 = fm(v, k, x);
if (n !== 0 && ft(v1, k, x)) flatTo$(a, v1, n - 1, fm, ft);
else a.set(k, v1);
}
return a;
}
/**
* Flatten nested lists, based on map function.
* @param x nested lists
* @param fm map function (v, k, x)
* @param ft test function for flatten (v, k, x) [is]
* @returns flat lists
*/ export function flatMap(x, fm = null, ft = null) {
fm = fm || IDENTITY;
ft = ft || is;
const a = new Map();
for (const [k, v] of entries(x)){
const w = fm(v, k, x);
if (ft(w, k, x)) xmap.concat$(a, entries(w));
else a.set(k, w);
}
return [
[
...a.keys()
],
[
...a.values()
]
];
}
/**
* Combine matching entries from all lists.
* @param xs all lists
* @param fm map function (vs, k)
* @param ft end function (dones) [some]
* @param vd default value
* @returns fm([x₀[k₀], x₁[k₀], ...]), fm([x₀[k₁], x₁[k₁], ...]), ...
*/ export function zip(xs, fm = null, ft = null, vd) {
const a = xmap.zip(xs.map((x)=>new Map(entries(x))), fm, ft, vd);
return [
[
...a.keys()
],
[
...a.values()
]
];
}
// MANIPULATION
// ------------
/**
* Segregate values by test result.
* @param x lists
* @param ft test function (v, k, x)
* @returns [satisfies, doesnt]
*/ export function partition(x, ft) {
const tk = [], tv = [], fk = [], fv = [];
for (const [k, v] of entries(x)){
if (ft(v, k, x)) {
tk.push(k);
tv.push(v);
} else {
fk.push(k);
fv.push(v);
}
}
return [
[
tk,
tv
],
[
fk,
fv
]
];
}
/**
* Segregate entries by similarity.
* @param x entries
* @param fm map function (v, k, x)
* @returns Map \{key ⇒ entries\}
*/ export function partitionAs(x, fm = null) {
fm = fm || IDENTITY;
const a = new Map();
for (const [k, v] of entries(x)){
const v1 = fm(v, k, x);
if (!a.has(v1)) a.set(v1, [
[],
[]
]);
const [ak, av] = a.get(v1);
ak.push(k);
av.push(v);
}
return a;
}
/**
* Break lists into chunks of given size.
* @param x lists
* @param n chunk size [1]
* @param s chunk step [n]
* @returns [x[0..n], x[s..s+n], x[2s..2s+n], ...]
*/ export function chunk(x, n = 1, s = n) {
const kss = xarray.chunk([
...keys(x)
], n, s);
const vss = xarray.chunk([
...values(x)
], n, s);
return xarray.zip([
kss,
vss
]);
}
// COMBINE
// -------
/**
* Append entries from all lists, preferring last.
* @param xs all lists
* @returns x₀ ∪ x₁ ∪ ... | [x₀, x₁, ...] = xs
*/ export function concat(...xs) {
const ks = xiterable.concat(...xs.map(keys));
const vs = xiterable.concat(...xs.map(values));
const a = xmap.fromLists([
ks,
vs
]);
return [
[
...a.keys()
],
[
...a.values()
]
];
}
/**
* Join lists together into a string.
* @param x lists
* @param sep separator [,]
* @param asc associator [=]
* @returns "$\{k₀\}=$\{v₀\},$\{k₁\}=$\{v₁\}..." | [kᵢ, vᵢ] ∈ x
*/ export function join(x, sep = ',', asc = '=') {
return xentries.join(entries(x), sep, asc);
}
// SET OPERATIONS
// --------------
/**
* Check if lists have no common keys.
* @param x lists
* @param y another lists
* @returns x ∩ y = Φ?
*/ export function isDisjoint(x, y) {
const xs = new Set(x[0]);
for (const k of y[0])if (xs.has(k)) return false;
return true;
}
/**
* Obtain keys present in any lists.
* @param xs all lists
* @returns \{k₀, k₁, ...\} | [kᵢ, vᵢ] ∈ x₀ ∪ x₁, ...; [x₀, x₁, ...] = xs
*/ export function unionKeys(...xs) {
const a = new Set();
for (const x of xs){
for (const k of x[0])a.add(k);
}
return a;
}
/**
* Obtain entries present in any lists.
* @param x lists
* @param y another lists
* @param fc combine function (a, b)
* @returns x ∪ y = \{[kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x or [kᵢ, vᵢ] ∈ y\}
*/ export function union(x, y, fc = null) {
const a = new Map();
const xk = x[0], xv = x[1];
const yk = y[0], yv = y[1];
const X = x[0].length;
const Y = y[0].length;
for(let i = 0; i < X; ++i)a.set(xk[i], xv[i]);
for(let i = 0; i < Y; ++i){
const k = yk[i], v = yv[i];
const w = fc && a.has(k) ? fc(a.get(k), v) : v;
a.set(k, w);
}
return fromMap(a);
}
/**
* Obtain entries present in both lists.
* @param x lists
* @param y another lists
* @param fc combine function (a, b)
* @returns x ∩ y = \{[kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x and [kᵢ, vᵢ] ∈ y\}
*/ export function intersection(x, y, fc = null) {
const xm = new Map();
const a = new Map();
const xk = x[0], xv = x[1];
const yk = y[0], yv = y[1];
const X = x[0].length;
const Y = y[0].length;
for(let i = 0; i < X; ++i)xm.set(xk[i], xv[i]);
for(let i = 0; i < Y; ++i){
const k = yk[i], v = yv[i];
if (xm.has(k)) {
const w = fc ? fc(xm.get(k), v) : v;
a.set(k, w);
}
}
return fromMap(a);
}
/**
* Obtain entries not present in another lists.
* @param x lists
* @param y another lists
* @returns x = x - y = \{[kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x, [kᵢ, *] ∉ y\}
*/ export function difference(x, y) {
const a = new Map();
const xk = x[0], xv = x[1];
const yk = y[0];
const X = x[0].length;
for(let i = 0; i < X; ++i)a.set(xk[i], xv[i]);
for (const k of yk)a.delete(k);
return fromMap(a);
}
/**
* Obtain entries not present in both lists.
* @param x lists
* @param y another lists
* @returns x = x-y ∪ y-x
*/ export function symmetricDifference(x, y) {
const a = xmap.symmetricDifference(entries(x), entries(y));
return [
[
...a.keys()
],
[
...a.values()
]
];
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9leHRyYS1saXN0cy9leHRyYS1saXN0cy9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBJREVOVElUWSxcbiAgQ09NUEFSRSxcbn0gZnJvbSBcIkBub2RlZi9leHRyYS1mdW5jdGlvblwiO1xuaW1wb3J0ICogYXMgeGl0ZXJhYmxlIGZyb20gXCJAbm9kZWYvZXh0cmEtaXRlcmFibGVcIjtcbmltcG9ydCAqIGFzIHhhcnJheSAgICBmcm9tIFwiQG5vZGVmL2V4dHJhLWFycmF5XCI7XG5pbXBvcnQgKiBhcyB4ZW50cmllcyAgZnJvbSBcIkBub2RlZi9leHRyYS1lbnRyaWVzXCI7XG5pbXBvcnQgKiBhcyB4bWFwICAgICAgZnJvbSBcIkBub2RlZi9leHRyYS1tYXBcIjtcbi8vIGltcG9ydCAqIGFzIHhzZXQgICBmcm9tIFwiQG5vZGVmL2V4dHJhLXNldFwiO1xuXG5cblxuXG4vLyBUWVBFU1xuLy8gPT09PT1cblxuLyoqIEVudHJpZXMgaXMgYW4gYXJyYXkgb2Yga2V5LXZhbHVlIHBhaXJzLCB3aXRoIHVuaXF1ZSBrZXlzLiAqL1xuZXhwb3J0IHR5cGUgRW50cmllczxLLCBWPiA9IFtLLCBWXVtdO1xuLyoqIExpc3RzIGlzIGEgcGFpciBvZiBrZXkgYXJyYXkgYW5kIHZhbHVlIGFycmF5LCB3aXRoIHVuaXF1ZSBrZXlzLiAqL1xuZXhwb3J0IHR5cGUgTGlzdHM8SywgVj4gPSBbS1tdLCBWW11dO1xuXG5cbi8qKlxuICogSGFuZGxlIHJlYWRpbmcgb2YgYSBzaW5nbGUgdmFsdWUuXG4gKiBAcmV0dXJucyB2YWx1ZVxuICovXG5leHBvcnQgdHlwZSBSZWFkRnVuY3Rpb248VD4gPSAoKSA9PiBUO1xuXG5cbi8qKlxuICogSGFuZGxlIGNvbWJpbmluZyBvZiB0d28gdmFsdWVzLlxuICogQHBhcmFtIGEgYSB2YWx1ZVxuICogQHBhcmFtIGIgYW5vdGhlciB2YWx1ZVxuICogQHJldHVybnMgY29tYmluZWQgdmFsdWVcbiAqL1xuZXhwb3J0IHR5cGUgQ29tYmluZUZ1bmN0aW9uPFQ+ID0gKGE6IFQsIGI6IFQpID0+IFQ7XG5cblxuLyoqXG4gKiBIYW5kbGUgY29tcGFyaXNvbiBvZiB0d28gdmFsdWVzLlxuICogQHBhcmFtIGEgYSB2YWx1ZVxuICogQHBhcmFtIGIgYW5vdGhlciB2YWx1ZVxuICogQHJldHVybnMgYTxiOiAtdmUsIGE9YjogMCwgYT5iOiArdmVcbiAqL1xuZXhwb3J0IHR5cGUgQ29tcGFyZUZ1bmN0aW9uPFQ+ID0gKGE6IFQsIGI6IFQpID0+IG51bWJlcjtcblxuXG4vKipcbiAqIEhhbmRsZSBwcm9jZXNzaW5nIG9mIHZhbHVlcyBpbiBsaXN0cy5cbiAqIEBwYXJhbSB2IHZhbHVlIGluIGxpc3RzXG4gKiBAcGFyYW0gayBrZXkgb2YgdmFsdWUgaW4gbGlzdHNcbiAqIEBwYXJhbSB4IGxpc3RzIGNvbnRhaW5pbmcgdGhlIHZhbHVlXG4gKi9cbmV4cG9ydCB0eXBlIFByb2Nlc3NGdW5jdGlvbjxLLCBWPiA9ICh2OiBWLCBrOiBLLCB4OiBMaXN0czxLLCBWPikgPT4gdm9pZDtcblxuXG4vKipcbiAqIEhhbmRsZSBzZWxlY3Rpb24gb2YgdmFsdWVzIGluIGxpc3RzLlxuICogQHBhcmFtIHYgdmFsdWUgaW4gbGlzdHNcbiAqIEBwYXJhbSBrIGtleSBvZiB2YWx1ZSBpbiBsaXN0c1xuICogQHBhcmFtIHggbGlzdHMgY29udGFpbmluZyB0aGUgdmFsdWVcbiAqIEByZXR1cm5zIHNlbGVjdGVkP1xuICovXG5leHBvcnQgdHlwZSBUZXN0RnVuY3Rpb248SywgVj4gPSAodjogViwgazogSywgeDogTGlzdHM8SywgVj4pID0+IGJvb2xlYW47XG5cblxuLyoqXG4gKiBIYW5kbGUgdHJhbnNmb3JtYXRpb24gb2YgYSB2YWx1ZSB0byBhbm90aGVyLlxuICogQHBhcmFtIHYgdmFsdWUgaW4gbGlzdHNcbiAqIEBwYXJhbSBrIGtleSBvZiB2YWx1ZSBpbiBsaXN0c1xuICogQHBhcmFtIHggbGlzdHMgY29udGFpbmluZyB0aGUgdmFsdWVcbiAqIEByZXR1cm5zIHRyYW5zZm9ybWVkIHZhbHVlXG4gKi9cbmV4cG9ydCB0eXBlIE1hcEZ1bmN0aW9uPEssIFYsIFc+ID0gKHY6IFYsIGs6IEssIHg6IExpc3RzPEssIFY+IHwgbnVsbCkgPT4gVztcblxuXG4vKipcbiAqIEhhbmRsZSByZWR1Y3Rpb24gb2YgbXVsdGlwbGUgdmFsdWVzIGludG8gYSBzaW5nbGUgdmFsdWUuXG4gKiBAcGFyYW0gYWNjIGFjY3VtdWxhdG9yICh0ZW1wb3JhcnkgcmVzdWx0KVxuICogQHBhcmFtIHYgdmFsdWUgaW4gbGlzdHNcbiAqIEBwYXJhbSBrIGtleSBvZiB2YWx1ZSBpbiBsaXN0c1xuICogQHBhcmFtIHggbGlzdHMgY29udGFpbmluZyB0aGUgdmFsdWVcbiAqIEByZXR1cm5zIHJlZHVjZWQgdmFsdWVcbiAqL1xuZXhwb3J0IHR5cGUgUmVkdWNlRnVuY3Rpb248SywgViwgVz4gPSAoYWNjOiBXLCB2OiBWLCBrOiBLLCB4OiBMaXN0czxLLCBWPikgPT4gVztcblxuXG4vKipcbiAqIEhhbmRsZSBlbmRpbmcgb2YgY29tYmluZWQgbGlzdHMuXG4gKiBAcGFyYW0gZG9uZXMgaeG1l8qwIGxpc3RzIGRvbmU/XG4gKiBAcmV0dXJucyBjb21iaW5lZCBsaXN0cyBkb25lP1xuICovXG5leHBvcnQgdHlwZSBFbmRGdW5jdGlvbiA9IChkb25lczogYm9vbGVhbltdKSA9PiBib29sZWFuO1xuXG5cblxuXG4vLyBNRVRIT0RTXG4vLyA9PT09PT09XG5cbi8vIEFCT1VUXG4vLyAtLS0tLVxuXG4vKipcbiAqIENoZWNrIGlmIHZhbHVlIGlzIGxpc3RzLlxuICogQHBhcmFtIHYgdmFsdWVcbiAqIEByZXR1cm5zIHYgaXMgbGlzdHM/XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpczxLLCBWPih2OiB1bmtub3duKTogdiBpcyBMaXN0czxLLCBWPiB7XG4gIHJldHVybiBBcnJheS5pc0FycmF5KHYpICYmIHYubGVuZ3RoPT09MiAmJiBBcnJheS5pc0FycmF5KHZbMF0pICYmIEFycmF5LmlzQXJyYXkodlsxXSk7XG59XG5cblxuLyoqXG4gKiBHZXQgYWxsIGtleXMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHJldHVybnMgW2vigoAsIGvigoEsIC4uLl0gfCBr4bWiIOKIiCB4WzBdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBrZXlzPEssIFY+KHg6IExpc3RzPEssIFY+KTogS1tdIHtcbiAgcmV0dXJuIHhbMF07XG59XG5cblxuLyoqXG4gKiBHZXQgYWxsIHZhbHVlcy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcmV0dXJucyBbduKCgCwgduKCgSwgLi4uXSB8IHbhtaIg4oiIIHhbMV1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbHVlczxLLCBWPih4OiBMaXN0czxLLCBWPik6IFZbXSB7XG4gIHJldHVybiB4WzFdO1xufVxuXG5cbi8qKlxuICogT2J0YWluIGFsbCBrZXktdmFsdWUgcGFpcnMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHJldHVybnMgW1tr4oKALCB24oKAXSwgW2vigoEsIHbigoFdLCAuLi5dIHwga+G1oiDiiIggeFswXTsgduG1oiDiiIggeFsxXVxuICovXG5leHBvcnQgZnVuY3Rpb24gZW50cmllczxLLCBWPih4OiBMaXN0czxLLCBWPik6IEVudHJpZXM8SywgVj4ge1xuICBjb25zdCBhOiBFbnRyaWVzPEssIFY+ID0gW107XG4gIGNvbnN0IHhrID0geFswXSwgeHYgPSB4WzFdO1xuICBjb25zdCBYICA9IHhrLmxlbmd0aDtcbiAgZm9yIChsZXQgaT0wOyBpPFg7ICsraSlcbiAgICBhLnB1c2goW3hrW2ldLCB4dltpXV0pO1xuICByZXR1cm4gYTtcbn1cblxuXG5cblxuLy8gR0VORVJBVEVcbi8vIC0tLS0tLS0tXG5cbi8qKlxuICogQ29udmVydCBtYXAgdG8gbGlzdHMuXG4gKiBAcGFyYW0geCBtYXBcbiAqIEByZXR1cm5zIHggYXMgbGlzdHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZyb21NYXA8SywgVj4oeDogTWFwPEssIFY+KTogTGlzdHM8SywgVj4ge1xuICByZXR1cm4gW0FycmF5LmZyb20oeC5rZXlzKCkpLCBBcnJheS5mcm9tKHgudmFsdWVzKCkpXTtcbn1cblxuXG4vKipcbiAqIENvbnZlcnQgZW50cmllcyB0byBsaXN0cy5cbiAqIEBwYXJhbSB4IGVudHJpZXNcbiAqIEByZXR1cm5zIHggYXMgbGlzdHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZyb21FbnRyaWVzPEssIFY+KHg6IEVudHJpZXM8SywgVj4pOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IGFrOiBLW10gPSBbXTtcbiAgY29uc3QgYXY6IFZbXSA9IFtdO1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiB4KSB7XG4gICAgYWsucHVzaChrKTtcbiAgICBhdi5wdXNoKHYpO1xuICB9XG4gIHJldHVybiBbYWssIGF2XTtcbn1cblxuXG5cblxuLy8gQ0xPTkVcbi8vIC0tLS0tXG5cbi8qKlxuICogU2hhbGxvdyBjbG9uZSBsaXN0cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcmV0dXJucyBzaGFsbG93IGNsb25lIG9mIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNoYWxsb3dDbG9uZTxLLCBWPih4OiBMaXN0czxLLCBWPik6IExpc3RzPEssIFY+IHtcbiAgcmV0dXJuIFt4WzBdLnNsaWNlKCksIHhbMV0uc2xpY2UoKV07XG59XG5leHBvcnQge3NoYWxsb3dDbG9uZSBhcyBzaGFsbG93Q29weX07XG5leHBvcnQge3NoYWxsb3dDbG9uZSBhcyBjbG9uZX07XG5leHBvcnQge3NoYWxsb3dDbG9uZSBhcyBjb3B5fTtcblxuXG4vKipcbiAqIERlZXAgY2xvbmUgbGlzdHMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHJldHVybnMgZGVlcCBjbG9uZSBvZiB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ2xvbmU8SywgVj4oeDogTGlzdHM8SywgVj4pOiBMaXN0czxLLCBWPiB7XG4gIHJldHVybiBzdHJ1Y3R1cmVkQ2xvbmUoeCk7XG59XG5leHBvcnQge2RlZXBDbG9uZSBhcyBzdHJ1Y3R1cmVkQ2xvbmV9O1xuZXhwb3J0IHtkZWVwQ2xvbmUgYXMgZGVlcENvcHl9O1xuXG5cblxuXG4vLyBTSVpFXG4vLyAtLS0tXG5cbi8qKlxuICogRmluZCB0aGUgc2l6ZSBvZiBsaXN0cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcmV0dXJucyB8eHxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNpemU8SywgVj4oeDogTGlzdHM8SywgVj4pOiBudW1iZXIge1xuICByZXR1cm4geFswXS5sZW5ndGg7XG59XG5leHBvcnQge3NpemUgYXMgbGVuZ3RofTtcblxuXG4vKipcbiAqIENoZWNrIGlmIGxpc3RzIGlzIGVtcHR5LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEByZXR1cm5zIHx4fCA9IDA/XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0VtcHR5PEssIFY+KHg6IExpc3RzPEssIFY+KTogYm9vbGVhbiB7XG4gIHJldHVybiB4WzBdLmxlbmd0aD09PTA7XG59XG5cblxuXG5cbi8vIENPTVBBUkVcbi8vIC0tLS0tLS1cblxuLyoqXG4gKiBDb21wYXJlIHR3byBsaXN0cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0geSBhbm90aGVyIGxpc3RzXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyB4PXk6IDAsIG90aGVyd2lzZTogLXZlLyt2ZVxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGFyZTxLLCBWLCBXPVY+KHg6IExpc3RzPEssIFY+LCB5OiBMaXN0czxLLCBWPiwgZmM6IENvbXBhcmVGdW5jdGlvbjxWfFc+IHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb248SywgViwgVnxXPiB8IG51bGw9bnVsbCk6IG51bWJlciB7XG4gIHJldHVybiB4bWFwLmNvbXBhcmUoeG1hcC5mcm9tTGlzdHMoeCksIHhtYXAuZnJvbUxpc3RzKHkpLCBmYywgZm0gYXMgeG1hcC5NYXBGdW5jdGlvbjxLLCBWLCBWIHwgVz4pO1xufVxuXG5cbi8qKlxuICogQ2hlY2sgaWYgdHdvIGxpc3RzIGFyZSBlcXVhbC5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0geSBhbm90aGVyIGxpc3RzXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyB4PXk/XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0VxdWFsPEssIFYsIFc9Vj4oeDogTGlzdHM8SywgVj4sIHk6IExpc3RzPEssIFY+LCBmYzogQ29tcGFyZUZ1bmN0aW9uPFZ8Vz4gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbjxLLCBWLCBWfFc+IHwgbnVsbD1udWxsKTogYm9vbGVhbiB7XG4gIHJldHVybiBjb21wYXJlKHgsIHksIGZjLCBmbSk9PT0wO1xufVxuXG5cblxuXG4vLyBHRVQvU0VUXG4vLyAtLS0tLS0tXG5cbi8qKlxuICogR2V0IGtleSBhdCBpbmRleC5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gaSBpbmRleFxuICogQHJldHVybnMga+KCgCB8IGvhtaIgPSB4WzBdW2ldXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBrZXlBdDxLLCBWPih4OiBMaXN0czxLLCBWPiwgaTogbnVtYmVyKTogSyB7XG4gIHJldHVybiB4WzBdW2ldO1xufVxuXG5cbi8qKlxuICogR2V0IHZhbHVlIGF0IGluZGV4LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBpIGluZGV4XG4gKiBAcmV0dXJucyB24oKAIHwgduG1oiA9IHhbMV1baV1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbHVlQXQ8SywgVj4oeDogTGlzdHM8SywgVj4sIGk6IG51bWJlcik6IFYge1xuICByZXR1cm4geFsxXVtpXTtcbn1cblxuXG4vKipcbiAqIEdldCBlbnRyeSBhdCBpbmRleC5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gaSBpbmRleFxuICogQHJldHVybnMgW2vigoAsIHbigoBdIHwga+G1oiA9IHhbMF1baV07IHbhtaIgPSB4WzFdW2ldXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlbnRyeUF0PEssIFY+KHg6IExpc3RzPEssIFY+LCBpOiBudW1iZXIpOiBbSywgVl0ge1xuICByZXR1cm4gW3hbMF1baV0sIHhbMV1baV1dO1xufVxuXG5cbi8qKlxuICogT2J0YWluIHZhbHVlIGF0IGtleS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gayBrZXlcbiAqIEByZXR1cm5zIHhba11cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldDxLLCBWPih4OiBMaXN0czxLLCBWPiwgazogSyk6IFYgfCB1bmRlZmluZWQge1xuICBjb25zdCBpID0geFswXS5pbmRleE9mKGspO1xuICByZXR1cm4gaT49MD8geFsxXVtpXSA6IHVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIE9idGFpbiB2YWx1ZXMgYXQga2V5cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0ga3Mga2V5c1xuICogQHJldHVybnMgW3hba+KCgF0sIHhba+KCgV0sIC4uLl0gfCBba+KCgCwga+KCgSwgLi4uXSA9IGtzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGw8SywgVj4oeDogTGlzdHM8SywgVj4sIGtzOiBLW10pOiBWW10ge1xuICBjb25zdCBhOiBWW10gPSBbXTtcbiAgZm9yIChjb25zdCBrIG9mIGtzKVxuICAgIGEucHVzaChnZXQoeCwgaykgYXMgVik7XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogT2J0YWluIHZhbHVlIGF0IHBhdGggaW4gbmVzdGVkIGxpc3RzLlxuICogQHBhcmFtIHggbmVzdGVkIGxpc3RzXG4gKiBAcGFyYW0gcCBwYXRoXG4gKiBAcmV0dXJucyB4W2vigoBdW2vigoFdWy4uLl0gfCBba+KCgCwga+KCgSwgLi4uXSA9IHBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBhdGg8Sz4oeDogTGlzdHM8SywgdW5rbm93bj4sIHA6IEtbXSk6IHVua25vd24ge1xuICBsZXQgeGFueTogdW5rbm93biA9IHg7XG4gIGZvciAoY29uc3QgayBvZiBwKVxuICAgIHhhbnkgPSBpcyh4YW55KT8gZ2V0KHhhbnksIGspIDogdW5kZWZpbmVkO1xuICByZXR1cm4geGFueTtcbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIG5lc3RlZCBsaXN0cyBoYXMgYSBwYXRoLlxuICogQHBhcmFtIHggbmVzdGVkIGxpc3RzXG4gKiBAcGFyYW0gcCBzZWFyY2ggcGF0aFxuICogQHJldHVybnMgeFtr4oKAXVtr4oKBXVsuLi5dIGV4aXN0cz8gfCBba+KCgCwga+KCgSwgLi4uXSA9IHBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc1BhdGg8VD4oeDogTGlzdHM8VCwgdW5rbm93bj4sIHA6IFRbXSk6IGJvb2xlYW4ge1xuICByZXR1cm4gZ2V0UGF0aCh4LCBwKSE9PXVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIFNldCB2YWx1ZSBhdCBrZXkuXG4gKiBAcGFyYW0geCBsaXN0cyAodXBkYXRlZCEpXG4gKiBAcGFyYW0gayBrZXlcbiAqIEBwYXJhbSB2IHZhbHVlXG4gKiBAcmV0dXJucyB4IHwgeFtrXSA9IHZcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldCQ8SywgVj4oeDogTGlzdHM8SywgVj4sIGs6IEssIHY6IFYpOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IGkgPSB4WzBdLmluZGV4T2Yoayk7XG4gIGlmIChpPj0wKSB4WzFdW2ldID0gdjtcbiAgZWxzZSB7IHhbMF0ucHVzaChrKTsgeFsxXS5wdXNoKHYpOyB9XG4gIHJldHVybiB4O1xufVxuXG5cbi8qKlxuICogU2V0IHZhbHVlIGF0IGtleS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gayBrZXlcbiAqIEBwYXJhbSB2IHZhbHVlXG4gKiBAcmV0dXJucyB4JyB8IHgnID0geDsgeCdba10gPSB2XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXQ8SywgVj4oeDogTGlzdHM8SywgVj4sIGs6IEssIHY6IFYpOiBMaXN0czxLLCBWPiB7XG4gIHJldHVybiBzZXQkKHNoYWxsb3dDbG9uZSh4KSwgaywgdik7XG59XG5cblxuLyoqXG4gKiBFeGNoYW5nZSB0d28gdmFsdWVzLlxuICogQHBhcmFtIHggbGlzdHMgKHVwZGF0ZWQhKVxuICogQHBhcmFtIGsgYSBrZXlcbiAqIEBwYXJhbSBsIGFub3RoZXIga2V5XG4gKiBAcmV0dXJucyB4IHwgeFtrXSDih5QgeFtsXVxuICovXG5leHBvcnQgZnVuY3Rpb24gc3dhcCQ8SywgVj4oeDogTGlzdHM8SywgVj4sIGs6IEssIGw6IEspOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IGkgPSB4WzBdLmluZGV4T2Yoayk7XG4gIGNvbnN0IGogPSB4WzBdLmluZGV4T2YobCk7XG4gIGlmIChpPj0wICYmIGo+PTApIHsgIC8vIHhhcnJheS5zd2FwJCh4WzFdLCBpLCBqKVxuICAgIGNvbnN0IHQgPSB4WzFdW2ldO1xuICAgIHhbMV1baV0gPSB4WzFdW2pdO1xuICAgIHhbMV1bal0gPSB0O1xuICB9XG4gIHJldHVybiB4O1xufVxuXG5cbi8qKlxuICogRXhjaGFuZ2UgdHdvIHZhbHVlcy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gayBhIGtleVxuICogQHBhcmFtIGwgYW5vdGhlciBrZXlcbiAqIEByZXR1cm5zIHgnIHwgeCcgPSB4OyB4J1trXSA9IHhbbF07IHgnW2xdID0geFtrXVxuICovXG5leHBvcnQgZnVuY3Rpb24gc3dhcDxLLCBWPih4OiBMaXN0czxLLCBWPiwgazogSywgbDogSyk6IExpc3RzPEssIFY+IHtcbiAgcmV0dXJuIHN3YXAkKHNoYWxsb3dDbG9uZSh4KSwgaywgbCk7XG59XG5cblxuLyoqXG4gKiBSZW1vdmUgdmFsdWUgYXQga2V5LlxuICogQHBhcmFtIHggbGlzdHMgKHVwZGF0ZWQhKVxuICogQHBhcmFtIGsga2V5XG4gKiBAcmV0dXJucyB4IHwgeCA9IHggXFxcXCBcXHtbaywgKl1cXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZSQ8SywgVj4oeDogTGlzdHM8SywgVj4sIGs6IEspOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IGkgPSB4WzBdLmluZGV4T2Yoayk7XG4gIGlmIChpPj0wKSB7XG4gICAgeFswXS5zcGxpY2UoaSwgMSk7XG4gICAgeFsxXS5zcGxpY2UoaSwgMSk7XG4gIH1cbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBSZW1vdmUgdmFsdWUgYXQga2V5LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBrIGtleVxuICogQHJldHVybnMgeCBcXFxcIFxce1trLCAqXVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVtb3ZlPEssIFY+KHg6IExpc3RzPEssIFY+LCBrOiBLKTogTGlzdHM8SywgVj4ge1xuICByZXR1cm4gcmVtb3ZlJChzaGFsbG93Q2xvbmUoeCksIGspO1xufVxuXG5cblxuXG4vLyBQQVJUXG4vLyAtLS0tXG5cbi8qKlxuICogR2V0IGZpcnN0IGVudHJ5IGZyb20gbGlzdHMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGVkIGRlZmF1bHQgZW50cnlcbiAqIEByZXR1cm5zIFtr4oKALCB24oKAXSBpZiB4IOKJoCDOpiBlbHNlIGVkIHwgW2vigoAsIHbigoBdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoZWFkPEssIFY+KHg6IExpc3RzPEssIFY+LCBlZDogW0ssIFZdPVtdIGFzIHVua25vd24gYXMgW0ssIFZdKTogW0ssIFZdIHtcbiAgcmV0dXJuIHhbMF0ubGVuZ3RoID4gMD8gW3hbMF1bMF0sIHhbMV1bMF1dIDogZWQ7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gbGlzdHMgd2l0aG91dCBpdHMgZmlyc3QgZW50cnkuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHJldHVybnMgeCBcXFxcIFxce1tr4oKALCB24oKAXVxcfSBpZiB4IOKJoCDOpiBlbHNlIHggfCBba+KCgCwgduKCgF0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRhaWw8SywgVj4oeDogTGlzdHM8SywgVj4pOiBMaXN0czxLLCBWPiB7XG4gIHJldHVybiBzbGljZSh4LCAxKTtcbn1cblxuXG4vKipcbiAqIE9idGFpbiBhbGwgYnV0IHRoZSBsYXN0IGVudHJ5IGZyb20gbGlzdHMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHJldHVybnMgeCBcXFxcIFxce1tr4bWiLCB24bWiXVxcfSBpZiB4IOKJoCDOpiBlbHNlIHggfCBba+G1oiwgduG1ol0g4oiIIHg7IGkgPSB8eHwgLSAxXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbml0PEssIFY+KHg6IExpc3RzPEssIFY+KTogTGlzdHM8SywgVj4ge1xuICByZXR1cm4gc2xpY2UoeCwgMCwgLTEpO1xufVxuXG5cbi8qKlxuICogR2V0IGxhc3QgZW50cnkgZnJvbSBsaXN0cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZWQgZGVmYXVsdCBlbnRyeVxuICogQHJldHVybnMgW2vhtaIsIHbhtaJdIGlmIHgg4omgIM6mIGVsc2UgZWQgfCBba+G1oiwgduG1ol0g4oiIIHg7IGkgPSB8eHwgLSAxXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsYXN0PEssIFY+KHg6IExpc3RzPEssIFY+LCBlZDogW0ssIFZdPVtdIGFzIHVua25vd24gYXMgW0ssIFZdKTogW0ssIFZdIHtcbiAgY29uc3QgaSA9IHhbMF0ubGVuZ3RoIC0gMTtcbiAgcmV0dXJuIGk+PTA/IFt4WzBdW2ldLCB4WzFdW2ldXSA6IGVkO1xufVxuXG5cbi8qKlxuICogT2J0YWluIGEgcG9ydGlvbiBvZiBsaXN0cyAoc2hhbGxvdykuXG4gKiBAcGFyYW0geCBsaXN0cyAodXBkYXRlZCEpXG4gKiBAcGFyYW0gaSBzdGFydCBpbmRleCBbMF1cbiAqIEBwYXJhbSBJIGVuZCBpbmRleCAoZXhjbHVzaXZlKSBbfHh8XVxuICogQHJldHVybnMgeCB8IHggPSBcXHtba+G1oiwgduG1ol0sIFtr4bWi4oKK4oKBLCB24bWi4oKK4oKBXSwgLi4uXFx9IHwgW2visbwsIHbisbxdIOKIiCB4IGFuZCBpIOKJpCBqIDwgSVxuICovXG5leHBvcnQgZnVuY3Rpb24gc2xpY2UkPEssIFY+KHg6IExpc3RzPEssIFY+LCBpOiBudW1iZXI9MCwgSTogbnVtYmVyPXhbMF0ubGVuZ3RoKTogTGlzdHM8SywgVj4ge1xuICBjb25zdCBYID0geFswXS5sZW5ndGg7XG4gIGkgPSBpPDA/IE1hdGgubWF4KFgraSwgMCkgOiBpO1xuICBJID0gSTwwPyBNYXRoLm1heChYK0ksIDApIDogSTtcbiAgeFswXS5sZW5ndGggPSBJO1xuICB4WzFdLmxlbmd0aCA9IEk7XG4gIHhbMF0uc3BsaWNlKDAsIGkpO1xuICB4WzBdLnNwbGljZSgwLCBpKTtcbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gYSBwb3J0aW9uIG9mIGxpc3RzIChzaGFsbG93KS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gaSBzdGFydCBpbmRleCBbMF1cbiAqIEBwYXJhbSBJIGVuZCBpbmRleCAoZXhjbHVzaXZlKSBbfHh8XVxuICogQHJldHVybnMgXFx7W2vhtaIsIHbhtaJdLCBba+G1ouKCiuKCgSwgduG1ouKCiuKCgV0sIC4uLlxcfSB8IFtr4rG8LCB24rG8XSDiiIggeCBhbmQgaSDiiaQgaiA8IElcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNsaWNlPEssIFY+KHg6IExpc3RzPEssIFY+LCBpOiBudW1iZXI9MCwgSTogbnVtYmVyPXhbMF0ubGVuZ3RoKTogTGlzdHM8SywgVj4ge1xuICByZXR1cm4gW3hbMF0uc2xpY2UoaSwgSSksIHhbMV0uc2xpY2UoaSwgSSldO1xufVxuXG5cbi8qKlxuICogQ2hhbmdlIGNvbnRlbnRzIG9mIGxpc3RzIGJ5IHJlbW92aW5nIGV4aXN0aW5nIGVudHJpZXMgYW5kL29yIGFkZGluZyBuZXcgb25lcy5cbiAqIEBwYXJhbSB4IGxpc3RzICh1cGRhdGVkISlcbiAqIEBwYXJhbSBpIHN0YXJ0IGluZGV4IFswXVxuICogQHBhcmFtIG4gbnVtYmVyIG9mIGVudHJpZXMgdG8gcmVtb3ZlIFt8eHwtaV1cbiAqIEBwYXJhbSBlcyBlbnRyaWVzIHRvIGFkZCBbzqZdXG4gKiBAcmV0dXJucyB4IHwgeCA9IFxce1tr4oKALCB24oKAXSwgLi4uLCBba+G1ouKCi+KCgSwgduG1ouKCi+KCgV0sIFtr4bWi4oKK4oKZLCB24bWi4oKK4oKZXSwgLi4uXFx9IHwgW2visbwsIHbisbxdIOKIiCB4IGFuZCBqIOKIiCBbMCwgaSkg4oiqIFtpK24sIHx4fClcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNwbGljZSQ8SywgVj4oeDogTGlzdHM8SywgVj4sIGk6IG51bWJlcj0wLCBuOiBudW1iZXI9eFswXS5sZW5ndGgsIC4uLmVzOiBbSywgVl1bXSk6IExpc3RzPEssIFY+IHtcbiAgY29uc3QgWCA9IHhbMF0ubGVuZ3RoO1xuICBpID0gaTwwPyBNYXRoLm1heChYK2ksIDApIDogaTtcbiAgbiA9IE1hdGgubWF4KG4sIDApO1xuICBjb25zdCBrcyA9IFtdLCB2cyA9IFtdO1xuICBmb3IoY29uc3QgW2ssIHZdIG9mIGVzKSB7XG4gICAga3MucHVzaChrKTtcbiAgICB2cy5wdXNoKHYpO1xuICB9XG4gIHhbMF0uc3BsaWNlKGksIG4sIC4uLmtzKTtcbiAgeFsxXS5zcGxpY2UoaSwgbiwgLi4udnMpO1xuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIENoYW5nZSBjb250ZW50cyBvZiBsaXN0cyBieSByZW1vdmluZyBleGlzdGluZyBlbnRyaWVzIGFuZC9vciBhZGRpbmcgbmV3IG9uZXMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGkgc3RhcnQgaW5kZXggWzBdXG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgZW50cmllcyB0byByZW1vdmUgW3x4fC1pXVxuICogQHBhcmFtIGVzIGVudHJpZXMgdG8gYWRkIFvOpl1cbiAqIEByZXR1cm5zIFxce1tr4oKALCB24oKAXSwgLi4uLCBba+G1ouKCi+KCgSwgduG1ouKCi+KCgV0sIFtr4bWi4oKK4oKZLCB24bWi4oKK4oKZXSwgLi4uXFx9IHwgW2visbwsIHbisbxdIOKIiCB4IGFuZCBqIOKIiCBbMCwgaSkg4oiqIFtpK24sIHx4fClcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNwbGljZTxLLCBWPih4OiBMaXN0czxLLCBWPiwgaTogbnVtYmVyPTAsIG46IG51bWJlcj14WzBdLmxlbmd0aCwgLi4uZXM6IFtLLCBWXVtdKTogTGlzdHM8SywgVj4ge1xuICBjb25zdCBrcyA9IFtdLCB2cyA9IFtdO1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBlcykge1xuICAgIGtzLnB1c2goayk7XG4gICAgdnMucHVzaCh2KTtcbiAgfVxuICBjb25zdCB4ayA9IHhbMF0uc2xpY2UoMCwgaSkuY29uY2F0KGtzLCB4WzBdLnNsaWNlKGkrbikpO1xuICBjb25zdCB4diA9IHhbMV0uc2xpY2UoMCwgaSkuY29uY2F0KHZzLCB4WzFdLnNsaWNlKGkrbikpO1xuICByZXR1cm4gW3hrLCB4dl07XG59XG5cblxuLyoqXG4gKiBLZWVwIGZpcnN0IG4gZW50cmllcyBvbmx5LlxuICogQHBhcmFtIHggbGlzdHMgKHVwZGF0ZWQhKVxuICogQHBhcmFtIG4gbnVtYmVyIG9mIGVudHJpZXMgWzFdXG4gKiBAcmV0dXJucyB4IHwgeCA9IFxce1tr4oKALCB24oKAXSwgW2vigoEsIHbigoFdLCAuLi5cXH0gfCBba+G1oiwgduG1ol0g4oiIIHggYW5kIHxcXHtba+KCgCwgduKCgF0sIFtr4oKBLCB24oKBXSwgLi4uXFx9fCDiiaQgblxuICovXG5leHBvcnQgZnVuY3Rpb24gdGFrZSQ8SywgVj4oeDogTGlzdHM8SywgVj4sIG46IG51bWJlcj0xKTogTGlzdHM8SywgVj4ge1xuICByZXR1cm4gc2xpY2UkKHgsIDAsIG4pO1xufVxuXG5cbi8qKlxuICogS2VlcCBmaXJzdCBuIGVudHJpZXMgb25seS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgZW50cmllcyBbMV1cbiAqIEByZXR1cm5zIFxce1tr4oKALCB24oKAXSwgW2vigoEsIHbigoFdLCAuLi5cXH0gfCBba+G1oiwgduG1ol0g4oiIIHggYW5kIHxcXHtba+KCgCwgduKCgF0sIFtr4oKBLCB24oKBXSwgLi4uXFx9fCDiiaQgblxuICovXG5leHBvcnQgZnVuY3Rpb24gdGFrZTxLLCBWPih4OiBMaXN0czxLLCBWPiwgbjogbnVtYmVyPTEpOiBMaXN0czxLLCBWPiB7XG4gIHJldHVybiBzbGljZSh4LCAwLCBuKTtcbn1cblxuXG4vKipcbiAqIFJlbW92ZSBmaXJzdCBuIGVudHJpZXMuXG4gKiBAcGFyYW0geCBsaXN0cyAodXBkYXRlZCEpXG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgZW50cmllcyBbMV1cbiAqIEByZXR1cm5zIHggfCB4ID0gXFx7W2vigpksIHbigpldLCBba+KCmeKCiuKCgSwgduKCmeKCiuKCgV0sIC4uLlxcfSB8IFtr4bWiLCB24bWiXSDiiIggeCBhbmQgfFxce1tr4oKZLCB24oKZXSwgW2vigpnigorigoEsIHbigpnigorigoFdLCAuLi5cXH18IOKJpCBtYXgofHh8IC0gbiwgMClcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRyb3AkPEssIFY+KHg6IExpc3RzPEssIFY+LCBuOiBudW1iZXI9MSk6IExpc3RzPEssIFY+IHtcbiAgcmV0dXJuIHNsaWNlJCh4LCBuKTtcbn1cblxuXG4vKipcbiAqIFJlbW92ZSBmaXJzdCBuIGVudHJpZXMuXG4gKiBAcGFyYW0geCBhIG1hcFxuICogQHBhcmFtIG4gbnVtYmVyIG9mIGVudHJpZXMgWzFdXG4gKiBAcmV0dXJucyBcXHtba+KCmSwgduKCmV0sIFtr4oKZ4oKK4oKBLCB24oKZ4oKK4oKBXSwgLi4uXFx9IHwgW2vhtaIsIHbhtaJdIOKIiCB4IGFuZCB8XFx7W2vigpksIHbigpldLCBba+KCmeKCiuKCgSwgduKCmeKCiuKCgV0sIC4uLlxcfXwg4omkIG1heCh8eHwgLSBuLCAwKVxuICovXG5leHBvcnQgZnVuY3Rpb24gZHJvcDxLLCBWPih4OiBMaXN0czxLLCBWPiwgbjogbnVtYmVyPTEpOiBMaXN0czxLLCBWPiB7XG4gIHJldHVybiBzbGljZSh4LCBuKTtcbn1cblxuXG5cblxuLy8gUFJPUEVSVFlcbi8vIC0tLS0tLS0tXG5cbi8qKlxuICogQ291bnQgdmFsdWVzIHdoaWNoIHNhdGlzZnkgYSB0ZXN0LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgzqN04bWiIHwgdOG1oiA9IDEgaWYgZnQoduG1oikgZWxzZSAwOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvdW50PEssIFY+KHg6IExpc3RzPEssIFY+LCBmdDogVGVzdEZ1bmN0aW9uPEssIFY+KTogbnVtYmVyIHtcbiAgbGV0IGEgPSAwO1xuICBjb25zdCB4ayA9IHhbMF0sIHh2ID0geFsxXTtcbiAgY29uc3QgWCAgPSB4ay5sZW5ndGg7XG4gIGZvciAobGV0IGk9MDsgaTxYOyArK2kpXG4gICAgaWYgKGZ0KHh2W2ldLCB4a1tpXSwgeCkpICsrYTtcbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBDb3VudCBvY2N1cnJlbmNlcyBvZiB2YWx1ZXMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIE1hcCBcXHt2YWx1ZSDih5IgY291bnRcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvdW50QXM8SywgViwgVz1WPih4OiBMaXN0czxLLCBWPiwgZm06IE1hcEZ1bmN0aW9uPEssIFYsIFZ8Vz4gfCBudWxsPW51bGwpOiBNYXA8VnxXLCBudW1iZXI+IHtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgY29uc3QgeGsgPSB4WzBdLCB4diA9IHhbMV07XG4gIGNvbnN0IGEgID0gbmV3IE1hcDxWfFcsIG51bWJlcj4oKTtcbiAgY29uc3QgWCAgPSB4ay5sZW5ndGg7XG4gIGZvciAobGV0IGk9MDsgaTxYOyArK2kpIHtcbiAgICBjb25zdCB3ID0gZm0oeHZbaV0sIHhrW2ldLCB4KTtcbiAgICBhLnNldCh3LCAoYS5nZXQodykgfHwgMCkgKyAxKTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEZpbmQgc21hbGxlc3QgdmFsdWUuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgdiB8IHYg4omkIHbhtaI7IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gbWluPEssIFYsIFc9Vj4oeDogTGlzdHM8SywgVj4sIGZjOiBDb21wYXJlRnVuY3Rpb248VnxXPiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uPEssIFYsIFZ8Vz4gfCBudWxsPW51bGwpOiBWIHtcbiAgcmV0dXJuIHJhbmdlRW50cmllcyh4LCBmYywgZm0pWzBdWzFdO1xufVxuXG5cbi8qKlxuICogRmluZCBzbWFsbGVzdCBlbnRyeS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBbbWluX2tleSwgbWluX3ZhbHVlXVxuICovXG5leHBvcnQgZnVuY3Rpb24gbWluRW50cnk8SywgViwgVz1WPih4OiBMaXN0czxLLCBWPiwgZmM6IENvbXBhcmVGdW5jdGlvbjxWfFc+IHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb248SywgViwgVnxXPiB8IG51bGw9bnVsbCk6IFtLLCBWXSB7XG4gIHJldHVybiByYW5nZUVudHJpZXMoeCwgZmMsIGZtKVswXTtcbn1cblxuXG4vKipcbiAqIEZpbmQgbGFyZ2VzdCB2YWx1ZS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyB2IHwgdiDiiaUgduG1ojsgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXg8SywgViwgVz1WPih4OiBMaXN0czxLLCBWPiwgZmM6IENvbXBhcmVGdW5jdGlvbjxWfFc+IHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb248SywgViwgVnxXPiB8IG51bGw9bnVsbCk6IFYge1xuICByZXR1cm4gcmFuZ2VFbnRyaWVzKHgsIGZjLCBmbSlbMV1bMV07XG59XG5cblxuLyoqXG4gKiBGaW5kIGxhcmdlc3QgZW50cnkuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgW21heF9rZXksIG1heF92YWx1ZV1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1heEVudHJ5PEssIFYsIFc9Vj4oeDogTGlzdHM8SywgVj4sIGZjOiBDb21wYXJlRnVuY3Rpb248VnxXPiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uPEssIFYsIFZ8Vz4gfCBudWxsPW51bGwpOiBbSywgVl0ge1xuICByZXR1cm4gcmFuZ2VFbnRyaWVzKHgsIGZjLCBmbSlbMV07XG59XG5cblxuLyoqXG4gKiBGaW5kIHNtYWxsZXN0IGFuZCBsYXJnZXN0IHZhbHVlcy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBbbWluX3ZhbHVlLCBtYXhfdmFsdWVdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByYW5nZTxLLCBWLCBXPVY+KHg6IExpc3RzPEssIFY+LCBmYzogQ29tcGFyZUZ1bmN0aW9uPFZ8Vz4gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbjxLLCBWLCBWfFc+IHwgbnVsbD1udWxsKTogW1YsIFZdIHtcbiAgY29uc3QgW2EsIGJdID0gcmFuZ2VFbnRyaWVzKHgsIGZjLCBmbSk7XG4gIHJldHVybiBbYVsxXSwgYlsxXV07XG59XG5cblxuLyoqXG4gKiBGaW5kIHNtYWxsZXN0IGFuZCBsYXJnZXN0IGVudHJpZXMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgW21pbl9lbnRyeSwgbWF4X2VudHJ5XVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmFuZ2VFbnRyaWVzPEssIFYsIFc9Vj4oeDogTGlzdHM8SywgVj4sIGZjOiBDb21wYXJlRnVuY3Rpb248VnxXPiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uPEssIFYsIFZ8Vz4gfCBudWxsPW51bGwpOiBbW0ssIFZdLCBbSywgVl1dIHtcbiAgZmMgPSBmYyB8fCBDT01QQVJFO1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBjb25zdCB4ayA9IHhbMF0sIHh2ID0geFsxXTtcbiAgbGV0ICAgbWsgPSB4a1swXSwgbXYgPSB4dlswXSwgbXcgPSBmbShtdiwgbWssIHgpO1xuICBsZXQgICBuayA9IHhrWzBdLCBudiA9IHh2WzBdLCBudyA9IG13O1xuICBjb25zdCBYICA9IHhbMF0ubGVuZ3RoO1xuICBmb3IgKGxldCBpPTE7IGk8WDsgKytpKSB7XG4gICAgY29uc3QgdyA9IGZtKHh2W2ldLCB4a1tpXSwgeCk7XG4gICAgaWYgKGZjKHcsIG13KTwwKSB7IG1rID0geGtbaV07IG12ID0geHZbaV07IG13ID0gdzsgfVxuICAgIGlmIChmYyh3LCBudyk+MCkgeyBuayA9IHhrW2ldOyBudiA9IHh2W2ldOyBudyA9IHc7IH1cbiAgfVxuICByZXR1cm4gW1ttaywgbXZdLCBbbmssIG52XV07XG59XG5cblxuXG5cbi8vIEFSUkFOR0VNRU5UU1xuLy8gLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogTGlzdCBhbGwgcG9zc2libGUgc3Vic2V0cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgZW50cmllcyBpbiBlYWNoIHN1YnNldCBbLTEg4oeSIGFueV1cbiAqIEByZXR1cm5zIGVudHJpZXMgc2VsZWN0ZWQgYnkgYml0IGZyb20gMC4uMl58eHwgaWYgbjwwOyBvbmx5IG9mIGxlbmd0aCBuIG90aGVyd2lzZVxuICovXG5leHBvcnQgZnVuY3Rpb24qIHN1YnNldHM8SywgVj4oeDogTGlzdHM8SywgVj4sIG46IG51bWJlcj0tMSk6IEl0ZXJhYmxlPExpc3RzPEssIFY+PiB7XG4gIGZvcihjb25zdCBhIG9mIHhtYXAuc3Vic2V0cyh4bWFwLmZyb21MaXN0cyh4KSwgbikpXG4gICAgeWllbGQgW1suLi5hLmtleXMoKV0sIFsuLi5hLnZhbHVlcygpXV07XG59XG5cblxuLyoqXG4gKiBQaWNrIGFuIGFyYml0cmFyeSBrZXkuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZyIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIChbMCwgMSkpXG4gKiBAcmV0dXJucyBr4bWiIHwga+G1oiDiiIggeFswXVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmFuZG9tS2V5PEssIFY+KHg6IExpc3RzPEssIFY+LCBmcjogUmVhZEZ1bmN0aW9uPG51bWJlcj49TWF0aC5yYW5kb20pOiBLIHtcbiAgcmV0dXJuIHhhcnJheS5yYW5kb21WYWx1ZShbLi4ua2V5cyh4KV0sIGZyKTtcbn1cbmV4cG9ydCB7cmFuZG9tS2V5IGFzIGtleX07XG5cblxuLyoqXG4gKiBQaWNrIGFuIGFyYml0cmFyeSB2YWx1ZS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZnIgcmFuZG9tIG51bWJlciBnZW5lcmF0b3IgKFswLCAxKSlcbiAqIEByZXR1cm5zIHbhtaIgfCB24bWiIOKIiCB4WzFdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByYW5kb21WYWx1ZTxLLCBWPih4OiBMaXN0czxLLCBWPiwgZnI6IFJlYWRGdW5jdGlvbjxudW1iZXI+PU1hdGgucmFuZG9tKTogViB7XG4gIHJldHVybiB4YXJyYXkucmFuZG9tVmFsdWUoWy4uLnZhbHVlcyh4KV0sIGZyKTtcbn1cbmV4cG9ydCB7cmFuZG9tVmFsdWUgYXMgdmFsdWV9O1xuXG5cbi8qKlxuICogUGljayBhbiBhcmJpdHJhcnkgZW50cnkuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZyIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIChbMCwgMSkpXG4gKiBAcmV0dXJucyBba+G1oiwgduG1ol0gfCBr4bWiIOKIiCB4WzBdOyB24bWiIOKIiCB4WzFdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByYW5kb21FbnRyeTxLLCBWPih4OiBMaXN0czxLLCBWPiwgZnI6IFJlYWRGdW5jdGlvbjxudW1iZXI+PU1hdGgucmFuZG9tKTogW0ssIFZdIHtcbiAgcmV0dXJuIHhhcnJheS5yYW5kb21WYWx1ZShbLi4uZW50cmllcyh4KV0sIGZyKTtcbn1cbmV4cG9ydCB7cmFuZG9tRW50cnkgYXMgZW50cnl9O1xuXG5cbi8qKlxuICogUGljayBhbiBhcmJpdHJhcnkgc3Vic2V0LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBuIG51bWJlciBvZiBlbnRyaWVzIFstMSDih5IgYW55XVxuICogQHBhcmFtIGZyIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIChbMCwgMSkpXG4gKiBAcmV0dXJucyBbW2vhtaIsIGvisbwsIC4uLl0sIFt24bWiLCB24rG8LCAuLi5dXSB8IGvhtaIsIGvisbwsIC4uLiDiiIggeFswXTsgduG1oiwgduKxvCwgLi4uIOKIiCB4WzFdOyB8W2vhtaIsIGvisbwsICwgLi4uXXwgPSB8eHwgaWYgbjwwIGVsc2UgblxuICovXG5leHBvcnQgZnVuY3Rpb24gcmFuZG9tU3Vic2V0PEssIFY+KHg6IExpc3RzPEssIFY+LCBuOiBudW1iZXI9LTEsIGZyOiBSZWFkRnVuY3Rpb248bnVtYmVyPj1NYXRoLnJhbmRvbSk6IExpc3RzPEssIFY+IHtcbiAgY29uc3QgYSA9IHhtYXAucmFuZG9tU3Vic2V0KHhtYXAuZnJvbUxpc3RzKHgpLCBuLCBmcik7XG4gIHJldHVybiBbWy4uLmEua2V5cygpXSwgWy4uLmEudmFsdWVzKCldXTtcbn1cbmV4cG9ydCB7cmFuZG9tU3Vic2V0IGFzIHN1YnNldH07XG5cblxuXG5cbi8vIEZJTkRcbi8vIC0tLS1cblxuLyoqXG4gKiBDaGVjayBpZiBsaXN0cyBoYXMgYSBrZXkuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGsgc2VhcmNoIGtleVxuICogQHJldHVybnMgayDiiIgga2V5cyh4KT9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc0tleTxLLCBWPih4OiBMaXN0czxLLCBWPiwgazogSyk6IGJvb2xlYW4ge1xuICByZXR1cm4geFswXS5pbmNsdWRlcyhrKTtcbn1cbmV4cG9ydCB7aGFzS2V5IGFzIGhhc307XG5cblxuLyoqXG4gKiBDaGVjayBpZiBsaXN0cyBoYXMgYSB2YWx1ZS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gdiBzZWFyY2ggdmFsdWVcbiAqIEBwYXJhbSBmYyBjb21wYXJlIGZ1bmN0aW9uIChhLCBiKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIHYg4oiIIHZhbHVlcyh4KT9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc1ZhbHVlPEssIFYsIFc9Vj4oeDogTGlzdHM8SywgVj4sIHY6IFYsIGZjOiBDb21wYXJlRnVuY3Rpb248VnxXPiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uPEssIFYsIFZ8Vz4gfCBudWxsPW51bGwpOiBib29sZWFuIHtcbiAgaWYgKCFmYyAmJiAhZm0pIHJldHVybiB4WzFdLmluY2x1ZGVzKHYpO1xuICByZXR1cm4gc2VhcmNoVmFsdWUoeCwgdiwgZmMsIGZtKSE9PXVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIGxpc3RzIGhhcyBhbiBlbnRyeS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZSBzZWFyY2ggZW50cnlcbiAqIEBwYXJhbSBmYyBjb21wYXJlIGZ1bmN0aW9uIChhLCBiKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIGsg4oiIIHhbMF07IHYg4oiIIHhbMV07IGsg4oeSIHY/IHwgW2ssIHZdID0gZVxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzRW50cnk8SywgViwgVz1WPih4OiBMaXN0czxLLCBWPiwgZTogW0ssIFZdLCBmYzogQ29tcGFyZUZ1bmN0aW9uPFZ8Vz4gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbjxLLCBWLCBWfFc+IHwgbnVsbD1udWxsKTogYm9vbGVhbiB7XG4gIGZjID0gZmMgfHwgQ09NUEFSRTtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgY29uc3QgW2ssIHZdID0gZSwgdSA9IGdldCh4LCBrKTtcbiAgY29uc3QgdTEgPSBmbSh1IGFzIFYsIGssIHgpO1xuICBjb25zdCB2MSA9IGZtKHYsIGssIHgpO1xuICByZXR1cm4gZmModTEsIHYxKT09PTA7XG59XG5cblxuLyoqXG4gKiBDaGVjayBpZiBsaXN0cyBoYXMgYSBzdWJzZXQuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIHkgc2VhcmNoIHN1YnNldFxuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgeSDiioYgeD9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc1N1YnNldDxLLCBWLCBXPVY+KHg6IExpc3RzPEssIFY+LCB5OiBMaXN0czxLLCBWPiwgZmM6IENvbXBhcmVGdW5jdGlvbjxWfFc+IHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb248SywgViwgVnxXPiB8IG51bGw9bnVsbCk6IGJvb2xlYW4ge1xuICByZXR1cm4geG1hcC5oYXNTdWJzZXQoeG1hcC5mcm9tTGlzdHMoeCksIHhtYXAuZnJvbUxpc3RzKHkpLCBmYywgZm0gYXMgeG1hcC5NYXBGdW5jdGlvbjxLLCBWLCBWIHwgVz4pO1xufVxuXG5cbi8qKlxuICogRmluZCBmaXJzdCB2YWx1ZSBwYXNzaW5nIGEgdGVzdCAoZGVmYXVsdCBvcmRlcikuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBmaXJzdCB2IHwgZnQodikgPSB0cnVlOyBbaywgdl0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmQ8SywgVj4oeDogTGlzdHM8SywgVj4sIGZ0OiBUZXN0RnVuY3Rpb248SywgVj4pOiBWIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHhlbnRyaWVzLmZpbmQoZW50cmllcyh4KSwgZnQgYXMgeGVudHJpZXMuVGVzdEZ1bmN0aW9uPEssIFY+KTtcbn1cblxuXG4vKipcbiAqIEZpbmQgdmFsdWVzIHBhc3NpbmcgYSB0ZXN0LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgduKCgCwgduKCgSwgLi4uIHwgZnQoduG1oikgPSB0cnVlOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRBbGw8SywgVj4oeDogTGlzdHM8SywgVj4sIGZ0OiBUZXN0RnVuY3Rpb248SywgVj4pOiBJdGVyYWJsZTxWPiB7XG4gIHJldHVybiB4ZW50cmllcy5maW5kQWxsKGVudHJpZXMoeCksIGZ0IGFzIHhlbnRyaWVzLlRlc3RGdW5jdGlvbjxLLCBWPik7XG59XG5cblxuLyoqXG4gKiBGaW5kcyBrZXkgb2YgYW4gZW50cnkgcGFzc2luZyBhIHRlc3QuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBrZXkgb2YgZW50cnlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlYXJjaDxLLCBWPih4OiBMaXN0czxLLCBWPiwgZnQ6IFRlc3RGdW5jdGlvbjxLLCBWPik6IEsgfCB1bmRlZmluZWQge1xuICByZXR1cm4geGVudHJpZXMuc2VhcmNoKGVudHJpZXMoeCksIGZ0IGFzIHhlbnRyaWVzLlRlc3RGdW5jdGlvbjxLLCBWPik7XG59XG5cblxuLyoqXG4gKiBGaW5kIGtleXMgb2YgZW50cmllcyBwYXNzaW5nIGEgdGVzdC5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIGtleXMgb2YgZW50cmllc1xuICovXG5leHBvcnQgZnVuY3Rpb24gc2VhcmNoQWxsPEssIFY+KHg6IExpc3RzPEssIFY+LCBmdDogVGVzdEZ1bmN0aW9uPEssIFY+KTogSXRlcmFibGU8Sz4ge1xuICByZXR1cm4geGVudHJpZXMuc2VhcmNoQWxsKGVudHJpZXMoeCksIGZ0IGFzIHhlbnRyaWVzLlRlc3RGdW5jdGlvbjxLLCBWPik7XG59XG5cblxuLyoqXG4gKiBGaW5kIGEga2V5IHdpdGggZ2l2ZW4gdmFsdWUuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIHYgc2VhcmNoIHZhbHVlXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBrZXkgb2YgdmFsdWVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlYXJjaFZhbHVlPEssIFYsIFc9Vj4oeDogTGlzdHM8SywgVj4sIHY6IFYsIGZjOiBDb21wYXJlRnVuY3Rpb248VnxXPiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uPEssIFYsIFZ8Vz4gfCBudWxsPW51bGwpOiBLIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHhlbnRyaWVzLnNlYXJjaFZhbHVlKGVudHJpZXMoeCksIHYsIGZjLCBmbSBhcyB4ZW50cmllcy5NYXBGdW5jdGlvbjxLLCBWLCBWIHwgVz4pO1xufVxuXG5cbi8qKlxuICogRmluZCBrZXlzIHdpdGggZ2l2ZW4gdmFsdWUuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIHYgc2VhcmNoIHZhbHVlXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBrZXlzIG9mIHZhbHVlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZWFyY2hWYWx1ZUFsbDxLLCBWLCBXPVY+KHg6IExpc3RzPEssIFY+LCB2OiBWLCBmYzogQ29tcGFyZUZ1bmN0aW9uPFZ8Vz4gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbjxLLCBWLCBWfFc+IHwgbnVsbD1udWxsKTogSXRlcmFibGU8Sz4ge1xuICByZXR1cm4geGVudHJpZXMuc2VhcmNoVmFsdWVBbGwoZW50cmllcyh4KSwgdiwgZmMsIGZtIGFzIHhlbnRyaWVzLk1hcEZ1bmN0aW9uPEssIFYsIFYgfCBXPik7XG59XG5cblxuXG5cbi8vIEZVTkNUSU9OQUxcbi8vIC0tLS0tLS0tLS1cblxuLyoqXG4gKiBDYWxsIGEgZnVuY3Rpb24gZm9yIGVhY2ggdmFsdWUuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZwIHByb2Nlc3MgZnVuY3Rpb24gKHYsIGssIHgpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JFYWNoPEssIFY+KHg6IExpc3RzPEssIFY+LCBmYzogUHJvY2Vzc0Z1bmN0aW9uPEssIFY+KTogdm9pZCB7XG4gIHhlbnRyaWVzLmZvckVhY2goZW50cmllcyh4KSwgZmMgYXMgeGVudHJpZXMuUHJvY2Vzc0Z1bmN0aW9uPEssIFY+KTtcbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIGFueSB2YWx1ZSBzYXRpc2ZpZXMgYSB0ZXN0LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgdHJ1ZSBpZiBmdCh24bWiKSA9IHRydWUgZm9yIHNvbWUgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzb21lPEssIFY+KHg6IExpc3RzPEssIFY+LCBmdDogVGVzdEZ1bmN0aW9uPEssIFY+IHwgbnVsbD1udWxsKTogYm9vbGVhbiB7XG4gIHJldHVybiB4ZW50cmllcy5zb21lKGVudHJpZXMoeCksIGZ0IGFzIHhlbnRyaWVzLlRlc3RGdW5jdGlvbjxLLCBWPik7XG59XG5cblxuLyoqXG4gKiBDaGVjayBpZiBhbGwgdmFsdWVzIHNhdGlzZnkgYSB0ZXN0LlxuICogQHBhcmFtIHggZW50cmllc1xuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyB0cnVlIGlmIGZ0KHbhtaIpID0gdHJ1ZSBmb3IgZXZlcnkgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBldmVyeTxLLCBWPih4OiBMaXN0czxLLCBWPiwgZnQ6IFRlc3RGdW5jdGlvbjxLLCBWPik6IGJvb2xlYW4ge1xuICByZXR1cm4geGVudHJpZXMuZXZlcnkoZW50cmllcyh4KSwgZnQgYXMgeGVudHJpZXMuVGVzdEZ1bmN0aW9uPEssIFY+KTtcbn1cblxuXG4vKipcbiAqIFRyYW5zZm9ybSB2YWx1ZXMgb2YgZW50cmllcy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgW2vigoAsIGZtKHbigoApXSwgW2vigoEsIGZtKHbigoEpXSwgLi4uIHwgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXA8SywgViwgVz4oeDogTGlzdHM8SywgVj4sIGZtOiBNYXBGdW5jdGlvbjxLLCBWLCBXPik6IExpc3RzPEssIFc+IHtcbiAgY29uc3Qga3MgPSBbXSwgdnMgPSBbXTtcbiAgZm9yIChjb25zdCBbaywgdl0gb2YgZW50cmllcyh4KSkge1xuICAgIGtzLnB1c2goayk7XG4gICAgdnMucHVzaChmbSh2LCBrLCB4KSk7XG4gIH1cbiAgcmV0dXJuIFtrcywgdnNdO1xufVxuXG5cbi8qKlxuICogUmVkdWNlIHZhbHVlcyBvZiBlbnRyaWVzIHRvIGEgc2luZ2xlIHZhbHVlLlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBmciByZWR1Y2UgZnVuY3Rpb24gKGFjYywgdiwgaywgeClcbiAqIEBwYXJhbSBhY2MgaW5pdGlhbCB2YWx1ZVxuICogQHJldHVybnMgZnIoZnIoYWNjLCB24oKAKSwgduKCgSkuLi4gfCBmcihhY2MsIHbigoApID0gduKCgCBpZiBhY2Mgbm90IGdpdmVuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWR1Y2U8SywgViwgVz1WPih4OiBMaXN0czxLLCBWPiwgZnI6IFJlZHVjZUZ1bmN0aW9uPEssIFYsIFZ8Vz4sIGFjYz86IFZ8Vyk6IFZ8VyB7XG4gIGNvbnN0IEEgPSBhcmd1bWVudHMubGVuZ3RoLCBlcyA9IGVudHJpZXMoeCk7XG4gIHJldHVybiBBPjI/IHhlbnRyaWVzLnJlZHVjZShlcywgZnIgYXMgeGVudHJpZXMuUmVkdWNlRnVuY3Rpb248SywgViwgViB8IFc+LCBhY2MpIDogeGVudHJpZXMucmVkdWNlKGVzLCBmciBhcyB4ZW50cmllcy5SZWR1Y2VGdW5jdGlvbjxLLCBWLCBWIHwgVz4pO1xufVxuXG5cbi8qKlxuICogS2VlcCBlbnRyaWVzIHdoaWNoIHBhc3MgYSB0ZXN0LlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgW2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLiB8IGZ0KHbhtaIpID0gdHJ1ZTsgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaWx0ZXI8SywgVj4oeDogTGlzdHM8SywgVj4sIGZ0OiBUZXN0RnVuY3Rpb248SywgVj4pOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IGtzID0gW10sIHZzID0gW107XG4gIGZvciAoY29uc3QgW2ssIHZdIG9mIGVudHJpZXMoeCkpXG4gICAgaWYgKGZ0KHYsIGssIHgpKSB7IGtzLnB1c2goayk7IHZzLnB1c2godik7IH1cbiAgcmV0dXJuIFtrcywgdnNdO1xufVxuXG5cbi8qKlxuICogS2VlcCBlbnRyaWVzIHdpdGggZ2l2ZW4ga2V5cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0ga3Mga2V5c1xuICogQHJldHVybnMgW2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLiB8IGvhtaIg4oiIIGtzOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlckF0PEssIFY+KHg6IExpc3RzPEssIFY+LCBrczogS1tdKTogTGlzdHM8SywgVj4ge1xuICBjb25zdCBqcyA9IFtdLCB1cyA9IFtdO1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBlbnRyaWVzKHgpKVxuICAgIGlmIChrcy5pbmNsdWRlcyhrKSkgeyBqcy5wdXNoKGspOyB1cy5wdXNoKHYpOyB9XG4gIHJldHVybiBbanMsIHVzXTtcbn1cblxuXG4vKipcbiAqIERpc2NhcmQgZW50cmllcyB3aGljaCBwYXNzIGEgdGVzdC5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIFtr4oKALCB24oKAXSwgW2vigoEsIHbigoFdLCAuLi4gfCBmdCh24bWiKSA9IGZhbHNlOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlamVjdDxLLCBWPih4OiBMaXN0czxLLCBWPiwgZnQ6IFRlc3RGdW5jdGlvbjxLLCBWPik6IExpc3RzPEssIFY+IHtcbiAgY29uc3Qga3MgPSBbXSwgdnMgPSBbXTtcbiAgZm9yIChjb25zdCBbaywgdl0gb2YgZW50cmllcyh4KSlcbiAgICBpZiAoIWZ0KHYsIGssIHgpKSB7IGtzLnB1c2goayk7IHZzLnB1c2godik7IH1cbiAgcmV0dXJuIFtrcywgdnNdO1xufVxuXG5cbi8qKlxuICogRGlzY2FyZCBlbnRyaWVzIHdpdGggZ2l2ZW4ga2V5cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0ga3Mga2V5c1xuICogQHJldHVybnMgW2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLiB8IGvhtaIg4oiJIGtzOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlamVjdEF0PEssIFY+KHg6IExpc3RzPEssIFY+LCBrczogS1tdKTogTGlzdHM8SywgVj4ge1xuICBjb25zdCBqcyA9IFtdLCB1cyA9IFtdO1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBlbnRyaWVzKHgpKVxuICAgIGlmICgha3MuaW5jbHVkZXMoaykpIHsganMucHVzaChrKTsgdXMucHVzaCh2KTsgfVxuICByZXR1cm4gW2pzLCB1c107XG59XG5cblxuLyoqXG4gKiBGbGF0dGVuIG5lc3RlZCBsaXN0cyB0byBnaXZlbiBkZXB0aC5cbiAqIEBwYXJhbSB4IG5lc3RlZCBsaXN0c1xuICogQHBhcmFtIG4gbWF4aW11bSBkZXB0aCBbLTEg4oeSIGFsbF1cbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiBmb3IgZmxhdHRlbiAodiwgaywgeCkgW2lzXVxuICogQHJldHVybnMgZmxhdCBsaXN0c1xuICovXG5leHBvcnQgZnVuY3Rpb24gZmxhdDxLPih4OiBMaXN0czxLLCB1bmtub3duPiwgbjogbnVtYmVyPS0xLCBmbTogTWFwRnVuY3Rpb248SywgdW5rbm93biwgdW5rbm93bj4gfCBudWxsPW51bGwsIGZ0OiBUZXN0RnVuY3Rpb248SywgdW5rbm93bj4gfCBudWxsPW51bGwpOiBMaXN0czxLLCB1bmtub3duPiB7XG4gIGZtID0gZm0gfHwgSURFTlRJVFk7XG4gIGZ0ID0gZnQgfHwgaXM7XG4gIGNvbnN0IGEgPSBmbGF0VG8kKG5ldyBNYXAoKSwgeCwgbiwgZm0sIGZ0KTtcbiAgcmV0dXJuIFtbLi4uYS5rZXlzKCldLCBbLi4uYS52YWx1ZXMoKV1dO1xufVxuXG5mdW5jdGlvbiBmbGF0VG8kPEs+KGE6IE1hcDxLLCB1bmtub3duPiwgeDogTGlzdHM8SywgdW5rbm93bj4sIG46IG51bWJlciwgZm06IE1hcEZ1bmN0aW9uPEssIHVua25vd24sIHVua25vd24+LCBmdDogVGVzdEZ1bmN0aW9uPEssIHVua25vd24+KTogTWFwPEssIHVua25vd24+IHtcbiAgZm9yIChjb25zdCBbaywgdl0gb2YgZW50cmllcyh4KSkge1xuICAgIGNvbnN0IHYxID0gZm0odiwgaywgeCk7XG4gICAgaWYgKG4hPT0wICYmIGZ0KHYxLCBrLCB4KSkgZmxhdFRvJChhLCB2MSBhcyBMaXN0czxLLCB1bmtub3duPiwgbi0xLCBmbSwgZnQpO1xuICAgIGVsc2UgYS5zZXQoaywgdjEpO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogRmxhdHRlbiBuZXN0ZWQgbGlzdHMsIGJhc2VkIG9uIG1hcCBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IG5lc3RlZCBsaXN0c1xuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uIGZvciBmbGF0dGVuICh2LCBrLCB4KSBbaXNdXG4gKiBAcmV0dXJucyBmbGF0IGxpc3RzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0TWFwPEs+KHg6IExpc3RzPEssIHVua25vd24+LCBmbTogTWFwRnVuY3Rpb248SywgdW5rbm93biwgdW5rbm93bj4gfCBudWxsPW51bGwsIGZ0OiBUZXN0RnVuY3Rpb248SywgdW5rbm93bj4gfCBudWxsPW51bGwpOiBMaXN0czxLLCB1bmtub3duPiB7XG4gIGZtID0gZm0gfHwgSURFTlRJVFk7XG4gIGZ0ID0gZnQgfHwgaXM7XG4gIGNvbnN0IGEgID0gbmV3IE1hcCgpO1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBlbnRyaWVzKHgpKSB7XG4gICAgY29uc3QgdyA9IGZtKHYsIGssIHgpO1xuICAgIGlmIChmdCh3LCBrLCB4KSkgeG1hcC5jb25jYXQkKGEsIGVudHJpZXModyBhcyBMaXN0czxLLCB1bmtub3duPikpO1xuICAgIGVsc2UgYS5zZXQoaywgdyk7XG4gIH1cbiAgcmV0dXJuIFtbLi4uYS5rZXlzKCldLCBbLi4uYS52YWx1ZXMoKV1dO1xufVxuXG5cbi8qKlxuICogQ29tYmluZSBtYXRjaGluZyBlbnRyaWVzIGZyb20gYWxsIGxpc3RzLlxuICogQHBhcmFtIHhzIGFsbCBsaXN0c1xuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodnMsIGspXG4gKiBAcGFyYW0gZnQgZW5kIGZ1bmN0aW9uIChkb25lcykgW3NvbWVdXG4gKiBAcGFyYW0gdmQgZGVmYXVsdCB2YWx1ZVxuICogQHJldHVybnMgZm0oW3jigoBba+KCgF0sIHjigoFba+KCgF0sIC4uLl0pLCBmbShbeOKCgFtr4oKBXSwgeOKCgVtr4oKBXSwgLi4uXSksIC4uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gemlwPEssIFYsIFc9Vj4oeHM6IExpc3RzPEssIFY+W10sIGZtOiBNYXBGdW5jdGlvbjxLLCBWW10sIFZbXXxXPiB8IG51bGw9bnVsbCwgZnQ6IEVuZEZ1bmN0aW9uIHwgbnVsbD1udWxsLCB2ZD86IFYpOiBMaXN0czxLLCBWW118Vz4ge1xuICBjb25zdCBhID0geG1hcC56aXAoeHMubWFwKHggPT4gbmV3IE1hcChlbnRyaWVzKHgpKSksIGZtIGFzIHhtYXAuTWFwRnVuY3Rpb248SywgVltdLCBWW118Vz4sIGZ0LCB2ZCk7XG4gIHJldHVybiBbWy4uLmEua2V5cygpXSwgWy4uLmEudmFsdWVzKCldIGFzIHVua25vd24gYXMgVltdW11dO1xufVxuXG5cblxuXG4vLyBNQU5JUFVMQVRJT05cbi8vIC0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIFNlZ3JlZ2F0ZSB2YWx1ZXMgYnkgdGVzdCByZXN1bHQuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBbc2F0aXNmaWVzLCBkb2VzbnRdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJ0aXRpb248SywgVj4oeDogTGlzdHM8SywgVj4sIGZ0OiBUZXN0RnVuY3Rpb248SywgVj4pOiBbTGlzdHM8SywgVj4sIExpc3RzPEssIFY+XSB7XG4gIGNvbnN0IHRrID0gW10sIHR2ID0gW10sIGZrID0gW10sIGZ2ID0gW107XG4gIGZvciAoY29uc3QgW2ssIHZdIG9mIGVudHJpZXMoeCkpIHtcbiAgICBpZiAoZnQodiwgaywgeCkpIHsgdGsucHVzaChrKTsgdHYucHVzaCh2KTsgfVxuICAgIGVsc2UgICAgICAgICAgICAgeyBmay5wdXNoKGspOyBmdi5wdXNoKHYpOyB9XG4gIH1cbiAgcmV0dXJuIFtbdGssIHR2XSwgW2ZrLCBmdl1dO1xufVxuXG5cbi8qKlxuICogU2VncmVnYXRlIGVudHJpZXMgYnkgc2ltaWxhcml0eS5cbiAqIEBwYXJhbSB4IGVudHJpZXNcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBNYXAgXFx7a2V5IOKHkiBlbnRyaWVzXFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJ0aXRpb25BczxLLCBWLCBXPVY+KHg6IExpc3RzPEssIFY+LCBmbTogTWFwRnVuY3Rpb248SywgViwgVnxXPiB8IG51bGw9bnVsbCk6IE1hcDxWfFcsIExpc3RzPEssIFY+PiB7XG4gIGZtID0gZm0gfHwgSURFTlRJVFk7XG4gIGNvbnN0IGEgID0gbmV3IE1hcCgpO1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBlbnRyaWVzKHgpKSB7XG4gICAgY29uc3QgdjEgPSBmbSh2LCBrLCB4KTtcbiAgICBpZiAoIWEuaGFzKHYxKSkgYS5zZXQodjEsIFtbXSwgW11dKTtcbiAgICBjb25zdCBbYWssIGF2XSA9IGEuZ2V0KHYxKTtcbiAgICBhay5wdXNoKGspOyBhdi5wdXNoKHYpO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogQnJlYWsgbGlzdHMgaW50byBjaHVua3Mgb2YgZ2l2ZW4gc2l6ZS5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gbiBjaHVuayBzaXplIFsxXVxuICogQHBhcmFtIHMgY2h1bmsgc3RlcCBbbl1cbiAqIEByZXR1cm5zIFt4WzAuLm5dLCB4W3MuLnMrbl0sIHhbMnMuLjJzK25dLCAuLi5dXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaHVuazxLLCBWPih4OiBMaXN0czxLLCBWPiwgbjogbnVtYmVyPTEsIHM6IG51bWJlcj1uKTogTGlzdHM8SywgVj5bXSB7XG4gIGNvbnN0IGtzcyA9IHhhcnJheS5jaHVuayhbLi4ua2V5cyh4KV0sIG4sIHMpO1xuICBjb25zdCB2c3MgPSB4YXJyYXkuY2h1bmsoWy4uLnZhbHVlcyh4KV0sIG4sIHMpO1xuICByZXR1cm4geGFycmF5LnppcChba3NzLCB2c3MgYXMgdW5rbm93biBhcyBLW11bXV0pIGFzIExpc3RzPEssIFY+W107XG59XG5cblxuXG5cbi8vIENPTUJJTkVcbi8vIC0tLS0tLS1cblxuLyoqXG4gKiBBcHBlbmQgZW50cmllcyBmcm9tIGFsbCBsaXN0cywgcHJlZmVycmluZyBsYXN0LlxuICogQHBhcmFtIHhzIGFsbCBsaXN0c1xuICogQHJldHVybnMgeOKCgCDiiKogeOKCgSDiiKogLi4uIHwgW3jigoAsIHjigoEsIC4uLl0gPSB4c1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29uY2F0PEssIFY+KC4uLnhzOiBMaXN0czxLLCBWPltdKTogTGlzdHM8SywgVj4ge1xuICBjb25zdCBrcyA9IHhpdGVyYWJsZS5jb25jYXQoLi4ueHMubWFwKGtleXMpKTtcbiAgY29uc3QgdnMgPSB4aXRlcmFibGUuY29uY2F0KC4uLnhzLm1hcCh2YWx1ZXMpKTtcbiAgY29uc3QgYSAgPSB4bWFwLmZyb21MaXN0cyhba3MsIHZzXSk7XG4gIHJldHVybiBbWy4uLmEua2V5cygpXSwgWy4uLmEudmFsdWVzKCldXTtcbn1cblxuXG4vKipcbiAqIEpvaW4gbGlzdHMgdG9nZXRoZXIgaW50byBhIHN0cmluZy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0gc2VwIHNlcGFyYXRvciBbLF1cbiAqIEBwYXJhbSBhc2MgYXNzb2NpYXRvciBbPV1cbiAqIEByZXR1cm5zIFwiJFxce2vigoBcXH09JFxce3bigoBcXH0sJFxce2vigoFcXH09JFxce3bigoFcXH0uLi5cIiB8IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gam9pbjxLLCBWPih4OiBMaXN0czxLLCBWPiwgc2VwOiBzdHJpbmc9JywnLCBhc2M6IHN0cmluZz0nPScpOiBzdHJpbmcge1xuICByZXR1cm4geGVudHJpZXMuam9pbihlbnRyaWVzKHgpLCBzZXAsIGFzYyk7XG59XG5cblxuXG5cbi8vIFNFVCBPUEVSQVRJT05TXG4vLyAtLS0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIENoZWNrIGlmIGxpc3RzIGhhdmUgbm8gY29tbW9uIGtleXMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIHkgYW5vdGhlciBsaXN0c1xuICogQHJldHVybnMgeCDiiKkgeSA9IM6mP1xuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEaXNqb2ludDxLLCBWPih4OiBMaXN0czxLLCBWPiwgeTogTGlzdHM8SywgVj4pOiBib29sZWFuIHtcbiAgY29uc3QgeHMgPSBuZXcgU2V0PEs+KHhbMF0pO1xuICBmb3IgKGNvbnN0IGsgb2YgeVswXSlcbiAgICBpZiAoeHMuaGFzKGspKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiB0cnVlO1xufVxuXG5cbi8qKlxuICogT2J0YWluIGtleXMgcHJlc2VudCBpbiBhbnkgbGlzdHMuXG4gKiBAcGFyYW0geHMgYWxsIGxpc3RzXG4gKiBAcmV0dXJucyBcXHtr4oKALCBr4oKBLCAuLi5cXH0gfCBba+G1oiwgduG1ol0g4oiIIHjigoAg4oiqIHjigoEsIC4uLjsgW3jigoAsIHjigoEsIC4uLl0gPSB4c1xuICovXG5leHBvcnQgZnVuY3Rpb24gdW5pb25LZXlzPEssIFY+KC4uLnhzOiBMaXN0czxLLCBWPltdKTogU2V0PEs+IHtcbiAgY29uc3QgYSA9IG5ldyBTZXQ8Sz4oKTtcbiAgZm9yIChjb25zdCB4IG9mIHhzKSB7XG4gICAgZm9yIChjb25zdCBrIG9mIHhbMF0pXG4gICAgICBhLmFkZChrKTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIE9idGFpbiBlbnRyaWVzIHByZXNlbnQgaW4gYW55IGxpc3RzLlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSB5IGFub3RoZXIgbGlzdHNcbiAqIEBwYXJhbSBmYyBjb21iaW5lIGZ1bmN0aW9uIChhLCBiKVxuICogQHJldHVybnMgeCDiiKogeSA9IFxce1tr4bWiLCB24bWiXSB8IFtr4bWiLCB24bWiXSDiiIggeCBvciBba+G1oiwgduG1ol0g4oiIIHlcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVuaW9uPEssIFY+KHg6IExpc3RzPEssIFY+LCB5OiBMaXN0czxLLCBWPiwgZmM6IENvbWJpbmVGdW5jdGlvbjxWPiB8IG51bGw9bnVsbCk6IExpc3RzPEssIFY+IHtcbiAgY29uc3QgYSAgPSBuZXcgTWFwPEssIFY+KCk7XG4gIGNvbnN0IHhrID0geFswXSwgeHYgPSB4WzFdO1xuICBjb25zdCB5ayA9IHlbMF0sIHl2ID0geVsxXTtcbiAgY29uc3QgWCAgPSB4WzBdLmxlbmd0aDtcbiAgY29uc3QgWSAgPSB5WzBdLmxlbmd0aDtcbiAgZm9yIChsZXQgaT0wOyBpPFg7ICsraSlcbiAgICBhLnNldCh4a1tpXSwgeHZbaV0pO1xuICBmb3IgKGxldCBpPTA7IGk8WTsgKytpKSB7XG4gICAgY29uc3QgayA9IHlrW2ldLCB2ID0geXZbaV07XG4gICAgY29uc3QgdyA9IGZjICYmIGEuaGFzKGspPyBmYyhhLmdldChrKSBhcyBWLCB2KSA6IHY7XG4gICAgYS5zZXQoaywgdyk7XG4gIH1cbiAgcmV0dXJuIGZyb21NYXAoYSk7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gZW50cmllcyBwcmVzZW50IGluIGJvdGggbGlzdHMuXG4gKiBAcGFyYW0geCBsaXN0c1xuICogQHBhcmFtIHkgYW5vdGhlciBsaXN0c1xuICogQHBhcmFtIGZjIGNvbWJpbmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcmV0dXJucyB4IOKIqSB5ID0gXFx7W2vhtaIsIHbhtaJdIHwgW2vhtaIsIHbhtaJdIOKIiCB4IGFuZCBba+G1oiwgduG1ol0g4oiIIHlcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGludGVyc2VjdGlvbjxLLCBWPih4OiBMaXN0czxLLCBWPiwgeTogTGlzdHM8SywgVj4sIGZjOiBDb21iaW5lRnVuY3Rpb248Vj4gfCBudWxsPW51bGwpOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IHhtID0gbmV3IE1hcDxLLCBWPigpO1xuICBjb25zdCBhICA9IG5ldyBNYXA8SywgVj4oKTtcbiAgY29uc3QgeGsgPSB4WzBdLCB4diA9IHhbMV07XG4gIGNvbnN0IHlrID0geVswXSwgeXYgPSB5WzFdO1xuICBjb25zdCBYICA9IHhbMF0ubGVuZ3RoO1xuICBjb25zdCBZICA9IHlbMF0ubGVuZ3RoO1xuICBmb3IgKGxldCBpPTA7IGk8WDsgKytpKVxuICAgIHhtLnNldCh4a1tpXSwgeHZbaV0pO1xuICBmb3IgKGxldCBpPTA7IGk8WTsgKytpKSB7XG4gICAgY29uc3QgayA9IHlrW2ldLCB2ID0geXZbaV07XG4gICAgaWYgKHhtLmhhcyhrKSkge1xuICAgICAgY29uc3QgdyA9IGZjPyBmYyh4bS5nZXQoaykgYXMgViwgdikgOiB2O1xuICAgICAgYS5zZXQoaywgdyk7XG4gICAgfVxuICB9XG4gIHJldHVybiBmcm9tTWFwKGEpO1xufVxuXG5cbi8qKlxuICogT2J0YWluIGVudHJpZXMgbm90IHByZXNlbnQgaW4gYW5vdGhlciBsaXN0cy5cbiAqIEBwYXJhbSB4IGxpc3RzXG4gKiBAcGFyYW0geSBhbm90aGVyIGxpc3RzXG4gKiBAcmV0dXJucyB4ID0geCAtIHkgPSBcXHtba+G1oiwgduG1ol0gfCBba+G1oiwgduG1ol0g4oiIIHgsIFtr4bWiLCAqXSDiiIkgeVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gZGlmZmVyZW5jZTxLLCBWPih4OiBMaXN0czxLLCBWPiwgeTogTGlzdHM8SywgVj4pOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IGEgID0gbmV3IE1hcDxLLCBWPigpO1xuICBjb25zdCB4ayA9IHhbMF0sIHh2ID0geFsxXTtcbiAgY29uc3QgeWsgPSB5WzBdO1xuICBjb25zdCBYICA9IHhbMF0ubGVuZ3RoO1xuICBmb3IgKGxldCBpPTA7IGk8WDsgKytpKVxuICAgIGEuc2V0KHhrW2ldLCB4dltpXSk7XG4gIGZvciAoY29uc3QgayBvZiB5aylcbiAgICBhLmRlbGV0ZShrKTtcbiAgcmV0dXJuIGZyb21NYXAoYSk7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gZW50cmllcyBub3QgcHJlc2VudCBpbiBib3RoIGxpc3RzLlxuICogQHBhcmFtIHggbGlzdHNcbiAqIEBwYXJhbSB5IGFub3RoZXIgbGlzdHNcbiAqIEByZXR1cm5zIHggPSB4LXkg4oiqIHkteFxuICovXG5leHBvcnQgZnVuY3Rpb24gc3ltbWV0cmljRGlmZmVyZW5jZTxLLCBWPih4OiBMaXN0czxLLCBWPiwgeTogTGlzdHM8SywgVj4pOiBMaXN0czxLLCBWPiB7XG4gIGNvbnN0IGEgPSB4bWFwLnN5bW1ldHJpY0RpZmZlcmVuY2UoZW50cmllcyh4KSwgZW50cmllcyh5KSk7XG4gIHJldHVybiBbWy4uLmEua2V5cygpXSwgWy4uLmEudmFsdWVzKCldXTtcbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxTQUNFLFFBQVEsRUFDUixPQUFPLFFBQ0Ysd0JBQXdCO0FBQy9CLFlBQVksZUFBZSx3QkFBd0I7QUFDbkQsWUFBWSxZQUFlLHFCQUFxQjtBQUNoRCxZQUFZLGNBQWUsdUJBQXVCO0FBQ2xELFlBQVksVUFBZSxtQkFBbUI7QUEwRjlDLFVBQVU7QUFDVixVQUFVO0FBRVYsUUFBUTtBQUNSLFFBQVE7QUFFUjs7OztDQUlDLEdBQ0QsT0FBTyxTQUFTLEdBQVMsQ0FBVTtFQUNqQyxPQUFPLE1BQU0sT0FBTyxDQUFDLE1BQU0sRUFBRSxNQUFNLEtBQUcsS0FBSyxNQUFNLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLE1BQU0sT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFO0FBQ3RGO0FBR0E7Ozs7Q0FJQyxHQUNELE9BQU8sU0FBUyxLQUFXLENBQWM7RUFDdkMsT0FBTyxDQUFDLENBQUMsRUFBRTtBQUNiO0FBR0E7Ozs7Q0FJQyxHQUNELE9BQU8sU0FBUyxPQUFhLENBQWM7RUFDekMsT0FBTyxD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LENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUc7R0FBRztBQUM3QztBQUdBOzs7Ozs7O0NBT0MsR0FDRCxPQUFPLFNBQVMsUUFBYyxDQUFjLEVBQUUsSUFBVSxDQUFDLEVBQUUsSUFBVSxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQVk7RUFDL0YsTUFBTSxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTTtFQUNyQixJQUFJLElBQUUsSUFBRyxLQUFLLEdBQUcsQ0FBQyxJQUFFLEdBQUcsS0FBSztFQUM1QixJQUFJLEtBQUssR0FBRyxDQUFDLEdBQUc7RUFDaEIsTUFBTSxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUU7RUFDdEIsS0FBSSxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUksR0FBSTtJQUN0QixHQUFHLElBQUksQ0FBQztJQUNSLEdBQUcsSUFBSSxDQUFDO0VBQ1Y7RUFDQSxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE1BQU07RUFDckIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxNQUFNO0VBQ3JCLE9BQU87QUFDVDtBQUdBOzs7Ozs7O0NBT0MsR0FDRCxPQUFPLFNBQVMsT0FBYSxDQUFjLEVBQUUsSUFBVSxDQUFDLEVBQUUsSUFBVSxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQVk7RUFDOUYsTUFBTSxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUU7RUFDdEIsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUksR0FBSTtJQUN2QixHQUFHLElBQUksQ0FBQztJQUNSLEdBQUcsSUFBSSxDQUFDO0VBQ1Y7RUFDQSxNQUFNLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUU7RUFDcEQsTUFBTSxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxNQUFN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