PHP WebShell

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

Просмотр файла: utils.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.CosmosUtils = void 0;
const sdk_core_1 = require("@bitgo/sdk-core");
const amino_1 = require("@cosmjs/amino");
const encoding_1 = require("@cosmjs/encoding");
const proto_signing_1 = require("@cosmjs/proto-signing");
const stargate_1 = require("@cosmjs/stargate");
const statics_1 = require("@bitgo/statics");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const tx_1 = require("cosmjs-types/cosmos/tx/v1beta1/tx");
const tx_2 = require("cosmjs-types/cosmwasm/wasm/v1/tx");
const crypto_1 = require("crypto");
const constants = __importStar(require("./constants"));
const keyPair_1 = require("./keyPair");
const { MsgSend } = require('../../resources/MsgCompiled').types;
class CosmosUtils {
    constructor() {
        this.registry = new proto_signing_1.Registry([...stargate_1.defaultRegistryTypes]);
        this.registry.register(constants.executeContractMsgTypeUrl, tx_2.MsgExecuteContract);
        this.registry.register('/types.MsgSend', MsgSend);
    }
    /** @inheritdoc */
    isValidBlockId(hash) {
        return this.validateBlake2b(hash);
    }
    /** @inheritdoc */
    isValidPrivateKey(key) {
        try {
            new keyPair_1.CosmosKeyPair({ prv: key });
            return true;
        }
        catch {
            return false;
        }
    }
    /** @inheritdoc */
    isValidPublicKey(key) {
        try {
            new keyPair_1.CosmosKeyPair({ pub: key });
            return true;
        }
        catch {
            return false;
        }
    }
    /** @inheritdoc */
    isValidSignature(signature) {
        throw new sdk_core_1.NotImplementedError('isValidSignature not implemented');
    }
    /** @inheritdoc */
    isValidTransactionId(txId) {
        return this.validateBlake2b(txId);
    }
    /**
     * Checks if transaction hash is in valid black2b format
     */
    validateBlake2b(hash) {
        if (hash?.length !== 64) {
            return false;
        }
        return hash.match(/^[a-zA-Z0-9]+$/) !== null;
    }
    /**
     * Validates whether amounts are in range
     *
     * @param {number[]} amounts - the amounts to validate
     * @returns {boolean} - the validation result
     */
    isValidAmounts(amounts) {
        for (const amount of amounts) {
            if (!this.isValidAmount(amount)) {
                return false;
            }
        }
        return true;
    }
    /**
     * Validates whether amount is in range
     * @param {number} amount
     * @returns {boolean} the validation result
     */
    isValidAmount(amount) {
        const bigNumberAmount = new bignumber_js_1.default(amount);
        if (!bigNumberAmount.isInteger() || bigNumberAmount.isLessThanOrEqualTo(0)) {
            return false;
        }
        return true;
    }
    /**
     * Decodes raw tx data into messages, signing info, and fee data
     * @param {string} txHex - raw base64 tx
     * @returns {DecodedTxRaw} Decoded transaction
     */
    getDecodedTxFromRawBase64(txRaw) {
        try {
            return (0, proto_signing_1.decodeTxRaw)((0, encoding_1.fromBase64)(txRaw));
        }
        catch (e) {
            throw new sdk_core_1.ParseTransactionError('Error decoding TxRaw base64 encoded string: ' + e.message);
        }
    }
    /**
     * Returns the array of messages in the body of the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {EncodeObject[]} messages along with type url
     */
    getEncodedMessagesFromDecodedTx(decodedTx) {
        return decodedTx.body.messages;
    }
    /**
     * Checks the txn sequence is valid or not
     * @param {number} sequence
     */
    validateSequence(sequence) {
        if (sequence < 0) {
            throw new sdk_core_1.InvalidTransactionError('Invalid sequence: less than zero');
        }
    }
    /**
     * Pulls the sequence number from a DecodedTxRaw AuthInfo property
     * @param {DecodedTxRaw} decodedTx
     * @returns {number} sequence
     */
    getSequenceFromDecodedTx(decodedTx) {
        return Number(decodedTx.authInfo.signerInfos[0].sequence);
    }
    /**
     * Pulls the typeUrl from the encoded message of a DecodedTxRaw
     * @param {DecodedTxRaw} decodedTx
     * @returns {string} cosmos proto type url
     */
    getTypeUrlFromDecodedTx(decodedTx) {
        const encodedMessage = this.getEncodedMessagesFromDecodedTx(decodedTx)[0];
        return encodedMessage.typeUrl;
    }
    /**
     * Returns the fee data from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {FeeData} fee data
     */
    getGasBudgetFromDecodedTx(decodedTx) {
        return {
            amount: decodedTx.authInfo.fee?.amount,
            gasLimit: Number(decodedTx.authInfo.fee?.gasLimit),
        };
    }
    /**
     * Returns the publicKey from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {string | undefined} publicKey in hex format if it exists, undefined otherwise
     */
    getPublicKeyFromDecodedTx(decodedTx) {
        const publicKeyUInt8Array = decodedTx.authInfo.signerInfos?.[0].publicKey?.value;
        if (publicKeyUInt8Array) {
            return (0, encoding_1.toHex)((0, encoding_1.fromBase64)((0, proto_signing_1.decodePubkey)(decodedTx.authInfo.signerInfos?.[0].publicKey)?.value));
        }
        return undefined;
    }
    /**
     * Returns the array of MessageData[] from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {MessageData[]} Send transaction message data
     */
    getSendMessageDataFromDecodedTx(decodedTx) {
        return decodedTx.body.messages.map((message) => {
            const value = this.registry.decode(message);
            return {
                value: {
                    fromAddress: value.fromAddress,
                    toAddress: value.toAddress,
                    amount: value.amount,
                },
                typeUrl: message.typeUrl,
            };
        });
    }
    /**
     * Returns the array of MessageData[] from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {MessageData[]} Delegate of undelegate transaction message data
     */
    getDelegateOrUndelegateMessageDataFromDecodedTx(decodedTx) {
        return decodedTx.body.messages.map((message) => {
            const value = this.registry.decode(message);
            return {
                value: {
                    delegatorAddress: value.delegatorAddress,
                    validatorAddress: value.validatorAddress,
                    amount: value.amount,
                },
                typeUrl: message.typeUrl,
            };
        });
    }
    /**
     * Returns the array of MessageData[] from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {MessageData[]} Redelegate transaction message data
     */
    getRedelegateMessageDataFromDecodedTx(decodedTx) {
        return decodedTx.body.messages.map((message) => {
            const value = this.registry.decode(message);
            return {
                value: {
                    delegatorAddress: value.delegatorAddress,
                    validatorSrcAddress: value.validatorSrcAddress,
                    validatorDstAddress: value.validatorDstAddress,
                    amount: value.amount,
                },
                typeUrl: message.typeUrl,
            };
        });
    }
    /**
     * Returns the array of MessageData[] from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {MessageData[]} WithdrawDelegatorRewards transaction message data
     */
    getWithdrawRewardsMessageDataFromDecodedTx(decodedTx) {
        return decodedTx.body.messages.map((message) => {
            const value = this.registry.decode(message);
            return {
                value: {
                    delegatorAddress: value.delegatorAddress,
                    validatorAddress: value.validatorAddress,
                },
                typeUrl: message.typeUrl,
            };
        });
    }
    /**
     * Returns the array of MessageData[] from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {MessageData[]} Delegate of undelegate transaction message data
     */
    getWithdrawDelegatorRewardsMessageDataFromDecodedTx(decodedTx) {
        return decodedTx.body.messages.map((message) => {
            const value = this.registry.decode(message);
            return {
                value: {
                    delegatorAddress: value.delegatorAddress,
                    validatorAddress: value.validatorAddress,
                },
                typeUrl: message.typeUrl,
            };
        });
    }
    /**
     * Get a cosmos chain address from its equivalent hex
     * @param {string} prefix
     * @param {string} addressHex
     * @returns {string}
     */
    getCosmosLikeAddressFromHex(prefix, addressHex) {
        if (addressHex.indexOf('0x') === 0) {
            addressHex = addressHex.slice(2);
        }
        return (0, encoding_1.toBech32)(prefix, (0, encoding_1.fromHex)(addressHex));
    }
    /**
     * Get a EVM chain address from its equivalent hex
     * @param {string} prefix
     * @param {string} addressHex
     * @returns {string}
     */
    getEvmLikeAddressFromCosmos(cosmosLikeAddress) {
        return '0x' + (0, encoding_1.toHex)((0, encoding_1.fromBech32)(cosmosLikeAddress).data);
    }
    /**
     * Returns the array of MessageData[] from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {MessageData[]} Execute contract transaction message data
     */
    getExecuteContractMessageDataFromDecodedTx(decodedTx) {
        return decodedTx.body.messages.map((message) => {
            const value = this.registry.decode(message);
            return {
                value: {
                    sender: value.sender,
                    contract: value.contract,
                    msg: value.msg,
                    funds: value.funds,
                },
                typeUrl: message.typeUrl,
            };
        });
    }
    /**
     * Returns the array of MessageData[] from the decoded transaction
     * @param {DecodedTxRaw} decodedTx
     * @returns {MessageData[]} Custom transaction message data
     */
    getCustomMessageDataFromDecodedTx(decodedTx) {
        throw new sdk_core_1.NotSupported('Custom message data not supported');
    }
    /**
     * Determines bitgo transaction type based on cosmos proto type url
     * @param {string} typeUrl
     * @returns {TransactionType | undefined} TransactionType if url is supported else undefined
     */
    getTransactionTypeFromTypeUrl(typeUrl) {
        switch (typeUrl) {
            case constants.sendMsgTypeUrl:
                return sdk_core_1.TransactionType.Send;
            case constants.sendMsgType:
                return sdk_core_1.TransactionType.Send;
            case constants.delegateMsgTypeUrl:
                return sdk_core_1.TransactionType.StakingActivate;
            case constants.undelegateMsgTypeUrl:
                return sdk_core_1.TransactionType.StakingDeactivate;
            case constants.withdrawDelegatorRewardMsgTypeUrl:
                return sdk_core_1.TransactionType.StakingWithdraw;
            case constants.executeContractMsgTypeUrl:
                return sdk_core_1.TransactionType.ContractCall;
            case constants.redelegateTypeUrl:
                return sdk_core_1.TransactionType.StakingRedelegate;
            default:
                return undefined;
        }
    }
    /**
     * Takes a hex encoded pubkey, converts it to the Amino JSON representation (type/value wrapper)
     * and returns it as protobuf `Any`
     * @param {string} pubkey hex encoded compressed secp256k1 public key
     * @returns {Any} pubkey encoded as protobuf `Any`
     */
    getEncodedPubkey(pubkey) {
        return (0, proto_signing_1.encodePubkey)((0, amino_1.encodeSecp256k1Pubkey)((0, encoding_1.fromHex)(pubkey)));
    }
    /**
     * Gets the send messages used in the final step of encoding a transaction. This allows for any final processing needed.
     * @param {CosmosLikeTransaction} cosmosLikeTransaction transaction to get send messages from
     * @returns {Any[]} processed send messages
     */
    getSendMessagesForEncodingTx(cosmosLikeTransaction) {
        return cosmosLikeTransaction.sendMessages;
    }
    /**
     * Creates a txRaw from an cosmos like transaction @see CosmosLikeTransaction
     * @Precondition cosmosLikeTransaction.publicKey must be defined
     * @param {CosmosLikeTransaction} cosmosLikeTransaction
     * @returns {TxRaw} Unsigned raw transaction
     */
    createTxRawFromCosmosLikeTransaction(cosmosLikeTransaction) {
        if (!cosmosLikeTransaction.publicKey) {
            throw new Error('publicKey is required to create a txRaw');
        }
        const encodedPublicKey = this.getEncodedPubkey(cosmosLikeTransaction.publicKey);
        const messages = this.getSendMessagesForEncodingTx(cosmosLikeTransaction);
        let txBodyValue;
        if (cosmosLikeTransaction.memo) {
            txBodyValue = {
                memo: cosmosLikeTransaction.memo,
                messages: messages,
            };
        }
        else {
            txBodyValue = {
                messages: messages,
            };
        }
        const txBodyBytes = this.registry.encodeTxBody(txBodyValue);
        const sequence = cosmosLikeTransaction.sequence;
        const authInfoBytes = (0, proto_signing_1.makeAuthInfoBytes)([{ pubkey: encodedPublicKey, sequence }], cosmosLikeTransaction.gasBudget.amount, cosmosLikeTransaction.gasBudget.gasLimit, undefined, undefined, undefined);
        return tx_1.TxRaw.fromPartial({
            bodyBytes: txBodyBytes,
            authInfoBytes: authInfoBytes,
        });
    }
    /**
     * Encodes a signature into a txRaw
     * @param {string} publicKeyHex publicKey in hex encoded string format
     * @param {string} signatureHex signature in hex encoded string format
     * @param {TxRaw} unsignedTx raw transaction
     * @returns {TxRaw} Signed raw transaction
     */
    createSignedTxRaw(publicKeyHex, signatureHex, unsignedTx) {
        const stdSignature = (0, amino_1.encodeSecp256k1Signature)((0, encoding_1.fromHex)(publicKeyHex), (0, encoding_1.fromHex)(signatureHex));
        return tx_1.TxRaw.fromPartial({
            bodyBytes: unsignedTx.bodyBytes,
            authInfoBytes: unsignedTx.authInfoBytes,
            signatures: [(0, encoding_1.fromBase64)(stdSignature.signature)],
        });
    }
    /**
     * Decodes a raw transaction into a DecodedTxRaw and checks if it has non empty signatures
     * @param {string} rawTransaction
     * @returns {boolean} true if transaction is signed else false
     */
    isSignedRawTx(rawTransaction) {
        const decodedTx = this.getDecodedTxFromRawBase64(rawTransaction);
        if (decodedTx.signatures.length > 0) {
            return true;
        }
        return false;
    }
    /**
     * Returns whether or not the string is a valid protocol public key
     * @param {string | undefined} publicKey - the  public key to be validated
     */
    validatePublicKey(publicKey) {
        if (publicKey !== undefined) {
            try {
                new keyPair_1.CosmosKeyPair({ pub: publicKey });
            }
            catch {
                throw new sdk_core_1.InvalidTransactionError(`Invalid Public Key`);
            }
        }
    }
    /**
     * Creates a sign doc from an cosmos like transaction @see CosmosLikeTransaction
     * @Precondition cosmosLikeTransaction.accountNumber and cosmosLikeTransaction.chainId must be defined
     * @param {CosmosLikeTransaction} cosmosLikeTransaction
     * @returns {SignDoc} sign doc
     */
    createSignDoc(cosmosLikeTransaction, accountNumber, chainId) {
        if (!accountNumber) {
            throw new Error('accountNumber is required to create a sign doc');
        }
        if (!chainId) {
            throw new Error('chainId is required to create a sign doc');
        }
        if (!cosmosLikeTransaction) {
            throw new Error('cosmosLikeTransaction is required to create a sign doc');
        }
        const txRaw = this.createTxRawFromCosmosLikeTransaction(cosmosLikeTransaction);
        return (0, proto_signing_1.makeSignDoc)(txRaw.bodyBytes, txRaw.authInfoBytes, chainId, accountNumber);
    }
    /**
     * Returns whether or not the string is a valid hex
     * @param hexString - hex string format
     * @returns {boolean} true if string is hex else false
     */
    isValidHexString(hexString) {
        return /^[0-9A-Fa-f]*$/.test(hexString);
    }
    /**
     * Validates the WithdrawDelegatorRewardsMessage
     * @param {WithdrawDelegatorRewardsMessage} withdrawRewardsMessage - The WithdrawDelegatorRewardsMessage to validate.
     * @throws {InvalidTransactionError} Throws an error if the validatorAddress or delegatorAddress is invalid or missing.
     */
    validateWithdrawRewardsMessage(withdrawRewardsMessage) {
        if (!withdrawRewardsMessage.validatorAddress ||
            !this.isValidValidatorAddress(withdrawRewardsMessage.validatorAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid WithdrawDelegatorRewardsMessage validatorAddress: ` + withdrawRewardsMessage.validatorAddress);
        }
        if (!withdrawRewardsMessage.delegatorAddress || !this.isValidAddress(withdrawRewardsMessage.delegatorAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid WithdrawDelegatorRewardsMessage delegatorAddress: ` + withdrawRewardsMessage.delegatorAddress);
        }
    }
    /**
     * Helper method to check if the specified properties in an object are missing or null.
     * @param {Object} obj - The object to check.
     * @param {string[]} keys - An array of property keys to check.
     * @throws {Error} Throws an error if any of the specified properties are missing or null.
     */
    isObjPropertyNull(obj, keys) {
        for (const key of keys) {
            if (obj[key] == null) {
                throw new Error(`Missing or null value for property ${key}`);
            }
        }
    }
    /**
     * Validates the DelegateOrUndelegeteMessage
     * @param {DelegateOrUndelegeteMessage} delegateMessage - The DelegateOrUndelegeteMessage to validate.
     * @throws {InvalidTransactionError} Throws an error if the validatorAddress, delegatorAddress, or amount is invalid or missing.
     */
    validateDelegateOrUndelegateMessage(delegateMessage) {
        this.isObjPropertyNull(delegateMessage, ['validatorAddress', 'delegatorAddress']);
        if (!this.isValidValidatorAddress(delegateMessage.validatorAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid DelegateOrUndelegeteMessage validatorAddress: ` + delegateMessage.validatorAddress);
        }
        if (!this.isValidAddress(delegateMessage.delegatorAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid DelegateOrUndelegeteMessage delegatorAddress: ` + delegateMessage.delegatorAddress);
        }
        this.validateAmount(delegateMessage.amount);
    }
    /**
     * Validates the RedelegateMessage
     * @param {DelegateOrUndelegeteMessage} redelegateMessage - The RedelegateMessage to validate.
     * @throws {InvalidTransactionError} Throws an error if the validatorSrcAddress, validatorDstAddress, delegatorAddress, or amount is invalid or missing.
     */
    validateRedelegateMessage(redelegateMessage) {
        this.isObjPropertyNull(redelegateMessage, ['validatorSrcAddress', 'validatorDstAddress', 'delegatorAddress']);
        if (!this.isValidValidatorAddress(redelegateMessage.validatorSrcAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid RedelegateMessage validatorSrcAddress: ` + redelegateMessage.validatorSrcAddress);
        }
        if (!this.isValidValidatorAddress(redelegateMessage.validatorDstAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid RedelegateMessage validatorDstAddress: ` + redelegateMessage.validatorDstAddress);
        }
        if (!this.isValidAddress(redelegateMessage.delegatorAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid DelegateOrUndelegeteMessage delegatorAddress: ` + redelegateMessage.delegatorAddress);
        }
        this.validateAmount(redelegateMessage.amount);
    }
    /**
     * Validates the CustomMessage
     * @param {CustomMessage} customMessage - The CustomMessage to validate.
     * @throws {InvalidTransactionError} Throws an error if the custom message is invalid or missing required fields.
     * @throws {NotSupported} Throws an error if the custom message data is not supported.
     */
    validateCustomMessage(customMessage) {
        throw new sdk_core_1.NotSupported('Custom message data not supported');
    }
    /**
     * Validates the MessageData
     * @param {MessageData} messageData - The MessageData to validate.
     * @throws {InvalidTransactionError} Throws an error if the messageData is invalid or missing required fields.
     */
    validateMessageData(messageData) {
        if (messageData == null) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid MessageData: undefined`);
        }
        if (messageData.typeUrl == null || this.getTransactionTypeFromTypeUrl(messageData.typeUrl) == null) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid MessageData typeurl: ` + messageData.typeUrl);
        }
        const type = this.getTransactionTypeFromTypeUrl(messageData.typeUrl);
        switch (type) {
            case sdk_core_1.TransactionType.Send: {
                const value = messageData.value;
                this.validateSendMessage(value);
                break;
            }
            case sdk_core_1.TransactionType.StakingActivate:
            case sdk_core_1.TransactionType.StakingDeactivate: {
                const value = messageData.value;
                this.validateDelegateOrUndelegateMessage(value);
                break;
            }
            case sdk_core_1.TransactionType.StakingWithdraw: {
                const value = messageData.value;
                this.validateWithdrawRewardsMessage(value);
                break;
            }
            case sdk_core_1.TransactionType.ContractCall: {
                const value = messageData.value;
                this.validateExecuteContractMessage(value, sdk_core_1.TransactionType.ContractCall);
                break;
            }
            case sdk_core_1.TransactionType.StakingRedelegate: {
                const value = messageData.value;
                this.validateRedelegateMessage(value);
                break;
            }
            case sdk_core_1.TransactionType.CustomTx: {
                const value = messageData.value;
                this.validateCustomMessage(value);
                break;
            }
            default:
                throw new sdk_core_1.InvalidTransactionError(`Invalid MessageData TypeUrl is not supported: ` + messageData.typeUrl);
        }
    }
    /**
     * Validates the Cosmos-like transaction.
     * @param {CosmosLikeTransaction} tx - The transaction to validate.
     * @throws {InvalidTransactionError} Throws an error if the transaction is invalid or missing required fields.
     */
    validateTransaction(tx) {
        this.validateSequence(tx.sequence);
        this.validateGasBudget(tx.gasBudget);
        this.validatePublicKey(tx.publicKey);
        if (tx.sendMessages === undefined || tx.sendMessages.length === 0) {
            throw new sdk_core_1.InvalidTransactionError('Invalid transaction: messages is required');
        }
        else {
            tx.sendMessages.forEach((message) => this.validateMessageData(message));
        }
    }
    /**
     * Creates a Cosmos-like transaction.
     * @param {number} sequence - The sender address sequence number for the transaction.
     * @param {MessageData[]} messages - The array of message data for the transaction.
     * @param {FeeData} gasBudget - The fee data for the transaction.
     * @param {string} [publicKey] - The public key associated with the sender.
     * @param {string} [memo] - The memo for the transaction.
     * @returns {CosmosLikeTransaction} Returns the created Cosmos-like transaction.
     * @throws {InvalidTransactionError} Throws an error if the created transaction is invalid.
     */
    createTransaction(sequence, messages, gasBudget, publicKey, memo) {
        const cosmosLikeTxn = {
            sequence: sequence,
            sendMessages: messages,
            gasBudget: gasBudget,
            publicKey: publicKey,
            memo: memo,
        };
        this.validateTransaction(cosmosLikeTxn);
        return cosmosLikeTxn;
    }
    /**
     * Creates a Cosmos-like transaction with a hash.
     * @param {number} sequence - The sender address sequence number for the transaction.
     * @param {MessageData[]} messages - The array of message data for the transaction.
     * @param {FeeData} gasBudget - The fee data for the transaction.
     * @param {string} [publicKey] - The public key associated with the transaction.
     * @param {Buffer} [signature] - The signature for the transaction.
     * @param {string} [memo] - The memo for the transaction.
     * @returns {CosmosLikeTransaction} Returns the created Cosmos-like transaction with the hash and signature if provided.
     */
    createTransactionWithHash(sequence, messages, gasBudget, publicKey, signature, memo) {
        const cosmosLikeTxn = this.createTransaction(sequence, messages, gasBudget, publicKey, memo);
        let hash = constants.UNAVAILABLE_TEXT;
        if (signature !== undefined) {
            const unsignedTx = this.createTxRawFromCosmosLikeTransaction(cosmosLikeTxn);
            const signedTx = tx_1.TxRaw.fromPartial({
                bodyBytes: unsignedTx.bodyBytes,
                authInfoBytes: unsignedTx.authInfoBytes,
                signatures: [signature],
            });
            hash = (0, crypto_1.createHash)('sha256')
                .update(tx_1.TxRaw.encode(signedTx).finish())
                .digest()
                .toString('hex')
                .toLocaleUpperCase('en-US');
            return { ...cosmosLikeTxn, hash: hash, signature: signature };
        }
        return { ...cosmosLikeTxn, hash: hash };
    }
    /**
     * Deserializes base64 enocded raw transaction string into @see CosmosLikeTransaction
     * @param {string} rawTx base64 enocded raw transaction string
     * @returns {CosmosLikeTransaction} Deserialized cosmosLikeTransaction
     */
    deserializeTransaction(rawTx) {
        const decodedTx = this.getDecodedTxFromRawBase64(rawTx);
        const typeUrl = this.getTypeUrlFromDecodedTx(decodedTx);
        const type = this.getTransactionTypeFromTypeUrl(typeUrl);
        let sendMessageData;
        if (type === sdk_core_1.TransactionType.Send) {
            sendMessageData = this.getSendMessageDataFromDecodedTx(decodedTx);
        }
        else if (type === sdk_core_1.TransactionType.StakingActivate || type === sdk_core_1.TransactionType.StakingDeactivate) {
            sendMessageData = this.getDelegateOrUndelegateMessageDataFromDecodedTx(decodedTx);
        }
        else if (type === sdk_core_1.TransactionType.StakingWithdraw) {
            sendMessageData = this.getWithdrawRewardsMessageDataFromDecodedTx(decodedTx);
        }
        else if (type === sdk_core_1.TransactionType.ContractCall) {
            sendMessageData = this.getExecuteContractMessageDataFromDecodedTx(decodedTx);
        }
        else if (type === sdk_core_1.TransactionType.StakingRedelegate) {
            sendMessageData = this.getRedelegateMessageDataFromDecodedTx(decodedTx);
        }
        else if (type === sdk_core_1.TransactionType.CustomTx) {
            sendMessageData = this.getCustomMessageDataFromDecodedTx(decodedTx);
        }
        else {
            throw new Error('Transaction type not supported: ' + typeUrl);
        }
        const sequence = this.getSequenceFromDecodedTx(decodedTx);
        const gasBudget = this.getGasBudgetFromDecodedTx(decodedTx);
        const publicKey = this.getPublicKeyFromDecodedTx(decodedTx);
        const signature = decodedTx.signatures?.[0] !== undefined ? Buffer.from(decodedTx.signatures[0]) : undefined;
        return this.createTransactionWithHash(sequence, sendMessageData, gasBudget, publicKey, signature, decodedTx.body?.memo);
    }
    /**
     * Validates an array of coin amounts.
     * @param {Coin[]} amountArray - The array of coin amounts to validate.
     * @param {TransactionType} transactionType - optional field for transaction type
     */
    validateAmountData(amountArray, transactionType) {
        amountArray.forEach((coinAmount) => {
            this.validateAmount(coinAmount, transactionType);
        });
    }
    /**
     * Validates the gas limit and gas amount for a transaction.
     * @param {FeeData} gasBudget - The gas budget to validate.
     * @throws {InvalidTransactionError} Throws an error if the gas budget is invalid.
     */
    validateGasBudget(gasBudget) {
        if (gasBudget.gasLimit <= 0) {
            throw new sdk_core_1.InvalidTransactionError('Invalid gas limit ' + gasBudget.gasLimit);
        }
        this.validateAmountData(gasBudget.amount);
    }
    /**
     * Validates a send message for a transaction.
     * @param {SendMessage} sendMessage - The send message to validate.
     * @throws {InvalidTransactionError} Throws an error if the send message is invalid.
     */
    validateSendMessage(sendMessage) {
        if (!sendMessage.toAddress || !this.isValidAddress(sendMessage.toAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid SendMessage toAddress: ` + sendMessage.toAddress);
        }
        if (!sendMessage.fromAddress || !this.isValidAddress(sendMessage.fromAddress)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid SendMessage fromAddress: ` + sendMessage.fromAddress);
        }
        this.validateAmountData(sendMessage.amount);
    }
    /**
     * Validates a coin amount.
     * @param {Coin} amount - The coin amount to validate.
     * @param {TransactionType} transactionType - optional field for transaction type
     * @throws {InvalidTransactionError} Throws an error if the coin amount is invalid.
     */
    validateAmount(amount, transactionType) {
        throw new sdk_core_1.NotImplementedError('validateAmount not implemented');
    }
    /**
     * Checks if a cosmos like Bech32 address matches given regular expression and
     * validates memoId if present
     * @param {string} address
     * @param {RegExp} regExp Regular expression to validate the root address against after trimming the memoId
     * @returns {boolean} true if address is valid
     */
    isValidCosmosLikeAddressWithMemoId(address, regExp) {
        if (typeof address !== 'string')
            return false;
        const addressArray = address.split('?memoId=');
        if (![1, 2].includes(addressArray.length) || // should have at most one occurrence of 'memoId='
            !this.isValidBech32AddressMatchingRegex(addressArray[0], regExp) ||
            (addressArray[1] && !this.isValidMemoId(addressArray[1]))) {
            return false;
        }
        return true;
    }
    /**
     * Checks if address is valid Bech32 and matches given regular expression
     * @param {string} address
     * @param {RegExp} regExp Regular expression to validate the address against
     * @returns {boolean} true if address is valid
     */
    isValidBech32AddressMatchingRegex(address, regExp) {
        try {
            (0, encoding_1.fromBech32)(address);
        }
        catch (e) {
            return false;
        }
        return regExp.test(address);
    }
    /**
     * Return boolean indicating whether a memo id is valid
     *
     * @param memoId memo id
     * @returns true if memo id is valid
     */
    isValidMemoId(memoId) {
        // Allow alphanumeric memo IDs (including uppercase and lowercase letters)
        const alphanumericRegex = /^[0-9a-zA-Z]+$/;
        // Check if the memoId is alphanumeric
        if (!alphanumericRegex.test(memoId)) {
            return false;
        }
        // If the memoId is purely numeric, ensure it is a positive integer
        if (/^\d+$/.test(memoId)) {
            const memoIdNumber = new bignumber_js_1.default(memoId);
            return memoIdNumber.gte(0) && memoIdNumber.isInteger();
        }
        return true;
    }
    /**
     * Validates if the address matches with regex @see accountAddressRegex
     * @param {string} address
     * @returns {boolean} - the validation result
     */
    isValidValidatorAddress(address) {
        throw new sdk_core_1.NotImplementedError('isValidValidatorAddress not implemented');
    }
    /**
     * Validates if the address matches with regex @see accountAddressRegex
     * @param {string} address
     * @returns {boolean} - the validation result
     */
    isValidAddress(address) {
        throw new sdk_core_1.NotImplementedError('isValidAddress not implemented');
    }
    /**
     * Validates if the address matches with regex @see contractAddressRegex
     * @param {string} address
     * @returns {boolean} - the validation result
     */
    isValidContractAddress(address) {
        throw new sdk_core_1.NotImplementedError('isValidContractAddress not implemented');
    }
    /**
     * Validates a execute contract message
     * @param {ExecuteContractMessage} message - The execute contract message to validate
     * @param {TransactionType} transactionType - optional field for transaction type
     * @throws {InvalidTransactionError} Throws an error if the message is invalid
     */
    validateExecuteContractMessage(message, transactionType) {
        if (!message.contract || !this.isValidContractAddress(message.contract)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid ExecuteContractMessage contract address: ` + message.contract);
        }
        if (!message.sender || !this.isValidAddress(message.sender)) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid ExecuteContractMessage sender address: ` + message.sender);
        }
        if (!message.msg) {
            throw new sdk_core_1.InvalidTransactionError(`Invalid ExecuteContractMessage msg: ` + message.msg);
        }
        if (message.funds) {
            this.validateAmountData(message.funds, transactionType);
        }
    }
    /**
     * Get coin specific hash function
     * @returns {Hash} The hash function
     */
    getHashFunction() {
        return (0, crypto_1.createHash)('sha256');
    }
    getTokenDenomsUsingCoinFamily(coinFamily) {
        // using set to remove duplicates as denom can be same on testnet and mainnet for a few tokens
        return [
            ...new Set(statics_1.coins
                .filter((coin) => coin.family.toLowerCase() === coinFamily.toLowerCase() && coin.isToken && coin.denom !== undefined)
                .map((coin) => coin.denom)),
        ];
    }
}
exports.CosmosUtils = CosmosUtils;
const utils = new CosmosUtils();
exports.default = utils;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDhDQU95QjtBQUN6Qix5Q0FBZ0Y7QUFDaEYsK0NBQW9GO0FBQ3BGLHlEQVMrQjtBQUMvQiwrQ0FBOEQ7QUFDOUQsNENBQXVDO0FBQ3ZDLGdFQUFxQztBQUNyQywwREFBbUU7QUFFbkUseURBQXNFO0FBQ3RFLG1DQUEwQztBQUMxQyx1REFBeUM7QUFXekMsdUNBQXFEO0FBRXJELE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxPQUFPLENBQUMsNkJBQTZCLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFFakUsTUFBYSxXQUFXO0lBR3RCO1FBQ0UsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLHdCQUFRLENBQUMsQ0FBQyxHQUFHLCtCQUFvQixDQUFDLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMseUJBQXlCLEVBQUUsdUJBQWtCLENBQUMsQ0FBQztRQUNoRixJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQsa0JBQWtCO0lBQ2xCLGNBQWMsQ0FBQyxJQUFZO1FBQ3pCLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQsa0JBQWtCO0lBQ2xCLGlCQUFpQixDQUFDLEdBQVc7UUFDM0IsSUFBSSxDQUFDO1lBQ0gsSUFBSSx1QkFBTyxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFDMUIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO0lBQ0gsQ0FBQztJ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SSxrQ0FBdUIsQ0FBQyxzQ0FBc0MsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUYsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2xCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQzFELENBQUM7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZUFBZTtRQUNiLE9BQU8sSUFBQSxtQkFBVSxFQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFRCw2QkFBNkIsQ0FBQyxVQUFrQjtRQUM5Qyw4RkFBOEY7UUFDOUYsT0FBTztZQUNMLEdBQUcsSUFBSSxHQUFHLENBQ1IsZUFBSztpQkFDRixNQUFNLENBQ0wsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLEtBQUssVUFBVSxDQUFDLFdBQVcsRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLEtBQUssS0FBSyxTQUFTLENBQzdHO2lCQUNBLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQWUsQ0FBQyxDQUN2QztTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUEzNEJELGtDQTI0QkM7QUFFRCxNQUFNLEtBQUssR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO0FBRWhDLGtCQUFlLEtBQUssQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEJhc2VVdGlscyxcbiAgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IsXG4gIE5vdEltcGxlbWVudGVkRXJyb3IsXG4gIE5vdFN1cHBvcnRlZCxcbiAgUGFyc2VUcmFuc2FjdGlvbkVycm9yLFxuICBUcmFuc2FjdGlvblR5cGUsXG59IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBlbmNvZGVTZWNwMjU2azFQdWJrZXksIGVuY29kZVNlY3AyNTZrMVNpZ25hdHVyZSB9IGZyb20gJ0Bjb3NtanMvYW1pbm8nO1xuaW1wb3J0IHsgZnJvbUJhc2U2NCwgZnJvbUJlY2gzMiwgZnJvbUhleCwgdG9CZWNoMzIsIHRvSGV4IH0gZnJvbSAnQGNvc21qcy9lbmNvZGluZyc7XG5pbXBvcnQge1xuICBEZWNvZGVkVHhSYXcsXG4gIGRlY29kZVB1YmtleSxcbiAgZGVjb2RlVHhSYXcsXG4gIEVuY29kZU9iamVjdCxcbiAgZW5jb2RlUHVia2V5LFxuICBtYWtlQXV0aEluZm9CeXRlcyxcbiAgbWFrZVNpZ25Eb2MsXG4gIFJlZ2lzdHJ5LFxufSBmcm9tICdAY29zbWpzL3Byb3RvLXNpZ25pbmcnO1xuaW1wb3J0IHsgQ29pbiwgZGVmYXVsdFJlZ2lzdHJ5VHlwZXMgfSBmcm9tICdAY29zbWpzL3N0YXJnYXRlJztcbmltcG9ydCB7IGNvaW5zIH0gZnJvbSAnQGJpdGdvL3N0YXRpY3MnO1xuaW1wb3J0IEJpZ051bWJlciBmcm9tICdiaWdudW1iZXIuanMnO1xuaW1wb3J0IHsgU2lnbkRvYywgVHhSYXcgfSBmcm9tICdjb3NtanMtdHlwZXMvY29zbW9zL3R4L3YxYmV0YTEvdHgnO1xuaW1wb3J0IHsgQW55IH0gZnJvbSAnY29zbWpzLXR5cGVzL2dvb2dsZS9wcm90b2J1Zi9hbnknO1xuaW1wb3J0IHsgTXNnRXhlY3V0ZUNvbnRyYWN0IH0gZnJvbSAnY29zbWpzLXR5cGVzL2Nvc213YXNtL3dhc20vdjEvdHgnO1xuaW1wb3J0IHsgY3JlYXRlSGFzaCwgSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgKiBhcyBjb25zdGFudHMgZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHtcbiAgQ29zbW9zTGlrZVRyYW5zYWN0aW9uLFxuICBEZWxlZ2F0ZU9yVW5kZWxlZ2V0ZU1lc3NhZ2UsXG4gIEV4ZWN1dGVDb250cmFjdE1lc3NhZ2UsXG4gIEZlZURhdGEsXG4gIE1lc3NhZ2VEYXRhLFxuICBSZWRlbGVnYXRlTWVzc2FnZSxcbiAgU2VuZE1lc3NhZ2UsXG4gIFdpdGhkcmF3RGVsZWdhdG9yUmV3YXJkc01lc3NhZ2UsXG59IGZyb20gJy4vaWZhY2UnO1xuaW1wb3J0IHsgQ29zbW9zS2V5UGFpciBhcyBLZXlQYWlyIH0gZnJvbSAnLi9rZXlQYWlyJztcblxuY29uc3QgeyBNc2dTZW5kIH0gPSByZXF1aXJlKCcuLi8uLi9yZXNvdXJjZXMvTXNnQ29tcGlsZWQnKS50eXBlcztcblxuZXhwb3J0IGNsYXNzIENvc21vc1V0aWxzPEN1c3RvbU1lc3NhZ2UgPSBuZXZlcj4gaW1wbGVtZW50cyBCYXNlVXRpbHMge1xuICBwcm90ZWN0ZWQgcmVnaXN0cnk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5yZWdpc3RyeSA9IG5ldyBSZWdpc3RyeShbLi4uZGVmYXVsdFJlZ2lzdHJ5VHlwZXNdKTtcbiAgICB0aGlzLnJlZ2lzdHJ5LnJlZ2lzdGVyKGNvbnN0YW50cy5leGVjdXRlQ29udHJhY3RNc2dUeXBlVXJsLCBNc2dFeGVjdXRlQ29udHJhY3QpO1xuICAgIHRoaXMucmVnaXN0cnkucmVnaXN0ZXIoJy90eXBlcy5Nc2dTZW5kJywgTXNnU2VuZCk7XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgaXNWYWxpZEJsb2NrSWQoaGFzaDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMudmFsaWRhdGVCbGFrZTJiKGhhc2gpO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIGlzVmFsaWRQcml2YXRlS2V5KGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIG5ldyBLZXlQYWlyKHsgcHJ2OiBrZXkgfSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgaXNWYWxpZFB1YmxpY0tleShrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICBuZXcgS2V5UGFpcih7IHB1Yjoga2V5IH0pO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIGlzVmFsaWRTaWduYXR1cmUoc2lnbmF0dXJlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcignaXNWYWxpZFNpZ25hdHVyZSBub3QgaW1wbGVtZW50ZWQnKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkVHJhbnNhY3Rpb25JZCh0eElkOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52YWxpZGF0ZUJsYWtlMmIodHhJZCk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRyYW5zYWN0aW9uIGhhc2ggaXMgaW4gdmFsaWQgYmxhY2syYiBmb3JtYXRcbiAgICovXG4gIHZhbGlkYXRlQmxha2UyYihoYXNoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBpZiAoaGFzaD8ubGVuZ3RoICE9PSA2NCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gaGFzaC5tYXRjaCgvXlthLXpBLVowLTldKyQvKSAhPT0gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgd2hldGhlciBhbW91bnRzIGFyZSBpbiByYW5nZVxuICAgKlxuICAgKiBAcGFyYW0ge251bWJlcltdfSBhbW91bnRzIC0gdGhlIGFtb3VudHMgdG8gdmFsaWRhdGVcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gdGhlIHZhbGlkYXRpb24gcmVzdWx0XG4gICAqL1xuICBpc1ZhbGlkQW1vdW50cyhhbW91bnRzOiBudW1iZXJbXSk6IGJvb2xlYW4ge1xuICAgIGZvciAoY29uc3QgYW1vdW50IG9mIGFtb3VudHMpIHtcbiAgICAgIGlmICghdGhpcy5pc1ZhbGlkQW1vdW50KGFtb3VudCkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgd2hldGhlciBhbW91bnQgaXMgaW4gcmFuZ2VcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFtb3VudFxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gdGhlIHZhbGlkYXRpb24gcmVzdWx0XG4gICAqL1xuICBpc1ZhbGlkQW1vdW50KGFtb3VudDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgY29uc3QgYmlnTnVtYmVyQW1vdW50ID0gbmV3IEJpZ051bWJlcihhbW91bnQpO1xuICAgIGlmICghYmlnTnVtYmVyQW1vdW50LmlzSW50ZWdlcigpIHx8IGJpZ051bWJlckFtb3VudC5pc0xlc3NUaGFuT3JFcXVhbFRvKDApKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZXMgcmF3IHR4IGRhdGEgaW50byBtZXNzYWdlcywgc2lnbmluZyBpbmZvLCBhbmQgZmVlIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IHR4SGV4IC0gcmF3IGJhc2U2NCB0eFxuICAgKiBAcmV0dXJucyB7RGVjb2RlZFR4UmF3fSBEZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqL1xuICBnZXREZWNvZGVkVHhGcm9tUmF3QmFzZTY0KHR4UmF3OiBzdHJpbmcpOiBEZWNvZGVkVHhSYXcge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gZGVjb2RlVHhSYXcoZnJvbUJhc2U2NCh0eFJhdykpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBQYXJzZVRyYW5zYWN0aW9uRXJyb3IoJ0Vycm9yIGRlY29kaW5nIFR4UmF3IGJhc2U2NCBlbmNvZGVkIHN0cmluZzogJyArIGUubWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGFycmF5IG9mIG1lc3NhZ2VzIGluIHRoZSBib2R5IG9mIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge0VuY29kZU9iamVjdFtdfSBtZXNzYWdlcyBhbG9uZyB3aXRoIHR5cGUgdXJsXG4gICAqL1xuICBwcml2YXRlIGdldEVuY29kZWRNZXNzYWdlc0Zyb21EZWNvZGVkVHgoZGVjb2RlZFR4OiBEZWNvZGVkVHhSYXcpOiBFbmNvZGVPYmplY3RbXSB7XG4gICAgcmV0dXJuIGRlY29kZWRUeC5ib2R5Lm1lc3NhZ2VzO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyB0aGUgdHhuIHNlcXVlbmNlIGlzIHZhbGlkIG9yIG5vdFxuICAgKiBAcGFyYW0ge251bWJlcn0gc2VxdWVuY2VcbiAgICovXG4gIHZhbGlkYXRlU2VxdWVuY2Uoc2VxdWVuY2U6IG51bWJlcikge1xuICAgIGlmIChzZXF1ZW5jZSA8IDApIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcignSW52YWxpZCBzZXF1ZW5jZTogbGVzcyB0aGFuIHplcm8nKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHVsbHMgdGhlIHNlcXVlbmNlIG51bWJlciBmcm9tIGEgRGVjb2RlZFR4UmF3IEF1dGhJbmZvIHByb3BlcnR5XG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge251bWJlcn0gc2VxdWVuY2VcbiAgICovXG4gIGdldFNlcXVlbmNlRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IG51bWJlciB7XG4gICAgcmV0dXJuIE51bWJlcihkZWNvZGVkVHguYXV0aEluZm8uc2lnbmVySW5mb3NbMF0uc2VxdWVuY2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIFB1bGxzIHRoZSB0eXBlVXJsIGZyb20gdGhlIGVuY29kZWQgbWVzc2FnZSBvZiBhIERlY29kZWRUeFJhd1xuICAgKiBAcGFyYW0ge0RlY29kZWRUeFJhd30gZGVjb2RlZFR4XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGNvc21vcyBwcm90byB0eXBlIHVybFxuICAgKi9cbiAgZ2V0VHlwZVVybEZyb21EZWNvZGVkVHgoZGVjb2RlZFR4OiBEZWNvZGVkVHhSYXcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGVuY29kZWRNZXNzYWdlID0gdGhpcy5nZXRFbmNvZGVkTWVzc2FnZXNGcm9tRGVjb2RlZFR4KGRlY29kZWRUeClbMF07XG4gICAgcmV0dXJuIGVuY29kZWRNZXNzYWdlLnR5cGVVcmw7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgZmVlIGRhdGEgZnJvbSB0aGUgZGVjb2RlZCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0RlY29kZWRUeFJhd30gZGVjb2RlZFR4XG4gICAqIEByZXR1cm5zIHtGZWVEYXRhfSBmZWUgZGF0YVxuICAgKi9cbiAgZ2V0R2FzQnVkZ2V0RnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IEZlZURhdGEge1xuICAgIHJldHVybiB7XG4gICAgICBhbW91bnQ6IGRlY29kZWRUeC5hdXRoSW5mby5mZWU/LmFtb3VudCBhcyBDb2luW10sXG4gICAgICBnYXNMaW1pdDogTnVtYmVyKGRlY29kZWRUeC5hdXRoSW5mby5mZWU/Lmdhc0xpbWl0KSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHB1YmxpY0tleSBmcm9tIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge3N0cmluZyB8IHVuZGVmaW5lZH0gcHVibGljS2V5IGluIGhleCBmb3JtYXQgaWYgaXQgZXhpc3RzLCB1bmRlZmluZWQgb3RoZXJ3aXNlXG4gICAqL1xuICBnZXRQdWJsaWNLZXlGcm9tRGVjb2RlZFR4KGRlY29kZWRUeDogRGVjb2RlZFR4UmF3KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBwdWJsaWNLZXlVSW50OEFycmF5ID0gZGVjb2RlZFR4LmF1dGhJbmZvLnNpZ25lckluZm9zPy5bMF0ucHVibGljS2V5Py52YWx1ZTtcbiAgICBpZiAocHVibGljS2V5VUludDhBcnJheSkge1xuICAgICAgcmV0dXJuIHRvSGV4KGZyb21CYXNlNjQoZGVjb2RlUHVia2V5KGRlY29kZWRUeC5hdXRoSW5mby5zaWduZXJJbmZvcz8uWzBdLnB1YmxpY0tleSk/LnZhbHVlKSk7XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXJyYXkgb2YgTWVzc2FnZURhdGFbXSBmcm9tIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge01lc3NhZ2VEYXRhW119IFNlbmQgdHJhbnNhY3Rpb24gbWVzc2FnZSBkYXRhXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0U2VuZE1lc3NhZ2VEYXRhRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IE1lc3NhZ2VEYXRhPEN1c3RvbU1lc3NhZ2U+W10ge1xuICAgIHJldHVybiBkZWNvZGVkVHguYm9keS5tZXNzYWdlcy5tYXAoKG1lc3NhZ2UpID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5yZWdpc3RyeS5kZWNvZGUobWVzc2FnZSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgIGZyb21BZGRyZXNzOiB2YWx1ZS5mcm9tQWRkcmVzcyxcbiAgICAgICAgICB0b0FkZHJlc3M6IHZhbHVlLnRvQWRkcmVzcyxcbiAgICAgICAgICBhbW91bnQ6IHZhbHVlLmFtb3VudCxcbiAgICAgICAgfSxcbiAgICAgICAgdHlwZVVybDogbWVzc2FnZS50eXBlVXJsLFxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBNZXNzYWdlRGF0YVtdIGZyb20gdGhlIGRlY29kZWQgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtEZWNvZGVkVHhSYXd9IGRlY29kZWRUeFxuICAgKiBAcmV0dXJucyB7TWVzc2FnZURhdGFbXX0gRGVsZWdhdGUgb2YgdW5kZWxlZ2F0ZSB0cmFuc2FjdGlvbiBtZXNzYWdlIGRhdGFcbiAgICovXG4gIGdldERlbGVnYXRlT3JVbmRlbGVnYXRlTWVzc2FnZURhdGFGcm9tRGVjb2RlZFR4KGRlY29kZWRUeDogRGVjb2RlZFR4UmF3KTogTWVzc2FnZURhdGE8Q3VzdG9tTWVzc2FnZT5bXSB7XG4gICAgcmV0dXJuIGRlY29kZWRUeC5ib2R5Lm1lc3NhZ2VzLm1hcCgobWVzc2FnZSkgPT4ge1xuICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLnJlZ2lzdHJ5LmRlY29kZShtZXNzYWdlKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbHVlOiB7XG4gICAgICAgICAgZGVsZWdhdG9yQWRkcmVzczogdmFsdWUuZGVsZWdhdG9yQWRkcmVzcyxcbiAgICAgICAgICB2YWxpZGF0b3JBZGRyZXNzOiB2YWx1ZS52YWxpZGF0b3JBZGRyZXNzLFxuICAgICAgICAgIGFtb3VudDogdmFsdWUuYW1vdW50LFxuICAgICAgICB9LFxuICAgICAgICB0eXBlVXJsOiBtZXNzYWdlLnR5cGVVcmwsXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGFycmF5IG9mIE1lc3NhZ2VEYXRhW10gZnJvbSB0aGUgZGVjb2RlZCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0RlY29kZWRUeFJhd30gZGVjb2RlZFR4XG4gICAqIEByZXR1cm5zIHtNZXNzYWdlRGF0YVtdfSBSZWRlbGVnYXRlIHRyYW5zYWN0aW9uIG1lc3NhZ2UgZGF0YVxuICAgKi9cbiAgZ2V0UmVkZWxlZ2F0ZU1lc3NhZ2VEYXRhRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IE1lc3NhZ2VEYXRhPEN1c3RvbU1lc3NhZ2U+W10ge1xuICAgIHJldHVybiBkZWNvZGVkVHguYm9keS5tZXNzYWdlcy5tYXAoKG1lc3NhZ2UpID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5yZWdpc3RyeS5kZWNvZGUobWVzc2FnZSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgIGRlbGVnYXRvckFkZHJlc3M6IHZhbHVlLmRlbGVnYXRvckFkZHJlc3MsXG4gICAgICAgICAgdmFsaWRhdG9yU3JjQWRkcmVzczogdmFsdWUudmFsaWRhdG9yU3JjQWRkcmVzcyxcbiAgICAgICAgICB2YWxpZGF0b3JEc3RBZGRyZXNzOiB2YWx1ZS52YWxpZGF0b3JEc3RBZGRyZXNzLFxuICAgICAgICAgIGFtb3VudDogdmFsdWUuYW1vdW50LFxuICAgICAgICB9LFxuICAgICAgICB0eXBlVXJsOiBtZXNzYWdlLnR5cGVVcmwsXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGFycmF5IG9mIE1lc3NhZ2VEYXRhW10gZnJvbSB0aGUgZGVjb2RlZCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0RlY29kZWRUeFJhd30gZGVjb2RlZFR4XG4gICAqIEByZXR1cm5zIHtNZXNzYWdlRGF0YVtdfSBXaXRoZHJhd0RlbGVnYXRvclJld2FyZHMgdHJhbnNhY3Rpb24gbWVzc2FnZSBkYXRhXG4gICAqL1xuICBnZXRXaXRoZHJhd1Jld2FyZHNNZXNzYWdlRGF0YUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4OiBEZWNvZGVkVHhSYXcpOiBNZXNzYWdlRGF0YTxDdXN0b21NZXNzYWdlPltdIHtcbiAgICByZXR1cm4gZGVjb2RlZFR4LmJvZHkubWVzc2FnZXMubWFwKChtZXNzYWdlKSA9PiB7XG4gICAgICBjb25zdCB2YWx1ZSA9IHRoaXMucmVnaXN0cnkuZGVjb2RlKG1lc3NhZ2UpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsdWU6IHtcbiAgICAgICAgICBkZWxlZ2F0b3JBZGRyZXNzOiB2YWx1ZS5kZWxlZ2F0b3JBZGRyZXNzLFxuICAgICAgICAgIHZhbGlkYXRvckFkZHJlc3M6IHZhbHVlLnZhbGlkYXRvckFkZHJlc3MsXG4gICAgICAgIH0sXG4gICAgICAgIHR5cGVVcmw6IG1lc3NhZ2UudHlwZVVybCxcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXJyYXkgb2YgTWVzc2FnZURhdGFbXSBmcm9tIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge01lc3NhZ2VEYXRhW119IERlbGVnYXRlIG9mIHVuZGVsZWdhdGUgdHJhbnNhY3Rpb24gbWVzc2FnZSBkYXRhXG4gICAqL1xuICBnZXRXaXRoZHJhd0RlbGVnYXRvclJld2FyZHNNZXNzYWdlRGF0YUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4OiBEZWNvZGVkVHhSYXcpOiBNZXNzYWdlRGF0YTxDdXN0b21NZXNzYWdlPltdIHtcbiAgICByZXR1cm4gZGVjb2RlZFR4LmJvZHkubWVzc2FnZXMubWFwKChtZXNzYWdlKSA9PiB7XG4gICAgICBjb25zdCB2YWx1ZSA9IHRoaXMucmVnaXN0cnkuZGVjb2RlKG1lc3NhZ2UpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsdWU6IHtcbiAgICAgICAgICBkZWxlZ2F0b3JBZGRyZXNzOiB2YWx1ZS5kZWxlZ2F0b3JBZGRyZXNzLFxuICAgICAgICAgIHZhbGlkYXRvckFkZHJlc3M6IHZhbHVlLnZhbGlkYXRvckFkZHJlc3MsXG4gICAgICAgIH0sXG4gICAgICAgIHR5cGVVcmw6IG1lc3NhZ2UudHlwZVVybCxcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgY29zbW9zIGNoYWluIGFkZHJlc3MgZnJvbSBpdHMgZXF1aXZhbGVudCBoZXhcbiAgICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzc0hleFxuICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgKi9cbiAgZ2V0Q29zbW9zTGlrZUFkZHJlc3NGcm9tSGV4KHByZWZpeDogc3RyaW5nLCBhZGRyZXNzSGV4OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmIChhZGRyZXNzSGV4LmluZGV4T2YoJzB4JykgPT09IDApIHtcbiAgICAgIGFkZHJlc3NIZXggPSBhZGRyZXNzSGV4LnNsaWNlKDIpO1xuICAgIH1cbiAgICByZXR1cm4gdG9CZWNoMzIocHJlZml4LCBmcm9tSGV4KGFkZHJlc3NIZXgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSBFVk0gY2hhaW4gYWRkcmVzcyBmcm9tIGl0cyBlcXVpdmFsZW50IGhleFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzSGV4XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9XG4gICAqL1xuICBnZXRFdm1MaWtlQWRkcmVzc0Zyb21Db3Ntb3MoY29zbW9zTGlrZUFkZHJlc3M6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuICcweCcgKyB0b0hleChmcm9tQmVjaDMyKGNvc21vc0xpa2VBZGRyZXNzKS5kYXRhKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBNZXNzYWdlRGF0YVtdIGZyb20gdGhlIGRlY29kZWQgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtEZWNvZGVkVHhSYXd9IGRlY29kZWRUeFxuICAgKiBAcmV0dXJucyB7TWVzc2FnZURhdGFbXX0gRXhlY3V0ZSBjb250cmFjdCB0cmFuc2FjdGlvbiBtZXNzYWdlIGRhdGFcbiAgICovXG4gIGdldEV4ZWN1dGVDb250cmFjdE1lc3NhZ2VEYXRhRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IE1lc3NhZ2VEYXRhPEN1c3RvbU1lc3NhZ2U+W10ge1xuICAgIHJldHVybiBkZWNvZGVkVHguYm9keS5tZXNzYWdlcy5tYXAoKG1lc3NhZ2UpID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5yZWdpc3RyeS5kZWNvZGUobWVzc2FnZSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgIHNlbmRlcjogdmFsdWUuc2VuZGVyLFxuICAgICAgICAgIGNvbnRyYWN0OiB2YWx1ZS5jb250cmFjdCxcbiAgICAgICAgICBtc2c6IHZhbHVlLm1zZyxcbiAgICAgICAgICBmdW5kczogdmFsdWUuZnVuZHMsXG4gICAgICAgIH0sXG4gICAgICAgIHR5cGVVcmw6IG1lc3NhZ2UudHlwZVVybCxcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXJyYXkgb2YgTWVzc2FnZURhdGFbXSBmcm9tIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge01lc3NhZ2VEYXRhW119IEN1c3RvbSB0cmFuc2FjdGlvbiBtZXNzYWdlIGRhdGFcbiAgICovXG4gIGdldEN1c3RvbU1lc3NhZ2VEYXRhRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IE1lc3NhZ2VEYXRhPEN1c3RvbU1lc3NhZ2U+W10ge1xuICAgIHRocm93IG5ldyBOb3RTdXBwb3J0ZWQoJ0N1c3RvbSBtZXNzYWdlIGRhdGEgbm90IHN1cHBvcnRlZCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgYml0Z28gdHJhbnNhY3Rpb24gdHlwZSBiYXNlZCBvbiBjb3Ntb3MgcHJvdG8gdHlwZSB1cmxcbiAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGVVcmxcbiAgICogQHJldHVybnMge1RyYW5zYWN0aW9uVHlwZSB8IHVuZGVmaW5lZH0gVHJhbnNhY3Rpb25UeXBlIGlmIHVybCBpcyBzdXBwb3J0ZWQgZWxzZSB1bmRlZmluZWRcbiAgICovXG4gIGdldFRyYW5zYWN0aW9uVHlwZUZyb21UeXBlVXJsKHR5cGVVcmw6IHN0cmluZyk6IFRyYW5zYWN0aW9uVHlwZSB8IHVuZGVmaW5lZCB7XG4gICAgc3dpdGNoICh0eXBlVXJsKSB7XG4gICAgICBjYXNlIGNvbnN0YW50cy5zZW5kTXNnVHlwZVVybDpcbiAgICAgICAgcmV0dXJuIFRyYW5zYWN0aW9uVHlwZS5TZW5kO1xuICAgICAgY2FzZSBjb25zdGFudHMuc2VuZE1zZ1R5cGU6XG4gICAgICAgIHJldHVybiBUcmFuc2FjdGlvblR5cGUuU2VuZDtcbiAgICAgIGNhc2UgY29uc3RhbnRzLmRlbGVnYXRlTXNnVHlwZVVybDpcbiAgICAgICAgcmV0dXJuIFRyYW5zYWN0aW9uVHlwZS5TdGFraW5nQWN0aXZhdGU7XG4gICAgICBjYXNlIGNvbnN0YW50cy51bmRlbGVnYXRlTXNnVHlwZVVybDpcbiAgICAgICAgcmV0dXJuIFRyYW5zYWN0aW9uVHlwZS5TdGFraW5nRGVhY3RpdmF0ZTtcbiAgICAgIGNhc2UgY29uc3RhbnRzLndpdGhkcmF3RGVsZWdhdG9yUmV3YXJkTXNnVHlwZVVybDpcbiAgICAgICAgcmV0dXJuIFRyYW5zYWN0aW9uVHlwZS5TdGFraW5nV2l0aGRyYXc7XG4gICAgICBjYXNlIGNvbnN0YW50cy5leGVjdXRlQ29udHJhY3RNc2dUeXBlVXJsOlxuICAgICAgICByZXR1cm4gVHJhbnNhY3Rpb25UeXBlLkNvbnRyYWN0Q2FsbDtcbiAgICAgIGNhc2UgY29uc3RhbnRzLnJlZGVsZWdhdGVUeXBlVXJsOlxuICAgICAgICByZXR1cm4gVHJhbnNhY3Rpb25UeXBlLlN0YWtpbmdSZWRlbGVnYXRlO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGFrZXMgYSBoZXggZW5jb2RlZCBwdWJrZXksIGNvbnZlcnRzIGl0IHRvIHRoZSBBbWlubyBKU09OIHJlcHJlc2VudGF0aW9uICh0eXBlL3ZhbHVlIHdyYXBwZXIpXG4gICAqIGFuZCByZXR1cm5zIGl0IGFzIHByb3RvYnVmIGBBbnlgXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwdWJrZXkgaGV4IGVuY29kZWQgY29tcHJlc3NlZCBzZWNwMjU2azEgcHVibGljIGtleVxuICAgKiBAcmV0dXJucyB7QW55fSBwdWJrZXkgZW5jb2RlZCBhcyBwcm90b2J1ZiBgQW55YFxuICAgKi9cbiAgZ2V0RW5jb2RlZFB1YmtleShwdWJrZXk6IHN0cmluZyk6IEFueSB7XG4gICAgcmV0dXJuIGVuY29kZVB1YmtleShlbmNvZGVTZWNwMjU2azFQdWJrZXkoZnJvbUhleChwdWJrZXkpKSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgc2VuZCBtZXNzYWdlcyB1c2VkIGluIHRoZSBmaW5hbCBzdGVwIG9mIGVuY29kaW5nIGEgdHJhbnNhY3Rpb24uIFRoaXMgYWxsb3dzIGZvciBhbnkgZmluYWwgcHJvY2Vzc2luZyBuZWVkZWQuXG4gICAqIEBwYXJhbSB7Q29zbW9zTGlrZVRyYW5zYWN0aW9ufSBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24gdHJhbnNhY3Rpb24gdG8gZ2V0IHNlbmQgbWVzc2FnZXMgZnJvbVxuICAgKiBAcmV0dXJucyB7QW55W119IHByb2Nlc3NlZCBzZW5kIG1lc3NhZ2VzXG4gICAqL1xuICBnZXRTZW5kTWVzc2FnZXNGb3JFbmNvZGluZ1R4KGNvc21vc0xpa2VUcmFuc2FjdGlvbjogQ29zbW9zTGlrZVRyYW5zYWN0aW9uPEN1c3RvbU1lc3NhZ2U+KTogQW55W10ge1xuICAgIHJldHVybiBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24uc2VuZE1lc3NhZ2VzIGFzIHVua25vd24gYXMgQW55W107XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHR4UmF3IGZyb20gYW4gY29zbW9zIGxpa2UgdHJhbnNhY3Rpb24gQHNlZSBDb3Ntb3NMaWtlVHJhbnNhY3Rpb25cbiAgICogQFByZWNvbmRpdGlvbiBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24ucHVibGljS2V5IG11c3QgYmUgZGVmaW5lZFxuICAgKiBAcGFyYW0ge0Nvc21vc0xpa2VUcmFuc2FjdGlvbn0gY29zbW9zTGlrZVRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm5zIHtUeFJhd30gVW5zaWduZWQgcmF3IHRyYW5zYWN0aW9uXG4gICAqL1xuICBjcmVhdGVUeFJhd0Zyb21Db3Ntb3NMaWtlVHJhbnNhY3Rpb24oY29zbW9zTGlrZVRyYW5zYWN0aW9uOiBDb3Ntb3NMaWtlVHJhbnNhY3Rpb248Q3VzdG9tTWVzc2FnZT4pOiBUeFJhdyB7XG4gICAgaWYgKCFjb3Ntb3NMaWtlVHJhbnNhY3Rpb24ucHVibGljS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3B1YmxpY0tleSBpcyByZXF1aXJlZCB0byBjcmVhdGUgYSB0eFJhdycpO1xuICAgIH1cbiAgICBjb25zdCBlbmNvZGVkUHVibGljS2V5OiBBbnkgPSB0aGlzLmdldEVuY29kZWRQdWJrZXkoY29zbW9zTGlrZVRyYW5zYWN0aW9uLnB1YmxpY0tleSk7XG4gICAgY29uc3QgbWVzc2FnZXMgPSB0aGlzLmdldFNlbmRNZXNzYWdlc0ZvckVuY29kaW5nVHgoY29zbW9zTGlrZVRyYW5zYWN0aW9uKTtcbiAgICBsZXQgdHhCb2R5VmFsdWU7XG4gICAgaWYgKGNvc21vc0xpa2VUcmFuc2FjdGlvbi5tZW1vKSB7XG4gICAgICB0eEJvZHlWYWx1ZSA9IHtcbiAgICAgICAgbWVtbzogY29zbW9zTGlrZVRyYW5zYWN0aW9uLm1lbW8sXG4gICAgICAgIG1lc3NhZ2VzOiBtZXNzYWdlcyxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHR4Qm9keVZhbHVlID0ge1xuICAgICAgICBtZXNzYWdlczogbWVzc2FnZXMsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHR4Qm9keUJ5dGVzID0gdGhpcy5yZWdpc3RyeS5lbmNvZGVUeEJvZHkodHhCb2R5VmFsdWUpO1xuICAgIGNvbnN0IHNlcXVlbmNlID0gY29zbW9zTGlrZVRyYW5zYWN0aW9uLnNlcXVlbmNlO1xuICAgIGNvbnN0IGF1dGhJbmZvQnl0ZXMgPSBtYWtlQXV0aEluZm9CeXRlcyhcbiAgICAgIFt7IHB1YmtleTogZW5jb2RlZFB1YmxpY0tleSwgc2VxdWVuY2UgfV0sXG4gICAgICBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24uZ2FzQnVkZ2V0LmFtb3VudCxcbiAgICAgIGNvc21vc0xpa2VUcmFuc2FjdGlvbi5nYXNCdWRnZXQuZ2FzTGltaXQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWRcbiAgICApO1xuICAgIHJldHVybiBUeFJhdy5mcm9tUGFydGlhbCh7XG4gICAgICBib2R5Qnl0ZXM6IHR4Qm9keUJ5dGVzLFxuICAgICAgYXV0aEluZm9CeXRlczogYXV0aEluZm9CeXRlcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmNvZGVzIGEgc2lnbmF0dXJlIGludG8gYSB0eFJhd1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcHVibGljS2V5SGV4IHB1YmxpY0tleSBpbiBoZXggZW5jb2RlZCBzdHJpbmcgZm9ybWF0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzaWduYXR1cmVIZXggc2lnbmF0dXJlIGluIGhleCBlbmNvZGVkIHN0cmluZyBmb3JtYXRcbiAgICogQHBhcmFtIHtUeFJhd30gdW5zaWduZWRUeCByYXcgdHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge1R4UmF3fSBTaWduZWQgcmF3IHRyYW5zYWN0aW9uXG4gICAqL1xuICBjcmVhdGVTaWduZWRUeFJhdyhcbiAgICBwdWJsaWNLZXlIZXg6IHN0cmluZyxcbiAgICBzaWduYXR1cmVIZXg6IHN0cmluZyxcbiAgICB1bnNpZ25lZFR4OiB7IGJvZHlCeXRlczogVWludDhBcnJheTsgYXV0aEluZm9CeXRlczogVWludDhBcnJheSB9XG4gICk6IFR4UmF3IHtcbiAgICBjb25zdCBzdGRTaWduYXR1cmUgPSBlbmNvZGVTZWNwMjU2azFTaWduYXR1cmUoZnJvbUhleChwdWJsaWNLZXlIZXgpLCBmcm9tSGV4KHNpZ25hdHVyZUhleCkpO1xuICAgIHJldHVybiBUeFJhdy5mcm9tUGFydGlhbCh7XG4gICAgICBib2R5Qnl0ZXM6IHVuc2lnbmVkVHguYm9keUJ5dGVzLFxuICAgICAgYXV0aEluZm9CeXRlczogdW5zaWduZWRUeC5hdXRoSW5mb0J5dGVzLFxuICAgICAgc2lnbmF0dXJlczogW2Zyb21CYXNlNjQoc3RkU2lnbmF0dXJlLnNpZ25hdHVyZSldLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZXMgYSByYXcgdHJhbnNhY3Rpb24gaW50byBhIERlY29kZWRUeFJhdyBhbmQgY2hlY2tzIGlmIGl0IGhhcyBub24gZW1wdHkgc2lnbmF0dXJlc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcmF3VHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge2Jvb2xlYW59IHRydWUgaWYgdHJhbnNhY3Rpb24gaXMgc2lnbmVkIGVsc2UgZmFsc2VcbiAgICovXG4gIGlzU2lnbmVkUmF3VHgocmF3VHJhbnNhY3Rpb246IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGRlY29kZWRUeCA9IHRoaXMuZ2V0RGVjb2RlZFR4RnJvbVJhd0Jhc2U2NChyYXdUcmFuc2FjdGlvbik7XG4gICAgaWYgKGRlY29kZWRUeC5zaWduYXR1cmVzLmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB3aGV0aGVyIG9yIG5vdCB0aGUgc3RyaW5nIGlzIGEgdmFsaWQgcHJvdG9jb2wgcHVibGljIGtleVxuICAgKiBAcGFyYW0ge3N0cmluZyB8IHVuZGVmaW5lZH0gcHVibGljS2V5IC0gdGhlICBwdWJsaWMga2V5IHRvIGJlIHZhbGlkYXRlZFxuICAgKi9cbiAgdmFsaWRhdGVQdWJsaWNLZXkocHVibGljS2V5OiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgICBpZiAocHVibGljS2V5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIG5ldyBLZXlQYWlyKHsgcHViOiBwdWJsaWNLZXkgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRUcmFuc2FjdGlvbkVycm9yKGBJbnZhbGlkIFB1YmxpYyBLZXlgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHNpZ24gZG9jIGZyb20gYW4gY29zbW9zIGxpa2UgdHJhbnNhY3Rpb24gQHNlZSBDb3Ntb3NMaWtlVHJhbnNhY3Rpb25cbiAgICogQFByZWNvbmRpdGlvbiBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24uYWNjb3VudE51bWJlciBhbmQgY29zbW9zTGlrZVRyYW5zYWN0aW9uLmNoYWluSWQgbXVzdCBiZSBkZWZpbmVkXG4gICAqIEBwYXJhbSB7Q29zbW9zTGlrZVRyYW5zYWN0aW9ufSBjb3Ntb3NMaWtlVHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge1NpZ25Eb2N9IHNpZ24gZG9jXG4gICAqL1xuICBjcmVhdGVTaWduRG9jKFxuICAgIGNvc21vc0xpa2VUcmFuc2FjdGlvbjogQ29zbW9zTGlrZVRyYW5zYWN0aW9uPEN1c3RvbU1lc3NhZ2U+LFxuICAgIGFjY291bnROdW1iZXI6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgICBjaGFpbklkOiBzdHJpbmcgfCB1bmRlZmluZWRcbiAgKTogU2lnbkRvYyB7XG4gICAgaWYgKCFhY2NvdW50TnVtYmVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2FjY291bnROdW1iZXIgaXMgcmVxdWlyZWQgdG8gY3JlYXRlIGEgc2lnbiBkb2MnKTtcbiAgICB9XG4gICAgaWYgKCFjaGFpbklkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NoYWluSWQgaXMgcmVxdWlyZWQgdG8gY3JlYXRlIGEgc2lnbiBkb2MnKTtcbiAgICB9XG4gICAgaWYgKCFjb3Ntb3NMaWtlVHJhbnNhY3Rpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY29zbW9zTGlrZVRyYW5zYWN0aW9uIGlzIHJlcXVpcmVkIHRvIGNyZWF0ZSBhIHNpZ24gZG9jJyk7XG4gICAgfVxuICAgIGNvbnN0IHR4UmF3ID0gdGhpcy5jcmVhdGVUeFJhd0Zyb21Db3Ntb3NMaWtlVHJhbnNhY3Rpb24oY29zbW9zTGlrZVRyYW5zYWN0aW9uKTtcbiAgICByZXR1cm4gbWFrZVNpZ25Eb2ModHhSYXcuYm9keUJ5dGVzLCB0eFJhdy5hdXRoSW5mb0J5dGVzLCBjaGFpbklkLCBhY2NvdW50TnVtYmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHdoZXRoZXIgb3Igbm90IHRoZSBzdHJpbmcgaXMgYSB2YWxpZCBoZXhcbiAgICogQHBhcmFtIGhleFN0cmluZyAtIGhleCBzdHJpbmcgZm9ybWF0XG4gICAqIEByZXR1cm5zIHtib29sZWFufSB0cnVlIGlmIHN0cmluZyBpcyBoZXggZWxzZSBmYWxzZVxuICAgKi9cbiAgaXNWYWxpZEhleFN0cmluZyhoZXhTdHJpbmc6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAvXlswLTlBLUZhLWZdKiQvLnRlc3QoaGV4U3RyaW5nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgdGhlIFdpdGhkcmF3RGVsZWdhdG9yUmV3YXJkc01lc3NhZ2VcbiAgICogQHBhcmFtIHtXaXRoZHJhd0RlbGVnYXRvclJld2FyZHNNZXNzYWdlfSB3aXRoZHJhd1Jld2FyZHNNZXNzYWdlIC0gVGhlIFdpdGhkcmF3RGVsZWdhdG9yUmV3YXJkc01lc3NhZ2UgdG8gdmFsaWRhdGUuXG4gICAqIEB0aHJvd3Mge0ludmFsaWRUcmFuc2FjdGlvbkVycm9yfSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHZhbGlkYXRvckFkZHJlc3Mgb3IgZGVsZWdhdG9yQWRkcmVzcyBpcyBpbnZhbGlkIG9yIG1pc3NpbmcuXG4gICAqL1xuICB2YWxpZGF0ZVdpdGhkcmF3UmV3YXJkc01lc3NhZ2Uod2l0aGRyYXdSZXdhcmRzTWVzc2FnZTogV2l0aGRyYXdEZWxlZ2F0b3JSZXdhcmRzTWVzc2FnZSkge1xuICAgIGlmIChcbiAgICAgICF3aXRoZHJhd1Jld2FyZHNNZXNzYWdlLnZhbGlkYXRvckFkZHJlc3MgfHxcbiAgICAgICF0aGlzLmlzVmFsaWRWYWxpZGF0b3JBZGRyZXNzKHdpdGhkcmF3UmV3YXJkc01lc3NhZ2UudmFsaWRhdG9yQWRkcmVzcylcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcihcbiAgICAgICAgYEludmFsaWQgV2l0aGRyYXdEZWxlZ2F0b3JSZXdhcmRzTWVzc2FnZSB2YWxpZGF0b3JBZGRyZXNzOiBgICsgd2l0aGRyYXdSZXdhcmRzTWVzc2FnZS52YWxpZGF0b3JBZGRyZXNzXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoIXdpdGhkcmF3UmV3YXJkc01lc3NhZ2UuZGVsZWdhdG9yQWRkcmVzcyB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyh3aXRoZHJhd1Jld2FyZHNNZXNzYWdlLmRlbGVnYXRvckFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoXG4gICAgICAgIGBJbnZhbGlkIFdpdGhkcmF3RGVsZWdhdG9yUmV3YXJkc01lc3NhZ2UgZGVsZWdhdG9yQWRkcmVzczogYCArIHdpdGhkcmF3UmV3YXJkc01lc3NhZ2UuZGVsZWdhdG9yQWRkcmVzc1xuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIG1ldGhvZCB0byBjaGVjayBpZiB0aGUgc3BlY2lmaWVkIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGFyZSBtaXNzaW5nIG9yIG51bGwuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IHRvIGNoZWNrLlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBrZXlzIC0gQW4gYXJyYXkgb2YgcHJvcGVydHkga2V5cyB0byBjaGVjay5cbiAgICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiBhbnkgb2YgdGhlIHNwZWNpZmllZCBwcm9wZXJ0aWVzIGFyZSBtaXNzaW5nIG9yIG51bGwuXG4gICAqL1xuICBpc09ialByb3BlcnR5TnVsbChvYmo6IHsgW2tleTogc3RyaW5nXTogYW55IH0sIGtleXM6IEFycmF5PHN0cmluZz4pIHtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBrZXlzKSB7XG4gICAgICBpZiAob2JqW2tleV0gPT0gbnVsbCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE1pc3Npbmcgb3IgbnVsbCB2YWx1ZSBmb3IgcHJvcGVydHkgJHtrZXl9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB0aGUgRGVsZWdhdGVPclVuZGVsZWdldGVNZXNzYWdlXG4gICAqIEBwYXJhbSB7RGVsZWdhdGVPclVuZGVsZWdldGVNZXNzYWdlfSBkZWxlZ2F0ZU1lc3NhZ2UgLSBUaGUgRGVsZWdhdGVPclVuZGVsZWdldGVNZXNzYWdlIHRvIHZhbGlkYXRlLlxuICAgKiBAdGhyb3dzIHtJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcn0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSB2YWxpZGF0b3JBZGRyZXNzLCBkZWxlZ2F0b3JBZGRyZXNzLCBvciBhbW91bnQgaXMgaW52YWxpZCBvciBtaXNzaW5nLlxuICAgKi9cbiAgdmFsaWRhdGVEZWxlZ2F0ZU9yVW5kZWxlZ2F0ZU1lc3NhZ2UoZGVsZWdhdGVNZXNzYWdlOiBEZWxlZ2F0ZU9yVW5kZWxlZ2V0ZU1lc3NhZ2UpIHtcbiAgICB0aGlzLmlzT2JqUHJvcGVydHlOdWxsKGRlbGVnYXRlTWVzc2FnZSwgWyd2YWxpZGF0b3JBZGRyZXNzJywgJ2RlbGVnYXRvckFkZHJlc3MnXSk7XG5cbiAgICBpZiAoIXRoaXMuaXNWYWxpZFZhbGlkYXRvckFkZHJlc3MoZGVsZWdhdGVNZXNzYWdlLnZhbGlkYXRvckFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoXG4gICAgICAgIGBJbnZhbGlkIERlbGVnYXRlT3JVbmRlbGVnZXRlTWVzc2FnZSB2YWxpZGF0b3JBZGRyZXNzOiBgICsgZGVsZWdhdGVNZXNzYWdlLnZhbGlkYXRvckFkZHJlc3NcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICghdGhpcy5pc1ZhbGlkQWRkcmVzcyhkZWxlZ2F0ZU1lc3NhZ2UuZGVsZWdhdG9yQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcihcbiAgICAgICAgYEludmFsaWQgRGVsZWdhdGVPclVuZGVsZWdldGVNZXNzYWdlIGRlbGVnYXRvckFkZHJlc3M6IGAgKyBkZWxlZ2F0ZU1lc3NhZ2UuZGVsZWdhdG9yQWRkcmVzc1xuICAgICAgKTtcbiAgICB9XG4gICAgdGhpcy52YWxpZGF0ZUFtb3VudChkZWxlZ2F0ZU1lc3NhZ2UuYW1vdW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgdGhlIFJlZGVsZWdhdGVNZXNzYWdlXG4gICAqIEBwYXJhbSB7RGVsZWdhdGVPclVuZGVsZWdldGVNZXNzYWdlfSByZWRlbGVnYXRlTWVzc2FnZSAtIFRoZSBSZWRlbGVnYXRlTWVzc2FnZSB0byB2YWxpZGF0ZS5cbiAgICogQHRocm93cyB7SW52YWxpZFRyYW5zYWN0aW9uRXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgdmFsaWRhdG9yU3JjQWRkcmVzcywgdmFsaWRhdG9yRHN0QWRkcmVzcywgZGVsZWdhdG9yQWRkcmVzcywgb3IgYW1vdW50IGlzIGludmFsaWQgb3IgbWlzc2luZy5cbiAgICovXG4gIHZhbGlkYXRlUmVkZWxlZ2F0ZU1lc3NhZ2UocmVkZWxlZ2F0ZU1lc3NhZ2U6IFJlZGVsZWdhdGVNZXNzYWdlKSB7XG4gICAgdGhpcy5pc09ialByb3BlcnR5TnVsbChyZWRlbGVnYXRlTWVzc2FnZSwgWyd2YWxpZGF0b3JTcmNBZGRyZXNzJywgJ3ZhbGlkYXRvckRzdEFkZHJlc3MnLCAnZGVsZWdhdG9yQWRkcmVzcyddKTtcblxuICAgIGlmICghdGhpcy5pc1ZhbGlkVmFsaWRhdG9yQWRkcmVzcyhyZWRlbGVnYXRlTWVzc2FnZS52YWxpZGF0b3JTcmNBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRUcmFuc2FjdGlvbkVycm9yKFxuICAgICAgICBgSW52YWxpZCBSZWRlbGVnYXRlTWVzc2FnZSB2YWxpZGF0b3JTcmNBZGRyZXNzOiBgICsgcmVkZWxlZ2F0ZU1lc3NhZ2UudmFsaWRhdG9yU3JjQWRkcmVzc1xuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRWYWxpZGF0b3JBZGRyZXNzKHJlZGVsZWdhdGVNZXNzYWdlLnZhbGlkYXRvckRzdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoXG4gICAgICAgIGBJbnZhbGlkIFJlZGVsZWdhdGVNZXNzYWdlIHZhbGlkYXRvckRzdEFkZHJlc3M6IGAgKyByZWRlbGVnYXRlTWVzc2FnZS52YWxpZGF0b3JEc3RBZGRyZXNzXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuaXNWYWxpZEFkZHJlc3MocmVkZWxlZ2F0ZU1lc3NhZ2UuZGVsZWdhdG9yQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcihcbiAgICAgICAgYEludmFsaWQgRGVsZWdhdGVPclVuZGVsZWdldGVNZXNzYWdlIGRlbGVnYXRvckFkZHJlc3M6IGAgKyByZWRlbGVnYXRlTWVzc2FnZS5kZWxlZ2F0b3JBZGRyZXNzXG4gICAgICApO1xuICAgIH1cbiAgICB0aGlzLnZhbGlkYXRlQW1vdW50KHJlZGVsZWdhdGVNZXNzYWdlLmFtb3VudCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoZSBDdXN0b21NZXNzYWdlXG4gICAqIEBwYXJhbSB7Q3VzdG9tTWVzc2FnZX0gY3VzdG9tTWVzc2FnZSAtIFRoZSBDdXN0b21NZXNzYWdlIHRvIHZhbGlkYXRlLlxuICAgKiBAdGhyb3dzIHtJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcn0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBjdXN0b20gbWVzc2FnZSBpcyBpbnZhbGlkIG9yIG1pc3NpbmcgcmVxdWlyZWQgZmllbGRzLlxuICAgKiBAdGhyb3dzIHtOb3RTdXBwb3J0ZWR9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgY3VzdG9tIG1lc3NhZ2UgZGF0YSBpcyBub3Qgc3VwcG9ydGVkLlxuICAgKi9cbiAgdmFsaWRhdGVDdXN0b21NZXNzYWdlKGN1c3RvbU1lc3NhZ2U6IEN1c3RvbU1lc3NhZ2UpIHtcbiAgICB0aHJvdyBuZXcgTm90U3VwcG9ydGVkKCdDdXN0b20gbWVzc2FnZSBkYXRhIG5vdCBzdXBwb3J0ZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgdGhlIE1lc3NhZ2VEYXRhXG4gICAqIEBwYXJhbSB7TWVzc2FnZURhdGF9IG1lc3NhZ2VEYXRhIC0gVGhlIE1lc3NhZ2VEYXRhIHRvIHZhbGlkYXRlLlxuICAgKiBAdGhyb3dzIHtJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcn0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtZXNzYWdlRGF0YSBpcyBpbnZhbGlkIG9yIG1pc3NpbmcgcmVxdWlyZWQgZmllbGRzLlxuICAgKi9cbiAgdmFsaWRhdGVNZXNzYWdlRGF0YShtZXNzYWdlRGF0YTogTWVzc2FnZURhdGE8Q3VzdG9tTWVzc2FnZT4pOiB2b2lkIHtcbiAgICBpZiAobWVzc2FnZURhdGEgPT0gbnVsbCkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRUcmFuc2FjdGlvbkVycm9yKGBJbnZhbGlkIE1lc3NhZ2VEYXRhOiB1bmRlZmluZWRgKTtcbiAgICB9XG4gICAgaWYgKG1lc3NhZ2VEYXRhLnR5cGVVcmwgPT0gbnVsbCB8fCB0aGlzLmdldFRyYW5zYWN0aW9uVHlwZUZyb21UeXBlVXJsKG1lc3NhZ2VEYXRhLnR5cGVVcmwpID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcihgSW52YWxpZCBNZXNzYWdlRGF0YSB0eXBldXJsOiBgICsgbWVzc2FnZURhdGEudHlwZVVybCk7XG4gICAgfVxuXG4gICAgY29uc3QgdHlwZSA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25UeXBlRnJvbVR5cGVVcmwobWVzc2FnZURhdGEudHlwZVVybCk7XG4gICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICBjYXNlIFRyYW5zYWN0aW9uVHlwZS5TZW5kOiB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gbWVzc2FnZURhdGEudmFsdWUgYXMgU2VuZE1lc3NhZ2U7XG4gICAgICAgIHRoaXMudmFsaWRhdGVTZW5kTWVzc2FnZSh2YWx1ZSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSBUcmFuc2FjdGlvblR5cGUuU3Rha2luZ0FjdGl2YXRlOlxuICAgICAgY2FzZSBUcmFuc2FjdGlvblR5cGUuU3Rha2luZ0RlYWN0aXZhdGU6IHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBtZXNzYWdlRGF0YS52YWx1ZSBhcyBEZWxlZ2F0ZU9yVW5kZWxlZ2V0ZU1lc3NhZ2U7XG4gICAgICAgIHRoaXMudmFsaWRhdGVEZWxlZ2F0ZU9yVW5kZWxlZ2F0ZU1lc3NhZ2UodmFsdWUpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLlN0YWtpbmdXaXRoZHJhdzoge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IG1lc3NhZ2VEYXRhLnZhbHVlIGFzIFdpdGhkcmF3RGVsZWdhdG9yUmV3YXJkc01lc3NhZ2U7XG4gICAgICAgIHRoaXMudmFsaWRhdGVXaXRoZHJhd1Jld2FyZHNNZXNzYWdlKHZhbHVlKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlIFRyYW5zYWN0aW9uVHlwZS5Db250cmFjdENhbGw6IHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBtZXNzYWdlRGF0YS52YWx1ZSBhcyBFeGVjdXRlQ29udHJhY3RNZXNzYWdlO1xuICAgICAgICB0aGlzLnZhbGlkYXRlRXhlY3V0ZUNvbnRyYWN0TWVzc2FnZSh2YWx1ZSwgVHJhbnNhY3Rpb25UeXBlLkNvbnRyYWN0Q2FsbCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSBUcmFuc2FjdGlvblR5cGUuU3Rha2luZ1JlZGVsZWdhdGU6IHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBtZXNzYWdlRGF0YS52YWx1ZSBhcyBSZWRlbGVnYXRlTWVzc2FnZTtcbiAgICAgICAgdGhpcy52YWxpZGF0ZVJlZGVsZWdhdGVNZXNzYWdlKHZhbHVlKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlIFRyYW5zYWN0aW9uVHlwZS5DdXN0b21UeDoge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IG1lc3NhZ2VEYXRhLnZhbHVlIGFzIEN1c3RvbU1lc3NhZ2U7XG4gICAgICAgIHRoaXMudmFsaWRhdGVDdXN0b21NZXNzYWdlKHZhbHVlKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoYEludmFsaWQgTWVzc2FnZURhdGEgVHlwZVVybCBpcyBub3Qgc3VwcG9ydGVkOiBgICsgbWVzc2FnZURhdGEudHlwZVVybCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB0aGUgQ29zbW9zLWxpa2UgdHJhbnNhY3Rpb24uXG4gICAqIEBwYXJhbSB7Q29zbW9zTGlrZVRyYW5zYWN0aW9ufSB0eCAtIFRoZSB0cmFuc2FjdGlvbiB0byB2YWxpZGF0ZS5cbiAgICogQHRocm93cyB7SW52YWxpZFRyYW5zYWN0aW9uRXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgdHJhbnNhY3Rpb24gaXMgaW52YWxpZCBvciBtaXNzaW5nIHJlcXVpcmVkIGZpZWxkcy5cbiAgICovXG4gIHZhbGlkYXRlVHJhbnNhY3Rpb24odHg6IENvc21vc0xpa2VUcmFuc2FjdGlvbjxDdXN0b21NZXNzYWdlPik6IHZvaWQge1xuICAgIHRoaXMudmFsaWRhdGVTZXF1ZW5jZSh0eC5zZXF1ZW5jZSk7XG4gICAgdGhpcy52YWxpZGF0ZUdhc0J1ZGdldCh0eC5nYXNCdWRnZXQpO1xuICAgIHRoaXMudmFsaWRhdGVQdWJsaWNLZXkodHgucHVibGljS2V5KTtcbiAgICBpZiAodHguc2VuZE1lc3NhZ2VzID09PSB1bmRlZmluZWQgfHwgdHguc2VuZE1lc3NhZ2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRUcmFuc2FjdGlvbkVycm9yKCdJbnZhbGlkIHRyYW5zYWN0aW9uOiBtZXNzYWdlcyBpcyByZXF1aXJlZCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0eC5zZW5kTWVzc2FnZXMuZm9yRWFjaCgobWVzc2FnZSkgPT4gdGhpcy52YWxpZGF0ZU1lc3NhZ2VEYXRhKG1lc3NhZ2UpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIENvc21vcy1saWtlIHRyYW5zYWN0aW9uLlxuICAgKiBAcGFyYW0ge251bWJlcn0gc2VxdWVuY2UgLSBUaGUgc2VuZGVyIGFkZHJlc3Mgc2VxdWVuY2UgbnVtYmVyIGZvciB0aGUgdHJhbnNhY3Rpb24uXG4gICAqIEBwYXJhbSB7TWVzc2FnZURhdGFbXX0gbWVzc2FnZXMgLSBUaGUgYXJyYXkgb2YgbWVzc2FnZSBkYXRhIGZvciB0aGUgdHJhbnNhY3Rpb24uXG4gICAqIEBwYXJhbSB7RmVlRGF0YX0gZ2FzQnVkZ2V0IC0gVGhlIGZlZSBkYXRhIGZvciB0aGUgdHJhbnNhY3Rpb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcHVibGljS2V5XSAtIFRoZSBwdWJsaWMga2V5IGFzc29jaWF0ZWQgd2l0aCB0aGUgc2VuZGVyLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW21lbW9dIC0gVGhlIG1lbW8gZm9yIHRoZSB0cmFuc2FjdGlvbi5cbiAgICogQHJldHVybnMge0Nvc21vc0xpa2VUcmFuc2FjdGlvbn0gUmV0dXJucyB0aGUgY3JlYXRlZCBDb3Ntb3MtbGlrZSB0cmFuc2FjdGlvbi5cbiAgICogQHRocm93cyB7SW52YWxpZFRyYW5zYWN0aW9uRXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgY3JlYXRlZCB0cmFuc2FjdGlvbiBpcyBpbnZhbGlkLlxuICAgKi9cbiAgY3JlYXRlVHJhbnNhY3Rpb24oXG4gICAgc2VxdWVuY2U6IG51bWJlcixcbiAgICBtZXNzYWdlczogTWVzc2FnZURhdGE8Q3VzdG9tTWVzc2FnZT5bXSxcbiAgICBnYXNCdWRnZXQ6IEZlZURhdGEsXG4gICAgcHVibGljS2V5Pzogc3RyaW5nLFxuICAgIG1lbW8/OiBzdHJpbmdcbiAgKTogQ29zbW9zTGlrZVRyYW5zYWN0aW9uPEN1c3RvbU1lc3NhZ2U+IHtcbiAgICBjb25zdCBjb3Ntb3NMaWtlVHhuID0ge1xuICAgICAgc2VxdWVuY2U6IHNlcXVlbmNlLFxuICAgICAgc2VuZE1lc3NhZ2VzOiBtZXNzYWdlcyxcbiAgICAgIGdhc0J1ZGdldDogZ2FzQnVkZ2V0LFxuICAgICAgcHVibGljS2V5OiBwdWJsaWNLZXksXG4gICAgICBtZW1vOiBtZW1vLFxuICAgIH07XG4gICAgdGhpcy52YWxpZGF0ZVRyYW5zYWN0aW9uKGNvc21vc0xpa2VUeG4pO1xuICAgIHJldHVybiBjb3Ntb3NMaWtlVHhuO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBDb3Ntb3MtbGlrZSB0cmFuc2FjdGlvbiB3aXRoIGEgaGFzaC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IHNlcXVlbmNlIC0gVGhlIHNlbmRlciBhZGRyZXNzIHNlcXVlbmNlIG51bWJlciBmb3IgdGhlIHRyYW5zYWN0aW9uLlxuICAgKiBAcGFyYW0ge01lc3NhZ2VEYXRhW119IG1lc3NhZ2VzIC0gVGhlIGFycmF5IG9mIG1lc3NhZ2UgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uLlxuICAgKiBAcGFyYW0ge0ZlZURhdGF9IGdhc0J1ZGdldCAtIFRoZSBmZWUgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3B1YmxpY0tleV0gLSBUaGUgcHVibGljIGtleSBhc3NvY2lhdGVkIHdpdGggdGhlIHRyYW5zYWN0aW9uLlxuICAgKiBAcGFyYW0ge0J1ZmZlcn0gW3NpZ25hdHVyZV0gLSBUaGUgc2lnbmF0dXJlIGZvciB0aGUgdHJhbnNhY3Rpb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbbWVtb10gLSBUaGUgbWVtbyBmb3IgdGhlIHRyYW5zYWN0aW9uLlxuICAgKiBAcmV0dXJucyB7Q29zbW9zTGlrZVRyYW5zYWN0aW9ufSBSZXR1cm5zIHRoZSBjcmVhdGVkIENvc21vcy1saWtlIHRyYW5zYWN0aW9uIHdpdGggdGhlIGhhc2ggYW5kIHNpZ25hdHVyZSBpZiBwcm92aWRlZC5cbiAgICovXG4gIGNyZWF0ZVRyYW5zYWN0aW9uV2l0aEhhc2goXG4gICAgc2VxdWVuY2U6IG51bWJlcixcbiAgICBtZXNzYWdlczogTWVzc2FnZURhdGE8Q3VzdG9tTWVzc2FnZT5bXSxcbiAgICBnYXNCdWRnZXQ6IEZlZURhdGEsXG4gICAgcHVibGljS2V5Pzogc3RyaW5nLFxuICAgIHNpZ25hdHVyZT86IEJ1ZmZlcixcbiAgICBtZW1vPzogc3RyaW5nXG4gICk6IENvc21vc0xpa2VUcmFuc2FjdGlvbjxDdXN0b21NZXNzYWdlPiB7XG4gICAgY29uc3QgY29zbW9zTGlrZVR4biA9IHRoaXMuY3JlYXRlVHJhbnNhY3Rpb24oc2VxdWVuY2UsIG1lc3NhZ2VzLCBnYXNCdWRnZXQsIHB1YmxpY0tleSwgbWVtbyk7XG4gICAgbGV0IGhhc2ggPSBjb25zdGFudHMuVU5BVkFJTEFCTEVfVEVYVDtcbiAgICBpZiAoc2lnbmF0dXJlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHVuc2lnbmVkVHggPSB0aGlzLmNyZWF0ZVR4UmF3RnJvbUNvc21vc0xpa2VUcmFuc2FjdGlvbihjb3Ntb3NMaWtlVHhuKTtcbiAgICAgIGNvbnN0IHNpZ25lZFR4ID0gVHhSYXcuZnJvbVBhcnRpYWwoe1xuICAgICAgICBib2R5Qnl0ZXM6IHVuc2lnbmVkVHguYm9keUJ5dGVzLFxuICAgICAgICBhdXRoSW5mb0J5dGVzOiB1bnNpZ25lZFR4LmF1dGhJbmZvQnl0ZXMsXG4gICAgICAgIHNpZ25hdHVyZXM6IFtzaWduYXR1cmVdLFxuICAgICAgfSk7XG4gICAgICBoYXNoID0gY3JlYXRlSGFzaCgnc2hhMjU2JylcbiAgICAgICAgLnVwZGF0ZShUeFJhdy5lbmNvZGUoc2lnbmVkVHgpLmZpbmlzaCgpKVxuICAgICAgICAuZGlnZXN0KClcbiAgICAgICAgLnRvU3RyaW5nKCdoZXgnKVxuICAgICAgICAudG9Mb2NhbGVVcHBlckNhc2UoJ2VuLVVTJyk7XG4gICAgICByZXR1cm4geyAuLi5jb3Ntb3NMaWtlVHhuLCBoYXNoOiBoYXNoLCBzaWduYXR1cmU6IHNpZ25hdHVyZSB9O1xuICAgIH1cbiAgICByZXR1cm4geyAuLi5jb3Ntb3NMaWtlVHhuLCBoYXNoOiBoYXNoIH07XG4gIH1cblxuICAvKipcbiAgICogRGVzZXJpYWxpemVzIGJhc2U2NCBlbm9jZGVkIHJhdyB0cmFuc2FjdGlvbiBzdHJpbmcgaW50byBAc2VlIENvc21vc0xpa2VUcmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmF3VHggYmFzZTY0IGVub2NkZWQgcmF3IHRyYW5zYWN0aW9uIHN0cmluZ1xuICAgKiBAcmV0dXJucyB7Q29zbW9zTGlrZVRyYW5zYWN0aW9ufSBEZXNlcmlhbGl6ZWQgY29zbW9zTGlrZVRyYW5zYWN0aW9uXG4gICAqL1xuICBkZXNlcmlhbGl6ZVRyYW5zYWN0aW9uKHJhd1R4OiBzdHJpbmcpOiBDb3Ntb3NMaWtlVHJhbnNhY3Rpb248Q3VzdG9tTWVzc2FnZT4ge1xuICAgIGNvbnN0IGRlY29kZWRUeCA9IHRoaXMuZ2V0RGVjb2RlZFR4RnJvbVJhd0Jhc2U2NChyYXdUeCk7XG4gICAgY29uc3QgdHlwZVVybCA9IHRoaXMuZ2V0VHlwZVVybEZyb21EZWNvZGVkVHgoZGVjb2RlZFR4KTtcbiAgICBjb25zdCB0eXBlOiBUcmFuc2FjdGlvblR5cGUgfCB1bmRlZmluZWQgPSB0aGlzLmdldFRyYW5zYWN0aW9uVHlwZUZyb21UeXBlVXJsKHR5cGVVcmwpO1xuICAgIGxldCBzZW5kTWVzc2FnZURhdGE6IE1lc3NhZ2VEYXRhPEN1c3RvbU1lc3NhZ2U+W107XG4gICAgaWYgKHR5cGUgPT09IFRyYW5zYWN0aW9uVHlwZS5TZW5kKSB7XG4gICAgICBzZW5kTWVzc2FnZURhdGEgPSB0aGlzLmdldFNlbmRNZXNzYWdlRGF0YUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4KTtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09IFRyYW5zYWN0aW9uVHlwZS5TdGFraW5nQWN0aXZhdGUgfHwgdHlwZSA9PT0gVHJhbnNhY3Rpb25UeXBlLlN0YWtpbmdEZWFjdGl2YXRlKSB7XG4gICAgICBzZW5kTWVzc2FnZURhdGEgPSB0aGlzLmdldERlbGVnYXRlT3JVbmRlbGVnYXRlTWVzc2FnZURhdGFGcm9tRGVjb2RlZFR4KGRlY29kZWRUeCk7XG4gICAgfSBlbHNlIGlmICh0eXBlID09PSBUcmFuc2FjdGlvblR5cGUuU3Rha2luZ1dpdGhkcmF3KSB7XG4gICAgICBzZW5kTWVzc2FnZURhdGEgPSB0aGlzLmdldFdpdGhkcmF3UmV3YXJkc01lc3NhZ2VEYXRhRnJvbURlY29kZWRUeChkZWNvZGVkVHgpO1xuICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gVHJhbnNhY3Rpb25UeXBlLkNvbnRyYWN0Q2FsbCkge1xuICAgICAgc2VuZE1lc3NhZ2VEYXRhID0gdGhpcy5nZXRFeGVjdXRlQ29udHJhY3RNZXNzYWdlRGF0YUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4KTtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09IFRyYW5zYWN0aW9uVHlwZS5TdGFraW5nUmVkZWxlZ2F0ZSkge1xuICAgICAgc2VuZE1lc3NhZ2VEYXRhID0gdGhpcy5nZXRSZWRlbGVnYXRlTWVzc2FnZURhdGFGcm9tRGVjb2RlZFR4KGRlY29kZWRUeCk7XG4gICAgfSBlbHNlIGlmICh0eXBlID09PSBUcmFuc2FjdGlvblR5cGUuQ3VzdG9tVHgpIHtcbiAgICAgIHNlbmRNZXNzYWdlRGF0YSA9IHRoaXMuZ2V0Q3VzdG9tTWVzc2FnZURhdGFGcm9tRGVjb2RlZFR4KGRlY29kZWRUeCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNhY3Rpb24gdHlwZSBub3Qgc3VwcG9ydGVkOiAnICsgdHlwZVVybCk7XG4gICAgfVxuICAgIGNvbnN0IHNlcXVlbmNlID0gdGhpcy5nZXRTZXF1ZW5jZUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4KTtcbiAgICBjb25zdCBnYXNCdWRnZXQgPSB0aGlzLmdldEdhc0J1ZGdldEZyb21EZWNvZGVkVHgoZGVjb2RlZFR4KTtcbiAgICBjb25zdCBwdWJsaWNLZXkgPSB0aGlzLmdldFB1YmxpY0tleUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4KTtcbiAgICBjb25zdCBzaWduYXR1cmUgPSBkZWNvZGVkVHguc2lnbmF0dXJlcz8uWzBdICE9PSB1bmRlZmluZWQgPyBCdWZmZXIuZnJvbShkZWNvZGVkVHguc2lnbmF0dXJlc1swXSkgOiB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlVHJhbnNhY3Rpb25XaXRoSGFzaChcbiAgICAgIHNlcXVlbmNlLFxuICAgICAgc2VuZE1lc3NhZ2VEYXRhLFxuICAgICAgZ2FzQnVkZ2V0LFxuICAgICAgcHVibGljS2V5LFxuICAgICAgc2lnbmF0dXJlLFxuICAgICAgZGVjb2RlZFR4LmJvZHk/Lm1lbW9cbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyBhbiBhcnJheSBvZiBjb2luIGFtb3VudHMuXG4gICAqIEBwYXJhbSB7Q29pbltdfSBhbW91bnRBcnJheSAtIFRoZSBhcnJheSBvZiBjb2luIGFtb3VudHMgdG8gdmFsaWRhdGUuXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb25UeXBlfSB0cmFuc2FjdGlvblR5cGUgLSBvcHRpb25hbCBmaWVsZCBmb3IgdHJhbnNhY3Rpb24gdHlwZVxuICAgKi9cbiAgdmFsaWRhdGVBbW91bnREYXRhKGFtb3VudEFycmF5OiBDb2luW10sIHRyYW5zYWN0aW9uVHlwZT86IFRyYW5zYWN0aW9uVHlwZSk6IHZvaWQge1xuICAgIGFtb3VudEFycmF5LmZvckVhY2goKGNvaW5BbW91bnQpID0+IHtcbiAgICAgIHRoaXMudmFsaWRhdGVBbW91bnQoY29pbkFtb3VudCwgdHJhbnNhY3Rpb25UeXBlKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgdGhlIGdhcyBsaW1pdCBhbmQgZ2FzIGFtb3VudCBmb3IgYSB0cmFuc2FjdGlvbi5cbiAgICogQHBhcmFtIHtGZWVEYXRhfSBnYXNCdWRnZXQgLSBUaGUgZ2FzIGJ1ZGdldCB0byB2YWxpZGF0ZS5cbiAgICogQHRocm93cyB7SW52YWxpZFRyYW5zYWN0aW9uRXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgZ2FzIGJ1ZGdldCBpcyBpbnZhbGlkLlxuICAgKi9cbiAgdmFsaWRhdGVHYXNCdWRnZXQoZ2FzQnVkZ2V0OiBGZWVEYXRhKTogdm9pZCB7XG4gICAgaWYgKGdhc0J1ZGdldC5nYXNMaW1pdCA8PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoJ0ludmFsaWQgZ2FzIGxpbWl0ICcgKyBnYXNCdWRnZXQuZ2FzTGltaXQpO1xuICAgIH1cbiAgICB0aGlzLnZhbGlkYXRlQW1vdW50RGF0YShnYXNCdWRnZXQuYW1vdW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgYSBzZW5kIG1lc3NhZ2UgZm9yIGEgdHJhbnNhY3Rpb24uXG4gICAqIEBwYXJhbSB7U2VuZE1lc3NhZ2V9IHNlbmRNZXNzYWdlIC0gVGhlIHNlbmQgbWVzc2FnZSB0byB2YWxpZGF0ZS5cbiAgICogQHRocm93cyB7SW52YWxpZFRyYW5zYWN0aW9uRXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VuZCBtZXNzYWdlIGlzIGludmFsaWQuXG4gICAqL1xuICB2YWxpZGF0ZVNlbmRNZXNzYWdlKHNlbmRNZXNzYWdlOiBTZW5kTWVzc2FnZSkge1xuICAgIGlmICghc2VuZE1lc3NhZ2UudG9BZGRyZXNzIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHNlbmRNZXNzYWdlLnRvQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcihgSW52YWxpZCBTZW5kTWVzc2FnZSB0b0FkZHJlc3M6IGAgKyBzZW5kTWVzc2FnZS50b0FkZHJlc3MpO1xuICAgIH1cbiAgICBpZiAoIXNlbmRNZXNzYWdlLmZyb21BZGRyZXNzIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHNlbmRNZXNzYWdlLmZyb21BZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRUcmFuc2FjdGlvbkVycm9yKGBJbnZhbGlkIFNlbmRNZXNzYWdlIGZyb21BZGRyZXNzOiBgICsgc2VuZE1lc3NhZ2UuZnJvbUFkZHJlc3MpO1xuICAgIH1cbiAgICB0aGlzLnZhbGlkYXRlQW1vdW50RGF0YShzZW5kTWVzc2FnZS5hbW91bnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyBhIGNvaW4gYW1vdW50LlxuICAgKiBAcGFyYW0ge0NvaW59IGFtb3VudCAtIFRoZSBjb2luIGFtb3VudCB0byB2YWxpZGF0ZS5cbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvblR5cGV9IHRyYW5zYWN0aW9uVHlwZSAtIG9wdGlvbmFsIGZpZWxkIGZvciB0cmFuc2FjdGlvbiB0eXBlXG4gICAqIEB0aHJvd3Mge0ludmFsaWRUcmFuc2FjdGlvbkVycm9yfSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGNvaW4gYW1vdW50IGlzIGludmFsaWQuXG4gICAqL1xuICB2YWxpZGF0ZUFtb3VudChhbW91bnQ6IENvaW4sIHRyYW5zYWN0aW9uVHlwZT86IFRyYW5zYWN0aW9uVHlwZSk6IHZvaWQge1xuICAgIHRocm93IG5ldyBOb3RJbXBsZW1lbnRlZEVycm9yKCd2YWxpZGF0ZUFtb3VudCBub3QgaW1wbGVtZW50ZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYSBjb3Ntb3MgbGlrZSBCZWNoMzIgYWRkcmVzcyBtYXRjaGVzIGdpdmVuIHJlZ3VsYXIgZXhwcmVzc2lvbiBhbmRcbiAgICogdmFsaWRhdGVzIG1lbW9JZCBpZiBwcmVzZW50XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzXG4gICAqIEBwYXJhbSB7UmVnRXhwfSByZWdFeHAgUmVndWxhciBleHByZXNzaW9uIHRvIHZhbGlkYXRlIHRoZSByb290IGFkZHJlc3MgYWdhaW5zdCBhZnRlciB0cmltbWluZyB0aGUgbWVtb0lkXG4gICAqIEByZXR1cm5zIHtib29sZWFufSB0cnVlIGlmIGFkZHJlc3MgaXMgdmFsaWRcbiAgICovXG4gIHByb3RlY3RlZCBpc1ZhbGlkQ29zbW9zTGlrZUFkZHJlc3NXaXRoTWVtb0lkKGFkZHJlc3M6IHN0cmluZywgcmVnRXhwOiBSZWdFeHApOiBib29sZWFuIHtcbiAgICBpZiAodHlwZW9mIGFkZHJlc3MgIT09ICdzdHJpbmcnKSByZXR1cm4gZmFsc2U7XG4gICAgY29uc3QgYWRkcmVzc0FycmF5ID0gYWRkcmVzcy5zcGxpdCgnP21lbW9JZD0nKTtcbiAgICBpZiAoXG4gICAgICAhWzEsIDJdLmluY2x1ZGVzKGFkZHJlc3NBcnJheS5sZW5ndGgpIHx8IC8vIHNob3VsZCBoYXZlIGF0IG1vc3Qgb25lIG9jY3VycmVuY2Ugb2YgJ21lbW9JZD0nXG4gICAgICAhdGhpcy5pc1ZhbGlkQmVjaDMyQWRkcmVzc01hdGNoaW5nUmVnZXgoYWRkcmVzc0FycmF5WzBdLCByZWdFeHApIHx8XG4gICAgICAoYWRkcmVzc0FycmF5WzFdICYmICF0aGlzLmlzVmFsaWRNZW1vSWQoYWRkcmVzc0FycmF5WzFdKSlcbiAgICApIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGFkZHJlc3MgaXMgdmFsaWQgQmVjaDMyIGFuZCBtYXRjaGVzIGdpdmVuIHJlZ3VsYXIgZXhwcmVzc2lvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzc1xuICAgKiBAcGFyYW0ge1JlZ0V4cH0gcmVnRXhwIFJlZ3VsYXIgZXhwcmVzc2lvbiB0byB2YWxpZGF0ZSB0aGUgYWRkcmVzcyBhZ2FpbnN0XG4gICAqIEByZXR1cm5zIHtib29sZWFufSB0cnVlIGlmIGFkZHJlc3MgaXMgdmFsaWRcbiAgICovXG4gIHByb3RlY3RlZCBpc1ZhbGlkQmVjaDMyQWRkcmVzc01hdGNoaW5nUmVnZXgoYWRkcmVzczogc3RyaW5nLCByZWdFeHA6IFJlZ0V4cCk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICBmcm9tQmVjaDMyKGFkZHJlc3MpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHJlZ0V4cC50ZXN0KGFkZHJlc3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBhIG1lbW8gaWQgaXMgdmFsaWRcbiAgICpcbiAgICogQHBhcmFtIG1lbW9JZCBtZW1vIGlkXG4gICAqIEByZXR1cm5zIHRydWUgaWYgbWVtbyBpZCBpcyB2YWxpZFxuICAgKi9cbiAgaXNWYWxpZE1lbW9JZChtZW1vSWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIC8vIEFsbG93IGFscGhhbnVtZXJpYyBtZW1vIElEcyAoaW5jbHVkaW5nIHVwcGVyY2FzZSBhbmQgbG93ZXJjYXNlIGxldHRlcnMpXG4gICAgY29uc3QgYWxwaGFudW1lcmljUmVnZXggPSAvXlswLTlhLXpBLVpdKyQvO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1lbW9JZCBpcyBhbHBoYW51bWVyaWNcbiAgICBpZiAoIWFscGhhbnVtZXJpY1JlZ2V4LnRlc3QobWVtb0lkKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIElmIHRoZSBtZW1vSWQgaXMgcHVyZWx5IG51bWVyaWMsIGVuc3VyZSBpdCBpcyBhIHBvc2l0aXZlIGludGVnZXJcbiAgICBpZiAoL15cXGQrJC8udGVzdChtZW1vSWQpKSB7XG4gICAgICBjb25zdCBtZW1vSWROdW1iZXIgPSBuZXcgQmlnTnVtYmVyKG1lbW9JZCk7XG4gICAgICByZXR1cm4gbWVtb0lkTnVtYmVyLmd0ZSgwKSAmJiBtZW1vSWROdW1iZXIuaXNJbnRlZ2VyKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIGlmIHRoZSBhZGRyZXNzIG1hdGNoZXMgd2l0aCByZWdleCBAc2VlIGFjY291bnRBZGRyZXNzUmVnZXhcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3NcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gdGhlIHZhbGlkYXRpb24gcmVzdWx0XG4gICAqL1xuICBpc1ZhbGlkVmFsaWRhdG9yQWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcignaXNWYWxpZFZhbGlkYXRvckFkZHJlc3Mgbm90IGltcGxlbWVudGVkJyk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIGlmIHRoZSBhZGRyZXNzIG1hdGNoZXMgd2l0aCByZWdleCBAc2VlIGFjY291bnRBZGRyZXNzUmVnZXhcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3NcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gdGhlIHZhbGlkYXRpb24gcmVzdWx0XG4gICAqL1xuICBpc1ZhbGlkQWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcignaXNWYWxpZEFkZHJlc3Mgbm90IGltcGxlbWVudGVkJyk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIGlmIHRoZSBhZGRyZXNzIG1hdGNoZXMgd2l0aCByZWdleCBAc2VlIGNvbnRyYWN0QWRkcmVzc1JlZ2V4XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIHRoZSB2YWxpZGF0aW9uIHJlc3VsdFxuICAgKi9cbiAgaXNWYWxpZENvbnRyYWN0QWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcignaXNWYWxpZENvbnRyYWN0QWRkcmVzcyBub3QgaW1wbGVtZW50ZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgYSBleGVjdXRlIGNvbnRyYWN0IG1lc3NhZ2VcbiAgICogQHBhcmFtIHtFeGVjdXRlQ29udHJhY3RNZXNzYWdlfSBtZXNzYWdlIC0gVGhlIGV4ZWN1dGUgY29udHJhY3QgbWVzc2FnZSB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uVHlwZX0gdHJhbnNhY3Rpb25UeXBlIC0gb3B0aW9uYWwgZmllbGQgZm9yIHRyYW5zYWN0aW9uIHR5cGVcbiAgICogQHRocm93cyB7SW52YWxpZFRyYW5zYWN0aW9uRXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgbWVzc2FnZSBpcyBpbnZhbGlkXG4gICAqL1xuICB2YWxpZGF0ZUV4ZWN1dGVDb250cmFjdE1lc3NhZ2UobWVzc2FnZTogRXhlY3V0ZUNvbnRyYWN0TWVzc2FnZSwgdHJhbnNhY3Rpb25UeXBlPzogVHJhbnNhY3Rpb25UeXBlKSB7XG4gICAgaWYgKCFtZXNzYWdlLmNvbnRyYWN0IHx8ICF0aGlzLmlzVmFsaWRDb250cmFjdEFkZHJlc3MobWVzc2FnZS5jb250cmFjdCkpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcihgSW52YWxpZCBFeGVjdXRlQ29udHJhY3RNZXNzYWdlIGNvbnRyYWN0IGFkZHJlc3M6IGAgKyBtZXNzYWdlLmNvbnRyYWN0KTtcbiAgICB9XG4gICAgaWYgKCFtZXNzYWdlLnNlbmRlciB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhtZXNzYWdlLnNlbmRlcikpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcihgSW52YWxpZCBFeGVjdXRlQ29udHJhY3RNZXNzYWdlIHNlbmRlciBhZGRyZXNzOiBgICsgbWVzc2FnZS5zZW5kZXIpO1xuICAgIH1cbiAgICBpZiAoIW1lc3NhZ2UubXNnKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoYEludmFsaWQgRXhlY3V0ZUNvbnRyYWN0TWVzc2FnZSBtc2c6IGAgKyBtZXNzYWdlLm1zZyk7XG4gICAgfVxuICAgIGlmIChtZXNzYWdlLmZ1bmRzKSB7XG4gICAgICB0aGlzLnZhbGlkYXRlQW1vdW50RGF0YShtZXNzYWdlLmZ1bmRzLCB0cmFuc2FjdGlvblR5cGUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY29pbiBzcGVjaWZpYyBoYXNoIGZ1bmN0aW9uXG4gICAqIEByZXR1cm5zIHtIYXNofSBUaGUgaGFzaCBmdW5jdGlvblxuICAgKi9cbiAgZ2V0SGFzaEZ1bmN0aW9uKCk6IEhhc2gge1xuICAgIHJldHVybiBjcmVhdGVIYXNoKCdzaGEyNTYnKTtcbiAgfVxuXG4gIGdldFRva2VuRGVub21zVXNpbmdDb2luRmFtaWx5KGNvaW5GYW1pbHk6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICAvLyB1c2luZyBzZXQgdG8gcmVtb3ZlIGR1cGxpY2F0ZXMgYXMgZGVub20gY2FuIGJlIHNhbWUgb24gdGVzdG5ldCBhbmQgbWFpbm5ldCBmb3IgYSBmZXcgdG9rZW5zXG4gICAgcmV0dXJuIFtcbiAgICAgIC4uLm5ldyBTZXQoXG4gICAgICAgIGNvaW5zXG4gICAgICAgICAgLmZpbHRlcihcbiAgICAgICAgICAgIChjb2luKSA9PiBjb2luLmZhbWlseS50b0xvd2VyQ2FzZSgpID09PSBjb2luRmFtaWx5LnRvTG93ZXJDYXNlKCkgJiYgY29pbi5pc1Rva2VuICYmIGNvaW4uZGVub20gIT09IHVuZGVmaW5lZFxuICAgICAgICAgIClcbiAgICAgICAgICAubWFwKChjb2luKSA9PiBjb2luLmRlbm9tIGFzIHN0cmluZylcbiAgICAgICksXG4gICAgXTtcbiAgfVxufVxuXG5jb25zdCB1dGlscyA9IG5ldyBDb3Ntb3NVdGlscygpO1xuXG5leHBvcnQgZGVmYXVsdCB1dGlscztcbiJdfQ==

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


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