PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-staking/dist/test/unit/babylon
Просмотр файла: transactions.js
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = __importDefault(require("assert"));
const vendor = __importStar(require("@bitgo/babylonlabs-io-btc-staking-ts"));
const bitcoinjslib = __importStar(require("bitcoinjs-lib"));
const utxolib = __importStar(require("@bitgo/utxo-lib"));
const wasm_miniscript_1 = require("@bitgo/wasm-miniscript");
const descriptor_1 = require("@bitgo/utxo-core/descriptor");
const testutil_1 = require("@bitgo/utxo-core/testutil");
const babylonlabs_io_btc_staking_ts_1 = require("@bitgo/babylonlabs-io-btc-staking-ts");
const babylon_1 = require("../../../src/babylon");
const fixtures_utils_1 = require("../fixtures.utils");
const key_utils_1 = require("./key.utils");
const vendor_utils_1 = require("./vendor.utils");
function getStakingTransactionTreeVendor(builder, amount, utxos, feeRateSatB, signers, descriptorBuilder) {
const staking = builder.createStakingTransaction(amount, utxos, feeRateSatB);
const stakingWithdraw = builder.createWithdrawStakingExpiredPsbt(staking.transaction, feeRateSatB);
const unbonding = builder.createUnbondingTransaction(staking.transaction);
const unbondingWithdraw = builder.createWithdrawEarlyUnbondedTransaction(unbonding.transaction, feeRateSatB);
const unbondingSlashing = builder.createUnbondingOutputSlashingPsbt(unbonding.transaction);
const signSequence = [signers.staker];
if ('finalityProvider' in signers) {
signSequence.push(signers.finalityProvider, ...signers.covenant);
}
const unbondingSlashingWithdraw = signSequence
? builder.createWithdrawSlashingPsbt((0, babylon_1.forceFinalizePsbt)((0, babylon_1.getSignedPsbt)(unbondingSlashing.psbt, descriptorBuilder.getUnbondingDescriptor(), signSequence, {
finalize: false,
}), builder.network).extractTransaction(), feeRateSatB)
: undefined;
const slashing = builder.createStakingOutputSlashingPsbt(staking.transaction);
const slashingSigned = signSequence
? (0, babylon_1.getSignedPsbt)(slashing.psbt, descriptorBuilder.getStakingDescriptor(), signSequence, {
finalize: false,
})
: undefined;
const slashingWithdraw = slashingSigned
? builder.createWithdrawSlashingPsbt((0, babylon_1.forceFinalizePsbt)(slashingSigned.toBuffer(), builder.network).extractTransaction(), feeRateSatB)
: undefined;
return {
staking,
stakingWithdraw,
unbonding,
unbondingWithdraw,
unbondingSlashing,
unbondingSlashingWithdraw,
slashing,
slashingSigned,
slashingSignedBase64: slashingSigned?.toBuffer().toString('base64'),
slashingWithdraw,
};
}
function createUnstakingTransaction(stakingTx, stakingDescriptor, changeAddress, { sequence }) {
const network = utxolib.networks.bitcoin;
const witnessUtxoNumber = stakingTx.transaction.outs[0];
const witnessUtxo = {
script: witnessUtxoNumber.script,
value: BigInt(witnessUtxoNumber.value),
};
return (0, descriptor_1.createPsbt)({
network,
}, [
{
hash: stakingTx.transaction.getId(),
index: 0,
witnessUtxo,
descriptor: stakingDescriptor,
sequence,
},
], [
{
script: utxolib.address.toOutputScript(changeAddress, network),
value: BigInt(witnessUtxoNumber.value) - 1000n,
},
]);
}
function getTestnetStakingParamsWithCovenant(params, covenantKeys) {
return {
...params,
covenantNoCoordPks: covenantKeys.map((pk) => (0, key_utils_1.getXOnlyPubkey)(pk).toString('hex')),
};
}
function wpkhDescriptor(key) {
return wasm_miniscript_1.Descriptor.fromString(wasm_miniscript_1.ast.formatNode({ wpkh: key.publicKey.toString('hex') }), 'definite');
}
function mockUtxo(descriptor) {
const scriptPubKey = Buffer.from(descriptor.scriptPubkey());
const witnessScript = Buffer.from(descriptor.encode());
return {
rawTxHex: undefined,
txid: Buffer.alloc(32).fill(0x11).toString('hex'),
value: 666666,
vout: 0,
redeemScript: undefined,
witnessScript: witnessScript.toString('hex'),
scriptPubKey: scriptPubKey.toString('hex'),
};
}
function parseScript(key, script) {
if (!Buffer.isBuffer(script)) {
throw new Error('script must be a buffer');
}
const ms = wasm_miniscript_1.Miniscript.fromBitcoinScript(script, 'tap');
return {
script: script.toString('hex'),
miniscript: ms.toString(),
miniscriptAst: wasm_miniscript_1.ast.fromMiniscript(ms),
scriptASM: utxolib.script.toASM(script).split(/\s+/),
};
}
function parseScripts(scripts) {
if (typeof scripts !== 'object' || scripts === null) {
throw new Error('scripts must be an object');
}
return Object.fromEntries(Object.entries(scripts).map(([key, value]) => [key, parseScript(key, value)]));
}
async function assertEqualsFixture(fixtureName, value, n = fixtures_utils_1.normalize, eq = assert_1.default.deepStrictEqual) {
value = n(value);
eq(await (0, testutil_1.getFixture)(fixtureName, value), value);
}
async function assertScriptsEqualFixture(fixtureName, builder, scripts) {
await assertEqualsFixture(fixtureName, {
builder: (0, testutil_1.toPlainObject)(builder),
scripts: parseScripts(scripts),
});
}
async function assertTransactionEqualsFixture(fixtureName, tx) {
await assertEqualsFixture(fixtureName, (0, fixtures_utils_1.normalize)(tx));
}
function assertEqualsMiniscript(script, miniscript) {
const ms = wasm_miniscript_1.Miniscript.fromBitcoinScript(script, 'tap');
assert_1.default.deepStrictEqual(wasm_miniscript_1.ast.fromMiniscript(ms), miniscript);
assert_1.default.deepStrictEqual(script.toString('hex'), Buffer.from(wasm_miniscript_1.Miniscript.fromString(wasm_miniscript_1.ast.formatNode(miniscript), 'tap').encode()).toString('hex'));
}
function assertEqualScripts(descriptorBuilder, builder) {
for (const [key, script] of Object.entries(builder)) {
switch (key) {
case 'timelockScript':
assertEqualsMiniscript(script, descriptorBuilder.getTimelockMiniscript());
break;
case 'unbondingScript':
assertEqualsMiniscript(script, descriptorBuilder.getUnbondingMiniscript());
break;
case 'slashingScript':
assertEqualsMiniscript(script, descriptorBuilder.getSlashingMiniscript());
break;
case 'unbondingTimelockScript':
assertEqualsMiniscript(script, descriptorBuilder.getUnbondingTimelockMiniscript());
break;
default:
throw new Error(`unexpected script key: ${key}`);
}
}
}
function assertEqualOutputScript(outputInfo, descriptor) {
assert_1.default.strictEqual(outputInfo.scriptPubKey.toString('hex'), Buffer.from(descriptor.scriptPubkey()).toString('hex'));
}
function describeWithKeys(tag, finalityProviderKeys, covenantKeys, stakingParams, { signIntermediateTxs = false } = {}) {
const stakerKey = (0, key_utils_1.getECKey)('staker');
const covenantThreshold = stakingParams.covenantQuorum;
const stakingTimelock = stakingParams.minStakingTimeBlocks;
const unbondingTimelock = stakingParams.unbondingTime;
const vendorBuilder = new vendor.StakingScriptData((0, key_utils_1.getXOnlyPubkey)(stakerKey), finalityProviderKeys.map(key_utils_1.getXOnlyPubkey), covenantKeys.map(key_utils_1.getXOnlyPubkey), covenantThreshold, stakingTimelock, unbondingTimelock);
const descriptorBuilder = new babylon_1.BabylonDescriptorBuilder((0, key_utils_1.getXOnlyPubkey)(stakerKey), finalityProviderKeys.map(key_utils_1.getXOnlyPubkey), covenantKeys.map(key_utils_1.getXOnlyPubkey), covenantThreshold, stakingTimelock, unbondingTimelock);
describe(`Babylon Staking [${tag}]`, function () {
it('generates expected staking scripts', async function () {
await assertScriptsEqualFixture(`test/fixtures/babylon/scripts.${tag}.json`, vendorBuilder, vendorBuilder.buildScripts());
});
it('matches inner taproot scripts', function () {
assertEqualScripts(descriptorBuilder, vendorBuilder.buildScripts());
});
it('matches output scripts', function () {
assertEqualOutputScript(vendor.deriveStakingOutputInfo(vendorBuilder.buildScripts(), bitcoinjslib.networks.bitcoin), descriptorBuilder.getStakingDescriptor());
assertEqualOutputScript(vendor.deriveSlashingOutput(vendorBuilder.buildScripts(), bitcoinjslib.networks.bitcoin), descriptorBuilder.getSlashingDescriptor());
assertEqualOutputScript(vendor.deriveUnbondingOutputInfo(vendorBuilder.buildScripts(), bitcoinjslib.networks.bitcoin), descriptorBuilder.getUnbondingDescriptor());
});
describe('Transaction Sets', async function () {
const stakerMainWalletKey = (0, key_utils_1.getECKey)('stakerMainWallet');
const mainWallet = wpkhDescriptor(stakerMainWalletKey);
const amount = 55555;
const changeAddress = (0, descriptor_1.createAddressFromDescriptor)(mainWallet, undefined, utxolib.networks.bitcoin);
const feeRateSatB = 2;
const utxo = mockUtxo(mainWallet);
let stakingTx;
before('setup stakingTx', function () {
stakingTx = vendor.stakingTransaction(vendorBuilder.buildScripts(), amount, changeAddress, [mockUtxo(mainWallet)], bitcoinjslib.networks.bitcoin, feeRateSatB);
});
it('has expected transactions', async function () {
await assertTransactionEqualsFixture(`test/fixtures/babylon/stakingTransaction.${tag}.json`, stakingTx);
// simply one staking output and one change output
// nothing special
assert_1.default.deepStrictEqual(stakingTx.transaction.outs, [
{
script: Buffer.from(descriptorBuilder.getStakingDescriptor().scriptPubkey()),
value: amount,
},
{
script: utxolib.address.toOutputScript(changeAddress, utxolib.networks.bitcoin),
value: utxo.value - amount - stakingTx.fee,
},
]);
});
if (finalityProviderKeys.length !== 1) {
return;
}
const finalityProvider = finalityProviderKeys[0];
it('has expected transactions (vendorStaking.Staking)', async function () {
const vendorStakingTxBuilder = new vendor.Staking(bitcoinjslib.networks.bitcoin, (0, babylon_1.toStakerInfo)(stakerKey, changeAddress), stakingParams, (0, key_utils_1.getXOnlyPubkey)(finalityProvider).toString('hex'), stakingParams.minStakingTimeBlocks);
const txTree = getStakingTransactionTreeVendor(vendorStakingTxBuilder, amount, [utxo], feeRateSatB, signIntermediateTxs
? {
staker: stakerKey,
finalityProvider,
covenant: covenantKeys,
covenantThreshold: covenantThreshold,
}
: { staker: stakerKey }, descriptorBuilder);
await assertTransactionEqualsFixture(`test/fixtures/babylon/txTree.${tag}.json`, txTree);
});
it('creates MsgCreateBTCDelegation', async function () {
const fVendor = vendor_utils_1.getVendorMsgCreateBtcDelegation;
const fBitGo = vendor_utils_1.getBitGoUtxoStakingMsgCreateBtcDelegation;
for (const f of [fVendor, fBitGo]) {
await assertEqualsFixture(`test/fixtures/babylon/msgCreateBTCDelegation.${tag}.json`, await f(bitcoinjslib.networks.bitcoin, stakerKey, finalityProvider, descriptorBuilder, [{ ...stakingParams, version: 0, btcActivationHeight: 0 }], changeAddress, amount, utxo, feeRateSatB, 800000), fixtures_utils_1.normalize, (a, b) => {
// The vendor library serializes the signature as BIP322, while
// our implementation serializes it as ECDSA.
// Strip the pop field from the MsgCreateBTCDelegation.
function stripPop(v) {
const vAny = v;
delete vAny['unsignedDelegationMsg']['value']['pop'];
}
stripPop(a);
stripPop(b);
assert_1.default.deepStrictEqual(a, b);
});
}
});
it('creates unstaking transaction', async function () {
const unstaking = createUnstakingTransaction(stakingTx, descriptorBuilder.getStakingDescriptor(), changeAddress, { sequence: stakingParams.minStakingTimeBlocks });
const wrappedPsbt = (0, descriptor_1.toWrappedPsbt)(unstaking);
(0, assert_1.default)((0, descriptor_1.getNewSignatureCount)((0, descriptor_1.signWithKey)(wrappedPsbt, stakerKey)) > 0);
wrappedPsbt.finalize();
const tx = (0, descriptor_1.toUtxoPsbt)(wrappedPsbt, utxolib.networks.bitcoin).extractTransaction();
await assertTransactionEqualsFixture(`test/fixtures/babylon/unstakingTransaction.${tag}.json`, {
transaction: tx,
});
});
});
});
}
function describeWithKeysFromStakingParams(tag, finalityProviderKeys, stakingParams) {
describeWithKeys(tag, finalityProviderKeys, stakingParams.covenantNoCoordPks.map((pk) => (0, key_utils_1.fromXOnlyPublicKey)(Buffer.from(pk, 'hex'))), stakingParams);
}
function describeWithMockKeys(tag, stakingParams, finalityProviderKeys, covenantKeys) {
describeWithKeys(tag, finalityProviderKeys, covenantKeys, getTestnetStakingParamsWithCovenant(stakingParams, covenantKeys), {
signIntermediateTxs: true,
});
}
describeWithKeysFromStakingParams('testnet', [(0, key_utils_1.fromXOnlyPublicKey)(babylon_1.testnetFinalityProvider0)], (0, babylonlabs_io_btc_staking_ts_1.getBabylonParamByVersion)(5, (0, babylon_1.getStakingParams)('testnet')));
describeWithMockKeys('testnetMock', (0, babylonlabs_io_btc_staking_ts_1.getBabylonParamByVersion)(5, (0, babylon_1.getStakingParams)('testnet')), (0, key_utils_1.getECKeys)('finalityProvider', 1), (0, key_utils_1.getECKeys)('covenant', 9));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNhY3Rpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdGVzdC91bml0L2JhYnlsb24vdHJhbnNhY3Rpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsb0RBQTRCO0FBRTVCLDZFQUErRDtBQUMvRCw0REFBOEM7QUFDOUMseURBQTJDO0FBRTNDLDREQUFxRTtBQUNyRSw0REFPcUM7QUFDckMsd0RBQXNFO0FBQ3RFLHdGQUFnRjtBQUVoRixrREFPOEI7QUFDOUIsc0RBQThDO0FBRTlDLDJDQUFzRjtBQUN0RixpREFBNEc7QUFxQjVHLFNBQVMsK0JBQStCLENBQ3RDLE9BQXVCLEVBQ3ZCLE1BQWMsRUFDZCxLQUFvQixFQUNwQixXQUFtQixFQUNuQixPQU8rQixFQUMvQixpQkFBMkM7SUFFM0MsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLHdCQUF3QixDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDN0UsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDLGdDQUFnQyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDbkcsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLDBCQUEwQixDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMxRSxNQUFNLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxzQ0FBc0MsQ0FBQyxTQUFTLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQzdHLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDLGlDQUFpQyxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMzRixNQUFNLFlBQVksR0FBRyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN0QyxJQUFJLGtCQUFrQixJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQ2xDLFlBQVksQ0FBQyxJ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QUFXLEVBQ1gsYUFBbUMsRUFDbkMsb0JBQXVDLEVBQ3ZDLFlBQStCO0lBRS9CLGdCQUFnQixDQUNkLEdBQUcsRUFDSCxvQkFBb0IsRUFDcEIsWUFBWSxFQUNaLG1DQUFtQyxDQUFDLGFBQWEsRUFBRSxZQUFZLENBQUMsRUFDaEU7UUFDRSxtQkFBbUIsRUFBRSxJQUFJO0tBQzFCLENBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRCxpQ0FBaUMsQ0FDL0IsU0FBUyxFQUNULENBQUMsSUFBQSw4QkFBa0IsRUFBQyxrQ0FBd0IsQ0FBQyxDQUFDLEVBQzlDLElBQUEsd0RBQXdCLEVBQUMsQ0FBQyxFQUFFLElBQUEsMEJBQWdCLEVBQUMsU0FBUyxDQUFDLENBQUMsQ0FDekQsQ0FBQztBQUNGLG9CQUFvQixDQUNsQixhQUFhLEVBQ2IsSUFBQSx3REFBd0IsRUFBQyxDQUFDLEVBQUUsSUFBQSwwQkFBZ0IsRUFBQyxTQUFTLENBQUMsQ0FBQyxFQUN4RCxJQUFBLHFCQUFTLEVBQUMsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDLEVBQ2hDLElBQUEscUJBQVMsRUFBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQ3pCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5cbmltcG9ydCAqIGFzIHZlbmRvciBmcm9tICdAYml0Z28vYmFieWxvbmxhYnMtaW8tYnRjLXN0YWtpbmctdHMnO1xuaW1wb3J0ICogYXMgYml0Y29pbmpzbGliIGZyb20gJ2JpdGNvaW5qcy1saWInO1xuaW1wb3J0ICogYXMgdXR4b2xpYiBmcm9tICdAYml0Z28vdXR4by1saWInO1xuaW1wb3J0IHsgRUNQYWlySW50ZXJmYWNlIH0gZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcbmltcG9ydCB7IGFzdCwgRGVzY3JpcHRvciwgTWluaXNjcmlwdCB9IGZyb20gJ0BiaXRnby93YXNtLW1pbmlzY3JpcHQnO1xuaW1wb3J0IHtcbiAgY3JlYXRlQWRkcmVzc0Zyb21EZXNjcmlwdG9yLFxuICBjcmVhdGVQc2J0LFxuICBnZXROZXdTaWduYXR1cmVDb3VudCxcbiAgc2lnbldpdGhLZXksXG4gIHRvVXR4b1BzYnQsXG4gIHRvV3JhcHBlZFBzYnQsXG59IGZyb20gJ0BiaXRnby91dHhvLWNvcmUvZGVzY3JpcHRvcic7XG5pbXBvcnQgeyBnZXRGaXh0dXJlLCB0b1BsYWluT2JqZWN0IH0gZnJvbSAnQGJpdGdvL3V0eG8tY29yZS90ZXN0dXRpbCc7XG5pbXBvcnQgeyBnZXRCYWJ5bG9uUGFyYW1CeVZlcnNpb24gfSBmcm9tICdAYml0Z28vYmFieWxvbmxhYnMtaW8tYnRjLXN0YWtpbmctdHMnO1xuXG5pbXBvcnQge1xuICBCYWJ5bG9uRGVzY3JpcHRvckJ1aWxkZXIsXG4gIHRlc3RuZXRGaW5hbGl0eVByb3ZpZGVyMCxcbiAgZ2V0U2lnbmVkUHNidCxcbiAgZ2V0U3Rha2luZ1BhcmFtcyxcbiAgdG9TdGFrZXJJbmZvLFxuICBmb3JjZUZpbmFsaXplUHNidCxcbn0gZnJvbSAnLi4vLi4vLi4vc3JjL2JhYnlsb24nO1xuaW1wb3J0IHsgbm9ybWFsaXplIH0gZnJvbSAnLi4vZml4dHVyZXMudXRpbHMnO1xuXG5pbXBvcnQgeyBmcm9tWE9ubHlQdWJsaWNLZXksIGdldEVDS2V5LCBnZXRFQ0tleXMsIGdldFhPbmx5UHVia2V5IH0gZnJvbSAnLi9rZXkudXRpbHMnO1xuaW1wb3J0IHsgZ2V0Qml0R29VdHhvU3Rha2luZ01zZ0NyZWF0ZUJ0Y0RlbGVnYXRpb24sIGdldFZlbmRvck1zZ0NyZWF0ZUJ0Y0RlbGVnYXRpb24gfSBmcm9tICcuL3ZlbmRvci51dGlscyc7XG5cbnR5cGUgV2l0aEZlZTxUPiA9IFQgJiB7IGZlZTogbnVtYmVyIH07XG50eXBlIFRyYW5zYWN0aW9uV2l0aEZlZSA9IFdpdGhGZWU8eyB0cmFuc2FjdGlvbjogYml0Y29pbmpzbGliLlRyYW5zYWN0aW9uIH0+O1xudHlwZSBQc2J0V2l0aEZlZSA9IFdpdGhGZWU8eyBwc2J0OiBiaXRjb2luanNsaWIuUHNidCB9PjtcblxudHlwZSBUcmFuc2FjdGlvblRyZWUgPSB7XG4gIHN0YWtpbmc6IFRyYW5zYWN0aW9uV2l0aEZlZTtcbiAgc3Rha2luZ1dpdGhkcmF3OiBQc2J0V2l0aEZlZTtcblxuICB1bmJvbmRpbmc6IFRyYW5zYWN0aW9uV2l0aEZlZTtcbiAgdW5ib25kaW5nV2l0aGRyYXc6IFBzYnRXaXRoRmVlO1xuICB1bmJvbmRpbmdTbGFzaGluZzogUHNidFdpdGhGZWU7XG4gIHVuYm9uZGluZ1NsYXNoaW5nV2l0aGRyYXc6IFBzYnRXaXRoRmVlIHwgdW5kZWZpbmVkO1xuXG4gIHNsYXNoaW5nOiBQc2J0V2l0aEZlZTtcbiAgc2xhc2hpbmdXaXRoZHJhdzogUHNidFdpdGhGZWUgfCB1bmRlZmluZWQ7XG4gIHNsYXNoaW5nU2lnbmVkOiBiaXRjb2luanNsaWIuUHNidCB8IHVuZGVmaW5lZDtcbiAgc2xhc2hpbmdTaWduZWRCYXNlNjQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbn07XG5cbmZ1bmN0aW9uIGdldFN0YWtpbmdUcmFuc2FjdGlvblRyZWVWZW5kb3IoXG4gIGJ1aWxkZXI6IHZlbmRvci5TdGFraW5nLFxuICBhbW91bnQ6IG51bWJlcixcbiAgdXR4b3M6IHZlbmRvci5VVFhPW10sXG4gIGZlZVJhdGVTYXRCOiBudW1iZXIsXG4gIHNpZ25lcnM6XG4gICAgfCB7XG4gICAgICAgIHN0YWtlcjogRUNQYWlySW50ZXJmYWNlO1xuICAgICAgICBmaW5hbGl0eVByb3ZpZGVyOiBFQ1BhaXJJbnRlcmZhY2U7XG4gICAgICAgIGNvdmVuYW50OiBFQ1BhaXJJbnRlcmZhY2VbXTtcbiAgICAgICAgY292ZW5hbnRUaHJlc2hvbGQ6IG51bWJlcjtcbiAgICAgIH1cbiAgICB8IHsgc3Rha2VyOiBFQ1BhaXJJbnRlcmZhY2UgfSxcbiAgZGVzY3JpcHRvckJ1aWxkZXI6IEJhYnlsb25EZXNjcmlwdG9yQnVpbGRlclxuKTogVHJhbnNhY3Rpb25UcmVlIHtcbiAgY29uc3Qgc3Rha2luZyA9IGJ1aWxkZXIuY3JlYXRlU3Rha2luZ1RyYW5zYWN0aW9uKGFtb3VudCwgdXR4b3MsIGZlZVJhdGVTYXRCKTtcbiAgY29uc3Qgc3Rha2luZ1dpdGhkcmF3ID0gYnVpbGRlci5jcmVhdGVXaXRoZHJhd1N0YWtpbmdFeHBpcmVkUHNidChzdGFraW5nLnRyYW5zYWN0aW9uLCBmZWVSYXRlU2F0Qik7XG4gIGNvbnN0IHVuYm9uZGluZyA9IGJ1aWxkZXIuY3JlYXRlVW5ib25kaW5nVHJhbnNhY3Rpb24oc3Rha2luZy50cmFuc2FjdGlvbik7XG4gIGNvbnN0IHVuYm9uZGluZ1dpdGhkcmF3ID0gYnVpbGRlci5jcmVhdGVXaXRoZHJhd0Vhcmx5VW5ib25kZWRUcmFuc2FjdGlvbih1bmJvbmRpbmcudHJhbnNhY3Rpb24sIGZlZVJhdGVTYXRCKTtcbiAgY29uc3QgdW5ib25kaW5nU2xhc2hpbmcgPSBidWlsZGVyLmNyZWF0ZVVuYm9uZGluZ091dHB1dFNsYXNoaW5nUHNidCh1bmJvbmRpbmcudHJhbnNhY3Rpb24pO1xuICBjb25zdCBzaWduU2VxdWVuY2UgPSBbc2lnbmVycy5zdGFrZXJdO1xuICBpZiAoJ2ZpbmFsaXR5UHJvdmlkZXInIGluIHNpZ25lcnMpIHtcbiAgICBzaWduU2VxdWVuY2UucHVzaChzaWduZXJzLmZpbmFsaXR5UHJvdmlkZXIsIC4uLnNpZ25lcnMuY292ZW5hbnQpO1xuICB9XG4gIGNvbnN0IHVuYm9uZGluZ1NsYXNoaW5nV2l0aGRyYXcgPSBzaWduU2VxdWVuY2VcbiAgICA/IGJ1aWxkZXIuY3JlYXRlV2l0aGRyYXdTbGFzaGluZ1BzYnQoXG4gICAgICAgIGZvcmNlRmluYWxpemVQc2J0KFxuICAgICAgICAgIGdldFNpZ25lZFBzYnQodW5ib25kaW5nU2xhc2hpbmcucHNidCwgZGVzY3JpcHRvckJ1aWxkZXIuZ2V0VW5ib25kaW5nRGVzY3JpcHRvcigpLCBzaWduU2VxdWVuY2UsIHtcbiAgICAgICAgICAgIGZpbmFsaXplOiBmYWxzZSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBidWlsZGVyLm5ldHdvcmtcbiAgICAgICAgKS5leHRyYWN0VHJhbnNhY3Rpb24oKSxcbiAgICAgICAgZmVlUmF0ZVNhdEJcbiAgICAgIClcbiAgICA6IHVuZGVmaW5lZDtcbiAgY29uc3Qgc2xhc2hpbmcgPSBidWlsZGVyLmNyZWF0ZVN0YWtpbmdPdXRwdXRTbGFzaGluZ1BzYnQoc3Rha2luZy50cmFuc2FjdGlvbik7XG4gIGNvbnN0IHNsYXNoaW5nU2lnbmVkID0gc2lnblNlcXVlbmNlXG4gICAgPyBnZXRTaWduZWRQc2J0KHNsYXNoaW5nLnBzYnQsIGRlc2NyaXB0b3JCdWlsZGVyLmdldFN0YWtpbmdEZXNjcmlwdG9yKCksIHNpZ25TZXF1ZW5jZSwge1xuICAgICAgICBmaW5hbGl6ZTogZmFsc2UsXG4gICAgICB9KVxuICAgIDogdW5kZWZpbmVkO1xuICBjb25zdCBzbGFzaGluZ1dpdGhkcmF3ID0gc2xhc2hpbmdTaWduZWRcbiAgICA/IGJ1aWxkZXIuY3JlYXRlV2l0aGRyYXdTbGFzaGluZ1BzYnQoXG4gICAgICAgIGZvcmNlRmluYWxpemVQc2J0KHNsYXNoaW5nU2lnbmVkLnRvQnVmZmVyKCksIGJ1aWxkZXIubmV0d29yaykuZXh0cmFjdFRyYW5zYWN0aW9uKCksXG4gICAgICAgIGZlZVJhdGVTYXRCXG4gICAgICApXG4gICAgOiB1bmRlZmluZWQ7XG5cbiAgcmV0dXJuIHtcbiAgICBzdGFraW5nLFxuICAgIHN0YWtpbmdXaXRoZHJhdyxcbiAgICB1bmJvbmRpbmcsXG4gICAgdW5ib25kaW5nV2l0aGRyYXcsXG4gICAgdW5ib25kaW5nU2xhc2hpbmcsXG4gICAgdW5ib25kaW5nU2xhc2hpbmdXaXRoZHJhdyxcbiAgICBzbGFzaGluZyxcbiAgICBzbGFzaGluZ1NpZ25lZCxcbiAgICBzbGFzaGluZ1NpZ25lZEJhc2U2NDogc2xhc2hpbmdTaWduZWQ/LnRvQnVmZmVyKCkudG9TdHJpbmcoJ2Jhc2U2NCcpLFxuICAgIHNsYXNoaW5nV2l0aGRyYXcsXG4gIH07XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVVuc3Rha2luZ1RyYW5zYWN0aW9uKFxuICBzdGFraW5nVHg6IHZlbmRvci5UcmFuc2FjdGlvblJlc3VsdCxcbiAgc3Rha2luZ0Rlc2NyaXB0b3I6IERlc2NyaXB0b3IsXG4gIGNoYW5nZUFkZHJlc3M6IHN0cmluZyxcbiAgeyBzZXF1ZW5jZSB9OiB7IHNlcXVlbmNlOiBudW1iZXIgfVxuKTogdXR4b2xpYi5Qc2J0IHtcbiAgY29uc3QgbmV0d29yayA9IHV0eG9saWIubmV0d29ya3MuYml0Y29pbjtcbiAgY29uc3Qgd2l0bmVzc1V0eG9OdW1iZXIgPSBzdGFraW5nVHgudHJhbnNhY3Rpb24ub3V0c1swXTtcbiAgY29uc3Qgd2l0bmVzc1V0eG8gPSB7XG4gICAgc2NyaXB0OiB3aXRuZXNzVXR4b051bWJlci5zY3JpcHQsXG4gICAgdmFsdWU6IEJpZ0ludCh3aXRuZXNzVXR4b051bWJlci52YWx1ZSksXG4gIH07XG4gIHJldHVybiBjcmVhdGVQc2J0KFxuICAgIHtcbiAgICAgIG5ldHdvcmssXG4gICAgfSxcbiAgICBbXG4gICAgICB7XG4gICAgICAgIGhhc2g6IHN0YWtpbmdUeC50cmFuc2FjdGlvbi5nZXRJZCgpLFxuICAgICAgICBpbmRleDogMCxcbiAgICAgICAgd2l0bmVzc1V0eG8sXG4gICAgICAgIGRlc2NyaXB0b3I6IHN0YWtpbmdEZXNjcmlwdG9yLFxuICAgICAgICBzZXF1ZW5jZSxcbiAgICAgIH0sXG4gICAgXSxcbiAgICBbXG4gICAgICB7XG4gICAgICAgIHNjcmlwdDogdXR4b2xpYi5hZGRyZXNzLnRvT3V0cHV0U2NyaXB0KGNoYW5nZUFkZHJlc3MsIG5ldHdvcmspLFxuICAgICAgICB2YWx1ZTogQmlnSW50KHdpdG5lc3NVdHhvTnVtYmVyLnZhbHVlKSAtIDEwMDBuLFxuICAgICAgfSxcbiAgICBdXG4gICk7XG59XG5cbmZ1bmN0aW9uIGdldFRlc3RuZXRTdGFraW5nUGFyYW1zV2l0aENvdmVuYW50KFxuICBwYXJhbXM6IHZlbmRvci5TdGFraW5nUGFyYW1zLFxuICBjb3ZlbmFudEtleXM6IEVDUGFpckludGVyZmFjZVtdXG4pOiB2ZW5kb3IuU3Rha2luZ1BhcmFtcyB7XG4gIHJldHVybiB7XG4gICAgLi4ucGFyYW1zLFxuICAgIGNvdmVuYW50Tm9Db29yZFBrczogY292ZW5hbnRLZXlzLm1hcCgocGspID0+IGdldFhPbmx5UHVia2V5KHBrKS50b1N0cmluZygnaGV4JykpLFxuICB9O1xufVxuXG5mdW5jdGlvbiB3cGtoRGVzY3JpcHRvcihrZXk6IHV0eG9saWIuRUNQYWlySW50ZXJmYWNlKTogRGVzY3JpcHRvciB7XG4gIHJldHVybiBEZXNjcmlwdG9yLmZyb21TdHJpbmcoYXN0LmZvcm1hdE5vZGUoeyB3cGtoOiBrZXkucHVibGljS2V5LnRvU3RyaW5nKCdoZXgnKSB9KSwgJ2RlZmluaXRlJyk7XG59XG5cbmZ1bmN0aW9uIG1vY2tVdHhvKGRlc2NyaXB0b3I6IERlc2NyaXB0b3IpOiB2ZW5kb3IuVVRYTyB7XG4gIGNvbnN0IHNjcmlwdFB1YktleSA9IEJ1ZmZlci5mcm9tKGRlc2NyaXB0b3Iuc2NyaXB0UHVia2V5KCkpO1xuICBjb25zdCB3aXRuZXNzU2NyaXB0ID0gQnVmZmVyLmZyb20oZGVzY3JpcHRvci5lbmNvZGUoKSk7XG4gIHJldHVybiB7XG4gICAgcmF3VHhIZXg6IHVuZGVmaW5lZCxcbiAgICB0eGlkOiBCdWZmZXIuYWxsb2MoMzIpLmZpbGwoMHgxMSkudG9TdHJpbmcoJ2hleCcpLFxuICAgIHZhbHVlOiA2NjZfNjY2LFxuICAgIHZvdXQ6IDAsXG4gICAgcmVkZWVtU2NyaXB0OiB1bmRlZmluZWQsXG4gICAgd2l0bmVzc1NjcmlwdDogd2l0bmVzc1NjcmlwdC50b1N0cmluZygnaGV4JyksXG4gICAgc2NyaXB0UHViS2V5OiBzY3JpcHRQdWJLZXkudG9TdHJpbmcoJ2hleCcpLFxuICB9O1xufVxuXG5mdW5jdGlvbiBwYXJzZVNjcmlwdChrZXk6IHN0cmluZywgc2NyaXB0OiB1bmtub3duKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKHNjcmlwdCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3NjcmlwdCBtdXN0IGJlIGEgYnVmZmVyJyk7XG4gIH1cbiAgY29uc3QgbXMgPSBNaW5pc2NyaXB0LmZyb21CaXRjb2luU2NyaXB0KHNjcmlwdCwgJ3RhcCcpO1xuICByZXR1cm4ge1xuICAgIHNjcmlwdDogc2NyaXB0LnRvU3RyaW5nKCdoZXgnKSxcbiAgICBtaW5pc2NyaXB0OiBtcy50b1N0cmluZygpLFxuICAgIG1pbmlzY3JpcHRBc3Q6IGFzdC5mcm9tTWluaXNjcmlwdChtcyksXG4gICAgc2NyaXB0QVNNOiB1dHhvbGliLnNjcmlwdC50b0FTTShzY3JpcHQpLnNwbGl0KC9cXHMrLyksXG4gIH07XG59XG5cbmZ1bmN0aW9uIHBhcnNlU2NyaXB0cyhzY3JpcHRzOiB1bmtub3duKSB7XG4gIGlmICh0eXBlb2Ygc2NyaXB0cyAhPT0gJ29iamVjdCcgfHwgc2NyaXB0cyA9PT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBFcnJvcignc2NyaXB0cyBtdXN0IGJlIGFuIG9iamVjdCcpO1xuICB9XG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMoc2NyaXB0cykubWFwKChba2V5LCB2YWx1ZV0pID0+IFtrZXksIHBhcnNlU2NyaXB0KGtleSwgdmFsdWUpXSkpO1xufVxuXG50eXBlIEVxdWFsc0Fzc2VydGlvbiA9IHR5cGVvZiBhc3NlcnQuZGVlcFN0cmljdEVxdWFsO1xuXG5hc3luYyBmdW5jdGlvbiBhc3NlcnRFcXVhbHNGaXh0dXJlKFxuICBmaXh0dXJlTmFtZTogc3RyaW5nLFxuICB2YWx1ZTogdW5rbm93bixcbiAgbiA9IG5vcm1hbGl6ZSxcbiAgZXE6IEVxdWFsc0Fzc2VydGlvbiA9IGFzc2VydC5kZWVwU3RyaWN0RXF1YWxcbik6IFByb21pc2U8dm9pZD4ge1xuICB2YWx1ZSA9IG4odmFsdWUpO1xuICBlcShhd2FpdCBnZXRGaXh0dXJlKGZpeHR1cmVOYW1lLCB2YWx1ZSksIHZhbHVlKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gYXNzZXJ0U2NyaXB0c0VxdWFsRml4dHVyZShcbiAgZml4dHVyZU5hbWU6IHN0cmluZyxcbiAgYnVpbGRlcjogdmVuZG9yLlN0YWtpbmdTY3JpcHREYXRhLFxuICBzY3JpcHRzOiB1bmtub3duXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgYXNzZXJ0RXF1YWxzRml4dHVyZShmaXh0dXJlTmFtZSwge1xuICAgIGJ1aWxkZXI6IHRvUGxhaW5PYmplY3QoYnVpbGRlciksXG4gICAgc2NyaXB0czogcGFyc2VTY3JpcHRzKHNjcmlwdHMpLFxuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gYXNzZXJ0VHJhbnNhY3Rpb25FcXVhbHNGaXh0dXJlKGZpeHR1cmVOYW1lOiBzdHJpbmcsIHR4OiB1bmtub3duKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGFzc2VydEVxdWFsc0ZpeHR1cmUoZml4dHVyZU5hbWUsIG5vcm1hbGl6ZSh0eCkpO1xufVxuXG5mdW5jdGlvbiBhc3NlcnRFcXVhbHNNaW5pc2NyaXB0KHNjcmlwdDogQnVmZmVyLCBtaW5pc2NyaXB0OiBhc3QuTWluaXNjcmlwdE5vZGUpOiB2b2lkIHtcbiAgY29uc3QgbXMgPSBNaW5pc2NyaXB0LmZyb21CaXRjb2luU2NyaXB0KHNjcmlwdCwgJ3RhcCcpO1xuICBhc3NlcnQuZGVlcFN0cmljdEVxdWFsKGFzdC5mcm9tTWluaXNjcmlwdChtcyksIG1pbmlzY3JpcHQpO1xuICBhc3NlcnQuZGVlcFN0cmljdEVxdWFsKFxuICAgIHNjcmlwdC50b1N0cmluZygnaGV4JyksXG4gICAgQnVmZmVyLmZyb20oTWluaXNjcmlwdC5mcm9tU3RyaW5nKGFzdC5mb3JtYXROb2RlKG1pbmlzY3JpcHQpLCAndGFwJykuZW5jb2RlKCkpLnRvU3RyaW5nKCdoZXgnKVxuICApO1xufVxuXG5mdW5jdGlvbiBhc3NlcnRFcXVhbFNjcmlwdHMoZGVzY3JpcHRvckJ1aWxkZXI6IEJhYnlsb25EZXNjcmlwdG9yQnVpbGRlciwgYnVpbGRlcjogdmVuZG9yLlN0YWtpbmdTY3JpcHRzKSB7XG4gIGZvciAoY29uc3QgW2tleSwgc2NyaXB0XSBvZiBPYmplY3QuZW50cmllcyhidWlsZGVyKSBhcyBba2V5b2YgdmVuZG9yLlN0YWtpbmdTY3JpcHRzLCBCdWZmZXJdW10pIHtcbiAgICBzd2l0Y2ggKGtleSkge1xuICAgICAgY2FzZSAndGltZWxvY2tTY3JpcHQnOlxuICAgICAgICBhc3NlcnRFcXVhbHNNaW5pc2NyaXB0KHNjcmlwdCwgZGVzY3JpcHRvckJ1aWxkZXIuZ2V0VGltZWxvY2tNaW5pc2NyaXB0KCkpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3VuYm9uZGluZ1NjcmlwdCc6XG4gICAgICAgIGFzc2VydEVxdWFsc01pbmlzY3JpcHQoc2NyaXB0LCBkZXNjcmlwdG9yQnVpbGRlci5nZXRVbmJvbmRpbmdNaW5pc2NyaXB0KCkpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3NsYXNoaW5nU2NyaXB0JzpcbiAgICAgICAgYXNzZXJ0RXF1YWxzTWluaXNjcmlwdChzY3JpcHQsIGRlc2NyaXB0b3JCdWlsZGVyLmdldFNsYXNoaW5nTWluaXNjcmlwdCgpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd1bmJvbmRpbmdUaW1lbG9ja1NjcmlwdCc6XG4gICAgICAgIGFzc2VydEVxdWFsc01pbmlzY3JpcHQoc2NyaXB0LCBkZXNjcmlwdG9yQnVpbGRlci5nZXRVbmJvbmRpbmdUaW1lbG9ja01pbmlzY3JpcHQoKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB1bmV4cGVjdGVkIHNjcmlwdCBrZXk6ICR7a2V5fWApO1xuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBhc3NlcnRFcXVhbE91dHB1dFNjcmlwdChvdXRwdXRJbmZvOiB7IHNjcmlwdFB1YktleTogQnVmZmVyIH0sIGRlc2NyaXB0b3I6IERlc2NyaXB0b3IpIHtcbiAgYXNzZXJ0LnN0cmljdEVxdWFsKG91dHB1dEluZm8uc2NyaXB0UHViS2V5LnRvU3RyaW5nKCdoZXgnKSwgQnVmZmVyLmZyb20oZGVzY3JpcHRvci5zY3JpcHRQdWJrZXkoKSkudG9TdHJpbmcoJ2hleCcpKTtcbn1cblxuZnVuY3Rpb24gZGVzY3JpYmVXaXRoS2V5cyhcbiAgdGFnOiBzdHJpbmcsXG4gIGZpbmFsaXR5UHJvdmlkZXJLZXlzOiBFQ1BhaXJJbnRlcmZhY2VbXSxcbiAgY292ZW5hbnRLZXlzOiBFQ1BhaXJJbnRlcmZhY2VbXSxcbiAgc3Rha2luZ1BhcmFtczogdmVuZG9yLlN0YWtpbmdQYXJhbXMsXG4gIHsgc2lnbkludGVybWVkaWF0ZVR4cyA9IGZhbHNlIH0gPSB7fVxuKSB7XG4gIGNvbnN0IHN0YWtlcktleSA9IGdldEVDS2V5KCdzdGFrZXInKSBhcyBFQ1BhaXJJbnRlcmZhY2UgJiB7IHByaXZhdGVLZXk6IEJ1ZmZlciB9O1xuICBjb25zdCBjb3ZlbmFudFRocmVzaG9sZCA9IHN0YWtpbmdQYXJhbXMuY292ZW5hbnRRdW9ydW07XG4gIGNvbnN0IHN0YWtpbmdUaW1lbG9jayA9IHN0YWtpbmdQYXJhbXMubWluU3Rha2luZ1RpbWVCbG9ja3M7XG4gIGNvbnN0IHVuYm9uZGluZ1RpbWVsb2NrID0gc3Rha2luZ1BhcmFtcy51bmJvbmRpbmdUaW1lO1xuICBjb25zdCB2ZW5kb3JCdWlsZGVyID0gbmV3IHZlbmRvci5TdGFraW5nU2NyaXB0RGF0YShcbiAgICBnZXRYT25seVB1YmtleShzdGFrZXJLZXkpLFxuICAgIGZpbmFsaXR5UHJvdmlkZXJLZXlzLm1hcChnZXRYT25seVB1YmtleSksXG4gICAgY292ZW5hbnRLZXlzLm1hcChnZXRYT25seVB1YmtleSksXG4gICAgY292ZW5hbnRUaHJlc2hvbGQsXG4gICAgc3Rha2luZ1RpbWVsb2NrLFxuICAgIHVuYm9uZGluZ1RpbWVsb2NrXG4gICk7XG5cbiAgY29uc3QgZGVzY3JpcHRvckJ1aWxkZXIgPSBuZXcgQmFieWxvbkRlc2NyaXB0b3JCdWlsZGVyKFxuICAgIGdldFhPbmx5UHVia2V5KHN0YWtlcktleSksXG4gICAgZmluYWxpdHlQcm92aWRlcktleXMubWFwKGdldFhPbmx5UHVia2V5KSxcbiAgICBjb3ZlbmFudEtleXMubWFwKGdldFhPbmx5UHVia2V5KSxcbiAgICBjb3ZlbmFudFRocmVzaG9sZCxcbiAgICBzdGFraW5nVGltZWxvY2ssXG4gICAgdW5ib25kaW5nVGltZWxvY2tcbiAgKTtcblxuICBkZXNjcmliZShgQmFieWxvbiBTdGFraW5nIFske3RhZ31dYCwgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdnZW5lcmF0ZXMgZXhwZWN0ZWQgc3Rha2luZyBzY3JpcHRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgYXNzZXJ0U2NyaXB0c0VxdWFsRml4dHVyZShcbiAgICAgICAgYHRlc3QvZml4dHVyZXMvYmFieWxvbi9zY3JpcHRzLiR7dGFnfS5qc29uYCxcbiAgICAgICAgdmVuZG9yQnVpbGRlcixcbiAgICAgICAgdmVuZG9yQnVpbGRlci5idWlsZFNjcmlwdHMoKVxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdtYXRjaGVzIGlubmVyIHRhcHJvb3Qgc2NyaXB0cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGFzc2VydEVxdWFsU2NyaXB0cyhkZXNjcmlwdG9yQnVpbGRlciwgdmVuZG9yQnVpbGRlci5idWlsZFNjcmlwdHMoKSk7XG4gICAgfSk7XG5cbiAgICBpdCgnbWF0Y2hlcyBvdXRwdXQgc2NyaXB0cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGFzc2VydEVxdWFsT3V0cHV0U2NyaXB0KFxuICAgICAgICB2ZW5kb3IuZGVyaXZlU3Rha2luZ091dHB1dEluZm8odmVuZG9yQnVpbGRlci5idWlsZFNjcmlwdHMoKSwgYml0Y29pbmpzbGliLm5ldHdvcmtzLmJpdGNvaW4pLFxuICAgICAgICBkZXNjcmlwdG9yQnVpbGRlci5nZXRTdGFraW5nRGVzY3JpcHRvcigpXG4gICAgICApO1xuICAgICAgYXNzZXJ0RXF1YWxPdXRwdXRTY3JpcHQoXG4gICAgICAgIHZlbmRvci5kZXJpdmVTbGFzaGluZ091dHB1dCh2ZW5kb3JCdWlsZGVyLmJ1aWxkU2NyaXB0cygpLCBiaXRjb2luanNsaWIubmV0d29ya3MuYml0Y29pbiksXG4gICAgICAgIGRlc2NyaXB0b3JCdWlsZGVyLmdldFNsYXNoaW5nRGVzY3JpcHRvcigpXG4gICAgICApO1xuICAgICAgYXNzZXJ0RXF1YWxPdXRwdXRTY3JpcHQoXG4gICAgICAgIHZlbmRvci5kZXJpdmVVbmJvbmRpbmdPdXRwdXRJbmZvKHZlbmRvckJ1aWxkZXIuYnVpbGRTY3JpcHRzKCksIGJpdGNvaW5qc2xpYi5uZXR3b3Jrcy5iaXRjb2luKSxcbiAgICAgICAgZGVzY3JpcHRvckJ1aWxkZXIuZ2V0VW5ib25kaW5nRGVzY3JpcHRvcigpXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ1RyYW5zYWN0aW9uIFNldHMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBzdGFrZXJNYWluV2FsbGV0S2V5ID0gZ2V0RUNLZXkoJ3N0YWtlck1haW5XYWxsZXQnKTtcbiAgICAgIGNvbnN0IG1haW5XYWxsZXQgPSB3cGtoRGVzY3JpcHRvcihzdGFrZXJNYWluV2FsbGV0S2V5KTtcbiAgICAgIGNvbnN0IGFtb3VudCA9IDU1XzU1NTtcbiAgICAgIGNvbnN0IGNoYW5nZUFkZHJlc3MgPSBjcmVhdGVBZGRyZXNzRnJvbURlc2NyaXB0b3IobWFpbldhbGxldCwgdW5kZWZpbmVkLCB1dHhvbGliLm5ldHdvcmtzLmJpdGNvaW4pO1xuICAgICAgY29uc3QgZmVlUmF0ZVNhdEIgPSAyO1xuICAgICAgY29uc3QgdXR4byA9IG1vY2tVdHhvKG1haW5XYWxsZXQpO1xuXG4gICAgICBsZXQgc3Rha2luZ1R4OiB2ZW5kb3IuVHJhbnNhY3Rpb25SZXN1bHQ7XG5cbiAgICAgIGJlZm9yZSgnc2V0dXAgc3Rha2luZ1R4JywgZnVuY3Rpb24gKCkge1xuICAgICAgICBzdGFraW5nVHggPSB2ZW5kb3Iuc3Rha2luZ1RyYW5zYWN0aW9uKFxuICAgICAgICAgIHZlbmRvckJ1aWxkZXIuYnVpbGRTY3JpcHRzKCksXG4gICAgICAgICAgYW1vdW50LFxuICAgICAgICAgIGNoYW5nZUFkZHJlc3MsXG4gICAgICAgICAgW21vY2tVdHhvKG1haW5XYWxsZXQpXSxcbiAgICAgICAgICBiaXRjb2luanNsaWIubmV0d29ya3MuYml0Y29pbixcbiAgICAgICAgICBmZWVSYXRlU2F0QlxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdoYXMgZXhwZWN0ZWQgdHJhbnNhY3Rpb25zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBhd2FpdCBhc3NlcnRUcmFuc2FjdGlvbkVxdWFsc0ZpeHR1cmUoYHRlc3QvZml4dHVyZXMvYmFieWxvbi9zdGFraW5nVHJhbnNhY3Rpb24uJHt0YWd9Lmpzb25gLCBzdGFraW5nVHgpO1xuXG4gICAgICAgIC8vIHNpbXBseSBvbmUgc3Rha2luZyBvdXRwdXQgYW5kIG9uZSBjaGFuZ2Ugb3V0cHV0XG4gICAgICAgIC8vIG5vdGhpbmcgc3BlY2lhbFxuICAgICAgICBhc3NlcnQuZGVlcFN0cmljdEVxdWFsKHN0YWtpbmdUeC50cmFuc2FjdGlvbi5vdXRzLCBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgc2NyaXB0OiBCdWZmZXIuZnJvbShkZXNjcmlwdG9yQnVpbGRlci5nZXRTdGFraW5nRGVzY3JpcHRvcigpLnNjcmlwdFB1YmtleSgpKSxcbiAgICAgICAgICAgIHZhbHVlOiBhbW91bnQsXG4gICAgICAgICAgfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzY3JpcHQ6IHV0eG9saWIuYWRkcmVzcy50b091dHB1dFNjcmlwdChjaGFuZ2VBZGRyZXNzLCB1dHhvbGliLm5ldHdvcmtzLmJpdGNvaW4pLFxuICAgICAgICAgICAgdmFsdWU6IHV0eG8udmFsdWUgLSBhbW91bnQgLSBzdGFraW5nVHguZmVlLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0pO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChmaW5hbGl0eVByb3ZpZGVyS2V5cy5sZW5ndGggIT09IDEpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBmaW5hbGl0eVByb3ZpZGVyID0gZmluYWxpdHlQcm92aWRlcktleXNbMF07XG5cbiAgICAgIGl0KCdoYXMgZXhwZWN0ZWQgdHJhbnNhY3Rpb25zICh2ZW5kb3JTdGFraW5nLlN0YWtpbmcpJywgYXN5bmMgZnVuY3Rpb24gKHRoaXM6IE1vY2hhLkNvbnRleHQpIHtcbiAgICAgICAgY29uc3QgdmVuZG9yU3Rha2luZ1R4QnVpbGRlciA9IG5ldyB2ZW5kb3IuU3Rha2luZyhcbiAgICAgICAgICBiaXRjb2luanNsaWIubmV0d29ya3MuYml0Y29pbixcbiAgICAgICAgICB0b1N0YWtlckluZm8oc3Rha2VyS2V5LCBjaGFuZ2VBZGRyZXNzKSxcbiAgICAgICAgICBzdGFraW5nUGFyYW1zLFxuICAgICAgICAgIGdldFhPbmx5UHVia2V5KGZpbmFsaXR5UHJvdmlkZXIpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgICAgICBzdGFraW5nUGFyYW1zLm1pblN0YWtpbmdUaW1lQmxvY2tzXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgdHhUcmVlID0gZ2V0U3Rha2luZ1RyYW5zYWN0aW9uVHJlZVZlbmRvcihcbiAgICAgICAgICB2ZW5kb3JTdGFraW5nVHhCdWlsZGVyLFxuICAgICAgICAgIGFtb3VudCxcbiAgICAgICAgICBbdXR4b10sXG4gICAgICAgICAgZmVlUmF0ZVNhdEIsXG4gICAgICAgICAgc2lnbkludGVybWVkaWF0ZVR4c1xuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgc3Rha2VyOiBzdGFrZXJLZXksXG4gICAgICAgICAgICAgICAgZmluYWxpdHlQcm92aWRlcixcbiAgICAgICAgICAgICAgICBjb3ZlbmFudDogY292ZW5hbnRLZXlzLFxuICAgICAgICAgICAgICAgIGNvdmVuYW50VGhyZXNob2xkOiBjb3ZlbmFudFRocmVzaG9sZCxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7IHN0YWtlcjogc3Rha2VyS2V5IH0sXG4gICAgICAgICAgZGVzY3JpcHRvckJ1aWxkZXJcbiAgICAgICAgKTtcbiAgICAgICAgYXdhaXQgYXNzZXJ0VHJhbnNhY3Rpb25FcXVhbHNGaXh0dXJlKGB0ZXN0L2ZpeHR1cmVzL2JhYnlsb24vdHhUcmVlLiR7dGFnfS5qc29uYCwgdHhUcmVlKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnY3JlYXRlcyBNc2dDcmVhdGVCVENEZWxlZ2F0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICB0eXBlIEYgPSB0eXBlb2YgZ2V0VmVuZG9yTXNnQ3JlYXRlQnRjRGVsZWdhdGlvbjtcbiAgICAgICAgY29uc3QgZlZlbmRvcjogRiA9IGdldFZlbmRvck1zZ0NyZWF0ZUJ0Y0RlbGVnYXRpb247XG4gICAgICAgIGNvbnN0IGZCaXRHbzogRiA9IGdldEJpdEdvVXR4b1N0YWtpbmdNc2dDcmVhdGVCdGNEZWxlZ2F0aW9uO1xuXG4gICAgICAgIGZvciAoY29uc3QgZiBvZiBbZlZlbmRvciwgZkJpdEdvXSkge1xuICAgICAgICAgIGF3YWl0IGFzc2VydEVxdWFsc0ZpeHR1cmUoXG4gICAgICAgICAgICBgdGVzdC9maXh0dXJlcy9iYWJ5bG9uL21zZ0NyZWF0ZUJUQ0RlbGVnYXRpb24uJHt0YWd9Lmpzb25gLFxuICAgICAgICAgICAgYXdhaXQgZihcbiAgICAgICAgICAgICAgYml0Y29pbmpzbGliLm5ldHdvcmtzLmJpdGNvaW4sXG4gICAgICAgICAgICAgIHN0YWtlcktleSxcbiAgICAgICAgICAgICAgZmluYWxpdHlQcm92aWRlcixcbiAgICAgICAgICAgICAgZGVzY3JpcHRvckJ1aWxkZXIsXG4gICAgICAgICAgICAgIFt7IC4uLnN0YWtpbmdQYXJhbXMsIHZlcnNpb246IDAsIGJ0Y0FjdGl2YXRpb25IZWlnaHQ6IDAgfV0sXG4gICAgICAgICAgICAgIGNoYW5nZUFkZHJlc3MsXG4gICAgICAgICAgICAgIGFtb3VudCxcbiAgICAgICAgICAgICAgdXR4byxcbiAgICAgICAgICAgICAgZmVlUmF0ZVNhdEIsXG4gICAgICAgICAgICAgIDgwMF8wMDBcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICBub3JtYWxpemUsXG4gICAgICAgICAgICAoYSwgYikgPT4ge1xuICAgICAgICAgICAgICAvLyBUaGUgdmVuZG9yIGxpYnJhcnkgc2VyaWFsaXplcyB0aGUgc2lnbmF0dXJlIGFzIEJJUDMyMiwgd2hpbGVcbiAgICAgICAgICAgICAgLy8gb3VyIGltcGxlbWVudGF0aW9uIHNlcmlhbGl6ZXMgaXQgYXMgRUNEU0EuXG4gICAgICAgICAgICAgIC8vIFN0cmlwIHRoZSBwb3AgZmllbGQgZnJvbSB0aGUgTXNnQ3JlYXRlQlRDRGVsZWdhdGlvbi5cbiAgICAgICAgICAgICAgZnVuY3Rpb24gc3RyaXBQb3AodjogdW5rbm93bikge1xuICAgICAgICAgICAgICAgIGNvbnN0IHZBbnkgPSB2IGFzIGFueTtcbiAgICAgICAgICAgICAgICBkZWxldGUgdkFueVsndW5zaWduZWREZWxlZ2F0aW9uTXNnJ11bJ3ZhbHVlJ11bJ3BvcCddO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHN0cmlwUG9wKGEpO1xuICAgICAgICAgICAgICBzdHJpcFBvcChiKTtcbiAgICAgICAgICAgICAgYXNzZXJ0LmRlZXBTdHJpY3RFcXVhbChhLCBiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2NyZWF0ZXMgdW5zdGFraW5nIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB1bnN0YWtpbmcgPSBjcmVhdGVVbnN0YWtpbmdUcmFuc2FjdGlvbihcbiAgICAgICAgICBzdGFraW5nVHgsXG4gICAgICAgICAgZGVzY3JpcHRvckJ1aWxkZXIuZ2V0U3Rha2luZ0Rlc2NyaXB0b3IoKSxcbiAgICAgICAgICBjaGFuZ2VBZGRyZXNzLFxuICAgICAgICAgIHsgc2VxdWVuY2U6IHN0YWtpbmdQYXJhbXMubWluU3Rha2luZ1RpbWVCbG9ja3MgfVxuICAgICAgICApO1xuICAgICAgICBjb25zdCB3cmFwcGVkUHNidCA9IHRvV3JhcHBlZFBzYnQodW5zdGFraW5nKTtcbiAgICAgICAgYXNzZXJ0KGdldE5ld1NpZ25hdHVyZUNvdW50KHNpZ25XaXRoS2V5KHdyYXBwZWRQc2J0LCBzdGFrZXJLZXkpKSA+IDApO1xuICAgICAgICB3cmFwcGVkUHNidC5maW5hbGl6ZSgpO1xuICAgICAgICBjb25zdCB0eCA9IHRvVXR4b1BzYnQod3JhcHBlZFBzYnQsIHV0eG9saWIubmV0d29ya3MuYml0Y29pbikuZXh0cmFjdFRyYW5zYWN0aW9uKCk7XG4gICAgICAgIGF3YWl0IGFzc2VydFRyYW5zYWN0aW9uRXF1YWxzRml4dHVyZShgdGVzdC9maXh0dXJlcy9iYWJ5bG9uL3Vuc3Rha2luZ1RyYW5zYWN0aW9uLiR7dGFnfS5qc29uYCwge1xuICAgICAgICAgIHRyYW5zYWN0aW9uOiB0eCxcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGRlc2NyaWJlV2l0aEtleXNGcm9tU3Rha2luZ1BhcmFtcyhcbiAgdGFnOiBzdHJpbmcsXG4gIGZpbmFsaXR5UHJvdmlkZXJLZXlzOiBFQ1BhaXJJbnRlcmZhY2VbXSxcbiAgc3Rha2luZ1BhcmFtczogdmVuZG9yLlN0YWtpbmdQYXJhbXNcbikge1xuICBkZXNjcmliZVdpdGhLZXlzKFxuICAgIHRhZyxcbiAgICBmaW5hbGl0eVByb3ZpZGVyS2V5cyxcbiAgICBzdGFraW5nUGFyYW1zLmNvdmVuYW50Tm9Db29yZFBrcy5tYXAoKHBrKSA9PiBmcm9tWE9ubHlQdWJsaWNLZXkoQnVmZmVyLmZyb20ocGssICdoZXgnKSkpLFxuICAgIHN0YWtpbmdQYXJhbXNcbiAgKTtcbn1cblxuZnVuY3Rpb24gZGVzY3JpYmVXaXRoTW9ja0tleXMoXG4gIHRhZzogc3RyaW5nLFxuICBzdGFraW5nUGFyYW1zOiB2ZW5kb3IuU3Rha2luZ1BhcmFtcyxcbiAgZmluYWxpdHlQcm92aWRlcktleXM6IEVDUGFpckludGVyZmFjZVtdLFxuICBjb3ZlbmFudEtleXM6IEVDUGFpckludGVyZmFjZVtdXG4pIHtcbiAgZGVzY3JpYmVXaXRoS2V5cyhcbiAgICB0YWcsXG4gICAgZmluYWxpdHlQcm92aWRlcktleXMsXG4gICAgY292ZW5hbnRLZXlzLFxuICAgIGdldFRlc3RuZXRTdGFraW5nUGFyYW1zV2l0aENvdmVuYW50KHN0YWtpbmdQYXJhbXMsIGNvdmVuYW50S2V5cyksXG4gICAge1xuICAgICAgc2lnbkludGVybWVkaWF0ZVR4czogdHJ1ZSxcbiAgICB9XG4gICk7XG59XG5cbmRlc2NyaWJlV2l0aEtleXNGcm9tU3Rha2luZ1BhcmFtcyhcbiAgJ3Rlc3RuZXQnLFxuICBbZnJvbVhPbmx5UHVibGljS2V5KHRlc3RuZXRGaW5hbGl0eVByb3ZpZGVyMCldLFxuICBnZXRCYWJ5bG9uUGFyYW1CeVZlcnNpb24oNSwgZ2V0U3Rha2luZ1BhcmFtcygndGVzdG5ldCcpKVxuKTtcbmRlc2NyaWJlV2l0aE1vY2tLZXlzKFxuICAndGVzdG5ldE1vY2snLFxuICBnZXRCYWJ5bG9uUGFyYW1CeVZlcnNpb24oNSwgZ2V0U3Rha2luZ1BhcmFtcygndGVzdG5ldCcpKSxcbiAgZ2V0RUNLZXlzKCdmaW5hbGl0eVByb3ZpZGVyJywgMSksXG4gIGdldEVDS2V5cygnY292ZW5hbnQnLCA5KVxuKTtcbiJdfQ==Выполнить команду
Для локальной разработки. Не используйте в интернете!