PHP WebShell

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

Просмотр файла: icp.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.Icp = void 0;
const assert_1 = __importDefault(require("assert"));
const sdk_core_1 = require("@bitgo/sdk-core");
const statics_1 = require("@bitgo/statics");
const principal_1 = require("@dfinity/principal");
const axios_1 = __importDefault(require("axios"));
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const crypto_1 = require("crypto");
const request = __importStar(require("superagent"));
const iface_1 = require("./lib/iface");
const transactionBuilderFactory_1 = require("./lib/transactionBuilderFactory");
const utils_1 = __importDefault(require("./lib/utils"));
/**
 * Class representing the Internet Computer (ICP) coin.
 * Extends the BaseCoin class and provides specific implementations for ICP.
 *
 * @see {@link https://internetcomputer.org/}
 * @see {@link https://internetcomputer.org/docs/current/developer-docs/defi/rosetta/icp_rosetta/data_api/}
 */
class Icp extends sdk_core_1.BaseCoin {
    constructor(bitgo, staticsCoin) {
        super(bitgo);
        if (!staticsCoin) {
            throw new Error('missing required constructor parameter staticsCoin');
        }
        this._staticsCoin = staticsCoin;
    }
    static createInstance(bitgo, staticsCoin) {
        return new Icp(bitgo, staticsCoin);
    }
    getChain() {
        return 'icp';
    }
    getBaseChain() {
        return 'icp';
    }
    getFamily() {
        return this._staticsCoin.family;
    }
    getFullName() {
        return 'Internet Computer';
    }
    getBaseFactor() {
        return Math.pow(10, this._staticsCoin.decimalPlaces);
    }
    async explainTransaction(params) {
        const factory = this.getBuilderFactory();
        const txBuilder = await factory.from(params.transactionHex);
        const transaction = await txBuilder.build();
        if (params.signableHex !== undefined) {
            const generatedSignableHex = txBuilder.transaction.payloadsData.payloads[0].hex_bytes;
            if (generatedSignableHex !== params.signableHex) {
                throw new Error('generated signableHex is not equal to params.signableHex');
            }
        }
        return transaction.explainTransaction();
    }
    async verifyTransaction(params) {
        const { txParams, txPrebuild } = params;
        const txHex = txPrebuild?.txHex;
        if (!txHex) {
            throw new Error('txHex is required');
        }
        const txHexParams = {
            transactionHex: txHex,
        };
        if (txPrebuild.txInfo && txPrebuild.txInfo !== undefined && typeof txPrebuild.txInfo === 'string') {
            txHexParams.signableHex = txPrebuild.txInfo;
        }
        const explainedTx = await this.explainTransaction(txHexParams);
        if (Array.isArray(txParams.recipients) && txParams.recipients.length > 0) {
            if (txParams.recipients.length > 1) {
                throw new Error(`${this.getChain()} doesn't support sending to more than 1 destination address within a single transaction. Try again, using only a single recipient.`);
            }
            (0, assert_1.default)(explainedTx.outputs.length === 1, 'Tx outputs does not match with expected txParams recipients');
            const output = explainedTx.outputs[0];
            const recipient = txParams.recipients[0];
            (0, assert_1.default)(typeof recipient.address === 'string' &&
                typeof output.address === 'string' &&
                output.address === recipient.address &&
                (0, bignumber_js_1.default)(output.amount).eq((0, bignumber_js_1.default)(recipient.amount)), 'Tx outputs does not match with expected txParams recipients');
        }
        return true;
    }
    async isWalletAddress(params) {
        return this.isValidAddress(params.address);
    }
    async parseTransaction(params) {
        return {};
    }
    /**
     * Generate a new keypair for this coin.
     * @param seed Seed from which the new keypair should be generated, otherwise a random seed is used
     */
    generateKeyPair(seed) {
        return utils_1.default.generateKeyPair(seed);
    }
    isValidAddress(address) {
        return utils_1.default.isValidAddress(address);
    }
    async signTransaction(params) {
        const txHex = params?.txPrebuild?.txHex;
        const privateKey = params?.prv;
        if (!txHex) {
            throw new sdk_core_1.SigningError('missing required txPrebuild parameter: params.txPrebuild.txHex');
        }
        if (!privateKey) {
            throw new sdk_core_1.SigningError('missing required prv parameter: params.prv');
        }
        const factory = this.getBuilderFactory();
        const txBuilder = await factory.from(params.txPrebuild.txHex);
        txBuilder.sign({ key: params.prv });
        txBuilder.combine();
        const serializedTx = txBuilder.transaction.toBroadcastFormat();
        return {
            txHex: serializedTx,
        };
    }
    isValidPub(key) {
        return utils_1.default.isValidPublicKey(key);
    }
    isValidPrv(key) {
        return utils_1.default.isValidPrivateKey(key);
    }
    /** @inheritDoc */
    supportsTss() {
        return true;
    }
    /** inherited doc */
    getDefaultMultisigType() {
        return sdk_core_1.multisigTypes.tss;
    }
    /** @inheritDoc */
    getMPCAlgorithm() {
        return 'ecdsa';
    }
    /** @inheritDoc **/
    getHashFunction() {
        return (0, crypto_1.createHash)('sha256');
    }
    async getAddressFromPublicKey(hexEncodedPublicKey) {
        return utils_1.default.getAddressFromPublicKey(hexEncodedPublicKey);
    }
    /** @inheritDoc **/
    getPublicNodeUrl() {
        return sdk_core_1.Environments[this.bitgo.getEnv()].icpNodeUrl;
    }
    getRosettaNodeUrl() {
        return sdk_core_1.Environments[this.bitgo.getEnv()].icpRosettaNodeUrl;
    }
    /**
     * Sends a POST request to the Rosetta node with the specified payload and endpoint.
     *
     * @param payload - A JSON string representing the request payload to be sent to the Rosetta node.
     * @param endpoint - The endpoint path to append to the Rosetta node URL.
     * @returns A promise that resolves to the HTTP response from the Rosetta node.
     * @throws An error if the HTTP request fails or if the response status is not 200.
     */
    async getRosettaNodeResponse(payload, endpoint) {
        const nodeUrl = this.getRosettaNodeUrl();
        const fullEndpoint = `${nodeUrl}${endpoint}`;
        const body = {
            network_identifier: {
                blockchain: this.getFullName(),
                network: iface_1.Network.ID,
            },
            ...JSON.parse(payload),
        };
        try {
            const response = await request.post(fullEndpoint).set('Content-Type', 'application/json').send(body);
            if (response.status !== 200) {
                throw new Error(`Call to Rosetta node failed, got HTTP Status: ${response.status} with body: ${response.body}`);
            }
            return response;
        }
        catch (error) {
            throw new Error(`Unable to call rosetta node: ${error.message || error}`);
        }
    }
    /* inheritDoc */
    // this method calls the public node to broadcast the transaction and not the rosetta node
    async broadcastTransaction(payload) {
        const endpoint = this.getPublicNodeBroadcastEndpoint();
        try {
            const response = await axios_1.default.post(endpoint, payload.serializedSignedTransaction, {
                responseType: 'arraybuffer', // This ensures you get a Buffer, not a string
                headers: {
                    'Content-Type': 'application/cbor',
                },
            });
            if (response.status !== 200) {
                throw new Error(`Transaction broadcast failed with status: ${response.status} - ${response.statusText}`);
            }
            const decodedResponse = utils_1.default.cborDecode(response.data);
            if (decodedResponse.status === 'replied') {
                const txnId = this.extractTransactionId(decodedResponse);
                return { txId: txnId };
            }
            else {
                throw new Error(`Unexpected response status from node: ${decodedResponse.status}`);
            }
        }
        catch (error) {
            throw new Error(`Transaction broadcast error: ${error?.message || JSON.stringify(error)}`);
        }
    }
    getPublicNodeBroadcastEndpoint() {
        const nodeUrl = this.getPublicNodeUrl();
        const principal = principal_1.Principal.fromUint8Array(iface_1.LEDGER_CANISTER_ID);
        const canisterIdHex = principal.toText();
        const endpoint = `${nodeUrl}${iface_1.PUBLIC_NODE_REQUEST_ENDPOINT}${canisterIdHex}/call`;
        return endpoint;
    }
    // TODO: Implement the real logic to extract the transaction ID, Ticket: https://bitgoinc.atlassian.net/browse/WIN-5075
    extractTransactionId(decodedResponse) {
        return '4c10cf22a768a20e7eebc86e49c031d0e22895a39c6355b5f7455b2acad59c1e';
    }
    /**
     * Helper to fetch account balance
     * @param senderAddress - The address of the account to fetch the balance for
     * @returns The balance of the account as a string
     * @throws If the account is not found or there is an error fetching the balance
     */
    async getAccountBalance(address) {
        try {
            const payload = {
                account_identifier: {
                    address: address,
                },
            };
            const response = await this.getRosettaNodeResponse(JSON.stringify(payload), iface_1.ACCOUNT_BALANCE_ENDPOINT);
            const coinName = this._staticsCoin.name.toUpperCase();
            const balanceEntry = response.body.balances.find((b) => b.currency?.symbol === coinName);
            if (!balanceEntry) {
                throw new Error(`No balance found for ICP account ${address}.`);
            }
            const balance = balanceEntry.value;
            return balance;
        }
        catch (error) {
            throw new Error(`Unable to fetch account balance: ${error.message || error}`);
        }
    }
    getBuilderFactory() {
        return new transactionBuilderFactory_1.TransactionBuilderFactory(statics_1.coins.get(this.getBaseChain()));
    }
    /**
     * Generates an array of signatures for the provided payloads using MPC
     *
     * @param payloadsData - The data containing the payloads to be signed.
     * @param senderPublicKey - The public key of the sender in hexadecimal format.
     * @param userKeyShare - The user's key share as a Buffer.
     * @param backupKeyShare - The backup key share as a Buffer.
     * @param commonKeyChain - The common key chain identifier used for MPC signing.
     * @returns A promise that resolves to an array of `Signatures` objects, each containing the signing payload,
     *          signature type, public key, and the generated signature in hexadecimal format.
     */
    async signatures(payloadsData, senderPublicKey, userKeyShare, backupKeyShare, commonKeyChain) {
        try {
            const payload = payloadsData.payloads[0];
            const message = Buffer.from(payload.hex_bytes, 'hex');
            const messageHash = (0, crypto_1.createHash)('sha256').update(message).digest();
            const signature = await sdk_core_1.ECDSAUtils.signRecoveryMpcV2(messageHash, userKeyShare, backupKeyShare, commonKeyChain);
            const signaturePayload = {
                signing_payload: payload,
                signature_type: payload.signature_type,
                public_key: {
                    hex_bytes: senderPublicKey,
                    curve_type: iface_1.CurveType.SECP256K1,
                },
                hex_bytes: signature.r + signature.s,
            };
            return [signaturePayload];
        }
        catch (error) {
            throw new Error(`Error generating signatures: ${error.message || error}`);
        }
    }
    /**
     * Builds a funds recovery transaction without BitGo
     * @param params
     */
    async recover(params) {
        if (!params.recoveryDestination || !this.isValidAddress(params.recoveryDestination)) {
            throw new Error('invalid recoveryDestination');
        }
        if (!params.userKey) {
            throw new Error('missing userKey');
        }
        if (!params.backupKey) {
            throw new Error('missing backupKey');
        }
        if (!params.walletPassphrase) {
            throw new Error('missing wallet passphrase');
        }
        const userKey = params.userKey.replace(/\s/g, '');
        const backupKey = params.backupKey.replace(/\s/g, '');
        const { userKeyShare, backupKeyShare, commonKeyChain } = await sdk_core_1.ECDSAUtils.getMpcV2RecoveryKeyShares(userKey, backupKey, params.walletPassphrase);
        const MPC = new sdk_core_1.Ecdsa();
        const publicKey = MPC.deriveUnhardened(commonKeyChain, iface_1.ROOT_PATH).slice(0, 66);
        if (!publicKey || !backupKeyShare) {
            throw new Error('Missing publicKey or backupKeyShare');
        }
        const senderAddress = await this.getAddressFromPublicKey(publicKey);
        const balance = new bignumber_js_1.default(await this.getAccountBalance(senderAddress));
        const feeData = new bignumber_js_1.default(utils_1.default.feeData());
        const actualBalance = balance.plus(feeData); // gas amount returned from gasData is negative so we add it
        if (actualBalance.isLessThanOrEqualTo(0)) {
            throw new Error('Did not have enough funds to recover');
        }
        const factory = this.getBuilderFactory();
        const txBuilder = factory.getTransferBuilder();
        txBuilder.sender(senderAddress, publicKey);
        txBuilder.receiverId(params.recoveryDestination);
        txBuilder.amount(actualBalance.toString());
        if (params.memo !== undefined && utils_1.default.validateMemo(params.memo)) {
            txBuilder.memo(Number(params.memo));
        }
        await txBuilder.build();
        if (txBuilder.transaction.payloadsData.payloads.length === 0) {
            throw new Error('Missing payloads to generate signatures');
        }
        const signatures = await this.signatures(txBuilder.transaction.payloadsData, publicKey, userKeyShare, backupKeyShare, commonKeyChain);
        if (!signatures || signatures.length === 0) {
            throw new Error('Failed to generate signatures');
        }
        txBuilder.transaction.addSignature(signatures);
        txBuilder.combine();
        const broadcastableTxn = txBuilder.transaction.toBroadcastFormat();
        const result = await this.broadcastTransaction({ serializedSignedTransaction: broadcastableTxn });
        if (!result.txId) {
            throw new Error('Transaction failed to broadcast');
        }
        return result.txId;
    }
}
exports.Icp = Icp;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWNwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ljcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsOENBbUJ5QjtBQUN6Qiw0Q0FBb0U7QUFDcEUsa0RBQStDO0FBQy9DLGtEQUEwQjtBQUMxQixnRUFBcUM7QUFDckMsbUNBQTBDO0FBQzFDLG9EQUFzQztBQUN0Qyx1Q0FjcUI7QUFDckIsK0VBQTRFO0FBQzVFLHdEQUFnQztBQUVoQzs7Ozs7O0dBTUc7QUFDSCxNQUFhLEdBQUksU0FBUSxtQkFBUTtJQUUvQixZQUFzQixLQUFnQixFQUFFLFdBQXVDO1FBQzdFLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUViLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLG9EQUFvRCxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUVELElBQUksQ0FBQyxZQUFZLEdBQUcsV0FBVyxDQUFDO0lBQ2xDLENBQUM7SUFFRCxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQWdCLEVBQUUsV0FBdUM7UUFDN0UsT0FBTyxJQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVELFFBQVE7UUFDTixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxZQUFZO1FBQ1YsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsU0FBUztRQUNQLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUM7SUFDbEMsQ0FBQztJQUVELFdBQVc7UUFDVCxPQUFPLG1CQUFtQixDQUFDO0lBQzdCLENBQUM7SUFFRCxhQUFhO1FBQ1gsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFF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dEMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQ2xDLFNBQVMsRUFDVCxZQUFZLEVBQ1osY0FBYyxFQUNkLGNBQWMsQ0FDZixDQUFDO1FBQ0YsSUFBSSxDQUFDLFVBQVUsSUFBSSxVQUFVLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzNDLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBQ0QsU0FBUyxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDL0MsU0FBUyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3BCLE1BQU0sZ0JBQWdCLEdBQUcsU0FBUyxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ25FLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixDQUFDLEVBQUUsMkJBQTJCLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUM7SUFDckIsQ0FBQztDQUNGO0FBbFlELGtCQWtZQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcbmltcG9ydCB7XG4gIEJhc2VCcm9hZGNhc3RUcmFuc2FjdGlvbk9wdGlvbnMsXG4gIEJhc2VCcm9hZGNhc3RUcmFuc2FjdGlvblJlc3VsdCxcbiAgQmFzZUNvaW4sXG4gIEJpdEdvQmFzZSxcbiAgRWNkc2EsXG4gIEVDRFNBVXRpbHMsXG4gIEVudmlyb25tZW50cyxcbiAgS2V5UGFpcixcbiAgTVBDQWxnb3JpdGhtLFxuICBNdWx0aXNpZ1R5cGUsXG4gIG11bHRpc2lnVHlwZXMsXG4gIFBhcnNlZFRyYW5zYWN0aW9uLFxuICBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgU2lnbmVkVHJhbnNhY3Rpb24sXG4gIFNpZ25pbmdFcnJvcixcbiAgU2lnblRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgVHNzVmVyaWZ5QWRkcmVzc09wdGlvbnMsXG4gIFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyxcbn0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IGNvaW5zLCBCYXNlQ29pbiBhcyBTdGF0aWNzQmFzZUNvaW4gfSBmcm9tICdAYml0Z28vc3RhdGljcyc7XG5pbXBvcnQgeyBQcmluY2lwYWwgfSBmcm9tICdAZGZpbml0eS9wcmluY2lwYWwnO1xuaW1wb3J0IGF4aW9zIGZyb20gJ2F4aW9zJztcbmltcG9ydCBCaWdOdW1iZXIgZnJvbSAnYmlnbnVtYmVyLmpzJztcbmltcG9ydCB7IGNyZWF0ZUhhc2gsIEhhc2ggfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgcmVxdWVzdCBmcm9tICdzdXBlcmFnZW50JztcbmltcG9ydCB7XG4gIEFDQ09VTlRfQkFMQU5DRV9FTkRQT0lOVCxcbiAgQ3VydmVUeXBlLFxuICBMRURHRVJfQ0FOSVNURVJfSUQsXG4gIE5ldHdvcmssXG4gIFBheWxvYWRzRGF0YSxcbiAgUFVCTElDX05PREVfUkVRVUVTVF9FTkRQT0lOVCxcbiAgUHVibGljTm9kZVN1Ym1pdFJlc3BvbnNlLFxuICBSZWNvdmVyeU9wdGlvbnMsXG4gIFJPT1RfUEFUSCxcbiAgU2lnbmF0dXJlcyxcbiAgU2lnbmluZ1BheWxvYWQsXG4gIEljcFRyYW5zYWN0aW9uRXhwbGFuYXRpb24sXG4gIFRyYW5zYWN0aW9uSGV4UGFyYW1zLFxufSBmcm9tICcuL2xpYi9pZmFjZSc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5IH0gZnJvbSAnLi9saWIvdHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeSc7XG5pbXBvcnQgdXRpbHMgZnJvbSAnLi9saWIvdXRpbHMnO1xuXG4vKipcbiAqIENsYXNzIHJlcHJlc2VudGluZyB0aGUgSW50ZXJuZXQgQ29tcHV0ZXIgKElDUCkgY29pbi5cbiAqIEV4dGVuZHMgdGhlIEJhc2VDb2luIGNsYXNzIGFuZCBwcm92aWRlcyBzcGVjaWZpYyBpbXBsZW1lbnRhdGlvbnMgZm9yIElDUC5cbiAqXG4gKiBAc2VlIHtAbGluayBodHRwczovL2ludGVybmV0Y29tcHV0ZXIub3JnL31cbiAqIEBzZWUge0BsaW5rIGh0dHBzOi8vaW50ZXJuZXRjb21wdXRlci5vcmcvZG9jcy9jdXJyZW50L2RldmVsb3Blci1kb2NzL2RlZmkvcm9zZXR0YS9pY3Bfcm9zZXR0YS9kYXRhX2FwaS99XG4gKi9cbmV4cG9ydCBjbGFzcyBJY3AgZXh0ZW5kcyBCYXNlQ29pbiB7XG4gIHByb3RlY3RlZCByZWFkb25seSBfc3RhdGljc0NvaW46IFJlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj47XG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihiaXRnbzogQml0R29CYXNlLCBzdGF0aWNzQ29pbj86IFJlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj4pIHtcbiAgICBzdXBlcihiaXRnbyk7XG5cbiAgICBpZiAoIXN0YXRpY3NDb2luKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgY29uc3RydWN0b3IgcGFyYW1ldGVyIHN0YXRpY3NDb2luJyk7XG4gICAgfVxuXG4gICAgdGhpcy5fc3RhdGljc0NvaW4gPSBzdGF0aWNzQ29pbjtcbiAgfVxuXG4gIHN0YXRpYyBjcmVhdGVJbnN0YW5jZShiaXRnbzogQml0R29CYXNlLCBzdGF0aWNzQ29pbj86IFJlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj4pOiBCYXNlQ29pbiB7XG4gICAgcmV0dXJuIG5ldyBJY3AoYml0Z28sIHN0YXRpY3NDb2luKTtcbiAgfVxuXG4gIGdldENoYWluKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdpY3AnO1xuICB9XG5cbiAgZ2V0QmFzZUNoYWluKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdpY3AnO1xuICB9XG5cbiAgZ2V0RmFtaWx5KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YXRpY3NDb2luLmZhbWlseTtcbiAgfVxuXG4gIGdldEZ1bGxOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdJbnRlcm5ldCBDb21wdXRlcic7XG4gIH1cblxuICBnZXRCYXNlRmFjdG9yKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIE1hdGgucG93KDEwLCB0aGlzLl9zdGF0aWNzQ29pbi5kZWNpbWFsUGxhY2VzKTtcbiAgfVxuXG4gIGFzeW5jIGV4cGxhaW5UcmFuc2FjdGlvbihwYXJhbXM6IFRyYW5zYWN0aW9uSGV4UGFyYW1zKTogUHJvbWlzZTxJY3BUcmFuc2FjdGlvbkV4cGxhbmF0aW9uPiB7XG4gICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0QnVpbGRlckZhY3RvcnkoKTtcbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBhd2FpdCBmYWN0b3J5LmZyb20ocGFyYW1zLnRyYW5zYWN0aW9uSGV4KTtcbiAgICBjb25zdCB0cmFuc2FjdGlvbiA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIGlmIChwYXJhbXMuc2lnbmFibGVIZXggIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgZ2VuZXJhdGVkU2lnbmFibGVIZXggPSB0eEJ1aWxkZXIudHJhbnNhY3Rpb24ucGF5bG9hZHNEYXRhLnBheWxvYWRzWzBdLmhleF9ieXRlcztcbiAgICAgIGlmIChnZW5lcmF0ZWRTaWduYWJsZUhleCAhPT0gcGFyYW1zLnNpZ25hYmxlSGV4KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZ2VuZXJhdGVkIHNpZ25hYmxlSGV4IGlzIG5vdCBlcXVhbCB0byBwYXJhbXMuc2lnbmFibGVIZXgnKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRyYW5zYWN0aW9uLmV4cGxhaW5UcmFuc2FjdGlvbigpO1xuICB9XG5cbiAgYXN5bmMgdmVyaWZ5VHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkIH0gPSBwYXJhbXM7XG4gICAgY29uc3QgdHhIZXggPSB0eFByZWJ1aWxkPy50eEhleDtcbiAgICBpZiAoIXR4SGV4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4SGV4IGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IHR4SGV4UGFyYW1zOiBUcmFuc2FjdGlvbkhleFBhcmFtcyA9IHtcbiAgICAgIHRyYW5zYWN0aW9uSGV4OiB0eEhleCxcbiAgICB9O1xuXG4gICAgaWYgKHR4UHJlYnVpbGQudHhJbmZvICYmIHR4UHJlYnVpbGQudHhJbmZvICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHR4UHJlYnVpbGQudHhJbmZvID09PSAnc3RyaW5nJykge1xuICAgICAgdHhIZXhQYXJhbXMuc2lnbmFibGVIZXggPSB0eFByZWJ1aWxkLnR4SW5mbztcbiAgICB9XG5cbiAgICBjb25zdCBleHBsYWluZWRUeCA9IGF3YWl0IHRoaXMuZXhwbGFpblRyYW5zYWN0aW9uKHR4SGV4UGFyYW1zKTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KHR4UGFyYW1zLnJlY2lwaWVudHMpICYmIHR4UGFyYW1zLnJlY2lwaWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgaWYgKHR4UGFyYW1zLnJlY2lwaWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYCR7dGhpcy5nZXRDaGFpbigpfSBkb2Vzbid0IHN1cHBvcnQgc2VuZGluZyB0byBtb3JlIHRoYW4gMSBkZXN0aW5hdGlvbiBhZGRyZXNzIHdpdGhpbiBhIHNpbmdsZSB0cmFuc2FjdGlvbi4gVHJ5IGFnYWluLCB1c2luZyBvbmx5IGEgc2luZ2xlIHJlY2lwaWVudC5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBhc3NlcnQoZXhwbGFpbmVkVHgub3V0cHV0cy5sZW5ndGggPT09IDEsICdUeCBvdXRwdXRzIGRvZXMgbm90IG1hdGNoIHdpdGggZXhwZWN0ZWQgdHhQYXJhbXMgcmVjaXBpZW50cycpO1xuXG4gICAgICBjb25zdCBvdXRwdXQgPSBleHBsYWluZWRUeC5vdXRwdXRzWzBdO1xuICAgICAgY29uc3QgcmVjaXBpZW50ID0gdHhQYXJhbXMucmVjaXBpZW50c1swXTtcbiAgICAgIGFzc2VydChcbiAgICAgICAgdHlwZW9mIHJlY2lwaWVudC5hZGRyZXNzID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgIHR5cGVvZiBvdXRwdXQuYWRkcmVzcyA9PT0gJ3N0cmluZycgJiZcbiAgICAgICAgICBvdXRwdXQuYWRkcmVzcyA9PT0gcmVjaXBpZW50LmFkZHJlc3MgJiZcbiAgICAgICAgICBCaWdOdW1iZXIob3V0cHV0LmFtb3VudCkuZXEoQmlnTnVtYmVyKHJlY2lwaWVudC5hbW91bnQpKSxcbiAgICAgICAgJ1R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCB0eFBhcmFtcyByZWNpcGllbnRzJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBhc3luYyBpc1dhbGxldEFkZHJlc3MocGFyYW1zOiBUc3NWZXJpZnlBZGRyZXNzT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5hZGRyZXNzKTtcbiAgfVxuXG4gIGFzeW5jIHBhcnNlVHJhbnNhY3Rpb24ocGFyYW1zOiBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8UGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgYSBuZXcga2V5cGFpciBmb3IgdGhpcyBjb2luLlxuICAgKiBAcGFyYW0gc2VlZCBTZWVkIGZyb20gd2hpY2ggdGhlIG5ldyBrZXlwYWlyIHNob3VsZCBiZSBnZW5lcmF0ZWQsIG90aGVyd2lzZSBhIHJhbmRvbSBzZWVkIGlzIHVzZWRcbiAgICovXG4gIHB1YmxpYyBnZW5lcmF0ZUtleVBhaXIoc2VlZD86IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIHJldHVybiB1dGlscy5nZW5lcmF0ZUtleVBhaXIoc2VlZCk7XG4gIH1cblxuICBpc1ZhbGlkQWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdXRpbHMuaXNWYWxpZEFkZHJlc3MoYWRkcmVzcyk7XG4gIH1cblxuICBhc3luYyBzaWduVHJhbnNhY3Rpb24oXG4gICAgcGFyYW1zOiBTaWduVHJhbnNhY3Rpb25PcHRpb25zICYgeyB0eFByZWJ1aWxkOiB7IHR4SGV4OiBzdHJpbmcgfTsgcHJ2OiBzdHJpbmcgfVxuICApOiBQcm9taXNlPFNpZ25lZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3QgdHhIZXggPSBwYXJhbXM/LnR4UHJlYnVpbGQ/LnR4SGV4O1xuICAgIGNvbnN0IHByaXZhdGVLZXkgPSBwYXJhbXM/LnBydjtcbiAgICBpZiAoIXR4SGV4KSB7XG4gICAgICB0aHJvdyBuZXcgU2lnbmluZ0Vycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHR4UHJlYnVpbGQgcGFyYW1ldGVyOiBwYXJhbXMudHhQcmVidWlsZC50eEhleCcpO1xuICAgIH1cbiAgICBpZiAoIXByaXZhdGVLZXkpIHtcbiAgICAgIHRocm93IG5ldyBTaWduaW5nRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgcHJ2IHBhcmFtZXRlcjogcGFyYW1zLnBydicpO1xuICAgIH1cbiAgICBjb25zdCBmYWN0b3J5ID0gdGhpcy5nZXRCdWlsZGVyRmFjdG9yeSgpO1xuICAgIGNvbnN0IHR4QnVpbGRlciA9IGF3YWl0IGZhY3RvcnkuZnJvbShwYXJhbXMudHhQcmVidWlsZC50eEhleCk7XG4gICAgdHhCdWlsZGVyLnNpZ24oeyBrZXk6IHBhcmFtcy5wcnYgfSk7XG4gICAgdHhCdWlsZGVyLmNvbWJpbmUoKTtcbiAgICBjb25zdCBzZXJpYWxpemVkVHggPSB0eEJ1aWxkZXIudHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgICByZXR1cm4ge1xuICAgICAgdHhIZXg6IHNlcmlhbGl6ZWRUeCxcbiAgICB9O1xuICB9XG5cbiAgaXNWYWxpZFB1YihrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB1dGlscy5pc1ZhbGlkUHVibGljS2V5KGtleSk7XG4gIH1cblxuICBpc1ZhbGlkUHJ2KGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHV0aWxzLmlzVmFsaWRQcml2YXRlS2V5KGtleSk7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKi9cbiAgc3VwcG9ydHNUc3MoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKiogaW5oZXJpdGVkIGRvYyAqL1xuICBnZXREZWZhdWx0TXVsdGlzaWdUeXBlKCk6IE11bHRpc2lnVHlwZSB7XG4gICAgcmV0dXJuIG11bHRpc2lnVHlwZXMudHNzO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICovXG4gIGdldE1QQ0FsZ29yaXRobSgpOiBNUENBbGdvcml0aG0ge1xuICAgIHJldHVybiAnZWNkc2EnO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICoqL1xuICBnZXRIYXNoRnVuY3Rpb24oKTogSGFzaCB7XG4gICAgcmV0dXJuIGNyZWF0ZUhhc2goJ3NoYTI1NicpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRBZGRyZXNzRnJvbVB1YmxpY0tleShoZXhFbmNvZGVkUHVibGljS2V5OiBzdHJpbmcpIHtcbiAgICByZXR1cm4gdXRpbHMuZ2V0QWRkcmVzc0Zyb21QdWJsaWNLZXkoaGV4RW5jb2RlZFB1YmxpY0tleSk7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKiovXG4gIHByb3RlY3RlZCBnZXRQdWJsaWNOb2RlVXJsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIEVudmlyb25tZW50c1t0aGlzLmJpdGdvLmdldEVudigpXS5pY3BOb2RlVXJsO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFJvc2V0dGFOb2RlVXJsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIEVudmlyb25tZW50c1t0aGlzLmJpdGdvLmdldEVudigpXS5pY3BSb3NldHRhTm9kZVVybDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgUm9zZXR0YSBub2RlIHdpdGggdGhlIHNwZWNpZmllZCBwYXlsb2FkIGFuZCBlbmRwb2ludC5cbiAgICpcbiAgICogQHBhcmFtIHBheWxvYWQgLSBBIEpTT04gc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgcmVxdWVzdCBwYXlsb2FkIHRvIGJlIHNlbnQgdG8gdGhlIFJvc2V0dGEgbm9kZS5cbiAgICogQHBhcmFtIGVuZHBvaW50IC0gVGhlIGVuZHBvaW50IHBhdGggdG8gYXBwZW5kIHRvIHRoZSBSb3NldHRhIG5vZGUgVVJMLlxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUCByZXNwb25zZSBmcm9tIHRoZSBSb3NldHRhIG5vZGUuXG4gICAqIEB0aHJvd3MgQW4gZXJyb3IgaWYgdGhlIEhUVFAgcmVxdWVzdCBmYWlscyBvciBpZiB0aGUgcmVzcG9uc2Ugc3RhdHVzIGlzIG5vdCAyMDAuXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0Um9zZXR0YU5vZGVSZXNwb25zZShwYXlsb2FkOiBzdHJpbmcsIGVuZHBvaW50OiBzdHJpbmcpOiBQcm9taXNlPHJlcXVlc3QuUmVzcG9uc2U+IHtcbiAgICBjb25zdCBub2RlVXJsID0gdGhpcy5nZXRSb3NldHRhTm9kZVVybCgpO1xuICAgIGNvbnN0IGZ1bGxFbmRwb2ludCA9IGAke25vZGVVcmx9JHtlbmRwb2ludH1gO1xuICAgIGNvbnN0IGJvZHkgPSB7XG4gICAgICBuZXR3b3JrX2lkZW50aWZpZXI6IHtcbiAgICAgICAgYmxvY2tjaGFpbjogdGhpcy5nZXRGdWxsTmFtZSgpLFxuICAgICAgICBuZXR3b3JrOiBOZXR3b3JrLklELFxuICAgICAgfSxcbiAgICAgIC4uLkpTT04ucGFyc2UocGF5bG9hZCksXG4gICAgfTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHJlcXVlc3QucG9zdChmdWxsRW5kcG9pbnQpLnNldCgnQ29udGVudC1UeXBlJywgJ2FwcGxpY2F0aW9uL2pzb24nKS5zZW5kKGJvZHkpO1xuICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2FsbCB0byBSb3NldHRhIG5vZGUgZmFpbGVkLCBnb3QgSFRUUCBTdGF0dXM6ICR7cmVzcG9uc2Uuc3RhdHVzfSB3aXRoIGJvZHk6ICR7cmVzcG9uc2UuYm9keX1gKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gY2FsbCByb3NldHRhIG5vZGU6ICR7ZXJyb3IubWVzc2FnZSB8fCBlcnJvcn1gKTtcbiAgICB9XG4gIH1cblxuICAvKiBpbmhlcml0RG9jICovXG4gIC8vIHRoaXMgbWV0aG9kIGNhbGxzIHRoZSBwdWJsaWMgbm9kZSB0byBicm9hZGNhc3QgdGhlIHRyYW5zYWN0aW9uIGFuZCBub3QgdGhlIHJvc2V0dGEgbm9kZVxuICBwdWJsaWMgYXN5bmMgYnJvYWRjYXN0VHJhbnNhY3Rpb24ocGF5bG9hZDogQmFzZUJyb2FkY2FzdFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8QmFzZUJyb2FkY2FzdFRyYW5zYWN0aW9uUmVzdWx0PiB7XG4gICAgY29uc3QgZW5kcG9pbnQgPSB0aGlzLmdldFB1YmxpY05vZGVCcm9hZGNhc3RFbmRwb2ludCgpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgYXhpb3MucG9zdChlbmRwb2ludCwgcGF5bG9hZC5zZXJpYWxpemVkU2lnbmVkVHJhbnNhY3Rpb24sIHtcbiAgICAgICAgcmVzcG9uc2VUeXBlOiAnYXJyYXlidWZmZXInLCAvLyBUaGlzIGVuc3VyZXMgeW91IGdldCBhIEJ1ZmZlciwgbm90IGEgc3RyaW5nXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2Nib3InLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFRyYW5zYWN0aW9uIGJyb2FkY2FzdCBmYWlsZWQgd2l0aCBzdGF0dXM6ICR7cmVzcG9uc2Uuc3RhdHVzfSAtICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGVjb2RlZFJlc3BvbnNlID0gdXRpbHMuY2JvckRlY29kZShyZXNwb25zZS5kYXRhKSBhcyBQdWJsaWNOb2RlU3VibWl0UmVzcG9uc2U7XG5cbiAgICAgIGlmIChkZWNvZGVkUmVzcG9uc2Uuc3RhdHVzID09PSAncmVwbGllZCcpIHtcbiAgICAgICAgY29uc3QgdHhuSWQgPSB0aGlzLmV4dHJhY3RUcmFuc2FjdGlvbklkKGRlY29kZWRSZXNwb25zZSk7XG4gICAgICAgIHJldHVybiB7IHR4SWQ6IHR4bklkIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuZXhwZWN0ZWQgcmVzcG9uc2Ugc3RhdHVzIGZyb20gbm9kZTogJHtkZWNvZGVkUmVzcG9uc2Uuc3RhdHVzfWApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRyYW5zYWN0aW9uIGJyb2FkY2FzdCBlcnJvcjogJHtlcnJvcj8ubWVzc2FnZSB8fCBKU09OLnN0cmluZ2lmeShlcnJvcil9YCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRQdWJsaWNOb2RlQnJvYWRjYXN0RW5kcG9pbnQoKTogc3RyaW5nIHtcbiAgICBjb25zdCBub2RlVXJsID0gdGhpcy5nZXRQdWJsaWNOb2RlVXJsKCk7XG4gICAgY29uc3QgcHJpbmNpcGFsID0gUHJpbmNpcGFsLmZyb21VaW50OEFycmF5KExFREdFUl9DQU5JU1RFUl9JRCk7XG4gICAgY29uc3QgY2FuaXN0ZXJJZEhleCA9IHByaW5jaXBhbC50b1RleHQoKTtcbiAgICBjb25zdCBlbmRwb2ludCA9IGAke25vZGVVcmx9JHtQVUJMSUNfTk9ERV9SRVFVRVNUX0VORFBPSU5UfSR7Y2FuaXN0ZXJJZEhleH0vY2FsbGA7XG4gICAgcmV0dXJuIGVuZHBvaW50O1xuICB9XG5cbiAgLy8gVE9ETzogSW1wbGVtZW50IHRoZSByZWFsIGxvZ2ljIHRvIGV4dHJhY3QgdGhlIHRyYW5zYWN0aW9uIElELCBUaWNrZXQ6IGh0dHBzOi8vYml0Z29pbmMuYXRsYXNzaWFuLm5ldC9icm93c2UvV0lOLTUwNzVcbiAgcHJpdmF0ZSBleHRyYWN0VHJhbnNhY3Rpb25JZChkZWNvZGVkUmVzcG9uc2U6IFB1YmxpY05vZGVTdWJtaXRSZXNwb25zZSk6IHN0cmluZyB7XG4gICAgcmV0dXJuICc0YzEwY2YyMmE3NjhhMjBlN2VlYmM4NmU0OWMwMzFkMGUyMjg5NWEzOWM2MzU1YjVmNzQ1NWIyYWNhZDU5YzFlJztcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgdG8gZmV0Y2ggYWNjb3VudCBiYWxhbmNlXG4gICAqIEBwYXJhbSBzZW5kZXJBZGRyZXNzIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIGFjY291bnQgdG8gZmV0Y2ggdGhlIGJhbGFuY2UgZm9yXG4gICAqIEByZXR1cm5zIFRoZSBiYWxhbmNlIG9mIHRoZSBhY2NvdW50IGFzIGEgc3RyaW5nXG4gICAqIEB0aHJvd3MgSWYgdGhlIGFjY291bnQgaXMgbm90IGZvdW5kIG9yIHRoZXJlIGlzIGFuIGVycm9yIGZldGNoaW5nIHRoZSBiYWxhbmNlXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0QWNjb3VudEJhbGFuY2UoYWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcGF5bG9hZCA9IHtcbiAgICAgICAgYWNjb3VudF9pZGVudGlmaWVyOiB7XG4gICAgICAgICAgYWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0Um9zZXR0YU5vZGVSZXNwb25zZShKU09OLnN0cmluZ2lmeShwYXlsb2FkKSwgQUNDT1VOVF9CQUxBTkNFX0VORFBPSU5UKTtcbiAgICAgIGNvbnN0IGNvaW5OYW1lID0gdGhpcy5fc3RhdGljc0NvaW4ubmFtZS50b1VwcGVyQ2FzZSgpO1xuICAgICAgY29uc3QgYmFsYW5jZUVudHJ5ID0gcmVzcG9uc2UuYm9keS5iYWxhbmNlcy5maW5kKChiKSA9PiBiLmN1cnJlbmN5Py5zeW1ib2wgPT09IGNvaW5OYW1lKTtcbiAgICAgIGlmICghYmFsYW5jZUVudHJ5KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gYmFsYW5jZSBmb3VuZCBmb3IgSUNQIGFjY291bnQgJHthZGRyZXNzfS5gKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGJhbGFuY2UgPSBiYWxhbmNlRW50cnkudmFsdWU7XG4gICAgICByZXR1cm4gYmFsYW5jZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gZmV0Y2ggYWNjb3VudCBiYWxhbmNlOiAke2Vycm9yLm1lc3NhZ2UgfHwgZXJyb3J9YCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRCdWlsZGVyRmFjdG9yeSgpOiBUcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5IHtcbiAgICByZXR1cm4gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KHRoaXMuZ2V0QmFzZUNoYWluKCkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYW4gYXJyYXkgb2Ygc2lnbmF0dXJlcyBmb3IgdGhlIHByb3ZpZGVkIHBheWxvYWRzIHVzaW5nIE1QQ1xuICAgKlxuICAgKiBAcGFyYW0gcGF5bG9hZHNEYXRhIC0gVGhlIGRhdGEgY29udGFpbmluZyB0aGUgcGF5bG9hZHMgdG8gYmUgc2lnbmVkLlxuICAgKiBAcGFyYW0gc2VuZGVyUHVibGljS2V5IC0gVGhlIHB1YmxpYyBrZXkgb2YgdGhlIHNlbmRlciBpbiBoZXhhZGVjaW1hbCBmb3JtYXQuXG4gICAqIEBwYXJhbSB1c2VyS2V5U2hhcmUgLSBUaGUgdXNlcidzIGtleSBzaGFyZSBhcyBhIEJ1ZmZlci5cbiAgICogQHBhcmFtIGJhY2t1cEtleVNoYXJlIC0gVGhlIGJhY2t1cCBrZXkgc2hhcmUgYXMgYSBCdWZmZXIuXG4gICAqIEBwYXJhbSBjb21tb25LZXlDaGFpbiAtIFRoZSBjb21tb24ga2V5IGNoYWluIGlkZW50aWZpZXIgdXNlZCBmb3IgTVBDIHNpZ25pbmcuXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IG9mIGBTaWduYXR1cmVzYCBvYmplY3RzLCBlYWNoIGNvbnRhaW5pbmcgdGhlIHNpZ25pbmcgcGF5bG9hZCxcbiAgICogICAgICAgICAgc2lnbmF0dXJlIHR5cGUsIHB1YmxpYyBrZXksIGFuZCB0aGUgZ2VuZXJhdGVkIHNpZ25hdHVyZSBpbiBoZXhhZGVjaW1hbCBmb3JtYXQuXG4gICAqL1xuICBhc3luYyBzaWduYXR1cmVzKFxuICAgIHBheWxvYWRzRGF0YTogUGF5bG9hZHNEYXRhLFxuICAgIHNlbmRlclB1YmxpY0tleTogc3RyaW5nLFxuICAgIHVzZXJLZXlTaGFyZTogQnVmZmVyPEFycmF5QnVmZmVyTGlrZT4sXG4gICAgYmFja3VwS2V5U2hhcmU6IEJ1ZmZlcjxBcnJheUJ1ZmZlckxpa2U+LFxuICAgIGNvbW1vbktleUNoYWluOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxTaWduYXR1cmVzW10+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcGF5bG9hZCA9IHBheWxvYWRzRGF0YS5wYXlsb2Fkc1swXSBhcyBTaWduaW5nUGF5bG9hZDtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSBCdWZmZXIuZnJvbShwYXlsb2FkLmhleF9ieXRlcywgJ2hleCcpO1xuICAgICAgY29uc3QgbWVzc2FnZUhhc2ggPSBjcmVhdGVIYXNoKCdzaGEyNTYnKS51cGRhdGUobWVzc2FnZSkuZGlnZXN0KCk7XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBhd2FpdCBFQ0RTQVV0aWxzLnNpZ25SZWNvdmVyeU1wY1YyKG1lc3NhZ2VIYXNoLCB1c2VyS2V5U2hhcmUsIGJhY2t1cEtleVNoYXJlLCBjb21tb25LZXlDaGFpbik7XG4gICAgICBjb25zdCBzaWduYXR1cmVQYXlsb2FkOiBTaWduYXR1cmVzID0ge1xuICAgICAgICBzaWduaW5nX3BheWxvYWQ6IHBheWxvYWQsXG4gICAgICAgIHNpZ25hdHVyZV90eXBlOiBwYXlsb2FkLnNpZ25hdHVyZV90eXBlLFxuICAgICAgICBwdWJsaWNfa2V5OiB7XG4gICAgICAgICAgaGV4X2J5dGVzOiBzZW5kZXJQdWJsaWNLZXksXG4gICAgICAgICAgY3VydmVfdHlwZTogQ3VydmVUeXBlLlNFQ1AyNTZLMSxcbiAgICAgICAgfSxcbiAgICAgICAgaGV4X2J5dGVzOiBzaWduYXR1cmUuciArIHNpZ25hdHVyZS5zLFxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIFtzaWduYXR1cmVQYXlsb2FkXTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBnZW5lcmF0aW5nIHNpZ25hdHVyZXM6ICR7ZXJyb3IubWVzc2FnZSB8fCBlcnJvcn1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQnVpbGRzIGEgZnVuZHMgcmVjb3ZlcnkgdHJhbnNhY3Rpb24gd2l0aG91dCBCaXRHb1xuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqL1xuICBhc3luYyByZWNvdmVyKHBhcmFtczogUmVjb3ZlcnlPcHRpb25zKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAoIXBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHJlY292ZXJ5RGVzdGluYXRpb24nKTtcbiAgICB9XG5cbiAgICBpZiAoIXBhcmFtcy51c2VyS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdXNlcktleScpO1xuICAgIH1cblxuICAgIGlmICghcGFyYW1zLmJhY2t1cEtleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIGJhY2t1cEtleScpO1xuICAgIH1cblxuICAgIGlmICghcGFyYW1zLndhbGxldFBhc3NwaHJhc2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyB3YWxsZXQgcGFzc3BocmFzZScpO1xuICAgIH1cblxuICAgIGNvbnN0IHVzZXJLZXkgPSBwYXJhbXMudXNlcktleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuICAgIGNvbnN0IGJhY2t1cEtleSA9IHBhcmFtcy5iYWNrdXBLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcblxuICAgIGNvbnN0IHsgdXNlcktleVNoYXJlLCBiYWNrdXBLZXlTaGFyZSwgY29tbW9uS2V5Q2hhaW4gfSA9IGF3YWl0IEVDRFNBVXRpbHMuZ2V0TXBjVjJSZWNvdmVyeUtleVNoYXJlcyhcbiAgICAgIHVzZXJLZXksXG4gICAgICBiYWNrdXBLZXksXG4gICAgICBwYXJhbXMud2FsbGV0UGFzc3BocmFzZVxuICAgICk7XG4gICAgY29uc3QgTVBDID0gbmV3IEVjZHNhKCk7XG4gICAgY29uc3QgcHVibGljS2V5ID0gTVBDLmRlcml2ZVVuaGFyZGVuZWQoY29tbW9uS2V5Q2hhaW4sIFJPT1RfUEFUSCkuc2xpY2UoMCwgNjYpO1xuXG4gICAgaWYgKCFwdWJsaWNLZXkgfHwgIWJhY2t1cEtleVNoYXJlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgcHVibGljS2V5IG9yIGJhY2t1cEtleVNoYXJlJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2VuZGVyQWRkcmVzcyA9IGF3YWl0IHRoaXMuZ2V0QWRkcmVzc0Zyb21QdWJsaWNLZXkocHVibGljS2V5KTtcblxuICAgIGNvbnN0IGJhbGFuY2UgPSBuZXcgQmlnTnVtYmVyKGF3YWl0IHRoaXMuZ2V0QWNjb3VudEJhbGFuY2Uoc2VuZGVyQWRkcmVzcykpO1xuICAgIGNvbnN0IGZlZURhdGEgPSBuZXcgQmlnTnVtYmVyKHV0aWxzLmZlZURhdGEoKSk7XG4gICAgY29uc3QgYWN0dWFsQmFsYW5jZSA9IGJhbGFuY2UucGx1cyhmZWVEYXRhKTsgLy8gZ2FzIGFtb3VudCByZXR1cm5lZCBmcm9tIGdhc0RhdGEgaXMgbmVnYXRpdmUgc28gd2UgYWRkIGl0XG4gICAgaWYgKGFjdHVhbEJhbGFuY2UuaXNMZXNzVGhhbk9yRXF1YWxUbygwKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdEaWQgbm90IGhhdmUgZW5vdWdoIGZ1bmRzIHRvIHJlY292ZXInKTtcbiAgICB9XG5cbiAgICBjb25zdCBmYWN0b3J5ID0gdGhpcy5nZXRCdWlsZGVyRmFjdG9yeSgpO1xuICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0VHJhbnNmZXJCdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLnNlbmRlcihzZW5kZXJBZGRyZXNzLCBwdWJsaWNLZXkgYXMgc3RyaW5nKTtcbiAgICB0eEJ1aWxkZXIucmVjZWl2ZXJJZChwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbik7XG4gICAgdHhCdWlsZGVyLmFtb3VudChhY3R1YWxCYWxhbmNlLnRvU3RyaW5nKCkpO1xuICAgIGlmIChwYXJhbXMubWVtbyAhPT0gdW5kZWZpbmVkICYmIHV0aWxzLnZhbGlkYXRlTWVtbyhwYXJhbXMubWVtbykpIHtcbiAgICAgIHR4QnVpbGRlci5tZW1vKE51bWJlcihwYXJhbXMubWVtbykpO1xuICAgIH1cbiAgICBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBpZiAodHhCdWlsZGVyLnRyYW5zYWN0aW9uLnBheWxvYWRzRGF0YS5wYXlsb2Fkcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBwYXlsb2FkcyB0byBnZW5lcmF0ZSBzaWduYXR1cmVzJyk7XG4gICAgfVxuICAgIGNvbnN0IHNpZ25hdHVyZXMgPSBhd2FpdCB0aGlzLnNpZ25hdHVyZXMoXG4gICAgICB0eEJ1aWxkZXIudHJhbnNhY3Rpb24ucGF5bG9hZHNEYXRhLFxuICAgICAgcHVibGljS2V5LFxuICAgICAgdXNlcktleVNoYXJlLFxuICAgICAgYmFja3VwS2V5U2hhcmUsXG4gICAgICBjb21tb25LZXlDaGFpblxuICAgICk7XG4gICAgaWYgKCFzaWduYXR1cmVzIHx8IHNpZ25hdHVyZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZhaWxlZCB0byBnZW5lcmF0ZSBzaWduYXR1cmVzJyk7XG4gICAgfVxuICAgIHR4QnVpbGRlci50cmFuc2FjdGlvbi5hZGRTaWduYXR1cmUoc2lnbmF0dXJlcyk7XG4gICAgdHhCdWlsZGVyLmNvbWJpbmUoKTtcbiAgICBjb25zdCBicm9hZGNhc3RhYmxlVHhuID0gdHhCdWlsZGVyLnRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5icm9hZGNhc3RUcmFuc2FjdGlvbih7IHNlcmlhbGl6ZWRTaWduZWRUcmFuc2FjdGlvbjogYnJvYWRjYXN0YWJsZVR4biB9KTtcbiAgICBpZiAoIXJlc3VsdC50eElkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zYWN0aW9uIGZhaWxlZCB0byBicm9hZGNhc3QnKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdC50eElkO1xuICB9XG59XG4iXX0=

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


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