PHP WebShell

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

Просмотр файла: baseCoin.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.BaseCoin = void 0;
/**
 * @prettier
 */
const crypto = __importStar(require("crypto"));
const utxolib = __importStar(require("@bitgo/utxo-lib"));
const utxo_lib_1 = require("@bitgo/utxo-lib");
const sjcl = __importStar(require("@bitgo/sjcl"));
const bignumber_js_1 = require("bignumber.js");
const statics_1 = require("@bitgo/statics");
const bip32util_1 = require("../bip32util");
const account_lib_1 = require("../../account-lib");
const enterprise_1 = require("../enterprise");
const keychain_1 = require("../keychain");
const market_1 = require("../market");
const pendingApproval_1 = require("../pendingApproval");
const wallet_1 = require("../wallet");
const webhook_1 = require("../webhook");
class BaseCoin {
    constructor(bitgo) {
        this.bitgo = bitgo;
        this._url = this.bitgo.url('/', 2);
        this._wallets = new wallet_1.Wallets(this.bitgo, this);
        this._keychains = new keychain_1.Keychains(this.bitgo, this);
        this._webhooks = new webhook_1.Webhooks(this.bitgo, this);
        this._pendingApprovals = new pendingApproval_1.PendingApprovals(this.bitgo, this);
        this._enterprises = new enterprise_1.Enterprises(this.bitgo, this);
        this._markets = new market_1.Markets(this.bitgo, this);
    }
    url(suffix) {
        return this._url + this.getChain() + suffix;
    }
    wallets() {
        return this._wallets;
    }
    enterprises() {
        return this._enterprises;
    }
    keychains() {
        return this._keychains;
    }
    webhooks() {
        return this._webhooks;
    }
    pendingApprovals() {
        return this._pendingApprovals;
    }
    markets() {
        return this._markets;
    }
    static get coinTokenPatternSeparator() {
        return this._coinTokenPatternSeparator;
    }
    get type() {
        return this.getChain();
    }
    /**
     * Gets the statics coin object
     * @returns {Readonly<StaticsBaseCoin>} the statics coin object
     */
    getConfig() {
        return this._staticsCoin;
    }
    /**
     * Flag for sending value of 0.
     * @returns {boolean} True if okay to send 0 value, false otherwise
     */
    valuelessTransferAllowed() {
        return false;
    }
    /**
     * Use `sendMany()` to perform wallet sweep.
     * FIXME(BG-39738): add coin.sweepWallet() instead
     */
    sweepWithSendMany() {
        return false;
    }
    /**
     * Flag for sending data along with transactions
     * @returns {boolean} True if okay to send tx data (ETH), false otherwise
     */
    transactionDataAllowed() {
        return false;
    }
    /**
     * Flag for determining whether this coin supports account consolidations
     * from its receive addresses to the root address.
     * @returns {boolean} True if okay to consolidate over this coin; false, otherwise
     */
    allowsAccountConsolidations() {
        return false;
    }
    /**
     * Gets config for how token enablements work for this coin
     * @returns
     *    requiresTokenEnablement: True if tokens need to be enabled for this coin
     *    supportsMultipleTokenEnablements: True if multiple tokens can be enabled in one transaction
     */
    getTokenEnablementConfig() {
        return {
            requiresTokenEnablement: false,
            supportsMultipleTokenEnablements: false,
        };
    }
    /**
     * Flag indicating if this coin supports TSS wallets.
     * @returns {boolean} True if TSS Wallets can be created for this coin
     */
    supportsTss() {
        return false;
    }
    /**
     * @deprecated use CoinFeature.MULTISIG from statics instead
     * Flag indicating if this coin supports MultiSig wallets.
     * @return {boolean} True if MultiSig wallets can be created for this coin
     */
    supportsMultisig() {
        // Use the static coin configuration to check if MULTISIG is supported
        return this._staticsCoin.features.includes(statics_1.CoinFeature.MULTISIG);
    }
    /**
     * It will return the default multisig type value for coin
     * @return {MultisigType} return 'tss' if coin supports only TSS not MultiSig
     * else if coin supports MultiSig return 'onchain'
     * if coin supports both return 'onchain'
     * else undefined
     */
    getDefaultMultisigType() {
        return undefined;
    }
    /**
     * Flag indicating if the coin supports deriving a key with a seed (keyID)
     * to the user/backup keys.
     */
    supportsDeriveKeyWithSeed() {
        return true;
    }
    /**
     * Flag indicating if this blockchain runs on EVM architecture.
     * @returns {boolean} True if the blockchain runs on EVM architecture.
     */
    isEVM() {
        return false;
    }
    /**
     * Flag indicating if this coin supports BLS-DKG wallets.
     * @returns {boolean} True if BLS-DKG Wallets can be created for this coin
     */
    supportsBlsDkg() {
        return false;
    }
    /**
     * Convert a currency amount represented in base units (satoshi, wei, atoms, drops, stroops)
     * to big units (btc, eth, xrp, xlm)
     */
    baseUnitsToBigUnits(baseUnits) {
        bignumber_js_1.BigNumber.set({ DECIMAL_PLACES: 24 });
        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(null, null, { groupSeparator: '', decimalSeparator: '.' });
    }
    checkRecipient(recipient) {
        if (recipient.amount !== 'max') {
            const amount = new bignumber_js_1.BigNumber(recipient.amount);
            if (amount.isNegative()) {
                throw new Error('invalid argument for amount - positive number greater than zero or numeric string expected');
            }
            if (!this.valuelessTransferAllowed() && amount.isZero()) {
                throw new Error('invalid argument for amount - positive number greater than zero or numeric string expected');
            }
        }
    }
    /**
     * Convert a currency amount represented in big units (btc, eth, xrp, xlm)
     * to base units (satoshi, wei, atoms, drops, stroops)
     * @param bigUnits
     */
    bigUnitsToBaseUnits(bigUnits) {
        const multiplier = this.getBaseFactor();
        const bigNumber = new bignumber_js_1.BigNumber(bigUnits).times(multiplier);
        if (!bigNumber.isInteger()) {
            throw new Error(`non-integer output resulted from multiplying ${bigUnits} by ${multiplier}`);
        }
        return bigNumber.toFixed(0);
    }
    /**
     * Preprocess the build parameters before sending to the API
     * @param buildParams
     */
    preprocessBuildParams(buildParams) {
        return buildParams;
    }
    /**
     * Sign message with private key
     *
     * @param key
     * @param message
     */
    async signMessage(key, message) {
        return (0, bip32util_1.signMessage)(message, utxo_lib_1.bip32.fromBase58(key.prv), utxolib.networks.bitcoin);
    }
    /**
     * Create signatures for the backup and bitgo keys using the user key.
     * We can verify the signatures when fetching the keys from wallet-platform later.
     * Currently only `AbstractUtxoCoin` implements and uses the complementary `verifyKeySignature` method.
     * @param prv - the user private key
     * @param backupKeychain - contains the backup public key
     * @param bitgoKeychain - contains the bitgo public key
     */
    async createKeySignatures(prv, backupKeychain, bitgoKeychain) {
        return {
            backup: (await this.signMessage({ prv }, backupKeychain.pub)).toString('hex'),
            bitgo: (await this.signMessage({ prv }, bitgoKeychain.pub)).toString('hex'),
        };
    }
    /**
     * Decompose a raw transaction into useful information.
     * @param options - coin-specific
     */
    explainTransaction(options) {
        throw new Error(`not implemented`);
    }
    /**
     * @deprecated use {@see isWalletAddress} instead
     */
    verifyAddress(params) {
        return this.isWalletAddress(params);
    }
    /**
     * convert address into desired address format.
     * @param address
     * @param format
     */
    canonicalAddress(address, format) {
        return address;
    }
    /**
     * Check whether a coin supports blockTarget for transactions to be included in
     * @returns {boolean}
     */
    supportsBlockTarget() {
        return false;
    }
    /**
     * Check whether a coin supports lightning transactions
     * @returns {boolean}
     */
    supportsLightning() {
        return false;
    }
    /**
     * Check whether a coin supports message signing
     * @returns {boolean}
     */
    supportsMessageSigning() {
        return false;
    }
    /**
     * Check whether a coin supports signing of Typed data
     * @returns {boolean}
     */
    supportsSigningTypedData() {
        return false;
    }
    /**
     * Hook to add additional parameters to the wallet generation
     * @param walletParams
     * @param keychains
     * @return {*}
     */
    supplementGenerateWallet(walletParams, keychains) {
        return Promise.resolve(walletParams);
    }
    /**
     * Get extra parameters for prebuilding a tx. Add things like hop transaction params
     */
    getExtraPrebuildParams(buildParams) {
        return Promise.resolve({});
    }
    /**
     * Modify prebuild after receiving it from the server. Add things like nlocktime
     */
    postProcessPrebuild(prebuildResponse) {
        return Promise.resolve(prebuildResponse);
    }
    /**
     * Coin-specific things done before signing a transaction, i.e. verification
     */
    presignTransaction(params) {
        return Promise.resolve(params);
    }
    /**
     * Create a new wallet object from a wallet data object
     * @param walletParams
     */
    newWalletObject(walletParams) {
        return new wallet_1.Wallet(this.bitgo, this, walletParams);
    }
    /**
     * Fetch fee estimate information from the server
     * @param {Object} params The params passed into the function
     * @param {Integer} params.numBlocks The number of blocks to target for conformation (Only works for btc)
     * @returns {Object} The info returned from the merchant server
     */
    async feeEstimate(params) {
        const query = {};
        if (params && params.numBlocks) {
            query.numBlocks = params.numBlocks;
        }
        return this.bitgo.get(this.url('/tx/fee')).query(query).result();
    }
    /**
     * The cold wallet tool uses this function to derive an extended key that is based on the passed key and seed
     * @param key
     * @param seed
     * @returns {{key: string, derivationPath: string}}
     */
    static deriveKeyWithSeedBip32(key, seed) {
        function sha256(input) {
            return crypto.createHash('sha256').update(input).digest();
        }
        const derivationPathInput = sha256(sha256(`${seed}`)).toString('hex');
        const derivationPathParts = [
            parseInt(derivationPathInput.slice(0, 7), 16),
            parseInt(derivationPathInput.slice(7, 14), 16),
        ];
        const derivationPath = 'm/999999/' + derivationPathParts.join('/');
        return {
            key: key.derivePath(derivationPath),
            derivationPath,
        };
    }
    /** {@see deriveKeyWithSeedBip32} */
    deriveKeyWithSeed(params) {
        const { key, derivationPath } = BaseCoin.deriveKeyWithSeedBip32(utxo_lib_1.bip32.fromBase58(params.key), params.seed);
        return {
            key: key.toBase58(),
            derivationPath,
        };
    }
    /**
     * Specifies what key we will need for signing - right now we just need the
     * user key.
     */
    keyIdsForSigning() {
        return [keychain_1.KeyIndices.USER];
    }
    /**
     * Perform additional checks before adding a bitgo key. Base controller
     * is a no-op, but coin-specific controller may do something
     * @param params
     */
    preCreateBitGo(params) {
        return;
    }
    /**
     * @deprecated - use getBip32Keys() in conjunction with isValidAddress instead
     */
    initiateRecovery(params) {
        throw new Error('deprecated method');
    }
    /**
     * Generate a root key pair on the curve used by the coin
     * @param {Buffer} seed - seed to use for key pair generation
     * @returns {KeyPair} the generated key pair
     */
    generateRootKeyPair(seed) {
        throw new account_lib_1.NotImplementedError('generateRootKeyPair is not supported for this coin');
    }
    /**
     * Return wether the given m of n wallet signers/ key amounts are valid for the coin
     */
    isValidMofNSetup({ m, n }) {
        return m === 2 && n === 3;
    }
    /**
     * Returns the portion of the transaction that needs to be signed in Buffer format.
     * Only needed for coins that support adding signatures directly (e.g. TSS).
     *
     * @param {String} serializedTx - the unsigned transaction in broadcast format
     * @returns {Promise<Buffer>} - the portion of the transaction that needs to be signed
     */
    async getSignablePayload(serializedTx) {
        return Buffer.from(serializedTx);
    }
    /**
     * Returns the MPC algorithm (ecdsa or eddsa) used for coins that support TSS
     */
    getMPCAlgorithm() {
        throw new Error('no MPC algorithm is defined for this coin');
    }
    async recoverToken(params) {
        throw new account_lib_1.NotImplementedError('recoverToken is not supported for this coin');
    }
    getInscriptionBuilder(wallet) {
        throw new account_lib_1.NotImplementedError('Inscription Builder is not supported for this coin');
    }
    /**
     * Function to get coin specific hash function used to generate transaction digests.
     * @returns {@see Hash} hash function if implemented, otherwise throws exception
     */
    getHashFunction() {
        throw new account_lib_1.NotImplementedError('getHashFunction is not supported for this coin');
    }
    buildNftTransferData(params) {
        throw new account_lib_1.NotImplementedError('buildNftTransferData is not supported for this coin');
    }
    /**
     * Broadcast a transaction to the network
     * @param params options for broadcasting
     * @returns {Promise<BaseBroadcastTransactionResult>} result of broadcast
     * @throws {NotImplementedError} if not implemented
     */
    broadcastTransaction(params) {
        throw new account_lib_1.NotImplementedError('broadcastTransaction is not supported for this coin');
    }
    /**
     * Creates funds sweep recovery transaction(s) without BitGo
     *
     * @param {MPCSweepRecoveryOptions} params parameters needed to combine the signatures
     * and transactions to create broadcastable transactions
     *
     * @returns {MPCTxs} array of the serialized transaction hex strings and indices
     * of the addresses being swept
     */
    async createBroadcastableSweepTransaction(params) {
        throw new account_lib_1.NotImplementedError('createBroadcastableSweepTransaction is not supported for this coin');
    }
    /**
     * Sets coinspecific fields in intent from input params.
     * This method should be overridden in coin-specific classes
     * to configure these fields in the intent
     * @param intent - intent in which coinspecific fields are to be set
     * @param params
     */
    setCoinSpecificFieldsInIntent(intent, params) {
        return;
    }
    /** @inheritDoc */
    assertIsValidKey(params) {
        let decryptedKey;
        try {
            decryptedKey = sjcl.decrypt(params.walletPassphrase, params.encryptedPrv);
        }
        catch (e) {
            throw new Error(`failed to decrypt prv: ${e.message}`);
        }
        this.auditDecryptedKey({ ...params, prv: decryptedKey });
    }
}
exports.BaseCoin = BaseCoin;
BaseCoin._coinTokenPatternSeparator = ':';
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZUNvaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYml0Z28vYmFzZUNvaW4vYmFzZUNvaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0dBRUc7QUFDSCwrQ0FBaUM7QUFFakMseURBQTJDO0FBQzNDLDhDQUF3QztBQUN4QyxrREFBb0M7QUFDcEMsK0NBQXlDO0FBQ3pDLDRDQUEwRTtBQUcxRSw0Q0FBMkM7QUFDM0MsbURBQXdEO0FBRXhELDhDQUE0QztBQUM1QywwQ0FBb0Q7QUFDcEQsc0NBQW9DO0FBQ3BDLHdEQUFzRDtBQUN0RCxzQ0FBcUQ7QUFDckQsd0NBQXNDO0FBdUN0QyxNQUFzQixRQUFRO0lBWTVCLFlBQXNCLEtBQWdCO1FBQ3BDLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ25DLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxnQkFBTyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLG9CQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksa0JBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLGtDQUFnQixDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEUsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLHdCQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztR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Q0FBQztJQUN0RyxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsNkJBQTZCLENBQUMsTUFBdUIsRUFBRSxNQUE0QztRQUNqRyxPQUFPO0lBQ1QsQ0FBQztJQUVELGtCQUFrQjtJQUNsQixnQkFBZ0IsQ0FBQyxNQUFzQjtRQUNyQyxJQUFJLFlBQW9CLENBQUM7UUFFekIsSUFBSSxDQUFDO1lBQ0gsWUFBWSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUM1RSxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ3pELENBQUM7UUFDRCxJQUFJLENBQUMsaUJBQWlCLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxHQUFHLEVBQUUsWUFBWSxFQUFFLENBQUMsQ0FBQztJQUMzRCxDQUFDOztBQXZrQkgsNEJBaWxCQztBQXhrQjJCLG1DQUEwQixHQUFHLEdBQUcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQHByZXR0aWVyXG4gKi9cbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgKiBhcyB1dHhvbGliIGZyb20gJ0BiaXRnby91dHhvLWxpYic7XG5pbXBvcnQgeyBiaXAzMiB9IGZyb20gJ0BiaXRnby91dHhvLWxpYic7XG5pbXBvcnQgKiBhcyBzamNsIGZyb20gJ0BiaXRnby9zamNsJztcbmltcG9ydCB7IEJpZ051bWJlciB9IGZyb20gJ2JpZ251bWJlci5qcyc7XG5pbXBvcnQgeyBCYXNlQ29pbiBhcyBTdGF0aWNzQmFzZUNvaW4sIENvaW5GZWF0dXJlIH0gZnJvbSAnQGJpdGdvL3N0YXRpY3MnO1xuXG5pbXBvcnQgeyBJbml0aWF0ZVJlY292ZXJ5T3B0aW9ucyB9IGZyb20gJy4uL3JlY292ZXJ5JztcbmltcG9ydCB7IHNpZ25NZXNzYWdlIH0gZnJvbSAnLi4vYmlwMzJ1dGlsJztcbmltcG9ydCB7IE5vdEltcGxlbWVudGVkRXJyb3IgfSBmcm9tICcuLi8uLi9hY2NvdW50LWxpYic7XG5pbXBvcnQgeyBCaXRHb0Jhc2UgfSBmcm9tICcuLi9iaXRnb0Jhc2UnO1xuaW1wb3J0IHsgRW50ZXJwcmlzZXMgfSBmcm9tICcuLi9lbnRlcnByaXNlJztcbmltcG9ydCB7IEtleWNoYWlucywgS2V5SW5kaWNlcyB9IGZyb20gJy4uL2tleWNoYWluJztcbmltcG9ydCB7IE1hcmtldHMgfSBmcm9tICcuLi9tYXJrZXQnO1xuaW1wb3J0IHsgUGVuZGluZ0FwcHJvdmFscyB9IGZyb20gJy4uL3BlbmRpbmdBcHByb3ZhbCc7XG5pbXBvcnQgeyBJV2FsbGV0LCBXYWxsZXQsIFdhbGxldHMgfSBmcm9tICcuLi93YWxsZXQnO1xuaW1wb3J0IHsgV2ViaG9va3MgfSBmcm9tICcuLi93ZWJob29rJztcbmltcG9ydCB7XG4gIEJhc2VCcm9hZGNhc3RUcmFuc2FjdGlvbk9wdGlvbnMsXG4gIEJhc2VCcm9hZGNhc3RUcmFuc2FjdGlvblJlc3VsdCxcbiAgQnVpbGROZnRUcmFuc2ZlckRhdGFPcHRpb25zLFxuICBEZXJpdmVLZXlXaXRoU2VlZE9wdGlvbnMsXG4gIEV4dHJhUHJlYnVpbGRQYXJhbXNPcHRpb25zLFxuICBGZWVFc3RpbWF0ZU9wdGlvbnMsXG4gIElCYXNlQ29pbixcbiAgSVRyYW5zYWN0aW9uRXhwbGFuYXRpb24sXG4gIEtleWNoYWluc1RyaXBsZXQsXG4gIEtleVBhaXIsXG4gIE1QQ0FsZ29yaXRobSxcbiAgTXVsdGlzaWdUeXBlLFxuICBQYXJzZWRUcmFuc2FjdGlvbixcbiAgUGFyc2VUcmFuc2FjdGlvbk9wdGlvbnMsXG4gIFByZWNyZWF0ZUJpdEdvT3B0aW9ucyxcbiAgUHJlc2lnblRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgUmVjb3ZlclRva2VuVHJhbnNhY3Rpb24sXG4gIFJlY292ZXJXYWxsZXRUb2tlbk9wdGlvbnMsXG4gIFNpZ25lZFRyYW5zYWN0aW9uLFxuICBTaWduVHJhbnNhY3Rpb25PcHRpb25zLFxuICBTdXBwbGVtZW50R2VuZXJhdGVXYWxsZXRPcHRpb25zLFxuICBUb2tlbkVuYWJsZW1lbnRDb25maWcsXG4gIFRyYW5zYWN0aW9uUHJlYnVpbGQsXG4gIFZlcmlmeUFkZHJlc3NPcHRpb25zLFxuICBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMsXG4gIEF1ZGl0S2V5UGFyYW1zLFxuICBBdWRpdERlY3J5cHRlZEtleVBhcmFtcyxcbn0gZnJvbSAnLi9pQmFzZUNvaW4nO1xuaW1wb3J0IHsgSUluc2NyaXB0aW9uQnVpbGRlciB9IGZyb20gJy4uL2luc2NyaXB0aW9uQnVpbGRlcic7XG5pbXBvcnQge1xuICBNUENTd2VlcFJlY292ZXJ5T3B0aW9ucyxcbiAgTVBDVHhzLFxuICBQb3B1bGF0ZWRJbnRlbnQsXG4gIFByZWJ1aWxkVHJhbnNhY3Rpb25XaXRoSW50ZW50T3B0aW9ucyxcbiAgVG9rZW5UcmFuc2ZlclJlY2lwaWVudFBhcmFtcyxcbn0gZnJvbSAnLi4vdXRpbHMnO1xuXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQmFzZUNvaW4gaW1wbGVtZW50cyBJQmFzZUNvaW4ge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgYml0Z286IEJpdEdvQmFzZTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF91cmw6IHN0cmluZztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF9lbnRlcnByaXNlczogRW50ZXJwcmlzZXM7XG4gIHByb3RlY3RlZCByZWFkb25seSBfd2FsbGV0czogV2FsbGV0cztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF9rZXljaGFpbnM6IEtleWNoYWlucztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF93ZWJob29rczogV2ViaG9va3M7XG4gIHByb3RlY3RlZCByZWFkb25seSBfcGVuZGluZ0FwcHJvdmFsczogUGVuZGluZ0FwcHJvdmFscztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF9tYXJrZXRzOiBNYXJrZXRzO1xuICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IF9jb2luVG9rZW5QYXR0ZXJuU2VwYXJhdG9yID0gJzonO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgX3N0YXRpY3NDb2luOiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+O1xuXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihiaXRnbzogQml0R29CYXNlKSB7XG4gICAgdGhpcy5iaXRnbyA9IGJpdGdvO1xuICAgIHRoaXMuX3VybCA9IHRoaXMuYml0Z28udXJsKCcvJywgMik7XG4gICAgdGhpcy5fd2FsbGV0cyA9IG5ldyBXYWxsZXRzKHRoaXMuYml0Z28sIHRoaXMpO1xuICAgIHRoaXMuX2tleWNoYWlucyA9IG5ldyBLZXljaGFpbnModGhpcy5iaXRnbywgdGhpcyk7XG4gICAgdGhpcy5fd2ViaG9va3MgPSBuZXcgV2ViaG9va3ModGhpcy5iaXRnbywgdGhpcyk7XG4gICAgdGhpcy5fcGVuZGluZ0FwcHJvdmFscyA9IG5ldyBQZW5kaW5nQXBwcm92YWxzKHRoaXMuYml0Z28sIHRoaXMpO1xuICAgIHRoaXMuX2VudGVycHJpc2VzID0gbmV3IEVudGVycHJpc2VzKHRoaXMuYml0Z28sIHRoaXMpO1xuICAgIHRoaXMuX21hcmtldHMgPSBuZXcgTWFya2V0cyh0aGlzLmJpdGdvLCB0aGlzKTtcbiAgfVxuXG4gIHB1YmxpYyB1cmwoc3VmZml4OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl91cmwgKyB0aGlzLmdldENoYWluKCkgKyBzdWZmaXg7XG4gIH1cblxuICBwdWJsaWMgd2FsbGV0cygpOiBXYWxsZXRzIHtcbiAgICByZXR1cm4gdGhpcy5fd2FsbGV0cztcbiAgfVxuXG4gIHB1YmxpYyBlbnRlcnByaXNlcygpOiBFbnRlcnByaXNlcyB7XG4gICAgcmV0dXJuIHRoaXMuX2VudGVycHJpc2VzO1xuICB9XG5cbiAgcHVibGljIGtleWNoYWlucygpOiBLZXljaGFpbnMge1xuICAgIHJldHVybiB0aGlzLl9rZXljaGFpbnM7XG4gIH1cblxuICBwdWJsaWMgd2ViaG9va3MoKTogV2ViaG9va3Mge1xuICAgIHJldHVybiB0aGlzLl93ZWJob29rcztcbiAgfVxuXG4gIHB1YmxpYyBwZW5kaW5nQXBwcm92YWxzKCk6IFBlbmRpbmdBcHByb3ZhbHMge1xuICAgIHJldHVybiB0aGlzLl9wZW5kaW5nQXBwcm92YWxzO1xuICB9XG5cbiAgcHVibGljIG1hcmtldHMoKTogTWFya2V0cyB7XG4gICAgcmV0dXJuIHRoaXMuX21hcmtldHM7XG4gIH1cblxuICBwdWJsaWMgc3RhdGljIGdldCBjb2luVG9rZW5QYXR0ZXJuU2VwYXJhdG9yKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2NvaW5Ub2tlblBhdHRlcm5TZXBhcmF0b3I7XG4gIH1cblxuICBwdWJsaWMgZ2V0IHR5cGUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRDaGFpbigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIHN0YXRpY3MgY29pbiBvYmplY3RcbiAgICogQHJldHVybnMge1JlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj59IHRoZSBzdGF0aWNzIGNvaW4gb2JqZWN0XG4gICAqL1xuICBnZXRDb25maWcoKTogUmVhZG9ubHk8U3RhdGljc0Jhc2VDb2luPiB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YXRpY3NDb2luO1xuICB9XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIGNoYWluIHdoaWNoIHN1cHBvcnRzIHRoaXMgY29pbiAoZWcsICdidGMnLCAnZXRoJylcbiAgICovXG4gIGFic3RyYWN0IGdldENoYWluKCk6IHN0cmluZztcblxuICAvKipcbiAgICogTmFtZSBvZiB0aGUgY29pbiBmYW1pbHkgKGVnLiBmb3IgdGJ0YywgdGhpcyB3b3VsZCBiZSBidGMpXG4gICAqL1xuICBhYnN0cmFjdCBnZXRGYW1pbHkoKTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBIdW1hbiByZWFkYWJsZSBmdWxsIG5hbWUgZm9yIHRoZSBjb2luXG4gICAqL1xuICBhYnN0cmFjdCBnZXRGdWxsTmFtZSgpOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEZsYWcgZm9yIHNlbmRpbmcgdmFsdWUgb2YgMC5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgb2theSB0byBzZW5kIDAgdmFsdWUsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgdmFsdWVsZXNzVHJhbnNmZXJBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVc2UgYHNlbmRNYW55KClgIHRvIHBlcmZvcm0gd2FsbGV0IHN3ZWVwLlxuICAgKiBGSVhNRShCRy0zOTczOCk6IGFkZCBjb2luLnN3ZWVwV2FsbGV0KCkgaW5zdGVhZFxuICAgKi9cbiAgc3dlZXBXaXRoU2VuZE1hbnkoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgZm9yIHNlbmRpbmcgZGF0YSBhbG9uZyB3aXRoIHRyYW5zYWN0aW9uc1xuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiBva2F5IHRvIHNlbmQgdHggZGF0YSAoRVRIKSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICB0cmFuc2FjdGlvbkRhdGFBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGbGFnIGZvciBkZXRlcm1pbmluZyB3aGV0aGVyIHRoaXMgY29pbiBzdXBwb3J0cyBhY2NvdW50IGNvbnNvbGlkYXRpb25zXG4gICAqIGZyb20gaXRzIHJlY2VpdmUgYWRkcmVzc2VzIHRvIHRoZSByb290IGFkZHJlc3MuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIG9rYXkgdG8gY29uc29saWRhdGUgb3ZlciB0aGlzIGNvaW47IGZhbHNlLCBvdGhlcndpc2VcbiAgICovXG4gIGFsbG93c0FjY291bnRDb25zb2xpZGF0aW9ucygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBjb25maWcgZm9yIGhvdyB0b2tlbiBlbmFibGVtZW50cyB3b3JrIGZvciB0aGlzIGNvaW5cbiAgICogQHJldHVybnNcbiAgICogICAgcmVxdWlyZXNUb2tlbkVuYWJsZW1lbnQ6IFRydWUgaWYgdG9rZW5zIG5lZWQgdG8gYmUgZW5hYmxlZCBmb3IgdGhpcyBjb2luXG4gICAqICAgIHN1cHBvcnRzTXVsdGlwbGVUb2tlbkVuYWJsZW1lbnRzOiBUcnVlIGlmIG11bHRpcGxlIHRva2VucyBjYW4gYmUgZW5hYmxlZCBpbiBvbmUgdHJhbnNhY3Rpb25cbiAgICovXG4gIGdldFRva2VuRW5hYmxlbWVudENvbmZpZygpOiBUb2tlbkVuYWJsZW1lbnRDb25maWcge1xuICAgIHJldHVybiB7XG4gICAgICByZXF1aXJlc1Rva2VuRW5hYmxlbWVudDogZmFsc2UsXG4gICAgICBzdXBwb3J0c011bHRpcGxlVG9rZW5FbmFibGVtZW50czogZmFsc2UsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGbGFnIGluZGljYXRpbmcgaWYgdGhpcyBjb2luIHN1cHBvcnRzIFRTUyB3YWxsZXRzLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiBUU1MgV2FsbGV0cyBjYW4gYmUgY3JlYXRlZCBmb3IgdGhpcyBjb2luXG4gICAqL1xuICBzdXBwb3J0c1RzcygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQgdXNlIENvaW5GZWF0dXJlLk1VTFRJU0lHIGZyb20gc3RhdGljcyBpbnN0ZWFkXG4gICAqIEZsYWcgaW5kaWNhdGluZyBpZiB0aGlzIGNvaW4gc3VwcG9ydHMgTXVsdGlTaWcgd2FsbGV0cy5cbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBNdWx0aVNpZyB3YWxsZXRzIGNhbiBiZSBjcmVhdGVkIGZvciB0aGlzIGNvaW5cbiAgICovXG4gIHN1cHBvcnRzTXVsdGlzaWcoKTogYm9vbGVhbiB7XG4gICAgLy8gVXNlIHRoZSBzdGF0aWMgY29pbiBjb25maWd1cmF0aW9uIHRvIGNoZWNrIGlmIE1VTFRJU0lHIGlzIHN1cHBvcnRlZFxuICAgIHJldHVybiB0aGlzLl9zdGF0aWNzQ29pbi5mZWF0dXJlcy5pbmNsdWRlcyhDb2luRmVhdHVyZS5NVUxUSVNJRyk7XG4gIH1cblxuICAvKipcbiAgICogSXQgd2lsbCByZXR1cm4gdGhlIGRlZmF1bHQgbXVsdGlzaWcgdHlwZSB2YWx1ZSBmb3IgY29pblxuICAgKiBAcmV0dXJuIHtNdWx0aXNpZ1R5cGV9IHJldHVybiAndHNzJyBpZiBjb2luIHN1cHBvcnRzIG9ubHkgVFNTIG5vdCBNdWx0aVNpZ1xuICAgKiBlbHNlIGlmIGNvaW4gc3VwcG9ydHMgTXVsdGlTaWcgcmV0dXJuICdvbmNoYWluJ1xuICAgKiBpZiBjb2luIHN1cHBvcnRzIGJvdGggcmV0dXJuICdvbmNoYWluJ1xuICAgKiBlbHNlIHVuZGVmaW5lZFxuICAgKi9cbiAgZ2V0RGVmYXVsdE11bHRpc2lnVHlwZSgpOiBNdWx0aXNpZ1R5cGUgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogRmxhZyBpbmRpY2F0aW5nIGlmIHRoZSBjb2luIHN1cHBvcnRzIGRlcml2aW5nIGEga2V5IHdpdGggYSBzZWVkIChrZXlJRClcbiAgICogdG8gdGhlIHVzZXIvYmFja3VwIGtleXMuXG4gICAqL1xuICBzdXBwb3J0c0Rlcml2ZUtleVdpdGhTZWVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgaW5kaWNhdGluZyBpZiB0aGlzIGJsb2NrY2hhaW4gcnVucyBvbiBFVk0gYXJjaGl0ZWN0dXJlLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgYmxvY2tjaGFpbiBydW5zIG9uIEVWTSBhcmNoaXRlY3R1cmUuXG4gICAqL1xuICBpc0VWTSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogRmxhZyBpbmRpY2F0aW5nIGlmIHRoaXMgY29pbiBzdXBwb3J0cyBCTFMtREtHIHdhbGxldHMuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIEJMUy1ES0cgV2FsbGV0cyBjYW4gYmUgY3JlYXRlZCBmb3IgdGhpcyBjb2luXG4gICAqL1xuICBzdXBwb3J0c0Jsc0RrZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgZmFjdG9yIGJldHdlZW4gdGhlIGJhc2UgdW5pdCBhbmQgaXRzIHNtYWxsZXN0IHN1YmRpdmlzb25cbiAgICogQHJldHVybiB7bnVtYmVyfVxuICAgKi9cbiAgYWJzdHJhY3QgZ2V0QmFzZUZhY3RvcigpOiBudW1iZXIgfCBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBjdXJyZW5jeSBhbW91bnQgcmVwcmVzZW50ZWQgaW4gYmFzZSB1bml0cyAoc2F0b3NoaSwgd2VpLCBhdG9tcywgZHJvcHMsIHN0cm9vcHMpXG4gICAqIHRvIGJpZyB1bml0cyAoYnRjLCBldGgsIHhycCwgeGxtKVxuICAgKi9cbiAgYmFzZVVuaXRzVG9CaWdVbml0cyhiYXNlVW5pdHM6IHN0cmluZyB8IG51bWJlcik6IHN0cmluZyB7XG4gICAgQmlnTnVtYmVyLnNldCh7IERFQ0lNQUxfUExBQ0VTOiAyNCB9KTtcbiAgICBjb25zdCBkaXZpZGVuZCA9IHRoaXMuZ2V0QmFzZUZhY3RvcigpO1xuICAgIGNvbnN0IGJpZ051bWJlciA9IG5ldyBCaWdOdW1iZXIoYmFzZVVuaXRzKS5kaXZpZGVkQnkoZGl2aWRlbmQpO1xuICAgIC8vIHNldCB0aGUgZm9ybWF0IHNvIGNvbW1hcyBhcmVuJ3QgYWRkZWQgdG8gbGFyZ2UgY29pbiBhbW91bnRzXG4gICAgcmV0dXJuIGJpZ051bWJlci50b0Zvcm1hdChudWxsIGFzIGFueSwgbnVsbCBhcyBhbnksIHsgZ3JvdXBTZXBhcmF0b3I6ICcnLCBkZWNpbWFsU2VwYXJhdG9yOiAnLicgfSk7XG4gIH1cblxuICBjaGVja1JlY2lwaWVudChyZWNpcGllbnQ6IHsgYWRkcmVzczogc3RyaW5nOyBhbW91bnQ6IHN0cmluZyB8IG51bWJlciB9KTogdm9pZCB7XG4gICAgaWYgKHJlY2lwaWVudC5hbW91bnQgIT09ICdtYXgnKSB7XG4gICAgICBjb25zdCBhbW91bnQgPSBuZXcgQmlnTnVtYmVyKHJlY2lwaWVudC5hbW91bnQpO1xuICAgICAgaWYgKGFtb3VudC5pc05lZ2F0aXZlKCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGFyZ3VtZW50IGZvciBhbW91bnQgLSBwb3NpdGl2ZSBudW1iZXIgZ3JlYXRlciB0aGFuIHplcm8gb3IgbnVtZXJpYyBzdHJpbmcgZXhwZWN0ZWQnKTtcbiAgICAgIH1cbiAgICAgIGlmICghdGhpcy52YWx1ZWxlc3NUcmFuc2ZlckFsbG93ZWQoKSAmJiBhbW91bnQuaXNaZXJvKCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGFyZ3VtZW50IGZvciBhbW91bnQgLSBwb3NpdGl2ZSBudW1iZXIgZ3JlYXRlciB0aGFuIHplcm8gb3IgbnVtZXJpYyBzdHJpbmcgZXhwZWN0ZWQnKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCBhIGN1cnJlbmN5IGFtb3VudCByZXByZXNlbnRlZCBpbiBiaWcgdW5pdHMgKGJ0YywgZXRoLCB4cnAsIHhsbSlcbiAgICogdG8gYmFzZSB1bml0cyAoc2F0b3NoaSwgd2VpLCBhdG9tcywgZHJvcHMsIHN0cm9vcHMpXG4gICAqIEBwYXJhbSBiaWdVbml0c1xuICAgKi9cbiAgYmlnVW5pdHNUb0Jhc2VVbml0cyhiaWdVbml0czogc3RyaW5nIHwgbnVtYmVyKTogc3RyaW5nIHtcbiAgICBjb25zdCBtdWx0aXBsaWVyID0gdGhpcy5nZXRCYXNlRmFjdG9yKCk7XG4gICAgY29uc3QgYmlnTnVtYmVyID0gbmV3IEJpZ051bWJlcihiaWdVbml0cykudGltZXMobXVsdGlwbGllcik7XG4gICAgaWYgKCFiaWdOdW1iZXIuaXNJbnRlZ2VyKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgbm9uLWludGVnZXIgb3V0cHV0IHJlc3VsdGVkIGZyb20gbXVsdGlwbHlpbmcgJHtiaWdVbml0c30gYnkgJHttdWx0aXBsaWVyfWApO1xuICAgIH1cbiAgICByZXR1cm4gYmlnTnVtYmVyLnRvRml4ZWQoMCk7XG4gIH1cblxuICAvKipcbiAgICogUHJlcHJvY2VzcyB0aGUgYnVpbGQgcGFyYW1ldGVycyBiZWZvcmUgc2VuZGluZyB0byB0aGUgQVBJXG4gICAqIEBwYXJhbSBidWlsZFBhcmFtc1xuICAgKi9cbiAgcHJlcHJvY2Vzc0J1aWxkUGFyYW1zKGJ1aWxkUGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgcmV0dXJuIGJ1aWxkUGFyYW1zO1xuICB9XG5cbiAgLyoqXG4gICAqIFNpZ24gbWVzc2FnZSB3aXRoIHByaXZhdGUga2V5XG4gICAqXG4gICAqIEBwYXJhbSBrZXlcbiAgICogQHBhcmFtIG1lc3NhZ2VcbiAgICovXG4gIGFzeW5jIHNpZ25NZXNzYWdlKGtleTogeyBwcnY6IHN0cmluZyB9LCBtZXNzYWdlOiBzdHJpbmcpOiBQcm9taXNlPEJ1ZmZlcj4ge1xuICAgIHJldHVybiBzaWduTWVzc2FnZShtZXNzYWdlLCBiaXAzMi5mcm9tQmFzZTU4KGtleS5wcnYpLCB1dHhvbGliLm5ldHdvcmtzLmJpdGNvaW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBzaWduYXR1cmVzIGZvciB0aGUgYmFja3VwIGFuZCBiaXRnbyBrZXlzIHVzaW5nIHRoZSB1c2VyIGtleS5cbiAgICogV2UgY2FuIHZlcmlmeSB0aGUgc2lnbmF0dXJlcyB3aGVuIGZldGNoaW5nIHRoZSBrZXlzIGZyb20gd2FsbGV0LXBsYXRmb3JtIGxhdGVyLlxuICAgKiBDdXJyZW50bHkgb25seSBgQWJzdHJhY3RVdHhvQ29pbmAgaW1wbGVtZW50cyBhbmQgdXNlcyB0aGUgY29tcGxlbWVudGFyeSBgdmVyaWZ5S2V5U2lnbmF0dXJlYCBtZXRob2QuXG4gICAqIEBwYXJhbSBwcnYgLSB0aGUgdXNlciBwcml2YXRlIGtleVxuICAgKiBAcGFyYW0gYmFja3VwS2V5Y2hhaW4gLSBjb250YWlucyB0aGUgYmFja3VwIHB1YmxpYyBrZXlcbiAgICogQHBhcmFtIGJpdGdvS2V5Y2hhaW4gLSBjb250YWlucyB0aGUgYml0Z28gcHVibGljIGtleVxuICAgKi9cbiAgcHVibGljIGFzeW5jIGNyZWF0ZUtleVNpZ25hdHVyZXMoXG4gICAgcHJ2OiBzdHJpbmcsXG4gICAgYmFja3VwS2V5Y2hhaW46IHsgcHViOiBzdHJpbmcgfSxcbiAgICBiaXRnb0tleWNoYWluOiB7IHB1Yjogc3RyaW5nIH1cbiAgKTogUHJvbWlzZTx7XG4gICAgYmFja3VwOiBzdHJpbmc7XG4gICAgYml0Z286IHN0cmluZztcbiAgfT4ge1xuICAgIHJldHVybiB7XG4gICAgICBiYWNrdXA6IChhd2FpdCB0aGlzLnNpZ25NZXNzYWdlKHsgcHJ2IH0sIGJhY2t1cEtleWNoYWluLnB1YikpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgIGJpdGdvOiAoYXdhaXQgdGhpcy5zaWduTWVzc2FnZSh7IHBydiB9LCBiaXRnb0tleWNoYWluLnB1YikpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29tcG9zZSBhIHJhdyB0cmFuc2FjdGlvbiBpbnRvIHVzZWZ1bCBpbmZvcm1hdGlvbi5cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBjb2luLXNwZWNpZmljXG4gICAqL1xuICBleHBsYWluVHJhbnNhY3Rpb24ob3B0aW9uczogUmVjb3JkPHN0cmluZywgYW55Pik6IFByb21pc2U8SVRyYW5zYWN0aW9uRXhwbGFuYXRpb248YW55LCBzdHJpbmcgfCBudW1iZXI+IHwgdW5kZWZpbmVkPiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBub3QgaW1wbGVtZW50ZWRgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgdGhhdCBhIHRyYW5zYWN0aW9uIHByZWJ1aWxkIGNvbXBsaWVzIHdpdGggdGhlIG9yaWdpbmFsIGludGVudGlvblxuICAgKi9cbiAgYWJzdHJhY3QgdmVyaWZ5VHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+O1xuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB1c2Uge0BzZWUgaXNXYWxsZXRBZGRyZXNzfSBpbnN0ZWFkXG4gICAqL1xuICB2ZXJpZnlBZGRyZXNzKHBhcmFtczogVmVyaWZ5QWRkcmVzc09wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5pc1dhbGxldEFkZHJlc3MocGFyYW1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEByZXR1cm4gdHJ1ZSBpZmYgYWRkcmVzcyBpcyBhIHdhbGxldCBhZGRyZXNzLiBNdXN0IHJldHVybiBmYWxzZSBpZiBhZGRyZXNzIGlzIG91dHNpZGUgd2FsbGV0LlxuICAgKi9cbiAgYWJzdHJhY3QgaXNXYWxsZXRBZGRyZXNzKHBhcmFtczogVmVyaWZ5QWRkcmVzc09wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+O1xuXG4gIC8qKlxuICAgKiBjb252ZXJ0IGFkZHJlc3MgaW50byBkZXNpcmVkIGFkZHJlc3MgZm9ybWF0LlxuICAgKiBAcGFyYW0gYWRkcmVzc1xuICAgKiBAcGFyYW0gZm9ybWF0XG4gICAqL1xuICBjYW5vbmljYWxBZGRyZXNzKGFkZHJlc3M6IHN0cmluZywgZm9ybWF0PzogdW5rbm93bik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGFkZHJlc3M7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciBhIGNvaW4gc3VwcG9ydHMgYmxvY2tUYXJnZXQgZm9yIHRyYW5zYWN0aW9ucyB0byBiZSBpbmNsdWRlZCBpblxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAgICovXG4gIHN1cHBvcnRzQmxvY2tUYXJnZXQoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIHdoZXRoZXIgYSBjb2luIHN1cHBvcnRzIGxpZ2h0bmluZyB0cmFuc2FjdGlvbnNcbiAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAqL1xuICBzdXBwb3J0c0xpZ2h0bmluZygpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciBhIGNvaW4gc3VwcG9ydHMgbWVzc2FnZSBzaWduaW5nXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgc3VwcG9ydHNNZXNzYWdlU2lnbmluZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciBhIGNvaW4gc3VwcG9ydHMgc2lnbmluZyBvZiBUeXBlZCBkYXRhXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgc3VwcG9ydHNTaWduaW5nVHlwZWREYXRhKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIb29rIHRvIGFkZCBhZGRpdGlvbmFsIHBhcmFtZXRlcnMgdG8gdGhlIHdhbGxldCBnZW5lcmF0aW9uXG4gICAqIEBwYXJhbSB3YWxsZXRQYXJhbXNcbiAgICogQHBhcmFtIGtleWNoYWluc1xuICAgKiBAcmV0dXJuIHsqfVxuICAgKi9cbiAgc3VwcGxlbWVudEdlbmVyYXRlV2FsbGV0KHdhbGxldFBhcmFtczogU3VwcGxlbWVudEdlbmVyYXRlV2FsbGV0T3B0aW9ucywga2V5Y2hhaW5zOiBLZXljaGFpbnNUcmlwbGV0KTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHdhbGxldFBhcmFtcyk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGV4dHJhIHBhcmFtZXRlcnMgZm9yIHByZWJ1aWxkaW5nIGEgdHguIEFkZCB0aGluZ3MgbGlrZSBob3AgdHJhbnNhY3Rpb24gcGFyYW1zXG4gICAqL1xuICBnZXRFeHRyYVByZWJ1aWxkUGFyYW1zKGJ1aWxkUGFyYW1zOiBFeHRyYVByZWJ1aWxkUGFyYW1zT3B0aW9ucyk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb2RpZnkgcHJlYnVpbGQgYWZ0ZXIgcmVjZWl2aW5nIGl0IGZyb20gdGhlIHNlcnZlci4gQWRkIHRoaW5ncyBsaWtlIG5sb2NrdGltZVxuICAgKi9cbiAgcG9zdFByb2Nlc3NQcmVidWlsZChwcmVidWlsZFJlc3BvbnNlOiBUcmFuc2FjdGlvblByZWJ1aWxkKTogUHJvbWlzZTxUcmFuc2FjdGlvblByZWJ1aWxkPiB7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShwcmVidWlsZFJlc3BvbnNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb2luLXNwZWNpZmljIHRoaW5ncyBkb25lIGJlZm9yZSBzaWduaW5nIGEgdHJhbnNhY3Rpb24sIGkuZS4gdmVyaWZpY2F0aW9uXG4gICAqL1xuICBwcmVzaWduVHJhbnNhY3Rpb24ocGFyYW1zOiBQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zPiB7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShwYXJhbXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyB3YWxsZXQgb2JqZWN0IGZyb20gYSB3YWxsZXQgZGF0YSBvYmplY3RcbiAgICogQHBhcmFtIHdhbGxldFBhcmFtc1xuICAgKi9cbiAgbmV3V2FsbGV0T2JqZWN0KHdhbGxldFBhcmFtczogYW55KTogSVdhbGxldCB7XG4gICAgcmV0dXJuIG5ldyBXYWxsZXQodGhpcy5iaXRnbywgdGhpcywgd2FsbGV0UGFyYW1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaCBmZWUgZXN0aW1hdGUgaW5mb3JtYXRpb24gZnJvbSB0aGUgc2VydmVyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXMgVGhlIHBhcmFtcyBwYXNzZWQgaW50byB0aGUgZnVuY3Rpb25cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBwYXJhbXMubnVtQmxvY2tzIFRoZSBudW1iZXIgb2YgYmxvY2tzIHRvIHRhcmdldCBmb3IgY29uZm9ybWF0aW9uIChPbmx5IHdvcmtzIGZvciBidGMpXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBpbmZvIHJldHVybmVkIGZyb20gdGhlIG1lcmNoYW50IHNlcnZlclxuICAgKi9cbiAgYXN5bmMgZmVlRXN0aW1hdGUocGFyYW1zOiBGZWVFc3RpbWF0ZU9wdGlvbnMpOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHF1ZXJ5OiBhbnkgPSB7fTtcbiAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5udW1CbG9ja3MpIHtcbiAgICAgIHF1ZXJ5Lm51bUJsb2NrcyA9IHBhcmFtcy5udW1CbG9ja3M7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuYml0Z28uZ2V0KHRoaXMudXJsKCcvdHgvZmVlJykpLnF1ZXJ5KHF1ZXJ5KS5yZXN1bHQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY29sZCB3YWxsZXQgdG9vbCB1c2VzIHRoaXMgZnVuY3Rpb24gdG8gZGVyaXZlIGFuIGV4dGVuZGVkIGtleSB0aGF0IGlzIGJhc2VkIG9uIHRoZSBwYXNzZWQga2V5IGFuZCBzZWVkXG4gICAqIEBwYXJhbSBrZXlcbiAgICogQHBhcmFtIHNlZWRcbiAgICogQHJldHVybnMge3trZXk6IHN0cmluZywgZGVyaXZhdGlvblBhdGg6IHN0cmluZ319XG4gICAqL1xuICBzdGF0aWMgZGVyaXZlS2V5V2l0aFNlZWRCaXAzMihcbiAgICBrZXk6IHV0eG9saWIuQklQMzJJbnRlcmZhY2UsXG4gICAgc2VlZDogc3RyaW5nXG4gICk6IHtcbiAgICBrZXk6IHV0eG9saWIuQklQMzJJbnRlcmZhY2U7XG4gICAgZGVyaXZhdGlvblBhdGg6IHN0cmluZztcbiAgfSB7XG4gICAgZnVuY3Rpb24gc2hhMjU2KGlucHV0KSB7XG4gICAgICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShpbnB1dCkuZGlnZXN0KCk7XG4gICAgfVxuICAgIGNvbnN0IGRlcml2YXRpb25QYXRoSW5wdXQgPSBzaGEyNTYoc2hhMjU2KGAke3NlZWR9YCkpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICBjb25zdCBkZXJpdmF0aW9uUGF0aFBhcnRzID0gW1xuICAgICAgcGFyc2VJbnQoZGVyaXZhdGlvblBhdGhJbnB1dC5zbGljZSgwLCA3KSwgMTYpLFxuICAgICAgcGFyc2VJbnQoZGVyaXZhdGlvblBhdGhJbnB1dC5zbGljZSg3LCAxNCksIDE2KSxcbiAgICBdO1xuICAgIGNvbnN0IGRlcml2YXRpb25QYXRoID0gJ20vOTk5OTk5LycgKyBkZXJpdmF0aW9uUGF0aFBhcnRzLmpvaW4oJy8nKTtcbiAgICByZXR1cm4ge1xuICAgICAga2V5OiBrZXkuZGVyaXZlUGF0aChkZXJpdmF0aW9uUGF0aCksXG4gICAgICBkZXJpdmF0aW9uUGF0aCxcbiAgICB9O1xuICB9XG5cbiAgLyoqIHtAc2VlIGRlcml2ZUtleVdpdGhTZWVkQmlwMzJ9ICovXG4gIGRlcml2ZUtleVdpdGhTZWVkKHBhcmFtczogRGVyaXZlS2V5V2l0aFNlZWRPcHRpb25zKToge1xuICAgIGtleTogc3RyaW5nO1xuICAgIGRlcml2YXRpb25QYXRoOiBzdHJpbmc7XG4gIH0ge1xuICAgIGNvbnN0IHsga2V5LCBkZXJpdmF0aW9uUGF0aCB9ID0gQmFzZUNvaW4uZGVyaXZlS2V5V2l0aFNlZWRCaXAzMihiaXAzMi5mcm9tQmFzZTU4KHBhcmFtcy5rZXkpLCBwYXJhbXMuc2VlZCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGtleToga2V5LnRvQmFzZTU4KCksXG4gICAgICBkZXJpdmF0aW9uUGF0aCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNwZWNpZmllcyB3aGF0IGtleSB3ZSB3aWxsIG5lZWQgZm9yIHNpZ25pbmcgLSByaWdodCBub3cgd2UganVzdCBuZWVkIHRoZVxuICAgKiB1c2VyIGtleS5cbiAgICovXG4gIGtleUlkc0ZvclNpZ25pbmcoKTogbnVtYmVyW10ge1xuICAgIHJldHVybiBbS2V5SW5kaWNlcy5VU0VSXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtIGFkZGl0aW9uYWwgY2hlY2tzIGJlZm9yZSBhZGRpbmcgYSBiaXRnbyBrZXkuIEJhc2UgY29udHJvbGxlclxuICAgKiBpcyBhIG5vLW9wLCBidXQgY29pbi1zcGVjaWZpYyBjb250cm9sbGVyIG1heSBkbyBzb21ldGhpbmdcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgcHJlQ3JlYXRlQml0R28ocGFyYW1zOiBQcmVjcmVhdGVCaXRHb09wdGlvbnMpOiB2b2lkIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQgLSB1c2UgZ2V0QmlwMzJLZXlzKCkgaW4gY29uanVuY3Rpb24gd2l0aCBpc1ZhbGlkQWRkcmVzcyBpbnN0ZWFkXG4gICAqL1xuICBpbml0aWF0ZVJlY292ZXJ5KHBhcmFtczogSW5pdGlhdGVSZWNvdmVyeU9wdGlvbnMpOiBuZXZlciB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdkZXByZWNhdGVkIG1ldGhvZCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9ubHkgdXNlZCBpbiBQZW5kaW5nQXBwcm92YWwgZm9yIGNvbXBhcmluZyBQQVlHbyBmZWVzIHB1cnBvc2VcbiAgICogQHBhcmFtIHBhcmFtcyBvcHRpb25zIGZvciBwYXJzaW5nXG4gICAqL1xuICBhYnN0cmFjdCBwYXJzZVRyYW5zYWN0aW9uKHBhcmFtczogUGFyc2VUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPFBhcnNlZFRyYW5zYWN0aW9uPjtcblxuICAvKipcbiAgICogR2VuZXJhdGUgYSBrZXkgcGFpciBvbiB0aGUgY3VydmUgdXNlZCBieSB0aGUgY29pblxuICAgKiBAcGFyYW0ge0J1ZmZlcn0gc2VlZCAtIHNlZWQgdG8gdXNlIGZvciBrZXkgcGFpciBnZW5lcmF0aW9uXG4gICAqIEByZXR1cm5zIHtLZXlQYWlyfSB0aGUgZ2VuZXJhdGVkIGtleSBwYWlyXG4gICAqL1xuICBhYnN0cmFjdCBnZW5lcmF0ZUtleVBhaXIoc2VlZD86IEJ1ZmZlcik6IEtleVBhaXI7XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgcm9vdCBrZXkgcGFpciBvbiB0aGUgY3VydmUgdXNlZCBieSB0aGUgY29pblxuICAgKiBAcGFyYW0ge0J1ZmZlcn0gc2VlZCAtIHNlZWQgdG8gdXNlIGZvciBrZXkgcGFpciBnZW5lcmF0aW9uXG4gICAqIEByZXR1cm5zIHtLZXlQYWlyfSB0aGUgZ2VuZXJhdGVkIGtleSBwYWlyXG4gICAqL1xuICBnZW5lcmF0ZVJvb3RLZXlQYWlyKHNlZWQ/OiBCdWZmZXIpOiBLZXlQYWlyIHtcbiAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcignZ2VuZXJhdGVSb290S2V5UGFpciBpcyBub3Qgc3VwcG9ydGVkIGZvciB0aGlzIGNvaW4nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgaW5wdXQgaXMgdmFsaWQgcHVibGljIGtleSBmb3IgdGhlIGNvaW4uXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwdWIgdGhlIHB1YiB0byBiZSBjaGVja2VkXG4gICAqIEByZXR1cm5zIHtCb29sZWFufSBpcyBpdCB2YWxpZD9cbiAgICovXG4gIGFic3RyYWN0IGlzVmFsaWRQdWIocHViOiBzdHJpbmcpOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBSZXR1cm4gd2V0aGVyIHRoZSBnaXZlbiBtIG9mIG4gd2FsbGV0IHNpZ25lcnMvIGtleSBhbW91bnRzIGFyZSB2YWxpZCBmb3IgdGhlIGNvaW5cbiAgICovXG4gIGlzVmFsaWRNb2ZOU2V0dXAoeyBtLCBuIH06IHsgbT86IG51bWJlcjsgbj86IG51bWJlciB9KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG0gPT09IDIgJiYgbiA9PT0gMztcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBgYWRkcmVzc2AgaXMgYSBwbGF1c2libHkgdmFsaWQgYWRkcmVzcyBmb3IgdGhlIGdpdmVuIGNvaW4uXG4gICAqXG4gICAqIERvZXMgbm90IHZlcmlmeSB0aGF0IHRoZSBhZGRyZXNzIGJlbG9uZ3MgdG8gYSB3YWxsZXQuIEZvciB0aGF0LFxuICAgKiB1c2UgW1t2ZXJpZnlBZGRyZXNzXV1cbiAgICogQHBhcmFtIGFkZHJlc3NcbiAgICovXG4gIGFic3RyYWN0IGlzVmFsaWRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZyk6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFNpZ24gYSB0cmFuc2FjdGlvblxuICAgKi9cbiAgYWJzdHJhY3Qgc2lnblRyYW5zYWN0aW9uKHBhcmFtczogU2lnblRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8U2lnbmVkVHJhbnNhY3Rpb24+O1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBwb3J0aW9uIG9mIHRoZSB0cmFuc2FjdGlvbiB0aGF0IG5lZWRzIHRvIGJlIHNpZ25lZCBpbiBCdWZmZXIgZm9ybWF0LlxuICAgKiBPbmx5IG5lZWRlZCBmb3IgY29pbnMgdGhhdCBzdXBwb3J0IGFkZGluZyBzaWduYXR1cmVzIGRpcmVjdGx5IChlLmcuIFRTUykuXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzZXJpYWxpemVkVHggLSB0aGUgdW5zaWduZWQgdHJhbnNhY3Rpb24gaW4gYnJvYWRjYXN0IGZvcm1hdFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSAtIHRoZSBwb3J0aW9uIG9mIHRoZSB0cmFuc2FjdGlvbiB0aGF0IG5lZWRzIHRvIGJlIHNpZ25lZFxuICAgKi9cbiAgYXN5bmMgZ2V0U2lnbmFibGVQYXlsb2FkKHNlcmlhbGl6ZWRUeDogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oc2VyaWFsaXplZFR4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBNUEMgYWxnb3JpdGhtIChlY2RzYSBvciBlZGRzYSkgdXNlZCBmb3IgY29pbnMgdGhhdCBzdXBwb3J0IFRTU1xuICAgKi9cbiAgZ2V0TVBDQWxnb3JpdGhtKCk6IE1QQ0FsZ29yaXRobSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdubyBNUEMgYWxnb3JpdGhtIGlzIGRlZmluZWQgZm9yIHRoaXMgY29pbicpO1xuICB9XG5cbiAgYXN5bmMgcmVjb3ZlclRva2VuKHBhcmFtczogUmVjb3ZlcldhbGxldFRva2VuT3B0aW9ucyk6IFByb21pc2U8UmVjb3ZlclRva2VuVHJhbnNhY3Rpb24+IHtcbiAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcigncmVjb3ZlclRva2VuIGlzIG5vdCBzdXBwb3J0ZWQgZm9yIHRoaXMgY29pbicpO1xuICB9XG5cbiAgZ2V0SW5zY3JpcHRpb25CdWlsZGVyKHdhbGxldDogV2FsbGV0KTogSUluc2NyaXB0aW9uQnVpbGRlciB7XG4gICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoJ0luc2NyaXB0aW9uIEJ1aWxkZXIgaXMgbm90IHN1cHBvcnRlZCBmb3IgdGhpcyBjb2luJyk7XG4gIH1cblxuICAvKipcbiAgICogRnVuY3Rpb24gdG8gZ2V0IGNvaW4gc3BlY2lmaWMgaGFzaCBmdW5jdGlvbiB1c2VkIHRvIGdlbmVyYXRlIHRyYW5zYWN0aW9uIGRpZ2VzdHMuXG4gICAqIEByZXR1cm5zIHtAc2VlIEhhc2h9IGhhc2ggZnVuY3Rpb24gaWYgaW1wbGVtZW50ZWQsIG90aGVyd2lzZSB0aHJvd3MgZXhjZXB0aW9uXG4gICAqL1xuICBnZXRIYXNoRnVuY3Rpb24oKTogSGFzaCB7XG4gICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoJ2dldEhhc2hGdW5jdGlvbiBpcyBub3Qgc3VwcG9ydGVkIGZvciB0aGlzIGNvaW4nKTtcbiAgfVxuXG4gIGJ1aWxkTmZ0VHJhbnNmZXJEYXRhKHBhcmFtczogQnVpbGROZnRUcmFuc2ZlckRhdGFPcHRpb25zKTogc3RyaW5nIHwgVG9rZW5UcmFuc2ZlclJlY2lwaWVudFBhcmFtcyB7XG4gICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoJ2J1aWxkTmZ0VHJhbnNmZXJEYXRhIGlzIG5vdCBzdXBwb3J0ZWQgZm9yIHRoaXMgY29pbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJyb2FkY2FzdCBhIHRyYW5zYWN0aW9uIHRvIHRoZSBuZXR3b3JrXG4gICAqIEBwYXJhbSBwYXJhbXMgb3B0aW9ucyBmb3IgYnJvYWRjYXN0aW5nXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEJhc2VCcm9hZGNhc3RUcmFuc2FjdGlvblJlc3VsdD59IHJlc3VsdCBvZiBicm9hZGNhc3RcbiAgICogQHRocm93cyB7Tm90SW1wbGVtZW50ZWRFcnJvcn0gaWYgbm90IGltcGxlbWVudGVkXG4gICAqL1xuICBicm9hZGNhc3RUcmFuc2FjdGlvbihwYXJhbXM6IEJhc2VCcm9hZGNhc3RUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPEJhc2VCcm9hZGNhc3RUcmFuc2FjdGlvblJlc3VsdD4ge1xuICAgIHRocm93IG5ldyBOb3RJbXBsZW1lbnRlZEVycm9yKCdicm9hZGNhc3RUcmFuc2FjdGlvbiBpcyBub3Qgc3VwcG9ydGVkIGZvciB0aGlzIGNvaW4nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGZ1bmRzIHN3ZWVwIHJlY292ZXJ5IHRyYW5zYWN0aW9uKHMpIHdpdGhvdXQgQml0R29cbiAgICpcbiAgICogQHBhcmFtIHtNUENTd2VlcFJlY292ZXJ5T3B0aW9uc30gcGFyYW1zIHBhcmFtZXRlcnMgbmVlZGVkIHRvIGNvbWJpbmUgdGhlIHNpZ25hdHVyZXNcbiAgICogYW5kIHRyYW5zYWN0aW9ucyB0byBjcmVhdGUgYnJvYWRjYXN0YWJsZSB0cmFuc2FjdGlvbnNcbiAgICpcbiAgICogQHJldHVybnMge01QQ1R4c30gYXJyYXkgb2YgdGhlIHNlcmlhbGl6ZWQgdHJhbnNhY3Rpb24gaGV4IHN0cmluZ3MgYW5kIGluZGljZXNcbiAgICogb2YgdGhlIGFkZHJlc3NlcyBiZWluZyBzd2VwdFxuICAgKi9cbiAgYXN5bmMgY3JlYXRlQnJvYWRjYXN0YWJsZVN3ZWVwVHJhbnNhY3Rpb24ocGFyYW1zOiBNUENTd2VlcFJlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8TVBDVHhzPiB7XG4gICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoJ2NyZWF0ZUJyb2FkY2FzdGFibGVTd2VlcFRyYW5zYWN0aW9uIGlzIG5vdCBzdXBwb3J0ZWQgZm9yIHRoaXMgY29pbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgY29pbnNwZWNpZmljIGZpZWxkcyBpbiBpbnRlbnQgZnJvbSBpbnB1dCBwYXJhbXMuXG4gICAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBvdmVycmlkZGVuIGluIGNvaW4tc3BlY2lmaWMgY2xhc3Nlc1xuICAgKiB0byBjb25maWd1cmUgdGhlc2UgZmllbGRzIGluIHRoZSBpbnRlbnRcbiAgICogQHBhcmFtIGludGVudCAtIGludGVudCBpbiB3aGljaCBjb2luc3BlY2lmaWMgZmllbGRzIGFyZSB0byBiZSBzZXRcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgc2V0Q29pblNwZWNpZmljRmllbGRzSW5JbnRlbnQoaW50ZW50OiBQb3B1bGF0ZWRJbnRlbnQsIHBhcmFtczogUHJlYnVpbGRUcmFuc2FjdGlvbldpdGhJbnRlbnRPcHRpb25zKTogdm9pZCB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICovXG4gIGFzc2VydElzVmFsaWRLZXkocGFyYW1zOiBBdWRpdEtleVBhcmFtcyk6IHZvaWQge1xuICAgIGxldCBkZWNyeXB0ZWRLZXk6IHN0cmluZztcblxuICAgIHRyeSB7XG4gICAgICBkZWNyeXB0ZWRLZXkgPSBzamNsLmRlY3J5cHQocGFyYW1zLndhbGxldFBhc3NwaHJhc2UsIHBhcmFtcy5lbmNyeXB0ZWRQcnYpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgZmFpbGVkIHRvIGRlY3J5cHQgcHJ2OiAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gICAgdGhpcy5hdWRpdERlY3J5cHRlZEtleSh7IC4uLnBhcmFtcywgcHJ2OiBkZWNyeXB0ZWRLZXkgfSk7XG4gIH1cblxuICAvKipcbiAgICogQXVkaXQgaWYgYSBkZWNyeXB0ZWQga2V5IGlzIHZhbGlkLlxuICAgKiBAcGFyYW0ge0F1ZGl0RGVjcnlwdGVkS2V5UGFyYW1zfSBwYXJhbXMgLSBwYXJhbWV0ZXJzIGZvciBhdWRpdGluZyB0aGUgZGVjcnlwdGVkIGtleVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnBydiAtIHRoZSBkZWNyeXB0ZWQgcHJpdmF0ZSBrZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5wdWJsaWNLZXkgLSB0aGUgcHVibGljIGtleSwgb3IgY29tbW9uIGtleWNoYWluXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMubXVsdGlTaWdUeXBlIC0gdGhlIG11bHRpLXNpZyB0eXBlLCBpZiBhcHBsaWNhYmxlXG4gICAqL1xuICBhYnN0cmFjdCBhdWRpdERlY3J5cHRlZEtleShwYXJhbXM6IEF1ZGl0RGVjcnlwdGVkS2V5UGFyYW1zKTogdm9pZDtcbn1cbiJdfQ==

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


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