PHP WebShell

Текущая директория: /opt/BitGoJS/modules/bitgo/dist/test/v2/unit/coins

Просмотр файла: abstractEthCoin.js

"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3RFdGhDb2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2NvaW5zL2Fic3RyYWN0RXRoQ29pbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7O0FBRUgsNEJBQTRCO0FBQzVCLGlDQUFpQztBQUNqQyw4Q0FBd0M7QUFDeEMsOENBQTRDO0FBQzVDLGlEQUE4QztBQUM5QyxvREFBcUQ7QUFDckQseUNBQXlDO0FBQ3pDLDJDQUEyQztBQUMzQyw0Q0FBb0U7QUFDcEUsOENBQW1FO0FBRW5FLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLEVBQUU7SUFDOUIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRTtRQUNqRCxRQUFRLENBQUMsR0FBRyxRQUFRLEVBQUUsRUFBRSxHQUFHLEVBQUU7WUFDM0IsSUFBSSxLQUFLLENBQUM7WUFDVixJQUFJLFFBQVEsQ0FBQztZQUNiLElBQUksSUFBSSxDQUFDO1lBRVQsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDekYsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDaEcsTUFBTSxnQkFBZ0IsR0FBRztnQkFDdkIsTUFBTSxFQUFFO29CQUNOLElBQUksRUFBRSxLQUFLO29CQUNYLEtBQUssRUFBRSxNQUFNO29CQUNiLEtBQUssRUFBRSxLQUFLO2lCQUNiO2dCQUNELEtBQUssRUFBRTtvQkFDTCxJQUFJLEVBQUUsV0FBVztvQkFDakIsS0FBSyxFQUFFLFlBQVk7b0JBQ25CLEtBQUssRUFBRSxXQUFXO2lCQUNuQjthQUNGLENBQUM7WUFFRjs7OztlQUlHO1lBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLEVBQW1CLEVBQVUsRUFBRTtnQkFDdkQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxFQUFFLG9CQUFvQixFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLGlCQUFHLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUV4RyxJQUFJLElBQUksWUFBWSxxQ0FBMkIsRUFBRSxDQUFDO29CQUNoRCxPQUFPLE1BQU0sQ0FBQyxZQUFZLENBQ3hCLEdBQUc7d0JBQ0QsQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQzt3QkFDeEQ7NEJBQ0UsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQzs0QkFDaEMsNkRBQTZEOzRCQUM3RCw2RUFBNkU7NEJBQzdFLElBQUksT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQzs0QkFDOUMsTUFBTTs0QkFDTiw2REFBNkQ7NEJBQzdELDZFQUE2RTs0QkFDN0UsSUFBSSxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsb0JBQW9CLENBQUMsRUFBRSxFQUFFLENBQUM7NEJBQ2hFLFVBQVU7NEJBQ1YsVUFBVTt5QkFDWDtxQkFDRixDQUNGLENBQUM7Z0JBQ0osQ0FBQztxQkFBTSxDQUFDO29CQUNOLE9BQU8sTUFBTSxDQUFDLFlBQVksQ0FDeEIsR0FBRzt3QkFDRCxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUM7d0JBQzdDOzRCQUNFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUM7NEJBQ2pDLDZEQUE2RDs0QkFDN0QsNkVBQTZFOzRCQUM3RSxJQUFJLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7NEJBQzlDLE1BQU07NEJBQ04sVUFBVTs0QkFDVixVQUFVO3lCQUNYO3FCQUNGLENBQ0YsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQyxDQUFDO1lBRUY7Ozs7ZUFJRztZQUNILE1BQU0sYUFBYSxHQUFHLFVBQVUsRUFBbUI7Z0JBQ2pELE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxpQkFBRyxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ3JFLE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ2xELE1BQU0sYUFBYSxHQUFHLGdCQUFnQixDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUMzQyw2REFBNkQ7Z0JBQzdELG1FQUFtRTtnQkFDbkUsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDL0QsT0FBTyxPQUFPLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdkYsQ0FBQyxDQUFDO1lBRUY7Ozs7Ozs7Ozs7ZUFVRztZQUNILE1BQU0sd0JBQXdCLEdBQUcsS0FBSyxXQUFXLEVBQy9DLFdBQVcsRUFDWCxlQUFlLEVBQ2Ysa0JBQWtCLEdBQUcsQ0FBQyxFQUN0QixLQUFLLEdBQUcsQ0FBQyxFQUNULFVBQVUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQ3BELE1BQU0sR0FBRyxRQUFRLEVBQ2pCLFFBQVEsR0FBRyxPQUFPLEVBQ2xCLFFBQVEsR0FBRyxPQUFPLEdBQ25CO2dCQUNDLE1BQU0sU0FBUyxHQUEyQixJQUFBLHdCQUFVLEVBQUMsUUFBUSxDQUEyQixDQUFDO2dCQUN6RixTQUFTLENBQUMsSUFBSSxDQUFDLDBCQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ3JDLFNBQVMsQ0FBQyxHQUFHLENBQUM7b0JBQ1osR0FBRyxFQUFFLFFBQVE7b0JBQ2IsUUFBUSxFQUFFLFFBQVE7aUJBQ25CLENBQUMsQ0FBQztnQkFDSCxTQUFTLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN6QixTQUFTLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dCQUNwQyxNQUFNLGVBQWUsR0FBRyxTQUFTLENBQUMsUUFBUSxFQUF5QixDQUFDO2dCQUVwRSxlQUFlO3FCQUNaLElBQUksQ0FBQyxRQUFRLENBQUM7cUJBQ2QsY0FBYyxDQUFDLFVBQVUsQ0FBQztxQkFDMUIsTUFBTSxDQUFDLE1BQU0sQ0FBQztxQkFDZCxFQUFFLENBQUMsV0FBVyxDQUFDO3FCQUNmLGtCQUFrQixDQUFDLGtCQUFrQixDQUFDLENBQUM7Z0JBRTFDLE9BQU8sTUFBTSxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDakMsQ0FBQyxDQUFDO1lBRUYsTUFBTSxDQUFDO2dCQUNMLEtBQUssR0FBRyxvQkFBUyxDQUFDLFFBQVEsQ0FBQyxhQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztnQkFDbkQsS0FBSyxDQUFDLGtCQUFrQixFQUFFLENBQUM7Z0JBQzNCLFFBQVEsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUNoQyxJQUFJLEdBQUcsZUFBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM3QixDQUFDLENBQUMsQ0FBQztZQUVILFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxHQUFHLEVBQUU7Z0JBQ2hDLEVBQUUsQ0FBQyx5Q0FBeUMsRUFBRSxHQUFHLEVBQUU7b0JBQ2pELFFBQVEsQ0FBQyxjQUFjLENBQUMsNENBQTRDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUN6RixRQUFRLENBQUMsY0FBYyxDQUFDLDRDQUE0QyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDM0YsQ0FBQyxDQUFDLENBQUM7Z0JBRUgsRUFBRSxDQUFDLDZDQUE2QyxFQUFFLEdBQUcsRUFBRTtvQkFDckQsUUFBUSxDQUFDLGNBQWMsQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQzNGLFFBQVEsQ0FBQyxjQUFjLENBQUMsMkNBQTJDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUN6RixRQUFRLENBQUMsY0FBYyxDQUFDLDBDQUEwQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDeEYsUUFBUSxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUM1RCxRQUFRLENBQUMsY0FBYyxDQUFDLGdCQUFnQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDOUQsUUFBUSxDQUFDLGNBQWMsQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3BGLENBQUMsQ0FBQyxDQUFDO2dCQUVILEdBQUcsQ0FBQyxpREFBaUQsRUFBRTtvQkFDckQsbUNBQW1DO2dCQUNyQyxDQUFDLENBQUMsQ0FBQztnQkFFSCxHQUFHLENBQUMsK0NBQStDLEVBQUU7b0JBQ25ELG1DQUFtQztnQkFDckMsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVILFFBQVEsQ0FBQyxjQUFjLEVBQUUsR0FBRyxFQUFFO2dCQUM1QixFQUFFLENBQUMsb0NBQW9DLEVBQUUsR0FBRyxFQUFFO29CQUM1QyxRQUFRO3lCQUNMLFVBQVUsQ0FDVCxpSEFBaUgsQ0FDbEg7eUJBQ0EsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDdEIsUUFBUTt5QkFDTCxVQUFVLENBQ1Qsb0lBQW9JLENBQ3JJO3lCQUNBLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ3RCLFFBQVEsQ0FBQyxVQUFVLENBQUMsb0VBQW9FLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUMvRyxDQUFDLENBQUMsQ0FBQztnQkFFSCxFQUFFLENBQUMsd0NBQXdDLEVBQUUsR0FBRyxFQUFFO29CQUNoRCxRQUFRLENBQUMsVUFBVSxDQUFDLDJDQUEyQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDckYsUUFBUSxDQUFDLFVBQVUsQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQ3RGLFFBQVEsQ0FBQyxVQUFVLENBQUMsMENBQTBDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUNwRixRQUFRLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQ25ELFFBQVEsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDckQsUUFBUSxDQUFDLFVBQVUsQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ2hGLENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQyxDQUFDLENBQUM7WUFFSCxRQUFRLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxFQUFFO2dCQUNoQyxFQUFFLENBQUMsNENBQTRDLEVBQUUsR0FBRyxFQUFFO29CQUNwRCxNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLFFBQVEsQ0FBQyxlQUFlLEVBQUUsQ0FBQztvQkFDaEQsUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUM1QyxNQUFNLFFBQVEsR0FBRyxnQkFBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztvQkFDdkMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN6RSxDQUFDLENBQUMsQ0FBQztnQkFFSCxFQUFFLENBQUMseUNBQXlDLEVBQUUsR0FBRyxFQUFFO29CQUNqRCxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLGtFQUFrRSxFQUFFLEtBQUssQ0FBQyxDQUFDO29CQUNwRyxNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLFFBQVEsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ3BELFFBQVEsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDNUMsTUFBTSxRQUFRLEdBQUcsZ0JBQUssQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7b0JBQ3ZDLFFBQVEsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDekUsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVILFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxHQUFHLEVBQUU7Z0JBQ2pDLE1BQU0sSUFBSSxHQUNSLGlIQUFpSCxDQUFDO2dCQUVwSCxFQUFFLENBQUMsb0NBQW9DLEVBQUUsS0FBSztvQkFDNUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxpQkFBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUMzQyxNQUFNLFdBQVcsR0FBRyw0Q0FBNEMsQ0FBQztvQkFDakUsTUFBTSxlQUFlLEdBQUcsNENBQTRDLENBQUM7b0JBQ3JFLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQztvQkFDeEIsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO29CQUNoRSxNQUFNLGVBQWUsR0FBRyxDQUFDLENBQUM7b0JBRTFCLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSx3QkFBd0IsQ0FBQzt3QkFDekQsV0FBVzt3QkFDWCxlQUFlO3dCQUNmLE1BQU07d0JBQ04sVUFBVSxFQUFFLGVBQWU7d0JBQzNCLGtCQUFrQixFQUFFLGVBQWU7cUJBQ3BDLENBQUMsQ0FBQztvQkFFSCxNQUFNLEVBQUUsR0FBRyxNQUFNLFFBQVEsQ0FBQyxlQUFlLENBQUM7d0JBQ3hDLEdBQUcsRUFBRSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRzt3QkFDdEIsVUFBVSxFQUFFOzRCQUNWLEtBQUssRUFBRSxtQkFBbUIsQ0FBQyxpQkFBaUIsRUFBRTt5QkFDL0M7cUJBQ0YsQ0FBQyxDQUFDO29CQUVILE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO29CQUNuRCxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQ3BDLE1BQU0sV0FBVyxHQUFHLE1BQU0sU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUM1QyxNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ3BDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztvQkFFeEMsSUFBSSxXQUFXLENBQUM7b0JBQ2hCLElBQUksU0FBUyxDQUFDO29CQUNkLElBQUksS0FBSyxDQUFDO29CQUNWLElBQUksSUFBSSxDQUFDO29CQUNULElBQUksVUFBVSxDQUFDO29CQUNmLElBQUksVUFBVSxDQUFDO29CQUNmLElBQUksSUFBSSxZQUFZLHFDQUEyQixFQUFFLENBQUM7d0JBQ2hELFdBQVcsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLHNCQUFzQixFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQzt3QkFDbEcsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLDBCQUEwQixFQUFFLEFBQUQsRUFBRyxVQUFVLEVBQUUsVUFBVSxDQUFDLEdBQUcsV0FBVyxDQUFDO3dCQUN0RixJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDekIsQ0FBQzt5QkFBTSxDQUFDO3dCQUNOLFdBQVcsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQzt3QkFDN0YsQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsVUFBVSxDQUFDLEdBQUcsV0FBVyxDQUFDO29CQUNqRSxDQUFDO29CQUNELE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztvQkFDMUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUN4QyxlQUFlLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO29CQUN2RSxlQUFlLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO29CQUN2RSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBRTVCLE1BQU0sZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLFdBQVcsQ0FBQyxDQUFDO29CQUNwRCxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO2dCQUNsRCxDQUFDLENBQUMsQ0FBQztnQkFFSCxFQUFFLENBQUMsaURBQWlELEVBQUUsS0FBSztvQkFDekQsTUFBTSxHQUFHLEdBQUcsSUFBSSxpQkFBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUMzQyxNQUFNLFdBQVcsR0FBRyw0Q0FBNEMsQ0FBQztvQkFDakUsTUFBTSxlQUFlLEdBQUcsNENBQTRDLENBQUM7b0JBQ3JFLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQztvQkFDeEIsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO29CQUNoRSxNQUFNLGVBQWUsR0FBRyxDQUFDLENBQUM7b0JBRTFCLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSx3QkFBd0IsQ0FBQzt3QkFDekQsV0FBVzt3QkFDWCxlQUFlO3dCQUNmLE1BQU07d0JBQ04sVUFBVSxFQUFFLGVBQWU7d0JBQzNCLGtCQUFrQixFQUFFLGVBQWU7cUJBQ3BDLENBQUMsQ0FBQztvQkFFSCxNQUFNLEVBQUUsR0FBRyxNQUFNLFFBQVEsQ0FBQyxlQUFlLENBQUM7d0JBQ3hDLEdBQUcsRUFBRSxJQUFJO3dCQUNULFVBQVUsRUFBRTs0QkFDVixLQUFLLEVBQUUsbUJBQW1CLENBQUMsaUJBQWlCLEVBQUU7eUJBQy9DO3FCQUNGLENBQUMsQ0FBQztvQkFFSCxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMscUJBQXFCLEVBQUUsQ0FBQztvQkFDbkQsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUNwQyxNQUFNLFdBQVcsR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztvQkFDNUMsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNwQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7b0JBRXhDLElBQUksV0FBVyxDQUFDO29CQUNoQixJQUFJLFNBQVMsQ0FBQztvQkFDZCxJQUFJLEtBQUssQ0FBQztvQkFDVixJQUFJLElBQUksQ0FBQztvQkFDVCxJQUFJLFVBQVUsQ0FBQztvQkFDZixJQUFJLFVBQVUsQ0FBQztvQkFDZixJQUFJLElBQUksWUFBWSxxQ0FBMkIsRUFBRSxDQUFDO3dCQUNoRCxXQUFXLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxzQkFBc0IsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7d0JBQ2xHLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxBQUFELEVBQUcsVUFBVSxFQUFFLFVBQVUsQ0FBQyxHQUFHLFdBQVcsQ0FBQzt3QkFDdEYsSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQ3pCLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixXQUFXLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7d0JBQzdGLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQyxHQUFHLFdBQVcsQ0FBQztvQkFDakUsQ0FBQztvQkFFRCxPQUFPLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7b0JBQzFELEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDeEMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDdkUsZUFBZSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDdkUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUU1QixNQUFNLGdCQUFnQixHQUFHLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztvQkFDcEQsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztnQkFDbEQsQ0FBQyxDQUFDLENBQUM7Z0JBRUgsRUFBRSxDQUFDLHVDQUF1QyxFQUFFLEtBQUs7b0JBQy9DLE1BQU0sR0FBRyxHQUFHLElBQUksaUJBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDM0MsTUFBTSxXQUFXLEdBQUcsNENBQTRDLENBQUM7b0JBQ2pFLE1BQU0sZUFBZSxHQUFHLDRDQUE0QyxDQUFDO29CQUNyRSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUM7b0JBQ3hCLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztvQkFDaEUsTUFBTSxlQUFlLEdBQUcsQ0FBQyxDQUFDO29CQUUxQixNQUFNLG1CQUFtQixHQUFHLE1BQU0sd0JBQXdCLENBQUM7d0JBQ3pELFdBQVc7d0JBQ1gsZUFBZTt3QkFDZixNQUFNO3dCQUNOLFVBQVUsRUFBRSxlQUFlO3dCQUMzQixrQkFBa0IsRUFBRSxlQUFlO3FCQUNwQyxDQUFDLENBQUM7b0JBRUgsTUFBTSxFQUFFLEdBQUcsTUFBTSxRQUFRLENBQUMsZUFBZSxDQUFDO3dCQUN4QyxHQUFHLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUc7d0JBQ3RCLFVBQVUsRUFBRTs0QkFDVixLQUFLLEVBQUUsbUJBQW1CLENBQUMsaUJBQWlCLEVBQUU7eUJBQy9DO3FCQUNGLENBQUMsQ0FBQztvQkFFSCxNQUFNLGFBQWEsR0FBRyxNQUFNLFFBQVEsQ0FBQyxlQUFlLENBQUM7d0JBQ25ELEdBQUcsRUFBRSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRzt3QkFDdEIsVUFBVSxFQUFFOzRCQUNWLEtBQUssRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUs7eUJBQzNCO3FCQUNGLENBQUMsQ0FBQztvQkFFSCxhQUFhLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDM0QsYUFBYSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7b0JBQ3pFLGFBQWEsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUVuRSxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMscUJBQXFCLEVBQUUsQ0FBQztvQkFDbkQsU0FBUyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUMvQyxNQUFNLFdBQVcsR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztvQkFDNUMsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNwQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7b0JBRXhDLElBQUksV0FBVyxDQUFDO29CQUNoQixJQUFJLFNBQVMsQ0FBQztvQkFDZCxJQUFJLEtBQUssQ0FBQztvQkFDVixJQUFJLElBQUksQ0FBQztvQkFDVCxJQUFJLFVBQVUsQ0FBQztvQkFDZixJQUFJLFVBQVUsQ0FBQztvQkFDZixJQUFJLElBQUksWUFBWSxxQ0FBMkIsRUFBRSxDQUFDO3dCQUNoRCxXQUFXLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxzQkFBc0IsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7d0JBQ2xHLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxBQUFELEVBQUcsVUFBVSxFQUFFLFVBQVUsQ0FBQyxHQUFHLFdBQVcsQ0FBQzt3QkFDdEYsSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQ3pCLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixXQUFXLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7d0JBQzdGLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQyxHQUFHLFdBQVcsQ0FBQztvQkFDakUsQ0FBQztvQkFFRCxPQUFPLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7b0JBQzFELEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDeEMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDdkUsZUFBZSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDdkUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUU1QixNQUFNLGdCQUFnQixHQUFHLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztvQkFDcEQsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztnQkFDbEQsQ0FBQyxDQUFDLENBQUM7Z0JBRUgsRUFBRSxDQUFDLHFEQUFxRCxFQUFFLEtBQUs7b0JBQzdELE1BQU0sR0FBRyxHQUFHLElBQUksaUJBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDM0MsTUFBTSxRQUFRO3lCQUNYLGVBQWUsQ0FBQzt3QkFDZixHQUFHLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUc7d0JBQ3RCLFVBQVUsRUFBRTs0QkFDVixLQUFLLEVBQUUsV0FBVzt5QkFDbkI7cUJBQ0YsQ0FBQzt5QkFDRCxNQUFNLENBQUMsRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUMxQixDQUFDLENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDO1lBRUgsUUFBUSxDQUFDLHNCQUFzQixFQUFFLEdBQUcsRUFBRTtnQkFDcEMsTUFBTSxJQUFJLEdBQ1IsaUhBQWlILENBQUM7Z0JBRXBILEVBQUUsQ0FBQyx3REFBd0QsRUFBRSxLQUFLO29CQUNoRSxNQUFNLGFBQWEsR0FBRzt3QkFDcEIsT0FBTyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRTt3QkFDbkIsS0FBSyxFQUFFLElBQUk7cUJBQ1osQ0FBQztvQkFDRixNQUFNLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO2dCQUMzRyxDQUFDLENBQUMsQ0FBQztnQkFFSCxFQUFFLENBQUMsMENBQTBDLEVBQUUsS0FBSztvQkFDbEQsTUFBTSxXQUFXLEdBQUcsNENBQTRDLENBQUM7b0JBQ2pFLE1BQU0sZUFBZSxHQUFHLDRDQUE0QyxDQUFDO29CQUVyRSxNQUFNLG1CQUFtQixHQUFHLE1BQU0sd0JBQXdCLENBQUM7d0JBQ3pELFdBQVc7d0JBQ1gsZUFBZTtxQkFDaEIsQ0FBQyxDQUFDO29CQUVILE1BQU0sYUFBYSxHQUFHO3dCQUNwQixVQUFVLEVBQUU7NEJBQ1YsS0FBSyxFQUFFLG1CQUFtQixDQUFDLGlCQUFpQixFQUFFO3lCQUMvQzt3QkFDRCxPQUFPLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFO3FCQUNwQixDQUFDO29CQUNGLE1BQU0sV0FBVyxHQUFHLE1BQU0sUUFBUSxDQUFDLGtCQUFrQixDQUFDLGFBQWEsQ0FBQyxDQUFDO29CQUNyRSxNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDN0IseUVBQXlFO2dCQUMzRSxDQUFDLENBQUMsQ0FBQztnQkFFSCxFQUFFLENBQUMsdUNBQXVDLEVBQUUsS0FBSztvQkFDL0MsTUFBTSxHQUFHLEdBQUcsSUFBSSxpQkFBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUMzQyxNQUFNLFdBQVcsR0FBRyw0Q0FBNEMsQ0FBQztvQkFDakUsTUFBTSxlQUFlLEdBQUcsNENBQTRDLENBQUM7b0JBRXJFLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSx3QkFBd0IsQ0FBQzt3QkFDekQsV0FBVzt3QkFDWCxlQUFlO3FCQUNoQixDQUFDLENBQUM7b0JBRUgsTUFBTSxRQUFRLEdBQUcsTUFBTSxRQUFRLENBQUMsZUFBZSxDQUFDO3dCQUM5QyxHQUFHLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUc7d0JBQ3RCLFVBQVUsRUFBRTs0QkFDVixLQUFLLEVBQUUsbUJBQW1CLENBQUMsaUJBQWlCLEVBQUU7eUJBQy9DO3FCQUNGLENBQUMsQ0FBQztvQkFFSCxNQUFNLGFBQWEsR0FBRzt3QkFDcEIsS0FBSyxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsS0FBSzt3QkFDaEMsT0FBTyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRTtxQkFDcEIsQ0FBQztvQkFDRixNQUFNLFdBQVcsR0FBRyxNQUFNLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFDckUsTUFBTSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQzdCLHlFQUF5RTtnQkFDM0UsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQHByZXR0aWVyXG4gKi9cblxuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0ICogYXMgc2hvdWxkIGZyb20gJ3Nob3VsZCc7XG5pbXBvcnQgeyBiaXAzMiB9IGZyb20gJ0BiaXRnby91dHhvLWxpYic7XG5pbXBvcnQgeyBUZXN0Qml0R28gfSBmcm9tICdAYml0Z28vc2RrLXRlc3QnO1xuaW1wb3J0IHsgQml0R28gfSBmcm9tICcuLi8uLi8uLi8uLi9zcmMvYml0Z28nO1xuaW1wb3J0IHsgZ2V0QnVpbGRlciwgRXRoIH0gZnJvbSAnQGJpdGdvL2FjY291bnQtbGliJztcbmltcG9ydCAqIGFzIGV0aEFiaSBmcm9tICdldGhlcmV1bWpzLWFiaSc7XG5pbXBvcnQgKiBhcyBldGhVdGlsIGZyb20gJ2V0aGVyZXVtanMtdXRpbCc7XG5pbXBvcnQgeyBjb2lucywgQ29udHJhY3RBZGRyZXNzRGVmaW5lZFRva2VuIH0gZnJvbSAnQGJpdGdvL3N0YXRpY3MnO1xuaW1wb3J0IHsgQmFzZVRyYW5zYWN0aW9uLCBUcmFuc2FjdGlvblR5cGUgfSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuXG5kZXNjcmliZSgnRVRILWxpa2UgY29pbnMnLCAoKSA9PiB7XG4gIF8uZm9yRWFjaChbJ3RldGMnLCAndGNlbG8nLCAndHJidGMnXSwgKGNvaW5OYW1lKSA9PiB7XG4gICAgZGVzY3JpYmUoYCR7Y29pbk5hbWV9YCwgKCkgPT4ge1xuICAgICAgbGV0IGJpdGdvO1xuICAgICAgbGV0IGJhc2Vjb2luO1xuICAgICAgbGV0IGNvaW47XG5cbiAgICAgIGNvbnN0IHNlbmRNdWx0aXNpZ1R5cGVzID0gWydhZGRyZXNzJywgJ3VpbnQyNTYnLCAnYnl0ZXMnLCAndWludDI1NicsICd1aW50MjU2JywgJ2J5dGVzJ107XG4gICAgICBjb25zdCBzZW5kTXVsdGlzaWdUb2tlblR5cGVzID0gWydhZGRyZXNzJywgJ3VpbnQyNTYnLCAnYWRkcmVzcycsICd1aW50MjU2JywgJ3VpbnQyNTYnLCAnYnl0ZXMnXTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZVNhbHRNYXAgPSB7XG4gICAgICAgIG5hdGl2ZToge1xuICAgICAgICAgIHRldGM6ICdFVEMnLFxuICAgICAgICAgIHRjZWxvOiAnQ0VMTycsXG4gICAgICAgICAgdHJidGM6ICdSU0snLFxuICAgICAgICB9LFxuICAgICAgICB0b2tlbjoge1xuICAgICAgICAgIHRldGM6ICdFVEMtRVJDMjAnLFxuICAgICAgICAgIHRjZWxvOiAnQ0VMTy1FUkMyMCcsXG4gICAgICAgICAgdHJidGM6ICdSU0stRVJDMjAnLFxuICAgICAgICB9LFxuICAgICAgfTtcblxuICAgICAgLyoqXG4gICAgICAgKiBHZXQgdGhlIG9wZXJhdGlvbiBoYXNoIHRoYXQgdGhlIHVzZXIga2V5IHNpZ25lZFxuICAgICAgICogQHBhcmFtIHR4IFRoZSB0cmFuc2FjdGlvbiB0byBjYWxjdWxhdGUgb3BlcmF0aW5vIGhhc2ggZnJvbVxuICAgICAgICogQHJldHVybiBUaGUgb3BlcmF0aW9uIGhhc2hcbiAgICAgICAqL1xuICAgICAgY29uc3QgZ2V0T3BlcmF0aW9uSGFzaCA9ICh0eDogQmFzZVRyYW5zYWN0aW9uKTogc3RyaW5nID0+IHtcbiAgICAgICAgY29uc3QgeyBkYXRhIH0gPSB0eC50b0pzb24oKTtcbiAgICAgICAgY29uc3QgeyB0b2tlbkNvbnRyYWN0QWRkcmVzcywgZXhwaXJlVGltZSwgc2VxdWVuY2VJZCwgYW1vdW50LCB0byB9ID0gRXRoLlV0aWxzLmRlY29kZVRyYW5zZmVyRGF0YShkYXRhKTtcblxuICAgICAgICBpZiAoY29pbiBpbnN0YW5jZW9mIENvbnRyYWN0QWRkcmVzc0RlZmluZWRUb2tlbikge1xuICAgICAgICAgIHJldHVybiBldGhBYmkuc29saWRpdHlTSEEzKFxuICAgICAgICAgICAgLi4uW1xuICAgICAgICAgICAgICBbJ3N0cmluZycsICdhZGRyZXNzJywgJ3VpbnQnLCAnYWRkcmVzcycsICd1aW50JywgJ3VpbnQnXSxcbiAgICAgICAgICAgICAgW1xuICAgICAgICAgICAgICAgIHNpZ25hdHVyZVNhbHRNYXAudG9rZW5bY29pbk5hbWVdLFxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvYmFuLXRzLWNvbW1lbnRcbiAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlIEJHLTM0NTc5OiBrbm93biBjb21wYXRpYmlsaXR5IGlzc3VlIHdpdGggQHR5cGVzL2V0aGVyZXVtanMtdXRpbFxuICAgICAgICAgICAgICAgIG5ldyBldGhVdGlsLkJOKGV0aFV0aWwuc3RyaXBIZXhQcmVmaXgodG8pLCAxNiksXG4gICAgICAgICAgICAgICAgYW1vdW50LFxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvYmFuLXRzLWNvbW1lbnRcbiAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlIEJHLTM0NTc5OiBrbm93biBjb21wYXRpYmlsaXR5IGlzc3VlIHdpdGggQHR5cGVzL2V0aGVyZXVtanMtdXRpbFxuICAgICAgICAgICAgICAgIG5ldyBldGhVdGlsLkJOKGV0aFV0aWwuc3RyaXBIZXhQcmVmaXgodG9rZW5Db250cmFjdEFkZHJlc3MpLCAxNiksXG4gICAgICAgICAgICAgICAgZXhwaXJlVGltZSxcbiAgICAgICAgICAgICAgICBzZXF1ZW5jZUlkLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgXVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIGV0aEFiaS5zb2xpZGl0eVNIQTMoXG4gICAgICAgICAgICAuLi5bXG4gICAgICAgICAgICAgIFsnc3RyaW5nJywgJ2FkZHJlc3MnLCAndWludCcsICd1aW50JywgJ3VpbnQnXSxcbiAgICAgICAgICAgICAgW1xuICAgICAgICAgICAgICAgIHNpZ25hdHVyZVNhbHRNYXAubmF0aXZlW2NvaW5OYW1lXSxcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50XG4gICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZSBCRy0zNDU3OToga25vd24gY29tcGF0aWJpbGl0eSBpc3N1ZSB3aXRoIEB0eXBlcy9ldGhlcmV1bWpzLXV0aWxcbiAgICAgICAgICAgICAgICBuZXcgZXRoVXRpbC5CTihldGhVdGlsLnN0cmlwSGV4UHJlZml4KHRvKSwgMTYpLFxuICAgICAgICAgICAgICAgIGFtb3VudCxcbiAgICAgICAgICAgICAgICBleHBpcmVUaW1lLFxuICAgICAgICAgICAgICAgIHNlcXVlbmNlSWQsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBdXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgLyoqXG4gICAgICAgKiBSZWNvdmVyIHRoZSBzaWduaW5nIGFkZHJlc3Mgb2YgYSBzaWduYXR1cmVcbiAgICAgICAqIEBwYXJhbSB0eCBUaGUgdHJhbnNhY3Rpb24gdG8gcmVjb3ZlciBhIHNpZ25lciBmcm9tXG4gICAgICAgKiBAcmV0dXJuIFRoZSBldGggYWRkcmVzcyBvZiB0aGUgc2lnbmVyXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IHJlY292ZXJTaWduZXIgPSBmdW5jdGlvbiAodHg6IEJhc2VUcmFuc2FjdGlvbikge1xuICAgICAgICBjb25zdCB7IHNpZ25hdHVyZSB9ID0gRXRoLlV0aWxzLmRlY29kZVRyYW5zZmVyRGF0YSh0eC50b0pzb24oKS5kYXRhKTtcbiAgICAgICAgY29uc3QgeyB2LCByLCBzIH0gPSBldGhVdGlsLmZyb21ScGNTaWcoc2lnbmF0dXJlKTtcbiAgICAgICAgY29uc3Qgb3BlcmF0aW9uSGFzaCA9IGdldE9wZXJhdGlvbkhhc2godHgpO1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50XG4gICAgICAgIC8vIEB0cy1pZ25vcmUga25vd24gY29tcGF0aWJpbGl0eSBpc3N1ZSB3aXRoIEB0eXBlcy9ldGhlcmV1bWpzLXV0aWxcbiAgICAgICAgY29uc3QgcHViS2V5QnVmZmVyID0gZXRoVXRpbC5lY3JlY292ZXIob3BlcmF0aW9uSGFzaCwgdiwgciwgcyk7XG4gICAgICAgIHJldHVybiBldGhVdGlsLmJ1ZmZlclRvSGV4KGV0aFV0aWwucHViVG9BZGRyZXNzKGV0aFV0aWwuaW1wb3J0UHVibGljKHB1YktleUJ1ZmZlcikpKTtcbiAgICAgIH07XG5cbiAgICAgIC8qKlxuICAgICAgICogQnVpbGQgYW4gdW5zaWduZWQgYWNjb3VudC1saWIgbXVsdGktc2lnbmF0dXJlIHNlbmQgdHJhbnNhY3Rpbm9cbiAgICAgICAqIEBwYXJhbSBkZXN0aW5hdGlvbiBUaGUgZGVzdGluYXRpb24gYWRkcmVzcyBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICAgICAqIEBwYXJhbSBjb250cmFjdEFkZHJlc3MgVGhlIGFkZHJlc3Mgb2YgdGhlIHNtYXJ0IGNvbnRyYWN0IHByb2Nlc3NpbmcgdGhlIHRyYW5zYWN0aW9uXG4gICAgICAgKiBAcGFyYW0gY29udHJhY3RTZXF1ZW5jZUlkIFRoZSBzZXF1ZW5jZSBpZCBvZiB0aGUgY29udHJhY3RcbiAgICAgICAqIEBwYXJhbSBub25jZSBUaGUgbm9uY2Ugb2YgdGhlIHNlbmRpbmcgYWRkcmVzc1xuICAgICAgICogQHBhcmFtIGV4cGlyZVRpbWUgVGhlIGV4cGlyZSB0aW1lIG9mIHRoZSB0cmFuc2FjdGlvblxuICAgICAgICogQHBhcmFtIGFtb3VudCBUaGUgYW1vdW50IHRvIHNlbmQgdG8gdGhlIHJlY2lwaWVudFxuICAgICAgICogQHBhcmFtIGdhc1ByaWNlIFRoZSBnYXMgcHJpY2Ugb2YgdGhlIHRyYW5zYWN0aW9uXG4gICAgICAgKiBAcGFyYW0gZ2FzTGltaXQgVGhlIGdhcyBsaW1pdCBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICAgICAqL1xuICAgICAgY29uc3QgYnVpbGRVbnNpZ25lZFRyYW5zYWN0aW9uID0gYXN5bmMgZnVuY3Rpb24gKHtcbiAgICAgICAgZGVzdGluYXRpb24sXG4gICAgICAgIGNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgY29udHJhY3RTZXF1ZW5jZUlkID0gMSxcbiAgICAgICAgbm9uY2UgPSAwLFxuICAgICAgICBleHBpcmVUaW1lID0gTWF0aC5mbG9vcihuZXcgRGF0ZSgpLmdldFRpbWUoKSAvIDEwMDApLFxuICAgICAgICBhbW91bnQgPSAnMTAwMDAwJyxcbiAgICAgICAgZ2FzUHJpY2UgPSAnMTAwMDAnLFxuICAgICAgICBnYXNMaW1pdCA9ICcyMDAwMCcsXG4gICAgICB9KSB7XG4gICAgICAgIGNvbnN0IHR4QnVpbGRlcjogRXRoLlRyYW5zYWN0aW9uQnVpbGRlciA9IGdldEJ1aWxkZXIoY29pbk5hbWUpIGFzIEV0aC5UcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgICAgIHR4QnVpbGRlci50eXBlKFRyYW5zYWN0aW9uVHlwZS5TZW5kKTtcbiAgICAgICAgdHhCdWlsZGVyLmZlZSh7XG4gICAgICAgICAgZmVlOiBnYXNQcmljZSxcbiAgICAgICAgICBnYXNMaW1pdDogZ2FzTGltaXQsXG4gICAgICAgIH0pO1xuICAgICAgICB0eEJ1aWxkZXIuY291bnRlcihub25jZSk7XG4gICAgICAgIHR4QnVpbGRlci5jb250cmFjdChjb250cmFjdEFkZHJlc3MpO1xuICAgICAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSB0eEJ1aWxkZXIudHJhbnNmZXIoKSBhcyBFdGguVHJhbnNmZXJCdWlsZGVyO1xuXG4gICAgICAgIHRyYW5zZmVyQnVpbGRlclxuICAgICAgICAgIC5jb2luKGNvaW5OYW1lKVxuICAgICAgICAgIC5leHBpcmF0aW9uVGltZShleHBpcmVUaW1lKVxuICAgICAgICAgIC5hbW91bnQoYW1vdW50KVxuICAgICAgICAgIC50byhkZXN0aW5hdGlvbilcbiAgICAgICAgICAuY29udHJhY3RTZXF1ZW5jZUlkKGNvbnRyYWN0U2VxdWVuY2VJZCk7XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgfTtcblxuICAgICAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R28sIHsgZW52OiAnbW9jaycgfSk7XG4gICAgICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgICAgICBiYXNlY29pbiA9IGJpdGdvLmNvaW4oY29pbk5hbWUpO1xuICAgICAgICBjb2luID0gY29pbnMuZ2V0KGNvaW5OYW1lKTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnSXMgdmFsaWQgYWRkcmVzcycsICgpID0+IHtcbiAgICAgICAgaXQoJ1Nob3VsZCBmaW5kIHZhbGlkIGFkZHJlc3NlcyB0byBiZSB2YWxpZCcsICgpID0+IHtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnMHgyYWY5MTUyZmM0YWZkODlhODEyNDczMWJkZmI4NzEwYzg3NTFmM2VkJykuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKCcweDJhZjkxNTJGQzRhZmQ4OUE4MTI0NzMxQmRGYjg3MTBjODc1MWYzZUQnKS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdTaG91bGQgZmluZCBpbnZhbGlkIGFkZHJlc3NlcyB0byBiZSBpbnZhbGlkJywgKCkgPT4ge1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKCcweDJhZjkxNTJmYzRhZmQ4OWE4MTI0NzMxYmRmYjg3MTBjODc1MWYzZWRkJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnMHgyYWY5MTUyZmM0YWZkODlhODEyNDczMWJkZmI4NzEwYzg3NTFmM2UnKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKCcyYWY5MTUyZmM0YWZkODlhODEyNDczMWJkZmI4NzEwYzg3NTFmM2VkJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnbm90YW5hZGRyZXNzJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcygnbm90IGFuIGFkZHJlc3MnKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKCczS2dMNkRUVWI2Z0VvcVN3TU1KenlmOTZla0g4b1p0V3RaJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgeGl0KCdTaG91bGQgbm90IHRocm93IHdoZW4gdmVyaWZ5aW5nIHZhbGlkIGFkZHJlc3NlcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAvLyBGSVhNRShCRy00MzIyNSk6IG5vdCBpbXBsZW1lbnRlZFxuICAgICAgICB9KTtcblxuICAgICAgICB4aXQoJ1Nob3VsZCB0aHJvdyB3aGVuIHZlcmlmeWluZyBpbnZhbGlkIGFkZHJlc3NlcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAvLyBGSVhNRShCRy00MzIyNSk6IG5vdCBpbXBsZW1lbnRlZFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnSXMgdmFsaWQgcHViJywgKCkgPT4ge1xuICAgICAgICBpdCgnU2hvdWxkIGZpbmQgdmFsaWQgcHVicyB0byBiZSB2YWxpZCcsICgpID0+IHtcbiAgICAgICAgICBiYXNlY29pblxuICAgICAgICAgICAgLmlzVmFsaWRQdWIoXG4gICAgICAgICAgICAgICd4cHViNjYxTXlNd0FxUmJjRjlOYzdUYkJvMXJaQWFnaVdFVlBXS2JES1RoTkc4enFqazc2SEFLTGthU2JUbjZkSzJkUVBmdUQ3eGppY3hDWlZXdmo2N2ZQNW5ROVc3UVVSbW9NVkFYOG02alpzR3AnXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgICAgIGJhc2Vjb2luXG4gICAgICAgICAgICAuaXNWYWxpZFB1YihcbiAgICAgICAgICAgICAgJzA0NjE0QzA3MEM2RDFDMThBNkEyRDZFRTJCQkJFMUZGMjkxQTBBQkE4RUQ2QjU1MDIzQzAzQkU0MjU4M0FDMjNBNzQzQkNCNUVGOURCNTlFMTRGRDcwMjVBOUE1RDkzQzZCQTg5RUVGRUI0MDIxNUJGMjQ5MzNENEYyOTM1RDE0Q0InXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoJzAzNGYzNTViZGNiN2NjMGFmNzI4ZWYzY2NlYjk2MTVkOTA2ODRiYjViMmNhNWY4NTlhYjBmMGI3MDQwNzU4NzFhYScpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ1Nob3VsZCBmaW5kIGludmFsaWQgcHVicyB0byBiZSBpbnZhbGlkJywgKCkgPT4ge1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoJzB4MmFmOTE1MmZjNGFmZDg5YTgxMjQ3MzFiZGZiODcxMGM4NzUxZjNlJykuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICAgICAgICBiYXNlY29pbi5pc1ZhbGlkUHViKCcweDJhZjkxNTJmYzRhZmQ4OWE4MTI0NzMxYmRmYjg3MTBjODc1MWYzZWQnKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoJzJhZjkxNTJmYzRhZmQ4OWE4MTI0NzMxYmRmYjg3MTBjODc1MWYzZWQnKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoJ25vdGFwdWInKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoJ25vdCBhIHB1YicpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZFB1YignM0tnTDZEVFViNmdFb3FTd01NSnp5Zjk2ZWtIOG9adFd0WicpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCdHZW5lcmF0ZSBrZXlwYWlyJywgKCkgPT4ge1xuICAgICAgICBpdCgnU2hvdWxkIGdlbmVyYXRlIHZhbGlkIGtleXBhaXIgd2l0aG91dCBzZWVkJywgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgcHViLCBwcnYgfSA9IGJhc2Vjb2luLmdlbmVyYXRlS2V5UGFpcigpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIocHViKS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICAgICAgY29uc3QgYml0Z29LZXkgPSBiaXAzMi5mcm9tQmFzZTU4KHBydik7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZFB1YihiaXRnb0tleS5uZXV0ZXJlZCgpLnRvQmFzZTU4KCkpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ1Nob3VsZCBnZW5lcmF0ZSB2YWxpZCBrZXlwYWlyIHdpdGggc2VlZCcsICgpID0+IHtcbiAgICAgICAgICBjb25zdCBzZWVkID0gQnVmZmVyLmZyb20oJ2MzYjA5YzI0NzMxYmUyODUxYjY0MWQ5ZDViM2Y2MGZhMTI5Njk1YzI0MDcxNzY4ZDE1NjU0YmVhMjA3YjdiYjYnLCAnaGV4Jyk7XG4gICAgICAgICAgY29uc3QgeyBwdWIsIHBydiB9ID0gYmFzZWNvaW4uZ2VuZXJhdGVLZXlQYWlyKHNlZWQpO1xuICAgICAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIocHViKS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICAgICAgY29uc3QgYml0Z29LZXkgPSBiaXAzMi5mcm9tQmFzZTU4KHBydik7XG4gICAgICAgICAgYmFzZWNvaW4uaXNWYWxpZFB1YihiaXRnb0tleS5uZXV0ZXJlZCgpLnRvQmFzZTU4KCkpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoJ1NpZ24gdHJhbnNhY3Rpb246JywgKCkgPT4ge1xuICAgICAgICBjb25zdCB4cHJ2ID1cbiAgICAgICAgICAneHBydjlzMjFaclFIMTQzSzNEOFRYZnZBSmdIVmZURWVRTlc1WXM5d1p0blVaa3FQekZ6U2piRUpyV0Mxdlo0R25YQ3ZSN3JRTDJVRlgzUlN1WWVVOU1yRVJtMVhCdkFDb3c3YzM2dm56NWlZeWoyJztcblxuICAgICAgICBpdCgnc2hvdWxkIHNpZ24gdHJhbnNhY3Rpb24gaW50ZXJuYWxseScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBrZXkgPSBuZXcgRXRoLktleVBhaXIoeyBwcnY6IHhwcnYgfSk7XG4gICAgICAgICAgY29uc3QgZGVzdGluYXRpb24gPSAnMHhmYWE4ZjE0ZjQ2YTk5ZWI0MzljNTBlMGMzYjgzNWNjMjFkYWQ1MWI0JztcbiAgICAgICAgICBjb25zdCBjb250cmFjdEFkZHJlc3MgPSAnMHg5ZTJjNTcxMmFiNGNhZjQwMmE5OGM0YmY1OGM3OWEwZGZlNzE4YWQxJztcbiAgICAgICAgICBjb25zdCBhbW91bnQgPSAnMTAwMDAwJztcbiAgICAgICAgICBjb25zdCBpbnB1dEV4cGlyZVRpbWUgPSBNYXRoLmZsb29yKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC8gMTAwMCk7XG4gICAgICAgICAgY29uc3QgaW5wdXRTZXF1ZW5jZUlkID0gMTtcblxuICAgICAgICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBidWlsZFVuc2lnbmVkVHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgZGVzdGluYXRpb24sXG4gICAgICAgICAgICBjb250cmFjdEFkZHJlc3MsXG4gICAgICAgICAgICBhbW91bnQsXG4gICAgICAgICAgICBleHBpcmVUaW1lOiBpbnB1dEV4cGlyZVRpbWUsXG4gICAgICAgICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IGlucHV0U2VxdWVuY2VJZCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IHR4ID0gYXdhaXQgYmFzZWNvaW4uc2lnblRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgIHBydjoga2V5LmdldEtleXMoKS5wcnYsXG4gICAgICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgICAgIHR4SGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc3QgdHhCdWlsZGVyID0gYmFzZWNvaW4uZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgICAgICAgdHhCdWlsZGVyLmZyb20odHguaGFsZlNpZ25lZC50eEhleCk7XG4gICAgICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgICAgICBjb25zdCB0eEpzb24gPSB0cmFuc2FjdGlvbi50b0pzb24oKTtcbiAgICAgICAgICB0eEpzb24udG8uc2hvdWxkLmVxdWFsKGNvbnRyYWN0QWRkcmVzcyk7XG5cbiAgICAgICAgICBsZXQgZGVjb2RlZERhdGE7XG4gICAgICAgICAgbGV0IHJlY2lwaWVudDtcbiAgICAgICAgICBsZXQgdmFsdWU7XG4gICAgICAgICAgbGV0IGRhdGE7XG4gICAgICAgICAgbGV0IGV4cGlyZVRpbWU7XG4gICAgICAgICAgbGV0IHNlcXVlbmNlSWQ7XG4gICAgICAgICAgaWYgKGNvaW4gaW5zdGFuY2VvZiBDb250cmFjdEFkZHJlc3NEZWZpbmVkVG9rZW4pIHtcbiAgICAgICAgICAgIGRlY29kZWREYXRhID0gZXRoQWJpLnJhd0RlY29kZShzZW5kTXVsdGlzaWdUb2tlblR5cGVzLCBCdWZmZXIuZnJvbSh0eEpzb24uZGF0YS5zbGljZSgxMCksICdoZXgnKSk7XG4gICAgICAgICAgICBbcmVjaXBpZW50LCB2YWx1ZSAvKiB0b2tlbkNvbnRyYWN0QWRkcmVzcyAqLywgLCBleHBpcmVUaW1lLCBzZXF1ZW5jZUlkXSA9IGRlY29kZWREYXRhO1xuICAgICAgICAgICAgZGF0YSA9IEJ1ZmZlci5mcm9tKCcnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGVjb2RlZERhdGEgPSBldGhBYmkucmF3RGVjb2RlKHNlbmRNdWx0aXNpZ1R5cGVzLCBCdWZmZXIuZnJvbSh0eEpzb24uZGF0YS5zbGljZSgxMCksICdoZXgnKSk7XG4gICAgICAgICAgICBbcmVjaXBpZW50LCB2YWx1ZSwgZGF0YSwgZXhwaXJlVGltZSwgc2VxdWVuY2VJZF0gPSBkZWNvZGVkRGF0YTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZXRoVXRpbC5hZGRIZXhQcmVmaXgocmVjaXBpZW50KS5zaG91bGQuZXF1YWwoZGVzdGluYXRpb24pO1xuICAgICAgICAgIHZhbHVlLnRvU3RyaW5nKDEwKS5zaG91bGQuZXF1YWwoYW1vdW50KTtcbiAgICAgICAgICBpbnB1dEV4cGlyZVRpbWUuc2hvdWxkLmVxdWFsKHBhcnNlSW50KGV4cGlyZVRpbWUudG9TdHJpbmcoJ2hleCcpLCAxNikpO1xuICAgICAgICAgIGlucHV0U2VxdWVuY2VJZC5zaG91bGQuZXF1YWwocGFyc2VJbnQoc2VxdWVuY2VJZC50b1N0cmluZygnaGV4JyksIDE2KSk7XG4gICAgICAgICAgZGF0YS5sZW5ndGguc2hvdWxkLmVxdWFsKDApO1xuXG4gICAgICAgICAgY29uc3QgcmVjb3ZlcmVkQWRkcmVzcyA9IHJlY292ZXJTaWduZXIodHJhbnNhY3Rpb24pO1xuICAgICAgICAgIHJlY292ZXJlZEFkZHJlc3Muc2hvdWxkLmVxdWFsKGtleS5nZXRBZGRyZXNzKCkpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnc2hvdWxkIHNpZ24gdHJhbnNhY3Rpb24gaW50ZXJuYWxseSB3aXRoIGFuIHhwcnYnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3Qga2V5ID0gbmV3IEV0aC5LZXlQYWlyKHsgcHJ2OiB4cHJ2IH0pO1xuICAgICAgICAgIGNvbnN0IGRlc3RpbmF0aW9uID0gJzB4ZmFhOGYxNGY0NmE5OWViNDM5YzUwZTBjM2I4MzVjYzIxZGFkNTFiNCc7XG4gICAgICAgICAgY29uc3QgY29udHJhY3RBZGRyZXNzID0gJzB4OWUyYzU3MTJhYjRjYWY0MDJhOThjNGJmNThjNzlhMGRmZTcxOGFkMSc7XG4gICAgICAgICAgY29uc3QgYW1vdW50ID0gJzEwMDAwMCc7XG4gICAgICAgICAgY29uc3QgaW5wdXRFeHBpcmVUaW1lID0gTWF0aC5mbG9vcihuZXcgRGF0ZSgpLmdldFRpbWUoKSAvIDEwMDApO1xuICAgICAgICAgIGNvbnN0IGlucHV0U2VxdWVuY2VJZCA9IDE7XG5cbiAgICAgICAgICBjb25zdCB1bnNpZ25lZFRyYW5zYWN0aW9uID0gYXdhaXQgYnVpbGRVbnNpZ25lZFRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgIGRlc3RpbmF0aW9uLFxuICAgICAgICAgICAgY29udHJhY3RBZGRyZXNzLFxuICAgICAgICAgICAgYW1vdW50LFxuICAgICAgICAgICAgZXhwaXJlVGltZTogaW5wdXRFeHBpcmVUaW1lLFxuICAgICAgICAgICAgY29udHJhY3RTZXF1ZW5jZUlkOiBpbnB1dFNlcXVlbmNlSWQsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBjb25zdCB0eCA9IGF3YWl0IGJhc2Vjb2luLnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBwcnY6IHhwcnYsXG4gICAgICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgICAgIHR4SGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc3QgdHhCdWlsZGVyID0gYmFzZWNvaW4uZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgICAgICAgdHhCdWlsZGVyLmZyb20odHguaGFsZlNpZ25lZC50eEhleCk7XG4gICAgICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgICAgICBjb25zdCB0eEpzb24gPSB0cmFuc2FjdGlvbi50b0pzb24oKTtcbiAgICAgICAgICB0eEpzb24udG8uc2hvdWxkLmVxdWFsKGNvbnRyYWN0QWRkcmVzcyk7XG5cbiAgICAgICAgICBsZXQgZGVjb2RlZERhdGE7XG4gICAgICAgICAgbGV0IHJlY2lwaWVudDtcbiAgICAgICAgICBsZXQgdmFsdWU7XG4gICAgICAgICAgbGV0IGRhdGE7XG4gICAgICAgICAgbGV0IGV4cGlyZVRpbWU7XG4gICAgICAgICAgbGV0IHNlcXVlbmNlSWQ7XG4gICAgICAgICAgaWYgKGNvaW4gaW5zdGFuY2VvZiBDb250cmFjdEFkZHJlc3NEZWZpbmVkVG9rZW4pIHtcbiAgICAgICAgICAgIGRlY29kZWREYXRhID0gZXRoQWJpLnJhd0RlY29kZShzZW5kTXVsdGlzaWdUb2tlblR5cGVzLCBCdWZmZXIuZnJvbSh0eEpzb24uZGF0YS5zbGljZSgxMCksICdoZXgnKSk7XG4gICAgICAgICAgICBbcmVjaXBpZW50LCB2YWx1ZSAvKiB0b2tlbkNvbnRyYWN0QWRkcmVzcyAqLywgLCBleHBpcmVUaW1lLCBzZXF1ZW5jZUlkXSA9IGRlY29kZWREYXRhO1xuICAgICAgICAgICAgZGF0YSA9IEJ1ZmZlci5mcm9tKCcnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGVjb2RlZERhdGEgPSBldGhBYmkucmF3RGVjb2RlKHNlbmRNdWx0aXNpZ1R5cGVzLCBCdWZmZXIuZnJvbSh0eEpzb24uZGF0YS5zbGljZSgxMCksICdoZXgnKSk7XG4gICAgICAgICAgICBbcmVjaXBpZW50LCB2YWx1ZSwgZGF0YSwgZXhwaXJlVGltZSwgc2VxdWVuY2VJZF0gPSBkZWNvZGVkRGF0YTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBldGhVdGlsLmFkZEhleFByZWZpeChyZWNpcGllbnQpLnNob3VsZC5lcXVhbChkZXN0aW5hdGlvbik7XG4gICAgICAgICAgdmFsdWUudG9TdHJpbmcoMTApLnNob3VsZC5lcXVhbChhbW91bnQpO1xuICAgICAgICAgIGlucHV0RXhwaXJlVGltZS5zaG91bGQuZXF1YWwocGFyc2VJbnQoZXhwaXJlVGltZS50b1N0cmluZygnaGV4JyksIDE2KSk7XG4gICAgICAgICAgaW5wdXRTZXF1ZW5jZUlkLnNob3VsZC5lcXVhbChwYXJzZUludChzZXF1ZW5jZUlkLnRvU3RyaW5nKCdoZXgnKSwgMTYpKTtcbiAgICAgICAgICBkYXRhLmxlbmd0aC5zaG91bGQuZXF1YWwoMCk7XG5cbiAgICAgICAgICBjb25zdCByZWNvdmVyZWRBZGRyZXNzID0gcmVjb3ZlclNpZ25lcih0cmFuc2FjdGlvbik7XG4gICAgICAgICAgcmVjb3ZlcmVkQWRkcmVzcy5zaG91bGQuZXF1YWwoa2V5LmdldEFkZHJlc3MoKSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdzaG91bGQgc2lnbiBhIGhhbGYgc2lnbmVkIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGtleSA9IG5ldyBFdGguS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgICAgICBjb25zdCBkZXN0aW5hdGlvbiA9ICcweGZhYThmMTRmNDZhOTllYjQzOWM1MGUwYzNiODM1Y2MyMWRhZDUxYjQnO1xuICAgICAgICAgIGNvbnN0IGNvbnRyYWN0QWRkcmVzcyA9ICcweDllMmM1NzEyYWI0Y2FmNDAyYTk4YzRiZjU4Yzc5YTBkZmU3MThhZDEnO1xuICAgICAgICAgIGNvbnN0IGFtb3VudCA9ICcxMDAwMDAnO1xuICAgICAgICAgIGNvbnN0IGlucHV0RXhwaXJlVGltZSA9IE1hdGguZmxvb3IobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwKTtcbiAgICAgICAgICBjb25zdCBpbnB1dFNlcXVlbmNlSWQgPSAxO1xuXG4gICAgICAgICAgY29uc3QgdW5zaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJ1aWxkVW5zaWduZWRUcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBkZXN0aW5hdGlvbixcbiAgICAgICAgICAgIGNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICAgIGFtb3VudCxcbiAgICAgICAgICAgIGV4cGlyZVRpbWU6IGlucHV0RXhwaXJlVGltZSxcbiAgICAgICAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogaW5wdXRTZXF1ZW5jZUlkLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc3QgdHggPSBhd2FpdCBiYXNlY29pbi5zaWduVHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgcHJ2OiBrZXkuZ2V0S2V5cygpLnBydixcbiAgICAgICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICAgICAgdHhIZXg6IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBjb25zdCBmdWxseVNpZ25lZFR4ID0gYXdhaXQgYmFzZWNvaW4uc2lnblRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgIHBydjoga2V5LmdldEtleXMoKS5wcnYsXG4gICAgICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgICAgIHR4SGV4OiB0eC5oYWxmU2lnbmVkLnR4SGV4LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGZ1bGx5U2lnbmVkVHguaGFsZlNpZ25lZC5yZWNpcGllbnRzLmxlbmd0aC5zaG91bGQuZXF1YWwoMSk7XG4gICAgICAgICAgZnVsbHlTaWduZWRUeC5oYWxmU2lnbmVkLnJlY2lwaWVudHNbMF0uYWRkcmVzcy5zaG91bGQuZXF1YWwoZGVzdGluYXRpb24pO1xuICAgICAgICAgIGZ1bGx5U2lnbmVkVHguaGFsZlNpZ25lZC5yZWNpcGllbnRzWzBdLmFtb3VudC5zaG91bGQuZXF1YWwoYW1vdW50KTtcblxuICAgICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGJhc2Vjb2luLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgICAgICAgIHR4QnVpbGRlci5mcm9tKGZ1bGx5U2lnbmVkVHguaGFsZlNpZ25lZC50eEhleCk7XG4gICAgICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgICAgICBjb25zdCB0eEpzb24gPSB0cmFuc2FjdGlvbi50b0pzb24oKTtcbiAgICAgICAgICB0eEpzb24udG8uc2hvdWxkLmVxdWFsKGNvbnRyYWN0QWRkcmVzcyk7XG5cbiAgICAgICAgICBsZXQgZGVjb2RlZERhdGE7XG4gICAgICAgICAgbGV0IHJlY2lwaWVudDtcbiAgICAgICAgICBsZXQgdmFsdWU7XG4gICAgICAgICAgbGV0IGRhdGE7XG4gICAgICAgICAgbGV0IGV4cGlyZVRpbWU7XG4gICAgICAgICAgbGV0IHNlcXVlbmNlSWQ7XG4gICAgICAgICAgaWYgKGNvaW4gaW5zdGFuY2VvZiBDb250cmFjdEFkZHJlc3NEZWZpbmVkVG9rZW4pIHtcbiAgICAgICAgICAgIGRlY29kZWREYXRhID0gZXRoQWJpLnJhd0RlY29kZShzZW5kTXVsdGlzaWdUb2tlblR5cGVzLCBCdWZmZXIuZnJvbSh0eEpzb24uZGF0YS5zbGljZSgxMCksICdoZXgnKSk7XG4gICAgICAgICAgICBbcmVjaXBpZW50LCB2YWx1ZSAvKiB0b2tlbkNvbnRyYWN0QWRkcmVzcyAqLywgLCBleHBpcmVUaW1lLCBzZXF1ZW5jZUlkXSA9IGRlY29kZWREYXRhO1xuICAgICAgICAgICAgZGF0YSA9IEJ1ZmZlci5mcm9tKCcnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGVjb2RlZERhdGEgPSBldGhBYmkucmF3RGVjb2RlKHNlbmRNdWx0aXNpZ1R5cGVzLCBCdWZmZXIuZnJvbSh0eEpzb24uZGF0YS5zbGljZSgxMCksICdoZXgnKSk7XG4gICAgICAgICAgICBbcmVjaXBpZW50LCB2YWx1ZSwgZGF0YSwgZXhwaXJlVGltZSwgc2VxdWVuY2VJZF0gPSBkZWNvZGVkRGF0YTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBldGhVdGlsLmFkZEhleFByZWZpeChyZWNpcGllbnQpLnNob3VsZC5lcXVhbChkZXN0aW5hdGlvbik7XG4gICAgICAgICAgdmFsdWUudG9TdHJpbmcoMTApLnNob3VsZC5lcXVhbChhbW91bnQpO1xuICAgICAgICAgIGlucHV0RXhwaXJlVGltZS5zaG91bGQuZXF1YWwocGFyc2VJbnQoZXhwaXJlVGltZS50b1N0cmluZygnaGV4JyksIDE2KSk7XG4gICAgICAgICAgaW5wdXRTZXF1ZW5jZUlkLnNob3VsZC5lcXVhbChwYXJzZUludChzZXF1ZW5jZUlkLnRvU3RyaW5nKCdoZXgnKSwgMTYpKTtcbiAgICAgICAgICBkYXRhLmxlbmd0aC5zaG91bGQuZXF1YWwoMCk7XG5cbiAgICAgICAgICBjb25zdCByZWNvdmVyZWRBZGRyZXNzID0gcmVjb3ZlclNpZ25lcih0cmFuc2FjdGlvbik7XG4gICAgICAgICAgcmVjb3ZlcmVkQWRkcmVzcy5zaG91bGQuZXF1YWwoa2V5LmdldEFkZHJlc3MoKSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdzaG91bGQgZmFpbCB0byBzaWduIHRyYW5zYWN0aW9uIHdpdGggaW52YWxpZCB0eCBoZXgnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3Qga2V5ID0gbmV3IEV0aC5LZXlQYWlyKHsgcHJ2OiB4cHJ2IH0pO1xuICAgICAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgICAgICAuc2lnblRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgICAgcHJ2OiBrZXkuZ2V0S2V5cygpLnBydixcbiAgICAgICAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgICAgICAgIHR4SGV4OiAnMHhpbnZhbGlkJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCdFeHBsYWluIHRyYW5zYWN0aW9uOicsICgpID0+IHtcbiAgICAgICAgY29uc3QgeHBydiA9XG4gICAgICAgICAgJ3hwcnY5czIxWnJRSDE0M0szRDhUWGZ2QUpnSFZmVEVlUU5XNVlzOXdadG5VWmtxUHpGelNqYkVKcldDMXZaNEduWEN2UjdyUUwyVUZYM1JTdVllVTlNckVSbTFYQnZBQ293N2MzNnZuejVpWXlqMic7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBmYWlsIGlmIHRoZSBwYXJhbXMgb2JqZWN0IGlzIG1pc3NpbmcgcGFyYW1ldGVycycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBleHBsYWluUGFyYW1zID0ge1xuICAgICAgICAgICAgZmVlSW5mbzogeyBmZWU6IDEgfSxcbiAgICAgICAgICAgIHR4SGV4OiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgICAgYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKGV4cGxhaW5QYXJhbXMpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ21pc3NpbmcgZXhwbGFpbiB0eCBwYXJhbWV0ZXJzJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdleHBsYWluIGFuIHVuc2lnbmVkIHRyYW5zZmVyIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGRlc3RpbmF0aW9uID0gJzB4ZmFhOGYxNGY0NmE5OWViNDM5YzUwZTBjM2I4MzVjYzIxZGFkNTFiNCc7XG4gICAgICAgICAgY29uc3QgY29udHJhY3RBZGRyZXNzID0gJzB4OWUyYzU3MTJhYjRjYWY0MDJhOThjNGJmNThjNzlhMGRmZTcxOGFkMSc7XG5cbiAgICAgICAgICBjb25zdCB1bnNpZ25lZFRyYW5zYWN0aW9uID0gYXdhaXQgYnVpbGRVbnNpZ25lZFRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgIGRlc3RpbmF0aW9uLFxuICAgICAgICAgICAgY29udHJhY3RBZGRyZXNzLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc3QgZXhwbGFpblBhcmFtcyA9IHtcbiAgICAgICAgICAgIGhhbGZTaWduZWQ6IHtcbiAgICAgICAgICAgICAgdHhIZXg6IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmZWVJbmZvOiB7IGZlZTogMSB9LFxuICAgICAgICAgIH07XG4gICAgICAgICAgY29uc3QgZXhwbGFuYXRpb24gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oZXhwbGFpblBhcmFtcyk7XG4gICAgICAgICAgc2hvdWxkLmV4aXN0KGV4cGxhbmF0aW9uLmlkKTtcbiAgICAgICAgICAvLyBUT0RPIGNoZWNrIG90aGVyIGZpZWxkcyBvbmNlIGFjY291bnQtbGliIHByb3Blcmx5IGV4cGxhaW5zIHRyYW5zYWN0aW9uXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdleHBsYWluIGEgc2lnbmVkIHRyYW5zZmVyIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGtleSA9IG5ldyBFdGguS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgICAgICBjb25zdCBkZXN0aW5hdGlvbiA9ICcweGZhYThmMTRmNDZhOTllYjQzOWM1MGUwYzNiODM1Y2MyMWRhZDUxYjQnO1xuICAgICAgICAgIGNvbnN0IGNvbnRyYWN0QWRkcmVzcyA9ICcweDllMmM1NzEyYWI0Y2FmNDAyYTk4YzRiZjU4Yzc5YTBkZmU3MThhZDEnO1xuXG4gICAgICAgICAgY29uc3QgdW5zaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJ1aWxkVW5zaWduZWRUcmFuc2FjdGlvbih7XG4gICAgICAgICAgICBkZXN0aW5hdGlvbixcbiAgICAgICAgICAgIGNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IHNpZ25lZFR4ID0gYXdhaXQgYmFzZWNvaW4uc2lnblRyYW5zYWN0aW9uKHtcbiAgICAgICAgICAgIHBydjoga2V5LmdldEtleXMoKS5wcnYsXG4gICAgICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgICAgIHR4SGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc3QgZXhwbGFpblBhcmFtcyA9IHtcbiAgICAgICAgICAgIHR4SGV4OiBzaWduZWRUeC5oYWxmU2lnbmVkLnR4SGV4LFxuICAgICAgICAgICAgZmVlSW5mbzogeyBmZWU6IDEgfSxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IGV4cGxhbmF0aW9uID0gYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKGV4cGxhaW5QYXJhbXMpO1xuICAgICAgICAgIHNob3VsZC5leGlzdChleHBsYW5hdGlvbi5pZCk7XG4gICAgICAgICAgLy8gVE9ETyBjaGVjayBvdGhlciBmaWVsZHMgb25jZSBhY2NvdW50LWxpYiBwcm9wZXJseSBleHBsYWlucyB0cmFuc2FjdGlvblxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19

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


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