PHP WebShell

Текущая директория: /opt/BitGoJS/modules/sdk-coin-icp/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 principal_1 = require("@dfinity/principal");
const agent = __importStar(require("@dfinity/agent"));
const crypto_1 = __importDefault(require("crypto"));
const crc_32_1 = __importDefault(require("crc-32"));
const iface_1 = require("./iface");
const keyPair_1 = require("./keyPair");
const messageCompiled = require('../../resources/messageCompiled');
const { encode, decode, Encoder } = require('cbor-x/index-no-eval'); // The "cbor-x" library is used here because it supports modern features like BigInt. do not replace it with "cbor as "cbor" is not compatible with Rust's serde_cbor when handling big numbers.
const js_sha256_1 = __importDefault(require("js-sha256"));
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const secp256k1_1 = require("@noble/curves/secp256k1");
//custom encoder that avoids tagging
const encoder = new Encoder({
    structuredClone: false,
    useToJSON: false,
    mapsAsObjects: false,
    largeBigIntToFloat: false,
});
class Utils {
    constructor() {
        this.signPayload = (privateKey, payloadHex) => {
            const privateKeyBytes = Buffer.from(privateKey, 'hex');
            const payloadHash = crypto_1.default.createHash('sha256').update(Buffer.from(payloadHex, 'hex')).digest('hex');
            const signature = secp256k1_1.secp256k1.sign(payloadHash, privateKeyBytes);
            const r = Buffer.from(signature.r.toString(16).padStart(64, '0'), 'hex');
            const s = Buffer.from(signature.s.toString(16).padStart(64, '0'), 'hex');
            return Buffer.concat([r, s]).toString('hex');
        };
    }
    /** @inheritdoc */
    isValidSignature(signature) {
        throw new sdk_core_1.MethodNotImplementedError();
    }
    /**
     * gets the gas data of this transaction.
     */
    //TODO WIN-4242: to moved to a config and eventually to an API for dynamic value
    feeData() {
        return '-10000';
    }
    /**
     * Checks if the provided address is a valid ICP address.
     *
     * @param {string} address - The address to validate.
     * @returns {boolean} - Returns `true` if the address is valid, otherwise `false`.
     */
    isValidAddress(address) {
        const rootAddress = this.validateMemoAndReturnRootAddress(address);
        return rootAddress !== undefined && this.isValidHash(rootAddress);
    }
    /**
     * Validates the memo ID in the address and returns the root address.
     *
     * @param {string} address - The address to validate and extract the root address from.
     * @returns {string | undefined} - The root address if valid, otherwise `undefined`.
     */
    validateMemoAndReturnRootAddress(address) {
        if (!address) {
            return undefined;
        }
        const [rootAddress, memoId] = address.split('?memoId=');
        if (memoId && this.validateMemo(BigInt(memoId))) {
            return rootAddress;
        }
        return address;
    }
    /**
     * Checks if the provided hex string is a valid public key.
     *
     * A valid public key can be either compressed or uncompressed:
     * - Compressed public keys are 33 bytes long and start with either 0x02 or 0x03.
     * - Uncompressed public keys are 65 bytes long and start with 0x04.
     *
     * @param {string} hexStr - The hex string representation of the public key to validate.
     * @returns {boolean} - Returns `true` if the hex string is a valid public key, otherwise `false`.
     */
    isValidPublicKey(hexStr) {
        if (!this.isValidHex(hexStr) || !this.isValidLength(hexStr)) {
            return false;
        }
        const pubKeyBytes = this.hexToBytes(hexStr);
        const firstByte = pubKeyBytes[0];
        const validCompressed = pubKeyBytes.length === 33 && (firstByte === 2 || firstByte === 3);
        const validUncompressed = pubKeyBytes.length === 65 && firstByte === 4;
        return validCompressed || validUncompressed;
    }
    /**
     * Encodes a value into CBOR format and returns it as a hex string.
     *
     * @param {unknown} value - The value to encode.
     * @returns {string} - The CBOR encoded value as a hex string.
     */
    cborEncode(value) {
        if (value === undefined) {
            throw new Error('Value to encode cannot be undefined.');
        }
        const cborData = encode(value);
        return Buffer.from(cborData).toString('hex');
    }
    /**
     * Checks if the length of the given hexadecimal string is valid.
     * A valid length is either 66 characters (33 bytes) or 130 characters (65 bytes).
     *
     * @param {string} hexStr - The hexadecimal string to check.
     * @returns {boolean} - Returns `true` if the length is valid, otherwise `false`.
     */
    isValidLength(hexStr) {
        return hexStr.length / 2 === 33 || hexStr.length / 2 === 65;
    }
    /**
     * Checks if the provided string is a valid hexadecimal string.
     *
     * A valid hexadecimal string consists of pairs of hexadecimal digits (0-9, a-f, A-F).
     *
     * @param hexStr - The string to be validated as a hexadecimal string.
     * @returns True if the string is a valid hexadecimal string, false otherwise.
     */
    isValidHex(hexStr) {
        return /^([0-9a-fA-F]{2})+$/.test(hexStr);
    }
    /**
     * Converts a hexadecimal string to a Uint8Array.
     *
     * @param {string} hex - The hexadecimal string to convert.
     * @returns {Uint8Array} The resulting byte array.
     */
    hexToBytes(hex) {
        const bytes = new Uint8Array(hex.length / 2);
        for (let i = 0; i < hex.length; i += 2) {
            bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
        }
        return bytes;
    }
    /** @inheritdoc */
    isValidPrivateKey(key) {
        return this.isValidKey(key);
    }
    /**
     * Validates whether the provided key is a valid ICP private key.
     *
     * This function attempts to create a new instance of `IcpKeyPair` using the provided key.
     * If the key is valid, the function returns `true`. If the key is invalid, an error is thrown,
     * and the function returns `false`.
     *
     * @param {string} key - The private key to validate.
     * @returns {boolean} - `true` if the key is valid, `false` otherwise.
     */
    isValidKey(key) {
        try {
            new keyPair_1.KeyPair({ prv: key });
            return true;
        }
        catch {
            return false;
        }
    }
    /**
     * Compresses an uncompressed public key.
     *
     * @param {string} uncompressedKey - The uncompressed public key in hexadecimal format.
     * @returns {string} - The compressed public key in hexadecimal format.
     * @throws {Error} - If the input key is not a valid uncompressed public key.
     */
    compressPublicKey(uncompressedKey) {
        if (uncompressedKey.startsWith('02') || uncompressedKey.startsWith('03')) {
            return uncompressedKey;
        }
        if (!uncompressedKey.startsWith('04') || uncompressedKey.length !== 130) {
            throw new Error('Invalid uncompressed public key format.');
        }
        const xHex = uncompressedKey.slice(2, 66);
        const yHex = uncompressedKey.slice(66);
        const y = BigInt(`0x${yHex}`);
        const prefix = y % 2n === 0n ? '02' : '03';
        return `${prefix}${xHex}`;
    }
    /**
     * Converts a public key from its hexadecimal string representation to DER format.
     *
     * @param {string} publicKeyHex - The public key in hexadecimal string format.
     * @returns The public key in DER format as a Uint8Array.
     */
    getPublicKeyInDERFormat(publicKeyHex) {
        const publicKeyBuffer = Buffer.from(publicKeyHex, 'hex');
        const ellipticKey = secp256k1_1.secp256k1.ProjectivePoint.fromHex(publicKeyBuffer.toString('hex'));
        const uncompressedPublicKeyHex = ellipticKey.toHex(false);
        const derEncodedKey = agent.wrapDER(Buffer.from(uncompressedPublicKeyHex, 'hex'), agent.SECP256K1_OID);
        return derEncodedKey;
    }
    /**
     * Converts a public key in hexadecimal format to a Dfinity Principal ID.
     *
     * @param {string} publicKeyHex - The public key in hexadecimal format.
     * @returns The corresponding Dfinity Principal ID.
     */
    getPrincipalIdFromPublicKey(publicKeyHex) {
        const derEncodedKey = this.getPublicKeyInDERFormat(publicKeyHex);
        const principalId = principal_1.Principal.selfAuthenticating(Buffer.from(derEncodedKey));
        return principalId;
    }
    /**
     * Derives a DfinityPrincipal from a given public key in hexadecimal format.
     *
     * @param {string} publicKeyHex - The public key in hexadecimal format.
     * @returns The derived DfinityPrincipal.
     * @throws Will throw an error if the principal cannot be derived from the public key.
     */
    derivePrincipalFromPublicKey(publicKeyHex) {
        try {
            const derEncodedKey = this.getPublicKeyInDERFormat(publicKeyHex);
            const principalId = principal_1.Principal.selfAuthenticating(Buffer.from(derEncodedKey));
            const principal = principal_1.Principal.fromUint8Array(principalId.toUint8Array());
            return principal;
        }
        catch (error) {
            throw new Error(`Failed to derive principal from public key: ${error.message}`);
        }
    }
    /**
     * Converts a DfinityPrincipal and an optional subAccount to a string representation of an account ID.
     *
     * @param {DfinityPrincipal} principal - The principal to convert.
     * @param {Uint8Array} [subAccount=new Uint8Array(32)] - An optional sub-account, defaults to a 32-byte array of zeros.
     * @returns {string} The hexadecimal string representation of the account ID.
     */
    fromPrincipal(principal, subAccount = new Uint8Array(32)) {
        const principalBytes = Buffer.from(principal.toUint8Array().buffer);
        return this.getAccountIdFromPrincipalBytes(this.getAccountIdPrefix(), principalBytes, subAccount);
    }
    getAccountIdFromPrincipalBytes(ACCOUNT_ID_PREFIX, principalBytes, subAccount) {
        const combinedBytes = Buffer.concat([ACCOUNT_ID_PREFIX, principalBytes, subAccount]);
        const sha224Hash = crypto_1.default.createHash('sha224').update(combinedBytes).digest();
        const checksum = Buffer.alloc(4);
        checksum.writeUInt32BE(crc_32_1.default.buf(sha224Hash) >>> 0, 0);
        const accountIdBytes = Buffer.concat([checksum, sha224Hash]);
        return accountIdBytes.toString('hex');
    }
    /**
     * Retrieves the address associated with a given hex-encoded public key.
     *
     * @param {string} hexEncodedPublicKey - The public key in hex-encoded format.
     * @returns {Promise<string>} A promise that resolves to the address derived from the provided public key.
     * @throws {Error} Throws an error if the provided public key is not in a valid hex-encoded format.
     */
    async getAddressFromPublicKey(hexEncodedPublicKey) {
        if (!this.isValidPublicKey(hexEncodedPublicKey)) {
            throw new Error('Invalid hex-encoded public key format.');
        }
        const compressedKey = this.compressPublicKey(hexEncodedPublicKey);
        const keyPair = new keyPair_1.KeyPair({ pub: compressedKey });
        return keyPair.getAddress();
    }
    /**
     * Generates a new key pair. If a seed is provided, it will be used to generate the key pair.
     *
     * @param {Buffer} [seed] - Optional seed for key generation.
     * @returns {KeyPair} - The generated key pair containing both public and private keys.
     * @throws {Error} - If the private key is missing in the generated key pair.
     */
    generateKeyPair(seed) {
        const keyPair = seed ? new keyPair_1.KeyPair({ seed }) : new keyPair_1.KeyPair();
        const { pub, prv } = keyPair.getKeys();
        if (!prv) {
            throw new Error('Private key is missing in the generated key pair.');
        }
        return { pub, prv };
    }
    /**
     * Validates the provided fee.
     *
     * @param {string} fee - The fee to validate.
     * @throws {BuildTransactionError} - If the fee is zero or invalid.
     */
    validateFee(fee) {
        const feeValue = new bignumber_js_1.default(fee);
        if (feeValue.isZero()) {
            throw new sdk_core_1.BuildTransactionError('Fee cannot be zero');
        }
        return true;
    }
    /** @inheritdoc */
    validateValue(value) {
        if (value.isLessThanOrEqualTo(0)) {
            throw new sdk_core_1.BuildTransactionError('amount cannot be less than or equal to zero');
        }
        return true;
    }
    /**
     * Validates the provided memo.
     *
     * @param {number | BigInt} memo - The memo to validate.
     * @returns {boolean} - Returns `true` if the memo is valid.
     * @throws {BuildTransactionError} - If the memo is invalid.
     */
    validateMemo(memo) {
        const memoNumber = Number(memo);
        if (memoNumber < 0 || Number.isNaN(memoNumber)) {
            throw new sdk_core_1.BuildTransactionError('Invalid memo');
        }
        return true;
    }
    validateExpireTime(expireTime) {
        if (Number(expireTime) < Date.now() * 1000000) {
            throw new sdk_core_1.BuildTransactionError('Invalid expiry time');
        }
        return true;
    }
    /**
     * Validates the raw transaction data to ensure it has a valid format in the blockchain context.
     *
     * @param {IcpTransactionData} transactionData - The transaction data to validate.
     * @throws {ParseTransactionError} If the transaction data is invalid.
     */
    validateRawTransaction(transactionData) {
        if (!transactionData) {
            throw new sdk_core_1.ParseTransactionError('Transaction data is missing.');
        }
        const { senderPublicKeyHex, senderAddress, receiverAddress } = transactionData;
        if (senderPublicKeyHex && !this.isValidPublicKey(senderPublicKeyHex)) {
            throw new sdk_core_1.ParseTransactionError('Sender public key is invalid.');
        }
        if (!this.isValidAddress(senderAddress)) {
            throw new sdk_core_1.ParseTransactionError('Sender address is invalid.');
        }
        if (!this.isValidAddress(receiverAddress)) {
            throw new sdk_core_1.ParseTransactionError('Receiver address is invalid.');
        }
        this.validateFee(transactionData.fee);
        this.validateValue(new bignumber_js_1.default(transactionData.amount));
        this.validateMemo(transactionData.memo);
        this.validateExpireTime(transactionData.expiryTime);
    }
    /**
     *
     * @param {object} update
     * @returns {Buffer}
     */
    generateHttpCanisterUpdateId(update) {
        return this.HttpCanisterUpdateRepresentationIndependentHash(update);
    }
    /**
     * Generates a representation-independent hash for an HTTP canister update.
     *
     * @param {HttpCanisterUpdate} update - The HTTP canister update object.
     * @returns {Buffer} - The hash of the update object.
     */
    HttpCanisterUpdateRepresentationIndependentHash(update) {
        const updateMap = {
            request_type: iface_1.RequestType.CALL,
            canister_id: update.canister_id,
            method_name: update.method_name,
            arg: update.arg,
            ingress_expiry: update.ingress_expiry,
            sender: update.sender,
        };
        return this.hashOfMap(updateMap);
    }
    /**
     * Generates a SHA-256 hash for a given map object.
     *
     * @param {Record<string, unknown>} map - The map object to hash.
     * @returns {Buffer} - The resulting hash as a Buffer.
     */
    hashOfMap(map) {
        const hashes = [];
        for (const key in map) {
            hashes.push(this.hashKeyVal(key, map[key]));
        }
        hashes.sort((buf0, buf1) => buf0.compare(buf1));
        return this.sha256(hashes);
    }
    /**
     * Generates a hash for a key-value pair.
     *
     * @param {string} key - The key to hash.
     * @param {string | Buffer | BigInt} val - The value to hash.
     * @returns {Buffer} - The resulting hash as a Buffer.
     */
    hashKeyVal(key, val) {
        const keyHash = this.hashString(key);
        const valHash = this.hashVal(val);
        return Buffer.concat([keyHash, valHash]);
    }
    /**
     * Generates a SHA-256 hash for a given string.
     *
     * @param {string} value - The string to hash.
     * @returns {Buffer} - The resulting hash as a Buffer.
     */
    hashString(value) {
        return this.sha256([Buffer.from(value)]);
    }
    /**
     * Generates a hash for a 64-bit unsigned integer.
     *
     * @param {bigint} n - The 64-bit unsigned integer to hash.
     * @returns {Buffer} - The resulting hash as a Buffer.
     */
    hashU64(n) {
        const buf = Buffer.allocUnsafe(10);
        let i = 0;
        while (true) {
            const byte = Number(n & BigInt(0x7f));
            n >>= BigInt(7);
            if (n === BigInt(0)) {
                buf[i] = byte;
                break;
            }
            else {
                buf[i] = byte | 0x80;
                ++i;
            }
        }
        return this.hashBytes(buf.subarray(0, i + 1));
    }
    /**
     * Generates a SHA-256 hash for an array of elements.
     *
     * @param {Array<any>} elements - The array of elements to hash.
     * @returns {Buffer} - The resulting hash as a Buffer.
     */
    hashArray(elements) {
        return this.sha256(elements.map(this.hashVal));
    }
    /**
     * Generates a hash for a given value.
     *
     * @param {string | Buffer | BigInt | number | Array<unknown>} val - The value to hash.
     * @returns {Buffer} - The resulting hash as a Buffer.
     * @throws {Error} - If the value type is unsupported.
     */
    hashVal(val) {
        if (typeof val === 'string') {
            return utils.hashString(val);
        }
        else if (Buffer.isBuffer(val) || val instanceof Uint8Array) {
            return utils.hashBytes(val);
        }
        else if (typeof val === 'bigint' || typeof val === 'number') {
            return utils.hashU64(BigInt(val));
        }
        else if (Array.isArray(val)) {
            return utils.hashArray(val);
        }
        else {
            throw new Error(`Unsupported value type for hashing: ${typeof val}`);
        }
    }
    /**
     * Computes the SHA-256 hash of the given buffer.
     *
     * @param value - The buffer to hash.
     * @returns The SHA-256 hash of the input buffer.
     */
    hashBytes(value) {
        return this.sha256([value]);
    }
    /**
     * Computes the SHA-256 hash of the provided array of Buffer chunks.
     *
     * @param {Array<Buffer>} chunks - An array of Buffer objects to be hashed.
     * @returns {Buffer} - The resulting SHA-256 hash as a Buffer.
     */
    sha256(chunks) {
        const hasher = js_sha256_1.default.sha256.create();
        chunks.forEach((chunk) => hasher.update(chunk));
        return Buffer.from(hasher.arrayBuffer());
    }
    /**
     * Converts a hexadecimal string to a Buffer.
     *
     * @param hex - The hexadecimal string to convert.
     * @returns A Buffer containing the binary data represented by the hexadecimal string.
     */
    blobFromHex(hex) {
        return Buffer.from(hex, 'hex');
    }
    /**
     * Converts a binary blob (Buffer) to a hexadecimal string.
     *
     * @param {Buffer} blob - The binary data to be converted.
     * @returns {string} The hexadecimal representation of the binary data.
     */
    blobToHex(blob) {
        return blob.toString('hex');
    }
    /**
     * Decodes a given CBOR-encoded buffer.
     *
     * @param buffer - The CBOR-encoded buffer to decode.
     * @returns The decoded data.
     */
    cborDecode(buffer) {
        const res = decode(buffer);
        return res;
    }
    /**
     * Generates a Buffer containing the domain IC request string.
     *
     * @returns {Buffer} A Buffer object initialized with the string '\x0Aic-request'.
     */
    getDomainICRequest() {
        return Buffer.from('\x0Aic-request');
    }
    /**
     * Combines the domain IC request buffer with the provided message ID buffer to create signature data.
     *
     * @param {Buffer} messageId - The buffer containing the message ID.
     * @returns {Buffer} - The concatenated buffer containing the domain IC request and the message ID.
     */
    makeSignatureData(messageId) {
        return Buffer.concat([this.getDomainICRequest(), messageId]);
    }
    /**
     * Extracts the recipient information from the provided ICP transaction data.
     *
     * @param {IcpTransactionData} icpTransactionData - The ICP transaction data containing the receiver's address and amount.
     * @returns {Recipient[]} An array containing a single recipient object with the receiver's address and amount.
     */
    getRecipients(icpTransactionData) {
        return {
            address: icpTransactionData.receiverAddress,
            amount: icpTransactionData.amount,
        };
    }
    getTransactionSignature(signatureMap, update) {
        return signatureMap.get(this.blobToHex(this.makeSignatureData(this.generateHttpCanisterUpdateId(update))));
    }
    getMetaData(memo, timestamp, ingressEnd) {
        let currentTime = Date.now() * 1000000;
        if (timestamp) {
            currentTime = Number(timestamp);
        }
        let ingressStartTime, ingressEndTime;
        if (ingressEnd) {
            ingressEndTime = Number(ingressEnd);
            ingressStartTime = ingressEndTime - iface_1.MAX_INGRESS_TTL; // 5 mins in nanoseconds
        }
        else {
            ingressStartTime = currentTime;
            ingressEndTime = ingressStartTime + iface_1.MAX_INGRESS_TTL; // 5 mins in nanoseconds
        }
        const metaData = {
            created_at_time: currentTime,
            ingress_start: ingressStartTime,
            ingress_end: ingressEndTime,
            memo: memo,
        };
        return { metaData, ingressEndTime };
    }
    convertSenderBlobToPrincipal(senderBlob) {
        const MAX_LENGTH_IN_BYTES = 29;
        if (senderBlob.length > MAX_LENGTH_IN_BYTES) {
            throw new Error('Bytes too long for a valid Principal');
        }
        const principalBytes = new Uint8Array(MAX_LENGTH_IN_BYTES);
        principalBytes.set(senderBlob.slice(0, senderBlob.length));
        return principalBytes;
    }
    fromArgs(arg) {
        const SendRequestMessage = messageCompiled.SendRequest;
        const args = SendRequestMessage.decode(arg);
        const transformedArgs = {
            payment: { receiverGets: { e8s: Number(args.payment.receiverGets.e8s) } },
            maxFee: { e8s: Number(args.maxFee.e8s) },
            to: { hash: Buffer.from(args.to.hash) },
            createdAtTime: { timestampNanos: (0, bignumber_js_1.default)(args.createdAtTime.timestampNanos.toString()).toNumber() },
            memo: { memo: Number(args.memo.memo.toString()) },
        };
        return transformedArgs;
    }
    async toArg(args) {
        const SendRequestMessage = messageCompiled.SendRequest;
        const errMsg = SendRequestMessage.verify(args);
        if (errMsg)
            throw new Error(errMsg);
        const message = SendRequestMessage.create(args);
        return SendRequestMessage.encode(message).finish();
    }
    getAccountIdPrefix() {
        return Buffer.from([0x0a, ...Buffer.from('account-id')]);
    }
    /** @inheritdoc */
    isValidBlockId(hash) {
        // ICP block hashes are 64-character hexadecimal strings
        return this.isValidHash(hash);
    }
    /**
     * Returns whether or not the string is a valid ICP hash
     *
     * @param {string} hash - string to validate
     * @returns {boolean}
     */
    isValidHash(hash) {
        return typeof hash === 'string' && /^[0-9a-fA-F]{64}$/.test(hash);
    }
    /** @inheritdoc */
    isValidTransactionId(txId) {
        return this.isValidHash(txId);
    }
    getSignatures(payloadsData, senderPublicKey, senderPrivateKey) {
        return payloadsData.payloads.map((payload) => ({
            signing_payload: payload,
            signature_type: payload.signature_type,
            public_key: {
                hex_bytes: senderPublicKey,
                curve_type: iface_1.CurveType.SECP256K1,
            },
            hex_bytes: this.signPayload(senderPrivateKey, payload.hex_bytes),
        }));
    }
    getTransactionId(unsignedTransaction, senderAddress, receiverAddress) {
        try {
            const decodedTxn = utils.cborDecode(utils.blobFromHex(unsignedTransaction));
            const updates = decodedTxn.updates;
            for (const [, update] of updates) {
                const updateArgs = update.arg;
                const sendArgs = utils.fromArgs(updateArgs);
                const transactionHash = this.generateTransactionHash(sendArgs, senderAddress, receiverAddress);
                return transactionHash;
            }
            throw new Error('No updates found in the unsigned transaction.');
        }
        catch (error) {
            throw new Error(`Unable to compute transaction ID: ${error.message}`);
        }
    }
    safeBigInt(value) {
        if (typeof value === 'bigint') {
            return value;
        }
        if (typeof value === 'number') {
            const isUnsafe = value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER;
            return isUnsafe ? BigInt(value) : value;
        }
        throw new Error(`Invalid type: expected a number or bigint, but received ${typeof value}`);
    }
    generateTransactionHash(sendArgs, senderAddress, receiverAddress) {
        const senderAccount = this.accountIdentifier(senderAddress);
        const receiverAccount = this.accountIdentifier(receiverAddress);
        const transferFields = new Map([
            [0, senderAccount],
            [1, receiverAccount],
            [2, new Map([[0, this.safeBigInt(Number(sendArgs.payment.receiverGets.e8s))]])],
            [3, new Map([[0, sendArgs.maxFee.e8s]])],
        ]);
        const operationMap = new Map([[2, transferFields]]);
        const txnFields = new Map([
            [0, operationMap],
            [1, this.safeBigInt(sendArgs.memo.memo)],
            [2, new Map([[0, BigInt(sendArgs.createdAtTime.timestampNanos)]])],
        ]);
        const processedTxn = this.getProcessedTransactionMap(txnFields);
        const serializedTxn = encoder.encode(processedTxn);
        return crypto_1.default.createHash('sha256').update(serializedTxn).digest('hex');
    }
    accountIdentifier(accountAddress) {
        const bytes = Buffer.from(accountAddress, 'hex');
        if (bytes.length === 32) {
            return { hash: bytes.slice(4) };
        }
        throw new Error(`Invalid AccountIdentifier: 64 hex chars, got ${accountAddress.length}`);
    }
    getProcessedTransactionMap(txnMap) {
        const operationMap = txnMap.get(0);
        const transferMap = operationMap.get(2);
        transferMap.set(0, this.serializeAccountIdentifier(transferMap.get(0)));
        transferMap.set(1, this.serializeAccountIdentifier(transferMap.get(1)));
        return txnMap;
    }
    serializeAccountIdentifier(accountHash) {
        if (accountHash && accountHash.hash) {
            const hashBuffer = accountHash.hash;
            const checksum = Buffer.alloc(4);
            checksum.writeUInt32BE(crc_32_1.default.buf(hashBuffer) >>> 0, 0);
            return Buffer.concat([checksum, hashBuffer]).toString('hex').toLowerCase();
        }
        throw new Error('Invalid accountHash format');
    }
}
exports.Utils = Utils;
const utils = new Utils();
exports.default = utils;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDhDQU95QjtBQUN6QixrREFBbUU7QUFDbkUsc0RBQXdDO0FBQ3hDLG9EQUE0QjtBQUM1QixvREFBMkI7QUFDM0IsbUNBWWlCO0FBQ2pCLHVDQUFrRDtBQUNsRCxNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUMsaUNBQWlDLENBQUMsQ0FBQztBQUNuRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxPQUFPLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLGdNQUFnTTtBQUNyUSwwREFBa0M7QUFDbEMsZ0VBQXFDO0FBQ3JDLHVEQUFvRDtBQUVwRCxvQ0FBb0M7QUFDcEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxPQUFPLENBQUM7SUFDMUIsZUFBZSxFQUFFLEtBQUs7SUFDdEIsU0FBUyxFQUFFLEtBQUs7SUFDaEIsYUFBYSxFQUFFLEtBQUs7SUFDcEIsa0JBQWtCLEVBQUUsS0FBSztDQUMxQixDQUFDLENBQUM7QUFFSCxNQUFhLEtBQUs7SUFBbEI7UUE2bkJFLGdCQUFXLEdBQUcsQ0FBQyxVQUFrQixFQUFFLFVBQWtCLEVBQVUsRUFBRTtZQUMvRCxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN2RCxNQUFNLFdBQVcsR0FBRyxnQkFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDckcsTUFBTSxTQUFTLEdBQUcscUJBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLGVB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QUN4RSxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsMEJBQTBCLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDeEUsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELDBCQUEwQixDQUFDLFdBQWtDO1FBQzNELElBQUksV0FBVyxJQUFJLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNwQyxNQUFNLFVBQVUsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDO1lBQ3BDLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDakMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxnQkFBSyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDdkQsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzdFLENBQUM7UUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7SUFDaEQsQ0FBQztDQUNGO0FBbnRCRCxzQkFtdEJDO0FBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQztBQUMxQixrQkFBZSxLQUFLLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBCYXNlVXRpbHMsXG4gIEtleVBhaXIsXG4gIFBhcnNlVHJhbnNhY3Rpb25FcnJvcixcbiAgUmVjaXBpZW50LFxuICBCdWlsZFRyYW5zYWN0aW9uRXJyb3IsXG4gIE1ldGhvZE5vdEltcGxlbWVudGVkRXJyb3IsXG59IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBQcmluY2lwYWwgYXMgRGZpbml0eVByaW5jaXBhbCB9IGZyb20gJ0BkZmluaXR5L3ByaW5jaXBhbCc7XG5pbXBvcnQgKiBhcyBhZ2VudCBmcm9tICdAZGZpbml0eS9hZ2VudCc7XG5pbXBvcnQgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgY3JjMzIgZnJvbSAnY3JjLTMyJztcbmltcG9ydCB7XG4gIEh0dHBDYW5pc3RlclVwZGF0ZSxcbiAgSWNwVHJhbnNhY3Rpb25EYXRhLFxuICBSZXF1ZXN0VHlwZSxcbiAgU2lnbmF0dXJlcyxcbiAgTWV0YURhdGEsXG4gIFNlbmRBcmdzLFxuICBQYXlsb2Fkc0RhdGEsXG4gIEN1cnZlVHlwZSxcbiAgQWNjb3VudElkZW50aWZpZXJIYXNoLFxuICBDYm9yVW5zaWduZWRUcmFuc2FjdGlvbixcbiAgTUFYX0lOR1JFU1NfVFRMLFxufSBmcm9tICcuL2lmYWNlJztcbmltcG9ydCB7IEtleVBhaXIgYXMgSWNwS2V5UGFpciB9IGZyb20gJy4va2V5UGFpcic7XG5jb25zdCBtZXNzYWdlQ29tcGlsZWQgPSByZXF1aXJlKCcuLi8uLi9yZXNvdXJjZXMvbWVzc2FnZUNvbXBpbGVkJyk7XG5jb25zdCB7IGVuY29kZSwgZGVjb2RlLCBFbmNvZGVyIH0gPSByZXF1aXJlKCdjYm9yLXgvaW5kZXgtbm8tZXZhbCcpOyAvLyBUaGUgXCJjYm9yLXhcIiBsaWJyYXJ5IGlzIHVzZWQgaGVyZSBiZWNhdXNlIGl0IHN1cHBvcnRzIG1vZGVybiBmZWF0dXJlcyBsaWtlIEJpZ0ludC4gZG8gbm90IHJlcGxhY2UgaXQgd2l0aCBcImNib3IgYXMgXCJjYm9yXCIgaXMgbm90IGNvbXBhdGlibGUgd2l0aCBSdXN0J3Mgc2VyZGVfY2JvciB3aGVuIGhhbmRsaW5nIGJpZyBudW1iZXJzLlxuaW1wb3J0IGpzX3NoYTI1NiBmcm9tICdqcy1zaGEyNTYnO1xuaW1wb3J0IEJpZ051bWJlciBmcm9tICdiaWdudW1iZXIuanMnO1xuaW1wb3J0IHsgc2VjcDI1NmsxIH0gZnJvbSAnQG5vYmxlL2N1cnZlcy9zZWNwMjU2azEnO1xuXG4vL2N1c3RvbSBlbmNvZGVyIHRoYXQgYXZvaWRzIHRhZ2dpbmdcbmNvbnN0IGVuY29kZXIgPSBuZXcgRW5jb2Rlcih7XG4gIHN0cnVjdHVyZWRDbG9uZTogZmFsc2UsXG4gIHVzZVRvSlNPTjogZmFsc2UsXG4gIG1hcHNBc09iamVjdHM6IGZhbHNlLFxuICBsYXJnZUJpZ0ludFRvRmxvYXQ6IGZhbHNlLFxufSk7XG5cbmV4cG9ydCBjbGFzcyBVdGlscyBpbXBsZW1lbnRzIEJhc2VVdGlscyB7XG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkU2lnbmF0dXJlKHNpZ25hdHVyZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdGhyb3cgbmV3IE1ldGhvZE5vdEltcGxlbWVudGVkRXJyb3IoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBnZXRzIHRoZSBnYXMgZGF0YSBvZiB0aGlzIHRyYW5zYWN0aW9uLlxuICAgKi9cbiAgLy9UT0RPIFdJTi00MjQyOiB0byBtb3ZlZCB0byBhIGNvbmZpZyBhbmQgZXZlbnR1YWxseSB0byBhbiBBUEkgZm9yIGR5bmFtaWMgdmFsdWVcbiAgZmVlRGF0YSgpOiBzdHJpbmcge1xuICAgIHJldHVybiAnLTEwMDAwJztcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhlIHByb3ZpZGVkIGFkZHJlc3MgaXMgYSB2YWxpZCBJQ1AgYWRkcmVzcy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3MgLSBUaGUgYWRkcmVzcyB0byB2YWxpZGF0ZS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGFkZHJlc3MgaXMgdmFsaWQsIG90aGVyd2lzZSBgZmFsc2VgLlxuICAgKi9cbiAgaXNWYWxpZEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgY29uc3Qgcm9vdEFkZHJlc3MgPSB0aGlzLnZhbGlkYXRlTWVtb0FuZFJldHVyblJvb3RBZGRyZXNzKGFkZHJlc3MpO1xuICAgIHJldHVybiByb290QWRkcmVzcyAhPT0gdW5kZWZpbmVkICYmIHRoaXMuaXNWYWxpZEhhc2gocm9vdEFkZHJlc3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB0aGUgbWVtbyBJRCBpbiB0aGUgYWRkcmVzcyBhbmQgcmV0dXJucyB0aGUgcm9vdCBhZGRyZXNzLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzcyAtIFRoZSBhZGRyZXNzIHRvIHZhbGlkYXRlIGFuZCBleHRyYWN0IHRoZSByb290IGFkZHJlc3MgZnJvbS5cbiAgICogQHJldHVybnMge3N0cmluZyB8IHVuZGVmaW5lZH0gLSBUaGUgcm9vdCBhZGRyZXNzIGlmIHZhbGlkLCBvdGhlcndpc2UgYHVuZGVmaW5lZGAuXG4gICAqL1xuICB2YWxpZGF0ZU1lbW9BbmRSZXR1cm5Sb290QWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghYWRkcmVzcykge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY29uc3QgW3Jvb3RBZGRyZXNzLCBtZW1vSWRdID0gYWRkcmVzcy5zcGxpdCgnP21lbW9JZD0nKTtcbiAgICBpZiAobWVtb0lkICYmIHRoaXMudmFsaWRhdGVNZW1vKEJpZ0ludChtZW1vSWQpKSkge1xuICAgICAgcmV0dXJuIHJvb3RBZGRyZXNzO1xuICAgIH1cbiAgICByZXR1cm4gYWRkcmVzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhlIHByb3ZpZGVkIGhleCBzdHJpbmcgaXMgYSB2YWxpZCBwdWJsaWMga2V5LlxuICAgKlxuICAgKiBBIHZhbGlkIHB1YmxpYyBrZXkgY2FuIGJlIGVpdGhlciBjb21wcmVzc2VkIG9yIHVuY29tcHJlc3NlZDpcbiAgICogLSBDb21wcmVzc2VkIHB1YmxpYyBrZXlzIGFyZSAzMyBieXRlcyBsb25nIGFuZCBzdGFydCB3aXRoIGVpdGhlciAweDAyIG9yIDB4MDMuXG4gICAqIC0gVW5jb21wcmVzc2VkIHB1YmxpYyBrZXlzIGFyZSA2NSBieXRlcyBsb25nIGFuZCBzdGFydCB3aXRoIDB4MDQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBoZXhTdHIgLSBUaGUgaGV4IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgcHVibGljIGtleSB0byB2YWxpZGF0ZS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGhleCBzdHJpbmcgaXMgYSB2YWxpZCBwdWJsaWMga2V5LCBvdGhlcndpc2UgYGZhbHNlYC5cbiAgICovXG4gIGlzVmFsaWRQdWJsaWNLZXkoaGV4U3RyOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBpZiAoIXRoaXMuaXNWYWxpZEhleChoZXhTdHIpIHx8ICF0aGlzLmlzVmFsaWRMZW5ndGgoaGV4U3RyKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IHB1YktleUJ5dGVzID0gdGhpcy5oZXhUb0J5dGVzKGhleFN0cik7XG4gICAgY29uc3QgZmlyc3RCeXRlID0gcHViS2V5Qnl0ZXNbMF07XG4gICAgY29uc3QgdmFsaWRDb21wcmVzc2VkID0gcHViS2V5Qnl0ZXMubGVuZ3RoID09PSAzMyAmJiAoZmlyc3RCeXRlID09PSAyIHx8IGZpcnN0Qnl0ZSA9PT0gMyk7XG4gICAgY29uc3QgdmFsaWRVbmNvbXByZXNzZWQgPSBwdWJLZXlCeXRlcy5sZW5ndGggPT09IDY1ICYmIGZpcnN0Qnl0ZSA9PT0gNDtcblxuICAgIHJldHVybiB2YWxpZENvbXByZXNzZWQgfHwgdmFsaWRVbmNvbXByZXNzZWQ7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlcyBhIHZhbHVlIGludG8gQ0JPUiBmb3JtYXQgYW5kIHJldHVybnMgaXQgYXMgYSBoZXggc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0ge3Vua25vd259IHZhbHVlIC0gVGhlIHZhbHVlIHRvIGVuY29kZS5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgQ0JPUiBlbmNvZGVkIHZhbHVlIGFzIGEgaGV4IHN0cmluZy5cbiAgICovXG4gIGNib3JFbmNvZGUodmFsdWU6IHVua25vd24pOiBzdHJpbmcge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1ZhbHVlIHRvIGVuY29kZSBjYW5ub3QgYmUgdW5kZWZpbmVkLicpO1xuICAgIH1cbiAgICBjb25zdCBjYm9yRGF0YSA9IGVuY29kZSh2YWx1ZSk7XG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGNib3JEYXRhKS50b1N0cmluZygnaGV4Jyk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBsZW5ndGggb2YgdGhlIGdpdmVuIGhleGFkZWNpbWFsIHN0cmluZyBpcyB2YWxpZC5cbiAgICogQSB2YWxpZCBsZW5ndGggaXMgZWl0aGVyIDY2IGNoYXJhY3RlcnMgKDMzIGJ5dGVzKSBvciAxMzAgY2hhcmFjdGVycyAoNjUgYnl0ZXMpLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGV4U3RyIC0gVGhlIGhleGFkZWNpbWFsIHN0cmluZyB0byBjaGVjay5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGxlbmd0aCBpcyB2YWxpZCwgb3RoZXJ3aXNlIGBmYWxzZWAuXG4gICAqL1xuICBpc1ZhbGlkTGVuZ3RoKGhleFN0cjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGhleFN0ci5sZW5ndGggLyAyID09PSAzMyB8fCBoZXhTdHIubGVuZ3RoIC8gMiA9PT0gNjU7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBwcm92aWRlZCBzdHJpbmcgaXMgYSB2YWxpZCBoZXhhZGVjaW1hbCBzdHJpbmcuXG4gICAqXG4gICAqIEEgdmFsaWQgaGV4YWRlY2ltYWwgc3RyaW5nIGNvbnNpc3RzIG9mIHBhaXJzIG9mIGhleGFkZWNpbWFsIGRpZ2l0cyAoMC05LCBhLWYsIEEtRikuXG4gICAqXG4gICAqIEBwYXJhbSBoZXhTdHIgLSBUaGUgc3RyaW5nIHRvIGJlIHZhbGlkYXRlZCBhcyBhIGhleGFkZWNpbWFsIHN0cmluZy5cbiAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgc3RyaW5nIGlzIGEgdmFsaWQgaGV4YWRlY2ltYWwgc3RyaW5nLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqL1xuICBpc1ZhbGlkSGV4KGhleFN0cjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIC9eKFswLTlhLWZBLUZdezJ9KSskLy50ZXN0KGhleFN0cik7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBoZXhhZGVjaW1hbCBzdHJpbmcgdG8gYSBVaW50OEFycmF5LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGV4IC0gVGhlIGhleGFkZWNpbWFsIHN0cmluZyB0byBjb252ZXJ0LlxuICAgKiBAcmV0dXJucyB7VWludDhBcnJheX0gVGhlIHJlc3VsdGluZyBieXRlIGFycmF5LlxuICAgKi9cbiAgaGV4VG9CeXRlcyhoZXg6IHN0cmluZyk6IFVpbnQ4QXJyYXkge1xuICAgIGNvbnN0IGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoaGV4Lmxlbmd0aCAvIDIpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaGV4Lmxlbmd0aDsgaSArPSAyKSB7XG4gICAgICBieXRlc1tpIC8gMl0gPSBwYXJzZUludChoZXguc3Vic3RyKGksIDIpLCAxNik7XG4gICAgfVxuICAgIHJldHVybiBieXRlcztcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkUHJpdmF0ZUtleShrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzVmFsaWRLZXkoa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgd2hldGhlciB0aGUgcHJvdmlkZWQga2V5IGlzIGEgdmFsaWQgSUNQIHByaXZhdGUga2V5LlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGF0dGVtcHRzIHRvIGNyZWF0ZSBhIG5ldyBpbnN0YW5jZSBvZiBgSWNwS2V5UGFpcmAgdXNpbmcgdGhlIHByb3ZpZGVkIGtleS5cbiAgICogSWYgdGhlIGtleSBpcyB2YWxpZCwgdGhlIGZ1bmN0aW9uIHJldHVybnMgYHRydWVgLiBJZiB0aGUga2V5IGlzIGludmFsaWQsIGFuIGVycm9yIGlzIHRocm93bixcbiAgICogYW5kIHRoZSBmdW5jdGlvbiByZXR1cm5zIGBmYWxzZWAuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSBUaGUgcHJpdmF0ZSBrZXkgdG8gdmFsaWRhdGUuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIGB0cnVlYCBpZiB0aGUga2V5IGlzIHZhbGlkLCBgZmFsc2VgIG90aGVyd2lzZS5cbiAgICovXG4gIGlzVmFsaWRLZXkoa2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgbmV3IEljcEtleVBhaXIoeyBwcnY6IGtleSB9KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wcmVzc2VzIGFuIHVuY29tcHJlc3NlZCBwdWJsaWMga2V5LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdW5jb21wcmVzc2VkS2V5IC0gVGhlIHVuY29tcHJlc3NlZCBwdWJsaWMga2V5IGluIGhleGFkZWNpbWFsIGZvcm1hdC5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29tcHJlc3NlZCBwdWJsaWMga2V5IGluIGhleGFkZWNpbWFsIGZvcm1hdC5cbiAgICogQHRocm93cyB7RXJyb3J9IC0gSWYgdGhlIGlucHV0IGtleSBpcyBub3QgYSB2YWxpZCB1bmNvbXByZXNzZWQgcHVibGljIGtleS5cbiAgICovXG4gIGNvbXByZXNzUHVibGljS2V5KHVuY29tcHJlc3NlZEtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAodW5jb21wcmVzc2VkS2V5LnN0YXJ0c1dpdGgoJzAyJykgfHwgdW5jb21wcmVzc2VkS2V5LnN0YXJ0c1dpdGgoJzAzJykpIHtcbiAgICAgIHJldHVybiB1bmNvbXByZXNzZWRLZXk7XG4gICAgfVxuICAgIGlmICghdW5jb21wcmVzc2VkS2V5LnN0YXJ0c1dpdGgoJzA0JykgfHwgdW5jb21wcmVzc2VkS2V5Lmxlbmd0aCAhPT0gMTMwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdW5jb21wcmVzc2VkIHB1YmxpYyBrZXkgZm9ybWF0LicpO1xuICAgIH1cblxuICAgIGNvbnN0IHhIZXggPSB1bmNvbXByZXNzZWRLZXkuc2xpY2UoMiwgNjYpO1xuICAgIGNvbnN0IHlIZXggPSB1bmNvbXByZXNzZWRLZXkuc2xpY2UoNjYpO1xuICAgIGNvbnN0IHkgPSBCaWdJbnQoYDB4JHt5SGV4fWApO1xuICAgIGNvbnN0IHByZWZpeCA9IHkgJSAybiA9PT0gMG4gPyAnMDInIDogJzAzJztcblxuICAgIHJldHVybiBgJHtwcmVmaXh9JHt4SGV4fWA7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBwdWJsaWMga2V5IGZyb20gaXRzIGhleGFkZWNpbWFsIHN0cmluZyByZXByZXNlbnRhdGlvbiB0byBERVIgZm9ybWF0LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHVibGljS2V5SGV4IC0gVGhlIHB1YmxpYyBrZXkgaW4gaGV4YWRlY2ltYWwgc3RyaW5nIGZvcm1hdC5cbiAgICogQHJldHVybnMgVGhlIHB1YmxpYyBrZXkgaW4gREVSIGZvcm1hdCBhcyBhIFVpbnQ4QXJyYXkuXG4gICAqL1xuICBnZXRQdWJsaWNLZXlJbkRFUkZvcm1hdChwdWJsaWNLZXlIZXg6IHN0cmluZyk6IFVpbnQ4QXJyYXkge1xuICAgIGNvbnN0IHB1YmxpY0tleUJ1ZmZlciA9IEJ1ZmZlci5mcm9tKHB1YmxpY0tleUhleCwgJ2hleCcpO1xuICAgIGNvbnN0IGVsbGlwdGljS2V5ID0gc2VjcDI1NmsxLlByb2plY3RpdmVQb2ludC5mcm9tSGV4KHB1YmxpY0tleUJ1ZmZlci50b1N0cmluZygnaGV4JykpO1xuICAgIGNvbnN0IHVuY29tcHJlc3NlZFB1YmxpY0tleUhleCA9IGVsbGlwdGljS2V5LnRvSGV4KGZhbHNlKTtcbiAgICBjb25zdCBkZXJFbmNvZGVkS2V5ID0gYWdlbnQud3JhcERFUihCdWZmZXIuZnJvbSh1bmNvbXByZXNzZWRQdWJsaWNLZXlIZXgsICdoZXgnKSwgYWdlbnQuU0VDUDI1NksxX09JRCk7XG4gICAgcmV0dXJuIGRlckVuY29kZWRLZXk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBwdWJsaWMga2V5IGluIGhleGFkZWNpbWFsIGZvcm1hdCB0byBhIERmaW5pdHkgUHJpbmNpcGFsIElELlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHVibGljS2V5SGV4IC0gVGhlIHB1YmxpYyBrZXkgaW4gaGV4YWRlY2ltYWwgZm9ybWF0LlxuICAgKiBAcmV0dXJucyBUaGUgY29ycmVzcG9uZGluZyBEZmluaXR5IFByaW5jaXBhbCBJRC5cbiAgICovXG4gIGdldFByaW5jaXBhbElkRnJvbVB1YmxpY0tleShwdWJsaWNLZXlIZXg6IHN0cmluZyk6IERmaW5pdHlQcmluY2lwYWwge1xuICAgIGNvbnN0IGRlckVuY29kZWRLZXkgPSB0aGlzLmdldFB1YmxpY0tleUluREVSRm9ybWF0KHB1YmxpY0tleUhleCk7XG4gICAgY29uc3QgcHJpbmNpcGFsSWQgPSBEZmluaXR5UHJpbmNpcGFsLnNlbGZBdXRoZW50aWNhdGluZyhCdWZmZXIuZnJvbShkZXJFbmNvZGVkS2V5KSk7XG4gICAgcmV0dXJuIHByaW5jaXBhbElkO1xuICB9XG5cbiAgLyoqXG4gICAqIERlcml2ZXMgYSBEZmluaXR5UHJpbmNpcGFsIGZyb20gYSBnaXZlbiBwdWJsaWMga2V5IGluIGhleGFkZWNpbWFsIGZvcm1hdC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHB1YmxpY0tleUhleCAtIFRoZSBwdWJsaWMga2V5IGluIGhleGFkZWNpbWFsIGZvcm1hdC5cbiAgICogQHJldHVybnMgVGhlIGRlcml2ZWQgRGZpbml0eVByaW5jaXBhbC5cbiAgICogQHRocm93cyBXaWxsIHRocm93IGFuIGVycm9yIGlmIHRoZSBwcmluY2lwYWwgY2Fubm90IGJlIGRlcml2ZWQgZnJvbSB0aGUgcHVibGljIGtleS5cbiAgICovXG4gIGRlcml2ZVByaW5jaXBhbEZyb21QdWJsaWNLZXkocHVibGljS2V5SGV4OiBzdHJpbmcpOiBEZmluaXR5UHJpbmNpcGFsIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZGVyRW5jb2RlZEtleSA9IHRoaXMuZ2V0UHVibGljS2V5SW5ERVJGb3JtYXQocHVibGljS2V5SGV4KTtcbiAgICAgIGNvbnN0IHByaW5jaXBhbElkID0gRGZpbml0eVByaW5jaXBhbC5zZWxmQXV0aGVudGljYXRpbmcoQnVmZmVyLmZyb20oZGVyRW5jb2RlZEtleSkpO1xuICAgICAgY29uc3QgcHJpbmNpcGFsID0gRGZpbml0eVByaW5jaXBhbC5mcm9tVWludDhBcnJheShwcmluY2lwYWxJZC50b1VpbnQ4QXJyYXkoKSk7XG4gICAgICByZXR1cm4gcHJpbmNpcGFsO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBkZXJpdmUgcHJpbmNpcGFsIGZyb20gcHVibGljIGtleTogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0cyBhIERmaW5pdHlQcmluY2lwYWwgYW5kIGFuIG9wdGlvbmFsIHN1YkFjY291bnQgdG8gYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYW4gYWNjb3VudCBJRC5cbiAgICpcbiAgICogQHBhcmFtIHtEZmluaXR5UHJpbmNpcGFsfSBwcmluY2lwYWwgLSBUaGUgcHJpbmNpcGFsIHRvIGNvbnZlcnQuXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gW3N1YkFjY291bnQ9bmV3IFVpbnQ4QXJyYXkoMzIpXSAtIEFuIG9wdGlvbmFsIHN1Yi1hY2NvdW50LCBkZWZhdWx0cyB0byBhIDMyLWJ5dGUgYXJyYXkgb2YgemVyb3MuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBoZXhhZGVjaW1hbCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGFjY291bnQgSUQuXG4gICAqL1xuICBmcm9tUHJpbmNpcGFsKHByaW5jaXBhbDogRGZpbml0eVByaW5jaXBhbCwgc3ViQWNjb3VudDogVWludDhBcnJheSA9IG5ldyBVaW50OEFycmF5KDMyKSk6IHN0cmluZyB7XG4gICAgY29uc3QgcHJpbmNpcGFsQnl0ZXMgPSBCdWZmZXIuZnJvbShwcmluY2lwYWwudG9VaW50OEFycmF5KCkuYnVmZmVyKTtcbiAgICByZXR1cm4gdGhpcy5nZXRBY2NvdW50SWRGcm9tUHJpbmNpcGFsQnl0ZXModGhpcy5nZXRBY2NvdW50SWRQcmVmaXgoKSwgcHJpbmNpcGFsQnl0ZXMsIHN1YkFjY291bnQpO1xuICB9XG5cbiAgZ2V0QWNjb3VudElkRnJvbVByaW5jaXBhbEJ5dGVzKFxuICAgIEFDQ09VTlRfSURfUFJFRklYOiBCdWZmZXI8QXJyYXlCdWZmZXI+LFxuICAgIHByaW5jaXBhbEJ5dGVzOiBCdWZmZXI8QXJyYXlCdWZmZXJMaWtlPixcbiAgICBzdWJBY2NvdW50OiBVaW50OEFycmF5PEFycmF5QnVmZmVyTGlrZT5cbiAgKTogc3RyaW5nIHtcbiAgICBjb25zdCBjb21iaW5lZEJ5dGVzID0gQnVmZmVyLmNvbmNhdChbQUNDT1VOVF9JRF9QUkVGSVgsIHByaW5jaXBhbEJ5dGVzLCBzdWJBY2NvdW50XSk7XG4gICAgY29uc3Qgc2hhMjI0SGFzaCA9IGNyeXB0by5jcmVhdGVIYXNoKCdzaGEyMjQnKS51cGRhdGUoY29tYmluZWRCeXRlcykuZGlnZXN0KCk7XG4gICAgY29uc3QgY2hlY2tzdW0gPSBCdWZmZXIuYWxsb2MoNCk7XG4gICAgY2hlY2tzdW0ud3JpdGVVSW50MzJCRShjcmMzMi5idWYoc2hhMjI0SGFzaCkgPj4+IDAsIDApO1xuICAgIGNvbnN0IGFjY291bnRJZEJ5dGVzID0gQnVmZmVyLmNvbmNhdChbY2hlY2tzdW0sIHNoYTIyNEhhc2hdKTtcbiAgICByZXR1cm4gYWNjb3VudElkQnl0ZXMudG9TdHJpbmcoJ2hleCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgYWRkcmVzcyBhc3NvY2lhdGVkIHdpdGggYSBnaXZlbiBoZXgtZW5jb2RlZCBwdWJsaWMga2V5LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGV4RW5jb2RlZFB1YmxpY0tleSAtIFRoZSBwdWJsaWMga2V5IGluIGhleC1lbmNvZGVkIGZvcm1hdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGFkZHJlc3MgZGVyaXZlZCBmcm9tIHRoZSBwcm92aWRlZCBwdWJsaWMga2V5LlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBwcm92aWRlZCBwdWJsaWMga2V5IGlzIG5vdCBpbiBhIHZhbGlkIGhleC1lbmNvZGVkIGZvcm1hdC5cbiAgICovXG4gIGFzeW5jIGdldEFkZHJlc3NGcm9tUHVibGljS2V5KGhleEVuY29kZWRQdWJsaWNLZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRQdWJsaWNLZXkoaGV4RW5jb2RlZFB1YmxpY0tleSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXgtZW5jb2RlZCBwdWJsaWMga2V5IGZvcm1hdC4nKTtcbiAgICB9XG4gICAgY29uc3QgY29tcHJlc3NlZEtleSA9IHRoaXMuY29tcHJlc3NQdWJsaWNLZXkoaGV4RW5jb2RlZFB1YmxpY0tleSk7XG4gICAgY29uc3Qga2V5UGFpciA9IG5ldyBJY3BLZXlQYWlyKHsgcHViOiBjb21wcmVzc2VkS2V5IH0pO1xuICAgIHJldHVybiBrZXlQYWlyLmdldEFkZHJlc3MoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYSBuZXcga2V5IHBhaXIuIElmIGEgc2VlZCBpcyBwcm92aWRlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGdlbmVyYXRlIHRoZSBrZXkgcGFpci5cbiAgICpcbiAgICogQHBhcmFtIHtCdWZmZXJ9IFtzZWVkXSAtIE9wdGlvbmFsIHNlZWQgZm9yIGtleSBnZW5lcmF0aW9uLlxuICAgKiBAcmV0dXJucyB7S2V5UGFpcn0gLSBUaGUgZ2VuZXJhdGVkIGtleSBwYWlyIGNvbnRhaW5pbmcgYm90aCBwdWJsaWMgYW5kIHByaXZhdGUga2V5cy5cbiAgICogQHRocm93cyB7RXJyb3J9IC0gSWYgdGhlIHByaXZhdGUga2V5IGlzIG1pc3NpbmcgaW4gdGhlIGdlbmVyYXRlZCBrZXkgcGFpci5cbiAgICovXG4gIHB1YmxpYyBnZW5lcmF0ZUtleVBhaXIoc2VlZD86IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIGNvbnN0IGtleVBhaXIgPSBzZWVkID8gbmV3IEljcEtleVBhaXIoeyBzZWVkIH0pIDogbmV3IEljcEtleVBhaXIoKTtcbiAgICBjb25zdCB7IHB1YiwgcHJ2IH0gPSBrZXlQYWlyLmdldEtleXMoKTtcbiAgICBpZiAoIXBydikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdQcml2YXRlIGtleSBpcyBtaXNzaW5nIGluIHRoZSBnZW5lcmF0ZWQga2V5IHBhaXIuJyk7XG4gICAgfVxuICAgIHJldHVybiB7IHB1YiwgcHJ2IH07XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoZSBwcm92aWRlZCBmZWUuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBmZWUgLSBUaGUgZmVlIHRvIHZhbGlkYXRlLlxuICAgKiBAdGhyb3dzIHtCdWlsZFRyYW5zYWN0aW9uRXJyb3J9IC0gSWYgdGhlIGZlZSBpcyB6ZXJvIG9yIGludmFsaWQuXG4gICAqL1xuICB2YWxpZGF0ZUZlZShmZWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGZlZVZhbHVlID0gbmV3IEJpZ051bWJlcihmZWUpO1xuICAgIGlmIChmZWVWYWx1ZS5pc1plcm8oKSkge1xuICAgICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcignRmVlIGNhbm5vdCBiZSB6ZXJvJyk7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIHZhbGlkYXRlVmFsdWUodmFsdWU6IEJpZ051bWJlcik6IGJvb2xlYW4ge1xuICAgIGlmICh2YWx1ZS5pc0xlc3NUaGFuT3JFcXVhbFRvKDApKSB7XG4gICAgICB0aHJvdyBuZXcgQnVpbGRUcmFuc2FjdGlvbkVycm9yKCdhbW91bnQgY2Fubm90IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byB6ZXJvJyk7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB0aGUgcHJvdmlkZWQgbWVtby5cbiAgICpcbiAgICogQHBhcmFtIHtudW1iZXIgfCBCaWdJbnR9IG1lbW8gLSBUaGUgbWVtbyB0byB2YWxpZGF0ZS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIG1lbW8gaXMgdmFsaWQuXG4gICAqIEB0aHJvd3Mge0J1aWxkVHJhbnNhY3Rpb25FcnJvcn0gLSBJZiB0aGUgbWVtbyBpcyBpbnZhbGlkLlxuICAgKi9cbiAgdmFsaWRhdGVNZW1vKG1lbW86IG51bWJlciB8IEJpZ0ludCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IG1lbW9OdW1iZXIgPSBOdW1iZXIobWVtbyk7XG4gICAgaWYgKG1lbW9OdW1iZXIgPCAwIHx8IE51bWJlci5pc05hTihtZW1vTnVtYmVyKSkge1xuICAgICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcignSW52YWxpZCBtZW1vJyk7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgdmFsaWRhdGVFeHBpcmVUaW1lKGV4cGlyZVRpbWU6IG51bWJlciB8IEJpZ0ludCk6IGJvb2xlYW4ge1xuICAgIGlmIChOdW1iZXIoZXhwaXJlVGltZSkgPCBEYXRlLm5vdygpICogMTAwMF8wMDApIHtcbiAgICAgIHRocm93IG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoJ0ludmFsaWQgZXhwaXJ5IHRpbWUnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoZSByYXcgdHJhbnNhY3Rpb24gZGF0YSB0byBlbnN1cmUgaXQgaGFzIGEgdmFsaWQgZm9ybWF0IGluIHRoZSBibG9ja2NoYWluIGNvbnRleHQuXG4gICAqXG4gICAqIEBwYXJhbSB7SWNwVHJhbnNhY3Rpb25EYXRhfSB0cmFuc2FjdGlvbkRhdGEgLSBUaGUgdHJhbnNhY3Rpb24gZGF0YSB0byB2YWxpZGF0ZS5cbiAgICogQHRocm93cyB7UGFyc2VUcmFuc2FjdGlvbkVycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZGF0YSBpcyBpbnZhbGlkLlxuICAgKi9cbiAgdmFsaWRhdGVSYXdUcmFuc2FjdGlvbih0cmFuc2FjdGlvbkRhdGE6IEljcFRyYW5zYWN0aW9uRGF0YSk6IHZvaWQge1xuICAgIGlmICghdHJhbnNhY3Rpb25EYXRhKSB7XG4gICAgICB0aHJvdyBuZXcgUGFyc2VUcmFuc2FjdGlvbkVycm9yKCdUcmFuc2FjdGlvbiBkYXRhIGlzIG1pc3NpbmcuJyk7XG4gICAgfVxuICAgIGNvbnN0IHsgc2VuZGVyUHVibGljS2V5SGV4LCBzZW5kZXJBZGRyZXNzLCByZWNlaXZlckFkZHJlc3MgfSA9IHRyYW5zYWN0aW9uRGF0YTtcbiAgICBpZiAoc2VuZGVyUHVibGljS2V5SGV4ICYmICF0aGlzLmlzVmFsaWRQdWJsaWNLZXkoc2VuZGVyUHVibGljS2V5SGV4KSkge1xuICAgICAgdGhyb3cgbmV3IFBhcnNlVHJhbnNhY3Rpb25FcnJvcignU2VuZGVyIHB1YmxpYyBrZXkgaXMgaW52YWxpZC4nKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRBZGRyZXNzKHNlbmRlckFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgUGFyc2VUcmFuc2FjdGlvbkVycm9yKCdTZW5kZXIgYWRkcmVzcyBpcyBpbnZhbGlkLicpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuaXNWYWxpZEFkZHJlc3MocmVjZWl2ZXJBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IFBhcnNlVHJhbnNhY3Rpb25FcnJvcignUmVjZWl2ZXIgYWRkcmVzcyBpcyBpbnZhbGlkLicpO1xuICAgIH1cbiAgICB0aGlzLnZhbGlkYXRlRmVlKHRyYW5zYWN0aW9uRGF0YS5mZWUpO1xuICAgIHRoaXMudmFsaWRhdGVWYWx1ZShuZXcgQmlnTnVtYmVyKHRyYW5zYWN0aW9uRGF0YS5hbW91bnQpKTtcbiAgICB0aGlzLnZhbGlkYXRlTWVtbyh0cmFuc2FjdGlvbkRhdGEubWVtbyk7XG4gICAgdGhpcy52YWxpZGF0ZUV4cGlyZVRpbWUodHJhbnNhY3Rpb25EYXRhLmV4cGlyeVRpbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSB1cGRhdGVcbiAgICogQHJldHVybnMge0J1ZmZlcn1cbiAgICovXG4gIGdlbmVyYXRlSHR0cENhbmlzdGVyVXBkYXRlSWQodXBkYXRlOiBIdHRwQ2FuaXN0ZXJVcGRhdGUpOiBCdWZmZXIge1xuICAgIHJldHVybiB0aGlzLkh0dHBDYW5pc3RlclVwZGF0ZVJlcHJlc2VudGF0aW9uSW5kZXBlbmRlbnRIYXNoKHVwZGF0ZSk7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGEgcmVwcmVzZW50YXRpb24taW5kZXBlbmRlbnQgaGFzaCBmb3IgYW4gSFRUUCBjYW5pc3RlciB1cGRhdGUuXG4gICAqXG4gICAqIEBwYXJhbSB7SHR0cENhbmlzdGVyVXBkYXRlfSB1cGRhdGUgLSBUaGUgSFRUUCBjYW5pc3RlciB1cGRhdGUgb2JqZWN0LlxuICAgKiBAcmV0dXJucyB7QnVmZmVyfSAtIFRoZSBoYXNoIG9mIHRoZSB1cGRhdGUgb2JqZWN0LlxuICAgKi9cbiAgSHR0cENhbmlzdGVyVXBkYXRlUmVwcmVzZW50YXRpb25JbmRlcGVuZGVudEhhc2godXBkYXRlOiBIdHRwQ2FuaXN0ZXJVcGRhdGUpOiBCdWZmZXIge1xuICAgIGNvbnN0IHVwZGF0ZU1hcCA9IHtcbiAgICAgIHJlcXVlc3RfdHlwZTogUmVxdWVzdFR5cGUuQ0FMTCxcbiAgICAgIGNhbmlzdGVyX2lkOiB1cGRhdGUuY2FuaXN0ZXJfaWQsXG4gICAgICBtZXRob2RfbmFtZTogdXBkYXRlLm1ldGhvZF9uYW1lLFxuICAgICAgYXJnOiB1cGRhdGUuYXJnLFxuICAgICAgaW5ncmVzc19leHBpcnk6IHVwZGF0ZS5pbmdyZXNzX2V4cGlyeSxcbiAgICAgIHNlbmRlcjogdXBkYXRlLnNlbmRlcixcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLmhhc2hPZk1hcCh1cGRhdGVNYXApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIFNIQS0yNTYgaGFzaCBmb3IgYSBnaXZlbiBtYXAgb2JqZWN0LlxuICAgKlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSBtYXAgLSBUaGUgbWFwIG9iamVjdCB0byBoYXNoLlxuICAgKiBAcmV0dXJucyB7QnVmZmVyfSAtIFRoZSByZXN1bHRpbmcgaGFzaCBhcyBhIEJ1ZmZlci5cbiAgICovXG4gIGhhc2hPZk1hcChtYXA6IFJlY29yZDxzdHJpbmcsIGFueT4pOiBCdWZmZXIge1xuICAgIGNvbnN0IGhhc2hlczogQnVmZmVyW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGtleSBpbiBtYXApIHtcbiAgICAgIGhhc2hlcy5wdXNoKHRoaXMuaGFzaEtleVZhbChrZXksIG1hcFtrZXldKSk7XG4gICAgfVxuICAgIGhhc2hlcy5zb3J0KChidWYwLCBidWYxKSA9PiBidWYwLmNvbXBhcmUoYnVmMSkpO1xuICAgIHJldHVybiB0aGlzLnNoYTI1NihoYXNoZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIGhhc2ggZm9yIGEga2V5LXZhbHVlIHBhaXIuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSBUaGUga2V5IHRvIGhhc2guXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgQnVmZmVyIHwgQmlnSW50fSB2YWwgLSBUaGUgdmFsdWUgdG8gaGFzaC5cbiAgICogQHJldHVybnMge0J1ZmZlcn0gLSBUaGUgcmVzdWx0aW5nIGhhc2ggYXMgYSBCdWZmZXIuXG4gICAqL1xuICBoYXNoS2V5VmFsKGtleTogc3RyaW5nLCB2YWw6IGFueSk6IEJ1ZmZlciB7XG4gICAgY29uc3Qga2V5SGFzaCA9IHRoaXMuaGFzaFN0cmluZyhrZXkpO1xuICAgIGNvbnN0IHZhbEhhc2ggPSB0aGlzLmhhc2hWYWwodmFsKTtcbiAgICByZXR1cm4gQnVmZmVyLmNvbmNhdChba2V5SGFzaCwgdmFsSGFzaF0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIFNIQS0yNTYgaGFzaCBmb3IgYSBnaXZlbiBzdHJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSBzdHJpbmcgdG8gaGFzaC5cbiAgICogQHJldHVybnMge0J1ZmZlcn0gLSBUaGUgcmVzdWx0aW5nIGhhc2ggYXMgYSBCdWZmZXIuXG4gICAqL1xuICBoYXNoU3RyaW5nKHZhbHVlOiBzdHJpbmcpOiBCdWZmZXIge1xuICAgIHJldHVybiB0aGlzLnNoYTI1NihbQnVmZmVyLmZyb20odmFsdWUpXSk7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGEgaGFzaCBmb3IgYSA2NC1iaXQgdW5zaWduZWQgaW50ZWdlci5cbiAgICpcbiAgICogQHBhcmFtIHtiaWdpbnR9IG4gLSBUaGUgNjQtYml0IHVuc2lnbmVkIGludGVnZXIgdG8gaGFzaC5cbiAgICogQHJldHVybnMge0J1ZmZlcn0gLSBUaGUgcmVzdWx0aW5nIGhhc2ggYXMgYSBCdWZmZXIuXG4gICAqL1xuICBoYXNoVTY0KG46IGJpZ2ludCk6IEJ1ZmZlciB7XG4gICAgY29uc3QgYnVmID0gQnVmZmVyLmFsbG9jVW5zYWZlKDEwKTtcbiAgICBsZXQgaSA9IDA7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGNvbnN0IGJ5dGUgPSBOdW1iZXIobiAmIEJpZ0ludCgweDdmKSk7XG4gICAgICBuID4+PSBCaWdJbnQoNyk7XG4gICAgICBpZiAobiA9PT0gQmlnSW50KDApKSB7XG4gICAgICAgIGJ1ZltpXSA9IGJ5dGU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYnVmW2ldID0gYnl0ZSB8IDB4ODA7XG4gICAgICAgICsraTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaGFzaEJ5dGVzKGJ1Zi5zdWJhcnJheSgwLCBpICsgMSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIFNIQS0yNTYgaGFzaCBmb3IgYW4gYXJyYXkgb2YgZWxlbWVudHMuXG4gICAqXG4gICAqIEBwYXJhbSB7QXJyYXk8YW55Pn0gZWxlbWVudHMgLSBUaGUgYXJyYXkgb2YgZWxlbWVudHMgdG8gaGFzaC5cbiAgICogQHJldHVybnMge0J1ZmZlcn0gLSBUaGUgcmVzdWx0aW5nIGhhc2ggYXMgYSBCdWZmZXIuXG4gICAqL1xuICBoYXNoQXJyYXkoZWxlbWVudHM6IEFycmF5PGFueT4pOiBCdWZmZXIge1xuICAgIHJldHVybiB0aGlzLnNoYTI1NihlbGVtZW50cy5tYXAodGhpcy5oYXNoVmFsKSk7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGEgaGFzaCBmb3IgYSBnaXZlbiB2YWx1ZS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBCdWZmZXIgfCBCaWdJbnQgfCBudW1iZXIgfCBBcnJheTx1bmtub3duPn0gdmFsIC0gVGhlIHZhbHVlIHRvIGhhc2guXG4gICAqIEByZXR1cm5zIHtCdWZmZXJ9IC0gVGhlIHJlc3VsdGluZyBoYXNoIGFzIGEgQnVmZmVyLlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gLSBJZiB0aGUgdmFsdWUgdHlwZSBpcyB1bnN1cHBvcnRlZC5cbiAgICovXG4gIGhhc2hWYWwodmFsOiBzdHJpbmcgfCBCdWZmZXIgfCBCaWdJbnQgfCBudW1iZXIgfCBBcnJheTx1bmtub3duPik6IEJ1ZmZlciB7XG4gICAgaWYgKHR5cGVvZiB2YWwgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gdXRpbHMuaGFzaFN0cmluZyh2YWwpO1xuICAgIH0gZWxzZSBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkgfHwgdmFsIGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgcmV0dXJuIHV0aWxzLmhhc2hCeXRlcyh2YWwpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbCA9PT0gJ2JpZ2ludCcgfHwgdHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICAgIHJldHVybiB1dGlscy5oYXNoVTY0KEJpZ0ludCh2YWwpKTtcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkodmFsKSkge1xuICAgICAgcmV0dXJuIHV0aWxzLmhhc2hBcnJheSh2YWwpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIHZhbHVlIHR5cGUgZm9yIGhhc2hpbmc6ICR7dHlwZW9mIHZhbH1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29tcHV0ZXMgdGhlIFNIQS0yNTYgaGFzaCBvZiB0aGUgZ2l2ZW4gYnVmZmVyLlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgYnVmZmVyIHRvIGhhc2guXG4gICAqIEByZXR1cm5zIFRoZSBTSEEtMjU2IGhhc2ggb2YgdGhlIGlucHV0IGJ1ZmZlci5cbiAgICovXG4gIGhhc2hCeXRlcyh2YWx1ZTogQnVmZmVyIHwgVWludDhBcnJheSk6IEJ1ZmZlciB7XG4gICAgcmV0dXJuIHRoaXMuc2hhMjU2KFt2YWx1ZV0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbXB1dGVzIHRoZSBTSEEtMjU2IGhhc2ggb2YgdGhlIHByb3ZpZGVkIGFycmF5IG9mIEJ1ZmZlciBjaHVua3MuXG4gICAqXG4gICAqIEBwYXJhbSB7QXJyYXk8QnVmZmVyPn0gY2h1bmtzIC0gQW4gYXJyYXkgb2YgQnVmZmVyIG9iamVjdHMgdG8gYmUgaGFzaGVkLlxuICAgKiBAcmV0dXJucyB7QnVmZmVyfSAtIFRoZSByZXN1bHRpbmcgU0hBLTI1NiBoYXNoIGFzIGEgQnVmZmVyLlxuICAgKi9cbiAgc2hhMjU2KGNodW5rczogQXJyYXk8QnVmZmVyPiB8IEFycmF5PFVpbnQ4QXJyYXk+KTogQnVmZmVyIHtcbiAgICBjb25zdCBoYXNoZXIgPSBqc19zaGEyNTYuc2hhMjU2LmNyZWF0ZSgpO1xuICAgIGNodW5rcy5mb3JFYWNoKChjaHVuaykgPT4gaGFzaGVyLnVwZGF0ZShjaHVuaykpO1xuICAgIHJldHVybiBCdWZmZXIuZnJvbShoYXNoZXIuYXJyYXlCdWZmZXIoKSk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBoZXhhZGVjaW1hbCBzdHJpbmcgdG8gYSBCdWZmZXIuXG4gICAqXG4gICAqIEBwYXJhbSBoZXggLSBUaGUgaGV4YWRlY2ltYWwgc3RyaW5nIHRvIGNvbnZlcnQuXG4gICAqIEByZXR1cm5zIEEgQnVmZmVyIGNvbnRhaW5pbmcgdGhlIGJpbmFyeSBkYXRhIHJlcHJlc2VudGVkIGJ5IHRoZSBoZXhhZGVjaW1hbCBzdHJpbmcuXG4gICAqL1xuICBibG9iRnJvbUhleChoZXg6IHN0cmluZyk6IEJ1ZmZlciB7XG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGhleCwgJ2hleCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnRzIGEgYmluYXJ5IGJsb2IgKEJ1ZmZlcikgdG8gYSBoZXhhZGVjaW1hbCBzdHJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7QnVmZmVyfSBibG9iIC0gVGhlIGJpbmFyeSBkYXRhIHRvIGJlIGNvbnZlcnRlZC5cbiAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGhleGFkZWNpbWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBiaW5hcnkgZGF0YS5cbiAgICovXG4gIGJsb2JUb0hleChibG9iOiBCdWZmZXIpOiBzdHJpbmcge1xuICAgIHJldHVybiBibG9iLnRvU3RyaW5nKCdoZXgnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNvZGVzIGEgZ2l2ZW4gQ0JPUi1lbmNvZGVkIGJ1ZmZlci5cbiAgICpcbiAgICogQHBhcmFtIGJ1ZmZlciAtIFRoZSBDQk9SLWVuY29kZWQgYnVmZmVyIHRvIGRlY29kZS5cbiAgICogQHJldHVybnMgVGhlIGRlY29kZWQgZGF0YS5cbiAgICovXG4gIGNib3JEZWNvZGUoYnVmZmVyOiBCdWZmZXIpOiB1bmtub3duIHtcbiAgICBjb25zdCByZXMgPSBkZWNvZGUoYnVmZmVyKTtcbiAgICByZXR1cm4gcmVzO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIEJ1ZmZlciBjb250YWluaW5nIHRoZSBkb21haW4gSUMgcmVxdWVzdCBzdHJpbmcuXG4gICAqXG4gICAqIEByZXR1cm5zIHtCdWZmZXJ9IEEgQnVmZmVyIG9iamVjdCBpbml0aWFsaXplZCB3aXRoIHRoZSBzdHJpbmcgJ1xceDBBaWMtcmVxdWVzdCcuXG4gICAqL1xuICBnZXREb21haW5JQ1JlcXVlc3QoKTogQnVmZmVyIHtcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oJ1xceDBBaWMtcmVxdWVzdCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbWJpbmVzIHRoZSBkb21haW4gSUMgcmVxdWVzdCBidWZmZXIgd2l0aCB0aGUgcHJvdmlkZWQgbWVzc2FnZSBJRCBidWZmZXIgdG8gY3JlYXRlIHNpZ25hdHVyZSBkYXRhLlxuICAgKlxuICAgKiBAcGFyYW0ge0J1ZmZlcn0gbWVzc2FnZUlkIC0gVGhlIGJ1ZmZlciBjb250YWluaW5nIHRoZSBtZXNzYWdlIElELlxuICAgKiBAcmV0dXJucyB7QnVmZmVyfSAtIFRoZSBjb25jYXRlbmF0ZWQgYnVmZmVyIGNvbnRhaW5pbmcgdGhlIGRvbWFpbiBJQyByZXF1ZXN0IGFuZCB0aGUgbWVzc2FnZSBJRC5cbiAgICovXG4gIG1ha2VTaWduYXR1cmVEYXRhKG1lc3NhZ2VJZDogQnVmZmVyKTogQnVmZmVyIHtcbiAgICByZXR1cm4gQnVmZmVyLmNvbmNhdChbdGhpcy5nZXREb21haW5JQ1JlcXVlc3QoKSwgbWVzc2FnZUlkXSk7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdHMgdGhlIHJlY2lwaWVudCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBwcm92aWRlZCBJQ1AgdHJhbnNhY3Rpb24gZGF0YS5cbiAgICpcbiAgICogQHBhcmFtIHtJY3BUcmFuc2FjdGlvbkRhdGF9IGljcFRyYW5zYWN0aW9uRGF0YSAtIFRoZSBJQ1AgdHJhbnNhY3Rpb24gZGF0YSBjb250YWluaW5nIHRoZSByZWNlaXZlcidzIGFkZHJlc3MgYW5kIGFtb3VudC5cbiAgICogQHJldHVybnMge1JlY2lwaWVudFtdfSBBbiBhcnJheSBjb250YWluaW5nIGEgc2luZ2xlIHJlY2lwaWVudCBvYmplY3Qgd2l0aCB0aGUgcmVjZWl2ZXIncyBhZGRyZXNzIGFuZCBhbW91bnQuXG4gICAqL1xuICBnZXRSZWNpcGllbnRzKGljcFRyYW5zYWN0aW9uRGF0YTogSWNwVHJhbnNhY3Rpb25EYXRhKTogUmVjaXBpZW50IHtcbiAgICByZXR1cm4ge1xuICAgICAgYWRkcmVzczogaWNwVHJhbnNhY3Rpb25EYXRhLnJlY2VpdmVyQWRkcmVzcyxcbiAgICAgIGFtb3VudDogaWNwVHJhbnNhY3Rpb25EYXRhLmFtb3VudCxcbiAgICB9O1xuICB9XG5cbiAgZ2V0VHJhbnNhY3Rpb25TaWduYXR1cmUoc2lnbmF0dXJlTWFwOiBNYXA8c3RyaW5nLCBTaWduYXR1cmVzPiwgdXBkYXRlOiBIdHRwQ2FuaXN0ZXJVcGRhdGUpOiBTaWduYXR1cmVzIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gc2lnbmF0dXJlTWFwLmdldCh0aGlzLmJsb2JUb0hleCh0aGlzLm1ha2VTaWduYXR1cmVEYXRhKHRoaXMuZ2VuZXJhdGVIdHRwQ2FuaXN0ZXJVcGRhdGVJZCh1cGRhdGUpKSkpO1xuICB9XG5cbiAgZ2V0TWV0YURhdGEoXG4gICAgbWVtbzogbnVtYmVyIHwgQmlnSW50LFxuICAgIHRpbWVzdGFtcDogbnVtYmVyIHwgYmlnaW50IHwgdW5kZWZpbmVkLFxuICAgIGluZ3Jlc3NFbmQ6IG51bWJlciB8IEJpZ0ludCB8IHVuZGVmaW5lZFxuICApOiB7IG1ldGFEYXRhOiBNZXRhRGF0YTsgaW5ncmVzc0VuZFRpbWU6IG51bWJlciB8IEJpZ0ludCB9IHtcbiAgICBsZXQgY3VycmVudFRpbWUgPSBEYXRlLm5vdygpICogMTAwMDAwMDtcbiAgICBpZiAodGltZXN0YW1wKSB7XG4gICAgICBjdXJyZW50VGltZSA9IE51bWJlcih0aW1lc3RhbXApO1xuICAgIH1cbiAgICBsZXQgaW5ncmVzc1N0YXJ0VGltZTogbnVtYmVyLCBpbmdyZXNzRW5kVGltZTogbnVtYmVyO1xuICAgIGlmIChpbmdyZXNzRW5kKSB7XG4gICAgICBpbmdyZXNzRW5kVGltZSA9IE51bWJlcihpbmdyZXNzRW5kKTtcbiAgICAgIGluZ3Jlc3NTdGFydFRpbWUgPSBpbmdyZXNzRW5kVGltZSAtIE1BWF9JTkdSRVNTX1RUTDsgLy8gNSBtaW5zIGluIG5hbm9zZWNvbmRzXG4gICAgfSBlbHNlIHtcbiAgICAgIGluZ3Jlc3NTdGFydFRpbWUgPSBjdXJyZW50VGltZTtcbiAgICAgIGluZ3Jlc3NFbmRUaW1lID0gaW5ncmVzc1N0YXJ0VGltZSArIE1BWF9JTkdSRVNTX1RUTDsgLy8gNSBtaW5zIGluIG5hbm9zZWNvbmRzXG4gICAgfVxuICAgIGNvbnN0IG1ldGFEYXRhOiBNZXRhRGF0YSA9IHtcbiAgICAgIGNyZWF0ZWRfYXRfdGltZTogY3VycmVudFRpbWUsXG4gICAgICBpbmdyZXNzX3N0YXJ0OiBpbmdyZXNzU3RhcnRUaW1lLFxuICAgICAgaW5ncmVzc19lbmQ6IGluZ3Jlc3NFbmRUaW1lLFxuICAgICAgbWVtbzogbWVtbyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHsgbWV0YURhdGEsIGluZ3Jlc3NFbmRUaW1lIH07XG4gIH1cblxuICBjb252ZXJ0U2VuZGVyQmxvYlRvUHJpbmNpcGFsKHNlbmRlckJsb2I6IFVpbnQ4QXJyYXkpOiBVaW50OEFycmF5IHtcbiAgICBjb25zdCBNQVhfTEVOR1RIX0lOX0JZVEVTID0gMjk7XG4gICAgaWYgKHNlbmRlckJsb2IubGVuZ3RoID4gTUFYX0xFTkdUSF9JTl9CWVRFUykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdCeXRlcyB0b28gbG9uZyBmb3IgYSB2YWxpZCBQcmluY2lwYWwnKTtcbiAgICB9XG4gICAgY29uc3QgcHJpbmNpcGFsQnl0ZXMgPSBuZXcgVWludDhBcnJheShNQVhfTEVOR1RIX0lOX0JZVEVTKTtcbiAgICBwcmluY2lwYWxCeXRlcy5zZXQoc2VuZGVyQmxvYi5zbGljZSgwLCBzZW5kZXJCbG9iLmxlbmd0aCkpO1xuICAgIHJldHVybiBwcmluY2lwYWxCeXRlcztcbiAgfVxuXG4gIGZyb21BcmdzKGFyZzogVWludDhBcnJheSk6IFNlbmRBcmdzIHtcbiAgICBjb25zdCBTZW5kUmVxdWVzdE1lc3NhZ2UgPSBtZXNzYWdlQ29tcGlsZWQuU2VuZFJlcXVlc3Q7XG4gICAgY29uc3QgYXJncyA9IFNlbmRSZXF1ZXN0TWVzc2FnZS5kZWNvZGUoYXJnKSBhcyB1bmtub3duIGFzIFNlbmRBcmdzO1xuICAgIGNvbnN0IHRyYW5zZm9ybWVkQXJnczogU2VuZEFyZ3MgPSB7XG4gICAgICBwYXltZW50OiB7IHJlY2VpdmVyR2V0czogeyBlOHM6IE51bWJlcihhcmdzLnBheW1lbnQucmVjZWl2ZXJHZXRzLmU4cykgfSB9LFxuICAgICAgbWF4RmVlOiB7IGU4czogTnVtYmVyKGFyZ3MubWF4RmVlLmU4cykgfSxcbiAgICAgIHRvOiB7IGhhc2g6IEJ1ZmZlci5mcm9tKGFyZ3MudG8uaGFzaCkgfSxcbiAgICAgIGNyZWF0ZWRBdFRpbWU6IHsgdGltZXN0YW1wTmFub3M6IEJpZ051bWJlcihhcmdzLmNyZWF0ZWRBdFRpbWUudGltZXN0YW1wTmFub3MudG9TdHJpbmcoKSkudG9OdW1iZXIoKSB9LFxuICAgICAgbWVtbzogeyBtZW1vOiBOdW1iZXIoYXJncy5tZW1vLm1lbW8udG9TdHJpbmcoKSkgfSxcbiAgICB9O1xuICAgIHJldHVybiB0cmFuc2Zvcm1lZEFyZ3M7XG4gIH1cblxuICBhc3luYyB0b0FyZyhhcmdzOiBTZW5kQXJncyk6IFByb21pc2U8VWludDhBcnJheT4ge1xuICAgIGNvbnN0IFNlbmRSZXF1ZXN0TWVzc2FnZSA9IG1lc3NhZ2VDb21waWxlZC5TZW5kUmVxdWVzdDtcbiAgICBjb25zdCBlcnJNc2cgPSBTZW5kUmVxdWVzdE1lc3NhZ2UudmVyaWZ5KGFyZ3MpO1xuICAgIGlmIChlcnJNc2cpIHRocm93IG5ldyBFcnJvcihlcnJNc2cpO1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBTZW5kUmVxdWVzdE1lc3NhZ2UuY3JlYXRlKGFyZ3MgYXMgYW55KTtcbiAgICByZXR1cm4gU2VuZFJlcXVlc3RNZXNzYWdlLmVuY29kZShtZXNzYWdlKS5maW5pc2goKTtcbiAgfVxuXG4gIGdldEFjY291bnRJZFByZWZpeCgpOiBCdWZmZXI8QXJyYXlCdWZmZXI+IHtcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oWzB4MGEsIC4uLkJ1ZmZlci5mcm9tKCdhY2NvdW50LWlkJyldKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkQmxvY2tJZChoYXNoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAvLyBJQ1AgYmxvY2sgaGFzaGVzIGFyZSA2NC1jaGFyYWN0ZXIgaGV4YWRlY2ltYWwgc3RyaW5nc1xuICAgIHJldHVybiB0aGlzLmlzVmFsaWRIYXNoKGhhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgd2hldGhlciBvciBub3QgdGhlIHN0cmluZyBpcyBhIHZhbGlkIElDUCBoYXNoXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBoYXNoIC0gc3RyaW5nIHRvIHZhbGlkYXRlXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgaXNWYWxpZEhhc2goaGFzaDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHR5cGVvZiBoYXNoID09PSAnc3RyaW5nJyAmJiAvXlswLTlhLWZBLUZdezY0fSQvLnRlc3QoaGFzaCk7XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgaXNWYWxpZFRyYW5zYWN0aW9uSWQodHhJZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNWYWxpZEhhc2godHhJZCk7XG4gIH1cblxuICBnZXRTaWduYXR1cmVzKHBheWxvYWRzRGF0YTogUGF5bG9hZHNEYXRhLCBzZW5kZXJQdWJsaWNLZXk6IHN0cmluZywgc2VuZGVyUHJpdmF0ZUtleTogc3RyaW5nKTogU2lnbmF0dXJlc1tdIHtcbiAgICByZXR1cm4gcGF5bG9hZHNEYXRhLnBheWxvYWRzLm1hcCgocGF5bG9hZCkgPT4gKHtcbiAgICAgIHNpZ25pbmdfcGF5bG9hZDogcGF5bG9hZCxcbiAgICAgIHNpZ25hdHVyZV90eXBlOiBwYXlsb2FkLnNpZ25hdHVyZV90eXBlLFxuICAgICAgcHVibGljX2tleToge1xuICAgICAgICBoZXhfYnl0ZXM6IHNlbmRlclB1YmxpY0tleSxcbiAgICAgICAgY3VydmVfdHlwZTogQ3VydmVUeXBlLlNFQ1AyNTZLMSxcbiAgICAgIH0sXG4gICAgICBoZXhfYnl0ZXM6IHRoaXMuc2lnblBheWxvYWQoc2VuZGVyUHJpdmF0ZUtleSwgcGF5bG9hZC5oZXhfYnl0ZXMpLFxuICAgIH0pKTtcbiAgfVxuXG4gIHNpZ25QYXlsb2FkID0gKHByaXZhdGVLZXk6IHN0cmluZywgcGF5bG9hZEhleDogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgICBjb25zdCBwcml2YXRlS2V5Qnl0ZXMgPSBCdWZmZXIuZnJvbShwcml2YXRlS2V5LCAnaGV4Jyk7XG4gICAgY29uc3QgcGF5bG9hZEhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKEJ1ZmZlci5mcm9tKHBheWxvYWRIZXgsICdoZXgnKSkuZGlnZXN0KCdoZXgnKTtcbiAgICBjb25zdCBzaWduYXR1cmUgPSBzZWNwMjU2azEuc2lnbihwYXlsb2FkSGFzaCwgcHJpdmF0ZUtleUJ5dGVzKTtcbiAgICBjb25zdCByID0gQnVmZmVyLmZyb20oc2lnbmF0dXJlLnIudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDY0LCAnMCcpLCAnaGV4Jyk7XG4gICAgY29uc3QgcyA9IEJ1ZmZlci5mcm9tKHNpZ25hdHVyZS5zLnRvU3RyaW5nKDE2KS5wYWRTdGFydCg2NCwgJzAnKSwgJ2hleCcpO1xuICAgIHJldHVybiBCdWZmZXIuY29uY2F0KFtyLCBzXSkudG9TdHJpbmcoJ2hleCcpO1xuICB9O1xuXG4gIGdldFRyYW5zYWN0aW9uSWQodW5zaWduZWRUcmFuc2FjdGlvbjogc3RyaW5nLCBzZW5kZXJBZGRyZXNzOiBzdHJpbmcsIHJlY2VpdmVyQWRkcmVzczogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZGVjb2RlZFR4biA9IHV0aWxzLmNib3JEZWNvZGUodXRpbHMuYmxvYkZyb21IZXgodW5zaWduZWRUcmFuc2FjdGlvbikpIGFzIENib3JVbnNpZ25lZFRyYW5zYWN0aW9uO1xuICAgICAgY29uc3QgdXBkYXRlcyA9IGRlY29kZWRUeG4udXBkYXRlcyBhcyB1bmtub3duIGFzIFtzdHJpbmcsIEh0dHBDYW5pc3RlclVwZGF0ZV1bXTtcbiAgICAgIGZvciAoY29uc3QgWywgdXBkYXRlXSBvZiB1cGRhdGVzKSB7XG4gICAgICAgIGNvbnN0IHVwZGF0ZUFyZ3MgPSB1cGRhdGUuYXJnO1xuICAgICAgICBjb25zdCBzZW5kQXJncyA9IHV0aWxzLmZyb21BcmdzKHVwZGF0ZUFyZ3MpO1xuICAgICAgICBjb25zdCB0cmFuc2FjdGlvbkhhc2ggPSB0aGlzLmdlbmVyYXRlVHJhbnNhY3Rpb25IYXNoKHNlbmRBcmdzLCBzZW5kZXJBZGRyZXNzLCByZWNlaXZlckFkZHJlc3MpO1xuICAgICAgICByZXR1cm4gdHJhbnNhY3Rpb25IYXNoO1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1cGRhdGVzIGZvdW5kIGluIHRoZSB1bnNpZ25lZCB0cmFuc2FjdGlvbi4nKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gY29tcHV0ZSB0cmFuc2FjdGlvbiBJRDogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxuXG4gIHNhZmVCaWdJbnQodmFsdWU6IHVua25vd24pOiBudW1iZXIgfCBiaWdpbnQge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdiaWdpbnQnKSB7XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICAgIGNvbnN0IGlzVW5zYWZlID0gdmFsdWUgPiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUiB8fCB2YWx1ZSA8IE51bWJlci5NSU5fU0FGRV9JTlRFR0VSO1xuICAgICAgcmV0dXJuIGlzVW5zYWZlID8gQmlnSW50KHZhbHVlKSA6IHZhbHVlO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0eXBlOiBleHBlY3RlZCBhIG51bWJlciBvciBiaWdpbnQsIGJ1dCByZWNlaXZlZCAke3R5cGVvZiB2YWx1ZX1gKTtcbiAgfVxuXG4gIGdlbmVyYXRlVHJhbnNhY3Rpb25IYXNoKHNlbmRBcmdzOiBTZW5kQXJncywgc2VuZGVyQWRkcmVzczogc3RyaW5nLCByZWNlaXZlckFkZHJlc3M6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3Qgc2VuZGVyQWNjb3VudCA9IHRoaXMuYWNjb3VudElkZW50aWZpZXIoc2VuZGVyQWRkcmVzcyk7XG4gICAgY29uc3QgcmVjZWl2ZXJBY2NvdW50ID0gdGhpcy5hY2NvdW50SWRlbnRpZmllcihyZWNlaXZlckFkZHJlc3MpO1xuXG4gICAgY29uc3QgdHJhbnNmZXJGaWVsZHMgPSBuZXcgTWFwPGFueSwgYW55PihbXG4gICAgICBbMCwgc2VuZGVyQWNjb3VudF0sXG4gICAgICBbMSwgcmVjZWl2ZXJBY2NvdW50XSxcbiAgICAgIFsyLCBuZXcgTWFwKFtbMCwgdGhpcy5zYWZlQmlnSW50KE51bWJlcihzZW5kQXJncy5wYXltZW50LnJlY2VpdmVyR2V0cy5lOHMpKV1dKV0sXG4gICAgICBbMywgbmV3IE1hcChbWzAsIHNlbmRBcmdzLm1heEZlZS5lOHNdXSldLFxuICAgIF0pO1xuXG4gICAgY29uc3Qgb3BlcmF0aW9uTWFwID0gbmV3IE1hcChbWzIsIHRyYW5zZmVyRmllbGRzXV0pO1xuICAgIGNvbnN0IHR4bkZpZWxkcyA9IG5ldyBNYXA8YW55LCBhbnk+KFtcbiAgICAgIFswLCBvcGVyYXRpb25NYXBdLFxuICAgICAgWzEsIHRoaXMuc2FmZUJpZ0ludChzZW5kQXJncy5tZW1vLm1lbW8pXSxcbiAgICAgIFsyLCBuZXcgTWFwKFtbMCwgQmlnSW50KHNlbmRBcmdzLmNyZWF0ZWRBdFRpbWUudGltZXN0YW1wTmFub3MpXV0pXSxcbiAgICBdKTtcblxuICAgIGNvbnN0IHByb2Nlc3NlZFR4biA9IHRoaXMuZ2V0UHJvY2Vzc2VkVHJhbnNhY3Rpb25NYXAodHhuRmllbGRzKTtcbiAgICBjb25zdCBzZXJpYWxpemVkVHhuID0gZW5jb2Rlci5lbmNvZGUocHJvY2Vzc2VkVHhuKTtcbiAgICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShzZXJpYWxpemVkVHhuKS5kaWdlc3QoJ2hleCcpO1xuICB9XG5cbiAgYWNjb3VudElkZW50aWZpZXIoYWNjb3VudEFkZHJlc3M6IHN0cmluZyk6IEFjY291bnRJZGVudGlmaWVySGFzaCB7XG4gICAgY29uc3QgYnl0ZXMgPSBCdWZmZXIuZnJvbShhY2NvdW50QWRkcmVzcywgJ2hleCcpO1xuICAgIGlmIChieXRlcy5sZW5ndGggPT09IDMyKSB7XG4gICAgICByZXR1cm4geyBoYXNoOiBieXRlcy5zbGljZSg0KSB9O1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgQWNjb3VudElkZW50aWZpZXI6IDY0IGhleCBjaGFycywgZ290ICR7YWNjb3VudEFkZHJlc3MubGVuZ3RofWApO1xuICB9XG5cbiAgZ2V0UHJvY2Vzc2VkVHJhbnNhY3Rpb25NYXAodHhuTWFwOiBNYXA8YW55LCBhbnk+KTogTWFwPGFueSwgYW55PiB7XG4gICAgY29uc3Qgb3BlcmF0aW9uTWFwID0gdHhuTWFwLmdldCgwKTtcbiAgICBjb25zdCB0cmFuc2Zlck1hcCA9IG9wZXJhdGlvbk1hcC5nZXQoMik7XG4gICAgdHJhbnNmZXJNYXAuc2V0KDAsIHRoaXMuc2VyaWFsaXplQWNjb3VudElkZW50aWZpZXIodHJhbnNmZXJNYXAuZ2V0KDApKSk7XG4gICAgdHJhbnNmZXJNYXAuc2V0KDEsIHRoaXMuc2VyaWFsaXplQWNjb3VudElkZW50aWZpZXIodHJhbnNmZXJNYXAuZ2V0KDEpKSk7XG4gICAgcmV0dXJuIHR4bk1hcDtcbiAgfVxuXG4gIHNlcmlhbGl6ZUFjY291bnRJZGVudGlmaWVyKGFjY291bnRIYXNoOiBBY2NvdW50SWRlbnRpZmllckhhc2gpOiBzdHJpbmcge1xuICAgIGlmIChhY2NvdW50SGFzaCAmJiBhY2NvdW50SGFzaC5oYXNoKSB7XG4gICAgICBjb25zdCBoYXNoQnVmZmVyID0gYWNjb3VudEhhc2guaGFzaDtcbiAgICAgIGNvbnN0IGNoZWNrc3VtID0gQnVmZmVyLmFsbG9jKDQpO1xuICAgICAgY2hlY2tzdW0ud3JpdGVVSW50MzJCRShjcmMzMi5idWYoaGFzaEJ1ZmZlcikgPj4+IDAsIDApO1xuICAgICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW2NoZWNrc3VtLCBoYXNoQnVmZmVyXSkudG9TdHJpbmcoJ2hleCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBhY2NvdW50SGFzaCBmb3JtYXQnKTtcbiAgfVxufVxuXG5jb25zdCB1dGlscyA9IG5ldyBVdGlscygpO1xuZXhwb3J0IGRlZmF1bHQgdXRpbHM7XG4iXX0=

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


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