@bitgo-beta/abstract-eth 1.2.3-alpha.50 → 1.2.3-alpha.500

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