PHP WebShell

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

Просмотр файла: eos.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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Eos = void 0;
/**
 * @prettier
 */
const bignumber_js_1 = require("bignumber.js");
const secp256k1_1 = require("@bitgo/secp256k1");
const crypto_1 = require("crypto");
const eosjs_1 = require("eosjs");
const ecc = __importStar(require("eosjs-ecc"));
const _ = __importStar(require("lodash"));
const querystring = __importStar(require("querystring"));
const request = __importStar(require("superagent"));
const url = __importStar(require("url"));
const eosabiprovider_1 = require("./eosutil/eosabiprovider");
const utils_1 = require("./lib/utils");
const sdk_core_1 = require("@bitgo/sdk-core");
class NoopJsonRpc extends eosjs_1.JsonRpc {
    constructor() {
        super('');
    }
}
class NoopSignatureProvider {
    async getAvailableKeys() {
        throw new Error('noop signature provider implementation has no available keys');
    }
    async sign(args) {
        throw new Error('noop implementation is unable to sign');
    }
}
class Eos extends sdk_core_1.BaseCoin {
    static createInstance(bitgo) {
        return new Eos(bitgo);
    }
    getChainId() {
        return 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906'; // mainnet chain id
    }
    getChain() {
        return 'eos';
    }
    getFamily() {
        return 'eos';
    }
    getFullName() {
        return 'EOS';
    }
    getBaseFactor() {
        return 1e4;
    }
    get decimalPlaces() {
        return 4;
    }
    /** {@inheritDoc } **/
    supportsMultisig() {
        return true;
    }
    /** inherited doc */
    getDefaultMultisigType() {
        return sdk_core_1.multisigTypes.onchain;
    }
    /**
     * Flag for sending value of 0
     * @returns {boolean} True if okay to send 0 value, false otherwise
     */
    valuelessTransferAllowed() {
        return true;
    }
    /**
     * Get URLs of some active public nodes
     */
    getPublicNodeUrls() {
        return sdk_core_1.Environments[this.bitgo.getEnv()].eosNodeUrls;
    }
    /**
     * Generate secp256k1 key pair
     *
     * @param seed - Seed from which the new keypair should be generated, otherwise a random seed is used
     */
    generateKeyPair(seed) {
        if (!seed) {
            // An extended private key has both a normal 256 bit private key and a 256
            // bit chain code, both of which must be random. 512 bits is therefore the
            // maximum entropy and gives us maximum security against cracking.
            seed = (0, crypto_1.randomBytes)(512 / 8);
        }
        const extendedKey = secp256k1_1.bip32.fromSeed(seed);
        const xpub = extendedKey.neutered().toBase58();
        return {
            pub: xpub,
            prv: extendedKey.toBase58(),
        };
    }
    /**
     * Return boolean indicating whether input is valid public key for the coin.
     *
     * @param pub - the pub to be checked
     */
    isValidPub(pub) {
        try {
            return secp256k1_1.bip32.fromBase58(pub).isNeutered();
        }
        catch (e) {
            return false;
        }
    }
    /**
     * Return boolean indicating whether input is valid seed for the coin
     *
     * @param prv - the prv to be checked
     */
    isValidPrv(prv) {
        try {
            return !secp256k1_1.bip32.fromBase58(prv).isNeutered();
        }
        catch (e) {
            return false;
        }
    }
    /**
     * Evaluates whether a memo is valid
     *
     * @param value - the memo to be checked
     */
    isValidMemo({ value }) {
        return _.isString(value) && value.length <= 256;
    }
    /**
     * Return boolean indicating whether a memo id is valid
     *
     * @param memoId - the memo id to be checked
     */
    isValidMemoId(memoId) {
        return this.isValidMemo({ value: memoId });
    }
    /**
     * Process address into address and memo id
     * @param address - the address
     */
    getAddressDetails(address) {
        const destinationDetails = url.parse(address);
        const destinationAddress = destinationDetails.pathname;
        if (!destinationAddress) {
            throw new sdk_core_1.InvalidAddressError(`failed to parse address: ${address}`);
        }
        // EOS addresses have to be "human readable", which means up to 12 characters and only a-z1-5., i.e.mtoda1.bitgo
        // source: https://developers.eos.io/eosio-cpp/docs/naming-conventions
        if (!/^[a-z1-5.]*$/.test(destinationAddress) || destinationAddress.length > Eos.ADDRESS_LENGTH) {
            throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
        }
        // address doesn't have a memo id
        if (destinationDetails.pathname === address) {
            return {
                address: address,
                memoId: undefined,
            };
        }
        if (!destinationDetails.query) {
            throw new sdk_core_1.InvalidAddressError(`failed to parse query string: ${address}`);
        }
        const queryDetails = querystring.parse(destinationDetails.query);
        if (!queryDetails.memoId) {
            // if there are more properties, the query details need to contain the memoId property
            throw new sdk_core_1.InvalidAddressError(`invalid property in address: ${address}`);
        }
        if (Array.isArray(queryDetails.memoId) && queryDetails.memoId.length !== 1) {
            // valid addresses can only contain one memo id
            throw new sdk_core_1.InvalidAddressError(`invalid address '${address}', must contain exactly one memoId`);
        }
        const [memoId] = _.castArray(queryDetails.memoId);
        if (!this.isValidMemoId(memoId)) {
            throw new sdk_core_1.InvalidAddressError(`invalid address: '${address}', memoId is not valid`);
        }
        return {
            address: destinationAddress,
            memoId,
        };
    }
    /**
     * Convert a currency amount represented in base units (satoshi, wei, atoms, drops, stroops)
     * to big units (btc, eth, xrp, xlm)
     */
    baseUnitsToBigUnits(baseUnits) {
        const dividend = this.getBaseFactor();
        const bigNumber = new bignumber_js_1.BigNumber(baseUnits).dividedBy(dividend);
        // set the format so commas aren't added to large coin amounts
        return bigNumber.toFormat(this.decimalPlaces, null, { groupSeparator: '', decimalSeparator: '.' });
    }
    /**
     * Validate and return address with appended memo id
     *
     * @param address
     * @param memoId
     */
    normalizeAddress({ address, memoId }) {
        if (memoId && this.isValidMemoId(memoId)) {
            return `${address}?memoId=${memoId}`;
        }
        return address;
    }
    /**
     * Return boolean indicating whether input is valid public key for the coin
     *
     * @param address - the address to be checked
     */
    isValidAddress(address) {
        try {
            const addressDetails = this.getAddressDetails(address);
            return address === this.normalizeAddress(addressDetails);
        }
        catch (e) {
            return false;
        }
    }
    /**
     * @param address - the address to verify
     * @param rootAddress - the wallet's root address
     * @return true iff address is a wallet address (based on rootAddress)
     */
    async isWalletAddress({ address, rootAddress }) {
        if (!rootAddress || !_.isString(rootAddress)) {
            throw new Error('missing required string rootAddress');
        }
        if (!this.isValidAddress(address)) {
            throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
        }
        const addressDetails = this.getAddressDetails(address);
        const rootAddressDetails = this.getAddressDetails(rootAddress);
        if (!addressDetails || !rootAddressDetails) {
            return false;
        }
        if (addressDetails.address !== rootAddressDetails.address) {
            throw new sdk_core_1.UnexpectedAddressError(`address validation failure: ${addressDetails.address} vs ${rootAddressDetails.address}`);
        }
        return true;
    }
    /**
     * Assemble keychain and half-sign prebuilt transaction
     *
     * @param params
     * @param params.txPrebuild {Object} prebuild object returned by platform
     * @param params.prv {String} user prv
     * @returns {Promise<EosSignedTransaction>}
     */
    async signTransaction(params) {
        const prv = params.prv;
        const txHex = params.txPrebuild.txHex;
        const transaction = params.txPrebuild.transaction;
        const signBuffer = Buffer.from(txHex, 'hex');
        const privateKeyBuffer = secp256k1_1.bip32.fromBase58(prv).privateKey;
        if (!privateKeyBuffer) {
            throw new Error('no privateKey');
        }
        const signature = ecc.Signature.sign(signBuffer, privateKeyBuffer).toString();
        transaction.signatures.push(signature);
        const txParams = {
            transaction,
            txHex,
            recipients: params.txPrebuild.recipients,
            headers: params.txPrebuild.headers,
            txid: params.txPrebuild.txid,
        };
        return { halfSigned: txParams };
    }
    validateStakeActionData(stakeActionData) {
        if (stakeActionData.from !== stakeActionData.receiver) {
            throw new Error(`staker (${stakeActionData.from}) and receiver (${stakeActionData.receiver}) must be the same`);
        }
        if (stakeActionData.transfer !== 0) {
            throw new Error('cannot transfer funds as part of delegatebw action');
        }
        // stake_cpu_quantity is used as the amount because the BitGo platform only stakes cpu for voting transactions
        return {
            address: stakeActionData.from,
            amount: this.bigUnitsToBaseUnits(stakeActionData.stake_cpu_quantity.split(' ')[0]),
        };
    }
    validateUnstakeActionData(unstakeActionData) {
        if (unstakeActionData.from !== unstakeActionData.receiver) {
            throw new Error(`unstaker (${unstakeActionData.from}) and receiver (${unstakeActionData.receiver}) must be the same`);
        }
        const cpuAmount = new bignumber_js_1.BigNumber(unstakeActionData.unstake_cpu_quantity.split(' ')[0]);
        const netAmount = new bignumber_js_1.BigNumber(unstakeActionData.unstake_net_quantity.split(' ')[0]);
        const totalAmount = cpuAmount.plus(netAmount).toNumber();
        return {
            address: unstakeActionData.receiver,
            amount: this.bigUnitsToBaseUnits(totalAmount),
        };
    }
    static validateVoteActionData(voteActionData) {
        const proxyIsEmpty = _.isEmpty(voteActionData.proxy);
        const producersIsEmpty = _.isEmpty(voteActionData.producers);
        if ((proxyIsEmpty && producersIsEmpty) || (!proxyIsEmpty && !producersIsEmpty)) {
            throw new Error('voting transactions must specify either producers or proxy to vote for');
        }
        return {
            address: voteActionData.voter,
            proxy: voteActionData.proxy,
            producers: voteActionData.producers,
        };
    }
    static createTransactionIdHex(serializedTransactionBuffer) {
        return (0, crypto_1.createHash)('sha256').update(serializedTransactionBuffer).digest().toString('hex');
    }
    /**
     * Deserialize a transaction
     * @param transaction
     * @param headers
     */
    async deserializeTransaction({ transaction, headers, }) {
        // create an eosjs API client
        const api = new eosjs_1.Api({
            abiProvider: new eosabiprovider_1.OfflineAbiProvider(),
            rpc: new NoopJsonRpc(),
            signatureProvider: new NoopSignatureProvider(),
            chainId: this.getChainId(),
            // Use a custom TextDecoder as the global TextDecoder leads to crashes in OVC / Electron.
            textDecoder: new utils_1.StringTextDecoder(),
            textEncoder: new TextEncoder(),
        });
        // type guards
        const isTransferActionData = (txActionData) => {
            return (txActionData.from !== undefined &&
                txActionData.to !== undefined &&
                txActionData.quantity !== undefined);
        };
        const isStakeActionData = (txActionData) => {
            return (txActionData.from !== undefined &&
                txActionData.receiver !== undefined &&
                txActionData.transfer !== undefined &&
                txActionData.stake_cpu_quantity !== undefined);
        };
        const isUnstakeActionData = (txActionData) => {
            return (txActionData.from !== undefined &&
                txActionData.receiver !== undefined &&
                txActionData.unstake_cpu_quantity !== undefined &&
                txActionData.unstake_net_quantity !== undefined);
        };
        const isVoteActionData = (txActionData) => {
            return txActionData.voter !== undefined;
        };
        const isRefundActionData = (txActionData) => {
            return txActionData.owner !== undefined;
        };
        // deserializeTransaction
        const serializedTxBuffer = Buffer.from(transaction.packed_trx, 'hex');
        const deserializedTxJsonFromPackedTrx = await api.deserializeTransactionWithActions(serializedTxBuffer);
        if (!deserializedTxJsonFromPackedTrx) {
            throw new Error('could not process transaction from txHex');
        }
        const tx = deserializedTxJsonFromPackedTrx;
        // validate context free actions
        if (tx.context_free_actions.length !== 0) {
            if (tx.context_free_actions.length !== 1) {
                throw new Error('number of context free actions must be 1');
            }
            if (!_.isEqual(_.pick(tx.context_free_actions[0], ['account', 'authorization', 'name']), {
                account: 'eosio.null',
                authorization: [],
                name: 'nonce',
            }) ||
                _.isEmpty(tx.context_free_actions[0].data)) {
                throw new Error('the context free action is invalid');
            }
        }
        // Only support transactions with one (transfer | voteproducer) or two (delegatebw & voteproducer) actions
        if (tx.actions.length !== 1 && tx.actions.length !== 2) {
            throw new Error(`invalid number of actions: ${tx.actions.length}`);
        }
        const txAction = tx.actions[0];
        if (!txAction) {
            throw new Error('missing transaction action');
        }
        if (txAction.name === 'transfer') {
            // Transfers should only have 1 action
            if (tx.actions.length !== 1) {
                throw new Error(`transfers should only have 1 action: ${tx.actions.length} given`);
            }
            if (!isTransferActionData(txAction.data)) {
                throw new Error('Invalid or incomplete transfer action data');
            }
            const transferActionData = txAction.data;
            tx.address = transferActionData.to;
            tx.amount = this.bigUnitsToBaseUnits(transferActionData.quantity.split(' ')[0]);
            tx.memo = transferActionData.memo;
        }
        else if (txAction.name === 'delegatebw') {
            // The delegatebw action should only be part of voting transactions
            if (tx.actions.length !== 2) {
                throw new Error(`staking transactions that include the delegatebw action should have 2 actions: ${tx.actions.length} given`);
            }
            const txAction2 = tx.actions[1];
            if (txAction2.name !== 'voteproducer') {
                throw new Error(`invalid staking transaction action: ${txAction2.name}, expecting: voteproducer`);
            }
            if (!isStakeActionData(txAction.data) || !isVoteActionData(txAction2.data)) {
                throw new Error('Invalid or incomplete stake or vote action data');
            }
            const stakeActionData = txAction.data;
            const voteActionData = txAction2.data;
            const deserializedStakeAction = this.validateStakeActionData(stakeActionData);
            const deserializedVoteAction = Eos.validateVoteActionData(voteActionData);
            if (deserializedStakeAction.address !== deserializedVoteAction.address) {
                throw new Error(`staker (${deserializedStakeAction.address}) and voter (${deserializedVoteAction.address}) must be the same`);
            }
            tx.amount = deserializedStakeAction.amount;
            tx.proxy = deserializedVoteAction.proxy;
            tx.producers = deserializedVoteAction.producers;
        }
        else if (txAction.name === 'voteproducer') {
            if (tx.actions.length > 2) {
                throw new Error('voting transactions should not have more than 2 actions');
            }
            let deserializedStakeAction;
            if (tx.actions.length === 2) {
                const txAction2 = tx.actions[1];
                if (txAction2.name !== 'delegatebw') {
                    throw new Error(`invalid staking transaction action: ${txAction2.name}, expecting: delegatebw`);
                }
                if (!isStakeActionData(txAction.data)) {
                    throw new Error('Invalid or incomplete stake action data');
                }
                const stakeActionData = txAction.data;
                deserializedStakeAction = this.validateStakeActionData(stakeActionData);
            }
            if (!isVoteActionData(txAction.data)) {
                throw new Error('Invalid or incomplete vote action data');
            }
            const voteActionData = txAction.data;
            const deserializedVoteAction = Eos.validateVoteActionData(voteActionData);
            if (!!deserializedStakeAction && deserializedStakeAction.address !== deserializedVoteAction.address) {
                throw new Error(`staker (${deserializedStakeAction.address}) and voter (${deserializedVoteAction.address}) must be the same`);
            }
            tx.amount = !!deserializedStakeAction ? deserializedStakeAction.amount : '0';
            tx.proxy = deserializedVoteAction.proxy;
            tx.producers = deserializedVoteAction.producers;
        }
        else if (txAction.name === 'undelegatebw') {
            if (tx.actions.length !== 1) {
                throw new Error(`unstake should only have 1 action: ${tx.actions.length} given`);
            }
            if (!isUnstakeActionData(txAction.data)) {
                throw new Error('Invalid or incomplete unstake action data');
            }
            const unstakeActionData = txAction.data;
            const deserializedUnstakeAction = this.validateUnstakeActionData(unstakeActionData);
            tx.amount = deserializedUnstakeAction.amount;
            tx.address = deserializedUnstakeAction.address;
        }
        else if (txAction.name === 'refund') {
            if (tx.actions.length !== 1) {
                throw new Error(`refund should only have 1 action: ${tx.actions.length} given`);
            }
            if (!isRefundActionData(txAction.data)) {
                throw new Error('Invalid or incomplete refund action data');
            }
            const refundActionData = txAction.data;
            tx.address = refundActionData.owner;
            tx.amount = '0';
        }
        else {
            throw new Error(`invalid action: ${txAction.name}`);
        }
        // Get the tx id if tx headers were provided
        if (headers) {
            let rebuiltTransaction;
            try {
                // remove Z at the end
                if (headers.expiration.endsWith('Z')) {
                    headers.expiration = headers.expiration.slice(0, -1);
                }
                rebuiltTransaction = await api.transact({ ...tx, ...headers }, { sign: false, broadcast: false });
            }
            catch (e) {
                throw new Error('Could not build transaction to get transaction_id. Please check transaction or headers format.');
            }
            tx.transaction_id = Eos.createTransactionIdHex(rebuiltTransaction.serializedTransaction);
        }
        return tx;
    }
    /**
     * Explain/parse transaction
     * @param params - ExplainTransactionOptions
     */
    async explainTransaction(params) {
        let transaction;
        try {
            transaction = await this.deserializeTransaction(params);
        }
        catch (e) {
            throw new Error('invalid EOS transaction or headers: ' + e.toString());
        }
        return {
            displayOrder: [
                'id',
                'outputAmount',
                'changeAmount',
                'outputs',
                'changeOutputs',
                'fee',
                'memo',
                'proxy',
                'producers',
            ],
            id: transaction.transaction_id,
            changeOutputs: [],
            outputAmount: transaction.amount,
            changeAmount: 0,
            outputs: !!transaction.address ? [{ address: transaction.address, amount: transaction.amount }] : [],
            fee: {},
            memo: transaction.memo,
            proxy: transaction.proxy,
            producers: transaction.producers,
        };
    }
    /**
     * @deprecated
     */
    initiateRecovery(params) {
        throw new Error('deprecated method');
    }
    /**
     * Make a request to one of the public EOS nodes available
     * @param params.endpoint
     * @param params.payload
     */
    async getDataFromNode(params) {
        const nodeUrls = this.getPublicNodeUrls();
        for (const nodeUrl of nodeUrls) {
            try {
                return await request.post(nodeUrl + params.endpoint).send(params.payload);
            }
            catch (e) {
                // let's hope another call succeeds
            }
        }
        throw new Error(`Unable to call endpoint: ${params.endpoint} from nodes: ${_.join(nodeUrls, ', ')}`);
    }
    /**
     * Get EOS chain info from a public node
     */
    async getChainInfoFromNode() {
        const response = await this.getDataFromNode({ endpoint: '/v1/chain/get_info' });
        if (response.status !== 200) {
            throw new Error('Unable to fetch chain info');
        }
        return response.body;
    }
    /**
     * Get data specific to an account from a public node
     * @param address
     */
    async getAccountFromNode({ address }) {
        const response = await this.getDataFromNode({
            endpoint: '/v1/chain/get_account',
            payload: { account_name: address },
        });
        if (response.status !== 200) {
            throw new Error('Account not found');
        }
        return response.body;
    }
    /**
     * Get block data from a public node using its block number or block id
     * @param blockNumOrId
     */
    async getBlockFromNode({ blockNumOrId }) {
        const response = await this.getDataFromNode({
            endpoint: '/v1/chain/get_block',
            payload: { block_num_or_id: blockNumOrId },
        });
        if (response.status !== 200) {
            throw new Error('Block not found');
        }
        return response.body;
    }
    /**
     * Get headers for an EOS tx from a public node
     */
    async getTransactionHeadersFromNode() {
        const chainInfo = await this.getChainInfoFromNode();
        const headBlockInfoResult = await this.getBlockFromNode({ blockNumOrId: chainInfo.head_block_num });
        const expireSeconds = 28800; // maximum tx expire time of 8h
        const chainDate = new Date(chainInfo.head_block_time + 'Z').getTime();
        const expirationDate = new Date(chainDate + expireSeconds * 1000);
        return {
            expiration: expirationDate.toISOString(),
            ref_block_num: chainInfo.head_block_num & 0xffff,
            ref_block_prefix: headBlockInfoResult.ref_block_prefix,
        };
    }
    getTransferAction({ recipient, sender, amount, memo }) {
        return {
            account: 'eosio.token',
            name: 'transfer',
            authorization: [
                {
                    actor: sender,
                    permission: 'active',
                },
            ],
            data: {
                from: sender,
                to: recipient,
                quantity: `${this.baseUnitsToBigUnits(amount)} EOS`,
                memo: !_.isNil(memo) ? memo : '', // Memo must be defined, set it to empty string if it is not
            },
        };
    }
    /**
     * Sign a transaction with a key
     * @param signableTx
     * @param signingKey
     */
    signTx(signableTx, signingKey) {
        const signBuffer = Buffer.from(signableTx, 'hex');
        const privateKeyBuffer = signingKey.privateKey;
        return ecc.Signature.sign(signBuffer, privateKeyBuffer).toString();
    }
    /**
     * Builds a funds recovery transaction without BitGo
     * @param params
     */
    async recover(params) {
        if (!params.rootAddress) {
            throw new Error('missing required string rootAddress');
        }
        const isKrsRecovery = (0, sdk_core_1.getIsKrsRecovery)(params);
        const isUnsignedSweep = (0, sdk_core_1.getIsUnsignedSweep)(params);
        const { krsProvider } = params;
        if ((0, sdk_core_1.getIsKrsRecovery)(params)) {
            (0, sdk_core_1.checkKrsProvider)(this, krsProvider);
        }
        if (!this.isValidAddress(params.recoveryDestination)) {
            throw new Error('Invalid destination address!');
        }
        const keys = (0, sdk_core_1.getBip32Keys)(this.bitgo, params, { requireBitGoXpub: false });
        const rootAddressDetails = this.getAddressDetails(params.rootAddress);
        const account = await this.getAccountFromNode({ address: rootAddressDetails.address });
        if (!account.core_liquid_balance) {
            throw new Error('Could not find any balance to recovery for ' + params.rootAddress);
        }
        if (!account.permissions) {
            throw new Error('Could not find permissions for ' + params.rootAddress);
        }
        const userPub = ecc.PublicKey.fromBuffer(keys[0].publicKey).toString();
        const backupPub = ecc.PublicKey.fromBuffer(keys[1].publicKey).toString();
        const activePermission = _.find(account.permissions, { perm_name: 'active' });
        const requiredAuth = _.get(activePermission, 'required_auth');
        if (!requiredAuth) {
            throw new Error('Required auth for active permission not found in account');
        }
        if (requiredAuth.threshold !== 2) {
            throw new Error('Unexpected active permission threshold');
        }
        const foundPubs = {};
        const requiredAuthKeys = requiredAuth.keys;
        for (const signer of requiredAuthKeys) {
            if (signer.weight !== 1) {
                throw new Error('invalid signer weight');
            }
            // if it's a dupe of a pub we already know, block
            if (foundPubs[signer.key]) {
                throw new Error('duplicate signer key');
            }
            foundPubs[signer.key] = (foundPubs[signer.key] || 0) + 1;
        }
        if (foundPubs[userPub] !== 1 || foundPubs[backupPub] !== 1) {
            throw new Error('unexpected incidence frequency of user signer key');
        }
        const accountBalance = account.core_liquid_balance.split(' ')[0];
        const recoveryAmount = this.bigUnitsToBaseUnits(new bignumber_js_1.BigNumber(accountBalance).toFixed());
        const destinationAddress = params.recoveryDestination;
        const destinationAddressDetails = this.getAddressDetails(destinationAddress);
        const destinationAccount = await this.getAccountFromNode({ address: destinationAddressDetails.address });
        if (!destinationAccount) {
            throw new Error('Destination account not found');
        }
        const transactionHeaders = await this.getTransactionHeadersFromNode();
        if (!transactionHeaders) {
            throw new Error('Could not get transaction headers from node');
        }
        const headers = transactionHeaders;
        const nativeDate = new Date(headers.expiration);
        // drop milliseconds and trailing Z from expiration
        nativeDate.setMilliseconds(0);
        const expiration = nativeDate.toISOString();
        if (expiration.endsWith('Z')) {
            headers.expiration = expiration.slice(0, -1);
        }
        // create an offline eosjs API client
        const api = new eosjs_1.Api({
            rpc: new NoopJsonRpc(),
            signatureProvider: new NoopSignatureProvider(),
            abiProvider: new eosabiprovider_1.OfflineAbiProvider(),
            chainId: this.getChainId(),
            textDecoder: new TextDecoder(),
            textEncoder: new TextEncoder(),
        });
        const transferAction = this.getTransferAction({
            recipient: destinationAddressDetails.address,
            sender: rootAddressDetails.address,
            amount: new bignumber_js_1.BigNumber(recoveryAmount),
            memo: destinationAddressDetails.memoId,
        });
        let serializedTransaction;
        const tx = { actions: [transferAction] };
        try {
            serializedTransaction = await api.transact({ ...tx, ...headers }, { sign: false, broadcast: false });
        }
        catch (e) {
            throw new Error('Eos API error: Could not build transaction');
        }
        // create transaction object
        const serializedTransactionHex = Buffer.from(serializedTransaction.serializedTransaction).toString('hex');
        const transactionId = Eos.createTransactionIdHex(serializedTransaction.serializedTransaction);
        const txObject = {
            transaction: {
                compression: 'none',
                packed_trx: serializedTransactionHex,
                signatures: [],
            },
            txid: transactionId,
            recoveryAmount: accountBalance,
            coin: this.getChain(),
            txHex: '',
        };
        const signableTx = Buffer.concat([
            Buffer.from(this.getChainId(), 'hex'), // The ChainID representing the chain that we are on
            Buffer.from(serializedTransaction.serializedTransaction), // The serialized unsigned tx
            Buffer.from(new Uint8Array(32)), // Some padding
        ]).toString('hex');
        if (isUnsignedSweep) {
            txObject.txHex = signableTx;
            return txObject;
        }
        const userSignature = this.signTx(signableTx, keys[0]);
        txObject.transaction.signatures.push(userSignature);
        if (!isKrsRecovery) {
            const backupSignature = this.signTx(signableTx, keys[1]);
            txObject.transaction.signatures.push(backupSignature);
        }
        return txObject;
    }
    async parseTransaction(params) {
        return {};
    }
    /**
     * Verify that a transaction prebuild complies with the original intention
     *
     * @param params
     * @param params.txParams params used to build the transaction
     * @param params.txPrebuild the prebuilt transaction
     */
    async verifyTransaction(params) {
        const { txParams: txParams, txPrebuild: txPrebuild } = params;
        // check if the transaction has a txHex
        if (!txPrebuild.txHex) {
            throw new Error('missing required tx prebuild property txHex');
        }
        // construct transaction from txHex
        const txFromHex = Buffer.from(txPrebuild.txHex, 'hex');
        const txDataWithPadding = txFromHex.slice(32);
        const txData = txDataWithPadding.slice(0, txDataWithPadding.length - 32);
        const deserializedTxJson = await this.deserializeTransaction({
            transaction: { packed_trx: txData.toString('hex') },
            headers: txPrebuild.headers,
        });
        if (!deserializedTxJson) {
            throw new Error('could not process transaction from txHex');
        }
        const txJsonFromHex = deserializedTxJson;
        // check that if txParams has a txPrebuild, it should be the same as txPrebuild
        if (txParams.txPrebuild && !_.isEqual(txParams.txPrebuild, txPrebuild)) {
            throw new Error('inputs txParams.txPrebuild and txPrebuild expected to be equal but were not');
        }
        // check if prebuild has a transaction
        if (!txPrebuild.transaction) {
            throw new Error('missing required transaction in txPrebuild');
        }
        // check if transaction has a packed_trx
        if (!txPrebuild.transaction?.packed_trx) {
            throw new Error('missing required transaction.packed_trx in txPrebuild');
        }
        // construct transaction using packed_trx
        const deserializedTxJsonFromPackedTrx = await this.deserializeTransaction({
            transaction: { packed_trx: txPrebuild.transaction.packed_trx },
            headers: txPrebuild.headers,
        });
        if (!deserializedTxJsonFromPackedTrx) {
            throw new Error('could not process transaction from packed_trx');
        }
        const txJsonFromPackedTrx = deserializedTxJsonFromPackedTrx;
        // deep check of object from packed_trx and txHex
        if (!_.isEqual(txJsonFromPackedTrx, txJsonFromHex)) {
            throw new Error('unpacked packed_trx and unpacked txHex are not equal');
        }
        if (txParams.recipients.length > 1) {
            throw new Error('only 0 or 1 recipients are supported');
        }
        // check the amounts, recipient, and coin name for transfers
        if (txParams.recipients.length === 1) {
            const expectedOutput = txParams.recipients[0];
            // check output address and memoId
            const expectedOutputAddressAndMemoId = this.getAddressDetails(expectedOutput.address);
            const txHexAction = txJsonFromHex.actions[0];
            const txHexTransferAction = txHexAction.data;
            if (txHexTransferAction.to !== expectedOutputAddressAndMemoId.address) {
                throw new Error('txHex receive address does not match expected recipient address');
            }
            // check if txaction memoid is equal to address memo id only if address also has memoid present
            if (!_.isUndefined(expectedOutputAddressAndMemoId.memoId)) {
                if (txHexTransferAction.memo !== expectedOutputAddressAndMemoId.memoId) {
                    throw new Error('txHex receive memoId does not match expected recipient memoId');
                }
            }
            // check amount and coin
            const expectedOutputAmount = expectedOutput.amount;
            const actualAmountAndCoin = txHexTransferAction.quantity.split(' ');
            const actualOutputAmount = this.bigUnitsToBaseUnits(actualAmountAndCoin[0]);
            if (expectedOutputAmount !== actualOutputAmount) {
                throw new Error('txHex receive amount does not match expected recipient amount');
            }
            if (txPrebuild.coin === 'eos' || txPrebuild.coin === 'teos') {
                const expectedSymbol = _.isNil(txPrebuild.token) ? 'EOS' : txPrebuild.token.split(':')[1];
                if (actualAmountAndCoin[1] !== expectedSymbol) {
                    throw new Error('txHex receive symbol does not match expected recipient symbol');
                }
            }
            else {
                // this should never happen
                throw new Error('txHex coin name does not match expected coin name');
            }
        }
        return true;
    }
    /**
     * Generate a random EOS address.
     *
     * This is just a random string which abides by the EOS adddress constraints,
     * and is not actually checked for availability on the EOS blockchain.
     *
     * Current EOS address constraints are:
     * * Address must be exactly 12 characters
     * * Address must only contain lowercase letters and numbers 1-5
     * @returns a validly formatted EOS address, which may or may not actually be available on chain.
     */
    generateRandomAddress(params) {
        const address = [];
        while (address.length < 12) {
            const char = _.sample(Eos.VALID_ADDRESS_CHARS);
            if (!char) {
                throw new Error('failed to sample valid EOS address characters');
            }
            address.push(char);
        }
        return address.join('');
    }
}
exports.Eos = Eos;
Eos.VALID_ADDRESS_CHARS = '12345abcdefghijklmnopqrstuvwxyz'.split('');
Eos.ADDRESS_LENGTH = 12;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW9zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Vvcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7R0FFRztBQUNILCtDQUF5QztBQUN6QyxnREFBeUQ7QUFDekQsbUNBQWlEO0FBQ2pELGlDQUFtRTtBQUNuRSwrQ0FBaUM7QUFDakMsMENBQTRCO0FBQzVCLHlEQUEyQztBQUMzQyxvREFBc0M7QUFDdEMseUNBQTJCO0FBRTNCLDZEQUE4RDtBQUM5RCx1Q0FBZ0Q7QUFDaEQsOENBdUJ5QjtBQW9KekIsTUFBTSxXQUFZLFNBQVEsZUFBTztJQUMvQjtRQUNFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNaLENBQUM7Q0FDRjtBQUVELE1BQU0scUJBQXFCO0lBQ3pCLEtBQUssQ0FBQyxnQkFBZ0I7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyw4REFBOEQsQ0FBQyxDQUFDO0lBQ2xGLENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSSxDQUFDLElBQXlDO1FBQ2xELE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQztJQUMzRCxDQUFDO0NBQ0Y7QUFFRCxNQUFhLEdBQUksU0FBUSxtQkFBUTtJQUkvQixNQUFNLENBQUMsY0FBYyxDQUFDLEtBQWdCO1FBQ3BDLE9BQU8sSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDeEIsQ0FBQztJQUVELFVBQVU7UUFDUixPQUFPLGtFQUFrRSxDQUFDLENBQUMsbUJBQW1CO0lBQ2hHLENBQUM7SUFFRCxRQUFRO1FBQ04sT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsU0FBUztRQUNQLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELFdBQVc7UUFDVCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxhQUFhO1FBQ1gsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRUQsSUFBSSxh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R0FBRyxpQ0FBaUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDbEUsa0JBQWMsR0FBRyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwcmV0dGllclxuICovXG5pbXBvcnQgeyBCaWdOdW1iZXIgfSBmcm9tICdiaWdudW1iZXIuanMnO1xuaW1wb3J0IHsgYmlwMzIsIEJJUDMySW50ZXJmYWNlIH0gZnJvbSAnQGJpdGdvL3NlY3AyNTZrMSc7XG5pbXBvcnQgeyBjcmVhdGVIYXNoLCByYW5kb21CeXRlcyB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgeyBBcGksIEFwaUludGVyZmFjZXMsIEpzb25ScGMsIFJwY0ludGVyZmFjZXMgfSBmcm9tICdlb3Nqcyc7XG5pbXBvcnQgKiBhcyBlY2MgZnJvbSAnZW9zanMtZWNjJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCAqIGFzIHF1ZXJ5c3RyaW5nIGZyb20gJ3F1ZXJ5c3RyaW5nJztcbmltcG9ydCAqIGFzIHJlcXVlc3QgZnJvbSAnc3VwZXJhZ2VudCc7XG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcblxuaW1wb3J0IHsgT2ZmbGluZUFiaVByb3ZpZGVyIH0gZnJvbSAnLi9lb3N1dGlsL2Vvc2FiaXByb3ZpZGVyJztcbmltcG9ydCB7IFN0cmluZ1RleHREZWNvZGVyIH0gZnJvbSAnLi9saWIvdXRpbHMnO1xuaW1wb3J0IHtcbiAgQmFzZUNvaW4sXG4gIEJpdEdvQmFzZSxcbiAgY2hlY2tLcnNQcm92aWRlcixcbiAgRW52aXJvbm1lbnRzLFxuICBnZXRCaXAzMktleXMsXG4gIGdldElzS3JzUmVjb3ZlcnksXG4gIGdldElzVW5zaWduZWRTd2VlcCxcbiAgSGFsZlNpZ25lZEFjY291bnRUcmFuc2FjdGlvbiBhcyBCYXNlSGFsZlNpZ25lZFRyYW5zYWN0aW9uLFxuICBJbnZhbGlkQWRkcmVzc0Vycm9yLFxuICBLZXlQYWlyLFxuICBNdWx0aXNpZ1R5cGUsXG4gIG11bHRpc2lnVHlwZXMsXG4gIFBhcnNlZFRyYW5zYWN0aW9uLFxuICBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgUmVxdWVzdFRyYWNlcixcbiAgU2lnblRyYW5zYWN0aW9uT3B0aW9ucyBhcyBCYXNlU2lnblRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgVHJhbnNhY3Rpb25FeHBsYW5hdGlvbixcbiAgVW5leHBlY3RlZEFkZHJlc3NFcnJvcixcbiAgVmVyaWZpY2F0aW9uT3B0aW9ucyxcbiAgVmVyaWZ5QWRkcmVzc09wdGlvbnMgYXMgQmFzZVZlcmlmeUFkZHJlc3NPcHRpb25zLFxuICBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMgYXMgQmFzZVZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgV2FsbGV0LFxufSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuXG5pbnRlcmZhY2UgQWRkcmVzc0RldGFpbHMge1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIG1lbW9JZD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFb3NUeCB7XG4gIHNpZ25hdHVyZXM6IHN0cmluZ1tdO1xuICBwYWNrZWRfdHJ4OiBzdHJpbmc7XG4gIGNvbXByZXNzaW9uOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVjaXBpZW50IHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhbW91bnQ6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIEVvc1RyYW5zYWN0aW9uSGVhZGVycyB7XG4gIHJlZl9ibG9ja19wcmVmaXg6IG51bWJlcjtcbiAgcmVmX2Jsb2NrX251bTogbnVtYmVyO1xuICBleHBpcmF0aW9uPzogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgRW9zVHJhbnNhY3Rpb25BY3Rpb24ge1xuICBhY2NvdW50OiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgYXV0aG9yaXphdGlvbjogW3sgYWN0b3I6IHN0cmluZzsgcGVybWlzc2lvbjogc3RyaW5nIH1dO1xuICBkYXRhOiBUcmFuc2ZlckFjdGlvbkRhdGEgfCBTdGFrZUFjdGlvbkRhdGEgfCBWb3RlQWN0aW9uRGF0YTtcbn1cblxuaW50ZXJmYWNlIEVvc1RyYW5zYWN0aW9uUHJlYnVpbGQge1xuICByZWNpcGllbnRzOiBSZWNpcGllbnRbXTtcbiAgaGVhZGVyczogRW9zVHJhbnNhY3Rpb25IZWFkZXJzO1xuICB0eEhleDogc3RyaW5nOyAvLyBUaGUgc2lnbmFibGUgdHggaGV4IHN0cmluZ1xuICB0cmFuc2FjdGlvbjogRW9zVHg7XG4gIHR4aWQ6IHN0cmluZztcbiAgY29pbjogc3RyaW5nO1xuICAvLyBmdWxsIHRva2VuIG5hbWUgd2l0aCB0aGUgZm9ybWF0LCBbdF1lb3M6U1lNQk9MLiBUaGlzIHdpbGwgb25seSBiZSBwcmVzZW50IGZvciB0b2tlbiB0cmFuc2FjdGlvbnMuIGUuZy4gdGVvczpDSEVYLlxuICB0b2tlbj86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFb3NTaWduVHJhbnNhY3Rpb25QYXJhbXMgZXh0ZW5kcyBCYXNlU2lnblRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIHBydjogc3RyaW5nO1xuICB0eFByZWJ1aWxkOiBFb3NUcmFuc2FjdGlvblByZWJ1aWxkO1xuICByZWNpcGllbnRzOiBSZWNpcGllbnRbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFb3NWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMgZXh0ZW5kcyBCYXNlVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhQcmVidWlsZDogRW9zVHJhbnNhY3Rpb25QcmVidWlsZDtcbiAgdHhQYXJhbXM6IEVvc1NpZ25UcmFuc2FjdGlvblBhcmFtcztcbiAgd2FsbGV0OiBXYWxsZXQ7XG4gIHZlcmlmaWNhdGlvbj86IFZlcmlmaWNhdGlvbk9wdGlvbnM7XG4gIHJlcUlkPzogUmVxdWVzdFRyYWNlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFb3NIYWxmU2lnbmVkIHtcbiAgcmVjaXBpZW50czogUmVjaXBpZW50W107XG4gIGhlYWRlcnM6IEVvc1RyYW5zYWN0aW9uSGVhZGVycztcbiAgdHhIZXg6IHN0cmluZzsgLy8gVGhlIHNpZ25hYmxlIHR4IGhleCBzdHJpbmdcbiAgdHJhbnNhY3Rpb246IEVvc1R4O1xuICB0eGlkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW9zU2lnbmVkVHJhbnNhY3Rpb24gZXh0ZW5kcyBCYXNlSGFsZlNpZ25lZFRyYW5zYWN0aW9uIHtcbiAgaGFsZlNpZ25lZDogRW9zSGFsZlNpZ25lZDtcbn1cblxuaW50ZXJmYWNlIERlc2VyaWFsaXplZEVvc1RyYW5zYWN0aW9uIHtcbiAgZXhwaXJhdGlvbjogc3RyaW5nO1xuICByZWZfYmxvY2tfbnVtOiBzdHJpbmc7XG4gIHJlZl9ibG9ja19wcmVmaXg6IHN0cmluZztcbiAgbWF4X25ldF91c2FnZV93b3JkczogbnVtYmVyO1xuICBtYXhfY3B1X3VzYWdlX21zOiBudW1iZXI7XG4gIGRlbGF5X3NlYzogbnVtYmVyO1xuICBjb250ZXh0X2ZyZWVfYWN0aW9uczogRW9zVHJhbnNhY3Rpb25BY3Rpb25bXTtcbiAgYWN0aW9uczogRW9zVHJhbnNhY3Rpb25BY3Rpb25bXTtcbiAgdHJhbnNhY3Rpb25fZXh0ZW5zaW9uczogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXTtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhbW91bnQ6IHN0cmluZztcbiAgdHJhbnNhY3Rpb25faWQ6IHN0cmluZztcbiAgbWVtbz86IHN0cmluZztcbiAgcHJveHk/OiBzdHJpbmc7XG4gIHByb2R1Y2Vycz86IHN0cmluZ1tdO1xufVxuXG5pbnRlcmZhY2UgVHJhbnNmZXJBY3Rpb25EYXRhIHtcbiAgZnJvbTogc3RyaW5nO1xuICB0bzogc3RyaW5nO1xuICBxdWFudGl0eTogc3RyaW5nO1xuICBtZW1vPzogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgU3Rha2VBY3Rpb25EYXRhIHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhbW91bnQ6IHN0cmluZztcbiAgZnJvbTogc3RyaW5nO1xuICByZWNlaXZlcjogc3RyaW5nO1xuICB0cmFuc2ZlcjogbnVtYmVyO1xuICBzdGFrZV9jcHVfcXVhbnRpdHk6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIFVuc3Rha2VBY3Rpb25EYXRhIHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhbW91bnQ6IHN0cmluZztcbiAgZnJvbTogc3RyaW5nO1xuICByZWNlaXZlcjogc3RyaW5nO1xuICB1bnN0YWtlX2NwdV9xdWFudGl0eTogc3RyaW5nO1xuICB1bnN0YWtlX25ldF9xdWFudGl0eTogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgUmVmdW5kQWN0aW9uRGF0YSB7XG4gIGFkZHJlc3M6IHN0cmluZztcbiAgb3duZXI6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIFZvdGVBY3Rpb25EYXRhIHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBwcm94eTogc3RyaW5nO1xuICBwcm9kdWNlcnM6IHN0cmluZ1tdO1xuICB2b3Rlcjogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgRXhwbGFpblRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIHRyYW5zYWN0aW9uOiB7IHBhY2tlZF90cng6IHN0cmluZyB9O1xuICBoZWFkZXJzOiBFb3NUcmFuc2FjdGlvbkhlYWRlcnM7XG59XG5cbmludGVyZmFjZSBSZWNvdmVyeVRyYW5zYWN0aW9uIHtcbiAgdHJhbnNhY3Rpb246IEVvc1R4O1xuICB0eGlkOiBzdHJpbmc7XG4gIHJlY292ZXJ5QW1vdW50OiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBSZWNvdmVyeU9wdGlvbnMge1xuICB1c2VyS2V5OiBzdHJpbmc7IC8vIEJveCBBXG4gIGJhY2t1cEtleTogc3RyaW5nOyAvLyBCb3ggQlxuICBiaXRnb0tleT86IHN0cmluZzsgLy8gQm94IENcbiAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogc3RyaW5nO1xuICBrcnNQcm92aWRlcj86IHN0cmluZztcbiAgd2FsbGV0UGFzc3BocmFzZT86IHN0cmluZztcbiAgcm9vdEFkZHJlc3M/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBWZXJpZnlBZGRyZXNzT3B0aW9ucyBleHRlbmRzIEJhc2VWZXJpZnlBZGRyZXNzT3B0aW9ucyB7XG4gIHJvb3RBZGRyZXNzOiBzdHJpbmc7XG59XG5cbmNsYXNzIE5vb3BKc29uUnBjIGV4dGVuZHMgSnNvblJwYyB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCcnKTtcbiAgfVxufVxuXG5jbGFzcyBOb29wU2lnbmF0dXJlUHJvdmlkZXIgaW1wbGVtZW50cyBBcGlJbnRlcmZhY2VzLlNpZ25hdHVyZVByb3ZpZGVyIHtcbiAgYXN5bmMgZ2V0QXZhaWxhYmxlS2V5cygpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdub29wIHNpZ25hdHVyZSBwcm92aWRlciBpbXBsZW1lbnRhdGlvbiBoYXMgbm8gYXZhaWxhYmxlIGtleXMnKTtcbiAgfVxuXG4gIGFzeW5jIHNpZ24oYXJnczogQXBpSW50ZXJmYWNlcy5TaWduYXR1cmVQcm92aWRlckFyZ3MpOiBQcm9taXNlPFJwY0ludGVyZmFjZXMuUHVzaFRyYW5zYWN0aW9uQXJncz4ge1xuICAgIHRocm93IG5ldyBFcnJvcignbm9vcCBpbXBsZW1lbnRhdGlvbiBpcyB1bmFibGUgdG8gc2lnbicpO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBFb3MgZXh0ZW5kcyBCYXNlQ29pbiB7XG4gIHB1YmxpYyBzdGF0aWMgVkFMSURfQUREUkVTU19DSEFSUyA9ICcxMjM0NWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Jy5zcGxpdCgnJyk7XG4gIHB1YmxpYyBzdGF0aWMgQUREUkVTU19MRU5HVEggPSAxMjtcblxuICBzdGF0aWMgY3JlYXRlSW5zdGFuY2UoYml0Z286IEJpdEdvQmFzZSk6IEJhc2VDb2luIHtcbiAgICByZXR1cm4gbmV3IEVvcyhiaXRnbyk7XG4gIH1cblxuICBnZXRDaGFpbklkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdhY2EzNzZmMjA2YjhmYzI1YTZlZDQ0ZGJkYzY2NTQ3YzM2YzZjMzNlM2ExMTlmZmJlYWVmOTQzNjQyZjBlOTA2JzsgLy8gbWFpbm5ldCBjaGFpbiBpZFxuICB9XG5cbiAgZ2V0Q2hhaW4oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ2Vvcyc7XG4gIH1cblxuICBnZXRGYW1pbHkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ2Vvcyc7XG4gIH1cblxuICBnZXRGdWxsTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiAnRU9TJztcbiAgfVxuXG4gIGdldEJhc2VGYWN0b3IoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gMWU0O1xuICB9XG5cbiAgZ2V0IGRlY2ltYWxQbGFjZXMoKSB7XG4gICAgcmV0dXJuIDQ7XG4gIH1cblxuICAvKioge0Bpbmhlcml0RG9jIH0gKiovXG4gIHN1cHBvcnRzTXVsdGlzaWcoKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKiogaW5oZXJpdGVkIGRvYyAqL1xuICBnZXREZWZhdWx0TXVsdGlzaWdUeXBlKCk6IE11bHRpc2lnVHlwZSB7XG4gICAgcmV0dXJuIG11bHRpc2lnVHlwZXMub25jaGFpbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBGbGFnIGZvciBzZW5kaW5nIHZhbHVlIG9mIDBcbiAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgb2theSB0byBzZW5kIDAgdmFsdWUsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgdmFsdWVsZXNzVHJhbnNmZXJBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBVUkxzIG9mIHNvbWUgYWN0aXZlIHB1YmxpYyBub2Rlc1xuICAgKi9cbiAgZ2V0UHVibGljTm9kZVVybHMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBFbnZpcm9ubWVudHNbdGhpcy5iaXRnby5nZXRFbnYoKV0uZW9zTm9kZVVybHM7XG4gIH1cbiAgLyoqXG4gICAqIEdlbmVyYXRlIHNlY3AyNTZrMSBrZXkgcGFpclxuICAgKlxuICAgKiBAcGFyYW0gc2VlZCAtIFNlZWQgZnJvbSB3aGljaCB0aGUgbmV3IGtleXBhaXIgc2hvdWxkIGJlIGdlbmVyYXRlZCwgb3RoZXJ3aXNlIGEgcmFuZG9tIHNlZWQgaXMgdXNlZFxuICAgKi9cbiAgZ2VuZXJhdGVLZXlQYWlyKHNlZWQ/OiBCdWZmZXIpOiBLZXlQYWlyIHtcbiAgICBpZiAoIXNlZWQpIHtcbiAgICAgIC8vIEFuIGV4dGVuZGVkIHByaXZhdGUga2V5IGhhcyBib3RoIGEgbm9ybWFsIDI1NiBiaXQgcHJpdmF0ZSBrZXkgYW5kIGEgMjU2XG4gICAgICAvLyBiaXQgY2hhaW4gY29kZSwgYm90aCBvZiB3aGljaCBtdXN0IGJlIHJhbmRvbS4gNTEyIGJpdHMgaXMgdGhlcmVmb3JlIHRoZVxuICAgICAgLy8gbWF4aW11bSBlbnRyb3B5IGFuZCBnaXZlcyB1cyBtYXhpbXVtIHNlY3VyaXR5IGFnYWluc3QgY3JhY2tpbmcuXG4gICAgICBzZWVkID0gcmFuZG9tQnl0ZXMoNTEyIC8gOCk7XG4gICAgfVxuICAgIGNvbnN0IGV4dGVuZGVkS2V5ID0gYmlwMzIuZnJvbVNlZWQoc2VlZCk7XG4gICAgY29uc3QgeHB1YiA9IGV4dGVuZGVkS2V5Lm5ldXRlcmVkKCkudG9CYXNlNTgoKTtcbiAgICByZXR1cm4ge1xuICAgICAgcHViOiB4cHViLFxuICAgICAgcHJ2OiBleHRlbmRlZEtleS50b0Jhc2U1OCgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGlucHV0IGlzIHZhbGlkIHB1YmxpYyBrZXkgZm9yIHRoZSBjb2luLlxuICAgKlxuICAgKiBAcGFyYW0gcHViIC0gdGhlIHB1YiB0byBiZSBjaGVja2VkXG4gICAqL1xuICBpc1ZhbGlkUHViKHB1Yjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBiaXAzMi5mcm9tQmFzZTU4KHB1YikuaXNOZXV0ZXJlZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGlucHV0IGlzIHZhbGlkIHNlZWQgZm9yIHRoZSBjb2luXG4gICAqXG4gICAqIEBwYXJhbSBwcnYgLSB0aGUgcHJ2IHRvIGJlIGNoZWNrZWRcbiAgICovXG4gIGlzVmFsaWRQcnYocHJ2OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuICFiaXAzMi5mcm9tQmFzZTU4KHBydikuaXNOZXV0ZXJlZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXZhbHVhdGVzIHdoZXRoZXIgYSBtZW1vIGlzIHZhbGlkXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIHRoZSBtZW1vIHRvIGJlIGNoZWNrZWRcbiAgICovXG4gIGlzVmFsaWRNZW1vKHsgdmFsdWUgfTogeyB2YWx1ZTogc3RyaW5nIH0pOiBib29sZWFuIHtcbiAgICByZXR1cm4gXy5pc1N0cmluZyh2YWx1ZSkgJiYgdmFsdWUubGVuZ3RoIDw9IDI1NjtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgYSBtZW1vIGlkIGlzIHZhbGlkXG4gICAqXG4gICAqIEBwYXJhbSBtZW1vSWQgLSB0aGUgbWVtbyBpZCB0byBiZSBjaGVja2VkXG4gICAqL1xuICBpc1ZhbGlkTWVtb0lkKG1lbW9JZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNWYWxpZE1lbW8oeyB2YWx1ZTogbWVtb0lkIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFByb2Nlc3MgYWRkcmVzcyBpbnRvIGFkZHJlc3MgYW5kIG1lbW8gaWRcbiAgICogQHBhcmFtIGFkZHJlc3MgLSB0aGUgYWRkcmVzc1xuICAgKi9cbiAgZ2V0QWRkcmVzc0RldGFpbHMoYWRkcmVzczogc3RyaW5nKTogQWRkcmVzc0RldGFpbHMge1xuICAgIGNvbnN0IGRlc3RpbmF0aW9uRGV0YWlscyA9IHVybC5wYXJzZShhZGRyZXNzKTtcbiAgICBjb25zdCBkZXN0aW5hdGlvbkFkZHJlc3MgPSBkZXN0aW5hdGlvbkRldGFpbHMucGF0aG5hbWU7XG5cbiAgICBpZiAoIWRlc3RpbmF0aW9uQWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoYGZhaWxlZCB0byBwYXJzZSBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgLy8gRU9TIGFkZHJlc3NlcyBoYXZlIHRvIGJlIFwiaHVtYW4gcmVhZGFibGVcIiwgd2hpY2ggbWVhbnMgdXAgdG8gMTIgY2hhcmFjdGVycyBhbmQgb25seSBhLXoxLTUuLCBpLmUubXRvZGExLmJpdGdvXG4gICAgLy8gc291cmNlOiBodHRwczovL2RldmVsb3BlcnMuZW9zLmlvL2Vvc2lvLWNwcC9kb2NzL25hbWluZy1jb252ZW50aW9uc1xuICAgIGlmICghL15bYS16MS01Ll0qJC8udGVzdChkZXN0aW5hdGlvbkFkZHJlc3MpIHx8IGRlc3RpbmF0aW9uQWRkcmVzcy5sZW5ndGggPiBFb3MuQUREUkVTU19MRU5HVEgpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIGFkZHJlc3M6ICR7YWRkcmVzc31gKTtcbiAgICB9XG5cbiAgICAvLyBhZGRyZXNzIGRvZXNuJ3QgaGF2ZSBhIG1lbW8gaWRcbiAgICBpZiAoZGVzdGluYXRpb25EZXRhaWxzLnBhdGhuYW1lID09PSBhZGRyZXNzKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhZGRyZXNzOiBhZGRyZXNzLFxuICAgICAgICBtZW1vSWQ6IHVuZGVmaW5lZCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKCFkZXN0aW5hdGlvbkRldGFpbHMucXVlcnkpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBmYWlsZWQgdG8gcGFyc2UgcXVlcnkgc3RyaW5nOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgcXVlcnlEZXRhaWxzID0gcXVlcnlzdHJpbmcucGFyc2UoZGVzdGluYXRpb25EZXRhaWxzLnF1ZXJ5KTtcbiAgICBpZiAoIXF1ZXJ5RGV0YWlscy5tZW1vSWQpIHtcbiAgICAgIC8vIGlmIHRoZXJlIGFyZSBtb3JlIHByb3BlcnRpZXMsIHRoZSBxdWVyeSBkZXRhaWxzIG5lZWQgdG8gY29udGFpbiB0aGUgbWVtb0lkIHByb3BlcnR5XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBwcm9wZXJ0eSBpbiBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkocXVlcnlEZXRhaWxzLm1lbW9JZCkgJiYgcXVlcnlEZXRhaWxzLm1lbW9JZC5sZW5ndGggIT09IDEpIHtcbiAgICAgIC8vIHZhbGlkIGFkZHJlc3NlcyBjYW4gb25seSBjb250YWluIG9uZSBtZW1vIGlkXG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzICcke2FkZHJlc3N9JywgbXVzdCBjb250YWluIGV4YWN0bHkgb25lIG1lbW9JZGApO1xuICAgIH1cblxuICAgIGNvbnN0IFttZW1vSWRdID0gXy5jYXN0QXJyYXkocXVlcnlEZXRhaWxzLm1lbW9JZCk7XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRNZW1vSWQobWVtb0lkKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoYGludmFsaWQgYWRkcmVzczogJyR7YWRkcmVzc30nLCBtZW1vSWQgaXMgbm90IHZhbGlkYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGFkZHJlc3M6IGRlc3RpbmF0aW9uQWRkcmVzcyxcbiAgICAgIG1lbW9JZCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBjdXJyZW5jeSBhbW91bnQgcmVwcmVzZW50ZWQgaW4gYmFzZSB1bml0cyAoc2F0b3NoaSwgd2VpLCBhdG9tcywgZHJvcHMsIHN0cm9vcHMpXG4gICAqIHRvIGJpZyB1bml0cyAoYnRjLCBldGgsIHhycCwgeGxtKVxuICAgKi9cbiAgYmFzZVVuaXRzVG9CaWdVbml0cyhiYXNlVW5pdHM6IHN0cmluZyB8IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgZGl2aWRlbmQgPSB0aGlzLmdldEJhc2VGYWN0b3IoKTtcbiAgICBjb25zdCBiaWdOdW1iZXIgPSBuZXcgQmlnTnVtYmVyKGJhc2VVbml0cykuZGl2aWRlZEJ5KGRpdmlkZW5kKTtcbiAgICAvLyBzZXQgdGhlIGZvcm1hdCBzbyBjb21tYXMgYXJlbid0IGFkZGVkIHRvIGxhcmdlIGNvaW4gYW1vdW50c1xuICAgIHJldHVybiBiaWdOdW1iZXIudG9Gb3JtYXQodGhpcy5kZWNpbWFsUGxhY2VzLCBudWxsIGFzIGFueSwgeyBncm91cFNlcGFyYXRvcjogJycsIGRlY2ltYWxTZXBhcmF0b3I6ICcuJyB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbmQgcmV0dXJuIGFkZHJlc3Mgd2l0aCBhcHBlbmRlZCBtZW1vIGlkXG4gICAqXG4gICAqIEBwYXJhbSBhZGRyZXNzXG4gICAqIEBwYXJhbSBtZW1vSWRcbiAgICovXG4gIG5vcm1hbGl6ZUFkZHJlc3MoeyBhZGRyZXNzLCBtZW1vSWQgfTogQWRkcmVzc0RldGFpbHMpOiBzdHJpbmcge1xuICAgIGlmIChtZW1vSWQgJiYgdGhpcy5pc1ZhbGlkTWVtb0lkKG1lbW9JZCkpIHtcbiAgICAgIHJldHVybiBgJHthZGRyZXNzfT9tZW1vSWQ9JHttZW1vSWR9YDtcbiAgICB9XG4gICAgcmV0dXJuIGFkZHJlc3M7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGlucHV0IGlzIHZhbGlkIHB1YmxpYyBrZXkgZm9yIHRoZSBjb2luXG4gICAqXG4gICAqIEBwYXJhbSBhZGRyZXNzIC0gdGhlIGFkZHJlc3MgdG8gYmUgY2hlY2tlZFxuICAgKi9cbiAgaXNWYWxpZEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGFkZHJlc3NEZXRhaWxzID0gdGhpcy5nZXRBZGRyZXNzRGV0YWlscyhhZGRyZXNzKTtcbiAgICAgIHJldHVybiBhZGRyZXNzID09PSB0aGlzLm5vcm1hbGl6ZUFkZHJlc3MoYWRkcmVzc0RldGFpbHMpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIGFkZHJlc3MgLSB0aGUgYWRkcmVzcyB0byB2ZXJpZnlcbiAgICogQHBhcmFtIHJvb3RBZGRyZXNzIC0gdGhlIHdhbGxldCdzIHJvb3QgYWRkcmVzc1xuICAgKiBAcmV0dXJuIHRydWUgaWZmIGFkZHJlc3MgaXMgYSB3YWxsZXQgYWRkcmVzcyAoYmFzZWQgb24gcm9vdEFkZHJlc3MpXG4gICAqL1xuICBhc3luYyBpc1dhbGxldEFkZHJlc3MoeyBhZGRyZXNzLCByb290QWRkcmVzcyB9OiBWZXJpZnlBZGRyZXNzT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICghcm9vdEFkZHJlc3MgfHwgIV8uaXNTdHJpbmcocm9vdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgc3RyaW5nIHJvb3RBZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgYWRkcmVzc0RldGFpbHMgPSB0aGlzLmdldEFkZHJlc3NEZXRhaWxzKGFkZHJlc3MpO1xuICAgIGNvbnN0IHJvb3RBZGRyZXNzRGV0YWlscyA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMocm9vdEFkZHJlc3MpO1xuXG4gICAgaWYgKCFhZGRyZXNzRGV0YWlscyB8fCAhcm9vdEFkZHJlc3NEZXRhaWxzKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKGFkZHJlc3NEZXRhaWxzLmFkZHJlc3MgIT09IHJvb3RBZGRyZXNzRGV0YWlscy5hZGRyZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgVW5leHBlY3RlZEFkZHJlc3NFcnJvcihcbiAgICAgICAgYGFkZHJlc3MgdmFsaWRhdGlvbiBmYWlsdXJlOiAke2FkZHJlc3NEZXRhaWxzLmFkZHJlc3N9IHZzICR7cm9vdEFkZHJlc3NEZXRhaWxzLmFkZHJlc3N9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlbWJsZSBrZXljaGFpbiBhbmQgaGFsZi1zaWduIHByZWJ1aWx0IHRyYW5zYWN0aW9uXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogQHBhcmFtIHBhcmFtcy50eFByZWJ1aWxkIHtPYmplY3R9IHByZWJ1aWxkIG9iamVjdCByZXR1cm5lZCBieSBwbGF0Zm9ybVxuICAgKiBAcGFyYW0gcGFyYW1zLnBydiB7U3RyaW5nfSB1c2VyIHBydlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxFb3NTaWduZWRUcmFuc2FjdGlvbj59XG4gICAqL1xuICBhc3luYyBzaWduVHJhbnNhY3Rpb24ocGFyYW1zOiBFb3NTaWduVHJhbnNhY3Rpb25QYXJhbXMpOiBQcm9taXNlPEVvc1NpZ25lZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3QgcHJ2OiBzdHJpbmcgPSBwYXJhbXMucHJ2O1xuICAgIGNvbnN0IHR4SGV4OiBzdHJpbmcgPSBwYXJhbXMudHhQcmVidWlsZC50eEhleDtcbiAgICBjb25zdCB0cmFuc2FjdGlvbjogRW9zVHggPSBwYXJhbXMudHhQcmVidWlsZC50cmFuc2FjdGlvbjtcblxuICAgIGNvbnN0IHNpZ25CdWZmZXI6IEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKHR4SGV4LCAnaGV4Jyk7XG4gICAgY29uc3QgcHJpdmF0ZUtleUJ1ZmZlciA9IGJpcDMyLmZyb21CYXNlNTgocHJ2KS5wcml2YXRlS2V5O1xuICAgIGlmICghcHJpdmF0ZUtleUJ1ZmZlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdubyBwcml2YXRlS2V5Jyk7XG4gICAgfVxuICAgIGNvbnN0IHNpZ25hdHVyZTogc3RyaW5nID0gZWNjLlNpZ25hdHVyZS5zaWduKHNpZ25CdWZmZXIsIHByaXZhdGVLZXlCdWZmZXIpLnRvU3RyaW5nKCk7XG5cbiAgICB0cmFuc2FjdGlvbi5zaWduYXR1cmVzLnB1c2goc2lnbmF0dXJlKTtcblxuICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICB0eEhleCxcbiAgICAgIHJlY2lwaWVudHM6IHBhcmFtcy50eFByZWJ1aWxkLnJlY2lwaWVudHMsXG4gICAgICBoZWFkZXJzOiBwYXJhbXMudHhQcmVidWlsZC5oZWFkZXJzLFxuICAgICAgdHhpZDogcGFyYW1zLnR4UHJlYnVpbGQudHhpZCxcbiAgICB9O1xuICAgIHJldHVybiB7IGhhbGZTaWduZWQ6IHR4UGFyYW1zIH07XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlU3Rha2VBY3Rpb25EYXRhKHN0YWtlQWN0aW9uRGF0YTogU3Rha2VBY3Rpb25EYXRhKTogYW55IHtcbiAgICBpZiAoc3Rha2VBY3Rpb25EYXRhLmZyb20gIT09IHN0YWtlQWN0aW9uRGF0YS5yZWNlaXZlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBzdGFrZXIgKCR7c3Rha2VBY3Rpb25EYXRhLmZyb219KSBhbmQgcmVjZWl2ZXIgKCR7c3Rha2VBY3Rpb25EYXRhLnJlY2VpdmVyfSkgbXVzdCBiZSB0aGUgc2FtZWApO1xuICAgIH1cblxuICAgIGlmIChzdGFrZUFjdGlvbkRhdGEudHJhbnNmZXIgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2Fubm90IHRyYW5zZmVyIGZ1bmRzIGFzIHBhcnQgb2YgZGVsZWdhdGVidyBhY3Rpb24nKTtcbiAgICB9XG5cbiAgICAvLyBzdGFrZV9jcHVfcXVhbnRpdHkgaXMgdXNlZCBhcyB0aGUgYW1vdW50IGJlY2F1c2UgdGhlIEJpdEdvIHBsYXRmb3JtIG9ubHkgc3Rha2VzIGNwdSBmb3Igdm90aW5nIHRyYW5zYWN0aW9uc1xuICAgIHJldHVybiB7XG4gICAgICBhZGRyZXNzOiBzdGFrZUFjdGlvbkRhdGEuZnJvbSxcbiAgICAgIGFtb3VudDogdGhpcy5iaWdVbml0c1RvQmFzZVVuaXRzKHN0YWtlQWN0aW9uRGF0YS5zdGFrZV9jcHVfcXVhbnRpdHkuc3BsaXQoJyAnKVswXSksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVVbnN0YWtlQWN0aW9uRGF0YSh1bnN0YWtlQWN0aW9uRGF0YTogVW5zdGFrZUFjdGlvbkRhdGEpOiBhbnkge1xuICAgIGlmICh1bnN0YWtlQWN0aW9uRGF0YS5mcm9tICE9PSB1bnN0YWtlQWN0aW9uRGF0YS5yZWNlaXZlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdW5zdGFrZXIgKCR7dW5zdGFrZUFjdGlvbkRhdGEuZnJvbX0pIGFuZCByZWNlaXZlciAoJHt1bnN0YWtlQWN0aW9uRGF0YS5yZWNlaXZlcn0pIG11c3QgYmUgdGhlIHNhbWVgXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBjcHVBbW91bnQgPSBuZXcgQmlnTnVtYmVyKHVuc3Rha2VBY3Rpb25EYXRhLnVuc3Rha2VfY3B1X3F1YW50aXR5LnNwbGl0KCcgJylbMF0pO1xuICAgIGNvbnN0IG5ldEFtb3VudCA9IG5ldyBCaWdOdW1iZXIodW5zdGFrZUFjdGlvbkRhdGEudW5zdGFrZV9uZXRfcXVhbnRpdHkuc3BsaXQoJyAnKVswXSk7XG4gICAgY29uc3QgdG90YWxBbW91bnQgPSBjcHVBbW91bnQucGx1cyhuZXRBbW91bnQpLnRvTnVtYmVyKCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgYWRkcmVzczogdW5zdGFrZUFjdGlvbkRhdGEucmVjZWl2ZXIsXG4gICAgICBhbW91bnQ6IHRoaXMuYmlnVW5pdHNUb0Jhc2VVbml0cyh0b3RhbEFtb3VudCksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHZhbGlkYXRlVm90ZUFjdGlvbkRhdGEodm90ZUFjdGlvbkRhdGE6IFZvdGVBY3Rpb25EYXRhKSB7XG4gICAgY29uc3QgcHJveHlJc0VtcHR5ID0gXy5pc0VtcHR5KHZvdGVBY3Rpb25EYXRhLnByb3h5KTtcbiAgICBjb25zdCBwcm9kdWNlcnNJc0VtcHR5ID0gXy5pc0VtcHR5KHZvdGVBY3Rpb25EYXRhLnByb2R1Y2Vycyk7XG4gICAgaWYgKChwcm94eUlzRW1wdHkgJiYgcHJvZHVjZXJzSXNFbXB0eSkgfHwgKCFwcm94eUlzRW1wdHkgJiYgIXByb2R1Y2Vyc0lzRW1wdHkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZvdGluZyB0cmFuc2FjdGlvbnMgbXVzdCBzcGVjaWZ5IGVpdGhlciBwcm9kdWNlcnMgb3IgcHJveHkgdG8gdm90ZSBmb3InKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgYWRkcmVzczogdm90ZUFjdGlvbkRhdGEudm90ZXIsXG4gICAgICBwcm94eTogdm90ZUFjdGlvbkRhdGEucHJveHksXG4gICAgICBwcm9kdWNlcnM6IHZvdGVBY3Rpb25EYXRhLnByb2R1Y2VycyxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlVHJhbnNhY3Rpb25JZEhleChzZXJpYWxpemVkVHJhbnNhY3Rpb25CdWZmZXI6IEJ1ZmZlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShzZXJpYWxpemVkVHJhbnNhY3Rpb25CdWZmZXIpLmRpZ2VzdCgpLnRvU3RyaW5nKCdoZXgnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXNlcmlhbGl6ZSBhIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0gaGVhZGVyc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBkZXNlcmlhbGl6ZVRyYW5zYWN0aW9uKHtcbiAgICB0cmFuc2FjdGlvbixcbiAgICBoZWFkZXJzLFxuICB9OiBFeHBsYWluVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxEZXNlcmlhbGl6ZWRFb3NUcmFuc2FjdGlvbj4ge1xuICAgIC8vIGNyZWF0ZSBhbiBlb3NqcyBBUEkgY2xpZW50XG4gICAgY29uc3QgYXBpID0gbmV3IEFwaSh7XG4gICAgICBhYmlQcm92aWRlcjogbmV3IE9mZmxpbmVBYmlQcm92aWRlcigpLFxuICAgICAgcnBjOiBuZXcgTm9vcEpzb25ScGMoKSxcbiAgICAgIHNpZ25hdHVyZVByb3ZpZGVyOiBuZXcgTm9vcFNpZ25hdHVyZVByb3ZpZGVyKCksXG4gICAgICBjaGFpbklkOiB0aGlzLmdldENoYWluSWQoKSxcbiAgICAgIC8vIFVzZSBhIGN1c3RvbSBUZXh0RGVjb2RlciBhcyB0aGUgZ2xvYmFsIFRleHREZWNvZGVyIGxlYWRzIHRvIGNyYXNoZXMgaW4gT1ZDIC8gRWxlY3Ryb24uXG4gICAgICB0ZXh0RGVjb2RlcjogbmV3IFN0cmluZ1RleHREZWNvZGVyKCksXG4gICAgICB0ZXh0RW5jb2RlcjogbmV3IFRleHRFbmNvZGVyKCksXG4gICAgfSk7XG5cbiAgICAvLyB0eXBlIGd1YXJkc1xuICAgIGNvbnN0IGlzVHJhbnNmZXJBY3Rpb25EYXRhID0gKHR4QWN0aW9uRGF0YTogYW55KTogdHhBY3Rpb25EYXRhIGlzIFRyYW5zZmVyQWN0aW9uRGF0YSA9PiB7XG4gICAgICByZXR1cm4gKFxuICAgICAgICAodHhBY3Rpb25EYXRhIGFzIFRyYW5zZmVyQWN0aW9uRGF0YSkuZnJvbSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICh0eEFjdGlvbkRhdGEgYXMgVHJhbnNmZXJBY3Rpb25EYXRhKS50byAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICh0eEFjdGlvbkRhdGEgYXMgVHJhbnNmZXJBY3Rpb25EYXRhKS5xdWFudGl0eSAhPT0gdW5kZWZpbmVkXG4gICAgICApO1xuICAgIH07XG4gICAgY29uc3QgaXNTdGFrZUFjdGlvbkRhdGEgPSAodHhBY3Rpb25EYXRhOiBhbnkpOiB0eEFjdGlvbkRhdGEgaXMgU3Rha2VBY3Rpb25EYXRhID0+IHtcbiAgICAgIHJldHVybiAoXG4gICAgICAgICh0eEFjdGlvbkRhdGEgYXMgU3Rha2VBY3Rpb25EYXRhKS5mcm9tICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBTdGFrZUFjdGlvbkRhdGEpLnJlY2VpdmVyICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBTdGFrZUFjdGlvbkRhdGEpLnRyYW5zZmVyICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBTdGFrZUFjdGlvbkRhdGEpLnN0YWtlX2NwdV9xdWFudGl0eSAhPT0gdW5kZWZpbmVkXG4gICAgICApO1xuICAgIH07XG4gICAgY29uc3QgaXNVbnN0YWtlQWN0aW9uRGF0YSA9ICh0eEFjdGlvbkRhdGE6IGFueSk6IHR4QWN0aW9uRGF0YSBpcyBVbnN0YWtlQWN0aW9uRGF0YSA9PiB7XG4gICAgICByZXR1cm4gKFxuICAgICAgICAodHhBY3Rpb25EYXRhIGFzIFVuc3Rha2VBY3Rpb25EYXRhKS5mcm9tICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBVbnN0YWtlQWN0aW9uRGF0YSkucmVjZWl2ZXIgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAodHhBY3Rpb25EYXRhIGFzIFVuc3Rha2VBY3Rpb25EYXRhKS51bnN0YWtlX2NwdV9xdWFudGl0eSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICh0eEFjdGlvbkRhdGEgYXMgVW5zdGFrZUFjdGlvbkRhdGEpLnVuc3Rha2VfbmV0X3F1YW50aXR5ICE9PSB1bmRlZmluZWRcbiAgICAgICk7XG4gICAgfTtcbiAgICBjb25zdCBpc1ZvdGVBY3Rpb25EYXRhID0gKHR4QWN0aW9uRGF0YTogYW55KTogdHhBY3Rpb25EYXRhIGlzIFZvdGVBY3Rpb25EYXRhID0+IHtcbiAgICAgIHJldHVybiAodHhBY3Rpb25EYXRhIGFzIFZvdGVBY3Rpb25EYXRhKS52b3RlciAhPT0gdW5kZWZpbmVkO1xuICAgIH07XG4gICAgY29uc3QgaXNSZWZ1bmRBY3Rpb25EYXRhID0gKHR4QWN0aW9uRGF0YTogYW55KTogdHhBY3Rpb25EYXRhIGlzIFJlZnVuZEFjdGlvbkRhdGEgPT4ge1xuICAgICAgcmV0dXJuICh0eEFjdGlvbkRhdGEgYXMgUmVmdW5kQWN0aW9uRGF0YSkub3duZXIgIT09IHVuZGVmaW5lZDtcbiAgICB9O1xuXG4gICAgLy8gZGVzZXJpYWxpemVUcmFuc2FjdGlvblxuICAgIGNvbnN0IHNlcmlhbGl6ZWRUeEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKHRyYW5zYWN0aW9uLnBhY2tlZF90cngsICdoZXgnKTtcbiAgICBjb25zdCBkZXNlcmlhbGl6ZWRUeEpzb25Gcm9tUGFja2VkVHJ4ID0gYXdhaXQgYXBpLmRlc2VyaWFsaXplVHJhbnNhY3Rpb25XaXRoQWN0aW9ucyhzZXJpYWxpemVkVHhCdWZmZXIpO1xuXG4gICAgaWYgKCFkZXNlcmlhbGl6ZWRUeEpzb25Gcm9tUGFja2VkVHJ4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NvdWxkIG5vdCBwcm9jZXNzIHRyYW5zYWN0aW9uIGZyb20gdHhIZXgnKTtcbiAgICB9XG4gICAgY29uc3QgdHg6IERlc2VyaWFsaXplZEVvc1RyYW5zYWN0aW9uID0gZGVzZXJpYWxpemVkVHhKc29uRnJvbVBhY2tlZFRyeDtcblxuICAgIC8vIHZhbGlkYXRlIGNvbnRleHQgZnJlZSBhY3Rpb25zXG4gICAgaWYgKHR4LmNvbnRleHRfZnJlZV9hY3Rpb25zLmxlbmd0aCAhPT0gMCkge1xuICAgICAgaWYgKHR4LmNvbnRleHRfZnJlZV9hY3Rpb25zLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ251bWJlciBvZiBjb250ZXh0IGZyZWUgYWN0aW9ucyBtdXN0IGJlIDEnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICAhXy5pc0VxdWFsKF8ucGljayh0eC5jb250ZXh0X2ZyZWVfYWN0aW9uc1swXSwgWydhY2NvdW50JywgJ2F1dGhvcml6YXRpb24nLCAnbmFtZSddKSwge1xuICAgICAgICAgIGFjY291bnQ6ICdlb3Npby5udWxsJyxcbiAgICAgICAgICBhdXRob3JpemF0aW9uOiBbXSxcbiAgICAgICAgICBuYW1lOiAnbm9uY2UnLFxuICAgICAgICB9KSB8fFxuICAgICAgICBfLmlzRW1wdHkodHguY29udGV4dF9mcmVlX2FjdGlvbnNbMF0uZGF0YSlcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RoZSBjb250ZXh0IGZyZWUgYWN0aW9uIGlzIGludmFsaWQnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBPbmx5IHN1cHBvcnQgdHJhbnNhY3Rpb25zIHdpdGggb25lICh0cmFuc2ZlciB8IHZvdGVwcm9kdWNlcikgb3IgdHdvIChkZWxlZ2F0ZWJ3ICYgdm90ZXByb2R1Y2VyKSBhY3Rpb25zXG4gICAgaWYgKHR4LmFjdGlvbnMubGVuZ3RoICE9PSAxICYmIHR4LmFjdGlvbnMubGVuZ3RoICE9PSAyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgbnVtYmVyIG9mIGFjdGlvbnM6ICR7dHguYWN0aW9ucy5sZW5ndGh9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgdHhBY3Rpb24gPSB0eC5hY3Rpb25zWzBdO1xuICAgIGlmICghdHhBY3Rpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyB0cmFuc2FjdGlvbiBhY3Rpb24nKTtcbiAgICB9XG4gICAgaWYgKHR4QWN0aW9uLm5hbWUgPT09ICd0cmFuc2ZlcicpIHtcbiAgICAgIC8vIFRyYW5zZmVycyBzaG91bGQgb25seSBoYXZlIDEgYWN0aW9uXG4gICAgICBpZiAodHguYWN0aW9ucy5sZW5ndGggIT09IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB0cmFuc2ZlcnMgc2hvdWxkIG9ubHkgaGF2ZSAxIGFjdGlvbjogJHt0eC5hY3Rpb25zLmxlbmd0aH0gZ2l2ZW5gKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1RyYW5zZmVyQWN0aW9uRGF0YSh0eEFjdGlvbi5kYXRhKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgb3IgaW5jb21wbGV0ZSB0cmFuc2ZlciBhY3Rpb24gZGF0YScpO1xuICAgICAgfVxuICAgICAgY29uc3QgdHJhbnNmZXJBY3Rpb25EYXRhID0gdHhBY3Rpb24uZGF0YTtcblxuICAgICAgdHguYWRkcmVzcyA9IHRyYW5zZmVyQWN0aW9uRGF0YS50bztcbiAgICAgIHR4LmFtb3VudCA9IHRoaXMuYmlnVW5pdHNUb0Jhc2VVbml0cyh0cmFuc2ZlckFjdGlvbkRhdGEucXVhbnRpdHkuc3BsaXQoJyAnKVswXSk7XG4gICAgICB0eC5tZW1vID0gdHJhbnNmZXJBY3Rpb25EYXRhLm1lbW87XG4gICAgfSBlbHNlIGlmICh0eEFjdGlvbi5uYW1lID09PSAnZGVsZWdhdGVidycpIHtcbiAgICAgIC8vIFRoZSBkZWxlZ2F0ZWJ3IGFjdGlvbiBzaG91bGQgb25seSBiZSBwYXJ0IG9mIHZvdGluZyB0cmFuc2FjdGlvbnNcbiAgICAgIGlmICh0eC5hY3Rpb25zLmxlbmd0aCAhPT0gMikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHN0YWtpbmcgdHJhbnNhY3Rpb25zIHRoYXQgaW5jbHVkZSB0aGUgZGVsZWdhdGVidyBhY3Rpb24gc2hvdWxkIGhhdmUgMiBhY3Rpb25zOiAke3R4LmFjdGlvbnMubGVuZ3RofSBnaXZlbmBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdHhBY3Rpb24yID0gdHguYWN0aW9uc1sxXTtcbiAgICAgIGlmICh0eEFjdGlvbjIubmFtZSAhPT0gJ3ZvdGVwcm9kdWNlcicpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIHN0YWtpbmcgdHJhbnNhY3Rpb24gYWN0aW9uOiAke3R4QWN0aW9uMi5uYW1lfSwgZXhwZWN0aW5nOiB2b3RlcHJvZHVjZXJgKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1N0YWtlQWN0aW9uRGF0YSh0eEFjdGlvbi5kYXRhKSB8fCAhaXNWb3RlQWN0aW9uRGF0YSh0eEFjdGlvbjIuZGF0YSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIG9yIGluY29tcGxldGUgc3Rha2Ugb3Igdm90ZSBhY3Rpb24gZGF0YScpO1xuICAgICAgfVxuICAgICAgY29uc3Qgc3Rha2VBY3Rpb25EYXRhID0gdHhBY3Rpb24uZGF0YTtcbiAgICAgIGNvbnN0IHZvdGVBY3Rpb25EYXRhID0gdHhBY3Rpb24yLmRhdGE7XG5cbiAgICAgIGNvbnN0IGRlc2VyaWFsaXplZFN0YWtlQWN0aW9uID0gdGhpcy52YWxpZGF0ZVN0YWtlQWN0aW9uRGF0YShzdGFrZUFjdGlvbkRhdGEpO1xuICAgICAgY29uc3QgZGVzZXJpYWxpemVkVm90ZUFjdGlvbiA9IEVvcy52YWxpZGF0ZVZvdGVBY3Rpb25EYXRhKHZvdGVBY3Rpb25EYXRhKTtcbiAgICAgIGlmIChkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbi5hZGRyZXNzICE9PSBkZXNlcmlhbGl6ZWRWb3RlQWN0aW9uLmFkZHJlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBzdGFrZXIgKCR7ZGVzZXJpYWxpemVkU3Rha2VBY3Rpb24uYWRkcmVzc30pIGFuZCB2b3RlciAoJHtkZXNlcmlhbGl6ZWRWb3RlQWN0aW9uLmFkZHJlc3N9KSBtdXN0IGJlIHRoZSBzYW1lYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICB0eC5hbW91bnQgPSBkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbi5hbW91bnQ7XG4gICAgICB0eC5wcm94eSA9IGRlc2VyaWFsaXplZFZvdGVBY3Rpb24ucHJveHk7XG4gICAgICB0eC5wcm9kdWNlcnMgPSBkZXNlcmlhbGl6ZWRWb3RlQWN0aW9uLnByb2R1Y2VycztcbiAgICB9IGVsc2UgaWYgKHR4QWN0aW9uLm5hbWUgPT09ICd2b3RlcHJvZHVjZXInKSB7XG4gICAgICBpZiAodHguYWN0aW9ucy5sZW5ndGggPiAyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndm90aW5nIHRyYW5zYWN0aW9ucyBzaG91bGQgbm90IGhhdmUgbW9yZSB0aGFuIDIgYWN0aW9ucycpO1xuICAgICAgfVxuXG4gICAgICBsZXQgZGVzZXJpYWxpemVkU3Rha2VBY3Rpb247XG4gICAgICBpZiAodHguYWN0aW9ucy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgY29uc3QgdHhBY3Rpb24yID0gdHguYWN0aW9uc1sxXTtcbiAgICAgICAgaWYgKHR4QWN0aW9uMi5uYW1lICE9PSAnZGVsZWdhdGVidycpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgc3Rha2luZyB0cmFuc2FjdGlvbiBhY3Rpb246ICR7dHhBY3Rpb24yLm5hbWV9LCBleHBlY3Rpbmc6IGRlbGVnYXRlYndgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWlzU3Rha2VBY3Rpb25EYXRhKHR4QWN0aW9uLmRhdGEpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIG9yIGluY29tcGxldGUgc3Rha2UgYWN0aW9uIGRhdGEnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzdGFrZUFjdGlvbkRhdGEgPSB0eEFjdGlvbi5kYXRhO1xuICAgICAgICBkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbiA9IHRoaXMudmFsaWRhdGVTdGFrZUFjdGlvbkRhdGEoc3Rha2VBY3Rpb25EYXRhKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1ZvdGVBY3Rpb25EYXRhKHR4QWN0aW9uLmRhdGEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBvciBpbmNvbXBsZXRlIHZvdGUgYWN0aW9uIGRhdGEnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHZvdGVBY3Rpb25EYXRhID0gdHhBY3Rpb24uZGF0YTtcbiAgICAgIGNvbnN0IGRlc2VyaWFsaXplZFZvdGVBY3Rpb24gPSBFb3MudmFsaWRhdGVWb3RlQWN0aW9uRGF0YSh2b3RlQWN0aW9uRGF0YSk7XG5cbiAgICAgIGlmICghIWRlc2VyaWFsaXplZFN0YWtlQWN0aW9uICYmIGRlc2VyaWFsaXplZFN0YWtlQWN0aW9uLmFkZHJlc3MgIT09IGRlc2VyaWFsaXplZFZvdGVBY3Rpb24uYWRkcmVzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHN0YWtlciAoJHtkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbi5hZGRyZXNzfSkgYW5kIHZvdGVyICgke2Rlc2VyaWFsaXplZFZvdGVBY3Rpb24uYWRkcmVzc30pIG11c3QgYmUgdGhlIHNhbWVgXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHR4LmFtb3VudCA9ICEhZGVzZXJpYWxpemVkU3Rha2VBY3Rpb24gPyBkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbi5hbW91bnQgOiAnMCc7XG4gICAgICB0eC5wcm94eSA9IGRlc2VyaWFsaXplZFZvdGVBY3Rpb24ucHJveHk7XG4gICAgICB0eC5wcm9kdWNlcnMgPSBkZXNlcmlhbGl6ZWRWb3RlQWN0aW9uLnByb2R1Y2VycztcbiAgICB9IGVsc2UgaWYgKHR4QWN0aW9uLm5hbWUgPT09ICd1bmRlbGVnYXRlYncnKSB7XG4gICAgICBpZiAodHguYWN0aW9ucy5sZW5ndGggIT09IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB1bnN0YWtlIHNob3VsZCBvbmx5IGhhdmUgMSBhY3Rpb246ICR7dHguYWN0aW9ucy5sZW5ndGh9IGdpdmVuYCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghaXNVbnN0YWtlQWN0aW9uRGF0YSh0eEFjdGlvbi5kYXRhKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgb3IgaW5jb21wbGV0ZSB1bnN0YWtlIGFjdGlvbiBkYXRhJyk7XG4gICAgICB9XG4gICAgICBjb25zdCB1bnN0YWtlQWN0aW9uRGF0YSA9IHR4QWN0aW9uLmRhdGE7XG4gICAgICBjb25zdCBkZXNlcmlhbGl6ZWRVbnN0YWtlQWN0aW9uID0gdGhpcy52YWxpZGF0ZVVuc3Rha2VBY3Rpb25EYXRhKHVuc3Rha2VBY3Rpb25EYXRhKTtcblxuICAgICAgdHguYW1vdW50ID0gZGVzZXJpYWxpemVkVW5zdGFrZUFjdGlvbi5hbW91bnQ7XG4gICAgICB0eC5hZGRyZXNzID0gZGVzZXJpYWxpemVkVW5zdGFrZUFjdGlvbi5hZGRyZXNzO1xuICAgIH0gZWxzZSBpZiAodHhBY3Rpb24ubmFtZSA9PT0gJ3JlZnVuZCcpIHtcbiAgICAgIGlmICh0eC5hY3Rpb25zLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHJlZnVuZCBzaG91bGQgb25seSBoYXZlIDEgYWN0aW9uOiAke3R4LmFjdGlvbnMubGVuZ3RofSBnaXZlbmApO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzUmVmdW5kQWN0aW9uRGF0YSh0eEFjdGlvbi5kYXRhKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgb3IgaW5jb21wbGV0ZSByZWZ1bmQgYWN0aW9uIGRhdGEnKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVmdW5kQWN0aW9uRGF0YSA9IHR4QWN0aW9uLmRhdGE7XG4gICAgICB0eC5hZGRyZXNzID0gcmVmdW5kQWN0aW9uRGF0YS5vd25lcjtcbiAgICAgIHR4LmFtb3VudCA9ICcwJztcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIGFjdGlvbjogJHt0eEFjdGlvbi5uYW1lfWApO1xuICAgIH1cblxuICAgIC8vIEdldCB0aGUgdHggaWQgaWYgdHggaGVhZGVycyB3ZXJlIHByb3ZpZGVkXG4gICAgaWYgKGhlYWRlcnMpIHtcbiAgICAgIGxldCByZWJ1aWx0VHJhbnNhY3Rpb247XG4gICAgICB0cnkge1xuICAgICAgICAvLyByZW1vdmUgWiBhdCB0aGUgZW5kXG4gICAgICAgIGlmICgoaGVhZGVycy5leHBpcmF0aW9uIGFzIHN0cmluZykuZW5kc1dpdGgoJ1onKSkge1xuICAgICAgICAgIGhlYWRlcnMuZXhwaXJhdGlvbiA9IChoZWFkZXJzLmV4cGlyYXRpb24gYXMgc3RyaW5nKS5zbGljZSgwLCAtMSk7XG4gICAgICAgIH1cbiAgICAgICAgcmVidWlsdFRyYW5zYWN0aW9uID0gYXdhaXQgYXBpLnRyYW5zYWN0KHsgLi4udHgsIC4uLmhlYWRlcnMgfSwgeyBzaWduOiBmYWxzZSwgYnJvYWRjYXN0OiBmYWxzZSB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICdDb3VsZCBub3QgYnVpbGQgdHJhbnNhY3Rpb24gdG8gZ2V0IHRyYW5zYWN0aW9uX2lkLiBQbGVhc2UgY2hlY2sgdHJhbnNhY3Rpb24gb3IgaGVhZGVycyBmb3JtYXQuJ1xuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICB0eC50cmFuc2FjdGlvbl9pZCA9IEVvcy5jcmVhdGVUcmFuc2FjdGlvbklkSGV4KChyZWJ1aWx0VHJhbnNhY3Rpb24gYXMgYW55KS5zZXJpYWxpemVkVHJhbnNhY3Rpb24pO1xuICAgIH1cblxuICAgIHJldHVybiB0eDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBsYWluL3BhcnNlIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBFeHBsYWluVHJhbnNhY3Rpb25PcHRpb25zXG4gICAqL1xuICBhc3luYyBleHBsYWluVHJhbnNhY3Rpb24ocGFyYW1zOiBFeHBsYWluVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxUcmFuc2FjdGlvbkV4cGxhbmF0aW9uPiB7XG4gICAgbGV0IHRyYW5zYWN0aW9uO1xuICAgIHRyeSB7XG4gICAgICB0cmFuc2FjdGlvbiA9IGF3YWl0IHRoaXMuZGVzZXJpYWxpemVUcmFuc2FjdGlvbihwYXJhbXMpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBFT1MgdHJhbnNhY3Rpb24gb3IgaGVhZGVyczogJyArIGUudG9TdHJpbmcoKSk7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBkaXNwbGF5T3JkZXI6IFtcbiAgICAgICAgJ2lkJyxcbiAgICAgICAgJ291dHB1dEFtb3VudCcsXG4gICAgICAgICdjaGFuZ2VBbW91bnQnLFxuICAgICAgICAnb3V0cHV0cycsXG4gICAgICAgICdjaGFuZ2VPdXRwdXRzJyxcbiAgICAgICAgJ2ZlZScsXG4gICAgICAgICdtZW1vJyxcbiAgICAgICAgJ3Byb3h5JyxcbiAgICAgICAgJ3Byb2R1Y2VycycsXG4gICAgICBdLFxuICAgICAgaWQ6IHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uX2lkLFxuICAgICAgY2hhbmdlT3V0cHV0czogW10sXG4gICAgICBvdXRwdXRBbW91bnQ6IHRyYW5zYWN0aW9uLmFtb3VudCxcbiAgICAgIGNoYW5nZUFtb3VudDogMCxcbiAgICAgIG91dHB1dHM6ICEhdHJhbnNhY3Rpb24uYWRkcmVzcyA/IFt7IGFkZHJlc3M6IHRyYW5zYWN0aW9uLmFkZHJlc3MsIGFtb3VudDogdHJhbnNhY3Rpb24uYW1vdW50IH1dIDogW10sXG4gICAgICBmZWU6IHt9LFxuICAgICAgbWVtbzogdHJhbnNhY3Rpb24ubWVtbyxcbiAgICAgIHByb3h5OiB0cmFuc2FjdGlvbi5wcm94eSxcbiAgICAgIHByb2R1Y2VyczogdHJhbnNhY3Rpb24ucHJvZHVjZXJzLFxuICAgIH0gYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkXG4gICAqL1xuICBpbml0aWF0ZVJlY292ZXJ5KHBhcmFtczogUmVjb3ZlcnlPcHRpb25zKTogbmV2ZXIge1xuICAgIHRocm93IG5ldyBFcnJvcignZGVwcmVjYXRlZCBtZXRob2QnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYWtlIGEgcmVxdWVzdCB0byBvbmUgb2YgdGhlIHB1YmxpYyBFT1Mgbm9kZXMgYXZhaWxhYmxlXG4gICAqIEBwYXJhbSBwYXJhbXMuZW5kcG9pbnRcbiAgICogQHBhcmFtIHBhcmFtcy5wYXlsb2FkXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0RGF0YUZyb21Ob2RlKHBhcmFtczoge1xuICAgIGVuZHBvaW50OiBzdHJpbmc7XG4gICAgcGF5bG9hZD86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB9KTogUHJvbWlzZTxyZXF1ZXN0LlJlc3BvbnNlPiB7XG4gICAgY29uc3Qgbm9kZVVybHMgPSB0aGlzLmdldFB1YmxpY05vZGVVcmxzKCk7XG4gICAgZm9yIChjb25zdCBub2RlVXJsIG9mIG5vZGVVcmxzKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgcmVxdWVzdC5wb3N0KG5vZGVVcmwgKyBwYXJhbXMuZW5kcG9pbnQpLnNlbmQocGFyYW1zLnBheWxvYWQpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAvLyBsZXQncyBob3BlIGFub3RoZXIgY2FsbCBzdWNjZWVkc1xuICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byBjYWxsIGVuZHBvaW50OiAke3BhcmFtcy5lbmRwb2ludH0gZnJvbSBub2RlczogJHtfLmpvaW4obm9kZVVybHMsICcsICcpfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBFT1MgY2hhaW4gaW5mbyBmcm9tIGEgcHVibGljIG5vZGVcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRDaGFpbkluZm9Gcm9tTm9kZSgpOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5nZXREYXRhRnJvbU5vZGUoeyBlbmRwb2ludDogJy92MS9jaGFpbi9nZXRfaW5mbycgfSk7XG4gICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuYWJsZSB0byBmZXRjaCBjaGFpbiBpbmZvJyk7XG4gICAgfVxuICAgIHJldHVybiByZXNwb25zZS5ib2R5O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBkYXRhIHNwZWNpZmljIHRvIGFuIGFjY291bnQgZnJvbSBhIHB1YmxpYyBub2RlXG4gICAqIEBwYXJhbSBhZGRyZXNzXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0QWNjb3VudEZyb21Ob2RlKHsgYWRkcmVzcyB9OiB7IGFkZHJlc3M6IHN0cmluZyB9KTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIGVuZHBvaW50OiAnL3YxL2NoYWluL2dldF9hY2NvdW50JyxcbiAgICAgIHBheWxvYWQ6IHsgYWNjb3VudF9uYW1lOiBhZGRyZXNzIH0sXG4gICAgfSk7XG4gICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FjY291bnQgbm90IGZvdW5kJyk7XG4gICAgfVxuICAgIHJldHVybiByZXNwb25zZS5ib2R5O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBibG9jayBkYXRhIGZyb20gYSBwdWJsaWMgbm9kZSB1c2luZyBpdHMgYmxvY2sgbnVtYmVyIG9yIGJsb2NrIGlkXG4gICAqIEBwYXJhbSBibG9ja051bU9ySWRcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRCbG9ja0Zyb21Ob2RlKHsgYmxvY2tOdW1PcklkIH06IHsgYmxvY2tOdW1PcklkOiBzdHJpbmcgfSk6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldERhdGFGcm9tTm9kZSh7XG4gICAgICBlbmRwb2ludDogJy92MS9jaGFpbi9nZXRfYmxvY2snLFxuICAgICAgcGF5bG9hZDogeyBibG9ja19udW1fb3JfaWQ6IGJsb2NrTnVtT3JJZCB9LFxuICAgIH0pO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdCbG9jayBub3QgZm91bmQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BvbnNlLmJvZHk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGhlYWRlcnMgZm9yIGFuIEVPUyB0eCBmcm9tIGEgcHVibGljIG5vZGVcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRUcmFuc2FjdGlvbkhlYWRlcnNGcm9tTm9kZSgpOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IGNoYWluSW5mbyA9IGF3YWl0IHRoaXMuZ2V0Q2hhaW5JbmZvRnJvbU5vZGUoKTtcbiAgICBjb25zdCBoZWFkQmxvY2tJbmZvUmVzdWx0ID0gYXdhaXQgdGhpcy5nZXRCbG9ja0Zyb21Ob2RlKHsgYmxvY2tOdW1PcklkOiBjaGFpbkluZm8uaGVhZF9ibG9ja19udW0gfSk7XG4gICAgY29uc3QgZXhwaXJlU2Vjb25kcyA9IDI4ODAwOyAvLyBtYXhpbXVtIHR4IGV4cGlyZSB0aW1lIG9mIDhoXG4gICAgY29uc3QgY2hhaW5EYXRlID0gbmV3IERhdGUoY2hhaW5JbmZvLmhlYWRfYmxvY2tfdGltZSArICdaJykuZ2V0VGltZSgpO1xuICAgIGNvbnN0IGV4cGlyYXRpb25EYXRlID0gbmV3IERhdGUoY2hhaW5EYXRlICsgZXhwaXJlU2Vjb25kcyAqIDEwMDApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGV4cGlyYXRpb246IGV4cGlyYXRpb25EYXRlLnRvSVNPU3RyaW5nKCksXG4gICAgICByZWZfYmxvY2tfbnVtOiBjaGFpbkluZm8uaGVhZF9ibG9ja19udW0gJiAweGZmZmYsXG4gICAgICByZWZfYmxvY2tfcHJlZml4OiBoZWFkQmxvY2tJbmZvUmVzdWx0LnJlZl9ibG9ja19wcmVmaXgsXG4gICAgfTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXRUcmFuc2ZlckFjdGlvbih7IHJlY2lwaWVudCwgc2VuZGVyLCBhbW91bnQsIG1lbW8gfTogYW55KTogRW9zVHJhbnNhY3Rpb25BY3Rpb24ge1xuICAgIHJldHVybiB7XG4gICAgICBhY2NvdW50OiAnZW9zaW8udG9rZW4nLFxuICAgICAgbmFtZTogJ3RyYW5zZmVyJyxcbiAgICAgIGF1dGhvcml6YXRpb246IFtcbiAgICAgICAge1xuICAgICAgICAgIGFjdG9yOiBzZW5kZXIsXG4gICAgICAgICAgcGVybWlzc2lvbjogJ2FjdGl2ZScsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgZGF0YToge1xuICAgICAgICBmcm9tOiBzZW5kZXIsXG4gICAgICAgIHRvOiByZWNpcGllbnQsXG4gICAgICAgIHF1YW50aXR5OiBgJHt0aGlzLmJhc2VVbml0c1RvQmlnVW5pdHMoYW1vdW50KX0gRU9TYCxcbiAgICAgICAgbWVtbzogIV8uaXNOaWwobWVtbykgPyBtZW1vIDogJycsIC8vIE1lbW8gbXVzdCBiZSBkZWZpbmVkLCBzZXQgaXQgdG8gZW1wdHkgc3RyaW5nIGlmIGl0IGlzIG5vdFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNpZ24gYSB0cmFuc2FjdGlvbiB3aXRoIGEga2V5XG4gICAqIEBwYXJhbSBzaWduYWJsZVR4XG4gICAqIEBwYXJhbSBzaWduaW5nS2V5XG4gICAqL1xuICBzaWduVHgoc2lnbmFibGVUeDogc3RyaW5nLCBzaWduaW5nS2V5OiBCSVAzMkludGVyZmFjZSk6IHN0cmluZyB7XG4gICAgY29uc3Qgc2lnbkJ1ZmZlciA9IEJ1ZmZlci5mcm9tKHNpZ25hYmxlVHgsICdoZXgnKTtcbiAgICBjb25zdCBwcml2YXRlS2V5QnVmZmVyID0gc2lnbmluZ0tleS5wcml2YXRlS2V5O1xuICAgIHJldHVybiBlY2MuU2lnbmF0dXJlLnNpZ24oc2lnbkJ1ZmZlciwgcHJpdmF0ZUtleUJ1ZmZlcikudG9TdHJpbmcoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgYSBmdW5kcyByZWNvdmVyeSB0cmFuc2FjdGlvbiB3aXRob3V0IEJpdEdvXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICovXG4gIGFzeW5jIHJlY292ZXIocGFyYW1zOiBSZWNvdmVyeU9wdGlvbnMpOiBQcm9taXNlPFJlY292ZXJ5VHJhbnNhY3Rpb24+IHtcbiAgICBpZiAoIXBhcmFtcy5yb290QWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHN0cmluZyByb290QWRkcmVzcycpO1xuICAgIH1cblxuICAgIGNvbnN0IGlzS3JzUmVjb3ZlcnkgPSBnZXRJc0tyc1JlY292ZXJ5KHBhcmFtcyk7XG4gICAgY29uc3QgaXNVbnNpZ25lZFN3ZWVwID0gZ2V0SXNVbnNpZ25lZFN3ZWVwKHBhcmFtcyk7XG5cbiAgICBjb25zdCB7IGtyc1Byb3ZpZGVyIH0gPSBwYXJhbXM7XG4gICAgaWYgKGdldElzS3JzUmVjb3ZlcnkocGFyYW1zKSkge1xuICAgICAgY2hlY2tLcnNQcm92aWRlcih0aGlzLCBrcnNQcm92aWRlcik7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGRlc3RpbmF0aW9uIGFkZHJlc3MhJyk7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5cyA9IGdldEJpcDMyS2V5cyh0aGlzLmJpdGdvLCBwYXJhbXMsIHsgcmVxdWlyZUJpdEdvWHB1YjogZmFsc2UgfSk7XG5cbiAgICBjb25zdCByb290QWRkcmVzc0RldGFpbHMgPSB0aGlzLmdldEFkZHJlc3NEZXRhaWxzKHBhcmFtcy5yb290QWRkcmVzcyk7XG4gICAgY29uc3QgYWNjb3VudCA9IGF3YWl0IHRoaXMuZ2V0QWNjb3VudEZyb21Ob2RlKHsgYWRkcmVzczogcm9vdEFkZHJlc3NEZXRhaWxzLmFkZHJlc3MgfSk7XG5cbiAgICBpZiAoIWFjY291bnQuY29yZV9saXF1aWRfYmFsYW5jZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgZmluZCBhbnkgYmFsYW5jZSB0byByZWNvdmVyeSBmb3IgJyArIHBhcmFtcy5yb290QWRkcmVzcyk7XG4gICAgfVxuXG4gICAgaWYgKCFhY2NvdW50LnBlcm1pc3Npb25zKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBmaW5kIHBlcm1pc3Npb25zIGZvciAnICsgcGFyYW1zLnJvb3RBZGRyZXNzKTtcbiAgICB9XG4gICAgY29uc3QgdXNlclB1YiA9IGVjYy5QdWJsaWNLZXkuZnJvbUJ1ZmZlcihrZXlzWzBdLnB1YmxpY0tleSkudG9TdHJpbmcoKTtcbiAgICBjb25zdCBiYWNrdXBQdWIgPSBlY2MuUHVibGljS2V5LmZyb21CdWZmZXIoa2V5c1sxXS5wdWJsaWNLZXkpLnRvU3RyaW5nKCk7XG5cbiAgICBjb25zdCBhY3RpdmVQZXJtaXNzaW9uID0gXy5maW5kKGFjY291bnQucGVybWlzc2lvbnMsIHsgcGVybV9uYW1lOiAnYWN0aXZlJyB9KTtcbiAgICBjb25zdCByZXF1aXJlZEF1dGggPSBfLmdldChhY3RpdmVQZXJtaXNzaW9uLCAncmVxdWlyZWRfYXV0aCcpO1xuICAgIGlmICghcmVxdWlyZWRBdXRoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlcXVpcmVkIGF1dGggZm9yIGFjdGl2ZSBwZXJtaXNzaW9uIG5vdCBmb3VuZCBpbiBhY2NvdW50Jyk7XG4gICAgfVxuICAgIGlmIChyZXF1aXJlZEF1dGgudGhyZXNob2xkICE9PSAyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuZXhwZWN0ZWQgYWN0aXZlIHBlcm1pc3Npb24gdGhyZXNob2xkJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZm91bmRQdWJzID0ge307XG4gICAgY29uc3QgcmVxdWlyZWRBdXRoS2V5cyA9IHJlcXVpcmVkQXV0aC5rZXlzO1xuICAgIGZvciAoY29uc3Qgc2lnbmVyIG9mIHJlcXVpcmVkQXV0aEtleXMpIHtcbiAgICAgIGlmIChzaWduZXIud2VpZ2h0ICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBzaWduZXIgd2VpZ2h0Jyk7XG4gICAgICB9XG4gICAgICAvLyBpZiBpdCdzIGEgZHVwZSBvZiBhIHB1YiB3ZSBhbHJlYWR5IGtub3csIGJsb2NrXG4gICAgICBpZiAoZm91bmRQdWJzW3NpZ25lci5rZXldKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZHVwbGljYXRlIHNpZ25lciBrZXknKTtcbiAgICAgIH1cbiAgICAgIGZvdW5kUHVic1tzaWduZXIua2V5XSA9IChmb3VuZFB1YnNbc2lnbmVyLmtleV0gfHwgMCkgKyAxO1xuICAgIH1cbiAgICBpZiAoZm91bmRQdWJzW3VzZXJQdWJdICE9PSAxIHx8IGZvdW5kUHVic1tiYWNrdXBQdWJdICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuZXhwZWN0ZWQgaW5jaWRlbmNlIGZyZXF1ZW5jeSBvZiB1c2VyIHNpZ25lciBrZXknKTtcbiAgICB9XG5cbiAgICBjb25zdCBhY2NvdW50QmFsYW5jZSA9IGFjY291bnQuY29yZV9saXF1aWRfYmFsYW5jZS5zcGxpdCgnICcpWzBdO1xuICAgIGNvbnN0IHJlY292ZXJ5QW1vdW50ID0gdGhpcy5iaWdVbml0c1RvQmFzZVVuaXRzKG5ldyBCaWdOdW1iZXIoYWNjb3VudEJhbGFuY2UpLnRvRml4ZWQoKSk7XG5cbiAgICBjb25zdCBkZXN0aW5hdGlvbkFkZHJlc3MgPSBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbjtcbiAgICBjb25zdCBkZXN0aW5hdGlvbkFkZHJlc3NEZXRhaWxzID0gdGhpcy5nZXRBZGRyZXNzRGV0YWlscyhkZXN0aW5hdGlvbkFkZHJlc3MpO1xuICAgIGNvbnN0IGRlc3RpbmF0aW9uQWNjb3VudCA9IGF3YWl0IHRoaXMuZ2V0QWNjb3VudEZyb21Ob2RlKHsgYWRkcmVzczogZGVzdGluYXRpb25BZGRyZXNzRGV0YWlscy5hZGRyZXNzIH0pO1xuICAgIGlmICghZGVzdGluYXRpb25BY2NvdW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Rlc3RpbmF0aW9uIGFjY291bnQgbm90IGZvdW5kJyk7XG4gICAgfVxuXG4gICAgY29uc3QgdHJhbnNhY3Rpb25IZWFkZXJzID0gYXdhaXQgdGhpcy5nZXRUcmFuc2FjdGlvbkhlYWRlcnNGcm9tTm9kZSgpO1xuICAgIGlmICghdHJhbnNhY3Rpb25IZWFkZXJzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBnZXQgdHJhbnNhY3Rpb24gaGVhZGVycyBmcm9tIG5vZGUnKTtcbiAgICB9XG4gICAgY29uc3QgaGVhZGVyczogRW9zVHJhbnNhY3Rpb25IZWFkZXJzID0gdHJhbnNhY3Rpb25IZWFkZXJzO1xuICAgIGNvbnN0IG5hdGl2ZURhdGUgPSBuZXcgRGF0ZShoZWFkZXJzLmV4cGlyYXRpb24gYXMgc3RyaW5nKTtcbiAgICAvLyBkcm9wIG1pbGxpc2Vjb25kcyBhbmQgdHJhaWxpbmcgWiBmcm9tIGV4cGlyYXRpb25cbiAgICBuYXRpdmVEYXRlLnNldE1pbGxpc2Vjb25kcygwKTtcbiAgICBjb25zdCBleHBpcmF0aW9uID0gbmF0aXZlRGF0ZS50b0lTT1N0cmluZygpO1xuICAgIGlmIChleHBpcmF0aW9uLmVuZHNXaXRoKCdaJykpIHtcbiAgICAgIGhlYWRlcnMuZXhwaXJhdGlvbiA9IGV4cGlyYXRpb24uc2xpY2UoMCwgLTEpO1xuICAgIH1cblxuICAgIC8vIGNyZWF0ZSBhbiBvZmZsaW5lIGVvc2pzIEFQSSBjbGllbnRcbiAgICBjb25zdCBhcGkgPSBuZXcgQXBpKHtcbiAgICAgIHJwYzogbmV3IE5vb3BKc29uUnBjKCksXG4gICAgICBzaWduYXR1cmVQcm92aWRlcjogbmV3IE5vb3BTaWduYXR1cmVQcm92aWRlcigpLFxuICAgICAgYWJpUHJvdmlkZXI6IG5ldyBPZmZsaW5lQWJpUHJvdmlkZXIoKSxcbiAgICAgIGNoYWluSWQ6IHRoaXMuZ2V0Q2hhaW5JZCgpLFxuICAgICAgdGV4dERlY29kZXI6IG5ldyBUZXh0RGVjb2RlcigpLFxuICAgICAgdGV4dEVuY29kZXI6IG5ldyBUZXh0RW5jb2RlcigpLFxuICAgIH0pO1xuXG4gICAgY29uc3QgdHJhbnNmZXJBY3Rpb24gPSB0aGlzLmdldFRyYW5zZmVyQWN0aW9uKHtcbiAgICAgIHJlY2lwaWVudDogZGVzdGluYXRpb25BZGRyZXNzRGV0YWlscy5hZGRyZXNzLFxuICAgICAgc2VuZGVyOiByb290QWRkcmVzc0RldGFpbHMuYWRkcmVzcyxcbiAgICAgIGFtb3VudDogbmV3IEJpZ051bWJlcihyZWNvdmVyeUFtb3VudCksXG4gICAgICBtZW1vOiBkZXN0aW5hdGlvbkFkZHJlc3NEZXRhaWxzLm1lbW9JZCxcbiAgICB9KTtcblxuICAgIGxldCBzZXJpYWxpemVkVHJhbnNhY3Rpb247XG4gICAgY29uc3QgdHggPSB7IGFjdGlvbnM6IFt0cmFuc2ZlckFjdGlvbl0gfTtcbiAgICB0cnkge1xuICAgICAgc2VyaWFsaXplZFRyYW5zYWN0aW9uID0gYXdhaXQgYXBpLnRyYW5zYWN0KHsgLi4udHgsIC4uLmhlYWRlcnMgfSwgeyBzaWduOiBmYWxzZSwgYnJvYWRjYXN0OiBmYWxzZSB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VvcyBBUEkgZXJyb3I6IENvdWxkIG5vdCBidWlsZCB0cmFuc2FjdGlvbicpO1xuICAgIH1cblxuICAgIC8vIGNyZWF0ZSB0cmFuc2FjdGlvbiBvYmplY3RcbiAgICBjb25zdCBzZXJpYWxpemVkVHJhbnNhY3Rpb25IZXggPSBCdWZmZXIuZnJvbShzZXJpYWxpemVkVHJhbnNhY3Rpb24uc2VyaWFsaXplZFRyYW5zYWN0aW9uKS50b1N0cmluZygnaGV4Jyk7XG4gICAgY29uc3QgdHJhbnNhY3Rpb25JZCA9IEVvcy5jcmVhdGVUcmFuc2FjdGlvbklkSGV4KHNlcmlhbGl6ZWRUcmFuc2FjdGlvbi5zZXJpYWxpemVkVHJhbnNhY3Rpb24pO1xuICAgIGNvbnN0IHR4T2JqZWN0ID0ge1xuICAgICAgdHJhbnNhY3Rpb246IHtcbiAgICAgICAgY29tcHJlc3Npb246ICdub25lJyxcbiAgICAgICAgcGFja2VkX3RyeDogc2VyaWFsaXplZFRyYW5zYWN0aW9uSGV4LFxuICAgICAgICBzaWduYXR1cmVzOiBbXSBhcyBzdHJpbmdbXSxcbiAgICAgIH0sXG4gICAgICB0eGlkOiB0cmFuc2FjdGlvbklkLFxuICAgICAgcmVjb3ZlcnlBbW91bnQ6IGFjY291bnRCYWxhbmNlLFxuICAgICAgY29pbjogdGhpcy5nZXRDaGFpbigpLFxuICAgICAgdHhIZXg6ICcnLFxuICAgIH07XG5cbiAgICBjb25zdCBzaWduYWJsZVR4ID0gQnVmZmVyLmNvbmNhdChbXG4gICAgICBCdWZmZXIuZnJvbSh0aGlzLmdldENoYWluSWQoKSwgJ2hleCcpLCAvLyBUaGUgQ2hhaW5JRCByZXByZXNlbnRpbmcgdGhlIGNoYWluIHRoYXQgd2UgYXJlIG9uXG4gICAgICBCdWZmZXIuZnJvbShzZXJpYWxpemVkVHJhbnNhY3Rpb24uc2VyaWFsaXplZFRyYW5zYWN0aW9uKSwgLy8gVGhlIHNlcmlhbGl6ZWQgdW5zaWduZWQgdHhcbiAgICAgIEJ1ZmZlci5mcm9tKG5ldyBVaW50OEFycmF5KDMyKSksIC8vIFNvbWUgcGFkZGluZ1xuICAgIF0pLnRvU3RyaW5nKCdoZXgnKTtcblxuICAgIGlmIChpc1Vuc2lnbmVkU3dlZXApIHtcbiAgICAgIHR4T2JqZWN0LnR4SGV4ID0gc2lnbmFibGVUeDtcbiAgICAgIHJldHVybiB0eE9iamVjdDtcbiAgICB9XG5cbiAgICBjb25zdCB1c2VyU2lnbmF0dXJlID0gdGhpcy5zaWduVHgoc2lnbmFibGVUeCwga2V5c1swXSk7XG4gICAgdHhPYmplY3QudHJhbnNhY3Rpb24uc2lnbmF0dXJlcy5wdXNoKHVzZXJTaWduYXR1cmUpO1xuXG4gICAgaWYgKCFpc0tyc1JlY292ZXJ5KSB7XG4gICAgICBjb25zdCBiYWNrdXBTaWduYXR1cmUgPSB0aGlzLnNpZ25UeChzaWduYWJsZVR4LCBrZXlzWzFdKTtcbiAgICAgIHR4T2JqZWN0LnRyYW5zYWN0aW9uLnNpZ25hdHVyZXMucHVzaChiYWNrdXBTaWduYXR1cmUpO1xuICAgIH1cblxuICAgIHJldHVybiB0eE9iamVjdDtcbiAgfVxuXG4gIGFzeW5jIHBhcnNlVHJhbnNhY3Rpb24ocGFyYW1zOiBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8UGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IHRoYXQgYSB0cmFuc2FjdGlvbiBwcmVidWlsZCBjb21wbGllcyB3aXRoIHRoZSBvcmlnaW5hbCBpbnRlbnRpb25cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKiBAcGFyYW0gcGFyYW1zLnR4UGFyYW1zIHBhcmFtcyB1c2VkIHRvIGJ1aWxkIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0gcGFyYW1zLnR4UHJlYnVpbGQgdGhlIHByZWJ1aWx0IHRyYW5zYWN0aW9uXG4gICAqL1xuICBhc3luYyB2ZXJpZnlUcmFuc2FjdGlvbihwYXJhbXM6IEVvc1ZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3QgeyB0eFBhcmFtczogdHhQYXJhbXMsIHR4UHJlYnVpbGQ6IHR4UHJlYnVpbGQgfSA9IHBhcmFtcztcblxuICAgIC8vIGNoZWNrIGlmIHRoZSB0cmFuc2FjdGlvbiBoYXMgYSB0eEhleFxuICAgIGlmICghdHhQcmVidWlsZC50eEhleCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHR4IHByZWJ1aWxkIHByb3BlcnR5IHR4SGV4Jyk7XG4gICAgfVxuXG4gICAgLy8gY29uc3RydWN0IHRyYW5zYWN0aW9uIGZyb20gdHhIZXhcbiAgICBjb25zdCB0eEZyb21IZXggPSBCdWZmZXIuZnJvbSh0eFByZWJ1aWxkLnR4SGV4LCAnaGV4Jyk7XG4gICAgY29uc3QgdHhEYXRhV2l0aFBhZGRpbmcgPSB0eEZyb21IZXguc2xpY2UoMzIpO1xuICAgIGNvbnN0IHR4RGF0YSA9IHR4RGF0YVdpdGhQYWRkaW5nLnNsaWNlKDAsIHR4RGF0YVdpdGhQYWRkaW5nLmxlbmd0aCAtIDMyKTtcbiAgICBjb25zdCBkZXNlcmlhbGl6ZWRUeEpzb24gPSBhd2FpdCB0aGlzLmRlc2VyaWFsaXplVHJhbnNhY3Rpb24oe1xuICAgICAgdHJhbnNhY3Rpb246IHsgcGFja2VkX3RyeDogdHhEYXRhLnRvU3RyaW5nKCdoZXgnKSB9LFxuICAgICAgaGVhZGVyczogdHhQcmVidWlsZC5oZWFkZXJzLFxuICAgIH0pO1xuICAgIGlmICghZGVzZXJpYWxpemVkVHhKc29uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NvdWxkIG5vdCBwcm9jZXNzIHRyYW5zYWN0aW9uIGZyb20gdHhIZXgnKTtcbiAgICB9XG4gICAgY29uc3QgdHhKc29uRnJvbUhleDogRGVzZXJpYWxpemVkRW9zVHJhbnNhY3Rpb24gPSBkZXNlcmlhbGl6ZWRUeEpzb247XG5cbiAgICAvLyBjaGVjayB0aGF0IGlmIHR4UGFyYW1zIGhhcyBhIHR4UHJlYnVpbGQsIGl0IHNob3VsZCBiZSB0aGUgc2FtZSBhcyB0eFByZWJ1aWxkXG4gICAgaWYgKHR4UGFyYW1zLnR4UHJlYnVpbGQgJiYgIV8uaXNFcXVhbCh0eFBhcmFtcy50eFByZWJ1aWxkLCB0eFByZWJ1aWxkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnB1dHMgdHhQYXJhbXMudHhQcmVidWlsZCBhbmQgdHhQcmVidWlsZCBleHBlY3RlZCB0byBiZSBlcXVhbCBidXQgd2VyZSBub3QnKTtcbiAgICB9XG5cbiAgICAvLyBjaGVjayBpZiBwcmVidWlsZCBoYXMgYSB0cmFuc2FjdGlvblxuICAgIGlmICghdHhQcmVidWlsZC50cmFuc2FjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHRyYW5zYWN0aW9uIGluIHR4UHJlYnVpbGQnKTtcbiAgICB9XG5cbiAgICAvLyBjaGVjayBpZiB0cmFuc2FjdGlvbiBoYXMgYSBwYWNrZWRfdHJ4XG4gICAgaWYgKCF0eFByZWJ1aWxkLnRyYW5zYWN0aW9uPy5wYWNrZWRfdHJ4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgdHJhbnNhY3Rpb24ucGFja2VkX3RyeCBpbiB0eFByZWJ1aWxkJyk7XG4gICAgfVxuXG4gICAgLy8gY29uc3RydWN0IHRyYW5zYWN0aW9uIHVzaW5nIHBhY2tlZF90cnhcbiAgICBjb25zdCBkZXNlcmlhbGl6ZWRUeEpzb25Gcm9tUGFja2VkVHJ4ID0gYXdhaXQgdGhpcy5kZXNlcmlhbGl6ZVRyYW5zYWN0aW9uKHtcbiAgICAgIHRyYW5zYWN0aW9uOiB7IHBhY2tlZF90cng6IHR4UHJlYnVpbGQudHJhbnNhY3Rpb24ucGFja2VkX3RyeCB9LFxuICAgICAgaGVhZGVyczogdHhQcmVidWlsZC5oZWFkZXJzLFxuICAgIH0pO1xuICAgIGlmICghZGVzZXJpYWxpemVkVHhKc29uRnJvbVBhY2tlZFRyeCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjb3VsZCBub3QgcHJvY2VzcyB0cmFuc2FjdGlvbiBmcm9tIHBhY2tlZF90cngnKTtcbiAgICB9XG4gICAgY29uc3QgdHhKc29uRnJvbVBhY2tlZFRyeDogRGVzZXJpYWxpemVkRW9zVHJhbnNhY3Rpb24gPSBkZXNlcmlhbGl6ZWRUeEpzb25Gcm9tUGFja2VkVHJ4O1xuXG4gICAgLy8gZGVlcCBjaGVjayBvZiBvYmplY3QgZnJvbSBwYWNrZWRfdHJ4IGFuZCB0eEhleFxuICAgIGlmICghXy5pc0VxdWFsKHR4SnNvbkZyb21QYWNrZWRUcngsIHR4SnNvbkZyb21IZXgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VucGFja2VkIHBhY2tlZF90cnggYW5kIHVucGFja2VkIHR4SGV4IGFyZSBub3QgZXF1YWwnKTtcbiAgICB9XG5cbiAgICBpZiAodHhQYXJhbXMucmVjaXBpZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ29ubHkgMCBvciAxIHJlY2lwaWVudHMgYXJlIHN1cHBvcnRlZCcpO1xuICAgIH1cblxuICAgIC8vIGNoZWNrIHRoZSBhbW91bnRzLCByZWNpcGllbnQsIGFuZCBjb2luIG5hbWUgZm9yIHRyYW5zZmVyc1xuICAgIGlmICh0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgY29uc3QgZXhwZWN0ZWRPdXRwdXQgPSB0eFBhcmFtcy5yZWNpcGllbnRzWzBdO1xuXG4gICAgICAvLyBjaGVjayBvdXRwdXQgYWRkcmVzcyBhbmQgbWVtb0lkXG4gICAgICBjb25zdCBleHBlY3RlZE91dHB1dEFkZHJlc3NBbmRNZW1vSWQgPSB0aGlzLmdldEFkZHJlc3NEZXRhaWxzKGV4cGVjdGVkT3V0cHV0LmFkZHJlc3MpO1xuICAgICAgY29uc3QgdHhIZXhBY3Rpb24gPSB0eEpzb25Gcm9tSGV4LmFjdGlvbnNbMF07XG4gICAgICBjb25zdCB0eEhleFRyYW5zZmVyQWN0aW9uID0gdHhIZXhBY3Rpb24uZGF0YSBhcyBUcmFuc2ZlckFjdGlvbkRhdGE7XG5cbiAgICAgIGlmICh0eEhleFRyYW5zZmVyQWN0aW9uLnRvICE9PSBleHBlY3RlZE91dHB1dEFkZHJlc3NBbmRNZW1vSWQuYWRkcmVzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4SGV4IHJlY2VpdmUgYWRkcmVzcyBkb2VzIG5vdCBtYXRjaCBleHBlY3RlZCByZWNpcGllbnQgYWRkcmVzcycpO1xuICAgICAgfVxuICAgICAgLy8gY2hlY2sgaWYgdHhhY3Rpb24gbWVtb2lkIGlzIGVxdWFsIHRvIGFkZHJlc3MgbWVtbyBpZCBvbmx5IGlmIGFkZHJlc3MgYWxzbyBoYXMgbWVtb2lkIHByZXNlbnRcbiAgICAgIGlmICghXy5pc1VuZGVmaW5lZChleHBlY3RlZE91dHB1dEFkZHJlc3NBbmRNZW1vSWQubWVtb0lkKSkge1xuICAgICAgICBpZiAodHhIZXhUcmFuc2ZlckFjdGlvbi5tZW1vICE9PSBleHBlY3RlZE91dHB1dEFkZHJlc3NBbmRNZW1vSWQubWVtb0lkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0eEhleCByZWNlaXZlIG1lbW9JZCBkb2VzIG5vdCBtYXRjaCBleHBlY3RlZCByZWNpcGllbnQgbWVtb0lkJyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gY2hlY2sgYW1vdW50IGFuZCBjb2luXG4gICAgICBjb25zdCBleHBlY3RlZE91dHB1dEFtb3VudCA9IGV4cGVjdGVkT3V0cHV0LmFtb3VudDtcbiAgICAgIGNvbnN0IGFjdHVhbEFtb3VudEFuZENvaW4gPSB0eEhleFRyYW5zZmVyQWN0aW9uLnF1YW50aXR5LnNwbGl0KCcgJyk7XG4gICAgICBjb25zdCBhY3R1YWxPdXRwdXRBbW91bnQgPSB0aGlzLmJpZ1VuaXRzVG9CYXNlVW5pdHMoYWN0dWFsQW1vdW50QW5kQ29pblswXSk7XG4gICAgICBpZiAoZXhwZWN0ZWRPdXRwdXRBbW91bnQgIT09IGFjdHVhbE91dHB1dEFtb3VudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4SGV4IHJlY2VpdmUgYW1vdW50IGRvZXMgbm90IG1hdGNoIGV4cGVjdGVkIHJlY2lwaWVudCBhbW91bnQnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHR4UHJlYnVpbGQuY29pbiA9PT0gJ2VvcycgfHwgdHhQcmVidWlsZC5jb2luID09PSAndGVvcycpIHtcbiAgICAgICAgY29uc3QgZXhwZWN0ZWRTeW1ib2wgPSBfLmlzTmlsKHR4UHJlYnVpbGQudG9rZW4pID8gJ0VPUycgOiB0eFByZWJ1aWxkLnRva2VuLnNwbGl0KCc6JylbMV07XG5cbiAgICAgICAgaWYgKGFjdHVhbEFtb3VudEFuZENvaW5bMV0gIT09IGV4cGVjdGVkU3ltYm9sKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0eEhleCByZWNlaXZlIHN5bWJvbCBkb2VzIG5vdCBtYXRjaCBleHBlY3RlZCByZWNpcGllbnQgc3ltYm9sJyk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHRoaXMgc2hvdWxkIG5ldmVyIGhhcHBlblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4SGV4IGNvaW4gbmFtZSBkb2VzIG5vdCBtYXRjaCBleHBlY3RlZCBjb2luIG5hbWUnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhIHJhbmRvbSBFT1MgYWRkcmVzcy5cbiAgICpcbiAgICogVGhpcyBpcyBqdXN0IGEgcmFuZG9tIHN0cmluZyB3aGljaCBhYmlkZXMgYnkgdGhlIEVPUyBhZGRkcmVzcyBjb25zdHJhaW50cyxcbiAgICogYW5kIGlzIG5vdCBhY3R1YWxseSBjaGVja2VkIGZvciBhdmFpbGFiaWxpdHkgb24gdGhlIEVPUyBibG9ja2NoYWluLlxuICAgKlxuICAgKiBDdXJyZW50IEVPUyBhZGRyZXNzIGNvbnN0cmFpbnRzIGFyZTpcbiAgICogKiBBZGRyZXNzIG11c3QgYmUgZXhhY3RseSAxMiBjaGFyYWN0ZXJzXG4gICAqICogQWRkcmVzcyBtdXN0IG9ubHkgY29udGFpbiBsb3dlcmNhc2UgbGV0dGVycyBhbmQgbnVtYmVycyAxLTVcbiAgICogQHJldHVybnMgYSB2YWxpZGx5IGZvcm1hdHRlZCBFT1MgYWRkcmVzcywgd2hpY2ggbWF5IG9yIG1heSBub3QgYWN0dWFsbHkgYmUgYXZhaWxhYmxlIG9uIGNoYWluLlxuICAgKi9cbiAgZ2VuZXJhdGVSYW5kb21BZGRyZXNzKHBhcmFtczogUmVjb3JkPHN0cmluZywgbmV2ZXI+KTogc3RyaW5nIHtcbiAgICBjb25zdCBhZGRyZXNzOiBzdHJpbmdbXSA9IFtdO1xuICAgIHdoaWxlIChhZGRyZXNzLmxlbmd0aCA8IDEyKSB7XG4gICAgICBjb25zdCBjaGFyID0gXy5zYW1wbGUoRW9zLlZBTElEX0FERFJFU1NfQ0hBUlMpO1xuICAgICAgaWYgKCFjaGFyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZmFpbGVkIHRvIHNhbXBsZSB2YWxpZCBFT1MgYWRkcmVzcyBjaGFyYWN0ZXJzJyk7XG4gICAgICB9XG4gICAgICBhZGRyZXNzLnB1c2goY2hhcik7XG4gICAgfVxuICAgIHJldHVybiBhZGRyZXNzLmpvaW4oJycpO1xuICB9XG59XG4iXX0=

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


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