UNPKG

@bitgo/utxo-lib

Version:

Client-side Bitcoin JavaScript library

122 lines 18.8 kB
"use strict"; /** * Contains helper methods for getting and sorting root nodes from a PSBT. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ErrorNoMultiSigInputFound = void 0; exports.getUnsortedRootNodes = getUnsortedRootNodes; exports.sortRootNodes = sortRootNodes; exports.getSortedRootNodes = getSortedRootNodes; const assert_1 = require("assert"); const bs58check = require("bs58check"); const types_1 = require("../../types"); const secp256k1_1 = require("@bitgo/secp256k1"); const outputScripts_1 = require("../../outputScripts"); const transaction_1 = require("../../transaction"); const Psbt_1 = require("../Psbt"); /** * Error thrown when no multi-sig input is found in a PSBT. * */ class ErrorNoMultiSigInputFound extends Error { constructor(message) { super(message); } } exports.ErrorNoMultiSigInputFound = ErrorNoMultiSigInputFound; /** * Retrieves unsorted root BIP32Interface nodes from a PSBT if available. * @param psbt - The PSBT from which to extract the global Xpubs. * @returns An array of BIP32Interface objects or undefined if not available. */ function getUnsortedRootNodes(psbt) { const bip32s = psbt.data.globalMap.globalXpub?.map((xpub) => (0, secp256k1_1.BIP32Factory)(secp256k1_1.ecc).fromBase58(bs58check.encode(xpub.extendedPubkey))); (0, assert_1.ok)(!bip32s || (0, types_1.isTriple)(bip32s), `Invalid globalXpubs in PSBT. Expected 3 or none. Got ${bip32s?.length}`); return bip32s; } /** * Determines if the given public keys' permutation matches a specified script. * @param params - Object containing public keys, permutation, script public key, script type, and network. * @returns A boolean indicating if the permutation matches the script. */ function matchesScript({ pubKeys, perm, scriptPubKey, parsedScriptType, network, }) { const pubKeysPerm = [pubKeys[perm[0]], pubKeys[perm[1]], pubKeys[perm[2]]]; const scriptTypes = (0, Psbt_1.toScriptType2Of3s)(parsedScriptType); return scriptTypes.some((scriptType) => (0, outputScripts_1.createOutputScript2of3)(pubKeysPerm, scriptType, network).scriptPubKey.equals(scriptPubKey)); } /** * Finds the correct order of public keys to match a given script. * @param pubKeys - Array of public keys involved in the script. * @param scriptPubKey - The script public key to match against. * @param parsedScriptType - The parsed script type. * @param network - Bitcoin network. * @returns The order of public keys that match the script. */ function findSortOrderOfPubKeys(pubKeys, scriptPubKey, parsedScriptType, network) { const permutations = [ [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0], ]; const order = permutations.find((perm) => matchesScript({ pubKeys, perm, scriptPubKey, parsedScriptType, network })); (0, assert_1.ok)(order, 'Could not find sort order of multi sig public keys'); return order; } /** * Extracts multi-sig input data, including script type, script public key, and derivation path, from the first relevant PSBT input. * @param psbt - The PSBT to extract data from. * @returns An object containing the parsed script type, script public key, and derivation path. */ function getFirstMultiSigInputData(psbt) { function getScriptPubKey(input, prevOutIndex) { const scriptPubKey = input.witnessUtxo?.script ?? (input.nonWitnessUtxo ? (0, transaction_1.createTransactionFromBuffer)(input.nonWitnessUtxo, psbt.network, { amountType: 'bigint' }).outs[prevOutIndex] .script : undefined); (0, assert_1.ok)(scriptPubKey, 'Input scriptPubKey can not be found'); return scriptPubKey; } function getDerivationPath(input) { const bip32Dv = input?.bip32Derivation ?? input?.tapBip32Derivation; (0, assert_1.ok)(bip32Dv?.length, 'Input Bip32Derivation can not be found'); return bip32Dv[0].path; } const txInputs = psbt.txInputs; for (let i = 0; i < psbt.data.inputs.length; i++) { const input = psbt.data.inputs[i]; const parsedScriptType = (0, Psbt_1.getPsbtInputScriptType)(input); if (parsedScriptType === 'p2shP2pk') { continue; } const scriptPubKey = getScriptPubKey(input, txInputs[i].index); const derivationPath = getDerivationPath(input); return { parsedScriptType, scriptPubKey, derivationPath }; } throw new ErrorNoMultiSigInputFound('No multi sig input found'); } /** * Sorts given root nodes based on the script compatibility with the PSBT's multi-sig inputs. * @param psbt - The PSBT containing multi-sig inputs. * @param rootNodes - Array of root nodes to sort. * @returns An array of BIP32Interface objects in the order that matches the multi-sig script. */ function sortRootNodes(psbt, rootNodes) { const { parsedScriptType, scriptPubKey, derivationPath } = getFirstMultiSigInputData(psbt); const pubKeys = rootNodes.map((rootNode) => rootNode.derivePath(derivationPath).publicKey); const order = findSortOrderOfPubKeys(pubKeys, scriptPubKey, parsedScriptType, psbt.network); return order.map((i) => rootNodes[i]); } /** * Retrieves sorted root nodes from a PSBT, ensuring they are ordered according to script compatibility. * @param psbt - The PSBT to extract and sort root nodes from. * @returns An array of sorted BIP32Interface root nodes. */ function getSortedRootNodes(psbt) { const unsortedRootNodes = getUnsortedRootNodes(psbt); (0, assert_1.ok)(unsortedRootNodes, 'Could not find root nodes in PSBT'); return sortRootNodes(psbt, unsortedRootNodes); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm9vdE5vZGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2JpdGdvL3dhbGxldC9wc2J0L1Jvb3ROb2Rlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7OztBQTZCSCxvREFNQztBQXdHRCxzQ0FLQztBQU9ELGdEQUlDO0FBekpELG1DQUFzQztBQUN0Qyx1Q0FBdUM7QUFHdkMsdUNBQStDO0FBQy9DLGdEQUErRTtBQUcvRSx1REFBNkQ7QUFFN0QsbURBQWdFO0FBQ2hFLGtDQUFvRTtBQUVwRTs7S0FFSztBQUNMLE1BQWEseUJBQTBCLFNBQVEsS0FBSztJQUNsRCxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2pCLENBQUM7Q0FDRjtBQUpELDhEQUlDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLG9CQUFvQixDQUFDLElBQWM7SUFDakQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQzFELElBQUEsd0JBQVksRUFBQyxlQUFNLENBQUMsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FDdkUsQ0FBQztJQUNGLElBQUEsV0FBTSxFQUFDLENBQUMsTUFBTSxJQUFJLElBQUEsZ0JBQVEsRUFBQyxNQUFNLENBQUMsRUFBRSx3REFBd0QsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDOUcsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLGFBQWEsQ0FBQyxFQUNyQixPQUFPLEVBQ1AsSUFBSSxFQUNKLFlBQVksRUFDWixnQkFBZ0IsRUFDaEIsT0FBTyxHQU9SO0lBQ0MsTUFBTSxXQUFXLEdBQW1CLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxD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QyxDQUFDO0FBQ2hELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvbnRhaW5zIGhlbHBlciBtZXRob2RzIGZvciBnZXR0aW5nIGFuZCBzb3J0aW5nIHJvb3Qgbm9kZXMgZnJvbSBhIFBTQlQuXG4gKi9cblxuaW1wb3J0IHsgb2sgYXMgYXNzZXJ0IH0gZnJvbSAnYXNzZXJ0JztcbmltcG9ydCAqIGFzIGJzNThjaGVjayBmcm9tICdiczU4Y2hlY2snO1xuXG5pbXBvcnQgeyBVdHhvUHNidCB9IGZyb20gJy4uLy4uL1V0eG9Qc2J0JztcbmltcG9ydCB7IGlzVHJpcGxlLCBUcmlwbGUgfSBmcm9tICcuLi8uLi90eXBlcyc7XG5pbXBvcnQgeyBCSVAzMkZhY3RvcnksIEJJUDMySW50ZXJmYWNlLCBlY2MgYXMgZWNjTGliIH0gZnJvbSAnQGJpdGdvL3NlY3AyNTZrMSc7XG5pbXBvcnQgeyBQYXJzZWRTY3JpcHRUeXBlMk9mMyB9IGZyb20gJy4uLy4uL3BhcnNlSW5wdXQnO1xuaW1wb3J0IHsgTmV0d29yayB9IGZyb20gJy4uLy4uLy4uL25ldHdvcmtzJztcbmltcG9ydCB7IGNyZWF0ZU91dHB1dFNjcmlwdDJvZjMgfSBmcm9tICcuLi8uLi9vdXRwdXRTY3JpcHRzJztcbmltcG9ydCB7IFBzYnRJbnB1dCB9IGZyb20gJ2JpcDE3NC9zcmMvbGliL2ludGVyZmFjZXMnO1xuaW1wb3J0IHsgY3JlYXRlVHJhbnNhY3Rpb25Gcm9tQnVmZmVyIH0gZnJvbSAnLi4vLi4vdHJhbnNhY3Rpb24nO1xuaW1wb3J0IHsgZ2V0UHNidElucHV0U2NyaXB0VHlwZSwgdG9TY3JpcHRUeXBlMk9mM3MgfSBmcm9tICcuLi9Qc2J0JztcblxuLyoqXG4gKiBFcnJvciB0aHJvd24gd2hlbiBubyBtdWx0aS1zaWcgaW5wdXQgaXMgZm91bmQgaW4gYSBQU0JULlxuICogKi9cbmV4cG9ydCBjbGFzcyBFcnJvck5vTXVsdGlTaWdJbnB1dEZvdW5kIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgfVxufVxuXG4vKipcbiAqIFJldHJpZXZlcyB1bnNvcnRlZCByb290IEJJUDMySW50ZXJmYWNlIG5vZGVzIGZyb20gYSBQU0JUIGlmIGF2YWlsYWJsZS5cbiAqIEBwYXJhbSBwc2J0IC0gVGhlIFBTQlQgZnJvbSB3aGljaCB0byBleHRyYWN0IHRoZSBnbG9iYWwgWHB1YnMuXG4gKiBAcmV0dXJucyBBbiBhcnJheSBvZiBCSVAzMkludGVyZmFjZSBvYmplY3RzIG9yIHVuZGVmaW5lZCBpZiBub3QgYXZhaWxhYmxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VW5zb3J0ZWRSb290Tm9kZXMocHNidDogVXR4b1BzYnQpOiBUcmlwbGU8QklQMzJJbnRlcmZhY2U+IHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgYmlwMzJzID0gcHNidC5kYXRhLmdsb2JhbE1hcC5nbG9iYWxYcHViPy5tYXAoKHhwdWIpID0+XG4gICAgQklQMzJGYWN0b3J5KGVjY0xpYikuZnJvbUJhc2U1OChiczU4Y2hlY2suZW5jb2RlKHhwdWIuZXh0ZW5kZWRQdWJrZXkpKVxuICApO1xuICBhc3NlcnQoIWJpcDMycyB8fCBpc1RyaXBsZShiaXAzMnMpLCBgSW52YWxpZCBnbG9iYWxYcHVicyBpbiBQU0JULiBFeHBlY3RlZCAzIG9yIG5vbmUuIEdvdCAke2JpcDMycz8ubGVuZ3RofWApO1xuICByZXR1cm4gYmlwMzJzO1xufVxuXG4vKipcbiAqIERldGVybWluZXMgaWYgdGhlIGdpdmVuIHB1YmxpYyBrZXlzJyBwZXJtdXRhdGlvbiBtYXRjaGVzIGEgc3BlY2lmaWVkIHNjcmlwdC5cbiAqIEBwYXJhbSBwYXJhbXMgLSBPYmplY3QgY29udGFpbmluZyBwdWJsaWMga2V5cywgcGVybXV0YXRpb24sIHNjcmlwdCBwdWJsaWMga2V5LCBzY3JpcHQgdHlwZSwgYW5kIG5ldHdvcmsuXG4gKiBAcmV0dXJucyBBIGJvb2xlYW4gaW5kaWNhdGluZyBpZiB0aGUgcGVybXV0YXRpb24gbWF0Y2hlcyB0aGUgc2NyaXB0LlxuICovXG5mdW5jdGlvbiBtYXRjaGVzU2NyaXB0KHtcbiAgcHViS2V5cyxcbiAgcGVybSxcbiAgc2NyaXB0UHViS2V5LFxuICBwYXJzZWRTY3JpcHRUeXBlLFxuICBuZXR3b3JrLFxufToge1xuICBwdWJLZXlzOiBCdWZmZXJbXTtcbiAgcGVybTogVHJpcGxlPG51bWJlcj47XG4gIHNjcmlwdFB1YktleTogQnVmZmVyO1xuICBwYXJzZWRTY3JpcHRUeXBlOiBQYXJzZWRTY3JpcHRUeXBlMk9mMztcbiAgbmV0d29yazogTmV0d29yaztcbn0pOiBib29sZWFuIHtcbiAgY29uc3QgcHViS2V5c1Blcm06IFRyaXBsZTxCdWZmZXI+ID0gW3B1YktleXNbcGVybVswXV0sIHB1YktleXNbcGVybVsxXV0sIHB1YktleXNbcGVybVsyXV1dO1xuICBjb25zdCBzY3JpcHRUeXBlcyA9IHRvU2NyaXB0VHlwZTJPZjNzKHBhcnNlZFNjcmlwdFR5cGUpO1xuICByZXR1cm4gc2NyaXB0VHlwZXMuc29tZSgoc2NyaXB0VHlwZSkgPT5cbiAgICBjcmVhdGVPdXRwdXRTY3JpcHQyb2YzKHB1YktleXNQZXJtLCBzY3JpcHRUeXBlLCBuZXR3b3JrKS5zY3JpcHRQdWJLZXkuZXF1YWxzKHNjcmlwdFB1YktleSlcbiAgKTtcbn1cblxuLyoqXG4gKiBGaW5kcyB0aGUgY29ycmVjdCBvcmRlciBvZiBwdWJsaWMga2V5cyB0byBtYXRjaCBhIGdpdmVuIHNjcmlwdC5cbiAqIEBwYXJhbSBwdWJLZXlzIC0gQXJyYXkgb2YgcHVibGljIGtleXMgaW52b2x2ZWQgaW4gdGhlIHNjcmlwdC5cbiAqIEBwYXJhbSBzY3JpcHRQdWJLZXkgLSBUaGUgc2NyaXB0IHB1YmxpYyBrZXkgdG8gbWF0Y2ggYWdhaW5zdC5cbiAqIEBwYXJhbSBwYXJzZWRTY3JpcHRUeXBlIC0gVGhlIHBhcnNlZCBzY3JpcHQgdHlwZS5cbiAqIEBwYXJhbSBuZXR3b3JrIC0gQml0Y29pbiBuZXR3b3JrLlxuICogQHJldHVybnMgVGhlIG9yZGVyIG9mIHB1YmxpYyBrZXlzIHRoYXQgbWF0Y2ggdGhlIHNjcmlwdC5cbiAqL1xuZnVuY3Rpb24gZmluZFNvcnRPcmRlck9mUHViS2V5cyhcbiAgcHViS2V5czogVHJpcGxlPEJ1ZmZlcj4sXG4gIHNjcmlwdFB1YktleTogQnVmZmVyLFxuICBwYXJzZWRTY3JpcHRUeXBlOiBQYXJzZWRTY3JpcHRUeXBlMk9mMyxcbiAgbmV0d29yazogTmV0d29ya1xuKTogVHJpcGxlPG51bWJlcj4ge1xuICBjb25zdCBwZXJtdXRhdGlvbnM6IEFycmF5PFRyaXBsZTxudW1iZXI+PiA9IFtcbiAgICBbMCwgMSwgMl0sXG4gICAgWzAsIDIsIDFdLFxuICAgIFsxLCAwLCAyXSxcbiAgICBbMSwgMiwgMF0sXG4gICAgWzIsIDAsIDFdLFxuICAgIFsyLCAxLCAwXSxcbiAgXTtcblxuICBjb25zdCBvcmRlciA9IHBlcm11dGF0aW9ucy5maW5kKChwZXJtKSA9PiBtYXRjaGVzU2NyaXB0KHsgcHViS2V5cywgcGVybSwgc2NyaXB0UHViS2V5LCBwYXJzZWRTY3JpcHRUeXBlLCBuZXR3b3JrIH0pKTtcbiAgYXNzZXJ0KG9yZGVyLCAnQ291bGQgbm90IGZpbmQgc29ydCBvcmRlciBvZiBtdWx0aSBzaWcgcHVibGljIGtleXMnKTtcbiAgcmV0dXJuIG9yZGVyO1xufVxuXG4vKipcbiAqIEV4dHJhY3RzIG11bHRpLXNpZyBpbnB1dCBkYXRhLCBpbmNsdWRpbmcgc2NyaXB0IHR5cGUsIHNjcmlwdCBwdWJsaWMga2V5LCBhbmQgZGVyaXZhdGlvbiBwYXRoLCBmcm9tIHRoZSBmaXJzdCByZWxldmFudCBQU0JUIGlucHV0LlxuICogQHBhcmFtIHBzYnQgLSBUaGUgUFNCVCB0byBleHRyYWN0IGRhdGEgZnJvbS5cbiAqIEByZXR1cm5zIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBwYXJzZWQgc2NyaXB0IHR5cGUsIHNjcmlwdCBwdWJsaWMga2V5LCBhbmQgZGVyaXZhdGlvbiBwYXRoLlxuICovXG5mdW5jdGlvbiBnZXRGaXJzdE11bHRpU2lnSW5wdXREYXRhKHBzYnQ6IFV0eG9Qc2J0KToge1xuICBwYXJzZWRTY3JpcHRUeXBlOiBQYXJzZWRTY3JpcHRUeXBlMk9mMztcbiAgc2NyaXB0UHViS2V5OiBCdWZmZXI7XG4gIGRlcml2YXRpb25QYXRoOiBzdHJpbmc7XG59IHtcbiAgZnVuY3Rpb24gZ2V0U2NyaXB0UHViS2V5KGlucHV0OiBQc2J0SW5wdXQsIHByZXZPdXRJbmRleDogbnVtYmVyKSB7XG4gICAgY29uc3Qgc2NyaXB0UHViS2V5ID1cbiAgICAgIGlucHV0LndpdG5lc3NVdHhvPy5zY3JpcHQgPz9cbiAgICAgIChpbnB1dC5ub25XaXRuZXNzVXR4b1xuICAgICAgICA/IGNyZWF0ZVRyYW5zYWN0aW9uRnJvbUJ1ZmZlcihpbnB1dC5ub25XaXRuZXNzVXR4bywgcHNidC5uZXR3b3JrLCB7IGFtb3VudFR5cGU6ICdiaWdpbnQnIH0pLm91dHNbcHJldk91dEluZGV4XVxuICAgICAgICAgICAgLnNjcmlwdFxuICAgICAgICA6IHVuZGVmaW5lZCk7XG4gICAgYXNzZXJ0KHNjcmlwdFB1YktleSwgJ0lucHV0IHNjcmlwdFB1YktleSBjYW4gbm90IGJlIGZvdW5kJyk7XG4gICAgcmV0dXJuIHNjcmlwdFB1YktleTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGdldERlcml2YXRpb25QYXRoKGlucHV0OiBQc2J0SW5wdXQpIHtcbiAgICBjb25zdCBiaXAzMkR2ID0gaW5wdXQ/LmJpcDMyRGVyaXZhdGlvbiA/PyBpbnB1dD8udGFwQmlwMzJEZXJpdmF0aW9uO1xuICAgIGFzc2VydChiaXAzMkR2Py5sZW5ndGgsICdJbnB1dCBCaXAzMkRlcml2YXRpb24gY2FuIG5vdCBiZSBmb3VuZCcpO1xuICAgIHJldHVybiBiaXAzMkR2WzBdLnBhdGg7XG4gIH1cblxuICBjb25zdCB0eElucHV0cyA9IHBzYnQudHhJbnB1dHM7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBwc2J0LmRhdGEuaW5wdXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgaW5wdXQgPSBwc2J0LmRhdGEuaW5wdXRzW2ldO1xuICAgIGNvbnN0IHBhcnNlZFNjcmlwdFR5cGUgPSBnZXRQc2J0SW5wdXRTY3JpcHRUeXBlKGlucHV0KTtcbiAgICBpZiAocGFyc2VkU2NyaXB0VHlwZSA9PT0gJ3Ayc2hQMnBrJykge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IHNjcmlwdFB1YktleSA9IGdldFNjcmlwdFB1YktleShpbnB1dCwgdHhJbnB1dHNbaV0uaW5kZXgpO1xuICAgIGNvbnN0IGRlcml2YXRpb25QYXRoID0gZ2V0RGVyaXZhdGlvblBhdGgoaW5wdXQpO1xuICAgIHJldHVybiB7IHBhcnNlZFNjcmlwdFR5cGUsIHNjcmlwdFB1YktleSwgZGVyaXZhdGlvblBhdGggfTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvck5vTXVsdGlTaWdJbnB1dEZvdW5kKCdObyBtdWx0aSBzaWcgaW5wdXQgZm91bmQnKTtcbn1cblxuLyoqXG4gKiBTb3J0cyBnaXZlbiByb290IG5vZGVzIGJhc2VkIG9uIHRoZSBzY3JpcHQgY29tcGF0aWJpbGl0eSB3aXRoIHRoZSBQU0JUJ3MgbXVsdGktc2lnIGlucHV0cy5cbiAqIEBwYXJhbSBwc2J0IC0gVGhlIFBTQlQgY29udGFpbmluZyBtdWx0aS1zaWcgaW5wdXRzLlxuICogQHBhcmFtIHJvb3ROb2RlcyAtIEFycmF5IG9mIHJvb3Qgbm9kZXMgdG8gc29ydC5cbiAqIEByZXR1cm5zIEFuIGFycmF5IG9mIEJJUDMySW50ZXJmYWNlIG9iamVjdHMgaW4gdGhlIG9yZGVyIHRoYXQgbWF0Y2hlcyB0aGUgbXVsdGktc2lnIHNjcmlwdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNvcnRSb290Tm9kZXMocHNidDogVXR4b1BzYnQsIHJvb3ROb2RlczogVHJpcGxlPEJJUDMySW50ZXJmYWNlPik6IFRyaXBsZTxCSVAzMkludGVyZmFjZT4ge1xuICBjb25zdCB7IHBhcnNlZFNjcmlwdFR5cGUsIHNjcmlwdFB1YktleSwgZGVyaXZhdGlvblBhdGggfSA9IGdldEZpcnN0TXVsdGlTaWdJbnB1dERhdGEocHNidCk7XG4gIGNvbnN0IHB1YktleXMgPSByb290Tm9kZXMubWFwKChyb290Tm9kZSkgPT4gcm9vdE5vZGUuZGVyaXZlUGF0aChkZXJpdmF0aW9uUGF0aCkucHVibGljS2V5KSBhcyBUcmlwbGU8QnVmZmVyPjtcbiAgY29uc3Qgb3JkZXIgPSBmaW5kU29ydE9yZGVyT2ZQdWJLZXlzKHB1YktleXMsIHNjcmlwdFB1YktleSwgcGFyc2VkU2NyaXB0VHlwZSwgcHNidC5uZXR3b3JrKTtcbiAgcmV0dXJuIG9yZGVyLm1hcCgoaSkgPT4gcm9vdE5vZGVzW2ldKSBhcyBUcmlwbGU8QklQMzJJbnRlcmZhY2U+O1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBzb3J0ZWQgcm9vdCBub2RlcyBmcm9tIGEgUFNCVCwgZW5zdXJpbmcgdGhleSBhcmUgb3JkZXJlZCBhY2NvcmRpbmcgdG8gc2NyaXB0IGNvbXBhdGliaWxpdHkuXG4gKiBAcGFyYW0gcHNidCAtIFRoZSBQU0JUIHRvIGV4dHJhY3QgYW5kIHNvcnQgcm9vdCBub2RlcyBmcm9tLlxuICogQHJldHVybnMgQW4gYXJyYXkgb2Ygc29ydGVkIEJJUDMySW50ZXJmYWNlIHJvb3Qgbm9kZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTb3J0ZWRSb290Tm9kZXMocHNidDogVXR4b1BzYnQpOiBUcmlwbGU8QklQMzJJbnRlcmZhY2U+IHtcbiAgY29uc3QgdW5zb3J0ZWRSb290Tm9kZXMgPSBnZXRVbnNvcnRlZFJvb3ROb2Rlcyhwc2J0KTtcbiAgYXNzZXJ0KHVuc29ydGVkUm9vdE5vZGVzLCAnQ291bGQgbm90IGZpbmQgcm9vdCBub2RlcyBpbiBQU0JUJyk7XG4gIHJldHVybiBzb3J0Um9vdE5vZGVzKHBzYnQsIHVuc29ydGVkUm9vdE5vZGVzKTtcbn1cbiJdfQ==