UNPKG

extra-set

Version:

A pack of functions for working with Sets.<br>

683 lines • 59.5 kB
import { IDENTITY, COMPARE } from "@nodef/extra-function";
import { chunk as arrayChunk, subsequences as arraySubsequences, randomValue as arrayRandomValue, randomSubsequence as arrayRandomSubsequence } from "@nodef/extra-array";
// METHODS
// =======
// ABOUT
// -----
/**
 * Check if value is a set.
 * @param v a value
 * @returns v is a set?
 */ export function is(v) {
  return v instanceof Set;
}
/**
 * List all values.
 * @param x a set
 * @returns v₀, v₁, ... | vᵢ ∈ x
 */ export function values(x) {
  return x.values();
}
export { values as keys };
/**
 * List all value-value pairs.
 * @param x a set
 * @returns [v₀, v₀], [v₁, v₁], ... | vᵢ ∈ x
 */ export function entries(x) {
  return x.entries();
}
// GENERATE
// --------
/**
 * Convert an iterable to set.
 * @param x an iterable
 * @param fm map function (v, i, x)
 * @returns x as set
 */ export function from(x, fm = null) {
  if (!fm) return new Set(x);
  const a = new Set();
  let i = -1;
  for (const v of x)a.add(fm(v, ++i, x));
  return a;
}
/**
 * Convert an iterable to set.
 * @param x an iterable (updatable if set!)
 * @returns x as set
 */ export function from$(x) {
  return x instanceof Set ? x : new Set(x);
}
// COMPARE
// -------
/**
 * Compare two sets.
 * @param x a set
 * @param y another set
 * @returns x=y: 0, otherwise: -ve/+ve
 */ export function compare(x, y) {
  for (const v of x)if (!y.has(v)) return 1;
  for (const v of y)if (!x.has(v)) return -1;
  return 0;
}
/**
 * Check if two sets are equal.
 * @param x a set
 * @param y another set
 * @returns x = y?
 */ export function isEqual(x, y) {
  return x.size === y.size && compare(x, y) === 0;
}
// SIZE
// ----
/**
 * Find the size of a set.
 * @param x a set
 * @returns |x|
 */ export function size(x) {
  return x.size;
}
export { size as length };
/**
 * Check if a set is empty.
 * @param x a set
 * @returns |x| = 0?
 */ export function isEmpty(x) {
  return x.size === 0;
}
// ADD/REMOVE
// ----------
/**
 * Add a value to set.
 * @param x a set
 * @param v value
 * @returns x ∪ \{v\}
 */ export function add(x, v) {
  return new Set(x).add(v);
}
/**
 * Add a value to set.
 * @param x a set (updated)
 * @param v value
 * @returns x = x ∪ \{v\}
 */ export function add$(x, v) {
  return x.add(v);
}
/**
 * Delete a value from set.
 * @param x a set
 * @param v value
 * @returns x \\ \{v\}
 */ export function remove(x, v) {
  return remove$(new Set(x), v);
}
/**
 * Delete a value from set.
 * @param x a set (updated)
 * @param v value
 * @returns x = x \\ \{v\}
 */ export function remove$(x, v) {
  x.delete(v);
  return x;
}
// PROPERTY
// --------
/**
 * Count values which satisfy a test.
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns Σtᵢ | tᵢ = 1 if ft(vᵢ) else 0; vᵢ ∈ x
 */ export function count(x, ft) {
  let a = 0;
  for (const v of x)if (ft(v, v, x)) ++a;
  return a;
}
/**
 * Count occurrences of values.
 * @param x a set
 * @param fm map function (v, v, x)
 * @returns Map \{value ⇒ count\}
 */ export function countAs(x, fm) {
  fm = fm || IDENTITY;
  const a = new Map();
  for (const v of x){
    const w = fm(v, v, x);
    const n = a.get(w) || 0;
    a.set(w, n + 1);
  }
  return a;
}
/**
 * Find smallest value.
 * @param x a set
 * @param fc compare function (a, b)
 * @param fm map function (v, v, x)
 * @returns v | v ≤ vᵢ; vᵢ ∈ x
 */ export function min(x, fc = null, fm = null) {
  return range(x, fc, fm)[0];
}
/**
 * Find largest value.
 * @param x a set
 * @param fc compare function (a, b)
 * @param fm map function (v, v, x)
 * @returns v | v ≥ vᵢ; vᵢ ∈ x
 */ export function max(x, fc = null, fm = null) {
  return range(x, fc, fm)[1];
}
/**
 * Find smallest and largest entries.
 * @param x a set
 * @param fc compare function (a, b)
 * @param fm map function (v, v, x)
 * @returns [min_value, max_value]
 */ export function range(x, fc = null, fm = null) {
  fc = fc || COMPARE;
  fm = fm || IDENTITY;
  let mu, mv;
  let nu, nv;
  let i = 0;
  for (const u of x){
    const v = fm(u, u, x);
    if (i === 0 || fc(v, mv) < 0) {
      mu = u;
      mv = v;
    }
    if (i === 0 || fc(v, nv) > 0) {
      nu = u;
      nv = v;
    }
    i++;
  }
  return [
    mu,
    nu
  ];
}
// PART
// ----
/**
 * Get first value from set (default order).
 * @param x a set
 * @param vd default value
 * @returns v₀ if x ≠ Φ else vd | v₀ ∈ x
 */ export function head(x, vd) {
  for (const v of x)return v;
  return vd;
}
/**
 * Get a set without its first value (default order).
 * @param x a set
 * @returns x \\ \{v₀\} if x ≠ Φ else x | v₀ ∈ x
 */ export function tail(x) {
  return drop(x, 1);
}
/**
 * Keep first n values only (default order).
 * @param x a set
 * @param n number of values [1]
 * @returns \{v₀, v₁, ...\} | vᵢ ∈ x and |\{v₀, v₁, ...\}| ≤ n
 */ export function take(x, n = 1) {
  const a = new Set();
  let i = -1;
  for (const v of x){
    if (++i >= n) break;
    a.add(v);
  }
  return a;
}
/**
 * Keep first n values only (default order).
 * @param x a set (updated)
 * @param n number of values [1]
 * @returns x = \{v₀, v₁, ...\} | vᵢ ∈ x and |\{v₀, v₁, ...\}| ≤ n
 */ export function take$(x, n = 1) {
  let i = -1;
  for (const v of x)if (++i >= n) x.delete(v);
  return x;
}
/**
 * Remove first n values (default order).
 * @param x a set
 * @param n number of values [1]
 * @returns \{vₙ, vₙ₊₁, ...\} | vᵢ ∈ x and |\{vₙ, vₙ₊₁, ...\}| ≤ max(|x| - n, 0)
 */ export function drop(x, n = 1) {
  const a = new Set();
  let i = -1;
  for (const v of x)if (++i >= n) a.add(v);
  return a;
}
/**
 * Remove first n values (default order).
 * @param x a set (updated)
 * @param n number of values [1]
 * @returns x = \{vₙ, vₙ₊₁, ...\} | vᵢ ∈ x and |\{vₙ, vₙ₊₁, ...\}| ≤ max(|x| - n, 0)
 */ export function drop$(x, n = 1) {
  let i = -1;
  for (const v of x){
    if (++i >= n) break;
    x.delete(v);
  }
  return x;
}
// ARRANGEMENTS
// ------------
/**
 * List all possible subsets.
 * @param x a set
 * @param n number of values [-1 ⇒ any]
 * @returns elements selected by bit from 0..2^|x| if n<0; only of length n otherwise
 */ export function* subsets(x, n = -1) {
  for (const vs of arraySubsequences([
    ...x
  ], n))yield new Set(vs);
}
/**
 * Pick an arbitrary value.
 * @param x a set
 * @param fr random number generator ([0, 1))
 * @returns vᵢ | vᵢ ∈ x
 */ export function randomValue(x, fr = Math.random) {
  return arrayRandomValue([
    ...x
  ], fr);
}
export { randomValue as randomKey };
export { randomValue as value };
export { randomValue as key };
/**
 * Pick an arbitrary entry.
 * @param x a set
 * @param fr random number generator ([0, 1))
 * @returns [vᵢ, vᵢ] | vᵢ ∈ x
 */ export function randomEntry(x, fr = Math.random) {
  return arrayRandomValue([
    ...x.entries()
  ], fr);
}
export { randomEntry as entry };
/**
 * Pick an arbitrary subset.
 * @param x a set
 * @param n number of values [-1 ⇒ any]
 * @param fr random number generator ([0, 1))
 * @returns \{vᵢ, vⱼ, ...\} | vᵢ, vⱼ, ... ∈ x; |\{vᵢ, vⱼ, ...\}| = |x| if n<0 else n
 */ export function randomSubset(x, n = -1, fr = Math.random) {
  const vs = arrayRandomSubsequence([
    ...x
  ], n, fr);
  return new Set(vs);
}
/**
 * Checks if set has a subset.
 * @param x a set
 * @param y search subset
 * @returns y ⊆ x?
 */ export function hasSubset(x, y) {
  for (const v of y)if (!x.has(v)) return false;
  return true;
}
// FIND
// ----
/**
 * Check if set has a value.
 * @param x a set
 * @param v search value
 * @returns v ∈ x?
 */ export function has(x, v) {
  return x.has(v);
}
/**
 * Find first value passing a test (default order).
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns first v | ft(v) = true; v ∈ x
 */ export function find(x, ft) {
  for (const v of x)if (ft(v, v, x)) return v;
}
export { find as search };
/**
 * Find all values passing a test.
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns [v₀, v₁, ...] | ft(vᵢ) = true; vᵢ ∈ x
 */ export function findAll(x, ft) {
  const a = [];
  for (const v of x)if (ft(v, v, x)) a.push(v);
  return a;
}
export { findAll as searchAll };
// FUNCTIONAL
// ----------
/**
 * Call a function for each value.
 * @param x a set
 * @param fp process function (v, v, x)
 */ export function forEach(x, fp) {
  for (const v of x)fp(v, v, x);
}
/**
 * Check if any value satisfies a test.
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns true if ft(vᵢ) = true for some vᵢ ∈ x
 */ export function some(x, ft = null) {
  ft = ft || IDENTITY;
  for (const v of x)if (ft(v, v, x)) return true;
  return false;
}
/**
 * Check if all values satisfy a test.
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns true if ft(vᵢ) = true for all vᵢ ∈ x
 */ export function every(x, ft = null) {
  ft = ft || IDENTITY;
  for (const v of x)if (!ft(v, v, x)) return false;
  return true;
}
/**
 * Transform values of a set.
 * @param x a set
 * @param fm map function (v, v, x)
 * @returns \{fm(v₀), fm(v₁), ...\} | vᵢ ∈ x
 */ export function map(x, fm) {
  const a = new Set();
  for (const v of x)a.add(fm(v, v, x));
  return a;
}
/**
 * Transform values of a set.
 * @param x a set (updated)
 * @param fm map function (v, v, x)
 * @returns x = \{fm(v₀), fm(v₁), ...\} | vᵢ ∈ x
 */ export function map$(x, fm) {
  const vs = [];
  for (const v of x)vs.push(fm(v, v, x));
  x.clear();
  return concat$(x, vs);
}
/**
 * Reduce values of set to a single value.
 * @param x a set
 * @param fr reduce function (acc, v, v, 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 v of x){
    if (init) {
      acc = v;
      init = false;
    } else acc = fr(acc, v, v, x);
  }
  return acc;
}
/**
 * Keep values which pass a test.
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns \{v₀, v₁, ...\} | ft(vᵢ) = true; vᵢ ∈ x
 */ export function filter(x, ft) {
  const a = new Set();
  for (const v of x)if (ft(v, v, x)) a.add(v);
  return a;
}
/**
 * Keep values which pass a test.
 * @param x a set (updated)
 * @param ft test function (v, v, x)
 * @returns x = \{v₀, v₁, ...\} | ft(vᵢ) = true; vᵢ ∈ x
 */ export function filter$(x, ft) {
  for (const v of x)if (!ft(v, v, x)) x.delete(v);
  return x;
}
/**
 * Discard values which pass a test.
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns \{v₀, v₁, ...\} | ft(vᵢ) = false; vᵢ ∈ x
 */ export function reject(x, ft) {
  const a = new Set();
  for (const v of x)if (!ft(v, v, x)) a.add(v);
  return a;
}
/**
 * Discard values which pass a test.
 * @param x a set (updated)
 * @param ft test function (v, v, x)
 * @returns x = \{v₀, v₁, ...\} | ft(vᵢ) = false; vᵢ ∈ x
 */ export function reject$(x, ft) {
  for (const v of x)if (ft(v, v, x)) x.delete(v);
  return x;
}
/**
 * Flatten nested set to given depth.
 * @param x a nested set
 * @param n maximum depth [-1 ⇒ all]
 * @param fm map function (v, v, x)
 * @param ft flatten test function (v, v, x) [is]
 * @returns flat set
 */ export function flat(x, n = -1, fm = null, ft = null) {
  fm = fm || IDENTITY;
  ft = ft || is;
  return flatTo$(new Set(), x, n, fm, ft);
}
function flatTo$(a, x, n, fm, ft) {
  for (const v of x){
    const v1 = fm(v, v, x);
    if (n !== 0 && ft(v1, v1, x)) flatTo$(a, v1, n - 1, fm, ft);
    else a.add(v1);
  }
  return a;
}
/**
 * Flatten nested set, based on map function.
 * @param x a nested set
 * @param fm map function (v, v, x)
 * @param ft flatten test function (v, v, x) [is]
 * @returns flat set
 */ export function flatMap(x, fm = null, ft = null) {
  fm = fm || IDENTITY;
  ft = ft || is;
  const a = new Set();
  for (const v of x){
    const w = fm(v, v, x);
    if (ft(w, w, x)) concat$(a, w);
    else a.add(w);
  }
  return a;
}
// MANIPULATION
// ------------
/**
 * Segregate values by test result.
 * @param x a set
 * @param ft test function (v, v, x)
 * @returns [satisfies, doesnt]
 */ export function partition(x, ft) {
  const t = new Set();
  const f = new Set();
  for (const v of x){
    if (ft(v, v, x)) t.add(v);
    else f.add(v);
  }
  return [
    t,
    f
  ];
}
/**
 * Segregates values by similarity.
 * @param x a set
 * @param fm map function (v, v, x)
 * @returns Map \{key ⇒ values\}
 */ export function partitionAs(x, fm) {
  fm = fm || IDENTITY;
  const a = new Map();
  for (const v of x){
    const v1 = fm(v, v, x);
    if (!a.has(v1)) a.set(v1, new Set());
    a.get(v1).add(v);
  }
  return a;
}
/**
 * Break set into chunks of given size.
 * @param x a set
 * @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) {
  return arrayChunk([
    ...x
  ], n, s).map((c)=>new Set(c));
}
// COMBINE
// -------
/**
 * Append values from sets.
 * @param xs sets
 * @returns x₀ ∪ x₁ ∪ ... | [x₀, x₁, ...] = xs
 */ export function concat(...xs) {
  return concat$(new Set(), ...xs);
}
/**
 * Append values from sets.
 * @param x a set (updated)
 * @param ys other sets
 * @returns x = x ∪ y₀ ∪ y₁ ∪ ... | [y₀, y₁, ...] = ys
 */ export function concat$(x, ...ys) {
  for (const y of ys){
    for (const v of y)x.add(v);
  }
  return x;
}
/**
 * Join values together into a string.
 * @param x a set
 * @param sep separator [,]
 * @returns "$\{v₀\}$\{sep\}$\{v₁\}..." | vᵢ ∈ x
 */ export function join(x, sep = ",") {
  return [
    ...x
  ].join(sep);
}
// SET OPERATIONS
// --------------
/**
 * Check if sets have no value in common.
 * @param x a set
 * @param y another set
 * @returns x ∩ y = Φ?
 */ export function isDisjoint(x, y) {
  for (const v of y)if (x.has(v)) return false;
  return true;
}
/**
 * Obtain values present in any set.
 * @param x a set
 * @param y another set
 * @returns x ∪ y = \{v | v ∈ x or v ∈ y\}
 */ export function union(x, y) {
  return concat$(new Set(), x, y);
}
/**
 * Obtain values present in any set.
 * @param x a set (updated)
 * @param y another set
 * @returns x = x ∪ y = \{v | v ∈ x or v ∈ y\}
 */ export function union$(x, y) {
  return concat$(x, y);
}
/**
 * Obtain values present in both sets.
 * @param x a set
 * @param y another set
 * @returns x ∩ y = \{v | v ∈ x, v ∈ y\}
 */ export function intersection(x, y) {
  const a = new Set();
  for (const v of y)if (x.has(v)) a.add(v);
  return a;
}
/**
 * Obtain values present in both sets.
 * @param x a set (updated)
 * @param y another set
 * @returns x = x ∩ y = \{v | v ∈ x, v ∈ y\}
 */ export function intersection$(x, y) {
  for (const v of x)if (!y.has(v)) x.delete(v);
  return x;
}
/**
 * Obtain values not present in another set.
 * @param x a set
 * @param y another set
 * @returns x - y = \{v | v ∈ x, v ∉ y\}
 */ export function difference(x, y) {
  const a = new Set();
  for (const v of x)if (!y.has(v)) a.add(v);
  return a;
}
/**
 * Obtain values not present in another set.
 * @param x a set (updated)
 * @param y another set
 * @returns x = x - y = \{v | v ∈ x, v ∉ y\}
 */ export function difference$(x, y) {
  for (const v of y)x.delete(v);
  return x;
}
/**
 * Obtain values not present in both sets.
 * @param x a set
 * @param y another set
 * @returns x-y ∪ y-x
 */ export function symmetricDifference(x, y) {
  const a = new Set();
  for (const v of x)if (!y.has(v)) a.add(v);
  for (const v of y)if (!x.has(v)) a.add(v);
  return a;
}
/**
 * Obtain values not present in both sets.
 * @param x a set (updated)
 * @param y another set
 * @returns x = x-y ∪ y-x
 */ export function symmetricDifference$(x, y) {
  for (const v of y){
    if (x.has(v)) x.delete(v);
    else x.add(v);
  }
  return x;
}
/**
 * List cartesian product of sets.
 * @param xs sets
 * @param fm map function (vs, vs)
 * @returns x₀ × x₁ × ... = \{\{v₀, v₁, ...\} | v₀ ∈ x₀, v₁ ∈ x₁, ...]\}
 */ export function* cartesianProduct(xs, fm = null) {
  fm = fm || IDENTITY;
  const XS = xs.length;
  const ys = xs.map((x)=>[
      ...x
    ]);
  const ls = ys.map((vs)=>vs.length);
  const is = ys.map((_vs)=>0);
  while(true){
    const a = new Set();
    for(let n = 0; n < XS; ++n){
      const i = is[n];
      const vs = ys[n], v = vs[i];
      a.add(v);
    }
    yield fm(a, a, null);
    let r = XS - 1;
    for(; r >= 0; --r){
      if (++is[r] < ls[r]) break;
      is[r] = 0;
    }
    if (r < 0) break;
  }
}
export default cartesianProduct;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9leHRyYS1zZXQvZXh0cmEtc2V0L2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIElERU5USVRZLFxuICBDT01QQVJFLFxufSBmcm9tIFwiQG5vZGVmL2V4dHJhLWZ1bmN0aW9uXCI7XG5pbXBvcnQge1xuICBjaHVuayAgICAgICAgICAgICBhcyBhcnJheUNodW5rLFxuICBzdWJzZXF1ZW5jZXMgICAgICBhcyBhcnJheVN1YnNlcXVlbmNlcyxcbiAgcmFuZG9tVmFsdWUgICAgICAgYXMgYXJyYXlSYW5kb21WYWx1ZSxcbiAgcmFuZG9tU3Vic2VxdWVuY2UgYXMgYXJyYXlSYW5kb21TdWJzZXF1ZW5jZSxcbn0gZnJvbSBcIkBub2RlZi9leHRyYS1hcnJheVwiO1xuaW1wb3J0IHR5cGUge1xuICBNYXBGdW5jdGlvbiBhcyBJdGVyYWJsZU1hcEZ1bmN0aW9uLFxufSBmcm9tIFwiQG5vZGVmL2V4dHJhLWl0ZXJhYmxlXCI7XG5cblxuXG4vLyBUWVBFU1xuLy8gPT09PT1cblxuLyoqXG4gKiBIYW5kbGUgcmVhZGluZyBvZiBhIHNpbmdsZSB2YWx1ZS5cbiAqIEByZXR1cm5zIHZhbHVlXG4gKi9cbmV4cG9ydCB0eXBlIFJlYWRGdW5jdGlvbjxUPiA9ICgpID0+IFQ7XG5cblxuLyoqXG4gKiBIYW5kbGUgY29tYmluaW5nIG9mIHR3byB2YWx1ZXMuXG4gKiBAcGFyYW0gYSBhIHZhbHVlXG4gKiBAcGFyYW0gYiBhbm90aGVyIHZhbHVlXG4gKiBAcmV0dXJucyBjb21iaW5lZCB2YWx1ZVxuICovXG5leHBvcnQgdHlwZSBDb21iaW5lRnVuY3Rpb248VD4gPSAoYTogVCwgYjogVCkgPT4gVDtcblxuXG4vKipcbiAqIEhhbmRsZSBjb21wYXJpc29uIG9mIHR3byB2YWx1ZXMuXG4gKiBAcGFyYW0gYSBhIHZhbHVlXG4gKiBAcGFyYW0gYiBhbm90aGVyIHZhbHVlXG4gKiBAcmV0dXJucyBhPGI6IC12ZSwgYT1iOiAwLCBhPmI6ICt2ZVxuICovXG5leHBvcnQgdHlwZSBDb21wYXJlRnVuY3Rpb248VD4gPSAoYTogVCwgYjogVCkgPT4gbnVtYmVyO1xuXG5cbi8qKlxuICogSGFuZGxlIHByb2Nlc3Npbmcgb2YgdmFsdWVzIGluIGEgc2V0LlxuICogQHBhcmFtIHYgdmFsdWUgaW4gc2V0XG4gKiBAcGFyYW0gayBrZXkgb2YgdmFsdWUgaW4gc2V0ICg9IHZhbHVlKVxuICogQHBhcmFtIHggc2V0IGNvbnRhaW5pbmcgdGhlIHZhbHVlXG4gKi9cbmV4cG9ydCB0eXBlIFByb2Nlc3NGdW5jdGlvbjxUPiA9ICh2OiBULCBrOiBULCB4OiBTZXQ8VD4pID0+IHZvaWQ7XG5cblxuLyoqXG4gKiBIYW5kbGUgc2VsZWN0aW9uIG9mIHZhbHVlcyBpbiBhIHNldC5cbiAqIEBwYXJhbSB2IHZhbHVlIGluIHNldFxuICogQHBhcmFtIGsga2V5IG9mIHZhbHVlIGluIHNldCAoPSB2YWx1ZSlcbiAqIEBwYXJhbSB4IHNldCBjb250YWluaW5nIHRoZSB2YWx1ZVxuICogQHJldHVybnMgc2VsZWN0ZWQ/XG4gKi9cbmV4cG9ydCB0eXBlIFRlc3RGdW5jdGlvbjxUPiA9ICh2OiBULCBrOiBULCB4OiBTZXQ8VD4pID0+IGJvb2xlYW47XG5cblxuLyoqXG4gKiBIYW5kbGUgdHJhbnNmb3JtYXRpb24gb2YgYSB2YWx1ZSB0byBhbm90aGVyLlxuICogQHBhcmFtIHYgdmFsdWUgaW4gc2V0XG4gKiBAcGFyYW0gayBrZXkgb2YgdmFsdWUgaW4gc2V0ICg9IHZhbHVlKVxuICogQHBhcmFtIHggc2V0IGNvbnRhaW5pbmcgdGhlIHZhbHVlXG4gKiBAcmV0dXJucyB0cmFuc2Zvcm1lZCB2YWx1ZVxuICovXG5leHBvcnQgdHlwZSBNYXBGdW5jdGlvbjxULCBVPiA9ICh2OiBULCBrOiBULCB4OiBTZXQ8VD4gfCBudWxsKSA9PiBVO1xuXG5cbi8qKlxuICogSGFuZGxlIHJlZHVjdGlvbiBvZiBtdWx0aXBsZSB2YWx1ZXMgaW50byBhIHNpbmdsZSB2YWx1ZS5cbiAqIEBwYXJhbSBhY2MgYWNjdW11bGF0b3IgKHRlbXBvcmFyeSByZXN1bHQpXG4gKiBAcGFyYW0gdiB2YWx1ZSBpbiBzZXRcbiAqIEBwYXJhbSBrIGtleSBvZiB2YWx1ZSBpbiBzZXQgKD0gdmFsdWUpXG4gKiBAcGFyYW0geCBzZXQgY29udGFpbmluZyB0aGUgdmFsdWVcbiAqIEByZXR1cm5zIHJlZHVjZWQgdmFsdWVcbiAqL1xuZXhwb3J0IHR5cGUgUmVkdWNlRnVuY3Rpb248VCwgVT4gPSAoYWNjOiBVLCB2OiBULCBrOiBULCB4OiBTZXQ8VD4pID0+IFU7XG5cblxuLyoqXG4gKiBIYW5kbGUgZW5kaW5nIG9mIGEgY29tYmluZWQgc2V0LlxuICogQHBhcmFtIGRvbmVzIGnhtZfKsCBzZXQgZG9uZT9cbiAqIEByZXR1cm5zIGNvbWJpbmVkIHNldCBkb25lP1xuICovXG5leHBvcnQgdHlwZSBFbmRGdW5jdGlvbiA9IChkb25lczogYm9vbGVhbltdKSA9PiBib29sZWFuO1xuXG5cblxuXG4vLyBNRVRIT0RTXG4vLyA9PT09PT09XG5cbi8vIEFCT1VUXG4vLyAtLS0tLVxuXG4vKipcbiAqIENoZWNrIGlmIHZhbHVlIGlzIGEgc2V0LlxuICogQHBhcmFtIHYgYSB2YWx1ZVxuICogQHJldHVybnMgdiBpcyBhIHNldD9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzKHY6IHVua25vd24pOiB2IGlzIFNldDx1bmtub3duPiB7XG4gIHJldHVybiB2IGluc3RhbmNlb2YgU2V0O1xufVxuXG5cbi8qKlxuICogTGlzdCBhbGwgdmFsdWVzLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEByZXR1cm5zIHbigoAsIHbigoEsIC4uLiB8IHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbHVlczxUPih4OiBTZXQ8VD4pOiBJdGVyYWJsZUl0ZXJhdG9yPFQ+IHtcbiAgcmV0dXJuIHgudmFsdWVzKCk7XG59XG5leHBvcnQge3ZhbHVlcyBhcyBrZXlzfTtcblxuXG4vKipcbiAqIExpc3QgYWxsIHZhbHVlLXZhbHVlIHBhaXJzLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEByZXR1cm5zIFt24oKALCB24oKAXSwgW3bigoEsIHbigoFdLCAuLi4gfCB24bWiIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlbnRyaWVzPFQ+KHg6IFNldDxUPik6IEl0ZXJhYmxlSXRlcmF0b3I8W1QsIFRdPiB7XG4gIHJldHVybiB4LmVudHJpZXMoKTtcbn1cblxuXG5cblxuLy8gR0VORVJBVEVcbi8vIC0tLS0tLS0tXG5cbi8qKlxuICogQ29udmVydCBhbiBpdGVyYWJsZSB0byBzZXQuXG4gKiBAcGFyYW0geCBhbiBpdGVyYWJsZVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgaSwgeClcbiAqIEByZXR1cm5zIHggYXMgc2V0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tPFQsIFU9VD4oeDogSXRlcmFibGU8VD4sIGZtOiBJdGVyYWJsZU1hcEZ1bmN0aW9uPFQsIFU+IHwgbnVsbD1udWxsKTogU2V0PFR8VT4ge1xuICBpZiAoIWZtKSByZXR1cm4gbmV3IFNldCh4KTtcbiAgY29uc3QgYSA9IG5ldyBTZXQ8VT4oKTsgbGV0IGkgPSAtMTtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgYS5hZGQoZm0odiwgKytpLCB4KSk7XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogQ29udmVydCBhbiBpdGVyYWJsZSB0byBzZXQuXG4gKiBAcGFyYW0geCBhbiBpdGVyYWJsZSAodXBkYXRhYmxlIGlmIHNldCEpXG4gKiBAcmV0dXJucyB4IGFzIHNldFxuICovXG5leHBvcnQgZnVuY3Rpb24gZnJvbSQ8VD4oeDogSXRlcmFibGU8VD4pOiBTZXQ8VD4ge1xuICByZXR1cm4geCBpbnN0YW5jZW9mIFNldD8geCA6IG5ldyBTZXQoeCk7XG59XG5cblxuXG5cbi8vIENPTVBBUkVcbi8vIC0tLS0tLS1cblxuLyoqXG4gKiBDb21wYXJlIHR3byBzZXRzLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSB5IGFub3RoZXIgc2V0XG4gKiBAcmV0dXJucyB4PXk6IDAsIG90aGVyd2lzZTogLXZlLyt2ZVxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGFyZTxUPih4OiBTZXQ8VD4sIHk6IFNldDxUPik6IG51bWJlciB7XG4gIGZvciAoY29uc3QgdiBvZiB4KVxuICAgIGlmICgheS5oYXModikpIHJldHVybiAxO1xuICBmb3IgKGNvbnN0IHYgb2YgeSlcbiAgICBpZiAoIXguaGFzKHYpKSByZXR1cm4gLTE7XG4gIHJldHVybiAwO1xufVxuXG5cbi8qKlxuICogQ2hlY2sgaWYgdHdvIHNldHMgYXJlIGVxdWFsLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSB5IGFub3RoZXIgc2V0XG4gKiBAcmV0dXJucyB4ID0geT9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRXF1YWw8VD4oeDogU2V0PFQ+LCB5OiBTZXQ8VD4pOiBib29sZWFuIHtcbiAgcmV0dXJuIHguc2l6ZT09PXkuc2l6ZSAmJiBjb21wYXJlKHgsIHkpPT09MDtcbn1cblxuXG5cblxuLy8gU0laRVxuLy8gLS0tLVxuXG4vKipcbiAqIEZpbmQgdGhlIHNpemUgb2YgYSBzZXQuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHJldHVybnMgfHh8XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzaXplPFQ+KHg6IFNldDxUPik6IG51bWJlciB7XG4gIHJldHVybiB4LnNpemU7XG59XG5leHBvcnQge3NpemUgYXMgbGVuZ3RofTtcblxuXG4vKipcbiAqIENoZWNrIGlmIGEgc2V0IGlzIGVtcHR5LlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEByZXR1cm5zIHx4fCA9IDA/XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0VtcHR5PFQ+KHg6IFNldDxUPik6IGJvb2xlYW4ge1xuICByZXR1cm4geC5zaXplPT09MDtcbn1cblxuXG5cblxuLy8gQUREL1JFTU9WRVxuLy8gLS0tLS0tLS0tLVxuXG4vKipcbiAqIEFkZCBhIHZhbHVlIHRvIHNldC5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gdiB2YWx1ZVxuICogQHJldHVybnMgeCDiiKogXFx7dlxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkPFQ+KHg6IFNldDxUPiwgdjogVCk6IFNldDxUPiB7XG4gIHJldHVybiBuZXcgU2V0KHgpLmFkZCh2KTtcbn1cblxuXG4vKipcbiAqIEFkZCBhIHZhbHVlIHRvIHNldC5cbiAqIEBwYXJhbSB4IGEgc2V0ICh1cGRhdGVkKVxuICogQHBhcmFtIHYgdmFsdWVcbiAqIEByZXR1cm5zIHggPSB4IOKIqiBcXHt2XFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGQkPFQ+KHg6IFNldDxUPiwgdjogVCk6IFNldDxUPiB7XG4gIHJldHVybiB4LmFkZCh2KTtcbn1cblxuXG4vKipcbiAqIERlbGV0ZSBhIHZhbHVlIGZyb20gc2V0LlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSB2IHZhbHVlXG4gKiBAcmV0dXJucyB4IFxcXFwgXFx7dlxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVtb3ZlPFQ+KHg6IFNldDxUPiwgdjogVCk6IFNldDxUPiB7XG4gIHJldHVybiByZW1vdmUkKG5ldyBTZXQoeCksIHYpO1xufVxuXG5cbi8qKlxuICogRGVsZXRlIGEgdmFsdWUgZnJvbSBzZXQuXG4gKiBAcGFyYW0geCBhIHNldCAodXBkYXRlZClcbiAqIEBwYXJhbSB2IHZhbHVlXG4gKiBAcmV0dXJucyB4ID0geCBcXFxcIFxce3ZcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZSQ8VD4oeDogU2V0PFQ+LCB2OiBUKTogU2V0PFQ+IHtcbiAgeC5kZWxldGUodik7XG4gIHJldHVybiB4O1xufVxuXG5cblxuXG4vLyBQUk9QRVJUWVxuLy8gLS0tLS0tLS1cblxuLyoqXG4gKiBDb3VudCB2YWx1ZXMgd2hpY2ggc2F0aXNmeSBhIHRlc3QuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyDOo3ThtaIgfCB04bWiID0gMSBpZiBmdCh24bWiKSBlbHNlIDA7IHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvdW50PFQ+KHg6IFNldDxUPiwgZnQ6IFRlc3RGdW5jdGlvbjxUPik6IG51bWJlciB7XG4gIGxldCBhID0gMDtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgaWYgKGZ0KHYsIHYsIHgpKSArK2E7XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogQ291bnQgb2NjdXJyZW5jZXMgb2YgdmFsdWVzLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyBNYXAgXFx7dmFsdWUg4oeSIGNvdW50XFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb3VudEFzPFQsIFU9VD4oeDogU2V0PFQ+LCBmbTogTWFwRnVuY3Rpb248VCwgVHxVPik6IE1hcDxUfFUsIG51bWJlcj4ge1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBjb25zdCBhICA9IG5ldyBNYXAoKTtcbiAgZm9yIChjb25zdCB2IG9mIHgpIHtcbiAgICBjb25zdCB3ID0gZm0odiwgdiwgeCk7XG4gICAgY29uc3QgbiA9IGEuZ2V0KHcpIHx8IDA7XG4gICAgYS5zZXQodywgbisxKTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEZpbmQgc21hbGxlc3QgdmFsdWUuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZjIGNvbXBhcmUgZnVuY3Rpb24gKGEsIGIpXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCB2LCB4KVxuICogQHJldHVybnMgdiB8IHYg4omkIHbhtaI7IHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1pbjxULCBVPVQ+KHg6IFNldDxUPiwgZmM6IENvbXBhcmVGdW5jdGlvbjxUfFU+IHwgbnVsbD1udWxsLCBmbTogTWFwRnVuY3Rpb248VCwgVHxVPiB8IG51bGw9bnVsbCk6IFQgfCB1bmRlZmluZWQge1xuICByZXR1cm4gcmFuZ2UoeCwgZmMsIGZtKVswXTtcbn1cblxuXG4vKipcbiAqIEZpbmQgbGFyZ2VzdCB2YWx1ZS5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gZmMgY29tcGFyZSBmdW5jdGlvbiAoYSwgYilcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyB2IHwgdiDiiaUgduG1ojsgduG1oiDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gbWF4PFQsIFU9VD4oeDogU2V0PFQ+LCBmYzogQ29tcGFyZUZ1bmN0aW9uPFR8VT4gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbjxULCBUfFU+IHwgbnVsbD1udWxsKTogVCB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiByYW5nZSh4LCBmYywgZm0pWzFdO1xufVxuXG5cbi8qKlxuICogRmluZCBzbWFsbGVzdCBhbmQgbGFyZ2VzdCBlbnRyaWVzLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBmYyBjb21wYXJlIGZ1bmN0aW9uIChhLCBiKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgdiwgeClcbiAqIEByZXR1cm5zIFttaW5fdmFsdWUsIG1heF92YWx1ZV1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhbmdlPFQsIFU9VD4oeDogU2V0PFQ+LCBmYzogQ29tcGFyZUZ1bmN0aW9uPFR8VT4gfCBudWxsPW51bGwsIGZtOiBNYXBGdW5jdGlvbjxULCBUfFU+IHwgbnVsbD1udWxsKTogW1QgfCB1bmRlZmluZWQsIFQgfCB1bmRlZmluZWRdIHtcbiAgZmMgPSBmYyB8fCBDT01QQVJFO1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBsZXQgbXU6IFQgfCB1bmRlZmluZWQsIG12OiBUfFUgfCB1bmRlZmluZWQ7XG4gIGxldCBudTogVCB8IHVuZGVmaW5lZCwgbnY6IFR8VSB8IHVuZGVmaW5lZDtcbiAgbGV0IGkgPSAwO1xuICBmb3IgKGNvbnN0IHUgb2YgeCkge1xuICAgIGNvbnN0IHYgPSBmbSh1LCB1LCB4KTtcbiAgICBpZihpPT09MCB8fCBmYyh2LCBtdiBhcyBUfFUpPDApIHsgbXUgPSB1OyBtdiA9IHY7IH1cbiAgICBpZihpPT09MCB8fCBmYyh2LCBudiBhcyBUfFUpPjApIHsgbnUgPSB1OyBudiA9IHY7IH1cbiAgICBpKys7XG4gIH1cbiAgcmV0dXJuIFttdSwgbnVdO1xufVxuXG5cblxuXG4vLyBQQVJUXG4vLyAtLS0tXG5cbi8qKlxuICogR2V0IGZpcnN0IHZhbHVlIGZyb20gc2V0IChkZWZhdWx0IG9yZGVyKS5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gdmQgZGVmYXVsdCB2YWx1ZVxuICogQHJldHVybnMgduKCgCBpZiB4IOKJoCDOpiBlbHNlIHZkIHwgduKCgCDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gaGVhZDxUPih4OiBTZXQ8VD4sIHZkPzogVCk6IFQgfCB1bmRlZmluZWQge1xuICBmb3IgKGNvbnN0IHYgb2YgeClcbiAgICByZXR1cm4gdjtcbiAgcmV0dXJuIHZkO1xufVxuXG5cbi8qKlxuICogR2V0IGEgc2V0IHdpdGhvdXQgaXRzIGZpcnN0IHZhbHVlIChkZWZhdWx0IG9yZGVyKS5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcmV0dXJucyB4IFxcXFwgXFx7duKCgFxcfSBpZiB4IOKJoCDOpiBlbHNlIHggfCB24oKAIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0YWlsPFQ+KHg6IFNldDxUPik6IFNldDxUPiB7XG4gIHJldHVybiBkcm9wKHgsIDEpO1xufVxuXG5cbi8qKlxuICogS2VlcCBmaXJzdCBuIHZhbHVlcyBvbmx5IChkZWZhdWx0IG9yZGVyKS5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgdmFsdWVzIFsxXVxuICogQHJldHVybnMgXFx7duKCgCwgduKCgSwgLi4uXFx9IHwgduG1oiDiiIggeCBhbmQgfFxce3bigoAsIHbigoEsIC4uLlxcfXwg4omkIG5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRha2U8VD4oeDogSXRlcmFibGU8VD4sIG46IG51bWJlcj0xKTogU2V0PFQ+IHtcbiAgY29uc3QgYSA9IG5ldyBTZXQ8VD4oKTsgbGV0IGkgPSAtMTtcbiAgZm9yIChjb25zdCB2IG9mIHgpIHtcbiAgICBpZiAoKytpPj1uKSBicmVhaztcbiAgICBhLmFkZCh2KTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEtlZXAgZmlyc3QgbiB2YWx1ZXMgb25seSAoZGVmYXVsdCBvcmRlcikuXG4gKiBAcGFyYW0geCBhIHNldCAodXBkYXRlZClcbiAqIEBwYXJhbSBuIG51bWJlciBvZiB2YWx1ZXMgWzFdXG4gKiBAcmV0dXJucyB4ID0gXFx7duKCgCwgduKCgSwgLi4uXFx9IHwgduG1oiDiiIggeCBhbmQgfFxce3bigoAsIHbigoEsIC4uLlxcfXwg4omkIG5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRha2UkPFQ+KHg6IFNldDxUPiwgbjogbnVtYmVyPTEpOiBTZXQ8VD4ge1xuICBsZXQgaSA9IC0xO1xuICBmb3IgKGNvbnN0IHYgb2YgeClcbiAgICBpZiAoKytpPj1uKSB4LmRlbGV0ZSh2KTtcbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBSZW1vdmUgZmlyc3QgbiB2YWx1ZXMgKGRlZmF1bHQgb3JkZXIpLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBuIG51bWJlciBvZiB2YWx1ZXMgWzFdXG4gKiBAcmV0dXJucyBcXHt24oKZLCB24oKZ4oKK4oKBLCAuLi5cXH0gfCB24bWiIOKIiCB4IGFuZCB8XFx7duKCmSwgduKCmeKCiuKCgSwgLi4uXFx9fCDiiaQgbWF4KHx4fCAtIG4sIDApXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkcm9wPFQ+KHg6IFNldDxUPiwgbjogbnVtYmVyPTEpOiBTZXQ8VD4ge1xuICBjb25zdCBhID0gbmV3IFNldDxUPigpOyBsZXQgaSA9IC0xO1xuICBmb3IgKGNvbnN0IHYgb2YgeClcbiAgICBpZiAoKytpPj1uKSBhLmFkZCh2KTtcbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBSZW1vdmUgZmlyc3QgbiB2YWx1ZXMgKGRlZmF1bHQgb3JkZXIpLlxuICogQHBhcmFtIHggYSBzZXQgKHVwZGF0ZWQpXG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgdmFsdWVzIFsxXVxuICogQHJldHVybnMgeCA9IFxce3bigpksIHbigpnigorigoEsIC4uLlxcfSB8IHbhtaIg4oiIIHggYW5kIHxcXHt24oKZLCB24oKZ4oKK4oKBLCAuLi5cXH18IOKJpCBtYXgofHh8IC0gbiwgMClcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRyb3AkPFQ+KHg6IFNldDxUPiwgbjogbnVtYmVyPTEpOiBTZXQ8VD4ge1xuICBsZXQgaSA9IC0xO1xuICBmb3IgKGNvbnN0IHYgb2YgeCkge1xuICAgIGlmICgrK2k+PW4pIGJyZWFrO1xuICAgIHguZGVsZXRlKHYpO1xuICB9XG4gIHJldHVybiB4O1xufVxuXG5cblxuXG4vLyBBUlJBTkdFTUVOVFNcbi8vIC0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIExpc3QgYWxsIHBvc3NpYmxlIHN1YnNldHMuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIG4gbnVtYmVyIG9mIHZhbHVlcyBbLTEg4oeSIGFueV1cbiAqIEByZXR1cm5zIGVsZW1lbnRzIHNlbGVjdGVkIGJ5IGJpdCBmcm9tIDAuLjJefHh8IGlmIG48MDsgb25seSBvZiBsZW5ndGggbiBvdGhlcndpc2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uKiBzdWJzZXRzPFQ+KHg6IFNldDxUPiwgbjogbnVtYmVyPS0xKTogSXRlcmFibGVJdGVyYXRvcjxTZXQ8VD4+IHtcbiAgZm9yIChjb25zdCB2cyBvZiBhcnJheVN1YnNlcXVlbmNlcyhbLi4ueF0sIG4pKVxuICAgIHlpZWxkIG5ldyBTZXQodnMpO1xufVxuXG5cbi8qKlxuICogUGljayBhbiBhcmJpdHJhcnkgdmFsdWUuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZyIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIChbMCwgMSkpXG4gKiBAcmV0dXJucyB24bWiIHwgduG1oiDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmFuZG9tVmFsdWU8VD4oeDogU2V0PFQ+LCBmcjogUmVhZEZ1bmN0aW9uPG51bWJlcj49TWF0aC5yYW5kb20pOiBUIHtcbiAgcmV0dXJuIGFycmF5UmFuZG9tVmFsdWUoWy4uLnhdLCBmcik7XG59XG5leHBvcnQge3JhbmRvbVZhbHVlIGFzIHJhbmRvbUtleX07XG5leHBvcnQge3JhbmRvbVZhbHVlIGFzIHZhbHVlfTtcbmV4cG9ydCB7cmFuZG9tVmFsdWUgYXMga2V5fTtcblxuXG4vKipcbiAqIFBpY2sgYW4gYXJiaXRyYXJ5IGVudHJ5LlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBmciByYW5kb20gbnVtYmVyIGdlbmVyYXRvciAoWzAsIDEpKVxuICogQHJldHVybnMgW3bhtaIsIHbhtaJdIHwgduG1oiDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmFuZG9tRW50cnk8VD4oeDogU2V0PFQ+LCBmcjogUmVhZEZ1bmN0aW9uPG51bWJlcj49TWF0aC5yYW5kb20pOiBbVCwgVF0ge1xuICByZXR1cm4gYXJyYXlSYW5kb21WYWx1ZShbLi4ueC5lbnRyaWVzKCldLCBmcik7XG59XG5leHBvcnQge3JhbmRvbUVudHJ5IGFzIGVudHJ5fTtcblxuXG4vKipcbiAqIFBpY2sgYW4gYXJiaXRyYXJ5IHN1YnNldC5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgdmFsdWVzIFstMSDih5IgYW55XVxuICogQHBhcmFtIGZyIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIChbMCwgMSkpXG4gKiBAcmV0dXJucyBcXHt24bWiLCB24rG8LCAuLi5cXH0gfCB24bWiLCB24rG8LCAuLi4g4oiIIHg7IHxcXHt24bWiLCB24rG8LCAuLi5cXH18ID0gfHh8IGlmIG48MCBlbHNlIG5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhbmRvbVN1YnNldDxUPih4OiBTZXQ8VD4sIG46IG51bWJlcj0tMSwgZnI6IFJlYWRGdW5jdGlvbjxudW1iZXI+PU1hdGgucmFuZG9tKTogU2V0PFQ+IHtcbiAgY29uc3QgdnMgPSBhcnJheVJhbmRvbVN1YnNlcXVlbmNlKFsuLi54XSwgbiwgZnIpO1xuICByZXR1cm4gbmV3IFNldCh2cyk7XG59XG5cblxuLyoqXG4gKiBDaGVja3MgaWYgc2V0IGhhcyBhIHN1YnNldC5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0geSBzZWFyY2ggc3Vic2V0XG4gKiBAcmV0dXJucyB5IOKKhiB4P1xuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzU3Vic2V0PFQ+KHg6IFNldDxUPiwgeTogU2V0PFQ+KTogYm9vbGVhbiB7XG4gIGZvciAoY29uc3QgdiBvZiB5KVxuICAgIGlmICgheC5oYXModikpIHJldHVybiBmYWxzZTtcbiAgcmV0dXJuIHRydWU7XG59XG5cblxuXG5cbi8vIEZJTkRcbi8vIC0tLS1cblxuLyoqXG4gKiBDaGVjayBpZiBzZXQgaGFzIGEgdmFsdWUuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIHYgc2VhcmNoIHZhbHVlXG4gKiBAcmV0dXJucyB2IOKIiCB4P1xuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzPFQ+KHg6IFNldDxUPiwgdjogVCk6IGJvb2xlYW4ge1xuICByZXR1cm4geC5oYXModik7XG59XG5cblxuLyoqXG4gKiBGaW5kIGZpcnN0IHZhbHVlIHBhc3NpbmcgYSB0ZXN0IChkZWZhdWx0IG9yZGVyKS5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgdiwgeClcbiAqIEByZXR1cm5zIGZpcnN0IHYgfCBmdCh2KSA9IHRydWU7IHYg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmQ8VD4oeDogU2V0PFQ+LCBmdDogVGVzdEZ1bmN0aW9uPFQ+KTogVCB8IHVuZGVmaW5lZCB7XG4gIGZvciAoY29uc3QgdiBvZiB4KVxuICAgIGlmIChmdCh2LCB2LCB4KSkgcmV0dXJuIHY7XG59XG5leHBvcnQge2ZpbmQgYXMgc2VhcmNofTtcblxuXG4vKipcbiAqIEZpbmQgYWxsIHZhbHVlcyBwYXNzaW5nIGEgdGVzdC5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgdiwgeClcbiAqIEByZXR1cm5zIFt24oKALCB24oKBLCAuLi5dIHwgZnQoduG1oikgPSB0cnVlOyB24bWiIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kQWxsPFQ+KHg6IFNldDxUPiwgZnQ6IFRlc3RGdW5jdGlvbjxUPik6IFRbXSB7XG4gIGNvbnN0IGEgPSBbXTtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgaWYgKGZ0KHYsIHYsIHgpKSBhLnB1c2godik7XG4gIHJldHVybiBhO1xufVxuZXhwb3J0IHtmaW5kQWxsIGFzIHNlYXJjaEFsbH07XG5cblxuXG5cbi8vIEZVTkNUSU9OQUxcbi8vIC0tLS0tLS0tLS1cblxuLyoqXG4gKiBDYWxsIGEgZnVuY3Rpb24gZm9yIGVhY2ggdmFsdWUuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZwIHByb2Nlc3MgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JFYWNoPFQ+KHg6IFNldDxUPiwgZnA6IFByb2Nlc3NGdW5jdGlvbjxUPik6IHZvaWQge1xuICBmb3IgKGNvbnN0IHYgb2YgeClcbiAgICBmcCh2LCB2LCB4KTtcbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIGFueSB2YWx1ZSBzYXRpc2ZpZXMgYSB0ZXN0LlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCB2LCB4KVxuICogQHJldHVybnMgdHJ1ZSBpZiBmdCh24bWiKSA9IHRydWUgZm9yIHNvbWUgduG1oiDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gc29tZTxUPih4OiBTZXQ8VD4sIGZ0OiBUZXN0RnVuY3Rpb248VD4gfCBudWxsPW51bGwpOiBib29sZWFuIHtcbiAgZnQgPSBmdCB8fCBJREVOVElUWSBhcyBUZXN0RnVuY3Rpb248VD47XG4gIGZvciAoY29uc3QgdiBvZiB4KVxuICAgIGlmIChmdCh2LCB2LCB4KSkgcmV0dXJuIHRydWU7XG4gIHJldHVybiBmYWxzZTtcbn1cblxuXG4vKipcbiAqIENoZWNrIGlmIGFsbCB2YWx1ZXMgc2F0aXNmeSBhIHRlc3QuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyB0cnVlIGlmIGZ0KHbhtaIpID0gdHJ1ZSBmb3IgYWxsIHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV2ZXJ5PFQ+KHg6IFNldDxUPiwgZnQ6IFRlc3RGdW5jdGlvbjxUPiB8IG51bGw9bnVsbCk6IGJvb2xlYW4ge1xuICBmdCA9IGZ0IHx8IElERU5USVRZIGFzIFRlc3RGdW5jdGlvbjxUPjtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgaWYgKCFmdCh2LCB2LCB4KSkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuXG4vKipcbiAqIFRyYW5zZm9ybSB2YWx1ZXMgb2YgYSBzZXQuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgdiwgeClcbiAqIEByZXR1cm5zIFxce2ZtKHbigoApLCBmbSh24oKBKSwgLi4uXFx9IHwgduG1oiDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gbWFwPFQsIFU9VD4oeDogU2V0PFQ+LCBmbTogTWFwRnVuY3Rpb248VCwgVHxVPik6IFNldDxUfFU+IHtcbiAgY29uc3QgYSA9IG5ldyBTZXQ8VHxVPigpO1xuICBmb3IgKGNvbnN0IHYgb2YgeClcbiAgICBhLmFkZChmbSh2LCB2LCB4KSk7XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogVHJhbnNmb3JtIHZhbHVlcyBvZiBhIHNldC5cbiAqIEBwYXJhbSB4IGEgc2V0ICh1cGRhdGVkKVxuICogQHBhcmFtIGZtIG1hcCBmdW5jdGlvbiAodiwgdiwgeClcbiAqIEByZXR1cm5zIHggPSBcXHtmbSh24oKAKSwgZm0oduKCgSksIC4uLlxcfSB8IHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcCQ8VD4oeDogU2V0PFQ+LCBmbTogTWFwRnVuY3Rpb248VCwgVD4pOiBTZXQ8VD4ge1xuICBjb25zdCB2czogVFtdID0gW107XG4gIGZvciAoY29uc3QgdiBvZiB4KVxuICAgIHZzLnB1c2goZm0odiwgdiwgeCkpO1xuICB4LmNsZWFyKCk7XG4gIHJldHVybiBjb25jYXQkKHgsIHZzKTtcbn1cblxuXG4vKipcbiAqIFJlZHVjZSB2YWx1ZXMgb2Ygc2V0IHRvIGEgc2luZ2xlIHZhbHVlLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBmciByZWR1Y2UgZnVuY3Rpb24gKGFjYywgdiwgdiwgeClcbiAqIEBwYXJhbSBhY2MgaW5pdGlhbCB2YWx1ZVxuICogQHJldHVybnMgZnIoZnIoYWNjLCB24oKAKSwgduKCgSkuLi4gfCBmcihhY2MsIHbigoApID0gduKCgCBpZiBhY2Mgbm90IGdpdmVuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWR1Y2U8VCwgVT1UPih4OiBTZXQ8VD4sIGZyOiBSZWR1Y2VGdW5jdGlvbjxULCBUfFU+LCBhY2M/OiBUfFUpOiBUfFUge1xuICBsZXQgaW5pdCA9IGFyZ3VtZW50cy5sZW5ndGggPD0gMjtcbiAgZm9yIChjb25zdCB2IG9mIHgpIHtcbiAgICBpZiAoaW5pdCkgeyBhY2MgPSB2OyBpbml0ID0gZmFsc2U7IH1cbiAgICBlbHNlIGFjYyA9IGZyKGFjYyBhcyBUfFUsIHYsIHYsIHgpO1xuICB9XG4gIHJldHVybiBhY2MgYXMgVHxVO1xufVxuXG5cbi8qKlxuICogS2VlcCB2YWx1ZXMgd2hpY2ggcGFzcyBhIHRlc3QuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyBcXHt24oKALCB24oKBLCAuLi5cXH0gfCBmdCh24bWiKSA9IHRydWU7IHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlcjxUPih4OiBTZXQ8VD4sIGZ0OiBUZXN0RnVuY3Rpb248VD4pOiBTZXQ8VD4ge1xuICBjb25zdCBhID0gbmV3IFNldDxUPigpO1xuICBmb3IgKGNvbnN0IHYgb2YgeClcbiAgICBpZiAoZnQodiwgdiwgeCkpIGEuYWRkKHYpO1xuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEtlZXAgdmFsdWVzIHdoaWNoIHBhc3MgYSB0ZXN0LlxuICogQHBhcmFtIHggYSBzZXQgKHVwZGF0ZWQpXG4gKiBAcGFyYW0gZnQgdGVzdCBmdW5jdGlvbiAodiwgdiwgeClcbiAqIEByZXR1cm5zIHggPSBcXHt24oKALCB24oKBLCAuLi5cXH0gfCBmdCh24bWiKSA9IHRydWU7IHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlciQ8VD4oeDogU2V0PFQ+LCBmdDogVGVzdEZ1bmN0aW9uPFQ+KTogU2V0PFQ+IHtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgaWYgKCFmdCh2LCB2LCB4KSkgeC5kZWxldGUodik7XG4gIHJldHVybiB4O1xufVxuXG5cbi8qKlxuICogRGlzY2FyZCB2YWx1ZXMgd2hpY2ggcGFzcyBhIHRlc3QuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyBcXHt24oKALCB24oKBLCAuLi5cXH0gfCBmdCh24bWiKSA9IGZhbHNlOyB24bWiIOKIiCB4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWplY3Q8VD4oeDogU2V0PFQ+LCBmdDogVGVzdEZ1bmN0aW9uPFQ+KTogU2V0PFQ+IHtcbiAgY29uc3QgYSA9IG5ldyBTZXQ8VD4oKTtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgaWYgKCFmdCh2LCB2LCB4KSkgYS5hZGQodik7XG4gIHJldHVybiBhO1xufVxuXG5cbi8qKlxuICogRGlzY2FyZCB2YWx1ZXMgd2hpY2ggcGFzcyBhIHRlc3QuXG4gKiBAcGFyYW0geCBhIHNldCAodXBkYXRlZClcbiAqIEBwYXJhbSBmdCB0ZXN0IGZ1bmN0aW9uICh2LCB2LCB4KVxuICogQHJldHVybnMgeCA9IFxce3bigoAsIHbigoEsIC4uLlxcfSB8IGZ0KHbhtaIpID0gZmFsc2U7IHbhtaIg4oiIIHhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlamVjdCQ8VD4oeDogU2V0PFQ+LCBmdDogVGVzdEZ1bmN0aW9uPFQ+KTogU2V0PFQ+IHtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgaWYgKGZ0KHYsIHYsIHgpKSB4LmRlbGV0ZSh2KTtcbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBGbGF0dGVuIG5lc3RlZCBzZXQgdG8gZ2l2ZW4gZGVwdGguXG4gKiBAcGFyYW0geCBhIG5lc3RlZCBzZXRcbiAqIEBwYXJhbSBuIG1heGltdW0gZGVwdGggWy0xIOKHkiBhbGxdXG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCB2LCB4KVxuICogQHBhcmFtIGZ0IGZsYXR0ZW4gdGVzdCBmdW5jdGlvbiAodiwgdiwgeCkgW2lzXVxuICogQHJldHVybnMgZmxhdCBzZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZsYXQ8VD11bmtub3duPih4OiBTZXQ8VD4sIG46IG51bWJlcj0tMSwgZm06IE1hcEZ1bmN0aW9uPFQsIHVua25vd24+IHwgbnVsbD1udWxsLCBmdDogVGVzdEZ1bmN0aW9uPFQ+IHwgbnVsbD1udWxsKTogU2V0PHVua25vd24+IHtcbiAgZm0gPSBmbSB8fCBJREVOVElUWTtcbiAgZnQgPSBmdCB8fCBpcztcbiAgcmV0dXJuIGZsYXRUbyQobmV3IFNldCgpLCB4LCBuLCBmbSwgZnQpO1xufVxuXG5mdW5jdGlvbiBmbGF0VG8kPFQ9dW5rbm93bj4oYTogU2V0PHVua25vd24+LCB4OiBTZXQ8VD4sIG46IG51bWJlciwgZm06IE1hcEZ1bmN0aW9uPFQsIHVua25vd24+LCBmdDogVGVzdEZ1bmN0aW9uPFQ+KTogU2V0PHVua25vd24+IHtcbiAgZm9yIChjb25zdCB2IG9mIHgpIHtcbiAgICBjb25zdCB2MSA9IGZtKHYsIHYsIHgpO1xuICAgIGlmIChuIT09MCAmJiBmdCh2MSBhcyBULCB2MSBhcyBULCB4KSkgZmxhdFRvJChhLCB2MSBhcyBTZXQ8VD4sIG4tMSwgZm0sIGZ0KTtcbiAgICBlbHNlIGEuYWRkKHYxKTtcbiAgfVxuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIEZsYXR0ZW4gbmVzdGVkIHNldCwgYmFzZWQgb24gbWFwIGZ1bmN0aW9uLlxuICogQHBhcmFtIHggYSBuZXN0ZWQgc2V0XG4gKiBAcGFyYW0gZm0gbWFwIGZ1bmN0aW9uICh2LCB2LCB4KVxuICogQHBhcmFtIGZ0IGZsYXR0ZW4gdGVzdCBmdW5jdGlvbiAodiwgdiwgeCkgW2lzXVxuICogQHJldHVybnMgZmxhdCBzZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZsYXRNYXA8VD11bmtub3duPih4OiBTZXQ8VD4sIGZtOiBNYXBGdW5jdGlvbjxULCB1bmtub3duPiB8IG51bGw9bnVsbCwgZnQ6IFRlc3RGdW5jdGlvbjxUPiB8IG51bGw9bnVsbCk6IFNldDx1bmtub3duPiB7XG4gIGZtID0gZm0gfHwgSURFTlRJVFk7XG4gIGZ0ID0gZnQgfHwgaXM7XG4gIGNvbnN0IGEgID0gbmV3IFNldCgpO1xuICBmb3IgKGNvbnN0IHYgb2YgeCkge1xuICAgIGNvbnN0IHcgPSBmbSh2LCB2LCB4KTtcbiAgICBpZiAoZnQodyBhcyBULCB3IGFzIFQsIHgpKSBjb25jYXQkKGEsIHcgYXMgU2V0PHVua25vd24+KTtcbiAgICBlbHNlIGEuYWRkKHcpO1xuICB9XG4gIHJldHVybiBhO1xufVxuXG5cblxuXG4vLyBNQU5JUFVMQVRJT05cbi8vIC0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIFNlZ3JlZ2F0ZSB2YWx1ZXMgYnkgdGVzdCByZXN1bHQuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIGZ0IHRlc3QgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyBbc2F0aXNmaWVzLCBkb2VzbnRdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJ0aXRpb248VD4oeDogU2V0PFQ+LCBmdDogVGVzdEZ1bmN0aW9uPFQ+KTogW1NldDxUPiwgU2V0PFQ+XSB7XG4gIGNvbnN0IHQgPSBuZXcgU2V0PFQ+KCk7XG4gIGNvbnN0IGYgPSBuZXcgU2V0PFQ+KCk7XG4gIGZvciAoY29uc3QgdiBvZiB4KSB7XG4gICAgaWYgKGZ0KHYsIHYsIHgpKSB0LmFkZCh2KTtcbiAgICBlbHNlIGYuYWRkKHYpO1xuICB9XG4gIHJldHVybiBbdCwgZl07XG59XG5cblxuLyoqXG4gKiBTZWdyZWdhdGVzIHZhbHVlcyBieSBzaW1pbGFyaXR5LlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHYsIHYsIHgpXG4gKiBAcmV0dXJucyBNYXAgXFx7a2V5IOKHkiB2YWx1ZXNcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnRpdGlvbkFzPFQsIFU9VD4oeDogU2V0PFQ+LCBmbTogTWFwRnVuY3Rpb248VCwgVHxVPik6IE1hcDxUfFUsIFNldDxUPj4ge1xuICBmbSA9IGZtIHx8IElERU5USVRZO1xuICBjb25zdCBhID0gbmV3IE1hcCgpO1xuICBmb3IgKGNvbnN0IHYgb2YgeCkge1xuICAgIGNvbnN0IHYxID0gZm0odiwgdiwgeCk7XG4gICAgaWYgKCFhLmhhcyh2MSkpIGEuc2V0KHYxLCBuZXcgU2V0KCkpO1xuICAgIGEuZ2V0KHYxKS5hZGQodik7XG4gIH1cbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBCcmVhayBzZXQgaW50byBjaHVua3Mgb2YgZ2l2ZW4gc2l6ZS5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0gbiBjaHVuayBzaXplIFsxXVxuICogQHBhcmFtIHMgY2h1bmsgc3RlcCBbbl1cbiAqIEByZXR1cm5zIFt4WzAuLm5dLCB4W3MuLnMrbl0sIHhbMnMuLjJzK25dLCAuLi5dXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaHVuazxUPih4OiBTZXQ8VD4sIG46IG51bWJlcj0xLCBzOiBudW1iZXI9bik6IFNldDxUPltdIHtcbiAgcmV0dXJuIGFycmF5Q2h1bmsoWy4uLnhdLCBuICxzKS5tYXAoYyA9PiBuZXcgU2V0KGMpKTtcbn1cblxuXG5cblxuLy8gQ09NQklORVxuLy8gLS0tLS0tLVxuXG4vKipcbiAqIEFwcGVuZCB2YWx1ZXMgZnJvbSBzZXRzLlxuICogQHBhcmFtIHhzIHNldHNcbiAqIEByZXR1cm5zIHjigoAg4oiqIHjigoEg4oiqIC4uLiB8IFt44oKALCB44oKBLCAuLi5dID0geHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbmNhdDxUPiguLi54czogU2V0PFQ+W10pOiBTZXQ8VD4ge1xuICByZXR1cm4gY29uY2F0JChuZXcgU2V0KCksIC4uLnhzKTtcbn1cblxuXG4vKipcbiAqIEFwcGVuZCB2YWx1ZXMgZnJvbSBzZXRzLlxuICogQHBhcmFtIHggYSBzZXQgKHVwZGF0ZWQpXG4gKiBAcGFyYW0geXMgb3RoZXIgc2V0c1xuICogQHJldHVybnMgeCA9IHgg4oiqIHnigoAg4oiqIHnigoEg4oiqIC4uLiB8IFt54oKALCB54oKBLCAuLi5dID0geXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbmNhdCQ8VD4oeDogU2V0PFQ+LCAuLi55czogSXRlcmFibGU8VD5bXSk6IFNldDxUPiB7XG4gIGZvciAoY29uc3QgeSBvZiB5cykge1xuICAgIGZvciAoY29uc3QgdiBvZiB5KVxuICAgICAgeC5hZGQodik7XG4gIH1cbiAgcmV0dXJuIHg7XG59XG5cblxuLyoqXG4gKiBKb2luIHZhbHVlcyB0b2dldGhlciBpbnRvIGEgc3RyaW5nLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSBzZXAgc2VwYXJhdG9yIFssXVxuICogQHJldHVybnMgXCIkXFx7duKCgFxcfSRcXHtzZXBcXH0kXFx7duKCgVxcfS4uLlwiIHwgduG1oiDiiIggeFxuICovXG5leHBvcnQgZnVuY3Rpb24gam9pbjxUPih4OiBTZXQ8VD4sIHNlcDogc3RyaW5nPVwiLFwiKTogc3RyaW5nIHtcbiAgcmV0dXJuIFsuLi54XS5qb2luKHNlcCk7XG59XG5cblxuXG5cbi8vIFNFVCBPUEVSQVRJT05TXG4vLyAtLS0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIENoZWNrIGlmIHNldHMgaGF2ZSBubyB2YWx1ZSBpbiBjb21tb24uXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIHkgYW5vdGhlciBzZXRcbiAqIEByZXR1cm5zIHgg4oipIHkgPSDOpj9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRGlzam9pbnQ8VD4oeDogU2V0PFQ+LCB5OiBJdGVyYWJsZTxUPik6IGJvb2xlYW4ge1xuICBmb3IgKGNvbnN0IHYgb2YgeSlcbiAgICBpZiAoeC5oYXModikpIHJldHVybiBmYWxzZTtcbiAgcmV0dXJuIHRydWU7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gdmFsdWVzIHByZXNlbnQgaW4gYW55IHNldC5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0geSBhbm90aGVyIHNldFxuICogQHJldHVybnMgeCDiiKogeSA9IFxce3YgfCB2IOKIiCB4IG9yIHYg4oiIIHlcXH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVuaW9uPFQ+KHg6IEl0ZXJhYmxlPFQ+LCB5OiBJdGVyYWJsZTxUPik6IFNldDxUPiB7XG4gIHJldHVybiBjb25jYXQkKG5ldyBTZXQoKSwgeCwgeSk7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gdmFsdWVzIHByZXNlbnQgaW4gYW55IHNldC5cbiAqIEBwYXJhbSB4IGEgc2V0ICh1cGRhdGVkKVxuICogQHBhcmFtIHkgYW5vdGhlciBzZXRcbiAqIEByZXR1cm5zIHggPSB4IOKIqiB5ID0gXFx7diB8IHYg4oiIIHggb3IgdiDiiIggeVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5pb24kPFQ+KHg6IFNldDxUPiwgeTogSXRlcmFibGU8VD4pOiBTZXQ8VD4ge1xuICByZXR1cm4gY29uY2F0JCh4LCB5KTtcbn1cblxuXG4vKipcbiAqIE9idGFpbiB2YWx1ZXMgcHJlc2VudCBpbiBib3RoIHNldHMuXG4gKiBAcGFyYW0geCBhIHNldFxuICogQHBhcmFtIHkgYW5vdGhlciBzZXRcbiAqIEByZXR1cm5zIHgg4oipIHkgPSBcXHt2IHwgdiDiiIggeCwgdiDiiIggeVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gaW50ZXJzZWN0aW9uPFQ+KHg6IFNldDxUPiwgeTogSXRlcmFibGU8VD4pOiBTZXQ8VD4ge1xuICBjb25zdCBhID0gbmV3IFNldDxUPigpO1xuICBmb3IgKGNvbnN0IHYgb2YgeSlcbiAgICBpZiAoeC5oYXModikpIGEuYWRkKHYpO1xuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIE9idGFpbiB2YWx1ZXMgcHJlc2VudCBpbiBib3RoIHNldHMuXG4gKiBAcGFyYW0geCBhIHNldCAodXBkYXRlZClcbiAqIEBwYXJhbSB5IGFub3RoZXIgc2V0XG4gKiBAcmV0dXJucyB4ID0geCDiiKkgeSA9IFxce3YgfCB2IOKIiCB4LCB2IOKIiCB5XFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbnRlcnNlY3Rpb24kPFQ+KHg6IFNldDxUPiwgeTogU2V0PFQ+KTogU2V0PFQ+IHtcbiAgZm9yIChjb25zdCB2IG9mIHgpXG4gICAgaWYgKCF5Lmhhcyh2KSkgeC5kZWxldGUodik7XG4gIHJldHVybiB4O1xufVxuXG5cbi8qKlxuICogT2J0YWluIHZhbHVlcyBub3QgcHJlc2VudCBpbiBhbm90aGVyIHNldC5cbiAqIEBwYXJhbSB4IGEgc2V0XG4gKiBAcGFyYW0geSBhbm90aGVyIHNldFxuICogQHJldHVybnMgeCAtIHkgPSBcXHt2IHwgdiDiiIggeCwgdiDiiIkgeVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gZGlmZmVyZW5jZTxUPih4OiBTZXQ8VD4sIHk6IFNldDxUPik6IFNldDxUPiB7XG4gIGNvbnN0IGEgPSBuZXcgU2V0PFQ+KCk7XG4gIGZvciAoY29uc3QgdiBvZiB4KVxuICAgIGlmICgheS5oYXModikpIGEuYWRkKHYpO1xuICByZXR1cm4gYTtcbn1cblxuXG4vKipcbiAqIE9idGFpbiB2YWx1ZXMgbm90IHByZXNlbnQgaW4gYW5vdGhlciBzZXQuXG4gKiBAcGFyYW0geCBhIHNldCAodXBkYXRlZClcbiAqIEBwYXJhbSB5IGFub3RoZXIgc2V0XG4gKiBAcmV0dXJucyB4ID0geCAtIHkgPSBcXHt2IHwgdiDiiIggeCwgdiDiiIkgeVxcfVxuICovXG5leHBvcnQgZnVuY3Rpb24gZGlmZmVyZW5jZSQ8VD4oeDogU2V0PFQ+LCB5OiBJdGVyYWJsZTxUPik6IFNldDxUPiB7XG4gIGZvciAoY29uc3QgdiBvZiB5KVxuICAgIHguZGVsZXRlKHYpO1xuICByZXR1cm4geDtcbn1cblxuXG4vKipcbiAqIE9idGFpbiB2YWx1ZXMgbm90IHByZXNlbnQgaW4gYm90aCBzZXRzLlxuICogQHBhcmFtIHggYSBzZXRcbiAqIEBwYXJhbSB5IGFub3RoZXIgc2V0XG4gKiBAcmV0dXJucyB4LXkg4oiqIHkteFxuICovXG5leHBvcnQgZnVuY3Rpb24gc3ltbWV0cmljRGlmZmVyZW5jZTxUPih4OiBTZXQ8VD4sIHk6IFNldDxUPik6IFNldDxUPiB7XG4gIGNvbnN0IGEgPSBuZXcgU2V0PFQ+KCk7XG4gIGZvciAoY29uc3QgdiBvZiB4KVxuICAgIGlmICgheS5oYXModikpIGEuYWRkKHYpO1xuICBmb3IgKGNvbnN0IHYgb2YgeSlcbiAgICBpZiAoIXguaGFzKHYpKSBhLmFkZCh2KTtcbiAgcmV0dXJuIGE7XG59XG5cblxuLyoqXG4gKiBPYnRhaW4gdmFsdWVzIG5vdCBwcmVzZW50IGluIGJvdGggc2V0cy5cbiAqIEBwYXJhbSB4IGEgc2V0ICh1cGRhdGVkKVxuICogQHBhcmFtIHkgYW5vdGhlciBzZXRcbiAqIEByZXR1cm5zIHggPSB4LXkg4oiqIHkteFxuICovXG5leHBvcnQgZnVuY3Rpb24gc3ltbWV0cmljRGlmZmVyZW5jZSQ8VD4oeDogU2V0PFQ+LCB5OiBJdGVyYWJsZTxUPik6IFNldDxUPiB7XG4gIGZvciAoY29uc3QgdiBvZiB5KSB7XG4gICAgaWYgKHguaGFzKHYpKSB4LmRlbGV0ZSh2KTtcbiAgICBlbHNlIHguYWRkKHYpO1xuICB9XG4gIHJldHVybiB4O1xufVxuXG5cbi8qKlxuICogTGlzdCBjYXJ0ZXNpYW4gcHJvZHVjdCBvZiBzZXRzLlxuICogQHBhcmFtIHhzIHNldHNcbiAqIEBwYXJhbSBmbSBtYXAgZnVuY3Rpb24gKHZzLCB2cylcbiAqIEByZXR1cm5zIHjigoAgw5cgeOKCgSDDlyAuLi4gPSBcXHtcXHt24oKALCB24oKBLCAuLi5cXH0gfCB24oKAIOKIiCB44oKALCB24oKBIOKIiCB44oKBLCAuLi5dXFx9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiogY2FydGVzaWFuUHJvZHVjdDxULCBVPVNldDxUPj4oeHM6IFNldDxUPltdLCBmbTogTWFwRnVuY3Rpb248U2V0PFQ+LCBTZXQ8VD58VT4gfCBudWxsPW51bGwpOiBJdGVyYWJsZUl0ZXJhdG9yPFNldDxUPnxVPiB7XG4gIGZtID0gZm0gfHwgSURFTlRJVFk7XG4gIGNvbnN0IFhTID0geHMubGVuZ3RoO1xuICBjb25zdCB5cyA9IHhzLm1hcCh4ID0+IFsuLi54XSk7XG4gIGNvbnN0IGxzID0geXMubWFwKHZzID0+IHZzLmxlbmd0aCk7XG4gIGNvbnN0IGlzID0geXMubWFwKF92cyA9PiAwKTtcbiAgd2hpbGUgKHRydWUpIHtcbiAgICBjb25zdCBhID0gbmV3IFNldDxUPigpO1xuICAgIGZvciAobGV0IG49MDsgbjxYUzsgKytuKSB7XG4gICAgICBjb25zdCBpICA9IGlzW25dO1xuICAgICAgY29uc3QgdnMgPSB5c1tuXSwgdiA9IHZzW2ldO1xuICAgICAgYS5hZGQodik7XG4gICAgfVxuICAgIHlpZWxkIGZtKGEsIGEsIG51bGwpO1xuICAgIGxldCByID0gWFMtMTtcbiAgICBmb3IgKDsgcj49MDsgLS1yKSB7XG4gICAgICBpZiAoKytpc1tyXSA8IGxzW3JdKSBicmVhaztcbiAgICAgIGlzW3JdID0gMDtcbiAgICB9XG4gICAgaWYgKHI8MCkgYnJlYWs7XG4gIH1cbn1cbmV4cG9ydCBkZWZhdWx0IGNhcnRlc2lhblByb2R1Y3Q7XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsU0FDRSxRQUFRLEVBQ1IsT0FB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