PHP WebShell

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

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

"use strict";
//
// Tests for a Pending Approval
//
// Copyright 2015, BitGo, Inc.  All Rights Reserved.
//
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const assert_1 = require("assert");
require("should");
const utxolib = require("@bitgo/utxo-lib");
const BitGoJS = require('../../src/index');
const TestBitGo = require('../lib/test_bitgo');
const TestUtil = require('./testutil');
const Q = require('q');
describe('PendingApproval', function () {
    let bitgo;
    let bitgoSharedKeyUser;
    let bitgoThirdUser;
    let sharedWallet;
    /**
     * There is a 0-limit policy on the shared wallet
     * Create a pending approval by attempting to send coins
     */
    const createTransactionPendingApproval = function () {
        return sharedWallet
            .sendCoins({
            address: TestBitGo.TEST_WALLET2_ADDRESS,
            amount: 0.0001 * 1e8,
            walletPassphrase: TestBitGo.TEST_PASSWORD,
            otp: bitgo.testUserOTP(),
            message: 'never gonna',
        })
            .then(function (result) {
            result.should.have.property('pendingApproval');
            return bitgo.pendingApprovals().get({ id: result.pendingApproval });
        });
    };
    /**
     * There is a 0-limit policy on the shared wallet
     * Create a pending approval by attempting to send to many
     */
    const createTransactionPendingApprovalToMultipleRecipients = function () {
        return sharedWallet
            .sendMany({
            recipients: [
                {
                    address: TestBitGo.TEST_WALLET3_ADDRESS,
                    amount: 0.0002 * 1e8,
                },
                {
                    address: TestBitGo.TEST_WALLET2_ADDRESS,
                    amount: 0.0001 * 1e8,
                },
                {
                    address: TestBitGo.TEST_SHARED_WALLET_CHANGE_ADDRESS,
                    amount: 0.0005 * 1e8,
                },
            ],
            walletPassphrase: TestBitGo.TEST_PASSWORD,
            otp: bitgo.testUserOTP(),
            message: 'never gonna',
        })
            .then(function (result) {
            result.should.have.property('pendingApproval');
            return bitgo.pendingApprovals().get({ id: result.pendingApproval });
        });
    };
    /**
     * Create a pending approval by attempting to add a user to the wallet
     */
    const createPolicyPendingApproval = function () {
        // it's ok to set up any tx limit since the daily limit is 0
        return sharedWallet
            .updatePolicyRule({
            action: {
                type: 'getApproval',
            },
            condition: {
                amount: 1e8 + Math.round(Math.random() * 1e8),
            },
            id: 'com.bitgo.limit.tx',
            type: 'transactionLimit',
        })
            .then(function (result) {
            result.should.have.property('pendingApproval');
            return bitgo.pendingApprovals().get({ id: result.pendingApproval.id });
        });
    };
    before(function () {
        bitgo = new TestBitGo();
        bitgo.initializeTestVars();
        bitgoSharedKeyUser = new TestBitGo();
        bitgoSharedKeyUser.initializeTestVars();
        bitgoThirdUser = new TestBitGo();
        bitgoThirdUser.initializeTestVars();
        return bitgo
            .authenticateTestUser(bitgo.testUserOTP())
            .then(function () {
            return bitgoSharedKeyUser.authenticate({
                username: TestBitGo.TEST_SHARED_KEY_USER,
                password: TestBitGo.TEST_SHARED_KEY_PASSWORD,
                otp: bitgo.testUserOTP(),
            });
        })
            .then(function () {
            return bitgo.unlock({ otp: bitgo.testUserOTP() });
        })
            .then(function () {
            return bitgoSharedKeyUser.unlock({ otp: bitgo.testUserOTP() });
        })
            .then(function () {
            return bitgo.wallets().get({ id: TestBitGo.TEST_SHARED_WALLET_ADDRESS });
        })
            .then(function (result) {
            sharedWallet = result;
        });
    });
    describe('Create and Get', function () {
        let pendingApproval;
        before(function () {
            return createTransactionPendingApproval().then(function (result) {
                pendingApproval = result;
            });
        });
        after(function () {
            return pendingApproval.reject();
        });
        it('arguments', function () {
            assert_1.strict.throws(function () {
                bitgo.pendingApprovals().get({}, 'invalid');
            });
            assert_1.strict.throws(function () {
                bitgo.pendingApprovals().get('invalid');
            });
            assert_1.strict.throws(function () {
                bitgo.pendingApprovals().get({ id: 54321 }, 'invalid');
            });
        });
        it('get property methods', function () {
            pendingApproval.id().should.eql(pendingApproval.pendingApproval.id);
            pendingApproval.ownerType().should.eql('wallet');
            pendingApproval.walletId().should.eql(sharedWallet.id());
            assert_1.strict.equal(pendingApproval.enterpriseId(), undefined);
            pendingApproval.state().should.eql('pending');
            pendingApproval.creator().should.eql(TestBitGo.TEST_USERID);
            pendingApproval.type().should.eql('transactionRequest');
            pendingApproval.info().transactionRequest.message.should.eql('never gonna');
            pendingApproval.info().transactionRequest.destinationAddress.should.eql(TestBitGo.TEST_WALLET2_ADDRESS);
        });
        it('get', function () {
            pendingApproval.get({}).then(function (result) {
                pendingApproval = result;
                pendingApproval.id().should.eql(pendingApproval.pendingApproval.id);
                pendingApproval.ownerType().should.eql('wallet');
                pendingApproval.walletId().should.eql(sharedWallet.id());
                assert_1.strict.equal(pendingApproval.enterpriseId(), undefined);
                pendingApproval.state().should.eql('pending');
                pendingApproval.creator().should.eql(TestBitGo.TEST_USERID);
                pendingApproval.type().should.eql('transactionRequest');
                pendingApproval.info().transactionRequest.destinationAddress.should.eql(TestBitGo.TEST_WALLET2_ADDRESS);
            });
        });
    });
    describe('Approve', function () {
        let pendingApproval;
        before(function () {
            return createTransactionPendingApproval().then(function (result) {
                pendingApproval = result;
            });
        });
        after(function () {
            return pendingApproval.reject();
        });
        it('arguments', function () {
            assert_1.strict.throws(function () {
                pendingApproval.approve({}, 'invalid');
            });
            assert_1.strict.throws(function () {
                pendingApproval.approve('invalid');
            });
        });
        it('error when self approving', function () {
            return createPolicyPendingApproval()
                .then(function (pendingApproval) {
                return pendingApproval.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() });
            })
                .catch(function (err) {
                err.message.should.containEql('cannot approve by self');
                return pendingApproval.reject();
            });
        });
        it('can approve when it does not require tx signing', function () {
            return createPolicyPendingApproval().then(function (pendingApproval) {
                return bitgoSharedKeyUser
                    .pendingApprovals()
                    .get({ id: pendingApproval.id() })
                    .then(function (result) {
                    return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() });
                })
                    .then(function (result) {
                    result.state.should.eql('approved');
                    result.info.policyRuleRequest.update.condition.amount.should.eql(pendingApproval.info().policyRuleRequest.update.condition.amount);
                });
            });
        });
        it('can approve when tx does not require reconstruction', function () {
            return createTransactionPendingApproval().then(function (pendingApproval) {
                return bitgoSharedKeyUser
                    .pendingApprovals()
                    .get({ id: pendingApproval.id() })
                    .then(function (result) {
                    return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() });
                })
                    .then(function (result) {
                    result.state.should.eql('approved');
                });
            });
        });
        it('error when it does require tx signing but wrong passphrase', function () {
            return createTransactionPendingApproval()
                .then(function (pendingApproval) {
                return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() });
            })
                .then(function (result) {
                return result.approve({ walletPassphrase: 'abcdef', otp: bitgo.testUserOTP() });
            })
                .catch(function (err) {
                err.message.should.containEql('Unable to decrypt user keychain');
                return pendingApproval.reject();
            });
        });
        it('can approve when it does require tx signing', function () {
            return createTransactionPendingApproval()
                .then(function (pendingApproval) {
                return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() });
            })
                .then(function (result) {
                return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() });
            })
                .then(function (result) {
                result.state.should.eql('approved');
            });
        });
        it('cannot approve when transaction needs reconstructing', function () {
            let approvals = [];
            return Q.all([createTransactionPendingApproval(), createTransactionPendingApproval()])
                .spread(function (approval1, approval2) {
                approvals = [approval1, approval2];
                return bitgoSharedKeyUser.pendingApprovals().get({ id: approval1.id() });
            })
                .then(function (result) {
                return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() });
            })
                .then(function (result) {
                result.state.should.eql('approved');
                const approval2 = approvals[1];
                return bitgoSharedKeyUser.pendingApprovals().get({ id: approval2.id() });
            })
                .then(function (result) {
                return result.approve({ otp: bitgo.testUserOTP() });
            })
                .then(function () {
                throw new Error('approval success');
            })
                .catch(function (error) {
                error.message.should.equal('unspents expired, wallet passphrase or xprv required to recreate transaction');
            });
        });
        it('can approve when it does require tx signing (multiple recipients)', function () {
            return createTransactionPendingApprovalToMultipleRecipients()
                .then(function (pendingApproval) {
                return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() });
            })
                .then(function (result) {
                return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() });
            })
                .then(function (result) {
                result.state.should.eql('approved');
                // Parse the completed tx hex and make sure it was built with proper outputs
                const completedTxHex = result.info.transactionRequest.validTransaction;
                const transaction = utxolib.bitgo.createTransactionFromHex(completedTxHex, utxolib.networks.bitcoin);
                if (!transaction || !transaction.outs) {
                    throw new Error('transaction had no outputs or failed to parse successfully');
                }
                const outputAddresses = _.map(transaction.outs, function (out) {
                    return utxolib.address.fromOutputScript(out.script, BitGoJS.getNetworkObj());
                });
                // Output addresses should contain the 2 destinations, but not the change address
                outputAddresses.should.containEql(TestBitGo.TEST_WALLET3_ADDRESS);
                outputAddresses.should.containEql(TestBitGo.TEST_WALLET2_ADDRESS);
                outputAddresses.should.not.containEql(TestBitGo.TEST_SHARED_WALLET_CHANGE_ADDRESS);
            });
        });
        it('can manually pass in reconstructed tx', function () {
            let pendingApproval;
            return createTransactionPendingApprovalToMultipleRecipients()
                .then(function (pendingApproval) {
                return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() });
            })
                .then(function (result) {
                pendingApproval = result;
                return pendingApproval.constructApprovalTx({
                    walletPassphrase: TestBitGo.TEST_PASSWORD,
                    otp: bitgo.testUserOTP(),
                });
            })
                .then(function (result) {
                return pendingApproval.approve({
                    walletPassphrase: TestBitGo.TEST_PASSWORD,
                    tx: result.tx,
                    otp: bitgo.testUserOTP(),
                });
            })
                .then(function (result) {
                result.state.should.eql('approved');
                // Parse the completed tx hex and make sure it was built with proper outputs
                const completedTxHex = result.info.transactionRequest.validTransaction;
                const transaction = utxolib.bitgo.createTransactionFromHex(completedTxHex, utxolib.networks.bitcoin);
                if (!transaction || !transaction.outs) {
                    throw new Error('transaction had no outputs or failed to parse successfully');
                }
                const outputAddresses = _.map(transaction.outs, function (out) {
                    return utxolib.address.fromOutputScript(out.script, BitGoJS.getNetworkObj());
                });
                // Output addresses should contain the 2 destinations, but not the change address
                outputAddresses.should.containEql(TestBitGo.TEST_WALLET3_ADDRESS);
                outputAddresses.should.containEql(TestBitGo.TEST_WALLET2_ADDRESS);
                outputAddresses.should.not.containEql(TestBitGo.TEST_SHARED_WALLET_CHANGE_ADDRESS);
            });
        });
    });
    describe('Reject', function () {
        let pendingApproval;
        before(function () {
            return Q.delay(500)
                .then(function () {
                return createTransactionPendingApproval();
            })
                .then(function (result) {
                pendingApproval = result;
            });
        });
        it('arguments', function () {
            assert_1.strict.throws(function () {
                pendingApproval.reject({}, 'invalid');
            });
            assert_1.strict.throws(function () {
                pendingApproval.reject('invalid');
            });
        });
        it('can cancel', function () {
            return pendingApproval.reject().then(function (result) {
                result.state.should.eql('rejected');
            });
        });
        it('can reject', function () {
            return bitgoSharedKeyUser
                .pendingApprovals()
                .get({ id: pendingApproval.id() })
                .then(function (result) {
                return result.reject();
            })
                .then(function (result) {
                result.state.should.eql('rejected');
            });
        });
    });
    describe('Create, Get, Approve and Reject with Multiple Approvers', function () {
        // setup third user
        let multipleApproversWallet;
        let pendingApproval;
        before(function () {
            return bitgoThirdUser
                .authenticate({
                username: TestBitGo.TEST_THIRD_USER,
                password: TestBitGo.TEST_THIRD_PASSWORD,
                otp: bitgo.testUserOTP(),
            })
                .then(function () {
                return bitgoThirdUser.unlock({ otp: bitgoThirdUser.testUserOTP() });
            })
                .then(function () {
                return bitgoThirdUser.wallets().get({ id: TestBitGo.TEST_WALLETMULTAPPROVERS_ADDRESS });
            })
                .then(function (result) {
                multipleApproversWallet = result;
                if (multipleApproversWallet.approvalsRequired() === 2) {
                    // we don't need to bother setting the number of approvals required
                    return;
                }
                return multipleApproversWallet
                    .updateApprovalsRequired({ approvalsRequired: 2 })
                    .then(function (result) {
                    return bitgoSharedKeyUser.pendingApprovals().get({ id: result.id });
                })
                    .then(function (result) {
                    pendingApproval = result;
                    pendingApproval.approvalsRequired().should.equal(1);
                    return result.approve({ otp: bitgo.testUserOTP() });
                })
                    .then(function (result) {
                    result.state.should.eql('approved');
                    // update wallet variable with new approvalsRequired
                    return bitgoThirdUser.wallets().get({ id: TestBitGo.TEST_WALLETMULTAPPROVERS_ADDRESS });
                })
                    .then(function (result) {
                    multipleApproversWallet = result;
                });
            });
        });
        after(function () {
            pendingApproval.reject();
        });
        it('should fail with too low approvalsRequired', function () {
            assert_1.strict.throws(function () {
                multipleApproversWallet.updateApprovalsRequired({ approvalsRequired: 0 });
            }, 'invalid approvalsRequired');
        });
        it('should fail with too high approvalsRequired', function () {
            const promise = multipleApproversWallet.updateApprovalsRequired({ approvalsRequired: 3 });
            return TestUtil.throws(promise, 'approvalsRequired must be less than the number of admins on the wallet');
        });
        it('should be a no-op with same approvalsRequired', function () {
            return multipleApproversWallet.updateApprovalsRequired({ approvalsRequired: 2 }).then(function (wallet) {
                wallet.should.equal(multipleApproversWallet.wallet);
            });
        });
        it('should set approvals required to 1 after 2 approvals', function () {
            return multipleApproversWallet
                .updateApprovalsRequired({ approvalsRequired: 1 })
                .then(function (result) {
                return bitgoSharedKeyUser.pendingApprovals().get({ id: result.id });
            })
                .then(function (result) {
                pendingApproval = result;
                pendingApproval.approvalsRequired().should.equal(2);
                return result.approve({ otp: bitgo.testUserOTP() });
            })
                .then(function (result) {
                result.state.should.eql('pending');
                return bitgo.pendingApprovals().get({ id: result.id });
            })
                .then(function (result) {
                return result.approve({ otp: bitgo.testUserOTP() });
            })
                .then(function (result) {
                result.state.should.eql('approved');
                return bitgoThirdUser.wallets().get({ id: TestBitGo.TEST_WALLETMULTAPPROVERS_ADDRESS });
            })
                .then(function (wallet) {
                multipleApproversWallet = wallet;
                multipleApproversWallet.approvalsRequired().should.equal(1);
            });
        });
    });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVuZGluZ2FwcHJvdmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdGVzdC9pbnRlZ3JhdGlvbi9wZW5kaW5nYXBwcm92YWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLEVBQUU7QUFDRiwrQkFBK0I7QUFDL0IsRUFBRTtBQUNGLG9EQUFvRDtBQUNwRCxFQUFFOztBQUVGLDRCQUE0QjtBQUM1QixtQ0FBMEM7QUFDMUMsa0JBQWdCO0FBQ2hCLDJDQUEyQztBQUUzQyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUMzQyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQztBQUMvQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7QUFFdkMsTUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBRXZCLFFBQVEsQ0FBQyxpQkFBaUIsRUFBRTtJQUMxQixJQUFJLEtBQUssQ0FBQztJQUNWLElBQUksa0JBQWtCLENBQUM7SUFDdkIsSUFBSSxjQUFjLENBQUM7SUFDbkIsSUFBSSxZQUFZLENBQUM7SUFFakI7OztPQUdHO0lBQ0gsTUFBTSxnQ0FBZ0MsR0FBRztRQUN2QyxPQUFPLFlBQVk7YUFDaEIsU0FBUyxDQUFDO1lBQ1QsT0FBTyxFQUFFLFNBQVMsQ0FBQyxvQkFBb0I7WUFDdkMsTUFBTSxFQUFFLE1BQU0sR0FBRyxHQUFHO1lBQ3BCLGdCQUFnQixFQUFFLFNBQVMsQ0FBQyxhQUFhO1lBQ3pDLEdBQUcsRUFBRSxLQUFLLENBQUMsV0FBVyxFQUFFO1lBQ3hCLE9BQU8sRUFBRSxhQUFhO1NBQ3ZCLENBQUM7YUFDRCxJQUFJLENBQUMsVUFBVSxNQUFNO1lBQ3BCLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQy9DLE9BQU8sS0FBSyxDQUFDLGdCQUFnQixFQUFF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cmlnaHQgMjAxNSwgQml0R28sIEluYy4gIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vL1xuXG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBzdHJpY3QgYXMgYXNzZXJ0IH0gZnJvbSAnYXNzZXJ0JztcbmltcG9ydCAnc2hvdWxkJztcbmltcG9ydCAqIGFzIHV0eG9saWIgZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcblxuY29uc3QgQml0R29KUyA9IHJlcXVpcmUoJy4uLy4uL3NyYy9pbmRleCcpO1xuY29uc3QgVGVzdEJpdEdvID0gcmVxdWlyZSgnLi4vbGliL3Rlc3RfYml0Z28nKTtcbmNvbnN0IFRlc3RVdGlsID0gcmVxdWlyZSgnLi90ZXN0dXRpbCcpO1xuXG5jb25zdCBRID0gcmVxdWlyZSgncScpO1xuXG5kZXNjcmliZSgnUGVuZGluZ0FwcHJvdmFsJywgZnVuY3Rpb24gKCkge1xuICBsZXQgYml0Z287XG4gIGxldCBiaXRnb1NoYXJlZEtleVVzZXI7XG4gIGxldCBiaXRnb1RoaXJkVXNlcjtcbiAgbGV0IHNoYXJlZFdhbGxldDtcblxuICAvKipcbiAgICogVGhlcmUgaXMgYSAwLWxpbWl0IHBvbGljeSBvbiB0aGUgc2hhcmVkIHdhbGxldFxuICAgKiBDcmVhdGUgYSBwZW5kaW5nIGFwcHJvdmFsIGJ5IGF0dGVtcHRpbmcgdG8gc2VuZCBjb2luc1xuICAgKi9cbiAgY29uc3QgY3JlYXRlVHJhbnNhY3Rpb25QZW5kaW5nQXBwcm92YWwgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHNoYXJlZFdhbGxldFxuICAgICAgLnNlbmRDb2lucyh7XG4gICAgICAgIGFkZHJlc3M6IFRlc3RCaXRHby5URVNUX1dBTExFVDJfQUREUkVTUyxcbiAgICAgICAgYW1vdW50OiAwLjAwMDEgKiAxZTgsXG4gICAgICAgIHdhbGxldFBhc3NwaHJhc2U6IFRlc3RCaXRHby5URVNUX1BBU1NXT1JELFxuICAgICAgICBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksXG4gICAgICAgIG1lc3NhZ2U6ICduZXZlciBnb25uYScsXG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICByZXN1bHQuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3BlbmRpbmdBcHByb3ZhbCcpO1xuICAgICAgICByZXR1cm4gYml0Z28ucGVuZGluZ0FwcHJvdmFscygpLmdldCh7IGlkOiByZXN1bHQucGVuZGluZ0FwcHJvdmFsIH0pO1xuICAgICAgfSk7XG4gIH07XG5cbiAgLyoqXG4gICAqIFRoZXJlIGlzIGEgMC1saW1pdCBwb2xpY3kgb24gdGhlIHNoYXJlZCB3YWxsZXRcbiAgICogQ3JlYXRlIGEgcGVuZGluZyBhcHByb3ZhbCBieSBhdHRlbXB0aW5nIHRvIHNlbmQgdG8gbWFueVxuICAgKi9cbiAgY29uc3QgY3JlYXRlVHJhbnNhY3Rpb25QZW5kaW5nQXBwcm92YWxUb011bHRpcGxlUmVjaXBpZW50cyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gc2hhcmVkV2FsbGV0XG4gICAgICAuc2VuZE1hbnkoe1xuICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogVGVzdEJpdEdvLlRFU1RfV0FMTEVUM19BRERSRVNTLFxuICAgICAgICAgICAgYW1vdW50OiAwLjAwMDIgKiAxZTgsXG4gICAgICAgICAgfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhZGRyZXNzOiBUZXN0Qml0R28uVEVTVF9XQUxMRVQyX0FERFJFU1MsXG4gICAgICAgICAgICBhbW91bnQ6IDAuMDAwMSAqIDFlOCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFkZHJlc3M6IFRlc3RCaXRHby5URVNUX1NIQVJFRF9XQUxMRVRfQ0hBTkdFX0FERFJFU1MsXG4gICAgICAgICAgICBhbW91bnQ6IDAuMDAwNSAqIDFlOCxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVEVTVF9QQVNTV09SRCxcbiAgICAgICAgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLFxuICAgICAgICBtZXNzYWdlOiAnbmV2ZXIgZ29ubmEnLFxuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgcmVzdWx0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdwZW5kaW5nQXBwcm92YWwnKTtcbiAgICAgICAgcmV0dXJuIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogcmVzdWx0LnBlbmRpbmdBcHByb3ZhbCB9KTtcbiAgICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBwZW5kaW5nIGFwcHJvdmFsIGJ5IGF0dGVtcHRpbmcgdG8gYWRkIGEgdXNlciB0byB0aGUgd2FsbGV0XG4gICAqL1xuICBjb25zdCBjcmVhdGVQb2xpY3lQZW5kaW5nQXBwcm92YWwgPSBmdW5jdGlvbiAoKSB7XG4gICAgLy8gaXQncyBvayB0byBzZXQgdXAgYW55IHR4IGxpbWl0IHNpbmNlIHRoZSBkYWlseSBsaW1pdCBpcyAwXG4gICAgcmV0dXJuIHNoYXJlZFdhbGxldFxuICAgICAgLnVwZGF0ZVBvbGljeVJ1bGUoe1xuICAgICAgICBhY3Rpb246IHtcbiAgICAgICAgICB0eXBlOiAnZ2V0QXBwcm92YWwnLFxuICAgICAgICB9LFxuICAgICAgICBjb25kaXRpb246IHtcbiAgICAgICAgICBhbW91bnQ6IDFlOCArIE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIDFlOCksXG4gICAgICAgIH0sXG4gICAgICAgIGlkOiAnY29tLmJpdGdvLmxpbWl0LnR4JyxcbiAgICAgICAgdHlwZTogJ3RyYW5zYWN0aW9uTGltaXQnLFxuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgcmVzdWx0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdwZW5kaW5nQXBwcm92YWwnKTtcbiAgICAgICAgcmV0dXJuIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogcmVzdWx0LnBlbmRpbmdBcHByb3ZhbC5pZCB9KTtcbiAgICAgIH0pO1xuICB9O1xuXG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgYml0Z28gPSBuZXcgVGVzdEJpdEdvKCk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYml0Z29TaGFyZWRLZXlVc2VyID0gbmV3IFRlc3RCaXRHbygpO1xuICAgIGJpdGdvU2hhcmVkS2V5VXNlci5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBiaXRnb1RoaXJkVXNlciA9IG5ldyBUZXN0Qml0R28oKTtcbiAgICBiaXRnb1RoaXJkVXNlci5pbml0aWFsaXplVGVzdFZhcnMoKTtcblxuICAgIHJldHVybiBiaXRnb1xuICAgICAgLmF1dGhlbnRpY2F0ZVRlc3RVc2VyKGJpdGdvLnRlc3RVc2VyT1RQKCkpXG4gICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBiaXRnb1NoYXJlZEtleVVzZXIuYXV0aGVudGljYXRlKHtcbiAgICAgICAgICB1c2VybmFtZTogVGVzdEJpdEdvLlRFU1RfU0hBUkVEX0tFWV9VU0VSLFxuICAgICAgICAgIHBhc3N3b3JkOiBUZXN0Qml0R28uVEVTVF9TSEFSRURfS0VZX1BBU1NXT1JELFxuICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z28udW5sb2NrKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpIH0pO1xuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGJpdGdvU2hhcmVkS2V5VXNlci51bmxvY2soeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCkgfSk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z28ud2FsbGV0cygpLmdldCh7IGlkOiBUZXN0Qml0R28uVEVTVF9TSEFSRURfV0FMTEVUX0FERFJFU1MgfSk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICBzaGFyZWRXYWxsZXQgPSByZXN1bHQ7XG4gICAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0NyZWF0ZSBhbmQgR2V0JywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBwZW5kaW5nQXBwcm92YWw7XG5cbiAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGNyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsKCkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgIHBlbmRpbmdBcHByb3ZhbCA9IHJlc3VsdDtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXIoZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIHBlbmRpbmdBcHByb3ZhbC5yZWplY3QoKTtcbiAgICB9KTtcblxuICAgIGl0KCdhcmd1bWVudHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYml0Z28ucGVuZGluZ0FwcHJvdmFscygpLmdldCh7fSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogNTQzMjEgfSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2dldCBwcm9wZXJ0eSBtZXRob2RzJywgZnVuY3Rpb24gKCkge1xuICAgICAgcGVuZGluZ0FwcHJvdmFsLmlkKCkuc2hvdWxkLmVxbChwZW5kaW5nQXBwcm92YWwucGVuZGluZ0FwcHJvdmFsLmlkKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5vd25lclR5cGUoKS5zaG91bGQuZXFsKCd3YWxsZXQnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC53YWxsZXRJZCgpLnNob3VsZC5lcWwoc2hhcmVkV2FsbGV0LmlkKCkpO1xuICAgICAgYXNzZXJ0LmVxdWFsKHBlbmRpbmdBcHByb3ZhbC5lbnRlcnByaXNlSWQoKSwgdW5kZWZpbmVkKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5zdGF0ZSgpLnNob3VsZC5lcWwoJ3BlbmRpbmcnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5jcmVhdG9yKCkuc2hvdWxkLmVxbChUZXN0Qml0R28uVEVTVF9VU0VSSUQpO1xuICAgICAgcGVuZGluZ0FwcHJvdmFsLnR5cGUoKS5zaG91bGQuZXFsKCd0cmFuc2FjdGlvblJlcXVlc3QnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5pbmZvKCkudHJhbnNhY3Rpb25SZXF1ZXN0Lm1lc3NhZ2Uuc2hvdWxkLmVxbCgnbmV2ZXIgZ29ubmEnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5pbmZvKCkudHJhbnNhY3Rpb25SZXF1ZXN0LmRlc3RpbmF0aW9uQWRkcmVzcy5zaG91bGQuZXFsKFRlc3RCaXRHby5URVNUX1dBTExFVDJfQUREUkVTUyk7XG4gICAgfSk7XG5cbiAgICBpdCgnZ2V0JywgZnVuY3Rpb24gKCkge1xuICAgICAgcGVuZGluZ0FwcHJvdmFsLmdldCh7fSkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgIHBlbmRpbmdBcHByb3ZhbCA9IHJlc3VsdDtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLmlkKCkuc2hvdWxkLmVxbChwZW5kaW5nQXBwcm92YWwucGVuZGluZ0FwcHJvdmFsLmlkKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLm93bmVyVHlwZSgpLnNob3VsZC5lcWwoJ3dhbGxldCcpO1xuICAgICAgICBwZW5kaW5nQXBwcm92YWwud2FsbGV0SWQoKS5zaG91bGQuZXFsKHNoYXJlZFdhbGxldC5pZCgpKTtcbiAgICAgICAgYXNzZXJ0LmVxdWFsKHBlbmRpbmdBcHByb3ZhbC5lbnRlcnByaXNlSWQoKSwgdW5kZWZpbmVkKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLnN0YXRlKCkuc2hvdWxkLmVxbCgncGVuZGluZycpO1xuICAgICAgICBwZW5kaW5nQXBwcm92YWwuY3JlYXRvcigpLnNob3VsZC5lcWwoVGVzdEJpdEdvLlRFU1RfVVNFUklEKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLnR5cGUoKS5zaG91bGQuZXFsKCd0cmFuc2FjdGlvblJlcXVlc3QnKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLmluZm8oKS50cmFuc2FjdGlvblJlcXVlc3QuZGVzdGluYXRpb25BZGRyZXNzLnNob3VsZC5lcWwoVGVzdEJpdEdvLlRFU1RfV0FMTEVUMl9BRERSRVNTKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnQXBwcm92ZScsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgcGVuZGluZ0FwcHJvdmFsO1xuXG4gICAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBjcmVhdGVUcmFuc2FjdGlvblBlbmRpbmdBcHByb3ZhbCgpLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICBwZW5kaW5nQXBwcm92YWwgPSByZXN1bHQ7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGFmdGVyKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBwZW5kaW5nQXBwcm92YWwucmVqZWN0KCk7XG4gICAgfSk7XG5cbiAgICBpdCgnYXJndW1lbnRzJywgZnVuY3Rpb24gKCkge1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIHBlbmRpbmdBcHByb3ZhbC5hcHByb3ZlKHt9LCAnaW52YWxpZCcpO1xuICAgICAgfSk7XG4gICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLmFwcHJvdmUoJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2Vycm9yIHdoZW4gc2VsZiBhcHByb3ZpbmcnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gY3JlYXRlUG9saWN5UGVuZGluZ0FwcHJvdmFsKClcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHBlbmRpbmdBcHByb3ZhbCkge1xuICAgICAgICAgIHJldHVybiBwZW5kaW5nQXBwcm92YWwuYXBwcm92ZSh7IHdhbGxldFBhc3NwaHJhc2U6IFRlc3RCaXRHby5URVNUX1BBU1NXT1JELCBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCkgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC5jYXRjaChmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgZXJyLm1lc3NhZ2Uuc2hvdWxkLmNvbnRhaW5FcWwoJ2Nhbm5vdCBhcHByb3ZlIGJ5IHNlbGYnKTtcbiAgICAgICAgICByZXR1cm4gcGVuZGluZ0FwcHJvdmFsLnJlamVjdCgpO1xuICAgICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdjYW4gYXBwcm92ZSB3aGVuIGl0IGRvZXMgbm90IHJlcXVpcmUgdHggc2lnbmluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBjcmVhdGVQb2xpY3lQZW5kaW5nQXBwcm92YWwoKS50aGVuKGZ1bmN0aW9uIChwZW5kaW5nQXBwcm92YWwpIHtcbiAgICAgICAgcmV0dXJuIGJpdGdvU2hhcmVkS2V5VXNlclxuICAgICAgICAgIC5wZW5kaW5nQXBwcm92YWxzKClcbiAgICAgICAgICAuZ2V0KHsgaWQ6IHBlbmRpbmdBcHByb3ZhbC5pZCgpIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdC5hcHByb3ZlKHsgd2FsbGV0UGFzc3BocmFzZTogVGVzdEJpdEdvLlRFU1RfUEFTU1dPUkQsIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSB9KTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgIHJlc3VsdC5zdGF0ZS5zaG91bGQuZXFsKCdhcHByb3ZlZCcpO1xuICAgICAgICAgICAgcmVzdWx0LmluZm8ucG9saWN5UnVsZVJlcXVlc3QudXBkYXRlLmNvbmRpdGlvbi5hbW91bnQuc2hvdWxkLmVxbChcbiAgICAgICAgICAgICAgcGVuZGluZ0FwcHJvdmFsLmluZm8oKS5wb2xpY3lSdWxlUmVxdWVzdC51cGRhdGUuY29uZGl0aW9uLmFtb3VudFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbiBhcHByb3ZlIHdoZW4gdHggZG9lcyBub3QgcmVxdWlyZSByZWNvbnN0cnVjdGlvbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBjcmVhdGVUcmFuc2FjdGlvblBlbmRpbmdBcHByb3ZhbCgpLnRoZW4oZnVuY3Rpb24gKHBlbmRpbmdBcHByb3ZhbCkge1xuICAgICAgICByZXR1cm4gYml0Z29TaGFyZWRLZXlVc2VyXG4gICAgICAgICAgLnBlbmRpbmdBcHByb3ZhbHMoKVxuICAgICAgICAgIC5nZXQoeyBpZDogcGVuZGluZ0FwcHJvdmFsLmlkKCkgfSlcbiAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0LmFwcHJvdmUoeyB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVEVTVF9QQVNTV09SRCwgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpIH0pO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgcmVzdWx0LnN0YXRlLnNob3VsZC5lcWwoJ2FwcHJvdmVkJyk7XG4gICAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdlcnJvciB3aGVuIGl0IGRvZXMgcmVxdWlyZSB0eCBzaWduaW5nIGJ1dCB3cm9uZyBwYXNzcGhyYXNlJywgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGNyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsKClcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHBlbmRpbmdBcHByb3ZhbCkge1xuICAgICAgICAgIHJldHVybiBiaXRnb1NoYXJlZEtleVVzZXIucGVuZGluZ0FwcHJvdmFscygpLmdldCh7IGlkOiBwZW5kaW5nQXBwcm92YWwuaWQoKSB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJldHVybiByZXN1bHQuYXBwcm92ZSh7IHdhbGxldFBhc3NwaHJhc2U6ICdhYmNkZWYnLCBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCkgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC5jYXRjaChmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgZXJyLm1lc3NhZ2Uuc2hvdWxkLmNvbnRhaW5FcWwoJ1VuYWJsZSB0byBkZWNyeXB0IHVzZXIga2V5Y2hhaW4nKTtcbiAgICAgICAgICByZXR1cm4gcGVuZGluZ0FwcHJvdmFsLnJlamVjdCgpO1xuICAgICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdjYW4gYXBwcm92ZSB3aGVuIGl0IGRvZXMgcmVxdWlyZSB0eCBzaWduaW5nJywgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGNyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsKClcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHBlbmRpbmdBcHByb3ZhbCkge1xuICAgICAgICAgIHJldHVybiBiaXRnb1NoYXJlZEtleVVzZXIucGVuZGluZ0FwcHJvdmFscygpLmdldCh7IGlkOiBwZW5kaW5nQXBwcm92YWwuaWQoKSB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJldHVybiByZXN1bHQuYXBwcm92ZSh7IHdhbGxldFBhc3NwaHJhc2U6IFRlc3RCaXRHby5URVNUX1BBU1NXT1JELCBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCkgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICByZXN1bHQuc3RhdGUuc2hvdWxkLmVxbCgnYXBwcm92ZWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnY2Fubm90IGFwcHJvdmUgd2hlbiB0cmFuc2FjdGlvbiBuZWVkcyByZWNvbnN0cnVjdGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBhcHByb3ZhbHM6IGFueVtdID0gW107XG4gICAgICByZXR1cm4gUS5hbGwoW2NyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsKCksIGNyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsKCldKVxuICAgICAgICAuc3ByZWFkKGZ1bmN0aW9uIChhcHByb3ZhbDEsIGFwcHJvdmFsMikge1xuICAgICAgICAgIGFwcHJvdmFscyA9IFthcHByb3ZhbDEsIGFwcHJvdmFsMl07XG4gICAgICAgICAgcmV0dXJuIGJpdGdvU2hhcmVkS2V5VXNlci5wZW5kaW5nQXBwcm92YWxzKCkuZ2V0KHsgaWQ6IGFwcHJvdmFsMS5pZCgpIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdC5hcHByb3ZlKHsgd2FsbGV0UGFzc3BocmFzZTogVGVzdEJpdEdvLlRFU1RfUEFTU1dPUkQsIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJlc3VsdC5zdGF0ZS5zaG91bGQuZXFsKCdhcHByb3ZlZCcpO1xuICAgICAgICAgIGNvbnN0IGFwcHJvdmFsMiA9IGFwcHJvdmFsc1sxXTtcbiAgICAgICAgICByZXR1cm4gYml0Z29TaGFyZWRLZXlVc2VyLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogYXBwcm92YWwyLmlkKCkgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0LmFwcHJvdmUoeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCkgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2FwcHJvdmFsIHN1Y2Nlc3MnKTtcbiAgICAgICAgfSlcbiAgICAgICAgLmNhdGNoKGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgIGVycm9yLm1lc3NhZ2Uuc2hvdWxkLmVxdWFsKCd1bnNwZW50cyBleHBpcmVkLCB3YWxsZXQgcGFzc3BocmFzZSBvciB4cHJ2IHJlcXVpcmVkIHRvIHJlY3JlYXRlIHRyYW5zYWN0aW9uJyk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbiBhcHByb3ZlIHdoZW4gaXQgZG9lcyByZXF1aXJlIHR4IHNpZ25pbmcgKG11bHRpcGxlIHJlY2lwaWVudHMpJywgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGNyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsVG9NdWx0aXBsZVJlY2lwaWVudHMoKVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocGVuZGluZ0FwcHJvdmFsKSB7XG4gICAgICAgICAgcmV0dXJuIGJpdGdvU2hhcmVkS2V5VXNlci5wZW5kaW5nQXBwcm92YWxzKCkuZ2V0KHsgaWQ6IHBlbmRpbmdBcHByb3ZhbC5pZCgpIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdC5hcHByb3ZlKHsgd2FsbGV0UGFzc3BocmFzZTogVGVzdEJpdEdvLlRFU1RfUEFTU1dPUkQsIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJlc3VsdC5zdGF0ZS5zaG91bGQuZXFsKCdhcHByb3ZlZCcpO1xuXG4gICAgICAgICAgLy8gUGFyc2UgdGhlIGNvbXBsZXRlZCB0eCBoZXggYW5kIG1ha2Ugc3VyZSBpdCB3YXMgYnVpbHQgd2l0aCBwcm9wZXIgb3V0cHV0c1xuICAgICAgICAgIGNvbnN0IGNvbXBsZXRlZFR4SGV4ID0gcmVzdWx0LmluZm8udHJhbnNhY3Rpb25SZXF1ZXN0LnZhbGlkVHJhbnNhY3Rpb247XG4gICAgICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSB1dHhvbGliLmJpdGdvLmNyZWF0ZVRyYW5zYWN0aW9uRnJvbUhleChjb21wbGV0ZWRUeEhleCwgdXR4b2xpYi5uZXR3b3Jrcy5iaXRjb2luKTtcbiAgICAgICAgICBpZiAoIXRyYW5zYWN0aW9uIHx8ICF0cmFuc2FjdGlvbi5vdXRzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RyYW5zYWN0aW9uIGhhZCBubyBvdXRwdXRzIG9yIGZhaWxlZCB0byBwYXJzZSBzdWNjZXNzZnVsbHknKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qgb3V0cHV0QWRkcmVzc2VzID0gXy5tYXAodHJhbnNhY3Rpb24ub3V0cywgZnVuY3Rpb24gKG91dCkge1xuICAgICAgICAgICAgcmV0dXJuIHV0eG9saWIuYWRkcmVzcy5mcm9tT3V0cHV0U2NyaXB0KG91dC5zY3JpcHQsIEJpdEdvSlMuZ2V0TmV0d29ya09iaigpKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIE91dHB1dCBhZGRyZXNzZXMgc2hvdWxkIGNvbnRhaW4gdGhlIDIgZGVzdGluYXRpb25zLCBidXQgbm90IHRoZSBjaGFuZ2UgYWRkcmVzc1xuICAgICAgICAgIG91dHB1dEFkZHJlc3Nlcy5zaG91bGQuY29udGFpbkVxbChUZXN0Qml0R28uVEVTVF9XQUxMRVQzX0FERFJFU1MpO1xuICAgICAgICAgIG91dHB1dEFkZHJlc3Nlcy5zaG91bGQuY29udGFpbkVxbChUZXN0Qml0R28uVEVTVF9XQUxMRVQyX0FERFJFU1MpO1xuICAgICAgICAgIG91dHB1dEFkZHJlc3Nlcy5zaG91bGQubm90LmNvbnRhaW5FcWwoVGVzdEJpdEdvLlRFU1RfU0hBUkVEX1dBTExFVF9DSEFOR0VfQUREUkVTUyk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbiBtYW51YWxseSBwYXNzIGluIHJlY29uc3RydWN0ZWQgdHgnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgcGVuZGluZ0FwcHJvdmFsO1xuICAgICAgcmV0dXJuIGNyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsVG9NdWx0aXBsZVJlY2lwaWVudHMoKVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocGVuZGluZ0FwcHJvdmFsKSB7XG4gICAgICAgICAgcmV0dXJuIGJpdGdvU2hhcmVkS2V5VXNlci5wZW5kaW5nQXBwcm92YWxzKCkuZ2V0KHsgaWQ6IHBlbmRpbmdBcHByb3ZhbC5pZCgpIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgcGVuZGluZ0FwcHJvdmFsID0gcmVzdWx0O1xuICAgICAgICAgIHJldHVybiBwZW5kaW5nQXBwcm92YWwuY29uc3RydWN0QXBwcm92YWxUeCh7XG4gICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVEVTVF9QQVNTV09SRCxcbiAgICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJldHVybiBwZW5kaW5nQXBwcm92YWwuYXBwcm92ZSh7XG4gICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVEVTVF9QQVNTV09SRCxcbiAgICAgICAgICAgIHR4OiByZXN1bHQudHgsXG4gICAgICAgICAgICBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICByZXN1bHQuc3RhdGUuc2hvdWxkLmVxbCgnYXBwcm92ZWQnKTtcblxuICAgICAgICAgIC8vIFBhcnNlIHRoZSBjb21wbGV0ZWQgdHggaGV4IGFuZCBtYWtlIHN1cmUgaXQgd2FzIGJ1aWx0IHdpdGggcHJvcGVyIG91dHB1dHNcbiAgICAgICAgICBjb25zdCBjb21wbGV0ZWRUeEhleCA9IHJlc3VsdC5pbmZvLnRyYW5zYWN0aW9uUmVxdWVzdC52YWxpZFRyYW5zYWN0aW9uO1xuICAgICAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gdXR4b2xpYi5iaXRnby5jcmVhdGVUcmFuc2FjdGlvbkZyb21IZXgoY29tcGxldGVkVHhIZXgsIHV0eG9saWIubmV0d29ya3MuYml0Y29pbik7XG4gICAgICAgICAgaWYgKCF0cmFuc2FjdGlvbiB8fCAhdHJhbnNhY3Rpb24ub3V0cykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0cmFuc2FjdGlvbiBoYWQgbm8gb3V0cHV0cyBvciBmYWlsZWQgdG8gcGFyc2Ugc3VjY2Vzc2Z1bGx5Jyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IG91dHB1dEFkZHJlc3NlcyA9IF8ubWFwKHRyYW5zYWN0aW9uLm91dHMsIGZ1bmN0aW9uIChvdXQpIHtcbiAgICAgICAgICAgIHJldHVybiB1dHhvbGliLmFkZHJlc3MuZnJvbU91dHB1dFNjcmlwdChvdXQuc2NyaXB0LCBCaXRHb0pTLmdldE5ldHdvcmtPYmooKSk7XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyBPdXRwdXQgYWRkcmVzc2VzIHNob3VsZCBjb250YWluIHRoZSAyIGRlc3RpbmF0aW9ucywgYnV0IG5vdCB0aGUgY2hhbmdlIGFkZHJlc3NcbiAgICAgICAgICBvdXRwdXRBZGRyZXNzZXMuc2hvdWxkLmNvbnRhaW5FcWwoVGVzdEJpdEdvLlRFU1RfV0FMTEVUM19BRERSRVNTKTtcbiAgICAgICAgICBvdXRwdXRBZGRyZXNzZXMuc2hvdWxkLmNvbnRhaW5FcWwoVGVzdEJpdEdvLlRFU1RfV0FMTEVUMl9BRERSRVNTKTtcbiAgICAgICAgICBvdXRwdXRBZGRyZXNzZXMuc2hvdWxkLm5vdC5jb250YWluRXFsKFRlc3RCaXRHby5URVNUX1NIQVJFRF9XQUxMRVRfQ0hBTkdFX0FERFJFU1MpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1JlamVjdCcsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgcGVuZGluZ0FwcHJvdmFsO1xuXG4gICAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBRLmRlbGF5KDUwMClcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiBjcmVhdGVUcmFuc2FjdGlvblBlbmRpbmdBcHByb3ZhbCgpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgcGVuZGluZ0FwcHJvdmFsID0gcmVzdWx0O1xuICAgICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdhcmd1bWVudHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLnJlamVjdCh7fSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIHBlbmRpbmdBcHByb3ZhbC5yZWplY3QoJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbiBjYW5jZWwnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gcGVuZGluZ0FwcHJvdmFsLnJlamVjdCgpLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICByZXN1bHQuc3RhdGUuc2hvdWxkLmVxbCgncmVqZWN0ZWQnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbiByZWplY3QnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gYml0Z29TaGFyZWRLZXlVc2VyXG4gICAgICAgIC5wZW5kaW5nQXBwcm92YWxzKClcbiAgICAgICAgLmdldCh7IGlkOiBwZW5kaW5nQXBwcm92YWwuaWQoKSB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdC5yZWplY3QoKTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJlc3VsdC5zdGF0ZS5zaG91bGQuZXFsKCdyZWplY3RlZCcpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0NyZWF0ZSwgR2V0LCBBcHByb3ZlIGFuZCBSZWplY3Qgd2l0aCBNdWx0aXBsZSBBcHByb3ZlcnMnLCBmdW5jdGlvbiAoKSB7XG4gICAgLy8gc2V0dXAgdGhpcmQgdXNlclxuICAgIGxldCBtdWx0aXBsZUFwcHJvdmVyc1dhbGxldDtcbiAgICBsZXQgcGVuZGluZ0FwcHJvdmFsO1xuICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gYml0Z29UaGlyZFVzZXJcbiAgICAgICAgLmF1dGhlbnRpY2F0ZSh7XG4gICAgICAgICAgdXNlcm5hbWU6IFRlc3RCaXRHby5URVNUX1RISVJEX1VTRVIsXG4gICAgICAgICAgcGFzc3dvcmQ6IFRlc3RCaXRHby5URVNUX1RISVJEX1BBU1NXT1JELFxuICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiBiaXRnb1RoaXJkVXNlci51bmxvY2soeyBvdHA6IGJpdGdvVGhpcmRVc2VyLnRlc3RVc2VyT1RQKCkgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gYml0Z29UaGlyZFVzZXIud2FsbGV0cygpLmdldCh7IGlkOiBUZXN0Qml0R28uVEVTVF9XQUxMRVRNVUxUQVBQUk9WRVJTX0FERFJFU1MgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICBtdWx0aXBsZUFwcHJvdmVyc1dhbGxldCA9IHJlc3VsdDtcblxuICAgICAgICAgIGlmIChtdWx0aXBsZUFwcHJvdmVyc1dhbGxldC5hcHByb3ZhbHNSZXF1aXJlZCgpID09PSAyKSB7XG4gICAgICAgICAgICAvLyB3ZSBkb24ndCBuZWVkIHRvIGJvdGhlciBzZXR0aW5nIHRoZSBudW1iZXIgb2YgYXBwcm92YWxzIHJlcXVpcmVkXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG11bHRpcGxlQXBwcm92ZXJzV2FsbGV0XG4gICAgICAgICAgICAudXBkYXRlQXBwcm92YWxzUmVxdWlyZWQoeyBhcHByb3ZhbHNSZXF1aXJlZDogMiB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICByZXR1cm4gYml0Z29TaGFyZWRLZXlVc2VyLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogcmVzdWx0LmlkIH0pO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgcGVuZGluZ0FwcHJvdmFsID0gcmVzdWx0O1xuICAgICAgICAgICAgICBwZW5kaW5nQXBwcm92YWwuYXBwcm92YWxzUmVxdWlyZWQoKS5zaG91bGQuZXF1YWwoMSk7XG4gICAgICAgICAgICAgIHJldHVybiByZXN1bHQuYXBwcm92ZSh7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSB9KTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgIHJlc3VsdC5zdGF0ZS5zaG91bGQuZXFsKCdhcHByb3ZlZCcpO1xuXG4gICAgICAgICAgICAgIC8vIHVwZGF0ZSB3YWxsZXQgdmFyaWFibGUgd2l0aCBuZXcgYXBwcm92YWxzUmVxdWlyZWRcbiAgICAgICAgICAgICAgcmV0dXJuIGJpdGdvVGhpcmRVc2VyLndhbGxldHMoKS5nZXQoeyBpZDogVGVzdEJpdEdvLlRFU1RfV0FMTEVUTVVMVEFQUFJPVkVSU19BRERSRVNTIH0pO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgbXVsdGlwbGVBcHByb3ZlcnNXYWxsZXQgPSByZXN1bHQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBhZnRlcihmdW5jdGlvbiAoKSB7XG4gICAgICBwZW5kaW5nQXBwcm92YWwucmVqZWN0KCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2l0aCB0b28gbG93IGFwcHJvdmFsc1JlcXVpcmVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIG11bHRpcGxlQXBwcm92ZXJzV2FsbGV0LnVwZGF0ZUFwcHJvdmFsc1JlcXVpcmVkKHsgYXBwcm92YWxzUmVxdWlyZWQ6IDAgfSk7XG4gICAgICB9LCAnaW52YWxpZCBhcHByb3ZhbHNSZXF1aXJlZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdpdGggdG9vIGhpZ2ggYXBwcm92YWxzUmVxdWlyZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBwcm9taXNlID0gbXVsdGlwbGVBcHByb3ZlcnNXYWxsZXQudXBkYXRlQXBwcm92YWxzUmVxdWlyZWQoeyBhcHByb3ZhbHNSZXF1aXJlZDogMyB9KTtcbiAgICAgIHJldHVybiBUZXN0VXRpbC50aHJvd3MocHJvbWlzZSwgJ2FwcHJvdmFsc1JlcXVpcmVkIG11c3QgYmUgbGVzcyB0aGFuIHRoZSBudW1iZXIgb2YgYWRtaW5zIG9uIHRoZSB3YWxsZXQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYmUgYSBuby1vcCB3aXRoIHNhbWUgYXBwcm92YWxzUmVxdWlyZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gbXVsdGlwbGVBcHByb3ZlcnNXYWxsZXQudXBkYXRlQXBwcm92YWxzUmVxdWlyZWQoeyBhcHByb3ZhbHNSZXF1aXJlZDogMiB9KS50aGVuKGZ1bmN0aW9uICh3YWxsZXQpIHtcbiAgICAgICAgd2FsbGV0LnNob3VsZC5lcXVhbChtdWx0aXBsZUFwcHJvdmVyc1dhbGxldC53YWxsZXQpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHNldCBhcHByb3ZhbHMgcmVxdWlyZWQgdG8gMSBhZnRlciAyIGFwcHJvdmFscycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBtdWx0aXBsZUFwcHJvdmVyc1dhbGxldFxuICAgICAgICAudXBkYXRlQXBwcm92YWxzUmVxdWlyZWQoeyBhcHByb3ZhbHNSZXF1aXJlZDogMSB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgcmV0dXJuIGJpdGdvU2hhcmVkS2V5VXNlci5wZW5kaW5nQXBwcm92YWxzKCkuZ2V0KHsgaWQ6IHJlc3VsdC5pZCB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHBlbmRpbmdBcHByb3ZhbCA9IHJlc3VsdDtcbiAgICAgICAgICBwZW5kaW5nQXBwcm92YWwuYXBwcm92YWxzUmVxdWlyZWQoKS5zaG91bGQuZXF1YWwoMik7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdC5hcHByb3ZlKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgcmVzdWx0LnN0YXRlLnNob3VsZC5lcWwoJ3BlbmRpbmcnKTtcblxuICAgICAgICAgIHJldHVybiBiaXRnby5wZW5kaW5nQXBwcm92YWxzKCkuZ2V0KHsgaWQ6IHJlc3VsdC5pZCB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJldHVybiByZXN1bHQuYXBwcm92ZSh7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgIHJlc3VsdC5zdGF0ZS5zaG91bGQuZXFsKCdhcHByb3ZlZCcpO1xuXG4gICAgICAgICAgcmV0dXJuIGJpdGdvVGhpcmRVc2VyLndhbGxldHMoKS5nZXQoeyBpZDogVGVzdEJpdEdvLlRFU1RfV0FMTEVUTVVMVEFQUFJPVkVSU19BRERSRVNTIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAod2FsbGV0KSB7XG4gICAgICAgICAgbXVsdGlwbGVBcHByb3ZlcnNXYWxsZXQgPSB3YWxsZXQ7XG4gICAgICAgICAgbXVsdGlwbGVBcHByb3ZlcnNXYWxsZXQuYXBwcm92YWxzUmVxdWlyZWQoKS5zaG91bGQuZXF1YWwoMSk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19

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


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