@bitgo-beta/abstract-eth 1.2.3-alpha.16 → 1.2.3-alpha.161
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1377 -0
- package/dist/src/abstractEthLikeCoin.d.ts +12 -6
- package/dist/src/abstractEthLikeCoin.d.ts.map +1 -1
- package/dist/src/abstractEthLikeCoin.js +14 -11
- package/dist/src/abstractEthLikeNewCoins.d.ts +638 -0
- package/dist/src/abstractEthLikeNewCoins.d.ts.map +1 -0
- package/dist/src/abstractEthLikeNewCoins.js +1942 -0
- package/dist/src/ethLikeToken.d.ts +34 -4
- package/dist/src/ethLikeToken.d.ts.map +1 -1
- package/dist/src/ethLikeToken.js +281 -7
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -2
- package/dist/src/lib/contractCall.d.ts +8 -0
- package/dist/src/lib/contractCall.d.ts.map +1 -0
- package/dist/src/lib/contractCall.js +17 -0
- package/dist/src/lib/iface.d.ts +132 -0
- package/dist/src/lib/iface.d.ts.map +1 -0
- package/dist/src/lib/iface.js +8 -0
- package/dist/src/lib/index.d.ts +15 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +46 -0
- package/dist/src/lib/keyPair.d.ts +26 -0
- package/dist/src/lib/keyPair.d.ts.map +1 -0
- package/dist/src/lib/keyPair.js +66 -0
- package/dist/src/lib/transaction.d.ts +64 -0
- package/dist/src/lib/transaction.d.ts.map +1 -0
- package/dist/src/lib/transaction.js +137 -0
- package/dist/src/lib/transactionBuilder.d.ts +245 -0
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilder.js +726 -0
- package/dist/src/lib/transferBuilder.d.ts +71 -0
- package/dist/src/lib/transferBuilder.d.ts.map +1 -0
- package/dist/src/lib/transferBuilder.js +261 -0
- package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.d.ts +54 -0
- package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.d.ts.map +1 -0
- package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.js +121 -0
- package/dist/src/lib/transferBuilders/index.d.ts +4 -0
- package/dist/src/lib/transferBuilders/index.d.ts.map +1 -0
- package/dist/src/lib/transferBuilders/index.js +20 -0
- package/dist/src/lib/transferBuilders/transferBuilderERC1155.d.ts +16 -0
- package/dist/src/lib/transferBuilders/transferBuilderERC1155.d.ts.map +1 -0
- package/dist/src/lib/transferBuilders/transferBuilderERC1155.js +93 -0
- package/dist/src/lib/transferBuilders/transferBuilderERC721.d.ts +15 -0
- package/dist/src/lib/transferBuilders/transferBuilderERC721.d.ts.map +1 -0
- package/dist/src/lib/transferBuilders/transferBuilderERC721.js +78 -0
- package/dist/src/lib/types.d.ts +39 -0
- package/dist/src/lib/types.d.ts.map +1 -0
- package/dist/src/lib/types.js +137 -0
- package/dist/src/lib/utils.d.ts +263 -0
- package/dist/src/lib/utils.d.ts.map +1 -0
- package/dist/src/lib/utils.js +681 -0
- package/dist/src/lib/walletUtil.d.ts +30 -0
- package/dist/src/lib/walletUtil.d.ts.map +1 -0
- package/dist/src/lib/walletUtil.js +33 -0
- package/dist/tsconfig.tsbuildinfo +1 -7964
- package/package.json +24 -9
|
@@ -0,0 +1,1942 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AbstractEthLikeNewCoins = exports.optionalDeps = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* @prettier
|
|
9
|
+
*/
|
|
10
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
11
|
+
const sdk_lib_mpc_1 = require("@bitgo-beta/sdk-lib-mpc");
|
|
12
|
+
const statics_1 = require("@bitgo-beta/statics");
|
|
13
|
+
const utxo_lib_1 = require("@bitgo-beta/utxo-lib");
|
|
14
|
+
const tx_1 = require("@ethereumjs/tx");
|
|
15
|
+
const eth_sig_util_1 = require("@metamask/eth-sig-util");
|
|
16
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
17
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
18
|
+
const crypto_1 = require("crypto");
|
|
19
|
+
const debug_1 = __importDefault(require("debug"));
|
|
20
|
+
const ethereumjs_util_1 = require("ethereumjs-util");
|
|
21
|
+
const keccak_1 = __importDefault(require("keccak"));
|
|
22
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
23
|
+
const secp256k1_1 = __importDefault(require("secp256k1"));
|
|
24
|
+
const abstractEthLikeCoin_1 = require("./abstractEthLikeCoin");
|
|
25
|
+
const ethLikeToken_1 = require("./ethLikeToken");
|
|
26
|
+
const lib_1 = require("./lib");
|
|
27
|
+
const debug = (0, debug_1.default)('bitgo:v2:ethlike');
|
|
28
|
+
exports.optionalDeps = {
|
|
29
|
+
get ethAbi() {
|
|
30
|
+
try {
|
|
31
|
+
return require('ethereumjs-abi');
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
debug('unable to load ethereumjs-abi:');
|
|
35
|
+
debug(e.stack);
|
|
36
|
+
throw new sdk_core_1.EthereumLibraryUnavailableError(`ethereumjs-abi`);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
get ethUtil() {
|
|
40
|
+
try {
|
|
41
|
+
return require('ethereumjs-util');
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
debug('unable to load ethereumjs-util:');
|
|
45
|
+
debug(e.stack);
|
|
46
|
+
throw new sdk_core_1.EthereumLibraryUnavailableError(`ethereumjs-util`);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
get EthTx() {
|
|
50
|
+
try {
|
|
51
|
+
return require('@ethereumjs/tx');
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
debug('unable to load @ethereumjs/tx');
|
|
55
|
+
debug(e.stack);
|
|
56
|
+
throw new sdk_core_1.EthereumLibraryUnavailableError(`@ethereumjs/tx`);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
get EthCommon() {
|
|
60
|
+
try {
|
|
61
|
+
return require('@ethereumjs/common');
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
debug('unable to load @ethereumjs/common:');
|
|
65
|
+
debug(e.stack);
|
|
66
|
+
throw new sdk_core_1.EthereumLibraryUnavailableError(`@ethereumjs/common`);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
class AbstractEthLikeNewCoins extends abstractEthLikeCoin_1.AbstractEthLikeCoin {
|
|
71
|
+
constructor(bitgo, staticsCoin) {
|
|
72
|
+
super(bitgo, staticsCoin);
|
|
73
|
+
/**
|
|
74
|
+
* Get the data required to make an ETH function call defined by the given types and values
|
|
75
|
+
*
|
|
76
|
+
* @param {string} functionName - The name of the function being called, e.g. transfer
|
|
77
|
+
* @param types The types of the function call in order
|
|
78
|
+
* @param values The values of the function call in order
|
|
79
|
+
* @return {Buffer} The combined data for the function call
|
|
80
|
+
*/
|
|
81
|
+
this.getMethodCallData = (functionName, types, values) => {
|
|
82
|
+
return Buffer.concat([
|
|
83
|
+
// function signature
|
|
84
|
+
exports.optionalDeps.ethAbi.methodID(functionName, types),
|
|
85
|
+
// function arguments
|
|
86
|
+
exports.optionalDeps.ethAbi.rawEncode(types, values),
|
|
87
|
+
]);
|
|
88
|
+
};
|
|
89
|
+
if (!staticsCoin) {
|
|
90
|
+
throw new Error('missing required constructor parameter staticsCoin');
|
|
91
|
+
}
|
|
92
|
+
this.staticsCoin = staticsCoin;
|
|
93
|
+
this.sendMethodName = 'sendMultiSig';
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Method to return the coin's network object
|
|
97
|
+
* @returns {EthLikeNetwork | undefined}
|
|
98
|
+
*/
|
|
99
|
+
getNetwork() {
|
|
100
|
+
var _a;
|
|
101
|
+
return (_a = this.staticsCoin) === null || _a === void 0 ? void 0 : _a.network;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Evaluates whether an address string is valid for this coin
|
|
105
|
+
* @param {string} address
|
|
106
|
+
* @returns {boolean} True if address is the valid ethlike adderss
|
|
107
|
+
*/
|
|
108
|
+
isValidAddress(address) {
|
|
109
|
+
return exports.optionalDeps.ethUtil.isValidAddress(exports.optionalDeps.ethUtil.addHexPrefix(address));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Flag for sending data along with transactions
|
|
113
|
+
* @returns {boolean} True if okay to send tx data (ETH), false otherwise
|
|
114
|
+
*/
|
|
115
|
+
transactionDataAllowed() {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Default expire time for a contract call (1 week)
|
|
120
|
+
* @returns {number} Time in seconds
|
|
121
|
+
*/
|
|
122
|
+
getDefaultExpireTime() {
|
|
123
|
+
return Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 * 7;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Method to get the custom chain common object based on params from recovery
|
|
127
|
+
* @param {number} chainId - the chain id of the custom chain
|
|
128
|
+
* @returns {EthLikeCommon.default}
|
|
129
|
+
*/
|
|
130
|
+
static getCustomChainCommon(chainId) {
|
|
131
|
+
const coinName = statics_1.CoinMap.coinNameFromChainId(chainId);
|
|
132
|
+
const coin = statics_1.coins.get(coinName);
|
|
133
|
+
const ethLikeCommon = (0, lib_1.getCommon)(coin.network);
|
|
134
|
+
return ethLikeCommon;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Gets correct Eth Common object based on params from either recovery or tx building
|
|
138
|
+
* @param {EIP1559} eip1559 - configs that specify whether we should construct an eip1559 tx
|
|
139
|
+
* @param {ReplayProtectionOptions} replayProtectionOptions - check if chain id supports replay protection
|
|
140
|
+
* @returns {EthLikeCommon.default}
|
|
141
|
+
*/
|
|
142
|
+
static getEthLikeCommon(eip1559, replayProtectionOptions) {
|
|
143
|
+
var _a;
|
|
144
|
+
// if eip1559 params are specified, default to london hardfork, otherwise,
|
|
145
|
+
// default to tangerine whistle to avoid replay protection issues
|
|
146
|
+
const defaultHardfork = !!eip1559 ? 'london' : exports.optionalDeps.EthCommon.Hardfork.TangerineWhistle;
|
|
147
|
+
const ethLikeCommon = AbstractEthLikeNewCoins.getCustomChainCommon(replayProtectionOptions === null || replayProtectionOptions === void 0 ? void 0 : replayProtectionOptions.chain);
|
|
148
|
+
ethLikeCommon.setHardfork((_a = replayProtectionOptions === null || replayProtectionOptions === void 0 ? void 0 : replayProtectionOptions.hardfork) !== null && _a !== void 0 ? _a : defaultHardfork);
|
|
149
|
+
return ethLikeCommon;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Method to build the tx object
|
|
153
|
+
* @param {BuildTransactionParams} params - params to build transaction
|
|
154
|
+
* @returns {EthLikeTxLib.FeeMarketEIP1559Transaction | EthLikeTxLib.Transaction}
|
|
155
|
+
*/
|
|
156
|
+
static buildTransaction(params) {
|
|
157
|
+
// if eip1559 params are specified, default to london hardfork, otherwise,
|
|
158
|
+
// default to tangerine whistle to avoid replay protection issues
|
|
159
|
+
const ethLikeCommon = AbstractEthLikeNewCoins.getEthLikeCommon(params.eip1559, params.replayProtectionOptions);
|
|
160
|
+
const baseParams = {
|
|
161
|
+
to: params.to,
|
|
162
|
+
nonce: params.nonce,
|
|
163
|
+
value: params.value,
|
|
164
|
+
data: params.data,
|
|
165
|
+
gasLimit: new exports.optionalDeps.ethUtil.BN(params.gasLimit),
|
|
166
|
+
};
|
|
167
|
+
const unsignedEthTx = !!params.eip1559
|
|
168
|
+
? exports.optionalDeps.EthTx.FeeMarketEIP1559Transaction.fromTxData({
|
|
169
|
+
...baseParams,
|
|
170
|
+
maxFeePerGas: new exports.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas),
|
|
171
|
+
maxPriorityFeePerGas: new exports.optionalDeps.ethUtil.BN(params.eip1559.maxPriorityFeePerGas),
|
|
172
|
+
}, { common: ethLikeCommon })
|
|
173
|
+
: exports.optionalDeps.EthTx.Transaction.fromTxData({
|
|
174
|
+
...baseParams,
|
|
175
|
+
gasPrice: new exports.optionalDeps.ethUtil.BN(params.gasPrice),
|
|
176
|
+
}, { common: ethLikeCommon });
|
|
177
|
+
return unsignedEthTx;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Query explorer for the balance of an address
|
|
181
|
+
* @param {String} address - the ETHLike address
|
|
182
|
+
* @returns {BigNumber} address balance
|
|
183
|
+
*/
|
|
184
|
+
async queryAddressBalance(address) {
|
|
185
|
+
const result = await this.recoveryBlockchainExplorerQuery({
|
|
186
|
+
module: 'account',
|
|
187
|
+
action: 'balance',
|
|
188
|
+
address: address,
|
|
189
|
+
});
|
|
190
|
+
// throw if the result does not exist or the result is not a valid number
|
|
191
|
+
if (!result || !result.result || isNaN(result.result)) {
|
|
192
|
+
throw new Error(`Could not obtain address balance for ${address} from the explorer, got: ${result.result}`);
|
|
193
|
+
}
|
|
194
|
+
return new exports.optionalDeps.ethUtil.BN(result.result, 10);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* @param {Recipient[]} recipients - the recipients of the transaction
|
|
198
|
+
* @param {number} expireTime - the expire time of the transaction
|
|
199
|
+
* @param {number} contractSequenceId - the contract sequence id of the transaction
|
|
200
|
+
* @returns {string}
|
|
201
|
+
*/
|
|
202
|
+
getOperationSha3ForExecuteAndConfirm(recipients, expireTime, contractSequenceId) {
|
|
203
|
+
if (!recipients || !Array.isArray(recipients)) {
|
|
204
|
+
throw new Error('expecting array of recipients');
|
|
205
|
+
}
|
|
206
|
+
// Right now we only support 1 recipient
|
|
207
|
+
if (recipients.length !== 1) {
|
|
208
|
+
throw new Error('must send to exactly 1 recipient');
|
|
209
|
+
}
|
|
210
|
+
if (!lodash_1.default.isNumber(expireTime)) {
|
|
211
|
+
throw new Error('expireTime must be number of seconds since epoch');
|
|
212
|
+
}
|
|
213
|
+
if (!lodash_1.default.isNumber(contractSequenceId)) {
|
|
214
|
+
throw new Error('contractSequenceId must be number');
|
|
215
|
+
}
|
|
216
|
+
// Check inputs
|
|
217
|
+
recipients.forEach(function (recipient) {
|
|
218
|
+
if (!lodash_1.default.isString(recipient.address) ||
|
|
219
|
+
!exports.optionalDeps.ethUtil.isValidAddress(exports.optionalDeps.ethUtil.addHexPrefix(recipient.address))) {
|
|
220
|
+
throw new Error('Invalid address: ' + recipient.address);
|
|
221
|
+
}
|
|
222
|
+
let amount;
|
|
223
|
+
try {
|
|
224
|
+
amount = new bignumber_js_1.BigNumber(recipient.amount);
|
|
225
|
+
}
|
|
226
|
+
catch (e) {
|
|
227
|
+
throw new Error('Invalid amount for: ' + recipient.address + ' - should be numeric');
|
|
228
|
+
}
|
|
229
|
+
recipient.amount = amount.toFixed(0);
|
|
230
|
+
if (recipient.data && !lodash_1.default.isString(recipient.data)) {
|
|
231
|
+
throw new Error('Data for recipient ' + recipient.address + ' - should be of type hex string');
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
const recipient = recipients[0];
|
|
235
|
+
return exports.optionalDeps.ethUtil.bufferToHex(exports.optionalDeps.ethAbi.soliditySHA3(...this.getOperation(recipient, expireTime, contractSequenceId)));
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get transfer operation for coin
|
|
239
|
+
* @param {Recipient} recipient - recipient info
|
|
240
|
+
* @param {number} expireTime - expiry time
|
|
241
|
+
* @param {number} contractSequenceId - sequence id
|
|
242
|
+
* @returns {Array} operation array
|
|
243
|
+
*/
|
|
244
|
+
getOperation(recipient, expireTime, contractSequenceId) {
|
|
245
|
+
const network = this.getNetwork();
|
|
246
|
+
return [
|
|
247
|
+
['string', 'address', 'uint', 'bytes', 'uint', 'uint'],
|
|
248
|
+
[
|
|
249
|
+
network.nativeCoinOperationHashPrefix,
|
|
250
|
+
new exports.optionalDeps.ethUtil.BN(exports.optionalDeps.ethUtil.stripHexPrefix(recipient.address), 16),
|
|
251
|
+
recipient.amount,
|
|
252
|
+
Buffer.from(exports.optionalDeps.ethUtil.stripHexPrefix(exports.optionalDeps.ethUtil.padToEven(recipient.data || '')), 'hex'),
|
|
253
|
+
expireTime,
|
|
254
|
+
contractSequenceId,
|
|
255
|
+
],
|
|
256
|
+
];
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Queries the contract (via explorer API) for the next sequence ID
|
|
260
|
+
* @param {String} address - address of the contract
|
|
261
|
+
* @returns {Promise<Number>} sequence ID
|
|
262
|
+
*/
|
|
263
|
+
async querySequenceId(address) {
|
|
264
|
+
// Get sequence ID using contract call
|
|
265
|
+
const sequenceIdMethodSignature = exports.optionalDeps.ethAbi.methodID('getNextSequenceId', []);
|
|
266
|
+
const sequenceIdArgs = exports.optionalDeps.ethAbi.rawEncode([], []);
|
|
267
|
+
const sequenceIdData = Buffer.concat([sequenceIdMethodSignature, sequenceIdArgs]).toString('hex');
|
|
268
|
+
const result = await this.recoveryBlockchainExplorerQuery({
|
|
269
|
+
module: 'proxy',
|
|
270
|
+
action: 'eth_call',
|
|
271
|
+
to: address,
|
|
272
|
+
data: sequenceIdData,
|
|
273
|
+
tag: 'latest',
|
|
274
|
+
});
|
|
275
|
+
if (!result || !result.result) {
|
|
276
|
+
throw new Error('Could not obtain sequence ID from explorer, got: ' + result.result);
|
|
277
|
+
}
|
|
278
|
+
const sequenceIdHex = result.result;
|
|
279
|
+
return new exports.optionalDeps.ethUtil.BN(sequenceIdHex.slice(2), 16).toNumber();
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Recover an unsupported token from a BitGo multisig wallet
|
|
283
|
+
* This builds a half-signed transaction, for which there will be an admin route to co-sign and broadcast. Optionally
|
|
284
|
+
* the user can set params.broadcast = true and the half-signed tx will be sent to BitGo for cosigning and broadcasting
|
|
285
|
+
* @param {RecoverTokenOptions} params
|
|
286
|
+
* @param {Wallet} params.wallet - the wallet to recover the token from
|
|
287
|
+
* @param {string} params.tokenContractAddress - the contract address of the unsupported token
|
|
288
|
+
* @param {string} params.recipient - the destination address recovered tokens should be sent to
|
|
289
|
+
* @param {string} params.walletPassphrase - the wallet passphrase
|
|
290
|
+
* @param {string} params.prv - the xprv
|
|
291
|
+
* @param {boolean} params.broadcast - if true, we will automatically submit the half-signed tx to BitGo for cosigning and broadcasting
|
|
292
|
+
* @returns {Promise<RecoverTokenTransaction>}
|
|
293
|
+
*/
|
|
294
|
+
async recoverToken(params) {
|
|
295
|
+
const network = this.getNetwork();
|
|
296
|
+
if (!lodash_1.default.isObject(params)) {
|
|
297
|
+
throw new Error(`recoverToken must be passed a params object. Got ${params} (type ${typeof params})`);
|
|
298
|
+
}
|
|
299
|
+
if (lodash_1.default.isUndefined(params.tokenContractAddress) || !lodash_1.default.isString(params.tokenContractAddress)) {
|
|
300
|
+
throw new Error(`tokenContractAddress must be a string, got ${params.tokenContractAddress} (type ${typeof params.tokenContractAddress})`);
|
|
301
|
+
}
|
|
302
|
+
if (!this.isValidAddress(params.tokenContractAddress)) {
|
|
303
|
+
throw new Error('tokenContractAddress not a valid address');
|
|
304
|
+
}
|
|
305
|
+
if (lodash_1.default.isUndefined(params.wallet) || !(params.wallet instanceof sdk_core_1.Wallet)) {
|
|
306
|
+
throw new Error(`wallet must be a wallet instance, got ${params.wallet} (type ${typeof params.wallet})`);
|
|
307
|
+
}
|
|
308
|
+
if (lodash_1.default.isUndefined(params.recipient) || !lodash_1.default.isString(params.recipient)) {
|
|
309
|
+
throw new Error(`recipient must be a string, got ${params.recipient} (type ${typeof params.recipient})`);
|
|
310
|
+
}
|
|
311
|
+
if (!this.isValidAddress(params.recipient)) {
|
|
312
|
+
throw new Error('recipient not a valid address');
|
|
313
|
+
}
|
|
314
|
+
if (!exports.optionalDeps.ethUtil.bufferToHex || !exports.optionalDeps.ethAbi.soliditySHA3) {
|
|
315
|
+
throw new Error('ethereum not fully supported in this environment');
|
|
316
|
+
}
|
|
317
|
+
// Get token balance from external API
|
|
318
|
+
const coinSpecific = params.wallet.coinSpecific();
|
|
319
|
+
if (!coinSpecific || !lodash_1.default.isString(coinSpecific.baseAddress)) {
|
|
320
|
+
throw new Error('missing required coin specific property baseAddress');
|
|
321
|
+
}
|
|
322
|
+
const recoveryAmount = await this.queryAddressTokenBalance(params.tokenContractAddress, coinSpecific.baseAddress);
|
|
323
|
+
if (params.broadcast) {
|
|
324
|
+
// We're going to create a normal ETH transaction that sends an amount of 0 ETH to the
|
|
325
|
+
// tokenContractAddress and encode the unsupported-token-send data in the data field
|
|
326
|
+
// #tricksy
|
|
327
|
+
const sendMethodArgs = [
|
|
328
|
+
{
|
|
329
|
+
name: '_to',
|
|
330
|
+
type: 'address',
|
|
331
|
+
value: params.recipient,
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
name: '_value',
|
|
335
|
+
type: 'uint256',
|
|
336
|
+
value: recoveryAmount.toString(10),
|
|
337
|
+
},
|
|
338
|
+
];
|
|
339
|
+
const methodSignature = exports.optionalDeps.ethAbi.methodID('transfer', lodash_1.default.map(sendMethodArgs, 'type'));
|
|
340
|
+
const encodedArgs = exports.optionalDeps.ethAbi.rawEncode(lodash_1.default.map(sendMethodArgs, 'type'), lodash_1.default.map(sendMethodArgs, 'value'));
|
|
341
|
+
const sendData = Buffer.concat([methodSignature, encodedArgs]);
|
|
342
|
+
const broadcastParams = {
|
|
343
|
+
address: params.tokenContractAddress,
|
|
344
|
+
amount: '0',
|
|
345
|
+
data: sendData.toString('hex'),
|
|
346
|
+
};
|
|
347
|
+
if (params.walletPassphrase) {
|
|
348
|
+
broadcastParams.walletPassphrase = params.walletPassphrase;
|
|
349
|
+
}
|
|
350
|
+
else if (params.prv) {
|
|
351
|
+
broadcastParams.prv = params.prv;
|
|
352
|
+
}
|
|
353
|
+
return await params.wallet.send(broadcastParams);
|
|
354
|
+
}
|
|
355
|
+
const recipient = {
|
|
356
|
+
address: params.recipient,
|
|
357
|
+
amount: recoveryAmount.toString(10),
|
|
358
|
+
};
|
|
359
|
+
// This signature will be valid for one week
|
|
360
|
+
const expireTime = Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 * 7;
|
|
361
|
+
// Get sequence ID. We do this by building a 'fake' eth transaction, so the platform will increment and return us the new sequence id
|
|
362
|
+
// This _does_ require the user to have a non-zero wallet balance
|
|
363
|
+
const { nextContractSequenceId, gasPrice, gasLimit } = (await params.wallet.prebuildTransaction({
|
|
364
|
+
recipients: [
|
|
365
|
+
{
|
|
366
|
+
address: params.recipient,
|
|
367
|
+
amount: '1',
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
}));
|
|
371
|
+
// these recoveries need to be processed by support, but if the customer sends any transactions before recovery is
|
|
372
|
+
// complete the sequence ID will be invalid. artificially inflate the sequence ID to allow more time for processing
|
|
373
|
+
const safeSequenceId = nextContractSequenceId + 1000;
|
|
374
|
+
// Build sendData for ethereum tx
|
|
375
|
+
const operationTypes = ['string', 'address', 'uint', 'address', 'uint', 'uint'];
|
|
376
|
+
const operationArgs = [
|
|
377
|
+
// Token operation has prefix has been added here so that ether operation hashes, signatures cannot be re-used for tokenSending
|
|
378
|
+
network.tokenOperationHashPrefix,
|
|
379
|
+
new exports.optionalDeps.ethUtil.BN(exports.optionalDeps.ethUtil.stripHexPrefix(recipient.address), 16),
|
|
380
|
+
recipient.amount,
|
|
381
|
+
new exports.optionalDeps.ethUtil.BN(exports.optionalDeps.ethUtil.stripHexPrefix(params.tokenContractAddress), 16),
|
|
382
|
+
expireTime,
|
|
383
|
+
safeSequenceId,
|
|
384
|
+
];
|
|
385
|
+
const operationHash = exports.optionalDeps.ethUtil.bufferToHex(exports.optionalDeps.ethAbi.soliditySHA3(operationTypes, operationArgs));
|
|
386
|
+
const userPrv = await params.wallet.getPrv({
|
|
387
|
+
prv: params.prv,
|
|
388
|
+
walletPassphrase: params.walletPassphrase,
|
|
389
|
+
});
|
|
390
|
+
const signature = sdk_core_1.Util.ethSignMsgHash(operationHash, sdk_core_1.Util.xprvToEthPrivateKey(userPrv));
|
|
391
|
+
return {
|
|
392
|
+
halfSigned: {
|
|
393
|
+
recipient: recipient,
|
|
394
|
+
expireTime: expireTime,
|
|
395
|
+
contractSequenceId: safeSequenceId,
|
|
396
|
+
operationHash: operationHash,
|
|
397
|
+
signature: signature,
|
|
398
|
+
gasLimit: gasLimit,
|
|
399
|
+
gasPrice: gasPrice,
|
|
400
|
+
tokenContractAddress: params.tokenContractAddress,
|
|
401
|
+
walletId: params.wallet.id(),
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Ensure either enterprise or newFeeAddress is passed, to know whether to create new key or use enterprise key
|
|
407
|
+
* @param {PrecreateBitGoOptions} params
|
|
408
|
+
* @param {string} params.enterprise {String} the enterprise id to associate with this key
|
|
409
|
+
* @param {string} params.newFeeAddress {Boolean} create a new fee address (enterprise not needed in this case)
|
|
410
|
+
* @returns {void}
|
|
411
|
+
*/
|
|
412
|
+
preCreateBitGo(params) {
|
|
413
|
+
// We always need params object, since either enterprise or newFeeAddress is required
|
|
414
|
+
if (!lodash_1.default.isObject(params)) {
|
|
415
|
+
throw new Error(`preCreateBitGo must be passed a params object. Got ${params} (type ${typeof params})`);
|
|
416
|
+
}
|
|
417
|
+
if (lodash_1.default.isUndefined(params.enterprise) && lodash_1.default.isUndefined(params.newFeeAddress)) {
|
|
418
|
+
throw new Error('expecting enterprise when adding BitGo key. If you want to create a new ETH bitgo key, set the newFeeAddress parameter to true.');
|
|
419
|
+
}
|
|
420
|
+
// Check whether key should be an enterprise key or a BitGo key for a new fee address
|
|
421
|
+
if (!lodash_1.default.isUndefined(params.enterprise) && !lodash_1.default.isUndefined(params.newFeeAddress)) {
|
|
422
|
+
throw new Error(`Incompatible arguments - cannot pass both enterprise and newFeeAddress parameter.`);
|
|
423
|
+
}
|
|
424
|
+
if (!lodash_1.default.isUndefined(params.enterprise) && !lodash_1.default.isString(params.enterprise)) {
|
|
425
|
+
throw new Error(`enterprise should be a string - got ${params.enterprise} (type ${typeof params.enterprise})`);
|
|
426
|
+
}
|
|
427
|
+
if (!lodash_1.default.isUndefined(params.newFeeAddress) && !lodash_1.default.isBoolean(params.newFeeAddress)) {
|
|
428
|
+
throw new Error(`newFeeAddress should be a boolean - got ${params.newFeeAddress} (type ${typeof params.newFeeAddress})`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Queries public block explorer to get the next ETHLike coin's nonce that should be used for the given ETH address
|
|
433
|
+
* @param {string} address
|
|
434
|
+
* @returns {Promise<number>}
|
|
435
|
+
*/
|
|
436
|
+
async getAddressNonce(address) {
|
|
437
|
+
// Get nonce for backup key (should be 0)
|
|
438
|
+
let nonce = 0;
|
|
439
|
+
const result = await this.recoveryBlockchainExplorerQuery({
|
|
440
|
+
module: 'account',
|
|
441
|
+
action: 'txlist',
|
|
442
|
+
address,
|
|
443
|
+
});
|
|
444
|
+
if (!result || !Array.isArray(result.result)) {
|
|
445
|
+
throw new Error('Unable to find next nonce from Etherscan, got: ' + JSON.stringify(result));
|
|
446
|
+
}
|
|
447
|
+
const backupKeyTxList = result.result;
|
|
448
|
+
if (backupKeyTxList.length > 0) {
|
|
449
|
+
// Calculate last nonce used
|
|
450
|
+
const outgoingTxs = backupKeyTxList.filter((tx) => tx.from === address);
|
|
451
|
+
nonce = outgoingTxs.length;
|
|
452
|
+
}
|
|
453
|
+
return nonce;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Helper function for recover()
|
|
457
|
+
* This transforms the unsigned transaction information into a format the BitGo offline vault expects
|
|
458
|
+
* @param {UnformattedTxInfo} txInfo - tx info
|
|
459
|
+
* @param {EthLikeTxLib.Transaction | EthLikeTxLib.FeeMarketEIP1559Transaction} ethTx - the ethereumjs tx object
|
|
460
|
+
* @param {string} userKey - the user's key
|
|
461
|
+
* @param {string} backupKey - the backup key
|
|
462
|
+
* @param {Buffer} gasPrice - gas price for the tx
|
|
463
|
+
* @param {number} gasLimit - gas limit for the tx
|
|
464
|
+
* @param {EIP1559} eip1559 - eip1559 params
|
|
465
|
+
* @param {ReplayProtectionOptions} replayProtectionOptions - replay protection options
|
|
466
|
+
* @returns {Promise<OfflineVaultTxInfo>}
|
|
467
|
+
*/
|
|
468
|
+
async formatForOfflineVault(txInfo, ethTx, userKey, backupKey, gasPrice, gasLimit, eip1559, replayProtectionOptions) {
|
|
469
|
+
if (!ethTx.to) {
|
|
470
|
+
throw new Error('Eth tx must have a `to` address');
|
|
471
|
+
}
|
|
472
|
+
const backupHDNode = utxo_lib_1.bip32.fromBase58(backupKey);
|
|
473
|
+
const backupSigningKey = backupHDNode.publicKey;
|
|
474
|
+
const response = {
|
|
475
|
+
tx: ethTx.serialize().toString('hex'),
|
|
476
|
+
userKey,
|
|
477
|
+
backupKey,
|
|
478
|
+
coin: this.getChain(),
|
|
479
|
+
gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
|
|
480
|
+
gasLimit,
|
|
481
|
+
recipients: [txInfo.recipient],
|
|
482
|
+
walletContractAddress: ethTx.to.toString(),
|
|
483
|
+
amount: txInfo.recipient.amount,
|
|
484
|
+
backupKeyNonce: await this.getAddressNonce(`0x${exports.optionalDeps.ethUtil.publicToAddress(backupSigningKey, true).toString('hex')}`),
|
|
485
|
+
eip1559,
|
|
486
|
+
replayProtectionOptions,
|
|
487
|
+
};
|
|
488
|
+
lodash_1.default.extend(response, txInfo);
|
|
489
|
+
response.nextContractSequenceId = response.contractSequenceId;
|
|
490
|
+
return response;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Helper function for recover()
|
|
494
|
+
* This transforms the unsigned transaction information into a format the BitGo offline vault expects
|
|
495
|
+
* @param {UnformattedTxInfo} txInfo - tx info
|
|
496
|
+
* @param {EthLikeTxLib.Transaction | EthLikeTxLib.FeeMarketEIP1559Transaction} ethTx - the ethereumjs tx object
|
|
497
|
+
* @param {string} userKey - the user's key
|
|
498
|
+
* @param {string} backupKey - the backup key
|
|
499
|
+
* @param {Buffer} gasPrice - gas price for the tx
|
|
500
|
+
* @param {number} gasLimit - gas limit for the tx
|
|
501
|
+
* @param {number} backupKeyNonce - the nonce of the backup key address
|
|
502
|
+
* @param {EIP1559} eip1559 - eip1559 params
|
|
503
|
+
* @param {ReplayProtectionOptions} replayProtectionOptions - replay protection options
|
|
504
|
+
* @returns {Promise<OfflineVaultTxInfo>}
|
|
505
|
+
*/
|
|
506
|
+
formatForOfflineVaultTSS(txInfo, ethTx, userKey, backupKey, gasPrice, gasLimit, backupKeyNonce, eip1559, replayProtectionOptions) {
|
|
507
|
+
if (!ethTx.to) {
|
|
508
|
+
throw new Error('Eth tx must have a `to` address');
|
|
509
|
+
}
|
|
510
|
+
const response = {
|
|
511
|
+
tx: ethTx.serialize().toString('hex'),
|
|
512
|
+
txHex: ethTx.getMessageToSign(false).toString(),
|
|
513
|
+
userKey,
|
|
514
|
+
backupKey,
|
|
515
|
+
coin: this.getChain(),
|
|
516
|
+
gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
|
|
517
|
+
gasLimit,
|
|
518
|
+
recipients: [txInfo.recipient],
|
|
519
|
+
walletContractAddress: ethTx.to.toString(),
|
|
520
|
+
amount: txInfo.recipient.amount,
|
|
521
|
+
backupKeyNonce: backupKeyNonce,
|
|
522
|
+
eip1559,
|
|
523
|
+
replayProtectionOptions,
|
|
524
|
+
};
|
|
525
|
+
lodash_1.default.extend(response, txInfo);
|
|
526
|
+
return response;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Check whether the gas price passed in by user are within our max and min bounds
|
|
530
|
+
* If they are not set, set them to the defaults
|
|
531
|
+
* @param {number} userGasPrice - user defined gas price
|
|
532
|
+
* @returns {number} the gas price to use for this transaction
|
|
533
|
+
*/
|
|
534
|
+
setGasPrice(userGasPrice) {
|
|
535
|
+
if (!userGasPrice) {
|
|
536
|
+
return statics_1.ethGasConfigs.defaultGasPrice;
|
|
537
|
+
}
|
|
538
|
+
const gasPriceMax = statics_1.ethGasConfigs.maximumGasPrice;
|
|
539
|
+
const gasPriceMin = statics_1.ethGasConfigs.minimumGasPrice;
|
|
540
|
+
if (userGasPrice < gasPriceMin || userGasPrice > gasPriceMax) {
|
|
541
|
+
throw new Error(`Gas price must be between ${gasPriceMin} and ${gasPriceMax}`);
|
|
542
|
+
}
|
|
543
|
+
return userGasPrice;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Check whether gas limit passed in by user are within our max and min bounds
|
|
547
|
+
* If they are not set, set them to the defaults
|
|
548
|
+
* @param {number} userGasLimit user defined gas limit
|
|
549
|
+
* @returns {number} the gas limit to use for this transaction
|
|
550
|
+
*/
|
|
551
|
+
setGasLimit(userGasLimit) {
|
|
552
|
+
if (!userGasLimit) {
|
|
553
|
+
return statics_1.ethGasConfigs.defaultGasLimit;
|
|
554
|
+
}
|
|
555
|
+
const gasLimitMax = statics_1.ethGasConfigs.maximumGasLimit;
|
|
556
|
+
const gasLimitMin = statics_1.ethGasConfigs.minimumGasLimit;
|
|
557
|
+
if (userGasLimit < gasLimitMin || userGasLimit > gasLimitMax) {
|
|
558
|
+
throw new Error(`Gas limit must be between ${gasLimitMin} and ${gasLimitMax}`);
|
|
559
|
+
}
|
|
560
|
+
return userGasLimit;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Helper function for signTransaction for the rare case that SDK is doing the second signature
|
|
564
|
+
* Note: we are expecting this to be called from the offline vault
|
|
565
|
+
* @param {SignFinalOptions.txPrebuild} params.txPrebuild
|
|
566
|
+
* @param {string} params.prv
|
|
567
|
+
* @returns {{txHex: string}}
|
|
568
|
+
*/
|
|
569
|
+
async signFinalEthLike(params) {
|
|
570
|
+
var _a;
|
|
571
|
+
const signingKey = new lib_1.KeyPair({ prv: params.prv }).getKeys().prv;
|
|
572
|
+
if (lodash_1.default.isUndefined(signingKey)) {
|
|
573
|
+
throw new Error('missing private key');
|
|
574
|
+
}
|
|
575
|
+
const txBuilder = this.getTransactionBuilder(params.common);
|
|
576
|
+
try {
|
|
577
|
+
txBuilder.from((_a = params.txPrebuild.halfSigned) === null || _a === void 0 ? void 0 : _a.txHex);
|
|
578
|
+
}
|
|
579
|
+
catch (e) {
|
|
580
|
+
throw new Error('invalid half-signed transaction');
|
|
581
|
+
}
|
|
582
|
+
txBuilder.sign({ key: signingKey });
|
|
583
|
+
const tx = await txBuilder.build();
|
|
584
|
+
return {
|
|
585
|
+
txHex: tx.toBroadcastFormat(),
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Assemble half-sign prebuilt transaction
|
|
590
|
+
* @param {SignTransactionOptions} params
|
|
591
|
+
*/
|
|
592
|
+
async signTransaction(params) {
|
|
593
|
+
var _a;
|
|
594
|
+
// Normally the SDK provides the first signature for an EthLike tx, but occasionally it provides the second and final one.
|
|
595
|
+
if (params.isLastSignature) {
|
|
596
|
+
// In this case when we're doing the second (final) signature, the logic is different.
|
|
597
|
+
return await this.signFinalEthLike(params);
|
|
598
|
+
}
|
|
599
|
+
const txBuilder = this.getTransactionBuilder(params.common);
|
|
600
|
+
txBuilder.from(params.txPrebuild.txHex);
|
|
601
|
+
txBuilder
|
|
602
|
+
.transfer()
|
|
603
|
+
.coin((_a = this.staticsCoin) === null || _a === void 0 ? void 0 : _a.name)
|
|
604
|
+
.key(new lib_1.KeyPair({ prv: params.prv }).getKeys().prv);
|
|
605
|
+
const transaction = await txBuilder.build();
|
|
606
|
+
const recipients = transaction.outputs.map((output) => ({ address: output.address, amount: output.value }));
|
|
607
|
+
const txParams = {
|
|
608
|
+
eip1559: params.txPrebuild.eip1559,
|
|
609
|
+
txHex: transaction.toBroadcastFormat(),
|
|
610
|
+
recipients: recipients,
|
|
611
|
+
expiration: params.txPrebuild.expireTime,
|
|
612
|
+
hopTransaction: params.txPrebuild.hopTransaction,
|
|
613
|
+
custodianTransactionId: params.custodianTransactionId,
|
|
614
|
+
expireTime: params.expireTime,
|
|
615
|
+
contractSequenceId: params.txPrebuild.nextContractSequenceId,
|
|
616
|
+
sequenceId: params.sequenceId,
|
|
617
|
+
};
|
|
618
|
+
return { halfSigned: txParams };
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Method to validate recovery params
|
|
622
|
+
* @param {RecoverOptions} params
|
|
623
|
+
* @returns {void}
|
|
624
|
+
*/
|
|
625
|
+
validateRecoveryParams(params) {
|
|
626
|
+
if (lodash_1.default.isUndefined(params.userKey)) {
|
|
627
|
+
throw new Error('missing userKey');
|
|
628
|
+
}
|
|
629
|
+
if (lodash_1.default.isUndefined(params.backupKey)) {
|
|
630
|
+
throw new Error('missing backupKey');
|
|
631
|
+
}
|
|
632
|
+
if (lodash_1.default.isUndefined(params.walletPassphrase) && !params.userKey.startsWith('xpub') && !params.isTss) {
|
|
633
|
+
throw new Error('missing wallet passphrase');
|
|
634
|
+
}
|
|
635
|
+
if (lodash_1.default.isUndefined(params.walletContractAddress) || !this.isValidAddress(params.walletContractAddress)) {
|
|
636
|
+
throw new Error('invalid walletContractAddress');
|
|
637
|
+
}
|
|
638
|
+
if (lodash_1.default.isUndefined(params.recoveryDestination) || !this.isValidAddress(params.recoveryDestination)) {
|
|
639
|
+
throw new Error('invalid recoveryDestination');
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Method to sign tss recovery transaction
|
|
644
|
+
* @param {ECDSA.KeyCombined} userKeyCombined
|
|
645
|
+
* @param {ECDSA.KeyCombined} backupKeyCombined
|
|
646
|
+
* @param {string} txHex
|
|
647
|
+
* @param {Object} options
|
|
648
|
+
* @param {EcdsaTypes.SerializedNtilde} options.rangeProofChallenge
|
|
649
|
+
* @returns {Promise<ECDSAMethodTypes.Signature>}
|
|
650
|
+
*/
|
|
651
|
+
async signRecoveryTSS(userKeyCombined, backupKeyCombined, txHex, { rangeProofChallenge, } = {}) {
|
|
652
|
+
if (!userKeyCombined || !backupKeyCombined) {
|
|
653
|
+
throw new Error('Missing key combined shares for user or backup');
|
|
654
|
+
}
|
|
655
|
+
const MPC = new sdk_core_1.Ecdsa();
|
|
656
|
+
const signerOneIndex = userKeyCombined.xShare.i;
|
|
657
|
+
const signerTwoIndex = backupKeyCombined.xShare.i;
|
|
658
|
+
rangeProofChallenge =
|
|
659
|
+
rangeProofChallenge !== null && rangeProofChallenge !== void 0 ? rangeProofChallenge : sdk_lib_mpc_1.EcdsaTypes.serializeNtildeWithProofs(await sdk_lib_mpc_1.EcdsaRangeProof.generateNtilde());
|
|
660
|
+
const userToBackupPaillierChallenge = await sdk_lib_mpc_1.EcdsaPaillierProof.generateP((0, sdk_core_1.hexToBigInt)(userKeyCombined.yShares[signerTwoIndex].n));
|
|
661
|
+
const backupToUserPaillierChallenge = await sdk_lib_mpc_1.EcdsaPaillierProof.generateP((0, sdk_core_1.hexToBigInt)(backupKeyCombined.yShares[signerOneIndex].n));
|
|
662
|
+
const userXShare = MPC.appendChallenge(userKeyCombined.xShare, rangeProofChallenge, sdk_lib_mpc_1.EcdsaTypes.serializePaillierChallenge({ p: userToBackupPaillierChallenge }));
|
|
663
|
+
const userYShare = MPC.appendChallenge(userKeyCombined.yShares[signerTwoIndex], rangeProofChallenge, sdk_lib_mpc_1.EcdsaTypes.serializePaillierChallenge({ p: backupToUserPaillierChallenge }));
|
|
664
|
+
const backupXShare = MPC.appendChallenge(backupKeyCombined.xShare, rangeProofChallenge, sdk_lib_mpc_1.EcdsaTypes.serializePaillierChallenge({ p: backupToUserPaillierChallenge }));
|
|
665
|
+
const backupYShare = MPC.appendChallenge(backupKeyCombined.yShares[signerOneIndex], rangeProofChallenge, sdk_lib_mpc_1.EcdsaTypes.serializePaillierChallenge({ p: userToBackupPaillierChallenge }));
|
|
666
|
+
const signShares = await MPC.signShare(userXShare, userYShare);
|
|
667
|
+
const signConvertS21 = await MPC.signConvertStep1({
|
|
668
|
+
xShare: backupXShare,
|
|
669
|
+
yShare: backupYShare,
|
|
670
|
+
kShare: signShares.kShare,
|
|
671
|
+
});
|
|
672
|
+
const signConvertS12 = await MPC.signConvertStep2({
|
|
673
|
+
aShare: signConvertS21.aShare,
|
|
674
|
+
wShare: signShares.wShare,
|
|
675
|
+
});
|
|
676
|
+
const signConvertS21_2 = await MPC.signConvertStep3({
|
|
677
|
+
muShare: signConvertS12.muShare,
|
|
678
|
+
bShare: signConvertS21.bShare,
|
|
679
|
+
});
|
|
680
|
+
const [signCombineOne, signCombineTwo] = [
|
|
681
|
+
MPC.signCombine({
|
|
682
|
+
gShare: signConvertS12.gShare,
|
|
683
|
+
signIndex: {
|
|
684
|
+
i: signConvertS12.muShare.i,
|
|
685
|
+
j: signConvertS12.muShare.j,
|
|
686
|
+
},
|
|
687
|
+
}),
|
|
688
|
+
MPC.signCombine({
|
|
689
|
+
gShare: signConvertS21_2.gShare,
|
|
690
|
+
signIndex: {
|
|
691
|
+
i: signConvertS21_2.signIndex.i,
|
|
692
|
+
j: signConvertS21_2.signIndex.j,
|
|
693
|
+
},
|
|
694
|
+
}),
|
|
695
|
+
];
|
|
696
|
+
const MESSAGE = Buffer.from(txHex, 'hex');
|
|
697
|
+
const [signA, signB] = [
|
|
698
|
+
MPC.sign(MESSAGE, signCombineOne.oShare, signCombineTwo.dShare, (0, keccak_1.default)('keccak256')),
|
|
699
|
+
MPC.sign(MESSAGE, signCombineTwo.oShare, signCombineOne.dShare, (0, keccak_1.default)('keccak256')),
|
|
700
|
+
];
|
|
701
|
+
return MPC.constructSignature([signA, signB]);
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Helper which combines key shares of user and backup
|
|
705
|
+
* @param {string} userPublicOrPrivateKeyShare
|
|
706
|
+
* @param {string} backupPrivateOrPublicKeyShare
|
|
707
|
+
* @param {string} walletPassphrase
|
|
708
|
+
* @returns {[ECDSAMethodTypes.KeyCombined, ECDSAMethodTypes.KeyCombined]}
|
|
709
|
+
*/
|
|
710
|
+
getKeyCombinedFromTssKeyShares(userPublicOrPrivateKeyShare, backupPrivateOrPublicKeyShare, walletPassphrase) {
|
|
711
|
+
let backupPrv;
|
|
712
|
+
let userPrv;
|
|
713
|
+
try {
|
|
714
|
+
backupPrv = this.bitgo.decrypt({
|
|
715
|
+
input: backupPrivateOrPublicKeyShare,
|
|
716
|
+
password: walletPassphrase,
|
|
717
|
+
});
|
|
718
|
+
userPrv = this.bitgo.decrypt({
|
|
719
|
+
input: userPublicOrPrivateKeyShare,
|
|
720
|
+
password: walletPassphrase,
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
catch (e) {
|
|
724
|
+
throw new Error(`Error decrypting backup keychain: ${e.message}`);
|
|
725
|
+
}
|
|
726
|
+
const userSigningMaterial = JSON.parse(userPrv);
|
|
727
|
+
const backupSigningMaterial = JSON.parse(backupPrv);
|
|
728
|
+
if (!userSigningMaterial.backupNShare) {
|
|
729
|
+
throw new Error('Invalid user key - missing backupNShare');
|
|
730
|
+
}
|
|
731
|
+
if (!backupSigningMaterial.userNShare) {
|
|
732
|
+
throw new Error('Invalid backup key - missing userNShare');
|
|
733
|
+
}
|
|
734
|
+
const MPC = new sdk_core_1.Ecdsa();
|
|
735
|
+
const userKeyCombined = MPC.keyCombine(userSigningMaterial.pShare, [
|
|
736
|
+
userSigningMaterial.bitgoNShare,
|
|
737
|
+
userSigningMaterial.backupNShare,
|
|
738
|
+
]);
|
|
739
|
+
const userSigningKeyDerived = MPC.keyDerive(userSigningMaterial.pShare, [userSigningMaterial.bitgoNShare, userSigningMaterial.backupNShare], 'm/0');
|
|
740
|
+
const userKeyDerivedCombined = {
|
|
741
|
+
xShare: userSigningKeyDerived.xShare,
|
|
742
|
+
yShares: userKeyCombined.yShares,
|
|
743
|
+
};
|
|
744
|
+
const backupKeyCombined = MPC.keyCombine(backupSigningMaterial.pShare, [
|
|
745
|
+
userSigningKeyDerived.nShares[2],
|
|
746
|
+
backupSigningMaterial.bitgoNShare,
|
|
747
|
+
]);
|
|
748
|
+
if (userKeyDerivedCombined.xShare.y !== backupKeyCombined.xShare.y ||
|
|
749
|
+
userKeyDerivedCombined.xShare.chaincode !== backupKeyCombined.xShare.chaincode) {
|
|
750
|
+
throw new Error('Common keychains do not match');
|
|
751
|
+
}
|
|
752
|
+
return [userKeyDerivedCombined, backupKeyCombined];
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Helper which Adds signatures to tx object and re-serializes tx
|
|
756
|
+
* @param {EthLikeCommon.default} ethCommon
|
|
757
|
+
* @param {EthLikeTxLib.FeeMarketEIP1559Transaction | EthLikeTxLib.Transaction} tx
|
|
758
|
+
* @param {ECDSAMethodTypes.Signature} signature
|
|
759
|
+
* @returns {EthLikeTxLib.FeeMarketEIP1559Transaction | EthLikeTxLib.Transaction}
|
|
760
|
+
*/
|
|
761
|
+
getSignedTxFromSignature(ethCommon, tx, signature) {
|
|
762
|
+
// get signed Tx from signature
|
|
763
|
+
const txData = tx.toJSON();
|
|
764
|
+
const yParity = signature.recid;
|
|
765
|
+
const baseParams = {
|
|
766
|
+
to: txData.to,
|
|
767
|
+
nonce: new bn_js_1.default((0, ethereumjs_util_1.stripHexPrefix)(txData.nonce), 'hex'),
|
|
768
|
+
value: new bn_js_1.default((0, ethereumjs_util_1.stripHexPrefix)(txData.value), 'hex'),
|
|
769
|
+
gasLimit: new bn_js_1.default((0, ethereumjs_util_1.stripHexPrefix)(txData.gasLimit), 'hex'),
|
|
770
|
+
data: txData.data,
|
|
771
|
+
r: (0, ethereumjs_util_1.addHexPrefix)(signature.r),
|
|
772
|
+
s: (0, ethereumjs_util_1.addHexPrefix)(signature.s),
|
|
773
|
+
};
|
|
774
|
+
let finalTx;
|
|
775
|
+
if (txData.maxFeePerGas && txData.maxPriorityFeePerGas) {
|
|
776
|
+
finalTx = tx_1.FeeMarketEIP1559Transaction.fromTxData({
|
|
777
|
+
...baseParams,
|
|
778
|
+
maxPriorityFeePerGas: new bn_js_1.default((0, ethereumjs_util_1.stripHexPrefix)(txData.maxPriorityFeePerGas), 'hex'),
|
|
779
|
+
maxFeePerGas: new bn_js_1.default((0, ethereumjs_util_1.stripHexPrefix)(txData.maxFeePerGas), 'hex'),
|
|
780
|
+
v: new bn_js_1.default(yParity.toString()),
|
|
781
|
+
}, { common: ethCommon });
|
|
782
|
+
}
|
|
783
|
+
else if (txData.gasPrice) {
|
|
784
|
+
const v = BigInt(35) + BigInt(yParity) + BigInt(ethCommon.chainIdBN().toNumber()) * BigInt(2);
|
|
785
|
+
finalTx = tx_1.Transaction.fromTxData({
|
|
786
|
+
...baseParams,
|
|
787
|
+
v: new bn_js_1.default(v.toString()),
|
|
788
|
+
gasPrice: new bn_js_1.default((0, ethereumjs_util_1.stripHexPrefix)(txData.gasPrice.toString()), 'hex'),
|
|
789
|
+
}, { common: ethCommon });
|
|
790
|
+
}
|
|
791
|
+
return finalTx;
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Builds a funds recovery transaction without BitGo
|
|
795
|
+
* @param params
|
|
796
|
+
* @param {string} params.userKey - [encrypted] xprv
|
|
797
|
+
* @param {string} params.backupKey - [encrypted] xprv or xpub if the xprv is held by a KRS provider
|
|
798
|
+
* @param {string} params.walletPassphrase - used to decrypt userKey and backupKey
|
|
799
|
+
* @param {string} params.walletContractAddress - the ETH address of the wallet contract
|
|
800
|
+
* @param {string} params.krsProvider - necessary if backup key is held by KRS
|
|
801
|
+
* @param {string} params.recoveryDestination - target address to send recovered funds to
|
|
802
|
+
* @param {string} params.bitgoFeeAddress - wrong chain wallet fee address for evm based cross chain recovery txn
|
|
803
|
+
* @param {string} params.bitgoDestinationAddress - target bitgo address where fee will be sent for evm based cross chain recovery txn
|
|
804
|
+
*/
|
|
805
|
+
async recover(params) {
|
|
806
|
+
if (params.isTss) {
|
|
807
|
+
return this.recoverTSS(params);
|
|
808
|
+
}
|
|
809
|
+
return this.recoverEthLike(params);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Builds a funds recovery transaction without BitGo for non-TSS transaction
|
|
813
|
+
* @param params
|
|
814
|
+
* @param {string} params.userKey [encrypted] xprv or xpub
|
|
815
|
+
* @param {string} params.backupKey [encrypted] xprv or xpub if the xprv is held by a KRS provider
|
|
816
|
+
* @param {string} params.walletPassphrase used to decrypt userKey and backupKey
|
|
817
|
+
* @param {string} params.walletContractAddress the EthLike address of the wallet contract
|
|
818
|
+
* @param {string} params.krsProvider necessary if backup key is held by KRS
|
|
819
|
+
* @param {string} params.recoveryDestination target address to send recovered funds to
|
|
820
|
+
* @param {string} params.bitgoFeeAddress wrong chain wallet fee address for evm based cross chain recovery txn
|
|
821
|
+
* @param {string} params.bitgoDestinationAddress target bitgo address where fee will be sent for evm based cross chain recovery txn
|
|
822
|
+
* @returns {Promise<RecoveryInfo | OfflineVaultTxInfo>}
|
|
823
|
+
*/
|
|
824
|
+
async recoverEthLike(params) {
|
|
825
|
+
var _a, _b, _c;
|
|
826
|
+
// bitgoFeeAddress is only defined when it is a evm cross chain recovery
|
|
827
|
+
// as we use fee from this wrong chain address for the recovery txn on the correct chain.
|
|
828
|
+
if (params.bitgoFeeAddress) {
|
|
829
|
+
return this.recoverEthLikeforEvmBasedRecovery(params);
|
|
830
|
+
}
|
|
831
|
+
this.validateRecoveryParams(params);
|
|
832
|
+
const isUnsignedSweep = (0, sdk_core_1.getIsUnsignedSweep)(params);
|
|
833
|
+
// Clean up whitespace from entered values
|
|
834
|
+
let userKey = params.userKey.replace(/\s/g, '');
|
|
835
|
+
const backupKey = params.backupKey.replace(/\s/g, '');
|
|
836
|
+
const gasLimit = new exports.optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit));
|
|
837
|
+
const gasPrice = params.eip1559
|
|
838
|
+
? new exports.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas)
|
|
839
|
+
: new exports.optionalDeps.ethUtil.BN(this.setGasPrice(params.gasPrice));
|
|
840
|
+
if (!userKey.startsWith('xpub') && !userKey.startsWith('xprv')) {
|
|
841
|
+
try {
|
|
842
|
+
userKey = this.bitgo.decrypt({
|
|
843
|
+
input: userKey,
|
|
844
|
+
password: params.walletPassphrase,
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
catch (e) {
|
|
848
|
+
throw new Error(`Error decrypting user keychain: ${e.message}`);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
let backupKeyAddress;
|
|
852
|
+
let backupSigningKey;
|
|
853
|
+
if (isUnsignedSweep) {
|
|
854
|
+
const backupHDNode = utxo_lib_1.bip32.fromBase58(backupKey);
|
|
855
|
+
backupSigningKey = backupHDNode.publicKey;
|
|
856
|
+
backupKeyAddress = `0x${exports.optionalDeps.ethUtil.publicToAddress(backupSigningKey, true).toString('hex')}`;
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
// Decrypt backup private key and get address
|
|
860
|
+
let backupPrv;
|
|
861
|
+
try {
|
|
862
|
+
backupPrv = this.bitgo.decrypt({
|
|
863
|
+
input: backupKey,
|
|
864
|
+
password: params.walletPassphrase,
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
catch (e) {
|
|
868
|
+
throw new Error(`Error decrypting backup keychain: ${e.message}`);
|
|
869
|
+
}
|
|
870
|
+
const keyPair = new lib_1.KeyPair({ prv: backupPrv });
|
|
871
|
+
backupSigningKey = keyPair.getKeys().prv;
|
|
872
|
+
if (!backupSigningKey) {
|
|
873
|
+
throw new Error('no private key');
|
|
874
|
+
}
|
|
875
|
+
backupKeyAddress = keyPair.getAddress();
|
|
876
|
+
}
|
|
877
|
+
const backupKeyNonce = await this.getAddressNonce(backupKeyAddress);
|
|
878
|
+
// get balance of backupKey to ensure funds are available to pay fees
|
|
879
|
+
const backupKeyBalance = await this.queryAddressBalance(backupKeyAddress);
|
|
880
|
+
let totalGasNeeded = gasPrice.mul(gasLimit);
|
|
881
|
+
// On optimism chain, L1 fees is to be paid as well apart from L2 fees
|
|
882
|
+
// So we are adding the amount that can be used up as l1 fees
|
|
883
|
+
if (((_a = this.staticsCoin) === null || _a === void 0 ? void 0 : _a.family) === 'opeth') {
|
|
884
|
+
totalGasNeeded = totalGasNeeded.add(new exports.optionalDeps.ethUtil.BN(statics_1.ethGasConfigs.opethGasL1Fees));
|
|
885
|
+
}
|
|
886
|
+
const weiToGwei = 10 ** 9;
|
|
887
|
+
if (backupKeyBalance.lt(totalGasNeeded)) {
|
|
888
|
+
throw new Error(`Backup key address ${backupKeyAddress} has balance ${(backupKeyBalance / weiToGwei).toString()} Gwei.` +
|
|
889
|
+
`This address must have a balance of at least ${(totalGasNeeded / weiToGwei).toString()}` +
|
|
890
|
+
` Gwei to perform recoveries. Try sending some funds to this address then retry.`);
|
|
891
|
+
}
|
|
892
|
+
// get balance of wallet
|
|
893
|
+
const txAmount = await this.queryAddressBalance(params.walletContractAddress);
|
|
894
|
+
if (new bignumber_js_1.BigNumber(txAmount).isLessThanOrEqualTo(0)) {
|
|
895
|
+
throw new Error('Wallet does not have enough funds to recover');
|
|
896
|
+
}
|
|
897
|
+
// build recipients object
|
|
898
|
+
const recipients = [
|
|
899
|
+
{
|
|
900
|
+
address: params.recoveryDestination,
|
|
901
|
+
amount: txAmount.toString(10),
|
|
902
|
+
},
|
|
903
|
+
];
|
|
904
|
+
// Get sequence ID using contract call
|
|
905
|
+
// we need to wait between making two explorer api calls to avoid getting banned
|
|
906
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
907
|
+
const sequenceId = await this.querySequenceId(params.walletContractAddress);
|
|
908
|
+
let operationHash, signature;
|
|
909
|
+
// Get operation hash and sign it
|
|
910
|
+
if (!isUnsignedSweep) {
|
|
911
|
+
operationHash = this.getOperationSha3ForExecuteAndConfirm(recipients, this.getDefaultExpireTime(), sequenceId);
|
|
912
|
+
signature = sdk_core_1.Util.ethSignMsgHash(operationHash, sdk_core_1.Util.xprvToEthPrivateKey(userKey));
|
|
913
|
+
try {
|
|
914
|
+
sdk_core_1.Util.ecRecoverEthAddress(operationHash, signature);
|
|
915
|
+
}
|
|
916
|
+
catch (e) {
|
|
917
|
+
throw new Error('Invalid signature');
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
const txInfo = {
|
|
921
|
+
recipient: recipients[0],
|
|
922
|
+
expireTime: this.getDefaultExpireTime(),
|
|
923
|
+
contractSequenceId: sequenceId,
|
|
924
|
+
operationHash: operationHash,
|
|
925
|
+
signature: signature,
|
|
926
|
+
gasLimit: gasLimit.toString(10),
|
|
927
|
+
};
|
|
928
|
+
const txBuilder = this.getTransactionBuilder(params.common);
|
|
929
|
+
txBuilder.counter(backupKeyNonce);
|
|
930
|
+
txBuilder.contract(params.walletContractAddress);
|
|
931
|
+
let txFee;
|
|
932
|
+
if (params.eip1559) {
|
|
933
|
+
txFee = {
|
|
934
|
+
eip1559: {
|
|
935
|
+
maxPriorityFeePerGas: params.eip1559.maxPriorityFeePerGas,
|
|
936
|
+
maxFeePerGas: params.eip1559.maxFeePerGas,
|
|
937
|
+
},
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
txFee = { fee: gasPrice.toString() };
|
|
942
|
+
}
|
|
943
|
+
txBuilder.fee({
|
|
944
|
+
...txFee,
|
|
945
|
+
gasLimit: gasLimit.toString(),
|
|
946
|
+
});
|
|
947
|
+
const transferBuilder = txBuilder.transfer();
|
|
948
|
+
transferBuilder
|
|
949
|
+
.coin((_b = this.staticsCoin) === null || _b === void 0 ? void 0 : _b.name)
|
|
950
|
+
.amount(recipients[0].amount)
|
|
951
|
+
.contractSequenceId(sequenceId)
|
|
952
|
+
.expirationTime(this.getDefaultExpireTime())
|
|
953
|
+
.to(params.recoveryDestination);
|
|
954
|
+
const tx = await txBuilder.build();
|
|
955
|
+
if (isUnsignedSweep) {
|
|
956
|
+
const response = {
|
|
957
|
+
txHex: tx.toBroadcastFormat(),
|
|
958
|
+
userKey,
|
|
959
|
+
backupKey,
|
|
960
|
+
coin: this.getChain(),
|
|
961
|
+
gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
|
|
962
|
+
gasLimit,
|
|
963
|
+
recipients: [txInfo.recipient],
|
|
964
|
+
walletContractAddress: tx.toJson().to,
|
|
965
|
+
amount: txInfo.recipient.amount,
|
|
966
|
+
backupKeyNonce,
|
|
967
|
+
eip1559: params.eip1559,
|
|
968
|
+
};
|
|
969
|
+
lodash_1.default.extend(response, txInfo);
|
|
970
|
+
response.nextContractSequenceId = response.contractSequenceId;
|
|
971
|
+
return response;
|
|
972
|
+
}
|
|
973
|
+
txBuilder
|
|
974
|
+
.transfer()
|
|
975
|
+
.coin((_c = this.staticsCoin) === null || _c === void 0 ? void 0 : _c.name)
|
|
976
|
+
.key(new lib_1.KeyPair({ prv: userKey }).getKeys().prv);
|
|
977
|
+
txBuilder.sign({ key: backupSigningKey });
|
|
978
|
+
const signedTx = await txBuilder.build();
|
|
979
|
+
return {
|
|
980
|
+
id: signedTx.toJson().id,
|
|
981
|
+
tx: signedTx.toBroadcastFormat(),
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Builds a unsigned (for cold, custody wallet) or
|
|
986
|
+
* half-signed (for hot wallet) evm cross chain recovery transaction with
|
|
987
|
+
* same expected arguments as recover method.
|
|
988
|
+
* This helps recover funds from evm based wrong chain.
|
|
989
|
+
* @param {RecoverOptions} params
|
|
990
|
+
* @returns {Promise<RecoveryInfo | OfflineVaultTxInfo>}
|
|
991
|
+
*/
|
|
992
|
+
async recoverEthLikeforEvmBasedRecovery(params) {
|
|
993
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
994
|
+
this.validateEvmBasedRecoveryParams(params);
|
|
995
|
+
// Clean up whitespace from entered values
|
|
996
|
+
const userKey = params.userKey.replace(/\s/g, '');
|
|
997
|
+
const bitgoFeeAddress = (_a = params.bitgoFeeAddress) === null || _a === void 0 ? void 0 : _a.replace(/\s/g, '').toLowerCase();
|
|
998
|
+
const bitgoDestinationAddress = (_b = params.bitgoDestinationAddress) === null || _b === void 0 ? void 0 : _b.replace(/\s/g, '').toLowerCase();
|
|
999
|
+
const recoveryDestination = (_c = params.recoveryDestination) === null || _c === void 0 ? void 0 : _c.replace(/\s/g, '').toLowerCase();
|
|
1000
|
+
const walletContractAddress = (_d = params.walletContractAddress) === null || _d === void 0 ? void 0 : _d.replace(/\s/g, '').toLowerCase();
|
|
1001
|
+
const tokenContractAddress = (_e = params.tokenContractAddress) === null || _e === void 0 ? void 0 : _e.replace(/\s/g, '').toLowerCase();
|
|
1002
|
+
let userSigningKey;
|
|
1003
|
+
let userKeyPrv;
|
|
1004
|
+
if (params.walletPassphrase) {
|
|
1005
|
+
if (!userKey.startsWith('xpub') && !userKey.startsWith('xprv')) {
|
|
1006
|
+
try {
|
|
1007
|
+
userKeyPrv = this.bitgo.decrypt({
|
|
1008
|
+
input: userKey,
|
|
1009
|
+
password: params.walletPassphrase,
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
catch (e) {
|
|
1013
|
+
throw new Error(`Error decrypting user keychain: ${e.message}`);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
const keyPair = new lib_1.KeyPair({ prv: userKeyPrv });
|
|
1017
|
+
userSigningKey = keyPair.getKeys().prv;
|
|
1018
|
+
if (!userSigningKey) {
|
|
1019
|
+
throw new Error('no private key');
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
const gasLimit = new exports.optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit));
|
|
1023
|
+
const gasPrice = params.eip1559
|
|
1024
|
+
? new exports.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas)
|
|
1025
|
+
: new exports.optionalDeps.ethUtil.BN(this.setGasPrice(params.gasPrice));
|
|
1026
|
+
const bitgoFeeAddressNonce = await this.getAddressNonce(bitgoFeeAddress);
|
|
1027
|
+
// get balance of bitgoFeeAddress to ensure funds are available to pay fees
|
|
1028
|
+
const bitgoFeeAddressBalance = await this.queryAddressBalance(bitgoFeeAddress);
|
|
1029
|
+
const totalGasNeeded = gasPrice.mul(gasLimit);
|
|
1030
|
+
const weiToGwei = 10 ** 9;
|
|
1031
|
+
if (bitgoFeeAddressBalance.lt(totalGasNeeded)) {
|
|
1032
|
+
throw new Error(`Fee address ${bitgoFeeAddress} has balance ${(bitgoFeeAddressBalance / weiToGwei).toString()} Gwei.` +
|
|
1033
|
+
`This address must have a balance of at least ${(totalGasNeeded / weiToGwei).toString()}` +
|
|
1034
|
+
` Gwei to perform recoveries. Try sending some ${this.getChain()} to this address then retry.`);
|
|
1035
|
+
}
|
|
1036
|
+
if (tokenContractAddress) {
|
|
1037
|
+
return this.recoverEthLikeTokenforEvmBasedRecovery(params, bitgoFeeAddressNonce, gasLimit, gasPrice, userKey, userSigningKey);
|
|
1038
|
+
}
|
|
1039
|
+
// get balance of wallet
|
|
1040
|
+
const txAmount = await this.queryAddressBalance(walletContractAddress);
|
|
1041
|
+
const bitgoFeePercentage = 0; // TODO: BG-71912 can change the fee% here.
|
|
1042
|
+
const bitgoFeeAmount = txAmount * (bitgoFeePercentage / 100);
|
|
1043
|
+
// build recipients object
|
|
1044
|
+
const recipients = [
|
|
1045
|
+
{
|
|
1046
|
+
address: recoveryDestination,
|
|
1047
|
+
amount: new bignumber_js_1.BigNumber(txAmount).minus(bitgoFeeAmount).toFixed(),
|
|
1048
|
+
},
|
|
1049
|
+
];
|
|
1050
|
+
if (bitgoFeePercentage > 0) {
|
|
1051
|
+
if (lodash_1.default.isUndefined(bitgoDestinationAddress) || !this.isValidAddress(bitgoDestinationAddress)) {
|
|
1052
|
+
throw new Error('invalid bitgoDestinationAddress');
|
|
1053
|
+
}
|
|
1054
|
+
recipients.push({
|
|
1055
|
+
address: bitgoDestinationAddress,
|
|
1056
|
+
amount: bitgoFeeAmount.toString(10),
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
// calculate batch data
|
|
1060
|
+
const BATCH_METHOD_NAME = 'batch';
|
|
1061
|
+
const BATCH_METHOD_TYPES = ['address[]', 'uint256[]'];
|
|
1062
|
+
const batchExecutionInfo = this.getBatchExecutionInfo(recipients);
|
|
1063
|
+
const batchData = exports.optionalDeps.ethUtil.addHexPrefix(this.getMethodCallData(BATCH_METHOD_NAME, BATCH_METHOD_TYPES, batchExecutionInfo.values).toString('hex'));
|
|
1064
|
+
// Get sequence ID using contract call
|
|
1065
|
+
// we need to wait between making two explorer api calls to avoid getting banned
|
|
1066
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
1067
|
+
const sequenceId = await this.querySequenceId(walletContractAddress);
|
|
1068
|
+
const txInfo = {
|
|
1069
|
+
recipients: recipients,
|
|
1070
|
+
expireTime: this.getDefaultExpireTime(),
|
|
1071
|
+
contractSequenceId: sequenceId,
|
|
1072
|
+
gasLimit: gasLimit.toString(10),
|
|
1073
|
+
isEvmBasedCrossChainRecovery: true,
|
|
1074
|
+
};
|
|
1075
|
+
const network = this.getNetwork();
|
|
1076
|
+
const batcherContractAddress = network === null || network === void 0 ? void 0 : network.batcherContractAddress;
|
|
1077
|
+
const txBuilder = this.getTransactionBuilder(params.common);
|
|
1078
|
+
txBuilder.counter(bitgoFeeAddressNonce);
|
|
1079
|
+
txBuilder.contract(walletContractAddress);
|
|
1080
|
+
let txFee;
|
|
1081
|
+
if (params.eip1559) {
|
|
1082
|
+
txFee = {
|
|
1083
|
+
eip1559: {
|
|
1084
|
+
maxPriorityFeePerGas: params.eip1559.maxPriorityFeePerGas,
|
|
1085
|
+
maxFeePerGas: params.eip1559.maxFeePerGas,
|
|
1086
|
+
},
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
else {
|
|
1090
|
+
txFee = { fee: gasPrice.toString() };
|
|
1091
|
+
}
|
|
1092
|
+
txBuilder.fee({
|
|
1093
|
+
...txFee,
|
|
1094
|
+
gasLimit: gasLimit.toString(),
|
|
1095
|
+
});
|
|
1096
|
+
const transferBuilder = txBuilder.transfer();
|
|
1097
|
+
if (!batcherContractAddress) {
|
|
1098
|
+
transferBuilder
|
|
1099
|
+
.coin((_f = this.staticsCoin) === null || _f === void 0 ? void 0 : _f.name)
|
|
1100
|
+
.amount(batchExecutionInfo.totalAmount)
|
|
1101
|
+
.contractSequenceId(sequenceId)
|
|
1102
|
+
.expirationTime(this.getDefaultExpireTime())
|
|
1103
|
+
.to(recoveryDestination);
|
|
1104
|
+
}
|
|
1105
|
+
else {
|
|
1106
|
+
transferBuilder
|
|
1107
|
+
.coin((_g = this.staticsCoin) === null || _g === void 0 ? void 0 : _g.name)
|
|
1108
|
+
.amount(batchExecutionInfo.totalAmount)
|
|
1109
|
+
.contractSequenceId(sequenceId)
|
|
1110
|
+
.expirationTime(this.getDefaultExpireTime())
|
|
1111
|
+
.to(batcherContractAddress)
|
|
1112
|
+
.data(batchData);
|
|
1113
|
+
}
|
|
1114
|
+
if (params.walletPassphrase) {
|
|
1115
|
+
transferBuilder.key(userSigningKey);
|
|
1116
|
+
}
|
|
1117
|
+
// If the intended chain is arbitrum or optimism, we need to use wallet version 4
|
|
1118
|
+
// since these contracts construct operationHash differently
|
|
1119
|
+
if (params.intendedChain && ['arbeth', 'opeth'].includes(statics_1.coins.get(params.intendedChain).family)) {
|
|
1120
|
+
txBuilder.walletVersion(4);
|
|
1121
|
+
}
|
|
1122
|
+
const tx = await txBuilder.build();
|
|
1123
|
+
const response = {
|
|
1124
|
+
txHex: tx.toBroadcastFormat(),
|
|
1125
|
+
userKey,
|
|
1126
|
+
coin: this.getChain(),
|
|
1127
|
+
gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
|
|
1128
|
+
gasLimit,
|
|
1129
|
+
recipients: txInfo.recipients,
|
|
1130
|
+
walletContractAddress: tx.toJson().to,
|
|
1131
|
+
amount: batchExecutionInfo.totalAmount,
|
|
1132
|
+
backupKeyNonce: bitgoFeeAddressNonce,
|
|
1133
|
+
eip1559: params.eip1559,
|
|
1134
|
+
};
|
|
1135
|
+
lodash_1.default.extend(response, txInfo);
|
|
1136
|
+
response.nextContractSequenceId = response.contractSequenceId;
|
|
1137
|
+
if (params.walletPassphrase) {
|
|
1138
|
+
const halfSignedTxn = {
|
|
1139
|
+
halfSigned: {
|
|
1140
|
+
txHex: tx.toBroadcastFormat(),
|
|
1141
|
+
recipients: txInfo.recipients,
|
|
1142
|
+
expireTime: txInfo.expireTime,
|
|
1143
|
+
},
|
|
1144
|
+
};
|
|
1145
|
+
lodash_1.default.extend(response, halfSignedTxn);
|
|
1146
|
+
const feesUsed = {
|
|
1147
|
+
gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
|
|
1148
|
+
gasLimit: exports.optionalDeps.ethUtil.bufferToInt(gasLimit).toFixed(),
|
|
1149
|
+
};
|
|
1150
|
+
response['feesUsed'] = feesUsed;
|
|
1151
|
+
}
|
|
1152
|
+
return response;
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Query explorer for the balance of an address for a token
|
|
1156
|
+
* @param {string} tokenContractAddress - address where the token smart contract is hosted
|
|
1157
|
+
* @param {string} walletContractAddress - address of the wallet
|
|
1158
|
+
* @returns {BigNumber} token balaance in base units
|
|
1159
|
+
*/
|
|
1160
|
+
async queryAddressTokenBalance(tokenContractAddress, walletContractAddress) {
|
|
1161
|
+
if (!exports.optionalDeps.ethUtil.isValidAddress(tokenContractAddress)) {
|
|
1162
|
+
throw new Error('cannot get balance for invalid token address');
|
|
1163
|
+
}
|
|
1164
|
+
if (!exports.optionalDeps.ethUtil.isValidAddress(walletContractAddress)) {
|
|
1165
|
+
throw new Error('cannot get token balance for invalid wallet address');
|
|
1166
|
+
}
|
|
1167
|
+
const result = await this.recoveryBlockchainExplorerQuery({
|
|
1168
|
+
module: 'account',
|
|
1169
|
+
action: 'tokenbalance',
|
|
1170
|
+
contractaddress: tokenContractAddress,
|
|
1171
|
+
address: walletContractAddress,
|
|
1172
|
+
tag: 'latest',
|
|
1173
|
+
});
|
|
1174
|
+
// throw if the result does not exist or the result is not a valid number
|
|
1175
|
+
if (!result || !result.result || isNaN(result.result)) {
|
|
1176
|
+
throw new Error(`Could not obtain token address balance for ${tokenContractAddress} from Etherscan, got: ${result.result}`);
|
|
1177
|
+
}
|
|
1178
|
+
return new exports.optionalDeps.ethUtil.BN(result.result, 10);
|
|
1179
|
+
}
|
|
1180
|
+
async recoverEthLikeTokenforEvmBasedRecovery(params, bitgoFeeAddressNonce, gasLimit, gasPrice, userKey, userSigningKey) {
|
|
1181
|
+
var _a, _b, _c;
|
|
1182
|
+
// get token balance of wallet
|
|
1183
|
+
const txAmount = await this.queryAddressTokenBalance(params.tokenContractAddress, params.walletContractAddress);
|
|
1184
|
+
// build recipients object
|
|
1185
|
+
const recipients = [
|
|
1186
|
+
{
|
|
1187
|
+
address: params.recoveryDestination,
|
|
1188
|
+
amount: new bignumber_js_1.BigNumber(txAmount).toFixed(),
|
|
1189
|
+
},
|
|
1190
|
+
];
|
|
1191
|
+
// Get sequence ID using contract call
|
|
1192
|
+
// we need to wait between making two explorer api calls to avoid getting banned
|
|
1193
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
1194
|
+
const sequenceId = await this.querySequenceId(params.walletContractAddress);
|
|
1195
|
+
const txInfo = {
|
|
1196
|
+
recipients: recipients,
|
|
1197
|
+
expireTime: this.getDefaultExpireTime(),
|
|
1198
|
+
contractSequenceId: sequenceId,
|
|
1199
|
+
gasLimit: gasLimit.toString(10),
|
|
1200
|
+
isEvmBasedCrossChainRecovery: true,
|
|
1201
|
+
};
|
|
1202
|
+
const txBuilder = this.getTransactionBuilder(params.common);
|
|
1203
|
+
txBuilder.counter(bitgoFeeAddressNonce);
|
|
1204
|
+
txBuilder.contract(params.walletContractAddress);
|
|
1205
|
+
let txFee;
|
|
1206
|
+
if (params.eip1559) {
|
|
1207
|
+
txFee = {
|
|
1208
|
+
eip1559: {
|
|
1209
|
+
maxPriorityFeePerGas: params.eip1559.maxPriorityFeePerGas,
|
|
1210
|
+
maxFeePerGas: params.eip1559.maxFeePerGas,
|
|
1211
|
+
},
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
else {
|
|
1215
|
+
txFee = { fee: gasPrice.toString() };
|
|
1216
|
+
}
|
|
1217
|
+
txBuilder.fee({
|
|
1218
|
+
...txFee,
|
|
1219
|
+
gasLimit: gasLimit.toString(),
|
|
1220
|
+
});
|
|
1221
|
+
const transferBuilder = txBuilder.transfer();
|
|
1222
|
+
const network = this.getNetwork();
|
|
1223
|
+
const token = (_b = (0, lib_1.getToken)(params.tokenContractAddress, network, (_a = this.staticsCoin) === null || _a === void 0 ? void 0 : _a.family)) === null || _b === void 0 ? void 0 : _b.name;
|
|
1224
|
+
transferBuilder
|
|
1225
|
+
.amount(txAmount)
|
|
1226
|
+
.contractSequenceId(sequenceId)
|
|
1227
|
+
.expirationTime(this.getDefaultExpireTime())
|
|
1228
|
+
.to(params.recoveryDestination);
|
|
1229
|
+
if (token) {
|
|
1230
|
+
transferBuilder.coin(token);
|
|
1231
|
+
}
|
|
1232
|
+
else {
|
|
1233
|
+
transferBuilder
|
|
1234
|
+
.coin((_c = this.staticsCoin) === null || _c === void 0 ? void 0 : _c.name)
|
|
1235
|
+
.tokenContractAddress(params.tokenContractAddress);
|
|
1236
|
+
}
|
|
1237
|
+
if (params.walletPassphrase) {
|
|
1238
|
+
txBuilder.transfer().key(userSigningKey);
|
|
1239
|
+
}
|
|
1240
|
+
// If the intended chain is arbitrum or optimism, we need to use wallet version 4
|
|
1241
|
+
// since these contracts construct operationHash differently
|
|
1242
|
+
if (params.intendedChain && ['arbeth', 'opeth'].includes(statics_1.coins.get(params.intendedChain).family)) {
|
|
1243
|
+
txBuilder.walletVersion(4);
|
|
1244
|
+
}
|
|
1245
|
+
const tx = await txBuilder.build();
|
|
1246
|
+
const response = {
|
|
1247
|
+
txHex: tx.toBroadcastFormat(),
|
|
1248
|
+
userKey,
|
|
1249
|
+
coin: token ? token : this.getChain(),
|
|
1250
|
+
gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
|
|
1251
|
+
gasLimit,
|
|
1252
|
+
recipients: txInfo.recipients,
|
|
1253
|
+
walletContractAddress: tx.toJson().to,
|
|
1254
|
+
amount: txAmount.toString(),
|
|
1255
|
+
backupKeyNonce: bitgoFeeAddressNonce,
|
|
1256
|
+
eip1559: params.eip1559,
|
|
1257
|
+
};
|
|
1258
|
+
lodash_1.default.extend(response, txInfo);
|
|
1259
|
+
response.nextContractSequenceId = response.contractSequenceId;
|
|
1260
|
+
if (params.walletPassphrase) {
|
|
1261
|
+
const halfSignedTxn = {
|
|
1262
|
+
halfSigned: {
|
|
1263
|
+
txHex: tx.toBroadcastFormat(),
|
|
1264
|
+
recipients: txInfo.recipients,
|
|
1265
|
+
expireTime: txInfo.expireTime,
|
|
1266
|
+
},
|
|
1267
|
+
};
|
|
1268
|
+
lodash_1.default.extend(response, halfSignedTxn);
|
|
1269
|
+
const feesUsed = {
|
|
1270
|
+
gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
|
|
1271
|
+
gasLimit: exports.optionalDeps.ethUtil.bufferToInt(gasLimit).toFixed(),
|
|
1272
|
+
};
|
|
1273
|
+
response['feesUsed'] = feesUsed;
|
|
1274
|
+
}
|
|
1275
|
+
return response;
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Validate evm based cross chain recovery params
|
|
1279
|
+
* @param params {RecoverOptions}
|
|
1280
|
+
* @returns {void}
|
|
1281
|
+
*/
|
|
1282
|
+
validateEvmBasedRecoveryParams(params) {
|
|
1283
|
+
if (lodash_1.default.isUndefined(params.bitgoFeeAddress) || !this.isValidAddress(params.bitgoFeeAddress)) {
|
|
1284
|
+
throw new Error('invalid bitgoFeeAddress');
|
|
1285
|
+
}
|
|
1286
|
+
if (lodash_1.default.isUndefined(params.walletContractAddress) || !this.isValidAddress(params.walletContractAddress)) {
|
|
1287
|
+
throw new Error('invalid walletContractAddress');
|
|
1288
|
+
}
|
|
1289
|
+
if (lodash_1.default.isUndefined(params.recoveryDestination) || !this.isValidAddress(params.recoveryDestination)) {
|
|
1290
|
+
throw new Error('invalid recoveryDestination');
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Return types, values, and total amount in wei to send in a batch transaction, using the method signature
|
|
1295
|
+
* `distributeBatch(address[], uint256[])`
|
|
1296
|
+
* @param {Recipient[]} recipients - transaction recipients
|
|
1297
|
+
* @returns {GetBatchExecutionInfoRT} information needed to execute the batch transaction
|
|
1298
|
+
*/
|
|
1299
|
+
getBatchExecutionInfo(recipients) {
|
|
1300
|
+
const addresses = [];
|
|
1301
|
+
const amounts = [];
|
|
1302
|
+
let sum = new bignumber_js_1.BigNumber('0');
|
|
1303
|
+
lodash_1.default.forEach(recipients, ({ address, amount }) => {
|
|
1304
|
+
addresses.push(address);
|
|
1305
|
+
amounts.push(amount);
|
|
1306
|
+
sum = sum.plus(amount);
|
|
1307
|
+
});
|
|
1308
|
+
return {
|
|
1309
|
+
values: [addresses, amounts],
|
|
1310
|
+
totalAmount: sum.toFixed(),
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* Build arguments to call the send method on the wallet contract
|
|
1315
|
+
* @param txInfo
|
|
1316
|
+
*/
|
|
1317
|
+
getSendMethodArgs(txInfo) {
|
|
1318
|
+
// Method signature is
|
|
1319
|
+
// sendMultiSig(address toAddress, uint value, bytes data, uint expireTime, uint sequenceId, bytes signature)
|
|
1320
|
+
return [
|
|
1321
|
+
{
|
|
1322
|
+
name: 'toAddress',
|
|
1323
|
+
type: 'address',
|
|
1324
|
+
value: txInfo.recipient.address,
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
name: 'value',
|
|
1328
|
+
type: 'uint',
|
|
1329
|
+
value: txInfo.recipient.amount,
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
name: 'data',
|
|
1333
|
+
type: 'bytes',
|
|
1334
|
+
value: exports.optionalDeps.ethUtil.toBuffer(exports.optionalDeps.ethUtil.addHexPrefix(txInfo.recipient.data || '')),
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
name: 'expireTime',
|
|
1338
|
+
type: 'uint',
|
|
1339
|
+
value: txInfo.expireTime,
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
name: 'sequenceId',
|
|
1343
|
+
type: 'uint',
|
|
1344
|
+
value: txInfo.contractSequenceId,
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
name: 'signature',
|
|
1348
|
+
type: 'bytes',
|
|
1349
|
+
value: exports.optionalDeps.ethUtil.toBuffer(exports.optionalDeps.ethUtil.addHexPrefix(txInfo.signature)),
|
|
1350
|
+
},
|
|
1351
|
+
];
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Recovers a tx with TSS key shares
|
|
1355
|
+
* same expected arguments as recover method, but with TSS key shares
|
|
1356
|
+
*/
|
|
1357
|
+
async recoverTSS(params) {
|
|
1358
|
+
this.validateRecoveryParams(params);
|
|
1359
|
+
// Clean up whitespace from entered values
|
|
1360
|
+
const userPublicOrPrivateKeyShare = params.userKey.replace(/\s/g, '');
|
|
1361
|
+
const backupPrivateOrPublicKeyShare = params.backupKey.replace(/\s/g, '');
|
|
1362
|
+
const gasLimit = new exports.optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit));
|
|
1363
|
+
const gasPrice = params.eip1559
|
|
1364
|
+
? new exports.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas)
|
|
1365
|
+
: new exports.optionalDeps.ethUtil.BN(this.setGasPrice(params.gasPrice));
|
|
1366
|
+
if ((0, sdk_core_1.getIsUnsignedSweep)({
|
|
1367
|
+
userKey: userPublicOrPrivateKeyShare,
|
|
1368
|
+
backupKey: backupPrivateOrPublicKeyShare,
|
|
1369
|
+
isTss: params.isTss,
|
|
1370
|
+
})) {
|
|
1371
|
+
const backupKeyPair = new lib_1.KeyPair({ pub: backupPrivateOrPublicKeyShare });
|
|
1372
|
+
const baseAddress = backupKeyPair.getAddress();
|
|
1373
|
+
const { txInfo, tx, nonce } = await this.buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params);
|
|
1374
|
+
return this.formatForOfflineVaultTSS(txInfo, tx, userPublicOrPrivateKeyShare, backupPrivateOrPublicKeyShare, gasPrice, gasLimit, nonce, params.eip1559, params.replayProtectionOptions);
|
|
1375
|
+
}
|
|
1376
|
+
else {
|
|
1377
|
+
const isGG18SigningMaterial = this.isGG18SigningMaterial(userPublicOrPrivateKeyShare, params.walletPassphrase);
|
|
1378
|
+
let signature;
|
|
1379
|
+
let unsignedTx;
|
|
1380
|
+
if (isGG18SigningMaterial) {
|
|
1381
|
+
const [userKeyCombined, backupKeyCombined] = this.getKeyCombinedFromTssKeyShares(userPublicOrPrivateKeyShare, backupPrivateOrPublicKeyShare, params.walletPassphrase);
|
|
1382
|
+
const backupKeyPair = new lib_1.KeyPair({ pub: backupKeyCombined.xShare.y });
|
|
1383
|
+
const baseAddress = backupKeyPair.getAddress();
|
|
1384
|
+
unsignedTx = (await this.buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params)).tx;
|
|
1385
|
+
signature = await this.signRecoveryTSS(userKeyCombined, backupKeyCombined, unsignedTx.getMessageToSign(false).toString('hex'));
|
|
1386
|
+
}
|
|
1387
|
+
else {
|
|
1388
|
+
const { userKeyShare, backupKeyShare, commonKeyChain, baseAddress } = await this.getMpcV2RecoveryKeyShares(userPublicOrPrivateKeyShare, backupPrivateOrPublicKeyShare, params.walletPassphrase);
|
|
1389
|
+
unsignedTx = (await this.buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params)).tx;
|
|
1390
|
+
signature = await AbstractEthLikeNewCoins.signRecoveryMpcV2(unsignedTx, userKeyShare, backupKeyShare, commonKeyChain);
|
|
1391
|
+
}
|
|
1392
|
+
const ethCommmon = AbstractEthLikeNewCoins.getEthLikeCommon(params.eip1559, params.replayProtectionOptions);
|
|
1393
|
+
const signedTx = this.getSignedTxFromSignature(ethCommmon, unsignedTx, signature);
|
|
1394
|
+
return {
|
|
1395
|
+
id: (0, ethereumjs_util_1.addHexPrefix)(signedTx.hash().toString('hex')),
|
|
1396
|
+
tx: (0, ethereumjs_util_1.addHexPrefix)(signedTx.serialize().toString('hex')),
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
static async signRecoveryMpcV2(tx, userKeyShare, backupKeyShare, commonKeyChain) {
|
|
1401
|
+
const messageHash = tx.getMessageToSign(true);
|
|
1402
|
+
const userDsg = new sdk_lib_mpc_1.DklsDsg.Dsg(userKeyShare, 0, 'm/0', messageHash);
|
|
1403
|
+
const backupDsg = new sdk_lib_mpc_1.DklsDsg.Dsg(backupKeyShare, 1, 'm/0', messageHash);
|
|
1404
|
+
const signatureString = sdk_lib_mpc_1.DklsUtils.verifyAndConvertDklsSignature(messageHash, (await sdk_lib_mpc_1.DklsUtils.executeTillRound(5, userDsg, backupDsg)), commonKeyChain, 'm/0', undefined, false);
|
|
1405
|
+
const sigParts = signatureString.split(':');
|
|
1406
|
+
return {
|
|
1407
|
+
recid: parseInt(sigParts[0], 10),
|
|
1408
|
+
r: sigParts[1],
|
|
1409
|
+
s: sigParts[2],
|
|
1410
|
+
y: sigParts[3],
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
async getMpcV2RecoveryKeyShares(userPublicOrPrivateKeyShare, backupPrivateOrPublicKeyShare, walletPassphrase) {
|
|
1414
|
+
const userCompressedPrv = Buffer.from(this.bitgo.decrypt({
|
|
1415
|
+
input: userPublicOrPrivateKeyShare,
|
|
1416
|
+
password: walletPassphrase,
|
|
1417
|
+
}), 'base64');
|
|
1418
|
+
const bakcupCompressedPrv = Buffer.from(this.bitgo.decrypt({
|
|
1419
|
+
input: backupPrivateOrPublicKeyShare,
|
|
1420
|
+
password: walletPassphrase,
|
|
1421
|
+
}), 'base64');
|
|
1422
|
+
const userPrvJSON = sdk_lib_mpc_1.DklsTypes.getDecodedReducedKeyShare(userCompressedPrv);
|
|
1423
|
+
const backupPrvJSON = sdk_lib_mpc_1.DklsTypes.getDecodedReducedKeyShare(bakcupCompressedPrv);
|
|
1424
|
+
const userKeyRetrofit = {
|
|
1425
|
+
xShare: {
|
|
1426
|
+
x: Buffer.from(userPrvJSON.prv).toString('hex'),
|
|
1427
|
+
y: Buffer.from(userPrvJSON.pub).toString('hex'),
|
|
1428
|
+
chaincode: Buffer.from(userPrvJSON.rootChainCode).toString('hex'),
|
|
1429
|
+
},
|
|
1430
|
+
xiList: userPrvJSON.xList.slice(0, 2),
|
|
1431
|
+
};
|
|
1432
|
+
const backupKeyRetrofit = {
|
|
1433
|
+
xShare: {
|
|
1434
|
+
x: Buffer.from(backupPrvJSON.prv).toString('hex'),
|
|
1435
|
+
y: Buffer.from(backupPrvJSON.pub).toString('hex'),
|
|
1436
|
+
chaincode: Buffer.from(backupPrvJSON.rootChainCode).toString('hex'),
|
|
1437
|
+
},
|
|
1438
|
+
xiList: backupPrvJSON.xList.slice(0, 2),
|
|
1439
|
+
};
|
|
1440
|
+
const [user, backup] = await sdk_lib_mpc_1.DklsUtils.generate2of2KeyShares(userKeyRetrofit, backupKeyRetrofit);
|
|
1441
|
+
const userKeyShare = user.getKeyShare();
|
|
1442
|
+
const backupKeyShare = backup.getKeyShare();
|
|
1443
|
+
const commonKeyChain = sdk_lib_mpc_1.DklsTypes.getCommonKeychain(userKeyShare);
|
|
1444
|
+
const MPC = new sdk_core_1.Ecdsa();
|
|
1445
|
+
const derivedCommonKeyChain = MPC.deriveUnhardened(commonKeyChain, 'm');
|
|
1446
|
+
const backupKeyPair = new lib_1.KeyPair({ pub: derivedCommonKeyChain.slice(0, 66) });
|
|
1447
|
+
const baseAddress = backupKeyPair.getAddress();
|
|
1448
|
+
return { userKeyShare, backupKeyShare, commonKeyChain, baseAddress };
|
|
1449
|
+
}
|
|
1450
|
+
isGG18SigningMaterial(keyShare, walletPassphrase) {
|
|
1451
|
+
const prv = this.bitgo.decrypt({
|
|
1452
|
+
input: keyShare,
|
|
1453
|
+
password: walletPassphrase,
|
|
1454
|
+
});
|
|
1455
|
+
try {
|
|
1456
|
+
const signingMaterial = JSON.parse(prv);
|
|
1457
|
+
return (signingMaterial.pShare &&
|
|
1458
|
+
signingMaterial.bitgoNShare &&
|
|
1459
|
+
(signingMaterial.userNShare || signingMaterial.backupNShare));
|
|
1460
|
+
}
|
|
1461
|
+
catch (error) {
|
|
1462
|
+
return false;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
async buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params) {
|
|
1466
|
+
const nonce = await this.getAddressNonce(baseAddress);
|
|
1467
|
+
const txAmount = await this.validateBalanceAndGetTxAmount(baseAddress, gasPrice, gasLimit);
|
|
1468
|
+
const recipients = [
|
|
1469
|
+
{
|
|
1470
|
+
address: params.recoveryDestination,
|
|
1471
|
+
amount: txAmount.toString(10),
|
|
1472
|
+
},
|
|
1473
|
+
];
|
|
1474
|
+
const txInfo = {
|
|
1475
|
+
recipient: recipients[0],
|
|
1476
|
+
expireTime: this.getDefaultExpireTime(),
|
|
1477
|
+
gasLimit: gasLimit.toString(10),
|
|
1478
|
+
};
|
|
1479
|
+
const txParams = {
|
|
1480
|
+
to: params.recoveryDestination,
|
|
1481
|
+
nonce: nonce,
|
|
1482
|
+
value: txAmount,
|
|
1483
|
+
gasPrice: gasPrice,
|
|
1484
|
+
gasLimit: gasLimit,
|
|
1485
|
+
data: Buffer.from('0x'),
|
|
1486
|
+
eip1559: params.eip1559,
|
|
1487
|
+
replayProtectionOptions: params.replayProtectionOptions,
|
|
1488
|
+
};
|
|
1489
|
+
const tx = AbstractEthLikeNewCoins.buildTransaction(txParams);
|
|
1490
|
+
return { txInfo, tx, nonce };
|
|
1491
|
+
}
|
|
1492
|
+
async validateBalanceAndGetTxAmount(baseAddress, gasPrice, gasLimit) {
|
|
1493
|
+
const baseAddressBalance = await this.queryAddressBalance(baseAddress);
|
|
1494
|
+
const totalGasNeeded = gasPrice.mul(gasLimit);
|
|
1495
|
+
const weiToGwei = new bn_js_1.default(10 ** 9);
|
|
1496
|
+
if (baseAddressBalance.lt(totalGasNeeded)) {
|
|
1497
|
+
throw new Error(`Backup key address ${baseAddress} has balance ${baseAddressBalance.div(weiToGwei).toString()} Gwei.` +
|
|
1498
|
+
`This address must have a balance of at least ${totalGasNeeded.div(weiToGwei).toString()}` +
|
|
1499
|
+
` Gwei to perform recoveries. Try sending some ETH to this address then retry.`);
|
|
1500
|
+
}
|
|
1501
|
+
const txAmount = baseAddressBalance.sub(totalGasNeeded);
|
|
1502
|
+
return txAmount;
|
|
1503
|
+
}
|
|
1504
|
+
async recoveryBlockchainExplorerQuery(query) {
|
|
1505
|
+
throw new Error('method not implemented');
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Creates the extra parameters needed to build a hop transaction
|
|
1509
|
+
* @param buildParams The original build parameters
|
|
1510
|
+
* @returns extra parameters object to merge with the original build parameters object and send to the platform
|
|
1511
|
+
*/
|
|
1512
|
+
async createHopTransactionParams(buildParams) {
|
|
1513
|
+
const wallet = buildParams.wallet;
|
|
1514
|
+
const recipients = buildParams.recipients;
|
|
1515
|
+
const walletPassphrase = buildParams.walletPassphrase;
|
|
1516
|
+
const userKeychain = await this.keychains().get({ id: wallet.keyIds()[0] });
|
|
1517
|
+
const userPrv = wallet.getUserPrv({ keychain: userKeychain, walletPassphrase });
|
|
1518
|
+
const userPrvBuffer = utxo_lib_1.bip32.fromBase58(userPrv).privateKey;
|
|
1519
|
+
if (!userPrvBuffer) {
|
|
1520
|
+
throw new Error('invalid userPrv');
|
|
1521
|
+
}
|
|
1522
|
+
if (!recipients || !Array.isArray(recipients)) {
|
|
1523
|
+
throw new Error('expecting array of recipients');
|
|
1524
|
+
}
|
|
1525
|
+
// Right now we only support 1 recipient
|
|
1526
|
+
if (recipients.length !== 1) {
|
|
1527
|
+
throw new Error('must send to exactly 1 recipient');
|
|
1528
|
+
}
|
|
1529
|
+
const recipientAddress = recipients[0].address;
|
|
1530
|
+
const recipientAmount = recipients[0].amount;
|
|
1531
|
+
const feeEstimateParams = {
|
|
1532
|
+
recipient: recipientAddress,
|
|
1533
|
+
amount: recipientAmount,
|
|
1534
|
+
hop: true,
|
|
1535
|
+
};
|
|
1536
|
+
const feeEstimate = await this.feeEstimate(feeEstimateParams);
|
|
1537
|
+
const gasLimit = feeEstimate.gasLimitEstimate;
|
|
1538
|
+
const gasPrice = Math.round(feeEstimate.feeEstimate / gasLimit);
|
|
1539
|
+
const gasPriceMax = gasPrice * 5;
|
|
1540
|
+
// Payment id a random number so its different for every tx
|
|
1541
|
+
const paymentId = Math.floor(Math.random() * 10000000000).toString();
|
|
1542
|
+
const hopDigest = AbstractEthLikeNewCoins.getHopDigest([
|
|
1543
|
+
recipientAddress,
|
|
1544
|
+
recipientAmount,
|
|
1545
|
+
gasPriceMax.toString(),
|
|
1546
|
+
gasLimit.toString(),
|
|
1547
|
+
paymentId,
|
|
1548
|
+
]);
|
|
1549
|
+
const userReqSig = exports.optionalDeps.ethUtil.addHexPrefix(Buffer.from(secp256k1_1.default.ecdsaSign(hopDigest, userPrvBuffer).signature).toString('hex'));
|
|
1550
|
+
return {
|
|
1551
|
+
hopParams: {
|
|
1552
|
+
gasPriceMax,
|
|
1553
|
+
userReqSig,
|
|
1554
|
+
paymentId,
|
|
1555
|
+
},
|
|
1556
|
+
gasLimit,
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Validates that the hop prebuild from the HSM is valid and correct
|
|
1561
|
+
* @param {IWallet} wallet - The wallet that the prebuild is for
|
|
1562
|
+
* @param {HopPrebuild} hopPrebuild - The prebuild to validate
|
|
1563
|
+
* @param {Object} originalParams - The original parameters passed to prebuildTransaction
|
|
1564
|
+
* @param {Recipient[]} originalParams.recipients - The original recipients array
|
|
1565
|
+
* @returns {void}
|
|
1566
|
+
* @throws Error if The prebuild is invalid
|
|
1567
|
+
*/
|
|
1568
|
+
async validateHopPrebuild(wallet, hopPrebuild, originalParams) {
|
|
1569
|
+
const { tx, id, signature } = hopPrebuild;
|
|
1570
|
+
// first, validate the HSM signature
|
|
1571
|
+
const serverXpub = sdk_core_1.common.Environments[this.bitgo.getEnv()].hsmXpub;
|
|
1572
|
+
const serverPubkeyBuffer = utxo_lib_1.bip32.fromBase58(serverXpub).publicKey;
|
|
1573
|
+
const signatureBuffer = Buffer.from(exports.optionalDeps.ethUtil.stripHexPrefix(signature), 'hex');
|
|
1574
|
+
const messageBuffer = Buffer.from(exports.optionalDeps.ethUtil.padToEven(exports.optionalDeps.ethUtil.stripHexPrefix(id)), 'hex');
|
|
1575
|
+
const sig = new Uint8Array(signatureBuffer.slice(1));
|
|
1576
|
+
const isValidSignature = secp256k1_1.default.ecdsaVerify(sig, messageBuffer, serverPubkeyBuffer);
|
|
1577
|
+
if (!isValidSignature) {
|
|
1578
|
+
throw new Error(`Hop txid signature invalid - pub: ${serverXpub}, msg: ${messageBuffer === null || messageBuffer === void 0 ? void 0 : messageBuffer.toString()}, sig: ${signatureBuffer === null || signatureBuffer === void 0 ? void 0 : signatureBuffer.toString()}`);
|
|
1579
|
+
}
|
|
1580
|
+
const builtHopTx = exports.optionalDeps.EthTx.TransactionFactory.fromSerializedData(exports.optionalDeps.ethUtil.toBuffer(tx));
|
|
1581
|
+
// If original params are given, we can check them against the transaction prebuild params
|
|
1582
|
+
if (!lodash_1.default.isNil(originalParams)) {
|
|
1583
|
+
const { recipients } = originalParams;
|
|
1584
|
+
// Then validate that the tx params actually equal the requested params
|
|
1585
|
+
const originalAmount = new bignumber_js_1.BigNumber(recipients[0].amount);
|
|
1586
|
+
const originalDestination = recipients[0].address;
|
|
1587
|
+
const hopAmount = new bignumber_js_1.BigNumber(exports.optionalDeps.ethUtil.bufferToHex(builtHopTx.value));
|
|
1588
|
+
if (!builtHopTx.to) {
|
|
1589
|
+
throw new Error(`Transaction does not have a destination address`);
|
|
1590
|
+
}
|
|
1591
|
+
const hopDestination = builtHopTx.to.toString();
|
|
1592
|
+
if (!hopAmount.eq(originalAmount)) {
|
|
1593
|
+
throw new Error(`Hop amount: ${hopAmount} does not equal original amount: ${originalAmount}`);
|
|
1594
|
+
}
|
|
1595
|
+
if (hopDestination.toLowerCase() !== originalDestination.toLowerCase()) {
|
|
1596
|
+
throw new Error(`Hop destination: ${hopDestination} does not equal original recipient: ${hopDestination}`);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
if (!builtHopTx.verifySignature()) {
|
|
1600
|
+
// We dont want to continue at all in this case, at risk of ETH being stuck on the hop address
|
|
1601
|
+
throw new Error(`Invalid hop transaction signature, txid: ${id}`);
|
|
1602
|
+
}
|
|
1603
|
+
if (exports.optionalDeps.ethUtil.addHexPrefix(builtHopTx.hash().toString('hex')) !== id) {
|
|
1604
|
+
throw new Error(`Signed hop txid does not equal actual txid`);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
/**
|
|
1608
|
+
* Gets the hop digest for the user to sign. This is validated in the HSM to prove that the user requested this tx
|
|
1609
|
+
* @param {string[]} paramsArr - The parameters to hash together for the digest
|
|
1610
|
+
* @returns {Buffer}
|
|
1611
|
+
*/
|
|
1612
|
+
static getHopDigest(paramsArr) {
|
|
1613
|
+
const hash = (0, keccak_1.default)('keccak256');
|
|
1614
|
+
hash.update([AbstractEthLikeNewCoins.hopTransactionSalt, ...paramsArr].join('$'));
|
|
1615
|
+
return hash.digest();
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Modify prebuild before sending it to the server. Add things like hop transaction params
|
|
1619
|
+
* @param {BuildOptions} buildParams - The whitelisted parameters for this prebuild
|
|
1620
|
+
* @param {boolean} buildParams.hop - True if this should prebuild a hop tx, else false
|
|
1621
|
+
* @param {Recipient[]} buildParams.recipients - The recipients array of this transaction
|
|
1622
|
+
* @param {Wallet} buildParams.wallet - The wallet sending this tx
|
|
1623
|
+
* @param {string} buildParams.walletPassphrase - the passphrase for this wallet
|
|
1624
|
+
* @returns {Promise<BuildOptions>}
|
|
1625
|
+
*/
|
|
1626
|
+
async getExtraPrebuildParams(buildParams) {
|
|
1627
|
+
if (!lodash_1.default.isUndefined(buildParams.hop) &&
|
|
1628
|
+
buildParams.hop &&
|
|
1629
|
+
!lodash_1.default.isUndefined(buildParams.wallet) &&
|
|
1630
|
+
!lodash_1.default.isUndefined(buildParams.recipients) &&
|
|
1631
|
+
!lodash_1.default.isUndefined(buildParams.walletPassphrase)) {
|
|
1632
|
+
if (this instanceof ethLikeToken_1.EthLikeToken) {
|
|
1633
|
+
throw new Error(`Hop transactions are not enabled for ERC-20 tokens, nor are they necessary. Please remove the 'hop' parameter and try again.`);
|
|
1634
|
+
}
|
|
1635
|
+
return (await this.createHopTransactionParams({
|
|
1636
|
+
wallet: buildParams.wallet,
|
|
1637
|
+
recipients: buildParams.recipients,
|
|
1638
|
+
walletPassphrase: buildParams.walletPassphrase,
|
|
1639
|
+
}));
|
|
1640
|
+
}
|
|
1641
|
+
return {};
|
|
1642
|
+
}
|
|
1643
|
+
/**
|
|
1644
|
+
* Modify prebuild after receiving it from the server. Add things like nlocktime
|
|
1645
|
+
* @param {TransactionPrebuild} params - The prebuild to modify
|
|
1646
|
+
* @returns {TransactionPrebuild} The modified prebuild
|
|
1647
|
+
*/
|
|
1648
|
+
async postProcessPrebuild(params) {
|
|
1649
|
+
if (!lodash_1.default.isUndefined(params.hopTransaction) && !lodash_1.default.isUndefined(params.wallet) && !lodash_1.default.isUndefined(params.buildParams)) {
|
|
1650
|
+
await this.validateHopPrebuild(params.wallet, params.hopTransaction, params.buildParams);
|
|
1651
|
+
}
|
|
1652
|
+
return params;
|
|
1653
|
+
}
|
|
1654
|
+
/**
|
|
1655
|
+
* Coin-specific things done before signing a transaction, i.e. verification
|
|
1656
|
+
* @param {PresignTransactionOptions} params
|
|
1657
|
+
* @returns {Promise<PresignTransactionOptions>}
|
|
1658
|
+
*/
|
|
1659
|
+
async presignTransaction(params) {
|
|
1660
|
+
if (!lodash_1.default.isUndefined(params.hopTransaction) && !lodash_1.default.isUndefined(params.wallet) && !lodash_1.default.isUndefined(params.buildParams)) {
|
|
1661
|
+
await this.validateHopPrebuild(params.wallet, params.hopTransaction);
|
|
1662
|
+
}
|
|
1663
|
+
return params;
|
|
1664
|
+
}
|
|
1665
|
+
/**
|
|
1666
|
+
* Fetch fee estimate information from the server
|
|
1667
|
+
* @param {Object} params - The params passed into the function
|
|
1668
|
+
* @param {boolean} [params.hop] - True if we should estimate fee for a hop transaction
|
|
1669
|
+
* @param {string} [params.recipient] - The recipient of the transaction to estimate a send to
|
|
1670
|
+
* @param {string} [params.data] - The ETH tx data to estimate a send for
|
|
1671
|
+
* @returns {Object} The fee info returned from the server
|
|
1672
|
+
*/
|
|
1673
|
+
async feeEstimate(params) {
|
|
1674
|
+
const query = {};
|
|
1675
|
+
if (params && params.hop) {
|
|
1676
|
+
query.hop = params.hop;
|
|
1677
|
+
}
|
|
1678
|
+
if (params && params.recipient) {
|
|
1679
|
+
query.recipient = params.recipient;
|
|
1680
|
+
}
|
|
1681
|
+
if (params && params.data) {
|
|
1682
|
+
query.data = params.data;
|
|
1683
|
+
}
|
|
1684
|
+
if (params && params.amount) {
|
|
1685
|
+
query.amount = params.amount;
|
|
1686
|
+
}
|
|
1687
|
+
return await this.bitgo.get(this.url('/tx/fee')).query(query).result();
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Generate secp256k1 key pair
|
|
1691
|
+
*
|
|
1692
|
+
* @param {Buffer} seed
|
|
1693
|
+
* @returns {KeyPair} object with generated pub and prv
|
|
1694
|
+
*/
|
|
1695
|
+
generateKeyPair(seed) {
|
|
1696
|
+
if (!seed) {
|
|
1697
|
+
// An extended private key has both a normal 256 bit private key and a 256
|
|
1698
|
+
// bit chain code, both of which must be random. 512 bits is therefore the
|
|
1699
|
+
// maximum entropy and gives us maximum security against cracking.
|
|
1700
|
+
seed = (0, crypto_1.randomBytes)(512 / 8);
|
|
1701
|
+
}
|
|
1702
|
+
const extendedKey = utxo_lib_1.bip32.fromSeed(seed);
|
|
1703
|
+
const xpub = extendedKey.neutered().toBase58();
|
|
1704
|
+
return {
|
|
1705
|
+
pub: xpub,
|
|
1706
|
+
prv: extendedKey.toBase58(),
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
async parseTransaction(params) {
|
|
1710
|
+
return {};
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Make sure an address is a wallet address and throw an error if it's not.
|
|
1714
|
+
* @param {Object} params
|
|
1715
|
+
* @param {string} params.address - The derived address string on the network
|
|
1716
|
+
* @param {Object} params.coinSpecific - Coin-specific details for the address such as a forwarderVersion
|
|
1717
|
+
* @param {string} params.baseAddress - The base address of the wallet on the network
|
|
1718
|
+
* @throws {InvalidAddressError}
|
|
1719
|
+
* @throws {InvalidAddressVerificationObjectPropertyError}
|
|
1720
|
+
* @throws {UnexpectedAddressError}
|
|
1721
|
+
* @returns {boolean} True iff address is a wallet address
|
|
1722
|
+
*/
|
|
1723
|
+
async isWalletAddress(params) {
|
|
1724
|
+
const ethUtil = exports.optionalDeps.ethUtil;
|
|
1725
|
+
let expectedAddress;
|
|
1726
|
+
let actualAddress;
|
|
1727
|
+
const { address, coinSpecific, baseAddress, impliedForwarderVersion = coinSpecific === null || coinSpecific === void 0 ? void 0 : coinSpecific.forwarderVersion } = params;
|
|
1728
|
+
if (address && !this.isValidAddress(address)) {
|
|
1729
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
|
|
1730
|
+
}
|
|
1731
|
+
// base address is required to calculate the salt which is used in calculateForwarderV1Address method
|
|
1732
|
+
if (lodash_1.default.isUndefined(baseAddress) || !this.isValidAddress(baseAddress)) {
|
|
1733
|
+
throw new sdk_core_1.InvalidAddressError('invalid base address');
|
|
1734
|
+
}
|
|
1735
|
+
if (!lodash_1.default.isObject(coinSpecific)) {
|
|
1736
|
+
throw new sdk_core_1.InvalidAddressVerificationObjectPropertyError('address validation failure: coinSpecific field must be an object');
|
|
1737
|
+
}
|
|
1738
|
+
if (impliedForwarderVersion === 0 || impliedForwarderVersion === 3) {
|
|
1739
|
+
return true;
|
|
1740
|
+
}
|
|
1741
|
+
else {
|
|
1742
|
+
const ethNetwork = this.getNetwork();
|
|
1743
|
+
const forwarderFactoryAddress = ethNetwork === null || ethNetwork === void 0 ? void 0 : ethNetwork.forwarderFactoryAddress;
|
|
1744
|
+
const forwarderImplementationAddress = ethNetwork === null || ethNetwork === void 0 ? void 0 : ethNetwork.forwarderImplementationAddress;
|
|
1745
|
+
const initcode = (0, lib_1.getProxyInitcode)(forwarderImplementationAddress);
|
|
1746
|
+
const saltBuffer = ethUtil.setLengthLeft(Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(coinSpecific.salt || '')), 'hex'), 32);
|
|
1747
|
+
// Hash the wallet base address with the given salt, so the address directly relies on the base address
|
|
1748
|
+
const calculationSalt = exports.optionalDeps.ethUtil.bufferToHex(exports.optionalDeps.ethAbi.soliditySHA3(['address', 'bytes32'], [baseAddress, saltBuffer]));
|
|
1749
|
+
expectedAddress = (0, lib_1.calculateForwarderV1Address)(forwarderFactoryAddress, calculationSalt, initcode);
|
|
1750
|
+
actualAddress = address;
|
|
1751
|
+
}
|
|
1752
|
+
if (expectedAddress !== actualAddress) {
|
|
1753
|
+
throw new sdk_core_1.UnexpectedAddressError(`address validation failure: expected ${expectedAddress} but got ${address}`);
|
|
1754
|
+
}
|
|
1755
|
+
return true;
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
*
|
|
1759
|
+
* @param {TransactionPrebuild} txPrebuild
|
|
1760
|
+
* @returns {boolean}
|
|
1761
|
+
*/
|
|
1762
|
+
verifyCoin(txPrebuild) {
|
|
1763
|
+
return txPrebuild.coin === this.getChain();
|
|
1764
|
+
}
|
|
1765
|
+
/**
|
|
1766
|
+
* Verify if a tss transaction is valid
|
|
1767
|
+
*
|
|
1768
|
+
* @param {VerifyEthTransactionOptions} params
|
|
1769
|
+
* @param {TransactionParams} params.txParams - params object passed to send
|
|
1770
|
+
* @param {TransactionPrebuild} params.txPrebuild - prebuild object returned by server
|
|
1771
|
+
* @param {Wallet} params.wallet - Wallet object to obtain keys to verify against
|
|
1772
|
+
* @returns {boolean}
|
|
1773
|
+
*/
|
|
1774
|
+
verifyTssTransaction(params) {
|
|
1775
|
+
var _a;
|
|
1776
|
+
const { txParams, txPrebuild, wallet } = params;
|
|
1777
|
+
if (!(txParams === null || txParams === void 0 ? void 0 : txParams.recipients) &&
|
|
1778
|
+
!(((_a = txParams.prebuildTx) === null || _a === void 0 ? void 0 : _a.consolidateId) ||
|
|
1779
|
+
(txParams.type && ['acceleration', 'fillNonce', 'transferToken'].includes(txParams.type)))) {
|
|
1780
|
+
throw new Error(`missing txParams`);
|
|
1781
|
+
}
|
|
1782
|
+
if (!wallet || !txPrebuild) {
|
|
1783
|
+
throw new Error(`missing params`);
|
|
1784
|
+
}
|
|
1785
|
+
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
|
|
1786
|
+
throw new Error(`tx cannot be both a batch and hop transaction`);
|
|
1787
|
+
}
|
|
1788
|
+
return true;
|
|
1789
|
+
}
|
|
1790
|
+
/**
|
|
1791
|
+
* Verify that a transaction prebuild complies with the original intention
|
|
1792
|
+
*
|
|
1793
|
+
* @param {VerifyEthTransactionOptions} params
|
|
1794
|
+
* @param {TransactionParams} params.txParams - params object passed to send
|
|
1795
|
+
* @param {TransactionPrebuild} params.txPrebuild - prebuild object returned by server
|
|
1796
|
+
* @param {Wallet} params.wallet - Wallet object to obtain keys to verify against
|
|
1797
|
+
* @returns {boolean}
|
|
1798
|
+
*/
|
|
1799
|
+
async verifyTransaction(params) {
|
|
1800
|
+
const ethNetwork = this.getNetwork();
|
|
1801
|
+
const { txParams, txPrebuild, wallet, walletType } = params;
|
|
1802
|
+
if (walletType === 'tss') {
|
|
1803
|
+
return this.verifyTssTransaction(params);
|
|
1804
|
+
}
|
|
1805
|
+
if (!(txParams === null || txParams === void 0 ? void 0 : txParams.recipients) || !(txPrebuild === null || txPrebuild === void 0 ? void 0 : txPrebuild.recipients) || !wallet) {
|
|
1806
|
+
throw new Error(`missing params`);
|
|
1807
|
+
}
|
|
1808
|
+
if (txParams.hop && txParams.recipients.length > 1) {
|
|
1809
|
+
throw new Error(`tx cannot be both a batch and hop transaction`);
|
|
1810
|
+
}
|
|
1811
|
+
if (txPrebuild.recipients.length !== 1) {
|
|
1812
|
+
throw new Error(`txPrebuild should only have 1 recipient but ${txPrebuild.recipients.length} found`);
|
|
1813
|
+
}
|
|
1814
|
+
if (txParams.hop && txPrebuild.hopTransaction) {
|
|
1815
|
+
// Check recipient amount for hop transaction
|
|
1816
|
+
if (txParams.recipients.length !== 1) {
|
|
1817
|
+
throw new Error(`hop transaction only supports 1 recipient but ${txParams.recipients.length} found`);
|
|
1818
|
+
}
|
|
1819
|
+
// Check tx sends to hop address
|
|
1820
|
+
const decodedHopTx = exports.optionalDeps.EthTx.TransactionFactory.fromSerializedData(exports.optionalDeps.ethUtil.toBuffer(txPrebuild.hopTransaction.tx));
|
|
1821
|
+
const expectedHopAddress = exports.optionalDeps.ethUtil.stripHexPrefix(decodedHopTx.getSenderAddress().toString());
|
|
1822
|
+
const actualHopAddress = exports.optionalDeps.ethUtil.stripHexPrefix(txPrebuild.recipients[0].address);
|
|
1823
|
+
if (expectedHopAddress.toLowerCase() !== actualHopAddress.toLowerCase()) {
|
|
1824
|
+
throw new Error('recipient address of txPrebuild does not match hop address');
|
|
1825
|
+
}
|
|
1826
|
+
// Convert TransactionRecipient array to Recipient array
|
|
1827
|
+
const recipients = txParams.recipients.map((r) => {
|
|
1828
|
+
return {
|
|
1829
|
+
address: r.address,
|
|
1830
|
+
amount: typeof r.amount === 'number' ? r.amount.toString() : r.amount,
|
|
1831
|
+
};
|
|
1832
|
+
});
|
|
1833
|
+
// Check destination address and amount
|
|
1834
|
+
await this.validateHopPrebuild(wallet, txPrebuild.hopTransaction, { recipients });
|
|
1835
|
+
}
|
|
1836
|
+
else if (txParams.recipients.length > 1) {
|
|
1837
|
+
// Check total amount for batch transaction
|
|
1838
|
+
let expectedTotalAmount = new bignumber_js_1.BigNumber(0);
|
|
1839
|
+
for (let i = 0; i < txParams.recipients.length; i++) {
|
|
1840
|
+
expectedTotalAmount = expectedTotalAmount.plus(txParams.recipients[i].amount);
|
|
1841
|
+
}
|
|
1842
|
+
if (!expectedTotalAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
|
|
1843
|
+
throw new Error('batch transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client');
|
|
1844
|
+
}
|
|
1845
|
+
// Check batch transaction is sent to the batcher contract address for the chain
|
|
1846
|
+
const batcherContractAddress = ethNetwork === null || ethNetwork === void 0 ? void 0 : ethNetwork.batcherContractAddress;
|
|
1847
|
+
if (!batcherContractAddress ||
|
|
1848
|
+
batcherContractAddress.toLowerCase() !== txPrebuild.recipients[0].address.toLowerCase()) {
|
|
1849
|
+
throw new Error('recipient address of txPrebuild does not match batcher address');
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
else {
|
|
1853
|
+
// Check recipient address and amount for normal transaction
|
|
1854
|
+
if (txParams.recipients.length !== 1) {
|
|
1855
|
+
throw new Error(`normal transaction only supports 1 recipient but ${txParams.recipients.length} found`);
|
|
1856
|
+
}
|
|
1857
|
+
const expectedAmount = new bignumber_js_1.BigNumber(txParams.recipients[0].amount);
|
|
1858
|
+
if (!expectedAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
|
|
1859
|
+
throw new Error('normal transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client');
|
|
1860
|
+
}
|
|
1861
|
+
if (this.isETHAddress(txParams.recipients[0].address) &&
|
|
1862
|
+
txParams.recipients[0].address !== txPrebuild.recipients[0].address) {
|
|
1863
|
+
throw new Error('destination address in normal txPrebuild does not match that in txParams supplied by client');
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
// Check coin is correct for all transaction types
|
|
1867
|
+
if (!this.verifyCoin(txPrebuild)) {
|
|
1868
|
+
throw new Error(`coin in txPrebuild did not match that in txParams supplied by client`);
|
|
1869
|
+
}
|
|
1870
|
+
return true;
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Check if address is valid eth address
|
|
1874
|
+
* @param address
|
|
1875
|
+
* @returns {boolean}
|
|
1876
|
+
*/
|
|
1877
|
+
isETHAddress(address) {
|
|
1878
|
+
return !!address.match(/0x[a-fA-F0-9]{40}/);
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Transform message to accommodate specific blockchain requirements.
|
|
1882
|
+
* @param {string} message - the message to prepare
|
|
1883
|
+
* @return {string} the prepared message.
|
|
1884
|
+
*/
|
|
1885
|
+
encodeMessage(message) {
|
|
1886
|
+
const prefix = `\u0019Ethereum Signed Message:\n${message.length}`;
|
|
1887
|
+
return prefix.concat(message);
|
|
1888
|
+
}
|
|
1889
|
+
/**
|
|
1890
|
+
* Transform the Typed data to accomodate the blockchain requirements (EIP-712)
|
|
1891
|
+
* @param {TypedData} typedData - the typed data to prepare
|
|
1892
|
+
* @return {Buffer} a buffer of the result
|
|
1893
|
+
*/
|
|
1894
|
+
encodeTypedData(typedData) {
|
|
1895
|
+
const version = typedData.version;
|
|
1896
|
+
if (version === eth_sig_util_1.SignTypedDataVersion.V1) {
|
|
1897
|
+
throw new Error('SignTypedData v1 is not supported due to security concerns');
|
|
1898
|
+
}
|
|
1899
|
+
const typedDataRaw = JSON.parse(typedData.typedDataRaw);
|
|
1900
|
+
const sanitizedData = eth_sig_util_1.TypedDataUtils.sanitizeData(typedDataRaw);
|
|
1901
|
+
const parts = [Buffer.from('1901', 'hex')];
|
|
1902
|
+
const eip712Domain = 'EIP712Domain';
|
|
1903
|
+
parts.push(eth_sig_util_1.TypedDataUtils.hashStruct(eip712Domain, sanitizedData.domain, sanitizedData.types, version));
|
|
1904
|
+
if (sanitizedData.primaryType !== eip712Domain) {
|
|
1905
|
+
parts.push(eth_sig_util_1.TypedDataUtils.hashStruct(sanitizedData.primaryType, sanitizedData.message, sanitizedData.types, version));
|
|
1906
|
+
}
|
|
1907
|
+
return Buffer.concat(parts);
|
|
1908
|
+
}
|
|
1909
|
+
/**
|
|
1910
|
+
* Build the data to transfer an ERC-721 or ERC-1155 token to another address
|
|
1911
|
+
* @param params
|
|
1912
|
+
*/
|
|
1913
|
+
buildNftTransferData(params) {
|
|
1914
|
+
const { tokenContractAddress, recipientAddress, fromAddress } = params;
|
|
1915
|
+
switch (params.type) {
|
|
1916
|
+
case 'ERC721': {
|
|
1917
|
+
const tokenId = params.tokenId;
|
|
1918
|
+
const contractData = new lib_1.ERC721TransferBuilder()
|
|
1919
|
+
.tokenContractAddress(tokenContractAddress)
|
|
1920
|
+
.to(recipientAddress)
|
|
1921
|
+
.from(fromAddress)
|
|
1922
|
+
.tokenId(tokenId)
|
|
1923
|
+
.build();
|
|
1924
|
+
return contractData;
|
|
1925
|
+
}
|
|
1926
|
+
case 'ERC1155': {
|
|
1927
|
+
const entries = params.entries;
|
|
1928
|
+
const transferBuilder = new lib_1.ERC1155TransferBuilder()
|
|
1929
|
+
.tokenContractAddress(tokenContractAddress)
|
|
1930
|
+
.to(recipientAddress)
|
|
1931
|
+
.from(fromAddress);
|
|
1932
|
+
for (const entry of entries) {
|
|
1933
|
+
transferBuilder.entry(parseInt(entry.tokenId, 10), entry.amount);
|
|
1934
|
+
}
|
|
1935
|
+
return transferBuilder.build();
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
exports.AbstractEthLikeNewCoins = AbstractEthLikeNewCoins;
|
|
1941
|
+
AbstractEthLikeNewCoins.hopTransactionSalt = 'bitgoHopAddressRequestSalt';
|
|
1942
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7O0dBRUc7QUFDSCxtREFpQzhCO0FBQzlCLHlEQUF5SDtBQUN6SCxpREFNNkI7QUFDN0IsbURBQTZDO0FBRzdDLHVDQUErRjtBQUMvRix5REFBNEY7QUFDNUYsK0NBQXlDO0FBQ3pDLGtEQUF1QjtBQUN2QixtQ0FBcUM7QUFDckMsa0RBQTZCO0FBQzdCLHFEQUErRDtBQUMvRCxvREFBNEI7QUFDNUIsb0RBQXVCO0FBQ3ZCLDBEQUFrQztBQUVsQywrREFBNEQ7QUFDNUQsaURBQThDO0FBQzlDLCtCQVVlO0FBa1FmLE1BQU0sS0FBSyxHQUFHLElBQUEsZUFBUSxFQUFDLGtCQUFrQixDQUFDLENBQUM7QUFFOUIsUUFBQSxZQUFZLEdBQUc7SUFDMUIsSUFBSSxNQUFNO1FBQ1IsSUFBSTtZQUNGLE9BQU8sT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUM7U0FDbEM7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1lBQ3hDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDZixNQUFNLElBQUksMENBQStCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztTQUM3RDtJQUNILENBQUM7SUFFRCxJQUFJLE9BQU87UUFDVCxJQUFJO1lBQ0YsT0FBTyxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQztTQUNuQztRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsS0FBSyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7WUFDekMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNmLE1BQU0sSUFBSSwwQ0FBK0IsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1NBQzlEO0lBQ0gsQ0FBQztJQUVELElB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QUFvQixDQUFDO3FCQUMxQyxFQUFFLENBQUMsZ0JBQWdCLENBQUM7cUJBQ3BCLElBQUksQ0FBQyxXQUFXLENBQUM7cUJBQ2pCLE9BQU8sQ0FBQyxPQUFPLENBQUM7cUJBQ2hCLEtBQUssRUFBRSxDQUFDO2dCQUNYLE9BQU8sWUFBWSxDQUFDO2FBQ3JCO1lBRUQsS0FBSyxTQUFTLENBQUMsQ0FBQztnQkFDZCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDO2dCQUMvQixNQUFNLGVBQWUsR0FBRyxJQUFJLDRCQUFzQixFQUFFO3FCQUNqRCxvQkFBb0IsQ0FBQyxvQkFBb0IsQ0FBQztxQkFDMUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDO3FCQUNwQixJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBRXJCLEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxFQUFFO29CQUMzQixlQUFlLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztpQkFDbEU7Z0JBRUQsT0FBTyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7YUFDaEM7U0FDRjtJQUNILENBQUM7O0FBN3ZFSCwwREE4dkVDO0FBN3ZFUSwwQ0FBa0IsR0FBRyw0QkFBNEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQHByZXR0aWVyXG4gKi9cbmltcG9ydCB7XG4gIEFkZHJlc3NDb2luU3BlY2lmaWMsXG4gIEJpdEdvQmFzZSxcbiAgQnVpbGROZnRUcmFuc2ZlckRhdGFPcHRpb25zLFxuICBjb21tb24sXG4gIEVDRFNBLFxuICBFY2RzYSxcbiAgRUNEU0FNZXRob2RUeXBlcyxcbiAgRXRoZXJldW1MaWJyYXJ5VW5hdmFpbGFibGVFcnJvcixcbiAgRmVlRXN0aW1hdGVPcHRpb25zLFxuICBGdWxseVNpZ25lZFRyYW5zYWN0aW9uLFxuICBnZXRJc1Vuc2lnbmVkU3dlZXAsXG4gIEhhbGZTaWduZWRUcmFuc2FjdGlvbixcbiAgaGV4VG9CaWdJbnQsXG4gIEludmFsaWRBZGRyZXNzRXJyb3IsXG4gIEludmFsaWRBZGRyZXNzVmVyaWZpY2F0aW9uT2JqZWN0UHJvcGVydHlFcnJvcixcbiAgSVdhbGxldCxcbiAgS2V5UGFpcixcbiAgUGFyc2VkVHJhbnNhY3Rpb24sXG4gIFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zLFxuICBQcmVidWlsZFRyYW5zYWN0aW9uUmVzdWx0LFxuICBQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zIGFzIEJhc2VQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zLFxuICBSZWNpcGllbnQsXG4gIFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMgYXMgQmFzZVNpZ25UcmFuc2FjdGlvbk9wdGlvbnMsXG4gIFRyYW5zYWN0aW9uUGFyYW1zLFxuICBUcmFuc2FjdGlvblByZWJ1aWxkIGFzIEJhc2VUcmFuc2FjdGlvblByZWJ1aWxkLFxuICBUcmFuc2FjdGlvblJlY2lwaWVudCxcbiAgVHlwZWREYXRhLFxuICBVbmV4cGVjdGVkQWRkcmVzc0Vycm9yLFxuICBVdGlsLFxuICBWZXJpZnlBZGRyZXNzT3B0aW9ucyBhcyBCYXNlVmVyaWZ5QWRkcmVzc09wdGlvbnMsXG4gIFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgV2FsbGV0LFxufSBmcm9tICdAYml0Z28tYmV0YS9zZGstY29yZSc7XG5pbXBvcnQgeyBEa2xzRHNnLCBEa2xzVHlwZXMsIERrbHNVdGlscywgRWNkc2FQYWlsbGllclByb29mLCBFY2RzYVJhbmdlUHJvb2YsIEVjZHNhVHlwZXMgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstbGliLW1wYyc7XG5pbXBvcnQge1xuICBCYXNlQ29pbiBhcyBTdGF0aWNzQmFzZUNvaW4sXG4gIENvaW5NYXAsXG4gIGNvaW5zLFxuICBFdGhlcmV1bU5ldHdvcmsgYXMgRXRoTGlrZU5ldHdvcmssXG4gIGV0aEdhc0NvbmZpZ3MsXG59IGZyb20gJ0BiaXRnby1iZXRhL3N0YXRpY3MnO1xuaW1wb3J0IHsgYmlwMzIgfSBmcm9tICdAYml0Z28tYmV0YS91dHhvLWxpYic7XG5pbXBvcnQgdHlwZSAqIGFzIEV0aExpa2VDb21tb24gZnJvbSAnQGV0aGVyZXVtanMvY29tbW9uJztcbmltcG9ydCB0eXBlICogYXMgRXRoTGlrZVR4TGliIGZyb20gJ0BldGhlcmV1bWpzL3R4JztcbmltcG9ydCB7IEZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbiwgVHJhbnNhY3Rpb24gYXMgTGVnYWN5VHJhbnNhY3Rpb24gfSBmcm9tICdAZXRoZXJldW1qcy90eCc7XG5pbXBvcnQgeyBTaWduVHlwZWREYXRhVmVyc2lvbiwgVHlwZWREYXRhVXRpbHMsIFR5cGVkTWVzc2FnZSB9IGZyb20gJ0BtZXRhbWFzay9ldGgtc2lnLXV0aWwnO1xuaW1wb3J0IHsgQmlnTnVtYmVyIH0gZnJvbSAnYmlnbnVtYmVyLmpzJztcbmltcG9ydCBCTiBmcm9tICdibi5qcyc7XG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgZGVidWdMaWIgZnJvbSAnZGVidWcnO1xuaW1wb3J0IHsgYWRkSGV4UHJlZml4LCBzdHJpcEhleFByZWZpeCB9IGZyb20gJ2V0aGVyZXVtanMtdXRpbCc7XG5pbXBvcnQgS2VjY2FrIGZyb20gJ2tlY2Nhayc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHNlY3AyNTZrMSBmcm9tICdzZWNwMjU2azEnO1xuXG5pbXBvcnQgeyBBYnN0cmFjdEV0aExpa2VDb2luIH0gZnJvbSAnLi9hYnN0cmFjdEV0aExpa2VDb2luJztcbmltcG9ydCB7IEV0aExpa2VUb2tlbiB9IGZyb20gJy4vZXRoTGlrZVRva2VuJztcbmltcG9ydCB7XG4gIGNhbGN1bGF0ZUZvcndhcmRlclYxQWRkcmVzcyxcbiAgRVJDMTE1NVRyYW5zZmVyQnVpbGRlcixcbiAgRVJDNzIxVHJhbnNmZXJCdWlsZGVyLFxuICBnZXRDb21tb24sXG4gIGdldFByb3h5SW5pdGNvZGUsXG4gIGdldFRva2VuLFxuICBLZXlQYWlyIGFzIEtleVBhaXJMaWIsXG4gIFRyYW5zYWN0aW9uQnVpbGRlcixcbiAgVHJhbnNmZXJCdWlsZGVyLFxufSBmcm9tICcuL2xpYic7XG5cbi8qKlxuICogVGhlIHByZWJ1aWx0IGhvcCB0cmFuc2FjdGlvbiByZXR1cm5lZCBmcm9tIHRoZSBIU01cbiAqL1xuaW50ZXJmYWNlIEhvcFByZWJ1aWxkIHtcbiAgdHg6IHN0cmluZztcbiAgaWQ6IHN0cmluZztcbiAgc2lnbmF0dXJlOiBzdHJpbmc7XG4gIHBheW1lbnRJZDogc3RyaW5nO1xuICBnYXNQcmljZTogbnVtYmVyO1xuICBnYXNMaW1pdDogbnVtYmVyO1xuICBhbW91bnQ6IG51bWJlcjtcbiAgcmVjaXBpZW50OiBzdHJpbmc7XG4gIG5vbmNlOiBudW1iZXI7XG4gIHVzZXJSZXFTaWc6IHN0cmluZztcbiAgZ2FzUHJpY2VNYXg6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBUaGUgZXh0cmEgcGFyYW1ldGVycyB0byBzZW5kIHRvIHBsYXRmb3JtIGJ1aWxkIHJvdXRlIGZvciBob3AgdHJhbnNhY3Rpb25zXG4gKi9cbmludGVyZmFjZSBIb3BQYXJhbXMge1xuICBob3BQYXJhbXM6IHtcbiAgICBnYXNQcmljZU1heDogbnVtYmVyO1xuICAgIHVzZXJSZXFTaWc6IHN0cmluZztcbiAgICBwYXltZW50SWQ6IHN0cmluZztcbiAgfTtcbiAgZ2FzTGltaXQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFSVAxNTU5IHtcbiAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IG51bWJlcjtcbiAgbWF4RmVlUGVyR2FzOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMge1xuICBjaGFpbjogc3RyaW5nIHwgbnVtYmVyO1xuICBoYXJkZm9yazogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uUHJlYnVpbGQgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25QcmVidWlsZCB7XG4gIGhvcFRyYW5zYWN0aW9uPzogSG9wUHJlYnVpbGQ7XG4gIGJ1aWxkUGFyYW1zOiB7XG4gICAgcmVjaXBpZW50czogUmVjaXBpZW50W107XG4gIH07XG4gIHJlY2lwaWVudHM6IFRyYW5zYWN0aW9uUmVjaXBpZW50W107XG4gIG5leHRDb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcjtcbiAgZ2FzUHJpY2U6IG51bWJlcjtcbiAgZ2FzTGltaXQ6IG51bWJlcjtcbiAgaXNCYXRjaDogYm9vbGVhbjtcbiAgY29pbjogc3RyaW5nO1xuICB0b2tlbj86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaWduRmluYWxPcHRpb25zIHtcbiAgdHhQcmVidWlsZDoge1xuICAgIGVpcDE1NTk/OiBFSVAxNTU5O1xuICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM7XG4gICAgZ2FzUHJpY2U/OiBzdHJpbmc7XG4gICAgZ2FzTGltaXQ/OiBzdHJpbmc7XG4gICAgcmVjaXBpZW50cz86IFJlY2lwaWVudFtdO1xuICAgIGhhbGZTaWduZWQ/OiB7XG4gICAgICBleHBpcmVUaW1lOiBudW1iZXI7XG4gICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcjtcbiAgICAgIGJhY2t1cEtleU5vbmNlPzogbnVtYmVyO1xuICAgICAgc2lnbmF0dXJlOiBzdHJpbmc7XG4gICAgICB0eEhleD86IHN0cmluZztcbiAgICB9O1xuICAgIG5leHRDb250cmFjdFNlcXVlbmNlSWQ/OiBudW1iZXI7XG4gICAgaG9wVHJhbnNhY3Rpb24/OiBzdHJpbmc7XG4gICAgYmFja3VwS2V5Tm9uY2U/OiBudW1iZXI7XG4gICAgaXNCYXRjaD86IGJvb2xlYW47XG4gICAgdHhIZXg/OiBzdHJpbmc7XG4gICAgZXhwaXJlVGltZT86IG51bWJlcjtcbiAgfTtcbiAgc2lnbmluZ0tleU5vbmNlPzogbnVtYmVyO1xuICB3YWxsZXRDb250cmFjdEFkZHJlc3M/OiBzdHJpbmc7XG4gIHBydjogc3RyaW5nO1xuICByZWNpcGllbnRzPzogUmVjaXBpZW50W107XG4gIGNvbW1vbj86IEV0aExpa2VDb21tb24uZGVmYXVsdDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaWduVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgQmFzZVNpZ25UcmFuc2FjdGlvbk9wdGlvbnMsIFNpZ25GaW5hbE9wdGlvbnMge1xuICBpc0xhc3RTaWduYXR1cmU/OiBib29sZWFuO1xuICBleHBpcmVUaW1lPzogbnVtYmVyO1xuICBzZXF1ZW5jZUlkPzogbnVtYmVyO1xuICBnYXNMaW1pdD86IG51bWJlcjtcbiAgZ2FzUHJpY2U/OiBudW1iZXI7XG4gIGN1c3RvZGlhblRyYW5zYWN0aW9uSWQ/OiBzdHJpbmc7XG4gIGNvbW1vbj86IEV0aExpa2VDb21tb24uZGVmYXVsdDtcbn1cblxuZXhwb3J0IHR5cGUgU2lnbmVkVHJhbnNhY3Rpb24gPSBIYWxmU2lnbmVkVHJhbnNhY3Rpb24gfCBGdWxseVNpZ25lZFRyYW5zYWN0aW9uO1xuXG5leHBvcnQgaW50ZXJmYWNlIEZlZXNVc2VkIHtcbiAgZ2FzUHJpY2U6IG51bWJlcjtcbiAgZ2FzTGltaXQ6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFByZWNyZWF0ZUJpdEdvT3B0aW9ucyB7XG4gIGVudGVycHJpc2U/OiBzdHJpbmc7XG4gIG5ld0ZlZUFkZHJlc3M/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT2ZmbGluZVZhdWx0VHhJbmZvIHtcbiAgbmV4dENvbnRyYWN0U2VxdWVuY2VJZD86IHN0cmluZztcbiAgY29udHJhY3RTZXF1ZW5jZUlkPzogc3RyaW5nO1xuICB0eD86IHN0cmluZztcbiAgdHhIZXg/OiBzdHJpbmc7XG4gIHVzZXJLZXk/OiBzdHJpbmc7XG4gIGJhY2t1cEtleT86IHN0cmluZztcbiAgY29pbjogc3RyaW5nO1xuICBnYXNQcmljZTogbnVtYmVyO1xuICBnYXNMaW1pdDogbnVtYmVyO1xuICByZWNpcGllbnRzOiBSZWNpcGllbnRbXTtcbiAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiBzdHJpbmc7XG4gIGFtb3VudDogc3RyaW5nO1xuICBiYWNrdXBLZXlOb25jZTogbnVtYmVyO1xuICAvLyBGb3IgRXRoIFNwZWNpZmljIENvaW5zXG4gIGVpcDE1NTk/OiBFSVAxNTU5O1xuICByZXBsYXlQcm90ZWN0aW9uT3B0aW9ucz86IFJlcGxheVByb3RlY3Rpb25PcHRpb25zO1xuICAvLyBGb3IgSG90IFdhbGxldCBFdm1CYXNlZENyb3NzQ2hhaW5SZWNvdmVyeSBTcGVjaWZpY1xuICBoYWxmU2lnbmVkPzogSGFsZlNpZ25lZFRyYW5zYWN0aW9uO1xuICBmZWVzVXNlZD86IEZlZXNVc2VkO1xuICBpc0V2bUJhc2VkQ3Jvc3NDaGFpblJlY292ZXJ5PzogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIFVuZm9ybWF0dGVkVHhJbmZvIHtcbiAgcmVjaXBpZW50OiBSZWNpcGllbnQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVjb3Zlck9wdGlvbnMge1xuICB1c2VyS2V5OiBzdHJpbmc7XG4gIGJhY2t1cEtleTogc3RyaW5nO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IHN0cmluZzsgLy8gdXNlIHRoaXMgYXMgd2FsbGV0QmFzZUFkZHJlc3MgZm9yIFRTU1xuICByZWNvdmVyeURlc3RpbmF0aW9uOiBzdHJpbmc7XG4gIGtyc1Byb3ZpZGVyPzogc3RyaW5nO1xuICBnYXNQcmljZT86IG51bWJlcjtcbiAgZ2FzTGltaXQ/OiBudW1iZXI7XG4gIGVpcDE1NTk/OiBFSVAxNTU5O1xuICByZXBsYXlQcm90ZWN0aW9uT3B0aW9ucz86IFJlcGxheVByb3RlY3Rpb25PcHRpb25zO1xuICBpc1Rzcz86IGJvb2xlYW47XG4gIGJpdGdvRmVlQWRkcmVzcz86IHN0cmluZztcbiAgYml0Z29EZXN0aW5hdGlvbkFkZHJlc3M/OiBzdHJpbmc7XG4gIHRva2VuQ29udHJhY3RBZGRyZXNzPzogc3RyaW5nO1xuICBpbnRlbmRlZENoYWluPzogc3RyaW5nO1xuICBjb21tb24/OiBFdGhMaWtlQ29tbW9uLmRlZmF1bHQ7XG59XG5cbmV4cG9ydCB0eXBlIEdldEJhdGNoRXhlY3V0aW9uSW5mb1JUID0ge1xuICB2YWx1ZXM6IFtzdHJpbmdbXSwgc3RyaW5nW11dO1xuICB0b3RhbEFtb3VudDogc3RyaW5nO1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBCdWlsZFRyYW5zYWN0aW9uUGFyYW1zIHtcbiAgdG86IHN0cmluZztcbiAgbm9uY2U/OiBudW1iZXI7XG4gIHZhbHVlOiBudW1iZXI7XG4gIGRhdGE/OiBCdWZmZXI7XG4gIGdhc1ByaWNlPzogbnVtYmVyO1xuICBnYXNMaW1pdD86IG51bWJlcjtcbiAgZWlwMTU1OT86IEVJUDE1NTk7XG4gIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVjb3ZlcnlJbmZvIHtcbiAgaWQ6IHN0cmluZztcbiAgdHg6IHN0cmluZztcbiAgYmFja3VwS2V5Pzogc3RyaW5nO1xuICBjb2luPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlY292ZXJUb2tlblRyYW5zYWN0aW9uIHtcbiAgaGFsZlNpZ25lZDoge1xuICAgIHJlY2lwaWVudDogUmVjaXBpZW50O1xuICAgIGV4cGlyZVRpbWU6IG51bWJlcjtcbiAgICBjb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcjtcbiAgICBvcGVyYXRpb25IYXNoOiBzdHJpbmc7XG4gICAgc2lnbmF0dXJlOiBzdHJpbmc7XG4gICAgZ2FzTGltaXQ6IG51bWJlcjtcbiAgICBnYXNQcmljZTogbnVtYmVyO1xuICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBzdHJpbmc7XG4gICAgd2FsbGV0SWQ6IHN0cmluZztcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZWNvdmVyVG9rZW5PcHRpb25zIHtcbiAgdG9rZW5Db250cmFjdEFkZHJlc3M6IHN0cmluZztcbiAgd2FsbGV0OiBXYWxsZXQ7XG4gIHJlY2lwaWVudDogc3RyaW5nO1xuICBicm9hZGNhc3Q/OiBib29sZWFuO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICBwcnY/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2V0U2VuZE1ldGhvZEFyZ3NPcHRpb25zIHtcbiAgcmVjaXBpZW50OiBSZWNpcGllbnQ7XG4gIGV4cGlyZVRpbWU6IG51bWJlcjtcbiAgY29udHJhY3RTZXF1ZW5jZUlkOiBudW1iZXI7XG4gIHNpZ25hdHVyZTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNlbmRNZXRob2RBcmdzIHtcbiAgbmFtZTogc3RyaW5nO1xuICB0eXBlOiBzdHJpbmc7XG4gIHZhbHVlOiBhbnk7XG59XG5cbmludGVyZmFjZSBIb3BUcmFuc2FjdGlvbkJ1aWxkT3B0aW9ucyB7XG4gIHdhbGxldDogV2FsbGV0O1xuICByZWNpcGllbnRzOiBSZWNpcGllbnRbXTtcbiAgd2FsbGV0UGFzc3BocmFzZTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkT3B0aW9ucyB7XG4gIGhvcD86IGJvb2xlYW47XG4gIHdhbGxldD86IFdhbGxldDtcbiAgcmVjaXBpZW50cz86IFJlY2lwaWVudFtdO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICBbaW5kZXg6IHN0cmluZ106IHVua25vd247XG59XG5cbmludGVyZmFjZSBGZWVFc3RpbWF0ZSB7XG4gIGdhc0xpbWl0RXN0aW1hdGU6IG51bWJlcjtcbiAgZmVlRXN0aW1hdGU6IG51bWJlcjtcbn1cblxuLy8gVE9ETzogVGhpcyBpbnRlcmZhY2Ugd2lsbCBuZWVkIHRvIGJlIHVwZGF0ZWQgZm9yIHRoZSBuZXcgZmVlIG1vZGVsIGludHJvZHVjZWQgaW4gdGhlIExvbmRvbiBIYXJkIEZvcmtcbmludGVyZmFjZSBFdGhUcmFuc2FjdGlvblBhcmFtcyBleHRlbmRzIFRyYW5zYWN0aW9uUGFyYW1zIHtcbiAgZ2FzUHJpY2U/OiBudW1iZXI7XG4gIGdhc0xpbWl0PzogbnVtYmVyO1xuICBob3BQYXJhbXM/OiBIb3BQYXJhbXM7XG4gIGhvcD86IGJvb2xlYW47XG4gIHByZWJ1aWxkVHg/OiBQcmVidWlsZFRyYW5zYWN0aW9uUmVzdWx0O1xufVxuXG5pbnRlcmZhY2UgVmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhQcmVidWlsZDogVHJhbnNhY3Rpb25QcmVidWlsZDtcbiAgdHhQYXJhbXM6IEV0aFRyYW5zYWN0aW9uUGFyYW1zO1xufVxuXG5pbnRlcmZhY2UgUHJlc2lnblRyYW5zYWN0aW9uT3B0aW9ucyBleHRlbmRzIFRyYW5zYWN0aW9uUHJlYnVpbGQsIEJhc2VQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgd2FsbGV0OiBXYWxsZXQ7XG59XG5cbmludGVyZmFjZSBFdGhBZGRyZXNzQ29pblNwZWNpZmljcyBleHRlbmRzIEFkZHJlc3NDb2luU3BlY2lmaWMge1xuICBmb3J3YXJkZXJWZXJzaW9uOiBudW1iZXI7XG4gIHNhbHQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmVyaWZ5RXRoQWRkcmVzc09wdGlvbnMgZXh0ZW5kcyBCYXNlVmVyaWZ5QWRkcmVzc09wdGlvbnMge1xuICBiYXNlQWRkcmVzczogc3RyaW5nO1xuICBjb2luU3BlY2lmaWM6IEV0aEFkZHJlc3NDb2luU3BlY2lmaWNzO1xuICBmb3J3YXJkZXJWZXJzaW9uOiBudW1iZXI7XG59XG5cbmNvbnN0IGRlYnVnID0gZGVidWdMaWIoJ2JpdGdvOnYyOmV0aGxpa2UnKTtcblxuZXhwb3J0IGNvbnN0IG9wdGlvbmFsRGVwcyA9IHtcbiAgZ2V0IGV0aEFiaSgpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHJlcXVpcmUoJ2V0aGVyZXVtanMtYWJpJyk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZGVidWcoJ3VuYWJsZSB0byBsb2FkIGV0aGVyZXVtanMtYWJpOicpO1xuICAgICAgZGVidWcoZS5zdGFjayk7XG4gICAgICB0aHJvdyBuZXcgRXRoZXJldW1MaWJyYXJ5VW5hdmFpbGFibGVFcnJvcihgZXRoZXJldW1qcy1hYmlgKTtcbiAgICB9XG4gIH0sXG5cbiAgZ2V0IGV0aFV0aWwoKSB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiByZXF1aXJlKCdldGhlcmV1bWpzLXV0aWwnKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBkZWJ1ZygndW5hYmxlIHRvIGxvYWQgZXRoZXJldW1qcy11dGlsOicpO1xuICAgICAgZGVidWcoZS5zdGFjayk7XG4gICAgICB0aHJvdyBuZXcgRXRoZXJldW1MaWJyYXJ5VW5hdmFpbGFibGVFcnJvcihgZXRoZXJldW1qcy11dGlsYCk7XG4gICAgfVxuICB9LFxuXG4gIGdldCBFdGhUeCgpOiB0eXBlb2YgRXRoTGlrZVR4TGliIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHJlcXVpcmUoJ0BldGhlcmV1bWpzL3R4Jyk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZGVidWcoJ3VuYWJsZSB0byBsb2FkIEBldGhlcmV1bWpzL3R4Jyk7XG4gICAgICBkZWJ1ZyhlLnN0YWNrKTtcbiAgICAgIHRocm93IG5ldyBFdGhlcmV1bUxpYnJhcnlVbmF2YWlsYWJsZUVycm9yKGBAZXRoZXJldW1qcy90eGApO1xuICAgIH1cbiAgfSxcblxuICBnZXQgRXRoQ29tbW9uKCk6IHR5cGVvZiBFdGhMaWtlQ29tbW9uIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHJlcXVpcmUoJ0BldGhlcmV1bWpzL2NvbW1vbicpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGRlYnVnKCd1bmFibGUgdG8gbG9hZCBAZXRoZXJldW1qcy9jb21tb246Jyk7XG4gICAgICBkZWJ1ZyhlLnN0YWNrKTtcbiAgICAgIHRocm93IG5ldyBFdGhlcmV1bUxpYnJhcnlVbmF2YWlsYWJsZUVycm9yKGBAZXRoZXJldW1qcy9jb21tb25gKTtcbiAgICB9XG4gIH0sXG59O1xuXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMgZXh0ZW5kcyBBYnN0cmFjdEV0aExpa2VDb2luIHtcbiAgc3RhdGljIGhvcFRyYW5zYWN0aW9uU2FsdCA9ICdiaXRnb0hvcEFkZHJlc3NSZXF1ZXN0U2FsdCc7XG4gIHByb3RlY3RlZCByZWFkb25seSBzZW5kTWV0aG9kTmFtZTogJ3NlbmRNdWx0aVNpZycgfCAnc2VuZE11bHRpU2lnVG9rZW4nO1xuXG4gIHJlYWRvbmx5IHN0YXRpY3NDb2luPzogUmVhZG9ubHk8U3RhdGljc0Jhc2VDb2luPjtcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoYml0Z286IEJpdEdvQmFzZSwgc3RhdGljc0NvaW4/OiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+KSB7XG4gICAgc3VwZXIoYml0Z28sIHN0YXRpY3NDb2luKTtcblxuICAgIGlmICghc3RhdGljc0NvaW4pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCBjb25zdHJ1Y3RvciBwYXJhbWV0ZXIgc3RhdGljc0NvaW4nKTtcbiAgICB9XG5cbiAgICB0aGlzLnN0YXRpY3NDb2luID0gc3RhdGljc0NvaW47XG4gICAgdGhpcy5zZW5kTWV0aG9kTmFtZSA9ICdzZW5kTXVsdGlTaWcnO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byByZXR1cm4gdGhlIGNvaW4ncyBuZXR3b3JrIG9iamVjdFxuICAgKiBAcmV0dXJucyB7RXRoTGlrZU5ldHdvcmsgfCB1bmRlZmluZWR9XG4gICAqL1xuICBnZXROZXR3b3JrKCk6IEV0aExpa2VOZXR3b3JrIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0aWNzQ29pbj8ubmV0d29yayBhcyBFdGhMaWtlTmV0d29yaztcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZXMgd2hldGhlciBhbiBhZGRyZXNzIHN0cmluZyBpcyB2YWxpZCBmb3IgdGhpcyBjb2luXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGFkZHJlc3MgaXMgdGhlIHZhbGlkIGV0aGxpa2UgYWRkZXJzc1xuICAgKi9cbiAgaXNWYWxpZEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG9wdGlvbmFsRGVwcy5ldGhVdGlsLmlzVmFsaWRBZGRyZXNzKG9wdGlvbmFsRGVwcy5ldGhVdGlsLmFkZEhleFByZWZpeChhZGRyZXNzKSk7XG4gIH1cblxuICAvKipcbiAgICogRmxhZyBmb3Igc2VuZGluZyBkYXRhIGFsb25nIHdpdGggdHJhbnNhY3Rpb25zXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIG9rYXkgdG8gc2VuZCB0eCBkYXRhIChFVEgpLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHRyYW5zYWN0aW9uRGF0YUFsbG93ZWQoKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogRGVmYXVsdCBleHBpcmUgdGltZSBmb3IgYSBjb250cmFjdCBjYWxsICgxIHdlZWspXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFRpbWUgaW4gc2Vjb25kc1xuICAgKi9cbiAgZ2V0RGVmYXVsdEV4cGlyZVRpbWUoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gTWF0aC5mbG9vcihuZXcgRGF0ZSgpLmdldFRpbWUoKSAvIDEwMDApICsgNjAgKiA2MCAqIDI0ICogNztcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gZ2V0IHRoZSBjdXN0b20gY2hhaW4gY29tbW9uIG9iamVjdCBiYXNlZCBvbiBwYXJhbXMgZnJvbSByZWNvdmVyeVxuICAgKiBAcGFyYW0ge251bWJlcn0gY2hhaW5JZCAtIHRoZSBjaGFpbiBpZCBvZiB0aGUgY3VzdG9tIGNoYWluXG4gICAqIEByZXR1cm5zIHtFdGhMaWtlQ29tbW9uLmRlZmF1bHR9XG4gICAqL1xuICBzdGF0aWMgZ2V0Q3VzdG9tQ2hhaW5Db21tb24oY2hhaW5JZDogbnVtYmVyKTogRXRoTGlrZUNvbW1vbi5kZWZhdWx0IHtcbiAgICBjb25zdCBjb2luTmFtZSA9IENvaW5NYXAuY29pbk5hbWVGcm9tQ2hhaW5JZChjaGFpbklkKTtcbiAgICBjb25zdCBjb2luID0gY29pbnMuZ2V0KGNvaW5OYW1lKTtcbiAgICBjb25zdCBldGhMaWtlQ29tbW9uID0gZ2V0Q29tbW9uKGNvaW4ubmV0d29yayBhcyBFdGhMaWtlTmV0d29yayk7XG4gICAgcmV0dXJuIGV0aExpa2VDb21tb247XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBjb3JyZWN0IEV0aCBDb21tb24gb2JqZWN0IGJhc2VkIG9uIHBhcmFtcyBmcm9tIGVpdGhlciByZWNvdmVyeSBvciB0eCBidWlsZGluZ1xuICAgKiBAcGFyYW0ge0VJUDE1NTl9IGVpcDE1NTkgLSBjb25maWdzIHRoYXQgc3BlY2lmeSB3aGV0aGVyIHdlIHNob3VsZCBjb25zdHJ1Y3QgYW4gZWlwMTU1OSB0eFxuICAgKiBAcGFyYW0ge1JlcGxheVByb3RlY3Rpb25PcHRpb25zfSByZXBsYXlQcm90ZWN0aW9uT3B0aW9ucyAtIGNoZWNrIGlmIGNoYWluIGlkIHN1cHBvcnRzIHJlcGxheSBwcm90ZWN0aW9uXG4gICAqIEByZXR1cm5zIHtFdGhMaWtlQ29tbW9uLmRlZmF1bHR9XG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBnZXRFdGhMaWtlQ29tbW9uKFxuICAgIGVpcDE1NTk/OiBFSVAxNTU5LFxuICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnNcbiAgKTogRXRoTGlrZUNvbW1vbi5kZWZhdWx0IHtcbiAgICAvLyBpZiBlaXAxNTU5IHBhcmFtcyBhcmUgc3BlY2lmaWVkLCBkZWZhdWx0IHRvIGxvbmRvbiBoYXJkZm9yaywgb3RoZXJ3aXNlLFxuICAgIC8vIGRlZmF1bHQgdG8gdGFuZ2VyaW5lIHdoaXN0bGUgdG8gYXZvaWQgcmVwbGF5IHByb3RlY3Rpb24gaXNzdWVzXG4gICAgY29uc3QgZGVmYXVsdEhhcmRmb3JrID0gISFlaXAxNTU5ID8gJ2xvbmRvbicgOiBvcHRpb25hbERlcHMuRXRoQ29tbW9uLkhhcmRmb3JrLlRhbmdlcmluZVdoaXN0bGU7XG4gICAgY29uc3QgZXRoTGlrZUNvbW1vbiA9IEFic3RyYWN0RXRoTGlrZU5ld0NvaW5zLmdldEN1c3RvbUNoYWluQ29tbW9uKHJlcGxheVByb3RlY3Rpb25PcHRpb25zPy5jaGFpbiBhcyBudW1iZXIpO1xuICAgIGV0aExpa2VDb21tb24uc2V0SGFyZGZvcmsocmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM/LmhhcmRmb3JrID8/IGRlZmF1bHRIYXJkZm9yayk7XG4gICAgcmV0dXJuIGV0aExpa2VDb21tb247XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHRvIGJ1aWxkIHRoZSB0eCBvYmplY3RcbiAgICogQHBhcmFtIHtCdWlsZFRyYW5zYWN0aW9uUGFyYW1zfSBwYXJhbXMgLSBwYXJhbXMgdG8gYnVpbGQgdHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge0V0aExpa2VUeExpYi5GZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb24gfCBFdGhMaWtlVHhMaWIuVHJhbnNhY3Rpb259XG4gICAqL1xuICBzdGF0aWMgYnVpbGRUcmFuc2FjdGlvbihcbiAgICBwYXJhbXM6IEJ1aWxkVHJhbnNhY3Rpb25QYXJhbXNcbiAgKTogRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbiB8IEV0aExpa2VUeExpYi5UcmFuc2FjdGlvbiB7XG4gICAgLy8gaWYgZWlwMTU1OSBwYXJhbXMgYXJlIHNwZWNpZmllZCwgZGVmYXVsdCB0byBsb25kb24gaGFyZGZvcmssIG90aGVyd2lzZSxcbiAgICAvLyBkZWZhdWx0IHRvIHRhbmdlcmluZSB3aGlzdGxlIHRvIGF2b2lkIHJlcGxheSBwcm90ZWN0aW9uIGlzc3Vlc1xuICAgIGNvbnN0IGV0aExpa2VDb21tb24gPSBBYnN0cmFjdEV0aExpa2VOZXdDb2lucy5nZXRFdGhMaWtlQ29tbW9uKHBhcmFtcy5laXAxNTU5LCBwYXJhbXMucmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMpO1xuICAgIGNvbnN0IGJhc2VQYXJhbXMgPSB7XG4gICAgICB0bzogcGFyYW1zLnRvLFxuICAgICAgbm9uY2U6IHBhcmFtcy5ub25jZSxcbiAgICAgIHZhbHVlOiBwYXJhbXMudmFsdWUsXG4gICAgICBkYXRhOiBwYXJhbXMuZGF0YSxcbiAgICAgIGdhc0xpbWl0OiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocGFyYW1zLmdhc0xpbWl0KSxcbiAgICB9O1xuXG4gICAgY29uc3QgdW5zaWduZWRFdGhUeCA9ICEhcGFyYW1zLmVpcDE1NTlcbiAgICAgID8gb3B0aW9uYWxEZXBzLkV0aFR4LkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbi5mcm9tVHhEYXRhKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIC4uLmJhc2VQYXJhbXMsXG4gICAgICAgICAgICBtYXhGZWVQZXJHYXM6IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihwYXJhbXMuZWlwMTU1OS5tYXhGZWVQZXJHYXMpLFxuICAgICAgICAgICAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihwYXJhbXMuZWlwMTU1OS5tYXhQcmlvcml0eUZlZVBlckdhcyksXG4gICAgICAgICAgfSxcbiAgICAgICAgICB7IGNvbW1vbjogZXRoTGlrZUNvbW1vbiB9XG4gICAgICAgIClcbiAgICAgIDogb3B0aW9uYWxEZXBzLkV0aFR4LlRyYW5zYWN0aW9uLmZyb21UeERhdGEoXG4gICAgICAgICAge1xuICAgICAgICAgICAgLi4uYmFzZVBhcmFtcyxcbiAgICAgICAgICAgIGdhc1ByaWNlOiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocGFyYW1zLmdhc1ByaWNlKSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHsgY29tbW9uOiBldGhMaWtlQ29tbW9uIH1cbiAgICAgICAgKTtcblxuICAgIHJldHVybiB1bnNpZ25lZEV0aFR4O1xuICB9XG5cbiAgLyoqXG4gICAqIFF1ZXJ5IGV4cGxvcmVyIGZvciB0aGUgYmFsYW5jZSBvZiBhbiBhZGRyZXNzXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzIC0gdGhlIEVUSExpa2UgYWRkcmVzc1xuICAgKiBAcmV0dXJucyB7QmlnTnVtYmVyfSBhZGRyZXNzIGJhbGFuY2VcbiAgICovXG4gIGFzeW5jIHF1ZXJ5QWRkcmVzc0JhbGFuY2UoYWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgbW9kdWxlOiAnYWNjb3VudCcsXG4gICAgICBhY3Rpb246ICdiYWxhbmNlJyxcbiAgICAgIGFkZHJlc3M6IGFkZHJlc3MsXG4gICAgfSk7XG4gICAgLy8gdGhyb3cgaWYgdGhlIHJlc3VsdCBkb2VzIG5vdCBleGlzdCBvciB0aGUgcmVzdWx0IGlzIG5vdCBhIHZhbGlkIG51bWJlclxuICAgIGlmICghcmVzdWx0IHx8ICFyZXN1bHQucmVzdWx0IHx8IGlzTmFOKHJlc3VsdC5yZXN1bHQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBvYnRhaW4gYWRkcmVzcyBiYWxhbmNlIGZvciAke2FkZHJlc3N9IGZyb20gdGhlIGV4cGxvcmVyLCBnb3Q6ICR7cmVzdWx0LnJlc3VsdH1gKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihyZXN1bHQucmVzdWx0LCAxMCk7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtSZWNpcGllbnRbXX0gcmVjaXBpZW50cyAtIHRoZSByZWNpcGllbnRzIG9mIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge251bWJlcn0gZXhwaXJlVGltZSAtIHRoZSBleHBpcmUgdGltZSBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvbnRyYWN0U2VxdWVuY2VJZCAtIHRoZSBjb250cmFjdCBzZXF1ZW5jZSBpZCBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge3N0cmluZ31cbiAgICovXG4gIGdldE9wZXJhdGlvblNoYTNGb3JFeGVjdXRlQW5kQ29uZmlybShcbiAgICByZWNpcGllbnRzOiBSZWNpcGllbnRbXSxcbiAgICBleHBpcmVUaW1lOiBudW1iZXIsXG4gICAgY29udHJhY3RTZXF1ZW5jZUlkOiBudW1iZXJcbiAgKTogc3RyaW5nIHtcbiAgICBpZiAoIXJlY2lwaWVudHMgfHwgIUFycmF5LmlzQXJyYXkocmVjaXBpZW50cykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0aW5nIGFycmF5IG9mIHJlY2lwaWVudHMnKTtcbiAgICB9XG5cbiAgICAvLyBSaWdodCBub3cgd2Ugb25seSBzdXBwb3J0IDEgcmVjaXBpZW50XG4gICAgaWYgKHJlY2lwaWVudHMubGVuZ3RoICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ211c3Qgc2VuZCB0byBleGFjdGx5IDEgcmVjaXBpZW50Jyk7XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzTnVtYmVyKGV4cGlyZVRpbWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGlyZVRpbWUgbXVzdCBiZSBudW1iZXIgb2Ygc2Vjb25kcyBzaW5jZSBlcG9jaCcpO1xuICAgIH1cblxuICAgIGlmICghXy5pc051bWJlcihjb250cmFjdFNlcXVlbmNlSWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NvbnRyYWN0U2VxdWVuY2VJZCBtdXN0IGJlIG51bWJlcicpO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlucHV0c1xuICAgIHJlY2lwaWVudHMuZm9yRWFjaChmdW5jdGlvbiAocmVjaXBpZW50KSB7XG4gICAgICBpZiAoXG4gICAgICAgICFfLmlzU3RyaW5nKHJlY2lwaWVudC5hZGRyZXNzKSB8fFxuICAgICAgICAhb3B0aW9uYWxEZXBzLmV0aFV0aWwuaXNWYWxpZEFkZHJlc3Mob3B0aW9uYWxEZXBzLmV0aFV0aWwuYWRkSGV4UHJlZml4KHJlY2lwaWVudC5hZGRyZXNzKSlcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgYWRkcmVzczogJyArIHJlY2lwaWVudC5hZGRyZXNzKTtcbiAgICAgIH1cblxuICAgICAgbGV0IGFtb3VudDogQmlnTnVtYmVyO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYW1vdW50ID0gbmV3IEJpZ051bWJlcihyZWNpcGllbnQuYW1vdW50KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFtb3VudCBmb3I6ICcgKyByZWNpcGllbnQuYWRkcmVzcyArICcgLSBzaG91bGQgYmUgbnVtZXJpYycpO1xuICAgICAgfVxuXG4gICAgICByZWNpcGllbnQuYW1vdW50ID0gYW1vdW50LnRvRml4ZWQoMCk7XG5cbiAgICAgIGlmIChyZWNpcGllbnQuZGF0YSAmJiAhXy5pc1N0cmluZyhyZWNpcGllbnQuZGF0YSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdEYXRhIGZvciByZWNpcGllbnQgJyArIHJlY2lwaWVudC5hZGRyZXNzICsgJyAtIHNob3VsZCBiZSBvZiB0eXBlIGhleCBzdHJpbmcnKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGNvbnN0IHJlY2lwaWVudCA9IHJlY2lwaWVudHNbMF07XG4gICAgcmV0dXJuIG9wdGlvbmFsRGVwcy5ldGhVdGlsLmJ1ZmZlclRvSGV4KFxuICAgICAgb3B0aW9uYWxEZXBzLmV0aEFiaS5zb2xpZGl0eVNIQTMoLi4udGhpcy5nZXRPcGVyYXRpb24ocmVjaXBpZW50LCBleHBpcmVUaW1lLCBjb250cmFjdFNlcXVlbmNlSWQpKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRyYW5zZmVyIG9wZXJhdGlvbiBmb3IgY29pblxuICAgKiBAcGFyYW0ge1JlY2lwaWVudH0gcmVjaXBpZW50IC0gcmVjaXBpZW50IGluZm9cbiAgICogQHBhcmFtIHtudW1iZXJ9IGV4cGlyZVRpbWUgLSBleHBpcnkgdGltZVxuICAgKiBAcGFyYW0ge251bWJlcn0gY29udHJhY3RTZXF1ZW5jZUlkIC0gc2VxdWVuY2UgaWRcbiAgICogQHJldHVybnMge0FycmF5fSBvcGVyYXRpb24gYXJyYXlcbiAgICovXG4gIGdldE9wZXJhdGlvbihyZWNpcGllbnQ6IFJlY2lwaWVudCwgZXhwaXJlVGltZTogbnVtYmVyLCBjb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcik6IChzdHJpbmcgfCBCdWZmZXIpW11bXSB7XG4gICAgY29uc3QgbmV0d29yayA9IHRoaXMuZ2V0TmV0d29yaygpIGFzIEV0aExpa2VOZXR3b3JrO1xuICAgIHJldHVybiBbXG4gICAgICBbJ3N0cmluZycsICdhZGRyZXNzJywgJ3VpbnQnLCAnYnl0ZXMnLCAndWludCcsICd1aW50J10sXG4gICAgICBbXG4gICAgICAgIG5ldHdvcmsubmF0aXZlQ29pbk9wZXJhdGlvbkhhc2hQcmVmaXgsXG4gICAgICAgIG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihvcHRpb25hbERlcHMuZXRoVXRpbC5zdHJpcEhleFByZWZpeChyZWNpcGllbnQuYWRkcmVzcyksIDE2KSxcbiAgICAgICAgcmVjaXBpZW50LmFtb3VudCxcbiAgICAgICAgQnVmZmVyLmZyb20ob3B0aW9uYWxEZXBzLmV0aFV0aWwuc3RyaXBIZXhQcmVmaXgob3B0aW9uYWxEZXBzLmV0aFV0aWwucGFkVG9FdmVuKHJlY2lwaWVudC5kYXRhIHx8ICcnKSksICdoZXgnKSxcbiAgICAgICAgZXhwaXJlVGltZSxcbiAgICAgICAgY29udHJhY3RTZXF1ZW5jZUlkLFxuICAgICAgXSxcbiAgICBdO1xuICB9XG5cbiAgLyoqXG4gICAqIFF1ZXJpZXMgdGhlIGNvbnRyYWN0ICh2aWEgZXhwbG9yZXIgQVBJKSBmb3IgdGhlIG5leHQgc2VxdWVuY2UgSURcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgLSBhZGRyZXNzIG9mIHRoZSBjb250cmFjdFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxOdW1iZXI+fSBzZXF1ZW5jZSBJRFxuICAgKi9cbiAgYXN5bmMgcXVlcnlTZXF1ZW5jZUlkKGFkZHJlc3M6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgLy8gR2V0IHNlcXVlbmNlIElEIHVzaW5nIGNvbnRyYWN0IGNhbGxcbiAgICBjb25zdCBzZXF1ZW5jZUlkTWV0aG9kU2lnbmF0dXJlID0gb3B0aW9uYWxEZXBzLmV0aEFiaS5tZXRob2RJRCgnZ2V0TmV4dFNlcXVlbmNlSWQnLCBbXSk7XG4gICAgY29uc3Qgc2VxdWVuY2VJZEFyZ3MgPSBvcHRpb25hbERlcHMuZXRoQWJpLnJhd0VuY29kZShbXSwgW10pO1xuICAgIGNvbnN0IHNlcXVlbmNlSWREYXRhID0gQnVmZmVyLmNvbmNhdChbc2VxdWVuY2VJZE1ldGhvZFNpZ25hdHVyZSwgc2VxdWVuY2VJZEFyZ3NdKS50b1N0cmluZygnaGV4Jyk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5yZWNvdmVyeUJsb2NrY2hhaW5FeHBsb3JlclF1ZXJ5KHtcbiAgICAgIG1vZHVsZTogJ3Byb3h5JyxcbiAgICAgIGFjdGlvbjogJ2V0aF9jYWxsJyxcbiAgICAgIHRvOiBhZGRyZXNzLFxuICAgICAgZGF0YTogc2VxdWVuY2VJZERhdGEsXG4gICAgICB0YWc6ICdsYXRlc3QnLFxuICAgIH0pO1xuICAgIGlmICghcmVzdWx0IHx8ICFyZXN1bHQucmVzdWx0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBvYnRhaW4gc2VxdWVuY2UgSUQgZnJvbSBleHBsb3JlciwgZ290OiAnICsgcmVzdWx0LnJlc3VsdCk7XG4gICAgfVxuICAgIGNvbnN0IHNlcXVlbmNlSWRIZXggPSByZXN1bHQucmVzdWx0O1xuICAgIHJldHVybiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4oc2VxdWVuY2VJZEhleC5zbGljZSgyKSwgMTYpLnRvTnVtYmVyKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVjb3ZlciBhbiB1bnN1cHBvcnRlZCB0b2tlbiBmcm9tIGEgQml0R28gbXVsdGlzaWcgd2FsbGV0XG4gICAqIFRoaXMgYnVpbGRzIGEgaGFsZi1zaWduZWQgdHJhbnNhY3Rpb24sIGZvciB3aGljaCB0aGVyZSB3aWxsIGJlIGFuIGFkbWluIHJvdXRlIHRvIGNvLXNpZ24gYW5kIGJyb2FkY2FzdC4gT3B0aW9uYWxseVxuICAgKiB0aGUgdXNlciBjYW4gc2V0IHBhcmFtcy5icm9hZGNhc3QgPSB0cnVlIGFuZCB0aGUgaGFsZi1zaWduZWQgdHggd2lsbCBiZSBzZW50IHRvIEJpdEdvIGZvciBjb3NpZ25pbmcgYW5kIGJyb2FkY2FzdGluZ1xuICAgKiBAcGFyYW0ge1JlY292ZXJUb2tlbk9wdGlvbnN9IHBhcmFtc1xuICAgKiBAcGFyYW0ge1dhbGxldH0gcGFyYW1zLndhbGxldCAtIHRoZSB3YWxsZXQgdG8gcmVjb3ZlciB0aGUgdG9rZW4gZnJvbVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzIC0gdGhlIGNvbnRyYWN0IGFkZHJlc3Mgb2YgdGhlIHVuc3VwcG9ydGVkIHRva2VuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMucmVjaXBpZW50IC0gdGhlIGRlc3RpbmF0aW9uIGFkZHJlc3MgcmVjb3ZlcmVkIHRva2VucyBzaG91bGQgYmUgc2VudCB0b1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLndhbGxldFBhc3NwaHJhc2UgLSB0aGUgd2FsbGV0IHBhc3NwaHJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5wcnYgLSB0aGUgeHBydlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHBhcmFtcy5icm9hZGNhc3QgLSBpZiB0cnVlLCB3ZSB3aWxsIGF1dG9tYXRpY2FsbHkgc3VibWl0IHRoZSBoYWxmLXNpZ25lZCB0eCB0byBCaXRHbyBmb3IgY29zaWduaW5nIGFuZCBicm9hZGNhc3RpbmdcbiAgICogQHJldHVybnMge1Byb21pc2U8UmVjb3ZlclRva2VuVHJhbnNhY3Rpb24+fVxuICAgKi9cbiAgYXN5bmMgcmVjb3ZlclRva2VuKHBhcmFtczogUmVjb3ZlclRva2VuT3B0aW9ucyk6IFByb21pc2U8UmVjb3ZlclRva2VuVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCBuZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKCkgYXMgRXRoTGlrZU5ldHdvcms7XG4gICAgaWYgKCFfLmlzT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgcmVjb3ZlclRva2VuIG11c3QgYmUgcGFzc2VkIGEgcGFyYW1zIG9iamVjdC4gR290ICR7cGFyYW1zfSAodHlwZSAke3R5cGVvZiBwYXJhbXN9KWApO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcykgfHwgIV8uaXNTdHJpbmcocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdG9rZW5Db250cmFjdEFkZHJlc3MgbXVzdCBiZSBhIHN0cmluZywgZ290ICR7XG4gICAgICAgICAgcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzXG4gICAgICAgIH0gKHR5cGUgJHt0eXBlb2YgcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzfSlgXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMudG9rZW5Db250cmFjdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Rva2VuQ29udHJhY3RBZGRyZXNzIG5vdCBhIHZhbGlkIGFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMud2FsbGV0KSB8fCAhKHBhcmFtcy53YWxsZXQgaW5zdGFuY2VvZiBXYWxsZXQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHdhbGxldCBtdXN0IGJlIGEgd2FsbGV0IGluc3RhbmNlLCBnb3QgJHtwYXJhbXMud2FsbGV0fSAodHlwZSAke3R5cGVvZiBwYXJhbXMud2FsbGV0fSlgKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMucmVjaXBpZW50KSB8fCAhXy5pc1N0cmluZyhwYXJhbXMucmVjaXBpZW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGByZWNpcGllbnQgbXVzdCBiZSBhIHN0cmluZywgZ290ICR7cGFyYW1zLnJlY2lwaWVudH0gKHR5cGUgJHt0eXBlb2YgcGFyYW1zLnJlY2lwaWVudH0pYCk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5yZWNpcGllbnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3JlY2lwaWVudCBub3QgYSB2YWxpZCBhZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKCFvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleCB8fCAhb3B0aW9uYWxEZXBzLmV0aEFiaS5zb2xpZGl0eVNIQTMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXRoZXJldW0gbm90IGZ1bGx5IHN1cHBvcnRlZCBpbiB0aGlzIGVudmlyb25tZW50Jyk7XG4gICAgfVxuXG4gICAgLy8gR2V0IHRva2VuIGJhbGFuY2UgZnJvbSBleHRlcm5hbCBBUElcbiAgICBjb25zdCBjb2luU3BlY2lmaWMgPSBwYXJhbXMud2FsbGV0LmNvaW5TcGVjaWZpYygpO1xuICAgIGlmICghY29pblNwZWNpZmljIHx8ICFfLmlzU3RyaW5nKGNvaW5TcGVjaWZpYy5iYXNlQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCBjb2luIHNwZWNpZmljIHByb3BlcnR5IGJhc2VBZGRyZXNzJyk7XG4gICAgfVxuICAgIGNvbnN0IHJlY292ZXJ5QW1vdW50ID0gYXdhaXQgdGhpcy5xdWVyeUFkZHJlc3NUb2tlbkJhbGFuY2UocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzLCBjb2luU3BlY2lmaWMuYmFzZUFkZHJlc3MpO1xuXG4gICAgaWYgKHBhcmFtcy5icm9hZGNhc3QpIHtcbiAgICAgIC8vIFdlJ3JlIGdvaW5nIHRvIGNyZWF0ZSBhIG5vcm1hbCBFVEggdHJhbnNhY3Rpb24gdGhhdCBzZW5kcyBhbiBhbW91bnQgb2YgMCBFVEggdG8gdGhlXG4gICAgICAvLyB0b2tlbkNvbnRyYWN0QWRkcmVzcyBhbmQgZW5jb2RlIHRoZSB1bnN1cHBvcnRlZC10b2tlbi1zZW5kIGRhdGEgaW4gdGhlIGRhdGEgZmllbGRcbiAgICAgIC8vICN0cmlja3N5XG4gICAgICBjb25zdCBzZW5kTWV0aG9kQXJncyA9IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6ICdfdG8nLFxuICAgICAgICAgIHR5cGU6ICdhZGRyZXNzJyxcbiAgICAgICAgICB2YWx1ZTogcGFyYW1zLnJlY2lwaWVudCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6ICdfdmFsdWUnLFxuICAgICAgICAgIHR5cGU6ICd1aW50MjU2JyxcbiAgICAgICAgICB2YWx1ZTogcmVjb3ZlcnlBbW91bnQudG9TdHJpbmcoMTApLFxuICAgICAgICB9LFxuICAgICAgXTtcbiAgICAgIGNvbnN0IG1ldGhvZFNpZ25hdHVyZSA9IG9wdGlvbmFsRGVwcy5ldGhBYmkubWV0aG9kSUQoJ3RyYW5zZmVyJywgXy5tYXAoc2VuZE1ldGhvZEFyZ3MsICd0eXBlJykpO1xuICAgICAgY29uc3QgZW5jb2RlZEFyZ3MgPSBvcHRpb25hbERlcHMuZXRoQWJpLnJhd0VuY29kZShfLm1hcChzZW5kTWV0aG9kQXJncywgJ3R5cGUnKSwgXy5tYXAoc2VuZE1ldGhvZEFyZ3MsICd2YWx1ZScpKTtcbiAgICAgIGNvbnN0IHNlbmREYXRhID0gQnVmZmVyLmNvbmNhdChbbWV0aG9kU2lnbmF0dXJlLCBlbmNvZGVkQXJnc10pO1xuXG4gICAgICBjb25zdCBicm9hZGNhc3RQYXJhbXM6IGFueSA9IHtcbiAgICAgICAgYWRkcmVzczogcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6ICcwJyxcbiAgICAgICAgZGF0YTogc2VuZERhdGEudG9TdHJpbmcoJ2hleCcpLFxuICAgICAgfTtcblxuICAgICAgaWYgKHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKSB7XG4gICAgICAgIGJyb2FkY2FzdFBhcmFtcy53YWxsZXRQYXNzcGhyYXNlID0gcGFyYW1zLndhbGxldFBhc3NwaHJhc2U7XG4gICAgICB9IGVsc2UgaWYgKHBhcmFtcy5wcnYpIHtcbiAgICAgICAgYnJvYWRjYXN0UGFyYW1zLnBydiA9IHBhcmFtcy5wcnY7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhd2FpdCBwYXJhbXMud2FsbGV0LnNlbmQoYnJvYWRjYXN0UGFyYW1zKTtcbiAgICB9XG5cbiAgICBjb25zdCByZWNpcGllbnQgPSB7XG4gICAgICBhZGRyZXNzOiBwYXJhbXMucmVjaXBpZW50LFxuICAgICAgYW1vdW50OiByZWNvdmVyeUFtb3VudC50b1N0cmluZygxMCksXG4gICAgfTtcblxuICAgIC8vIFRoaXMgc2lnbmF0dXJlIHdpbGwgYmUgdmFsaWQgZm9yIG9uZSB3ZWVrXG4gICAgY29uc3QgZXhwaXJlVGltZSA9IE1hdGguZmxvb3IobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwKSArIDYwICogNjAgKiAyNCAqIDc7XG5cbiAgICAvLyBHZXQgc2VxdWVuY2UgSUQuIFdlIGRvIHRoaXMgYnkgYnVpbGRpbmcgYSAnZmFrZScgZXRoIHRyYW5zYWN0aW9uLCBzbyB0aGUgcGxhdGZvcm0gd2lsbCBpbmNyZW1lbnQgYW5kIHJldHVybiB1cyB0aGUgbmV3IHNlcXVlbmNlIGlkXG4gICAgLy8gVGhpcyBfZG9lc18gcmVxdWlyZSB0aGUgdXNlciB0byBoYXZlIGEgbm9uLXplcm8gd2FsbGV0IGJhbGFuY2VcbiAgICBjb25zdCB7IG5leHRDb250cmFjdFNlcXVlbmNlSWQsIGdhc1ByaWNlLCBnYXNMaW1pdCB9ID0gKGF3YWl0IHBhcmFtcy53YWxsZXQucHJlYnVpbGRUcmFuc2FjdGlvbih7XG4gICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiBwYXJhbXMucmVjaXBpZW50LFxuICAgICAgICAgIGFtb3VudDogJzEnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KSkgYXMgYW55O1xuXG4gICAgLy8gdGhlc2UgcmVjb3ZlcmllcyBuZWVkIHRvIGJlIHByb2Nlc3NlZCBieSBzdXBwb3J0LCBidXQgaWYgdGhlIGN1c3RvbWVyIHNlbmRzIGFueSB0cmFuc2FjdGlvbnMgYmVmb3JlIHJlY292ZXJ5IGlzXG4gICAgLy8gY29tcGxldGUgdGhlIHNlcXVlbmNlIElEIHdpbGwgYmUgaW52YWxpZC4gYXJ0aWZpY2lhbGx5IGluZmxhdGUgdGhlIHNlcXVlbmNlIElEIHRvIGFsbG93IG1vcmUgdGltZSBmb3IgcHJvY2Vzc2luZ1xuICAgIGNvbnN0IHNhZmVTZXF1ZW5jZUlkID0gbmV4dENvbnRyYWN0U2VxdWVuY2VJZCArIDEwMDA7XG5cbiAgICAvLyBCdWlsZCBzZW5kRGF0YSBmb3IgZXRoZXJldW0gdHhcbiAgICBjb25zdCBvcGVyYXRpb25UeXBlcyA9IFsnc3RyaW5nJywgJ2FkZHJlc3MnLCAndWludCcsICdhZGRyZXNzJywgJ3VpbnQnLCAndWludCddO1xuICAgIGNvbnN0IG9wZXJhdGlvbkFyZ3MgPSBbXG4gICAgICAvLyBUb2tlbiBvcGVyYXRpb24gaGFzIHByZWZpeCBoYXMgYmVlbiBhZGRlZCBoZXJlIHNvIHRoYXQgZXRoZXIgb3BlcmF0aW9uIGhhc2hlcywgc2lnbmF0dXJlcyBjYW5ub3QgYmUgcmUtdXNlZCBmb3IgdG9rZW5TZW5kaW5nXG4gICAgICBuZXR3b3JrLnRva2VuT3BlcmF0aW9uSGFzaFByZWZpeCxcbiAgICAgIG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihvcHRpb25hbERlcHMuZXRoVXRpbC5zdHJpcEhleFByZWZpeChyZWNpcGllbnQuYWRkcmVzcyksIDE2KSxcbiAgICAgIHJlY2lwaWVudC5hbW91bnQsXG4gICAgICBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ob3B0aW9uYWxEZXBzLmV0aFV0aWwuc3RyaXBIZXhQcmVmaXgocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKSwgMTYpLFxuICAgICAgZXhwaXJlVGltZSxcbiAgICAgIHNhZmVTZXF1ZW5jZUlkLFxuICAgIF07XG5cbiAgICBjb25zdCBvcGVyYXRpb25IYXNoID0gb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9IZXgoXG4gICAgICBvcHRpb25hbERlcHMuZXRoQWJpLnNvbGlkaXR5U0hBMyhvcGVyYXRpb25UeXBlcywgb3BlcmF0aW9uQXJncylcbiAgICApO1xuXG4gICAgY29uc3QgdXNlclBydiA9IGF3YWl0IHBhcmFtcy53YWxsZXQuZ2V0UHJ2KHtcbiAgICAgIHBydjogcGFyYW1zLnBydixcbiAgICAgIHdhbGxldFBhc3NwaHJhc2U6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgIH0pO1xuXG4gICAgY29uc3Qgc2lnbmF0dXJlID0gVXRpbC5ldGhTaWduTXNnSGFzaChvcGVyYXRpb25IYXNoLCBVdGlsLnhwcnZUb0V0aFByaXZhdGVLZXkodXNlclBydikpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGhhbGZTaWduZWQ6IHtcbiAgICAgICAgcmVjaXBpZW50OiByZWNpcGllbnQsXG4gICAgICAgIGV4cGlyZVRpbWU6IGV4cGlyZVRpbWUsXG4gICAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogc2FmZVNlcXVlbmNlSWQsXG4gICAgICAgIG9wZXJhdGlvbkhhc2g6IG9wZXJhdGlvbkhhc2gsXG4gICAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlLFxuICAgICAgICBnYXNMaW1pdDogZ2FzTGltaXQsXG4gICAgICAgIGdhc1ByaWNlOiBnYXNQcmljZSxcbiAgICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgd2FsbGV0SWQ6IHBhcmFtcy53YWxsZXQuaWQoKSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbnN1cmUgZWl0aGVyIGVudGVycHJpc2Ugb3IgbmV3RmVlQWRkcmVzcyBpcyBwYXNzZWQsIHRvIGtub3cgd2hldGhlciB0byBjcmVhdGUgbmV3IGtleSBvciB1c2UgZW50ZXJwcmlzZSBrZXlcbiAgICogQHBhcmFtIHtQcmVjcmVhdGVCaXRHb09wdGlvbnN9IHBhcmFtc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmVudGVycHJpc2Uge1N0cmluZ30gdGhlIGVudGVycHJpc2UgaWQgdG8gYXNzb2NpYXRlIHdpdGggdGhpcyBrZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5uZXdGZWVBZGRyZXNzIHtCb29sZWFufSBjcmVhdGUgYSBuZXcgZmVlIGFkZHJlc3MgKGVudGVycHJpc2Ugbm90IG5lZWRlZCBpbiB0aGlzIGNhc2UpXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgcHJlQ3JlYXRlQml0R28ocGFyYW1zOiBQcmVjcmVhdGVCaXRHb09wdGlvbnMpOiB2b2lkIHtcbiAgICAvLyBXZSBhbHdheXMgbmVlZCBwYXJhbXMgb2JqZWN0LCBzaW5jZSBlaXRoZXIgZW50ZXJwcmlzZSBvciBuZXdGZWVBZGRyZXNzIGlzIHJlcXVpcmVkXG4gICAgaWYgKCFfLmlzT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgcHJlQ3JlYXRlQml0R28gbXVzdCBiZSBwYXNzZWQgYSBwYXJhbXMgb2JqZWN0LiBHb3QgJHtwYXJhbXN9ICh0eXBlICR7dHlwZW9mIHBhcmFtc30pYCk7XG4gICAgfVxuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLmVudGVycHJpc2UpICYmIF8uaXNVbmRlZmluZWQocGFyYW1zLm5ld0ZlZUFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdleHBlY3RpbmcgZW50ZXJwcmlzZSB3aGVuIGFkZGluZyBCaXRHbyBrZXkuIElmIHlvdSB3YW50IHRvIGNyZWF0ZSBhIG5ldyBFVEggYml0Z28ga2V5LCBzZXQgdGhlIG5ld0ZlZUFkZHJlc3MgcGFyYW1ldGVyIHRvIHRydWUuJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayB3aGV0aGVyIGtleSBzaG91bGQgYmUgYW4gZW50ZXJwcmlzZSBrZXkgb3IgYSBCaXRHbyBrZXkgZm9yIGEgbmV3IGZlZSBhZGRyZXNzXG4gICAgaWYgKCFfLmlzVW5kZWZpbmVkKHBhcmFtcy5lbnRlcnByaXNlKSAmJiAhXy5pc1VuZGVmaW5lZChwYXJhbXMubmV3RmVlQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW5jb21wYXRpYmxlIGFyZ3VtZW50cyAtIGNhbm5vdCBwYXNzIGJvdGggZW50ZXJwcmlzZSBhbmQgbmV3RmVlQWRkcmVzcyBwYXJhbWV0ZXIuYCk7XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzVW5kZWZpbmVkKHBhcmFtcy5lbnRlcnByaXNlKSAmJiAhXy5pc1N0cmluZyhwYXJhbXMuZW50ZXJwcmlzZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgZW50ZXJwcmlzZSBzaG91bGQgYmUgYSBzdHJpbmcgLSBnb3QgJHtwYXJhbXMuZW50ZXJwcmlzZX0gKHR5cGUgJHt0eXBlb2YgcGFyYW1zLmVudGVycHJpc2V9KWApO1xuICAgIH1cblxuICAgIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMubmV3RmVlQWRkcmVzcykgJiYgIV8uaXNCb29sZWFuKHBhcmFtcy5uZXdGZWVBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgbmV3RmVlQWRkcmVzcyBzaG91bGQgYmUgYSBib29sZWFuIC0gZ290ICR7cGFyYW1zLm5ld0ZlZUFkZHJlc3N9ICh0eXBlICR7dHlwZW9mIHBhcmFtcy5uZXdGZWVBZGRyZXNzfSlgXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyaWVzIHB1YmxpYyBibG9jayBleHBsb3JlciB0byBnZXQgdGhlIG5leHQgRVRITGlrZSBjb2luJ3Mgbm9uY2UgdGhhdCBzaG91bGQgYmUgdXNlZCBmb3IgdGhlIGdpdmVuIEVUSCBhZGRyZXNzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59XG4gICAqL1xuICBhc3luYyBnZXRBZGRyZXNzTm9uY2UoYWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICAvLyBHZXQgbm9uY2UgZm9yIGJhY2t1cCBrZXkgKHNob3VsZCBiZSAwKVxuICAgIGxldCBub25jZSA9IDA7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgbW9kdWxlOiAnYWNjb3VudCcsXG4gICAgICBhY3Rpb246ICd0eGxpc3QnLFxuICAgICAgYWRkcmVzcyxcbiAgICB9KTtcbiAgICBpZiAoIXJlc3VsdCB8fCAhQXJyYXkuaXNBcnJheShyZXN1bHQucmVzdWx0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmFibGUgdG8gZmluZCBuZXh0IG5vbmNlIGZyb20gRXRoZXJzY2FuLCBnb3Q6ICcgKyBKU09OLnN0cmluZ2lmeShyZXN1bHQpKTtcbiAgICB9XG4gICAgY29uc3QgYmFja3VwS2V5VHhMaXN0ID0gcmVzdWx0LnJlc3VsdDtcbiAgICBpZiAoYmFja3VwS2V5VHhMaXN0Lmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIENhbGN1bGF0ZSBsYXN0IG5vbmNlIHVzZWRcbiAgICAgIGNvbnN0IG91dGdvaW5nVHhzID0gYmFja3VwS2V5VHhMaXN0LmZpbHRlcigodHgpID0+IHR4LmZyb20gPT09IGFkZHJlc3MpO1xuICAgICAgbm9uY2UgPSBvdXRnb2luZ1R4cy5sZW5ndGg7XG4gICAgfVxuICAgIHJldHVybiBub25jZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIHJlY292ZXIoKVxuICAgKiBUaGlzIHRyYW5zZm9ybXMgdGhlIHVuc2lnbmVkIHRyYW5zYWN0aW9uIGluZm9ybWF0aW9uIGludG8gYSBmb3JtYXQgdGhlIEJpdEdvIG9mZmxpbmUgdmF1bHQgZXhwZWN0c1xuICAgKiBAcGFyYW0ge1VuZm9ybWF0dGVkVHhJbmZvfSB0eEluZm8gLSB0eCBpbmZvXG4gICAqIEBwYXJhbSB7RXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbn0gZXRoVHggLSB0aGUgZXRoZXJldW1qcyB0eCBvYmplY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJLZXkgLSB0aGUgdXNlcidzIGtleVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYmFja3VwS2V5IC0gdGhlIGJhY2t1cCBrZXlcbiAgICogQHBhcmFtIHtCdWZmZXJ9IGdhc1ByaWNlIC0gZ2FzIHByaWNlIGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtudW1iZXJ9IGdhc0xpbWl0IC0gZ2FzIGxpbWl0IGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtFSVAxNTU5fSBlaXAxNTU5IC0gZWlwMTU1OSBwYXJhbXNcbiAgICogQHBhcmFtIHtSZXBsYXlQcm90ZWN0aW9uT3B0aW9uc30gcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMgLSByZXBsYXkgcHJvdGVjdGlvbiBvcHRpb25zXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE9mZmxpbmVWYXVsdFR4SW5mbz59XG4gICAqL1xuICBhc3luYyBmb3JtYXRGb3JPZmZsaW5lVmF1bHQoXG4gICAgdHhJbmZvOiBVbmZvcm1hdHRlZFR4SW5mbyxcbiAgICBldGhUeDogRXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbixcbiAgICB1c2VyS2V5OiBzdHJpbmcsXG4gICAgYmFja3VwS2V5OiBzdHJpbmcsXG4gICAgZ2FzUHJpY2U6IEJ1ZmZlcixcbiAgICBnYXNMaW1pdDogbnVtYmVyLFxuICAgIGVpcDE1NTk/OiBFSVAxNTU5LFxuICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnNcbiAgKTogUHJvbWlzZTxPZmZsaW5lVmF1bHRUeEluZm8+IHtcbiAgICBpZiAoIWV0aFR4LnRvKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0V0aCB0eCBtdXN0IGhhdmUgYSBgdG9gIGFkZHJlc3MnKTtcbiAgICB9XG4gICAgY29uc3QgYmFja3VwSEROb2RlID0gYmlwMzIuZnJvbUJhc2U1OChiYWNrdXBLZXkpO1xuICAgIGNvbnN0IGJhY2t1cFNpZ25pbmdLZXkgPSBiYWNrdXBIRE5vZGUucHVibGljS2V5O1xuICAgIGNvbnN0IHJlc3BvbnNlOiBPZmZsaW5lVmF1bHRUeEluZm8gPSB7XG4gICAgICB0eDogZXRoVHguc2VyaWFsaXplKCkudG9TdHJpbmcoJ2hleCcpLFxuICAgICAgdXNlcktleSxcbiAgICAgIGJhY2t1cEtleSxcbiAgICAgIGNvaW46IHRoaXMuZ2V0Q2hhaW4oKSxcbiAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgZ2FzTGltaXQsXG4gICAgICByZWNpcGllbnRzOiBbdHhJbmZvLnJlY2lwaWVudF0sXG4gICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IGV0aFR4LnRvLnRvU3RyaW5nKCksXG4gICAgICBhbW91bnQ6IHR4SW5mby5yZWNpcGllbnQuYW1vdW50IGFzIHN0cmluZyxcbiAgICAgIGJhY2t1cEtleU5vbmNlOiBhd2FpdCB0aGlzLmdldEFkZHJlc3NOb25jZShcbiAgICAgICAgYDB4JHtvcHRpb25hbERlcHMuZXRoVXRpbC5wdWJsaWNUb0FkZHJlc3MoYmFja3VwU2lnbmluZ0tleSwgdHJ1ZSkudG9TdHJpbmcoJ2hleCcpfWBcbiAgICAgICksXG4gICAgICBlaXAxNTU5LFxuICAgICAgcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMsXG4gICAgfTtcbiAgICBfLmV4dGVuZChyZXNwb25zZSwgdHhJbmZvKTtcbiAgICByZXNwb25zZS5uZXh0Q29udHJhY3RTZXF1ZW5jZUlkID0gcmVzcG9uc2UuY29udHJhY3RTZXF1ZW5jZUlkO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIHJlY292ZXIoKVxuICAgKiBUaGlzIHRyYW5zZm9ybXMgdGhlIHVuc2lnbmVkIHRyYW5zYWN0aW9uIGluZm9ybWF0aW9uIGludG8gYSBmb3JtYXQgdGhlIEJpdEdvIG9mZmxpbmUgdmF1bHQgZXhwZWN0c1xuICAgKiBAcGFyYW0ge1VuZm9ybWF0dGVkVHhJbmZvfSB0eEluZm8gLSB0eCBpbmZvXG4gICAqIEBwYXJhbSB7RXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbn0gZXRoVHggLSB0aGUgZXRoZXJldW1qcyB0eCBvYmplY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJLZXkgLSB0aGUgdXNlcidzIGtleVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYmFja3VwS2V5IC0gdGhlIGJhY2t1cCBrZXlcbiAgICogQHBhcmFtIHtCdWZmZXJ9IGdhc1ByaWNlIC0gZ2FzIHByaWNlIGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtudW1iZXJ9IGdhc0xpbWl0IC0gZ2FzIGxpbWl0IGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtudW1iZXJ9IGJhY2t1cEtleU5vbmNlIC0gdGhlIG5vbmNlIG9mIHRoZSBiYWNrdXAga2V5IGFkZHJlc3NcbiAgICogQHBhcmFtIHtFSVAxNTU5fSBlaXAxNTU5IC0gZWlwMTU1OSBwYXJhbXNcbiAgICogQHBhcmFtIHtSZXBsYXlQcm90ZWN0aW9uT3B0aW9uc30gcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMgLSByZXBsYXkgcHJvdGVjdGlvbiBvcHRpb25zXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE9mZmxpbmVWYXVsdFR4SW5mbz59XG4gICAqL1xuICBmb3JtYXRGb3JPZmZsaW5lVmF1bHRUU1MoXG4gICAgdHhJbmZvOiBVbmZvcm1hdHRlZFR4SW5mbyxcbiAgICBldGhUeDogRXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbixcbiAgICB1c2VyS2V5OiBzdHJpbmcsXG4gICAgYmFja3VwS2V5OiBzdHJpbmcsXG4gICAgZ2FzUHJpY2U6IEJ1ZmZlcixcbiAgICBnYXNMaW1pdDogbnVtYmVyLFxuICAgIGJhY2t1cEtleU5vbmNlOiBudW1iZXIsXG4gICAgZWlwMTU1OT86IEVJUDE1NTksXG4gICAgcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM/OiBSZXBsYXlQcm90ZWN0aW9uT3B0aW9uc1xuICApOiBPZmZsaW5lVmF1bHRUeEluZm8ge1xuICAgIGlmICghZXRoVHgudG8pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRXRoIHR4IG11c3QgaGF2ZSBhIGB0b2AgYWRkcmVzcycpO1xuICAgIH1cbiAgICBjb25zdCByZXNwb25zZTogT2ZmbGluZVZhdWx0VHhJbmZvID0ge1xuICAgICAgdHg6IGV0aFR4LnNlcmlhbGl6ZSgpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgIHR4SGV4OiBldGhUeC5nZXRNZXNzYWdlVG9TaWduKGZhbHNlKS50b1N0cmluZygpLFxuICAgICAgdXNlcktleSxcbiAgICAgIGJhY2t1cEtleSxcbiAgICAgIGNvaW46IHRoaXMuZ2V0Q2hhaW4oKSxcbiAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgZ2FzTGltaXQsXG4gICAgICByZWNpcGllbnRzOiBbdHhJbmZvLnJlY2lwaWVudF0sXG4gICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IGV0aFR4LnRvLnRvU3RyaW5nKCksXG4gICAgICBhbW91bnQ6IHR4SW5mby5yZWNpcGllbnQuYW1vdW50IGFzIHN0cmluZyxcbiAgICAgIGJhY2t1cEtleU5vbmNlOiBiYWNrdXBLZXlOb25jZSxcbiAgICAgIGVpcDE1NTksXG4gICAgICByZXBsYXlQcm90ZWN0aW9uT3B0aW9ucyxcbiAgICB9O1xuICAgIF8uZXh0ZW5kKHJlc3BvbnNlLCB0eEluZm8pO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayB3aGV0aGVyIHRoZSBnYXMgcHJpY2UgcGFzc2VkIGluIGJ5IHVzZXIgYXJlIHdpdGhpbiBvdXIgbWF4IGFuZCBtaW4gYm91bmRzXG4gICAqIElmIHRoZXkgYXJlIG5vdCBzZXQsIHNldCB0aGVtIHRvIHRoZSBkZWZhdWx0c1xuICAgKiBAcGFyYW0ge251bWJlcn0gdXNlckdhc1ByaWNlIC0gdXNlciBkZWZpbmVkIGdhcyBwcmljZVxuICAgKiBAcmV0dXJucyB7bnVtYmVyfSB0aGUgZ2FzIHByaWNlIHRvIHVzZSBmb3IgdGhpcyB0cmFuc2FjdGlvblxuICAgKi9cbiAgc2V0R2FzUHJpY2UodXNlckdhc1ByaWNlPzogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBpZiAoIXVzZXJHYXNQcmljZSkge1xuICAgICAgcmV0dXJuIGV0aEdhc0NvbmZpZ3MuZGVmYXVsdEdhc1ByaWNlO1xuICAgIH1cblxuICAgIGNvbnN0IGdhc1ByaWNlTWF4ID0gZXRoR2FzQ29uZmlncy5tYXhpbXVtR2FzUHJpY2U7XG4gICAgY29uc3QgZ2FzUHJpY2VNaW4gPSBldGhHYXNDb25maWdzLm1pbmltdW1HYXNQcmljZTtcbiAgICBpZiAodXNlckdhc1ByaWNlIDwgZ2FzUHJpY2VNaW4gfHwgdXNlckdhc1ByaWNlID4gZ2FzUHJpY2VNYXgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgR2FzIHByaWNlIG11c3QgYmUgYmV0d2VlbiAke2dhc1ByaWNlTWlufSBhbmQgJHtnYXNQcmljZU1heH1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHVzZXJHYXNQcmljZTtcbiAgfVxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciBnYXMgbGltaXQgcGFzc2VkIGluIGJ5IHVzZXIgYXJlIHdpdGhpbiBvdXIgbWF4IGFuZCBtaW4gYm91bmRzXG4gICAqIElmIHRoZXkgYXJlIG5vdCBzZXQsIHNldCB0aGVtIHRvIHRoZSBkZWZhdWx0c1xuICAgKiBAcGFyYW0ge251bWJlcn0gdXNlckdhc0xpbWl0IHVzZXIgZGVmaW5lZCBnYXMgbGltaXRcbiAgICogQHJldHVybnMge251bWJlcn0gdGhlIGdhcyBsaW1pdCB0byB1c2UgZm9yIHRoaXMgdHJhbnNhY3Rpb25cbiAgICovXG4gIHNldEdhc0xpbWl0KHVzZXJHYXNMaW1pdD86IG51bWJlcik6IG51bWJlciB7XG4gICAgaWYgKCF1c2VyR2FzTGltaXQpIHtcbiAgICAgIHJldHVybiBldGhHYXNDb25maWdzLmRlZmF1bHRHYXNMaW1pdDtcbiAgICB9XG4gICAgY29uc3QgZ2FzTGltaXRNYXggPSBldGhHYXNDb25maWdzLm1heGltdW1HYXNMaW1pdDtcbiAgICBjb25zdCBnYXNMaW1pdE1pbiA9IGV0aEdhc0NvbmZpZ3MubWluaW11bUdhc0xpbWl0O1xuICAgIGlmICh1c2VyR2FzTGltaXQgPCBnYXNMaW1pdE1pbiB8fCB1c2VyR2FzTGltaXQgPiBnYXNMaW1pdE1heCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBHYXMgbGltaXQgbXVzdCBiZSBiZXR3ZWVuICR7Z2FzTGltaXRNaW59IGFuZCAke2dhc0xpbWl0TWF4fWApO1xuICAgIH1cbiAgICByZXR1cm4gdXNlckdhc0xpbWl0O1xuICB9XG5cbiAgLyoqXG4gICAqIEhlbHBlciBmdW5jdGlvbiBmb3Igc2lnblRyYW5zYWN0aW9uIGZvciB0aGUgcmFyZSBjYXNlIHRoYXQgU0RLIGlzIGRvaW5nIHRoZSBzZWNvbmQgc2lnbmF0dXJlXG4gICAqIE5vdGU6IHdlIGFyZSBleHBlY3RpbmcgdGhpcyB0byBiZSBjYWxsZWQgZnJvbSB0aGUgb2ZmbGluZSB2YXVsdFxuICAgKiBAcGFyYW0ge1NpZ25GaW5hbE9wdGlvbnMudHhQcmVidWlsZH0gcGFyYW1zLnR4UHJlYnVpbGRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5wcnZcbiAgICogQHJldHVybnMge3t0eEhleDogc3RyaW5nfX1cbiAgICovXG4gIGFzeW5jIHNpZ25GaW5hbEV0aExpa2UocGFyYW1zOiBTaWduRmluYWxPcHRpb25zKTogUHJvbWlzZTxGdWxseVNpZ25lZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3Qgc2lnbmluZ0tleSA9IG5ldyBLZXlQYWlyTGliKHsgcHJ2OiBwYXJhbXMucHJ2IH0pLmdldEtleXMoKS5wcnY7XG4gICAgaWYgKF8uaXNVbmRlZmluZWQoc2lnbmluZ0tleSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwcml2YXRlIGtleScpO1xuICAgIH1cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKTtcbiAgICB0cnkge1xuICAgICAgdHhCdWlsZGVyLmZyb20ocGFyYW1zLnR4UHJlYnVpbGQuaGFsZlNpZ25lZD8udHhIZXgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBoYWxmLXNpZ25lZCB0cmFuc2FjdGlvbicpO1xuICAgIH1cbiAgICB0eEJ1aWxkZXIuc2lnbih7IGtleTogc2lnbmluZ0tleSB9KTtcbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIHJldHVybiB7XG4gICAgICB0eEhleDogdHgudG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIGhhbGYtc2lnbiBwcmVidWlsdCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1NpZ25UcmFuc2FjdGlvbk9wdGlvbnN9IHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgc2lnblRyYW5zYWN0aW9uKHBhcmFtczogU2lnblRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8U2lnbmVkVHJhbnNhY3Rpb24+IHtcbiAgICAvLyBOb3JtYWxseSB0aGUgU0RLIHByb3ZpZGVzIHRoZSBmaXJzdCBzaWduYXR1cmUgZm9yIGFuIEV0aExpa2UgdHgsIGJ1dCBvY2Nhc2lvbmFsbHkgaXQgcHJvdmlkZXMgdGhlIHNlY29uZCBhbmQgZmluYWwgb25lLlxuICAgIGlmIChwYXJhbXMuaXNMYXN0U2lnbmF0dXJlKSB7XG4gICAgICAvLyBJbiB0aGlzIGNhc2Ugd2hlbiB3ZSdyZSBkb2luZyB0aGUgc2Vjb25kIChmaW5hbCkgc2lnbmF0dXJlLCB0aGUgbG9naWMgaXMgZGlmZmVyZW50LlxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuc2lnbkZpbmFsRXRoTGlrZShwYXJhbXMpO1xuICAgIH1cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKTtcbiAgICB0eEJ1aWxkZXIuZnJvbShwYXJhbXMudHhQcmVidWlsZC50eEhleCk7XG4gICAgdHhCdWlsZGVyXG4gICAgICAudHJhbnNmZXIoKVxuICAgICAgLmNvaW4odGhpcy5zdGF0aWNzQ29pbj8ubmFtZSBhcyBzdHJpbmcpXG4gICAgICAua2V5KG5ldyBLZXlQYWlyTGliKHsgcHJ2OiBwYXJhbXMucHJ2IH0pLmdldEtleXMoKS5wcnYhKTtcbiAgICBjb25zdCB0cmFuc2FjdGlvbiA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgY29uc3QgcmVjaXBpZW50cyA9IHRyYW5zYWN0aW9uLm91dHB1dHMubWFwKChvdXRwdXQpID0+ICh7IGFkZHJlc3M6IG91dHB1dC5hZGRyZXNzLCBhbW91bnQ6IG91dHB1dC52YWx1ZSB9KSk7XG5cbiAgICBjb25zdCB0eFBhcmFtcyA9IHtcbiAgICAgIGVpcDE1NTk6IHBhcmFtcy50eFByZWJ1aWxkLmVpcDE1NTksXG4gICAgICB0eEhleDogdHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgIHJlY2lwaWVudHM6IHJlY2lwaWVudHMsXG4gICAgICBleHBpcmF0aW9uOiBwYXJhbXMudHhQcmVidWlsZC5leHBpcmVUaW1lLFxuICAgICAgaG9wVHJhbnNhY3Rpb246IHBhcmFtcy50eFByZWJ1aWxkLmhvcFRyYW5zYWN0aW9uLFxuICAgICAgY3VzdG9kaWFuVHJhbnNhY3Rpb25JZDogcGFyYW1zLmN1c3RvZGlhblRyYW5zYWN0aW9uSWQsXG4gICAgICBleHBpcmVUaW1lOiBwYXJhbXMuZXhwaXJlVGltZSxcbiAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogcGFyYW1zLnR4UHJlYnVpbGQubmV4dENvbnRyYWN0U2VxdWVuY2VJZCBhcyBudW1iZXIsXG4gICAgICBzZXF1ZW5jZUlkOiBwYXJhbXMuc2VxdWVuY2VJZCxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHsgaGFsZlNpZ25lZDogdHhQYXJhbXMgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gdmFsaWRhdGUgcmVjb3ZlcnkgcGFyYW1zXG4gICAqIEBwYXJhbSB7UmVjb3Zlck9wdGlvbnN9IHBhcmFtc1xuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHZhbGlkYXRlUmVjb3ZlcnlQYXJhbXMocGFyYW1zOiBSZWNvdmVyT3B0aW9ucyk6IHZvaWQge1xuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy51c2VyS2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHVzZXJLZXknKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMuYmFja3VwS2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIGJhY2t1cEtleScpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKSAmJiAhcGFyYW1zLnVzZXJLZXkuc3RhcnRzV2l0aCgneHB1YicpICYmICFwYXJhbXMuaXNUc3MpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyB3YWxsZXQgcGFzc3BocmFzZScpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MpIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgd2FsbGV0Q29udHJhY3RBZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHJlY292ZXJ5RGVzdGluYXRpb24nKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHRvIHNpZ24gdHNzIHJlY292ZXJ5IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RUNEU0EuS2V5Q29tYmluZWR9IHVzZXJLZXlDb21iaW5lZFxuICAgKiBAcGFyYW0ge0VDRFNBLktleUNvbWJpbmVkfSBiYWNrdXBLZXlDb21iaW5lZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIZXhcbiAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnNcbiAgICogQHBhcmFtIHtFY2RzYVR5cGVzLlNlcmlhbGl6ZWROdGlsZGV9IG9wdGlvbnMucmFuZ2VQcm9vZkNoYWxsZW5nZVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxFQ0RTQU1ldGhvZFR5cGVzLlNpZ25hdHVyZT59XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNpZ25SZWNvdmVyeVRTUyhcbiAgICB1c2VyS2V5Q29tYmluZWQ6IEVDRFNBLktleUNvbWJpbmVkLFxuICAgIGJhY2t1cEtleUNvbWJpbmVkOiBFQ0RTQS5LZXlDb21iaW5lZCxcbiAgICB0eEhleDogc3RyaW5nLFxuICAgIHtcbiAgICAgIHJhbmdlUHJvb2ZDaGFsbGVuZ2UsXG4gICAgfToge1xuICAgICAgcmFuZ2VQcm9vZkNoYWxsZW5nZT86IEVjZHNhVHlwZXMuU2VyaWFsaXplZE50aWxkZTtcbiAgICB9ID0ge31cbiAgKTogUHJvbWlzZTxFQ0RTQU1ldGhvZFR5cGVzLlNpZ25hdHVyZT4ge1xuICAgIGlmICghdXNlcktleUNvbWJpbmVkIHx8ICFiYWNrdXBLZXlDb21iaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGtleSBjb21iaW5lZCBzaGFyZXMgZm9yIHVzZXIgb3IgYmFja3VwJyk7XG4gICAgfVxuXG4gICAgY29uc3QgTVBDID0gbmV3IEVjZHNhKCk7XG4gICAgY29uc3Qgc2lnbmVyT25lSW5kZXggPSB1c2VyS2V5Q29tYmluZWQueFNoYXJlLmk7XG4gICAgY29uc3Qgc2lnbmVyVHdvSW5kZXggPSBiYWNrdXBLZXlDb21iaW5lZC54U2hhcmUuaTtcblxuICAgIHJhbmdlUHJvb2ZDaGFsbGVuZ2UgPVxuICAgICAgcmFuZ2VQcm9vZkNoYWxsZW5nZSA/PyBFY2RzYVR5cGVzLnNlcmlhbGl6ZU50aWxkZVdpdGhQcm9vZnMoYXdhaXQgRWNkc2FSYW5nZVByb29mLmdlbmVyYXRlTnRpbGRlKCkpO1xuXG4gICAgY29uc3QgdXNlclRvQmFja3VwUGFpbGxpZXJDaGFsbGVuZ2UgPSBhd2FpdCBFY2RzYVBhaWxsaWVyUHJvb2YuZ2VuZXJhdGVQKFxuICAgICAgaGV4VG9CaWdJbnQodXNlcktleUNvbWJpbmVkLnlTaGFyZXNbc2lnbmVyVHdvSW5kZXhdLm4pXG4gICAgKTtcbiAgICBjb25zdCBiYWNrdXBUb1VzZXJQYWlsbGllckNoYWxsZW5nZSA9IGF3YWl0IEVjZHNhUGFpbGxpZXJQcm9vZi5nZW5lcmF0ZVAoXG4gICAgICBoZXhUb0JpZ0ludChiYWNrdXBLZXlDb21iaW5lZC55U2hhcmVzW3NpZ25lck9uZUluZGV4XS5uKVxuICAgICk7XG5cbiAgICBjb25zdCB1c2VyWFNoYXJlID0gTVBDLmFwcGVuZENoYWxsZW5nZShcbiAgICAgIHVzZXJLZXlDb21iaW5lZC54U2hhcmUsXG4gICAgICByYW5nZVByb29mQ2hhbGxlbmdlLFxuICAgICAgRWNkc2FUeXBlcy5zZXJpYWxpemVQYWlsbGllckNoYWxsZW5nZSh7IHA6IHVzZXJUb0JhY2t1cFBhaWxsaWVyQ2hhbGxlbmdlIH0pXG4gICAgKTtcbiAgICBjb25zdCB1c2VyWVNoYXJlID0gTVBDLmFwcGVuZENoYWxsZW5nZShcbiAgICAgIHVzZXJLZXlDb21iaW5lZC55U2hhcmVzW3NpZ25lclR3b0luZGV4XSxcbiAgICAgIHJhbmdlUHJvb2ZDaGFsbGVuZ2UsXG4gICAgICBFY2RzYVR5cGVzLnNlcmlhbGl6ZVBhaWxsaWVyQ2hhbGxlbmdlKHsgcDogYmFja3VwVG9Vc2VyUGFpbGxpZXJDaGFsbGVuZ2UgfSlcbiAgICApO1xuICAgIGNvbnN0IGJhY2t1cFhTaGFyZSA9IE1QQy5hcHBlbmRDaGFsbGVuZ2UoXG4gICAgICBiYWNrdXBLZXlDb21iaW5lZC54U2hhcmUsXG4gICAgICByYW5nZVByb29mQ2hhbGxlbmdlLFxuICAgICAgRWNkc2FUeXBlcy5zZXJpYWxpemVQYWlsbGllckNoYWxsZW5nZSh7IHA6IGJhY2t1cFRvVXNlclBhaWxsaWVyQ2hhbGxlbmdlIH0pXG4gICAgKTtcbiAgICBjb25zdCBiYWNrdXBZU2hhcmUgPSBNUEMuYXBwZW5kQ2hhbGxlbmdlKFxuICAgICAgYmFja3VwS2V5Q29tYmluZWQueVNoYXJlc1tzaWduZXJPbmVJbmRleF0sXG4gICAgICByYW5nZVByb29mQ2hhbGxlbmdlLFxuICAgICAgRWNkc2FUeXBlcy5zZXJpYWxpemVQYWlsbGllckNoYWxsZW5nZSh7IHA6IHVzZXJUb0JhY2t1cFBhaWxsaWVyQ2hhbGxlbmdlIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IHNpZ25TaGFyZXM6IEVDRFNBLlNpZ25TaGFyZVJUID0gYXdhaXQgTVBDLnNpZ25TaGFyZSh1c2VyWFNoYXJlLCB1c2VyWVNoYXJlKTtcblxuICAgIGNvbnN0IHNpZ25Db252ZXJ0UzIxID0gYXdhaXQgTVBDLnNpZ25Db252ZXJ0U3RlcDEoe1xuICAgICAgeFNoYXJlOiBiYWNrdXBYU2hhcmUsXG4gICAgICB5U2hhcmU6IGJhY2t1cFlTaGFyZSwgLy8gWVNoYXJlIGNvcnJlc3BvbmRpbmcgdG8gdGhlIG90aGVyIHBhcnRpY2lwYW50IHNpZ25lck9uZVxuICAgICAga1NoYXJlOiBzaWduU2hhcmVzLmtTaGFyZSxcbiAgICB9KTtcbiAgICBjb25zdCBzaWduQ29udmVydFMxMiA9IGF3YWl0IE1QQy5zaWduQ29udmVydFN0ZXAyKHtcbiAgICAgIGFTaGFyZTogc2lnbkNvbnZlcnRTMjEuYVNoYXJlLFxuICAgICAgd1NoYXJlOiBzaWduU2hhcmVzLndTaGFyZSxcbiAgICB9KTtcbiAgICBjb25zdCBzaWduQ29udmVydFMyMV8yID0gYXdhaXQgTVBDLnNpZ25Db252ZXJ0U3RlcDMoe1xuICAgICAgbXVTaGFyZTogc2lnbkNvbnZlcnRTMTIubXVTaGFyZSxcbiAgICAgIGJTaGFyZTogc2lnbkNvbnZlcnRTMjEuYlNoYXJlLFxuICAgIH0pO1xuXG4gICAgY29uc3QgW3NpZ25Db21iaW5lT25lLCBzaWduQ29tYmluZVR3b10gPSBbXG4gICAgICBNUEMuc2lnbkNvbWJpbmUoe1xuICAgICAgICBnU2hhcmU6IHNpZ25Db252ZXJ0UzEyLmdTaGFyZSxcbiAgICAgICAgc2lnbkluZGV4OiB7XG4gICAgICAgICAgaTogc2lnbkNvbnZlcnRTMTIubXVTaGFyZS5pLFxuICAgICAgICAgIGo6IHNpZ25Db252ZXJ0UzEyLm11U2hhcmUuaixcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICAgTVBDLnNpZ25Db21iaW5lKHtcbiAgICAgICAgZ1NoYXJlOiBzaWduQ29udmVydFMyMV8yLmdTaGFyZSxcbiAgICAgICAgc2lnbkluZGV4OiB7XG4gICAgICAgICAgaTogc2lnbkNvbnZlcnRTMjFfMi5zaWduSW5kZXguaSxcbiAgICAgICAgICBqOiBzaWduQ29udmVydFMyMV8yLnNpZ25JbmRleC5qLFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgXTtcblxuICAgIGNvbnN0IE1FU1NBR0UgPSBCdWZmZXIuZnJvbSh0eEhleCwgJ2hleCcpO1xuXG4gICAgY29uc3QgW3NpZ25BLCBzaWduQl0gPSBbXG4gICAgICBNUEMuc2lnbihNRVNTQUdFLCBzaWduQ29tYmluZU9uZS5vU2hhcmUsIHNpZ25Db21iaW5lVHdvLmRTaGFyZSwgS2VjY2FrKCdrZWNjYWsyNTYnKSksXG4gICAgICBNUEMuc2lnbihNRVNTQUdFLCBzaWduQ29tYmluZVR3by5vU2hhcmUsIHNpZ25Db21iaW5lT25lLmRTaGFyZSwgS2VjY2FrKCdrZWNjYWsyNTYnKSksXG4gICAgXTtcblxuICAgIHJldHVybiBNUEMuY29uc3RydWN0U2lnbmF0dXJlKFtzaWduQSwgc2lnbkJdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgd2hpY2ggY29tYmluZXMga2V5IHNoYXJlcyBvZiB1c2VyIGFuZCBiYWNrdXBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJQdWJsaWNPclByaXZhdGVLZXlTaGFyZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYmFja3VwUHJpdmF0ZU9yUHVibGljS2V5U2hhcmVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHdhbGxldFBhc3NwaHJhc2VcbiAgICogQHJldHVybnMge1tFQ0RTQU1ldGhvZFR5cGVzLktleUNvbWJpbmVkLCBFQ0RTQU1ldGhvZFR5cGVzLktleUNvbWJpbmVkXX1cbiAgICovXG4gIHByaXZhdGUgZ2V0S2V5Q29tYmluZWRGcm9tVHNzS2V5U2hhcmVzKFxuICAgIHVzZXJQdWJsaWNPclByaXZhdGVLZXlTaGFyZTogc3RyaW5nLFxuICAgIGJhY2t1cFByaXZhdGVPclB1YmxpY0tleVNoYXJlOiBzdHJpbmcsXG4gICAgd2FsbGV0UGFzc3BocmFzZT86IHN0cmluZ1xuICApOiBbRUNEU0FNZXRob2RUeXBlcy5LZXlDb21iaW5lZCwgRUNEU0FNZXRob2RUeXBlcy5LZXlDb21iaW5lZF0ge1xuICAgIGxldCBiYWNrdXBQcnY7XG4gICAgbGV0IHVzZXJQcnY7XG4gICAgdHJ5IHtcbiAgICAgIGJhY2t1cFBydiA9IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgIGlucHV0OiBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSxcbiAgICAgICAgcGFzc3dvcmQ6IHdhbGxldFBhc3NwaHJhc2UsXG4gICAgICB9KTtcbiAgICAgIHVzZXJQcnYgPSB0aGlzLmJpdGdvLmRlY3J5cHQoe1xuICAgICAgICBpbnB1dDogdXNlclB1YmxpY09yUHJpdmF0ZUtleVNoYXJlLFxuICAgICAgICBwYXNzd29yZDogd2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyBiYWNrdXAga2V5Y2hhaW46ICR7ZS5tZXNzYWdlfWApO1xuICAgIH1cblxuICAgIGNvbnN0IHVzZXJTaWduaW5nTWF0ZXJpYWwgPSBKU09OLnBhcnNlKHVzZXJQcnYpIGFzIEVDRFNBTWV0aG9kVHlwZXMuU2lnbmluZ01hdGVyaWFsO1xuICAgIGNvbnN0IGJhY2t1cFNpZ25pbmdNYXRlcmlhbCA9IEpTT04ucGFyc2UoYmFja3VwUHJ2KSBhcyBFQ0RTQU1ldGhvZFR5cGVzLlNpZ25pbmdNYXRlcmlhbDtcblxuICAgIGlmICghdXNlclNpZ25pbmdNYXRlcmlhbC5iYWNrdXBOU2hhcmUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB1c2VyIGtleSAtIG1pc3NpbmcgYmFja3VwTlNoYXJlJyk7XG4gICAgfVxuXG4gICAgaWYgKCFiYWNrdXBTaWduaW5nTWF0ZXJpYWwudXNlck5TaGFyZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGJhY2t1cCBrZXkgLSBtaXNzaW5nIHVzZXJOU2hhcmUnKTtcbiAgICB9XG5cbiAgICBjb25zdCBNUEMgPSBuZXcgRWNkc2EoKTtcblxuICAgIGNvbnN0IHVzZXJLZXlDb21iaW5lZCA9IE1QQy5rZXlDb21iaW5lKHVzZXJTaWduaW5nTWF0ZXJpYWwucFNoYXJlLCBbXG4gICAgICB1c2VyU2lnbmluZ01hdGVyaWFsLmJpdGdvTlNoYXJlLFxuICAgICAgdXNlclNpZ25pbmdNYXRlcmlhbC5iYWNrdXBOU2hhcmUsXG4gICAgXSk7XG4gICAgY29uc3QgdXNlclNpZ25pbmdLZXlEZXJpdmVkID0gTVBDLmtleURlcml2ZShcbiAgICAgIHVzZXJTaWduaW5nTWF0ZXJpYWwucFNoYXJlLFxuICAgICAgW3VzZXJTaWduaW5nTWF0ZXJpYWwuYml0Z29OU2hhcmUsIHVzZXJTaWduaW5nTWF0ZXJpYWwuYmFja3VwTlNoYXJlXSxcbiAgICAgICdtLzAnXG4gICAgKTtcbiAgICBjb25zdCB1c2VyS2V5RGVyaXZlZENvbWJpbmVkID0ge1xuICAgICAgeFNoYXJlOiB1c2VyU2lnbmluZ0tleURlcml2ZWQueFNoYXJlLFxuICAgICAgeVNoYXJlczogdXNlcktleUNvbWJpbmVkLnlTaGFyZXMsXG4gICAgfTtcbiAgICBjb25zdCBiYWNrdXBLZXlDb21iaW5lZCA9IE1QQy5rZXlDb21iaW5lKGJhY2t1cFNpZ25pbmdNYXRlcmlhbC5wU2hhcmUsIFtcbiAgICAgIHVzZXJTaWduaW5nS2V5RGVyaXZlZC5uU2hhcmVzWzJdLFxuICAgICAgYmFja3VwU2lnbmluZ01hdGVyaWFsLmJpdGdvTlNoYXJlLFxuICAgIF0pO1xuICAgIGlmIChcbiAgICAgIHVzZXJLZXlEZXJpdmVkQ29tYmluZWQueFNoYXJlLnkgIT09IGJhY2t1cEtleUNvbWJpbmVkLnhTaGFyZS55IHx8XG4gICAgICB1c2VyS2V5RGVyaXZlZENvbWJpbmVkLnhTaGFyZS5jaGFpbmNvZGUgIT09IGJhY2t1cEtleUNvbWJpbmVkLnhTaGFyZS5jaGFpbmNvZGVcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ29tbW9uIGtleWNoYWlucyBkbyBub3QgbWF0Y2gnKTtcbiAgICB9XG4gICAgcmV0dXJuIFt1c2VyS2V5RGVyaXZlZENvbWJpbmVkLCBiYWNrdXBLZXlDb21iaW5lZF07XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIHdoaWNoIEFkZHMgc2lnbmF0dXJlcyB0byB0eCBvYmplY3QgYW5kIHJlLXNlcmlhbGl6ZXMgdHhcbiAgICogQHBhcmFtIHtFdGhMaWtlQ29tbW9uLmRlZmF1bHR9IGV0aENvbW1vblxuICAgKiBAcGFyYW0ge0V0aExpa2VUeExpYi5GZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb24gfCBFdGhMaWtlVHhMaWIuVHJhbnNhY3Rpb259IHR4XG4gICAqIEBwYXJhbSB7RUNEU0FNZXRob2RUeXBlcy5TaWduYXR1cmV9IHNpZ25hdHVyZVxuICAgKiBAcmV0dXJucyB7RXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbiB8IEV0aExpa2VUeExpYi5UcmFuc2FjdGlvbn1cbiAgICovXG4gIHByaXZhdGUgZ2V0U2lnbmVkVHhGcm9tU2lnbmF0dXJlKFxuICAgIGV0aENvbW1vbjogRXRoTGlrZUNvbW1vbi5kZWZhdWx0LFxuICAgIHR4OiBFdGhMaWtlVHhMaWIuRmVlTWFya2V0RUlQMTU1OVRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uLFxuICAgIHNpZ25hdHVyZTogRUNEU0FNZXRob2RUeXBlcy5TaWduYXR1cmVcbiAgKSB7XG4gICAgLy8gZ2V0IHNpZ25lZCBUeCBmcm9tIHNpZ25hdHVyZVxuICAgIGNvbnN0IHR4RGF0YSA9IHR4LnRvSlNPTigpO1xuICAgIGNvbnN0IHlQYXJpdHkgPSBzaWduYXR1cmUucmVjaWQ7XG4gICAgY29uc3QgYmFzZVBhcmFtcyA9IHtcbiAgICAgIHRvOiB0eERhdGEudG8sXG4gICAgICBub25jZTogbmV3IEJOKHN0cmlwSGV4UHJlZml4KHR4RGF0YS5ub25jZSEpLCAnaGV4JyksXG4gICAgICB2YWx1ZTogbmV3IEJOKHN0cmlwSGV4UHJlZml4KHR4RGF0YS52YWx1ZSEpLCAnaGV4JyksXG4gICAgICBnYXNMaW1pdDogbmV3IEJOKHN0cmlwSGV4UHJlZml4KHR4RGF0YS5nYXNMaW1pdCEpLCAnaGV4JyksXG4gICAgICBkYXRhOiB0eERhdGEuZGF0YSxcbiAgICAgIHI6IGFkZEhleFByZWZpeChzaWduYXR1cmUuciksXG4gICAgICBzOiBhZGRIZXhQcmVmaXgoc2lnbmF0dXJlLnMpLFxuICAgIH07XG5cbiAgICBsZXQgZmluYWxUeDtcbiAgICBpZiAodHhEYXRhLm1heEZlZVBlckdhcyAmJiB0eERhdGEubWF4UHJpb3JpdHlGZWVQZXJHYXMpIHtcbiAgICAgIGZpbmFsVHggPSBGZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb24uZnJvbVR4RGF0YShcbiAgICAgICAge1xuICAgICAgICAgIC4uLmJhc2VQYXJhbXMsXG4gICAgICAgICAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IG5ldyBCTihzdHJpcEhleFByZWZpeCh0eERhdGEubWF4UHJpb3JpdHlGZWVQZXJHYXMhKSwgJ2hleCcpLFxuICAgICAgICAgIG1heEZlZVBlckdhczogbmV3IEJOKHN0cmlwSGV4UHJlZml4KHR4RGF0YS5tYXhGZWVQZXJHYXMhKSwgJ2hleCcpLFxuICAgICAgICAgIHY6IG5ldyBCTih5UGFyaXR5LnRvU3RyaW5nKCkpLFxuICAgICAgICB9LFxuICAgICAgICB7IGNvbW1vbjogZXRoQ29tbW9uIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIGlmICh0eERhdGEuZ2FzUHJpY2UpIHtcbiAgICAgIGNvbnN0IHYgPSBCaWdJbnQoMzUpICsgQmlnSW50KHlQYXJpdHkpICsgQmlnSW50KGV0aENvbW1vbi5jaGFpbklkQk4oKS50b051bWJlcigpKSAqIEJpZ0ludCgyKTtcbiAgICAgIGZpbmFsVHggPSBMZWdhY3lUcmFuc2FjdGlvbi5mcm9tVHhEYXRhKFxuICAgICAgICB7XG4gICAgICAgICAgLi4uYmFzZVBhcmFtcyxcbiAgICAgICAgICB2OiBuZXcgQk4odi50b1N0cmluZygpKSxcbiAgICAgICAgICBnYXNQcmljZTogbmV3IEJOKHN0cmlwSGV4UHJlZml4KHR4RGF0YS5nYXNQcmljZSEudG9TdHJpbmcoKSksICdoZXgnKSxcbiAgICAgICAgfSxcbiAgICAgICAgeyBjb21tb246IGV0aENvbW1vbiB9XG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiBmaW5hbFR4O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIGZ1bmRzIHJlY292ZXJ5IHRyYW5zYWN0aW9uIHdpdGhvdXQgQml0R29cbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnVzZXJLZXkgLSBbZW5jcnlwdGVkXSB4cHJ2XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuYmFja3VwS2V5IC0gW2VuY3J5cHRlZF0geHBydiBvciB4cHViIGlmIHRoZSB4cHJ2IGlzIGhlbGQgYnkgYSBLUlMgcHJvdmlkZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlIC0gdXNlZCB0byBkZWNyeXB0IHVzZXJLZXkgYW5kIGJhY2t1cEtleVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcyAtIHRoZSBFVEggYWRkcmVzcyBvZiB0aGUgd2FsbGV0IGNvbnRyYWN0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMua3JzUHJvdmlkZXIgLSBuZWNlc3NhcnkgaWYgYmFja3VwIGtleSBpcyBoZWxkIGJ5IEtSU1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24gLSB0YXJnZXQgYWRkcmVzcyB0byBzZW5kIHJlY292ZXJlZCBmdW5kcyB0b1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmJpdGdvRmVlQWRkcmVzcyAtIHdyb25nIGNoYWluIHdhbGxldCBmZWUgYWRkcmVzcyBmb3IgZXZtIGJhc2VkIGNyb3NzIGNoYWluIHJlY292ZXJ5IHR4blxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmJpdGdvRGVzdGluYXRpb25BZGRyZXNzIC0gdGFyZ2V0IGJpdGdvIGFkZHJlc3Mgd2hlcmUgZmVlIHdpbGwgYmUgc2VudCBmb3IgZXZtIGJhc2VkIGNyb3NzIGNoYWluIHJlY292ZXJ5IHR4blxuICAgKi9cbiAgYXN5bmMgcmVjb3ZlcihwYXJhbXM6IFJlY292ZXJPcHRpb25zKTogUHJvbWlzZTxSZWNvdmVyeUluZm8gfCBPZmZsaW5lVmF1bHRUeEluZm8+IHtcbiAgICBpZiAocGFyYW1zLmlzVHNzKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZWNvdmVyVFNTKHBhcmFtcyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnJlY292ZXJFdGhMaWtlKHBhcmFtcyk7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGRzIGEgZnVuZHMgcmVjb3ZlcnkgdHJhbnNhY3Rpb24gd2l0aG91dCBCaXRHbyBmb3Igbm9uLVRTUyB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMudXNlcktleSBbZW5jcnlwdGVkXSB4cHJ2IG9yIHhwdWJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5iYWNrdXBLZXkgW2VuY3J5cHRlZF0geHBydiBvciB4cHViIGlmIHRoZSB4cHJ2IGlzIGhlbGQgYnkgYSBLUlMgcHJvdmlkZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlIHVzZWQgdG8gZGVjcnlwdCB1c2VyS2V5IGFuZCBiYWNrdXBLZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MgdGhlIEV0aExpa2UgYWRkcmVzcyBvZiB0aGUgd2FsbGV0IGNvbnRyYWN0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMua3JzUHJvdmlkZXIgbmVjZXNzYXJ5IGlmIGJhY2t1cCBrZXkgaXMgaGVsZCBieSBLUlNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uIHRhcmdldCBhZGRyZXNzIHRvIHNlbmQgcmVjb3ZlcmVkIGZ1bmRzIHRvXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuYml0Z29GZWVBZGRyZXNzIHdyb25nIGNoYWluIHdhbGxldCBmZWUgYWRkcmVzcyBmb3IgZXZtIGJhc2VkIGNyb3NzIGNoYWluIHJlY292ZXJ5IHR4blxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmJpdGdvRGVzdGluYXRpb25BZGRyZXNzIHRhcmdldCBiaXRnbyBhZGRyZXNzIHdoZXJlIGZlZSB3aWxsIGJlIHNlbnQgZm9yIGV2bSBiYXNlZCBjcm9zcyBjaGFpbiByZWNvdmVyeSB0eG5cbiAgICogQHJldHVybnMge1Byb21pc2U8UmVjb3ZlcnlJbmZvIHwgT2ZmbGluZVZhdWx0VHhJbmZvPn1cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZWNvdmVyRXRoTGlrZShwYXJhbXM6IFJlY292ZXJPcHRpb25zKTogUHJvbWlzZTxSZWNvdmVyeUluZm8gfCBPZmZsaW5lVmF1bHRUeEluZm8+IHtcbiAgICAvLyBiaXRnb0ZlZUFkZHJlc3MgaXMgb25seSBkZWZpbmVkIHdoZW4gaXQgaXMgYSBldm0gY3Jvc3MgY2hhaW4gcmVjb3ZlcnlcbiAgICAvLyBhcyB3ZSB1c2UgZmVlIGZyb20gdGhpcyB3cm9uZyBjaGFpbiBhZGRyZXNzIGZvciB0aGUgcmVjb3ZlcnkgdHhuIG9uIHRoZSBjb3JyZWN0IGNoYWluLlxuICAgIGlmIChwYXJhbXMuYml0Z29GZWVBZGRyZXNzKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZWNvdmVyRXRoTGlrZWZvckV2bUJhc2VkUmVjb3ZlcnkocGFyYW1zKTtcbiAgICB9XG5cbiAgICB0aGlzLnZhbGlkYXRlUmVjb3ZlcnlQYXJhbXMocGFyYW1zKTtcbiAgICBjb25zdCBpc1Vuc2lnbmVkU3dlZXAgPSBnZXRJc1Vuc2lnbmVkU3dlZXAocGFyYW1zKTtcblxuICAgIC8vIENsZWFuIHVwIHdoaXRlc3BhY2UgZnJvbSBlbnRlcmVkIHZhbHVlc1xuICAgIGxldCB1c2VyS2V5ID0gcGFyYW1zLnVzZXJLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBiYWNrdXBLZXkgPSBwYXJhbXMuYmFja3VwS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgY29uc3QgZ2FzTGltaXQgPSBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4odGhpcy5zZXRHYXNMaW1pdChwYXJhbXMuZ2FzTGltaXQpKTtcbiAgICBjb25zdCBnYXNQcmljZSA9IHBhcmFtcy5laXAxNTU5XG4gICAgICA/IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihwYXJhbXMuZWlwMTU1OS5tYXhGZWVQZXJHYXMpXG4gICAgICA6IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTih0aGlzLnNldEdhc1ByaWNlKHBhcmFtcy5nYXNQcmljZSkpO1xuXG4gICAgaWYgKCF1c2VyS2V5LnN0YXJ0c1dpdGgoJ3hwdWInKSAmJiAhdXNlcktleS5zdGFydHNXaXRoKCd4cHJ2JykpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHVzZXJLZXkgPSB0aGlzLmJpdGdvLmRlY3J5cHQoe1xuICAgICAgICAgIGlucHV0OiB1c2VyS2V5LFxuICAgICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyB1c2VyIGtleWNoYWluOiAke2UubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgbGV0IGJhY2t1cEtleUFkZHJlc3M7XG4gICAgbGV0IGJhY2t1cFNpZ25pbmdLZXk7XG4gICAgaWYgKGlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgY29uc3QgYmFja3VwSEROb2RlID0gYmlwMzIuZnJvbUJhc2U1OChiYWNrdXBLZXkpO1xuICAgICAgYmFja3VwU2lnbmluZ0tleSA9IGJhY2t1cEhETm9kZS5wdWJsaWNLZXk7XG4gICAgICBiYWNrdXBLZXlBZGRyZXNzID0gYDB4JHtvcHRpb25hbERlcHMuZXRoVXRpbC5wdWJsaWNUb0FkZHJlc3MoYmFja3VwU2lnbmluZ0tleSwgdHJ1ZSkudG9TdHJpbmcoJ2hleCcpfWA7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIERlY3J5cHQgYmFja3VwIHByaXZhdGUga2V5IGFuZCBnZXQgYWRkcmVzc1xuICAgICAgbGV0IGJhY2t1cFBydjtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgYmFja3VwUHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgICBpbnB1dDogYmFja3VwS2V5LFxuICAgICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyBiYWNrdXAga2V5Y2hhaW46ICR7ZS5tZXNzYWdlfWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBrZXlQYWlyID0gbmV3IEtleVBhaXJMaWIoeyBwcnY6IGJhY2t1cFBydiB9KTtcbiAgICAgIGJhY2t1cFNpZ25pbmdLZXkgPSBrZXlQYWlyLmdldEtleXMoKS5wcnY7XG4gICAgICBpZiAoIWJhY2t1cFNpZ25pbmdLZXkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdubyBwcml2YXRlIGtleScpO1xuICAgICAgfVxuICAgICAgYmFja3VwS2V5QWRkcmVzcyA9IGtleVBhaXIuZ2V0QWRkcmVzcygpO1xuICAgIH1cblxuICAgIGNvbnN0IGJhY2t1cEtleU5vbmNlID0gYXdhaXQgdGhpcy5nZXRBZGRyZXNzTm9uY2UoYmFja3VwS2V5QWRkcmVzcyk7XG4gICAgLy8gZ2V0IGJhbGFuY2Ugb2YgYmFja3VwS2V5IHRvIGVuc3VyZSBmdW5kcyBhcmUgYXZhaWxhYmxlIHRvIHBheSBmZWVzXG4gICAgY29uc3QgYmFja3VwS2V5QmFsYW5jZSA9IGF3YWl0IHRoaXMucXVlcnlBZGRyZXNzQmFsYW5jZShiYWNrdXBLZXlBZGRyZXNzKTtcbiAgICBsZXQgdG90YWxHYXNOZWVkZWQgPSBnYXNQcmljZS5tdWwoZ2FzTGltaXQpO1xuXG4gICAgLy8gT24gb3B0aW1pc20gY2hhaW4sIEwxIGZlZXMgaXMgdG8gYmUgcGFpZCBhcyB3ZWxsIGFwYXJ0IGZyb20gTDIgZmVlc1xuICAgIC8vIFNvIHdlIGFyZSBhZGRpbmcgdGhlIGFtb3VudCB0aGF0IGNhbiBiZSB1c2VkIHVwIGFzIGwxIGZlZXNcbiAgICBpZiAodGhpcy5zdGF0aWNzQ29pbj8uZmFtaWx5ID09PSAnb3BldGgnKSB7XG4gICAgICB0b3RhbEdhc05lZWRlZCA9IHRvdGFsR2FzTmVlZGVkLmFkZChuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4oZXRoR2FzQ29uZmlncy5vcGV0aEdhc0wxRmVlcykpO1xuICAgIH1cblxuICAgIGNvbnN0IHdlaVRvR3dlaSA9IDEwICoqIDk7XG4gICAgaWYgKGJhY2t1cEtleUJhbGFuY2UubHQodG90YWxHYXNOZWVkZWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBCYWNrdXAga2V5IGFkZHJlc3MgJHtiYWNrdXBLZXlBZGRyZXNzfSBoYXMgYmFsYW5jZSAkeyhiYWNrdXBLZXlCYWxhbmNlIC8gd2VpVG9Hd2VpKS50b1N0cmluZygpfSBHd2VpLmAgK1xuICAgICAgICAgIGBUaGlzIGFkZHJlc3MgbXVzdCBoYXZlIGEgYmFsYW5jZSBvZiBhdCBsZWFzdCAkeyh0b3RhbEdhc05lZWRlZCAvIHdlaVRvR3dlaSkudG9TdHJpbmcoKX1gICtcbiAgICAgICAgICBgIEd3ZWkgdG8gcGVyZm9ybSByZWNvdmVyaWVzLiBUcnkgc2VuZGluZyBzb21lIGZ1bmRzIHRvIHRoaXMgYWRkcmVzcyB0aGVuIHJldHJ5LmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gZ2V0IGJhbGFuY2Ugb2Ygd2FsbGV0XG4gICAgY29uc3QgdHhBbW91bnQgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc0JhbGFuY2UocGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcyk7XG4gICAgaWYgKG5ldyBCaWdOdW1iZXIodHhBbW91bnQpLmlzTGVzc1RoYW5PckVxdWFsVG8oMCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignV2FsbGV0IGRvZXMgbm90IGhhdmUgZW5vdWdoIGZ1bmRzIHRvIHJlY292ZXInKTtcbiAgICB9XG5cbiAgICAvLyBidWlsZCByZWNpcGllbnRzIG9iamVjdFxuICAgIGNvbnN0IHJlY2lwaWVudHMgPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgICBhbW91bnQ6IHR4QW1vdW50LnRvU3RyaW5nKDEwKSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIC8vIEdldCBzZXF1ZW5jZSBJRCB1c2luZyBjb250cmFjdCBjYWxsXG4gICAgLy8gd2UgbmVlZCB0byB3YWl0IGJldHdlZW4gbWFraW5nIHR3byBleHBsb3JlciBhcGkgY2FsbHMgdG8gYXZvaWQgZ2V0dGluZyBiYW5uZWRcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxMDAwKSk7XG4gICAgY29uc3Qgc2VxdWVuY2VJZCA9IGF3YWl0IHRoaXMucXVlcnlTZXF1ZW5jZUlkKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MpO1xuXG4gICAgbGV0IG9wZXJhdGlvbkhhc2gsIHNpZ25hdHVyZTtcbiAgICAvLyBHZXQgb3BlcmF0aW9uIGhhc2ggYW5kIHNpZ24gaXRcbiAgICBpZiAoIWlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgb3BlcmF0aW9uSGFzaCA9IHRoaXMuZ2V0T3BlcmF0aW9uU2hhM0ZvckV4ZWN1dGVBbmRDb25maXJtKHJlY2lwaWVudHMsIHRoaXMuZ2V0RGVmYXVsdEV4cGlyZVRpbWUoKSwgc2VxdWVuY2VJZCk7XG4gICAgICBzaWduYXR1cmUgPSBVdGlsLmV0aFNpZ25Nc2dIYXNoKG9wZXJhdGlvbkhhc2gsIFV0aWwueHBydlRvRXRoUHJpdmF0ZUtleSh1c2VyS2V5KSk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIFV0aWwuZWNSZWNvdmVyRXRoQWRkcmVzcyhvcGVyYXRpb25IYXNoLCBzaWduYXR1cmUpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc2lnbmF0dXJlJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgdHhJbmZvID0ge1xuICAgICAgcmVjaXBpZW50OiByZWNpcGllbnRzWzBdLFxuICAgICAgZXhwaXJlVGltZTogdGhpcy5nZXREZWZhdWx0RXhwaXJlVGltZSgpLFxuICAgICAgY29udHJhY3RTZXF1ZW5jZUlkOiBzZXF1ZW5jZUlkLFxuICAgICAgb3BlcmF0aW9uSGFzaDogb3BlcmF0aW9uSGFzaCxcbiAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlLFxuICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LnRvU3RyaW5nKDEwKSxcbiAgICB9O1xuXG4gICAgY29uc3QgdHhCdWlsZGVyID0gdGhpcy5nZXRUcmFuc2FjdGlvbkJ1aWxkZXIocGFyYW1zLmNvbW1vbikgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICAgIHR4QnVpbGRlci5jb3VudGVyKGJhY2t1cEtleU5vbmNlKTtcbiAgICB0eEJ1aWxkZXIuY29udHJhY3QocGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcyk7XG4gICAgbGV0IHR4RmVlO1xuICAgIGlmIChwYXJhbXMuZWlwMTU1OSkge1xuICAgICAgdHhGZWUgPSB7XG4gICAgICAgIGVpcDE1NTk6IHtcbiAgICAgICAgICBtYXhQcmlvcml0eUZlZVBlckdhczogcGFyYW1zLmVpcDE1NTkubWF4UHJpb3JpdHlGZWVQZXJHYXMsXG4gICAgICAgICAgbWF4RmVlUGVyR2FzOiBwYXJhbXMuZWlwMTU1OS5tYXhGZWVQZXJHYXMsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICB0eEZlZSA9IHsgZmVlOiBnYXNQcmljZS50b1N0cmluZygpIH07XG4gICAgfVxuICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgLi4udHhGZWUsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoKSxcbiAgICB9KTtcbiAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSB0eEJ1aWxkZXIudHJhbnNmZXIoKSBhcyBUcmFuc2ZlckJ1aWxkZXI7XG4gICAgdHJhbnNmZXJCdWlsZGVyXG4gICAgICAuY29pbih0aGlzLnN0YXRpY3NDb2luPy5uYW1lIGFzIHN0cmluZylcbiAgICAgIC5hbW91bnQocmVjaXBpZW50c1swXS5hbW91bnQpXG4gICAgICAuY29udHJhY3RTZXF1ZW5jZUlkKHNlcXVlbmNlSWQpXG4gICAgICAuZXhwaXJhdGlvblRpbWUodGhpcy5nZXREZWZhdWx0RXhwaXJlVGltZSgpKVxuICAgICAgLnRvKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKTtcblxuICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgaWYgKGlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgY29uc3QgcmVzcG9uc2U6IE9mZmxpbmVWYXVsdFR4SW5mbyA9IHtcbiAgICAgICAgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgIHVzZXJLZXksXG4gICAgICAgIGJhY2t1cEtleSxcbiAgICAgICAgY29pbjogdGhpcy5nZXRDaGFpbigpLFxuICAgICAgICBnYXNQcmljZTogb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9JbnQoZ2FzUHJpY2UpLnRvRml4ZWQoKSxcbiAgICAgICAgZ2FzTGltaXQsXG4gICAgICAgIHJlY2lwaWVudHM6IFt0eEluZm8ucmVjaXBpZW50XSxcbiAgICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiB0eC50b0pzb24oKS50byxcbiAgICAgICAgYW1vdW50OiB0eEluZm8ucmVjaXBpZW50LmFtb3VudCxcbiAgICAgICAgYmFja3VwS2V5Tm9uY2UsXG4gICAgICAgIGVpcDE1NTk6IHBhcmFtcy5laXAxNTU5LFxuICAgICAgfTtcbiAgICAgIF8uZXh0ZW5kKHJlc3BvbnNlLCB0eEluZm8pO1xuICAgICAgcmVzcG9uc2UubmV4dENvbnRyYWN0U2VxdWVuY2VJZCA9IHJlc3BvbnNlLmNvbnRyYWN0U2VxdWVuY2VJZDtcbiAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICB9XG5cbiAgICB0eEJ1aWxkZXJcbiAgICAgIC50cmFuc2ZlcigpXG4gICAgICAuY29pbih0aGlzLnN0YXRpY3NDb2luPy5uYW1lIGFzIHN0cmluZylcbiAgICAgIC5rZXkobmV3IEtleVBhaXJMaWIoeyBwcnY6IHVzZXJLZXkgfSkuZ2V0S2V5cygpLnBydiBhcyBzdHJpbmcpO1xuICAgIHR4QnVpbGRlci5zaWduKHsga2V5OiBiYWNrdXBTaWduaW5nS2V5IH0pO1xuXG4gICAgY29uc3Qgc2lnbmVkVHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBpZDogc2lnbmVkVHgudG9Kc29uKCkuaWQsXG4gICAgICB0eDogc2lnbmVkVHgudG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIHVuc2lnbmVkIChmb3IgY29sZCwgY3VzdG9keSB3YWxsZXQpIG9yXG4gICAqIGhhbGYtc2lnbmVkIChmb3IgaG90IHdhbGxldCkgZXZtIGNyb3NzIGNoYWluIHJlY292ZXJ5IHRyYW5zYWN0aW9uIHdpdGhcbiAgICogc2FtZSBleHBlY3RlZCBhcmd1bWVudHMgYXMgcmVjb3ZlciBtZXRob2QuXG4gICAqIFRoaXMgaGVscHMgcmVjb3ZlciBmdW5kcyBmcm9tIGV2bSBiYXNlZCB3cm9uZyBjaGFpbi5cbiAgICogQHBhcmFtIHtSZWNvdmVyT3B0aW9uc30gcGFyYW1zXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFJlY292ZXJ5SW5mbyB8IE9mZmxpbmVWYXVsdFR4SW5mbz59XG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgcmVjb3ZlckV0aExpa2Vmb3JFdm1CYXNlZFJlY292ZXJ5KFxuICAgIHBhcmFtczogUmVjb3Zlck9wdGlvbnNcbiAgKTogUHJvbWlzZTxSZWNvdmVyeUluZm8gfCBPZmZsaW5lVmF1bHRUeEluZm8+IHtcbiAgICB0aGlzLnZhbGlkYXRlRXZtQmFzZWRSZWNvdmVyeVBhcmFtcyhwYXJhbXMpO1xuXG4gICAgLy8gQ2xlYW4gdXAgd2hpdGVzcGFjZSBmcm9tIGVudGVyZWQgdmFsdWVzXG4gICAgY29uc3QgdXNlcktleSA9IHBhcmFtcy51c2VyS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgY29uc3QgYml0Z29GZWVBZGRyZXNzID0gcGFyYW1zLmJpdGdvRmVlQWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcbiAgICBjb25zdCBiaXRnb0Rlc3RpbmF0aW9uQWRkcmVzcyA9IHBhcmFtcy5iaXRnb0Rlc3RpbmF0aW9uQWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcbiAgICBjb25zdCByZWNvdmVyeURlc3RpbmF0aW9uID0gcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24/LnJlcGxhY2UoL1xccy9nLCAnJykudG9Mb3dlckNhc2UoKSBhcyBzdHJpbmc7XG4gICAgY29uc3Qgd2FsbGV0Q29udHJhY3RBZGRyZXNzID0gcGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcbiAgICBjb25zdCB0b2tlbkNvbnRyYWN0QWRkcmVzcyA9IHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcblxuICAgIGxldCB1c2VyU2lnbmluZ0tleTtcbiAgICBsZXQgdXNlcktleVBydjtcbiAgICBpZiAocGFyYW1zLndhbGxldFBhc3NwaHJhc2UpIHtcbiAgICAgIGlmICghdXNlcktleS5zdGFydHNXaXRoKCd4cHViJykgJiYgIXVzZXJLZXkuc3RhcnRzV2l0aCgneHBydicpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdXNlcktleVBydiA9IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgICAgICBpbnB1dDogdXNlcktleSxcbiAgICAgICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyB1c2VyIGtleWNoYWluOiAke2UubWVzc2FnZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBrZXlQYWlyID0gbmV3IEtleVBhaXJMaWIoeyBwcnY6IHVzZXJLZXlQcnYgfSk7XG4gICAgICB1c2VyU2lnbmluZ0tleSA9IGtleVBhaXIuZ2V0S2V5cygpLnBydjtcbiAgICAgIGlmICghdXNlclNpZ25pbmdLZXkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdubyBwcml2YXRlIGtleScpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGdhc0xpbWl0ID0gbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHRoaXMuc2V0R2FzTGltaXQocGFyYW1zLmdhc0xpbWl0KSk7XG4gICAgY29uc3QgZ2FzUHJpY2UgPSBwYXJhbXMuZWlwMTU1OVxuICAgICAgPyBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocGFyYW1zLmVpcDE1NTkubWF4RmVlUGVyR2FzKVxuICAgICAgOiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4odGhpcy5zZXRHYXNQcmljZShwYXJhbXMuZ2FzUHJpY2UpKTtcblxuICAgIGNvbnN0IGJpdGdvRmVlQWRkcmVzc05vbmNlID0gYXdhaXQgdGhpcy5nZXRBZGRyZXNzTm9uY2UoYml0Z29GZWVBZGRyZXNzKTtcblxuICAgIC8vIGdldCBiYWxhbmNlIG9mIGJpdGdvRmVlQWRkcmVzcyB0byBlbnN1cmUgZnVuZHMgYXJlIGF2YWlsYWJsZSB0byBwYXkgZmVlc1xuICAgIGNvbnN0IGJpdGdvRmVlQWRkcmVzc0JhbGFuY2UgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc0JhbGFuY2UoYml0Z29GZWVBZGRyZXNzKTtcbiAgICBjb25zdCB0b3RhbEdhc05lZWRlZCA9IGdhc1ByaWNlLm11bChnYXNMaW1pdCk7XG4gICAgY29uc3Qgd2VpVG9Hd2VpID0gMTAgKiogOTtcbiAgICBpZiAoYml0Z29GZWVBZGRyZXNzQmFsYW5jZS5sdCh0b3RhbEdhc05lZWRlZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZlZSBhZGRyZXNzICR7Yml0Z29GZWVBZGRyZXNzfSBoYXMgYmFsYW5jZSAkeyhiaXRnb0ZlZUFkZHJlc3NCYWxhbmNlIC8gd2VpVG9Hd2VpKS50b1N0cmluZygpfSBHd2VpLmAgK1xuICAgICAgICAgIGBUaGlzIGFkZHJlc3MgbXVzdCBoYXZlIGEgYmFsYW5jZSBvZiBhdCBsZWFzdCAkeyh0b3RhbEdhc05lZWRlZCAvIHdlaVRvR3dlaSkudG9TdHJpbmcoKX1gICtcbiAgICAgICAgICBgIEd3ZWkgdG8gcGVyZm9ybSByZWNvdmVyaWVzLiBUcnkgc2VuZGluZyBzb21lICR7dGhpcy5nZXRDaGFpbigpfSB0byB0aGlzIGFkZHJlc3MgdGhlbiByZXRyeS5gXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICh0b2tlbkNvbnRyYWN0QWRkcmVzcykge1xuICAgICAgcmV0dXJuIHRoaXMucmVjb3ZlckV0aExpa2VUb2tlbmZvckV2bUJhc2VkUmVjb3ZlcnkoXG4gICAgICAgIHBhcmFtcyxcbiAgICAgICAgYml0Z29GZWVBZGRyZXNzTm9uY2UsXG4gICAgICAgIGdhc0xpbWl0LFxuICAgICAgICBnYXNQcmljZSxcbiAgICAgICAgdXNlcktleSxcbiAgICAgICAgdXNlclNpZ25pbmdLZXlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gZ2V0IGJhbGFuY2Ugb2Ygd2FsbGV0XG4gICAgY29uc3QgdHhBbW91bnQgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc0JhbGFuY2Uod2FsbGV0Q29udHJhY3RBZGRyZXNzKTtcblxuICAgIGNvbnN0IGJpdGdvRmVlUGVyY2VudGFnZSA9IDA7IC8vIFRPRE86IEJHLTcxOTEyIGNhbiBjaGFuZ2UgdGhlIGZlZSUgaGVyZS5cbiAgICBjb25zdCBiaXRnb0ZlZUFtb3VudCA9IHR4QW1vdW50ICogKGJpdGdvRmVlUGVyY2VudGFnZSAvIDEwMCk7XG5cbiAgICAvLyBidWlsZCByZWNpcGllbnRzIG9iamVjdFxuICAgIGNvbnN0IHJlY2lwaWVudHM6IFJlY2lwaWVudFtdID0gW1xuICAgICAge1xuICAgICAgICBhZGRyZXNzOiByZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgICBhbW91bnQ6IG5ldyBCaWdOdW1iZXIodHhBbW91bnQpLm1pbnVzKGJpdGdvRmVlQW1vdW50KS50b0ZpeGVkKCksXG4gICAgICB9LFxuICAgIF07XG5cbiAgICBpZiAoYml0Z29GZWVQZXJjZW50YWdlID4gMCkge1xuICAgICAgaWYgKF8uaXNVbmRlZmluZWQoYml0Z29EZXN0aW5hdGlvbkFkZHJlc3MpIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKGJpdGdvRGVzdGluYXRpb25BZGRyZXNzKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgYml0Z29EZXN0aW5hdGlvbkFkZHJlc3MnKTtcbiAgICAgIH1cblxuICAgICAgcmVjaXBpZW50cy5wdXNoKHtcbiAgICAgICAgYWRkcmVzczogYml0Z29EZXN0aW5hdGlvbkFkZHJlc3MsXG4gICAgICAgIGFtb3VudDogYml0Z29GZWVBbW91bnQudG9TdHJpbmcoMTApLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gY2FsY3VsYXRlIGJhdGNoIGRhdGFcbiAgICBjb25zdCBCQVRDSF9NRVRIT0RfTkFNRSA9ICdiYXRjaCc7XG4gICAgY29uc3QgQkFUQ0hfTUVUSE9EX1RZUEVTID0gWydhZGRyZXNzW10nLCAndWludDI1NltdJ107XG4gICAgY29uc3QgYmF0Y2hFeGVjdXRpb25JbmZvID0gdGhpcy5nZXRCYXRjaEV4ZWN1dGlvbkluZm8ocmVjaXBpZW50cyk7XG4gICAgY29uc3QgYmF0Y2hEYXRhID0gb3B0aW9uYWxEZXBzLmV0aFV0aWwuYWRkSGV4UHJlZml4KFxuICAgICAgdGhpcy5nZXRNZXRob2RDYWxsRGF0YShCQVRDSF9NRVRIT0RfTkFNRSwgQkFUQ0hfTUVUSE9EX1RZUEVTLCBiYXRjaEV4ZWN1dGlvbkluZm8udmFsdWVzKS50b1N0cmluZygnaGV4JylcbiAgICApO1xuXG4gICAgLy8gR2V0IHNlcXVlbmNlIElEIHVzaW5nIGNvbnRyYWN0IGNhbGxcbiAgICAvLyB3ZSBuZWVkIHRvIHdhaXQgYmV0d2VlbiBtYWtpbmcgdHdvIGV4cGxvcmVyIGFwaSBjYWxscyB0byBhdm9pZCBnZXR0aW5nIGJhbm5lZFxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMDApKTtcbiAgICBjb25zdCBzZXF1ZW5jZUlkID0gYXdhaXQgdGhpcy5xdWVyeVNlcXVlbmNlSWQod2FsbGV0Q29udHJhY3RBZGRyZXNzKTtcblxuICAgIGNvbnN0IHR4SW5mbyA9IHtcbiAgICAgIHJlY2lwaWVudHM6IHJlY2lwaWVudHMsXG4gICAgICBleHBpcmVUaW1lOiB0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCksXG4gICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IHNlcXVlbmNlSWQsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoMTApLFxuICAgICAgaXNFdm1CYXNlZENyb3NzQ2hhaW5SZWNvdmVyeTogdHJ1ZSxcbiAgICB9O1xuXG4gICAgY29uc3QgbmV0d29yayA9IHRoaXMuZ2V0TmV0d29yaygpO1xuICAgIGNvbnN0IGJhdGNoZXJDb250cmFjdEFkZHJlc3MgPSBuZXR3b3JrPy5iYXRjaGVyQ29udHJhY3RBZGRyZXNzIGFzIHN0cmluZztcblxuICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKHBhcmFtcy5jb21tb24pIGFzIFRyYW5zYWN0aW9uQnVpbGRlcjtcbiAgICB0eEJ1aWxkZXIuY291bnRlcihiaXRnb0ZlZUFkZHJlc3NOb25jZSk7XG4gICAgdHhCdWlsZGVyLmNvbnRyYWN0KHdhbGxldENvbnRyYWN0QWRkcmVzcyk7XG4gICAgbGV0IHR4RmVlO1xuICAgIGlmIChwYXJhbXMuZWlwMTU1OSkge1xuICAgICAgdHhGZWUgPSB7XG4gICAgICAgIGVpcDE1NTk6IHtcbiAgICAgICAgICBtYXhQcmlvcml0eUZlZVBlckdhczogcGFyYW1zLmVpcDE1NTkubWF4UHJpb3JpdHlGZWVQZXJHYXMsXG4gICAgICAgICAgbWF4RmVlUGVyR2FzOiBwYXJhbXMuZWlwMTU1OS5tYXhGZWVQZXJHYXMsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICB0eEZlZSA9IHsgZmVlOiBnYXNQcmljZS50b1N0cmluZygpIH07XG4gICAgfVxuICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgLi4udHhGZWUsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoKSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHRyYW5zZmVyQnVpbGRlciA9IHR4QnVpbGRlci50cmFuc2ZlcigpIGFzIFRyYW5zZmVyQnVpbGRlcjtcbiAgICBpZiAoIWJhdGNoZXJDb250cmFjdEFkZHJlc3MpIHtcbiAgICAgIHRyYW5zZmVyQnVpbGRlclxuICAgICAgICAuY29pbih0aGlzLnN0YXRpY3NDb2luPy5uYW1lIGFzIHN0cmluZylcbiAgICAgICAgLmFtb3VudChiYXRjaEV4ZWN1dGlvbkluZm8udG90YWxBbW91bnQpXG4gICAgICAgIC5jb250cmFjdFNlcXVlbmNlSWQoc2VxdWVuY2VJZClcbiAgICAgICAgLmV4cGlyYXRpb25UaW1lKHRoaXMuZ2V0RGVmYXVsdEV4cGlyZVRpbWUoKSlcbiAgICAgICAgLnRvKHJlY292ZXJ5RGVzdGluYXRpb24pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAgICAgLmNvaW4odGhpcy5zdGF0aWNzQ29pbj8ubmFtZSBhcyBzdHJpbmcpXG4gICAgICAgIC5hbW91bnQoYmF0Y2hFeGVjdXRpb25JbmZvLnRvdGFsQW1vdW50KVxuICAgICAgICAuY29udHJhY3RTZXF1ZW5jZUlkKHNlcXVlbmNlSWQpXG4gICAgICAgIC5leHBpcmF0aW9uVGltZSh0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCkpXG4gICAgICAgIC50byhiYXRjaGVyQ29udHJhY3RBZGRyZXNzKVxuICAgICAgICAuZGF0YShiYXRjaERhdGEpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgdHJhbnNmZXJCdWlsZGVyLmtleSh1c2VyU2lnbmluZ0tleSk7XG4gICAgfVxuXG4gICAgLy8gSWYgdGhlIGludGVuZGVkIGNoYWluIGlzIGFyYml0cnVtIG9yIG9wdGltaXNtLCB3ZSBuZWVkIHRvIHVzZSB3YWxsZXQgdmVyc2lvbiA0XG4gICAgLy8gc2luY2UgdGhlc2UgY29udHJhY3RzIGNvbnN0cnVjdCBvcGVyYXRpb25IYXNoIGRpZmZlcmVudGx5XG4gICAgaWYgKHBhcmFtcy5pbnRlbmRlZENoYWluICYmIFsnYXJiZXRoJywgJ29wZXRoJ10uaW5jbHVkZXMoY29pbnMuZ2V0KHBhcmFtcy5pbnRlbmRlZENoYWluKS5mYW1pbHkpKSB7XG4gICAgICB0eEJ1aWxkZXIud2FsbGV0VmVyc2lvbig0KTtcbiAgICB9XG5cbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgY29uc3QgcmVzcG9uc2U6IE9mZmxpbmVWYXVsdFR4SW5mbyA9IHtcbiAgICAgIHR4SGV4OiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgICAgdXNlcktleSxcbiAgICAgIGNvaW46IHRoaXMuZ2V0Q2hhaW4oKSxcbiAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgZ2FzTGltaXQsXG4gICAgICByZWNpcGllbnRzOiB0eEluZm8ucmVjaXBpZW50cyxcbiAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogdHgudG9Kc29uKCkudG8sXG4gICAgICBhbW91bnQ6IGJhdGNoRXhlY3V0aW9uSW5mby50b3RhbEFtb3VudCxcbiAgICAgIGJhY2t1cEtleU5vbmNlOiBiaXRnb0ZlZUFkZHJlc3NOb25jZSxcbiAgICAgIGVpcDE1NTk6IHBhcmFtcy5laXAxNTU5LFxuICAgIH07XG4gICAgXy5leHRlbmQocmVzcG9uc2UsIHR4SW5mbyk7XG4gICAgcmVzcG9uc2UubmV4dENvbnRyYWN0U2VxdWVuY2VJZCA9IHJlc3BvbnNlLmNvbnRyYWN0U2VxdWVuY2VJZDtcblxuICAgIGlmIChwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgY29uc3QgaGFsZlNpZ25lZFR4bjogSGFsZlNpZ25lZFRyYW5zYWN0aW9uID0ge1xuICAgICAgICBoYWxmU2lnbmVkOiB7XG4gICAgICAgICAgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgcmVjaXBpZW50czogdHhJbmZvLnJlY2lwaWVudHMsXG4gICAgICAgICAgZXhwaXJlVGltZTogdHhJbmZvLmV4cGlyZVRpbWUsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgXy5leHRlbmQocmVzcG9uc2UsIGhhbGZTaWduZWRUeG4pO1xuXG4gICAgICBjb25zdCBmZWVzVXNlZDogRmVlc1VzZWQgPSB7XG4gICAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgICBnYXNMaW1pdDogb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9JbnQoZ2FzTGltaXQpLnRvRml4ZWQoKSxcbiAgICAgIH07XG4gICAgICByZXNwb25zZVsnZmVlc1VzZWQnXSA9IGZlZXNVc2VkO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyeSBleHBsb3JlciBmb3IgdGhlIGJhbGFuY2Ugb2YgYW4gYWRkcmVzcyBmb3IgYSB0b2tlblxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9rZW5Db250cmFjdEFkZHJlc3MgLSBhZGRyZXNzIHdoZXJlIHRoZSB0b2tlbiBzbWFydCBjb250cmFjdCBpcyBob3N0ZWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHdhbGxldENvbnRyYWN0QWRkcmVzcyAtIGFkZHJlc3Mgb2YgdGhlIHdhbGxldFxuICAgKiBAcmV0dXJucyB7QmlnTnVtYmVyfSB0b2tlbiBiYWxhYW5jZSBpbiBiYXNlIHVuaXRzXG4gICAqL1xuICBhc3luYyBxdWVyeUFkZHJlc3NUb2tlbkJhbGFuY2UodG9rZW5Db250cmFjdEFkZHJlc3M6IHN0cmluZywgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiBzdHJpbmcpOiBQcm9taXNlPGFueT4ge1xuICAgIGlmICghb3B0aW9uYWxEZXBzLmV0aFV0aWwuaXNWYWxpZEFkZHJlc3ModG9rZW5Db250cmFjdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Nhbm5vdCBnZXQgYmFsYW5jZSBmb3IgaW52YWxpZCB0b2tlbiBhZGRyZXNzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9uYWxEZXBzLmV0aFV0aWwuaXNWYWxpZEFkZHJlc3Mod2FsbGV0Q29udHJhY3RBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgZ2V0IHRva2VuIGJhbGFuY2UgZm9yIGludmFsaWQgd2FsbGV0IGFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgbW9kdWxlOiAnYWNjb3VudCcsXG4gICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgY29udHJhY3RhZGRyZXNzOiB0b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgIGFkZHJlc3M6IHdhbGxldENvbnRyYWN0QWRkcmVzcyxcbiAgICAgIHRhZzogJ2xhdGVzdCcsXG4gICAgfSk7XG4gICAgLy8gdGhyb3cgaWYgdGhlIHJlc3VsdCBkb2VzIG5vdCBleGlzdCBvciB0aGUgcmVzdWx0IGlzIG5vdCBhIHZhbGlkIG51bWJlclxuICAgIGlmICghcmVzdWx0IHx8ICFyZXN1bHQucmVzdWx0IHx8IGlzTmFOKHJlc3VsdC5yZXN1bHQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBDb3VsZCBub3Qgb2J0YWluIHRva2VuIGFkZHJlc3MgYmFsYW5jZSBmb3IgJHt0b2tlbkNvbnRyYWN0QWRkcmVzc30gZnJvbSBFdGhlcnNjYW4sIGdvdDogJHtyZXN1bHQucmVzdWx0fWBcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocmVzdWx0LnJlc3VsdCwgMTApO1xuICB9XG5cbiAgYXN5bmMgcmVjb3ZlckV0aExpa2VUb2tlbmZvckV2bUJhc2VkUmVjb3ZlcnkoXG4gICAgcGFyYW1zOiBSZWNvdmVyT3B0aW9ucyxcbiAgICBiaXRnb0ZlZUFkZHJlc3NOb25jZTogbnVtYmVyLFxuICAgIGdhc0xpbWl0LFxuICAgIGdhc1ByaWNlLFxuICAgIHVzZXJLZXksXG4gICAgdXNlclNpZ25pbmdLZXlcbiAgKSB7XG4gICAgLy8gZ2V0IHRva2VuIGJhbGFuY2Ugb2Ygd2FsbGV0XG4gICAgY29uc3QgdHhBbW91bnQgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc1Rva2VuQmFsYW5jZShcbiAgICAgIHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcyBhcyBzdHJpbmcsXG4gICAgICBwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzXG4gICAgKTtcblxuICAgIC8vIGJ1aWxkIHJlY2lwaWVudHMgb2JqZWN0XG4gICAgY29uc3QgcmVjaXBpZW50czogUmVjaXBpZW50W10gPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgICBhbW91bnQ6IG5ldyBCaWdOdW1iZXIodHhBbW91bnQpLnRvRml4ZWQoKSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIC8vIEdldCBzZXF1ZW5jZSBJRCB1c2luZyBjb250cmFjdCBjYWxsXG4gICAgLy8gd2UgbmVlZCB0byB3YWl0IGJldHdlZW4gbWFraW5nIHR3byBleHBsb3JlciBhcGkgY2FsbHMgdG8gYXZvaWQgZ2V0dGluZyBiYW5uZWRcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxMDAwKSk7XG4gICAgY29uc3Qgc2VxdWVuY2VJZCA9IGF3YWl0IHRoaXMucXVlcnlTZXF1ZW5jZUlkKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MpO1xuXG4gICAgY29uc3QgdHhJbmZvID0ge1xuICAgICAgcmVjaXBpZW50czogcmVjaXBpZW50cyxcbiAgICAgIGV4cGlyZVRpbWU6IHRoaXMuZ2V0RGVmYXVsdEV4cGlyZVRpbWUoKSxcbiAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogc2VxdWVuY2VJZCxcbiAgICAgIGdhc0xpbWl0OiBnYXNMaW1pdC50b1N0cmluZygxMCksXG4gICAgICBpc0V2bUJhc2VkQ3Jvc3NDaGFpblJlY292ZXJ5OiB0cnVlLFxuICAgIH07XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgdHhCdWlsZGVyLmNvdW50ZXIoYml0Z29GZWVBZGRyZXNzTm9uY2UpO1xuICAgIHR4QnVpbGRlci5jb250cmFjdChwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzIGFzIHN0cmluZyk7XG4gICAgbGV0IHR4RmVlO1xuICAgIGlmIChwYXJhbXMuZWlwMTU1OSkge1xuICAgICAgdHhGZWUgPSB7XG4gICAgICAgIGVpcDE1NTk6IHtcbiAgICAgICAgICBtYXhQcmlvcml0eUZlZVBlckdhczogcGFyYW1zLmVpcDE1NTkubWF4UHJpb3JpdHlGZWVQZXJHYXMsXG4gICAgICAgICAgbWF4RmVlUGVyR2FzOiBwYXJhbXMuZWlwMTU1OS5tYXhGZWVQZXJHYXMsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICB0eEZlZSA9IHsgZmVlOiBnYXNQcmljZS50b1N0cmluZygpIH07XG4gICAgfVxuICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgLi4udHhGZWUsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoKSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHRyYW5zZmVyQnVpbGRlciA9IHR4QnVpbGRlci50cmFuc2ZlcigpIGFzIFRyYW5zZmVyQnVpbGRlcjtcblxuICAgIGNvbnN0IG5ldHdvcmsgPSB0aGlzLmdldE5ldHdvcmsoKTtcbiAgICBjb25zdCB0b2tlbiA9IGdldFRva2VuKFxuICAgICAgcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzIGFzIHN0cmluZyxcbiAgICAgIG5ldHdvcmsgYXMgRXRoTGlrZU5ldHdvcmssXG4gICAgICB0aGlzLnN0YXRpY3NDb2luPy5mYW1pbHkgYXMgc3RyaW5nXG4gICAgKT8ubmFtZSBhcyBzdHJpbmc7XG5cbiAgICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAgIC5hbW91bnQodHhBbW91bnQpXG4gICAgICAuY29udHJhY3RTZXF1ZW5jZUlkKHNlcXVlbmNlSWQpXG4gICAgICAuZXhwaXJhdGlvblRpbWUodGhpcy5nZXREZWZhdWx0RXhwaXJlVGltZSgpKVxuICAgICAgLnRvKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKTtcblxuICAgIGlmICh0b2tlbikge1xuICAgICAgdHJhbnNmZXJCdWlsZGVyLmNvaW4odG9rZW4pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAgICAgLmNvaW4odGhpcy5zdGF0aWNzQ29pbj8ubmFtZSBhcyBzdHJpbmcpXG4gICAgICAgIC50b2tlbkNvbnRyYWN0QWRkcmVzcyhwYXJhbXMudG9rZW5Db250cmFjdEFkZHJlc3MgYXMgc3RyaW5nKTtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLndhbGxldFBhc3NwaHJhc2UpIHtcbiAgICAgIHR4QnVpbGRlci50cmFuc2ZlcigpLmtleSh1c2VyU2lnbmluZ0tleSk7XG4gICAgfVxuICAgIC8vIElmIHRoZSBpbnRlbmRlZCBjaGFpbiBpcyBhcmJpdHJ1bSBvciBvcHRpbWlzbSwgd2UgbmVlZCB0byB1c2Ugd2FsbGV0IHZlcnNpb24gNFxuICAgIC8vIHNpbmNlIHRoZXNlIGNvbnRyYWN0cyBjb25zdHJ1Y3Qgb3BlcmF0aW9uSGFzaCBkaWZmZXJlbnRseVxuICAgIGlmIChwYXJhbXMuaW50ZW5kZWRDaGFpbiAmJiBbJ2FyYmV0aCcsICdvcGV0aCddLmluY2x1ZGVzKGNvaW5zLmdldChwYXJhbXMuaW50ZW5kZWRDaGFpbikuZmFtaWx5KSkge1xuICAgICAgdHhCdWlsZGVyLndhbGxldFZlcnNpb24oNCk7XG4gICAgfVxuXG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcblxuICAgIGNvbnN0IHJlc3BvbnNlOiBPZmZsaW5lVmF1bHRUeEluZm8gPSB7XG4gICAgICB0eEhleDogdHgudG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgIHVzZXJLZXksXG4gICAgICBjb2luOiB0b2tlbiA/IHRva2VuIDogdGhpcy5nZXRDaGFpbigpLFxuICAgICAgZ2FzUHJpY2U6IG9wdGlvbmFsRGVwcy5ldGhVdGlsLmJ1ZmZlclRvSW50KGdhc1ByaWNlKS50b0ZpeGVkKCksXG4gICAgICBnYXNMaW1pdCxcbiAgICAgIHJlY2lwaWVudHM6IHR4SW5mby5yZWNpcGllbnRzLFxuICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiB0eC50b0pzb24oKS50byxcbiAgICAgIGFtb3VudDogdHhBbW91bnQudG9TdHJpbmcoKSxcbiAgICAgIGJhY2t1cEtleU5vbmNlOiBiaXRnb0ZlZUFkZHJlc3NOb25jZSxcbiAgICAgIGVpcDE1NTk6IHBhcmFtcy5laXAxNTU5LFxuICAgIH07XG4gICAgXy5leHRlbmQocmVzcG9uc2UsIHR4SW5mbyk7XG4gICAgcmVzcG9uc2UubmV4dENvbnRyYWN0U2VxdWVuY2VJZCA9IHJlc3BvbnNlLmNvbnRyYWN0U2VxdWVuY2VJZDtcblxuICAgIGlmIChwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgY29uc3QgaGFsZlNpZ25lZFR4bjogSGFsZlNpZ25lZFRyYW5zYWN0aW9uID0ge1xuICAgICAgICBoYWxmU2lnbmVkOiB7XG4gICAgICAgICAgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgcmVjaXBpZW50czogdHhJbmZvLnJlY2lwaWVudHMsXG4gICAgICAgICAgZXhwaXJlVGltZTogdHhJbmZvLmV4cGlyZVRpbWUsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgXy5leHRlbmQocmVzcG9uc2UsIGhhbGZTaWduZWRUeG4pO1xuXG4gICAgICBjb25zdCBmZWVzVXNlZDogRmVlc1VzZWQgPSB7XG4gICAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgICBnYXNMaW1pdDogb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9JbnQoZ2FzTGltaXQpLnRvRml4ZWQoKSxcbiAgICAgIH07XG4gICAgICByZXNwb25zZVsnZmVlc1VzZWQnXSA9IGZlZXNVc2VkO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBldm0gYmFzZWQgY3Jvc3MgY2hhaW4gcmVjb3ZlcnkgcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMge1JlY292ZXJPcHRpb25zfVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHZhbGlkYXRlRXZtQmFzZWRSZWNvdmVyeVBhcmFtcyhwYXJhbXM6IFJlY292ZXJPcHRpb25zKTogdm9pZCB7XG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLmJpdGdvRmVlQWRkcmVzcykgfHwgIXRoaXMuaXNWYWxpZEFkZHJlc3MocGFyYW1zLmJpdGdvRmVlQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBiaXRnb0ZlZUFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzKSB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHdhbGxldENvbnRyYWN0QWRkcmVzcycpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCByZWNvdmVyeURlc3RpbmF0aW9uJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0eXBlcywgdmFsdWVzLCBhbmQgdG90YWwgYW1vdW50IGluIHdlaSB0byBzZW5kIGluIGEgYmF0Y2ggdHJhbnNhY3Rpb24sIHVzaW5nIHRoZSBtZXRob2Qgc2lnbmF0dXJlXG4gICAqIGBkaXN0cmlidXRlQmF0Y2goYWRkcmVzc1tdLCB1aW50MjU2W10pYFxuICAgKiBAcGFyYW0ge1JlY2lwaWVudFtdfSByZWNpcGllbnRzIC0gdHJhbnNhY3Rpb24gcmVjaXBpZW50c1xuICAgKiBAcmV0dXJucyB7R2V0QmF0Y2hFeGVjdXRpb25JbmZvUlR9IGluZm9ybWF0aW9uIG5lZWRlZCB0byBleGVjdXRlIHRoZSBiYXRjaCB0cmFuc2FjdGlvblxuICAgKi9cbiAgZ2V0QmF0Y2hFeGVjdXRpb25JbmZvKHJlY2lwaWVudHM6IFJlY2lwaWVudFtdKTogR2V0QmF0Y2hFeGVjdXRpb25JbmZvUlQge1xuICAgIGNvbnN0IGFkZHJlc3Nlczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBhbW91bnRzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGxldCBzdW0gPSBuZXcgQmlnTnVtYmVyKCcwJyk7XG4gICAgXy5mb3JFYWNoKHJlY2lwaWVudHMsICh7IGFkZHJlc3MsIGFtb3VudCB9KSA9PiB7XG4gICAgICBhZGRyZXNzZXMucHVzaChhZGRyZXNzKTtcbiAgICAgIGFtb3VudHMucHVzaChhbW91bnQgYXMgc3RyaW5nKTtcbiAgICAgIHN1bSA9IHN1bS5wbHVzKGFtb3VudCk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdmFsdWVzOiBbYWRkcmVzc2VzLCBhbW91bnRzXSxcbiAgICAgIHRvdGFsQW1vdW50OiBzdW0udG9GaXhlZCgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBkYXRhIHJlcXVpcmVkIHRvIG1ha2UgYW4gRVRIIGZ1bmN0aW9uIGNhbGwgZGVmaW5lZCBieSB0aGUgZ2l2ZW4gdHlwZXMgYW5kIHZhbHVlc1xuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZnVuY3Rpb25OYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uIGJlaW5nIGNhbGxlZCwgZS5nLiB0cmFuc2ZlclxuICAgKiBAcGFyYW0gdHlwZXMgVGhlIHR5cGVzIG9mIHRoZSBmdW5jdGlvbiBjYWxsIGluIG9yZGVyXG4gICAqIEBwYXJhbSB2YWx1ZXMgVGhlIHZhbHVlcyBvZiB0aGUgZnVuY3Rpb24gY2FsbCBpbiBvcmRlclxuICAgKiBAcmV0dXJuIHtCdWZmZXJ9IFRoZSBjb21iaW5lZCBkYXRhIGZvciB0aGUgZnVuY3Rpb24gY2FsbFxuICAgKi9cbiAgZ2V0TWV0aG9kQ2FsbERhdGEgPSAoZnVuY3Rpb25OYW1lLCB0eXBlcywgdmFsdWVzKSA9PiB7XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW1xuICAgICAgLy8gZnVuY3Rpb24gc2lnbmF0dXJlXG4gICAgICBvcHRpb25hbERlcHMuZXRoQWJpLm1ldGhvZElEKGZ1bmN0aW9uTmFtZSwgdHlwZXMpLFxuICAgICAgLy8gZnVuY3Rpb24gYXJndW1lbnRzXG4gICAgICBvcHRpb25hbERlcHMuZXRoQWJpLnJhd0VuY29kZSh0eXBlcywgdmFsdWVzKSxcbiAgICBdKTtcbiAgfTtcblxuICAvKipcbiAgICogQnVpbGQgYXJndW1lbnRzIHRvIGNhbGwgdGhlIHNlbmQgbWV0aG9kIG9uIHRoZSB3YWxsZXQgY29udHJhY3RcbiAgICogQHBhcmFtIHR4SW5mb1xuICAgKi9cbiAgZ2V0U2VuZE1ldGhvZEFyZ3ModHhJbmZvOiBHZXRTZW5kTWV0aG9kQXJnc09wdGlvbnMpOiBTZW5kTWV0aG9kQXJnc1tdIHtcbiAgICAvLyBNZXRob2Qgc2lnbmF0dXJlIGlzXG4gICAgLy8gc2VuZE11bHRpU2lnKGFkZHJlc3MgdG9BZGRyZXNzLCB1aW50IHZhbHVlLCBieXRlcyBkYXRhLCB1aW50IGV4cGlyZVRpbWUsIHVpbnQgc2VxdWVuY2VJZCwgYnl0ZXMgc2lnbmF0dXJlKVxuICAgIHJldHVybiBbXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICd0b0FkZHJlc3MnLFxuICAgICAgICB0eXBlOiAnYWRkcmVzcycsXG4gICAgICAgIHZhbHVlOiB0eEluZm8ucmVjaXBpZW50LmFkZHJlc3MsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAndmFsdWUnLFxuICAgICAgICB0eXBlOiAndWludCcsXG4gICAgICAgIHZhbHVlOiB0eEluZm8ucmVjaXBpZW50LmFtb3VudCxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdkYXRhJyxcbiAgICAgICAgdHlwZTogJ2J5dGVzJyxcbiAgICAgICAgdmFsdWU6IG9wdGlvbmFsRGVwcy5ldGhVdGlsLnRvQnVmZmVyKG9wdGlvbmFsRGVwcy5ldGhVdGlsLmFkZEhleFByZWZpeCh0eEluZm8ucmVjaXBpZW50LmRhdGEgfHwgJycpKSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdleHBpcmVUaW1lJyxcbiAgICAgICAgdHlwZTogJ3VpbnQnLFxuICAgICAgICB2YWx1ZTogdHhJbmZvLmV4cGlyZVRpbWUsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAnc2VxdWVuY2VJZCcsXG4gICAgICAgIHR5cGU6ICd1aW50JyxcbiAgICAgICAgdmFsdWU6IHR4SW5mby5jb250cmFjdFNlcXVlbmNlSWQsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAnc2lnbmF0dXJlJyxcbiAgICAgICAgdHlwZTogJ2J5dGVzJyxcbiAgICAgICAgdmFsdWU6IG9wdGlvbmFsRGVwcy5ldGhVdGlsLnRvQnVmZmVyKG9wdGlvbmFsRGVwcy5ldGhVdGlsLmFkZEhleFByZWZpeCh0eEluZm8uc2lnbmF0dXJlKSksXG4gICAgICB9LFxuICAgIF07XG4gIH1cblxuICAvKipcbiAgICogUmVjb3ZlcnMgYSB0eCB3aXRoIFRTUyBrZXkgc2hhcmVzXG4gICAqIHNhbWUgZXhwZWN0ZWQgYXJndW1lbnRzIGFzIHJlY292ZXIgbWV0aG9kLCBidXQgd2l0aCBUU1Mga2V5IHNoYXJlc1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHJlY292ZXJUU1MocGFyYW1zOiBSZWNvdmVyT3B0aW9ucyk6IFByb21pc2U8UmVjb3ZlcnlJbmZvIHwgT2ZmbGluZVZhdWx0VHhJbmZvPiB7XG4gICAgdGhpcy52YWxpZGF0ZVJlY292ZXJ5UGFyYW1zKHBhcmFtcyk7XG4gICAgLy8gQ2xlYW4gdXAgd2hpdGVzcGFjZSBmcm9tIGVudGVyZWQgdmFsdWVzXG4gICAgY29uc3QgdXNlclB1YmxpY09yUHJpdmF0ZUtleVNoYXJlID0gcGFyYW1zLnVzZXJLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSA9IHBhcmFtcy5iYWNrdXBLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcblxuICAgIGNvbnN0IGdhc0xpbWl0ID0gbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHRoaXMuc2V0R2FzTGltaXQocGFyYW1zLmdhc0xpbWl0KSk7XG4gICAgY29uc3QgZ2FzUHJpY2UgPSBwYXJhbXMuZWlwMTU1OVxuICAgICAgPyBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocGFyYW1zLmVpcDE1NTkubWF4RmVlUGVyR2FzKVxuICAgICAgOiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4odGhpcy5zZXRHYXNQcmljZShwYXJhbXMuZ2FzUHJpY2UpKTtcblxuICAgIGlmIChcbiAgICAgIGdldElzVW5zaWduZWRTd2VlcCh7XG4gICAgICAgIHVzZXJLZXk6IHVzZXJQdWJsaWNPclByaXZhdGVLZXlTaGFyZSxcbiAgICAgICAgYmFja3VwS2V5OiBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSxcbiAgICAgICAgaXNUc3M6IHBhcmFtcy5pc1RzcyxcbiAgICAgIH0pXG4gICAgKSB7XG4gICAgICBjb25zdCBiYWNrdXBLZXlQYWlyID0gbmV3IEtleVBhaXJMaWIoeyBwdWI6IGJhY2t1cFByaXZhdGVPclB1YmxpY0tleVNoYXJlIH0pO1xuICAgICAgY29uc3QgYmFzZUFkZHJlc3MgPSBiYWNrdXBLZXlQYWlyLmdldEFkZHJlc3MoKTtcbiAgICAgIGNvbnN0IHsgdHhJbmZvLCB0eCwgbm9uY2UgfSA9IGF3YWl0IHRoaXMuYnVpbGRUc3NSZWNvdmVyeVR4bihiYXNlQWRkcmVzcywgZ2FzUHJpY2UsIGdhc0xpbWl0LCBwYXJhbXMpO1xuICAgICAgcmV0dXJuIHRoaXMuZm9ybWF0Rm9yT2ZmbGluZVZhdWx0VFNTKFxuICAgICAgICB0eEluZm8sXG4gICAgICAgIHR4LFxuICAgICAgICB1c2VyUHVibGljT3JQcml2YXRlS2V5U2hhcmUsXG4gICAgICAgIGJhY2t1cFByaXZhdGVPclB1YmxpY0tleVNoYXJlLFxuICAgICAgICBnYXNQcmljZSxcbiAgICAgICAgZ2FzTGltaXQsXG4gICAgICAgIG5vbmNlLFxuICAgICAgICBwYXJhbXMuZWlwMTU1OSxcbiAgICAgICAgcGFyYW1zLnJlcGxheVByb3RlY3Rpb25PcHRpb25zXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBpc0dHMThTaWduaW5nTWF0ZXJpYWwgPSB0aGlzLmlzR0cxOFNpZ25pbmdNYXRlcmlhbCh1c2VyUHVibGljT3JQcml2YXRlS2V5U2hhcmUsIHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKTtcbiAgICAgIGxldCBzaWduYXR1cmU6IEVDRFNBTWV0aG9kVHlwZXMuU2lnbmF0dXJlO1xuICAgICAgbGV0IHVuc2lnbmVkVHg6IEV0aExpa2VUeExpYi5UcmFuc2FjdGlvbiB8IEV0aExpa2VUeExpYi5GZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb247XG4gICAgICBpZiAoaXNHRzE4U2lnbmluZ01hdGVyaWFsKSB7XG4gICAgICAgIGNvbnN0IFt1c2VyS2V5Q29tYmluZWQsIGJhY2t1cEtleUNvbWJpbmVkXSA9IHRoaXMuZ2V0S2V5Q29tYmluZWRGcm9tVHNzS2V5U2hhcmVzKFxuICAgICAgICAgIHVzZXJQdWJsaWNPclByaXZhdGVLZXlTaGFyZSxcbiAgICAgICAgICBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSxcbiAgICAgICAgICBwYXJhbXMud2FsbGV0UGFzc3BocmFzZVxuICAgICAgICApO1xuICAgICAgICBjb25zdCBiYWNrdXBLZXlQYWlyID0gbmV3IEtleVBhaXJMaWIoeyBwdWI6IGJhY2t1cEtleUNvbWJpbmVkLnhTaGFyZS55IH0pO1xuICAgICAgICBjb25zdCBiYXNlQWRkcmVzcyA9IGJhY2t1cEtleVBhaXIuZ2V0QWRkcmVzcygpO1xuXG4gICAgICAgIHVuc2lnbmVkVHggPSAoYXdhaXQgdGhpcy5idWlsZFRzc1JlY292ZXJ5VHhuKGJhc2VBZGRyZXNzLCBnYXNQcmljZSwgZ2FzTGltaXQsIHBhcmFtcykpLnR4O1xuXG4gICAgICAgIHNpZ25hdHVyZSA9IGF3YWl0IHRoaXMuc2lnblJlY292ZXJ5VFNTKFxuICAgICAgICAgIHVzZXJLZXlDb21iaW5lZCxcbiAgICAgICAgICBiYWNrdXBLZXlDb21iaW5lZCxcbiAgICAgICAgICB1bnNpZ25lZFR4LmdldE1lc3NhZ2VUb1NpZ24oZmFsc2UpLnRvU3RyaW5nKCdoZXgnKVxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgeyB1c2VyS2V5U2hhcmUsIGJhY2t1cEtleVNoYXJlLCBjb21tb25LZXlDaGFpbiwgYmFzZUFkZHJlc3MgfSA9IGF3YWl0IHRoaXMuZ2V0TXBjVjJSZWNvdmVyeUtleVNoYXJlcyhcbiAgICAgICAgICB1c2VyUHVibGljT3JQcml2YXRlS2V5U2hhcmUsXG4gICAgICAgICAgYmFja3VwUHJpdmF0ZU9yUHVibGljS2V5U2hhcmUsXG4gICAgICAgICAgcGFyYW1zLndhbGxldFBhc3NwaHJhc2VcbiAgICAgICAgKTtcblxuICAgICAgICB1bnNpZ25lZFR4ID0gKGF3YWl0IHRoaXMuYnVpbGRUc3NSZWNvdmVyeVR4bihiYXNlQWRkcmVzcywgZ2FzUHJpY2UsIGdhc0xpbWl0LCBwYXJhbXMpKS50eDtcblxuICAgICAgICBzaWduYXR1cmUgPSBhd2FpdCBBYnN0cmFjdEV0aExpa2VOZXdDb2lucy5zaWduUmVjb3ZlcnlNcGNWMihcbiAgICAgICAgICB1bnNpZ25lZFR4LFxuICAgICAgICAgIHVzZXJLZXlTaGFyZSxcbiAgICAgICAgICBiYWNrdXBLZXlTaGFyZSxcbiAgICAgICAgICBjb21tb25LZXlDaGFpblxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBldGhDb21tbW9uID0gQWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuZ2V0RXRoTGlrZUNvbW1vbihwYXJhbXMuZWlwMTU1OSwgcGFyYW1zLnJlcGxheVByb3RlY3Rpb25PcHRpb25zKTtcbiAgICAgIGNvbnN0IHNpZ25lZFR4ID0gdGhpcy5nZXRTaWduZWRUeEZyb21TaWduYXR1cmUoZXRoQ29tbW1vbiwgdW5zaWduZWRUeCwgc2lnbmF0dXJlKTtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaWQ6IGFkZEhleFByZWZpeChzaWduZWRUeC5oYXNoKCkudG9TdHJpbmcoJ2hleCcpKSxcbiAgICAgICAgdHg6IGFkZEhleFByZWZpeChzaWduZWRUeC5zZXJpYWxpemUoKS50b1N0cmluZygnaGV4JykpLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBhc3luYyBzaWduUmVjb3ZlcnlNcGNWMihcbiAgICB0eDogRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbiB8IEV0aExpa2VUeExpYi5UcmFuc2FjdGlvbixcbiAgICB1c2VyS2V5U2hhcmU6IEJ1ZmZlcixcbiAgICBiYWNrdXBLZXlTaGFyZTogQnVmZmVyLFxuICAgIGNvbW1vbktleUNoYWluOiBzdHJpbmdcbiAgKSB7XG4gICAgY29uc3QgbWVzc2FnZUhhc2ggPSB0eC5nZXRNZXNzYWdlVG9TaWduKHRydWUpO1xuICAgIGNvbnN0IHVzZXJEc2cgPSBuZXcgRGtsc0RzZy5Ec2codXNlcktleVNoYXJlLCAwLCAnbS8wJywgbWVzc2FnZUhhc2gpO1xuICAgIGNvbnN0IGJhY2t1cERzZyA9IG5ldyBEa2xzRHNnLkRzZyhiYWNrdXBLZXlTaGFyZSwgMSwgJ20vMCcsIG1lc3NhZ2VIYXNoKTtcblxuICAgIGNvbnN0IHNpZ25hdHVyZVN0cmluZyA9IERrbHNVdGlscy52ZXJpZnlBbmRDb252ZXJ0RGtsc1NpZ25hdHVyZShcbiAgICAgIG1lc3NhZ2VIYXNoLFxuICAgICAgKGF3YWl0IERrbHNVdGlscy5leGVjdXRlVGlsbFJvdW5kKDUsIHVzZXJEc2csIGJhY2t1cERzZykpIGFzIERrbHNUeXBlcy5EZXNlcmlhbGl6ZWREa2xzU2lnbmF0dXJlLFxuICAgICAgY29tbW9uS2V5Q2hhaW4sXG4gICAgICAnbS8wJyxcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIGZhbHNlXG4gICAgKTtcbiAgICBjb25zdCBzaWdQYXJ0cyA9IHNpZ25hdHVyZVN0cmluZy5zcGxpdCgnOicpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlY2lkOiBwYXJzZUludChzaWdQYXJ0c1swXSwgMTApLFxuICAgICAgcjogc2lnUGFydHNbMV0sXG4gICAgICBzOiBzaWdQYXJ0c1syXSxcbiAgICAgIHk6IHNpZ1BhcnRzWzNdLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGdldE1wY1YyUmVjb3ZlcnlLZXlTaGFyZXMoXG4gICAgdXNlclB1YmxpY09yUHJpdmF0ZUtleVNoYXJlOiBzdHJpbmcsXG4gICAgYmFja3VwUHJpdmF0ZU9yUHVibGljS2V5U2hhcmU6IHN0cmluZyxcbiAgICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nXG4gICkge1xuICAgIGNvbnN0IHVzZXJDb21wcmVzc2VkUHJ2ID0gQnVmZmVyLmZyb20oXG4gICAgICB0aGlzLmJpdGdvLmRlY3J5cHQoe1xuICAgICAgICBpbnB1dDogdXNlclB1YmxpY09yUHJpdmF0ZUtleVNoYXJlLFxuICAgICAgICBwYXNzd29yZDogd2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIH0pLFxuICAgICAgJ2Jhc2U2NCdcbiAgICApO1xuICAgIGNvbnN0IGJha2N1cENvbXByZXNzZWRQcnYgPSBCdWZmZXIuZnJvbShcbiAgICAgIHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgIGlucHV0OiBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSxcbiAgICAgICAgcGFzc3dvcmQ6IHdhbGxldFBhc3NwaHJhc2UsXG4gICAgICB9KSxcbiAgICAgICdiYXNlNjQnXG4gICAgKTtcblxuICAgIGNvbnN0IHVzZXJQcnZKU09OOiBEa2xzVHlwZXMuUmVkdWNlZEtleVNoYXJlID0gRGtsc1R5cGVzLmdldERlY29kZWRSZWR1Y2VkS2V5U2hhcmUodXNlckNvbXByZXNzZWRQcnYpO1xuICAgIGNvbnN0IGJhY2t1cFBydkpTT046IERrbHNUeXBlcy5SZWR1Y2VkS2V5U2hhcmUgPSBEa2xzVHlwZXMuZ2V0RGVjb2RlZFJlZHVjZWRLZXlTaGFyZShiYWtjdXBDb21wcmVzc2VkUHJ2KTtcbiAgICBjb25zdCB1c2VyS2V5UmV0cm9maXQ6IERrbHNUeXBlcy5SZXRyb2ZpdERhdGEgPSB7XG4gICAgICB4U2hhcmU6IHtcbiAgICAgICAgeDogQnVmZmVyLmZyb20odXNlclBydkpTT04ucHJ2KS50b1N0cmluZygnaGV4JyksXG4gICAgICAgIHk6IEJ1ZmZlci5mcm9tKHVzZXJQcnZKU09OLnB1YikudG9TdHJpbmcoJ2hleCcpLFxuICAgICAgICBjaGFpbmNvZGU6IEJ1ZmZlci5mcm9tKHVzZXJQcnZKU09OLnJvb3RDaGFpbkNvZGUpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgIH0sXG4gICAgICB4aUxpc3Q6IHVzZXJQcnZKU09OLnhMaXN0LnNsaWNlKDAsIDIpLFxuICAgIH07XG4gICAgY29uc3QgYmFja3VwS2V5UmV0cm9maXQ6IERrbHNUeXBlcy5SZXRyb2ZpdERhdGEgPSB7XG4gICAgICB4U2hhcmU6IHtcbiAgICAgICAgeDogQnVmZmVyLmZyb20oYmFja3VwUHJ2SlNPTi5wcnYpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgICAgeTogQnVmZmVyLmZyb20oYmFja3VwUHJ2SlNPTi5wdWIpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgICAgY2hhaW5jb2RlOiBCdWZmZXIuZnJvbShiYWNrdXBQcnZKU09OLnJvb3RDaGFpbkNvZGUpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgIH0sXG4gICAgICB4aUxpc3Q6IGJhY2t1cFBydkpTT04ueExpc3Quc2xpY2UoMCwgMiksXG4gICAgfTtcbiAgICBjb25zdCBbdXNlciwgYmFja3VwXSA9IGF3YWl0IERrbHNVdGlscy5nZW5lcmF0ZTJvZjJLZXlTaGFyZXModXNlcktleVJldHJvZml0LCBiYWNrdXBLZXlSZXRyb2ZpdCk7XG4gICAgY29uc3QgdXNlcktleVNoYXJlID0gdXNlci5nZXRLZXlTaGFyZSgpO1xuICAgIGNvbnN0IGJhY2t1cEtleVNoYXJlID0gYmFja3VwLmdldEtleVNoYXJlKCk7XG4gICAgY29uc3QgY29tbW9uS2V5Q2hhaW4gPSBEa2xzVHlwZXMuZ2V0Q29tbW9uS2V5Y2hhaW4odXNlcktleVNoYXJlKTtcbiAgICBjb25zdCBNUEMgPSBuZXcgRWNkc2EoKTtcbiAgICBjb25zdCBkZXJpdmVkQ29tbW9uS2V5Q2hhaW4gPSBNUEMuZGVyaXZlVW5oYXJkZW5lZChjb21tb25LZXlDaGFpbiwgJ20nKTtcbiAgICBjb25zdCBiYWNrdXBLZXlQYWlyID0gbmV3IEtleVBhaXJMaWIoeyBwdWI6IGRlcml2ZWRDb21tb25LZXlDaGFpbi5zbGljZSgwLCA2NikgfSk7XG4gICAgY29uc3QgYmFzZUFkZHJlc3MgPSBiYWNrdXBLZXlQYWlyLmdldEFkZHJlc3MoKTtcbiAgICByZXR1cm4geyB1c2VyS2V5U2hhcmUsIGJhY2t1cEtleVNoYXJlLCBjb21tb25LZXlDaGFpbiwgYmFzZUFkZHJlc3MgfTtcbiAgfVxuXG4gIHByaXZhdGUgaXNHRzE4U2lnbmluZ01hdGVyaWFsKGtleVNoYXJlOiBzdHJpbmcsIHdhbGxldFBhc3NwaHJhc2U6IHN0cmluZyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHBydiA9IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICBpbnB1dDoga2V5U2hhcmUsXG4gICAgICBwYXNzd29yZDogd2FsbGV0UGFzc3BocmFzZSxcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc2lnbmluZ01hdGVyaWFsID0gSlNPTi5wYXJzZShwcnYpO1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgc2lnbmluZ01hdGVyaWFsLnBTaGFyZSAmJlxuICAgICAgICBzaWduaW5nTWF0ZXJpYWwuYml0Z29OU2hhcmUgJiZcbiAgICAgICAgKHNpZ25pbmdNYXRlcmlhbC51c2VyTlNoYXJlIHx8IHNpZ25pbmdNYXRlcmlhbC5iYWNrdXBOU2hhcmUpXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBidWlsZFRzc1JlY292ZXJ5VHhuKGJhc2VBZGRyZXNzOiBzdHJpbmcsIGdhc1ByaWNlOiBhbnksIGdhc0xpbWl0OiBhbnksIHBhcmFtczogUmVjb3Zlck9wdGlvbnMpIHtcbiAgICBjb25zdCBub25jZSA9IGF3YWl0IHRoaXMuZ2V0QWRkcmVzc05vbmNlKGJhc2VBZGRyZXNzKTtcbiAgICBjb25zdCB0eEFtb3VudCA9IGF3YWl0IHRoaXMudmFsaWRhdGVCYWxhbmNlQW5kR2V0VHhBbW91bnQoYmFzZUFkZHJlc3MsIGdhc1ByaWNlLCBnYXNMaW1pdCk7XG4gICAgY29uc3QgcmVjaXBpZW50cyA9IFtcbiAgICAgIHtcbiAgICAgICAgYWRkcmVzczogcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24sXG4gICAgICAgIGFtb3VudDogdHhBbW91bnQudG9TdHJpbmcoMTApLFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgY29uc3QgdHhJbmZvID0ge1xuICAgICAgcmVjaXBpZW50OiByZWNpcGllbnRzWzBdLFxuICAgICAgZXhwaXJlVGltZTogdGhpcy5nZXREZWZhdWx0RXhwaXJlVGltZSgpLFxuICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LnRvU3RyaW5nKDEwKSxcbiAgICB9O1xuXG4gICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICB0bzogcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24sXG4gICAgICBub25jZTogbm9uY2UsXG4gICAgICB2YWx1ZTogdHhBbW91bnQsXG4gICAgICBnYXNQcmljZTogZ2FzUHJpY2UsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQsXG4gICAgICBkYXRhOiBCdWZmZXIuZnJvbSgnMHgnKSxcbiAgICAgIGVpcDE1NTk6IHBhcmFtcy5laXAxNTU5LFxuICAgICAgcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM6IHBhcmFtcy5yZXBsYXlQcm90ZWN0aW9uT3B0aW9ucyxcbiAgICB9O1xuXG4gICAgY29uc3QgdHggPSBBYnN0cmFjdEV0aExpa2VOZXdDb2lucy5idWlsZFRyYW5zYWN0aW9uKHR4UGFyYW1zKTtcbiAgICByZXR1cm4geyB0eEluZm8sIHR4LCBub25jZSB9O1xuICB9XG5cbiAgYXN5bmMgdmFsaWRhdGVCYWxhbmNlQW5kR2V0VHhBbW91bnQoYmFzZUFkZHJlc3M6IHN0cmluZywgZ2FzUHJpY2U6IEJOLCBnYXNMaW1pdDogQk4pIHtcbiAgICBjb25zdCBiYXNlQWRkcmVzc0JhbGFuY2UgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc0JhbGFuY2UoYmFzZUFkZHJlc3MpO1xuXG4gICAgY29uc3QgdG90YWxHYXNOZWVkZWQgPSBnYXNQcmljZS5tdWwoZ2FzTGltaXQpO1xuICAgIGNvbnN0IHdlaVRvR3dlaSA9IG5ldyBCTigxMCAqKiA5KTtcbiAgICBpZiAoYmFzZUFkZHJlc3NCYWxhbmNlLmx0KHRvdGFsR2FzTmVlZGVkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgQmFja3VwIGtleSBhZGRyZXNzICR7YmFzZUFkZHJlc3N9IGhhcyBiYWxhbmNlICR7YmFzZUFkZHJlc3NCYWxhbmNlLmRpdih3ZWlUb0d3ZWkpLnRvU3RyaW5nKCl9IEd3ZWkuYCArXG4gICAgICAgICAgYFRoaXMgYWRkcmVzcyBtdXN0IGhhdmUgYSBiYWxhbmNlIG9mIGF0IGxlYXN0ICR7dG90YWxHYXNOZWVkZWQuZGl2KHdlaVRvR3dlaSkudG9TdHJpbmcoKX1gICtcbiAgICAgICAgICBgIEd3ZWkgdG8gcGVyZm9ybSByZWNvdmVyaWVzLiBUcnkgc2VuZGluZyBzb21lIEVUSCB0byB0aGlzIGFkZHJlc3MgdGhlbiByZXRyeS5gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHR4QW1vdW50ID0gYmFzZUFkZHJlc3NCYWxhbmNlLnN1Yih0b3RhbEdhc05lZWRlZCk7XG4gICAgcmV0dXJuIHR4QW1vdW50O1xuICB9XG5cbiAgYXN5bmMgcmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeShxdWVyeTogUmVjb3JkPHN0cmluZywgc3RyaW5nPik6IFByb21pc2U8YW55PiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdtZXRob2Qgbm90IGltcGxlbWVudGVkJyk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgZXh0cmEgcGFyYW1ldGVycyBuZWVkZWQgdG8gYnVpbGQgYSBob3AgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIGJ1aWxkUGFyYW1zIFRoZSBvcmlnaW5hbCBidWlsZCBwYXJhbWV0ZXJzXG4gICAqIEByZXR1cm5zIGV4dHJhIHBhcmFtZXRlcnMgb2JqZWN0IHRvIG1lcmdlIHdpdGggdGhlIG9yaWdpbmFsIGJ1aWxkIHBhcmFtZXRlcnMgb2JqZWN0IGFuZCBzZW5kIHRvIHRoZSBwbGF0Zm9ybVxuICAgKi9cbiAgYXN5bmMgY3JlYXRlSG9wVHJhbnNhY3Rpb25QYXJhbXMoYnVpbGRQYXJhbXM6IEhvcFRyYW5zYWN0aW9uQnVpbGRPcHRpb25zKTogUHJvbWlzZTxIb3BQYXJhbXM+IHtcbiAgICBjb25zdCB3YWxsZXQgPSBidWlsZFBhcmFtcy53YWxsZXQ7XG4gICAgY29uc3QgcmVjaXBpZW50cyA9IGJ1aWxkUGFyYW1zLnJlY2lwaWVudHM7XG4gICAgY29uc3Qgd2FsbGV0UGFzc3BocmFzZSA9IGJ1aWxkUGFyYW1zLndhbGxldFBhc3NwaHJhc2U7XG5cbiAgICBjb25zdCB1c2VyS2V5Y2hhaW4gPSBhd2FpdCB0aGlzLmtleWNoYWlucygpLmdldCh7IGlkOiB3YWxsZXQua2V5SWRzKClbMF0gfSk7XG4gICAgY29uc3QgdXNlclBydiA9IHdhbGxldC5nZXRVc2VyUHJ2KHsga2V5Y2hhaW46IHVzZXJLZXljaGFpbiwgd2FsbGV0UGFzc3BocmFzZSB9KTtcbiAgICBjb25zdCB1c2VyUHJ2QnVmZmVyID0gYmlwMzIuZnJvbUJhc2U1OCh1c2VyUHJ2KS5wcml2YXRlS2V5O1xuICAgIGlmICghdXNlclBydkJ1ZmZlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHVzZXJQcnYnKTtcbiAgICB9XG4gICAgaWYgKCFyZWNpcGllbnRzIHx8ICFBcnJheS5pc0FycmF5KHJlY2lwaWVudHMpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGluZyBhcnJheSBvZiByZWNpcGllbnRzJyk7XG4gICAgfVxuXG4gICAgLy8gUmlnaHQgbm93IHdlIG9ubHkgc3VwcG9ydCAxIHJlY2lwaWVudFxuICAgIGlmIChyZWNpcGllbnRzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtdXN0IHNlbmQgdG8gZXhhY3RseSAxIHJlY2lwaWVudCcpO1xuICAgIH1cbiAgICBjb25zdCByZWNpcGllbnRBZGRyZXNzID0gcmVjaXBpZW50c1swXS5hZGRyZXNzO1xuICAgIGNvbnN0IHJlY2lwaWVudEFtb3VudCA9IHJlY2lwaWVudHNbMF0uYW1vdW50IGFzIHN0cmluZztcbiAgICBjb25zdCBmZWVFc3RpbWF0ZVBhcmFtcyA9IHtcbiAgICAgIHJlY2lwaWVudDogcmVjaXBpZW50QWRkcmVzcyxcbiAgICAgIGFtb3VudDogcmVjaXBpZW50QW1vdW50LFxuICAgICAgaG9wOiB0cnVlLFxuICAgIH07XG4gICAgY29uc3QgZmVlRXN0aW1hdGU6IEZlZUVzdGltYXRlID0gYXdhaXQgdGhpcy5mZWVFc3RpbWF0ZShmZWVFc3RpbWF0ZVBhcmFtcyk7XG5cbiAgICBjb25zdCBnYXNMaW1pdCA9IGZlZUVzdGltYXRlLmdhc0xpbWl0RXN0aW1hdGU7XG4gICAgY29uc3QgZ2FzUHJpY2UgPSBNYXRoLnJvdW5kKGZlZUVzdGltYXRlLmZlZUVzdGltYXRlIC8gZ2FzTGltaXQpO1xuICAgIGNvbnN0IGdhc1ByaWNlTWF4ID0gZ2FzUHJpY2UgKiA1O1xuICAgIC8vIFBheW1lbnQgaWQgYSByYW5kb20gbnVtYmVyIHNvIGl0cyBkaWZmZXJlbnQgZm9yIGV2ZXJ5IHR4XG4gICAgY29uc3QgcGF5bWVudElkID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMTAwMDAwMDAwMDApLnRvU3RyaW5nKCk7XG4gICAgY29uc3QgaG9wRGlnZXN0OiBCdWZmZXIgPSBBYnN0cmFjdEV0aExpa2VOZXdDb2lucy5nZXRIb3BEaWdlc3QoW1xuICAgICAgcmVjaXBpZW50QWRkcmVzcyxcbiAgICAgIHJlY2lwaWVudEFtb3VudCxcbiAgICAgIGdhc1ByaWNlTWF4LnRvU3RyaW5nKCksXG4gICAgICBnYXNMaW1pdC50b1N0cmluZygpLFxuICAgICAgcGF5bWVudElkLFxuICAgIF0pO1xuXG4gICAgY29uc3QgdXNlclJlcVNpZyA9IG9wdGlvbmFsRGVwcy5ldGhVdGlsLmFkZEhleFByZWZpeChcbiAgICAgIEJ1ZmZlci5mcm9tKHNlY3AyNTZrMS5lY2RzYVNpZ24oaG9wRGlnZXN0LCB1c2VyUHJ2QnVmZmVyKS5zaWduYXR1cmUpLnRvU3RyaW5nKCdoZXgnKVxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgaG9wUGFyYW1zOiB7XG4gICAgICAgIGdhc1ByaWNlTWF4LFxuICAgICAgICB1c2VyUmVxU2lnLFxuICAgICAgICBwYXltZW50SWQsXG4gICAgICB9LFxuICAgICAgZ2FzTGltaXQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgdGhhdCB0aGUgaG9wIHByZWJ1aWxkIGZyb20gdGhlIEhTTSBpcyB2YWxpZCBhbmQgY29ycmVjdFxuICAgKiBAcGFyYW0ge0lXYWxsZXR9IHdhbGxldCAtIFRoZSB3YWxsZXQgdGhhdCB0aGUgcHJlYnVpbGQgaXMgZm9yXG4gICAqIEBwYXJhbSB7SG9wUHJlYnVpbGR9IGhvcFByZWJ1aWxkIC0gVGhlIHByZWJ1aWxkIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbFBhcmFtcyAtIFRoZSBvcmlnaW5hbCBwYXJhbWV0ZXJzIHBhc3NlZCB0byBwcmVidWlsZFRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7UmVjaXBpZW50W119IG9yaWdpbmFsUGFyYW1zLnJlY2lwaWVudHMgLSBUaGUgb3JpZ2luYWwgcmVjaXBpZW50cyBhcnJheVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQHRocm93cyBFcnJvciBpZiBUaGUgcHJlYnVpbGQgaXMgaW52YWxpZFxuICAgKi9cbiAgYXN5bmMgdmFsaWRhdGVIb3BQcmVidWlsZChcbiAgICB3YWxsZXQ6IElXYWxsZXQsXG4gICAgaG9wUHJlYnVpbGQ6IEhvcFByZWJ1aWxkLFxuICAgIG9yaWdpbmFsUGFyYW1zPzogeyByZWNpcGllbnRzOiBSZWNpcGllbnRbXSB9XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgdHgsIGlkLCBzaWduYXR1cmUgfSA9IGhvcFByZWJ1aWxkO1xuXG4gICAgLy8gZmlyc3QsIHZhbGlkYXRlIHRoZSBIU00gc2lnbmF0dXJlXG4gICAgY29uc3Qgc2VydmVyWHB1YiA9IGNvbW1vbi5FbnZpcm9ubWVudHNbdGhpcy5iaXRnby5nZXRFbnYoKV0uaHNtWHB1YjtcbiAgICBjb25zdCBzZXJ2ZXJQdWJrZXlCdWZmZXI6IEJ1ZmZlciA9IGJpcDMyLmZyb21CYXNlNTgoc2VydmVyWHB1YikucHVibGljS2V5O1xuICAgIGNvbnN0IHNpZ25hdHVyZUJ1ZmZlcjogQnVmZmVyID0gQnVmZmVyLmZyb20ob3B0aW9uYWxEZXBzLmV0aFV0aWwuc3RyaXBIZXhQcmVmaXgoc2lnbmF0dXJlKSwgJ2hleCcpO1xuICAgIGNvbnN0IG1lc3NhZ2VCdWZmZXI6IEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKFxuICAgICAgb3B0aW9uYWxEZXBzLmV0aFV0aWwucGFkVG9FdmVuKG9wdGlvbmFsRGVwcy5ldGhVdGlsLnN0cmlwSGV4UHJlZml4KGlkKSksXG4gICAgICAnaGV4J1xuICAgICk7XG5cbiAgICBjb25zdCBzaWcgPSBuZXcgVWludDhBcnJheShzaWduYXR1cmVCdWZmZXIuc2xpY2UoMSkpO1xuICAgIGNvbnN0IGlzVmFsaWRTaWduYXR1cmU6IGJvb2xlYW4gPSBzZWNwMjU2azEuZWNkc2FWZXJpZnkoc2lnLCBtZXNzYWdlQnVmZmVyLCBzZXJ2ZXJQdWJrZXlCdWZmZXIpO1xuICAgIGlmICghaXNWYWxpZFNpZ25hdHVyZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgSG9wIHR4aWQgc2lnbmF0dXJlIGludmFsaWQgLSBwdWI6ICR7c2VydmVyWHB1Yn0sIG1zZzogJHttZXNzYWdlQnVmZmVyPy50b1N0cmluZygpfSwgc2lnOiAke3NpZ25hdHVyZUJ1ZmZlcj8udG9TdHJpbmcoKX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGJ1aWx0SG9wVHggPSBvcHRpb25hbERlcHMuRXRoVHguVHJhbnNhY3Rpb25GYWN0b3J5LmZyb21TZXJpYWxpemVkRGF0YShvcHRpb25hbERlcHMuZXRoVXRpbC50b0J1ZmZlcih0eCkpO1xuICAgIC8vIElmIG9yaWdpbmFsIHBhcmFtcyBhcmUgZ2l2ZW4sIHdlIGNhbiBjaGVjayB0aGVtIGFnYWluc3QgdGhlIHRyYW5zYWN0aW9uIHByZWJ1aWxkIHBhcmFtc1xuICAgIGlmICghXy5pc05pbChvcmlnaW5hbFBhcmFtcykpIHtcbiAgICAgIGNvbnN0IHsgcmVjaXBpZW50cyB9ID0gb3JpZ2luYWxQYXJhbXM7XG5cbiAgICAgIC8vIFRoZW4gdmFsaWRhdGUgdGhhdCB0aGUgdHggcGFyYW1zIGFjdHVhbGx5IGVxdWFsIHRoZSByZXF1ZXN0ZWQgcGFyYW1zXG4gICAgICBjb25zdCBvcmlnaW5hbEFtb3VudCA9IG5ldyBCaWdOdW1iZXIocmVjaXBpZW50c1swXS5hbW91bnQpO1xuICAgICAgY29uc3Qgb3JpZ2luYWxEZXN0aW5hdGlvbjogc3RyaW5nID0gcmVjaXBpZW50c1swXS5hZGRyZXNzO1xuXG4gICAgICBjb25zdCBob3BBbW91bnQgPSBuZXcgQmlnTnVtYmVyKG9wdGlvbmFsRGVwcy5ldGhVdGlsLmJ1ZmZlclRvSGV4KGJ1aWx0SG9wVHgudmFsdWUpKTtcbiAgICAgIGlmICghYnVpbHRIb3BUeC50bykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFRyYW5zYWN0aW9uIGRvZXMgbm90IGhhdmUgYSBkZXN0aW5hdGlvbiBhZGRyZXNzYCk7XG4gICAgICB9XG4gICAgICBjb25zdCBob3BEZXN0aW5hdGlvbiA9IGJ1aWx0SG9wVHgudG8udG9TdHJpbmcoKTtcbiAgICAgIGlmICghaG9wQW1vdW50LmVxKG9yaWdpbmFsQW1vdW50KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhvcCBhbW91bnQ6ICR7aG9wQW1vdW50fSBkb2VzIG5vdCBlcXVhbCBvcmlnaW5hbCBhbW91bnQ6ICR7b3JpZ2luYWxBbW91bnR9YCk7XG4gICAgICB9XG4gICAgICBpZiAoaG9wRGVzdGluYXRpb24udG9Mb3dlckNhc2UoKSAhPT0gb3JpZ2luYWxEZXN0aW5hdGlvbi50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSG9wIGRlc3RpbmF0aW9uOiAke2hvcERlc3RpbmF0aW9ufSBkb2VzIG5vdCBlcXVhbCBvcmlnaW5hbCByZWNpcGllbnQ6ICR7aG9wRGVzdGluYXRpb259YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFidWlsdEhvcFR4LnZlcmlmeVNpZ25hdHVyZSgpKSB7XG4gICAgICAvLyBXZSBkb250IHdhbnQgdG8gY29udGludWUgYXQgYWxsIGluIHRoaXMgY2FzZSwgYXQgcmlzayBvZiBFVEggYmVpbmcgc3R1Y2sgb24gdGhlIGhvcCBhZGRyZXNzXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgaG9wIHRyYW5zYWN0aW9uIHNpZ25hdHVyZSwgdHhpZDogJHtpZH1gKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbmFsRGVwcy5ldGhVdGlsLmFkZEhleFByZWZpeChidWlsdEhvcFR4Lmhhc2goKS50b1N0cmluZygnaGV4JykpICE9PSBpZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBTaWduZWQgaG9wIHR4aWQgZG9lcyBub3QgZXF1YWwgYWN0dWFsIHR4aWRgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgaG9wIGRpZ2VzdCBmb3IgdGhlIHVzZXIgdG8gc2lnbi4gVGhpcyBpcyB2YWxpZGF0ZWQgaW4gdGhlIEhTTSB0byBwcm92ZSB0aGF0IHRoZSB1c2VyIHJlcXVlc3RlZCB0aGlzIHR4XG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHBhcmFtc0FyciAtIFRoZSBwYXJhbWV0ZXJzIHRvIGhhc2ggdG9nZXRoZXIgZm9yIHRoZSBkaWdlc3RcbiAgICogQHJldHVybnMge0J1ZmZlcn1cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdldEhvcERpZ2VzdChwYXJhbXNBcnI6IHN0cmluZ1tdKTogQnVmZmVyIHtcbiAgICBjb25zdCBoYXNoID0gS2VjY2FrKCdrZWNjYWsyNTYnKTtcbiAgICBoYXNoLnVwZGF0ZShbQWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuaG9wVHJhbnNhY3Rpb25TYWx0LCAuLi5wYXJhbXNBcnJdLmpvaW4oJyQnKSk7XG4gICAgcmV0dXJuIGhhc2guZGlnZXN0KCk7XG4gIH1cblxuICAvKipcbiAgICogTW9kaWZ5IHByZWJ1aWxkIGJlZm9yZSBzZW5kaW5nIGl0IHRvIHRoZSBzZXJ2ZXIuIEFkZCB0aGluZ3MgbGlrZSBob3AgdHJhbnNhY3Rpb24gcGFyYW1zXG4gICAqIEBwYXJhbSB7QnVpbGRPcHRpb25zfSBidWlsZFBhcmFtcyAtIFRoZSB3aGl0ZWxpc3RlZCBwYXJhbWV0ZXJzIGZvciB0aGlzIHByZWJ1aWxkXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYnVpbGRQYXJhbXMuaG9wIC0gVHJ1ZSBpZiB0aGlzIHNob3VsZCBwcmVidWlsZCBhIGhvcCB0eCwgZWxzZSBmYWxzZVxuICAgKiBAcGFyYW0ge1JlY2lwaWVudFtdfSBidWlsZFBhcmFtcy5yZWNpcGllbnRzIC0gVGhlIHJlY2lwaWVudHMgYXJyYXkgb2YgdGhpcyB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1dhbGxldH0gYnVpbGRQYXJhbXMud2FsbGV0IC0gVGhlIHdhbGxldCBzZW5kaW5nIHRoaXMgdHhcbiAgICogQHBhcmFtIHtzdHJpbmd9IGJ1aWxkUGFyYW1zLndhbGxldFBhc3NwaHJhc2UgLSB0aGUgcGFzc3BocmFzZSBmb3IgdGhpcyB3YWxsZXRcbiAgICogQHJldHVybnMge1Byb21pc2U8QnVpbGRPcHRpb25zPn1cbiAgICovXG4gIGFzeW5jIGdldEV4dHJhUHJlYnVpbGRQYXJhbXMoYnVpbGRQYXJhbXM6IEJ1aWxkT3B0aW9ucyk6IFByb21pc2U8QnVpbGRPcHRpb25zPiB7XG4gICAgaWYgKFxuICAgICAgIV8uaXNVbmRlZmluZWQoYnVpbGRQYXJhbXMuaG9wKSAmJlxuICAgICAgYnVpbGRQYXJhbXMuaG9wICYmXG4gICAgICAhXy5pc1VuZGVmaW5lZChidWlsZFBhcmFtcy53YWxsZXQpICYmXG4gICAgICAhXy5pc1VuZGVmaW5lZChidWlsZFBhcmFtcy5yZWNpcGllbnRzKSAmJlxuICAgICAgIV8uaXNVbmRlZmluZWQoYnVpbGRQYXJhbXMud2FsbGV0UGFzc3BocmFzZSlcbiAgICApIHtcbiAgICAgIGlmICh0aGlzIGluc3RhbmNlb2YgRXRoTGlrZVRva2VuKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgSG9wIHRyYW5zYWN0aW9ucyBhcmUgbm90IGVuYWJsZWQgZm9yIEVSQy0yMCB0b2tlbnMsIG5vciBhcmUgdGhleSBuZWNlc3NhcnkuIFBsZWFzZSByZW1vdmUgdGhlICdob3AnIHBhcmFtZXRlciBhbmQgdHJ5IGFnYWluLmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiAoYXdhaXQgdGhpcy5jcmVhdGVIb3BUcmFuc2FjdGlvblBhcmFtcyh7XG4gICAgICAgIHdhbGxldDogYnVpbGRQYXJhbXMud2FsbGV0LFxuICAgICAgICByZWNpcGllbnRzOiBidWlsZFBhcmFtcy5yZWNpcGllbnRzLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBidWlsZFBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgfSkpIGFzIGFueTtcbiAgICB9XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgLyoqXG4gICAqIE1vZGlmeSBwcmVidWlsZCBhZnRlciByZWNlaXZpbmcgaXQgZnJvbSB0aGUgc2VydmVyLiBBZGQgdGhpbmdzIGxpa2UgbmxvY2t0aW1lXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb25QcmVidWlsZH0gcGFyYW1zIC0gVGhlIHByZWJ1aWxkIHRvIG1vZGlmeVxuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25QcmVidWlsZH0gVGhlIG1vZGlmaWVkIHByZWJ1aWxkXG4gICAqL1xuICBhc3luYyBwb3N0UHJvY2Vzc1ByZWJ1aWxkKHBhcmFtczogVHJhbnNhY3Rpb25QcmVidWlsZCk6IFByb21pc2U8VHJhbnNhY3Rpb25QcmVidWlsZD4ge1xuICAgIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMuaG9wVHJhbnNhY3Rpb24pICYmICFfLmlzVW5kZWZpbmVkKHBhcmFtcy53YWxsZXQpICYmICFfLmlzVW5kZWZpbmVkKHBhcmFtcy5idWlsZFBhcmFtcykpIHtcbiAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVIb3BQcmVidWlsZChwYXJhbXMud2FsbGV0LCBwYXJhbXMuaG9wVHJhbnNhY3Rpb24sIHBhcmFtcy5idWlsZFBhcmFtcyk7XG4gICAgfVxuICAgIHJldHVybiBwYXJhbXM7XG4gIH1cblxuICAvKipcbiAgICogQ29pbi1zcGVjaWZpYyB0aGluZ3MgZG9uZSBiZWZvcmUgc2lnbmluZyBhIHRyYW5zYWN0aW9uLCBpLmUuIHZlcmlmaWNhdGlvblxuICAgKiBAcGFyYW0ge1ByZXNpZ25UcmFuc2FjdGlvbk9wdGlvbnN9IHBhcmFtc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zPn1cbiAgICovXG4gIGFzeW5jIHByZXNpZ25UcmFuc2FjdGlvbihwYXJhbXM6IFByZXNpZ25UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPFByZXNpZ25UcmFuc2FjdGlvbk9wdGlvbnM+IHtcbiAgICBpZiAoIV8uaXNVbmRlZmluZWQocGFyYW1zLmhvcFRyYW5zYWN0aW9uKSAmJiAhXy5pc1VuZGVmaW5lZChwYXJhbXMud2FsbGV0KSAmJiAhXy5pc1VuZGVmaW5lZChwYXJhbXMuYnVpbGRQYXJhbXMpKSB7XG4gICAgICBhd2FpdCB0aGlzLnZhbGlkYXRlSG9wUHJlYnVpbGQocGFyYW1zLndhbGxldCwgcGFyYW1zLmhvcFRyYW5zYWN0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcmFtcztcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaCBmZWUgZXN0aW1hdGUgaW5mb3JtYXRpb24gZnJvbSB0aGUgc2VydmVyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXMgLSBUaGUgcGFyYW1zIHBhc3NlZCBpbnRvIHRoZSBmdW5jdGlvblxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtwYXJhbXMuaG9wXSAtIFRydWUgaWYgd2Ugc2hvdWxkIGVzdGltYXRlIGZlZSBmb3IgYSBob3AgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtwYXJhbXMucmVjaXBpZW50XSAtIFRoZSByZWNpcGllbnQgb2YgdGhlIHRyYW5zYWN0aW9uIHRvIGVzdGltYXRlIGEgc2VuZCB0b1xuICAgKiBAcGFyYW0ge3N0cmluZ30gW3BhcmFtcy5kYXRhXSAtIFRoZSBFVEggdHggZGF0YSB0byBlc3RpbWF0ZSBhIHNlbmQgZm9yXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBmZWUgaW5mbyByZXR1cm5lZCBmcm9tIHRoZSBzZXJ2ZXJcbiAgICovXG4gIGFzeW5jIGZlZUVzdGltYXRlKHBhcmFtczogRmVlRXN0aW1hdGVPcHRpb25zKTogUHJvbWlzZTxGZWVFc3RpbWF0ZT4ge1xuICAgIGNvbnN0IHF1ZXJ5OiBGZWVFc3RpbWF0ZU9wdGlvbnMgPSB7fTtcbiAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5ob3ApIHtcbiAgICAgIHF1ZXJ5LmhvcCA9IHBhcmFtcy5ob3A7XG4gICAgfVxuICAgIGlmIChwYXJhbXMgJiYgcGFyYW1zLnJlY2lwaWVudCkge1xuICAgICAgcXVlcnkucmVjaXBpZW50ID0gcGFyYW1zLnJlY2lwaWVudDtcbiAgICB9XG4gICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuZGF0YSkge1xuICAgICAgcXVlcnkuZGF0YSA9IHBhcmFtcy5kYXRhO1xuICAgIH1cbiAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5hbW91bnQpIHtcbiAgICAgIHF1ZXJ5LmFtb3VudCA9IHBhcmFtcy5hbW91bnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuYml0Z28uZ2V0KHRoaXMudXJsKCcvdHgvZmVlJykpLnF1ZXJ5KHF1ZXJ5KS5yZXN1bHQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBzZWNwMjU2azEga2V5IHBhaXJcbiAgICpcbiAgICogQHBhcmFtIHtCdWZmZXJ9IHNlZWRcbiAgICogQHJldHVybnMge0tleVBhaXJ9IG9iamVjdCB3aXRoIGdlbmVyYXRlZCBwdWIgYW5kIHBydlxuICAgKi9cbiAgZ2VuZXJhdGVLZXlQYWlyKHNlZWQ6IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIGlmICghc2VlZCkge1xuICAgICAgLy8gQW4gZXh0ZW5kZWQgcHJpdmF0ZSBrZXkgaGFzIGJvdGggYSBub3JtYWwgMjU2IGJpdCBwcml2YXRlIGtleSBhbmQgYSAyNTZcbiAgICAgIC8vIGJpdCBjaGFpbiBjb2RlLCBib3RoIG9mIHdoaWNoIG11c3QgYmUgcmFuZG9tLiA1MTIgYml0cyBpcyB0aGVyZWZvcmUgdGhlXG4gICAgICAvLyBtYXhpbXVtIGVudHJvcHkgYW5kIGdpdmVzIHVzIG1heGltdW0gc2VjdXJpdHkgYWdhaW5zdCBjcmFja2luZy5cbiAgICAgIHNlZWQgPSByYW5kb21CeXRlcyg1MTIgLyA4KTtcbiAgICB9XG4gICAgY29uc3QgZXh0ZW5kZWRLZXkgPSBiaXAzMi5mcm9tU2VlZChzZWVkKTtcbiAgICBjb25zdCB4cHViID0gZXh0ZW5kZWRLZXkubmV1dGVyZWQoKS50b0Jhc2U1OCgpO1xuICAgIHJldHVybiB7XG4gICAgICBwdWI6IHhwdWIsXG4gICAgICBwcnY6IGV4dGVuZGVkS2V5LnRvQmFzZTU4KCksXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIHBhcnNlVHJhbnNhY3Rpb24ocGFyYW1zOiBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8UGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICAvKipcbiAgICogTWFrZSBzdXJlIGFuIGFkZHJlc3MgaXMgYSB3YWxsZXQgYWRkcmVzcyBhbmQgdGhyb3cgYW4gZXJyb3IgaWYgaXQncyBub3QuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5hZGRyZXNzIC0gVGhlIGRlcml2ZWQgYWRkcmVzcyBzdHJpbmcgb24gdGhlIG5ldHdvcmtcbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcy5jb2luU3BlY2lmaWMgLSBDb2luLXNwZWNpZmljIGRldGFpbHMgZm9yIHRoZSBhZGRyZXNzIHN1Y2ggYXMgYSBmb3J3YXJkZXJWZXJzaW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuYmFzZUFkZHJlc3MgLSBUaGUgYmFzZSBhZGRyZXNzIG9mIHRoZSB3YWxsZXQgb24gdGhlIG5ldHdvcmtcbiAgICogQHRocm93cyB7SW52YWxpZEFkZHJlc3NFcnJvcn1cbiAgICogQHRocm93cyB7SW52YWxpZEFkZHJlc3NWZXJpZmljYXRpb25PYmplY3RQcm9wZXJ0eUVycm9yfVxuICAgKiBAdGhyb3dzIHtVbmV4cGVjdGVkQWRkcmVzc0Vycm9yfVxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZmYgYWRkcmVzcyBpcyBhIHdhbGxldCBhZGRyZXNzXG4gICAqL1xuICBhc3luYyBpc1dhbGxldEFkZHJlc3MocGFyYW1zOiBWZXJpZnlFdGhBZGRyZXNzT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGV0aFV0aWwgPSBvcHRpb25hbERlcHMuZXRoVXRpbDtcblxuICAgIGxldCBleHBlY3RlZEFkZHJlc3M7XG4gICAgbGV0IGFjdHVhbEFkZHJlc3M7XG5cbiAgICBjb25zdCB7IGFkZHJlc3MsIGNvaW5TcGVjaWZpYywgYmFzZUFkZHJlc3MsIGltcGxpZWRGb3J3YXJkZXJWZXJzaW9uID0gY29pblNwZWNpZmljPy5mb3J3YXJkZXJWZXJzaW9uIH0gPSBwYXJhbXM7XG5cbiAgICBpZiAoYWRkcmVzcyAmJiAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhhZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoYGludmFsaWQgYWRkcmVzczogJHthZGRyZXNzfWApO1xuICAgIH1cblxuICAgIC8vIGJhc2UgYWRkcmVzcyBpcyByZXF1aXJlZCB0byBjYWxjdWxhdGUgdGhlIHNhbHQgd2hpY2ggaXMgdXNlZCBpbiBjYWxjdWxhdGVGb3J3YXJkZXJWMUFkZHJlc3MgbWV0aG9kXG4gICAgaWYgKF8uaXNVbmRlZmluZWQoYmFzZUFkZHJlc3MpIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKGJhc2VBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoJ2ludmFsaWQgYmFzZSBhZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzT2JqZWN0KGNvaW5TcGVjaWZpYykpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc1ZlcmlmaWNhdGlvbk9iamVjdFByb3BlcnR5RXJyb3IoXG4gICAgICAgICdhZGRyZXNzIHZhbGlkYXRpb24gZmFpbHVyZTogY29pblNwZWNpZmljIGZpZWxkIG11c3QgYmUgYW4gb2JqZWN0J1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoaW1wbGllZEZvcndhcmRlclZlcnNpb24gPT09IDAgfHwgaW1wbGllZEZvcndhcmRlclZlcnNpb24gPT09IDMpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBldGhOZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKCk7XG4gICAgICBjb25zdCBmb3J3YXJkZXJGYWN0b3J5QWRkcmVzcyA9IGV0aE5ldHdvcms/LmZvcndhcmRlckZhY3RvcnlBZGRyZXNzIGFzIHN0cmluZztcbiAgICAgIGNvbnN0IGZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcyA9IGV0aE5ldHdvcms/LmZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcyBhcyBzdHJpbmc7XG5cbiAgICAgIGNvbnN0IGluaXRjb2RlID0gZ2V0UHJveHlJbml0Y29kZShmb3J3YXJkZXJJbXBsZW1lbnRhdGlvbkFkZHJlc3MpO1xuICAgICAgY29uc3Qgc2FsdEJ1ZmZlciA9IGV0aFV0aWwuc2V0TGVuZ3RoTGVmdChcbiAgICAgICAgQnVmZmVyLmZyb20oZXRoVXRpbC5wYWRUb0V2ZW4oZXRoVXRpbC5zdHJpcEhleFByZWZpeChjb2luU3BlY2lmaWMuc2FsdCB8fCAnJykpLCAnaGV4JyksXG4gICAgICAgIDMyXG4gICAgICApO1xuXG4gICAgICAvLyBIYXNoIHRoZSB3YWxsZXQgYmFzZSBhZGRyZXNzIHdpdGggdGhlIGdpdmVuIHNhbHQsIHNvIHRoZSBhZGRyZXNzIGRpcmVjdGx5IHJlbGllcyBvbiB0aGUgYmFzZSBhZGRyZXNzXG4gICAgICBjb25zdCBjYWxjdWxhdGlvblNhbHQgPSBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleChcbiAgICAgICAgb3B0aW9uYWxEZXBzLmV0aEFiaS5zb2xpZGl0eVNIQTMoWydhZGRyZXNzJywgJ2J5dGVzMzInXSwgW2Jhc2VBZGRyZXNzLCBzYWx0QnVmZmVyXSlcbiAgICAgICk7XG5cbiAgICAgIGV4cGVjdGVkQWRkcmVzcyA9IGNhbGN1bGF0ZUZvcndhcmRlclYxQWRkcmVzcyhmb3J3YXJkZXJGYWN0b3J5QWRkcmVzcywgY2FsY3VsYXRpb25TYWx0LCBpbml0Y29kZSk7XG4gICAgICBhY3R1YWxBZGRyZXNzID0gYWRkcmVzcztcbiAgICB9XG5cbiAgICBpZiAoZXhwZWN0ZWRBZGRyZXNzICE9PSBhY3R1YWxBZGRyZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgVW5leHBlY3RlZEFkZHJlc3NFcnJvcihgYWRkcmVzcyB2YWxpZGF0aW9uIGZhaWx1cmU6IGV4cGVjdGVkICR7ZXhwZWN0ZWRBZGRyZXNzfSBidXQgZ290ICR7YWRkcmVzc31gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uUHJlYnVpbGR9IHR4UHJlYnVpbGRcbiAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAqL1xuICB2ZXJpZnlDb2luKHR4UHJlYnVpbGQ6IFRyYW5zYWN0aW9uUHJlYnVpbGQpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHhQcmVidWlsZC5jb2luID09PSB0aGlzLmdldENoYWluKCk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IGlmIGEgdHNzIHRyYW5zYWN0aW9uIGlzIHZhbGlkXG4gICAqXG4gICAqIEBwYXJhbSB7VmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zfSBwYXJhbXNcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvblBhcmFtc30gcGFyYW1zLnR4UGFyYW1zIC0gcGFyYW1zIG9iamVjdCBwYXNzZWQgdG8gc2VuZFxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uUHJlYnVpbGR9IHBhcmFtcy50eFByZWJ1aWxkIC0gcHJlYnVpbGQgb2JqZWN0IHJldHVybmVkIGJ5IHNlcnZlclxuICAgKiBAcGFyYW0ge1dhbGxldH0gcGFyYW1zLndhbGxldCAtIFdhbGxldCBvYmplY3QgdG8gb2J0YWluIGtleXMgdG8gdmVyaWZ5IGFnYWluc3RcbiAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAqL1xuICB2ZXJpZnlUc3NUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHdhbGxldCB9ID0gcGFyYW1zO1xuICAgIGlmIChcbiAgICAgICF0eFBhcmFtcz8ucmVjaXBpZW50cyAmJlxuICAgICAgIShcbiAgICAgICAgdHhQYXJhbXMucHJlYnVpbGRUeD8uY29uc29saWRhdGVJZCB8fFxuICAgICAgICAodHhQYXJhbXMudHlwZSAmJiBbJ2FjY2VsZXJhdGlvbicsICdmaWxsTm9uY2UnLCAndHJhbnNmZXJUb2tlbiddLmluY2x1ZGVzKHR4UGFyYW1zLnR5cGUpKVxuICAgICAgKVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBtaXNzaW5nIHR4UGFyYW1zYCk7XG4gICAgfVxuICAgIGlmICghd2FsbGV0IHx8ICF0eFByZWJ1aWxkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYG1pc3NpbmcgcGFyYW1zYCk7XG4gICAgfVxuICAgIGlmICh0eFBhcmFtcy5ob3AgJiYgdHhQYXJhbXMucmVjaXBpZW50cyAmJiB0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdHggY2Fubm90IGJlIGJvdGggYSBiYXRjaCBhbmQgaG9wIHRyYW5zYWN0aW9uYCk7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmeSB0aGF0IGEgdHJhbnNhY3Rpb24gcHJlYnVpbGQgY29tcGxpZXMgd2l0aCB0aGUgb3JpZ2luYWwgaW50ZW50aW9uXG4gICAqXG4gICAqIEBwYXJhbSB7VmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zfSBwYXJhbXNcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvblBhcmFtc30gcGFyYW1zLnR4UGFyYW1zIC0gcGFyYW1zIG9iamVjdCBwYXNzZWQgdG8gc2VuZFxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uUHJlYnVpbGR9IHBhcmFtcy50eFByZWJ1aWxkIC0gcHJlYnVpbGQgb2JqZWN0IHJldHVybmVkIGJ5IHNlcnZlclxuICAgKiBAcGFyYW0ge1dhbGxldH0gcGFyYW1zLndhbGxldCAtIFdhbGxldCBvYmplY3QgdG8gb2J0YWluIGtleXMgdG8gdmVyaWZ5IGFnYWluc3RcbiAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAqL1xuICBhc3luYyB2ZXJpZnlUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGV0aE5ldHdvcmsgPSB0aGlzLmdldE5ldHdvcmsoKTtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQsIHdhbGxldFR5cGUgfSA9IHBhcmFtcztcblxuICAgIGlmICh3YWxsZXRUeXBlID09PSAndHNzJykge1xuICAgICAgcmV0dXJuIHRoaXMudmVyaWZ5VHNzVHJhbnNhY3Rpb24ocGFyYW1zKTtcbiAgICB9XG5cbiAgICBpZiAoIXR4UGFyYW1zPy5yZWNpcGllbnRzIHx8ICF0eFByZWJ1aWxkPy5yZWNpcGllbnRzIHx8ICF3YWxsZXQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgbWlzc2luZyBwYXJhbXNgKTtcbiAgICB9XG4gICAgaWYgKHR4UGFyYW1zLmhvcCAmJiB0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdHggY2Fubm90IGJlIGJvdGggYSBiYXRjaCBhbmQgaG9wIHRyYW5zYWN0aW9uYCk7XG4gICAgfVxuICAgIGlmICh0eFByZWJ1aWxkLnJlY2lwaWVudHMubGVuZ3RoICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHR4UHJlYnVpbGQgc2hvdWxkIG9ubHkgaGF2ZSAxIHJlY2lwaWVudCBidXQgJHt0eFByZWJ1aWxkLnJlY2lwaWVudHMubGVuZ3RofSBmb3VuZGApO1xuICAgIH1cbiAgICBpZiAodHhQYXJhbXMuaG9wICYmIHR4UHJlYnVpbGQuaG9wVHJhbnNhY3Rpb24pIHtcbiAgICAgIC8vIENoZWNrIHJlY2lwaWVudCBhbW91bnQgZm9yIGhvcCB0cmFuc2FjdGlvblxuICAgICAgaWYgKHR4UGFyYW1zLnJlY2lwaWVudHMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgaG9wIHRyYW5zYWN0aW9uIG9ubHkgc3VwcG9ydHMgMSByZWNpcGllbnQgYnV0ICR7dHhQYXJhbXMucmVjaXBpZW50cy5sZW5ndGh9IGZvdW5kYCk7XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIHR4IHNlbmRzIHRvIGhvcCBhZGRyZXNzXG4gICAgICBjb25zdCBkZWNvZGVkSG9wVHggPSBvcHRpb25hbERlcHMuRXRoVHguVHJhbnNhY3Rpb25GYWN0b3J5LmZyb21TZXJpYWxpemVkRGF0YShcbiAgICAgICAgb3B0aW9uYWxEZXBzLmV0aFV0aWwudG9CdWZmZXIodHhQcmVidWlsZC5ob3BUcmFuc2FjdGlvbi50eClcbiAgICAgICk7XG4gICAgICBjb25zdCBleHBlY3RlZEhvcEFkZHJlc3MgPSBvcHRpb25hbERlcHMuZXRoVXRpbC5zdHJpcEhleFByZWZpeChkZWNvZGVkSG9wVHguZ2V0U2VuZGVyQWRkcmVzcygpLnRvU3RyaW5nKCkpO1xuICAgICAgY29uc3QgYWN0dWFsSG9wQWRkcmVzcyA9IG9wdGlvbmFsRGVwcy5ldGhVdGlsLnN0cmlwSGV4UHJlZml4KHR4UHJlYnVpbGQucmVjaXBpZW50c1swXS5hZGRyZXNzKTtcbiAgICAgIGlmIChleHBlY3RlZEhvcEFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gYWN0dWFsSG9wQWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigncmVjaXBpZW50IGFkZHJlc3Mgb2YgdHhQcmVidWlsZCBkb2VzIG5vdCBtYXRjaCBob3AgYWRkcmVzcycpO1xuICAgICAgfVxuXG4gICAgICAvLyBDb252ZXJ0IFRyYW5zYWN0aW9uUmVjaXBpZW50IGFycmF5IHRvIFJlY2lwaWVudCBhcnJheVxuICAgICAgY29uc3QgcmVjaXBpZW50czogUmVjaXBpZW50W10gPSB0eFBhcmFtcy5yZWNpcGllbnRzLm1hcCgocikgPT4ge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFkZHJlc3M6IHIuYWRkcmVzcyxcbiAgICAgICAgICBhbW91bnQ6IHR5cGVvZiByLmFtb3VudCA9PT0gJ251bWJlcicgPyByLmFtb3VudC50b1N0cmluZygpIDogci5hbW91bnQsXG4gICAgICAgIH07XG4gICAgICB9KTtcblxuICAgICAgLy8gQ2hlY2sgZGVzdGluYXRpb24gYWRkcmVzcyBhbmQgYW1vdW50XG4gICAgICBhd2FpdCB0aGlzLnZhbGlkYXRlSG9wUHJlYnVpbGQod2FsbGV0LCB0eFByZWJ1aWxkLmhvcFRyYW5zYWN0aW9uLCB7IHJlY2lwaWVudHMgfSk7XG4gICAgfSBlbHNlIGlmICh0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIC8vIENoZWNrIHRvdGFsIGFtb3VudCBmb3IgYmF0Y2ggdHJhbnNhY3Rpb25cbiAgICAgIGxldCBleHBlY3RlZFRvdGFsQW1vdW50ID0gbmV3IEJpZ051bWJlcigwKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdHhQYXJhbXMucmVjaXBpZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBleHBlY3RlZFRvdGFsQW1vdW50ID0gZXhwZWN0ZWRUb3RhbEFtb3VudC5wbHVzKHR4UGFyYW1zLnJlY2lwaWVudHNbaV0uYW1vdW50KTtcbiAgICAgIH1cbiAgICAgIGlmICghZXhwZWN0ZWRUb3RhbEFtb3VudC5pc0VxdWFsVG8odHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFtb3VudCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICdiYXRjaCB0cmFuc2FjdGlvbiBhbW91bnQgaW4gdHhQcmVidWlsZCByZWNlaXZlZCBmcm9tIEJpdEdvIHNlcnZlcnMgZG9lcyBub3QgbWF0Y2ggdHhQYXJhbXMgc3VwcGxpZWQgYnkgY2xpZW50J1xuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBiYXRjaCB0cmFuc2FjdGlvbiBpcyBzZW50IHRvIHRoZSBiYXRjaGVyIGNvbnRyYWN0IGFkZHJlc3MgZm9yIHRoZSBjaGFpblxuICAgICAgY29uc3QgYmF0Y2hlckNvbnRyYWN0QWRkcmVzcyA9IGV0aE5ldHdvcms/LmJhdGNoZXJDb250cmFjdEFkZHJlc3M7XG4gICAgICBpZiAoXG4gICAgICAgICFiYXRjaGVyQ29udHJhY3RBZGRyZXNzIHx8XG4gICAgICAgIGJhdGNoZXJDb250cmFjdEFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFkZHJlc3MudG9Mb3dlckNhc2UoKVxuICAgICAgKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigncmVjaXBpZW50IGFkZHJlc3Mgb2YgdHhQcmVidWlsZCBkb2VzIG5vdCBtYXRjaCBiYXRjaGVyIGFkZHJlc3MnKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ2hlY2sgcmVjaXBpZW50IGFkZHJlc3MgYW5kIGFtb3VudCBmb3Igbm9ybWFsIHRyYW5zYWN0aW9uXG4gICAgICBpZiAodHhQYXJhbXMucmVjaXBpZW50cy5sZW5ndGggIT09IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBub3JtYWwgdHJhbnNhY3Rpb24gb25seSBzdXBwb3J0cyAxIHJlY2lwaWVudCBidXQgJHt0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aH0gZm91bmRgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGV4cGVjdGVkQW1vdW50ID0gbmV3IEJpZ051bWJlcih0eFBhcmFtcy5yZWNpcGllbnRzWzBdLmFtb3VudCk7XG4gICAgICBpZiAoIWV4cGVjdGVkQW1vdW50LmlzRXF1YWxUbyh0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYW1vdW50KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ25vcm1hbCB0cmFuc2FjdGlvbiBhbW91bnQgaW4gdHhQcmVidWlsZCByZWNlaXZlZCBmcm9tIEJpdEdvIHNlcnZlcnMgZG9lcyBub3QgbWF0Y2ggdHhQYXJhbXMgc3VwcGxpZWQgYnkgY2xpZW50J1xuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKFxuICAgICAgICB0aGlzLmlzRVRIQWRkcmVzcyh0eFBhcmFtcy5yZWNpcGllbnRzWzBdLmFkZHJlc3MpICYmXG4gICAgICAgIHR4UGFyYW1zLnJlY2lwaWVudHNbMF0uYWRkcmVzcyAhPT0gdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFkZHJlc3NcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Rlc3RpbmF0aW9uIGFkZHJlc3MgaW4gbm9ybWFsIHR4UHJlYnVpbGQgZG9lcyBub3QgbWF0Y2ggdGhhdCBpbiB0eFBhcmFtcyBzdXBwbGllZCBieSBjbGllbnQnKTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gQ2hlY2sgY29pbiBpcyBjb3JyZWN0IGZvciBhbGwgdHJhbnNhY3Rpb24gdHlwZXNcbiAgICBpZiAoIXRoaXMudmVyaWZ5Q29pbih0eFByZWJ1aWxkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBjb2luIGluIHR4UHJlYnVpbGQgZGlkIG5vdCBtYXRjaCB0aGF0IGluIHR4UGFyYW1zIHN1cHBsaWVkIGJ5IGNsaWVudGApO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhZGRyZXNzIGlzIHZhbGlkIGV0aCBhZGRyZXNzXG4gICAqIEBwYXJhbSBhZGRyZXNzXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgcHJpdmF0ZSBpc0VUSEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhYWRkcmVzcy5tYXRjaCgvMHhbYS1mQS1GMC05XXs0MH0vKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2Zvcm0gbWVzc2FnZSB0byBhY2NvbW1vZGF0ZSBzcGVjaWZpYyBibG9ja2NoYWluIHJlcXVpcmVtZW50cy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSB0aGUgbWVzc2FnZSB0byBwcmVwYXJlXG4gICAqIEByZXR1cm4ge3N0cmluZ30gdGhlIHByZXBhcmVkIG1lc3NhZ2UuXG4gICAqL1xuICBlbmNvZGVNZXNzYWdlKG1lc3NhZ2U6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcHJlZml4ID0gYFxcdTAwMTlFdGhlcmV1bSBTaWduZWQgTWVzc2FnZTpcXG4ke21lc3NhZ2UubGVuZ3RofWA7XG4gICAgcmV0dXJuIHByZWZpeC5jb25jYXQobWVzc2FnZSk7XG4gIH1cblxuICAvKipcbiAgICogVHJhbnNmb3JtIHRoZSBUeXBlZCBkYXRhIHRvIGFjY29tb2RhdGUgdGhlIGJsb2NrY2hhaW4gcmVxdWlyZW1lbnRzIChFSVAtNzEyKVxuICAgKiBAcGFyYW0ge1R5cGVkRGF0YX0gdHlwZWREYXRhIC0gdGhlIHR5cGVkIGRhdGEgdG8gcHJlcGFyZVxuICAgKiBAcmV0dXJuIHtCdWZmZXJ9IGEgYnVmZmVyIG9mIHRoZSByZXN1bHRcbiAgICovXG4gIGVuY29kZVR5cGVkRGF0YSh0eXBlZERhdGE6IFR5cGVkRGF0YSk6IEJ1ZmZlciB7XG4gICAgY29uc3QgdmVyc2lvbiA9IHR5cGVkRGF0YS52ZXJzaW9uO1xuICAgIGlmICh2ZXJzaW9uID09PSBTaWduVHlwZWREYXRhVmVyc2lvbi5WMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdTaWduVHlwZWREYXRhIHYxIGlzIG5vdCBzdXBwb3J0ZWQgZHVlIHRvIHNlY3VyaXR5IGNvbmNlcm5zJyk7XG4gICAgfVxuICAgIGNvbnN0IHR5cGVkRGF0YVJhdyA9IEpTT04ucGFyc2UodHlwZWREYXRhLnR5cGVkRGF0YVJhdyk7XG4gICAgY29uc3Qgc2FuaXRpemVkRGF0YSA9IFR5cGVkRGF0YVV0aWxzLnNhbml0aXplRGF0YSh0eXBlZERhdGFSYXcgYXMgdW5rbm93biBhcyBUeXBlZE1lc3NhZ2U8YW55Pik7XG4gICAgY29uc3QgcGFydHMgPSBbQnVmZmVyLmZyb20oJzE5MDEnLCAnaGV4JyldO1xuICAgIGNvbnN0IGVpcDcxMkRvbWFpbiA9ICdFSVA3MTJEb21haW4nO1xuICAgIHBhcnRzLnB1c2goVHlwZWREYXRhVXRpbHMuaGFzaFN0cnVjdChlaXA3MTJEb21haW4sIHNhbml0aXplZERhdGEuZG9tYWluLCBzYW5pdGl6ZWREYXRhLnR5cGVzLCB2ZXJzaW9uKSk7XG5cbiAgICBpZiAoc2FuaXRpemVkRGF0YS5wcmltYXJ5VHlwZSAhPT0gZWlwNzEyRG9tYWluKSB7XG4gICAgICBwYXJ0cy5wdXNoKFxuICAgICAgICBUeXBlZERhdGFVdGlscy5oYXNoU3RydWN0KFxuICAgICAgICAgIHNhbml0aXplZERhdGEucHJpbWFyeVR5cGUgYXMgc3RyaW5nLFxuICAgICAgICAgIHNhbml0aXplZERhdGEubWVzc2FnZSxcbiAgICAgICAgICBzYW5pdGl6ZWREYXRhLnR5cGVzLFxuICAgICAgICAgIHZlcnNpb25cbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQocGFydHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIHRoZSBkYXRhIHRvIHRyYW5zZmVyIGFuIEVSQy03MjEgb3IgRVJDLTExNTUgdG9rZW4gdG8gYW5vdGhlciBhZGRyZXNzXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICovXG4gIGJ1aWxkTmZ0VHJhbnNmZXJEYXRhKHBhcmFtczogQnVpbGROZnRUcmFuc2ZlckRhdGFPcHRpb25zKTogc3RyaW5nIHtcbiAgICBjb25zdCB7IHRva2VuQ29udHJhY3RBZGRyZXNzLCByZWNpcGllbnRBZGRyZXNzLCBmcm9tQWRkcmVzcyB9ID0gcGFyYW1zO1xuICAgIHN3aXRjaCAocGFyYW1zLnR5cGUpIHtcbiAgICAgIGNhc2UgJ0VSQzcyMSc6IHtcbiAgICAgICAgY29uc3QgdG9rZW5JZCA9IHBhcmFtcy50b2tlbklkO1xuICAgICAgICBjb25zdCBjb250cmFjdERhdGEgPSBuZXcgRVJDNzIxVHJhbnNmZXJCdWlsZGVyKClcbiAgICAgICAgICAudG9rZW5Db250cmFjdEFkZHJlc3ModG9rZW5Db250cmFjdEFkZHJlc3MpXG4gICAgICAgICAgLnRvKHJlY2lwaWVudEFkZHJlc3MpXG4gICAgICAgICAgLmZyb20oZnJvbUFkZHJlc3MpXG4gICAgICAgICAgLnRva2VuSWQodG9rZW5JZClcbiAgICAgICAgICAuYnVpbGQoKTtcbiAgICAgICAgcmV0dXJuIGNvbnRyYWN0RGF0YTtcbiAgICAgIH1cblxuICAgICAgY2FzZSAnRVJDMTE1NSc6IHtcbiAgICAgICAgY29uc3QgZW50cmllcyA9IHBhcmFtcy5lbnRyaWVzO1xuICAgICAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSBuZXcgRVJDMTE1NVRyYW5zZmVyQnVpbGRlcigpXG4gICAgICAgICAgLnRva2VuQ29udHJhY3RBZGRyZXNzKHRva2VuQ29udHJhY3RBZGRyZXNzKVxuICAgICAgICAgIC50byhyZWNpcGllbnRBZGRyZXNzKVxuICAgICAgICAgIC5mcm9tKGZyb21BZGRyZXNzKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICB0cmFuc2ZlckJ1aWxkZXIuZW50cnkocGFyc2VJbnQoZW50cnkudG9rZW5JZCwgMTApLCBlbnRyeS5hbW91bnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRyYW5zZmVyQnVpbGRlci5idWlsZCgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl19
|