PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-xlm/dist/src
Просмотр файла: xlm.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.Xlm = void 0;
const assert_1 = __importDefault(require("assert"));
const _ = __importStar(require("lodash"));
const querystring = __importStar(require("querystring"));
const url = __importStar(require("url"));
const request = __importStar(require("superagent"));
const stellar = __importStar(require("stellar-sdk"));
const bignumber_js_1 = require("bignumber.js");
const Utils = __importStar(require("./lib/utils"));
const keyPair_1 = require("./lib/keyPair");
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_api_1 = require("@bitgo/sdk-api");
const getStellarKeys_1 = require("./getStellarKeys");
class Xlm extends sdk_core_1.BaseCoin {
constructor(bitgo) {
super(bitgo);
this.homeDomain = 'bitgo.com'; // used for reverse federation lookup
}
static createInstance(bitgo) {
return new Xlm(bitgo);
}
getStellarNetwork() {
return stellar.Networks.PUBLIC;
}
/**
* Factor between the base unit and its smallest subdivison
*/
getBaseFactor() {
return 1e7;
}
/**
* Identifier for the blockchain which supports this coin
*/
getChain() {
return 'xlm';
}
/**
* Identifier for the coin family
*/
getFamily() {
return 'xlm';
}
/**
* Complete human-readable name of this coin
*/
getFullName() {
return 'Stellar';
}
/**
* Url at which the stellar federation server can be reached
*/
getFederationServerUrl() {
return sdk_core_1.common.Environments[this.bitgo.getEnv()].stellarFederationServerUrl;
}
/**
* Url at which horizon can be reached
*/
getHorizonUrl() {
return 'https://horizon.stellar.org';
}
/** inheritdoc */
generateKeyPair(seed) {
const keyPair = seed ? new keyPair_1.KeyPair({ seed }) : new keyPair_1.KeyPair();
const keys = keyPair.getKeys();
if (!keys.prv) {
throw new Error('Missing prv in key generation.');
}
return { pub: keys.pub, prv: keys.prv };
}
generateRootKeyPair(seed) {
const keyPair = seed ? new keyPair_1.KeyPair({ seed }) : new keyPair_1.KeyPair();
const keys = keyPair.getKeys(true);
if (!keys.prv) {
throw new Error('Missing prv in key generation.');
}
return { prv: keys.prv + keys.pub, pub: keys.pub };
}
/**
* Get encoded ed25519 public key from raw data
*
* @param pub Raw public key
* @returns Encoded public key
*/
getPubFromRaw(pub) {
return Utils.encodePublicKey(Buffer.from(pub, 'hex'));
}
/**
* Get encoded ed25519 private key from raw data
*
* @param prv Raw private key
* @returns Encoded private key
*/
getPrvFromRaw(prv) {
return Utils.encodePrivateKey(Buffer.from(prv, 'hex'));
}
/**
* Return boolean indicating whether input is valid public key for the coin.
*
* @param pub the pub to be checked
* @returns is it valid?
*/
isValidPub(pub) {
// Stellar's validation method only allows keys in Stellar-specific format, with a 'G' prefix
// We need to allow for both Stellar and raw root keys
return Utils.isValidRootPublicKey(pub) || Utils.isValidStellarPublicKey(pub);
}
/**
* Return boolean indicating whether input is valid private key for the coin
*
* @param prv the prv to be checked
* @returns is it valid?
*/
isValidPrv(prv) {
// Stellar's validation method only allows keys in Stellar-specific format, with an 'S' prefix
// We need to allow for both Stellar and raw root private keys
return Utils.isValidRootPrivateKey(prv) || Utils.isValidStellarPrivateKey(prv);
}
/**
* Return boolean indicating whether a memo id is valid
*
* @param memoId memo id
* @returns true if memo id is valid
*/
isValidMemoId(memoId) {
let memoIdNumber;
try {
stellar.Memo.id(memoId); // throws if the value is not valid memo id
memoIdNumber = new bignumber_js_1.BigNumber(memoId);
}
catch (e) {
return false;
}
return memoIdNumber.gte(0) && memoIdNumber.lt(Xlm.maxMemoId);
}
supportsDeriveKeyWithSeed() {
return false;
}
/** {@inheritDoc } **/
supportsMultisig() {
return true;
}
/** inherited doc */
getDefaultMultisigType() {
return sdk_core_1.multisigTypes.onchain;
}
/**
* Evaluates whether a memo is valid
*
* @param value value of the memo
* @param type type of the memo
* @returns true if value and type are a valid
*/
isValidMemo({ value, type }) {
if (!value || !type) {
return false;
}
try {
// throws if the value is not valid for the type
// valid types are: 'id', 'text', 'hash', 'return'
// See https://www.stellar.org/developers/guides/concepts/transactions.html#memo
stellar.Memo[type](value);
}
catch (e) {
return false;
}
return true;
}
/**
* Create instance of stellar.MuxedAccount from M address
* See: https://developers.stellar.org/docs/glossary/muxed-accounts
*/
getMuxedAccount(address) {
try {
return stellar.MuxedAccount.fromAddress(address, '0');
}
catch (e) {
throw new Error(`invalid muxed address: ${address}`);
}
}
/**
* Return boolean indicating whether a muxed address is valid
* See: https://developers.stellar.org/docs/glossary/muxed-accounts
*
* @param address
* @returns {boolean}
*/
isValidMuxedAddress(address) {
if (!_.isString(address) || !address.startsWith('M')) {
return false;
}
try {
// return true if muxed account is valid or throw
return !!stellar.MuxedAccount.fromAddress(address, '0');
}
catch (e) {
return false;
}
}
/**
* Minimum balance of a 2-of-3 multisig wallet
* @returns minimum balance in stroops
*/
async getMinimumReserve() {
const server = new stellar.Server(this.getHorizonUrl());
const horizonLedgerInfo = await server.ledgers().order('desc').limit(1).call();
if (!horizonLedgerInfo) {
throw new Error('unable to connect to Horizon for reserve requirement data');
}
const baseReserve = horizonLedgerInfo.records[0].base_reserve_in_stroops;
// 2-of-3 wallets have a minimum reserve of 5x the base reserve
return 5 * baseReserve;
}
/**
* Transaction fee for each operation
* @returns transaction fee in stroops
*/
async getBaseTransactionFee() {
const server = new stellar.Server(this.getHorizonUrl());
const horizonLedgerInfo = await server.ledgers().order('desc').limit(1).call();
if (!horizonLedgerInfo) {
throw new Error('unable to connect to Horizon for reserve requirement data');
}
return horizonLedgerInfo.records[0].base_fee_in_stroops;
}
/**
* Process address into address and memo id
*
* @param address the address
* @returns object containing address and memo id
*/
getAddressDetails(address) {
if (address.startsWith('M')) {
if (this.isValidMuxedAddress(address)) {
const muxedAccount = this.getMuxedAccount(address);
return {
baseAddress: muxedAccount.baseAccount().accountId(),
address,
id: muxedAccount.id(),
memoId: undefined,
};
}
else {
throw new sdk_core_1.InvalidAddressError(`invalid muxed address: ${address}`);
}
}
const destinationDetails = url.parse(address);
const destinationAddress = destinationDetails.pathname || '';
if (!destinationAddress || !stellar.StrKey.isValidEd25519PublicKey(destinationAddress)) {
throw new Error(`invalid address: ${address}`);
}
// address doesn't have a memo id
if (destinationDetails.pathname === address) {
return {
baseAddress: address,
address: address,
id: undefined,
memoId: undefined,
};
}
if (!destinationDetails.query) {
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
}
const queryDetails = querystring.parse(destinationDetails.query);
if (!queryDetails.memoId) {
// if there are more properties, the query details need to contain the memo id property
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
}
if (Array.isArray(queryDetails.memoId)) {
throw new sdk_core_1.InvalidAddressError(`memoId may only be given at most once, but found ${queryDetails.memoId.length} instances in address ${address}`);
}
if (Array.isArray(queryDetails.memoId) && queryDetails.memoId.length !== 1) {
// valid addresses can only contain one memo id
throw new sdk_core_1.InvalidAddressError(`invalid address '${address}', must contain exactly one memoId`);
}
const [memoId] = _.castArray(queryDetails.memoId) || undefined;
if (!this.isValidMemoId(memoId)) {
throw new sdk_core_1.InvalidMemoIdError(`invalid address: '${address}', memoId is not valid`);
}
return {
baseAddress: destinationAddress,
address: destinationAddress,
id: undefined,
memoId,
};
}
/**
* Validate and return address with appended memo id or muxed address
*
* @param address address
* @param memoId memo id
* @returns address with memo id
*/
normalizeAddress({ address, memoId }) {
if (this.isValidMuxedAddress(address)) {
return address;
}
if (!stellar.StrKey.isValidEd25519PublicKey(address)) {
throw new Error(`invalid address details: ${address}`);
}
if (memoId && this.isValidMemoId(memoId)) {
return `${address}?memoId=${memoId}`;
}
return address;
}
/**
* Return boolean indicating whether input is valid public key for the coin
*
* @param address the pub to be checked
* @returns is it valid?
*/
isValidAddress(address) {
try {
const addressDetails = this.getAddressDetails(address);
return address === this.normalizeAddress(addressDetails);
}
catch (e) {
return false;
}
}
/**
* Return a Stellar Asset in coin:token form (i.e. (t)xlm:<code>-<issuer>)
* If the asset is XLM, return the chain
* @param {stellar.Asset} asset - instance of Stellar Asset
*/
getTokenNameFromStellarAsset(asset) {
const code = asset.getCode();
const issuer = asset.getIssuer();
if (asset.isNative()) {
return this.getChain();
}
return `${this.getChain()}${sdk_core_1.BaseCoin.coinTokenPatternSeparator}${code}${Xlm.tokenPatternSeparator}${issuer}`;
}
/**
* Evaluate whether a stellar username has valid format
* This method is used by the client when a stellar address is being added to a wallet
* Example of a common stellar username: foo@bar.baz
* The above example would result in the Stellar address: foo@bar.baz*bitgo.com
*
* @param username - stellar username
* @return true if stellar username is valid
*/
isValidStellarUsername(username) {
return /^[a-z0-9\-_.+@]+$/.test(username);
}
/**
* Get an instance of FederationServer for BitGo lookups
*
* @returns instance of BitGo Federation Server
*/
getBitGoFederationServer() {
// Identify the URI scheme in case we need to allow connecting to HTTP server.
const isNonSecureEnv = !_.startsWith(sdk_core_1.common.Environments[this.bitgo.env].uri, 'https');
const federationServerOptions = { allowHttp: isNonSecureEnv };
return new stellar.FederationServer(this.getFederationServerUrl(), 'bitgo.com', federationServerOptions);
}
/**
* Perform federation lookups
* Our federation server handles lookups for bitgo as well as for other federation domains
*
* @param {String} [address] - address to look up
* @param {String} [accountId] - account id to look up
*/
async federationLookup({ address, accountId, }) {
try {
const federationServer = this.getBitGoFederationServer();
if (address) {
return await federationServer.resolveAddress(address);
}
else if (accountId) {
return await federationServer.resolveAccountId(accountId);
}
else {
throw new Error('invalid argument - must provide Stellar address or account id');
}
}
catch (e) {
const error = _.get(e, 'response.data.detail');
if (error) {
throw new sdk_core_1.StellarFederationUserNotFoundError(error);
}
else {
throw e;
}
}
}
/**
* Attempt to resolve a stellar address into a stellar account
*
* @param {String} address - stellar address to look for
*/
async federationLookupByName(address) {
if (!address) {
throw new Error('invalid Stellar address');
}
return this.federationLookup({ address });
}
/**
* Attempt to resolve an account id into a stellar account
* Only works for accounts that can be resolved by our federation server
*
* @param {String} accountId - stellar account id
*/
async federationLookupByAccountId(accountId) {
if (!accountId) {
throw new Error('invalid Stellar account');
}
return this.federationLookup({ accountId });
}
/**
* Check if address is a valid XLM address, and then make sure it matches the root address.
*
* @param address {String} the address to verify
* @param rootAddress {String} the wallet's root address
*/
async isWalletAddress({ address, rootAddress }) {
if (!this.isValidAddress(address)) {
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
}
const addressDetails = this.getAddressDetails(address);
const rootAddressDetails = this.getAddressDetails(rootAddress);
if (addressDetails.baseAddress !== rootAddressDetails.address) {
throw new sdk_core_1.UnexpectedAddressError(`address validation failure: ${addressDetails.baseAddress} vs ${rootAddressDetails.address}`);
}
return true;
}
/**
* Get extra parameters for prebuilding a tx
* Set empty recipients array in trustline txs
*/
async getExtraPrebuildParams(buildParams) {
const params = {};
if (buildParams.type === 'trustline') {
params.recipients = [];
}
return params;
}
/**
* @deprecated
*/
initiateRecovery(params) {
throw new Error('deprecated method');
}
/**
* Builds a funds recovery transaction without BitGo
* @param params
* - userKey: [encrypted] Stellar private key
* - backupKey: [encrypted] Stellar private key, or public key if the private key is held by a KRS provider
* - walletPassphrase: necessary if one of the private keys is encrypted
* - rootAddress: base address of the wallet to recover funds from
* - krsProvider: necessary if backup key is held by KRS
* - recoveryDestination: target address to send recovered funds to
*/
async recover(params) {
// Check if unencrypted root keys were provided, convert to Stellar format if necessary
if (Utils.isValidRootPrivateKey(params.userKey)) {
params.userKey = Utils.encodePrivateKey(Buffer.from(params.userKey.slice(0, 64), 'hex'));
}
else if (Utils.isValidRootPublicKey(params.userKey)) {
params.userKey = Utils.encodePublicKey(Buffer.from(params.userKey, 'hex'));
}
if (Utils.isValidRootPrivateKey(params.backupKey)) {
params.backupKey = Utils.encodePrivateKey(Buffer.from(params.backupKey.slice(0, 64), 'hex'));
}
else if (Utils.isValidRootPublicKey(params.backupKey)) {
params.backupKey = Utils.encodePublicKey(Buffer.from(params.backupKey, 'hex'));
}
// Stellar's Ed25519 public keys start with a G, while private keys start with an S
const isKrsRecovery = params.backupKey.startsWith('G') && !params.userKey.startsWith('G');
const isUnsignedSweep = params.backupKey.startsWith('G') && params.userKey.startsWith('G');
if (isKrsRecovery) {
(0, sdk_core_1.checkKrsProvider)(this, params.krsProvider);
}
if (!this.isValidAddress(params.recoveryDestination)) {
throw new sdk_core_1.InvalidAddressError('Invalid destination address!');
}
const [userKey, backupKey] = (0, getStellarKeys_1.getStellarKeys)(this.bitgo, params);
if (!params.rootAddress || !stellar.StrKey.isValidEd25519PublicKey(params.rootAddress)) {
throw new Error(`Invalid wallet address: ${params.rootAddress}`);
}
const accountDataUrl = `${this.getHorizonUrl()}/accounts/${params.rootAddress}`;
const destinationUrl = `${this.getHorizonUrl()}/accounts/${params.recoveryDestination}`;
let accountData;
try {
accountData = await (0, sdk_api_1.toBitgoRequest)(request.get(accountDataUrl)).result();
}
catch (e) {
throw new Error('Unable to reach the Stellar network via Horizon.');
}
// Now check if the destination account is empty or not
let unfundedDestination = false;
try {
await request.get(destinationUrl);
}
catch (e) {
if (e.status === 404) {
// If the destination account does not yet exist, horizon responds with 404
unfundedDestination = true;
}
}
if (!accountData.sequence || !accountData.balances) {
throw new Error('Horizon server error - unable to retrieve sequence ID or account balance');
}
const account = new stellar.Account(params.rootAddress, accountData.sequence);
// Stellar supports multiple assets on chain, we're only interested in the balances entry whose type is "native" (XLM)
const nativeBalanceInfo = accountData.balances.find((assetBalance) => assetBalance['asset_type'] === 'native');
if (!nativeBalanceInfo) {
throw new Error('Provided wallet has a balance of 0 XLM, recovery aborted');
}
const walletBalance = Number(this.bigUnitsToBaseUnits(nativeBalanceInfo.balance));
const minimumReserve = await this.getMinimumReserve();
const baseTxFee = await this.getBaseTransactionFee();
const recoveryAmount = walletBalance - minimumReserve - baseTxFee;
const formattedRecoveryAmount = this.baseUnitsToBigUnits(recoveryAmount).toString();
const txBuilder = new stellar.TransactionBuilder(account, {
fee: baseTxFee.toFixed(0),
networkPassphrase: this.getStellarNetwork(),
});
const operation = unfundedDestination
? // In this case, we need to create the account
stellar.Operation.createAccount({
destination: params.recoveryDestination,
startingBalance: formattedRecoveryAmount,
})
: // Otherwise if the account already exists, we do a normal send
stellar.Operation.payment({
destination: params.recoveryDestination,
asset: stellar.Asset.native(),
amount: formattedRecoveryAmount,
});
const tx = txBuilder.addOperation(operation).setTimeout(stellar.TimeoutInfinite).build();
const feeInfo = {
fee: new bignumber_js_1.BigNumber(tx.fee).toNumber(),
feeString: tx.fee,
};
if (!isUnsignedSweep) {
tx.sign(userKey);
}
if (!isKrsRecovery && !isUnsignedSweep) {
tx.sign(backupKey);
}
const transaction = {
txBase64: Xlm.txToString(tx),
recoveryAmount,
};
if (isKrsRecovery) {
transaction.backupKey = params.backupKey;
}
transaction.coin = this.getChain();
transaction.feeInfo = feeInfo;
return transaction;
}
/**
* Assemble keychain and half-sign prebuilt transaction
*
* @param params
* @param params.txPrebuild {Object} prebuild object returned by platform
* @param params.prv {String} user prv
* @returns {Promise<HalfSignedTransaction>}
*/
async signTransaction(params) {
const { txPrebuild, prv } = params;
if (_.isUndefined(txPrebuild)) {
throw new Error('missing txPrebuild parameter');
}
if (!_.isObject(txPrebuild)) {
throw new Error(`txPrebuild must be an object, got type ${typeof txPrebuild}`);
}
if (_.isUndefined(prv)) {
throw new Error('missing prv parameter to sign transaction');
}
if (!_.isString(prv)) {
throw new Error(`prv must be a string, got type ${typeof prv}`);
}
const keyPair = Utils.createStellarKeypairFromPrv(prv);
const tx = new stellar.Transaction(txPrebuild.txBase64, this.getStellarNetwork());
tx.sign(keyPair);
const txBase64 = Xlm.txToString(tx);
const type = txPrebuild?.buildParams?.type;
const recipients = txPrebuild?.buildParams?.recipients;
if (type === 'enabletoken') {
return {
halfSigned: { txBase64 },
type,
recipients,
};
}
else {
return { halfSigned: { txBase64 } };
}
}
/**
* Extend walletParams with extra params required for generating an XLM wallet
*
* Stellar wallets have three keychains on them. Two are generated by the platform, and the last is generated by the user.
* Initially, we need a root prv to generate the account, which must be distinct from all three keychains on the wallet.
* If a root prv is not provided, a random one is generated.
*/
async supplementGenerateWallet(walletParams) {
let seed;
const rootPrv = walletParams.rootPrivateKey;
if (rootPrv) {
if (!this.isValidPrv(rootPrv)) {
throw new Error('rootPrivateKey needs to be valid ed25519 secret seed');
}
seed = stellar.StrKey.decodeEd25519SecretSeed(rootPrv);
}
const keyPair = this.generateKeyPair(seed);
// extend the wallet initialization params
walletParams.rootPrivateKey = keyPair.prv;
return walletParams;
}
/**
* Sign message with private key
*
* @param key
* @param message
*/
async signMessage(key, message) {
if (!this.isValidPrv(key.prv)) {
throw new Error(`invalid prv: ${key.prv}`);
}
if (!Buffer.isBuffer(message)) {
message = Buffer.from(message);
}
const keypair = Utils.createStellarKeypairFromPrv(key.prv);
return keypair.sign(message);
}
/**
* Verifies if signature for message is valid.
*
* @param pub public key
* @param message signed message
* @param signature signature to verify
* @returns true if signature is valid.
*/
verifySignature(pub, message, signature) {
if (!this.isValidPub(pub)) {
throw new Error(`invalid pub: ${pub}`);
}
if (!Buffer.isBuffer(message)) {
message = Buffer.from(message);
}
const keyPair = Utils.createStellarKeypairFromPub(pub);
return keyPair.verify(message, signature);
}
/**
* Explain/parse transaction
* @param params
*/
async explainTransaction(params) {
const { txHex, txBase64 } = params;
let tx = undefined;
if (!txHex && !txBase64) {
throw new Error('explainTransaction missing txHex or txBase64 parameter, must have at least one');
}
try {
if (txHex) {
tx = new stellar.Transaction(Buffer.from(txHex, 'hex').toString('base64'), this.getStellarNetwork());
}
else if (txBase64) {
tx = new stellar.Transaction(txBase64, this.getStellarNetwork());
}
}
catch (e) {
throw new Error('txBase64 needs to be a valid tx encoded as base64 string');
}
if (!tx) {
throw new Error('tx needs to be defined in order to explain transaction');
}
const id = tx.hash().toString('hex');
// In a Stellar tx, the _memo property is an object with the methods:
// value() and arm() that provide memo value and type, respectively.
const memo = _.result(tx, '_memo.value') && _.result(tx, '_memo.arm')
? {
value: _.result(tx, '_memo.value').toString(),
type: _.result(tx, '_memo.arm'),
}
: {};
let spendAmount = new bignumber_js_1.BigNumber(0); // amount of XLM used in XLM-only txs
const spendAmounts = {}; // track both xlm and token amounts
if (_.isEmpty(tx.operations)) {
throw new Error('missing operations');
}
const outputs = [];
const operations = []; // non-payment operations
_.forEach(tx.operations, (op) => {
if (op.type === 'createAccount' || op.type === 'payment') {
// TODO Remove memoId from address
// Get memo to attach to address, if type is 'id'
const memoId = _.get(memo, 'type') === 'id' && !_.get(memo, 'value') ? `?memoId=${memo.value}` : '';
let asset;
if (op.type === 'payment') {
if (op.asset.getAssetType() === 'liquidity_pool_shares') {
throw new Error('Invalid asset type');
}
asset = op.asset;
}
else {
asset = stellar.Asset.native();
}
const coin = this.getTokenNameFromStellarAsset(asset); // coin or token id
const output = {
amount: this.bigUnitsToBaseUnits(op.startingBalance || op.amount),
address: op.destination + memoId,
coin,
};
if (!_.isUndefined(spendAmounts[coin])) {
spendAmounts[coin] = spendAmounts[coin].plus(output.amount);
}
else {
spendAmounts[coin] = new bignumber_js_1.BigNumber(output.amount);
}
if (asset.isNative()) {
spendAmount = spendAmount.plus(output.amount);
}
outputs.push(output);
}
else if (op.type === 'changeTrust') {
if (op.line.getAssetType() === 'liquidity_pool_shares') {
throw new Error('Invalid asset type');
}
const asset = op.line;
operations.push({
type: op.type,
coin: this.getTokenNameFromStellarAsset(asset),
asset,
limit: this.bigUnitsToBaseUnits(op.limit),
});
}
});
const outputAmount = spendAmount.toFixed(0);
const outputAmounts = _.mapValues(spendAmounts, (amount) => amount.toFixed(0));
const fee = {
fee: new bignumber_js_1.BigNumber(tx.fee).toFixed(0),
feeRate: null,
size: null,
};
return {
displayOrder: [
'id',
'outputAmount',
'outputAmounts',
'changeAmount',
'outputs',
'changeOutputs',
'fee',
'memo',
'operations',
],
id,
outputs,
outputAmount,
outputAmounts,
changeOutputs: [],
changeAmount: '0',
memo,
fee,
operations,
};
}
/**
* Verify that a tx prebuild's operations comply with the original intention
* @param {stellar.Operation} operations - tx operations
* @param {TransactionParams} txParams - params used to build the tx
*/
verifyEnableTokenTxOperations(operations, txParams) {
const trustlineOperations = _.filter(operations, ['type', 'changeTrust']);
if (trustlineOperations.length !== _.get(txParams, 'recipients', []).length) {
throw new Error('transaction prebuild does not match expected trustline operations');
}
_.forEach(trustlineOperations, (op) => {
if (op.type !== 'changeTrust') {
throw new Error('Invalid asset type');
}
if (op.line.getAssetType() === 'liquidity_pool_shares') {
throw new Error('Invalid asset type');
}
const asset = op.line;
const opToken = this.getTokenNameFromStellarAsset(asset);
const tokenTrustline = _.find(txParams.recipients, (recipient) => {
// trustline params use limits in base units
const opLimitBaseUnits = this.bigUnitsToBaseUnits(op.limit);
// Enable token limit is set to Xlm.maxTrustlineLimit by default
return recipient.tokenName === opToken && opLimitBaseUnits === Xlm.maxTrustlineLimit;
});
if (!tokenTrustline) {
throw new Error('transaction prebuild does not match expected trustline tokens');
}
});
}
/**
* Verify that a tx prebuild's operations comply with the original intention
* @param {stellar.Operation} operations - tx operations
* @param {TransactionParams} txParams - params used to build the tx
*/
verifyTrustlineTxOperations(operations, txParams) {
const trustlineOperations = _.filter(operations, ['type', 'changeTrust']);
if (trustlineOperations.length !== _.get(txParams, 'trustlines', []).length) {
throw new Error('transaction prebuild does not match expected trustline operations');
}
_.forEach(trustlineOperations, (op) => {
if (op.type !== 'changeTrust') {
throw new Error('Invalid asset type');
}
if (op.line.getAssetType() === 'liquidity_pool_shares') {
throw new Error('Invalid asset type');
}
const asset = op.line;
const opToken = this.getTokenNameFromStellarAsset(asset);
const tokenTrustline = _.find(txParams.trustlines, (trustline) => {
// trustline params use limits in base units
const opLimitBaseUnits = this.bigUnitsToBaseUnits(op.limit);
// Prepare the conditions to check for
// Limit will always be set in the operation, even if it was omitted from txParams in the following cases:
// 1. Action is 'add' - limit is set to Xlm.maxTrustlineLimit by default
// 2. Action is 'remove' - limit is set to '0'
const noLimit = _.isUndefined(trustline.limit);
const addTrustlineWithDefaultLimit = trustline.action === 'add' && opLimitBaseUnits === Xlm.maxTrustlineLimit;
const removeTrustline = trustline.action === 'remove' && opLimitBaseUnits === '0';
return (trustline.token === opToken &&
(trustline.limit === opLimitBaseUnits || (noLimit && (addTrustlineWithDefaultLimit || removeTrustline))));
});
if (!tokenTrustline) {
throw new Error('transaction prebuild does not match expected trustline tokens');
}
});
}
/**
* Verify that a transaction prebuild complies with the original intention
*
* @param options
* @param options.txPrebuild prebuild object returned by platform
* @param options.txPrebuild.txBase64 prebuilt transaction encoded as base64 string
* @param options.wallet wallet object to obtain keys to verify against
* @param options.verification specifying some verification parameters
* @param options.verification.disableNetworking Disallow fetching any data from the internet for verification purposes
* @param options.verification.keychains Pass keychains manually rather than fetching them by id
*/
async verifyTransaction(options) {
// TODO BG-5600 Add parseTransaction / improve verification
const { txParams, txPrebuild, wallet, verification = {} } = options;
const disableNetworking = !!verification.disableNetworking;
if (!txPrebuild.txBase64) {
throw new Error('missing required tx prebuild property txBase64');
}
const tx = new stellar.Transaction(txPrebuild.txBase64, this.getStellarNetwork());
if (txParams.recipients && txParams.recipients.length > 1) {
throw new Error('cannot specify more than 1 recipient');
}
// Stellar txs are made up of operations. We only care about Create Account and Payment for sending funds.
const outputOperations = _.filter(tx.operations, (operation) => operation.type === 'createAccount' || operation.type === 'payment');
if (txParams.type === 'enabletoken') {
this.verifyEnableTokenTxOperations(tx.operations, txParams);
}
else if (txParams.type === 'trustline') {
this.verifyTrustlineTxOperations(tx.operations, txParams);
}
else {
if (_.isEmpty(outputOperations)) {
throw new Error('transaction prebuild does not have any operations');
}
_.forEach(txParams.recipients, (expectedOutput, index) => {
const expectedOutputAddressDetails = this.getAddressDetails(expectedOutput.address);
const expectedOutputAddress = expectedOutputAddressDetails.address;
const output = outputOperations[index];
if (output.destination !== expectedOutputAddress) {
throw new Error('transaction prebuild does not match expected recipient');
}
const expectedOutputAmount = new bignumber_js_1.BigNumber(expectedOutput.amount);
// The output amount is expressed as startingBalance in createAccount operations and as amount in payment operations.
const outputAmountString = output.type === 'createAccount' ? output.startingBalance : output.amount;
const outputAmount = new bignumber_js_1.BigNumber(this.bigUnitsToBaseUnits(outputAmountString));
if (!outputAmount.eq(expectedOutputAmount)) {
throw new Error('transaction prebuild does not match expected amount');
}
});
}
// Verify the user signature, if the tx is half-signed
if (!_.isEmpty(tx.signatures)) {
const userSignature = tx.signatures[0].signature();
// obtain the keychains and key signatures
let keychains = verification.keychains;
if (!keychains && disableNetworking) {
throw new Error('cannot fetch keychains without networking');
}
else if (!keychains) {
keychains = await (0, sdk_core_1.promiseProps)({
user: this.keychains().get({ id: wallet.keyIds()[sdk_core_1.KeyIndices.USER] }),
backup: this.keychains().get({ id: wallet.keyIds()[sdk_core_1.KeyIndices.BACKUP] }),
});
}
if (!keychains || !keychains.backup || !keychains.user) {
throw new Error('keychains are required, but could not be fetched');
}
(0, assert_1.default)(keychains.backup.pub);
if (this.verifySignature(keychains.backup.pub, tx.hash(), userSignature)) {
throw new Error('transaction signed with wrong key');
}
(0, assert_1.default)(keychains.user.pub);
if (!this.verifySignature(keychains.user.pub, tx.hash(), userSignature)) {
throw new Error('transaction signature invalid');
}
}
return true;
}
/** inheritdoc */
deriveKeyWithSeed() {
throw new sdk_core_1.NotSupported('method deriveKeyWithSeed not supported for eddsa curve');
}
async parseTransaction(params) {
return {};
}
/**
* Gets config for how token enablements work for this coin
* @returns
* requiresTokenEnablement: True if tokens need to be enabled for this coin
* supportsMultipleTokenEnablements: True if multiple tokens can be enabled in one transaction
*/
getTokenEnablementConfig() {
return {
requiresTokenEnablement: true,
supportsMultipleTokenEnablements: false,
};
}
}
exports.Xlm = Xlm;
Xlm.tokenPatternSeparator = '-'; // separator for token code and issuer
Xlm.maxMemoId = '0xFFFFFFFFFFFFFFFF'; // max unsigned 64-bit number = 18446744073709551615
// max int64 number supported by the network (2^63)-1
// See: https://www.stellar.org/developers/guides/concepts/assets.html#amount-precision-and-representation
Xlm.maxTrustlineLimit = '9223372036854775807';
/**
* stellar-sdk has two overloads for toXDR, and typescript can't seem to figure out the
* correct one to use, so we have to be very explicit as to which one we want.
* @param tx transaction to convert
*/
Xlm.txToString = (tx) => tx.toEnvelope().toXDR('base64');
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieGxtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3hsbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMENBQTRCO0FBQzVCLHlEQUEyQztBQUMzQyx5Q0FBMkI7QUFDM0Isb0RBQXNDO0FBQ3RDLHFEQUF1QztBQUN2QywrQ0FBeUM7QUFDekMsbURBQXFDO0FBQ3JDLDJDQUEwRDtBQUUxRCw4Q0E0QnlCO0FBQ3pCLDRDQUFnRDtBQUNoRCxxREFBa0Q7QUFpSGxELE1BQWEsR0FBSSxTQUFRLG1CQUFRO0lBUS9CLFlBQVksS0FBZ0I7UUFDMUIsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2IsSUFBSSxDQUFDLFVBQVUsR0FBRyxXQUFXLENBQUMsQ0FBQyxxQ0FBcUM7SUFDdEUsQ0FBQztJQUVELE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBZ0I7UUFDcEMsT0FBTyxJQUFJLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBRVMsaUJBQWlCO1FBQ3pCLE9BQU8sT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUM7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsYUFBYTtRQUNYLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsUUFBUTtRQUNOLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0gsU0FBUztRQUNQLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0gsV0FBVztRQUNULE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRDs7T0FFRztJQUNILHNCQUFzQjtRQUNwQixPQUFPLGlCQUFNLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQywwQkFBMEIsQ0FBQztJQUM3RSxDQUFDO0lB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QyxHQUFHLENBQUMsQ0FBQztZQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsYUFBYSxDQUFDLEVBQUUsQ0FBQztnQkFDeEUsTUFBTSxJQUFJLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1lBQ25ELENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsaUJBQWlCO0lBQ2pCLGlCQUFpQjtRQUNmLE1BQU0sSUFBSSx1QkFBWSxDQUFDLHdEQUF3RCxDQUFDLENBQUM7SUFDbkYsQ0FBQztJQVVELEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxNQUErQjtRQUNwRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILHdCQUF3QjtRQUN0QixPQUFPO1lBQ0wsdUJBQXVCLEVBQUUsSUFBSTtZQUM3QixnQ0FBZ0MsRUFBRSxLQUFLO1NBQ3hDLENBQUM7SUFDSixDQUFDOztBQWhoQ0gsa0JBaWhDQztBQS9nQ3dCLHlCQUFxQixHQUFHLEdBQUcsQ0FBQyxDQUFDLHNDQUFzQztBQUMxRSxhQUFTLEdBQVcsb0JBQW9CLENBQUMsQ0FBQyxvREFBb0Q7QUFDOUcscURBQXFEO0FBQ3JELDBHQUEwRztBQUMxRixxQkFBaUIsR0FBVyxxQkFBcUIsQ0FBQztBQW0vQmxFOzs7O0dBSUc7QUFDYyxjQUFVLEdBQUcsQ0FBQyxFQUF1QixFQUFVLEVBQUUsQ0FDL0QsRUFBRSxDQUFDLFVBQVUsRUFBRSxDQUFDLEtBQStCLENBQUMsUUFBUSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgKiBhcyBxdWVyeXN0cmluZyBmcm9tICdxdWVyeXN0cmluZyc7XG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcbmltcG9ydCAqIGFzIHJlcXVlc3QgZnJvbSAnc3VwZXJhZ2VudCc7XG5pbXBvcnQgKiBhcyBzdGVsbGFyIGZyb20gJ3N0ZWxsYXItc2RrJztcbmltcG9ydCB7IEJpZ051bWJlciB9IGZyb20gJ2JpZ251bWJlci5qcyc7XG5pbXBvcnQgKiBhcyBVdGlscyBmcm9tICcuL2xpYi91dGlscyc7XG5pbXBvcnQgeyBLZXlQYWlyIGFzIFN0ZWxsYXJLZXlQYWlyIH0gZnJvbSAnLi9saWIva2V5UGFpcic7XG5cbmltcG9ydCB7XG4gIEJhc2VDb2luLFxuICBCaXRHb0Jhc2UsXG4gIGNoZWNrS3JzUHJvdmlkZXIsXG4gIGNvbW1vbixcbiAgRXh0cmFQcmVidWlsZFBhcmFtc09wdGlvbnMsXG4gIEludmFsaWRBZGRyZXNzRXJyb3IsXG4gIEludmFsaWRNZW1vSWRFcnJvcixcbiAgSVRyYW5zYWN0aW9uUmVjaXBpZW50LFxuICBLZXlJbmRpY2VzLFxuICBLZXlQYWlyLFxuICBQYXJzZWRUcmFuc2FjdGlvbixcbiAgUGFyc2VUcmFuc2FjdGlvbk9wdGlvbnMsXG4gIHByb21pc2VQcm9wcyxcbiAgU2lnblRyYW5zYWN0aW9uT3B0aW9ucyBhcyBCYXNlU2lnblRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgU3RlbGxhckZlZGVyYXRpb25Vc2VyTm90Rm91bmRFcnJvcixcbiAgVG9rZW5FbmFibGVtZW50Q29uZmlnLFxuICBUcmFuc2FjdGlvbkV4cGxhbmF0aW9uIGFzIEJhc2VUcmFuc2FjdGlvbkV4cGxhbmF0aW9uLFxuICBUcmFuc2FjdGlvblBhcmFtcyBhcyBCYXNlVHJhbnNhY3Rpb25QYXJhbXMsXG4gIFRyYW5zYWN0aW9uUHJlYnVpbGQgYXMgQmFzZVRyYW5zYWN0aW9uUHJlYnVpbGQsXG4gIFRyYW5zYWN0aW9uUmVjaXBpZW50IGFzIEJhc2VUcmFuc2FjdGlvbk91dHB1dCxcbiAgVW5leHBlY3RlZEFkZHJlc3NFcnJvcixcbiAgVmVyaWZ5QWRkcmVzc09wdGlvbnMgYXMgQmFzZVZlcmlmeUFkZHJlc3NPcHRpb25zLFxuICBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMgYXMgQmFzZVZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgV2FsbGV0LFxuICBOb3RTdXBwb3J0ZWQsXG4gIE11bHRpc2lnVHlwZSxcbiAgbXVsdGlzaWdUeXBlcyxcbn0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IHRvQml0Z29SZXF1ZXN0IH0gZnJvbSAnQGJpdGdvL3Nkay1hcGknO1xuaW1wb3J0IHsgZ2V0U3RlbGxhcktleXMgfSBmcm9tICcuL2dldFN0ZWxsYXJLZXlzJztcblxuLyoqXG4gKiBYTE0gYWNjb3VudHMgc3VwcG9ydCB2aXJ0dWFsIChtdXhlZCkgYWRkcmVzc2VzXG4gKiBBIGJhc2UgYWRkcmVzcyBzdGFydHMgd2l0aCBcIkdcIiBhbmQgaXMgdGllZCB0byB0aGUgdW5kZXJseWluZyBcInJlYWxcIiBhY2NvdW50XG4gKiBBIG11eGVkIGFkZHJlc3Mgc3RhcnRzIHdpdGggXCJNXCIgYW5kIGNvbWJpbmVzIHRoZSBiYXNlIGFkZHJlc3Mgd2l0aCBhIDY0LWJpdCBpbnRlZ2VyIElEIGluIG9yZGVyIHRvIHByb3ZpZGVcbiAqIGFuIGFsdGVybmF0aXZlIHRvIG1lbW8gaWRzLlxuICovXG5pbnRlcmZhY2UgQWRkcmVzc0RldGFpbHMge1xuICBiYXNlQWRkcmVzczogc3RyaW5nO1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIGlkPzogc3RyaW5nO1xuICBtZW1vSWQ/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG59XG5cbmludGVyZmFjZSBNZW1vIHtcbiAgdHlwZTogc3RlbGxhci5NZW1vVHlwZTtcbiAgdmFsdWU6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIEluaXRpYXRlUmVjb3ZlcnlPcHRpb25zIHtcbiAgdXNlcktleTogc3RyaW5nO1xuICBiYWNrdXBLZXk6IHN0cmluZztcbiAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogc3RyaW5nO1xuICBrcnNQcm92aWRlcj86IHN0cmluZztcbiAgd2FsbGV0UGFzc3BocmFzZT86IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIFJlY292ZXJ5T3B0aW9ucyBleHRlbmRzIEluaXRpYXRlUmVjb3ZlcnlPcHRpb25zIHtcbiAgcm9vdEFkZHJlc3M/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBSZWNvdmVyeVRyYW5zYWN0aW9uIHtcbiAgdHhCYXNlNjQ6IHN0cmluZztcbiAgcmVjb3ZlcnlBbW91bnQ6IG51bWJlcjtcbiAgY29pbj86IHN0cmluZztcbiAgYmFja3VwS2V5Pzogc3RyaW5nO1xuICB0eEluZm8/OiBhbnk7XG4gIGZlZUluZm8/OiBhbnk7XG59XG5cbmludGVyZmFjZSBCdWlsZE9wdGlvbnMge1xuICB3YWxsZXQ/OiBXYWxsZXQ7XG4gIHJlY2lwaWVudHM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+W107XG4gIHR5cGU/OiBzdHJpbmc7XG4gIHdhbGxldFBhc3NwaHJhc2U/OiBzdHJpbmc7XG4gIFtpbmRleDogc3RyaW5nXTogdW5rbm93bjtcbn1cblxuaW50ZXJmYWNlIFRyYW5zYWN0aW9uUHJlYnVpbGQgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25QcmVidWlsZCB7XG4gIHR4QmFzZTY0OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBTaWduVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgQmFzZVNpZ25UcmFuc2FjdGlvbk9wdGlvbnMge1xuICB0eFByZWJ1aWxkOiBUcmFuc2FjdGlvblByZWJ1aWxkO1xuICBwcnY6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIEhhbGZTaWduZWRUcmFuc2FjdGlvbiB7XG4gIGhhbGZTaWduZWQ6IHtcbiAgICB0eEJhc2U2NDogc3RyaW5nO1xuICB9O1xuICByZWNpcGllbnRzPzogSVRyYW5zYWN0aW9uUmVjaXBpZW50W107XG4gIHR5cGU/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBTdXBwbGVtZW50R2VuZXJhdGVXYWxsZXRPcHRpb25zIHtcbiAgcm9vdFByaXZhdGVLZXk/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBFeHBsYWluVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhIZXg/OiBzdHJpbmc7XG4gIHR4QmFzZTY0Pzogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgVHJhbnNhY3Rpb25NZW1vIHtcbiAgdmFsdWU/OiBzdHJpbmc7XG4gIHR5cGU/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBUcmFuc2FjdGlvbk9wZXJhdGlvbiB7XG4gIHR5cGU6IHN0cmluZztcbiAgY29pbjogc3RyaW5nO1xuICBsaW1pdD86IHN0cmluZztcbiAgYXNzZXQ/OiBzdGVsbGFyLkFzc2V0O1xufVxuXG5pbnRlcmZhY2UgVHJhbnNhY3Rpb25PdXRwdXQgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25PdXRwdXQge1xuICBjb2luOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBUcmFuc2FjdGlvbkV4cGxhbmF0aW9uIGV4dGVuZHMgQmFzZVRyYW5zYWN0aW9uRXhwbGFuYXRpb24ge1xuICBtZW1vOiBUcmFuc2FjdGlvbk1lbW87XG59XG5cbmludGVyZmFjZSBWZXJpZnlBZGRyZXNzT3B0aW9ucyBleHRlbmRzIEJhc2VWZXJpZnlBZGRyZXNzT3B0aW9ucyB7XG4gIHJvb3RBZGRyZXNzOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBUcnVzdGxpbmVPcHRpb25zIHtcbiAgdG9rZW46IHN0cmluZztcbiAgYWN0aW9uOiBzdHJpbmc7XG4gIGxpbWl0Pzogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgVHJhbnNhY3Rpb25QYXJhbXMgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25QYXJhbXMge1xuICB0cnVzdGxpbmVzPzogVHJ1c3RsaW5lT3B0aW9uc1tdO1xufVxuXG5pbnRlcmZhY2UgVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgQmFzZVZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIHR4UGFyYW1zOiBUcmFuc2FjdGlvblBhcmFtcztcbn1cblxuZXhwb3J0IGNsYXNzIFhsbSBleHRlbmRzIEJhc2VDb2luIHtcbiAgcHVibGljIHJlYWRvbmx5IGhvbWVEb21haW46IHN0cmluZztcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSB0b2tlblBhdHRlcm5TZXBhcmF0b3IgPSAnLSc7IC8vIHNlcGFyYXRvciBmb3IgdG9rZW4gY29kZSBhbmQgaXNzdWVyXG4gIHN0YXRpYyByZWFkb25seSBtYXhNZW1vSWQ6IHN0cmluZyA9ICcweEZGRkZGRkZGRkZGRkZGRkYnOyAvLyBtYXggdW5zaWduZWQgNjQtYml0IG51bWJlciA9IDE4NDQ2NzQ0MDczNzA5NTUxNjE1XG4gIC8vIG1heCBpbnQ2NCBudW1iZXIgc3VwcG9ydGVkIGJ5IHRoZSBuZXR3b3JrICgyXjYzKS0xXG4gIC8vIFNlZTogaHR0cHM6Ly93d3cuc3RlbGxhci5vcmcvZGV2ZWxvcGVycy9ndWlkZXMvY29uY2VwdHMvYXNzZXRzLmh0bWwjYW1vdW50LXByZWNpc2lvbi1hbmQtcmVwcmVzZW50YXRpb25cbiAgc3RhdGljIHJlYWRvbmx5IG1heFRydXN0bGluZUxpbWl0OiBzdHJpbmcgPSAnOTIyMzM3MjAzNjg1NDc3NTgwNyc7XG5cbiAgY29uc3RydWN0b3IoYml0Z286IEJpdEdvQmFzZSkge1xuICAgIHN1cGVyKGJpdGdvKTtcbiAgICB0aGlzLmhvbWVEb21haW4gPSAnYml0Z28uY29tJzsgLy8gdXNlZCBmb3IgcmV2ZXJzZSBmZWRlcmF0aW9uIGxvb2t1cFxuICB9XG5cbiAgc3RhdGljIGNyZWF0ZUluc3RhbmNlKGJpdGdvOiBCaXRHb0Jhc2UpOiBCYXNlQ29pbiB7XG4gICAgcmV0dXJuIG5ldyBYbG0oYml0Z28pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFN0ZWxsYXJOZXR3b3JrKCk6IHN0ZWxsYXIuTmV0d29ya3Mge1xuICAgIHJldHVybiBzdGVsbGFyLk5ldHdvcmtzLlBVQkxJQztcbiAgfVxuXG4gIC8qKlxuICAgKiBGYWN0b3IgYmV0d2VlbiB0aGUgYmFzZSB1bml0IGFuZCBpdHMgc21hbGxlc3Qgc3ViZGl2aXNvblxuICAgKi9cbiAgZ2V0QmFzZUZhY3RvcigpIHtcbiAgICByZXR1cm4gMWU3O1xuICB9XG5cbiAgLyoqXG4gICAqIElkZW50aWZpZXIgZm9yIHRoZSBibG9ja2NoYWluIHdoaWNoIHN1cHBvcnRzIHRoaXMgY29pblxuICAgKi9cbiAgZ2V0Q2hhaW4oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ3hsbSc7XG4gIH1cblxuICAvKipcbiAgICogSWRlbnRpZmllciBmb3IgdGhlIGNvaW4gZmFtaWx5XG4gICAqL1xuICBnZXRGYW1pbHkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ3hsbSc7XG4gIH1cblxuICAvKipcbiAgICogQ29tcGxldGUgaHVtYW4tcmVhZGFibGUgbmFtZSBvZiB0aGlzIGNvaW5cbiAgICovXG4gIGdldEZ1bGxOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdTdGVsbGFyJztcbiAgfVxuXG4gIC8qKlxuICAgKiBVcmwgYXQgd2hpY2ggdGhlIHN0ZWxsYXIgZmVkZXJhdGlvbiBzZXJ2ZXIgY2FuIGJlIHJlYWNoZWRcbiAgICovXG4gIGdldEZlZGVyYXRpb25TZXJ2ZXJVcmwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY29tbW9uLkVudmlyb25tZW50c1t0aGlzLmJpdGdvLmdldEVudigpXS5zdGVsbGFyRmVkZXJhdGlvblNlcnZlclVybDtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcmwgYXQgd2hpY2ggaG9yaXpvbiBjYW4gYmUgcmVhY2hlZFxuICAgKi9cbiAgZ2V0SG9yaXpvblVybCgpOiBzdHJpbmcge1xuICAgIHJldHVybiAnaHR0cHM6Ly9ob3Jpem9uLnN0ZWxsYXIub3JnJztcbiAgfVxuXG4gIC8qKiBpbmhlcml0ZG9jICovXG4gIGdlbmVyYXRlS2V5UGFpcihzZWVkPzogQnVmZmVyKTogS2V5UGFpciB7XG4gICAgY29uc3Qga2V5UGFpciA9IHNlZWQgPyBuZXcgU3RlbGxhcktleVBhaXIoeyBzZWVkIH0pIDogbmV3IFN0ZWxsYXJLZXlQYWlyKCk7XG4gICAgY29uc3Qga2V5cyA9IGtleVBhaXIuZ2V0S2V5cygpO1xuICAgIGlmICgha2V5cy5wcnYpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBwcnYgaW4ga2V5IGdlbmVyYXRpb24uJyk7XG4gICAgfVxuICAgIHJldHVybiB7IHB1Yjoga2V5cy5wdWIsIHBydjoga2V5cy5wcnYgfTtcbiAgfVxuXG4gIGdlbmVyYXRlUm9vdEtleVBhaXIoc2VlZD86IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIGNvbnN0IGtleVBhaXIgPSBzZWVkID8gbmV3IFN0ZWxsYXJLZXlQYWlyKHsgc2VlZCB9KSA6IG5ldyBTdGVsbGFyS2V5UGFpcigpO1xuICAgIGNvbnN0IGtleXMgPSBrZXlQYWlyLmdldEtleXModHJ1ZSk7XG4gICAgaWYgKCFrZXlzLnBydikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHBydiBpbiBrZXkgZ2VuZXJhdGlvbi4nKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcHJ2OiBrZXlzLnBydiArIGtleXMucHViLCBwdWI6IGtleXMucHViIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IGVuY29kZWQgZWQyNTUxOSBwdWJsaWMga2V5IGZyb20gcmF3IGRhdGFcbiAgICpcbiAgICogQHBhcmFtIHB1YiBSYXcgcHVibGljIGtleVxuICAgKiBAcmV0dXJucyBFbmNvZGVkIHB1YmxpYyBrZXlcbiAgICovXG4gIGdldFB1YkZyb21SYXcocHViOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBVdGlscy5lbmNvZGVQdWJsaWNLZXkoQnVmZmVyLmZyb20ocHViLCAnaGV4JykpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBlbmNvZGVkIGVkMjU1MTkgcHJpdmF0ZSBrZXkgZnJvbSByYXcgZGF0YVxuICAgKlxuICAgKiBAcGFyYW0gcHJ2IFJhdyBwcml2YXRlIGtleVxuICAgKiBAcmV0dXJucyBFbmNvZGVkIHByaXZhdGUga2V5XG4gICAqL1xuICBnZXRQcnZGcm9tUmF3KHBydjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gVXRpbHMuZW5jb2RlUHJpdmF0ZUtleShCdWZmZXIuZnJvbShwcnYsICdoZXgnKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGlucHV0IGlzIHZhbGlkIHB1YmxpYyBrZXkgZm9yIHRoZSBjb2luLlxuICAgKlxuICAgKiBAcGFyYW0gcHViIHRoZSBwdWIgdG8gYmUgY2hlY2tlZFxuICAgKiBAcmV0dXJucyBpcyBpdCB2YWxpZD9cbiAgICovXG4gIGlzVmFsaWRQdWIocHViOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAvLyBTdGVsbGFyJ3MgdmFsaWRhdGlvbiBtZXRob2Qgb25seSBhbGxvd3Mga2V5cyBpbiBTdGVsbGFyLXNwZWNpZmljIGZvcm1hdCwgd2l0aCBhICdHJyBwcmVmaXhcbiAgICAvLyBXZSBuZWVkIHRvIGFsbG93IGZvciBib3RoIFN0ZWxsYXIgYW5kIHJhdyByb290IGtleXNcbiAgICByZXR1cm4gVXRpbHMuaXNWYWxpZFJvb3RQdWJsaWNLZXkocHViKSB8fCBVdGlscy5pc1ZhbGlkU3RlbGxhclB1YmxpY0tleShwdWIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBpbnB1dCBpcyB2YWxpZCBwcml2YXRlIGtleSBmb3IgdGhlIGNvaW5cbiAgICpcbiAgICogQHBhcmFtIHBydiB0aGUgcHJ2IHRvIGJlIGNoZWNrZWRcbiAgICogQHJldHVybnMgaXMgaXQgdmFsaWQ/XG4gICAqL1xuICBpc1ZhbGlkUHJ2KHBydjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgLy8gU3RlbGxhcidzIHZhbGlkYXRpb24gbWV0aG9kIG9ubHkgYWxsb3dzIGtleXMgaW4gU3RlbGxhci1zcGVjaWZpYyBmb3JtYXQsIHdpdGggYW4gJ1MnIHByZWZpeFxuICAgIC8vIFdlIG5lZWQgdG8gYWxsb3cgZm9yIGJvdGggU3RlbGxhciBhbmQgcmF3IHJvb3QgcHJpdmF0ZSBrZXlzXG4gICAgcmV0dXJuIFV0aWxzLmlzVmFsaWRSb290UHJpdmF0ZUtleShwcnYpIHx8IFV0aWxzLmlzVmFsaWRTdGVsbGFyUHJpdmF0ZUtleShwcnYpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBhIG1lbW8gaWQgaXMgdmFsaWRcbiAgICpcbiAgICogQHBhcmFtIG1lbW9JZCBtZW1vIGlkXG4gICAqIEByZXR1cm5zIHRydWUgaWYgbWVtbyBpZCBpcyB2YWxpZFxuICAgKi9cbiAgaXNWYWxpZE1lbW9JZChtZW1vSWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGxldCBtZW1vSWROdW1iZXI7XG4gICAgdHJ5IHtcbiAgICAgIHN0ZWxsYXIuTWVtby5pZChtZW1vSWQpOyAvLyB0aHJvd3MgaWYgdGhlIHZhbHVlIGlzIG5vdCB2YWxpZCBtZW1vIGlkXG4gICAgICBtZW1vSWROdW1iZXIgPSBuZXcgQmlnTnVtYmVyKG1lbW9JZCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHJldHVybiBtZW1vSWROdW1iZXIuZ3RlKDApICYmIG1lbW9JZE51bWJlci5sdChYbG0ubWF4TWVtb0lkKTtcbiAgfVxuXG4gIHN1cHBvcnRzRGVyaXZlS2V5V2l0aFNlZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqIHtAaW5oZXJpdERvYyB9ICoqL1xuICBzdXBwb3J0c011bHRpc2lnKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIGluaGVyaXRlZCBkb2MgKi9cbiAgZ2V0RGVmYXVsdE11bHRpc2lnVHlwZSgpOiBNdWx0aXNpZ1R5cGUge1xuICAgIHJldHVybiBtdWx0aXNpZ1R5cGVzLm9uY2hhaW47XG4gIH1cblxuICAvKipcbiAgICogRXZhbHVhdGVzIHdoZXRoZXIgYSBtZW1vIGlzIHZhbGlkXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSB2YWx1ZSBvZiB0aGUgbWVtb1xuICAgKiBAcGFyYW0gdHlwZSB0eXBlIG9mIHRoZSBtZW1vXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdmFsdWUgYW5kIHR5cGUgYXJlIGEgdmFsaWRcbiAgICovXG4gIGlzVmFsaWRNZW1vKHsgdmFsdWUsIHR5cGUgfTogTWVtbyk6IGJvb2xlYW4ge1xuICAgIGlmICghdmFsdWUgfHwgIXR5cGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIC8vIHRocm93cyBpZiB0aGUgdmFsdWUgaXMgbm90IHZhbGlkIGZvciB0aGUgdHlwZVxuICAgICAgLy8gdmFsaWQgdHlwZXMgYXJlOiAnaWQnLCAndGV4dCcsICdoYXNoJywgJ3JldHVybidcbiAgICAgIC8vIFNlZSBodHRwczovL3d3dy5zdGVsbGFyLm9yZy9kZXZlbG9wZXJzL2d1aWRlcy9jb25jZXB0cy90cmFuc2FjdGlvbnMuaHRtbCNtZW1vXG4gICAgICBzdGVsbGFyLk1lbW9bdHlwZV0odmFsdWUpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGluc3RhbmNlIG9mIHN0ZWxsYXIuTXV4ZWRBY2NvdW50IGZyb20gTSBhZGRyZXNzXG4gICAqIFNlZTogaHR0cHM6Ly9kZXZlbG9wZXJzLnN0ZWxsYXIub3JnL2RvY3MvZ2xvc3NhcnkvbXV4ZWQtYWNjb3VudHNcbiAgICovXG4gIGdldE11eGVkQWNjb3VudChhZGRyZXNzOiBzdHJpbmcpOiBzdGVsbGFyLk11eGVkQWNjb3VudCB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBzdGVsbGFyLk11eGVkQWNjb3VudC5mcm9tQWRkcmVzcyhhZGRyZXNzLCAnMCcpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBtdXhlZCBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBhIG11eGVkIGFkZHJlc3MgaXMgdmFsaWRcbiAgICogU2VlOiBodHRwczovL2RldmVsb3BlcnMuc3RlbGxhci5vcmcvZG9jcy9nbG9zc2FyeS9tdXhlZC1hY2NvdW50c1xuICAgKlxuICAgKiBAcGFyYW0gYWRkcmVzc1xuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAgICovXG4gIGlzVmFsaWRNdXhlZEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKCFfLmlzU3RyaW5nKGFkZHJlc3MpIHx8ICFhZGRyZXNzLnN0YXJ0c1dpdGgoJ00nKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAvLyByZXR1cm4gdHJ1ZSBpZiBtdXhlZCBhY2NvdW50IGlzIHZhbGlkIG9yIHRocm93XG4gICAgICByZXR1cm4gISFzdGVsbGFyLk11eGVkQWNjb3VudC5mcm9tQWRkcmVzcyhhZGRyZXNzLCAnMCcpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWluaW11bSBiYWxhbmNlIG9mIGEgMi1vZi0zIG11bHRpc2lnIHdhbGxldFxuICAgKiBAcmV0dXJucyBtaW5pbXVtIGJhbGFuY2UgaW4gc3Ryb29wc1xuICAgKi9cbiAgYXN5bmMgZ2V0TWluaW11bVJlc2VydmUoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBzZXJ2ZXIgPSBuZXcgc3RlbGxhci5TZXJ2ZXIodGhpcy5nZXRIb3Jpem9uVXJsKCkpO1xuXG4gICAgY29uc3QgaG9yaXpvbkxlZGdlckluZm8gPSBhd2FpdCBzZXJ2ZXIubGVkZ2VycygpLm9yZGVyKCdkZXNjJykubGltaXQoMSkuY2FsbCgpO1xuXG4gICAgaWYgKCFob3Jpem9uTGVkZ2VySW5mbykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmFibGUgdG8gY29ubmVjdCB0byBIb3Jpem9uIGZvciByZXNlcnZlIHJlcXVpcmVtZW50IGRhdGEnKTtcbiAgICB9XG5cbiAgICBjb25zdCBiYXNlUmVzZXJ2ZSA9IGhvcml6b25MZWRnZXJJbmZvLnJlY29yZHNbMF0uYmFzZV9yZXNlcnZlX2luX3N0cm9vcHM7XG5cbiAgICAvLyAyLW9mLTMgd2FsbGV0cyBoYXZlIGEgbWluaW11bSByZXNlcnZlIG9mIDV4IHRoZSBiYXNlIHJlc2VydmVcbiAgICByZXR1cm4gNSAqIGJhc2VSZXNlcnZlO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYW5zYWN0aW9uIGZlZSBmb3IgZWFjaCBvcGVyYXRpb25cbiAgICogQHJldHVybnMgdHJhbnNhY3Rpb24gZmVlIGluIHN0cm9vcHNcbiAgICovXG4gIGFzeW5jIGdldEJhc2VUcmFuc2FjdGlvbkZlZSgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHNlcnZlciA9IG5ldyBzdGVsbGFyLlNlcnZlcih0aGlzLmdldEhvcml6b25VcmwoKSk7XG5cbiAgICBjb25zdCBob3Jpem9uTGVkZ2VySW5mbyA9IGF3YWl0IHNlcnZlci5sZWRnZXJzKCkub3JkZXIoJ2Rlc2MnKS5saW1pdCgxKS5jYWxsKCk7XG5cbiAgICBpZiAoIWhvcml6b25MZWRnZXJJbmZvKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuYWJsZSB0byBjb25uZWN0IHRvIEhvcml6b24gZm9yIHJlc2VydmUgcmVxdWlyZW1lbnQgZGF0YScpO1xuICAgIH1cblxuICAgIHJldHVybiBob3Jpem9uTGVkZ2VySW5mby5yZWNvcmRzWzBdLmJhc2VfZmVlX2luX3N0cm9vcHM7XG4gIH1cblxuICAvKipcbiAgICogUHJvY2VzcyBhZGRyZXNzIGludG8gYWRkcmVzcyBhbmQgbWVtbyBpZFxuICAgKlxuICAgKiBAcGFyYW0gYWRkcmVzcyB0aGUgYWRkcmVzc1xuICAgKiBAcmV0dXJucyBvYmplY3QgY29udGFpbmluZyBhZGRyZXNzIGFuZCBtZW1vIGlkXG4gICAqL1xuICBnZXRBZGRyZXNzRGV0YWlscyhhZGRyZXNzOiBzdHJpbmcpOiBBZGRyZXNzRGV0YWlscyB7XG4gICAgaWYgKGFkZHJlc3Muc3RhcnRzV2l0aCgnTScpKSB7XG4gICAgICBpZiAodGhpcy5pc1ZhbGlkTXV4ZWRBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICAgIGNvbnN0IG11eGVkQWNjb3VudCA9IHRoaXMuZ2V0TXV4ZWRBY2NvdW50KGFkZHJlc3MpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGJhc2VBZGRyZXNzOiBtdXhlZEFjY291bnQuYmFzZUFjY291bnQoKS5hY2NvdW50SWQoKSxcbiAgICAgICAgICBhZGRyZXNzLFxuICAgICAgICAgIGlkOiBtdXhlZEFjY291bnQuaWQoKSxcbiAgICAgICAgICBtZW1vSWQ6IHVuZGVmaW5lZCxcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIG11eGVkIGFkZHJlc3M6ICR7YWRkcmVzc31gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBkZXN0aW5hdGlvbkRldGFpbHMgPSB1cmwucGFyc2UoYWRkcmVzcyk7XG4gICAgY29uc3QgZGVzdGluYXRpb25BZGRyZXNzID0gZGVzdGluYXRpb25EZXRhaWxzLnBhdGhuYW1lIHx8ICcnO1xuICAgIGlmICghZGVzdGluYXRpb25BZGRyZXNzIHx8ICFzdGVsbGFyLlN0cktleS5pc1ZhbGlkRWQyNTUxOVB1YmxpY0tleShkZXN0aW5hdGlvbkFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgYWRkcmVzczogJHthZGRyZXNzfWApO1xuICAgIH1cbiAgICAvLyBhZGRyZXNzIGRvZXNuJ3QgaGF2ZSBhIG1lbW8gaWRcbiAgICBpZiAoZGVzdGluYXRpb25EZXRhaWxzLnBhdGhuYW1lID09PSBhZGRyZXNzKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBiYXNlQWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgYWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgaWQ6IHVuZGVmaW5lZCxcbiAgICAgICAgbWVtb0lkOiB1bmRlZmluZWQsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmICghZGVzdGluYXRpb25EZXRhaWxzLnF1ZXJ5KSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgcXVlcnlEZXRhaWxzID0gcXVlcnlzdHJpbmcucGFyc2UoZGVzdGluYXRpb25EZXRhaWxzLnF1ZXJ5KTtcbiAgICBpZiAoIXF1ZXJ5RGV0YWlscy5tZW1vSWQpIHtcbiAgICAgIC8vIGlmIHRoZXJlIGFyZSBtb3JlIHByb3BlcnRpZXMsIHRoZSBxdWVyeSBkZXRhaWxzIG5lZWQgdG8gY29udGFpbiB0aGUgbWVtbyBpZCBwcm9wZXJ0eVxuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoYGludmFsaWQgYWRkcmVzczogJHthZGRyZXNzfWApO1xuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHF1ZXJ5RGV0YWlscy5tZW1vSWQpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihcbiAgICAgICAgYG1lbW9JZCBtYXkgb25seSBiZSBnaXZlbiBhdCBtb3N0IG9uY2UsIGJ1dCBmb3VuZCAke3F1ZXJ5RGV0YWlscy5tZW1vSWQubGVuZ3RofSBpbnN0YW5jZXMgaW4gYWRkcmVzcyAke2FkZHJlc3N9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShxdWVyeURldGFpbHMubWVtb0lkKSAmJiBxdWVyeURldGFpbHMubWVtb0lkLmxlbmd0aCAhPT0gMSkge1xuICAgICAgLy8gdmFsaWQgYWRkcmVzc2VzIGNhbiBvbmx5IGNvbnRhaW4gb25lIG1lbW8gaWRcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIGFkZHJlc3MgJyR7YWRkcmVzc30nLCBtdXN0IGNvbnRhaW4gZXhhY3RseSBvbmUgbWVtb0lkYCk7XG4gICAgfVxuXG4gICAgY29uc3QgW21lbW9JZF0gPSBfLmNhc3RBcnJheShxdWVyeURldGFpbHMubWVtb0lkKSB8fCB1bmRlZmluZWQ7XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRNZW1vSWQobWVtb0lkKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRNZW1vSWRFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAnJHthZGRyZXNzfScsIG1lbW9JZCBpcyBub3QgdmFsaWRgKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgYmFzZUFkZHJlc3M6IGRlc3RpbmF0aW9uQWRkcmVzcyxcbiAgICAgIGFkZHJlc3M6IGRlc3RpbmF0aW9uQWRkcmVzcyxcbiAgICAgIGlkOiB1bmRlZmluZWQsXG4gICAgICBtZW1vSWQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbmQgcmV0dXJuIGFkZHJlc3Mgd2l0aCBhcHBlbmRlZCBtZW1vIGlkIG9yIG11eGVkIGFkZHJlc3NcbiAgICpcbiAgICogQHBhcmFtIGFkZHJlc3MgYWRkcmVzc1xuICAgKiBAcGFyYW0gbWVtb0lkIG1lbW8gaWRcbiAgICogQHJldHVybnMgYWRkcmVzcyB3aXRoIG1lbW8gaWRcbiAgICovXG4gIG5vcm1hbGl6ZUFkZHJlc3MoeyBhZGRyZXNzLCBtZW1vSWQgfTogQWRkcmVzc0RldGFpbHMpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLmlzVmFsaWRNdXhlZEFkZHJlc3MoYWRkcmVzcykpIHtcbiAgICAgIHJldHVybiBhZGRyZXNzO1xuICAgIH1cbiAgICBpZiAoIXN0ZWxsYXIuU3RyS2V5LmlzVmFsaWRFZDI1NTE5UHVibGljS2V5KGFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgYWRkcmVzcyBkZXRhaWxzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuICAgIGlmIChtZW1vSWQgJiYgdGhpcy5pc1ZhbGlkTWVtb0lkKG1lbW9JZCkpIHtcbiAgICAgIHJldHVybiBgJHthZGRyZXNzfT9tZW1vSWQ9JHttZW1vSWR9YDtcbiAgICB9XG4gICAgcmV0dXJuIGFkZHJlc3M7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGlucHV0IGlzIHZhbGlkIHB1YmxpYyBrZXkgZm9yIHRoZSBjb2luXG4gICAqXG4gICAqIEBwYXJhbSBhZGRyZXNzIHRoZSBwdWIgdG8gYmUgY2hlY2tlZFxuICAgKiBAcmV0dXJucyBpcyBpdCB2YWxpZD9cbiAgICovXG4gIGlzVmFsaWRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBhZGRyZXNzRGV0YWlscyA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMoYWRkcmVzcyk7XG4gICAgICByZXR1cm4gYWRkcmVzcyA9PT0gdGhpcy5ub3JtYWxpemVBZGRyZXNzKGFkZHJlc3NEZXRhaWxzKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIFN0ZWxsYXIgQXNzZXQgaW4gY29pbjp0b2tlbiBmb3JtIChpLmUuICh0KXhsbTo8Y29kZT4tPGlzc3Vlcj4pXG4gICAqIElmIHRoZSBhc3NldCBpcyBYTE0sIHJldHVybiB0aGUgY2hhaW5cbiAgICogQHBhcmFtIHtzdGVsbGFyLkFzc2V0fSBhc3NldCAtIGluc3RhbmNlIG9mIFN0ZWxsYXIgQXNzZXRcbiAgICovXG4gIGdldFRva2VuTmFtZUZyb21TdGVsbGFyQXNzZXQoYXNzZXQ6IHN0ZWxsYXIuQXNzZXQpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvZGUgPSBhc3NldC5nZXRDb2RlKCk7XG4gICAgY29uc3QgaXNzdWVyID0gYXNzZXQuZ2V0SXNzdWVyKCk7XG4gICAgaWYgKGFzc2V0LmlzTmF0aXZlKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLmdldENoYWluKCk7XG4gICAgfVxuICAgIHJldHVybiBgJHt0aGlzLmdldENoYWluKCl9JHtCYXNlQ29pbi5jb2luVG9rZW5QYXR0ZXJuU2VwYXJhdG9yfSR7Y29kZX0ke1hsbS50b2tlblBhdHRlcm5TZXBhcmF0b3J9JHtpc3N1ZXJ9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZSB3aGV0aGVyIGEgc3RlbGxhciB1c2VybmFtZSBoYXMgdmFsaWQgZm9ybWF0XG4gICAqIFRoaXMgbWV0aG9kIGlzIHVzZWQgYnkgdGhlIGNsaWVudCB3aGVuIGEgc3RlbGxhciBhZGRyZXNzIGlzIGJlaW5nIGFkZGVkIHRvIGEgd2FsbGV0XG4gICAqIEV4YW1wbGUgb2YgYSBjb21tb24gc3RlbGxhciB1c2VybmFtZTogZm9vQGJhci5iYXpcbiAgICogVGhlIGFib3ZlIGV4YW1wbGUgd291bGQgcmVzdWx0IGluIHRoZSBTdGVsbGFyIGFkZHJlc3M6IGZvb0BiYXIuYmF6KmJpdGdvLmNvbVxuICAgKlxuICAgKiBAcGFyYW0gdXNlcm5hbWUgLSBzdGVsbGFyIHVzZXJuYW1lXG4gICAqIEByZXR1cm4gdHJ1ZSBpZiBzdGVsbGFyIHVzZXJuYW1lIGlzIHZhbGlkXG4gICAqL1xuICBpc1ZhbGlkU3RlbGxhclVzZXJuYW1lKHVzZXJuYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gL15bYS16MC05XFwtXy4rQF0rJC8udGVzdCh1c2VybmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFuIGluc3RhbmNlIG9mIEZlZGVyYXRpb25TZXJ2ZXIgZm9yIEJpdEdvIGxvb2t1cHNcbiAgICpcbiAgICogQHJldHVybnMgaW5zdGFuY2Ugb2YgQml0R28gRmVkZXJhdGlvbiBTZXJ2ZXJcbiAgICovXG4gIGdldEJpdEdvRmVkZXJhdGlvblNlcnZlcigpOiBzdGVsbGFyLkZlZGVyYXRpb25TZXJ2ZXIge1xuICAgIC8vIElkZW50aWZ5IHRoZSBVUkkgc2NoZW1lIGluIGNhc2Ugd2UgbmVlZCB0byBhbGxvdyBjb25uZWN0aW5nIHRvIEhUVFAgc2VydmVyLlxuICAgIGNvbnN0IGlzTm9uU2VjdXJlRW52ID0gIV8uc3RhcnRzV2l0aChjb21tb24uRW52aXJvbm1lbnRzW3RoaXMuYml0Z28uZW52XS51cmksICdodHRwcycpO1xuICAgIGNvbnN0IGZlZGVyYXRpb25TZXJ2ZXJPcHRpb25zID0geyBhbGxvd0h0dHA6IGlzTm9uU2VjdXJlRW52IH07XG4gICAgcmV0dXJuIG5ldyBzdGVsbGFyLkZlZGVyYXRpb25TZXJ2ZXIodGhpcy5nZXRGZWRlcmF0aW9uU2VydmVyVXJsKCksICdiaXRnby5jb20nLCBmZWRlcmF0aW9uU2VydmVyT3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUGVyZm9ybSBmZWRlcmF0aW9uIGxvb2t1cHNcbiAgICogT3VyIGZlZGVyYXRpb24gc2VydmVyIGhhbmRsZXMgbG9va3VwcyBmb3IgYml0Z28gYXMgd2VsbCBhcyBmb3Igb3RoZXIgZmVkZXJhdGlvbiBkb21haW5zXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBbYWRkcmVzc10gLSBhZGRyZXNzIHRvIGxvb2sgdXBcbiAgICogQHBhcmFtIHtTdHJpbmd9IFthY2NvdW50SWRdIC0gYWNjb3VudCBpZCB0byBsb29rIHVwXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZlZGVyYXRpb25Mb29rdXAoe1xuICAgIGFkZHJlc3MsXG4gICAgYWNjb3VudElkLFxuICB9OiB7XG4gICAgYWRkcmVzcz86IHN0cmluZztcbiAgICBhY2NvdW50SWQ/OiBzdHJpbmc7XG4gIH0pOiBQcm9taXNlPHN0ZWxsYXIuRmVkZXJhdGlvblNlcnZlci5SZWNvcmQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZmVkZXJhdGlvblNlcnZlciA9IHRoaXMuZ2V0Qml0R29GZWRlcmF0aW9uU2VydmVyKCk7XG4gICAgICBpZiAoYWRkcmVzcykge1xuICAgICAgICByZXR1cm4gYXdhaXQgZmVkZXJhdGlvblNlcnZlci5yZXNvbHZlQWRkcmVzcyhhZGRyZXNzKTtcbiAgICAgIH0gZWxzZSBpZiAoYWNjb3VudElkKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBmZWRlcmF0aW9uU2VydmVyLnJlc29sdmVBY2NvdW50SWQoYWNjb3VudElkKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBhcmd1bWVudCAtIG11c3QgcHJvdmlkZSBTdGVsbGFyIGFkZHJlc3Mgb3IgYWNjb3VudCBpZCcpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnN0IGVycm9yID0gXy5nZXQoZSwgJ3Jlc3BvbnNlLmRhdGEuZGV0YWlsJyk7XG4gICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgbmV3IFN0ZWxsYXJGZWRlcmF0aW9uVXNlck5vdEZvdW5kRXJyb3IoZXJyb3IpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXR0ZW1wdCB0byByZXNvbHZlIGEgc3RlbGxhciBhZGRyZXNzIGludG8gYSBzdGVsbGFyIGFjY291bnRcbiAgICpcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgLSBzdGVsbGFyIGFkZHJlc3MgdG8gbG9vayBmb3JcbiAgICovXG4gIGFzeW5jIGZlZGVyYXRpb25Mb29rdXBCeU5hbWUoYWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxzdGVsbGFyLkZlZGVyYXRpb25TZXJ2ZXIuUmVjb3JkPiB7XG4gICAgaWYgKCFhZGRyZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgU3RlbGxhciBhZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuZmVkZXJhdGlvbkxvb2t1cCh7IGFkZHJlc3MgfSk7XG4gIH1cblxuICAvKipcbiAgICogQXR0ZW1wdCB0byByZXNvbHZlIGFuIGFjY291bnQgaWQgaW50byBhIHN0ZWxsYXIgYWNjb3VudFxuICAgKiBPbmx5IHdvcmtzIGZvciBhY2NvdW50cyB0aGF0IGNhbiBiZSByZXNvbHZlZCBieSBvdXIgZmVkZXJhdGlvbiBzZXJ2ZXJcbiAgICpcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFjY291bnRJZCAtIHN0ZWxsYXIgYWNjb3VudCBpZFxuICAgKi9cbiAgYXN5bmMgZmVkZXJhdGlvbkxvb2t1cEJ5QWNjb3VudElkKGFjY291bnRJZDogc3RyaW5nKTogUHJvbWlzZTxzdGVsbGFyLkZlZGVyYXRpb25TZXJ2ZXIuUmVjb3JkPiB7XG4gICAgaWYgKCFhY2NvdW50SWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBTdGVsbGFyIGFjY291bnQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZmVkZXJhdGlvbkxvb2t1cCh7IGFjY291bnRJZCB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhZGRyZXNzIGlzIGEgdmFsaWQgWExNIGFkZHJlc3MsIGFuZCB0aGVuIG1ha2Ugc3VyZSBpdCBtYXRjaGVzIHRoZSByb290IGFkZHJlc3MuXG4gICAqXG4gICAqIEBwYXJhbSBhZGRyZXNzIHtTdHJpbmd9IHRoZSBhZGRyZXNzIHRvIHZlcmlmeVxuICAgKiBAcGFyYW0gcm9vdEFkZHJlc3Mge1N0cmluZ30gdGhlIHdhbGxldCdzIHJvb3QgYWRkcmVzc1xuICAgKi9cbiAgYXN5bmMgaXNXYWxsZXRBZGRyZXNzKHsgYWRkcmVzcywgcm9vdEFkZHJlc3MgfTogVmVyaWZ5QWRkcmVzc09wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAoIXRoaXMuaXNWYWxpZEFkZHJlc3MoYWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIGFkZHJlc3M6ICR7YWRkcmVzc31gKTtcbiAgICB9XG5cbiAgICBjb25zdCBhZGRyZXNzRGV0YWlscyA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMoYWRkcmVzcyk7XG4gICAgY29uc3Qgcm9vdEFkZHJlc3NEZXRhaWxzID0gdGhpcy5nZXRBZGRyZXNzRGV0YWlscyhyb290QWRkcmVzcyk7XG4gICAgaWYgKGFkZHJlc3NEZXRhaWxzLmJhc2VBZGRyZXNzICE9PSByb290QWRkcmVzc0RldGFpbHMuYWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IFVuZXhwZWN0ZWRBZGRyZXNzRXJyb3IoXG4gICAgICAgIGBhZGRyZXNzIHZhbGlkYXRpb24gZmFpbHVyZTogJHthZGRyZXNzRGV0YWlscy5iYXNlQWRkcmVzc30gdnMgJHtyb290QWRkcmVzc0RldGFpbHMuYWRkcmVzc31gXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBleHRyYSBwYXJhbWV0ZXJzIGZvciBwcmVidWlsZGluZyBhIHR4XG4gICAqIFNldCBlbXB0eSByZWNpcGllbnRzIGFycmF5IGluIHRydXN0bGluZSB0eHNcbiAgICovXG4gIGFzeW5jIGdldEV4dHJhUHJlYnVpbGRQYXJhbXMoYnVpbGRQYXJhbXM6IEV4dHJhUHJlYnVpbGRQYXJhbXNPcHRpb25zKTogUHJvbWlzZTxCdWlsZE9wdGlvbnM+IHtcbiAgICBjb25zdCBwYXJhbXM6IHsgcmVjaXBpZW50cz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz5bXSB9ID0ge307XG4gICAgaWYgKGJ1aWxkUGFyYW1zLnR5cGUgPT09ICd0cnVzdGxpbmUnKSB7XG4gICAgICBwYXJhbXMucmVjaXBpZW50cyA9IFtdO1xuICAgIH1cbiAgICByZXR1cm4gcGFyYW1zO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkXG4gICAqL1xuICBpbml0aWF0ZVJlY292ZXJ5KHBhcmFtczogUmVjb3ZlcnlPcHRpb25zKTogbmV2ZXIge1xuICAgIHRocm93IG5ldyBFcnJvcignZGVwcmVjYXRlZCBtZXRob2QnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgYSBmdW5kcyByZWNvdmVyeSB0cmFuc2FjdGlvbiB3aXRob3V0IEJpdEdvXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogLSB1c2VyS2V5OiBbZW5jcnlwdGVkXSBTdGVsbGFyIHByaXZhdGUga2V5XG4gICAqIC0gYmFja3VwS2V5OiBbZW5jcnlwdGVkXSBTdGVsbGFyIHByaXZhdGUga2V5LCBvciBwdWJsaWMga2V5IGlmIHRoZSBwcml2YXRlIGtleSBpcyBoZWxkIGJ5IGEgS1JTIHByb3ZpZGVyXG4gICAqIC0gd2FsbGV0UGFzc3BocmFzZTogbmVjZXNzYXJ5IGlmIG9uZSBvZiB0aGUgcHJpdmF0ZSBrZXlzIGlzIGVuY3J5cHRlZFxuICAgKiAtIHJvb3RBZGRyZXNzOiBiYXNlIGFkZHJlc3Mgb2YgdGhlIHdhbGxldCB0byByZWNvdmVyIGZ1bmRzIGZyb21cbiAgICogLSBrcnNQcm92aWRlcjogbmVjZXNzYXJ5IGlmIGJhY2t1cCBrZXkgaXMgaGVsZCBieSBLUlNcbiAgICogLSByZWNvdmVyeURlc3RpbmF0aW9uOiB0YXJnZXQgYWRkcmVzcyB0byBzZW5kIHJlY292ZXJlZCBmdW5kcyB0b1xuICAgKi9cbiAgYXN5bmMgcmVjb3ZlcihwYXJhbXM6IFJlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8UmVjb3ZlcnlUcmFuc2FjdGlvbj4ge1xuICAgIC8vIENoZWNrIGlmIHVuZW5jcnlwdGVkIHJvb3Qga2V5cyB3ZXJlIHByb3ZpZGVkLCBjb252ZXJ0IHRvIFN0ZWxsYXIgZm9ybWF0IGlmIG5lY2Vzc2FyeVxuICAgIGlmIChVdGlscy5pc1ZhbGlkUm9vdFByaXZhdGVLZXkocGFyYW1zLnVzZXJLZXkpKSB7XG4gICAgICBwYXJhbXMudXNlcktleSA9IFV0aWxzLmVuY29kZVByaXZhdGVLZXkoQnVmZmVyLmZyb20ocGFyYW1zLnVzZXJLZXkuc2xpY2UoMCwgNjQpLCAnaGV4JykpO1xuICAgIH0gZWxzZSBpZiAoVXRpbHMuaXNWYWxpZFJvb3RQdWJsaWNLZXkocGFyYW1zLnVzZXJLZXkpKSB7XG4gICAgICBwYXJhbXMudXNlcktleSA9IFV0aWxzLmVuY29kZVB1YmxpY0tleShCdWZmZXIuZnJvbShwYXJhbXMudXNlcktleSwgJ2hleCcpKTtcbiAgICB9XG5cbiAgICBpZiAoVXRpbHMuaXNWYWxpZFJvb3RQcml2YXRlS2V5KHBhcmFtcy5iYWNrdXBLZXkpKSB7XG4gICAgICBwYXJhbXMuYmFja3VwS2V5ID0gVXRpbHMuZW5jb2RlUHJpdmF0ZUtleShCdWZmZXIuZnJvbShwYXJhbXMuYmFja3VwS2V5LnNsaWNlKDAsIDY0KSwgJ2hleCcpKTtcbiAgICB9IGVsc2UgaWYgKFV0aWxzLmlzVmFsaWRSb290UHVibGljS2V5KHBhcmFtcy5iYWNrdXBLZXkpKSB7XG4gICAgICBwYXJhbXMuYmFja3VwS2V5ID0gVXRpbHMuZW5jb2RlUHVibGljS2V5KEJ1ZmZlci5mcm9tKHBhcmFtcy5iYWNrdXBLZXksICdoZXgnKSk7XG4gICAgfVxuXG4gICAgLy8gU3RlbGxhcidzIEVkMjU1MTkgcHVibGljIGtleXMgc3RhcnQgd2l0aCBhIEcsIHdoaWxlIHByaXZhdGUga2V5cyBzdGFydCB3aXRoIGFuIFNcbiAgICBjb25zdCBpc0tyc1JlY292ZXJ5ID0gcGFyYW1zLmJhY2t1cEtleS5zdGFydHNXaXRoKCdHJykgJiYgIXBhcmFtcy51c2VyS2V5LnN0YXJ0c1dpdGgoJ0cnKTtcbiAgICBjb25zdCBpc1Vuc2lnbmVkU3dlZXAgPSBwYXJhbXMuYmFja3VwS2V5LnN0YXJ0c1dpdGgoJ0cnKSAmJiBwYXJhbXMudXNlcktleS5zdGFydHNXaXRoKCdHJyk7XG5cbiAgICBpZiAoaXNLcnNSZWNvdmVyeSkge1xuICAgICAgY2hlY2tLcnNQcm92aWRlcih0aGlzLCBwYXJhbXMua3JzUHJvdmlkZXIpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKCdJbnZhbGlkIGRlc3RpbmF0aW9uIGFkZHJlc3MhJyk7XG4gICAgfVxuXG4gICAgY29uc3QgW3VzZXJLZXksIGJhY2t1cEtleV0gPSBnZXRTdGVsbGFyS2V5cyh0aGlzLmJpdGdvLCBwYXJhbXMpO1xuXG4gICAgaWYgKCFwYXJhbXMucm9vdEFkZHJlc3MgfHwgIXN0ZWxsYXIuU3RyS2V5LmlzVmFsaWRFZDI1NTE5UHVibGljS2V5KHBhcmFtcy5yb290QWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB3YWxsZXQgYWRkcmVzczogJHtwYXJhbXMucm9vdEFkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgYWNjb3VudERhdGFVcmwgPSBgJHt0aGlzLmdldEhvcml6b25VcmwoKX0vYWNjb3VudHMvJHtwYXJhbXMucm9vdEFkZHJlc3N9YDtcbiAgICBjb25zdCBkZXN0aW5hdGlvblVybCA9IGAke3RoaXMuZ2V0SG9yaXpvblVybCgpfS9hY2NvdW50cy8ke3BhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9ufWA7XG5cbiAgICBsZXQgYWNjb3VudERhdGE7XG4gICAgdHJ5IHtcbiAgICAgIGFjY291bnREYXRhID0gYXdhaXQgdG9CaXRnb1JlcXVlc3QocmVxdWVzdC5nZXQoYWNjb3VudERhdGFVcmwpKS5yZXN1bHQoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuYWJsZSB0byByZWFjaCB0aGUgU3RlbGxhciBuZXR3b3JrIHZpYSBIb3Jpem9uLicpO1xuICAgIH1cblxuICAgIC8vIE5vdyBjaGVjayBpZiB0aGUgZGVzdGluYXRpb24gYWNjb3VudCBpcyBlbXB0eSBvciBub3RcbiAgICBsZXQgdW5mdW5kZWREZXN0aW5hdGlvbiA9IGZhbHNlO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCByZXF1ZXN0LmdldChkZXN0aW5hdGlvblVybCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgaWYgKGUuc3RhdHVzID09PSA0MDQpIHtcbiAgICAgICAgLy8gSWYgdGhlIGRlc3RpbmF0aW9uIGFjY291bnQgZG9lcyBub3QgeWV0IGV4aXN0LCBob3Jpem9uIHJlc3BvbmRzIHdpdGggNDA0XG4gICAgICAgIHVuZnVuZGVkRGVzdGluYXRpb24gPSB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghYWNjb3VudERhdGEuc2VxdWVuY2UgfHwgIWFjY291bnREYXRhLmJhbGFuY2VzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0hvcml6b24gc2VydmVyIGVycm9yIC0gdW5hYmxlIHRvIHJldHJpZXZlIHNlcXVlbmNlIElEIG9yIGFjY291bnQgYmFsYW5jZScpO1xuICAgIH1cblxuICAgIGNvbnN0IGFjY291bnQgPSBuZXcgc3RlbGxhci5BY2NvdW50KHBhcmFtcy5yb290QWRkcmVzcywgYWNjb3VudERhdGEuc2VxdWVuY2UpO1xuXG4gICAgLy8gU3RlbGxhciBzdXBwb3J0cyBtdWx0aXBsZSBhc3NldHMgb24gY2hhaW4sIHdlJ3JlIG9ubHkgaW50ZXJlc3RlZCBpbiB0aGUgYmFsYW5jZXMgZW50cnkgd2hvc2UgdHlwZSBpcyBcIm5hdGl2ZVwiIChYTE0pXG4gICAgY29uc3QgbmF0aXZlQmFsYW5jZUluZm8gPSBhY2NvdW50RGF0YS5iYWxhbmNlcy5maW5kKChhc3NldEJhbGFuY2UpID0+IGFzc2V0QmFsYW5jZVsnYXNzZXRfdHlwZSddID09PSAnbmF0aXZlJyk7XG5cbiAgICBpZiAoIW5hdGl2ZUJhbGFuY2VJbmZvKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Byb3ZpZGVkIHdhbGxldCBoYXMgYSBiYWxhbmNlIG9mIDAgWExNLCByZWNvdmVyeSBhYm9ydGVkJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgd2FsbGV0QmFsYW5jZSA9IE51bWJlcih0aGlzLmJpZ1VuaXRzVG9CYXNlVW5pdHMobmF0aXZlQmFsYW5jZUluZm8uYmFsYW5jZSkpO1xuICAgIGNvbnN0IG1pbmltdW1SZXNlcnZlID0gYXdhaXQgdGhpcy5nZXRNaW5pbXVtUmVzZXJ2ZSgpO1xuICAgIGNvbnN0IGJhc2VUeEZlZSA9IGF3YWl0IHRoaXMuZ2V0QmFzZVRyYW5zYWN0aW9uRmVlKCk7XG4gICAgY29uc3QgcmVjb3ZlcnlBbW91bnQgPSB3YWxsZXRCYWxhbmNlIC0gbWluaW11bVJlc2VydmUgLSBiYXNlVHhGZWU7XG4gICAgY29uc3QgZm9ybWF0dGVkUmVjb3ZlcnlBbW91bnQgPSB0aGlzLmJhc2VVbml0c1RvQmlnVW5pdHMocmVjb3ZlcnlBbW91bnQpLnRvU3RyaW5nKCk7XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBuZXcgc3RlbGxhci5UcmFuc2FjdGlvbkJ1aWxkZXIoYWNjb3VudCwge1xuICAgICAgZmVlOiBiYXNlVHhGZWUudG9GaXhlZCgwKSxcbiAgICAgIG5ldHdvcmtQYXNzcGhyYXNlOiB0aGlzLmdldFN0ZWxsYXJOZXR3b3JrKCksXG4gICAgfSk7XG4gICAgY29uc3Qgb3BlcmF0aW9uID0gdW5mdW5kZWREZXN0aW5hdGlvblxuICAgICAgPyAvLyBJbiB0aGlzIGNhc2UsIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSBhY2NvdW50XG4gICAgICAgIHN0ZWxsYXIuT3BlcmF0aW9uLmNyZWF0ZUFjY291bnQoe1xuICAgICAgICAgIGRlc3RpbmF0aW9uOiBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgICAgICBzdGFydGluZ0JhbGFuY2U6IGZvcm1hdHRlZFJlY292ZXJ5QW1vdW50LFxuICAgICAgICB9KVxuICAgICAgOiAvLyBPdGhlcndpc2UgaWYgdGhlIGFjY291bnQgYWxyZWFkeSBleGlzdHMsIHdlIGRvIGEgbm9ybWFsIHNlbmRcbiAgICAgICAgc3RlbGxhci5PcGVyYXRpb24ucGF5bWVudCh7XG4gICAgICAgICAgZGVzdGluYXRpb246IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgICAgIGFzc2V0OiBzdGVsbGFyLkFzc2V0Lm5hdGl2ZSgpLFxuICAgICAgICAgIGFtb3VudDogZm9ybWF0dGVkUmVjb3ZlcnlBbW91bnQsXG4gICAgICAgIH0pO1xuICAgIGNvbnN0IHR4ID0gdHhCdWlsZGVyLmFkZE9wZXJhdGlvbihvcGVyYXRpb24pLnNldFRpbWVvdXQoc3RlbGxhci5UaW1lb3V0SW5maW5pdGUpLmJ1aWxkKCk7XG5cbiAgICBjb25zdCBmZWVJbmZvID0ge1xuICAgICAgZmVlOiBuZXcgQmlnTnVtYmVyKHR4LmZlZSkudG9OdW1iZXIoKSxcbiAgICAgIGZlZVN0cmluZzogdHguZmVlLFxuICAgIH07XG5cbiAgICBpZiAoIWlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgdHguc2lnbih1c2VyS2V5KTtcbiAgICB9XG5cbiAgICBpZiAoIWlzS3JzUmVjb3ZlcnkgJiYgIWlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgdHguc2lnbihiYWNrdXBLZXkpO1xuICAgIH1cblxuICAgIGNvbnN0IHRyYW5zYWN0aW9uOiBSZWNvdmVyeVRyYW5zYWN0aW9uID0ge1xuICAgICAgdHhCYXNlNjQ6IFhsbS50eFRvU3RyaW5nKHR4KSxcbiAgICAgIHJlY292ZXJ5QW1vdW50LFxuICAgIH07XG5cbiAgICBpZiAoaXNLcnNSZWNvdmVyeSkge1xuICAgICAgdHJhbnNhY3Rpb24uYmFja3VwS2V5ID0gcGFyYW1zLmJhY2t1cEtleTtcbiAgICB9XG5cbiAgICB0cmFuc2FjdGlvbi5jb2luID0gdGhpcy5nZXRDaGFpbigpO1xuICAgIHRyYW5zYWN0aW9uLmZlZUluZm8gPSBmZWVJbmZvO1xuXG4gICAgcmV0dXJuIHRyYW5zYWN0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIGtleWNoYWluIGFuZCBoYWxmLXNpZ24gcHJlYnVpbHQgdHJhbnNhY3Rpb25cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKiBAcGFyYW0gcGFyYW1zLnR4UHJlYnVpbGQge09iamVjdH0gcHJlYnVpbGQgb2JqZWN0IHJldHVybmVkIGJ5IHBsYXRmb3JtXG4gICAqIEBwYXJhbSBwYXJhbXMucHJ2IHtTdHJpbmd9IHVzZXIgcHJ2XG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEhhbGZTaWduZWRUcmFuc2FjdGlvbj59XG4gICAqL1xuICBhc3luYyBzaWduVHJhbnNhY3Rpb24ocGFyYW1zOiBTaWduVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxIYWxmU2lnbmVkVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCB7IHR4UHJlYnVpbGQsIHBydiB9ID0gcGFyYW1zO1xuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQodHhQcmVidWlsZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyB0eFByZWJ1aWxkIHBhcmFtZXRlcicpO1xuICAgIH1cbiAgICBpZiAoIV8uaXNPYmplY3QodHhQcmVidWlsZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdHhQcmVidWlsZCBtdXN0IGJlIGFuIG9iamVjdCwgZ290IHR5cGUgJHt0eXBlb2YgdHhQcmVidWlsZH1gKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwcnYpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcHJ2IHBhcmFtZXRlciB0byBzaWduIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuICAgIGlmICghXy5pc1N0cmluZyhwcnYpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHBydiBtdXN0IGJlIGEgc3RyaW5nLCBnb3QgdHlwZSAke3R5cGVvZiBwcnZ9YCk7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5UGFpciA9IFV0aWxzLmNyZWF0ZVN0ZWxsYXJLZXlwYWlyRnJvbVBydihwcnYpO1xuICAgIGNvbnN0IHR4ID0gbmV3IHN0ZWxsYXIuVHJhbnNhY3Rpb24odHhQcmVidWlsZC50eEJhc2U2NCwgdGhpcy5nZXRTdGVsbGFyTmV0d29yaygpKTtcbiAgICB0eC5zaWduKGtleVBhaXIpO1xuICAgIGNvbnN0IHR4QmFzZTY0ID0gWGxtLnR4VG9TdHJpbmcodHgpO1xuXG4gICAgY29uc3QgdHlwZSA9IHR4UHJlYnVpbGQ/LmJ1aWxkUGFyYW1zPy50eXBlO1xuICAgIGNvbnN0IHJlY2lwaWVudHMgPSB0eFByZWJ1aWxkPy5idWlsZFBhcmFtcz8ucmVjaXBpZW50cztcbiAgICBpZiAodHlwZSA9PT0gJ2VuYWJsZXRva2VuJykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaGFsZlNpZ25lZDogeyB0eEJhc2U2NCB9LFxuICAgICAgICB0eXBlLFxuICAgICAgICByZWNpcGllbnRzLFxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHsgaGFsZlNpZ25lZDogeyB0eEJhc2U2NCB9IH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEV4dGVuZCB3YWxsZXRQYXJhbXMgd2l0aCBleHRyYSBwYXJhbXMgcmVxdWlyZWQgZm9yIGdlbmVyYXRpbmcgYW4gWExNIHdhbGxldFxuICAgKlxuICAgKiBTdGVsbGFyIHdhbGxldHMgaGF2ZSB0aHJlZSBrZXljaGFpbnMgb24gdGhlbS4gVHdvIGFyZSBnZW5lcmF0ZWQgYnkgdGhlIHBsYXRmb3JtLCBhbmQgdGhlIGxhc3QgaXMgZ2VuZXJhdGVkIGJ5IHRoZSB1c2VyLlxuICAgKiBJbml0aWFsbHksIHdlIG5lZWQgYSByb290IHBydiB0byBnZW5lcmF0ZSB0aGUgYWNjb3VudCwgd2hpY2ggbXVzdCBiZSBkaXN0aW5jdCBmcm9tIGFsbCB0aHJlZSBrZXljaGFpbnMgb24gdGhlIHdhbGxldC5cbiAgICogSWYgYSByb290IHBydiBpcyBub3QgcHJvdmlkZWQsIGEgcmFuZG9tIG9uZSBpcyBnZW5lcmF0ZWQuXG4gICAqL1xuICBhc3luYyBzdXBwbGVtZW50R2VuZXJhdGVXYWxsZXQoXG4gICAgd2FsbGV0UGFyYW1zOiBTdXBwbGVtZW50R2VuZXJhdGVXYWxsZXRPcHRpb25zXG4gICk6IFByb21pc2U8U3VwcGxlbWVudEdlbmVyYXRlV2FsbGV0T3B0aW9ucz4ge1xuICAgIGxldCBzZWVkO1xuICAgIGNvbnN0IHJvb3RQcnYgPSB3YWxsZXRQYXJhbXMucm9vdFByaXZhdGVLZXk7XG4gICAgaWYgKHJvb3RQcnYpIHtcbiAgICAgIGlmICghdGhpcy5pc1ZhbGlkUHJ2KHJvb3RQcnYpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigncm9vdFByaXZhdGVLZXkgbmVlZHMgdG8gYmUgdmFsaWQgZWQyNTUxOSBzZWNyZXQgc2VlZCcpO1xuICAgICAgfVxuICAgICAgc2VlZCA9IHN0ZWxsYXIuU3RyS2V5LmRlY29kZUVkMjU1MTlTZWNyZXRTZWVkKHJvb3RQcnYpO1xuICAgIH1cbiAgICBjb25zdCBrZXlQYWlyID0gdGhpcy5nZW5lcmF0ZUtleVBhaXIoc2VlZCk7XG4gICAgLy8gZXh0ZW5kIHRoZSB3YWxsZXQgaW5pdGlhbGl6YXRpb24gcGFyYW1zXG4gICAgd2FsbGV0UGFyYW1zLnJvb3RQcml2YXRlS2V5ID0ga2V5UGFpci5wcnY7XG4gICAgcmV0dXJuIHdhbGxldFBhcmFtcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTaWduIG1lc3NhZ2Ugd2l0aCBwcml2YXRlIGtleVxuICAgKlxuICAgKiBAcGFyYW0ga2V5XG4gICAqIEBwYXJhbSBtZXNzYWdlXG4gICAqL1xuICBhc3luYyBzaWduTWVzc2FnZShrZXk6IEtleVBhaXIsIG1lc3NhZ2U6IHN0cmluZyB8IEJ1ZmZlcik6IFByb21pc2U8QnVmZmVyPiB7XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRQcnYoa2V5LnBydikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBwcnY6ICR7a2V5LnBydn1gKTtcbiAgICB9XG4gICAgaWYgKCFCdWZmZXIuaXNCdWZmZXIobWVzc2FnZSkpIHtcbiAgICAgIG1lc3NhZ2UgPSBCdWZmZXIuZnJvbShtZXNzYWdlKTtcbiAgICB9XG5cbiAgICBjb25zdCBrZXlwYWlyID0gVXRpbHMuY3JlYXRlU3RlbGxhcktleXBhaXJGcm9tUHJ2KGtleS5wcnYpO1xuICAgIHJldHVybiBrZXlwYWlyLnNpZ24obWVzc2FnZSk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpZXMgaWYgc2lnbmF0dXJlIGZvciBtZXNzYWdlIGlzIHZhbGlkLlxuICAgKlxuICAgKiBAcGFyYW0gcHViIHB1YmxpYyBrZXlcbiAgICogQHBhcmFtIG1lc3NhZ2Ugc2lnbmVkIG1lc3NhZ2VcbiAgICogQHBhcmFtIHNpZ25hdHVyZSBzaWduYXR1cmUgdG8gdmVyaWZ5XG4gICAqIEByZXR1cm5zIHRydWUgaWYgc2lnbmF0dXJlIGlzIHZhbGlkLlxuICAgKi9cbiAgdmVyaWZ5U2lnbmF0dXJlKHB1Yjogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcgfCBCdWZmZXIsIHNpZ25hdHVyZTogQnVmZmVyKSB7XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRQdWIocHViKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIHB1YjogJHtwdWJ9YCk7XG4gICAgfVxuICAgIGlmICghQnVmZmVyLmlzQnVmZmVyKG1lc3NhZ2UpKSB7XG4gICAgICBtZXNzYWdlID0gQnVmZmVyLmZyb20obWVzc2FnZSk7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5UGFpciA9IFV0aWxzLmNyZWF0ZVN0ZWxsYXJLZXlwYWlyRnJvbVB1YihwdWIpO1xuICAgIHJldHVybiBrZXlQYWlyLnZlcmlmeShtZXNzYWdlLCBzaWduYXR1cmUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cGxhaW4vcGFyc2UgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgZXhwbGFpblRyYW5zYWN0aW9uKHBhcmFtczogRXhwbGFpblRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8VHJhbnNhY3Rpb25FeHBsYW5hdGlvbj4ge1xuICAgIGNvbnN0IHsgdHhIZXgsIHR4QmFzZTY0IH0gPSBwYXJhbXM7XG4gICAgbGV0IHR4OiBzdGVsbGFyLlRyYW5zYWN0aW9uIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuXG4gICAgaWYgKCF0eEhleCAmJiAhdHhCYXNlNjQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXhwbGFpblRyYW5zYWN0aW9uIG1pc3NpbmcgdHhIZXggb3IgdHhCYXNlNjQgcGFyYW1ldGVyLCBtdXN0IGhhdmUgYXQgbGVhc3Qgb25lJyk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGlmICh0eEhleCkge1xuICAgICAgICB0eCA9IG5ldyBzdGVsbGFyLlRyYW5zYWN0aW9uKEJ1ZmZlci5mcm9tKHR4SGV4LCAnaGV4JykudG9TdHJpbmcoJ2Jhc2U2NCcpLCB0aGlzLmdldFN0ZWxsYXJOZXR3b3JrKCkpO1xuICAgICAgfSBlbHNlIGlmICh0eEJhc2U2NCkge1xuICAgICAgICB0eCA9IG5ldyBzdGVsbGFyLlRyYW5zYWN0aW9uKHR4QmFzZTY0LCB0aGlzLmdldFN0ZWxsYXJOZXR3b3JrKCkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndHhCYXNlNjQgbmVlZHMgdG8gYmUgYSB2YWxpZCB0eCBlbmNvZGVkIGFzIGJhc2U2NCBzdHJpbmcnKTtcbiAgICB9XG5cbiAgICBpZiAoIXR4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4IG5lZWRzIHRvIGJlIGRlZmluZWQgaW4gb3JkZXIgdG8gZXhwbGFpbiB0cmFuc2FjdGlvbicpO1xuICAgIH1cbiAgICBjb25zdCBpZCA9IHR4Lmhhc2goKS50b1N0cmluZygnaGV4Jyk7XG5cbiAgICAvLyBJbiBhIFN0ZWxsYXIgdHgsIHRoZSBfbWVtbyBwcm9wZXJ0eSBpcyBhbiBvYmplY3Qgd2l0aCB0aGUgbWV0aG9kczpcbiAgICAvLyB2YWx1ZSgpIGFuZCBhcm0oKSB0aGF0IHByb3ZpZGUgbWVtbyB2YWx1ZSBhbmQgdHlwZSwgcmVzcGVjdGl2ZWx5LlxuICAgIGNvbnN0IG1lbW86IFRyYW5zYWN0aW9uTWVtbyA9XG4gICAgICBfLnJlc3VsdCh0eCwgJ19tZW1vLnZhbHVlJykgJiYgXy5yZXN1bHQodHgsICdfbWVtby5hcm0nKVxuICAgICAgICA/IHtcbiAgICAgICAgICAgIHZhbHVlOiAoXy5yZXN1bHQodHgsICdfbWVtby52YWx1ZScpIGFzIGFueSkudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIHR5cGU6IF8ucmVzdWx0KHR4LCAnX21lbW8uYXJtJyksXG4gICAgICAgICAgfVxuICAgICAgICA6IHt9O1xuXG4gICAgbGV0IHNwZW5kQW1vdW50ID0gbmV3IEJpZ051bWJlcigwKTsgLy8gYW1vdW50IG9mIFhMTSB1c2VkIGluIFhMTS1vbmx5IHR4c1xuICAgIGNvbnN0IHNwZW5kQW1vdW50cyA9IHt9OyAvLyB0cmFjayBib3RoIHhsbSBhbmQgdG9rZW4gYW1vdW50c1xuICAgIGlmIChfLmlzRW1wdHkodHgub3BlcmF0aW9ucykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBvcGVyYXRpb25zJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgb3V0cHV0czogVHJhbnNhY3Rpb25PdXRwdXRbXSA9IFtdO1xuICAgIGNvbnN0IG9wZXJhdGlvbnM6IFRyYW5zYWN0aW9uT3BlcmF0aW9uW10gPSBbXTsgLy8gbm9uLXBheW1lbnQgb3BlcmF0aW9uc1xuXG4gICAgXy5mb3JFYWNoKHR4Lm9wZXJhdGlvbnMsIChvcDogc3RlbGxhci5PcGVyYXRpb24pID0+IHtcbiAgICAgIGlmIChvcC50eXBlID09PSAnY3JlYXRlQWNjb3VudCcgfHwgb3AudHlwZSA9PT0gJ3BheW1lbnQnKSB7XG4gICAgICAgIC8vIFRPRE8gUmVtb3ZlIG1lbW9JZCBmcm9tIGFkZHJlc3NcbiAgICAgICAgLy8gR2V0IG1lbW8gdG8gYXR0YWNoIHRvIGFkZHJlc3MsIGlmIHR5cGUgaXMgJ2lkJ1xuICAgICAgICBjb25zdCBtZW1vSWQgPSBfLmdldChtZW1vLCAndHlwZScpID09PSAnaWQnICYmICFfLmdldChtZW1vLCAndmFsdWUnKSA/IGA/bWVtb0lkPSR7bWVtby52YWx1ZX1gIDogJyc7XG4gICAgICAgIGxldCBhc3NldDtcbiAgICAgICAgaWYgKG9wLnR5cGUgPT09ICdwYXltZW50Jykge1xuICAgICAgICAgIGlmIChvcC5hc3NldC5nZXRBc3NldFR5cGUoKSA9PT0gJ2xpcXVpZGl0eV9wb29sX3NoYXJlcycpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBhc3NldCB0eXBlJyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGFzc2V0ID0gb3AuYXNzZXQgYXMgc3RlbGxhci5Bc3NldDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhc3NldCA9IHN0ZWxsYXIuQXNzZXQubmF0aXZlKCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY29pbiA9IHRoaXMuZ2V0VG9rZW5OYW1lRnJvbVN0ZWxsYXJBc3NldChhc3NldCk7IC8vIGNvaW4gb3IgdG9rZW4gaWRcbiAgICAgICAgY29uc3Qgb3V0cHV0OiBUcmFuc2FjdGlvbk91dHB1dCA9IHtcbiAgICAgICAgICBhbW91bnQ6IHRoaXMuYmlnVW5pdHNUb0Jhc2VVbml0cyhcbiAgICAgICAgICAgIChvcCBhcyBzdGVsbGFyLk9wZXJhdGlvbi5DcmVhdGVBY2NvdW50KS5zdGFydGluZ0JhbGFuY2UgfHwgKG9wIGFzIHN0ZWxsYXIuT3BlcmF0aW9uLlBheW1lbnQpLmFtb3VudFxuICAgICAgICAgICksXG4gICAgICAgICAgYWRkcmVzczogb3AuZGVzdGluYXRpb24gKyBtZW1vSWQsXG4gICAgICAgICAgY29pbixcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoIV8uaXNVbmRlZmluZWQoc3BlbmRBbW91bnRzW2NvaW5dKSkge1xuICAgICAgICAgIHNwZW5kQW1vdW50c1tjb2luXSA9IHNwZW5kQW1vdW50c1tjb2luXS5wbHVzKG91dHB1dC5hbW91bnQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNwZW5kQW1vdW50c1tjb2luXSA9IG5ldyBCaWdOdW1iZXIob3V0cHV0LmFtb3VudCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGFzc2V0LmlzTmF0aXZlKCkpIHtcbiAgICAgICAgICBzcGVuZEFtb3VudCA9IHNwZW5kQW1vdW50LnBsdXMob3V0cHV0LmFtb3VudCk7XG4gICAgICAgIH1cbiAgICAgICAgb3V0cHV0cy5wdXNoKG91dHB1dCk7XG4gICAgICB9IGVsc2UgaWYgKG9wLnR5cGUgPT09ICdjaGFuZ2VUcnVzdCcpIHtcbiAgICAgICAgaWYgKG9wLmxpbmUuZ2V0QXNzZXRUeXBlKCkgPT09ICdsaXF1aWRpdHlfcG9vbF9zaGFyZXMnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFzc2V0IHR5cGUnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBhc3NldCA9IG9wLmxpbmUgYXMgc3RlbGxhci5Bc3NldDtcblxuICAgICAgICBvcGVyYXRpb25zLnB1c2goe1xuICAgICAgICAgIHR5cGU6IG9wLnR5cGUsXG4gICAgICAgICAgY29pbjogdGhpcy5nZXRUb2tlbk5hbWVGcm9tU3RlbGxhckFzc2V0KGFzc2V0KSxcbiAgICAgICAgICBhc3NldCxcbiAgICAgICAgICBsaW1pdDogdGhpcy5iaWdVbml0c1RvQmFzZVVuaXRzKG9wLmxpbWl0KSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBjb25zdCBvdXRwdXRBbW91bnQgPSBzcGVuZEFtb3VudC50b0ZpeGVkKDApO1xuICAgIGNvbnN0IG91dHB1dEFtb3VudHMgPSBfLm1hcFZhbHVlcyhzcGVuZEFtb3VudHMsIChhbW91bnQ6IEJpZ051bWJlcikgPT4gYW1vdW50LnRvRml4ZWQoMCkpO1xuICAgIGNvbnN0IGZlZSA9IHtcbiAgICAgIGZlZTogbmV3IEJpZ051bWJlcih0eC5mZWUpLnRvRml4ZWQoMCksXG4gICAgICBmZWVSYXRlOiBudWxsLFxuICAgICAgc2l6ZTogbnVsbCxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRpc3BsYXlPcmRlcjogW1xuICAgICAgICAnaWQnLFxuICAgICAgICAnb3V0cHV0QW1vdW50JyxcbiAgICAgICAgJ291dHB1dEFtb3VudHMnLFxuICAgICAgICAnY2hhbmdlQW1vdW50JyxcbiAgICAgICAgJ291dHB1dHMnLFxuICAgICAgICAnY2hhbmdlT3V0cHV0cycsXG4gICAgICAgICdmZWUnLFxuICAgICAgICAnbWVtbycsXG4gICAgICAgICdvcGVyYXRpb25zJyxcbiAgICAgIF0sXG4gICAgICBpZCxcbiAgICAgIG91dHB1dHMsXG4gICAgICBvdXRwdXRBbW91bnQsXG4gICAgICBvdXRwdXRBbW91bnRzLFxuICAgICAgY2hhbmdlT3V0cHV0czogW10sXG4gICAgICBjaGFuZ2VBbW91bnQ6ICcwJyxcbiAgICAgIG1lbW8sXG4gICAgICBmZWUsXG4gICAgICBvcGVyYXRpb25zLFxuICAgIH0gYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmeSB0aGF0IGEgdHggcHJlYnVpbGQncyBvcGVyYXRpb25zIGNvbXBseSB3aXRoIHRoZSBvcmlnaW5hbCBpbnRlbnRpb25cbiAgICogQHBhcmFtIHtzdGVsbGFyLk9wZXJhdGlvbn0gb3BlcmF0aW9ucyAtIHR4IG9wZXJhdGlvbnNcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvblBhcmFtc30gdHhQYXJhbXMgLSBwYXJhbXMgdXNlZCB0byBidWlsZCB0aGUgdHhcbiAgICovXG4gIHZlcmlmeUVuYWJsZVRva2VuVHhPcGVyYXRpb25zKG9wZXJhdGlvbnM6IHN0ZWxsYXIuT3BlcmF0aW9uW10sIHR4UGFyYW1zOiBUcmFuc2FjdGlvblBhcmFtcyk6IHZvaWQge1xuICAgIGNvbnN0IHRydXN0bGluZU9wZXJhdGlvbnMgPSBfLmZpbHRlcihvcGVyYXRpb25zLCBbJ3R5cGUnLCAnY2hhbmdlVHJ1c3QnXSkgYXMgc3RlbGxhci5PcGVyYXRpb24uQ2hhbmdlVHJ1c3RbXTtcbiAgICBpZiAodHJ1c3RsaW5lT3BlcmF0aW9ucy5sZW5ndGggIT09IF8uZ2V0KHR4UGFyYW1zLCAncmVjaXBpZW50cycsIFtdKS5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndHJhbnNhY3Rpb24gcHJlYnVpbGQgZG9lcyBub3QgbWF0Y2ggZXhwZWN0ZWQgdHJ1c3RsaW5lIG9wZXJhdGlvbnMnKTtcbiAgICB9XG4gICAgXy5mb3JFYWNoKHRydXN0bGluZU9wZXJhdGlvbnMsIChvcDogc3RlbGxhci5PcGVyYXRpb24pID0+IHtcbiAgICAgIGlmIChvcC50eXBlICE9PSAnY2hhbmdlVHJ1c3QnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBhc3NldCB0eXBlJyk7XG4gICAgICB9XG4gICAgICBpZiAob3AubGluZS5nZXRBc3NldFR5cGUoKSA9PT0gJ2xpcXVpZGl0eV9wb29sX3NoYXJlcycpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFzc2V0IHR5cGUnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGFzc2V0ID0gb3AubGluZSBhcyBzdGVsbGFyLkFzc2V0O1xuICAgICAgY29uc3Qgb3BUb2tlbiA9IHRoaXMuZ2V0VG9rZW5OYW1lRnJvbVN0ZWxsYXJBc3NldChhc3NldCk7XG4gICAgICBjb25zdCB0b2tlblRydXN0bGluZSA9IF8uZmluZCh0eFBhcmFtcy5yZWNpcGllbnRzLCAocmVjaXBpZW50KSA9PiB7XG4gICAgICAgIC8vIHRydXN0bGluZSBwYXJhbXMgdXNlIGxpbWl0cyBpbiBiYXNlIHVuaXRzXG4gICAgICAgIGNvbnN0IG9wTGltaXRCYXNlVW5pdHMgPSB0aGlzLmJpZ1VuaXRzVG9CYXNlVW5pdHMob3AubGltaXQpO1xuICAgICAgICAvLyBFbmFibGUgdG9rZW4gbGltaXQgaXMgc2V0IHRvIFhsbS5tYXhUcnVzdGxpbmVMaW1pdCBieSBkZWZhdWx0XG4gICAgICAgIHJldHVybiByZWNpcGllbnQudG9rZW5OYW1lID09PSBvcFRva2VuICYmIG9wTGltaXRCYXNlVW5pdHMgPT09IFhsbS5tYXhUcnVzdGxpbmVMaW1pdDtcbiAgICAgIH0pO1xuICAgICAgaWYgKCF0b2tlblRydXN0bGluZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RyYW5zYWN0aW9uIHByZWJ1aWxkIGRvZXMgbm90IG1hdGNoIGV4cGVjdGVkIHRydXN0bGluZSB0b2tlbnMnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgdGhhdCBhIHR4IHByZWJ1aWxkJ3Mgb3BlcmF0aW9ucyBjb21wbHkgd2l0aCB0aGUgb3JpZ2luYWwgaW50ZW50aW9uXG4gICAqIEBwYXJhbSB7c3RlbGxhci5PcGVyYXRpb259IG9wZXJhdGlvbnMgLSB0eCBvcGVyYXRpb25zXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb25QYXJhbXN9IHR4UGFyYW1zIC0gcGFyYW1zIHVzZWQgdG8gYnVpbGQgdGhlIHR4XG4gICAqL1xuICB2ZXJpZnlUcnVzdGxpbmVUeE9wZXJhdGlvbnMob3BlcmF0aW9uczogc3RlbGxhci5PcGVyYXRpb25bXSwgdHhQYXJhbXM6IFRyYW5zYWN0aW9uUGFyYW1zKTogdm9pZCB7XG4gICAgY29uc3QgdHJ1c3RsaW5lT3BlcmF0aW9ucyA9IF8uZmlsdGVyKG9wZXJhdGlvbnMsIFsndHlwZScsICdjaGFuZ2VUcnVzdCddKSBhcyBzdGVsbGFyLk9wZXJhdGlvbi5DaGFuZ2VUcnVzdFtdO1xuICAgIGlmICh0cnVzdGxpbmVPcGVyYXRpb25zLmxlbmd0aCAhPT0gXy5nZXQodHhQYXJhbXMsICd0cnVzdGxpbmVzJywgW10pLmxlbmd0aCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd0cmFuc2FjdGlvbiBwcmVidWlsZCBkb2VzIG5vdCBtYXRjaCBleHBlY3RlZCB0cnVzdGxpbmUgb3BlcmF0aW9ucycpO1xuICAgIH1cbiAgICBfLmZvckVhY2godHJ1c3RsaW5lT3BlcmF0aW9ucywgKG9wOiBzdGVsbGFyLk9wZXJhdGlvbikgPT4ge1xuICAgICAgaWYgKG9wLnR5cGUgIT09ICdjaGFuZ2VUcnVzdCcpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFzc2V0IHR5cGUnKTtcbiAgICAgIH1cbiAgICAgIGlmIChvcC5saW5lLmdldEFzc2V0VHlwZSgpID09PSAnbGlxdWlkaXR5X3Bvb2xfc2hhcmVzJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgYXNzZXQgdHlwZScpO1xuICAgICAgfVxuICAgICAgY29uc3QgYXNzZXQgPSBvcC5saW5lIGFzIHN0ZWxsYXIuQXNzZXQ7XG4gICAgICBjb25zdCBvcFRva2VuID0gdGhpcy5nZXRUb2tlbk5hbWVGcm9tU3RlbGxhckFzc2V0KGFzc2V0KTtcbiAgICAgIGNvbnN0IHRva2VuVHJ1c3RsaW5lID0gXy5maW5kKHR4UGFyYW1zLnRydXN0bGluZXMsICh0cnVzdGxpbmUpID0+IHtcbiAgICAgICAgLy8gdHJ1c3RsaW5lIHBhcmFtcyB1c2UgbGltaXRzIGluIGJhc2UgdW5pdHNcbiAgICAgICAgY29uc3Qgb3BMaW1pdEJhc2VVbml0cyA9IHRoaXMuYmlnVW5pdHNUb0Jhc2VVbml0cyhvcC5saW1pdCk7XG4gICAgICAgIC8vIFByZXBhcmUgdGhlIGNvbmRpdGlvbnMgdG8gY2hlY2sgZm9yXG4gICAgICAgIC8vIExpbWl0IHdpbGwgYWx3YXlzIGJlIHNldCBpbiB0aGUgb3BlcmF0aW9uLCBldmVuIGlmIGl0IHdhcyBvbWl0dGVkIGZyb20gdHhQYXJhbXMgaW4gdGhlIGZvbGxvd2luZyBjYXNlczpcbiAgICAgICAgLy8gMS4gQWN0aW9uIGlzICdhZGQnIC0gbGltaXQgaXMgc2V0IHRvIFhsbS5tYXhUcnVzdGxpbmVMaW1pdCBieSBkZWZhdWx0XG4gICAgICAgIC8vIDIuIEFjdGlvbiBpcyAncmVtb3ZlJyAtIGxpbWl0IGlzIHNldCB0byAnMCdcbiAgICAgICAgY29uc3Qgbm9MaW1pdCA9IF8uaXNVbmRlZmluZWQodHJ1c3RsaW5lLmxpbWl0KTtcbiAgICAgICAgY29uc3QgYWRkVHJ1c3RsaW5lV2l0aERlZmF1bHRMaW1pdCA9IHRydXN0bGluZS5hY3Rpb24gPT09ICdhZGQnICYmIG9wTGltaXRCYXNlVW5pdHMgPT09IFhsbS5tYXhUcnVzdGxpbmVMaW1pdDtcbiAgICAgICAgY29uc3QgcmVtb3ZlVHJ1c3RsaW5lID0gdHJ1c3RsaW5lLmFjdGlvbiA9PT0gJ3JlbW92ZScgJiYgb3BMaW1pdEJhc2VVbml0cyA9PT0gJzAnO1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIHRydXN0bGluZS50b2tlbiA9PT0gb3BUb2tlbiAmJlxuICAgICAgICAgICh0cnVzdGxpbmUubGltaXQgPT09IG9wTGltaXRCYXNlVW5pdHMgfHwgKG5vTGltaXQgJiYgKGFkZFRydXN0bGluZVdpdGhEZWZhdWx0TGltaXQgfHwgcmVtb3ZlVHJ1c3RsaW5lKSkpXG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgICAgIGlmICghdG9rZW5UcnVzdGxpbmUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0cmFuc2FjdGlvbiBwcmVidWlsZCBkb2VzIG5vdCBtYXRjaCBleHBlY3RlZCB0cnVzdGxpbmUgdG9rZW5zJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IHRoYXQgYSB0cmFuc2FjdGlvbiBwcmVidWlsZCBjb21wbGllcyB3aXRoIHRoZSBvcmlnaW5hbCBpbnRlbnRpb25cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnNcbiAgICogQHBhcmFtIG9wdGlvbnMudHhQcmVidWlsZCBwcmVidWlsZCBvYmplY3QgcmV0dXJuZWQgYnkgcGxhdGZvcm1cbiAgICogQHBhcmFtIG9wdGlvbnMudHhQcmVidWlsZC50eEJhc2U2NCBwcmVidWlsdCB0cmFuc2FjdGlvbiBlbmNvZGVkIGFzIGJhc2U2NCBzdHJpbmdcbiAgICogQHBhcmFtIG9wdGlvbnMud2FsbGV0IHdhbGxldCBvYmplY3QgdG8gb2J0YWluIGtleXMgdG8gdmVyaWZ5IGFnYWluc3RcbiAgICogQHBhcmFtIG9wdGlvbnMudmVyaWZpY2F0aW9uIHNwZWNpZnlpbmcgc29tZSB2ZXJpZmljYXRpb24gcGFyYW1ldGVyc1xuICAgKiBAcGFyYW0gb3B0aW9ucy52ZXJpZmljYXRpb24uZGlzYWJsZU5ldHdvcmtpbmcgRGlzYWxsb3cgZmV0Y2hpbmcgYW55IGRhdGEgZnJvbSB0aGUgaW50ZXJuZXQgZm9yIHZlcmlmaWNhdGlvbiBwdXJwb3Nlc1xuICAgKiBAcGFyYW0gb3B0aW9ucy52ZXJpZmljYXRpb24ua2V5Y2hhaW5zIFBhc3Mga2V5Y2hhaW5zIG1hbnVhbGx5IHJhdGhlciB0aGFuIGZldGNoaW5nIHRoZW0gYnkgaWRcbiAgICovXG4gIGFzeW5jIHZlcmlmeVRyYW5zYWN0aW9uKG9wdGlvbnM6IFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIC8vIFRPRE8gQkctNTYwMCBBZGQgcGFyc2VUcmFuc2FjdGlvbiAvIGltcHJvdmUgdmVyaWZpY2F0aW9uXG4gICAgY29uc3QgeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0LCB2ZXJpZmljYXRpb24gPSB7fSB9ID0gb3B0aW9ucztcbiAgICBjb25zdCBkaXNhYmxlTmV0d29ya2luZyA9ICEhdmVyaWZpY2F0aW9uLmRpc2FibGVOZXR3b3JraW5nO1xuXG4gICAgaWYgKCF0eFByZWJ1aWxkLnR4QmFzZTY0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgdHggcHJlYnVpbGQgcHJvcGVydHkgdHhCYXNlNjQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB0eCA9IG5ldyBzdGVsbGFyLlRyYW5zYWN0aW9uKHR4UHJlYnVpbGQudHhCYXNlNjQsIHRoaXMuZ2V0U3RlbGxhck5ldHdvcmsoKSk7XG5cbiAgICBpZiAodHhQYXJhbXMucmVjaXBpZW50cyAmJiB0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2Fubm90IHNwZWNpZnkgbW9yZSB0aGFuIDEgcmVjaXBpZW50Jyk7XG4gICAgfVxuXG4gICAgLy8gU3RlbGxhciB0eHMgYXJlIG1hZGUgdXAgb2Ygb3BlcmF0aW9ucy4gV2Ugb25seSBjYXJlIGFib3V0IENyZWF0ZSBBY2NvdW50IGFuZCBQYXltZW50IGZvciBzZW5kaW5nIGZ1bmRzLlxuICAgIGNvbnN0IG91dHB1dE9wZXJhdGlvbnMgPSBfLmZpbHRlcihcbiAgICAgIHR4Lm9wZXJhdGlvbnMsXG4gICAgICAob3BlcmF0aW9uKSA9PiBvcGVyYXRpb24udHlwZSA9PT0gJ2NyZWF0ZUFjY291bnQnIHx8IG9wZXJhdGlvbi50eXBlID09PSAncGF5bWVudCdcbiAgICApO1xuXG4gICAgaWYgKHR4UGFyYW1zLnR5cGUgPT09ICdlbmFibGV0b2tlbicpIHtcbiAgICAgIHRoaXMudmVyaWZ5RW5hYmxlVG9rZW5UeE9wZXJhdGlvbnModHgub3BlcmF0aW9ucywgdHhQYXJhbXMpO1xuICAgIH0gZWxzZSBpZiAodHhQYXJhbXMudHlwZSA9PT0gJ3RydXN0bGluZScpIHtcbiAgICAgIHRoaXMudmVyaWZ5VHJ1c3RsaW5lVHhPcGVyYXRpb25zKHR4Lm9wZXJhdGlvbnMsIHR4UGFyYW1zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKF8uaXNFbXB0eShvdXRwdXRPcGVyYXRpb25zKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RyYW5zYWN0aW9uIHByZWJ1aWxkIGRvZXMgbm90IGhhdmUgYW55IG9wZXJhdGlvbnMnKTtcbiAgICAgIH1cblxuICAgICAgXy5mb3JFYWNoKHR4UGFyYW1zLnJlY2lwaWVudHMsIChleHBlY3RlZE91dHB1dCwgaW5kZXgpID0+IHtcbiAgICAgICAgY29uc3QgZXhwZWN0ZWRPdXRwdXRBZGRyZXNzRGV0YWlscyA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMoZXhwZWN0ZWRPdXRwdXQuYWRkcmVzcyk7XG4gICAgICAgIGNvbnN0IGV4cGVjdGVkT3V0cHV0QWRkcmVzcyA9IGV4cGVjdGVkT3V0cHV0QWRkcmVzc0RldGFpbHMuYWRkcmVzcztcbiAgICAgICAgY29uc3Qgb3V0cHV0ID0gb3V0cHV0T3BlcmF0aW9uc1tpbmRleF0gYXMgc3RlbGxhci5PcGVyYXRpb24uUGF5bWVudCB8IHN0ZWxsYXIuT3BlcmF0aW9uLkNyZWF0ZUFjY291bnQ7XG4gICAgICAgIGlmIChvdXRwdXQuZGVzdGluYXRpb24gIT09IGV4cGVjdGVkT3V0cHV0QWRkcmVzcykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndHJhbnNhY3Rpb24gcHJlYnVpbGQgZG9lcyBub3QgbWF0Y2ggZXhwZWN0ZWQgcmVjaXBpZW50Jyk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBleHBlY3RlZE91dHB1dEFtb3VudCA9IG5ldyBCaWdOdW1iZXIoZXhwZWN0ZWRPdXRwdXQuYW1vdW50KTtcbiAgICAgICAgLy8gVGhlIG91dHB1dCBhbW91bnQgaXMgZXhwcmVzc2VkIGFzIHN0YXJ0aW5nQmFsYW5jZSBpbiBjcmVhdGVBY2NvdW50IG9wZXJhdGlvbnMgYW5kIGFzIGFtb3VudCBpbiBwYXltZW50IG9wZXJhdGlvbnMuXG4gICAgICAgIGNvbnN0IG91dHB1dEFtb3VudFN0cmluZyA9IG91dHB1dC50eXBlID09PSAnY3JlYXRlQWNjb3VudCcgPyBvdXRwdXQuc3RhcnRpbmdCYWxhbmNlIDogb3V0cHV0LmFtb3VudDtcbiAgICAgICAgY29uc3Qgb3V0cHV0QW1vdW50ID0gbmV3IEJpZ051bWJlcih0aGlzLmJpZ1VuaXRzVG9CYXNlVW5pdHMob3V0cHV0QW1vdW50U3RyaW5nKSk7XG5cbiAgICAgICAgaWYgKCFvdXRwdXRBbW91bnQuZXEoZXhwZWN0ZWRPdXRwdXRBbW91bnQpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0cmFuc2FjdGlvbiBwcmVidWlsZCBkb2VzIG5vdCBtYXRjaCBleHBlY3RlZCBhbW91bnQnKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gVmVyaWZ5IHRoZSB1c2VyIHNpZ25hdHVyZSwgaWYgdGhlIHR4IGlzIGhhbGYtc2lnbmVkXG4gICAgaWYgKCFfLmlzRW1wdHkodHguc2lnbmF0dXJlcykpIHtcbiAgICAgIGNvbnN0IHVzZXJTaWduYXR1cmUgPSB0eC5zaWduYXR1cmVzWzBdLnNpZ25hdHVyZSgpO1xuXG4gICAgICAvLyBvYnRhaW4gdGhlIGtleWNoYWlucyBhbmQga2V5IHNpZ25hdHVyZXNcbiAgICAgIGxldCBrZXljaGFpbnMgPSB2ZXJpZmljYXRpb24ua2V5Y2hhaW5zO1xuICAgICAgaWYgKCFrZXljaGFpbnMgJiYgZGlzYWJsZU5ldHdvcmtpbmcpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgZmV0Y2gga2V5Y2hhaW5zIHdpdGhvdXQgbmV0d29ya2luZycpO1xuICAgICAgfSBlbHNlIGlmICgha2V5Y2hhaW5zKSB7XG4gICAgICAgIGtleWNoYWlucyA9IGF3YWl0IHByb21pc2VQcm9wcyh7XG4gICAgICAgICAgdXNlcjogdGhpcy5rZXljaGFpbnMoKS5nZXQoeyBpZDogd2FsbGV0LmtleUlkcygpW0tleUluZGljZXMuVVNFUl0gfSksXG4gICAgICAgICAgYmFja3VwOiB0aGlzLmtleWNoYWlucygpLmdldCh7IGlkOiB3YWxsZXQua2V5SWRzKClbS2V5SW5kaWNlcy5CQUNLVVBdIH0pLFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFrZXljaGFpbnMgfHwgIWtleWNoYWlucy5iYWNrdXAgfHwgIWtleWNoYWlucy51c2VyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigna2V5Y2hhaW5zIGFyZSByZXF1aXJlZCwgYnV0IGNvdWxkIG5vdCBiZSBmZXRjaGVkJyk7XG4gICAgICB9XG5cbiAgICAgIGFzc2VydChrZXljaGFpbnMuYmFja3VwLnB1Yik7XG4gICAgICBpZiAodGhpcy52ZXJpZnlTaWduYXR1cmUoa2V5Y2hhaW5zLmJhY2t1cC5wdWIsIHR4Lmhhc2goKSwgdXNlclNpZ25hdHVyZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0cmFuc2FjdGlvbiBzaWduZWQgd2l0aCB3cm9uZyBrZXknKTtcbiAgICAgIH1cbiAgICAgIGFzc2VydChrZXljaGFpbnMudXNlci5wdWIpO1xuICAgICAgaWYgKCF0aGlzLnZlcmlmeVNpZ25hdHVyZShrZXljaGFpbnMudXNlci5wdWIsIHR4Lmhhc2goKSwgdXNlclNpZ25hdHVyZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd0cmFuc2FjdGlvbiBzaWduYXR1cmUgaW52YWxpZCcpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIGluaGVyaXRkb2MgKi9cbiAgZGVyaXZlS2V5V2l0aFNlZWQoKTogeyBkZXJpdmF0aW9uUGF0aDogc3RyaW5nOyBrZXk6IHN0cmluZyB9IHtcbiAgICB0aHJvdyBuZXcgTm90U3VwcG9ydGVkKCdtZXRob2QgZGVyaXZlS2V5V2l0aFNlZWQgbm90IHN1cHBvcnRlZCBmb3IgZWRkc2EgY3VydmUnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBzdGVsbGFyLXNkayBoYXMgdHdvIG92ZXJsb2FkcyBmb3IgdG9YRFIsIGFuZCB0eXBlc2NyaXB0IGNhbid0IHNlZW0gdG8gZmlndXJlIG91dCB0aGVcbiAgICogY29ycmVjdCBvbmUgdG8gdXNlLCBzbyB3ZSBoYXZlIHRvIGJlIHZlcnkgZXhwbGljaXQgYXMgdG8gd2hpY2ggb25lIHdlIHdhbnQuXG4gICAqIEBwYXJhbSB0eCB0cmFuc2FjdGlvbiB0byBjb252ZXJ0XG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIHR4VG9TdHJpbmcgPSAodHg6IHN0ZWxsYXIuVHJhbnNhY3Rpb24pOiBzdHJpbmcgPT5cbiAgICAodHgudG9FbnZlbG9wZSgpLnRvWERSIGFzIChfOiBzdHJpbmcpID0+IHN0cmluZykoJ2Jhc2U2NCcpO1xuXG4gIGFzeW5jIHBhcnNlVHJhbnNhY3Rpb24ocGFyYW1zOiBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8UGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBjb25maWcgZm9yIGhvdyB0b2tlbiBlbmFibGVtZW50cyB3b3JrIGZvciB0aGlzIGNvaW5cbiAgICogQHJldHVybnNcbiAgICogICAgcmVxdWlyZXNUb2tlbkVuYWJsZW1lbnQ6IFRydWUgaWYgdG9rZW5zIG5lZWQgdG8gYmUgZW5hYmxlZCBmb3IgdGhpcyBjb2luXG4gICAqICAgIHN1cHBvcnRzTXVsdGlwbGVUb2tlbkVuYWJsZW1lbnRzOiBUcnVlIGlmIG11bHRpcGxlIHRva2VucyBjYW4gYmUgZW5hYmxlZCBpbiBvbmUgdHJhbnNhY3Rpb25cbiAgICovXG4gIGdldFRva2VuRW5hYmxlbWVudENvbmZpZygpOiBUb2tlbkVuYWJsZW1lbnRDb25maWcge1xuICAgIHJldHVybiB7XG4gICAgICByZXF1aXJlc1Rva2VuRW5hYmxlbWVudDogdHJ1ZSxcbiAgICAgIHN1cHBvcnRzTXVsdGlwbGVUb2tlbkVuYWJsZW1lbnRzOiBmYWxzZSxcbiAgICB9O1xuICB9XG59XG4iXX0=Выполнить команду
Для локальной разработки. Не используйте в интернете!