UNPKG

extra-function

Version:

Functions are one of the fundamental building blocks in JavaScript.

1,077 lines 75.4 kB
//#region TYPES
/**
 * unknown function type.
 * @params args arguments
 * @returns unknown value
 */ //#endregion
//#region CONSTANTS
/**
 * Do nothing.
 * @param _args arguments (ignored)
 * @example
 * ```javascript
 * xfunction.NOOP(1, 2);
 * // → undefined
 *
 * xfunction.NOOP('a', 'b');
 * // → undefined
 * ```
 */ export function NOOP(..._args) {}
// - https://lodash.com/docs/4.17.15#noop
/**
 * Return false.
 * @param _args arguments (ignored)
 * @returns false.
 * @example
 * ```javascript
 * xfunction.FALSE();
 * // → false
 * ```
 */ export function FALSE(..._args) {
  return false;
}
// - https://www.npmjs.com/package/boolbase
/**
 * Return true.
 * @param _args arguments (ignored)
 * @returns true.
 * @example
 * ```javascript
 * xfunction.TRUE();
 * // → true
 * ```
 */ export function TRUE(..._args) {
  return true;
}
// - https://www.npmjs.com/package/boolbase
/**
 * Return the same (first) value.
 * @param v a value
 * @returns v
 * @example
 * ```javascript
 * xfunction.IDENTITY(1);
 * // → 1
 *
 * xfunction.IDENTITY('a');
 * // → 'a'
 * ```
 */ export function IDENTITY(v) {
  return v;
}
/**
 * Compare two values.
 * @param a a value
 * @param b another value
 * @returns a<b: -1, a=b: 0, a>b: 1
 * @example
 * ```javascript
 * xfunction.COMPARE(1, 2);
 * // → -1
 *
 * xfunction.COMPARE(2, 1);
 * // → 1
 *
 * xfunction.COMPARE(1, 1);
 * // → 0
 */ export function COMPARE(a, b) {
  return a < b ? -1 : a > b ? 1 : 0;
}
/**
 * Return the arguments passed as a array.
 * @param args arguments
 * @returns [...args]
 * @example
 * ```javascript
 * xfunction.ARGUMENTS(1, 2);
 * // → [1, 2]
 *
 * xfunction.ARGUMENTS('a', 'b');
 * // → ['a', 'b']
 * ```
 */ export function ARGUMENTS(...args) {
  return args;
}
//#endregion
//#region METHODS (BUILTIN)
//#region ABOUT
/**
 * Get the name of a function.
 * @param x a function
 * @returns name
 * @example
 * ```javascript
 * import {delay, debounce} from "jsr:@nodef/extra-function";
 *
 * xfunction.name(delay);
 * // → 'delay'
 *
 * xfunction.name(debounce);
 * // → 'debounce'
 * ```
 */ export function name(x) {
  return x.name;
}
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
// - https://www.npmjs.com/package/fn-name
/**
 * Get the number of parameters of a function.
 * @param x a function
 * @returns |[p, q, ...]| | x(p, q, ...)
 * @example
 * ```javascript
 * xfunction.length(() => 0);
 * // → 0
 *
 * xfunction.length((x, y) => 0);
 * // → 2
 * ```
 */ export function length(x) {
  return x.length;
}
export { length as arity };
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length
//#endregion
//#region BINDING
/**
 * Bind this-object, and optional prefix arguments to a function.
 * @param x a function
 * @param ths this object to bind
 * @param prefix prefix arguments
 * @returns (...args) => this.x(...prefix, ...args)
 * @example
 * ```javascript
 * var array  = [1];
 * var fn = xfunction.bind(Array.prototype.push, array);
 * fn(2, 3, 4);  // push(2, 3, 4)
 * array;
 * // → [1, 2, 3, 4]
 *
 * var array  = [1, 2, 3, 4];
 * var fn = xfunction.bind(Array.prototype.splice, array, 1);
 * fn(2);  // splice(1, 2)
 * array;
 * // → [1, 4]
 * ```
 */ export function bind(x, ths, ...prefix) {
  return x.bind(ths, ...prefix);
}
// - https://underscorejs.org/#bind
// - https://lodash.com/docs/4.17.15#bind
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
//#endregion
//#region INVOCATION
/**
 * Invoke a function with specified this-object, and arguments provided individually.
 * @param x a function
 * @param ths this object to invoke with
 * @param args arguments
 * @returns this.x(...args)
 * @example
 * ```javascript
 * var array = [1];
 * xfunction.call(Array.prototype.push, array, 2, 3, 4);  // push(2, 3, 4)
 * array;
 * // → [1, 2, 3, 4]
 *
 * var array = [1, 2, 3, 4];
 * xfunction.call(Array.prototype.splice, array, 1, 2);  // splice(1, 2)
 * array;
 * // → [1, 4]
 * ```
 */ export function call(x, ths = null, ...args) {
  return x.call(ths, ...args);
}
/**
 * Invoke a function with specified this-object, and arguments provided as an array.
 * @param x a function
 * @param ths this object to invoke with
 * @param args arguments array
 * @returns this.x(...args)
 * @example
 * ```javascript
 * var array = [1];
 * xfunction.apply(Array.prototype.push, array, [2, 3, 4]);  // push(2, 3, 4)
 * array;
 * // → [1, 2, 3, 4]
 *
 * var array = [1, 2, 3, 4];
 * xfunction.apply(Array.prototype.splice, array, [1, 2]);  // splice(1, 2)
 * array;
 * // → [1, 4]
 * ```
 */ export function apply(x, ths = null, args) {
  return x.apply(ths, args);
}
//#endregion
//#endregion
//#region METHODS (CUSTOM)
//#region ABOUT
/**
 * Check if value is a function.
 * @param v a value
 * @returns is function?
 * @example
 * ```javascript
 * xfunction.is(Object.keys);
 * // → true
 *
 * xfunction.is(() => 0);
 * // → true
 *
 * xfunction.is(async () => 0);
 * // → true
 *
 * xfunction.is(0);
 * // → false
 * ```
 */ export function is(v) {
  return typeof v === "function";
}
// - https://www.npmjs.com/package/is-function
/**
 * Check if value is an async function.
 * @param v a value
 * @returns is async function?
 * @example
 * ```javascript
 * xfunction.isAsync(async () => 0);
 * // → true
 *
 * xfunction.isAsync(() => 0);
 * // → false
 * ```
 */ export function isAsync(v) {
  const AsyncFunction = (async function() {}).constructor;
  return v instanceof AsyncFunction;
}
// - https://www.npmjs.com/package/is-async-function
// - https://www.npmjs.com/package/is-callback-function
// - https://davidwalsh.name/javascript-detect-async-function
// - https://stackoverflow.com/questions/38508420/how-to-know-if-a-function-is-async
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction
/**
 * Check if value is a generator function.
 * @param v a value
 * @returns is generator function?
 * @example
 * ```javascript
 * function* naturalNumbers() {
 *   for (var i=0;; ++i)
 *     yield i;
 * }
 *
 * xfunction.isGenerator(naturalNumbers);
 * // → true
 *
 * xfunction.isGenerator(() => 0);
 * // → false
 * ```
 */ export function isGenerator(v) {
  const GeneratorFunction = (function*() {}).constructor;
  return v instanceof GeneratorFunction;
}
// - https://www.npmjs.com/package/is-generator
// - https://www.npmjs.com/package/is-generator-fn
// - https://www.npmjs.com/package/is-generator-function
// - https://stackoverflow.com/questions/16754956/check-if-function-is-a-generator
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction
//#endregion
//#region CONTEXT
/**
 * Contextify a function by accepting the first parameter as this-object.
 * @param x a function
 * @returns (...args) => x(this, ...args)
 * @example
 * ```javascript
 * function count(x, value) {
 *   var a = 0;
 *   for (var v of x)
 *     if (v===value) ++a;
 *   return a;
 * }
 *
 * var fn = xfunction.contextify(count);
 *
 * fn.call([6, 3, 4, 3], 3);
 * // → 2
 *
 * fn.call([6, 1, 4, 3], 3);
 * // → 1
 * ```
 */ export function contextify(x) {
  return function(...args) {
    return x(this, ...args);
  };
}
/**
 * Decontextify a function by accepting this-object as the first argument.
 * @param x a function
 * @returns (this, ...args) => this.x(...args)
 * @example
 * ```javascript
 * function count(value) {
 *   var a = 0;
 *   for (var v of this)
 *     if (v===value) ++a;
 *   return a;
 * }
 *
 * var fn = xfunction.decontextify(count);
 *
 * fn([6, 3, 4, 3], 3);
 * // → 2
 *
 * fn([6, 1, 4, 3], 3);
 * // → 1
 * ```
 */ export function decontextify(x) {
  return (ths = null, ...args)=>x.call(ths, ...args);
}
//#endregion
//#region RESULT MANIPULATION
/**
 * Generate a result-negated version of a function.
 * @param x a function
 * @returns (...args) => !x(...args)
 * @example
 * ```javascript
 * var fn = xfunction.negate(isFinite);
 * fn(Infinity)
 * // → true
 * fn(1)
 * // → false
 *
 * var fn = xfunction.negate(isNaN);
 * fn(1);
 * // → true
 * fn(NaN);
 * // → false
 * ```
 */ export function negate(x) {
  return (...args)=>!x(...args);
}
/**
 * Generate result-cached version of a function.
 * @param x a function
 * @param fr resolver ((...args) => unique key) [IDENTITY]
 * @param cache result cache [Map()]
 * @example
 * ```javascript
 * var calls = 0;
 *
 * function factorialRec(n: number) {
 *   if (n<=1) return 1;
 *   return n * factorialRec(n-1);
 * }
 *
 * function factorial(n: number) {
 *   ++calls;
 *   return factorialRec(n);
 * }
 *
 * var fn = xfunction.memoize(factorial);
 * fn(3);
 * // → 6
 * fn(4);
 * // → 24
 * fn(5);
 * // → 120
 * fn(3);
 * // → 6
 * fn(4);
 * // → 24
 * fn(5);
 * // → 120
 * calls;
 * // → 3
 *
 *
 * var calls = 0;
 *
 * function hypot(x: number, y: number) {
 *   ++calls;
 *   return Math.hypot(x, y);
 * }
 *
 * function resolver(x: number, y: number) {
 *   return 4093*y + x;  // a hash
 * }
 *
 * var fn = xfunction.memoize(hypot, resolver);
 * fn(3,  4);
 * // → 5
 * fn(6,  8);
 * // → 10
 * fn(5, 12);
 * // → 13
 * fn(3,  4);
 * // → 5
 * fn(6,  8);
 * // → 10
 * fn(5, 12);
 * // → 13
 * calls;
 * // → 3
 * ```
 */ export function memoize(x, fr = null, cache = null) {
  fr = fr || IDENTITY;
  cache = cache || new Map();
  return (...args)=>{
    const k = fr(...args);
    if (cache.has(k)) return cache.get(k);
    const v = x(...args);
    cache.set(k, v);
    return v;
  };
}
// - https://www.npmjs.com/package/memoizee
// - https://www.npmjs.com/package/memoizerific
//#endregion
//#region PARAMETER MANIPULATION
/**
 * Generate a parameter-reversed version of a function.
 * @param x a function
 * @returns (p, q, ...) => x(..., q, p)
 * @example
 * ```javascript
 * function divide(x, y) {
 *   return x/y;
 * }
 *
 * var fn = xfunction.reverse(divide);
 * fn(2, 4);
 * // → 2
 * fn(2, 6);
 * // → 3
 * fn(2, 8);
 * // → 4
 *
 *
 * var array = [1];
 *
 * function push(...args) {
 *   array.push(...args);
 * }
 *
 * var fn = xfunction.reverse(push);
 * fn(2, 3, 4);  // push(2, 3, 4) in reverse order
 * array;
 * // → [1, 4, 3, 2]
 * ```
 */ export function reverse(x) {
  return (...args)=>x(...args.reverse());
}
export { reverse as flip };
/**
 * Generate a (first) parameter-spreaded version of a function.
 * @param x a function
 * @returns (p, q, ...) => x([p, q, ...])
 * @example
 * ```javascript
 * function sum(x: number[]) {
 *   var a = 0;
 *   for (var v of x)
 *     a += v;
 *   return a;
 * }
 *
 * var fn = xfunction.spread(sum);
 * fn(1, 2, 3);  // sum([1, 2, 3])
 * // → 6
 *
 *
 * var array = [1];
 *
 * function concat(x: number[]) {
 *   return array.concat(x);
 * }
 *
 * var fn = xfunction.spread(concat);
 * fn(2, 3, 4);  // concat([2, 3, 4])
 * // → [1, 2, 3, 4]
 * ```
 */ export function spread(x) {
  return (...args)=>x(args);
}
/**
 * Generate a (first) parameter-collapsed version of a function.
 * @param x a function
 * @returns ([p, q, ...]) => x(p, q, ...)
 * @example
 * ```javascript
 * var fn = xfunction.unspread(Math.min);
 * fn([7, 4, 9]);  // Math.min(7, 4, 9)
 * // → 4
 *
 * var fn = xfunction.unspread((x, i, I) => x.slice(i, I));
 * fn([[1, 2, 3, 4], 2]);  // [1, 2, 3, 4].slice(2)
 * // → [3, 4]
 * ```
 */ export function unspread(x) {
  return (args)=>x(...args);
}
/**
 * Attach prefix arguments to leftmost parameters of a function.
 * @param x a function
 * @param prefix prefix arguments
 * @returns (...args) => x(...prefix, ...args)
 * @example
 * ```javascript
 * var fn = xfunction.attach(Math.min, 100);
 * fn(180, 130);  // Math.min(100, 180, 130)
 * // → 100
 *
 * var array = [1];
 * var fn = xfunction.attach((...vs) => array.push(...vs), 10, 10);
 * fn(1, 2, 3);  // array.push(10, 10, 1, 2, 3)
 * array;
 * // → [1, 10, 10, 1, 2, 3]
 * ```
 */ export function attach(x, ...prefix) {
  return (...args)=>x(...prefix, ...args);
}
export { attach as partial };
/**
 * Attach suffix arguments to rightmost parameters of a function.
 * @param x a function
 * @param suffix suffix arguments
 * @returns (...args) => x(...args, ...suffix)
 * @example
 * ```javascript
 * var fn = xfunction.attachRight(Math.min, 100);
 * fn(180, 130);  // Math.min(180, 130, 100)
 * // → 100
 *
 * var array = [1];
 * var fn = xfunction.attachRight((...vs) => array.push(...vs), 10, 10);
 * fn(1, 2, 3);  // array.push(1, 2, 3, 10, 10)
 * array;
 * // → [1, 1, 2, 3, 10, 10]
 * ```
 */ export function attachRight(x, ...suffix) {
  return (...args)=>x(...args, ...suffix);
}
export { attachRight as partialRight };
//#endregion
//#region FUNCTIONAL BEHAVIOUR
/**
 * Compose functions together, in applicative order.
 * @param xs functions (f, g)
 * @returns (f o g), or f(g(x))
 * @example
 * ```javascript
 * var fn = xfunction.compose(Math.sqrt, Math.abs);
 * fn(-64);  // Math.sqrt(Math.abs(-64))
 * // → 8
 *
 * var fn = xfunction.compose(Math.sqrt, Math.min);
 * fn(22, 9);  // Math.sqrt(Math.min(22, 9))
 * // → 3
 * ```
 */ export function compose(...xs) {
  return composeRight(...xs.reverse());
}
// - https://en.wikipedia.org/wiki/Function_composition
// - http://learnyouahaskell.com/higher-order-functions
// - https://www.npmjs.com/package/compose-function
/**
 * Compose functions together, such that result is piped forward.
 * @param xs functions (f, g)
 * @returns (f ▷ g), or g(f(x))
 * @example
 * ```javascript
 * var fn = xfunction.composeRight(Math.abs, Math.sqrt);
 * fn(-64);  // Math.sqrt(Math.abs(-64))
 * // → 8
 *
 * var fn = xfunction.composeRight(Math.min, Math.sqrt);
 * fn(22, 9);  // Math.sqrt(Math.min(22, 9))
 * // → 3
 * ```
 */ export function composeRight(...xs) {
  return (...args)=>{
    if (xs.length === 0) return;
    let a = xs[0](...args);
    for(let i = 1, I = xs.length; i < I; i++)a = xs[i](a);
    return a;
  };
}
// - https://stackoverflow.com/questions/1457140/haskell-composition-vs-fs-pipe-forward-operator
// - https://www.npmjs.com/package/chain-function
/**
 * Generate curried version of a function.
 * @param x a function
 * @param n number of parameters [all]
 * @returns (p)(q)(...) => x(p, q, ...)
 * @example
 * ```javascript
 * var sub = (x: number, y: number) => x - y;
 * var fn  = xfunction.curry(sub);
 * fn(2)(3);  // sub(2, 3)
 * // → -1
 *
 * var fn  = xfunction.curry(Math.min, 3);
 * fn(5)(8)(3);  // Math.min(5, 8, 3)
 * // → 3
 * ```
 */ export function curry(x, n = x.length) {
  return (...args)=>{
    if (args.length >= n) return x(...args);
    else return curry((...rest)=>x(...args, ...rest), n - args.length);
  };
}
// - https://www.npmjs.com/package/@spudly/curry
/**
 * Generate right-curried version of a function.
 * @param x a function
 * @param n number of parameters [all]
 * @returns (p)(q)(...) => x(..., q, p)
 * @example
 * ```javascript
 * var sub = (x: number, y: number) => x - y;
 * var fn  = xfunction.curryRight(sub);
 * fn(2)(3);  // sub(3, 2)
 * // → 1
 *
 * var array = [1];
 * var push2 = (x: number, y: number) => array.push(x, y);
 * var fn  = xfunction.curryRight(push2, 2);
 * fn(2)(3);  // push2(3, 2)
 * array;
 * // → [1, 3, 2]
 * ```
 */ export function curryRight(x, n = x.length) {
  return curry(reverse(x), n);
}
/**
 * Generate deferred version of a function, that executes after the current stack has cleared.
 * @param x a function
 * @returns (...args) => invocation control
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.defer(() => ++count);
 * fn();
 * fn();
 * // `count` incremented after 0s
 * // `count` incremented after 0s
 * ```
 */ export function defer(x) {
  return (...args)=>{
    let h = setTimeout(flush, 0);
    function clear() {
      clearTimeout(h);
      h = 0;
    }
    function flush() {
      x(...args);
      clear();
    }
    return {
      clear,
      flush
    };
  };
}
/**
 * Generate delayed version of a function.
 * @param x a function
 * @param t delay time (ms)
 * @returns (...args) => invocation control
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.delay(() => ++count, 500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * // `count` incremented after 0.5s
 * // `count` incremented after 1.5s
 *
 *
 * var count = 0;
 * var fn = xfunction.delay(() => ++count, 500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 3000);
 * // `count` incremented after 0.5s
 * // `count` incremented after 1.5s
 * // `count` incremented after 2.5s
 * // `count` incremented after 3.5s
 * ```
 */ export function delay(x, t) {
  return (...args)=>{
    let h = setTimeout(flush, t);
    function clear() {
      clearTimeout(h);
      h = 0;
    }
    function flush() {
      x(...args);
      clear();
    }
    return {
      clear,
      flush
    };
  };
}
//#endregion
//#region RATE CONTROL (COUNT)
/**
 * Generate restricted-use version of a function.
 * @param x a function
 * @param start usable from
 * @param end usable till (excluding) [-1 ⇒ end]
 * @returns (...args) => x(...args) from [start:end] calls
 * @example
 * ```javascript
 * var sum = 0;
 * var add = (x: number) => sum += x;
 * var fn  = xfunction.restrict(add, 0, 4);
 * for (var i=0; i<10; ++i)
 *   fn(i);
 * sum;  // 0 + 1 + 2 + 3
 * // → 6
 *
 *
 * var sum = 0;
 * var add = (x: number) => sum += x;
 * var fn  = xfunction.restrict(add, 4, 8);
 * for (var i=0; i<10; ++i)
 *   fn(i);
 * sum;  // 4 + 5 + 6 + 7
 * // → 22
 * ```
 */ export function restrict(x, start, end = -1) {
  let i = -1;
  return (...args)=>{
    if (++i < start === (i < end || end < 0)) return;
    return x(...args);
  };
}
// - https://www.npmjs.com/package/one-time
// - https://www.npmjs.com/package/onetime
// - https://www.npmjs.com/package/once
// - https://lodash.com/docs/4.17.15#after
// - https://lodash.com/docs/4.17.15#before
/**
 * Restrict a function to be used only once.
 * @param x a function
 * @returns (...args) => x(...args) from [0:1] calls
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.restrictOnce(x => ++count);
 * for (var i=0; i<10; ++i)
 *   fn(i);
 * count;
 * // → 1
 * ```
 */ export function restrictOnce(x) {
  return restrict(x, 0, 1);
}
export { restrictOnce as once };
// - https://www.npmjs.com/package/one-time
// - https://www.npmjs.com/package/onetime
// - https://www.npmjs.com/package/once
/**
 * Restrict a function to be used only upto a certain number of calls.
 * @param x a function
 * @param n number of calls upto which it is usable
 * @returns (...args) => x(...args) from [0:n] calls
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.restrictBefore(x => ++count, 3);
 * for (var i=0; i<10; ++i)
 *   fn(i);
 * count;
 * // → 3
 * ```
 */ export function restrictBefore(x, n) {
  return restrict(x, 0, n);
}
export { restrictBefore as before };
// - https://lodash.com/docs/4.17.15#before
/**
 * Restrict a function to be used only after a certain number of calls.
 * @param x a function
 * @param n number of calls after which it is usable
 * @returns (...args) => x(...args) from [n:end] calls
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.restrictAfter(x => ++count, 3);
 * for (var i=0; i<10; ++i)
 *   fn(i);
 * count;
 * // → 7
 * ```
 */ export function restrictAfter(x, n) {
  return restrict(x, n);
}
export { restrictAfter as after };
// - https://lodash.com/docs/4.17.15#after
//#endregion
//#region RATE CONTROL (TIME)
/**
 * Generate debounced version of a function.
 * @param x a function
 * @param t delay time (ms)
 * @param T max delay time [-1 ⇒ none]
 * @returns (...args) => invocation control
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.debounce(() => ++count, 1500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 4000);
 * setTimeout(fn, 5000);
 * // `count` incremented after 3.5s
 * // `count` incremented after 6.5s
 *
 *
 * var count = 0;
 * var fn = xfunction.debounce(() => ++count, 1500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 500);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 1500);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 4000);
 * setTimeout(fn, 4500);
 * setTimeout(fn, 5000);
 * // `count` incremented after 3.5s
 * // `count` incremented after 6.5s
 *
 *
 * var count = 0;
 * var fn = xfunction.debounce(() => ++count, 1500, 3500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 3000);
 * setTimeout(fn, 4000);
 * setTimeout(fn, 6000);
 * // `count` incremented after 3.5s
 * // `count` incremented after 5.5s
 * // `count` incremented after 7.5s
 * ```
 */ export function debounce(x, t, T = -1) {
  let savedArgs;
  let h = 0, H = 0;
  function clear() {
    clearTimeout(h);
    clearTimeout(H);
    h = H = 0;
  }
  function flush() {
    x(...savedArgs);
    clear();
  }
  ;
  return (...args)=>{
    savedArgs = args;
    if (T >= 0) H = H || setTimeout(flush, T);
    if (T < 0 || t < T) {
      clearTimeout(h);
      h = setTimeout(flush, t);
    }
    return {
      clear,
      flush
    };
  };
}
// - https://github.com/lodash/lodash/blob/4.8.0-npm/debounce.js
// - https://github.com/jashkenas/underscore/commit/9e3e067f5025dbe5e93ed784f93b233882ca0ffe
// - https://css-tricks.com/debouncing-throttling-explained-examples/
// - https://www.npmjs.com/package/debounce
/**
 * Generate leading-edge debounced version of a function.
 * @param x a function
 * @param t delay time (ms)
 * @param T max delay time [-1 ⇒ none]
 * @returns (...args) => invocation control
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.debounceEarly(() => ++count, 1500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 4000);
 * setTimeout(fn, 5000);
 * // `count` incremented after 0s
 * // `count` incremented after 4s
 *
 *
 * var count = 0;
 * var fn = xfunction.debounceEarly(() => ++count, 1500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 500);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 1500);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 4000);
 * setTimeout(fn, 4500);
 * setTimeout(fn, 5000);
 * // `count` incremented after 0s
 * // `count` incremented after 4s
 *
 *
 * var count = 0;
 * var fn = xfunction.debounceEarly(() => ++count, 1500, 3500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 3000);
 * setTimeout(fn, 4000);
 * setTimeout(fn, 6000);
 * // `count` incremented after 0s
 * // `count` incremented after 4s
 * // `count` incremented after 6s
 * ```
 */ export function debounceEarly(x, t, T = -1) {
  let h = 0, H = 0;
  function clear() {
    h = H = 0;
  }
  function flush() {
    clear();
  }
  return (...args)=>{
    if (!h && !H) x(...args);
    if (T >= 0) H = H || setTimeout(flush, T);
    if (T < 0 || t < T) {
      clearTimeout(h);
      h = setTimeout(flush, t);
    }
    return {
      clear,
      flush
    };
  };
}
// - https://github.com/lodash/lodash/blob/4.8.0-npm/debounce.js
// - https://github.com/jashkenas/underscore/commit/9e3e067f5025dbe5e93ed784f93b233882ca0ffe
// - https://css-tricks.com/debouncing-throttling-explained-examples/
// - https://www.npmjs.com/package/debounce
/**
 * Generate throttled version of a function.
 * @param x a function
 * @param t wait time (ms)
 * @returns (...args) => invocation control
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.throttle(() => ++count, 2500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * // `count` incremented after 2.5s
 *
 *
 * var count = 0;
 * var fn = xfunction.throttle(() => ++count, 2500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 3000);
 * setTimeout(fn, 4000);
 * // `count` incremented after 2.5s
 * // `count` incremented after 5.5s
 * ```
 */ export function throttle(x, t) {
  let savedArgs;
  let h = 0;
  function clear() {
    h = 0;
  }
  function flush() {
    x(...savedArgs);
    clear();
  }
  return (...args)=>{
    savedArgs = args;
    h = h || setTimeout(flush, t);
    return {
      clear,
      flush
    };
  };
}
// - https://www.npmjs.com/package/throttle-debounce
// - https://www.npmjs.com/package/throttleit
/**
 * Generate leading-edge throttled version of a function.
 * @param x a function
 * @param t wait time (ms)
 * @returns (...args) => invocation control
 * @example
 * ```javascript
 * var count = 0;
 * var fn = xfunction.throttleEarly(() => ++count, 2500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * // `count` incremented after 0s
 *
 *
 * var count = 0;
 * var fn = xfunction.throttleEarly(() => ++count, 2500);
 * setTimeout(fn, 0);
 * setTimeout(fn, 1000);
 * setTimeout(fn, 2000);
 * setTimeout(fn, 3000);
 * setTimeout(fn, 4000);
 * // `count` incremented after 0s
 * // `count` incremented after 3s
 * ```
 */ export function throttleEarly(x, t) {
  let h = 0;
  function clear() {
    h = 0;
  }
  function flush() {
    clear();
  }
  return (...args)=>{
    if (!h) x(...args);
    h = h || setTimeout(flush, t);
    return {
      clear,
      flush
    };
  };
} // - https://www.npmjs.com/package/throttle-debounce
 // - https://www.npmjs.com/package/throttleit
 // TODO: Is a generator function better for this?
 // function backoffRetryRec(x: Function, args: unknown[], err: unknown, n: number, N: number, t: number, T: number, tf: number): void {
 //   if (N>=0 && n>=N) throw err;
 //   if (T>=0 && t>=T) throw err;
 //   try { return x(...args, err); }
 //   catch(e) { setTimeout(() => backoffRetryRec(x, args, e, n+1, N, t*tf, T, tf), t); }
 // }
 //
 // TODO: Generate exponential-backoff-retried version of a function.
 // @param x a function
 // @param N maximum retries (-1 ⇒ unlimited)
 // @param t initial retry time (1 ms)
 // @param T maximum retry time [-1 ⇒ none]
 // @param tf retry time factor [2]
 //
 // function backoffRetry(x: Function, N: number, t: number, T: number=-1, tf: number=2): Function {
 //   return (...args: unknown[]) => backoffRetryRec(x, args, null, 0, N, t, T, tf);
 // }
 // - TODO
 //#endregion
 //#endregion
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9leHRyYS1mdW5jdGlvbi9leHRyYS1mdW5jdGlvbi9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyNyZWdpb24gVFlQRVNcbi8qKlxuICogdW5rbm93biBmdW5jdGlvbiB0eXBlLlxuICogQHBhcmFtcyBhcmdzIGFyZ3VtZW50c1xuICogQHJldHVybnMgdW5rbm93biB2YWx1ZVxuICovXG5leHBvcnQgdHlwZSBGdW5jdGlvbiA9ICguLi5hcmdzOiB1bmtub3duW10pID0+IHVua25vd247XG4vLyNlbmRyZWdpb25cblxuXG5cblxuLy8jcmVnaW9uIENPTlNUQU5UU1xuLyoqXG4gKiBEbyBub3RoaW5nLlxuICogQHBhcmFtIF9hcmdzIGFyZ3VtZW50cyAoaWdub3JlZClcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB4ZnVuY3Rpb24uTk9PUCgxLCAyKTtcbiAqIC8vIOKGkiB1bmRlZmluZWRcbiAqXG4gKiB4ZnVuY3Rpb24uTk9PUCgnYScsICdiJyk7XG4gKiAvLyDihpIgdW5kZWZpbmVkXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE5PT1AoLi4uX2FyZ3M6IHVua25vd25bXSk6IHZvaWQge31cbi8vIC0gaHR0cHM6Ly9sb2Rhc2guY29tL2RvY3MvNC4xNy4xNSNub29wXG5cblxuLyoqXG4gKiBSZXR1cm4gZmFsc2UuXG4gKiBAcGFyYW0gX2FyZ3MgYXJndW1lbnRzIChpZ25vcmVkKVxuICogQHJldHVybnMgZmFsc2UuXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogeGZ1bmN0aW9uLkZBTFNFKCk7XG4gKiAvLyDihpIgZmFsc2VcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gRkFMU0UoLi4uX2FyZ3M6IHVua25vd25bXSk6IGZhbHNlIHtcbiAgcmV0dXJuIGZhbHNlO1xufVxuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9ib29sYmFzZVxuXG5cbi8qKlxuICogUmV0dXJuIHRydWUuXG4gKiBAcGFyYW0gX2FyZ3MgYXJndW1lbnRzIChpZ25vcmVkKVxuICogQHJldHVybnMgdHJ1ZS5cbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB4ZnVuY3Rpb24uVFJVRSgpO1xuICogLy8g4oaSIHRydWVcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gVFJVRSguLi5fYXJnczogdW5rbm93bltdKTogdHJ1ZSB7XG4gIHJldHVybiB0cnVlO1xufVxuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9ib29sYmFzZVxuXG5cbi8qKlxuICogUmV0dXJuIHRoZSBzYW1lIChmaXJzdCkgdmFsdWUuXG4gKiBAcGFyYW0gdiBhIHZhbHVlXG4gKiBAcmV0dXJucyB2XG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogeGZ1bmN0aW9uLklERU5USVRZKDEpO1xuICogLy8g4oaSIDFcbiAqXG4gKiB4ZnVuY3Rpb24uSURFTlRJVFkoJ2EnKTtcbiAqIC8vIOKGkiAnYSdcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gSURFTlRJVFk8VD4odjogVCk6IFQge1xuICByZXR1cm4gdjtcbn1cblxuXG4vKipcbiAqIENvbXBhcmUgdHdvIHZhbHVlcy5cbiAqIEBwYXJhbSBhIGEgdmFsdWVcbiAqIEBwYXJhbSBiIGFub3RoZXIgdmFsdWVcbiAqIEByZXR1cm5zIGE8YjogLTEsIGE9YjogMCwgYT5iOiAxXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogeGZ1bmN0aW9uLkNPTVBBUkUoMSwgMik7XG4gKiAvLyDihpIgLTFcbiAqXG4gKiB4ZnVuY3Rpb24uQ09NUEFSRSgyLCAxKTtcbiAqIC8vIOKGkiAxXG4gKlxuICogeGZ1bmN0aW9uLkNPTVBBUkUoMSwgMSk7XG4gKiAvLyDihpIgMFxuICovXG5leHBvcnQgZnVuY3Rpb24gQ09NUEFSRTxUPihhOiBULCBiOiBUKTogbnVtYmVyIHtcbiAgcmV0dXJuIGE8Yj8gLTEgOiAoYT5iPyAxIDogMCk7XG59XG5cblxuLyoqXG4gKiBSZXR1cm4gdGhlIGFyZ3VtZW50cyBwYXNzZWQgYXMgYSBhcnJheS5cbiAqIEBwYXJhbSBhcmdzIGFyZ3VtZW50c1xuICogQHJldHVybnMgWy4uLmFyZ3NdXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogeGZ1bmN0aW9uLkFSR1VNRU5UUygxLCAyKTtcbiAqIC8vIOKGkiBbMSwgMl1cbiAqXG4gKiB4ZnVuY3Rpb24uQVJHVU1FTlRTKCdhJywgJ2InKTtcbiAqIC8vIOKGkiBbJ2EnLCAnYiddXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEFSR1VNRU5UUyguLi5hcmdzOiB1bmtub3duW10pOiB1bmtub3duW10ge1xuICByZXR1cm4gYXJncztcbn1cbi8vI2VuZHJlZ2lvblxuXG5cblxuXG4vLyNyZWdpb24gTUVUSE9EUyAoQlVJTFRJTilcbi8vI3JlZ2lvbiBBQk9VVFxuLyoqXG4gKiBHZXQgdGhlIG5hbWUgb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEByZXR1cm5zIG5hbWVcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiBpbXBvcnQge2RlbGF5LCBkZWJvdW5jZX0gZnJvbSBcImpzcjpAbm9kZWYvZXh0cmEtZnVuY3Rpb25cIjtcbiAqXG4gKiB4ZnVuY3Rpb24ubmFtZShkZWxheSk7XG4gKiAvLyDihpIgJ2RlbGF5J1xuICpcbiAqIHhmdW5jdGlvbi5uYW1lKGRlYm91bmNlKTtcbiAqIC8vIOKGkiAnZGVib3VuY2UnXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5hbWUoeDogRnVuY3Rpb24pOiBzdHJpbmcge1xuICByZXR1cm4geC5uYW1lO1xufVxuLy8gLSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9GdW5jdGlvbi9uYW1lXG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL2ZuLW5hbWVcblxuXG4vKipcbiAqIEdldCB0aGUgbnVtYmVyIG9mIHBhcmFtZXRlcnMgb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEByZXR1cm5zIHxbcCwgcSwgLi4uXXwgfCB4KHAsIHEsIC4uLilcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB4ZnVuY3Rpb24ubGVuZ3RoKCgpID0+IDApO1xuICogLy8g4oaSIDBcbiAqXG4gKiB4ZnVuY3Rpb24ubGVuZ3RoKCh4LCB5KSA9PiAwKTtcbiAqIC8vIOKGkiAyXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxlbmd0aCh4OiBGdW5jdGlvbik6IG51bWJlciB7XG4gIHJldHVybiB4Lmxlbmd0aDtcbn1cbmV4cG9ydCB7bGVuZ3RoIGFzIGFyaXR5fTtcbi8vIC0gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRnVuY3Rpb24vbGVuZ3RoXG4vLyNlbmRyZWdpb25cblxuXG5cblxuLy8jcmVnaW9uIEJJTkRJTkdcbi8qKlxuICogQmluZCB0aGlzLW9iamVjdCwgYW5kIG9wdGlvbmFsIHByZWZpeCBhcmd1bWVudHMgdG8gYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEBwYXJhbSB0aHMgdGhpcyBvYmplY3QgdG8gYmluZFxuICogQHBhcmFtIHByZWZpeCBwcmVmaXggYXJndW1lbnRzXG4gKiBAcmV0dXJucyAoLi4uYXJncykgPT4gdGhpcy54KC4uLnByZWZpeCwgLi4uYXJncylcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgYXJyYXkgID0gWzFdO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLmJpbmQoQXJyYXkucHJvdG90eXBlLnB1c2gsIGFycmF5KTtcbiAqIGZuKDIsIDMsIDQpOyAgLy8gcHVzaCgyLCAzLCA0KVxuICogYXJyYXk7XG4gKiAvLyDihpIgWzEsIDIsIDMsIDRdXG4gKlxuICogdmFyIGFycmF5ICA9IFsxLCAyLCAzLCA0XTtcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5iaW5kKEFycmF5LnByb3RvdHlwZS5zcGxpY2UsIGFycmF5LCAxKTtcbiAqIGZuKDIpOyAgLy8gc3BsaWNlKDEsIDIpXG4gKiBhcnJheTtcbiAqIC8vIOKGkiBbMSwgNF1cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYmluZCh4OiBGdW5jdGlvbiwgdGhzOiB1bmtub3duLCAuLi5wcmVmaXg6IHVua25vd25bXSk6IEZ1bmN0aW9uIHtcbiAgcmV0dXJuIHguYmluZCh0aHMsIC4uLnByZWZpeCk7XG59XG4vLyAtIGh0dHBzOi8vdW5kZXJzY29yZWpzLm9yZy8jYmluZFxuLy8gLSBodHRwczovL2xvZGFzaC5jb20vZG9jcy80LjE3LjE1I2JpbmRcbi8vIC0gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRnVuY3Rpb24vYmluZFxuLy8jZW5kcmVnaW9uXG5cblxuXG5cbi8vI3JlZ2lvbiBJTlZPQ0FUSU9OXG4vKipcbiAqIEludm9rZSBhIGZ1bmN0aW9uIHdpdGggc3BlY2lmaWVkIHRoaXMtb2JqZWN0LCBhbmQgYXJndW1lbnRzIHByb3ZpZGVkIGluZGl2aWR1YWxseS5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEBwYXJhbSB0aHMgdGhpcyBvYmplY3QgdG8gaW52b2tlIHdpdGhcbiAqIEBwYXJhbSBhcmdzIGFyZ3VtZW50c1xuICogQHJldHVybnMgdGhpcy54KC4uLmFyZ3MpXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGFycmF5ID0gWzFdO1xuICogeGZ1bmN0aW9uLmNhbGwoQXJyYXkucHJvdG90eXBlLnB1c2gsIGFycmF5LCAyLCAzLCA0KTsgIC8vIHB1c2goMiwgMywgNClcbiAqIGFycmF5O1xuICogLy8g4oaSIFsxLCAyLCAzLCA0XVxuICpcbiAqIHZhciBhcnJheSA9IFsxLCAyLCAzLCA0XTtcbiAqIHhmdW5jdGlvbi5jYWxsKEFycmF5LnByb3RvdHlwZS5zcGxpY2UsIGFycmF5LCAxLCAyKTsgIC8vIHNwbGljZSgxLCAyKVxuICogYXJyYXk7XG4gKiAvLyDihpIgWzEsIDRdXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhbGwoeDogRnVuY3Rpb24sIHRoczogdW5rbm93bj1udWxsLCAuLi5hcmdzOiB1bmtub3duW10pOiB1bmtub3duIHtcbiAgcmV0dXJuIHguY2FsbCh0aHMsIC4uLmFyZ3MpO1xufVxuXG5cbi8qKlxuICogSW52b2tlIGEgZnVuY3Rpb24gd2l0aCBzcGVjaWZpZWQgdGhpcy1vYmplY3QsIGFuZCBhcmd1bWVudHMgcHJvdmlkZWQgYXMgYW4gYXJyYXkuXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcGFyYW0gdGhzIHRoaXMgb2JqZWN0IHRvIGludm9rZSB3aXRoXG4gKiBAcGFyYW0gYXJncyBhcmd1bWVudHMgYXJyYXlcbiAqIEByZXR1cm5zIHRoaXMueCguLi5hcmdzKVxuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHZhciBhcnJheSA9IFsxXTtcbiAqIHhmdW5jdGlvbi5hcHBseShBcnJheS5wcm90b3R5cGUucHVzaCwgYXJyYXksIFsyLCAzLCA0XSk7ICAvLyBwdXNoKDIsIDMsIDQpXG4gKiBhcnJheTtcbiAqIC8vIOKGkiBbMSwgMiwgMywgNF1cbiAqXG4gKiB2YXIgYXJyYXkgPSBbMSwgMiwgMywgNF07XG4gKiB4ZnVuY3Rpb24uYXBwbHkoQXJyYXkucHJvdG90eXBlLnNwbGljZSwgYXJyYXksIFsxLCAyXSk7ICAvLyBzcGxpY2UoMSwgMilcbiAqIGFycmF5O1xuICogLy8g4oaSIFsxLCA0XVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBseSh4OiBGdW5jdGlvbiwgdGhzOiB1bmtub3duPW51bGwsIGFyZ3M6IHVua25vd25bXSk6IHVua25vd24ge1xuICByZXR1cm4geC5hcHBseSh0aHMsIGFyZ3MpO1xufVxuLy8jZW5kcmVnaW9uXG4vLyNlbmRyZWdpb25cblxuXG5cblxuLy8jcmVnaW9uIE1FVEhPRFMgKENVU1RPTSlcbi8vI3JlZ2lvbiBBQk9VVFxuLyoqXG4gKiBDaGVjayBpZiB2YWx1ZSBpcyBhIGZ1bmN0aW9uLlxuICogQHBhcmFtIHYgYSB2YWx1ZVxuICogQHJldHVybnMgaXMgZnVuY3Rpb24/XG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogeGZ1bmN0aW9uLmlzKE9iamVjdC5rZXlzKTtcbiAqIC8vIOKGkiB0cnVlXG4gKlxuICogeGZ1bmN0aW9uLmlzKCgpID0+IDApO1xuICogLy8g4oaSIHRydWVcbiAqXG4gKiB4ZnVuY3Rpb24uaXMoYXN5bmMgKCkgPT4gMCk7XG4gKiAvLyDihpIgdHJ1ZVxuICpcbiAqIHhmdW5jdGlvbi5pcygwKTtcbiAqIC8vIOKGkiBmYWxzZVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpcyh2OiB1bmtub3duKTogdiBpcyBGdW5jdGlvbiB7XG4gIHJldHVybiB0eXBlb2Ygdj09PVwiZnVuY3Rpb25cIjtcbn1cbi8vIC0gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvaXMtZnVuY3Rpb25cblxuXG4vKipcbiAqIENoZWNrIGlmIHZhbHVlIGlzIGFuIGFzeW5jIGZ1bmN0aW9uLlxuICogQHBhcmFtIHYgYSB2YWx1ZVxuICogQHJldHVybnMgaXMgYXN5bmMgZnVuY3Rpb24/XG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogeGZ1bmN0aW9uLmlzQXN5bmMoYXN5bmMgKCkgPT4gMCk7XG4gKiAvLyDihpIgdHJ1ZVxuICpcbiAqIHhmdW5jdGlvbi5pc0FzeW5jKCgpID0+IDApO1xuICogLy8g4oaSIGZhbHNlXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQXN5bmModjogdW5rbm93bik6IGJvb2xlYW4ge1xuICBjb25zdCBBc3luY0Z1bmN0aW9uID0gKGFzeW5jIGZ1bmN0aW9uICgpIHt9KS5jb25zdHJ1Y3RvcjtcbiAgcmV0dXJuIHYgaW5zdGFuY2VvZiBBc3luY0Z1bmN0aW9uO1xufVxuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9pcy1hc3luYy1mdW5jdGlvblxuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9pcy1jYWxsYmFjay1mdW5jdGlvblxuLy8gLSBodHRwczovL2Rhdmlkd2Fsc2gubmFtZS9qYXZhc2NyaXB0LWRldGVjdC1hc3luYy1mdW5jdGlvblxuLy8gLSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zODUwODQyMC9ob3ctdG8ta25vdy1pZi1hLWZ1bmN0aW9uLWlzLWFzeW5jXG4vLyAtIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL1N0YXRlbWVudHMvYXN5bmNfZnVuY3Rpb25cbi8vIC0gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXN5bmNGdW5jdGlvblxuXG5cbi8qKlxuICogQ2hlY2sgaWYgdmFsdWUgaXMgYSBnZW5lcmF0b3IgZnVuY3Rpb24uXG4gKiBAcGFyYW0gdiBhIHZhbHVlXG4gKiBAcmV0dXJucyBpcyBnZW5lcmF0b3IgZnVuY3Rpb24/XG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogZnVuY3Rpb24qIG5hdHVyYWxOdW1iZXJzKCkge1xuICogICBmb3IgKHZhciBpPTA7OyArK2kpXG4gKiAgICAgeWllbGQgaTtcbiAqIH1cbiAqXG4gKiB4ZnVuY3Rpb24uaXNHZW5lcmF0b3IobmF0dXJhbE51bWJlcnMpO1xuICogLy8g4oaSIHRydWVcbiAqXG4gKiB4ZnVuY3Rpb24uaXNHZW5lcmF0b3IoKCkgPT4gMCk7XG4gKiAvLyDihpIgZmFsc2VcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNHZW5lcmF0b3IodjogdW5rbm93bik6IHYgaXMgR2VuZXJhdG9yRnVuY3Rpb24ge1xuICBjb25zdCBHZW5lcmF0b3JGdW5jdGlvbiA9IChmdW5jdGlvbiogKCkge30pLmNvbnN0cnVjdG9yO1xuICByZXR1cm4gdiBpbnN0YW5jZW9mIEdlbmVyYXRvckZ1bmN0aW9uO1xufVxuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9pcy1nZW5lcmF0b3Jcbi8vIC0gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvaXMtZ2VuZXJhdG9yLWZuXG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL2lzLWdlbmVyYXRvci1mdW5jdGlvblxuLy8gLSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xNjc1NDk1Ni9jaGVjay1pZi1mdW5jdGlvbi1pcy1hLWdlbmVyYXRvclxuLy8gLSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9TdGF0ZW1lbnRzL2Z1bmN0aW9uKlxuLy8gLSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9HZW5lcmF0b3Jcbi8vIC0gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvR2VuZXJhdG9yRnVuY3Rpb25cbi8vI2VuZHJlZ2lvblxuXG5cblxuXG4vLyNyZWdpb24gQ09OVEVYVFxuLyoqXG4gKiBDb250ZXh0aWZ5IGEgZnVuY3Rpb24gYnkgYWNjZXB0aW5nIHRoZSBmaXJzdCBwYXJhbWV0ZXIgYXMgdGhpcy1vYmplY3QuXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcmV0dXJucyAoLi4uYXJncykgPT4geCh0aGlzLCAuLi5hcmdzKVxuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIGZ1bmN0aW9uIGNvdW50KHgsIHZhbHVlKSB7XG4gKiAgIHZhciBhID0gMDtcbiAqICAgZm9yICh2YXIgdiBvZiB4KVxuICogICAgIGlmICh2PT09dmFsdWUpICsrYTtcbiAqICAgcmV0dXJuIGE7XG4gKiB9XG4gKlxuICogdmFyIGZuID0geGZ1bmN0aW9uLmNvbnRleHRpZnkoY291bnQpO1xuICpcbiAqIGZuLmNhbGwoWzYsIDMsIDQsIDNdLCAzKTtcbiAqIC8vIOKGkiAyXG4gKlxuICogZm4uY2FsbChbNiwgMSwgNCwgM10sIDMpO1xuICogLy8g4oaSIDFcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udGV4dGlmeSh4OiBGdW5jdGlvbik6IEZ1bmN0aW9uIHtcbiAgcmV0dXJuIGZ1bmN0aW9uKHRoaXM6IHVua25vd24sIC4uLmFyZ3M6IHVua25vd25bXSkgeyByZXR1cm4geCh0aGlzLCAuLi5hcmdzKTsgfTtcbn1cblxuXG4vKipcbiAqIERlY29udGV4dGlmeSBhIGZ1bmN0aW9uIGJ5IGFjY2VwdGluZyB0aGlzLW9iamVjdCBhcyB0aGUgZmlyc3QgYXJndW1lbnQuXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcmV0dXJucyAodGhpcywgLi4uYXJncykgPT4gdGhpcy54KC4uLmFyZ3MpXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogZnVuY3Rpb24gY291bnQodmFsdWUpIHtcbiAqICAgdmFyIGEgPSAwO1xuICogICBmb3IgKHZhciB2IG9mIHRoaXMpXG4gKiAgICAgaWYgKHY9PT12YWx1ZSkgKythO1xuICogICByZXR1cm4gYTtcbiAqIH1cbiAqXG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24uZGVjb250ZXh0aWZ5KGNvdW50KTtcbiAqXG4gKiBmbihbNiwgMywgNCwgM10sIDMpO1xuICogLy8g4oaSIDJcbiAqXG4gKiBmbihbNiwgMSwgNCwgM10sIDMpO1xuICogLy8g4oaSIDFcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVjb250ZXh0aWZ5KHg6IEZ1bmN0aW9uKTogRnVuY3Rpb24ge1xuICByZXR1cm4gKHRoczogdW5rbm93bj1udWxsLCAuLi5hcmdzOiB1bmtub3duW10pID0+IHguY2FsbCh0aHMsIC4uLmFyZ3MpO1xufVxuLy8jZW5kcmVnaW9uXG5cblxuXG5cbi8vI3JlZ2lvbiBSRVNVTFQgTUFOSVBVTEFUSU9OXG4vKipcbiAqIEdlbmVyYXRlIGEgcmVzdWx0LW5lZ2F0ZWQgdmVyc2lvbiBvZiBhIGZ1bmN0aW9uLlxuICogQHBhcmFtIHggYSBmdW5jdGlvblxuICogQHJldHVybnMgKC4uLmFyZ3MpID0+ICF4KC4uLmFyZ3MpXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGZuID0geGZ1bmN0aW9uLm5lZ2F0ZShpc0Zpbml0ZSk7XG4gKiBmbihJbmZpbml0eSlcbiAqIC8vIOKGkiB0cnVlXG4gKiBmbigxKVxuICogLy8g4oaSIGZhbHNlXG4gKlxuICogdmFyIGZuID0geGZ1bmN0aW9uLm5lZ2F0ZShpc05hTik7XG4gKiBmbigxKTtcbiAqIC8vIOKGkiB0cnVlXG4gKiBmbihOYU4pO1xuICogLy8g4oaSIGZhbHNlXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5lZ2F0ZSh4OiBGdW5jdGlvbik6IEZ1bmN0aW9uIHtcbiAgcmV0dXJuICguLi5hcmdzOiB1bmtub3duW10pID0+ICF4KC4uLmFyZ3MpO1xufVxuLy8jZW5kcmVnaW9uXG5cblxuXG5cbi8vI3JlZ2lvbiBSRVNVTFQgQ0FDSElOR1xuLyoqXG4gKiBSZXNvbHZlIGFyZ3VtZW50cyBpbnRvIGEgdW5pcXVlIGtleS5cbiAqIEBwYXJhbSBhcmdzIGFyZ3VtZW50c1xuICogQHJldHVybnMgdW5pcXVlIGtleVxuICovXG5leHBvcnQgdHlwZSBSZXNvbHZlciA9ICguLi5hcmdzOiB1bmtub3duW10pID0+IHVua25vd247XG5cblxuLyoqXG4gKiBHZW5lcmF0ZSByZXN1bHQtY2FjaGVkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEBwYXJhbSBmciByZXNvbHZlciAoKC4uLmFyZ3MpID0+IHVuaXF1ZSBrZXkpIFtJREVOVElUWV1cbiAqIEBwYXJhbSBjYWNoZSByZXN1bHQgY2FjaGUgW01hcCgpXVxuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHZhciBjYWxscyA9IDA7XG4gKlxuICogZnVuY3Rpb24gZmFjdG9yaWFsUmVjKG46IG51bWJlcikge1xuICogICBpZiAobjw9MSkgcmV0dXJuIDE7XG4gKiAgIHJldHVybiBuICogZmFjdG9yaWFsUmVjKG4tMSk7XG4gKiB9XG4gKlxuICogZnVuY3Rpb24gZmFjdG9yaWFsKG46IG51bWJlcikge1xuICogICArK2NhbGxzO1xuICogICByZXR1cm4gZmFjdG9yaWFsUmVjKG4pO1xuICogfVxuICpcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5tZW1vaXplKGZhY3RvcmlhbCk7XG4gKiBmbigzKTtcbiAqIC8vIOKGkiA2XG4gKiBmbig0KTtcbiAqIC8vIOKGkiAyNFxuICogZm4oNSk7XG4gKiAvLyDihpIgMTIwXG4gKiBmbigzKTtcbiAqIC8vIOKGkiA2XG4gKiBmbig0KTtcbiAqIC8vIOKGkiAyNFxuICogZm4oNSk7XG4gKiAvLyDihpIgMTIwXG4gKiBjYWxscztcbiAqIC8vIOKGkiAzXG4gKlxuICpcbiAqIHZhciBjYWxscyA9IDA7XG4gKlxuICogZnVuY3Rpb24gaHlwb3QoeDogbnVtYmVyLCB5OiBudW1iZXIpIHtcbiAqICAgKytjYWxscztcbiAqICAgcmV0dXJuIE1hdGguaHlwb3QoeCwgeSk7XG4gKiB9XG4gKlxuICogZnVuY3Rpb24gcmVzb2x2ZXIoeDogbnVtYmVyLCB5OiBudW1iZXIpIHtcbiAqICAgcmV0dXJuIDQwOTMqeSArIHg7ICAvLyBhIGhhc2hcbiAqIH1cbiAqXG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24ubWVtb2l6ZShoeXBvdCwgcmVzb2x2ZXIpO1xuICogZm4oMywgIDQpO1xuICogLy8g4oaSIDVcbiAqIGZuKDYsICA4KTtcbiAqIC8vIOKGkiAxMFxuICogZm4oNSwgMTIpO1xuICogLy8g4oaSIDEzXG4gKiBmbigzLCAgNCk7XG4gKiAvLyDihpIgNVxuICogZm4oNiwgIDgpO1xuICogLy8g4oaSIDEwXG4gKiBmbig1LCAxMik7XG4gKiAvLyDihpIgMTNcbiAqIGNhbGxzO1xuICogLy8g4oaSIDNcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gbWVtb2l6ZSh4OiBGdW5jdGlvbiwgZnI6IFJlc29sdmVyIHwgbnVsbD1udWxsLCBjYWNoZTogTWFwPHVua25vd24sIHVua25vd24+IHwgbnVsbD1udWxsKTogRnVuY3Rpb24ge1xuICBmciAgICA9IGZyIHx8IElERU5USVRZO1xuICBjYWNoZSA9IGNhY2hlIHx8IG5ldyBNYXAoKTtcbiAgcmV0dXJuICguLi5hcmdzOiB1bmtub3duW10pID0+IHtcbiAgICBjb25zdCBrID0gZnIoLi4uYXJncyk7XG4gICAgaWYgKGNhY2hlLmhhcyhrKSkgcmV0dXJuIGNhY2hlLmdldChrKTtcbiAgICBjb25zdCB2ID0geCguLi5hcmdzKTtcbiAgICBjYWNoZS5zZXQoaywgdik7XG4gICAgcmV0dXJuIHY7XG4gIH07XG59XG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL21lbW9pemVlXG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL21lbW9pemVyaWZpY1xuLy8jZW5kcmVnaW9uXG5cblxuXG5cbi8vI3JlZ2lvbiBQQVJBTUVURVIgTUFOSVBVTEFUSU9OXG4vKipcbiAqIEdlbmVyYXRlIGEgcGFyYW1ldGVyLXJldmVyc2VkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEByZXR1cm5zIChwLCBxLCAuLi4pID0+IHgoLi4uLCBxLCBwKVxuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIGZ1bmN0aW9uIGRpdmlkZSh4LCB5KSB7XG4gKiAgIHJldHVybiB4L3k7XG4gKiB9XG4gKlxuICogdmFyIGZuID0geGZ1bmN0aW9uLnJldmVyc2UoZGl2aWRlKTtcbiAqIGZuKDIsIDQpO1xuICogLy8g4oaSIDJcbiAqIGZuKDIsIDYpO1xuICogLy8g4oaSIDNcbiAqIGZuKDIsIDgpO1xuICogLy8g4oaSIDRcbiAqXG4gKlxuICogdmFyIGFycmF5ID0gWzFdO1xuICpcbiAqIGZ1bmN0aW9uIHB1c2goLi4uYXJncykge1xuICogICBhcnJheS5wdXNoKC4uLmFyZ3MpO1xuICogfVxuICpcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5yZXZlcnNlKHB1c2gpO1xuICogZm4oMiwgMywgNCk7ICAvLyBwdXNoKDIsIDMsIDQpIGluIHJldmVyc2Ugb3JkZXJcbiAqIGFycmF5O1xuICogLy8g4oaSIFsxLCA0LCAzLCAyXVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXZlcnNlKHg6IEZ1bmN0aW9uKTogRnVuY3Rpb24ge1xuICByZXR1cm4gKC4uLmFyZ3M6IHVua25vd25bXSkgPT4geCguLi5hcmdzLnJldmVyc2UoKSk7XG59XG5leHBvcnQge3JldmVyc2UgYXMgZmxpcH07XG5cblxuLyoqXG4gKiBHZW5lcmF0ZSBhIChmaXJzdCkgcGFyYW1ldGVyLXNwcmVhZGVkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEByZXR1cm5zIChwLCBxLCAuLi4pID0+IHgoW3AsIHEsIC4uLl0pXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogZnVuY3Rpb24gc3VtKHg6IG51bWJlcltdKSB7XG4gKiAgIHZhciBhID0gMDtcbiAqICAgZm9yICh2YXIgdiBvZiB4KVxuICogICAgIGEgKz0gdjtcbiAqICAgcmV0dXJuIGE7XG4gKiB9XG4gKlxuICogdmFyIGZuID0geGZ1bmN0aW9uLnNwcmVhZChzdW0pO1xuICogZm4oMSwgMiwgMyk7ICAvLyBzdW0oWzEsIDIsIDNdKVxuICogLy8g4oaSIDZcbiAqXG4gKlxuICogdmFyIGFycmF5ID0gWzFdO1xuICpcbiAqIGZ1bmN0aW9uIGNvbmNhdCh4OiBudW1iZXJbXSkge1xuICogICByZXR1cm4gYXJyYXkuY29uY2F0KHgpO1xuICogfVxuICpcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5zcHJlYWQoY29uY2F0KTtcbiAqIGZuKDIsIDMsIDQpOyAgLy8gY29uY2F0KFsyLCAzLCA0XSlcbiAqIC8vIOKGkiBbMSwgMiwgMywgNF1cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gc3ByZWFkKHg6IEZ1bmN0aW9uKTogRnVuY3Rpb24ge1xuICByZXR1cm4gKC4uLmFyZ3M6IHVua25vd25bXSkgPT4geChhcmdzKTtcbn1cblxuXG4vKipcbiAqIEdlbmVyYXRlIGEgKGZpcnN0KSBwYXJhbWV0ZXItY29sbGFwc2VkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEByZXR1cm5zIChbcCwgcSwgLi4uXSkgPT4geChwLCBxLCAuLi4pXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGZuID0geGZ1bmN0aW9uLnVuc3ByZWFkKE1hdGgubWluKTtcbiAqIGZuKFs3LCA0LCA5XSk7ICAvLyBNYXRoLm1pbig3LCA0LCA5KVxuICogLy8g4oaSIDRcbiAqXG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24udW5zcHJlYWQoKHgsIGksIEkpID0+IHguc2xpY2UoaSwgSSkpO1xuICogZm4oW1sxLCAyLCAzLCA0XSwgMl0pOyAgLy8gWzEsIDIsIDMsIDRdLnNsaWNlKDIpXG4gKiAvLyDihpIgWzMsIDRdXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVuc3ByZWFkKHg6IEZ1bmN0aW9uKTogRnVuY3Rpb24ge1xuICByZXR1cm4gKGFyZ3M6IHVua25vd24pID0+IHgoLi4uKGFyZ3MgYXMgdW5rbm93bltdKSk7XG59XG5cblxuLyoqXG4gKiBBdHRhY2ggcHJlZml4IGFyZ3VtZW50cyB0byBsZWZ0bW9zdCBwYXJhbWV0ZXJzIG9mIGEgZnVuY3Rpb24uXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcGFyYW0gcHJlZml4IHByZWZpeCBhcmd1bWVudHNcbiAqIEByZXR1cm5zICguLi5hcmdzKSA9PiB4KC4uLnByZWZpeCwgLi4uYXJncylcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24uYXR0YWNoKE1hdGgubWluLCAxMDApO1xuICogZm4oMTgwLCAxMzApOyAgLy8gTWF0aC5taW4oMTAwLCAxODAsIDEzMClcbiAqIC8vIOKGkiAxMDBcbiAqXG4gKiB2YXIgYXJyYXkgPSBbMV07XG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24uYXR0YWNoKCguLi52cykgPT4gYXJyYXkucHVzaCguLi52cyksIDEwLCAxMCk7XG4gKiBmbigxLCAyLCAzKTsgIC8vIGFycmF5LnB1c2goMTAsIDEwLCAxLCAyLCAzKVxuICogYXJyYXk7XG4gKiAvLyDihpIgWzEsIDEwLCAxMCwgMSwgMiwgM11cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYXR0YWNoKHg6IEZ1bmN0aW9uLCAuLi5wcmVmaXg6IHVua25vd25bXSk6IEZ1bmN0aW9uIHtcbiAgcmV0dXJuICguLi5hcmdzOiB1bmtub3duW10pID0+IHgoLi4ucHJlZml4LCAuLi5hcmdzKTtcbn1cbmV4cG9ydCB7YXR0YWNoIGFzIHBhcnRpYWx9O1xuXG5cbi8qKlxuICogQXR0YWNoIHN1ZmZpeCBhcmd1bWVudHMgdG8gcmlnaHRtb3N0IHBhcmFtZXRlcnMgb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEBwYXJhbSBzdWZmaXggc3VmZml4IGFyZ3VtZW50c1xuICogQHJldHVybnMgKC4uLmFyZ3MpID0+IHgoLi4uYXJncywgLi4uc3VmZml4KVxuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5hdHRhY2hSaWdodChNYXRoLm1pbiwgMTAwKTtcbiAqIGZuKDE4MCwgMTMwKTsgIC8vIE1hdGgubWluKDE4MCwgMTMwLCAxMDApXG4gKiAvLyDihpIgMTAwXG4gKlxuICogdmFyIGFycmF5ID0gWzFdO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLmF0dGFjaFJpZ2h0KCguLi52cykgPT4gYXJyYXkucHVzaCguLi52cyksIDEwLCAxMCk7XG4gKiBmbigxLCAyLCAzKTsgIC8vIGFycmF5LnB1c2goMSwgMiwgMywgMTAsIDEwKVxuICogYXJyYXk7XG4gKiAvLyDihpIgWzEsIDEsIDIsIDMsIDEwLCAxMF1cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYXR0YWNoUmlnaHQoeDogRnVuY3Rpb24sIC4uLnN1ZmZpeDogdW5rbm93bltdKTogRnVuY3Rpb24ge1xuICByZXR1cm4gKC4uLmFyZ3M6IHVua25vd25bXSkgPT4geCguLi5hcmdzLCAuLi5zdWZmaXgpO1xufVxuZXhwb3J0IHthdHRhY2hSaWdodCBhcyBwYXJ0aWFsUmlnaHR9O1xuLy8jZW5kcmVnaW9uXG5cblxuXG5cbi8vI3JlZ2lvbiBGVU5DVElPTkFMIEJFSEFWSU9VUlxuLyoqXG4gKiBDb21wb3NlIGZ1bmN0aW9ucyB0b2dldGhlciwgaW4gYXBwbGljYXRpdmUgb3JkZXIuXG4gKiBAcGFyYW0geHMgZnVuY3Rpb25zIChmLCBnKVxuICogQHJldHVybnMgKGYgbyBnKSwgb3IgZihnKHgpKVxuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5jb21wb3NlKE1hdGguc3FydCwgTWF0aC5hYnMpO1xuICogZm4oLTY0KTsgIC8vIE1hdGguc3FydChNYXRoLmFicygtNjQpKVxuICogLy8g4oaSIDhcbiAqXG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24uY29tcG9zZShNYXRoLnNxcnQsIE1hdGgubWluKTtcbiAqIGZuKDIyLCA5KTsgIC8vIE1hdGguc3FydChNYXRoLm1pbigyMiwgOSkpXG4gKiAvLyDihpIgM1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wb3NlKC4uLnhzOiBGdW5jdGlvbltdKTogRnVuY3Rpb24ge1xuICByZXR1cm4gY29tcG9zZVJpZ2h0KC4uLnhzLnJldmVyc2UoKSk7XG59XG4vLyAtIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Z1bmN0aW9uX2NvbXBvc2l0aW9uXG4vLyAtIGh0dHA6Ly9sZWFybnlvdWFoYXNrZWxsLmNvbS9oaWdoZXItb3JkZXItZnVuY3Rpb25zXG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL2NvbXBvc2UtZnVuY3Rpb25cblxuXG4vKipcbiAqIENvbXBvc2UgZnVuY3Rpb25zIHRvZ2V0aGVyLCBzdWNoIHRoYXQgcmVzdWx0IGlzIHBpcGVkIGZvcndhcmQuXG4gKiBAcGFyYW0geHMgZnVuY3Rpb25zIChmLCBnKVxuICogQHJldHVybnMgKGYg4pa3IGcpLCBvciBnKGYoeCkpXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGZuID0geGZ1bmN0aW9uLmNvbXBvc2VSaWdodChNYXRoLmFicywgTWF0aC5zcXJ0KTtcbiAqIGZuKC02NCk7ICAvLyBNYXRoLnNxcnQoTWF0aC5hYnMoLTY0KSlcbiAqIC8vIOKGkiA4XG4gKlxuICogdmFyIGZuID0geGZ1bmN0aW9uLmNvbXBvc2VSaWdodChNYXRoLm1pbiwgTWF0aC5zcXJ0KTtcbiAqIGZuKDIyLCA5KTsgIC8vIE1hdGguc3FydChNYXRoLm1pbigyMiwgOSkpXG4gKiAvLyDihpIgM1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wb3NlUmlnaHQoLi4ueHM6IEZ1bmN0aW9uW10pOiBGdW5jdGlvbiB7XG4gIHJldHVybiAoLi4uYXJnczogdW5rbm93bltdKSA9PiB7XG4gICAgaWYgKHhzLmxlbmd0aD09PTApIHJldHVybjtcbiAgICBsZXQgYSA9IHhzWzBdKC4uLmFyZ3MpO1xuICAgIGZvciAobGV0IGk9MSwgST14cy5sZW5ndGg7IGk8STsgaSsrKVxuICAgICAgYSA9IHhzW2ldKGEpO1xuICAgIHJldHVybiBhO1xuICB9O1xufVxuLy8gLSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xNDU3MTQwL2hhc2tlbGwtY29tcG9zaXRpb24tdnMtZnMtcGlwZS1mb3J3YXJkLW9wZXJhdG9yXG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL2NoYWluLWZ1bmN0aW9uXG5cblxuLyoqXG4gKiBHZW5lcmF0ZSBjdXJyaWVkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEBwYXJhbSBuIG51bWJlciBvZiBwYXJhbWV0ZXJzIFthbGxdXG4gKiBAcmV0dXJucyAocCkocSkoLi4uKSA9PiB4KHAsIHEsIC4uLilcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgc3ViID0gKHg6IG51bWJlciwgeTogbnVtYmVyKSA9PiB4IC0geTtcbiAqIHZhciBmbiAgPSB4ZnVuY3Rpb24uY3Vycnkoc3ViKTtcbiAqIGZuKDIpKDMpOyAgLy8gc3ViKDIsIDMpXG4gKiAvLyDihpIgLTFcbiAqXG4gKiB2YXIgZm4gID0geGZ1bmN0aW9uLmN1cnJ5KE1hdGgubWluLCAzKTtcbiAqIGZuKDUpKDgpKDMpOyAgLy8gTWF0aC5taW4oNSwgOCwgMylcbiAqIC8vIOKGkiAzXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGN1cnJ5KHg6IEZ1bmN0aW9uLCBuOiBudW1iZXI9eC5sZW5ndGgpOiBGdW5jdGlvbiB7XG4gIHJldHVybiAoLi4uYXJnczogdW5rbm93bltdKSA9PiB7XG4gICAgaWYgKGFyZ3MubGVuZ3RoPj1uKSByZXR1cm4geCguLi5hcmdzKTtcbiAgICBlbHNlIHJldHVybiBjdXJyeSgoLi4ucmVzdDogdW5rbm93bltdKSA9PiB4KC4uLmFyZ3MsIC4uLnJlc3QpLCBuLWFyZ3MubGVuZ3RoKTtcbiAgfTtcbn1cbi8vIC0gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvQHNwdWRseS9jdXJyeVxuXG5cbi8qKlxuICogR2VuZXJhdGUgcmlnaHQtY3VycmllZCB2ZXJzaW9uIG9mIGEgZnVuY3Rpb24uXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcGFyYW0gbiBudW1iZXIgb2YgcGFyYW1ldGVycyBbYWxsXVxuICogQHJldHVybnMgKHApKHEpKC4uLikgPT4geCguLi4sIHEsIHApXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIHN1YiA9ICh4OiBudW1iZXIsIHk6IG51bWJlcikgPT4geCAtIHk7XG4gKiB2YXIgZm4gID0geGZ1bmN0aW9uLmN1cnJ5UmlnaHQoc3ViKTtcbiAqIGZuKDIpKDMpOyAgLy8gc3ViKDMsIDIpXG4gKiAvLyDihpIgMVxuICpcbiAqIHZhciBhcnJheSA9IFsxXTtcbiAqIHZhciBwdXNoMiA9ICh4OiBudW1iZXIsIHk6IG51bWJlcikgPT4gYXJyYXkucHVzaCh4LCB5KTtcbiAqIHZhciBmbiAgPSB4ZnVuY3Rpb24uY3VycnlSaWdodChwdXNoMiwgMik7XG4gKiBmbigyKSgzKTsgIC8vIHB1c2gyKDMsIDIpXG4gKiBhcnJheTtcbiAqIC8vIOKGkiBbMSwgMywgMl1cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3VycnlSaWdodCh4OiBGdW5jdGlvbiwgbjogbnVtYmVyPXgubGVuZ3RoKTogRnVuY3Rpb24ge1xuICByZXR1cm4gY3VycnkocmV2ZXJzZSh4KSwgbik7XG59XG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL2xvZGFzaC5jdXJyeXJpZ2h0XG4vLyNlbmRyZWdpb25cblxuXG5cblxuLy8jcmVnaW9uIFRJTUUgQ09OVFJPTFxuLyoqIEludm9jYXRpb24gY29udHJvbCBmb3IgdGltZS9yYXRlLWNvbnRyb2xsZWQgZnVuY3Rpb25zLiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbnZvY2F0aW9uQ29udHJvbCB7XG4gIC8qKiBEaXNhYmxlIGludm9raW5nIG9mIHRhcmdldCBmdW5jdGlvbi4gKi9cbiAgY2xlYXI6ICgpID0+IHZvaWQ7XG4gIC8qKiBJbW1lZGlhdGVseSBpbnZva2UgdGFyZ2V0IGZ1bmN0aW9uLiAqL1xuICBmbHVzaDogKCkgPT4gdm9pZDtcbn1cblxuXG4vKipcbiAqIEdlbmVyYXRlIGRlZmVycmVkIHZlcnNpb24gb2YgYSBmdW5jdGlvbiwgdGhhdCBleGVjdXRlcyBhZnRlciB0aGUgY3VycmVudCBzdGFjayBoYXMgY2xlYXJlZC5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEByZXR1cm5zICguLi5hcmdzKSA9PiBpbnZvY2F0aW9uIGNvbnRyb2xcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgY291bnQgPSAwO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLmRlZmVyKCgpID0+ICsrY291bnQpO1xuICogZm4oKTtcbiAqIGZuKCk7XG4gKiAvLyBgY291bnRgIGluY3JlbWVudGVkIGFmdGVyIDBzXG4gKiAvLyBgY291bnRgIGluY3JlbWVudGVkIGFmdGVyIDBzXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlZmVyKHg6IEZ1bmN0aW9uKTogRnVuY3Rpb24ge1xuICByZXR1cm4gKC4uLmFyZ3M6IHVua25vd25bXSk6IEludm9jYXRpb25Db250cm9sID0+IHtcbiAgICBsZXQgaDogTm9kZUpTLlRpbWVvdXQgfCBudW1iZXIgPSBzZXRUaW1lb3V0KGZsdXNoLCAwKTtcbiAgICBmdW5jdGlvbiBjbGVhcigpIHsgY2xlYXJUaW1lb3V0KGggYXMgbnVtYmVyKTsgaCA9IDA7IH1cbiAgICBmdW5jdGlvbiBmbHVzaCgpIHsgeCguLi5hcmdzKTsgY2xlYXIoKTsgfVxuICAgIHJldHVybiB7Y2xlYXIsIGZsdXNofTtcbiAgfTtcbn1cblxuXG4vKipcbiAqIEdlbmVyYXRlIGRlbGF5ZWQgdmVyc2lvbiBvZiBhIGZ1bmN0aW9uLlxuICogQHBhcmFtIHggYSBmdW5jdGlvblxuICogQHBhcmFtIHQgZGVsYXkgdGltZSAobXMpXG4gKiBAcmV0dXJucyAoLi4uYXJncykgPT4gaW52b2NhdGlvbiBjb250cm9sXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGNvdW50ID0gMDtcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5kZWxheSgoKSA9PiArK2NvdW50LCA1MDApO1xuICogc2V0VGltZW91dChmbiwgMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAxMDAwKTtcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMC41c1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciAxLjVzXG4gKlxuICpcbiAqIHZhciBjb3VudCA9IDA7XG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24uZGVsYXkoKCkgPT4gKytjb3VudCwgNTAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDApO1xuICogc2V0VGltZW91dChmbiwgMTAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAyMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDMwMDApO1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciAwLjVzXG4gKiAvLyBgY291bnRgIGluY3JlbWVudGVkIGFmdGVyIDEuNXNcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMi41c1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciAzLjVzXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlbGF5KHg6IEZ1bmN0aW9uLCB0OiBudW1iZXIpOiBGdW5jdGlvbiB7XG4gIHJldHVybiAoLi4uYXJnczogdW5rbm93bltdKTogSW52b2NhdGlvbkNvbnRyb2wgPT4ge1xuICAgIGxldCBoOiBOb2RlSlMuVGltZW91dCB8IG51bWJlciA9IHNldFRpbWVvdXQoZmx1c2gsIHQpO1xuICAgIGZ1bmN0aW9uIGNsZWFyKCkgeyBjbGVhclRpbWVvdXQoaCBhcyBudW1iZXIpOyBoID0gMDsgfVxuICAgIGZ1bmN0aW9uIGZsdXNoKCkgeyB4KC4uLmFyZ3MpOyBjbGVhcigpOyB9XG4gICAgcmV0dXJuIHtjbGVhciwgZmx1c2h9O1xuICB9XG59XG4vLyNlbmRyZWdpb25cblxuXG5cblxuLy8jcmVnaW9uIFJBVEUgQ09OVFJPTCAoQ09VTlQpXG4vKipcbiAqIEdlbmVyYXRlIHJlc3RyaWN0ZWQtdXNlIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEBwYXJhbSBzdGFydCB1c2FibGUgZnJvbVxuICogQHBhcmFtIGVuZCB1c2FibGUgdGlsbCAoZXhjbHVkaW5nKSBbLTEg4oeSIGVuZF1cbiAqIEByZXR1cm5zICguLi5hcmdzKSA9PiB4KC4uLmFyZ3MpIGZyb20gW3N0YXJ0OmVuZF0gY2FsbHNcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgc3VtID0gMDtcbiAqIHZhciBhZGQgPSAoeDogbnVtYmVyKSA9PiBzdW0gKz0geDtcbiAqIHZhciBmbiAgPSB4ZnVuY3Rpb24ucmVzdHJpY3QoYWRkLCAwLCA0KTtcbiAqIGZvciAodmFyIGk9MDsgaTwxMDsgKytpKVxuICogICBmbihpKTtcbiAqIHN1bTsgIC8vIDAgKyAxICsgMiArIDNcbiAqIC8vIOKGkiA2XG4gKlxuICpcbiAqIHZhciBzdW0gPSAwO1xuICogdmFyIGFkZCA9ICh4OiBudW1iZXIpID0+IHN1bSArPSB4O1xuICogdmFyIGZuICA9IHhmdW5jdGlvbi5yZXN0cmljdChhZGQsIDQsIDgpO1xuICogZm9yICh2YXIgaT0wOyBpPDEwOyArK2kpXG4gKiAgIGZuKGkpO1xuICogc3VtOyAgLy8gNCArIDUgKyA2ICsgN1xuICogLy8g4oaSIDIyXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc3RyaWN0KHg6IEZ1bmN0aW9uLCBzdGFydDogbnVtYmVyLCBlbmQ6IG51bWJlcj0tMSk6IEZ1bmN0aW9uIHtcbiAgbGV0IGkgPSAtMTtcbiAgcmV0dXJuICguLi5hcmdzOiB1bmtub3duW10pID0+IHtcbiAgICBpZiAoKCsraTxzdGFydCk9PT0oaTxlbmQgfHwgZW5kPDApKSByZXR1cm47XG4gICAgcmV0dXJuIHgoLi4uYXJncyk7XG4gIH07XG59XG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL29uZS10aW1lXG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL29uZXRpbWVcbi8vIC0gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2Uvb25jZVxuLy8gLSBodHRwczovL2xvZGFzaC5jb20vZG9jcy80LjE3LjE1I2FmdGVyXG4vLyAtIGh0dHBzOi8vbG9kYXNoLmNvbS9kb2NzLzQuMTcuMTUjYmVmb3JlXG5cblxuLyoqXG4gKiBSZXN0cmljdCBhIGZ1bmN0aW9uIHRvIGJlIHVzZWQgb25seSBvbmNlLlxuICogQHBhcmFtIHggYSBmdW5jdGlvblxuICogQHJldHVybnMgKC4uLmFyZ3MpID0+IHgoLi4uYXJncykgZnJvbSBbMDoxXSBjYWxsc1xuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHZhciBjb3VudCA9IDA7XG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24ucmVzdHJpY3RPbmNlKHggPT4gKytjb3VudCk7XG4gKiBmb3IgKHZhciBpPTA7IGk8MTA7ICsraSlcbiAqICAgZm4oaSk7XG4gKiBjb3VudDtcbiAqIC8vIOKGkiAxXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc3RyaWN0T25jZSh4OiBGdW5jdGlvbik6IEZ1bmN0aW9uIHtcbiAgcmV0dXJuIHJlc3RyaWN0KHgsIDAsIDEpO1xufVxuZXhwb3J0IHtyZXN0cmljdE9uY2UgYXMgb25jZX07XG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL29uZS10aW1lXG4vLyAtIGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL29uZXRpbWVcbi8vIC0gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2Uvb25jZVxuXG5cbi8qKlxuICogUmVzdHJpY3QgYSBmdW5jdGlvbiB0byBiZSB1c2VkIG9ubHkgdXB0byBhIGNlcnRhaW4gbnVtYmVyIG9mIGNhbGxzLlxuICogQHBhcmFtIHggYSBmdW5jdGlvblxuICogQHBhcmFtIG4gbnVtYmVyIG9mIGNhbGxzIHVwdG8gd2hpY2ggaXQgaXMgdXNhYmxlXG4gKiBAcmV0dXJucyAoLi4uYXJncykgPT4geCguLi5hcmdzKSBmcm9tIFswOm5dIGNhbGxzXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGNvdW50ID0gMDtcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5yZXN0cmljdEJlZm9yZSh4ID0+ICsrY291bnQsIDMpO1xuICogZm9yICh2YXIgaT0wOyBpPDEwOyArK2kpXG4gKiAgIGZuKGkpO1xuICogY291bnQ7XG4gKiAvLyDihpIgM1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXN0cmljdEJlZm9yZSh4OiBGdW5jdGlvbiwgbjogbnVtYmVyKTogRnVuY3Rpb24ge1xuICByZXR1cm4gcmVzdHJpY3QoeCwgMCwgbik7XG59XG5leHBvcnQge3Jlc3RyaWN0QmVmb3JlIGFzIGJlZm9yZX07XG4vLyAtIGh0dHBzOi8vbG9kYXNoLmNvbS9kb2NzLzQuMTcuMTUjYmVmb3JlXG5cblxuLyoqXG4gKiBSZXN0cmljdCBhIGZ1bmN0aW9uIHRvIGJlIHVzZWQgb25seSBhZnRlciBhIGNlcnRhaW4gbnVtYmVyIG9mIGNhbGxzLlxuICogQHBhcmFtIHggYSBmdW5jdGlvblxuICogQHBhcmFtIG4gbnVtYmVyIG9mIGNhbGxzIGFmdGVyIHdoaWNoIGl0IGlzIHVzYWJsZVxuICogQHJldHVybnMgKC4uLmFyZ3MpID0+IHgoLi4uYXJncykgZnJvbSBbbjplbmRdIGNhbGxzXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGNvdW50ID0gMDtcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi5yZXN0cmljdEFmdGVyKHggPT4gKytjb3VudCwgMyk7XG4gKiBmb3IgKHZhciBpPTA7IGk8MTA7ICsraSlcbiAqICAgZm4oaSk7XG4gKiBjb3VudDtcbiAqIC8vIOKGkiA3XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc3RyaWN0QWZ0ZXIoeDogRnVuY3Rpb24sIG46IG51bWJlcik6IEZ1bmN0aW9uIHtcbiAgcmV0dXJuIHJlc3RyaWN0KHgsIG4pO1xufVxuZXhwb3J0IHtyZXN0cmljdEFmdGVyIGFzIGFmdGVyfTtcbi8vIC0gaHR0cHM6Ly9sb2Rhc2guY29tL2RvY3MvNC4xNy4xNSNhZnRlclxuLy8jZW5kcmVnaW9uXG5cblxuXG5cbi8vI3JlZ2lvbiBSQVRFIENPTlRST0wgKFRJTUUpXG4vKipcbiAqIEdlbmVyYXRlIGRlYm91bmNlZCB2ZXJzaW9uIG9mIGEgZnVuY3Rpb24uXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcGFyYW0gdCBkZWxheSB0aW1lIChtcylcbiAqIEBwYXJhbSBUIG1heCBkZWxheSB0aW1lIFstMSDih5Igbm9uZV1cbiAqIEByZXR1cm5zICguLi5hcmdzKSA9PiBpbnZvY2F0aW9uIGNvbnRyb2xcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgY291bnQgPSAwO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLmRlYm91bmNlKCgpID0+ICsrY291bnQsIDE1MDApO1xuICogc2V0VGltZW91dChmbiwgMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAxMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDIwMDApO1xuICogc2V0VGltZW91dChmbiwgNDAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA1MDAwKTtcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMy41c1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciA2LjVzXG4gKlxuICpcbiAqIHZhciBjb3VudCA9IDA7XG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24uZGVib3VuY2UoKCkgPT4gKytjb3VudCwgMTUwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDUwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAxMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDE1MDApO1xuICogc2V0VGltZW91dChmbiwgMjAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA0MDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDQ1MDApO1xuICogc2V0VGltZW91dChmbiwgNTAwMCk7XG4gKiAvLyBgY291bnRgIGluY3JlbWVudGVkIGFmdGVyIDMuNXNcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgNi41c1xuICpcbiAqXG4gKiB2YXIgY291bnQgPSAwO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLmRlYm91bmNlKCgpID0+ICsrY291bnQsIDE1MDAsIDM1MDApO1xuICogc2V0VGltZW91dChmbiwgMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAxMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDIwMDApO1xuICogc2V0VGltZW91dChmbiwgMzAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA0MDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDYwMDApO1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciAzLjVzXG4gKiAvLyBgY291bnRgIGluY3JlbWVudGVkIGFmdGVyIDUuNXNcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgNy41c1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWJvdW5jZSh4OiBGdW5jdGlvbiwgdDogbnVtYmVyLCBUOiBudW1iZXI9LTEpOiBGdW5jdGlvbiB7XG4gIGxldCBzYXZlZEFyZ3M6IHVua25vd25bXTtcbiAgbGV0IGggPSAwIGFzIE5vZGVKUy5UaW1lb3V0IHwgbnVtYmVyLCBIID0gMCBhcyBOb2RlSlMuVGltZW91dCB8IG51bWJlcjtcbiAgZnVuY3Rpb24gY2xlYXIoKSB7XG4gICAgY2xlYXJUaW1lb3V0KGggYXMgbnVtYmVyKTtcbiAgICBjbGVhclRpbWVvdXQoSCBhcyBudW1iZXIpO1xuICAgIGggPSBIID0gMDtcbiAgfVxuICBmdW5jdGlvbiBmbHVzaCgpIHsgeCguLi5zYXZlZEFyZ3MpOyBjbGVhcigpOyB9O1xuICByZXR1cm4gKC4uLmFyZ3M6IHVua25vd25bXSk6IEludm9jYXRpb25Db250cm9sID0+IHtcbiAgICBzYXZlZEFyZ3MgPSBhcmdzO1xuICAgIGlmIChUPj0wKSAgSCA9IEggfHwgc2V0VGltZW91dChmbHVzaCwgVCk7XG4gICAgaWYgKFQ8MCB8fCB0PFQpIHsgY2xlYXJUaW1lb3V0KGggYXMgbnVtYmVyKTsgaCA9IHNldFRpbWVvdXQoZmx1c2gsIHQpOyB9XG4gICAgcmV0dXJuIHtjbGVhciwgZmx1c2h9O1xuICB9O1xufVxuLy8gLSBodHRwczovL2dpdGh1Yi5jb20vbG9kYXNoL2xvZGFzaC9ibG9iLzQuOC4wLW5wbS9kZWJvdW5jZS5qc1xuLy8gLSBodHRwczovL2dpdGh1Yi5jb20vamFzaGtlbmFzL3VuZGVyc2NvcmUvY29tbWl0LzllM2UwNjdmNTAyNWRiZTVlOTNlZDc4NGY5M2IyMzM4ODJjYTBmZmVcbi8vIC0gaHR0cHM6Ly9jc3MtdHJpY2tzLmNvbS9kZWJvdW5jaW5nLXRocm90dGxpbmctZXhwbGFpbmVkLWV4YW1wbGVzL1xuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9kZWJvdW5jZVxuXG5cbi8qKlxuICogR2VuZXJhdGUgbGVhZGluZy1lZGdlIGRlYm91bmNlZCB2ZXJzaW9uIG9mIGEgZnVuY3Rpb24uXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcGFyYW0gdCBkZWxheSB0aW1lIChtcylcbiAqIEBwYXJhbSBUIG1heCBkZWxheSB0aW1lIFstMSDih5Igbm9uZV1cbiAqIEByZXR1cm5zICguLi5hcmdzKSA9PiBpbnZvY2F0aW9uIGNvbnRyb2xcbiAqIEBleGFtcGxlXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgY291bnQgPSAwO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLmRlYm91bmNlRWFybHkoKCkgPT4gKytjb3VudCwgMTUwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDEwMDApO1xuICogc2V0VGltZW91dChmbiwgMjAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA0MDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDUwMDApO1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciAwc1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciA0c1xuICpcbiAqXG4gKiB2YXIgY291bnQgPSAwO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLmRlYm91bmNlRWFybHkoKCkgPT4gKytjb3VudCwgMTUwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDUwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAxMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDE1MDApO1xuICogc2V0VGltZW91dChmbiwgMjAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA0MDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDQ1MDApO1xuICogc2V0VGltZW91dChmbiwgNTAwMCk7XG4gKiAvLyBgY291bnRgIGluY3JlbWVudGVkIGFmdGVyIDBzXG4gKiAvLyBgY291bnRgIGluY3JlbWVudGVkIGFmdGVyIDRzXG4gKlxuICpcbiAqIHZhciBjb3VudCA9IDA7XG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24uZGVib3VuY2VFYXJseSgoKSA9PiArK2NvdW50LCAxNTAwLCAzNTAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDApO1xuICogc2V0VGltZW91dChmbiwgMTAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAyMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDMwMDApO1xuICogc2V0VGltZW91dChmbiwgNDAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA2MDAwKTtcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMHNcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgNHNcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgNnNcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVib3VuY2VFYXJseSh4OiBGdW5jdGlvbiwgdDogbnVtYmVyLCBUOiBudW1iZXI9LTEpOiBGdW5jdGlvbiB7XG4gIGxldCBoID0gMCBhcyBOb2RlSlMuVGltZW91dCB8IG51bWJlciwgSCA9IDAgYXMgTm9kZUpTLlRpbWVvdXQgfCBudW1iZXI7XG4gIGZ1bmN0aW9uIGNsZWFyKCkgeyBoID0gSCA9IDA7IH1cbiAgZnVuY3Rpb24gZmx1c2goKSB7IGNsZWFyKCk7IH1cbiAgcmV0dXJuICguLi5hcmdzOiB1bmtub3duW10pOiBJbnZvY2F0aW9uQ29udHJvbCA9PiB7XG4gICAgaWYgKCFoICYmICFIKSB4KC4uLmFyZ3MpO1xuICAgIGlmIChUPj0wKSAgSCA9IEggfHwgc2V0VGltZW91dChmbHVzaCwgVCk7XG4gICAgaWYgKFQ8MCB8fCB0PFQpIHsgY2xlYXJUaW1lb3V0KGggYXMgbnVtYmVyKTsgaCA9IHNldFRpbWVvdXQoZmx1c2gsIHQpOyB9XG4gICAgcmV0dXJuIHtjbGVhciwgZmx1c2h9O1xuICB9O1xufVxuLy8gLSBodHRwczovL2dpdGh1Yi5jb20vbG9kYXNoL2xvZGFzaC9ibG9iLzQuOC4wLW5wbS9kZWJvdW5jZS5qc1xuLy8gLSBodHRwczovL2dpdGh1Yi5jb20vamFzaGtlbmFzL3VuZGVyc2NvcmUvY29tbWl0LzllM2UwNjdmNTAyNWRiZTVlOTNlZDc4NGY5M2IyMzM4ODJjYTBmZmVcbi8vIC0gaHR0cHM6Ly9jc3MtdHJpY2tzLmNvbS9kZWJvdW5jaW5nLXRocm90dGxpbmctZXhwbGFpbmVkLWV4YW1wbGVzL1xuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9kZWJvdW5jZVxuXG5cbi8qKlxuICogR2VuZXJhdGUgdGhyb3R0bGVkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBwYXJhbSB4IGEgZnVuY3Rpb25cbiAqIEBwYXJhbSB0IHdhaXQgdGltZSAobXMpXG4gKiBAcmV0dXJucyAoLi4uYXJncykgPT4gaW52b2NhdGlvbiBjb250cm9sXG4gKiBAZXhhbXBsZVxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIGNvdW50ID0gMDtcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi50aHJvdHRsZSgoKSA9PiArK2NvdW50LCAyNTAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDApO1xuICogc2V0VGltZW91dChmbiwgMTAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAyMDAwKTtcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMi41c1xuICpcbiAqXG4gKiB2YXIgY291bnQgPSAwO1xuICogdmFyIGZuID0geGZ1bmN0aW9uLnRocm90dGxlKCgpID0+ICsrY291bnQsIDI1MDApO1xuICogc2V0VGltZW91dChmbiwgMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAxMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDIwMDApO1xuICogc2V0VGltZW91dChmbiwgMzAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA0MDAwKTtcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMi41c1xuICogLy8gYGNvdW50YCBpbmNyZW1lbnRlZCBhZnRlciA1LjVzXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRocm90dGxlKHg6IEZ1bmN0aW9uLCB0OiBudW1iZXIpOiBGdW5jdGlvbiB7XG4gIGxldCBzYXZlZEFyZ3M6IHVua25vd25bXTtcbiAgbGV0IGggPSAwIGFzIE5vZGVKUy5UaW1lb3V0IHwgbnVtYmVyO1xuICBmdW5jdGlvbiBjbGVhcigpIHsgaCA9IDA7IH1cbiAgZnVuY3Rpb24gZmx1c2goKSB7IHgoLi4uc2F2ZWRBcmdzKTsgY2xlYXIoKTsgfVxuICByZXR1cm4gKC4uLmFyZ3M6IHVua25vd25bXSk6IEludm9jYXRpb25Db250cm9sID0+IHtcbiAgICBzYXZlZEFyZ3MgPSBhcmdzO1xuICAgIGggPSBoIHx8IHNldFRpbWVvdXQoZmx1c2gsIHQpO1xuICAgIHJldHVybiB7Y2xlYXIsIGZsdXNofTtcbiAgfTtcbn1cbi8vIC0gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvdGhyb3R0bGUtZGVib3VuY2Vcbi8vIC0gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvdGhyb3R0bGVpdFxuXG5cbi8qKlxuICogR2VuZXJhdGUgbGVhZGluZy1lZGdlIHRocm90dGxlZCB2ZXJzaW9uIG9mIGEgZnVuY3Rpb24uXG4gKiBAcGFyYW0geCBhIGZ1bmN0aW9uXG4gKiBAcGFyYW0gdCB3YWl0IHRpbWUgKG1zKVxuICogQHJldHVybnMgKC4uLmFyZ3MpID0+IGludm9jYXRpb24gY29udHJvbFxuICogQGV4YW1wbGVcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHZhciBjb3VudCA9IDA7XG4gKiB2YXIgZm4gPSB4ZnVuY3Rpb24udGhyb3R0bGVFYXJseSgoKSA9PiArK2NvdW50LCAyNTAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDApO1xuICogc2V0VGltZW91dChmbiwgMTAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAyMDAwKTtcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMHNcbiAqXG4gKlxuICogdmFyIGNvdW50ID0gMDtcbiAqIHZhciBmbiA9IHhmdW5jdGlvbi50aHJvdHRsZUVhcmx5KCgpID0+ICsrY291bnQsIDI1MDApO1xuICogc2V0VGltZW91dChmbiwgMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCAxMDAwKTtcbiAqIHNldFRpbWVvdXQoZm4sIDIwMDApO1xuICogc2V0VGltZW91dChmbiwgMzAwMCk7XG4gKiBzZXRUaW1lb3V0KGZuLCA0MDAwKTtcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgMHNcbiAqIC8vIGBjb3VudGAgaW5jcmVtZW50ZWQgYWZ0ZXIgM3NcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gdGhyb3R0bGVFYXJseSh4OiBGdW5jdGlvbiwgdDogbnVtYmVyKTogRnVuY3Rpb24ge1xuICBsZXQgaCA9IDAgYXMgTm9kZUpTLlRpbWVvdXQgfCBudW1iZXI7XG4gIGZ1bmN0aW9uIGNsZWFyKCkgeyBoID0gMDsgfVxuICBmdW5jdGlvbiBmbHVzaCgpIHsgY2xlYXIoKTsgfVxuICByZXR1cm4gKC4uLmFyZ3M6IHVua25vd25bXSk6IEludm9jYXRpb25Db250cm9sID0+IHtcbiAgICBpZiAoIWgpIHgoLi4uYXJncyk7XG4gICAgaCA9IGggfHwgc2V0VGltZW91dChmbHVzaCwgdCk7XG4gICAgcmV0dXJuIHtjbGVhciwgZmx1c2h9O1xuICB9O1xufVxuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS90aHJvdHRsZS1kZWJvdW5jZVxuLy8gLSBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS90aHJvdHRsZWl0XG5cblxuLy8gVE9ETzogSXMgYSBnZW5lcmF0b3IgZnVuY3Rpb24gYmV0dGVyIGZvciB0aGlzP1xuLy8gZnVuY3Rpb24gYmFja29mZlJldHJ5UmVjKHg6IEZ1bmN0aW9uLCBhcmdzOiB1bmtub3duW10sIGVycjogdW5rbm93biwgbjogbnVtYmVyLCBOOiBudW1iZXIsIHQ6IG51bWJlciwgVDogbnVtYmVyLCB0ZjogbnVtYmVyKTogdm9pZCB7XG4vLyAgIGlmIChOPj0wICYmIG4+PU4pIHRocm93IGVycjtcbi8vICAgaWYgKFQ+PTAgJiYgdD49VCkgdGhyb3cgZXJyO1xuLy8gICB0cnkgeyByZXR1cm4geCguLi5hcmdzLCBlcnIpOyB9XG4vLyAgIGNhdGNoKGUpIHsgc2V0VGltZW91dCgoKSA9PiBiYWNrb2ZmUmV0cnlSZWMoeCwgYXJncywgZSwgbisxLCBOLCB0KnRmLCBULCB0ZiksIHQpOyB9XG4vLyB9XG5cbi8vXG4vLyBUT0RPOiBHZW5lcmF0ZSBleHBvbmVudGlhbC1iYWNrb2ZmLXJldHJpZWQgdmVyc2lvbiBvZiBhIGZ1bmN0aW9uLlxuLy8gQHBhcmFtIHggYSBmdW5jdGlvblxuLy8gQHBhcmFtIE4gbWF4aW11bSByZXRyaWVzICgtMSDih5IgdW5saW1pdGVkKVxuLy8gQHBhcmFtIHQgaW5pdGlhbCByZXRyeSB0aW1lICgxIG1zKVxuLy8gQHBhcmFtIFQgbWF4aW11bSByZXRyeSB0aW1lIFstMSDih5Igbm9uZV1cbi8vIEBwYXJhbSB0ZiByZXRyeSB0aW1lIGZhY3RvciBbMl1cbi8vXG4vLyBmdW5jdGlvbiBiYWNrb2ZmUmV0cnkoeDogRnVuY3Rpb24sIE46IG51bWJlciwgdDogbnVtYmVyLCBUOiBudW1iZXI9LTEsIHRmOiBudW1iZXI9Mik6IEZ1bmN0aW9uIHtcbi8vICAgcmV0dXJuICguLi5hcmdzOiB1bmtub3duW10pID0+IGJhY2tvZmZSZXRyeVJlYyh4LCBhcmdzLCBudWxsLCAwLCBOLCB0LCBULCB0Zik7XG4vLyB9XG4vLyAtIFRPRE9cbi8vI2VuZHJlZ2lvblxuLy8jZW5kcmVnaW9uXG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsZUFBZTtBQUNmOzs7O0NBSUMsR0FFRCxZQUFZO0FBS1osbUJBQW1CO0FBQ25COzs7Ozs7Ozs7OztDQVdDLEdBQ0QsT0FBTyxTQUFTLEtBQUssR0FBRyxLQUFnQixHQUFTO0FBQ2pELHlDQUF5QztBQUd6Qzs7Ozs7Ozs7O0NBU0MsR0FDRCxPQUFPLFNBQVMsTUFBTSxHQUFHLEtBQWdCO0VBQ3ZDLE9BQU87QUFDVDtBQUNBLDJDQUEyQztBQUczQzs7Ozs7Ozs7O0NBU0MsR0FDRCxPQUFPLFNBQVMsS0FBSyxHQUFHLEtBQWdCO0VBQ3RDLE9BQU87QUFDVDtBQUNBLDJDQUEyQztBQUczQzs7Ozs7Ozs7Ozs7O0NBWUMsR0FDRCxPQUFPLFNBQVMsU0FBWSxDQUFJO0VBQzlCLE9BQU87QUFDVDtBQUdBOzs7Ozs7Ozs7Ozs7Ozs7Q0FlQyxHQUNELE9BQU8sU0FBUyxRQUFXLENBQUksRUFBRSxDQUFJO0VBQ25DLE9BQU8sSUFBRSxJQUFHLENBQUMsSUFBSyxJQUFFLElBQUcsSUFBSTtBQUM3QjtBQUdBOzs7Ozs7Ozs7Ozs7Q0FZQyxHQUNELE9BQU8sU0FBUyxVQUFVLEdBQUcsSUFBZTtFQUMxQyxPQUFPO0FBQ1Q7QUFDQSxZQUFZO0FBS1osMkJBQTJCO0FBQzNCLGVBQWU7QUFDZjs7Ozs7Ozs7Ozs7Ozs7Q0FjQyxHQUNELE9BQU8sU0FBUyxLQUFLLENBQVc7RUFDOUIsT0FBTyxFQUFFLElBQUk7QUFDZjtBQUNBLG1HQUFtRztBQUNuRywwQ0FBMEM7QUFHMUM7Ozs7Ozs7Ozs7OztDQVlDLEdBQ0QsT0FBTyxTQUFTLE9BQU8sQ0FBVztFQUNoQyxPQUFPLEVBQUUsTUFBTTtBQUNq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