UNPKG

@bitgo-beta/utxo-ord

Version:

Utilities for building ordinals with BitGo utxo-lib

254 lines (238 loc) 29.1 kB
"use strict"; /* This file contains code for creating an output layouts for transactions that pass on inscriptions. When passing on an inscription, we want to satisfy a few constraints: * All outputs should be larger than a minimal value (dust limit) * The sum of all output values needs to be less than the input to cover the transaction fee. * The output containing the inscription should be as small as possible, but large enough to contain the inscription. To keep the inscription output small, we can pad the satoshi range preceding and following the range with change outputs, which have a minimal size and incur a fee cost. Broadly speaking, there are four scenarios: (1) Small inscription input that has just enough value to pay for fee and a single inscription output (u0). No padding outputs. ┌────────┬────────┐ │ │ u0 │ │ r ┼ │ │ ├────────┘ │ │ fee └────────┘ (2) Large inscription input with inscription close to start of input. Inscription output followed by change output (u1) padding the remaining value. ┌────────┬────────┐ │ │ u0 │ │ r ┼ │ │ ├────────┤ │ │ u1 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├────────┘ │ │ │ │ fee │ │ └────────┘ (3) Large inscription input with inscription close to end of input. Change output padding start followed by inscription output. (TODO) ┌────────┬────────┐ │ │ u0 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├────────┤ │ r ┼ │ │ │ u1 │ │ ├────────┘ │ │ │ │ fee │ │ └────────┘ (4) Large inscription input with inscription in the middle. Inscription input (u1) with padding on both sides (u0 and u2) (TODO) ┌────────┬────────┐ │ │ u0 │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├────────┤ │ │ u1 │ │ r ┼ │ │ ├────────┤ │ │ u2 │ │ │ │ │ │ │ │ │ │ │ ├────────┘ │ │ │ │ fee │ │ └────────┘ */ Object.defineProperty(exports, "__esModule", { value: true }); exports.findOutputLayout = exports.getOrdOutputsForLayout = exports.toParameters = exports.toArray = exports.Constraint = void 0; const SatRange_1 = require("./SatRange"); /** * A range constraint */ class Constraint { /** * @param minValue - inclusive * @param maxValue - inclusive */ constructor(minValue, maxValue) { this.minValue = minValue; this.maxValue = maxValue; if (minValue < 0 || maxValue < minValue) { throw new Error(`invalid constraint [${minValue}, ${maxValue}]`); } } /** @return true iff value satisfies constraint */ check(v) { return new SatRange_1.SatRange(this.minValue, this.maxValue).isSupersetOf(v); } } exports.Constraint = Constraint; Constraint.ZERO = new Constraint(BigInt(0), BigInt(0)); /** infinity for all practical purposes */ Constraint.MAXSAT = BigInt(21e14); /** @return canonical sequence of parameters */ function toArray(p) { return [p.firstChangeOutput, p.inscriptionOutput, p.secondChangeOutput, p.feeOutput]; } exports.toArray = toArray; function toParameters(firstChangeOutput, inscriptionOutput, secondChangeOutput, feeOutput) { return { firstChangeOutput, inscriptionOutput, secondChangeOutput, feeOutput, }; } exports.toParameters = toParameters; /** * Translates a layout into OrdOutputs. Absent outputs are set to `null`. * * @param inscriptionInput * @param layout * @return OrdOutputs for layout */ function getOrdOutputsForLayout(inscriptionInput, layout) { const outputs = inscriptionInput.splitAllWithParams(toArray(layout), { exact: true, allowZero: true }); if (outputs.length !== 4) { throw new Error(`unexpected result`); } return toParameters(...outputs); } exports.getOrdOutputsForLayout = getOrdOutputsForLayout; /** * @param layout * @return output sum (including fee output) for layout. */ function getLayoutSum(layout) { return toArray(layout).reduce((a, b) => a + b, BigInt(0)); } /** * @param inscriptionInput * @param layout * @param constraints * @return true iff layout satisfies constraints */ function check(inscriptionInput, layout, constraints) { var _a; if (constraints.firstChangeOutput.check(layout.firstChangeOutput) && constraints.inscriptionOutput.check(layout.inscriptionOutput) && constraints.secondChangeOutput.check(layout.secondChangeOutput) && constraints.feeOutput.check(layout.feeOutput) && getLayoutSum(layout) === inscriptionInput.value) { /* make sure inscription actually lies on the inscriptionOutput */ const outputs = getOrdOutputsForLayout(inscriptionInput, layout); return ((_a = outputs.inscriptionOutput) === null || _a === void 0 ? void 0 : _a.ordinals.length) === 1; } return false; } /** * Solves the constraints defined in _p_ to produce a layout by expanding a parameter. * Currently only works with one expandable parameter. * @param total - the total input sum * @param p - the constraint parameters. * @return OutputLayout */ function toOutputLayout(total, p) { const fixed = Object.values(p).filter((v) => v.minValue === v.maxValue); const expandable = Object.values(p).filter((v) => v.minValue !== v.maxValue); if (expandable.length === 0) { return Object.fromEntries(Object.entries(p).map(([k, v]) => [k, v.minValue])); } if (expandable.length === 1) { const sumFixed = fixed.reduce((sum, e) => sum + e.minValue, BigInt(0)); const remainder = total - sumFixed; if (remainder < 0) { return; } for (const k in p) { if (p[k] === expandable[0]) { return toOutputLayout(total, { ...p, [k]: new Constraint(remainder, remainder) }); } } throw new Error(`illegal state`); } throw new Error(`cannot expand more than one constraint`); } /** * @param inscriptionInput * @param minChangeOutput * @param maxChangeOutput * @param minInscriptionOutput * @param maxInscriptionOutput * @param feeFixed * @param feePerOutput * @return a solution that satisfies constraints. If no solution can be found, return `undefined`. */ function findOutputLayout(inscriptionInput, { minChangeOutput, maxChangeOutput, minInscriptionOutput, maxInscriptionOutput, feeFixed, feePerOutput }) { if (inscriptionInput.ordinals.length !== 1) { throw new Error(`unexpected ordinal count`); } if (inscriptionInput.ordinals[0].size() !== BigInt(1)) { throw new Error(`only single-satoshi inscriptions are supported`); } function feeConstraintForOutputCount(n) { const fee = feeFixed + feePerOutput * BigInt(n); return new Constraint(fee, fee); } const fixedZero = Constraint.ZERO; const expandableChangePadding = new Constraint(minChangeOutput, maxChangeOutput); const expandableInscriptionConstraint = new Constraint(minInscriptionOutput, maxInscriptionOutput); const fixedMinInscriptionConstraint = new Constraint(minInscriptionOutput, minInscriptionOutput); const fixedMaxInscriptionConstraint = new Constraint(maxInscriptionOutput, maxInscriptionOutput); const candidates = [ toParameters(fixedZero, expandableInscriptionConstraint, fixedZero, feeConstraintForOutputCount(1)), toParameters(fixedZero, fixedMinInscriptionConstraint, expandableChangePadding, feeConstraintForOutputCount(2)), toParameters(fixedZero, fixedMaxInscriptionConstraint, expandableChangePadding, feeConstraintForOutputCount(2)), /* TODO(BG-68135): search solution space with change padding at the start */ ]; for (const candidate of candidates) { const result = toOutputLayout(inscriptionInput.value, candidate); if (!result) { continue; } if (check(inscriptionInput, result, candidate)) { return result; } } } exports.findOutputLayout = findOutputLayout; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT3V0cHV0TGF5b3V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL091dHB1dExheW91dC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0dHOzs7QUFHSCx5Q0FBc0M7QUFFdEM7O0dBRUc7QUFDSCxNQUFhLFVBQVU7SUFDckI7OztPQUdHO0lBQ0gsWUFBbUIsUUFBZ0IsRUFBUyxRQUFnQjtRQUF6QyxhQUFRLEdBQVIsUUFBUSxDQUFRO1FBQVMsYUFBUSxHQUFSLFFBQVEsQ0FBUTtRQUMxRCxJQUFJLFFBQVEsR0FBRyxDQUFDLElBQUksUUFBUSxHQUFHLFFBQVEsRUFBRTtZQUN2QyxNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixRQUFRLEtBQUssUUFBUSxHQUFHLENBQUMsQ0FBQztTQUNsRTtJQUNILENBQUM7SUFFRCxrREFBa0Q7SUFDbEQsS0FBSyxDQUFDLENBQVM7UUFDYixPQUFPLElBQUksbUJBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEUsQ0FBQzs7QUFkSCxnQ0FtQkM7QUFIUSxlQUFJLEdBQUcsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ25ELDBDQUEwQztBQUNuQyxpQkFBTSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQWNoQywrQ0FBK0M7QUFDL0MsU0FBZ0IsT0FBTyxDQUFJLENBQWdCO0lBQ3pDLE9BQU8sQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLGlCQUFpQixFQUFFLENBQUMsQ0FBQyxrQkFBa0Is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QUNqRSxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ1gsU0FBUztTQUNWO1FBQ0QsSUFBSSxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxFQUFFO1lBQzlDLE9BQU8sTUFBTSxDQUFDO1NBQ2Y7S0FDRjtBQUNILENBQUM7QUFyQ0QsNENBcUNDIiwic291cmNlc0NvbnRlbnQiOlsiLypcblxuVGhpcyBmaWxlIGNvbnRhaW5zIGNvZGUgZm9yIGNyZWF0aW5nIGFuIG91dHB1dCBsYXlvdXRzIGZvciB0cmFuc2FjdGlvbnMgdGhhdCBwYXNzIG9uIGluc2NyaXB0aW9ucy5cblxuV2hlbiBwYXNzaW5nIG9uIGFuIGluc2NyaXB0aW9uLCB3ZSB3YW50IHRvIHNhdGlzZnkgYSBmZXcgY29uc3RyYWludHM6XG5cbiogQWxsIG91dHB1dHMgc2hvdWxkIGJlIGxhcmdlciB0aGFuIGEgbWluaW1hbCB2YWx1ZSAoZHVzdCBsaW1pdClcbiogVGhlIHN1bSBvZiBhbGwgb3V0cHV0IHZhbHVlcyBuZWVkcyB0byBiZSBsZXNzIHRoYW4gdGhlIGlucHV0IHRvIGNvdmVyIHRoZSB0cmFuc2FjdGlvbiBmZWUuXG4qIFRoZSBvdXRwdXQgY29udGFpbmluZyB0aGUgaW5zY3JpcHRpb24gc2hvdWxkIGJlIGFzIHNtYWxsIGFzIHBvc3NpYmxlLCBidXQgbGFyZ2UgZW5vdWdoIHRvXG4gIGNvbnRhaW4gdGhlIGluc2NyaXB0aW9uLlxuXG5UbyBrZWVwIHRoZSBpbnNjcmlwdGlvbiBvdXRwdXQgc21hbGwsIHdlIGNhbiBwYWQgdGhlIHNhdG9zaGkgcmFuZ2UgcHJlY2VkaW5nIGFuZCBmb2xsb3dpbmcgdGhlIHJhbmdlXG53aXRoIGNoYW5nZSBvdXRwdXRzLCB3aGljaCBoYXZlIGEgbWluaW1hbCBzaXplIGFuZCBpbmN1ciBhIGZlZSBjb3N0LlxuXG5cbkJyb2FkbHkgc3BlYWtpbmcsIHRoZXJlIGFyZSBmb3VyIHNjZW5hcmlvczpcblxuKDEpIFNtYWxsIGluc2NyaXB0aW9uIGlucHV0IHRoYXQgaGFzIGp1c3QgZW5vdWdoIHZhbHVlIHRvIHBheSBmb3IgZmVlIGFuZCBhIHNpbmdsZSBpbnNjcmlwdGlvblxuICAgIG91dHB1dCAodTApLiBObyBwYWRkaW5nIG91dHB1dHMuXG4gICAg4pSM4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSs4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSQXG4gICAg4pSCICAgICAgICDilIIgdTAgICAgIOKUglxuICAgIOKUgiAgICAgIHIg4pS8ICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUnOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmFxuICAgIOKUgiAgICAgICAg4pSCIGZlZVxuICAgIOKUlOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmFxuXG5cbigyKSBMYXJnZSBpbnNjcmlwdGlvbiBpbnB1dCB3aXRoIGluc2NyaXB0aW9uIGNsb3NlIHRvIHN0YXJ0IG9mIGlucHV0LlxuICAgIEluc2NyaXB0aW9uIG91dHB1dCBmb2xsb3dlZCBieSBjaGFuZ2Ugb3V0cHV0ICh1MSkgcGFkZGluZyB0aGUgcmVtYWluaW5nIHZhbHVlLlxuXG4gICAg4pSM4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSs4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSQXG4gICAg4pSCICAgICAgICDilIIgdTAgICAgIOKUglxuICAgIOKUgiAgICAgIHIg4pS8ICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUnOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUpFxuICAgIOKUgiAgICAgICAg4pSCIHUxICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUnOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmFxuICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgZmVlXG4gICAg4pSCICAgICAgICDilIJcbiAgICDilJTilIDilIDilIDilIDilIDilIDilIDilIDilJhcblxuXG4oMykgTGFyZ2UgaW5zY3JpcHRpb24gaW5wdXQgd2l0aCBpbnNjcmlwdGlvbiBjbG9zZSB0byBlbmQgb2YgaW5wdXQuXG4gICAgQ2hhbmdlIG91dHB1dCBwYWRkaW5nIHN0YXJ0IGZvbGxvd2VkIGJ5IGluc2NyaXB0aW9uIG91dHB1dC5cbiAgICAoVE9ETylcblxuICAgIOKUjOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUrOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUkFxuICAgIOKUgiAgICAgICAg4pSCIHUwICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSc4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSkXG4gICAg4pSCICAgICAgciDilLwgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCIHUxICAgICDilIJcbiAgICDilIIgICAgICAgIOKUnOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmFxuICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgZmVlXG4gICAg4pSCICAgICAgICDilIJcbiAgICDilJTilIDilIDilIDilIDilIDilIDilIDilIDilJhcblxuXG4oNCkgTGFyZ2UgaW5zY3JpcHRpb24gaW5wdXQgd2l0aCBpbnNjcmlwdGlvbiBpbiB0aGUgbWlkZGxlLlxuICAgIEluc2NyaXB0aW9uIGlucHV0ICh1MSkgd2l0aCBwYWRkaW5nIG9uIGJvdGggc2lkZXMgKHUwIGFuZCB1MilcbiAgICAoVE9ETylcblxuICAgIOKUjOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUrOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUkFxuICAgIOKUgiAgICAgICAg4pSCIHUwICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilJzilIDilIDilIDilIDilIDilIDilIDilIDilKRcbiAgICDilIIgICAgICAgIOKUgiB1MSAgICAg4pSCXG4gICAg4pSCICAgICAgciDilLwgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSc4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSkXG4gICAg4pSCICAgICAgICDilIIgdTIgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiAgICAgICAg4pSCXG4gICAg4pSCICAgICAgICDilIIgICAgICAgIOKUglxuICAgIOKUgiAgICAgICAg4pSc4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSYXG4gICAg4pSCICAgICAgICDilIJcbiAgICDilIIgICAgICAgIOKUgiBmZWVcbiAgICDilIIgICAgICAgIOKUglxuICAgIOKUlOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmFxuICovXG5cbmltcG9ydCB7IE9yZE91dHB1dCB9IGZyb20gJy4vT3JkT3V0cHV0JztcbmltcG9ydCB7IFNhdFJhbmdlIH0gZnJvbSAnLi9TYXRSYW5nZSc7XG5cbi8qKlxuICogQSByYW5nZSBjb25zdHJhaW50XG4gKi9cbmV4cG9ydCBjbGFzcyBDb25zdHJhaW50IHtcbiAgLyoqXG4gICAqIEBwYXJhbSBtaW5WYWx1ZSAtIGluY2x1c2l2ZVxuICAgKiBAcGFyYW0gbWF4VmFsdWUgLSBpbmNsdXNpdmVcbiAgICovXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyBtaW5WYWx1ZTogYmlnaW50LCBwdWJsaWMgbWF4VmFsdWU6IGJpZ2ludCkge1xuICAgIGlmIChtaW5WYWx1ZSA8IDAgfHwgbWF4VmFsdWUgPCBtaW5WYWx1ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIGNvbnN0cmFpbnQgWyR7bWluVmFsdWV9LCAke21heFZhbHVlfV1gKTtcbiAgICB9XG4gIH1cblxuICAvKiogQHJldHVybiB0cnVlIGlmZiB2YWx1ZSBzYXRpc2ZpZXMgY29uc3RyYWludCAqL1xuICBjaGVjayh2OiBiaWdpbnQpOiBib29sZWFuIHtcbiAgICByZXR1cm4gbmV3IFNhdFJhbmdlKHRoaXMubWluVmFsdWUsIHRoaXMubWF4VmFsdWUpLmlzU3VwZXJzZXRPZih2KTtcbiAgfVxuXG4gIHN0YXRpYyBaRVJPID0gbmV3IENvbnN0cmFpbnQoQmlnSW50KDApLCBCaWdJbnQoMCkpO1xuICAvKiogaW5maW5pdHkgZm9yIGFsbCBwcmFjdGljYWwgcHVycG9zZXMgKi9cbiAgc3RhdGljIE1BWFNBVCA9IEJpZ0ludCgyMWUxNCk7XG59XG5cbnR5cGUgUGFyYW1ldGVyczxUPiA9IHtcbiAgLyoqIFBhZGRpbmcgcHJlY2VkaW5nIHRoZSBpbnNjcmlwdGlvbiBvdXRwdXQgKi9cbiAgZmlyc3RDaGFuZ2VPdXRwdXQ6IFQ7XG4gIC8qKiBUaGUgaW5zY3JpcHRpb24gb3V0cHV0IHRoYXQgd2lsbCBpbmhlcml0IHRoZSBpbnB1dCBpbnNjcmlwdGlvbiAqL1xuICBpbnNjcmlwdGlvbk91dHB1dDogVDtcbiAgLyoqIFBhZGRpbmcgZm9sbG93aW5nIHRoZSBpbnNjcmlwdGlvbiBvdXRwdXQgKi9cbiAgc2Vjb25kQ2hhbmdlT3V0cHV0OiBUO1xuICAvKiogTm90IGEgcmVhbCBvdXRwdXQsIHVzZWQgb25seSB0byBzaW1wbGlmeSBjYWxjdWxhdGlvbnMgKi9cbiAgZmVlT3V0cHV0OiBUO1xufTtcblxuLyoqIEByZXR1cm4gY2Fub25pY2FsIHNlcXVlbmNlIG9mIHBhcmFtZXRlcnMgKi9cbmV4cG9ydCBmdW5jdGlvbiB0b0FycmF5PFQ+KHA6IFBhcmFtZXRlcnM8VD4pOiBbVCwgVCwgVCwgVF0ge1xuICByZXR1cm4gW3AuZmlyc3RDaGFuZ2VPdXRwdXQsIHAuaW5zY3JpcHRpb25PdXRwdXQsIHAuc2Vjb25kQ2hhbmdlT3V0cHV0LCBwLmZlZU91dHB1dF07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0b1BhcmFtZXRlcnM8VD4oXG4gIGZpcnN0Q2hhbmdlT3V0cHV0OiBULFxuICBpbnNjcmlwdGlvbk91dHB1dDogVCxcbiAgc2Vjb25kQ2hhbmdlT3V0cHV0OiBULFxuICBmZWVPdXRwdXQ6IFRcbik6IFBhcmFtZXRlcnM8VD4ge1xuICByZXR1cm4ge1xuICAgIGZpcnN0Q2hhbmdlT3V0cHV0LFxuICAgIGluc2NyaXB0aW9uT3V0cHV0LFxuICAgIHNlY29uZENoYW5nZU91dHB1dCxcbiAgICBmZWVPdXRwdXQsXG4gIH07XG59XG5cbi8qKiBBIGZpbmlzaGVkIG91dHB1dCBsYXlvdXQgKi9cbmV4cG9ydCB0eXBlIE91dHB1dExheW91dCA9IFBhcmFtZXRlcnM8YmlnaW50PjtcblxuLyoqXG4gKiBUcmFuc2xhdGVzIGEgbGF5b3V0IGludG8gT3JkT3V0cHV0cy4gQWJzZW50IG91dHB1dHMgYXJlIHNldCB0byBgbnVsbGAuXG4gKlxuICogQHBhcmFtIGluc2NyaXB0aW9uSW5wdXRcbiAqIEBwYXJhbSBsYXlvdXRcbiAqIEByZXR1cm4gT3JkT3V0cHV0cyBmb3IgbGF5b3V0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPcmRPdXRwdXRzRm9yTGF5b3V0KFxuICBpbnNjcmlwdGlvbklucHV0OiBPcmRPdXRwdXQsXG4gIGxheW91dDogT3V0cHV0TGF5b3V0XG4pOiBQYXJhbWV0ZXJzPE9yZE91dHB1dCB8IG51bGw+IHtcbiAgY29uc3Qgb3V0cHV0cyA9IGluc2NyaXB0aW9uSW5wdXQuc3BsaXRBbGxXaXRoUGFyYW1zKHRvQXJyYXkobGF5b3V0KSwgeyBleGFjdDogdHJ1ZSwgYWxsb3daZXJvOiB0cnVlIH0pO1xuICBpZiAob3V0cHV0cy5sZW5ndGggIT09IDQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgcmVzdWx0YCk7XG4gIH1cbiAgdHlwZSBUID0gT3JkT3V0cHV0IHwgbnVsbDtcbiAgcmV0dXJuIHRvUGFyYW1ldGVycyguLi4ob3V0cHV0cyBhcyBbVCwgVCwgVCwgVF0pKTtcbn1cblxuLyoqXG4gKiBAcGFyYW0gbGF5b3V0XG4gKiBAcmV0dXJuIG91dHB1dCBzdW0gKGluY2x1ZGluZyBmZWUgb3V0cHV0KSBmb3IgbGF5b3V0LlxuICovXG5mdW5jdGlvbiBnZXRMYXlvdXRTdW0obGF5b3V0OiBPdXRwdXRMYXlvdXQpOiBiaWdpbnQge1xuICByZXR1cm4gdG9BcnJheShsYXlvdXQpLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIEJpZ0ludCgwKSk7XG59XG5cbi8qKlxuICogQHBhcmFtIGluc2NyaXB0aW9uSW5wdXRcbiAqIEBwYXJhbSBsYXlvdXRcbiAqIEBwYXJhbSBjb25zdHJhaW50c1xuICogQHJldHVybiB0cnVlIGlmZiBsYXlvdXQgc2F0aXNmaWVzIGNvbnN0cmFpbnRzXG4gKi9cbmZ1bmN0aW9uIGNoZWNrKGluc2NyaXB0aW9uSW5wdXQ6IE9yZE91dHB1dCwgbGF5b3V0OiBPdXRwdXRMYXlvdXQsIGNvbnN0cmFpbnRzOiBQYXJhbWV0ZXJzPENvbnN0cmFpbnQ+KTogYm9vbGVhbiB7XG4gIGlmIChcbiAgICBjb25zdHJhaW50cy5maXJzdENoYW5nZU91dHB1dC5jaGVjayhsYXlvdXQuZmlyc3RDaGFuZ2VPdXRwdXQpICYmXG4gICAgY29uc3RyYWludHMuaW5zY3JpcHRpb25PdXRwdXQuY2hlY2sobGF5b3V0Lmluc2NyaXB0aW9uT3V0cHV0KSAmJlxuICAgIGNvbnN0cmFpbnRzLnNlY29uZENoYW5nZU91dHB1dC5jaGVjayhsYXlvdXQuc2Vjb25kQ2hhbmdlT3V0cHV0KSAmJlxuICAgIGNvbnN0cmFpbnRzLmZlZU91dHB1dC5jaGVjayhsYXlvdXQuZmVlT3V0cHV0KSAmJlxuICAgIGdldExheW91dFN1bShsYXlvdXQpID09PSBpbnNjcmlwdGlvbklucHV0LnZhbHVlXG4gICkge1xuICAgIC8qIG1ha2Ugc3VyZSBpbnNjcmlwdGlvbiBhY3R1YWxseSBsaWVzIG9uIHRoZSBpbnNjcmlwdGlvbk91dHB1dCAqL1xuICAgIGNvbnN0IG91dHB1dHMgPSBnZXRPcmRPdXRwdXRzRm9yTGF5b3V0KGluc2NyaXB0aW9uSW5wdXQsIGxheW91dCk7XG4gICAgcmV0dXJuIG91dHB1dHMuaW5zY3JpcHRpb25PdXRwdXQ/Lm9yZGluYWxzLmxlbmd0aCA9PT0gMTtcbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBTb2x2ZXMgdGhlIGNvbnN0cmFpbnRzIGRlZmluZWQgaW4gX3BfIHRvIHByb2R1Y2UgYSBsYXlvdXQgYnkgZXhwYW5kaW5nIGEgcGFyYW1ldGVyLlxuICogQ3VycmVudGx5IG9ubHkgd29ya3Mgd2l0aCBvbmUgZXhwYW5kYWJsZSBwYXJhbWV0ZXIuXG4gKiBAcGFyYW0gdG90YWwgLSB0aGUgdG90YWwgaW5wdXQgc3VtXG4gKiBAcGFyYW0gcCAtIHRoZSBjb25zdHJhaW50IHBhcmFtZXRlcnMuXG4gKiBAcmV0dXJuIE91dHB1dExheW91dFxuICovXG5mdW5jdGlvbiB0b091dHB1dExheW91dCh0b3RhbDogYmlnaW50LCBwOiBQYXJhbWV0ZXJzPENvbnN0cmFpbnQ+KTogT3V0cHV0TGF5b3V0IHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZml4ZWQgPSBPYmplY3QudmFsdWVzKHApLmZpbHRlcigodikgPT4gdi5taW5WYWx1ZSA9PT0gdi5tYXhWYWx1ZSk7XG4gIGNvbnN0IGV4cGFuZGFibGUgPSBPYmplY3QudmFsdWVzKHApLmZpbHRlcigodikgPT4gdi5taW5WYWx1ZSAhPT0gdi5tYXhWYWx1ZSk7XG4gIGlmIChleHBhbmRhYmxlLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMocCkubWFwKChbaywgdl0pID0+IFtrLCB2Lm1pblZhbHVlXSkpIGFzIE91dHB1dExheW91dDtcbiAgfVxuXG4gIGlmIChleHBhbmRhYmxlLmxlbmd0aCA9PT0gMSkge1xuICAgIGNvbnN0IHN1bUZpeGVkID0gZml4ZWQucmVkdWNlKChzdW0sIGUpID0+IHN1bSArIGUubWluVmFsdWUsIEJpZ0ludCgwKSk7XG4gICAgY29uc3QgcmVtYWluZGVyID0gdG90YWwgLSBzdW1GaXhlZDtcbiAgICBpZiAocmVtYWluZGVyIDwgMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGsgaW4gcCkge1xuICAgICAgaWYgKHBbayBhcyBrZXlvZiBQYXJhbWV0ZXJzPHVua25vd24+XSA9PT0gZXhwYW5kYWJsZVswXSkge1xuICAgICAgICByZXR1cm4gdG9PdXRwdXRMYXlvdXQodG90YWwsIHsgLi4ucCwgW2tdOiBuZXcgQ29uc3RyYWludChyZW1haW5kZXIsIHJlbWFpbmRlcikgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgaWxsZWdhbCBzdGF0ZWApO1xuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKGBjYW5ub3QgZXhwYW5kIG1vcmUgdGhhbiBvbmUgY29uc3RyYWludGApO1xufVxuXG4vKipcbiAqIEhpZ2gtbGV2ZWwgY29uc3RyYWludHMgZm9yIG91dHB1dCBsYXlvdXRcbiAqL1xuZXhwb3J0IHR5cGUgU2VhcmNoUGFyYW1zID0ge1xuICBtaW5DaGFuZ2VPdXRwdXQ6IGJpZ2ludDtcbiAgbWF4Q2hhbmdlT3V0cHV0OiBiaWdpbnQ7XG4gIG1pbkluc2NyaXB0aW9uT3V0cHV0OiBiaWdpbnQ7XG4gIG1heEluc2NyaXB0aW9uT3V0cHV0OiBiaWdpbnQ7XG4gIGZlZUZpeGVkOiBiaWdpbnQ7XG4gIGZlZVBlck91dHB1dDogYmlnaW50O1xufTtcblxuLyoqXG4gKiBAcGFyYW0gaW5zY3JpcHRpb25JbnB1dFxuICogQHBhcmFtIG1pbkNoYW5nZU91dHB1dFxuICogQHBhcmFtIG1heENoYW5nZU91dHB1dFxuICogQHBhcmFtIG1pbkluc2NyaXB0aW9uT3V0cHV0XG4gKiBAcGFyYW0gbWF4SW5zY3JpcHRpb25PdXRwdXRcbiAqIEBwYXJhbSBmZWVGaXhlZFxuICogQHBhcmFtIGZlZVBlck91dHB1dFxuICogQHJldHVybiBhIHNvbHV0aW9uIHRoYXQgc2F0aXNmaWVzIGNvbnN0cmFpbnRzLiBJZiBubyBzb2x1dGlvbiBjYW4gYmUgZm91bmQsIHJldHVybiBgdW5kZWZpbmVkYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRPdXRwdXRMYXlvdXQoXG4gIGluc2NyaXB0aW9uSW5wdXQ6IE9yZE91dHB1dCxcbiAgeyBtaW5DaGFuZ2VPdXRwdXQsIG1heENoYW5nZU91dHB1dCwgbWluSW5zY3JpcHRpb25PdXRwdXQsIG1heEluc2NyaXB0aW9uT3V0cHV0LCBmZWVGaXhlZCwgZmVlUGVyT3V0cHV0IH06IFNlYXJjaFBhcmFtc1xuKTogT3V0cHV0TGF5b3V0IHwgdW5kZWZpbmVkIHtcbiAgaWYgKGluc2NyaXB0aW9uSW5wdXQub3JkaW5hbHMubGVuZ3RoICE9PSAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGB1bmV4cGVjdGVkIG9yZGluYWwgY291bnRgKTtcbiAgfVxuICBpZiAoaW5zY3JpcHRpb25JbnB1dC5vcmRpbmFsc1swXS5zaXplKCkgIT09IEJpZ0ludCgxKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgb25seSBzaW5nbGUtc2F0b3NoaSBpbnNjcmlwdGlvbnMgYXJlIHN1cHBvcnRlZGApO1xuICB9XG4gIGZ1bmN0aW9uIGZlZUNvbnN0cmFpbnRGb3JPdXRwdXRDb3VudChuOiBudW1iZXIpIHtcbiAgICBjb25zdCBmZWUgPSBmZWVGaXhlZCArIGZlZVBlck91dHB1dCAqIEJpZ0ludChuKTtcbiAgICByZXR1cm4gbmV3IENvbnN0cmFpbnQoZmVlLCBmZWUpO1xuICB9XG5cbiAgY29uc3QgZml4ZWRaZXJvID0gQ29uc3RyYWludC5aRVJPO1xuICBjb25zdCBleHBhbmRhYmxlQ2hhbmdlUGFkZGluZyA9IG5ldyBDb25zdHJhaW50KG1pbkNoYW5nZU91dHB1dCwgbWF4Q2hhbmdlT3V0cHV0KTtcbiAgY29uc3QgZXhwYW5kYWJsZUluc2NyaXB0aW9uQ29uc3RyYWludCA9IG5ldyBDb25zdHJhaW50KG1pbkluc2NyaXB0aW9uT3V0cHV0LCBtYXhJbnNjcmlwdGlvbk91dHB1dCk7XG4gIGNvbnN0IGZpeGVkTWluSW5zY3JpcHRpb25Db25zdHJhaW50ID0gbmV3IENvbnN0cmFpbnQobWluSW5zY3JpcHRpb25PdXRwdXQsIG1pbkluc2NyaXB0aW9uT3V0cHV0KTtcbiAgY29uc3QgZml4ZWRNYXhJbnNjcmlwdGlvbkNvbnN0cmFpbnQgPSBuZXcgQ29uc3RyYWludChtYXhJbnNjcmlwdGlvbk91dHB1dCwgbWF4SW5zY3JpcHRpb25PdXRwdXQpO1xuXG4gIGNvbnN0IGNhbmRpZGF0ZXMgPSBbXG4gICAgdG9QYXJhbWV0ZXJzKGZpeGVkWmVybywgZXhwYW5kYWJsZUluc2NyaXB0aW9uQ29uc3RyYWludCwgZml4ZWRaZXJvLCBmZWVDb25zdHJhaW50Rm9yT3V0cHV0Q291bnQoMSkpLFxuICAgIHRvUGFyYW1ldGVycyhmaXhlZFplcm8sIGZpeGVkTWluSW5zY3JpcHRpb25Db25zdHJhaW50LCBleHBhbmRhYmxlQ2hhbmdlUGFkZGluZywgZmVlQ29uc3RyYWludEZvck91dHB1dENvdW50KDIpKSxcbiAgICB0b1BhcmFtZXRlcnMoZml4ZWRaZXJvLCBmaXhlZE1heEluc2NyaXB0aW9uQ29uc3RyYWludCwgZXhwYW5kYWJsZUNoYW5nZVBhZGRpbmcsIGZlZUNvbnN0cmFpbnRGb3JPdXRwdXRDb3VudCgyKSksXG4gICAgLyogVE9ETyhCRy02ODEzNSk6IHNlYXJjaCBzb2x1dGlvbiBzcGFjZSB3aXRoIGNoYW5nZSBwYWRkaW5nIGF0IHRoZSBzdGFydCAqL1xuICBdO1xuXG4gIGZvciAoY29uc3QgY2FuZGlkYXRlIG9mIGNhbmRpZGF0ZXMpIHtcbiAgICBjb25zdCByZXN1bHQgPSB0b091dHB1dExheW91dChpbnNjcmlwdGlvbklucHV0LnZhbHVlLCBjYW5kaWRhdGUpO1xuICAgIGlmICghcmVzdWx0KSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKGNoZWNrKGluc2NyaXB0aW9uSW5wdXQsIHJlc3VsdCwgY2FuZGlkYXRlKSkge1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gIH1cbn1cbiJdfQ==