PHP WebShell

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

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * @prettier
 */
const assert = require("assert");
const abstract_utxo_1 = require("@bitgo/abstract-utxo");
const utxolib = require("@bitgo/utxo-lib");
const nock = require("nock");
const util_1 = require("./util");
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_test_1 = require("@bitgo/sdk-test");
const src_1 = require("../../../../../src");
const txFormats = ['legacy', 'psbt'];
const walletPassphrase = 'gabagool';
const webauthnWalletPassPhrase = 'just the gabagool';
const scriptTypes = [...utxolib.bitgo.outputScripts.scriptTypes2Of3, 'taprootKeyPathSpend', 'p2shP2pk'];
function assertSignable(psbtHex, inputScripts, network) {
    const psbt = utxolib.bitgo.createPsbtFromHex(psbtHex, network);
    // Make sure that you can sign with bitgo key and extract the transaction
    // No signatures should be present if it's a p2shP2pk input
    if (!inputScripts.includes('p2shP2pk')) {
        const key = inputScripts.includes('p2trMusig2') ? rootWalletKeys.backup : rootWalletKeys.bitgo;
        psbt.signAllInputsHD(key, { deterministic: true });
        psbt.validateSignaturesOfAllInputs();
        psbt.finalizeAllInputs();
        const tx = psbt.extractTransaction();
        assert.ok(tx);
    }
}
// Build the key objects
const rootWalletKeys = (0, util_1.getDefaultWalletKeys)();
const keyDocumentObjects = rootWalletKeys.triple.map((bip32, keyIdx) => {
    return {
        id: (0, sdk_test_1.getSeed)(util_1.keychainsBase58[keyIdx].pub).toString('hex'),
        pub: bip32.neutered().toBase58(),
        source: ['user', 'backup', 'bitgo'][keyIdx],
        encryptedPrv: (0, util_1.encryptKeychain)(walletPassphrase, util_1.keychainsBase58[keyIdx]),
        webauthnDevices: [
            {
                otpDeviceId: '123',
                authenticatorInfo: {
                    credID: 'credID',
                    fmt: 'packed',
                    publicKey: 'some value',
                },
                prfSalt: '456',
                encryptedPrv: (0, util_1.encryptKeychain)(webauthnWalletPassPhrase, util_1.keychainsBase58[keyIdx]),
            },
        ],
        coinSpecific: {},
    };
});
function run(coin, inputScripts, txFormat) {
    function createPrebuildPsbt(inputs, outputs) {
        const psbt = utxolib.testutil.constructPsbt(inputs, outputs, coin.network, rootWalletKeys, 'unsigned');
        utxolib.bitgo.addXpubsToPsbt(psbt, rootWalletKeys);
        return psbt;
    }
    function createNocks(params) {
        const nocks = [];
        // Nock the prebuild route (/tx/build, blockheight)
        const expected_params = {
            recipients: [params.recipient],
            rbfTxIds: params.rbfTxIds,
            feeMultiplier: params.feeMultiplier,
            changeAddressType: ['p2trMusig2', 'p2wsh', 'p2shP2wsh', 'p2sh', 'p2tr'],
        };
        if (params.txFormat) {
            expected_params['txFormat'] = params.txFormat;
        }
        nocks.push(nock(params.bgUrl)
            .post(`/api/v2/${coin.getChain()}/wallet/${params.wallet.id()}/tx/build`, expected_params)
            .reply(200, { txHex: params.prebuild.toHex(), txInfo: {} }));
        nocks.push(nock(params.bgUrl).get(`/api/v2/${coin.getChain()}/public/block/latest`).reply(200, { height: 1000 }));
        // nock the keychain fetch - 3 times (prebuildAndSign, verifyTransaction, and signTransaction)
        params.keyDocuments.forEach((keyDocument) => {
            nocks.push(nock(params.bgUrl).get(`/api/v2/${coin.getChain()}/key/${keyDocument.id}`).times(3).reply(200, keyDocument));
        });
        // nock the address info fetch
        if (params.nockOutputAddresses) {
            nocks.push(nock(params.bgUrl)
                .get(`/api/v2/${coin.getChain()}/wallet/${params.wallet.id()}/address/${params.addressInfo.address}`)
                .reply(200, params.addressInfo));
        }
        if (params.rbfTxIds) {
            nocks.push(nock(params.bgUrl)
                .get(`/api/v2/${coin.getChain()}/wallet/${params.wallet.id()}/tx/${params.rbfTxIds[0]}?includeRbf=true`)
                .reply(200, {
                outputs: [
                    {
                        address: params.recipient.address,
                        value: Number(params.recipient.amount),
                        valueString: params.recipient.amount,
                        wallet: params.selfSend ? params.wallet.id() : 'some-other-wallet-id', // external output if not a self send
                    },
                    // Dummy change output to test transfer entries filtering
                    {
                        address: params.recipient.address,
                        value: Number(params.recipient.amount),
                        valueString: params.recipient.amount,
                        wallet: params.wallet.id(), // internal output
                    },
                ],
            }));
        }
        // nock the deterministic nonce response
        if (inputScripts.includes('taprootKeyPathSpend')) {
            const psbt = params.prebuild.clone();
            psbt.setAllInputsMusig2NonceHD(rootWalletKeys.user);
            psbt.setAllInputsMusig2NonceHD(rootWalletKeys.bitgo);
            nocks.push(nock(params.bgUrl)
                .post(`/api/v2/${coin.getChain()}/wallet/${params.wallet.id()}/tx/signpsbt`, (body) => body.psbt)
                .reply(200, { psbt: psbt.toHex() }));
        }
        return nocks;
    }
    describe(`${coin.getFullName()}-prebuildAndSign-txFormat=${txFormat}-inputScripts=${inputScripts.join(',')}`, function () {
        const wallet = (0, util_1.getUtxoWallet)(coin, {
            coinSpecific: { addressVersion: 'base58' },
            keys: keyDocumentObjects.map((k) => k.id),
            id: 'walletId',
        });
        const bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
        const bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
        let prebuild;
        let recipient;
        let addressInfo;
        const fee = BigInt(10000);
        before(async function () {
            // Make output address information
            const outputAmount = BigInt(inputScripts.length) * BigInt(1e8) - fee;
            const outputScriptType = 'p2sh';
            const outputChain = utxolib.bitgo.getExternalChainCode(outputScriptType);
            const outputAddress = utxolib.bitgo.getWalletAddress(rootWalletKeys, outputChain, 0, coin.network);
            recipient = {
                address: outputAddress,
                amount: outputAmount.toString(),
            };
            addressInfo = {
                address: outputAddress,
                chain: outputChain,
                index: 0,
                coin: coin.getChain(),
                wallet: wallet.id(),
                coinSpecific: {},
            };
            prebuild = createPrebuildPsbt(inputScripts.map((s) => ({ scriptType: s, value: BigInt(1e8) })), [{ scriptType: outputScriptType, value: outputAmount }]);
        });
        afterEach(nock.cleanAll);
        [true, false].forEach((useWebauthn) => {
            it(`should succeed with ${useWebauthn ? 'webauthn encryptedPrv' : 'encryptedPrv'}`, async function () {
                const txCoins = ['tzec', 'zec', 'ltc', 'bcha', 'doge', 'dash', 'btg', 'bch'];
                const nocks = createNocks({
                    bgUrl,
                    wallet,
                    keyDocuments: keyDocumentObjects,
                    prebuild,
                    recipient,
                    addressInfo,
                    nockOutputAddresses: txFormat !== 'psbt',
                    txFormat: !txCoins.includes(coin.getChain()) ? 'psbt' : undefined,
                });
                // call prebuild and sign, nocks should be consumed
                const res = (await wallet.prebuildAndSignTransaction({
                    recipients: [recipient],
                    walletPassphrase: useWebauthn ? webauthnWalletPassPhrase : walletPassphrase,
                }));
                nocks.forEach((nock) => assert.ok(nock.isDone()));
                assertSignable(res.txHex, inputScripts, coin.network);
            });
            it('should fail if the wallet passphrase is incorrect', async function () {
                createNocks({
                    bgUrl,
                    wallet,
                    keyDocuments: keyDocumentObjects,
                    prebuild,
                    recipient,
                    addressInfo,
                    nockOutputAddresses: txFormat !== 'psbt',
                });
                await wallet
                    .prebuildAndSignTransaction({
                    recipients: [recipient],
                    walletPassphrase: Math.random().toString(),
                })
                    .should.be.rejectedWith('unable to decrypt keychain with the given wallet passphrase');
            });
        });
        [true, false].forEach((selfSend) => {
            it(`should be able to build, sign, & verify a replacement transaction with selfSend: ${selfSend}`, async function () {
                const rbfTxIds = ['tx-to-be-replaced'], feeMultiplier = 1.5;
                const txCoins = ['tzec', 'zec', 'ltc', 'bcha', 'doge', 'dash', 'btg', 'bch'];
                const nocks = createNocks({
                    bgUrl,
                    wallet,
                    keyDocuments: keyDocumentObjects,
                    prebuild,
                    recipient,
                    addressInfo,
                    rbfTxIds,
                    feeMultiplier,
                    selfSend,
                    nockOutputAddresses: txFormat !== 'psbt',
                    txFormat: !txCoins.includes(coin.getChain()) ? 'psbt' : undefined,
                });
                // call prebuild and sign, nocks should be consumed
                const res = (await wallet.prebuildAndSignTransaction({
                    recipients: [recipient],
                    walletPassphrase,
                    rbfTxIds,
                    feeMultiplier,
                }));
                nocks.forEach((nock) => assert.ok(nock.isDone()));
                assertSignable(res.txHex, inputScripts, coin.network);
            });
        });
    });
}
util_1.utxoCoins
    .filter((coin) => utxolib.getMainnet(coin.network) !== utxolib.networks.bitcoinsv)
    .forEach((coin) => {
    scriptTypes
        // Don't iterate over p2shP2pk - in no scenario would a wallet spend two p2shP2pk inputs as these
        // are single signature inputs that are used for replay protection and are added to the transaction
        // by our system from a separate wallet. We do run tests below where one of the inputs is a p2shP2pk and
        // the other is an input spent by the user.
        .filter((scriptType) => scriptType !== 'p2shP2pk')
        .forEach((inputScript) => {
        const inputScriptCleaned = (inputScript === 'taprootKeyPathSpend' ? 'p2trMusig2' : inputScript);
        if (!coin.supportsAddressType(inputScriptCleaned)) {
            return;
        }
        run(coin, [inputScript, inputScript], 'psbt');
        if ((0, abstract_utxo_1.getReplayProtectionAddresses)(coin.network).length) {
            run(coin, ['p2shP2pk', inputScript], 'psbt');
        }
    });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJlYnVpbGRBbmRTaWduLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2NvaW5zL3V0eG8vcHJlYnVpbGRBbmRTaWduLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUE7O0dBRUc7QUFDSCxpQ0FBaUM7QUFFakMsd0RBQXNGO0FBQ3RGLDJDQUEyQztBQUMzQyw2QkFBNkI7QUFFN0IsaUNBQTBHO0FBQzFHLDhDQUE0RTtBQUM1RSw4Q0FBcUQ7QUFDckQsNENBQTJDO0FBRTNDLE1BQU0sU0FBUyxHQUFHLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBVSxDQUFDO0FBVzlDLE1BQU0sZ0JBQWdCLEdBQUcsVUFBVSxDQUFDO0FBQ3BDLE1BQU0sd0JBQXdCLEdBQUcsbUJBQW1CLENBQUM7QUFFckQsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxVQUFVLENBQVUsQ0FBQztBQVFqSCxTQUFTLGNBQWMsQ0FBQyxPQUFlLEVBQUUsWUFBMEIsRUFBRSxPQUF3QjtJQUMzRixNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMvRCx5RUFBeUU7SUFDekUsMkRBQTJEO0lBQzNELElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDdkMsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQztRQUMvRixJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsRUFBRSxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyw2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Q0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDO1lBQ2xELE9BQU87UUFDVCxDQUFDO1FBRUQsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM5QyxJQUFJLElBQUEsNENBQTRCLEVBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3RELEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDL0MsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwcmV0dGllclxuICovXG5pbXBvcnQgKiBhcyBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcblxuaW1wb3J0IHsgQWJzdHJhY3RVdHhvQ29pbiwgZ2V0UmVwbGF5UHJvdGVjdGlvbkFkZHJlc3NlcyB9IGZyb20gJ0BiaXRnby9hYnN0cmFjdC11dHhvJztcbmltcG9ydCAqIGFzIHV0eG9saWIgZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcbmltcG9ydCAqIGFzIG5vY2sgZnJvbSAnbm9jayc7XG5cbmltcG9ydCB7IGVuY3J5cHRLZXljaGFpbiwgZ2V0RGVmYXVsdFdhbGxldEtleXMsIGdldFV0eG9XYWxsZXQsIGtleWNoYWluc0Jhc2U1OCwgdXR4b0NvaW5zIH0gZnJvbSAnLi91dGlsJztcbmltcG9ydCB7IGNvbW1vbiwgSGFsZlNpZ25lZFV0eG9UcmFuc2FjdGlvbiwgV2FsbGV0IH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IGdldFNlZWQsIFRlc3RCaXRHbyB9IGZyb20gJ0BiaXRnby9zZGstdGVzdCc7XG5pbXBvcnQgeyBCaXRHbyB9IGZyb20gJy4uLy4uLy4uLy4uLy4uL3NyYyc7XG5cbmNvbnN0IHR4Rm9ybWF0cyA9IFsnbGVnYWN5JywgJ3BzYnQnXSBhcyBjb25zdDtcbmV4cG9ydCB0eXBlIFR4Rm9ybWF0ID0gKHR5cGVvZiB0eEZvcm1hdHMpW251bWJlcl07XG5cbnR5cGUgS2V5RG9jID0ge1xuICBpZDogc3RyaW5nO1xuICBwdWI6IHN0cmluZztcbiAgc291cmNlOiBzdHJpbmc7XG4gIGVuY3J5cHRlZFBydjogc3RyaW5nO1xuICBjb2luU3BlY2lmaWM6IGFueTtcbn07XG5cbmNvbnN0IHdhbGxldFBhc3NwaHJhc2UgPSAnZ2FiYWdvb2wnO1xuY29uc3Qgd2ViYXV0aG5XYWxsZXRQYXNzUGhyYXNlID0gJ2p1c3QgdGhlIGdhYmFnb29sJztcblxuY29uc3Qgc2NyaXB0VHlwZXMgPSBbLi4udXR4b2xpYi5iaXRnby5vdXRwdXRTY3JpcHRzLnNjcmlwdFR5cGVzMk9mMywgJ3RhcHJvb3RLZXlQYXRoU3BlbmQnLCAncDJzaFAycGsnXSBhcyBjb25zdDtcbmV4cG9ydCB0eXBlIFNjcmlwdFR5cGUgPSAodHlwZW9mIHNjcmlwdFR5cGVzKVtudW1iZXJdO1xuXG50eXBlIElucHV0ID0ge1xuICBzY3JpcHRUeXBlOiBTY3JpcHRUeXBlO1xuICB2YWx1ZTogYmlnaW50O1xufTtcblxuZnVuY3Rpb24gYXNzZXJ0U2lnbmFibGUocHNidEhleDogc3RyaW5nLCBpbnB1dFNjcmlwdHM6IFNjcmlwdFR5cGVbXSwgbmV0d29yazogdXR4b2xpYi5OZXR3b3JrKTogdm9pZCB7XG4gIGNvbnN0IHBzYnQgPSB1dHhvbGliLmJpdGdvLmNyZWF0ZVBzYnRGcm9tSGV4KHBzYnRIZXgsIG5ldHdvcmspO1xuICAvLyBNYWtlIHN1cmUgdGhhdCB5b3UgY2FuIHNpZ24gd2l0aCBiaXRnbyBrZXkgYW5kIGV4dHJhY3QgdGhlIHRyYW5zYWN0aW9uXG4gIC8vIE5vIHNpZ25hdHVyZXMgc2hvdWxkIGJlIHByZXNlbnQgaWYgaXQncyBhIHAyc2hQMnBrIGlucHV0XG4gIGlmICghaW5wdXRTY3JpcHRzLmluY2x1ZGVzKCdwMnNoUDJwaycpKSB7XG4gICAgY29uc3Qga2V5ID0gaW5wdXRTY3JpcHRzLmluY2x1ZGVzKCdwMnRyTXVzaWcyJykgPyByb290V2FsbGV0S2V5cy5iYWNrdXAgOiByb290V2FsbGV0S2V5cy5iaXRnbztcbiAgICBwc2J0LnNpZ25BbGxJbnB1dHNIRChrZXksIHsgZGV0ZXJtaW5pc3RpYzogdHJ1ZSB9KTtcbiAgICBwc2J0LnZhbGlkYXRlU2lnbmF0dXJlc09mQWxsSW5wdXRzKCk7XG4gICAgcHNidC5maW5hbGl6ZUFsbElucHV0cygpO1xuICAgIGNvbnN0IHR4ID0gcHNidC5leHRyYWN0VHJhbnNhY3Rpb24oKTtcbiAgICBhc3NlcnQub2sodHgpO1xuICB9XG59XG5cbi8vIEJ1aWxkIHRoZSBrZXkgb2JqZWN0c1xuY29uc3Qgcm9vdFdhbGxldEtleXMgPSBnZXREZWZhdWx0V2FsbGV0S2V5cygpO1xuY29uc3Qga2V5RG9jdW1lbnRPYmplY3RzID0gcm9vdFdhbGxldEtleXMudHJpcGxlLm1hcCgoYmlwMzIsIGtleUlkeCkgPT4ge1xuICByZXR1cm4ge1xuICAgIGlkOiBnZXRTZWVkKGtleWNoYWluc0Jhc2U1OFtrZXlJZHhdLnB1YikudG9TdHJpbmcoJ2hleCcpLFxuICAgIHB1YjogYmlwMzIubmV1dGVyZWQoKS50b0Jhc2U1OCgpLFxuICAgIHNvdXJjZTogWyd1c2VyJywgJ2JhY2t1cCcsICdiaXRnbyddW2tleUlkeF0sXG4gICAgZW5jcnlwdGVkUHJ2OiBlbmNyeXB0S2V5Y2hhaW4od2FsbGV0UGFzc3BocmFzZSwga2V5Y2hhaW5zQmFzZTU4W2tleUlkeF0pLFxuICAgIHdlYmF1dGhuRGV2aWNlczogW1xuICAgICAge1xuICAgICAgICBvdHBEZXZpY2VJZDogJzEyMycsXG4gICAgICAgIGF1dGhlbnRpY2F0b3JJbmZvOiB7XG4gICAgICAgICAgY3JlZElEOiAnY3JlZElEJyxcbiAgICAgICAgICBmbXQ6ICdwYWNrZWQnLFxuICAgICAgICAgIHB1YmxpY0tleTogJ3NvbWUgdmFsdWUnLFxuICAgICAgICB9LFxuICAgICAgICBwcmZTYWx0OiAnNDU2JyxcbiAgICAgICAgZW5jcnlwdGVkUHJ2OiBlbmNyeXB0S2V5Y2hhaW4od2ViYXV0aG5XYWxsZXRQYXNzUGhyYXNlLCBrZXljaGFpbnNCYXNlNThba2V5SWR4XSksXG4gICAgICB9LFxuICAgIF0sXG4gICAgY29pblNwZWNpZmljOiB7fSxcbiAgfTtcbn0pO1xuXG5mdW5jdGlvbiBydW4oY29pbjogQWJzdHJhY3RVdHhvQ29pbiwgaW5wdXRTY3JpcHRzOiBTY3JpcHRUeXBlW10sIHR4Rm9ybWF0OiBUeEZvcm1hdCk6IHZvaWQge1xuICBmdW5jdGlvbiBjcmVhdGVQcmVidWlsZFBzYnQoaW5wdXRzOiBJbnB1dFtdLCBvdXRwdXRzOiB7IHNjcmlwdFR5cGU6ICdwMnNoJzsgdmFsdWU6IGJpZ2ludCB9W10pIHtcbiAgICBjb25zdCBwc2J0ID0gdXR4b2xpYi50ZXN0dXRpbC5jb25zdHJ1Y3RQc2J0KFxuICAgICAgaW5wdXRzIGFzIHV0eG9saWIudGVzdHV0aWwuSW5wdXRbXSxcbiAgICAgIG91dHB1dHMsXG4gICAgICBjb2luLm5ldHdvcmssXG4gICAgICByb290V2FsbGV0S2V5cyxcbiAgICAgICd1bnNpZ25lZCdcbiAgICApO1xuICAgIHV0eG9saWIuYml0Z28uYWRkWHB1YnNUb1BzYnQocHNidCwgcm9vdFdhbGxldEtleXMpO1xuICAgIHJldHVybiBwc2J0O1xuICB9XG5cbiAgZnVuY3Rpb24gY3JlYXRlTm9ja3MocGFyYW1zOiB7XG4gICAgYmdVcmw6IHN0cmluZztcbiAgICB3YWxsZXQ6IFdhbGxldDtcbiAgICBrZXlEb2N1bWVudHM6IEtleURvY1tdO1xuICAgIHByZWJ1aWxkOiB1dHhvbGliLmJpdGdvLlV0eG9Qc2J0O1xuICAgIHJlY2lwaWVudDogeyBhZGRyZXNzOiBzdHJpbmc7IGFtb3VudDogc3RyaW5nIH07XG4gICAgYWRkcmVzc0luZm86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgcmJmVHhJZHM/OiBzdHJpbmdbXTtcbiAgICBmZWVNdWx0aXBsaWVyPzogbnVtYmVyO1xuICAgIHNlbGZTZW5kPzogYm9vbGVhbjtcbiAgICBub2NrT3V0cHV0QWRkcmVzc2VzPzogYm9vbGVhbjtcbiAgICB0eEZvcm1hdD86IHN0cmluZztcbiAgfSk6IG5vY2suU2NvcGVbXSB7XG4gICAgY29uc3Qgbm9ja3M6IG5vY2suU2NvcGVbXSA9IFtdO1xuXG4gICAgLy8gTm9jayB0aGUgcHJlYnVpbGQgcm91dGUgKC90eC9idWlsZCwgYmxvY2toZWlnaHQpXG4gICAgY29uc3QgZXhwZWN0ZWRfcGFyYW1zID0ge1xuICAgICAgcmVjaXBpZW50czogW3BhcmFtcy5yZWNpcGllbnRdLFxuICAgICAgcmJmVHhJZHM6IHBhcmFtcy5yYmZUeElkcyxcbiAgICAgIGZlZU11bHRpcGxpZXI6IHBhcmFtcy5mZWVNdWx0aXBsaWVyLFxuICAgICAgY2hhbmdlQWRkcmVzc1R5cGU6IFsncDJ0ck11c2lnMicsICdwMndzaCcsICdwMnNoUDJ3c2gnLCAncDJzaCcsICdwMnRyJ10sXG4gICAgfTtcbiAgICBpZiAocGFyYW1zLnR4Rm9ybWF0KSB7XG4gICAgICBleHBlY3RlZF9wYXJhbXNbJ3R4Rm9ybWF0J10gPSBwYXJhbXMudHhGb3JtYXQ7XG4gICAgfVxuICAgIG5vY2tzLnB1c2goXG4gICAgICBub2NrKHBhcmFtcy5iZ1VybClcbiAgICAgICAgLnBvc3QoYC9hcGkvdjIvJHtjb2luLmdldENoYWluKCl9L3dhbGxldC8ke3BhcmFtcy53YWxsZXQuaWQoKX0vdHgvYnVpbGRgLCBleHBlY3RlZF9wYXJhbXMpXG4gICAgICAgIC5yZXBseSgyMDAsIHsgdHhIZXg6IHBhcmFtcy5wcmVidWlsZC50b0hleCgpLCB0eEluZm86IHt9IH0pXG4gICAgKTtcbiAgICBub2Nrcy5wdXNoKG5vY2socGFyYW1zLmJnVXJsKS5nZXQoYC9hcGkvdjIvJHtjb2luLmdldENoYWluKCl9L3B1YmxpYy9ibG9jay9sYXRlc3RgKS5yZXBseSgyMDAsIHsgaGVpZ2h0OiAxMDAwIH0pKTtcblxuICAgIC8vIG5vY2sgdGhlIGtleWNoYWluIGZldGNoIC0gMyB0aW1lcyAocHJlYnVpbGRBbmRTaWduLCB2ZXJpZnlUcmFuc2FjdGlvbiwgYW5kIHNpZ25UcmFuc2FjdGlvbilcbiAgICBwYXJhbXMua2V5RG9jdW1lbnRzLmZvckVhY2goKGtleURvY3VtZW50KSA9PiB7XG4gICAgICBub2Nrcy5wdXNoKFxuICAgICAgICBub2NrKHBhcmFtcy5iZ1VybCkuZ2V0KGAvYXBpL3YyLyR7Y29pbi5nZXRDaGFpbigpfS9rZXkvJHtrZXlEb2N1bWVudC5pZH1gKS50aW1lcygzKS5yZXBseSgyMDAsIGtleURvY3VtZW50KVxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIC8vIG5vY2sgdGhlIGFkZHJlc3MgaW5mbyBmZXRjaFxuICAgIGlmIChwYXJhbXMubm9ja091dHB1dEFkZHJlc3Nlcykge1xuICAgICAgbm9ja3MucHVzaChcbiAgICAgICAgbm9jayhwYXJhbXMuYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92Mi8ke2NvaW4uZ2V0Q2hhaW4oKX0vd2FsbGV0LyR7cGFyYW1zLndhbGxldC5pZCgpfS9hZGRyZXNzLyR7cGFyYW1zLmFkZHJlc3NJbmZvLmFkZHJlc3N9YClcbiAgICAgICAgICAucmVwbHkoMjAwLCBwYXJhbXMuYWRkcmVzc0luZm8pXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMucmJmVHhJZHMpIHtcbiAgICAgIG5vY2tzLnB1c2goXG4gICAgICAgIG5vY2socGFyYW1zLmJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjIvJHtjb2luLmdldENoYWluKCl9L3dhbGxldC8ke3BhcmFtcy53YWxsZXQuaWQoKX0vdHgvJHtwYXJhbXMucmJmVHhJZHNbMF19P2luY2x1ZGVSYmY9dHJ1ZWApXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYWRkcmVzczogcGFyYW1zLnJlY2lwaWVudC5hZGRyZXNzLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBOdW1iZXIocGFyYW1zLnJlY2lwaWVudC5hbW91bnQpLFxuICAgICAgICAgICAgICAgIHZhbHVlU3RyaW5nOiBwYXJhbXMucmVjaXBpZW50LmFtb3VudCxcbiAgICAgICAgICAgICAgICB3YWxsZXQ6IHBhcmFtcy5zZWxmU2VuZCA/IHBhcmFtcy53YWxsZXQuaWQoKSA6ICdzb21lLW90aGVyLXdhbGxldC1pZCcsIC8vIGV4dGVybmFsIG91dHB1dCBpZiBub3QgYSBzZWxmIHNlbmRcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgLy8gRHVtbXkgY2hhbmdlIG91dHB1dCB0byB0ZXN0IHRyYW5zZmVyIGVudHJpZXMgZmlsdGVyaW5nXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhZGRyZXNzOiBwYXJhbXMucmVjaXBpZW50LmFkZHJlc3MsXG4gICAgICAgICAgICAgICAgdmFsdWU6IE51bWJlcihwYXJhbXMucmVjaXBpZW50LmFtb3VudCksXG4gICAgICAgICAgICAgICAgdmFsdWVTdHJpbmc6IHBhcmFtcy5yZWNpcGllbnQuYW1vdW50LFxuICAgICAgICAgICAgICAgIHdhbGxldDogcGFyYW1zLndhbGxldC5pZCgpLCAvLyBpbnRlcm5hbCBvdXRwdXRcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gbm9jayB0aGUgZGV0ZXJtaW5pc3RpYyBub25jZSByZXNwb25zZVxuICAgIGlmIChpbnB1dFNjcmlwdHMuaW5jbHVkZXMoJ3RhcHJvb3RLZXlQYXRoU3BlbmQnKSkge1xuICAgICAgY29uc3QgcHNidCA9IHBhcmFtcy5wcmVidWlsZC5jbG9uZSgpO1xuICAgICAgcHNidC5zZXRBbGxJbnB1dHNNdXNpZzJOb25jZUhEKHJvb3RXYWxsZXRLZXlzLnVzZXIpO1xuICAgICAgcHNidC5zZXRBbGxJbnB1dHNNdXNpZzJOb25jZUhEKHJvb3RXYWxsZXRLZXlzLmJpdGdvKTtcbiAgICAgIG5vY2tzLnB1c2goXG4gICAgICAgIG5vY2socGFyYW1zLmJnVXJsKVxuICAgICAgICAgIC5wb3N0KGAvYXBpL3YyLyR7Y29pbi5nZXRDaGFpbigpfS93YWxsZXQvJHtwYXJhbXMud2FsbGV0LmlkKCl9L3R4L3NpZ25wc2J0YCwgKGJvZHkpID0+IGJvZHkucHNidClcbiAgICAgICAgICAucmVwbHkoMjAwLCB7IHBzYnQ6IHBzYnQudG9IZXgoKSB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbm9ja3M7XG4gIH1cblxuICBkZXNjcmliZShgJHtjb2luLmdldEZ1bGxOYW1lKCl9LXByZWJ1aWxkQW5kU2lnbi10eEZvcm1hdD0ke3R4Rm9ybWF0fS1pbnB1dFNjcmlwdHM9JHtpbnB1dFNjcmlwdHMuam9pbihcbiAgICAnLCdcbiAgKX1gLCBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3Qgd2FsbGV0ID0gZ2V0VXR4b1dhbGxldChjb2luLCB7XG4gICAgICBjb2luU3BlY2lmaWM6IHsgYWRkcmVzc1ZlcnNpb246ICdiYXNlNTgnIH0sXG4gICAgICBrZXlzOiBrZXlEb2N1bWVudE9iamVjdHMubWFwKChrKSA9PiBrLmlkKSxcbiAgICAgIGlkOiAnd2FsbGV0SWQnLFxuICAgIH0pO1xuXG4gICAgY29uc3QgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R28sIHsgZW52OiAnbW9jaycgfSk7XG4gICAgY29uc3QgYmdVcmwgPSBjb21tb24uRW52aXJvbm1lbnRzW2JpdGdvLmdldEVudigpXS51cmk7XG4gICAgbGV0IHByZWJ1aWxkOiB1dHhvbGliLmJpdGdvLlV0eG9Qc2J0O1xuICAgIGxldCByZWNpcGllbnQ6IHsgYWRkcmVzczogc3RyaW5nOyBhbW91bnQ6IHN0cmluZyB9O1xuICAgIGxldCBhZGRyZXNzSW5mbzogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICBjb25zdCBmZWUgPSBCaWdJbnQoMTAwMDApO1xuXG4gICAgYmVmb3JlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIE1ha2Ugb3V0cHV0IGFkZHJlc3MgaW5mb3JtYXRpb25cbiAgICAgIGNvbnN0IG91dHB1dEFtb3VudCA9IEJpZ0ludChpbnB1dFNjcmlwdHMubGVuZ3RoKSAqIEJpZ0ludCgxZTgpIC0gZmVlO1xuICAgICAgY29uc3Qgb3V0cHV0U2NyaXB0VHlwZTogdXR4b2xpYi5iaXRnby5vdXRwdXRTY3JpcHRzLlNjcmlwdFR5cGUgPSAncDJzaCc7XG4gICAgICBjb25zdCBvdXRwdXRDaGFpbiA9IHV0eG9saWIuYml0Z28uZ2V0RXh0ZXJuYWxDaGFpbkNvZGUob3V0cHV0U2NyaXB0VHlwZSk7XG4gICAgICBjb25zdCBvdXRwdXRBZGRyZXNzID0gdXR4b2xpYi5iaXRnby5nZXRXYWxsZXRBZGRyZXNzKHJvb3RXYWxsZXRLZXlzLCBvdXRwdXRDaGFpbiwgMCwgY29pbi5uZXR3b3JrKTtcblxuICAgICAgcmVjaXBpZW50ID0ge1xuICAgICAgICBhZGRyZXNzOiBvdXRwdXRBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6IG91dHB1dEFtb3VudC50b1N0cmluZygpLFxuICAgICAgfTtcbiAgICAgIGFkZHJlc3NJbmZvID0ge1xuICAgICAgICBhZGRyZXNzOiBvdXRwdXRBZGRyZXNzLFxuICAgICAgICBjaGFpbjogb3V0cHV0Q2hhaW4sXG4gICAgICAgIGluZGV4OiAwLFxuICAgICAgICBjb2luOiBjb2luLmdldENoYWluKCksXG4gICAgICAgIHdhbGxldDogd2FsbGV0LmlkKCksXG4gICAgICAgIGNvaW5TcGVjaWZpYzoge30sXG4gICAgICB9O1xuXG4gICAgICBwcmVidWlsZCA9IGNyZWF0ZVByZWJ1aWxkUHNidChcbiAgICAgICAgaW5wdXRTY3JpcHRzLm1hcCgocykgPT4gKHsgc2NyaXB0VHlwZTogcywgdmFsdWU6IEJpZ0ludCgxZTgpIH0pKSxcbiAgICAgICAgW3sgc2NyaXB0VHlwZTogb3V0cHV0U2NyaXB0VHlwZSwgdmFsdWU6IG91dHB1dEFtb3VudCB9XVxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGFmdGVyRWFjaChub2NrLmNsZWFuQWxsKTtcblxuICAgIFt0cnVlLCBmYWxzZV0uZm9yRWFjaCgodXNlV2ViYXV0aG4pID0+IHtcbiAgICAgIGl0KGBzaG91bGQgc3VjY2VlZCB3aXRoICR7dXNlV2ViYXV0aG4gPyAnd2ViYXV0aG4gZW5jcnlwdGVkUHJ2JyA6ICdlbmNyeXB0ZWRQcnYnfWAsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgdHhDb2lucyA9IFsndHplYycsICd6ZWMnLCAnbHRjJywgJ2JjaGEnLCAnZG9nZScsICdkYXNoJywgJ2J0ZycsICdiY2gnXTtcbiAgICAgICAgY29uc3Qgbm9ja3MgPSBjcmVhdGVOb2Nrcyh7XG4gICAgICAgICAgYmdVcmwsXG4gICAgICAgICAgd2FsbGV0LFxuICAgICAgICAgIGtleURvY3VtZW50czoga2V5RG9jdW1lbnRPYmplY3RzLFxuICAgICAgICAgIHByZWJ1aWxkLFxuICAgICAgICAgIHJlY2lwaWVudCxcbiAgICAgICAgICBhZGRyZXNzSW5mbyxcbiAgICAgICAgICBub2NrT3V0cHV0QWRkcmVzc2VzOiB0eEZvcm1hdCAhPT0gJ3BzYnQnLFxuICAgICAgICAgIHR4Rm9ybWF0OiAhdHhDb2lucy5pbmNsdWRlcyhjb2luLmdldENoYWluKCkpID8gJ3BzYnQnIDogdW5kZWZpbmVkLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBjYWxsIHByZWJ1aWxkIGFuZCBzaWduLCBub2NrcyBzaG91bGQgYmUgY29uc3VtZWRcbiAgICAgICAgY29uc3QgcmVzID0gKGF3YWl0IHdhbGxldC5wcmVidWlsZEFuZFNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgICAgcmVjaXBpZW50czogW3JlY2lwaWVudF0sXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogdXNlV2ViYXV0aG4gPyB3ZWJhdXRobldhbGxldFBhc3NQaHJhc2UgOiB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICB9KSkgYXMgSGFsZlNpZ25lZFV0eG9UcmFuc2FjdGlvbjtcblxuICAgICAgICBub2Nrcy5mb3JFYWNoKChub2NrKSA9PiBhc3NlcnQub2sobm9jay5pc0RvbmUoKSkpO1xuXG4gICAgICAgIGFzc2VydFNpZ25hYmxlKHJlcy50eEhleCwgaW5wdXRTY3JpcHRzLCBjb2luLm5ldHdvcmspO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgZmFpbCBpZiB0aGUgd2FsbGV0IHBhc3NwaHJhc2UgaXMgaW5jb3JyZWN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjcmVhdGVOb2Nrcyh7XG4gICAgICAgICAgYmdVcmwsXG4gICAgICAgICAgd2FsbGV0LFxuICAgICAgICAgIGtleURvY3VtZW50czoga2V5RG9jdW1lbnRPYmplY3RzLFxuICAgICAgICAgIHByZWJ1aWxkLFxuICAgICAgICAgIHJlY2lwaWVudCxcbiAgICAgICAgICBhZGRyZXNzSW5mbyxcbiAgICAgICAgICBub2NrT3V0cHV0QWRkcmVzc2VzOiB0eEZvcm1hdCAhPT0gJ3BzYnQnLFxuICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCB3YWxsZXRcbiAgICAgICAgICAucHJlYnVpbGRBbmRTaWduVHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgcmVjaXBpZW50czogW3JlY2lwaWVudF0sXG4gICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKCksXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgndW5hYmxlIHRvIGRlY3J5cHQga2V5Y2hhaW4gd2l0aCB0aGUgZ2l2ZW4gd2FsbGV0IHBhc3NwaHJhc2UnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgW3RydWUsIGZhbHNlXS5mb3JFYWNoKChzZWxmU2VuZCkgPT4ge1xuICAgICAgaXQoYHNob3VsZCBiZSBhYmxlIHRvIGJ1aWxkLCBzaWduLCAmIHZlcmlmeSBhIHJlcGxhY2VtZW50IHRyYW5zYWN0aW9uIHdpdGggc2VsZlNlbmQ6ICR7c2VsZlNlbmR9YCwgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCByYmZUeElkcyA9IFsndHgtdG8tYmUtcmVwbGFjZWQnXSxcbiAgICAgICAgICBmZWVNdWx0aXBsaWVyID0gMS41O1xuICAgICAgICBjb25zdCB0eENvaW5zID0gWyd0emVjJywgJ3plYycsICdsdGMnLCAnYmNoYScsICdkb2dlJywgJ2Rhc2gnLCAnYnRnJywgJ2JjaCddO1xuICAgICAgICBjb25zdCBub2NrcyA9IGNyZWF0ZU5vY2tzKHtcbiAgICAgICAgICBiZ1VybCxcbiAgICAgICAgICB3YWxsZXQsXG4gICAgICAgICAga2V5RG9jdW1lbnRzOiBrZXlEb2N1bWVudE9iamVjdHMsXG4gICAgICAgICAgcHJlYnVpbGQsXG4gICAgICAgICAgcmVjaXBpZW50LFxuICAgICAgICAgIGFkZHJlc3NJbmZvLFxuICAgICAgICAgIHJiZlR4SWRzLFxuICAgICAgICAgIGZlZU11bHRpcGxpZXIsXG4gICAgICAgICAgc2VsZlNlbmQsXG4gICAgICAgICAgbm9ja091dHB1dEFkZHJlc3NlczogdHhGb3JtYXQgIT09ICdwc2J0JyxcbiAgICAgICAgICB0eEZvcm1hdDogIXR4Q29pbnMuaW5jbHVkZXMoY29pbi5nZXRDaGFpbigpKSA/ICdwc2J0JyA6IHVuZGVmaW5lZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gY2FsbCBwcmVidWlsZCBhbmQgc2lnbiwgbm9ja3Mgc2hvdWxkIGJlIGNvbnN1bWVkXG4gICAgICAgIGNvbnN0IHJlcyA9IChhd2FpdCB3YWxsZXQucHJlYnVpbGRBbmRTaWduVHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHJlY2lwaWVudHM6IFtyZWNpcGllbnRdLFxuICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2UsXG4gICAgICAgICAgcmJmVHhJZHMsXG4gICAgICAgICAgZmVlTXVsdGlwbGllcixcbiAgICAgICAgfSkpIGFzIEhhbGZTaWduZWRVdHhvVHJhbnNhY3Rpb247XG5cbiAgICAgICAgbm9ja3MuZm9yRWFjaCgobm9jaykgPT4gYXNzZXJ0Lm9rKG5vY2suaXNEb25lKCkpKTtcblxuICAgICAgICBhc3NlcnRTaWduYWJsZShyZXMudHhIZXgsIGlucHV0U2NyaXB0cywgY29pbi5uZXR3b3JrKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbn1cblxudXR4b0NvaW5zXG4gIC5maWx0ZXIoKGNvaW4pID0+IHV0eG9saWIuZ2V0TWFpbm5ldChjb2luLm5ldHdvcmspICE9PSB1dHhvbGliLm5ldHdvcmtzLmJpdGNvaW5zdilcbiAgLmZvckVhY2goKGNvaW4pID0+IHtcbiAgICBzY3JpcHRUeXBlc1xuICAgICAgLy8gRG9uJ3QgaXRlcmF0ZSBvdmVyIHAyc2hQMnBrIC0gaW4gbm8gc2NlbmFyaW8gd291bGQgYSB3YWxsZXQgc3BlbmQgdHdvIHAyc2hQMnBrIGlucHV0cyBhcyB0aGVzZVxuICAgICAgLy8gYXJlIHNpbmdsZSBzaWduYXR1cmUgaW5wdXRzIHRoYXQgYXJlIHVzZWQgZm9yIHJlcGxheSBwcm90ZWN0aW9uIGFuZCBhcmUgYWRkZWQgdG8gdGhlIHRyYW5zYWN0aW9uXG4gICAgICAvLyBieSBvdXIgc3lzdGVtIGZyb20gYSBzZXBhcmF0ZSB3YWxsZXQuIFdlIGRvIHJ1biB0ZXN0cyBiZWxvdyB3aGVyZSBvbmUgb2YgdGhlIGlucHV0cyBpcyBhIHAyc2hQMnBrIGFuZFxuICAgICAgLy8gdGhlIG90aGVyIGlzIGFuIGlucHV0IHNwZW50IGJ5IHRoZSB1c2VyLlxuICAgICAgLmZpbHRlcigoc2NyaXB0VHlwZSkgPT4gc2NyaXB0VHlwZSAhPT0gJ3Ayc2hQMnBrJylcbiAgICAgIC5mb3JFYWNoKChpbnB1dFNjcmlwdCkgPT4ge1xuICAgICAgICBjb25zdCBpbnB1dFNjcmlwdENsZWFuZWQgPSAoXG4gICAgICAgICAgaW5wdXRTY3JpcHQgPT09ICd0YXByb290S2V5UGF0aFNwZW5kJyA/ICdwMnRyTXVzaWcyJyA6IGlucHV0U2NyaXB0XG4gICAgICAgICkgYXMgdXR4b2xpYi5iaXRnby5vdXRwdXRTY3JpcHRzLlNjcmlwdFR5cGUyT2YzO1xuXG4gICAgICAgIGlmICghY29pbi5zdXBwb3J0c0FkZHJlc3NUeXBlKGlucHV0U2NyaXB0Q2xlYW5lZCkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBydW4oY29pbiwgW2lucHV0U2NyaXB0LCBpbnB1dFNjcmlwdF0sICdwc2J0Jyk7XG4gICAgICAgIGlmIChnZXRSZXBsYXlQcm90ZWN0aW9uQWRkcmVzc2VzKGNvaW4ubmV0d29yaykubGVuZ3RoKSB7XG4gICAgICAgICAgcnVuKGNvaW4sIFsncDJzaFAycGsnLCBpbnB1dFNjcmlwdF0sICdwc2J0Jyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9KTtcbiJdfQ==

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


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