UNPKG

@bitgo/utxo-ord

Version:

Utilities for building ordinals with BitGo utxo-lib

192 lines (182 loc) 19.8 kB
/* Classes used for tracking sats across transactions. https://github.com/casey/ord/blob/master/bip.mediawiki#design > The ordinal numbers of sats in transaction inputs are transferred to output sats in > first-in-first-out order, according to the size and order of the transactions inputs and outputs. Sample scenario: inputs i0, i1, i2 outputs u0, u1 inscriptions r0, r1, r2, r3, r4 createOutputs( [i0, i1], [ [u0, [r0, r1]], [u1, [r2, r3]], ] ); r4 is donated to the miner ┌────────┬────────┐ │ i0 │ u0 │ │ │ │ │ r0 ┼ │ │ │ │ ├────────┤ │ │ i1 │ │ │ r1 ┼ │ │ │ │ │ ├────────┤ │ │ u1 │ │ r2 ┼ │ │ │ │ ├────────┤ │ │ i2 │ │ │ r3 ┼ │ │ │ │ │ │ │ │ ├────────┘ │ │ │ r4 ┼ │ │ └────────┘ */ import { SatRange } from './SatRange'; export class InvalidOrdOutput extends Error { constructor(message, value, ordinals) { super(message); this.value = value; this.ordinals = ordinals; } } /** * The ordinal metadata for an output */ export class OrdOutput { /** * @param value - the input value * @param ordinals - The ordinal ranges of an output, relative to the first satoshi. * Required to be ordered and non-overlapping. * Not required to be exhaustive. */ constructor(value, ordinals = []) { this.value = value; this.ordinals = ordinals; const maxRange = this.asSatRange(); ordinals.forEach((r, i) => { if (!maxRange.isSupersetOf(r)) { throw new InvalidOrdOutput(`range ${r} outside output maxRange ${maxRange}`, value, ordinals); } if (0 < i) { const prevRange = ordinals[i - 1]; if (r.start <= prevRange.end) { throw new InvalidOrdOutput(`SatRange #${i - 1} ${prevRange} overlaps SatRange #${i} ${r}`, value, ordinals); } } }); } /** * @param other * @return OrdOutput extended by other.value and SatRanges shifted by this.value */ joinedWith(other) { return new OrdOutput(this.value + other.value, [ ...this.ordinals, ...other.ordinals.map((r) => r.shiftedBy(this.value)), ]); } /** * @param ords * @return single OrdOutput containing all SatRanges, shifted by preceding output values */ static joinAll(ords) { if (ords.length === 0) { throw new TypeError(`empty input`); } return ords.reduce((a, b) => a.joinedWith(b)); } asSatRange() { return new SatRange(BigInt(0), this.value - BigInt(1)); } /** * @param r * @return new OrdOutput with all ranges fully contained in _r_. SatRanges are aligned to new start. */ fromSatRange(r) { return new OrdOutput(r.size(), this.ordinals.flatMap((s) => { if (r.intersectsWith(s)) { if (!r.isSupersetOf(s)) { throw new Error(`partial overlap in ${r} and ${s}`); } return s.shiftedBy(-r.start); } return []; })); } /** * @param value * @return first OrdOutput with value `value`, second OrdOutput with remaining value. * With respective SatRanges */ splitAt(value) { if (this.value < value) { throw new Error(`must split at value inside range`); } return [ this.fromSatRange(new SatRange(BigInt(0), value - BigInt(1))), this.fromSatRange(new SatRange(value, this.value - BigInt(1))), ]; } /** * Like splitAt but returns _null_ where a zero-sized OrdOutput would be * @param value */ splitAtAllowZero(value) { if (value === BigInt(0)) { return [null, this.fromSatRange(this.asSatRange())]; } if (value === this.value) { return [this.fromSatRange(this.asSatRange()), null]; } return this.splitAt(value); } /** * Split output successively at values. * @param values * @param exact - when set, ensure that value sum matches _this.value_ * @param allowZero - when set, return _null_ for zero-sized values * @return (OrdOutput | null)[]. Zero-sized outputs are substituted with _null_. */ splitAllWithParams(values, { exact = false, allowZero = false }) { if (values.length === 0) { throw new Error(`invalid argument`); } if (exact) { const valueSum = values.reduce((a, b) => a + b, BigInt(0)); if (this.value !== valueSum) { throw new Error(`value sum ${valueSum} does not match this.value ${this.value}`); } return this.splitAllWithParams(values.slice(0, -1), { allowZero, exact: false }); } const [v, ...rest] = values; const [a, b] = allowZero ? this.splitAtAllowZero(v) : this.splitAt(v); if (rest.length) { if (b === null) { throw new Error(`invalid remainder`); } else { return [a, ...b.splitAllWithParams(rest, { exact, allowZero })]; } } else { return [a, b]; } } /** * Split output successively at values. * @param values * @return OrdOutput[] with length _values.length + 1_ */ splitAll(values) { return this.splitAllWithParams(values, { exact: false, allowZero: false }); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT3JkT3V0cHV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL09yZE91dHB1dC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrREc7QUFFSCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRXRDLE1BQU0sT0FBTyxnQkFBaUIsU0FBUSxLQUFLO0lBQ3pDLFlBQVksT0FBZSxFQUFTLEtBQWEsRUFBUyxRQUFvQjtRQUM1RSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFEbUIsVUFBSyxHQUFMLEtBQUssQ0FBUTtRQUFTLGFBQVEsR0FBUixRQUFRLENBQVk7SUFFOUUsQ0FBQztDQUNGO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sU0FBUztJQUNwQjs7Ozs7T0FLRztJQUNILFlBQW1CLEtBQWEsRUFBUyxXQUF1QixFQUFFO1FBQS9DLFVBQUssR0FBTCxLQUFLLENBQVE7UUFBUyxhQUFRLEdBQVIsUUFBUSxDQUFpQjtRQUNoRSxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDbkMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN4QixJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUM5QixNQUFNLElBQUksZ0JBQWdCLENBQUMsU0FBUyxDQUFDLDRCQUE0QixRQUFRLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDaEcsQ0FBQztZQUNELElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNWLE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQ2xDLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUM7b0JBQzdCLE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksU0FBUyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQztnQkFDOUcsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7O09BR0c7SUFDSCxVQUFVLENBQUMsS0FBZ0I7UUFDekIsT0FBTyxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxLQUFLLEVBQUU7WUFDN0MsR0FBRyxJQUFJLENBQUMsUUFBUTtZQUNoQixHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUN0RCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFpQjtRQUM5QixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDdEIsTUFBTSxJQUFJLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUNyQyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTyxJQUFJLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsWUFBWSxDQUFDLENBQVc7UUFDdEIsT0FBTyxJQUFJLFNBQVMsQ0FDbEIsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUNSLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDMUIsSUFBSSxDQUFDLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3hCLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7b0JBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsc0JBQXNCLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUN0RCxDQUFDO2dCQUNELE9BQU8sQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMvQixDQUFDO1lBQ0QsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxPQUFPLENBQUMsS0FBYTtRQUNuQixJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxFQUFFLENBQUM7WUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1FBQ3RELENBQUM7UUFDRCxPQUFPO1lBQ0wsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzdELElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxRQUFRLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDL0QsQ0FBQztJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSCxnQkFBZ0IsQ0FBQyxLQUFhO1FBQzVCLElBQUksS0FBSyxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3RELENBQUM7UUFDRCxJQUFJLEtBQUssS0FBSyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDekIsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDdEQsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsa0JBQWtCLENBQ2hCLE1BQWdCLEVBQ2hCLEVBQUUsS0FBSyxHQUFHLEtBQUssRUFBRSxTQUFTLEdBQUcsS0FBSyxFQUE0QztRQUU5RSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDeEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFDRCxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0QsSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLGFBQWEsUUFBUSw4QkFBOEIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDbkYsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDbkYsQ0FBQztRQUNELE1BQU0sQ0FBQyxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUM7UUFDNUIsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0RSxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDZixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDdkMsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE9BQU8sQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsa0JBQWtCLENBQUMsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNsRSxDQUFDO1FBQ0gsQ0FBQzthQUFNLENBQUM7WUFDTixPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ2hCLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFFBQVEsQ0FBQyxNQUFnQjtRQUN2QixPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsQ0FBZ0IsQ0FBQztJQUM1RixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuXG5DbGFzc2VzIHVzZWQgZm9yIHRyYWNraW5nIHNhdHMgYWNyb3NzIHRyYW5zYWN0aW9ucy5cblxuaHR0cHM6Ly9naXRodWIuY29tL2Nhc2V5L29yZC9ibG9iL21hc3Rlci9iaXAubWVkaWF3aWtpI2Rlc2lnblxuXG4+IFRoZSBvcmRpbmFsIG51bWJlcnMgb2Ygc2F0cyBpbiB0cmFuc2FjdGlvbiBpbnB1dHMgYXJlIHRyYW5zZmVycmVkIHRvIG91dHB1dCBzYXRzIGluXG4+IGZpcnN0LWluLWZpcnN0LW91dCBvcmRlciwgYWNjb3JkaW5nIHRvIHRoZSBzaXplIGFuZCBvcmRlciBvZiB0aGUgdHJhbnNhY3Rpb25zIGlucHV0cyBhbmQgb3V0cHV0cy5cblxuXG5TYW1wbGUgc2NlbmFyaW86XG4gICBpbnB1dHMgICAgICAgICBpMCwgaTEsIGkyXG4gICBvdXRwdXRzICAgICAgICB1MCwgdTFcbiAgIGluc2NyaXB0aW9ucyAgIHIwLCByMSwgcjIsIHIzLCByNFxuXG5cbmNyZWF0ZU91dHB1dHMoXG4gIFtpMCwgaTFdLFxuICBbXG4gICAgW3UwLCBbcjAsIHIxXV0sXG4gICAgW3UxLCBbcjIsIHIzXV0sXG4gIF1cbik7XG5cbiAgcjQgaXMgZG9uYXRlZCB0byB0aGUgbWluZXJcblxuICDilIzilIDilIDilIDilIDilIDilIDilIDilIDilKzilIDilIDilIDilIDilIDilIDilIDilIDilJBcbiAg4pSCIGkwICAgICDilIIgdTAgICAgIOKUglxuICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gIOKUgiAgICAgcjAg4pS8ICAgICAgICDilIJcbiAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICDilJzilIDilIDilIDilIDilIDilIDilIDilIDilKQgICAgICAgIOKUglxuICDilIIgaTEgICAgIOKUgiAgICAgICAg4pSCXG4gIOKUgiAgICAgcjEg4pS8ICAgICAgICDilIJcbiAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICDilIIgICAgICAgIOKUnOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUpFxuICDilIIgICAgICAgIOKUgiB1MSAgICAg4pSCXG4gIOKUgiAgICAgcjIg4pS8ICAgICAgICDilIJcbiAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICDilJzilIDilIDilIDilIDilIDilIDilIDilIDilKQgICAgICAgIOKUglxuICDilIIgaTIgICAgIOKUgiAgICAgICAg4pSCXG4gIOKUgiAgICAgcjMg4pS8ICAgICAgICDilIJcbiAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gIOKUgiAgICAgICAg4pSc4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSYXG4gIOKUgiAgICAgICAg4pSCXG4gIOKUgiAgICAgcjQg4pS8XG4gIOKUgiAgICAgICAg4pSCXG4gIOKUlOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmFxuXG4gKi9cblxuaW1wb3J0IHsgU2F0UmFuZ2UgfSBmcm9tICcuL1NhdFJhbmdlJztcblxuZXhwb3J0IGNsYXNzIEludmFsaWRPcmRPdXRwdXQgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZywgcHVibGljIHZhbHVlOiBiaWdpbnQsIHB1YmxpYyBvcmRpbmFsczogU2F0UmFuZ2VbXSkge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICB9XG59XG5cbi8qKlxuICogVGhlIG9yZGluYWwgbWV0YWRhdGEgZm9yIGFuIG91dHB1dFxuICovXG5leHBvcnQgY2xhc3MgT3JkT3V0cHV0IHtcbiAgLyoqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIHRoZSBpbnB1dCB2YWx1ZVxuICAgKiBAcGFyYW0gb3JkaW5hbHMgLSBUaGUgb3JkaW5hbCByYW5nZXMgb2YgYW4gb3V0cHV0LCByZWxhdGl2ZSB0byB0aGUgZmlyc3Qgc2F0b3NoaS5cbiAgICogICAgICAgICAgICAgICAgICAgUmVxdWlyZWQgdG8gYmUgb3JkZXJlZCBhbmQgbm9uLW92ZXJsYXBwaW5nLlxuICAgKiAgICAgICAgICAgICAgICAgICBOb3QgcmVxdWlyZWQgdG8gYmUgZXhoYXVzdGl2ZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyB2YWx1ZTogYmlnaW50LCBwdWJsaWMgb3JkaW5hbHM6IFNhdFJhbmdlW10gPSBbXSkge1xuICAgIGNvbnN0IG1heFJhbmdlID0gdGhpcy5hc1NhdFJhbmdlKCk7XG4gICAgb3JkaW5hbHMuZm9yRWFjaCgociwgaSkgPT4ge1xuICAgICAgaWYgKCFtYXhSYW5nZS5pc1N1cGVyc2V0T2YocikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRPcmRPdXRwdXQoYHJhbmdlICR7cn0gb3V0c2lkZSBvdXRwdXQgbWF4UmFuZ2UgJHttYXhSYW5nZX1gLCB2YWx1ZSwgb3JkaW5hbHMpO1xuICAgICAgfVxuICAgICAgaWYgKDAgPCBpKSB7XG4gICAgICAgIGNvbnN0IHByZXZSYW5nZSA9IG9yZGluYWxzW2kgLSAxXTtcbiAgICAgICAgaWYgKHIuc3RhcnQgPD0gcHJldlJhbmdlLmVuZCkge1xuICAgICAgICAgIHRocm93IG5ldyBJbnZhbGlkT3JkT3V0cHV0KGBTYXRSYW5nZSAjJHtpIC0gMX0gJHtwcmV2UmFuZ2V9IG92ZXJsYXBzIFNhdFJhbmdlICMke2l9ICR7cn1gLCB2YWx1ZSwgb3JkaW5hbHMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIG90aGVyXG4gICAqIEByZXR1cm4gT3JkT3V0cHV0IGV4dGVuZGVkIGJ5IG90aGVyLnZhbHVlIGFuZCBTYXRSYW5nZXMgc2hpZnRlZCBieSB0aGlzLnZhbHVlXG4gICAqL1xuICBqb2luZWRXaXRoKG90aGVyOiBPcmRPdXRwdXQpOiBPcmRPdXRwdXQge1xuICAgIHJldHVybiBuZXcgT3JkT3V0cHV0KHRoaXMudmFsdWUgKyBvdGhlci52YWx1ZSwgW1xuICAgICAgLi4udGhpcy5vcmRpbmFscyxcbiAgICAgIC4uLm90aGVyLm9yZGluYWxzLm1hcCgocikgPT4gci5zaGlmdGVkQnkodGhpcy52YWx1ZSkpLFxuICAgIF0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBvcmRzXG4gICAqIEByZXR1cm4gc2luZ2xlIE9yZE91dHB1dCBjb250YWluaW5nIGFsbCBTYXRSYW5nZXMsIHNoaWZ0ZWQgYnkgcHJlY2VkaW5nIG91dHB1dCB2YWx1ZXNcbiAgICovXG4gIHN0YXRpYyBqb2luQWxsKG9yZHM6IE9yZE91dHB1dFtdKTogT3JkT3V0cHV0IHtcbiAgICBpZiAob3Jkcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYGVtcHR5IGlucHV0YCk7XG4gICAgfVxuICAgIHJldHVybiBvcmRzLnJlZHVjZSgoYSwgYikgPT4gYS5qb2luZWRXaXRoKGIpKTtcbiAgfVxuXG4gIGFzU2F0UmFuZ2UoKTogU2F0UmFuZ2Uge1xuICAgIHJldHVybiBuZXcgU2F0UmFuZ2UoQmlnSW50KDApLCB0aGlzLnZhbHVlIC0gQmlnSW50KDEpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gclxuICAgKiBAcmV0dXJuIG5ldyBPcmRPdXRwdXQgd2l0aCBhbGwgcmFuZ2VzIGZ1bGx5IGNvbnRhaW5lZCBpbiBfcl8uIFNhdFJhbmdlcyBhcmUgYWxpZ25lZCB0byBuZXcgc3RhcnQuXG4gICAqL1xuICBmcm9tU2F0UmFuZ2UocjogU2F0UmFuZ2UpOiBPcmRPdXRwdXQge1xuICAgIHJldHVybiBuZXcgT3JkT3V0cHV0KFxuICAgICAgci5zaXplKCksXG4gICAgICB0aGlzLm9yZGluYWxzLmZsYXRNYXAoKHMpID0+IHtcbiAgICAgICAgaWYgKHIuaW50ZXJzZWN0c1dpdGgocykpIHtcbiAgICAgICAgICBpZiAoIXIuaXNTdXBlcnNldE9mKHMpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHBhcnRpYWwgb3ZlcmxhcCBpbiAke3J9IGFuZCAke3N9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBzLnNoaWZ0ZWRCeSgtci5zdGFydCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB2YWx1ZVxuICAgKiBAcmV0dXJuIGZpcnN0IE9yZE91dHB1dCB3aXRoIHZhbHVlIGB2YWx1ZWAsIHNlY29uZCBPcmRPdXRwdXQgd2l0aCByZW1haW5pbmcgdmFsdWUuXG4gICAqICAgICAgICAgV2l0aCByZXNwZWN0aXZlIFNhdFJhbmdlc1xuICAgKi9cbiAgc3BsaXRBdCh2YWx1ZTogYmlnaW50KTogW09yZE91dHB1dCwgT3JkT3V0cHV0XSB7XG4gICAgaWYgKHRoaXMudmFsdWUgPCB2YWx1ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBtdXN0IHNwbGl0IGF0IHZhbHVlIGluc2lkZSByYW5nZWApO1xuICAgIH1cbiAgICByZXR1cm4gW1xuICAgICAgdGhpcy5mcm9tU2F0UmFuZ2UobmV3IFNhdFJhbmdlKEJpZ0ludCgwKSwgdmFsdWUgLSBCaWdJbnQoMSkpKSxcbiAgICAgIHRoaXMuZnJvbVNhdFJhbmdlKG5ldyBTYXRSYW5nZSh2YWx1ZSwgdGhpcy52YWx1ZSAtIEJpZ0ludCgxKSkpLFxuICAgIF07XG4gIH1cblxuICAvKipcbiAgICogTGlrZSBzcGxpdEF0IGJ1dCByZXR1cm5zIF9udWxsXyB3aGVyZSBhIHplcm8tc2l6ZWQgT3JkT3V0cHV0IHdvdWxkIGJlXG4gICAqIEBwYXJhbSB2YWx1ZVxuICAgKi9cbiAgc3BsaXRBdEFsbG93WmVybyh2YWx1ZTogYmlnaW50KTogW09yZE91dHB1dCB8IG51bGwsIE9yZE91dHB1dCB8IG51bGxdIHtcbiAgICBpZiAodmFsdWUgPT09IEJpZ0ludCgwKSkge1xuICAgICAgcmV0dXJuIFtudWxsLCB0aGlzLmZyb21TYXRSYW5nZSh0aGlzLmFzU2F0UmFuZ2UoKSldO1xuICAgIH1cbiAgICBpZiAodmFsdWUgPT09IHRoaXMudmFsdWUpIHtcbiAgICAgIHJldHVybiBbdGhpcy5mcm9tU2F0UmFuZ2UodGhpcy5hc1NhdFJhbmdlKCkpLCBudWxsXTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuc3BsaXRBdCh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogU3BsaXQgb3V0cHV0IHN1Y2Nlc3NpdmVseSBhdCB2YWx1ZXMuXG4gICAqIEBwYXJhbSB2YWx1ZXNcbiAgICogQHBhcmFtIGV4YWN0IC0gd2hlbiBzZXQsIGVuc3VyZSB0aGF0IHZhbHVlIHN1bSBtYXRjaGVzIF90aGlzLnZhbHVlX1xuICAgKiBAcGFyYW0gYWxsb3daZXJvIC0gd2hlbiBzZXQsIHJldHVybiBfbnVsbF8gZm9yIHplcm8tc2l6ZWQgdmFsdWVzXG4gICAqIEByZXR1cm4gKE9yZE91dHB1dCB8IG51bGwpW10uIFplcm8tc2l6ZWQgb3V0cHV0cyBhcmUgc3Vic3RpdHV0ZWQgd2l0aCBfbnVsbF8uXG4gICAqL1xuICBzcGxpdEFsbFdpdGhQYXJhbXMoXG4gICAgdmFsdWVzOiBiaWdpbnRbXSxcbiAgICB7IGV4YWN0ID0gZmFsc2UsIGFsbG93WmVybyA9IGZhbHNlIH06IHsgYWxsb3daZXJvPzogYm9vbGVhbjsgZXhhY3Q/OiBib29sZWFuIH1cbiAgKTogKE9yZE91dHB1dCB8IG51bGwpW10ge1xuICAgIGlmICh2YWx1ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgYXJndW1lbnRgKTtcbiAgICB9XG4gICAgaWYgKGV4YWN0KSB7XG4gICAgICBjb25zdCB2YWx1ZVN1bSA9IHZhbHVlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCBCaWdJbnQoMCkpO1xuICAgICAgaWYgKHRoaXMudmFsdWUgIT09IHZhbHVlU3VtKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgc3VtICR7dmFsdWVTdW19IGRvZXMgbm90IG1hdGNoIHRoaXMudmFsdWUgJHt0aGlzLnZhbHVlfWApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuc3BsaXRBbGxXaXRoUGFyYW1zKHZhbHVlcy5zbGljZSgwLCAtMSksIHsgYWxsb3daZXJvLCBleGFjdDogZmFsc2UgfSk7XG4gICAgfVxuICAgIGNvbnN0IFt2LCAuLi5yZXN0XSA9IHZhbHVlcztcbiAgICBjb25zdCBbYSwgYl0gPSBhbGxvd1plcm8gPyB0aGlzLnNwbGl0QXRBbGxvd1plcm8odikgOiB0aGlzLnNwbGl0QXQodik7XG4gICAgaWYgKHJlc3QubGVuZ3RoKSB7XG4gICAgICBpZiAoYiA9PT0gbnVsbCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgcmVtYWluZGVyYCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gW2EsIC4uLmIuc3BsaXRBbGxXaXRoUGFyYW1zKHJlc3QsIHsgZXhhY3QsIGFsbG93WmVybyB9KV07XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBbYSwgYl07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNwbGl0IG91dHB1dCBzdWNjZXNzaXZlbHkgYXQgdmFsdWVzLlxuICAgKiBAcGFyYW0gdmFsdWVzXG4gICAqIEByZXR1cm4gT3JkT3V0cHV0W10gd2l0aCBsZW5ndGggX3ZhbHVlcy5sZW5ndGggKyAxX1xuICAgKi9cbiAgc3BsaXRBbGwodmFsdWVzOiBiaWdpbnRbXSk6IE9yZE91dHB1dFtdIHtcbiAgICByZXR1cm4gdGhpcy5zcGxpdEFsbFdpdGhQYXJhbXModmFsdWVzLCB7IGV4YWN0OiBmYWxzZSwgYWxsb3daZXJvOiBmYWxzZSB9KSBhcyBPcmRPdXRwdXRbXTtcbiAgfVxufVxuIl19