PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/@bitgo/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');
                        // todo: add test case for this
                        // add new transfer before sending tx
                        await this.bitgo
                            .post(this.bitgo.url('/wallet/' + this.wallet?.id() + '/txrequests/' + this._pendingApproval.txRequestId + '/transfers', 2))
                            .send()
                            .result();
                        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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Q0FBQyxDQUFDO2dCQUNuRSxDQUFDO2dCQUNELE1BQU07WUFDUixLQUFLLHNCQUFJLENBQUMsd0JBQXdCO2dCQUNoQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ2pDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztvQkFDZCxNQUFNLElBQUksS0FBSyxDQUFDLHFFQUFxRSxDQUFDLENBQUM7Z0JBQ3pGLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3pFLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ2pCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0VBQWdFLENBQUMsQ0FBQztnQkFDcEYsQ0FBQztnQkFDRCxNQUFNO1FBQ1YsQ0FBQztRQUNELE9BQU87SUFDVCxDQUFDO0NBQ0Y7QUEvY0QsMENBK2NDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAcHJldHRpZXJcbiAqL1xuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0ICogYXMgdXR4b2xpYiBmcm9tICdAYml0Z28vdXR4by1saWInO1xuaW1wb3J0IHsgSUJhc2VDb2luIH0gZnJvbSAnLi4vYmFzZUNvaW4nO1xuaW1wb3J0IHsgQml0R29CYXNlIH0gZnJvbSAnLi4vYml0Z29CYXNlJztcbmltcG9ydCB7XG4gIEFwcHJvdmVPcHRpb25zLFxuICBJUGVuZGluZ0FwcHJvdmFsLFxuICBPd25lclR5cGUsXG4gIFBlbmRpbmdBcHByb3ZhbERhdGEsXG4gIFBlbmRpbmdBcHByb3ZhbEluZm8sXG4gIFN0YXRlLFxuICBUeXBlLFxufSBmcm9tICcuLi9wZW5kaW5nQXBwcm92YWwnO1xuaW1wb3J0IHsgUmVxdWVzdFRyYWNlciwgUmVxdWVzdFR5cGUgfSBmcm9tICcuLi91dGlscyc7XG5pbXBvcnQgeyBJV2FsbGV0IH0gZnJvbSAnLi4vd2FsbGV0JztcbmltcG9ydCB7IEJ1aWxkUGFyYW1zIH0gZnJvbSAnLi4vd2FsbGV0L0J1aWxkUGFyYW1zJztcbmltcG9ydCB7IElSZXF1ZXN0VHJhY2VyIH0gZnJvbSAnLi4vLi4vYXBpJztcbmltcG9ydCBCYXNlVHNzVXRpbHMgZnJvbSAnLi4vdXRpbHMvdHNzL2Jhc2VUU1NVdGlscyc7XG5pbXBvcnQgRWRkc2FVdGlscyBmcm9tICcuLi91dGlscy90c3MvZWRkc2EnO1xuaW1wb3J0IHsgRWNkc2FNUEN2MlV0aWxzLCBFY2RzYVV0aWxzIH0gZnJvbSAnLi4vdXRpbHMvdHNzL2VjZHNhJztcbmltcG9ydCB7IEtleVNoYXJlIGFzIEVjZHNhS2V5U2hhcmUgfSBmcm9tICcuLi91dGlscy90c3MvZWNkc2EvdHlwZXMnO1xuaW1wb3J0IHsgS2V5U2hhcmUgYXMgRWRkc2FLZXlTaGFyZSB9IGZyb20gJy4uL3V0aWxzL3Rzcy9lZGRzYS90eXBlcyc7XG5pbXBvcnQgeyBzZW5kVHhSZXF1ZXN0IH0gZnJvbSAnLi4vdHNzL2NvbW1vbic7XG5pbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5cbnR5cGUgUHJlQXBwcm92ZVJlc3VsdCA9IHtcbiAgdHhIZXg6IHN0cmluZztcbiAgaGFsZlNpZ25lZD86IHN0cmluZztcbn07XG5cbnR5cGUgQXBwcm92ZVBlbmRpbmdBcHByb3ZhbFJlcXVlc3RCb2R5ID0ge1xuICBzdGF0ZTogJ2FwcHJvdmVkJztcbiAgb3RwOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGhhbGZTaWduZWQ/OiBzdHJpbmcgfCBPbWl0PFByZUFwcHJvdmVSZXN1bHQsICdoYWxmU2lnbmVkJz47XG59O1xuXG5leHBvcnQgY2xhc3MgUGVuZGluZ0FwcHJvdmFsIGltcGxlbWVudHMgSVBlbmRpbmdBcHByb3ZhbCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYml0Z286IEJpdEdvQmFzZTtcbiAgcHJpdmF0ZSByZWFkb25seSBiYXNlQ29pbjogSUJhc2VDb2luO1xuICBwcml2YXRlIHRzc1V0aWxzPzogQmFzZVRzc1V0aWxzPEVjZHNhS2V5U2hhcmUgfCBFZGRzYUtleVNoYXJlPjtcbiAgcHJpdmF0ZSB3YWxsZXQ/OiBJV2FsbGV0O1xuICBwcml2YXRlIF9wZW5kaW5nQXBwcm92YWw6IFBlbmRpbmdBcHByb3ZhbERhdGE7XG5cbiAgY29uc3RydWN0b3IoYml0Z286IEJpdEdvQmFzZSwgYmFzZUNvaW46IElCYXNlQ29pbiwgcGVuZGluZ0FwcHJvdmFsRGF0YTogUGVuZGluZ0FwcHJvdmFsRGF0YSwgd2FsbGV0PzogSVdhbGxldCkge1xuICAgIHRoaXMuYml0Z28gPSBiaXRnbztcbiAgICB0aGlzLmJhc2VDb2luID0gYmFzZUNvaW47XG4gICAgdGhpcy53YWxsZXQgPSB3YWxsZXQ7XG5cbiAgICBpZiAodGhpcy5iYXNlQ29pbi5zdXBwb3J0c1RzcygpKSB7XG4gICAgICBpZiAodGhpcy5iYXNlQ29pbi5nZXRNUENBbGdvcml0aG0oKSA9PT0gJ2VjZHNhJykge1xuICAgICAgICBpZiAodGhpcy53YWxsZXQ/Lm11bHRpc2lnVHlwZVZlcnNpb24oKSA9PT0gJ01QQ3YyJykge1xuICAgICAgICAgIHRoaXMudHNzVXRpbHMgPSBuZXcgRWNkc2FNUEN2MlV0aWxzKHRoaXMuYml0Z28sIHRoaXMuYmFzZUNvaW4sIHdhbGxldCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy50c3NVdGlscyA9IG5ldyBFY2RzYVV0aWxzKHRoaXMuYml0Z28sIHRoaXMuYmFzZUNvaW4sIHdhbGxldCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudHNzVXRpbHMgPSBuZXcgRWRkc2FVdGlscyh0aGlzLmJpdGdvLCB0aGlzLmJhc2VDb2luLCB3YWxsZXQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuX3BlbmRpbmdBcHByb3ZhbCA9IHBlbmRpbmdBcHByb3ZhbERhdGE7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBpZCBmb3IgdGhpcyBQZW5kaW5nQXBwcm92YWxcbiAgICovXG4gIGlkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5pZDtcbiAgfVxuXG4gIHRvSlNPTigpOiBQZW5kaW5nQXBwcm92YWxEYXRhIHtcbiAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgb3duZXIgdHlwZSAod2FsbGV0IG9yIGVudGVycHJpc2UpXG4gICAqIFBlbmRpbmcgYXBwcm92YWxzIGNhbiBiZSBhcHByb3ZlZCBvciBtb2RpZmllZCBieSBkaWZmZXJlbnQgc2NvcGVzIChkZXBlbmRpbmcgb24gaG93IHRoZXkgd2VyZSBjcmVhdGVkKVxuICAgKiBJZiBhIHBlbmRpbmcgYXBwcm92YWwgaXMgb3duZWQgYnkgYSB3YWxsZXQsIHRoZW4gaXQgY2FuIGJlIGFwcHJvdmVkIGJ5IGFkbWluaXN0cmF0b3JzIG9mIHRoZSB3YWxsZXRcbiAgICogSWYgYSBwZW5kaW5nIGFwcHJvdmFsIGlzIG93bmVkIGJ5IGFuIGVudGVycHJpc2UsIHRoZW4gaXQgY2FuIGJlIGFwcHJvdmVkIGJ5IGFkbWluaXN0cmF0b3JzIG9mIHRoZSBlbnRlcnByaXNlXG4gICAqL1xuICBvd25lclR5cGUoKTogT3duZXJUeXBlIHtcbiAgICBpZiAodGhpcy5fcGVuZGluZ0FwcHJvdmFsLndhbGxldCkge1xuICAgICAgcmV0dXJuIE93bmVyVHlwZS5XQUxMRVQ7XG4gICAgfSBlbHNlIGlmICh0aGlzLl9wZW5kaW5nQXBwcm92YWwuZW50ZXJwcmlzZSkge1xuICAgICAgcmV0dXJuIE93bmVyVHlwZS5FTlRFUlBSSVNFO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuZXhwZWN0ZWQgcGVuZGluZyBhcHByb3ZhbCBvd25lcjogbmVpdGhlciB3YWxsZXQgbm9yIGVudGVycHJpc2Ugd2FzIHByZXNlbnQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBpZCBvZiB0aGUgd2FsbGV0IHdoaWNoIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIFBlbmRpbmdBcHByb3ZhbFxuICAgKi9cbiAgd2FsbGV0SWQoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsLndhbGxldDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGVudGVycHJpc2UgSUQgdGhhdCBpcyBhc3NvY2lhdGVkIHdpdGggdGhpcyBQZW5kaW5nQXBwcm92YWxcbiAgICovXG4gIGVudGVycHJpc2VJZCgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9wZW5kaW5nQXBwcm92YWwuZW50ZXJwcmlzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHN0YXRlIG9mIHRoaXMgUGVuZGluZ0FwcHJvdmFsXG4gICAqL1xuICBzdGF0ZSgpOiBTdGF0ZSB7XG4gICAgcmV0dXJuIHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5zdGF0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGlkIG9mIHRoZSB1c2VyIHRoYXQgcGVyZm9ybWVkIHRoZSBhY3Rpb24gcmVzdWx0aW5nIGluIHRoaXMgUGVuZGluZ0FwcHJvdmFsXG4gICAqL1xuICBjcmVhdG9yKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5jcmVhdG9yO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgdHlwZSBvZiB0aGUgcGVuZGluZyBhcHByb3ZhbCAod2hhdCBpdCBhcHByb3ZlcylcbiAgICovXG4gIHR5cGUoKTogVHlwZSB7XG4gICAgaWYgKCF0aGlzLl9wZW5kaW5nQXBwcm92YWwuaW5mbykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdwZW5kaW5nIGFwcHJvdmFsIGluZm8gaXMgbm90IGF2YWlsYWJsZScpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLl9wZW5kaW5nQXBwcm92YWwuaW5mby50eXBlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBpbmZvcm1hdGlvbiBhYm91dCB0aGlzIFBlbmRpbmdBcHByb3ZhbFxuICAgKi9cbiAgaW5mbygpOiBQZW5kaW5nQXBwcm92YWxJbmZvIHtcbiAgICByZXR1cm4gdGhpcy5fcGVuZGluZ0FwcHJvdmFsLmluZm87XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBudW1iZXIgb2YgYXBwcm92YWxzIHRoYXQgYXJlIHJlcXVpcmVkIGZvciB0aGlzIFBlbmRpbmdBcHByb3ZhbCB0byBiZSBhcHByb3ZlZC5cbiAgICogRGVmYXVsdHMgdG8gMSBpZiBhcHByb3ZhbHNSZXF1aXJlZCBkb2Vzbid0IGV4aXN0IG9uIHRoZSBvYmplY3RcbiAgICovXG4gIGFwcHJvdmFsc1JlcXVpcmVkKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX3BlbmRpbmdBcHByb3ZhbC5hcHByb3ZhbHNSZXF1aXJlZCB8fCAxO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgdXJsIGZvciB0aGlzIFBlbmRpbmdBcHByb3ZhbCBmb3IgbWFraW5nIHJlcXVlc3RzIHRvIHRoZSBzZXJ2ZXIuXG4gICAqIEBwYXJhbSBleHRyYVxuICAgKi9cbiAgdXJsKGV4dHJhID0gJycpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmJhc2VDb2luLnVybCgnL3BlbmRpbmdhcHByb3ZhbHMvJyArIHRoaXMuaWQoKSArIGV4dHJhKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWZldGNoZXMgdGhpcyBQZW5kaW5nQXBwcm92YWwgZnJvbSB0aGUgc2VydmVyIGFuZCByZXR1cm5zIGl0LlxuICAgKlxuICAgKiBOb3RlIHRoYXQgdGhpcyBtdXRhdGVzIHRoZSBQZW5kaW5nQXBwcm92YWwgb2JqZWN0IGluIHBsYWNlLlxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqL1xuICBhc3luYyBnZXQocGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBuZXZlcj4gPSB7fSk6IFByb21pc2U8UGVuZGluZ0FwcHJvdmFsPiB7XG4gICAgdGhpcy5fcGVuZGluZ0FwcHJvdmFsID0gYXdhaXQgdGhpcy5iaXRnby5nZXQodGhpcy51cmwoKSkucmVzdWx0KCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGlzIFBlbmRpbmdBcHByb3ZhbCB0byBhbiBhcHByb3ZlZCBzdGF0ZVxuICAgKi9cbiAgYXN5bmMgYXBwcm92ZShwYXJhbXM6IEFwcHJvdmVPcHRpb25zID0ge30pOiBQcm9taXNlPGFueT4ge1xuICAgIHBhcmFtcy5wcmV2aWV3UGVuZGluZ1R4cyA9IHRydWU7XG4gICAgcGFyYW1zLnBlbmRpbmdBcHByb3ZhbElkID0gdGhpcy5pZCgpO1xuICAgIGNvbnN0IGNhblJlY3JlYXRlVHJhbnNhY3Rpb24gPSB0aGlzLmNhblJlY3JlYXRlVHJhbnNhY3Rpb24ocGFyYW1zKTtcbiAgICBjb25zdCByZXFJZCA9IG5ldyBSZXF1ZXN0VHJhY2VyKCk7XG4gICAgdGhpcy5iaXRnby5zZXRSZXF1ZXN0VHJhY2VyKHJlcUlkKTtcbiAgICBhd2FpdCB0aGlzLnBvcHVsYXRlV2FsbGV0KCk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSBhd2FpdCB0aGlzLnByZUFwcHJvdmUocGFyYW1zLCByZXFJZCk7XG5cbiAgICAgIGNvbnN0IGFwcHJvdmFsUGFyYW1zOiBBcHByb3ZlUGVuZGluZ0FwcHJvdmFsUmVxdWVzdEJvZHkgPSB7IHN0YXRlOiAnYXBwcm92ZWQnLCBvdHA6IHBhcmFtcy5vdHAgfTtcbiAgICAgIGlmICh0cmFuc2FjdGlvbikge1xuICAgICAgICAvLyBpZiB0aGUgdHJhbnNhY3Rpb24gYWxyZWFkeSBoYXMgYSBoYWxmIHNpZ25lZCBwcm9wZXJ0eSwgd2UgdGFrZSB0aGF0IGRpcmVjdGx5XG4gICAgICAgIGFwcHJvdmFsUGFyYW1zLmhhbGZTaWduZWQgPSB0cmFuc2FjdGlvbi5oYWxmU2lnbmVkIHx8IHRyYW5zYWN0aW9uO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmJpdGdvLnB1dCh0aGlzLnVybCgpKS5zZW5kKGFwcHJvdmFsUGFyYW1zKS5yZXN1bHQoKTtcblxuICAgICAgLy8gaWYgdGhlIHJlc3BvbnNlIGNvbWVzIHdpdGggYW4gZXJyb3IsIG1lYW5zIHRoYXQgdGhlIHRyYW5zYWN0aW9uIHRyaWdnZXJlZCBhbm90aGVyIGNvbmRpdGlvblxuICAgICAgaWYgKHJlc3BvbnNlLmhhc093blByb3BlcnR5KCdlcnJvcicpICYmIHJlc3BvbnNlLmhhc093blByb3BlcnR5KCdwZW5kaW5nQXBwcm92YWwnKSkge1xuICAgICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX3BlbmRpbmdBcHByb3ZhbCA9IHJlc3BvbnNlO1xuICAgICAgYXdhaXQgdGhpcy5wb3N0QXBwcm92ZShwYXJhbXMsIHJlcUlkKTtcblxuICAgICAgcmV0dXJuIHRoaXMuX3BlbmRpbmdBcHByb3ZhbDtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBpZiAoXG4gICAgICAgICFjYW5SZWNyZWF0ZVRyYW5zYWN0aW9uICYmXG4gICAgICAgIChlLm1lc3NhZ2UuaW5kZXhPZignY291bGQgbm90IGZpbmQgdW5zcGVudCBvdXRwdXQgZm9yIGlucHV0JykgIT09IC0xIHx8XG4gICAgICAgICAgZS5tZXNzYWdlLmluZGV4T2YoJ3RyYW5zYWN0aW9uIGNvbmZsaWN0cyB3aXRoIGFuIGV4aXN0aW5nIHRyYW5zYWN0aW9uIGluIHRoZSBzZW5kIHF1ZXVlJykgIT09IC0xKVxuICAgICAgKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndW5zcGVudHMgZXhwaXJlZCwgd2FsbGV0IHBhc3NwaHJhc2Ugb3IgeHBydiByZXF1aXJlZCB0byByZWNyZWF0ZSB0cmFuc2FjdGlvbicpO1xuICAgICAgfVxuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGlzIFBlbmRpbmdBcHByb3ZhbCB0byBhIHJlamVjdGVkIHN0YXRlXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICovXG4gIGFzeW5jIHJlamVjdChwYXJhbXM6IFJlY29yZDxzdHJpbmcsIG5ldmVyPiA9IHt9KTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5iaXRnby5wdXQodGhpcy51cmwoKSkuc2VuZCh7IHN0YXRlOiAncmVqZWN0ZWQnIH0pLnJlc3VsdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsaWFzIGZvciBQZW5kaW5nQXBwcm92YWwucmVqZWN0KClcbiAgICpcbiAgICogQGRlcHJlY2F0ZWRcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgY2FuY2VsKHBhcmFtczogUmVjb3JkPHN0cmluZywgbmV2ZXI+ID0ge30pOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLnJlamVjdChwYXJhbXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlY3JlYXRlIGFuZCBzaWduIFRTUyB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0FwcHJvdmVPcHRpb25zfSBwYXJhbXMgbmVlZGVkIHRvIGdldCB0eHMgYW5kIHVzZSB0aGUgd2FsbGV0UGFzc3BocmFzZSB0byB0c3Mgc2lnblxuICAgKiBAcGFyYW0ge1JlcXVlc3RUcmFjZXJ9IHJlcUlkIGlkIHRyYWNlci5cbiAgICovXG4gIGFzeW5jIHJlY3JlYXRlQW5kU2lnblRTU1RyYW5zYWN0aW9uKHBhcmFtczogQXBwcm92ZU9wdGlvbnMsIHJlcUlkOiBJUmVxdWVzdFRyYWNlcik6IFByb21pc2U8eyB0eEhleDogc3RyaW5nIH0+IHtcbiAgICBjb25zdCB7IHdhbGxldFBhc3NwaHJhc2UgfSA9IHBhcmFtcztcbiAgICBjb25zdCB0eFJlcXVlc3RJZCA9IHRoaXMuX3BlbmRpbmdBcHByb3ZhbC50eFJlcXVlc3RJZDtcblxuICAgIGlmICghdGhpcy53YWxsZXQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignV2FsbGV0IG5vdCBmb3VuZCcpO1xuICAgIH1cblxuICAgIGlmICghd2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd3YWxsZXRQYXNzcGhyYXNlIG5vdCBmb3VuZCcpO1xuICAgIH1cblxuICAgIGlmICghdHhSZXF1ZXN0SWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndHhSZXF1ZXN0SWQgbm90IGZvdW5kJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZGVjcnlwdGVkUHJ2ID0gYXdhaXQgdGhpcy53YWxsZXQuZ2V0UHJ2KHsgd2FsbGV0UGFzc3BocmFzZSB9KTtcbiAgICBjb25zdCB0eFJlcXVlc3QgPSBhd2FpdCB0aGlzLnRzc1V0aWxzIS5yZWNyZWF0ZVR4UmVxdWVzdCh0eFJlcXVlc3RJZCwgZGVjcnlwdGVkUHJ2LCByZXFJZCk7XG4gICAgaWYgKHR4UmVxdWVzdC5hcGlWZXJzaW9uID09PSAnbGl0ZScpIHtcbiAgICAgIGlmICghdHhSZXF1ZXN0LnVuc2lnbmVkVHhzIHx8IHR4UmVxdWVzdC51bnNpZ25lZFR4cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmV4cGVjdGVkIGVycm9yLCBubyB0cmFuc2FjdGlvbnMgZm91bmQgaW4gdHhSZXF1ZXN0LicpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHhIZXg6IHR4UmVxdWVzdC51bnNpZ25lZFR4c1swXS5zZXJpYWxpemVkVHhIZXgsXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoIXR4UmVxdWVzdC50cmFuc2FjdGlvbnMgfHwgdHhSZXF1ZXN0LnRyYW5zYWN0aW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmV4cGVjdGVkIGVycm9yLCBubyB0cmFuc2FjdGlvbnMgZm91bmQgaW4gdHhSZXF1ZXN0LicpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHhIZXg6IHR4UmVxdWVzdC50cmFuc2FjdGlvbnNbMF0udW5zaWduZWRUeC5zZXJpYWxpemVkVHhIZXgsXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNyZWF0ZSBhIHRyYW5zYWN0aW9uIGZvciBhIHBlbmRpbmcgYXBwcm92YWwgdG8gcmVzcG9uZCB0byB1cGRhdGVkIG5ldHdvcmsgY29uZGl0aW9uc1xuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSByZXFJZFxuICAgKi9cbiAgYXN5bmMgcmVjcmVhdGVBbmRTaWduVHJhbnNhY3Rpb24ocGFyYW1zOiBhbnkgPSB7fSwgcmVxSWQ/OiBJUmVxdWVzdFRyYWNlcik6IFByb21pc2U8YW55PiB7XG4gICAgLy8gdGhpcyBtZXRob2Qgb25seSBtYWtlcyBzZW5zZSB3aXRoIGV4aXN0aW5nIHRyYW5zYWN0aW9uIHJlcXVlc3RzXG4gICAgY29uc3QgdHJhbnNhY3Rpb25SZXF1ZXN0ID0gdGhpcy5pbmZvKCkudHJhbnNhY3Rpb25SZXF1ZXN0O1xuICAgIGlmIChfLmlzVW5kZWZpbmVkKHRyYW5zYWN0aW9uUmVxdWVzdCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2Fubm90IHJlY3JlYXRlIHRyYW5zYWN0aW9uIHdpdGhvdXQgdHJhbnNhY3Rpb24gcmVxdWVzdCcpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHRoaXMud2FsbGV0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgcmVjcmVhdGUgdHJhbnNhY3Rpb24gd2l0aG91dCB3YWxsZXQnKTtcbiAgICB9XG5cbiAgICBjb25zdCBvcmlnaW5hbFByZWJ1aWxkID0gdHJhbnNhY3Rpb25SZXF1ZXN0LmNvaW5TcGVjaWZpY1t0aGlzLmJhc2VDb2luLnR5cGVdO1xuXG4gICAgY29uc3QgcmVjaXBpZW50cyA9IHRyYW5zYWN0aW9uUmVxdWVzdC5yZWNpcGllbnRzO1xuICAgIGxldCBwcmVidWlsZFBhcmFtcyA9IF8uZXh0ZW5kKHt9LCBwYXJhbXMsIHsgcmVjaXBpZW50czogcmVjaXBpZW50cyB9LCB0cmFuc2FjdGlvblJlcXVlc3QuYnVpbGRQYXJhbXMpO1xuXG4gICAgaWYgKCFfLmlzVW5kZWZpbmVkKG9yaWdpbmFsUHJlYnVpbGQuaG9wVHJhbnNhY3Rpb24pKSB7XG4gICAgICBwcmVidWlsZFBhcmFtcy5ob3AgPSB0cnVlO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcVRyYWNlciA9IHJlcUlkIHx8IG5ldyBSZXF1ZXN0VHJhY2VyKCk7XG4gICAgaWYgKHRyYW5zYWN0aW9uUmVxdWVzdC5idWlsZFBhcmFtcyAmJiB0cmFuc2FjdGlvblJlcXVlc3QuYnVpbGRQYXJhbXMudHlwZSA9PT0gJ2NvbnNvbGlkYXRlJykge1xuICAgICAgLy8gY29uc29saWRhdGUgdGFnIGlzIGluIHRoZSBidWlsZCBwYXJhbXMgLSB0aGlzIGlzIGEgY29uc29saWRhdGlvbiB0cmFuc2FjdGlvbiwgc29cbiAgICAgIC8vIGl0IG5lZWRzIHRvIGJlIHJlYnVpbHQgdXNpbmcgdGhlIHNwZWNpYWwgY29uc29saWRhdGlvbiBidWlsZCByb3V0ZVxuICAgICAgdGhpcy5iaXRnby5zZXRSZXF1ZXN0VHJhY2VyKHJlcVRyYWNlcik7XG4gICAgICBwcmVidWlsZFBhcmFtcy5wcmVidWlsZFR4ID0gYXdhaXQgdGhpcy5iaXRnb1xuICAgICAgICAucG9zdCh0aGlzLndhbGxldC51cmwoYC9jb25zb2xpZGF0ZVVuc3BlbnRzYCkpXG4gICAgICAgIC5zZW5kKEJ1aWxkUGFyYW1zLmVuY29kZShwcmVidWlsZFBhcmFtcykpXG4gICAgICAgIC5yZXN1bHQoKTtcbiAgICAgIGRlbGV0ZSBwcmVidWlsZFBhcmFtcy5yZWNpcGllbnRzO1xuICAgIH1cblxuICAgIHByZWJ1aWxkUGFyYW1zID0gXy5leHRlbmQoe30sIHByZWJ1aWxkUGFyYW1zLCB7IHJlcUlkOiByZXFJZCB9KTtcbiAgICBjb25zdCBzaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IHRoaXMud2FsbGV0LnByZWJ1aWxkQW5kU2lnblRyYW5zYWN0aW9uKHByZWJ1aWxkUGFyYW1zKTtcbiAgICAvLyBjb21wYXJlIFBBWUdvIGZlZXNcbiAgICBjb25zdCBvcmlnaW5hbFBhcnNlZFRyYW5zYWN0aW9uID0gKGF3YWl0IHRoaXMuYmFzZUNvaW4ucGFyc2VUcmFuc2FjdGlvbih7XG4gICAgICB0eFBhcmFtczogcHJlYnVpbGRQYXJhbXMsXG4gICAgICB3YWxsZXQ6IHRoaXMud2FsbGV0LFxuICAgICAgdHhQcmVidWlsZDogb3JpZ2luYWxQcmVidWlsZCxcbiAgICB9KSkgYXMgYW55O1xuICAgIGNvbnN0IHJlY3JlYXRlZFBhcnNlZFRyYW5zYWN0aW9uID0gKGF3YWl0IHRoaXMuYmFzZUNvaW4ucGFyc2VUcmFuc2FjdGlvbih7XG4gICAgICB0eFBhcmFtczogcHJlYnVpbGRQYXJhbXMsXG4gICAgICB3YWxsZXQ6IHRoaXMud2FsbGV0LFxuICAgICAgdHhQcmVidWlsZDogc2lnbmVkVHJhbnNhY3Rpb24sXG4gICAgfSkpIGFzIGFueTtcblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHJlY3JlYXRlZFBhcnNlZFRyYW5zYWN0aW9uLmltcGxpY2l0RXh0ZXJuYWxTcGVuZEFtb3VudCkpIHtcbiAgICAgIHJldHVybiBzaWduZWRUcmFuc2FjdGlvbjtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICB0eXBlb2YgcmVjcmVhdGVkUGFyc2VkVHJhbnNhY3Rpb24uaW1wbGljaXRFeHRlcm5hbFNwZW5kQW1vdW50ICE9PSAnYmlnaW50JyAmJlxuICAgICAgIV8uaXNGaW5pdGUocmVjcmVhdGVkUGFyc2VkVHJhbnNhY3Rpb24uaW1wbGljaXRFeHRlcm5hbFNwZW5kQW1vdW50KVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbXBsaWNpdCBleHRlcm5hbCBzcGVuZCBhbW91bnQgY291bGQgbm90IGJlIGRldGVybWluZWQnKTtcbiAgICB9XG4gICAgaWYgKFxuICAgICAgIV8uaXNVbmRlZmluZWQob3JpZ2luYWxQYXJzZWRUcmFuc2FjdGlvbi5pbXBsaWNpdEV4dGVybmFsU3BlbmRBbW91bnQpICYmXG4gICAgICByZWNyZWF0ZWRQYXJzZWRUcmFuc2FjdGlvbi5pbXBsaWNpdEV4dGVybmFsU3BlbmRBbW91bnQgPiBvcmlnaW5hbFBhcnNlZFRyYW5zYWN0aW9uLmltcGxpY2l0RXh0ZXJuYWxTcGVuZEFtb3VudFxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdyZWNyZWF0ZWQgdHJhbnNhY3Rpb24gaXMgdXNpbmcgYSBoaWdoZXIgcGF5LWFzLXlvdS1nby1mZWUnKTtcbiAgICB9XG4gICAgcmV0dXJuIHNpZ25lZFRyYW5zYWN0aW9uO1xuICB9XG5cbiAgLypcbiAgICogQ29sZCB3YWxsZXRzIGNhbm5vdCByZWNyZWF0ZSB0cmFuc2FjdGlvbnMgaWYgdGhlIG9ubHkgdGhpbmcgcHJvdmlkZWQgaXMgdGhlIHdhbGxldCBwYXNzcGhyYXNlXG4gICAqXG4gICAqIFRoZSB0cmFuc2FjdGlvbiBjYW4gYmUgcmVjcmVhdGVkIGlmIGVpdGhlclxuICAgKiDigJMgdGhlcmUgaXMgYW4geHBydlxuICAgKiDigJMgdGhlcmUgaXMgYSB3YWxsZXRQYXNzcGhyYXNlIGFuZCB0aGUgd2FsbGV0IGlzIG5vdCBjb2xkIChiZWNhdXNlIGlmIGl0J3MgY29sZCwgdGhlIHBhc3NwaHJhc2UgaXMgb2YgbGl0dGxlIHVzZSlcbiAgICpcbiAgICogVGhlcmVmb3JlLCBpZiBuZWl0aGVyIG9mIHRoZXNlIGlzIHRydWUsIHRoZSB0cmFuc2FjdGlvbiBjYW5ub3QgYmUgcmVjcmVhdGVkLCB3aGljaCBpcyByZWZsZWN0ZWQgaW4gdGhlIGlmXG4gICAqIHN0YXRlbWVudCBiZWxvdy5cbiAgICpcbiAgICogTGlnaHRuaW5nIHRyYW5zYWN0aW9ucyBjYW5ub3QgYmUgcmVjcmVhdGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBjYW5SZWNyZWF0ZVRyYW5zYWN0aW9uKHBhcmFtczogQXBwcm92ZU9wdGlvbnMpOiBib29sZWFuIHtcbiAgICBjb25zdCBpc0NvbGRXYWxsZXQgPSAhIV8uZ2V0KHRoaXMud2FsbGV0LCAnX3dhbGxldC5pc0NvbGQnKTtcbiAgICBjb25zdCBpc09GQ1dhbGxldCA9IHRoaXMuYmFzZUNvaW4uZ2V0RmFtaWx5KCkgPT09ICdvZmMnOyAvLyBPZmYtY2hhaW4gdHJhbnNhY3Rpb25zIGRvbid0IG5lZWQgdG8gYmUgcmVidWlsdFxuICAgIGNvbnN0IGlzTGlnaHRuaW5nV2FsbGV0ID0gdGhpcy5iYXNlQ29pbi5nZXRGYW1pbHkoKSA9PT0gJ2xuYnRjJztcbiAgICBpZiAoaXNMaWdodG5pbmdXYWxsZXQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoIXBhcmFtcy54cHJ2ICYmICEocGFyYW1zLndhbGxldFBhc3NwaHJhc2UgJiYgIWlzQ29sZFdhbGxldCAmJiAhaXNPRkNXYWxsZXQpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gSWYgdGhlcmUgYXJlIG5vIHJlY2lwaWVudHMsIHRoZW4gdGhlIHRyYW5zYWN0aW9uIGNhbm5vdCBiZSByZWNyZWF0ZWRcbiAgICBjb25zdCByZWNpcGllbnRzID0gdGhpcy5pbmZvKCk/LnRyYW5zYWN0aW9uUmVxdWVzdD8uYnVpbGRQYXJhbXM/LnJlY2lwaWVudHMgfHwgW107XG4gICAgY29uc3QgdHlwZSA9IHRoaXMuaW5mbygpPy50cmFuc2FjdGlvblJlcXVlc3Q/LmJ1aWxkUGFyYW1zPy50eXBlO1xuXG4gICAgLy8gV2Ugb25seSB3YW50IHRvIG5vdCByZWNyZWF0ZSB0cmFuc2FjdGlvbnMgd2l0aCBubyByZWNpcGllbnRzIGlmIGl0IGlzIGEgVVRYTyBjb2luLlxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gICAgcmV0dXJuICEoXG4gICAgICB1dHhvbGliLmlzVmFsaWROZXR3b3JrKCh0aGlzLmJhc2VDb2luIGFzIGFueSkubmV0d29yaykgJiZcbiAgICAgIHJlY2lwaWVudHMubGVuZ3RoID09PSAwICYmXG4gICAgICB0eXBlICE9PSAnY29uc29saWRhdGUnXG4gICAgKTtcbiAgfVxuXG4gIC8qXG4gICAqIEludGVybmFsIGhlbHBlciBmdW5jdGlvbiB0byBnZXQgdGhlIHNlcmlhbGl6ZWQgdHJhbnNhY3Rpb24gd2hpY2ggaXMgYmVpbmcgYXBwcm92ZWQuXG4gICAqIElmIHRoaXMgUEEgaXMgb2YgdHlwZSAndHJhbnNhY3Rpb25SZXF1ZXN0JyB0aGlzIGZ1bmN0aW9uIHdpbGwgdHJ5IHRvIHJlYnVpbGQgYW5kIHJlc2lnbiB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtBcHByb3ZlT3B0aW9uc30gcGFyYW1zXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gY2FuUmVjcmVhdGVUcmFuc2FjdGlvbiAtXG4gICAqIEBwYXJhbSB7UmVxdWVzdFRyYWNlcn0gcmVxSWQgaWQgdHJhY2VyXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHByZUFwcHJvdmUocGFyYW1zOiBBcHByb3ZlT3B0aW9ucyA9IHt9LCByZXFJZDogSVJlcXVlc3RUcmFjZXIpOiBQcm9taXNlPFByZUFwcHJvdmVSZXN1bHQgfCB1bmRlZmluZWQ+IHtcbiAgICAvLyBUcmFuc2FjdGlvblJlcXVlc3RMaXRlIG9yIE11bHRpc2lnIHR4J3MgbXVzdCBzaWduIGJlZm9yZSBwZW5kaW5nIGFwcHJvdmFsIGlzIGFwcHJvdmVkXG4gICAgLy8gUmUtc2lnbmVkIHR4IGlzIHByb3ZpZGVkIHRvIHRoZSBwZW5kaW5nIGFwcHJvdmFsIGFwaVxuICAgIGlmICh0aGlzLnR5cGUoKSA9PT0gVHlwZS5UUkFOU0FDVElPTl9SRVFVRVNUKSB7XG4gICAgICAvKlxuICAgICAgICogSWYgdGhpcyBpcyBhIHJlcXVlc3QgZm9yIGFwcHJvdmluZyBhIHRyYW5zYWN0aW9uLCBkZXBlbmRpbmcgb24gd2hldGhlciB0aGlzIHVzZXIgaGFzIGEgcHJpdmF0ZSBrZXkgdG8gdGhlIHdhbGxldFxuICAgICAgICogKHNvbWUgYWRtaW5zIG1heSBub3QgaGF2ZSB0aGUgc3BlbmQgcGVybWlzc2lvbiksIHRoZSB0cmFuc2FjdGlvbiBjb3VsZCBlaXRoZXIgYmUgcmVicm9hZGNhc3QgYXMgaXMsIG9yIGl0IGNvdWxkXG4gICAgICAgKiBiZSByZWNvbnN0cnVjdGVkLiBJdCBpcyBwcmVmZXJhYmxlIHRvIHJlY29uc3RydWN0IGEgdHggaW4gb3JkZXIgdG8gYWRoZXJlIHRvIHRoZSBsYXRlc3QgbmV0d29yayBjb25kaXRpb25zXG4gICAgICAgKiBzdWNoIGFzIG5ld2VyIHVuc3BlbnRzLCBkaWZmZXJlbnQgZmVlcywgb3IgYSBoaWdoZXIgc2VxdWVuY2UgaWRcbiAgICAgICAqL1xuICAgICAgaWYgKHBhcmFtcy50eCkge1xuICAgICAgICAvLyB0aGUgYXBwcm92YWwgdHggd2FzIHJlY29uc3RydWN0ZWQgYW5kIGV4cGxpY2l0bHkgc3BlY2lmaWVkIC0gcGFzcyBpdCB0aHJvdWdoXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdHhIZXg6IHBhcmFtcy50eCxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgLy8gdGhpcyB1c2VyIG1heSBub3QgaGF2ZSBzcGVuZGluZyBwcml2aWxlZ2VzIG9yIGEgcGFzc3BocmFzZSBtYXkgbm90IGhhdmUgYmVlbiBwYXNzZWQgaW5cbiAgICAgIGlmICghdGhpcy5jYW5SZWNyZWF0ZVRyYW5zYWN0aW9uKHBhcmFtcykpIHtcbiAgICAgICAgLy8gSWYgdGhpcyBpcyBhIFRyYW5zYWN0aW9uUmVxdWVzdCwgdGhlbiB0aGUgdHhSZXF1ZXN0IGFscmVhZHkgaGFzIHRoZSB1bnNpZ25lZCB0cmFuc2FjdGlvblxuICAgICAgICBpZiAodGhpcy5fcGVuZGluZ0FwcHJvdmFsLnR4UmVxdWVzdElkKSB7XG4gICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZiB0aGlzIGlzIGEgTXVsdGlTaWcsIHRoZW4gd2UgbmVlZCB0byBmZXRjaCB0aGUgaGFsZiBzaWduZWQgdHggdG8gcHJvcGFnYXRlIHRvIHRoZSBhcHByb3ZhbCBBUElcbiAgICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSBfLmdldChcbiAgICAgICAgICB0aGlzLmluZm8oKSxcbiAgICAgICAgICBgdHJhbnNhY3Rpb25SZXF1ZXN0LmNvaW5TcGVjaWZpYy4ke3RoaXMuYmFzZUNvaW4udHlwZX1gXG4gICAgICAgICkgYXMgUHJlQXBwcm92ZVJlc3VsdDtcbiAgICAgICAgaWYgKCFfLmlzT2JqZWN0KHRyYW5zYWN0aW9uKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndGhlcmUgaXMgbmVpdGhlciBhbiBvcmlnaW5hbCB0cmFuc2FjdGlvbiBvYmplY3Qgbm9yIGNhbiBhIG5ldyBvbmUgYmUgcmVjcmVhdGVkJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRyYW5zYWN0aW9uO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5fcGVuZGluZ0FwcHJvdmFsLnR4UmVxdWVzdElkKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnJlY3JlYXRlQW5kU2lnblRTU1RyYW5zYWN0aW9uKHBhcmFtcywgcmVxSWQpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmVjcmVhdGVBbmRTaWduVHJhbnNhY3Rpb24ocGFyYW1zLCByZXFJZCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEludGVybmFsIGhlbHBlciBmdW5jdGlvbiB0byBwZXJmb3JtIGFueSBwb3N0LWFwcHJvdmFsIGFjdGlvbnMuXG4gICAqIElmIHR5cGUgaXMgJ3RyYW5zYWN0aW9uUmVxdWVzdEZ1bGwnLCB0aGlzIHdpbGwgc2lnbiB0aGUgdHhSZXF1ZXN0RnVsbCBpZiBwb3NzaWJsZVxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSByZXFJZFxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwb3N0QXBwcm92ZShwYXJhbXM6IEFwcHJvdmVPcHRpb25zID0ge30sIHJlcUlkOiBJUmVxdWVzdFRyYWNlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHN3aXRjaCAodGhpcy50eXBlKCkpIHtcbiAgICAgIGNhc2UgVHlwZS5UUkFOU0FDVElPTl9SRVFVRVNUX0ZVTEw6XG4gICAgICAgIGlmICh0aGlzLl9wZW5kaW5nQXBwcm92YWwuc3RhdGUgPT09IFN0YXRlLkFQUFJPVkVEKSB7XG4gICAgICAgICAgLy8gQWZ0ZXIgd2UgYXBwcm92ZSBhIGxpZ2h0bmluZyB0cmFuc2FjdGlvbiwgd2Ugc2hvdWxkIHByb2NlZWQgd2l0aCBzdWJtaXR0aW5nIHRoZSBwYXltZW50XG4gICAgICAgICAgaWYgKHRoaXMuYmFzZUNvaW4uZ2V0RmFtaWx5KCkgPT09ICdsbmJ0YycpIHtcbiAgICAgICAgICAgIGFzc2VydCh0aGlzLl9wZW5kaW5nQXBwcm92YWwudHhSZXF1ZXN0SWQsICdNaXNzaW5nIHR4UmVxdWVzdElkJyk7XG4gICAgICAgICAgICAvLyB0aGlzLnBvcHVsYXRlV2FsbGV0IGlzIGNhbGxlZCBiZWZvcmUgdGhpcyBzbyB3ZSBzaG91bGQgYmUgZ29vZCBoZXJlXG4gICAgICAgICAgICBhc3NlcnQodGhpcy53YWxsZXQ/LmlkKCksICdNaXNzaW5nIHdhbGxldCBpZCcpO1xuICAgICAgICAgICAgLy8gdG9kbzogYWRkIHRlc3QgY2FzZSBmb3IgdGhpc1xuICAgICAgICAgICAgLy8gYWRkIG5ldyB0cmFuc2ZlciBiZWZvcmUgc2VuZGluZyB0eFxuICAgICAgICAgICAgYXdhaXQgdGhpcy5iaXRnb1xuICAgICAgICAgICAgICAucG9zdChcbiAgICAgICAgICAgICAgICB0aGlzLmJpdGdvLnVybChcbiAgICAgICAgICAgICAgICAgICcvd2FsbGV0LycgKyB0aGlzLndhbGxldD8uaWQoKSArICcvdHhyZXF1ZXN0cy8nICsgdGhpcy5fcGVuZGluZ0FwcHJvdmFsLnR4UmVxdWVzdElkICsgJy90cmFuc2ZlcnMnLFxuICAgICAgICAgICAgICAgICAgMlxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAuc2VuZCgpXG4gICAgICAgICAgICAgIC5yZXN1bHQoKTtcbiAgICAgICAgICAgIGF3YWl0IHNlbmRUeFJlcXVlc3QoXG4gICAgICAgICAgICAgIHRoaXMuYml0Z28sXG4gICAgICAgICAgICAgIHRoaXMud2FsbGV0Py5pZCgpIGFzIHN0cmluZyxcbiAgICAgICAgICAgICAgdGhpcy5fcGVuZGluZ0FwcHJvdmFsLnR4UmVxdWVzdElkLFxuICAgICAgICAgICAgICBSZXF1ZXN0VHlwZS50eCxcbiAgICAgICAgICAgICAgcmVxSWRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmNhblJlY3JlYXRlVHJhbnNhY3Rpb24ocGFyYW1zKSAmJiB0aGlzLmJhc2VDb2luLnN1cHBvcnRzVHNzKCkpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucmVjcmVhdGVBbmRTaWduVFNTVHJhbnNhY3Rpb24ocGFyYW1zLCByZXFJZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEhlbHBlciBmdW5jdGlvbiB0byBlbnN1cmUgdGhhdCBzZWxmLndhbGxldCBpcyBzZXRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcG9wdWxhdGVXYWxsZXQoKTogUHJvbWlzZTx1bmRlZmluZWQ+IHtcbiAgICBpZiAodGhpcy53YWxsZXQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gVE9ETyhXUC0xMzQxKTogY29uc29saWRhdGUvc2ltcGxpZnkgdGhpcyBsb2dpY1xuICAgIHN3aXRjaCAodGhpcy50eXBlKCkpIHtcbiAgICAgIGNhc2UgVHlwZS5UUkFOU0FDVElPTl9SRVFVRVNUOlxuICAgICAgICBjb25zdCB0cmFuc2FjdGlvblJlcXVlc3QgPSB0aGlzLmluZm8oKS50cmFuc2FjdGlvblJlcXVlc3Q7XG4gICAgICAgIGlmIChfLmlzVW5kZWZpbmVkKHRyYW5zYWN0aW9uUmVxdWVzdCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgb2JqZWN0IHByb3BlcnR5IHRyYW5zYWN0aW9uUmVxdWVzdCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdXBkYXRlZFdhbGxldDogSVdhbGxldCA9IGF3YWl0IHRoaXMuYmFzZUNvaW4ud2FsbGV0cygpLmdldCh7IGlkOiB0cmFuc2FjdGlvblJlcXVlc3Quc291cmNlV2FsbGV0IH0pO1xuXG4gICAgICAgIGlmIChfLmlzVW5kZWZpbmVkKHVwZGF0ZWRXYWxsZXQpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmV4cGVjdGVkIC0gdW5hYmxlIHRvIGdldCB3YWxsZXQgdXNpbmcgc291cmNld2FsbGV0Jyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLndhbGxldCA9IHVwZGF0ZWRXYWxsZXQ7XG5cbiAgICAgICAgaWYgKHRoaXMud2FsbGV0LmlkKCkgIT09IHRyYW5zYWN0aW9uUmVxdWVzdC5zb3VyY2VXYWxsZXQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuZXhwZWN0ZWQgc291cmNlIHdhbGxldCBmb3IgcGVuZGluZyBhcHByb3ZhbCcpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBUeXBlLlRSQU5TQUNUSU9OX1JFUVVFU1RfRlVMTDpcbiAgICAgICAgY29uc3Qgd2FsbGV0SWQgPSB0aGlzLndhbGxldElkKCk7XG4gICAgICAgIGlmICghd2FsbGV0SWQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuZXhwZWN0ZWQgZXJyb3IsIHBlbmRpbmdBcHByb3ZhbC53YWxsZXQgaXMgZXhwZWN0ZWQgdG8gYmUgZGVmaW5lZCEnKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLndhbGxldCA9IGF3YWl0IHRoaXMuYmFzZUNvaW4ud2FsbGV0cygpLmdldCh7IGlkOiB0aGlzLndhbGxldElkKCkgfSk7XG4gICAgICAgIGlmICghdGhpcy53YWxsZXQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuZXhwZWN0ZWQgLSB1bmFibGUgdG8gZ2V0IHdhbGxldCB1c2luZyBwZW5kaW5nQXBwcm92YWwud2FsbGV0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIHJldHVybjtcbiAgfVxufVxuIl19

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


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