@bitgo/abstract-eth 24.9.3 → 24.10.1

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