PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-algo/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 = exports.BETANET_GENESIS_HASH = exports.BETANET_GENESIS_ID = exports.TESTNET_GENESIS_HASH = exports.TESTNET_GENESIS_ID = exports.MAINNET_GENESIS_HASH = exports.MAINNET_GENESIS_ID = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const algosdk_1 = __importDefault(require("algosdk"));
const transaction_1 = require("./transaction");
const errors_1 = require("./errors");
const keyPair_1 = require("./keyPair");
const txnSchema_1 = require("./txnSchema");
const utils_1 = __importDefault(require("./utils"));
const sdk_core_1 = require("@bitgo/sdk-core");
const _1 = require(".");
const MIN_FEE = 1000; // in microalgos
exports.MAINNET_GENESIS_ID = 'mainnet-v1.0';
exports.MAINNET_GENESIS_HASH = 'wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=';
exports.TESTNET_GENESIS_ID = 'testnet-v1.0';
exports.TESTNET_GENESIS_HASH = 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=';
exports.BETANET_GENESIS_ID = 'betanet-v1.0';
exports.BETANET_GENESIS_HASH = 'mFgazF+2uRS1tMiL9dsj01hJGySEmPN28B/TjjvpVW0=';
class TransactionBuilder extends sdk_core_1.BaseTransactionBuilder {
constructor(coinConfig) {
super(coinConfig);
this._transaction = new transaction_1.Transaction(coinConfig);
this._keyPairs = [];
}
/**
* Sets the fee.
*
* The minimum fee is 1000 microalgos.
*
* @param {BaseFee} feeObj The amount to pay to the fee sink denoted in microalgos
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
fee(feeObj) {
this._isFlatFee = true;
const fee = new bignumber_js_1.default(feeObj.fee).toNumber();
if (this._isFlatFee && fee < MIN_FEE) {
throw new errors_1.InsufficientFeeError(fee, MIN_FEE);
}
this._fee = fee;
return this;
}
/**
* Sets whether the fee is a flat fee.
*
* A flat fee is the fee for the entire transaction whereas a normal fee
* is a fee for every byte in the transaction.
*
* @param {boolean} isFlatFee Whether the fee should be specified as a flat fee.
* @returns {TransactionBuilder} This transaction builder.
*/
isFlatFee(isFlatFee) {
this._isFlatFee = isFlatFee;
return this;
}
/**
* Sets the transaction sender.
*
* @param {BaseAddress} sender The sender account
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
sender(sender) {
this.validateAddress(sender);
this._sender = sender.address;
this._transaction.sender(sender.address);
return this;
}
/**
* Sets the genesis id.
*
* @param {string} genesisId The genesis id.
* @example "mainnet-v1.0"
*
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
genesisId(genesisId) {
this._genesisId = genesisId;
return this;
}
/**
* Sets the genesis hash.
*
* The genesis hash must be base64 encoded.
*
* @param {string} genesisHash The genesis hash.
* @example "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="
*
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
genesisHash(genesisHash) {
this._genesisHash = genesisHash;
return this;
}
/**
* Sets the genesis id and hash to mainnet.
*
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/algorand-networks/mainnet/#genesis-id
* @see https://developer.algorand.org/docs/reference/algorand-networks/mainnet/#genesis-hash
*/
mainnet() {
this.genesisId(exports.MAINNET_GENESIS_ID);
this.genesisHash(exports.MAINNET_GENESIS_HASH);
return this;
}
/**
* Sets the genesis id and hash to testnet.
*
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/algorand-networks/testnet/#genesis-id
* @see https://developer.algorand.org/docs/reference/algorand-networks/testnet/#genesis-hash
*/
testnet() {
this.genesisId(exports.TESTNET_GENESIS_ID);
this.genesisHash(exports.TESTNET_GENESIS_HASH);
return this;
}
/**
* Sets the genesis id and hash to betanet.
*
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/algorand-networks/betanet/#genesis-id
* @see https://developer.algorand.org/docs/reference/algorand-networks/betanet/#genesis-hash
*/
betanet() {
this.genesisId(exports.BETANET_GENESIS_ID);
this.genesisHash(exports.BETANET_GENESIS_HASH);
return this;
}
/**
* Sets the first round.
*
* @param {number} round The first protocol round on which this txn is valid.
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
firstRound(round) {
this.validateValue(new bignumber_js_1.default(round));
this._firstRound = round;
return this;
}
/**
* Sets the last round.
*
* @param {number} round The first protocol round on which this txn is valid.
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
lastRound(round) {
this.validateValue(new bignumber_js_1.default(round));
this._lastRound = round;
return this;
}
/**
* Sets the lease on the transaction.
*
* A lease is a mutex on the transaction that prevents any other transaction
* from being sent with the same lease until the prior transaction's last
* round has passed.
*
* @param {Uint8Array} lease The lease to put the transaction.
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
lease(lease) {
this._lease = lease;
return this;
}
/**
* Sets the note for the transaction.
*
* @param {Uint8Array} note Arbitrary data for sender to store.
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
note(note) {
this._note = note;
return this;
}
/**
* Sets the authorized address.
*
* The authorized asset will be used to authorize all future transactions.
*
* @param {BaseAddress} authorizer The address to delegate authorization authority to.
* @returns {TransactionBuilder} This transaction builder.
*
* @see https://developer.algorand.org/docs/reference/transactions/
*/
reKeyTo(authorizer) {
this.validateAddress(authorizer);
this._reKeyTo = authorizer.address;
return this;
}
/** @inheritdoc */
validateAddress({ address }) {
if (!algosdk_1.default.isValidAddress(address)) {
throw new errors_1.AddressValidationError(address);
}
}
/** @inheritdoc */
async buildImplementation() {
this.transaction.setAlgoTransaction(this.buildAlgoTxn());
this.transaction.setTransactionType(this.transactionType);
this.transaction.sign(this._keyPairs);
this._transaction.loadInputsAndOutputs();
return this._transaction;
}
/** @inheritdoc */
fromImplementation(rawTransaction) {
const decodedTxn = utils_1.default.decodeAlgoTxn(rawTransaction);
const algosdkTxn = decodedTxn.txn;
if (decodedTxn.signed) {
this._transaction.signedTransaction = decodedTxn.rawTransaction;
if (decodedTxn.signers) {
this.setSigners(decodedTxn.signers);
}
if (decodedTxn.signedBy) {
this._transaction.signedBy = decodedTxn.signedBy;
}
}
this.sender({ address: algosdk_1.default.encodeAddress(algosdkTxn.from.publicKey) });
this._isFlatFee = true;
this._fee = algosdkTxn.fee;
this._genesisHash = algosdkTxn.genesisHash.toString('base64');
this._genesisId = algosdkTxn.genesisID;
this._firstRound = algosdkTxn.firstRound;
this._lastRound = algosdkTxn.lastRound;
this._lease = algosdkTxn.lease;
this._note = algosdkTxn.note;
this._reKeyTo = algosdkTxn.reKeyTo ? algosdk_1.default.encodeAddress(algosdkTxn.reKeyTo.publicKey) : undefined;
this._transaction.setAlgoTransaction(algosdkTxn);
return this._transaction;
}
/** @inheritdoc */
signImplementation({ key }) {
try {
const buffKey = utils_1.default.decodeSeed(key);
const keypair = new keyPair_1.KeyPair({ prv: Buffer.from(buffKey.seed).toString('hex') });
this._keyPairs.push(keypair);
}
catch (e) {
if (_1.algoUtils.isValidPrivateKey(key)) {
const keypair = new keyPair_1.KeyPair({ prv: key });
this._keyPairs.push(keypair);
}
else {
throw e;
}
}
return this._transaction;
}
numberOfSigners(num) {
this._transaction.setNumberOfRequiredSigners(num);
return this;
}
setSigners(addrs) {
const signers = addrs instanceof Array ? addrs : [addrs];
signers.forEach((address) => this.validateAddress({ address: address }));
this._transaction.signers = signers;
return this;
}
/**
* Sets the number of signers required to sign the transaction.
*
* The number of signers cannot be set to a negative value.
*
* @param {number} n The number of signers.
* @returns {TransactionBuilder} This transaction builder.
*/
numberOfRequiredSigners(n) {
if (n < 0) {
throw new sdk_core_1.BuildTransactionError(`Number of signers: '${n}' cannot be negative`);
}
this._transaction.setNumberOfRequiredSigners(n);
return this;
}
/**
* @inheritdoc
* @see https://developer.algorand.org/docs/features/accounts/#transformation-private-key-to-base64-private-key
*/
validateKey({ key }) {
let isValidPrivateKeyFromBytes;
const isValidPrivateKeyFromHex = (0, sdk_core_1.isValidEd25519Seed)(key);
const isValidPrivateKeyFromBase64 = (0, sdk_core_1.isValidEd25519Seed)(Buffer.from(key, 'base64').toString('hex'));
const isValidRootPrvKey = (0, sdk_core_1.isValidEd25519SecretKey)(key);
try {
const decodedSeed = utils_1.default.decodeSeed(key);
isValidPrivateKeyFromBytes = (0, sdk_core_1.isValidEd25519Seed)(Buffer.from(decodedSeed.seed).toString('hex'));
}
catch (err) {
isValidPrivateKeyFromBytes = false;
}
if (!isValidPrivateKeyFromBytes &&
!isValidPrivateKeyFromHex &&
!isValidPrivateKeyFromBase64 &&
!isValidRootPrvKey) {
throw new sdk_core_1.BuildTransactionError(`Key validation failed`);
}
}
/** @inheritdoc */
validateRawTransaction(rawTransaction) {
const decodedTxn = utils_1.default.decodeAlgoTxn(rawTransaction);
const algoTxn = decodedTxn.txn;
const validationResult = txnSchema_1.BaseTransactionSchema.validate({
fee: algoTxn?.fee,
firstRound: algoTxn?.firstRound,
genesisHash: algoTxn?.genesisHash.toString('base64'),
lastRound: algoTxn?.lastRound,
sender: algoTxn ? algosdk_1.default.encodeAddress(algoTxn.from.publicKey) : undefined,
genesisId: algoTxn?.genesisID,
lease: algoTxn?.lease,
note: algoTxn?.note,
reKeyTo: algoTxn?.reKeyTo ? algosdk_1.default.encodeAddress(algoTxn.reKeyTo.publicKey) : undefined,
});
if (validationResult.error) {
throw new sdk_core_1.InvalidTransactionError(`Transaction validation failed: ${validationResult.error.message}`);
}
}
/** @inheritdoc */
validateTransaction(_) {
this.validateBaseFields(this._fee, this._firstRound, this._genesisHash, this._lastRound, this._sender, this._genesisId, this._lease, this._note, this._reKeyTo);
}
validateBaseFields(fee, firstRound, genesisHash, lastRound, sender, genesisId, lease, note, reKeyTo) {
const validationResult = txnSchema_1.BaseTransactionSchema.validate({
fee,
firstRound,
genesisHash,
lastRound,
sender,
genesisId,
lease,
note,
reKeyTo,
});
if (validationResult.error) {
throw new sdk_core_1.InvalidTransactionError(`Transaction validation failed: ${validationResult.error.message}`);
}
}
/** @inheritdoc */
validateValue(value) {
if (value.isLessThan(0)) {
throw new sdk_core_1.BuildTransactionError('Value cannot be less than zero');
}
}
/** @inheritdoc */
get transaction() {
return this._transaction;
}
/** @inheritdoc */
set transaction(transaction) {
this._transaction = transaction;
}
/**
* Convenience method to retrieve the algosdk suggested parameters.
*
* @returns {algosdk.SuggestedParams} The algosdk suggested parameters.
*/
get suggestedParams() {
return {
flatFee: this._isFlatFee,
fee: this._fee,
firstRound: this._firstRound,
lastRound: this._lastRound,
genesisID: this._genesisId,
genesisHash: this._genesisHash,
};
}
}
exports.TransactionBuilder = TransactionBuilder;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNhY3Rpb25CdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi90cmFuc2FjdGlvbkJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EsZ0VBQXFDO0FBQ3JDLHNEQUE4QjtBQUU5QiwrQ0FBNEM7QUFDNUMscUNBQXdFO0FBQ3hFLHVDQUFvQztBQUNwQywyQ0FBb0Q7QUFDcEQsb0RBQTRCO0FBQzVCLDhDQVV5QjtBQUN6Qix3QkFBOEI7QUFFOUIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLENBQUMsZ0JBQWdCO0FBRXpCLFFBQUEsa0JBQWtCLEdBQUcsY0FBYyxDQUFDO0FBQ3BDLFFBQUEsb0JBQW9CLEdBQUcsOENBQThDLENBQUM7QUFDdEUsUUFBQSxrQkFBa0IsR0FBRyxjQUFjLENBQUM7QUFDcEMsUUFBQSxvQkFBb0IsR0FBRyw4Q0FBOEMsQ0FBQztBQUN0RSxRQUFBLGtCQUFrQixHQUFHLGNBQWMsQ0FBQztBQUNwQyxRQUFBLG9CQUFvQixHQUFHLDhDQUE4QyxDQUFDO0FBRW5GLE1BQXNCLGtCQUFtQixTQUFRLGlDQUFzQjtJQW1CckUsWUFBWSxVQUFnQztRQUMxQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFbEIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLHlCQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNILEdBQUcsQ0FBQyxNQUFlO1FBQ2pCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1FBQ3ZCLE1BQU0sR0FBRyxHQUFHLElBQUksc0JBQVMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDakQsSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLEdBQUcsR0FBRyxPQUFPLEVBQUUsQ0FBQztZQUNy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RUFBRSxJQUFJLENBQUMsSUFBSTtZQUNkLFVBQVUsRUFBRSxJQUFJLENBQUMsV0FBVztZQUM1QixTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVU7WUFDMUIsU0FBUyxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQzFCLFdBQVcsRUFBRSxJQUFJLENBQUMsWUFBWTtTQUMvQixDQUFDO0lBQ0osQ0FBQztDQUNGO0FBbmRELGdEQW1kQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJhc2VDb2luIGFzIENvaW5Db25maWcgfSBmcm9tICdAYml0Z28vc3RhdGljcyc7XG5pbXBvcnQgQmlnTnVtYmVyIGZyb20gJ2JpZ251bWJlci5qcyc7XG5pbXBvcnQgYWxnb3NkayBmcm9tICdhbGdvc2RrJztcblxuaW1wb3J0IHsgVHJhbnNhY3Rpb24gfSBmcm9tICcuL3RyYW5zYWN0aW9uJztcbmltcG9ydCB7IEFkZHJlc3NWYWxpZGF0aW9uRXJyb3IsIEluc3VmZmljaWVudEZlZUVycm9yIH0gZnJvbSAnLi9lcnJvcnMnO1xuaW1wb3J0IHsgS2V5UGFpciB9IGZyb20gJy4va2V5UGFpcic7XG5pbXBvcnQgeyBCYXNlVHJhbnNhY3Rpb25TY2hlbWEgfSBmcm9tICcuL3R4blNjaGVtYSc7XG5pbXBvcnQgVXRpbHMgZnJvbSAnLi91dGlscyc7XG5pbXBvcnQge1xuICBCYXNlQWRkcmVzcyxcbiAgQmFzZUZlZSxcbiAgQmFzZUtleSxcbiAgQmFzZVRyYW5zYWN0aW9uQnVpbGRlcixcbiAgQnVpbGRUcmFuc2FjdGlvbkVycm9yLFxuICBJbnZhbGlkVHJhbnNhY3Rpb25FcnJvcixcbiAgaXNWYWxpZEVkMjU1MTlTZWNyZXRLZXksXG4gIGlzVmFsaWRFZDI1NTE5U2VlZCxcbiAgVHJhbnNhY3Rpb25UeXBlLFxufSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgYWxnb1V0aWxzIH0gZnJvbSAnLic7XG5cbmNvbnN0IE1JTl9GRUUgPSAxMDAwOyAvLyBpbiBtaWNyb2FsZ29zXG5cbmV4cG9ydCBjb25zdCBNQUlOTkVUX0dFTkVTSVNfSUQgPSAnbWFpbm5ldC12MS4wJztcbmV4cG9ydCBjb25zdCBNQUlOTkVUX0dFTkVTSVNfSEFTSCA9ICd3R0hFMlB3ZHZkN1MxMkJMNUZhT1AyMEVHWWVzTjcza3RpQzFxemtraXQ4PSc7XG5leHBvcnQgY29uc3QgVEVTVE5FVF9HRU5FU0lTX0lEID0gJ3Rlc3RuZXQtdjEuMCc7XG5leHBvcnQgY29uc3QgVEVTVE5FVF9HRU5FU0lTX0hBU0ggPSAnU0dPMUdLU3p5RTdJRVBJdFR4Q0J5dzl4OEZtbnJDRGV4aTkvY09VSk9pST0nO1xuZXhwb3J0IGNvbnN0IEJFVEFORVRfR0VORVNJU19JRCA9ICdiZXRhbmV0LXYxLjAnO1xuZXhwb3J0IGNvbnN0IEJFVEFORVRfR0VORVNJU19IQVNIID0gJ21GZ2F6RisydVJTMXRNaUw5ZHNqMDFoSkd5U0VtUE4yOEIvVGpqdnBWVzA9JztcblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFRyYW5zYWN0aW9uQnVpbGRlciBleHRlbmRzIEJhc2VUcmFuc2FjdGlvbkJ1aWxkZXIge1xuICBwcm90ZWN0ZWQgX3RyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbjtcbiAgcHJvdGVjdGVkIF9rZXlQYWlyczogS2V5UGFpcltdO1xuXG4gIC8vIHRoZSBmZWUgaXMgc3BlY2lmaWVkIGFzIGEgbnVtYmVyIGhlcmUgaW5zdGVhZCBvZiBhIGJpZyBudW1iZXIgYmVjYXVzZVxuICAvLyB0aGUgYWxnb3NkayBhbHNvIHNwZWNpZmllcyBpdCBhcyBhIG51bWJlci5cbiAgcHJvdGVjdGVkIF9mZWU6IG51bWJlcjtcbiAgcHJvdGVjdGVkIF9pc0ZsYXRGZWU6IGJvb2xlYW47XG5cbiAgcHJvdGVjdGVkIF9zZW5kZXI6IHN0cmluZztcbiAgcHJvdGVjdGVkIF9nZW5lc2lzSGFzaDogc3RyaW5nO1xuICBwcm90ZWN0ZWQgX2dlbmVzaXNJZDogc3RyaW5nO1xuICBwcm90ZWN0ZWQgX2ZpcnN0Um91bmQ6IG51bWJlcjtcbiAgcHJvdGVjdGVkIF9sYXN0Um91bmQ6IG51bWJlcjtcbiAgcHJvdGVjdGVkIF9sZWFzZT86IFVpbnQ4QXJyYXk7XG4gIHByb3RlY3RlZCBfbm90ZT86IFVpbnQ4QXJyYXk7XG4gIHByb3RlY3RlZCBfcmVLZXlUbz86IHN0cmluZztcbiAgcHJvdGVjdGVkIF9zdWdnZXN0ZWRQYXJhbXM6IGFsZ29zZGsuU3VnZ2VzdGVkUGFyYW1zO1xuXG4gIGNvbnN0cnVjdG9yKGNvaW5Db25maWc6IFJlYWRvbmx5PENvaW5Db25maWc+KSB7XG4gICAgc3VwZXIoY29pbkNvbmZpZyk7XG5cbiAgICB0aGlzLl90cmFuc2FjdGlvbiA9IG5ldyBUcmFuc2FjdGlvbihjb2luQ29uZmlnKTtcbiAgICB0aGlzLl9rZXlQYWlycyA9IFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGZlZS5cbiAgICpcbiAgICogVGhlIG1pbmltdW0gZmVlIGlzIDEwMDAgbWljcm9hbGdvcy5cbiAgICpcbiAgICogQHBhcmFtIHtCYXNlRmVlfSBmZWVPYmogVGhlIGFtb3VudCB0byBwYXkgdG8gdGhlIGZlZSBzaW5rIGRlbm90ZWQgaW4gbWljcm9hbGdvc1xuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25CdWlsZGVyfSBUaGlzIHRyYW5zYWN0aW9uIGJ1aWxkZXIuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYWxnb3JhbmQub3JnL2RvY3MvcmVmZXJlbmNlL3RyYW5zYWN0aW9ucy9cbiAgICovXG4gIGZlZShmZWVPYmo6IEJhc2VGZWUpOiB0aGlzIHtcbiAgICB0aGlzLl9pc0ZsYXRGZWUgPSB0cnVlO1xuICAgIGNvbnN0IGZlZSA9IG5ldyBCaWdOdW1iZXIoZmVlT2JqLmZlZSkudG9OdW1iZXIoKTtcbiAgICBpZiAodGhpcy5faXNGbGF0RmVlICYmIGZlZSA8IE1JTl9GRUUpIHtcbiAgICAgIHRocm93IG5ldyBJbnN1ZmZpY2llbnRGZWVFcnJvcihmZWUsIE1JTl9GRUUpO1xuICAgIH1cblxuICAgIHRoaXMuX2ZlZSA9IGZlZTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgd2hldGhlciB0aGUgZmVlIGlzIGEgZmxhdCBmZWUuXG4gICAqXG4gICAqIEEgZmxhdCBmZWUgaXMgdGhlIGZlZSBmb3IgdGhlIGVudGlyZSB0cmFuc2FjdGlvbiB3aGVyZWFzIGEgbm9ybWFsIGZlZVxuICAgKiBpcyBhIGZlZSBmb3IgZXZlcnkgYnl0ZSBpbiB0aGUgdHJhbnNhY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNGbGF0RmVlIFdoZXRoZXIgdGhlIGZlZSBzaG91bGQgYmUgc3BlY2lmaWVkIGFzIGEgZmxhdCBmZWUuXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlci5cbiAgICovXG4gIGlzRmxhdEZlZShpc0ZsYXRGZWU6IGJvb2xlYW4pOiB0aGlzIHtcbiAgICB0aGlzLl9pc0ZsYXRGZWUgPSBpc0ZsYXRGZWU7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSB0cmFuc2FjdGlvbiBzZW5kZXIuXG4gICAqXG4gICAqIEBwYXJhbSB7QmFzZUFkZHJlc3N9IHNlbmRlciBUaGUgc2VuZGVyIGFjY291bnRcbiAgICogQHJldHVybnMge1RyYW5zYWN0aW9uQnVpbGRlcn0gVGhpcyB0cmFuc2FjdGlvbiBidWlsZGVyLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLmFsZ29yYW5kLm9yZy9kb2NzL3JlZmVyZW5jZS90cmFuc2FjdGlvbnMvXG4gICAqL1xuICBzZW5kZXIoc2VuZGVyOiBCYXNlQWRkcmVzcyk6IHRoaXMge1xuICAgIHRoaXMudmFsaWRhdGVBZGRyZXNzKHNlbmRlcik7XG4gICAgdGhpcy5fc2VuZGVyID0gc2VuZGVyLmFkZHJlc3M7XG4gICAgdGhpcy5fdHJhbnNhY3Rpb24uc2VuZGVyKHNlbmRlci5hZGRyZXNzKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGdlbmVzaXMgaWQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBnZW5lc2lzSWQgVGhlIGdlbmVzaXMgaWQuXG4gICAqIEBleGFtcGxlIFwibWFpbm5ldC12MS4wXCJcbiAgICpcbiAgICogQHJldHVybnMge1RyYW5zYWN0aW9uQnVpbGRlcn0gVGhpcyB0cmFuc2FjdGlvbiBidWlsZGVyLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLmFsZ29yYW5kLm9yZy9kb2NzL3JlZmVyZW5jZS90cmFuc2FjdGlvbnMvXG4gICAqL1xuICBnZW5lc2lzSWQoZ2VuZXNpc0lkOiBzdHJpbmcpOiB0aGlzIHtcbiAgICB0aGlzLl9nZW5lc2lzSWQgPSBnZW5lc2lzSWQ7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBnZW5lc2lzIGhhc2guXG4gICAqXG4gICAqIFRoZSBnZW5lc2lzIGhhc2ggbXVzdCBiZSBiYXNlNjQgZW5jb2RlZC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGdlbmVzaXNIYXNoIFRoZSBnZW5lc2lzIGhhc2guXG4gICAqIEBleGFtcGxlIFwid0dIRTJQd2R2ZDdTMTJCTDVGYU9QMjBFR1llc043M2t0aUMxcXpra2l0OD1cIlxuICAgKlxuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25CdWlsZGVyfSBUaGlzIHRyYW5zYWN0aW9uIGJ1aWxkZXIuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYWxnb3JhbmQub3JnL2RvY3MvcmVmZXJlbmNlL3RyYW5zYWN0aW9ucy9cbiAgICovXG4gIGdlbmVzaXNIYXNoKGdlbmVzaXNIYXNoOiBzdHJpbmcpOiB0aGlzIHtcbiAgICB0aGlzLl9nZW5lc2lzSGFzaCA9IGdlbmVzaXNIYXNoO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgZ2VuZXNpcyBpZCBhbmQgaGFzaCB0byBtYWlubmV0LlxuICAgKlxuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25CdWlsZGVyfSBUaGlzIHRyYW5zYWN0aW9uIGJ1aWxkZXIuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYWxnb3JhbmQub3JnL2RvY3MvcmVmZXJlbmNlL2FsZ29yYW5kLW5ldHdvcmtzL21haW5uZXQvI2dlbmVzaXMtaWRcbiAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5hbGdvcmFuZC5vcmcvZG9jcy9yZWZlcmVuY2UvYWxnb3JhbmQtbmV0d29ya3MvbWFpbm5ldC8jZ2VuZXNpcy1oYXNoXG4gICAqL1xuICBtYWlubmV0KCk6IHRoaXMge1xuICAgIHRoaXMuZ2VuZXNpc0lkKE1BSU5ORVRfR0VORVNJU19JRCk7XG4gICAgdGhpcy5nZW5lc2lzSGFzaChNQUlOTkVUX0dFTkVTSVNfSEFTSCk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBnZW5lc2lzIGlkIGFuZCBoYXNoIHRvIHRlc3RuZXQuXG4gICAqXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlci5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5hbGdvcmFuZC5vcmcvZG9jcy9yZWZlcmVuY2UvYWxnb3JhbmQtbmV0d29ya3MvdGVzdG5ldC8jZ2VuZXNpcy1pZFxuICAgKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLmFsZ29yYW5kLm9yZy9kb2NzL3JlZmVyZW5jZS9hbGdvcmFuZC1uZXR3b3Jrcy90ZXN0bmV0LyNnZW5lc2lzLWhhc2hcbiAgICovXG4gIHRlc3RuZXQoKTogdGhpcyB7XG4gICAgdGhpcy5nZW5lc2lzSWQoVEVTVE5FVF9HRU5FU0lTX0lEKTtcbiAgICB0aGlzLmdlbmVzaXNIYXNoKFRFU1RORVRfR0VORVNJU19IQVNIKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGdlbmVzaXMgaWQgYW5kIGhhc2ggdG8gYmV0YW5ldC5cbiAgICpcbiAgICogQHJldHVybnMge1RyYW5zYWN0aW9uQnVpbGRlcn0gVGhpcyB0cmFuc2FjdGlvbiBidWlsZGVyLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLmFsZ29yYW5kLm9yZy9kb2NzL3JlZmVyZW5jZS9hbGdvcmFuZC1uZXR3b3Jrcy9iZXRhbmV0LyNnZW5lc2lzLWlkXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYWxnb3JhbmQub3JnL2RvY3MvcmVmZXJlbmNlL2FsZ29yYW5kLW5ldHdvcmtzL2JldGFuZXQvI2dlbmVzaXMtaGFzaFxuICAgKi9cbiAgYmV0YW5ldCgpOiB0aGlzIHtcbiAgICB0aGlzLmdlbmVzaXNJZChCRVRBTkVUX0dFTkVTSVNfSUQpO1xuICAgIHRoaXMuZ2VuZXNpc0hhc2goQkVUQU5FVF9HRU5FU0lTX0hBU0gpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgZmlyc3Qgcm91bmQuXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSByb3VuZCBUaGUgZmlyc3QgcHJvdG9jb2wgcm91bmQgb24gd2hpY2ggdGhpcyB0eG4gaXMgdmFsaWQuXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlci5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5hbGdvcmFuZC5vcmcvZG9jcy9yZWZlcmVuY2UvdHJhbnNhY3Rpb25zL1xuICAgKi9cbiAgZmlyc3RSb3VuZChyb3VuZDogbnVtYmVyKTogdGhpcyB7XG4gICAgdGhpcy52YWxpZGF0ZVZhbHVlKG5ldyBCaWdOdW1iZXIocm91bmQpKTtcblxuICAgIHRoaXMuX2ZpcnN0Um91bmQgPSByb3VuZDtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGxhc3Qgcm91bmQuXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSByb3VuZCBUaGUgZmlyc3QgcHJvdG9jb2wgcm91bmQgb24gd2hpY2ggdGhpcyB0eG4gaXMgdmFsaWQuXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlci5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5hbGdvcmFuZC5vcmcvZG9jcy9yZWZlcmVuY2UvdHJhbnNhY3Rpb25zL1xuICAgKi9cbiAgbGFzdFJvdW5kKHJvdW5kOiBudW1iZXIpOiB0aGlzIHtcbiAgICB0aGlzLnZhbGlkYXRlVmFsdWUobmV3IEJpZ051bWJlcihyb3VuZCkpO1xuXG4gICAgdGhpcy5fbGFzdFJvdW5kID0gcm91bmQ7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBsZWFzZSBvbiB0aGUgdHJhbnNhY3Rpb24uXG4gICAqXG4gICAqIEEgbGVhc2UgaXMgYSBtdXRleCBvbiB0aGUgdHJhbnNhY3Rpb24gdGhhdCBwcmV2ZW50cyBhbnkgb3RoZXIgdHJhbnNhY3Rpb25cbiAgICogZnJvbSBiZWluZyBzZW50IHdpdGggdGhlIHNhbWUgbGVhc2UgdW50aWwgdGhlIHByaW9yIHRyYW5zYWN0aW9uJ3MgbGFzdFxuICAgKiByb3VuZCBoYXMgcGFzc2VkLlxuICAgKlxuICAgKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IGxlYXNlIFRoZSBsZWFzZSB0byBwdXQgdGhlIHRyYW5zYWN0aW9uLlxuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25CdWlsZGVyfSBUaGlzIHRyYW5zYWN0aW9uIGJ1aWxkZXIuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYWxnb3JhbmQub3JnL2RvY3MvcmVmZXJlbmNlL3RyYW5zYWN0aW9ucy9cbiAgICovXG4gIGxlYXNlKGxlYXNlOiBVaW50OEFycmF5KTogdGhpcyB7XG4gICAgdGhpcy5fbGVhc2UgPSBsZWFzZTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIG5vdGUgZm9yIHRoZSB0cmFuc2FjdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtVaW50OEFycmF5fSBub3RlIEFyYml0cmFyeSBkYXRhIGZvciBzZW5kZXIgdG8gc3RvcmUuXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlci5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5hbGdvcmFuZC5vcmcvZG9jcy9yZWZlcmVuY2UvdHJhbnNhY3Rpb25zL1xuICAgKi9cbiAgbm90ZShub3RlOiBVaW50OEFycmF5KTogdGhpcyB7XG4gICAgdGhpcy5fbm90ZSA9IG5vdGU7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBhdXRob3JpemVkIGFkZHJlc3MuXG4gICAqXG4gICAqIFRoZSBhdXRob3JpemVkIGFzc2V0IHdpbGwgYmUgdXNlZCB0byBhdXRob3JpemUgYWxsIGZ1dHVyZSB0cmFuc2FjdGlvbnMuXG4gICAqXG4gICAqIEBwYXJhbSB7QmFzZUFkZHJlc3N9IGF1dGhvcml6ZXIgVGhlIGFkZHJlc3MgdG8gZGVsZWdhdGUgYXV0aG9yaXphdGlvbiBhdXRob3JpdHkgdG8uXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlci5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5hbGdvcmFuZC5vcmcvZG9jcy9yZWZlcmVuY2UvdHJhbnNhY3Rpb25zL1xuICAgKi9cbiAgcmVLZXlUbyhhdXRob3JpemVyOiBCYXNlQWRkcmVzcyk6IHRoaXMge1xuICAgIHRoaXMudmFsaWRhdGVBZGRyZXNzKGF1dGhvcml6ZXIpO1xuICAgIHRoaXMuX3JlS2V5VG8gPSBhdXRob3JpemVyLmFkZHJlc3M7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICB2YWxpZGF0ZUFkZHJlc3MoeyBhZGRyZXNzIH06IEJhc2VBZGRyZXNzKTogdm9pZCB7XG4gICAgaWYgKCFhbGdvc2RrLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgQWRkcmVzc1ZhbGlkYXRpb25FcnJvcihhZGRyZXNzKTtcbiAgICB9XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGJ1aWxkSW1wbGVtZW50YXRpb24oKTogUHJvbWlzZTxUcmFuc2FjdGlvbj4ge1xuICAgIHRoaXMudHJhbnNhY3Rpb24uc2V0QWxnb1RyYW5zYWN0aW9uKHRoaXMuYnVpbGRBbGdvVHhuKCkpO1xuICAgIHRoaXMudHJhbnNhY3Rpb24uc2V0VHJhbnNhY3Rpb25UeXBlKHRoaXMudHJhbnNhY3Rpb25UeXBlKTtcblxuICAgIHRoaXMudHJhbnNhY3Rpb24uc2lnbih0aGlzLl9rZXlQYWlycyk7XG4gICAgdGhpcy5fdHJhbnNhY3Rpb24ubG9hZElucHV0c0FuZE91dHB1dHMoKTtcbiAgICByZXR1cm4gdGhpcy5fdHJhbnNhY3Rpb247XG4gIH1cblxuICAvKipcbiAgICogQnVpbGRzIHRoZSBhbGdvcmFuZCB0cmFuc2FjdGlvbi5cbiAgICovXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBidWlsZEFsZ29UeG4oKTogYWxnb3Nkay5UcmFuc2FjdGlvbjtcblxuICAvKipcbiAgICogVGhlIHRyYW5zYWN0aW9uIHR5cGUuXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgZ2V0IHRyYW5zYWN0aW9uVHlwZSgpOiBUcmFuc2FjdGlvblR5cGU7XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIHByb3RlY3RlZCBmcm9tSW1wbGVtZW50YXRpb24ocmF3VHJhbnNhY3Rpb246IFVpbnQ4QXJyYXkgfCBzdHJpbmcpOiBUcmFuc2FjdGlvbiB7XG4gICAgY29uc3QgZGVjb2RlZFR4biA9IFV0aWxzLmRlY29kZUFsZ29UeG4ocmF3VHJhbnNhY3Rpb24pO1xuICAgIGNvbnN0IGFsZ29zZGtUeG4gPSBkZWNvZGVkVHhuLnR4bjtcblxuICAgIGlmIChkZWNvZGVkVHhuLnNpZ25lZCkge1xuICAgICAgdGhpcy5fdHJhbnNhY3Rpb24uc2lnbmVkVHJhbnNhY3Rpb24gPSBkZWNvZGVkVHhuLnJhd1RyYW5zYWN0aW9uO1xuICAgICAgaWYgKGRlY29kZWRUeG4uc2lnbmVycykge1xuICAgICAgICB0aGlzLnNldFNpZ25lcnMoZGVjb2RlZFR4bi5zaWduZXJzKTtcbiAgICAgIH1cbiAgICAgIGlmIChkZWNvZGVkVHhuLnNpZ25lZEJ5KSB7XG4gICAgICAgIHRoaXMuX3RyYW5zYWN0aW9uLnNpZ25lZEJ5ID0gZGVjb2RlZFR4bi5zaWduZWRCeTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5zZW5kZXIoeyBhZGRyZXNzOiBhbGdvc2RrLmVuY29kZUFkZHJlc3MoYWxnb3Nka1R4bi5mcm9tLnB1YmxpY0tleSkgfSk7XG4gICAgdGhpcy5faXNGbGF0RmVlID0gdHJ1ZTtcbiAgICB0aGlzLl9mZWUgPSBhbGdvc2RrVHhuLmZlZTtcbiAgICB0aGlzLl9nZW5lc2lzSGFzaCA9IGFsZ29zZGtUeG4uZ2VuZXNpc0hhc2gudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIHRoaXMuX2dlbmVzaXNJZCA9IGFsZ29zZGtUeG4uZ2VuZXNpc0lEO1xuICAgIHRoaXMuX2ZpcnN0Um91bmQgPSBhbGdvc2RrVHhuLmZpcnN0Um91bmQ7XG4gICAgdGhpcy5fbGFzdFJvdW5kID0gYWxnb3Nka1R4bi5sYXN0Um91bmQ7XG4gICAgdGhpcy5fbGVhc2UgPSBhbGdvc2RrVHhuLmxlYXNlO1xuICAgIHRoaXMuX25vdGUgPSBhbGdvc2RrVHhuLm5vdGU7XG4gICAgdGhpcy5fcmVLZXlUbyA9IGFsZ29zZGtUeG4ucmVLZXlUbyA/IGFsZ29zZGsuZW5jb2RlQWRkcmVzcyhhbGdvc2RrVHhuLnJlS2V5VG8ucHVibGljS2V5KSA6IHVuZGVmaW5lZDtcblxuICAgIHRoaXMuX3RyYW5zYWN0aW9uLnNldEFsZ29UcmFuc2FjdGlvbihhbGdvc2RrVHhuKTtcblxuICAgIHJldHVybiB0aGlzLl90cmFuc2FjdGlvbjtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBwcm90ZWN0ZWQgc2lnbkltcGxlbWVudGF0aW9uKHsga2V5IH06IEJhc2VLZXkpOiBUcmFuc2FjdGlvbiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGJ1ZmZLZXkgPSBVdGlscy5kZWNvZGVTZWVkKGtleSk7XG4gICAgICBjb25zdCBrZXlwYWlyID0gbmV3IEtleVBhaXIoeyBwcnY6IEJ1ZmZlci5mcm9tKGJ1ZmZLZXkuc2VlZCkudG9TdHJpbmcoJ2hleCcpIH0pO1xuICAgICAgdGhpcy5fa2V5UGFpcnMucHVzaChrZXlwYWlyKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBpZiAoYWxnb1V0aWxzLmlzVmFsaWRQcml2YXRlS2V5KGtleSkpIHtcbiAgICAgICAgY29uc3Qga2V5cGFpciA9IG5ldyBLZXlQYWlyKHsgcHJ2OiBrZXkgfSk7XG4gICAgICAgIHRoaXMuX2tleVBhaXJzLnB1c2goa2V5cGFpcik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLl90cmFuc2FjdGlvbjtcbiAgfVxuXG4gIG51bWJlck9mU2lnbmVycyhudW06IG51bWJlcik6IHRoaXMge1xuICAgIHRoaXMuX3RyYW5zYWN0aW9uLnNldE51bWJlck9mUmVxdWlyZWRTaWduZXJzKG51bSk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFNpZ25lcnMoYWRkcnM6IHN0cmluZyB8IHN0cmluZ1tdKTogdGhpcyB7XG4gICAgY29uc3Qgc2lnbmVycyA9IGFkZHJzIGluc3RhbmNlb2YgQXJyYXkgPyBhZGRycyA6IFthZGRyc107XG4gICAgc2lnbmVycy5mb3JFYWNoKChhZGRyZXNzKSA9PiB0aGlzLnZhbGlkYXRlQWRkcmVzcyh7IGFkZHJlc3M6IGFkZHJlc3MgfSkpO1xuICAgIHRoaXMuX3RyYW5zYWN0aW9uLnNpZ25lcnMgPSBzaWduZXJzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIG51bWJlciBvZiBzaWduZXJzIHJlcXVpcmVkIHRvIHNpZ24gdGhlIHRyYW5zYWN0aW9uLlxuICAgKlxuICAgKiBUaGUgbnVtYmVyIG9mIHNpZ25lcnMgY2Fubm90IGJlIHNldCB0byBhIG5lZ2F0aXZlIHZhbHVlLlxuICAgKlxuICAgKiBAcGFyYW0ge251bWJlcn0gbiBUaGUgbnVtYmVyIG9mIHNpZ25lcnMuXG4gICAqIEByZXR1cm5zIHtUcmFuc2FjdGlvbkJ1aWxkZXJ9IFRoaXMgdHJhbnNhY3Rpb24gYnVpbGRlci5cbiAgICovXG4gIG51bWJlck9mUmVxdWlyZWRTaWduZXJzKG46IG51bWJlcik6IHRoaXMge1xuICAgIGlmIChuIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcihgTnVtYmVyIG9mIHNpZ25lcnM6ICcke259JyBjYW5ub3QgYmUgbmVnYXRpdmVgKTtcbiAgICB9XG5cbiAgICB0aGlzLl90cmFuc2FjdGlvbi5zZXROdW1iZXJPZlJlcXVpcmVkU2lnbmVycyhuKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBpbmhlcml0ZG9jXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYWxnb3JhbmQub3JnL2RvY3MvZmVhdHVyZXMvYWNjb3VudHMvI3RyYW5zZm9ybWF0aW9uLXByaXZhdGUta2V5LXRvLWJhc2U2NC1wcml2YXRlLWtleVxuICAgKi9cbiAgdmFsaWRhdGVLZXkoeyBrZXkgfTogQmFzZUtleSk6IHZvaWQge1xuICAgIGxldCBpc1ZhbGlkUHJpdmF0ZUtleUZyb21CeXRlcztcbiAgICBjb25zdCBpc1ZhbGlkUHJpdmF0ZUtleUZyb21IZXggPSBpc1ZhbGlkRWQyNTUxOVNlZWQoa2V5KTtcbiAgICBjb25zdCBpc1ZhbGlkUHJpdmF0ZUtleUZyb21CYXNlNjQgPSBpc1ZhbGlkRWQyNTUxOVNlZWQoQnVmZmVyLmZyb20oa2V5LCAnYmFzZTY0JykudG9TdHJpbmcoJ2hleCcpKTtcbiAgICBjb25zdCBpc1ZhbGlkUm9vdFBydktleSA9IGlzVmFsaWRFZDI1NTE5U2VjcmV0S2V5KGtleSk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGRlY29kZWRTZWVkID0gVXRpbHMuZGVjb2RlU2VlZChrZXkpO1xuICAgICAgaXNWYWxpZFByaXZhdGVLZXlGcm9tQnl0ZXMgPSBpc1ZhbGlkRWQyNTUxOVNlZWQoQnVmZmVyLmZyb20oZGVjb2RlZFNlZWQuc2VlZCkudG9TdHJpbmcoJ2hleCcpKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlzVmFsaWRQcml2YXRlS2V5RnJvbUJ5dGVzID0gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgIWlzVmFsaWRQcml2YXRlS2V5RnJvbUJ5dGVzICYmXG4gICAgICAhaXNWYWxpZFByaXZhdGVLZXlGcm9tSGV4ICYmXG4gICAgICAhaXNWYWxpZFByaXZhdGVLZXlGcm9tQmFzZTY0ICYmXG4gICAgICAhaXNWYWxpZFJvb3RQcnZLZXlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBCdWlsZFRyYW5zYWN0aW9uRXJyb3IoYEtleSB2YWxpZGF0aW9uIGZhaWxlZGApO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICB2YWxpZGF0ZVJhd1RyYW5zYWN0aW9uKHJhd1RyYW5zYWN0aW9uOiBVaW50OEFycmF5IHwgc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgZGVjb2RlZFR4biA9IFV0aWxzLmRlY29kZUFsZ29UeG4ocmF3VHJhbnNhY3Rpb24pO1xuICAgIGNvbnN0IGFsZ29UeG4gPSBkZWNvZGVkVHhuLnR4bjtcblxuICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSBCYXNlVHJhbnNhY3Rpb25TY2hlbWEudmFsaWRhdGUoe1xuICAgICAgZmVlOiBhbGdvVHhuPy5mZWUsXG4gICAgICBmaXJzdFJvdW5kOiBhbGdvVHhuPy5maXJzdFJvdW5kLFxuICAgICAgZ2VuZXNpc0hhc2g6IGFsZ29UeG4/LmdlbmVzaXNIYXNoLnRvU3RyaW5nKCdiYXNlNjQnKSxcbiAgICAgIGxhc3RSb3VuZDogYWxnb1R4bj8ubGFzdFJvdW5kLFxuICAgICAgc2VuZGVyOiBhbGdvVHhuID8gYWxnb3Nkay5lbmNvZGVBZGRyZXNzKGFsZ29UeG4uZnJvbS5wdWJsaWNLZXkpIDogdW5kZWZpbmVkLFxuICAgICAgZ2VuZXNpc0lkOiBhbGdvVHhuPy5nZW5lc2lzSUQsXG4gICAgICBsZWFzZTogYWxnb1R4bj8ubGVhc2UsXG4gICAgICBub3RlOiBhbGdvVHhuPy5ub3RlLFxuICAgICAgcmVLZXlUbzogYWxnb1R4bj8ucmVLZXlUbyA/IGFsZ29zZGsuZW5jb2RlQWRkcmVzcyhhbGdvVHhuLnJlS2V5VG8ucHVibGljS2V5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGlmICh2YWxpZGF0aW9uUmVzdWx0LmVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoYFRyYW5zYWN0aW9uIHZhbGlkYXRpb24gZmFpbGVkOiAke3ZhbGlkYXRpb25SZXN1bHQuZXJyb3IubWVzc2FnZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgdmFsaWRhdGVUcmFuc2FjdGlvbihfOiBUcmFuc2FjdGlvbik6IHZvaWQge1xuICAgIHRoaXMudmFsaWRhdGVCYXNlRmllbGRzKFxuICAgICAgdGhpcy5fZmVlLFxuICAgICAgdGhpcy5fZmlyc3RSb3VuZCxcbiAgICAgIHRoaXMuX2dlbmVzaXNIYXNoLFxuICAgICAgdGhpcy5fbGFzdFJvdW5kLFxuICAgICAgdGhpcy5fc2VuZGVyLFxuICAgICAgdGhpcy5fZ2VuZXNpc0lkLFxuICAgICAgdGhpcy5fbGVhc2UsXG4gICAgICB0aGlzLl9ub3RlLFxuICAgICAgdGhpcy5fcmVLZXlUb1xuICAgICk7XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlQmFzZUZpZWxkcyhcbiAgICBmZWU6IG51bWJlcixcbiAgICBmaXJzdFJvdW5kOiBudW1iZXIsXG4gICAgZ2VuZXNpc0hhc2g6IHN0cmluZyxcbiAgICBsYXN0Um91bmQ6IG51bWJlcixcbiAgICBzZW5kZXI6IHN0cmluZyxcbiAgICBnZW5lc2lzSWQ6IHN0cmluZyxcbiAgICBsZWFzZTogVWludDhBcnJheSB8IHVuZGVmaW5lZCxcbiAgICBub3RlOiBVaW50OEFycmF5IHwgdW5kZWZpbmVkLFxuICAgIHJlS2V5VG86IHN0cmluZyB8IHVuZGVmaW5lZFxuICApOiB2b2lkIHtcbiAgICBjb25zdCB2YWxpZGF0aW9uUmVzdWx0ID0gQmFzZVRyYW5zYWN0aW9uU2NoZW1hLnZhbGlkYXRlKHtcbiAgICAgIGZlZSxcbiAgICAgIGZpcnN0Um91bmQsXG4gICAgICBnZW5lc2lzSGFzaCxcbiAgICAgIGxhc3RSb3VuZCxcbiAgICAgIHNlbmRlcixcbiAgICAgIGdlbmVzaXNJZCxcbiAgICAgIGxlYXNlLFxuICAgICAgbm90ZSxcbiAgICAgIHJlS2V5VG8sXG4gICAgfSk7XG5cbiAgICBpZiAodmFsaWRhdGlvblJlc3VsdC5lcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRUcmFuc2FjdGlvbkVycm9yKGBUcmFuc2FjdGlvbiB2YWxpZGF0aW9uIGZhaWxlZDogJHt2YWxpZGF0aW9uUmVzdWx0LmVycm9yLm1lc3NhZ2V9YCk7XG4gICAgfVxuICB9XG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICB2YWxpZGF0ZVZhbHVlKHZhbHVlOiBCaWdOdW1iZXIpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUuaXNMZXNzVGhhbigwKSkge1xuICAgICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcignVmFsdWUgY2Fubm90IGJlIGxlc3MgdGhhbiB6ZXJvJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIHByb3RlY3RlZCBnZXQgdHJhbnNhY3Rpb24oKTogVHJhbnNhY3Rpb24ge1xuICAgIHJldHVybiB0aGlzLl90cmFuc2FjdGlvbjtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBwcm90ZWN0ZWQgc2V0IHRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbikge1xuICAgIHRoaXMuX3RyYW5zYWN0aW9uID0gdHJhbnNhY3Rpb247XG4gIH1cblxuICAvKipcbiAgICogQ29udmVuaWVuY2UgbWV0aG9kIHRvIHJldHJpZXZlIHRoZSBhbGdvc2RrIHN1Z2dlc3RlZCBwYXJhbWV0ZXJzLlxuICAgKlxuICAgKiBAcmV0dXJucyB7YWxnb3Nkay5TdWdnZXN0ZWRQYXJhbXN9IFRoZSBhbGdvc2RrIHN1Z2dlc3RlZCBwYXJhbWV0ZXJzLlxuICAgKi9cbiAgcHJvdGVjdGVkIGdldCBzdWdnZXN0ZWRQYXJhbXMoKTogYWxnb3Nkay5TdWdnZXN0ZWRQYXJhbXMge1xuICAgIHJldHVybiB7XG4gICAgICBmbGF0RmVlOiB0aGlzLl9pc0ZsYXRGZWUsXG4gICAgICBmZWU6IHRoaXMuX2ZlZSxcbiAgICAgIGZpcnN0Um91bmQ6IHRoaXMuX2ZpcnN0Um91bmQsXG4gICAgICBsYXN0Um91bmQ6IHRoaXMuX2xhc3RSb3VuZCxcbiAgICAgIGdlbmVzaXNJRDogdGhpcy5fZ2VuZXNpc0lkLFxuICAgICAgZ2VuZXNpc0hhc2g6IHRoaXMuX2dlbmVzaXNIYXNoLFxuICAgIH07XG4gIH1cbn1cbiJdfQ==Выполнить команду
Для локальной разработки. Не используйте в интернете!