PHP WebShell
Текущая директория: /opt/BitGoJS/modules/abstract-eth/dist/src/lib
Просмотр файла: transferBuilder.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.TransferBuilder = void 0;
const assert_1 = __importDefault(require("assert"));
const ethUtil = __importStar(require("ethereumjs-util"));
const ethereumjs_abi_1 = __importDefault(require("ethereumjs-abi"));
const bn_js_1 = __importDefault(require("bn.js"));
const statics_1 = require("@bitgo/statics");
const sdk_core_1 = require("@bitgo/sdk-core");
const utils_1 = require("./utils");
const utils_2 = require("ethers/lib/utils");
const walletUtil_1 = require("./walletUtil");
/** ETH transfer builder */
class TransferBuilder {
constructor(serializedData, isFirstSigner) {
this._EMPTY_HEX_VALUE = '0x';
this._isFirstSigner = isFirstSigner;
if (serializedData) {
this.decodeTransferData(serializedData);
}
else {
// initialize with default values for non mandatory fields
this._expirationTime = this.getExpirationTime();
this._data = this._EMPTY_HEX_VALUE;
this._signature = this._EMPTY_HEX_VALUE;
}
}
/**
* A method to set the native coin or ERC20 token to be transferred.
* This ERC20 token may not be compatible with the network.
*
* @param {string} coin - the native coin or ERC20 token to be set
* @returns {TransferBuilder} the transfer builder instance modified
*/
coin(coin) {
this._coin = statics_1.coins.get(coin);
if (this._coin instanceof statics_1.ContractAddressDefinedToken) {
this._tokenContractAddress = this._coin.contractAddress.toString();
}
return this;
}
getIsFirstSigner() {
return this._isFirstSigner ? this._isFirstSigner : false;
}
walletVersion(version) {
this._walletVersion = version;
return this;
}
data(additionalData) {
this._signature = this._EMPTY_HEX_VALUE;
this._data = additionalData;
return this;
}
amount(amount) {
if (!(0, utils_1.isValidAmount)(amount)) {
throw new sdk_core_1.InvalidParameterValueError('Invalid amount');
}
this._signature = this._EMPTY_HEX_VALUE;
this._amount = amount;
return this;
}
to(address) {
if ((0, utils_1.isValidEthAddress)(address)) {
this._signature = this._EMPTY_HEX_VALUE;
this._toAddress = address;
return this;
}
throw new sdk_core_1.InvalidParameterValueError('Invalid address');
}
contractSequenceId(counter) {
if (counter >= 0) {
this._signature = this._EMPTY_HEX_VALUE;
this._sequenceId = counter;
return this;
}
throw new sdk_core_1.InvalidParameterValueError('Invalid contract sequence id');
}
key(signKey) {
this._signKey = signKey;
return this;
}
expirationTime(date) {
if (date > 0) {
this._signature = this._EMPTY_HEX_VALUE;
this._expirationTime = date;
return this;
}
throw new sdk_core_1.InvalidParameterValueError('Invalid expiration time');
}
isFirstSigner(isFirstSigner) {
this._isFirstSigner = isFirstSigner;
return this;
}
tokenContractAddress(tokenContractAddress) {
this._tokenContractAddress = tokenContractAddress;
return this;
}
setCoinUsesNonPackedEncodingForTxData(isCoinUsesNonPackedEncodingForTxData) {
this._coinUsesNonPackedEncodingForTxData = isCoinUsesNonPackedEncodingForTxData;
return this;
}
setSignature(signature) {
this._signKey = null;
this._signature = signature;
return this;
}
signAndBuild(chainId, coinUsesNonPackedEncodingForTxData) {
this._chainId = chainId;
// If the coin uses non-packed encoding for tx data, the operation hash is calculated differently
// This new encoding type is applicable only for native coins and not tokens
this._coinUsesNonPackedEncodingForTxData =
coinUsesNonPackedEncodingForTxData && this._tokenContractAddress === undefined;
if (this.hasMandatoryFields()) {
if (this._isFirstSigner) {
// First signer signs different data than the second signer in multisig evm contracts.
return ethUtil.addHexPrefix(this.getSignatureData().toString('hex'));
}
else {
if (this._tokenContractAddress !== undefined) {
return (0, utils_1.sendMultiSigTokenData)(this._toAddress, this._amount, this._tokenContractAddress, this._expirationTime, this._sequenceId, this.getSignature());
}
else {
return (0, utils_1.sendMultiSigData)(this._toAddress, this._amount, this._data, this._expirationTime, this._sequenceId, this.getSignature());
}
}
}
throw new sdk_core_1.BuildTransactionError('Missing transfer mandatory fields. Amount, destination (to) address and sequenceID are mandatory');
}
hasMandatoryFields() {
return this._amount !== undefined && this._toAddress !== undefined && this._sequenceId !== undefined;
}
/**
* Obtains the proper operation hash to sign either a sendMultiSig data
* or a sendMultiSigToken data
*
* @returns {string} the operation hash
*/
getOperationHash() {
const operationData = this.getOperationData();
let operationHash;
if (this._coinUsesNonPackedEncodingForTxData) {
const types = operationData[0];
const values = operationData[1].map((item) => typeof item === 'string' || typeof item === 'number' ? item : '0x' + item.toString('hex'));
operationHash = (0, utils_2.keccak256)(utils_2.defaultAbiCoder.encode(types, values));
}
else {
// If the coin uses packed encoding for tx data or it is a token, the operation hash is calculated using the Ethereum ABI
operationHash = ethUtil.bufferToHex(ethereumjs_abi_1.default.soliditySHA3(...operationData));
}
return operationHash;
}
getOperationData() {
let operationData;
const prefix = this.getOperationHashPrefix();
if (this._tokenContractAddress !== undefined) {
operationData = [
['string', 'address', 'uint', 'address', 'uint', 'uint'],
[
prefix,
new bn_js_1.default(ethUtil.stripHexPrefix(this._toAddress), 16),
this._amount,
new bn_js_1.default(ethUtil.stripHexPrefix(this._tokenContractAddress), 16),
this._expirationTime,
this._sequenceId,
],
];
}
else {
const toAddress = this._coinUsesNonPackedEncodingForTxData
? this._toAddress
: new bn_js_1.default(ethUtil.stripHexPrefix(this._toAddress), 16);
operationData = [
['string', 'address', 'uint', 'bytes', 'uint', 'uint'],
[
prefix,
toAddress,
this._amount,
Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(this._data)) || '', 'hex'),
this._expirationTime,
this._sequenceId,
],
];
}
return operationData;
}
getOperationHashPrefix() {
if (this._walletVersion === 4) {
return this._tokenContractAddress ? `${this._chainId}-ERC20` : `${this._chainId}`;
}
return this._tokenContractAddress ? this.getTokenOperationHashPrefix() : this.getNativeOperationHashPrefix();
}
/**
* Get the prefix used in generating an operation hash for sending tokens
*
* @returns the string prefix
*/
getTokenOperationHashPrefix() {
return this._coin?.network?.tokenOperationHashPrefix ?? `${this._chainId}-ERC20` ?? 'ERC20';
}
/**
* Get the prefix used in generating an operation hash for sending native coins
*
* @returns the string prefix
*/
getNativeOperationHashPrefix() {
return this._coin?.network?.nativeCoinOperationHashPrefix ?? `${this._chainId}` ?? 'ETHER';
}
/** Return an expiration time, in seconds, set to one hour from now
*
* @returns {number} expiration time
*/
getExpirationTime() {
const currentDate = new Date();
currentDate.setHours(currentDate.getHours() + 1);
return currentDate.getTime() / 1000;
}
/**
* If a signing key is set for this builder, recalculates the signature
*
* @returns {string} the signature value
*/
getSignature() {
if (this._signKey) {
this._signature = this.ethSignMsgHash();
}
return this._signature;
}
ethSignMsgHash() {
const data = this.getOperationHash();
(0, assert_1.default)(this._signKey);
const keyBuffer = Buffer.from(ethUtil.padToEven(this._signKey), 'hex');
if (keyBuffer.length !== 32) {
throw new Error('private key length is invalid');
}
const signatureInParts = ethUtil.ecsign(Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(data)), 'hex'), keyBuffer);
// Assemble strings from r, s and v
const r = ethUtil.setLengthLeft(signatureInParts.r, 32).toString('hex');
const s = ethUtil.setLengthLeft(signatureInParts.s, 32).toString('hex');
const v = ethUtil.stripHexPrefix(ethUtil.intToHex(signatureInParts.v));
// Concatenate the r, s and v parts to make the signature string
return ethUtil.addHexPrefix(r.concat(s, v));
}
decodeTransferData(data) {
const transferData = (0, utils_1.decodeTransferData)(data, this._isFirstSigner);
this._toAddress = transferData.to;
this._amount = transferData.amount;
this._expirationTime = transferData.expireTime;
this._sequenceId = transferData.sequenceId;
this._signature = transferData.signature;
if (transferData.data) {
this._data = transferData.data;
}
if (transferData.tokenContractAddress) {
this._tokenContractAddress = transferData.tokenContractAddress;
}
}
getSignatureData() {
const method = this._tokenContractAddress
? ethereumjs_abi_1.default.methodID('sendMultiSigToken', walletUtil_1.sendMultiSigTokenTypes)
: ethereumjs_abi_1.default.methodID('sendMultiSig', walletUtil_1.sendMultiSigTypes);
const operationData = this.getOperationData();
const rawEncodedOperationData = ethereumjs_abi_1.default.rawEncode(...operationData);
return Buffer.concat([
method,
rawEncodedOperationData,
Buffer.from([this._coinUsesNonPackedEncodingForTxData ? 1 : 0]),
]);
}
}
exports.TransferBuilder = TransferBuilder;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNmZXJCdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi90cmFuc2ZlckJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsb0RBQTRCO0FBQzVCLHlEQUEyQztBQUMzQyxvRUFBeUM7QUFDekMsa0RBQXVCO0FBQ3ZCLDRDQUFpSDtBQUNqSCw4Q0FBb0Y7QUFDcEYsbUNBQXdIO0FBQ3hILDRDQUE4RDtBQUM5RCw2Q0FBeUU7QUFFekUsMkJBQTJCO0FBQzNCLE1BQWEsZUFBZTtJQWdCMUIsWUFBWSxjQUF1QixFQUFFLGFBQXVCO1FBZjNDLHFCQUFnQixHQUFHLElBQUksQ0FBQztRQWdCdkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxhQUFhLENBQUM7UUFDcEMsSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsa0JBQWtCLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDMUMsQ0FBQzthQUFNLENBQUM7WUFDTiwwREFBMEQ7WUFDMUQsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUNoRCxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztZQUNuQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztRQUMxQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILElBQUksQ0FBQyxJQUFZO1FBQ2YsSUFBSSxDQUFDLEtBQUssR0FBRyxlQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdCLElBQUksSUFBSSxDQUFDLEtBQUssWUFBWSxxQ0FBMkIsRUFBRSxDQUFDO1lBQ3RELElBQUksQ0FBQyxxQkFBcUIsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNyRSxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDM0QsQ0FBQztJQUVELGFBQWEsQ0FBQyxPQUFlO1FBQzNCLElBQUksQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDO1FBQzlCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELElBQUksQ0FBQyxjQUFzQjtRQUN6QixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztRQUN4QyxJQUFJLENBQUMsS0FBSyxHQUFHLGNBQWMsQ0FBQztRQUM1QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxNQUFNLENBQUMsTUFBYztRQUNuQixJQUFJLENBQUMsSUFBQSxxQkFBYSxFQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLHFDQUEwQixDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDekQsQ0FBQztRQUNELElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDO1FBQ3hDLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDO1FBQ3RCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELEVBQUUsQ0FBQyxPQUFlO1FBQ2hCLElBQUksSUFBQSx5QkFBaUIsRUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDO1lBQ3hDLElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDO1lBQzFCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE1BQU0sSUFBSSxxQ0FBMEIsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRCxrQkFBa0IsQ0FBQyxPQUFlO1FBQ2hDLElBQUksT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDO1lBQ3hDLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDO1lBQzNCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE1BQU0sSUFBSSxxQ0FBMEIsQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFFRCxHQUFHLENBQUMsT0FBZTtRQUNqQixJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQztRQUN4QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxjQUFjLENBQUMsSUFBWTtRQUN6QixJQUFJLElBQUksR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNiLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDO1lBQ3hDLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDO1lBQzVCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE1BQU0sSUFBSSxxQ0FBMEIsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7SUFFRCxhQUFhLENBQUMsYUFBc0I7UUFDbEMsSUFBSSxDQUFDLGNBQWMsR0FBRyxhQUFhLENBQUM7UUFDcEMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsb0JBQW9CLENBQUMsb0JBQTRCO1FBQy9DLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxvQkFBb0IsQ0FBQztRQUNsRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxxQ0FBcUMsQ0FBQyxvQ0FBNkM7UUFDakYsSUFBSSxDQUFDLG1DQUFtQyxHQUFHLG9DQUFvQyxDQUFDO1FBQ2hGLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELFlBQVksQ0FBQyxTQUFpQjtRQUM1QixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUNyQixJQUFJLENBQUMsVUFBVSxHQUFHLFNBQVMsQ0FBQztRQUM1QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxZQUFZLENBQUMsT0FBZSxFQUFFLGtDQUE0QztRQUN4RSxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQztRQUV4QixpR0FBaUc7UUFDakcsNEVBQTRFO1FBQzVFLElBQUksQ0FBQyxtQ0FBbUM7WUFDdEMsa0NBQWtDLElBQUksSUFBSSxDQUFDLHFCQUFxQixLQUFLLFNBQVMsQ0FBQztRQUNqRixJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLENBQUM7WUFDOUIsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3hCLHNGQUFzRjtnQkFDdEYsT0FBTyxPQUFPLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ3ZFLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLElBQUksQ0FBQyxxQkFBcUIsS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDN0MsT0FBTyxJQUFBLDZCQUFxQixFQUMxQixJQUFJLENBQUMsVUFBVSxFQUNmLElBQUksQ0FBQyxPQUFPLEVBQ1osSUFBSSxDQUFDLHFCQUFxQixFQUMxQixJQUFJLENBQUMsZUFBZSxFQUNwQixJQUFJLENBQUMsV0FBVyxFQUNoQixJQUFJLENBQUMsWUFBWSxFQUFFLENBQ3BCLENBQUM7Z0JBQ0osQ0FBQztxQkFBTSxDQUFDO29CQUNOLE9BQU8sSUFBQSx3QkFBZ0IsRUFDckIsSUFBSSxDQUFDLFVBQVUsRUFDZixJQUFJLENBQUMsT0FBTyxFQUNaLElBQUksQ0FBQyxLQUFLLEVBQ1YsSUFBSSxDQUFDLGVBQWUsRUFDcEIsSUFBSSxDQUFDLFdBQVcsRUFDaEIsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUNwQixDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUNELE1BQU0sSUFBSSxnQ0FBcUIsQ0FDN0Isa0dBQWtHLENBQ25HLENBQUM7SUFDSixDQUFDO0lBRU8sa0JBQWtCO1FBQ3hCLE9BQU8sSUFBSSxDQUFDLE9BQU8sS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLFVBQVUsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxTQUFTLENBQUM7SUFDdkcsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksZ0JBQWdCO1FBQ3JCLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQzlDLElBQUksYUFBcUIsQ0FBQztRQUUxQixJQUFJLElBQUksQ0FBQyxtQ0FBbUMsRUFBRSxDQUFDO1lBQzdDLE1BQU0sS0FBSyxHQUFhLGFBQWEsQ0FBQyxDQUFDLENBQWEsQ0FBQztZQUNyRCxNQUFNLE1BQU0sR0FBd0IsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQ2hFLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQzFGLENBQUM7WUFDRixhQUFhLEdBQUcsSUFBQSxpQkFBUyxFQUFDLHVCQUFlLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ25FLENBQUM7YUFBTSxDQUFDO1lBQ04seUhBQXlIO1lBQ3pILGFBQWEsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLHdCQUFXLENBQUMsWUFBWSxDQUFDLEdBQUcsYUFBYSxDQUFDLENBQUMsQ0FBQztRQUNsRixDQUFDO1FBQ0QsT0FBTyxhQUFhLENBQUM7SUFDdkIsQ0FBQztJQUVTLGdCQUFnQjtRQUN4QixJQUFJLGFBQWEsQ0FBQztRQUNsQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztRQUM3QyxJQUFJLElBQUksQ0FBQyxxQkFBcUIsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM3QyxhQUFhLEdBQUc7Z0JBQ2QsQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQztnQkFDeEQ7b0JBQ0UsTUFBTTtvQkFDTixJQUFJLGVBQUUsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUM7b0JBQ25ELElBQUksQ0FBQyxPQUFPO29CQUNaLElBQUksZUFBRSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEVBQUUsRUFBRSxDQUFDO29CQUM5RCxJQUFJLENBQUMsZUFBZTtvQkFDcEIsSUFBSSxDQUFDLFdBQVc7aUJBQ2pCO2FBQ0YsQ0FBQztRQUNKLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLG1DQUFtQztnQkFDeEQsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVO2dCQUNqQixDQUFDLENBQUMsSUFBSSxlQUFFLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDeEQsYUFBYSxHQUFHO2dCQUNkLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUM7Z0JBQ3REO29CQUNFLE1BQU07b0JBQ04sU0FBUztvQkFDVCxJQUFJLENBQUMsT0FBTztvQkFDWixNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsS0FBSyxDQUFDO29CQUMvRSxJQUFJLENBQUMsZUFBZTtvQkFDcEIsSUFBSSxDQUFDLFdBQVc7aUJBQ2pCO2FBQ0YsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLGFBQWEsQ0FBQztJQUN2QixDQUFDO0lBRU8sc0JBQXNCO1FBQzVCLElBQUksSUFBSSxDQUFDLGNBQWMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUM5QixPQUFPLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxRQUFRLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3BGLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLDJCQUEyQixFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyw0QkFBNEIsRUFBRSxDQUFDO0lBQy9HLENBQUM7SUFFRDs7OztPQUlHO0lBQ08sMkJBQTJCO1FBQ25DLE9BQVEsSUFBSSxDQUFDLEtBQUssRUFBRSxPQUEwQixFQUFFLHdCQUF3QixJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsUUFBUSxJQUFJLE9BQU8sQ0FBQztJQUNsSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLDRCQUE0QjtRQUNwQyxPQUFRLElBQUksQ0FBQyxLQUFLLEVBQUUsT0FBMEIsRUFBRSw2QkFBNkIsSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxPQUFPLENBQUM7SUFDakgsQ0FBQztJQUVEOzs7T0FHRztJQUNLLGlCQUFpQjtRQUN2QixNQUFNLFdBQVcsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQy9CLFdBQVcsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ2pELE9BQU8sV0FBVyxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQztJQUN0QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLFlBQVk7UUFDcEIsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDMUMsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFVBQVcsQ0FBQztJQUMxQixDQUFDO0lBRVMsY0FBYztRQUN0QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUNyQyxJQUFBLGdCQUFNLEVBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3RCLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkUsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLEVBQUUsRUFBRSxDQUFDO1lBQzVCLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBQ0QsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUNyQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUNuRSxTQUFTLENBQ1YsQ0FBQztRQUVGLG1DQUFtQztRQUNuQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDLGdCQUFnQixDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDeEUsTUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hFLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRXZFLGdFQUFnRTtRQUNoRSxPQUFPLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRU8sa0JBQWtCLENBQUMsSUFBWTtRQUNyQyxNQUFNLFlBQVksR0FBRyxJQUFBLDBCQUFrQixFQUFDLElBQUksRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFbkUsSUFBSSxDQUFDLFVBQVUsR0FBRyxZQUFZLENBQUMsRUFBRSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxPQUFPLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQztRQUNuQyxJQUFJLENBQUMsZUFBZSxHQUFHLFlBQVksQ0FBQyxVQUFVLENBQUM7UUFDL0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxZQUFZLENBQUMsVUFBVSxDQUFDO1FBQzNDLElBQUksQ0FBQyxVQUFVLEdBQUcsWUFBWSxDQUFDLFNBQVMsQ0FBQztRQUV6QyxJQUFJLFlBQVksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN0QixJQUFJLENBQUMsS0FBSyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUM7UUFDakMsQ0FBQztRQUVELElBQUksWUFBWSxDQUFDLG9CQUFvQixFQUFFLENBQUM7WUFDdEMsSUFBSSxDQUFDLHFCQUFxQixHQUFHLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQztRQUNqRSxDQUFDO0lBQ0gsQ0FBQztJQUVNLGdCQUFnQjtRQUNyQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMscUJBQXFCO1lBQ3ZDLENBQUMsQ0FBQyx3QkFBVyxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxtQ0FBc0IsQ0FBQztZQUNuRSxDQUFDLENBQUMsd0JBQVcsQ0FBQyxRQUFRLENBQUMsY0FBYyxFQUFFLDhCQUFpQixDQUFDLENBQUM7UUFDNUQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDOUMsTUFBTSx1QkFBdUIsR0FBRyx3QkFBVyxDQUFDLFNBQVMsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxDQUFDO1FBQ3hFLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQztZQUNuQixNQUFNO1lBQ04sdUJBQXVCO1lBQ3ZCLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsbUNBQW1DLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDaEUsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBOVRELDBDQThUQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcbmltcG9ydCAqIGFzIGV0aFV0aWwgZnJvbSAnZXRoZXJldW1qcy11dGlsJztcbmltcG9ydCBFdGhlcmV1bUFiaSBmcm9tICdldGhlcmV1bWpzLWFiaSc7XG5pbXBvcnQgQk4gZnJvbSAnYm4uanMnO1xuaW1wb3J0IHsgY29pbnMsIEJhc2VDb2luLCBDb250cmFjdEFkZHJlc3NEZWZpbmVkVG9rZW4sIEV0aGVyZXVtTmV0d29yayBhcyBFdGhMaWtlTmV0d29yayB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcbmltcG9ydCB7IEJ1aWxkVHJhbnNhY3Rpb25FcnJvciwgSW52YWxpZFBhcmFtZXRlclZhbHVlRXJyb3IgfSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgZGVjb2RlVHJhbnNmZXJEYXRhLCBzZW5kTXVsdGlTaWdEYXRhLCBzZW5kTXVsdGlTaWdUb2tlbkRhdGEsIGlzVmFsaWRFdGhBZGRyZXNzLCBpc1ZhbGlkQW1vdW50IH0gZnJvbSAnLi91dGlscyc7XG5pbXBvcnQgeyBkZWZhdWx0QWJpQ29kZXIsIGtlY2NhazI1NiB9IGZyb20gJ2V0aGVycy9saWIvdXRpbHMnO1xuaW1wb3J0IHsgc2VuZE11bHRpU2lnVG9rZW5UeXBlcywgc2VuZE11bHRpU2lnVHlwZXMgfSBmcm9tICcuL3dhbGxldFV0aWwnO1xuXG4vKiogRVRIIHRyYW5zZmVyIGJ1aWxkZXIgKi9cbmV4cG9ydCBjbGFzcyBUcmFuc2ZlckJ1aWxkZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IF9FTVBUWV9IRVhfVkFMVUUgPSAnMHgnO1xuICBwcm90ZWN0ZWQgX2Ftb3VudDogc3RyaW5nO1xuICBwcm90ZWN0ZWQgX3RvQWRkcmVzczogc3RyaW5nO1xuICBwcm90ZWN0ZWQgX3NlcXVlbmNlSWQ6IG51bWJlcjtcbiAgcHJvdGVjdGVkIF9zaWduS2V5OiBzdHJpbmcgfCBudWxsO1xuICBwcm90ZWN0ZWQgX2V4cGlyYXRpb25UaW1lOiBudW1iZXI7XG4gIHByb3RlY3RlZCBfc2lnbmF0dXJlOiBzdHJpbmc7XG4gIHByb3RlY3RlZCBfaXNGaXJzdFNpZ25lcjogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBfZGF0YTogc3RyaW5nO1xuICBwcml2YXRlIF90b2tlbkNvbnRyYWN0QWRkcmVzcz86IHN0cmluZztcbiAgcHJpdmF0ZSBfY29pbjogUmVhZG9ubHk8QmFzZUNvaW4+O1xuICBwcml2YXRlIF9jaGFpbklkPzogc3RyaW5nO1xuICBwcml2YXRlIF9jb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhPzogYm9vbGVhbjtcbiAgcHJpdmF0ZSBfd2FsbGV0VmVyc2lvbj86IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihzZXJpYWxpemVkRGF0YT86IHN0cmluZywgaXNGaXJzdFNpZ25lcj86IGJvb2xlYW4pIHtcbiAgICB0aGlzLl9pc0ZpcnN0U2lnbmVyID0gaXNGaXJzdFNpZ25lcjtcbiAgICBpZiAoc2VyaWFsaXplZERhdGEpIHtcbiAgICAgIHRoaXMuZGVjb2RlVHJhbnNmZXJEYXRhKHNlcmlhbGl6ZWREYXRhKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gaW5pdGlhbGl6ZSB3aXRoIGRlZmF1bHQgdmFsdWVzIGZvciBub24gbWFuZGF0b3J5IGZpZWxkc1xuICAgICAgdGhpcy5fZXhwaXJhdGlvblRpbWUgPSB0aGlzLmdldEV4cGlyYXRpb25UaW1lKCk7XG4gICAgICB0aGlzLl9kYXRhID0gdGhpcy5fRU1QVFlfSEVYX1ZBTFVFO1xuICAgICAgdGhpcy5fc2lnbmF0dXJlID0gdGhpcy5fRU1QVFlfSEVYX1ZBTFVFO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBIG1ldGhvZCB0byBzZXQgdGhlIG5hdGl2ZSBjb2luIG9yIEVSQzIwIHRva2VuIHRvIGJlIHRyYW5zZmVycmVkLlxuICAgKiBUaGlzIEVSQzIwIHRva2VuIG1heSBub3QgYmUgY29tcGF0aWJsZSB3aXRoIHRoZSBuZXR3b3JrLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29pbiAtIHRoZSBuYXRpdmUgY29pbiBvciBFUkMyMCB0b2tlbiB0byBiZSBzZXRcbiAgICogQHJldHVybnMge1RyYW5zZmVyQnVpbGRlcn0gdGhlIHRyYW5zZmVyIGJ1aWxkZXIgaW5zdGFuY2UgbW9kaWZpZWRcbiAgICovXG4gIGNvaW4oY29pbjogc3RyaW5nKTogVHJhbnNmZXJCdWlsZGVyIHtcbiAgICB0aGlzLl9jb2luID0gY29pbnMuZ2V0KGNvaW4pO1xuICAgIGlmICh0aGlzLl9jb2luIGluc3RhbmNlb2YgQ29udHJhY3RBZGRyZXNzRGVmaW5lZFRva2VuKSB7XG4gICAgICB0aGlzLl90b2tlbkNvbnRyYWN0QWRkcmVzcyA9IHRoaXMuX2NvaW4uY29udHJhY3RBZGRyZXNzLnRvU3RyaW5nKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRJc0ZpcnN0U2lnbmVyKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9pc0ZpcnN0U2lnbmVyID8gdGhpcy5faXNGaXJzdFNpZ25lciA6IGZhbHNlO1xuICB9XG5cbiAgd2FsbGV0VmVyc2lvbih2ZXJzaW9uOiBudW1iZXIpOiBUcmFuc2ZlckJ1aWxkZXIge1xuICAgIHRoaXMuX3dhbGxldFZlcnNpb24gPSB2ZXJzaW9uO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZGF0YShhZGRpdGlvbmFsRGF0YTogc3RyaW5nKTogVHJhbnNmZXJCdWlsZGVyIHtcbiAgICB0aGlzLl9zaWduYXR1cmUgPSB0aGlzLl9FTVBUWV9IRVhfVkFMVUU7XG4gICAgdGhpcy5fZGF0YSA9IGFkZGl0aW9uYWxEYXRhO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgYW1vdW50KGFtb3VudDogc3RyaW5nKTogdGhpcyB7XG4gICAgaWYgKCFpc1ZhbGlkQW1vdW50KGFtb3VudCkpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkUGFyYW1ldGVyVmFsdWVFcnJvcignSW52YWxpZCBhbW91bnQnKTtcbiAgICB9XG4gICAgdGhpcy5fc2lnbmF0dXJlID0gdGhpcy5fRU1QVFlfSEVYX1ZBTFVFO1xuICAgIHRoaXMuX2Ftb3VudCA9IGFtb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHRvKGFkZHJlc3M6IHN0cmluZyk6IFRyYW5zZmVyQnVpbGRlciB7XG4gICAgaWYgKGlzVmFsaWRFdGhBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICB0aGlzLl9zaWduYXR1cmUgPSB0aGlzLl9FTVBUWV9IRVhfVkFMVUU7XG4gICAgICB0aGlzLl90b0FkZHJlc3MgPSBhZGRyZXNzO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHRocm93IG5ldyBJbnZhbGlkUGFyYW1ldGVyVmFsdWVFcnJvcignSW52YWxpZCBhZGRyZXNzJyk7XG4gIH1cblxuICBjb250cmFjdFNlcXVlbmNlSWQoY291bnRlcjogbnVtYmVyKTogVHJhbnNmZXJCdWlsZGVyIHtcbiAgICBpZiAoY291bnRlciA+PSAwKSB7XG4gICAgICB0aGlzLl9zaWduYXR1cmUgPSB0aGlzLl9FTVBUWV9IRVhfVkFMVUU7XG4gICAgICB0aGlzLl9zZXF1ZW5jZUlkID0gY291bnRlcjtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgSW52YWxpZFBhcmFtZXRlclZhbHVlRXJyb3IoJ0ludmFsaWQgY29udHJhY3Qgc2VxdWVuY2UgaWQnKTtcbiAgfVxuXG4gIGtleShzaWduS2V5OiBzdHJpbmcpOiBUcmFuc2ZlckJ1aWxkZXIge1xuICAgIHRoaXMuX3NpZ25LZXkgPSBzaWduS2V5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZXhwaXJhdGlvblRpbWUoZGF0ZTogbnVtYmVyKTogVHJhbnNmZXJCdWlsZGVyIHtcbiAgICBpZiAoZGF0ZSA+IDApIHtcbiAgICAgIHRoaXMuX3NpZ25hdHVyZSA9IHRoaXMuX0VNUFRZX0hFWF9WQUxVRTtcbiAgICAgIHRoaXMuX2V4cGlyYXRpb25UaW1lID0gZGF0ZTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgSW52YWxpZFBhcmFtZXRlclZhbHVlRXJyb3IoJ0ludmFsaWQgZXhwaXJhdGlvbiB0aW1lJyk7XG4gIH1cblxuICBpc0ZpcnN0U2lnbmVyKGlzRmlyc3RTaWduZXI6IGJvb2xlYW4pOiBUcmFuc2ZlckJ1aWxkZXIge1xuICAgIHRoaXMuX2lzRmlyc3RTaWduZXIgPSBpc0ZpcnN0U2lnbmVyO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdG9rZW5Db250cmFjdEFkZHJlc3ModG9rZW5Db250cmFjdEFkZHJlc3M6IHN0cmluZyk6IFRyYW5zZmVyQnVpbGRlciB7XG4gICAgdGhpcy5fdG9rZW5Db250cmFjdEFkZHJlc3MgPSB0b2tlbkNvbnRyYWN0QWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldENvaW5Vc2VzTm9uUGFja2VkRW5jb2RpbmdGb3JUeERhdGEoaXNDb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhOiBib29sZWFuKTogVHJhbnNmZXJCdWlsZGVyIHtcbiAgICB0aGlzLl9jb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhID0gaXNDb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0U2lnbmF0dXJlKHNpZ25hdHVyZTogc3RyaW5nKTogVHJhbnNmZXJCdWlsZGVyIHtcbiAgICB0aGlzLl9zaWduS2V5ID0gbnVsbDtcbiAgICB0aGlzLl9zaWduYXR1cmUgPSBzaWduYXR1cmU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzaWduQW5kQnVpbGQoY2hhaW5JZDogc3RyaW5nLCBjb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhPzogYm9vbGVhbik6IHN0cmluZyB7XG4gICAgdGhpcy5fY2hhaW5JZCA9IGNoYWluSWQ7XG5cbiAgICAvLyBJZiB0aGUgY29pbiB1c2VzIG5vbi1wYWNrZWQgZW5jb2RpbmcgZm9yIHR4IGRhdGEsIHRoZSBvcGVyYXRpb24gaGFzaCBpcyBjYWxjdWxhdGVkIGRpZmZlcmVudGx5XG4gICAgLy8gVGhpcyBuZXcgZW5jb2RpbmcgdHlwZSBpcyBhcHBsaWNhYmxlIG9ubHkgZm9yIG5hdGl2ZSBjb2lucyBhbmQgbm90IHRva2Vuc1xuICAgIHRoaXMuX2NvaW5Vc2VzTm9uUGFja2VkRW5jb2RpbmdGb3JUeERhdGEgPVxuICAgICAgY29pblVzZXNOb25QYWNrZWRFbmNvZGluZ0ZvclR4RGF0YSAmJiB0aGlzLl90b2tlbkNvbnRyYWN0QWRkcmVzcyA9PT0gdW5kZWZpbmVkO1xuICAgIGlmICh0aGlzLmhhc01hbmRhdG9yeUZpZWxkcygpKSB7XG4gICAgICBpZiAodGhpcy5faXNGaXJzdFNpZ25lcikge1xuICAgICAgICAvLyBGaXJzdCBzaWduZXIgc2lnbnMgZGlmZmVyZW50IGRhdGEgdGhhbiB0aGUgc2Vjb25kIHNpZ25lciBpbiBtdWx0aXNpZyBldm0gY29udHJhY3RzLlxuICAgICAgICByZXR1cm4gZXRoVXRpbC5hZGRIZXhQcmVmaXgodGhpcy5nZXRTaWduYXR1cmVEYXRhKCkudG9TdHJpbmcoJ2hleCcpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh0aGlzLl90b2tlbkNvbnRyYWN0QWRkcmVzcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgcmV0dXJuIHNlbmRNdWx0aVNpZ1Rva2VuRGF0YShcbiAgICAgICAgICAgIHRoaXMuX3RvQWRkcmVzcyxcbiAgICAgICAgICAgIHRoaXMuX2Ftb3VudCxcbiAgICAgICAgICAgIHRoaXMuX3Rva2VuQ29udHJhY3RBZGRyZXNzLFxuICAgICAgICAgICAgdGhpcy5fZXhwaXJhdGlvblRpbWUsXG4gICAgICAgICAgICB0aGlzLl9zZXF1ZW5jZUlkLFxuICAgICAgICAgICAgdGhpcy5nZXRTaWduYXR1cmUoKVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIHNlbmRNdWx0aVNpZ0RhdGEoXG4gICAgICAgICAgICB0aGlzLl90b0FkZHJlc3MsXG4gICAgICAgICAgICB0aGlzLl9hbW91bnQsXG4gICAgICAgICAgICB0aGlzLl9kYXRhLFxuICAgICAgICAgICAgdGhpcy5fZXhwaXJhdGlvblRpbWUsXG4gICAgICAgICAgICB0aGlzLl9zZXF1ZW5jZUlkLFxuICAgICAgICAgICAgdGhpcy5nZXRTaWduYXR1cmUoKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEJ1aWxkVHJhbnNhY3Rpb25FcnJvcihcbiAgICAgICdNaXNzaW5nIHRyYW5zZmVyIG1hbmRhdG9yeSBmaWVsZHMuIEFtb3VudCwgZGVzdGluYXRpb24gKHRvKSBhZGRyZXNzIGFuZCBzZXF1ZW5jZUlEIGFyZSBtYW5kYXRvcnknXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgaGFzTWFuZGF0b3J5RmllbGRzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9hbW91bnQgIT09IHVuZGVmaW5lZCAmJiB0aGlzLl90b0FkZHJlc3MgIT09IHVuZGVmaW5lZCAmJiB0aGlzLl9zZXF1ZW5jZUlkICE9PSB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogT2J0YWlucyB0aGUgcHJvcGVyIG9wZXJhdGlvbiBoYXNoIHRvIHNpZ24gZWl0aGVyIGEgc2VuZE11bHRpU2lnIGRhdGFcbiAgICogb3IgYSBzZW5kTXVsdGlTaWdUb2tlbiBkYXRhXG4gICAqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IHRoZSBvcGVyYXRpb24gaGFzaFxuICAgKi9cbiAgcHVibGljIGdldE9wZXJhdGlvbkhhc2goKTogc3RyaW5nIHtcbiAgICBjb25zdCBvcGVyYXRpb25EYXRhID0gdGhpcy5nZXRPcGVyYXRpb25EYXRhKCk7XG4gICAgbGV0IG9wZXJhdGlvbkhhc2g6IHN0cmluZztcblxuICAgIGlmICh0aGlzLl9jb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhKSB7XG4gICAgICBjb25zdCB0eXBlczogc3RyaW5nW10gPSBvcGVyYXRpb25EYXRhWzBdIGFzIHN0cmluZ1tdO1xuICAgICAgY29uc3QgdmFsdWVzOiAoc3RyaW5nIHwgbnVtYmVyKVtdID0gb3BlcmF0aW9uRGF0YVsxXS5tYXAoKGl0ZW0pID0+XG4gICAgICAgIHR5cGVvZiBpdGVtID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgaXRlbSA9PT0gJ251bWJlcicgPyBpdGVtIDogJzB4JyArIGl0ZW0udG9TdHJpbmcoJ2hleCcpXG4gICAgICApO1xuICAgICAgb3BlcmF0aW9uSGFzaCA9IGtlY2NhazI1NihkZWZhdWx0QWJpQ29kZXIuZW5jb2RlKHR5cGVzLCB2YWx1ZXMpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSWYgdGhlIGNvaW4gdXNlcyBwYWNrZWQgZW5jb2RpbmcgZm9yIHR4IGRhdGEgb3IgaXQgaXMgYSB0b2tlbiwgdGhlIG9wZXJhdGlvbiBoYXNoIGlzIGNhbGN1bGF0ZWQgdXNpbmcgdGhlIEV0aGVyZXVtIEFCSVxuICAgICAgb3BlcmF0aW9uSGFzaCA9IGV0aFV0aWwuYnVmZmVyVG9IZXgoRXRoZXJldW1BYmkuc29saWRpdHlTSEEzKC4uLm9wZXJhdGlvbkRhdGEpKTtcbiAgICB9XG4gICAgcmV0dXJuIG9wZXJhdGlvbkhhc2g7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0T3BlcmF0aW9uRGF0YSgpOiAoc3RyaW5nIHwgbnVtYmVyIHwgQnVmZmVyKVtdW10ge1xuICAgIGxldCBvcGVyYXRpb25EYXRhO1xuICAgIGNvbnN0IHByZWZpeCA9IHRoaXMuZ2V0T3BlcmF0aW9uSGFzaFByZWZpeCgpO1xuICAgIGlmICh0aGlzLl90b2tlbkNvbnRyYWN0QWRkcmVzcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBvcGVyYXRpb25EYXRhID0gW1xuICAgICAgICBbJ3N0cmluZycsICdhZGRyZXNzJywgJ3VpbnQnLCAnYWRkcmVzcycsICd1aW50JywgJ3VpbnQnXSxcbiAgICAgICAgW1xuICAgICAgICAgIHByZWZpeCxcbiAgICAgICAgICBuZXcgQk4oZXRoVXRpbC5zdHJpcEhleFByZWZpeCh0aGlzLl90b0FkZHJlc3MpLCAxNiksXG4gICAgICAgICAgdGhpcy5fYW1vdW50LFxuICAgICAgICAgIG5ldyBCTihldGhVdGlsLnN0cmlwSGV4UHJlZml4KHRoaXMuX3Rva2VuQ29udHJhY3RBZGRyZXNzKSwgMTYpLFxuICAgICAgICAgIHRoaXMuX2V4cGlyYXRpb25UaW1lLFxuICAgICAgICAgIHRoaXMuX3NlcXVlbmNlSWQsXG4gICAgICAgIF0sXG4gICAgICBdO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCB0b0FkZHJlc3MgPSB0aGlzLl9jb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhXG4gICAgICAgID8gdGhpcy5fdG9BZGRyZXNzXG4gICAgICAgIDogbmV3IEJOKGV0aFV0aWwuc3RyaXBIZXhQcmVmaXgodGhpcy5fdG9BZGRyZXNzKSwgMTYpO1xuICAgICAgb3BlcmF0aW9uRGF0YSA9IFtcbiAgICAgICAgWydzdHJpbmcnLCAnYWRkcmVzcycsICd1aW50JywgJ2J5dGVzJywgJ3VpbnQnLCAndWludCddLFxuICAgICAgICBbXG4gICAgICAgICAgcHJlZml4LFxuICAgICAgICAgIHRvQWRkcmVzcyxcbiAgICAgICAgICB0aGlzLl9hbW91bnQsXG4gICAgICAgICAgQnVmZmVyLmZyb20oZXRoVXRpbC5wYWRUb0V2ZW4oZXRoVXRpbC5zdHJpcEhleFByZWZpeCh0aGlzLl9kYXRhKSkgfHwgJycsICdoZXgnKSxcbiAgICAgICAgICB0aGlzLl9leHBpcmF0aW9uVGltZSxcbiAgICAgICAgICB0aGlzLl9zZXF1ZW5jZUlkLFxuICAgICAgICBdLFxuICAgICAgXTtcbiAgICB9XG4gICAgcmV0dXJuIG9wZXJhdGlvbkRhdGE7XG4gIH1cblxuICBwcml2YXRlIGdldE9wZXJhdGlvbkhhc2hQcmVmaXgoKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5fd2FsbGV0VmVyc2lvbiA9PT0gNCkge1xuICAgICAgcmV0dXJuIHRoaXMuX3Rva2VuQ29udHJhY3RBZGRyZXNzID8gYCR7dGhpcy5fY2hhaW5JZH0tRVJDMjBgIDogYCR7dGhpcy5fY2hhaW5JZH1gO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fdG9rZW5Db250cmFjdEFkZHJlc3MgPyB0aGlzLmdldFRva2VuT3BlcmF0aW9uSGFzaFByZWZpeCgpIDogdGhpcy5nZXROYXRpdmVPcGVyYXRpb25IYXNoUHJlZml4KCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBwcmVmaXggdXNlZCBpbiBnZW5lcmF0aW5nIGFuIG9wZXJhdGlvbiBoYXNoIGZvciBzZW5kaW5nIHRva2Vuc1xuICAgKlxuICAgKiBAcmV0dXJucyB0aGUgc3RyaW5nIHByZWZpeFxuICAgKi9cbiAgcHJvdGVjdGVkIGdldFRva2VuT3BlcmF0aW9uSGFzaFByZWZpeCgpOiBzdHJpbmcge1xuICAgIHJldHVybiAodGhpcy5fY29pbj8ubmV0d29yayBhcyBFdGhMaWtlTmV0d29yayk/LnRva2VuT3BlcmF0aW9uSGFzaFByZWZpeCA/PyBgJHt0aGlzLl9jaGFpbklkfS1FUkMyMGAgPz8gJ0VSQzIwJztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHByZWZpeCB1c2VkIGluIGdlbmVyYXRpbmcgYW4gb3BlcmF0aW9uIGhhc2ggZm9yIHNlbmRpbmcgbmF0aXZlIGNvaW5zXG4gICAqXG4gICAqIEByZXR1cm5zIHRoZSBzdHJpbmcgcHJlZml4XG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0TmF0aXZlT3BlcmF0aW9uSGFzaFByZWZpeCgpOiBzdHJpbmcge1xuICAgIHJldHVybiAodGhpcy5fY29pbj8ubmV0d29yayBhcyBFdGhMaWtlTmV0d29yayk/Lm5hdGl2ZUNvaW5PcGVyYXRpb25IYXNoUHJlZml4ID8/IGAke3RoaXMuX2NoYWluSWR9YCA/PyAnRVRIRVInO1xuICB9XG5cbiAgLyoqIFJldHVybiBhbiBleHBpcmF0aW9uIHRpbWUsIGluIHNlY29uZHMsIHNldCB0byBvbmUgaG91ciBmcm9tIG5vd1xuICAgKlxuICAgKiBAcmV0dXJucyB7bnVtYmVyfSBleHBpcmF0aW9uIHRpbWVcbiAgICovXG4gIHByaXZhdGUgZ2V0RXhwaXJhdGlvblRpbWUoKTogbnVtYmVyIHtcbiAgICBjb25zdCBjdXJyZW50RGF0ZSA9IG5ldyBEYXRlKCk7XG4gICAgY3VycmVudERhdGUuc2V0SG91cnMoY3VycmVudERhdGUuZ2V0SG91cnMoKSArIDEpO1xuICAgIHJldHVybiBjdXJyZW50RGF0ZS5nZXRUaW1lKCkgLyAxMDAwO1xuICB9XG5cbiAgLyoqXG4gICAqIElmIGEgc2lnbmluZyBrZXkgaXMgc2V0IGZvciB0aGlzIGJ1aWxkZXIsIHJlY2FsY3VsYXRlcyB0aGUgc2lnbmF0dXJlXG4gICAqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IHRoZSBzaWduYXR1cmUgdmFsdWVcbiAgICovXG4gIHByb3RlY3RlZCBnZXRTaWduYXR1cmUoKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5fc2lnbktleSkge1xuICAgICAgdGhpcy5fc2lnbmF0dXJlID0gdGhpcy5ldGhTaWduTXNnSGFzaCgpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fc2lnbmF0dXJlITtcbiAgfVxuXG4gIHByb3RlY3RlZCBldGhTaWduTXNnSGFzaCgpOiBzdHJpbmcge1xuICAgIGNvbnN0IGRhdGEgPSB0aGlzLmdldE9wZXJhdGlvbkhhc2goKTtcbiAgICBhc3NlcnQodGhpcy5fc2lnbktleSk7XG4gICAgY29uc3Qga2V5QnVmZmVyID0gQnVmZmVyLmZyb20oZXRoVXRpbC5wYWRUb0V2ZW4odGhpcy5fc2lnbktleSksICdoZXgnKTtcbiAgICBpZiAoa2V5QnVmZmVyLmxlbmd0aCAhPT0gMzIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigncHJpdmF0ZSBrZXkgbGVuZ3RoIGlzIGludmFsaWQnKTtcbiAgICB9XG4gICAgY29uc3Qgc2lnbmF0dXJlSW5QYXJ0cyA9IGV0aFV0aWwuZWNzaWduKFxuICAgICAgQnVmZmVyLmZyb20oZXRoVXRpbC5wYWRUb0V2ZW4oZXRoVXRpbC5zdHJpcEhleFByZWZpeChkYXRhKSksICdoZXgnKSxcbiAgICAgIGtleUJ1ZmZlclxuICAgICk7XG5cbiAgICAvLyBBc3NlbWJsZSBzdHJpbmdzIGZyb20gciwgcyBhbmQgdlxuICAgIGNvbnN0IHIgPSBldGhVdGlsLnNldExlbmd0aExlZnQoc2lnbmF0dXJlSW5QYXJ0cy5yLCAzMikudG9TdHJpbmcoJ2hleCcpO1xuICAgIGNvbnN0IHMgPSBldGhVdGlsLnNldExlbmd0aExlZnQoc2lnbmF0dXJlSW5QYXJ0cy5zLCAzMikudG9TdHJpbmcoJ2hleCcpO1xuICAgIGNvbnN0IHYgPSBldGhVdGlsLnN0cmlwSGV4UHJlZml4KGV0aFV0aWwuaW50VG9IZXgoc2lnbmF0dXJlSW5QYXJ0cy52KSk7XG5cbiAgICAvLyBDb25jYXRlbmF0ZSB0aGUgciwgcyBhbmQgdiBwYXJ0cyB0byBtYWtlIHRoZSBzaWduYXR1cmUgc3RyaW5nXG4gICAgcmV0dXJuIGV0aFV0aWwuYWRkSGV4UHJlZml4KHIuY29uY2F0KHMsIHYpKTtcbiAgfVxuXG4gIHByaXZhdGUgZGVjb2RlVHJhbnNmZXJEYXRhKGRhdGE6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IHRyYW5zZmVyRGF0YSA9IGRlY29kZVRyYW5zZmVyRGF0YShkYXRhLCB0aGlzLl9pc0ZpcnN0U2lnbmVyKTtcblxuICAgIHRoaXMuX3RvQWRkcmVzcyA9IHRyYW5zZmVyRGF0YS50bztcbiAgICB0aGlzLl9hbW91bnQgPSB0cmFuc2ZlckRhdGEuYW1vdW50O1xuICAgIHRoaXMuX2V4cGlyYXRpb25UaW1lID0gdHJhbnNmZXJEYXRhLmV4cGlyZVRpbWU7XG4gICAgdGhpcy5fc2VxdWVuY2VJZCA9IHRyYW5zZmVyRGF0YS5zZXF1ZW5jZUlkO1xuICAgIHRoaXMuX3NpZ25hdHVyZSA9IHRyYW5zZmVyRGF0YS5zaWduYXR1cmU7XG5cbiAgICBpZiAodHJhbnNmZXJEYXRhLmRhdGEpIHtcbiAgICAgIHRoaXMuX2RhdGEgPSB0cmFuc2ZlckRhdGEuZGF0YTtcbiAgICB9XG5cbiAgICBpZiAodHJhbnNmZXJEYXRhLnRva2VuQ29udHJhY3RBZGRyZXNzKSB7XG4gICAgICB0aGlzLl90b2tlbkNvbnRyYWN0QWRkcmVzcyA9IHRyYW5zZmVyRGF0YS50b2tlbkNvbnRyYWN0QWRkcmVzcztcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgZ2V0U2lnbmF0dXJlRGF0YSgpOiBCdWZmZXI8QXJyYXlCdWZmZXI+IHtcbiAgICBjb25zdCBtZXRob2QgPSB0aGlzLl90b2tlbkNvbnRyYWN0QWRkcmVzc1xuICAgICAgPyBFdGhlcmV1bUFiaS5tZXRob2RJRCgnc2VuZE11bHRpU2lnVG9rZW4nLCBzZW5kTXVsdGlTaWdUb2tlblR5cGVzKVxuICAgICAgOiBFdGhlcmV1bUFiaS5tZXRob2RJRCgnc2VuZE11bHRpU2lnJywgc2VuZE11bHRpU2lnVHlwZXMpO1xuICAgIGNvbnN0IG9wZXJhdGlvbkRhdGEgPSB0aGlzLmdldE9wZXJhdGlvbkRhdGEoKTtcbiAgICBjb25zdCByYXdFbmNvZGVkT3BlcmF0aW9uRGF0YSA9IEV0aGVyZXVtQWJpLnJhd0VuY29kZSguLi5vcGVyYXRpb25EYXRhKTtcbiAgICByZXR1cm4gQnVmZmVyLmNvbmNhdChbXG4gICAgICBtZXRob2QsXG4gICAgICByYXdFbmNvZGVkT3BlcmF0aW9uRGF0YSxcbiAgICAgIEJ1ZmZlci5mcm9tKFt0aGlzLl9jb2luVXNlc05vblBhY2tlZEVuY29kaW5nRm9yVHhEYXRhID8gMSA6IDBdKSxcbiAgICBdKTtcbiAgfVxufVxuIl19Выполнить команду
Для локальной разработки. Не используйте в интернете!