PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/@bitgo/sdk-coin-near/dist/src

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

"use strict";
/**
 * @prettier
 */
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.Near = void 0;
const _ = __importStar(require("lodash"));
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const base58 = __importStar(require("bs58"));
const nearAPI = __importStar(require("near-api-js"));
const request = __importStar(require("superagent"));
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const sdk_core_1 = require("@bitgo/sdk-core");
const statics_1 = require("@bitgo/statics");
const lib_1 = require("./lib");
const utils_1 = __importDefault(require("./lib/utils"));
const constants_1 = require("./lib/constants");
class Near extends sdk_core_1.BaseCoin {
    constructor(bitgo, staticsCoin) {
        super(bitgo);
        this.network = this.bitgo.getEnv() === 'prod' ? 'main' : 'test';
        if (!staticsCoin) {
            throw new Error('missing required constructor parameter staticsCoin');
        }
        this._staticsCoin = staticsCoin;
    }
    static createInstance(bitgo, staticsCoin) {
        return new Near(bitgo, staticsCoin);
    }
    allowsAccountConsolidations() {
        return true;
    }
    /**
     * Flag indicating if this coin supports TSS wallets.
     * @returns {boolean} True if TSS Wallets can be created for this coin
     */
    supportsTss() {
        return true;
    }
    /** inherited doc */
    getDefaultMultisigType() {
        return sdk_core_1.multisigTypes.tss;
    }
    /**
     * @inheritDoc
     */
    getTokenEnablementConfig() {
        return {
            requiresTokenEnablement: true,
            supportsMultipleTokenEnablements: false,
        };
    }
    getMPCAlgorithm() {
        return 'eddsa';
    }
    getChain() {
        return this._staticsCoin.name;
    }
    getBaseChain() {
        return this.getChain();
    }
    getFamily() {
        return this._staticsCoin.family;
    }
    getFullName() {
        return this._staticsCoin.fullName;
    }
    getBaseFactor() {
        return Math.pow(10, this._staticsCoin.decimalPlaces);
    }
    /**
     * Flag for sending value of 0
     * @returns {boolean} True if okay to send 0 value, false otherwise
     */
    valuelessTransferAllowed() {
        return false;
    }
    /**
     * Generate ed25519 key pair
     *
     * @param seed
     * @returns {Object} object with generated pub, prv
     */
    generateKeyPair(seed) {
        const keyPair = seed ? new lib_1.KeyPair({ seed }) : new lib_1.KeyPair();
        const keys = keyPair.getKeys();
        if (!keys.prv) {
            throw new Error('Missing prv in key generation.');
        }
        return {
            pub: keys.pub,
            prv: keys.prv,
        };
    }
    /**
     * Return boolean indicating whether input is valid public key for the coin.
     *
     * @param {String} pub the pub to be checked
     * @returns {Boolean} is it valid?
     */
    isValidPub(pub) {
        return utils_1.default.isValidPublicKey(pub);
    }
    /**
     * Return boolean indicating whether the supplied private key is a valid near private key
     *
     * @param {String} prv the prv to be checked
     * @returns {Boolean} is it valid?
     */
    isValidPrv(prv) {
        return utils_1.default.isValidPrivateKey(prv);
    }
    /**
     * Return boolean indicating whether input is valid public key for the coin
     *
     * @param {String} address the pub to be checked
     * @returns {Boolean} is it valid?
     */
    isValidAddress(address) {
        return utils_1.default.isValidAddress(address);
    }
    /** @inheritDoc */
    async signMessage(key, message) {
        const nearKeypair = new lib_1.KeyPair({ prv: key.prv });
        if (Buffer.isBuffer(message)) {
            message = base58.encode(message);
        }
        return Buffer.from(nearKeypair.signMessage(message));
    }
    /**
     * Explain/parse transaction
     * @param params
     */
    async explainTransaction(params) {
        const factory = this.getBuilder();
        let rebuiltTransaction;
        const txRaw = params.txPrebuild.txHex;
        try {
            const transactionBuilder = factory.from(txRaw);
            rebuiltTransaction = await transactionBuilder.build();
        }
        catch {
            throw new Error('Invalid transaction');
        }
        return rebuiltTransaction.explainTransaction();
    }
    verifySignTransactionParams(params) {
        const prv = params.prv;
        const txHex = params.txPrebuild.txHex;
        if (_.isUndefined(txHex)) {
            throw new Error('missing txPrebuild parameter');
        }
        if (!_.isString(txHex)) {
            throw new Error(`txPrebuild must be an object, got type ${typeof txHex}`);
        }
        if (_.isUndefined(prv)) {
            throw new Error('missing prv parameter to sign transaction');
        }
        if (!_.isString(prv)) {
            throw new Error(`prv must be a string, got type ${typeof prv}`);
        }
        if (!_.has(params.txPrebuild, 'key')) {
            throw new Error('missing public key parameter to sign transaction');
        }
        // if we are receiving addresses do not try to convert them
        const signer = !utils_1.default.isValidAddress(params.txPrebuild.key)
            ? new lib_1.KeyPair({ pub: params.txPrebuild.key }).getAddress()
            : params.txPrebuild.key;
        return { txHex, prv, signer };
    }
    /**
     * Assemble keychain and half-sign prebuilt transaction
     *
     * @param params
     * @param params.txPrebuild {TransactionPrebuild} prebuild object returned by platform
     * @param params.prv {String} user prv
     * @param callback
     * @returns {Bluebird<SignedTransaction>}
     */
    async signTransaction(params) {
        const factory = this.getBuilder();
        const txBuilder = factory.from(params.txPrebuild.txHex);
        txBuilder.sign({ key: params.prv });
        const transaction = await txBuilder.build();
        if (!transaction) {
            throw new Error('Invalid transaction');
        }
        const serializedTx = transaction.toBroadcastFormat();
        return {
            txHex: serializedTx,
        };
    }
    /**
     * Builds a funds recovery transaction without BitGo
     * @param params
     */
    async recover(params) {
        if (!params.bitgoKey) {
            throw new Error('missing bitgoKey');
        }
        if (!params.recoveryDestination || !this.isValidAddress(params.recoveryDestination)) {
            throw new Error('invalid recoveryDestination');
        }
        let startIdx = params.startingScanIndex;
        if (startIdx === undefined) {
            startIdx = 0;
        }
        else if (!Number.isInteger(startIdx) || startIdx < 0) {
            throw new Error('Invalid starting index to scan for addresses');
        }
        let numIteration = params.scan;
        if (numIteration === undefined) {
            numIteration = 20;
        }
        else if (!Number.isInteger(numIteration) || numIteration <= 0) {
            throw new Error('Invalid scanning factor');
        }
        const bitgoKey = params.bitgoKey.replace(/\s/g, '');
        const isUnsignedSweep = !params.userKey && !params.backupKey && !params.walletPassphrase;
        const MPC = await sdk_core_1.EDDSAMethods.getInitializedMpcInstance();
        const { storageAmountPerByte, transferCost, receiptConfig } = await this.getProtocolConfig();
        let isStorageDepositEnabled = false;
        if (params.tokenContractAddress) {
            // check if receiver storage deposit is enabled
            isStorageDepositEnabled = await this.checkIfStorageDepositIsEnabled(params.recoveryDestination, params.tokenContractAddress);
        }
        for (let i = startIdx; i < numIteration + startIdx; i++) {
            const currPath = `m/${i}`;
            const accountId = MPC.deriveUnhardened(bitgoKey, currPath).slice(0, 64);
            let availableBalance = new bignumber_js_1.default(0);
            try {
                availableBalance = new bignumber_js_1.default(await this.getAccountBalance(accountId, storageAmountPerByte));
            }
            catch (e) {
                // UNKNOWN_ACCOUNT error indicates that the address has not partake in any transaction so far, so we will
                // treat it as a zero balance address
                if (e.message !== 'UNKNOWN_ACCOUNT') {
                    throw e;
                }
            }
            if (availableBalance.toNumber() <= 0) {
                continue;
            }
            const feeReserve = (0, bignumber_js_1.default)(statics_1.Networks[this.network].near.feeReserve);
            const storageReserve = (0, bignumber_js_1.default)(statics_1.Networks[this.network].near.storageReserve);
            // check for possible token recovery, recover the token provided by the user
            if (params.tokenContractAddress) {
                const tokenName = utils_1.default.findTokenNameFromContractAddress(params.tokenContractAddress);
                if (!tokenName) {
                    throw new Error(`Token name not found for contract address ${params.tokenContractAddress}. The address may be invalid or unsupported. Please refer to the supported tokens in the BitGo documentation for guidance.`);
                }
                const token = utils_1.default.getTokenInstanceFromTokenName(tokenName);
                if (!token) {
                    throw new Error(`Token instance could not be created for token name ${tokenName}. The token may be invalid or unsupported. Please refer to the supported tokens in the BitGo documentation for guidance.`);
                }
                let availableTokenBalance;
                try {
                    availableTokenBalance = new bignumber_js_1.default(await this.getAccountFungibleTokenBalance(accountId, params.tokenContractAddress));
                }
                catch (e) {
                    throw e;
                }
                if (availableTokenBalance.toNumber() <= 0) {
                    continue;
                }
                const netAmount = availableBalance
                    .minus(utils_1.default.convertGasUnitsToYoctoNear(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER))
                    .minus(feeReserve)
                    .minus(storageReserve);
                if (netAmount.toNumber() <= 0) {
                    throw new Error(`Found address ${i} with non-zero fund but fund is insufficient to support a token recover ` +
                        `transaction. Please start the next scan at address index ${i + 1}.`);
                }
                return this.recoverNearToken(params, token, accountId, currPath, i, bitgoKey, isStorageDepositEnabled, availableTokenBalance, isUnsignedSweep);
            }
            // first build the unsigned txn
            const bs58EncodedPublicKey = nearAPI.utils.serialize.base_encode(new Uint8Array(Buffer.from(accountId, 'hex')));
            const { nonce, blockHash } = await this.getAccessKey({ accountId, bs58EncodedPublicKey });
            const gasPrice = await this.getGasPrice(blockHash);
            const gasPriceFirstBlock = new bignumber_js_1.default(gasPrice);
            const gasPriceSecondBlock = gasPriceFirstBlock.multipliedBy(1.05);
            const totalGasRequired = new bignumber_js_1.default(transferCost.sendSir)
                .plus(receiptConfig.sendSir)
                .multipliedBy(gasPriceFirstBlock)
                .plus(new bignumber_js_1.default(transferCost.execution).plus(receiptConfig.execution).multipliedBy(gasPriceSecondBlock));
            // adding some padding to make sure the gas doesn't go below required gas by network
            const totalGasWithPadding = totalGasRequired.multipliedBy(1.5);
            const netAmount = availableBalance.minus(totalGasWithPadding).minus(feeReserve).minus(storageReserve);
            if (netAmount.toNumber() <= 0) {
                throw new Error(`Found address ${i} with non-zero fund but fund is insufficient to support a recover ` +
                    `transaction. Please start the next scan at address index ${i + 1}.`);
            }
            const factory = new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getChain()));
            const txBuilder = factory
                .getTransferBuilder()
                .sender(accountId, accountId)
                .nonce(nonce)
                .receiverId(params.recoveryDestination)
                .recentBlockHash(blockHash)
                .amount(netAmount.toFixed());
            const unsignedTransaction = (await txBuilder.build());
            let serializedTx = unsignedTransaction.toBroadcastFormat();
            if (!isUnsignedSweep) {
                serializedTx = await this.signRecoveryTransaction(txBuilder, params, currPath, accountId);
            }
            else {
                return this.buildUnsignedSweepTransaction(txBuilder, accountId, params.recoveryDestination, bitgoKey, i, currPath, netAmount, totalGasWithPadding);
            }
            return { serializedTx: serializedTx, scanIndex: i };
        }
        throw new Error('Did not find an address with funds to recover');
    }
    /**
     * Function to handle near token recovery
     * @param {MPCRecoveryOptions} params mpc recovery options input
     * @param {Nep141Token} token the token object
     * @param {String} senderAddress sender address
     * @param {String} derivationPath the derivation path
     * @param {Number} idx current index
     * @param {String} bitgoKey bitgo key
     * @param {Boolean} isStorageDepositEnabled flag indicating whether storage deposit is enabled on the receiver
     * @param {BigNumber} availableTokenBalance currently available token balance on the address
     * @param {Boolean} isUnsignedSweep flag indicating whether it is an unsigned sweep
     * @returns {Promise<MPCTx | MPCSweepTxs>}
     */
    async recoverNearToken(params, token, senderAddress, derivationPath, idx, bitgoKey, isStorageDepositEnabled, availableTokenBalance, isUnsignedSweep) {
        const factory = new lib_1.TransactionBuilderFactory(token);
        const bs58EncodedPublicKey = nearAPI.utils.serialize.base_encode(new Uint8Array(Buffer.from(senderAddress, 'hex')));
        const { nonce, blockHash } = await this.getAccessKey({ accountId: senderAddress, bs58EncodedPublicKey });
        const txBuilder = factory
            .getFungibleTokenTransferBuilder()
            .sender(senderAddress, senderAddress)
            .nonce(nonce)
            .receiverId(token.contractAddress)
            .recentBlockHash(blockHash)
            .ftReceiverId(params.recoveryDestination)
            .gas(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER)
            .deposit('1')
            .amount(availableTokenBalance.toString());
        if (!isStorageDepositEnabled) {
            txBuilder.addStorageDeposit({
                deposit: BigInt(token.storageDepositAmount),
                gas: BigInt(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER),
                accountId: params.recoveryDestination,
            });
        }
        if (isUnsignedSweep) {
            return this.buildUnsignedSweepTransaction(txBuilder, senderAddress, params.recoveryDestination, bitgoKey, idx, derivationPath, availableTokenBalance, new bignumber_js_1.default(utils_1.default.convertGasUnitsToYoctoNear(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER)), token);
        }
        else {
            const serializedTx = await this.signRecoveryTransaction(txBuilder, params, derivationPath, senderAddress);
            return { serializedTx: serializedTx, scanIndex: idx };
        }
    }
    /**
     * Function to build unsigned sweep transaction
     * @param {TransactionBuilder} txBuilder the near transaction builder
     * @param {String} senderAddress sender address
     * @param {String} receiverAddress the receiver address
     * @param {String} bitgoKey bitgo key
     * @param {Number} index current index
     * @param {String} derivationPath the derivation path
     * @param {BigNumber} netAmount net amount to be recovered
     * @param {BigNumber} netGas net gas required
     * @param {Nep141Token} token optional nep141 token instance
     * @returns {Promise<MPCSweepTxs>}
     */
    async buildUnsignedSweepTransaction(txBuilder, senderAddress, receiverAddress, bitgoKey, index, derivationPath, netAmount, netGas, token) {
        const isTokenTransaction = !!token;
        const unsignedTransaction = (await txBuilder.build());
        const serializedTx = unsignedTransaction.toBroadcastFormat();
        const walletCoin = isTokenTransaction ? token.name : this.getChain();
        const inputs = [
            {
                address: senderAddress,
                valueString: netAmount.toString(),
                value: netAmount.toNumber(),
            },
        ];
        const outputs = [
            {
                address: receiverAddress,
                valueString: netAmount.toString(),
                coinName: walletCoin,
            },
        ];
        const spendAmount = netAmount.toString();
        const parsedTx = { inputs: inputs, outputs: outputs, spendAmount: spendAmount, type: '' };
        const feeInfo = { fee: netGas.toNumber(), feeString: netGas.toFixed() }; // Include gas fees
        const transaction = {
            serializedTx: serializedTx, // Serialized unsigned transaction
            scanIndex: index, // Current index in the scan
            coin: walletCoin,
            signableHex: unsignedTransaction.signablePayload.toString('hex'), // Hex payload for signing
            derivationPath: derivationPath, // Derivation path for the account
            parsedTx: parsedTx,
            feeInfo: feeInfo,
            coinSpecific: { commonKeychain: bitgoKey }, // Include block hash for NEAR
        };
        const transactions = [{ unsignedTx: transaction, signatureShares: [] }];
        const txRequest = {
            transactions: transactions,
            walletCoin: walletCoin,
        };
        return { txRequests: [txRequest] };
    }
    /**
     * Function to sign the recovery transaction
     * @param {TransactionBuilder} txBuilder the near transaction builder
     * @param {MPCRecoveryOptions} params mpc recovery options input
     * @param {String} derivationPath the derivation path
     * @param {String} senderAddress the sender address
     * @returns {Promise<String>}
     */
    async signRecoveryTransaction(txBuilder, params, derivationPath, senderAddress) {
        const unsignedTransaction = (await txBuilder.build());
        // Sign the txn
        /* ***************** START **************************************/
        // TODO(BG-51092): This looks like a common part which can be extracted out too
        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, '');
        // Decrypt private keys from KeyCard values
        let userPrv;
        try {
            userPrv = this.bitgo.decrypt({
                input: userKey,
                password: params.walletPassphrase,
            });
        }
        catch (e) {
            throw new Error(`Error decrypting user keychain: ${e.message}`);
        }
        /** TODO BG-52419 Implement Codec for parsing */
        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);
        /* ********************** END ***********************************/
        // add signature
        const signatureHex = await sdk_core_1.EDDSAMethods.getTSSSignature(userSigningMaterial, backupSigningMaterial, derivationPath, unsignedTransaction);
        const publicKeyObj = { pub: senderAddress };
        txBuilder.addSignature(publicKeyObj, signatureHex);
        const completedTransaction = await txBuilder.build();
        return completedTransaction.toBroadcastFormat();
    }
    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;
            // Validate signature shares
            if (!req[i].ovc || !req[i].ovc[0].eddsaSignature) {
                throw new Error('Missing signature(s)');
            }
            const signature = req[i].ovc[0].eddsaSignature;
            // Validate signable hex
            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');
            }
            // Prepare the signature in hex format
            const signatureHex = Buffer.concat([Buffer.from(signature.R, 'hex'), Buffer.from(signature.sigma, 'hex')]);
            // Validate transaction-specific fields
            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;
            // Derive account ID and sender address
            const accountId = MPC.deriveUnhardened(commonKeychain, derivationPath).slice(0, 64);
            const txnBuilder = this.getBuilder().from(transaction.serializedTx);
            // Add the signature
            const nearKeyPair = new lib_1.KeyPair({ pub: accountId });
            txnBuilder.addSignature({ pub: nearKeyPair.getKeys().pub }, signatureHex);
            // Finalize and serialize the transaction
            const signedTransaction = await txnBuilder.build();
            const serializedTx = signedTransaction.toBroadcastFormat();
            // Add the signed transaction to the list
            broadcastableTransactions.push({
                serializedTx: serializedTx,
                scanIndex: transaction.scanIndex,
            });
            // Update the last scan index if applicable
            if (i === req.length - 1 && transaction.coinSpecific.lastScanIndex) {
                lastScanIndex = transaction.coinSpecific.lastScanIndex;
            }
        }
        // Return the broadcastable transactions and the last scan index
        return { transactions: broadcastableTransactions, lastScanIndex };
    }
    /**
     * Make a request to one of the public EOS nodes available
     * @param params.payload
     */
    async getDataFromNode(params) {
        const nodeUrls = this.getPublicNodeUrls();
        for (const nodeUrl of nodeUrls) {
            try {
                return await request.post(nodeUrl).send(params.payload);
            }
            catch (e) {
                console.debug(e);
            }
        }
        throw new Error(`Unable to call endpoint: '/' from nodes: ${_.join(nodeUrls, ', ')}`);
    }
    async getAccessKey({ accountId, bs58EncodedPublicKey, }) {
        const response = await this.getDataFromNode({
            payload: {
                jsonrpc: '2.0',
                id: 'dontcare',
                method: 'query',
                params: {
                    request_type: 'view_access_key',
                    finality: 'final',
                    account_id: accountId,
                    public_key: bs58EncodedPublicKey,
                },
            },
        });
        if (response.status !== 200) {
            throw new Error('Account not found');
        }
        const accessKey = response.body.result;
        return { nonce: accessKey.nonce + 1, blockHash: accessKey.block_hash };
    }
    async getAccountBalance(accountId, storageAmountPerByte) {
        const response = await this.getDataFromNode({
            payload: {
                jsonrpc: '2.0',
                id: 'dontcare',
                method: 'query',
                params: {
                    request_type: 'view_account',
                    finality: 'final',
                    account_id: accountId,
                },
            },
        });
        if (response.status !== 200) {
            throw new Error('Failed to query account information');
        }
        const errorCause = response.body.error?.cause.name;
        if (errorCause !== undefined) {
            throw new Error(errorCause);
        }
        const account = response.body.result;
        const costPerByte = new bignumber_js_1.default(storageAmountPerByte);
        const stateStaked = new bignumber_js_1.default(account.storage_usage).multipliedBy(costPerByte);
        const staked = new bignumber_js_1.default(account.locked);
        const totalBalance = new bignumber_js_1.default(account.amount).plus(staked);
        const availableBalance = totalBalance.minus(bignumber_js_1.default.max(staked, stateStaked));
        return availableBalance.toString();
    }
    /**
     * Function to get the fungible token balance for an account
     * @param {String} accountId account for which the ft balance to be fetched
     * @param tokenContractAddress the token contract address
     * @returns {Promise<String>}
     */
    async getAccountFungibleTokenBalance(accountId, tokenContractAddress) {
        const base64Args = utils_1.default.convertToBase64({ account_id: accountId });
        const response = await this.getDataFromNode({
            payload: {
                jsonrpc: '2.0',
                id: 'dontcare',
                method: 'query',
                params: {
                    request_type: 'call_function',
                    finality: 'final',
                    account_id: tokenContractAddress,
                    method_name: 'ft_balance_of',
                    args_base64: base64Args,
                },
            },
        });
        if (response.status !== 200) {
            throw new Error('Failed to fetch ft balance of the account');
        }
        const errorCause = response.body.error?.cause?.name;
        if (errorCause !== undefined) {
            throw new Error(errorCause);
        }
        const resultUint8Array = new Uint8Array(response.body.result.result);
        const raw = new TextDecoder().decode(resultUint8Array);
        return JSON.parse(raw);
    }
    /**
     * Function to check if storage deposit is enabled on an address for a token
     * @param {String} accountId account for which the storage balance to be fetched
     * @param tokenContractAddress the token contract address
     * @returns {Promise<Boolean>} true if we find the storage balance, false if response is null
     */
    async checkIfStorageDepositIsEnabled(accountId, tokenContractAddress) {
        const base64Args = utils_1.default.convertToBase64({ account_id: accountId });
        const response = await this.getDataFromNode({
            payload: {
                jsonrpc: '2.0',
                id: 'dontcare',
                method: 'query',
                params: {
                    request_type: 'call_function',
                    finality: 'final',
                    account_id: tokenContractAddress,
                    method_name: 'storage_balance_of',
                    args_base64: base64Args,
                },
            },
        });
        if (response.status !== 200) {
            throw new Error('Failed to fetch storage deposit of the account');
        }
        const errorCause = response.body.error?.cause?.name;
        if (errorCause !== undefined) {
            throw new Error(errorCause);
        }
        const resultUint8Array = new Uint8Array(response.body.result.result);
        const raw = new TextDecoder().decode(resultUint8Array);
        const decoded = JSON.parse(raw);
        return decoded !== null;
    }
    async getProtocolConfig() {
        const response = await this.getDataFromNode({
            payload: {
                jsonrpc: '2.0',
                id: 'dontcare',
                method: 'EXPERIMENTAL_protocol_config',
                params: {
                    finality: 'final',
                },
            },
        });
        if (response.status !== 200) {
            throw new Error('Account not found');
        }
        const config = response.body.result;
        const storageAmountPerByte = config.runtime_config.storage_amount_per_byte;
        const transferCostFromNetwork = config.runtime_config.transaction_costs.action_creation_config.transfer_cost;
        const transferCost = {
            sendSir: transferCostFromNetwork.send_sir,
            sendNotSir: transferCostFromNetwork.send_not_sir,
            execution: transferCostFromNetwork.execution,
        };
        const receiptConfigFromNetwork = config.runtime_config.transaction_costs.action_receipt_creation_config;
        const receiptConfig = {
            sendSir: receiptConfigFromNetwork.send_sir,
            sendNotSir: receiptConfigFromNetwork.send_not_sir,
            execution: receiptConfigFromNetwork.execution,
        };
        return { storageAmountPerByte, transferCost, receiptConfig };
    }
    async getGasPrice(blockHash) {
        const response = await this.getDataFromNode({
            payload: {
                jsonrpc: '2.0',
                id: 'dontcare',
                method: 'gas_price',
                params: [blockHash],
            },
        });
        if (response.status !== 200) {
            throw new Error('Account not found');
        }
        return response.body.result.gas_price;
    }
    getPublicNodeUrls() {
        return sdk_core_1.Environments[this.bitgo.getEnv()].nearNodeUrls;
    }
    async parseTransaction(params) {
        const transactionExplanation = await this.explainTransaction({
            txPrebuild: params.txPrebuild,
            publicKey: params.publicKey,
            feeInfo: params.feeInfo,
        });
        if (!transactionExplanation) {
            throw new Error('Invalid transaction');
        }
        const nearTransaction = transactionExplanation;
        if (nearTransaction.outputs.length <= 0) {
            return {
                inputs: [],
                outputs: [],
            };
        }
        const senderAddress = nearTransaction.outputs[0].address;
        const feeAmount = new bignumber_js_1.default(nearTransaction.fee.fee === '' ? '0' : nearTransaction.fee.fee);
        // assume 1 sender, who is also the fee payer
        const inputs = [
            {
                address: senderAddress,
                amount: new bignumber_js_1.default(nearTransaction.outputAmount).plus(feeAmount).toFixed(),
            },
        ];
        const outputs = nearTransaction.outputs.map((output) => {
            return {
                address: output.address,
                amount: new bignumber_js_1.default(output.amount).toFixed(),
            };
        });
        return {
            inputs,
            outputs,
        };
    }
    async isWalletAddress(params) {
        throw new sdk_core_1.MethodNotImplementedError();
    }
    async verifyTransaction(params) {
        let totalAmount = new bignumber_js_1.default(0);
        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(rawTx);
        const explainedTx = transaction.explainTransaction();
        // users do not input recipients for consolidation requests as they are generated by the server
        if (txParams.recipients !== undefined) {
            if (txParams.type === 'enabletoken') {
                const tokenName = explainedTx.outputs[0].tokenName;
                if (tokenName) {
                    const nepToken = utils_1.default.getTokenInstanceFromTokenName(tokenName);
                    if (nepToken) {
                        explainedTx.outputs.forEach((output) => {
                            if (output.amount !== nepToken.storageDepositAmount) {
                                throw new Error('Storage deposit amount not matching!');
                            }
                        });
                    }
                }
            }
            const filteredRecipients = txParams.recipients?.map((recipient) => {
                if (txParams.type !== 'enabletoken') {
                    return _.pick(recipient, ['address', 'amount']);
                }
                else {
                    return _.pick(recipient, ['address', 'tokenName']);
                }
            });
            const filteredOutputs = explainedTx.outputs.map((output) => {
                if (txParams.type !== 'enabletoken') {
                    return _.pick(output, ['address', 'amount']);
                }
                else {
                    return _.pick(output, ['address', 'tokenName']);
                }
            });
            if (!_.isEqual(filteredOutputs, filteredRecipients)) {
                throw new Error('Tx outputs does not match with expected txParams recipients');
            }
            for (const recipients of txParams.recipients) {
                totalAmount = txParams.type !== 'enabletoken' ? totalAmount.plus(recipients.amount) : (0, bignumber_js_1.default)(0);
            }
            if (!totalAmount.isEqualTo(explainedTx.outputAmount) && txParams.type !== 'enabletoken') {
                throw new Error('Tx total amount does not match with expected total amount field');
            }
        }
        if (params.verification?.consolidationToBaseAddress) {
            await this.verifyConsolidationToBaseAddress(params, explainedTx);
        }
        return true;
    }
    getBuilder() {
        return new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getBaseChain()));
    }
    /** @inheritDoc */
    auditDecryptedKey({ prv, publicKey, multiSigType }) {
        if (multiSigType !== 'tss') {
            throw new Error('Unsupported multiSigType');
        }
        (0, sdk_lib_mpc_1.auditEddsaPrivateKey)(prv, publicKey ?? '');
    }
    async verifyConsolidationToBaseAddress(params, explainedTx) {
        const baseAddresses = await params.wallet.addresses({ sort: -1, limit: 1 });
        if (!baseAddresses || baseAddresses.length === 0) {
            throw new Error('No base address found on wallet');
        }
        const baseAddress = baseAddresses[0];
        for (const output of explainedTx.outputs) {
            if (output.address !== baseAddress.address) {
                throw new Error('tx outputs does not match with expected address');
            }
        }
    }
}
exports.Near = Near;
Near.initialized = false;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVhci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9uZWFyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7R0FFRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsMENBQTRCO0FBQzVCLGdFQUFxQztBQUNyQyw2Q0FBK0I7QUFDL0IscURBQXVDO0FBQ3ZDLG9EQUFzQztBQUV0QyxvREFBMEQ7QUFDMUQsOENBK0J5QjtBQUN6Qiw0Q0FBdUc7QUFFdkcsK0JBQTJHO0FBQzNHLHdEQUFvQztBQUNwQywrQ0FBZ0U7QUFzRWhFLE1BQWEsSUFBSyxTQUFRLG1CQUFRO0lBR2hDLFlBQVksS0FBZ0IsRUFBRSxXQUF1QztRQUNuRSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFVTCxZQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO1FBVG5FLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLG9EQUFvRCxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUVELElBQUksQ0FBQyxZQUFZLEdBQUcsV0FBVyxDQUFDO0lBQ2xDLENBQUM7SUFNRCxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQWdCLEVBQUUsV0FBdUM7UUFDN0UsT0FBTyxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELDJCQUEyQjtRQUN6QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7O09BR0c7SUFDSCxXQUFXO1FBQ1QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsb0JBQW9CO0lBQ3BCLHNCQUFzQjtRQUNwQixPQUFPLHdCQUFhLENBQUMsR0FBRyxDQUFDO0lBQzNCLENBQUM7SUFFRDs7T0FFRztJQUNILHdCQUF3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LENBQUMsQ0FBQztRQUN2RyxJQUFJLENBQUMsYUFBYSxJQUFJLGFBQWEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDakQsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFckMsS0FBSyxNQUFNLE1BQU0sSUFBSSxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekMsSUFBSSxNQUFNLENBQUMsT0FBTyxLQUFLLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDM0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpREFBaUQsQ0FBQyxDQUFDO1lBQ3JFLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQzs7QUFqOEJILG9CQWs4QkM7QUF0N0JrQixnQkFBVyxHQUFHLEtBQUssQUFBUixDQUFTIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAcHJldHRpZXJcbiAqL1xuXG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgQmlnTnVtYmVyIGZyb20gJ2JpZ251bWJlci5qcyc7XG5pbXBvcnQgKiBhcyBiYXNlNTggZnJvbSAnYnM1OCc7XG5pbXBvcnQgKiBhcyBuZWFyQVBJIGZyb20gJ25lYXItYXBpLWpzJztcbmltcG9ydCAqIGFzIHJlcXVlc3QgZnJvbSAnc3VwZXJhZ2VudCc7XG5cbmltcG9ydCB7IGF1ZGl0RWRkc2FQcml2YXRlS2V5IH0gZnJvbSAnQGJpdGdvL3Nkay1saWItbXBjJztcbmltcG9ydCB7XG4gIEF1ZGl0RGVjcnlwdGVkS2V5UGFyYW1zLFxuICBCYXNlQWRkcmVzcyxcbiAgQmFzZUNvaW4sXG4gIEJhc2VUcmFuc2FjdGlvbixcbiAgQml0R29CYXNlLFxuICBFZGRzYSxcbiAgRUREU0FNZXRob2RzLFxuICBFRERTQU1ldGhvZFR5cGVzLFxuICBFbnZpcm9ubWVudHMsXG4gIEtleVBhaXIsXG4gIE1ldGhvZE5vdEltcGxlbWVudGVkRXJyb3IsXG4gIE1QQ0FsZ29yaXRobSxcbiAgTVBDUmVjb3ZlcnlPcHRpb25zLFxuICBNUENTd2VlcFJlY292ZXJ5T3B0aW9ucyxcbiAgTVBDU3dlZXBUeHMsXG4gIE1QQ1R4LFxuICBNUENUeHMsXG4gIE1QQ1Vuc2lnbmVkVHgsXG4gIE11bHRpc2lnVHlwZSxcbiAgbXVsdGlzaWdUeXBlcyxcbiAgUGFyc2VkVHJhbnNhY3Rpb24sXG4gIFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIGFzIEJhc2VQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgUHVibGljS2V5LFxuICBSZWNvdmVyeVR4UmVxdWVzdCxcbiAgU2lnbmVkVHJhbnNhY3Rpb24sXG4gIFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMgYXMgQmFzZVNpZ25UcmFuc2FjdGlvbk9wdGlvbnMsXG4gIFRva2VuRW5hYmxlbWVudENvbmZpZyxcbiAgVHJhbnNhY3Rpb25FeHBsYW5hdGlvbixcbiAgVmVyaWZ5QWRkcmVzc09wdGlvbnMsXG4gIFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyxcbn0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IEJhc2VDb2luIGFzIFN0YXRpY3NCYXNlQ29pbiwgQ29pbkZhbWlseSwgY29pbnMsIE5lcDE0MVRva2VuLCBOZXR3b3JrcyB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcblxuaW1wb3J0IHsgS2V5UGFpciBhcyBOZWFyS2V5UGFpciwgVHJhbnNhY3Rpb24sIFRyYW5zYWN0aW9uQnVpbGRlciwgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeSB9IGZyb20gJy4vbGliJztcbmltcG9ydCBuZWFyVXRpbHMgZnJvbSAnLi9saWIvdXRpbHMnO1xuaW1wb3J0IHsgTUFYX0dBU19MSU1JVF9GT1JfRlRfVFJBTlNGRVIgfSBmcm9tICcuL2xpYi9jb25zdGFudHMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMgZXh0ZW5kcyBCYXNlU2lnblRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIHR4UHJlYnVpbGQ6IFRyYW5zYWN0aW9uUHJlYnVpbGQ7XG4gIHBydjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uUHJlYnVpbGQge1xuICB0eEhleDogc3RyaW5nO1xuICBrZXk6IHN0cmluZztcbiAgYmxvY2tIYXNoOiBzdHJpbmc7XG4gIG5vbmNlOiBiaWdpbnQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXhwbGFpblRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIHR4UHJlYnVpbGQ6IFRyYW5zYWN0aW9uUHJlYnVpbGQ7XG4gIHB1YmxpY0tleTogc3RyaW5nO1xuICBmZWVJbmZvOiB7XG4gICAgZmVlOiBzdHJpbmc7XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmVyaWZpZWRUcmFuc2FjdGlvblBhcmFtZXRlcnMge1xuICB0eEhleDogc3RyaW5nO1xuICBwcnY6IHN0cmluZztcbiAgc2lnbmVyOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmVhclBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgQmFzZVBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhQcmVidWlsZDogVHJhbnNhY3Rpb25QcmVidWlsZDtcbiAgcHVibGljS2V5OiBzdHJpbmc7XG4gIGZlZUluZm86IHtcbiAgICBmZWU6IHN0cmluZztcbiAgfTtcbn1cblxuaW50ZXJmYWNlIFRyYW5zYWN0aW9uT3V0cHV0IHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhbW91bnQ6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIE5lYXJUeEJ1aWxkZXJQYXJhbXNGcm9tTm9kZSB7XG4gIG5vbmNlOiBiaWdpbnQ7XG4gIGJsb2NrSGFzaDogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgTmVhckZlZUNvbmZpZyB7XG4gIHNlbmRTaXI6IG51bWJlcjtcbiAgc2VuZE5vdFNpcjogbnVtYmVyO1xuICBleGVjdXRpb246IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFByb3RvY29sQ29uZmlnT3V0cHV0IHtcbiAgc3RvcmFnZUFtb3VudFBlckJ5dGU6IG51bWJlcjtcbiAgdHJhbnNmZXJDb3N0OiBOZWFyRmVlQ29uZmlnO1xuICByZWNlaXB0Q29uZmlnOiBOZWFyRmVlQ29uZmlnO1xufVxuXG50eXBlIFRyYW5zYWN0aW9uSW5wdXQgPSBUcmFuc2FjdGlvbk91dHB1dDtcblxuZXhwb3J0IGludGVyZmFjZSBOZWFyUGFyc2VkVHJhbnNhY3Rpb24gZXh0ZW5kcyBQYXJzZWRUcmFuc2FjdGlvbiB7XG4gIC8vIHRvdGFsIGFzc2V0cyBiZWluZyBtb3ZlZCwgaW5jbHVkaW5nIGZlZXNcbiAgaW5wdXRzOiBUcmFuc2FjdGlvbklucHV0W107XG5cbiAgLy8gd2hlcmUgYXNzZXRzIGFyZSBtb3ZlZCB0b1xuICBvdXRwdXRzOiBUcmFuc2FjdGlvbk91dHB1dFtdO1xufVxuXG5leHBvcnQgdHlwZSBOZWFyVHJhbnNhY3Rpb25FeHBsYW5hdGlvbiA9IFRyYW5zYWN0aW9uRXhwbGFuYXRpb247XG5cbmV4cG9ydCBjbGFzcyBOZWFyIGV4dGVuZHMgQmFzZUNvaW4ge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgX3N0YXRpY3NDb2luOiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+O1xuXG4gIGNvbnN0cnVjdG9yKGJpdGdvOiBCaXRHb0Jhc2UsIHN0YXRpY3NDb2luPzogUmVhZG9ubHk8U3RhdGljc0Jhc2VDb2luPikge1xuICAgIHN1cGVyKGJpdGdvKTtcbiAgICBpZiAoIXN0YXRpY3NDb2luKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgY29uc3RydWN0b3IgcGFyYW1ldGVyIHN0YXRpY3NDb2luJyk7XG4gICAgfVxuXG4gICAgdGhpcy5fc3RhdGljc0NvaW4gPSBzdGF0aWNzQ29pbjtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGF0aWMgaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgcHJvdGVjdGVkIHN0YXRpYyBNUEM6IEVkZHNhO1xuICBwcm90ZWN0ZWQgbmV0d29yayA9IHRoaXMuYml0Z28uZ2V0RW52KCkgPT09ICdwcm9kJyA/ICdtYWluJyA6ICd0ZXN0JztcblxuICBzdGF0aWMgY3JlYXRlSW5zdGFuY2UoYml0Z286IEJpdEdvQmFzZSwgc3RhdGljc0NvaW4/OiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+KTogQmFzZUNvaW4ge1xuICAgIHJldHVybiBuZXcgTmVhcihiaXRnbywgc3RhdGljc0NvaW4pO1xuICB9XG5cbiAgYWxsb3dzQWNjb3VudENvbnNvbGlkYXRpb25zKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgaW5kaWNhdGluZyBpZiB0aGlzIGNvaW4gc3VwcG9ydHMgVFNTIHdhbGxldHMuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIFRTUyBXYWxsZXRzIGNhbiBiZSBjcmVhdGVkIGZvciB0aGlzIGNvaW5cbiAgICovXG4gIHN1cHBvcnRzVHNzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIGluaGVyaXRlZCBkb2MgKi9cbiAgZ2V0RGVmYXVsdE11bHRpc2lnVHlwZSgpOiBNdWx0aXNpZ1R5cGUge1xuICAgIHJldHVybiBtdWx0aXNpZ1R5cGVzLnRzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAaW5oZXJpdERvY1xuICAgKi9cbiAgZ2V0VG9rZW5FbmFibGVtZW50Q29uZmlnKCk6IFRva2VuRW5hYmxlbWVudENvbmZpZyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlcXVpcmVzVG9rZW5FbmFibGVtZW50OiB0cnVlLFxuICAgICAgc3VwcG9ydHNNdWx0aXBsZVRva2VuRW5hYmxlbWVudHM6IGZhbHNlLFxuICAgIH07XG4gIH1cblxuICBnZXRNUENBbGdvcml0aG0oKTogTVBDQWxnb3JpdGhtIHtcbiAgICByZXR1cm4gJ2VkZHNhJztcbiAgfVxuXG4gIGdldENoYWluKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YXRpY3NDb2luLm5hbWU7XG4gIH1cblxuICBnZXRCYXNlQ2hhaW4oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRDaGFpbigpO1xuICB9XG5cbiAgZ2V0RmFtaWx5KCk6IENvaW5GYW1pbHkge1xuICAgIHJldHVybiB0aGlzLl9zdGF0aWNzQ29pbi5mYW1pbHk7XG4gIH1cblxuICBnZXRGdWxsTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9zdGF0aWNzQ29pbi5mdWxsTmFtZTtcbiAgfVxuXG4gIGdldEJhc2VGYWN0b3IoKTogYW55IHtcbiAgICByZXR1cm4gTWF0aC5wb3coMTAsIHRoaXMuX3N0YXRpY3NDb2luLmRlY2ltYWxQbGFjZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgZm9yIHNlbmRpbmcgdmFsdWUgb2YgMFxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiBva2F5IHRvIHNlbmQgMCB2YWx1ZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICB2YWx1ZWxlc3NUcmFuc2ZlckFsbG93ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGVkMjU1MTkga2V5IHBhaXJcbiAgICpcbiAgICogQHBhcmFtIHNlZWRcbiAgICogQHJldHVybnMge09iamVjdH0gb2JqZWN0IHdpdGggZ2VuZXJhdGVkIHB1YiwgcHJ2XG4gICAqL1xuICBnZW5lcmF0ZUtleVBhaXIoc2VlZD86IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIGNvbnN0IGtleVBhaXIgPSBzZWVkID8gbmV3IE5lYXJLZXlQYWlyKHsgc2VlZCB9KSA6IG5ldyBOZWFyS2V5UGFpcigpO1xuICAgIGNvbnN0IGtleXMgPSBrZXlQYWlyLmdldEtleXMoKTtcbiAgICBpZiAoIWtleXMucHJ2KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgcHJ2IGluIGtleSBnZW5lcmF0aW9uLicpO1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgcHViOiBrZXlzLnB1YixcbiAgICAgIHBydjoga2V5cy5wcnYsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgaW5wdXQgaXMgdmFsaWQgcHVibGljIGtleSBmb3IgdGhlIGNvaW4uXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwdWIgdGhlIHB1YiB0byBiZSBjaGVja2VkXG4gICAqIEByZXR1cm5zIHtCb29sZWFufSBpcyBpdCB2YWxpZD9cbiAgICovXG4gIGlzVmFsaWRQdWIocHViOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gbmVhclV0aWxzLmlzVmFsaWRQdWJsaWNLZXkocHViKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIHN1cHBsaWVkIHByaXZhdGUga2V5IGlzIGEgdmFsaWQgbmVhciBwcml2YXRlIGtleVxuICAgKlxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHJ2IHRoZSBwcnYgdG8gYmUgY2hlY2tlZFxuICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gaXMgaXQgdmFsaWQ/XG4gICAqL1xuICBpc1ZhbGlkUHJ2KHBydjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG5lYXJVdGlscy5pc1ZhbGlkUHJpdmF0ZUtleShwcnYpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBpbnB1dCBpcyB2YWxpZCBwdWJsaWMga2V5IGZvciB0aGUgY29pblxuICAgKlxuICAgKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzcyB0aGUgcHViIHRvIGJlIGNoZWNrZWRcbiAgICogQHJldHVybnMge0Jvb2xlYW59IGlzIGl0IHZhbGlkP1xuICAgKi9cbiAgaXNWYWxpZEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG5lYXJVdGlscy5pc1ZhbGlkQWRkcmVzcyhhZGRyZXNzKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBhc3luYyBzaWduTWVzc2FnZShrZXk6IEtleVBhaXIsIG1lc3NhZ2U6IHN0cmluZyB8IEJ1ZmZlcik6IFByb21pc2U8QnVmZmVyPiB7XG4gICAgY29uc3QgbmVhcktleXBhaXIgPSBuZXcgTmVhcktleVBhaXIoeyBwcnY6IGtleS5wcnYgfSk7XG4gICAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihtZXNzYWdlKSkge1xuICAgICAgbWVzc2FnZSA9IGJhc2U1OC5lbmNvZGUobWVzc2FnZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKG5lYXJLZXlwYWlyLnNpZ25NZXNzYWdlKG1lc3NhZ2UpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBsYWluL3BhcnNlIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICovXG4gIGFzeW5jIGV4cGxhaW5UcmFuc2FjdGlvbihwYXJhbXM6IEV4cGxhaW5UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPE5lYXJUcmFuc2FjdGlvbkV4cGxhbmF0aW9uPiB7XG4gICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0QnVpbGRlcigpO1xuICAgIGxldCByZWJ1aWx0VHJhbnNhY3Rpb246IEJhc2VUcmFuc2FjdGlvbjtcbiAgICBjb25zdCB0eFJhdyA9IHBhcmFtcy50eFByZWJ1aWxkLnR4SGV4O1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uQnVpbGRlciA9IGZhY3RvcnkuZnJvbSh0eFJhdyk7XG4gICAgICByZWJ1aWx0VHJhbnNhY3Rpb24gPSBhd2FpdCB0cmFuc2FjdGlvbkJ1aWxkZXIuYnVpbGQoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB0cmFuc2FjdGlvbicpO1xuICAgIH1cblxuICAgIHJldHVybiByZWJ1aWx0VHJhbnNhY3Rpb24uZXhwbGFpblRyYW5zYWN0aW9uKCk7XG4gIH1cblxuICB2ZXJpZnlTaWduVHJhbnNhY3Rpb25QYXJhbXMocGFyYW1zOiBTaWduVHJhbnNhY3Rpb25PcHRpb25zKTogVmVyaWZpZWRUcmFuc2FjdGlvblBhcmFtZXRlcnMge1xuICAgIGNvbnN0IHBydiA9IHBhcmFtcy5wcnY7XG5cbiAgICBjb25zdCB0eEhleCA9IHBhcmFtcy50eFByZWJ1aWxkLnR4SGV4O1xuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQodHhIZXgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdHhQcmVidWlsZCBwYXJhbWV0ZXInKTtcbiAgICB9XG5cbiAgICBpZiAoIV8uaXNTdHJpbmcodHhIZXgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHR4UHJlYnVpbGQgbXVzdCBiZSBhbiBvYmplY3QsIGdvdCB0eXBlICR7dHlwZW9mIHR4SGV4fWApO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBydikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwcnYgcGFyYW1ldGVyIHRvIHNpZ24gdHJhbnNhY3Rpb24nKTtcbiAgICB9XG5cbiAgICBpZiAoIV8uaXNTdHJpbmcocHJ2KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBwcnYgbXVzdCBiZSBhIHN0cmluZywgZ290IHR5cGUgJHt0eXBlb2YgcHJ2fWApO1xuICAgIH1cblxuICAgIGlmICghXy5oYXMocGFyYW1zLnR4UHJlYnVpbGQsICdrZXknKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHB1YmxpYyBrZXkgcGFyYW1ldGVyIHRvIHNpZ24gdHJhbnNhY3Rpb24nKTtcbiAgICB9XG5cbiAgICAvLyBpZiB3ZSBhcmUgcmVjZWl2aW5nIGFkZHJlc3NlcyBkbyBub3QgdHJ5IHRvIGNvbnZlcnQgdGhlbVxuICAgIGNvbnN0IHNpZ25lciA9ICFuZWFyVXRpbHMuaXNWYWxpZEFkZHJlc3MocGFyYW1zLnR4UHJlYnVpbGQua2V5KVxuICAgICAgPyBuZXcgTmVhcktleVBhaXIoeyBwdWI6IHBhcmFtcy50eFByZWJ1aWxkLmtleSB9KS5nZXRBZGRyZXNzKClcbiAgICAgIDogcGFyYW1zLnR4UHJlYnVpbGQua2V5O1xuICAgIHJldHVybiB7IHR4SGV4LCBwcnYsIHNpZ25lciB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIGtleWNoYWluIGFuZCBoYWxmLXNpZ24gcHJlYnVpbHQgdHJhbnNhY3Rpb25cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKiBAcGFyYW0gcGFyYW1zLnR4UHJlYnVpbGQge1RyYW5zYWN0aW9uUHJlYnVpbGR9IHByZWJ1aWxkIG9iamVjdCByZXR1cm5lZCBieSBwbGF0Zm9ybVxuICAgKiBAcGFyYW0gcGFyYW1zLnBydiB7U3RyaW5nfSB1c2VyIHBydlxuICAgKiBAcGFyYW0gY2FsbGJhY2tcbiAgICogQHJldHVybnMge0JsdWViaXJkPFNpZ25lZFRyYW5zYWN0aW9uPn1cbiAgICovXG4gIGFzeW5jIHNpZ25UcmFuc2FjdGlvbihwYXJhbXM6IFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPFNpZ25lZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0QnVpbGRlcigpO1xuICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZnJvbShwYXJhbXMudHhQcmVidWlsZC50eEhleCk7XG4gICAgdHhCdWlsZGVyLnNpZ24oeyBrZXk6IHBhcmFtcy5wcnYgfSk7XG4gICAgY29uc3QgdHJhbnNhY3Rpb246IEJhc2VUcmFuc2FjdGlvbiA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgaWYgKCF0cmFuc2FjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2VyaWFsaXplZFR4ID0gKHRyYW5zYWN0aW9uIGFzIEJhc2VUcmFuc2FjdGlvbikudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgIHJldHVybiB7XG4gICAgICB0eEhleDogc2VyaWFsaXplZFR4LFxuICAgIH0gYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIGZ1bmRzIHJlY292ZXJ5IHRyYW5zYWN0aW9uIHdpdGhvdXQgQml0R29cbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgcmVjb3ZlcihwYXJhbXM6IE1QQ1JlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8TVBDVHggfCBNUENTd2VlcFR4cz4ge1xuICAgIGlmICghcGFyYW1zLmJpdGdvS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgYml0Z29LZXknKTtcbiAgICB9XG4gICAgaWYgKCFwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbiB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCByZWNvdmVyeURlc3RpbmF0aW9uJyk7XG4gICAgfVxuICAgIGxldCBzdGFydElkeCA9IHBhcmFtcy5zdGFydGluZ1NjYW5JbmRleDtcbiAgICBpZiAoc3RhcnRJZHggPT09IHVuZGVmaW5lZCkge1xuICAgICAgc3RhcnRJZHggPSAwO1xuICAgIH0gZWxzZSBpZiAoIU51bWJlci5pc0ludGVnZXIoc3RhcnRJZHgpIHx8IHN0YXJ0SWR4IDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHN0YXJ0aW5nIGluZGV4IHRvIHNjYW4gZm9yIGFkZHJlc3NlcycpO1xuICAgIH1cbiAgICBsZXQgbnVtSXRlcmF0aW9uID0gcGFyYW1zLnNjYW47XG4gICAgaWYgKG51bUl0ZXJhdGlvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBudW1JdGVyYXRpb24gPSAyMDtcbiAgICB9IGVsc2UgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKG51bUl0ZXJhdGlvbikgfHwgbnVtSXRlcmF0aW9uIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzY2FubmluZyBmYWN0b3InKTtcbiAgICB9XG4gICAgY29uc3QgYml0Z29LZXkgPSBwYXJhbXMuYml0Z29LZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBpc1Vuc2lnbmVkU3dlZXAgPSAhcGFyYW1zLnVzZXJLZXkgJiYgIXBhcmFtcy5iYWNrdXBLZXkgJiYgIXBhcmFtcy53YWxsZXRQYXNzcGhyYXNlO1xuICAgIGNvbnN0IE1QQyA9IGF3YWl0IEVERFNBTWV0aG9kcy5nZXRJbml0aWFsaXplZE1wY0luc3RhbmNlKCk7XG4gICAgY29uc3QgeyBzdG9yYWdlQW1vdW50UGVyQnl0ZSwgdHJhbnNmZXJDb3N0LCByZWNlaXB0Q29uZmlnIH0gPSBhd2FpdCB0aGlzLmdldFByb3RvY29sQ29uZmlnKCk7XG4gICAgbGV0IGlzU3RvcmFnZURlcG9zaXRFbmFibGVkID0gZmFsc2U7XG5cbiAgICBpZiAocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKSB7XG4gICAgICAvLyBjaGVjayBpZiByZWNlaXZlciBzdG9yYWdlIGRlcG9zaXQgaXMgZW5hYmxlZFxuICAgICAgaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQgPSBhd2FpdCB0aGlzLmNoZWNrSWZTdG9yYWdlRGVwb3NpdElzRW5hYmxlZChcbiAgICAgICAgcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24sXG4gICAgICAgIHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzc1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBmb3IgKGxldCBpID0gc3RhcnRJZHg7IGkgPCBudW1JdGVyYXRpb24gKyBzdGFydElkeDsgaSsrKSB7XG4gICAgICBjb25zdCBjdXJyUGF0aCA9IGBtLyR7aX1gO1xuICAgICAgY29uc3QgYWNjb3VudElkID0gTVBDLmRlcml2ZVVuaGFyZGVuZWQoYml0Z29LZXksIGN1cnJQYXRoKS5zbGljZSgwLCA2NCk7XG4gICAgICBsZXQgYXZhaWxhYmxlQmFsYW5jZSA9IG5ldyBCaWdOdW1iZXIoMCk7XG4gICAgICB0cnkge1xuICAgICAgICBhdmFpbGFibGVCYWxhbmNlID0gbmV3IEJpZ051bWJlcihhd2FpdCB0aGlzLmdldEFjY291bnRCYWxhbmNlKGFjY291bnRJZCwgc3RvcmFnZUFtb3VudFBlckJ5dGUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgLy8gVU5LTk9XTl9BQ0NPVU5UIGVycm9yIGluZGljYXRlcyB0aGF0IHRoZSBhZGRyZXNzIGhhcyBub3QgcGFydGFrZSBpbiBhbnkgdHJhbnNhY3Rpb24gc28gZmFyLCBzbyB3ZSB3aWxsXG4gICAgICAgIC8vIHRyZWF0IGl0IGFzIGEgemVybyBiYWxhbmNlIGFkZHJlc3NcbiAgICAgICAgaWYgKGUubWVzc2FnZSAhPT0gJ1VOS05PV05fQUNDT1VOVCcpIHtcbiAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoYXZhaWxhYmxlQmFsYW5jZS50b051bWJlcigpIDw9IDApIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBmZWVSZXNlcnZlID0gQmlnTnVtYmVyKE5ldHdvcmtzW3RoaXMubmV0d29ya10ubmVhci5mZWVSZXNlcnZlKTtcbiAgICAgIGNvbnN0IHN0b3JhZ2VSZXNlcnZlID0gQmlnTnVtYmVyKE5ldHdvcmtzW3RoaXMubmV0d29ya10ubmVhci5zdG9yYWdlUmVzZXJ2ZSk7XG5cbiAgICAgIC8vIGNoZWNrIGZvciBwb3NzaWJsZSB0b2tlbiByZWNvdmVyeSwgcmVjb3ZlciB0aGUgdG9rZW4gcHJvdmlkZWQgYnkgdGhlIHVzZXJcbiAgICAgIGlmIChwYXJhbXMudG9rZW5Db250cmFjdEFkZHJlc3MpIHtcbiAgICAgICAgY29uc3QgdG9rZW5OYW1lID0gbmVhclV0aWxzLmZpbmRUb2tlbk5hbWVGcm9tQ29udHJhY3RBZGRyZXNzKHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcyk7XG4gICAgICAgIGlmICghdG9rZW5OYW1lKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYFRva2VuIG5hbWUgbm90IGZvdW5kIGZvciBjb250cmFjdCBhZGRyZXNzICR7cGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzfS4gVGhlIGFkZHJlc3MgbWF5IGJlIGludmFsaWQgb3IgdW5zdXBwb3J0ZWQuIFBsZWFzZSByZWZlciB0byB0aGUgc3VwcG9ydGVkIHRva2VucyBpbiB0aGUgQml0R28gZG9jdW1lbnRhdGlvbiBmb3IgZ3VpZGFuY2UuYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdG9rZW4gPSBuZWFyVXRpbHMuZ2V0VG9rZW5JbnN0YW5jZUZyb21Ub2tlbk5hbWUodG9rZW5OYW1lKTtcbiAgICAgICAgaWYgKCF0b2tlbikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBUb2tlbiBpbnN0YW5jZSBjb3VsZCBub3QgYmUgY3JlYXRlZCBmb3IgdG9rZW4gbmFtZSAke3Rva2VuTmFtZX0uIFRoZSB0b2tlbiBtYXkgYmUgaW52YWxpZCBvciB1bnN1cHBvcnRlZC4gUGxlYXNlIHJlZmVyIHRvIHRoZSBzdXBwb3J0ZWQgdG9rZW5zIGluIHRoZSBCaXRHbyBkb2N1bWVudGF0aW9uIGZvciBndWlkYW5jZS5gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgYXZhaWxhYmxlVG9rZW5CYWxhbmNlOiBCaWdOdW1iZXI7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXZhaWxhYmxlVG9rZW5CYWxhbmNlID0gbmV3IEJpZ051bWJlcihcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZ2V0QWNjb3VudEZ1bmdpYmxlVG9rZW5CYWxhbmNlKGFjY291bnRJZCwgcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKVxuICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChhdmFpbGFibGVUb2tlbkJhbGFuY2UudG9OdW1iZXIoKSA8PSAwKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbmV0QW1vdW50ID0gYXZhaWxhYmxlQmFsYW5jZVxuICAgICAgICAgIC5taW51cyhuZWFyVXRpbHMuY29udmVydEdhc1VuaXRzVG9Zb2N0b05lYXIoTUFYX0dBU19MSU1JVF9GT1JfRlRfVFJBTlNGRVIpKVxuICAgICAgICAgIC5taW51cyhmZWVSZXNlcnZlKVxuICAgICAgICAgIC5taW51cyhzdG9yYWdlUmVzZXJ2ZSk7XG4gICAgICAgIGlmIChuZXRBbW91bnQudG9OdW1iZXIoKSA8PSAwKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEZvdW5kIGFkZHJlc3MgJHtpfSB3aXRoIG5vbi16ZXJvIGZ1bmQgYnV0IGZ1bmQgaXMgaW5zdWZmaWNpZW50IHRvIHN1cHBvcnQgYSB0b2tlbiByZWNvdmVyIGAgK1xuICAgICAgICAgICAgICBgdHJhbnNhY3Rpb24uIFBsZWFzZSBzdGFydCB0aGUgbmV4dCBzY2FuIGF0IGFkZHJlc3MgaW5kZXggJHtpICsgMX0uYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMucmVjb3Zlck5lYXJUb2tlbihcbiAgICAgICAgICBwYXJhbXMsXG4gICAgICAgICAgdG9rZW4sXG4gICAgICAgICAgYWNjb3VudElkLFxuICAgICAgICAgIGN1cnJQYXRoLFxuICAgICAgICAgIGksXG4gICAgICAgICAgYml0Z29LZXksXG4gICAgICAgICAgaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQsXG4gICAgICAgICAgYXZhaWxhYmxlVG9rZW5CYWxhbmNlLFxuICAgICAgICAgIGlzVW5zaWduZWRTd2VlcFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBmaXJzdCBidWlsZCB0aGUgdW5zaWduZWQgdHhuXG4gICAgICBjb25zdCBiczU4RW5jb2RlZFB1YmxpY0tleSA9IG5lYXJBUEkudXRpbHMuc2VyaWFsaXplLmJhc2VfZW5jb2RlKG5ldyBVaW50OEFycmF5KEJ1ZmZlci5mcm9tKGFjY291bnRJZCwgJ2hleCcpKSk7XG4gICAgICBjb25zdCB7IG5vbmNlLCBibG9ja0hhc2ggfSA9IGF3YWl0IHRoaXMuZ2V0QWNjZXNzS2V5KHsgYWNjb3VudElkLCBiczU4RW5jb2RlZFB1YmxpY0tleSB9KTtcbiAgICAgIGNvbnN0IGdhc1ByaWNlID0gYXdhaXQgdGhpcy5nZXRHYXNQcmljZShibG9ja0hhc2gpO1xuICAgICAgY29uc3QgZ2FzUHJpY2VGaXJzdEJsb2NrID0gbmV3IEJpZ051bWJlcihnYXNQcmljZSk7XG4gICAgICBjb25zdCBnYXNQcmljZVNlY29uZEJsb2NrID0gZ2FzUHJpY2VGaXJzdEJsb2NrLm11bHRpcGxpZWRCeSgxLjA1KTtcbiAgICAgIGNvbnN0IHRvdGFsR2FzUmVxdWlyZWQgPSBuZXcgQmlnTnVtYmVyKHRyYW5zZmVyQ29zdC5zZW5kU2lyKVxuICAgICAgICAucGx1cyhyZWNlaXB0Q29uZmlnLnNlbmRTaXIpXG4gICAgICAgIC5tdWx0aXBsaWVkQnkoZ2FzUHJpY2VGaXJzdEJsb2NrKVxuICAgICAgICAucGx1cyhuZXcgQmlnTnVtYmVyKHRyYW5zZmVyQ29zdC5leGVjdXRpb24pLnBsdXMocmVjZWlwdENvbmZpZy5leGVjdXRpb24pLm11bHRpcGxpZWRCeShnYXNQcmljZVNlY29uZEJsb2NrKSk7XG4gICAgICAvLyBhZGRpbmcgc29tZSBwYWRkaW5nIHRvIG1ha2Ugc3VyZSB0aGUgZ2FzIGRvZXNuJ3QgZ28gYmVsb3cgcmVxdWlyZWQgZ2FzIGJ5IG5ldHdvcmtcbiAgICAgIGNvbnN0IHRvdGFsR2FzV2l0aFBhZGRpbmcgPSB0b3RhbEdhc1JlcXVpcmVkLm11bHRpcGxpZWRCeSgxLjUpO1xuICAgICAgY29uc3QgbmV0QW1vdW50ID0gYXZhaWxhYmxlQmFsYW5jZS5taW51cyh0b3RhbEdhc1dpdGhQYWRkaW5nKS5taW51cyhmZWVSZXNlcnZlKS5taW51cyhzdG9yYWdlUmVzZXJ2ZSk7XG4gICAgICBpZiAobmV0QW1vdW50LnRvTnVtYmVyKCkgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYEZvdW5kIGFkZHJlc3MgJHtpfSB3aXRoIG5vbi16ZXJvIGZ1bmQgYnV0IGZ1bmQgaXMgaW5zdWZmaWNpZW50IHRvIHN1cHBvcnQgYSByZWNvdmVyIGAgK1xuICAgICAgICAgICAgYHRyYW5zYWN0aW9uLiBQbGVhc2Ugc3RhcnQgdGhlIG5leHQgc2NhbiBhdCBhZGRyZXNzIGluZGV4ICR7aSArIDF9LmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGZhY3RvcnkgPSBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQodGhpcy5nZXRDaGFpbigpKSk7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5XG4gICAgICAgIC5nZXRUcmFuc2ZlckJ1aWxkZXIoKVxuICAgICAgICAuc2VuZGVyKGFjY291bnRJZCwgYWNjb3VudElkKVxuICAgICAgICAubm9uY2Uobm9uY2UpXG4gICAgICAgIC5yZWNlaXZlcklkKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKVxuICAgICAgICAucmVjZW50QmxvY2tIYXNoKGJsb2NrSGFzaClcbiAgICAgICAgLmFtb3VudChuZXRBbW91bnQudG9GaXhlZCgpKTtcbiAgICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkpIGFzIFRyYW5zYWN0aW9uO1xuICAgICAgbGV0IHNlcmlhbGl6ZWRUeCA9IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgICAgIGlmICghaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICAgIHNlcmlhbGl6ZWRUeCA9IGF3YWl0IHRoaXMuc2lnblJlY292ZXJ5VHJhbnNhY3Rpb24odHhCdWlsZGVyLCBwYXJhbXMsIGN1cnJQYXRoLCBhY2NvdW50SWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVpbGRVbnNpZ25lZFN3ZWVwVHJhbnNhY3Rpb24oXG4gICAgICAgICAgdHhCdWlsZGVyLFxuICAgICAgICAgIGFjY291bnRJZCxcbiAgICAgICAgICBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgICAgICBiaXRnb0tleSxcbiAgICAgICAgICBpLFxuICAgICAgICAgIGN1cnJQYXRoLFxuICAgICAgICAgIG5ldEFtb3VudCxcbiAgICAgICAgICB0b3RhbEdhc1dpdGhQYWRkaW5nXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm4geyBzZXJpYWxpemVkVHg6IHNlcmlhbGl6ZWRUeCwgc2NhbkluZGV4OiBpIH07XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignRGlkIG5vdCBmaW5kIGFuIGFkZHJlc3Mgd2l0aCBmdW5kcyB0byByZWNvdmVyJyk7XG4gIH1cblxuICAvKipcbiAgICogRnVuY3Rpb24gdG8gaGFuZGxlIG5lYXIgdG9rZW4gcmVjb3ZlcnlcbiAgICogQHBhcmFtIHtNUENSZWNvdmVyeU9wdGlvbnN9IHBhcmFtcyBtcGMgcmVjb3Zlcnkgb3B0aW9ucyBpbnB1dFxuICAgKiBAcGFyYW0ge05lcDE0MVRva2VufSB0b2tlbiB0aGUgdG9rZW4gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzZW5kZXJBZGRyZXNzIHNlbmRlciBhZGRyZXNzXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkZXJpdmF0aW9uUGF0aCB0aGUgZGVyaXZhdGlvbiBwYXRoXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBpZHggY3VycmVudCBpbmRleFxuICAgKiBAcGFyYW0ge1N0cmluZ30gYml0Z29LZXkgYml0Z28ga2V5XG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgc3RvcmFnZSBkZXBvc2l0IGlzIGVuYWJsZWQgb24gdGhlIHJlY2VpdmVyXG4gICAqIEBwYXJhbSB7QmlnTnVtYmVyfSBhdmFpbGFibGVUb2tlbkJhbGFuY2UgY3VycmVudGx5IGF2YWlsYWJsZSB0b2tlbiBiYWxhbmNlIG9uIHRoZSBhZGRyZXNzXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNVbnNpZ25lZFN3ZWVwIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGl0IGlzIGFuIHVuc2lnbmVkIHN3ZWVwXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1QQ1R4IHwgTVBDU3dlZXBUeHM+fVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZWNvdmVyTmVhclRva2VuKFxuICAgIHBhcmFtczogTVBDUmVjb3ZlcnlPcHRpb25zLFxuICAgIHRva2VuOiBOZXAxNDFUb2tlbixcbiAgICBzZW5kZXJBZGRyZXNzOiBzdHJpbmcsXG4gICAgZGVyaXZhdGlvblBhdGg6IHN0cmluZyxcbiAgICBpZHg6IG51bWJlcixcbiAgICBiaXRnb0tleTogc3RyaW5nLFxuICAgIGlzU3RvcmFnZURlcG9zaXRFbmFibGVkOiBib29sZWFuLFxuICAgIGF2YWlsYWJsZVRva2VuQmFsYW5jZTogQmlnTnVtYmVyLFxuICAgIGlzVW5zaWduZWRTd2VlcDogYm9vbGVhblxuICApOiBQcm9taXNlPE1QQ1R4IHwgTVBDU3dlZXBUeHM+IHtcbiAgICBjb25zdCBmYWN0b3J5ID0gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkodG9rZW4pO1xuICAgIGNvbnN0IGJzNThFbmNvZGVkUHVibGljS2V5ID0gbmVhckFQSS51dGlscy5zZXJpYWxpemUuYmFzZV9lbmNvZGUobmV3IFVpbnQ4QXJyYXkoQnVmZmVyLmZyb20oc2VuZGVyQWRkcmVzcywgJ2hleCcpKSk7XG4gICAgY29uc3QgeyBub25jZSwgYmxvY2tIYXNoIH0gPSBhd2FpdCB0aGlzLmdldEFjY2Vzc0tleSh7IGFjY291bnRJZDogc2VuZGVyQWRkcmVzcywgYnM1OEVuY29kZWRQdWJsaWNLZXkgfSk7XG4gICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeVxuICAgICAgLmdldEZ1bmdpYmxlVG9rZW5UcmFuc2ZlckJ1aWxkZXIoKVxuICAgICAgLnNlbmRlcihzZW5kZXJBZGRyZXNzLCBzZW5kZXJBZGRyZXNzKVxuICAgICAgLm5vbmNlKG5vbmNlKVxuICAgICAgLnJlY2VpdmVySWQodG9rZW4uY29udHJhY3RBZGRyZXNzKVxuICAgICAgLnJlY2VudEJsb2NrSGFzaChibG9ja0hhc2gpXG4gICAgICAuZnRSZWNlaXZlcklkKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKVxuICAgICAgLmdhcyhNQVhfR0FTX0xJTUlUX0ZPUl9GVF9UUkFOU0ZFUilcbiAgICAgIC5kZXBvc2l0KCcxJylcbiAgICAgIC5hbW91bnQoYXZhaWxhYmxlVG9rZW5CYWxhbmNlLnRvU3RyaW5nKCkpO1xuICAgIGlmICghaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQpIHtcbiAgICAgIHR4QnVpbGRlci5hZGRTdG9yYWdlRGVwb3NpdCh7XG4gICAgICAgIGRlcG9zaXQ6IEJpZ0ludCh0b2tlbi5zdG9yYWdlRGVwb3NpdEFtb3VudCksXG4gICAgICAgIGdhczogQmlnSW50KE1BWF9HQVNfTElNSVRfRk9SX0ZUX1RSQU5TRkVSKSxcbiAgICAgICAgYWNjb3VudElkOiBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgIH0pO1xuICAgIH1cbiAgICBpZiAoaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICByZXR1cm4gdGhpcy5idWlsZFVuc2lnbmVkU3dlZXBUcmFuc2FjdGlvbihcbiAgICAgICAgdHhCdWlsZGVyLFxuICAgICAgICBzZW5kZXJBZGRyZXNzLFxuICAgICAgICBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgICAgYml0Z29LZXksXG4gICAgICAgIGlkeCxcbiAgICAgICAgZGVyaXZhdGlvblBhdGgsXG4gICAgICAgIGF2YWlsYWJsZVRva2VuQmFsYW5jZSxcbiAgICAgICAgbmV3IEJpZ051bWJlcihuZWFyVXRpbHMuY29udmVydEdhc1VuaXRzVG9Zb2N0b05lYXIoTUFYX0dBU19MSU1JVF9GT1JfRlRfVFJBTlNGRVIpKSxcbiAgICAgICAgdG9rZW5cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHNlcmlhbGl6ZWRUeCA9IGF3YWl0IHRoaXMuc2lnblJlY292ZXJ5VHJhbnNhY3Rpb24odHhCdWlsZGVyLCBwYXJhbXMsIGRlcml2YXRpb25QYXRoLCBzZW5kZXJBZGRyZXNzKTtcbiAgICAgIHJldHVybiB7IHNlcmlhbGl6ZWRUeDogc2VyaWFsaXplZFR4LCBzY2FuSW5kZXg6IGlkeCB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB0byBidWlsZCB1bnNpZ25lZCBzd2VlcCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uQnVpbGRlcn0gdHhCdWlsZGVyIHRoZSBuZWFyIHRyYW5zYWN0aW9uIGJ1aWxkZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IHNlbmRlckFkZHJlc3Mgc2VuZGVyIGFkZHJlc3NcbiAgICogQHBhcmFtIHtTdHJpbmd9IHJlY2VpdmVyQWRkcmVzcyB0aGUgcmVjZWl2ZXIgYWRkcmVzc1xuICAgKiBAcGFyYW0ge1N0cmluZ30gYml0Z29LZXkgYml0Z28ga2V5XG4gICAqIEBwYXJhbSB7TnVtYmVyfSBpbmRleCBjdXJyZW50IGluZGV4XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkZXJpdmF0aW9uUGF0aCB0aGUgZGVyaXZhdGlvbiBwYXRoXG4gICAqIEBwYXJhbSB7QmlnTnVtYmVyfSBuZXRBbW91bnQgbmV0IGFtb3VudCB0byBiZSByZWNvdmVyZWRcbiAgICogQHBhcmFtIHtCaWdOdW1iZXJ9IG5ldEdhcyBuZXQgZ2FzIHJlcXVpcmVkXG4gICAqIEBwYXJhbSB7TmVwMTQxVG9rZW59IHRva2VuIG9wdGlvbmFsIG5lcDE0MSB0b2tlbiBpbnN0YW5jZVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNUENTd2VlcFR4cz59XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGJ1aWxkVW5zaWduZWRTd2VlcFRyYW5zYWN0aW9uKFxuICAgIHR4QnVpbGRlcjogVHJhbnNhY3Rpb25CdWlsZGVyLFxuICAgIHNlbmRlckFkZHJlc3M6IHN0cmluZyxcbiAgICByZWNlaXZlckFkZHJlc3M6IHN0cmluZyxcbiAgICBiaXRnb0tleTogc3RyaW5nLFxuICAgIGluZGV4OiBudW1iZXIsXG4gICAgZGVyaXZhdGlvblBhdGg6IHN0cmluZyxcbiAgICBuZXRBbW91bnQ6IEJpZ051bWJlcixcbiAgICBuZXRHYXM6IEJpZ051bWJlcixcbiAgICB0b2tlbj86IE5lcDE0MVRva2VuXG4gICk6IFByb21pc2U8TVBDU3dlZXBUeHM+IHtcbiAgICBjb25zdCBpc1Rva2VuVHJhbnNhY3Rpb24gPSAhIXRva2VuO1xuICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkpIGFzIFRyYW5zYWN0aW9uO1xuICAgIGNvbnN0IHNlcmlhbGl6ZWRUeCA9IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgICBjb25zdCB3YWxsZXRDb2luID0gaXNUb2tlblRyYW5zYWN0aW9uID8gdG9rZW4ubmFtZSA6IHRoaXMuZ2V0Q2hhaW4oKTtcbiAgICBjb25zdCBpbnB1dHMgPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHNlbmRlckFkZHJlc3MsXG4gICAgICAgIHZhbHVlU3RyaW5nOiBuZXRBbW91bnQudG9TdHJpbmcoKSxcbiAgICAgICAgdmFsdWU6IG5ldEFtb3VudC50b051bWJlcigpLFxuICAgICAgfSxcbiAgICBdO1xuICAgIGNvbnN0IG91dHB1dHMgPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgICAgdmFsdWVTdHJpbmc6IG5ldEFtb3VudC50b1N0cmluZygpLFxuICAgICAgICBjb2luTmFtZTogd2FsbGV0Q29pbixcbiAgICAgIH0sXG4gICAgXTtcbiAgICBjb25zdCBzcGVuZEFtb3VudCA9IG5ldEFtb3VudC50b1N0cmluZygpO1xuICAgIGNvbnN0IHBhcnNlZFR4ID0geyBpbnB1dHM6IGlucHV0cywgb3V0cHV0czogb3V0cHV0cywgc3BlbmRBbW91bnQ6IHNwZW5kQW1vdW50LCB0eXBlOiAnJyB9O1xuICAgIGNvbnN0IGZlZUluZm8gPSB7IGZlZTogbmV0R2FzLnRvTnVtYmVyKCksIGZlZVN0cmluZzogbmV0R2FzLnRvRml4ZWQoKSB9OyAvLyBJbmNsdWRlIGdhcyBmZWVzXG5cbiAgICBjb25zdCB0cmFuc2FjdGlvbjogTVBDVHggPSB7XG4gICAgICBzZXJpYWxpemVkVHg6IHNlcmlhbGl6ZWRUeCwgLy8gU2VyaWFsaXplZCB1bnNpZ25lZCB0cmFuc2FjdGlvblxuICAgICAgc2NhbkluZGV4OiBpbmRleCwgLy8gQ3VycmVudCBpbmRleCBpbiB0aGUgc2NhblxuICAgICAgY29pbjogd2FsbGV0Q29pbixcbiAgICAgIHNpZ25hYmxlSGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnNpZ25hYmxlUGF5bG9hZC50b1N0cmluZygnaGV4JyksIC8vIEhleCBwYXlsb2FkIGZvciBzaWduaW5nXG4gICAgICBkZXJpdmF0aW9uUGF0aDogZGVyaXZhdGlvblBhdGgsIC8vIERlcml2YXRpb24gcGF0aCBmb3IgdGhlIGFjY291bnRcbiAgICAgIHBhcnNlZFR4OiBwYXJzZWRUeCxcbiAgICAgIGZlZUluZm86IGZlZUluZm8sXG4gICAgICBjb2luU3BlY2lmaWM6IHsgY29tbW9uS2V5Y2hhaW46IGJpdGdvS2V5IH0sIC8vIEluY2x1ZGUgYmxvY2sgaGFzaCBmb3IgTkVBUlxuICAgIH07XG5cbiAgICBjb25zdCB0cmFuc2FjdGlvbnM6IE1QQ1Vuc2lnbmVkVHhbXSA9IFt7IHVuc2lnbmVkVHg6IHRyYW5zYWN0aW9uLCBzaWduYXR1cmVTaGFyZXM6IFtdIH1dO1xuICAgIGNvbnN0IHR4UmVxdWVzdDogUmVjb3ZlcnlUeFJlcXVlc3QgPSB7XG4gICAgICB0cmFuc2FjdGlvbnM6IHRyYW5zYWN0aW9ucyxcbiAgICAgIHdhbGxldENvaW46IHdhbGxldENvaW4sXG4gICAgfTtcbiAgICByZXR1cm4geyB0eFJlcXVlc3RzOiBbdHhSZXF1ZXN0XSB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEZ1bmN0aW9uIHRvIHNpZ24gdGhlIHJlY292ZXJ5IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb25CdWlsZGVyfSB0eEJ1aWxkZXIgdGhlIG5lYXIgdHJhbnNhY3Rpb24gYnVpbGRlclxuICAgKiBAcGFyYW0ge01QQ1JlY292ZXJ5T3B0aW9uc30gcGFyYW1zIG1wYyByZWNvdmVyeSBvcHRpb25zIGlucHV0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkZXJpdmF0aW9uUGF0aCB0aGUgZGVyaXZhdGlvbiBwYXRoXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzZW5kZXJBZGRyZXNzIHRoZSBzZW5kZXIgYWRkcmVzc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTdHJpbmc+fVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzaWduUmVjb3ZlcnlUcmFuc2FjdGlvbihcbiAgICB0eEJ1aWxkZXI6IFRyYW5zYWN0aW9uQnVpbGRlcixcbiAgICBwYXJhbXM6IE1QQ1JlY292ZXJ5T3B0aW9ucyxcbiAgICBkZXJpdmF0aW9uUGF0aDogc3RyaW5nLFxuICAgIHNlbmRlckFkZHJlc3M6IHN0cmluZ1xuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkpIGFzIFRyYW5zYWN0aW9uO1xuICAgIC8vIFNpZ24gdGhlIHR4blxuICAgIC8qICoqKioqKioqKioqKioqKioqIFNUQVJUICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuICAgIC8vIFRPRE8oQkctNTEwOTIpOiBUaGlzIGxvb2tzIGxpa2UgYSBjb21tb24gcGFydCB3aGljaCBjYW4gYmUgZXh0cmFjdGVkIG91dCB0b29cbiAgICBpZiAoIXBhcmFtcy51c2VyS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdXNlcktleScpO1xuICAgIH1cbiAgICBpZiAoIXBhcmFtcy5iYWNrdXBLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBiYWNrdXBLZXknKTtcbiAgICB9XG4gICAgaWYgKCFwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHdhbGxldCBwYXNzcGhyYXNlJyk7XG4gICAgfVxuXG4gICAgLy8gQ2xlYW4gdXAgd2hpdGVzcGFjZSBmcm9tIGVudGVyZWQgdmFsdWVzXG4gICAgY29uc3QgdXNlcktleSA9IHBhcmFtcy51c2VyS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgY29uc3QgYmFja3VwS2V5ID0gcGFyYW1zLmJhY2t1cEtleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuXG4gICAgLy8gRGVjcnlwdCBwcml2YXRlIGtleXMgZnJvbSBLZXlDYXJkIHZhbHVlc1xuICAgIGxldCB1c2VyUHJ2O1xuICAgIHRyeSB7XG4gICAgICB1c2VyUHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgaW5wdXQ6IHVzZXJLZXksXG4gICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyB1c2VyIGtleWNoYWluOiAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gICAgLyoqIFRPRE8gQkctNTI0MTkgSW1wbGVtZW50IENvZGVjIGZvciBwYXJzaW5nICovXG4gICAgY29uc3QgdXNlclNpZ25pbmdNYXRlcmlhbCA9IEpTT04ucGFyc2UodXNlclBydikgYXMgRUREU0FNZXRob2RUeXBlcy5Vc2VyU2lnbmluZ01hdGVyaWFsO1xuXG4gICAgbGV0IGJhY2t1cFBydjtcbiAgICB0cnkge1xuICAgICAgYmFja3VwUHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgaW5wdXQ6IGJhY2t1cEtleSxcbiAgICAgICAgcGFzc3dvcmQ6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBkZWNyeXB0aW5nIGJhY2t1cCBrZXljaGFpbjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgfVxuICAgIGNvbnN0IGJhY2t1cFNpZ25pbmdNYXRlcmlhbCA9IEpTT04ucGFyc2UoYmFja3VwUHJ2KSBhcyBFRERTQU1ldGhvZFR5cGVzLkJhY2t1cFNpZ25pbmdNYXRlcmlhbDtcbiAgICAvKiAqKioqKioqKioqKioqKioqKioqKioqIEVORCAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAgIC8vIGFkZCBzaWduYXR1cmVcbiAgICBjb25zdCBzaWduYXR1cmVIZXggPSBhd2FpdCBFRERTQU1ldGhvZHMuZ2V0VFNTU2lnbmF0dXJlKFxuICAgICAgdXNlclNpZ25pbmdNYXRlcmlhbCxcbiAgICAgIGJhY2t1cFNpZ25pbmdNYXRlcmlhbCxcbiAgICAgIGRlcml2YXRpb25QYXRoLFxuICAgICAgdW5zaWduZWRUcmFuc2FjdGlvblxuICAgICk7XG4gICAgY29uc3QgcHVibGljS2V5T2JqID0geyBwdWI6IHNlbmRlckFkZHJlc3MgfTtcbiAgICB0eEJ1aWxkZXIuYWRkU2lnbmF0dXJlKHB1YmxpY0tleU9iaiBhcyBQdWJsaWNLZXksIHNpZ25hdHVyZUhleCk7XG5cbiAgICBjb25zdCBjb21wbGV0ZWRUcmFuc2FjdGlvbiA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIHJldHVybiBjb21wbGV0ZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlQnJvYWRjYXN0YWJsZVN3ZWVwVHJhbnNhY3Rpb24ocGFyYW1zOiBNUENTd2VlcFJlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8TVBDVHhzPiB7XG4gICAgY29uc3QgcmVxID0gcGFyYW1zLnNpZ25hdHVyZVNoYXJlcztcbiAgICBjb25zdCBicm9hZGNhc3RhYmxlVHJhbnNhY3Rpb25zOiBNUENUeFtdID0gW107XG4gICAgbGV0IGxhc3RTY2FuSW5kZXggPSAwO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IE1QQyA9IGF3YWl0IEVERFNBTWV0aG9kcy5nZXRJbml0aWFsaXplZE1wY0luc3RhbmNlKCk7XG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IHJlcVtpXS50eFJlcXVlc3QudHJhbnNhY3Rpb25zWzBdLnVuc2lnbmVkVHg7XG5cbiAgICAgIC8vIFZhbGlkYXRlIHNpZ25hdHVyZSBzaGFyZXNcbiAgICAgIGlmICghcmVxW2ldLm92YyB8fCAhcmVxW2ldLm92Y1swXS5lZGRzYVNpZ25hdHVyZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3Npbmcgc2lnbmF0dXJlKHMpJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSByZXFbaV0ub3ZjWzBdLmVkZHNhU2lnbmF0dXJlO1xuXG4gICAgICAvLyBWYWxpZGF0ZSBzaWduYWJsZSBoZXhcbiAgICAgIGlmICghdHJhbnNhY3Rpb24uc2lnbmFibGVIZXgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHNpZ25hYmxlIGhleCcpO1xuICAgICAgfVxuICAgICAgY29uc3QgbWVzc2FnZUJ1ZmZlciA9IEJ1ZmZlci5mcm9tKHRyYW5zYWN0aW9uLnNpZ25hYmxlSGV4ISwgJ2hleCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gTVBDLnZlcmlmeShtZXNzYWdlQnVmZmVyLCBzaWduYXR1cmUpO1xuICAgICAgaWYgKCFyZXN1bHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZScpO1xuICAgICAgfVxuXG4gICAgICAvLyBQcmVwYXJlIHRoZSBzaWduYXR1cmUgaW4gaGV4IGZvcm1hdFxuICAgICAgY29uc3Qgc2lnbmF0dXJlSGV4ID0gQnVmZmVyLmNvbmNhdChbQnVmZmVyLmZyb20oc2lnbmF0dXJlLlIsICdoZXgnKSwgQnVmZmVyLmZyb20oc2lnbmF0dXJlLnNpZ21hLCAnaGV4JyldKTtcblxuICAgICAgLy8gVmFsaWRhdGUgdHJhbnNhY3Rpb24tc3BlY2lmaWMgZmllbGRzXG4gICAgICBpZiAoIXRyYW5zYWN0aW9uLmNvaW5TcGVjaWZpYz8uY29tbW9uS2V5Y2hhaW4pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGNvbW1vbiBrZXljaGFpbicpO1xuICAgICAgfVxuICAgICAgY29uc3QgY29tbW9uS2V5Y2hhaW4gPSB0cmFuc2FjdGlvbi5jb2luU3BlY2lmaWMhLmNvbW1vbktleWNoYWluISBhcyBzdHJpbmc7XG5cbiAgICAgIGlmICghdHJhbnNhY3Rpb24uZGVyaXZhdGlvblBhdGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGRlcml2YXRpb24gcGF0aCcpO1xuICAgICAgfVxuICAgICAgY29uc3QgZGVyaXZhdGlvblBhdGggPSB0cmFuc2FjdGlvbi5kZXJpdmF0aW9uUGF0aCBhcyBzdHJpbmc7XG5cbiAgICAgIC8vIERlcml2ZSBhY2NvdW50IElEIGFuZCBzZW5kZXIgYWRkcmVzc1xuICAgICAgY29uc3QgYWNjb3VudElkID0gTVBDLmRlcml2ZVVuaGFyZGVuZWQoY29tbW9uS2V5Y2hhaW4sIGRlcml2YXRpb25QYXRoKS5zbGljZSgwLCA2NCk7XG4gICAgICBjb25zdCB0eG5CdWlsZGVyID0gdGhpcy5nZXRCdWlsZGVyKCkuZnJvbSh0cmFuc2FjdGlvbi5zZXJpYWxpemVkVHggYXMgc3RyaW5nKTtcblxuICAgICAgLy8gQWRkIHRoZSBzaWduYXR1cmVcbiAgICAgIGNvbnN0IG5lYXJLZXlQYWlyID0gbmV3IE5lYXJLZXlQYWlyKHsgcHViOiBhY2NvdW50SWQgfSk7XG4gICAgICB0eG5CdWlsZGVyLmFkZFNpZ25hdHVyZSh7IHB1YjogbmVhcktleVBhaXIuZ2V0S2V5cygpLnB1YiB9LCBzaWduYXR1cmVIZXgpO1xuXG4gICAgICAvLyBGaW5hbGl6ZSBhbmQgc2VyaWFsaXplIHRoZSB0cmFuc2FjdGlvblxuICAgICAgY29uc3Qgc2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCB0eG5CdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCBzZXJpYWxpemVkVHggPSBzaWduZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuXG4gICAgICAvLyBBZGQgdGhlIHNpZ25lZCB0cmFuc2FjdGlvbiB0byB0aGUgbGlzdFxuICAgICAgYnJvYWRjYXN0YWJsZVRyYW5zYWN0aW9ucy5wdXNoKHtcbiAgICAgICAgc2VyaWFsaXplZFR4OiBzZXJpYWxpemVkVHgsXG4gICAgICAgIHNjYW5JbmRleDogdHJhbnNhY3Rpb24uc2NhbkluZGV4LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFVwZGF0ZSB0aGUgbGFzdCBzY2FuIGluZGV4IGlmIGFwcGxpY2FibGVcbiAgICAgIGlmIChpID09PSByZXEubGVuZ3RoIC0gMSAmJiB0cmFuc2FjdGlvbi5jb2luU3BlY2lmaWMhLmxhc3RTY2FuSW5kZXgpIHtcbiAgICAgICAgbGFzdFNjYW5JbmRleCA9IHRyYW5zYWN0aW9uLmNvaW5TcGVjaWZpYyEubGFzdFNjYW5JbmRleCBhcyBudW1iZXI7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmV0dXJuIHRoZSBicm9hZGNhc3RhYmxlIHRyYW5zYWN0aW9ucyBhbmQgdGhlIGxhc3Qgc2NhbiBpbmRleFxuICAgIHJldHVybiB7IHRyYW5zYWN0aW9uczogYnJvYWRjYXN0YWJsZVRyYW5zYWN0aW9ucywgbGFzdFNjYW5JbmRleCB9O1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2UgYSByZXF1ZXN0IHRvIG9uZSBvZiB0aGUgcHVibGljIEVPUyBub2RlcyBhdmFpbGFibGVcbiAgICogQHBhcmFtIHBhcmFtcy5wYXlsb2FkXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0RGF0YUZyb21Ob2RlKHBhcmFtczogeyBwYXlsb2FkPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfSk6IFByb21pc2U8cmVxdWVzdC5SZXNwb25zZT4ge1xuICAgIGNvbnN0IG5vZGVVcmxzID0gdGhpcy5nZXRQdWJsaWNOb2RlVXJscygpO1xuICAgIGZvciAoY29uc3Qgbm9kZVVybCBvZiBub2RlVXJscykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QucG9zdChub2RlVXJsKS5zZW5kKHBhcmFtcy5wYXlsb2FkKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gY2FsbCBlbmRwb2ludDogJy8nIGZyb20gbm9kZXM6ICR7Xy5qb2luKG5vZGVVcmxzLCAnLCAnKX1gKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBnZXRBY2Nlc3NLZXkoe1xuICAgIGFjY291bnRJZCxcbiAgICBiczU4RW5jb2RlZFB1YmxpY0tleSxcbiAgfToge1xuICAgIGFjY291bnRJZDogc3RyaW5nO1xuICAgIGJzNThFbmNvZGVkUHVibGljS2V5OiBzdHJpbmc7XG4gIH0pOiBQcm9taXNlPE5lYXJUeEJ1aWxkZXJQYXJhbXNGcm9tTm9kZT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5nZXREYXRhRnJvbU5vZGUoe1xuICAgICAgcGF5bG9hZDoge1xuICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgaWQ6ICdkb250Y2FyZScsXG4gICAgICAgIG1ldGhvZDogJ3F1ZXJ5JyxcbiAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgcmVxdWVzdF90eXBlOiAndmlld19hY2Nlc3Nfa2V5JyxcbiAgICAgICAgICBmaW5hbGl0eTogJ2ZpbmFsJyxcbiAgICAgICAgICBhY2NvdW50X2lkOiBhY2NvdW50SWQsXG4gICAgICAgICAgcHVibGljX2tleTogYnM1OEVuY29kZWRQdWJsaWNLZXksXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY2NvdW50IG5vdCBmb3VuZCcpO1xuICAgIH1cbiAgICBjb25zdCBhY2Nlc3NLZXkgPSByZXNwb25zZS5ib2R5LnJlc3VsdDtcbiAgICByZXR1cm4geyBub25jZTogYWNjZXNzS2V5Lm5vbmNlICsgMSwgYmxvY2tIYXNoOiBhY2Nlc3NLZXkuYmxvY2tfaGFzaCB9O1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEFjY291bnRCYWxhbmNlKGFjY291bnRJZDogc3RyaW5nLCBzdG9yYWdlQW1vdW50UGVyQnl0ZTogbnVtYmVyKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgIGlkOiAnZG9udGNhcmUnLFxuICAgICAgICBtZXRob2Q6ICdxdWVyeScsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIHJlcXVlc3RfdHlwZTogJ3ZpZXdfYWNjb3VudCcsXG4gICAgICAgICAgZmluYWxpdHk6ICdmaW5hbCcsXG4gICAgICAgICAgYWNjb3VudF9pZDogYWNjb3VudElkLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIHF1ZXJ5IGFjY291bnQgaW5mb3JtYXRpb24nKTtcbiAgICB9XG4gICAgY29uc3QgZXJyb3JDYXVzZSA9IHJlc3BvbnNlLmJvZHkuZXJyb3I/LmNhdXNlLm5hbWU7XG4gICAgaWYgKGVycm9yQ2F1c2UgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGVycm9yQ2F1c2UpO1xuICAgIH1cblxuICAgIGNvbnN0IGFjY291bnQgPSByZXNwb25zZS5ib2R5LnJlc3VsdDtcbiAgICBjb25zdCBjb3N0UGVyQnl0ZSA9IG5ldyBCaWdOdW1iZXIoc3RvcmFnZUFtb3VudFBlckJ5dGUpO1xuICAgIGNvbnN0IHN0YXRlU3Rha2VkID0gbmV3IEJpZ051bWJlcihhY2NvdW50LnN0b3JhZ2VfdXNhZ2UpLm11bHRpcGxpZWRCeShjb3N0UGVyQnl0ZSk7XG4gICAgY29uc3Qgc3Rha2VkID0gbmV3IEJpZ051bWJlcihhY2NvdW50LmxvY2tlZCk7XG4gICAgY29uc3QgdG90YWxCYWxhbmNlID0gbmV3IEJpZ051bWJlcihhY2NvdW50LmFtb3VudCkucGx1cyhzdGFrZWQpO1xuICAgIGNvbnN0IGF2YWlsYWJsZUJhbGFuY2UgPSB0b3RhbEJhbGFuY2UubWludXMoQmlnTnVtYmVyLm1heChzdGFrZWQsIHN0YXRlU3Rha2VkKSk7XG4gICAgcmV0dXJuIGF2YWlsYWJsZUJhbGFuY2UudG9TdHJpbmcoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB0byBnZXQgdGhlIGZ1bmdpYmxlIHRva2VuIGJhbGFuY2UgZm9yIGFuIGFjY291bnRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGZvciB3aGljaCB0aGUgZnQgYmFsYW5jZSB0byBiZSBmZXRjaGVkXG4gICAqIEBwYXJhbSB0b2tlbkNvbnRyYWN0QWRkcmVzcyB0aGUgdG9rZW4gY29udHJhY3QgYWRkcmVzc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTdHJpbmc+fVxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEFjY291bnRGdW5naWJsZVRva2VuQmFsYW5jZShhY2NvdW50SWQ6IHN0cmluZywgdG9rZW5Db250cmFjdEFkZHJlc3M6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgYmFzZTY0QXJncyA9IG5lYXJVdGlscy5jb252ZXJ0VG9CYXNlNjQoeyBhY2NvdW50X2lkOiBhY2NvdW50SWQgfSk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldERhdGFGcm9tTm9kZSh7XG4gICAgICBwYXlsb2FkOiB7XG4gICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICBpZDogJ2RvbnRjYXJlJyxcbiAgICAgICAgbWV0aG9kOiAncXVlcnknLFxuICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICByZXF1ZXN0X3R5cGU6ICdjYWxsX2Z1bmN0aW9uJyxcbiAgICAgICAgICBmaW5hbGl0eTogJ2ZpbmFsJyxcbiAgICAgICAgICBhY2NvdW50X2lkOiB0b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICBtZXRob2RfbmFtZTogJ2Z0X2JhbGFuY2Vfb2YnLFxuICAgICAgICAgIGFyZ3NfYmFzZTY0OiBiYXNlNjRBcmdzLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIGZldGNoIGZ0IGJhbGFuY2Ugb2YgdGhlIGFjY291bnQnKTtcbiAgICB9XG4gICAgY29uc3QgZXJyb3JDYXVzZSA9IHJlc3BvbnNlLmJvZHkuZXJyb3I/LmNhdXNlPy5uYW1lO1xuICAgIGlmIChlcnJvckNhdXNlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvckNhdXNlKTtcbiAgICB9XG4gICAgY29uc3QgcmVzdWx0VWludDhBcnJheTogVWludDhBcnJheSA9IG5ldyBVaW50OEFycmF5KHJlc3BvbnNlLmJvZHkucmVzdWx0LnJlc3VsdCk7XG4gICAgY29uc3QgcmF3ID0gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKHJlc3VsdFVpbnQ4QXJyYXkpO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHJhdyk7XG4gIH1cblxuICAvKipcbiAgICogRnVuY3Rpb24gdG8gY2hlY2sgaWYgc3RvcmFnZSBkZXBvc2l0IGlzIGVuYWJsZWQgb24gYW4gYWRkcmVzcyBmb3IgYSB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gYWNjb3VudElkIGFjY291bnQgZm9yIHdoaWNoIHRoZSBzdG9yYWdlIGJhbGFuY2UgdG8gYmUgZmV0Y2hlZFxuICAgKiBAcGFyYW0gdG9rZW5Db250cmFjdEFkZHJlc3MgdGhlIHRva2VuIGNvbnRyYWN0IGFkZHJlc3NcbiAgICogQHJldHVybnMge1Byb21pc2U8Qm9vbGVhbj59IHRydWUgaWYgd2UgZmluZCB0aGUgc3RvcmFnZSBiYWxhbmNlLCBmYWxzZSBpZiByZXNwb25zZSBpcyBudWxsXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgY2hlY2tJZlN0b3JhZ2VEZXBvc2l0SXNFbmFibGVkKGFjY291bnRJZDogc3RyaW5nLCB0b2tlbkNvbnRyYWN0QWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgYmFzZTY0QXJncyA9IG5lYXJVdGlscy5jb252ZXJ0VG9CYXNlNjQoeyBhY2NvdW50X2lkOiBhY2NvdW50SWQgfSk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldERhdGFGcm9tTm9kZSh7XG4gICAgICBwYXlsb2FkOiB7XG4gICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICBpZDogJ2RvbnRjYXJlJyxcbiAgICAgICAgbWV0aG9kOiAncXVlcnknLFxuICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICByZXF1ZXN0X3R5cGU6ICdjYWxsX2Z1bmN0aW9uJyxcbiAgICAgICAgICBmaW5hbGl0eTogJ2ZpbmFsJyxcbiAgICAgICAgICBhY2NvdW50X2lkOiB0b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICBtZXRob2RfbmFtZTogJ3N0b3JhZ2VfYmFsYW5jZV9vZicsXG4gICAgICAgICAgYXJnc19iYXNlNjQ6IGJhc2U2NEFyZ3MsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gZmV0Y2ggc3RvcmFnZSBkZXBvc2l0IG9mIHRoZSBhY2NvdW50Jyk7XG4gICAgfVxuICAgIGNvbnN0IGVycm9yQ2F1c2UgPSByZXNwb25zZS5ib2R5LmVycm9yPy5jYXVzZT8ubmFtZTtcbiAgICBpZiAoZXJyb3JDYXVzZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3JDYXVzZSk7XG4gICAgfVxuICAgIGNvbnN0IHJlc3VsdFVpbnQ4QXJyYXk6IFVpbnQ4QXJyYXkgPSBuZXcgVWludDhBcnJheShyZXNwb25zZS5ib2R5LnJlc3VsdC5yZXN1bHQpO1xuICAgIGNvbnN0IHJhdyA9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShyZXN1bHRVaW50OEFycmF5KTtcbiAgICBjb25zdCBkZWNvZGVkID0gSlNPTi5wYXJzZShyYXcpO1xuICAgIHJldHVybiBkZWNvZGVkICE9PSBudWxsO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGdldFByb3RvY29sQ29uZmlnKCk6IFByb21pc2U8UHJvdG9jb2xDb25maWdPdXRwdXQ+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgIGlkOiAnZG9udGNhcmUnLFxuICAgICAgICBtZXRob2Q6ICdFWFBFUklNRU5UQUxfcHJvdG9jb2xfY29uZmlnJyxcbiAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgZmluYWxpdHk6ICdmaW5hbCcsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY2NvdW50IG5vdCBmb3VuZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbmZpZyA9IHJlc3BvbnNlLmJvZHkucmVzdWx0O1xuICAgIGNvbnN0IHN0b3JhZ2VBbW91bnRQZXJCeXRlID0gY29uZmlnLnJ1bnRpbWVfY29uZmlnLnN0b3JhZ2VfYW1vdW50X3Blcl9ieXRlO1xuICAgIGNvbnN0IHRyYW5zZmVyQ29zdEZyb21OZXR3b3JrID0gY29uZmlnLnJ1bnRpbWVfY29uZmlnLnRyYW5zYWN0aW9uX2Nvc3RzLmFjdGlvbl9jcmVhdGlvbl9jb25maWcudHJhbnNmZXJfY29zdDtcbiAgICBjb25zdCB0cmFuc2ZlckNvc3Q6IE5lYXJGZWVDb25maWcgPSB7XG4gICAgICBzZW5kU2lyOiB0cmFuc2ZlckNvc3RGcm9tTmV0d29yay5zZW5kX3NpcixcbiAgICAgIHNlbmROb3RTaXI6IHRyYW5zZmVyQ29zdEZyb21OZXR3b3JrLnNlbmRfbm90X3NpcixcbiAgICAgIGV4ZWN1dGlvbjogdHJhbnNmZXJDb3N0RnJvbU5ldHdvcmsuZXhlY3V0aW9uLFxuICAgIH07XG5cbiAgICBjb25zdCByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsgPSBjb25maWcucnVudGltZV9jb25maWcudHJhbnNhY3Rpb25fY29zdHMuYWN0aW9uX3JlY2VpcHRfY3JlYXRpb25fY29uZmlnO1xuICAgIGNvbnN0IHJlY2VpcHRDb25maWc6IE5lYXJGZWVDb25maWcgPSB7XG4gICAgICBzZW5kU2lyOiByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsuc2VuZF9zaXIsXG4gICAgICBzZW5kTm90U2lyOiByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsuc2VuZF9ub3Rfc2lyLFxuICAgICAgZXhlY3V0aW9uOiByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsuZXhlY3V0aW9uLFxuICAgIH07XG4gICAgcmV0dXJuIHsgc3RvcmFnZUFtb3VudFBlckJ5dGUsIHRyYW5zZmVyQ29zdCwgcmVjZWlwdENvbmZpZyB9O1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEdhc1ByaWNlKGJsb2NrSGFzaDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgIGlkOiAnZG9udGNhcmUnLFxuICAgICAgICBtZXRob2Q6ICdnYXNfcHJpY2UnLFxuICAgICAgICBwYXJhbXM6IFtibG9ja0hhc2hdLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQWNjb3VudCBub3QgZm91bmQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BvbnNlLmJvZHkucmVzdWx0Lmdhc19wcmljZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXRQdWJsaWNOb2RlVXJscygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIEVudmlyb25tZW50c1t0aGlzLmJpdGdvLmdldEVudigpXS5uZWFyTm9kZVVybHM7XG4gIH1cblxuICBhc3luYyBwYXJzZVRyYW5zYWN0aW9uKHBhcmFtczogTmVhclBhcnNlVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxOZWFyUGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCB0cmFuc2FjdGlvbkV4cGxhbmF0aW9uID0gYXdhaXQgdGhpcy5leHBsYWluVHJhbnNhY3Rpb24oe1xuICAgICAgdHhQcmVidWlsZDogcGFyYW1zLnR4UHJlYnVpbGQsXG4gICAgICBwdWJsaWNLZXk6IHBhcmFtcy5wdWJsaWNLZXksXG4gICAgICBmZWVJbmZvOiBwYXJhbXMuZmVlSW5mbyxcbiAgICB9KTtcblxuICAgIGlmICghdHJhbnNhY3Rpb25FeHBsYW5hdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuXG4gICAgY29uc3QgbmVhclRyYW5zYWN0aW9uID0gdHJhbnNhY3Rpb25FeHBsYW5hdGlvbiBhcyBOZWFyVHJhbnNhY3Rpb25FeHBsYW5hdGlvbjtcbiAgICBpZiAobmVhclRyYW5zYWN0aW9uLm91dHB1dHMubGVuZ3RoIDw9IDApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlucHV0czogW10sXG4gICAgICAgIG91dHB1dHM6IFtdLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBzZW5kZXJBZGRyZXNzID0gbmVhclRyYW5zYWN0aW9uLm91dHB1dHNbMF0uYWRkcmVzcztcbiAgICBjb25zdCBmZWVBbW91bnQgPSBuZXcgQmlnTnVtYmVyKG5lYXJUcmFuc2FjdGlvbi5mZWUuZmVlID09PSAnJyA/ICcwJyA6IG5lYXJUcmFuc2FjdGlvbi5mZWUuZmVlKTtcblxuICAgIC8vIGFzc3VtZSAxIHNlbmRlciwgd2hvIGlzIGFsc28gdGhlIGZlZSBwYXllclxuICAgIGNvbnN0IGlucHV0cyA9IFtcbiAgICAgIHtcbiAgICAgICAgYWRkcmVzczogc2VuZGVyQWRkcmVzcyxcbiAgICAgICAgYW1vdW50OiBuZXcgQmlnTnVtYmVyKG5lYXJUcmFuc2FjdGlvbi5vdXRwdXRBbW91bnQpLnBsdXMoZmVlQW1vdW50KS50b0ZpeGVkKCksXG4gICAgICB9LFxuICAgIF07XG5cbiAgICBjb25zdCBvdXRwdXRzOiBUcmFuc2FjdGlvbk91dHB1dFtdID0gbmVhclRyYW5zYWN0aW9uLm91dHB1dHMubWFwKChvdXRwdXQpID0+IHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFkZHJlc3M6IG91dHB1dC5hZGRyZXNzLFxuICAgICAgICBhbW91bnQ6IG5ldyBCaWdOdW1iZXIob3V0cHV0LmFtb3VudCkudG9GaXhlZCgpLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICBpbnB1dHMsXG4gICAgICBvdXRwdXRzLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBpc1dhbGxldEFkZHJlc3MocGFyYW1zOiBWZXJpZnlBZGRyZXNzT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRocm93IG5ldyBNZXRob2ROb3RJbXBsZW1lbnRlZEVycm9yKCk7XG4gIH1cblxuICBhc3luYyB2ZXJpZnlUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGxldCB0b3RhbEFtb3VudCA9IG5ldyBCaWdOdW1iZXIoMCk7XG4gICAgY29uc3QgY29pbkNvbmZpZyA9IGNvaW5zLmdldCh0aGlzLmdldENoYWluKCkpO1xuICAgIGNvbnN0IHsgdHhQcmVidWlsZDogdHhQcmVidWlsZCwgdHhQYXJhbXM6IHR4UGFyYW1zIH0gPSBwYXJhbXM7XG4gICAgY29uc3QgdHJhbnNhY3Rpb24gPSBuZXcgVHJhbnNhY3Rpb24oY29pbkNvbmZpZyk7XG4gICAgY29uc3QgcmF3VHggPSB0eFByZWJ1aWxkLnR4SGV4O1xuICAgIGlmICghcmF3VHgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCB0eCBwcmVidWlsZCBwcm9wZXJ0eSB0eEhleCcpO1xuICAgIH1cblxuICAgIHRyYW5zYWN0aW9uLmZyb21SYXdUcmFuc2FjdGlvbihyYXdUeCk7XG4gICAgY29uc3QgZXhwbGFpbmVkVHggPSB0cmFuc2FjdGlvbi5leHBsYWluVHJhbnNhY3Rpb24oKTtcblxuICAgIC8vIHVzZXJzIGRvIG5vdCBpbnB1dCByZWNpcGllbnRzIGZvciBjb25zb2xpZGF0aW9uIHJlcXVlc3RzIGFzIHRoZXkgYXJlIGdlbmVyYXRlZCBieSB0aGUgc2VydmVyXG4gICAgaWYgKHR4UGFyYW1zLnJlY2lwaWVudHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHR4UGFyYW1zLnR5cGUgPT09ICdlbmFibGV0b2tlbicpIHtcbiAgICAgICAgY29uc3QgdG9rZW5OYW1lID0gZXhwbGFpbmVkVHgub3V0cHV0c1swXS50b2tlbk5hbWU7XG4gICAgICAgIGlmICh0b2tlbk5hbWUpIHtcbiAgICAgICAgICBjb25zdCBuZXBUb2tlbiA9IG5lYXJVdGlscy5nZXRUb2tlbkluc3RhbmNlRnJvbVRva2VuTmFtZSh0b2tlbk5hbWUpO1xuICAgICAgICAgIGlmIChuZXBUb2tlbikge1xuICAgICAgICAgICAgZXhwbGFpbmVkVHgub3V0cHV0cy5mb3JFYWNoKChvdXRwdXQpID0+IHtcbiAgICAgICAgICAgICAgaWYgKG91dHB1dC5hbW91bnQgIT09IG5lcFRva2VuLnN0b3JhZ2VEZXBvc2l0QW1vdW50KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTdG9yYWdlIGRlcG9zaXQgYW1vdW50IG5vdCBtYXRjaGluZyEnKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZpbHRlcmVkUmVjaXBpZW50cyA9IHR4UGFyYW1zLnJlY2lwaWVudHM/Lm1hcCgocmVjaXBpZW50KSA9PiB7XG4gICAgICAgIGlmICh0eFBhcmFtcy50eXBlICE9PSAnZW5hYmxldG9rZW4nKSB7XG4gICAgICAgICAgcmV0dXJuIF8ucGljayhyZWNpcGllbnQsIFsnYWRkcmVzcycsICdhbW91bnQnXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIF8ucGljayhyZWNpcGllbnQsIFsnYWRkcmVzcycsICd0b2tlbk5hbWUnXSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgY29uc3QgZmlsdGVyZWRPdXRwdXRzID0gZXhwbGFpbmVkVHgub3V0cHV0cy5tYXAoKG91dHB1dCkgPT4ge1xuICAgICAgICBpZiAodHhQYXJhbXMudHlwZSAhPT0gJ2VuYWJsZXRva2VuJykge1xuICAgICAgICAgIHJldHVybiBfLnBpY2sob3V0cHV0LCBbJ2FkZHJlc3MnLCAnYW1vdW50J10pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBfLnBpY2sob3V0cHV0LCBbJ2FkZHJlc3MnLCAndG9rZW5OYW1lJ10pO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaWYgKCFfLmlzRXF1YWwoZmlsdGVyZWRPdXRwdXRzLCBmaWx0ZXJlZFJlY2lwaWVudHMpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHggb3V0cHV0cyBkb2VzIG5vdCBtYXRjaCB3aXRoIGV4cGVjdGVkIHR4UGFyYW1zIHJlY2lwaWVudHMnKTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgcmVjaXBpZW50cyBvZiB0eFBhcmFtcy5yZWNpcGllbnRzKSB7XG4gICAgICAgIHRvdGFsQW1vdW50ID0gdHhQYXJhbXMudHlwZSAhPT0gJ2VuYWJsZXRva2VuJyA/IHRvdGFsQW1vdW50LnBsdXMocmVjaXBpZW50cy5hbW91bnQpIDogQmlnTnVtYmVyKDApO1xuICAgICAgfVxuICAgICAgaWYgKCF0b3RhbEFtb3VudC5pc0VxdWFsVG8oZXhwbGFpbmVkVHgub3V0cHV0QW1vdW50KSAmJiB0eFBhcmFtcy50eXBlICE9PSAnZW5hYmxldG9rZW4nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHggdG90YWwgYW1vdW50IGRvZXMgbm90IG1hdGNoIHdpdGggZXhwZWN0ZWQgdG90YWwgYW1vdW50IGZpZWxkJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy52ZXJpZmljYXRpb24/LmNvbnNvbGlkYXRpb25Ub0Jhc2VBZGRyZXNzKSB7XG4gICAgICBhd2FpdCB0aGlzLnZlcmlmeUNvbnNvbGlkYXRpb25Ub0Jhc2VBZGRyZXNzKHBhcmFtcywgZXhwbGFpbmVkVHgpO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRCdWlsZGVyKCk6IFRyYW5zYWN0aW9uQnVpbGRlckZhY3Rvcnkge1xuICAgIHJldHVybiBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQodGhpcy5nZXRCYXNlQ2hhaW4oKSkpO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICovXG4gIGF1ZGl0RGVjcnlwdGVkS2V5KHsgcHJ2LCBwdWJsaWNLZXksIG11bHRpU2lnVHlwZSB9OiBBdWRpdERlY3J5cHRlZEtleVBhcmFtcykge1xuICAgIGlmIChtdWx0aVNpZ1R5cGUgIT09ICd0c3MnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vuc3VwcG9ydGVkIG11bHRpU2lnVHlwZScpO1xuICAgIH1cbiAgICBhdWRpdEVkZHNhUHJpdmF0ZUtleShwcnYsIHB1YmxpY0tleSA/PyAnJyk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgdmVyaWZ5Q29uc29saWRhdGlvblRvQmFzZUFkZHJlc3MoXG4gICAgcGFyYW1zOiBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMsXG4gICAgZXhwbGFpbmVkVHg6IFRyYW5zYWN0aW9uRXhwbGFuYXRpb25cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgYmFzZUFkZHJlc3NlczogQmFzZUFkZHJlc3NbXSB8IHVuZGVmaW5lZCA9IGF3YWl0IHBhcmFtcy53YWxsZXQuYWRkcmVzc2VzKHsgc29ydDogLTEsIGxpbWl0OiAxIH0pO1xuICAgIGlmICghYmFzZUFkZHJlc3NlcyB8fCBiYXNlQWRkcmVzc2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBiYXNlIGFkZHJlc3MgZm91bmQgb24gd2FsbGV0Jyk7XG4gICAgfVxuICAgIGNvbnN0IGJhc2VBZGRyZXNzID0gYmFzZUFkZHJlc3Nlc1swXTtcblxuICAgIGZvciAoY29uc3Qgb3V0cHV0IG9mIGV4cGxhaW5lZFR4Lm91dHB1dHMpIHtcbiAgICAgIGlmIChvdXRwdXQuYWRkcmVzcyAhPT0gYmFzZUFkZHJlc3MuYWRkcmVzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCBhZGRyZXNzJyk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=

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


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