PHP WebShell

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

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

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const sdk_core_1 = require("@bitgo/sdk-core");
const statics_1 = require("@bitgo/statics");
const ethereumjs_abi_1 = __importDefault(require("ethereumjs-abi"));
const assert_1 = __importDefault(require("assert"));
const should_1 = __importDefault(require("should"));
const ethUtil = __importStar(require("ethereumjs-util"));
const src_1 = require("../../../src");
const testData = __importStar(require("../../resources/eth"));
const getBuilder_1 = require("../getBuilder");
describe('Eth transaction builder send', () => {
    it('should validate a send type transaction', () => {
        const txBuilder = (0, getBuilder_1.getBuilder)('teth');
        const coinConfig = statics_1.coins.get('eth');
        const common = (0, src_1.getCommon)(coinConfig.network);
        const tx = new src_1.Transaction(coinConfig, common);
        txBuilder.counter(1);
        txBuilder.type(sdk_core_1.TransactionType.Send);
        assert_1.default.throws(() => txBuilder.validateTransaction(tx), /Invalid transaction: missing fee/);
        txBuilder.fee({
            fee: '10',
            gasLimit: '1000',
        });
        assert_1.default.throws(() => txBuilder.validateTransaction(tx), /Invalid transaction: missing contract address/);
        assert_1.default.throws(() => txBuilder.validateTransaction(tx), /Invalid transaction: missing contract address/);
    });
    describe('should sign and build', () => {
        let txBuilder;
        let key;
        let contractAddress;
        const getOperationHash = function (tx) {
            const { data } = tx.toJson();
            const { tokenContractAddress, expireTime, sequenceId, amount, to } = (0, src_1.decodeTransferData)(data);
            const operationParams = [
                ['string', 'address', 'uint', 'address', 'uint', 'uint'],
                [
                    'ERC20',
                    new ethUtil.BN(ethUtil.stripHexPrefix(to), 16),
                    amount,
                    new ethUtil.BN(ethUtil.stripHexPrefix(tokenContractAddress || ''), 16),
                    expireTime,
                    sequenceId,
                ],
            ];
            return ethereumjs_abi_1.default.soliditySHA3(...operationParams);
        };
        beforeEach(() => {
            contractAddress = '0x8f977e912ef500548a0c3be6ddde9899f1199b81';
            txBuilder = (0, getBuilder_1.getBuilder)('hteth');
            key = testData.KEYPAIR_PRV.getKeys().prv;
            txBuilder.fee({
                fee: '1000000000',
                gasLimit: '12100000',
            });
            txBuilder.counter(2);
            txBuilder.type(sdk_core_1.TransactionType.Send);
            txBuilder.contract(contractAddress);
        });
        it('a send funds transaction', async () => {
            const recipient = '0x19645032c7f1533395d44a629462e751084d3e4c';
            const amount = '1000000000';
            const expireTime = 1590066728;
            const sequenceId = 5;
            txBuilder
                .transfer()
                .amount(amount)
                .to(recipient)
                .expirationTime(expireTime)
                .contractSequenceId(sequenceId)
                .key(key);
            txBuilder.sign({ key: testData.PRIVATE_KEY });
            const tx = await txBuilder.build();
            should_1.default.equal(tx.toJson().chainId, 17000);
            should_1.default.equal(tx.toBroadcastFormat(), testData.SEND_TX_BROADCAST_LEGACY);
            should_1.default.equal(tx.signature.length, 2);
            should_1.default.equal(tx.inputs.length, 1);
            should_1.default.equal(tx.inputs[0].address, contractAddress);
            should_1.default.equal(tx.inputs[0].value, amount);
            should_1.default.equal(tx.outputs.length, 1);
            should_1.default.equal(tx.outputs[0].address, recipient);
            should_1.default.equal(tx.outputs[0].value, amount);
            const data = tx.toJson().data;
            const { to, amount: parsedAmount, expireTime: parsedExpireTime, sequenceId: parsedSequenceId, } = (0, src_1.decodeTransferData)(data);
            should_1.default.equal(to, recipient);
            should_1.default.equal(parsedAmount, amount);
            should_1.default.equal(parsedExpireTime, expireTime);
            should_1.default.equal(parsedSequenceId, sequenceId);
        });
        it('a send funds transaction built for a first signer', async () => {
            const recipient = '0x19645032c7f1533395d44a629462e751084d3e4c';
            const amount = '1000000000';
            const expireTime = 1590066728;
            const sequenceId = 5;
            txBuilder.fee({
                eip1559: {
                    maxFeePerGas: '100',
                    maxPriorityFeePerGas: '10',
                },
                fee: '10',
                gasLimit: '1000',
            });
            const transfer = txBuilder.transfer();
            transfer
                .amount(amount)
                .to(recipient)
                .expirationTime(expireTime)
                .contractSequenceId(sequenceId)
                .isFirstSigner(true);
            const tx = await txBuilder.build();
            const methodId = ethereumjs_abi_1.default.methodID('sendMultiSig', src_1.sendMultiSigTypes);
            const decodedData = ethereumjs_abi_1.default.rawDecode(['string', 'address', 'uint', 'bytes', 'uint', 'uint'], Buffer.from(ethUtil.stripHexPrefix(tx.toJson().data).slice(methodId.toString('hex').length, -2), 'hex'));
            should_1.default.equal(decodedData[0], 'ETHER');
            should_1.default.equal(decodedData[1], ethUtil.stripHexPrefix(recipient));
            should_1.default.equal(decodedData[2].toString(), amount);
            should_1.default.equal(decodedData[3].toString('hex'), '');
            should_1.default.equal(decodedData[4].toString(), expireTime);
            should_1.default.equal(decodedData[5].toString(), sequenceId);
            should_1.default.equal(tx.toJson().chainId, 17000);
            should_1.default.equal(tx.toBroadcastFormat(), testData.SEND_TX_BROADCAST_RECOVERY);
            should_1.default.equal(tx.signature.length, 0);
            should_1.default.equal(tx.inputs.length, 1);
            should_1.default.equal(tx.inputs[0].address, contractAddress);
            should_1.default.equal(tx.inputs[0].value, amount);
            should_1.default.equal(tx.outputs.length, 1);
            should_1.default.equal(tx.outputs[0].address, recipient);
            should_1.default.equal(tx.outputs[0].value, amount);
            const data = tx.toJson().data;
            const { to, amount: parsedAmount, expireTime: parsedExpireTime, sequenceId: parsedSequenceId, } = (0, src_1.decodeTransferData)(data, true);
            should_1.default.equal(to, recipient);
            should_1.default.equal(parsedAmount, amount);
            should_1.default.equal(parsedExpireTime, expireTime);
            should_1.default.equal(parsedSequenceId, sequenceId);
            // Add signature from first signer
            transfer.setSignature('0x1234567890abcdef').isFirstSigner(false);
            const signedTx = await txBuilder.build();
            const { to: toSigned, amount: parsedAmountSigned, expireTime: parsedExpireTimeSigned, sequenceId: parsedSequenceIdSigned, signature, } = (0, src_1.decodeTransferData)(signedTx.toJson().data);
            should_1.default.equal(toSigned, recipient);
            should_1.default.equal(parsedAmountSigned, amount);
            should_1.default.equal(parsedExpireTimeSigned, expireTime);
            should_1.default.equal(parsedSequenceIdSigned, sequenceId);
            should_1.default.equal(signature, '0x1234567890abcdef');
            const fromSerializedTxBuilder = (0, getBuilder_1.getBuilder)('hteth');
            fromSerializedTxBuilder.from(testData.SEND_TX_BROADCAST_RECOVERY, true);
            const fromSerializedTx = await fromSerializedTxBuilder.build();
            const { to: toFromSerialized, amount: amountFromSerialized, expireTime: expireTimeFromSerialized, sequenceId: sequenceIdFromSerialized, } = (0, src_1.decodeTransferData)(fromSerializedTx.toJson().data, true);
            should_1.default.equal(toFromSerialized, recipient);
            should_1.default.equal(amountFromSerialized, amount);
            should_1.default.equal(expireTimeFromSerialized, expireTime);
            should_1.default.equal(sequenceIdFromSerialized, sequenceId);
        });
        it('should send funds for wallet version 4', async () => {
            const recipient = '0x19645032c7f1533395d44a629462e751084d3e4c';
            const amount = '1000000000';
            const expireTime = 1590066728;
            const sequenceId = 5;
            txBuilder.walletVersion(4);
            txBuilder
                .transfer()
                .amount(amount)
                .to(recipient)
                .expirationTime(expireTime)
                .contractSequenceId(sequenceId)
                .key(key);
            txBuilder.sign({ key: testData.PRIVATE_KEY });
            await txBuilder.build();
            const operationData = txBuilder.transfer().getOperationData();
            should_1.default.equal(operationData[1][0], '17000');
            should_1.default.equal(txBuilder.coinUsesNonPackedEncodingForTxData(), true);
        });
        it('a send funds with amount 0 transaction', async () => {
            txBuilder
                .transfer()
                .amount('0')
                .to('0x19645032c7f1533395d44a629462e751084d3e4c')
                .expirationTime(1590066728)
                .contractSequenceId(5)
                .key(key);
            txBuilder.sign({ key: testData.PRIVATE_KEY });
            const tx = await txBuilder.build();
            should_1.default.equal(tx.toBroadcastFormat(), testData.SEND_TX_AMOUNT_ZERO_BROADCAST);
        });
        it('Goerli chain id should be correct', async () => {
            const txBuilder = (0, getBuilder_1.getBuilder)('gteth');
            txBuilder.fee({
                fee: '1000000000',
                gasLimit: '12100000',
            });
            txBuilder.counter(2);
            txBuilder.type(sdk_core_1.TransactionType.Send);
            txBuilder.contract(contractAddress);
            const transferBuilder = txBuilder.transfer();
            transferBuilder
                .amount('0')
                .to('0x19645032c7f1533395d44a629462e751084d3e4c')
                .expirationTime(1590066728)
                .contractSequenceId(5)
                .key(key);
            txBuilder.sign({ key: testData.PRIVATE_KEY });
            const tx = await txBuilder.build();
            should_1.default.equal(tx.toJson().chainId, 5);
        });
        it('Holesky chain id should be correct', async () => {
            const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
            txBuilder.fee({
                fee: '1000000000',
                gasLimit: '12100000',
            });
            txBuilder.counter(2);
            txBuilder.type(sdk_core_1.TransactionType.Send);
            txBuilder.contract(contractAddress);
            const transferBuilder = txBuilder.transfer();
            transferBuilder
                .amount('0')
                .to('0x19645032c7f1533395d44a629462e751084d3e4c')
                .expirationTime(1590066728)
                .contractSequenceId(5)
                .key(key);
            txBuilder.sign({ key: testData.PRIVATE_KEY });
            const tx = await txBuilder.build();
            should_1.default.equal(tx.toJson().chainId, 17000);
        });
        it('a send token transaction', async () => {
            const recipient = '0x72c2c8e08bf91d755cd7d26b49a2ee3dc99de1b9';
            const contractAddress = '0xdf7decb1baa8f529f0c8982cbb4be50357195299';
            const amount = '100';
            txBuilder.contract(contractAddress);
            txBuilder
                .transfer()
                .coin('trif')
                .amount(amount)
                .to(recipient)
                .expirationTime(1590066728)
                .contractSequenceId(5)
                .key(key);
            txBuilder.sign({
                key: testData.PRIVATE_KEY,
            });
            const tx = await txBuilder.build();
            should_1.default.equal(tx.toBroadcastFormat(), testData.SEND_TOKEN_TX_BROADCAST);
            should_1.default.equal(tx.signature.length, 2);
            should_1.default.equal(tx.inputs.length, 1);
            should_1.default.equal(tx.inputs[0].address, contractAddress);
            should_1.default.equal(tx.inputs[0].value, amount);
            should_1.default.equal(tx.inputs[0].coin, 'trif');
            should_1.default.equal(tx.outputs.length, 1);
            should_1.default.equal(tx.outputs[0].address, recipient);
            should_1.default.equal(tx.outputs[0].value, amount);
            should_1.default.equal(tx.outputs[0].coin, 'trif');
            const { signature } = (0, src_1.decodeTransferData)(tx.toJson().data);
            const operationHash = getOperationHash(tx);
            const { v, r, s } = ethUtil.fromRpcSig(signature);
            const senderPubKey = ethUtil.ecrecover(Buffer.from(operationHash, 'hex'), v, r, s);
            const senderAddress = ethUtil.pubToAddress(senderPubKey);
            const senderKey = new src_1.KeyPair({ prv: testData.PRIVATE_KEY });
            ethUtil.bufferToHex(senderAddress).should.equal(senderKey.getAddress());
        });
        it('a send token transactions from serialized', async () => {
            const txBuilder = new src_1.TransactionBuilder(statics_1.coins.get('hteth'));
            txBuilder.from(testData.SEND_TOKEN_TX_BROADCAST);
            const tx = await txBuilder.build();
            should_1.default.equal(tx.toBroadcastFormat(), testData.SEND_TOKEN_TX_BROADCAST);
            const { signature } = (0, src_1.decodeTransferData)(tx.toJson().data);
            const operationHash = getOperationHash(tx);
            const { v, r, s } = ethUtil.fromRpcSig(signature);
            const senderPubKey = ethUtil.ecrecover(Buffer.from(operationHash || ''), v, r, s);
            const senderAddress = ethUtil.pubToAddress(senderPubKey);
            const senderKey = new src_1.KeyPair({ prv: testData.PRIVATE_KEY });
            ethUtil.bufferToHex(senderAddress).should.equal(senderKey.getAddress());
        });
    });
    describe('sign and build from serialized', () => {
        {
            const testParams = [
                ['Legacy', testData.SEND_TX_BROADCAST_LEGACY],
                ['EIP1559', testData.SEND_TX_BROADCAST_EIP1559],
            ];
            testParams.map(([txnType, txnHex]) => {
                it(`should be able to create a send transaction from serialized ${txnType} tx hex`, async () => {
                    const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
                    txBuilder.from(txnHex);
                    const signedTx = await txBuilder.build();
                    should_1.default.equal(signedTx.toBroadcastFormat(), txnHex);
                });
            });
        }
        it('a send funds transaction with amount 0 from serialized', async () => {
            const txBuilder = (0, getBuilder_1.getBuilder)('hteth');
            txBuilder.from(testData.SEND_TX_AMOUNT_ZERO_BROADCAST);
            const signedTx = await txBuilder.build();
            should_1.default.equal(signedTx.toBroadcastFormat(), testData.SEND_TX_AMOUNT_ZERO_BROADCAST);
        });
    });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Rlc3QvdW5pdC90cmFuc2FjdGlvbkJ1aWxkZXIvc2VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDhDQUFtRTtBQUNuRSw0Q0FBd0Q7QUFDeEQsb0VBQXlDO0FBQ3pDLG9EQUE0QjtBQUM1QixvREFBNEI7QUFDNUIseURBQTJDO0FBRTNDLHNDQVFzQjtBQUN0Qiw4REFBZ0Q7QUFDaEQsOENBQTJDO0FBRTNDLFFBQVEsQ0FBQyw4QkFBOEIsRUFBRSxHQUFHLEVBQUU7SUFDNUMsRUFBRSxDQUFDLHlDQUF5QyxFQUFFLEdBQUcsRUFBRTtRQUNqRCxNQUFNLFNBQVMsR0FBRyxJQUFBLHVCQUFVLEVBQUMsTUFBTSxDQUF1QixDQUFDO1FBQzNELE1BQU0sVUFBVSxHQUFHLGVBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDcEMsTUFBTSxNQUFNLEdBQUcsSUFBQSxlQUFTLEVBQUMsVUFBVSxDQUFDLE9BQTBCLENBQUMsQ0FBQztRQUNoRSxNQUFNLEVBQUUsR0FBRyxJQUFJLGlCQUFXLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQy9DLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDckIsU0FBUyxDQUFDLElBQUksQ0FBQywwQkFBZSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3JDLGdCQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsRUFBRSxrQ0FBa0MsQ0FBQyxDQUFDO1FBQzNGLFNBQVMsQ0FBQyxHQUFHLENBQUM7WUFDWixHQUFHLEVBQUUsSUFBSTtZQUNULFFBQVEsRUFBRSxNQUFNO1NBQ2pCLENBQUMsQ0FBQztRQUNILGdCQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFB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QUUsS0FBSyxJQUFJLEVBQUU7WUFDdEUsTUFBTSxTQUFTLEdBQUcsSUFBQSx1QkFBVSxFQUFDLE9BQU8sQ0FBdUIsQ0FBQztZQUM1RCxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQ3ZELE1BQU0sUUFBUSxHQUFHLE1BQU0sU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3pDLGdCQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLFFBQVEsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1FBQ3JGLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFRyYW5zYWN0aW9uVHlwZSwgQmFzZVRyYW5zYWN0aW9uIH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IGNvaW5zLCBFdGhlcmV1bU5ldHdvcmsgfSBmcm9tICdAYml0Z28vc3RhdGljcyc7XG5pbXBvcnQgRXRoZXJldW1BYmkgZnJvbSAnZXRoZXJldW1qcy1hYmknO1xuaW1wb3J0IGFzc2VydCBmcm9tICdhc3NlcnQnO1xuaW1wb3J0IHNob3VsZCBmcm9tICdzaG91bGQnO1xuaW1wb3J0ICogYXMgZXRoVXRpbCBmcm9tICdldGhlcmV1bWpzLXV0aWwnO1xuXG5pbXBvcnQge1xuICBkZWNvZGVUcmFuc2ZlckRhdGEsXG4gIGdldENvbW1vbixcbiAgVHJhbnNhY3Rpb24sXG4gIFRyYW5zYWN0aW9uQnVpbGRlcixcbiAgVHJhbnNmZXJCdWlsZGVyLFxuICBLZXlQYWlyLFxuICBzZW5kTXVsdGlTaWdUeXBlcyxcbn0gZnJvbSAnLi4vLi4vLi4vc3JjJztcbmltcG9ydCAqIGFzIHRlc3REYXRhIGZyb20gJy4uLy4uL3Jlc291cmNlcy9ldGgnO1xuaW1wb3J0IHsgZ2V0QnVpbGRlciB9IGZyb20gJy4uL2dldEJ1aWxkZXInO1xuXG5kZXNjcmliZSgnRXRoIHRyYW5zYWN0aW9uIGJ1aWxkZXIgc2VuZCcsICgpID0+IHtcbiAgaXQoJ3Nob3VsZCB2YWxpZGF0ZSBhIHNlbmQgdHlwZSB0cmFuc2FjdGlvbicsICgpID0+IHtcbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBnZXRCdWlsZGVyKCd0ZXRoJykgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICAgIGNvbnN0IGNvaW5Db25maWcgPSBjb2lucy5nZXQoJ2V0aCcpO1xuICAgIGNvbnN0IGNvbW1vbiA9IGdldENvbW1vbihjb2luQ29uZmlnLm5ldHdvcmsgYXMgRXRoZXJldW1OZXR3b3JrKTtcbiAgICBjb25zdCB0eCA9IG5ldyBUcmFuc2FjdGlvbihjb2luQ29uZmlnLCBjb21tb24pO1xuICAgIHR4QnVpbGRlci5jb3VudGVyKDEpO1xuICAgIHR4QnVpbGRlci50eXBlKFRyYW5zYWN0aW9uVHlwZS5TZW5kKTtcbiAgICBhc3NlcnQudGhyb3dzKCgpID0+IHR4QnVpbGRlci52YWxpZGF0ZVRyYW5zYWN0aW9uKHR4KSwgL0ludmFsaWQgdHJhbnNhY3Rpb246IG1pc3NpbmcgZmVlLyk7XG4gICAgdHhCdWlsZGVyLmZlZSh7XG4gICAgICBmZWU6ICcxMCcsXG4gICAgICBnYXNMaW1pdDogJzEwMDAnLFxuICAgIH0pO1xuICAgIGFzc2VydC50aHJvd3MoKCkgPT4gdHhCdWlsZGVyLnZhbGlkYXRlVHJhbnNhY3Rpb24odHgpLCAvSW52YWxpZCB0cmFuc2FjdGlvbjogbWlzc2luZyBjb250cmFjdCBhZGRyZXNzLyk7XG4gICAgYXNzZXJ0LnRocm93cygoKSA9PiB0eEJ1aWxkZXIudmFsaWRhdGVUcmFuc2FjdGlvbih0eCksIC9JbnZhbGlkIHRyYW5zYWN0aW9uOiBtaXNzaW5nIGNvbnRyYWN0IGFkZHJlc3MvKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3Nob3VsZCBzaWduIGFuZCBidWlsZCcsICgpID0+IHtcbiAgICBsZXQgdHhCdWlsZGVyO1xuICAgIGxldCBrZXk7XG4gICAgbGV0IGNvbnRyYWN0QWRkcmVzcztcblxuICAgIGNvbnN0IGdldE9wZXJhdGlvbkhhc2ggPSBmdW5jdGlvbiAodHg6IEJhc2VUcmFuc2FjdGlvbik6IHN0cmluZyB7XG4gICAgICBjb25zdCB7IGRhdGEgfSA9IHR4LnRvSnNvbigpO1xuICAgICAgY29uc3QgeyB0b2tlbkNvbnRyYWN0QWRkcmVzcywgZXhwaXJlVGltZSwgc2VxdWVuY2VJZCwgYW1vdW50LCB0byB9ID0gZGVjb2RlVHJhbnNmZXJEYXRhKGRhdGEpO1xuICAgICAgY29uc3Qgb3BlcmF0aW9uUGFyYW1zID0gW1xuICAgICAgICBbJ3N0cmluZycsICdhZGRyZXNzJywgJ3VpbnQnLCAnYWRkcmVzcycsICd1aW50JywgJ3VpbnQnXSxcbiAgICAgICAgW1xuICAgICAgICAgICdFUkMyMCcsXG4gICAgICAgICAgbmV3IGV0aFV0aWwuQk4oZXRoVXRpbC5zdHJpcEhleFByZWZpeCh0byksIDE2KSxcbiAgICAgICAgICBhbW91bnQsXG4gICAgICAgICAgbmV3IGV0aFV0aWwuQk4oZXRoVXRpbC5zdHJpcEhleFByZWZpeCh0b2tlbkNvbnRyYWN0QWRkcmVzcyB8fCAnJyksIDE2KSxcbiAgICAgICAgICBleHBpcmVUaW1lLFxuICAgICAgICAgIHNlcXVlbmNlSWQsXG4gICAgICAgIF0sXG4gICAgICBdO1xuICAgICAgcmV0dXJuIEV0aGVyZXVtQWJpLnNvbGlkaXR5U0hBMyguLi5vcGVyYXRpb25QYXJhbXMpO1xuICAgIH07XG5cbiAgICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAgIGNvbnRyYWN0QWRkcmVzcyA9ICcweDhmOTc3ZTkxMmVmNTAwNTQ4YTBjM2JlNmRkZGU5ODk5ZjExOTliODEnO1xuICAgICAgdHhCdWlsZGVyID0gZ2V0QnVpbGRlcignaHRldGgnKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgICBrZXkgPSB0ZXN0RGF0YS5LRVlQQUlSX1BSVi5nZXRLZXlzKCkucHJ2IGFzIHN0cmluZztcbiAgICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgICBmZWU6ICcxMDAwMDAwMDAwJyxcbiAgICAgICAgZ2FzTGltaXQ6ICcxMjEwMDAwMCcsXG4gICAgICB9KTtcbiAgICAgIHR4QnVpbGRlci5jb3VudGVyKDIpO1xuICAgICAgdHhCdWlsZGVyLnR5cGUoVHJhbnNhY3Rpb25UeXBlLlNlbmQpO1xuICAgICAgdHhCdWlsZGVyLmNvbnRyYWN0KGNvbnRyYWN0QWRkcmVzcyk7XG4gICAgfSk7XG5cbiAgICBpdCgnYSBzZW5kIGZ1bmRzIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVjaXBpZW50ID0gJzB4MTk2NDUwMzJjN2YxNTMzMzk1ZDQ0YTYyOTQ2MmU3NTEwODRkM2U0Yyc7XG4gICAgICBjb25zdCBhbW91bnQgPSAnMTAwMDAwMDAwMCc7XG4gICAgICBjb25zdCBleHBpcmVUaW1lID0gMTU5MDA2NjcyODtcbiAgICAgIGNvbnN0IHNlcXVlbmNlSWQgPSA1O1xuICAgICAgdHhCdWlsZGVyXG4gICAgICAgIC50cmFuc2ZlcigpXG4gICAgICAgIC5hbW91bnQoYW1vdW50KVxuICAgICAgICAudG8ocmVjaXBpZW50KVxuICAgICAgICAuZXhwaXJhdGlvblRpbWUoZXhwaXJlVGltZSlcbiAgICAgICAgLmNvbnRyYWN0U2VxdWVuY2VJZChzZXF1ZW5jZUlkKVxuICAgICAgICAua2V5KGtleSk7XG4gICAgICB0eEJ1aWxkZXIuc2lnbih7IGtleTogdGVzdERhdGEuUFJJVkFURV9LRVkgfSk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgICBzaG91bGQuZXF1YWwodHgudG9Kc29uKCkuY2hhaW5JZCwgMTcwMDApO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksIHRlc3REYXRhLlNFTkRfVFhfQlJPQURDQVNUX0xFR0FDWSk7XG4gICAgICBzaG91bGQuZXF1YWwodHguc2lnbmF0dXJlLmxlbmd0aCwgMik7XG4gICAgICBzaG91bGQuZXF1YWwodHguaW5wdXRzLmxlbmd0aCwgMSk7XG4gICAgICBzaG91bGQuZXF1YWwodHguaW5wdXRzWzBdLmFkZHJlc3MsIGNvbnRyYWN0QWRkcmVzcyk7XG4gICAgICBzaG91bGQuZXF1YWwodHguaW5wdXRzWzBdLnZhbHVlLCBhbW91bnQpO1xuXG4gICAgICBzaG91bGQuZXF1YWwodHgub3V0cHV0cy5sZW5ndGgsIDEpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4Lm91dHB1dHNbMF0uYWRkcmVzcywgcmVjaXBpZW50KTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC5vdXRwdXRzWzBdLnZhbHVlLCBhbW91bnQpO1xuXG4gICAgICBjb25zdCBkYXRhID0gdHgudG9Kc29uKCkuZGF0YTtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgdG8sXG4gICAgICAgIGFtb3VudDogcGFyc2VkQW1vdW50LFxuICAgICAgICBleHBpcmVUaW1lOiBwYXJzZWRFeHBpcmVUaW1lLFxuICAgICAgICBzZXF1ZW5jZUlkOiBwYXJzZWRTZXF1ZW5jZUlkLFxuICAgICAgfSA9IGRlY29kZVRyYW5zZmVyRGF0YShkYXRhKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0bywgcmVjaXBpZW50KTtcbiAgICAgIHNob3VsZC5lcXVhbChwYXJzZWRBbW91bnQsIGFtb3VudCk7XG4gICAgICBzaG91bGQuZXF1YWwocGFyc2VkRXhwaXJlVGltZSwgZXhwaXJlVGltZSk7XG4gICAgICBzaG91bGQuZXF1YWwocGFyc2VkU2VxdWVuY2VJZCwgc2VxdWVuY2VJZCk7XG4gICAgfSk7XG5cbiAgICBpdCgnYSBzZW5kIGZ1bmRzIHRyYW5zYWN0aW9uIGJ1aWx0IGZvciBhIGZpcnN0IHNpZ25lcicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlY2lwaWVudCA9ICcweDE5NjQ1MDMyYzdmMTUzMzM5NWQ0NGE2Mjk0NjJlNzUxMDg0ZDNlNGMnO1xuICAgICAgY29uc3QgYW1vdW50ID0gJzEwMDAwMDAwMDAnO1xuICAgICAgY29uc3QgZXhwaXJlVGltZSA9IDE1OTAwNjY3Mjg7XG4gICAgICBjb25zdCBzZXF1ZW5jZUlkID0gNTtcbiAgICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgICBlaXAxNTU5OiB7XG4gICAgICAgICAgbWF4RmVlUGVyR2FzOiAnMTAwJyxcbiAgICAgICAgICBtYXhQcmlvcml0eUZlZVBlckdhczogJzEwJyxcbiAgICAgICAgfSxcbiAgICAgICAgZmVlOiAnMTAnLFxuICAgICAgICBnYXNMaW1pdDogJzEwMDAnLFxuICAgICAgfSk7XG4gICAgICBjb25zdCB0cmFuc2ZlcjogVHJhbnNmZXJCdWlsZGVyID0gdHhCdWlsZGVyLnRyYW5zZmVyKCk7XG4gICAgICB0cmFuc2ZlclxuICAgICAgICAuYW1vdW50KGFtb3VudClcbiAgICAgICAgLnRvKHJlY2lwaWVudClcbiAgICAgICAgLmV4cGlyYXRpb25UaW1lKGV4cGlyZVRpbWUpXG4gICAgICAgIC5jb250cmFjdFNlcXVlbmNlSWQoc2VxdWVuY2VJZClcbiAgICAgICAgLmlzRmlyc3RTaWduZXIodHJ1ZSk7XG4gICAgICBjb25zdCB0eDogVHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcblxuICAgICAgY29uc3QgbWV0aG9kSWQgPSBFdGhlcmV1bUFiaS5tZXRob2RJRCgnc2VuZE11bHRpU2lnJywgc2VuZE11bHRpU2lnVHlwZXMpO1xuICAgICAgY29uc3QgZGVjb2RlZERhdGEgPSBFdGhlcmV1bUFiaS5yYXdEZWNvZGUoXG4gICAgICAgIFsnc3RyaW5nJywgJ2FkZHJlc3MnLCAndWludCcsICdieXRlcycsICd1aW50JywgJ3VpbnQnXSxcbiAgICAgICAgQnVmZmVyLmZyb20oZXRoVXRpbC5zdHJpcEhleFByZWZpeCh0eC50b0pzb24oKS5kYXRhKS5zbGljZShtZXRob2RJZC50b1N0cmluZygnaGV4JykubGVuZ3RoLCAtMiksICdoZXgnKVxuICAgICAgKTtcblxuICAgICAgc2hvdWxkLmVxdWFsKGRlY29kZWREYXRhWzBdLCAnRVRIRVInKTtcbiAgICAgIHNob3VsZC5lcXVhbChkZWNvZGVkRGF0YVsxXSwgZXRoVXRpbC5zdHJpcEhleFByZWZpeChyZWNpcGllbnQpKTtcbiAgICAgIHNob3VsZC5lcXVhbChkZWNvZGVkRGF0YVsyXS50b1N0cmluZygpLCBhbW91bnQpO1xuICAgICAgc2hvdWxkLmVxdWFsKGRlY29kZWREYXRhWzNdLnRvU3RyaW5nKCdoZXgnKSwgJycpO1xuICAgICAgc2hvdWxkLmVxdWFsKGRlY29kZWREYXRhWzRdLnRvU3RyaW5nKCksIGV4cGlyZVRpbWUpO1xuICAgICAgc2hvdWxkLmVxdWFsKGRlY29kZWREYXRhWzVdLnRvU3RyaW5nKCksIHNlcXVlbmNlSWQpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4LnRvSnNvbigpLmNoYWluSWQsIDE3MDAwKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC50b0Jyb2FkY2FzdEZvcm1hdCgpLCB0ZXN0RGF0YS5TRU5EX1RYX0JST0FEQ0FTVF9SRUNPVkVSWSk7XG4gICAgICBzaG91bGQuZXF1YWwodHguc2lnbmF0dXJlLmxlbmd0aCwgMCk7XG4gICAgICBzaG91bGQuZXF1YWwodHguaW5wdXRzLmxlbmd0aCwgMSk7XG4gICAgICBzaG91bGQuZXF1YWwodHguaW5wdXRzWzBdLmFkZHJlc3MsIGNvbnRyYWN0QWRkcmVzcyk7XG4gICAgICBzaG91bGQuZXF1YWwodHguaW5wdXRzWzBdLnZhbHVlLCBhbW91bnQpO1xuXG4gICAgICBzaG91bGQuZXF1YWwodHgub3V0cHV0cy5sZW5ndGgsIDEpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4Lm91dHB1dHNbMF0uYWRkcmVzcywgcmVjaXBpZW50KTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC5vdXRwdXRzWzBdLnZhbHVlLCBhbW91bnQpO1xuXG4gICAgICBjb25zdCBkYXRhID0gdHgudG9Kc29uKCkuZGF0YTtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgdG8sXG4gICAgICAgIGFtb3VudDogcGFyc2VkQW1vdW50LFxuICAgICAgICBleHBpcmVUaW1lOiBwYXJzZWRFeHBpcmVUaW1lLFxuICAgICAgICBzZXF1ZW5jZUlkOiBwYXJzZWRTZXF1ZW5jZUlkLFxuICAgICAgfSA9IGRlY29kZVRyYW5zZmVyRGF0YShkYXRhLCB0cnVlKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0bywgcmVjaXBpZW50KTtcbiAgICAgIHNob3VsZC5lcXVhbChwYXJzZWRBbW91bnQsIGFtb3VudCk7XG4gICAgICBzaG91bGQuZXF1YWwocGFyc2VkRXhwaXJlVGltZSwgZXhwaXJlVGltZSk7XG4gICAgICBzaG91bGQuZXF1YWwocGFyc2VkU2VxdWVuY2VJZCwgc2VxdWVuY2VJZCk7XG4gICAgICAvLyBBZGQgc2lnbmF0dXJlIGZyb20gZmlyc3Qgc2lnbmVyXG4gICAgICB0cmFuc2Zlci5zZXRTaWduYXR1cmUoJzB4MTIzNDU2Nzg5MGFiY2RlZicpLmlzRmlyc3RTaWduZXIoZmFsc2UpO1xuICAgICAgY29uc3Qgc2lnbmVkVHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgdG86IHRvU2lnbmVkLFxuICAgICAgICBhbW91bnQ6IHBhcnNlZEFtb3VudFNpZ25lZCxcbiAgICAgICAgZXhwaXJlVGltZTogcGFyc2VkRXhwaXJlVGltZVNpZ25lZCxcbiAgICAgICAgc2VxdWVuY2VJZDogcGFyc2VkU2VxdWVuY2VJZFNpZ25lZCxcbiAgICAgICAgc2lnbmF0dXJlLFxuICAgICAgfSA9IGRlY29kZVRyYW5zZmVyRGF0YShzaWduZWRUeC50b0pzb24oKS5kYXRhKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0b1NpZ25lZCwgcmVjaXBpZW50KTtcbiAgICAgIHNob3VsZC5lcXVhbChwYXJzZWRBbW91bnRTaWduZWQsIGFtb3VudCk7XG4gICAgICBzaG91bGQuZXF1YWwocGFyc2VkRXhwaXJlVGltZVNpZ25lZCwgZXhwaXJlVGltZSk7XG4gICAgICBzaG91bGQuZXF1YWwocGFyc2VkU2VxdWVuY2VJZFNpZ25lZCwgc2VxdWVuY2VJZCk7XG4gICAgICBzaG91bGQuZXF1YWwoc2lnbmF0dXJlLCAnMHgxMjM0NTY3ODkwYWJjZGVmJyk7XG5cbiAgICAgIGNvbnN0IGZyb21TZXJpYWxpemVkVHhCdWlsZGVyID0gZ2V0QnVpbGRlcignaHRldGgnKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgICBmcm9tU2VyaWFsaXplZFR4QnVpbGRlci5mcm9tKHRlc3REYXRhLlNFTkRfVFhfQlJPQURDQVNUX1JFQ09WRVJZLCB0cnVlKTtcbiAgICAgIGNvbnN0IGZyb21TZXJpYWxpemVkVHggPSBhd2FpdCBmcm9tU2VyaWFsaXplZFR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgY29uc3Qge1xuICAgICAgICB0bzogdG9Gcm9tU2VyaWFsaXplZCxcbiAgICAgICAgYW1vdW50OiBhbW91bnRGcm9tU2VyaWFsaXplZCxcbiAgICAgICAgZXhwaXJlVGltZTogZXhwaXJlVGltZUZyb21TZXJpYWxpemVkLFxuICAgICAgICBzZXF1ZW5jZUlkOiBzZXF1ZW5jZUlkRnJvbVNlcmlhbGl6ZWQsXG4gICAgICB9ID0gZGVjb2RlVHJhbnNmZXJEYXRhKGZyb21TZXJpYWxpemVkVHgudG9Kc29uKCkuZGF0YSwgdHJ1ZSk7XG4gICAgICBzaG91bGQuZXF1YWwodG9Gcm9tU2VyaWFsaXplZCwgcmVjaXBpZW50KTtcbiAgICAgIHNob3VsZC5lcXVhbChhbW91bnRGcm9tU2VyaWFsaXplZCwgYW1vdW50KTtcbiAgICAgIHNob3VsZC5lcXVhbChleHBpcmVUaW1lRnJvbVNlcmlhbGl6ZWQsIGV4cGlyZVRpbWUpO1xuICAgICAgc2hvdWxkLmVxdWFsKHNlcXVlbmNlSWRGcm9tU2VyaWFsaXplZCwgc2VxdWVuY2VJZCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHNlbmQgZnVuZHMgZm9yIHdhbGxldCB2ZXJzaW9uIDQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZWNpcGllbnQgPSAnMHgxOTY0NTAzMmM3ZjE1MzMzOTVkNDRhNjI5NDYyZTc1MTA4NGQzZTRjJztcbiAgICAgIGNvbnN0IGFtb3VudCA9ICcxMDAwMDAwMDAwJztcbiAgICAgIGNvbnN0IGV4cGlyZVRpbWUgPSAxNTkwMDY2NzI4O1xuICAgICAgY29uc3Qgc2VxdWVuY2VJZCA9IDU7XG4gICAgICB0eEJ1aWxkZXIud2FsbGV0VmVyc2lvbig0KTtcbiAgICAgIHR4QnVpbGRlclxuICAgICAgICAudHJhbnNmZXIoKVxuICAgICAgICAuYW1vdW50KGFtb3VudClcbiAgICAgICAgLnRvKHJlY2lwaWVudClcbiAgICAgICAgLmV4cGlyYXRpb25UaW1lKGV4cGlyZVRpbWUpXG4gICAgICAgIC5jb250cmFjdFNlcXVlbmNlSWQoc2VxdWVuY2VJZClcbiAgICAgICAgLmtleShrZXkpO1xuICAgICAgdHhCdWlsZGVyLnNpZ24oeyBrZXk6IHRlc3REYXRhLlBSSVZBVEVfS0VZIH0pO1xuICAgICAgYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCBvcGVyYXRpb25EYXRhID0gdHhCdWlsZGVyLnRyYW5zZmVyKCkuZ2V0T3BlcmF0aW9uRGF0YSgpO1xuICAgICAgc2hvdWxkLmVxdWFsKG9wZXJhdGlvbkRhdGFbMV1bMF0sICcxNzAwMCcpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4QnVpbGRlci5jb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhKCksIHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ2Egc2VuZCBmdW5kcyB3aXRoIGFtb3VudCAwIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgdHhCdWlsZGVyXG4gICAgICAgIC50cmFuc2ZlcigpXG4gICAgICAgIC5hbW91bnQoJzAnKVxuICAgICAgICAudG8oJzB4MTk2NDUwMzJjN2YxNTMzMzk1ZDQ0YTYyOTQ2MmU3NTEwODRkM2U0YycpXG4gICAgICAgIC5leHBpcmF0aW9uVGltZSgxNTkwMDY2NzI4KVxuICAgICAgICAuY29udHJhY3RTZXF1ZW5jZUlkKDUpXG4gICAgICAgIC5rZXkoa2V5KTtcbiAgICAgIHR4QnVpbGRlci5zaWduKHsga2V5OiB0ZXN0RGF0YS5QUklWQVRFX0tFWSB9KTtcbiAgICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBzaG91bGQuZXF1YWwodHgudG9Ccm9hZGNhc3RGb3JtYXQoKSwgdGVzdERhdGEuU0VORF9UWF9BTU9VTlRfWkVST19CUk9BRENBU1QpO1xuICAgIH0pO1xuXG4gICAgaXQoJ0dvZXJsaSBjaGFpbiBpZCBzaG91bGQgYmUgY29ycmVjdCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGdldEJ1aWxkZXIoJ2d0ZXRoJykgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICAgICAgdHhCdWlsZGVyLmZlZSh7XG4gICAgICAgIGZlZTogJzEwMDAwMDAwMDAnLFxuICAgICAgICBnYXNMaW1pdDogJzEyMTAwMDAwJyxcbiAgICAgIH0pO1xuICAgICAgdHhCdWlsZGVyLmNvdW50ZXIoMik7XG4gICAgICB0eEJ1aWxkZXIudHlwZShUcmFuc2FjdGlvblR5cGUuU2VuZCk7XG4gICAgICB0eEJ1aWxkZXIuY29udHJhY3QoY29udHJhY3RBZGRyZXNzKTtcbiAgICAgIGNvbnN0IHRyYW5zZmVyQnVpbGRlciA9IHR4QnVpbGRlci50cmFuc2ZlcigpIGFzIFRyYW5zZmVyQnVpbGRlcjtcbiAgICAgIHRyYW5zZmVyQnVpbGRlclxuICAgICAgICAuYW1vdW50KCcwJylcbiAgICAgICAgLnRvKCcweDE5NjQ1MDMyYzdmMTUzMzM5NWQ0NGE2Mjk0NjJlNzUxMDg0ZDNlNGMnKVxuICAgICAgICAuZXhwaXJhdGlvblRpbWUoMTU5MDA2NjcyOClcbiAgICAgICAgLmNvbnRyYWN0U2VxdWVuY2VJZCg1KVxuICAgICAgICAua2V5KGtleSk7XG4gICAgICB0eEJ1aWxkZXIuc2lnbih7IGtleTogdGVzdERhdGEuUFJJVkFURV9LRVkgfSk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4LnRvSnNvbigpLmNoYWluSWQsIDUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ0hvbGVza3kgY2hhaW4gaWQgc2hvdWxkIGJlIGNvcnJlY3QnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBnZXRCdWlsZGVyKCdodGV0aCcpIGFzIFRyYW5zYWN0aW9uQnVpbGRlcjtcbiAgICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgICBmZWU6ICcxMDAwMDAwMDAwJyxcbiAgICAgICAgZ2FzTGltaXQ6ICcxMjEwMDAwMCcsXG4gICAgICB9KTtcbiAgICAgIHR4QnVpbGRlci5jb3VudGVyKDIpO1xuICAgICAgdHhCdWlsZGVyLnR5cGUoVHJhbnNhY3Rpb25UeXBlLlNlbmQpO1xuICAgICAgdHhCdWlsZGVyLmNvbnRyYWN0KGNvbnRyYWN0QWRkcmVzcyk7XG4gICAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSB0eEJ1aWxkZXIudHJhbnNmZXIoKSBhcyBUcmFuc2ZlckJ1aWxkZXI7XG4gICAgICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAgICAgLmFtb3VudCgnMCcpXG4gICAgICAgIC50bygnMHgxOTY0NTAzMmM3ZjE1MzMzOTVkNDRhNjI5NDYyZTc1MTA4NGQzZTRjJylcbiAgICAgICAgLmV4cGlyYXRpb25UaW1lKDE1OTAwNjY3MjgpXG4gICAgICAgIC5jb250cmFjdFNlcXVlbmNlSWQoNSlcbiAgICAgICAgLmtleShrZXkpO1xuICAgICAgdHhCdWlsZGVyLnNpZ24oeyBrZXk6IHRlc3REYXRhLlBSSVZBVEVfS0VZIH0pO1xuICAgICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC50b0pzb24oKS5jaGFpbklkLCAxNzAwMCk7XG4gICAgfSk7XG5cbiAgICBpdCgnYSBzZW5kIHRva2VuIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVjaXBpZW50ID0gJzB4NzJjMmM4ZTA4YmY5MWQ3NTVjZDdkMjZiNDlhMmVlM2RjOTlkZTFiOSc7XG4gICAgICBjb25zdCBjb250cmFjdEFkZHJlc3MgPSAnMHhkZjdkZWNiMWJhYThmNTI5ZjBjODk4MmNiYjRiZTUwMzU3MTk1Mjk5JztcbiAgICAgIGNvbnN0IGFtb3VudCA9ICcxMDAnO1xuICAgICAgdHhCdWlsZGVyLmNvbnRyYWN0KGNvbnRyYWN0QWRkcmVzcyk7XG4gICAgICB0eEJ1aWxkZXJcbiAgICAgICAgLnRyYW5zZmVyKClcbiAgICAgICAgLmNvaW4oJ3RyaWYnKVxuICAgICAgICAuYW1vdW50KGFtb3VudClcbiAgICAgICAgLnRvKHJlY2lwaWVudClcbiAgICAgICAgLmV4cGlyYXRpb25UaW1lKDE1OTAwNjY3MjgpXG4gICAgICAgIC5jb250cmFjdFNlcXVlbmNlSWQoNSlcbiAgICAgICAgLmtleShrZXkpO1xuICAgICAgdHhCdWlsZGVyLnNpZ24oe1xuICAgICAgICBrZXk6IHRlc3REYXRhLlBSSVZBVEVfS0VZLFxuICAgICAgfSk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksIHRlc3REYXRhLlNFTkRfVE9LRU5fVFhfQlJPQURDQVNUKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC5zaWduYXR1cmUubGVuZ3RoLCAyKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC5pbnB1dHMubGVuZ3RoLCAxKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC5pbnB1dHNbMF0uYWRkcmVzcywgY29udHJhY3RBZGRyZXNzKTtcbiAgICAgIHNob3VsZC5lcXVhbCh0eC5pbnB1dHNbMF0udmFsdWUsIGFtb3VudCk7XG4gICAgICBzaG91bGQuZXF1YWwodHguaW5wdXRzWzBdLmNvaW4sICd0cmlmJyk7XG5cbiAgICAgIHNob3VsZC5lcXVhbCh0eC5vdXRwdXRzLmxlbmd0aCwgMSk7XG4gICAgICBzaG91bGQuZXF1YWwodHgub3V0cHV0c1swXS5hZGRyZXNzLCByZWNpcGllbnQpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4Lm91dHB1dHNbMF0udmFsdWUsIGFtb3VudCk7XG4gICAgICBzaG91bGQuZXF1YWwodHgub3V0cHV0c1swXS5jb2luLCAndHJpZicpO1xuXG4gICAgICBjb25zdCB7IHNpZ25hdHVyZSB9ID0gZGVjb2RlVHJhbnNmZXJEYXRhKHR4LnRvSnNvbigpLmRhdGEpO1xuICAgICAgY29uc3Qgb3BlcmF0aW9uSGFzaCA9IGdldE9wZXJhdGlvbkhhc2godHgpO1xuXG4gICAgICBjb25zdCB7IHYsIHIsIHMgfSA9IGV0aFV0aWwuZnJvbVJwY1NpZyhzaWduYXR1cmUpO1xuICAgICAgY29uc3Qgc2VuZGVyUHViS2V5ID0gZXRoVXRpbC5lY3JlY292ZXIoQnVmZmVyLmZyb20ob3BlcmF0aW9uSGFzaCwgJ2hleCcpLCB2LCByLCBzKTtcbiAgICAgIGNvbnN0IHNlbmRlckFkZHJlc3MgPSBldGhVdGlsLnB1YlRvQWRkcmVzcyhzZW5kZXJQdWJLZXkpO1xuICAgICAgY29uc3Qgc2VuZGVyS2V5ID0gbmV3IEtleVBhaXIoeyBwcnY6IHRlc3REYXRhLlBSSVZBVEVfS0VZIH0pO1xuICAgICAgZXRoVXRpbC5idWZmZXJUb0hleChzZW5kZXJBZGRyZXNzKS5zaG91bGQuZXF1YWwoc2VuZGVyS2V5LmdldEFkZHJlc3MoKSk7XG4gICAgfSk7XG5cbiAgICBpdCgnYSBzZW5kIHRva2VuIHRyYW5zYWN0aW9ucyBmcm9tIHNlcmlhbGl6ZWQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyKGNvaW5zLmdldCgnaHRldGgnKSk7XG4gICAgICB0eEJ1aWxkZXIuZnJvbSh0ZXN0RGF0YS5TRU5EX1RPS0VOX1RYX0JST0FEQ0FTVCk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgc2hvdWxkLmVxdWFsKHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksIHRlc3REYXRhLlNFTkRfVE9LRU5fVFhfQlJPQURDQVNUKTtcblxuICAgICAgY29uc3QgeyBzaWduYXR1cmUgfSA9IGRlY29kZVRyYW5zZmVyRGF0YSh0eC50b0pzb24oKS5kYXRhKTtcbiAgICAgIGNvbnN0IG9wZXJhdGlvbkhhc2ggPSBnZXRPcGVyYXRpb25IYXNoKHR4KTtcblxuICAgICAgY29uc3QgeyB2LCByLCBzIH0gPSBldGhVdGlsLmZyb21ScGNTaWcoc2lnbmF0dXJlKTtcbiAgICAgIGNvbnN0IHNlbmRlclB1YktleSA9IGV0aFV0aWwuZWNyZWNvdmVyKEJ1ZmZlci5mcm9tKG9wZXJhdGlvbkhhc2ggfHwgJycpLCB2LCByLCBzKTtcbiAgICAgIGNvbnN0IHNlbmRlckFkZHJlc3MgPSBldGhVdGlsLnB1YlRvQWRkcmVzcyhzZW5kZXJQdWJLZXkpO1xuICAgICAgY29uc3Qgc2VuZGVyS2V5ID0gbmV3IEtleVBhaXIoeyBwcnY6IHRlc3REYXRhLlBSSVZBVEVfS0VZIH0pO1xuICAgICAgZXRoVXRpbC5idWZmZXJUb0hleChzZW5kZXJBZGRyZXNzKS5zaG91bGQuZXF1YWwoc2VuZGVyS2V5LmdldEFkZHJlc3MoKSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdzaWduIGFuZCBidWlsZCBmcm9tIHNlcmlhbGl6ZWQnLCAoKSA9PiB7XG4gICAge1xuICAgICAgY29uc3QgdGVzdFBhcmFtcyA9IFtcbiAgICAgICAgWydMZWdhY3knLCB0ZXN0RGF0YS5TRU5EX1RYX0JST0FEQ0FTVF9MRUdBQ1ldLFxuICAgICAgICBbJ0VJUDE1NTknLCB0ZXN0RGF0YS5TRU5EX1RYX0JST0FEQ0FTVF9FSVAxNTU5XSxcbiAgICAgIF07XG5cbiAgICAgIHRlc3RQYXJhbXMubWFwKChbdHhuVHlwZSwgdHhuSGV4XSkgPT4ge1xuICAgICAgICBpdChgc2hvdWxkIGJlIGFibGUgdG8gY3JlYXRlIGEgc2VuZCB0cmFuc2FjdGlvbiBmcm9tIHNlcmlhbGl6ZWQgJHt0eG5UeXBlfSB0eCBoZXhgLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgdHhCdWlsZGVyID0gZ2V0QnVpbGRlcignaHRldGgnKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgICAgICAgdHhCdWlsZGVyLmZyb20odHhuSGV4KTtcbiAgICAgICAgICBjb25zdCBzaWduZWRUeCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgICAgIHNob3VsZC5lcXVhbChzaWduZWRUeC50b0Jyb2FkY2FzdEZvcm1hdCgpLCB0eG5IZXgpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGl0KCdhIHNlbmQgZnVuZHMgdHJhbnNhY3Rpb24gd2l0aCBhbW91bnQgMCBmcm9tIHNlcmlhbGl6ZWQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBnZXRCdWlsZGVyKCdodGV0aCcpIGFzIFRyYW5zYWN0aW9uQnVpbGRlcjtcbiAgICAgIHR4QnVpbGRlci5mcm9tKHRlc3REYXRhLlNFTkRfVFhfQU1PVU5UX1pFUk9fQlJPQURDQVNUKTtcbiAgICAgIGNvbnN0IHNpZ25lZFR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBzaG91bGQuZXF1YWwoc2lnbmVkVHgudG9Ccm9hZGNhc3RGb3JtYXQoKSwgdGVzdERhdGEuU0VORF9UWF9BTU9VTlRfWkVST19CUk9BRENBU1QpO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19

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


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