@bitgo/utxo-lib
Version:
Client-side Bitcoin JavaScript library
323 lines • 42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.scriptTypes2Of3 = exports.scriptTypeP2shP2pk = exports.scriptTypeForChain = void 0;
exports.isScriptType2Of3 = isScriptType2Of3;
exports.hasWitnessData = hasWitnessData;
exports.isSupportedScriptType = isSupportedScriptType;
exports.scriptType2Of3AsPrevOutType = scriptType2Of3AsPrevOutType;
exports.createOutputScriptP2shP2pk = createOutputScriptP2shP2pk;
exports.getOutputScript = getOutputScript;
exports.createOutputScript2of3 = createOutputScript2of3;
exports.toXOnlyPublicKey = toXOnlyPublicKey;
exports.checkXOnlyPublicKey = checkXOnlyPublicKey;
exports.checkPlainPublicKey = checkPlainPublicKey;
exports.checkTapMerkleRoot = checkTapMerkleRoot;
exports.checkTxHash = checkTxHash;
exports.createPaymentP2trCommon = createPaymentP2trCommon;
exports.createPaymentP2tr = createPaymentP2tr;
exports.createPaymentP2trMusig2 = createPaymentP2trMusig2;
exports.getLeafHash = getLeafHash;
exports.createKeyPathP2trMusig2 = createKeyPathP2trMusig2;
exports.createSpendScriptP2tr = createSpendScriptP2tr;
exports.createSpendScriptP2trMusig2 = createSpendScriptP2trMusig2;
const assert_1 = require("assert");
const bitcoinjs = require("bitcoinjs-lib");
const networks_1 = require("../networks");
const p2trPayments = require("../payments");
const taproot = require("../taproot");
const types_1 = require("./types");
const secp256k1_1 = require("@bitgo/secp256k1");
const taproot_1 = require("../taproot");
var chains_1 = require("./wallet/chains");
Object.defineProperty(exports, "scriptTypeForChain", { enumerable: true, get: function () { return chains_1.scriptTypeForChain; } });
exports.scriptTypeP2shP2pk = 'p2shP2pk';
exports.scriptTypes2Of3 = ['p2sh', 'p2shP2wsh', 'p2wsh', 'p2tr', 'p2trMusig2'];
function isScriptType2Of3(t) {
return exports.scriptTypes2Of3.includes(t);
}
/**
* @return true iff scriptType requires witness data
*/
function hasWitnessData(scriptType) {
return ['p2shP2wsh', 'p2wsh', 'p2tr', 'p2trMusig2'].includes(scriptType);
}
/**
* @param network
* @param scriptType
* @return true iff script type is supported for network
*/
function isSupportedScriptType(network, scriptType) {
switch (scriptType) {
case 'p2sh':
case 'p2shP2pk':
return true;
case 'p2shP2wsh':
case 'p2wsh':
return (0, networks_1.supportsSegwit)(network);
case 'p2tr':
case 'p2trMusig2':
return (0, networks_1.supportsTaproot)(network);
}
/* istanbul ignore next */
throw new Error(`unexpected script type ${scriptType}`);
}
/**
* @param t
* @return string prevOut as defined in PREVOUT_TYPES (bitcoinjs-lib/.../transaction_builder.js)
*/
function scriptType2Of3AsPrevOutType(t) {
switch (t) {
case 'p2sh':
return 'p2sh-p2ms';
case 'p2shP2wsh':
return 'p2sh-p2wsh-p2ms';
case 'p2wsh':
return 'p2wsh-p2ms';
case 'p2tr':
return 'p2tr-p2ns';
case 'p2trMusig2':
return 'p2tr';
}
/* istanbul ignore next */
throw new Error(`unsupported script type ${t}`);
}
/**
* Return scripts for p2sh-p2pk (used for BCH/BSV replay protection)
* @param pubkey
*/
function createOutputScriptP2shP2pk(pubkey) {
const p2pk = bitcoinjs.payments.p2pk({ pubkey });
const p2sh = bitcoinjs.payments.p2sh({ redeem: p2pk });
if (!p2sh.output || !p2pk.output) {
throw new Error(`invalid state`);
}
return {
scriptPubKey: p2sh.output,
redeemScript: p2pk.output,
};
}
function getOutputScript(scriptType, conditionScript) {
let output;
switch (scriptType) {
case 'p2sh':
({ output } = bitcoinjs.payments.p2sh({ redeem: { output: conditionScript } }));
break;
case 'p2shP2wsh':
({ output } = bitcoinjs.payments.p2sh({
redeem: { output: getOutputScript('p2wsh', conditionScript) },
}));
break;
case 'p2wsh':
({ output } = bitcoinjs.payments.p2wsh({ redeem: { output: conditionScript } }));
break;
}
if (output === undefined) {
throw new Error(`output undefined`);
}
return output;
}
/**
* Return scripts for 2-of-3 multisig output
* @param pubkeys - the key triple for multisig
* @param scriptType
* @param network - if set, performs sanity check for scriptType support
* @returns {{redeemScript, witnessScript, scriptPubKey}}
*/
function createOutputScript2of3(pubkeys, scriptType, network) {
if (network) {
if (!isSupportedScriptType(network, scriptType)) {
throw new Error(`unsupported script type ${scriptType} for network`);
}
}
if (!(0, types_1.isTriple)(pubkeys)) {
throw new Error(`must provide pubkey triple`);
}
pubkeys.forEach((key) => {
if (key.length !== 33) {
throw new Error(`Unexpected key length ${key.length}. Must use compressed keys.`);
}
});
if (scriptType === 'p2tr' || scriptType === 'p2trMusig2') {
// p2tr/p2trMusig2 addresses use a combination of 2 of 2 multisig scripts distinct from
// the 2 of 3 multisig used for other script types
return createTaprootScript2of3(scriptType, pubkeys);
}
const script2of3 = bitcoinjs.payments.p2ms({ m: 2, pubkeys });
(0, assert_1.ok)(script2of3.output);
let redeemScript;
let witnessScript;
switch (scriptType) {
case 'p2sh':
redeemScript = script2of3;
break;
case 'p2shP2wsh':
witnessScript = script2of3;
redeemScript = bitcoinjs.payments.p2wsh({ redeem: script2of3 });
break;
case 'p2wsh':
witnessScript = script2of3;
break;
default:
throw new Error(`unknown multisig script type ${scriptType}`);
}
return {
scriptPubKey: getOutputScript(scriptType, script2of3.output),
redeemScript: redeemScript?.output,
witnessScript: witnessScript?.output,
};
}
function toXOnlyPublicKey(b) {
if (b.length === 33) {
return b.slice(1);
}
if (b.length === 32) {
return b;
}
throw new Error(`invalid key size ${b.length}`);
}
function checkSize(b, targetSize, name) {
if (b.length === targetSize) {
return b;
}
throw new Error(`invalid size ${b.length}. Must use ${name}.`);
}
/**
* Validates size of the pub key for 32 bytes and returns the same iff true.
*/
function checkXOnlyPublicKey(b) {
return checkSize(b, 32, 'x-only key');
}
/**
* Validates size of the pub key for 32 bytes and returns the same iff true.
*/
function checkPlainPublicKey(b) {
return checkSize(b, 33, 'plain key');
}
function checkTapMerkleRoot(b) {
return checkSize(b, 32, 'tap merkle root');
}
function checkTxHash(b) {
return checkSize(b, 32, 'tx hash');
}
function getTaptreeKeyCombinations(scriptType, keys) {
const [userKey, backupKey, bitGoKey] = keys.map((k) => toXOnlyPublicKey(k));
return scriptType === 'p2tr'
? [
[userKey, bitGoKey],
[userKey, backupKey],
[backupKey, bitGoKey],
]
: [
[userKey, backupKey],
[backupKey, bitGoKey],
];
}
function getKeyPathCombination(scriptType, keys) {
const sanitizePublicKey = scriptType === 'p2tr' ? toXOnlyPublicKey : checkPlainPublicKey;
return [sanitizePublicKey(keys[0]), sanitizePublicKey(keys[2])];
}
function getRedeemIndex(keyCombinations, signer, cosigner) {
signer = toXOnlyPublicKey(signer);
cosigner = toXOnlyPublicKey(cosigner);
const i = keyCombinations.findIndex(([a, b]) => {
if (a.length !== signer.length || b.length !== cosigner.length) {
throw new Error(`invalid comparison`);
}
return (a.equals(signer) && b.equals(cosigner)) || (a.equals(cosigner) && b.equals(signer));
});
if (0 <= i) {
return i;
}
throw new Error(`could not find singer/cosigner combination`);
}
function createPaymentP2trCommon(scriptType, pubkeys, redeemIndex) {
const keyCombinations2of2 = getTaptreeKeyCombinations(scriptType, pubkeys);
if (typeof redeemIndex === 'object') {
redeemIndex = getRedeemIndex(keyCombinations2of2, redeemIndex.signer, redeemIndex.cosigner);
}
const redeems = keyCombinations2of2.map((pubkeys, index) => p2trPayments.p2tr_ns({
pubkeys,
depth: scriptType === 'p2trMusig2' || index === 0 ? 1 : 2,
}, { eccLib: secp256k1_1.ecc }));
return p2trPayments.p2tr({
pubkeys: getKeyPathCombination(scriptType, pubkeys),
redeems,
redeemIndex,
}, { eccLib: secp256k1_1.ecc });
}
function createPaymentP2tr(pubkeys, redeemIndex) {
return createPaymentP2trCommon('p2tr', pubkeys, redeemIndex);
}
function createPaymentP2trMusig2(pubkeys, redeemIndex) {
return createPaymentP2trCommon('p2trMusig2', pubkeys, redeemIndex);
}
function getLeafHashCommon(scriptType, params) {
if ('publicKeys' in params) {
params = createPaymentP2trCommon(scriptType, params.publicKeys, params);
}
const { output, controlBlock, redeem } = params;
if (!output || !controlBlock || !redeem || !redeem.output) {
throw new Error(`invalid state`);
}
return taproot.getTapleafHash(secp256k1_1.ecc, controlBlock, redeem.output);
}
function getLeafHash(params) {
return getLeafHashCommon('p2tr', params);
}
function createKeyPathP2trMusig2(pubkeys) {
const payment = createPaymentP2trCommon('p2trMusig2', pubkeys);
(0, assert_1.ok)(payment.internalPubkey);
(0, assert_1.ok)(payment.tapTree);
return {
internalPubkey: payment.internalPubkey,
outputPubkey: (0, taproot_1.getTweakedOutputKey)(payment),
taptreeRoot: (0, taproot_1.getDepthFirstTaptree)(payment.tapTree).root,
};
}
function createSpendScriptP2trCommon(scriptType, pubkeys, keyCombination) {
const keyCombinations = getTaptreeKeyCombinations(scriptType, pubkeys);
const [a, b] = keyCombination.map((k) => toXOnlyPublicKey(k));
const redeemIndex = keyCombinations.findIndex(([c, d]) => (a.equals(c) && b.equals(d)) || (a.equals(d) && b.equals(c)));
if (redeemIndex < 0) {
throw new Error(`could not find redeemIndex for key combination`);
}
const payment = createPaymentP2trCommon(scriptType, pubkeys, redeemIndex);
const { controlBlock } = payment;
(0, assert_1.ok)(Buffer.isBuffer(controlBlock));
(0, assert_1.ok)(payment.redeem);
const leafScript = payment.redeem.output;
(0, assert_1.ok)(Buffer.isBuffer(leafScript));
const parsedControlBlock = taproot.parseControlBlock(secp256k1_1.ecc, controlBlock);
const { leafVersion } = parsedControlBlock;
const leafHash = taproot.getTapleafHash(secp256k1_1.ecc, parsedControlBlock, leafScript);
return {
controlBlock,
witnessScript: leafScript,
leafVersion,
leafHash,
};
}
function createSpendScriptP2tr(pubkeys, keyCombination) {
return createSpendScriptP2trCommon('p2tr', pubkeys, keyCombination);
}
function createSpendScriptP2trMusig2(pubkeys, keyCombination) {
return createSpendScriptP2trCommon('p2trMusig2', pubkeys, keyCombination);
}
/**
* Creates and returns a taproot output script using the user+bitgo keys for the aggregate
* public key using MuSig2 and a taptree containing either of the following depends on scriptType.
* p2tr type: a user+bitgo 2-of-2 script at the first depth level of the tree and user+backup
* and bitgo+backup 2-of-2 scripts one level deeper.
* p2trMusig2 type: user+backup and bitgo+backup 2-of-2 scripts at the first depth level of the
* tree.
* @param pubkeys - a pubkey array containing the user key, backup key, and bitgo key in that order
* @returns {{scriptPubKey}}
*/
function createTaprootScript2of3(scriptType, pubkeys) {
const { output } = createPaymentP2trCommon(scriptType, pubkeys);
(0, assert_1.ok)(Buffer.isBuffer(output));
return {
scriptPubKey: output,
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0cHV0U2NyaXB0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iaXRnby9vdXRwdXRTY3JpcHRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQW9CQSw0Q0FFQztBQU9ELHdDQUVDO0FBT0Qsc0RBZUM7QUFNRCxrRUFnQkM7QUE0QkQsZ0VBVUM7QUFFRCwwQ0FtQkM7QUFTRCx3REFvREM7QUFFRCw0Q0FRQztBQVlELGtEQUVDO0FBS0Qsa0RBRUM7QUFFRCxnREFFQztBQUVELGtDQUVDO0FBb0NELDBEQTJCQztBQUVELDhDQUtDO0FBRUQsMERBS0M7QUFnQkQsa0NBSUM7QUFFRCwwREFTQztBQXFDRCxzREFFQztBQUVELGtFQUVDO0FBallELG1DQUFzQztBQUN0QywyQ0FBMkM7QUFFM0MsMENBQXVFO0FBQ3ZFLDRDQUE0QztBQUM1QyxzQ0FBc0M7QUFFdEMsbUNBQWtEO0FBRWxELGdEQUFpRDtBQUNqRCx3Q0FBdUU7QUFFdkUsMENBQXFEO0FBQTVDLDRHQUFBLGtCQUFrQixPQUFBO0FBRWQsUUFBQSxrQkFBa0IsR0FBRyxVQUFVLENBQUM7QUFHaEMsUUFBQSxlQUFlLEdBQUcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsWUFBWSxDQUFVLENBQUM7QUFHN0YsU0FBZ0IsZ0JBQWdCLENBQUMsQ0FBUztJQUN4QyxPQUFPLHVCQUFlLENBQUMsUUFBUSxDQUFDLENBQW1CLENBQUMsQ0FBQztBQUN2RCxDQUFDO0FBSUQ7O0dBRUc7QUFDSCxTQUFnQixjQUFjLENBQUMsVUFBc0I7SUFDbkQsT0FBTyxDQUFDLFdBQVcsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLFlBQVksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUMzRSxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLHFCQUFxQixDQUFDLE9BQWdCLEVBQUUsVUFBc0I7SUFDNUUsUUFBUSxVQUFVLEVBQUUsQ0FBQztRQUNuQixLQUFLLE1BQU0sQ0FBQztRQUNaLEtBQUssVUFBVTtZQUNiLE9BQU8sSUFBSSxDQUFDO1FBQ2QsS0FBSyxXQUFXLENBQUM7UUFDakIsS0FBSyxPQUFPO1lBQ1YsT0FBTyxJQUFBLHlCQUFjLEVBQUMsT0FBTyxDQUFDLENBQUM7UUFDakMsS0FBSyxNQUFNLENBQUM7UUFDWixLQUFLLFlBQVk7WUFDZixPQUFPLElBQUEsMEJBQWUsRUFBQyxPQUFPLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQsMEJBQTBCO0lBQzFCLE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLFVBQVUsRUFBRSxDQUFDLENBQUM7QUFDMUQsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLDJCQUEyQixDQUFDLENBQWlCO0lBQzNELFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDVixLQUFLLE1BQU07WUFDVCxPQUFPLFdBQVcsQ0FBQztRQUNyQixLQUFLLFdBQVc7WUFDZCxPQUFPLGlCQUFpQixDQUFDO1FBQzNCLEtBQUssT0FBTztZQUNWLE9BQU8sWUFBWSxDQUFDO1FBQ3RCLEtBQUssTUFBTTtZQUNULE9BQU8sV0FBVyxDQUFDO1FBQ3JCLEtBQUssWUFBWTtZQUNmLE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFFRCwwQkFBMEI7SUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUNsRCxDQUFDO0FBd0JEOzs7R0FHRztBQUNILFNBQWdCLDBCQUEwQixDQUFDLE1BQWM7SUFDdkQsTUFBTSxJQUFJLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ2pELE1BQU0sSUFBSSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdkQsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDakMsTUFBTSxJQUFJLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBQ0QsT0FBTztRQUNMLFlBQVksRUFBRSxJQUFJLENBQUMsTUFBTTtRQUN6QixZQUFZLEVBQUUsSUFBSSxDQUFDLE1BQU07S0FDMUIsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixlQUFlLENBQUMsVUFBMEMsRUFBRSxlQUF1QjtJQUNqRyxJQUFJLE1BQU0sQ0FBQztJQUNYLFFBQVEsVUFBVSxFQUFFLENBQUM7UUFDbkIsS0FBSyxNQUFNO1lBQ1QsQ0FBQyxFQUFFLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ2hGLE1BQU07UUFDUixLQUFLLFdBQVc7WUFDZCxDQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ3BDLE1BQU0sRUFBRSxFQUFFLE1BQU0sRUFBRSxlQUFlLENBQUMsT0FBTyxFQUFFLGVBQWUsQ0FBQyxFQUFFO2FBQzlELENBQUMsQ0FBQyxDQUFDO1lBQ0osTUFBTTtRQUNSLEtBQUssT0FBTztZQUNWLENBQUMsRUFBRSxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLE1BQU0sRUFBRSxlQUFlLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNqRixNQUFNO0lBQ1YsQ0FBQztJQUNELElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQWdCLHNCQUFzQixDQUNwQyxPQUFpQixFQUNqQixVQUEwQixFQUMxQixPQUFpQjtJQUVqQixJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQ1osSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ2hELE1BQU0sSUFBSSxLQUFLLENBQUMsMkJBQTJCLFVBQVUsY0FBYyxDQUFDLENBQUM7UUFDdkUsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLENBQUMsSUFBQSxnQkFBUSxFQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRCxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7UUFDdEIsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLEVBQUUsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLEdBQUcsQ0FBQyxNQUFNLDZCQUE2QixDQUFDLENBQUM7UUFDcEYsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBSSxVQUFVLEtBQUssTUFBTSxJQUFJLFVBQVUsS0FBSyxZQUFZLEVBQUUsQ0FBQztRQUN6RCx1RkFBdUY7UUFDdkYsa0RBQWtEO1FBQ2xELE9BQU8sdUJBQXVCLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFRCxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUM5RCxJQUFBLFdBQU0sRUFBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFMUIsSUFBSSxZQUEyQyxDQUFDO0lBQ2hELElBQUksYUFBNEMsQ0FBQztJQUNqRCxRQUFRLFVBQVUsRUFBRSxDQUFDO1FBQ25CLEtBQUssTUFBTTtZQUNULFlBQVksR0FBRyxVQUFVLENBQUM7WUFDMUIsTUFBTTtRQUNSLEtBQUssV0FBVztZQUNkLGFBQWEsR0FBRyxVQUFVLENBQUM7WUFDM0IsWUFBWSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7WUFDaEUsTUFBTTtRQUNSLEtBQUssT0FBTztZQUNWLGFBQWEsR0FBRyxVQUFVLENBQUM7WUFDM0IsTUFBTTtRQUNSO1lBQ0UsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBRUQsT0FBTztRQUNMLFlBQVksRUFBRSxlQUFlLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxNQUFNLENBQUM7UUFDNUQsWUFBWSxFQUFFLFlBQVksRUFBRSxNQUFNO1FBQ2xDLGFBQWEsRUFBRSxhQUFhLEVBQUUsTUFBTTtLQUNyQyxDQUFDO0FBQ0osQ0FBQztBQUVELFNBQWdCLGdCQUFnQixDQUFDLENBQVM7SUFDeEMsSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwQixDQUFDO0lBQ0QsSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0FBQ2xELENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxDQUFTLEVBQUUsVUFBa0IsRUFBRSxJQUFZO0lBQzVELElBQUksQ0FBQyxDQUFDLE1BQU0sS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUM1QixPQUFPLENBQUMsQ0FBQztJQUNYLENBQUM7SUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLGdCQUFnQixDQUFDLENBQUMsTUFBTSxjQUFjLElBQUksR0FBRyxDQUFDLENBQUM7QUFDakUsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQUMsQ0FBUztJQUMzQyxPQUFPLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLFlBQVksQ0FBQyxDQUFDO0FBQ3hDLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLG1CQUFtQixDQUFDLENBQVM7SUFDM0MsT0FBTyxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxXQUFXLENBQUMsQ0FBQztBQUN2QyxDQUFDO0FBRUQsU0FBZ0Isa0JBQWtCLENBQUMsQ0FBUztJQUMxQyxPQUFPLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLGlCQUFpQixDQUFDLENBQUM7QUFDN0MsQ0FBQztBQUVELFNBQWdCLFdBQVcsQ0FBQyxDQUFTO0lBQ25DLE9BQU8sU0FBUyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFDckMsQ0FBQztBQUVELFNBQVMseUJBQXlCLENBQUMsVUFBaUMsRUFBRSxJQUFvQjtJQUN4RixNQUFNLENBQUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzVFLE9BQU8sVUFBVSxLQUFLLE1BQU07UUFDMUIsQ0FBQyxDQUFDO1lBQ0UsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDO1lBQ25CLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQztZQUNwQixDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUM7U0FDdEI7UUFDSCxDQUFDLENBQUM7WUFDRSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUM7WUFDcEIsQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDO1NBQ3RCLENBQUM7QUFDUixDQUFDO0FBRUQsU0FBUyxxQkFBcUIsQ0FBQyxVQUFpQyxFQUFFLElBQW9CO0lBQ3BGLE1BQU0saUJBQWlCLEdBQUcsVUFBVSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLG1CQUFtQixDQUFDO0lBQ3pGLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2xFLENBQUM7QUFFRCxTQUFTLGNBQWMsQ0FBQyxlQUFtQyxFQUFFLE1BQWMsRUFBRSxRQUFnQjtJQUMzRixNQUFNLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbEMsUUFBUSxHQUFHLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3RDLE1BQU0sQ0FBQyxHQUFHLGVBQWUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFO1FBQzdDLElBQUksQ0FBQyxDQUFDLE1BQU0sS0FBSyxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxNQUFNLEtBQUssUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQy9ELE1BQU0sSUFBSSxLQUFLLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUN4QyxDQUFDO1FBQ0QsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDOUYsQ0FBQyxDQUFDLENBQUM7SUFDSCxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNYLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsNENBQTRDLENBQUMsQ0FBQztBQUNoRSxDQUFDO0FBRUQsU0FBZ0IsdUJBQXVCLENBQ3JDLFVBQWlDLEVBQ2pDLE9BQXVCLEVBQ3ZCLFdBQTJEO0lBRTNELE1BQU0sbUJBQW1CLEdBQUcseUJBQXlCLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzNFLElBQUksT0FBTyxXQUFXLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDcEMsV0FBVyxHQUFHLGNBQWMsQ0FBQyxtQkFBbUIsRUFBRSxXQUFXLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5RixDQUFDO0lBQ0QsTUFBTSxPQUFPLEdBQUcsbUJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQ3pELFlBQVksQ0FBQyxPQUFPLENBQ2xCO1FBQ0UsT0FBTztRQUNQLEtBQUssRUFBRSxVQUFVLEtBQUssWUFBWSxJQUFJLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUMxRCxFQUNELEVBQUUsTUFBTSxFQUFOLGVBQU0sRUFBRSxDQUNYLENBQ0YsQ0FBQztJQUVGLE9BQU8sWUFBWSxDQUFDLElBQUksQ0FDdEI7UUFDRSxPQUFPLEVBQUUscUJBQXFCLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQztRQUNuRCxPQUFPO1FBQ1AsV0FBVztLQUNaLEVBQ0QsRUFBRSxNQUFNLEVBQU4sZUFBTSxFQUFFLENBQ1gsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixpQkFBaUIsQ0FDL0IsT0FBdUIsRUFDdkIsV0FBMkQ7SUFFM0QsT0FBTyx1QkFBdUIsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQy9ELENBQUM7QUFFRCxTQUFnQix1QkFBdUIsQ0FDckMsT0FBdUIsRUFDdkIsV0FBMkQ7SUFFM0QsT0FBTyx1QkFBdUIsQ0FBQyxZQUFZLEVBQUUsT0FBTyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQ3JFLENBQUM7QUFFRCxTQUFTLGlCQUFpQixDQUN4QixVQUFpQyxFQUNqQyxNQUE0RjtJQUU1RixJQUFJLFlBQVksSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUMzQixNQUFNLEdBQUcsdUJBQXVCLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDMUUsQ0FBQztJQUNELE1BQU0sRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUNoRCxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsWUFBWSxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQzFELE1BQU0sSUFBSSxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUNELE9BQU8sT0FBTyxDQUFDLGNBQWMsQ0FBQyxlQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUNyRSxDQUFDO0FBRUQsU0FBZ0IsV0FBVyxDQUN6QixNQUE0RjtJQUU1RixPQUFPLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztBQUMzQyxDQUFDO0FBRUQsU0FBZ0IsdUJBQXVCLENBQUMsT0FBdUI7SUFDN0QsTUFBTSxPQUFPLEdBQUcsdUJBQXVCLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQy9ELElBQUEsV0FBTSxFQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUMvQixJQUFBLFdBQU0sRUFBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDeEIsT0FBTztRQUNMLGNBQWMsRUFBRSxPQUFPLENBQUMsY0FBYztRQUN0QyxZQUFZLEVBQUUsSUFBQSw2QkFBbUIsRUFBQyxPQUFPLENBQUM7UUFDMUMsV0FBVyxFQUFFLElBQUEsOEJBQW9CLEVBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUk7S0FDeEQsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLDJCQUEyQixDQUNsQyxVQUFpQyxFQUNqQyxPQUF1QixFQUN2QixjQUE2QjtJQUU3QixNQUFNLGVBQWUsR0FBRyx5QkFBeUIsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDdkUsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzlELE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQyxTQUFTLENBQzNDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDekUsQ0FBQztJQUVGLElBQUksV0FBVyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3BCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsdUJBQXVCLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQztJQUMxRSxNQUFNLEVBQUUsWUFBWSxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBQ2pDLElBQUEsV0FBTSxFQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQztJQUV0QyxJQUFBLFdBQU0sRUFBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDdkIsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDekMsSUFBQSxXQUFNLEVBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBRXBDLE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUFDLGVBQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztJQUMzRSxNQUFNLEVBQUUsV0FBVyxFQUFFLEdBQUcsa0JBQWtCLENBQUM7SUFDM0MsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQyxlQUFNLEVBQUUsa0JBQWtCLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFFaEYsT0FBTztRQUNMLFlBQVk7UUFDWixhQUFhLEVBQUUsVUFBVTtRQUN6QixXQUFXO1FBQ1gsUUFBUTtLQUNULENBQUM7QUFDSixDQUFDO0FBRUQsU0FBZ0IscUJBQXFCLENBQUMsT0FBdUIsRUFBRSxjQUE2QjtJQUMxRixPQUFPLDJCQUEyQixDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFDdEUsQ0FBQztBQUVELFNBQWdCLDJCQUEyQixDQUFDLE9BQXVCLEVBQUUsY0FBNkI7SUFDaEcsT0FBTywyQkFBMkIsQ0FBQyxZQUFZLEVBQUUsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDO0FBQzVFLENBQUM7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCxTQUFTLHVCQUF1QixDQUFDLFVBQWlDLEVBQUUsT0FBdUI7SUFDekYsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLHVCQUF1QixDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNoRSxJQUFBLFdBQU0sRUFBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEMsT0FBTztRQUNMLFlBQVksRUFBRSxNQUFNO0tBQ3JCLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgb2sgYXMgYXNzZXJ0IH0gZnJvbSAnYXNzZXJ0JztcbmltcG9ydCAqIGFzIGJpdGNvaW5qcyBmcm9tICdiaXRjb2luanMtbGliJztcblxuaW1wb3J0IHsgTmV0d29yaywgc3VwcG9ydHNTZWd3aXQsIHN1cHBvcnRzVGFwcm9vdCB9IGZyb20gJy4uL25ldHdvcmtzJztcbmltcG9ydCAqIGFzIHAydHJQYXltZW50cyBmcm9tICcuLi9wYXltZW50cyc7XG5pbXBvcnQgKiBhcyB0YXByb290IGZyb20gJy4uL3RhcHJvb3QnO1xuXG5pbXBvcnQgeyBpc1RyaXBsZSwgVHJpcGxlLCBUdXBsZSB9IGZyb20gJy4vdHlwZXMnO1xuXG5pbXBvcnQgeyBlY2MgYXMgZWNjTGliIH0gZnJvbSAnQGJpdGdvL3NlY3AyNTZrMSc7XG5pbXBvcnQgeyBnZXREZXB0aEZpcnN0VGFwdHJlZSwgZ2V0VHdlYWtlZE91dHB1dEtleSB9IGZyb20gJy4uL3RhcHJvb3QnO1xuXG5leHBvcnQgeyBzY3JpcHRUeXBlRm9yQ2hhaW4gfSBmcm9tICcuL3dhbGxldC9jaGFpbnMnO1xuXG5leHBvcnQgY29uc3Qgc2NyaXB0VHlwZVAyc2hQMnBrID0gJ3Ayc2hQMnBrJztcbmV4cG9ydCB0eXBlIFNjcmlwdFR5cGVQMnNoUDJwayA9IHR5cGVvZiBzY3JpcHRUeXBlUDJzaFAycGs7XG5cbmV4cG9ydCBjb25zdCBzY3JpcHRUeXBlczJPZjMgPSBbJ3Ayc2gnLCAncDJzaFAyd3NoJywgJ3Ayd3NoJywgJ3AydHInLCAncDJ0ck11c2lnMiddIGFzIGNvbnN0O1xuZXhwb3J0IHR5cGUgU2NyaXB0VHlwZTJPZjMgPSAodHlwZW9mIHNjcmlwdFR5cGVzMk9mMylbbnVtYmVyXTtcblxuZXhwb3J0IGZ1bmN0aW9uIGlzU2NyaXB0VHlwZTJPZjModDogc3RyaW5nKTogdCBpcyBTY3JpcHRUeXBlMk9mMyB7XG4gIHJldHVybiBzY3JpcHRUeXBlczJPZjMuaW5jbHVkZXModCBhcyBTY3JpcHRUeXBlMk9mMyk7XG59XG5cbmV4cG9ydCB0eXBlIFNjcmlwdFR5cGUgPSBTY3JpcHRUeXBlUDJzaFAycGsgfCBTY3JpcHRUeXBlMk9mMztcblxuLyoqXG4gKiBAcmV0dXJuIHRydWUgaWZmIHNjcmlwdFR5cGUgcmVxdWlyZXMgd2l0bmVzcyBkYXRhXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNXaXRuZXNzRGF0YShzY3JpcHRUeXBlOiBTY3JpcHRUeXBlKTogc2NyaXB0VHlwZSBpcyAncDJzaFAyd3NoJyB8ICdwMndzaCcgfCAncDJ0cicgfCAncDJ0ck11c2lnMicge1xuICByZXR1cm4gWydwMnNoUDJ3c2gnLCAncDJ3c2gnLCAncDJ0cicsICdwMnRyTXVzaWcyJ10uaW5jbHVkZXMoc2NyaXB0VHlwZSk7XG59XG5cbi8qKlxuICogQHBhcmFtIG5ldHdvcmtcbiAqIEBwYXJhbSBzY3JpcHRUeXBlXG4gKiBAcmV0dXJuIHRydWUgaWZmIHNjcmlwdCB0eXBlIGlzIHN1cHBvcnRlZCBmb3IgbmV0d29ya1xuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTdXBwb3J0ZWRTY3JpcHRUeXBlKG5ldHdvcms6IE5ldHdvcmssIHNjcmlwdFR5cGU6IFNjcmlwdFR5cGUpOiBib29sZWFuIHtcbiAgc3dpdGNoIChzY3JpcHRUeXBlKSB7XG4gICAgY2FzZSAncDJzaCc6XG4gICAgY2FzZSAncDJzaFAycGsnOlxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgY2FzZSAncDJzaFAyd3NoJzpcbiAgICBjYXNlICdwMndzaCc6XG4gICAgICByZXR1cm4gc3VwcG9ydHNTZWd3aXQobmV0d29yayk7XG4gICAgY2FzZSAncDJ0cic6XG4gICAgY2FzZSAncDJ0ck11c2lnMic6XG4gICAgICByZXR1cm4gc3VwcG9ydHNUYXByb290KG5ldHdvcmspO1xuICB9XG5cbiAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgdGhyb3cgbmV3IEVycm9yKGB1bmV4cGVjdGVkIHNjcmlwdCB0eXBlICR7c2NyaXB0VHlwZX1gKTtcbn1cblxuLyoqXG4gKiBAcGFyYW0gdFxuICogQHJldHVybiBzdHJpbmcgcHJldk91dCBhcyBkZWZpbmVkIGluIFBSRVZPVVRfVFlQRVMgKGJpdGNvaW5qcy1saWIvLi4uL3RyYW5zYWN0aW9uX2J1aWxkZXIuanMpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzY3JpcHRUeXBlMk9mM0FzUHJldk91dFR5cGUodDogU2NyaXB0VHlwZTJPZjMpOiBzdHJpbmcge1xuICBzd2l0Y2ggKHQpIHtcbiAgICBjYXNlICdwMnNoJzpcbiAgICAgIHJldHVybiAncDJzaC1wMm1zJztcbiAgICBjYXNlICdwMnNoUDJ3c2gnOlxuICAgICAgcmV0dXJuICdwMnNoLXAyd3NoLXAybXMnO1xuICAgIGNhc2UgJ3Ayd3NoJzpcbiAgICAgIHJldHVybiAncDJ3c2gtcDJtcyc7XG4gICAgY2FzZSAncDJ0cic6XG4gICAgICByZXR1cm4gJ3AydHItcDJucyc7XG4gICAgY2FzZSAncDJ0ck11c2lnMic6XG4gICAgICByZXR1cm4gJ3AydHInO1xuICB9XG5cbiAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgdGhyb3cgbmV3IEVycm9yKGB1bnN1cHBvcnRlZCBzY3JpcHQgdHlwZSAke3R9YCk7XG59XG5cbmV4cG9ydCB0eXBlIFNwZW5kYWJsZVNjcmlwdCA9IHtcbiAgc2NyaXB0UHViS2V5OiBCdWZmZXI7XG4gIHJlZGVlbVNjcmlwdD86IEJ1ZmZlcjtcbiAgd2l0bmVzc1NjcmlwdD86IEJ1ZmZlcjtcbn07XG5cbmV4cG9ydCB0eXBlIFNwZW5kU2NyaXB0UDJ0ciA9IHtcbiAgY29udHJvbEJsb2NrOiBCdWZmZXI7XG4gIHdpdG5lc3NTY3JpcHQ6IEJ1ZmZlcjtcbiAgbGVhZlZlcnNpb246IG51bWJlcjtcbiAgbGVhZkhhc2g6IEJ1ZmZlcjtcbn07XG5cbi8qKlxuICogVHdlYWsgZGF0YSBob2xkZXIgZm9yIFAydHIgTXVzaWcyIGtleSBwYXRoLlxuICovXG5leHBvcnQgdHlwZSBLZXlQYXRoUDJ0ck11c2lnMiA9IHtcbiAgaW50ZXJuYWxQdWJrZXk6IEJ1ZmZlcjtcbiAgb3V0cHV0UHVia2V5OiBCdWZmZXI7XG4gIHRhcHRyZWVSb290OiBCdWZmZXI7XG59O1xuXG4vKipcbiAqIFJldHVybiBzY3JpcHRzIGZvciBwMnNoLXAycGsgKHVzZWQgZm9yIEJDSC9CU1YgcmVwbGF5IHByb3RlY3Rpb24pXG4gKiBAcGFyYW0gcHVia2V5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVPdXRwdXRTY3JpcHRQMnNoUDJwayhwdWJrZXk6IEJ1ZmZlcik6IFNwZW5kYWJsZVNjcmlwdCB7XG4gIGNvbnN0IHAycGsgPSBiaXRjb2luanMucGF5bWVudHMucDJwayh7IHB1YmtleSB9KTtcbiAgY29uc3QgcDJzaCA9IGJpdGNvaW5qcy5wYXltZW50cy5wMnNoKHsgcmVkZWVtOiBwMnBrIH0pO1xuICBpZiAoIXAyc2gub3V0cHV0IHx8ICFwMnBrLm91dHB1dCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBzdGF0ZWApO1xuICB9XG4gIHJldHVybiB7XG4gICAgc2NyaXB0UHViS2V5OiBwMnNoLm91dHB1dCxcbiAgICByZWRlZW1TY3JpcHQ6IHAycGsub3V0cHV0LFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3V0cHV0U2NyaXB0KHNjcmlwdFR5cGU6ICdwMnNoJyB8ICdwMnNoUDJ3c2gnIHwgJ3Ayd3NoJywgY29uZGl0aW9uU2NyaXB0OiBCdWZmZXIpOiBCdWZmZXIge1xuICBsZXQgb3V0cHV0O1xuICBzd2l0Y2ggKHNjcmlwdFR5cGUpIHtcbiAgICBjYXNlICdwMnNoJzpcbiAgICAgICh7IG91dHB1dCB9ID0gYml0Y29pbmpzLnBheW1lbnRzLnAyc2goeyByZWRlZW06IHsgb3V0cHV0OiBjb25kaXRpb25TY3JpcHQgfSB9KSk7XG4gICAgICBicmVhaztcbiAgICBjYXNlICdwMnNoUDJ3c2gnOlxuICAgICAgKHsgb3V0cHV0IH0gPSBiaXRjb2luanMucGF5bWVudHMucDJzaCh7XG4gICAgICAgIHJlZGVlbTogeyBvdXRwdXQ6IGdldE91dHB1dFNjcmlwdCgncDJ3c2gnLCBjb25kaXRpb25TY3JpcHQpIH0sXG4gICAgICB9KSk7XG4gICAgICBicmVhaztcbiAgICBjYXNlICdwMndzaCc6XG4gICAgICAoeyBvdXRwdXQgfSA9IGJpdGNvaW5qcy5wYXltZW50cy5wMndzaCh7IHJlZGVlbTogeyBvdXRwdXQ6IGNvbmRpdGlvblNjcmlwdCB9IH0pKTtcbiAgICAgIGJyZWFrO1xuICB9XG4gIGlmIChvdXRwdXQgPT09IHVuZGVmaW5lZCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgb3V0cHV0IHVuZGVmaW5lZGApO1xuICB9XG4gIHJldHVybiBvdXRwdXQ7XG59XG5cbi8qKlxuICogUmV0dXJuIHNjcmlwdHMgZm9yIDItb2YtMyBtdWx0aXNpZyBvdXRwdXRcbiAqIEBwYXJhbSBwdWJrZXlzIC0gdGhlIGtleSB0cmlwbGUgZm9yIG11bHRpc2lnXG4gKiBAcGFyYW0gc2NyaXB0VHlwZVxuICogQHBhcmFtIG5ldHdvcmsgLSBpZiBzZXQsIHBlcmZvcm1zIHNhbml0eSBjaGVjayBmb3Igc2NyaXB0VHlwZSBzdXBwb3J0XG4gKiBAcmV0dXJucyB7e3JlZGVlbVNjcmlwdCwgd2l0bmVzc1NjcmlwdCwgc2NyaXB0UHViS2V5fX1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU91dHB1dFNjcmlwdDJvZjMoXG4gIHB1YmtleXM6IEJ1ZmZlcltdLFxuICBzY3JpcHRUeXBlOiBTY3JpcHRUeXBlMk9mMyxcbiAgbmV0d29yaz86IE5ldHdvcmtcbik6IFNwZW5kYWJsZVNjcmlwdCB7XG4gIGlmIChuZXR3b3JrKSB7XG4gICAgaWYgKCFpc1N1cHBvcnRlZFNjcmlwdFR5cGUobmV0d29yaywgc2NyaXB0VHlwZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdW5zdXBwb3J0ZWQgc2NyaXB0IHR5cGUgJHtzY3JpcHRUeXBlfSBmb3IgbmV0d29ya2ApO1xuICAgIH1cbiAgfVxuXG4gIGlmICghaXNUcmlwbGUocHVia2V5cykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYG11c3QgcHJvdmlkZSBwdWJrZXkgdHJpcGxlYCk7XG4gIH1cblxuICBwdWJrZXlzLmZvckVhY2goKGtleSkgPT4ge1xuICAgIGlmIChrZXkubGVuZ3RoICE9PSAzMykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmV4cGVjdGVkIGtleSBsZW5ndGggJHtrZXkubGVuZ3RofS4gTXVzdCB1c2UgY29tcHJlc3NlZCBrZXlzLmApO1xuICAgIH1cbiAgfSk7XG5cbiAgaWYgKHNjcmlwdFR5cGUgPT09ICdwMnRyJyB8fCBzY3JpcHRUeXBlID09PSAncDJ0ck11c2lnMicpIHtcbiAgICAvLyBwMnRyL3AydHJNdXNpZzIgYWRkcmVzc2VzIHVzZSBhIGNvbWJpbmF0aW9uIG9mIDIgb2YgMiBtdWx0aXNpZyBzY3JpcHRzIGRpc3RpbmN0IGZyb21cbiAgICAvLyB0aGUgMiBvZiAzIG11bHRpc2lnIHVzZWQgZm9yIG90aGVyIHNjcmlwdCB0eXBlc1xuICAgIHJldHVybiBjcmVhdGVUYXByb290U2NyaXB0Mm9mMyhzY3JpcHRUeXBlLCBwdWJrZXlzKTtcbiAgfVxuXG4gIGNvbnN0IHNjcmlwdDJvZjMgPSBiaXRjb2luanMucGF5bWVudHMucDJtcyh7IG06IDIsIHB1YmtleXMgfSk7XG4gIGFzc2VydChzY3JpcHQyb2YzLm91dHB1dCk7XG5cbiAgbGV0IHJlZGVlbVNjcmlwdDogYml0Y29pbmpzLlBheW1lbnQgfCB1bmRlZmluZWQ7XG4gIGxldCB3aXRuZXNzU2NyaXB0OiBiaXRjb2luanMuUGF5bWVudCB8IHVuZGVmaW5lZDtcbiAgc3dpdGNoIChzY3JpcHRUeXBlKSB7XG4gICAgY2FzZSAncDJzaCc6XG4gICAgICByZWRlZW1TY3JpcHQgPSBzY3JpcHQyb2YzO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAncDJzaFAyd3NoJzpcbiAgICAgIHdpdG5lc3NTY3JpcHQgPSBzY3JpcHQyb2YzO1xuICAgICAgcmVkZWVtU2NyaXB0ID0gYml0Y29pbmpzLnBheW1lbnRzLnAyd3NoKHsgcmVkZWVtOiBzY3JpcHQyb2YzIH0pO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAncDJ3c2gnOlxuICAgICAgd2l0bmVzc1NjcmlwdCA9IHNjcmlwdDJvZjM7XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IEVycm9yKGB1bmtub3duIG11bHRpc2lnIHNjcmlwdCB0eXBlICR7c2NyaXB0VHlwZX1gKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgc2NyaXB0UHViS2V5OiBnZXRPdXRwdXRTY3JpcHQoc2NyaXB0VHlwZSwgc2NyaXB0Mm9mMy5vdXRwdXQpLFxuICAgIHJlZGVlbVNjcmlwdDogcmVkZWVtU2NyaXB0Py5vdXRwdXQsXG4gICAgd2l0bmVzc1NjcmlwdDogd2l0bmVzc1NjcmlwdD8ub3V0cHV0LFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdG9YT25seVB1YmxpY0tleShiOiBCdWZmZXIpOiBCdWZmZXIge1xuICBpZiAoYi5sZW5ndGggPT09IDMzKSB7XG4gICAgcmV0dXJuIGIuc2xpY2UoMSk7XG4gIH1cbiAgaWYgKGIubGVuZ3RoID09PSAzMikge1xuICAgIHJldHVybiBiO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBrZXkgc2l6ZSAke2IubGVuZ3RofWApO1xufVxuXG5mdW5jdGlvbiBjaGVja1NpemUoYjogQnVmZmVyLCB0YXJnZXRTaXplOiBudW1iZXIsIG5hbWU6IHN0cmluZyk6IEJ1ZmZlciB7XG4gIGlmIChiLmxlbmd0aCA9PT0gdGFyZ2V0U2l6ZSkge1xuICAgIHJldHVybiBiO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBzaXplICR7Yi5sZW5ndGh9LiBNdXN0IHVzZSAke25hbWV9LmApO1xufVxuXG4vKipcbiAqIFZhbGlkYXRlcyBzaXplIG9mIHRoZSBwdWIga2V5IGZvciAzMiBieXRlcyBhbmQgcmV0dXJucyB0aGUgc2FtZSBpZmYgdHJ1ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoZWNrWE9ubHlQdWJsaWNLZXkoYjogQnVmZmVyKTogQnVmZmVyIHtcbiAgcmV0dXJuIGNoZWNrU2l6ZShiLCAzMiwgJ3gtb25seSBrZXknKTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgc2l6ZSBvZiB0aGUgcHViIGtleSBmb3IgMzIgYnl0ZXMgYW5kIHJldHVybnMgdGhlIHNhbWUgaWZmIHRydWUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGVja1BsYWluUHVibGljS2V5KGI6IEJ1ZmZlcik6IEJ1ZmZlciB7XG4gIHJldHVybiBjaGVja1NpemUoYiwgMzMsICdwbGFpbiBrZXknKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNoZWNrVGFwTWVya2xlUm9vdChiOiBCdWZmZXIpOiBCdWZmZXIge1xuICByZXR1cm4gY2hlY2tTaXplKGIsIDMyLCAndGFwIG1lcmtsZSByb290Jyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjaGVja1R4SGFzaChiOiBCdWZmZXIpOiBCdWZmZXIge1xuICByZXR1cm4gY2hlY2tTaXplKGIsIDMyLCAndHggaGFzaCcpO1xufVxuXG5mdW5jdGlvbiBnZXRUYXB0cmVlS2V5Q29tYmluYXRpb25zKHNjcmlwdFR5cGU6ICdwMnRyJyB8ICdwMnRyTXVzaWcyJywga2V5czogVHJpcGxlPEJ1ZmZlcj4pOiBUdXBsZTxCdWZmZXI+W10ge1xuICBjb25zdCBbdXNlcktleSwgYmFja3VwS2V5LCBiaXRHb0tleV0gPSBrZXlzLm1hcCgoaykgPT4gdG9YT25seVB1YmxpY0tleShrKSk7XG4gIHJldHVybiBzY3JpcHRUeXBlID09PSAncDJ0cidcbiAgICA/IFtcbiAgICAgICAgW3VzZXJLZXksIGJpdEdvS2V5XSxcbiAgICAgICAgW3VzZXJLZXksIGJhY2t1cEtleV0sXG4gICAgICAgIFtiYWNrdXBLZXksIGJpdEdvS2V5XSxcbiAgICAgIF1cbiAgICA6IFtcbiAgICAgICAgW3VzZXJLZXksIGJhY2t1cEtleV0sXG4gICAgICAgIFtiYWNrdXBLZXksIGJpdEdvS2V5XSxcbiAgICAgIF07XG59XG5cbmZ1bmN0aW9uIGdldEtleVBhdGhDb21iaW5hdGlvbihzY3JpcHRUeXBlOiAncDJ0cicgfCAncDJ0ck11c2lnMicsIGtleXM6IFRyaXBsZTxCdWZmZXI+KTogVHVwbGU8QnVmZmVyPiB7XG4gIGNvbnN0IHNhbml0aXplUHVibGljS2V5ID0gc2NyaXB0VHlwZSA9PT0gJ3AydHInID8gdG9YT25seVB1YmxpY0tleSA6IGNoZWNrUGxhaW5QdWJsaWNLZXk7XG4gIHJldHVybiBbc2FuaXRpemVQdWJsaWNLZXkoa2V5c1swXSksIHNhbml0aXplUHVibGljS2V5KGtleXNbMl0pXTtcbn1cblxuZnVuY3Rpb24gZ2V0UmVkZWVtSW5kZXgoa2V5Q29tYmluYXRpb25zOiBbQnVmZmVyLCBCdWZmZXJdW10sIHNpZ25lcjogQnVmZmVyLCBjb3NpZ25lcjogQnVmZmVyKTogbnVtYmVyIHtcbiAgc2lnbmVyID0gdG9YT25seVB1YmxpY0tleShzaWduZXIpO1xuICBjb3NpZ25lciA9IHRvWE9ubHlQdWJsaWNLZXkoY29zaWduZXIpO1xuICBjb25zdCBpID0ga2V5Q29tYmluYXRpb25zLmZpbmRJbmRleCgoW2EsIGJdKSA9PiB7XG4gICAgaWYgKGEubGVuZ3RoICE9PSBzaWduZXIubGVuZ3RoIHx8IGIubGVuZ3RoICE9PSBjb3NpZ25lci5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBjb21wYXJpc29uYCk7XG4gICAgfVxuICAgIHJldHVybiAoYS5lcXVhbHMoc2lnbmVyKSAmJiBiLmVxdWFscyhjb3NpZ25lcikpIHx8IChhLmVxdWFscyhjb3NpZ25lcikgJiYgYi5lcXVhbHMoc2lnbmVyKSk7XG4gIH0pO1xuICBpZiAoMCA8PSBpKSB7XG4gICAgcmV0dXJuIGk7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKGBjb3VsZCBub3QgZmluZCBzaW5nZXIvY29zaWduZXIgY29tYmluYXRpb25gKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVBheW1lbnRQMnRyQ29tbW9uKFxuICBzY3JpcHRUeXBlOiAncDJ0cicgfCAncDJ0ck11c2lnMicsXG4gIHB1YmtleXM6IFRyaXBsZTxCdWZmZXI+LFxuICByZWRlZW1JbmRleD86IG51bWJlciB8IHsgc2lnbmVyOiBCdWZmZXI7IGNvc2lnbmVyOiBCdWZmZXIgfVxuKTogYml0Y29pbmpzLlBheW1lbnQge1xuICBjb25zdCBrZXlDb21iaW5hdGlvbnMyb2YyID0gZ2V0VGFwdHJlZUtleUNvbWJpbmF0aW9ucyhzY3JpcHRUeXBlLCBwdWJrZXlzKTtcbiAgaWYgKHR5cGVvZiByZWRlZW1JbmRleCA9PT0gJ29iamVjdCcpIHtcbiAgICByZWRlZW1JbmRleCA9IGdldFJlZGVlbUluZGV4KGtleUNvbWJpbmF0aW9uczJvZjIsIHJlZGVlbUluZGV4LnNpZ25lciwgcmVkZWVtSW5kZXguY29zaWduZXIpO1xuICB9XG4gIGNvbnN0IHJlZGVlbXMgPSBrZXlDb21iaW5hdGlvbnMyb2YyLm1hcCgocHVia2V5cywgaW5kZXgpID0+XG4gICAgcDJ0clBheW1lbnRzLnAydHJfbnMoXG4gICAgICB7XG4gICAgICAgIHB1YmtleXMsXG4gICAgICAgIGRlcHRoOiBzY3JpcHRUeXBlID09PSAncDJ0ck11c2lnMicgfHwgaW5kZXggPT09IDAgPyAxIDogMixcbiAgICAgIH0sXG4gICAgICB7IGVjY0xpYiB9XG4gICAgKVxuICApO1xuXG4gIHJldHVybiBwMnRyUGF5bWVudHMucDJ0cihcbiAgICB7XG4gICAgICBwdWJrZXlzOiBnZXRLZXlQYXRoQ29tYmluYXRpb24oc2NyaXB0VHlwZSwgcHVia2V5cyksXG4gICAgICByZWRlZW1zLFxuICAgICAgcmVkZWVtSW5kZXgsXG4gICAgfSxcbiAgICB7IGVjY0xpYiB9XG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQYXltZW50UDJ0cihcbiAgcHVia2V5czogVHJpcGxlPEJ1ZmZlcj4sXG4gIHJlZGVlbUluZGV4PzogbnVtYmVyIHwgeyBzaWduZXI6IEJ1ZmZlcjsgY29zaWduZXI6IEJ1ZmZlciB9XG4pOiBiaXRjb2luanMuUGF5bWVudCB7XG4gIHJldHVybiBjcmVhdGVQYXltZW50UDJ0ckNvbW1vbigncDJ0cicsIHB1YmtleXMsIHJlZGVlbUluZGV4KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVBheW1lbnRQMnRyTXVzaWcyKFxuICBwdWJrZXlzOiBUcmlwbGU8QnVmZmVyPixcbiAgcmVkZWVtSW5kZXg/OiBudW1iZXIgfCB7IHNpZ25lcjogQnVmZmVyOyBjb3NpZ25lcjogQnVmZmVyIH1cbik6IGJpdGNvaW5qcy5QYXltZW50IHtcbiAgcmV0dXJuIGNyZWF0ZVBheW1lbnRQMnRyQ29tbW9uKCdwMnRyTXVzaWcyJywgcHVia2V5cywgcmVkZWVtSW5kZXgpO1xufVxuXG5mdW5jdGlvbiBnZXRMZWFmSGFzaENvbW1vbihcbiAgc2NyaXB0VHlwZTogJ3AydHInIHwgJ3AydHJNdXNpZzInLFxuICBwYXJhbXM6IGJpdGNvaW5qcy5QYXltZW50IHwgeyBwdWJsaWNLZXlzOiBUcmlwbGU8QnVmZmVyPjsgc2lnbmVyOiBCdWZmZXI7IGNvc2lnbmVyOiBCdWZmZXIgfVxuKTogQnVmZmVyIHtcbiAgaWYgKCdwdWJsaWNLZXlzJyBpbiBwYXJhbXMpIHtcbiAgICBwYXJhbXMgPSBjcmVhdGVQYXltZW50UDJ0ckNvbW1vbihzY3JpcHRUeXBlLCBwYXJhbXMucHVibGljS2V5cywgcGFyYW1zKTtcbiAgfVxuICBjb25zdCB7IG91dHB1dCwgY29udHJvbEJsb2NrLCByZWRlZW0gfSA9IHBhcmFtcztcbiAgaWYgKCFvdXRwdXQgfHwgIWNvbnRyb2xCbG9jayB8fCAhcmVkZWVtIHx8ICFyZWRlZW0ub3V0cHV0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIHN0YXRlYCk7XG4gIH1cbiAgcmV0dXJuIHRhcHJvb3QuZ2V0VGFwbGVhZkhhc2goZWNjTGliLCBjb250cm9sQmxvY2ssIHJlZGVlbS5vdXRwdXQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TGVhZkhhc2goXG4gIHBhcmFtczogYml0Y29pbmpzLlBheW1lbnQgfCB7IHB1YmxpY0tleXM6IFRyaXBsZTxCdWZmZXI+OyBzaWduZXI6IEJ1ZmZlcjsgY29zaWduZXI6IEJ1ZmZlciB9XG4pOiBCdWZmZXIge1xuICByZXR1cm4gZ2V0TGVhZkhhc2hDb21tb24oJ3AydHInLCBwYXJhbXMpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlS2V5UGF0aFAydHJNdXNpZzIocHVia2V5czogVHJpcGxlPEJ1ZmZlcj4pOiBLZXlQYXRoUDJ0ck11c2lnMiB7XG4gIGNvbnN0IHBheW1lbnQgPSBjcmVhdGVQYXltZW50UDJ0ckNvbW1vbigncDJ0ck11c2lnMicsIHB1YmtleXMpO1xuICBhc3NlcnQocGF5bWVudC5pbnRlcm5hbFB1YmtleSk7XG4gIGFzc2VydChwYXltZW50LnRhcFRyZWUpO1xuICByZXR1cm4ge1xuICAgIGludGVybmFsUHVia2V5OiBwYXltZW50LmludGVybmFsUHVia2V5LFxuICAgIG91dHB1dFB1YmtleTogZ2V0VHdlYWtlZE91dHB1dEtleShwYXltZW50KSxcbiAgICB0YXB0cmVlUm9vdDogZ2V0RGVwdGhGaXJzdFRhcHRyZWUocGF5bWVudC50YXBUcmVlKS5yb290LFxuICB9O1xufVxuXG5mdW5jdGlvbiBjcmVhdGVTcGVuZFNjcmlwdFAydHJDb21tb24oXG4gIHNjcmlwdFR5cGU6ICdwMnRyJyB8ICdwMnRyTXVzaWcyJyxcbiAgcHVia2V5czogVHJpcGxlPEJ1ZmZlcj4sXG4gIGtleUNvbWJpbmF0aW9uOiBUdXBsZTxCdWZmZXI+XG4pOiBTcGVuZFNjcmlwdFAydHIge1xuICBjb25zdCBrZXlDb21iaW5hdGlvbnMgPSBnZXRUYXB0cmVlS2V5Q29tYmluYXRpb25zKHNjcmlwdFR5cGUsIHB1YmtleXMpO1xuICBjb25zdCBbYSwgYl0gPSBrZXlDb21iaW5hdGlvbi5tYXAoKGspID0+IHRvWE9ubHlQdWJsaWNLZXkoaykpO1xuICBjb25zdCByZWRlZW1JbmRleCA9IGtleUNvbWJpbmF0aW9ucy5maW5kSW5kZXgoXG4gICAgKFtjLCBkXSkgPT4gKGEuZXF1YWxzKGMpICYmIGIuZXF1YWxzKGQpKSB8fCAoYS5lcXVhbHMoZCkgJiYgYi5lcXVhbHMoYykpXG4gICk7XG5cbiAgaWYgKHJlZGVlbUluZGV4IDwgMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgY291bGQgbm90IGZpbmQgcmVkZWVtSW5kZXggZm9yIGtleSBjb21iaW5hdGlvbmApO1xuICB9XG5cbiAgY29uc3QgcGF5bWVudCA9IGNyZWF0ZVBheW1lbnRQMnRyQ29tbW9uKHNjcmlwdFR5cGUsIHB1YmtleXMsIHJlZGVlbUluZGV4KTtcbiAgY29uc3QgeyBjb250cm9sQmxvY2sgfSA9IHBheW1lbnQ7XG4gIGFzc2VydChCdWZmZXIuaXNCdWZmZXIoY29udHJvbEJsb2NrKSk7XG5cbiAgYXNzZXJ0KHBheW1lbnQucmVkZWVtKTtcbiAgY29uc3QgbGVhZlNjcmlwdCA9IHBheW1lbnQucmVkZWVtLm91dHB1dDtcbiAgYXNzZXJ0KEJ1ZmZlci5pc0J1ZmZlcihsZWFmU2NyaXB0KSk7XG5cbiAgY29uc3QgcGFyc2VkQ29udHJvbEJsb2NrID0gdGFwcm9vdC5wYXJzZUNvbnRyb2xCbG9jayhlY2NMaWIsIGNvbnRyb2xCbG9jayk7XG4gIGNvbnN0IHsgbGVhZlZlcnNpb24gfSA9IHBhcnNlZENvbnRyb2xCbG9jaztcbiAgY29uc3QgbGVhZkhhc2ggPSB0YXByb290LmdldFRhcGxlYWZIYXNoKGVjY0xpYiwgcGFyc2VkQ29udHJvbEJsb2NrLCBsZWFmU2NyaXB0KTtcblxuICByZXR1cm4ge1xuICAgIGNvbnRyb2xCbG9jayxcbiAgICB3aXRuZXNzU2NyaXB0OiBsZWFmU2NyaXB0LFxuICAgIGxlYWZWZXJzaW9uLFxuICAgIGxlYWZIYXNoLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU3BlbmRTY3JpcHRQMnRyKHB1YmtleXM6IFRyaXBsZTxCdWZmZXI+LCBrZXlDb21iaW5hdGlvbjogVHVwbGU8QnVmZmVyPik6IFNwZW5kU2NyaXB0UDJ0ciB7XG4gIHJldHVybiBjcmVhdGVTcGVuZFNjcmlwdFAydHJDb21tb24oJ3AydHInLCBwdWJrZXlzLCBrZXlDb21iaW5hdGlvbik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTcGVuZFNjcmlwdFAydHJNdXNpZzIocHVia2V5czogVHJpcGxlPEJ1ZmZlcj4sIGtleUNvbWJpbmF0aW9uOiBUdXBsZTxCdWZmZXI+KTogU3BlbmRTY3JpcHRQMnRyIHtcbiAgcmV0dXJuIGNyZWF0ZVNwZW5kU2NyaXB0UDJ0ckNvbW1vbigncDJ0ck11c2lnMicsIHB1YmtleXMsIGtleUNvbWJpbmF0aW9uKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgdGFwcm9vdCBvdXRwdXQgc2NyaXB0IHVzaW5nIHRoZSB1c2VyK2JpdGdvIGtleXMgZm9yIHRoZSBhZ2dyZWdhdGVcbiAqIHB1YmxpYyBrZXkgdXNpbmcgTXVTaWcyIGFuZCBhIHRhcHRyZWUgY29udGFpbmluZyBlaXRoZXIgb2YgdGhlIGZvbGxvd2luZyBkZXBlbmRzIG9uIHNjcmlwdFR5cGUuXG4gKiBwMnRyIHR5cGU6IGEgdXNlcitiaXRnbyAyLW9mLTIgc2NyaXB0IGF0IHRoZSBmaXJzdCBkZXB0aCBsZXZlbCBvZiB0aGUgdHJlZSBhbmQgdXNlcitiYWNrdXBcbiAqIGFuZCBiaXRnbytiYWNrdXAgMi1vZi0yIHNjcmlwdHMgb25lIGxldmVsIGRlZXBlci5cbiAqIHAydHJNdXNpZzIgdHlwZTogdXNlcitiYWNrdXAgYW5kIGJpdGdvK2JhY2t1cCAyLW9mLTIgc2NyaXB0cyBhdCB0aGUgZmlyc3QgZGVwdGggbGV2ZWwgb2YgdGhlXG4gKiB0cmVlLlxuICogQHBhcmFtIHB1YmtleXMgLSBhIHB1YmtleSBhcnJheSBjb250YWluaW5nIHRoZSB1c2VyIGtleSwgYmFja3VwIGtleSwgYW5kIGJpdGdvIGtleSBpbiB0aGF0IG9yZGVyXG4gKiBAcmV0dXJucyB7e3NjcmlwdFB1YktleX19XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVRhcHJvb3RTY3JpcHQyb2YzKHNjcmlwdFR5cGU6ICdwMnRyJyB8ICdwMnRyTXVzaWcyJywgcHVia2V5czogVHJpcGxlPEJ1ZmZlcj4pOiBTcGVuZGFibGVTY3JpcHQge1xuICBjb25zdCB7IG91dHB1dCB9ID0gY3JlYXRlUGF5bWVudFAydHJDb21tb24oc2NyaXB0VHlwZSwgcHVia2V5cyk7XG4gIGFzc2VydChCdWZmZXIuaXNCdWZmZXIob3V0cHV0KSk7XG4gIHJldHVybiB7XG4gICAgc2NyaXB0UHViS2V5OiBvdXRwdXQsXG4gIH07XG59XG4iXX0=