UNPKG

bitgo

Version:
398 lines • 68.7 kB
"use strict";
/**
 * @prettier
 */
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const should = require("should");
const utxo_lib_1 = require("@bitgo/utxo-lib");
const sdk_test_1 = require("@bitgo/sdk-test");
const bitgo_1 = require("../../../../src/bitgo");
const account_lib_1 = require("@bitgo/account-lib");
const ethAbi = require("ethereumjs-abi");
const ethUtil = require("ethereumjs-util");
const statics_1 = require("@bitgo/statics");
const sdk_core_1 = require("@bitgo/sdk-core");
describe('ETH-like coins', () => {
    _.forEach(['tetc', 'tcelo', 'trbtc'], (coinName) => {
        describe(`${coinName}`, () => {
            let bitgo;
            let basecoin;
            let coin;
            const sendMultisigTypes = ['address', 'uint256', 'bytes', 'uint256', 'uint256', 'bytes'];
            const sendMultisigTokenTypes = ['address', 'uint256', 'address', 'uint256', 'uint256', 'bytes'];
            const signatureSaltMap = {
                native: {
                    tetc: 'ETC',
                    tcelo: 'CELO',
                    trbtc: 'RSK',
                },
                token: {
                    tetc: 'ETC-ERC20',
                    tcelo: 'CELO-ERC20',
                    trbtc: 'RSK-ERC20',
                },
            };
            /**
             * Get the operation hash that the user key signed
             * @param tx The transaction to calculate operatino hash from
             * @return The operation hash
             */
            const getOperationHash = (tx) => {
                const { data } = tx.toJson();
                const { tokenContractAddress, expireTime, sequenceId, amount, to } = account_lib_1.Eth.Utils.decodeTransferData(data);
                if (coin instanceof statics_1.ContractAddressDefinedToken) {
                    return ethAbi.soliditySHA3(...[
                        ['string', 'address', 'uint', 'address', 'uint', 'uint'],
                        [
                            signatureSaltMap.token[coinName],
                            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                            // @ts-ignore BG-34579: known compatibility issue with @types/ethereumjs-util
                            new ethUtil.BN(ethUtil.stripHexPrefix(to), 16),
                            amount,
                            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                            // @ts-ignore BG-34579: known compatibility issue with @types/ethereumjs-util
                            new ethUtil.BN(ethUtil.stripHexPrefix(tokenContractAddress), 16),
                            expireTime,
                            sequenceId,
                        ],
                    ]);
                }
                else {
                    return ethAbi.soliditySHA3(...[
                        ['string', 'address', 'uint', 'uint', 'uint'],
                        [
                            signatureSaltMap.native[coinName],
                            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                            // @ts-ignore BG-34579: known compatibility issue with @types/ethereumjs-util
                            new ethUtil.BN(ethUtil.stripHexPrefix(to), 16),
                            amount,
                            expireTime,
                            sequenceId,
                        ],
                    ]);
                }
            };
            /**
             * Recover the signing address of a signature
             * @param tx The transaction to recover a signer from
             * @return The eth address of the signer
             */
            const recoverSigner = function (tx) {
                const { signature } = account_lib_1.Eth.Utils.decodeTransferData(tx.toJson().data);
                const { v, r, s } = ethUtil.fromRpcSig(signature);
                const operationHash = getOperationHash(tx);
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore known compatibility issue with @types/ethereumjs-util
                const pubKeyBuffer = ethUtil.ecrecover(operationHash, v, r, s);
                return ethUtil.bufferToHex(ethUtil.pubToAddress(ethUtil.importPublic(pubKeyBuffer)));
            };
            /**
             * 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', }) {
                const txBuilder = (0, account_lib_1.getBuilder)(coinName);
                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(coinName)
                    .expirationTime(expireTime)
                    .amount(amount)
                    .to(destination)
                    .contractSequenceId(contractSequenceId);
                return await txBuilder.build();
            };
            before(function () {
                bitgo = sdk_test_1.TestBitGo.decorate(bitgo_1.BitGo, { env: 'mock' });
                bitgo.initializeTestVars();
                basecoin = bitgo.coin(coinName);
                coin = statics_1.coins.get(coinName);
            });
            describe('Is valid address', () => {
                it('Should find valid addresses to be valid', () => {
                    basecoin.isValidAddress('0x2af9152fc4afd89a8124731bdfb8710c8751f3ed').should.equal(true);
                    basecoin.isValidAddress('0x2af9152FC4afd89A8124731BdFb8710c8751f3eD').should.equal(true);
                });
                it('Should find invalid addresses to be invalid', () => {
                    basecoin.isValidAddress('0x2af9152fc4afd89a8124731bdfb8710c8751f3edd').should.equal(false);
                    basecoin.isValidAddress('0x2af9152fc4afd89a8124731bdfb8710c8751f3e').should.equal(false);
                    basecoin.isValidAddress('2af9152fc4afd89a8124731bdfb8710c8751f3ed').should.equal(false);
                    basecoin.isValidAddress('notanaddress').should.equal(false);
                    basecoin.isValidAddress('not an address').should.equal(false);
                    basecoin.isValidAddress('3KgL6DTUb6gEoqSwMMJzyf96ekH8oZtWtZ').should.equal(false);
                });
                xit('Should not throw when verifying valid addresses', function () {
                    // FIXME(BG-43225): not implemented
                });
                xit('Should throw when verifying invalid addresses', function () {
                    // FIXME(BG-43225): not implemented
                });
            });
            describe('Is valid pub', () => {
                it('Should find valid pubs to be valid', () => {
                    basecoin
                        .isValidPub('xpub661MyMwAqRbcF9Nc7TbBo1rZAagiWEVPWKbDKThNG8zqjk76HAKLkaSbTn6dK2dQPfuD7xjicxCZVWvj67fP5nQ9W7QURmoMVAX8m6jZsGp')
                        .should.equal(true);
                    basecoin
                        .isValidPub('04614C070C6D1C18A6A2D6EE2BBBE1FF291A0ABA8ED6B55023C03BE42583AC23A743BCB5EF9DB59E14FD7025A9A5D93C6BA89EEFEB40215BF24933D4F2935D14CB')
                        .should.equal(true);
                    basecoin.isValidPub('034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa').should.equal(true);
                });
                it('Should find invalid pubs to be invalid', () => {
                    basecoin.isValidPub('0x2af9152fc4afd89a8124731bdfb8710c8751f3e').should.equal(false);
                    basecoin.isValidPub('0x2af9152fc4afd89a8124731bdfb8710c8751f3ed').should.equal(false);
                    basecoin.isValidPub('2af9152fc4afd89a8124731bdfb8710c8751f3ed').should.equal(false);
                    basecoin.isValidPub('notapub').should.equal(false);
                    basecoin.isValidPub('not a pub').should.equal(false);
                    basecoin.isValidPub('3KgL6DTUb6gEoqSwMMJzyf96ekH8oZtWtZ').should.equal(false);
                });
            });
            describe('Generate keypair', () => {
                it('Should generate valid keypair without seed', () => {
                    const { pub, prv } = basecoin.generateKeyPair();
                    basecoin.isValidPub(pub).should.equal(true);
                    const bitgoKey = utxo_lib_1.bip32.fromBase58(prv);
                    basecoin.isValidPub(bitgoKey.neutered().toBase58()).should.equal(true);
                });
                it('Should generate valid keypair with seed', () => {
                    const seed = Buffer.from('c3b09c24731be2851b641d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex');
                    const { pub, prv } = basecoin.generateKeyPair(seed);
                    basecoin.isValidPub(pub).should.equal(true);
                    const bitgoKey = utxo_lib_1.bip32.fromBase58(prv);
                    basecoin.isValidPub(bitgoKey.neutered().toBase58()).should.equal(true);
                });
            });
            describe('Sign transaction:', () => {
                const xprv = 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2';
                it('should sign transaction internally', async function () {
                    const key = new account_lib_1.Eth.KeyPair({ prv: xprv });
                    const destination = '0xfaa8f14f46a99eb439c50e0c3b835cc21dad51b4';
                    const contractAddress = '0x9e2c5712ab4caf402a98c4bf58c79a0dfe718ad1';
                    const amount = '100000';
                    const inputExpireTime = Math.floor(new Date().getTime() / 1000);
                    const inputSequenceId = 1;
                    const unsignedTransaction = await buildUnsignedTransaction({
                        destination,
                        contractAddress,
                        amount,
                        expireTime: inputExpireTime,
                        contractSequenceId: inputSequenceId,
                    });
                    const tx = await basecoin.signTransaction({
                        prv: key.getKeys().prv,
                        txPrebuild: {
                            txHex: unsignedTransaction.toBroadcastFormat(),
                        },
                    });
                    const txBuilder = basecoin.getTransactionBuilder();
                    txBuilder.from(tx.halfSigned.txHex);
                    const transaction = await txBuilder.build();
                    const txJson = transaction.toJson();
                    txJson.to.should.equal(contractAddress);
                    let decodedData;
                    let recipient;
                    let value;
                    let data;
                    let expireTime;
                    let sequenceId;
                    if (coin instanceof statics_1.ContractAddressDefinedToken) {
                        decodedData = ethAbi.rawDecode(sendMultisigTokenTypes, Buffer.from(txJson.data.slice(10), 'hex'));
                        [recipient, value /* tokenContractAddress */, , expireTime, sequenceId] = decodedData;
                        data = Buffer.from('');
                    }
                    else {
                        decodedData = ethAbi.rawDecode(sendMultisigTypes, Buffer.from(txJson.data.slice(10), 'hex'));
                        [recipient, value, data, expireTime, sequenceId] = decodedData;
                    }
                    ethUtil.addHexPrefix(recipient).should.equal(destination);
                    value.toString(10).should.equal(amount);
                    inputExpireTime.should.equal(parseInt(expireTime.toString('hex'), 16));
                    inputSequenceId.should.equal(parseInt(sequenceId.toString('hex'), 16));
                    data.length.should.equal(0);
                    const recoveredAddress = recoverSigner(transaction);
                    recoveredAddress.should.equal(key.getAddress());
                });
                it('should sign transaction internally with an xprv', async function () {
                    const key = new account_lib_1.Eth.KeyPair({ prv: xprv });
                    const destination = '0xfaa8f14f46a99eb439c50e0c3b835cc21dad51b4';
                    const contractAddress = '0x9e2c5712ab4caf402a98c4bf58c79a0dfe718ad1';
                    const amount = '100000';
                    const inputExpireTime = Math.floor(new Date().getTime() / 1000);
                    const inputSequenceId = 1;
                    const unsignedTransaction = await buildUnsignedTransaction({
                        destination,
                        contractAddress,
                        amount,
                        expireTime: inputExpireTime,
                        contractSequenceId: inputSequenceId,
                    });
                    const tx = await basecoin.signTransaction({
                        prv: xprv,
                        txPrebuild: {
                            txHex: unsignedTransaction.toBroadcastFormat(),
                        },
                    });
                    const txBuilder = basecoin.getTransactionBuilder();
                    txBuilder.from(tx.halfSigned.txHex);
                    const transaction = await txBuilder.build();
                    const txJson = transaction.toJson();
                    txJson.to.should.equal(contractAddress);
                    let decodedData;
                    let recipient;
                    let value;
                    let data;
                    let expireTime;
                    let sequenceId;
                    if (coin instanceof statics_1.ContractAddressDefinedToken) {
                        decodedData = ethAbi.rawDecode(sendMultisigTokenTypes, Buffer.from(txJson.data.slice(10), 'hex'));
                        [recipient, value /* tokenContractAddress */, , expireTime, sequenceId] = decodedData;
                        data = Buffer.from('');
                    }
                    else {
                        decodedData = ethAbi.rawDecode(sendMultisigTypes, Buffer.from(txJson.data.slice(10), 'hex'));
                        [recipient, value, data, expireTime, sequenceId] = decodedData;
                    }
                    ethUtil.addHexPrefix(recipient).should.equal(destination);
                    value.toString(10).should.equal(amount);
                    inputExpireTime.should.equal(parseInt(expireTime.toString('hex'), 16));
                    inputSequenceId.should.equal(parseInt(sequenceId.toString('hex'), 16));
                    data.length.should.equal(0);
                    const recoveredAddress = recoverSigner(transaction);
                    recoveredAddress.should.equal(key.getAddress());
                });
                it('should sign a half signed transaction', async function () {
                    const key = new account_lib_1.Eth.KeyPair({ prv: xprv });
                    const destination = '0xfaa8f14f46a99eb439c50e0c3b835cc21dad51b4';
                    const contractAddress = '0x9e2c5712ab4caf402a98c4bf58c79a0dfe718ad1';
                    const amount = '100000';
                    const inputExpireTime = Math.floor(new Date().getTime() / 1000);
                    const inputSequenceId = 1;
                    const unsignedTransaction = await buildUnsignedTransaction({
                        destination,
                        contractAddress,
                        amount,
                        expireTime: inputExpireTime,
                        contractSequenceId: inputSequenceId,
                    });
                    const tx = await basecoin.signTransaction({
                        prv: key.getKeys().prv,
                        txPrebuild: {
                            txHex: unsignedTransaction.toBroadcastFormat(),
                        },
                    });
                    const fullySignedTx = await basecoin.signTransaction({
                        prv: key.getKeys().prv,
                        txPrebuild: {
                            txHex: tx.halfSigned.txHex,
                        },
                    });
                    fullySignedTx.halfSigned.recipients.length.should.equal(1);
                    fullySignedTx.halfSigned.recipients[0].address.should.equal(destination);
                    fullySignedTx.halfSigned.recipients[0].amount.should.equal(amount);
                    const txBuilder = basecoin.getTransactionBuilder();
                    txBuilder.from(fullySignedTx.halfSigned.txHex);
                    const transaction = await txBuilder.build();
                    const txJson = transaction.toJson();
                    txJson.to.should.equal(contractAddress);
                    let decodedData;
                    let recipient;
                    let value;
                    let data;
                    let expireTime;
                    let sequenceId;
                    if (coin instanceof statics_1.ContractAddressDefinedToken) {
                        decodedData = ethAbi.rawDecode(sendMultisigTokenTypes, Buffer.from(txJson.data.slice(10), 'hex'));
                        [recipient, value /* tokenContractAddress */, , expireTime, sequenceId] = decodedData;
                        data = Buffer.from('');
                    }
                    else {
                        decodedData = ethAbi.rawDecode(sendMultisigTypes, Buffer.from(txJson.data.slice(10), 'hex'));
                        [recipient, value, data, expireTime, sequenceId] = decodedData;
                    }
                    ethUtil.addHexPrefix(recipient).should.equal(destination);
                    value.toString(10).should.equal(amount);
                    inputExpireTime.should.equal(parseInt(expireTime.toString('hex'), 16));
                    inputSequenceId.should.equal(parseInt(sequenceId.toString('hex'), 16));
                    data.length.should.equal(0);
                    const recoveredAddress = recoverSigner(transaction);
                    recoveredAddress.should.equal(key.getAddress());
                });
                it('should fail to sign transaction with invalid tx hex', async function () {
                    const key = new account_lib_1.Eth.KeyPair({ prv: xprv });
                    await basecoin
                        .signTransaction({
                        prv: key.getKeys().prv,
                        txPrebuild: {
                            txHex: '0xinvalid',
                        },
                    })
                        .should.be.rejected();
                });
            });
            describe('Explain transaction:', () => {
                const xprv = 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2';
                it('should fail if the params object is missing parameters', async function () {
                    const explainParams = {
                        feeInfo: { fee: 1 },
                        txHex: null,
                    };
                    await basecoin.explainTransaction(explainParams).should.be.rejectedWith('missing explain tx parameters');
                });
                it('explain an unsigned transfer transaction', async function () {
                    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);
                    // TODO check other fields once account-lib properly explains transaction
                });
                it('explain a signed transfer transaction', async function () {
                    const key = new account_lib_1.Eth.KeyPair({ prv: xprv });
                    const destination = '0xfaa8f14f46a99eb439c50e0c3b835cc21dad51b4';
                    const contractAddress = '0x9e2c5712ab4caf402a98c4bf58c79a0dfe718ad1';
                    const unsignedTransaction = await buildUnsignedTransaction({
                        destination,
                        contractAddress,
                    });
                    const signedTx = await basecoin.signTransaction({
                        prv: key.getKeys().prv,
                        txPrebuild: {
                            txHex: unsignedTransaction.toBroadcastFormat(),
                        },
                    });
                    const explainParams = {
                        txHex: signedTx.halfSigned.txHex,
                        feeInfo: { fee: 1 },
                    };
                    const explanation = await basecoin.explainTransaction(explainParams);
                    should.exist(explanation.id);
                    // TODO check other fields once account-lib properly explains transaction
                });
            });
        });
    });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3RFdGhDb2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2NvaW5zL2Fic3RyYWN0RXRoQ29pbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7O0FBRUgsNEJBQTRCO0FBQzVCLGlDQUFrQztBQUNsQyw4Q0FBd0M7QUFDeEMsOENBQTRDO0FBQzVDLGlEQUE4QztBQUM5QyxvREFBcUQ7QUFDckQseUNBQXlDO0FBQ3pDLDJDQUEyQztBQUMzQyw0Q0FBb0U7QUFDcEUsOENBQW1FO0FBRW5FLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLEVBQUU7SUFDOUIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRTtRQUNqRCxRQUFRLENBQUMsR0FBRyxRQUFRLEVBQUUsRUFBRSxHQUFHLEVBQUU7WUFDM0IsSUFBSSxLQUFLLENBQUM7WUFDVixJQUFJLFFBQVEsQ0FBQztZQUNiLElBQUksSUFBSSxDQUFDO1lBRVQsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDekYsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDaEcsTUFBTSxnQkFBZ0IsR0FBRztnQkFDdkIsTUFBTSxFQUFFO29CQUNOLElBQUksRUFBRSxLQUFLO29CQUNYLEtBQUssRUFBRSxNQUFNO29CQUNiLEtBQUssRUFBRSxLQUFLO2lCQUNiO2dCQUNELEtBQUssRUFBRTtvQkFDTCxJQUFJLEVBQUUsV0FBVztvQkFDakIsS0FBSyxFQUFFLFlBQVk7b0JBQ25CLEtBQUssRUFBRSxXQUFXO2lCQUNu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SUFBSSxpQkFBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUMzQyxNQUFNLFdBQVcsR0FBRyw0Q0FBNEMsQ0FBQztvQkFDakUsTUFBTSxlQUFlLEdBQUcsNENBQTRDLENBQUM7b0JBRXJFLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSx3QkFBd0IsQ0FBQzt3QkFDekQsV0FBVzt3QkFDWCxlQUFlO3FCQUNoQixDQUFDLENBQUM7b0JBRUgsTUFBTSxRQUFRLEdBQUcsTUFBTSxRQUFRLENBQUMsZUFBZSxDQUFDO3dCQUM5QyxHQUFHLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUc7d0JBQ3RCLFVBQVUsRUFBRTs0QkFDVixLQUFLLEVBQUUsbUJBQW1CLENBQUMsaUJBQWlCLEVBQUU7eUJBQy9DO3FCQUNGLENBQUMsQ0FBQztvQkFFSCxNQUFNLGFBQWEsR0FBRzt3QkFDcEIsS0FBSyxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsS0FBSzt3QkFDaEMsT0FBTyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRTtxQkFDcEIsQ0FBQztvQkFDRixNQUFNLFdBQVcsR0FBRyxNQUFNLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFDckUsTUFBTSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQzdCLHlFQUF5RTtnQkFDM0UsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQHByZXR0aWVyXG4gKi9cblxuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHNob3VsZCA9IHJlcXVpcmUoJ3Nob3VsZCcpO1xuaW1wb3J0IHsgYmlwMzIgfSBmcm9tICdAYml0Z28vdXR4by1saWInO1xuaW1wb3J0IHsgVGVzdEJpdEdvIH0gZnJvbSAnQGJpdGdvL3Nkay10ZXN0JztcbmltcG9ydCB7IEJpdEdvIH0gZnJvbSAnLi4vLi4vLi4vLi4vc3JjL2JpdGdvJztcbmltcG9ydCB7IGdldEJ1aWxkZXIsIEV0aCB9IGZyb20gJ0BiaXRnby9hY2NvdW50LWxpYic7XG5pbXBvcnQgKiBhcyBldGhBYmkgZnJvbSAnZXRoZXJldW1qcy1hYmknO1xuaW1wb3J0ICogYXMgZXRoVXRpbCBmcm9tICdldGhlcmV1bWpzLXV0aWwnO1xuaW1wb3J0IHsgY29pbnMsIENvbnRyYWN0QWRkcmVzc0RlZmluZWRUb2tlbiB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcbmltcG9ydCB7IEJhc2VUcmFuc2FjdGlvbiwgVHJhbnNhY3Rpb25UeXBlIH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcblxuZGVzY3JpYmUoJ0VUSC1saWtlIGNvaW5zJywgKCkgPT4ge1xuICBfLmZvckVhY2goWyd0ZXRjJywgJ3RjZWxvJywgJ3RyYnRjJ10sIChjb2luTmFtZSkgPT4ge1xuICAgIGRlc2NyaWJlKGAke2NvaW5OYW1lfWAsICgpID0+IHtcbiAgICAgIGxldCBiaXRnbztcbiAgICAgIGxldCBiYXNlY29pbjtcbiAgICAgIGxldCBjb2luO1xuXG4gICAgICBjb25zdCBzZW5kTXVsdGlzaWdUeXBlcyA9IFsnYWRkcmVzcycsICd1aW50MjU2JywgJ2J5dGVzJywgJ3VpbnQyNTYnLCAndWludDI1NicsICdieXRlcyddO1xuICAgICAgY29uc3Qgc2VuZE11bHRpc2lnVG9rZW5UeXBlcyA9IFsnYWRkcmVzcycsICd1aW50MjU2JywgJ2FkZHJlc3MnLCAndWludDI1NicsICd1aW50MjU2JywgJ2J5dGVzJ107XG4gICAgICBjb25zdCBzaWduYXR1cmVTYWx0TWFwID0ge1xuICAgICAgICBuYXRpdmU6IHtcbiAgICAgICAgICB0ZXRjOiAnRVRDJyxcbiAgICAgICAgICB0Y2VsbzogJ0NFTE8nLFxuICAgICAgICAgIHRyYnRjOiAnUlNLJyxcbiAgICAgICAgfSxcbiAgICAgICAgdG9rZW46IHtcbiAgICAgICAgICB0ZXRjOiAnRVRDLUVSQzIwJyxcbiAgICAgICAgICB0Y2VsbzogJ0NFTE8tRVJDMjAnLFxuICAgICAgICAgIHRyYnRjOiAnUlNLLUVSQzIwJyxcbiAgICAgICAgfSxcbiAgICAgIH07XG5cbiAgICAgIC8qKlxuICAgICAgICogR2V0IHRoZSBvcGVyYXRpb24gaGFzaCB0aGF0IHRoZSB1c2VyIGtleSBzaWduZWRcbiAgICAgICAqIEBwYXJhbSB0eCBUaGUgdHJhbnNhY3Rpb24gdG8gY2FsY3VsYXRlIG9wZXJhdGlubyBoYXNoIGZyb21cbiAgICAgICAqIEByZXR1cm4gVGhlIG9wZXJhdGlvbiBoYXNoXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IGdldE9wZXJhdGlvbkhhc2ggPSAodHg6IEJhc2VUcmFuc2FjdGlvbik6IHN0cmluZyA9PiB7XG4gICAgICAgIGNvbnN0IHsgZGF0YSB9ID0gdHgudG9Kc29uKCk7XG4gICAgICAgIGNvbnN0IHsgdG9rZW5Db250cmFjdEFkZHJlc3MsIGV4cGlyZVRpbWUsIHNlcXVlbmNlSWQsIGFtb3VudCwgdG8gfSA9IEV0aC5VdGlscy5kZWNvZGVUcmFuc2ZlckRhdGEoZGF0YSk7XG5cbiAgICAgICAgaWYgKGNvaW4gaW5zdGFuY2VvZiBDb250cmFjdEFkZHJlc3NEZWZpbmVkVG9rZW4pIHtcbiAgICAgICAgICByZXR1cm4gZXRoQWJpLnNvbGlkaXR5U0hBMyhcbiAgICAgICAgICAgIC4uLltcbiAgICAgICAgICAgICAgWydzdHJpbmcnLCAnYWRkcmVzcycsICd1aW50JywgJ2FkZHJlc3MnLCAndWludCcsICd1aW50J10sXG4gICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICBzaWduYXR1cmVTYWx0TWFwLnRva2VuW2NvaW5OYW1lXSxcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50XG4gICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZSBCRy0zNDU3OToga25vd24gY29tcGF0aWJpbGl0eSBpc3N1ZSB3aXRoIEB0eXBlcy9ldGhlcmV1bWpzLXV0aWxcbiAgICAgICAgICAgICAgICBuZXcgZXRoVXRpbC5CTihldGhVdGlsLnN0cmlwSGV4UHJlZml4KHRvKSwgMTYpLFxuICAgICAgICAgICAgICAgIGFtb3VudCxcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50XG4gICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZSBCRy0zNDU3OToga25vd24gY29tcGF0aWJpbGl0eSBpc3N1ZSB3aXRoIEB0eXBlcy9ldGhlcmV1bWpzLXV0aWxcbiAgICAgICAgICAgICAgICBuZXcgZXRoVXRpbC5CTihldGhVdGlsLnN0cmlwSGV4UHJlZml4KHRva2VuQ29udHJhY3RBZGRyZXNzKSwgMTYpLFxuICAgICAgICAgICAgICAgIGV4cGlyZVRpbWUsXG4gICAgICAgICAgICAgICAgc2VxdWVuY2VJZCxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIF1cbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBldGhBYmkuc29saWRpdHlTSEEzKFxuICAgICAgICAgICAgLi4uW1xuICAgICAgICAgICAgICBbJ3N0cmluZycsICdhZGRyZXNzJywgJ3VpbnQnLCAndWludCcsICd1aW50J10sXG4gICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICBzaWduYXR1cmVTYWx0TWFwLm5hdGl2ZVtjb2luTmFtZV0sXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9iYW4tdHMtY29tbWVudFxuICAgICAgICAgICAgICAgIC8vIEB0cy1pZ25vcmUgQkctMzQ1Nzk6IGtub3duIGNvbXBhdGliaWxpdHkgaXNzdWUgd2l0aCBAdHlwZXMvZXRoZXJldW1qcy11dGlsXG4gICAgICAgICAgICAgICAgbmV3IGV0aFV0aWwuQk4oZXRoVXRpbC5zdHJpcEhleFByZWZpeCh0byksIDE2KSxcbiAgICAgICAgICAgICAgICBhbW91bnQsXG4gICAgICAgICAgICAgICAgZXhwaXJlVGltZSxcbiAgICAgICAgICAgICAgICBzZXF1ZW5jZUlkLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgXVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIC8qKlxuICAgICAgICogUmVjb3ZlciB0aGUgc2lnbmluZyBhZGRyZXNzIG9mIGEgc2lnbmF0dXJlXG4gICAgICAgKiBAcGFyYW0gdHggVGhlIHRyYW5zYWN0aW9uIHRvIHJlY292ZXIgYSBzaWduZXIgZnJvbVxuICAgICAgICogQHJldHVybiBUaGUgZXRoIGFkZHJlc3Mgb2YgdGhlIHNpZ25lclxuICAgICAgICovXG4gICAgICBjb25zdCByZWNvdmVyU2lnbmVyID0gZnVuY3Rpb24gKHR4OiBCYXNlVHJhbnNhY3Rpb24pIHtcbiAgICAgICAgY29uc3QgeyBzaWduYXR1cmUgfSA9IEV0aC5VdGlscy5kZWNvZGVUcmFuc2ZlckRhdGEodHgudG9Kc29uKCkuZGF0YSk7XG4gICAgICAgIGNvbnN0IHsgdiwgciwgcyB9ID0gZXRoVXRpbC5mcm9tUnBjU2lnKHNpZ25hdHVyZSk7XG4gICAgICAgIGNvbnN0IG9wZXJhdGlvbkhhc2ggPSBnZXRPcGVyYXRpb25IYXNoKHR4KTtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9iYW4tdHMtY29tbWVudFxuICAgICAgICAvLyBAdHMtaWdub3JlIGtub3duIGNvbXBhdGliaWxpdHkgaXNzdWUgd2l0aCBAdHlwZXMvZXRoZXJldW1qcy11dGlsXG4gICAgICAgIGNvbnN0IHB1YktleUJ1ZmZlciA9IGV0aFV0aWwuZWNyZWNvdmVyKG9wZXJhdGlvbkhhc2gsIHYsIHIsIHMpO1xuICAgICAgICByZXR1cm4gZXRoVXRpbC5idWZmZXJUb0hleChldGhVdGlsLnB1YlRvQWRkcmVzcyhldGhVdGlsLmltcG9ydFB1YmxpYyhwdWJLZXlCdWZmZXIpKSk7XG4gICAgICB9O1xuXG4gICAgICAvKipcbiAgICAgICAqIEJ1aWxkIGFuIHVuc2lnbmVkIGFjY291bnQtbGliIG11bHRpLXNpZ25hdHVyZSBzZW5kIHRyYW5zYWN0aW5vXG4gICAgICAgKiBAcGFyYW0gZGVzdGluYXRpb24gVGhlIGRlc3RpbmF0aW9uIGFkZHJlc3Mgb2YgdGhlIHRyYW5zYWN0aW9uXG4gICAgICAgKiBAcGFyYW0gY29udHJhY3RBZGRyZXNzIFRoZSBhZGRyZXNzIG9mIHRoZSBzbWFydCBjb250cmFjdCBwcm9jZXNzaW5nIHRoZSB0cmFuc2FjdGlvblxuICAgICAgICogQHBhcmFtIGNvbnRyYWN0U2VxdWVuY2VJZCBUaGUgc2VxdWVuY2UgaWQgb2YgdGhlIGNvbnRyYWN0XG4gICAgICAgKiBAcGFyYW0gbm9uY2UgVGhlIG5vbmNlIG9mIHRoZSBzZW5kaW5nIGFkZHJlc3NcbiAgICAgICAqIEBwYXJhbSBleHBpcmVUaW1lIFRoZSBleHBpcmUgdGltZSBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICAgICAqIEBwYXJhbSBhbW91bnQgVGhlIGFtb3VudCB0byBzZW5kIHRvIHRoZSByZWNpcGllbnRcbiAgICAgICAqIEBwYXJhbSBnYXNQcmljZSBUaGUgZ2FzIHByaWNlIG9mIHRoZSB0cmFuc2FjdGlvblxuICAgICAgICogQHBhcmFtIGdhc0xpbWl0IFRoZSBnYXMgbGltaXQgb2YgdGhlIHRyYW5zYWN0aW9uXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IGJ1aWxkVW5zaWduZWRUcmFuc2FjdGlvbiA9IGFzeW5jIGZ1bmN0aW9uICh7XG4gICAgICAgIGRlc3RpbmF0aW9uLFxuICAgICAgICBjb250cmFjdEFkZHJlc3MsXG4gICAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZCA9IDEsXG4gICAgICAgIG5vbmNlID0gMCxcbiAgICAgICAgZXhwaXJlVGltZSA9IE1hdGguZmxvb3IobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwKSxcbiAgICAgICAgYW1vdW50ID0gJzEwMDAwMCcsXG4gICAgICAgIGdhc1ByaWNlID0gJzEwMDAwJyxcbiAgICAgICAgZ2FzTGltaXQgPSAnMjAwMDAnLFxuICAgICAgfSkge1xuICAgICAgICBjb25zdCB0eEJ1aWxkZXI6IEV0aC5UcmFuc2FjdGlvbkJ1aWxkZXIgPSBnZXRCdWlsZGVyKGNvaW5OYW1lKSBhcyBFdGguVHJhbnNhY3Rpb25CdWlsZGVyO1xuICAgICAgICB0eEJ1aWxkZXIudHlwZShUcmFuc2FjdGlvblR5cGUuU2VuZCk7XG4gICAgICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgICAgIGZlZTogZ2FzUHJpY2UsXG4gICAgICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LFxuICAgICAgICB9KTtcbiAgICAgICAgdHhCdWlsZGVyLmNvdW50ZXIobm9uY2UpO1xuICAgICAgICB0eEJ1aWxkZXIuY29udHJhY3QoY29udHJhY3RBZGRyZXNzKTtcbiAgICAgICAgY29uc3QgdHJhbnNmZXJCdWlsZGVyID0gdHhCdWlsZGVyLnRyYW5zZmVyKCkgYXMgRXRoLlRyYW5zZmVyQnVpbGRlcjtcblxuICAgICAgICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAgICAgICAuY29pbihjb2luTmFtZSlcbiAgICAgICAgICAuZXhwaXJhdGlvblRpbWUoZXhwaXJlVGltZSlcbiAgICAgICAgICAuYW1vdW50KGFtb3VudClcbiAgICAgICAgICAudG8oZGVzdGluYXRpb24pXG4gICAgICAgICAgLmNvbnRyYWN0U2VxdWVuY2VJZChjb250cmFjdFNlcXVlbmNlSWQpO1xuXG4gICAgICAgIHJldHVybiBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIH07XG5cbiAgICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvLCB7IGVudjogJ21vY2snIH0pO1xuICAgICAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICAgICAgYmFzZWNvaW4gPSBiaXRnby5jb2luKGNvaW5OYW1lKTtcbiAgICAgICAgY29pbiA9IGNvaW5zLmdldChjb2luTmFtZSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoJ0lzIHZhbGlkIGFkZHJlc3MnLCAoKSA9PiB7XG4gICAgICAgIGl0KCdTaG91bGQgZmluZCB2YWxpZCBhZGRyZXNzZXMgdG8gYmUgdmFsaWQnLCAoKSA9PiB7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZEFkZHJlc3MoJzB4MmFmOTE1MmZjNGFmZDg5YTgxMjQ3MzFiZGZiODcxMGM4NzUxZjNlZCcpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnMHgyYWY5MTUyRkM0YWZkODlBODEyNDczMUJkRmI4NzEwYzg3NTFmM2VEJykuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnU2hvdWxkIGZpbmQgaW52YWxpZCBhZGRyZXNzZXMgdG8gYmUgaW52YWxpZCcsICgpID0+IHtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnMHgyYWY5MTUyZmM0YWZkODlhODEyNDczMWJkZmI4NzEwYzg3NTFmM2VkZCcpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZEFkZHJlc3MoJzB4MmFmOTE1MmZjNGFmZDg5YTgxMjQ3MzFiZGZiODcxMGM4NzUxZjNlJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnMmFmOTE1MmZjNGFmZDg5YTgxMjQ3MzFiZGZiODcxMGM4NzUxZjNlZCcpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZEFkZHJlc3MoJ25vdGFuYWRkcmVzcycpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZEFkZHJlc3MoJ25vdCBhbiBhZGRyZXNzJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnM0tnTDZEVFViNmdFb3FTd01NSnp5Zjk2ZWtIOG9adFd0WicpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHhpdCgnU2hvdWxkIG5vdCB0aHJvdyB3aGVuIHZlcmlmeWluZyB2YWxpZCBhZGRyZXNzZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgLy8gRklYTUUoQkctNDMyMjUpOiBub3QgaW1wbGVtZW50ZWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgeGl0KCdTaG91bGQgdGhyb3cgd2hlbiB2ZXJpZnlpbmcgaW52YWxpZCBhZGRyZXNzZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgLy8gRklYTUUoQkctNDMyMjUpOiBub3QgaW1wbGVtZW50ZWRcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoJ0lzIHZhbGlkIHB1YicsICgpID0+IHtcbiAgICAgICAgaXQoJ1Nob3VsZCBmaW5kIHZhbGlkIHB1YnMgdG8gYmUgdmFsaWQnLCAoKSA9PiB7XG4gICAgICAgICAgYmFzZWNvaW5cbiAgICAgICAgICAgIC5pc1ZhbGlkUHViKFxuICAgICAgICAgICAgICAneHB1YjY2MU15TXdBcVJiY0Y5TmM3VGJCbzFyWkFhZ2lXRVZQV0tiREtUaE5HOHpxams3NkhBS0xrYVNiVG42ZEsyZFFQZnVEN3hqaWN4Q1pWV3ZqNjdmUDVuUTlXN1FVUm1vTVZBWDhtNmpac0dwJ1xuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgICAgICBiYXNlY29pblxuICAgICAgICAgICAgLmlzVmFsaWRQdWIoXG4gICAgICAgICAgICAgICcwNDYxNEMwNzBDNkQxQzE4QTZBMkQ2RUUyQkJCRTFGRjI5MUEwQUJBOEVENkI1NTAyM0MwM0JFNDI1ODNBQzIzQTc0M0JDQjVFRjlEQjU5RTE0RkQ3MDI1QTlBNUQ5M0M2QkE4OUVFRkVCNDAyMTVCRjI0OTMzRDRGMjkzNUQxNENCJ1xuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKCcwMzRmMzU1YmRjYjdjYzBhZjcyOGVmM2NjZWI5NjE1ZDkwNjg0YmI1YjJjYTVmODU5YWIwZjBiNzA0MDc1ODcxYWEnKS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdTaG91bGQgZmluZCBpbnZhbGlkIHB1YnMgdG8gYmUgaW52YWxpZCcsICgpID0+IHtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKCcweDJhZjkxNTJmYzRhZmQ4OWE4MTI0NzMxYmRmYjg3MTBjODc1MWYzZScpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZFB1YignMHgyYWY5MTUyZmM0YWZkODlhODEyNDczMWJkZmI4NzEwYzg3NTFmM2VkJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKCcyYWY5MTUyZmM0YWZkODlhODEyNDczMWJkZmI4NzEwYzg3NTFmM2VkJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKCdub3RhcHViJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKCdub3QgYSBwdWInKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoJzNLZ0w2RFRVYjZnRW9xU3dNTUp6eWY5NmVrSDhvWnRXdFonKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnR2VuZXJhdGUga2V5cGFpcicsICgpID0+IHtcbiAgICAgICAgaXQoJ1Nob3VsZCBnZW5lcmF0ZSB2YWxpZCBrZXlwYWlyIHdpdGhvdXQgc2VlZCcsICgpID0+IHtcbiAgICAgICAgICBjb25zdCB7IHB1YiwgcHJ2IH0gPSBiYXNlY29pbi5nZW5lcmF0ZUtleVBhaXIoKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKHB1Yikuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgICAgIGNvbnN0IGJpdGdvS2V5ID0gYmlwMzIuZnJvbUJhc2U1OChwcnYpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoYml0Z29LZXkubmV1dGVyZWQoKS50b0Jhc2U1OCgpKS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdTaG91bGQgZ2VuZXJhdGUgdmFsaWQga2V5cGFpciB3aXRoIHNlZWQnLCAoKSA9PiB7XG4gICAgICAgICAgY29uc3Qgc2VlZCA9IEJ1ZmZlci5mcm9tKCdjM2IwOWMyNDczMWJlMjg1MWI2NDFkOWQ1YjNmNjBmYTEyOTY5NWMyNDA3MTc2OGQxNTY1NGJlYTIwN2I3YmI2JywgJ2hleCcpO1xuICAgICAgICAgIGNvbnN0IHsgcHViLCBwcnYgfSA9IGJhc2Vjb2luLmdlbmVyYXRlS2V5UGFpcihzZWVkKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKHB1Yikuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgICAgIGNvbnN0IGJpdGdvS2V5ID0gYmlwMzIuZnJvbUJhc2U1OChwcnYpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoYml0Z29LZXkubmV1dGVyZWQoKS50b0Jhc2U1OCgpKS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCdTaWduIHRyYW5zYWN0aW9uOicsICgpID0+IHtcbiAgICAgICAgY29uc3QgeHBydiA9XG4gICAgICAgICAgJ3hwcnY5czIxWnJRSDE0M0szRDhUWGZ2QUpnSFZmVEVlUU5XNVlzOXdadG5VWmtxUHpGelNqYkVKcldDMXZaNEduWEN2UjdyUUwyVUZYM1JTdVllVTlNckVSbTFYQnZBQ293N2MzNnZuejVpWXlqMic7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBzaWduIHRyYW5zYWN0aW9uIGludGVybmFsbHknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3Qga2V5ID0gbmV3IEV0aC5LZXlQYWlyKHsgcHJ2OiB4cHJ2IH0pO1xuICAgICAgICAgIGNvbnN0IGRlc3RpbmF0aW9uID0gJzB4ZmFhOGYxNGY0NmE5OWViNDM5YzUwZTBjM2I4MzVjYzIxZGFkNTFiNCc7XG4gICAgICAgICAgY29uc3QgY29udHJhY3RBZGRyZXNzID0gJzB4OWUyYzU3MTJhYjRjYWY0MDJhOThjNGJmNThjNzlhMGRmZTcxOGFkMSc7XG4gICAgICAgICAgY29uc3QgYW1vdW50ID0gJzEwMDAwMCc7XG4gICAgICAgICAgY29uc3QgaW5wdXRFeHBpcmVUaW1lID0gTWF0aC5mbG9vcihuZXcgRGF0ZSgpLmdldFRpbWUoKSAvIDEwMDApO1xuICAgICAgICAgIGNvbnN0IGlucHV0U2VxdWVuY2VJZCA9IDE7XG5cbiAgICAgICAgICBjb25zdCB1bnNpZ25lZFRyYW5zYWN0aW9uID0gYXdhaXQgYnVpbGRVbnNpZ25lZFRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgIGRlc3RpbmF0aW9uLFxuICAgICAgICAgICAgY29udHJhY3RBZGRyZXNzLFxuICAgICAgICAgICAgYW1vdW50LFxuICAgICAgICAgICAgZXhwaXJlVGltZTogaW5wdXRFeHBpcmVUaW1lLFxuICAgICAgICAgICAgY29udHJhY3RTZXF1ZW5jZUlkOiBpbnB1dFNlcXVlbmNlSWQsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBjb25zdCB0eCA9IGF3YWl0IGJhc2Vjb2luLnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBwcnY6IGtleS5nZXRLZXlzKCkucHJ2LFxuICAgICAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgICAgICB0eEhleDogdW5zaWduZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGJhc2Vjb2luLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgICAgICAgIHR4QnVpbGRlci5mcm9tKHR4LmhhbGZTaWduZWQudHhIZXgpO1xuICAgICAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgICAgY29uc3QgdHhKc29uID0gdHJhbnNhY3Rpb24udG9Kc29uKCk7XG4gICAgICAgICAgdHhKc29uLnRvLnNob3VsZC5lcXVhbChjb250cmFjdEFkZHJlc3MpO1xuXG4gICAgICAgICAgbGV0IGRlY29kZWREYXRhO1xuICAgICAgICAgIGxldCByZWNpcGllbnQ7XG4gICAgICAgICAgbGV0IHZhbHVlO1xuICAgICAgICAgIGxldCBkYXRhO1xuICAgICAgICAgIGxldCBleHBpcmVUaW1lO1xuICAgICAgICAgIGxldCBzZXF1ZW5jZUlkO1xuICAgICAgICAgIGlmIChjb2luIGluc3RhbmNlb2YgQ29udHJhY3RBZGRyZXNzRGVmaW5lZFRva2VuKSB7XG4gICAgICAgICAgICBkZWNvZGVkRGF0YSA9IGV0aEFiaS5yYXdEZWNvZGUoc2VuZE11bHRpc2lnVG9rZW5UeXBlcywgQnVmZmVyLmZyb20odHhKc29uLmRhdGEuc2xpY2UoMTApLCAnaGV4JykpO1xuICAgICAgICAgICAgW3JlY2lwaWVudCwgdmFsdWUgLyogdG9rZW5Db250cmFjdEFkZHJlc3MgKi8sICwgZXhwaXJlVGltZSwgc2VxdWVuY2VJZF0gPSBkZWNvZGVkRGF0YTtcbiAgICAgICAgICAgIGRhdGEgPSBCdWZmZXIuZnJvbSgnJyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRlY29kZWREYXRhID0gZXRoQWJpLnJhd0RlY29kZShzZW5kTXVsdGlzaWdUeXBlcywgQnVmZmVyLmZyb20odHhKc29uLmRhdGEuc2xpY2UoMTApLCAnaGV4JykpO1xuICAgICAgICAgICAgW3JlY2lwaWVudCwgdmFsdWUsIGRhdGEsIGV4cGlyZVRpbWUsIHNlcXVlbmNlSWRdID0gZGVjb2RlZERhdGE7XG4gICAgICAgICAgfVxuICAgICAgICAgIGV0aFV0aWwuYWRkSGV4UHJlZml4KHJlY2lwaWVudCkuc2hvdWxkLmVxdWFsKGRlc3RpbmF0aW9uKTtcbiAgICAgICAgICB2YWx1ZS50b1N0cmluZygxMCkuc2hvdWxkLmVxdWFsKGFtb3VudCk7XG4gICAgICAgICAgaW5wdXRFeHBpcmVUaW1lLnNob3VsZC5lcXVhbChwYXJzZUludChleHBpcmVUaW1lLnRvU3RyaW5nKCdoZXgnKSwgMTYpKTtcbiAgICAgICAgICBpbnB1dFNlcXVlbmNlSWQuc2hvdWxkLmVxdWFsKHBhcnNlSW50KHNlcXVlbmNlSWQudG9TdHJpbmcoJ2hleCcpLCAxNikpO1xuICAgICAgICAgIGRhdGEubGVuZ3RoLnNob3VsZC5lcXVhbCgwKTtcblxuICAgICAgICAgIGNvbnN0IHJlY292ZXJlZEFkZHJlc3MgPSByZWNvdmVyU2lnbmVyKHRyYW5zYWN0aW9uKTtcbiAgICAgICAgICByZWNvdmVyZWRBZGRyZXNzLnNob3VsZC5lcXVhbChrZXkuZ2V0QWRkcmVzcygpKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBzaWduIHRyYW5zYWN0aW9uIGludGVybmFsbHkgd2l0aCBhbiB4cHJ2JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGtleSA9IG5ldyBFdGguS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgICAgICBjb25zdCBkZXN0aW5hdGlvbiA9ICcweGZhYThmMTRmNDZhOTllYjQzOWM1MGUwYzNiODM1Y2MyMWRhZDUxYjQnO1xuICAgICAgICAgIGNvbnN0IGNvbnRyYWN0QWRkcmVzcyA9ICcweDllMmM1NzEyYWI0Y2FmNDAyYTk4YzRiZjU4Yzc5YTBkZmU3MThhZDEnO1xuICAgICAgICAgIGNvbnN0IGFtb3VudCA9ICcxMDAwMDAnO1xuICAgICAgICAgIGNvbnN0IGlucHV0RXhwaXJlVGltZSA9IE1hdGguZmxvb3IobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwKTtcbiAgICAgICAgICBjb25zdCBpbnB1dFNlcXVlbmNlSWQgPSAxO1xuXG4gICAgICAgICAgY29uc3QgdW5zaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJ1aWxkVW5zaWduZWRUcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBkZXN0aW5hdGlvbixcbiAgICAgICAgICAgIGNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICAgIGFtb3VudCxcbiAgICAgICAgICAgIGV4cGlyZVRpbWU6IGlucHV0RXhwaXJlVGltZSxcbiAgICAgICAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogaW5wdXRTZXF1ZW5jZUlkLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc3QgdHggPSBhd2FpdCBiYXNlY29pbi5zaWduVHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgcHJ2OiB4cHJ2LFxuICAgICAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgICAgICB0eEhleDogdW5zaWduZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGJhc2Vjb2luLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgICAgICAgIHR4QnVpbGRlci5mcm9tKHR4LmhhbGZTaWduZWQudHhIZXgpO1xuICAgICAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgICAgY29uc3QgdHhKc29uID0gdHJhbnNhY3Rpb24udG9Kc29uKCk7XG4gICAgICAgICAgdHhKc29uLnRvLnNob3VsZC5lcXVhbChjb250cmFjdEFkZHJlc3MpO1xuXG4gICAgICAgICAgbGV0IGRlY29kZWREYXRhO1xuICAgICAgICAgIGxldCByZWNpcGllbnQ7XG4gICAgICAgICAgbGV0IHZhbHVlO1xuICAgICAgICAgIGxldCBkYXRhO1xuICAgICAgICAgIGxldCBleHBpcmVUaW1lO1xuICAgICAgICAgIGxldCBzZXF1ZW5jZUlkO1xuICAgICAgICAgIGlmIChjb2luIGluc3RhbmNlb2YgQ29udHJhY3RBZGRyZXNzRGVmaW5lZFRva2VuKSB7XG4gICAgICAgICAgICBkZWNvZGVkRGF0YSA9IGV0aEFiaS5yYXdEZWNvZGUoc2VuZE11bHRpc2lnVG9rZW5UeXBlcywgQnVmZmVyLmZyb20odHhKc29uLmRhdGEuc2xpY2UoMTApLCAnaGV4JykpO1xuICAgICAgICAgICAgW3JlY2lwaWVudCwgdmFsdWUgLyogdG9rZW5Db250cmFjdEFkZHJlc3MgKi8sICwgZXhwaXJlVGltZSwgc2VxdWVuY2VJZF0gPSBkZWNvZGVkRGF0YTtcbiAgICAgICAgICAgIGRhdGEgPSBCdWZmZXIuZnJvbSgnJyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRlY29kZWREYXRhID0gZXRoQWJpLnJhd0RlY29kZShzZW5kTXVsdGlzaWdUeXBlcywgQnVmZmVyLmZyb20odHhKc29uLmRhdGEuc2xpY2UoMTApLCAnaGV4JykpO1xuICAgICAgICAgICAgW3JlY2lwaWVudCwgdmFsdWUsIGRhdGEsIGV4cGlyZVRpbWUsIHNlcXVlbmNlSWRdID0gZGVjb2RlZERhdGE7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZXRoVXRpbC5hZGRIZXhQcmVmaXgocmVjaXBpZW50KS5zaG91bGQuZXF1YWwoZGVzdGluYXRpb24pO1xuICAgICAgICAgIHZhbHVlLnRvU3RyaW5nKDEwKS5zaG91bGQuZXF1YWwoYW1vdW50KTtcbiAgICAgICAgICBpbnB1dEV4cGlyZVRpbWUuc2hvdWxkLmVxdWFsKHBhcnNlSW50KGV4cGlyZVRpbWUudG9TdHJpbmcoJ2hleCcpLCAxNikpO1xuICAgICAgICAgIGlucHV0U2VxdWVuY2VJZC5zaG91bGQuZXF1YWwocGFyc2VJbnQoc2VxdWVuY2VJZC50b1N0cmluZygnaGV4JyksIDE2KSk7XG4gICAgICAgICAgZGF0YS5sZW5ndGguc2hvdWxkLmVxdWFsKDApO1xuXG4gICAgICAgICAgY29uc3QgcmVjb3ZlcmVkQWRkcmVzcyA9IHJlY292ZXJTaWduZXIodHJhbnNhY3Rpb24pO1xuICAgICAgICAgIHJlY292ZXJlZEFkZHJlc3Muc2hvdWxkLmVxdWFsKGtleS5nZXRBZGRyZXNzKCkpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnc2hvdWxkIHNpZ24gYSBoYWxmIHNpZ25lZCB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBrZXkgPSBuZXcgRXRoLktleVBhaXIoeyBwcnY6IHhwcnYgfSk7XG4gICAgICAgICAgY29uc3QgZGVzdGluYXRpb24gPSAnMHhmYWE4ZjE0ZjQ2YTk5ZWI0MzljNTBlMGMzYjgzNWNjMjFkYWQ1MWI0JztcbiAgICAgICAgICBjb25zdCBjb250cmFjdEFkZHJlc3MgPSAnMHg5ZTJjNTcxMmFiNGNhZjQwMmE5OGM0YmY1OGM3OWEwZGZlNzE4YWQxJztcbiAgICAgICAgICBjb25zdCBhbW91bnQgPSAnMTAwMDAwJztcbiAgICAgICAgICBjb25zdCBpbnB1dEV4cGlyZVRpbWUgPSBNYXRoLmZsb29yKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC8gMTAwMCk7XG4gICAgICAgICAgY29uc3QgaW5wdXRTZXF1ZW5jZUlkID0gMTtcblxuICAgICAgICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBidWlsZFVuc2lnbmVkVHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgZGVzdGluYXRpb24sXG4gICAgICAgICAgICBjb250cmFjdEFkZHJlc3MsXG4gICAgICAgICAgICBhbW91bnQsXG4gICAgICAgICAgICBleHBpcmVUaW1lOiBpbnB1dEV4cGlyZVRpbWUsXG4gICAgICAgICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IGlucHV0U2VxdWVuY2VJZCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IHR4ID0gYXdhaXQgYmFzZWNvaW4uc2lnblRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgIHBydjoga2V5LmdldEtleXMoKS5wcnYsXG4gICAgICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgICAgIHR4SGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc3QgZnVsbHlTaWduZWRUeCA9IGF3YWl0IGJhc2Vjb2luLnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBwcnY6IGtleS5nZXRLZXlzKCkucHJ2LFxuICAgICAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgICAgICB0eEhleDogdHguaGFsZlNpZ25lZC50eEhleCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBmdWxseVNpZ25lZFR4LmhhbGZTaWduZWQucmVjaXBpZW50cy5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuICAgICAgICAgIGZ1bGx5U2lnbmVkVHguaGFsZlNpZ25lZC5yZWNpcGllbnRzWzBdLmFkZHJlc3Muc2hvdWxkLmVxdWFsKGRlc3RpbmF0aW9uKTtcbiAgICAgICAgICBmdWxseVNpZ25lZFR4LmhhbGZTaWduZWQucmVjaXBpZW50c1swXS5hbW91bnQuc2hvdWxkLmVxdWFsKGFtb3VudCk7XG5cbiAgICAgICAgICBjb25zdCB0eEJ1aWxkZXIgPSBiYXNlY29pbi5nZXRUcmFuc2FjdGlvbkJ1aWxkZXIoKTtcbiAgICAgICAgICB0eEJ1aWxkZXIuZnJvbShmdWxseVNpZ25lZFR4LmhhbGZTaWduZWQudHhIZXgpO1xuICAgICAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgICAgY29uc3QgdHhKc29uID0gdHJhbnNhY3Rpb24udG9Kc29uKCk7XG4gICAgICAgICAgdHhKc29uLnRvLnNob3VsZC5lcXVhbChjb250cmFjdEFkZHJlc3MpO1xuXG4gICAgICAgICAgbGV0IGRlY29kZWREYXRhO1xuICAgICAgICAgIGxldCByZWNpcGllbnQ7XG4gICAgICAgICAgbGV0IHZhbHVlO1xuICAgICAgICAgIGxldCBkYXRhO1xuICAgICAgICAgIGxldCBleHBpcmVUaW1lO1xuICAgICAgICAgIGxldCBzZXF1ZW5jZUlkO1xuICAgICAgICAgIGlmIChjb2luIGluc3RhbmNlb2YgQ29udHJhY3RBZGRyZXNzRGVmaW5lZFRva2VuKSB7XG4gICAgICAgICAgICBkZWNvZGVkRGF0YSA9IGV0aEFiaS5yYXdEZWNvZGUoc2VuZE11bHRpc2lnVG9rZW5UeXBlcywgQnVmZmVyLmZyb20odHhKc29uLmRhdGEuc2xpY2UoMTApLCAnaGV4JykpO1xuICAgICAgICAgICAgW3JlY2lwaWVudCwgdmFsdWUgLyogdG9rZW5Db250cmFjdEFkZHJlc3MgKi8sICwgZXhwaXJlVGltZSwgc2VxdWVuY2VJZF0gPSBkZWNvZGVkRGF0YTtcbiAgICAgICAgICAgIGRhdGEgPSBCdWZmZXIuZnJvbSgnJyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRlY29kZWREYXRhID0gZXRoQWJpLnJhd0RlY29kZShzZW5kTXVsdGlzaWdUeXBlcywgQnVmZmVyLmZyb20odHhKc29uLmRhdGEuc2xpY2UoMTApLCAnaGV4JykpO1xuICAgICAgICAgICAgW3JlY2lwaWVudCwgdmFsdWUsIGRhdGEsIGV4cGlyZVRpbWUsIHNlcXVlbmNlSWRdID0gZGVjb2RlZERhdGE7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZXRoVXRpbC5hZGRIZXhQcmVmaXgocmVjaXBpZW50KS5zaG91bGQuZXF1YWwoZGVzdGluYXRpb24pO1xuICAgICAgICAgIHZhbHVlLnRvU3RyaW5nKDEwKS5zaG91bGQuZXF1YWwoYW1vdW50KTtcbiAgICAgICAgICBpbnB1dEV4cGlyZVRpbWUuc2hvdWxkLmVxdWFsKHBhcnNlSW50KGV4cGlyZVRpbWUudG9TdHJpbmcoJ2hleCcpLCAxNikpO1xuICAgICAgICAgIGlucHV0U2VxdWVuY2VJZC5zaG91bGQuZXF1YWwocGFyc2VJbnQoc2VxdWVuY2VJZC50b1N0cmluZygnaGV4JyksIDE2KSk7XG4gICAgICAgICAgZGF0YS5sZW5ndGguc2hvdWxkLmVxdWFsKDApO1xuXG4gICAgICAgICAgY29uc3QgcmVjb3ZlcmVkQWRkcmVzcyA9IHJlY292ZXJTaWduZXIodHJhbnNhY3Rpb24pO1xuICAgICAgICAgIHJlY292ZXJlZEFkZHJlc3Muc2hvdWxkLmVxdWFsKGtleS5nZXRBZGRyZXNzKCkpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnc2hvdWxkIGZhaWwgdG8gc2lnbiB0cmFuc2FjdGlvbiB3aXRoIGludmFsaWQgdHggaGV4JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGtleSA9IG5ldyBFdGguS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAgICAgLnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgICAgICAgIHBydjoga2V5LmdldEtleXMoKS5wcnYsXG4gICAgICAgICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICAgICAgICB0eEhleDogJzB4aW52YWxpZCcsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZCgpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnRXhwbGFpbiB0cmFuc2FjdGlvbjonLCAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHhwcnYgPVxuICAgICAgICAgICd4cHJ2OXMyMVpyUUgxNDNLM0Q4VFhmdkFKZ0hWZlRFZVFOVzVZczl3WnRuVVprcVB6RnpTamJFSnJXQzF2WjRHblhDdlI3clFMMlVGWDNSU3VZZVU5TXJFUm0xWEJ2QUNvdzdjMzZ2bno1aVl5ajInO1xuXG4gICAgICAgIGl0KCdzaG91bGQgZmFpbCBpZiB0aGUgcGFyYW1zIG9iamVjdCBpcyBtaXNzaW5nIHBhcmFtZXRlcnMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgZXhwbGFpblBhcmFtcyA9IHtcbiAgICAgICAgICAgIGZlZUluZm86IHsgZmVlOiAxIH0sXG4gICAgICAgICAgICB0eEhleDogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbihleHBsYWluUGFyYW1zKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdtaXNzaW5nIGV4cGxhaW4gdHggcGFyYW1ldGVycycpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnZXhwbGFpbiBhbiB1bnNpZ25lZCB0cmFuc2ZlciB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBkZXN0aW5hdGlvbiA9ICcweGZhYThmMTRmNDZhOTllYjQzOWM1MGUwYzNiODM1Y2MyMWRhZDUxYjQnO1xuICAgICAgICAgIGNvbnN0IGNvbnRyYWN0QWRkcmVzcyA9ICcweDllMmM1NzEyYWI0Y2FmNDAyYTk4YzRiZjU4Yzc5YTBkZmU3MThhZDEnO1xuXG4gICAgICAgICAgY29uc3QgdW5zaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJ1aWxkVW5zaWduZWRUcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBkZXN0aW5hdGlvbixcbiAgICAgICAgICAgIGNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IGV4cGxhaW5QYXJhbXMgPSB7XG4gICAgICAgICAgICBoYWxmU2lnbmVkOiB7XG4gICAgICAgICAgICAgIHR4SGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZmVlSW5mbzogeyBmZWU6IDEgfSxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IGV4cGxhbmF0aW9uID0gYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKGV4cGxhaW5QYXJhbXMpO1xuICAgICAgICAgIHNob3VsZC5leGlzdChleHBsYW5hdGlvbi5pZCk7XG4gICAgICAgICAgLy8gVE9ETyBjaGVjayBvdGhlciBmaWVsZHMgb25jZSBhY2NvdW50LWxpYiBwcm9wZXJseSBleHBsYWlucyB0cmFuc2FjdGlvblxuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnZXhwbGFpbiBhIHNpZ25lZCB0cmFuc2ZlciB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBrZXkgPSBuZXcgRXRoLktleVBhaXIoeyBwcnY6IHhwcnYgfSk7XG4gICAgICAgICAgY29uc3QgZGVzdGluYXRpb24gPSAnMHhmYWE4ZjE0ZjQ2YTk5ZWI0MzljNTBlMGMzYjgzNWNjMjFkYWQ1MWI0JztcbiAgICAgICAgICBjb25zdCBjb250cmFjdEFkZHJlc3MgPSAnMHg5ZTJjNTcxMmFiNGNhZjQwMmE5OGM0YmY1OGM3OWEwZGZlNzE4YWQxJztcblxuICAgICAgICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBidWlsZFVuc2lnbmVkVHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgZGVzdGluYXRpb24sXG4gICAgICAgICAgICBjb250cmFjdEFkZHJlc3MsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBjb25zdCBzaWduZWRUeCA9IGF3YWl0IGJhc2Vjb2luLnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBwcnY6IGtleS5nZXRLZXlzKCkucHJ2LFxuICAgICAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgICAgICB0eEhleDogdW5zaWduZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IGV4cGxhaW5QYXJhbXMgPSB7XG4gICAgICAgICAgICB0eEhleDogc2lnbmVkVHguaGFsZlNpZ25lZC50eEhleCxcbiAgICAgICAgICAgIGZlZUluZm86IHsgZmVlOiAxIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCBleHBsYW5hdGlvbiA9IGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbihleHBsYWluUGFyYW1zKTtcbiAgICAgICAgICBzaG91bGQuZXhpc3QoZXhwbGFuYXRpb24uaWQpO1xuICAgICAgICAgIC8vIFRPRE8gY2hlY2sgb3RoZXIgZmllbGRzIG9uY2UgYWNjb3VudC1saWIgcHJvcGVybHkgZXhwbGFpbnMgdHJhbnNhY3Rpb25cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==