PHP WebShell

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

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * @prettier
 */
require("should");
const nock = require("nock");
const sinon = require("sinon");
const sdk_test_1 = require("@bitgo/sdk-test");
const src_1 = require("../../../src");
const sdk_core_1 = require("@bitgo/sdk-core");
describe('Pending Approvals:', () => {
    let sandbox;
    let bitgo;
    let basecoin;
    let wallet;
    let bgUrl;
    const coin = 'tbtc';
    const walletId = 'wallet_id';
    const pendingApprovalData = {
        id: 'pa0',
        info: {
            type: sdk_core_1.Type.TRANSACTION_REQUEST,
            transactionRequest: {
                coinSpecific: {
                    [coin]: {},
                },
                recipients: [],
                buildParams: {
                    type: 'consolidate',
                },
                sourceWallet: walletId,
            },
        },
        state: sdk_core_1.State.PENDING,
        creator: 'test',
    };
    const walletData = {
        id: walletId,
        coin,
        pendingApprovals: [pendingApprovalData],
    };
    beforeEach(function () {
        sandbox = sinon.createSandbox();
        nock.disableNetConnect();
    });
    afterEach(function () {
        sandbox.restore();
    });
    before(async () => {
        // create wallet
        bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
        bitgo.initializeTestVars();
        basecoin = bitgo.coin(coin);
        wallet = new sdk_core_1.Wallet(bitgo, basecoin, walletData);
        bgUrl = sdk_core_1.Environments[bitgo.getEnv()].uri;
        pendingApprovalData.wallet = wallet;
    });
    ['tsol', 'teth', 'tbtc'].forEach((coinName) => {
        it(`should use correct tssUtils for  ${coinName}`, () => {
            const coin = bitgo.coin(coinName);
            const pendingAproval = new sdk_core_1.PendingApproval(bitgo, coin, {});
            if (coin.supportsTss()) {
                if (coin.getMPCAlgorithm() === 'ecdsa') {
                    pendingAproval['tssUtils'].should.be.instanceOf(sdk_core_1.ECDSAUtils.EcdsaUtils);
                }
                else if (coin.getMPCAlgorithm() === 'eddsa') {
                    pendingAproval['tssUtils'].should.be.instanceOf(sdk_core_1.EddsaUtils);
                }
            }
            else {
                (pendingAproval['tssUtils'] === undefined).should.be.true();
            }
        });
    });
    ['MPCv2', undefined].forEach((multisigTypeVersion) => {
        it(`should use correct tssUtils for multisigTypeVersion: ${multisigTypeVersion}`, () => {
            const coin = bitgo.coin('hteth');
            const walletDataMpcV2 = {
                ...walletData,
                multisigTypeVersion: multisigTypeVersion,
            };
            const walletMPCv2 = new sdk_core_1.Wallet(bitgo, basecoin, walletDataMpcV2);
            const pendingAproval = new sdk_core_1.PendingApproval(bitgo, coin, {}, walletMPCv2);
            if (walletMPCv2.multisigTypeVersion() === 'MPCv2') {
                pendingAproval['tssUtils'].should.be.instanceOf(sdk_core_1.ECDSAUtils.EcdsaMPCv2Utils);
            }
            else {
                pendingAproval['tssUtils'].should.be.instanceOf(sdk_core_1.ECDSAUtils.EcdsaUtils);
            }
        });
    });
    it('should call consolidate instead of build when rebuilding consolidation pending approvals', async () => {
        const scope = nock(bgUrl).post(`/api/v2/${coin}/wallet/${walletId}/consolidateUnspents`).reply(200);
        const pendingApprovals = wallet.pendingApprovals();
        pendingApprovals.should.have.length(1);
        const pendingApproval = pendingApprovals[0];
        // approval will fail when attempting to resign. This is ok - we just want to make sure
        // the consolidateUnspents endpoint was called already before failing
        await pendingApproval.approve({ xprv: 'nonsense' }).should.be.rejected();
        scope.done();
    });
    it('should approve for transactionRequestLite if we cannot recreate transaction', async () => {
        const pendingApprovalData2 = { ...pendingApprovalData, txRequestId: '1234-4567-6789' };
        const pendingApproval = new sdk_core_1.PendingApproval(bitgo, basecoin, pendingApprovalData2, wallet);
        const paScope = nock(bgUrl)
            .put(`/api/v2/${coin}/pendingapprovals/${pendingApprovalData.id}`, {
            state: 'approved',
            otp: undefined,
        })
            .reply(200, {
            ...pendingApprovalData2,
            state: 'approved',
        });
        const recreateTransactionTssStub = sandbox.stub(sdk_core_1.PendingApproval.prototype, 'recreateAndSignTSSTransaction');
        const recreateTransactionStub = sandbox.stub(sdk_core_1.PendingApproval.prototype, 'recreateAndSignTransaction');
        pendingApproval.type().should.equal(sdk_core_1.Type.TRANSACTION_REQUEST);
        await pendingApproval.approve({});
        recreateTransactionTssStub.notCalled.should.be.true();
        recreateTransactionStub.notCalled.should.be.true();
        paScope.isDone().should.be.true();
    });
    function testRecreateTransaction(coinName, recreateTransaction, type) {
        it(`[${coinName}] should ${recreateTransaction ? 'not ' : ''}recreate the transaction during approving a pending approval if there are no recipients for PA type ${type}`, async () => {
            const coin = bitgo.coin(coinName);
            const txRequestId = coin.supportsTss() ? 'requestTxIdTest' : undefined;
            const pendingApprovalInfo = type === 'transactionRequest'
                ? {
                    type,
                    transactionRequest: {
                        coinSpecific: {
                            [coinName]: { txHex: 'gabagool' },
                        },
                        recipients: [],
                        buildParams: {},
                        sourceWallet: walletId,
                    },
                }
                : { type };
            const pendingApprovalDataTemp = {
                id: 'pa0',
                info: pendingApprovalInfo,
                wallet: walletId,
                state: sdk_core_1.State.PENDING,
                creator: 'test',
                txRequestId,
            };
            const walletDataTemp = {
                id: walletId,
                coinName,
                pendingApprovals: [pendingApprovalDataTemp],
            };
            const walletTemp = new sdk_core_1.Wallet(bitgo, coin, walletDataTemp);
            pendingApprovalDataTemp.wallet = walletTemp.id();
            const pendingApprovals = walletTemp.pendingApprovals();
            pendingApprovals.should.have.length(1);
            const pendingApproval = pendingApprovals[0];
            let stub;
            if (coin.supportsTss()) {
                stub = sandbox.stub(sdk_core_1.PendingApproval.prototype, 'recreateAndSignTSSTransaction').resolves({
                    txHex: 'gabagool',
                });
            }
            else {
                stub = sandbox.stub(sdk_core_1.PendingApproval.prototype, 'recreateAndSignTransaction').resolves({
                    state: 'approved',
                    halfSigned: { txHex: 'gabagool' },
                });
            }
            const paScope = nock(bgUrl)
                .put(`/api/v2/${coinName}/pendingapprovals/${pendingApprovalDataTemp.id}`, {
                state: 'approved',
                halfSigned: type === sdk_core_1.Type.TRANSACTION_REQUEST ? { txHex: 'gabagool' } : undefined,
            })
                .reply(200, {
                ...pendingApprovalDataTemp,
                state: 'approved',
            });
            await pendingApproval.approve({ xprv: 'nonsense', walletPassphrase: 'gabagoolio' });
            // Should not call build and should call pa
            paScope.isDone().should.be.true();
            stub.calledOnce.should.equal(recreateTransaction);
        });
    }
    testRecreateTransaction('tbtc', false, sdk_core_1.Type.TRANSACTION_REQUEST);
    testRecreateTransaction('tsol', true, sdk_core_1.Type.TRANSACTION_REQUEST);
    testRecreateTransaction('tsol', true, sdk_core_1.Type.TRANSACTION_REQUEST_FULL);
    testRecreateTransaction('teth', true, sdk_core_1.Type.TRANSACTION_REQUEST_FULL);
    describe('recreateAndSignTSSTransaction', function () {
        let coin;
        before(() => {
            coin = bitgo.coin('tsol');
        });
        it('should call approve and do the TSS flow and fail if the txRequestId is missing', async () => {
            const pendingApproval = wallet.pendingApprovals()[0];
            const reqId = new sdk_core_1.RequestTracer();
            const params = { walletPassphrase: 'test' };
            await pendingApproval
                .recreateAndSignTSSTransaction(params, reqId)
                .should.be.rejectedWith('txRequestId not found');
        });
        it('should call approve and do the TSS flow and fail if the walletPassphrase is missing', async () => {
            const pendingApproval = wallet.pendingApprovals()[0];
            pendingApprovalData['txRequestId'] = 'requestTxIdTest';
            const reqId = new sdk_core_1.RequestTracer();
            const params = {};
            await pendingApproval
                .recreateAndSignTSSTransaction(params, reqId)
                .should.be.rejectedWith('walletPassphrase not found');
        });
        it('should call approve and do the TSS flow and fail if the wallet is missing', async () => {
            const pendingApproval = new sdk_core_1.PendingApproval(bitgo, coin, pendingApprovalData);
            const reqId = new sdk_core_1.RequestTracer();
            const params = { walletPassphrase: 'test' };
            await pendingApproval.recreateAndSignTSSTransaction(params, reqId).should.be.rejectedWith('Wallet not found');
        });
        it('should get txHex for transactionRequestLite', async () => {
            pendingApprovalData['txRequestId'] = 'requestTxIdTest';
            const pendingApproval = new sdk_core_1.PendingApproval(bitgo, coin, pendingApprovalData, wallet);
            const reqId = new sdk_core_1.RequestTracer();
            const txRequestId = 'test';
            const walletPassphrase = 'test';
            const decryptedPrvResponse = 'decryptedPrv';
            const params = { txRequestId, walletPassphrase };
            const txRequest = {
                apiVersion: 'lite',
                txRequestId: txRequestId,
                unsignedTxs: [{ signableHex: 'randomhex', serializedTxHex: 'randomhex2', derivationPath: 'm/0' }],
                signatureShares: [
                    {
                        from: sdk_core_1.SignatureShareType.BITGO,
                        to: sdk_core_1.SignatureShareType.USER,
                        share: '9d7159a76700635TEST',
                    },
                ],
                transactions: [],
                userId: 'userId',
                date: new Date().toISOString(),
                intent: {
                    intentType: 'payment',
                },
                latest: true,
                walletId: 'walletId',
                version: 1,
                policiesChecked: false,
                walletType: 'hot',
                state: 'pendingUserSignature',
            };
            const decryptedPrv = sandbox.stub(sdk_core_1.Wallet.prototype, 'getPrv');
            decryptedPrv.calledOnceWithExactly({ walletPassphrase });
            decryptedPrv.resolves(decryptedPrvResponse);
            const recreateTxRequest = sandbox.stub(sdk_core_1.TssUtils.prototype, 'recreateTxRequest');
            recreateTxRequest.calledOnceWithExactly(txRequest.txRequestId, decryptedPrvResponse, reqId);
            recreateTxRequest.resolves(txRequest);
            const recreatedTx = await pendingApproval.recreateAndSignTSSTransaction(params, reqId);
            recreatedTx.should.be.deepEqual({ txHex: txRequest.unsignedTxs[0].serializedTxHex });
            sandbox.verify();
        });
        it('should get txHex for transactionRequestFull ', async () => {
            pendingApprovalData['txRequestId'] = 'requestTxIdTest';
            const pendingApproval = new sdk_core_1.PendingApproval(bitgo, coin, pendingApprovalData, wallet);
            const reqId = new sdk_core_1.RequestTracer();
            const txRequestId = 'test';
            const walletPassphrase = 'test';
            const decryptedPrvResponse = 'decryptedPrv';
            const params = { txRequestId, walletPassphrase };
            const txRequest = {
                txRequestId: txRequestId,
                apiVersion: 'full',
                unsignedTxs: [],
                transactions: [
                    {
                        unsignedTx: { signableHex: 'randomhex', serializedTxHex: 'randomhex2', derivationPath: 'm/0' },
                        signatureShares: [
                            {
                                from: sdk_core_1.SignatureShareType.BITGO,
                                to: sdk_core_1.SignatureShareType.USER,
                                share: '9d7159a76700635TEST',
                            },
                        ],
                        state: 'initialized',
                    },
                ],
                userId: 'userId',
                date: new Date().toISOString(),
                intent: {
                    intentType: 'payment',
                },
                latest: true,
                walletId: 'walletId',
                version: 1,
                policiesChecked: false,
                walletType: 'hot',
                state: 'pendingDelivery',
            };
            const decryptedPrv = sandbox.stub(sdk_core_1.Wallet.prototype, 'getPrv');
            decryptedPrv.calledOnceWithExactly({ walletPassphrase });
            decryptedPrv.resolves(decryptedPrvResponse);
            const recreateTxRequest = sandbox.stub(sdk_core_1.TssUtils.prototype, 'recreateTxRequest');
            recreateTxRequest.calledOnceWithExactly(txRequest.txRequestId, decryptedPrvResponse, reqId);
            recreateTxRequest.resolves(txRequest);
            const recreatedTx = await pendingApproval.recreateAndSignTSSTransaction(params, reqId);
            recreatedTx.should.be.deepEqual({ txHex: txRequest.transactions[0].unsignedTx.serializedTxHex });
            sandbox.verify();
        });
    });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVuZGluZ0FwcHJvdmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L3BlbmRpbmdBcHByb3ZhbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBOztHQUVHO0FBQ0gsa0JBQWdCO0FBQ2hCLDZCQUE2QjtBQUM3QiwrQkFBK0I7QUFDL0IsOENBQXdEO0FBQ3hELHNDQUFxQztBQUVyQyw4Q0FleUI7QUFFekIsUUFBUSxDQUFDLG9CQUFvQixFQUFFLEdBQUcsRUFBRTtJQUNsQyxJQUFJLE9BQTJCLENBQUM7SUFDaEMsSUFBSSxLQUF5QixDQUFDO0lBQzlCLElBQUksUUFBa0IsQ0FBQztJQUN2QixJQUFJLE1BQWMsQ0FBQztJQUNuQixJQUFJLEtBQWEsQ0FBQztJQUVsQixNQUFNLElBQUksR0FBRyxNQUFNLENBQUM7SUFDcEIsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDO0lBRTdCLE1BQU0sbUJBQW1CLEdBQXdCO1FBQy9DLEVBQUUsRUFBRSxLQUFLO1FBQ1QsSUFBSSxFQUFFO1lBQ0osSUFBSSxFQUFFLGVBQUksQ0FBQyxtQkFBbUI7WUFDOUIsa0JBQWtCLEVBQUU7Z0JBQ2xCLFlBQVksRUFBRTtvQkFDWixDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUU7aUJBQ1g7Z0JBQ0QsVUFBVSxFQUFFLEVBQUU7Z0JBQ2QsV0FBVyxFQUFFO29CQUNYLElBQUksRUFBRSxhQUFhO2lCQUNwQjtnQkFDRCxZQUFZLEVBQUUsUUFBUTthQUN2QjtTQUNGO1FBQ0QsS0FBSyxFQUFFLGdCQUFLLENBQUMsT0FBTztRQUNwQixPQUFPLEVBQUUsTUFBTTtLQUNoQixDQUFDO0lBQ0YsTUFBTSxVQUFVLEdBQUc7UUFDakIsRUFBRSxFQUFFLFFBQVE7UUFDWixJQUFJO1FBQ0osZ0JBQWdCLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQztLQUN4QyxDQUFDO0lBRUYsVUFBVSxDQUFDO1FBQ1QsT0FBTyxHQUFHLEtBQUssQ0FBQyxhQUFh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QUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsU0FBUyxDQUFDLFlBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQztZQUVsRyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbkIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAcHJldHRpZXJcbiAqL1xuaW1wb3J0ICdzaG91bGQnO1xuaW1wb3J0ICogYXMgbm9jayBmcm9tICdub2NrJztcbmltcG9ydCAqIGFzIHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCB7IFRlc3RhYmxlQkcsIFRlc3RCaXRHbyB9IGZyb20gJ0BiaXRnby9zZGstdGVzdCc7XG5pbXBvcnQgeyBCaXRHbyB9IGZyb20gJy4uLy4uLy4uL3NyYyc7XG5cbmltcG9ydCB7XG4gIEJhc2VDb2luLFxuICBFQ0RTQVV0aWxzLFxuICBFZGRzYVV0aWxzLFxuICBFbnZpcm9ubWVudHMsXG4gIFBlbmRpbmdBcHByb3ZhbCxcbiAgUGVuZGluZ0FwcHJvdmFsRGF0YSxcbiAgUGVuZGluZ0FwcHJvdmFsSW5mbyxcbiAgUmVxdWVzdFRyYWNlcixcbiAgU2lnbmF0dXJlU2hhcmVUeXBlLFxuICBTdGF0ZSxcbiAgVHNzVXRpbHMsXG4gIFR4UmVxdWVzdCxcbiAgVHlwZSxcbiAgV2FsbGV0LFxufSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuXG5kZXNjcmliZSgnUGVuZGluZyBBcHByb3ZhbHM6JywgKCkgPT4ge1xuICBsZXQgc2FuZGJveDogc2lub24uU2lub25TYW5kYm94O1xuICBsZXQgYml0Z286IFRlc3RhYmxlQkcgJiBCaXRHbztcbiAgbGV0IGJhc2Vjb2luOiBCYXNlQ29pbjtcbiAgbGV0IHdhbGxldDogV2FsbGV0O1xuICBsZXQgYmdVcmw6IHN0cmluZztcblxuICBjb25zdCBjb2luID0gJ3RidGMnO1xuICBjb25zdCB3YWxsZXRJZCA9ICd3YWxsZXRfaWQnO1xuXG4gIGNvbnN0IHBlbmRpbmdBcHByb3ZhbERhdGE6IFBlbmRpbmdBcHByb3ZhbERhdGEgPSB7XG4gICAgaWQ6ICdwYTAnLFxuICAgIGluZm86IHtcbiAgICAgIHR5cGU6IFR5cGUuVFJBTlNBQ1RJT05fUkVRVUVTVCxcbiAgICAgIHRyYW5zYWN0aW9uUmVxdWVzdDoge1xuICAgICAgICBjb2luU3BlY2lmaWM6IHtcbiAgICAgICAgICBbY29pbl06IHt9LFxuICAgICAgICB9LFxuICAgICAgICByZWNpcGllbnRzOiBbXSxcbiAgICAgICAgYnVpbGRQYXJhbXM6IHtcbiAgICAgICAgICB0eXBlOiAnY29uc29saWRhdGUnLFxuICAgICAgICB9LFxuICAgICAgICBzb3VyY2VXYWxsZXQ6IHdhbGxldElkLFxuICAgICAgfSxcbiAgICB9LFxuICAgIHN0YXRlOiBTdGF0ZS5QRU5ESU5HLFxuICAgIGNyZWF0b3I6ICd0ZXN0JyxcbiAgfTtcbiAgY29uc3Qgd2FsbGV0RGF0YSA9IHtcbiAgICBpZDogd2FsbGV0SWQsXG4gICAgY29pbixcbiAgICBwZW5kaW5nQXBwcm92YWxzOiBbcGVuZGluZ0FwcHJvdmFsRGF0YV0sXG4gIH07XG5cbiAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgc2FuZGJveCA9IHNpbm9uLmNyZWF0ZVNhbmRib3goKTtcbiAgICBub2NrLmRpc2FibGVOZXRDb25uZWN0KCk7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgc2FuZGJveC5yZXN0b3JlKCk7XG4gIH0pO1xuXG4gIGJlZm9yZShhc3luYyAoKSA9PiB7XG4gICAgLy8gY3JlYXRlIHdhbGxldFxuICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvLCB7IGVudjogJ21vY2snIH0pO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIGJhc2Vjb2luID0gYml0Z28uY29pbihjb2luKTtcblxuICAgIHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2Vjb2luLCB3YWxsZXREYXRhKTtcbiAgICBiZ1VybCA9IEVudmlyb25tZW50c1tiaXRnby5nZXRFbnYoKV0udXJpO1xuICAgIChwZW5kaW5nQXBwcm92YWxEYXRhIGFzIGFueSkud2FsbGV0ID0gd2FsbGV0O1xuICB9KTtcblxuICBbJ3Rzb2wnLCAndGV0aCcsICd0YnRjJ10uZm9yRWFjaCgoY29pbk5hbWUpID0+IHtcbiAgICBpdChgc2hvdWxkIHVzZSBjb3JyZWN0IHRzc1V0aWxzIGZvciAgJHtjb2luTmFtZX1gLCAoKSA9PiB7XG4gICAgICBjb25zdCBjb2luID0gYml0Z28uY29pbihjb2luTmFtZSk7XG4gICAgICBjb25zdCBwZW5kaW5nQXByb3ZhbCA9IG5ldyBQZW5kaW5nQXBwcm92YWwoYml0Z28sIGNvaW4sIHt9IGFzIHVua25vd24gYXMgUGVuZGluZ0FwcHJvdmFsRGF0YSk7XG4gICAgICBpZiAoY29pbi5zdXBwb3J0c1RzcygpKSB7XG4gICAgICAgIGlmIChjb2luLmdldE1QQ0FsZ29yaXRobSgpID09PSAnZWNkc2EnKSB7XG4gICAgICAgICAgcGVuZGluZ0Fwcm92YWxbJ3Rzc1V0aWxzJ10uc2hvdWxkLmJlLmluc3RhbmNlT2YoRUNEU0FVdGlscy5FY2RzYVV0aWxzKTtcbiAgICAgICAgfSBlbHNlIGlmIChjb2luLmdldE1QQ0FsZ29yaXRobSgpID09PSAnZWRkc2EnKSB7XG4gICAgICAgICAgcGVuZGluZ0Fwcm92YWxbJ3Rzc1V0aWxzJ10uc2hvdWxkLmJlLmluc3RhbmNlT2YoRWRkc2FVdGlscyk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIChwZW5kaW5nQXByb3ZhbFsndHNzVXRpbHMnXSA9PT0gdW5kZWZpbmVkKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcblxuICBbJ01QQ3YyJywgdW5kZWZpbmVkXS5mb3JFYWNoKChtdWx0aXNpZ1R5cGVWZXJzaW9uKSA9PiB7XG4gICAgaXQoYHNob3VsZCB1c2UgY29ycmVjdCB0c3NVdGlscyBmb3IgbXVsdGlzaWdUeXBlVmVyc2lvbjogJHttdWx0aXNpZ1R5cGVWZXJzaW9ufWAsICgpID0+IHtcbiAgICAgIGNvbnN0IGNvaW4gPSBiaXRnby5jb2luKCdodGV0aCcpO1xuICAgICAgY29uc3Qgd2FsbGV0RGF0YU1wY1YyID0ge1xuICAgICAgICAuLi53YWxsZXREYXRhLFxuICAgICAgICBtdWx0aXNpZ1R5cGVWZXJzaW9uOiBtdWx0aXNpZ1R5cGVWZXJzaW9uLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHdhbGxldE1QQ3YyID0gbmV3IFdhbGxldChiaXRnbywgYmFzZWNvaW4sIHdhbGxldERhdGFNcGNWMik7XG5cbiAgICAgIGNvbnN0IHBlbmRpbmdBcHJvdmFsID0gbmV3IFBlbmRpbmdBcHByb3ZhbChiaXRnbywgY29pbiwge30gYXMgdW5rbm93biBhcyBQZW5kaW5nQXBwcm92YWxEYXRhLCB3YWxsZXRNUEN2Mik7XG4gICAgICBpZiAod2FsbGV0TVBDdjIubXVsdGlzaWdUeXBlVmVyc2lvbigpID09PSAnTVBDdjInKSB7XG4gICAgICAgIHBlbmRpbmdBcHJvdmFsWyd0c3NVdGlscyddLnNob3VsZC5iZS5pbnN0YW5jZU9mKEVDRFNBVXRpbHMuRWNkc2FNUEN2MlV0aWxzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBlbmRpbmdBcHJvdmFsWyd0c3NVdGlscyddLnNob3VsZC5iZS5pbnN0YW5jZU9mKEVDRFNBVXRpbHMuRWNkc2FVdGlscyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgY2FsbCBjb25zb2xpZGF0ZSBpbnN0ZWFkIG9mIGJ1aWxkIHdoZW4gcmVidWlsZGluZyBjb25zb2xpZGF0aW9uIHBlbmRpbmcgYXBwcm92YWxzJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHNjb3BlID0gbm9jayhiZ1VybCkucG9zdChgL2FwaS92Mi8ke2NvaW59L3dhbGxldC8ke3dhbGxldElkfS9jb25zb2xpZGF0ZVVuc3BlbnRzYCkucmVwbHkoMjAwKTtcbiAgICBjb25zdCBwZW5kaW5nQXBwcm92YWxzID0gd2FsbGV0LnBlbmRpbmdBcHByb3ZhbHMoKTtcbiAgICBwZW5kaW5nQXBwcm92YWxzLnNob3VsZC5oYXZlLmxlbmd0aCgxKTtcbiAgICBjb25zdCBwZW5kaW5nQXBwcm92YWwgPSBwZW5kaW5nQXBwcm92YWxzWzBdO1xuXG4gICAgLy8gYXBwcm92YWwgd2lsbCBmYWlsIHdoZW4gYXR0ZW1wdGluZyB0byByZXNpZ24uIFRoaXMgaXMgb2sgLSB3ZSBqdXN0IHdhbnQgdG8gbWFrZSBzdXJlXG4gICAgLy8gdGhlIGNvbnNvbGlkYXRlVW5zcGVudHMgZW5kcG9pbnQgd2FzIGNhbGxlZCBhbHJlYWR5IGJlZm9yZSBmYWlsaW5nXG4gICAgYXdhaXQgcGVuZGluZ0FwcHJvdmFsLmFwcHJvdmUoeyB4cHJ2OiAnbm9uc2Vuc2UnIH0pLnNob3VsZC5iZS5yZWplY3RlZCgpO1xuXG4gICAgc2NvcGUuZG9uZSgpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIGFwcHJvdmUgZm9yIHRyYW5zYWN0aW9uUmVxdWVzdExpdGUgaWYgd2UgY2Fubm90IHJlY3JlYXRlIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHBlbmRpbmdBcHByb3ZhbERhdGEyID0geyAuLi5wZW5kaW5nQXBwcm92YWxEYXRhLCB0eFJlcXVlc3RJZDogJzEyMzQtNDU2Ny02Nzg5JyB9O1xuICAgIGNvbnN0IHBlbmRpbmdBcHByb3ZhbCA9IG5ldyBQZW5kaW5nQXBwcm92YWwoYml0Z28sIGJhc2Vjb2luLCBwZW5kaW5nQXBwcm92YWxEYXRhMiwgd2FsbGV0KTtcblxuICAgIGNvbnN0IHBhU2NvcGUgPSBub2NrKGJnVXJsKVxuICAgICAgLnB1dChgL2FwaS92Mi8ke2NvaW59L3BlbmRpbmdhcHByb3ZhbHMvJHtwZW5kaW5nQXBwcm92YWxEYXRhLmlkfWAsIHtcbiAgICAgICAgc3RhdGU6ICdhcHByb3ZlZCcsXG4gICAgICAgIG90cDogdW5kZWZpbmVkLFxuICAgICAgfSlcbiAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgLi4ucGVuZGluZ0FwcHJvdmFsRGF0YTIsXG4gICAgICAgIHN0YXRlOiAnYXBwcm92ZWQnLFxuICAgICAgfSk7XG4gICAgY29uc3QgcmVjcmVhdGVUcmFuc2FjdGlvblRzc1N0dWIgPSBzYW5kYm94LnN0dWIoUGVuZGluZ0FwcHJvdmFsLnByb3RvdHlwZSwgJ3JlY3JlYXRlQW5kU2lnblRTU1RyYW5zYWN0aW9uJyk7XG4gICAgY29uc3QgcmVjcmVhdGVUcmFuc2FjdGlvblN0dWIgPSBzYW5kYm94LnN0dWIoUGVuZGluZ0FwcHJvdmFsLnByb3RvdHlwZSwgJ3JlY3JlYXRlQW5kU2lnblRyYW5zYWN0aW9uJyk7XG5cbiAgICBwZW5kaW5nQXBwcm92YWwudHlwZSgpLnNob3VsZC5lcXVhbChUeXBlLlRSQU5TQUNUSU9OX1JFUVVFU1QpO1xuICAgIGF3YWl0IHBlbmRpbmdBcHByb3ZhbC5hcHByb3ZlKHt9KTtcbiAgICByZWNyZWF0ZVRyYW5zYWN0aW9uVHNzU3R1Yi5ub3RDYWxsZWQuc2hvdWxkLmJlLnRydWUoKTtcbiAgICByZWNyZWF0ZVRyYW5zYWN0aW9uU3R1Yi5ub3RDYWxsZWQuc2hvdWxkLmJlLnRydWUoKTtcblxuICAgIHBhU2NvcGUuaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgfSk7XG5cbiAgZnVuY3Rpb24gdGVzdFJlY3JlYXRlVHJhbnNhY3Rpb24oY29pbk5hbWU6IHN0cmluZywgcmVjcmVhdGVUcmFuc2FjdGlvbjogYm9vbGVhbiwgdHlwZTogVHlwZSkge1xuICAgIGl0KGBbJHtjb2luTmFtZX1dIHNob3VsZCAke1xuICAgICAgcmVjcmVhdGVUcmFuc2FjdGlvbiA/ICdub3QgJyA6ICcnXG4gICAgfXJlY3JlYXRlIHRoZSB0cmFuc2FjdGlvbiBkdXJpbmcgYXBwcm92aW5nIGEgcGVuZGluZyBhcHByb3ZhbCBpZiB0aGVyZSBhcmUgbm8gcmVjaXBpZW50cyBmb3IgUEEgdHlwZSAke3R5cGV9YCwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgY29pbiA9IGJpdGdvLmNvaW4oY29pbk5hbWUpO1xuICAgICAgY29uc3QgdHhSZXF1ZXN0SWQgPSBjb2luLnN1cHBvcnRzVHNzKCkgPyAncmVxdWVzdFR4SWRUZXN0JyA6IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHBlbmRpbmdBcHByb3ZhbEluZm8gPVxuICAgICAgICB0eXBlID09PSAndHJhbnNhY3Rpb25SZXF1ZXN0J1xuICAgICAgICAgID8ge1xuICAgICAgICAgICAgICB0eXBlLFxuICAgICAgICAgICAgICB0cmFuc2FjdGlvblJlcXVlc3Q6IHtcbiAgICAgICAgICAgICAgICBjb2luU3BlY2lmaWM6IHtcbiAgICAgICAgICAgICAgICAgIFtjb2luTmFtZV06IHsgdHhIZXg6ICdnYWJhZ29vbCcgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHJlY2lwaWVudHM6IFtdLFxuICAgICAgICAgICAgICAgIGJ1aWxkUGFyYW1zOiB7fSxcbiAgICAgICAgICAgICAgICBzb3VyY2VXYWxsZXQ6IHdhbGxldElkLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfVxuICAgICAgICAgIDogKHsgdHlwZSB9IGFzIHVua25vd24gYXMgUGVuZGluZ0FwcHJvdmFsSW5mbyk7XG4gICAgICBjb25zdCBwZW5kaW5nQXBwcm92YWxEYXRhVGVtcDogUGVuZGluZ0FwcHJvdmFsRGF0YSA9IHtcbiAgICAgICAgaWQ6ICdwYTAnLFxuICAgICAgICBpbmZvOiBwZW5kaW5nQXBwcm92YWxJbmZvLFxuICAgICAgICB3YWxsZXQ6IHdhbGxldElkLFxuICAgICAgICBzdGF0ZTogU3RhdGUuUEVORElORyxcbiAgICAgICAgY3JlYXRvcjogJ3Rlc3QnLFxuICAgICAgICB0eFJlcXVlc3RJZCxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHdhbGxldERhdGFUZW1wID0ge1xuICAgICAgICBpZDogd2FsbGV0SWQsXG4gICAgICAgIGNvaW5OYW1lLFxuICAgICAgICBwZW5kaW5nQXBwcm92YWxzOiBbcGVuZGluZ0FwcHJvdmFsRGF0YVRlbXBdLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHdhbGxldFRlbXAgPSBuZXcgV2FsbGV0KGJpdGdvLCBjb2luLCB3YWxsZXREYXRhVGVtcCk7XG4gICAgICBwZW5kaW5nQXBwcm92YWxEYXRhVGVtcC53YWxsZXQgPSB3YWxsZXRUZW1wLmlkKCk7XG5cbiAgICAgIGNvbnN0IHBlbmRpbmdBcHByb3ZhbHMgPSB3YWxsZXRUZW1wLnBlbmRpbmdBcHByb3ZhbHMoKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbHMuc2hvdWxkLmhhdmUubGVuZ3RoKDEpO1xuICAgICAgY29uc3QgcGVuZGluZ0FwcHJvdmFsID0gcGVuZGluZ0FwcHJvdmFsc1swXTtcblxuICAgICAgbGV0IHN0dWI6IHNpbm9uLlNpbm9uU3R1YjtcbiAgICAgIGlmIChjb2luLnN1cHBvcnRzVHNzKCkpIHtcbiAgICAgICAgc3R1YiA9IHNhbmRib3guc3R1YihQZW5kaW5nQXBwcm92YWwucHJvdG90eXBlLCAncmVjcmVhdGVBbmRTaWduVFNTVHJhbnNhY3Rpb24nKS5yZXNvbHZlcyh7XG4gICAgICAgICAgdHhIZXg6ICdnYWJhZ29vbCcsXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3R1YiA9IHNhbmRib3guc3R1YihQZW5kaW5nQXBwcm92YWwucHJvdG90eXBlLCAncmVjcmVhdGVBbmRTaWduVHJhbnNhY3Rpb24nKS5yZXNvbHZlcyh7XG4gICAgICAgICAgc3RhdGU6ICdhcHByb3ZlZCcsXG4gICAgICAgICAgaGFsZlNpZ25lZDogeyB0eEhleDogJ2dhYmFnb29sJyB9LFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcGFTY29wZSA9IG5vY2soYmdVcmwpXG4gICAgICAgIC5wdXQoYC9hcGkvdjIvJHtjb2luTmFtZX0vcGVuZGluZ2FwcHJvdmFscy8ke3BlbmRpbmdBcHByb3ZhbERhdGFUZW1wLmlkfWAsIHtcbiAgICAgICAgICBzdGF0ZTogJ2FwcHJvdmVkJyxcbiAgICAgICAgICBoYWxmU2lnbmVkOiB0eXBlID09PSBUeXBlLlRSQU5TQUNUSU9OX1JFUVVFU1QgPyB7IHR4SGV4OiAnZ2FiYWdvb2wnIH0gOiB1bmRlZmluZWQsXG4gICAgICAgIH0pXG4gICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAuLi5wZW5kaW5nQXBwcm92YWxEYXRhVGVtcCxcbiAgICAgICAgICBzdGF0ZTogJ2FwcHJvdmVkJyxcbiAgICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IHBlbmRpbmdBcHByb3ZhbC5hcHByb3ZlKHsgeHBydjogJ25vbnNlbnNlJywgd2FsbGV0UGFzc3BocmFzZTogJ2dhYmFnb29saW8nIH0pO1xuXG4gICAgICAvLyBTaG91bGQgbm90IGNhbGwgYnVpbGQgYW5kIHNob3VsZCBjYWxsIHBhXG4gICAgICBwYVNjb3BlLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgICBzdHViLmNhbGxlZE9uY2Uuc2hvdWxkLmVxdWFsKHJlY3JlYXRlVHJhbnNhY3Rpb24pO1xuICAgIH0pO1xuICB9XG5cbiAgdGVzdFJlY3JlYXRlVHJhbnNhY3Rpb24oJ3RidGMnLCBmYWxzZSwgVHlwZS5UUkFOU0FDVElPTl9SRVFVRVNUKTtcbiAgdGVzdFJlY3JlYXRlVHJhbnNhY3Rpb24oJ3Rzb2wnLCB0cnVlLCBUeXBlLlRSQU5TQUNUSU9OX1JFUVVFU1QpO1xuICB0ZXN0UmVjcmVhdGVUcmFuc2FjdGlvbigndHNvbCcsIHRydWUsIFR5cGUuVFJBTlNBQ1RJT05fUkVRVUVTVF9GVUxMKTtcbiAgdGVzdFJlY3JlYXRlVHJhbnNhY3Rpb24oJ3RldGgnLCB0cnVlLCBUeXBlLlRSQU5TQUNUSU9OX1JFUVVFU1RfRlVMTCk7XG5cbiAgZGVzY3JpYmUoJ3JlY3JlYXRlQW5kU2lnblRTU1RyYW5zYWN0aW9uJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBjb2luOiBCYXNlQ29pbjtcblxuICAgIGJlZm9yZSgoKSA9PiB7XG4gICAgICBjb2luID0gYml0Z28uY29pbigndHNvbCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBjYWxsIGFwcHJvdmUgYW5kIGRvIHRoZSBUU1MgZmxvdyBhbmQgZmFpbCBpZiB0aGUgdHhSZXF1ZXN0SWQgaXMgbWlzc2luZycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHBlbmRpbmdBcHByb3ZhbCA9IHdhbGxldC5wZW5kaW5nQXBwcm92YWxzKClbMF07XG4gICAgICBjb25zdCByZXFJZCA9IG5ldyBSZXF1ZXN0VHJhY2VyKCk7XG4gICAgICBjb25zdCBwYXJhbXMgPSB7IHdhbGxldFBhc3NwaHJhc2U6ICd0ZXN0JyB9O1xuICAgICAgYXdhaXQgcGVuZGluZ0FwcHJvdmFsXG4gICAgICAgIC5yZWNyZWF0ZUFuZFNpZ25UU1NUcmFuc2FjdGlvbihwYXJhbXMsIHJlcUlkKVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgndHhSZXF1ZXN0SWQgbm90IGZvdW5kJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGNhbGwgYXBwcm92ZSBhbmQgZG8gdGhlIFRTUyBmbG93IGFuZCBmYWlsIGlmIHRoZSB3YWxsZXRQYXNzcGhyYXNlIGlzIG1pc3NpbmcnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBwZW5kaW5nQXBwcm92YWwgPSB3YWxsZXQucGVuZGluZ0FwcHJvdmFscygpWzBdO1xuICAgICAgcGVuZGluZ0FwcHJvdmFsRGF0YVsndHhSZXF1ZXN0SWQnXSA9ICdyZXF1ZXN0VHhJZFRlc3QnO1xuICAgICAgY29uc3QgcmVxSWQgPSBuZXcgUmVxdWVzdFRyYWNlcigpO1xuICAgICAgY29uc3QgcGFyYW1zID0ge307XG4gICAgICBhd2FpdCBwZW5kaW5nQXBwcm92YWxcbiAgICAgICAgLnJlY3JlYXRlQW5kU2lnblRTU1RyYW5zYWN0aW9uKHBhcmFtcywgcmVxSWQpXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCd3YWxsZXRQYXNzcGhyYXNlIG5vdCBmb3VuZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBjYWxsIGFwcHJvdmUgYW5kIGRvIHRoZSBUU1MgZmxvdyBhbmQgZmFpbCBpZiB0aGUgd2FsbGV0IGlzIG1pc3NpbmcnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBwZW5kaW5nQXBwcm92YWwgPSBuZXcgUGVuZGluZ0FwcHJvdmFsKGJpdGdvLCBjb2luLCBwZW5kaW5nQXBwcm92YWxEYXRhKTtcbiAgICAgIGNvbnN0IHJlcUlkID0gbmV3IFJlcXVlc3RUcmFjZXIoKTtcbiAgICAgIGNvbnN0IHBhcmFtcyA9IHsgd2FsbGV0UGFzc3BocmFzZTogJ3Rlc3QnIH07XG4gICAgICBhd2FpdCBwZW5kaW5nQXBwcm92YWwucmVjcmVhdGVBbmRTaWduVFNTVHJhbnNhY3Rpb24ocGFyYW1zLCByZXFJZCkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnV2FsbGV0IG5vdCBmb3VuZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZXQgdHhIZXggZm9yIHRyYW5zYWN0aW9uUmVxdWVzdExpdGUnLCBhc3luYyAoKSA9PiB7XG4gICAgICBwZW5kaW5nQXBwcm92YWxEYXRhWyd0eFJlcXVlc3RJZCddID0gJ3JlcXVlc3RUeElkVGVzdCc7XG4gICAgICBjb25zdCBwZW5kaW5nQXBwcm92YWwgPSBuZXcgUGVuZGluZ0FwcHJvdmFsKGJpdGdvLCBjb2luLCBwZW5kaW5nQXBwcm92YWxEYXRhLCB3YWxsZXQpO1xuICAgICAgY29uc3QgcmVxSWQgPSBuZXcgUmVxdWVzdFRyYWNlcigpO1xuICAgICAgY29uc3QgdHhSZXF1ZXN0SWQgPSAndGVzdCc7XG4gICAgICBjb25zdCB3YWxsZXRQYXNzcGhyYXNlID0gJ3Rlc3QnO1xuICAgICAgY29uc3QgZGVjcnlwdGVkUHJ2UmVzcG9uc2UgPSAnZGVjcnlwdGVkUHJ2JztcbiAgICAgIGNvbnN0IHBhcmFtcyA9IHsgdHhSZXF1ZXN0SWQsIHdhbGxldFBhc3NwaHJhc2UgfTtcbiAgICAgIGNvbnN0IHR4UmVxdWVzdDogVHhSZXF1ZXN0ID0ge1xuICAgICAgICBhcGlWZXJzaW9uOiAnbGl0ZScsXG4gICAgICAgIHR4UmVxdWVzdElkOiB0eFJlcXVlc3RJZCxcbiAgICAgICAgdW5zaWduZWRUeHM6IFt7IHNpZ25hYmxlSGV4OiAncmFuZG9taGV4Jywgc2VyaWFsaXplZFR4SGV4OiAncmFuZG9taGV4MicsIGRlcml2YXRpb25QYXRoOiAnbS8wJyB9XSxcbiAgICAgICAgc2lnbmF0dXJlU2hhcmVzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgZnJvbTogU2lnbmF0dXJlU2hhcmVUeXBlLkJJVEdPLFxuICAgICAgICAgICAgdG86IFNpZ25hdHVyZVNoYXJlVHlwZS5VU0VSLFxuICAgICAgICAgICAgc2hhcmU6ICc5ZDcxNTlhNzY3MDA2MzVURVNUJyxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICB0cmFuc2FjdGlvbnM6IFtdLFxuICAgICAgICB1c2VySWQ6ICd1c2VySWQnLFxuICAgICAgICBkYXRlOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIGludGVudDoge1xuICAgICAgICAgIGludGVudFR5cGU6ICdwYXltZW50JyxcbiAgICAgICAgfSxcbiAgICAgICAgbGF0ZXN0OiB0cnVlLFxuICAgICAgICB3YWxsZXRJZDogJ3dhbGxldElkJyxcbiAgICAgICAgdmVyc2lvbjogMSxcbiAgICAgICAgcG9saWNpZXNDaGVja2VkOiBmYWxzZSxcbiAgICAgICAgd2FsbGV0VHlwZTogJ2hvdCcsXG4gICAgICAgIHN0YXRlOiAncGVuZGluZ1VzZXJTaWduYXR1cmUnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZGVjcnlwdGVkUHJ2ID0gc2FuZGJveC5zdHViKFdhbGxldC5wcm90b3R5cGUsICdnZXRQcnYnKTtcbiAgICAgIGRlY3J5cHRlZFBydi5jYWxsZWRPbmNlV2l0aEV4YWN0bHkoeyB3YWxsZXRQYXNzcGhyYXNlIH0pO1xuICAgICAgZGVjcnlwdGVkUHJ2LnJlc29sdmVzKGRlY3J5cHRlZFBydlJlc3BvbnNlKTtcblxuICAgICAgY29uc3QgcmVjcmVhdGVUeFJlcXVlc3QgPSBzYW5kYm94LnN0dWIoVHNzVXRpbHMucHJvdG90eXBlLCAncmVjcmVhdGVUeFJlcXVlc3QnKTtcbiAgICAgIHJlY3JlYXRlVHhSZXF1ZXN0LmNhbGxlZE9uY2VXaXRoRXhhY3RseSh0eFJlcXVlc3QudHhSZXF1ZXN0SWQsIGRlY3J5cHRlZFBydlJlc3BvbnNlLCByZXFJZCk7XG4gICAgICByZWNyZWF0ZVR4UmVxdWVzdC5yZXNvbHZlcyh0eFJlcXVlc3QpO1xuXG4gICAgICBjb25zdCByZWNyZWF0ZWRUeCA9IGF3YWl0IHBlbmRpbmdBcHByb3ZhbC5yZWNyZWF0ZUFuZFNpZ25UU1NUcmFuc2FjdGlvbihwYXJhbXMsIHJlcUlkKTtcbiAgICAgIHJlY3JlYXRlZFR4LnNob3VsZC5iZS5kZWVwRXF1YWwoeyB0eEhleDogdHhSZXF1ZXN0LnVuc2lnbmVkVHhzWzBdLnNlcmlhbGl6ZWRUeEhleCB9KTtcblxuICAgICAgc2FuZGJveC52ZXJpZnkoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2V0IHR4SGV4IGZvciB0cmFuc2FjdGlvblJlcXVlc3RGdWxsICcsIGFzeW5jICgpID0+IHtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbERhdGFbJ3R4UmVxdWVzdElkJ10gPSAncmVxdWVzdFR4SWRUZXN0JztcbiAgICAgIGNvbnN0IHBlbmRpbmdBcHByb3ZhbCA9IG5ldyBQZW5kaW5nQXBwcm92YWwoYml0Z28sIGNvaW4sIHBlbmRpbmdBcHByb3ZhbERhdGEsIHdhbGxldCk7XG4gICAgICBjb25zdCByZXFJZCA9IG5ldyBSZXF1ZXN0VHJhY2VyKCk7XG4gICAgICBjb25zdCB0eFJlcXVlc3RJZCA9ICd0ZXN0JztcbiAgICAgIGNvbnN0IHdhbGxldFBhc3NwaHJhc2UgPSAndGVzdCc7XG4gICAgICBjb25zdCBkZWNyeXB0ZWRQcnZSZXNwb25zZSA9ICdkZWNyeXB0ZWRQcnYnO1xuICAgICAgY29uc3QgcGFyYW1zID0geyB0eFJlcXVlc3RJZCwgd2FsbGV0UGFzc3BocmFzZSB9O1xuICAgICAgY29uc3QgdHhSZXF1ZXN0OiBUeFJlcXVlc3QgPSB7XG4gICAgICAgIHR4UmVxdWVzdElkOiB0eFJlcXVlc3RJZCxcbiAgICAgICAgYXBpVmVyc2lvbjogJ2Z1bGwnLFxuICAgICAgICB1bnNpZ25lZFR4czogW10sXG4gICAgICAgIHRyYW5zYWN0aW9uczogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIHVuc2lnbmVkVHg6IHsgc2lnbmFibGVIZXg6ICdyYW5kb21oZXgnLCBzZXJpYWxpemVkVHhIZXg6ICdyYW5kb21oZXgyJywgZGVyaXZhdGlvblBhdGg6ICdtLzAnIH0sXG4gICAgICAgICAgICBzaWduYXR1cmVTaGFyZXM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGZyb206IFNpZ25hdHVyZVNoYXJlVHlwZS5CSVRHTyxcbiAgICAgICAgICAgICAgICB0bzogU2lnbmF0dXJlU2hhcmVUeXBlLlVTRVIsXG4gICAgICAgICAgICAgICAgc2hhcmU6ICc5ZDcxNTlhNzY3MDA2MzVURVNUJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBzdGF0ZTogJ2luaXRpYWxpemVkJyxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICB1c2VySWQ6ICd1c2VySWQnLFxuICAgICAgICBkYXRlOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIGludGVudDoge1xuICAgICAgICAgIGludGVudFR5cGU6ICdwYXltZW50JyxcbiAgICAgICAgfSxcbiAgICAgICAgbGF0ZXN0OiB0cnVlLFxuICAgICAgICB3YWxsZXRJZDogJ3dhbGxldElkJyxcbiAgICAgICAgdmVyc2lvbjogMSxcbiAgICAgICAgcG9saWNpZXNDaGVja2VkOiBmYWxzZSxcbiAgICAgICAgd2FsbGV0VHlwZTogJ2hvdCcsXG4gICAgICAgIHN0YXRlOiAncGVuZGluZ0RlbGl2ZXJ5JyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGRlY3J5cHRlZFBydiA9IHNhbmRib3guc3R1YihXYWxsZXQucHJvdG90eXBlLCAnZ2V0UHJ2Jyk7XG4gICAgICBkZWNyeXB0ZWRQcnYuY2FsbGVkT25jZVdpdGhFeGFjdGx5KHsgd2FsbGV0UGFzc3BocmFzZSB9KTtcbiAgICAgIGRlY3J5cHRlZFBydi5yZXNvbHZlcyhkZWNyeXB0ZWRQcnZSZXNwb25zZSk7XG5cbiAgICAgIGNvbnN0IHJlY3JlYXRlVHhSZXF1ZXN0ID0gc2FuZGJveC5zdHViKFRzc1V0aWxzLnByb3RvdHlwZSwgJ3JlY3JlYXRlVHhSZXF1ZXN0Jyk7XG4gICAgICByZWNyZWF0ZVR4UmVxdWVzdC5jYWxsZWRPbmNlV2l0aEV4YWN0bHkodHhSZXF1ZXN0LnR4UmVxdWVzdElkLCBkZWNyeXB0ZWRQcnZSZXNwb25zZSwgcmVxSWQpO1xuICAgICAgcmVjcmVhdGVUeFJlcXVlc3QucmVzb2x2ZXModHhSZXF1ZXN0KTtcblxuICAgICAgY29uc3QgcmVjcmVhdGVkVHggPSBhd2FpdCBwZW5kaW5nQXBwcm92YWwucmVjcmVhdGVBbmRTaWduVFNTVHJhbnNhY3Rpb24ocGFyYW1zLCByZXFJZCk7XG4gICAgICByZWNyZWF0ZWRUeC5zaG91bGQuYmUuZGVlcEVxdWFsKHsgdHhIZXg6IHR4UmVxdWVzdC50cmFuc2FjdGlvbnMhWzBdLnVuc2lnbmVkVHguc2VyaWFsaXplZFR4SGV4IH0pO1xuXG4gICAgICBzYW5kYm94LnZlcmlmeSgpO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19

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


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