PHP WebShell

Текущая директория: /opt/BitGoJS/modules/abstract-eth/dist/test/unit

Просмотр файла: coin.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 });
exports.runBasicCoinInfoTests = runBasicCoinInfoTests;
exports.runExplainTransactionTests = runExplainTransactionTests;
exports.runSignTransactionTests = runSignTransactionTests;
exports.runTransactionVerificationTests = runTransactionVerificationTests;
exports.runRecoveryTransactionTests = runRecoveryTransactionTests;
const sdk_test_1 = require("@bitgo/sdk-test");
const secp256k1_1 = require("@bitgo/secp256k1");
const secp256k1 = __importStar(require("secp256k1"));
const sdk_core_1 = require("@bitgo/sdk-core");
const nock_1 = __importDefault(require("nock"));
const should = __importStar(require("should"));
const src_1 = require("../../src");
nock_1.default.enableNetConnect();
function runBasicCoinInfoTests(coinName, bitgo, MainCoin, TestCoin, testData) {
    describe(`${coinName} basic info test`, () => {
        const coinTest = testData.COIN;
        const coinMain = coinTest.slice(1);
        it(`should return the right info for ${coinMain}`, () => {
            const coin = bitgo.coin(coinMain);
            coin.should.be.an.instanceof(MainCoin);
            coin.getChain().should.equal(coinMain);
            coin.getFamily().should.equal(coinMain);
            coin.getFullName().should.equal(testData.CHAIN_FULL_NAME);
            coin.getBaseFactor().should.equal(1e18);
        });
        it(`should return the right info for ${coinTest}`, () => {
            const coin = bitgo.coin(coinTest);
            coin.should.be.an.instanceof(TestCoin);
            coin.getChain().should.equal(coinTest);
            coin.getFamily().should.equal(coinMain);
            coin.getFullName().should.equal(`Testnet ${testData.CHAIN_FULL_NAME}`);
            coin.getBaseFactor().should.equal(1e18);
        });
    });
}
function runExplainTransactionTests(coinName, txBuilder, basecoin, testData) {
    describe(`${coinName} explain transaction`, () => {
        const coinTest = testData.COIN;
        /**
         * Build an unsigned account-lib multi-signature send transactino
         * @param destination The destination address of the transaction
         * @param contractAddress The address of the smart contract processing the transaction
         * @param contractSequenceId The sequence id of the contract
         * @param nonce The nonce of the sending address
         * @param expireTime The expire time of the transaction
         * @param amount The amount to send to the recipient
         * @param gasPrice The gas price of the transaction
         * @param gasLimit The gas limit of the transaction
         */
        const buildUnsignedTransaction = async function ({ destination, contractAddress, contractSequenceId = 1, nonce = 0, expireTime = Math.floor(new Date().getTime() / 1000), amount = '100000', gasPrice = '10000', gasLimit = '20000', }) {
            txBuilder.type(sdk_core_1.TransactionType.Send);
            txBuilder.fee({
                fee: gasPrice,
                gasLimit: gasLimit,
            });
            txBuilder.counter(nonce);
            txBuilder.contract(contractAddress);
            const transferBuilder = txBuilder.transfer();
            transferBuilder
                .coin(coinTest)
                .expirationTime(expireTime)
                .amount(amount)
                .to(destination)
                .contractSequenceId(contractSequenceId);
            return await txBuilder.build();
        };
        it('should fail if the options object is missing parameters', async () => {
            const explainParams = {
                feeInfo: { fee: 1 },
                txHex: null,
            };
            await basecoin.explainTransaction(explainParams).should.be.rejectedWith('missing explain tx parameters');
        });
        it('explain a transfer transaction', async () => {
            const destination = '0xfaa8f14f46a99eb439c50e0c3b835cc21dad51b4';
            const contractAddress = '0x9e2c5712ab4caf402a98c4bf58c79a0dfe718ad1';
            const unsignedTransaction = await buildUnsignedTransaction({
                destination,
                contractAddress,
            });
            const explainParams = {
                halfSigned: {
                    txHex: unsignedTransaction.toBroadcastFormat(),
                },
                feeInfo: { fee: 1 },
            };
            const explanation = await basecoin.explainTransaction(explainParams);
            should.exist(explanation.id);
        });
    });
}
function runSignTransactionTests(coinName, builder, basecoin, testData) {
    describe(`${coinName} sign transaction tests`, async () => {
        const account_1 = {
            address: '0x8Ce59c2d1702844F8EdED451AA103961bC37B4e8',
            owner_1: '4ee089aceabf3ddbf748db79b1066c33b7d3ea1ab3eb7e325121bba2bff2f5ca',
            owner_2: '5c7e4efff7304d4dfff6d5f1591844ec6f2adfa6a47e9fece6a3c1a4d755f1e3',
            owner_3: '4421ab25dd91e1a3180d03d57c323a7886dcc313d3b3a4b4256a5791572bf597',
        };
        const account_2 = {
            address: '0xeeaf0F05f37891ab4a21208B105A0687d12c5aF7',
            owner_1: '4ee089aceabf3ddbf748db79b1066c33b7d3ea1ab3eb7e325121bba2bff2f5ca',
            owner_2: '5ca116d25aec5f765465432cc421ff25ef9ffdc330b10bb3d9ad61e3baad88d7',
            owner_3: '1fae946cc84af8bd74d610a88537e24e19c3349d478d86fc5bb59ba4c88fb9cc',
        };
        const coinTest = testData.COIN;
        it('should sign an unsigned test tx', async () => {
            builder.fee({
                fee: '280000000000',
                gasLimit: '7000000',
            });
            builder.counter(1);
            builder.type(sdk_core_1.TransactionType.Send);
            builder.contract(account_1.address);
            const transferBuilder = builder.transfer();
            transferBuilder.coin(coinTest).amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1);
            const unsignedTx = await builder.build();
            const unsignedTxForBroadcasting = unsignedTx.toBroadcastFormat();
            const halfSignedRawTx = await basecoin.signTransaction({
                txPrebuild: {
                    txHex: unsignedTxForBroadcasting,
                },
                prv: account_1.owner_2,
            });
            builder.transfer().key(account_1.owner_2);
            const halfSignedTx = await builder.build();
            const halfSignedTxForBroadcasting = halfSignedTx.toBroadcastFormat();
            halfSignedRawTx.halfSigned.txHex.should.equals(halfSignedTxForBroadcasting);
            halfSignedRawTx.halfSigned.recipients.length.should.equals(1);
            halfSignedRawTx.halfSigned.recipients[0].address.toLowerCase().should.equals(account_2.address.toLowerCase());
            halfSignedRawTx.halfSigned.recipients[0].amount.toLowerCase().should.equals('1');
        });
        it('should sign an unsigned test tx with eip1559', async () => {
            builder.fee({
                fee: '280000000000',
                gasLimit: '7000000',
                eip1559: {
                    maxFeePerGas: '7593123',
                    maxPriorityFeePerGas: '150',
                },
            });
            builder.counter(1);
            builder.type(sdk_core_1.TransactionType.Send);
            builder.contract(account_1.address);
            const transferBuilder = builder.transfer();
            transferBuilder.coin(coinTest).amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1);
            const unsignedTx = await builder.build();
            const unsignedTxForBroadcasting = unsignedTx.toBroadcastFormat();
            const halfSignedRawTx = await basecoin.signTransaction({
                txPrebuild: {
                    txHex: unsignedTxForBroadcasting,
                    eip1559: {
                        maxFeePerGas: '7593123',
                        maxPriorityFeePerGas: '150',
                    },
                },
                prv: account_1.owner_2,
            });
            builder.transfer().key(account_1.owner_2);
            const halfSignedTx = await builder.build();
            const halfSignedTxForBroadcasting = halfSignedTx.toBroadcastFormat();
            halfSignedRawTx.halfSigned.txHex.should.equals(halfSignedTxForBroadcasting);
            halfSignedRawTx.halfSigned.recipients.length.should.equals(1);
            halfSignedRawTx.halfSigned.recipients[0].address.toLowerCase().should.equals(account_2.address.toLowerCase());
            halfSignedRawTx.halfSigned.recipients[0].amount.toLowerCase().should.equals('1');
            halfSignedRawTx.halfSigned.eip1559.maxFeePerGas.should.equal('7593123');
            halfSignedRawTx.halfSigned.eip1559.maxPriorityFeePerGas.should.equal('150');
        });
    });
}
function runTransactionVerificationTests(coinName, bitgo, basecoin, testData) {
    describe(`${coinName} Transaction Verification`, () => {
        const coinTest = testData.COIN;
        const address1 = '0x174cfd823af8ce27ed0afee3fcf3c3ba259116be';
        const address2 = '0x7e85bdc27c050e3905ebf4b8e634d9ad6edd0de6';
        const hopDestinationAddress = '0x9c7e8ce6825bD48278B3Ab59228EE26f8BE7925b';
        const hopTx = '0xf86b808504a817c8ff8252ff949c7e8ce6825bd48278b3ab59228ee26f8be7925b87038d7ea4c68000801ca011bc22c664570133dfca4f08a0b8d02339cf467046d6a4152f04f368d0eaf99ea01d6dc5cf0c897c8d4c3e1df53d0d042784c424536a4cc5b802552b7d64fee8b5';
        const hopTxid = '0x4af65143bc77da2b50f35b3d13cacb4db18f026bf84bc0743550bc57b9b53351';
        const userReqSig = '0x404db307f6147f0d8cd338c34c13906ef46a6faa7e0e119d5194ef05aec16e6f3d710f9b7901460f97e924066b62efd74443bd34402c6d40b49c203a559ff2c8';
        const bitgoKeyXprv = 'xprv9s21ZrQH143K3tpWBHWe31sLoXNRQ9AvRYJgitkKxQ4ATFQMwvr7hHNqYRUnS7PsjzB7aK1VxqHLuNQjj1sckJ2Jwo2qxmsvejwECSpFMfC';
        const bitgoKey = secp256k1_1.bip32.fromBase58(bitgoKeyXprv);
        if (!bitgoKey.privateKey) {
            throw new Error('no privateKey');
        }
        const hopTxBitgoSignature = '0xaa' +
            Buffer.from(secp256k1.ecdsaSign(Buffer.from(hopTxid.slice(2), 'hex'), bitgoKey.privateKey).signature).toString('hex');
        it('should verify a normal txPrebuild from the bitgo server that matches the client txParams', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = {
                recipients: [{ amount: '1000000000000', address: address1 }],
                wallet: wallet,
                walletPassphrase: 'fakeWalletPassphrase',
            };
            const txPrebuild = {
                recipients: [{ amount: '1000000000000', address: address1 }],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: false,
                coin: coinTest,
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
            };
            const verification = {};
            const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification });
            isTransactionVerified.should.equal(true);
        });
        it('should reject when client txParams are missing', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = null;
            const txPrebuild = {
                recipients: [{ amount: '1000000000000', address: address1 }],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: false,
                coin: coinTest,
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
            };
            const verification = {};
            await basecoin
                .verifyTransaction({ txParams, txPrebuild, wallet, verification })
                .should.be.rejectedWith('missing params');
        });
        it('should reject txPrebuild that is both batch and hop', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = {
                recipients: [
                    { amount: '1000000000000', address: address1 },
                    { amount: '2500000000000', address: address2 },
                ],
                wallet: wallet,
                walletPassphrase: 'fakeWalletPassphrase',
                hop: true,
            };
            const txPrebuild = {
                recipients: [{ amount: '3500000000000', address: address1 }],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: true,
                coin: coinTest,
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
                hopTransaction: {
                    tx: hopTx,
                    id: hopTxid,
                    signature: hopTxBitgoSignature,
                    paymentId: '2773928196',
                    gasPrice: 20000000000,
                    gasLimit: 500000,
                    amount: '1000000000000000',
                    recipient: hopDestinationAddress,
                    nonce: 0,
                    userReqSig: userReqSig,
                    gasPriceMax: 500000000000,
                },
            };
            const verification = {};
            await basecoin
                .verifyTransaction({ txParams, txPrebuild, wallet, verification })
                .should.be.rejectedWith('tx cannot be both a batch and hop transaction');
        });
        it('should reject a txPrebuild with more than one recipient', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = {
                recipients: [
                    { amount: '1000000000000', address: address1 },
                    { amount: '2500000000000', address: address2 },
                ],
                wallet: wallet,
                walletPassphrase: 'fakeWalletPassphrase',
            };
            const txPrebuild = {
                recipients: [
                    { amount: '1000000000000', address: address1 },
                    { amount: '2500000000000', address: address2 },
                ],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: true,
                coin: coinTest,
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
            };
            const verification = {};
            await basecoin
                .verifyTransaction({ txParams, txPrebuild, wallet, verification })
                .should.be.rejectedWith(`${coinTest} doesn't support sending to more than 1 destination address within a single transaction. Try again, using only a single recipient.`);
        });
        it('should reject a hop txPrebuild that does not send to its hop address', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = {
                recipients: [{ amount: '1000000000000000', address: hopDestinationAddress }],
                wallet: wallet,
                walletPassphrase: 'fakeWalletPassphrase',
                hop: true,
            };
            const txPrebuild = {
                recipients: [{ amount: '5000000000000000', address: address1 }],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: false,
                coin: coinTest,
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
                hopTransaction: {
                    tx: hopTx,
                    id: hopTxid,
                    signature: hopTxBitgoSignature,
                    paymentId: '0',
                    gasPrice: 20000000000,
                    gasLimit: 500000,
                    amount: '1000000000000000',
                    recipient: hopDestinationAddress,
                    nonce: 0,
                    userReqSig: userReqSig,
                    gasPriceMax: 500000000000,
                },
            };
            const verification = {};
            await basecoin
                .verifyTransaction({ txParams, txPrebuild, wallet, verification })
                .should.be.rejectedWith('recipient address of txPrebuild does not match hop address');
        });
        it('should reject a normal txPrebuild from the bitgo server with the wrong amount', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = {
                recipients: [{ amount: '1000000000000', address: address1 }],
                wallet: wallet,
                walletPassphrase: 'fakeWalletPassphrase',
            };
            const txPrebuild = {
                recipients: [{ amount: '2000000000000', address: address1 }],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: false,
                coin: coinTest,
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
            };
            const verification = {};
            await basecoin
                .verifyTransaction({ txParams, txPrebuild, wallet, verification })
                .should.be.rejectedWith('normal transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client');
        });
        it('should reject a normal txPrebuild from the bitgo server with the wrong recipient', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = {
                recipients: [{ amount: '1000000000000', address: address1 }],
                wallet: wallet,
                walletPassphrase: 'fakeWalletPassphrase',
            };
            const txPrebuild = {
                recipients: [{ amount: '1000000000000', address: address2 }],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: false,
                coin: coinTest,
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
            };
            const verification = {};
            await basecoin
                .verifyTransaction({ txParams, txPrebuild, wallet, verification })
                .should.be.rejectedWith('destination address in normal txPrebuild does not match that in txParams supplied by client');
        });
        it('should reject a txPrebuild from the bitgo server with the wrong coin', async () => {
            const wallet = new sdk_core_1.Wallet(bitgo, basecoin, {});
            const txParams = {
                recipients: [{ amount: '1000000000000', address: address1 }],
                wallet: wallet,
                walletPassphrase: 'fakeWalletPassphrase',
            };
            const txPrebuild = {
                recipients: [{ amount: '1000000000000', address: address1 }],
                nextContractSequenceId: 0,
                gasPrice: 20000000000,
                gasLimit: 500000,
                isBatch: false,
                coin: 'btc',
                walletId: 'fakeWalletId',
                walletContractAddress: 'fakeWalletContractAddress',
            };
            const verification = {};
            await basecoin
                .verifyTransaction({ txParams, txPrebuild, wallet, verification })
                .should.be.rejectedWith('coin in txPrebuild did not match that in txParams supplied by client');
        });
    });
}
function runRecoveryTransactionTests(coinName, txBuilder, bitgo, testData, mockData) {
    describe(`${coinName} Recover transaction:`, function () {
        const baseUrl = testData.BASE_URL;
        const userXpub = 'xpub661MyMwAqRbcEeTc8789MK5PUGEYiPG4F4V17n2Rd2LoTATA1XoCnJT5FAYAShQxSxtFjpo5NHmcWwTp2LiWGBMwpUcAA3HywhxivgYfq7q';
        const userXprv = 'xprv9s21ZrQH143K2AP925b8zB8evEQ4JvYCsqZQKPcp4gopaN81TzUxEW8bPtVyDgjmddGhRRETn8xi1cVAB9bf1Bx9kGRRFgTZXxJayZLnag1';
        const backupXpub = 'xpub661MyMwAqRbcFZX15xpZf4ERCGHiVSJm8r5C4yh1yXV2GrdZCUPYo4WQr6tN9oUywKXsgSHo7Risf9r22GH5joVD2hEEEhqnSCvK8qy11wW';
        const backupXprv = 'xprv9s21ZrQH143K35SXywHZHvHgeETE5yaumd9bGbHQRBx3Q4JQew5JFGBvzqiZjCUkBdBUZnfuMDTGURRayN1hFSWxEJQsCEAMm1D3pk1h7Jj';
        const coin = testData.COIN;
        after(function () {
            nock_1.default.cleanAll();
        });
        it('should generate an unsigned sweep', async () => {
            const walletContractAddress = sdk_test_1.TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS;
            const backupKeyAddress = '0x4f2c4830cc37f2785c646f89ded8a919219fa0e9';
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .twice()
                .query(mockData.getTxListRequest(backupKeyAddress))
                .reply(200, mockData.getTxListResponse);
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .query(mockData.getBalanceRequest(walletContractAddress))
                .reply(200, mockData.getBalanceResponse);
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .query(mockData.getBalanceRequest(backupKeyAddress))
                .reply(200, mockData.getBalanceResponse);
            (0, nock_1.default)(baseUrl).get('/api').query(mockData.getContractCallRequest).reply(200, mockData.getContractCallResponse);
            const basecoin = bitgo.coin(coin);
            const transaction = (await basecoin.recover({
                userKey: userXpub,
                backupKey: backupXpub,
                walletContractAddress: walletContractAddress,
                recoveryDestination: sdk_test_1.TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT,
                eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
                gasLimit: 500000,
            }));
            should.exist(transaction);
            transaction.should.have.property('txHex');
            transaction.should.have.property('contractSequenceId');
            transaction.should.have.property('expireTime');
            transaction.should.have.property('gasLimit');
            transaction.gasLimit.should.equal('500000');
            transaction.should.have.property('walletContractAddress');
            transaction.walletContractAddress.should.equal(sdk_test_1.TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS);
            transaction.should.have.property('recipients');
            const recipient = transaction.recipients[0];
            recipient.should.have.property('address');
            recipient.address.should.equal(sdk_test_1.TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT);
            recipient.should.have.property('amount');
            recipient.amount.should.equal('9999999999999999928');
        });
        it('should construct a recovery transaction without BitGo', async () => {
            const backupKeyAddress = '0x6d22efdd634996248170c948e5726007fc251bb3';
            const walletContractAddress = sdk_test_1.TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS;
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .query(mockData.getTxListRequest(backupKeyAddress))
                .reply(200, mockData.getTxListResponse);
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .query(mockData.getBalanceRequest(walletContractAddress))
                .reply(200, mockData.getBalanceResponse);
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .query(mockData.getBalanceRequest(backupKeyAddress))
                .reply(200, mockData.getBalanceResponse);
            (0, nock_1.default)(baseUrl).get('/api').query(mockData.getContractCallRequest).reply(200, mockData.getContractCallResponse);
            const basecoin = bitgo.coin(coin);
            const transaction = (await basecoin.recover({
                userKey: '{"iv":"VFZ3jvXhxo1Z+Yaf2MtZnA==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' +
                    ':"ccm","adata":"","cipher":"aes","salt":"p+fkHuLa/8k=","ct":"hYG7pvljLIgCjZ\n' +
                    '53PBlCde5KZRmlUKKHLtDMk+HJfuU46hW+x+C9WsIAO4gFPnTCvFVmQ8x7czCtcNFub5AO2otOG\n' +
                    'OsX4GE2gXOEmCl1TpWwwNhm7yMUjGJUpgW6ZZgXSXdDitSKi4V/hk78SGSzjFOBSPYRa6I="}\n',
                backupKey: '{"iv":"AbsCtv1qwPIhOgyrCpNagA==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' +
                    ':"ccm","adata":"","cipher":"aes","salt":"5vpUDBUlzm8=","ct":"PapYYCjBXRLUKA\n' +
                    'JbOsB/EJ9B8fUmVQTxMPjUnQyAky12me9K66GiMEAxTD7kd6bYAQJuuTkATXKU7Bnf7vK9JxNOw\n' +
                    'oji7HF9eFH0aD4/hX5SWFfHF2Qfi+TnXv6hVsMAoisDZs3/F67/ZUaDYR0ZsdrQ4Q/cLD0="}\n',
                walletContractAddress: walletContractAddress,
                walletPassphrase: sdk_test_1.TestBitGo.V2.TEST_RECOVERY_PASSCODE,
                recoveryDestination: sdk_test_1.TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT,
                gasLimit: 500000,
            }));
            should.exist(transaction);
            transaction.should.have.property('tx');
            transaction.should.have.property('id');
            const decodedTx = src_1.optionalDeps.EthTx.Transaction.fromSerializedTx(src_1.optionalDeps.ethUtil.toBuffer(transaction.tx));
            decodedTx.should.have.property('gasPrice');
            decodedTx.should.have.property('nonce');
            decodedTx.should.have.property('to');
        });
        it('should be able to second sign', async () => {
            const walletContractAddress = sdk_test_1.TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS;
            const backupKeyAddress = '0x4f2c4830cc37f2785c646f89ded8a919219fa0e9';
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .twice()
                .query(mockData.getTxListRequest(backupKeyAddress))
                .reply(200, mockData.getTxListResponse);
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .query(mockData.getBalanceRequest(walletContractAddress))
                .reply(200, mockData.getBalanceResponse);
            (0, nock_1.default)(baseUrl)
                .get('/api')
                .query(mockData.getBalanceRequest(backupKeyAddress))
                .reply(200, mockData.getBalanceResponse);
            (0, nock_1.default)(baseUrl).get('/api').query(mockData.getContractCallRequest).reply(200, mockData.getContractCallResponse);
            const basecoin = bitgo.coin(coin);
            const transaction = (await basecoin.recover({
                userKey: userXpub,
                backupKey: backupXpub,
                walletContractAddress: walletContractAddress,
                recoveryDestination: sdk_test_1.TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT,
                eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
                replayProtectionOptions: { chain: 80001, hardfork: 'london' },
                gasLimit: 500000,
            }));
            const txPrebuild = {
                txHex: transaction.txHex,
            };
            const params = {
                txPrebuild,
                prv: userXprv,
            };
            // sign transaction once
            const halfSigned = await basecoin.signTransaction(params);
            const halfSignedParams = {
                txPrebuild: halfSigned,
                isLastSignature: true,
                walletContractAddress: walletContractAddress,
                prv: backupXprv,
            };
            const finalSigned = (await basecoin.signTransaction(halfSignedParams));
            finalSigned.should.have.property('txHex');
            txBuilder.from(finalSigned.txHex);
            const rebuiltTx = await txBuilder.build();
            rebuiltTx.signature.length.should.equal(2);
            rebuiltTx.outputs.length.should.equal(1);
        });
    });
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29pbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Rlc3QvdW5pdC9jb2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBZ0JBLHNEQXdCQztBQUVELGdFQXFFQztBQUVELDBEQTBGQztBQUVELDBFQW9SQztBQUVELGtFQW1LQztBQXRvQkQsOENBQTBEO0FBQzFELGdEQUF5QztBQUN6QyxxREFBdUM7QUFDdkMsOENBQWtGO0FBQ2xGLGdEQUF3QjtBQUN4QiwrQ0FBaUM7QUFDakMsbUNBTW1CO0FBRW5CLGNBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0FBRXhCLFNBQWdCLHFCQUFxQixDQUFDLFFBQWdCLEVBQUUsS0FBbUIsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLFFBQWE7SUFDNUcsUUFBUSxDQUFDLEdBQUcsUUFBUSxrQkFBa0IsRUFBRSxHQUFHLEVBQUU7UUFDM0MsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQztRQUMvQixNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25DLEVBQUUsQ0FBQyxvQ0FBb0MsUUFBUSxFQUFFLEVBQUUsR0FBRyxFQUFFO1lBQ3RELE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7WUFFbEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN2QyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN2QyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN4QyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLEtB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QUFDO1lBRTFCLE1BQU0sVUFBVSxHQUFHO2dCQUNqQixLQUFLLEVBQUUsV0FBVyxDQUFDLEtBQUs7YUFDekIsQ0FBQztZQUVGLE1BQU0sTUFBTSxHQUFHO2dCQUNiLFVBQVU7Z0JBQ1YsR0FBRyxFQUFFLFFBQVE7YUFDZCxDQUFDO1lBQ0Ysd0JBQXdCO1lBQ3hCLE1BQU0sVUFBVSxHQUFHLE1BQU0sUUFBUSxDQUFDLGVBQWUsQ0FBQyxNQUFnQyxDQUFDLENBQUM7WUFDcEYsTUFBTSxnQkFBZ0IsR0FBRztnQkFDdkIsVUFBVSxFQUFFLFVBQVU7Z0JBQ3RCLGVBQWUsRUFBRSxJQUFJO2dCQUNyQixxQkFBcUIsRUFBRSxxQkFBcUI7Z0JBQzVDLEdBQUcsRUFBRSxVQUFVO2FBQ2hCLENBQUM7WUFFRixNQUFNLFdBQVcsR0FBRyxDQUFDLE1BQU0sUUFBUSxDQUFDLGVBQWUsQ0FDakQsZ0JBQTBDLENBQzNDLENBQTJCLENBQUM7WUFDN0IsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2xDLE1BQU0sU0FBUyxHQUFHLE1BQU0sU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0MsU0FBUyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMzQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFRlc3RCaXRHbywgVGVzdEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvL3Nkay10ZXN0JztcbmltcG9ydCB7IGJpcDMyIH0gZnJvbSAnQGJpdGdvL3NlY3AyNTZrMSc7XG5pbXBvcnQgKiBhcyBzZWNwMjU2azEgZnJvbSAnc2VjcDI1NmsxJztcbmltcG9ydCB7IEZ1bGx5U2lnbmVkVHJhbnNhY3Rpb24sIFRyYW5zYWN0aW9uVHlwZSwgV2FsbGV0IH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCBub2NrIGZyb20gJ25vY2snO1xuaW1wb3J0ICogYXMgc2hvdWxkIGZyb20gJ3Nob3VsZCc7XG5pbXBvcnQge1xuICBPZmZsaW5lVmF1bHRUeEluZm8sXG4gIG9wdGlvbmFsRGVwcyxcbiAgU2lnblRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgVHJhbnNmZXJCdWlsZGVyLFxuICBUcmFuc2FjdGlvbkJ1aWxkZXIsXG59IGZyb20gJy4uLy4uL3NyYyc7XG5cbm5vY2suZW5hYmxlTmV0Q29ubmVjdCgpO1xuXG5leHBvcnQgZnVuY3Rpb24gcnVuQmFzaWNDb2luSW5mb1Rlc3RzKGNvaW5OYW1lOiBzdHJpbmcsIGJpdGdvOiBUZXN0Qml0R29BUEksIE1haW5Db2luLCBUZXN0Q29pbiwgdGVzdERhdGE6IGFueSkge1xuICBkZXNjcmliZShgJHtjb2luTmFtZX0gYmFzaWMgaW5mbyB0ZXN0YCwgKCkgPT4ge1xuICAgIGNvbnN0IGNvaW5UZXN0ID0gdGVzdERhdGEuQ09JTjtcbiAgICBjb25zdCBjb2luTWFpbiA9IGNvaW5UZXN0LnNsaWNlKDEpO1xuICAgIGl0KGBzaG91bGQgcmV0dXJuIHRoZSByaWdodCBpbmZvIGZvciAke2NvaW5NYWlufWAsICgpID0+IHtcbiAgICAgIGNvbnN0IGNvaW4gPSBiaXRnby5jb2luKGNvaW5NYWluKTtcblxuICAgICAgY29pbi5zaG91bGQuYmUuYW4uaW5zdGFuY2VvZihNYWluQ29pbik7XG4gICAgICBjb2luLmdldENoYWluKCkuc2hvdWxkLmVxdWFsKGNvaW5NYWluKTtcbiAgICAgIGNvaW4uZ2V0RmFtaWx5KCkuc2hvdWxkLmVxdWFsKGNvaW5NYWluKTtcbiAgICAgIGNvaW4uZ2V0RnVsbE5hbWUoKS5zaG91bGQuZXF1YWwodGVzdERhdGEuQ0hBSU5fRlVMTF9OQU1FKTtcbiAgICAgIGNvaW4uZ2V0QmFzZUZhY3RvcigpLnNob3VsZC5lcXVhbCgxZTE4KTtcbiAgICB9KTtcblxuICAgIGl0KGBzaG91bGQgcmV0dXJuIHRoZSByaWdodCBpbmZvIGZvciAke2NvaW5UZXN0fWAsICgpID0+IHtcbiAgICAgIGNvbnN0IGNvaW4gPSBiaXRnby5jb2luKGNvaW5UZXN0KTtcblxuICAgICAgY29pbi5zaG91bGQuYmUuYW4uaW5zdGFuY2VvZihUZXN0Q29pbik7XG4gICAgICBjb2luLmdldENoYWluKCkuc2hvdWxkLmVxdWFsKGNvaW5UZXN0KTtcbiAgICAgIGNvaW4uZ2V0RmFtaWx5KCkuc2hvdWxkLmVxdWFsKGNvaW5NYWluKTtcbiAgICAgIGNvaW4uZ2V0RnVsbE5hbWUoKS5zaG91bGQuZXF1YWwoYFRlc3RuZXQgJHt0ZXN0RGF0YS5DSEFJTl9GVUxMX05BTUV9YCk7XG4gICAgICBjb2luLmdldEJhc2VGYWN0b3IoKS5zaG91bGQuZXF1YWwoMWUxOCk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcnVuRXhwbGFpblRyYW5zYWN0aW9uVGVzdHMoY29pbk5hbWU6IHN0cmluZywgdHhCdWlsZGVyOiBUcmFuc2FjdGlvbkJ1aWxkZXIsIGJhc2Vjb2luLCB0ZXN0RGF0YTogYW55KSB7XG4gIGRlc2NyaWJlKGAke2NvaW5OYW1lfSBleHBsYWluIHRyYW5zYWN0aW9uYCwgKCkgPT4ge1xuICAgIGNvbnN0IGNvaW5UZXN0ID0gdGVzdERhdGEuQ09JTjtcbiAgICAvKipcbiAgICAgKiBCdWlsZCBhbiB1bnNpZ25lZCBhY2NvdW50LWxpYiBtdWx0aS1zaWduYXR1cmUgc2VuZCB0cmFuc2FjdGlub1xuICAgICAqIEBwYXJhbSBkZXN0aW5hdGlvbiBUaGUgZGVzdGluYXRpb24gYWRkcmVzcyBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICAgKiBAcGFyYW0gY29udHJhY3RBZGRyZXNzIFRoZSBhZGRyZXNzIG9mIHRoZSBzbWFydCBjb250cmFjdCBwcm9jZXNzaW5nIHRoZSB0cmFuc2FjdGlvblxuICAgICAqIEBwYXJhbSBjb250cmFjdFNlcXVlbmNlSWQgVGhlIHNlcXVlbmNlIGlkIG9mIHRoZSBjb250cmFjdFxuICAgICAqIEBwYXJhbSBub25jZSBUaGUgbm9uY2Ugb2YgdGhlIHNlbmRpbmcgYWRkcmVzc1xuICAgICAqIEBwYXJhbSBleHBpcmVUaW1lIFRoZSBleHBpcmUgdGltZSBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICAgKiBAcGFyYW0gYW1vdW50IFRoZSBhbW91bnQgdG8gc2VuZCB0byB0aGUgcmVjaXBpZW50XG4gICAgICogQHBhcmFtIGdhc1ByaWNlIFRoZSBnYXMgcHJpY2Ugb2YgdGhlIHRyYW5zYWN0aW9uXG4gICAgICogQHBhcmFtIGdhc0xpbWl0IFRoZSBnYXMgbGltaXQgb2YgdGhlIHRyYW5zYWN0aW9uXG4gICAgICovXG4gICAgY29uc3QgYnVpbGRVbnNpZ25lZFRyYW5zYWN0aW9uID0gYXN5bmMgZnVuY3Rpb24gKHtcbiAgICAgIGRlc3RpbmF0aW9uLFxuICAgICAgY29udHJhY3RBZGRyZXNzLFxuICAgICAgY29udHJhY3RTZXF1ZW5jZUlkID0gMSxcbiAgICAgIG5vbmNlID0gMCxcbiAgICAgIGV4cGlyZVRpbWUgPSBNYXRoLmZsb29yKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC8gMTAwMCksXG4gICAgICBhbW91bnQgPSAnMTAwMDAwJyxcbiAgICAgIGdhc1ByaWNlID0gJzEwMDAwJyxcbiAgICAgIGdhc0xpbWl0ID0gJzIwMDAwJyxcbiAgICB9KSB7XG4gICAgICB0eEJ1aWxkZXIudHlwZShUcmFuc2FjdGlvblR5cGUuU2VuZCk7XG4gICAgICB0eEJ1aWxkZXIuZmVlKHtcbiAgICAgICAgZmVlOiBnYXNQcmljZSxcbiAgICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LFxuICAgICAgfSk7XG4gICAgICB0eEJ1aWxkZXIuY291bnRlcihub25jZSk7XG4gICAgICB0eEJ1aWxkZXIuY29udHJhY3QoY29udHJhY3RBZGRyZXNzKTtcbiAgICAgIGNvbnN0IHRyYW5zZmVyQnVpbGRlciA9IHR4QnVpbGRlci50cmFuc2ZlcigpIGFzIFRyYW5zZmVyQnVpbGRlcjtcblxuICAgICAgdHJhbnNmZXJCdWlsZGVyXG4gICAgICAgIC5jb2luKGNvaW5UZXN0KVxuICAgICAgICAuZXhwaXJhdGlvblRpbWUoZXhwaXJlVGltZSlcbiAgICAgICAgLmFtb3VudChhbW91bnQpXG4gICAgICAgIC50byhkZXN0aW5hdGlvbilcbiAgICAgICAgLmNvbnRyYWN0U2VxdWVuY2VJZChjb250cmFjdFNlcXVlbmNlSWQpO1xuXG4gICAgICByZXR1cm4gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgfTtcbiAgICBpdCgnc2hvdWxkIGZhaWwgaWYgdGhlIG9wdGlvbnMgb2JqZWN0IGlzIG1pc3NpbmcgcGFyYW1ldGVycycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGV4cGxhaW5QYXJhbXMgPSB7XG4gICAgICAgIGZlZUluZm86IHsgZmVlOiAxIH0sXG4gICAgICAgIHR4SGV4OiBudWxsLFxuICAgICAgfTtcbiAgICAgIGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbihleHBsYWluUGFyYW1zKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdtaXNzaW5nIGV4cGxhaW4gdHggcGFyYW1ldGVycycpO1xuICAgIH0pO1xuXG4gICAgaXQoJ2V4cGxhaW4gYSB0cmFuc2ZlciB0cmFuc2FjdGlvbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGRlc3RpbmF0aW9uID0gJzB4ZmFhOGYxNGY0NmE5OWViNDM5YzUwZTBjM2I4MzVjYzIxZGFkNTFiNCc7XG4gICAgICBjb25zdCBjb250cmFjdEFkZHJlc3MgPSAnMHg5ZTJjNTcxMmFiNGNhZjQwMmE5OGM0YmY1OGM3OWEwZGZlNzE4YWQxJztcblxuICAgICAgY29uc3QgdW5zaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJ1aWxkVW5zaWduZWRUcmFuc2FjdGlvbih7XG4gICAgICAgIGRlc3RpbmF0aW9uLFxuICAgICAgICBjb250cmFjdEFkZHJlc3MsXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgZXhwbGFpblBhcmFtcyA9IHtcbiAgICAgICAgaGFsZlNpZ25lZDoge1xuICAgICAgICAgIHR4SGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgIH0sXG4gICAgICAgIGZlZUluZm86IHsgZmVlOiAxIH0sXG4gICAgICB9O1xuICAgICAgY29uc3QgZXhwbGFuYXRpb24gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oZXhwbGFpblBhcmFtcyk7XG4gICAgICBzaG91bGQuZXhpc3QoZXhwbGFuYXRpb24uaWQpO1xuICAgIH0pO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJ1blNpZ25UcmFuc2FjdGlvblRlc3RzKGNvaW5OYW1lOiBzdHJpbmcsIGJ1aWxkZXI6IFRyYW5zYWN0aW9uQnVpbGRlciwgYmFzZWNvaW4sIHRlc3REYXRhOiBhbnkpIHtcbiAgZGVzY3JpYmUoYCR7Y29pbk5hbWV9IHNpZ24gdHJhbnNhY3Rpb24gdGVzdHNgLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgYWNjb3VudF8xID0ge1xuICAgICAgYWRkcmVzczogJzB4OENlNTljMmQxNzAyODQ0RjhFZEVENDUxQUExMDM5NjFiQzM3QjRlOCcsXG4gICAgICBvd25lcl8xOiAnNGVlMDg5YWNlYWJmM2RkYmY3NDhkYjc5YjEwNjZjMzNiN2QzZWExYWIzZWI3ZTMyNTEyMWJiYTJiZmYyZjVjYScsXG4gICAgICBvd25lcl8yOiAnNWM3ZTRlZmZmNzMwNGQ0ZGZmZjZkNWYxNTkxODQ0ZWM2ZjJhZGZhNmE0N2U5ZmVjZTZhM2MxYTRkNzU1ZjFlMycsXG4gICAgICBvd25lcl8zOiAnNDQyMWFiMjVkZDkxZTFhMzE4MGQwM2Q1N2MzMjNhNzg4NmRjYzMxM2QzYjNhNGI0MjU2YTU3OTE1NzJiZjU5NycsXG4gICAgfTtcblxuICAgIGNvbnN0IGFjY291bnRfMiA9IHtcbiAgICAgIGFkZHJlc3M6ICcweGVlYWYwRjA1ZjM3ODkxYWI0YTIxMjA4QjEwNUEwNjg3ZDEyYzVhRjcnLFxuICAgICAgb3duZXJfMTogJzRlZTA4OWFjZWFiZjNkZGJmNzQ4ZGI3OWIxMDY2YzMzYjdkM2VhMWFiM2ViN2UzMjUxMjFiYmEyYmZmMmY1Y2EnLFxuICAgICAgb3duZXJfMjogJzVjYTExNmQyNWFlYzVmNzY1NDY1NDMyY2M0MjFmZjI1ZWY5ZmZkYzMzMGIxMGJiM2Q5YWQ2MWUzYmFhZDg4ZDcnLFxuICAgICAgb3duZXJfMzogJzFmYWU5NDZjYzg0YWY4YmQ3NGQ2MTBhODg1MzdlMjRlMTljMzM0OWQ0NzhkODZmYzViYjU5YmE0Yzg4ZmI5Y2MnLFxuICAgIH07XG5cbiAgICBjb25zdCBjb2luVGVzdCA9IHRlc3REYXRhLkNPSU47XG5cbiAgICBpdCgnc2hvdWxkIHNpZ24gYW4gdW5zaWduZWQgdGVzdCB0eCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGJ1aWxkZXIuZmVlKHtcbiAgICAgICAgZmVlOiAnMjgwMDAwMDAwMDAwJyxcbiAgICAgICAgZ2FzTGltaXQ6ICc3MDAwMDAwJyxcbiAgICAgIH0pO1xuICAgICAgYnVpbGRlci5jb3VudGVyKDEpO1xuICAgICAgYnVpbGRlci50eXBlKFRyYW5zYWN0aW9uVHlwZS5TZW5kKTtcbiAgICAgIGJ1aWxkZXIuY29udHJhY3QoYWNjb3VudF8xLmFkZHJlc3MpO1xuICAgICAgY29uc3QgdHJhbnNmZXJCdWlsZGVyID0gYnVpbGRlci50cmFuc2ZlcigpIGFzIFRyYW5zZmVyQnVpbGRlcjtcbiAgICAgIHRyYW5zZmVyQnVpbGRlci5jb2luKGNvaW5UZXN0KS5hbW91bnQoJzEnKS50byhhY2NvdW50XzIuYWRkcmVzcykuZXhwaXJhdGlvblRpbWUoMTAwMDApLmNvbnRyYWN0U2VxdWVuY2VJZCgxKTtcblxuICAgICAgY29uc3QgdW5zaWduZWRUeCA9IGF3YWl0IGJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGNvbnN0IHVuc2lnbmVkVHhGb3JCcm9hZGNhc3RpbmcgPSB1bnNpZ25lZFR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgICAgIGNvbnN0IGhhbGZTaWduZWRSYXdUeCA9IGF3YWl0IGJhc2Vjb2luLnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICB0eEhleDogdW5zaWduZWRUeEZvckJyb2FkY2FzdGluZyxcbiAgICAgICAgfSxcbiAgICAgICAgcHJ2OiBhY2NvdW50XzEub3duZXJfMixcbiAgICAgIH0pO1xuXG4gICAgICBidWlsZGVyLnRyYW5zZmVyKCkua2V5KGFjY291bnRfMS5vd25lcl8yKTtcbiAgICAgIGNvbnN0IGhhbGZTaWduZWRUeCA9IGF3YWl0IGJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGNvbnN0IGhhbGZTaWduZWRUeEZvckJyb2FkY2FzdGluZyA9IGhhbGZTaWduZWRUeC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuXG4gICAgICBoYWxmU2lnbmVkUmF3VHguaGFsZlNpZ25lZC50eEhleC5zaG91bGQuZXF1YWxzKGhhbGZTaWduZWRUeEZvckJyb2FkY2FzdGluZyk7XG4gICAgICBoYWxmU2lnbmVkUmF3VHguaGFsZlNpZ25lZC5yZWNpcGllbnRzLmxlbmd0aC5zaG91bGQuZXF1YWxzKDEpO1xuICAgICAgaGFsZlNpZ25lZFJhd1R4LmhhbGZTaWduZWQucmVjaXBpZW50c1swXS5hZGRyZXNzLnRvTG93ZXJDYXNlKCkuc2hvdWxkLmVxdWFscyhhY2NvdW50XzIuYWRkcmVzcy50b0xvd2VyQ2FzZSgpKTtcbiAgICAgIGhhbGZTaWduZWRSYXdUeC5oYWxmU2lnbmVkLnJlY2lwaWVudHNbMF0uYW1vdW50LnRvTG93ZXJDYXNlKCkuc2hvdWxkLmVxdWFscygnMScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBzaWduIGFuIHVuc2lnbmVkIHRlc3QgdHggd2l0aCBlaXAxNTU5JywgYXN5bmMgKCkgPT4ge1xuICAgICAgYnVpbGRlci5mZWUoe1xuICAgICAgICBmZWU6ICcyODAwMDAwMDAwMDAnLFxuICAgICAgICBnYXNMaW1pdDogJzcwMDAwMDAnLFxuICAgICAgICBlaXAxNTU5OiB7XG4gICAgICAgICAgbWF4RmVlUGVyR2FzOiAnNzU5MzEyMycsXG4gICAgICAgICAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6ICcxNTAnLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBidWlsZGVyLmNvdW50ZXIoMSk7XG4gICAgICBidWlsZGVyLnR5cGUoVHJhbnNhY3Rpb25UeXBlLlNlbmQpO1xuICAgICAgYnVpbGRlci5jb250cmFjdChhY2NvdW50XzEuYWRkcmVzcyk7XG4gICAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSBidWlsZGVyLnRyYW5zZmVyKCkgYXMgVHJhbnNmZXJCdWlsZGVyO1xuICAgICAgdHJhbnNmZXJCdWlsZGVyLmNvaW4oY29pblRlc3QpLmFtb3VudCgnMScpLnRvKGFjY291bnRfMi5hZGRyZXNzKS5leHBpcmF0aW9uVGltZSgxMDAwMCkuY29udHJhY3RTZXF1ZW5jZUlkKDEpO1xuXG4gICAgICBjb25zdCB1bnNpZ25lZFR4ID0gYXdhaXQgYnVpbGRlci5idWlsZCgpO1xuICAgICAgY29uc3QgdW5zaWduZWRUeEZvckJyb2FkY2FzdGluZyA9IHVuc2lnbmVkVHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgICAgY29uc3QgaGFsZlNpZ25lZFJhd1R4ID0gYXdhaXQgYmFzZWNvaW4uc2lnblRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgIHR4SGV4OiB1bnNpZ25lZFR4Rm9yQnJvYWRjYXN0aW5nLFxuICAgICAgICAgIGVpcDE1NTk6IHtcbiAgICAgICAgICAgIG1heEZlZVBlckdhczogJzc1OTMxMjMnLFxuICAgICAgICAgICAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6ICcxNTAnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHBydjogYWNjb3VudF8xLm93bmVyXzIsXG4gICAgICB9KTtcblxuICAgICAgYnVpbGRlci50cmFuc2ZlcigpLmtleShhY2NvdW50XzEub3duZXJfMik7XG4gICAgICBjb25zdCBoYWxmU2lnbmVkVHggPSBhd2FpdCBidWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCBoYWxmU2lnbmVkVHhGb3JCcm9hZGNhc3RpbmcgPSBoYWxmU2lnbmVkVHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgICAgaGFsZlNpZ25lZFJhd1R4LmhhbGZTaWduZWQudHhIZXguc2hvdWxkLmVxdWFscyhoYWxmU2lnbmVkVHhGb3JCcm9hZGNhc3RpbmcpO1xuICAgICAgaGFsZlNpZ25lZFJhd1R4LmhhbGZTaWduZWQucmVjaXBpZW50cy5sZW5ndGguc2hvdWxkLmVxdWFscygxKTtcbiAgICAgIGhhbGZTaWduZWRSYXdUeC5oYWxmU2lnbmVkLnJlY2lwaWVudHNbMF0uYWRkcmVzcy50b0xvd2VyQ2FzZSgpLnNob3VsZC5lcXVhbHMoYWNjb3VudF8yLmFkZHJlc3MudG9Mb3dlckNhc2UoKSk7XG4gICAgICBoYWxmU2lnbmVkUmF3VHguaGFsZlNpZ25lZC5yZWNpcGllbnRzWzBdLmFtb3VudC50b0xvd2VyQ2FzZSgpLnNob3VsZC5lcXVhbHMoJzEnKTtcbiAgICAgIGhhbGZTaWduZWRSYXdUeC5oYWxmU2lnbmVkLmVpcDE1NTkubWF4RmVlUGVyR2FzLnNob3VsZC5lcXVhbCgnNzU5MzEyMycpO1xuICAgICAgaGFsZlNpZ25lZFJhd1R4LmhhbGZTaWduZWQuZWlwMTU1OS5tYXhQcmlvcml0eUZlZVBlckdhcy5zaG91bGQuZXF1YWwoJzE1MCcpO1xuICAgIH0pO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJ1blRyYW5zYWN0aW9uVmVyaWZpY2F0aW9uVGVzdHMoY29pbk5hbWU6IHN0cmluZywgYml0Z286IFRlc3RCaXRHb0FQSSwgYmFzZWNvaW4sIHRlc3REYXRhOiBhbnkpIHtcbiAgZGVzY3JpYmUoYCR7Y29pbk5hbWV9IFRyYW5zYWN0aW9uIFZlcmlmaWNhdGlvbmAsICgpID0+IHtcbiAgICBjb25zdCBjb2luVGVzdCA9IHRlc3REYXRhLkNPSU47XG4gICAgY29uc3QgYWRkcmVzczEgPSAnMHgxNzRjZmQ4MjNhZjhjZTI3ZWQwYWZlZTNmY2YzYzNiYTI1OTExNmJlJztcbiAgICBjb25zdCBhZGRyZXNzMiA9ICcweDdlODViZGMyN2MwNTBlMzkwNWViZjRiOGU2MzRkOWFkNmVkZDBkZTYnO1xuICAgIGNvbnN0IGhvcERlc3RpbmF0aW9uQWRkcmVzcyA9ICcweDljN2U4Y2U2ODI1YkQ0ODI3OEIzQWI1OTIyOEVFMjZmOEJFNzkyNWInO1xuICAgIGNvbnN0IGhvcFR4ID1cbiAgICAgICcweGY4NmI4MDg1MDRhODE3YzhmZjgyNTJmZjk0OWM3ZThjZTY4MjViZDQ4Mjc4YjNhYjU5MjI4ZWUyNmY4YmU3OTI1Yjg3MDM4ZDdlYTRjNjgwMDA4MDFjYTAxMWJjMjJjNjY0NTcwMTMzZGZjYTRmMDhhMGI4ZDAyMzM5Y2Y0NjcwNDZkNmE0MTUyZjA0ZjM2OGQwZWFmOTllYTAxZDZkYzVjZjBjODk3YzhkNGMzZTFkZjUzZDBkMDQyNzg0YzQyNDUzNmE0Y2M1YjgwMjU1MmI3ZDY0ZmVlOGI1JztcbiAgICBjb25zdCBob3BUeGlkID0gJzB4NGFmNjUxNDNiYzc3ZGEyYjUwZjM1YjNkMTNjYWNiNGRiMThmMDI2YmY4NGJjMDc0MzU1MGJjNTdiOWI1MzM1MSc7XG4gICAgY29uc3QgdXNlclJlcVNpZyA9XG4gICAgICAnMHg0MDRkYjMwN2Y2MTQ3ZjBkOGNkMzM4YzM0YzEzOTA2ZWY0NmE2ZmFhN2UwZTExOWQ1MTk0ZWYwNWFlYzE2ZTZmM2Q3MTBmOWI3OTAxNDYwZjk3ZTkyNDA2NmI2MmVmZDc0NDQzYmQzNDQwMmM2ZDQwYjQ5YzIwM2E1NTlmZjJjOCc7XG4gICAgY29uc3QgYml0Z29LZXlYcHJ2ID1cbiAgICAgICd4cHJ2OXMyMVpyUUgxNDNLM3RwV0JIV2UzMXNMb1hOUlE5QXZSWUpnaXRrS3hRNEFURlFNd3ZyN2hITnFZUlVuUzdQc2p6QjdhSzFWeHFITHVOUWpqMXNja0oySndvMnF4bXN2ZWp3RUNTcEZNZkMnO1xuICAgIGNvbnN0IGJpdGdvS2V5ID0gYmlwMzIuZnJvbUJhc2U1OChiaXRnb0tleVhwcnYpO1xuICAgIGlmICghYml0Z29LZXkucHJpdmF0ZUtleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdubyBwcml2YXRlS2V5Jyk7XG4gICAgfVxuICAgIGNvbnN0IGhvcFR4Qml0Z29TaWduYXR1cmUgPVxuICAgICAgJzB4YWEnICtcbiAgICAgIEJ1ZmZlci5mcm9tKHNlY3AyNTZrMS5lY2RzYVNpZ24oQnVmZmVyLmZyb20oaG9wVHhpZC5zbGljZSgyKSwgJ2hleCcpLCBiaXRnb0tleS5wcml2YXRlS2V5KS5zaWduYXR1cmUpLnRvU3RyaW5nKFxuICAgICAgICAnaGV4J1xuICAgICAgKTtcbiAgICBpdCgnc2hvdWxkIHZlcmlmeSBhIG5vcm1hbCB0eFByZWJ1aWxkIGZyb20gdGhlIGJpdGdvIHNlcnZlciB0aGF0IG1hdGNoZXMgdGhlIGNsaWVudCB0eFBhcmFtcycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2Vjb2luLCB7fSk7XG5cbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbeyBhbW91bnQ6ICcxMDAwMDAwMDAwMDAwJywgYWRkcmVzczogYWRkcmVzczEgfV0sXG4gICAgICAgIHdhbGxldDogd2FsbGV0LFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiAnZmFrZVdhbGxldFBhc3NwaHJhc2UnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW3sgYW1vdW50OiAnMTAwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MxIH1dLFxuICAgICAgICBuZXh0Q29udHJhY3RTZXF1ZW5jZUlkOiAwLFxuICAgICAgICBnYXNQcmljZTogMjAwMDAwMDAwMDAsXG4gICAgICAgIGdhc0xpbWl0OiA1MDAwMDAsXG4gICAgICAgIGlzQmF0Y2g6IGZhbHNlLFxuICAgICAgICBjb2luOiBjb2luVGVzdCxcbiAgICAgICAgd2FsbGV0SWQ6ICdmYWtlV2FsbGV0SWQnLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6ICdmYWtlV2FsbGV0Q29udHJhY3RBZGRyZXNzJyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuXG4gICAgICBjb25zdCBpc1RyYW5zYWN0aW9uVmVyaWZpZWQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQsIHZlcmlmaWNhdGlvbiB9KTtcbiAgICAgIGlzVHJhbnNhY3Rpb25WZXJpZmllZC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlamVjdCB3aGVuIGNsaWVudCB0eFBhcmFtcyBhcmUgbWlzc2luZycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2Vjb2luLCB7fSk7XG5cbiAgICAgIGNvbnN0IHR4UGFyYW1zID0gbnVsbDtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW3sgYW1vdW50OiAnMTAwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MxIH1dLFxuICAgICAgICBuZXh0Q29udHJhY3RTZXF1ZW5jZUlkOiAwLFxuICAgICAgICBnYXNQcmljZTogMjAwMDAwMDAwMDAsXG4gICAgICAgIGdhc0xpbWl0OiA1MDAwMDAsXG4gICAgICAgIGlzQmF0Y2g6IGZhbHNlLFxuICAgICAgICBjb2luOiBjb2luVGVzdCxcbiAgICAgICAgd2FsbGV0SWQ6ICdmYWtlV2FsbGV0SWQnLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6ICdmYWtlV2FsbGV0Q29udHJhY3RBZGRyZXNzJyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuXG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0LCB2ZXJpZmljYXRpb24gfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ21pc3NpbmcgcGFyYW1zJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlamVjdCB0eFByZWJ1aWxkIHRoYXQgaXMgYm90aCBiYXRjaCBhbmQgaG9wJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgd2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYmFzZWNvaW4sIHt9KTtcblxuICAgICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICAgIHJlY2lwaWVudHM6IFtcbiAgICAgICAgICB7IGFtb3VudDogJzEwMDAwMDAwMDAwMDAnLCBhZGRyZXNzOiBhZGRyZXNzMSB9LFxuICAgICAgICAgIHsgYW1vdW50OiAnMjUwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MyIH0sXG4gICAgICAgIF0sXG4gICAgICAgIHdhbGxldDogd2FsbGV0LFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiAnZmFrZVdhbGxldFBhc3NwaHJhc2UnLFxuICAgICAgICBob3A6IHRydWUsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbeyBhbW91bnQ6ICczNTAwMDAwMDAwMDAwJywgYWRkcmVzczogYWRkcmVzczEgfV0sXG4gICAgICAgIG5leHRDb250cmFjdFNlcXVlbmNlSWQ6IDAsXG4gICAgICAgIGdhc1ByaWNlOiAyMDAwMDAwMDAwMCxcbiAgICAgICAgZ2FzTGltaXQ6IDUwMDAwMCxcbiAgICAgICAgaXNCYXRjaDogdHJ1ZSxcbiAgICAgICAgY29pbjogY29pblRlc3QsXG4gICAgICAgIHdhbGxldElkOiAnZmFrZVdhbGxldElkJyxcbiAgICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiAnZmFrZVdhbGxldENvbnRyYWN0QWRkcmVzcycsXG4gICAgICAgIGhvcFRyYW5zYWN0aW9uOiB7XG4gICAgICAgICAgdHg6IGhvcFR4LFxuICAgICAgICAgIGlkOiBob3BUeGlkLFxuICAgICAgICAgIHNpZ25hdHVyZTogaG9wVHhCaXRnb1NpZ25hdHVyZSxcbiAgICAgICAgICBwYXltZW50SWQ6ICcyNzczOTI4MTk2JyxcbiAgICAgICAgICBnYXNQcmljZTogMjAwMDAwMDAwMDAsXG4gICAgICAgICAgZ2FzTGltaXQ6IDUwMDAwMCxcbiAgICAgICAgICBhbW91bnQ6ICcxMDAwMDAwMDAwMDAwMDAwJyxcbiAgICAgICAgICByZWNpcGllbnQ6IGhvcERlc3RpbmF0aW9uQWRkcmVzcyxcbiAgICAgICAgICBub25jZTogMCxcbiAgICAgICAgICB1c2VyUmVxU2lnOiB1c2VyUmVxU2lnLFxuICAgICAgICAgIGdhc1ByaWNlTWF4OiA1MDAwMDAwMDAwMDAsXG4gICAgICAgIH0sXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB2ZXJpZmljYXRpb24gPSB7fTtcblxuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHdhbGxldCwgdmVyaWZpY2F0aW9uIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCd0eCBjYW5ub3QgYmUgYm90aCBhIGJhdGNoIGFuZCBob3AgdHJhbnNhY3Rpb24nKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IGEgdHhQcmVidWlsZCB3aXRoIG1vcmUgdGhhbiBvbmUgcmVjaXBpZW50JywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgd2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYmFzZWNvaW4sIHt9KTtcblxuICAgICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICAgIHJlY2lwaWVudHM6IFtcbiAgICAgICAgICB7IGFtb3VudDogJzEwMDAwMDAwMDAwMDAnLCBhZGRyZXNzOiBhZGRyZXNzMSB9LFxuICAgICAgICAgIHsgYW1vdW50OiAnMjUwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MyIH0sXG4gICAgICAgIF0sXG4gICAgICAgIHdhbGxldDogd2FsbGV0LFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiAnZmFrZVdhbGxldFBhc3NwaHJhc2UnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW1xuICAgICAgICAgIHsgYW1vdW50OiAnMTAwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MxIH0sXG4gICAgICAgICAgeyBhbW91bnQ6ICcyNTAwMDAwMDAwMDAwJywgYWRkcmVzczogYWRkcmVzczIgfSxcbiAgICAgICAgXSxcbiAgICAgICAgbmV4dENvbnRyYWN0U2VxdWVuY2VJZDogMCxcbiAgICAgICAgZ2FzUHJpY2U6IDIwMDAwMDAwMDAwLFxuICAgICAgICBnYXNMaW1pdDogNTAwMDAwLFxuICAgICAgICBpc0JhdGNoOiB0cnVlLFxuICAgICAgICBjb2luOiBjb2luVGVzdCxcbiAgICAgICAgd2FsbGV0SWQ6ICdmYWtlV2FsbGV0SWQnLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6ICdmYWtlV2FsbGV0Q29udHJhY3RBZGRyZXNzJyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuXG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0LCB2ZXJpZmljYXRpb24gfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoXG4gICAgICAgICAgYCR7Y29pblRlc3R9IGRvZXNuJ3Qgc3VwcG9ydCBzZW5kaW5nIHRvIG1vcmUgdGhhbiAxIGRlc3RpbmF0aW9uIGFkZHJlc3Mgd2l0aGluIGEgc2luZ2xlIHRyYW5zYWN0aW9uLiBUcnkgYWdhaW4sIHVzaW5nIG9ubHkgYSBzaW5nbGUgcmVjaXBpZW50LmBcbiAgICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IGEgaG9wIHR4UHJlYnVpbGQgdGhhdCBkb2VzIG5vdCBzZW5kIHRvIGl0cyBob3AgYWRkcmVzcycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2Vjb2luLCB7fSk7XG5cbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbeyBhbW91bnQ6ICcxMDAwMDAwMDAwMDAwMDAwJywgYWRkcmVzczogaG9wRGVzdGluYXRpb25BZGRyZXNzIH1dLFxuICAgICAgICB3YWxsZXQ6IHdhbGxldCxcbiAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogJ2Zha2VXYWxsZXRQYXNzcGhyYXNlJyxcbiAgICAgICAgaG9wOiB0cnVlLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW3sgYW1vdW50OiAnNTAwMDAwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MxIH1dLFxuICAgICAgICBuZXh0Q29udHJhY3RTZXF1ZW5jZUlkOiAwLFxuICAgICAgICBnYXNQcmljZTogMjAwMDAwMDAwMDAsXG4gICAgICAgIGdhc0xpbWl0OiA1MDAwMDAsXG4gICAgICAgIGlzQmF0Y2g6IGZhbHNlLFxuICAgICAgICBjb2luOiBjb2luVGVzdCxcbiAgICAgICAgd2FsbGV0SWQ6ICdmYWtlV2FsbGV0SWQnLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6ICdmYWtlV2FsbGV0Q29udHJhY3RBZGRyZXNzJyxcbiAgICAgICAgaG9wVHJhbnNhY3Rpb246IHtcbiAgICAgICAgICB0eDogaG9wVHgsXG4gICAgICAgICAgaWQ6IGhvcFR4aWQsXG4gICAgICAgICAgc2lnbmF0dXJlOiBob3BUeEJpdGdvU2lnbmF0dXJlLFxuICAgICAgICAgIHBheW1lbnRJZDogJzAnLFxuICAgICAgICAgIGdhc1ByaWNlOiAyMDAwMDAwMDAwMCxcbiAgICAgICAgICBnYXNMaW1pdDogNTAwMDAwLFxuICAgICAgICAgIGFtb3VudDogJzEwMDAwMDAwMDAwMDAwMDAnLFxuICAgICAgICAgIHJlY2lwaWVudDogaG9wRGVzdGluYXRpb25BZGRyZXNzLFxuICAgICAgICAgIG5vbmNlOiAwLFxuICAgICAgICAgIHVzZXJSZXFTaWc6IHVzZXJSZXFTaWcsXG4gICAgICAgICAgZ2FzUHJpY2VNYXg6IDUwMDAwMDAwMDAwMCxcbiAgICAgICAgfSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuXG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0LCB2ZXJpZmljYXRpb24gfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ3JlY2lwaWVudCBhZGRyZXNzIG9mIHR4UHJlYnVpbGQgZG9lcyBub3QgbWF0Y2ggaG9wIGFkZHJlc3MnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IGEgbm9ybWFsIHR4UHJlYnVpbGQgZnJvbSB0aGUgYml0Z28gc2VydmVyIHdpdGggdGhlIHdyb25nIGFtb3VudCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2Vjb2luLCB7fSk7XG5cbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbeyBhbW91bnQ6ICcxMDAwMDAwMDAwMDAwJywgYWRkcmVzczogYWRkcmVzczEgfV0sXG4gICAgICAgIHdhbGxldDogd2FsbGV0LFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiAnZmFrZVdhbGxldFBhc3NwaHJhc2UnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW3sgYW1vdW50OiAnMjAwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MxIH1dLFxuICAgICAgICBuZXh0Q29udHJhY3RTZXF1ZW5jZUlkOiAwLFxuICAgICAgICBnYXNQcmljZTogMjAwMDAwMDAwMDAsXG4gICAgICAgIGdhc0xpbWl0OiA1MDAwMDAsXG4gICAgICAgIGlzQmF0Y2g6IGZhbHNlLFxuICAgICAgICBjb2luOiBjb2luVGVzdCxcbiAgICAgICAgd2FsbGV0SWQ6ICdmYWtlV2FsbGV0SWQnLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6ICdmYWtlV2FsbGV0Q29udHJhY3RBZGRyZXNzJyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuXG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0LCB2ZXJpZmljYXRpb24gfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoXG4gICAgICAgICAgJ25vcm1hbCB0cmFuc2FjdGlvbiBhbW91bnQgaW4gdHhQcmVidWlsZCByZWNlaXZlZCBmcm9tIEJpdEdvIHNlcnZlcnMgZG9lcyBub3QgbWF0Y2ggdHhQYXJhbXMgc3VwcGxpZWQgYnkgY2xpZW50J1xuICAgICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZWplY3QgYSBub3JtYWwgdHhQcmVidWlsZCBmcm9tIHRoZSBiaXRnbyBzZXJ2ZXIgd2l0aCB0aGUgd3JvbmcgcmVjaXBpZW50JywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgd2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYmFzZWNvaW4sIHt9KTtcblxuICAgICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICAgIHJlY2lwaWVudHM6IFt7IGFtb3VudDogJzEwMDAwMDAwMDAwMDAnLCBhZGRyZXNzOiBhZGRyZXNzMSB9XSxcbiAgICAgICAgd2FsbGV0OiB3YWxsZXQsXG4gICAgICAgIHdhbGxldFBhc3NwaHJhc2U6ICdmYWtlV2FsbGV0UGFzc3BocmFzZScsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbeyBhbW91bnQ6ICcxMDAwMDAwMDAwMDAwJywgYWRkcmVzczogYWRkcmVzczIgfV0sXG4gICAgICAgIG5leHRDb250cmFjdFNlcXVlbmNlSWQ6IDAsXG4gICAgICAgIGdhc1ByaWNlOiAyMDAwMDAwMDAwMCxcbiAgICAgICAgZ2FzTGltaXQ6IDUwMDAwMCxcbiAgICAgICAgaXNCYXRjaDogZmFsc2UsXG4gICAgICAgIGNvaW46IGNvaW5UZXN0LFxuICAgICAgICB3YWxsZXRJZDogJ2Zha2VXYWxsZXRJZCcsXG4gICAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogJ2Zha2VXYWxsZXRDb250cmFjdEFkZHJlc3MnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdmVyaWZpY2F0aW9uID0ge307XG5cbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQsIHZlcmlmaWNhdGlvbiB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aChcbiAgICAgICAgICAnZGVzdGluYXRpb24gYWRkcmVzcyBpbiBub3JtYWwgdHhQcmVidWlsZCBkb2VzIG5vdCBtYXRjaCB0aGF0IGluIHR4UGFyYW1zIHN1cHBsaWVkIGJ5IGNsaWVudCdcbiAgICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IGEgdHhQcmVidWlsZCBmcm9tIHRoZSBiaXRnbyBzZXJ2ZXIgd2l0aCB0aGUgd3JvbmcgY29pbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2Vjb2luLCB7fSk7XG5cbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbeyBhbW91bnQ6ICcxMDAwMDAwMDAwMDAwJywgYWRkcmVzczogYWRkcmVzczEgfV0sXG4gICAgICAgIHdhbGxldDogd2FsbGV0LFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiAnZmFrZVdhbGxldFBhc3NwaHJhc2UnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW3sgYW1vdW50OiAnMTAwMDAwMDAwMDAwMCcsIGFkZHJlc3M6IGFkZHJlc3MxIH1dLFxuICAgICAgICBuZXh0Q29udHJhY3RTZXF1ZW5jZUlkOiAwLFxuICAgICAgICBnYXNQcmljZTogMjAwMDAwMDAwMDAsXG4gICAgICAgIGdhc0xpbWl0OiA1MDAwMDAsXG4gICAgICAgIGlzQmF0Y2g6IGZhbHNlLFxuICAgICAgICBjb2luOiAnYnRjJyxcbiAgICAgICAgd2FsbGV0SWQ6ICdmYWtlV2FsbGV0SWQnLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6ICdmYWtlV2FsbGV0Q29udHJhY3RBZGRyZXNzJyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHt9O1xuXG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0LCB2ZXJpZmljYXRpb24gfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ2NvaW4gaW4gdHhQcmVidWlsZCBkaWQgbm90IG1hdGNoIHRoYXQgaW4gdHhQYXJhbXMgc3VwcGxpZWQgYnkgY2xpZW50Jyk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcnVuUmVjb3ZlcnlUcmFuc2FjdGlvblRlc3RzKFxuICBjb2luTmFtZTogc3RyaW5nLFxuICB0eEJ1aWxkZXI6IFRyYW5zYWN0aW9uQnVpbGRlcixcbiAgYml0Z286IFRlc3RCaXRHb0FQSSxcbiAgdGVzdERhdGE6IGFueSxcbiAgbW9ja0RhdGE6IGFueVxuKSB7XG4gIGRlc2NyaWJlKGAke2NvaW5OYW1lfSBSZWNvdmVyIHRyYW5zYWN0aW9uOmAsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBiYXNlVXJsID0gdGVzdERhdGEuQkFTRV9VUkw7XG4gICAgY29uc3QgdXNlclhwdWIgPVxuICAgICAgJ3hwdWI2NjFNeU13QXFSYmNFZVRjODc4OU1LNVBVR0VZaVBHNEY0VjE3bjJSZDJMb1RBVEExWG9DbkpUNUZBWUFTaFF4U3h0RmpwbzVOSG1jV3dUcDJMaVdHQk13cFVjQUEzSHl3aHhpdmdZZnE3cSc7XG4gICAgY29uc3QgdXNlclhwcnYgPVxuICAgICAgJ3hwcnY5czIxWnJRSDE0M0syQVA5MjViOHpCOGV2RVE0SnZZQ3NxWlFLUGNwNGdvcGFOODFUelV4RVc4YlB0VnlEZ2ptZGRHaFJSRVRuOHhpMWNWQUI5YmYxQng5a0dSUkZnVFpYeEpheVpMbmFnMSc7XG4gICAgY29uc3QgYmFja3VwWHB1YiA9XG4gICAgICAneHB1YjY2MU15TXdBcVJiY0ZaWDE1eHBaZjRFUkNHSGlWU0ptOHI1QzR5aDF5WFYyR3JkWkNVUFlvNFdRcjZ0TjlvVXl3S1hzZ1NIbzdSaXNmOXIyMkdINWpvVkQyaEVFRWhxblNDdks4cXkxMXdXJztcbiAgICBjb25zdCBiYWNrdXBYcHJ2ID1cbiAgICAgICd4cHJ2OXMyMVpyUUgxNDNLMzVTWHl3SFpIdkhnZUVURTV5YXVtZDliR2JIUVJCeDNRNEpRZXc1SkZHQnZ6cWlaakNVa0JkQlVabmZ1TURUR1VSUmF5TjFoRlNXeEVKUXNDRUFNbTFEM3BrMWg3SmonO1xuICAgIGNvbnN0IGNvaW4gPSB0ZXN0RGF0YS5DT0lOO1xuXG4gICAgYWZ0ZXIoZnVuY3Rpb24gKCkge1xuICAgICAgbm9jay5jbGVhbkFsbCgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBhbiB1bnNpZ25lZCBzd2VlcCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHdhbGxldENvbnRyYWN0QWRkcmVzcyA9IFRlc3RCaXRHby5WMi5URVNUX0VUSF9XQUxMRVRfRklSU1RfQUREUkVTUyBhcyBzdHJpbmc7XG4gICAgICBjb25zdCBiYWNrdXBLZXlBZGRyZXNzID0gJzB4NGYyYzQ4MzBjYzM3ZjI3ODVjNjQ2Zjg5ZGVkOGE5MTkyMTlmYTBlOSc7XG4gICAgICBub2NrKGJhc2VVcmwpXG4gICAgICAgIC5nZXQoJy9hcGknKVxuICAgICAgICAudHdpY2UoKVxuICAgICAgICAucXVlcnkobW9ja0RhdGEuZ2V0VHhMaXN0UmVxdWVzdChiYWNrdXBLZXlBZGRyZXNzKSlcbiAgICAgICAgLnJlcGx5KDIwMCwgbW9ja0RhdGEuZ2V0VHhMaXN0UmVzcG9uc2UpO1xuICAgICAgbm9jayhiYXNlVXJsKVxuICAgICAgICAuZ2V0KCcvYXBpJylcbiAgICAgICAgLnF1ZXJ5KG1vY2tEYXRhLmdldEJhbGFuY2VSZXF1ZXN0KHdhbGxldENvbnRyYWN0QWRkcmVzcykpXG4gICAgICAgIC5yZXBseSgyMDAsIG1vY2tEYXRhLmdldEJhbGFuY2VSZXNwb25zZSk7XG4gICAgICBub2NrKGJhc2VVcmwpXG4gICAgICAgIC5nZXQoJy9hcGknKVxuICAgICAgICAucXVlcnkobW9ja0RhdGEuZ2V0QmFsYW5jZVJlcXVlc3QoYmFja3VwS2V5QWRkcmVzcykpXG4gICAgICAgIC5yZXBseSgyMDAsIG1vY2tEYXRhLmdldEJhbGFuY2VSZXNwb25zZSk7XG4gICAgICBub2NrKGJhc2VVcmwpLmdldCgnL2FwaScpLnF1ZXJ5KG1vY2tEYXRhLmdldENvbnRyYWN0Q2FsbFJlcXVlc3QpLnJlcGx5KDIwMCwgbW9ja0RhdGEuZ2V0Q29udHJhY3RDYWxsUmVzcG9uc2UpO1xuICAgICAgY29uc3QgYmFzZWNvaW46IGFueSA9IGJpdGdvLmNvaW4oY29pbik7XG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgdXNlcktleTogdXNlclhwdWIsXG4gICAgICAgIGJhY2t1cEtleTogYmFja3VwWHB1YixcbiAgICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiB3YWxsZXRDb250cmFjdEFkZHJlc3MsXG4gICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IFRlc3RCaXRHby5WMi5URVNUX0VSQzIwX1RPS0VOX1JFQ0lQSUVOVCBhcyBzdHJpbmcsXG4gICAgICAgIGVpcDE1NTk6IHsgbWF4RmVlUGVyR2FzOiAyMDAwMDAwMDAwMCwgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IDEwMDAwMDAwMDAwIH0sXG4gICAgICAgIGdhc0xpbWl0OiA1MDAwMDAsXG4gICAgICB9KSkgYXMgT2ZmbGluZVZhdWx0VHhJbmZvO1xuICAgICAgc2hvdWxkLmV4aXN0KHRyYW5zYWN0aW9uKTtcbiAgICAgIHRyYW5zYWN0aW9uLnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eEhleCcpO1xuICAgICAgdHJhbnNhY3Rpb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ2NvbnRyYWN0U2VxdWVuY2VJZCcpO1xuICAgICAgdHJhbnNhY3Rpb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ2V4cGlyZVRpbWUnKTtcbiAgICAgIHRyYW5zYWN0aW9uLnNob3VsZC5oYXZlLnByb3BlcnR5KCdnYXNMaW1pdCcpO1xuICAgICAgdHJhbnNhY3Rpb24uZ2FzTGltaXQuc2hvdWxkLmVxdWFsKCc1MDAwMDAnKTtcbiAgICAgIHRyYW5zYWN0aW9uLnNob3VsZC5oYXZlLnByb3BlcnR5KCd3YWxsZXRDb250cmFjdEFkZHJlc3MnKTtcbiAgICAgIHRyYW5zYWN0aW9uLndhbGxldENvbnRyYWN0QWRkcmVzcy5zaG91bGQuZXF1YWwoVGVzdEJpdEdvLlYyLlRFU1RfRVRIX1dBTExFVF9GSVJTVF9BRERSRVNTKTtcbiAgICAgIHRyYW5zYWN0aW9uLnNob3VsZC5oYXZlLnByb3BlcnR5KCdyZWNpcGllbnRzJyk7XG4gICAgICBjb25zdCByZWNpcGllbnQgPSB0cmFuc2FjdGlvbi5yZWNpcGllbnRzWzBdO1xuICAgICAgcmVjaXBpZW50LnNob3VsZC5oYXZlLnByb3BlcnR5KCdhZGRyZXNzJyk7XG4gICAgICByZWNpcGllbnQuYWRkcmVzcy5zaG91bGQuZXF1YWwoVGVzdEJpdEdvLlYyLlRFU1RfRVJDMjBfVE9LRU5fUkVDSVBJRU5UKTtcbiAgICAgIHJlY2lwaWVudC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnYW1vdW50Jyk7XG4gICAgICByZWNpcGllbnQuYW1vdW50LnNob3VsZC5lcXVhbCgnOTk5OTk5OTk5OTk5OTk5OTkyOCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBjb25zdHJ1Y3QgYSByZWNvdmVyeSB0cmFuc2FjdGlvbiB3aXRob3V0IEJpdEdvJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgYmFja3VwS2V5QWRkcmVzcyA9ICcweDZkMjJlZmRkNjM0OTk2MjQ4MTcwYzk0OGU1NzI2MDA3ZmMyNTFiYjMnO1xuICAgICAgY29uc3Qgd2FsbGV0Q29udHJhY3RBZGRyZXNzID0gVGVzdEJpdEdvLlYyLlRFU1RfRVRIX1dBTExFVF9GSVJTVF9BRERSRVNTIGFzIHN0cmluZztcbiAgICAgIG5vY2soYmFzZVVybClcbiAgICAgICAgLmdldCgnL2FwaScpXG4gICAgICAgIC5xdWVyeShtb2NrRGF0YS5nZXRUeExpc3RSZXF1ZXN0KGJhY2t1cEtleUFkZHJlc3MpKVxuICAgICAgICAucmVwbHkoMjAwLCBtb2NrRGF0YS5nZXRUeExpc3RSZXNwb25zZSk7XG4gICAgICBub2NrKGJhc2VVcmwpXG4gICAgICAgIC5nZXQoJy9hcGknKVxuICAgICAgICAucXVlcnkobW9ja0RhdGEuZ2V0QmFsYW5jZVJlcXVlc3Qod2FsbGV0Q29udHJhY3RBZGRyZXNzKSlcbiAgICAgICAgLnJlcGx5KDIwMCwgbW9ja0RhdGEuZ2V0QmFsYW5jZVJlc3BvbnNlKTtcbiAgICAgIG5vY2soYmFzZVVybClcbiAgICAgICAgLmdldCgnL2FwaScpXG4gICAgICAgIC5xdWVyeShtb2NrRGF0YS5nZXRCYWxhbmNlUmVxdWVzdChiYWNrdXBLZXlBZGRyZXNzKSlcbiAgICAgICAgLnJlcGx5KDIwMCwgbW9ja0RhdGEuZ2V0QmFsYW5jZVJlc3BvbnNlKTtcbiAgICAgIG5vY2soYmFzZVVybCkuZ2V0KCcvYXBpJykucXVlcnkobW9ja0RhdGEuZ2V0Q29udHJhY3RDYWxsUmVxdWVzdCkucmVwbHkoMjAwLCBtb2NrRGF0YS5nZXRDb250cmFjdENhbGxSZXNwb25zZSk7XG4gICAgICBjb25zdCBiYXNlY29pbjogYW55ID0gYml0Z28uY29pbihjb2luKTtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gKGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICB1c2VyS2V5OlxuICAgICAgICAgICd7XCJpdlwiOlwiVkZaM2p2WGh4bzFaK1lhZjJNdFpuQT09XCIsXCJ2XCI6MSxcIml0ZXJcIjoxMDAwMCxcImtzXCI6MjU2LFwidHNcIjo2NCxcIm1vZGVcIlxcbicgK1xuICAgICAgICAgICc6XCJjY21cIixcImFkYXRhXCI6XCJcIixcImNpcGhlclwiOlwiYWVzXCIsXCJzYWx0XCI6XCJwK2ZrSHVMYS84az1cIixcImN0XCI6XCJoWUc3cHZsakxJZ0NqWlxcbicgK1xuICAgICAgICAgICc1M1BCbENkZTVLWlJtbFVLS0hMdERNaytISmZ1VTQ2aFcreCtDOVdzSUFPNGdGUG5UQ3ZGVm1ROHg3Y3pDdGNORnViNUFPMm90T0dcXG4nICtcbiAgICAgICAgICAnT3NYNEdFMmdYT0VtQ2wxVHBXd3dOaG03eU1VakdKVXBnVzZaWmdYU1hkRGl0U0tpNFYvaGs3OFNHU3pqRk9CU1BZUmE2ST1cIn1cXG4nLFxuICAgICAgICBiYWNrdXBLZXk6XG4gICAgICAgICAgJ3tcIml2XCI6XCJBYnNDdHYxcXdQSWhPZ3lyQ3BOYWdBPT1cIixcInZcIjoxLFwiaXRlclwiOjEwMDAwLFwia3NcIjoyNTYsXCJ0c1wiOjY0LFwibW9kZVwiXFxuJyArXG4gICAgICAgICAgJzpcImNjbVwiLFwiYWRhdGFcIjpcIlwiLFwiY2lwaGVyXCI6XCJhZXNcIixcInNhbHRcIjpcIjV2cFVEQlVsem04PVwiLFwiY3RcIjpcIlBhcFlZQ2pCWFJMVUtBXFxuJyArXG4gICAgICAgICAgJ0piT3NCL0VKOUI4ZlVtVlFUeE1QalVuUXlBa3kxMm1lOUs2NkdpTUVBeFREN2tkNmJZQVFKdXVUa0FUWEtVN0JuZjd2SzlKeE5Pd1xcbicgK1xuICAgICAgICAgICdvamk3SEY5ZUZIMGFENC9oWDVTV0ZmSEYyUWZpK1RuWHY2aFZzTUFvaXNEWnMzL0Y2Ny9aVWFEWVIwWnNkclE0US9jTEQwPVwifVxcbicsXG5cbiAgICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiB3YWxsZXRDb250cmFjdEFkZHJlc3MsXG4gICAgICAgIHdhbGxldFBhc3NwaHJhc2U6IFRlc3RCaXRHby5WMi5URVNUX1JFQ09WRVJZX1BBU1NDT0RFLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBUZXN0Qml0R28uVjIuVEVTVF9FUkMyMF9UT0tFTl9SRUNJUElFTlQgYXMgc3RyaW5nLFxuICAgICAgICBnYXNMaW1pdDogNTAwMDAwLFxuICAgICAgfSkpIGFzIE9mZmxpbmVWYXVsdFR4SW5mbztcbiAgICAgIHNob3VsZC5leGlzdCh0cmFuc2FjdGlvbik7XG4gICAgICB0cmFuc2FjdGlvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndHgnKTtcbiAgICAgIHRyYW5zYWN0aW9uLnNob3VsZC5oYXZlLnByb3BlcnR5KCdpZCcpO1xuICAgICAgY29uc3QgZGVjb2RlZFR4ID0gb3B0aW9uYWxEZXBzLkV0aFR4LlRyYW5zYWN0aW9uLmZyb21TZXJpYWxpemVkVHgob3B0aW9uYWxEZXBzLmV0aFV0aWwudG9CdWZmZXIodHJhbnNhY3Rpb24udHgpKTtcbiAgICAgIGRlY29kZWRUeC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnZ2FzUHJpY2UnKTtcbiAgICAgIGRlY29kZWRUeC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbm9uY2UnKTtcbiAgICAgIGRlY29kZWRUeC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndG8nKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYmUgYWJsZSB0byBzZWNvbmQgc2lnbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHdhbGxldENvbnRyYWN0QWRkcmVzcyA9IFRlc3RCaXRHby5WMi5URVNUX0VUSF9XQUxMRVRfRklSU1RfQUREUkVTUyBhcyBzdHJpbmc7XG4gICAgICBjb25zdCBiYWNrdXBLZXlBZGRyZXNzID0gJzB4NGYyYzQ4MzBjYzM3ZjI3ODVjNjQ2Zjg5ZGVkOGE5MTkyMTlmYTBlOSc7XG4gICAgICBub2NrKGJhc2VVcmwpXG4gICAgICAgIC5nZXQoJy9hcGknKVxuICAgICAgICAudHdpY2UoKVxuICAgICAgICAucXVlcnkobW9ja0RhdGEuZ2V0VHhMaXN0UmVxdWVzdChiYWNrdXBLZXlBZGRyZXNzKSlcbiAgICAgICAgLnJlcGx5KDIwMCwgbW9ja0RhdGEuZ2V0VHhMaXN0UmVzcG9uc2UpO1xuICAgICAgbm9jayhiYXNlVXJsKVxuICAgICAgICAuZ2V0KCcvYXBpJylcbiAgICAgICAgLnF1ZXJ5KG1vY2tEYXRhLmdldEJhbGFuY2VSZXF1ZXN0KHdhbGxldENvbnRyYWN0QWRkcmVzcykpXG4gICAgICAgIC5yZXBseSgyMDAsIG1vY2tEYXRhLmdldEJhbGFuY2VSZXNwb25zZSk7XG4gICAgICBub2NrKGJhc2VVcmwpXG4gICAgICAgIC5nZXQoJy9hcGknKVxuICAgICAgICAucXVlcnkobW9ja0RhdGEuZ2V0QmFsYW5jZVJlcXVlc3QoYmFja3VwS2V5QWRkcmVzcykpXG4gICAgICAgIC5yZXBseSgyMDAsIG1vY2tEYXRhLmdldEJhbGFuY2VSZXNwb25zZSk7XG4gICAgICBub2NrKGJhc2VVcmwpLmdldCgnL2FwaScpLnF1ZXJ5KG1vY2tEYXRhLmdldENvbnRyYWN0Q2FsbFJlcXVlc3QpLnJlcGx5KDIwMCwgbW9ja0RhdGEuZ2V0Q29udHJhY3RDYWxsUmVzcG9uc2UpO1xuICAgICAgY29uc3QgYmFzZWNvaW46IGFueSA9IGJpdGdvLmNvaW4oY29pbik7XG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgdXNlcktleTogdXNlclhwdWIsXG4gICAgICAgIGJhY2t1cEtleTogYmFja3VwWHB1YixcbiAgICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiB3YWxsZXRDb250cmFjdEFkZHJlc3MsXG4gICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IFRlc3RCaXRHby5WMi5URVNUX0VSQzIwX1RPS0VOX1JFQ0lQSUVOVCBhcyBzdHJpbmcsXG4gICAgICAgIGVpcDE1NTk6IHsgbWF4RmVlUGVyR2FzOiAyMDAwMDAwMDAwMCwgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IDEwMDAwMDAwMDAwIH0sXG4gICAgICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zOiB7IGNoYWluOiA4MDAwMSwgaGFyZGZvcms6ICdsb25kb24nIH0sXG4gICAgICAgIGdhc0xpbWl0OiA1MDAwMDAsXG4gICAgICB9KSkgYXMgT2ZmbGluZVZhdWx0VHhJbmZvO1xuXG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgICAgICB0eEhleDogdHJhbnNhY3Rpb24udHhIZXgsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICAgIHR4UHJlYnVpbGQsXG4gICAgICAgIHBydjogdXNlclhwcnYsXG4gICAgICB9O1xuICAgICAgLy8gc2lnbiB0cmFuc2FjdGlvbiBvbmNlXG4gICAgICBjb25zdCBoYWxmU2lnbmVkID0gYXdhaXQgYmFzZWNvaW4uc2lnblRyYW5zYWN0aW9uKHBhcmFtcyBhcyBTaWduVHJhbnNhY3Rpb25PcHRpb25zKTtcbiAgICAgIGNvbnN0IGhhbGZTaWduZWRQYXJhbXMgPSB7XG4gICAgICAgIHR4UHJlYnVpbGQ6IGhhbGZTaWduZWQsXG4gICAgICAgIGlzTGFzdFNpZ25hdHVyZTogdHJ1ZSxcbiAgICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiB3YWxsZXRDb250cmFjdEFkZHJlc3MsXG4gICAgICAgIHBydjogYmFja3VwWHBydixcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGZpbmFsU2lnbmVkID0gKGF3YWl0IGJhc2Vjb2luLnNpZ25UcmFuc2FjdGlvbihcbiAgICAgICAgaGFsZlNpZ25lZFBhcmFtcyBhcyBTaWduVHJhbnNhY3Rpb25PcHRpb25zXG4gICAgICApKSBhcyBGdWxseVNpZ25lZFRyYW5zYWN0aW9uO1xuICAgICAgZmluYWxTaWduZWQuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3R4SGV4Jyk7XG4gICAgICB0eEJ1aWxkZXIuZnJvbShmaW5hbFNpZ25lZC50eEhleCk7XG4gICAgICBjb25zdCByZWJ1aWx0VHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIHJlYnVpbHRUeC5zaWduYXR1cmUubGVuZ3RoLnNob3VsZC5lcXVhbCgyKTtcbiAgICAgIHJlYnVpbHRUeC5vdXRwdXRzLmxlbmd0aC5zaG91bGQuZXF1YWwoMSk7XG4gICAgfSk7XG4gIH0pO1xufVxuIl19

Выполнить команду


Для локальной разработки. Не используйте в интернете!