PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/@bitgo/utxo-lib/dist/src

Просмотр файла: taproot.js

"use strict";
// Taproot-specific key aggregation and taptree logic as defined in:
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
Object.defineProperty(exports, "__esModule", { value: true });
exports.INITIAL_TAPSCRIPT_VERSION = exports.EVEN_Y_COORD_PREFIX = void 0;
exports.aggregateMuSigPubkeys = aggregateMuSigPubkeys;
exports.serializeScriptSize = serializeScriptSize;
exports.hashTapLeaf = hashTapLeaf;
exports.hashTapBranch = hashTapBranch;
exports.calculateTapTweak = calculateTapTweak;
exports.tapTweakPrivkey = tapTweakPrivkey;
exports.tapTweakPubkey = tapTweakPubkey;
exports.getDepthFirstTaptree = getDepthFirstTaptree;
exports.getHuffmanTaptree = getHuffmanTaptree;
exports.getControlBlock = getControlBlock;
exports.parseTaprootWitness = parseTaprootWitness;
exports.parseControlBlock = parseControlBlock;
exports.getTapleafHash = getTapleafHash;
exports.getTaptreeRoot = getTaptreeRoot;
exports.getTweakedOutputKey = getTweakedOutputKey;
exports.createTaprootOutputScript = createTaprootOutputScript;
exports.getTaprootOutputKey = getTaprootOutputKey;
const assert = require("assert");
const FastPriorityQueue = require("fastpriorityqueue");
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
const noble_ecc_1 = require("./noble_ecc");
const varuint = require('varuint-bitcoin');
/**
 * The 0x02 prefix indicating an even Y coordinate which is implicitly assumed
 * on all 32 byte x-only pub keys as defined in BIP340.
 */
exports.EVEN_Y_COORD_PREFIX = Buffer.of(0x02);
exports.INITIAL_TAPSCRIPT_VERSION = 0xc0;
/**
 * Aggregates a list of public keys into a single MuSig2* public key
 * according to the MuSig2 paper.
 * @param ecc Elliptic curve implementation
 * @param pubkeys The list of pub keys to aggregate
 * @returns a 32 byte Buffer representing the aggregate key
 */
function aggregateMuSigPubkeys(ecc, pubkeys) {
    // TODO: Consider enforcing key uniqueness.
    assert(pubkeys.length > 1, 'at least two pubkeys are required for musig key aggregation');
    // Sort the keys in ascending order
    pubkeys.sort(Buffer.compare);
    // In MuSig all signers contribute key material to a single signing key,
    // using the equation
    //
    //     P = sum_i µ_i * P_i
    //
    // where `P_i` is the public key of the `i`th signer and `µ_i` is a so-called
    // _MuSig coefficient_ computed according to the following equation
    //
    // L = H(P_1 || P_2 || ... || P_n)
    // µ_i = H(L || P_i)
    const L = bitcoinjs_lib_1.crypto.taggedHash('KeyAgg list', Buffer.concat(pubkeys));
    const secondUniquePubkey = pubkeys.find((pubkey) => !pubkeys[0].equals(pubkey));
    const tweakedPubkeys = pubkeys.map((pubkey) => {
        const xyPubkey = Buffer.concat([exports.EVEN_Y_COORD_PREFIX, pubkey]);
        if (secondUniquePubkey !== undefined && secondUniquePubkey.equals(pubkey)) {
            // The second unique key in the pubkey list given to ''KeyAgg'' (as well
            // as any keys identical to this key) gets the constant KeyAgg
            // coefficient 1 which saves an exponentiation (see the MuSig2* appendix
            // in the MuSig2 paper).
            return xyPubkey;
        }
        const c = bitcoinjs_lib_1.crypto.taggedHash('KeyAgg coefficient', Buffer.concat([L, pubkey]));
        const tweakedPubkey = ecc.pointMultiply(xyPubkey, c);
        if (!tweakedPubkey) {
            throw new Error('Failed to multiply pubkey by coefficient');
        }
        return tweakedPubkey;
    });
    const aggregatePubkey = tweakedPubkeys.reduce((prev, curr) => {
        const next = ecc.pointAdd(prev, curr);
        if (!next)
            throw new Error('Failed to sum pubkeys');
        return next;
    });
    return aggregatePubkey.slice(1);
}
/**
 * Encodes the length of a script as a bitcoin variable length integer.
 * @param script
 * @returns
 */
function serializeScriptSize(script) {
    return varuint.encode(script.length);
}
/**
 * Gets a tapleaf tagged hash from a script.
 * @param script
 * @returns
 */
function hashTapLeaf(script, leafVersion = exports.INITIAL_TAPSCRIPT_VERSION) {
    const size = serializeScriptSize(script);
    return bitcoinjs_lib_1.crypto.taggedHash('TapLeaf', Buffer.concat([Buffer.of(leafVersion), size, script]));
}
/**
 * Creates a lexicographically sorted tapbranch from two child taptree nodes
 * and returns its tagged hash.
 * @param child1
 * @param child2
 * @returns the tagged tapbranch hash
 */
function hashTapBranch(child1, child2) {
    // sort the children lexicographically
    const sortedChildren = [child1, child2].sort(Buffer.compare);
    return bitcoinjs_lib_1.crypto.taggedHash('TapBranch', Buffer.concat(sortedChildren));
}
function calculateTapTweak(pubkey, taptreeRoot) {
    if (pubkey.length !== 32) {
        throw new Error(`Invalid pubkey size ${pubkey.length}.`);
    }
    if (taptreeRoot) {
        if (taptreeRoot.length !== 32) {
            throw new Error(`Invalid taptreeRoot size ${taptreeRoot.length}.`);
        }
        return bitcoinjs_lib_1.crypto.taggedHash('TapTweak', Buffer.concat([pubkey, taptreeRoot]));
    }
    // If the spending conditions do not require a script path, the output key should commit to an
    // unspendable script path instead of having no script path.
    // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-22
    return bitcoinjs_lib_1.crypto.taggedHash('TapTweak', Buffer.from(pubkey));
}
/**
 * Tweaks a privkey, using the tagged hash of its pubkey, and (optionally) a taptree root
 * @param ecc Elliptic curve implementation
 * @param pubkey public key, used to calculate the tweak
 * @param privkey the privkey to tweak
 * @param taptreeRoot the taptree root tagged hash
 * @returns {Buffer} the tweaked privkey
 */
function tapTweakPrivkey(ecc, pubkey, privkey, taptreeRoot) {
    const tapTweak = calculateTapTweak(pubkey, taptreeRoot);
    const point = ecc.pointFromScalar(privkey);
    if (!point)
        throw new Error('Invalid private key');
    if (point[0] % 2 === 1)
        privkey = ecc.privateNegate(privkey);
    const result = ecc.privateAdd(privkey, tapTweak);
    if (!result)
        throw new Error('Invalid private key');
    return result;
}
/**
 * Tweaks an internal pubkey, using the tagged hash of itself, and (optionally) a taptree root
 * @param ecc Elliptic curve implementation
 * @param pubkey the internal pubkey to tweak
 * @param taptreeRoot the taptree root tagged hash
 * @returns {TweakedPubkey} the tweaked pubkey
 */
function tapTweakPubkey(ecc, pubkey, taptreeRoot) {
    const tapTweak = calculateTapTweak(pubkey, taptreeRoot);
    const result = ecc.xOnlyPointAddTweak(pubkey, tapTweak);
    if (!result)
        throw new Error('Invalid pubkey');
    return result;
}
function recurseTaptree(leaves, targetDepth = 0) {
    const { value, done } = leaves.next();
    assert(!done, 'insufficient leaves to reconstruct tap tree');
    const [index, leaf] = value;
    const tree = {
        root: hashTapLeaf(leaf.script, leaf.leafVersion),
        paths: [],
    };
    tree.paths[index] = [];
    for (let depth = leaf.depth; depth > targetDepth; depth--) {
        const sibling = recurseTaptree(leaves, depth);
        tree.paths.forEach((path) => path.push(sibling.root));
        sibling.paths.forEach((path) => path.push(tree.root));
        tree.root = hashTapBranch(tree.root, sibling.root);
        // Merge disjoint sparse arrays of paths into tree.paths
        Object.assign(tree.paths, sibling.paths);
    }
    return tree;
}
/**
 * Gets the root hash and hash-paths of a taptree from the depth-first
 * construction used in BIP-0371 PSBTs
 * @param tree
 * @returns {Taptree} the tree, represented by its root hash, and the paths to
 * that root from each of the input scripts
 */
function getDepthFirstTaptree(tree) {
    const iter = tree.leaves.entries();
    const ret = recurseTaptree(iter);
    assert(iter.next().done, 'invalid tap tree, no path to some leaves');
    return ret;
}
/**
 * Gets the root hash of a taptree using a weighted Huffman construction from a
 * list of scripts and corresponding weights.
 * @param scripts
 * @param weights
 * @returns {Taptree} the tree, represented by its root hash, and the paths to that root from each of the input scripts
 */
function getHuffmanTaptree(scripts, weights) {
    assert(scripts.length > 0, 'at least one script is required to construct a tap tree');
    // Create a queue/heap of the provided scripts prioritized according to their
    // corresponding weights.
    const queue = new FastPriorityQueue((a, b) => {
        return a.weight < b.weight;
    });
    scripts.forEach((script, index) => {
        const weight = weights[index] || 1;
        assert(weight > 0, 'script weight must be a positive value');
        queue.add({
            weight,
            taggedHash: hashTapLeaf(script),
            paths: { [index]: [] },
        });
    });
    // Now that we have a queue of weighted scripts, we begin a loop whereby we
    // remove the two lowest weighted items from the queue. We create a tap branch
    // node from the two items, and add the branch back to the queue with the
    // combined weight of both its children. Each loop reduces the number of items
    // in the queue by one, and we repeat until we are left with only one item -
    // this becomes the tap tree root.
    //
    // For example, if we begin with scripts A, B, C, D with weights 6, 3, 1, 1
    // After first loop: A(6), B(3), CD(1 + 1)
    // After second loop: A(6), B[CD](3 + 2)
    // Final loop: A[B[CD]](6+5)
    // The final tree will look like:
    //
    //        A[B[CD]]
    //       /        \
    //      A         B[CD]
    //               /     \
    //              B      [CD]
    //                    /    \
    //                   C      D
    //
    // This ensures that the spending conditions we believe to have the highest
    // probability of being used are further up the tree than less likely scripts,
    // thereby reducing the size of the merkle proofs for the more likely scripts.
    while (queue.size > 1) {
        // We can safely expect two polls to return non-null elements since we've
        // checked that the queue has at least two elements before looping.
        const child1 = queue.poll();
        const child2 = queue.poll();
        Object.values(child1.paths).forEach((path) => path.push(child2.taggedHash));
        Object.values(child2.paths).forEach((path) => path.push(child1.taggedHash));
        queue.add({
            taggedHash: hashTapBranch(child1.taggedHash, child2.taggedHash),
            weight: child1.weight + child2.weight,
            paths: { ...child1.paths, ...child2.paths },
        });
    }
    // After the while loop above completes we should have exactly one element
    // remaining in the queue, which we can safely extract below.
    const rootNode = queue.poll();
    const paths = Object.entries(rootNode.paths).reduce((acc, [index, path]) => {
        acc[Number(index)] = path; // TODO: Why doesn't TS know it's a number?
        return acc;
    }, Array(scripts.length));
    return { root: rootNode.taggedHash, paths };
}
function getControlBlock(parity, pubkey, path, leafVersion = exports.INITIAL_TAPSCRIPT_VERSION) {
    const parityVersion = leafVersion + parity;
    return Buffer.concat([Buffer.of(parityVersion), pubkey, ...path]);
}
/**
 * Parses a taproot witness stack and extracts key data elements.
 * @param witnessStack
 * @returns {ScriptPathWitness|KeyPathWitness} an object representing the
 * parsed witness for a script path or key path spend.
 * @throws {Error} if the witness stack does not conform to the BIP 341 script validation rules
 */
function parseTaprootWitness(witnessStack) {
    let annex;
    if (witnessStack.length >= 2 && witnessStack[witnessStack.length - 1][0] === 0x50) {
        // If there are at least two witness elements, and the first byte of the last element is
        // 0x50, this last element is called annex a and is removed from the witness stack
        annex = witnessStack[witnessStack.length - 1];
        witnessStack = witnessStack.slice(0, -1);
    }
    if (witnessStack.length < 1) {
        throw new Error('witness stack must have at least one element');
    }
    else if (witnessStack.length === 1) {
        // key path spend
        const signature = witnessStack[0];
        if (!bitcoinjs_lib_1.script.isCanonicalSchnorrSignature(signature)) {
            throw new Error('invalid signature');
        }
        return { spendType: 'Key', signature, annex };
    }
    // script path spend
    // second to last element is the tapscript
    const tapscript = witnessStack[witnessStack.length - 2];
    const tapscriptChunks = bitcoinjs_lib_1.script.decompile(tapscript);
    if (!tapscriptChunks || tapscriptChunks.length === 0) {
        throw new Error('tapscript is not a valid script');
    }
    // The last stack element is called the control block c, and must have length 33 + 32m,
    // for a value of m that is an integer between 0 and 128, inclusive
    const controlBlock = witnessStack[witnessStack.length - 1];
    if (controlBlock.length < 33 || controlBlock.length > 33 + 32 * 128 || controlBlock.length % 32 !== 1) {
        throw new Error('invalid control block length');
    }
    return {
        spendType: 'Script',
        scriptSig: witnessStack.slice(0, -2),
        tapscript,
        controlBlock,
        annex,
    };
}
/**
 * Parses a taproot control block.
 * @param ecc Elliptic curve implementation
 * @param controlBlock the control block to parse
 * @returns {ControlBlock} the parsed control block
 * @throws {Error} if the witness stack does not conform to the BIP 341 script validation rules
 */
function parseControlBlock(ecc, controlBlock) {
    if ((controlBlock.length - 1) % 32 !== 0) {
        throw new TypeError('Invalid control block length');
    }
    const parity = controlBlock[0] & 0x01;
    // Let p = c[1:33] and let P = lift_x(int(p)) where lift_x and [:] are defined as in BIP340.
    // Fail if this point is not on the curve
    const internalPubkey = controlBlock.slice(1, 33);
    if (!ecc.isXOnlyPoint(internalPubkey)) {
        throw new Error('internal pubkey is not an EC point');
    }
    // The leaf version cannot be 0x50 as that would result in ambiguity with the annex.
    const leafVersion = controlBlock[0] & 0xfe;
    if (leafVersion === 0x50) {
        throw new Error('invalid leaf version');
    }
    const path = [];
    for (let j = 33; j < controlBlock.length; j += 32) {
        path.push(controlBlock.slice(j, j + 32));
    }
    return {
        parity,
        internalPubkey,
        leafVersion,
        path,
    };
}
/**
 * Calculates the tapleaf hash from a control block and script.
 * @param ecc Elliptic curve implementation
 * @param controlBlock the control block, either raw or parsed
 * @param tapscript the leaf script corresdponding to the control block
 * @returns {Buffer} the tapleaf hash
 */
function getTapleafHash(ecc, controlBlock, tapscript) {
    if (Buffer.isBuffer(controlBlock)) {
        controlBlock = parseControlBlock(ecc, controlBlock);
    }
    const { leafVersion } = controlBlock;
    return bitcoinjs_lib_1.crypto.taggedHash('TapLeaf', Buffer.concat([Buffer.of(leafVersion), serializeScriptSize(tapscript), tapscript]));
}
/**
 * Calculates the taptree root hash from a control block and script.
 * @param ecc Elliptic curve implementation
 * @param controlBlock the control block, either raw or parsed
 * @param tapscript the leaf script corresdponding to the control block
 * @param tapleafHash the leaf hash if already calculated
 * @returns {Buffer} the taptree root hash
 */
function getTaptreeRoot(ecc, controlBlock, tapscript, tapleafHash) {
    if (Buffer.isBuffer(controlBlock)) {
        controlBlock = parseControlBlock(ecc, controlBlock);
    }
    const { path } = controlBlock;
    tapleafHash = tapleafHash || getTapleafHash(ecc, controlBlock, tapscript);
    // `taptreeMerkleHash` begins as our tapscript tapleaf hash and its value iterates
    // through its parent tapbranch hashes until it ends up as the taptree root hash
    let taptreeMerkleHash = tapleafHash;
    for (const taptreeSiblingHash of path) {
        taptreeMerkleHash =
            Buffer.compare(taptreeMerkleHash, taptreeSiblingHash) === -1
                ? bitcoinjs_lib_1.crypto.taggedHash('TapBranch', Buffer.concat([taptreeMerkleHash, taptreeSiblingHash]))
                : bitcoinjs_lib_1.crypto.taggedHash('TapBranch', Buffer.concat([taptreeSiblingHash, taptreeMerkleHash]));
    }
    return taptreeMerkleHash;
}
function getTweakedOutputKey(payment) {
    assert(payment.output);
    if (payment.output.length === 34) {
        return payment.output?.subarray(2);
    }
    throw new Error(`invalid p2tr tweaked output key size ${payment.output.length}`);
}
/**
 * @returns output script for either script path input controlBlock
 * & leafScript OR key path input internalPubKey & taptreeRoot
 */
function createTaprootOutputScript(p2trArgs) {
    let internalPubKey;
    let taptreeRoot;
    if ('internalPubKey' in p2trArgs) {
        internalPubKey = p2trArgs.internalPubKey;
        taptreeRoot = p2trArgs.taptreeRoot;
    }
    else {
        internalPubKey = parseControlBlock(noble_ecc_1.ecc, p2trArgs.controlBlock).internalPubkey;
        taptreeRoot = getTaptreeRoot(noble_ecc_1.ecc, p2trArgs.controlBlock, p2trArgs.leafScript);
    }
    const outputKey = tapTweakPubkey(noble_ecc_1.ecc, internalPubKey, taptreeRoot).xOnlyPubkey;
    return bitcoinjs_lib_1.script.compile([bitcoinjs_lib_1.script.OPS.OP_1, Buffer.from(outputKey)]);
}
/**
 * @returns x-only taproot output key (tapOutputKey)
 */
function getTaprootOutputKey(outputScript) {
    const outputDecompiled = bitcoinjs_lib_1.script.decompile(outputScript);
    if (outputDecompiled?.length !== 2) {
        throw new Error('invalid taproot output script');
    }
    const [op1, outputKey] = outputDecompiled;
    if (op1 !== bitcoinjs_lib_1.script.OPS.OP_1 || !Buffer.isBuffer(outputKey) || outputKey.length !== 32) {
        throw new Error('invalid taproot output script');
    }
    return outputKey;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwcm9vdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90YXByb290LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxvRUFBb0U7QUFDcEUsaUVBQWlFO0FBQ2pFLGlFQUFpRTs7O0FBaUNqRSxzREFnREM7QUFPRCxrREFFQztBQU9ELGtDQUdDO0FBU0Qsc0NBS0M7QUFFRCw4Q0FjQztBQVVELDBDQWNDO0FBY0Qsd0NBU0M7QUEyQ0Qsb0RBS0M7QUFTRCw4Q0FvRUM7QUFFRCwwQ0FTQztBQThCRCxrREEyQ0M7QUFTRCw4Q0ErQkM7QUFTRCx3Q0FjQztBQVVELHdDQXdCQztBQUVELGtEQU1DO0FBTUQsOERBY0M7QUFLRCxrREFVQztBQTNnQkQsaUNBQWtDO0FBQ2xDLHVEQUF3RDtBQUN4RCxpREFBNEY7QUFDNUYsMkNBQTRDO0FBQzVDLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0FBRTNDOzs7R0FHRztBQUNVLFFBQUEsbUJBQW1CLEdBQUcsTUFBTSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUN0QyxRQUFBLHlCQUF5QixHQUFHLElBQUksQ0FBQztBQVk5Qzs7Ozs7O0dBTUc7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxHQUEyQixFQUFFLE9BQWlCO0lBQ2xGLDJDQUEyQztJQUMzQyxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsNkRBQTZELENBQUMsQ0FBQztJQUUxRixtQ0FBbUM7SUFDbkMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFN0Isd0VBQXdFO0lBQ3hFLHFCQUFxQjtJQUNyQixFQUFFO0lBQ0YsMEJBQTBCO0lBQzFCLEVBQUU7SUFDRiw2RUFBNkU7SUFDN0UsbUVBQW1FO0lBQ25FLEVBQUU7SUFDRixrQ0FBa0M7SUFDbEMsb0JBQW9CO0lBRXBCLE1BQU0sQ0FBQyxHQUFHLHNCQUFPLENBQUMsVUFB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QUFDLFlBQTBDO0lBQzVFLE1BQU0sZ0JBQWdCLEdBQUcsc0JBQU8sQ0FBQyxTQUFTLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDekQsSUFBSSxnQkFBZ0IsRUFBRSxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFDRCxNQUFNLENBQUMsR0FBRyxFQUFFLFNBQVMsQ0FBQyxHQUFHLGdCQUFnQixDQUFDO0lBQzFDLElBQUksR0FBRyxLQUFLLHNCQUFPLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUN2RixNQUFNLElBQUksS0FBSyxDQUFDLCtCQUErQixDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUNELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBUYXByb290LXNwZWNpZmljIGtleSBhZ2dyZWdhdGlvbiBhbmQgdGFwdHJlZSBsb2dpYyBhcyBkZWZpbmVkIGluOlxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2JpdGNvaW4vYmlwcy9ibG9iL21hc3Rlci9iaXAtMDM0MC5tZWRpYXdpa2lcbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9iaXRjb2luL2JpcHMvYmxvYi9tYXN0ZXIvYmlwLTAzNDEubWVkaWF3aWtpXG5cbmltcG9ydCB7IFRhcFRyZWUgYXMgUHNidFRhcFRyZWUsIFRhcExlYWYgYXMgUHNidFRhcExlYWYgfSBmcm9tICdiaXAxNzQvc3JjL2xpYi9pbnRlcmZhY2VzJztcbmltcG9ydCBhc3NlcnQgPSByZXF1aXJlKCdhc3NlcnQnKTtcbmltcG9ydCBGYXN0UHJpb3JpdHlRdWV1ZSA9IHJlcXVpcmUoJ2Zhc3Rwcmlvcml0eXF1ZXVlJyk7XG5pbXBvcnQgeyBzY3JpcHQgYXMgYnNjcmlwdCwgY3J5cHRvIGFzIGJjcnlwdG8sIHBheW1lbnRzIGFzIGJwYXltZW50cyB9IGZyb20gJ2JpdGNvaW5qcy1saWInO1xuaW1wb3J0IHsgZWNjIGFzIGVjY0xpYiB9IGZyb20gJy4vbm9ibGVfZWNjJztcbmNvbnN0IHZhcnVpbnQgPSByZXF1aXJlKCd2YXJ1aW50LWJpdGNvaW4nKTtcblxuLyoqXG4gKiBUaGUgMHgwMiBwcmVmaXggaW5kaWNhdGluZyBhbiBldmVuIFkgY29vcmRpbmF0ZSB3aGljaCBpcyBpbXBsaWNpdGx5IGFzc3VtZWRcbiAqIG9uIGFsbCAzMiBieXRlIHgtb25seSBwdWIga2V5cyBhcyBkZWZpbmVkIGluIEJJUDM0MC5cbiAqL1xuZXhwb3J0IGNvbnN0IEVWRU5fWV9DT09SRF9QUkVGSVggPSBCdWZmZXIub2YoMHgwMik7XG5leHBvcnQgY29uc3QgSU5JVElBTF9UQVBTQ1JJUFRfVkVSU0lPTiA9IDB4YzA7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGlueVNlY3AyNTZrMUludGVyZmFjZSB7XG4gIGlzWE9ubHlQb2ludChwOiBVaW50OEFycmF5KTogYm9vbGVhbjtcbiAgeE9ubHlQb2ludEFkZFR3ZWFrKHA6IFVpbnQ4QXJyYXksIHR3ZWFrOiBVaW50OEFycmF5KTogWE9ubHlQb2ludEFkZFR3ZWFrUmVzdWx0IHwgbnVsbDtcbiAgcG9pbnRGcm9tU2NhbGFyKHNrOiBVaW50OEFycmF5LCBjb21wcmVzc2VkPzogYm9vbGVhbik6IFVpbnQ4QXJyYXkgfCBudWxsO1xuICBwb2ludE11bHRpcGx5KGE6IFVpbnQ4QXJyYXksIGI6IFVpbnQ4QXJyYXkpOiBVaW50OEFycmF5IHwgbnVsbDtcbiAgcG9pbnRBZGQoYTogVWludDhBcnJheSwgYjogVWludDhBcnJheSk6IFVpbnQ4QXJyYXkgfCBudWxsO1xuICBwcml2YXRlQWRkKGQ6IFVpbnQ4QXJyYXksIHR3ZWFrOiBVaW50OEFycmF5KTogVWludDhBcnJheSB8IG51bGw7XG4gIHByaXZhdGVOZWdhdGUoZDogVWludDhBcnJheSk6IFVpbnQ4QXJyYXk7XG59XG5cbi8qKlxuICogQWdncmVnYXRlcyBhIGxpc3Qgb2YgcHVibGljIGtleXMgaW50byBhIHNpbmdsZSBNdVNpZzIqIHB1YmxpYyBrZXlcbiAqIGFjY29yZGluZyB0byB0aGUgTXVTaWcyIHBhcGVyLlxuICogQHBhcmFtIGVjYyBFbGxpcHRpYyBjdXJ2ZSBpbXBsZW1lbnRhdGlvblxuICogQHBhcmFtIHB1YmtleXMgVGhlIGxpc3Qgb2YgcHViIGtleXMgdG8gYWdncmVnYXRlXG4gKiBAcmV0dXJucyBhIDMyIGJ5dGUgQnVmZmVyIHJlcHJlc2VudGluZyB0aGUgYWdncmVnYXRlIGtleVxuICovXG5leHBvcnQgZnVuY3Rpb24gYWdncmVnYXRlTXVTaWdQdWJrZXlzKGVjYzogVGlueVNlY3AyNTZrMUludGVyZmFjZSwgcHVia2V5czogQnVmZmVyW10pOiBVaW50OEFycmF5IHtcbiAgLy8gVE9ETzogQ29uc2lkZXIgZW5mb3JjaW5nIGtleSB1bmlxdWVuZXNzLlxuICBhc3NlcnQocHVia2V5cy5sZW5ndGggPiAxLCAnYXQgbGVhc3QgdHdvIHB1YmtleXMgYXJlIHJlcXVpcmVkIGZvciBtdXNpZyBrZXkgYWdncmVnYXRpb24nKTtcblxuICAvLyBTb3J0IHRoZSBrZXlzIGluIGFzY2VuZGluZyBvcmRlclxuICBwdWJrZXlzLnNvcnQoQnVmZmVyLmNvbXBhcmUpO1xuXG4gIC8vIEluIE11U2lnIGFsbCBzaWduZXJzIGNvbnRyaWJ1dGUga2V5IG1hdGVyaWFsIHRvIGEgc2luZ2xlIHNpZ25pbmcga2V5LFxuICAvLyB1c2luZyB0aGUgZXF1YXRpb25cbiAgLy9cbiAgLy8gICAgIFAgPSBzdW1faSDCtV9pICogUF9pXG4gIC8vXG4gIC8vIHdoZXJlIGBQX2lgIGlzIHRoZSBwdWJsaWMga2V5IG9mIHRoZSBgaWB0aCBzaWduZXIgYW5kIGDCtV9pYCBpcyBhIHNvLWNhbGxlZFxuICAvLyBfTXVTaWcgY29lZmZpY2llbnRfIGNvbXB1dGVkIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIGVxdWF0aW9uXG4gIC8vXG4gIC8vIEwgPSBIKFBfMSB8fCBQXzIgfHwgLi4uIHx8IFBfbilcbiAgLy8gwrVfaSA9IEgoTCB8fCBQX2kpXG5cbiAgY29uc3QgTCA9IGJjcnlwdG8udGFnZ2VkSGFzaCgnS2V5QWdnIGxpc3QnLCBCdWZmZXIuY29uY2F0KHB1YmtleXMpKTtcblxuICBjb25zdCBzZWNvbmRVbmlxdWVQdWJrZXkgPSBwdWJrZXlzLmZpbmQoKHB1YmtleSkgPT4gIXB1YmtleXNbMF0uZXF1YWxzKHB1YmtleSkpO1xuXG4gIGNvbnN0IHR3ZWFrZWRQdWJrZXlzOiBVaW50OEFycmF5W10gPSBwdWJrZXlzLm1hcCgocHVia2V5KSA9PiB7XG4gICAgY29uc3QgeHlQdWJrZXkgPSBCdWZmZXIuY29uY2F0KFtFVkVOX1lfQ09PUkRfUFJFRklYLCBwdWJrZXldKTtcblxuICAgIGlmIChzZWNvbmRVbmlxdWVQdWJrZXkgIT09IHVuZGVmaW5lZCAmJiBzZWNvbmRVbmlxdWVQdWJrZXkuZXF1YWxzKHB1YmtleSkpIHtcbiAgICAgIC8vIFRoZSBzZWNvbmQgdW5pcXVlIGtleSBpbiB0aGUgcHVia2V5IGxpc3QgZ2l2ZW4gdG8gJydLZXlBZ2cnJyAoYXMgd2VsbFxuICAgICAgLy8gYXMgYW55IGtleXMgaWRlbnRpY2FsIHRvIHRoaXMga2V5KSBnZXRzIHRoZSBjb25zdGFudCBLZXlBZ2dcbiAgICAgIC8vIGNvZWZmaWNpZW50IDEgd2hpY2ggc2F2ZXMgYW4gZXhwb25lbnRpYXRpb24gKHNlZSB0aGUgTXVTaWcyKiBhcHBlbmRpeFxuICAgICAgLy8gaW4gdGhlIE11U2lnMiBwYXBlcikuXG4gICAgICByZXR1cm4geHlQdWJrZXk7XG4gICAgfVxuXG4gICAgY29uc3QgYyA9IGJjcnlwdG8udGFnZ2VkSGFzaCgnS2V5QWdnIGNvZWZmaWNpZW50JywgQnVmZmVyLmNvbmNhdChbTCwgcHVia2V5XSkpO1xuXG4gICAgY29uc3QgdHdlYWtlZFB1YmtleSA9IGVjYy5wb2ludE11bHRpcGx5KHh5UHVia2V5LCBjKTtcbiAgICBpZiAoIXR3ZWFrZWRQdWJrZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIG11bHRpcGx5IHB1YmtleSBieSBjb2VmZmljaWVudCcpO1xuICAgIH1cbiAgICByZXR1cm4gdHdlYWtlZFB1YmtleTtcbiAgfSk7XG4gIGNvbnN0IGFnZ3JlZ2F0ZVB1YmtleSA9IHR3ZWFrZWRQdWJrZXlzLnJlZHVjZSgocHJldiwgY3VycikgPT4ge1xuICAgIGNvbnN0IG5leHQgPSBlY2MucG9pbnRBZGQocHJldiwgY3Vycik7XG4gICAgaWYgKCFuZXh0KSB0aHJvdyBuZXcgRXJyb3IoJ0ZhaWxlZCB0byBzdW0gcHVia2V5cycpO1xuICAgIHJldHVybiBuZXh0O1xuICB9KTtcblxuICByZXR1cm4gYWdncmVnYXRlUHVia2V5LnNsaWNlKDEpO1xufVxuXG4vKipcbiAqIEVuY29kZXMgdGhlIGxlbmd0aCBvZiBhIHNjcmlwdCBhcyBhIGJpdGNvaW4gdmFyaWFibGUgbGVuZ3RoIGludGVnZXIuXG4gKiBAcGFyYW0gc2NyaXB0XG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplU2NyaXB0U2l6ZShzY3JpcHQ6IEJ1ZmZlcik6IEJ1ZmZlciB7XG4gIHJldHVybiB2YXJ1aW50LmVuY29kZShzY3JpcHQubGVuZ3RoKTtcbn1cblxuLyoqXG4gKiBHZXRzIGEgdGFwbGVhZiB0YWdnZWQgaGFzaCBmcm9tIGEgc2NyaXB0LlxuICogQHBhcmFtIHNjcmlwdFxuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc2hUYXBMZWFmKHNjcmlwdDogQnVmZmVyLCBsZWFmVmVyc2lvbiA9IElOSVRJQUxfVEFQU0NSSVBUX1ZFUlNJT04pOiBCdWZmZXIge1xuICBjb25zdCBzaXplID0gc2VyaWFsaXplU2NyaXB0U2l6ZShzY3JpcHQpO1xuICByZXR1cm4gYmNyeXB0by50YWdnZWRIYXNoKCdUYXBMZWFmJywgQnVmZmVyLmNvbmNhdChbQnVmZmVyLm9mKGxlYWZWZXJzaW9uKSwgc2l6ZSwgc2NyaXB0XSkpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBsZXhpY29ncmFwaGljYWxseSBzb3J0ZWQgdGFwYnJhbmNoIGZyb20gdHdvIGNoaWxkIHRhcHRyZWUgbm9kZXNcbiAqIGFuZCByZXR1cm5zIGl0cyB0YWdnZWQgaGFzaC5cbiAqIEBwYXJhbSBjaGlsZDFcbiAqIEBwYXJhbSBjaGlsZDJcbiAqIEByZXR1cm5zIHRoZSB0YWdnZWQgdGFwYnJhbmNoIGhhc2hcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc2hUYXBCcmFuY2goY2hpbGQxOiBCdWZmZXIsIGNoaWxkMjogQnVmZmVyKTogQnVmZmVyIHtcbiAgLy8gc29ydCB0aGUgY2hpbGRyZW4gbGV4aWNvZ3JhcGhpY2FsbHlcbiAgY29uc3Qgc29ydGVkQ2hpbGRyZW4gPSBbY2hpbGQxLCBjaGlsZDJdLnNvcnQoQnVmZmVyLmNvbXBhcmUpO1xuXG4gIHJldHVybiBiY3J5cHRvLnRhZ2dlZEhhc2goJ1RhcEJyYW5jaCcsIEJ1ZmZlci5jb25jYXQoc29ydGVkQ2hpbGRyZW4pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZVRhcFR3ZWFrKHB1YmtleTogVWludDhBcnJheSwgdGFwdHJlZVJvb3Q/OiBVaW50OEFycmF5KTogVWludDhBcnJheSB7XG4gIGlmIChwdWJrZXkubGVuZ3RoICE9PSAzMikge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBwdWJrZXkgc2l6ZSAke3B1YmtleS5sZW5ndGh9LmApO1xuICB9XG4gIGlmICh0YXB0cmVlUm9vdCkge1xuICAgIGlmICh0YXB0cmVlUm9vdC5sZW5ndGggIT09IDMyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdGFwdHJlZVJvb3Qgc2l6ZSAke3RhcHRyZWVSb290Lmxlbmd0aH0uYCk7XG4gICAgfVxuICAgIHJldHVybiBiY3J5cHRvLnRhZ2dlZEhhc2goJ1RhcFR3ZWFrJywgQnVmZmVyLmNvbmNhdChbcHVia2V5LCB0YXB0cmVlUm9vdF0pKTtcbiAgfVxuICAvLyBJZiB0aGUgc3BlbmRpbmcgY29uZGl0aW9ucyBkbyBub3QgcmVxdWlyZSBhIHNjcmlwdCBwYXRoLCB0aGUgb3V0cHV0IGtleSBzaG91bGQgY29tbWl0IHRvIGFuXG4gIC8vIHVuc3BlbmRhYmxlIHNjcmlwdCBwYXRoIGluc3RlYWQgb2YgaGF2aW5nIG5vIHNjcmlwdCBwYXRoLlxuICAvLyBodHRwczovL2dpdGh1Yi5jb20vYml0Y29pbi9iaXBzL2Jsb2IvbWFzdGVyL2JpcC0wMzQxLm1lZGlhd2lraSNjaXRlX25vdGUtMjJcbiAgcmV0dXJuIGJjcnlwdG8udGFnZ2VkSGFzaCgnVGFwVHdlYWsnLCBCdWZmZXIuZnJvbShwdWJrZXkpKTtcbn1cblxuLyoqXG4gKiBUd2Vha3MgYSBwcml2a2V5LCB1c2luZyB0aGUgdGFnZ2VkIGhhc2ggb2YgaXRzIHB1YmtleSwgYW5kIChvcHRpb25hbGx5KSBhIHRhcHRyZWUgcm9vdFxuICogQHBhcmFtIGVjYyBFbGxpcHRpYyBjdXJ2ZSBpbXBsZW1lbnRhdGlvblxuICogQHBhcmFtIHB1YmtleSBwdWJsaWMga2V5LCB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgdHdlYWtcbiAqIEBwYXJhbSBwcml2a2V5IHRoZSBwcml2a2V5IHRvIHR3ZWFrXG4gKiBAcGFyYW0gdGFwdHJlZVJvb3QgdGhlIHRhcHRyZWUgcm9vdCB0YWdnZWQgaGFzaFxuICogQHJldHVybnMge0J1ZmZlcn0gdGhlIHR3ZWFrZWQgcHJpdmtleVxuICovXG5leHBvcnQgZnVuY3Rpb24gdGFwVHdlYWtQcml2a2V5KFxuICBlY2M6IFRpbnlTZWNwMjU2azFJbnRlcmZhY2UsXG4gIHB1YmtleTogVWludDhBcnJheSxcbiAgcHJpdmtleTogVWludDhBcnJheSxcbiAgdGFwdHJlZVJvb3Q/OiBVaW50OEFycmF5XG4pOiBVaW50OEFycmF5IHtcbiAgY29uc3QgdGFwVHdlYWsgPSBjYWxjdWxhdGVUYXBUd2VhayhwdWJrZXksIHRhcHRyZWVSb290KTtcblxuICBjb25zdCBwb2ludCA9IGVjYy5wb2ludEZyb21TY2FsYXIocHJpdmtleSk7XG4gIGlmICghcG9pbnQpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwcml2YXRlIGtleScpO1xuICBpZiAocG9pbnRbMF0gJSAyID09PSAxKSBwcml2a2V5ID0gZWNjLnByaXZhdGVOZWdhdGUocHJpdmtleSk7XG4gIGNvbnN0IHJlc3VsdCA9IGVjYy5wcml2YXRlQWRkKHByaXZrZXksIHRhcFR3ZWFrKTtcbiAgaWYgKCFyZXN1bHQpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwcml2YXRlIGtleScpO1xuICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFhPbmx5UG9pbnRBZGRUd2Vha1Jlc3VsdCB7XG4gIHBhcml0eTogMSB8IDA7XG4gIHhPbmx5UHVia2V5OiBVaW50OEFycmF5O1xufVxuXG4vKipcbiAqIFR3ZWFrcyBhbiBpbnRlcm5hbCBwdWJrZXksIHVzaW5nIHRoZSB0YWdnZWQgaGFzaCBvZiBpdHNlbGYsIGFuZCAob3B0aW9uYWxseSkgYSB0YXB0cmVlIHJvb3RcbiAqIEBwYXJhbSBlY2MgRWxsaXB0aWMgY3VydmUgaW1wbGVtZW50YXRpb25cbiAqIEBwYXJhbSBwdWJrZXkgdGhlIGludGVybmFsIHB1YmtleSB0byB0d2Vha1xuICogQHBhcmFtIHRhcHRyZWVSb290IHRoZSB0YXB0cmVlIHJvb3QgdGFnZ2VkIGhhc2hcbiAqIEByZXR1cm5zIHtUd2Vha2VkUHVia2V5fSB0aGUgdHdlYWtlZCBwdWJrZXlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRhcFR3ZWFrUHVia2V5KFxuICBlY2M6IFRpbnlTZWNwMjU2azFJbnRlcmZhY2UsXG4gIHB1YmtleTogVWludDhBcnJheSxcbiAgdGFwdHJlZVJvb3Q/OiBCdWZmZXJcbik6IFhPbmx5UG9pbnRBZGRUd2Vha1Jlc3VsdCB7XG4gIGNvbnN0IHRhcFR3ZWFrID0gY2FsY3VsYXRlVGFwVHdlYWsocHVia2V5LCB0YXB0cmVlUm9vdCk7XG4gIGNvbnN0IHJlc3VsdCA9IGVjYy54T25seVBvaW50QWRkVHdlYWsocHVia2V5LCB0YXBUd2Vhayk7XG4gIGlmICghcmVzdWx0KSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcHVia2V5Jyk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGFwdHJlZSB7XG4gIHJvb3Q6IEJ1ZmZlcjtcbiAgcGF0aHM6IEJ1ZmZlcltdW107XG59XG5cbmludGVyZmFjZSBXZWlnaHRlZFRhcFNjcmlwdCB7XG4gIC8qKiBBIFRhcExlYWYgb3IgVGFwQnJhbmNoIHRhZ2dlZCBoYXNoICovXG4gIHRhZ2dlZEhhc2g6IEJ1ZmZlcjtcbiAgd2VpZ2h0OiBudW1iZXI7XG4gIHBhdGhzOiB7XG4gICAgW2luZGV4OiBudW1iZXJdOiBCdWZmZXJbXTtcbiAgfTtcbn1cblxuZnVuY3Rpb24gcmVjdXJzZVRhcHRyZWUobGVhdmVzOiBJdGVyYXRvcjxbbnVtYmVyLCBQc2J0VGFwTGVhZl0+LCB0YXJnZXREZXB0aCA9IDApOiBUYXB0cmVlIHtcbiAgY29uc3QgeyB2YWx1ZSwgZG9uZSB9ID0gbGVhdmVzLm5leHQoKTtcbiAgYXNzZXJ0KCFkb25lLCAnaW5zdWZmaWNpZW50IGxlYXZlcyB0byByZWNvbnN0cnVjdCB0YXAgdHJlZScpO1xuICBjb25zdCBbaW5kZXgsIGxlYWZdID0gdmFsdWU7XG4gIGNvbnN0IHRyZWU6IFRhcHRyZWUgPSB7XG4gICAgcm9vdDogaGFzaFRhcExlYWYobGVhZi5zY3JpcHQsIGxlYWYubGVhZlZlcnNpb24pLFxuICAgIHBhdGhzOiBbXSxcbiAgfTtcbiAgdHJlZS5wYXRoc1tpbmRleF0gPSBbXTtcbiAgZm9yIChsZXQgZGVwdGggPSBsZWFmLmRlcHRoOyBkZXB0aCA+IHRhcmdldERlcHRoOyBkZXB0aC0tKSB7XG4gICAgY29uc3Qgc2libGluZyA9IHJlY3Vyc2VUYXB0cmVlKGxlYXZlcywgZGVwdGgpO1xuICAgIHRyZWUucGF0aHMuZm9yRWFjaCgocGF0aCkgPT4gcGF0aC5wdXNoKHNpYmxpbmcucm9vdCkpO1xuICAgIHNpYmxpbmcucGF0aHMuZm9yRWFjaCgocGF0aCkgPT4gcGF0aC5wdXNoKHRyZWUucm9vdCkpO1xuICAgIHRyZWUucm9vdCA9IGhhc2hUYXBCcmFuY2godHJlZS5yb290LCBzaWJsaW5nLnJvb3QpO1xuICAgIC8vIE1lcmdlIGRpc2pvaW50IHNwYXJzZSBhcnJheXMgb2YgcGF0aHMgaW50byB0cmVlLnBhdGhzXG4gICAgT2JqZWN0LmFzc2lnbih0cmVlLnBhdGhzLCBzaWJsaW5nLnBhdGhzKTtcbiAgfVxuICByZXR1cm4gdHJlZTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSByb290IGhhc2ggYW5kIGhhc2gtcGF0aHMgb2YgYSB0YXB0cmVlIGZyb20gdGhlIGRlcHRoLWZpcnN0XG4gKiBjb25zdHJ1Y3Rpb24gdXNlZCBpbiBCSVAtMDM3MSBQU0JUc1xuICogQHBhcmFtIHRyZWVcbiAqIEByZXR1cm5zIHtUYXB0cmVlfSB0aGUgdHJlZSwgcmVwcmVzZW50ZWQgYnkgaXRzIHJvb3QgaGFzaCwgYW5kIHRoZSBwYXRocyB0b1xuICogdGhhdCByb290IGZyb20gZWFjaCBvZiB0aGUgaW5wdXQgc2NyaXB0c1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RGVwdGhGaXJzdFRhcHRyZWUodHJlZTogUHNidFRhcFRyZWUpOiBUYXB0cmVlIHtcbiAgY29uc3QgaXRlciA9IHRyZWUubGVhdmVzLmVudHJpZXMoKTtcbiAgY29uc3QgcmV0ID0gcmVjdXJzZVRhcHRyZWUoaXRlcik7XG4gIGFzc2VydChpdGVyLm5leHQoKS5kb25lLCAnaW52YWxpZCB0YXAgdHJlZSwgbm8gcGF0aCB0byBzb21lIGxlYXZlcycpO1xuICByZXR1cm4gcmV0O1xufVxuXG4vKipcbiAqIEdldHMgdGhlIHJvb3QgaGFzaCBvZiBhIHRhcHRyZWUgdXNpbmcgYSB3ZWlnaHRlZCBIdWZmbWFuIGNvbnN0cnVjdGlvbiBmcm9tIGFcbiAqIGxpc3Qgb2Ygc2NyaXB0cyBhbmQgY29ycmVzcG9uZGluZyB3ZWlnaHRzLlxuICogQHBhcmFtIHNjcmlwdHNcbiAqIEBwYXJhbSB3ZWlnaHRzXG4gKiBAcmV0dXJucyB7VGFwdHJlZX0gdGhlIHRyZWUsIHJlcHJlc2VudGVkIGJ5IGl0cyByb290IGhhc2gsIGFuZCB0aGUgcGF0aHMgdG8gdGhhdCByb290IGZyb20gZWFjaCBvZiB0aGUgaW5wdXQgc2NyaXB0c1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0SHVmZm1hblRhcHRyZWUoc2NyaXB0czogQnVmZmVyW10sIHdlaWdodHM6IEFycmF5PG51bWJlciB8IHVuZGVmaW5lZD4pOiBUYXB0cmVlIHtcbiAgYXNzZXJ0KHNjcmlwdHMubGVuZ3RoID4gMCwgJ2F0IGxlYXN0IG9uZSBzY3JpcHQgaXMgcmVxdWlyZWQgdG8gY29uc3RydWN0IGEgdGFwIHRyZWUnKTtcblxuICAvLyBDcmVhdGUgYSBxdWV1ZS9oZWFwIG9mIHRoZSBwcm92aWRlZCBzY3JpcHRzIHByaW9yaXRpemVkIGFjY29yZGluZyB0byB0aGVpclxuICAvLyBjb3JyZXNwb25kaW5nIHdlaWdodHMuXG4gIGNvbnN0IHF1ZXVlID0gbmV3IEZhc3RQcmlvcml0eVF1ZXVlPFdlaWdodGVkVGFwU2NyaXB0PigoYSwgYik6IGJvb2xlYW4gPT4ge1xuICAgIHJldHVybiBhLndlaWdodCA8IGIud2VpZ2h0O1xuICB9KTtcbiAgc2NyaXB0cy5mb3JFYWNoKChzY3JpcHQsIGluZGV4KSA9PiB7XG4gICAgY29uc3Qgd2VpZ2h0ID0gd2VpZ2h0c1tpbmRleF0gfHwgMTtcbiAgICBhc3NlcnQod2VpZ2h0ID4gMCwgJ3NjcmlwdCB3ZWlnaHQgbXVzdCBiZSBhIHBvc2l0aXZlIHZhbHVlJyk7XG5cbiAgICBxdWV1ZS5hZGQoe1xuICAgICAgd2VpZ2h0LFxuICAgICAgdGFnZ2VkSGFzaDogaGFzaFRhcExlYWYoc2NyaXB0KSxcbiAgICAgIHBhdGhzOiB7IFtpbmRleF06IFtdIH0sXG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vIE5vdyB0aGF0IHdlIGhhdmUgYSBxdWV1ZSBvZiB3ZWlnaHRlZCBzY3JpcHRzLCB3ZSBiZWdpbiBhIGxvb3Agd2hlcmVieSB3ZVxuICAvLyByZW1vdmUgdGhlIHR3byBsb3dlc3Qgd2VpZ2h0ZWQgaXRlbXMgZnJvbSB0aGUgcXVldWUuIFdlIGNyZWF0ZSBhIHRhcCBicmFuY2hcbiAgLy8gbm9kZSBmcm9tIHRoZSB0d28gaXRlbXMsIGFuZCBhZGQgdGhlIGJyYW5jaCBiYWNrIHRvIHRoZSBxdWV1ZSB3aXRoIHRoZVxuICAvLyBjb21iaW5lZCB3ZWlnaHQgb2YgYm90aCBpdHMgY2hpbGRyZW4uIEVhY2ggbG9vcCByZWR1Y2VzIHRoZSBudW1iZXIgb2YgaXRlbXNcbiAgLy8gaW4gdGhlIHF1ZXVlIGJ5IG9uZSwgYW5kIHdlIHJlcGVhdCB1bnRpbCB3ZSBhcmUgbGVmdCB3aXRoIG9ubHkgb25lIGl0ZW0gLVxuICAvLyB0aGlzIGJlY29tZXMgdGhlIHRhcCB0cmVlIHJvb3QuXG4gIC8vXG4gIC8vIEZvciBleGFtcGxlLCBpZiB3ZSBiZWdpbiB3aXRoIHNjcmlwdHMgQSwgQiwgQywgRCB3aXRoIHdlaWdodHMgNiwgMywgMSwgMVxuICAvLyBBZnRlciBmaXJzdCBsb29wOiBBKDYpLCBCKDMpLCBDRCgxICsgMSlcbiAgLy8gQWZ0ZXIgc2Vjb25kIGxvb3A6IEEoNiksIEJbQ0RdKDMgKyAyKVxuICAvLyBGaW5hbCBsb29wOiBBW0JbQ0RdXSg2KzUpXG4gIC8vIFRoZSBmaW5hbCB0cmVlIHdpbGwgbG9vayBsaWtlOlxuICAvL1xuICAvLyAgICAgICAgQVtCW0NEXV1cbiAgLy8gICAgICAgLyAgICAgICAgXFxcbiAgLy8gICAgICBBICAgICAgICAgQltDRF1cbiAgLy8gICAgICAgICAgICAgICAvICAgICBcXFxuICAvLyAgICAgICAgICAgICAgQiAgICAgIFtDRF1cbiAgLy8gICAgICAgICAgICAgICAgICAgIC8gICAgXFxcbiAgLy8gICAgICAgICAgICAgICAgICAgQyAgICAgIERcbiAgLy9cbiAgLy8gVGhpcyBlbnN1cmVzIHRoYXQgdGhlIHNwZW5kaW5nIGNvbmRpdGlvbnMgd2UgYmVsaWV2ZSB0byBoYXZlIHRoZSBoaWdoZXN0XG4gIC8vIHByb2JhYmlsaXR5IG9mIGJlaW5nIHVzZWQgYXJlIGZ1cnRoZXIgdXAgdGhlIHRyZWUgdGhhbiBsZXNzIGxpa2VseSBzY3JpcHRzLFxuICAvLyB0aGVyZWJ5IHJlZHVjaW5nIHRoZSBzaXplIG9mIHRoZSBtZXJrbGUgcHJvb2ZzIGZvciB0aGUgbW9yZSBsaWtlbHkgc2NyaXB0cy5cbiAgd2hpbGUgKHF1ZXVlLnNpemUgPiAxKSB7XG4gICAgLy8gV2UgY2FuIHNhZmVseSBleHBlY3QgdHdvIHBvbGxzIHRvIHJldHVybiBub24tbnVsbCBlbGVtZW50cyBzaW5jZSB3ZSd2ZVxuICAgIC8vIGNoZWNrZWQgdGhhdCB0aGUgcXVldWUgaGFzIGF0IGxlYXN0IHR3byBlbGVtZW50cyBiZWZvcmUgbG9vcGluZy5cbiAgICBjb25zdCBjaGlsZDEgPSBxdWV1ZS5wb2xsKCkgYXMgV2VpZ2h0ZWRUYXBTY3JpcHQ7XG4gICAgY29uc3QgY2hpbGQyID0gcXVldWUucG9sbCgpIGFzIFdlaWdodGVkVGFwU2NyaXB0O1xuXG4gICAgT2JqZWN0LnZhbHVlcyhjaGlsZDEucGF0aHMpLmZvckVhY2goKHBhdGgpID0+IHBhdGgucHVzaChjaGlsZDIudGFnZ2VkSGFzaCkpO1xuICAgIE9iamVjdC52YWx1ZXMoY2hpbGQyLnBhdGhzKS5mb3JFYWNoKChwYXRoKSA9PiBwYXRoLnB1c2goY2hpbGQxLnRhZ2dlZEhhc2gpKTtcblxuICAgIHF1ZXVlLmFkZCh7XG4gICAgICB0YWdnZWRIYXNoOiBoYXNoVGFwQnJhbmNoKGNoaWxkMS50YWdnZWRIYXNoLCBjaGlsZDIudGFnZ2VkSGFzaCksXG4gICAgICB3ZWlnaHQ6IGNoaWxkMS53ZWlnaHQgKyBjaGlsZDIud2VpZ2h0LFxuICAgICAgcGF0aHM6IHsgLi4uY2hpbGQxLnBhdGhzLCAuLi5jaGlsZDIucGF0aHMgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8vIEFmdGVyIHRoZSB3aGlsZSBsb29wIGFib3ZlIGNvbXBsZXRlcyB3ZSBzaG91bGQgaGF2ZSBleGFjdGx5IG9uZSBlbGVtZW50XG4gIC8vIHJlbWFpbmluZyBpbiB0aGUgcXVldWUsIHdoaWNoIHdlIGNhbiBzYWZlbHkgZXh0cmFjdCBiZWxvdy5cbiAgY29uc3Qgcm9vdE5vZGUgPSBxdWV1ZS5wb2xsKCkgYXMgV2VpZ2h0ZWRUYXBTY3JpcHQ7XG5cbiAgY29uc3QgcGF0aHMgPSBPYmplY3QuZW50cmllcyhyb290Tm9kZS5wYXRocykucmVkdWNlKChhY2MsIFtpbmRleCwgcGF0aF0pID0+IHtcbiAgICBhY2NbTnVtYmVyKGluZGV4KV0gPSBwYXRoOyAvLyBUT0RPOiBXaHkgZG9lc24ndCBUUyBrbm93IGl0J3MgYSBudW1iZXI/XG4gICAgcmV0dXJuIGFjYztcbiAgfSwgQXJyYXkoc2NyaXB0cy5sZW5ndGgpKTtcbiAgcmV0dXJuIHsgcm9vdDogcm9vdE5vZGUudGFnZ2VkSGFzaCwgcGF0aHMgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldENvbnRyb2xCbG9jayhcbiAgcGFyaXR5OiAwIHwgMSxcbiAgcHVia2V5OiBVaW50OEFycmF5LFxuICBwYXRoOiBCdWZmZXJbXSxcbiAgbGVhZlZlcnNpb24gPSBJTklUSUFMX1RBUFNDUklQVF9WRVJTSU9OXG4pOiBCdWZmZXIge1xuICBjb25zdCBwYXJpdHlWZXJzaW9uID0gbGVhZlZlcnNpb24gKyBwYXJpdHk7XG5cbiAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW0J1ZmZlci5vZihwYXJpdHlWZXJzaW9uKSwgcHVia2V5LCAuLi5wYXRoXSk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgS2V5UGF0aFdpdG5lc3Mge1xuICBzcGVuZFR5cGU6ICdLZXknO1xuICBzaWduYXR1cmU6IEJ1ZmZlcjtcbiAgYW5uZXg/OiBCdWZmZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NyaXB0UGF0aFdpdG5lc3Mge1xuICBzcGVuZFR5cGU6ICdTY3JpcHQnO1xuICBzY3JpcHRTaWc6IEJ1ZmZlcltdO1xuICB0YXBzY3JpcHQ6IEJ1ZmZlcjtcbiAgY29udHJvbEJsb2NrOiBCdWZmZXI7XG4gIGFubmV4PzogQnVmZmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbnRyb2xCbG9jayB7XG4gIHBhcml0eTogbnVtYmVyO1xuICBpbnRlcm5hbFB1YmtleTogQnVmZmVyO1xuICBsZWFmVmVyc2lvbjogbnVtYmVyO1xuICBwYXRoOiBCdWZmZXJbXTtcbn1cblxuLyoqXG4gKiBQYXJzZXMgYSB0YXByb290IHdpdG5lc3Mgc3RhY2sgYW5kIGV4dHJhY3RzIGtleSBkYXRhIGVsZW1lbnRzLlxuICogQHBhcmFtIHdpdG5lc3NTdGFja1xuICogQHJldHVybnMge1NjcmlwdFBhdGhXaXRuZXNzfEtleVBhdGhXaXRuZXNzfSBhbiBvYmplY3QgcmVwcmVzZW50aW5nIHRoZVxuICogcGFyc2VkIHdpdG5lc3MgZm9yIGEgc2NyaXB0IHBhdGggb3Iga2V5IHBhdGggc3BlbmQuXG4gKiBAdGhyb3dzIHtFcnJvcn0gaWYgdGhlIHdpdG5lc3Mgc3RhY2sgZG9lcyBub3QgY29uZm9ybSB0byB0aGUgQklQIDM0MSBzY3JpcHQgdmFsaWRhdGlvbiBydWxlc1xuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VUYXByb290V2l0bmVzcyh3aXRuZXNzU3RhY2s6IEJ1ZmZlcltdKTogU2NyaXB0UGF0aFdpdG5lc3MgfCBLZXlQYXRoV2l0bmVzcyB7XG4gIGxldCBhbm5leDtcbiAgaWYgKHdpdG5lc3NTdGFjay5sZW5ndGggPj0gMiAmJiB3aXRuZXNzU3RhY2tbd2l0bmVzc1N0YWNrLmxlbmd0aCAtIDFdWzBdID09PSAweDUwKSB7XG4gICAgLy8gSWYgdGhlcmUgYXJlIGF0IGxlYXN0IHR3byB3aXRuZXNzIGVsZW1lbnRzLCBhbmQgdGhlIGZpcnN0IGJ5dGUgb2YgdGhlIGxhc3QgZWxlbWVudCBpc1xuICAgIC8vIDB4NTAsIHRoaXMgbGFzdCBlbGVtZW50IGlzIGNhbGxlZCBhbm5leCBhIGFuZCBpcyByZW1vdmVkIGZyb20gdGhlIHdpdG5lc3Mgc3RhY2tcbiAgICBhbm5leCA9IHdpdG5lc3NTdGFja1t3aXRuZXNzU3RhY2subGVuZ3RoIC0gMV07XG4gICAgd2l0bmVzc1N0YWNrID0gd2l0bmVzc1N0YWNrLnNsaWNlKDAsIC0xKTtcbiAgfVxuXG4gIGlmICh3aXRuZXNzU3RhY2subGVuZ3RoIDwgMSkge1xuICAgIHRocm93IG5ldyBFcnJvcignd2l0bmVzcyBzdGFjayBtdXN0IGhhdmUgYXQgbGVhc3Qgb25lIGVsZW1lbnQnKTtcbiAgfSBlbHNlIGlmICh3aXRuZXNzU3RhY2subGVuZ3RoID09PSAxKSB7XG4gICAgLy8ga2V5IHBhdGggc3BlbmRcbiAgICBjb25zdCBzaWduYXR1cmUgPSB3aXRuZXNzU3RhY2tbMF07XG4gICAgaWYgKCFic2NyaXB0LmlzQ2Fub25pY2FsU2Nobm9yclNpZ25hdHVyZShzaWduYXR1cmUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgc2lnbmF0dXJlJyk7XG4gICAgfVxuICAgIHJldHVybiB7IHNwZW5kVHlwZTogJ0tleScsIHNpZ25hdHVyZSwgYW5uZXggfTtcbiAgfVxuXG4gIC8vIHNjcmlwdCBwYXRoIHNwZW5kXG4gIC8vIHNlY29uZCB0byBsYXN0IGVsZW1lbnQgaXMgdGhlIHRhcHNjcmlwdFxuICBjb25zdCB0YXBzY3JpcHQgPSB3aXRuZXNzU3RhY2tbd2l0bmVzc1N0YWNrLmxlbmd0aCAtIDJdO1xuICBjb25zdCB0YXBzY3JpcHRDaHVua3MgPSBic2NyaXB0LmRlY29tcGlsZSh0YXBzY3JpcHQpO1xuXG4gIGlmICghdGFwc2NyaXB0Q2h1bmtzIHx8IHRhcHNjcmlwdENodW5rcy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3RhcHNjcmlwdCBpcyBub3QgYSB2YWxpZCBzY3JpcHQnKTtcbiAgfVxuXG4gIC8vIFRoZSBsYXN0IHN0YWNrIGVsZW1lbnQgaXMgY2FsbGVkIHRoZSBjb250cm9sIGJsb2NrIGMsIGFuZCBtdXN0IGhhdmUgbGVuZ3RoIDMzICsgMzJtLFxuICAvLyBmb3IgYSB2YWx1ZSBvZiBtIHRoYXQgaXMgYW4gaW50ZWdlciBiZXR3ZWVuIDAgYW5kIDEyOCwgaW5jbHVzaXZlXG4gIGNvbnN0IGNvbnRyb2xCbG9jayA9IHdpdG5lc3NTdGFja1t3aXRuZXNzU3RhY2subGVuZ3RoIC0gMV07XG4gIGlmIChjb250cm9sQmxvY2subGVuZ3RoIDwgMzMgfHwgY29udHJvbEJsb2NrLmxlbmd0aCA+IDMzICsgMzIgKiAxMjggfHwgY29udHJvbEJsb2NrLmxlbmd0aCAlIDMyICE9PSAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGNvbnRyb2wgYmxvY2sgbGVuZ3RoJyk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHNwZW5kVHlwZTogJ1NjcmlwdCcsXG4gICAgc2NyaXB0U2lnOiB3aXRuZXNzU3RhY2suc2xpY2UoMCwgLTIpLFxuICAgIHRhcHNjcmlwdCxcbiAgICBjb250cm9sQmxvY2ssXG4gICAgYW5uZXgsXG4gIH07XG59XG5cbi8qKlxuICogUGFyc2VzIGEgdGFwcm9vdCBjb250cm9sIGJsb2NrLlxuICogQHBhcmFtIGVjYyBFbGxpcHRpYyBjdXJ2ZSBpbXBsZW1lbnRhdGlvblxuICogQHBhcmFtIGNvbnRyb2xCbG9jayB0aGUgY29udHJvbCBibG9jayB0byBwYXJzZVxuICogQHJldHVybnMge0NvbnRyb2xCbG9ja30gdGhlIHBhcnNlZCBjb250cm9sIGJsb2NrXG4gKiBAdGhyb3dzIHtFcnJvcn0gaWYgdGhlIHdpdG5lc3Mgc3RhY2sgZG9lcyBub3QgY29uZm9ybSB0byB0aGUgQklQIDM0MSBzY3JpcHQgdmFsaWRhdGlvbiBydWxlc1xuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VDb250cm9sQmxvY2soZWNjOiBUaW55U2VjcDI1NmsxSW50ZXJmYWNlLCBjb250cm9sQmxvY2s6IEJ1ZmZlcik6IENvbnRyb2xCbG9jayB7XG4gIGlmICgoY29udHJvbEJsb2NrLmxlbmd0aCAtIDEpICUgMzIgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIGNvbnRyb2wgYmxvY2sgbGVuZ3RoJyk7XG4gIH1cblxuICBjb25zdCBwYXJpdHkgPSBjb250cm9sQmxvY2tbMF0gJiAweDAxO1xuXG4gIC8vIExldCBwID0gY1sxOjMzXSBhbmQgbGV0IFAgPSBsaWZ0X3goaW50KHApKSB3aGVyZSBsaWZ0X3ggYW5kIFs6XSBhcmUgZGVmaW5lZCBhcyBpbiBCSVAzNDAuXG4gIC8vIEZhaWwgaWYgdGhpcyBwb2ludCBpcyBub3Qgb24gdGhlIGN1cnZlXG4gIGNvbnN0IGludGVybmFsUHVia2V5ID0gY29udHJvbEJsb2NrLnNsaWNlKDEsIDMzKTtcbiAgaWYgKCFlY2MuaXNYT25seVBvaW50KGludGVybmFsUHVia2V5KSkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW50ZXJuYWwgcHVia2V5IGlzIG5vdCBhbiBFQyBwb2ludCcpO1xuICB9XG5cbiAgLy8gVGhlIGxlYWYgdmVyc2lvbiBjYW5ub3QgYmUgMHg1MCBhcyB0aGF0IHdvdWxkIHJlc3VsdCBpbiBhbWJpZ3VpdHkgd2l0aCB0aGUgYW5uZXguXG4gIGNvbnN0IGxlYWZWZXJzaW9uID0gY29udHJvbEJsb2NrWzBdICYgMHhmZTtcbiAgaWYgKGxlYWZWZXJzaW9uID09PSAweDUwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGxlYWYgdmVyc2lvbicpO1xuICB9XG5cbiAgY29uc3QgcGF0aDogQnVmZmVyW10gPSBbXTtcbiAgZm9yIChsZXQgaiA9IDMzOyBqIDwgY29udHJvbEJsb2NrLmxlbmd0aDsgaiArPSAzMikge1xuICAgIHBhdGgucHVzaChjb250cm9sQmxvY2suc2xpY2UoaiwgaiArIDMyKSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHBhcml0eSxcbiAgICBpbnRlcm5hbFB1YmtleSxcbiAgICBsZWFmVmVyc2lvbixcbiAgICBwYXRoLFxuICB9O1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHRhcGxlYWYgaGFzaCBmcm9tIGEgY29udHJvbCBibG9jayBhbmQgc2NyaXB0LlxuICogQHBhcmFtIGVjYyBFbGxpcHRpYyBjdXJ2ZSBpbXBsZW1lbnRhdGlvblxuICogQHBhcmFtIGNvbnRyb2xCbG9jayB0aGUgY29udHJvbCBibG9jaywgZWl0aGVyIHJhdyBvciBwYXJzZWRcbiAqIEBwYXJhbSB0YXBzY3JpcHQgdGhlIGxlYWYgc2NyaXB0IGNvcnJlc2Rwb25kaW5nIHRvIHRoZSBjb250cm9sIGJsb2NrXG4gKiBAcmV0dXJucyB7QnVmZmVyfSB0aGUgdGFwbGVhZiBoYXNoXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUYXBsZWFmSGFzaChcbiAgZWNjOiBUaW55U2VjcDI1NmsxSW50ZXJmYWNlLFxuICBjb250cm9sQmxvY2s6IEJ1ZmZlciB8IENvbnRyb2xCbG9jayxcbiAgdGFwc2NyaXB0OiBCdWZmZXJcbik6IEJ1ZmZlciB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIoY29udHJvbEJsb2NrKSkge1xuICAgIGNvbnRyb2xCbG9jayA9IHBhcnNlQ29udHJvbEJsb2NrKGVjYywgY29udHJvbEJsb2NrKTtcbiAgfVxuICBjb25zdCB7IGxlYWZWZXJzaW9uIH0gPSBjb250cm9sQmxvY2s7XG5cbiAgcmV0dXJuIGJjcnlwdG8udGFnZ2VkSGFzaChcbiAgICAnVGFwTGVhZicsXG4gICAgQnVmZmVyLmNvbmNhdChbQnVmZmVyLm9mKGxlYWZWZXJzaW9uKSwgc2VyaWFsaXplU2NyaXB0U2l6ZSh0YXBzY3JpcHQpLCB0YXBzY3JpcHRdKVxuICApO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHRhcHRyZWUgcm9vdCBoYXNoIGZyb20gYSBjb250cm9sIGJsb2NrIGFuZCBzY3JpcHQuXG4gKiBAcGFyYW0gZWNjIEVsbGlwdGljIGN1cnZlIGltcGxlbWVudGF0aW9uXG4gKiBAcGFyYW0gY29udHJvbEJsb2NrIHRoZSBjb250cm9sIGJsb2NrLCBlaXRoZXIgcmF3IG9yIHBhcnNlZFxuICogQHBhcmFtIHRhcHNjcmlwdCB0aGUgbGVhZiBzY3JpcHQgY29ycmVzZHBvbmRpbmcgdG8gdGhlIGNvbnRyb2wgYmxvY2tcbiAqIEBwYXJhbSB0YXBsZWFmSGFzaCB0aGUgbGVhZiBoYXNoIGlmIGFscmVhZHkgY2FsY3VsYXRlZFxuICogQHJldHVybnMge0J1ZmZlcn0gdGhlIHRhcHRyZWUgcm9vdCBoYXNoXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUYXB0cmVlUm9vdChcbiAgZWNjOiBUaW55U2VjcDI1NmsxSW50ZXJmYWNlLFxuICBjb250cm9sQmxvY2s6IEJ1ZmZlciB8IENvbnRyb2xCbG9jayxcbiAgdGFwc2NyaXB0OiBCdWZmZXIsXG4gIHRhcGxlYWZIYXNoPzogQnVmZmVyXG4pOiBCdWZmZXIge1xuICBpZiAoQnVmZmVyLmlzQnVmZmVyKGNvbnRyb2xCbG9jaykpIHtcbiAgICBjb250cm9sQmxvY2sgPSBwYXJzZUNvbnRyb2xCbG9jayhlY2MsIGNvbnRyb2xCbG9jayk7XG4gIH1cbiAgY29uc3QgeyBwYXRoIH0gPSBjb250cm9sQmxvY2s7XG5cbiAgdGFwbGVhZkhhc2ggPSB0YXBsZWFmSGFzaCB8fCBnZXRUYXBsZWFmSGFzaChlY2MsIGNvbnRyb2xCbG9jaywgdGFwc2NyaXB0KTtcblxuICAvLyBgdGFwdHJlZU1lcmtsZUhhc2hgIGJlZ2lucyBhcyBvdXIgdGFwc2NyaXB0IHRhcGxlYWYgaGFzaCBhbmQgaXRzIHZhbHVlIGl0ZXJhdGVzXG4gIC8vIHRocm91Z2ggaXRzIHBhcmVudCB0YXBicmFuY2ggaGFzaGVzIHVudGlsIGl0IGVuZHMgdXAgYXMgdGhlIHRhcHRyZWUgcm9vdCBoYXNoXG4gIGxldCB0YXB0cmVlTWVya2xlSGFzaCA9IHRhcGxlYWZIYXNoO1xuICBmb3IgKGNvbnN0IHRhcHRyZWVTaWJsaW5nSGFzaCBvZiBwYXRoKSB7XG4gICAgdGFwdHJlZU1lcmtsZUhhc2ggPVxuICAgICAgQnVmZmVyLmNvbXBhcmUodGFwdHJlZU1lcmtsZUhhc2gsIHRhcHRyZWVTaWJsaW5nSGFzaCkgPT09IC0xXG4gICAgICAgID8gYmNyeXB0by50YWdnZWRIYXNoKCdUYXBCcmFuY2gnLCBCdWZmZXIuY29uY2F0KFt0YXB0cmVlTWVya2xlSGFzaCwgdGFwdHJlZVNpYmxpbmdIYXNoXSkpXG4gICAgICAgIDogYmNyeXB0by50YWdnZWRIYXNoKCdUYXBCcmFuY2gnLCBCdWZmZXIuY29uY2F0KFt0YXB0cmVlU2libGluZ0hhc2gsIHRhcHRyZWVNZXJrbGVIYXNoXSkpO1xuICB9XG5cbiAgcmV0dXJuIHRhcHRyZWVNZXJrbGVIYXNoO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VHdlYWtlZE91dHB1dEtleShwYXltZW50OiBicGF5bWVudHMuUGF5bWVudCk6IEJ1ZmZlciB7XG4gIGFzc2VydChwYXltZW50Lm91dHB1dCk7XG4gIGlmIChwYXltZW50Lm91dHB1dC5sZW5ndGggPT09IDM0KSB7XG4gICAgcmV0dXJuIHBheW1lbnQub3V0cHV0Py5zdWJhcnJheSgyKTtcbiAgfVxuICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgcDJ0ciB0d2Vha2VkIG91dHB1dCBrZXkgc2l6ZSAke3BheW1lbnQub3V0cHV0Lmxlbmd0aH1gKTtcbn1cblxuLyoqXG4gKiBAcmV0dXJucyBvdXRwdXQgc2NyaXB0IGZvciBlaXRoZXIgc2NyaXB0IHBhdGggaW5wdXQgY29udHJvbEJsb2NrXG4gKiAmIGxlYWZTY3JpcHQgT1Iga2V5IHBhdGggaW5wdXQgaW50ZXJuYWxQdWJLZXkgJiB0YXB0cmVlUm9vdFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlVGFwcm9vdE91dHB1dFNjcmlwdChcbiAgcDJ0ckFyZ3M6IHsgaW50ZXJuYWxQdWJLZXk6IEJ1ZmZlcjsgdGFwdHJlZVJvb3Q6IEJ1ZmZlciB9IHwgeyBjb250cm9sQmxvY2s6IEJ1ZmZlcjsgbGVhZlNjcmlwdDogQnVmZmVyIH1cbik6IEJ1ZmZlciB7XG4gIGxldCBpbnRlcm5hbFB1YktleTogQnVmZmVyIHwgdW5kZWZpbmVkO1xuICBsZXQgdGFwdHJlZVJvb3Q6IEJ1ZmZlciB8IHVuZGVmaW5lZDtcbiAgaWYgKCdpbnRlcm5hbFB1YktleScgaW4gcDJ0ckFyZ3MpIHtcbiAgICBpbnRlcm5hbFB1YktleSA9IHAydHJBcmdzLmludGVybmFsUHViS2V5O1xuICAgIHRhcHRyZWVSb290ID0gcDJ0ckFyZ3MudGFwdHJlZVJvb3Q7XG4gIH0gZWxzZSB7XG4gICAgaW50ZXJuYWxQdWJLZXkgPSBwYXJzZUNvbnRyb2xCbG9jayhlY2NMaWIsIHAydHJBcmdzLmNvbnRyb2xCbG9jaykuaW50ZXJuYWxQdWJrZXk7XG4gICAgdGFwdHJlZVJvb3QgPSBnZXRUYXB0cmVlUm9vdChlY2NMaWIsIHAydHJBcmdzLmNvbnRyb2xCbG9jaywgcDJ0ckFyZ3MubGVhZlNjcmlwdCk7XG4gIH1cbiAgY29uc3Qgb3V0cHV0S2V5ID0gdGFwVHdlYWtQdWJrZXkoZWNjTGliLCBpbnRlcm5hbFB1YktleSwgdGFwdHJlZVJvb3QpLnhPbmx5UHVia2V5O1xuICByZXR1cm4gYnNjcmlwdC5jb21waWxlKFtic2NyaXB0Lk9QUy5PUF8xLCBCdWZmZXIuZnJvbShvdXRwdXRLZXkpXSk7XG59XG5cbi8qKlxuICogQHJldHVybnMgeC1vbmx5IHRhcHJvb3Qgb3V0cHV0IGtleSAodGFwT3V0cHV0S2V5KVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VGFwcm9vdE91dHB1dEtleShvdXRwdXRTY3JpcHQ6IEJ1ZmZlciB8IChudW1iZXIgfCBCdWZmZXIpW10pOiBCdWZmZXIge1xuICBjb25zdCBvdXRwdXREZWNvbXBpbGVkID0gYnNjcmlwdC5kZWNvbXBpbGUob3V0cHV0U2NyaXB0KTtcbiAgaWYgKG91dHB1dERlY29tcGlsZWQ/Lmxlbmd0aCAhPT0gMikge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCB0YXByb290IG91dHB1dCBzY3JpcHQnKTtcbiAgfVxuICBjb25zdCBbb3AxLCBvdXRwdXRLZXldID0gb3V0cHV0RGVjb21waWxlZDtcbiAgaWYgKG9wMSAhPT0gYnNjcmlwdC5PUFMuT1BfMSB8fCAhQnVmZmVyLmlzQnVmZmVyKG91dHB1dEtleSkgfHwgb3V0cHV0S2V5Lmxlbmd0aCAhPT0gMzIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgdGFwcm9vdCBvdXRwdXQgc2NyaXB0Jyk7XG4gIH1cbiAgcmV0dXJuIG91dHB1dEtleTtcbn1cbiJdfQ==

Выполнить команду


Для локальной разработки. Не используйте в интернете!