PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-lib/dist/test/bitgo
Просмотр файла: signature.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require("assert");
const src_1 = require("../../src");
const testutil_1 = require("../../src/testutil");
const networks_1 = require("../../src/networks");
const outputScripts_1 = require("../../src/bitgo/outputScripts");
const bitgo_1 = require("../../src/bitgo");
const fixtureUtil = require("../fixture.util");
const fixtures_1 = require("../integration_local_rpc/generate/fixtures");
const transaction_util_1 = require("../transaction_util");
const signatureModify_1 = require("./signatureModify");
const normalize_1 = require("../testutil/normalize");
function getScriptTypes2Of3() {
// FIXME(BG-66941): p2trMusig2 signing does not work in this test suite yet
// because the test suite is written with TransactionBuilder
return outputScripts_1.scriptTypes2Of3.filter((scriptType) => scriptType !== 'p2trMusig2');
}
function keyName(k) {
return (0, testutil_1.getKeyName)(fixtures_1.fixtureKeys, k);
}
async function readFixture(network, scriptType, name, defaultValue) {
return await fixtureUtil.readFixture(`${__dirname}/fixtures/signature/${(0, networks_1.getNetworkName)(network)}/${scriptType}/${name}.json`, defaultValue);
}
function runTestCheckScriptStructure(network, scriptType, signer1, signer2, amountType = 'number') {
it(`has expected script structure [${(0, networks_1.getNetworkName)(network)} ${scriptType} ` +
`${keyName(signer1)} ${signer2 ? keyName(signer2) : ''} ${amountType}]`, async function () {
let tx;
if (scriptType === 'p2shP2pk') {
tx = (0, transaction_util_1.getFullSignedTransactionP2shP2pk)(fixtures_1.fixtureKeys, signer1, network, { amountType });
}
else {
if (!signer2) {
throw new Error(`must set cosigner`);
}
tx = (0, transaction_util_1.getFullSignedTransaction2Of3)(fixtures_1.fixtureKeys, signer1, signer2, scriptType, network, { amountType });
}
const { script, witness } = tx.ins[0];
const scriptDecompiled = src_1.script.decompile(script);
if (!scriptDecompiled) {
throw new Error();
}
const scriptASM = src_1.script.toASM(script).split(' ');
const classifyInput = src_1.classify.input(script);
const classifyWitness = src_1.classify.witness(witness);
let pubScript;
let classifyPubScript;
let pubScriptASM;
let tapscript;
let tapscriptASM;
let classifyTapscript;
if (classifyInput === 'scripthash' || classifyWitness === 'witnessscripthash') {
if (witness.length) {
pubScript = witness[witness.length - 1];
}
else {
pubScript = scriptDecompiled[scriptDecompiled.length - 1];
}
classifyPubScript = src_1.classify.output(pubScript);
pubScriptASM = src_1.script.toASM(pubScript).split(' ');
}
else if (classifyWitness === 'taproot') {
tapscript = witness[witness.length - 2];
classifyTapscript = src_1.classify.output(tapscript);
tapscriptASM = src_1.script.toASM(tapscript).split(' ');
}
const structure = {
publicKeys: fixtures_1.fixtureKeys.map((k) => k.publicKey.toString('hex')),
script: script?.toString('hex'),
witness: witness?.map((w) => w.toString('hex')),
scriptASM,
pubScriptASM,
tapscriptASM,
classifyInput,
classifyWitness,
classifyPubScript,
classifyTapscript,
};
const fixtureName = ['structure', keyName(signer1), signer2 ? keyName(signer2) : 'none'].join('-');
fixtureUtil.assertEqualJSON(structure, await readFixture(network, scriptType, fixtureName, structure));
});
}
function runTestParseScript(network, scriptType, k1, k2, amountType = 'number') {
async function testParseSignedInputs(tx, name, expectedScriptType, { expectedPlaceholderSignatures }) {
const parsed = (0, bitgo_1.parseSignatureScript)(tx.ins[0]);
assert.strictEqual(parsed.scriptType, expectedScriptType === 'p2tr' ? 'taprootScriptPathSpend' : expectedScriptType);
const parsed2Of3 = { ...parsed, scriptType: expectedScriptType };
fixtureUtil.assertEqualJSON(parsed2Of3, await readFixture(network, scriptType, ['parsed', keyName(k1), keyName(k2), name].join('-'), parsed2Of3));
if (!parsed.scriptType) {
return;
}
switch (parsed.scriptType) {
case 'p2shP2pk':
// we don't parse the signature for this script type
break;
case 'p2sh':
case 'p2shP2wsh':
case 'p2wsh':
case 'taprootScriptPathSpend':
assert.strictEqual(parsed.signatures.filter((s) => (0, bitgo_1.isPlaceholderSignature)(s)).length, expectedPlaceholderSignatures);
break;
default:
throw new Error(`unexpected scriptType ${parsed.scriptType}`);
}
}
if (scriptType !== 'p2shP2pk') {
it(`parses half-signed inputs [${(0, networks_1.getNetworkName)(network)} ${scriptType} ${amountType}]`, async function () {
await testParseSignedInputs((0, transaction_util_1.getHalfSignedTransaction2Of3)(fixtures_1.fixtureKeys, k1, k2, scriptType, network, { amountType }), 'halfSigned', scriptType, { expectedPlaceholderSignatures: scriptType === 'p2tr' ? 1 : 2 });
});
}
it(`parses full-signed inputs [${(0, networks_1.getNetworkName)(network)} ${scriptType} ${amountType}]`, async function () {
if (scriptType === 'p2shP2pk') {
await testParseSignedInputs((0, transaction_util_1.getFullSignedTransactionP2shP2pk)(fixtures_1.fixtureKeys, k1, network, { amountType }), 'fullSigned', scriptType, { expectedPlaceholderSignatures: 0 });
}
else {
await testParseSignedInputs((0, transaction_util_1.getFullSignedTransaction2Of3)(fixtures_1.fixtureKeys, k1, k2, scriptType, network, { amountType }), 'fullSigned', scriptType, { expectedPlaceholderSignatures: 0 });
}
});
}
function assertVerifySignatureEquals(tx, prevOutputs, value, testOutputAmount, verificationSettings) {
tx.ins.forEach((input, i) => {
assert.doesNotThrow(() => {
(0, bitgo_1.getSignatureVerifications)(tx, i, testOutputAmount, verificationSettings, prevOutputs);
});
assert.strictEqual((0, bitgo_1.verifySignature)(tx, i, testOutputAmount, verificationSettings, prevOutputs), value, JSON.stringify(verificationSettings));
if (verificationSettings?.signatureIndex === undefined && verificationSettings?.publicKey) {
assert.strictEqual((0, bitgo_1.verifySignatureWithPublicKey)(tx, i, prevOutputs, verificationSettings.publicKey), value);
}
});
}
function checkSignTransaction(tx, scriptType, signKeys, testOutputAmount) {
const prevOutputs = (0, transaction_util_1.getPrevOutputs)(scriptType, testOutputAmount, tx.network);
// return true iff there are any valid signatures at all
assertVerifySignatureEquals(tx, prevOutputs, signKeys.length > 0, testOutputAmount);
fixtures_1.fixtureKeys.forEach((k) => {
// if publicKey is given, return true iff it is included in signKeys
assertVerifySignatureEquals(tx, prevOutputs, signKeys.includes(k), testOutputAmount, {
publicKey: k.publicKey,
});
});
// When transactions are signed, the signatures have the same order as the public keys in the outputScript.
const orderedSigningKeys = fixtures_1.fixtureKeys.filter((fixtureKey) => signKeys.includes(fixtureKey));
[0, 1, 2].forEach((signatureIndex) => {
if (scriptType === 'p2tr') {
// signatureIndex parameter not support for p2tr verification
return;
}
fixtures_1.fixtureKeys.forEach((k) => {
// If no public key is given, return true iff any valid signature with given index exists.
assertVerifySignatureEquals(tx, prevOutputs, signatureIndex < signKeys.length, testOutputAmount, {
signatureIndex,
});
// If publicKey and signatureIndex are provided only return if both match.
assertVerifySignatureEquals(tx, prevOutputs, signatureIndex === orderedSigningKeys.indexOf(k), testOutputAmount, {
publicKey: k.publicKey,
signatureIndex,
});
});
});
tx.ins.forEach((input, i) => {
const signatureCount = (res) => res.reduce((sum, b) => sum + (b ? 1 : 0), 0);
const pubkeys = fixtures_1.fixtureKeys.map((k) => k.publicKey);
const verifyResult = (0, bitgo_1.verifySignatureWithPublicKeys)(tx, i, prevOutputs, pubkeys);
assert.deepStrictEqual(verifyResult, fixtures_1.fixtureKeys.map((k) => signKeys.includes(k)));
assert.strictEqual(signatureCount(verifyResult), signKeys.length);
if (signKeys.length > 0) {
(0, signatureModify_1.getTransactionWithHighS)(tx, i).forEach((txWithHighS) => {
assert.strictEqual(signatureCount((0, bitgo_1.verifySignatureWithPublicKeys)(txWithHighS, i, prevOutputs, pubkeys)), signKeys.length - 1);
});
if (scriptType !== 'p2tr' && scriptType !== 'p2trMusig2') {
assert.throws(() => signatureCount((0, bitgo_1.verifySignatureWithPublicKeys)(tx, i, (0, signatureModify_1.getPrevOutsWithInvalidOutputScript)(prevOutputs, i), pubkeys)), /prevout script .* does not match computed script .*/);
}
}
});
}
function runTestCheckSignatureVerify(network, scriptType, k1, k2, amountType = 'number') {
if (k1 && k2) {
describe(`verifySignature ${(0, networks_1.getNetworkName)(network)} ${scriptType} ${keyName(k1)} ${keyName(k2)} ${amountType}`, function () {
it(`verifies half-signed`, function () {
checkSignTransaction((0, transaction_util_1.getHalfSignedTransaction2Of3)(fixtures_1.fixtureKeys, k1, k2, scriptType, network, { amountType }), scriptType, [k1], (0, bitgo_1.toTNumber)(transaction_util_1.defaultTestOutputAmount, amountType));
});
it(`verifies full-signed`, function () {
checkSignTransaction((0, transaction_util_1.getFullSignedTransaction2Of3)(fixtures_1.fixtureKeys, k1, k2, scriptType, network, { amountType }), scriptType, [k1, k2], (0, bitgo_1.toTNumber)(transaction_util_1.defaultTestOutputAmount, amountType));
});
});
}
else {
describe(`verifySignature ${(0, networks_1.getNetworkName)(network)} ${scriptType} ${amountType} unsigned`, function () {
it(`verifies unsigned`, function () {
checkSignTransaction((0, transaction_util_1.getUnsignedTransaction2Of3)(fixtures_1.fixtureKeys, scriptType, network, { amountType }), scriptType, [], (0, bitgo_1.toTNumber)(transaction_util_1.defaultTestOutputAmount, amountType));
});
});
}
}
describe('Signature (scriptTypes2Of3)', function () {
(0, networks_1.getNetworkList)()
.filter(networks_1.isMainnet)
// The signing and verification methods are largely network-independent so let's focus on a
// single network to reduce test time.
// During development it might make sense to test all networks.
.filter(networks_1.isBitcoin)
.forEach((network) => {
getScriptTypes2Of3().forEach((scriptType) => {
runTestCheckSignatureVerify(network, scriptType);
(0, transaction_util_1.getSignKeyCombinations)(2).map(([k1, k2]) => {
runTestCheckSignatureVerify(network, scriptType, k1, k2);
runTestCheckScriptStructure(network, scriptType, k1, k2);
runTestParseScript(network, scriptType, k1, k2);
});
});
getScriptTypes2Of3().forEach((scriptType) => {
runTestCheckSignatureVerify(network, scriptType, undefined, undefined, 'bigint');
(0, transaction_util_1.getSignKeyCombinations)(2).map(([k1, k2]) => {
runTestCheckSignatureVerify(network, scriptType, k1, k2, 'bigint');
runTestCheckScriptStructure(network, scriptType, k1, k2, 'bigint');
runTestParseScript(network, scriptType, k1, k2, 'bigint');
});
});
});
});
describe('Signature (p2shP2pk)', function () {
it('sign and parse', function () {
const signedTransaction = (0, transaction_util_1.getFullSignedTransactionP2shP2pk)(fixtures_1.fixtureKeys, fixtures_1.fixtureKeys[0], networks_1.networks.bitcoin);
signedTransaction.ins.forEach((input) => {
assert.deepStrictEqual((0, normalize_1.normDefault)((0, bitgo_1.parseSignatureScript)(input)), (0, normalize_1.normDefault)({
scriptType: 'p2shP2pk',
publicKeys: [fixtures_1.fixtureKeys[0].publicKey],
signatures: [
'3045022100e637466be405032a633dcef0bd161305fe93d34ffe2aabc4af434d6f265912210220113d7085b1e00435a2583af82b8a4df3fb009a8d279d231351e42f31d6bac74401',
],
}));
});
});
runTestCheckScriptStructure(networks_1.networks.bitcoin, 'p2shP2pk', fixtures_1.fixtureKeys[0]);
runTestCheckScriptStructure(networks_1.networks.bitcoin, 'p2shP2pk', fixtures_1.fixtureKeys[0], undefined, 'bigint');
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbmF0dXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdGVzdC9iaXRnby9zaWduYXR1cmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxpQ0FBaUM7QUFHakMsbUNBQWtFO0FBQ2xFLGlEQUFnRDtBQUNoRCxpREFBNkc7QUFFN0csaUVBQTRGO0FBQzVGLDJDQVN5QjtBQUV6QiwrQ0FBK0M7QUFFL0MseUVBQXlFO0FBQ3pFLDBEQVE2QjtBQUM3Qix1REFBZ0c7QUFDaEcscURBQW9EO0FBRXBELFNBQVMsa0JBQWtCO0lBQ3pCLDJFQUEyRTtJQUMzRSw2REFBNkQ7SUFDN0QsT0FBTywrQkFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsVUFBVSxLQUFLLFlBQVksQ0FBQyxDQUFDO0FBQzdFLENBQUM7QUFFRCxTQUFTLE9BQU8sQ0FBQyxDQUFpQjtJQUNoQyxPQUFPLElBQUEscUJBQVUsRUFBQyxzQkFBVyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ3BDLENBQUM7QUFFRCxLQUFLLFVBQVUsV0FBVyxDQUN4QixPQUFnQixFQUNoQixVQUF1QyxFQUN2QyxJQUFZLEVBQ1osWUFBZTtJQUVmLE9BQU8sTUFBTSxXQUFXLENBQUMsV0FBVyxDQUNsQyxHQUFHLFNBQVMsdUJBQXVCLElBQUEseUJBQWMsRUFBQyxPQUFPLENBQUMsSUFBSSxVQUFVLElBQUksSUFBSSxPQUFPLEVBQ3ZGLFlBQVksQ0FDYixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsMkJBQTJCLENBQ2xDLE9BQWdCLEVBQ2hCLFVBQXVDLEVBQ3ZDLE9BQXVCLEVBQ3ZCLE9BQXdCLEVBQ3hCLGFBQWtDLFFBQVE7SUFFMUMsRUFBRSxDQUNBLGtDQUFrQyxJQUFBLHlCQUFjLEVBQUMsT0FBTyxDQUFDLElBQUksVUFBVSxHQUFHO1FBQ3hFLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksVUFBVSxHQUFHLEVBQ3pFLEtBQUs7UUFDSCxJQUFJLEVBQUUsQ0FBQztRQUVQLElBQUksVUFBVSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQzlCLEVBQUUsR0FBRyxJQUFBLG1EQUFnQyxFQUFVLHNCQUFXLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDaEcsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7WUFDRCxFQUFFLEdBQUcsSUFBQSwrQ0FBNEIsRUFBVSxzQkFBVyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDakgsQ0FBQztRQUVELE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0QyxNQUFNLGdCQUFnQixHQUFHLFlBQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDdEIsTUFBTSxJQUFJLEtBQUssRUFBRSxDQUFDO1FBQ3BCLENBQUM7UUFDRCxNQUFNLFNBQVMsR0FBRyxZQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuRCxNQUFNLGFBQWEsR0FBRyxjQUFRLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzdDLE1BQU0sZUFBZSxHQUFHLGNBQVEsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFbEQsSUFBSSxTQUFTLENBQUM7UUFDZCxJQUFJLGlCQUFpQixDQUFDO1FBQ3RCLElBQUksWUFBWSxDQUFDO1FBRWpCLElBQUksU0FBUyxDQUFDO1FBQ2QsSUFBSSxZQUFZLENBQUM7UUFDakIsSUFBSSxpQkFBaUIsQ0FBQztRQUV0QixJQUFJLGFBQWEsS0FBSyxZQUFZLElBQUksZUFBZSxLQUFLLG1CQUFtQixFQUFFLENBQUM7WUFDOUUsSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ25CLFNBQVMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztZQUMxQyxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sU0FBUyxHQUFHLGdCQUFnQixDQUFDLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQVcsQ0FBQztZQUN0RSxDQUFDO1lBRUQsaUJBQWlCLEdBQUcsY0FBUSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMvQyxZQUFZLEdBQUcsWUFBTyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDckQsQ0FBQzthQUFNLElBQUksZUFBZSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3pDLFNBQVMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztZQUN4QyxpQkFBaUIsR0FBRyxjQUFRLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQy9DLFlBQVksR0FBRyxZQUFPLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyRCxDQUFDO1FBRUQsTUFBTSxTQUFTLEdBQUc7WUFDaEIsVUFBVSxFQUFFLHNCQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMvRCxNQUFNLEVBQUUsTUFBTSxFQUFFLFFBQVEsQ0FBQyxLQUFLLENBQUM7WUFDL0IsT0FBTyxFQUFFLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDL0MsU0FBUztZQUNULFlBQVk7WUFDWixZQUFZO1lBQ1osYUFBYTtZQUNiLGVBQWU7WUFDZixpQkFBaUI7WUFDakIsaUJBQWlCO1NBQ2xCLENBQUM7UUFFRixNQUFNLFdBQVcsR0FBRyxDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuRyxXQUFXLENBQUMsZUFBZSxDQUFDLFNBQVMsRUFBRSxNQUFNLFdBQVcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ3pHLENBQUMsQ0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsa0JBQWtCLENBQ3pCLE9BQWdCLEVBQ2hCLFVBQXNCLEVBQ3RCLEVBQWtCLEVBQ2xCLEVBQWtCLEVBQ2xCLGFBQWtDLFFBQVE7SUFFMUMsS0FBSyxVQUFVLHFCQUFxQixDQUNsQyxFQUE0QixFQUM1QixJQUFZLEVBQ1osa0JBQXNDLEVBQ3RDLEVBQUUsNkJBQTZCLEVBQTZDO1FBRTVFLE1BQU0sTUFBTSxHQUFHLElBQUEsNEJBQW9CLEVBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9DLE1BQU0sQ0FBQyxXQUFXLENBQ2hCLE1BQU0sQ0FBQyxVQUFVLEVBQ2pCLGtCQUFrQixLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsd0JBQXdCLENBQUMsQ0FBQyxDQUFDLGtCQUFrQixDQUM5RSxDQUFDO1FBQ0YsTUFBTSxVQUFVLEdBQUcsRUFBRSxHQUFHLE1BQU0sRUFBRSxVQUFVLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQztRQUNqRSxXQUFXLENBQUMsZUFBZSxDQUN6QixVQUFVLEVBQ1YsTUFBTSxXQUFXLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FDekcsQ0FBQztRQUVGLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDdkIsT0FBTztRQUNULENBQUM7UUFFRCxRQUFRLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUMxQixLQUFLLFVBQVU7Z0JBQ2Isb0RBQW9EO2dCQUNwRCxNQUFNO1lBQ1IsS0FBSyxNQUFNLENBQUM7WUFDWixLQUFLLFdBQVcsQ0FBQztZQUNqQixLQUFLLE9BQU8sQ0FBQztZQUNiLEtBQUssd0JBQXdCO2dCQUMzQixNQUFNLENBQUMsV0FBVyxDQUNoQixNQUFNLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBQSw4QkFBc0IsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFDakUsNkJBQTZCLENBQzlCLENBQUM7Z0JBQ0YsTUFBTTtZQUNSO2dCQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQTBCLE1BQWMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQzNFLENBQUM7SUFDSCxDQUFDO0lBRUQsSUFBSSxVQUFVLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDOUIsRUFBRSxDQUFDLDhCQUE4QixJQUFBLHlCQUFjLEVBQUMsT0FBTyxDQUFDLElBQUksVUFBVSxJQUFJLFVBQVUsR0FBRyxFQUFFLEtBQUs7WUFDNUYsTUFBTSxxQkFBcUIsQ0FDekIsSUFBQSwrQ0FBNEIsRUFBVSxzQkFBVyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxFQUFFLFVBQVUsRUFBRSxDQUFDLEVBQy9GLFlBQVksRUFDWixVQUFVLEVBQ1YsRUFBRSw2QkFBNkIsRUFBRSxVQUFVLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUNqRSxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsRUFBRSxDQUFDLDhCQUE4QixJQUFBLHlCQUFjLEVBQUMsT0FBTyxDQUFDLElBQUksVUFBVSxJQUFJLFVBQVUsR0FBRyxFQUFFLEtBQUs7UUFDNUYsSUFBSSxVQUFVLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDOUIsTUFBTSxxQkFBcUIsQ0FDekIsSUFBQSxtREFBZ0MsRUFBVSxzQkFBVyxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsRUFBRSxVQUFVLEVBQUUsQ0FBQyxFQUNuRixZQUFZLEVBQ1osVUFBVSxFQUNWLEVBQUUsNkJBQTZCLEVBQUUsQ0FBQyxFQUFFLENBQ3JDLENBQUM7UUFDSixDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0scUJBQXFCLENBQ3pCLElBQUEsK0NBQTRCLEVBQVUsc0JBQVcsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsRUFBRSxVQUFVLEVBQUUsQ0FBQyxFQUMvRixZQUFZLEVBQ1osVUFBVSxFQUNWLEVBQUUsNkJBQTZCLEVBQUUsQ0FBQyxFQUFFLENBQ3JDLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUywyQkFBMkIsQ0FDbEMsRUFBNEIsRUFDNUIsV0FBZ0MsRUFDaEMsS0FBYyxFQUNkLGdCQUF5QixFQUN6QixvQkFHQztJQUVELEVBQUUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQzFCLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBRyxFQUFFO1lBQ3ZCLElBQUEsaUNBQXlCLEVBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxnQkFBZ0IsRUFBRSxvQkFBb0IsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUN4RixDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sQ0FBQyxXQUFXLENBQ2hCLElBQUEsdUJBQWUsRUFBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLGdCQUFnQixFQUFFLG9CQUFvQixFQUFFLFdBQVcsQ0FBQyxFQUMzRSxLQUFLLEVBQ0wsSUFBSSxDQUFDLFNBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUNyQyxDQUFDO1FBQ0YsSUFBSSxvQkFBb0IsRUFBRSxjQUFjLEtBQUssU0FBUyxJQUFJLG9CQUFvQixFQUFFLFNBQVMsRUFBRSxDQUFDO1lBQzFGLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBQSxvQ0FBNEIsRUFBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLFdBQVcsRUFBRSxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUM5RyxDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxvQkFBb0IsQ0FDM0IsRUFBNEIsRUFDNUIsVUFBMEIsRUFDMUIsUUFBMEIsRUFDMUIsZ0JBQXlCO0lBRXpCLE1BQU0sV0FBVyxHQUFHLElBQUEsaUNBQWMsRUFBVSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBd0IsQ0FBQztJQUU3Ryx3REFBd0Q7SUFDeEQsMkJBQTJCLENBQVUsRUFBRSxFQUFFLFdBQVcsRUFBRSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0lBRTdGLHNCQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7UUFDeEIsb0VBQW9FO1FBQ3BFLDJCQUEyQixDQUFVLEVBQUUsRUFBRSxXQUFXLEVBQUUsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxnQkFBZ0IsRUFBRTtZQUM1RixTQUFTLEVBQUUsQ0FBQyxDQUFDLFNBQVM7U0FDdkIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCwyR0FBMkc7SUFDM0csTUFBTSxrQkFBa0IsR0FBRyxzQkFBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBRTdGLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxjQUFjLEVBQUUsRUFBRTtRQUNuQyxJQUFJLFVBQVUsS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUMxQiw2REFBNkQ7WUFDN0QsT0FBTztRQUNULENBQUM7UUFDRCxzQkFBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1lBQ3hCLDBGQUEwRjtZQUMxRiwyQkFBMkIsQ0FBVSxFQUFFLEVBQUUsV0FBVyxFQUFFLGNBQWMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLGdCQUFnQixFQUFFO2dCQUN4RyxjQUFjO2FBQ2YsQ0FBQyxDQUFDO1lBRUgsMEVBQTBFO1lBQzFFLDJCQUEyQixDQUN6QixFQUFFLEVBQ0YsV0FBVyxFQUNYLGNBQWMsS0FBSyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQ2hELGdCQUFnQixFQUNoQjtnQkFDRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLFNBQVM7Z0JBQ3RCLGNBQWM7YUFDZixDQUNGLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDMUIsTUFBTSxjQUFjLEdBQUcsQ0FBQyxHQUFjLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDeEYsTUFBTSxPQUFPLEdBQUcsc0JBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNwRCxNQUFNLFlBQVksR0FBRyxJQUFBLHFDQUE2QixFQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ2hGLE1BQU0sQ0FBQyxlQUFlLENBQ3BCLFlBQVksRUFDWixzQkFBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUM3QyxDQUFDO1FBQ0YsTUFBTSxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsWUFBWSxDQUFDLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRWxFLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QixJQUFBLHlDQUF1QixFQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRTtnQkFDckQsTUFBTSxDQUFDLFdBQVcsQ0FDaEIsY0FBYyxDQUFDLElBQUEscUNBQTZCLEVBQVUsV0FBVyxFQUFFLENBQUMsRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUMsRUFDNUYsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQ3BCLENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQztZQUVILElBQUksVUFBVSxLQUFLLE1BQU0sSUFBSSxVQUFVLEtBQUssWUFBWSxFQUFFLENBQUM7Z0JBQ3pELE1BQU0sQ0FBQyxNQUFNLENBQ1gsR0FBRyxFQUFFLENBQ0gsY0FBYyxDQUNaLElBQUEscUNBQTZCLEVBQVUsRUFBRSxFQUFFLENBQUMsRUFBRSxJQUFBLG9EQUFrQyxFQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FDM0csRUFDSCxxREFBcUQsQ0FDdEQsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUywyQkFBMkIsQ0FDbEMsT0FBZ0IsRUFDaEIsVUFBMEIsRUFDMUIsRUFBbUIsRUFDbkIsRUFBbUIsRUFDbkIsYUFBa0MsUUFBUTtJQUUxQyxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUNiLFFBQVEsQ0FBQyxtQkFBbUIsSUFBQSx5QkFBYyxFQUFDLE9BQU8sQ0FBQyxJQUFJLFVBQVUsSUFBSSxPQUFPLENBQUMsRUFBRSxDQUFDLElBQUksT0FBTyxDQUN6RixFQUFFLENBQ0gsSUFBSSxVQUFVLEVBQUUsRUFBRTtZQUNqQixFQUFFLENBQUMsc0JBQXNCLEVBQUU7Z0JBQ3pCLG9CQUFvQixDQUNsQixJQUFBLCtDQUE0QixFQUFVLHNCQUFXLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLEVBQUUsVUFBVSxFQUFFLENBQUMsRUFDL0YsVUFBVSxFQUNWLENBQUMsRUFBRSxDQUFDLEVBQ0osSUFBQSxpQkFBUyxFQUFVLDBDQUF1QixFQUFFLFVBQVUsQ0FBQyxDQUN4RCxDQUFDO1lBQ0osQ0FBQyxDQUFDLENBQUM7WUFFSCxFQUFFLENBQUMsc0JBQXNCLEVBQUU7Z0JBQ3pCLG9CQUFvQixDQUNsQixJQUFBLCtDQUE0QixFQUFVLHNCQUFXLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLEVBQUUsVUFBVSxFQUFFLENBQUMsRUFDL0YsVUFBVSxFQUNWLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUNSLElBQUEsaUJBQVMsRUFBVSwwQ0FBdUIsRUFBRSxVQUFVLENBQUMsQ0FDeEQsQ0FBQztZQUNKLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO1NBQU0sQ0FBQztRQUNOLFFBQVEsQ0FBQyxtQkFBbUIsSUFBQSx5QkFBYyxFQUFDLE9BQU8sQ0FBQyxJQUFJLFVBQVUsSUFBSSxVQUFVLFdBQVcsRUFBRTtZQUMxRixFQUFFLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ3RCLG9CQUFvQixDQUNsQixJQUFBLDZDQUEwQixFQUFVLHNCQUFXLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxFQUFFLFVBQVUsRUFBRSxDQUFDLEVBQ3JGLFVBQVUsRUFDVixFQUFFLEVBQ0YsSUFBQSxpQkFBUyxFQUFVLDBDQUF1QixFQUFFLFVBQVUsQ0FBQyxDQUN4RCxDQUFDO1lBQ0osQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7QUFDSCxDQUFDO0FBRUQsUUFBUSxDQUFDLDZCQUE2QixFQUFFO0lBQ3RDLElBQUEseUJBQWMsR0FBRTtTQUNiLE1BQU0sQ0FBQyxvQkFBUyxDQUFDO1FBQ2xCLDJGQUEyRjtRQUMzRixzQ0FBc0M7UUFDdEMsK0RBQStEO1NBQzlELE1BQU0sQ0FBQyxvQkFBUyxDQUFDO1NBQ2pCLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO1FBQ25CLGtCQUFrQixFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUU7WUFDMUMsMkJBQTJCLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBRWpELElBQUEseUNBQXNCLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRTtnQkFDekMsMkJBQTJCLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3pELDJCQUEyQixDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUN6RCxrQkFBa0IsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNsRCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0gsa0JBQWtCLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRTtZQUMxQywyQkFBMkIsQ0FBUyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFFekYsSUFBQSx5Q0FBc0IsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN6QywyQkFBMkIsQ0FBUyxPQUFPLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQzNFLDJCQUEyQixDQUFTLE9BQU8sRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxRQUFRLENBQUMsQ0FBQztnQkFDM0Usa0JBQWtCLENBQVMsT0FBTyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ3BFLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUMsQ0FBQyxDQUFDO0FBRUgsUUFBUSxDQUFDLHNCQUFzQixFQUFFO0lBQy9CLEVBQUUsQ0FBQyxnQkFBZ0IsRUFBRTtRQUNuQixNQUFNLGlCQUFpQixHQUFHLElBQUEsbURBQWdDLEVBQUMsc0JBQVcsRUFBRSxzQkFBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLG1CQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFMUcsaUJBQWlCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ3RDLE1BQU0sQ0FBQyxlQUFlLENBQ3BCLElBQUEsdUJBQVcsRUFBQyxJQUFBLDRCQUFvQixFQUFDLEtBQUssQ0FBQyxDQUFDLEVBQ3hDLElBQUEsdUJBQVcsRUFBQztnQkFDVixVQUFVLEVBQUUsVUFBVTtnQkFDdEIsVUFBVSxFQUFFLENBQUMsc0JBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7Z0JBQ3RDLFVBQVUsRUFBRTtvQkFDVixrSkFBa0o7aUJBQ25KO2FBQ0YsQ0FBQyxDQUNILENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsMkJBQTJCLENBQUMsbUJBQVEsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLHNCQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRSwyQkFBMkIsQ0FBUyxtQkFBUSxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsc0JBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFDekcsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcbmltcG9ydCB7IEJJUDMySW50ZXJmYWNlIH0gZnJvbSAnYmlwMzInO1xuXG5pbXBvcnQgeyBzY3JpcHQgYXMgYnNjcmlwdCwgY2xhc3NpZnksIFR4T3V0cHV0IH0gZnJvbSAnLi4vLi4vc3JjJztcbmltcG9ydCB7IGdldEtleU5hbWUgfSBmcm9tICcuLi8uLi9zcmMvdGVzdHV0aWwnO1xuaW1wb3J0IHsgZ2V0TmV0d29ya0xpc3QsIGdldE5ldHdvcmtOYW1lLCBpc0JpdGNvaW4sIGlzTWFpbm5ldCwgTmV0d29yaywgbmV0d29ya3MgfSBmcm9tICcuLi8uLi9zcmMvbmV0d29ya3MnO1xuXG5pbXBvcnQgeyBTY3JpcHRUeXBlLCBTY3JpcHRUeXBlMk9mMywgc2NyaXB0VHlwZXMyT2YzIH0gZnJvbSAnLi4vLi4vc3JjL2JpdGdvL291dHB1dFNjcmlwdHMnO1xuaW1wb3J0IHtcbiAgdmVyaWZ5U2lnbmF0dXJlLFxuICBVdHhvVHJhbnNhY3Rpb24sXG4gIHBhcnNlU2lnbmF0dXJlU2NyaXB0LFxuICBnZXRTaWduYXR1cmVWZXJpZmljYXRpb25zLFxuICB2ZXJpZnlTaWduYXR1cmVXaXRoUHVibGljS2V5cyxcbiAgdmVyaWZ5U2lnbmF0dXJlV2l0aFB1YmxpY0tleSxcbiAgaXNQbGFjZWhvbGRlclNpZ25hdHVyZSxcbiAgdG9UTnVtYmVyLFxufSBmcm9tICcuLi8uLi9zcmMvYml0Z28nO1xuXG5pbXBvcnQgKiBhcyBmaXh0dXJlVXRpbCBmcm9tICcuLi9maXh0dXJlLnV0aWwnO1xuXG5pbXBvcnQgeyBmaXh0dXJlS2V5cyB9IGZyb20gJy4uL2ludGVncmF0aW9uX2xvY2FsX3JwYy9nZW5lcmF0ZS9maXh0dXJlcyc7XG5pbXBvcnQge1xuICBkZWZhdWx0VGVzdE91dHB1dEFtb3VudCxcbiAgZ2V0RnVsbFNpZ25lZFRyYW5zYWN0aW9uMk9mMyxcbiAgZ2V0RnVsbFNpZ25lZFRyYW5zYWN0aW9uUDJzaFAycGssXG4gIGdldEhhbGZTaWduZWRUcmFuc2FjdGlvbjJPZjMsXG4gIGdldFByZXZPdXRwdXRzLFxuICBnZXRTaWduS2V5Q29tYmluYXRpb25zLFxuICBnZXRVbnNpZ25lZFRyYW5zYWN0aW9uMk9mMyxcbn0gZnJvbSAnLi4vdHJhbnNhY3Rpb25fdXRpbCc7XG5pbXBvcnQgeyBnZXRQcmV2T3V0c1dpdGhJbnZhbGlkT3V0cHV0U2NyaXB0LCBnZXRUcmFuc2FjdGlvbldpdGhIaWdoUyB9IGZyb20gJy4vc2lnbmF0dXJlTW9kaWZ5JztcbmltcG9ydCB7IG5vcm1EZWZhdWx0IH0gZnJvbSAnLi4vdGVzdHV0aWwvbm9ybWFsaXplJztcblxuZnVuY3Rpb24gZ2V0U2NyaXB0VHlwZXMyT2YzKCkge1xuICAvLyBGSVhNRShCRy02Njk0MSk6IHAydHJNdXNpZzIgc2lnbmluZyBkb2VzIG5vdCB3b3JrIGluIHRoaXMgdGVzdCBzdWl0ZSB5ZXRcbiAgLy8gIGJlY2F1c2UgdGhlIHRlc3Qgc3VpdGUgaXMgd3JpdHRlbiB3aXRoIFRyYW5zYWN0aW9uQnVpbGRlclxuICByZXR1cm4gc2NyaXB0VHlwZXMyT2YzLmZpbHRlcigoc2NyaXB0VHlwZSkgPT4gc2NyaXB0VHlwZSAhPT0gJ3AydHJNdXNpZzInKTtcbn1cblxuZnVuY3Rpb24ga2V5TmFtZShrOiBCSVAzMkludGVyZmFjZSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiBnZXRLZXlOYW1lKGZpeHR1cmVLZXlzLCBrKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZEZpeHR1cmU8VD4oXG4gIG5ldHdvcms6IE5ldHdvcmssXG4gIHNjcmlwdFR5cGU6IFNjcmlwdFR5cGUyT2YzIHwgJ3Ayc2hQMnBrJyxcbiAgbmFtZTogc3RyaW5nLFxuICBkZWZhdWx0VmFsdWU6IFRcbik6IFByb21pc2U8VD4ge1xuICByZXR1cm4gYXdhaXQgZml4dHVyZVV0aWwucmVhZEZpeHR1cmUoXG4gICAgYCR7X19kaXJuYW1lfS9maXh0dXJlcy9zaWduYXR1cmUvJHtnZXROZXR3b3JrTmFtZShuZXR3b3JrKX0vJHtzY3JpcHRUeXBlfS8ke25hbWV9Lmpzb25gLFxuICAgIGRlZmF1bHRWYWx1ZVxuICApO1xufVxuXG5mdW5jdGlvbiBydW5UZXN0Q2hlY2tTY3JpcHRTdHJ1Y3R1cmU8VE51bWJlciBleHRlbmRzIG51bWJlciB8IGJpZ2ludCA9IG51bWJlcj4oXG4gIG5ldHdvcms6IE5ldHdvcmssXG4gIHNjcmlwdFR5cGU6IFNjcmlwdFR5cGUyT2YzIHwgJ3Ayc2hQMnBrJyxcbiAgc2lnbmVyMTogQklQMzJJbnRlcmZhY2UsXG4gIHNpZ25lcjI/OiBCSVAzMkludGVyZmFjZSxcbiAgYW1vdW50VHlwZTogJ251bWJlcicgfCAnYmlnaW50JyA9ICdudW1iZXInXG4pIHtcbiAgaXQoXG4gICAgYGhhcyBleHBlY3RlZCBzY3JpcHQgc3RydWN0dXJlIFske2dldE5ldHdvcmtOYW1lKG5ldHdvcmspfSAke3NjcmlwdFR5cGV9IGAgK1xuICAgICAgYCR7a2V5TmFtZShzaWduZXIxKX0gJHtzaWduZXIyID8ga2V5TmFtZShzaWduZXIyKSA6ICcnfSAke2Ftb3VudFR5cGV9XWAsXG4gICAgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHR4O1xuXG4gICAgICBpZiAoc2NyaXB0VHlwZSA9PT0gJ3Ayc2hQMnBrJykge1xuICAgICAgICB0eCA9IGdldEZ1bGxTaWduZWRUcmFuc2FjdGlvblAyc2hQMnBrPFROdW1iZXI+KGZpeHR1cmVLZXlzLCBzaWduZXIxLCBuZXR3b3JrLCB7IGFtb3VudFR5cGUgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoIXNpZ25lcjIpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYG11c3Qgc2V0IGNvc2lnbmVyYCk7XG4gICAgICAgIH1cbiAgICAgICAgdHggPSBnZXRGdWxsU2lnbmVkVHJhbnNhY3Rpb24yT2YzPFROdW1iZXI+KGZpeHR1cmVLZXlzLCBzaWduZXIxLCBzaWduZXIyLCBzY3JpcHRUeXBlLCBuZXR3b3JrLCB7IGFtb3VudFR5cGUgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHsgc2NyaXB0LCB3aXRuZXNzIH0gPSB0eC5pbnNbMF07XG4gICAgICBjb25zdCBzY3JpcHREZWNvbXBpbGVkID0gYnNjcmlwdC5kZWNvbXBpbGUoc2NyaXB0KTtcbiAgICAgIGlmICghc2NyaXB0RGVjb21waWxlZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNjcmlwdEFTTSA9IGJzY3JpcHQudG9BU00oc2NyaXB0KS5zcGxpdCgnICcpO1xuICAgICAgY29uc3QgY2xhc3NpZnlJbnB1dCA9IGNsYXNzaWZ5LmlucHV0KHNjcmlwdCk7XG4gICAgICBjb25zdCBjbGFzc2lmeVdpdG5lc3MgPSBjbGFzc2lmeS53aXRuZXNzKHdpdG5lc3MpO1xuXG4gICAgICBsZXQgcHViU2NyaXB0O1xuICAgICAgbGV0IGNsYXNzaWZ5UHViU2NyaXB0O1xuICAgICAgbGV0IHB1YlNjcmlwdEFTTTtcblxuICAgICAgbGV0IHRhcHNjcmlwdDtcbiAgICAgIGxldCB0YXBzY3JpcHRBU007XG4gICAgICBsZXQgY2xhc3NpZnlUYXBzY3JpcHQ7XG5cbiAgICAgIGlmIChjbGFzc2lmeUlucHV0ID09PSAnc2NyaXB0aGFzaCcgfHwgY2xhc3NpZnlXaXRuZXNzID09PSAnd2l0bmVzc3NjcmlwdGhhc2gnKSB7XG4gICAgICAgIGlmICh3aXRuZXNzLmxlbmd0aCkge1xuICAgICAgICAgIHB1YlNjcmlwdCA9IHdpdG5lc3Nbd2l0bmVzcy5sZW5ndGggLSAxXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwdWJTY3JpcHQgPSBzY3JpcHREZWNvbXBpbGVkW3NjcmlwdERlY29tcGlsZWQubGVuZ3RoIC0gMV0gYXMgQnVmZmVyO1xuICAgICAgICB9XG5cbiAgICAgICAgY2xhc3NpZnlQdWJTY3JpcHQgPSBjbGFzc2lmeS5vdXRwdXQocHViU2NyaXB0KTtcbiAgICAgICAgcHViU2NyaXB0QVNNID0gYnNjcmlwdC50b0FTTShwdWJTY3JpcHQpLnNwbGl0KCcgJyk7XG4gICAgICB9IGVsc2UgaWYgKGNsYXNzaWZ5V2l0bmVzcyA9PT0gJ3RhcHJvb3QnKSB7XG4gICAgICAgIHRhcHNjcmlwdCA9IHdpdG5lc3Nbd2l0bmVzcy5sZW5ndGggLSAyXTtcbiAgICAgICAgY2xhc3NpZnlUYXBzY3JpcHQgPSBjbGFzc2lmeS5vdXRwdXQodGFwc2NyaXB0KTtcbiAgICAgICAgdGFwc2NyaXB0QVNNID0gYnNjcmlwdC50b0FTTSh0YXBzY3JpcHQpLnNwbGl0KCcgJyk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHN0cnVjdHVyZSA9IHtcbiAgICAgICAgcHVibGljS2V5czogZml4dHVyZUtleXMubWFwKChrKSA9PiBrLnB1YmxpY0tleS50b1N0cmluZygnaGV4JykpLFxuICAgICAgICBzY3JpcHQ6IHNjcmlwdD8udG9TdHJpbmcoJ2hleCcpLFxuICAgICAgICB3aXRuZXNzOiB3aXRuZXNzPy5tYXAoKHcpID0+IHcudG9TdHJpbmcoJ2hleCcpKSxcbiAgICAgICAgc2NyaXB0QVNNLFxuICAgICAgICBwdWJTY3JpcHRBU00sXG4gICAgICAgIHRhcHNjcmlwdEFTTSxcbiAgICAgICAgY2xhc3NpZnlJbnB1dCxcbiAgICAgICAgY2xhc3NpZnlXaXRuZXNzLFxuICAgICAgICBjbGFzc2lmeVB1YlNjcmlwdCxcbiAgICAgICAgY2xhc3NpZnlUYXBzY3JpcHQsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBmaXh0dXJlTmFtZSA9IFsnc3RydWN0dXJlJywga2V5TmFtZShzaWduZXIxKSwgc2lnbmVyMiA/IGtleU5hbWUoc2lnbmVyMikgOiAnbm9uZSddLmpvaW4oJy0nKTtcbiAgICAgIGZpeHR1cmVVdGlsLmFzc2VydEVxdWFsSlNPTihzdHJ1Y3R1cmUsIGF3YWl0IHJlYWRGaXh0dXJlKG5ldHdvcmssIHNjcmlwdFR5cGUsIGZpeHR1cmVOYW1lLCBzdHJ1Y3R1cmUpKTtcbiAgICB9XG4gICk7XG59XG5cbmZ1bmN0aW9uIHJ1blRlc3RQYXJzZVNjcmlwdDxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50ID0gbnVtYmVyPihcbiAgbmV0d29yazogTmV0d29yayxcbiAgc2NyaXB0VHlwZTogU2NyaXB0VHlwZSxcbiAgazE6IEJJUDMySW50ZXJmYWNlLFxuICBrMjogQklQMzJJbnRlcmZhY2UsXG4gIGFtb3VudFR5cGU6ICdudW1iZXInIHwgJ2JpZ2ludCcgPSAnbnVtYmVyJ1xuKSB7XG4gIGFzeW5jIGZ1bmN0aW9uIHRlc3RQYXJzZVNpZ25lZElucHV0cyhcbiAgICB0eDogVXR4b1RyYW5zYWN0aW9uPFROdW1iZXI+LFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBleHBlY3RlZFNjcmlwdFR5cGU6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICB7IGV4cGVjdGVkUGxhY2Vob2xkZXJTaWduYXR1cmVzIH06IHsgZXhwZWN0ZWRQbGFjZWhvbGRlclNpZ25hdHVyZXM6IG51bWJlciB9XG4gICkge1xuICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlU2lnbmF0dXJlU2NyaXB0KHR4Lmluc1swXSk7XG4gICAgYXNzZXJ0LnN0cmljdEVxdWFsKFxuICAgICAgcGFyc2VkLnNjcmlwdFR5cGUsXG4gICAgICBleHBlY3RlZFNjcmlwdFR5cGUgPT09ICdwMnRyJyA/ICd0YXByb290U2NyaXB0UGF0aFNwZW5kJyA6IGV4cGVjdGVkU2NyaXB0VHlwZVxuICAgICk7XG4gICAgY29uc3QgcGFyc2VkMk9mMyA9IHsgLi4ucGFyc2VkLCBzY3JpcHRUeXBlOiBleHBlY3RlZFNjcmlwdFR5cGUgfTtcbiAgICBmaXh0dXJlVXRpbC5hc3NlcnRFcXVhbEpTT04oXG4gICAgICBwYXJzZWQyT2YzLFxuICAgICAgYXdhaXQgcmVhZEZpeHR1cmUobmV0d29yaywgc2NyaXB0VHlwZSwgWydwYXJzZWQnLCBrZXlOYW1lKGsxKSwga2V5TmFtZShrMiksIG5hbWVdLmpvaW4oJy0nKSwgcGFyc2VkMk9mMylcbiAgICApO1xuXG4gICAgaWYgKCFwYXJzZWQuc2NyaXB0VHlwZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHN3aXRjaCAocGFyc2VkLnNjcmlwdFR5cGUpIHtcbiAgICAgIGNhc2UgJ3Ayc2hQMnBrJzpcbiAgICAgICAgLy8gd2UgZG9uJ3QgcGFyc2UgdGhlIHNpZ25hdHVyZSBmb3IgdGhpcyBzY3JpcHQgdHlwZVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3Ayc2gnOlxuICAgICAgY2FzZSAncDJzaFAyd3NoJzpcbiAgICAgIGNhc2UgJ3Ayd3NoJzpcbiAgICAgIGNhc2UgJ3RhcHJvb3RTY3JpcHRQYXRoU3BlbmQnOlxuICAgICAgICBhc3NlcnQuc3RyaWN0RXF1YWwoXG4gICAgICAgICAgcGFyc2VkLnNpZ25hdHVyZXMuZmlsdGVyKChzKSA9PiBpc1BsYWNlaG9sZGVyU2lnbmF0dXJlKHMpKS5sZW5ndGgsXG4gICAgICAgICAgZXhwZWN0ZWRQbGFjZWhvbGRlclNpZ25hdHVyZXNcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgc2NyaXB0VHlwZSAkeyhwYXJzZWQgYXMgYW55KS5zY3JpcHRUeXBlfWApO1xuICAgIH1cbiAgfVxuXG4gIGlmIChzY3JpcHRUeXBlICE9PSAncDJzaFAycGsnKSB7XG4gICAgaXQoYHBhcnNlcyBoYWxmLXNpZ25lZCBpbnB1dHMgWyR7Z2V0TmV0d29ya05hbWUobmV0d29yayl9ICR7c2NyaXB0VHlwZX0gJHthbW91bnRUeXBlfV1gLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCB0ZXN0UGFyc2VTaWduZWRJbnB1dHMoXG4gICAgICAgIGdldEhhbGZTaWduZWRUcmFuc2FjdGlvbjJPZjM8VE51bWJlcj4oZml4dHVyZUtleXMsIGsxLCBrMiwgc2NyaXB0VHlwZSwgbmV0d29yaywgeyBhbW91bnRUeXBlIH0pLFxuICAgICAgICAnaGFsZlNpZ25lZCcsXG4gICAgICAgIHNjcmlwdFR5cGUsXG4gICAgICAgIHsgZXhwZWN0ZWRQbGFjZWhvbGRlclNpZ25hdHVyZXM6IHNjcmlwdFR5cGUgPT09ICdwMnRyJyA/IDEgOiAyIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBpdChgcGFyc2VzIGZ1bGwtc2lnbmVkIGlucHV0cyBbJHtnZXROZXR3b3JrTmFtZShuZXR3b3JrKX0gJHtzY3JpcHRUeXBlfSAke2Ftb3VudFR5cGV9XWAsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoc2NyaXB0VHlwZSA9PT0gJ3Ayc2hQMnBrJykge1xuICAgICAgYXdhaXQgdGVzdFBhcnNlU2lnbmVkSW5wdXRzKFxuICAgICAgICBnZXRGdWxsU2lnbmVkVHJhbnNhY3Rpb25QMnNoUDJwazxUTnVtYmVyPihmaXh0dXJlS2V5cywgazEsIG5ldHdvcmssIHsgYW1vdW50VHlwZSB9KSxcbiAgICAgICAgJ2Z1bGxTaWduZWQnLFxuICAgICAgICBzY3JpcHRUeXBlLFxuICAgICAgICB7IGV4cGVjdGVkUGxhY2Vob2xkZXJTaWduYXR1cmVzOiAwIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRlc3RQYXJzZVNpZ25lZElucHV0cyhcbiAgICAgICAgZ2V0RnVsbFNpZ25lZFRyYW5zYWN0aW9uMk9mMzxUTnVtYmVyPihmaXh0dXJlS2V5cywgazEsIGsyLCBzY3JpcHRUeXBlLCBuZXR3b3JrLCB7IGFtb3VudFR5cGUgfSksXG4gICAgICAgICdmdWxsU2lnbmVkJyxcbiAgICAgICAgc2NyaXB0VHlwZSxcbiAgICAgICAgeyBleHBlY3RlZFBsYWNlaG9sZGVyU2lnbmF0dXJlczogMCB9XG4gICAgICApO1xuICAgIH1cbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGFzc2VydFZlcmlmeVNpZ25hdHVyZUVxdWFsczxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50PihcbiAgdHg6IFV0eG9UcmFuc2FjdGlvbjxUTnVtYmVyPixcbiAgcHJldk91dHB1dHM6IFR4T3V0cHV0PFROdW1iZXI+W10sXG4gIHZhbHVlOiBib29sZWFuLFxuICB0ZXN0T3V0cHV0QW1vdW50OiBUTnVtYmVyLFxuICB2ZXJpZmljYXRpb25TZXR0aW5ncz86IHtcbiAgICBwdWJsaWNLZXk/OiBCdWZmZXI7XG4gICAgc2lnbmF0dXJlSW5kZXg/OiBudW1iZXI7XG4gIH1cbikge1xuICB0eC5pbnMuZm9yRWFjaCgoaW5wdXQsIGkpID0+IHtcbiAgICBhc3NlcnQuZG9lc05vdFRocm93KCgpID0+IHtcbiAgICAgIGdldFNpZ25hdHVyZVZlcmlmaWNhdGlvbnModHgsIGksIHRlc3RPdXRwdXRBbW91bnQsIHZlcmlmaWNhdGlvblNldHRpbmdzLCBwcmV2T3V0cHV0cyk7XG4gICAgfSk7XG4gICAgYXNzZXJ0LnN0cmljdEVxdWFsKFxuICAgICAgdmVyaWZ5U2lnbmF0dXJlKHR4LCBpLCB0ZXN0T3V0cHV0QW1vdW50LCB2ZXJpZmljYXRpb25TZXR0aW5ncywgcHJldk91dHB1dHMpLFxuICAgICAgdmFsdWUsXG4gICAgICBKU09OLnN0cmluZ2lmeSh2ZXJpZmljYXRpb25TZXR0aW5ncylcbiAgICApO1xuICAgIGlmICh2ZXJpZmljYXRpb25TZXR0aW5ncz8uc2lnbmF0dXJlSW5kZXggPT09IHVuZGVmaW5lZCAmJiB2ZXJpZmljYXRpb25TZXR0aW5ncz8ucHVibGljS2V5KSB7XG4gICAgICBhc3NlcnQuc3RyaWN0RXF1YWwodmVyaWZ5U2lnbmF0dXJlV2l0aFB1YmxpY0tleSh0eCwgaSwgcHJldk91dHB1dHMsIHZlcmlmaWNhdGlvblNldHRpbmdzLnB1YmxpY0tleSksIHZhbHVlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBjaGVja1NpZ25UcmFuc2FjdGlvbjxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50PihcbiAgdHg6IFV0eG9UcmFuc2FjdGlvbjxUTnVtYmVyPixcbiAgc2NyaXB0VHlwZTogU2NyaXB0VHlwZTJPZjMsXG4gIHNpZ25LZXlzOiBCSVAzMkludGVyZmFjZVtdLFxuICB0ZXN0T3V0cHV0QW1vdW50OiBUTnVtYmVyXG4pIHtcbiAgY29uc3QgcHJldk91dHB1dHMgPSBnZXRQcmV2T3V0cHV0czxUTnVtYmVyPihzY3JpcHRUeXBlLCB0ZXN0T3V0cHV0QW1vdW50LCB0eC5uZXR3b3JrKSBhcyBUeE91dHB1dDxUTnVtYmVyPltdO1xuXG4gIC8vIHJldHVybiB0cnVlIGlmZiB0aGVyZSBhcmUgYW55IHZhbGlkIHNpZ25hdHVyZXMgYXQgYWxsXG4gIGFzc2VydFZlcmlmeVNpZ25hdHVyZUVxdWFsczxUTnVtYmVyPih0eCwgcHJldk91dHB1dHMsIHNpZ25LZXlzLmxlbmd0aCA+IDAsIHRlc3RPdXRwdXRBbW91bnQpO1xuXG4gIGZpeHR1cmVLZXlzLmZvckVhY2goKGspID0+IHtcbiAgICAvLyBpZiBwdWJsaWNLZXkgaXMgZ2l2ZW4sIHJldHVybiB0cnVlIGlmZiBpdCBpcyBpbmNsdWRlZCBpbiBzaWduS2V5c1xuICAgIGFzc2VydFZlcmlmeVNpZ25hdHVyZUVxdWFsczxUTnVtYmVyPih0eCwgcHJldk91dHB1dHMsIHNpZ25LZXlzLmluY2x1ZGVzKGspLCB0ZXN0T3V0cHV0QW1vdW50LCB7XG4gICAgICBwdWJsaWNLZXk6IGsucHVibGljS2V5LFxuICAgIH0pO1xuICB9KTtcblxuICAvLyBXaGVuIHRyYW5zYWN0aW9ucyBhcmUgc2lnbmVkLCB0aGUgc2lnbmF0dXJlcyBoYXZlIHRoZSBzYW1lIG9yZGVyIGFzIHRoZSBwdWJsaWMga2V5cyBpbiB0aGUgb3V0cHV0U2NyaXB0LlxuICBjb25zdCBvcmRlcmVkU2lnbmluZ0tleXMgPSBmaXh0dXJlS2V5cy5maWx0ZXIoKGZpeHR1cmVLZXkpID0+IHNpZ25LZXlzLmluY2x1ZGVzKGZpeHR1cmVLZXkpKTtcblxuICBbMCwgMSwgMl0uZm9yRWFjaCgoc2lnbmF0dXJlSW5kZXgpID0+IHtcbiAgICBpZiAoc2NyaXB0VHlwZSA9PT0gJ3AydHInKSB7XG4gICAgICAvLyBzaWduYXR1cmVJbmRleCBwYXJhbWV0ZXIgbm90IHN1cHBvcnQgZm9yIHAydHIgdmVyaWZpY2F0aW9uXG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGZpeHR1cmVLZXlzLmZvckVhY2goKGspID0+IHtcbiAgICAgIC8vIElmIG5vIHB1YmxpYyBrZXkgaXMgZ2l2ZW4sIHJldHVybiB0cnVlIGlmZiBhbnkgdmFsaWQgc2lnbmF0dXJlIHdpdGggZ2l2ZW4gaW5kZXggZXhpc3RzLlxuICAgICAgYXNzZXJ0VmVyaWZ5U2lnbmF0dXJlRXF1YWxzPFROdW1iZXI+KHR4LCBwcmV2T3V0cHV0cywgc2lnbmF0dXJlSW5kZXggPCBzaWduS2V5cy5sZW5ndGgsIHRlc3RPdXRwdXRBbW91bnQsIHtcbiAgICAgICAgc2lnbmF0dXJlSW5kZXgsXG4gICAgICB9KTtcblxuICAgICAgLy8gSWYgcHVibGljS2V5IGFuZCBzaWduYXR1cmVJbmRleCBhcmUgcHJvdmlkZWQgb25seSByZXR1cm4gaWYgYm90aCBtYXRjaC5cbiAgICAgIGFzc2VydFZlcmlmeVNpZ25hdHVyZUVxdWFsczxUTnVtYmVyPihcbiAgICAgICAgdHgsXG4gICAgICAgIHByZXZPdXRwdXRzLFxuICAgICAgICBzaWduYXR1cmVJbmRleCA9PT0gb3JkZXJlZFNpZ25pbmdLZXlzLmluZGV4T2YoayksXG4gICAgICAgIHRlc3RPdXRwdXRBbW91bnQsXG4gICAgICAgIHtcbiAgICAgICAgICBwdWJsaWNLZXk6IGsucHVibGljS2V5LFxuICAgICAgICAgIHNpZ25hdHVyZUluZGV4LFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcblxuICB0eC5pbnMuZm9yRWFjaCgoaW5wdXQsIGkpID0+IHtcbiAgICBjb25zdCBzaWduYXR1cmVDb3VudCA9IChyZXM6IGJvb2xlYW5bXSkgPT4gcmVzLnJlZHVjZSgoc3VtLCBiKSA9PiBzdW0gKyAoYiA/IDEgOiAwKSwgMCk7XG4gICAgY29uc3QgcHVia2V5cyA9IGZpeHR1cmVLZXlzLm1hcCgoaykgPT4gay5wdWJsaWNLZXkpO1xuICAgIGNvbnN0IHZlcmlmeVJlc3VsdCA9IHZlcmlmeVNpZ25hdHVyZVdpdGhQdWJsaWNLZXlzKHR4LCBpLCBwcmV2T3V0cHV0cywgcHVia2V5cyk7XG4gICAgYXNzZXJ0LmRlZXBTdHJpY3RFcXVhbChcbiAgICAgIHZlcmlmeVJlc3VsdCxcbiAgICAgIGZpeHR1cmVLZXlzLm1hcCgoaykgPT4gc2lnbktleXMuaW5jbHVkZXMoaykpXG4gICAgKTtcbiAgICBhc3NlcnQuc3RyaWN0RXF1YWwoc2lnbmF0dXJlQ291bnQodmVyaWZ5UmVzdWx0KSwgc2lnbktleXMubGVuZ3RoKTtcblxuICAgIGlmIChzaWduS2V5cy5sZW5ndGggPiAwKSB7XG4gICAgICBnZXRUcmFuc2FjdGlvbldpdGhIaWdoUyh0eCwgaSkuZm9yRWFjaCgodHhXaXRoSGlnaFMpID0+IHtcbiAgICAgICAgYXNzZXJ0LnN0cmljdEVxdWFsKFxuICAgICAgICAgIHNpZ25hdHVyZUNvdW50KHZlcmlmeVNpZ25hdHVyZVdpdGhQdWJsaWNLZXlzPFROdW1iZXI+KHR4V2l0aEhpZ2hTLCBpLCBwcmV2T3V0cHV0cywgcHVia2V5cykpLFxuICAgICAgICAgIHNpZ25LZXlzLmxlbmd0aCAtIDFcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoc2NyaXB0VHlwZSAhPT0gJ3AydHInICYmIHNjcmlwdFR5cGUgIT09ICdwMnRyTXVzaWcyJykge1xuICAgICAgICBhc3NlcnQudGhyb3dzKFxuICAgICAgICAgICgpID0+XG4gICAgICAgICAgICBzaWduYXR1cmVDb3VudChcbiAgICAgICAgICAgICAgdmVyaWZ5U2lnbmF0dXJlV2l0aFB1YmxpY0tleXM8VE51bWJlcj4odHgsIGksIGdldFByZXZPdXRzV2l0aEludmFsaWRPdXRwdXRTY3JpcHQocHJldk91dHB1dHMsIGkpLCBwdWJrZXlzKVxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAvcHJldm91dCBzY3JpcHQgLiogZG9lcyBub3QgbWF0Y2ggY29tcHV0ZWQgc2NyaXB0IC4qL1xuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59XG5cbmZ1bmN0aW9uIHJ1blRlc3RDaGVja1NpZ25hdHVyZVZlcmlmeTxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50ID0gbnVtYmVyPihcbiAgbmV0d29yazogTmV0d29yayxcbiAgc2NyaXB0VHlwZTogU2NyaXB0VHlwZTJPZjMsXG4gIGsxPzogQklQMzJJbnRlcmZhY2UsXG4gIGsyPzogQklQMzJJbnRlcmZhY2UsXG4gIGFtb3VudFR5cGU6ICdudW1iZXInIHwgJ2JpZ2ludCcgPSAnbnVtYmVyJ1xuKSB7XG4gIGlmIChrMSAmJiBrMikge1xuICAgIGRlc2NyaWJlKGB2ZXJpZnlTaWduYXR1cmUgJHtnZXROZXR3b3JrTmFtZShuZXR3b3JrKX0gJHtzY3JpcHRUeXBlfSAke2tleU5hbWUoazEpfSAke2tleU5hbWUoXG4gICAgICBrMlxuICAgICl9ICR7YW1vdW50VHlwZX1gLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdChgdmVyaWZpZXMgaGFsZi1zaWduZWRgLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNoZWNrU2lnblRyYW5zYWN0aW9uKFxuICAgICAgICAgIGdldEhhbGZTaWduZWRUcmFuc2FjdGlvbjJPZjM8VE51bWJlcj4oZml4dHVyZUtleXMsIGsxLCBrMiwgc2NyaXB0VHlwZSwgbmV0d29yaywgeyBhbW91bnRUeXBlIH0pLFxuICAgICAgICAgIHNjcmlwdFR5cGUsXG4gICAgICAgICAgW2sxXSxcbiAgICAgICAgICB0b1ROdW1iZXI8VE51bWJlcj4oZGVmYXVsdFRlc3RPdXRwdXRBbW91bnQsIGFtb3VudFR5cGUpXG4gICAgICAgICk7XG4gICAgICB9KTtcblxuICAgICAgaXQoYHZlcmlmaWVzIGZ1bGwtc2lnbmVkYCwgZnVuY3Rpb24gKCkge1xuICAgICAgICBjaGVja1NpZ25UcmFuc2FjdGlvbihcbiAgICAgICAgICBnZXRGdWxsU2lnbmVkVHJhbnNhY3Rpb24yT2YzPFROdW1iZXI+KGZpeHR1cmVLZXlzLCBrMSwgazIsIHNjcmlwdFR5cGUsIG5ldHdvcmssIHsgYW1vdW50VHlwZSB9KSxcbiAgICAgICAgICBzY3JpcHRUeXBlLFxuICAgICAgICAgIFtrMSwgazJdLFxuICAgICAgICAgIHRvVE51bWJlcjxUTnVtYmVyPihkZWZhdWx0VGVzdE91dHB1dEFtb3VudCwgYW1vdW50VHlwZSlcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIGRlc2NyaWJlKGB2ZXJpZnlTaWduYXR1cmUgJHtnZXROZXR3b3JrTmFtZShuZXR3b3JrKX0gJHtzY3JpcHRUeXBlfSAke2Ftb3VudFR5cGV9IHVuc2lnbmVkYCwgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoYHZlcmlmaWVzIHVuc2lnbmVkYCwgZnVuY3Rpb24gKCkge1xuICAgICAgICBjaGVja1NpZ25UcmFuc2FjdGlvbihcbiAgICAgICAgICBnZXRVbnNpZ25lZFRyYW5zYWN0aW9uMk9mMzxUTnVtYmVyPihmaXh0dXJlS2V5cywgc2NyaXB0VHlwZSwgbmV0d29yaywgeyBhbW91bnRUeXBlIH0pLFxuICAgICAgICAgIHNjcmlwdFR5cGUsXG4gICAgICAgICAgW10sXG4gICAgICAgICAgdG9UTnVtYmVyPFROdW1iZXI+KGRlZmF1bHRUZXN0T3V0cHV0QW1vdW50LCBhbW91bnRUeXBlKVxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbn1cblxuZGVzY3JpYmUoJ1NpZ25hdHVyZSAoc2NyaXB0VHlwZXMyT2YzKScsIGZ1bmN0aW9uICgpIHtcbiAgZ2V0TmV0d29ya0xpc3QoKVxuICAgIC5maWx0ZXIoaXNNYWlubmV0KVxuICAgIC8vIFRoZSBzaWduaW5nIGFuZCB2ZXJpZmljYXRpb24gbWV0aG9kcyBhcmUgbGFyZ2VseSBuZXR3b3JrLWluZGVwZW5kZW50IHNvIGxldCdzIGZvY3VzIG9uIGFcbiAgICAvLyBzaW5nbGUgbmV0d29yayB0byByZWR1Y2UgdGVzdCB0aW1lLlxuICAgIC8vIER1cmluZyBkZXZlbG9wbWVudCBpdCBtaWdodCBtYWtlIHNlbnNlIHRvIHRlc3QgYWxsIG5ldHdvcmtzLlxuICAgIC5maWx0ZXIoaXNCaXRjb2luKVxuICAgIC5mb3JFYWNoKChuZXR3b3JrKSA9PiB7XG4gICAgICBnZXRTY3JpcHRUeXBlczJPZjMoKS5mb3JFYWNoKChzY3JpcHRUeXBlKSA9PiB7XG4gICAgICAgIHJ1blRlc3RDaGVja1NpZ25hdHVyZVZlcmlmeShuZXR3b3JrLCBzY3JpcHRUeXBlKTtcblxuICAgICAgICBnZXRTaWduS2V5Q29tYmluYXRpb25zKDIpLm1hcCgoW2sxLCBrMl0pID0+IHtcbiAgICAgICAgICBydW5UZXN0Q2hlY2tTaWduYXR1cmVWZXJpZnkobmV0d29yaywgc2NyaXB0VHlwZSwgazEsIGsyKTtcbiAgICAgICAgICBydW5UZXN0Q2hlY2tTY3JpcHRTdHJ1Y3R1cmUobmV0d29yaywgc2NyaXB0VHlwZSwgazEsIGsyKTtcbiAgICAgICAgICBydW5UZXN0UGFyc2VTY3JpcHQobmV0d29yaywgc2NyaXB0VHlwZSwgazEsIGsyKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIGdldFNjcmlwdFR5cGVzMk9mMygpLmZvckVhY2goKHNjcmlwdFR5cGUpID0+IHtcbiAgICAgICAgcnVuVGVzdENoZWNrU2lnbmF0dXJlVmVyaWZ5PGJpZ2ludD4obmV0d29yaywgc2NyaXB0VHlwZSwgdW5kZWZpbmVkLCB1bmRlZmluZWQsICdiaWdpbnQnKTtcblxuICAgICAgICBnZXRTaWduS2V5Q29tYmluYXRpb25zKDIpLm1hcCgoW2sxLCBrMl0pID0+IHtcbiAgICAgICAgICBydW5UZXN0Q2hlY2tTaWduYXR1cmVWZXJpZnk8YmlnaW50PihuZXR3b3JrLCBzY3JpcHRUeXBlLCBrMSwgazIsICdiaWdpbnQnKTtcbiAgICAgICAgICBydW5UZXN0Q2hlY2tTY3JpcHRTdHJ1Y3R1cmU8YmlnaW50PihuZXR3b3JrLCBzY3JpcHRUeXBlLCBrMSwgazIsICdiaWdpbnQnKTtcbiAgICAgICAgICBydW5UZXN0UGFyc2VTY3JpcHQ8YmlnaW50PihuZXR3b3JrLCBzY3JpcHRUeXBlLCBrMSwgazIsICdiaWdpbnQnKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbn0pO1xuXG5kZXNjcmliZSgnU2lnbmF0dXJlIChwMnNoUDJwayknLCBmdW5jdGlvbiAoKSB7XG4gIGl0KCdzaWduIGFuZCBwYXJzZScsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBzaWduZWRUcmFuc2FjdGlvbiA9IGdldEZ1bGxTaWduZWRUcmFuc2FjdGlvblAyc2hQMnBrKGZpeHR1cmVLZXlzLCBmaXh0dXJlS2V5c1swXSwgbmV0d29ya3MuYml0Y29pbik7XG5cbiAgICBzaWduZWRUcmFuc2FjdGlvbi5pbnMuZm9yRWFjaCgoaW5wdXQpID0+IHtcbiAgICAgIGFzc2VydC5kZWVwU3RyaWN0RXF1YWwoXG4gICAgICAgIG5vcm1EZWZhdWx0KHBhcnNlU2lnbmF0dXJlU2NyaXB0KGlucHV0KSksXG4gICAgICAgIG5vcm1EZWZhdWx0KHtcbiAgICAgICAgICBzY3JpcHRUeXBlOiAncDJzaFAycGsnLFxuICAgICAgICAgIHB1YmxpY0tleXM6IFtmaXh0dXJlS2V5c1swXS5wdWJsaWNLZXldLFxuICAgICAgICAgIHNpZ25hdHVyZXM6IFtcbiAgICAgICAgICAgICczMDQ1MDIyMTAwZTYzNzQ2NmJlNDA1MDMyYTYzM2RjZWYwYmQxNjEzMDVmZTkzZDM0ZmZlMmFhYmM0YWY0MzRkNmYyNjU5MTIyMTAyMjAxMTNkNzA4NWIxZTAwNDM1YTI1ODNhZjgyYjhhNGRmM2ZiMDA5YThkMjc5ZDIzMTM1MWU0MmYzMWQ2YmFjNzQ0MDEnLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcblxuICBydW5UZXN0Q2hlY2tTY3JpcHRTdHJ1Y3R1cmUobmV0d29ya3MuYml0Y29pbiwgJ3Ayc2hQMnBrJywgZml4dHVyZUtleXNbMF0pO1xuICBydW5UZXN0Q2hlY2tTY3JpcHRTdHJ1Y3R1cmU8YmlnaW50PihuZXR3b3Jrcy5iaXRjb2luLCAncDJzaFAycGsnLCBmaXh0dXJlS2V5c1swXSwgdW5kZWZpbmVkLCAnYmlnaW50Jyk7XG59KTtcbiJdfQ==Выполнить команду
Для локальной разработки. Не используйте в интернете!