extra-object
Version:
A collection of methods for working with Objects.<br>
1,087 lines • 101 kB
JavaScript
import { IDENTITY, COMPARE } from "@nodef/extra-function";
import { last as arrayLast, some as arraySome, subsequences as arraySubsequences, randomValue as arrayRandomValue, randomSubsequence as arrayRandomSubsequence } from "@nodef/extra-array";
// CONSTANTS
// =========
/** You-Know-Who. */ const BAD_KEYS = [
"__proto__",
"prototype",
"constructor"
];
// METHODS
// =======
// ABOUT
// -----
/**
* Check if value is a dictionary.
* @param v a value
* @returns v is a dictionary?
*/ export function is(v) {
return typeof v === "object";
}
/**
* List all keys.
* @param x an object
* @returns k₀, k₁, ... | [kᵢ, vᵢ] ∈ x
*/ export function keys(x) {
return Object.keys(x);
}
/**
* List all values.
* @param x an object
* @returns v₀, v₁, ... | [kᵢ, vᵢ] ∈ x
*/ export function values(x) {
return Object.values(x);
}
/**
* List all key-value pairs.
* @param x an object
* @returns [k₀, v₀], [k₁, v₁], ... | [kᵢ, vᵢ] ∈ x
*/ export function entries(x) {
return Object.entries(x);
}
// GENERATE
// --------
/**
* Convert entries to object.
* @param x entries
* @returns x as object
*/ export function fromEntries(x) {
const a = {};
for (const [k, v] of x)a[k] = v;
return a;
}
/**
* Convert lists to object.
* @param x lists, i.e. [keys, values]
* @returns x as object
*/ export function fromLists(x) {
const [ks, vs] = x, a = {};
const iv = vs[Symbol.iterator]();
for (const k of ks)a[k] = iv.next().value;
return a;
}
// COMPARE
// -------
/**
* Compare two objects.
* @param x an object
* @param y another object
* @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) {
fc = fc || COMPARE;
fm = fm || IDENTITY;
const ks = unionKeys(x, y);
for (const k of ks){
if (!has(x, k)) return -1;
if (!has(y, k)) return 1;
const wx = fm(x[k], k, x);
const wy = fm(y[k], k, y);
const c = fc(wx, wy);
if (c !== 0) return c;
}
return 0;
}
/**
* Check if two objects are equal.
* @param x an object
* @param y another object
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns fm(x[kᵢ]) ≈ fm(y[kᵢ]) ∀ kᵢ ∈ x, y
*/ export function isEqual(x, y, fc = null, fm = null) {
return compare(x, y, fc, fm) === 0;
}
// SIZE
// ----
/**
* Get the number of keys in an object.
* @param x an object
* @returns |x|
*/ export function size(x) {
return Object.keys(x).length;
}
export { size as length };
/**
* Check if an object is empty.
* @param x an object
* @returns |x| = 0?
*/ export function isEmpty(x) {
return size(x) === 0;
}
// GET/SET
// -------
/**
* Get value at specified key.
* @param x an object
* @param k key
* @returns x[k]
*/ export function get(x, k) {
return x[k];
}
/**
* Get values at keys.
* @param x an object
* @param ks keys
* @returns [x[k], x[l], ...] | [k, l, ...] = ks
*/ export function getAll(x, ks) {
return ks.map((k)=>x[k]);
}
/**
* Get value at path in a nested object.
* @param x a nested object
* @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) && !BAD_KEYS.includes(k) ? xany[k] : undefined;
return xany;
}
/**
* Check if nested object has a path.
* @param x a nested object
* @param p path
* @returns x[k₀][k₁][...] exists? | [k₀, k₁, ...] = p
*/ export function hasPath(x, p) {
let xany = x;
for (const k of p){
if (!is(xany)) return false;
xany = xany[k];
}
return true;
}
/**
* Set value at specified key.
* @param x an object
* @param k key
* @param v value
* @returns x' | x' = x; x'[k] = v
*/ export function set(x, k, v) {
return set$(Object.assign({}, x), k, v);
}
/**
* Set value at specified key.
* @param x an object (updated)
* @param k key
* @param v value
* @returns x | x[k] = v
*/ export function set$(x, k, v) {
x[k] = v;
return x;
}
/**
* Set value at path in a nested object.
* @param x a nested object (updated)
* @param p path
* @param v value
* @returns x | x[k₀][k₁][...] = v; [k₀, k₁, ...] = p
*/ export function setPath$(x, p, v) {
const y = getPath(x, p.slice(0, -1));
const k = arrayLast(p, "");
if (is(y) && k && !BAD_KEYS.includes(k)) y[k] = v;
return x;
}
/**
* Exchange two values in an object.
* @param x an object
* @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$(Object.assign({}, x), k, l);
}
/**
* Exchange two values in an object.
* @param x an object (updated)
* @param k a key
* @param l another key
* @returns x | x[i] ↔ x[j]
*/ export function swap$(x, k, l) {
const t = x[k];
x[k] = x[l];
x[l] = t;
return x;
}
/**
* Remove an entry from object.
* @param x an object
* @param k key
* @returns x \\: [k]
*/ export function remove(x, k) {
const a = {};
for(const l in x){
if (!has(x, l)) continue;
if (l !== k) a[l] = x[l];
}
return a;
}
/**
* Remove an entry from object.
* @param x an object (updated)
* @param k key
* @returns x = x \\: [k]
*/ export function remove$(x, k) {
delete x[k];
return x;
}
/**
* Remove value at path in a nested object.
* @param x a nested object (updated)
* @param p path
* @returns x = x \\: [k₀][k₁][...] | [k₀, k₁, ...] = p
*/ export function removePath$(x, p) {
const y = getPath(x, p.slice(0, -1));
const k = arrayLast(p, "");
if (is(y) && k) delete y[k];
return x;
}
// PROPERTY
// --------
/**
* Count values which satisfy a test.
* @param x an object
* @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;
for(const k in x){
if (!has(x, k)) continue;
if (ft(x[k], k, x)) ++a;
}
return a;
}
/**
* Count occurrences of values.
* @param x an object
* @param fm map function (v, k, x)
* @returns Map \{value ⇒ count\}
*/ export function countAs(x, fm = null) {
fm = fm || IDENTITY;
const a = new Map();
for(const k in x){
if (!has(x, k)) continue;
const w = fm(x[k], k, x);
const n = a.get(w) || 0;
a.set(w, n + 1);
}
return a;
}
/**
* Find smallest value.
* @param x an object
* @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 an object
* @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 an object
* @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 an object
* @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 a map
* @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 an object
* @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;
let mk, mu, mv;
let nk, nu, nv;
let i = 0;
for(const k in x){
if (!has(x, k)) continue;
const u = x[k], v = fm(u, k, x);
if (i === 0 || fc(v, mv) < 0) {
mk = k;
mu = u;
mv = v;
}
if (i === 0 || fc(v, nv) > 0) {
nk = k;
nu = u;
nv = v;
}
++i;
}
return [
[
mk,
mu
],
[
nk,
nu
]
];
}
// PART
// ----
/**
* Gets first entry from object (default order).
* @param x an object
* @param ed default entry
* @returns [k₀, v₀] if x ≠ Φ else ed | [k₀, v₀] ∈ x
*/ export function head(x, ed = []) {
for(const k in x){
if (!has(x, k)) continue;
return [
k,
x[k]
];
}
return ed;
}
/**
* Get object without its first entry (default order).
* @param x an object
* @returns x \\ \{[k₀, v₀]\} if x ≠ Φ else x | [k₀, v₀] ∈ x
*/ export function tail(x) {
return drop(x, 1);
}
/**
* Keep first n entries only (default order).
* @param x an object
* @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) {
let i = -1;
const a = {};
for(const k in x){
if (!has(x, k)) continue;
if (++i >= n) break;
a[k] = x[k];
}
return a;
}
/**
* Keep first n entries only (default order).
* @param x an object (updated)
* @param n number of entries [1]
* @returns x = \{[k₀, v₀], [k₁, v₁], ...\} | [kᵢ, vᵢ] ∈ x and |\{[k₀, v₀], [k₁, v₁], ...\}| ≤ n
*/ export function take$(x, n = 1) {
let i = -1;
for(const k in x){
if (!has(x, k)) continue;
if (++i >= n) delete x[k];
}
return x;
}
/**
* Remove first n entries (default order).
* @param x an object
* @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) {
let i = -1;
const a = {};
for(const k in x){
if (!has(x, k)) continue;
if (++i >= n) a[k] = x[k];
}
return a;
}
/**
* Remove first n entries (default order).
* @param x an object (updated)
* @param n number of entries [1]
* @returns x = \{[kₙ, vₙ], [kₙ₊₁, vₙ₊₁], ...\} | [kᵢ, vᵢ] ∈ x and |\{[kₙ, vₙ], [kₙ₊₁, vₙ₊₁], ...\}| ≤ max(|x| - n, 0)
*/ export function drop$(x, n = 1) {
let i = -1;
for(const k in x){
if (!has(x, k)) continue;
if (++i >= n) break;
delete x[k];
}
return x;
}
// ARRANGEMENTS
// ------------
/**
* List all possible subsets.
* @param x an object
* @param n number of entries [-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 ks of arraySubsequences(Object.keys(x), n))yield filterAt(x, ks);
}
/**
* Pick an arbitrary key.
* @param x an object
* @param fr random number generator ([0, 1))
* @returns kᵢ | [kᵢ, vᵢ] ∈ x
*/ export function randomKey(x, fr = Math.random) {
return arrayRandomValue(Object.keys(x), fr);
}
export { randomKey as key };
/**
* Pick an arbitrary entry.
* @param x an object
* @param fr random number generator ([0, 1))
* @returns [kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x
` */ export function randomEntry(x, fr = Math.random) {
return arrayRandomValue(Object.entries(x), fr);
}
export { randomEntry as entry };
/**
* Pick an arbitrary subset.
* @param x an object
* @param n number of entries [-1 ⇒ any]
* @param fr random number generator ([0, 1))
* @returns \{[kᵢ, vᵢ], [kⱼ, vⱼ], ...\} | [kᵢ, vᵢ], [kⱼ, vⱼ], ... ∈ x; |\{[kᵢ, vᵢ], [kⱼ, vⱼ], ...\}| = |x| if n<0 else n
*/ export function randomSubset(x, n = -1, fr = Math.random) {
const ks = arrayRandomSubsequence(Object.keys(x), n, fr);
return filterAt(x, ks);
}
export { randomSubset as subset };
// FIND
// ----
/**
* Check if object has a key.
* @param x an object
* @param k search key
* @returns [k, *] ∈ x?
*/ export function has(x, k) {
return Object.prototype.hasOwnProperty.call(x, k);
}
export { has as hasKey };
/**
* Check if object has a value.
* @param x an object
* @param v search value
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns [*, v] ∈ x?
*/ export function hasValue(x, v, fc = null, fm = null) {
return searchValue(x, v, fc, fm) != null;
}
/**
* Check if object has an entry.
* @param x an object
* @param e search entry ([k, v])
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns [k, v] ∈ x? | [k, v] = e
*/ export function hasEntry(x, e, fc = null, fm = null) {
fc = fc || COMPARE;
fm = fm || IDENTITY;
const [k, v] = e;
return has(x, k) && fc(fm(x[k], k, x), v) === 0;
}
/**
* Check if object has a subset.
* @param x an object
* @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) {
fc = fc || COMPARE;
fm = fm || IDENTITY;
for (const k of Object.keys(y)){
if (!has(x, k)) return false;
const wx = fm(x[k], k, x);
const wy = fm(y[k], k, y);
if (fc(wx, wy) !== 0) return false;
}
return true;
}
/**
* Find value of an entry passing a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns v | ft(v) = true; [k, v] ∈ x
*/ export function find(x, ft) {
for (const k of Object.keys(x))if (ft(x[k], k, x)) return x[k];
}
/**
* Find values of entries passing a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns [vₒ, v₁, ...] | ft(vᵢ) = true; [kᵢ, vᵢ] ∈ x
*/ export function findAll(x, ft) {
const a = [];
for (const k of Object.keys(x))if (ft(x[k], k, x)) a.push(x[k]);
return a;
}
/**
* Find key of an entry passing a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns k | ft(x[k]) passes
*/ export function search(x, ft) {
for (const k of Object.keys(x))if (ft(x[k], k, x)) return k;
return null;
}
/**
* Find all keys of entries passing a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns [k₀, k₁, ...] | ft(x[kᵢ]) passes
*/ export function searchAll(x, ft) {
const a = [];
for (const k of Object.keys(x))if (ft(x[k], k, x)) a.push(k);
return a;
}
/**
* Find key with a given value.
* @param x an object
* @param v search value
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns k | fm(x[k]) ≈ fm(v)
*/ export function searchValue(x, v, fc = null, fm = null) {
fc = fc || COMPARE;
fm = fm || IDENTITY;
const w = fm(v, null, null);
for (const k of Object.keys(x)){
const wx = fm(x[k], k, x);
if (fc(wx, w) === 0) return k;
}
return null;
}
/**
* Find keys with a given value.
* @param x an object
* @param v search value
* @param fc compare function (a, b)
* @param fm map function (v, k, x)
* @returns [k₀, k₁, ...] | fm(x[kᵢ]) ≈ fm(v)
*/ export function searchValueAll(x, v, fc = null, fm = null) {
fc = fc || COMPARE;
fm = fm || IDENTITY;
const w = fm(v, null, null), a = [];
for (const k of Object.keys(x)){
const wx = fm(x[k], k, x);
if (fc(wx, w) === 0) a.push(k);
}
return a;
}
// FUNCTIONAL
// ----------
/**
* Call a function for each entry.
* @param x an object
* @param fp called function (v, k, x)
*/ export function forEach(x, fp) {
for(const k in x){
if (!has(x, k)) continue;
fp(x[k], k, x);
}
}
/**
* Check if any value satisfies a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns true if ft(vᵢ) = true for some [kᵢ, vᵢ] ∈ x
*/ export function some(x, ft = null) {
ft = ft || IDENTITY;
for(const k in x){
if (!has(x, k)) continue;
if (ft(x[k], k, x)) return true;
}
return false;
}
/**
* Check if all values satisfy a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns true if ft(vᵢ) = true for all [kᵢ, vᵢ] ∈ x
*/ export function every(x, ft) {
for(const k in x){
if (!has(x, k)) continue;
if (!ft(x[k], k, x)) return false;
}
return true;
}
/**
* Transform values of an object.
* @param x an object
* @param fm map function (v, k, x)
* @returns \{[k₀, fm(v₀)], [k₁, fm(v₁)], ...\} | [kᵢ, vᵢ] ∈ x
*/ export function map(x, fm) {
const a = {};
for(const k in x){
if (!has(x, k)) continue;
a[k] = fm(x[k], k, x);
}
return a;
}
/**
* Transform values of an object.
* @param x an object (updated)
* @param fm map function (v, k, x)
* @returns x = \{[k₀, fm(v₀)], [k₁, fm(v₁)], ...\} | [kᵢ, vᵢ] ∈ x
*/ export function map$(x, fm) {
for(const k in x){
if (!has(x, k)) continue;
x[k] = fm(x[k], k, x);
}
return x;
}
/**
* Reduce values to a single value.
* @param x an object
* @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) {
let init = arguments.length <= 2;
for(const k in x){
if (!has(x, k)) continue;
if (init) {
acc = x[k];
init = false;
} else acc = fr(acc, x[k], k, x);
}
return acc;
}
/**
* Keep entries which pass a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns \{[k₀, v₀], [k₁, v₁], ...\} | ft(vᵢ) = true; [kᵢ, vᵢ] ∈ x
*/ export function filter(x, ft) {
const a = {};
for(const k in x){
if (!has(x, k)) continue;
if (ft(x[k], k, x)) a[k] = x[k];
}
return a;
}
/**
* Keep entries which pass a test.
* @param x an object (updated)
* @param ft test function (v, k, x)
* @returns x = \{[k₀, v₀], [k₁, v₁], ...\} | ft(vᵢ) = true; [kᵢ, vᵢ] ∈ x
*/ export function filter$(x, ft) {
for(const k in x){
if (!has(x, k)) continue;
if (!ft(x[k], k, x)) delete x[k];
}
return x;
}
/**
* Get object with given keys.
* @param x an object
* @param ks keys
* @returns \{[k₀, v₀], [k₁, v₁], ...\} | kᵢ ∈ ks; [kᵢ, vᵢ] ∈ x
*/ export function filterAt(x, ks) {
const a = {};
for (const k of ks)if (has(x, k)) a[k] = x[k];
return a;
}
/**
* Get object with given keys.
* @param x an object (updated)
* @param ks keys
* @returns x = \{[k₀, v₀], [k₁, v₁], ...\} | kᵢ ∈ ks; [kᵢ, vᵢ] ∈ x
*/ export function filterAt$(x, ks) {
for(const k in x){
if (!has(x, k)) continue;
if (!ks.includes(k)) delete x[k];
}
return x;
}
/**
* Discard entries which pass a test.
* @param x an object
* @param ft test function (v, k, x)
* @returns \{[k₀, v₀], [k₁, v₁], ...\} | ft(vᵢ) = false; [kᵢ, vᵢ] ∈ x
*/ export function reject(x, ft) {
const a = {};
for(const k in x){
if (!has(x, k)) continue;
if (!ft(x[k], k, x)) a[k] = x[k];
}
return a;
}
/**
* Discard entries which pass a test.
* @param x an object (updated)
* @param ft test function (v, k, x)
* @returns x = \{[k₀, v₀], [k₁, v₁], ...\} | ft(vᵢ) = false; [kᵢ, vᵢ] ∈ x
*/ export function reject$(x, ft) {
for(const k in x){
if (!has(x, k)) continue;
if (ft(x[k], k, x)) delete x[k];
}
return x;
}
/**
* Get object without given keys.
* @param x an object
* @param ks keys
* @returns \{[k₀, v₀], [k₁, v₁], ...\} | kᵢ ∉ ks; [kᵢ, vᵢ] ∈ x
*/ export function rejectAt(x, ks) {
const a = {};
for(const k in x){
if (!has(x, k)) continue;
if (!ks.includes(k)) a[k] = x[k];
}
return a;
}
/**
* Get object without given keys.
* @param x an object (updated)
* @param ks keys
* @returns x = \{[k₀, v₀], [k₁, v₁], ...\} | kᵢ ∉ ks; [kᵢ, vᵢ] ∈ x
*/ export function rejectAt$(x, ks) {
for(const k in x){
if (!has(x, k)) continue;
if (ks.includes(k)) delete x[k];
}
return x;
}
/**
* Flatten nested object to given depth.
* @param x a nested object
* @param n maximum depth [-1 ⇒ all]
* @param fm map function (v, k, x)
* @param ft test function for flatten (v, k, x)
* @returns flat map
*/ export function flat(x, n = -1, fm = null, ft = null) {
fm = fm || IDENTITY;
ft = ft || is;
return flatTo$({}, x, n, fm, ft);
}
function flatTo$(a, x, dep, fm, ft) {
for(const k in x){
if (!has(x, k)) continue;
const w = fm(x[k], k, x);
if (dep !== 0 && ft(w, k, x)) flatTo$(a, w, dep - 1, fm, ft);
else a[k] = w;
}
return a;
}
/**
* Flatten nested object, using map function.
* @param x a nested object
* @param fm map function (v, k, x)
* @param ft test function (v, k, x)
* @returns flat map
*/ export function flatMap(x, fm = null, ft = null) {
fm = fm || IDENTITY;
ft = ft || is;
const a = {};
for(const k in x){
if (!has(x, k)) continue;
const w = fm(x[k], k, x);
if (ft(w, k, x)) Object.assign(a, w);
else a[k] = w;
}
return a;
}
/**
* Combine matching entries from objects.
* @param xs objects
* @param fm map function (vs, k)
* @param fe end function (dones) [array.some]
* @param vd default value
* @returns \{"k₀": fm([x₀[k₀], x₁[k₀], ...]), "k₁": fm([x₀[k₁], x₁[k₁], ...]), ...\}
*/ export function zip(xs, fm = null, fe = null, vd) {
fm = fm || IDENTITY;
fe = fe || arraySome;
const ks = unionKeys(...xs), a = {};
for (const k of ks){
const ds = xs.map((x)=>!has(x, k));
if (fe(ds)) break;
const vs = xs.map((x)=>!has(x, k) ? vd : x[k]);
a[k] = fm(vs, k, null);
}
return a;
}
// MANIPULATION
// ------------
/**
* Segregate entries by test result.
* @param x an object
* @param ft test function (v, k, x)
* @returns [satisfies, doesnt]
*/ export function partition(x, ft) {
const t = {};
const f = {};
for(const k in x){
if (!has(x, k)) continue;
if (ft(x[k], k, x)) t[k] = x[k];
else f[k] = x[k];
}
return [
t,
f
];
}
/**
* Segregate entries by similarity.
* @param x an object
* @param fm map function (v, k, x)
* @returns Map \{key ⇒ values\}
*/ export function partitionAs(x, fm) {
fm = fm || IDENTITY;
const a = new Map();
for(const k in x){
if (!has(x, k)) continue;
const w = fm(x[k], k, x);
if (!a.has(w)) a.set(w, {});
a.get(w)[k] = x[k];
}
return a;
}
/**
* Break object into chunks of given size.
* @param x an object
* @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 ks = Object.keys(x), a = [];
const I = ks.length;
for(let i = 0; i < I; i += s)a.push(filterAt(x, ks.slice(i, i + n)));
return a;
}
// COMBINE
// -------
/**
* Combine entries from objects, preferring last.
* @param xs objects
* @returns x₀ ∪ x₁ ∪ ... | [x₀, x₁, ...] = xs
*/ export function concat(...xs) {
return Object.assign({}, ...xs);
}
/**
* Combines entries from objects, preferring last.
* @param x an object (updated)
* @param ys other objects
* @returns x = x ∪ y₀ ∪ y₁ ∪ ... | [y₀, y₁, ...] = ys
*/ export function concat$(x, ...ys) {
return Object.assign(x, ...ys);
}
/**
* Join entries together into a string.
* @param x an object
* @param sep separator [,]
* @param asc associator [=]
* @returns "k₀=v₀,k₁=v₁,..." | [kᵢ, vᵢ] ∈ x
*/ export function join(x, sep = ",", asc = "=") {
let a = "";
for(const k in x){
if (!has(x, k)) continue;
a += k + asc + x[k] + sep;
}
return a.slice(0, -sep.length);
}
// SET OPERATIONS
// --------------
/**
* Check if objects have no common keys.
* @param x an object
* @param y another object
* @returns x ∩ y = Φ?
*/ export function isDisjoint(x, y) {
for(const k in x){
if (!has(x, k)) continue;
if (has(y, k)) return false;
}
return true;
}
/**
* Obtain keys present in any object.
* @param xs objects
* @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 in x)if (has(x, k)) a.add(k);
}
return a;
}
/**
* Obtain entries present in any object.
* @param x an object
* @param y another object
* @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) {
return union$(Object.assign({}, x), y, fc);
}
/**
* Obtain entries present in any object.
* @param x an object (updated)
* @param y another object
* @param fc combine function (a, b)
* @returns x = x ∪ y = \{[kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x or [kᵢ, vᵢ] ∈ y\}
*/ export function union$(x, y, fc = null) {
fc = fc || IDENTITY;
for(const k in y){
if (!has(y, k)) continue;
if (!has(x, k)) x[k] = y[k];
else x[k] = fc(x[k], y[k]);
}
return x;
}
/**
* Obtain keys present in all objects.
* @param xs objects
* @returns [k₀, k₁, ...] | [kᵢ, vᵢ] ∈ x₀ ∩ x₁, ...; [x₀, x₁, ...] = xs
*/ export function intersectionKeys(...xs) {
const a = new Set();
if (xs.length === 0) return a;
const x = xs[0], ys = xs.slice(1);
LOOPX: for(const k in x){
if (!has(x, k)) continue;
for (const y of ys)if (!has(y, k)) continue LOOPX;
a.add(k);
}
return a;
}
/**
* Obtain entries present in both objects.
* @param x an object
* @param y another object
* @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) {
fc = fc || IDENTITY;
const a = {};
for(const k in x){
if (!has(x, k)) continue;
if (!has(y, k)) continue;
a[k] = fc(x[k], y[k]);
}
return a;
}
/**
* Obtain entries present in both objects.
* @param x an object (updated)
* @param y another object
* @param fc combine function (a, b)
* @returns x = x ∩ y = \{[kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x and [kᵢ, vᵢ] ∈ y\}
*/ export function intersection$(x, y, fc = null) {
fc = fc || IDENTITY;
for(const k in x){
if (!has(x, k)) continue;
if (!has(y, k)) delete x[k];
else x[k] = fc(x[k], y[k]);
}
return x;
}
/**
* Obtain entries not present in another object.
* @param x an object
* @param y another object
* @returns x - y = \{[kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x, [kᵢ, *] ∉ y\}
*/ export function difference(x, y) {
const a = {};
for(const k in x){
if (!has(x, k)) continue;
if (!has(y, k)) a[k] = x[k];
}
return a;
}
/**
* Obtain entries not present in another object.
* @param x an object (updated)
* @param y another object
* @returns x = x - y = \{[kᵢ, vᵢ] | [kᵢ, vᵢ] ∈ x, [kᵢ, *] ∉ y\}
*/ export function difference$(x, y) {
for(const k in y){
if (!has(y, k)) continue;
if (has(x, k)) delete x[k];
}
return x;
}
/**
* Obtain entries not present in both objects.
* @param x an object
* @param y another object
* @returns x-y ∪ y-x
*/ export function symmetricDifference(x, y) {
const a = {};
for (const k of unionKeys(x, y)){
const xk = has(x, k);
const yk = has(y, k);
if (xk && !yk) a[k] = x[k];
else if (!xk && yk) a[k] = y[k];
}
return a;
}
/**
* Obtain entries not present in both objects.
* @param x an object (updated)
* @param y another object
* @returns x = x-y ∪ y-x
*/ export function symmetricDifference$(x, y) {
for(const k in y){
if (!has(y, k)) continue;
if (has(x, k)) delete x[k];
else x[k] = y[k];
}
return x;
}
/**
* List cartesian product of objects.
* @param xs objects
* @param fm map function (vs)
* @returns x₀ × x₁ × ... = \{\{[k₀, v₀], [k₁, v₁], ...\} | [k₀, v₀] ∈ x₀, [k₁, v₁] ∈ x₁, ...]\}
*/ export function* cartesianProduct(xs, fm = null) {
fm = fm || IDENTITY;
const XS = xs.length;
const kx = xs.map((x)=>Object.keys(x));
const ls = kx.map((ks)=>ks.length);
const is = kx.map((_ks)=>0);
while(true){
const a = {};
for(let n = 0; n < XS; ++n){
const i = is[n], x = xs[n];
const ks = kx[n], k = ks[i];
a[k] = x[k];
}
yield fm(a, null, null);
let r = XS - 1;
for(; r >= 0; --r){
if (++is[r] < ls[r]) break;
is[r] = 0;
}
if (r < 0) break;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9leHRyYS1vYmplY3QvZXh0cmEtb2JqZWN0L2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIElERU5USVRZLFxuICBDT01QQVJFLFxufSBmcm9tIFwiQG5vZGVmL2V4dHJhLWZ1bmN0aW9uXCI7XG5pbXBvcnQge1xuICBsYXN0ICAgICAgICAgICAgICBhcyBhcnJheUxhc3QsXG4gIHNvbWUgICAgICAgICAgICAgIGFzIGFycmF5U29tZSxcbiAgc3Vic2VxdWVuY2VzICAgICAgYXMgYXJyYXlTdWJzZXF1ZW5jZXMsXG4gIHJhbmRvbVZhbHVlICAgICAgIGFzIGFycmF5UmFuZG9tVmFsdWUsXG4gIHJhbmRvbVN1YnNlcXVlbmNlIGFzIGFycmF5UmFuZG9tU3Vic2VxdWVuY2UsXG59IGZyb20gXCJAbm9kZWYvZXh0cmEtYXJyYXlcIjtcblxuLy8gLSBodHRwczovL3d3dy5tZWFzdXJldGhhdC5uZXQvQmVuY2htYXJrcy9TaG93LzE5ODYzLzAvb2JqZWN0LWl0ZXJhdGUta2V5c1xuXG5cblxuXG4vLyBUWVBFU1xuLy8gPT09PT09XG5cbi8qKiBBIGRpY3Rpb25hcnkgaXMgYSBtYXBwaW5nIG9mIHN0cmluZyBrZXlzIHRvIHVua25vd24gdmFsdWVzLiAqL1xuZXhwb3J0IHR5cGUgRGljdGlvbmFyeSA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuZXhwb3J0IHR5cGUge0RpY3Rpb25hcnkgYXMgRGljdH07XG5cblxuLyoqIEVudHJpZXMgaXMgYSBsaXN0IG9mIGtleS12YWx1ZSBwYWlycywgd2l0aCB1bmlxdWUga2V5cyAoaW5kaWNlcykuICovXG5leHBvcnQgdHlwZSBFbnRyaWVzID0gSXRlcmFibGU8W3N0cmluZywgdW5rbm93bl0+O1xuXG5cbi8qKiBMaXN0cyBpcyBhIHBhaXIgb2Yga2V5IGxpc3QgYW5kIHZhbHVlIGxpc3QsIHdpdGggdW5pcXVlIGtleXMgKGluZGljZXMpLiAqL1xuZXhwb3J0IHR5cGUgTGlzdHMgPSBbSXRlcmFibGU8c3RyaW5nPiwgSXRlcmFibGU8dW5rbm93bj5dO1xuXG5cbi8qKlxuICogSGFuZGxlIHJlYWRpbmcgb2YgYSBzaW5nbGUgdmFsdWUuXG4gKiBAcmV0dXJucyB2YWx1ZVxuICovXG5leHBvcnQgdHlwZSBSZWFkRnVuY3Rpb248VD4gPSAoKSA9PiBUO1xuXG5cbi8qKlxuICogSGFuZGxlIGNvbWJpbmluZyBvZiB0d28gdmFsdWVzLlxuICogQHBhcmFtIGEgYSB2YWx1ZVxuICogQHBhcmFtIGIgYW5vdGhlciB2YWx1ZVxuICogQHJldHVybnMgY29tYmluZWQgdmFsdWVcbiAqL1xuZXhwb3J0IHR5cGUgQ29tYmluZUZ1bmN0aW9uID0gKGE6IHVua25vd24sIGI6IHVua25vd24pID0+IHVua25vd247XG5cblxuLyoqXG4gKiBIYW5kbGUgY29tcGFyaXNvbiBvZiB0d28gdmFsdWVzLlxuICogQHBhcmFtIGEgYSB2YWx1ZVxuICogQHBhcmFtIGIgYW5vdGhlciB2YWx1ZVxuICogQHJldHVybnMgYTxiOiAtdmUsIGE9YjogMCwgYT5iOiArdmVcbiAqL1xuZXhwb3J0IHR5cGUgQ29tcGFyZUZ1bmN0aW9uID0gKGE6IHVua25vd24sIGI6IHVua25vd24pID0+IG51bWJlcjtcblxuXG4vKipcbiAqIEhhbmRsZSBwcm9jZXNzaW5nIG9mIHZhbHVlcyBpbiBhbiBvYmplY3QuXG4gKiBAcGFyYW0gdiB2YWx1ZSBpbiBvYmplY3RcbiAqIEBwYXJhbSBrIGtleSBvZiB2YWx1ZSBpbiBvYmplY3RcbiAqIEBwYXJhbSB4IG9iamVjdCBjb250YWluaW5nIHRoZSB2YWx1ZVxuICovXG5leHBvcnQgdHlwZSBQcm9jZXNzRnVuY3Rpb24gPSAodjogdW5rbm93biwgazogc3RyaW5nLCB4OiBEaWN0aW9uYXJ5KSA9PiB2b2lkO1xuXG5cbi8qKlxuICogSGFuZGxlIHNlbGVjdGlvbiBvZiBlbnRyaWVzIGluIGFuIG9iamVjdC5cbiAqIEBwYXJhbSB2IHZhbHVlIGluIG9iamVjdFxuICogQHBhcmFtIGsga2V5IG9mIHZhbHVlIGluIG9iamVjdFxuICogQHBhcmFtIHggb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHZhbHVlXG4gKiBAcmV0dXJucyBzZWxlY3RlZD9cbiAqL1xuZXhwb3J0IHR5cGUgVGVzdEZ1bmN0aW9uID0gKHY6IHVua25vd24sIGs6IHN0cmluZywgeDogRGljdGlvbmFyeSkgPT4gYm9vbGVhbjtcblxuXG4vKipcbiAqIEhhbmRsZSB0cmFuc2Zvcm1hdGlvbiBvZiBhIHZhbHVlIHRvIGFub3RoZXIuXG4gKiBAcGFyYW0gdiB2YWx1ZSBpbiBvYmplY3RcbiAqIEBwYXJhbSBrIGtleSBvZiB2YWx1ZSBpbiBvYmplY3RcbiAqIEBwYXJhbSB4IG9iamVjdCBjb250YWluaW5nIHRoZSB2YWx1ZVxuICogQHJldHVybnMgdHJhbnNmb3JtZWQgdmFsdWVcbiAqL1xuZXhwb3J0IHR5cGUgTWFwRnVuY3Rpb24gPSAodjogdW5rbm93biwgazogc3RyaW5nLCB4OiBEaWN0aW9uYXJ5IHwgbnVsbCkgPT4gdW5rbm93bjtcblxuXG4vKipcbiAqIEhhbmRsZSByZWR1Y3Rpb24gb2YgbXVsdGlwbGUgdmFsdWVzIGludG8gYSBzaW5nbGUgdmFsdWUuXG4gKiBAcGFyYW0gYWNjIGFjY3VtdWxhdG9yICh0ZW1wb3JhcnkgcmVzdWx0KVxuICogQHBhcmFtIHYgdmFsdWUgaW4gb2JqZWN0XG4gKiBAcGFyYW0gayBrZXkgb2YgdmFsdWUgaW4gb2JqZWN0XG4gKiBAcGFyYW0geCBvYmplY3QgY29udGFpbmluZyB0aGUgdmFsdWVcbiAqIEByZXR1cm5zIHJlZHVjZWQgdmFsdWVcbiAqL1xuZXhwb3J0IHR5cGUgUmVkdWNlRnVuY3Rpb24gPSAoYWNjOiB1bmtub3duLCB2OiB1bmtub3duLCBrOiBzdHJpbmcsIHg6IERpY3Rpb25hcnkpID0+IHVua25vd247XG5cblxuLyoqXG4gKiBIYW5kbGUgZW5kaW5nIG9mIGEgY29tYmluZWQgb2JqZWN0LlxuICogQHBhcmFtIGRvbmVzIGnhtZfKsCBvYmplY3QgZG9uZT9cbiAqIEByZXR1cm5zIGNvbWJpbmVkIG9iamVjdCBkb25lP1xuICovXG5leHBvcnQgdHlwZSBFbmRGdW5jdGlvbiA9IChkb25lczogYm9vbGVhbltdKSA9PiBib29sZWFuO1xuXG5cblxuXG4vLyBDT05TVEFOVFNcbi8vID09PT09PT09PVxuXG4vKiogWW91LUtub3ctV2hvLiAqL1xuY29uc3QgQkFEX0tFWVMgPSBbXCJfX3Byb3RvX19cIiwgXCJwcm90b3R5cGVcIiwgXCJjb25zdHJ1Y3RvclwiXTtcblxuXG5cblxuLy8gTUVUSE9EU1xuLy8gPT09PT09PVxuXG4vLyBBQk9VVFxuLy8gLS0tLS1cblxuLyoqXG4gKiBDaGVjayBpZiB2YWx1ZSBpcyBhIGRpY3Rpb25hcnkuXG4gKiBAcGFyYW0gdiBhIHZhbHVlXG4gKiBAcmV0dXJucyB2IGlzIGEgZGljdGlvbmFyeT9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzKHY6IHVua25vd24pOiB2IGlzIERpY3Rpb25hcnkge1xuICByZXR1cm4gdHlwZW9mIHY9PT1cIm9iamVjdFwiO1xufVxuXG5cbi8qKlxuICogTGlzdCBhbGwga2V5cy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHJldHVybnMga+KCgCwga+KCgSwgLi4uIHwgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBrZXlzKHg6IERpY3Rpb25hcnkpOiBJdGVyYWJsZTxzdHJpbmc+IHtcbiAgcmV0dXJuIE9iamVjdC5rZXlzKHgpO1xufVxuXG5cbi8qKlxuICogTGlzdCBhbGwgdmFsdWVzLlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcmV0dXJucyB24oKALCB24oKBLCAuLi4gfCBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbHVlcyh4OiBEaWN0aW9uYXJ5KTogSXRlcmFibGU8dW5rbm93bj4ge1xuICByZXR1cm4gT2JqZWN0LnZhbHVlcyh4KTtcbn1cblxuXG4vKipcbiAqIExpc3QgYWxsIGtleS12YWx1ZSBwYWlycy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHJldHVybnMgW2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLiB8IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gZW50cmllcyh4OiBEaWN0aW9uYXJ5KTogRW50cmllcyB7XG4gIHJldHVybiBPYmplY3QuZW50cmllcyh4KTtcbn1cblxuXG5cblxuLy8gR0VORVJBVEVcbi8vIC0tLS0tLS0tXG5cbi8qKlxuICogQ29udmVydCBlbnRyaWVzIHRvIG9iamVjdC5cbiAqIEBwYXJhbSB4IGVudHJpZXNcbiAqIEByZXR1cm5zIHggYXMgb2JqZWN0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tRW50cmllcyh4OiBFbnRyaWVzKTogRGljdGlvbmFyeSB7XG4gIGNvbnN0IGE6IERpY3Rpb25hcnkgPSB7fTtcbiAgZm9yIChjb25zdCBbaywgdl0gb2YgeClcbiAgICBhW2tdID0gdjtcbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBDb252ZXJ0IGxpc3RzIHRvIG9iamVjdC5cbiAqIEBwYXJhbSB4IGxpc3RzLCBpLmUuIFtrZXlzLCB2YWx1ZXNdXG4gKiBAcmV0dXJucyB4IGFzIG9iamVjdFxuICovXG5leHBvcnQgZnVuY3Rpb24gZnJvbUxpc3RzKHg6IExpc3RzKTogRGljdGlvbmFyeSB7XG4gIGNvbnN0IFtrcywgdnNdID0geCwgYTogRGljdGlvbmFyeSA9IHt9O1xuICBjb25zdCBpdiA9IHZzW1N5bWJvbC5pdGVyYXRvcl0oKTtcbiAgZm9yIChjb25zdCBrIG9mIGtzKVxuICAgIGFba10gPSBpdi5uZXh0KCkudmFsdWU7XG4gIHJldHVybiBhO1xufVxuXG5cblxuXG4vLyBDT01QQVJFXG4vLyAtLS0tLS0tXG5cbi8qKlxuICogQ29tcGFyZSB0d28gb2JqZWN0cy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIHkgYW5vdGhlciBvYmplY3RcbiAqIEBwYXJhbSBmYyBjb21wYXJlIGZ1bmN0aW9uIChhLCBiKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIHg9eTogMCwgb3RoZXJ3aXNlOiAtdmUvK3ZlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wYXJlKHg6IERpY3Rpb25hcnksIHk6IERpY3Rpb25hcnksIGZjOiBDb21wYXJlRnVuY3Rpb24gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbiB8IG51bGw9bnVsbCk6IG51bWJlciB7XG4gIGZjID0gZmMgfHwgQ09NUEFSRTtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgY29uc3Qga3MgPSB1bmlvbktleXMoeCwgeSk7XG4gIGZvciAoY29uc3QgayBvZiBrcykge1xuICAgIGlmICghaGFzKHgsIGspKSByZXR1cm4gLTE7XG4gICAgaWYgKCFoYXMoeSwgaykpIHJldHVybiAxO1xuICAgIGNvbnN0IHd4ID0gZm0oeFtrXSwgaywgeCk7XG4gICAgY29uc3Qgd3kgPSBmbSh5W2tdLCBrLCB5KTtcbiAgICBjb25zdCBjICA9IGZjKHd4LCB3eSk7XG4gICAgaWYgKGMhPT0wKSByZXR1cm4gYztcbiAgfVxuICByZXR1cm4gMDtcbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIHR3byBvYmplY3RzIGFyZSBlcXVhbC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIHkgYW5vdGhlciBvYmplY3RcbiAqIEBwYXJhbSBmYyBjb21wYXJlIGZ1bmN0aW9uIChhLCBiKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIGZtKHhba+G1ol0pIOKJiCBmbSh5W2vhtaJdKSDiiIAga+G1oiDiiIggeCwgeVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNFcXVhbCh4OiBEaWN0aW9uYXJ5LCB5OiBEaWN0aW9uYXJ5LCBmYzogQ29tcGFyZUZ1bmN0aW9uIHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwpOiBib29sZWFuIHtcbiAgcmV0dXJuIGNvbXBhcmUoeCwgeSwgZmMsIGZtKT09PTA7XG59XG5cblxuXG5cbi8vIFNJWkVcbi8vIC0tLS1cblxuLyoqXG4gKiBHZXQgdGhlIG51bWJlciBvZiBrZXlzIGluIGFuIG9iamVjdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHJldHVybnMgfHh8XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzaXplKHg6IERpY3Rpb25hcnkpOiBudW1iZXIge1xuICByZXR1cm4gT2JqZWN0LmtleXMoeCkubGVuZ3RoO1xufVxuZXhwb3J0IHtzaXplIGFzIGxlbmd0aH07XG5cblxuLyoqXG4gKiBDaGVjayBpZiBhbiBvYmplY3QgaXMgZW1wdHkuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEByZXR1cm5zIHx4fCA9IDA/XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0VtcHR5KHg6IERpY3Rpb25hcnkpOiBib29sZWFuIHtcbiAgcmV0dXJuIHNpemUoeCk9PT0wO1xufVxuXG5cblxuXG4vLyBHRVQvU0VUXG4vLyAtLS0tLS0tXG5cbi8qKlxuICogR2V0IHZhbHVlIGF0IHNwZWNpZmllZCBrZXkuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBrIGtleVxuICogQHJldHVybnMgeFtrXVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0KHg6IERpY3Rpb25hcnksIGs6IHN0cmluZyk6IHVua25vd24ge1xuICByZXR1cm4geFtrXTtcbn1cblxuXG4vKipcbiAqIEdldCB2YWx1ZXMgYXQga2V5cy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGtzIGtleXNcbiAqIEByZXR1cm5zIFt4W2tdLCB4W2xdLCAuLi5dIHwgW2ssIGwsIC4uLl0gPSBrc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWxsKHg6IERpY3Rpb25hcnksIGtzOiBzdHJpbmdbXSk6IHVua25vd25bXSB7XG4gIHJldHVybiBrcy5tYXAoayA9PiB4W2tdKTtcbn1cblxuXG4vKipcbiAqIEdldCB2YWx1ZSBhdCBwYXRoIGluIGEgbmVzdGVkIG9iamVjdC5cbiAqIEBwYXJhbSB4IGEgbmVzdGVkIG9iamVjdFxuICogQHBhcmFtIHAgcGF0aFxuICogQHJldHVybnMgeFtr4oKAXVtr4oKBXVsuLi5dIHwgW2vigoAsIGvigoEsIC4uLl0gPSBwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRQYXRoKHg6IERpY3Rpb25hcnksIHA6IHN0cmluZ1tdKTogdW5rbm93biB7XG4gIGxldCB4YW55OiB1bmtub3duID0geDtcbiAgZm9yIChjb25zdCBrIG9mIHApXG4gICAgeGFueSA9IGlzKHhhbnkpICYmICFCQURfS0VZUy5pbmNsdWRlcyhrKT8geGFueVtrXSA6IHVuZGVmaW5lZDtcbiAgcmV0dXJuIHhhbnk7XG59XG5cblxuLyoqXG4gKiBDaGVjayBpZiBuZXN0ZWQgb2JqZWN0IGhhcyBhIHBhdGguXG4gKiBAcGFyYW0geCBhIG5lc3RlZCBvYmplY3RcbiAqIEBwYXJhbSBwIHBhdGhcbiAqIEByZXR1cm5zIHhba+KCgF1ba+KCgV1bLi4uXSBleGlzdHM/IHwgW2vigoAsIGvigoEsIC4uLl0gPSBwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNQYXRoKHg6IERpY3Rpb25hcnksIHA6IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gIGxldCB4YW55OiB1bmtub3duID0geDtcbiAgZm9yIChjb25zdCBrIG9mIHApIHtcbiAgICBpZiAoIWlzKHhhbnkpKSByZXR1cm4gZmFsc2U7XG4gICAgeGFueSA9IHhhbnlba107XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5cblxuLyoqXG4gKiBTZXQgdmFsdWUgYXQgc3BlY2lmaWVkIGtleS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGsga2V5XG4gKiBAcGFyYW0gdiB2YWx1ZVxuICogQHJldHVybnMgeCcgfCB4JyA9IHg7IHgnW2tdID0gdlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0KHg6IERpY3Rpb25hcnksIGs6IHN0cmluZywgdjogdW5rbm93bik6IERpY3Rpb25hcnkge1xuICByZXR1cm4gc2V0JChPYmplY3QuYXNzaWduKHt9LCB4KSwgaywgdik7XG59XG5cblxuLyoqXG4gKiBTZXQgdmFsdWUgYXQgc3BlY2lmaWVkIGtleS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSBrIGtleVxuICogQHBhcmFtIHYgdmFsdWVcbiAqIEByZXR1cm5zIHggfCB4W2tdID0gdlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0JCh4OiBEaWN0aW9uYXJ5LCBrOiBzdHJpbmcsIHY6IHVua25vd24pOiBEaWN0aW9uYXJ5IHtcbiAgeFtrXSA9IHY7XG4gIHJldHVybiB4O1xufVxuXG5cbi8qKlxuICogU2V0IHZhbHVlIGF0IHBhdGggaW4gYSBuZXN0ZWQgb2JqZWN0LlxuICogQHBhcmFtIHggYSBuZXN0ZWQgb2JqZWN0ICh1cGRhdGVkKVxuICogQHBhcmFtIHAgcGF0aFxuICogQHBhcmFtIHYgdmFsdWVcbiAqIEByZXR1cm5zIHggfCB4W2vigoBdW2vigoFdWy4uLl0gPSB2OyBba+KCgCwga+KCgSwgLi4uXSA9IHBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldFBhdGgkKHg6IERpY3Rpb25hcnksIHA6IHN0cmluZ1tdLCB2OiB1bmtub3duKTogRGljdGlvbmFyeSB7XG4gIGNvbnN0IHkgPSBnZXRQYXRoKHgsIHAuc2xpY2UoMCwgLTEpKTtcbiAgY29uc3QgayA9IGFycmF5TGFzdChwLCBcIlwiKTtcbiAgaWYgKGlzKHkpICYmIGsgJiYgIUJBRF9LRVlTLmluY2x1ZGVzKGspKSB5W2tdID0gdjtcbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBFeGNoYW5nZSB0d28gdmFsdWVzIGluIGFuIG9iamVjdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGsgYSBrZXlcbiAqIEBwYXJhbSBsIGFub3RoZXIga2V5XG4gKiBAcmV0dXJucyB4JyB8IHgnID0geDsgeCdba10gPSB4W2xdOyB4J1tsXSA9IHhba11cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN3YXAoeDogRGljdGlvbmFyeSwgazogc3RyaW5nLCBsOiBzdHJpbmcpOiBEaWN0aW9uYXJ5IHtcbiAgcmV0dXJuIHN3YXAkKE9iamVjdC5hc3NpZ24oe30sIHgpLCBrLCBsKTtcbn1cblxuXG4vKipcbiAqIEV4Y2hhbmdlIHR3byB2YWx1ZXMgaW4gYW4gb2JqZWN0LlxuICogQHBhcmFtIHggYW4gb2JqZWN0ICh1cGRhdGVkKVxuICogQHBhcmFtIGsgYSBrZXlcbiAqIEBwYXJhbSBsIGFub3RoZXIga2V5XG4gKiBAcmV0dXJucyB4IHwgeFtpXSDihpQgeFtqXVxuICovXG5leHBvcnQgZnVuY3Rpb24gc3dhcCQoeDogRGljdGlvbmFyeSwgazogc3RyaW5nLCBsOiBzdHJpbmcpOiBEaWN0aW9uYXJ5IHtcbiAgY29uc3QgdCA9IHhba107XG4gIHhba10gPSB4W2xdO1xuICB4W2xdID0gdDtcbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBSZW1vdmUgYW4gZW50cnkgZnJvbSBvYmplY3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBrIGtleVxuICogQHJldHVybnMgeCBcXFxcOiBba11cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZSh4OiBEaWN0aW9uYXJ5LCBrOiBzdHJpbmcpOiBEaWN0aW9uYXJ5IHtcbiAgY29uc3QgYTogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGwgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGwpKSBjb250aW51ZTtcbiAgICBpZiAobCE9PWspIGFbbF0gPSB4W2xdO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlIGFuIGVudHJ5IGZyb20gb2JqZWN0LlxuICogQHBhcmFtIHggYW4gb2JqZWN0ICh1cGRhdGVkKVxuICogQHBhcmFtIGsga2V5XG4gKiBAcmV0dXJucyB4ID0geCBcXFxcOiBba11cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZSQoeDogRGljdGlvbmFyeSwgazogc3RyaW5nKTogRGljdGlvbmFyeSB7XG4gIGRlbGV0ZSB4W2tdO1xuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIFJlbW92ZSB2YWx1ZSBhdCBwYXRoIGluIGEgbmVzdGVkIG9iamVjdC5cbiAqIEBwYXJhbSB4IGEgbmVzdGVkIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSBwIHBhdGhcbiAqIEByZXR1cm5zIHggPSB4IFxcXFw6IFtr4oKAXVtr4oKBXVsuLi5dIHwgW2vigoAsIGvigoEsIC4uLl0gPSBwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZW1vdmVQYXRoJCh4OiBEaWN0aW9uYXJ5LCBwOiBzdHJpbmdbXSk6IERpY3Rpb25hcnkge1xuICBjb25zdCB5ID0gZ2V0UGF0aCh4LCBwLnNsaWNlKDAsIC0xKSk7XG4gIGNvbnN0IGsgPSBhcnJheUxhc3QocCwgXCJcIik7XG4gIGlmIChpcyh5KSAmJiBrKSBkZWxldGUgeVtrXTtcbiAgcmV0dXJuIHg7XG59XG5cblxuXG5cbi8vIFBST1BFUlRZXG4vLyAtLS0tLS0tLVxuXG4vKipcbiAqIENvdW50IHZhbHVlcyB3aGljaCBzYXRpc2Z5IGEgdGVzdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyDOo3ThtaIgfCB04bWiID0gMSBpZiBmdCh24bWiKSBlbHNlIDA7IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gY291bnQoeDogRGljdGlvbmFyeSwgZnQ6IFRlc3RGdW5jdGlvbik6IG51bWJlciB7XG4gIGxldCBhID0gMDtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKGZ0KHhba10sIGssIHgpKSArK2E7XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBDb3VudCBvY2N1cnJlbmNlcyBvZiB2YWx1ZXMuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBNYXAgXFx7dmFsdWUg4oeSIGNvdW50XFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb3VudEFzKHg6IERpY3Rpb25hcnksIGZtOiBNYXBGdW5jdGlvbiB8IG51bGw9bnVsbCk6IE1hcDx1bmtub3duLCBudW1iZXI+IHtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgY29uc3QgYSAgPSBuZXcgTWFwKCk7XG4gIGZvciAoY29uc3QgayBpbiB4KSB7XG4gICAgaWYgKCFoYXMoeCwgaykpIGNvbnRpbnVlO1xuICAgIGNvbnN0IHcgPSBmbSh4W2tdLCBrLCB4KTtcbiAgICBjb25zdCBuID0gYS5nZXQodykgfHwgMDtcbiAgICBhLnNldCh3LCBuKzEpO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogRmluZCBzbWFsbGVzdCB2YWx1ZS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgdiB8IHYg4omkIHbhtaI7IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gbWluKHg6IERpY3Rpb25hcnksIGZjOiBDb21wYXJlRnVuY3Rpb24gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbiB8IG51bGw9bnVsbCk6IHVua25vd24ge1xuICByZXR1cm4gcmFuZ2VFbnRyaWVzKHgsIGZjLCBmbSlbMF1bMV07XG59XG5cblxuLyoqXG4gKiBGaW5kIHNtYWxsZXN0IGVudHJ5LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBbbWluX2tleSwgbWluX3ZhbHVlXVxuICovXG5leHBvcnQgZnVuY3Rpb24gbWluRW50cnkoeDogRGljdGlvbmFyeSwgZmM6IENvbXBhcmVGdW5jdGlvbiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uIHwgbnVsbD1udWxsKTogW3N0cmluZywgdW5rbm93bl0ge1xuICByZXR1cm4gcmFuZ2VFbnRyaWVzKHgsIGZjLCBmbSlbMF07XG59XG5cblxuLyoqXG4gKiBGaW5kIGxhcmdlc3QgdmFsdWUuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmYyBjb21wYXJlIGZ1bmN0aW9uIChhLCBiKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIHYgfCB2IOKJpSB24bWiOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1heCh4OiBEaWN0aW9uYXJ5LCBmYzogQ29tcGFyZUZ1bmN0aW9uIHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwpOiB1bmtub3duIHtcbiAgcmV0dXJuIHJhbmdlRW50cmllcyh4LCBmYywgZm0pWzFdWzFdO1xufVxuXG5cbi8qKlxuICogRmluZCBsYXJnZXN0IGVudHJ5LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBbbWF4X2tleSwgbWF4X3ZhbHVlXVxuICovXG5leHBvcnQgZnVuY3Rpb24gbWF4RW50cnkoeDogRGljdGlvbmFyeSwgZmM6IENvbXBhcmVGdW5jdGlvbiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uIHwgbnVsbD1udWxsKTogW3N0cmluZywgdW5rbm93bl0ge1xuICByZXR1cm4gcmFuZ2VFbnRyaWVzKHgsIGZjLCBmbSlbMV07XG59XG5cblxuLyoqXG4gKiBGaW5kIHNtYWxsZXN0IGFuZCBsYXJnZXN0IHZhbHVlcy5cbiAqIEBwYXJhbSB4IGEgbWFwXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBbbWluX3ZhbHVlLCBtYXhfdmFsdWVdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByYW5nZSh4OiBEaWN0aW9uYXJ5LCBmYzogQ29tcGFyZUZ1bmN0aW9uIHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwpOiBbdW5rbm93biwgdW5rbm93bl0ge1xuICBjb25zdCBbYSwgYl0gPSByYW5nZUVudHJpZXMoeCwgZmMsIGZtKTtcbiAgcmV0dXJuIFthWzFdLCBiWzFdXTtcbn1cblxuXG4vKipcbiAqIEZpbmQgc21hbGxlc3QgYW5kIGxhcmdlc3QgZW50cmllcy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgW21pbl9lbnRyeSwgbWF4X2VudHJ5XVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmFuZ2VFbnRyaWVzKHg6IERpY3Rpb25hcnksIGZjOiBDb21wYXJlRnVuY3Rpb24gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbiB8IG51bGw9bnVsbCk6IFtbc3RyaW5nLCB1bmtub3duXSwgW3N0cmluZywgdW5rbm93bl1dIHtcbiAgZmMgPSBmYyB8fCBDT01QQVJFO1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBsZXQgbWs6IHN0cmluZyB8IHVuZGVmaW5lZCwgbXU6IHVua25vd24sIG12OiB1bmtub3duO1xuICBsZXQgbms6IHN0cmluZyB8IHVuZGVmaW5lZCwgbnU6IHVua25vd24sIG52OiB1bmtub3duO1xuICBsZXQgaSA9IDA7XG4gIGZvciAoY29uc3QgayBpbiB4KSB7XG4gICAgaWYgKCFoYXMoeCwgaykpIGNvbnRpbnVlO1xuICAgIGNvbnN0IHUgPSB4W2tdLCB2ID0gZm0odSwgaywgeCk7XG4gICAgaWYgKGk9PT0wIHx8IGZjKHYsIG12KTwwKSB7IG1rID0gazsgbXUgPSB1OyBtdiA9IHY7IH1cbiAgICBpZiAoaT09PTAgfHwgZmModiwgbnYpPjApIHsgbmsgPSBrOyBudSA9IHU7IG52ID0gdjsgfVxuICAgICsraTtcbiAgfVxuICByZXR1cm4gW1ttayBhcyBzdHJpbmcsIG11XSwgW25rIGFzIHN0cmluZywgbnVdXTtcbn1cblxuXG5cblxuLy8gUEFSVFxuLy8gLS0tLVxuXG4vKipcbiAqIEdldHMgZmlyc3QgZW50cnkgZnJvbSBvYmplY3QgKGRlZmF1bHQgb3JkZXIpLlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZWQgZGVmYXVsdCBlbnRyeVxuICogQHJldHVybnMgW2vigoAsIHbigoBdIGlmIHgg4omgIM6mIGVsc2UgZWQgfCBba+KCgCwgduKCgF0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhlYWQoeDogRGljdGlvbmFyeSwgZWQ6IFtzdHJpbmcsIHVua25vd25dPVtdIGFzIHVua25vd24gYXMgW3N0cmluZywgdW5rbm93bl0pOiBbc3RyaW5nLCB1bmtub3duXSB7XG4gIGZvciAoY29uc3QgayBpbiB4KSB7XG4gICAgaWYgKCFoYXMoeCwgaykpIGNvbnRpbnVlO1xuICAgIHJldHVybiBbaywgeFtrXV07XG4gIH1cbiAgcmV0dXJuIGVkO1xufVxuXG5cbi8qKlxuICogR2V0IG9iamVjdCB3aXRob3V0IGl0cyBmaXJzdCBlbnRyeSAoZGVmYXVsdCBvcmRlcikuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEByZXR1cm5zIHggXFxcXCBcXHtba+KCgCwgduKCgF1cXH0gaWYgeCDiiaAgzqYgZWxzZSB4IHwgW2vigoAsIHbigoBdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0YWlsKHg6IERpY3Rpb25hcnkpOiBEaWN0aW9uYXJ5IHtcbiAgcmV0dXJuIGRyb3AoeCwgMSk7XG59XG5cblxuLyoqXG4gKiBLZWVwIGZpcnN0IG4gZW50cmllcyBvbmx5IChkZWZhdWx0IG9yZGVyKS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIG4gbnVtYmVyIG9mIGVudHJpZXMgWzFdXG4gKiBAcmV0dXJucyBcXHtba+KCgCwgduKCgF0sIFtr4oKBLCB24oKBXSwgLi4uXFx9IHwgW2vhtaIsIHbhtaJdIOKIiCB4IGFuZCB8XFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfXwg4omkIG5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRha2UoeDogRGljdGlvbmFyeSwgbjogbnVtYmVyPTEpOiBEaWN0aW9uYXJ5IHtcbiAgbGV0IGkgPSAtMTsgY29uc3QgYTogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoKytpPj1uKSBicmVhaztcbiAgICBhW2tdID0geFtrXTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEtlZXAgZmlyc3QgbiBlbnRyaWVzIG9ubHkgKGRlZmF1bHQgb3JkZXIpLlxuICogQHBhcmFtIHggYW4gb2JqZWN0ICh1cGRhdGVkKVxuICogQHBhcmFtIG4gbnVtYmVyIG9mIGVudHJpZXMgWzFdXG4gKiBAcmV0dXJucyB4ID0gXFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfSB8IFtr4bWiLCB24bWiXSDiiIggeCBhbmQgfFxce1tr4oKALCB24oKAXSwgW2vigoEsIHbigoFdLCAuLi5cXH18IOKJpCBuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0YWtlJCh4OiBEaWN0aW9uYXJ5LCBuOiBudW1iZXI9MSk6IERpY3Rpb25hcnkge1xuICBsZXQgaSA9IC0xO1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoKytpPj1uKSBkZWxldGUgeFtrXTtcbiAgfVxuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIFJlbW92ZSBmaXJzdCBuIGVudHJpZXMgKGRlZmF1bHQgb3JkZXIpLlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgZW50cmllcyBbMV1cbiAqIEByZXR1cm5zIFxce1tr4oKZLCB24oKZXSwgW2vigpnigorigoEsIHbigpnigorigoFdLCAuLi5cXH0gfCBba+G1oiwgduG1ol0g4oiIIHggYW5kIHxcXHtba+KCmSwgduKCmV0sIFtr4oKZ4oKK4oKBLCB24oKZ4oKK4oKBXSwgLi4uXFx9fCDiiaQgbWF4KHx4fCAtIG4sIDApXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkcm9wKHg6IERpY3Rpb25hcnksIG46IG51bWJlcj0xKTogRGljdGlvbmFyeSB7XG4gIGxldCBpID0gLTE7IGNvbnN0IGE6IERpY3Rpb25hcnkgPSB7fTtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKCsraT49bikgYVtrXSA9IHhba107XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBSZW1vdmUgZmlyc3QgbiBlbnRyaWVzIChkZWZhdWx0IG9yZGVyKS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSBuIG51bWJlciBvZiBlbnRyaWVzIFsxXVxuICogQHJldHVybnMgeCA9IFxce1tr4oKZLCB24oKZXSwgW2vigpnigorigoEsIHbigpnigorigoFdLCAuLi5cXH0gfCBba+G1oiwgduG1ol0g4oiIIHggYW5kIHxcXHtba+KCmSwgduKCmV0sIFtr4oKZ4oKK4oKBLCB24oKZ4oKK4oKBXSwgLi4uXFx9fCDiiaQgbWF4KHx4fCAtIG4sIDApXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkcm9wJCh4OiBEaWN0aW9uYXJ5LCBuOiBudW1iZXI9MSk6IERpY3Rpb25hcnkge1xuICBsZXQgaSA9IC0xO1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoKytpPj1uKSBicmVhaztcbiAgICBkZWxldGUgeFtrXTtcbiAgfVxuICByZXR1cm4geDtcbn1cblxuXG5cblxuLy8gQVJSQU5HRU1FTlRTXG4vLyAtLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBMaXN0IGFsbCBwb3NzaWJsZSBzdWJzZXRzLlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgZW50cmllcyBbLTEg4oeSIGFueV1cbiAqIEByZXR1cm5zIGVudHJpZXMgc2VsZWN0ZWQgYnkgYml0IGZyb20gMC4uMl58eHwgaWYgbjwwOyBvbmx5IG9mIGxlbmd0aCBuIG90aGVyd2lzZVxuICovXG5leHBvcnQgZnVuY3Rpb24qIHN1YnNldHMoeDogRGljdGlvbmFyeSwgbjogbnVtYmVyPS0xKTogSXRlcmFibGVJdGVyYXRvcjxvYmplY3Q+IHtcbiAgZm9yIChjb25zdCBrcyBvZiBhcnJheVN1YnNlcXVlbmNlcyhPYmplY3Qua2V5cyh4KSwgbikpXG4gICAgeWllbGQgZmlsdGVyQXQoeCwga3MpO1xufVxuXG5cbi8qKlxuICogUGljayBhbiBhcmJpdHJhcnkga2V5LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZnIgcmFuZG9tIG51bWJlciBnZW5lcmF0b3IgKFswLCAxKSlcbiAqIEByZXR1cm5zIGvhtaIgfCBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhbmRvbUtleSh4OiBEaWN0aW9uYXJ5LCBmcjogUmVhZEZ1bmN0aW9uPG51bWJlcj4gfCBudWxsPU1hdGgucmFuZG9tKTogc3RyaW5nIHtcbiAgcmV0dXJuIGFycmF5UmFuZG9tVmFsdWUoT2JqZWN0LmtleXMoeCksIGZyKTtcbn1cbmV4cG9ydCB7cmFuZG9tS2V5IGFzIGtleX07XG5cblxuLyoqXG4gKiBQaWNrIGFuIGFyYml0cmFyeSBlbnRyeS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGZyIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIChbMCwgMSkpXG4gKiBAcmV0dXJucyBba+G1oiwgduG1ol0gfCBba+G1oiwgduG1ol0g4oiIIHhcbmAgKi9cbmV4cG9ydCBmdW5jdGlvbiByYW5kb21FbnRyeSh4OiBEaWN0aW9uYXJ5LCBmcjogUmVhZEZ1bmN0aW9uPG51bWJlcj4gfCBudWxsPU1hdGgucmFuZG9tKTogW3N0cmluZywgdW5rbm93bl0ge1xuICByZXR1cm4gYXJyYXlSYW5kb21WYWx1ZShPYmplY3QuZW50cmllcyh4KSwgZnIpO1xufVxuZXhwb3J0IHtyYW5kb21FbnRyeSBhcyBlbnRyeX07XG5cblxuLyoqXG4gKiBQaWNrIGFuIGFyYml0cmFyeSBzdWJzZXQuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBuIG51bWJlciBvZiBlbnRyaWVzIFstMSDih5IgYW55XVxuICogQHBhcmFtIGZyIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIChbMCwgMSkpXG4gKiBAcmV0dXJucyBcXHtba+G1oiwgduG1ol0sIFtr4rG8LCB24rG8XSwgLi4uXFx9IHwgW2vhtaIsIHbhtaJdLCBba+KxvCwgduKxvF0sIC4uLiDiiIggeDsgfFxce1tr4bWiLCB24bWiXSwgW2visbwsIHbisbxdLCAuLi5cXH18ID0gfHh8IGlmIG48MCBlbHNlIG5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhbmRvbVN1YnNldCh4OiBEaWN0aW9uYXJ5LCBuOiBudW1iZXI9LTEsIGZyOiBSZWFkRnVuY3Rpb248bnVtYmVyPiB8IG51bGw9TWF0aC5yYW5kb20pOiBEaWN0aW9uYXJ5IHtcbiAgY29uc3Qga3MgPSBhcnJheVJhbmRvbVN1YnNlcXVlbmNlKE9iamVjdC5rZXlzKHgpLCBuLCBmcik7XG4gIHJldHVybiBmaWx0ZXJBdCh4LCBrcyBhcyBzdHJpbmdbXSk7XG59XG5leHBvcnQge3JhbmRvbVN1YnNldCBhcyBzdWJzZXR9O1xuXG5cblxuXG4vLyBGSU5EXG4vLyAtLS0tXG5cbi8qKlxuICogQ2hlY2sgaWYgb2JqZWN0IGhhcyBhIGtleS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGsgc2VhcmNoIGtleVxuICogQHJldHVybnMgW2ssICpdIOKIiCB4P1xuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzKHg6IERpY3Rpb25hcnksIGs6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHgsIGspO1xufVxuZXhwb3J0IHtoYXMgYXMgaGFzS2V5fTtcblxuXG4vKipcbiAqIENoZWNrIGlmIG9iamVjdCBoYXMgYSB2YWx1ZS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIHYgc2VhcmNoIHZhbHVlXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBbKiwgdl0g4oiIIHg/XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNWYWx1ZSh4OiBEaWN0aW9uYXJ5LCB2OiB1bmtub3duLCBmYzogQ29tcGFyZUZ1bmN0aW9uIHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwpOiBib29sZWFuIHtcbiAgcmV0dXJuIHNlYXJjaFZhbHVlKHgsIHYsIGZjLCBmbSkhPW51bGw7XG59XG5cblxuLyoqXG4gKiBDaGVjayBpZiBvYmplY3QgaGFzIGFuIGVudHJ5LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZSBzZWFyY2ggZW50cnkgKFtrLCB2XSlcbiAqIEBwYXJhbSBmYyBjb21wYXJlIGZ1bmN0aW9uIChhLCBiKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIFtrLCB2XSDiiIggeD8gfCBbaywgdl0gPSBlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNFbnRyeSh4OiBEaWN0aW9uYXJ5LCBlOiBbc3RyaW5nLCB1bmtub3duXSwgZmM6IENvbXBhcmVGdW5jdGlvbiB8IG51bGw9bnVsbCwgZm06IE1hcEZ1bmN0aW9uIHwgbnVsbD1udWxsKTogYm9vbGVhbiB7XG4gIGZjID0gZmMgfHwgQ09NUEFSRTtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgY29uc3QgW2ssIHZdID0gZTtcbiAgcmV0dXJuIGhhcyh4LCBrKSAmJiBmYyhmbSh4W2tdLCBrLCB4KSwgdik9PT0wO1xufVxuXG5cbi8qKlxuICogQ2hlY2sgaWYgb2JqZWN0IGhhcyBhIHN1YnNldC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIHkgc2VhcmNoIHN1YnNldFxuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgeSDiioYgeD9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc1N1YnNldCh4OiBEaWN0aW9uYXJ5LCB5OiBEaWN0aW9uYXJ5LCBmYzogQ29tcGFyZUZ1bmN0aW9uIHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwpOiBib29sZWFuIHtcbiAgZmMgPSBmYyB8fCBDT01QQVJFO1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBmb3IgKGNvbnN0IGsgb2YgT2JqZWN0LmtleXMoeSkpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgcmV0dXJuIGZhbHNlO1xuICAgIGNvbnN0IHd4ID0gZm0oeFtrXSwgaywgeCk7XG4gICAgY29uc3Qgd3kgPSBmbSh5W2tdLCBrLCB5KTtcbiAgICBpZiAoZmMod3gsIHd5KSE9PTApIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn1cblxuXG4vKipcbiAqIEZpbmQgdmFsdWUgb2YgYW4gZW50cnkgcGFzc2luZyBhIHRlc3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgdiB8IGZ0KHYpID0gdHJ1ZTsgW2ssIHZdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kKHg6IERpY3Rpb25hcnksIGZ0OiBUZXN0RnVuY3Rpb24pOiB1bmtub3duIHtcbiAgZm9yIChjb25zdCBrIG9mIE9iamVjdC5rZXlzKHgpKVxuICAgIGlmIChmdCh4W2tdLCBrLCB4KSkgcmV0dXJuIHhba107XG59XG5cblxuLyoqXG4gKiBGaW5kIHZhbHVlcyBvZiBlbnRyaWVzIHBhc3NpbmcgYSB0ZXN0LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIFt24oKSLCB24oKBLCAuLi5dIHwgZnQoduG1oikgPSB0cnVlOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRBbGwoeDogRGljdGlvbmFyeSwgZnQ6IFRlc3RGdW5jdGlvbik6IHVua25vd25bXSB7XG4gIGNvbnN0IGEgPSBbXTtcbiAgZm9yIChjb25zdCBrIG9mIE9iamVjdC5rZXlzKHgpKVxuICAgIGlmIChmdCh4W2tdLCBrLCB4KSkgYS5wdXNoKHhba10pO1xuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEZpbmQga2V5IG9mIGFuIGVudHJ5IHBhc3NpbmcgYSB0ZXN0LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIGsgfCBmdCh4W2tdKSBwYXNzZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlYXJjaCh4OiBEaWN0aW9uYXJ5LCBmdDogVGVzdEZ1bmN0aW9uKTogc3RyaW5nIHwgbnVsbCB7XG4gIGZvciAoY29uc3QgayBvZiBPYmplY3Qua2V5cyh4KSlcbiAgICBpZiAoZnQoeFtrXSwgaywgeCkpIHJldHVybiBrO1xuICByZXR1cm4gbnVsbDtcbn1cblxuXG4vKipcbiAqIEZpbmQgYWxsIGtleXMgb2YgZW50cmllcyBwYXNzaW5nIGEgdGVzdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBba+KCgCwga+KCgSwgLi4uXSB8IGZ0KHhba+G1ol0pIHBhc3Nlc1xuICovXG5leHBvcnQgZnVuY3Rpb24gc2VhcmNoQWxsKHg6IERpY3Rpb25hcnksIGZ0OiBUZXN0RnVuY3Rpb24pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGEgPSBbXTtcbiAgZm9yIChjb25zdCBrIG9mIE9iamVjdC5rZXlzKHgpKVxuICAgIGlmIChmdCh4W2tdLCBrLCB4KSkgYS5wdXNoKGspO1xuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEZpbmQga2V5IHdpdGggYSBnaXZlbiB2YWx1ZS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIHYgc2VhcmNoIHZhbHVlXG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBrIHwgZm0oeFtrXSkg4omIIGZtKHYpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZWFyY2hWYWx1ZSh4OiBEaWN0aW9uYXJ5LCB2OiB1bmtub3duLCBmYzogQ29tcGFyZUZ1bmN0aW9uIHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwpOiBzdHJpbmcgfCBudWxsIHtcbiAgZmMgPSBmYyB8fCBDT01QQVJFO1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBjb25zdCB3ICA9IGZtKHYsIG51bGwgYXMgdW5rbm93biBhcyBzdHJpbmcsIG51bGwpO1xuICBmb3IgKGNvbnN0IGsgb2YgT2JqZWN0LmtleXMoeCkpIHtcbiAgICBjb25zdCB3eCA9IGZtKHhba10sIGssIHgpO1xuICAgIGlmIChmYyh3eCwgdyk9PT0wKSByZXR1cm4gaztcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuXG4vKipcbiAqIEZpbmQga2V5cyB3aXRoIGEgZ2l2ZW4gdmFsdWUuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSB2IHNlYXJjaCB2YWx1ZVxuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgW2vigoAsIGvigoEsIC4uLl0gfCBmbSh4W2vhtaJdKSDiiYggZm0odilcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlYXJjaFZhbHVlQWxsKHg6IERpY3Rpb25hcnksIHY6IHVua25vd24sIGZjOiBDb21wYXJlRnVuY3Rpb24gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbiB8IG51bGw9bnVsbCk6IHN0cmluZ1tdIHtcbiAgZmMgPSBmYyB8fCBDT01QQVJFO1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBjb25zdCB3ICA9IGZtKHYsIG51bGwgYXMgdW5rbm93biBhcyBzdHJpbmcsIG51bGwpLCBhID0gW107XG4gIGZvciAoY29uc3QgayBvZiBPYmplY3Qua2V5cyh4KSkge1xuICAgIGNvbnN0IHd4ID0gZm0oeFtrXSwgaywgeCk7XG4gICAgaWYgKGZjKHd4LCB3KT09PTApIGEucHVzaChrKTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG5cblxuLy8gRlVOQ1RJT05BTFxuLy8gLS0tLS0tLS0tLVxuXG4vKipcbiAqIENhbGwgYSBmdW5jdGlvbiBmb3IgZWFjaCBlbnRyeS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIGZwIGNhbGxlZCBmdW5jdGlvbiAodiwgaywgeClcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvckVhY2goeDogRGljdGlvbmFyeSwgZnA6IFByb2Nlc3NGdW5jdGlvbik6IHZvaWQge1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBmcCAoeFtrXSwgaywgeCk7XG4gIH1cbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIGFueSB2YWx1ZSBzYXRpc2ZpZXMgYSB0ZXN0LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIHRydWUgaWYgZnQoduG1oikgPSB0cnVlIGZvciBzb21lIFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gc29tZSh4OiBEaWN0aW9uYXJ5LCBmdDogVGVzdEZ1bmN0aW9uIHwgbnVsbD1udWxsKTogYm9vbGVhbiB7XG4gIGZ0ID0gZnQgfHwgSURFTlRJVFkgYXMgVGVzdEZ1bmN0aW9uO1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoZnQoeFtrXSwgaywgeCkpIHJldHVybiB0cnVlO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIGFsbCB2YWx1ZXMgc2F0aXNmeSBhIHRlc3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgdHJ1ZSBpZiBmdCh24bWiKSA9IHRydWUgZm9yIGFsbCBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV2ZXJ5KHg6IERpY3Rpb25hcnksIGZ0OiBUZXN0RnVuY3Rpb24pOiBib29sZWFuIHtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKCFmdCh4W2tdLCBrLCB4KSkgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiB0cnVlO1xufVxuXG5cbi8qKlxuICogVHJhbnNmb3JtIHZhbHVlcyBvZiBhbiBvYmplY3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBcXHtba+KCgCwgZm0oduKCgCldLCBba+KCgSwgZm0oduKCgSldLCAuLi5cXH0gfCBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcCh4OiBEaWN0aW9uYXJ5LCBmbTogTWFwRnVuY3Rpb24pOiBEaWN0aW9uYXJ5IHtcbiAgY29uc3QgYTogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBhW2tdID0gZm0oeFtrXSwgaywgeCk7XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBUcmFuc2Zvcm0gdmFsdWVzIG9mIGFuIG9iamVjdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyB4ID0gXFx7W2vigoAsIGZtKHbigoApXSwgW2vigoEsIGZtKHbigoEpXSwgLi4uXFx9IHwgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXAkKHg6IERpY3Rpb25hcnksIGZtOiBNYXBGdW5jdGlvbik6IERpY3Rpb25hcnkge1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICB4W2tdID0gZm0oeFtrXSwgaywgeCk7XG4gIH1cbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBSZWR1Y2UgdmFsdWVzIHRvIGEgc2luZ2xlIHZhbHVlLlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZnIgcmVkdWNlIGZ1bmN0aW9uIChhY2MsIHYsIGssIHgpXG4gKiBAcGFyYW0gYWNjIGluaXRpYWwgdmFsdWVcbiAqIEByZXR1cm5zIGZyKGZyKGFjYywgduKCgCksIHbigoEpLi4uIHwgZnIoYWNjLCB24oKAKSA9IHbigoAgaWYgYWNjIG5vdCBnaXZlblxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVkdWNlKHg6IERpY3Rpb25hcnksIGZyOiBSZWR1Y2VGdW5jdGlvbiwgYWNjPzogdW5rbm93bik6IHVua25vd24ge1xuICBsZXQgaW5pdCA9IGFyZ3VtZW50cy5sZW5ndGggPD0gMjtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKGluaXQpIHsgYWNjID0geFtrXTsgaW5pdCA9IGZhbHNlOyB9XG4gICAgZWxzZSBhY2MgPSBmcihhY2MsIHhba10sIGssIHgpO1xuICB9XG4gIHJldHVybiBhY2M7XG59XG5cblxuLyoqXG4gKiBLZWVwIGVudHJpZXMgd2hpY2ggcGFzcyBhIHRlc3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgXFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfSB8IGZ0KHbhtaIpID0gdHJ1ZTsgW2vhtaIsIHbhtaJdIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaWx0ZXIoeDogRGljdGlvbmFyeSwgZnQ6IFRlc3RGdW5jdGlvbik6IERpY3Rpb25hcnkge1xuICBjb25zdCBhOiBEaWN0aW9uYXJ5ID0ge307XG4gIGZvciAoY29uc3QgayBpbiB4KSB7XG4gICAgaWYgKCFoYXMoeCwgaykpIGNvbnRpbnVlO1xuICAgIGlmIChmdCh4W2tdLCBrLCB4KSkgYVtrXSA9IHhba107XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBLZWVwIGVudHJpZXMgd2hpY2ggcGFzcyBhIHRlc3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3QgKHVwZGF0ZWQpXG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIHggPSBcXHtba+KCgCwgduKCgF0sIFtr4oKBLCB24oKBXSwgLi4uXFx9IHwgZnQoduG1oikgPSB0cnVlOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlciQoeDogRGljdGlvbmFyeSwgZnQ6IFRlc3RGdW5jdGlvbik6IERpY3Rpb25hcnkge1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoIWZ0KHhba10sIGssIHgpKSBkZWxldGUgeFtrXTtcbiAgfVxuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIEdldCBvYmplY3Qgd2l0aCBnaXZlbiBrZXlzLlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0ga3Mga2V5c1xuICogQHJldHVybnMgXFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfSB8IGvhtaIg4oiIIGtzOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlckF0KHg6IERpY3Rpb25hcnksIGtzOiBzdHJpbmdbXSk6IERpY3Rpb25hcnkge1xuICBjb25zdCBhOiBEaWN0aW9uYXJ5ID0ge307XG4gIGZvciAoY29uc3QgayBvZiBrcylcbiAgICBpZiAoaGFzKHgsIGspKSBhW2tdID0geFtrXTtcbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBHZXQgb2JqZWN0IHdpdGggZ2l2ZW4ga2V5cy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSBrcyBrZXlzXG4gKiBAcmV0dXJucyB4ID0gXFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfSB8IGvhtaIg4oiIIGtzOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlckF0JCh4OiBEaWN0aW9uYXJ5LCBrczogc3RyaW5nW10pOiBEaWN0aW9uYXJ5IHtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKCFrcy5pbmNsdWRlcyhrKSkgZGVsZXRlIHhba107XG4gIH1cbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBEaXNjYXJkIGVudHJpZXMgd2hpY2ggcGFzcyBhIHRlc3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgXFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfSB8IGZ0KHbhtaIpID0gZmFsc2U7IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVqZWN0KHg6IERpY3Rpb25hcnksIGZ0OiBUZXN0RnVuY3Rpb24pOiBEaWN0aW9uYXJ5IHtcbiAgY29uc3QgYTogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoIWZ0KHhba10sIGssIHgpKSBhW2tdID0geFtrXTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIERpc2NhcmQgZW50cmllcyB3aGljaCBwYXNzIGEgdGVzdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHJldHVybnMgeCA9IFxce1tr4oKALCB24oKAXSwgW2vigoEsIHbigoFdLCAuLi5cXH0gfCBmdCh24bWiKSA9IGZhbHNlOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlamVjdCQoeDogRGljdGlvbmFyeSwgZnQ6IFRlc3RGdW5jdGlvbik6IERpY3Rpb25hcnkge1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoZnQoeFtrXSwgaywgeCkpIGRlbGV0ZSB4W2tdO1xuICB9XG4gIHJldHVybiB4O1xufVxuXG5cbi8qKlxuICogR2V0IG9iamVjdCB3aXRob3V0IGdpdmVuIGtleXMuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBrcyBrZXlzXG4gKiBAcmV0dXJucyBcXHtba+KCgCwgduKCgF0sIFtr4oKBLCB24oKBXSwgLi4uXFx9IHwga+G1oiDiiIkga3M7IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVqZWN0QXQoeDogRGljdGlvbmFyeSwga3M6IHN0cmluZ1tdKTogRGljdGlvbmFyeSB7XG4gIGNvbnN0IGE6IERpY3Rpb25hcnkgPSB7fTtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKCFrcy5pbmNsdWRlcyhrKSkgYVtrXSA9IHhba107XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBHZXQgb2JqZWN0IHdpdGhvdXQgZ2l2ZW4ga2V5cy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSBrcyBrZXlzXG4gKiBAcmV0dXJucyB4ID0gXFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfSB8IGvhtaIg4oiJIGtzOyBba+G1oiwgduG1ol0g4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlamVjdEF0JCh4OiBEaWN0aW9uYXJ5LCBrczogc3RyaW5nW10pOiBEaWN0aW9uYXJ5IHtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKGtzLmluY2x1ZGVzKGspKSBkZWxldGUgeFtrXTtcbiAgfVxuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIEZsYXR0ZW4gbmVzdGVkIG9iamVjdCB0byBnaXZlbiBkZXB0aC5cbiAqIEBwYXJhbSB4IGEgbmVzdGVkIG9iamVjdFxuICogQHBhcmFtIG4gbWF4aW11bSBkZXB0aCBbLTEg4oeSIGFsbF1cbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiBmb3IgZmxhdHRlbiAodiwgaywgeClcbiAqIEByZXR1cm5zIGZsYXQgbWFwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0KHg6IERpY3Rpb25hcnksIG46IG51bWJlcj0tMSwgZm06IE1hcEZ1bmN0aW9uIHwgbnVsbD1udWxsLCBmdDogVGVzdEZ1bmN0aW9uIHwgbnVsbD1udWxsKTogRGljdGlvbmFyeSB7XG4gIGZtID0gZm0gfHwgSURFTlRJVFk7XG4gIGZ0ID0gZnQgfHwgaXM7XG4gIHJldHVybiBmbGF0VG8kKHt9LCB4LCBuLCBmbSwgZnQpO1xufVxuXG5mdW5jdGlvbiBmbGF0VG8kKGE6IERpY3Rpb25hcnksIHg6IERpY3Rpb25hcnksIGRlcDogbnVtYmVyLCBmbTogTWFwRnVuY3Rpb24sIGZ0OiBUZXN0RnVuY3Rpb24pOiBEaWN0aW9uYXJ5IHtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgY29uc3QgdyA9IGZtKHhba10sIGssIHgpO1xuICAgIGlmIChkZXAhPT0wICYmIGZ0KHcsIGssIHgpKSBmbGF0VG8kKGEsIHcgYXMgRGljdGlvbmFyeSwgZGVwLTEsIGZtLCBmdCk7XG4gICAgZWxzZSBhW2tdID0gdztcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEZsYXR0ZW4gbmVzdGVkIG9iamVjdCwgdXNpbmcgbWFwIGZ1bmN0aW9uLlxuICogQHBhcmFtIHggYSBuZXN0ZWQgb2JqZWN0XG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCBrLCB4KVxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBmbGF0IG1hcFxuICovXG5leHBvcnQgZnVuY3Rpb24gZmxhdE1hcCh4OiBEaWN0aW9uYXJ5LCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwsIGZ0OiBUZXN0RnVuY3Rpb24gfCBudWxsPW51bGwpOiBEaWN0aW9uYXJ5IHtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgZnQgPSBmdCB8fCBpcztcbiAgY29uc3QgYTogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBjb25zdCB3ID0gZm0oeFtrXSwgaywgeCk7XG4gICAgaWYgKGZ0KHcsIGssIHgpKSBPYmplY3QuYXNzaWduKGEsIHcpO1xuICAgIGVsc2UgYVtrXSA9IHc7XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBDb21iaW5lIG1hdGNoaW5nIGVudHJpZXMgZnJvbSBvYmplY3RzLlxuICogQHBhcmFtIHhzIG9iamVjdHNcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHZzLCBrKVxuICogQHBhcmFtIGZlIGVuZCBmdW5jdGlvbiAoZG9uZXMpIFthcnJheS5zb21lXVxuICogQHBhcmFtIHZkIGRlZmF1bHQgdmFsdWVcbiAqIEByZXR1cm5zIFxce1wia+KCgFwiOiBmbShbeOKCgFtr4oKAXSwgeOKCgVtr4oKAXSwgLi4uXSksIFwia+KCgVwiOiBmbShbeOKCgFtr4oKBXSwgeOKCgVtr4oKBXSwgLi4uXSksIC4uLlxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gemlwKHhzOiBEaWN0aW9uYXJ5W10sIGZtOiBNYXBGdW5jdGlvbiB8IG51bGw9bnVsbCwgZmU6IEVuZEZ1bmN0aW9uIHwgbnVsbD1udWxsLCB2ZD86IHVua25vd24pOiBEaWN0aW9uYXJ5IHtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgZmUgPSBmZSB8fCBhcnJheVNvbWUgYXMgRW5kRnVuY3Rpb247XG4gIGNvbnN0IGtzID0gdW5pb25LZXlzKC4uLnhzKSwgYTogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGsgb2Yga3MpIHtcbiAgICBjb25zdCBkcyA9IHhzLm1hcCh4ID0+ICFoYXMoeCwgaykpO1xuICAgIGlmIChmZShkcykpIGJyZWFrO1xuICAgIGNvbnN0IHZzID0geHMubWFwKHggPT4gIWhhcyh4LCBrKT8gdmQgOiB4W2tdKTtcbiAgICBhW2tdID0gZm0odnMsIGssIG51bGwpO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cblxuXG4vLyBNQU5JUFVMQVRJT05cbi8vIC0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIFNlZ3JlZ2F0ZSBlbnRyaWVzIGJ5IHRlc3QgcmVzdWx0LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgaywgeClcbiAqIEByZXR1cm5zIFtzYXRpc2ZpZXMsIGRvZXNudF1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnRpdGlvbih4OiBEaWN0aW9uYXJ5LCBmdDogVGVzdEZ1bmN0aW9uKTogW29iamVjdCwgb2JqZWN0XSB7XG4gIGNvbnN0IHQ6IERpY3Rpb25hcnkgPSB7fTtcbiAgY29uc3QgZjogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoZnQoeFtrXSwgaywgeCkpIHRba10gPSB4W2tdO1xuICAgIGVsc2UgZltrXSA9IHhba107XG4gIH1cbiAgcmV0dXJuIFt0LCBmXTtcbn1cblxuXG4vKipcbiAqIFNlZ3JlZ2F0ZSBlbnRyaWVzIGJ5IHNpbWlsYXJpdHkuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIGssIHgpXG4gKiBAcmV0dXJucyBNYXAgXFx7a2V5IOKHkiB2YWx1ZXNcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnRpdGlvbkFzKHg6IERpY3Rpb25hcnksIGZtOiBNYXBGdW5jdGlvbik6IE1hcDx1bmtub3duLCBvYmplY3Q+IHtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgY29uc3QgYSA9IG5ldyBNYXAoKTtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgY29uc3QgdyA9IGZtKHhba10sIGssIHgpO1xuICAgIGlmICghYS5oYXModykpIGEuc2V0KHcsIHt9KTtcbiAgICBhLmdldCh3KVtrXSA9IHhba107XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBCcmVhayBvYmplY3QgaW50byBjaHVua3Mgb2YgZ2l2ZW4gc2l6ZS5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIG4gY2h1bmsgc2l6ZSBbMV1cbiAqIEBwYXJhbSBzIGNodW5rIHN0ZXAgW25dXG4gKiBAcmV0dXJucyBbeFswLi5uXSwgeFtzLi5zK25dLCB4WzJzLi4ycytuXSwgLi4uXVxuICovXG5leHBvcnQgZnVuY3Rpb24gY2h1bmsoeDogRGljdGlvbmFyeSwgbjogbnVtYmVyPTEsIHM6IG51bWJlcj1uKTogRGljdGlvbmFyeVtdIHtcbiAgY29uc3Qga3MgPSBPYmplY3Qua2V5cyh4KSwgYSA9IFtdO1xuICBjb25zdCBJID0ga3MubGVuZ3RoO1xuICBmb3IgKGxldCBpPTA7IGk8STsgaSs9cylcbiAgICBhLnB1c2goZmlsdGVyQXQoeCwga3Muc2xpY2UoaSwgaStuKSkpO1xuICByZXR1cm4gYTtcbn1cblxuXG5cblxuLy8gQ09NQklORVxuLy8gLS0tLS0tLVxuXG4vKipcbiAqIENvbWJpbmUgZW50cmllcyBmcm9tIG9iamVjdHMsIHByZWZlcnJpbmcgbGFzdC5cbiAqIEBwYXJhbSB4cyBvYmplY3RzXG4gKiBAcmV0dXJucyB44oKAIOKIqiB44oKBIOKIqiAuLi4gfCBbeOKCgCwgeOKCgSwgLi4uXSA9IHhzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb25jYXQoLi4ueHM6IERpY3Rpb25hcnlbXSk6IERpY3Rpb25hcnkge1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgLi4ueHMpO1xufVxuXG5cbi8qKlxuICogQ29tYmluZXMgZW50cmllcyBmcm9tIG9iamVjdHMsIHByZWZlcnJpbmcgbGFzdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSB5cyBvdGhlciBvYmplY3RzXG4gKiBAcmV0dXJucyB4ID0geCDiiKogeeKCgCDiiKogeeKCgSDiiKogLi4uIHwgW3nigoAsIHnigoEsIC4uLl0gPSB5c1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29uY2F0JCh4OiBEaWN0aW9uYXJ5LCAuLi55czogRGljdGlvbmFyeVtdKTogRGljdGlvbmFyeSB7XG4gIHJldHVybiBPYmplY3QuYXNzaWduKHgsIC4uLnlzKTtcbn1cblxuXG4vKipcbiAqIEpvaW4gZW50cmllcyB0b2dldGhlciBpbnRvIGEgc3RyaW5nLlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0gc2VwIHNlcGFyYXRvciBbLF1cbiAqIEBwYXJhbSBhc2MgYXNzb2NpYXRvciBbPV1cbiAqIEByZXR1cm5zIFwia+KCgD124oKALGvigoE9duKCgSwuLi5cIiB8IFtr4bWiLCB24bWiXSDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gam9pbih4OiBEaWN0aW9uYXJ5LCBzZXA6IHN0cmluZz1cIixcIiwgYXNjOiBzdHJpbmc9XCI9XCIpOiBzdHJpbmcge1xuICBsZXQgYSA9IFwiXCI7XG4gIGZvciAoY29uc3QgayBpbiB4KSB7XG4gICAgaWYgKCFoYXMoeCwgaykpIGNvbnRpbnVlO1xuICAgIGEgKz0gayArIGFzYyArIHhba10gKyBzZXA7XG4gIH1cbiAgcmV0dXJuIGEuc2xpY2UoMCwgLXNlcC5sZW5ndGgpO1xufVxuXG5cblxuXG4vLyBTRVQgT1BFUkFUSU9OU1xuLy8gLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBDaGVjayBpZiBvYmplY3RzIGhhdmUgbm8gY29tbW9uIGtleXMuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSB5IGFub3RoZXIgb2JqZWN0XG4gKiBAcmV0dXJucyB4IOKIqSB5ID0gzqY/XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0Rpc2pvaW50KHg6IERpY3Rpb25hcnksIHk6IERpY3Rpb25hcnkpOiBib29sZWFuIHtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKGhhcyh5LCBrKSkgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiB0cnVlO1xufVxuXG5cbi8qKlxuICogT2J0YWluIGtleXMgcHJlc2VudCBpbiBhbnkgb2JqZWN0LlxuICogQHBhcmFtIHhzIG9iamVjdHNcbiAqIEByZXR1cm5zIFtr4oKALCBr4oKBLCAuLi5dIHwgW2vhtaIsIHbhtaJdIOKIiCB44oKAIOKIqiB44oKBLCAuLi47IFt44oKALCB44oKBLCAuLi5dID0geHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVuaW9uS2V5cyguLi54czogRGljdGlvbmFyeVtdKTogU2V0PHN0cmluZz4ge1xuICBjb25zdCBhID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGZvciAoY29uc3QgeCBvZiB4cykge1xuICAgIGZvciAoY29uc3QgayBpbiB4KVxuICAgICAgaWYgKGhhcyh4LCBrKSkgYS5hZGQoayk7XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gZW50cmllcyBwcmVzZW50IGluIGFueSBvYmplY3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSB5IGFub3RoZXIgb2JqZWN0XG4gKiBAcGFyYW0gZmMgY29tYmluZSBmdW5jdGlvbiAoYSwgYilcbiAqIEByZXR1cm5zIHgg4oiqIHkgPSBcXHtba+G1oiwgduG1ol0gfCBba+G1oiwgduG1ol0g4oiIIHggb3IgW2vhtaIsIHbhtaJdIOKIiCB5XFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1bmlvbih4OiBEaWN0aW9uYXJ5LCB5OiBEaWN0aW9uYXJ5LCBmYzogQ29tYmluZUZ1bmN0aW9uIHwgbnVsbD1udWxsKTogRGljdGlvbmFyeSB7XG4gIHJldHVybiB1bmlvbiQoT2JqZWN0LmFzc2lnbih7fSwgeCksIHksIGZjKTtcbn1cblxuXG4vKipcbiAqIE9idGFpbiBlbnRyaWVzIHByZXNlbnQgaW4gYW55IG9iamVjdC5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdCAodXBkYXRlZClcbiAqIEBwYXJhbSB5IGFub3RoZXIgb2JqZWN0XG4gKiBAcGFyYW0gZmMgY29tYmluZSBmdW5jdGlvbiAoYSwgYilcbiAqIEByZXR1cm5zIHggPSB4IOKIqiB5ID0gXFx7W2vhtaIsIHbhtaJdIHwgW2vhtaIsIHbhtaJdIOKIiCB4IG9yIFtr4bWiLCB24bWiXSDiiIggeVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5pb24kKHg6IERpY3Rpb25hcnksIHk6IERpY3Rpb25hcnksIGZjOiBDb21iaW5lRnVuY3Rpb24gfCBudWxsPW51bGwpOiBEaWN0aW9uYXJ5IHtcbiAgZmMgPSBmYyB8fCBJREVOVElUWSBhcyBDb21iaW5lRnVuY3Rpb247XG4gIGZvciAoY29uc3QgayBpbiB5KSB7XG4gICAgaWYgKCFoYXMoeSwgaykpIGNvbnRpbnVlO1xuICAgIGlmICghaGFzKHgsIGspKSB4W2tdID0geVtrXTtcbiAgICBlbHNlIHhba10gPSBmYyh4W2tdLCB5W2tdKTtcbiAgfVxuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIE9idGFpbiBrZXlzIHByZXNlbnQgaW4gYWxsIG9iamVjdHMuXG4gKiBAcGFyYW0geHMgb2JqZWN0c1xuICogQHJldHVybnMgW2vigoAsIGvigoEsIC4uLl0gfCBba+G1oiwgduG1ol0g4oiIIHjigoAg4oipIHjigoEsIC4uLjsgW3jigoAsIHjigoEsIC4uLl0gPSB4c1xuICovXG5leHBvcnQgZnVuY3Rpb24gaW50ZXJzZWN0aW9uS2V5cyguLi54czogRGljdGlvbmFyeVtdKTogU2V0PHN0cmluZz4ge1xuICBjb25zdCBhID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGlmICh4cy5sZW5ndGg9PT0wKSByZXR1cm4gYTtcbiAgY29uc3QgeCA9IHhzWzBdLCB5cyA9IHhzLnNsaWNlKDEpO1xuICBMT09QWDogZm9yKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBmb3IgKGNvbnN0IHkgb2YgeXMpXG4gICAgICBpZiAoIWhhcyh5LCBrKSkgY29udGludWUgTE9PUFg7XG4gICAgYS5hZGQoayk7XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gZW50cmllcyBwcmVzZW50IGluIGJvdGggb2JqZWN0cy5cbiAqIEBwYXJhbSB4IGFuIG9iamVjdFxuICogQHBhcmFtIHkgYW5vdGhlciBvYmplY3RcbiAqIEBwYXJhbSBmYyBjb21iaW5lIGZ1bmN0aW9uIChhLCBiKVxuICogQHJldHVybnMgeCDiiKkgeSA9IFxce1tr4bWiLCB24bWiXSB8IFtr4bWiLCB24bWiXSDiiIggeCBhbmQgW2vhtaIsIHbhtaJdIOKIiCB5XFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbnRlcnNlY3Rpb24oeDogRGljdGlvbmFyeSwgeTogRGljdGlvbmFyeSwgZmM6IENvbWJpbmVGdW5jdGlvbiB8IG51bGw9bnVsbCk6IERpY3Rpb25hcnkge1xuICBmYyA9IGZjIHx8IElERU5USVRZIGFzIENvbWJpbmVGdW5jdGlvbjtcbiAgY29uc3QgYTogRGljdGlvbmFyeSA9IHt9O1xuICBmb3IgKGNvbnN0IGsgaW4geCkge1xuICAgIGlmICghaGFzKHgsIGspKSBjb250aW51ZTtcbiAgICBpZiAoIWhhcyh5LCBrKSkgY29udGludWU7XG4gICAgYVtrXSA9IGZjKHhba10sIHlba10pO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogT2J0YWluIGVudHJpZXMgcHJlc2VudCBpbiBib3RoIG9iamVjdHMuXG4gKiBAcGFyYW0geCBhbiBvYmplY3QgKHVwZGF0ZWQpXG4gKiBAcGFyYW0geSBhbm90aGVyIG9iamVjdFxuICogQHBhcmFtIGZjIGNvbWJpbmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcmV0dXJucyB4ID0geCDiiKkgeSA9IFxce1tr4bWiLCB24bWiXSB8IFtr4bWiLCB24bWiXSDiiIggeCBhbmQgW2vhtaIsIHbhtaJdIOKIiCB5XFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbnRlcnNlY3Rpb24kKHg6IERpY3Rpb25hcnksIHk6IERpY3Rpb25hcnksIGZjOiBDb21iaW5lRnVuY3Rpb24gfCBudWxsPW51bGwpOiBEaWN0aW9uYXJ5IHtcbiAgZmMgPSBmYyB8fCBJREVOVElUWSBhcyBDb21iaW5lRnVuY3Rpb247XG4gIGZvciAoY29uc3QgayBpbiB4KSB7XG4gICAgaWYgKCFoYXMoeCwgaykpIGNvbnRpbnVlO1xuICAgIGlmICghaGFzKHksIGspKSBkZWxldGUgeFtrXTtcbiAgICBlbHNlIHhba10gPSBmYyh4W2tdLCB5W2tdKTtcbiAgfVxuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIE9idGFpbiBlbnRyaWVzIG5vdCBwcmVzZW50IGluIGFub3RoZXIgb2JqZWN0LlxuICogQHBhcmFtIHggYW4gb2JqZWN0XG4gKiBAcGFyYW0geSBhbm90aGVyIG9iamVjdFxuICogQHJldHVybnMgeCAtIHkgPSBcXHtba+G1oiwgduG1ol0gfCBba+G1oiwgduG1ol0g4oiIIHgsIFtr4bWiLCAqXSDiiIkgeVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gZGlmZmVyZW5jZSh4OiBEaWN0aW9uYXJ5LCB5OiBEaWN0aW9uYXJ5KTogRGljdGlvbmFyeSB7XG4gIGNvbnN0IGE6IERpY3Rpb25hcnkgPSB7fTtcbiAgZm9yIChjb25zdCBrIGluIHgpIHtcbiAgICBpZiAoIWhhcyh4LCBrKSkgY29udGludWU7XG4gICAgaWYgKCFoYXMoeSwgaykpIGFba10gPSB4W2tdO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogT2J0YWluIGVudHJpZXMgbm90IHByZXNlbnQgaW4gYW5vdGhlciBvYmplY3QuXG4gKiBAcGFyYW0geCBhbiBvYmplY3QgKHVwZGF0ZWQpXG4gKiBAcGFyYW0geSBhbm90aGVyIG9iamVjdFxuICogQHJldHVybnMgeCA9IHggLSB5ID0gXFx7W2vhtaIsIHbhtaJdIHwgW2vhtaIsIHbhtaJdIOKIiCB4LCBba+G1oiwgKl0g4oiJIHlcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpZmZlcmVuY2UkKHg6IERpY3Rpb25hcnksIHk6IERpY3Rpb25hcnkpOiBEaWN0aW9uYXJ5IHtcbiAgZm9yIChjb25zdCBrIGluIHkpIHtcbiAgICBpZiAoIWhhcyh5LCBrKSkgY29udGludWU7XG4gICAgaWYgKGhhcyh4LCBrKSkgZGVsZXRlIHhba107XG4gIH1cbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gZW50cmllcyBub3QgcHJlc2VudCBpbiBib3RoIG9iamVjdHMuXG4gKiBAcGFyYW0geCBhbiBvYmplY3RcbiAqIEBwYXJhbSB5IGFub3RoZXIgb2JqZWN0XG4gKiBAcmV0dXJucyB4LXkg4oiqIHkteFxuICovXG5leHBvcnQgZnVuY3Rpb24gc3ltbWV0cmljRGlmZmVyZW5jZSh4OiBEaWN0aW9uYXJ5LCB5OiBEaWN0aW9uYXJ5KTogRGljdGlvbmFyeSB7XG4gIGNvbnN0IGE6IERpY3Rpb25hcnkgPSB7fTtcbiAgZm9yIChjb25zdCBrIG9mIHVuaW9uS2V5cyh4LCB5KSkge1xuICAgIGNvbnN0IHhrID0gaGFzKHgsIGspO1xuICAgIGNvbnN0IHlrID0gaGFzKHksIGspO1xuICAgIGlmICh4ayAmJiAheWspIGFba10gPSB4W2tdO1xuICAgIGVsc2UgaWYgKCF4ayAmJiB5aykgYVtrXSA9IHlba107XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gZW50cmllcyBub3QgcHJlc2VudCBpbiBib3RoIG9iamVjdHMuXG4gKiBAcGFyYW0geCBhbiBvYmplY3QgKHVwZGF0ZWQpXG4gKiBAcGFyYW0geSBhbm90aGVyIG9iamVjdFxuICogQHJldHVybnMgeCA9IHgteSDiiKogeS14XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzeW1tZXRyaWNEaWZmZXJlbmNlJCh4OiBEaWN0aW9uYXJ5LCB5OiBEaWN0aW9uYXJ5KTogRGljdGlvbmFyeSB7XG4gIGZvciAoY29uc3QgayBpbiB5KSB7XG4gICAgaWYgKCFoYXMoeSwgaykpIGNvbnRpbnVlO1xuICAgIGlmIChoYXMoeCwgaykpIGRlbGV0ZSB4W2tdO1xuICAgIGVsc2UgeFtrXSA9IHlba107XG4gIH1cbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBMaXN0IGNhcnRlc2lhbiBwcm9kdWN0IG9mIG9iamVjdHMuXG4gKiBAcGFyYW0geHMgb2JqZWN0c1xuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodnMpXG4gKiBAcmV0dXJucyB44oKAIMOXIHjigoEgw5cgLi4uID0gXFx7XFx7W2vigoAsIHbigoBdLCBba+KCgSwgduKCgV0sIC4uLlxcfSB8IFtr4oKALCB24oKAXSDiiIggeOKCgCwgW2vigoEsIHbigoFdIOKIiCB44oKBLCAuLi5dXFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiogY2FydGVzaWFuUHJvZHVjdCh4czogRGljdGlvbmFyeVtdLCBmbTogTWFwRnVuY3Rpb24gfCBudWxsPW51bGwpOiBJdGVyYWJsZUl0ZXJhdG9yPHVua25vd24+IHtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgY29uc3QgWFMgPSB4cy5sZW5ndGg7XG4gIGNvbnN0IGt4ID0geHMubWFwKHggPT4gT2JqZWN0LmtleXMoeCkpO1xuICBjb25zdCBscyA9IGt4Lm1hcChrcyA9PiBrcy5sZW5ndGgpO1xuICBjb25zdCBpcyA9IGt4Lm1hcChfa3MgPT4gMCk7XG4gIHdoaWxlICh0cnVlKSB7XG4gICAgY29uc3QgYTogRGljdGlvbmFyeSA9IHt9O1xuICAgIGZvciAobGV0IG49MDsgbjxYUzsgKytuKSB7XG4gICAgICBjb25zdCBpICA9IGlzW25dLCB4ID0geHNbbl07XG4gICAgICBjb25zdCBrcyA9IGt4W25dLCBrID0ga3NbaV07XG4gICAgICBhW2tdID0geFtrXTtcbiAgICB9XG4gICAgeWllbGQgZm0oYSwgbnVsbCBhcyB1bmtub3duIGFzIHN0cmluZywgbnVsbCk7XG4gICAgbGV0IHIgPSBYUy0xO1xuICAgIGZvcig7IHI+PTA7IC0tcikge1xuICAgICAgaWYgKCsraXNbcl0gPCBsc1tyXSkgYnJlYWs7XG4gICAgICBpc1tyXSA9IDA7XG4gICAgfVxuICAgIGlmIChyPDApIGJyZWFrO1xuICB9XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsU0FDRSxRQUFRLEVBQ1IsT0FBTyxRQUNGLHdCQUF3QjtBQUMvQixTQUNFLFFBQXFCLFNBQVMsRUFDOUIsUUFBcUIsU0FBUyxFQUM5QixnQkFBcUIsaUJBQWlCLEVBQ3RDLGVBQXFCLGdCQUFnQixFQUNyQyxxQkFBcUIsc0JBQXNCLFFBQ3RDLHFCQUFxQjtBQWtHNUIsWUFBWTtBQUNaLFlB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