PHP WebShell

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

Просмотр файла: pendingApproval.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.PendingApproval = void 0;
/**
 * @prettier
 */
const _ = __importStar(require("lodash"));
const utxolib = __importStar(require("@bitgo/utxo-lib"));
const pendingApproval_1 = require("../pendingApproval");
const utils_1 = require("../utils");
const BuildParams_1 = require("../wallet/BuildParams");
const eddsa_1 = __importDefault(require("../utils/tss/eddsa"));
const ecdsa_1 = require("../utils/tss/ecdsa");
const common_1 = require("../tss/common");
const assert_1 = __importDefault(require("assert"));
class PendingApproval {
    constructor(bitgo, baseCoin, pendingApprovalData, wallet) {
        this.bitgo = bitgo;
        this.baseCoin = baseCoin;
        this.wallet = wallet;
        if (this.baseCoin.supportsTss()) {
            if (this.baseCoin.getMPCAlgorithm() === 'ecdsa') {
                if (this.wallet?.multisigTypeVersion() === 'MPCv2') {
                    this.tssUtils = new ecdsa_1.EcdsaMPCv2Utils(this.bitgo, this.baseCoin, wallet);
                }
                else {
                    this.tssUtils = new ecdsa_1.EcdsaUtils(this.bitgo, this.baseCoin, wallet);
                }
            }
            else {
                this.tssUtils = new eddsa_1.default(this.bitgo, this.baseCoin, wallet);
            }
        }
        this._pendingApproval = pendingApprovalData;
    }
    /**
     * Get the id for this PendingApproval
     */
    id() {
        return this._pendingApproval.id;
    }
    toJSON() {
        return this._pendingApproval;
    }
    /**
     * Get the owner type (wallet or enterprise)
     * Pending approvals can be approved or modified by different scopes (depending on how they were created)
     * If a pending approval is owned by a wallet, then it can be approved by administrators of the wallet
     * If a pending approval is owned by an enterprise, then it can be approved by administrators of the enterprise
     */
    ownerType() {
        if (this._pendingApproval.wallet) {
            return pendingApproval_1.OwnerType.WALLET;
        }
        else if (this._pendingApproval.enterprise) {
            return pendingApproval_1.OwnerType.ENTERPRISE;
        }
        else {
            throw new Error('unexpected pending approval owner: neither wallet nor enterprise was present');
        }
    }
    /**
     * Get the id of the wallet which is associated with this PendingApproval
     */
    walletId() {
        return this._pendingApproval.wallet;
    }
    /**
     * Get the enterprise ID that is associated with this PendingApproval
     */
    enterpriseId() {
        return this._pendingApproval.enterprise;
    }
    /**
     * Get the state of this PendingApproval
     */
    state() {
        return this._pendingApproval.state;
    }
    /**
     * Get the id of the user that performed the action resulting in this PendingApproval
     */
    creator() {
        return this._pendingApproval.creator;
    }
    /**
     * Get the type of the pending approval (what it approves)
     */
    type() {
        if (!this._pendingApproval.info) {
            throw new Error('pending approval info is not available');
        }
        return this._pendingApproval.info.type;
    }
    /**
     * Get information about this PendingApproval
     */
    info() {
        return this._pendingApproval.info;
    }
    /**
     * Get the number of approvals that are required for this PendingApproval to be approved.
     * Defaults to 1 if approvalsRequired doesn't exist on the object
     */
    approvalsRequired() {
        return this._pendingApproval.approvalsRequired || 1;
    }
    /**
     * Generate a url for this PendingApproval for making requests to the server.
     * @param extra
     */
    url(extra = '') {
        return this.baseCoin.url('/pendingapprovals/' + this.id() + extra);
    }
    /**
     * Refetches this PendingApproval from the server and returns it.
     *
     * Note that this mutates the PendingApproval object in place.
     * @param params
     */
    async get(params = {}) {
        this._pendingApproval = await this.bitgo.get(this.url()).result();
        return this;
    }
    /**
     * Sets this PendingApproval to an approved state
     */
    async approve(params = {}) {
        params.previewPendingTxs = true;
        params.pendingApprovalId = this.id();
        const canRecreateTransaction = this.canRecreateTransaction(params);
        const reqId = new utils_1.RequestTracer();
        this.bitgo.setRequestTracer(reqId);
        await this.populateWallet();
        try {
            const transaction = await this.preApprove(params, reqId);
            const approvalParams = { state: 'approved', otp: params.otp };
            if (transaction) {
                // if the transaction already has a half signed property, we take that directly
                approvalParams.halfSigned = transaction.halfSigned || transaction;
            }
            const response = await this.bitgo.put(this.url()).send(approvalParams).result();
            // if the response comes with an error, means that the transaction triggered another condition
            if (response.hasOwnProperty('error') && response.hasOwnProperty('pendingApproval')) {
                return response;
            }
            this._pendingApproval = response;
            await this.postApprove(params, reqId);
            return this._pendingApproval;
        }
        catch (e) {
            if (!canRecreateTransaction &&
                (e.message.indexOf('could not find unspent output for input') !== -1 ||
                    e.message.indexOf('transaction conflicts with an existing transaction in the send queue') !== -1)) {
                throw new Error('unspents expired, wallet passphrase or xprv required to recreate transaction');
            }
            throw e;
        }
    }
    /**
     * Sets this PendingApproval to a rejected state
     * @param params
     */
    async reject(params = {}) {
        return await this.bitgo.put(this.url()).send({ state: 'rejected' }).result();
    }
    /**
     * Alias for PendingApproval.reject()
     *
     * @deprecated
     * @param params
     */
    async cancel(params = {}) {
        return await this.reject(params);
    }
    /**
     * Recreate and sign TSS transaction
     * @param {ApproveOptions} params needed to get txs and use the walletPassphrase to tss sign
     * @param {RequestTracer} reqId id tracer.
     */
    async recreateAndSignTSSTransaction(params, reqId) {
        const { walletPassphrase } = params;
        const txRequestId = this._pendingApproval.txRequestId;
        if (!this.wallet) {
            throw new Error('Wallet not found');
        }
        if (!walletPassphrase) {
            throw new Error('walletPassphrase not found');
        }
        if (!txRequestId) {
            throw new Error('txRequestId not found');
        }
        const decryptedPrv = await this.wallet.getPrv({ walletPassphrase });
        const txRequest = await this.tssUtils.recreateTxRequest(txRequestId, decryptedPrv, reqId);
        if (txRequest.apiVersion === 'lite') {
            if (!txRequest.unsignedTxs || txRequest.unsignedTxs.length === 0) {
                throw new Error('Unexpected error, no transactions found in txRequest.');
            }
            return {
                txHex: txRequest.unsignedTxs[0].serializedTxHex,
            };
        }
        else {
            if (!txRequest.transactions || txRequest.transactions.length === 0) {
                throw new Error('Unexpected error, no transactions found in txRequest.');
            }
            return {
                txHex: txRequest.transactions[0].unsignedTx.serializedTxHex,
            };
        }
    }
    /**
     * Recreate a transaction for a pending approval to respond to updated network conditions
     * @param params
     * @param reqId
     */
    async recreateAndSignTransaction(params = {}, reqId) {
        // this method only makes sense with existing transaction requests
        const transactionRequest = this.info().transactionRequest;
        if (_.isUndefined(transactionRequest)) {
            throw new Error('cannot recreate transaction without transaction request');
        }
        if (_.isUndefined(this.wallet)) {
            throw new Error('cannot recreate transaction without wallet');
        }
        const originalPrebuild = transactionRequest.coinSpecific[this.baseCoin.type];
        const recipients = transactionRequest.recipients;
        let prebuildParams = _.extend({}, params, { recipients: recipients }, transactionRequest.buildParams);
        if (!_.isUndefined(originalPrebuild.hopTransaction)) {
            prebuildParams.hop = true;
        }
        const reqTracer = reqId || new utils_1.RequestTracer();
        if (transactionRequest.buildParams && transactionRequest.buildParams.type === 'consolidate') {
            // consolidate tag is in the build params - this is a consolidation transaction, so
            // it needs to be rebuilt using the special consolidation build route
            this.bitgo.setRequestTracer(reqTracer);
            prebuildParams.prebuildTx = await this.bitgo
                .post(this.wallet.url(`/consolidateUnspents`))
                .send(BuildParams_1.BuildParams.encode(prebuildParams))
                .result();
            delete prebuildParams.recipients;
        }
        prebuildParams = _.extend({}, prebuildParams, { reqId: reqId });
        const signedTransaction = await this.wallet.prebuildAndSignTransaction(prebuildParams);
        // compare PAYGo fees
        const originalParsedTransaction = (await this.baseCoin.parseTransaction({
            txParams: prebuildParams,
            wallet: this.wallet,
            txPrebuild: originalPrebuild,
        }));
        const recreatedParsedTransaction = (await this.baseCoin.parseTransaction({
            txParams: prebuildParams,
            wallet: this.wallet,
            txPrebuild: signedTransaction,
        }));
        if (_.isUndefined(recreatedParsedTransaction.implicitExternalSpendAmount)) {
            return signedTransaction;
        }
        if (typeof recreatedParsedTransaction.implicitExternalSpendAmount !== 'bigint' &&
            !_.isFinite(recreatedParsedTransaction.implicitExternalSpendAmount)) {
            throw new Error('implicit external spend amount could not be determined');
        }
        if (!_.isUndefined(originalParsedTransaction.implicitExternalSpendAmount) &&
            recreatedParsedTransaction.implicitExternalSpendAmount > originalParsedTransaction.implicitExternalSpendAmount) {
            throw new Error('recreated transaction is using a higher pay-as-you-go-fee');
        }
        return signedTransaction;
    }
    /*
     * Cold wallets cannot recreate transactions if the only thing provided is the wallet passphrase
     *
     * The transaction can be recreated if either
     * – there is an xprv
     * – there is a walletPassphrase and the wallet is not cold (because if it's cold, the passphrase is of little use)
     *
     * Therefore, if neither of these is true, the transaction cannot be recreated, which is reflected in the if
     * statement below.
     *
     * Lightning transactions cannot be recreated.
     */
    canRecreateTransaction(params) {
        const isColdWallet = !!_.get(this.wallet, '_wallet.isCold');
        const isOFCWallet = this.baseCoin.getFamily() === 'ofc'; // Off-chain transactions don't need to be rebuilt
        const isLightningWallet = this.baseCoin.getFamily() === 'lnbtc';
        if (isLightningWallet) {
            return false;
        }
        if (!params.xprv && !(params.walletPassphrase && !isColdWallet && !isOFCWallet)) {
            return false;
        }
        // If there are no recipients, then the transaction cannot be recreated
        const recipients = this.info()?.transactionRequest?.buildParams?.recipients || [];
        const type = this.info()?.transactionRequest?.buildParams?.type;
        // We only want to not recreate transactions with no recipients if it is a UTXO coin.
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return !(utxolib.isValidNetwork(this.baseCoin.network) &&
            recipients.length === 0 &&
            type !== 'consolidate');
    }
    /*
     * Internal helper function to get the serialized transaction which is being approved.
     * If this PA is of type 'transactionRequest' this function will try to rebuild and resign the transaction
     * @param {ApproveOptions} params
     * @param {boolean} canRecreateTransaction -
     * @param {RequestTracer} reqId id tracer
     */
    async preApprove(params = {}, reqId) {
        // TransactionRequestLite or Multisig tx's must sign before pending approval is approved
        // Re-signed tx is provided to the pending approval api
        if (this.type() === pendingApproval_1.Type.TRANSACTION_REQUEST) {
            /*
             * If this is a request for approving a transaction, depending on whether this user has a private key to the wallet
             * (some admins may not have the spend permission), the transaction could either be rebroadcast as is, or it could
             * be reconstructed. It is preferable to reconstruct a tx in order to adhere to the latest network conditions
             * such as newer unspents, different fees, or a higher sequence id
             */
            if (params.tx) {
                // the approval tx was reconstructed and explicitly specified - pass it through
                return {
                    txHex: params.tx,
                };
            }
            // this user may not have spending privileges or a passphrase may not have been passed in
            if (!this.canRecreateTransaction(params)) {
                // If this is a TransactionRequest, then the txRequest already has the unsigned transaction
                if (this._pendingApproval.txRequestId) {
                    return undefined;
                }
                // If this is a MultiSig, then we need to fetch the half signed tx to propagate to the approval API
                const transaction = _.get(this.info(), `transactionRequest.coinSpecific.${this.baseCoin.type}`);
                if (!_.isObject(transaction)) {
                    throw new Error('there is neither an original transaction object nor can a new one be recreated');
                }
                return transaction;
            }
            if (this._pendingApproval.txRequestId) {
                return await this.recreateAndSignTSSTransaction(params, reqId);
            }
            return await this.recreateAndSignTransaction(params, reqId);
        }
    }
    /**
     * Internal helper function to perform any post-approval actions.
     * If type is 'transactionRequestFull', this will sign the txRequestFull if possible
     * @param params
     * @param reqId
     * @private
     */
    async postApprove(params = {}, reqId) {
        switch (this.type()) {
            case pendingApproval_1.Type.TRANSACTION_REQUEST_FULL:
                if (this._pendingApproval.state === pendingApproval_1.State.APPROVED) {
                    // After we approve a lightning transaction, we should proceed with submitting the payment
                    if (this.baseCoin.getFamily() === 'lnbtc') {
                        (0, assert_1.default)(this._pendingApproval.txRequestId, 'Missing txRequestId');
                        // this.populateWallet is called before this so we should be good here
                        (0, assert_1.default)(this.wallet?.id(), 'Missing wallet id');
                        await (0, common_1.sendTxRequest)(this.bitgo, this.wallet?.id(), this._pendingApproval.txRequestId, utils_1.RequestType.tx, reqId);
                    }
                    else if (this.canRecreateTransaction(params) && this.baseCoin.supportsTss()) {
                        await this.recreateAndSignTSSTransaction(params, reqId);
                    }
                }
        }
    }
    /**
     * Helper function to ensure that self.wallet is set
     */
    async populateWallet() {
        if (this.wallet) {
            return;
        }
        // TODO(WP-1341): consolidate/simplify this logic
        switch (this.type()) {
            case pendingApproval_1.Type.TRANSACTION_REQUEST:
                const transactionRequest = this.info().transactionRequest;
                if (_.isUndefined(transactionRequest)) {
                    throw new Error('missing required object property transactionRequest');
                }
                const updatedWallet = await this.baseCoin.wallets().get({ id: transactionRequest.sourceWallet });
                if (_.isUndefined(updatedWallet)) {
                    throw new Error('unexpected - unable to get wallet using sourcewallet');
                }
                this.wallet = updatedWallet;
                if (this.wallet.id() !== transactionRequest.sourceWallet) {
                    throw new Error('unexpected source wallet for pending approval');
                }
                break;
            case pendingApproval_1.Type.TRANSACTION_REQUEST_FULL:
                const walletId = this.walletId();
                if (!walletId) {
                    throw new Error('Unexpected error, pendingApproval.wallet is expected to be defined!');
                }
                this.wallet = await this.baseCoin.wallets().get({ id: this.walletId() });
                if (!this.wallet) {
                    throw new Error('unexpected - unable to get wallet using pendingApproval.wallet');
                }
                break;
        }
        return;
    }
}
exports.PendingApproval = PendingApproval;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVuZGluZ0FwcHJvdmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2JpdGdvL3BlbmRpbmdBcHByb3ZhbC9wZW5kaW5nQXBwcm92YWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0dBRUc7QUFDSCwwQ0FBNEI7QUFDNUIseURBQTJDO0FBRzNDLHdEQVE0QjtBQUM1QixvQ0FBc0Q7QUFFdEQsdURBQW9EO0FBR3BELCtEQUE0QztBQUM1Qyw4Q0FBaUU7QUFHakUsMENBQThDO0FBQzlDLG9EQUE0QjtBQWE1QixNQUFhLGVBQWU7SUFPMUIsWUFBWSxLQUFnQixFQUFFLFFBQW1CLEVBQUUsbUJBQXdDLEVBQUUsTUFBZ0I7UUFDM0csSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFFckIsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7WUFDaEMsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsRUFBRSxLQUFLLE9BQU8sRUFBRSxDQUFDO2dCQUNoRCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsbUJBQW1CLEVBQUUsS0FBSyxPQUFPLEVBQUUsQ0FBQztvQkFDbkQsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLHVCQUFlLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUN6RSxDQUFDO3FCQUFNLENBQUM7b0JBQ04sSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLGtCQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUNwRSxDQUFDO1lB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LEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDekUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO2dCQUNwRixDQUFDO2dCQUNELE1BQU07UUFDVixDQUFDO1FBQ0QsT0FBTztJQUNULENBQUM7Q0FDRjtBQXBjRCwwQ0FvY0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwcmV0dGllclxuICovXG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgKiBhcyB1dHhvbGliIGZyb20gJ0BiaXRnby91dHhvLWxpYic7XG5pbXBvcnQgeyBJQmFzZUNvaW4gfSBmcm9tICcuLi9iYXNlQ29pbic7XG5pbXBvcnQgeyBCaXRHb0Jhc2UgfSBmcm9tICcuLi9iaXRnb0Jhc2UnO1xuaW1wb3J0IHtcbiAgQXBwcm92ZU9wdGlvbnMsXG4gIElQZW5kaW5nQXBwcm92YWwsXG4gIE93bmVyVHlwZSxcbiAgUGVuZGluZ0FwcHJvdmFsRGF0YSxcbiAgUGVuZGluZ0FwcHJvdmFsSW5mbyxcbiAgU3RhdGUsXG4gIFR5cGUsXG59IGZyb20gJy4uL3BlbmRpbmdBcHByb3ZhbCc7XG5pbXBvcnQgeyBSZXF1ZXN0VHJhY2VyLCBSZXF1ZXN0VHlwZSB9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7IElXYWxsZXQgfSBmcm9tICcuLi93YWxsZXQnO1xuaW1wb3J0IHsgQnVpbGRQYXJhbXMgfSBmcm9tICcuLi93YWxsZXQvQnVpbGRQYXJhbXMnO1xuaW1wb3J0IHsgSVJlcXVlc3RUcmFjZXIgfSBmcm9tICcuLi8uLi9hcGknO1xuaW1wb3J0IEJhc2VUc3NVdGlscyBmcm9tICcuLi91dGlscy90c3MvYmFzZVRTU1V0aWxzJztcbmltcG9ydCBFZGRzYVV0aWxzIGZyb20gJy4uL3V0aWxzL3Rzcy9lZGRzYSc7XG5pbXBvcnQgeyBFY2RzYU1QQ3YyVXRpbHMsIEVjZHNhVXRpbHMgfSBmcm9tICcuLi91dGlscy90c3MvZWNkc2EnO1xuaW1wb3J0IHsgS2V5U2hhcmUgYXMgRWNkc2FLZXlTaGFyZSB9IGZyb20gJy4uL3V0aWxzL3Rzcy9lY2RzYS90eXBlcyc7XG5pbXBvcnQgeyBLZXlTaGFyZSBhcyBFZGRzYUtleVNoYXJlIH0gZnJvbSAnLi4vdXRpbHMvdHNzL2VkZHNhL3R5cGVzJztcbmltcG9ydCB7IHNlbmRUeFJlcXVlc3QgfSBmcm9tICcuLi90c3MvY29tbW9uJztcbmltcG9ydCBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcblxudHlwZSBQcmVBcHByb3ZlUmVzdWx0ID0ge1xuICB0eEhleDogc3RyaW5nO1xuICBoYWxmU2lnbmVkPzogc3RyaW5nO1xufTtcblxudHlwZSBBcHByb3ZlUGVuZGluZ0FwcHJvdmFsUmVxdWVzdEJvZHkgPSB7XG4gIHN0YXRlOiAnYXBwcm92ZWQnO1xuICBvdHA6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgaGFsZlNpZ25lZD86IHN0cmluZyB8IE9taXQ8UHJlQXBwcm92ZVJlc3VsdCwgJ2hhbGZTaWduZWQnPjtcbn07XG5cbmV4cG9ydCBjbGFzcyBQZW5kaW5nQXBwcm92YWwgaW1wbGVtZW50cyBJUGVuZGluZ0FwcHJvdmFsIHtcbiAgcHJpdmF0ZSByZWFkb25seSBiaXRnbzogQml0R29CYXNlO1xuICBwcml2YXRlIHJlYWRvbmx5IGJhc2VDb2luOiBJQmFzZUNvaW47XG4gIHByaXZhdGUgdHNzVXRpbHM/OiBCYXNlVHNzVXRpbHM8RWNkc2FLZXlTaGFyZSB8IEVkZHNhS2V5U2hhcmU+O1xuICBwcml2YXRlIHdhbGxldD86IElXYWxsZXQ7XG4gIHByaXZhdGUgX3BlbmRpbmdBcHByb3ZhbDogUGVuZGluZ0FwcHJvdmFsRGF0YTtcblxuICBjb25zdHJ1Y3RvcihiaXRnbzogQml0R29CYXNlLCBiYXNlQ29pbjogSUJhc2VDb2luLCBwZW5kaW5nQXBwcm92YWxEYXRhOiBQZW5kaW5nQXBwcm92YWxEYXRhLCB3YWxsZXQ/OiBJV2FsbGV0KSB7XG4gICAgdGhpcy5iaXRnbyA9IGJpdGdvO1xuICAgIHRoaXMuYmFzZUNvaW4gPSBiYXNlQ29pbjtcbiAgICB0aGlzLndhbGxldCA9IHdhbGxldDtcblxuICAgIGlmICh0aGlzLmJhc2VDb2luLnN1cHBvcnRzVHNzKCkpIHtcbiAgICAgIGlmICh0aGlzLmJhc2VDb2luLmdldE1QQ0FsZ29yaXRobSgpID09PSAnZWNkc2EnKSB7XG4gICAgICAgIGlmICh0aGlzLndhbGxldD8ubXVsdGlzaWdUeXBlVmVyc2lvbigpID09PSAnTVBDdjInKSB7XG4gICAgICAgICAgdGhpcy50c3NVdGlscyA9IG5ldyBFY2RzYU1QQ3YyVXRpbHModGhpcy5iaXRnbywgdGhpcy5iYXNlQ29pbiwgd2FsbGV0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnRzc1V0aWxzID0gbmV3IEVjZHNhVXRpbHModGhpcy5iaXRnbywgdGhpcy5iYXNlQ29pbiwgd2FsbGV0KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy50c3NVdGlscyA9IG5ldyBFZGRzYVV0aWxzKHRoaXMuYml0Z28sIHRoaXMuYmFzZUNvaW4sIHdhbGxldCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5fcGVuZGluZ0FwcHJvdmFsID0gcGVuZGluZ0FwcHJvdmFsRGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGlkIGZvciB0aGlzIFBlbmRpbmdBcHByb3ZhbFxuICAgKi9cbiAgaWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsLmlkO1xuICB9XG5cbiAgdG9KU09OKCk6IFBlbmRpbmdBcHByb3ZhbERhdGEge1xuICAgIHJldHVybiB0aGlzLl9wZW5kaW5nQXBwcm92YWw7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBvd25lciB0eXBlICh3YWxsZXQgb3IgZW50ZXJwcmlzZSlcbiAgICogUGVuZGluZyBhcHByb3ZhbHMgY2FuIGJlIGFwcHJvdmVkIG9yIG1vZGlmaWVkIGJ5IGRpZmZlcmVudCBzY29wZXMgKGRlcGVuZGluZyBvbiBob3cgdGhleSB3ZXJlIGNyZWF0ZWQpXG4gICAqIElmIGEgcGVuZGluZyBhcHByb3ZhbCBpcyBvd25lZCBieSBhIHdhbGxldCwgdGhlbiBpdCBjYW4gYmUgYXBwcm92ZWQgYnkgYWRtaW5pc3RyYXRvcnMgb2YgdGhlIHdhbGxldFxuICAgKiBJZiBhIHBlbmRpbmcgYXBwcm92YWwgaXMgb3duZWQgYnkgYW4gZW50ZXJwcmlzZSwgdGhlbiBpdCBjYW4gYmUgYXBwcm92ZWQgYnkgYWRtaW5pc3RyYXRvcnMgb2YgdGhlIGVudGVycHJpc2VcbiAgICovXG4gIG93bmVyVHlwZSgpOiBPd25lclR5cGUge1xuICAgIGlmICh0aGlzLl9wZW5kaW5nQXBwcm92YWwud2FsbGV0KSB7XG4gICAgICByZXR1cm4gT3duZXJUeXBlLldBTExFVDtcbiAgICB9IGVsc2UgaWYgKHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5lbnRlcnByaXNlKSB7XG4gICAgICByZXR1cm4gT3duZXJUeXBlLkVOVEVSUFJJU0U7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndW5leHBlY3RlZCBwZW5kaW5nIGFwcHJvdmFsIG93bmVyOiBuZWl0aGVyIHdhbGxldCBub3IgZW50ZXJwcmlzZSB3YXMgcHJlc2VudCcpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGlkIG9mIHRoZSB3YWxsZXQgd2hpY2ggaXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgUGVuZGluZ0FwcHJvdmFsXG4gICAqL1xuICB3YWxsZXRJZCgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9wZW5kaW5nQXBwcm92YWwud2FsbGV0O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgZW50ZXJwcmlzZSBJRCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIFBlbmRpbmdBcHByb3ZhbFxuICAgKi9cbiAgZW50ZXJwcmlzZUlkKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5lbnRlcnByaXNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgc3RhdGUgb2YgdGhpcyBQZW5kaW5nQXBwcm92YWxcbiAgICovXG4gIHN0YXRlKCk6IFN0YXRlIHtcbiAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsLnN0YXRlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgaWQgb2YgdGhlIHVzZXIgdGhhdCBwZXJmb3JtZWQgdGhlIGFjdGlvbiByZXN1bHRpbmcgaW4gdGhpcyBQZW5kaW5nQXBwcm92YWxcbiAgICovXG4gIGNyZWF0b3IoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsLmNyZWF0b3I7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSB0eXBlIG9mIHRoZSBwZW5kaW5nIGFwcHJvdmFsICh3aGF0IGl0IGFwcHJvdmVzKVxuICAgKi9cbiAgdHlwZSgpOiBUeXBlIHtcbiAgICBpZiAoIXRoaXMuX3BlbmRpbmdBcHByb3ZhbC5pbmZvKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3BlbmRpbmcgYXBwcm92YWwgaW5mbyBpcyBub3QgYXZhaWxhYmxlJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5pbmZvLnR5cGU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGluZm9ybWF0aW9uIGFib3V0IHRoaXMgUGVuZGluZ0FwcHJvdmFsXG4gICAqL1xuICBpbmZvKCk6IFBlbmRpbmdBcHByb3ZhbEluZm8ge1xuICAgIHJldHVybiB0aGlzLl9wZW5kaW5nQXBwcm92YWwuaW5mbztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIG51bWJlciBvZiBhcHByb3ZhbHMgdGhhdCBhcmUgcmVxdWlyZWQgZm9yIHRoaXMgUGVuZGluZ0FwcHJvdmFsIHRvIGJlIGFwcHJvdmVkLlxuICAgKiBEZWZhdWx0cyB0byAxIGlmIGFwcHJvdmFsc1JlcXVpcmVkIGRvZXNuJ3QgZXhpc3Qgb24gdGhlIG9iamVjdFxuICAgKi9cbiAgYXBwcm92YWxzUmVxdWlyZWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsLmFwcHJvdmFsc1JlcXVpcmVkIHx8IDE7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgYSB1cmwgZm9yIHRoaXMgUGVuZGluZ0FwcHJvdmFsIGZvciBtYWtpbmcgcmVxdWVzdHMgdG8gdGhlIHNlcnZlci5cbiAgICogQHBhcmFtIGV4dHJhXG4gICAqL1xuICB1cmwoZXh0cmEgPSAnJyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYmFzZUNvaW4udXJsKCcvcGVuZGluZ2FwcHJvdmFscy8nICsgdGhpcy5pZCgpICsgZXh0cmEpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZmV0Y2hlcyB0aGlzIFBlbmRpbmdBcHByb3ZhbCBmcm9tIHRoZSBzZXJ2ZXIgYW5kIHJldHVybnMgaXQuXG4gICAqXG4gICAqIE5vdGUgdGhhdCB0aGlzIG11dGF0ZXMgdGhlIFBlbmRpbmdBcHByb3ZhbCBvYmplY3QgaW4gcGxhY2UuXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICovXG4gIGFzeW5jIGdldChwYXJhbXM6IFJlY29yZDxzdHJpbmcsIG5ldmVyPiA9IHt9KTogUHJvbWlzZTxQZW5kaW5nQXBwcm92YWw+IHtcbiAgICB0aGlzLl9wZW5kaW5nQXBwcm92YWwgPSBhd2FpdCB0aGlzLmJpdGdvLmdldCh0aGlzLnVybCgpKS5yZXN1bHQoKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoaXMgUGVuZGluZ0FwcHJvdmFsIHRvIGFuIGFwcHJvdmVkIHN0YXRlXG4gICAqL1xuICBhc3luYyBhcHByb3ZlKHBhcmFtczogQXBwcm92ZU9wdGlvbnMgPSB7fSk6IFByb21pc2U8YW55PiB7XG4gICAgcGFyYW1zLnByZXZpZXdQZW5kaW5nVHhzID0gdHJ1ZTtcbiAgICBwYXJhbXMucGVuZGluZ0FwcHJvdmFsSWQgPSB0aGlzLmlkKCk7XG4gICAgY29uc3QgY2FuUmVjcmVhdGVUcmFuc2FjdGlvbiA9IHRoaXMuY2FuUmVjcmVhdGVUcmFuc2FjdGlvbihwYXJhbXMpO1xuICAgIGNvbnN0IHJlcUlkID0gbmV3IFJlcXVlc3RUcmFjZXIoKTtcbiAgICB0aGlzLmJpdGdvLnNldFJlcXVlc3RUcmFjZXIocmVxSWQpO1xuICAgIGF3YWl0IHRoaXMucG9wdWxhdGVXYWxsZXQoKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IGF3YWl0IHRoaXMucHJlQXBwcm92ZShwYXJhbXMsIHJlcUlkKTtcblxuICAgICAgY29uc3QgYXBwcm92YWxQYXJhbXM6IEFwcHJvdmVQZW5kaW5nQXBwcm92YWxSZXF1ZXN0Qm9keSA9IHsgc3RhdGU6ICdhcHByb3ZlZCcsIG90cDogcGFyYW1zLm90cCB9O1xuICAgICAgaWYgKHRyYW5zYWN0aW9uKSB7XG4gICAgICAgIC8vIGlmIHRoZSB0cmFuc2FjdGlvbiBhbHJlYWR5IGhhcyBhIGhhbGYgc2lnbmVkIHByb3BlcnR5LCB3ZSB0YWtlIHRoYXQgZGlyZWN0bHlcbiAgICAgICAgYXBwcm92YWxQYXJhbXMuaGFsZlNpZ25lZCA9IHRyYW5zYWN0aW9uLmhhbGZTaWduZWQgfHwgdHJhbnNhY3Rpb247XG4gICAgICB9XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuYml0Z28ucHV0KHRoaXMudXJsKCkpLnNlbmQoYXBwcm92YWxQYXJhbXMpLnJlc3VsdCgpO1xuXG4gICAgICAvLyBpZiB0aGUgcmVzcG9uc2UgY29tZXMgd2l0aCBhbiBlcnJvciwgbWVhbnMgdGhhdCB0aGUgdHJhbnNhY3Rpb24gdHJpZ2dlcmVkIGFub3RoZXIgY29uZGl0aW9uXG4gICAgICBpZiAocmVzcG9uc2UuaGFzT3duUHJvcGVydHkoJ2Vycm9yJykgJiYgcmVzcG9uc2UuaGFzT3duUHJvcGVydHkoJ3BlbmRpbmdBcHByb3ZhbCcpKSB7XG4gICAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5fcGVuZGluZ0FwcHJvdmFsID0gcmVzcG9uc2U7XG4gICAgICBhd2FpdCB0aGlzLnBvc3RBcHByb3ZlKHBhcmFtcywgcmVxSWQpO1xuXG4gICAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGlmIChcbiAgICAgICAgIWNhblJlY3JlYXRlVHJhbnNhY3Rpb24gJiZcbiAgICAgICAgKGUubWVzc2FnZS5pbmRleE9mKCdjb3VsZCBub3QgZmluZCB1bnNwZW50IG91dHB1dCBmb3IgaW5wdXQnKSAhPT0gLTEgfHxcbiAgICAgICAgICBlLm1lc3NhZ2UuaW5kZXhPZigndHJhbnNhY3Rpb24gY29uZmxpY3RzIHdpdGggYW4gZXhpc3RpbmcgdHJhbnNhY3Rpb24gaW4gdGhlIHNlbmQgcXVldWUnKSAhPT0gLTEpXG4gICAgICApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bnNwZW50cyBleHBpcmVkLCB3YWxsZXQgcGFzc3BocmFzZSBvciB4cHJ2IHJlcXVpcmVkIHRvIHJlY3JlYXRlIHRyYW5zYWN0aW9uJyk7XG4gICAgICB9XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoaXMgUGVuZGluZ0FwcHJvdmFsIHRvIGEgcmVqZWN0ZWQgc3RhdGVcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgcmVqZWN0KHBhcmFtczogUmVjb3JkPHN0cmluZywgbmV2ZXI+ID0ge30pOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLmJpdGdvLnB1dCh0aGlzLnVybCgpKS5zZW5kKHsgc3RhdGU6ICdyZWplY3RlZCcgfSkucmVzdWx0KCk7XG4gIH1cblxuICAvKipcbiAgICogQWxpYXMgZm9yIFBlbmRpbmdBcHByb3ZhbC5yZWplY3QoKVxuICAgKlxuICAgKiBAZGVwcmVjYXRlZFxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqL1xuICBhc3luYyBjYW5jZWwocGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBuZXZlcj4gPSB7fSk6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMucmVqZWN0KHBhcmFtcyk7XG4gIH1cblxuICAvKipcbiAgICogUmVjcmVhdGUgYW5kIHNpZ24gVFNTIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7QXBwcm92ZU9wdGlvbnN9IHBhcmFtcyBuZWVkZWQgdG8gZ2V0IHR4cyBhbmQgdXNlIHRoZSB3YWxsZXRQYXNzcGhyYXNlIHRvIHRzcyBzaWduXG4gICAqIEBwYXJhbSB7UmVxdWVzdFRyYWNlcn0gcmVxSWQgaWQgdHJhY2VyLlxuICAgKi9cbiAgYXN5bmMgcmVjcmVhdGVBbmRTaWduVFNTVHJhbnNhY3Rpb24ocGFyYW1zOiBBcHByb3ZlT3B0aW9ucywgcmVxSWQ6IElSZXF1ZXN0VHJhY2VyKTogUHJvbWlzZTx7IHR4SGV4OiBzdHJpbmcgfT4ge1xuICAgIGNvbnN0IHsgd2FsbGV0UGFzc3BocmFzZSB9ID0gcGFyYW1zO1xuICAgIGNvbnN0IHR4UmVxdWVzdElkID0gdGhpcy5fcGVuZGluZ0FwcHJvdmFsLnR4UmVxdWVzdElkO1xuXG4gICAgaWYgKCF0aGlzLndhbGxldCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdXYWxsZXQgbm90IGZvdW5kJyk7XG4gICAgfVxuXG4gICAgaWYgKCF3YWxsZXRQYXNzcGhyYXNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3dhbGxldFBhc3NwaHJhc2Ugbm90IGZvdW5kJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0eFJlcXVlc3RJZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd0eFJlcXVlc3RJZCBub3QgZm91bmQnKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWNyeXB0ZWRQcnYgPSBhd2FpdCB0aGlzLndhbGxldC5nZXRQcnYoeyB3YWxsZXRQYXNzcGhyYXNlIH0pO1xuICAgIGNvbnN0IHR4UmVxdWVzdCA9IGF3YWl0IHRoaXMudHNzVXRpbHMhLnJlY3JlYXRlVHhSZXF1ZXN0KHR4UmVxdWVzdElkLCBkZWNyeXB0ZWRQcnYsIHJlcUlkKTtcbiAgICBpZiAodHhSZXF1ZXN0LmFwaVZlcnNpb24gPT09ICdsaXRlJykge1xuICAgICAgaWYgKCF0eFJlcXVlc3QudW5zaWduZWRUeHMgfHwgdHhSZXF1ZXN0LnVuc2lnbmVkVHhzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuZXhwZWN0ZWQgZXJyb3IsIG5vIHRyYW5zYWN0aW9ucyBmb3VuZCBpbiB0eFJlcXVlc3QuJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICB0eEhleDogdHhSZXF1ZXN0LnVuc2lnbmVkVHhzWzBdLnNlcmlhbGl6ZWRUeEhleCxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICghdHhSZXF1ZXN0LnRyYW5zYWN0aW9ucyB8fCB0eFJlcXVlc3QudHJhbnNhY3Rpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuZXhwZWN0ZWQgZXJyb3IsIG5vIHRyYW5zYWN0aW9ucyBmb3VuZCBpbiB0eFJlcXVlc3QuJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICB0eEhleDogdHhSZXF1ZXN0LnRyYW5zYWN0aW9uc1swXS51bnNpZ25lZFR4LnNlcmlhbGl6ZWRUeEhleCxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlY3JlYXRlIGEgdHJhbnNhY3Rpb24gZm9yIGEgcGVuZGluZyBhcHByb3ZhbCB0byByZXNwb25kIHRvIHVwZGF0ZWQgbmV0d29yayBjb25kaXRpb25zXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogQHBhcmFtIHJlcUlkXG4gICAqL1xuICBhc3luYyByZWNyZWF0ZUFuZFNpZ25UcmFuc2FjdGlvbihwYXJhbXM6IGFueSA9IHt9LCByZXFJZD86IElSZXF1ZXN0VHJhY2VyKTogUHJvbWlzZTxhbnk+IHtcbiAgICAvLyB0aGlzIG1ldGhvZCBvbmx5IG1ha2VzIHNlbnNlIHdpdGggZXhpc3RpbmcgdHJhbnNhY3Rpb24gcmVxdWVzdHNcbiAgICBjb25zdCB0cmFuc2FjdGlvblJlcXVlc3QgPSB0aGlzLmluZm8oKS50cmFuc2FjdGlvblJlcXVlc3Q7XG4gICAgaWYgKF8uaXNVbmRlZmluZWQodHJhbnNhY3Rpb25SZXF1ZXN0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgcmVjcmVhdGUgdHJhbnNhY3Rpb24gd2l0aG91dCB0cmFuc2FjdGlvbiByZXF1ZXN0Jyk7XG4gICAgfVxuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQodGhpcy53YWxsZXQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Nhbm5vdCByZWNyZWF0ZSB0cmFuc2FjdGlvbiB3aXRob3V0IHdhbGxldCcpO1xuICAgIH1cblxuICAgIGNvbnN0IG9yaWdpbmFsUHJlYnVpbGQgPSB0cmFuc2FjdGlvblJlcXVlc3QuY29pblNwZWNpZmljW3RoaXMuYmFzZUNvaW4udHlwZV07XG5cbiAgICBjb25zdCByZWNpcGllbnRzID0gdHJhbnNhY3Rpb25SZXF1ZXN0LnJlY2lwaWVudHM7XG4gICAgbGV0IHByZWJ1aWxkUGFyYW1zID0gXy5leHRlbmQoe30sIHBhcmFtcywgeyByZWNpcGllbnRzOiByZWNpcGllbnRzIH0sIHRyYW5zYWN0aW9uUmVxdWVzdC5idWlsZFBhcmFtcyk7XG5cbiAgICBpZiAoIV8uaXNVbmRlZmluZWQob3JpZ2luYWxQcmVidWlsZC5ob3BUcmFuc2FjdGlvbikpIHtcbiAgICAgIHByZWJ1aWxkUGFyYW1zLmhvcCA9IHRydWU7XG4gICAgfVxuXG4gICAgY29uc3QgcmVxVHJhY2VyID0gcmVxSWQgfHwgbmV3IFJlcXVlc3RUcmFjZXIoKTtcbiAgICBpZiAodHJhbnNhY3Rpb25SZXF1ZXN0LmJ1aWxkUGFyYW1zICYmIHRyYW5zYWN0aW9uUmVxdWVzdC5idWlsZFBhcmFtcy50eXBlID09PSAnY29uc29saWRhdGUnKSB7XG4gICAgICAvLyBjb25zb2xpZGF0ZSB0YWcgaXMgaW4gdGhlIGJ1aWxkIHBhcmFtcyAtIHRoaXMgaXMgYSBjb25zb2xpZGF0aW9uIHRyYW5zYWN0aW9uLCBzb1xuICAgICAgLy8gaXQgbmVlZHMgdG8gYmUgcmVidWlsdCB1c2luZyB0aGUgc3BlY2lhbCBjb25zb2xpZGF0aW9uIGJ1aWxkIHJvdXRlXG4gICAgICB0aGlzLmJpdGdvLnNldFJlcXVlc3RUcmFjZXIocmVxVHJhY2VyKTtcbiAgICAgIHByZWJ1aWxkUGFyYW1zLnByZWJ1aWxkVHggPSBhd2FpdCB0aGlzLmJpdGdvXG4gICAgICAgIC5wb3N0KHRoaXMud2FsbGV0LnVybChgL2NvbnNvbGlkYXRlVW5zcGVudHNgKSlcbiAgICAgICAgLnNlbmQoQnVpbGRQYXJhbXMuZW5jb2RlKHByZWJ1aWxkUGFyYW1zKSlcbiAgICAgICAgLnJlc3VsdCgpO1xuICAgICAgZGVsZXRlIHByZWJ1aWxkUGFyYW1zLnJlY2lwaWVudHM7XG4gICAgfVxuXG4gICAgcHJlYnVpbGRQYXJhbXMgPSBfLmV4dGVuZCh7fSwgcHJlYnVpbGRQYXJhbXMsIHsgcmVxSWQ6IHJlcUlkIH0pO1xuICAgIGNvbnN0IHNpZ25lZFRyYW5zYWN0aW9uID0gYXdhaXQgdGhpcy53YWxsZXQucHJlYnVpbGRBbmRTaWduVHJhbnNhY3Rpb24ocHJlYnVpbGRQYXJhbXMpO1xuICAgIC8vIGNvbXBhcmUgUEFZR28gZmVlc1xuICAgIGNvbnN0IG9yaWdpbmFsUGFyc2VkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdGhpcy5iYXNlQ29pbi5wYXJzZVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zOiBwcmVidWlsZFBhcmFtcyxcbiAgICAgIHdhbGxldDogdGhpcy53YWxsZXQsXG4gICAgICB0eFByZWJ1aWxkOiBvcmlnaW5hbFByZWJ1aWxkLFxuICAgIH0pKSBhcyBhbnk7XG4gICAgY29uc3QgcmVjcmVhdGVkUGFyc2VkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdGhpcy5iYXNlQ29pbi5wYXJzZVRyYW5zYWN0aW9uKHtcbiAgICAgIHR4UGFyYW1zOiBwcmVidWlsZFBhcmFtcyxcbiAgICAgIHdhbGxldDogdGhpcy53YWxsZXQsXG4gICAgICB0eFByZWJ1aWxkOiBzaWduZWRUcmFuc2FjdGlvbixcbiAgICB9KSkgYXMgYW55O1xuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocmVjcmVhdGVkUGFyc2VkVHJhbnNhY3Rpb24uaW1wbGljaXRFeHRlcm5hbFNwZW5kQW1vdW50KSkge1xuICAgICAgcmV0dXJuIHNpZ25lZFRyYW5zYWN0aW9uO1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgIHR5cGVvZiByZWNyZWF0ZWRQYXJzZWRUcmFuc2FjdGlvbi5pbXBsaWNpdEV4dGVybmFsU3BlbmRBbW91bnQgIT09ICdiaWdpbnQnICYmXG4gICAgICAhXy5pc0Zpbml0ZShyZWNyZWF0ZWRQYXJzZWRUcmFuc2FjdGlvbi5pbXBsaWNpdEV4dGVybmFsU3BlbmRBbW91bnQpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ltcGxpY2l0IGV4dGVybmFsIHNwZW5kIGFtb3VudCBjb3VsZCBub3QgYmUgZGV0ZXJtaW5lZCcpO1xuICAgIH1cbiAgICBpZiAoXG4gICAgICAhXy5pc1VuZGVmaW5lZChvcmlnaW5hbFBhcnNlZFRyYW5zYWN0aW9uLmltcGxpY2l0RXh0ZXJuYWxTcGVuZEFtb3VudCkgJiZcbiAgICAgIHJlY3JlYXRlZFBhcnNlZFRyYW5zYWN0aW9uLmltcGxpY2l0RXh0ZXJuYWxTcGVuZEFtb3VudCA+IG9yaWdpbmFsUGFyc2VkVHJhbnNhY3Rpb24uaW1wbGljaXRFeHRlcm5hbFNwZW5kQW1vdW50XG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3JlY3JlYXRlZCB0cmFuc2FjdGlvbiBpcyB1c2luZyBhIGhpZ2hlciBwYXktYXMteW91LWdvLWZlZScpO1xuICAgIH1cbiAgICByZXR1cm4gc2lnbmVkVHJhbnNhY3Rpb247XG4gIH1cblxuICAvKlxuICAgKiBDb2xkIHdhbGxldHMgY2Fubm90IHJlY3JlYXRlIHRyYW5zYWN0aW9ucyBpZiB0aGUgb25seSB0aGluZyBwcm92aWRlZCBpcyB0aGUgd2FsbGV0IHBhc3NwaHJhc2VcbiAgICpcbiAgICogVGhlIHRyYW5zYWN0aW9uIGNhbiBiZSByZWNyZWF0ZWQgaWYgZWl0aGVyXG4gICAqIOKAkyB0aGVyZSBpcyBhbiB4cHJ2XG4gICAqIOKAkyB0aGVyZSBpcyBhIHdhbGxldFBhc3NwaHJhc2UgYW5kIHRoZSB3YWxsZXQgaXMgbm90IGNvbGQgKGJlY2F1c2UgaWYgaXQncyBjb2xkLCB0aGUgcGFzc3BocmFzZSBpcyBvZiBsaXR0bGUgdXNlKVxuICAgKlxuICAgKiBUaGVyZWZvcmUsIGlmIG5laXRoZXIgb2YgdGhlc2UgaXMgdHJ1ZSwgdGhlIHRyYW5zYWN0aW9uIGNhbm5vdCBiZSByZWNyZWF0ZWQsIHdoaWNoIGlzIHJlZmxlY3RlZCBpbiB0aGUgaWZcbiAgICogc3RhdGVtZW50IGJlbG93LlxuICAgKlxuICAgKiBMaWdodG5pbmcgdHJhbnNhY3Rpb25zIGNhbm5vdCBiZSByZWNyZWF0ZWQuXG4gICAqL1xuICBwcml2YXRlIGNhblJlY3JlYXRlVHJhbnNhY3Rpb24ocGFyYW1zOiBBcHByb3ZlT3B0aW9ucyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGlzQ29sZFdhbGxldCA9ICEhXy5nZXQodGhpcy53YWxsZXQsICdfd2FsbGV0LmlzQ29sZCcpO1xuICAgIGNvbnN0IGlzT0ZDV2FsbGV0ID0gdGhpcy5iYXNlQ29pbi5nZXRGYW1pbHkoKSA9PT0gJ29mYyc7IC8vIE9mZi1jaGFpbiB0cmFuc2FjdGlvbnMgZG9uJ3QgbmVlZCB0byBiZSByZWJ1aWx0XG4gICAgY29uc3QgaXNMaWdodG5pbmdXYWxsZXQgPSB0aGlzLmJhc2VDb2luLmdldEZhbWlseSgpID09PSAnbG5idGMnO1xuICAgIGlmIChpc0xpZ2h0bmluZ1dhbGxldCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmICghcGFyYW1zLnhwcnYgJiYgIShwYXJhbXMud2FsbGV0UGFzc3BocmFzZSAmJiAhaXNDb2xkV2FsbGV0ICYmICFpc09GQ1dhbGxldCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBJZiB0aGVyZSBhcmUgbm8gcmVjaXBpZW50cywgdGhlbiB0aGUgdHJhbnNhY3Rpb24gY2Fubm90IGJlIHJlY3JlYXRlZFxuICAgIGNvbnN0IHJlY2lwaWVudHMgPSB0aGlzLmluZm8oKT8udHJhbnNhY3Rpb25SZXF1ZXN0Py5idWlsZFBhcmFtcz8ucmVjaXBpZW50cyB8fCBbXTtcbiAgICBjb25zdCB0eXBlID0gdGhpcy5pbmZvKCk/LnRyYW5zYWN0aW9uUmVxdWVzdD8uYnVpbGRQYXJhbXM/LnR5cGU7XG5cbiAgICAvLyBXZSBvbmx5IHdhbnQgdG8gbm90IHJlY3JlYXRlIHRyYW5zYWN0aW9ucyB3aXRoIG5vIHJlY2lwaWVudHMgaWYgaXQgaXMgYSBVVFhPIGNvaW4uXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbiAgICByZXR1cm4gIShcbiAgICAgIHV0eG9saWIuaXNWYWxpZE5ldHdvcmsoKHRoaXMuYmFzZUNvaW4gYXMgYW55KS5uZXR3b3JrKSAmJlxuICAgICAgcmVjaXBpZW50cy5sZW5ndGggPT09IDAgJiZcbiAgICAgIHR5cGUgIT09ICdjb25zb2xpZGF0ZSdcbiAgICApO1xuICB9XG5cbiAgLypcbiAgICogSW50ZXJuYWwgaGVscGVyIGZ1bmN0aW9uIHRvIGdldCB0aGUgc2VyaWFsaXplZCB0cmFuc2FjdGlvbiB3aGljaCBpcyBiZWluZyBhcHByb3ZlZC5cbiAgICogSWYgdGhpcyBQQSBpcyBvZiB0eXBlICd0cmFuc2FjdGlvblJlcXVlc3QnIHRoaXMgZnVuY3Rpb24gd2lsbCB0cnkgdG8gcmVidWlsZCBhbmQgcmVzaWduIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0FwcHJvdmVPcHRpb25zfSBwYXJhbXNcbiAgICogQHBhcmFtIHtib29sZWFufSBjYW5SZWNyZWF0ZVRyYW5zYWN0aW9uIC1cbiAgICogQHBhcmFtIHtSZXF1ZXN0VHJhY2VyfSByZXFJZCBpZCB0cmFjZXJcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcHJlQXBwcm92ZShwYXJhbXM6IEFwcHJvdmVPcHRpb25zID0ge30sIHJlcUlkOiBJUmVxdWVzdFRyYWNlcik6IFByb21pc2U8UHJlQXBwcm92ZVJlc3VsdCB8IHVuZGVmaW5lZD4ge1xuICAgIC8vIFRyYW5zYWN0aW9uUmVxdWVzdExpdGUgb3IgTXVsdGlzaWcgdHgncyBtdXN0IHNpZ24gYmVmb3JlIHBlbmRpbmcgYXBwcm92YWwgaXMgYXBwcm92ZWRcbiAgICAvLyBSZS1zaWduZWQgdHggaXMgcHJvdmlkZWQgdG8gdGhlIHBlbmRpbmcgYXBwcm92YWwgYXBpXG4gICAgaWYgKHRoaXMudHlwZSgpID09PSBUeXBlLlRSQU5TQUNUSU9OX1JFUVVFU1QpIHtcbiAgICAgIC8qXG4gICAgICAgKiBJZiB0aGlzIGlzIGEgcmVxdWVzdCBmb3IgYXBwcm92aW5nIGEgdHJhbnNhY3Rpb24sIGRlcGVuZGluZyBvbiB3aGV0aGVyIHRoaXMgdXNlciBoYXMgYSBwcml2YXRlIGtleSB0byB0aGUgd2FsbGV0XG4gICAgICAgKiAoc29tZSBhZG1pbnMgbWF5IG5vdCBoYXZlIHRoZSBzcGVuZCBwZXJtaXNzaW9uKSwgdGhlIHRyYW5zYWN0aW9uIGNvdWxkIGVpdGhlciBiZSByZWJyb2FkY2FzdCBhcyBpcywgb3IgaXQgY291bGRcbiAgICAgICAqIGJlIHJlY29uc3RydWN0ZWQuIEl0IGlzIHByZWZlcmFibGUgdG8gcmVjb25zdHJ1Y3QgYSB0eCBpbiBvcmRlciB0byBhZGhlcmUgdG8gdGhlIGxhdGVzdCBuZXR3b3JrIGNvbmRpdGlvbnNcbiAgICAgICAqIHN1Y2ggYXMgbmV3ZXIgdW5zcGVudHMsIGRpZmZlcmVudCBmZWVzLCBvciBhIGhpZ2hlciBzZXF1ZW5jZSBpZFxuICAgICAgICovXG4gICAgICBpZiAocGFyYW1zLnR4KSB7XG4gICAgICAgIC8vIHRoZSBhcHByb3ZhbCB0eCB3YXMgcmVjb25zdHJ1Y3RlZCBhbmQgZXhwbGljaXRseSBzcGVjaWZpZWQgLSBwYXNzIGl0IHRocm91Z2hcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0eEhleDogcGFyYW1zLnR4LFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICAvLyB0aGlzIHVzZXIgbWF5IG5vdCBoYXZlIHNwZW5kaW5nIHByaXZpbGVnZXMgb3IgYSBwYXNzcGhyYXNlIG1heSBub3QgaGF2ZSBiZWVuIHBhc3NlZCBpblxuICAgICAgaWYgKCF0aGlzLmNhblJlY3JlYXRlVHJhbnNhY3Rpb24ocGFyYW1zKSkge1xuICAgICAgICAvLyBJZiB0aGlzIGlzIGEgVHJhbnNhY3Rpb25SZXF1ZXN0LCB0aGVuIHRoZSB0eFJlcXVlc3QgYWxyZWFkeSBoYXMgdGhlIHVuc2lnbmVkIHRyYW5zYWN0aW9uXG4gICAgICAgIGlmICh0aGlzLl9wZW5kaW5nQXBwcm92YWwudHhSZXF1ZXN0SWQpIHtcbiAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIC8vIElmIHRoaXMgaXMgYSBNdWx0aVNpZywgdGhlbiB3ZSBuZWVkIHRvIGZldGNoIHRoZSBoYWxmIHNpZ25lZCB0eCB0byBwcm9wYWdhdGUgdG8gdGhlIGFwcHJvdmFsIEFQSVxuICAgICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IF8uZ2V0KFxuICAgICAgICAgIHRoaXMuaW5mbygpLFxuICAgICAgICAgIGB0cmFuc2FjdGlvblJlcXVlc3QuY29pblNwZWNpZmljLiR7dGhpcy5iYXNlQ29pbi50eXBlfWBcbiAgICAgICAgKSBhcyBQcmVBcHByb3ZlUmVzdWx0O1xuICAgICAgICBpZiAoIV8uaXNPYmplY3QodHJhbnNhY3Rpb24pKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0aGVyZSBpcyBuZWl0aGVyIGFuIG9yaWdpbmFsIHRyYW5zYWN0aW9uIG9iamVjdCBub3IgY2FuIGEgbmV3IG9uZSBiZSByZWNyZWF0ZWQnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJhbnNhY3Rpb247XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLl9wZW5kaW5nQXBwcm92YWwudHhSZXF1ZXN0SWQpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmVjcmVhdGVBbmRTaWduVFNTVHJhbnNhY3Rpb24ocGFyYW1zLCByZXFJZCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5yZWNyZWF0ZUFuZFNpZ25UcmFuc2FjdGlvbihwYXJhbXMsIHJlcUlkKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW50ZXJuYWwgaGVscGVyIGZ1bmN0aW9uIHRvIHBlcmZvcm0gYW55IHBvc3QtYXBwcm92YWwgYWN0aW9ucy5cbiAgICogSWYgdHlwZSBpcyAndHJhbnNhY3Rpb25SZXF1ZXN0RnVsbCcsIHRoaXMgd2lsbCBzaWduIHRoZSB0eFJlcXVlc3RGdWxsIGlmIHBvc3NpYmxlXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogQHBhcmFtIHJlcUlkXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHBvc3RBcHByb3ZlKHBhcmFtczogQXBwcm92ZU9wdGlvbnMgPSB7fSwgcmVxSWQ6IElSZXF1ZXN0VHJhY2VyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgc3dpdGNoICh0aGlzLnR5cGUoKSkge1xuICAgICAgY2FzZSBUeXBlLlRSQU5TQUNUSU9OX1JFUVVFU1RfRlVMTDpcbiAgICAgICAgaWYgKHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5zdGF0ZSA9PT0gU3RhdGUuQVBQUk9WRUQpIHtcbiAgICAgICAgICAvLyBBZnRlciB3ZSBhcHByb3ZlIGEgbGlnaHRuaW5nIHRyYW5zYWN0aW9uLCB3ZSBzaG91bGQgcHJvY2VlZCB3aXRoIHN1Ym1pdHRpbmcgdGhlIHBheW1lbnRcbiAgICAgICAgICBpZiAodGhpcy5iYXNlQ29pbi5nZXRGYW1pbHkoKSA9PT0gJ2xuYnRjJykge1xuICAgICAgICAgICAgYXNzZXJ0KHRoaXMuX3BlbmRpbmdBcHByb3ZhbC50eFJlcXVlc3RJZCwgJ01pc3NpbmcgdHhSZXF1ZXN0SWQnKTtcbiAgICAgICAgICAgIC8vIHRoaXMucG9wdWxhdGVXYWxsZXQgaXMgY2FsbGVkIGJlZm9yZSB0aGlzIHNvIHdlIHNob3VsZCBiZSBnb29kIGhlcmVcbiAgICAgICAgICAgIGFzc2VydCh0aGlzLndhbGxldD8uaWQoKSwgJ01pc3Npbmcgd2FsbGV0IGlkJyk7XG4gICAgICAgICAgICBhd2FpdCBzZW5kVHhSZXF1ZXN0KFxuICAgICAgICAgICAgICB0aGlzLmJpdGdvLFxuICAgICAgICAgICAgICB0aGlzLndhbGxldD8uaWQoKSBhcyBzdHJpbmcsXG4gICAgICAgICAgICAgIHRoaXMuX3BlbmRpbmdBcHByb3ZhbC50eFJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgUmVxdWVzdFR5cGUudHgsXG4gICAgICAgICAgICAgIHJlcUlkXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5jYW5SZWNyZWF0ZVRyYW5zYWN0aW9uKHBhcmFtcykgJiYgdGhpcy5iYXNlQ29pbi5zdXBwb3J0c1RzcygpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnJlY3JlYXRlQW5kU2lnblRTU1RyYW5zYWN0aW9uKHBhcmFtcywgcmVxSWQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gdG8gZW5zdXJlIHRoYXQgc2VsZi53YWxsZXQgaXMgc2V0XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHBvcHVsYXRlV2FsbGV0KCk6IFByb21pc2U8dW5kZWZpbmVkPiB7XG4gICAgaWYgKHRoaXMud2FsbGV0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIFRPRE8oV1AtMTM0MSk6IGNvbnNvbGlkYXRlL3NpbXBsaWZ5IHRoaXMgbG9naWNcbiAgICBzd2l0Y2ggKHRoaXMudHlwZSgpKSB7XG4gICAgICBjYXNlIFR5cGUuVFJBTlNBQ1RJT05fUkVRVUVTVDpcbiAgICAgICAgY29uc3QgdHJhbnNhY3Rpb25SZXF1ZXN0ID0gdGhpcy5pbmZvKCkudHJhbnNhY3Rpb25SZXF1ZXN0O1xuICAgICAgICBpZiAoXy5pc1VuZGVmaW5lZCh0cmFuc2FjdGlvblJlcXVlc3QpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIG9iamVjdCBwcm9wZXJ0eSB0cmFuc2FjdGlvblJlcXVlc3QnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHVwZGF0ZWRXYWxsZXQ6IElXYWxsZXQgPSBhd2FpdCB0aGlzLmJhc2VDb2luLndhbGxldHMoKS5nZXQoeyBpZDogdHJhbnNhY3Rpb25SZXF1ZXN0LnNvdXJjZVdhbGxldCB9KTtcblxuICAgICAgICBpZiAoXy5pc1VuZGVmaW5lZCh1cGRhdGVkV2FsbGV0KSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndW5leHBlY3RlZCAtIHVuYWJsZSB0byBnZXQgd2FsbGV0IHVzaW5nIHNvdXJjZXdhbGxldCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy53YWxsZXQgPSB1cGRhdGVkV2FsbGV0O1xuXG4gICAgICAgIGlmICh0aGlzLndhbGxldC5pZCgpICE9PSB0cmFuc2FjdGlvblJlcXVlc3Quc291cmNlV2FsbGV0KSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmV4cGVjdGVkIHNvdXJjZSB3YWxsZXQgZm9yIHBlbmRpbmcgYXBwcm92YWwnKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgVHlwZS5UUkFOU0FDVElPTl9SRVFVRVNUX0ZVTEw6XG4gICAgICAgIGNvbnN0IHdhbGxldElkID0gdGhpcy53YWxsZXRJZCgpO1xuICAgICAgICBpZiAoIXdhbGxldElkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmV4cGVjdGVkIGVycm9yLCBwZW5kaW5nQXBwcm92YWwud2FsbGV0IGlzIGV4cGVjdGVkIHRvIGJlIGRlZmluZWQhJyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy53YWxsZXQgPSBhd2FpdCB0aGlzLmJhc2VDb2luLndhbGxldHMoKS5nZXQoeyBpZDogdGhpcy53YWxsZXRJZCgpIH0pO1xuICAgICAgICBpZiAoIXRoaXMud2FsbGV0KSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmV4cGVjdGVkIC0gdW5hYmxlIHRvIGdldCB3YWxsZXQgdXNpbmcgcGVuZGluZ0FwcHJvdmFsLndhbGxldCcpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICByZXR1cm47XG4gIH1cbn1cbiJdfQ==

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


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