PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-injective/dist/test/unit
Просмотр файла: injective.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const abstract_cosmos_1 = require("@bitgo/abstract-cosmos");
const sdk_api_1 = require("@bitgo/sdk-api");
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const sdk_test_1 = require("@bitgo/sdk-test");
const statics_1 = require("@bitgo/statics");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const mocha_1 = require("mocha");
const sinon_1 = __importDefault(require("sinon"));
const src_1 = require("../../src");
const utils_1 = __importDefault(require("../../src/lib/utils"));
const injective_1 = require("../resources/injective");
const should = require("should");
const nock = require("nock");
describe('INJ', function () {
let bitgo;
let basecoin;
before(function () {
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
bitgo.safeRegister('injective', src_1.Injective.createInstance);
bitgo.safeRegister('tinjective', src_1.Tinjective.createInstance);
bitgo.initializeTestVars();
basecoin = bitgo.coin('tinjective');
});
it('should return the right info', function () {
const injective = bitgo.coin('injective');
const tinjective = bitgo.coin('tinjective');
injective.getChain().should.equal('injective');
injective.getFamily().should.equal('injective');
injective.getFullName().should.equal('Injective');
injective.getBaseFactor().should.equal(1e18);
tinjective.getChain().should.equal('tinjective');
tinjective.getFamily().should.equal('injective');
tinjective.getFullName().should.equal('Testnet Injective');
tinjective.getBaseFactor().should.equal(1e18);
});
describe('Address Validation', () => {
it('should get address details without memoId', function () {
const addressDetails = basecoin.getAddressDetails(injective_1.address.noMemoIdAddress);
addressDetails.address.should.equal(injective_1.address.noMemoIdAddress);
should.not.exist(addressDetails.memoId);
});
it('should get address details with memoId', function () {
const addressDetails = basecoin.getAddressDetails(injective_1.address.validMemoIdAddress);
addressDetails.address.should.equal(injective_1.address.validMemoIdAddress.split('?')[0]);
addressDetails.memoId.should.equal('2');
});
it('should throw on multiple memo id address', () => {
(() => {
basecoin.getAddressDetails(injective_1.address.multipleMemoIdAddress);
}).should.throw();
});
it('should validate wallet receive address', async function () {
const receiveAddress = {
address: 'inj1vftzm2nnlt0x8z9gq2hgxxywlk79m8k7k3ljgk?memoId=7',
coinSpecific: {
rootAddress: 'inj1vftzm2nnlt0x8z9gq2hgxxywlk79m8k7k3ljgk',
memoID: '7',
},
};
const isValid = await basecoin.isWalletAddress(receiveAddress);
isValid.should.equal(true);
});
it('should validate account addresses correctly', () => {
should.equal(utils_1.default.isValidAddress(injective_1.address.address1), true);
should.equal(utils_1.default.isValidAddress(injective_1.address.address2), true);
should.equal(utils_1.default.isValidAddress(injective_1.address.address3), false);
should.equal(utils_1.default.isValidAddress(injective_1.address.address4), false);
should.equal(utils_1.default.isValidAddress('dfjk35y'), false);
should.equal(utils_1.default.isValidAddress(undefined), false);
should.equal(utils_1.default.isValidAddress(''), false);
should.equal(utils_1.default.isValidAddress(injective_1.address.validMemoIdAddress), true);
should.equal(utils_1.default.isValidAddress(injective_1.address.multipleMemoIdAddress), false);
});
it('should validate validator addresses correctly', () => {
should.equal(utils_1.default.isValidValidatorAddress(injective_1.address.validatorAddress1), true);
should.equal(utils_1.default.isValidValidatorAddress(injective_1.address.validatorAddress2), true);
should.equal(utils_1.default.isValidValidatorAddress(injective_1.address.validatorAddress3), false);
should.equal(utils_1.default.isValidValidatorAddress(injective_1.address.validatorAddress4), false);
should.equal(utils_1.default.isValidValidatorAddress('dfjk35y'), false);
should.equal(utils_1.default.isValidValidatorAddress(undefined), false);
should.equal(utils_1.default.isValidValidatorAddress(''), false);
});
});
describe('Verify transaction: ', () => {
it('should succeed to verify transaction', async function () {
const txPrebuild = {
txHex: injective_1.TEST_SEND_TX.signedTxBase64,
txInfo: {},
};
const txParams = {
recipients: [
{
address: injective_1.TEST_SEND_TX.recipient,
amount: injective_1.TEST_SEND_TX.sendAmount,
},
],
};
const verification = {};
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
isTransactionVerified.should.equal(true);
});
it('should succeed to verify delegate transaction', async function () {
const txPrebuild = {
txHex: injective_1.TEST_DELEGATE_TX.signedTxBase64,
txInfo: {},
};
const txParams = {
recipients: [
{
address: injective_1.TEST_DELEGATE_TX.validator,
amount: injective_1.TEST_DELEGATE_TX.sendAmount,
},
],
};
const verification = {};
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
isTransactionVerified.should.equal(true);
});
it('should succeed to verify undelegate transaction', async function () {
const txPrebuild = {
txHex: injective_1.TEST_UNDELEGATE_TX.signedTxBase64,
txInfo: {},
};
const txParams = {
recipients: [
{
address: injective_1.TEST_UNDELEGATE_TX.validator,
amount: injective_1.TEST_UNDELEGATE_TX.sendAmount,
},
],
};
const verification = {};
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
isTransactionVerified.should.equal(true);
});
it('should succeed to verify withdraw rewards transaction', async function () {
const txPrebuild = {
txHex: injective_1.TEST_WITHDRAW_REWARDS_TX.signedTxBase64,
txInfo: {},
};
const txParams = {
recipients: [
{
address: injective_1.TEST_WITHDRAW_REWARDS_TX.validator,
amount: 'UNAVAILABLE',
},
],
};
const verification = {};
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
isTransactionVerified.should.equal(true);
});
it('should fail to verify transaction with invalid param', async function () {
const txPrebuild = {};
const txParams = { recipients: undefined };
await basecoin
.verifyTransaction({
txParams,
txPrebuild,
})
.should.rejectedWith('missing required tx prebuild property txHex');
});
});
describe('Explain Transaction: ', () => {
it('should explain a transfer transaction', async function () {
const explainedTransaction = await basecoin.explainTransaction({
txHex: injective_1.TEST_SEND_TX.signedTxBase64,
});
explainedTransaction.should.deepEqual({
displayOrder: ['id', 'outputs', 'outputAmount', 'changeOutputs', 'changeAmount', 'fee', 'type'],
id: injective_1.TEST_SEND_TX.hash,
outputs: [
{
address: injective_1.TEST_SEND_TX.recipient,
amount: injective_1.TEST_SEND_TX.sendAmount,
},
],
outputAmount: injective_1.TEST_SEND_TX.sendAmount,
changeOutputs: [],
changeAmount: '0',
fee: { fee: injective_1.TEST_SEND_TX.gasBudget.amount[0].amount },
type: 0,
});
});
it('should explain a delegate transaction', async function () {
const explainedTransaction = await basecoin.explainTransaction({
txHex: injective_1.TEST_DELEGATE_TX.signedTxBase64,
});
explainedTransaction.should.deepEqual({
displayOrder: ['id', 'outputs', 'outputAmount', 'changeOutputs', 'changeAmount', 'fee', 'type'],
id: injective_1.TEST_DELEGATE_TX.hash,
outputs: [
{
address: injective_1.TEST_DELEGATE_TX.validator,
amount: injective_1.TEST_DELEGATE_TX.sendAmount,
},
],
outputAmount: injective_1.TEST_DELEGATE_TX.sendAmount,
changeOutputs: [],
changeAmount: '0',
fee: { fee: injective_1.TEST_DELEGATE_TX.gasBudget.amount[0].amount },
type: 13,
});
});
it('should explain a undelegate transaction', async function () {
const explainedTransaction = await basecoin.explainTransaction({
txHex: injective_1.TEST_UNDELEGATE_TX.signedTxBase64,
});
explainedTransaction.should.deepEqual({
displayOrder: ['id', 'outputs', 'outputAmount', 'changeOutputs', 'changeAmount', 'fee', 'type'],
id: injective_1.TEST_UNDELEGATE_TX.hash,
outputs: [
{
address: injective_1.TEST_UNDELEGATE_TX.validator,
amount: injective_1.TEST_UNDELEGATE_TX.sendAmount,
},
],
outputAmount: injective_1.TEST_UNDELEGATE_TX.sendAmount,
changeOutputs: [],
changeAmount: '0',
fee: { fee: injective_1.TEST_UNDELEGATE_TX.gasBudget.amount[0].amount },
type: 17,
});
});
it('should explain a withdraw transaction', async function () {
const explainedTransaction = await basecoin.explainTransaction({
txHex: injective_1.TEST_WITHDRAW_REWARDS_TX.signedTxBase64,
});
explainedTransaction.should.deepEqual({
displayOrder: ['id', 'outputs', 'outputAmount', 'changeOutputs', 'changeAmount', 'fee', 'type'],
id: injective_1.TEST_WITHDRAW_REWARDS_TX.hash,
outputs: [
{
address: injective_1.TEST_WITHDRAW_REWARDS_TX.validator,
amount: 'UNAVAILABLE',
},
],
outputAmount: undefined,
changeOutputs: [],
changeAmount: '0',
fee: { fee: injective_1.TEST_WITHDRAW_REWARDS_TX.gasBudget.amount[0].amount },
type: 15,
});
});
it('should explain a transfer transaction with memo', async function () {
const explainedTransaction = await basecoin.explainTransaction({
txHex: injective_1.TEST_TX_WITH_MEMO.signedTxBase64,
});
explainedTransaction.should.deepEqual({
displayOrder: ['id', 'outputs', 'outputAmount', 'changeOutputs', 'changeAmount', 'fee', 'type'],
id: injective_1.TEST_TX_WITH_MEMO.hash,
outputs: [
{
address: injective_1.TEST_TX_WITH_MEMO.to,
amount: injective_1.TEST_TX_WITH_MEMO.sendAmount,
memo: injective_1.TEST_TX_WITH_MEMO.memo,
},
],
outputAmount: injective_1.TEST_TX_WITH_MEMO.sendAmount,
changeOutputs: [],
changeAmount: '0',
fee: { fee: injective_1.TEST_TX_WITH_MEMO.gasBudget.amount[0].amount },
type: 0,
});
});
it('should fail to explain transaction with missing params', async function () {
try {
await basecoin.explainTransaction({});
}
catch (error) {
should.equal(error.message, 'missing required txHex parameter');
}
});
it('should fail to explain transaction with invalid params', async function () {
try {
await basecoin.explainTransaction({ txHex: 'randomString' });
}
catch (error) {
should.equal(error.message.startsWith('Invalid transaction:'), true);
}
});
});
describe('Parse Transactions: ', () => {
it('should parse a transfer transaction', async function () {
const transferInputsResponse = {
address: injective_1.TEST_SEND_TX.recipient,
amount: new bignumber_js_1.default(injective_1.TEST_SEND_TX.sendAmount).plus(injective_1.TEST_SEND_TX.gasBudget.amount[0].amount).toFixed(),
};
const transferOutputsResponse = {
address: injective_1.TEST_SEND_TX.recipient,
amount: injective_1.TEST_SEND_TX.sendAmount,
};
const parsedTransaction = await basecoin.parseTransaction({ txHex: injective_1.TEST_SEND_TX.signedTxBase64 });
parsedTransaction.should.deepEqual({
inputs: [transferInputsResponse],
outputs: [transferOutputsResponse],
});
});
it('should fail to parse a transfer transaction when explainTransaction response is undefined', async function () {
const stub = sinon_1.default.stub(src_1.Injective.prototype, 'explainTransaction');
stub.resolves(undefined);
await basecoin
.parseTransaction({ txHex: injective_1.TEST_SEND_TX.signedTxBase64 })
.should.be.rejectedWith('Invalid transaction');
stub.restore();
});
});
describe('Recover transaction: success path', () => {
const sandBox = sinon_1.default.createSandbox();
const destinationAddress = injective_1.wrwUser.destinationAddress;
const coin = statics_1.coins.get('tinjective');
const testBalance = '15000000000000000';
const testChainId = 'test-chain';
(0, mocha_1.beforeEach)(() => {
nock('https://testnet.sentry.lcd.injective.network')
.get('/cosmos/auth/v1beta1/accounts/' + injective_1.wrwUser.senderAddress)
.reply(200, injective_1.mockAccountDetailsResponse);
const accountBalance = sandBox.stub(src_1.Injective.prototype, 'getAccountBalance');
accountBalance.withArgs(injective_1.wrwUser.senderAddress).resolves(testBalance);
const chainId = sandBox.stub(src_1.Injective.prototype, 'getChainId');
chainId.withArgs().resolves(testChainId);
const deserializedEntChallenge = sdk_lib_mpc_1.EcdsaTypes.deserializeNtildeWithProofs(sdk_test_1.mockSerializedChallengeWithProofs);
sinon_1.default.stub(sdk_lib_mpc_1.EcdsaRangeProof, 'generateNtilde').resolves(deserializedEntChallenge);
});
afterEach(() => {
sandBox.restore();
sinon_1.default.restore();
});
it('should recover funds for non-bitgo recoveries', async function () {
const res = await basecoin.recover({
userKey: injective_1.wrwUser.userPrivateKey,
backupKey: injective_1.wrwUser.backupPrivateKey,
bitgoKey: injective_1.wrwUser.bitgoPublicKey,
walletPassphrase: injective_1.wrwUser.walletPassphrase,
recoveryDestination: destinationAddress,
});
res.should.not.be.empty();
res.should.hasOwnProperty('serializedTx');
sandBox.assert.calledOnce(basecoin.getAccountBalance);
sandBox.assert.calledOnce(basecoin.getChainId);
const txn = new abstract_cosmos_1.CosmosTransaction(coin, utils_1.default);
txn.enrichTransactionDetailsFromRawTransaction(res.serializedTx);
const txnJson = txn.toJson();
const sendMessage = txnJson.sendMessages[0].value;
const balance = new bignumber_js_1.default(testBalance);
const gasAmount = new bignumber_js_1.default(125000000000000);
const actualBalance = balance.minus(gasAmount);
should.equal(sendMessage.toAddress, destinationAddress);
should.equal(sendMessage.amount[0].amount, actualBalance.toFixed());
});
});
describe('Recover transaction: failure path', () => {
const sandBox = sinon_1.default.createSandbox();
const destinationAddress = injective_1.wrwUser.destinationAddress;
const testZeroBalance = '0';
const testChainId = 'test-chain';
(0, mocha_1.beforeEach)(() => {
nock('https://testnet.sentry.lcd.injective.network')
.get('/cosmos/auth/v1beta1/accounts/' + injective_1.wrwUser.senderAddress)
.reply(200, injective_1.mockAccountDetailsResponse);
const accountBalance = sandBox.stub(src_1.Injective.prototype, 'getAccountBalance');
accountBalance.withArgs(injective_1.wrwUser.senderAddress).resolves(testZeroBalance);
const chainId = sandBox.stub(src_1.Injective.prototype, 'getChainId');
chainId.withArgs().resolves(testChainId);
const deserializedEntChallenge = sdk_lib_mpc_1.EcdsaTypes.deserializeNtildeWithProofs(sdk_test_1.mockSerializedChallengeWithProofs);
sinon_1.default.stub(sdk_lib_mpc_1.EcdsaRangeProof, 'generateNtilde').resolves(deserializedEntChallenge);
});
afterEach(() => {
sandBox.restore();
sinon_1.default.restore();
});
it('should throw error if backupkey is not present', async function () {
await basecoin
.recover({
userKey: injective_1.wrwUser.userPrivateKey,
bitgoKey: injective_1.wrwUser.bitgoPublicKey,
walletPassphrase: injective_1.wrwUser.walletPassphrase,
recoveryDestination: destinationAddress,
})
.should.rejectedWith('missing backupKey');
});
it('should throw error if userkey is not present', async function () {
await basecoin
.recover({
backupKey: injective_1.wrwUser.backupPrivateKey,
bitgoKey: injective_1.wrwUser.bitgoPublicKey,
walletPassphrase: injective_1.wrwUser.walletPassphrase,
recoveryDestination: destinationAddress,
})
.should.rejectedWith('missing userKey');
});
it('should throw error if wallet passphrase is not present', async function () {
await basecoin
.recover({
userKey: injective_1.wrwUser.userPrivateKey,
backupKey: injective_1.wrwUser.backupPrivateKey,
bitgoKey: injective_1.wrwUser.bitgoPublicKey,
recoveryDestination: destinationAddress,
})
.should.rejectedWith('missing wallet passphrase');
});
it('should throw error if there is no balance', async function () {
await basecoin
.recover({
userKey: injective_1.wrwUser.userPrivateKey,
backupKey: injective_1.wrwUser.backupPrivateKey,
bitgoKey: injective_1.wrwUser.bitgoPublicKey,
walletPassphrase: injective_1.wrwUser.walletPassphrase,
recoveryDestination: destinationAddress,
})
.should.rejectedWith('Did not have enough funds to recover');
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5qZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdGVzdC91bml0L2luamVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDREQUF3RTtBQUN4RSw0Q0FBMEM7QUFDMUMsb0RBQWlFO0FBQ2pFLDhDQUE2RjtBQUM3Riw0Q0FBdUM7QUFDdkMsZ0VBQXFDO0FBQ3JDLGlDQUFtQztBQUNuQyxrREFBMEI7QUFDMUIsbUNBQWtEO0FBQ2xELGdFQUF3QztBQUN4QyxzREFTZ0M7QUFDaEMsaUNBQWtDO0FBQ2xDLDZCQUE4QjtBQUU5QixRQUFRLENBQUMsS0FBSyxFQUFFO0lBQ2QsSUFBSSxLQUFtQixDQUFDO0lBQ3hCLElBQUksUUFBUSxDQUFDO0lBQ2IsTUFBTSxDQUFDO1FBQ0wsS0FBSyxHQUFHLG9CQUFTLENBQUMsUUFBUSxDQUFDLGtCQUFRLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUN0RCxLQUFLLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxlQUFTLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDMUQsS0FBSyxDQUFDLFlBQVksQ0FBQyxZQUFZLEVBQUUsZ0JBQVUsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUM1RCxLQUFLLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMzQixRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUN0QyxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQyw4QkFBOEIsRUFBRTtRQUNqQyxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzFDLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFNUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDL0MsU0FB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QywyQ0FBMkMsRUFBRSxLQUFLO1lBQ25ELE1BQU0sUUFBUTtpQkFDWCxPQUFPLENBQUM7Z0JBQ1AsT0FBTyxFQUFFLG1CQUFPLENBQUMsY0FBYztnQkFDL0IsU0FBUyxFQUFFLG1CQUFPLENBQUMsZ0JBQWdCO2dCQUNuQyxRQUFRLEVBQUUsbUJBQU8sQ0FBQyxjQUFjO2dCQUNoQyxnQkFBZ0IsRUFBRSxtQkFBTyxDQUFDLGdCQUFnQjtnQkFDMUMsbUJBQW1CLEVBQUUsa0JBQWtCO2FBQ3hDLENBQUM7aUJBQ0QsTUFBTSxDQUFDLFlBQVksQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1FBQ2pFLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvc21vc1RyYW5zYWN0aW9uLCBTZW5kTWVzc2FnZSB9IGZyb20gJ0BiaXRnby9hYnN0cmFjdC1jb3Ntb3MnO1xuaW1wb3J0IHsgQml0R29BUEkgfSBmcm9tICdAYml0Z28vc2RrLWFwaSc7XG5pbXBvcnQgeyBFY2RzYVJhbmdlUHJvb2YsIEVjZHNhVHlwZXMgfSBmcm9tICdAYml0Z28vc2RrLWxpYi1tcGMnO1xuaW1wb3J0IHsgbW9ja1NlcmlhbGl6ZWRDaGFsbGVuZ2VXaXRoUHJvb2ZzLCBUZXN0Qml0R28sIFRlc3RCaXRHb0FQSSB9IGZyb20gJ0BiaXRnby9zZGstdGVzdCc7XG5pbXBvcnQgeyBjb2lucyB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcbmltcG9ydCBCaWdOdW1iZXIgZnJvbSAnYmlnbnVtYmVyLmpzJztcbmltcG9ydCB7IGJlZm9yZUVhY2ggfSBmcm9tICdtb2NoYSc7XG5pbXBvcnQgc2lub24gZnJvbSAnc2lub24nO1xuaW1wb3J0IHsgSW5qZWN0aXZlLCBUaW5qZWN0aXZlIH0gZnJvbSAnLi4vLi4vc3JjJztcbmltcG9ydCB1dGlscyBmcm9tICcuLi8uLi9zcmMvbGliL3V0aWxzJztcbmltcG9ydCB7XG4gIGFkZHJlc3MsXG4gIG1vY2tBY2NvdW50RGV0YWlsc1Jlc3BvbnNlLFxuICBURVNUX0RFTEVHQVRFX1RYLFxuICBURVNUX1NFTkRfVFgsXG4gIFRFU1RfVFhfV0lUSF9NRU1PLFxuICBURVNUX1VOREVMRUdBVEVfVFgsXG4gIFRFU1RfV0lUSERSQVdfUkVXQVJEU19UWCxcbiAgd3J3VXNlcixcbn0gZnJvbSAnLi4vcmVzb3VyY2VzL2luamVjdGl2ZSc7XG5pbXBvcnQgc2hvdWxkID0gcmVxdWlyZSgnc2hvdWxkJyk7XG5pbXBvcnQgbm9jayA9IHJlcXVpcmUoJ25vY2snKTtcblxuZGVzY3JpYmUoJ0lOSicsIGZ1bmN0aW9uICgpIHtcbiAgbGV0IGJpdGdvOiBUZXN0Qml0R29BUEk7XG4gIGxldCBiYXNlY29pbjtcbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHb0FQSSwgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIoJ2luamVjdGl2ZScsIEluamVjdGl2ZS5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCd0aW5qZWN0aXZlJywgVGluamVjdGl2ZS5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYmFzZWNvaW4gPSBiaXRnby5jb2luKCd0aW5qZWN0aXZlJyk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRoZSByaWdodCBpbmZvJywgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IGluamVjdGl2ZSA9IGJpdGdvLmNvaW4oJ2luamVjdGl2ZScpO1xuICAgIGNvbnN0IHRpbmplY3RpdmUgPSBiaXRnby5jb2luKCd0aW5qZWN0aXZlJyk7XG5cbiAgICBpbmplY3RpdmUuZ2V0Q2hhaW4oKS5zaG91bGQuZXF1YWwoJ2luamVjdGl2ZScpO1xuICAgIGluamVjdGl2ZS5nZXRGYW1pbHkoKS5zaG91bGQuZXF1YWwoJ2luamVjdGl2ZScpO1xuICAgIGluamVjdGl2ZS5nZXRGdWxsTmFtZSgpLnNob3VsZC5lcXVhbCgnSW5qZWN0aXZlJyk7XG4gICAgaW5qZWN0aXZlLmdldEJhc2VGYWN0b3IoKS5zaG91bGQuZXF1YWwoMWUxOCk7XG5cbiAgICB0aW5qZWN0aXZlLmdldENoYWluKCkuc2hvdWxkLmVxdWFsKCd0aW5qZWN0aXZlJyk7XG4gICAgdGluamVjdGl2ZS5nZXRGYW1pbHkoKS5zaG91bGQuZXF1YWwoJ2luamVjdGl2ZScpO1xuICAgIHRpbmplY3RpdmUuZ2V0RnVsbE5hbWUoKS5zaG91bGQuZXF1YWwoJ1Rlc3RuZXQgSW5qZWN0aXZlJyk7XG4gICAgdGluamVjdGl2ZS5nZXRCYXNlRmFjdG9yKCkuc2hvdWxkLmVxdWFsKDFlMTgpO1xuICB9KTtcblxuICBkZXNjcmliZSgnQWRkcmVzcyBWYWxpZGF0aW9uJywgKCkgPT4ge1xuICAgIGl0KCdzaG91bGQgZ2V0IGFkZHJlc3MgZGV0YWlscyB3aXRob3V0IG1lbW9JZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGFkZHJlc3NEZXRhaWxzID0gYmFzZWNvaW4uZ2V0QWRkcmVzc0RldGFpbHMoYWRkcmVzcy5ub01lbW9JZEFkZHJlc3MpO1xuICAgICAgYWRkcmVzc0RldGFpbHMuYWRkcmVzcy5zaG91bGQuZXF1YWwoYWRkcmVzcy5ub01lbW9JZEFkZHJlc3MpO1xuICAgICAgc2hvdWxkLm5vdC5leGlzdChhZGRyZXNzRGV0YWlscy5tZW1vSWQpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZXQgYWRkcmVzcyBkZXRhaWxzIHdpdGggbWVtb0lkJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYWRkcmVzc0RldGFpbHMgPSBiYXNlY29pbi5nZXRBZGRyZXNzRGV0YWlscyhhZGRyZXNzLnZhbGlkTWVtb0lkQWRkcmVzcyk7XG4gICAgICBhZGRyZXNzRGV0YWlscy5hZGRyZXNzLnNob3VsZC5lcXVhbChhZGRyZXNzLnZhbGlkTWVtb0lkQWRkcmVzcy5zcGxpdCgnPycpWzBdKTtcbiAgICAgIGFkZHJlc3NEZXRhaWxzLm1lbW9JZC5zaG91bGQuZXF1YWwoJzInKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gbXVsdGlwbGUgbWVtbyBpZCBhZGRyZXNzJywgKCkgPT4ge1xuICAgICAgKCgpID0+IHtcbiAgICAgICAgYmFzZWNvaW4uZ2V0QWRkcmVzc0RldGFpbHMoYWRkcmVzcy5tdWx0aXBsZU1lbW9JZEFkZHJlc3MpO1xuICAgICAgfSkuc2hvdWxkLnRocm93KCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZhbGlkYXRlIHdhbGxldCByZWNlaXZlIGFkZHJlc3MnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZWNlaXZlQWRkcmVzcyA9IHtcbiAgICAgICAgYWRkcmVzczogJ2luajF2ZnR6bTJubmx0MHg4ejlncTJoZ3h4eXdsazc5bThrN2szbGpnaz9tZW1vSWQ9NycsXG4gICAgICAgIGNvaW5TcGVjaWZpYzoge1xuICAgICAgICAgIHJvb3RBZGRyZXNzOiAnaW5qMXZmdHptMm5ubHQweDh6OWdxMmhneHh5d2xrNzltOGs3azNsamdrJyxcbiAgICAgICAgICBtZW1vSUQ6ICc3JyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBjb25zdCBpc1ZhbGlkID0gYXdhaXQgYmFzZWNvaW4uaXNXYWxsZXRBZGRyZXNzKHJlY2VpdmVBZGRyZXNzKTtcbiAgICAgIGlzVmFsaWQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB2YWxpZGF0ZSBhY2NvdW50IGFkZHJlc3NlcyBjb3JyZWN0bHknLCAoKSA9PiB7XG4gICAgICBzaG91bGQuZXF1YWwodXRpbHMuaXNWYWxpZEFkZHJlc3MoYWRkcmVzcy5hZGRyZXNzMSksIHRydWUpO1xuICAgICAgc2hvdWxkLmVxdWFsKHV0aWxzLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3MuYWRkcmVzczIpLCB0cnVlKTtcbiAgICAgIHNob3VsZC5lcXVhbCh1dGlscy5pc1ZhbGlkQWRkcmVzcyhhZGRyZXNzLmFkZHJlc3MzKSwgZmFsc2UpO1xuICAgICAgc2hvdWxkLmVxdWFsKHV0aWxzLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3MuYWRkcmVzczQpLCBmYWxzZSk7XG4gICAgICBzaG91bGQuZXF1YWwodXRpbHMuaXNWYWxpZEFkZHJlc3MoJ2RmamszNXknKSwgZmFsc2UpO1xuICAgICAgc2hvdWxkLmVxdWFsKHV0aWxzLmlzVmFsaWRBZGRyZXNzKHVuZGVmaW5lZCBhcyB1bmtub3duIGFzIHN0cmluZyksIGZhbHNlKTtcbiAgICAgIHNob3VsZC5lcXVhbCh1dGlscy5pc1ZhbGlkQWRkcmVzcygnJyksIGZhbHNlKTtcbiAgICAgIHNob3VsZC5lcXVhbCh1dGlscy5pc1ZhbGlkQWRkcmVzcyhhZGRyZXNzLnZhbGlkTWVtb0lkQWRkcmVzcyksIHRydWUpO1xuICAgICAgc2hvdWxkLmVxdWFsKHV0aWxzLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3MubXVsdGlwbGVNZW1vSWRBZGRyZXNzKSwgZmFsc2UpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB2YWxpZGF0ZSB2YWxpZGF0b3IgYWRkcmVzc2VzIGNvcnJlY3RseScsICgpID0+IHtcbiAgICAgIHNob3VsZC5lcXVhbCh1dGlscy5pc1ZhbGlkVmFsaWRhdG9yQWRkcmVzcyhhZGRyZXNzLnZhbGlkYXRvckFkZHJlc3MxKSwgdHJ1ZSk7XG4gICAgICBzaG91bGQuZXF1YWwodXRpbHMuaXNWYWxpZFZhbGlkYXRvckFkZHJlc3MoYWRkcmVzcy52YWxpZGF0b3JBZGRyZXNzMiksIHRydWUpO1xuICAgICAgc2hvdWxkLmVxdWFsKHV0aWxzLmlzVmFsaWRWYWxpZGF0b3JBZGRyZXNzKGFkZHJlc3MudmFsaWRhdG9yQWRkcmVzczMpLCBmYWxzZSk7XG4gICAgICBzaG91bGQuZXF1YWwodXRpbHMuaXNWYWxpZFZhbGlkYXRvckFkZHJlc3MoYWRkcmVzcy52YWxpZGF0b3JBZGRyZXNzNCksIGZhbHNlKTtcbiAgICAgIHNob3VsZC5lcXVhbCh1dGlscy5pc1ZhbGlkVmFsaWRhdG9yQWRkcmVzcygnZGZqazM1eScpLCBmYWxzZSk7XG4gICAgICBzaG91bGQuZXF1YWwodXRpbHMuaXNWYWxpZFZhbGlkYXRvckFkZHJlc3ModW5kZWZpbmVkIGFzIHVua25vd24gYXMgc3RyaW5nKSwgZmFsc2UpO1xuICAgICAgc2hvdWxkLmVxdWFsKHV0aWxzLmlzVmFsaWRWYWxpZGF0b3JBZGRyZXNzKCcnKSwgZmFsc2UpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnVmVyaWZ5IHRyYW5zYWN0aW9uOiAnLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBzdWNjZWVkIHRvIHZlcmlmeSB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSB7XG4gICAgICAgIHR4SGV4OiBURVNUX1NFTkRfVFguc2lnbmVkVHhCYXNlNjQsXG4gICAgICAgIHR4SW5mbzoge30sXG4gICAgICB9O1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICAgIHJlY2lwaWVudHM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhZGRyZXNzOiBURVNUX1NFTkRfVFgucmVjaXBpZW50LFxuICAgICAgICAgICAgYW1vdW50OiBURVNUX1NFTkRfVFguc2VuZEFtb3VudCxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuICAgICAgY29uc3QgaXNUcmFuc2FjdGlvblZlcmlmaWVkID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgdmVyaWZpY2F0aW9uIH0pO1xuICAgICAgaXNUcmFuc2FjdGlvblZlcmlmaWVkLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc3VjY2VlZCB0byB2ZXJpZnkgZGVsZWdhdGUgdHJhbnNhY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgICAgICB0eEhleDogVEVTVF9ERUxFR0FURV9UWC5zaWduZWRUeEJhc2U2NCxcbiAgICAgICAgdHhJbmZvOiB7fSxcbiAgICAgIH07XG4gICAgICBjb25zdCB0eFBhcmFtcyA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFkZHJlc3M6IFRFU1RfREVMRUdBVEVfVFgudmFsaWRhdG9yLFxuICAgICAgICAgICAgYW1vdW50OiBURVNUX0RFTEVHQVRFX1RYLnNlbmRBbW91bnQsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgICBjb25zdCB2ZXJpZmljYXRpb24gPSB7fTtcbiAgICAgIGNvbnN0IGlzVHJhbnNhY3Rpb25WZXJpZmllZCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHZlcmlmaWNhdGlvbiB9KTtcbiAgICAgIGlzVHJhbnNhY3Rpb25WZXJpZmllZC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN1Y2NlZWQgdG8gdmVyaWZ5IHVuZGVsZWdhdGUgdHJhbnNhY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgICAgICB0eEhleDogVEVTVF9VTkRFTEVHQVRFX1RYLnNpZ25lZFR4QmFzZTY0LFxuICAgICAgICB0eEluZm86IHt9LFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogVEVTVF9VTkRFTEVHQVRFX1RYLnZhbGlkYXRvcixcbiAgICAgICAgICAgIGFtb3VudDogVEVTVF9VTkRFTEVHQVRFX1RYLnNlbmRBbW91bnQsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgICBjb25zdCB2ZXJpZmljYXRpb24gPSB7fTtcbiAgICAgIGNvbnN0IGlzVHJhbnNhY3Rpb25WZXJpZmllZCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHZlcmlmaWNhdGlvbiB9KTtcbiAgICAgIGlzVHJhbnNhY3Rpb25WZXJpZmllZC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN1Y2NlZWQgdG8gdmVyaWZ5IHdpdGhkcmF3IHJld2FyZHMgdHJhbnNhY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgICAgICB0eEhleDogVEVTVF9XSVRIRFJBV19SRVdBUkRTX1RYLnNpZ25lZFR4QmFzZTY0LFxuICAgICAgICB0eEluZm86IHt9LFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogVEVTVF9XSVRIRFJBV19SRVdBUkRTX1RYLnZhbGlkYXRvcixcbiAgICAgICAgICAgIGFtb3VudDogJ1VOQVZBSUxBQkxFJyxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuICAgICAgY29uc3QgaXNUcmFuc2FjdGlvblZlcmlmaWVkID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgdmVyaWZpY2F0aW9uIH0pO1xuICAgICAgaXNUcmFuc2FjdGlvblZlcmlmaWVkLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB0byB2ZXJpZnkgdHJhbnNhY3Rpb24gd2l0aCBpbnZhbGlkIHBhcmFtJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHt9O1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSB7IHJlY2lwaWVudHM6IHVuZGVmaW5lZCB9O1xuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtcyxcbiAgICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLnJlamVjdGVkV2l0aCgnbWlzc2luZyByZXF1aXJlZCB0eCBwcmVidWlsZCBwcm9wZXJ0eSB0eEhleCcpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnRXhwbGFpbiBUcmFuc2FjdGlvbjogJywgKCkgPT4ge1xuICAgIGl0KCdzaG91bGQgZXhwbGFpbiBhIHRyYW5zZmVyIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXhwbGFpbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oe1xuICAgICAgICB0eEhleDogVEVTVF9TRU5EX1RYLnNpZ25lZFR4QmFzZTY0LFxuICAgICAgfSk7XG4gICAgICBleHBsYWluZWRUcmFuc2FjdGlvbi5zaG91bGQuZGVlcEVxdWFsKHtcbiAgICAgICAgZGlzcGxheU9yZGVyOiBbJ2lkJywgJ291dHB1dHMnLCAnb3V0cHV0QW1vdW50JywgJ2NoYW5nZU91dHB1dHMnLCAnY2hhbmdlQW1vdW50JywgJ2ZlZScsICd0eXBlJ10sXG4gICAgICAgIGlkOiBURVNUX1NFTkRfVFguaGFzaCxcbiAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFkZHJlc3M6IFRFU1RfU0VORF9UWC5yZWNpcGllbnQsXG4gICAgICAgICAgICBhbW91bnQ6IFRFU1RfU0VORF9UWC5zZW5kQW1vdW50LFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICAgIG91dHB1dEFtb3VudDogVEVTVF9TRU5EX1RYLnNlbmRBbW91bnQsXG4gICAgICAgIGNoYW5nZU91dHB1dHM6IFtdLFxuICAgICAgICBjaGFuZ2VBbW91bnQ6ICcwJyxcbiAgICAgICAgZmVlOiB7IGZlZTogVEVTVF9TRU5EX1RYLmdhc0J1ZGdldC5hbW91bnRbMF0uYW1vdW50IH0sXG4gICAgICAgIHR5cGU6IDAsXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZXhwbGFpbiBhIGRlbGVnYXRlIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXhwbGFpbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oe1xuICAgICAgICB0eEhleDogVEVTVF9ERUxFR0FURV9UWC5zaWduZWRUeEJhc2U2NCxcbiAgICAgIH0pO1xuICAgICAgZXhwbGFpbmVkVHJhbnNhY3Rpb24uc2hvdWxkLmRlZXBFcXVhbCh7XG4gICAgICAgIGRpc3BsYXlPcmRlcjogWydpZCcsICdvdXRwdXRzJywgJ291dHB1dEFtb3VudCcsICdjaGFuZ2VPdXRwdXRzJywgJ2NoYW5nZUFtb3VudCcsICdmZWUnLCAndHlwZSddLFxuICAgICAgICBpZDogVEVTVF9ERUxFR0FURV9UWC5oYXNoLFxuICAgICAgICBvdXRwdXRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogVEVTVF9ERUxFR0FURV9UWC52YWxpZGF0b3IsXG4gICAgICAgICAgICBhbW91bnQ6IFRFU1RfREVMRUdBVEVfVFguc2VuZEFtb3VudCxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICBvdXRwdXRBbW91bnQ6IFRFU1RfREVMRUdBVEVfVFguc2VuZEFtb3VudCxcbiAgICAgICAgY2hhbmdlT3V0cHV0czogW10sXG4gICAgICAgIGNoYW5nZUFtb3VudDogJzAnLFxuICAgICAgICBmZWU6IHsgZmVlOiBURVNUX0RFTEVHQVRFX1RYLmdhc0J1ZGdldC5hbW91bnRbMF0uYW1vdW50IH0sXG4gICAgICAgIHR5cGU6IDEzLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGV4cGxhaW4gYSB1bmRlbGVnYXRlIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXhwbGFpbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oe1xuICAgICAgICB0eEhleDogVEVTVF9VTkRFTEVHQVRFX1RYLnNpZ25lZFR4QmFzZTY0LFxuICAgICAgfSk7XG4gICAgICBleHBsYWluZWRUcmFuc2FjdGlvbi5zaG91bGQuZGVlcEVxdWFsKHtcbiAgICAgICAgZGlzcGxheU9yZGVyOiBbJ2lkJywgJ291dHB1dHMnLCAnb3V0cHV0QW1vdW50JywgJ2NoYW5nZU91dHB1dHMnLCAnY2hhbmdlQW1vdW50JywgJ2ZlZScsICd0eXBlJ10sXG4gICAgICAgIGlkOiBURVNUX1VOREVMRUdBVEVfVFguaGFzaCxcbiAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFkZHJlc3M6IFRFU1RfVU5ERUxFR0FURV9UWC52YWxpZGF0b3IsXG4gICAgICAgICAgICBhbW91bnQ6IFRFU1RfVU5ERUxFR0FURV9UWC5zZW5kQW1vdW50LFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICAgIG91dHB1dEFtb3VudDogVEVTVF9VTkRFTEVHQVRFX1RYLnNlbmRBbW91bnQsXG4gICAgICAgIGNoYW5nZU91dHB1dHM6IFtdLFxuICAgICAgICBjaGFuZ2VBbW91bnQ6ICcwJyxcbiAgICAgICAgZmVlOiB7IGZlZTogVEVTVF9VTkRFTEVHQVRFX1RYLmdhc0J1ZGdldC5hbW91bnRbMF0uYW1vdW50IH0sXG4gICAgICAgIHR5cGU6IDE3LFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGV4cGxhaW4gYSB3aXRoZHJhdyB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGV4cGxhaW5lZFRyYW5zYWN0aW9uID0gYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhIZXg6IFRFU1RfV0lUSERSQVdfUkVXQVJEU19UWC5zaWduZWRUeEJhc2U2NCxcbiAgICAgIH0pO1xuICAgICAgZXhwbGFpbmVkVHJhbnNhY3Rpb24uc2hvdWxkLmRlZXBFcXVhbCh7XG4gICAgICAgIGRpc3BsYXlPcmRlcjogWydpZCcsICdvdXRwdXRzJywgJ291dHB1dEFtb3VudCcsICdjaGFuZ2VPdXRwdXRzJywgJ2NoYW5nZUFtb3VudCcsICdmZWUnLCAndHlwZSddLFxuICAgICAgICBpZDogVEVTVF9XSVRIRFJBV19SRVdBUkRTX1RYLmhhc2gsXG4gICAgICAgIG91dHB1dHM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhZGRyZXNzOiBURVNUX1dJVEhEUkFXX1JFV0FSRFNfVFgudmFsaWRhdG9yLFxuICAgICAgICAgICAgYW1vdW50OiAnVU5BVkFJTEFCTEUnLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICAgIG91dHB1dEFtb3VudDogdW5kZWZpbmVkLFxuICAgICAgICBjaGFuZ2VPdXRwdXRzOiBbXSxcbiAgICAgICAgY2hhbmdlQW1vdW50OiAnMCcsXG4gICAgICAgIGZlZTogeyBmZWU6IFRFU1RfV0lUSERSQVdfUkVXQVJEU19UWC5nYXNCdWRnZXQuYW1vdW50WzBdLmFtb3VudCB9LFxuICAgICAgICB0eXBlOiAxNSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBleHBsYWluIGEgdHJhbnNmZXIgdHJhbnNhY3Rpb24gd2l0aCBtZW1vJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXhwbGFpbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oe1xuICAgICAgICB0eEhleDogVEVTVF9UWF9XSVRIX01FTU8uc2lnbmVkVHhCYXNlNjQsXG4gICAgICB9KTtcbiAgICAgIGV4cGxhaW5lZFRyYW5zYWN0aW9uLnNob3VsZC5kZWVwRXF1YWwoe1xuICAgICAgICBkaXNwbGF5T3JkZXI6IFsnaWQnLCAnb3V0cHV0cycsICdvdXRwdXRBbW91bnQnLCAnY2hhbmdlT3V0cHV0cycsICdjaGFuZ2VBbW91bnQnLCAnZmVlJywgJ3R5cGUnXSxcbiAgICAgICAgaWQ6IFRFU1RfVFhfV0lUSF9NRU1PLmhhc2gsXG4gICAgICAgIG91dHB1dHM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhZGRyZXNzOiBURVNUX1RYX1dJVEhfTUVNTy50byxcbiAgICAgICAgICAgIGFtb3VudDogVEVTVF9UWF9XSVRIX01FTU8uc2VuZEFtb3VudCxcbiAgICAgICAgICAgIG1lbW86IFRFU1RfVFhfV0lUSF9NRU1PLm1lbW8sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgICAgb3V0cHV0QW1vdW50OiBURVNUX1RYX1dJVEhfTUVNTy5zZW5kQW1vdW50LFxuICAgICAgICBjaGFuZ2VPdXRwdXRzOiBbXSxcbiAgICAgICAgY2hhbmdlQW1vdW50OiAnMCcsXG4gICAgICAgIGZlZTogeyBmZWU6IFRFU1RfVFhfV0lUSF9NRU1PLmdhc0J1ZGdldC5hbW91bnRbMF0uYW1vdW50IH0sXG4gICAgICAgIHR5cGU6IDAsXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB0byBleHBsYWluIHRyYW5zYWN0aW9uIHdpdGggbWlzc2luZyBwYXJhbXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oe30pO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgc2hvdWxkLmVxdWFsKGVycm9yLm1lc3NhZ2UsICdtaXNzaW5nIHJlcXVpcmVkIHR4SGV4IHBhcmFtZXRlcicpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHRvIGV4cGxhaW4gdHJhbnNhY3Rpb24gd2l0aCBpbnZhbGlkIHBhcmFtcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbih7IHR4SGV4OiAncmFuZG9tU3RyaW5nJyB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHNob3VsZC5lcXVhbChlcnJvci5tZXNzYWdlLnN0YXJ0c1dpdGgoJ0ludmFsaWQgdHJhbnNhY3Rpb246JyksIHRydWUpO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnUGFyc2UgVHJhbnNhY3Rpb25zOiAnLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBwYXJzZSBhIHRyYW5zZmVyIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHJhbnNmZXJJbnB1dHNSZXNwb25zZSA9IHtcbiAgICAgICAgYWRkcmVzczogVEVTVF9TRU5EX1RYLnJlY2lwaWVudCxcbiAgICAgICAgYW1vdW50OiBuZXcgQmlnTnVtYmVyKFRFU1RfU0VORF9UWC5zZW5kQW1vdW50KS5wbHVzKFRFU1RfU0VORF9UWC5nYXNCdWRnZXQuYW1vdW50WzBdLmFtb3VudCkudG9GaXhlZCgpLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHJhbnNmZXJPdXRwdXRzUmVzcG9uc2UgPSB7XG4gICAgICAgIGFkZHJlc3M6IFRFU1RfU0VORF9UWC5yZWNpcGllbnQsXG4gICAgICAgIGFtb3VudDogVEVTVF9TRU5EX1RYLnNlbmRBbW91bnQsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBwYXJzZWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJhc2Vjb2luLnBhcnNlVHJhbnNhY3Rpb24oeyB0eEhleDogVEVTVF9TRU5EX1RYLnNpZ25lZFR4QmFzZTY0IH0pO1xuXG4gICAgICBwYXJzZWRUcmFuc2FjdGlvbi5zaG91bGQuZGVlcEVxdWFsKHtcbiAgICAgICAgaW5wdXRzOiBbdHJhbnNmZXJJbnB1dHNSZXNwb25zZV0sXG4gICAgICAgIG91dHB1dHM6IFt0cmFuc2Zlck91dHB1dHNSZXNwb25zZV0sXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB0byBwYXJzZSBhIHRyYW5zZmVyIHRyYW5zYWN0aW9uIHdoZW4gZXhwbGFpblRyYW5zYWN0aW9uIHJlc3BvbnNlIGlzIHVuZGVmaW5lZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHN0dWIgPSBzaW5vbi5zdHViKEluamVjdGl2ZS5wcm90b3R5cGUsICdleHBsYWluVHJhbnNhY3Rpb24nKTtcbiAgICAgIHN0dWIucmVzb2x2ZXModW5kZWZpbmVkKTtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC5wYXJzZVRyYW5zYWN0aW9uKHsgdHhIZXg6IFRFU1RfU0VORF9UWC5zaWduZWRUeEJhc2U2NCB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnSW52YWxpZCB0cmFuc2FjdGlvbicpO1xuICAgICAgc3R1Yi5yZXN0b3JlKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdSZWNvdmVyIHRyYW5zYWN0aW9uOiBzdWNjZXNzIHBhdGgnLCAoKSA9PiB7XG4gICAgY29uc3Qgc2FuZEJveCA9IHNpbm9uLmNyZWF0ZVNhbmRib3goKTtcbiAgICBjb25zdCBkZXN0aW5hdGlvbkFkZHJlc3MgPSB3cndVc2VyLmRlc3RpbmF0aW9uQWRkcmVzcztcbiAgICBjb25zdCBjb2luID0gY29pbnMuZ2V0KCd0aW5qZWN0aXZlJyk7XG4gICAgY29uc3QgdGVzdEJhbGFuY2UgPSAnMTUwMDAwMDAwMDAwMDAwMDAnO1xuICAgIGNvbnN0IHRlc3RDaGFpbklkID0gJ3Rlc3QtY2hhaW4nO1xuXG4gICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgICBub2NrKCdodHRwczovL3Rlc3RuZXQuc2VudHJ5LmxjZC5pbmplY3RpdmUubmV0d29yaycpXG4gICAgICAgIC5nZXQoJy9jb3Ntb3MvYXV0aC92MWJldGExL2FjY291bnRzLycgKyB3cndVc2VyLnNlbmRlckFkZHJlc3MpXG4gICAgICAgIC5yZXBseSgyMDAsIG1vY2tBY2NvdW50RGV0YWlsc1Jlc3BvbnNlKTtcblxuICAgICAgY29uc3QgYWNjb3VudEJhbGFuY2UgPSBzYW5kQm94LnN0dWIoSW5qZWN0aXZlLnByb3RvdHlwZSwgJ2dldEFjY291bnRCYWxhbmNlJyBhcyBrZXlvZiBJbmplY3RpdmUpO1xuICAgICAgYWNjb3VudEJhbGFuY2Uud2l0aEFyZ3Mod3J3VXNlci5zZW5kZXJBZGRyZXNzKS5yZXNvbHZlcyh0ZXN0QmFsYW5jZSk7XG5cbiAgICAgIGNvbnN0IGNoYWluSWQgPSBzYW5kQm94LnN0dWIoSW5qZWN0aXZlLnByb3RvdHlwZSwgJ2dldENoYWluSWQnIGFzIGtleW9mIEluamVjdGl2ZSk7XG4gICAgICBjaGFpbklkLndpdGhBcmdzKCkucmVzb2x2ZXModGVzdENoYWluSWQpO1xuXG4gICAgICBjb25zdCBkZXNlcmlhbGl6ZWRFbnRDaGFsbGVuZ2UgPSBFY2RzYVR5cGVzLmRlc2VyaWFsaXplTnRpbGRlV2l0aFByb29mcyhtb2NrU2VyaWFsaXplZENoYWxsZW5nZVdpdGhQcm9vZnMpO1xuICAgICAgc2lub24uc3R1YihFY2RzYVJhbmdlUHJvb2YsICdnZW5lcmF0ZU50aWxkZScpLnJlc29sdmVzKGRlc2VyaWFsaXplZEVudENoYWxsZW5nZSk7XG4gICAgfSk7XG5cbiAgICBhZnRlckVhY2goKCkgPT4ge1xuICAgICAgc2FuZEJveC5yZXN0b3JlKCk7XG4gICAgICBzaW5vbi5yZXN0b3JlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlY292ZXIgZnVuZHMgZm9yIG5vbi1iaXRnbyByZWNvdmVyaWVzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgIHVzZXJLZXk6IHdyd1VzZXIudXNlclByaXZhdGVLZXksXG4gICAgICAgIGJhY2t1cEtleTogd3J3VXNlci5iYWNrdXBQcml2YXRlS2V5LFxuICAgICAgICBiaXRnb0tleTogd3J3VXNlci5iaXRnb1B1YmxpY0tleSxcbiAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogd3J3VXNlci53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBkZXN0aW5hdGlvbkFkZHJlc3MsXG4gICAgICB9KTtcbiAgICAgIHJlcy5zaG91bGQubm90LmJlLmVtcHR5KCk7XG4gICAgICByZXMuc2hvdWxkLmhhc093blByb3BlcnR5KCdzZXJpYWxpemVkVHgnKTtcbiAgICAgIHNhbmRCb3guYXNzZXJ0LmNhbGxlZE9uY2UoYmFzZWNvaW4uZ2V0QWNjb3VudEJhbGFuY2UpO1xuICAgICAgc2FuZEJveC5hc3NlcnQuY2FsbGVkT25jZShiYXNlY29pbi5nZXRDaGFpbklkKTtcblxuICAgICAgY29uc3QgdHhuID0gbmV3IENvc21vc1RyYW5zYWN0aW9uKGNvaW4sIHV0aWxzKTtcbiAgICAgIHR4bi5lbnJpY2hUcmFuc2FjdGlvbkRldGFpbHNGcm9tUmF3VHJhbnNhY3Rpb24ocmVzLnNlcmlhbGl6ZWRUeCk7XG4gICAgICBjb25zdCB0eG5Kc29uID0gdHhuLnRvSnNvbigpO1xuICAgICAgY29uc3Qgc2VuZE1lc3NhZ2UgPSB0eG5Kc29uLnNlbmRNZXNzYWdlc1swXS52YWx1ZSBhcyBTZW5kTWVzc2FnZTtcbiAgICAgIGNvbnN0IGJhbGFuY2UgPSBuZXcgQmlnTnVtYmVyKHRlc3RCYWxhbmNlKTtcbiAgICAgIGNvbnN0IGdhc0Ftb3VudCA9IG5ldyBCaWdOdW1iZXIoMTI1MDAwMDAwMDAwMDAwKTtcbiAgICAgIGNvbnN0IGFjdHVhbEJhbGFuY2UgPSBiYWxhbmNlLm1pbnVzKGdhc0Ftb3VudCk7XG4gICAgICBzaG91bGQuZXF1YWwoc2VuZE1lc3NhZ2UudG9BZGRyZXNzLCBkZXN0aW5hdGlvbkFkZHJlc3MpO1xuICAgICAgc2hvdWxkLmVxdWFsKHNlbmRNZXNzYWdlLmFtb3VudFswXS5hbW91bnQsIGFjdHVhbEJhbGFuY2UudG9GaXhlZCgpKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1JlY292ZXIgdHJhbnNhY3Rpb246IGZhaWx1cmUgcGF0aCcsICgpID0+IHtcbiAgICBjb25zdCBzYW5kQm94ID0gc2lub24uY3JlYXRlU2FuZGJveCgpO1xuICAgIGNvbnN0IGRlc3RpbmF0aW9uQWRkcmVzcyA9IHdyd1VzZXIuZGVzdGluYXRpb25BZGRyZXNzO1xuICAgIGNvbnN0IHRlc3RaZXJvQmFsYW5jZSA9ICcwJztcbiAgICBjb25zdCB0ZXN0Q2hhaW5JZCA9ICd0ZXN0LWNoYWluJztcblxuICAgIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgICAgbm9jaygnaHR0cHM6Ly90ZXN0bmV0LnNlbnRyeS5sY2QuaW5qZWN0aXZlLm5ldHdvcmsnKVxuICAgICAgICAuZ2V0KCcvY29zbW9zL2F1dGgvdjFiZXRhMS9hY2NvdW50cy8nICsgd3J3VXNlci5zZW5kZXJBZGRyZXNzKVxuICAgICAgICAucmVwbHkoMjAwLCBtb2NrQWNjb3VudERldGFpbHNSZXNwb25zZSk7XG5cbiAgICAgIGNvbnN0IGFjY291bnRCYWxhbmNlID0gc2FuZEJveC5zdHViKEluamVjdGl2ZS5wcm90b3R5cGUsICdnZXRBY2NvdW50QmFsYW5jZScgYXMga2V5b2YgSW5qZWN0aXZlKTtcbiAgICAgIGFjY291bnRCYWxhbmNlLndpdGhBcmdzKHdyd1VzZXIuc2VuZGVyQWRkcmVzcykucmVzb2x2ZXModGVzdFplcm9CYWxhbmNlKTtcblxuICAgICAgY29uc3QgY2hhaW5JZCA9IHNhbmRCb3guc3R1YihJbmplY3RpdmUucHJvdG90eXBlLCAnZ2V0Q2hhaW5JZCcgYXMga2V5b2YgSW5qZWN0aXZlKTtcbiAgICAgIGNoYWluSWQud2l0aEFyZ3MoKS5yZXNvbHZlcyh0ZXN0Q2hhaW5JZCk7XG5cbiAgICAgIGNvbnN0IGRlc2VyaWFsaXplZEVudENoYWxsZW5nZSA9IEVjZHNhVHlwZXMuZGVzZXJpYWxpemVOdGlsZGVXaXRoUHJvb2ZzKG1vY2tTZXJpYWxpemVkQ2hhbGxlbmdlV2l0aFByb29mcyk7XG4gICAgICBzaW5vbi5zdHViKEVjZHNhUmFuZ2VQcm9vZiwgJ2dlbmVyYXRlTnRpbGRlJykucmVzb2x2ZXMoZGVzZXJpYWxpemVkRW50Q2hhbGxlbmdlKTtcbiAgICB9KTtcblxuICAgIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgICBzYW5kQm94LnJlc3RvcmUoKTtcbiAgICAgIHNpbm9uLnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3IgaWYgYmFja3Vwa2V5IGlzIG5vdCBwcmVzZW50JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnJlY292ZXIoe1xuICAgICAgICAgIHVzZXJLZXk6IHdyd1VzZXIudXNlclByaXZhdGVLZXksXG4gICAgICAgICAgYml0Z29LZXk6IHdyd1VzZXIuYml0Z29QdWJsaWNLZXksXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogd3J3VXNlci53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IGRlc3RpbmF0aW9uQWRkcmVzcyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5yZWplY3RlZFdpdGgoJ21pc3NpbmcgYmFja3VwS2V5Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGVycm9yIGlmIHVzZXJrZXkgaXMgbm90IHByZXNlbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAucmVjb3Zlcih7XG4gICAgICAgICAgYmFja3VwS2V5OiB3cndVc2VyLmJhY2t1cFByaXZhdGVLZXksXG4gICAgICAgICAgYml0Z29LZXk6IHdyd1VzZXIuYml0Z29QdWJsaWNLZXksXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogd3J3VXNlci53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IGRlc3RpbmF0aW9uQWRkcmVzcyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5yZWplY3RlZFdpdGgoJ21pc3NpbmcgdXNlcktleScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBlcnJvciBpZiB3YWxsZXQgcGFzc3BocmFzZSBpcyBub3QgcHJlc2VudCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC5yZWNvdmVyKHtcbiAgICAgICAgICB1c2VyS2V5OiB3cndVc2VyLnVzZXJQcml2YXRlS2V5LFxuICAgICAgICAgIGJhY2t1cEtleTogd3J3VXNlci5iYWNrdXBQcml2YXRlS2V5LFxuICAgICAgICAgIGJpdGdvS2V5OiB3cndVc2VyLmJpdGdvUHVibGljS2V5LFxuICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IGRlc3RpbmF0aW9uQWRkcmVzcyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5yZWplY3RlZFdpdGgoJ21pc3Npbmcgd2FsbGV0IHBhc3NwaHJhc2UnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3IgaWYgdGhlcmUgaXMgbm8gYmFsYW5jZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC5yZWNvdmVyKHtcbiAgICAgICAgICB1c2VyS2V5OiB3cndVc2VyLnVzZXJQcml2YXRlS2V5LFxuICAgICAgICAgIGJhY2t1cEtleTogd3J3VXNlci5iYWNrdXBQcml2YXRlS2V5LFxuICAgICAgICAgIGJpdGdvS2V5OiB3cndVc2VyLmJpdGdvUHVibGljS2V5LFxuICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2U6IHdyd1VzZXIud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBkZXN0aW5hdGlvbkFkZHJlc3MsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQucmVqZWN0ZWRXaXRoKCdEaWQgbm90IGhhdmUgZW5vdWdoIGZ1bmRzIHRvIHJlY292ZXInKTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==Выполнить команду
Для локальной разработки. Не используйте в интернете!