PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-sol/dist/src/lib
Просмотр файла: transactionBuilder.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TransactionBuilder = void 0;
const sdk_core_1 = require("@bitgo/sdk-core");
const transaction_1 = require("./transaction");
const web3_js_1 = require("@solana/web3.js");
const utils_1 = require("./utils");
const _1 = require(".");
const constants_1 = require("./constants");
const solInstructionFactory_1 = require("./solInstructionFactory");
const assert_1 = __importDefault(require("assert"));
const instructionParamsFactory_1 = require("./instructionParamsFactory");
class TransactionBuilder extends sdk_core_1.BaseTransactionBuilder {
constructor(_coinConfig) {
super(_coinConfig);
this._signatures = [];
this._instructionsData = [];
this._signers = [];
this.transaction = new transaction_1.Transaction(_coinConfig);
}
/**
* Initialize the transaction builder fields using the decoded transaction data
*
* @param {Transaction} tx the transaction data
*/
initBuilder(tx) {
this._transaction = tx;
const txData = tx.toJson();
const filteredTransferInstructionsData = txData.instructionsData.filter((data) => data.type === constants_1.InstructionBuilderTypes.Transfer);
let sender;
if (filteredTransferInstructionsData.length > 0) {
const transferInstructionsData = filteredTransferInstructionsData[0];
sender = transferInstructionsData.params.fromAddress;
}
else {
sender = txData.feePayer;
}
this.sender(sender);
this.feePayer(txData.feePayer);
this.nonce(txData.nonce, txData.durableNonce);
this._instructionsData = (0, instructionParamsFactory_1.instructionParamsFactory)(tx.type, tx.solTransaction.instructions, this._coinConfig.name);
// Parse priority fee instruction data
const filteredPriorityFeeInstructionsData = txData.instructionsData.filter((data) => data.type === constants_1.InstructionBuilderTypes.SetPriorityFee);
for (const instruction of this._instructionsData) {
if (instruction.type === constants_1.InstructionBuilderTypes.Memo) {
const memoInstruction = instruction;
this.memo(memoInstruction.params.memo);
}
if (instruction.type === constants_1.InstructionBuilderTypes.NonceAdvance) {
const advanceNonceInstruction = instruction;
this.nonce(txData.nonce, advanceNonceInstruction.params);
}
// If prio fee instruction exists, set the priority fee variable
if (instruction.type === constants_1.InstructionBuilderTypes.SetPriorityFee) {
const priorityFeeInstructionsData = filteredPriorityFeeInstructionsData[0];
this.setPriorityFee({ amount: Number(priorityFeeInstructionsData.params.fee) });
}
}
}
/** @inheritdoc */
fromImplementation(rawTransaction) {
const tx = new transaction_1.Transaction(this._coinConfig);
this.validateRawTransaction(rawTransaction);
tx.fromRawTransaction(rawTransaction);
this.initBuilder(tx);
return this.transaction;
}
/** @inheritdoc */
async buildImplementation() {
this.transaction.solTransaction = this.buildSolTransaction();
this.transaction.setTransactionType(this.transactionType);
this.transaction.loadInputsAndOutputs();
this._transaction.tokenAccountRentExemptAmount = this._tokenAccountRentExemptAmount;
return this.transaction;
}
/**
* Builds the solana transaction.
*/
buildSolTransaction() {
(0, assert_1.default)(this._sender, new sdk_core_1.BuildTransactionError('sender is required before building'));
(0, assert_1.default)(this._recentBlockhash, new sdk_core_1.BuildTransactionError('recent blockhash is required before building'));
const tx = new web3_js_1.Transaction();
if (this._transaction?.solTransaction?.signatures) {
tx.signatures = this._transaction?.solTransaction?.signatures;
}
tx.feePayer = this._feePayer ? new web3_js_1.PublicKey(this._feePayer) : new web3_js_1.PublicKey(this._sender);
if (this._nonceInfo) {
tx.nonceInfo = {
nonce: this._recentBlockhash,
nonceInstruction: (0, solInstructionFactory_1.solInstructionFactory)(this._nonceInfo)[0],
};
}
else {
tx.recentBlockhash = this._recentBlockhash;
}
for (const instruction of this._instructionsData) {
tx.add(...(0, solInstructionFactory_1.solInstructionFactory)(instruction));
}
if (this._memo) {
const memoData = {
type: constants_1.InstructionBuilderTypes.Memo,
params: {
memo: this._memo,
},
};
this._instructionsData.push(memoData);
tx.add(...(0, solInstructionFactory_1.solInstructionFactory)(memoData));
}
this._transaction.lamportsPerSignature = this._lamportsPerSignature;
for (const signer of this._signers) {
const publicKey = new web3_js_1.PublicKey(signer.getKeys().pub);
const secretKey = signer.getKeys(true).prv;
(0, assert_1.default)(secretKey instanceof Uint8Array);
tx.partialSign({ publicKey, secretKey });
}
for (const signature of this._signatures) {
const solPublicKey = new web3_js_1.PublicKey(signature.publicKey.pub);
tx.addSignature(solPublicKey, signature.signature);
}
return tx;
}
// region Getters and Setters
/** @inheritdoc */
get transaction() {
return this._transaction;
}
/** @inheritdoc */
set transaction(transaction) {
this._transaction = transaction;
}
/** @inheritdoc */
signImplementation(key) {
this.validateKey(key);
this.checkDuplicatedSigner(key);
const prv = key.key;
const signer = new _1.KeyPair({ prv: prv });
this._signers.push(signer);
return this._transaction;
}
/** @inheritDoc */
addSignature(publicKey, signature) {
this._signatures.push({ publicKey, signature });
}
/**
* Sets the sender of this transaction.
* This account will be responsible for paying transaction fees.
*
* @param {string} senderAddress the account that is sending this transaction
* @returns {TransactionBuilder} This transaction builder
*/
sender(senderAddress) {
(0, utils_1.validateAddress)(senderAddress, 'sender');
this._sender = senderAddress;
return this;
}
/**
* Set the transaction nonce
* Requires both optional params in order to use the durable nonce
*
* @param {Blockhash} blockHash The latest blockHash
* @param {DurableNonceParams} [durableNonceParams] An object containing the walletNonceAddress and the authWalletAddress (required for durable nonce)
* @returns {TransactionBuilder} This transaction builder
*/
nonce(blockHash, durableNonceParams) {
if (!blockHash || !(0, utils_1.isValidBlockId)(blockHash)) {
throw new sdk_core_1.BuildTransactionError('Invalid or missing blockHash, got: ' + blockHash);
}
if (durableNonceParams) {
(0, utils_1.validateAddress)(durableNonceParams.walletNonceAddress, 'walletNonceAddress');
(0, utils_1.validateAddress)(durableNonceParams.authWalletAddress, 'authWalletAddress');
if (durableNonceParams.walletNonceAddress === durableNonceParams.authWalletAddress) {
throw new sdk_core_1.BuildTransactionError('Invalid params: walletNonceAddress cannot be equal to authWalletAddress');
}
this._nonceInfo = {
type: constants_1.InstructionBuilderTypes.NonceAdvance,
params: durableNonceParams,
};
}
this._recentBlockhash = blockHash;
return this;
}
/**
* Set the memo
*
* @param {string} memo
* @returns {TransactionBuilder} This transaction builder
*/
memo(memo) {
this.validateMemo(memo);
this._memo = memo;
return this;
}
fee(feeOptions) {
this._lamportsPerSignature = Number(feeOptions.amount);
return this;
}
setPriorityFee(feeOptions) {
this._priorityFee = Number(feeOptions.amount);
return this;
}
feePayer(feePayer) {
this._feePayer = feePayer;
return this;
}
/**
* Used to set the minimum rent exempt amount for an ATA
*
* @param tokenAccountRentExemptAmount minimum rent exempt amount in lamports
*/
associatedTokenAccountRent(tokenAccountRentExemptAmount) {
this.validateRentExemptAmount(tokenAccountRentExemptAmount);
this._tokenAccountRentExemptAmount = tokenAccountRentExemptAmount;
return this;
}
validateRentExemptAmount(tokenAccountRentExemptAmount) {
// _tokenAccountRentExemptAmount is allowed to be undefined or a valid amount if it's defined
if (tokenAccountRentExemptAmount && !(0, utils_1.isValidAmount)(tokenAccountRentExemptAmount)) {
throw new sdk_core_1.BuildTransactionError('Invalid tokenAccountRentExemptAmount, got: ' + tokenAccountRentExemptAmount);
}
}
// endregion
// region Validators
/** @inheritdoc */
validateAddress(address, addressFormat) {
if (!(0, utils_1.isValidAddress)(address.address)) {
throw new sdk_core_1.BuildTransactionError('Invalid address ' + address.address);
}
}
/** @inheritdoc */
validateKey(key) {
let keyPair;
try {
keyPair = new _1.KeyPair({ prv: key.key });
}
catch {
throw new sdk_core_1.BuildTransactionError('Invalid key');
}
if (!keyPair.getKeys().prv) {
throw new sdk_core_1.BuildTransactionError('Invalid key');
}
}
/** @inheritdoc */
validateRawTransaction(rawTransaction) {
(0, utils_1.validateRawTransaction)(rawTransaction);
}
/** @inheritdoc */
validateTransaction(transaction) {
this.validateSender();
this.validateNonce();
this.validateRentExemptAmount(this._tokenAccountRentExemptAmount);
}
/** @inheritdoc */
validateValue(value) {
if (value.isLessThan(0)) {
throw new sdk_core_1.BuildTransactionError('Value cannot be less than zero');
}
}
/** Validates the memo
*
* @param {string} memo - the memo as string
*/
validateMemo(memo) {
if (!memo) {
throw new sdk_core_1.BuildTransactionError('Invalid memo, got: ' + memo);
}
if (!(0, utils_1.isValidMemo)(memo)) {
throw new sdk_core_1.BuildTransactionError('Memo is too long');
}
}
/**
* Validates that the given key is not already in this._signers
*
* @param {BaseKey} key - The key to check
*/
checkDuplicatedSigner(key) {
this._signers.forEach((kp) => {
if (kp.getKeys().prv === key.key) {
throw new sdk_core_1.SigningError('Duplicated signer: ' + key.key);
}
});
}
/**
* Validates that the sender field is defined
*/
validateSender() {
if (this._sender === undefined) {
throw new sdk_core_1.BuildTransactionError('Invalid transaction: missing sender');
}
}
/**
* Validates that the nonce field is defined
*/
validateNonce() {
if (this._recentBlockhash === undefined) {
throw new sdk_core_1.BuildTransactionError('Invalid transaction: missing nonce blockhash');
}
}
}
exports.TransactionBuilder = TransactionBuilder;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNhY3Rpb25CdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi90cmFuc2FjdGlvbkJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBRUEsOENBVXlCO0FBQ3pCLCtDQUE0QztBQUM1Qyw2Q0FBc0Y7QUFDdEYsbUNBT2lCO0FBQ2pCLHdCQUE0QjtBQUM1QiwyQ0FBc0Q7QUFDdEQsbUVBQWdFO0FBQ2hFLG9EQUE0QjtBQUU1Qix5RUFBc0U7QUFFdEUsTUFBc0Isa0JBQW1CLFNBQVEsaUNBQXNCO0lBZXJFLFlBQVksV0FBaUM7UUFDM0MsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBZGIsZ0JBQVcsR0FBZ0IsRUFBRSxDQUFDO1FBTzVCLHNCQUFpQixHQUF3QixFQUFFLENBQUM7UUFDNUMsYUFBUSxHQUFjLEVBQUUsQ0FBQztRQU9qQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUkseUJBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBT0Q7Ozs7T0FJRztJQUNILFdBQVcsQ0FBQyxFQUFlO1FBQ3pCLElBQUksQ0FBQyxZQUFZLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUUzQixNQUFNLGdDQUFnQyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQ3JFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLG1DQUF1QixDQUFDLFFBQVEsQ0FDekQsQ0FBQztRQUNGLElBQUksTUFBTSxDQUFDO1FBQ1gsSUFBSSxnQ0FBZ0MsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDaEQsTUFBTSx3QkFBd0IsR0FBRyxnQ0FBZ0MsQ0FBQyxDQUFDLENBQWEsQ0FBQztZQUNqRixNQUFNLEdBQUcsd0JBQXdCLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQztRQUN2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LFNBQVMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sSUFBSSxnQ0FBcUIsQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxhQUFhO1FBQ25CLElBQUksSUFBSSxDQUFDLGdCQUFnQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3hDLE1BQU0sSUFBSSxnQ0FBcUIsQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7SUFDSCxDQUFDO0NBRUY7QUF0VkQsZ0RBc1ZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEJpZ051bWJlciBmcm9tICdiaWdudW1iZXIuanMnO1xuaW1wb3J0IHsgQmFzZUNvaW4gYXMgQ29pbkNvbmZpZyB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcbmltcG9ydCB7XG4gIEJhc2VBZGRyZXNzLFxuICBCYXNlS2V5LFxuICBCYXNlVHJhbnNhY3Rpb25CdWlsZGVyLFxuICBCdWlsZFRyYW5zYWN0aW9uRXJyb3IsXG4gIEZlZU9wdGlvbnMsXG4gIFB1YmxpY0tleSBhcyBCYXNlUHVibGljS2V5LFxuICBTaWduYXR1cmUsXG4gIFNpZ25pbmdFcnJvcixcbiAgVHJhbnNhY3Rpb25UeXBlLFxufSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb24gfSBmcm9tICcuL3RyYW5zYWN0aW9uJztcbmltcG9ydCB7IEJsb2NraGFzaCwgUHVibGljS2V5LCBUcmFuc2FjdGlvbiBhcyBTb2xUcmFuc2FjdGlvbiB9IGZyb20gJ0Bzb2xhbmEvd2ViMy5qcyc7XG5pbXBvcnQge1xuICBpc1ZhbGlkQWRkcmVzcyxcbiAgaXNWYWxpZEFtb3VudCxcbiAgaXNWYWxpZEJsb2NrSWQsXG4gIGlzVmFsaWRNZW1vLFxuICB2YWxpZGF0ZUFkZHJlc3MsXG4gIHZhbGlkYXRlUmF3VHJhbnNhY3Rpb24sXG59IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgS2V5UGFpciB9IGZyb20gJy4nO1xuaW1wb3J0IHsgSW5zdHJ1Y3Rpb25CdWlsZGVyVHlwZXMgfSBmcm9tICcuL2NvbnN0YW50cyc7XG5pbXBvcnQgeyBzb2xJbnN0cnVjdGlvbkZhY3RvcnkgfSBmcm9tICcuL3NvbEluc3RydWN0aW9uRmFjdG9yeSc7XG5pbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQgeyBEdXJhYmxlTm9uY2VQYXJhbXMsIEluc3RydWN0aW9uUGFyYW1zLCBNZW1vLCBOb25jZSwgU2V0UHJpb3JpdHlGZWUsIFRyYW5zZmVyIH0gZnJvbSAnLi9pZmFjZSc7XG5pbXBvcnQgeyBpbnN0cnVjdGlvblBhcmFtc0ZhY3RvcnkgfSBmcm9tICcuL2luc3RydWN0aW9uUGFyYW1zRmFjdG9yeSc7XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBUcmFuc2FjdGlvbkJ1aWxkZXIgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25CdWlsZGVyIHtcbiAgcHJvdGVjdGVkIF90cmFuc2FjdGlvbjogVHJhbnNhY3Rpb247XG4gIHByaXZhdGUgX3NpZ25hdHVyZXM6IFNpZ25hdHVyZVtdID0gW107XG4gIHByaXZhdGUgX2xhbXBvcnRzUGVyU2lnbmF0dXJlOiBudW1iZXI7XG4gIHByaXZhdGUgX3Rva2VuQWNjb3VudFJlbnRFeGVtcHRBbW91bnQ6IHN0cmluZztcblxuICBwcm90ZWN0ZWQgX3NlbmRlcjogc3RyaW5nO1xuICBwcm90ZWN0ZWQgX3JlY2VudEJsb2NraGFzaDogQmxvY2toYXNoO1xuICBwcm90ZWN0ZWQgX25vbmNlSW5mbzogTm9uY2U7XG4gIHByb3RlY3RlZCBfaW5zdHJ1Y3Rpb25zRGF0YTogSW5zdHJ1Y3Rpb25QYXJhbXNbXSA9IFtdO1xuICBwcm90ZWN0ZWQgX3NpZ25lcnM6IEtleVBhaXJbXSA9IFtdO1xuICBwcm90ZWN0ZWQgX21lbW8/OiBzdHJpbmc7XG4gIHByb3RlY3RlZCBfZmVlUGF5ZXI/OiBzdHJpbmc7XG4gIHByb3RlY3RlZCBfcHJpb3JpdHlGZWU6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihfY29pbkNvbmZpZzogUmVhZG9ubHk8Q29pbkNvbmZpZz4pIHtcbiAgICBzdXBlcihfY29pbkNvbmZpZyk7XG4gICAgdGhpcy50cmFuc2FjdGlvbiA9IG5ldyBUcmFuc2FjdGlvbihfY29pbkNvbmZpZyk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIHRyYW5zYWN0aW9uIHR5cGUuXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgZ2V0IHRyYW5zYWN0aW9uVHlwZSgpOiBUcmFuc2FjdGlvblR5cGU7XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIHRyYW5zYWN0aW9uIGJ1aWxkZXIgZmllbGRzIHVzaW5nIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uIGRhdGFcbiAgICpcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvbn0gdHggdGhlIHRyYW5zYWN0aW9uIGRhdGFcbiAgICovXG4gIGluaXRCdWlsZGVyKHR4OiBUcmFuc2FjdGlvbik6IHZvaWQge1xuICAgIHRoaXMuX3RyYW5zYWN0aW9uID0gdHg7XG4gICAgY29uc3QgdHhEYXRhID0gdHgudG9Kc29uKCk7XG5cbiAgICBjb25zdCBmaWx0ZXJlZFRyYW5zZmVySW5zdHJ1Y3Rpb25zRGF0YSA9IHR4RGF0YS5pbnN0cnVjdGlvbnNEYXRhLmZpbHRlcihcbiAgICAgIChkYXRhKSA9PiBkYXRhLnR5cGUgPT09IEluc3RydWN0aW9uQnVpbGRlclR5cGVzLlRyYW5zZmVyXG4gICAgKTtcbiAgICBsZXQgc2VuZGVyO1xuICAgIGlmIChmaWx0ZXJlZFRyYW5zZmVySW5zdHJ1Y3Rpb25zRGF0YS5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCB0cmFuc2Zlckluc3RydWN0aW9uc0RhdGEgPSBmaWx0ZXJlZFRyYW5zZmVySW5zdHJ1Y3Rpb25zRGF0YVswXSBhcyBUcmFuc2ZlcjtcbiAgICAgIHNlbmRlciA9IHRyYW5zZmVySW5zdHJ1Y3Rpb25zRGF0YS5wYXJhbXMuZnJvbUFkZHJlc3M7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNlbmRlciA9IHR4RGF0YS5mZWVQYXllcjtcbiAgICB9XG4gICAgdGhpcy5zZW5kZXIoc2VuZGVyKTtcbiAgICB0aGlzLmZlZVBheWVyKHR4RGF0YS5mZWVQYXllciBhcyBzdHJpbmcpO1xuICAgIHRoaXMubm9uY2UodHhEYXRhLm5vbmNlLCB0eERhdGEuZHVyYWJsZU5vbmNlKTtcbiAgICB0aGlzLl9pbnN0cnVjdGlvbnNEYXRhID0gaW5zdHJ1Y3Rpb25QYXJhbXNGYWN0b3J5KHR4LnR5cGUsIHR4LnNvbFRyYW5zYWN0aW9uLmluc3RydWN0aW9ucywgdGhpcy5fY29pbkNvbmZpZy5uYW1lKTtcbiAgICAvLyBQYXJzZSBwcmlvcml0eSBmZWUgaW5zdHJ1Y3Rpb24gZGF0YVxuICAgIGNvbnN0IGZpbHRlcmVkUHJpb3JpdHlGZWVJbnN0cnVjdGlvbnNEYXRhID0gdHhEYXRhLmluc3RydWN0aW9uc0RhdGEuZmlsdGVyKFxuICAgICAgKGRhdGEpID0+IGRhdGEudHlwZSA9PT0gSW5zdHJ1Y3Rpb25CdWlsZGVyVHlwZXMuU2V0UHJpb3JpdHlGZWVcbiAgICApO1xuXG4gICAgZm9yIChjb25zdCBpbnN0cnVjdGlvbiBvZiB0aGlzLl9pbnN0cnVjdGlvbnNEYXRhKSB7XG4gICAgICBpZiAoaW5zdHJ1Y3Rpb24udHlwZSA9PT0gSW5zdHJ1Y3Rpb25CdWlsZGVyVHlwZXMuTWVtbykge1xuICAgICAgICBjb25zdCBtZW1vSW5zdHJ1Y3Rpb246IE1lbW8gPSBpbnN0cnVjdGlvbjtcbiAgICAgICAgdGhpcy5tZW1vKG1lbW9JbnN0cnVjdGlvbi5wYXJhbXMubWVtbyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpbnN0cnVjdGlvbi50eXBlID09PSBJbnN0cnVjdGlvbkJ1aWxkZXJUeXBlcy5Ob25jZUFkdmFuY2UpIHtcbiAgICAgICAgY29uc3QgYWR2YW5jZU5vbmNlSW5zdHJ1Y3Rpb246IE5vbmNlID0gaW5zdHJ1Y3Rpb247XG4gICAgICAgIHRoaXMubm9uY2UodHhEYXRhLm5vbmNlLCBhZHZhbmNlTm9uY2VJbnN0cnVjdGlvbi5wYXJhbXMpO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBwcmlvIGZlZSBpbnN0cnVjdGlvbiBleGlzdHMsIHNldCB0aGUgcHJpb3JpdHkgZmVlIHZhcmlhYmxlXG4gICAgICBpZiAoaW5zdHJ1Y3Rpb24udHlwZSA9PT0gSW5zdHJ1Y3Rpb25CdWlsZGVyVHlwZXMuU2V0UHJpb3JpdHlGZWUpIHtcbiAgICAgICAgY29uc3QgcHJpb3JpdHlGZWVJbnN0cnVjdGlvbnNEYXRhID0gZmlsdGVyZWRQcmlvcml0eUZlZUluc3RydWN0aW9uc0RhdGFbMF0gYXMgU2V0UHJpb3JpdHlGZWU7XG4gICAgICAgIHRoaXMuc2V0UHJpb3JpdHlGZWUoeyBhbW91bnQ6IE51bWJlcihwcmlvcml0eUZlZUluc3RydWN0aW9uc0RhdGEucGFyYW1zLmZlZSkgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIHByb3RlY3RlZCBmcm9tSW1wbGVtZW50YXRpb24ocmF3VHJhbnNhY3Rpb246IHN0cmluZyk6IFRyYW5zYWN0aW9uIHtcbiAgICBjb25zdCB0eCA9IG5ldyBUcmFuc2FjdGlvbih0aGlzLl9jb2luQ29uZmlnKTtcbiAgICB0aGlzLnZhbGlkYXRlUmF3VHJhbnNhY3Rpb24ocmF3VHJhbnNhY3Rpb24pO1xuICAgIHR4LmZyb21SYXdUcmFuc2FjdGlvbihyYXdUcmFuc2FjdGlvbik7XG4gICAgdGhpcy5pbml0QnVpbGRlcih0eCk7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNhY3Rpb247XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGJ1aWxkSW1wbGVtZW50YXRpb24oKTogUHJvbWlzZTxUcmFuc2FjdGlvbj4ge1xuICAgIHRoaXMudHJhbnNhY3Rpb24uc29sVHJhbnNhY3Rpb24gPSB0aGlzLmJ1aWxkU29sVHJhbnNhY3Rpb24oKTtcbiAgICB0aGlzLnRyYW5zYWN0aW9uLnNldFRyYW5zYWN0aW9uVHlwZSh0aGlzLnRyYW5zYWN0aW9uVHlwZSk7XG4gICAgdGhpcy50cmFuc2FjdGlvbi5sb2FkSW5wdXRzQW5kT3V0cHV0cygpO1xuICAgIHRoaXMuX3RyYW5zYWN0aW9uLnRva2VuQWNjb3VudFJlbnRFeGVtcHRBbW91bnQgPSB0aGlzLl90b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50O1xuICAgIHJldHVybiB0aGlzLnRyYW5zYWN0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyB0aGUgc29sYW5hIHRyYW5zYWN0aW9uLlxuICAgKi9cbiAgcHJvdGVjdGVkIGJ1aWxkU29sVHJhbnNhY3Rpb24oKTogU29sVHJhbnNhY3Rpb24ge1xuICAgIGFzc2VydCh0aGlzLl9zZW5kZXIsIG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoJ3NlbmRlciBpcyByZXF1aXJlZCBiZWZvcmUgYnVpbGRpbmcnKSk7XG4gICAgYXNzZXJ0KHRoaXMuX3JlY2VudEJsb2NraGFzaCwgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcigncmVjZW50IGJsb2NraGFzaCBpcyByZXF1aXJlZCBiZWZvcmUgYnVpbGRpbmcnKSk7XG5cbiAgICBjb25zdCB0eCA9IG5ldyBTb2xUcmFuc2FjdGlvbigpO1xuICAgIGlmICh0aGlzLl90cmFuc2FjdGlvbj8uc29sVHJhbnNhY3Rpb24/LnNpZ25hdHVyZXMpIHtcbiAgICAgIHR4LnNpZ25hdHVyZXMgPSB0aGlzLl90cmFuc2FjdGlvbj8uc29sVHJhbnNhY3Rpb24/LnNpZ25hdHVyZXM7XG4gICAgfVxuXG4gICAgdHguZmVlUGF5ZXIgPSB0aGlzLl9mZWVQYXllciA/IG5ldyBQdWJsaWNLZXkodGhpcy5fZmVlUGF5ZXIpIDogbmV3IFB1YmxpY0tleSh0aGlzLl9zZW5kZXIpO1xuXG4gICAgaWYgKHRoaXMuX25vbmNlSW5mbykge1xuICAgICAgdHgubm9uY2VJbmZvID0ge1xuICAgICAgICBub25jZTogdGhpcy5fcmVjZW50QmxvY2toYXNoLFxuICAgICAgICBub25jZUluc3RydWN0aW9uOiBzb2xJbnN0cnVjdGlvbkZhY3RvcnkodGhpcy5fbm9uY2VJbmZvKVswXSxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHR4LnJlY2VudEJsb2NraGFzaCA9IHRoaXMuX3JlY2VudEJsb2NraGFzaDtcbiAgICB9XG4gICAgZm9yIChjb25zdCBpbnN0cnVjdGlvbiBvZiB0aGlzLl9pbnN0cnVjdGlvbnNEYXRhKSB7XG4gICAgICB0eC5hZGQoLi4uc29sSW5zdHJ1Y3Rpb25GYWN0b3J5KGluc3RydWN0aW9uKSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX21lbW8pIHtcbiAgICAgIGNvbnN0IG1lbW9EYXRhOiBNZW1vID0ge1xuICAgICAgICB0eXBlOiBJbnN0cnVjdGlvbkJ1aWxkZXJUeXBlcy5NZW1vLFxuICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICBtZW1vOiB0aGlzLl9tZW1vLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICAgIHRoaXMuX2luc3RydWN0aW9uc0RhdGEucHVzaChtZW1vRGF0YSk7XG4gICAgICB0eC5hZGQoLi4uc29sSW5zdHJ1Y3Rpb25GYWN0b3J5KG1lbW9EYXRhKSk7XG4gICAgfVxuXG4gICAgdGhpcy5fdHJhbnNhY3Rpb24ubGFtcG9ydHNQZXJTaWduYXR1cmUgPSB0aGlzLl9sYW1wb3J0c1BlclNpZ25hdHVyZTtcblxuICAgIGZvciAoY29uc3Qgc2lnbmVyIG9mIHRoaXMuX3NpZ25lcnMpIHtcbiAgICAgIGNvbnN0IHB1YmxpY0tleSA9IG5ldyBQdWJsaWNLZXkoc2lnbmVyLmdldEtleXMoKS5wdWIpO1xuICAgICAgY29uc3Qgc2VjcmV0S2V5ID0gc2lnbmVyLmdldEtleXModHJ1ZSkucHJ2O1xuICAgICAgYXNzZXJ0KHNlY3JldEtleSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpO1xuICAgICAgdHgucGFydGlhbFNpZ24oeyBwdWJsaWNLZXksIHNlY3JldEtleSB9KTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IHNpZ25hdHVyZSBvZiB0aGlzLl9zaWduYXR1cmVzKSB7XG4gICAgICBjb25zdCBzb2xQdWJsaWNLZXkgPSBuZXcgUHVibGljS2V5KHNpZ25hdHVyZS5wdWJsaWNLZXkucHViKTtcbiAgICAgIHR4LmFkZFNpZ25hdHVyZShzb2xQdWJsaWNLZXksIHNpZ25hdHVyZS5zaWduYXR1cmUpO1xuICAgIH1cblxuICAgIHJldHVybiB0eDtcbiAgfVxuXG4gIC8vIHJlZ2lvbiBHZXR0ZXJzIGFuZCBTZXR0ZXJzXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBwcm90ZWN0ZWQgZ2V0IHRyYW5zYWN0aW9uKCk6IFRyYW5zYWN0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5fdHJhbnNhY3Rpb247XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgcHJvdGVjdGVkIHNldCB0cmFuc2FjdGlvbih0cmFuc2FjdGlvbjogVHJhbnNhY3Rpb24pIHtcbiAgICB0aGlzLl90cmFuc2FjdGlvbiA9IHRyYW5zYWN0aW9uO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIHByb3RlY3RlZCBzaWduSW1wbGVtZW50YXRpb24oa2V5OiBCYXNlS2V5KTogVHJhbnNhY3Rpb24ge1xuICAgIHRoaXMudmFsaWRhdGVLZXkoa2V5KTtcbiAgICB0aGlzLmNoZWNrRHVwbGljYXRlZFNpZ25lcihrZXkpO1xuICAgIGNvbnN0IHBydiA9IGtleS5rZXk7XG4gICAgY29uc3Qgc2lnbmVyID0gbmV3IEtleVBhaXIoeyBwcnY6IHBydiB9KTtcbiAgICB0aGlzLl9zaWduZXJzLnB1c2goc2lnbmVyKTtcblxuICAgIHJldHVybiB0aGlzLl90cmFuc2FjdGlvbjtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBhZGRTaWduYXR1cmUocHVibGljS2V5OiBCYXNlUHVibGljS2V5LCBzaWduYXR1cmU6IEJ1ZmZlcik6IHZvaWQge1xuICAgIHRoaXMuX3NpZ25hdHVyZXMucHVzaCh7IHB1YmxpY0tleSwgc2lnbmF0dXJlIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIHNlbmRlciBvZiB0aGlzIHRyYW5zYWN0aW9uLlxuICAgKiBUaGlzIGFjY291bnQgd2lsbCBiZSByZXNwb25zaWJsZSBmb3IgcGF5aW5nIHRyYW5zYWN0aW9uIGZlZXMuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzZW5kZXJBZGRyZXNzIHRoZSBhY2NvdW50IHRoYXQgaXMgc2VuZGluZyB0aGlzIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlclxuICAgKi9cbiAgc2VuZGVyKHNlbmRlckFkZHJlc3M6IHN0cmluZyk6IHRoaXMge1xuICAgIHZhbGlkYXRlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCAnc2VuZGVyJyk7XG4gICAgdGhpcy5fc2VuZGVyID0gc2VuZGVyQWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdGhlIHRyYW5zYWN0aW9uIG5vbmNlXG4gICAqIFJlcXVpcmVzIGJvdGggb3B0aW9uYWwgcGFyYW1zIGluIG9yZGVyIHRvIHVzZSB0aGUgZHVyYWJsZSBub25jZVxuICAgKlxuICAgKiBAcGFyYW0ge0Jsb2NraGFzaH0gYmxvY2tIYXNoIFRoZSBsYXRlc3QgYmxvY2tIYXNoXG4gICAqIEBwYXJhbSB7RHVyYWJsZU5vbmNlUGFyYW1zfSBbZHVyYWJsZU5vbmNlUGFyYW1zXSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd2FsbGV0Tm9uY2VBZGRyZXNzIGFuZCB0aGUgYXV0aFdhbGxldEFkZHJlc3MgKHJlcXVpcmVkIGZvciBkdXJhYmxlIG5vbmNlKVxuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25CdWlsZGVyfSBUaGlzIHRyYW5zYWN0aW9uIGJ1aWxkZXJcbiAgICovXG4gIG5vbmNlKGJsb2NrSGFzaDogQmxvY2toYXNoLCBkdXJhYmxlTm9uY2VQYXJhbXM/OiBEdXJhYmxlTm9uY2VQYXJhbXMpOiB0aGlzIHtcbiAgICBpZiAoIWJsb2NrSGFzaCB8fCAhaXNWYWxpZEJsb2NrSWQoYmxvY2tIYXNoKSkge1xuICAgICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcignSW52YWxpZCBvciBtaXNzaW5nIGJsb2NrSGFzaCwgZ290OiAnICsgYmxvY2tIYXNoKTtcbiAgICB9XG4gICAgaWYgKGR1cmFibGVOb25jZVBhcmFtcykge1xuICAgICAgdmFsaWRhdGVBZGRyZXNzKGR1cmFibGVOb25jZVBhcmFtcy53YWxsZXROb25jZUFkZHJlc3MsICd3YWxsZXROb25jZUFkZHJlc3MnKTtcbiAgICAgIHZhbGlkYXRlQWRkcmVzcyhkdXJhYmxlTm9uY2VQYXJhbXMuYXV0aFdhbGxldEFkZHJlc3MsICdhdXRoV2FsbGV0QWRkcmVzcycpO1xuICAgICAgaWYgKGR1cmFibGVOb25jZVBhcmFtcy53YWxsZXROb25jZUFkZHJlc3MgPT09IGR1cmFibGVOb25jZVBhcmFtcy5hdXRoV2FsbGV0QWRkcmVzcykge1xuICAgICAgICB0aHJvdyBuZXcgQnVpbGRUcmFuc2FjdGlvbkVycm9yKCdJbnZhbGlkIHBhcmFtczogd2FsbGV0Tm9uY2VBZGRyZXNzIGNhbm5vdCBiZSBlcXVhbCB0byBhdXRoV2FsbGV0QWRkcmVzcycpO1xuICAgICAgfVxuICAgICAgdGhpcy5fbm9uY2VJbmZvID0ge1xuICAgICAgICB0eXBlOiBJbnN0cnVjdGlvbkJ1aWxkZXJUeXBlcy5Ob25jZUFkdmFuY2UsXG4gICAgICAgIHBhcmFtczogZHVyYWJsZU5vbmNlUGFyYW1zLFxuICAgICAgfTtcbiAgICB9XG4gICAgdGhpcy5fcmVjZW50QmxvY2toYXNoID0gYmxvY2tIYXNoO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqICBTZXQgdGhlIG1lbW9cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lbW9cbiAgICogQHJldHVybnMge1RyYW5zYWN0aW9uQnVpbGRlcn0gVGhpcyB0cmFuc2FjdGlvbiBidWlsZGVyXG4gICAqL1xuICBtZW1vKG1lbW86IHN0cmluZyk6IHRoaXMge1xuICAgIHRoaXMudmFsaWRhdGVNZW1vKG1lbW8pO1xuICAgIHRoaXMuX21lbW8gPSBtZW1vO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZmVlKGZlZU9wdGlvbnM6IEZlZU9wdGlvbnMpOiB0aGlzIHtcbiAgICB0aGlzLl9sYW1wb3J0c1BlclNpZ25hdHVyZSA9IE51bWJlcihmZWVPcHRpb25zLmFtb3VudCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBwdWJsaWMgc2V0UHJpb3JpdHlGZWUoZmVlT3B0aW9uczogRmVlT3B0aW9ucyk6IHRoaXMge1xuICAgIHRoaXMuX3ByaW9yaXR5RmVlID0gTnVtYmVyKGZlZU9wdGlvbnMuYW1vdW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGZlZVBheWVyKGZlZVBheWVyOiBzdHJpbmcpOiB0aGlzIHtcbiAgICB0aGlzLl9mZWVQYXllciA9IGZlZVBheWVyO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFVzZWQgdG8gc2V0IHRoZSBtaW5pbXVtIHJlbnQgZXhlbXB0IGFtb3VudCBmb3IgYW4gQVRBXG4gICAqXG4gICAqIEBwYXJhbSB0b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50IG1pbmltdW0gcmVudCBleGVtcHQgYW1vdW50IGluIGxhbXBvcnRzXG4gICAqL1xuICBhc3NvY2lhdGVkVG9rZW5BY2NvdW50UmVudCh0b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50OiBzdHJpbmcpOiB0aGlzIHtcbiAgICB0aGlzLnZhbGlkYXRlUmVudEV4ZW1wdEFtb3VudCh0b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50KTtcbiAgICB0aGlzLl90b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50ID0gdG9rZW5BY2NvdW50UmVudEV4ZW1wdEFtb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVSZW50RXhlbXB0QW1vdW50KHRva2VuQWNjb3VudFJlbnRFeGVtcHRBbW91bnQ6IHN0cmluZykge1xuICAgIC8vIF90b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50IGlzIGFsbG93ZWQgdG8gYmUgdW5kZWZpbmVkIG9yIGEgdmFsaWQgYW1vdW50IGlmIGl0J3MgZGVmaW5lZFxuICAgIGlmICh0b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50ICYmICFpc1ZhbGlkQW1vdW50KHRva2VuQWNjb3VudFJlbnRFeGVtcHRBbW91bnQpKSB7XG4gICAgICB0aHJvdyBuZXcgQnVpbGRUcmFuc2FjdGlvbkVycm9yKCdJbnZhbGlkIHRva2VuQWNjb3VudFJlbnRFeGVtcHRBbW91bnQsIGdvdDogJyArIHRva2VuQWNjb3VudFJlbnRFeGVtcHRBbW91bnQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGVuZHJlZ2lvblxuXG4gIC8vIHJlZ2lvbiBWYWxpZGF0b3JzXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICB2YWxpZGF0ZUFkZHJlc3MoYWRkcmVzczogQmFzZUFkZHJlc3MsIGFkZHJlc3NGb3JtYXQ/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIWlzVmFsaWRBZGRyZXNzKGFkZHJlc3MuYWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoJ0ludmFsaWQgYWRkcmVzcyAnICsgYWRkcmVzcy5hZGRyZXNzKTtcbiAgICB9XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgdmFsaWRhdGVLZXkoa2V5OiBCYXNlS2V5KTogdm9pZCB7XG4gICAgbGV0IGtleVBhaXI6IEtleVBhaXI7XG4gICAgdHJ5IHtcbiAgICAgIGtleVBhaXIgPSBuZXcgS2V5UGFpcih7IHBydjoga2V5LmtleSB9KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRocm93IG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoJ0ludmFsaWQga2V5Jyk7XG4gICAgfVxuXG4gICAgaWYgKCFrZXlQYWlyLmdldEtleXMoKS5wcnYpIHtcbiAgICAgIHRocm93IG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoJ0ludmFsaWQga2V5Jyk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIHZhbGlkYXRlUmF3VHJhbnNhY3Rpb24ocmF3VHJhbnNhY3Rpb246IHN0cmluZyk6IHZvaWQge1xuICAgIHZhbGlkYXRlUmF3VHJhbnNhY3Rpb24ocmF3VHJhbnNhY3Rpb24pO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIHZhbGlkYXRlVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24/OiBUcmFuc2FjdGlvbik6IHZvaWQge1xuICAgIHRoaXMudmFsaWRhdGVTZW5kZXIoKTtcbiAgICB0aGlzLnZhbGlkYXRlTm9uY2UoKTtcbiAgICB0aGlzLnZhbGlkYXRlUmVudEV4ZW1wdEFtb3VudCh0aGlzLl90b2tlbkFjY291bnRSZW50RXhlbXB0QW1vdW50KTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICB2YWxpZGF0ZVZhbHVlKHZhbHVlOiBCaWdOdW1iZXIpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUuaXNMZXNzVGhhbigwKSkge1xuICAgICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcignVmFsdWUgY2Fubm90IGJlIGxlc3MgdGhhbiB6ZXJvJyk7XG4gICAgfVxuICB9XG4gIC8qKiBWYWxpZGF0ZXMgdGhlIG1lbW9cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lbW8gLSB0aGUgbWVtbyBhcyBzdHJpbmdcbiAgICovXG4gIHZhbGlkYXRlTWVtbyhtZW1vOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIW1lbW8pIHtcbiAgICAgIHRocm93IG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoJ0ludmFsaWQgbWVtbywgZ290OiAnICsgbWVtbyk7XG4gICAgfVxuICAgIGlmICghaXNWYWxpZE1lbW8obWVtbykpIHtcbiAgICAgIHRocm93IG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoJ01lbW8gaXMgdG9vIGxvbmcnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoYXQgdGhlIGdpdmVuIGtleSBpcyBub3QgYWxyZWFkeSBpbiB0aGlzLl9zaWduZXJzXG4gICAqXG4gICAqIEBwYXJhbSB7QmFzZUtleX0ga2V5IC0gVGhlIGtleSB0byBjaGVja1xuICAgKi9cbiAgcHJpdmF0ZSBjaGVja0R1cGxpY2F0ZWRTaWduZXIoa2V5OiBCYXNlS2V5KSB7XG4gICAgdGhpcy5fc2lnbmVycy5mb3JFYWNoKChrcCkgPT4ge1xuICAgICAgaWYgKGtwLmdldEtleXMoKS5wcnYgPT09IGtleS5rZXkpIHtcbiAgICAgICAgdGhyb3cgbmV3IFNpZ25pbmdFcnJvcignRHVwbGljYXRlZCBzaWduZXI6ICcgKyBrZXkua2V5KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgdGhhdCB0aGUgc2VuZGVyIGZpZWxkIGlzIGRlZmluZWRcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVTZW5kZXIoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX3NlbmRlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgQnVpbGRUcmFuc2FjdGlvbkVycm9yKCdJbnZhbGlkIHRyYW5zYWN0aW9uOiBtaXNzaW5nIHNlbmRlcicpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgdGhhdCB0aGUgbm9uY2UgZmllbGQgaXMgZGVmaW5lZFxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZU5vbmNlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLl9yZWNlbnRCbG9ja2hhc2ggPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcignSW52YWxpZCB0cmFuc2FjdGlvbjogbWlzc2luZyBub25jZSBibG9ja2hhc2gnKTtcbiAgICB9XG4gIH1cbiAgLy8gZW5kcmVnaW9uXG59XG4iXX0=Выполнить команду
Для локальной разработки. Не используйте в интернете!