PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/@bitgo/sdk-coin-dot/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.Utils = void 0;
const sdk_core_1 = require("@bitgo/sdk-core");
const keyring_1 = require("@polkadot/keyring");
const decode_1 = require("@polkadot/keyring/pair/decode");
const types_1 = require("@polkadot/types");
const Extrinsic_1 = require("@polkadot/types/extrinsic/v4/Extrinsic");
const util_1 = require("@polkadot/util");
const util_crypto_1 = require("@polkadot/util-crypto");
const txwrapper_core_1 = require("@substrate/txwrapper-core");
const txwrapper_polkadot_1 = require("@substrate/txwrapper-polkadot");
const bs58_1 = __importDefault(require("bs58"));
const hi_base32_1 = __importDefault(require("hi-base32"));
const _ = __importStar(require("lodash"));
const tweetnacl_1 = __importDefault(require("tweetnacl"));
const _1 = require(".");
const resources_1 = require("../resources");
const PROXY_METHOD_ARG = 2;
// map to retrieve the address encoding format when the key is the asset name
const coinToAddressMap = new Map([
    ['dot', sdk_core_1.DotAddressFormat.polkadot],
    ['tdot', sdk_core_1.DotAddressFormat.substrate],
]);
class Utils {
    /** @inheritdoc */
    isValidAddress(address) {
        try {
            (0, keyring_1.encodeAddress)((0, util_1.isHex)(address) ? (0, util_1.hexToU8a)(address) : (0, keyring_1.decodeAddress)(address));
            return true;
        }
        catch (error) {
            return false;
        }
    }
    /** @inheritdoc */
    isValidBlockId(hash) {
        return (0, util_1.isHex)(hash, 256);
    }
    /** @inheritdoc */
    isValidPrivateKey(key) {
        try {
            const decodedPrv = (0, util_1.hexToU8a)(key);
            return decodedPrv.length === tweetnacl_1.default.sign.secretKeyLength / 2;
        }
        catch (e) {
            return false;
        }
    }
    /** @inheritdoc */
    isValidPublicKey(key) {
        let pubKey = key;
        // convert base58 pub key to hex format
        // tss common pub is in base58 format and decodes to length of 32
        if ((0, sdk_core_1.isBase58)(pubKey, 32)) {
            const base58Decode = bs58_1.default.decode(pubKey);
            pubKey = base58Decode.toString('hex');
        }
        return (0, sdk_core_1.isValidEd25519PublicKey)(pubKey);
    }
    /** @inheritdoc */
    isValidSignature(signature) {
        const signatureU8a = (0, util_1.u8aToU8a)(signature);
        return [64, 65, 66].includes(signatureU8a.length);
    }
    /**
     * Verifies the signature on a given message
     *
     * @param {string} signedMessage the signed message for the signature
     * @param {string} signature the signature to verify
     * @param {string} address the address of the signer
     * @returns {boolean} whether the signature is valid or not
     */
    verifySignature(signedMessage, signature, address) {
        const publicKey = (0, keyring_1.decodeAddress)(address);
        const hexPublicKey = (0, util_1.u8aToHex)(publicKey);
        return (0, util_crypto_1.signatureVerify)(signedMessage, signature, hexPublicKey).isValid;
    }
    /** @inheritdoc */
    isValidTransactionId(txId) {
        return (0, util_1.isHex)(txId, 256);
    }
    /**
     * decodeSeed decodes a dot seed
     *
     * @param {string} seed - the seed to be validated.
     * @returns {Seed} - the object Seed
     */
    decodeSeed(seed) {
        const decoded = hi_base32_1.default.decode.asBytes(seed);
        return {
            seed: Buffer.from(decoded),
        };
    }
    /**
     * Helper function to capitalize the first letter of a string
     *
     * @param {string} val
     * @returns {string}
     */
    capitalizeFirstLetter(val) {
        return val.charAt(0).toUpperCase() + val.slice(1);
    }
    /**
     * Helper function to decode the internal method hex in case of a proxy transaction
     *
     * @param {string | UnsignedTransaction} tx
     * @param { metadataRpc: string; registry: TypeRegistry } options
     * @returns {TransferArgs}
     */
    decodeCallMethod(tx, options) {
        const { registry } = options;
        let methodCall;
        if (typeof tx === 'string') {
            try {
                const payload = (0, types_1.createTypeUnsafe)(registry, 'ExtrinsicPayload', [
                    tx,
                    { version: Extrinsic_1.EXTRINSIC_VERSION },
                ]);
                methodCall = (0, types_1.createTypeUnsafe)(registry, 'Call', [payload.method]);
            }
            catch (e) {
                methodCall = registry.createType('Extrinsic', (0, util_1.hexToU8a)(tx), {
                    isSigned: true,
                });
            }
        }
        else {
            methodCall = registry.createType('Call', tx.method);
        }
        const method = methodCall.args[PROXY_METHOD_ARG];
        const decodedArgs = method.toJSON();
        return decodedArgs.args;
    }
    /**
     * keyPairFromSeed generates an object with secretKey and publicKey using the polkadot sdk
     * @param seed 32 bytes long seed
     * @returns KeyPair
     */
    keyPairFromSeed(seed) {
        const keyring = new keyring_1.Keyring({ type: 'ed25519' });
        const keyringPair = keyring.addFromSeed(seed);
        const pairJson = keyringPair.toJson();
        const decodedKeyPair = (0, decode_1.decodePair)('', (0, util_crypto_1.base64Decode)(pairJson.encoded), pairJson.encoding.type);
        return new _1.KeyPair({ prv: Buffer.from(decodedKeyPair.secretKey).toString('hex') });
    }
    /**
     * Signing function. Implement this on the OFFLINE signing device.
     *
     * @param {KeyringPair} pair - The signing pair.
     * @param {string} signingPayload - Payload to sign.
     * @param {UnsignedTransaction} transaction - raw transaction to sign
     * @param {Object} options
     * @param {HexString} options.metadataRpc - metadata that is needed for dot to sign
     * @param {TypeRegistry} options.registry - metadata that is needed for dot to sign
     */
    createSignedTx(pair, signingPayload, transaction, options) {
        const { registry, metadataRpc } = options;
        const { signature } = registry
            .createType('ExtrinsicPayload', signingPayload, {
            version: Extrinsic_1.EXTRINSIC_VERSION,
        })
            .sign(pair);
        // Serialize a signed transaction.
        return this.serializeSignedTransaction(transaction, signature, metadataRpc, registry);
    }
    /**
     * Serializes the signed transaction
     *
     * @param transaction Transaction to serialize
     * @param signature Signature of the message
     * @param metadataRpc Network metadata
     * @param registry Transaction registry
     * @returns string Serialized transaction
     */
    serializeSignedTransaction(transaction, signature, metadataRpc, registry) {
        return txwrapper_polkadot_1.construct.signedTx(transaction, signature, {
            metadataRpc,
            registry,
        });
    }
    /**
     * Decodes the dot address from the given format
     *
     * @param {string} address
     * @param {number} [ss58Format]
     * @returns {string}
     */
    decodeDotAddress(address, ss58Format) {
        const keypair = new _1.KeyPair({ pub: Buffer.from((0, keyring_1.decodeAddress)(address, undefined, ss58Format)).toString('hex') });
        return keypair.getAddress(ss58Format);
    }
    /**
     * Decodes the dot address from the given format
     *
     * @param {string} address
     * @param {number} [ss58Format]
     * @returns {string}
     */
    encodeDotAddress(address, ss58Format) {
        return (0, keyring_1.encodeAddress)(address, ss58Format);
    }
    /**
     * Retrieves the txHash of a signed txHex
     *
     * @param txHex signed transaction hex
     * @returns {string}
     */
    getTxHash(txHex) {
        return txwrapper_polkadot_1.construct.txHash(txHex);
    }
    getMaterial(coinConfig) {
        const networkConfig = coinConfig.network;
        const { specName, specVersion, chainName, txVersion, genesisHash } = networkConfig;
        const metadataRpc = networkConfig.specName === 'westend' ? resources_1.westendMetadataRpc : resources_1.mainnetMetadataRpc;
        return {
            specName,
            specVersion,
            chainName,
            metadata: metadataRpc,
            txVersion,
            genesisHash,
        };
    }
    isSigningPayload(payload) {
        return payload.blockHash !== undefined;
    }
    isProxyTransfer(arg) {
        return arg.real !== undefined;
    }
    isTransfer(arg) {
        return arg.dest?.id !== undefined && arg.value !== undefined;
    }
    isTransferAll(arg) {
        return arg.dest?.id !== undefined && arg.keepAlive !== undefined;
    }
    /**
     * Returns true if arg is of type BatchArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type BatchArgs, false otherwise.
     */
    isBatch(arg) {
        return arg.calls !== undefined;
    }
    /**
     * Returns true if arg is of type BatchArgs and the calls of the batch are staking calls: a stake
     * call (bond) followed by an add proxy call (addProxy), false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type BatchArgs and the calls of the batch are staking calls: a stake
     * call (bond) followed by an add proxy call (addProxy), false otherwise.
     */
    isStakingBatch(arg) {
        const calls = arg.calls;
        if (calls !== undefined) {
            return (calls.length === 2 &&
                (this.isStakeBatchCallArgs(calls[0].args) || this.isBondBatchExtra(calls[0].args)) &&
                this.isAddProxyBatchCallArgs(calls[1].args));
        }
        return false;
    }
    /**
     * Returns true if arg is of type StakeBatchCallArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type StakeBatchCallArgs, false otherwise.
     */
    isStakeBatchCallArgs(arg) {
        return arg.value !== undefined && arg.payee !== undefined;
    }
    /**
     * Returns true if arg is of type AddProxyBatchCallArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type AddProxyBatchCallArgs, false otherwise.
     */
    isAddProxyBatchCallArgs(arg) {
        return (arg.delegate !== undefined &&
            arg.proxy_type !== undefined &&
            arg.delay !== undefined);
    }
    /**
     * Returns true if arg is of type BatchArgs and the calls of the batch are unstaking calls: a remove
     * proxy call (removeProxy), followed by a chill call, and an unstake call (unbond), false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type BatchArgs and the calls of the batch are unstaking calls: a remove
     * proxy call (removeProxy), followed by a chill call, and an unstake call (unbond), false otherwise.
     */
    isUnstakingBatch(arg) {
        const calls = arg.calls;
        if (calls !== undefined) {
            return (calls.length === 3 &&
                this.isRemoveProxyBatchCallArgs(calls[0].args) &&
                _.isEmpty(calls[1].args) &&
                this.isUnstakeBatchCallArgs(calls[2].args));
        }
        return false;
    }
    /**
     * Returns true if arg is of type AddProxyBatchCallArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type AddProxyBatchCallArgs, false otherwise.
     */
    isRemoveProxyBatchCallArgs(arg) {
        return (arg.delegate !== undefined &&
            arg.proxy_type !== undefined &&
            arg.delay !== undefined);
    }
    /**
     * Returns true if arg is of type UnstakeBatchCallArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type UnstakeBatchCallArgs, false otherwise.
     */
    isUnstakeBatchCallArgs(arg) {
        return arg.value !== undefined;
    }
    /**
     * Returns true if arg is of type StakeArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type StakeArgs, false otherwise.
     */
    isBond(arg) {
        return arg.value !== undefined && arg.payee !== undefined;
    }
    /**
     * Returns true if arg is of type StakeMoreArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type StakeMoreArgs, false otherwise.
     */
    isBondExtra(arg) {
        return arg.maxAdditional !== undefined;
    }
    /**
     * Returns true if arg is of type StakeMoreArgs, false otherwise.
     *
     * @param arg The object to test.
     *
     * @return true if arg is of type StakeMoreArgs, false otherwise.
     */
    isBondBatchExtra(arg) {
        return arg.max_additional !== undefined;
    }
    /**
     * extracts and returns the signature in hex format given a raw signed transaction
     *
     * @param {string} rawTx signed raw transaction
     * @param options registry dot registry used to retrieve the signature
     */
    recoverSignatureFromRawTx(rawTx, options) {
        const { registry } = options;
        const methodCall = registry.createType('Extrinsic', rawTx, {
            isSigned: true,
        });
        let signature = (0, util_1.u8aToHex)(methodCall.signature);
        // remove 0x from the signature since this is how it's returned from TSS signing
        if (signature.startsWith('0x')) {
            signature = signature.substr(2);
        }
        return signature;
    }
    /**
     * Decodes the dot address from the given format
     *
     * @param {string} address
     * @param {number} [ss58Format]
     * @returns {KeyPair}
     */
    decodeDotAddressToKeyPair(address, ss58Format) {
        return new _1.KeyPair({ pub: Buffer.from((0, keyring_1.decodeAddress)(address, undefined, ss58Format)).toString('hex') });
    }
    /**
     * Checks whether the given input is a hex string with with 0 value
     * used to check whether a given transaction is immortal or mortal
     * @param hexValue
     */
    isZeroHex(hexValue) {
        return hexValue === '0x00';
    }
    /**
     * Takes an asset name and returns the respective address to format to
     * since polkadot addresses differ depending on the network
     * ref: https://wiki.polkadot.network/docs/learn-accounts
     * @param networkCoinName
     */
    getAddressFormat(networkCoinName) {
        return coinToAddressMap.get(networkCoinName);
    }
    /**
     * Creates a pure proxy extrinsic. Polkadot has renamed anonymous proxies to pure proxies, but
     * the libraries we are using to build transactions have not been updated, as a stop gap we are
     * defining the pure proxy extrinsic here.
     *
     * @param args Arguments to the createPure extrinsic.
     * @param info Common information to all transactions.
     * @param options Chain registry and metadata.
     */
    pureProxy(args, info, options) {
        return (0, txwrapper_core_1.defineMethod)({
            method: {
                args,
                name: 'createPure',
                pallet: 'proxy',
            },
            ...info,
        }, options);
    }
    /**
     * Removes '0x' from a given `string` if present.
     *
     * @param {string} str the string value.
     *
     * @return {string} a string without a '0x' prefix.
     */
    stripHexPrefix(str) {
        return this.isHexPrefixed(str) ? str.slice(2) : str;
    }
    /**
     * Returns true if a string starts with '0x', false otherwise.
     *
     * @param {string} str the string value.
     *
     * @return {boolean} true if a string starts with '0x', false otherwise.
     */
    isHexPrefixed(str) {
        return str.slice(0, 2) === '0x';
    }
}
exports.Utils = Utils;
const utils = new Utils();
exports.default = utils;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDhDQUFzSDtBQUV0SCwrQ0FBMEU7QUFDMUUsMERBQTJEO0FBRTNELDJDQUEyRztBQUMzRyxzRUFBMkU7QUFDM0UseUNBQXFFO0FBQ3JFLHVEQUFzRTtBQUN0RSw4REFBaUg7QUFFakgsc0VBQTBEO0FBQzFELGdEQUF3QjtBQUN4QiwwREFBK0I7QUFDL0IsMENBQTRCO0FBQzVCLDBEQUE2QjtBQWtCN0Isd0JBQTRCO0FBQzVCLDRDQUFzRTtBQUV0RSxNQUFNLGdCQUFnQixHQUFHLENBQUMsQ0FBQztBQUMzQiw2RUFBNkU7QUFDN0UsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLEdBQUcsQ0FBa0M7SUFDaEUsQ0FBQyxLQUFLLEVBQUUsMkJBQWdCLENBQUMsUUFBUSxDQUFDO0lBQ2xDLENBQUMsTUFBTSxFQUFFLDJCQUFnQixDQUFDLFNBQVMsQ0FBQztDQUNyQyxDQUFDLENBQUM7QUFFSCxNQUFhLEtBQUs7SUFDaEIsa0JBQWtCO0lBQ2xCLGNBQWMsQ0FBQyxPQUFlO1FBQzVCLElBQUksQ0FBQztZQUNILElBQUEsdUJBQWEsRUFBQyxJQUFBLFlBQUssRUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBQSxlQUFRLEVBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUEsdUJBQWEsRUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBQzNFLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7SUFDSCxDQUFDO0lBRUQsa0JBQWtCO0lBQ2xCLGNBQWMsQ0FBQyxJQUFZO1FBQ3pCLE9BQU8sSUFBQSxZQUFLLEVBQUMsSUFBSSxFQUFFLEdB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SUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3RELENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxhQUFhLENBQUMsR0FBVztRQUN2QixPQUFPLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQztJQUNsQyxDQUFDO0NBQ0Y7QUEzZEQsc0JBMmRDO0FBUUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQztBQUUxQixrQkFBZSxLQUFLLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEb3RBc3NldFR5cGVzLCBCYXNlVXRpbHMsIERvdEFkZHJlc3NGb3JtYXQsIGlzQmFzZTU4LCBpc1ZhbGlkRWQyNTUxOVB1YmxpY0tleSwgU2VlZCB9IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBCYXNlQ29pbiBhcyBDb2luQ29uZmlnLCBEb3ROZXR3b3JrIH0gZnJvbSAnQGJpdGdvL3N0YXRpY3MnO1xuaW1wb3J0IHsgZGVjb2RlQWRkcmVzcywgZW5jb2RlQWRkcmVzcywgS2V5cmluZyB9IGZyb20gJ0Bwb2xrYWRvdC9rZXlyaW5nJztcbmltcG9ydCB7IGRlY29kZVBhaXIgfSBmcm9tICdAcG9sa2Fkb3Qva2V5cmluZy9wYWlyL2RlY29kZSc7XG5pbXBvcnQgeyBLZXlyaW5nUGFpciB9IGZyb20gJ0Bwb2xrYWRvdC9rZXlyaW5nL3R5cGVzJztcbmltcG9ydCB7IGNyZWF0ZVR5cGVVbnNhZmUsIEdlbmVyaWNDYWxsLCBHZW5lcmljRXh0cmluc2ljLCBHZW5lcmljRXh0cmluc2ljUGF5bG9hZCB9IGZyb20gJ0Bwb2xrYWRvdC90eXBlcyc7XG5pbXBvcnQgeyBFWFRSSU5TSUNfVkVSU0lPTiB9IGZyb20gJ0Bwb2xrYWRvdC90eXBlcy9leHRyaW5zaWMvdjQvRXh0cmluc2ljJztcbmltcG9ydCB7IGhleFRvVThhLCBpc0hleCwgdThhVG9IZXgsIHU4YVRvVThhIH0gZnJvbSAnQHBvbGthZG90L3V0aWwnO1xuaW1wb3J0IHsgYmFzZTY0RGVjb2RlLCBzaWduYXR1cmVWZXJpZnkgfSBmcm9tICdAcG9sa2Fkb3QvdXRpbC1jcnlwdG8nO1xuaW1wb3J0IHsgQXJncywgQmFzZVR4SW5mbywgZGVmaW5lTWV0aG9kLCBPcHRpb25zV2l0aE1ldGEsIFVuc2lnbmVkVHJhbnNhY3Rpb24gfSBmcm9tICdAc3Vic3RyYXRlL3R4d3JhcHBlci1jb3JlJztcbmltcG9ydCB7IERlY29kZWRTaWduZWRUeCwgRGVjb2RlZFNpZ25pbmdQYXlsb2FkLCBUeXBlUmVnaXN0cnkgfSBmcm9tICdAc3Vic3RyYXRlL3R4d3JhcHBlci1jb3JlL2xpYi90eXBlcyc7XG5pbXBvcnQgeyBjb25zdHJ1Y3QgfSBmcm9tICdAc3Vic3RyYXRlL3R4d3JhcHBlci1wb2xrYWRvdCc7XG5pbXBvcnQgYnM1OCBmcm9tICdiczU4JztcbmltcG9ydCBiYXNlMzIgZnJvbSAnaGktYmFzZTMyJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBuYWNsIGZyb20gJ3R3ZWV0bmFjbCc7XG5pbXBvcnQge1xuICBBZGRQcm94eUJhdGNoQ2FsbEFyZ3MsXG4gIEJhdGNoQXJncyxcbiAgQmF0Y2hDYWxsT2JqZWN0LFxuICBIZXhTdHJpbmcsXG4gIE1hdGVyaWFsLFxuICBQcm94eUFyZ3MsXG4gIFByb3h5Q2FsbEFyZ3MsXG4gIFN0YWtlQXJncyxcbiAgU3Rha2VCYXRjaENhbGxBcmdzLFxuICBTdGFrZU1vcmVBcmdzLFxuICBTdGFrZU1vcmVDYWxsQXJncyxcbiAgVHJhbnNmZXJBbGxBcmdzLFxuICBUcmFuc2ZlckFyZ3MsXG4gIFR4TWV0aG9kLFxuICBVbnN0YWtlQmF0Y2hDYWxsQXJncyxcbn0gZnJvbSAnLi9pZmFjZSc7XG5pbXBvcnQgeyBLZXlQYWlyIH0gZnJvbSAnLic7XG5pbXBvcnQgeyBtYWlubmV0TWV0YWRhdGFScGMsIHdlc3RlbmRNZXRhZGF0YVJwYyB9IGZyb20gJy4uL3Jlc291cmNlcyc7XG5cbmNvbnN0IFBST1hZX01FVEhPRF9BUkcgPSAyO1xuLy8gbWFwIHRvIHJldHJpZXZlIHRoZSBhZGRyZXNzIGVuY29kaW5nIGZvcm1hdCB3aGVuIHRoZSBrZXkgaXMgdGhlIGFzc2V0IG5hbWVcbmNvbnN0IGNvaW5Ub0FkZHJlc3NNYXAgPSBuZXcgTWFwPERvdEFzc2V0VHlwZXMsIERvdEFkZHJlc3NGb3JtYXQ+KFtcbiAgWydkb3QnLCBEb3RBZGRyZXNzRm9ybWF0LnBvbGthZG90XSxcbiAgWyd0ZG90JywgRG90QWRkcmVzc0Zvcm1hdC5zdWJzdHJhdGVdLFxuXSk7XG5cbmV4cG9ydCBjbGFzcyBVdGlscyBpbXBsZW1lbnRzIEJhc2VVdGlscyB7XG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkQWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgZW5jb2RlQWRkcmVzcyhpc0hleChhZGRyZXNzKSA/IGhleFRvVThhKGFkZHJlc3MpIDogZGVjb2RlQWRkcmVzcyhhZGRyZXNzKSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkQmxvY2tJZChoYXNoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gaXNIZXgoaGFzaCwgMjU2KTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkUHJpdmF0ZUtleShrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBkZWNvZGVkUHJ2ID0gaGV4VG9VOGEoa2V5KTtcbiAgICAgIHJldHVybiBkZWNvZGVkUHJ2Lmxlbmd0aCA9PT0gbmFjbC5zaWduLnNlY3JldEtleUxlbmd0aCAvIDI7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkUHVibGljS2V5KGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgbGV0IHB1YktleSA9IGtleTtcblxuICAgIC8vIGNvbnZlcnQgYmFzZTU4IHB1YiBrZXkgdG8gaGV4IGZvcm1hdFxuICAgIC8vIHRzcyBjb21tb24gcHViIGlzIGluIGJhc2U1OCBmb3JtYXQgYW5kIGRlY29kZXMgdG8gbGVuZ3RoIG9mIDMyXG4gICAgaWYgKGlzQmFzZTU4KHB1YktleSwgMzIpKSB7XG4gICAgICBjb25zdCBiYXNlNThEZWNvZGUgPSBiczU4LmRlY29kZShwdWJLZXkpO1xuICAgICAgcHViS2V5ID0gYmFzZTU4RGVjb2RlLnRvU3RyaW5nKCdoZXgnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gaXNWYWxpZEVkMjU1MTlQdWJsaWNLZXkocHViS2V5KTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkU2lnbmF0dXJlKHNpZ25hdHVyZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgY29uc3Qgc2lnbmF0dXJlVThhID0gdThhVG9VOGEoc2lnbmF0dXJlKTtcbiAgICByZXR1cm4gWzY0LCA2NSwgNjZdLmluY2x1ZGVzKHNpZ25hdHVyZVU4YS5sZW5ndGgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIHRoZSBzaWduYXR1cmUgb24gYSBnaXZlbiBtZXNzYWdlXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzaWduZWRNZXNzYWdlIHRoZSBzaWduZWQgbWVzc2FnZSBmb3IgdGhlIHNpZ25hdHVyZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2lnbmF0dXJlIHRoZSBzaWduYXR1cmUgdG8gdmVyaWZ5XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIHRoZSBhZGRyZXNzIG9mIHRoZSBzaWduZXJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IHdoZXRoZXIgdGhlIHNpZ25hdHVyZSBpcyB2YWxpZCBvciBub3RcbiAgICovXG4gIHZlcmlmeVNpZ25hdHVyZShzaWduZWRNZXNzYWdlOiBzdHJpbmcsIHNpZ25hdHVyZTogc3RyaW5nLCBhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBwdWJsaWNLZXkgPSBkZWNvZGVBZGRyZXNzKGFkZHJlc3MpO1xuICAgIGNvbnN0IGhleFB1YmxpY0tleSA9IHU4YVRvSGV4KHB1YmxpY0tleSk7XG5cbiAgICByZXR1cm4gc2lnbmF0dXJlVmVyaWZ5KHNpZ25lZE1lc3NhZ2UsIHNpZ25hdHVyZSwgaGV4UHVibGljS2V5KS5pc1ZhbGlkO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIGlzVmFsaWRUcmFuc2FjdGlvbklkKHR4SWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBpc0hleCh0eElkLCAyNTYpO1xuICB9XG5cbiAgLyoqXG4gICAqIGRlY29kZVNlZWQgZGVjb2RlcyBhIGRvdCBzZWVkXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzZWVkIC0gdGhlIHNlZWQgdG8gYmUgdmFsaWRhdGVkLlxuICAgKiBAcmV0dXJucyB7U2VlZH0gLSB0aGUgb2JqZWN0IFNlZWRcbiAgICovXG4gIGRlY29kZVNlZWQoc2VlZDogc3RyaW5nKTogU2VlZCB7XG4gICAgY29uc3QgZGVjb2RlZCA9IGJhc2UzMi5kZWNvZGUuYXNCeXRlcyhzZWVkKTtcbiAgICByZXR1cm4ge1xuICAgICAgc2VlZDogQnVmZmVyLmZyb20oZGVjb2RlZCksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gdG8gY2FwaXRhbGl6ZSB0aGUgZmlyc3QgbGV0dGVyIG9mIGEgc3RyaW5nXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB2YWxcbiAgICogQHJldHVybnMge3N0cmluZ31cbiAgICovXG4gIGNhcGl0YWxpemVGaXJzdExldHRlcih2YWw6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHZhbC5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHZhbC5zbGljZSgxKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gdG8gZGVjb2RlIHRoZSBpbnRlcm5hbCBtZXRob2QgaGV4IGluIGNhc2Ugb2YgYSBwcm94eSB0cmFuc2FjdGlvblxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IFVuc2lnbmVkVHJhbnNhY3Rpb259IHR4XG4gICAqIEBwYXJhbSB7IG1ldGFkYXRhUnBjOiBzdHJpbmc7IHJlZ2lzdHJ5OiBUeXBlUmVnaXN0cnkgfSBvcHRpb25zXG4gICAqIEByZXR1cm5zIHtUcmFuc2ZlckFyZ3N9XG4gICAqL1xuICBkZWNvZGVDYWxsTWV0aG9kKFxuICAgIHR4OiBzdHJpbmcgfCBVbnNpZ25lZFRyYW5zYWN0aW9uLFxuICAgIG9wdGlvbnM6IHsgbWV0YWRhdGFScGM6IHN0cmluZzsgcmVnaXN0cnk6IFR5cGVSZWdpc3RyeSB9XG4gICk6IFRyYW5zZmVyQXJncyB7XG4gICAgY29uc3QgeyByZWdpc3RyeSB9ID0gb3B0aW9ucztcbiAgICBsZXQgbWV0aG9kQ2FsbDogR2VuZXJpY0NhbGwgfCBHZW5lcmljRXh0cmluc2ljO1xuICAgIGlmICh0eXBlb2YgdHggPT09ICdzdHJpbmcnKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBwYXlsb2FkOiBHZW5lcmljRXh0cmluc2ljUGF5bG9hZCA9IGNyZWF0ZVR5cGVVbnNhZmUocmVnaXN0cnksICdFeHRyaW5zaWNQYXlsb2FkJywgW1xuICAgICAgICAgIHR4LFxuICAgICAgICAgIHsgdmVyc2lvbjogRVhUUklOU0lDX1ZFUlNJT04gfSxcbiAgICAgICAgXSk7XG4gICAgICAgIG1ldGhvZENhbGwgPSBjcmVhdGVUeXBlVW5zYWZlKHJlZ2lzdHJ5LCAnQ2FsbCcsIFtwYXlsb2FkLm1ldGhvZF0pO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBtZXRob2RDYWxsID0gcmVnaXN0cnkuY3JlYXRlVHlwZSgnRXh0cmluc2ljJywgaGV4VG9VOGEodHgpLCB7XG4gICAgICAgICAgaXNTaWduZWQ6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBtZXRob2RDYWxsID0gcmVnaXN0cnkuY3JlYXRlVHlwZSgnQ2FsbCcsIHR4Lm1ldGhvZCk7XG4gICAgfVxuICAgIGNvbnN0IG1ldGhvZCA9IG1ldGhvZENhbGwuYXJnc1tQUk9YWV9NRVRIT0RfQVJHXTtcbiAgICBjb25zdCBkZWNvZGVkQXJncyA9IG1ldGhvZC50b0pTT04oKSBhcyB1bmtub3duIGFzIFByb3h5Q2FsbEFyZ3M7XG4gICAgcmV0dXJuIGRlY29kZWRBcmdzLmFyZ3M7XG4gIH1cblxuICAvKipcbiAgICoga2V5UGFpckZyb21TZWVkIGdlbmVyYXRlcyBhbiBvYmplY3Qgd2l0aCBzZWNyZXRLZXkgYW5kIHB1YmxpY0tleSB1c2luZyB0aGUgcG9sa2Fkb3Qgc2RrXG4gICAqIEBwYXJhbSBzZWVkIDMyIGJ5dGVzIGxvbmcgc2VlZFxuICAgKiBAcmV0dXJucyBLZXlQYWlyXG4gICAqL1xuICBrZXlQYWlyRnJvbVNlZWQoc2VlZDogVWludDhBcnJheSk6IEtleVBhaXIge1xuICAgIGNvbnN0IGtleXJpbmcgPSBuZXcgS2V5cmluZyh7IHR5cGU6ICdlZDI1NTE5JyB9KTtcbiAgICBjb25zdCBrZXlyaW5nUGFpciA9IGtleXJpbmcuYWRkRnJvbVNlZWQoc2VlZCk7XG4gICAgY29uc3QgcGFpckpzb24gPSBrZXlyaW5nUGFpci50b0pzb24oKTtcbiAgICBjb25zdCBkZWNvZGVkS2V5UGFpciA9IGRlY29kZVBhaXIoJycsIGJhc2U2NERlY29kZShwYWlySnNvbi5lbmNvZGVkKSwgcGFpckpzb24uZW5jb2RpbmcudHlwZSk7XG4gICAgcmV0dXJuIG5ldyBLZXlQYWlyKHsgcHJ2OiBCdWZmZXIuZnJvbShkZWNvZGVkS2V5UGFpci5zZWNyZXRLZXkpLnRvU3RyaW5nKCdoZXgnKSB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTaWduaW5nIGZ1bmN0aW9uLiBJbXBsZW1lbnQgdGhpcyBvbiB0aGUgT0ZGTElORSBzaWduaW5nIGRldmljZS5cbiAgICpcbiAgICogQHBhcmFtIHtLZXlyaW5nUGFpcn0gcGFpciAtIFRoZSBzaWduaW5nIHBhaXIuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzaWduaW5nUGF5bG9hZCAtIFBheWxvYWQgdG8gc2lnbi5cbiAgICogQHBhcmFtIHtVbnNpZ25lZFRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvbiAtIHJhdyB0cmFuc2FjdGlvbiB0byBzaWduXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gICAqIEBwYXJhbSB7SGV4U3RyaW5nfSBvcHRpb25zLm1ldGFkYXRhUnBjIC0gbWV0YWRhdGEgdGhhdCBpcyBuZWVkZWQgZm9yIGRvdCB0byBzaWduXG4gICAqIEBwYXJhbSB7VHlwZVJlZ2lzdHJ5fSBvcHRpb25zLnJlZ2lzdHJ5IC0gbWV0YWRhdGEgdGhhdCBpcyBuZWVkZWQgZm9yIGRvdCB0byBzaWduXG4gICAqL1xuICBjcmVhdGVTaWduZWRUeChcbiAgICBwYWlyOiBLZXlyaW5nUGFpcixcbiAgICBzaWduaW5nUGF5bG9hZDogc3RyaW5nLFxuICAgIHRyYW5zYWN0aW9uOiBVbnNpZ25lZFRyYW5zYWN0aW9uLFxuICAgIG9wdGlvbnM6IHsgbWV0YWRhdGFScGM6IEhleFN0cmluZzsgcmVnaXN0cnk6IFR5cGVSZWdpc3RyeSB9XG4gICk6IHN0cmluZyB7XG4gICAgY29uc3QgeyByZWdpc3RyeSwgbWV0YWRhdGFScGMgfSA9IG9wdGlvbnM7XG4gICAgY29uc3QgeyBzaWduYXR1cmUgfSA9IHJlZ2lzdHJ5XG4gICAgICAuY3JlYXRlVHlwZSgnRXh0cmluc2ljUGF5bG9hZCcsIHNpZ25pbmdQYXlsb2FkLCB7XG4gICAgICAgIHZlcnNpb246IEVYVFJJTlNJQ19WRVJTSU9OLFxuICAgICAgfSlcbiAgICAgIC5zaWduKHBhaXIpO1xuXG4gICAgLy8gU2VyaWFsaXplIGEgc2lnbmVkIHRyYW5zYWN0aW9uLlxuICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZVNpZ25lZFRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uLCBzaWduYXR1cmUsIG1ldGFkYXRhUnBjLCByZWdpc3RyeSk7XG4gIH1cblxuICAvKipcbiAgICogU2VyaWFsaXplcyB0aGUgc2lnbmVkIHRyYW5zYWN0aW9uXG4gICAqXG4gICAqIEBwYXJhbSB0cmFuc2FjdGlvbiBUcmFuc2FjdGlvbiB0byBzZXJpYWxpemVcbiAgICogQHBhcmFtIHNpZ25hdHVyZSBTaWduYXR1cmUgb2YgdGhlIG1lc3NhZ2VcbiAgICogQHBhcmFtIG1ldGFkYXRhUnBjIE5ldHdvcmsgbWV0YWRhdGFcbiAgICogQHBhcmFtIHJlZ2lzdHJ5IFRyYW5zYWN0aW9uIHJlZ2lzdHJ5XG4gICAqIEByZXR1cm5zIHN0cmluZyBTZXJpYWxpemVkIHRyYW5zYWN0aW9uXG4gICAqL1xuICBzZXJpYWxpemVTaWduZWRUcmFuc2FjdGlvbih0cmFuc2FjdGlvbiwgc2lnbmF0dXJlLCBtZXRhZGF0YVJwYzogYDB4JHtzdHJpbmd9YCwgcmVnaXN0cnkpOiBzdHJpbmcge1xuICAgIHJldHVybiBjb25zdHJ1Y3Quc2lnbmVkVHgodHJhbnNhY3Rpb24sIHNpZ25hdHVyZSwge1xuICAgICAgbWV0YWRhdGFScGMsXG4gICAgICByZWdpc3RyeSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNvZGVzIHRoZSBkb3QgYWRkcmVzcyBmcm9tIHRoZSBnaXZlbiBmb3JtYXRcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3NcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtzczU4Rm9ybWF0XVxuICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgKi9cbiAgZGVjb2RlRG90QWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcsIHNzNThGb3JtYXQ6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3Qga2V5cGFpciA9IG5ldyBLZXlQYWlyKHsgcHViOiBCdWZmZXIuZnJvbShkZWNvZGVBZGRyZXNzKGFkZHJlc3MsIHVuZGVmaW5lZCwgc3M1OEZvcm1hdCkpLnRvU3RyaW5nKCdoZXgnKSB9KTtcbiAgICByZXR1cm4ga2V5cGFpci5nZXRBZGRyZXNzKHNzNThGb3JtYXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZXMgdGhlIGRvdCBhZGRyZXNzIGZyb20gdGhlIGdpdmVuIGZvcm1hdFxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzc1xuICAgKiBAcGFyYW0ge251bWJlcn0gW3NzNThGb3JtYXRdXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9XG4gICAqL1xuICBlbmNvZGVEb3RBZGRyZXNzKGFkZHJlc3M6IHN0cmluZywgc3M1OEZvcm1hdD86IG51bWJlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGVuY29kZUFkZHJlc3MoYWRkcmVzcywgc3M1OEZvcm1hdCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSB0eEhhc2ggb2YgYSBzaWduZWQgdHhIZXhcbiAgICpcbiAgICogQHBhcmFtIHR4SGV4IHNpZ25lZCB0cmFuc2FjdGlvbiBoZXhcbiAgICogQHJldHVybnMge3N0cmluZ31cbiAgICovXG4gIGdldFR4SGFzaCh0eEhleDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY29uc3RydWN0LnR4SGFzaCh0eEhleCk7XG4gIH1cblxuICBnZXRNYXRlcmlhbChjb2luQ29uZmlnOiBSZWFkb25seTxDb2luQ29uZmlnPik6IE1hdGVyaWFsIHtcbiAgICBjb25zdCBuZXR3b3JrQ29uZmlnID0gY29pbkNvbmZpZy5uZXR3b3JrIGFzIERvdE5ldHdvcms7XG4gICAgY29uc3QgeyBzcGVjTmFtZSwgc3BlY1ZlcnNpb24sIGNoYWluTmFtZSwgdHhWZXJzaW9uLCBnZW5lc2lzSGFzaCB9ID0gbmV0d29ya0NvbmZpZztcbiAgICBjb25zdCBtZXRhZGF0YVJwYyA9IG5ldHdvcmtDb25maWcuc3BlY05hbWUgPT09ICd3ZXN0ZW5kJyA/IHdlc3RlbmRNZXRhZGF0YVJwYyA6IG1haW5uZXRNZXRhZGF0YVJwYztcblxuICAgIHJldHVybiB7XG4gICAgICBzcGVjTmFtZSxcbiAgICAgIHNwZWNWZXJzaW9uLFxuICAgICAgY2hhaW5OYW1lLFxuICAgICAgbWV0YWRhdGE6IG1ldGFkYXRhUnBjLFxuICAgICAgdHhWZXJzaW9uLFxuICAgICAgZ2VuZXNpc0hhc2gsXG4gICAgfSBhcyBNYXRlcmlhbDtcbiAgfVxuXG4gIGlzU2lnbmluZ1BheWxvYWQocGF5bG9hZDogRGVjb2RlZFNpZ25pbmdQYXlsb2FkIHwgRGVjb2RlZFNpZ25lZFR4KTogcGF5bG9hZCBpcyBEZWNvZGVkU2lnbmluZ1BheWxvYWQge1xuICAgIHJldHVybiAocGF5bG9hZCBhcyBEZWNvZGVkU2lnbmluZ1BheWxvYWQpLmJsb2NrSGFzaCAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgaXNQcm94eVRyYW5zZmVyKGFyZzogVHhNZXRob2RbJ2FyZ3MnXSk6IGFyZyBpcyBQcm94eUFyZ3Mge1xuICAgIHJldHVybiAoYXJnIGFzIFByb3h5QXJncykucmVhbCAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgaXNUcmFuc2Zlcihhcmc6IFR4TWV0aG9kWydhcmdzJ10pOiBhcmcgaXMgVHJhbnNmZXJBcmdzIHtcbiAgICByZXR1cm4gKGFyZyBhcyBUcmFuc2ZlckFyZ3MpLmRlc3Q/LmlkICE9PSB1bmRlZmluZWQgJiYgKGFyZyBhcyBUcmFuc2ZlckFyZ3MpLnZhbHVlICE9PSB1bmRlZmluZWQ7XG4gIH1cblxuICBpc1RyYW5zZmVyQWxsKGFyZzogVHhNZXRob2RbJ2FyZ3MnXSk6IGFyZyBpcyBUcmFuc2ZlckFsbEFyZ3Mge1xuICAgIHJldHVybiAoYXJnIGFzIFRyYW5zZmVyQWxsQXJncykuZGVzdD8uaWQgIT09IHVuZGVmaW5lZCAmJiAoYXJnIGFzIFRyYW5zZmVyQWxsQXJncykua2VlcEFsaXZlICE9PSB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGFyZyBpcyBvZiB0eXBlIEJhdGNoQXJncywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAcGFyYW0gYXJnIFRoZSBvYmplY3QgdG8gdGVzdC5cbiAgICpcbiAgICogQHJldHVybiB0cnVlIGlmIGFyZyBpcyBvZiB0eXBlIEJhdGNoQXJncywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNCYXRjaChhcmc6IFR4TWV0aG9kWydhcmdzJ10pOiBhcmcgaXMgQmF0Y2hBcmdzIHtcbiAgICByZXR1cm4gKGFyZyBhcyBCYXRjaEFyZ3MpLmNhbGxzICE9PSB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGFyZyBpcyBvZiB0eXBlIEJhdGNoQXJncyBhbmQgdGhlIGNhbGxzIG9mIHRoZSBiYXRjaCBhcmUgc3Rha2luZyBjYWxsczogYSBzdGFrZVxuICAgKiBjYWxsIChib25kKSBmb2xsb3dlZCBieSBhbiBhZGQgcHJveHkgY2FsbCAoYWRkUHJveHkpLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqXG4gICAqIEBwYXJhbSBhcmcgVGhlIG9iamVjdCB0byB0ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgQmF0Y2hBcmdzIGFuZCB0aGUgY2FsbHMgb2YgdGhlIGJhdGNoIGFyZSBzdGFraW5nIGNhbGxzOiBhIHN0YWtlXG4gICAqIGNhbGwgKGJvbmQpIGZvbGxvd2VkIGJ5IGFuIGFkZCBwcm94eSBjYWxsIChhZGRQcm94eSksIGZhbHNlIG90aGVyd2lzZS5cbiAgICovXG4gIGlzU3Rha2luZ0JhdGNoKGFyZzogVHhNZXRob2RbJ2FyZ3MnXSk6IGFyZyBpcyBCYXRjaEFyZ3Mge1xuICAgIGNvbnN0IGNhbGxzID0gKGFyZyBhcyBCYXRjaEFyZ3MpLmNhbGxzO1xuICAgIGlmIChjYWxscyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gKFxuICAgICAgICBjYWxscy5sZW5ndGggPT09IDIgJiZcbiAgICAgICAgKHRoaXMuaXNTdGFrZUJhdGNoQ2FsbEFyZ3MoY2FsbHNbMF0uYXJncykgfHwgdGhpcy5pc0JvbmRCYXRjaEV4dHJhKGNhbGxzWzBdLmFyZ3MpKSAmJlxuICAgICAgICB0aGlzLmlzQWRkUHJveHlCYXRjaENhbGxBcmdzKGNhbGxzWzFdLmFyZ3MpXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGFyZyBpcyBvZiB0eXBlIFN0YWtlQmF0Y2hDYWxsQXJncywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAcGFyYW0gYXJnIFRoZSBvYmplY3QgdG8gdGVzdC5cbiAgICpcbiAgICogQHJldHVybiB0cnVlIGlmIGFyZyBpcyBvZiB0eXBlIFN0YWtlQmF0Y2hDYWxsQXJncywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNTdGFrZUJhdGNoQ2FsbEFyZ3MoYXJnOiBCYXRjaENhbGxPYmplY3RbJ2FyZ3MnXSk6IGFyZyBpcyBTdGFrZUJhdGNoQ2FsbEFyZ3Mge1xuICAgIHJldHVybiAoYXJnIGFzIFN0YWtlQmF0Y2hDYWxsQXJncykudmFsdWUgIT09IHVuZGVmaW5lZCAmJiAoYXJnIGFzIFN0YWtlQmF0Y2hDYWxsQXJncykucGF5ZWUgIT09IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgQWRkUHJveHlCYXRjaENhbGxBcmdzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqXG4gICAqIEBwYXJhbSBhcmcgVGhlIG9iamVjdCB0byB0ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgQWRkUHJveHlCYXRjaENhbGxBcmdzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqL1xuICBpc0FkZFByb3h5QmF0Y2hDYWxsQXJncyhhcmc6IEJhdGNoQ2FsbE9iamVjdFsnYXJncyddKTogYXJnIGlzIEFkZFByb3h5QmF0Y2hDYWxsQXJncyB7XG4gICAgcmV0dXJuIChcbiAgICAgIChhcmcgYXMgQWRkUHJveHlCYXRjaENhbGxBcmdzKS5kZWxlZ2F0ZSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAoYXJnIGFzIEFkZFByb3h5QmF0Y2hDYWxsQXJncykucHJveHlfdHlwZSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAoYXJnIGFzIEFkZFByb3h5QmF0Y2hDYWxsQXJncykuZGVsYXkgIT09IHVuZGVmaW5lZFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGFyZyBpcyBvZiB0eXBlIEJhdGNoQXJncyBhbmQgdGhlIGNhbGxzIG9mIHRoZSBiYXRjaCBhcmUgdW5zdGFraW5nIGNhbGxzOiBhIHJlbW92ZVxuICAgKiBwcm94eSBjYWxsIChyZW1vdmVQcm94eSksIGZvbGxvd2VkIGJ5IGEgY2hpbGwgY2FsbCwgYW5kIGFuIHVuc3Rha2UgY2FsbCAodW5ib25kKSwgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAcGFyYW0gYXJnIFRoZSBvYmplY3QgdG8gdGVzdC5cbiAgICpcbiAgICogQHJldHVybiB0cnVlIGlmIGFyZyBpcyBvZiB0eXBlIEJhdGNoQXJncyBhbmQgdGhlIGNhbGxzIG9mIHRoZSBiYXRjaCBhcmUgdW5zdGFraW5nIGNhbGxzOiBhIHJlbW92ZVxuICAgKiBwcm94eSBjYWxsIChyZW1vdmVQcm94eSksIGZvbGxvd2VkIGJ5IGEgY2hpbGwgY2FsbCwgYW5kIGFuIHVuc3Rha2UgY2FsbCAodW5ib25kKSwgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNVbnN0YWtpbmdCYXRjaChhcmc6IFR4TWV0aG9kWydhcmdzJ10pOiBhcmcgaXMgQmF0Y2hBcmdzIHtcbiAgICBjb25zdCBjYWxscyA9IChhcmcgYXMgQmF0Y2hBcmdzKS5jYWxscztcbiAgICBpZiAoY2FsbHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgY2FsbHMubGVuZ3RoID09PSAzICYmXG4gICAgICAgIHRoaXMuaXNSZW1vdmVQcm94eUJhdGNoQ2FsbEFyZ3MoY2FsbHNbMF0uYXJncykgJiZcbiAgICAgICAgXy5pc0VtcHR5KGNhbGxzWzFdLmFyZ3MpICYmXG4gICAgICAgIHRoaXMuaXNVbnN0YWtlQmF0Y2hDYWxsQXJncyhjYWxsc1syXS5hcmdzKVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBhcmcgaXMgb2YgdHlwZSBBZGRQcm94eUJhdGNoQ2FsbEFyZ3MsIGZhbHNlIG90aGVyd2lzZS5cbiAgICpcbiAgICogQHBhcmFtIGFyZyBUaGUgb2JqZWN0IHRvIHRlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gdHJ1ZSBpZiBhcmcgaXMgb2YgdHlwZSBBZGRQcm94eUJhdGNoQ2FsbEFyZ3MsIGZhbHNlIG90aGVyd2lzZS5cbiAgICovXG4gIGlzUmVtb3ZlUHJveHlCYXRjaENhbGxBcmdzKGFyZzogQmF0Y2hDYWxsT2JqZWN0WydhcmdzJ10pOiBhcmcgaXMgQWRkUHJveHlCYXRjaENhbGxBcmdzIHtcbiAgICByZXR1cm4gKFxuICAgICAgKGFyZyBhcyBBZGRQcm94eUJhdGNoQ2FsbEFyZ3MpLmRlbGVnYXRlICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIChhcmcgYXMgQWRkUHJveHlCYXRjaENhbGxBcmdzKS5wcm94eV90eXBlICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIChhcmcgYXMgQWRkUHJveHlCYXRjaENhbGxBcmdzKS5kZWxheSAhPT0gdW5kZWZpbmVkXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgVW5zdGFrZUJhdGNoQ2FsbEFyZ3MsIGZhbHNlIG90aGVyd2lzZS5cbiAgICpcbiAgICogQHBhcmFtIGFyZyBUaGUgb2JqZWN0IHRvIHRlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gdHJ1ZSBpZiBhcmcgaXMgb2YgdHlwZSBVbnN0YWtlQmF0Y2hDYWxsQXJncywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNVbnN0YWtlQmF0Y2hDYWxsQXJncyhhcmc6IEJhdGNoQ2FsbE9iamVjdFsnYXJncyddKTogYXJnIGlzIFVuc3Rha2VCYXRjaENhbGxBcmdzIHtcbiAgICByZXR1cm4gKGFyZyBhcyBVbnN0YWtlQmF0Y2hDYWxsQXJncykudmFsdWUgIT09IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgU3Rha2VBcmdzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqXG4gICAqIEBwYXJhbSBhcmcgVGhlIG9iamVjdCB0byB0ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgU3Rha2VBcmdzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqL1xuICBpc0JvbmQoYXJnOiBUeE1ldGhvZFsnYXJncyddKTogYXJnIGlzIFN0YWtlQXJncyB7XG4gICAgcmV0dXJuIChhcmcgYXMgU3Rha2VBcmdzKS52YWx1ZSAhPT0gdW5kZWZpbmVkICYmIChhcmcgYXMgU3Rha2VBcmdzKS5wYXllZSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBhcmcgaXMgb2YgdHlwZSBTdGFrZU1vcmVBcmdzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqXG4gICAqIEBwYXJhbSBhcmcgVGhlIG9iamVjdCB0byB0ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgU3Rha2VNb3JlQXJncywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNCb25kRXh0cmEoYXJnOiBUeE1ldGhvZFsnYXJncyddIHwgQmF0Y2hDYWxsT2JqZWN0WydhcmdzJ10pOiBhcmcgaXMgU3Rha2VNb3JlQXJncyB7XG4gICAgcmV0dXJuIChhcmcgYXMgU3Rha2VNb3JlQXJncykubWF4QWRkaXRpb25hbCAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBhcmcgaXMgb2YgdHlwZSBTdGFrZU1vcmVBcmdzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqXG4gICAqIEBwYXJhbSBhcmcgVGhlIG9iamVjdCB0byB0ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIHRydWUgaWYgYXJnIGlzIG9mIHR5cGUgU3Rha2VNb3JlQXJncywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNCb25kQmF0Y2hFeHRyYShhcmc6IEJhdGNoQ2FsbE9iamVjdFsnYXJncyddKTogYXJnIGlzIFN0YWtlTW9yZUNhbGxBcmdzIHtcbiAgICByZXR1cm4gKGFyZyBhcyBTdGFrZU1vcmVDYWxsQXJncykubWF4X2FkZGl0aW9uYWwgIT09IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBleHRyYWN0cyBhbmQgcmV0dXJucyB0aGUgc2lnbmF0dXJlIGluIGhleCBmb3JtYXQgZ2l2ZW4gYSByYXcgc2lnbmVkIHRyYW5zYWN0aW9uXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByYXdUeCBzaWduZWQgcmF3IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBvcHRpb25zIHJlZ2lzdHJ5IGRvdCByZWdpc3RyeSB1c2VkIHRvIHJldHJpZXZlIHRoZSBzaWduYXR1cmVcbiAgICovXG4gIHJlY292ZXJTaWduYXR1cmVGcm9tUmF3VHgocmF3VHg6IHN0cmluZywgb3B0aW9uczogeyByZWdpc3RyeTogVHlwZVJlZ2lzdHJ5IH0pOiBzdHJpbmcge1xuICAgIGNvbnN0IHsgcmVnaXN0cnkgfSA9IG9wdGlvbnM7XG4gICAgY29uc3QgbWV0aG9kQ2FsbCA9IHJlZ2lzdHJ5LmNyZWF0ZVR5cGUoJ0V4dHJpbnNpYycsIHJhd1R4LCB7XG4gICAgICBpc1NpZ25lZDogdHJ1ZSxcbiAgICB9KTtcbiAgICBsZXQgc2lnbmF0dXJlID0gdThhVG9IZXgobWV0aG9kQ2FsbC5zaWduYXR1cmUpIGFzIHN0cmluZztcblxuICAgIC8vIHJlbW92ZSAweCBmcm9tIHRoZSBzaWduYXR1cmUgc2luY2UgdGhpcyBpcyBob3cgaXQncyByZXR1cm5lZCBmcm9tIFRTUyBzaWduaW5nXG4gICAgaWYgKHNpZ25hdHVyZS5zdGFydHNXaXRoKCcweCcpKSB7XG4gICAgICBzaWduYXR1cmUgPSBzaWduYXR1cmUuc3Vic3RyKDIpO1xuICAgIH1cbiAgICByZXR1cm4gc2lnbmF0dXJlO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZXMgdGhlIGRvdCBhZGRyZXNzIGZyb20gdGhlIGdpdmVuIGZvcm1hdFxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzc1xuICAgKiBAcGFyYW0ge251bWJlcn0gW3NzNThGb3JtYXRdXG4gICAqIEByZXR1cm5zIHtLZXlQYWlyfVxuICAgKi9cbiAgZGVjb2RlRG90QWRkcmVzc1RvS2V5UGFpcihhZGRyZXNzOiBzdHJpbmcsIHNzNThGb3JtYXQ/OiBudW1iZXIpOiBLZXlQYWlyIHtcbiAgICByZXR1cm4gbmV3IEtleVBhaXIoeyBwdWI6IEJ1ZmZlci5mcm9tKGRlY29kZUFkZHJlc3MoYWRkcmVzcywgdW5kZWZpbmVkLCBzczU4Rm9ybWF0KSkudG9TdHJpbmcoJ2hleCcpIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyB3aGV0aGVyIHRoZSBnaXZlbiBpbnB1dCBpcyBhIGhleCBzdHJpbmcgd2l0aCB3aXRoIDAgdmFsdWVcbiAgICogdXNlZCB0byBjaGVjayB3aGV0aGVyIGEgZ2l2ZW4gdHJhbnNhY3Rpb24gaXMgaW1tb3J0YWwgb3IgbW9ydGFsXG4gICAqIEBwYXJhbSBoZXhWYWx1ZVxuICAgKi9cbiAgaXNaZXJvSGV4KGhleFZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gaGV4VmFsdWUgPT09ICcweDAwJztcbiAgfVxuXG4gIC8qKlxuICAgKiBUYWtlcyBhbiBhc3NldCBuYW1lIGFuZCByZXR1cm5zIHRoZSByZXNwZWN0aXZlIGFkZHJlc3MgdG8gZm9ybWF0IHRvXG4gICAqIHNpbmNlIHBvbGthZG90IGFkZHJlc3NlcyBkaWZmZXIgZGVwZW5kaW5nIG9uIHRoZSBuZXR3b3JrXG4gICAqIHJlZjogaHR0cHM6Ly93aWtpLnBvbGthZG90Lm5ldHdvcmsvZG9jcy9sZWFybi1hY2NvdW50c1xuICAgKiBAcGFyYW0gbmV0d29ya0NvaW5OYW1lXG4gICAqL1xuICBnZXRBZGRyZXNzRm9ybWF0KG5ldHdvcmtDb2luTmFtZTogRG90QXNzZXRUeXBlcyk6IERvdEFkZHJlc3NGb3JtYXQge1xuICAgIHJldHVybiBjb2luVG9BZGRyZXNzTWFwLmdldChuZXR3b3JrQ29pbk5hbWUpIGFzIERvdEFkZHJlc3NGb3JtYXQ7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHB1cmUgcHJveHkgZXh0cmluc2ljLiBQb2xrYWRvdCBoYXMgcmVuYW1lZCBhbm9ueW1vdXMgcHJveGllcyB0byBwdXJlIHByb3hpZXMsIGJ1dFxuICAgKiB0aGUgbGlicmFyaWVzIHdlIGFyZSB1c2luZyB0byBidWlsZCB0cmFuc2FjdGlvbnMgaGF2ZSBub3QgYmVlbiB1cGRhdGVkLCBhcyBhIHN0b3AgZ2FwIHdlIGFyZVxuICAgKiBkZWZpbmluZyB0aGUgcHVyZSBwcm94eSBleHRyaW5zaWMgaGVyZS5cbiAgICpcbiAgICogQHBhcmFtIGFyZ3MgQXJndW1lbnRzIHRvIHRoZSBjcmVhdGVQdXJlIGV4dHJpbnNpYy5cbiAgICogQHBhcmFtIGluZm8gQ29tbW9uIGluZm9ybWF0aW9uIHRvIGFsbCB0cmFuc2FjdGlvbnMuXG4gICAqIEBwYXJhbSBvcHRpb25zIENoYWluIHJlZ2lzdHJ5IGFuZCBtZXRhZGF0YS5cbiAgICovXG4gIHB1cmVQcm94eShhcmdzOiBQdXJlUHJveHlBcmdzLCBpbmZvOiBCYXNlVHhJbmZvLCBvcHRpb25zOiBPcHRpb25zV2l0aE1ldGEpOiBVbnNpZ25lZFRyYW5zYWN0aW9uIHtcbiAgICByZXR1cm4gZGVmaW5lTWV0aG9kKFxuICAgICAge1xuICAgICAgICBtZXRob2Q6IHtcbiAgICAgICAgICBhcmdzLFxuICAgICAgICAgIG5hbWU6ICdjcmVhdGVQdXJlJyxcbiAgICAgICAgICBwYWxsZXQ6ICdwcm94eScsXG4gICAgICAgIH0sXG4gICAgICAgIC4uLmluZm8sXG4gICAgICB9LFxuICAgICAgb3B0aW9uc1xuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyAnMHgnIGZyb20gYSBnaXZlbiBgc3RyaW5nYCBpZiBwcmVzZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyIHRoZSBzdHJpbmcgdmFsdWUuXG4gICAqXG4gICAqIEByZXR1cm4ge3N0cmluZ30gYSBzdHJpbmcgd2l0aG91dCBhICcweCcgcHJlZml4LlxuICAgKi9cbiAgc3RyaXBIZXhQcmVmaXgoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmlzSGV4UHJlZml4ZWQoc3RyKSA/IHN0ci5zbGljZSgyKSA6IHN0cjtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgYSBzdHJpbmcgc3RhcnRzIHdpdGggJzB4JywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyIHRoZSBzdHJpbmcgdmFsdWUuXG4gICAqXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgYSBzdHJpbmcgc3RhcnRzIHdpdGggJzB4JywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNIZXhQcmVmaXhlZChzdHI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBzdHIuc2xpY2UoMCwgMikgPT09ICcweCc7XG4gIH1cbn1cblxuaW50ZXJmYWNlIFB1cmVQcm94eUFyZ3MgZXh0ZW5kcyBBcmdzIHtcbiAgcHJveHlUeXBlOiBzdHJpbmc7XG4gIGRlbGF5OiBudW1iZXI7XG4gIGluZGV4OiBudW1iZXI7XG59XG5cbmNvbnN0IHV0aWxzID0gbmV3IFV0aWxzKCk7XG5cbmV4cG9ydCBkZWZhdWx0IHV0aWxzO1xuIl19

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


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