PHP WebShell

Текущая директория: /opt/BitGoJS/modules/sdk-coin-ton/dist/src

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

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Ton = void 0;
const sdk_core_1 = require("@bitgo/sdk-core");
const statics_1 = require("@bitgo/statics");
const keyPair_1 = require("./lib/keyPair");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const _ = __importStar(require("lodash"));
const lib_1 = require("./lib");
const tonweb_1 = __importDefault(require("tonweb"));
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const utils_1 = require("./lib/utils");
class Ton extends sdk_core_1.BaseCoin {
    constructor(bitgo, staticsCoin) {
        super(bitgo);
        if (!staticsCoin) {
            throw new Error('missing required constructor parameter staticsCoin');
        }
        this._staticsCoin = staticsCoin;
    }
    static createInstance(bitgo, staticsCoin) {
        return new Ton(bitgo, staticsCoin);
    }
    /**
     * Factor between the coin's base unit and its smallest subdivison
     */
    getBaseFactor() {
        return 1e9;
    }
    getChain() {
        return 'ton';
    }
    getFamily() {
        return 'ton';
    }
    getFullName() {
        return 'Ton';
    }
    /** @inheritDoc */
    supportsTss() {
        return true;
    }
    /** inherited doc */
    getDefaultMultisigType() {
        return sdk_core_1.multisigTypes.tss;
    }
    getMPCAlgorithm() {
        return 'eddsa';
    }
    allowsAccountConsolidations() {
        return true;
    }
    async verifyTransaction(params) {
        const coinConfig = statics_1.coins.get(this.getChain());
        const { txPrebuild: txPrebuild, txParams: txParams } = params;
        const transaction = new lib_1.Transaction(coinConfig);
        const rawTx = txPrebuild.txHex;
        if (!rawTx) {
            throw new Error('missing required tx prebuild property txHex');
        }
        transaction.fromRawTransaction(Buffer.from(rawTx, 'hex').toString('base64'));
        const explainedTx = transaction.explainTransaction();
        if (txParams.recipients !== undefined) {
            const filteredRecipients = txParams.recipients?.map((recipient) => {
                return {
                    address: new tonweb_1.default.Address(recipient.address).toString(true, true, true),
                    amount: BigInt(recipient.amount),
                };
            });
            const filteredOutputs = explainedTx.outputs.map((output) => {
                return {
                    address: new tonweb_1.default.Address(output.address).toString(true, true, true),
                    amount: BigInt(output.amount),
                };
            });
            if (!_.isEqual(filteredOutputs, filteredRecipients)) {
                throw new Error('Tx outputs does not match with expected txParams recipients');
            }
            let totalAmount = new bignumber_js_1.default(0);
            for (const recipients of txParams.recipients) {
                totalAmount = totalAmount.plus(recipients.amount);
            }
            if (!totalAmount.isEqualTo(explainedTx.outputAmount)) {
                throw new Error('Tx total amount does not match with expected total amount field');
            }
        }
        return true;
    }
    async isWalletAddress(params) {
        const { keychains, address: newAddress, index } = params;
        if (!this.isValidAddress(newAddress)) {
            throw new sdk_core_1.InvalidAddressError(`invalid address: ${newAddress}`);
        }
        if (!keychains) {
            throw new Error('missing required param keychains');
        }
        for (const keychain of keychains) {
            const [address, memoId] = newAddress.split('?memoId=');
            const MPC = await sdk_core_1.EDDSAMethods.getInitializedMpcInstance();
            const commonKeychain = keychain.commonKeychain;
            const derivationPath = 'm/' + index;
            const derivedPublicKey = MPC.deriveUnhardened(commonKeychain, derivationPath).slice(0, 64);
            const expectedAddress = await lib_1.Utils.default.getAddressFromPublicKey(derivedPublicKey);
            if (memoId) {
                return memoId === `${index}`;
            }
            if (address !== expectedAddress) {
                return false;
            }
        }
        return true;
    }
    async parseTransaction(params) {
        const factory = new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getChain()));
        const transactionBuilder = factory.from(Buffer.from(params.txHex, 'hex').toString('base64'));
        if (typeof params.toAddressBounceable === 'boolean') {
            transactionBuilder.toAddressBounceable(params.toAddressBounceable);
        }
        if (typeof params.fromAddressBounceable === 'boolean') {
            transactionBuilder.fromAddressBounceable(params.fromAddressBounceable);
        }
        const rebuiltTransaction = await transactionBuilder.build();
        const parsedTransaction = rebuiltTransaction.toJson();
        return {
            inputs: [
                {
                    address: parsedTransaction.sender,
                    amount: parsedTransaction.amount,
                },
            ],
            outputs: [
                {
                    address: parsedTransaction.destination,
                    amount: parsedTransaction.amount,
                },
            ],
        };
    }
    generateKeyPair(seed) {
        const keyPair = seed ? new keyPair_1.KeyPair({ seed }) : new keyPair_1.KeyPair();
        const keys = keyPair.getKeys();
        if (!keys.prv) {
            throw new Error('Missing prv in key generation.');
        }
        return {
            pub: keys.pub,
            prv: keys.prv,
        };
    }
    isValidPub(pub) {
        throw new Error('Method not implemented.');
    }
    isValidAddress(address) {
        try {
            const addressBase64 = address.replace(/\+/g, '-').replace(/\//g, '_');
            const buf = Buffer.from(addressBase64.split('?memoId=')[0], 'base64');
            return buf.length === 36;
        }
        catch {
            return false;
        }
    }
    signTransaction(params) {
        throw new Error('Method not implemented.');
    }
    /** @inheritDoc */
    async getSignablePayload(serializedTx) {
        const factory = new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getChain()));
        const rebuiltTransaction = await factory.from(serializedTx).build();
        return rebuiltTransaction.signablePayload;
    }
    /** @inheritDoc */
    async explainTransaction(params) {
        try {
            const factory = new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getChain()));
            const transactionBuilder = factory.from(Buffer.from(params.txHex, 'hex').toString('base64'));
            const { toAddressBounceable, fromAddressBounceable } = params;
            if (typeof toAddressBounceable === 'boolean') {
                transactionBuilder.toAddressBounceable(toAddressBounceable);
            }
            if (typeof fromAddressBounceable === 'boolean') {
                transactionBuilder.fromAddressBounceable(fromAddressBounceable);
            }
            const rebuiltTransaction = await transactionBuilder.build();
            return rebuiltTransaction.explainTransaction();
        }
        catch {
            throw new Error('Invalid transaction');
        }
    }
    getPublicNodeUrl() {
        return sdk_core_1.Environments[this.bitgo.getEnv()].tonNodeUrl;
    }
    getBuilder() {
        return new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getChain()));
    }
    async recover(params) {
        if (!params.bitgoKey) {
            throw new Error('missing bitgoKey');
        }
        if (!params.recoveryDestination || !this.isValidAddress(params.recoveryDestination)) {
            throw new Error('invalid recoveryDestination');
        }
        if (!params.apiKey) {
            throw new Error('missing apiKey');
        }
        const bitgoKey = params.bitgoKey.replace(/\s/g, '');
        const isUnsignedSweep = !params.userKey && !params.backupKey && !params.walletPassphrase;
        // Build the transaction
        const tonweb = new tonweb_1.default(new tonweb_1.default.HttpProvider(this.getPublicNodeUrl(), { apiKey: params.apiKey }));
        const MPC = await sdk_core_1.EDDSAMethods.getInitializedMpcInstance();
        const index = params.index || 0;
        const currPath = params.seed ? (0, sdk_lib_mpc_1.getDerivationPath)(params.seed) + `/${index}` : `m/${index}`;
        const accountId = MPC.deriveUnhardened(bitgoKey, currPath).slice(0, 64);
        const senderAddr = await lib_1.Utils.default.getAddressFromPublicKey(accountId);
        const balance = await tonweb.getBalance(senderAddr);
        if (new bignumber_js_1.default(balance).isEqualTo(0)) {
            throw Error('Did not find address with funds to recover');
        }
        const WalletClass = tonweb.wallet.all['v4R2'];
        const wallet = new WalletClass(tonweb.provider, {
            publicKey: tonweb.utils.hexToBytes(accountId),
            wc: 0,
        });
        let seqno = await wallet.methods.seqno().call();
        if (seqno === null) {
            seqno = 0;
        }
        const feeEstimate = await (0, utils_1.getFeeEstimate)(wallet, params.recoveryDestination, balance, seqno);
        const totalFeeEstimate = Math.round((feeEstimate.source_fees.in_fwd_fee +
            feeEstimate.source_fees.storage_fee +
            feeEstimate.source_fees.gas_fee +
            feeEstimate.source_fees.fwd_fee) *
            1.5);
        if (new bignumber_js_1.default(totalFeeEstimate).gt(balance)) {
            throw Error('Did not find address with funds to recover');
        }
        const factory = this.getBuilder();
        const expireAt = Math.floor(Date.now() / 1e3) + 60 * 60 * 24 * 7; // 7 days
        const txBuilder = factory
            .getTransferBuilder()
            .sender(senderAddr)
            .sequenceNumber(seqno)
            .publicKey(accountId)
            .expireTime(expireAt);
        txBuilder.send({
            address: params.recoveryDestination,
            amount: new bignumber_js_1.default(balance).minus(new bignumber_js_1.default(totalFeeEstimate)).toString(),
        });
        const unsignedTransaction = await txBuilder.build();
        if (!isUnsignedSweep) {
            if (!params.userKey) {
                throw new Error('missing userKey');
            }
            if (!params.backupKey) {
                throw new Error('missing backupKey');
            }
            if (!params.walletPassphrase) {
                throw new Error('missing wallet passphrase');
            }
            // Clean up whitespace from entered values
            const userKey = params.userKey.replace(/\s/g, '');
            const backupKey = params.backupKey.replace(/\s/g, '');
            let userPrv;
            try {
                userPrv = this.bitgo.decrypt({
                    input: userKey,
                    password: params.walletPassphrase,
                });
            }
            catch (e) {
                throw new Error(`Error decrypting user keychain: ${e.message}`);
            }
            const userSigningMaterial = JSON.parse(userPrv);
            let backupPrv;
            try {
                backupPrv = this.bitgo.decrypt({
                    input: backupKey,
                    password: params.walletPassphrase,
                });
            }
            catch (e) {
                throw new Error(`Error decrypting backup keychain: ${e.message}`);
            }
            const backupSigningMaterial = JSON.parse(backupPrv);
            const signatureHex = await sdk_core_1.EDDSAMethods.getTSSSignature(userSigningMaterial, backupSigningMaterial, currPath, unsignedTransaction);
            const publicKeyObj = { pub: senderAddr };
            txBuilder.addSignature(publicKeyObj, signatureHex);
        }
        const completedTransaction = await txBuilder.build();
        const serializedTx = completedTransaction.toBroadcastFormat();
        const walletCoin = this.getChain();
        const inputs = [];
        for (const input of completedTransaction.inputs) {
            inputs.push({
                address: input.address,
                valueString: input.value,
                value: new bignumber_js_1.default(input.value).toNumber(),
            });
        }
        const outputs = [];
        for (const output of completedTransaction.outputs) {
            outputs.push({
                address: output.address,
                valueString: output.value,
                coinName: output.coin,
            });
        }
        const spendAmount = completedTransaction.inputs.length === 1 ? completedTransaction.inputs[0].value : 0;
        const parsedTx = { inputs: inputs, outputs: outputs, spendAmount: spendAmount, type: '' };
        const feeInfo = { fee: totalFeeEstimate, feeString: totalFeeEstimate.toString() };
        const coinSpecific = { commonKeychain: bitgoKey };
        if (isUnsignedSweep) {
            const transaction = {
                serializedTx: serializedTx,
                scanIndex: index,
                coin: walletCoin,
                signableHex: completedTransaction.signablePayload.toString('hex'),
                derivationPath: currPath,
                parsedTx: parsedTx,
                feeInfo: feeInfo,
                coinSpecific: coinSpecific,
            };
            const unsignedTx = { unsignedTx: transaction, signatureShares: [] };
            const transactions = [unsignedTx];
            const txRequest = {
                transactions: transactions,
                walletCoin: walletCoin,
            };
            const txRequests = { txRequests: [txRequest] };
            return txRequests;
        }
        const transaction = {
            serializedTx: serializedTx,
            scanIndex: index,
        };
        return transaction;
    }
    /**
     * Creates funds sweep recovery transaction(s) without BitGo
     *
     * @param {MPCSweepRecoveryOptions} params parameters needed to combine the signatures
     * and transactions to create broadcastable transactions
     *
     * @returns {MPCTxs} array of the serialized transaction hex strings and indices
     * of the addresses being swept
     */
    async createBroadcastableSweepTransaction(params) {
        const req = params.signatureShares;
        const broadcastableTransactions = [];
        let lastScanIndex = 0;
        for (let i = 0; i < req.length; i++) {
            const MPC = await sdk_core_1.EDDSAMethods.getInitializedMpcInstance();
            const transaction = req[i].txRequest.transactions[0].unsignedTx;
            if (!req[i].ovc || !req[i].ovc[0].eddsaSignature) {
                throw new Error('Missing signature(s)');
            }
            const signature = req[i].ovc[0].eddsaSignature;
            if (!transaction.signableHex) {
                throw new Error('Missing signable hex');
            }
            const messageBuffer = Buffer.from(transaction.signableHex, 'hex');
            const result = MPC.verify(messageBuffer, signature);
            if (!result) {
                throw new Error('Invalid signature');
            }
            const signatureHex = Buffer.concat([Buffer.from(signature.R, 'hex'), Buffer.from(signature.sigma, 'hex')]);
            const txBuilder = this.getBuilder().from(transaction.serializedTx);
            if (!transaction.coinSpecific?.commonKeychain) {
                throw new Error('Missing common keychain');
            }
            const commonKeychain = transaction.coinSpecific.commonKeychain;
            if (!transaction.derivationPath) {
                throw new Error('Missing derivation path');
            }
            const derivationPath = transaction.derivationPath;
            const accountId = MPC.deriveUnhardened(commonKeychain, derivationPath).slice(0, 64);
            const tonKeyPair = new keyPair_1.KeyPair({ pub: accountId });
            // add combined signature from ovc
            txBuilder.addSignature({ pub: tonKeyPair.getKeys().pub }, signatureHex);
            const signedTransaction = await txBuilder.build();
            const serializedTx = signedTransaction.toBroadcastFormat();
            broadcastableTransactions.push({
                serializedTx: serializedTx,
                scanIndex: transaction.scanIndex,
            });
            if (i === req.length - 1 && transaction.coinSpecific.lastScanIndex) {
                lastScanIndex = transaction.coinSpecific.lastScanIndex;
            }
        }
        return { transactions: broadcastableTransactions, lastScanIndex };
    }
}
exports.Ton = Ton;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSw4Q0E0QnlCO0FBQ3pCLDRDQUFvRTtBQUNwRSwyQ0FBc0Q7QUFDdEQsZ0VBQXFDO0FBQ3JDLDBDQUE0QjtBQUM1QiwrQkFBdUY7QUFDdkYsb0RBQTRCO0FBQzVCLG9EQUF1RDtBQUN2RCx1Q0FBNkM7QUFRN0MsTUFBYSxHQUFJLFNBQVEsbUJBQVE7SUFFL0IsWUFBc0IsS0FBZ0IsRUFBRSxXQUF1QztRQUM3RSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFYixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyxvREFBb0QsQ0FBQyxDQUFDO1FBQ3hFLENBQUM7UUFFRCxJQUFJLENBQUMsWUFBWSxHQUFHLFdBQVcsQ0FBQztJQUNsQyxDQUFDO0lBRUQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFnQixFQUFFLFdBQXVDO1FBQzdFLE9BQU8sSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRDs7T0FFRztJQUNJLGFBQWE7UUFDbEIsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRU0sUUFBUTtRQUNiLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVNLFNBQVM7UUFDZCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFTSxXQUFXO1FBQ2hCLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELGtCQUFrQjtJQUNsQixXQUFXO1FBQ1QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsb0JBQW9CO0lBQ3BCLHNCQUFzQjtRQUNwQixPQUFPLHdCQUFhLENBQUMsR0FBRyxDQUFDO0lBQzNCLENBQUM7SUFFRCxlQUFlO1FBQ2IsT0FBTyxPQUFPLENBQUM7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QUFDLGdCQUFnQixDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3BGLE1BQU0sVUFBVSxHQUFHLElBQUksaUJBQVUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1lBRXRELGtDQUFrQztZQUNsQyxTQUFTLENBQUMsWUFBWSxDQUFDLEVBQUUsR0FBRyxFQUFFLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxZQUFZLENBQUMsQ0FBQztZQUN4RSxNQUFNLGlCQUFpQixHQUFHLE1BQU0sU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2xELE1BQU0sWUFBWSxHQUFHLGlCQUFpQixDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFFM0QseUJBQXlCLENBQUMsSUFBSSxDQUFDO2dCQUM3QixZQUFZLEVBQUUsWUFBWTtnQkFDMUIsU0FBUyxFQUFFLFdBQVcsQ0FBQyxTQUFTO2FBQ2pDLENBQUMsQ0FBQztZQUVILElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFdBQVcsQ0FBQyxZQUFhLENBQUMsYUFBYSxFQUFFLENBQUM7Z0JBQ3BFLGFBQWEsR0FBRyxXQUFXLENBQUMsWUFBYSxDQUFDLGFBQXVCLENBQUM7WUFDcEUsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLEVBQUUsWUFBWSxFQUFFLHlCQUF5QixFQUFFLGFBQWEsRUFBRSxDQUFDO0lBQ3BFLENBQUM7Q0FDRjtBQWhjRCxrQkFnY0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBCYXNlQ29pbixcbiAgQml0R29CYXNlLFxuICBFRERTQU1ldGhvZHMsXG4gIEludmFsaWRBZGRyZXNzRXJyb3IsXG4gIEtleVBhaXIsXG4gIE1QQ0FsZ29yaXRobSxcbiAgTXVsdGlzaWdUeXBlLFxuICBtdWx0aXNpZ1R5cGVzLFxuICBQYXJzZWRUcmFuc2FjdGlvbixcbiAgUGFyc2VUcmFuc2FjdGlvbk9wdGlvbnMsXG4gIFNpZ25lZFRyYW5zYWN0aW9uLFxuICBTaWduVHJhbnNhY3Rpb25PcHRpb25zLFxuICBUcmFuc2FjdGlvbkV4cGxhbmF0aW9uLFxuICBUc3NWZXJpZnlBZGRyZXNzT3B0aW9ucyxcbiAgVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zLFxuICBFRERTQU1ldGhvZFR5cGVzLFxuICBNUENSZWNvdmVyeU9wdGlvbnMsXG4gIE1QQ1R4LFxuICBNUENVbnNpZ25lZFR4LFxuICBSZWNvdmVyeVR4UmVxdWVzdCxcbiAgT3ZjSW5wdXQsXG4gIE92Y091dHB1dCxcbiAgRW52aXJvbm1lbnRzLFxuICBNUENTd2VlcFR4cyxcbiAgUHVibGljS2V5LFxuICBNUENUeHMsXG4gIE1QQ1N3ZWVwUmVjb3ZlcnlPcHRpb25zLFxufSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgQmFzZUNvaW4gYXMgU3RhdGljc0Jhc2VDb2luLCBjb2lucyB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcbmltcG9ydCB7IEtleVBhaXIgYXMgVG9uS2V5UGFpciB9IGZyb20gJy4vbGliL2tleVBhaXInO1xuaW1wb3J0IEJpZ051bWJlciBmcm9tICdiaWdudW1iZXIuanMnO1xuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb24sIFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnksIFV0aWxzLCBUcmFuc2ZlckJ1aWxkZXIgfSBmcm9tICcuL2xpYic7XG5pbXBvcnQgVG9uV2ViIGZyb20gJ3RvbndlYic7XG5pbXBvcnQgeyBnZXREZXJpdmF0aW9uUGF0aCB9IGZyb20gJ0BiaXRnby9zZGstbGliLW1wYyc7XG5pbXBvcnQgeyBnZXRGZWVFc3RpbWF0ZSB9IGZyb20gJy4vbGliL3V0aWxzJztcblxuZXhwb3J0IGludGVyZmFjZSBUb25QYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyBleHRlbmRzIFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhIZXg6IHN0cmluZztcbiAgZnJvbUFkZHJlc3NCb3VuY2VhYmxlPzogYm9vbGVhbjtcbiAgdG9BZGRyZXNzQm91bmNlYWJsZT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjbGFzcyBUb24gZXh0ZW5kcyBCYXNlQ29pbiB7XG4gIHByb3RlY3RlZCByZWFkb25seSBfc3RhdGljc0NvaW46IFJlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj47XG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihiaXRnbzogQml0R29CYXNlLCBzdGF0aWNzQ29pbj86IFJlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj4pIHtcbiAgICBzdXBlcihiaXRnbyk7XG5cbiAgICBpZiAoIXN0YXRpY3NDb2luKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgY29uc3RydWN0b3IgcGFyYW1ldGVyIHN0YXRpY3NDb2luJyk7XG4gICAgfVxuXG4gICAgdGhpcy5fc3RhdGljc0NvaW4gPSBzdGF0aWNzQ29pbjtcbiAgfVxuXG4gIHN0YXRpYyBjcmVhdGVJbnN0YW5jZShiaXRnbzogQml0R29CYXNlLCBzdGF0aWNzQ29pbj86IFJlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj4pOiBCYXNlQ29pbiB7XG4gICAgcmV0dXJuIG5ldyBUb24oYml0Z28sIHN0YXRpY3NDb2luKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGYWN0b3IgYmV0d2VlbiB0aGUgY29pbidzIGJhc2UgdW5pdCBhbmQgaXRzIHNtYWxsZXN0IHN1YmRpdmlzb25cbiAgICovXG4gIHB1YmxpYyBnZXRCYXNlRmFjdG9yKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIDFlOTtcbiAgfVxuXG4gIHB1YmxpYyBnZXRDaGFpbigpOiBzdHJpbmcge1xuICAgIHJldHVybiAndG9uJztcbiAgfVxuXG4gIHB1YmxpYyBnZXRGYW1pbHkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ3Rvbic7XG4gIH1cblxuICBwdWJsaWMgZ2V0RnVsbE5hbWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ1Rvbic7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKi9cbiAgc3VwcG9ydHNUc3MoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKiogaW5oZXJpdGVkIGRvYyAqL1xuICBnZXREZWZhdWx0TXVsdGlzaWdUeXBlKCk6IE11bHRpc2lnVHlwZSB7XG4gICAgcmV0dXJuIG11bHRpc2lnVHlwZXMudHNzO1xuICB9XG5cbiAgZ2V0TVBDQWxnb3JpdGhtKCk6IE1QQ0FsZ29yaXRobSB7XG4gICAgcmV0dXJuICdlZGRzYSc7XG4gIH1cblxuICBhbGxvd3NBY2NvdW50Q29uc29saWRhdGlvbnMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBhc3luYyB2ZXJpZnlUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNvaW5Db25maWcgPSBjb2lucy5nZXQodGhpcy5nZXRDaGFpbigpKTtcbiAgICBjb25zdCB7IHR4UHJlYnVpbGQ6IHR4UHJlYnVpbGQsIHR4UGFyYW1zOiB0eFBhcmFtcyB9ID0gcGFyYW1zO1xuICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gbmV3IFRyYW5zYWN0aW9uKGNvaW5Db25maWcpO1xuICAgIGNvbnN0IHJhd1R4ID0gdHhQcmVidWlsZC50eEhleDtcbiAgICBpZiAoIXJhd1R4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgdHggcHJlYnVpbGQgcHJvcGVydHkgdHhIZXgnKTtcbiAgICB9XG5cbiAgICB0cmFuc2FjdGlvbi5mcm9tUmF3VHJhbnNhY3Rpb24oQnVmZmVyLmZyb20ocmF3VHgsICdoZXgnKS50b1N0cmluZygnYmFzZTY0JykpO1xuICAgIGNvbnN0IGV4cGxhaW5lZFR4ID0gdHJhbnNhY3Rpb24uZXhwbGFpblRyYW5zYWN0aW9uKCk7XG4gICAgaWYgKHR4UGFyYW1zLnJlY2lwaWVudHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgZmlsdGVyZWRSZWNpcGllbnRzID0gdHhQYXJhbXMucmVjaXBpZW50cz8ubWFwKChyZWNpcGllbnQpID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhZGRyZXNzOiBuZXcgVG9uV2ViLkFkZHJlc3MocmVjaXBpZW50LmFkZHJlc3MpLnRvU3RyaW5nKHRydWUsIHRydWUsIHRydWUpLFxuICAgICAgICAgIGFtb3VudDogQmlnSW50KHJlY2lwaWVudC5hbW91bnQpLFxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgICBjb25zdCBmaWx0ZXJlZE91dHB1dHMgPSBleHBsYWluZWRUeC5vdXRwdXRzLm1hcCgob3V0cHV0KSA9PiB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYWRkcmVzczogbmV3IFRvbldlYi5BZGRyZXNzKG91dHB1dC5hZGRyZXNzKS50b1N0cmluZyh0cnVlLCB0cnVlLCB0cnVlKSxcbiAgICAgICAgICBhbW91bnQ6IEJpZ0ludChvdXRwdXQuYW1vdW50KSxcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgICAgaWYgKCFfLmlzRXF1YWwoZmlsdGVyZWRPdXRwdXRzLCBmaWx0ZXJlZFJlY2lwaWVudHMpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHggb3V0cHV0cyBkb2VzIG5vdCBtYXRjaCB3aXRoIGV4cGVjdGVkIHR4UGFyYW1zIHJlY2lwaWVudHMnKTtcbiAgICAgIH1cbiAgICAgIGxldCB0b3RhbEFtb3VudCA9IG5ldyBCaWdOdW1iZXIoMCk7XG4gICAgICBmb3IgKGNvbnN0IHJlY2lwaWVudHMgb2YgdHhQYXJhbXMucmVjaXBpZW50cykge1xuICAgICAgICB0b3RhbEFtb3VudCA9IHRvdGFsQW1vdW50LnBsdXMocmVjaXBpZW50cy5hbW91bnQpO1xuICAgICAgfVxuICAgICAgaWYgKCF0b3RhbEFtb3VudC5pc0VxdWFsVG8oZXhwbGFpbmVkVHgub3V0cHV0QW1vdW50KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1R4IHRvdGFsIGFtb3VudCBkb2VzIG5vdCBtYXRjaCB3aXRoIGV4cGVjdGVkIHRvdGFsIGFtb3VudCBmaWVsZCcpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGFzeW5jIGlzV2FsbGV0QWRkcmVzcyhwYXJhbXM6IFRzc1ZlcmlmeUFkZHJlc3NPcHRpb25zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyBrZXljaGFpbnMsIGFkZHJlc3M6IG5ld0FkZHJlc3MsIGluZGV4IH0gPSBwYXJhbXM7XG5cbiAgICBpZiAoIXRoaXMuaXNWYWxpZEFkZHJlc3MobmV3QWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIGFkZHJlc3M6ICR7bmV3QWRkcmVzc31gKTtcbiAgICB9XG5cbiAgICBpZiAoIWtleWNoYWlucykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHBhcmFtIGtleWNoYWlucycpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qga2V5Y2hhaW4gb2Yga2V5Y2hhaW5zKSB7XG4gICAgICBjb25zdCBbYWRkcmVzcywgbWVtb0lkXSA9IG5ld0FkZHJlc3Muc3BsaXQoJz9tZW1vSWQ9Jyk7XG4gICAgICBjb25zdCBNUEMgPSBhd2FpdCBFRERTQU1ldGhvZHMuZ2V0SW5pdGlhbGl6ZWRNcGNJbnN0YW5jZSgpO1xuICAgICAgY29uc3QgY29tbW9uS2V5Y2hhaW4gPSBrZXljaGFpbi5jb21tb25LZXljaGFpbiBhcyBzdHJpbmc7XG5cbiAgICAgIGNvbnN0IGRlcml2YXRpb25QYXRoID0gJ20vJyArIGluZGV4O1xuICAgICAgY29uc3QgZGVyaXZlZFB1YmxpY0tleSA9IE1QQy5kZXJpdmVVbmhhcmRlbmVkKGNvbW1vbktleWNoYWluLCBkZXJpdmF0aW9uUGF0aCkuc2xpY2UoMCwgNjQpO1xuICAgICAgY29uc3QgZXhwZWN0ZWRBZGRyZXNzID0gYXdhaXQgVXRpbHMuZGVmYXVsdC5nZXRBZGRyZXNzRnJvbVB1YmxpY0tleShkZXJpdmVkUHVibGljS2V5KTtcblxuICAgICAgaWYgKG1lbW9JZCkge1xuICAgICAgICByZXR1cm4gbWVtb0lkID09PSBgJHtpbmRleH1gO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWRkcmVzcyAhPT0gZXhwZWN0ZWRBZGRyZXNzKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGFzeW5jIHBhcnNlVHJhbnNhY3Rpb24ocGFyYW1zOiBUb25QYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8UGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCBmYWN0b3J5ID0gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KHRoaXMuZ2V0Q2hhaW4oKSkpO1xuICAgIGNvbnN0IHRyYW5zYWN0aW9uQnVpbGRlciA9IGZhY3RvcnkuZnJvbShCdWZmZXIuZnJvbShwYXJhbXMudHhIZXgsICdoZXgnKS50b1N0cmluZygnYmFzZTY0JykpO1xuXG4gICAgaWYgKHR5cGVvZiBwYXJhbXMudG9BZGRyZXNzQm91bmNlYWJsZSA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgICB0cmFuc2FjdGlvbkJ1aWxkZXIudG9BZGRyZXNzQm91bmNlYWJsZShwYXJhbXMudG9BZGRyZXNzQm91bmNlYWJsZSk7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBwYXJhbXMuZnJvbUFkZHJlc3NCb3VuY2VhYmxlID09PSAnYm9vbGVhbicpIHtcbiAgICAgIHRyYW5zYWN0aW9uQnVpbGRlci5mcm9tQWRkcmVzc0JvdW5jZWFibGUocGFyYW1zLmZyb21BZGRyZXNzQm91bmNlYWJsZSk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVidWlsdFRyYW5zYWN0aW9uID0gYXdhaXQgdHJhbnNhY3Rpb25CdWlsZGVyLmJ1aWxkKCk7XG4gICAgY29uc3QgcGFyc2VkVHJhbnNhY3Rpb24gPSByZWJ1aWx0VHJhbnNhY3Rpb24udG9Kc29uKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlucHV0czogW1xuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogcGFyc2VkVHJhbnNhY3Rpb24uc2VuZGVyLFxuICAgICAgICAgIGFtb3VudDogcGFyc2VkVHJhbnNhY3Rpb24uYW1vdW50LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIG91dHB1dHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6IHBhcnNlZFRyYW5zYWN0aW9uLmRlc3RpbmF0aW9uLFxuICAgICAgICAgIGFtb3VudDogcGFyc2VkVHJhbnNhY3Rpb24uYW1vdW50LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9O1xuICB9XG5cbiAgZ2VuZXJhdGVLZXlQYWlyKHNlZWQ/OiBCdWZmZXIpOiBLZXlQYWlyIHtcbiAgICBjb25zdCBrZXlQYWlyID0gc2VlZCA/IG5ldyBUb25LZXlQYWlyKHsgc2VlZCB9KSA6IG5ldyBUb25LZXlQYWlyKCk7XG4gICAgY29uc3Qga2V5cyA9IGtleVBhaXIuZ2V0S2V5cygpO1xuICAgIGlmICgha2V5cy5wcnYpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBwcnYgaW4ga2V5IGdlbmVyYXRpb24uJyk7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBwdWI6IGtleXMucHViLFxuICAgICAgcHJ2OiBrZXlzLnBydixcbiAgICB9O1xuICB9XG5cbiAgaXNWYWxpZFB1YihwdWI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRocm93IG5ldyBFcnJvcignTWV0aG9kIG5vdCBpbXBsZW1lbnRlZC4nKTtcbiAgfVxuXG4gIGlzVmFsaWRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBhZGRyZXNzQmFzZTY0ID0gYWRkcmVzcy5yZXBsYWNlKC9cXCsvZywgJy0nKS5yZXBsYWNlKC9cXC8vZywgJ18nKTtcbiAgICAgIGNvbnN0IGJ1ZiA9IEJ1ZmZlci5mcm9tKGFkZHJlc3NCYXNlNjQuc3BsaXQoJz9tZW1vSWQ9JylbMF0sICdiYXNlNjQnKTtcbiAgICAgIHJldHVybiBidWYubGVuZ3RoID09PSAzNjtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBzaWduVHJhbnNhY3Rpb24ocGFyYW1zOiBTaWduVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxTaWduZWRUcmFuc2FjdGlvbj4ge1xuICAgIHRocm93IG5ldyBFcnJvcignTWV0aG9kIG5vdCBpbXBsZW1lbnRlZC4nKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBhc3luYyBnZXRTaWduYWJsZVBheWxvYWQoc2VyaWFsaXplZFR4OiBzdHJpbmcpOiBQcm9taXNlPEJ1ZmZlcj4ge1xuICAgIGNvbnN0IGZhY3RvcnkgPSBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQodGhpcy5nZXRDaGFpbigpKSk7XG4gICAgY29uc3QgcmVidWlsdFRyYW5zYWN0aW9uID0gYXdhaXQgZmFjdG9yeS5mcm9tKHNlcmlhbGl6ZWRUeCkuYnVpbGQoKTtcbiAgICByZXR1cm4gcmVidWlsdFRyYW5zYWN0aW9uLnNpZ25hYmxlUGF5bG9hZDtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBhc3luYyBleHBsYWluVHJhbnNhY3Rpb24ocGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogUHJvbWlzZTxUcmFuc2FjdGlvbkV4cGxhbmF0aW9uPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGZhY3RvcnkgPSBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQodGhpcy5nZXRDaGFpbigpKSk7XG4gICAgICBjb25zdCB0cmFuc2FjdGlvbkJ1aWxkZXIgPSBmYWN0b3J5LmZyb20oQnVmZmVyLmZyb20ocGFyYW1zLnR4SGV4LCAnaGV4JykudG9TdHJpbmcoJ2Jhc2U2NCcpKTtcblxuICAgICAgY29uc3QgeyB0b0FkZHJlc3NCb3VuY2VhYmxlLCBmcm9tQWRkcmVzc0JvdW5jZWFibGUgfSA9IHBhcmFtcztcblxuICAgICAgaWYgKHR5cGVvZiB0b0FkZHJlc3NCb3VuY2VhYmxlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgdHJhbnNhY3Rpb25CdWlsZGVyLnRvQWRkcmVzc0JvdW5jZWFibGUodG9BZGRyZXNzQm91bmNlYWJsZSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlb2YgZnJvbUFkZHJlc3NCb3VuY2VhYmxlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgdHJhbnNhY3Rpb25CdWlsZGVyLmZyb21BZGRyZXNzQm91bmNlYWJsZShmcm9tQWRkcmVzc0JvdW5jZWFibGUpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCByZWJ1aWx0VHJhbnNhY3Rpb24gPSBhd2FpdCB0cmFuc2FjdGlvbkJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIHJldHVybiByZWJ1aWx0VHJhbnNhY3Rpb24uZXhwbGFpblRyYW5zYWN0aW9uKCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdHJhbnNhY3Rpb24nKTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0UHVibGljTm9kZVVybCgpOiBzdHJpbmcge1xuICAgIHJldHVybiBFbnZpcm9ubWVudHNbdGhpcy5iaXRnby5nZXRFbnYoKV0udG9uTm9kZVVybDtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0QnVpbGRlcigpOiBUcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5IHtcbiAgICByZXR1cm4gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KHRoaXMuZ2V0Q2hhaW4oKSkpO1xuICB9XG5cbiAgYXN5bmMgcmVjb3ZlcihwYXJhbXM6IE1QQ1JlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8TVBDVHggfCBNUENTd2VlcFR4cz4ge1xuICAgIGlmICghcGFyYW1zLmJpdGdvS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgYml0Z29LZXknKTtcbiAgICB9XG4gICAgaWYgKCFwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbiB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCByZWNvdmVyeURlc3RpbmF0aW9uJyk7XG4gICAgfVxuICAgIGlmICghcGFyYW1zLmFwaUtleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIGFwaUtleScpO1xuICAgIH1cbiAgICBjb25zdCBiaXRnb0tleSA9IHBhcmFtcy5iaXRnb0tleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuICAgIGNvbnN0IGlzVW5zaWduZWRTd2VlcCA9ICFwYXJhbXMudXNlcktleSAmJiAhcGFyYW1zLmJhY2t1cEtleSAmJiAhcGFyYW1zLndhbGxldFBhc3NwaHJhc2U7XG5cbiAgICAvLyBCdWlsZCB0aGUgdHJhbnNhY3Rpb25cbiAgICBjb25zdCB0b253ZWIgPSBuZXcgVG9uV2ViKG5ldyBUb25XZWIuSHR0cFByb3ZpZGVyKHRoaXMuZ2V0UHVibGljTm9kZVVybCgpLCB7IGFwaUtleTogcGFyYW1zLmFwaUtleSB9KSk7XG4gICAgY29uc3QgTVBDID0gYXdhaXQgRUREU0FNZXRob2RzLmdldEluaXRpYWxpemVkTXBjSW5zdGFuY2UoKTtcblxuICAgIGNvbnN0IGluZGV4ID0gcGFyYW1zLmluZGV4IHx8IDA7XG4gICAgY29uc3QgY3VyclBhdGggPSBwYXJhbXMuc2VlZCA/IGdldERlcml2YXRpb25QYXRoKHBhcmFtcy5zZWVkKSArIGAvJHtpbmRleH1gIDogYG0vJHtpbmRleH1gO1xuICAgIGNvbnN0IGFjY291bnRJZCA9IE1QQy5kZXJpdmVVbmhhcmRlbmVkKGJpdGdvS2V5LCBjdXJyUGF0aCkuc2xpY2UoMCwgNjQpO1xuICAgIGNvbnN0IHNlbmRlckFkZHIgPSBhd2FpdCBVdGlscy5kZWZhdWx0LmdldEFkZHJlc3NGcm9tUHVibGljS2V5KGFjY291bnRJZCk7XG4gICAgY29uc3QgYmFsYW5jZSA9IGF3YWl0IHRvbndlYi5nZXRCYWxhbmNlKHNlbmRlckFkZHIpO1xuICAgIGlmIChuZXcgQmlnTnVtYmVyKGJhbGFuY2UpLmlzRXF1YWxUbygwKSkge1xuICAgICAgdGhyb3cgRXJyb3IoJ0RpZCBub3QgZmluZCBhZGRyZXNzIHdpdGggZnVuZHMgdG8gcmVjb3ZlcicpO1xuICAgIH1cblxuICAgIGNvbnN0IFdhbGxldENsYXNzID0gdG9ud2ViLndhbGxldC5hbGxbJ3Y0UjInXTtcbiAgICBjb25zdCB3YWxsZXQgPSBuZXcgV2FsbGV0Q2xhc3ModG9ud2ViLnByb3ZpZGVyLCB7XG4gICAgICBwdWJsaWNLZXk6IHRvbndlYi51dGlscy5oZXhUb0J5dGVzKGFjY291bnRJZCksXG4gICAgICB3YzogMCxcbiAgICB9KTtcbiAgICBsZXQgc2Vxbm8gPSBhd2FpdCB3YWxsZXQubWV0aG9kcy5zZXFubygpLmNhbGwoKTtcbiAgICBpZiAoc2Vxbm8gPT09IG51bGwpIHtcbiAgICAgIHNlcW5vID0gMDtcbiAgICB9XG5cbiAgICBjb25zdCBmZWVFc3RpbWF0ZSA9IGF3YWl0IGdldEZlZUVzdGltYXRlKHdhbGxldCwgcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24sIGJhbGFuY2UsIHNlcW5vIGFzIG51bWJlcik7XG5cbiAgICBjb25zdCB0b3RhbEZlZUVzdGltYXRlID0gTWF0aC5yb3VuZChcbiAgICAgIChmZWVFc3RpbWF0ZS5zb3VyY2VfZmVlcy5pbl9md2RfZmVlICtcbiAgICAgICAgZmVlRXN0aW1hdGUuc291cmNlX2ZlZXMuc3RvcmFnZV9mZWUgK1xuICAgICAgICBmZWVFc3RpbWF0ZS5zb3VyY2VfZmVlcy5nYXNfZmVlICtcbiAgICAgICAgZmVlRXN0aW1hdGUuc291cmNlX2ZlZXMuZndkX2ZlZSkgKlxuICAgICAgICAxLjVcbiAgICApO1xuXG4gICAgaWYgKG5ldyBCaWdOdW1iZXIodG90YWxGZWVFc3RpbWF0ZSkuZ3QoYmFsYW5jZSkpIHtcbiAgICAgIHRocm93IEVycm9yKCdEaWQgbm90IGZpbmQgYWRkcmVzcyB3aXRoIGZ1bmRzIHRvIHJlY292ZXInKTtcbiAgICB9XG5cbiAgICBjb25zdCBmYWN0b3J5ID0gdGhpcy5nZXRCdWlsZGVyKCk7XG4gICAgY29uc3QgZXhwaXJlQXQgPSBNYXRoLmZsb29yKERhdGUubm93KCkgLyAxZTMpICsgNjAgKiA2MCAqIDI0ICogNzsgLy8gNyBkYXlzXG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5XG4gICAgICAuZ2V0VHJhbnNmZXJCdWlsZGVyKClcbiAgICAgIC5zZW5kZXIoc2VuZGVyQWRkcilcbiAgICAgIC5zZXF1ZW5jZU51bWJlcihzZXFubyBhcyBudW1iZXIpXG4gICAgICAucHVibGljS2V5KGFjY291bnRJZClcbiAgICAgIC5leHBpcmVUaW1lKGV4cGlyZUF0KTtcblxuICAgICh0eEJ1aWxkZXIgYXMgVHJhbnNmZXJCdWlsZGVyKS5zZW5kKHtcbiAgICAgIGFkZHJlc3M6IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgYW1vdW50OiBuZXcgQmlnTnVtYmVyKGJhbGFuY2UpLm1pbnVzKG5ldyBCaWdOdW1iZXIodG90YWxGZWVFc3RpbWF0ZSkpLnRvU3RyaW5nKCksXG4gICAgfSk7XG5cbiAgICBjb25zdCB1bnNpZ25lZFRyYW5zYWN0aW9uID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG5cbiAgICBpZiAoIWlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgaWYgKCFwYXJhbXMudXNlcktleSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdXNlcktleScpO1xuICAgICAgfVxuICAgICAgaWYgKCFwYXJhbXMuYmFja3VwS2V5KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBiYWNrdXBLZXknKTtcbiAgICAgIH1cbiAgICAgIGlmICghcGFyYW1zLndhbGxldFBhc3NwaHJhc2UpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHdhbGxldCBwYXNzcGhyYXNlJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIENsZWFuIHVwIHdoaXRlc3BhY2UgZnJvbSBlbnRlcmVkIHZhbHVlc1xuICAgICAgY29uc3QgdXNlcktleSA9IHBhcmFtcy51c2VyS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgICBjb25zdCBiYWNrdXBLZXkgPSBwYXJhbXMuYmFja3VwS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG5cbiAgICAgIGxldCB1c2VyUHJ2O1xuXG4gICAgICB0cnkge1xuICAgICAgICB1c2VyUHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgICBpbnB1dDogdXNlcktleSxcbiAgICAgICAgICBwYXNzd29yZDogcGFyYW1zLndhbGxldFBhc3NwaHJhc2UsXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIGRlY3J5cHRpbmcgdXNlciBrZXljaGFpbjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgICBjb25zdCB1c2VyU2lnbmluZ01hdGVyaWFsID0gSlNPTi5wYXJzZSh1c2VyUHJ2KSBhcyBFRERTQU1ldGhvZFR5cGVzLlVzZXJTaWduaW5nTWF0ZXJpYWw7XG5cbiAgICAgIGxldCBiYWNrdXBQcnY7XG4gICAgICB0cnkge1xuICAgICAgICBiYWNrdXBQcnYgPSB0aGlzLmJpdGdvLmRlY3J5cHQoe1xuICAgICAgICAgIGlucHV0OiBiYWNrdXBLZXksXG4gICAgICAgICAgcGFzc3dvcmQ6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBkZWNyeXB0aW5nIGJhY2t1cCBrZXljaGFpbjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgICBjb25zdCBiYWNrdXBTaWduaW5nTWF0ZXJpYWwgPSBKU09OLnBhcnNlKGJhY2t1cFBydikgYXMgRUREU0FNZXRob2RUeXBlcy5CYWNrdXBTaWduaW5nTWF0ZXJpYWw7XG5cbiAgICAgIGNvbnN0IHNpZ25hdHVyZUhleCA9IGF3YWl0IEVERFNBTWV0aG9kcy5nZXRUU1NTaWduYXR1cmUoXG4gICAgICAgIHVzZXJTaWduaW5nTWF0ZXJpYWwsXG4gICAgICAgIGJhY2t1cFNpZ25pbmdNYXRlcmlhbCxcbiAgICAgICAgY3VyclBhdGgsXG4gICAgICAgIHVuc2lnbmVkVHJhbnNhY3Rpb25cbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHB1YmxpY0tleU9iaiA9IHsgcHViOiBzZW5kZXJBZGRyIH07XG4gICAgICB0eEJ1aWxkZXIuYWRkU2lnbmF0dXJlKHB1YmxpY0tleU9iaiBhcyBQdWJsaWNLZXksIHNpZ25hdHVyZUhleCk7XG4gICAgfVxuXG4gICAgY29uc3QgY29tcGxldGVkVHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBjb25zdCBzZXJpYWxpemVkVHggPSBjb21wbGV0ZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuICAgIGNvbnN0IHdhbGxldENvaW4gPSB0aGlzLmdldENoYWluKCk7XG5cbiAgICBjb25zdCBpbnB1dHM6IE92Y0lucHV0W10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGlucHV0IG9mIGNvbXBsZXRlZFRyYW5zYWN0aW9uLmlucHV0cykge1xuICAgICAgaW5wdXRzLnB1c2goe1xuICAgICAgICBhZGRyZXNzOiBpbnB1dC5hZGRyZXNzLFxuICAgICAgICB2YWx1ZVN0cmluZzogaW5wdXQudmFsdWUsXG4gICAgICAgIHZhbHVlOiBuZXcgQmlnTnVtYmVyKGlucHV0LnZhbHVlKS50b051bWJlcigpLFxuICAgICAgfSk7XG4gICAgfVxuICAgIGNvbnN0IG91dHB1dHM6IE92Y091dHB1dFtdID0gW107XG4gICAgZm9yIChjb25zdCBvdXRwdXQgb2YgY29tcGxldGVkVHJhbnNhY3Rpb24ub3V0cHV0cykge1xuICAgICAgb3V0cHV0cy5wdXNoKHtcbiAgICAgICAgYWRkcmVzczogb3V0cHV0LmFkZHJlc3MsXG4gICAgICAgIHZhbHVlU3RyaW5nOiBvdXRwdXQudmFsdWUsXG4gICAgICAgIGNvaW5OYW1lOiBvdXRwdXQuY29pbixcbiAgICAgIH0pO1xuICAgIH1cbiAgICBjb25zdCBzcGVuZEFtb3VudCA9IGNvbXBsZXRlZFRyYW5zYWN0aW9uLmlucHV0cy5sZW5ndGggPT09IDEgPyBjb21wbGV0ZWRUcmFuc2FjdGlvbi5pbnB1dHNbMF0udmFsdWUgOiAwO1xuICAgIGNvbnN0IHBhcnNlZFR4ID0geyBpbnB1dHM6IGlucHV0cywgb3V0cHV0czogb3V0cHV0cywgc3BlbmRBbW91bnQ6IHNwZW5kQW1vdW50LCB0eXBlOiAnJyB9O1xuICAgIGNvbnN0IGZlZUluZm8gPSB7IGZlZTogdG90YWxGZWVFc3RpbWF0ZSwgZmVlU3RyaW5nOiB0b3RhbEZlZUVzdGltYXRlLnRvU3RyaW5nKCkgfTtcbiAgICBjb25zdCBjb2luU3BlY2lmaWMgPSB7IGNvbW1vbktleWNoYWluOiBiaXRnb0tleSB9O1xuICAgIGlmIChpc1Vuc2lnbmVkU3dlZXApIHtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uOiBNUENUeCA9IHtcbiAgICAgICAgc2VyaWFsaXplZFR4OiBzZXJpYWxpemVkVHgsXG4gICAgICAgIHNjYW5JbmRleDogaW5kZXgsXG4gICAgICAgIGNvaW46IHdhbGxldENvaW4sXG4gICAgICAgIHNpZ25hYmxlSGV4OiBjb21wbGV0ZWRUcmFuc2FjdGlvbi5zaWduYWJsZVBheWxvYWQudG9TdHJpbmcoJ2hleCcpLFxuICAgICAgICBkZXJpdmF0aW9uUGF0aDogY3VyclBhdGgsXG4gICAgICAgIHBhcnNlZFR4OiBwYXJzZWRUeCxcbiAgICAgICAgZmVlSW5mbzogZmVlSW5mbyxcbiAgICAgICAgY29pblNwZWNpZmljOiBjb2luU3BlY2lmaWMsXG4gICAgICB9O1xuICAgICAgY29uc3QgdW5zaWduZWRUeDogTVBDVW5zaWduZWRUeCA9IHsgdW5zaWduZWRUeDogdHJhbnNhY3Rpb24sIHNpZ25hdHVyZVNoYXJlczogW10gfTtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uczogTVBDVW5zaWduZWRUeFtdID0gW3Vuc2lnbmVkVHhdO1xuICAgICAgY29uc3QgdHhSZXF1ZXN0OiBSZWNvdmVyeVR4UmVxdWVzdCA9IHtcbiAgICAgICAgdHJhbnNhY3Rpb25zOiB0cmFuc2FjdGlvbnMsXG4gICAgICAgIHdhbGxldENvaW46IHdhbGxldENvaW4sXG4gICAgICB9O1xuICAgICAgY29uc3QgdHhSZXF1ZXN0czogTVBDU3dlZXBUeHMgPSB7IHR4UmVxdWVzdHM6IFt0eFJlcXVlc3RdIH07XG4gICAgICByZXR1cm4gdHhSZXF1ZXN0cztcbiAgICB9XG5cbiAgICBjb25zdCB0cmFuc2FjdGlvbjogTVBDVHggPSB7XG4gICAgICBzZXJpYWxpemVkVHg6IHNlcmlhbGl6ZWRUeCxcbiAgICAgIHNjYW5JbmRleDogaW5kZXgsXG4gICAgfTtcbiAgICByZXR1cm4gdHJhbnNhY3Rpb247XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBmdW5kcyBzd2VlcCByZWNvdmVyeSB0cmFuc2FjdGlvbihzKSB3aXRob3V0IEJpdEdvXG4gICAqXG4gICAqIEBwYXJhbSB7TVBDU3dlZXBSZWNvdmVyeU9wdGlvbnN9IHBhcmFtcyBwYXJhbWV0ZXJzIG5lZWRlZCB0byBjb21iaW5lIHRoZSBzaWduYXR1cmVzXG4gICAqIGFuZCB0cmFuc2FjdGlvbnMgdG8gY3JlYXRlIGJyb2FkY2FzdGFibGUgdHJhbnNhY3Rpb25zXG4gICAqXG4gICAqIEByZXR1cm5zIHtNUENUeHN9IGFycmF5IG9mIHRoZSBzZXJpYWxpemVkIHRyYW5zYWN0aW9uIGhleCBzdHJpbmdzIGFuZCBpbmRpY2VzXG4gICAqIG9mIHRoZSBhZGRyZXNzZXMgYmVpbmcgc3dlcHRcbiAgICovXG4gIGFzeW5jIGNyZWF0ZUJyb2FkY2FzdGFibGVTd2VlcFRyYW5zYWN0aW9uKHBhcmFtczogTVBDU3dlZXBSZWNvdmVyeU9wdGlvbnMpOiBQcm9taXNlPE1QQ1R4cz4ge1xuICAgIGNvbnN0IHJlcSA9IHBhcmFtcy5zaWduYXR1cmVTaGFyZXM7XG4gICAgY29uc3QgYnJvYWRjYXN0YWJsZVRyYW5zYWN0aW9uczogTVBDVHhbXSA9IFtdO1xuICAgIGxldCBsYXN0U2NhbkluZGV4ID0gMDtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmVxLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBNUEMgPSBhd2FpdCBFRERTQU1ldGhvZHMuZ2V0SW5pdGlhbGl6ZWRNcGNJbnN0YW5jZSgpO1xuICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSByZXFbaV0udHhSZXF1ZXN0LnRyYW5zYWN0aW9uc1swXS51bnNpZ25lZFR4O1xuICAgICAgaWYgKCFyZXFbaV0ub3ZjIHx8ICFyZXFbaV0ub3ZjWzBdLmVkZHNhU2lnbmF0dXJlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBzaWduYXR1cmUocyknKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IHJlcVtpXS5vdmNbMF0uZWRkc2FTaWduYXR1cmU7XG4gICAgICBpZiAoIXRyYW5zYWN0aW9uLnNpZ25hYmxlSGV4KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBzaWduYWJsZSBoZXgnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IG1lc3NhZ2VCdWZmZXIgPSBCdWZmZXIuZnJvbSh0cmFuc2FjdGlvbi5zaWduYWJsZUhleCEsICdoZXgnKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IE1QQy52ZXJpZnkobWVzc2FnZUJ1ZmZlciwgc2lnbmF0dXJlKTtcbiAgICAgIGlmICghcmVzdWx0KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzaWduYXR1cmUnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNpZ25hdHVyZUhleCA9IEJ1ZmZlci5jb25jYXQoW0J1ZmZlci5mcm9tKHNpZ25hdHVyZS5SLCAnaGV4JyksIEJ1ZmZlci5mcm9tKHNpZ25hdHVyZS5zaWdtYSwgJ2hleCcpXSk7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldEJ1aWxkZXIoKS5mcm9tKHRyYW5zYWN0aW9uLnNlcmlhbGl6ZWRUeCBhcyBzdHJpbmcpO1xuICAgICAgaWYgKCF0cmFuc2FjdGlvbi5jb2luU3BlY2lmaWM/LmNvbW1vbktleWNoYWluKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBjb21tb24ga2V5Y2hhaW4nKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGNvbW1vbktleWNoYWluID0gdHJhbnNhY3Rpb24uY29pblNwZWNpZmljIS5jb21tb25LZXljaGFpbiEgYXMgc3RyaW5nO1xuICAgICAgaWYgKCF0cmFuc2FjdGlvbi5kZXJpdmF0aW9uUGF0aCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgZGVyaXZhdGlvbiBwYXRoJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBkZXJpdmF0aW9uUGF0aCA9IHRyYW5zYWN0aW9uLmRlcml2YXRpb25QYXRoIGFzIHN0cmluZztcbiAgICAgIGNvbnN0IGFjY291bnRJZCA9IE1QQy5kZXJpdmVVbmhhcmRlbmVkKGNvbW1vbktleWNoYWluLCBkZXJpdmF0aW9uUGF0aCkuc2xpY2UoMCwgNjQpO1xuICAgICAgY29uc3QgdG9uS2V5UGFpciA9IG5ldyBUb25LZXlQYWlyKHsgcHViOiBhY2NvdW50SWQgfSk7XG5cbiAgICAgIC8vIGFkZCBjb21iaW5lZCBzaWduYXR1cmUgZnJvbSBvdmNcbiAgICAgIHR4QnVpbGRlci5hZGRTaWduYXR1cmUoeyBwdWI6IHRvbktleVBhaXIuZ2V0S2V5cygpLnB1YiB9LCBzaWduYXR1cmVIZXgpO1xuICAgICAgY29uc3Qgc2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGNvbnN0IHNlcmlhbGl6ZWRUeCA9IHNpZ25lZFRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgICAgIGJyb2FkY2FzdGFibGVUcmFuc2FjdGlvbnMucHVzaCh7XG4gICAgICAgIHNlcmlhbGl6ZWRUeDogc2VyaWFsaXplZFR4LFxuICAgICAgICBzY2FuSW5kZXg6IHRyYW5zYWN0aW9uLnNjYW5JbmRleCxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaSA9PT0gcmVxLmxlbmd0aCAtIDEgJiYgdHJhbnNhY3Rpb24uY29pblNwZWNpZmljIS5sYXN0U2NhbkluZGV4KSB7XG4gICAgICAgIGxhc3RTY2FuSW5kZXggPSB0cmFuc2FjdGlvbi5jb2luU3BlY2lmaWMhLmxhc3RTY2FuSW5kZXggYXMgbnVtYmVyO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IHRyYW5zYWN0aW9uczogYnJvYWRjYXN0YWJsZVRyYW5zYWN0aW9ucywgbGFzdFNjYW5JbmRleCB9O1xuICB9XG59XG4iXX0=

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


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