@bitgo-beta/abstract-eth 1.2.3-alpha.47 → 1.2.3-alpha.470

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 (154) 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 +846 -0
  5. package/dist/src/abstractEthLikeNewCoins.d.ts.map +1 -0
  6. package/dist/src/abstractEthLikeNewCoins.js +2528 -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 +286 -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/contractCall.d.ts +8 -0
  14. package/dist/src/lib/contractCall.d.ts.map +1 -0
  15. package/dist/src/lib/contractCall.js +17 -0
  16. package/dist/src/lib/iface.d.ts +133 -0
  17. package/dist/src/lib/iface.d.ts.map +1 -0
  18. package/dist/src/lib/iface.js +8 -0
  19. package/dist/src/lib/index.d.ts +16 -0
  20. package/dist/src/lib/index.d.ts.map +1 -0
  21. package/dist/src/lib/index.js +57 -0
  22. package/dist/src/lib/keyPair.d.ts +26 -0
  23. package/dist/src/lib/keyPair.d.ts.map +1 -0
  24. package/dist/src/lib/keyPair.js +65 -0
  25. package/dist/src/lib/messages/eip191/eip191Message.d.ts +12 -0
  26. package/dist/src/lib/messages/eip191/eip191Message.d.ts.map +1 -0
  27. package/dist/src/lib/messages/eip191/eip191Message.js +25 -0
  28. package/dist/src/lib/messages/eip191/eip191MessageBuilder.d.ts +19 -0
  29. package/dist/src/lib/messages/eip191/eip191MessageBuilder.d.ts.map +1 -0
  30. package/dist/src/lib/messages/eip191/eip191MessageBuilder.js +27 -0
  31. package/dist/src/lib/messages/eip191/index.d.ts +3 -0
  32. package/dist/src/lib/messages/eip191/index.d.ts.map +1 -0
  33. package/dist/src/lib/messages/eip191/index.js +19 -0
  34. package/dist/src/lib/messages/eip712/eip712Message.d.ts +6 -0
  35. package/dist/src/lib/messages/eip712/eip712Message.d.ts.map +1 -0
  36. package/dist/src/lib/messages/eip712/eip712Message.js +27 -0
  37. package/dist/src/lib/messages/eip712/eip712MessageBuilder.d.ts +7 -0
  38. package/dist/src/lib/messages/eip712/eip712MessageBuilder.d.ts.map +1 -0
  39. package/dist/src/lib/messages/eip712/eip712MessageBuilder.js +15 -0
  40. package/dist/src/lib/messages/eip712/index.d.ts +3 -0
  41. package/dist/src/lib/messages/eip712/index.d.ts.map +1 -0
  42. package/dist/src/lib/messages/eip712/index.js +19 -0
  43. package/dist/src/lib/messages/index.d.ts +4 -0
  44. package/dist/src/lib/messages/index.d.ts.map +1 -0
  45. package/dist/src/lib/messages/index.js +20 -0
  46. package/dist/src/lib/messages/messageBuilderFactory.d.ts +7 -0
  47. package/dist/src/lib/messages/messageBuilderFactory.d.ts.map +1 -0
  48. package/dist/src/lib/messages/messageBuilderFactory.js +23 -0
  49. package/dist/src/lib/transaction.d.ts +67 -0
  50. package/dist/src/lib/transaction.d.ts.map +1 -0
  51. package/dist/src/lib/transaction.js +142 -0
  52. package/dist/src/lib/transactionBuilder.d.ts +270 -0
  53. package/dist/src/lib/transactionBuilder.d.ts.map +1 -0
  54. package/dist/src/lib/transactionBuilder.js +822 -0
  55. package/dist/src/lib/transferBuilder.d.ts +76 -0
  56. package/dist/src/lib/transferBuilder.d.ts.map +1 -0
  57. package/dist/src/lib/transferBuilder.js +307 -0
  58. package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.d.ts +54 -0
  59. package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.d.ts.map +1 -0
  60. package/dist/src/lib/transferBuilders/baseNFTTransferBuilder.js +120 -0
  61. package/dist/src/lib/transferBuilders/index.d.ts +4 -0
  62. package/dist/src/lib/transferBuilders/index.d.ts.map +1 -0
  63. package/dist/src/lib/transferBuilders/index.js +20 -0
  64. package/dist/src/lib/transferBuilders/transferBuilderERC1155.d.ts +17 -0
  65. package/dist/src/lib/transferBuilders/transferBuilderERC1155.d.ts.map +1 -0
  66. package/dist/src/lib/transferBuilders/transferBuilderERC1155.js +96 -0
  67. package/dist/src/lib/transferBuilders/transferBuilderERC721.d.ts +16 -0
  68. package/dist/src/lib/transferBuilders/transferBuilderERC721.d.ts.map +1 -0
  69. package/dist/src/lib/transferBuilders/transferBuilderERC721.js +81 -0
  70. package/dist/src/lib/types.d.ts +39 -0
  71. package/dist/src/lib/types.d.ts.map +1 -0
  72. package/dist/src/lib/types.js +137 -0
  73. package/dist/src/lib/utils.d.ts +310 -0
  74. package/dist/src/lib/utils.d.ts.map +1 -0
  75. package/dist/src/lib/utils.js +829 -0
  76. package/dist/src/lib/walletUtil.d.ts +40 -0
  77. package/dist/src/lib/walletUtil.d.ts.map +1 -0
  78. package/dist/src/lib/walletUtil.js +43 -0
  79. package/dist/src/types.d.ts +9 -0
  80. package/dist/src/types.d.ts.map +1 -0
  81. package/dist/src/types.js +3 -0
  82. package/dist/test/index.d.ts +2 -0
  83. package/dist/test/index.d.ts.map +1 -0
  84. package/dist/test/index.js +18 -0
  85. package/dist/test/unit/coin.d.ts +8 -0
  86. package/dist/test/unit/coin.d.ts.map +1 -0
  87. package/dist/test/unit/coin.js +577 -0
  88. package/dist/test/unit/index.d.ts +6 -0
  89. package/dist/test/unit/index.d.ts.map +1 -0
  90. package/dist/test/unit/index.js +22 -0
  91. package/dist/test/unit/messages/abstractEthMessageBuilderTests.d.ts +3 -0
  92. package/dist/test/unit/messages/abstractEthMessageBuilderTests.d.ts.map +1 -0
  93. package/dist/test/unit/messages/abstractEthMessageBuilderTests.js +110 -0
  94. package/dist/test/unit/messages/abstractEthMessageTestTypes.d.ts +43 -0
  95. package/dist/test/unit/messages/abstractEthMessageTestTypes.d.ts.map +1 -0
  96. package/dist/test/unit/messages/abstractEthMessageTestTypes.js +3 -0
  97. package/dist/test/unit/messages/abstractEthMessagesTests.d.ts +3 -0
  98. package/dist/test/unit/messages/abstractEthMessagesTests.d.ts.map +1 -0
  99. package/dist/test/unit/messages/abstractEthMessagesTests.js +129 -0
  100. package/dist/test/unit/messages/eip191/eip191Message.d.ts +2 -0
  101. package/dist/test/unit/messages/eip191/eip191Message.d.ts.map +1 -0
  102. package/dist/test/unit/messages/eip191/eip191Message.js +15 -0
  103. package/dist/test/unit/messages/eip191/eip191MessageBuilder.d.ts +2 -0
  104. package/dist/test/unit/messages/eip191/eip191MessageBuilder.d.ts.map +1 -0
  105. package/dist/test/unit/messages/eip191/eip191MessageBuilder.js +16 -0
  106. package/dist/test/unit/messages/eip191/fixtures.d.ts +109 -0
  107. package/dist/test/unit/messages/eip191/fixtures.d.ts.map +1 -0
  108. package/dist/test/unit/messages/eip191/fixtures.js +63 -0
  109. package/dist/test/unit/messages/eip712/eip712Message.d.ts +2 -0
  110. package/dist/test/unit/messages/eip712/eip712Message.d.ts.map +1 -0
  111. package/dist/test/unit/messages/eip712/eip712Message.js +15 -0
  112. package/dist/test/unit/messages/eip712/eip712MessageBuilder.d.ts +2 -0
  113. package/dist/test/unit/messages/eip712/eip712MessageBuilder.d.ts.map +1 -0
  114. package/dist/test/unit/messages/eip712/eip712MessageBuilder.js +16 -0
  115. package/dist/test/unit/messages/eip712/fixtures.d.ts +76 -0
  116. package/dist/test/unit/messages/eip712/fixtures.d.ts.map +1 -0
  117. package/dist/test/unit/messages/eip712/fixtures.js +120 -0
  118. package/dist/test/unit/messages/index.d.ts +4 -0
  119. package/dist/test/unit/messages/index.d.ts.map +1 -0
  120. package/dist/test/unit/messages/index.js +20 -0
  121. package/dist/test/unit/messages/messageBuilderFactory.d.ts +2 -0
  122. package/dist/test/unit/messages/messageBuilderFactory.d.ts.map +1 -0
  123. package/dist/test/unit/messages/messageBuilderFactory.js +52 -0
  124. package/dist/test/unit/token.d.ts +2 -0
  125. package/dist/test/unit/token.d.ts.map +1 -0
  126. package/dist/test/unit/token.js +37 -0
  127. package/dist/test/unit/transaction.d.ts +3 -0
  128. package/dist/test/unit/transaction.d.ts.map +1 -0
  129. package/dist/test/unit/transaction.js +60 -0
  130. package/dist/test/unit/transactionBuilder/addressInitialization.d.ts +8 -0
  131. package/dist/test/unit/transactionBuilder/addressInitialization.d.ts.map +1 -0
  132. package/dist/test/unit/transactionBuilder/addressInitialization.js +95 -0
  133. package/dist/test/unit/transactionBuilder/flushNft.d.ts +2 -0
  134. package/dist/test/unit/transactionBuilder/flushNft.d.ts.map +1 -0
  135. package/dist/test/unit/transactionBuilder/flushNft.js +381 -0
  136. package/dist/test/unit/transactionBuilder/index.d.ts +5 -0
  137. package/dist/test/unit/transactionBuilder/index.d.ts.map +1 -0
  138. package/dist/test/unit/transactionBuilder/index.js +21 -0
  139. package/dist/test/unit/transactionBuilder/send.d.ts +3 -0
  140. package/dist/test/unit/transactionBuilder/send.d.ts.map +1 -0
  141. package/dist/test/unit/transactionBuilder/send.js +197 -0
  142. package/dist/test/unit/transactionBuilder/walletInitialization.d.ts +10 -0
  143. package/dist/test/unit/transactionBuilder/walletInitialization.d.ts.map +1 -0
  144. package/dist/test/unit/transactionBuilder/walletInitialization.js +124 -0
  145. package/dist/test/unit/transferBuilder.d.ts +2 -0
  146. package/dist/test/unit/transferBuilder.d.ts.map +1 -0
  147. package/dist/test/unit/transferBuilder.js +76 -0
  148. package/dist/test/unit/utils.d.ts +2 -0
  149. package/dist/test/unit/utils.d.ts.map +1 -0
  150. package/dist/test/unit/utils.js +184 -0
  151. package/dist/tsconfig.tsbuildinfo +1 -8436
  152. package/package.json +34 -10
  153. package/.eslintignore +0 -5
  154. package/CHANGELOG.md +0 -178
@@ -0,0 +1,2528 @@
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 optimism chain, L1 fees is to be paid as well apart from L2 fees
935
+ // So we are adding the amount that can be used up as l1 fees
936
+ if (this.staticsCoin?.family === 'opeth') {
937
+ totalGasNeeded = totalGasNeeded.add(new exports.optionalDeps.ethUtil.BN(statics_1.ethGasConfigs.opethGasL1Fees));
938
+ }
939
+ const weiToGwei = 10 ** 9;
940
+ if (backupKeyBalance.lt(totalGasNeeded)) {
941
+ throw new Error(`Backup key address ${backupKeyAddress} has balance ${(backupKeyBalance / weiToGwei).toString()} Gwei.` +
942
+ `This address must have a balance of at least ${(totalGasNeeded / weiToGwei).toString()}` +
943
+ ` Gwei to perform recoveries. Try sending some funds to this address then retry.`);
944
+ }
945
+ // get balance of wallet
946
+ const txAmount = await this.queryAddressBalance(params.walletContractAddress, params.apiKey);
947
+ if (new bignumber_js_1.BigNumber(txAmount).isLessThanOrEqualTo(0)) {
948
+ throw new Error('Wallet does not have enough funds to recover');
949
+ }
950
+ // build recipients object
951
+ const recipients = [
952
+ {
953
+ address: params.recoveryDestination,
954
+ amount: txAmount.toString(10),
955
+ },
956
+ ];
957
+ // Get sequence ID using contract call
958
+ // we need to wait between making two explorer api calls to avoid getting banned
959
+ await new Promise((resolve) => setTimeout(resolve, 1000));
960
+ const sequenceId = await this.querySequenceId(params.walletContractAddress, params.apiKey);
961
+ let operationHash, signature;
962
+ // Get operation hash and sign it
963
+ if (!isUnsignedSweep) {
964
+ operationHash = this.getOperationSha3ForExecuteAndConfirm(recipients, this.getDefaultExpireTime(), sequenceId);
965
+ signature = sdk_core_1.Util.ethSignMsgHash(operationHash, sdk_core_1.Util.xprvToEthPrivateKey(userKey));
966
+ try {
967
+ sdk_core_1.Util.ecRecoverEthAddress(operationHash, signature);
968
+ }
969
+ catch (e) {
970
+ throw new Error('Invalid signature');
971
+ }
972
+ }
973
+ const txInfo = {
974
+ recipient: recipients[0],
975
+ expireTime: this.getDefaultExpireTime(),
976
+ contractSequenceId: sequenceId,
977
+ operationHash: operationHash,
978
+ signature: signature,
979
+ gasLimit: gasLimit.toString(10),
980
+ };
981
+ const txBuilder = this.getTransactionBuilder(params.common);
982
+ txBuilder.counter(backupKeyNonce);
983
+ txBuilder.contract(params.walletContractAddress);
984
+ let txFee;
985
+ if (params.eip1559) {
986
+ txFee = {
987
+ eip1559: {
988
+ maxPriorityFeePerGas: params.eip1559.maxPriorityFeePerGas,
989
+ maxFeePerGas: params.eip1559.maxFeePerGas,
990
+ },
991
+ };
992
+ }
993
+ else {
994
+ txFee = { fee: gasPrice.toString() };
995
+ }
996
+ txBuilder.fee({
997
+ ...txFee,
998
+ gasLimit: gasLimit.toString(),
999
+ });
1000
+ const transferBuilder = txBuilder.transfer();
1001
+ transferBuilder
1002
+ .coin(this.staticsCoin?.name)
1003
+ .amount(recipients[0].amount)
1004
+ .contractSequenceId(sequenceId)
1005
+ .expirationTime(this.getDefaultExpireTime())
1006
+ .to(params.recoveryDestination);
1007
+ const tx = await txBuilder.build();
1008
+ if (isUnsignedSweep) {
1009
+ const response = {
1010
+ txHex: tx.toBroadcastFormat(),
1011
+ userKey,
1012
+ backupKey,
1013
+ coin: this.getChain(),
1014
+ gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
1015
+ gasLimit,
1016
+ recipients: [txInfo.recipient],
1017
+ walletContractAddress: tx.toJson().to,
1018
+ amount: txInfo.recipient.amount,
1019
+ backupKeyNonce,
1020
+ eip1559: params.eip1559,
1021
+ };
1022
+ lodash_1.default.extend(response, txInfo);
1023
+ response.nextContractSequenceId = response.contractSequenceId;
1024
+ return response;
1025
+ }
1026
+ txBuilder
1027
+ .transfer()
1028
+ .coin(this.staticsCoin?.name)
1029
+ .key(new lib_1.KeyPair({ prv: userKey }).getKeys().prv);
1030
+ txBuilder.sign({ key: backupSigningKey });
1031
+ const signedTx = await txBuilder.build();
1032
+ return {
1033
+ id: signedTx.toJson().id,
1034
+ tx: signedTx.toBroadcastFormat(),
1035
+ };
1036
+ }
1037
+ /**
1038
+ * Extract recipients from transaction hex
1039
+ * @param txHex - The transaction hex string
1040
+ * @returns Array of recipients with address and amount
1041
+ */
1042
+ async extractRecipientsFromTxHex(txHex) {
1043
+ const txBuffer = exports.optionalDeps.ethUtil.toBuffer(txHex);
1044
+ const decodedTx = exports.optionalDeps.EthTx.TransactionFactory.fromSerializedData(txBuffer);
1045
+ const recipients = [];
1046
+ if (decodedTx.data && decodedTx.data.length > 0) {
1047
+ const dataHex = exports.optionalDeps.ethUtil.bufferToHex(decodedTx.data);
1048
+ const transferData = (0, lib_1.decodeTransferData)(dataHex);
1049
+ if (transferData.to) {
1050
+ recipients.push({
1051
+ address: transferData.to,
1052
+ amount: transferData.amount,
1053
+ });
1054
+ }
1055
+ }
1056
+ return recipients;
1057
+ }
1058
+ async sendCrossChainRecoveryTransaction(params) {
1059
+ const buildResponse = await this.buildCrossChainRecoveryTransaction(params.recoveryId);
1060
+ if (params.walletType === 'cold') {
1061
+ return buildResponse;
1062
+ }
1063
+ if (!params.encryptedPrv) {
1064
+ throw new Error('missing encryptedPrv');
1065
+ }
1066
+ let userKeyPrv;
1067
+ try {
1068
+ userKeyPrv = this.bitgo.decrypt({
1069
+ input: params.encryptedPrv,
1070
+ password: params.walletPassphrase,
1071
+ });
1072
+ }
1073
+ catch (e) {
1074
+ throw new Error(`Error decrypting user keychain: ${e.message}`);
1075
+ }
1076
+ const keyPair = new lib_1.KeyPair({ prv: userKeyPrv });
1077
+ const userSigningKey = keyPair.getKeys().prv;
1078
+ if (!userSigningKey) {
1079
+ throw new Error('no private key');
1080
+ }
1081
+ const txBuilder = this.getTransactionBuilder(params.common);
1082
+ const txHex = buildResponse.txHex;
1083
+ txBuilder.from(txHex);
1084
+ if (buildResponse.walletVersion) {
1085
+ // If walletVersion is provided, set it in the txBuilder
1086
+ txBuilder.walletVersion(buildResponse.walletVersion);
1087
+ }
1088
+ txBuilder
1089
+ .transfer()
1090
+ .coin(this.staticsCoin?.name)
1091
+ .key(userSigningKey);
1092
+ const tx = await txBuilder.build();
1093
+ const res = await this.bitgo
1094
+ .post(this.bitgo.microservicesUrl(`/api/recovery/v1/crosschain/${params.recoveryId}/sign`))
1095
+ .send({ txHex: tx.toBroadcastFormat() });
1096
+ return {
1097
+ coin: this.staticsCoin?.name,
1098
+ txid: res.body.txid,
1099
+ };
1100
+ }
1101
+ async buildCrossChainRecoveryTransaction(recoveryId) {
1102
+ const res = await this.bitgo.get(this.bitgo.microservicesUrl(`/api/recovery/v1/crosschain/${recoveryId}/buildtx`));
1103
+ // Extract recipients from the transaction hex
1104
+ const recipients = await this.extractRecipientsFromTxHex(res.body.txHex);
1105
+ return {
1106
+ coin: res.body.coin,
1107
+ txHex: res.body.txHex,
1108
+ txid: res.body.txid,
1109
+ walletVersion: res.body.walletVersion,
1110
+ recipients,
1111
+ };
1112
+ }
1113
+ /**
1114
+ * Builds a unsigned (for cold, custody wallet) or
1115
+ * half-signed (for hot wallet) evm cross chain recovery transaction with
1116
+ * same expected arguments as recover method.
1117
+ * This helps recover funds from evm based wrong chain.
1118
+ * @param {RecoverOptions} params
1119
+ * @returns {Promise<RecoveryInfo | OfflineVaultTxInfo>}
1120
+ */
1121
+ async recoverEthLikeforEvmBasedRecovery(params) {
1122
+ this.validateEvmBasedRecoveryParams(params);
1123
+ // Clean up whitespace from entered values
1124
+ const userKey = params.userKey.replace(/\s/g, '');
1125
+ const bitgoFeeAddress = params.bitgoFeeAddress?.replace(/\s/g, '').toLowerCase();
1126
+ const bitgoDestinationAddress = params.bitgoDestinationAddress?.replace(/\s/g, '').toLowerCase();
1127
+ const recoveryDestination = params.recoveryDestination?.replace(/\s/g, '').toLowerCase();
1128
+ const walletContractAddress = params.walletContractAddress?.replace(/\s/g, '').toLowerCase();
1129
+ const tokenContractAddress = params.tokenContractAddress?.replace(/\s/g, '').toLowerCase();
1130
+ let userSigningKey;
1131
+ let userKeyPrv;
1132
+ if (params.walletPassphrase) {
1133
+ if (!userKey.startsWith('xpub') && !userKey.startsWith('xprv')) {
1134
+ try {
1135
+ userKeyPrv = this.bitgo.decrypt({
1136
+ input: userKey,
1137
+ password: params.walletPassphrase,
1138
+ });
1139
+ }
1140
+ catch (e) {
1141
+ throw new Error(`Error decrypting user keychain: ${e.message}`);
1142
+ }
1143
+ }
1144
+ const keyPair = new lib_1.KeyPair({ prv: userKeyPrv });
1145
+ userSigningKey = keyPair.getKeys().prv;
1146
+ if (!userSigningKey) {
1147
+ throw new Error('no private key');
1148
+ }
1149
+ }
1150
+ // Use default gasLimit for cold and custody wallets
1151
+ let gasLimit = params.gasLimit || userKey.startsWith('xpub') || !userKey
1152
+ ? new exports.optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit))
1153
+ : new exports.optionalDeps.ethUtil.BN(0);
1154
+ const gasPrice = params.eip1559
1155
+ ? new exports.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas)
1156
+ : params.gasPrice
1157
+ ? new exports.optionalDeps.ethUtil.BN(this.setGasPrice(params.gasPrice))
1158
+ : await this.getGasPriceFromExternalAPI(this.staticsCoin?.name, params.apiKey);
1159
+ const bitgoFeeAddressNonce = await this.getAddressNonce(bitgoFeeAddress, params.apiKey);
1160
+ if (tokenContractAddress) {
1161
+ return this.recoverEthLikeTokenforEvmBasedRecovery(params, bitgoFeeAddressNonce, gasLimit, gasPrice, userKey, userSigningKey, params.apiKey);
1162
+ }
1163
+ // get balance of wallet
1164
+ const txAmount = await this.queryAddressBalance(walletContractAddress, params.apiKey);
1165
+ const bitgoFeePercentage = 0; // TODO: BG-71912 can change the fee% here.
1166
+ const bitgoFeeAmount = txAmount * (bitgoFeePercentage / 100);
1167
+ // build recipients object
1168
+ const recipients = [
1169
+ {
1170
+ address: recoveryDestination,
1171
+ amount: new bignumber_js_1.BigNumber(txAmount).minus(bitgoFeeAmount).toFixed(),
1172
+ },
1173
+ ];
1174
+ if (bitgoFeePercentage > 0) {
1175
+ if (lodash_1.default.isUndefined(bitgoDestinationAddress) || !this.isValidAddress(bitgoDestinationAddress)) {
1176
+ throw new Error('invalid bitgoDestinationAddress');
1177
+ }
1178
+ recipients.push({
1179
+ address: bitgoDestinationAddress,
1180
+ amount: bitgoFeeAmount.toString(10),
1181
+ });
1182
+ }
1183
+ // calculate batch data
1184
+ const BATCH_METHOD_NAME = 'batch';
1185
+ const BATCH_METHOD_TYPES = ['address[]', 'uint256[]'];
1186
+ const batchExecutionInfo = this.getBatchExecutionInfo(recipients);
1187
+ const batchData = exports.optionalDeps.ethUtil.addHexPrefix(this.getMethodCallData(BATCH_METHOD_NAME, BATCH_METHOD_TYPES, batchExecutionInfo.values).toString('hex'));
1188
+ // Get sequence ID using contract call
1189
+ // we need to wait between making two explorer api calls to avoid getting banned
1190
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1191
+ const sequenceId = await this.querySequenceId(walletContractAddress, params.apiKey);
1192
+ const network = this.getNetwork();
1193
+ const batcherContractAddress = network?.batcherContractAddress;
1194
+ const txBuilder = this.getTransactionBuilder(params.common);
1195
+ txBuilder.counter(bitgoFeeAddressNonce);
1196
+ txBuilder.contract(walletContractAddress);
1197
+ let txFee;
1198
+ if (params.eip1559) {
1199
+ txFee = {
1200
+ eip1559: {
1201
+ maxPriorityFeePerGas: params.eip1559.maxPriorityFeePerGas,
1202
+ maxFeePerGas: params.eip1559.maxFeePerGas,
1203
+ },
1204
+ };
1205
+ }
1206
+ else {
1207
+ txFee = { fee: gasPrice.toString() };
1208
+ }
1209
+ txBuilder.fee({
1210
+ ...txFee,
1211
+ gasLimit: gasLimit.toString(),
1212
+ });
1213
+ const transferBuilder = txBuilder.transfer();
1214
+ if (!batcherContractAddress) {
1215
+ transferBuilder
1216
+ .coin(this.staticsCoin?.name)
1217
+ .amount(batchExecutionInfo.totalAmount)
1218
+ .contractSequenceId(sequenceId)
1219
+ .expirationTime(this.getDefaultExpireTime())
1220
+ .to(recoveryDestination);
1221
+ }
1222
+ else {
1223
+ transferBuilder
1224
+ .coin(this.staticsCoin?.name)
1225
+ .amount(batchExecutionInfo.totalAmount)
1226
+ .contractSequenceId(sequenceId)
1227
+ .expirationTime(this.getDefaultExpireTime())
1228
+ .to(batcherContractAddress)
1229
+ .data(batchData);
1230
+ }
1231
+ if (params.walletPassphrase) {
1232
+ transferBuilder.key(userSigningKey);
1233
+ }
1234
+ // If the intended chain is arbitrum or optimism, we need to use wallet version 4
1235
+ // since these contracts construct operationHash differently
1236
+ if (params.intendedChain && ['arbeth', 'opeth'].includes(statics_1.coins.get(params.intendedChain).family)) {
1237
+ txBuilder.walletVersion(4);
1238
+ }
1239
+ // If gasLimit was not passed as a param or if it is not cold/custody wallet, then fetch the gasLimit from Explorer
1240
+ if (!params.gasLimit && userKey && !userKey.startsWith('xpub')) {
1241
+ const sendData = txBuilder.getSendData();
1242
+ gasLimit = await this.getGasLimitFromExternalAPI(params.intendedChain, params.bitgoFeeAddress, params.walletContractAddress, sendData, params.apiKey);
1243
+ txBuilder.fee({
1244
+ ...txFee,
1245
+ gasLimit: gasLimit.toString(),
1246
+ });
1247
+ }
1248
+ // Get the balance of bitgoFeeAddress to ensure funds are available to pay fees
1249
+ await this.ensureSufficientBalance(bitgoFeeAddress, gasPrice, gasLimit, params.apiKey);
1250
+ const tx = await txBuilder.build();
1251
+ const txInfo = {
1252
+ recipients: recipients,
1253
+ expireTime: this.getDefaultExpireTime(),
1254
+ contractSequenceId: sequenceId,
1255
+ gasLimit: gasLimit.toString(10),
1256
+ isEvmBasedCrossChainRecovery: true,
1257
+ };
1258
+ const response = {
1259
+ txHex: tx.toBroadcastFormat(),
1260
+ userKey,
1261
+ coin: this.getChain(),
1262
+ gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
1263
+ gasLimit,
1264
+ recipients: txInfo.recipients,
1265
+ walletContractAddress: tx.toJson().to,
1266
+ amount: batchExecutionInfo.totalAmount,
1267
+ backupKeyNonce: bitgoFeeAddressNonce,
1268
+ eip1559: params.eip1559,
1269
+ ...(txBuilder.getWalletVersion() === 4 ? { walletVersion: txBuilder.getWalletVersion() } : {}),
1270
+ };
1271
+ lodash_1.default.extend(response, txInfo);
1272
+ response.nextContractSequenceId = response.contractSequenceId;
1273
+ if (params.walletPassphrase) {
1274
+ const halfSignedTxn = {
1275
+ halfSigned: {
1276
+ txHex: tx.toBroadcastFormat(),
1277
+ recipients: txInfo.recipients,
1278
+ expireTime: txInfo.expireTime,
1279
+ },
1280
+ };
1281
+ lodash_1.default.extend(response, halfSignedTxn);
1282
+ const feesUsed = {
1283
+ gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
1284
+ gasLimit: exports.optionalDeps.ethUtil.bufferToInt(gasLimit).toFixed(),
1285
+ };
1286
+ response['feesUsed'] = feesUsed;
1287
+ }
1288
+ return response;
1289
+ }
1290
+ /**
1291
+ * Query explorer for the balance of an address for a token
1292
+ * @param {string} tokenContractAddress - address where the token smart contract is hosted
1293
+ * @param {string} walletContractAddress - address of the wallet
1294
+ * @param {string} apiKey - optional API key to use instead of the one from the environment
1295
+ * @returns {BigNumber} token balaance in base units
1296
+ */
1297
+ async queryAddressTokenBalance(tokenContractAddress, walletContractAddress, apiKey) {
1298
+ if (!exports.optionalDeps.ethUtil.isValidAddress(tokenContractAddress)) {
1299
+ throw new Error('cannot get balance for invalid token address');
1300
+ }
1301
+ if (!exports.optionalDeps.ethUtil.isValidAddress(walletContractAddress)) {
1302
+ throw new Error('cannot get token balance for invalid wallet address');
1303
+ }
1304
+ const result = await this.recoveryBlockchainExplorerQuery({
1305
+ chainid: this.getChainId().toString(),
1306
+ module: 'account',
1307
+ action: 'tokenbalance',
1308
+ contractaddress: tokenContractAddress,
1309
+ address: walletContractAddress,
1310
+ tag: 'latest',
1311
+ }, apiKey);
1312
+ // throw if the result does not exist or the result is not a valid number
1313
+ if (!result || !result.result || isNaN(result.result)) {
1314
+ throw new Error(`Could not obtain token address balance for ${tokenContractAddress} from Etherscan, got: ${result.result}`);
1315
+ }
1316
+ return new exports.optionalDeps.ethUtil.BN(result.result, 10);
1317
+ }
1318
+ async recoverEthLikeTokenforEvmBasedRecovery(params, bitgoFeeAddressNonce, gasLimit, gasPrice, userKey, userSigningKey, apiKey) {
1319
+ // get token balance of wallet
1320
+ const txAmount = await this.queryAddressTokenBalance(params.tokenContractAddress, params.walletContractAddress, apiKey);
1321
+ // build recipients object
1322
+ const recipients = [
1323
+ {
1324
+ address: params.recoveryDestination,
1325
+ amount: new bignumber_js_1.BigNumber(txAmount).toFixed(),
1326
+ },
1327
+ ];
1328
+ // Get sequence ID using contract call
1329
+ // we need to wait between making two explorer api calls to avoid getting banned
1330
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1331
+ const sequenceId = await this.querySequenceId(params.walletContractAddress, params.apiKey);
1332
+ const txBuilder = this.getTransactionBuilder(params.common);
1333
+ txBuilder.counter(bitgoFeeAddressNonce);
1334
+ txBuilder.contract(params.walletContractAddress);
1335
+ let txFee;
1336
+ if (params.eip1559) {
1337
+ txFee = {
1338
+ eip1559: {
1339
+ maxPriorityFeePerGas: params.eip1559.maxPriorityFeePerGas,
1340
+ maxFeePerGas: params.eip1559.maxFeePerGas,
1341
+ },
1342
+ };
1343
+ }
1344
+ else {
1345
+ txFee = { fee: gasPrice.toString() };
1346
+ }
1347
+ txBuilder.fee({
1348
+ ...txFee,
1349
+ gasLimit: gasLimit.toString(),
1350
+ });
1351
+ const transferBuilder = txBuilder.transfer();
1352
+ const network = this.getNetwork();
1353
+ const token = (0, lib_1.getToken)(params.tokenContractAddress, network, this.staticsCoin?.family)?.name;
1354
+ transferBuilder
1355
+ .amount(txAmount)
1356
+ .contractSequenceId(sequenceId)
1357
+ .expirationTime(this.getDefaultExpireTime())
1358
+ .to(params.recoveryDestination);
1359
+ if (token) {
1360
+ transferBuilder.coin(token);
1361
+ }
1362
+ else {
1363
+ transferBuilder
1364
+ .coin(this.staticsCoin?.name)
1365
+ .tokenContractAddress(params.tokenContractAddress);
1366
+ }
1367
+ if (params.walletPassphrase) {
1368
+ txBuilder.transfer().key(userSigningKey);
1369
+ }
1370
+ // If the intended chain is arbitrum or optimism, we need to use wallet version 4
1371
+ // since these contracts construct operationHash differently
1372
+ if (params.intendedChain && ['arbeth', 'opeth'].includes(statics_1.coins.get(params.intendedChain).family)) {
1373
+ txBuilder.walletVersion(4);
1374
+ }
1375
+ if (!params.gasLimit && userKey && !userKey.startsWith('xpub')) {
1376
+ const sendData = txBuilder.getSendData();
1377
+ gasLimit = await this.getGasLimitFromExternalAPI(params.intendedChain, params.bitgoFeeAddress, params.walletContractAddress, sendData, apiKey);
1378
+ txBuilder.fee({
1379
+ ...txFee,
1380
+ gasLimit: gasLimit.toString(),
1381
+ });
1382
+ }
1383
+ // Get the balance of bitgoFeeAddress to ensure funds are available to pay fees
1384
+ await this.ensureSufficientBalance(params.bitgoFeeAddress, gasPrice, gasLimit, params.apiKey);
1385
+ const tx = await txBuilder.build();
1386
+ const txInfo = {
1387
+ recipients: recipients,
1388
+ expireTime: this.getDefaultExpireTime(),
1389
+ contractSequenceId: sequenceId,
1390
+ gasLimit: gasLimit.toString(10),
1391
+ isEvmBasedCrossChainRecovery: true,
1392
+ };
1393
+ const response = {
1394
+ txHex: tx.toBroadcastFormat(),
1395
+ userKey,
1396
+ coin: token ? token : this.getChain(),
1397
+ gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
1398
+ gasLimit,
1399
+ recipients: txInfo.recipients,
1400
+ walletContractAddress: tx.toJson().to,
1401
+ amount: txAmount.toString(),
1402
+ backupKeyNonce: bitgoFeeAddressNonce,
1403
+ eip1559: params.eip1559,
1404
+ ...(txBuilder.getWalletVersion() === 4 ? { walletVersion: txBuilder.getWalletVersion() } : {}),
1405
+ };
1406
+ lodash_1.default.extend(response, txInfo);
1407
+ response.nextContractSequenceId = response.contractSequenceId;
1408
+ if (params.walletPassphrase) {
1409
+ const halfSignedTxn = {
1410
+ halfSigned: {
1411
+ txHex: tx.toBroadcastFormat(),
1412
+ recipients: txInfo.recipients,
1413
+ expireTime: txInfo.expireTime,
1414
+ },
1415
+ };
1416
+ lodash_1.default.extend(response, halfSignedTxn);
1417
+ const feesUsed = {
1418
+ gasPrice: exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed(),
1419
+ gasLimit: exports.optionalDeps.ethUtil.bufferToInt(gasLimit).toFixed(),
1420
+ };
1421
+ response['feesUsed'] = feesUsed;
1422
+ }
1423
+ return response;
1424
+ }
1425
+ /**
1426
+ * Validate evm based cross chain recovery params
1427
+ * @param params {RecoverOptions}
1428
+ * @returns {void}
1429
+ */
1430
+ validateEvmBasedRecoveryParams(params) {
1431
+ if (lodash_1.default.isUndefined(params.bitgoFeeAddress) || !this.isValidAddress(params.bitgoFeeAddress)) {
1432
+ throw new Error('invalid bitgoFeeAddress');
1433
+ }
1434
+ if (lodash_1.default.isUndefined(params.walletContractAddress) || !this.isValidAddress(params.walletContractAddress)) {
1435
+ throw new Error('invalid walletContractAddress');
1436
+ }
1437
+ if (lodash_1.default.isUndefined(params.recoveryDestination) || !this.isValidAddress(params.recoveryDestination)) {
1438
+ throw new Error('invalid recoveryDestination');
1439
+ }
1440
+ }
1441
+ /**
1442
+ * Return types, values, and total amount in wei to send in a batch transaction, using the method signature
1443
+ * `distributeBatch(address[], uint256[])`
1444
+ * @param {Recipient[]} recipients - transaction recipients
1445
+ * @returns {GetBatchExecutionInfoRT} information needed to execute the batch transaction
1446
+ */
1447
+ getBatchExecutionInfo(recipients) {
1448
+ const addresses = [];
1449
+ const amounts = [];
1450
+ let sum = new bignumber_js_1.BigNumber('0');
1451
+ lodash_1.default.forEach(recipients, ({ address, amount }) => {
1452
+ addresses.push(address);
1453
+ amounts.push(amount);
1454
+ sum = sum.plus(amount);
1455
+ });
1456
+ return {
1457
+ values: [addresses, amounts],
1458
+ totalAmount: sum.toFixed(),
1459
+ };
1460
+ }
1461
+ /**
1462
+ * Build arguments to call the send method on the wallet contract
1463
+ * @param txInfo
1464
+ */
1465
+ getSendMethodArgs(txInfo) {
1466
+ // Method signature is
1467
+ // sendMultiSig(address toAddress, uint value, bytes data, uint expireTime, uint sequenceId, bytes signature)
1468
+ return [
1469
+ {
1470
+ name: 'toAddress',
1471
+ type: 'address',
1472
+ value: txInfo.recipient.address,
1473
+ },
1474
+ {
1475
+ name: 'value',
1476
+ type: 'uint',
1477
+ value: txInfo.recipient.amount,
1478
+ },
1479
+ {
1480
+ name: 'data',
1481
+ type: 'bytes',
1482
+ value: exports.optionalDeps.ethUtil.toBuffer(exports.optionalDeps.ethUtil.addHexPrefix(txInfo.recipient.data || '')),
1483
+ },
1484
+ {
1485
+ name: 'expireTime',
1486
+ type: 'uint',
1487
+ value: txInfo.expireTime,
1488
+ },
1489
+ {
1490
+ name: 'sequenceId',
1491
+ type: 'uint',
1492
+ value: txInfo.contractSequenceId,
1493
+ },
1494
+ {
1495
+ name: 'signature',
1496
+ type: 'bytes',
1497
+ value: exports.optionalDeps.ethUtil.toBuffer(exports.optionalDeps.ethUtil.addHexPrefix(txInfo.signature)),
1498
+ },
1499
+ ];
1500
+ }
1501
+ /**
1502
+ * Recovers a tx with TSS key shares
1503
+ * same expected arguments as recover method, but with TSS key shares
1504
+ */
1505
+ async recoverTSS(params) {
1506
+ this.validateRecoveryParams(params);
1507
+ // Clean up whitespace from entered values
1508
+ const userPublicOrPrivateKeyShare = params.userKey.replace(/\s/g, '');
1509
+ const backupPrivateOrPublicKeyShare = params.backupKey.replace(/\s/g, '');
1510
+ if ((0, sdk_core_1.getIsUnsignedSweep)({
1511
+ userKey: userPublicOrPrivateKeyShare,
1512
+ backupKey: backupPrivateOrPublicKeyShare,
1513
+ isTss: params.isTss,
1514
+ })) {
1515
+ return this.buildUnsignedSweepTxnTSS(params);
1516
+ }
1517
+ else {
1518
+ const { userKeyShare, backupKeyShare, commonKeyChain } = await sdk_core_1.ECDSAUtils.getMpcV2RecoveryKeyShares(userPublicOrPrivateKeyShare, backupPrivateOrPublicKeyShare, params.walletPassphrase);
1519
+ const { gasLimit, gasPrice } = await this.getGasValues(params);
1520
+ const MPC = new sdk_core_1.Ecdsa();
1521
+ const derivedCommonKeyChain = MPC.deriveUnhardened(commonKeyChain, 'm/0');
1522
+ const backupKeyPair = new lib_1.KeyPair({ pub: derivedCommonKeyChain.slice(0, 66) });
1523
+ const baseAddress = backupKeyPair.getAddress();
1524
+ const unsignedTx = (await this.buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params)).tx;
1525
+ const messageHash = unsignedTx.getMessageToSign(true);
1526
+ const signature = await sdk_core_1.ECDSAUtils.signRecoveryMpcV2(messageHash, userKeyShare, backupKeyShare, commonKeyChain);
1527
+ const ethCommmon = AbstractEthLikeNewCoins.getEthLikeCommon(params.eip1559, params.replayProtectionOptions);
1528
+ const signedTx = this.getSignedTxFromSignature(ethCommmon, unsignedTx, signature);
1529
+ return {
1530
+ id: (0, ethereumjs_util_1.addHexPrefix)(signedTx.hash().toString('hex')),
1531
+ tx: (0, ethereumjs_util_1.addHexPrefix)(signedTx.serialize().toString('hex')),
1532
+ };
1533
+ }
1534
+ }
1535
+ async getGasValues(params) {
1536
+ const gasLimit = new exports.optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit));
1537
+ const gasPrice = params.eip1559
1538
+ ? new exports.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas)
1539
+ : new exports.optionalDeps.ethUtil.BN(this.setGasPrice(params.gasPrice));
1540
+ return { gasLimit, gasPrice };
1541
+ }
1542
+ async buildUnsignedSweepTxnTSS(params) {
1543
+ const userPublicOrPrivateKeyShare = params.userKey.replace(/\s/g, '');
1544
+ const backupPrivateOrPublicKeyShare = params.backupKey.replace(/\s/g, '');
1545
+ const { gasLimit, gasPrice } = await this.getGasValues(params);
1546
+ const backupKeyPair = new lib_1.KeyPair({ pub: backupPrivateOrPublicKeyShare });
1547
+ const baseAddress = backupKeyPair.getAddress();
1548
+ const { txInfo, tx, nonce } = await this.buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params);
1549
+ return this.formatForOfflineVaultTSS(txInfo, tx, userPublicOrPrivateKeyShare, backupPrivateOrPublicKeyShare, gasPrice, gasLimit, nonce, params.eip1559, params.replayProtectionOptions);
1550
+ }
1551
+ async buildUnsignedSweepTxnMPCv2(params) {
1552
+ const { gasLimit, gasPrice } = await this.getGasValues(params);
1553
+ const recoverParams = params;
1554
+ this.validateUnsignedSweepTSSParams(recoverParams);
1555
+ const derivationPath = recoverParams.derivationSeed ? (0, sdk_lib_mpc_1.getDerivationPath)(recoverParams.derivationSeed) : 'm/0';
1556
+ const MPC = new sdk_core_1.Ecdsa();
1557
+ const derivedCommonKeyChain = MPC.deriveUnhardened(recoverParams.backupKey, derivationPath);
1558
+ const backupKeyPair = new lib_1.KeyPair({ pub: derivedCommonKeyChain.slice(0, 66) });
1559
+ const baseAddress = backupKeyPair.getAddress();
1560
+ const { txInfo, tx, nonce } = await this.buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params);
1561
+ return this.buildTxRequestForOfflineVaultMPCv2(txInfo, tx, derivationPath, nonce, gasPrice, gasLimit, params.eip1559, params.replayProtectionOptions, recoverParams.backupKey);
1562
+ }
1563
+ async createBroadcastableSweepTransaction(params) {
1564
+ const req = params.signatureShares;
1565
+ const broadcastableTransactions = [];
1566
+ let lastScanIndex = 0;
1567
+ for (let i = 0; i < req.length; i++) {
1568
+ const transaction = req[i]?.txRequest?.transactions?.[0]?.unsignedTx;
1569
+ if (!req[i].ovc || !req[i].ovc[0].ecdsaSignature) {
1570
+ throw new Error('Missing signature(s)');
1571
+ }
1572
+ if (!transaction.signableHex) {
1573
+ throw new Error('Missing signable hex');
1574
+ }
1575
+ const signature = req[i].ovc[0].ecdsaSignature;
1576
+ if (!signature) {
1577
+ throw new Error('Signature is undefined');
1578
+ }
1579
+ const shares = signature.toString().split(':');
1580
+ if (shares.length !== 4) {
1581
+ throw new Error('Invalid signature');
1582
+ }
1583
+ const finalSignature = {
1584
+ recid: Number(shares[0]),
1585
+ r: shares[1],
1586
+ s: shares[2],
1587
+ y: shares[3],
1588
+ };
1589
+ if (!transaction.coinSpecific?.commonKeyChain) {
1590
+ throw new Error(`Missing common keychain for transaction at index ${i}`);
1591
+ }
1592
+ const commonKeyChain = transaction.coinSpecific.commonKeyChain;
1593
+ if (!transaction.derivationPath) {
1594
+ throw new Error(`Missing derivation path for transaction at index ${i}`);
1595
+ }
1596
+ if (!commonKeyChain) {
1597
+ throw new Error(`Missing common key chain for transaction at index ${i}`);
1598
+ }
1599
+ const ethCommmon = AbstractEthLikeNewCoins.getEthLikeCommon(transaction.eip1559, transaction.replayProtectionOptions);
1600
+ let unsignedTx;
1601
+ if (transaction.eip1559) {
1602
+ unsignedTx = tx_1.FeeMarketEIP1559Transaction.fromSerializedTx(Buffer.from(transaction.serializedTxHex, 'hex'));
1603
+ }
1604
+ else {
1605
+ unsignedTx = tx_1.Transaction.fromSerializedTx(Buffer.from(transaction.serializedTxHex, 'hex'));
1606
+ }
1607
+ const signedTx = this.getSignedTxFromSignature(ethCommmon, unsignedTx, finalSignature);
1608
+ broadcastableTransactions.push({
1609
+ serializedTx: (0, ethereumjs_util_1.addHexPrefix)(signedTx.serialize().toString('hex')),
1610
+ });
1611
+ if (i === req.length - 1 && transaction.coinSpecific?.lastScanIndex) {
1612
+ lastScanIndex = transaction.coinSpecific?.lastScanIndex;
1613
+ }
1614
+ }
1615
+ return { transactions: broadcastableTransactions, lastScanIndex };
1616
+ }
1617
+ /**
1618
+ * Method to validate recovery params
1619
+ * @param {RecoverOptions} params
1620
+ * @returns {void}
1621
+ */
1622
+ async validateUnsignedSweepTSSParams(params) {
1623
+ if (lodash_1.default.isUndefined(params.backupKey) && params.backupKey === '') {
1624
+ throw new Error('missing commonKeyChain');
1625
+ }
1626
+ if (!lodash_1.default.isUndefined(params.derivationSeed) && typeof params.derivationSeed !== 'string') {
1627
+ throw new Error('invalid derivationSeed');
1628
+ }
1629
+ if (lodash_1.default.isUndefined(params.recoveryDestination) || !this.isValidAddress(params.recoveryDestination)) {
1630
+ throw new Error('missing or invalid destinationAddress');
1631
+ }
1632
+ }
1633
+ /**
1634
+ * Helper function for recover()
1635
+ * This transforms the unsigned transaction information into a format the BitGo offline vault expects
1636
+ * @param {UnformattedTxInfo} txInfo - tx info
1637
+ * @param {LegacyTransaction | FeeMarketEIP1559Transaction} ethTx - the ethereumjs tx object
1638
+ * @param {string} derivationPath - the derivationPath
1639
+ * @param {number} nonce - the nonce of the backup key address
1640
+ * @param {Buffer} gasPrice - gas price for the tx
1641
+ * @param {number} gasLimit - gas limit for the tx
1642
+ * @param {EIP1559} eip1559 - eip1559 params
1643
+ * @param replayProtectionOptions
1644
+ * @param commonKeyChain
1645
+ * @returns {Promise<OfflineVaultTxInfo>}
1646
+ */
1647
+ buildTxRequestForOfflineVaultMPCv2(txInfo, ethTx, derivationPath, nonce, gasPrice, gasLimit, eip1559, replayProtectionOptions, commonKeyChain) {
1648
+ if (!ethTx.to) {
1649
+ throw new Error('Eth tx must have a `to` address');
1650
+ }
1651
+ const fee = eip1559
1652
+ ? gasLimit * eip1559.maxFeePerGas
1653
+ : gasLimit * exports.optionalDeps.ethUtil.bufferToInt(gasPrice).toFixed();
1654
+ const unsignedTx = {
1655
+ serializedTxHex: ethTx.serialize().toString('hex'),
1656
+ signableHex: ethTx instanceof tx_1.FeeMarketEIP1559Transaction
1657
+ ? ethTx.getMessageToSign(false).toString('hex')
1658
+ : Buffer.from(rlp_1.RLP.encode((0, ethereumjs_util_1.bufArrToArr)(ethTx.getMessageToSign(false)))).toString('hex'),
1659
+ derivationPath: derivationPath,
1660
+ feeInfo: {
1661
+ fee: fee,
1662
+ feeString: fee.toString(),
1663
+ },
1664
+ parsedTx: {
1665
+ spendAmount: txInfo.recipient.amount,
1666
+ outputs: [
1667
+ {
1668
+ coinName: this.getChain(),
1669
+ address: txInfo.recipient.address,
1670
+ valueString: txInfo.recipient.amount,
1671
+ },
1672
+ ],
1673
+ },
1674
+ coinSpecific: {
1675
+ commonKeyChain: commonKeyChain,
1676
+ },
1677
+ eip1559: eip1559,
1678
+ replayProtectionOptions: replayProtectionOptions,
1679
+ };
1680
+ return {
1681
+ txRequests: [
1682
+ {
1683
+ walletCoin: this.getChain(),
1684
+ transactions: [
1685
+ {
1686
+ unsignedTx: unsignedTx,
1687
+ nonce: nonce,
1688
+ signatureShares: [],
1689
+ },
1690
+ ],
1691
+ },
1692
+ ],
1693
+ };
1694
+ }
1695
+ async buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params) {
1696
+ const txAmount = await this.validateBalanceAndGetTxAmount(baseAddress, gasPrice, gasLimit, params.apiKey);
1697
+ const nonce = await this.getAddressNonce(baseAddress, params.apiKey);
1698
+ const recipients = [
1699
+ {
1700
+ address: params.recoveryDestination,
1701
+ amount: txAmount.toString(10),
1702
+ },
1703
+ ];
1704
+ const txInfo = {
1705
+ recipient: recipients[0],
1706
+ expireTime: this.getDefaultExpireTime(),
1707
+ gasLimit: gasLimit.toString(10),
1708
+ };
1709
+ const txParams = {
1710
+ to: params.recoveryDestination,
1711
+ nonce: nonce,
1712
+ value: txAmount,
1713
+ gasPrice: gasPrice,
1714
+ gasLimit: gasLimit,
1715
+ data: Buffer.from('0x'),
1716
+ eip1559: params.eip1559,
1717
+ replayProtectionOptions: params.replayProtectionOptions,
1718
+ };
1719
+ const tx = AbstractEthLikeNewCoins.buildTransaction(txParams);
1720
+ return { txInfo, tx, nonce };
1721
+ }
1722
+ async validateBalanceAndGetTxAmount(baseAddress, gasPrice, gasLimit, apiKey) {
1723
+ const baseAddressBalance = await this.queryAddressBalance(baseAddress, apiKey);
1724
+ const totalGasNeeded = gasPrice.mul(gasLimit);
1725
+ const weiToGwei = new bn_js_1.default(10 ** 9);
1726
+ if (baseAddressBalance.lt(totalGasNeeded)) {
1727
+ throw new Error(`Backup key address ${baseAddress} has balance ${baseAddressBalance.div(weiToGwei).toString()} Gwei.` +
1728
+ `This address must have a balance of at least ${totalGasNeeded.div(weiToGwei).toString()}` +
1729
+ ` Gwei to perform recoveries. Try sending some ETH to this address then retry.`);
1730
+ }
1731
+ const txAmount = baseAddressBalance.sub(totalGasNeeded);
1732
+ return txAmount;
1733
+ }
1734
+ /**
1735
+ * Make a query to blockchain explorer for information such as balance, token balance, solidity calls
1736
+ * @param query {Object} key-value pairs of parameters to append after /api
1737
+ * @param apiKey {string} optional API key to use instead of the one from the environment
1738
+ * @returns {Object} response from the blockchain explorer
1739
+ */
1740
+ async recoveryBlockchainExplorerQuery(query, apiKey) {
1741
+ throw new Error('method not implemented');
1742
+ }
1743
+ /**
1744
+ * Creates the extra parameters needed to build a hop transaction
1745
+ * @param buildParams The original build parameters
1746
+ * @returns extra parameters object to merge with the original build parameters object and send to the platform
1747
+ */
1748
+ async createHopTransactionParams(buildParams) {
1749
+ const wallet = buildParams.wallet;
1750
+ const recipients = buildParams.recipients;
1751
+ const walletPassphrase = buildParams.walletPassphrase;
1752
+ const userKeychain = await this.keychains().get({ id: wallet.keyIds()[0] });
1753
+ const userPrv = wallet.getUserPrv({ keychain: userKeychain, walletPassphrase });
1754
+ const userPrvBuffer = secp256k1_1.bip32.fromBase58(userPrv).privateKey;
1755
+ if (!userPrvBuffer) {
1756
+ throw new Error('invalid userPrv');
1757
+ }
1758
+ if (!recipients || !Array.isArray(recipients)) {
1759
+ throw new Error('expecting array of recipients');
1760
+ }
1761
+ // Right now we only support 1 recipient
1762
+ if (recipients.length !== 1) {
1763
+ throw new Error('must send to exactly 1 recipient');
1764
+ }
1765
+ const recipientAddress = recipients[0].address;
1766
+ const recipientAmount = recipients[0].amount;
1767
+ const feeEstimateParams = {
1768
+ recipient: recipientAddress,
1769
+ amount: recipientAmount,
1770
+ hop: true,
1771
+ };
1772
+ const feeEstimate = await this.feeEstimate(feeEstimateParams);
1773
+ const gasLimit = feeEstimate.gasLimitEstimate;
1774
+ const gasPrice = Math.round(feeEstimate.feeEstimate / gasLimit);
1775
+ const gasPriceMax = gasPrice * 5;
1776
+ // Payment id a random number so its different for every tx
1777
+ const paymentId = Math.floor(Math.random() * 10000000000).toString();
1778
+ const hopDigest = AbstractEthLikeNewCoins.getHopDigest([
1779
+ recipientAddress,
1780
+ recipientAmount,
1781
+ gasPriceMax.toString(),
1782
+ gasLimit.toString(),
1783
+ paymentId,
1784
+ ]);
1785
+ const userReqSig = exports.optionalDeps.ethUtil.addHexPrefix(Buffer.from(secp256k1_2.default.ecdsaSign(hopDigest, userPrvBuffer).signature).toString('hex'));
1786
+ return {
1787
+ hopParams: {
1788
+ gasPriceMax,
1789
+ userReqSig,
1790
+ paymentId,
1791
+ gasLimit,
1792
+ },
1793
+ };
1794
+ }
1795
+ /**
1796
+ * Validates that the hop prebuild from the HSM is valid and correct
1797
+ * @param {IWallet} wallet - The wallet that the prebuild is for
1798
+ * @param {HopPrebuild} hopPrebuild - The prebuild to validate
1799
+ * @param {Object} originalParams - The original parameters passed to prebuildTransaction
1800
+ * @param {Recipient[]} originalParams.recipients - The original recipients array
1801
+ * @returns {void}
1802
+ * @throws Error if The prebuild is invalid
1803
+ */
1804
+ async validateHopPrebuild(wallet, hopPrebuild, originalParams) {
1805
+ const { tx, id, signature } = hopPrebuild;
1806
+ // first, validate the HSM signature
1807
+ const serverXpub = sdk_core_1.common.Environments[this.bitgo.getEnv()].hsmXpub;
1808
+ const serverPubkeyBuffer = secp256k1_1.bip32.fromBase58(serverXpub).publicKey;
1809
+ const signatureBuffer = Buffer.from(exports.optionalDeps.ethUtil.stripHexPrefix(signature), 'hex');
1810
+ const messageBuffer = Buffer.from(exports.optionalDeps.ethUtil.padToEven(exports.optionalDeps.ethUtil.stripHexPrefix(id)), 'hex');
1811
+ const sig = new Uint8Array(signatureBuffer.slice(1));
1812
+ const isValidSignature = secp256k1_2.default.ecdsaVerify(sig, messageBuffer, serverPubkeyBuffer);
1813
+ if (!isValidSignature) {
1814
+ throw new Error(`Hop txid signature invalid - pub: ${serverXpub}, msg: ${messageBuffer?.toString()}, sig: ${signatureBuffer?.toString()}`);
1815
+ }
1816
+ const builtHopTx = exports.optionalDeps.EthTx.TransactionFactory.fromSerializedData(exports.optionalDeps.ethUtil.toBuffer(tx));
1817
+ // If original params are given, we can check them against the transaction prebuild params
1818
+ if (!lodash_1.default.isNil(originalParams)) {
1819
+ const { recipients } = originalParams;
1820
+ // Then validate that the tx params actually equal the requested params
1821
+ const originalAmount = new bignumber_js_1.BigNumber(recipients[0].amount);
1822
+ const originalDestination = recipients[0].address;
1823
+ const hopAmount = new bignumber_js_1.BigNumber(exports.optionalDeps.ethUtil.bufferToHex(builtHopTx.value));
1824
+ if (!builtHopTx.to) {
1825
+ throw new Error(`Transaction does not have a destination address`);
1826
+ }
1827
+ const hopDestination = builtHopTx.to.toString();
1828
+ if (!hopAmount.eq(originalAmount)) {
1829
+ throw new Error(`Hop amount: ${hopAmount} does not equal original amount: ${originalAmount}`);
1830
+ }
1831
+ if (hopDestination.toLowerCase() !== originalDestination.toLowerCase()) {
1832
+ throw new Error(`Hop destination: ${hopDestination} does not equal original recipient: ${hopDestination}`);
1833
+ }
1834
+ }
1835
+ if (!builtHopTx.verifySignature()) {
1836
+ // We dont want to continue at all in this case, at risk of ETH being stuck on the hop address
1837
+ throw new Error(`Invalid hop transaction signature, txid: ${id}`);
1838
+ }
1839
+ if (exports.optionalDeps.ethUtil.addHexPrefix(builtHopTx.hash().toString('hex')) !== id) {
1840
+ throw new Error(`Signed hop txid does not equal actual txid`);
1841
+ }
1842
+ }
1843
+ /**
1844
+ * Gets the hop digest for the user to sign. This is validated in the HSM to prove that the user requested this tx
1845
+ * @param {string[]} paramsArr - The parameters to hash together for the digest
1846
+ * @returns {Buffer}
1847
+ */
1848
+ static getHopDigest(paramsArr) {
1849
+ const hash = (0, keccak_1.default)('keccak256');
1850
+ hash.update([AbstractEthLikeNewCoins.hopTransactionSalt, ...paramsArr].join('$'));
1851
+ return hash.digest();
1852
+ }
1853
+ /**
1854
+ * Modify prebuild before sending it to the server. Add things like hop transaction params
1855
+ * @param {BuildOptions} buildParams - The whitelisted parameters for this prebuild
1856
+ * @param {boolean} buildParams.hop - True if this should prebuild a hop tx, else false
1857
+ * @param {Recipient[]} buildParams.recipients - The recipients array of this transaction
1858
+ * @param {Wallet} buildParams.wallet - The wallet sending this tx
1859
+ * @param {string} buildParams.walletPassphrase - the passphrase for this wallet
1860
+ * @returns {Promise<BuildOptions>}
1861
+ */
1862
+ async getExtraPrebuildParams(buildParams) {
1863
+ if (!lodash_1.default.isUndefined(buildParams.hop) &&
1864
+ buildParams.hop &&
1865
+ !lodash_1.default.isUndefined(buildParams.wallet) &&
1866
+ !lodash_1.default.isUndefined(buildParams.recipients) &&
1867
+ !lodash_1.default.isUndefined(buildParams.walletPassphrase)) {
1868
+ if (this instanceof ethLikeToken_1.EthLikeToken) {
1869
+ throw new Error(`Hop transactions are not enabled for ERC-20 tokens, nor are they necessary. Please remove the 'hop' parameter and try again.`);
1870
+ }
1871
+ return (await this.createHopTransactionParams({
1872
+ wallet: buildParams.wallet,
1873
+ recipients: buildParams.recipients,
1874
+ walletPassphrase: buildParams.walletPassphrase,
1875
+ }));
1876
+ }
1877
+ return {};
1878
+ }
1879
+ /**
1880
+ * Modify prebuild after receiving it from the server. Add things like nlocktime
1881
+ * @param {TransactionPrebuild} params - The prebuild to modify
1882
+ * @returns {TransactionPrebuild} The modified prebuild
1883
+ */
1884
+ async postProcessPrebuild(params) {
1885
+ if (!lodash_1.default.isUndefined(params.hopTransaction) && !lodash_1.default.isUndefined(params.wallet) && !lodash_1.default.isUndefined(params.buildParams)) {
1886
+ await this.validateHopPrebuild(params.wallet, params.hopTransaction, params.buildParams);
1887
+ }
1888
+ return params;
1889
+ }
1890
+ /**
1891
+ * Coin-specific things done before signing a transaction, i.e. verification
1892
+ * @param {PresignTransactionOptions} params
1893
+ * @returns {Promise<PresignTransactionOptions>}
1894
+ */
1895
+ async presignTransaction(params) {
1896
+ if (!lodash_1.default.isUndefined(params.hopTransaction) && !lodash_1.default.isUndefined(params.wallet) && !lodash_1.default.isUndefined(params.buildParams)) {
1897
+ await this.validateHopPrebuild(params.wallet, params.hopTransaction);
1898
+ }
1899
+ return params;
1900
+ }
1901
+ /**
1902
+ * Fetch fee estimate information from the server
1903
+ * @param {Object} params - The params passed into the function
1904
+ * @param {boolean} [params.hop] - True if we should estimate fee for a hop transaction
1905
+ * @param {string} [params.recipient] - The recipient of the transaction to estimate a send to
1906
+ * @param {string} [params.data] - The ETH tx data to estimate a send for
1907
+ * @returns {Object} The fee info returned from the server
1908
+ */
1909
+ async feeEstimate(params) {
1910
+ const query = {};
1911
+ if (params && params.hop) {
1912
+ query.hop = params.hop;
1913
+ }
1914
+ if (params && params.recipient) {
1915
+ query.recipient = params.recipient;
1916
+ }
1917
+ if (params && params.data) {
1918
+ query.data = params.data;
1919
+ }
1920
+ if (params && params.amount) {
1921
+ query.amount = params.amount;
1922
+ }
1923
+ return await this.bitgo.get(this.url('/tx/fee')).query(query).result();
1924
+ }
1925
+ /**
1926
+ * Generate secp256k1 key pair
1927
+ *
1928
+ * @param {Buffer} seed
1929
+ * @returns {KeyPair} object with generated pub and prv
1930
+ */
1931
+ generateKeyPair(seed) {
1932
+ if (!seed) {
1933
+ // An extended private key has both a normal 256 bit private key and a 256
1934
+ // bit chain code, both of which must be random. 512 bits is therefore the
1935
+ // maximum entropy and gives us maximum security against cracking.
1936
+ seed = (0, crypto_1.randomBytes)(512 / 8);
1937
+ }
1938
+ const extendedKey = secp256k1_1.bip32.fromSeed(seed);
1939
+ const xpub = extendedKey.neutered().toBase58();
1940
+ return {
1941
+ pub: xpub,
1942
+ prv: extendedKey.toBase58(),
1943
+ };
1944
+ }
1945
+ async parseTransaction(params) {
1946
+ return {};
1947
+ }
1948
+ /**
1949
+ * Get forwarder factory and implementation addresses for deposit address verification.
1950
+ * Forwarders are smart contracts that forward funds to the base wallet address.
1951
+ *
1952
+ * @param {number | undefined} forwarderVersion - The wallet version
1953
+ * @returns {object} Factory and implementation addresses for forwarders
1954
+ */
1955
+ getForwarderFactoryAddressesAndForwarderImplementationAddress(forwarderVersion) {
1956
+ const ethNetwork = this.getNetwork();
1957
+ switch (forwarderVersion) {
1958
+ case 1:
1959
+ if (!ethNetwork?.forwarderFactoryAddress || !ethNetwork?.forwarderImplementationAddress) {
1960
+ throw new Error('Forwarder factory addresses not configured for this network');
1961
+ }
1962
+ return {
1963
+ forwarderFactoryAddress: ethNetwork.forwarderFactoryAddress,
1964
+ forwarderImplementationAddress: ethNetwork.forwarderImplementationAddress,
1965
+ };
1966
+ case 2:
1967
+ if (!ethNetwork?.walletV2ForwarderFactoryAddress || !ethNetwork?.walletV2ForwarderImplementationAddress) {
1968
+ throw new Error('Wallet v2 factory addresses not configured for this network');
1969
+ }
1970
+ return {
1971
+ forwarderFactoryAddress: ethNetwork.walletV2ForwarderFactoryAddress,
1972
+ forwarderImplementationAddress: ethNetwork.walletV2ForwarderImplementationAddress,
1973
+ };
1974
+ case 4:
1975
+ case 5:
1976
+ if (!ethNetwork?.walletV4ForwarderFactoryAddress || !ethNetwork?.walletV4ForwarderImplementationAddress) {
1977
+ throw new Error(`Forwarder v${forwarderVersion} factory addresses not configured for this network`);
1978
+ }
1979
+ return {
1980
+ forwarderFactoryAddress: ethNetwork.walletV4ForwarderFactoryAddress,
1981
+ forwarderImplementationAddress: ethNetwork.walletV4ForwarderImplementationAddress,
1982
+ };
1983
+ default:
1984
+ throw new Error(`Forwarder version ${forwarderVersion} not supported`);
1985
+ }
1986
+ }
1987
+ /**
1988
+ * Get wallet base address factory and implementation addresses.
1989
+ * This is used for base address verification for V1, V2, V4, and V5 wallets.
1990
+ * The base address is the main wallet contract deployed via CREATE2.
1991
+ *
1992
+ * @param {number} walletVersion - The wallet version (1, 2, 4, or 5)
1993
+ * @returns {object} Factory and implementation addresses for the wallet base address
1994
+ * @throws {Error} if wallet version addresses are not configured
1995
+ */
1996
+ getWalletAddressFactoryAddressesAndImplementationAddress(walletVersion) {
1997
+ const ethNetwork = this.getNetwork();
1998
+ switch (walletVersion) {
1999
+ case 1:
2000
+ if (!ethNetwork?.walletFactoryAddress || !ethNetwork?.walletImplementationAddress) {
2001
+ throw new Error('Wallet v1 factory addresses not configured for this network');
2002
+ }
2003
+ return {
2004
+ walletFactoryAddress: ethNetwork.walletFactoryAddress,
2005
+ walletImplementationAddress: ethNetwork.walletImplementationAddress,
2006
+ };
2007
+ case 2:
2008
+ if (!ethNetwork?.walletV2FactoryAddress || !ethNetwork?.walletV2ImplementationAddress) {
2009
+ throw new Error('Wallet v2 factory addresses not configured for this network');
2010
+ }
2011
+ return {
2012
+ walletFactoryAddress: ethNetwork.walletV2FactoryAddress,
2013
+ walletImplementationAddress: ethNetwork.walletV2ImplementationAddress,
2014
+ };
2015
+ case 4:
2016
+ case 5:
2017
+ if (!ethNetwork?.walletV4ForwarderFactoryAddress || !ethNetwork?.walletV4ForwarderImplementationAddress) {
2018
+ throw new Error(`Wallet v${walletVersion} factory addresses not configured for this network`);
2019
+ }
2020
+ return {
2021
+ walletFactoryAddress: ethNetwork.walletV4ForwarderFactoryAddress,
2022
+ walletImplementationAddress: ethNetwork.walletV4ForwarderImplementationAddress,
2023
+ };
2024
+ default:
2025
+ throw new Error(`Wallet version ${walletVersion} not supported`);
2026
+ }
2027
+ }
2028
+ /**
2029
+ * Helper method to create a salt buffer from hex string.
2030
+ * Converts a hex salt string to a 32-byte buffer.
2031
+ *
2032
+ * @param {string} salt - The hex salt string
2033
+ * @returns {Buffer} 32-byte salt buffer
2034
+ */
2035
+ createSaltBuffer(salt) {
2036
+ const ethUtil = exports.optionalDeps.ethUtil;
2037
+ return ethUtil.setLengthLeft(Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(salt || '')), 'hex'), 32);
2038
+ }
2039
+ /**
2040
+ * Verify BIP32 wallet base address (V1, V2, V4).
2041
+ * These wallets use a wallet factory to deploy base addresses with CREATE2.
2042
+ * The address is derived from the keychains' ethAddresses and a salt.
2043
+ *
2044
+ * @param {VerifyBip32BaseAddressOptions} params - Verification parameters
2045
+ * @returns {object} Expected and actual addresses for comparison
2046
+ */
2047
+ verifyCreate2BaseAddress(params) {
2048
+ const { address, coinSpecific, keychains, walletVersion } = params;
2049
+ if (!coinSpecific.salt) {
2050
+ throw new Error(`missing salt for v${walletVersion} base address verification`);
2051
+ }
2052
+ // Get wallet factory and implementation addresses for the wallet version
2053
+ const { walletFactoryAddress, walletImplementationAddress } = this.getWalletAddressFactoryAddressesAndImplementationAddress(walletVersion);
2054
+ const initcode = (0, lib_1.getProxyInitcode)(walletImplementationAddress);
2055
+ // Convert the wallet salt to a buffer, pad to 32 bytes
2056
+ const saltBuffer = this.createSaltBuffer(coinSpecific.salt);
2057
+ // Reconstruct calculationSalt using keychains' ethAddresses and wallet salt
2058
+ const ethAddresses = keychains.map((kc) => {
2059
+ if (!kc.ethAddress) {
2060
+ throw new Error(`keychain missing ethAddress for v${walletVersion} base address verification`);
2061
+ }
2062
+ return kc.ethAddress;
2063
+ });
2064
+ const calculationSalt = exports.optionalDeps.ethUtil.bufferToHex(exports.optionalDeps.ethAbi.soliditySHA3(['address[]', 'bytes32'], [ethAddresses, saltBuffer]));
2065
+ const expectedAddress = (0, lib_1.calculateForwarderV1Address)(walletFactoryAddress, calculationSalt, initcode);
2066
+ if (expectedAddress !== address) {
2067
+ throw new sdk_core_1.UnexpectedAddressError(`address validation failure: expected ${expectedAddress} but got ${address}`);
2068
+ }
2069
+ return true;
2070
+ }
2071
+ /**
2072
+ * Verify forwarder receive address (deposit address).
2073
+ * Forwarder addresses are derived using CREATE2 from the base address and salt.
2074
+ *
2075
+ * @param {VerifyEthAddressOptions} params - Verification parameters
2076
+ * @param {number} forwarderVersion - The forwarder version
2077
+ * @returns {object} Expected and actual addresses for comparison
2078
+ */
2079
+ verifyForwarderAddress(params, forwarderVersion) {
2080
+ const { address, coinSpecific, baseAddress } = params;
2081
+ const { forwarderFactoryAddress, forwarderImplementationAddress } = this.getForwarderFactoryAddressesAndForwarderImplementationAddress(forwarderVersion);
2082
+ const initcode = (0, lib_1.getProxyInitcode)(forwarderImplementationAddress);
2083
+ const saltBuffer = this.createSaltBuffer(coinSpecific.salt || '');
2084
+ const { createForwarderParams, createForwarderTypes } = forwarderVersion === 4
2085
+ ? (0, lib_1.getCreateForwarderParamsAndTypes)(baseAddress, saltBuffer, coinSpecific.feeAddress)
2086
+ : (0, lib_1.getCreateForwarderParamsAndTypes)(baseAddress, saltBuffer);
2087
+ const calculationSalt = exports.optionalDeps.ethUtil.bufferToHex(exports.optionalDeps.ethAbi.soliditySHA3(createForwarderTypes, createForwarderParams));
2088
+ const expectedAddress = (0, lib_1.calculateForwarderV1Address)(forwarderFactoryAddress, calculationSalt, initcode);
2089
+ if (expectedAddress !== address) {
2090
+ throw new sdk_core_1.UnexpectedAddressError(`address validation failure: expected ${expectedAddress} but got ${address}`);
2091
+ }
2092
+ return true;
2093
+ }
2094
+ /**
2095
+ * Make sure an address is a wallet address and throw an error if it's not.
2096
+ * @param {Object} params
2097
+ * @param {string} params.address - The derived address string on the network
2098
+ * @param {Object} params.coinSpecific - Coin-specific details for the address such as a forwarderVersion
2099
+ * @param {string} params.baseAddress - The base address of the wallet on the network
2100
+ * @throws {InvalidAddressError}
2101
+ * @throws {InvalidAddressVerificationObjectPropertyError}
2102
+ * @throws {UnexpectedAddressError}
2103
+ * @returns {boolean} True iff address is a wallet address
2104
+ */
2105
+ async isWalletAddress(params) {
2106
+ const { address, impliedForwarderVersion, coinSpecific, baseAddress } = params;
2107
+ const forwarderVersion = impliedForwarderVersion ?? coinSpecific?.forwarderVersion;
2108
+ // Validate address format
2109
+ if (address && !this.isValidAddress(address)) {
2110
+ throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
2111
+ }
2112
+ // Forwarder version 0 addresses cannot be verified because we do not store the nonce value required for address derivation.
2113
+ if (forwarderVersion === 0) {
2114
+ return true;
2115
+ }
2116
+ // Determine if we are verifying a base address
2117
+ const isVerifyingBaseAddress = baseAddress && address === baseAddress;
2118
+ // TSS/MPC wallet address verification (V3, V5, V6)
2119
+ // V5 base addresses use TSS, but V5 forwarders use the regular forwarder verification
2120
+ const isTssWalletVersion = params.walletVersion === 3 || params.walletVersion === 5 || params.walletVersion === 6;
2121
+ const shouldUseTssVerification = (0, sdk_core_1.isTssVerifyAddressOptions)(params) && isTssWalletVersion && (params.walletVersion !== 5 || isVerifyingBaseAddress);
2122
+ if (shouldUseTssVerification) {
2123
+ if (isVerifyingBaseAddress) {
2124
+ const index = typeof params.index === 'string' ? parseInt(params.index, 10) : params.index;
2125
+ if (index !== 0) {
2126
+ throw new Error(`Base address verification requires index 0, but got index ${params.index}. ` +
2127
+ `The base address is always derived at index 0.`);
2128
+ }
2129
+ }
2130
+ return (0, sdk_core_1.verifyMPCWalletAddress)({ ...params, keyCurve: 'secp256k1' }, this.isValidAddress, (pubKey) => {
2131
+ return new lib_1.KeyPair({ pub: pubKey }).getAddress();
2132
+ });
2133
+ }
2134
+ // From here on, we need baseAddress and coinSpecific for non-TSS verifications
2135
+ if (lodash_1.default.isUndefined(baseAddress) || !this.isValidAddress(baseAddress)) {
2136
+ throw new sdk_core_1.InvalidAddressError('invalid base address');
2137
+ }
2138
+ if (!lodash_1.default.isObject(coinSpecific)) {
2139
+ throw new sdk_core_1.InvalidAddressVerificationObjectPropertyError('address validation failure: coinSpecific field must be an object');
2140
+ }
2141
+ // BIP32 wallet base address verification (V1, V2, V4)
2142
+ if (isVerifyingBaseAddress && isVerifyContractBaseAddressOptions(params)) {
2143
+ return this.verifyCreate2BaseAddress(params);
2144
+ }
2145
+ // Forwarder receive address verification (deposit addresses)
2146
+ if (!isVerifyingBaseAddress) {
2147
+ return this.verifyForwarderAddress(params, forwarderVersion);
2148
+ }
2149
+ // If we reach here, it's a base address verification for an unsupported wallet version
2150
+ throw new Error(`Base address verification not supported for wallet version ${params.walletVersion}`);
2151
+ }
2152
+ /**
2153
+ *
2154
+ * @param {TransactionPrebuild} txPrebuild
2155
+ * @returns {boolean}
2156
+ */
2157
+ verifyCoin(txPrebuild) {
2158
+ const nativeCoin = this.getChain().split(':')[0];
2159
+ return txPrebuild.coin === nativeCoin;
2160
+ }
2161
+ /**
2162
+ * Generate transaction explanation for error reporting
2163
+ * @param txPrebuild - Transaction prebuild containing txHex and fee info
2164
+ * @returns Stringified JSON explanation
2165
+ */
2166
+ async getTxExplanation(txPrebuild) {
2167
+ if (!txPrebuild?.txHex || !txPrebuild?.gasPrice) {
2168
+ return undefined;
2169
+ }
2170
+ try {
2171
+ const explanation = await this.explainTransaction({
2172
+ txHex: txPrebuild.txHex,
2173
+ feeInfo: {
2174
+ fee: txPrebuild.gasPrice.toString(),
2175
+ },
2176
+ });
2177
+ return JSON.stringify(explanation, null, 2);
2178
+ }
2179
+ catch (e) {
2180
+ const errorDetails = {
2181
+ error: 'Failed to parse transaction explanation',
2182
+ txHex: txPrebuild.txHex,
2183
+ details: e instanceof Error ? e.message : String(e),
2184
+ };
2185
+ return JSON.stringify(errorDetails, null, 2);
2186
+ }
2187
+ }
2188
+ /**
2189
+ * Verify if a tss transaction is valid
2190
+ *
2191
+ * @param {VerifyEthTransactionOptions} params
2192
+ * @param {TransactionParams} params.txParams - params object passed to send
2193
+ * @param {TransactionPrebuild} params.txPrebuild - prebuild object returned by server
2194
+ * @param {Wallet} params.wallet - Wallet object to obtain keys to verify against
2195
+ * @returns {boolean}
2196
+ * @throws {TxIntentMismatchRecipientError} if transaction recipients don't match user intent
2197
+ */
2198
+ async verifyTssTransaction(params) {
2199
+ const { txParams, txPrebuild, wallet } = params;
2200
+ // Helper to throw TxIntentMismatchRecipientError with recipient details
2201
+ const throwRecipientMismatch = async (message, mismatchedRecipients) => {
2202
+ const txExplanation = await this.getTxExplanation(txPrebuild);
2203
+ throw new sdk_core_1.TxIntentMismatchRecipientError(message, undefined, [txParams], txPrebuild?.txHex, mismatchedRecipients, txExplanation);
2204
+ };
2205
+ if (!txParams?.recipients &&
2206
+ !(txParams.prebuildTx?.consolidateId ||
2207
+ txPrebuild?.consolidateId ||
2208
+ (txParams.type &&
2209
+ ['acceleration', 'fillNonce', 'transferToken', 'tokenApproval', 'consolidate'].includes(txParams.type)))) {
2210
+ throw new Error('missing txParams');
2211
+ }
2212
+ if (!wallet || !txPrebuild) {
2213
+ throw new Error('missing params');
2214
+ }
2215
+ if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
2216
+ throw new Error('tx cannot be both a batch and hop transaction');
2217
+ }
2218
+ if (txParams.type && ['transfer'].includes(txParams.type)) {
2219
+ if (txParams.recipients && txParams.recipients.length === 1) {
2220
+ const recipients = txParams.recipients;
2221
+ const expectedAmount = recipients[0].amount.toString();
2222
+ const expectedDestination = recipients[0].address;
2223
+ const txBuilder = this.getTransactionBuilder();
2224
+ txBuilder.from(txPrebuild.txHex);
2225
+ const tx = await txBuilder.build();
2226
+ const txJson = tx.toJson();
2227
+ if (txJson.data === '0x') {
2228
+ if (expectedAmount !== txJson.value) {
2229
+ await throwRecipientMismatch('the transaction amount in txPrebuild does not match the value given by client', [{ address: txJson.to, amount: txJson.value }]);
2230
+ }
2231
+ if (expectedDestination.toLowerCase() !== txJson.to.toLowerCase()) {
2232
+ await throwRecipientMismatch('destination address does not match with the recipient address', [
2233
+ { address: txJson.to, amount: txJson.value },
2234
+ ]);
2235
+ }
2236
+ }
2237
+ else if (txJson.data.startsWith('0xa9059cbb')) {
2238
+ const [recipientAddress, amount] = (0, lib_1.getRawDecoded)(['address', 'uint256'], (0, lib_1.getBufferedByteCode)('0xa9059cbb', txJson.data));
2239
+ // Check if recipients[0].data exists (WalletConnect flow)
2240
+ let expectedRecipientAddress;
2241
+ let expectedTokenAmount;
2242
+ const recipientData = recipients[0].data;
2243
+ if (recipientData && recipientData.startsWith('0xa9059cbb')) {
2244
+ // WalletConnect: decode expected recipient and amount from recipients[0].data
2245
+ const [expectedRecipient, expectedAmount] = (0, lib_1.getRawDecoded)(['address', 'uint256'], (0, lib_1.getBufferedByteCode)('0xa9059cbb', recipientData));
2246
+ expectedRecipientAddress = (0, ethereumjs_util_1.addHexPrefix)(expectedRecipient.toString()).toLowerCase();
2247
+ expectedTokenAmount = expectedAmount.toString();
2248
+ }
2249
+ else {
2250
+ // Normal flow: use recipients[0].address and recipients[0].amount
2251
+ expectedRecipientAddress = expectedDestination.toLowerCase();
2252
+ expectedTokenAmount = expectedAmount;
2253
+ }
2254
+ if (expectedTokenAmount !== amount.toString()) {
2255
+ 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() }]);
2256
+ }
2257
+ if (expectedRecipientAddress !== (0, ethereumjs_util_1.addHexPrefix)(recipientAddress.toString()).toLowerCase()) {
2258
+ await throwRecipientMismatch('destination address does not match with the recipient address', [
2259
+ { address: (0, ethereumjs_util_1.addHexPrefix)(recipientAddress.toString()), amount: amount.toString() },
2260
+ ]);
2261
+ }
2262
+ }
2263
+ }
2264
+ }
2265
+ // Verify consolidation transactions send to base address
2266
+ if (params.verification?.consolidationToBaseAddress) {
2267
+ const coinSpecific = wallet.coinSpecific();
2268
+ if (!coinSpecific || !coinSpecific.baseAddress) {
2269
+ throw new Error('Unable to determine base address for consolidation');
2270
+ }
2271
+ const baseAddress = coinSpecific.baseAddress;
2272
+ if (!txPrebuild.txHex) {
2273
+ throw new Error('missing txHex in txPrebuild');
2274
+ }
2275
+ const txBuilder = this.getTransactionBuilder();
2276
+ txBuilder.from(txPrebuild.txHex);
2277
+ const tx = await txBuilder.build();
2278
+ const txJson = tx.toJson();
2279
+ // Verify the transaction recipient matches the base address
2280
+ if (!txJson.to) {
2281
+ throw new Error('Consolidation transaction is missing recipient address');
2282
+ }
2283
+ if (txJson.to.toLowerCase() !== baseAddress.toLowerCase()) {
2284
+ await throwRecipientMismatch('Consolidation transaction recipient does not match wallet base address', [
2285
+ { address: txJson.to, amount: txJson.value },
2286
+ ]);
2287
+ }
2288
+ }
2289
+ return true;
2290
+ }
2291
+ /**
2292
+ * Verify that a transaction prebuild complies with the original intention
2293
+ *
2294
+ * @param {VerifyEthTransactionOptions} params
2295
+ * @param {TransactionParams} params.txParams - params object passed to send
2296
+ * @param {TransactionPrebuild} params.txPrebuild - prebuild object returned by server
2297
+ * @param {Wallet} params.wallet - Wallet object to obtain keys to verify against
2298
+ * @returns {boolean}
2299
+ * @throws {TxIntentMismatchError} if transaction validation fails
2300
+ * @throws {TxIntentMismatchRecipientError} if transaction recipients don't match user intent
2301
+ */
2302
+ async verifyTransaction(params) {
2303
+ const ethNetwork = this.getNetwork();
2304
+ const { txParams, txPrebuild, wallet, walletType } = params;
2305
+ if (walletType === 'tss') {
2306
+ return this.verifyTssTransaction(params);
2307
+ }
2308
+ // Helper to throw TxIntentMismatchRecipientError with recipient details
2309
+ const throwRecipientMismatch = async (message, mismatchedRecipients) => {
2310
+ const txExplanation = await this.getTxExplanation(txPrebuild);
2311
+ throw new sdk_core_1.TxIntentMismatchRecipientError(message, undefined, [txParams], txPrebuild?.txHex, mismatchedRecipients, txExplanation);
2312
+ };
2313
+ if (!txParams?.recipients || !txPrebuild?.recipients || !wallet) {
2314
+ throw new Error('missing params');
2315
+ }
2316
+ const recipients = txParams.recipients;
2317
+ if (txParams.hop && recipients.length > 1) {
2318
+ throw new Error('tx cannot be both a batch and hop transaction');
2319
+ }
2320
+ if (txPrebuild.recipients.length > 1) {
2321
+ 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.`);
2322
+ }
2323
+ if (txParams.hop && txPrebuild.hopTransaction) {
2324
+ // Check recipient amount for hop transaction
2325
+ if (recipients.length !== 1) {
2326
+ throw new Error(`hop transaction only supports 1 recipient but ${recipients.length} found`);
2327
+ }
2328
+ // Check tx sends to hop address
2329
+ const decodedHopTx = exports.optionalDeps.EthTx.TransactionFactory.fromSerializedData(exports.optionalDeps.ethUtil.toBuffer(txPrebuild.hopTransaction.tx));
2330
+ const expectedHopAddress = exports.optionalDeps.ethUtil.stripHexPrefix(decodedHopTx.getSenderAddress().toString());
2331
+ const actualHopAddress = exports.optionalDeps.ethUtil.stripHexPrefix(txPrebuild.recipients[0].address);
2332
+ if (expectedHopAddress.toLowerCase() !== actualHopAddress.toLowerCase()) {
2333
+ await throwRecipientMismatch('recipient address of txPrebuild does not match hop address', [
2334
+ { address: txPrebuild.recipients[0].address, amount: txPrebuild.recipients[0].amount.toString() },
2335
+ ]);
2336
+ }
2337
+ // Convert TransactionRecipient array to Recipient array
2338
+ const hopRecipients = recipients.map((r) => {
2339
+ return {
2340
+ address: r.address,
2341
+ amount: typeof r.amount === 'number' ? r.amount.toString() : r.amount,
2342
+ };
2343
+ });
2344
+ // Check destination address and amount
2345
+ await this.validateHopPrebuild(wallet, txPrebuild.hopTransaction, { recipients: hopRecipients });
2346
+ }
2347
+ else if (recipients.length > 1) {
2348
+ // Check total amount for batch transaction
2349
+ if (txParams.tokenName) {
2350
+ const expectedTotalAmount = new bignumber_js_1.BigNumber(0);
2351
+ if (!expectedTotalAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
2352
+ 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() }]);
2353
+ }
2354
+ }
2355
+ else {
2356
+ let expectedTotalAmount = new bignumber_js_1.BigNumber(0);
2357
+ for (let i = 0; i < recipients.length; i++) {
2358
+ expectedTotalAmount = expectedTotalAmount.plus(recipients[i].amount);
2359
+ }
2360
+ if (!expectedTotalAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
2361
+ 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() }]);
2362
+ }
2363
+ }
2364
+ // Check batch transaction is sent to the batcher contract address for the chain
2365
+ const batcherContractAddress = ethNetwork?.batcherContractAddress;
2366
+ if (!batcherContractAddress ||
2367
+ batcherContractAddress.toLowerCase() !== txPrebuild.recipients[0].address.toLowerCase()) {
2368
+ await throwRecipientMismatch('recipient address of txPrebuild does not match batcher address', [
2369
+ { address: txPrebuild.recipients[0].address, amount: txPrebuild.recipients[0].amount.toString() },
2370
+ ]);
2371
+ }
2372
+ }
2373
+ else {
2374
+ // Check recipient address and amount for normal transaction
2375
+ if (recipients.length !== 1) {
2376
+ throw new Error(`normal transaction only supports 1 recipient but ${recipients.length} found`);
2377
+ }
2378
+ const expectedAmount = new bignumber_js_1.BigNumber(recipients[0].amount);
2379
+ if (!expectedAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
2380
+ 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() }]);
2381
+ }
2382
+ if (this.isETHAddress(recipients[0].address) && recipients[0].address !== txPrebuild.recipients[0].address) {
2383
+ 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() }]);
2384
+ }
2385
+ }
2386
+ // Check coin is correct for all transaction types
2387
+ if (!this.verifyCoin(txPrebuild)) {
2388
+ const txExplanation = await this.getTxExplanation(txPrebuild);
2389
+ throw new sdk_core_1.TxIntentMismatchError('coin in txPrebuild did not match that in txParams supplied by client', undefined, [txParams], txPrebuild?.txHex, txExplanation);
2390
+ }
2391
+ return true;
2392
+ }
2393
+ /**
2394
+ * Check if address is valid eth address
2395
+ * @param address
2396
+ * @returns {boolean}
2397
+ */
2398
+ isETHAddress(address) {
2399
+ return !!address.match(/0x[a-fA-F0-9]{40}/);
2400
+ }
2401
+ /**
2402
+ * Transform message to accommodate specific blockchain requirements.
2403
+ * @param {string} message - the message to prepare
2404
+ * @return {string} the prepared message as a hex encoded string.
2405
+ */
2406
+ encodeMessage(message) {
2407
+ const prefix = `\u0019Ethereum Signed Message:\n${message.length}`;
2408
+ return Buffer.from(prefix.concat(message)).toString('hex');
2409
+ }
2410
+ /**
2411
+ * Transform the Typed data to accomodate the blockchain requirements (EIP-712)
2412
+ * @param {TypedData} typedData - the typed data to prepare
2413
+ * @return {Buffer} a buffer of the result
2414
+ */
2415
+ encodeTypedData(typedData) {
2416
+ const version = typedData.version;
2417
+ if (version === eth_sig_util_1.SignTypedDataVersion.V1) {
2418
+ throw new Error('SignTypedData v1 is not supported due to security concerns');
2419
+ }
2420
+ const typedDataRaw = JSON.parse(typedData.typedDataRaw);
2421
+ const sanitizedData = eth_sig_util_1.TypedDataUtils.sanitizeData(typedDataRaw);
2422
+ const parts = [Buffer.from('1901', 'hex')];
2423
+ const eip712Domain = 'EIP712Domain';
2424
+ parts.push(eth_sig_util_1.TypedDataUtils.hashStruct(eip712Domain, sanitizedData.domain, sanitizedData.types, version));
2425
+ if (sanitizedData.primaryType !== eip712Domain) {
2426
+ parts.push(eth_sig_util_1.TypedDataUtils.hashStruct(sanitizedData.primaryType, sanitizedData.message, sanitizedData.types, version));
2427
+ }
2428
+ return Buffer.concat(parts);
2429
+ }
2430
+ /**
2431
+ * Build the data to transfer an ERC-721 or ERC-1155 token to another address
2432
+ * @param params
2433
+ */
2434
+ buildNftTransferData(params) {
2435
+ const { tokenContractAddress, recipientAddress, fromAddress } = params;
2436
+ switch (params.type) {
2437
+ case 'ERC721': {
2438
+ const tokenId = params.tokenId;
2439
+ const contractData = new lib_1.ERC721TransferBuilder()
2440
+ .tokenContractAddress(tokenContractAddress)
2441
+ .to(recipientAddress)
2442
+ .from(fromAddress)
2443
+ .tokenId(tokenId)
2444
+ .build();
2445
+ return contractData;
2446
+ }
2447
+ case 'ERC1155': {
2448
+ const entries = params.entries;
2449
+ const transferBuilder = new lib_1.ERC1155TransferBuilder()
2450
+ .tokenContractAddress(tokenContractAddress)
2451
+ .to(recipientAddress)
2452
+ .from(fromAddress);
2453
+ for (const entry of entries) {
2454
+ transferBuilder.entry(parseInt(entry.tokenId, 10), entry.amount);
2455
+ }
2456
+ return transferBuilder.build();
2457
+ }
2458
+ default:
2459
+ throw new Error(`Unsupported NFT type: ${params.type}`);
2460
+ }
2461
+ }
2462
+ /**
2463
+ * Fetch the gas price from the explorer
2464
+ * @param {string} wrongChainCoin - the coin that we're getting gas price for
2465
+ * @param {string} apiKey - optional API key to use instead of the one from the environment
2466
+ */
2467
+ async getGasPriceFromExternalAPI(wrongChainCoin, apiKey) {
2468
+ try {
2469
+ const res = await this.recoveryBlockchainExplorerQuery({
2470
+ chainid: this.getChainId().toString(),
2471
+ module: 'proxy',
2472
+ action: 'eth_gasPrice',
2473
+ }, apiKey);
2474
+ const gasPrice = new bn_js_1.default(res.result.slice(2), 16);
2475
+ console.log(` Got gas price: ${gasPrice}`);
2476
+ return gasPrice;
2477
+ }
2478
+ catch (e) {
2479
+ throw new Error(`Failed to get gas price. Please make sure to use the api key of ${wrongChainCoin}`);
2480
+ }
2481
+ }
2482
+ /**
2483
+ * Fetch the gas limit from the explorer
2484
+ * @param intendedChain
2485
+ * @param from
2486
+ * @param to
2487
+ * @param data
2488
+ * @param {string} apiKey - optional API key to use instead of the one from the environment
2489
+ */
2490
+ async getGasLimitFromExternalAPI(intendedChain, from, to, data, apiKey) {
2491
+ try {
2492
+ const res = await this.recoveryBlockchainExplorerQuery({
2493
+ chainid: this.getChainId().toString(),
2494
+ module: 'proxy',
2495
+ action: 'eth_estimateGas',
2496
+ from,
2497
+ to,
2498
+ data,
2499
+ }, apiKey);
2500
+ const gasLimit = new bn_js_1.default(res.result.slice(2), 16);
2501
+ console.log(`Got gas limit: ${gasLimit}`);
2502
+ return gasLimit;
2503
+ }
2504
+ catch (e) {
2505
+ throw new Error(`Failed to get gas limit. Please make sure to use the privateKey aka userKey of ${intendedChain} wallet ${to}`);
2506
+ }
2507
+ }
2508
+ /**
2509
+ * Get the balance of bitgoFeeAddress to ensure funds are available to pay fees
2510
+ * @param bitgoFeeAddress
2511
+ * @param gasPrice
2512
+ * @param gasLimit
2513
+ * @param apiKey - optional API key to use instead of the one from the environment
2514
+ */
2515
+ async ensureSufficientBalance(bitgoFeeAddress, gasPrice, gasLimit, apiKey) {
2516
+ const bitgoFeeAddressBalance = await this.queryAddressBalance(bitgoFeeAddress, apiKey);
2517
+ const totalGasNeeded = Number(gasPrice.mul(gasLimit));
2518
+ const weiToGwei = 10 ** 9;
2519
+ if (bitgoFeeAddressBalance.lt(totalGasNeeded)) {
2520
+ throw new Error(`Fee address ${bitgoFeeAddress} has balance ${(bitgoFeeAddressBalance / weiToGwei).toString()} Gwei.` +
2521
+ `This address must have a balance of at least ${(totalGasNeeded / weiToGwei).toString()}` +
2522
+ ` Gwei to perform recoveries. Try sending some ${this.getChain()} to this address then retry.`);
2523
+ }
2524
+ }
2525
+ }
2526
+ exports.AbstractEthLikeNewCoins = AbstractEthLikeNewCoins;
2527
+ AbstractEthLikeNewCoins.hopTransactionSalt = 'bitgoHopAddressRequestSalt';
2528
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBbWJBLGdGQVVDO0FBN2JEOztHQUVHO0FBQ0gsbURBMEM4QjtBQUM5Qix5REFBNEQ7QUFDNUQscURBQThDO0FBQzlDLGlEQU82QjtBQUc3Qix1Q0FBK0Y7QUFDL0YseUNBQXNDO0FBQ3RDLHlEQUE0RjtBQUM1RiwrQ0FBeUM7QUFDekMsa0RBQXVCO0FBQ3ZCLG1DQUFxQztBQUNyQyxrREFBNkI7QUFDN0IscURBQWtIO0FBQ2xILG9EQUE0QjtBQUM1QixvREFBdUI7QUFDdkIsMERBQWtDO0FBRWxDLCtEQUE0RDtBQUM1RCxpREFBOEM7QUFDOUMsK0JBY2U7QUFtU0YsUUFBQSxtQkFBbUIsR0FBRyxFQUFFLENBQUM7QUFzRHRDOzs7R0FHRztBQUNILFNBQWdCLGtDQUFrQyxDQUNoRCxNQUE0RDtJQUU1RCxPQUFPLENBQ0wsQ0FBQyxNQUFNLENBQUMsYUFBYSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsYUFBYSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsYUFBYSxLQUFLLENBQUMsQ0FBQztRQUN4RixXQUFXLElBQUksTUFBTTtRQUNyQixLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7UUFDL0IsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQztRQUM3QixNQUFNLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQU8sRUFBRSxFQUFFLENBQUMsWUFBWSxJQUFJLEVBQUUsSUFBSSxPQUFPLEVBQUUsQ0FBQyxVQUFVLEtBQUssUUFBUSxDQUFDLENBQzdGLENBQUM7QUFDSixDQUFDO0FBRUQsTUFBTSxLQUFLLEdBQUcsSUFBQSxlQUFRLEVBQUMsa0JBQWtCLENBQUMsQ0FBQztBQUU5QixRQUFBLFlB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QUFRLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7UUFDdEQsTUFBTSxTQUFTLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUMxQixJQUFJLHNCQUFzQixDQUFDLEVBQUUsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO1lBQzlDLE1BQU0sSUFBSSxLQUFLLENBQ2IsZUFBZSxlQUFlLGdCQUFnQixDQUFDLHNCQUFzQixHQUFHLFNBQVMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxRQUFRO2dCQUNuRyxnREFBZ0QsQ0FBQyxjQUFjLEdBQUcsU0FBUyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7Z0JBQ3pGLGlEQUFpRCxJQUFJLENBQUMsUUFBUSxFQUFFLDhCQUE4QixDQUNqRyxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7O0FBajlGSCwwREFrOUZDO0FBajlGUSwwQ0FBa0IsR0FBRyw0QkFBNEIsQUFBL0IsQ0FBZ0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwcmV0dGllclxuICovXG5pbXBvcnQge1xuICBBZGRyZXNzQ29pblNwZWNpZmljLFxuICBCaXRHb0Jhc2UsXG4gIEJ1aWxkTmZ0VHJhbnNmZXJEYXRhT3B0aW9ucyxcbiAgY29tbW9uLFxuICBFY2RzYSxcbiAgRUNEU0FNZXRob2RUeXBlcyxcbiAgRUNEU0FVdGlscyxcbiAgRXRoZXJldW1MaWJyYXJ5VW5hdmFpbGFibGVFcnJvcixcbiAgRmVlRXN0aW1hdGVPcHRpb25zLFxuICBGdWxseVNpZ25lZFRyYW5zYWN0aW9uLFxuICBnZXRJc1Vuc2lnbmVkU3dlZXAsXG4gIEhhbGZTaWduZWRUcmFuc2FjdGlvbixcbiAgSW52YWxpZEFkZHJlc3NFcnJvcixcbiAgSW52YWxpZEFkZHJlc3NWZXJpZmljYXRpb25PYmplY3RQcm9wZXJ0eUVycm9yLFxuICBJV2FsbGV0LFxuICBLZXlQYWlyLFxuICBNUENTd2VlcFJlY292ZXJ5T3B0aW9ucyxcbiAgTVBDU3dlZXBUeHMsXG4gIE1QQ1R4LFxuICBNUENUeHMsXG4gIFBhcnNlZFRyYW5zYWN0aW9uLFxuICBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgUHJlYnVpbGRUcmFuc2FjdGlvblJlc3VsdCxcbiAgUHJlc2lnblRyYW5zYWN0aW9uT3B0aW9ucyBhcyBCYXNlUHJlc2lnblRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgUmVjaXBpZW50LFxuICBTaWduVHJhbnNhY3Rpb25PcHRpb25zIGFzIEJhc2VTaWduVHJhbnNhY3Rpb25PcHRpb25zLFxuICBUeEludGVudE1pc21hdGNoRXJyb3IsXG4gIFR4SW50ZW50TWlzbWF0Y2hSZWNpcGllbnRFcnJvcixcbiAgVHJhbnNhY3Rpb25QYXJhbXMsXG4gIFRyYW5zYWN0aW9uUHJlYnVpbGQgYXMgQmFzZVRyYW5zYWN0aW9uUHJlYnVpbGQsXG4gIFRyYW5zYWN0aW9uUmVjaXBpZW50LFxuICBUeXBlZERhdGEsXG4gIFVuZXhwZWN0ZWRBZGRyZXNzRXJyb3IsXG4gIFVuc2lnbmVkVHJhbnNhY3Rpb25Uc3MsXG4gIFV0aWwsXG4gIFZlcmlmeUFkZHJlc3NPcHRpb25zIGFzIEJhc2VWZXJpZnlBZGRyZXNzT3B0aW9ucyxcbiAgVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zLFxuICBXYWxsZXQsXG4gIHZlcmlmeU1QQ1dhbGxldEFkZHJlc3MsXG4gIFRzc1ZlcmlmeUFkZHJlc3NPcHRpb25zLFxuICBpc1Rzc1ZlcmlmeUFkZHJlc3NPcHRpb25zLFxufSBmcm9tICdAYml0Z28tYmV0YS9zZGstY29yZSc7XG5pbXBvcnQgeyBnZXREZXJpdmF0aW9uUGF0aCB9IGZyb20gJ0BiaXRnby1iZXRhL3Nkay1saWItbXBjJztcbmltcG9ydCB7IGJpcDMyIH0gZnJvbSAnQGJpdGdvLWJldGEvc2VjcDI1NmsxJztcbmltcG9ydCB7XG4gIEJhc2VDb2luIGFzIFN0YXRpY3NCYXNlQ29pbixcbiAgQ2hhaW5JZE5vdEZvdW5kRXJyb3IsXG4gIENvaW5GZWF0dXJlLFxuICBjb2lucyxcbiAgRXRoZXJldW1OZXR3b3JrIGFzIEV0aExpa2VOZXR3b3JrLFxuICBldGhHYXNDb25maWdzLFxufSBmcm9tICdAYml0Z28tYmV0YS9zdGF0aWNzJztcbmltcG9ydCB0eXBlICogYXMgRXRoTGlrZUNvbW1vbiBmcm9tICdAZXRoZXJldW1qcy9jb21tb24nO1xuaW1wb3J0IHR5cGUgKiBhcyBFdGhMaWtlVHhMaWIgZnJvbSAnQGV0aGVyZXVtanMvdHgnO1xuaW1wb3J0IHsgRmVlTWFya2V0RUlQMTU1OVRyYW5zYWN0aW9uLCBUcmFuc2FjdGlvbiBhcyBMZWdhY3lUcmFuc2FjdGlvbiB9IGZyb20gJ0BldGhlcmV1bWpzL3R4JztcbmltcG9ydCB7IFJMUCB9IGZyb20gJ0BldGhlcmV1bWpzL3JscCc7XG5pbXBvcnQgeyBTaWduVHlwZWREYXRhVmVyc2lvbiwgVHlwZWREYXRhVXRpbHMsIFR5cGVkTWVzc2FnZSB9IGZyb20gJ0BtZXRhbWFzay9ldGgtc2lnLXV0aWwnO1xuaW1wb3J0IHsgQmlnTnVtYmVyIH0gZnJvbSAnYmlnbnVtYmVyLmpzJztcbmltcG9ydCBCTiBmcm9tICdibi5qcyc7XG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgZGVidWdMaWIgZnJvbSAnZGVidWcnO1xuaW1wb3J0IHsgYWRkSGV4UHJlZml4LCBidWZBcnJUb0Fyciwgc3RyaXBIZXhQcmVmaXgsIGJ1ZmZlclRvSGV4LCBzZXRMZW5ndGhMZWZ0LCB0b0J1ZmZlciB9IGZyb20gJ2V0aGVyZXVtanMtdXRpbCc7XG5pbXBvcnQgS2VjY2FrIGZyb20gJ2tlY2Nhayc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHNlY3AyNTZrMSBmcm9tICdzZWNwMjU2azEnO1xuXG5pbXBvcnQgeyBBYnN0cmFjdEV0aExpa2VDb2luIH0gZnJvbSAnLi9hYnN0cmFjdEV0aExpa2VDb2luJztcbmltcG9ydCB7IEV0aExpa2VUb2tlbiB9IGZyb20gJy4vZXRoTGlrZVRva2VuJztcbmltcG9ydCB7XG4gIGNhbGN1bGF0ZUZvcndhcmRlclYxQWRkcmVzcyxcbiAgZGVjb2RlVHJhbnNmZXJEYXRhLFxuICBFUkMxMTU1VHJhbnNmZXJCdWlsZGVyLFxuICBFUkM3MjFUcmFuc2ZlckJ1aWxkZXIsXG4gIGdldEJ1ZmZlcmVkQnl0ZUNvZGUsXG4gIGdldENvbW1vbixcbiAgZ2V0Q3JlYXRlRm9yd2FyZGVyUGFyYW1zQW5kVHlwZXMsXG4gIGdldFByb3h5SW5pdGNvZGUsXG4gIGdldFJhd0RlY29kZWQsXG4gIGdldFRva2VuLFxuICBLZXlQYWlyIGFzIEtleVBhaXJMaWIsXG4gIFRyYW5zYWN0aW9uQnVpbGRlcixcbiAgVHJhbnNmZXJCdWlsZGVyLFxufSBmcm9tICcuL2xpYic7XG5pbXBvcnQgeyBTZW5kQ3Jvc3NDaGFpblJlY292ZXJ5T3B0aW9ucyB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKipcbiAqIFRoZSBwcmVidWlsdCBob3AgdHJhbnNhY3Rpb24gcmV0dXJuZWQgZnJvbSB0aGUgSFNNXG4gKi9cbmludGVyZmFjZSBIb3BQcmVidWlsZCB7XG4gIHR4OiBzdHJpbmc7XG4gIGlkOiBzdHJpbmc7XG4gIHNpZ25hdHVyZTogc3RyaW5nO1xuICBwYXltZW50SWQ6IHN0cmluZztcbiAgZ2FzUHJpY2U6IG51bWJlcjtcbiAgZ2FzTGltaXQ6IG51bWJlcjtcbiAgYW1vdW50OiBudW1iZXI7XG4gIHJlY2lwaWVudDogc3RyaW5nO1xuICBub25jZTogbnVtYmVyO1xuICB1c2VyUmVxU2lnOiBzdHJpbmc7XG4gIGdhc1ByaWNlTWF4OiBudW1iZXI7XG59XG5cbi8qKlxuICogVGhlIGV4dHJhIHBhcmFtZXRlcnMgdG8gc2VuZCB0byBwbGF0Zm9ybSBidWlsZCByb3V0ZSBmb3IgaG9wIHRyYW5zYWN0aW9uc1xuICovXG5pbnRlcmZhY2UgSG9wUGFyYW1zIHtcbiAgaG9wUGFyYW1zOiB7XG4gICAgZ2FzUHJpY2VNYXg6IG51bWJlcjtcbiAgICB1c2VyUmVxU2lnOiBzdHJpbmc7XG4gICAgcGF5bWVudElkOiBzdHJpbmc7XG4gICAgZ2FzTGltaXQ6IG51bWJlcjtcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFSVAxNTU5IHtcbiAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IG51bWJlcjtcbiAgbWF4RmVlUGVyR2FzOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMge1xuICBjaGFpbjogc3RyaW5nIHwgbnVtYmVyO1xuICBoYXJkZm9yazogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uUHJlYnVpbGQgZXh0ZW5kcyBCYXNlVHJhbnNhY3Rpb25QcmVidWlsZCB7XG4gIGhvcFRyYW5zYWN0aW9uPzogSG9wUHJlYnVpbGQ7XG4gIGJ1aWxkUGFyYW1zOiB7XG4gICAgcmVjaXBpZW50czogUmVjaXBpZW50W107XG4gIH07XG4gIHJlY2lwaWVudHM6IFRyYW5zYWN0aW9uUmVjaXBpZW50W107XG4gIG5leHRDb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcjtcbiAgZ2FzUHJpY2U6IG51bWJlcjtcbiAgZ2FzTGltaXQ6IG51bWJlcjtcbiAgaXNCYXRjaDogYm9vbGVhbjtcbiAgY29pbjogc3RyaW5nO1xuICB0b2tlbj86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaWduRmluYWxPcHRpb25zIHtcbiAgdHhQcmVidWlsZDoge1xuICAgIGVpcDE1NTk/OiBFSVAxNTU5O1xuICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM7XG4gICAgZ2FzUHJpY2U/OiBzdHJpbmc7XG4gICAgZ2FzTGltaXQ/OiBzdHJpbmc7XG4gICAgcmVjaXBpZW50cz86IFJlY2lwaWVudFtdO1xuICAgIGhhbGZTaWduZWQ/OiB7XG4gICAgICBleHBpcmVUaW1lOiBudW1iZXI7XG4gICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcjtcbiAgICAgIGJhY2t1cEtleU5vbmNlPzogbnVtYmVyO1xuICAgICAgc2lnbmF0dXJlOiBzdHJpbmc7XG4gICAgICB0eEhleD86IHN0cmluZztcbiAgICB9O1xuICAgIG5leHRDb250cmFjdFNlcXVlbmNlSWQ/OiBudW1iZXI7XG4gICAgaG9wVHJhbnNhY3Rpb24/OiBzdHJpbmc7XG4gICAgYmFja3VwS2V5Tm9uY2U/OiBudW1iZXI7XG4gICAgaXNCYXRjaD86IGJvb2xlYW47XG4gICAgdHhIZXg/OiBzdHJpbmc7XG4gICAgZXhwaXJlVGltZT86IG51bWJlcjtcbiAgfTtcbiAgc2lnbmluZ0tleU5vbmNlPzogbnVtYmVyO1xuICB3YWxsZXRDb250cmFjdEFkZHJlc3M/OiBzdHJpbmc7XG4gIHBydjogc3RyaW5nO1xuICByZWNpcGllbnRzPzogUmVjaXBpZW50W107XG4gIGNvbW1vbj86IEV0aExpa2VDb21tb24uZGVmYXVsdDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaWduVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgQmFzZVNpZ25UcmFuc2FjdGlvbk9wdGlvbnMsIFNpZ25GaW5hbE9wdGlvbnMge1xuICBpc0xhc3RTaWduYXR1cmU/OiBib29sZWFuO1xuICBleHBpcmVUaW1lPzogbnVtYmVyO1xuICBzZXF1ZW5jZUlkPzogbnVtYmVyO1xuICBnYXNMaW1pdD86IG51bWJlcjtcbiAgZ2FzUHJpY2U/OiBudW1iZXI7XG4gIGN1c3RvZGlhblRyYW5zYWN0aW9uSWQ/OiBzdHJpbmc7XG4gIGNvbW1vbj86IEV0aExpa2VDb21tb24uZGVmYXVsdDtcbiAgd2FsbGV0VmVyc2lvbj86IG51bWJlcjtcbn1cblxuZXhwb3J0IHR5cGUgU2lnbmVkVHJhbnNhY3Rpb24gPSBIYWxmU2lnbmVkVHJhbnNhY3Rpb24gfCBGdWxseVNpZ25lZFRyYW5zYWN0aW9uO1xuXG5leHBvcnQgaW50ZXJmYWNlIEZlZXNVc2VkIHtcbiAgZ2FzUHJpY2U6IG51bWJlcjtcbiAgZ2FzTGltaXQ6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFByZWNyZWF0ZUJpdEdvT3B0aW9ucyB7XG4gIGVudGVycHJpc2U/OiBzdHJpbmc7XG4gIG5ld0ZlZUFkZHJlc3M/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT2ZmbGluZVZhdWx0VHhJbmZvIHtcbiAgbmV4dENvbnRyYWN0U2VxdWVuY2VJZD86IHN0cmluZztcbiAgY29udHJhY3RTZXF1ZW5jZUlkPzogc3RyaW5nO1xuICB0eD86IHN0cmluZztcbiAgdHhIZXg/OiBzdHJpbmc7XG4gIHVzZXJLZXk/OiBzdHJpbmc7XG4gIGJhY2t1cEtleT86IHN0cmluZztcbiAgY29pbjogc3RyaW5nO1xuICBnYXNQcmljZTogbnVtYmVyO1xuICBnYXNMaW1pdDogbnVtYmVyO1xuICByZWNpcGllbnRzOiBSZWNpcGllbnRbXTtcbiAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiBzdHJpbmc7XG4gIGFtb3VudDogc3RyaW5nO1xuICBiYWNrdXBLZXlOb25jZTogbnVtYmVyO1xuICAvLyBGb3IgRXRoIFNwZWNpZmljIENvaW5zXG4gIGVpcDE1NTk/OiBFSVAxNTU5O1xuICByZXBsYXlQcm90ZWN0aW9uT3B0aW9ucz86IFJlcGxheVByb3RlY3Rpb25PcHRpb25zO1xuICAvLyBGb3IgSG90IFdhbGxldCBFdm1CYXNlZENyb3NzQ2hhaW5SZWNvdmVyeSBTcGVjaWZpY1xuICBoYWxmU2lnbmVkPzogSGFsZlNpZ25lZFRyYW5zYWN0aW9uO1xuICBmZWVzVXNlZD86IEZlZXNVc2VkO1xuICBpc0V2bUJhc2VkQ3Jvc3NDaGFpblJlY292ZXJ5PzogYm9vbGVhbjtcbiAgd2FsbGV0VmVyc2lvbj86IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFVuZm9ybWF0dGVkVHhJbmZvIHtcbiAgcmVjaXBpZW50OiBSZWNpcGllbnQ7XG59XG5cbmV4cG9ydCB0eXBlIFVuc2lnbmVkU3dlZXBUeE1QQ3YyID0ge1xuICB0eFJlcXVlc3RzOiB7XG4gICAgdHJhbnNhY3Rpb25zOiBbXG4gICAgICB7XG4gICAgICAgIHVuc2lnbmVkVHg6IFVuc2lnbmVkVHJhbnNhY3Rpb25Uc3M7XG4gICAgICAgIG5vbmNlOiBudW1iZXI7XG4gICAgICAgIHNpZ25hdHVyZVNoYXJlczogW107XG4gICAgICB9XG4gICAgXTtcbiAgICB3YWxsZXRDb2luOiBzdHJpbmc7XG4gIH1bXTtcbn07XG5cbmV4cG9ydCB0eXBlIFVuc2lnbmVkQnVpbENvbnNvbGlkYXRpb24gPSB7XG4gIHRyYW5zYWN0aW9uczogTVBDU3dlZXBUeHNbXSB8IFVuc2lnbmVkU3dlZXBUeE1QQ3YyW10gfCBSZWNvdmVyeUluZm9bXSB8IE9mZmxpbmVWYXVsdFR4SW5mb1tdO1xuICBsYXN0U2NhbkluZGV4OiBudW1iZXI7XG59O1xuXG5leHBvcnQgdHlwZSBSZWNvdmVyT3B0aW9uc1dpdGhCeXRlcyA9IHtcbiAgaXNUc3M6IHRydWU7XG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB0aGlzIGlzIG5vIGxvbmdlciB1c2VkXG4gICAqL1xuICBvcGVuU1NMQnl0ZXM/OiBVaW50OEFycmF5O1xufTtcblxuZXhwb3J0IHR5cGUgTm9uVFNTUmVjb3Zlck9wdGlvbnMgPSB7XG4gIGlzVHNzPzogZmFsc2UgfCB1bmRlZmluZWQ7XG59O1xuXG5leHBvcnQgdHlwZSBUU1NSZWNvdmVyT3B0aW9ucyA9IFJlY292ZXJPcHRpb25zV2l0aEJ5dGVzIHwgTm9uVFNTUmVjb3Zlck9wdGlvbnM7XG5cbmV4cG9ydCB0eXBlIFJlY292ZXJPcHRpb25zID0ge1xuICB1c2VyS2V5OiBzdHJpbmc7XG4gIGJhY2t1cEtleTogc3RyaW5nO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IHN0cmluZzsgLy8gdXNlIHRoaXMgYXMgd2FsbGV0QmFzZUFkZHJlc3MgZm9yIFRTU1xuICByZWNvdmVyeURlc3RpbmF0aW9uOiBzdHJpbmc7XG4gIGtyc1Byb3ZpZGVyPzogc3RyaW5nO1xuICBnYXNQcmljZT86IG51bWJlcjtcbiAgZ2FzTGltaXQ/OiBudW1iZXI7XG4gIGVpcDE1NTk/OiBFSVAxNTU5O1xuICByZXBsYXlQcm90ZWN0aW9uT3B0aW9ucz86IFJlcGxheVByb3RlY3Rpb25PcHRpb25zO1xuICBiaXRnb0ZlZUFkZHJlc3M/OiBzdHJpbmc7XG4gIGJpdGdvRGVzdGluYXRpb25BZGRyZXNzPzogc3RyaW5nO1xuICB0b2tlbkNvbnRyYWN0QWRkcmVzcz86IHN0cmluZztcbiAgaW50ZW5kZWRDaGFpbj86IHN0cmluZztcbiAgY29tbW9uPzogRXRoTGlrZUNvbW1vbi5kZWZhdWx0O1xuICBkZXJpdmF0aW9uU2VlZD86IHN0cmluZztcbiAgYXBpS2V5Pzogc3RyaW5nOyAvLyBvcHRpb25hbCBBUEkga2V5IHRvIHVzZSBpbnN0ZWFkIG9mIHRoZSBvbmUgZnJvbSB0aGUgZW52aXJvbm1lbnRcbiAgaXNVbnNpZ25lZFN3ZWVwPzogYm9vbGVhbjsgLy8gc3BlY2lmeSBpZiB0aGlzIGlzIGFuIHVuc2lnbmVkIHJlY292ZXJ5XG59ICYgVFNTUmVjb3Zlck9wdGlvbnM7XG5cbmV4cG9ydCB0eXBlIEdldEJhdGNoRXhlY3V0aW9uSW5mb1JUID0ge1xuICB2YWx1ZXM6IFtzdHJpbmdbXSwgc3RyaW5nW11dO1xuICB0b3RhbEFtb3VudDogc3RyaW5nO1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBCdWlsZFRyYW5zYWN0aW9uUGFyYW1zIHtcbiAgdG86IHN0cmluZztcbiAgbm9uY2U/OiBudW1iZXI7XG4gIHZhbHVlOiBudW1iZXI7XG4gIGRhdGE/OiBCdWZmZXI7XG4gIGdhc1ByaWNlPzogbnVtYmVyO1xuICBnYXNMaW1pdD86IG51bWJlcjtcbiAgZWlwMTU1OT86IEVJUDE1NTk7XG4gIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVjb3ZlcnlJbmZvIHtcbiAgaWQ6IHN0cmluZztcbiAgdHg6IHN0cmluZztcbiAgYmFja3VwS2V5Pzogc3RyaW5nO1xuICBjb2luPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlY292ZXJUb2tlblRyYW5zYWN0aW9uIHtcbiAgaGFsZlNpZ25lZDoge1xuICAgIHJlY2lwaWVudDogUmVjaXBpZW50O1xuICAgIGV4cGlyZVRpbWU6IG51bWJlcjtcbiAgICBjb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcjtcbiAgICBvcGVyYXRpb25IYXNoOiBzdHJpbmc7XG4gICAgc2lnbmF0dXJlOiBzdHJpbmc7XG4gICAgZ2FzTGltaXQ6IG51bWJlcjtcbiAgICBnYXNQcmljZTogbnVtYmVyO1xuICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBzdHJpbmc7XG4gICAgd2FsbGV0SWQ6IHN0cmluZztcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZWNvdmVyVG9rZW5PcHRpb25zIHtcbiAgdG9rZW5Db250cmFjdEFkZHJlc3M6IHN0cmluZztcbiAgd2FsbGV0OiBXYWxsZXQ7XG4gIHJlY2lwaWVudDogc3RyaW5nO1xuICBicm9hZGNhc3Q/OiBib29sZWFuO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICBwcnY/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2V0U2VuZE1ldGhvZEFyZ3NPcHRpb25zIHtcbiAgcmVjaXBpZW50OiBSZWNpcGllbnQ7XG4gIGV4cGlyZVRpbWU6IG51bWJlcjtcbiAgY29udHJhY3RTZXF1ZW5jZUlkOiBudW1iZXI7XG4gIHNpZ25hdHVyZTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNlbmRNZXRob2RBcmdzIHtcbiAgbmFtZTogc3RyaW5nO1xuICB0eXBlOiBzdHJpbmc7XG4gIHZhbHVlOiBhbnk7XG59XG5cbmludGVyZmFjZSBIb3BUcmFuc2FjdGlvbkJ1aWxkT3B0aW9ucyB7XG4gIHdhbGxldDogV2FsbGV0O1xuICByZWNpcGllbnRzOiBSZWNpcGllbnRbXTtcbiAgd2FsbGV0UGFzc3BocmFzZTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkT3B0aW9ucyB7XG4gIGhvcD86IGJvb2xlYW47XG4gIHdhbGxldD86IFdhbGxldDtcbiAgcmVjaXBpZW50cz86IFJlY2lwaWVudFtdO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICBbaW5kZXg6IHN0cmluZ106IHVua25vd247XG59XG5cbmludGVyZmFjZSBGZWVFc3RpbWF0ZSB7XG4gIGdhc0xpbWl0RXN0aW1hdGU6IG51bWJlcjtcbiAgZmVlRXN0aW1hdGU6IG51bWJlcjtcbn1cblxuLy8gVE9ETzogVGhpcyBpbnRlcmZhY2Ugd2lsbCBuZWVkIHRvIGJlIHVwZGF0ZWQgZm9yIHRoZSBuZXcgZmVlIG1vZGVsIGludHJvZHVjZWQgaW4gdGhlIExvbmRvbiBIYXJkIEZvcmtcbmludGVyZmFjZSBFdGhUcmFuc2FjdGlvblBhcmFtcyBleHRlbmRzIFRyYW5zYWN0aW9uUGFyYW1zIHtcbiAgZ2FzUHJpY2U/OiBudW1iZXI7XG4gIGdhc0xpbWl0PzogbnVtYmVyO1xuICBob3BQYXJhbXM/OiBIb3BQYXJhbXM7XG4gIGhvcD86IGJvb2xlYW47XG4gIHByZWJ1aWxkVHg/OiBQcmVidWlsZFRyYW5zYWN0aW9uUmVzdWx0O1xuICB0b2tlbk5hbWU/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhQcmVidWlsZDogVHJhbnNhY3Rpb25QcmVidWlsZDtcbiAgdHhQYXJhbXM6IEV0aFRyYW5zYWN0aW9uUGFyYW1zO1xufVxuXG5pbnRlcmZhY2UgUHJlc2lnblRyYW5zYWN0aW9uT3B0aW9ucyBleHRlbmRzIFRyYW5zYWN0aW9uUHJlYnVpbGQsIEJhc2VQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgd2FsbGV0OiBXYWxsZXQ7XG59XG5cbmludGVyZmFjZSBFdGhBZGRyZXNzQ29pblNwZWNpZmljcyBleHRlbmRzIEFkZHJlc3NDb2luU3BlY2lmaWMge1xuICBmb3J3YXJkZXJWZXJzaW9uOiBudW1iZXI7XG4gIHNhbHQ/OiBzdHJpbmc7XG4gIGZlZUFkZHJlc3M/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjb25zdCBERUZBVUxUX1NDQU5fRkFDVE9SID0gMjA7XG5leHBvcnQgaW50ZXJmYWNlIEV0aENvbnNvbGlkYXRpb25SZWNvdmVyeU9wdGlvbnMge1xuICBjb2luTmFtZT86IHN0cmluZztcbiAgd2FsbGV0Q29udHJhY3RBZGRyZXNzPzogc3RyaW5nO1xuICBhcGlLZXk/OiBzdHJpbmc7XG4gIGlzVHNzPzogYm9vbGVhbjtcbiAgdXNlcktleT86IHN0cmluZztcbiAgYmFja3VwS2V5Pzogc3RyaW5nO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICByZWNvdmVyeURlc3RpbmF0aW9uPzogc3RyaW5nO1xuICBrcnNQcm92aWRlcj86IHN0cmluZztcbiAgZ2FzUHJpY2U/OiBudW1iZXI7XG4gIGdhc0xpbWl0PzogbnVtYmVyO1xuICBlaXAxNTU5PzogRUlQMTU1OTtcbiAgcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM/OiBSZXBsYXlQcm90ZWN0aW9uT3B0aW9ucztcbiAgYml0Z29GZWVBZGRyZXNzPzogc3RyaW5nO1xuICBiaXRnb0Rlc3RpbmF0aW9uQWRkcmVzcz86IHN0cmluZztcbiAgdG9rZW5Db250cmFjdEFkZHJlc3M/OiBzdHJpbmc7XG4gIGludGVuZGVkQ2hhaW4/OiBzdHJpbmc7XG4gIGNvbW1vbj86IEV0aExpa2VDb21tb24uZGVmYXVsdDtcbiAgZGVyaXZhdGlvblNlZWQ/OiBzdHJpbmc7XG4gIGJpdGdvS2V5Pzogc3RyaW5nO1xuICBzdGFydGluZ1NjYW5JbmRleD86IG51bWJlcjtcbiAgZW5kaW5nU2NhbkluZGV4PzogbnVtYmVyO1xuICBpZ25vcmVBZGRyZXNzVHlwZXM/OiB1bmtub3duO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFZlcmlmeUV0aEFkZHJlc3NPcHRpb25zIGV4dGVuZHMgQmFzZVZlcmlmeUFkZHJlc3NPcHRpb25zIHtcbiAgYmFzZUFkZHJlc3M6IHN0cmluZztcbiAgY29pblNwZWNpZmljOiBFdGhBZGRyZXNzQ29pblNwZWNpZmljcztcbiAgZm9yd2FyZGVyVmVyc2lvbj86IG51bWJlcjtcbiAgd2FsbGV0VmVyc2lvbj86IG51bWJlcjtcbn1cblxuZXhwb3J0IHR5cGUgVHNzVmVyaWZ5RXRoQWRkcmVzc09wdGlvbnMgPSBUc3NWZXJpZnlBZGRyZXNzT3B0aW9ucyAmIFZlcmlmeUV0aEFkZHJlc3NPcHRpb25zO1xuXG4vKipcbiAqIEtleWNoYWluIHdpdGggZXRoQWRkcmVzcyBmb3IgQklQMzIgd2FsbGV0IHZlcmlmaWNhdGlvbiAoVjEsIFYyLCBWNClcbiAqIFVzZWQgZm9yIHdhbGxldHMgdGhhdCBkZXJpdmUgYWRkcmVzc2VzIHVzaW5nIEV0aGVyZXVtIGFkZHJlc3NlcyBmcm9tIGtleWNoYWluc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIEtleWNoYWluV2l0aEV0aEFkZHJlc3Mge1xuICBldGhBZGRyZXNzOiBzdHJpbmc7XG4gIHB1Yjogc3RyaW5nO1xufVxuXG4vKipcbiAqIEJJUDMyIHdhbGxldCBiYXNlIGFkZHJlc3MgdmVyaWZpY2F0aW9uIG9wdGlvbnNcbiAqIFN1cHBvcnRzIFYxLCBWMiwgYW5kIFY0IHdhbGxldHMgdGhhdCB1c2UgZXRoQWRkcmVzcy1iYXNlZCBkZXJpdmF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmVyaWZ5Q29udHJhY3RCYXNlQWRkcmVzc09wdGlvbnMgZXh0ZW5kcyBWZXJpZnlFdGhBZGRyZXNzT3B0aW9ucyB7XG4gIHdhbGxldFZlcnNpb246IG51bWJlcjtcbiAga2V5Y2hhaW5zOiBLZXljaGFpbldpdGhFdGhBZGRyZXNzW107XG59XG5cbi8qKlxuICogVHlwZSBndWFyZCB0byBjaGVjayBpZiBwYXJhbXMgYXJlIGZvciBCSVAzMiBiYXNlIGFkZHJlc3MgdmVyaWZpY2F0aW9uIChWMSwgVjIsIFY0KVxuICogVGhlc2Ugd2FsbGV0IHZlcnNpb25zIHVzZSBldGhBZGRyZXNzIGZvciBhZGRyZXNzIGRlcml2YXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVmVyaWZ5Q29udHJhY3RCYXNlQWRkcmVzc09wdGlvbnMoXG4gIHBhcmFtczogVmVyaWZ5RXRoQWRkcmVzc09wdGlvbnMgfCBUc3NWZXJpZnlFdGhBZGRyZXNzT3B0aW9uc1xuKTogcGFyYW1zIGlzIFZlcmlmeUNvbnRyYWN0QmFzZUFkZHJlc3NPcHRpb25zIHtcbiAgcmV0dXJuIChcbiAgICAocGFyYW1zLndhbGxldFZlcnNpb24gPT09IDEgfHwgcGFyYW1zLndhbGxldFZlcnNpb24gPT09IDIgfHwgcGFyYW1zLndhbGxldFZlcnNpb24gPT09IDQpICYmXG4gICAgJ2tleWNoYWlucycgaW4gcGFyYW1zICYmXG4gICAgQXJyYXkuaXNBcnJheShwYXJhbXMua2V5Y2hhaW5zKSAmJlxuICAgIHBhcmFtcy5rZXljaGFpbnMubGVuZ3RoID09PSAzICYmXG4gICAgcGFyYW1zLmtleWNoYWlucy5ldmVyeSgoa2M6IGFueSkgPT4gJ2V0aEFkZHJlc3MnIGluIGtjICYmIHR5cGVvZiBrYy5ldGhBZGRyZXNzID09PSAnc3RyaW5nJylcbiAgKTtcbn1cblxuY29uc3QgZGVidWcgPSBkZWJ1Z0xpYignYml0Z286djI6ZXRobGlrZScpO1xuXG5leHBvcnQgY29uc3Qgb3B0aW9uYWxEZXBzID0ge1xuICBnZXQgZXRoQWJpKCkge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gcmVxdWlyZSgnZXRoZXJldW1qcy1hYmknKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBkZWJ1ZygndW5hYmxlIHRvIGxvYWQgZXRoZXJldW1qcy1hYmk6Jyk7XG4gICAgICBkZWJ1ZyhlLnN0YWNrKTtcbiAgICAgIHRocm93IG5ldyBFdGhlcmV1bUxpYnJhcnlVbmF2YWlsYWJsZUVycm9yKGBldGhlcmV1bWpzLWFiaWApO1xuICAgIH1cbiAgfSxcblxuICBnZXQgZXRoVXRpbCgpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHJlcXVpcmUoJ2V0aGVyZXVtanMtdXRpbCcpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGRlYnVnKCd1bmFibGUgdG8gbG9hZCBldGhlcmV1bWpzLXV0aWw6Jyk7XG4gICAgICBkZWJ1ZyhlLnN0YWNrKTtcbiAgICAgIHRocm93IG5ldyBFdGhlcmV1bUxpYnJhcnlVbmF2YWlsYWJsZUVycm9yKGBldGhlcmV1bWpzLXV0aWxgKTtcbiAgICB9XG4gIH0sXG5cbiAgZ2V0IEV0aFR4KCk6IHR5cGVvZiBFdGhMaWtlVHhMaWIge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gcmVxdWlyZSgnQGV0aGVyZXVtanMvdHgnKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBkZWJ1ZygndW5hYmxlIHRvIGxvYWQgQGV0aGVyZXVtanMvdHgnKTtcbiAgICAgIGRlYnVnKGUuc3RhY2spO1xuICAgICAgdGhyb3cgbmV3IEV0aGVyZXVtTGlicmFyeVVuYXZhaWxhYmxlRXJyb3IoYEBldGhlcmV1bWpzL3R4YCk7XG4gICAgfVxuICB9LFxuXG4gIGdldCBFdGhDb21tb24oKTogdHlwZW9mIEV0aExpa2VDb21tb24ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gcmVxdWlyZSgnQGV0aGVyZXVtanMvY29tbW9uJyk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZGVidWcoJ3VuYWJsZSB0byBsb2FkIEBldGhlcmV1bWpzL2NvbW1vbjonKTtcbiAgICAgIGRlYnVnKGUuc3RhY2spO1xuICAgICAgdGhyb3cgbmV3IEV0aGVyZXVtTGlicmFyeVVuYXZhaWxhYmxlRXJyb3IoYEBldGhlcmV1bWpzL2NvbW1vbmApO1xuICAgIH1cbiAgfSxcbn07XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBBYnN0cmFjdEV0aExpa2VOZXdDb2lucyBleHRlbmRzIEFic3RyYWN0RXRoTGlrZUNvaW4ge1xuICBzdGF0aWMgaG9wVHJhbnNhY3Rpb25TYWx0ID0gJ2JpdGdvSG9wQWRkcmVzc1JlcXVlc3RTYWx0JztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHNlbmRNZXRob2ROYW1lOiAnc2VuZE11bHRpU2lnJyB8ICdzZW5kTXVsdGlTaWdUb2tlbic7XG5cbiAgcmVhZG9ubHkgc3RhdGljc0NvaW4/OiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+O1xuXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihiaXRnbzogQml0R29CYXNlLCBzdGF0aWNzQ29pbj86IFJlYWRvbmx5PFN0YXRpY3NCYXNlQ29pbj4pIHtcbiAgICBzdXBlcihiaXRnbywgc3RhdGljc0NvaW4pO1xuXG4gICAgaWYgKCFzdGF0aWNzQ29pbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIGNvbnN0cnVjdG9yIHBhcmFtZXRlciBzdGF0aWNzQ29pbicpO1xuICAgIH1cblxuICAgIHRoaXMuc3RhdGljc0NvaW4gPSBzdGF0aWNzQ29pbjtcbiAgICB0aGlzLnNlbmRNZXRob2ROYW1lID0gJ3NlbmRNdWx0aVNpZyc7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHRvIHJldHVybiB0aGUgY29pbidzIG5ldHdvcmsgb2JqZWN0XG4gICAqIEByZXR1cm5zIHtFdGhMaWtlTmV0d29yayB8IHVuZGVmaW5lZH1cbiAgICovXG4gIGdldE5ldHdvcmsoKTogRXRoTGlrZU5ldHdvcmsgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnN0YXRpY3NDb2luPy5uZXR3b3JrIGFzIEV0aExpa2VOZXR3b3JrO1xuICB9XG5cbiAgLyoqXG4gICAqIEV2YWx1YXRlcyB3aGV0aGVyIGFuIGFkZHJlc3Mgc3RyaW5nIGlzIHZhbGlkIGZvciB0aGlzIGNvaW5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3NcbiAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgYWRkcmVzcyBpcyB0aGUgdmFsaWQgZXRobGlrZSBhZGRlcnNzXG4gICAqL1xuICBpc1ZhbGlkQWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gb3B0aW9uYWxEZXBzLmV0aFV0aWwuaXNWYWxpZEFkZHJlc3Mob3B0aW9uYWxEZXBzLmV0aFV0aWwuYWRkSGV4UHJlZml4KGFkZHJlc3MpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGbGFnIGZvciBzZW5kaW5nIGRhdGEgYWxvbmcgd2l0aCB0cmFuc2FjdGlvbnNcbiAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgb2theSB0byBzZW5kIHR4IGRhdGEgKEVUSCksIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgdHJhbnNhY3Rpb25EYXRhQWxsb3dlZCgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBzdXBwb3J0c01lc3NhZ2VTaWduaW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICovXG4gIHN1cHBvcnRzU2lnbmluZ1R5cGVkRGF0YSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWZhdWx0IGV4cGlyZSB0aW1lIGZvciBhIGNvbnRyYWN0IGNhbGwgKDEgd2VlaylcbiAgICogQHJldHVybnMge251bWJlcn0gVGltZSBpbiBzZWNvbmRzXG4gICAqL1xuICBnZXREZWZhdWx0RXhwaXJlVGltZSgpOiBudW1iZXIge1xuICAgIHJldHVybiBNYXRoLmZsb29yKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC8gMTAwMCkgKyA2MCAqIDYwICogMjQgKiA3O1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byBnZXQgdGhlIGN1c3RvbSBjaGFpbiBjb21tb24gb2JqZWN0IGJhc2VkIG9uIHBhcmFtcyBmcm9tIHJlY292ZXJ5XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjaGFpbklkIC0gdGhlIGNoYWluIGlkIG9mIHRoZSBjdXN0b20gY2hhaW5cbiAgICogQHJldHVybnMge0V0aExpa2VDb21tb24uZGVmYXVsdH1cbiAgICovXG4gIHN0YXRpYyBnZXRDdXN0b21DaGFpbkNvbW1vbihjaGFpbklkOiBudW1iZXIpOiBFdGhMaWtlQ29tbW9uLmRlZmF1bHQge1xuICAgIGNvbnN0IGNvaW5OYW1lID0gY29pbnMuY29pbk5hbWVGcm9tQ2hhaW5JZChjaGFpbklkKTtcbiAgICBpZiAoIWNvaW5OYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgQ2hhaW5JZE5vdEZvdW5kRXJyb3IoY2hhaW5JZCk7XG4gICAgfVxuICAgIGNvbnN0IGNvaW4gPSBjb2lucy5nZXQoY29pbk5hbWUpO1xuICAgIGNvbnN0IGV0aExpa2VDb21tb24gPSBnZXRDb21tb24oY29pbi5uZXR3b3JrIGFzIEV0aExpa2VOZXR3b3JrKTtcbiAgICByZXR1cm4gZXRoTGlrZUNvbW1vbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGNvcnJlY3QgRXRoIENvbW1vbiBvYmplY3QgYmFzZWQgb24gcGFyYW1zIGZyb20gZWl0aGVyIHJlY292ZXJ5IG9yIHR4IGJ1aWxkaW5nXG4gICAqIEBwYXJhbSB7RUlQMTU1OX0gZWlwMTU1OSAtIGNvbmZpZ3MgdGhhdCBzcGVjaWZ5IHdoZXRoZXIgd2Ugc2hvdWxkIGNvbnN0cnVjdCBhbiBlaXAxNTU5IHR4XG4gICAqIEBwYXJhbSB7UmVwbGF5UHJvdGVjdGlvbk9wdGlvbnN9IHJlcGxheVByb3RlY3Rpb25PcHRpb25zIC0gY2hlY2sgaWYgY2hhaW4gaWQgc3VwcG9ydHMgcmVwbGF5IHByb3RlY3Rpb25cbiAgICogQHJldHVybnMge0V0aExpa2VDb21tb24uZGVmYXVsdH1cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdldEV0aExpa2VDb21tb24oXG4gICAgZWlwMTU1OT86IEVJUDE1NTksXG4gICAgcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM/OiBSZXBsYXlQcm90ZWN0aW9uT3B0aW9uc1xuICApOiBFdGhMaWtlQ29tbW9uLmRlZmF1bHQge1xuICAgIC8vIGlmIGVpcDE1NTkgcGFyYW1zIGFyZSBzcGVjaWZpZWQsIGRlZmF1bHQgdG8gbG9uZG9uIGhhcmRmb3JrLCBvdGhlcndpc2UsXG4gICAgLy8gZGVmYXVsdCB0byBwZXRlcnNidXJnIHRvIGF2b2lkIHJlcGxheSBwcm90ZWN0aW9uIGlzc3Vlc1xuICAgIGNvbnN0IGRlZmF1bHRIYXJkZm9yayA9ICEhZWlwMTU1OSA/ICdsb25kb24nIDogb3B0aW9uYWxEZXBzLkV0aENvbW1vbi5IYXJkZm9yay5QZXRlcnNidXJnO1xuICAgIGNvbnN0IGV0aExpa2VDb21tb24gPSBBYnN0cmFjdEV0aExpa2VOZXdDb2lucy5nZXRDdXN0b21DaGFpbkNvbW1vbihyZXBsYXlQcm90ZWN0aW9uT3B0aW9ucz8uY2hhaW4gYXMgbnVtYmVyKTtcbiAgICBldGhMaWtlQ29tbW9uLnNldEhhcmRmb3JrKHJlcGxheVByb3RlY3Rpb25PcHRpb25zPy5oYXJkZm9yayA/PyBkZWZhdWx0SGFyZGZvcmspO1xuICAgIHJldHVybiBldGhMaWtlQ29tbW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byBidWlsZCB0aGUgdHggb2JqZWN0XG4gICAqIEBwYXJhbSB7QnVpbGRUcmFuc2FjdGlvblBhcmFtc30gcGFyYW1zIC0gcGFyYW1zIHRvIGJ1aWxkIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm5zIHtFdGhMaWtlVHhMaWIuRmVlTWFya2V0RUlQMTU1OVRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLlRyYW5zYWN0aW9ufVxuICAgKi9cbiAgc3RhdGljIGJ1aWxkVHJhbnNhY3Rpb24oXG4gICAgcGFyYW1zOiBCdWlsZFRyYW5zYWN0aW9uUGFyYW1zXG4gICk6IEV0aExpa2VUeExpYi5GZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb24gfCBFdGhMaWtlVHhMaWIuVHJhbnNhY3Rpb24ge1xuICAgIC8vIGlmIGVpcDE1NTkgcGFyYW1zIGFyZSBzcGVjaWZpZWQsIGRlZmF1bHQgdG8gbG9uZG9uIGhhcmRmb3JrLCBvdGhlcndpc2UsXG4gICAgLy8gZGVmYXVsdCB0byB0YW5nZXJpbmUgd2hpc3RsZSB0byBhdm9pZCByZXBsYXkgcHJvdGVjdGlvbiBpc3N1ZXNcbiAgICBjb25zdCBldGhMaWtlQ29tbW9uID0gQWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuZ2V0RXRoTGlrZUNvbW1vbihwYXJhbXMuZWlwMTU1OSwgcGFyYW1zLnJlcGxheVByb3RlY3Rpb25PcHRpb25zKTtcbiAgICBjb25zdCBiYXNlUGFyYW1zID0ge1xuICAgICAgdG86IHBhcmFtcy50byxcbiAgICAgIG5vbmNlOiBwYXJhbXMubm9uY2UsXG4gICAgICB2YWx1ZTogcGFyYW1zLnZhbHVlLFxuICAgICAgZGF0YTogcGFyYW1zLmRhdGEsXG4gICAgICBnYXNMaW1pdDogbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHBhcmFtcy5nYXNMaW1pdCksXG4gICAgfTtcblxuICAgIGNvbnN0IHVuc2lnbmVkRXRoVHggPSAhIXBhcmFtcy5laXAxNTU5XG4gICAgICA/IG9wdGlvbmFsRGVwcy5FdGhUeC5GZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb24uZnJvbVR4RGF0YShcbiAgICAgICAgICB7XG4gICAgICAgICAgICAuLi5iYXNlUGFyYW1zLFxuICAgICAgICAgICAgbWF4RmVlUGVyR2FzOiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocGFyYW1zLmVpcDE1NTkubWF4RmVlUGVyR2FzKSxcbiAgICAgICAgICAgIG1heFByaW9yaXR5RmVlUGVyR2FzOiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocGFyYW1zLmVpcDE1NTkubWF4UHJpb3JpdHlGZWVQZXJHYXMpLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBjb21tb246IGV0aExpa2VDb21tb24gfVxuICAgICAgICApXG4gICAgICA6IG9wdGlvbmFsRGVwcy5FdGhUeC5UcmFuc2FjdGlvbi5mcm9tVHhEYXRhKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIC4uLmJhc2VQYXJhbXMsXG4gICAgICAgICAgICBnYXNQcmljZTogbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHBhcmFtcy5nYXNQcmljZSksXG4gICAgICAgICAgfSxcbiAgICAgICAgICB7IGNvbW1vbjogZXRoTGlrZUNvbW1vbiB9XG4gICAgICAgICk7XG5cbiAgICByZXR1cm4gdW5zaWduZWRFdGhUeDtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyeSBleHBsb3JlciBmb3IgdGhlIGJhbGFuY2Ugb2YgYW4gYWRkcmVzc1xuICAgKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzcyAtIHRoZSBFVEhMaWtlIGFkZHJlc3NcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFwaUtleSAtIG9wdGlvbmFsIEFQSSBrZXkgdG8gdXNlIGluc3RlYWQgb2YgdGhlIG9uZSBmcm9tIHRoZSBlbnZpcm9ubWVudFxuICAgKiBAcmV0dXJucyB7QmlnTnVtYmVyfSBhZGRyZXNzIGJhbGFuY2VcbiAgICovXG4gIGFzeW5jIHF1ZXJ5QWRkcmVzc0JhbGFuY2UoYWRkcmVzczogc3RyaW5nLCBhcGlLZXk/OiBzdHJpbmcpOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeShcbiAgICAgIHtcbiAgICAgICAgY2hhaW5pZDogdGhpcy5nZXRDaGFpbklkKCkudG9TdHJpbmcoKSxcbiAgICAgICAgbW9kdWxlOiAnYWNjb3VudCcsXG4gICAgICAgIGFjdGlvbjogJ2JhbGFuY2UnLFxuICAgICAgICBhZGRyZXNzOiBhZGRyZXNzLFxuICAgICAgfSxcbiAgICAgIGFwaUtleVxuICAgICk7XG4gICAgLy8gdGhyb3cgaWYgdGhlIHJlc3VsdCBkb2VzIG5vdCBleGlzdCBvciB0aGUgcmVzdWx0IGlzIG5vdCBhIHZhbGlkIG51bWJlclxuICAgIGlmICghcmVzdWx0IHx8ICFyZXN1bHQucmVzdWx0IHx8IGlzTmFOKHJlc3VsdC5yZXN1bHQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBvYnRhaW4gYWRkcmVzcyBiYWxhbmNlIGZvciAke2FkZHJlc3N9IGZyb20gdGhlIGV4cGxvcmVyLCBnb3Q6ICR7cmVzdWx0LnJlc3VsdH1gKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihyZXN1bHQucmVzdWx0LCAxMCk7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtSZWNpcGllbnRbXX0gcmVjaXBpZW50cyAtIHRoZSByZWNpcGllbnRzIG9mIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge251bWJlcn0gZXhwaXJlVGltZSAtIHRoZSBleHBpcmUgdGltZSBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvbnRyYWN0U2VxdWVuY2VJZCAtIHRoZSBjb250cmFjdCBzZXF1ZW5jZSBpZCBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge3N0cmluZ31cbiAgICovXG4gIGdldE9wZXJhdGlvblNoYTNGb3JFeGVjdXRlQW5kQ29uZmlybShcbiAgICByZWNpcGllbnRzOiBSZWNpcGllbnRbXSxcbiAgICBleHBpcmVUaW1lOiBudW1iZXIsXG4gICAgY29udHJhY3RTZXF1ZW5jZUlkOiBudW1iZXJcbiAgKTogc3RyaW5nIHtcbiAgICBpZiAoIXJlY2lwaWVudHMgfHwgIUFycmF5LmlzQXJyYXkocmVjaXBpZW50cykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0aW5nIGFycmF5IG9mIHJlY2lwaWVudHMnKTtcbiAgICB9XG5cbiAgICAvLyBSaWdodCBub3cgd2Ugb25seSBzdXBwb3J0IDEgcmVjaXBpZW50XG4gICAgaWYgKHJlY2lwaWVudHMubGVuZ3RoICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ211c3Qgc2VuZCB0byBleGFjdGx5IDEgcmVjaXBpZW50Jyk7XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzTnVtYmVyKGV4cGlyZVRpbWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGlyZVRpbWUgbXVzdCBiZSBudW1iZXIgb2Ygc2Vjb25kcyBzaW5jZSBlcG9jaCcpO1xuICAgIH1cblxuICAgIGlmICghXy5pc051bWJlcihjb250cmFjdFNlcXVlbmNlSWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NvbnRyYWN0U2VxdWVuY2VJZCBtdXN0IGJlIG51bWJlcicpO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlucHV0c1xuICAgIHJlY2lwaWVudHMuZm9yRWFjaChmdW5jdGlvbiAocmVjaXBpZW50KSB7XG4gICAgICBpZiAoXG4gICAgICAgICFfLmlzU3RyaW5nKHJlY2lwaWVudC5hZGRyZXNzKSB8fFxuICAgICAgICAhb3B0aW9uYWxEZXBzLmV0aFV0aWwuaXNWYWxpZEFkZHJlc3Mob3B0aW9uYWxEZXBzLmV0aFV0aWwuYWRkSGV4UHJlZml4KHJlY2lwaWVudC5hZGRyZXNzKSlcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgYWRkcmVzczogJyArIHJlY2lwaWVudC5hZGRyZXNzKTtcbiAgICAgIH1cblxuICAgICAgbGV0IGFtb3VudDogQmlnTnVtYmVyO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYW1vdW50ID0gbmV3IEJpZ051bWJlcihyZWNpcGllbnQuYW1vdW50KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFtb3VudCBmb3I6ICcgKyByZWNpcGllbnQuYWRkcmVzcyArICcgLSBzaG91bGQgYmUgbnVtZXJpYycpO1xuICAgICAgfVxuXG4gICAgICByZWNpcGllbnQuYW1vdW50ID0gYW1vdW50LnRvRml4ZWQoMCk7XG5cbiAgICAgIGlmIChyZWNpcGllbnQuZGF0YSAmJiAhXy5pc1N0cmluZyhyZWNpcGllbnQuZGF0YSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdEYXRhIGZvciByZWNpcGllbnQgJyArIHJlY2lwaWVudC5hZGRyZXNzICsgJyAtIHNob3VsZCBiZSBvZiB0eXBlIGhleCBzdHJpbmcnKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGNvbnN0IHJlY2lwaWVudCA9IHJlY2lwaWVudHNbMF07XG4gICAgcmV0dXJuIG9wdGlvbmFsRGVwcy5ldGhVdGlsLmJ1ZmZlclRvSGV4KFxuICAgICAgb3B0aW9uYWxEZXBzLmV0aEFiaS5zb2xpZGl0eVNIQTMoLi4udGhpcy5nZXRPcGVyYXRpb24ocmVjaXBpZW50LCBleHBpcmVUaW1lLCBjb250cmFjdFNlcXVlbmNlSWQpKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRyYW5zZmVyIG9wZXJhdGlvbiBmb3IgY29pblxuICAgKiBAcGFyYW0ge1JlY2lwaWVudH0gcmVjaXBpZW50IC0gcmVjaXBpZW50IGluZm9cbiAgICogQHBhcmFtIHtudW1iZXJ9IGV4cGlyZVRpbWUgLSBleHBpcnkgdGltZVxuICAgKiBAcGFyYW0ge251bWJlcn0gY29udHJhY3RTZXF1ZW5jZUlkIC0gc2VxdWVuY2UgaWRcbiAgICogQHJldHVybnMge0FycmF5fSBvcGVyYXRpb24gYXJyYXlcbiAgICovXG4gIGdldE9wZXJhdGlvbihyZWNpcGllbnQ6IFJlY2lwaWVudCwgZXhwaXJlVGltZTogbnVtYmVyLCBjb250cmFjdFNlcXVlbmNlSWQ6IG51bWJlcik6IChzdHJpbmcgfCBCdWZmZXIpW11bXSB7XG4gICAgY29uc3QgbmV0d29yayA9IHRoaXMuZ2V0TmV0d29yaygpIGFzIEV0aExpa2VOZXR3b3JrO1xuICAgIHJldHVybiBbXG4gICAgICBbJ3N0cmluZycsICdhZGRyZXNzJywgJ3VpbnQnLCAnYnl0ZXMnLCAndWludCcsICd1aW50J10sXG4gICAgICBbXG4gICAgICAgIG5ldHdvcmsubmF0aXZlQ29pbk9wZXJhdGlvbkhhc2hQcmVmaXgsXG4gICAgICAgIG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihvcHRpb25hbERlcHMuZXRoVXRpbC5zdHJpcEhleFByZWZpeChyZWNpcGllbnQuYWRkcmVzcyksIDE2KSxcbiAgICAgICAgcmVjaXBpZW50LmFtb3VudCxcbiAgICAgICAgQnVmZmVyLmZyb20ob3B0aW9uYWxEZXBzLmV0aFV0aWwuc3RyaXBIZXhQcmVmaXgob3B0aW9uYWxEZXBzLmV0aFV0aWwucGFkVG9FdmVuKHJlY2lwaWVudC5kYXRhIHx8ICcnKSksICdoZXgnKSxcbiAgICAgICAgZXhwaXJlVGltZSxcbiAgICAgICAgY29udHJhY3RTZXF1ZW5jZUlkLFxuICAgICAgXSxcbiAgICBdO1xuICB9XG5cbiAgLyoqXG4gICAqIFF1ZXJpZXMgdGhlIGNvbnRyYWN0ICh2aWEgZXhwbG9yZXIgQVBJKSBmb3IgdGhlIG5leHQgc2VxdWVuY2UgSURcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgLSBhZGRyZXNzIG9mIHRoZSBjb250cmFjdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gYXBpS2V5IC0gb3B0aW9uYWwgQVBJIGtleSB0byB1c2UgaW5zdGVhZCBvZiB0aGUgb25lIGZyb20gdGhlIGVudmlyb25tZW50XG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE51bWJlcj59IHNlcXVlbmNlIElEXG4gICAqL1xuICBhc3luYyBxdWVyeVNlcXVlbmNlSWQoYWRkcmVzczogc3RyaW5nLCBhcGlLZXk/OiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIC8vIEdldCBzZXF1ZW5jZSBJRCB1c2luZyBjb250cmFjdCBjYWxsXG4gICAgY29uc3Qgc2VxdWVuY2VJZE1ldGhvZFNpZ25hdHVyZSA9IG9wdGlvbmFsRGVwcy5ldGhBYmkubWV0aG9kSUQoJ2dldE5leHRTZXF1ZW5jZUlkJywgW10pO1xuICAgIGNvbnN0IHNlcXVlbmNlSWRBcmdzID0gb3B0aW9uYWxEZXBzLmV0aEFiaS5yYXdFbmNvZGUoW10sIFtdKTtcbiAgICBjb25zdCBzZXF1ZW5jZUlkRGF0YSA9IEJ1ZmZlci5jb25jYXQoW3NlcXVlbmNlSWRNZXRob2RTaWduYXR1cmUsIHNlcXVlbmNlSWRBcmdzXSkudG9TdHJpbmcoJ2hleCcpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeShcbiAgICAgIHtcbiAgICAgICAgY2hhaW5pZDogdGhpcy5nZXRDaGFpbklkKCkudG9TdHJpbmcoKSxcbiAgICAgICAgbW9kdWxlOiAncHJveHknLFxuICAgICAgICBhY3Rpb246ICdldGhfY2FsbCcsXG4gICAgICAgIHRvOiBhZGRyZXNzLFxuICAgICAgICBkYXRhOiBzZXF1ZW5jZUlkRGF0YSxcbiAgICAgICAgdGFnOiAnbGF0ZXN0JyxcbiAgICAgIH0sXG4gICAgICBhcGlLZXlcbiAgICApO1xuICAgIGlmICghcmVzdWx0IHx8ICFyZXN1bHQucmVzdWx0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBvYnRhaW4gc2VxdWVuY2UgSUQgZnJvbSBleHBsb3JlciwgZ290OiAnICsgcmVzdWx0LnJlc3VsdCk7XG4gICAgfVxuICAgIGNvbnN0IHNlcXVlbmNlSWRIZXggPSByZXN1bHQucmVzdWx0O1xuICAgIHJldHVybiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4oc2VxdWVuY2VJZEhleC5zbGljZSgyKSwgMTYpLnRvTnVtYmVyKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVjb3ZlciBhbiB1bnN1cHBvcnRlZCB0b2tlbiBmcm9tIGEgQml0R28gbXVsdGlzaWcgd2FsbGV0XG4gICAqIFRoaXMgYnVpbGRzIGEgaGFsZi1zaWduZWQgdHJhbnNhY3Rpb24sIGZvciB3aGljaCB0aGVyZSB3aWxsIGJlIGFuIGFkbWluIHJvdXRlIHRvIGNvLXNpZ24gYW5kIGJyb2FkY2FzdC4gT3B0aW9uYWxseVxuICAgKiB0aGUgdXNlciBjYW4gc2V0IHBhcmFtcy5icm9hZGNhc3QgPSB0cnVlIGFuZCB0aGUgaGFsZi1zaWduZWQgdHggd2lsbCBiZSBzZW50IHRvIEJpdEdvIGZvciBjb3NpZ25pbmcgYW5kIGJyb2FkY2FzdGluZ1xuICAgKiBAcGFyYW0ge1JlY292ZXJUb2tlbk9wdGlvbnN9IHBhcmFtc1xuICAgKiBAcGFyYW0ge1dhbGxldH0gcGFyYW1zLndhbGxldCAtIHRoZSB3YWxsZXQgdG8gcmVjb3ZlciB0aGUgdG9rZW4gZnJvbVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzIC0gdGhlIGNvbnRyYWN0IGFkZHJlc3Mgb2YgdGhlIHVuc3VwcG9ydGVkIHRva2VuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMucmVjaXBpZW50IC0gdGhlIGRlc3RpbmF0aW9uIGFkZHJlc3MgcmVjb3ZlcmVkIHRva2VucyBzaG91bGQgYmUgc2VudCB0b1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLndhbGxldFBhc3NwaHJhc2UgLSB0aGUgd2FsbGV0IHBhc3NwaHJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5wcnYgLSB0aGUgeHBydlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHBhcmFtcy5icm9hZGNhc3QgLSBpZiB0cnVlLCB3ZSB3aWxsIGF1dG9tYXRpY2FsbHkgc3VibWl0IHRoZSBoYWxmLXNpZ25lZCB0eCB0byBCaXRHbyBmb3IgY29zaWduaW5nIGFuZCBicm9hZGNhc3RpbmdcbiAgICogQHJldHVybnMge1Byb21pc2U8UmVjb3ZlclRva2VuVHJhbnNhY3Rpb24+fVxuICAgKi9cbiAgYXN5bmMgcmVjb3ZlclRva2VuKHBhcmFtczogUmVjb3ZlclRva2VuT3B0aW9ucyk6IFByb21pc2U8UmVjb3ZlclRva2VuVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCBuZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKCkgYXMgRXRoTGlrZU5ldHdvcms7XG4gICAgaWYgKCFfLmlzT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgcmVjb3ZlclRva2VuIG11c3QgYmUgcGFzc2VkIGEgcGFyYW1zIG9iamVjdC4gR290ICR7cGFyYW1zfSAodHlwZSAke3R5cGVvZiBwYXJhbXN9KWApO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcykgfHwgIV8uaXNTdHJpbmcocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdG9rZW5Db250cmFjdEFkZHJlc3MgbXVzdCBiZSBhIHN0cmluZywgZ290ICR7XG4gICAgICAgICAgcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzXG4gICAgICAgIH0gKHR5cGUgJHt0eXBlb2YgcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzfSlgXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMudG9rZW5Db250cmFjdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Rva2VuQ29udHJhY3RBZGRyZXNzIG5vdCBhIHZhbGlkIGFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMud2FsbGV0KSB8fCAhKHBhcmFtcy53YWxsZXQgaW5zdGFuY2VvZiBXYWxsZXQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHdhbGxldCBtdXN0IGJlIGEgd2FsbGV0IGluc3RhbmNlLCBnb3QgJHtwYXJhbXMud2FsbGV0fSAodHlwZSAke3R5cGVvZiBwYXJhbXMud2FsbGV0fSlgKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMucmVjaXBpZW50KSB8fCAhXy5pc1N0cmluZyhwYXJhbXMucmVjaXBpZW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGByZWNpcGllbnQgbXVzdCBiZSBhIHN0cmluZywgZ290ICR7cGFyYW1zLnJlY2lwaWVudH0gKHR5cGUgJHt0eXBlb2YgcGFyYW1zLnJlY2lwaWVudH0pYCk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5yZWNpcGllbnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3JlY2lwaWVudCBub3QgYSB2YWxpZCBhZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKCFvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleCB8fCAhb3B0aW9uYWxEZXBzLmV0aEFiaS5zb2xpZGl0eVNIQTMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXRoZXJldW0gbm90IGZ1bGx5IHN1cHBvcnRlZCBpbiB0aGlzIGVudmlyb25tZW50Jyk7XG4gICAgfVxuXG4gICAgLy8gR2V0IHRva2VuIGJhbGFuY2UgZnJvbSBleHRlcm5hbCBBUElcbiAgICBjb25zdCBjb2luU3BlY2lmaWMgPSBwYXJhbXMud2FsbGV0LmNvaW5TcGVjaWZpYygpO1xuICAgIGlmICghY29pblNwZWNpZmljIHx8ICFfLmlzU3RyaW5nKGNvaW5TcGVjaWZpYy5iYXNlQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCBjb2luIHNwZWNpZmljIHByb3BlcnR5IGJhc2VBZGRyZXNzJyk7XG4gICAgfVxuICAgIGNvbnN0IHJlY292ZXJ5QW1vdW50ID0gYXdhaXQgdGhpcy5xdWVyeUFkZHJlc3NUb2tlbkJhbGFuY2UocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzLCBjb2luU3BlY2lmaWMuYmFzZUFkZHJlc3MpO1xuXG4gICAgaWYgKHBhcmFtcy5icm9hZGNhc3QpIHtcbiAgICAgIC8vIFdlJ3JlIGdvaW5nIHRvIGNyZWF0ZSBhIG5vcm1hbCBFVEggdHJhbnNhY3Rpb24gdGhhdCBzZW5kcyBhbiBhbW91bnQgb2YgMCBFVEggdG8gdGhlXG4gICAgICAvLyB0b2tlbkNvbnRyYWN0QWRkcmVzcyBhbmQgZW5jb2RlIHRoZSB1bnN1cHBvcnRlZC10b2tlbi1zZW5kIGRhdGEgaW4gdGhlIGRhdGEgZmllbGRcbiAgICAgIC8vICN0cmlja3N5XG4gICAgICBjb25zdCBzZW5kTWV0aG9kQXJncyA9IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6ICdfdG8nLFxuICAgICAgICAgIHR5cGU6ICdhZGRyZXNzJyxcbiAgICAgICAgICB2YWx1ZTogcGFyYW1zLnJlY2lwaWVudCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6ICdfdmFsdWUnLFxuICAgICAgICAgIHR5cGU6ICd1aW50MjU2JyxcbiAgICAgICAgICB2YWx1ZTogcmVjb3ZlcnlBbW91bnQudG9TdHJpbmcoMTApLFxuICAgICAgICB9LFxuICAgICAgXTtcbiAgICAgIGNvbnN0IG1ldGhvZFNpZ25hdHVyZSA9IG9wdGlvbmFsRGVwcy5ldGhBYmkubWV0aG9kSUQoJ3RyYW5zZmVyJywgXy5tYXAoc2VuZE1ldGhvZEFyZ3MsICd0eXBlJykpO1xuICAgICAgY29uc3QgZW5jb2RlZEFyZ3MgPSBvcHRpb25hbERlcHMuZXRoQWJpLnJhd0VuY29kZShfLm1hcChzZW5kTWV0aG9kQXJncywgJ3R5cGUnKSwgXy5tYXAoc2VuZE1ldGhvZEFyZ3MsICd2YWx1ZScpKTtcbiAgICAgIGNvbnN0IHNlbmREYXRhID0gQnVmZmVyLmNvbmNhdChbbWV0aG9kU2lnbmF0dXJlLCBlbmNvZGVkQXJnc10pO1xuXG4gICAgICBjb25zdCBicm9hZGNhc3RQYXJhbXM6IGFueSA9IHtcbiAgICAgICAgYWRkcmVzczogcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6ICcwJyxcbiAgICAgICAgZGF0YTogc2VuZERhdGEudG9TdHJpbmcoJ2hleCcpLFxuICAgICAgfTtcblxuICAgICAgaWYgKHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKSB7XG4gICAgICAgIGJyb2FkY2FzdFBhcmFtcy53YWxsZXRQYXNzcGhyYXNlID0gcGFyYW1zLndhbGxldFBhc3NwaHJhc2U7XG4gICAgICB9IGVsc2UgaWYgKHBhcmFtcy5wcnYpIHtcbiAgICAgICAgYnJvYWRjYXN0UGFyYW1zLnBydiA9IHBhcmFtcy5wcnY7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhd2FpdCBwYXJhbXMud2FsbGV0LnNlbmQoYnJvYWRjYXN0UGFyYW1zKTtcbiAgICB9XG5cbiAgICBjb25zdCByZWNpcGllbnQgPSB7XG4gICAgICBhZGRyZXNzOiBwYXJhbXMucmVjaXBpZW50LFxuICAgICAgYW1vdW50OiByZWNvdmVyeUFtb3VudC50b1N0cmluZygxMCksXG4gICAgfTtcblxuICAgIC8vIFRoaXMgc2lnbmF0dXJlIHdpbGwgYmUgdmFsaWQgZm9yIG9uZSB3ZWVrXG4gICAgY29uc3QgZXhwaXJlVGltZSA9IE1hdGguZmxvb3IobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwKSArIDYwICogNjAgKiAyNCAqIDc7XG5cbiAgICAvLyBHZXQgc2VxdWVuY2UgSUQuIFdlIGRvIHRoaXMgYnkgYnVpbGRpbmcgYSAnZmFrZScgZXRoIHRyYW5zYWN0aW9uLCBzbyB0aGUgcGxhdGZvcm0gd2lsbCBpbmNyZW1lbnQgYW5kIHJldHVybiB1cyB0aGUgbmV3IHNlcXVlbmNlIGlkXG4gICAgLy8gVGhpcyBfZG9lc18gcmVxdWlyZSB0aGUgdXNlciB0byBoYXZlIGEgbm9uLXplcm8gd2FsbGV0IGJhbGFuY2VcbiAgICBjb25zdCB7IG5leHRDb250cmFjdFNlcXVlbmNlSWQsIGdhc1ByaWNlLCBnYXNMaW1pdCB9ID0gKGF3YWl0IHBhcmFtcy53YWxsZXQucHJlYnVpbGRUcmFuc2FjdGlvbih7XG4gICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiBwYXJhbXMucmVjaXBpZW50LFxuICAgICAgICAgIGFtb3VudDogJzEnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KSkgYXMgYW55O1xuXG4gICAgLy8gdGhlc2UgcmVjb3ZlcmllcyBuZWVkIHRvIGJlIHByb2Nlc3NlZCBieSBzdXBwb3J0LCBidXQgaWYgdGhlIGN1c3RvbWVyIHNlbmRzIGFueSB0cmFuc2FjdGlvbnMgYmVmb3JlIHJlY292ZXJ5IGlzXG4gICAgLy8gY29tcGxldGUgdGhlIHNlcXVlbmNlIElEIHdpbGwgYmUgaW52YWxpZC4gYXJ0aWZpY2lhbGx5IGluZmxhdGUgdGhlIHNlcXVlbmNlIElEIHRvIGFsbG93IG1vcmUgdGltZSBmb3IgcHJvY2Vzc2luZ1xuICAgIGNvbnN0IHNhZmVTZXF1ZW5jZUlkID0gbmV4dENvbnRyYWN0U2VxdWVuY2VJZCArIDEwMDA7XG5cbiAgICAvLyBCdWlsZCBzZW5kRGF0YSBmb3IgZXRoZXJldW0gdHhcbiAgICBjb25zdCBvcGVyYXRpb25UeXBlcyA9IFsnc3RyaW5nJywgJ2FkZHJlc3MnLCAndWludCcsICdhZGRyZXNzJywgJ3VpbnQnLCAndWludCddO1xuICAgIGNvbnN0IG9wZXJhdGlvbkFyZ3MgPSBbXG4gICAgICAvLyBUb2tlbiBvcGVyYXRpb24gaGFzIHByZWZpeCBoYXMgYmVlbiBhZGRlZCBoZXJlIHNvIHRoYXQgZXRoZXIgb3BlcmF0aW9uIGhhc2hlcywgc2lnbmF0dXJlcyBjYW5ub3QgYmUgcmUtdXNlZCBmb3IgdG9rZW5TZW5kaW5nXG4gICAgICBuZXR3b3JrLnRva2VuT3BlcmF0aW9uSGFzaFByZWZpeCxcbiAgICAgIG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihvcHRpb25hbERlcHMuZXRoVXRpbC5zdHJpcEhleFByZWZpeChyZWNpcGllbnQuYWRkcmVzcyksIDE2KSxcbiAgICAgIHJlY2lwaWVudC5hbW91bnQsXG4gICAgICBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ob3B0aW9uYWxEZXBzLmV0aFV0aWwuc3RyaXBIZXhQcmVmaXgocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKSwgMTYpLFxuICAgICAgZXhwaXJlVGltZSxcbiAgICAgIHNhZmVTZXF1ZW5jZUlkLFxuICAgIF07XG5cbiAgICBjb25zdCBvcGVyYXRpb25IYXNoID0gb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9IZXgoXG4gICAgICBvcHRpb25hbERlcHMuZXRoQWJpLnNvbGlkaXR5U0hBMyhvcGVyYXRpb25UeXBlcywgb3BlcmF0aW9uQXJncylcbiAgICApO1xuXG4gICAgY29uc3QgdXNlclBydiA9IGF3YWl0IHBhcmFtcy53YWxsZXQuZ2V0UHJ2KHtcbiAgICAgIHBydjogcGFyYW1zLnBydixcbiAgICAgIHdhbGxldFBhc3NwaHJhc2U6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgIH0pO1xuXG4gICAgY29uc3Qgc2lnbmF0dXJlID0gVXRpbC5ldGhTaWduTXNnSGFzaChvcGVyYXRpb25IYXNoLCBVdGlsLnhwcnZUb0V0aFByaXZhdGVLZXkodXNlclBydikpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGhhbGZTaWduZWQ6IHtcbiAgICAgICAgcmVjaXBpZW50OiByZWNpcGllbnQsXG4gICAgICAgIGV4cGlyZVRpbWU6IGV4cGlyZVRpbWUsXG4gICAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogc2FmZVNlcXVlbmNlSWQsXG4gICAgICAgIG9wZXJhdGlvbkhhc2g6IG9wZXJhdGlvbkhhc2gsXG4gICAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlLFxuICAgICAgICBnYXNMaW1pdDogZ2FzTGltaXQsXG4gICAgICAgIGdhc1ByaWNlOiBnYXNQcmljZSxcbiAgICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3M6IHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgd2FsbGV0SWQ6IHBhcmFtcy53YWxsZXQuaWQoKSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbnN1cmUgZWl0aGVyIGVudGVycHJpc2Ugb3IgbmV3RmVlQWRkcmVzcyBpcyBwYXNzZWQsIHRvIGtub3cgd2hldGhlciB0byBjcmVhdGUgbmV3IGtleSBvciB1c2UgZW50ZXJwcmlzZSBrZXlcbiAgICogQHBhcmFtIHtQcmVjcmVhdGVCaXRHb09wdGlvbnN9IHBhcmFtc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmVudGVycHJpc2Uge1N0cmluZ30gdGhlIGVudGVycHJpc2UgaWQgdG8gYXNzb2NpYXRlIHdpdGggdGhpcyBrZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5uZXdGZWVBZGRyZXNzIHtCb29sZWFufSBjcmVhdGUgYSBuZXcgZmVlIGFkZHJlc3MgKGVudGVycHJpc2Ugbm90IG5lZWRlZCBpbiB0aGlzIGNhc2UpXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgcHJlQ3JlYXRlQml0R28ocGFyYW1zOiBQcmVjcmVhdGVCaXRHb09wdGlvbnMpOiB2b2lkIHtcbiAgICAvLyBXZSBhbHdheXMgbmVlZCBwYXJhbXMgb2JqZWN0LCBzaW5jZSBlaXRoZXIgZW50ZXJwcmlzZSBvciBuZXdGZWVBZGRyZXNzIGlzIHJlcXVpcmVkXG4gICAgaWYgKCFfLmlzT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgcHJlQ3JlYXRlQml0R28gbXVzdCBiZSBwYXNzZWQgYSBwYXJhbXMgb2JqZWN0LiBHb3QgJHtwYXJhbXN9ICh0eXBlICR7dHlwZW9mIHBhcmFtc30pYCk7XG4gICAgfVxuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLmVudGVycHJpc2UpICYmIF8uaXNVbmRlZmluZWQocGFyYW1zLm5ld0ZlZUFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdleHBlY3RpbmcgZW50ZXJwcmlzZSB3aGVuIGFkZGluZyBCaXRHbyBrZXkuIElmIHlvdSB3YW50IHRvIGNyZWF0ZSBhIG5ldyBFVEggYml0Z28ga2V5LCBzZXQgdGhlIG5ld0ZlZUFkZHJlc3MgcGFyYW1ldGVyIHRvIHRydWUuJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayB3aGV0aGVyIGtleSBzaG91bGQgYmUgYW4gZW50ZXJwcmlzZSBrZXkgb3IgYSBCaXRHbyBrZXkgZm9yIGEgbmV3IGZlZSBhZGRyZXNzXG4gICAgaWYgKCFfLmlzVW5kZWZpbmVkKHBhcmFtcy5lbnRlcnByaXNlKSAmJiAhXy5pc1VuZGVmaW5lZChwYXJhbXMubmV3RmVlQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW5jb21wYXRpYmxlIGFyZ3VtZW50cyAtIGNhbm5vdCBwYXNzIGJvdGggZW50ZXJwcmlzZSBhbmQgbmV3RmVlQWRkcmVzcyBwYXJhbWV0ZXIuYCk7XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzVW5kZWZpbmVkKHBhcmFtcy5lbnRlcnByaXNlKSAmJiAhXy5pc1N0cmluZyhwYXJhbXMuZW50ZXJwcmlzZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgZW50ZXJwcmlzZSBzaG91bGQgYmUgYSBzdHJpbmcgLSBnb3QgJHtwYXJhbXMuZW50ZXJwcmlzZX0gKHR5cGUgJHt0eXBlb2YgcGFyYW1zLmVudGVycHJpc2V9KWApO1xuICAgIH1cblxuICAgIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMubmV3RmVlQWRkcmVzcykgJiYgIV8uaXNCb29sZWFuKHBhcmFtcy5uZXdGZWVBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgbmV3RmVlQWRkcmVzcyBzaG91bGQgYmUgYSBib29sZWFuIC0gZ290ICR7cGFyYW1zLm5ld0ZlZUFkZHJlc3N9ICh0eXBlICR7dHlwZW9mIHBhcmFtcy5uZXdGZWVBZGRyZXNzfSlgXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyaWVzIHB1YmxpYyBibG9jayBleHBsb3JlciB0byBnZXQgdGhlIG5leHQgRVRITGlrZSBjb2luJ3Mgbm9uY2UgdGhhdCBzaG91bGQgYmUgdXNlZCBmb3IgdGhlIGdpdmVuIEVUSCBhZGRyZXNzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcGlLZXkgLSBvcHRpb25hbCBBUEkga2V5IHRvIHVzZSBpbnN0ZWFkIG9mIHRoZSBvbmUgZnJvbSB0aGUgZW52aXJvbm1lbnRcbiAgICogQHJldHVybnMge1Byb21pc2U8bnVtYmVyPn1cbiAgICovXG4gIGFzeW5jIGdldEFkZHJlc3NOb25jZShhZGRyZXNzOiBzdHJpbmcsIGFwaUtleT86IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgLy8gR2V0IG5vbmNlIGZvciBiYWNrdXAga2V5IChzaG91bGQgYmUgMClcbiAgICBsZXQgbm9uY2UgPSAwO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5yZWNvdmVyeUJsb2NrY2hhaW5FeHBsb3JlclF1ZXJ5KFxuICAgICAge1xuICAgICAgICBjaGFpbmlkOiB0aGlzLmdldENoYWluSWQoKS50b1N0cmluZygpLFxuICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgYWN0aW9uOiAndHhsaXN0JyxcbiAgICAgICAgYWRkcmVzcyxcbiAgICAgIH0sXG4gICAgICBhcGlLZXlcbiAgICApO1xuXG4gICAgaWYgKHJlc3VsdCAmJiB0eXBlb2YgcmVzdWx0Py5ub25jZSA9PT0gJ251bWJlcicpIHtcbiAgICAgIHJldHVybiBOdW1iZXIocmVzdWx0Lm5vbmNlKTtcbiAgICB9XG5cbiAgICBpZiAoIXJlc3VsdCB8fCAhQXJyYXkuaXNBcnJheShyZXN1bHQucmVzdWx0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmFibGUgdG8gZmluZCBuZXh0IG5vbmNlIGZyb20gRXRoZXJzY2FuLCBnb3Q6ICcgKyBKU09OLnN0cmluZ2lmeShyZXN1bHQpKTtcbiAgICB9XG4gICAgY29uc3QgYmFja3VwS2V5VHhMaXN0ID0gcmVzdWx0LnJlc3VsdDtcbiAgICBpZiAoYmFja3VwS2V5VHhMaXN0Lmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIENhbGN1bGF0ZSBsYXN0IG5vbmNlIHVzZWRcbiAgICAgIGNvbnN0IG91dGdvaW5nVHhzID0gYmFja3VwS2V5VHhMaXN0LmZpbHRlcigodHgpID0+IHR4LmZyb20gPT09IGFkZHJlc3MpO1xuICAgICAgbm9uY2UgPSBvdXRnb2luZ1R4cy5sZW5ndGg7XG4gICAgfVxuICAgIHJldHVybiBub25jZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIHJlY292ZXIoKVxuICAgKiBUaGlzIHRyYW5zZm9ybXMgdGhlIHVuc2lnbmVkIHRyYW5zYWN0aW9uIGluZm9ybWF0aW9uIGludG8gYSBmb3JtYXQgdGhlIEJpdEdvIG9mZmxpbmUgdmF1bHQgZXhwZWN0c1xuICAgKiBAcGFyYW0ge1VuZm9ybWF0dGVkVHhJbmZvfSB0eEluZm8gLSB0eCBpbmZvXG4gICAqIEBwYXJhbSB7RXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbn0gZXRoVHggLSB0aGUgZXRoZXJldW1qcyB0eCBvYmplY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJLZXkgLSB0aGUgdXNlcidzIGtleVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYmFja3VwS2V5IC0gdGhlIGJhY2t1cCBrZXlcbiAgICogQHBhcmFtIHtCdWZmZXJ9IGdhc1ByaWNlIC0gZ2FzIHByaWNlIGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtudW1iZXJ9IGdhc0xpbWl0IC0gZ2FzIGxpbWl0IGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtFSVAxNTU5fSBlaXAxNTU5IC0gZWlwMTU1OSBwYXJhbXNcbiAgICogQHBhcmFtIHtSZXBsYXlQcm90ZWN0aW9uT3B0aW9uc30gcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMgLSByZXBsYXkgcHJvdGVjdGlvbiBvcHRpb25zXG4gICAqIEBwYXJhbSB7YXBpS2V5fSBhcGlLZXkgLSBvcHRpb25hbCBhcGlLZXkgdG8gdXNlIHdoZW4gcmV0cmlldmluZyBibG9jayBjaGFpbiBkYXRhXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE9mZmxpbmVWYXVsdFR4SW5mbz59XG4gICAqL1xuICBhc3luYyBmb3JtYXRGb3JPZmZsaW5lVmF1bHQoXG4gICAgdHhJbmZvOiBVbmZvcm1hdHRlZFR4SW5mbyxcbiAgICBldGhUeDogRXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbixcbiAgICB1c2VyS2V5OiBzdHJpbmcsXG4gICAgYmFja3VwS2V5OiBzdHJpbmcsXG4gICAgZ2FzUHJpY2U6IEJ1ZmZlcixcbiAgICBnYXNMaW1pdDogbnVtYmVyLFxuICAgIGVpcDE1NTk/OiBFSVAxNTU5LFxuICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMsXG4gICAgYXBpS2V5Pzogc3RyaW5nXG4gICk6IFByb21pc2U8T2ZmbGluZVZhdWx0VHhJbmZvPiB7XG4gICAgaWYgKCFldGhUeC50bykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdFdGggdHggbXVzdCBoYXZlIGEgYHRvYCBhZGRyZXNzJyk7XG4gICAgfVxuICAgIGNvbnN0IGJhY2t1cEhETm9kZSA9IGJpcDMyLmZyb21CYXNlNTgoYmFja3VwS2V5KTtcbiAgICBjb25zdCBiYWNrdXBTaWduaW5nS2V5ID0gYmFja3VwSEROb2RlLnB1YmxpY0tleTtcbiAgICBjb25zdCByZXNwb25zZTogT2ZmbGluZVZhdWx0VHhJbmZvID0ge1xuICAgICAgdHg6IGV0aFR4LnNlcmlhbGl6ZSgpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgIHVzZXJLZXksXG4gICAgICBiYWNrdXBLZXksXG4gICAgICBjb2luOiB0aGlzLmdldENoYWluKCksXG4gICAgICBnYXNQcmljZTogb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9JbnQoZ2FzUHJpY2UpLnRvRml4ZWQoKSxcbiAgICAgIGdhc0xpbWl0LFxuICAgICAgcmVjaXBpZW50czogW3R4SW5mby5yZWNpcGllbnRdLFxuICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiBldGhUeC50by50b1N0cmluZygpLFxuICAgICAgYW1vdW50OiB0eEluZm8ucmVjaXBpZW50LmFtb3VudCBhcyBzdHJpbmcsXG4gICAgICBiYWNrdXBLZXlOb25jZTogYXdhaXQgdGhpcy5nZXRBZGRyZXNzTm9uY2UoXG4gICAgICAgIGAweCR7b3B0aW9uYWxEZXBzLmV0aFV0aWwucHVibGljVG9BZGRyZXNzKGJhY2t1cFNpZ25pbmdLZXksIHRydWUpLnRvU3RyaW5nKCdoZXgnKX1gLFxuICAgICAgICBhcGlLZXlcbiAgICAgICksXG4gICAgICBlaXAxNTU5LFxuICAgICAgcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMsXG4gICAgfTtcbiAgICBfLmV4dGVuZChyZXNwb25zZSwgdHhJbmZvKTtcbiAgICByZXNwb25zZS5uZXh0Q29udHJhY3RTZXF1ZW5jZUlkID0gcmVzcG9uc2UuY29udHJhY3RTZXF1ZW5jZUlkO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIHJlY292ZXIoKVxuICAgKiBUaGlzIHRyYW5zZm9ybXMgdGhlIHVuc2lnbmVkIHRyYW5zYWN0aW9uIGluZm9ybWF0aW9uIGludG8gYSBmb3JtYXQgdGhlIEJpdEdvIG9mZmxpbmUgdmF1bHQgZXhwZWN0c1xuICAgKiBAcGFyYW0ge1VuZm9ybWF0dGVkVHhJbmZvfSB0eEluZm8gLSB0eCBpbmZvXG4gICAqIEBwYXJhbSB7RXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbn0gZXRoVHggLSB0aGUgZXRoZXJldW1qcyB0eCBvYmplY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJLZXkgLSB0aGUgdXNlcidzIGtleVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYmFja3VwS2V5IC0gdGhlIGJhY2t1cCBrZXlcbiAgICogQHBhcmFtIHtCdWZmZXJ9IGdhc1ByaWNlIC0gZ2FzIHByaWNlIGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtudW1iZXJ9IGdhc0xpbWl0IC0gZ2FzIGxpbWl0IGZvciB0aGUgdHhcbiAgICogQHBhcmFtIHtudW1iZXJ9IGJhY2t1cEtleU5vbmNlIC0gdGhlIG5vbmNlIG9mIHRoZSBiYWNrdXAga2V5IGFkZHJlc3NcbiAgICogQHBhcmFtIHtFSVAxNTU5fSBlaXAxNTU5IC0gZWlwMTU1OSBwYXJhbXNcbiAgICogQHBhcmFtIHtSZXBsYXlQcm90ZWN0aW9uT3B0aW9uc30gcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMgLSByZXBsYXkgcHJvdGVjdGlvbiBvcHRpb25zXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE9mZmxpbmVWYXVsdFR4SW5mbz59XG4gICAqL1xuICBmb3JtYXRGb3JPZmZsaW5lVmF1bHRUU1MoXG4gICAgdHhJbmZvOiBVbmZvcm1hdHRlZFR4SW5mbyxcbiAgICBldGhUeDogRXRoTGlrZVR4TGliLlRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbixcbiAgICB1c2VyS2V5OiBzdHJpbmcsXG4gICAgYmFja3VwS2V5OiBzdHJpbmcsXG4gICAgZ2FzUHJpY2U6IEJ1ZmZlcixcbiAgICBnYXNMaW1pdDogbnVtYmVyLFxuICAgIGJhY2t1cEtleU5vbmNlOiBudW1iZXIsXG4gICAgZWlwMTU1OT86IEVJUDE1NTksXG4gICAgcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM/OiBSZXBsYXlQcm90ZWN0aW9uT3B0aW9uc1xuICApOiBPZmZsaW5lVmF1bHRUeEluZm8ge1xuICAgIGlmICghZXRoVHgudG8pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRXRoIHR4IG11c3QgaGF2ZSBhIGB0b2AgYWRkcmVzcycpO1xuICAgIH1cbiAgICBjb25zdCByZXNwb25zZTogT2ZmbGluZVZhdWx0VHhJbmZvID0ge1xuICAgICAgdHg6IGV0aFR4LnNlcmlhbGl6ZSgpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgIHR4SGV4OiBldGhUeC5nZXRNZXNzYWdlVG9TaWduKGZhbHNlKS50b1N0cmluZygpLFxuICAgICAgdXNlcktleSxcbiAgICAgIGJhY2t1cEtleSxcbiAgICAgIGNvaW46IHRoaXMuZ2V0Q2hhaW4oKSxcbiAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgZ2FzTGltaXQsXG4gICAgICByZWNpcGllbnRzOiBbdHhJbmZvLnJlY2lwaWVudF0sXG4gICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IGV0aFR4LnRvLnRvU3RyaW5nKCksXG4gICAgICBhbW91bnQ6IHR4SW5mby5yZWNpcGllbnQuYW1vdW50IGFzIHN0cmluZyxcbiAgICAgIGJhY2t1cEtleU5vbmNlOiBiYWNrdXBLZXlOb25jZSxcbiAgICAgIGVpcDE1NTksXG4gICAgICByZXBsYXlQcm90ZWN0aW9uT3B0aW9ucyxcbiAgICB9O1xuICAgIF8uZXh0ZW5kKHJlc3BvbnNlLCB0eEluZm8pO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayB3aGV0aGVyIHRoZSBnYXMgcHJpY2UgcGFzc2VkIGluIGJ5IHVzZXIgYXJlIHdpdGhpbiBvdXIgbWF4IGFuZCBtaW4gYm91bmRzXG4gICAqIElmIHRoZXkgYXJlIG5vdCBzZXQsIHNldCB0aGVtIHRvIHRoZSBkZWZhdWx0c1xuICAgKiBAcGFyYW0ge251bWJlcn0gdXNlckdhc1ByaWNlIC0gdXNlciBkZWZpbmVkIGdhcyBwcmljZVxuICAgKiBAcmV0dXJucyB7bnVtYmVyfSB0aGUgZ2FzIHByaWNlIHRvIHVzZSBmb3IgdGhpcyB0cmFuc2FjdGlvblxuICAgKi9cbiAgc2V0R2FzUHJpY2UodXNlckdhc1ByaWNlPzogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBpZiAoIXVzZXJHYXNQcmljZSkge1xuICAgICAgcmV0dXJuIGV0aEdhc0NvbmZpZ3MuZGVmYXVsdEdhc1ByaWNlO1xuICAgIH1cblxuICAgIGNvbnN0IGdhc1ByaWNlTWF4ID0gZXRoR2FzQ29uZmlncy5tYXhpbXVtR2FzUHJpY2U7XG4gICAgY29uc3QgZ2FzUHJpY2VNaW4gPSBldGhHYXNDb25maWdzLm1pbmltdW1HYXNQcmljZTtcbiAgICBpZiAodXNlckdhc1ByaWNlIDwgZ2FzUHJpY2VNaW4gfHwgdXNlckdhc1ByaWNlID4gZ2FzUHJpY2VNYXgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgR2FzIHByaWNlIG11c3QgYmUgYmV0d2VlbiAke2dhc1ByaWNlTWlufSBhbmQgJHtnYXNQcmljZU1heH1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHVzZXJHYXNQcmljZTtcbiAgfVxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciBnYXMgbGltaXQgcGFzc2VkIGluIGJ5IHVzZXIgYXJlIHdpdGhpbiBvdXIgbWF4IGFuZCBtaW4gYm91bmRzXG4gICAqIElmIHRoZXkgYXJlIG5vdCBzZXQsIHNldCB0aGVtIHRvIHRoZSBkZWZhdWx0c1xuICAgKiBAcGFyYW0ge251bWJlcn0gdXNlckdhc0xpbWl0IHVzZXIgZGVmaW5lZCBnYXMgbGltaXRcbiAgICogQHJldHVybnMge251bWJlcn0gdGhlIGdhcyBsaW1pdCB0byB1c2UgZm9yIHRoaXMgdHJhbnNhY3Rpb25cbiAgICovXG4gIHNldEdhc0xpbWl0KHVzZXJHYXNMaW1pdD86IG51bWJlcik6IG51bWJlciB7XG4gICAgaWYgKCF1c2VyR2FzTGltaXQpIHtcbiAgICAgIHJldHVybiBldGhHYXNDb25maWdzLmRlZmF1bHRHYXNMaW1pdDtcbiAgICB9XG4gICAgY29uc3QgZ2FzTGltaXRNYXggPSBldGhHYXNDb25maWdzLm1heGltdW1HYXNMaW1pdDtcbiAgICBjb25zdCBnYXNMaW1pdE1pbiA9IGV0aEdhc0NvbmZpZ3MubWluaW11bUdhc0xpbWl0O1xuICAgIGlmICh1c2VyR2FzTGltaXQgPCBnYXNMaW1pdE1pbiB8fCB1c2VyR2FzTGltaXQgPiBnYXNMaW1pdE1heCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBHYXMgbGltaXQgbXVzdCBiZSBiZXR3ZWVuICR7Z2FzTGltaXRNaW59IGFuZCAke2dhc0xpbWl0TWF4fWApO1xuICAgIH1cbiAgICByZXR1cm4gdXNlckdhc0xpbWl0O1xuICB9XG5cbiAgLyoqXG4gICAqIEhlbHBlciBmdW5jdGlvbiBmb3Igc2lnblRyYW5zYWN0aW9uIGZvciB0aGUgcmFyZSBjYXNlIHRoYXQgU0RLIGlzIGRvaW5nIHRoZSBzZWNvbmQgc2lnbmF0dXJlXG4gICAqIE5vdGU6IHdlIGFyZSBleHBlY3RpbmcgdGhpcyB0byBiZSBjYWxsZWQgZnJvbSB0aGUgb2ZmbGluZSB2YXVsdFxuICAgKiBAcGFyYW0ge1NpZ25GaW5hbE9wdGlvbnMudHhQcmVidWlsZH0gcGFyYW1zLnR4UHJlYnVpbGRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5wcnZcbiAgICogQHJldHVybnMge3t0eEhleDogc3RyaW5nfX1cbiAgICovXG4gIGFzeW5jIHNpZ25GaW5hbEV0aExpa2UocGFyYW1zOiBTaWduRmluYWxPcHRpb25zKTogUHJvbWlzZTxGdWxseVNpZ25lZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3Qgc2lnbmluZ0tleSA9IG5ldyBLZXlQYWlyTGliKHsgcHJ2OiBwYXJhbXMucHJ2IH0pLmdldEtleXMoKS5wcnY7XG4gICAgaWYgKF8uaXNVbmRlZmluZWQoc2lnbmluZ0tleSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwcml2YXRlIGtleScpO1xuICAgIH1cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKTtcbiAgICB0cnkge1xuICAgICAgdHhCdWlsZGVyLmZyb20ocGFyYW1zLnR4UHJlYnVpbGQuaGFsZlNpZ25lZD8udHhIZXgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBoYWxmLXNpZ25lZCB0cmFuc2FjdGlvbicpO1xuICAgIH1cbiAgICB0eEJ1aWxkZXIuc2lnbih7IGtleTogc2lnbmluZ0tleSB9KTtcbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIHJldHVybiB7XG4gICAgICB0eEhleDogdHgudG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIGhhbGYtc2lnbiBwcmVidWlsdCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1NpZ25UcmFuc2FjdGlvbk9wdGlvbnN9IHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgc2lnblRyYW5zYWN0aW9uKHBhcmFtczogU2lnblRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8U2lnbmVkVHJhbnNhY3Rpb24+IHtcbiAgICAvLyBOb3JtYWxseSB0aGUgU0RLIHByb3ZpZGVzIHRoZSBmaXJzdCBzaWduYXR1cmUgZm9yIGFuIEV0aExpa2UgdHgsIGJ1dCBvY2Nhc2lvbmFsbHkgaXQgcHJvdmlkZXMgdGhlIHNlY29uZCBhbmQgZmluYWwgb25lLlxuICAgIGlmIChwYXJhbXMuaXNMYXN0U2lnbmF0dXJlKSB7XG4gICAgICAvLyBJbiB0aGlzIGNhc2Ugd2hlbiB3ZSdyZSBkb2luZyB0aGUgc2Vjb25kIChmaW5hbCkgc2lnbmF0dXJlLCB0aGUgbG9naWMgaXMgZGlmZmVyZW50LlxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuc2lnbkZpbmFsRXRoTGlrZShwYXJhbXMpO1xuICAgIH1cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKTtcbiAgICB0eEJ1aWxkZXIuZnJvbShwYXJhbXMudHhQcmVidWlsZC50eEhleCk7XG4gICAgdHhCdWlsZGVyXG4gICAgICAudHJhbnNmZXIoKVxuICAgICAgLmNvaW4odGhpcy5zdGF0aWNzQ29pbj8ubmFtZSBhcyBzdHJpbmcpXG4gICAgICAua2V5KG5ldyBLZXlQYWlyTGliKHsgcHJ2OiBwYXJhbXMucHJ2IH0pLmdldEtleXMoKS5wcnYhKTtcbiAgICBpZiAocGFyYW1zLndhbGxldFZlcnNpb24pIHtcbiAgICAgIHR4QnVpbGRlci53YWxsZXRWZXJzaW9uKHBhcmFtcy53YWxsZXRWZXJzaW9uKTtcbiAgICB9XG4gICAgY29uc3QgdHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcblxuICAgIC8vIEluIGNhc2Ugb2YgdHggd2l0aCBjb250cmFjdCBkYXRhIGZyb20gYSBjdXN0b2RpYWwgd2FsbGV0LCB3ZSBhcmUgcnVubmluZyBpbnRvIGFuIGlzc3VlXG4gICAgLy8gYXMgaGFsZlNpZ25lZCBpcyBub3QgaGF2aW5nIHRoZSBkYXRhIGZpZWxkLiBTbywgd2UgYXJlIGFkZGluZyB0aGUgZGF0YSBmaWVsZCB0byB0aGUgaGFsZlNpZ25lZCB0eFxuICAgIGxldCByZWNpcGllbnRzID0gcGFyYW1zLnR4UHJlYnVpbGQucmVjaXBpZW50cyB8fCBwYXJhbXMucmVjaXBpZW50cztcbiAgICBpZiAocmVjaXBpZW50cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZWNpcGllbnRzID0gdHJhbnNhY3Rpb24ub3V0cHV0cy5tYXAoKG91dHB1dCkgPT4gKHsgYWRkcmVzczogb3V0cHV0LmFkZHJlc3MsIGFtb3VudDogb3V0cHV0LnZhbHVlIH0pKTtcbiAgICB9XG5cbiAgICBjb25zdCB0eFBhcmFtcyA9IHtcbiAgICAgIGVpcDE1NTk6IHBhcmFtcy50eFByZWJ1aWxkLmVpcDE1NTksXG4gICAgICB0eEhleDogdHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgIHJlY2lwaWVudHM6IHJlY2lwaWVudHMsXG4gICAgICBleHBpcmF0aW9uOiBwYXJhbXMudHhQcmVidWlsZC5leHBpcmVUaW1lLFxuICAgICAgaG9wVHJhbnNhY3Rpb246IHBhcmFtcy50eFByZWJ1aWxkLmhvcFRyYW5zYWN0aW9uLFxuICAgICAgY3VzdG9kaWFuVHJhbnNhY3Rpb25JZDogcGFyYW1zLmN1c3RvZGlhblRyYW5zYWN0aW9uSWQsXG4gICAgICBleHBpcmVUaW1lOiBwYXJhbXMuZXhwaXJlVGltZSxcbiAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogcGFyYW1zLnR4UHJlYnVpbGQubmV4dENvbnRyYWN0U2VxdWVuY2VJZCBhcyBudW1iZXIsXG4gICAgICBzZXF1ZW5jZUlkOiBwYXJhbXMuc2VxdWVuY2VJZCxcbiAgICAgIC4uLihwYXJhbXMudHhQcmVidWlsZC5pc0JhdGNoID8geyBpc0JhdGNoOiBwYXJhbXMudHhQcmVidWlsZC5pc0JhdGNoIH0gOiB7fSksXG4gICAgfTtcblxuICAgIHJldHVybiB7IGhhbGZTaWduZWQ6IHR4UGFyYW1zIH07XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHRvIHZhbGlkYXRlIHJlY292ZXJ5IHBhcmFtc1xuICAgKiBAcGFyYW0ge1JlY292ZXJPcHRpb25zfSBwYXJhbXNcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICB2YWxpZGF0ZVJlY292ZXJ5UGFyYW1zKHBhcmFtczogUmVjb3Zlck9wdGlvbnMpOiB2b2lkIHtcbiAgICBpZiAocGFyYW1zLnVzZXJLZXkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHVzZXJLZXknKTtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLmJhY2t1cEtleSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgYmFja3VwS2V5Jyk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgIXBhcmFtcy5pc1Vuc2lnbmVkU3dlZXAgJiZcbiAgICAgIHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlID09PSB1bmRlZmluZWQgJiZcbiAgICAgICFwYXJhbXMudXNlcktleS5zdGFydHNXaXRoKCd4cHViJykgJiZcbiAgICAgICFwYXJhbXMuaXNUc3NcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyB3YWxsZXQgcGFzc3BocmFzZScpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzID09PSB1bmRlZmluZWQgfHwgIXRoaXMuaXNWYWxpZEFkZHJlc3MocGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCB3YWxsZXRDb250cmFjdEFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24gPT09IHVuZGVmaW5lZCB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCByZWNvdmVyeURlc3RpbmF0aW9uJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnN0YXRpY3NDb2luPy5mZWF0dXJlcy5pbmNsdWRlcyhDb2luRmVhdHVyZS5FSVAxNTU5KSkge1xuICAgICAgaWYgKHBhcmFtcy5laXAxNTU5KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBmZWUgcGFyYW1zLiBFSVAxNTU5IG5vdCBzdXBwb3J0ZWQnKTtcbiAgICAgIH1cbiAgICAgIGlmIChwYXJhbXMucmVwbGF5UHJvdGVjdGlvbk9wdGlvbnM/LmhhcmRmb3JrID09PSAnbG9uZG9uJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcmVwbGF5UHJvdGVjdGlvbiBvcHRpb25zLiBDYW5ub3QgdXNlIHRoZSBoYXJkZm9yayBcImxvbmRvblwiIGZvciB0aGlzIGNoYWluJyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEhlbHBlciB3aGljaCBBZGRzIHNpZ25hdHVyZXMgdG8gdHggb2JqZWN0IGFuZCByZS1zZXJpYWxpemVzIHR4XG4gICAqIEBwYXJhbSB7RXRoTGlrZUNvbW1vbi5kZWZhdWx0fSBldGhDb21tb25cbiAgICogQHBhcmFtIHtFdGhMaWtlVHhMaWIuRmVlTWFya2V0RUlQMTU1OVRyYW5zYWN0aW9uIHwgRXRoTGlrZVR4TGliLlRyYW5zYWN0aW9ufSB0eFxuICAgKiBAcGFyYW0ge0VDRFNBTWV0aG9kVHlwZXMuU2lnbmF0dXJlfSBzaWduYXR1cmVcbiAgICogQHJldHVybnMge0V0aExpa2VUeExpYi5GZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb24gfCBFdGhMaWtlVHhMaWIuVHJhbnNhY3Rpb259XG4gICAqL1xuICBwcml2YXRlIGdldFNpZ25lZFR4RnJvbVNpZ25hdHVyZShcbiAgICBldGhDb21tb246IEV0aExpa2VDb21tb24uZGVmYXVsdCxcbiAgICB0eDogRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbiB8IEV0aExpa2VUeExpYi5UcmFuc2FjdGlvbixcbiAgICBzaWduYXR1cmU6IEVDRFNBTWV0aG9kVHlwZXMuU2lnbmF0dXJlXG4gICkge1xuICAgIC8vIGdldCBzaWduZWQgVHggZnJvbSBzaWduYXR1cmVcbiAgICBjb25zdCB0eERhdGEgPSB0eC50b0pTT04oKTtcbiAgICBjb25zdCB5UGFyaXR5ID0gc2lnbmF0dXJlLnJlY2lkO1xuICAgIGNvbnN0IGJhc2VQYXJhbXMgPSB7XG4gICAgICB0bzogdHhEYXRhLnRvLFxuICAgICAgbm9uY2U6IG5ldyBCTihzdHJpcEhleFByZWZpeCh0eERhdGEubm9uY2UhKSwgJ2hleCcpLFxuICAgICAgdmFsdWU6IG5ldyBCTihzdHJpcEhleFByZWZpeCh0eERhdGEudmFsdWUhKSwgJ2hleCcpLFxuICAgICAgZ2FzTGltaXQ6IG5ldyBCTihzdHJpcEhleFByZWZpeCh0eERhdGEuZ2FzTGltaXQhKSwgJ2hleCcpLFxuICAgICAgZGF0YTogdHhEYXRhLmRhdGEsXG4gICAgICByOiBhZGRIZXhQcmVmaXgoc2lnbmF0dXJlLnIpLFxuICAgICAgczogYWRkSGV4UHJlZml4KHNpZ25hdHVyZS5zKSxcbiAgICB9O1xuXG4gICAgbGV0IGZpbmFsVHg7XG4gICAgaWYgKHR4RGF0YS5tYXhGZWVQZXJHYXMgJiYgdHhEYXRhLm1heFByaW9yaXR5RmVlUGVyR2FzKSB7XG4gICAgICBmaW5hbFR4ID0gRmVlTWFya2V0RUlQMTU1OVRyYW5zYWN0aW9uLmZyb21UeERhdGEoXG4gICAgICAgIHtcbiAgICAgICAgICAuLi5iYXNlUGFyYW1zLFxuICAgICAgICAgIG1heFByaW9yaXR5RmVlUGVyR2FzOiBuZXcgQk4oc3RyaXBIZXhQcmVmaXgodHhEYXRhLm1heFByaW9yaXR5RmVlUGVyR2FzISksICdoZXgnKSxcbiAgICAgICAgICBtYXhGZWVQZXJHYXM6IG5ldyBCTihzdHJpcEhleFByZWZpeCh0eERhdGEubWF4RmVlUGVyR2FzISksICdoZXgnKSxcbiAgICAgICAgICB2OiBuZXcgQk4oeVBhcml0eS50b1N0cmluZygpKSxcbiAgICAgICAgfSxcbiAgICAgICAgeyBjb21tb246IGV0aENvbW1vbiB9XG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAodHhEYXRhLmdhc1ByaWNlKSB7XG4gICAgICBjb25zdCB2ID0gQmlnSW50KDM1KSArIEJpZ0ludCh5UGFyaXR5KSArIEJpZ0ludChldGhDb21tb24uY2hhaW5JZEJOKCkudG9OdW1iZXIoKSkgKiBCaWdJbnQoMik7XG4gICAgICBmaW5hbFR4ID0gTGVnYWN5VHJhbnNhY3Rpb24uZnJvbVR4RGF0YShcbiAgICAgICAge1xuICAgICAgICAgIC4uLmJhc2VQYXJhbXMsXG4gICAgICAgICAgdjogbmV3IEJOKHYudG9TdHJpbmcoKSksXG4gICAgICAgICAgZ2FzUHJpY2U6IG5ldyBCTihzdHJpcEhleFByZWZpeCh0eERhdGEuZ2FzUHJpY2UhLnRvU3RyaW5nKCkpLCAnaGV4JyksXG4gICAgICAgIH0sXG4gICAgICAgIHsgY29tbW9uOiBldGhDb21tb24gfVxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmluYWxUeDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgYSBmdW5kcyByZWNvdmVyeSB0cmFuc2FjdGlvbiB3aXRob3V0IEJpdEdvXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy51c2VyS2V5IC0gW2VuY3J5cHRlZF0geHBydlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmJhY2t1cEtleSAtIFtlbmNyeXB0ZWRdIHhwcnYgb3IgeHB1YiBpZiB0aGUgeHBydiBpcyBoZWxkIGJ5IGEgS1JTIHByb3ZpZGVyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSAtIHVzZWQgdG8gZGVjcnlwdCB1c2VyS2V5IGFuZCBiYWNrdXBLZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MgLSB0aGUgRVRIIGFkZHJlc3Mgb2YgdGhlIHdhbGxldCBjb250cmFjdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmtyc1Byb3ZpZGVyIC0gbmVjZXNzYXJ5IGlmIGJhY2t1cCBrZXkgaXMgaGVsZCBieSBLUlNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uIC0gdGFyZ2V0IGFkZHJlc3MgdG8gc2VuZCByZWNvdmVyZWQgZnVuZHMgdG9cbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5iaXRnb0ZlZUFkZHJlc3MgLSB3cm9uZyBjaGFpbiB3YWxsZXQgZmVlIGFkZHJlc3MgZm9yIGV2bSBiYXNlZCBjcm9zcyBjaGFpbiByZWNvdmVyeSB0eG5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5iaXRnb0Rlc3RpbmF0aW9uQWRkcmVzcyAtIHRhcmdldCBiaXRnbyBhZGRyZXNzIHdoZXJlIGZlZSB3aWxsIGJlIHNlbnQgZm9yIGV2bSBiYXNlZCBjcm9zcyBjaGFpbiByZWNvdmVyeSB0eG5cbiAgICovXG4gIGFzeW5jIHJlY292ZXIocGFyYW1zOiBSZWNvdmVyT3B0aW9ucyk6IFByb21pc2U8UmVjb3ZlcnlJbmZvIHwgT2ZmbGluZVZhdWx0VHhJbmZvIHwgVW5zaWduZWRTd2VlcFR4TVBDdjI+IHtcbiAgICBpZiAocGFyYW1zLmlzVHNzID09PSB0cnVlKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZWNvdmVyVFNTKHBhcmFtcyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnJlY292ZXJFdGhMaWtlKHBhcmFtcyk7XG4gIH1cblxuICBnZW5lcmF0ZUZvcndhcmRlckFkZHJlc3MoXG4gICAgYmFzZUFkZHJlc3M6IHN0cmluZyxcbiAgICBmZWVBZGRyZXNzOiBzdHJpbmcsXG4gICAgZm9yd2FyZGVyRmFjdG9yeUFkZHJlc3M6IHN0cmluZyxcbiAgICBmb3J3YXJkZXJJbXBsZW1lbnRhdGlvbkFkZHJlc3M6IHN0cmluZyxcbiAgICBpbmRleDogbnVtYmVyXG4gICk6IHN0cmluZyB7XG4gICAgY29uc3Qgc2FsdCA9IGFkZEhleFByZWZpeChpbmRleC50b1N0cmluZygxNikpO1xuICAgIGNvbnN0IHNhbHRCdWZmZXIgPSBzZXRMZW5ndGhMZWZ0KHRvQnVmZmVyKHNhbHQpLCAzMik7XG5cbiAgICBjb25zdCB7IGNyZWF0ZUZvcndhcmRlclBhcmFtcywgY3JlYXRlRm9yd2FyZGVyVHlwZXMgfSA9IGdldENyZWF0ZUZvcndhcmRlclBhcmFtc0FuZFR5cGVzKFxuICAgICAgYmFzZUFkZHJlc3MsXG4gICAgICBzYWx0QnVmZmVyLFxuICAgICAgZmVlQWRkcmVzc1xuICAgICk7XG5cbiAgICBjb25zdCBjYWxjdWxhdGlvblNhbHQgPSBidWZmZXJUb0hleChvcHRpb25hbERlcHMuZXRoQWJpLnNvbGlkaXR5U0hBMyhjcmVhdGVGb3J3YXJkZXJUeXBlcywgY3JlYXRlRm9yd2FyZGVyUGFyYW1zKSk7XG5cbiAgICBjb25zdCBpbml0Q29kZSA9IGdldFByb3h5SW5pdGNvZGUoZm9yd2FyZGVySW1wbGVtZW50YXRpb25BZGRyZXNzKTtcbiAgICByZXR1cm4gY2FsY3VsYXRlRm9yd2FyZGVyVjFBZGRyZXNzKGZvcndhcmRlckZhY3RvcnlBZGRyZXNzLCBjYWxjdWxhdGlvblNhbHQsIGluaXRDb2RlKTtcbiAgfVxuXG4gIGRlcml2ZUFkZHJlc3NGcm9tUHVibGljS2V5KGNvbW1vbktleWNoYWluOiBzdHJpbmcsIGluZGV4OiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IGRlcml2YXRpb25QYXRoID0gYG0vJHtpbmRleH1gO1xuICAgIGNvbnN0IHB1YmtleVNpemUgPSAzMztcblxuICAgIGNvbnN0IGVjZHNhTXBjID0gbmV3IEVjZHNhKCk7XG4gICAgY29uc3QgZGVyaXZlZFB1YmxpY0tleSA9IEJ1ZmZlci5mcm9tKGVjZHNhTXBjLmRlcml2ZVVuaGFyZGVuZWQoY29tbW9uS2V5Y2hhaW4sIGRlcml2YXRpb25QYXRoKSwgJ2hleCcpXG4gICAgICAuc3ViYXJyYXkoMCwgcHVia2V5U2l6ZSlcbiAgICAgIC50b1N0cmluZygnaGV4Jyk7XG5cbiAgICBjb25zdCBwdWJsaWNLZXkgPSBCdWZmZXIuZnJvbShkZXJpdmVkUHVibGljS2V5LCAnaGV4Jykuc2xpY2UoMCwgNjYpLnRvU3RyaW5nKCdoZXgnKTtcblxuICAgIGNvbnN0IGtleVBhaXIgPSBuZXcgS2V5UGFpckxpYih7IHB1YjogcHVibGljS2V5IH0pO1xuICAgIGNvbnN0IGFkZHJlc3MgPSBrZXlQYWlyLmdldEFkZHJlc3MoKTtcbiAgICByZXR1cm4gYWRkcmVzcztcbiAgfVxuXG4gIGdldENvbnNvbGlkYXRpb25BZGRyZXNzKHBhcmFtczogRXRoQ29uc29saWRhdGlvblJlY292ZXJ5T3B0aW9ucywgaW5kZXg6IG51bWJlcik6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBwb3NzaWJsZUNvbnNvbGlkYXRpb25BZGRyZXNzZXM6IHN0cmluZ1tdID0gW107XG4gICAgaWYgKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MgJiYgcGFyYW1zLmJpdGdvRmVlQWRkcmVzcykge1xuICAgICAgY29uc3QgZXRoTmV0d29yayA9IHRoaXMuZ2V0TmV0d29yaygpO1xuICAgICAgY29uc3QgZm9yd2FyZGVyRmFjdG9yeUFkZHJlc3MgPSBldGhOZXR3b3JrPy53YWxsZXRWNEZvcndhcmRlckZhY3RvcnlBZGRyZXNzIGFzIHN0cmluZztcbiAgICAgIGNvbnN0IGZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcyA9IGV0aE5ldHdvcms/LndhbGxldFY0Rm9yd2FyZGVySW1wbGVtZW50YXRpb25BZGRyZXNzIGFzIHN0cmluZztcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGZvcndhcmRlckFkZHJlc3MgPSB0aGlzLmdlbmVyYXRlRm9yd2FyZGVyQWRkcmVzcyhcbiAgICAgICAgICBwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzLFxuICAgICAgICAgIHBhcmFtcy5iaXRnb0ZlZUFkZHJlc3MsXG4gICAgICAgICAgZm9yd2FyZGVyRmFjdG9yeUFkZHJlc3MsXG4gICAgICAgICAgZm9yd2FyZGVySW1wbGVtZW50YXRpb25BZGRyZXNzLFxuICAgICAgICAgIGluZGV4XG4gICAgICAgICk7XG4gICAgICAgIHBvc3NpYmxlQ29uc29saWRhdGlvbkFkZHJlc3Nlcy5wdXNoKGZvcndhcmRlckFkZHJlc3MpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLmxvZyhgRmFpbGVkIHRvIGdlbmVyYXRlIGZvcndhcmRlciBhZGRyZXNzOiAke2UubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLnVzZXJLZXkpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGRlcml2ZWRBZGRyZXNzID0gdGhpcy5kZXJpdmVBZGRyZXNzRnJvbVB1YmxpY0tleShwYXJhbXMudXNlcktleSwgaW5kZXgpO1xuICAgICAgICBwb3NzaWJsZUNvbnNvbGlkYXRpb25BZGRyZXNzZXMucHVzaChkZXJpdmVkQWRkcmVzcyk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBGYWlsZWQgdG8gZ2VuZXJhdGUgZGVyaXZlZCBhZGRyZXNzOiAke2V9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBvc3NpYmxlQ29uc29saWRhdGlvbkFkZHJlc3Nlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ1VuYWJsZSB0byBnZW5lcmF0ZSBjb25zb2xpZGF0aW9uIGFkZHJlc3MuIENoZWNrIHRoYXQgd2FsbGV0IGNvbnRyYWN0IGFkZHJlc3MsIGZlZSBhZGRyZXNzLCBvciB1c2VyIGtleSBpcyB2YWxpZC4nXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gcG9zc2libGVDb25zb2xpZGF0aW9uQWRkcmVzc2VzO1xuICB9XG5cbiAgYXN5bmMgcmVjb3ZlckNvbnNvbGlkYXRpb25zKHBhcmFtczogRXRoQ29uc29saWRhdGlvblJlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8VW5zaWduZWRCdWlsQ29uc29saWRhdGlvbj4ge1xuICAgIGNvbnN0IGlzVW5zaWduZWRTd2VlcCA9ICFwYXJhbXMudXNlcktleSAmJiAhcGFyYW1zLmJhY2t1cEtleSAmJiAhcGFyYW1zLndhbGxldFBhc3NwaHJhc2U7XG4gICAgY29uc3Qgc3RhcnRJZHggPSBwYXJhbXMuc3RhcnRpbmdTY2FuSW5kZXggfHwgMTtcbiAgICBjb25zdCBlbmRJZHggPSBwYXJhbXMuZW5kaW5nU2NhbkluZGV4IHx8IHN0YXJ0SWR4ICsgREVGQVVMVF9TQ0FOX0ZBQ1RPUjtcblxuICAgIGlmICghcGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcyB8fCBwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzID09PSAnJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHdhbGxldCBjb250cmFjdCBhZGRyZXNzICR7cGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzc31gKTtcbiAgICB9XG5cbiAgICBpZiAoIXBhcmFtcy5iaXRnb0ZlZUFkZHJlc3MgfHwgcGFyYW1zLmJpdGdvRmVlQWRkcmVzcyA9PT0gJycpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBmZWUgYWRkcmVzcyAke3BhcmFtcy5iaXRnb0ZlZUFkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0SWR4IDwgMSB8fCBlbmRJZHggPD0gc3RhcnRJZHggfHwgZW5kSWR4IC0gc3RhcnRJZHggPiAxMCAqIERFRkFVTFRfU0NBTl9GQUNUT1IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEludmFsaWQgc3RhcnRpbmcgb3IgZW5kaW5nIGluZGV4IHRvIHNjYW4gZm9yIGFkZHJlc3Nlcy4gc3RhcnRpbmdTY2FuSW5kZXg6ICR7c3RhcnRJZHh9LCBlbmRpbmdTY2FuSW5kZXg6ICR7ZW5kSWR4fS5gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbnNvbGlkYXRlZFRyYW5zYWN0aW9uczogYW55W10gPSBbXTtcbiAgICBsZXQgbGFzdFNjYW5JbmRleCA9IHN0YXJ0SWR4O1xuXG4gICAgZm9yIChsZXQgaSA9IHN0YXJ0SWR4OyBpIDwgZW5kSWR4OyBpKyspIHtcbiAgICAgIGNvbnN0IGNvbnNvbGlkYXRpb25BZGRyZXNzID0gdGhpcy5nZXRDb25zb2xpZGF0aW9uQWRkcmVzcyhwYXJhbXMsIGkpO1xuICAgICAgZm9yIChjb25zdCBhZGRyZXNzIG9mIGNvbnNvbGlkYXRpb25BZGRyZXNzKSB7XG4gICAgICAgIGNvbnN0IHJlY292ZXJQYXJhbXMgPSB7XG4gICAgICAgICAgYXBpS2V5OiBwYXJhbXMuYXBpS2V5LFxuICAgICAgICAgIGJhY2t1cEtleTogcGFyYW1zLmJhY2t1cEtleSB8fCAnJyxcbiAgICAgICAgICBnYXNMaW1pdDogcGFyYW1zLmdhc0xpbWl0LFxuICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uIHx8ICcnLFxuICAgICAgICAgIHVzZXJLZXk6IHBhcmFtcy51c2VyS2V5IHx8ICcnLFxuICAgICAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgICBkZXJpdmF0aW9uU2VlZDogJycsXG4gICAgICAgICAgaXNUc3M6IHBhcmFtcy5pc1RzcyxcbiAgICAgICAgICBlaXAxNTU5OiB7XG4gICAgICAgICAgICBtYXhGZWVQZXJHYXM6IHBhcmFtcy5laXAxNTU5Py5tYXhGZWVQZXJHYXMgfHwgMjAsXG4gICAgICAgICAgICBtYXhQcmlvcml0eUZlZVBlckdhczogcGFyYW1zLmVpcDE1NTk/Lm1heFByaW9yaXR5RmVlUGVyR2FzIHx8IDIwMDAwMCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zOiB7XG4gICAgICAgICAgICBjaGFpbjogcGFyYW1zLnJlcGxheVByb3RlY3Rpb25PcHRpb25zPy5jaGFpbiB8fCAwLFxuICAgICAgICAgICAgaGFyZGZvcms6IHBhcmFtcy5yZXBsYXlQcm90ZWN0aW9uT3B0aW9ucz8uaGFyZGZvcmsgfHwgJ2xvbmRvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBiaXRnb0tleTogJycsXG4gICAgICAgICAgaWdub3JlQWRkcmVzc1R5cGVzOiBbXSxcbiAgICAgICAgfTtcbiAgICAgICAgbGV0IHJlY292ZXJ5VHJhbnNhY3Rpb247XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmVjb3ZlcnlUcmFuc2FjdGlvbiA9IGF3YWl0IHRoaXMucmVjb3ZlcihyZWNvdmVyUGFyYW1zKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIGUubWVzc2FnZSA9PT0gJ0RpZCBub3QgZmluZCBhZGRyZXNzIHdpdGggZnVuZHMgdG8gcmVjb3ZlcicgfHxcbiAgICAgICAgICAgIGUubWVzc2FnZSA9PT0gJ0RpZCBub3QgZmluZCB0b2tlbiBhY2NvdW50IHRvIHJlY292ZXIgdG9rZW5zLCBwbGVhc2UgY2hlY2sgdG9rZW4gYWNjb3VudCcgfHxcbiAgICAgICAgICAgIGUubWVzc2FnZSA9PT0gJ05vdCBlbm91Z2ggdG9rZW4gZnVuZHMgdG8gcmVjb3ZlcidcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIGxhc3RTY2FuSW5kZXggPSBpO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgICAgIGNvbnNvbGlkYXRlZFRyYW5zYWN0aW9ucy5wdXNoKChyZWNvdmVyeVRyYW5zYWN0aW9uIGFzIE1QQ1N3ZWVwVHhzKS50eFJlcXVlc3RzWzBdKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zb2xpZGF0ZWRUcmFuc2FjdGlvbnMucHVzaChyZWNvdmVyeVRyYW5zYWN0aW9uKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gVG8gYXZvaWQgcmF0ZSBsaW1pdCBmb3IgZXRoZXJzY2FuXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxMDAwKSk7XG4gICAgICAvLyBsYXN0U2NhbkluZGV4ID0gaTtcbiAgICB9XG5cbiAgICBpZiAoY29uc29saWRhdGVkVHJhbnNhY3Rpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgRGlkIG5vdCBmaW5kIGFuIGFkZHJlc3Mgd2l0aCBzdWZmaWNpZW50IGZ1bmRzIHRvIHJlY292ZXIuIFBsZWFzZSBzdGFydCB0aGUgbmV4dCBzY2FuIGF0IGFkZHJlc3MgaW5kZXggJHtcbiAgICAgICAgICBsYXN0U2NhbkluZGV4ICsgMVxuICAgICAgICB9LmBcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiB7IHRyYW5zYWN0aW9uczogY29uc29saWRhdGVkVHJhbnNhY3Rpb25zLCBsYXN0U2NhbkluZGV4IH07XG4gIH1cblxuICAvKipcbiAgICogQnVpbGRzIGEgZnVuZHMgcmVjb3ZlcnkgdHJhbnNhY3Rpb24gd2l0aG91dCBCaXRHbyBmb3Igbm9uLVRTUyB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMudXNlcktleSBbZW5jcnlwdGVkXSB4cHJ2IG9yIHhwdWJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5iYWNrdXBLZXkgW2VuY3J5cHRlZF0geHBydiBvciB4cHViIGlmIHRoZSB4cHJ2IGlzIGhlbGQgYnkgYSBLUlMgcHJvdmlkZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlIHVzZWQgdG8gZGVjcnlwdCB1c2VyS2V5IGFuZCBiYWNrdXBLZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MgdGhlIEV0aExpa2UgYWRkcmVzcyBvZiB0aGUgd2FsbGV0IGNvbnRyYWN0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMua3JzUHJvdmlkZXIgbmVjZXNzYXJ5IGlmIGJhY2t1cCBrZXkgaXMgaGVsZCBieSBLUlNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uIHRhcmdldCBhZGRyZXNzIHRvIHNlbmQgcmVjb3ZlcmVkIGZ1bmRzIHRvXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuYml0Z29GZWVBZGRyZXNzIHdyb25nIGNoYWluIHdhbGxldCBmZWUgYWRkcmVzcyBmb3IgZXZtIGJhc2VkIGNyb3NzIGNoYWluIHJlY292ZXJ5IHR4blxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmJpdGdvRGVzdGluYXRpb25BZGRyZXNzIHRhcmdldCBiaXRnbyBhZGRyZXNzIHdoZXJlIGZlZSB3aWxsIGJlIHNlbnQgZm9yIGV2bSBiYXNlZCBjcm9zcyBjaGFpbiByZWNvdmVyeSB0eG5cbiAgICogQHJldHVybnMge1Byb21pc2U8UmVjb3ZlcnlJbmZvIHwgT2ZmbGluZVZhdWx0VHhJbmZvPn1cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZWNvdmVyRXRoTGlrZShwYXJhbXM6IFJlY292ZXJPcHRpb25zKTogUHJvbWlzZTxSZWNvdmVyeUluZm8gfCBPZmZsaW5lVmF1bHRUeEluZm8+IHtcbiAgICAvLyBiaXRnb0ZlZUFkZHJlc3MgaXMgb25seSBkZWZpbmVkIHdoZW4gaXQgaXMgYSBldm0gY3Jvc3MgY2hhaW4gcmVjb3ZlcnlcbiAgICAvLyBhcyB3ZSB1c2UgZmVlIGZyb20gdGhpcyB3cm9uZyBjaGFpbiBhZGRyZXNzIGZvciB0aGUgcmVjb3ZlcnkgdHhuIG9uIHRoZSBjb3JyZWN0IGNoYWluLlxuICAgIGlmIChwYXJhbXMuYml0Z29GZWVBZGRyZXNzKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZWNvdmVyRXRoTGlrZWZvckV2bUJhc2VkUmVjb3ZlcnkocGFyYW1zKTtcbiAgICB9XG5cbiAgICB0aGlzLnZhbGlkYXRlUmVjb3ZlcnlQYXJhbXMocGFyYW1zKTtcbiAgICBjb25zdCBpc1Vuc2lnbmVkU3dlZXAgPSBwYXJhbXMuaXNVbnNpZ25lZFN3ZWVwID8/IGdldElzVW5zaWduZWRTd2VlcChwYXJhbXMpO1xuXG4gICAgLy8gQ2xlYW4gdXAgd2hpdGVzcGFjZSBmcm9tIGVudGVyZWQgdmFsdWVzXG4gICAgbGV0IHVzZXJLZXkgPSBwYXJhbXMudXNlcktleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuICAgIGNvbnN0IGJhY2t1cEtleSA9IHBhcmFtcy5iYWNrdXBLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBnYXNMaW1pdCA9IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTih0aGlzLnNldEdhc0xpbWl0KHBhcmFtcy5nYXNMaW1pdCkpO1xuICAgIGNvbnN0IGdhc1ByaWNlID0gcGFyYW1zLmVpcDE1NTlcbiAgICAgID8gbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHBhcmFtcy5laXAxNTU5Lm1heEZlZVBlckdhcylcbiAgICAgIDogbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHRoaXMuc2V0R2FzUHJpY2UocGFyYW1zLmdhc1ByaWNlKSk7XG5cbiAgICBpZiAoIXVzZXJLZXkuc3RhcnRzV2l0aCgneHB1YicpICYmICF1c2VyS2V5LnN0YXJ0c1dpdGgoJ3hwcnYnKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdXNlcktleSA9IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgICAgaW5wdXQ6IHVzZXJLZXksXG4gICAgICAgICAgcGFzc3dvcmQ6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBkZWNyeXB0aW5nIHVzZXIga2V5Y2hhaW46ICR7ZS5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH1cbiAgICBsZXQgYmFja3VwS2V5QWRkcmVzcztcbiAgICBsZXQgYmFja3VwU2lnbmluZ0tleTtcbiAgICBpZiAoaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICBjb25zdCBiYWNrdXBIRE5vZGUgPSBiaXAzMi5mcm9tQmFzZTU4KGJhY2t1cEtleSk7XG4gICAgICBiYWNrdXBTaWduaW5nS2V5ID0gYmFja3VwSEROb2RlLnB1YmxpY0tleTtcbiAgICAgIGJhY2t1cEtleUFkZHJlc3MgPSBgMHgke29wdGlvbmFsRGVwcy5ldGhVdGlsLnB1YmxpY1RvQWRkcmVzcyhiYWNrdXBTaWduaW5nS2V5LCB0cnVlKS50b1N0cmluZygnaGV4Jyl9YDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gRGVjcnlwdCBiYWNrdXAgcHJpdmF0ZSBrZXkgYW5kIGdldCBhZGRyZXNzXG4gICAgICBsZXQgYmFja3VwUHJ2O1xuXG4gICAgICB0cnkge1xuICAgICAgICBiYWNrdXBQcnYgPSB0aGlzLmJpdGdvLmRlY3J5cHQoe1xuICAgICAgICAgIGlucHV0OiBiYWNrdXBLZXksXG4gICAgICAgICAgcGFzc3dvcmQ6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBkZWNyeXB0aW5nIGJhY2t1cCBrZXljaGFpbjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGtleVBhaXIgPSBuZXcgS2V5UGFpckxpYih7IHBydjogYmFja3VwUHJ2IH0pO1xuICAgICAgYmFja3VwU2lnbmluZ0tleSA9IGtleVBhaXIuZ2V0S2V5cygpLnBydjtcbiAgICAgIGlmICghYmFja3VwU2lnbmluZ0tleSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vIHByaXZhdGUga2V5Jyk7XG4gICAgICB9XG4gICAgICBiYWNrdXBLZXlBZGRyZXNzID0ga2V5UGFpci5nZXRBZGRyZXNzKCk7XG4gICAgfVxuXG4gICAgY29uc3QgYmFja3VwS2V5Tm9uY2UgPSBhd2FpdCB0aGlzLmdldEFkZHJlc3NOb25jZShiYWNrdXBLZXlBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcbiAgICAvLyBnZXQgYmFsYW5jZSBvZiBiYWNrdXBLZXkgdG8gZW5zdXJlIGZ1bmRzIGFyZSBhdmFpbGFibGUgdG8gcGF5IGZlZXNcbiAgICBjb25zdCBiYWNrdXBLZXlCYWxhbmNlID0gYXdhaXQgdGhpcy5xdWVyeUFkZHJlc3NCYWxhbmNlKGJhY2t1cEtleUFkZHJlc3MsIHBhcmFtcy5hcGlLZXkpO1xuICAgIGxldCB0b3RhbEdhc05lZWRlZCA9IGdhc1ByaWNlLm11bChnYXNMaW1pdCk7XG5cbiAgICAvLyBPbiBvcHRpbWlzbSBjaGFpbiwgTDEgZmVlcyBpcyB0byBiZSBwYWlkIGFzIHdlbGwgYXBhcnQgZnJvbSBMMiBmZWVzXG4gICAgLy8gU28gd2UgYXJlIGFkZGluZyB0aGUgYW1vdW50IHRoYXQgY2FuIGJlIHVzZWQgdXAgYXMgbDEgZmVlc1xuICAgIGlmICh0aGlzLnN0YXRpY3NDb2luPy5mYW1pbHkgPT09ICdvcGV0aCcpIHtcbiAgICAgIHRvdGFsR2FzTmVlZGVkID0gdG90YWxHYXNOZWVkZWQuYWRkKG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihldGhHYXNDb25maWdzLm9wZXRoR2FzTDFGZWVzKSk7XG4gICAgfVxuXG4gICAgY29uc3Qgd2VpVG9Hd2VpID0gMTAgKiogOTtcbiAgICBpZiAoYmFja3VwS2V5QmFsYW5jZS5sdCh0b3RhbEdhc05lZWRlZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEJhY2t1cCBrZXkgYWRkcmVzcyAke2JhY2t1cEtleUFkZHJlc3N9IGhhcyBiYWxhbmNlICR7KGJhY2t1cEtleUJhbGFuY2UgLyB3ZWlUb0d3ZWkpLnRvU3RyaW5nKCl9IEd3ZWkuYCArXG4gICAgICAgICAgYFRoaXMgYWRkcmVzcyBtdXN0IGhhdmUgYSBiYWxhbmNlIG9mIGF0IGxlYXN0ICR7KHRvdGFsR2FzTmVlZGVkIC8gd2VpVG9Hd2VpKS50b1N0cmluZygpfWAgK1xuICAgICAgICAgIGAgR3dlaSB0byBwZXJmb3JtIHJlY292ZXJpZXMuIFRyeSBzZW5kaW5nIHNvbWUgZnVuZHMgdG8gdGhpcyBhZGRyZXNzIHRoZW4gcmV0cnkuYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBnZXQgYmFsYW5jZSBvZiB3YWxsZXRcbiAgICBjb25zdCB0eEFtb3VudCA9IGF3YWl0IHRoaXMucXVlcnlBZGRyZXNzQmFsYW5jZShwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcbiAgICBpZiAobmV3IEJpZ051bWJlcih0eEFtb3VudCkuaXNMZXNzVGhhbk9yRXF1YWxUbygwKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdXYWxsZXQgZG9lcyBub3QgaGF2ZSBlbm91Z2ggZnVuZHMgdG8gcmVjb3ZlcicpO1xuICAgIH1cblxuICAgIC8vIGJ1aWxkIHJlY2lwaWVudHMgb2JqZWN0XG4gICAgY29uc3QgcmVjaXBpZW50cyA9IFtcbiAgICAgIHtcbiAgICAgICAgYWRkcmVzczogcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24sXG4gICAgICAgIGFtb3VudDogdHhBbW91bnQudG9TdHJpbmcoMTApLFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgLy8gR2V0IHNlcXVlbmNlIElEIHVzaW5nIGNvbnRyYWN0IGNhbGxcbiAgICAvLyB3ZSBuZWVkIHRvIHdhaXQgYmV0d2VlbiBtYWtpbmcgdHdvIGV4cGxvcmVyIGFwaSBjYWxscyB0byBhdm9pZCBnZXR0aW5nIGJhbm5lZFxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMDApKTtcbiAgICBjb25zdCBzZXF1ZW5jZUlkID0gYXdhaXQgdGhpcy5xdWVyeVNlcXVlbmNlSWQocGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcywgcGFyYW1zLmFwaUtleSk7XG5cbiAgICBsZXQgb3BlcmF0aW9uSGFzaCwgc2lnbmF0dXJlO1xuICAgIC8vIEdldCBvcGVyYXRpb24gaGFzaCBhbmQgc2lnbiBpdFxuICAgIGlmICghaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICBvcGVyYXRpb25IYXNoID0gdGhpcy5nZXRPcGVyYXRpb25TaGEzRm9yRXhlY3V0ZUFuZENvbmZpcm0ocmVjaXBpZW50cywgdGhpcy5nZXREZWZhdWx0RXhwaXJlVGltZSgpLCBzZXF1ZW5jZUlkKTtcbiAgICAgIHNpZ25hdHVyZSA9IFV0aWwuZXRoU2lnbk1zZ0hhc2gob3BlcmF0aW9uSGFzaCwgVXRpbC54cHJ2VG9FdGhQcml2YXRlS2V5KHVzZXJLZXkpKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgVXRpbC5lY1JlY292ZXJFdGhBZGRyZXNzKG9wZXJhdGlvbkhhc2gsIHNpZ25hdHVyZSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzaWduYXR1cmUnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCB0eEluZm8gPSB7XG4gICAgICByZWNpcGllbnQ6IHJlY2lwaWVudHNbMF0sXG4gICAgICBleHBpcmVUaW1lOiB0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCksXG4gICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IHNlcXVlbmNlSWQsXG4gICAgICBvcGVyYXRpb25IYXNoOiBvcGVyYXRpb25IYXNoLFxuICAgICAgc2lnbmF0dXJlOiBzaWduYXR1cmUsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoMTApLFxuICAgIH07XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgdHhCdWlsZGVyLmNvdW50ZXIoYmFja3VwS2V5Tm9uY2UpO1xuICAgIHR4QnVpbGRlci5jb250cmFjdChwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzKTtcbiAgICBsZXQgdHhGZWU7XG4gICAgaWYgKHBhcmFtcy5laXAxNTU5KSB7XG4gICAgICB0eEZlZSA9IHtcbiAgICAgICAgZWlwMTU1OToge1xuICAgICAgICAgIG1heFByaW9yaXR5RmVlUGVyR2FzOiBwYXJhbXMuZWlwMTU1OS5tYXhQcmlvcml0eUZlZVBlckdhcyxcbiAgICAgICAgICBtYXhGZWVQZXJHYXM6IHBhcmFtcy5laXAxNTU5Lm1heEZlZVBlckdhcyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHR4RmVlID0geyBmZWU6IGdhc1ByaWNlLnRvU3RyaW5nKCkgfTtcbiAgICB9XG4gICAgdHhCdWlsZGVyLmZlZSh7XG4gICAgICAuLi50eEZlZSxcbiAgICAgIGdhc0xpbWl0OiBnYXNMaW1pdC50b1N0cmluZygpLFxuICAgIH0pO1xuICAgIGNvbnN0IHRyYW5zZmVyQnVpbGRlciA9IHR4QnVpbGRlci50cmFuc2ZlcigpIGFzIFRyYW5zZmVyQnVpbGRlcjtcbiAgICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAgIC5jb2luKHRoaXMuc3RhdGljc0NvaW4/Lm5hbWUgYXMgc3RyaW5nKVxuICAgICAgLmFtb3VudChyZWNpcGllbnRzWzBdLmFtb3VudClcbiAgICAgIC5jb250cmFjdFNlcXVlbmNlSWQoc2VxdWVuY2VJZClcbiAgICAgIC5leHBpcmF0aW9uVGltZSh0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCkpXG4gICAgICAudG8ocGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pO1xuXG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBpZiAoaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICBjb25zdCByZXNwb25zZTogT2ZmbGluZVZhdWx0VHhJbmZvID0ge1xuICAgICAgICB0eEhleDogdHgudG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgICAgdXNlcktleSxcbiAgICAgICAgYmFja3VwS2V5LFxuICAgICAgICBjb2luOiB0aGlzLmdldENoYWluKCksXG4gICAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgICBnYXNMaW1pdCxcbiAgICAgICAgcmVjaXBpZW50czogW3R4SW5mby5yZWNpcGllbnRdLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IHR4LnRvSnNvbigpLnRvLFxuICAgICAgICBhbW91bnQ6IHR4SW5mby5yZWNpcGllbnQuYW1vdW50LFxuICAgICAgICBiYWNrdXBLZXlOb25jZSxcbiAgICAgICAgZWlwMTU1OTogcGFyYW1zLmVpcDE1NTksXG4gICAgICB9O1xuICAgICAgXy5leHRlbmQocmVzcG9uc2UsIHR4SW5mbyk7XG4gICAgICByZXNwb25zZS5uZXh0Q29udHJhY3RTZXF1ZW5jZUlkID0gcmVzcG9uc2UuY29udHJhY3RTZXF1ZW5jZUlkO1xuICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgIH1cblxuICAgIHR4QnVpbGRlclxuICAgICAgLnRyYW5zZmVyKClcbiAgICAgIC5jb2luKHRoaXMuc3RhdGljc0NvaW4/Lm5hbWUgYXMgc3RyaW5nKVxuICAgICAgLmtleShuZXcgS2V5UGFpckxpYih7IHBydjogdXNlcktleSB9KS5nZXRLZXlzKCkucHJ2IGFzIHN0cmluZyk7XG4gICAgdHhCdWlsZGVyLnNpZ24oeyBrZXk6IGJhY2t1cFNpZ25pbmdLZXkgfSk7XG5cbiAgICBjb25zdCBzaWduZWRUeCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBzaWduZWRUeC50b0pzb24oKS5pZCxcbiAgICAgIHR4OiBzaWduZWRUeC50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCByZWNpcGllbnRzIGZyb20gdHJhbnNhY3Rpb24gaGV4XG4gICAqIEBwYXJhbSB0eEhleCAtIFRoZSB0cmFuc2FjdGlvbiBoZXggc3RyaW5nXG4gICAqIEByZXR1cm5zIEFycmF5IG9mIHJlY2lwaWVudHMgd2l0aCBhZGRyZXNzIGFuZCBhbW91bnRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZXh0cmFjdFJlY2lwaWVudHNGcm9tVHhIZXgodHhIZXg6IHN0cmluZyk6IFByb21pc2U8QXJyYXk8eyBhZGRyZXNzOiBzdHJpbmc7IGFtb3VudDogc3RyaW5nIH0+PiB7XG4gICAgY29uc3QgdHhCdWZmZXIgPSBvcHRpb25hbERlcHMuZXRoVXRpbC50b0J1ZmZlcih0eEhleCk7XG4gICAgY29uc3QgZGVjb2RlZFR4ID0gb3B0aW9uYWxEZXBzLkV0aFR4LlRyYW5zYWN0aW9uRmFjdG9yeS5mcm9tU2VyaWFsaXplZERhdGEodHhCdWZmZXIpO1xuICAgIGNvbnN0IHJlY2lwaWVudHM6IEFycmF5PHsgYWRkcmVzczogc3RyaW5nOyBhbW91bnQ6IHN0cmluZyB9PiA9IFtdO1xuXG4gICAgaWYgKGRlY29kZWRUeC5kYXRhICYmIGRlY29kZWRUeC5kYXRhLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGRhdGFIZXggPSBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleChkZWNvZGVkVHguZGF0YSk7XG4gICAgICBjb25zdCB0cmFuc2ZlckRhdGEgPSBkZWNvZGVUcmFuc2ZlckRhdGEoZGF0YUhleCk7XG4gICAgICBpZiAodHJhbnNmZXJEYXRhLnRvKSB7XG4gICAgICAgIHJlY2lwaWVudHMucHVzaCh7XG4gICAgICAgICAgYWRkcmVzczogdHJhbnNmZXJEYXRhLnRvLFxuICAgICAgICAgIGFtb3VudDogdHJhbnNmZXJEYXRhLmFtb3VudCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlY2lwaWVudHM7XG4gIH1cblxuICBhc3luYyBzZW5kQ3Jvc3NDaGFpblJlY292ZXJ5VHJhbnNhY3Rpb24oXG4gICAgcGFyYW1zOiBTZW5kQ3Jvc3NDaGFpblJlY292ZXJ5T3B0aW9uc1xuICApOiBQcm9taXNlPHsgY29pbjogc3RyaW5nOyB0eEhleD86IHN0cmluZzsgdHhpZDogc3RyaW5nIH0+IHtcbiAgICBjb25zdCBidWlsZFJlc3BvbnNlID0gYXdhaXQgdGhpcy5idWlsZENyb3NzQ2hhaW5SZWNvdmVyeVRyYW5zYWN0aW9uKHBhcmFtcy5yZWNvdmVyeUlkKTtcbiAgICBpZiAocGFyYW1zLndhbGxldFR5cGUgPT09ICdjb2xkJykge1xuICAgICAgcmV0dXJuIGJ1aWxkUmVzcG9uc2U7XG4gICAgfVxuICAgIGlmICghcGFyYW1zLmVuY3J5cHRlZFBydikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIGVuY3J5cHRlZFBydicpO1xuICAgIH1cblxuICAgIGxldCB1c2VyS2V5UHJ2O1xuICAgIHRyeSB7XG4gICAgICB1c2VyS2V5UHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgaW5wdXQ6IHBhcmFtcy5lbmNyeXB0ZWRQcnYsXG4gICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyB1c2VyIGtleWNoYWluOiAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gICAgY29uc3Qga2V5UGFpciA9IG5ldyBLZXlQYWlyTGliKHsgcHJ2OiB1c2VyS2V5UHJ2IH0pO1xuICAgIGNvbnN0IHVzZXJTaWduaW5nS2V5ID0ga2V5UGFpci5nZXRLZXlzKCkucHJ2O1xuICAgIGlmICghdXNlclNpZ25pbmdLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbm8gcHJpdmF0ZSBrZXknKTtcbiAgICB9XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgY29uc3QgdHhIZXggPSBidWlsZFJlc3BvbnNlLnR4SGV4O1xuICAgIHR4QnVpbGRlci5mcm9tKHR4SGV4KTtcbiAgICBpZiAoYnVpbGRSZXNwb25zZS53YWxsZXRWZXJzaW9uKSB7XG4gICAgICAvLyBJZiB3YWxsZXRWZXJzaW9uIGlzIHByb3ZpZGVkLCBzZXQgaXQgaW4gdGhlIHR4QnVpbGRlclxuICAgICAgdHhCdWlsZGVyLndhbGxldFZlcnNpb24oYnVpbGRSZXNwb25zZS53YWxsZXRWZXJzaW9uKTtcbiAgICB9XG4gICAgdHhCdWlsZGVyXG4gICAgICAudHJhbnNmZXIoKVxuICAgICAgLmNvaW4odGhpcy5zdGF0aWNzQ29pbj8ubmFtZSBhcyBzdHJpbmcpXG4gICAgICAua2V5KHVzZXJTaWduaW5nS2V5KTtcbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IHRoaXMuYml0Z29cbiAgICAgIC5wb3N0KHRoaXMuYml0Z28ubWljcm9zZXJ2aWNlc1VybChgL2FwaS9yZWNvdmVyeS92MS9jcm9zc2NoYWluLyR7cGFyYW1zLnJlY292ZXJ5SWR9L3NpZ25gKSlcbiAgICAgIC5zZW5kKHsgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCkgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvaW46IHRoaXMuc3RhdGljc0NvaW4/Lm5hbWUgYXMgc3RyaW5nLFxuICAgICAgdHhpZDogcmVzLmJvZHkudHhpZCxcbiAgICB9O1xuICB9XG5cbiAgYXN5bmMgYnVpbGRDcm9zc0NoYWluUmVjb3ZlcnlUcmFuc2FjdGlvbihyZWNvdmVyeUlkOiBzdHJpbmcpOiBQcm9taXNlPHtcbiAgICBjb2luOiBzdHJpbmc7XG4gICAgdHhIZXg6IHN0cmluZztcbiAgICB0eGlkOiBzdHJpbmc7XG4gICAgd2FsbGV0VmVyc2lvbj86IG51bWJlcjtcbiAgICByZWNpcGllbnRzOiBBcnJheTx7IGFkZHJlc3M6IHN0cmluZzsgYW1vdW50OiBzdHJpbmcgfT47XG4gIH0+IHtcbiAgICBjb25zdCByZXMgPSBhd2FpdCB0aGlzLmJpdGdvLmdldCh0aGlzLmJpdGdvLm1pY3Jvc2VydmljZXNVcmwoYC9hcGkvcmVjb3ZlcnkvdjEvY3Jvc3NjaGFpbi8ke3JlY292ZXJ5SWR9L2J1aWxkdHhgKSk7XG4gICAgLy8gRXh0cmFjdCByZWNpcGllbnRzIGZyb20gdGhlIHRyYW5zYWN0aW9uIGhleFxuICAgIGNvbnN0IHJlY2lwaWVudHMgPSBhd2FpdCB0aGlzLmV4dHJhY3RSZWNpcGllbnRzRnJvbVR4SGV4KHJlcy5ib2R5LnR4SGV4KTtcbiAgICByZXR1cm4ge1xuICAgICAgY29pbjogcmVzLmJvZHkuY29pbixcbiAgICAgIHR4SGV4OiByZXMuYm9keS50eEhleCxcbiAgICAgIHR4aWQ6IHJlcy5ib2R5LnR4aWQsXG4gICAgICB3YWxsZXRWZXJzaW9uOiByZXMuYm9keS53YWxsZXRWZXJzaW9uLFxuICAgICAgcmVjaXBpZW50cyxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIHVuc2lnbmVkIChmb3IgY29sZCwgY3VzdG9keSB3YWxsZXQpIG9yXG4gICAqIGhhbGYtc2lnbmVkIChmb3IgaG90IHdhbGxldCkgZXZtIGNyb3NzIGNoYWluIHJlY292ZXJ5IHRyYW5zYWN0aW9uIHdpdGhcbiAgICogc2FtZSBleHBlY3RlZCBhcmd1bWVudHMgYXMgcmVjb3ZlciBtZXRob2QuXG4gICAqIFRoaXMgaGVscHMgcmVjb3ZlciBmdW5kcyBmcm9tIGV2bSBiYXNlZCB3cm9uZyBjaGFpbi5cbiAgICogQHBhcmFtIHtSZWNvdmVyT3B0aW9uc30gcGFyYW1zXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFJlY292ZXJ5SW5mbyB8IE9mZmxpbmVWYXVsdFR4SW5mbz59XG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgcmVjb3ZlckV0aExpa2Vmb3JFdm1CYXNlZFJlY292ZXJ5KFxuICAgIHBhcmFtczogUmVjb3Zlck9wdGlvbnNcbiAgKTogUHJvbWlzZTxSZWNvdmVyeUluZm8gfCBPZmZsaW5lVmF1bHRUeEluZm8+IHtcbiAgICB0aGlzLnZhbGlkYXRlRXZtQmFzZWRSZWNvdmVyeVBhcmFtcyhwYXJhbXMpO1xuXG4gICAgLy8gQ2xlYW4gdXAgd2hpdGVzcGFjZSBmcm9tIGVudGVyZWQgdmFsdWVzXG4gICAgY29uc3QgdXNlcktleSA9IHBhcmFtcy51c2VyS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgY29uc3QgYml0Z29GZWVBZGRyZXNzID0gcGFyYW1zLmJpdGdvRmVlQWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcbiAgICBjb25zdCBiaXRnb0Rlc3RpbmF0aW9uQWRkcmVzcyA9IHBhcmFtcy5iaXRnb0Rlc3RpbmF0aW9uQWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcbiAgICBjb25zdCByZWNvdmVyeURlc3RpbmF0aW9uID0gcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24/LnJlcGxhY2UoL1xccy9nLCAnJykudG9Mb3dlckNhc2UoKSBhcyBzdHJpbmc7XG4gICAgY29uc3Qgd2FsbGV0Q29udHJhY3RBZGRyZXNzID0gcGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcbiAgICBjb25zdCB0b2tlbkNvbnRyYWN0QWRkcmVzcyA9IHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcz8ucmVwbGFjZSgvXFxzL2csICcnKS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZztcblxuICAgIGxldCB1c2VyU2lnbmluZ0tleTtcbiAgICBsZXQgdXNlcktleVBydjtcbiAgICBpZiAocGFyYW1zLndhbGxldFBhc3NwaHJhc2UpIHtcbiAgICAgIGlmICghdXNlcktleS5zdGFydHNXaXRoKCd4cHViJykgJiYgIXVzZXJLZXkuc3RhcnRzV2l0aCgneHBydicpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdXNlcktleVBydiA9IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgICAgICBpbnB1dDogdXNlcktleSxcbiAgICAgICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyB1c2VyIGtleWNoYWluOiAke2UubWVzc2FnZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBrZXlQYWlyID0gbmV3IEtleVBhaXJMaWIoeyBwcnY6IHVzZXJLZXlQcnYgfSk7XG4gICAgICB1c2VyU2lnbmluZ0tleSA9IGtleVBhaXIuZ2V0S2V5cygpLnBydjtcbiAgICAgIGlmICghdXNlclNpZ25pbmdLZXkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdubyBwcml2YXRlIGtleScpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFVzZSBkZWZhdWx0IGdhc0xpbWl0IGZvciBjb2xkIGFuZCBjdXN0b2R5IHdhbGxldHNcbiAgICBsZXQgZ2FzTGltaXQgPVxuICAgICAgcGFyYW1zLmdhc0xpbWl0IHx8IHVzZXJLZXkuc3RhcnRzV2l0aCgneHB1YicpIHx8ICF1c2VyS2V5XG4gICAgICAgID8gbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHRoaXMuc2V0R2FzTGltaXQocGFyYW1zLmdhc0xpbWl0KSlcbiAgICAgICAgOiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4oMCk7XG5cbiAgICBjb25zdCBnYXNQcmljZSA9IHBhcmFtcy5laXAxNTU5XG4gICAgICA/IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihwYXJhbXMuZWlwMTU1OS5tYXhGZWVQZXJHYXMpXG4gICAgICA6IHBhcmFtcy5nYXNQcmljZVxuICAgICAgPyBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4odGhpcy5zZXRHYXNQcmljZShwYXJhbXMuZ2FzUHJpY2UpKVxuICAgICAgOiBhd2FpdCB0aGlzLmdldEdhc1ByaWNlRnJvbUV4dGVybmFsQVBJKHRoaXMuc3RhdGljc0NvaW4/Lm5hbWUgYXMgc3RyaW5nLCBwYXJhbXMuYXBpS2V5KTtcblxuICAgIGNvbnN0IGJpdGdvRmVlQWRkcmVzc05vbmNlID0gYXdhaXQgdGhpcy5nZXRBZGRyZXNzTm9uY2UoYml0Z29GZWVBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcblxuICAgIGlmICh0b2tlbkNvbnRyYWN0QWRkcmVzcykge1xuICAgICAgcmV0dXJuIHRoaXMucmVjb3ZlckV0aExpa2VUb2tlbmZvckV2bUJhc2VkUmVjb3ZlcnkoXG4gICAgICAgIHBhcmFtcyxcbiAgICAgICAgYml0Z29GZWVBZGRyZXNzTm9uY2UsXG4gICAgICAgIGdhc0xpbWl0LFxuICAgICAgICBnYXNQcmljZSxcbiAgICAgICAgdXNlcktleSxcbiAgICAgICAgdXNlclNpZ25pbmdLZXksXG4gICAgICAgIHBhcmFtcy5hcGlLZXlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gZ2V0IGJhbGFuY2Ugb2Ygd2FsbGV0XG4gICAgY29uc3QgdHhBbW91bnQgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc0JhbGFuY2Uod2FsbGV0Q29udHJhY3RBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcblxuICAgIGNvbnN0IGJpdGdvRmVlUGVyY2VudGFnZSA9IDA7IC8vIFRPRE86IEJHLTcxOTEyIGNhbiBjaGFuZ2UgdGhlIGZlZSUgaGVyZS5cbiAgICBjb25zdCBiaXRnb0ZlZUFtb3VudCA9IHR4QW1vdW50ICogKGJpdGdvRmVlUGVyY2VudGFnZSAvIDEwMCk7XG5cbiAgICAvLyBidWlsZCByZWNpcGllbnRzIG9iamVjdFxuICAgIGNvbnN0IHJlY2lwaWVudHM6IFJlY2lwaWVudFtdID0gW1xuICAgICAge1xuICAgICAgICBhZGRyZXNzOiByZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgICBhbW91bnQ6IG5ldyBCaWdOdW1iZXIodHhBbW91bnQpLm1pbnVzKGJpdGdvRmVlQW1vdW50KS50b0ZpeGVkKCksXG4gICAgICB9LFxuICAgIF07XG5cbiAgICBpZiAoYml0Z29GZWVQZXJjZW50YWdlID4gMCkge1xuICAgICAgaWYgKF8uaXNVbmRlZmluZWQoYml0Z29EZXN0aW5hdGlvbkFkZHJlc3MpIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKGJpdGdvRGVzdGluYXRpb25BZGRyZXNzKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgYml0Z29EZXN0aW5hdGlvbkFkZHJlc3MnKTtcbiAgICAgIH1cblxuICAgICAgcmVjaXBpZW50cy5wdXNoKHtcbiAgICAgICAgYWRkcmVzczogYml0Z29EZXN0aW5hdGlvbkFkZHJlc3MsXG4gICAgICAgIGFtb3VudDogYml0Z29GZWVBbW91bnQudG9TdHJpbmcoMTApLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gY2FsY3VsYXRlIGJhdGNoIGRhdGFcbiAgICBjb25zdCBCQVRDSF9NRVRIT0RfTkFNRSA9ICdiYXRjaCc7XG4gICAgY29uc3QgQkFUQ0hfTUVUSE9EX1RZUEVTID0gWydhZGRyZXNzW10nLCAndWludDI1NltdJ107XG4gICAgY29uc3QgYmF0Y2hFeGVjdXRpb25JbmZvID0gdGhpcy5nZXRCYXRjaEV4ZWN1dGlvbkluZm8ocmVjaXBpZW50cyk7XG4gICAgY29uc3QgYmF0Y2hEYXRhID0gb3B0aW9uYWxEZXBzLmV0aFV0aWwuYWRkSGV4UHJlZml4KFxuICAgICAgdGhpcy5nZXRNZXRob2RDYWxsRGF0YShCQVRDSF9NRVRIT0RfTkFNRSwgQkFUQ0hfTUVUSE9EX1RZUEVTLCBiYXRjaEV4ZWN1dGlvbkluZm8udmFsdWVzKS50b1N0cmluZygnaGV4JylcbiAgICApO1xuXG4gICAgLy8gR2V0IHNlcXVlbmNlIElEIHVzaW5nIGNvbnRyYWN0IGNhbGxcbiAgICAvLyB3ZSBuZWVkIHRvIHdhaXQgYmV0d2VlbiBtYWtpbmcgdHdvIGV4cGxvcmVyIGFwaSBjYWxscyB0byBhdm9pZCBnZXR0aW5nIGJhbm5lZFxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMDApKTtcbiAgICBjb25zdCBzZXF1ZW5jZUlkID0gYXdhaXQgdGhpcy5xdWVyeVNlcXVlbmNlSWQod2FsbGV0Q29udHJhY3RBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcblxuICAgIGNvbnN0IG5ldHdvcmsgPSB0aGlzLmdldE5ldHdvcmsoKTtcbiAgICBjb25zdCBiYXRjaGVyQ29udHJhY3RBZGRyZXNzID0gbmV0d29yaz8uYmF0Y2hlckNvbnRyYWN0QWRkcmVzcyBhcyBzdHJpbmc7XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcihwYXJhbXMuY29tbW9uKSBhcyBUcmFuc2FjdGlvbkJ1aWxkZXI7XG4gICAgdHhCdWlsZGVyLmNvdW50ZXIoYml0Z29GZWVBZGRyZXNzTm9uY2UpO1xuICAgIHR4QnVpbGRlci5jb250cmFjdCh3YWxsZXRDb250cmFjdEFkZHJlc3MpO1xuICAgIGxldCB0eEZlZTtcbiAgICBpZiAocGFyYW1zLmVpcDE1NTkpIHtcbiAgICAgIHR4RmVlID0ge1xuICAgICAgICBlaXAxNTU5OiB7XG4gICAgICAgICAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IHBhcmFtcy5laXAxNTU5Lm1heFByaW9yaXR5RmVlUGVyR2FzLFxuICAgICAgICAgIG1heEZlZVBlckdhczogcGFyYW1zLmVpcDE1NTkubWF4RmVlUGVyR2FzLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHhGZWUgPSB7IGZlZTogZ2FzUHJpY2UudG9TdHJpbmcoKSB9O1xuICAgIH1cbiAgICB0eEJ1aWxkZXIuZmVlKHtcbiAgICAgIC4uLnR4RmVlLFxuICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LnRvU3RyaW5nKCksXG4gICAgfSk7XG5cbiAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSB0eEJ1aWxkZXIudHJhbnNmZXIoKSBhcyBUcmFuc2ZlckJ1aWxkZXI7XG4gICAgaWYgKCFiYXRjaGVyQ29udHJhY3RBZGRyZXNzKSB7XG4gICAgICB0cmFuc2ZlckJ1aWxkZXJcbiAgICAgICAgLmNvaW4odGhpcy5zdGF0aWNzQ29pbj8ubmFtZSBhcyBzdHJpbmcpXG4gICAgICAgIC5hbW91bnQoYmF0Y2hFeGVjdXRpb25JbmZvLnRvdGFsQW1vdW50KVxuICAgICAgICAuY29udHJhY3RTZXF1ZW5jZUlkKHNlcXVlbmNlSWQpXG4gICAgICAgIC5leHBpcmF0aW9uVGltZSh0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCkpXG4gICAgICAgIC50byhyZWNvdmVyeURlc3RpbmF0aW9uKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHJhbnNmZXJCdWlsZGVyXG4gICAgICAgIC5jb2luKHRoaXMuc3RhdGljc0NvaW4/Lm5hbWUgYXMgc3RyaW5nKVxuICAgICAgICAuYW1vdW50KGJhdGNoRXhlY3V0aW9uSW5mby50b3RhbEFtb3VudClcbiAgICAgICAgLmNvbnRyYWN0U2VxdWVuY2VJZChzZXF1ZW5jZUlkKVxuICAgICAgICAuZXhwaXJhdGlvblRpbWUodGhpcy5nZXREZWZhdWx0RXhwaXJlVGltZSgpKVxuICAgICAgICAudG8oYmF0Y2hlckNvbnRyYWN0QWRkcmVzcylcbiAgICAgICAgLmRhdGEoYmF0Y2hEYXRhKTtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLndhbGxldFBhc3NwaHJhc2UpIHtcbiAgICAgIHRyYW5zZmVyQnVpbGRlci5rZXkodXNlclNpZ25pbmdLZXkpO1xuICAgIH1cblxuICAgIC8vIElmIHRoZSBpbnRlbmRlZCBjaGFpbiBpcyBhcmJpdHJ1bSBvciBvcHRpbWlzbSwgd2UgbmVlZCB0byB1c2Ugd2FsbGV0IHZlcnNpb24gNFxuICAgIC8vIHNpbmNlIHRoZXNlIGNvbnRyYWN0cyBjb25zdHJ1Y3Qgb3BlcmF0aW9uSGFzaCBkaWZmZXJlbnRseVxuICAgIGlmIChwYXJhbXMuaW50ZW5kZWRDaGFpbiAmJiBbJ2FyYmV0aCcsICdvcGV0aCddLmluY2x1ZGVzKGNvaW5zLmdldChwYXJhbXMuaW50ZW5kZWRDaGFpbikuZmFtaWx5KSkge1xuICAgICAgdHhCdWlsZGVyLndhbGxldFZlcnNpb24oNCk7XG4gICAgfVxuXG4gICAgLy8gSWYgZ2FzTGltaXQgd2FzIG5vdCBwYXNzZWQgYXMgYSBwYXJhbSBvciBpZiBpdCBpcyBub3QgY29sZC9jdXN0b2R5IHdhbGxldCwgdGhlbiBmZXRjaCB0aGUgZ2FzTGltaXQgZnJvbSBFeHBsb3JlclxuICAgIGlmICghcGFyYW1zLmdhc0xpbWl0ICYmIHVzZXJLZXkgJiYgIXVzZXJLZXkuc3RhcnRzV2l0aCgneHB1YicpKSB7XG4gICAgICBjb25zdCBzZW5kRGF0YSA9IHR4QnVpbGRlci5nZXRTZW5kRGF0YSgpO1xuICAgICAgZ2FzTGltaXQgPSBhd2FpdCB0aGlzLmdldEdhc0xpbWl0RnJvbUV4dGVybmFsQVBJKFxuICAgICAgICBwYXJhbXMuaW50ZW5kZWRDaGFpbiBhcyBzdHJpbmcsXG4gICAgICAgIHBhcmFtcy5iaXRnb0ZlZUFkZHJlc3MgYXMgc3RyaW5nLFxuICAgICAgICBwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzLFxuICAgICAgICBzZW5kRGF0YSxcbiAgICAgICAgcGFyYW1zLmFwaUtleVxuICAgICAgKTtcbiAgICAgIHR4QnVpbGRlci5mZWUoe1xuICAgICAgICAuLi50eEZlZSxcbiAgICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LnRvU3RyaW5nKCksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBHZXQgdGhlIGJhbGFuY2Ugb2YgYml0Z29GZWVBZGRyZXNzIHRvIGVuc3VyZSBmdW5kcyBhcmUgYXZhaWxhYmxlIHRvIHBheSBmZWVzXG4gICAgYXdhaXQgdGhpcy5lbnN1cmVTdWZmaWNpZW50QmFsYW5jZShiaXRnb0ZlZUFkZHJlc3MsIGdhc1ByaWNlLCBnYXNMaW1pdCwgcGFyYW1zLmFwaUtleSk7XG5cbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgY29uc3QgdHhJbmZvID0ge1xuICAgICAgcmVjaXBpZW50czogcmVjaXBpZW50cyxcbiAgICAgIGV4cGlyZVRpbWU6IHRoaXMuZ2V0RGVmYXVsdEV4cGlyZVRpbWUoKSxcbiAgICAgIGNvbnRyYWN0U2VxdWVuY2VJZDogc2VxdWVuY2VJZCxcbiAgICAgIGdhc0xpbWl0OiBnYXNMaW1pdC50b1N0cmluZygxMCksXG4gICAgICBpc0V2bUJhc2VkQ3Jvc3NDaGFpblJlY292ZXJ5OiB0cnVlLFxuICAgIH07XG5cbiAgICBjb25zdCByZXNwb25zZTogT2ZmbGluZVZhdWx0VHhJbmZvID0ge1xuICAgICAgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICB1c2VyS2V5LFxuICAgICAgY29pbjogdGhpcy5nZXRDaGFpbigpLFxuICAgICAgZ2FzUHJpY2U6IG9wdGlvbmFsRGVwcy5ldGhVdGlsLmJ1ZmZlclRvSW50KGdhc1ByaWNlKS50b0ZpeGVkKCksXG4gICAgICBnYXNMaW1pdCxcbiAgICAgIHJlY2lwaWVudHM6IHR4SW5mby5yZWNpcGllbnRzLFxuICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiB0eC50b0pzb24oKS50byxcbiAgICAgIGFtb3VudDogYmF0Y2hFeGVjdXRpb25JbmZvLnRvdGFsQW1vdW50LFxuICAgICAgYmFja3VwS2V5Tm9uY2U6IGJpdGdvRmVlQWRkcmVzc05vbmNlLFxuICAgICAgZWlwMTU1OTogcGFyYW1zLmVpcDE1NTksXG4gICAgICAuLi4odHhCdWlsZGVyLmdldFdhbGxldFZlcnNpb24oKSA9PT0gNCA/IHsgd2FsbGV0VmVyc2lvbjogdHhCdWlsZGVyLmdldFdhbGxldFZlcnNpb24oKSB9IDoge30pLFxuICAgIH07XG4gICAgXy5leHRlbmQocmVzcG9uc2UsIHR4SW5mbyk7XG4gICAgcmVzcG9uc2UubmV4dENvbnRyYWN0U2VxdWVuY2VJZCA9IHJlc3BvbnNlLmNvbnRyYWN0U2VxdWVuY2VJZDtcblxuICAgIGlmIChwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgY29uc3QgaGFsZlNpZ25lZFR4bjogSGFsZlNpZ25lZFRyYW5zYWN0aW9uID0ge1xuICAgICAgICBoYWxmU2lnbmVkOiB7XG4gICAgICAgICAgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgcmVjaXBpZW50czogdHhJbmZvLnJlY2lwaWVudHMsXG4gICAgICAgICAgZXhwaXJlVGltZTogdHhJbmZvLmV4cGlyZVRpbWUsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgXy5leHRlbmQocmVzcG9uc2UsIGhhbGZTaWduZWRUeG4pO1xuXG4gICAgICBjb25zdCBmZWVzVXNlZDogRmVlc1VzZWQgPSB7XG4gICAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgICBnYXNMaW1pdDogb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9JbnQoZ2FzTGltaXQpLnRvRml4ZWQoKSxcbiAgICAgIH07XG4gICAgICByZXNwb25zZVsnZmVlc1VzZWQnXSA9IGZlZXNVc2VkO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyeSBleHBsb3JlciBmb3IgdGhlIGJhbGFuY2Ugb2YgYW4gYWRkcmVzcyBmb3IgYSB0b2tlblxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9rZW5Db250cmFjdEFkZHJlc3MgLSBhZGRyZXNzIHdoZXJlIHRoZSB0b2tlbiBzbWFydCBjb250cmFjdCBpcyBob3N0ZWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHdhbGxldENvbnRyYWN0QWRkcmVzcyAtIGFkZHJlc3Mgb2YgdGhlIHdhbGxldFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXBpS2V5IC0gb3B0aW9uYWwgQVBJIGtleSB0byB1c2UgaW5zdGVhZCBvZiB0aGUgb25lIGZyb20gdGhlIGVudmlyb25tZW50XG4gICAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IHRva2VuIGJhbGFhbmNlIGluIGJhc2UgdW5pdHNcbiAgICovXG4gIGFzeW5jIHF1ZXJ5QWRkcmVzc1Rva2VuQmFsYW5jZShcbiAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogc3RyaW5nLFxuICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogc3RyaW5nLFxuICAgIGFwaUtleT86IHN0cmluZ1xuICApOiBQcm9taXNlPGFueT4ge1xuICAgIGlmICghb3B0aW9uYWxEZXBzLmV0aFV0aWwuaXNWYWxpZEFkZHJlc3ModG9rZW5Db250cmFjdEFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Nhbm5vdCBnZXQgYmFsYW5jZSBmb3IgaW52YWxpZCB0b2tlbiBhZGRyZXNzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9uYWxEZXBzLmV0aFV0aWwuaXNWYWxpZEFkZHJlc3Mod2FsbGV0Q29udHJhY3RBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgZ2V0IHRva2VuIGJhbGFuY2UgZm9yIGludmFsaWQgd2FsbGV0IGFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoXG4gICAgICB7XG4gICAgICAgIGNoYWluaWQ6IHRoaXMuZ2V0Q2hhaW5JZCgpLnRvU3RyaW5nKCksXG4gICAgICAgIG1vZHVsZTogJ2FjY291bnQnLFxuICAgICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgICBjb250cmFjdGFkZHJlc3M6IHRva2VuQ29udHJhY3RBZGRyZXNzLFxuICAgICAgICBhZGRyZXNzOiB3YWxsZXRDb250cmFjdEFkZHJlc3MsXG4gICAgICAgIHRhZzogJ2xhdGVzdCcsXG4gICAgICB9LFxuICAgICAgYXBpS2V5XG4gICAgKTtcbiAgICAvLyB0aHJvdyBpZiB0aGUgcmVzdWx0IGRvZXMgbm90IGV4aXN0IG9yIHRoZSByZXN1bHQgaXMgbm90IGEgdmFsaWQgbnVtYmVyXG4gICAgaWYgKCFyZXN1bHQgfHwgIXJlc3VsdC5yZXN1bHQgfHwgaXNOYU4ocmVzdWx0LnJlc3VsdCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENvdWxkIG5vdCBvYnRhaW4gdG9rZW4gYWRkcmVzcyBiYWxhbmNlIGZvciAke3Rva2VuQ29udHJhY3RBZGRyZXNzfSBmcm9tIEV0aGVyc2NhbiwgZ290OiAke3Jlc3VsdC5yZXN1bHR9YFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTihyZXN1bHQucmVzdWx0LCAxMCk7XG4gIH1cblxuICBhc3luYyByZWNvdmVyRXRoTGlrZVRva2VuZm9yRXZtQmFzZWRSZWNvdmVyeShcbiAgICBwYXJhbXM6IFJlY292ZXJPcHRpb25zLFxuICAgIGJpdGdvRmVlQWRkcmVzc05vbmNlOiBudW1iZXIsXG4gICAgZ2FzTGltaXQsXG4gICAgZ2FzUHJpY2UsXG4gICAgdXNlcktleSxcbiAgICB1c2VyU2lnbmluZ0tleSxcbiAgICBhcGlLZXk/OiBzdHJpbmdcbiAgKSB7XG4gICAgLy8gZ2V0IHRva2VuIGJhbGFuY2Ugb2Ygd2FsbGV0XG4gICAgY29uc3QgdHhBbW91bnQgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc1Rva2VuQmFsYW5jZShcbiAgICAgIHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcyBhcyBzdHJpbmcsXG4gICAgICBwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzLFxuICAgICAgYXBpS2V5XG4gICAgKTtcblxuICAgIC8vIGJ1aWxkIHJlY2lwaWVudHMgb2JqZWN0XG4gICAgY29uc3QgcmVjaXBpZW50czogUmVjaXBpZW50W10gPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgICBhbW91bnQ6IG5ldyBCaWdOdW1iZXIodHhBbW91bnQpLnRvRml4ZWQoKSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIC8vIEdldCBzZXF1ZW5jZSBJRCB1c2luZyBjb250cmFjdCBjYWxsXG4gICAgLy8gd2UgbmVlZCB0byB3YWl0IGJldHdlZW4gbWFraW5nIHR3byBleHBsb3JlciBhcGkgY2FsbHMgdG8gYXZvaWQgZ2V0dGluZyBiYW5uZWRcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxMDAwKSk7XG4gICAgY29uc3Qgc2VxdWVuY2VJZCA9IGF3YWl0IHRoaXMucXVlcnlTZXF1ZW5jZUlkKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MsIHBhcmFtcy5hcGlLZXkpO1xuXG4gICAgY29uc3QgdHhCdWlsZGVyID0gdGhpcy5nZXRUcmFuc2FjdGlvbkJ1aWxkZXIocGFyYW1zLmNvbW1vbikgYXMgVHJhbnNhY3Rpb25CdWlsZGVyO1xuICAgIHR4QnVpbGRlci5jb3VudGVyKGJpdGdvRmVlQWRkcmVzc05vbmNlKTtcbiAgICB0eEJ1aWxkZXIuY29udHJhY3QocGFyYW1zLndhbGxldENvbnRyYWN0QWRkcmVzcyBhcyBzdHJpbmcpO1xuICAgIGxldCB0eEZlZTtcbiAgICBpZiAocGFyYW1zLmVpcDE1NTkpIHtcbiAgICAgIHR4RmVlID0ge1xuICAgICAgICBlaXAxNTU5OiB7XG4gICAgICAgICAgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IHBhcmFtcy5laXAxNTU5Lm1heFByaW9yaXR5RmVlUGVyR2FzLFxuICAgICAgICAgIG1heEZlZVBlckdhczogcGFyYW1zLmVpcDE1NTkubWF4RmVlUGVyR2FzLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHhGZWUgPSB7IGZlZTogZ2FzUHJpY2UudG9TdHJpbmcoKSB9O1xuICAgIH1cbiAgICB0eEJ1aWxkZXIuZmVlKHtcbiAgICAgIC4uLnR4RmVlLFxuICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LnRvU3RyaW5nKCksXG4gICAgfSk7XG5cbiAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSB0eEJ1aWxkZXIudHJhbnNmZXIoKSBhcyBUcmFuc2ZlckJ1aWxkZXI7XG5cbiAgICBjb25zdCBuZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKCk7XG4gICAgY29uc3QgdG9rZW4gPSBnZXRUb2tlbihcbiAgICAgIHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcyBhcyBzdHJpbmcsXG4gICAgICBuZXR3b3JrIGFzIEV0aExpa2VOZXR3b3JrLFxuICAgICAgdGhpcy5zdGF0aWNzQ29pbj8uZmFtaWx5IGFzIHN0cmluZ1xuICAgICk/Lm5hbWUgYXMgc3RyaW5nO1xuXG4gICAgdHJhbnNmZXJCdWlsZGVyXG4gICAgICAuYW1vdW50KHR4QW1vdW50KVxuICAgICAgLmNvbnRyYWN0U2VxdWVuY2VJZChzZXF1ZW5jZUlkKVxuICAgICAgLmV4cGlyYXRpb25UaW1lKHRoaXMuZ2V0RGVmYXVsdEV4cGlyZVRpbWUoKSlcbiAgICAgIC50byhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbik7XG5cbiAgICBpZiAodG9rZW4pIHtcbiAgICAgIHRyYW5zZmVyQnVpbGRlci5jb2luKHRva2VuKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHJhbnNmZXJCdWlsZGVyXG4gICAgICAgIC5jb2luKHRoaXMuc3RhdGljc0NvaW4/Lm5hbWUgYXMgc3RyaW5nKVxuICAgICAgICAudG9rZW5Db250cmFjdEFkZHJlc3MocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzIGFzIHN0cmluZyk7XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKSB7XG4gICAgICB0eEJ1aWxkZXIudHJhbnNmZXIoKS5rZXkodXNlclNpZ25pbmdLZXkpO1xuICAgIH1cbiAgICAvLyBJZiB0aGUgaW50ZW5kZWQgY2hhaW4gaXMgYXJiaXRydW0gb3Igb3B0aW1pc20sIHdlIG5lZWQgdG8gdXNlIHdhbGxldCB2ZXJzaW9uIDRcbiAgICAvLyBzaW5jZSB0aGVzZSBjb250cmFjdHMgY29uc3RydWN0IG9wZXJhdGlvbkhhc2ggZGlmZmVyZW50bHlcbiAgICBpZiAocGFyYW1zLmludGVuZGVkQ2hhaW4gJiYgWydhcmJldGgnLCAnb3BldGgnXS5pbmNsdWRlcyhjb2lucy5nZXQocGFyYW1zLmludGVuZGVkQ2hhaW4pLmZhbWlseSkpIHtcbiAgICAgIHR4QnVpbGRlci53YWxsZXRWZXJzaW9uKDQpO1xuICAgIH1cblxuICAgIGlmICghcGFyYW1zLmdhc0xpbWl0ICYmIHVzZXJLZXkgJiYgIXVzZXJLZXkuc3RhcnRzV2l0aCgneHB1YicpKSB7XG4gICAgICBjb25zdCBzZW5kRGF0YSA9IHR4QnVpbGRlci5nZXRTZW5kRGF0YSgpO1xuICAgICAgZ2FzTGltaXQgPSBhd2FpdCB0aGlzLmdldEdhc0xpbWl0RnJvbUV4dGVybmFsQVBJKFxuICAgICAgICBwYXJhbXMuaW50ZW5kZWRDaGFpbiBhcyBzdHJpbmcsXG4gICAgICAgIHBhcmFtcy5iaXRnb0ZlZUFkZHJlc3MgYXMgc3RyaW5nLFxuICAgICAgICBwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzLFxuICAgICAgICBzZW5kRGF0YSxcbiAgICAgICAgYXBpS2V5XG4gICAgICApO1xuICAgICAgdHhCdWlsZGVyLmZlZSh7XG4gICAgICAgIC4uLnR4RmVlLFxuICAgICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoKSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEdldCB0aGUgYmFsYW5jZSBvZiBiaXRnb0ZlZUFkZHJlc3MgdG8gZW5zdXJlIGZ1bmRzIGFyZSBhdmFpbGFibGUgdG8gcGF5IGZlZXNcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVN1ZmZpY2llbnRCYWxhbmNlKHBhcmFtcy5iaXRnb0ZlZUFkZHJlc3MgYXMgc3RyaW5nLCBnYXNQcmljZSwgZ2FzTGltaXQsIHBhcmFtcy5hcGlLZXkpO1xuXG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcblxuICAgIGNvbnN0IHR4SW5mbyA9IHtcbiAgICAgIHJlY2lwaWVudHM6IHJlY2lwaWVudHMsXG4gICAgICBleHBpcmVUaW1lOiB0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCksXG4gICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IHNlcXVlbmNlSWQsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoMTApLFxuICAgICAgaXNFdm1CYXNlZENyb3NzQ2hhaW5SZWNvdmVyeTogdHJ1ZSxcbiAgICB9O1xuXG4gICAgY29uc3QgcmVzcG9uc2U6IE9mZmxpbmVWYXVsdFR4SW5mbyA9IHtcbiAgICAgIHR4SGV4OiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgICAgdXNlcktleSxcbiAgICAgIGNvaW46IHRva2VuID8gdG9rZW4gOiB0aGlzLmdldENoYWluKCksXG4gICAgICBnYXNQcmljZTogb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9JbnQoZ2FzUHJpY2UpLnRvRml4ZWQoKSxcbiAgICAgIGdhc0xpbWl0LFxuICAgICAgcmVjaXBpZW50czogdHhJbmZvLnJlY2lwaWVudHMsXG4gICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IHR4LnRvSnNvbigpLnRvLFxuICAgICAgYW1vdW50OiB0eEFtb3VudC50b1N0cmluZygpLFxuICAgICAgYmFja3VwS2V5Tm9uY2U6IGJpdGdvRmVlQWRkcmVzc05vbmNlLFxuICAgICAgZWlwMTU1OTogcGFyYW1zLmVpcDE1NTksXG4gICAgICAuLi4odHhCdWlsZGVyLmdldFdhbGxldFZlcnNpb24oKSA9PT0gNCA/IHsgd2FsbGV0VmVyc2lvbjogdHhCdWlsZGVyLmdldFdhbGxldFZlcnNpb24oKSB9IDoge30pLFxuICAgIH07XG4gICAgXy5leHRlbmQocmVzcG9uc2UsIHR4SW5mbyk7XG4gICAgcmVzcG9uc2UubmV4dENvbnRyYWN0U2VxdWVuY2VJZCA9IHJlc3BvbnNlLmNvbnRyYWN0U2VxdWVuY2VJZDtcblxuICAgIGlmIChwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgY29uc3QgaGFsZlNpZ25lZFR4bjogSGFsZlNpZ25lZFRyYW5zYWN0aW9uID0ge1xuICAgICAgICBoYWxmU2lnbmVkOiB7XG4gICAgICAgICAgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgICAgcmVjaXBpZW50czogdHhJbmZvLnJlY2lwaWVudHMsXG4gICAgICAgICAgZXhwaXJlVGltZTogdHhJbmZvLmV4cGlyZVRpbWUsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgXy5leHRlbmQocmVzcG9uc2UsIGhhbGZTaWduZWRUeG4pO1xuXG4gICAgICBjb25zdCBmZWVzVXNlZDogRmVlc1VzZWQgPSB7XG4gICAgICAgIGdhc1ByaWNlOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0ludChnYXNQcmljZSkudG9GaXhlZCgpLFxuICAgICAgICBnYXNMaW1pdDogb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9JbnQoZ2FzTGltaXQpLnRvRml4ZWQoKSxcbiAgICAgIH07XG4gICAgICByZXNwb25zZVsnZmVlc1VzZWQnXSA9IGZlZXNVc2VkO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBldm0gYmFzZWQgY3Jvc3MgY2hhaW4gcmVjb3ZlcnkgcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMge1JlY292ZXJPcHRpb25zfVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHZhbGlkYXRlRXZtQmFzZWRSZWNvdmVyeVBhcmFtcyhwYXJhbXM6IFJlY292ZXJPcHRpb25zKTogdm9pZCB7XG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLmJpdGdvRmVlQWRkcmVzcykgfHwgIXRoaXMuaXNWYWxpZEFkZHJlc3MocGFyYW1zLmJpdGdvRmVlQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBiaXRnb0ZlZUFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzKSB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHdhbGxldENvbnRyYWN0QWRkcmVzcycpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCByZWNvdmVyeURlc3RpbmF0aW9uJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0eXBlcywgdmFsdWVzLCBhbmQgdG90YWwgYW1vdW50IGluIHdlaSB0byBzZW5kIGluIGEgYmF0Y2ggdHJhbnNhY3Rpb24sIHVzaW5nIHRoZSBtZXRob2Qgc2lnbmF0dXJlXG4gICAqIGBkaXN0cmlidXRlQmF0Y2goYWRkcmVzc1tdLCB1aW50MjU2W10pYFxuICAgKiBAcGFyYW0ge1JlY2lwaWVudFtdfSByZWNpcGllbnRzIC0gdHJhbnNhY3Rpb24gcmVjaXBpZW50c1xuICAgKiBAcmV0dXJucyB7R2V0QmF0Y2hFeGVjdXRpb25JbmZvUlR9IGluZm9ybWF0aW9uIG5lZWRlZCB0byBleGVjdXRlIHRoZSBiYXRjaCB0cmFuc2FjdGlvblxuICAgKi9cbiAgZ2V0QmF0Y2hFeGVjdXRpb25JbmZvKHJlY2lwaWVudHM6IFJlY2lwaWVudFtdKTogR2V0QmF0Y2hFeGVjdXRpb25JbmZvUlQge1xuICAgIGNvbnN0IGFkZHJlc3Nlczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBhbW91bnRzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGxldCBzdW0gPSBuZXcgQmlnTnVtYmVyKCcwJyk7XG4gICAgXy5mb3JFYWNoKHJlY2lwaWVudHMsICh7IGFkZHJlc3MsIGFtb3VudCB9KSA9PiB7XG4gICAgICBhZGRyZXNzZXMucHVzaChhZGRyZXNzKTtcbiAgICAgIGFtb3VudHMucHVzaChhbW91bnQgYXMgc3RyaW5nKTtcbiAgICAgIHN1bSA9IHN1bS5wbHVzKGFtb3VudCk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdmFsdWVzOiBbYWRkcmVzc2VzLCBhbW91bnRzXSxcbiAgICAgIHRvdGFsQW1vdW50OiBzdW0udG9GaXhlZCgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBkYXRhIHJlcXVpcmVkIHRvIG1ha2UgYW4gRVRIIGZ1bmN0aW9uIGNhbGwgZGVmaW5lZCBieSB0aGUgZ2l2ZW4gdHlwZXMgYW5kIHZhbHVlc1xuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZnVuY3Rpb25OYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uIGJlaW5nIGNhbGxlZCwgZS5nLiB0cmFuc2ZlclxuICAgKiBAcGFyYW0gdHlwZXMgVGhlIHR5cGVzIG9mIHRoZSBmdW5jdGlvbiBjYWxsIGluIG9yZGVyXG4gICAqIEBwYXJhbSB2YWx1ZXMgVGhlIHZhbHVlcyBvZiB0aGUgZnVuY3Rpb24gY2FsbCBpbiBvcmRlclxuICAgKiBAcmV0dXJuIHtCdWZmZXJ9IFRoZSBjb21iaW5lZCBkYXRhIGZvciB0aGUgZnVuY3Rpb24gY2FsbFxuICAgKi9cbiAgZ2V0TWV0aG9kQ2FsbERhdGEgPSAoZnVuY3Rpb25OYW1lLCB0eXBlcywgdmFsdWVzKSA9PiB7XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW1xuICAgICAgLy8gZnVuY3Rpb24gc2lnbmF0dXJlXG4gICAgICBvcHRpb25hbERlcHMuZXRoQWJpLm1ldGhvZElEKGZ1bmN0aW9uTmFtZSwgdHlwZXMpLFxuICAgICAgLy8gZnVuY3Rpb24gYXJndW1lbnRzXG4gICAgICBvcHRpb25hbERlcHMuZXRoQWJpLnJhd0VuY29kZSh0eXBlcywgdmFsdWVzKSxcbiAgICBdKTtcbiAgfTtcblxuICAvKipcbiAgICogQnVpbGQgYXJndW1lbnRzIHRvIGNhbGwgdGhlIHNlbmQgbWV0aG9kIG9uIHRoZSB3YWxsZXQgY29udHJhY3RcbiAgICogQHBhcmFtIHR4SW5mb1xuICAgKi9cbiAgZ2V0U2VuZE1ldGhvZEFyZ3ModHhJbmZvOiBHZXRTZW5kTWV0aG9kQXJnc09wdGlvbnMpOiBTZW5kTWV0aG9kQXJnc1tdIHtcbiAgICAvLyBNZXRob2Qgc2lnbmF0dXJlIGlzXG4gICAgLy8gc2VuZE11bHRpU2lnKGFkZHJlc3MgdG9BZGRyZXNzLCB1aW50IHZhbHVlLCBieXRlcyBkYXRhLCB1aW50IGV4cGlyZVRpbWUsIHVpbnQgc2VxdWVuY2VJZCwgYnl0ZXMgc2lnbmF0dXJlKVxuICAgIHJldHVybiBbXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICd0b0FkZHJlc3MnLFxuICAgICAgICB0eXBlOiAnYWRkcmVzcycsXG4gICAgICAgIHZhbHVlOiB0eEluZm8ucmVjaXBpZW50LmFkZHJlc3MsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAndmFsdWUnLFxuICAgICAgICB0eXBlOiAndWludCcsXG4gICAgICAgIHZhbHVlOiB0eEluZm8ucmVjaXBpZW50LmFtb3VudCxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdkYXRhJyxcbiAgICAgICAgdHlwZTogJ2J5dGVzJyxcbiAgICAgICAgdmFsdWU6IG9wdGlvbmFsRGVwcy5ldGhVdGlsLnRvQnVmZmVyKG9wdGlvbmFsRGVwcy5ldGhVdGlsLmFkZEhleFByZWZpeCh0eEluZm8ucmVjaXBpZW50LmRhdGEgfHwgJycpKSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdleHBpcmVUaW1lJyxcbiAgICAgICAgdHlwZTogJ3VpbnQnLFxuICAgICAgICB2YWx1ZTogdHhJbmZvLmV4cGlyZVRpbWUsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAnc2VxdWVuY2VJZCcsXG4gICAgICAgIHR5cGU6ICd1aW50JyxcbiAgICAgICAgdmFsdWU6IHR4SW5mby5jb250cmFjdFNlcXVlbmNlSWQsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAnc2lnbmF0dXJlJyxcbiAgICAgICAgdHlwZTogJ2J5dGVzJyxcbiAgICAgICAgdmFsdWU6IG9wdGlvbmFsRGVwcy5ldGhVdGlsLnRvQnVmZmVyKG9wdGlvbmFsRGVwcy5ldGhVdGlsLmFkZEhleFByZWZpeCh0eEluZm8uc2lnbmF0dXJlKSksXG4gICAgICB9LFxuICAgIF07XG4gIH1cblxuICAvKipcbiAgICogUmVjb3ZlcnMgYSB0eCB3aXRoIFRTUyBrZXkgc2hhcmVzXG4gICAqIHNhbWUgZXhwZWN0ZWQgYXJndW1lbnRzIGFzIHJlY292ZXIgbWV0aG9kLCBidXQgd2l0aCBUU1Mga2V5IHNoYXJlc1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHJlY292ZXJUU1MoXG4gICAgcGFyYW1zOiBSZWNvdmVyT3B0aW9uc1xuICApOiBQcm9taXNlPFJlY292ZXJ5SW5mbyB8IE9mZmxpbmVWYXVsdFR4SW5mbyB8IFVuc2lnbmVkU3dlZXBUeE1QQ3YyPiB7XG4gICAgdGhpcy52YWxpZGF0ZVJlY292ZXJ5UGFyYW1zKHBhcmFtcyk7XG4gICAgLy8gQ2xlYW4gdXAgd2hpdGVzcGFjZSBmcm9tIGVudGVyZWQgdmFsdWVzXG4gICAgY29uc3QgdXNlclB1YmxpY09yUHJpdmF0ZUtleVNoYXJlID0gcGFyYW1zLnVzZXJLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSA9IHBhcmFtcy5iYWNrdXBLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcblxuICAgIGlmIChcbiAgICAgIGdldElzVW5zaWduZWRTd2VlcCh7XG4gICAgICAgIHVzZXJLZXk6IHVzZXJQdWJsaWNPclByaXZhdGVLZXlTaGFyZSxcbiAgICAgICAgYmFja3VwS2V5OiBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSxcbiAgICAgICAgaXNUc3M6IHBhcmFtcy5pc1RzcyxcbiAgICAgIH0pXG4gICAgKSB7XG4gICAgICByZXR1cm4gdGhpcy5idWlsZFVuc2lnbmVkU3dlZXBUeG5UU1MocGFyYW1zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgeyB1c2VyS2V5U2hhcmUsIGJhY2t1cEtleVNoYXJlLCBjb21tb25LZXlDaGFpbiB9ID0gYXdhaXQgRUNEU0FVdGlscy5nZXRNcGNWMlJlY292ZXJ5S2V5U2hhcmVzKFxuICAgICAgICB1c2VyUHVibGljT3JQcml2YXRlS2V5U2hhcmUsXG4gICAgICAgIGJhY2t1cFByaXZhdGVPclB1YmxpY0tleVNoYXJlLFxuICAgICAgICBwYXJhbXMud2FsbGV0UGFzc3BocmFzZVxuICAgICAgKTtcblxuICAgICAgY29uc3QgeyBnYXNMaW1pdCwgZ2FzUHJpY2UgfSA9IGF3YWl0IHRoaXMuZ2V0R2FzVmFsdWVzKHBhcmFtcyk7XG5cbiAgICAgIGNvbnN0IE1QQyA9IG5ldyBFY2RzYSgpO1xuICAgICAgY29uc3QgZGVyaXZlZENvbW1vbktleUNoYWluID0gTVBDLmRlcml2ZVVuaGFyZGVuZWQoY29tbW9uS2V5Q2hhaW4sICdtLzAnKTtcbiAgICAgIGNvbnN0IGJhY2t1cEtleVBhaXIgPSBuZXcgS2V5UGFpckxpYih7IHB1YjogZGVyaXZlZENvbW1vbktleUNoYWluLnNsaWNlKDAsIDY2KSB9KTtcbiAgICAgIGNvbnN0IGJhc2VBZGRyZXNzID0gYmFja3VwS2V5UGFpci5nZXRBZGRyZXNzKCk7XG4gICAgICBjb25zdCB1bnNpZ25lZFR4ID0gKGF3YWl0IHRoaXMuYnVpbGRUc3NSZWNvdmVyeVR4bihiYXNlQWRkcmVzcywgZ2FzUHJpY2UsIGdhc0xpbWl0LCBwYXJhbXMpKS50eDtcbiAgICAgIGNvbnN0IG1lc3NhZ2VIYXNoID0gdW5zaWduZWRUeC5nZXRNZXNzYWdlVG9TaWduKHRydWUpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gYXdhaXQgRUNEU0FVdGlscy5zaWduUmVjb3ZlcnlNcGNWMihtZXNzYWdlSGFzaCwgdXNlcktleVNoYXJlLCBiYWNrdXBLZXlTaGFyZSwgY29tbW9uS2V5Q2hhaW4pO1xuICAgICAgY29uc3QgZXRoQ29tbW1vbiA9IEFic3RyYWN0RXRoTGlrZU5ld0NvaW5zLmdldEV0aExpa2VDb21tb24ocGFyYW1zLmVpcDE1NTksIHBhcmFtcy5yZXBsYXlQcm90ZWN0aW9uT3B0aW9ucyk7XG4gICAgICBjb25zdCBzaWduZWRUeCA9IHRoaXMuZ2V0U2lnbmVkVHhGcm9tU2lnbmF0dXJlKGV0aENvbW1tb24sIHVuc2lnbmVkVHgsIHNpZ25hdHVyZSk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlkOiBhZGRIZXhQcmVmaXgoc2lnbmVkVHguaGFzaCgpLnRvU3RyaW5nKCdoZXgnKSksXG4gICAgICAgIHR4OiBhZGRIZXhQcmVmaXgoc2lnbmVkVHguc2VyaWFsaXplKCkudG9TdHJpbmcoJ2hleCcpKSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRHYXNWYWx1ZXMocGFyYW1zOiBSZWNvdmVyT3B0aW9ucyk6IFByb21pc2U8eyBnYXNMaW1pdDogbnVtYmVyOyBnYXNQcmljZTogQnVmZmVyIH0+IHtcbiAgICBjb25zdCBnYXNMaW1pdCA9IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTih0aGlzLnNldEdhc0xpbWl0KHBhcmFtcy5nYXNMaW1pdCkpO1xuICAgIGNvbnN0IGdhc1ByaWNlID0gcGFyYW1zLmVpcDE1NTlcbiAgICAgID8gbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHBhcmFtcy5laXAxNTU5Lm1heEZlZVBlckdhcylcbiAgICAgIDogbmV3IG9wdGlvbmFsRGVwcy5ldGhVdGlsLkJOKHRoaXMuc2V0R2FzUHJpY2UocGFyYW1zLmdhc1ByaWNlKSk7XG4gICAgcmV0dXJuIHsgZ2FzTGltaXQsIGdhc1ByaWNlIH07XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgYnVpbGRVbnNpZ25lZFN3ZWVwVHhuVFNTKHBhcmFtczogUmVjb3Zlck9wdGlvbnMpOiBQcm9taXNlPE9mZmxpbmVWYXVsdFR4SW5mbyB8IFVuc2lnbmVkU3dlZXBUeE1QQ3YyPiB7XG4gICAgY29uc3QgdXNlclB1YmxpY09yUHJpdmF0ZUtleVNoYXJlID0gcGFyYW1zLnVzZXJLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSA9IHBhcmFtcy5iYWNrdXBLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcblxuICAgIGNvbnN0IHsgZ2FzTGltaXQsIGdhc1ByaWNlIH0gPSBhd2FpdCB0aGlzLmdldEdhc1ZhbHVlcyhwYXJhbXMpO1xuXG4gICAgY29uc3QgYmFja3VwS2V5UGFpciA9IG5ldyBLZXlQYWlyTGliKHsgcHViOiBiYWNrdXBQcml2YXRlT3JQdWJsaWNLZXlTaGFyZSB9KTtcbiAgICBjb25zdCBiYXNlQWRkcmVzcyA9IGJhY2t1cEtleVBhaXIuZ2V0QWRkcmVzcygpO1xuICAgIGNvbnN0IHsgdHhJbmZvLCB0eCwgbm9uY2UgfSA9IGF3YWl0IHRoaXMuYnVpbGRUc3NSZWNvdmVyeVR4bihiYXNlQWRkcmVzcywgZ2FzUHJpY2UsIGdhc0xpbWl0LCBwYXJhbXMpO1xuICAgIHJldHVybiB0aGlzLmZvcm1hdEZvck9mZmxpbmVWYXVsdFRTUyhcbiAgICAgIHR4SW5mbyxcbiAgICAgIHR4LFxuICAgICAgdXNlclB1YmxpY09yUHJpdmF0ZUtleVNoYXJlLFxuICAgICAgYmFja3VwUHJpdmF0ZU9yUHVibGljS2V5U2hhcmUsXG4gICAgICBnYXNQcmljZSxcbiAgICAgIGdhc0xpbWl0LFxuICAgICAgbm9uY2UsXG4gICAgICBwYXJhbXMuZWlwMTU1OSxcbiAgICAgIHBhcmFtcy5yZXBsYXlQcm90ZWN0aW9uT3B0aW9uc1xuICAgICk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgYnVpbGRVbnNpZ25lZFN3ZWVwVHhuTVBDdjIocGFyYW1zOiBSZWNvdmVyT3B0aW9ucyk6IFByb21pc2U8VW5zaWduZWRTd2VlcFR4TVBDdjI+IHtcbiAgICBjb25zdCB7IGdhc0xpbWl0LCBnYXNQcmljZSB9ID0gYXdhaXQgdGhpcy5nZXRHYXNWYWx1ZXMocGFyYW1zKTtcblxuICAgIGNvbnN0IHJlY292ZXJQYXJhbXMgPSBwYXJhbXMgYXMgUmVjb3Zlck9wdGlvbnM7XG4gICAgdGhpcy52YWxpZGF0ZVVuc2lnbmVkU3dlZXBUU1NQYXJhbXMocmVjb3ZlclBhcmFtcyk7XG5cbiAgICBjb25zdCBkZXJpdmF0aW9uUGF0aCA9IHJlY292ZXJQYXJhbXMuZGVyaXZhdGlvblNlZWQgPyBnZXREZXJpdmF0aW9uUGF0aChyZWNvdmVyUGFyYW1zLmRlcml2YXRpb25TZWVkKSA6ICdtLzAnO1xuICAgIGNvbnN0IE1QQyA9IG5ldyBFY2RzYSgpO1xuICAgIGNvbnN0IGRlcml2ZWRDb21tb25LZXlDaGFpbiA9IE1QQy5kZXJpdmVVbmhhcmRlbmVkKHJlY292ZXJQYXJhbXMuYmFja3VwS2V5IGFzIHN0cmluZywgZGVyaXZhdGlvblBhdGgpO1xuICAgIGNvbnN0IGJhY2t1cEtleVBhaXIgPSBuZXcgS2V5UGFpckxpYih7IHB1YjogZGVyaXZlZENvbW1vbktleUNoYWluLnNsaWNlKDAsIDY2KSB9KTtcbiAgICBjb25zdCBiYXNlQWRkcmVzcyA9IGJhY2t1cEtleVBhaXIuZ2V0QWRkcmVzcygpO1xuICAgIGNvbnN0IHsgdHhJbmZvLCB0eCwgbm9uY2UgfSA9IGF3YWl0IHRoaXMuYnVpbGRUc3NSZWNvdmVyeVR4bihiYXNlQWRkcmVzcywgZ2FzUHJpY2UsIGdhc0xpbWl0LCBwYXJhbXMpO1xuICAgIHJldHVybiB0aGlzLmJ1aWxkVHhSZXF1ZXN0Rm9yT2ZmbGluZVZhdWx0TVBDdjIoXG4gICAgICB0eEluZm8sXG4gICAgICB0eCxcbiAgICAgIGRlcml2YXRpb25QYXRoLFxuICAgICAgbm9uY2UsXG4gICAgICBnYXNQcmljZSxcbiAgICAgIGdhc0xpbWl0LFxuICAgICAgcGFyYW1zLmVpcDE1NTksXG4gICAgICBwYXJhbXMucmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMsXG4gICAgICByZWNvdmVyUGFyYW1zLmJhY2t1cEtleSBhcyBzdHJpbmdcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlQnJvYWRjYXN0YWJsZVN3ZWVwVHJhbnNhY3Rpb24ocGFyYW1zOiBNUENTd2VlcFJlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8TVBDVHhzPiB7XG4gICAgY29uc3QgcmVxID0gcGFyYW1zLnNpZ25hdHVyZVNoYXJlcztcbiAgICBjb25zdCBicm9hZGNhc3RhYmxlVHJhbnNhY3Rpb25zOiBNUENUeFtdID0gW107XG4gICAgbGV0IGxhc3RTY2FuSW5kZXggPSAwO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gcmVxW2ldPy50eFJlcXVlc3Q/LnRyYW5zYWN0aW9ucz8uWzBdPy51bnNpZ25lZFR4IGFzIHVua25vd24gYXMgVW5zaWduZWRUcmFuc2FjdGlvblRzcztcbiAgICAgIGlmICghcmVxW2ldLm92YyB8fCAhcmVxW2ldLm92Y1swXS5lY2RzYVNpZ25hdHVyZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3Npbmcgc2lnbmF0dXJlKHMpJyk7XG4gICAgICB9XG4gICAgICBpZiAoIXRyYW5zYWN0aW9uLnNpZ25hYmxlSGV4KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBzaWduYWJsZSBoZXgnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IHJlcVtpXS5vdmNbMF0uZWNkc2FTaWduYXR1cmU7XG4gICAgICBpZiAoIXNpZ25hdHVyZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NpZ25hdHVyZSBpcyB1bmRlZmluZWQnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNoYXJlczogc3RyaW5nW10gPSBzaWduYXR1cmUudG9TdHJpbmcoKS5zcGxpdCgnOicpO1xuICAgICAgaWYgKHNoYXJlcy5sZW5ndGggIT09IDQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZScpO1xuICAgICAgfVxuICAgICAgY29uc3QgZmluYWxTaWduYXR1cmU6IEVDRFNBTWV0aG9kVHlwZXMuU2lnbmF0dXJlID0ge1xuICAgICAgICByZWNpZDogTnVtYmVyKHNoYXJlc1swXSksXG4gICAgICAgIHI6IHNoYXJlc1sxXSxcbiAgICAgICAgczogc2hhcmVzWzJdLFxuICAgICAgICB5OiBzaGFyZXNbM10sXG4gICAgICB9IGFzIHVua25vd24gYXMgRUNEU0FNZXRob2RUeXBlcy5TaWduYXR1cmU7XG5cbiAgICAgIGlmICghdHJhbnNhY3Rpb24uY29pblNwZWNpZmljPy5jb21tb25LZXlDaGFpbikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE1pc3NpbmcgY29tbW9uIGtleWNoYWluIGZvciB0cmFuc2FjdGlvbiBhdCBpbmRleCAke2l9YCk7XG4gICAgICB9XG4gICAgICBjb25zdCBjb21tb25LZXlDaGFpbiA9IHRyYW5zYWN0aW9uLmNvaW5TcGVjaWZpYy5jb21tb25LZXlDaGFpbjtcbiAgICAgIGlmICghdHJhbnNhY3Rpb24uZGVyaXZhdGlvblBhdGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBNaXNzaW5nIGRlcml2YXRpb24gcGF0aCBmb3IgdHJhbnNhY3Rpb24gYXQgaW5kZXggJHtpfWApO1xuICAgICAgfVxuICAgICAgaWYgKCFjb21tb25LZXlDaGFpbikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE1pc3NpbmcgY29tbW9uIGtleSBjaGFpbiBmb3IgdHJhbnNhY3Rpb24gYXQgaW5kZXggJHtpfWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBldGhDb21tbW9uID0gQWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuZ2V0RXRoTGlrZUNvbW1vbihcbiAgICAgICAgdHJhbnNhY3Rpb24uZWlwMTU1OSxcbiAgICAgICAgdHJhbnNhY3Rpb24ucmVwbGF5UHJvdGVjdGlvbk9wdGlvbnNcbiAgICAgICk7XG4gICAgICBsZXQgdW5zaWduZWRUeDogRXRoTGlrZVR4TGliLkZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbiB8IEV0aExpa2VUeExpYi5UcmFuc2FjdGlvbjtcbiAgICAgIGlmICh0cmFuc2FjdGlvbi5laXAxNTU5KSB7XG4gICAgICAgIHVuc2lnbmVkVHggPSBGZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb24uZnJvbVNlcmlhbGl6ZWRUeChCdWZmZXIuZnJvbSh0cmFuc2FjdGlvbi5zZXJpYWxpemVkVHhIZXgsICdoZXgnKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB1bnNpZ25lZFR4ID0gTGVnYWN5VHJhbnNhY3Rpb24uZnJvbVNlcmlhbGl6ZWRUeChCdWZmZXIuZnJvbSh0cmFuc2FjdGlvbi5zZXJpYWxpemVkVHhIZXgsICdoZXgnKSk7XG4gICAgICB9XG4gICAgICBjb25zdCBzaWduZWRUeCA9IHRoaXMuZ2V0U2lnbmVkVHhGcm9tU2lnbmF0dXJlKGV0aENvbW1tb24sIHVuc2lnbmVkVHgsIGZpbmFsU2lnbmF0dXJlKTtcbiAgICAgIGJyb2FkY2FzdGFibGVUcmFuc2FjdGlvbnMucHVzaCh7XG4gICAgICAgIHNlcmlhbGl6ZWRUeDogYWRkSGV4UHJlZml4KHNpZ25lZFR4LnNlcmlhbGl6ZSgpLnRvU3RyaW5nKCdoZXgnKSksXG4gICAgICB9KTtcblxuICAgICAgaWYgKGkgPT09IHJlcS5sZW5ndGggLSAxICYmIHRyYW5zYWN0aW9uLmNvaW5TcGVjaWZpYz8ubGFzdFNjYW5JbmRleCkge1xuICAgICAgICBsYXN0U2NhbkluZGV4ID0gdHJhbnNhY3Rpb24uY29pblNwZWNpZmljPy5sYXN0U2NhbkluZGV4IGFzIG51bWJlcjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4geyB0cmFuc2FjdGlvbnM6IGJyb2FkY2FzdGFibGVUcmFuc2FjdGlvbnMsIGxhc3RTY2FuSW5kZXggfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gdmFsaWRhdGUgcmVjb3ZlcnkgcGFyYW1zXG4gICAqIEBwYXJhbSB7UmVjb3Zlck9wdGlvbnN9IHBhcmFtc1xuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdmFsaWRhdGVVbnNpZ25lZFN3ZWVwVFNTUGFyYW1zKHBhcmFtczogUmVjb3Zlck9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMuYmFja3VwS2V5KSAmJiBwYXJhbXMuYmFja3VwS2V5ID09PSAnJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIGNvbW1vbktleUNoYWluJyk7XG4gICAgfVxuICAgIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMuZGVyaXZhdGlvblNlZWQpICYmIHR5cGVvZiBwYXJhbXMuZGVyaXZhdGlvblNlZWQgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgZGVyaXZhdGlvblNlZWQnKTtcbiAgICB9XG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pIHx8ICF0aGlzLmlzVmFsaWRBZGRyZXNzKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIG9yIGludmFsaWQgZGVzdGluYXRpb25BZGRyZXNzJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEhlbHBlciBmdW5jdGlvbiBmb3IgcmVjb3ZlcigpXG4gICAqIFRoaXMgdHJhbnNmb3JtcyB0aGUgdW5zaWduZWQgdHJhbnNhY3Rpb24gaW5mb3JtYXRpb24gaW50byBhIGZvcm1hdCB0aGUgQml0R28gb2ZmbGluZSB2YXVsdCBleHBlY3RzXG4gICAqIEBwYXJhbSB7VW5mb3JtYXR0ZWRUeEluZm99IHR4SW5mbyAtIHR4IGluZm9cbiAgICogQHBhcmFtIHtMZWdhY3lUcmFuc2FjdGlvbiB8IEZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbn0gZXRoVHggLSB0aGUgZXRoZXJldW1qcyB0eCBvYmplY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IGRlcml2YXRpb25QYXRoIC0gdGhlIGRlcml2YXRpb25QYXRoXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBub25jZSAtIHRoZSBub25jZSBvZiB0aGUgYmFja3VwIGtleSBhZGRyZXNzXG4gICAqIEBwYXJhbSB7QnVmZmVyfSBnYXNQcmljZSAtIGdhcyBwcmljZSBmb3IgdGhlIHR4XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBnYXNMaW1pdCAtIGdhcyBsaW1pdCBmb3IgdGhlIHR4XG4gICAqIEBwYXJhbSB7RUlQMTU1OX0gZWlwMTU1OSAtIGVpcDE1NTkgcGFyYW1zXG4gICAqIEBwYXJhbSByZXBsYXlQcm90ZWN0aW9uT3B0aW9uc1xuICAgKiBAcGFyYW0gY29tbW9uS2V5Q2hhaW5cbiAgICogQHJldHVybnMge1Byb21pc2U8T2ZmbGluZVZhdWx0VHhJbmZvPn1cbiAgICovXG4gIHByaXZhdGUgYnVpbGRUeFJlcXVlc3RGb3JPZmZsaW5lVmF1bHRNUEN2MihcbiAgICB0eEluZm86IFVuZm9ybWF0dGVkVHhJbmZvLFxuICAgIGV0aFR4OiBMZWdhY3lUcmFuc2FjdGlvbiB8IEZlZU1hcmtldEVJUDE1NTlUcmFuc2FjdGlvbixcbiAgICBkZXJpdmF0aW9uUGF0aDogc3RyaW5nLFxuICAgIG5vbmNlOiBudW1iZXIsXG4gICAgZ2FzUHJpY2U6IEJ1ZmZlcixcbiAgICBnYXNMaW1pdDogbnVtYmVyLFxuICAgIGVpcDE1NTk/OiBFSVAxNTU5LFxuICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zPzogUmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMsXG4gICAgY29tbW9uS2V5Q2hhaW4/OiBzdHJpbmdcbiAgKTogVW5zaWduZWRTd2VlcFR4TVBDdjIge1xuICAgIGlmICghZXRoVHgudG8pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRXRoIHR4IG11c3QgaGF2ZSBhIGB0b2AgYWRkcmVzcycpO1xuICAgIH1cblxuICAgIGNvbnN0IGZlZSA9IGVpcDE1NTlcbiAgICAgID8gZ2FzTGltaXQgKiBlaXAxNTU5Lm1heEZlZVBlckdhc1xuICAgICAgOiBnYXNMaW1pdCAqIG9wdGlvbmFsRGVwcy5ldGhVdGlsLmJ1ZmZlclRvSW50KGdhc1ByaWNlKS50b0ZpeGVkKCk7XG5cbiAgICBjb25zdCB1bnNpZ25lZFR4OiBVbnNpZ25lZFRyYW5zYWN0aW9uVHNzID0ge1xuICAgICAgc2VyaWFsaXplZFR4SGV4OiBldGhUeC5zZXJpYWxpemUoKS50b1N0cmluZygnaGV4JyksXG4gICAgICBzaWduYWJsZUhleDpcbiAgICAgICAgZXRoVHggaW5zdGFuY2VvZiBGZWVNYXJrZXRFSVAxNTU5VHJhbnNhY3Rpb25cbiAgICAgICAgICA/IGV0aFR4LmdldE1lc3NhZ2VUb1NpZ24oZmFsc2UpLnRvU3RyaW5nKCdoZXgnKVxuICAgICAgICAgIDogQnVmZmVyLmZyb20oUkxQLmVuY29kZShidWZBcnJUb0FycihldGhUeC5nZXRNZXNzYWdlVG9TaWduKGZhbHNlKSkpKS50b1N0cmluZygnaGV4JyksXG4gICAgICBkZXJpdmF0aW9uUGF0aDogZGVyaXZhdGlvblBhdGgsXG4gICAgICBmZWVJbmZvOiB7XG4gICAgICAgIGZlZTogZmVlLFxuICAgICAgICBmZWVTdHJpbmc6IGZlZS50b1N0cmluZygpLFxuICAgICAgfSxcbiAgICAgIHBhcnNlZFR4OiB7XG4gICAgICAgIHNwZW5kQW1vdW50OiB0eEluZm8ucmVjaXBpZW50LmFtb3VudCxcbiAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNvaW5OYW1lOiB0aGlzLmdldENoYWluKCksXG4gICAgICAgICAgICBhZGRyZXNzOiB0eEluZm8ucmVjaXBpZW50LmFkZHJlc3MsXG4gICAgICAgICAgICB2YWx1ZVN0cmluZzogdHhJbmZvLnJlY2lwaWVudC5hbW91bnQsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgICBjb2luU3BlY2lmaWM6IHtcbiAgICAgICAgY29tbW9uS2V5Q2hhaW46IGNvbW1vbktleUNoYWluLFxuICAgICAgfSxcbiAgICAgIGVpcDE1NTk6IGVpcDE1NTksXG4gICAgICByZXBsYXlQcm90ZWN0aW9uT3B0aW9uczogcmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMsXG4gICAgfTtcblxuICAgIHJldHVybiB7XG4gICAgICB0eFJlcXVlc3RzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICB3YWxsZXRDb2luOiB0aGlzLmdldENoYWluKCksXG4gICAgICAgICAgdHJhbnNhY3Rpb25zOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHVuc2lnbmVkVHg6IHVuc2lnbmVkVHgsXG4gICAgICAgICAgICAgIG5vbmNlOiBub25jZSxcbiAgICAgICAgICAgICAgc2lnbmF0dXJlU2hhcmVzOiBbXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgYnVpbGRUc3NSZWNvdmVyeVR4bihiYXNlQWRkcmVzczogc3RyaW5nLCBnYXNQcmljZTogYW55LCBnYXNMaW1pdDogYW55LCBwYXJhbXM6IFJlY292ZXJPcHRpb25zKSB7XG4gICAgY29uc3QgdHhBbW91bnQgPSBhd2FpdCB0aGlzLnZhbGlkYXRlQmFsYW5jZUFuZEdldFR4QW1vdW50KGJhc2VBZGRyZXNzLCBnYXNQcmljZSwgZ2FzTGltaXQsIHBhcmFtcy5hcGlLZXkpO1xuICAgIGNvbnN0IG5vbmNlID0gYXdhaXQgdGhpcy5nZXRBZGRyZXNzTm9uY2UoYmFzZUFkZHJlc3MsIHBhcmFtcy5hcGlLZXkpO1xuICAgIGNvbnN0IHJlY2lwaWVudHMgPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgICBhbW91bnQ6IHR4QW1vdW50LnRvU3RyaW5nKDEwKSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIGNvbnN0IHR4SW5mbyA9IHtcbiAgICAgIHJlY2lwaWVudDogcmVjaXBpZW50c1swXSxcbiAgICAgIGV4cGlyZVRpbWU6IHRoaXMuZ2V0RGVmYXVsdEV4cGlyZVRpbWUoKSxcbiAgICAgIGdhc0xpbWl0OiBnYXNMaW1pdC50b1N0cmluZygxMCksXG4gICAgfTtcblxuICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgdG86IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgbm9uY2U6IG5vbmNlLFxuICAgICAgdmFsdWU6IHR4QW1vdW50LFxuICAgICAgZ2FzUHJpY2U6IGdhc1ByaWNlLFxuICAgICAgZ2FzTGltaXQ6IGdhc0xpbWl0LFxuICAgICAgZGF0YTogQnVmZmVyLmZyb20oJzB4JyksXG4gICAgICBlaXAxNTU5OiBwYXJhbXMuZWlwMTU1OSxcbiAgICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zOiBwYXJhbXMucmVwbGF5UHJvdGVjdGlvbk9wdGlvbnMsXG4gICAgfTtcblxuICAgIGNvbnN0IHR4ID0gQWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuYnVpbGRUcmFuc2FjdGlvbih0eFBhcmFtcyk7XG4gICAgcmV0dXJuIHsgdHhJbmZvLCB0eCwgbm9uY2UgfTtcbiAgfVxuXG4gIGFzeW5jIHZhbGlkYXRlQmFsYW5jZUFuZEdldFR4QW1vdW50KGJhc2VBZGRyZXNzOiBzdHJpbmcsIGdhc1ByaWNlOiBCTiwgZ2FzTGltaXQ6IEJOLCBhcGlLZXk/OiBzdHJpbmcpIHtcbiAgICBjb25zdCBiYXNlQWRkcmVzc0JhbGFuY2UgPSBhd2FpdCB0aGlzLnF1ZXJ5QWRkcmVzc0JhbGFuY2UoYmFzZUFkZHJlc3MsIGFwaUtleSk7XG4gICAgY29uc3QgdG90YWxHYXNOZWVkZWQgPSBnYXNQcmljZS5tdWwoZ2FzTGltaXQpO1xuICAgIGNvbnN0IHdlaVRvR3dlaSA9IG5ldyBCTigxMCAqKiA5KTtcbiAgICBpZiAoYmFzZUFkZHJlc3NCYWxhbmNlLmx0KHRvdGFsR2FzTmVlZGVkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgQmFja3VwIGtleSBhZGRyZXNzICR7YmFzZUFkZHJlc3N9IGhhcyBiYWxhbmNlICR7YmFzZUFkZHJlc3NCYWxhbmNlLmRpdih3ZWlUb0d3ZWkpLnRvU3RyaW5nKCl9IEd3ZWkuYCArXG4gICAgICAgICAgYFRoaXMgYWRkcmVzcyBtdXN0IGhhdmUgYSBiYWxhbmNlIG9mIGF0IGxlYXN0ICR7dG90YWxHYXNOZWVkZWQuZGl2KHdlaVRvR3dlaSkudG9TdHJpbmcoKX1gICtcbiAgICAgICAgICBgIEd3ZWkgdG8gcGVyZm9ybSByZWNvdmVyaWVzLiBUcnkgc2VuZGluZyBzb21lIEVUSCB0byB0aGlzIGFkZHJlc3MgdGhlbiByZXRyeS5gXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCB0eEFtb3VudCA9IGJhc2VBZGRyZXNzQmFsYW5jZS5zdWIodG90YWxHYXNOZWVkZWQpO1xuICAgIHJldHVybiB0eEFtb3VudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYWtlIGEgcXVlcnkgdG8gYmxvY2tjaGFpbiBleHBsb3JlciBmb3IgaW5mb3JtYXRpb24gc3VjaCBhcyBiYWxhbmNlLCB0b2tlbiBiYWxhbmNlLCBzb2xpZGl0eSBjYWxsc1xuICAgKiBAcGFyYW0gcXVlcnkge09iamVjdH0ga2V5LXZhbHVlIHBhaXJzIG9mIHBhcmFtZXRlcnMgdG8gYXBwZW5kIGFmdGVyIC9hcGlcbiAgICogQHBhcmFtIGFwaUtleSB7c3RyaW5nfSBvcHRpb25hbCBBUEkga2V5IHRvIHVzZSBpbnN0ZWFkIG9mIHRoZSBvbmUgZnJvbSB0aGUgZW52aXJvbm1lbnRcbiAgICogQHJldHVybnMge09iamVjdH0gcmVzcG9uc2UgZnJvbSB0aGUgYmxvY2tjaGFpbiBleHBsb3JlclxuICAgKi9cbiAgYXN5bmMgcmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeShxdWVyeTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiwgYXBpS2V5Pzogc3RyaW5nKTogUHJvbWlzZTxhbnk+IHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ21ldGhvZCBub3QgaW1wbGVtZW50ZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIHRoZSBleHRyYSBwYXJhbWV0ZXJzIG5lZWRlZCB0byBidWlsZCBhIGhvcCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0gYnVpbGRQYXJhbXMgVGhlIG9yaWdpbmFsIGJ1aWxkIHBhcmFtZXRlcnNcbiAgICogQHJldHVybnMgZXh0cmEgcGFyYW1ldGVycyBvYmplY3QgdG8gbWVyZ2Ugd2l0aCB0aGUgb3JpZ2luYWwgYnVpbGQgcGFyYW1ldGVycyBvYmplY3QgYW5kIHNlbmQgdG8gdGhlIHBsYXRmb3JtXG4gICAqL1xuICBhc3luYyBjcmVhdGVIb3BUcmFuc2FjdGlvblBhcmFtcyhidWlsZFBhcmFtczogSG9wVHJhbnNhY3Rpb25CdWlsZE9wdGlvbnMpOiBQcm9taXNlPEhvcFBhcmFtcz4ge1xuICAgIGNvbnN0IHdhbGxldCA9IGJ1aWxkUGFyYW1zLndhbGxldDtcbiAgICBjb25zdCByZWNpcGllbnRzID0gYnVpbGRQYXJhbXMucmVjaXBpZW50cztcbiAgICBjb25zdCB3YWxsZXRQYXNzcGhyYXNlID0gYnVpbGRQYXJhbXMud2FsbGV0UGFzc3BocmFzZTtcblxuICAgIGNvbnN0IHVzZXJLZXljaGFpbiA9IGF3YWl0IHRoaXMua2V5Y2hhaW5zKCkuZ2V0KHsgaWQ6IHdhbGxldC5rZXlJZHMoKVswXSB9KTtcbiAgICBjb25zdCB1c2VyUHJ2ID0gd2FsbGV0LmdldFVzZXJQcnYoeyBrZXljaGFpbjogdXNlcktleWNoYWluLCB3YWxsZXRQYXNzcGhyYXNlIH0pO1xuICAgIGNvbnN0IHVzZXJQcnZCdWZmZXIgPSBiaXAzMi5mcm9tQmFzZTU4KHVzZXJQcnYpLnByaXZhdGVLZXk7XG4gICAgaWYgKCF1c2VyUHJ2QnVmZmVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgdXNlclBydicpO1xuICAgIH1cbiAgICBpZiAoIXJlY2lwaWVudHMgfHwgIUFycmF5LmlzQXJyYXkocmVjaXBpZW50cykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0aW5nIGFycmF5IG9mIHJlY2lwaWVudHMnKTtcbiAgICB9XG5cbiAgICAvLyBSaWdodCBub3cgd2Ugb25seSBzdXBwb3J0IDEgcmVjaXBpZW50XG4gICAgaWYgKHJlY2lwaWVudHMubGVuZ3RoICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ211c3Qgc2VuZCB0byBleGFjdGx5IDEgcmVjaXBpZW50Jyk7XG4gICAgfVxuICAgIGNvbnN0IHJlY2lwaWVudEFkZHJlc3MgPSByZWNpcGllbnRzWzBdLmFkZHJlc3M7XG4gICAgY29uc3QgcmVjaXBpZW50QW1vdW50ID0gcmVjaXBpZW50c1swXS5hbW91bnQgYXMgc3RyaW5nO1xuICAgIGNvbnN0IGZlZUVzdGltYXRlUGFyYW1zID0ge1xuICAgICAgcmVjaXBpZW50OiByZWNpcGllbnRBZGRyZXNzLFxuICAgICAgYW1vdW50OiByZWNpcGllbnRBbW91bnQsXG4gICAgICBob3A6IHRydWUsXG4gICAgfTtcbiAgICBjb25zdCBmZWVFc3RpbWF0ZTogRmVlRXN0aW1hdGUgPSBhd2FpdCB0aGlzLmZlZUVzdGltYXRlKGZlZUVzdGltYXRlUGFyYW1zKTtcblxuICAgIGNvbnN0IGdhc0xpbWl0ID0gZmVlRXN0aW1hdGUuZ2FzTGltaXRFc3RpbWF0ZTtcbiAgICBjb25zdCBnYXNQcmljZSA9IE1hdGgucm91bmQoZmVlRXN0aW1hdGUuZmVlRXN0aW1hdGUgLyBnYXNMaW1pdCk7XG4gICAgY29uc3QgZ2FzUHJpY2VNYXggPSBnYXNQcmljZSAqIDU7XG4gICAgLy8gUGF5bWVudCBpZCBhIHJhbmRvbSBudW1iZXIgc28gaXRzIGRpZmZlcmVudCBmb3IgZXZlcnkgdHhcbiAgICBjb25zdCBwYXltZW50SWQgPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAxMDAwMDAwMDAwMCkudG9TdHJpbmcoKTtcbiAgICBjb25zdCBob3BEaWdlc3Q6IEJ1ZmZlciA9IEFic3RyYWN0RXRoTGlrZU5ld0NvaW5zLmdldEhvcERpZ2VzdChbXG4gICAgICByZWNpcGllbnRBZGRyZXNzLFxuICAgICAgcmVjaXBpZW50QW1vdW50LFxuICAgICAgZ2FzUHJpY2VNYXgudG9TdHJpbmcoKSxcbiAgICAgIGdhc0xpbWl0LnRvU3RyaW5nKCksXG4gICAgICBwYXltZW50SWQsXG4gICAgXSk7XG5cbiAgICBjb25zdCB1c2VyUmVxU2lnID0gb3B0aW9uYWxEZXBzLmV0aFV0aWwuYWRkSGV4UHJlZml4KFxuICAgICAgQnVmZmVyLmZyb20oc2VjcDI1NmsxLmVjZHNhU2lnbihob3BEaWdlc3QsIHVzZXJQcnZCdWZmZXIpLnNpZ25hdHVyZSkudG9TdHJpbmcoJ2hleCcpXG4gICAgKTtcblxuICAgIHJldHVybiB7XG4gICAgICBob3BQYXJhbXM6IHtcbiAgICAgICAgZ2FzUHJpY2VNYXgsXG4gICAgICAgIHVzZXJSZXFTaWcsXG4gICAgICAgIHBheW1lbnRJZCxcbiAgICAgICAgZ2FzTGltaXQsXG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoYXQgdGhlIGhvcCBwcmVidWlsZCBmcm9tIHRoZSBIU00gaXMgdmFsaWQgYW5kIGNvcnJlY3RcbiAgICogQHBhcmFtIHtJV2FsbGV0fSB3YWxsZXQgLSBUaGUgd2FsbGV0IHRoYXQgdGhlIHByZWJ1aWxkIGlzIGZvclxuICAgKiBAcGFyYW0ge0hvcFByZWJ1aWxkfSBob3BQcmVidWlsZCAtIFRoZSBwcmVidWlsZCB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0ge09iamVjdH0gb3JpZ2luYWxQYXJhbXMgLSBUaGUgb3JpZ2luYWwgcGFyYW1ldGVycyBwYXNzZWQgdG8gcHJlYnVpbGRUcmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1JlY2lwaWVudFtdfSBvcmlnaW5hbFBhcmFtcy5yZWNpcGllbnRzIC0gVGhlIG9yaWdpbmFsIHJlY2lwaWVudHMgYXJyYXlcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgVGhlIHByZWJ1aWxkIGlzIGludmFsaWRcbiAgICovXG4gIGFzeW5jIHZhbGlkYXRlSG9wUHJlYnVpbGQoXG4gICAgd2FsbGV0OiBJV2FsbGV0LFxuICAgIGhvcFByZWJ1aWxkOiBIb3BQcmVidWlsZCxcbiAgICBvcmlnaW5hbFBhcmFtcz86IHsgcmVjaXBpZW50czogUmVjaXBpZW50W10gfVxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IHR4LCBpZCwgc2lnbmF0dXJlIH0gPSBob3BQcmVidWlsZDtcblxuICAgIC8vIGZpcnN0LCB2YWxpZGF0ZSB0aGUgSFNNIHNpZ25hdHVyZVxuICAgIGNvbnN0IHNlcnZlclhwdWIgPSBjb21tb24uRW52aXJvbm1lbnRzW3RoaXMuYml0Z28uZ2V0RW52KCldLmhzbVhwdWI7XG4gICAgY29uc3Qgc2VydmVyUHVia2V5QnVmZmVyOiBCdWZmZXIgPSBiaXAzMi5mcm9tQmFzZTU4KHNlcnZlclhwdWIpLnB1YmxpY0tleTtcbiAgICBjb25zdCBzaWduYXR1cmVCdWZmZXI6IEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKG9wdGlvbmFsRGVwcy5ldGhVdGlsLnN0cmlwSGV4UHJlZml4KHNpZ25hdHVyZSksICdoZXgnKTtcbiAgICBjb25zdCBtZXNzYWdlQnVmZmVyOiBCdWZmZXIgPSBCdWZmZXIuZnJvbShcbiAgICAgIG9wdGlvbmFsRGVwcy5ldGhVdGlsLnBhZFRvRXZlbihvcHRpb25hbERlcHMuZXRoVXRpbC5zdHJpcEhleFByZWZpeChpZCkpLFxuICAgICAgJ2hleCdcbiAgICApO1xuXG4gICAgY29uc3Qgc2lnID0gbmV3IFVpbnQ4QXJyYXkoc2lnbmF0dXJlQnVmZmVyLnNsaWNlKDEpKTtcbiAgICBjb25zdCBpc1ZhbGlkU2lnbmF0dXJlOiBib29sZWFuID0gc2VjcDI1NmsxLmVjZHNhVmVyaWZ5KHNpZywgbWVzc2FnZUJ1ZmZlciwgc2VydmVyUHVia2V5QnVmZmVyKTtcbiAgICBpZiAoIWlzVmFsaWRTaWduYXR1cmUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEhvcCB0eGlkIHNpZ25hdHVyZSBpbnZhbGlkIC0gcHViOiAke3NlcnZlclhwdWJ9LCBtc2c6ICR7bWVzc2FnZUJ1ZmZlcj8udG9TdHJpbmcoKX0sIHNpZzogJHtzaWduYXR1cmVCdWZmZXI/LnRvU3RyaW5nKCl9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBidWlsdEhvcFR4ID0gb3B0aW9uYWxEZXBzLkV0aFR4LlRyYW5zYWN0aW9uRmFjdG9yeS5mcm9tU2VyaWFsaXplZERhdGEob3B0aW9uYWxEZXBzLmV0aFV0aWwudG9CdWZmZXIodHgpKTtcbiAgICAvLyBJZiBvcmlnaW5hbCBwYXJhbXMgYXJlIGdpdmVuLCB3ZSBjYW4gY2hlY2sgdGhlbSBhZ2FpbnN0IHRoZSB0cmFuc2FjdGlvbiBwcmVidWlsZCBwYXJhbXNcbiAgICBpZiAoIV8uaXNOaWwob3JpZ2luYWxQYXJhbXMpKSB7XG4gICAgICBjb25zdCB7IHJlY2lwaWVudHMgfSA9IG9yaWdpbmFsUGFyYW1zO1xuXG4gICAgICAvLyBUaGVuIHZhbGlkYXRlIHRoYXQgdGhlIHR4IHBhcmFtcyBhY3R1YWxseSBlcXVhbCB0aGUgcmVxdWVzdGVkIHBhcmFtc1xuICAgICAgY29uc3Qgb3JpZ2luYWxBbW91bnQgPSBuZXcgQmlnTnVtYmVyKHJlY2lwaWVudHNbMF0uYW1vdW50KTtcbiAgICAgIGNvbnN0IG9yaWdpbmFsRGVzdGluYXRpb246IHN0cmluZyA9IHJlY2lwaWVudHNbMF0uYWRkcmVzcztcblxuICAgICAgY29uc3QgaG9wQW1vdW50ID0gbmV3IEJpZ051bWJlcihvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleChidWlsdEhvcFR4LnZhbHVlKSk7XG4gICAgICBpZiAoIWJ1aWx0SG9wVHgudG8pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUcmFuc2FjdGlvbiBkb2VzIG5vdCBoYXZlIGEgZGVzdGluYXRpb24gYWRkcmVzc2ApO1xuICAgICAgfVxuICAgICAgY29uc3QgaG9wRGVzdGluYXRpb24gPSBidWlsdEhvcFR4LnRvLnRvU3RyaW5nKCk7XG4gICAgICBpZiAoIWhvcEFtb3VudC5lcShvcmlnaW5hbEFtb3VudCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBIb3AgYW1vdW50OiAke2hvcEFtb3VudH0gZG9lcyBub3QgZXF1YWwgb3JpZ2luYWwgYW1vdW50OiAke29yaWdpbmFsQW1vdW50fWApO1xuICAgICAgfVxuICAgICAgaWYgKGhvcERlc3RpbmF0aW9uLnRvTG93ZXJDYXNlKCkgIT09IG9yaWdpbmFsRGVzdGluYXRpb24udG9Mb3dlckNhc2UoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhvcCBkZXN0aW5hdGlvbjogJHtob3BEZXN0aW5hdGlvbn0gZG9lcyBub3QgZXF1YWwgb3JpZ2luYWwgcmVjaXBpZW50OiAke2hvcERlc3RpbmF0aW9ufWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghYnVpbHRIb3BUeC52ZXJpZnlTaWduYXR1cmUoKSkge1xuICAgICAgLy8gV2UgZG9udCB3YW50IHRvIGNvbnRpbnVlIGF0IGFsbCBpbiB0aGlzIGNhc2UsIGF0IHJpc2sgb2YgRVRIIGJlaW5nIHN0dWNrIG9uIHRoZSBob3AgYWRkcmVzc1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGhvcCB0cmFuc2FjdGlvbiBzaWduYXR1cmUsIHR4aWQ6ICR7aWR9YCk7XG4gICAgfVxuICAgIGlmIChvcHRpb25hbERlcHMuZXRoVXRpbC5hZGRIZXhQcmVmaXgoYnVpbHRIb3BUeC5oYXNoKCkudG9TdHJpbmcoJ2hleCcpKSAhPT0gaWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgU2lnbmVkIGhvcCB0eGlkIGRvZXMgbm90IGVxdWFsIGFjdHVhbCB0eGlkYCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGhvcCBkaWdlc3QgZm9yIHRoZSB1c2VyIHRvIHNpZ24uIFRoaXMgaXMgdmFsaWRhdGVkIGluIHRoZSBIU00gdG8gcHJvdmUgdGhhdCB0aGUgdXNlciByZXF1ZXN0ZWQgdGhpcyB0eFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBwYXJhbXNBcnIgLSBUaGUgcGFyYW1ldGVycyB0byBoYXNoIHRvZ2V0aGVyIGZvciB0aGUgZGlnZXN0XG4gICAqIEByZXR1cm5zIHtCdWZmZXJ9XG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldEhvcERpZ2VzdChwYXJhbXNBcnI6IHN0cmluZ1tdKTogQnVmZmVyIHtcbiAgICBjb25zdCBoYXNoID0gS2VjY2FrKCdrZWNjYWsyNTYnKTtcbiAgICBoYXNoLnVwZGF0ZShbQWJzdHJhY3RFdGhMaWtlTmV3Q29pbnMuaG9wVHJhbnNhY3Rpb25TYWx0LCAuLi5wYXJhbXNBcnJdLmpvaW4oJyQnKSk7XG4gICAgcmV0dXJuIGhhc2guZGlnZXN0KCk7XG4gIH1cblxuICAvKipcbiAgICogTW9kaWZ5IHByZWJ1aWxkIGJlZm9yZSBzZW5kaW5nIGl0IHRvIHRoZSBzZXJ2ZXIuIEFkZCB0aGluZ3MgbGlrZSBob3AgdHJhbnNhY3Rpb24gcGFyYW1zXG4gICAqIEBwYXJhbSB7QnVpbGRPcHRpb25zfSBidWlsZFBhcmFtcyAtIFRoZSB3aGl0ZWxpc3RlZCBwYXJhbWV0ZXJzIGZvciB0aGlzIHByZWJ1aWxkXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYnVpbGRQYXJhbXMuaG9wIC0gVHJ1ZSBpZiB0aGlzIHNob3VsZCBwcmVidWlsZCBhIGhvcCB0eCwgZWxzZSBmYWxzZVxuICAgKiBAcGFyYW0ge1JlY2lwaWVudFtdfSBidWlsZFBhcmFtcy5yZWNpcGllbnRzIC0gVGhlIHJlY2lwaWVudHMgYXJyYXkgb2YgdGhpcyB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1dhbGxldH0gYnVpbGRQYXJhbXMud2FsbGV0IC0gVGhlIHdhbGxldCBzZW5kaW5nIHRoaXMgdHhcbiAgICogQHBhcmFtIHtzdHJpbmd9IGJ1aWxkUGFyYW1zLndhbGxldFBhc3NwaHJhc2UgLSB0aGUgcGFzc3BocmFzZSBmb3IgdGhpcyB3YWxsZXRcbiAgICogQHJldHVybnMge1Byb21pc2U8QnVpbGRPcHRpb25zPn1cbiAgICovXG4gIGFzeW5jIGdldEV4dHJhUHJlYnVpbGRQYXJhbXMoYnVpbGRQYXJhbXM6IEJ1aWxkT3B0aW9ucyk6IFByb21pc2U8QnVpbGRPcHRpb25zPiB7XG4gICAgaWYgKFxuICAgICAgIV8uaXNVbmRlZmluZWQoYnVpbGRQYXJhbXMuaG9wKSAmJlxuICAgICAgYnVpbGRQYXJhbXMuaG9wICYmXG4gICAgICAhXy5pc1VuZGVmaW5lZChidWlsZFBhcmFtcy53YWxsZXQpICYmXG4gICAgICAhXy5pc1VuZGVmaW5lZChidWlsZFBhcmFtcy5yZWNpcGllbnRzKSAmJlxuICAgICAgIV8uaXNVbmRlZmluZWQoYnVpbGRQYXJhbXMud2FsbGV0UGFzc3BocmFzZSlcbiAgICApIHtcbiAgICAgIGlmICh0aGlzIGluc3RhbmNlb2YgRXRoTGlrZVRva2VuKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgSG9wIHRyYW5zYWN0aW9ucyBhcmUgbm90IGVuYWJsZWQgZm9yIEVSQy0yMCB0b2tlbnMsIG5vciBhcmUgdGhleSBuZWNlc3NhcnkuIFBsZWFzZSByZW1vdmUgdGhlICdob3AnIHBhcmFtZXRlciBhbmQgdHJ5IGFnYWluLmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiAoYXdhaXQgdGhpcy5jcmVhdGVIb3BUcmFuc2FjdGlvblBhcmFtcyh7XG4gICAgICAgIHdhbGxldDogYnVpbGRQYXJhbXMud2FsbGV0LFxuICAgICAgICByZWNpcGllbnRzOiBidWlsZFBhcmFtcy5yZWNpcGllbnRzLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBidWlsZFBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgfSkpIGFzIGFueTtcbiAgICB9XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgLyoqXG4gICAqIE1vZGlmeSBwcmVidWlsZCBhZnRlciByZWNlaXZpbmcgaXQgZnJvbSB0aGUgc2VydmVyLiBBZGQgdGhpbmdzIGxpa2UgbmxvY2t0aW1lXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb25QcmVidWlsZH0gcGFyYW1zIC0gVGhlIHByZWJ1aWxkIHRvIG1vZGlmeVxuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25QcmVidWlsZH0gVGhlIG1vZGlmaWVkIHByZWJ1aWxkXG4gICAqL1xuICBhc3luYyBwb3N0UHJvY2Vzc1ByZWJ1aWxkKHBhcmFtczogVHJhbnNhY3Rpb25QcmVidWlsZCk6IFByb21pc2U8VHJhbnNhY3Rpb25QcmVidWlsZD4ge1xuICAgIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMuaG9wVHJhbnNhY3Rpb24pICYmICFfLmlzVW5kZWZpbmVkKHBhcmFtcy53YWxsZXQpICYmICFfLmlzVW5kZWZpbmVkKHBhcmFtcy5idWlsZFBhcmFtcykpIHtcbiAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVIb3BQcmVidWlsZChwYXJhbXMud2FsbGV0LCBwYXJhbXMuaG9wVHJhbnNhY3Rpb24sIHBhcmFtcy5idWlsZFBhcmFtcyk7XG4gICAgfVxuICAgIHJldHVybiBwYXJhbXM7XG4gIH1cblxuICAvKipcbiAgICogQ29pbi1zcGVjaWZpYyB0aGluZ3MgZG9uZSBiZWZvcmUgc2lnbmluZyBhIHRyYW5zYWN0aW9uLCBpLmUuIHZlcmlmaWNhdGlvblxuICAgKiBAcGFyYW0ge1ByZXNpZ25UcmFuc2FjdGlvbk9wdGlvbnN9IHBhcmFtc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxQcmVzaWduVHJhbnNhY3Rpb25PcHRpb25zPn1cbiAgICovXG4gIGFzeW5jIHByZXNpZ25UcmFuc2FjdGlvbihwYXJhbXM6IFByZXNpZ25UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPFByZXNpZ25UcmFuc2FjdGlvbk9wdGlvbnM+IHtcbiAgICBpZiAoIV8uaXNVbmRlZmluZWQocGFyYW1zLmhvcFRyYW5zYWN0aW9uKSAmJiAhXy5pc1VuZGVmaW5lZChwYXJhbXMud2FsbGV0KSAmJiAhXy5pc1VuZGVmaW5lZChwYXJhbXMuYnVpbGRQYXJhbXMpKSB7XG4gICAgICBhd2FpdCB0aGlzLnZhbGlkYXRlSG9wUHJlYnVpbGQocGFyYW1zLndhbGxldCwgcGFyYW1zLmhvcFRyYW5zYWN0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcmFtcztcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaCBmZWUgZXN0aW1hdGUgaW5mb3JtYXRpb24gZnJvbSB0aGUgc2VydmVyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXMgLSBUaGUgcGFyYW1zIHBhc3NlZCBpbnRvIHRoZSBmdW5jdGlvblxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtwYXJhbXMuaG9wXSAtIFRydWUgaWYgd2Ugc2hvdWxkIGVzdGltYXRlIGZlZSBmb3IgYSBob3AgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtwYXJhbXMucmVjaXBpZW50XSAtIFRoZSByZWNpcGllbnQgb2YgdGhlIHRyYW5zYWN0aW9uIHRvIGVzdGltYXRlIGEgc2VuZCB0b1xuICAgKiBAcGFyYW0ge3N0cmluZ30gW3BhcmFtcy5kYXRhXSAtIFRoZSBFVEggdHggZGF0YSB0byBlc3RpbWF0ZSBhIHNlbmQgZm9yXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBmZWUgaW5mbyByZXR1cm5lZCBmcm9tIHRoZSBzZXJ2ZXJcbiAgICovXG4gIGFzeW5jIGZlZUVzdGltYXRlKHBhcmFtczogRmVlRXN0aW1hdGVPcHRpb25zKTogUHJvbWlzZTxGZWVFc3RpbWF0ZT4ge1xuICAgIGNvbnN0IHF1ZXJ5OiBGZWVFc3RpbWF0ZU9wdGlvbnMgPSB7fTtcbiAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5ob3ApIHtcbiAgICAgIHF1ZXJ5LmhvcCA9IHBhcmFtcy5ob3A7XG4gICAgfVxuICAgIGlmIChwYXJhbXMgJiYgcGFyYW1zLnJlY2lwaWVudCkge1xuICAgICAgcXVlcnkucmVjaXBpZW50ID0gcGFyYW1zLnJlY2lwaWVudDtcbiAgICB9XG4gICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuZGF0YSkge1xuICAgICAgcXVlcnkuZGF0YSA9IHBhcmFtcy5kYXRhO1xuICAgIH1cbiAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5hbW91bnQpIHtcbiAgICAgIHF1ZXJ5LmFtb3VudCA9IHBhcmFtcy5hbW91bnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuYml0Z28uZ2V0KHRoaXMudXJsKCcvdHgvZmVlJykpLnF1ZXJ5KHF1ZXJ5KS5yZXN1bHQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBzZWNwMjU2azEga2V5IHBhaXJcbiAgICpcbiAgICogQHBhcmFtIHtCdWZmZXJ9IHNlZWRcbiAgICogQHJldHVybnMge0tleVBhaXJ9IG9iamVjdCB3aXRoIGdlbmVyYXRlZCBwdWIgYW5kIHBydlxuICAgKi9cbiAgZ2VuZXJhdGVLZXlQYWlyKHNlZWQ6IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIGlmICghc2VlZCkge1xuICAgICAgLy8gQW4gZXh0ZW5kZWQgcHJpdmF0ZSBrZXkgaGFzIGJvdGggYSBub3JtYWwgMjU2IGJpdCBwcml2YXRlIGtleSBhbmQgYSAyNTZcbiAgICAgIC8vIGJpdCBjaGFpbiBjb2RlLCBib3RoIG9mIHdoaWNoIG11c3QgYmUgcmFuZG9tLiA1MTIgYml0cyBpcyB0aGVyZWZvcmUgdGhlXG4gICAgICAvLyBtYXhpbXVtIGVudHJvcHkgYW5kIGdpdmVzIHVzIG1heGltdW0gc2VjdXJpdHkgYWdhaW5zdCBjcmFja2luZy5cbiAgICAgIHNlZWQgPSByYW5kb21CeXRlcyg1MTIgLyA4KTtcbiAgICB9XG4gICAgY29uc3QgZXh0ZW5kZWRLZXkgPSBiaXAzMi5mcm9tU2VlZChzZWVkKTtcbiAgICBjb25zdCB4cHViID0gZXh0ZW5kZWRLZXkubmV1dGVyZWQoKS50b0Jhc2U1OCgpO1xuICAgIHJldHVybiB7XG4gICAgICBwdWI6IHhwdWIsXG4gICAgICBwcnY6IGV4dGVuZGVkS2V5LnRvQmFzZTU4KCksXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIHBhcnNlVHJhbnNhY3Rpb24ocGFyYW1zOiBQYXJzZVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8UGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICAvKipcbiAgICogR2V0IGZvcndhcmRlciBmYWN0b3J5IGFuZCBpbXBsZW1lbnRhdGlvbiBhZGRyZXNzZXMgZm9yIGRlcG9zaXQgYWRkcmVzcyB2ZXJpZmljYXRpb24uXG4gICAqIEZvcndhcmRlcnMgYXJlIHNtYXJ0IGNvbnRyYWN0cyB0aGF0IGZvcndhcmQgZnVuZHMgdG8gdGhlIGJhc2Ugd2FsbGV0IGFkZHJlc3MuXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyIHwgdW5kZWZpbmVkfSBmb3J3YXJkZXJWZXJzaW9uIC0gVGhlIHdhbGxldCB2ZXJzaW9uXG4gICAqIEByZXR1cm5zIHtvYmplY3R9IEZhY3RvcnkgYW5kIGltcGxlbWVudGF0aW9uIGFkZHJlc3NlcyBmb3IgZm9yd2FyZGVyc1xuICAgKi9cbiAgZ2V0Rm9yd2FyZGVyRmFjdG9yeUFkZHJlc3Nlc0FuZEZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcyhmb3J3YXJkZXJWZXJzaW9uOiBudW1iZXIgfCB1bmRlZmluZWQpOiB7XG4gICAgZm9yd2FyZGVyRmFjdG9yeUFkZHJlc3M6IHN0cmluZztcbiAgICBmb3J3YXJkZXJJbXBsZW1lbnRhdGlvbkFkZHJlc3M6IHN0cmluZztcbiAgfSB7XG4gICAgY29uc3QgZXRoTmV0d29yayA9IHRoaXMuZ2V0TmV0d29yaygpO1xuXG4gICAgc3dpdGNoIChmb3J3YXJkZXJWZXJzaW9uKSB7XG4gICAgICBjYXNlIDE6XG4gICAgICAgIGlmICghZXRoTmV0d29yaz8uZm9yd2FyZGVyRmFjdG9yeUFkZHJlc3MgfHwgIWV0aE5ldHdvcms/LmZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRm9yd2FyZGVyIGZhY3RvcnkgYWRkcmVzc2VzIG5vdCBjb25maWd1cmVkIGZvciB0aGlzIG5ldHdvcmsnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGZvcndhcmRlckZhY3RvcnlBZGRyZXNzOiBldGhOZXR3b3JrLmZvcndhcmRlckZhY3RvcnlBZGRyZXNzLFxuICAgICAgICAgIGZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzczogZXRoTmV0d29yay5mb3J3YXJkZXJJbXBsZW1lbnRhdGlvbkFkZHJlc3MsXG4gICAgICAgIH07XG4gICAgICBjYXNlIDI6XG4gICAgICAgIGlmICghZXRoTmV0d29yaz8ud2FsbGV0VjJGb3J3YXJkZXJGYWN0b3J5QWRkcmVzcyB8fCAhZXRoTmV0d29yaz8ud2FsbGV0VjJGb3J3YXJkZXJJbXBsZW1lbnRhdGlvbkFkZHJlc3MpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1dhbGxldCB2MiBmYWN0b3J5IGFkZHJlc3NlcyBub3QgY29uZmlndXJlZCBmb3IgdGhpcyBuZXR3b3JrJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBmb3J3YXJkZXJGYWN0b3J5QWRkcmVzczogZXRoTmV0d29yay53YWxsZXRWMkZvcndhcmRlckZhY3RvcnlBZGRyZXNzLFxuICAgICAgICAgIGZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzczogZXRoTmV0d29yay53YWxsZXRWMkZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcyxcbiAgICAgICAgfTtcbiAgICAgIGNhc2UgNDpcbiAgICAgIGNhc2UgNTpcbiAgICAgICAgaWYgKCFldGhOZXR3b3JrPy53YWxsZXRWNEZvcndhcmRlckZhY3RvcnlBZGRyZXNzIHx8ICFldGhOZXR3b3JrPy53YWxsZXRWNEZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRm9yd2FyZGVyIHYke2ZvcndhcmRlclZlcnNpb259IGZhY3RvcnkgYWRkcmVzc2VzIG5vdCBjb25maWd1cmVkIGZvciB0aGlzIG5ldHdvcmtgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGZvcndhcmRlckZhY3RvcnlBZGRyZXNzOiBldGhOZXR3b3JrLndhbGxldFY0Rm9yd2FyZGVyRmFjdG9yeUFkZHJlc3MsXG4gICAgICAgICAgZm9yd2FyZGVySW1wbGVtZW50YXRpb25BZGRyZXNzOiBldGhOZXR3b3JrLndhbGxldFY0Rm9yd2FyZGVySW1wbGVtZW50YXRpb25BZGRyZXNzLFxuICAgICAgICB9O1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBGb3J3YXJkZXIgdmVyc2lvbiAke2ZvcndhcmRlclZlcnNpb259IG5vdCBzdXBwb3J0ZWRgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHdhbGxldCBiYXNlIGFkZHJlc3MgZmFjdG9yeSBhbmQgaW1wbGVtZW50YXRpb24gYWRkcmVzc2VzLlxuICAgKiBUaGlzIGlzIHVzZWQgZm9yIGJhc2UgYWRkcmVzcyB2ZXJpZmljYXRpb24gZm9yIFYxLCBWMiwgVjQsIGFuZCBWNSB3YWxsZXRzLlxuICAgKiBUaGUgYmFzZSBhZGRyZXNzIGlzIHRoZSBtYWluIHdhbGxldCBjb250cmFjdCBkZXBsb3llZCB2aWEgQ1JFQVRFMi5cbiAgICpcbiAgICogQHBhcmFtIHtudW1iZXJ9IHdhbGxldFZlcnNpb24gLSBUaGUgd2FsbGV0IHZlcnNpb24gKDEsIDIsIDQsIG9yIDUpXG4gICAqIEByZXR1cm5zIHtvYmplY3R9IEZhY3RvcnkgYW5kIGltcGxlbWVudGF0aW9uIGFkZHJlc3NlcyBmb3IgdGhlIHdhbGxldCBiYXNlIGFkZHJlc3NcbiAgICogQHRocm93cyB7RXJyb3J9IGlmIHdhbGxldCB2ZXJzaW9uIGFkZHJlc3NlcyBhcmUgbm90IGNvbmZpZ3VyZWRcbiAgICovXG4gIGdldFdhbGxldEFkZHJlc3NGYWN0b3J5QWRkcmVzc2VzQW5kSW1wbGVtZW50YXRpb25BZGRyZXNzKHdhbGxldFZlcnNpb246IG51bWJlcik6IHtcbiAgICB3YWxsZXRGYWN0b3J5QWRkcmVzczogc3RyaW5nO1xuICAgIHdhbGxldEltcGxlbWVudGF0aW9uQWRkcmVzczogc3RyaW5nO1xuICB9IHtcbiAgICBjb25zdCBldGhOZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKCk7XG5cbiAgICBzd2l0Y2ggKHdhbGxldFZlcnNpb24pIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgaWYgKCFldGhOZXR3b3JrPy53YWxsZXRGYWN0b3J5QWRkcmVzcyB8fCAhZXRoTmV0d29yaz8ud2FsbGV0SW1wbGVtZW50YXRpb25BZGRyZXNzKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdXYWxsZXQgdjEgZmFjdG9yeSBhZGRyZXNzZXMgbm90IGNvbmZpZ3VyZWQgZm9yIHRoaXMgbmV0d29yaycpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgd2FsbGV0RmFjdG9yeUFkZHJlc3M6IGV0aE5ldHdvcmsud2FsbGV0RmFjdG9yeUFkZHJlc3MsXG4gICAgICAgICAgd2FsbGV0SW1wbGVtZW50YXRpb25BZGRyZXNzOiBldGhOZXR3b3JrLndhbGxldEltcGxlbWVudGF0aW9uQWRkcmVzcyxcbiAgICAgICAgfTtcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgaWYgKCFldGhOZXR3b3JrPy53YWxsZXRWMkZhY3RvcnlBZGRyZXNzIHx8ICFldGhOZXR3b3JrPy53YWxsZXRWMkltcGxlbWVudGF0aW9uQWRkcmVzcykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignV2FsbGV0IHYyIGZhY3RvcnkgYWRkcmVzc2VzIG5vdCBjb25maWd1cmVkIGZvciB0aGlzIG5ldHdvcmsnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHdhbGxldEZhY3RvcnlBZGRyZXNzOiBldGhOZXR3b3JrLndhbGxldFYyRmFjdG9yeUFkZHJlc3MsXG4gICAgICAgICAgd2FsbGV0SW1wbGVtZW50YXRpb25BZGRyZXNzOiBldGhOZXR3b3JrLndhbGxldFYySW1wbGVtZW50YXRpb25BZGRyZXNzLFxuICAgICAgICB9O1xuICAgICAgY2FzZSA0OlxuICAgICAgY2FzZSA1OlxuICAgICAgICBpZiAoIWV0aE5ldHdvcms/LndhbGxldFY0Rm9yd2FyZGVyRmFjdG9yeUFkZHJlc3MgfHwgIWV0aE5ldHdvcms/LndhbGxldFY0Rm9yd2FyZGVySW1wbGVtZW50YXRpb25BZGRyZXNzKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBXYWxsZXQgdiR7d2FsbGV0VmVyc2lvbn0gZmFjdG9yeSBhZGRyZXNzZXMgbm90IGNvbmZpZ3VyZWQgZm9yIHRoaXMgbmV0d29ya2ApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgd2FsbGV0RmFjdG9yeUFkZHJlc3M6IGV0aE5ldHdvcmsud2FsbGV0VjRGb3J3YXJkZXJGYWN0b3J5QWRkcmVzcyxcbiAgICAgICAgICB3YWxsZXRJbXBsZW1lbnRhdGlvbkFkZHJlc3M6IGV0aE5ldHdvcmsud2FsbGV0VjRGb3J3YXJkZXJJbXBsZW1lbnRhdGlvbkFkZHJlc3MsXG4gICAgICAgIH07XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFdhbGxldCB2ZXJzaW9uICR7d2FsbGV0VmVyc2lvbn0gbm90IHN1cHBvcnRlZGApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgbWV0aG9kIHRvIGNyZWF0ZSBhIHNhbHQgYnVmZmVyIGZyb20gaGV4IHN0cmluZy5cbiAgICogQ29udmVydHMgYSBoZXggc2FsdCBzdHJpbmcgdG8gYSAzMi1ieXRlIGJ1ZmZlci5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNhbHQgLSBUaGUgaGV4IHNhbHQgc3RyaW5nXG4gICAqIEByZXR1cm5zIHtCdWZmZXJ9IDMyLWJ5dGUgc2FsdCBidWZmZXJcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlU2FsdEJ1ZmZlcihzYWx0OiBzdHJpbmcpOiBCdWZmZXIge1xuICAgIGNvbnN0IGV0aFV0aWwgPSBvcHRpb25hbERlcHMuZXRoVXRpbDtcbiAgICByZXR1cm4gZXRoVXRpbC5zZXRMZW5ndGhMZWZ0KEJ1ZmZlci5mcm9tKGV0aFV0aWwucGFkVG9FdmVuKGV0aFV0aWwuc3RyaXBIZXhQcmVmaXgoc2FsdCB8fCAnJykpLCAnaGV4JyksIDMyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgQklQMzIgd2FsbGV0IGJhc2UgYWRkcmVzcyAoVjEsIFYyLCBWNCkuXG4gICAqIFRoZXNlIHdhbGxldHMgdXNlIGEgd2FsbGV0IGZhY3RvcnkgdG8gZGVwbG95IGJhc2UgYWRkcmVzc2VzIHdpdGggQ1JFQVRFMi5cbiAgICogVGhlIGFkZHJlc3MgaXMgZGVyaXZlZCBmcm9tIHRoZSBrZXljaGFpbnMnIGV0aEFkZHJlc3NlcyBhbmQgYSBzYWx0LlxuICAgKlxuICAgKiBAcGFyYW0ge1ZlcmlmeUJpcDMyQmFzZUFkZHJlc3NPcHRpb25zfSBwYXJhbXMgLSBWZXJpZmljYXRpb24gcGFyYW1ldGVyc1xuICAgKiBAcmV0dXJucyB7b2JqZWN0fSBFeHBlY3RlZCBhbmQgYWN0dWFsIGFkZHJlc3NlcyBmb3IgY29tcGFyaXNvblxuICAgKi9cbiAgcHJpdmF0ZSB2ZXJpZnlDcmVhdGUyQmFzZUFkZHJlc3MocGFyYW1zOiBWZXJpZnlDb250cmFjdEJhc2VBZGRyZXNzT3B0aW9ucyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHsgYWRkcmVzcywgY29pblNwZWNpZmljLCBrZXljaGFpbnMsIHdhbGxldFZlcnNpb24gfSA9IHBhcmFtcztcblxuICAgIGlmICghY29pblNwZWNpZmljLnNhbHQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgbWlzc2luZyBzYWx0IGZvciB2JHt3YWxsZXRWZXJzaW9ufSBiYXNlIGFkZHJlc3MgdmVyaWZpY2F0aW9uYCk7XG4gICAgfVxuXG4gICAgLy8gR2V0IHdhbGxldCBmYWN0b3J5IGFuZCBpbXBsZW1lbnRhdGlvbiBhZGRyZXNzZXMgZm9yIHRoZSB3YWxsZXQgdmVyc2lvblxuICAgIGNvbnN0IHsgd2FsbGV0RmFjdG9yeUFkZHJlc3MsIHdhbGxldEltcGxlbWVudGF0aW9uQWRkcmVzcyB9ID1cbiAgICAgIHRoaXMuZ2V0V2FsbGV0QWRkcmVzc0ZhY3RvcnlBZGRyZXNzZXNBbmRJbXBsZW1lbnRhdGlvbkFkZHJlc3Mod2FsbGV0VmVyc2lvbik7XG4gICAgY29uc3QgaW5pdGNvZGUgPSBnZXRQcm94eUluaXRjb2RlKHdhbGxldEltcGxlbWVudGF0aW9uQWRkcmVzcyk7XG5cbiAgICAvLyBDb252ZXJ0IHRoZSB3YWxsZXQgc2FsdCB0byBhIGJ1ZmZlciwgcGFkIHRvIDMyIGJ5dGVzXG4gICAgY29uc3Qgc2FsdEJ1ZmZlciA9IHRoaXMuY3JlYXRlU2FsdEJ1ZmZlcihjb2luU3BlY2lmaWMuc2FsdCk7XG5cbiAgICAvLyBSZWNvbnN0cnVjdCBjYWxjdWxhdGlvblNhbHQgdXNpbmcga2V5Y2hhaW5zJyBldGhBZGRyZXNzZXMgYW5kIHdhbGxldCBzYWx0XG4gICAgY29uc3QgZXRoQWRkcmVzc2VzID0ga2V5Y2hhaW5zLm1hcCgoa2MpID0+IHtcbiAgICAgIGlmICgha2MuZXRoQWRkcmVzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGtleWNoYWluIG1pc3NpbmcgZXRoQWRkcmVzcyBmb3IgdiR7d2FsbGV0VmVyc2lvbn0gYmFzZSBhZGRyZXNzIHZlcmlmaWNhdGlvbmApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGtjLmV0aEFkZHJlc3M7XG4gICAgfSk7XG5cbiAgICBjb25zdCBjYWxjdWxhdGlvblNhbHQgPSBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleChcbiAgICAgIG9wdGlvbmFsRGVwcy5ldGhBYmkuc29saWRpdHlTSEEzKFsnYWRkcmVzc1tdJywgJ2J5dGVzMzInXSwgW2V0aEFkZHJlc3Nlcywgc2FsdEJ1ZmZlcl0pXG4gICAgKTtcblxuICAgIGNvbnN0IGV4cGVjdGVkQWRkcmVzcyA9IGNhbGN1bGF0ZUZvcndhcmRlclYxQWRkcmVzcyh3YWxsZXRGYWN0b3J5QWRkcmVzcywgY2FsY3VsYXRpb25TYWx0LCBpbml0Y29kZSk7XG5cbiAgICBpZiAoZXhwZWN0ZWRBZGRyZXNzICE9PSBhZGRyZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgVW5leHBlY3RlZEFkZHJlc3NFcnJvcihgYWRkcmVzcyB2YWxpZGF0aW9uIGZhaWx1cmU6IGV4cGVjdGVkICR7ZXhwZWN0ZWRBZGRyZXNzfSBidXQgZ290ICR7YWRkcmVzc31gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgZm9yd2FyZGVyIHJlY2VpdmUgYWRkcmVzcyAoZGVwb3NpdCBhZGRyZXNzKS5cbiAgICogRm9yd2FyZGVyIGFkZHJlc3NlcyBhcmUgZGVyaXZlZCB1c2luZyBDUkVBVEUyIGZyb20gdGhlIGJhc2UgYWRkcmVzcyBhbmQgc2FsdC5cbiAgICpcbiAgICogQHBhcmFtIHtWZXJpZnlFdGhBZGRyZXNzT3B0aW9uc30gcGFyYW1zIC0gVmVyaWZpY2F0aW9uIHBhcmFtZXRlcnNcbiAgICogQHBhcmFtIHtudW1iZXJ9IGZvcndhcmRlclZlcnNpb24gLSBUaGUgZm9yd2FyZGVyIHZlcnNpb25cbiAgICogQHJldHVybnMge29iamVjdH0gRXhwZWN0ZWQgYW5kIGFjdHVhbCBhZGRyZXNzZXMgZm9yIGNvbXBhcmlzb25cbiAgICovXG4gIHByaXZhdGUgdmVyaWZ5Rm9yd2FyZGVyQWRkcmVzcyhwYXJhbXM6IFZlcmlmeUV0aEFkZHJlc3NPcHRpb25zLCBmb3J3YXJkZXJWZXJzaW9uOiBudW1iZXIpOiBib29sZWFuIHtcbiAgICBjb25zdCB7IGFkZHJlc3MsIGNvaW5TcGVjaWZpYywgYmFzZUFkZHJlc3MgfSA9IHBhcmFtcztcblxuICAgIGNvbnN0IHsgZm9yd2FyZGVyRmFjdG9yeUFkZHJlc3MsIGZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcyB9ID1cbiAgICAgIHRoaXMuZ2V0Rm9yd2FyZGVyRmFjdG9yeUFkZHJlc3Nlc0FuZEZvcndhcmRlckltcGxlbWVudGF0aW9uQWRkcmVzcyhmb3J3YXJkZXJWZXJzaW9uKTtcbiAgICBjb25zdCBpbml0Y29kZSA9IGdldFByb3h5SW5pdGNvZGUoZm9yd2FyZGVySW1wbGVtZW50YXRpb25BZGRyZXNzKTtcbiAgICBjb25zdCBzYWx0QnVmZmVyID0gdGhpcy5jcmVhdGVTYWx0QnVmZmVyKGNvaW5TcGVjaWZpYy5zYWx0IHx8ICcnKTtcblxuICAgIGNvbnN0IHsgY3JlYXRlRm9yd2FyZGVyUGFyYW1zLCBjcmVhdGVGb3J3YXJkZXJUeXBlcyB9ID1cbiAgICAgIGZvcndhcmRlclZlcnNpb24gPT09IDRcbiAgICAgICAgPyBnZXRDcmVhdGVGb3J3YXJkZXJQYXJhbXNBbmRUeXBlcyhiYXNlQWRkcmVzcywgc2FsdEJ1ZmZlciwgY29pblNwZWNpZmljLmZlZUFkZHJlc3MpXG4gICAgICAgIDogZ2V0Q3JlYXRlRm9yd2FyZGVyUGFyYW1zQW5kVHlwZXMoYmFzZUFkZHJlc3MsIHNhbHRCdWZmZXIpO1xuXG4gICAgY29uc3QgY2FsY3VsYXRpb25TYWx0ID0gb3B0aW9uYWxEZXBzLmV0aFV0aWwuYnVmZmVyVG9IZXgoXG4gICAgICBvcHRpb25hbERlcHMuZXRoQWJpLnNvbGlkaXR5U0hBMyhjcmVhdGVGb3J3YXJkZXJUeXBlcywgY3JlYXRlRm9yd2FyZGVyUGFyYW1zKVxuICAgICk7XG5cbiAgICBjb25zdCBleHBlY3RlZEFkZHJlc3MgPSBjYWxjdWxhdGVGb3J3YXJkZXJWMUFkZHJlc3MoZm9yd2FyZGVyRmFjdG9yeUFkZHJlc3MsIGNhbGN1bGF0aW9uU2FsdCwgaW5pdGNvZGUpO1xuXG4gICAgaWYgKGV4cGVjdGVkQWRkcmVzcyAhPT0gYWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IFVuZXhwZWN0ZWRBZGRyZXNzRXJyb3IoYGFkZHJlc3MgdmFsaWRhdGlvbiBmYWlsdXJlOiBleHBlY3RlZCAke2V4cGVjdGVkQWRkcmVzc30gYnV0IGdvdCAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogTWFrZSBzdXJlIGFuIGFkZHJlc3MgaXMgYSB3YWxsZXQgYWRkcmVzcyBhbmQgdGhyb3cgYW4gZXJyb3IgaWYgaXQncyBub3QuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5hZGRyZXNzIC0gVGhlIGRlcml2ZWQgYWRkcmVzcyBzdHJpbmcgb24gdGhlIG5ldHdvcmtcbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcy5jb2luU3BlY2lmaWMgLSBDb2luLXNwZWNpZmljIGRldGFpbHMgZm9yIHRoZSBhZGRyZXNzIHN1Y2ggYXMgYSBmb3J3YXJkZXJWZXJzaW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuYmFzZUFkZHJlc3MgLSBUaGUgYmFzZSBhZGRyZXNzIG9mIHRoZSB3YWxsZXQgb24gdGhlIG5ldHdvcmtcbiAgICogQHRocm93cyB7SW52YWxpZEFkZHJlc3NFcnJvcn1cbiAgICogQHRocm93cyB7SW52YWxpZEFkZHJlc3NWZXJpZmljYXRpb25PYmplY3RQcm9wZXJ0eUVycm9yfVxuICAgKiBAdGhyb3dzIHtVbmV4cGVjdGVkQWRkcmVzc0Vycm9yfVxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZmYgYWRkcmVzcyBpcyBhIHdhbGxldCBhZGRyZXNzXG4gICAqL1xuICBhc3luYyBpc1dhbGxldEFkZHJlc3MocGFyYW1zOiBWZXJpZnlFdGhBZGRyZXNzT3B0aW9ucyB8IFRzc1ZlcmlmeUV0aEFkZHJlc3NPcHRpb25zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyBhZGRyZXNzLCBpbXBsaWVkRm9yd2FyZGVyVmVyc2lvbiwgY29pblNwZWNpZmljLCBiYXNlQWRkcmVzcyB9ID0gcGFyYW1zO1xuICAgIGNvbnN0IGZvcndhcmRlclZlcnNpb24gPSBpbXBsaWVkRm9yd2FyZGVyVmVyc2lvbiA/PyBjb2luU3BlY2lmaWM/LmZvcndhcmRlclZlcnNpb247XG5cbiAgICAvLyBWYWxpZGF0ZSBhZGRyZXNzIGZvcm1hdFxuICAgIGlmIChhZGRyZXNzICYmICF0aGlzLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgLy8gRm9yd2FyZGVyIHZlcnNpb24gMCBhZGRyZXNzZXMgY2Fubm90IGJlIHZlcmlmaWVkIGJlY2F1c2Ugd2UgZG8gbm90IHN0b3JlIHRoZSBub25jZSB2YWx1ZSByZXF1aXJlZCBmb3IgYWRkcmVzcyBkZXJpdmF0aW9uLlxuICAgIGlmIChmb3J3YXJkZXJWZXJzaW9uID09PSAwKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBEZXRlcm1pbmUgaWYgd2UgYXJlIHZlcmlmeWluZyBhIGJhc2UgYWRkcmVzc1xuICAgIGNvbnN0IGlzVmVyaWZ5aW5nQmFzZUFkZHJlc3MgPSBiYXNlQWRkcmVzcyAmJiBhZGRyZXNzID09PSBiYXNlQWRkcmVzcztcblxuICAgIC8vIFRTUy9NUEMgd2FsbGV0IGFkZHJlc3MgdmVyaWZpY2F0aW9uIChWMywgVjUsIFY2KVxuICAgIC8vIFY1IGJhc2UgYWRkcmVzc2VzIHVzZSBUU1MsIGJ1dCBWNSBmb3J3YXJkZXJzIHVzZSB0aGUgcmVndWxhciBmb3J3YXJkZXIgdmVyaWZpY2F0aW9uXG4gICAgY29uc3QgaXNUc3NXYWxsZXRWZXJzaW9uID0gcGFyYW1zLndhbGxldFZlcnNpb24gPT09IDMgfHwgcGFyYW1zLndhbGxldFZlcnNpb24gPT09IDUgfHwgcGFyYW1zLndhbGxldFZlcnNpb24gPT09IDY7XG4gICAgY29uc3Qgc2hvdWxkVXNlVHNzVmVyaWZpY2F0aW9uID1cbiAgICAgIGlzVHNzVmVyaWZ5QWRkcmVzc09wdGlvbnMocGFyYW1zKSAmJiBpc1Rzc1dhbGxldFZlcnNpb24gJiYgKHBhcmFtcy53YWxsZXRWZXJzaW9uICE9PSA1IHx8IGlzVmVyaWZ5aW5nQmFzZUFkZHJlc3MpO1xuXG4gICAgaWYgKHNob3VsZFVzZVRzc1ZlcmlmaWNhdGlvbikge1xuICAgICAgaWYgKGlzVmVyaWZ5aW5nQmFzZUFkZHJlc3MpIHtcbiAgICAgICAgY29uc3QgaW5kZXggPSB0eXBlb2YgcGFyYW1zLmluZGV4ID09PSAnc3RyaW5nJyA/IHBhcnNlSW50KHBhcmFtcy5pbmRleCwgMTApIDogcGFyYW1zLmluZGV4O1xuICAgICAgICBpZiAoaW5kZXggIT09IDApIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgQmFzZSBhZGRyZXNzIHZlcmlmaWNhdGlvbiByZXF1aXJlcyBpbmRleCAwLCBidXQgZ290IGluZGV4ICR7cGFyYW1zLmluZGV4fS4gYCArXG4gICAgICAgICAgICAgIGBUaGUgYmFzZSBhZGRyZXNzIGlzIGFsd2F5cyBkZXJpdmVkIGF0IGluZGV4IDAuYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHZlcmlmeU1QQ1dhbGxldEFkZHJlc3MoeyAuLi5wYXJhbXMsIGtleUN1cnZlOiAnc2VjcDI1NmsxJyB9LCB0aGlzLmlzVmFsaWRBZGRyZXNzLCAocHViS2V5KSA9PiB7XG4gICAgICAgIHJldHVybiBuZXcgS2V5UGFpckxpYih7IHB1YjogcHViS2V5IH0pLmdldEFkZHJlc3MoKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEZyb20gaGVyZSBvbiwgd2UgbmVlZCBiYXNlQWRkcmVzcyBhbmQgY29pblNwZWNpZmljIGZvciBub24tVFNTIHZlcmlmaWNhdGlvbnNcbiAgICBpZiAoXy5pc1VuZGVmaW5lZChiYXNlQWRkcmVzcykgfHwgIXRoaXMuaXNWYWxpZEFkZHJlc3MoYmFzZUFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcignaW52YWxpZCBiYXNlIGFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoIV8uaXNPYmplY3QoY29pblNwZWNpZmljKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzVmVyaWZpY2F0aW9uT2JqZWN0UHJvcGVydHlFcnJvcihcbiAgICAgICAgJ2FkZHJlc3MgdmFsaWRhdGlvbiBmYWlsdXJlOiBjb2luU3BlY2lmaWMgZmllbGQgbXVzdCBiZSBhbiBvYmplY3QnXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEJJUDMyIHdhbGxldCBiYXNlIGFkZHJlc3MgdmVyaWZpY2F0aW9uIChWMSwgVjIsIFY0KVxuICAgIGlmIChpc1ZlcmlmeWluZ0Jhc2VBZGRyZXNzICYmIGlzVmVyaWZ5Q29udHJhY3RCYXNlQWRkcmVzc09wdGlvbnMocGFyYW1zKSkge1xuICAgICAgcmV0dXJuIHRoaXMudmVyaWZ5Q3JlYXRlMkJhc2VBZGRyZXNzKHBhcmFtcyk7XG4gICAgfVxuXG4gICAgLy8gRm9yd2FyZGVyIHJlY2VpdmUgYWRkcmVzcyB2ZXJpZmljYXRpb24gKGRlcG9zaXQgYWRkcmVzc2VzKVxuICAgIGlmICghaXNWZXJpZnlpbmdCYXNlQWRkcmVzcykge1xuICAgICAgcmV0dXJuIHRoaXMudmVyaWZ5Rm9yd2FyZGVyQWRkcmVzcyhwYXJhbXMsIGZvcndhcmRlclZlcnNpb24pO1xuICAgIH1cblxuICAgIC8vIElmIHdlIHJlYWNoIGhlcmUsIGl0J3MgYSBiYXNlIGFkZHJlc3MgdmVyaWZpY2F0aW9uIGZvciBhbiB1bnN1cHBvcnRlZCB3YWxsZXQgdmVyc2lvblxuICAgIHRocm93IG5ldyBFcnJvcihgQmFzZSBhZGRyZXNzIHZlcmlmaWNhdGlvbiBub3Qgc3VwcG9ydGVkIGZvciB3YWxsZXQgdmVyc2lvbiAke3BhcmFtcy53YWxsZXRWZXJzaW9ufWApO1xuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb25QcmVidWlsZH0gdHhQcmVidWlsZFxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAgICovXG4gIHZlcmlmeUNvaW4odHhQcmVidWlsZDogVHJhbnNhY3Rpb25QcmVidWlsZCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IG5hdGl2ZUNvaW4gPSB0aGlzLmdldENoYWluKCkuc3BsaXQoJzonKVswXTtcbiAgICByZXR1cm4gdHhQcmVidWlsZC5jb2luID09PSBuYXRpdmVDb2luO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIHRyYW5zYWN0aW9uIGV4cGxhbmF0aW9uIGZvciBlcnJvciByZXBvcnRpbmdcbiAgICogQHBhcmFtIHR4UHJlYnVpbGQgLSBUcmFuc2FjdGlvbiBwcmVidWlsZCBjb250YWluaW5nIHR4SGV4IGFuZCBmZWUgaW5mb1xuICAgKiBAcmV0dXJucyBTdHJpbmdpZmllZCBKU09OIGV4cGxhbmF0aW9uXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGdldFR4RXhwbGFuYXRpb24odHhQcmVidWlsZD86IFRyYW5zYWN0aW9uUHJlYnVpbGQpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICAgIGlmICghdHhQcmVidWlsZD8udHhIZXggfHwgIXR4UHJlYnVpbGQ/Lmdhc1ByaWNlKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBleHBsYW5hdGlvbiA9IGF3YWl0IHRoaXMuZXhwbGFpblRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhIZXg6IHR4UHJlYnVpbGQudHhIZXgsXG4gICAgICAgIGZlZUluZm86IHtcbiAgICAgICAgICBmZWU6IHR4UHJlYnVpbGQuZ2FzUHJpY2UudG9TdHJpbmcoKSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGV4cGxhbmF0aW9uLCBudWxsLCAyKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zdCBlcnJvckRldGFpbHMgPSB7XG4gICAgICAgIGVycm9yOiAnRmFpbGVkIHRvIHBhcnNlIHRyYW5zYWN0aW9uIGV4cGxhbmF0aW9uJyxcbiAgICAgICAgdHhIZXg6IHR4UHJlYnVpbGQudHhIZXgsXG4gICAgICAgIGRldGFpbHM6IGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6IFN0cmluZyhlKSxcbiAgICAgIH07XG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoZXJyb3JEZXRhaWxzLCBudWxsLCAyKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IGlmIGEgdHNzIHRyYW5zYWN0aW9uIGlzIHZhbGlkXG4gICAqXG4gICAqIEBwYXJhbSB7VmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zfSBwYXJhbXNcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvblBhcmFtc30gcGFyYW1zLnR4UGFyYW1zIC0gcGFyYW1zIG9iamVjdCBwYXNzZWQgdG8gc2VuZFxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uUHJlYnVpbGR9IHBhcmFtcy50eFByZWJ1aWxkIC0gcHJlYnVpbGQgb2JqZWN0IHJldHVybmVkIGJ5IHNlcnZlclxuICAgKiBAcGFyYW0ge1dhbGxldH0gcGFyYW1zLndhbGxldCAtIFdhbGxldCBvYmplY3QgdG8gb2J0YWluIGtleXMgdG8gdmVyaWZ5IGFnYWluc3RcbiAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAqIEB0aHJvd3Mge1R4SW50ZW50TWlzbWF0Y2hSZWNpcGllbnRFcnJvcn0gaWYgdHJhbnNhY3Rpb24gcmVjaXBpZW50cyBkb24ndCBtYXRjaCB1c2VyIGludGVudFxuICAgKi9cbiAgYXN5bmMgdmVyaWZ5VHNzVHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQgfSA9IHBhcmFtcztcblxuICAgIC8vIEhlbHBlciB0byB0aHJvdyBUeEludGVudE1pc21hdGNoUmVjaXBpZW50RXJyb3Igd2l0aCByZWNpcGllbnQgZGV0YWlsc1xuICAgIGNvbnN0IHRocm93UmVjaXBpZW50TWlzbWF0Y2ggPSBhc3luYyAobWVzc2FnZTogc3RyaW5nLCBtaXNtYXRjaGVkUmVjaXBpZW50czogUmVjaXBpZW50W10pOiBQcm9taXNlPG5ldmVyPiA9PiB7XG4gICAgICBjb25zdCB0eEV4cGxhbmF0aW9uID0gYXdhaXQgdGhpcy5nZXRUeEV4cGxhbmF0aW9uKHR4UHJlYnVpbGQpO1xuICAgICAgdGhyb3cgbmV3IFR4SW50ZW50TWlzbWF0Y2hSZWNpcGllbnRFcnJvcihcbiAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICBbdHhQYXJhbXNdLFxuICAgICAgICB0eFByZWJ1aWxkPy50eEhleCxcbiAgICAgICAgbWlzbWF0Y2hlZFJlY2lwaWVudHMsXG4gICAgICAgIHR4RXhwbGFuYXRpb25cbiAgICAgICk7XG4gICAgfTtcblxuICAgIGlmIChcbiAgICAgICF0eFBhcmFtcz8ucmVjaXBpZW50cyAmJlxuICAgICAgIShcbiAgICAgICAgdHhQYXJhbXMucHJlYnVpbGRUeD8uY29uc29saWRhdGVJZCB8fFxuICAgICAgICB0eFByZWJ1aWxkPy5jb25zb2xpZGF0ZUlkIHx8XG4gICAgICAgICh0eFBhcmFtcy50eXBlICYmXG4gICAgICAgICAgWydhY2NlbGVyYXRpb24nLCAnZmlsbE5vbmNlJywgJ3RyYW5zZmVyVG9rZW4nLCAndG9rZW5BcHByb3ZhbCcsICdjb25zb2xpZGF0ZSddLmluY2x1ZGVzKHR4UGFyYW1zLnR5cGUpKVxuICAgICAgKVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHR4UGFyYW1zJyk7XG4gICAgfVxuICAgIGlmICghd2FsbGV0IHx8ICF0eFByZWJ1aWxkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcGFyYW1zJyk7XG4gICAgfVxuICAgIGlmICh0eFBhcmFtcy5ob3AgJiYgdHhQYXJhbXMucmVjaXBpZW50cyAmJiB0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndHggY2Fubm90IGJlIGJvdGggYSBiYXRjaCBhbmQgaG9wIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuXG4gICAgaWYgKHR4UGFyYW1zLnR5cGUgJiYgWyd0cmFuc2ZlciddLmluY2x1ZGVzKHR4UGFyYW1zLnR5cGUpKSB7XG4gICAgICBpZiAodHhQYXJhbXMucmVjaXBpZW50cyAmJiB0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBjb25zdCByZWNpcGllbnRzID0gdHhQYXJhbXMucmVjaXBpZW50cztcbiAgICAgICAgY29uc3QgZXhwZWN0ZWRBbW91bnQgPSByZWNpcGllbnRzWzBdLmFtb3VudC50b1N0cmluZygpO1xuICAgICAgICBjb25zdCBleHBlY3RlZERlc3RpbmF0aW9uID0gcmVjaXBpZW50c1swXS5hZGRyZXNzO1xuXG4gICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgICAgIHR4QnVpbGRlci5mcm9tKHR4UHJlYnVpbGQudHhIZXgpO1xuICAgICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgICBjb25zdCB0eEpzb24gPSB0eC50b0pzb24oKTtcbiAgICAgICAgaWYgKHR4SnNvbi5kYXRhID09PSAnMHgnKSB7XG4gICAgICAgICAgaWYgKGV4cGVjdGVkQW1vdW50ICE9PSB0eEpzb24udmFsdWUpIHtcbiAgICAgICAgICAgIGF3YWl0IHRocm93UmVjaXBpZW50TWlzbWF0Y2goXG4gICAgICAgICAgICAgICd0aGUgdHJhbnNhY3Rpb24gYW1vdW50IGluIHR4UHJlYnVpbGQgZG9lcyBub3QgbWF0Y2ggdGhlIHZhbHVlIGdpdmVuIGJ5IGNsaWVudCcsXG4gICAgICAgICAgICAgIFt7IGFkZHJlc3M6IHR4SnNvbi50bywgYW1vdW50OiB0eEpzb24udmFsdWUgfV1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChleHBlY3RlZERlc3RpbmF0aW9uLnRvTG93ZXJDYXNlKCkgIT09IHR4SnNvbi50by50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aHJvd1JlY2lwaWVudE1pc21hdGNoKCdkZXN0aW5hdGlvbiBhZGRyZXNzIGRvZXMgbm90IG1hdGNoIHdpdGggdGhlIHJlY2lwaWVudCBhZGRyZXNzJywgW1xuICAgICAgICAgICAgICB7IGFkZHJlc3M6IHR4SnNvbi50bywgYW1vdW50OiB0eEpzb24udmFsdWUgfSxcbiAgICAgICAgICAgIF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0eEpzb24uZGF0YS5zdGFydHNXaXRoKCcweGE5MDU5Y2JiJykpIHtcbiAgICAgICAgICBjb25zdCBbcmVjaXBpZW50QWRkcmVzcywgYW1vdW50XSA9IGdldFJhd0RlY29kZWQoXG4gICAgICAgICAgICBbJ2FkZHJlc3MnLCAndWludDI1NiddLFxuICAgICAgICAgICAgZ2V0QnVmZmVyZWRCeXRlQ29kZSgnMHhhOTA1OWNiYicsIHR4SnNvbi5kYXRhKVxuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBDaGVjayBpZiByZWNpcGllbnRzWzBdLmRhdGEgZXhpc3RzIChXYWxsZXRDb25uZWN0IGZsb3cpXG4gICAgICAgICAgbGV0IGV4cGVjdGVkUmVjaXBpZW50QWRkcmVzczogc3RyaW5nO1xuICAgICAgICAgIGxldCBleHBlY3RlZFRva2VuQW1vdW50OiBzdHJpbmc7XG4gICAgICAgICAgY29uc3QgcmVjaXBpZW50RGF0YSA9IChyZWNpcGllbnRzWzBdIGFzIGFueSkuZGF0YTtcblxuICAgICAgICAgIGlmIChyZWNpcGllbnREYXRhICYmIHJlY2lwaWVudERhdGEuc3RhcnRzV2l0aCgnMHhhOTA1OWNiYicpKSB7XG4gICAgICAgICAgICAvLyBXYWxsZXRDb25uZWN0OiBkZWNvZGUgZXhwZWN0ZWQgcmVjaXBpZW50IGFuZCBhbW91bnQgZnJvbSByZWNpcGllbnRzWzBdLmRhdGFcbiAgICAgICAgICAgIGNvbnN0IFtleHBlY3RlZFJlY2lwaWVudCwgZXhwZWN0ZWRBbW91bnRdID0gZ2V0UmF3RGVjb2RlZChcbiAgICAgICAgICAgICAgWydhZGRyZXNzJywgJ3VpbnQyNTYnXSxcbiAgICAgICAgICAgICAgZ2V0QnVmZmVyZWRCeXRlQ29kZSgnMHhhOTA1OWNiYicsIHJlY2lwaWVudERhdGEpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZXhwZWN0ZWRSZWNpcGllbnRBZGRyZXNzID0gYWRkSGV4UHJlZml4KGV4cGVjdGVkUmVjaXBpZW50LnRvU3RyaW5nKCkpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgICAgICBleHBlY3RlZFRva2VuQW1vdW50ID0gZXhwZWN0ZWRBbW91bnQudG9TdHJpbmcoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gTm9ybWFsIGZsb3c6IHVzZSByZWNpcGllbnRzWzBdLmFkZHJlc3MgYW5kIHJlY2lwaWVudHNbMF0uYW1vdW50XG4gICAgICAgICAgICBleHBlY3RlZFJlY2lwaWVudEFkZHJlc3MgPSBleHBlY3RlZERlc3RpbmF0aW9uLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgICAgICBleHBlY3RlZFRva2VuQW1vdW50ID0gZXhwZWN0ZWRBbW91bnQ7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGV4cGVjdGVkVG9rZW5BbW91bnQgIT09IGFtb3VudC50b1N0cmluZygpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aHJvd1JlY2lwaWVudE1pc21hdGNoKFxuICAgICAgICAgICAgICAndGhlIHRyYW5zYWN0aW9uIGFtb3VudCBpbiB0eFByZWJ1aWxkIGRvZXMgbm90IG1hdGNoIHRoZSB2YWx1ZSBnaXZlbiBieSBjbGllbnQnLFxuICAgICAgICAgICAgICBbeyBhZGRyZXNzOiBhZGRIZXhQcmVmaXgocmVjaXBpZW50QWRkcmVzcy50b1N0cmluZygpKSwgYW1vdW50OiBhbW91bnQudG9TdHJpbmcoKSB9XVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoZXhwZWN0ZWRSZWNpcGllbnRBZGRyZXNzICE9PSBhZGRIZXhQcmVmaXgocmVjaXBpZW50QWRkcmVzcy50b1N0cmluZygpKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aHJvd1JlY2lwaWVudE1pc21hdGNoKCdkZXN0aW5hdGlvbiBhZGRyZXNzIGRvZXMgbm90IG1hdGNoIHdpdGggdGhlIHJlY2lwaWVudCBhZGRyZXNzJywgW1xuICAgICAgICAgICAgICB7IGFkZHJlc3M6IGFkZEhleFByZWZpeChyZWNpcGllbnRBZGRyZXNzLnRvU3RyaW5nKCkpLCBhbW91bnQ6IGFtb3VudC50b1N0cmluZygpIH0sXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWZXJpZnkgY29uc29saWRhdGlvbiB0cmFuc2FjdGlvbnMgc2VuZCB0byBiYXNlIGFkZHJlc3NcbiAgICBpZiAocGFyYW1zLnZlcmlmaWNhdGlvbj8uY29uc29saWRhdGlvblRvQmFzZUFkZHJlc3MpIHtcbiAgICAgIGNvbnN0IGNvaW5TcGVjaWZpYyA9IHdhbGxldC5jb2luU3BlY2lmaWMoKTtcbiAgICAgIGlmICghY29pblNwZWNpZmljIHx8ICFjb2luU3BlY2lmaWMuYmFzZUFkZHJlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmFibGUgdG8gZGV0ZXJtaW5lIGJhc2UgYWRkcmVzcyBmb3IgY29uc29saWRhdGlvbicpO1xuICAgICAgfVxuICAgICAgY29uc3QgYmFzZUFkZHJlc3MgPSBjb2luU3BlY2lmaWMuYmFzZUFkZHJlc3M7XG5cbiAgICAgIGlmICghdHhQcmVidWlsZC50eEhleCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdHhIZXggaW4gdHhQcmVidWlsZCcpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgICAgdHhCdWlsZGVyLmZyb20odHhQcmVidWlsZC50eEhleCk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG5cbiAgICAgIC8vIFZlcmlmeSB0aGUgdHJhbnNhY3Rpb24gcmVjaXBpZW50IG1hdGNoZXMgdGhlIGJhc2UgYWRkcmVzc1xuICAgICAgaWYgKCF0eEpzb24udG8pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25zb2xpZGF0aW9uIHRyYW5zYWN0aW9uIGlzIG1pc3NpbmcgcmVjaXBpZW50IGFkZHJlc3MnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHR4SnNvbi50by50b0xvd2VyQ2FzZSgpICE9PSBiYXNlQWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgIGF3YWl0IHRocm93UmVjaXBpZW50TWlzbWF0Y2goJ0NvbnNvbGlkYXRpb24gdHJhbnNhY3Rpb24gcmVjaXBpZW50IGRvZXMgbm90IG1hdGNoIHdhbGxldCBiYXNlIGFkZHJlc3MnLCBbXG4gICAgICAgICAgeyBhZGRyZXNzOiB0eEpzb24udG8sIGFtb3VudDogdHhKc29uLnZhbHVlIH0sXG4gICAgICAgIF0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmeSB0aGF0IGEgdHJhbnNhY3Rpb24gcHJlYnVpbGQgY29tcGxpZXMgd2l0aCB0aGUgb3JpZ2luYWwgaW50ZW50aW9uXG4gICAqXG4gICAqIEBwYXJhbSB7VmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zfSBwYXJhbXNcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvblBhcmFtc30gcGFyYW1zLnR4UGFyYW1zIC0gcGFyYW1zIG9iamVjdCBwYXNzZWQgdG8gc2VuZFxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uUHJlYnVpbGR9IHBhcmFtcy50eFByZWJ1aWxkIC0gcHJlYnVpbGQgb2JqZWN0IHJldHVybmVkIGJ5IHNlcnZlclxuICAgKiBAcGFyYW0ge1dhbGxldH0gcGFyYW1zLndhbGxldCAtIFdhbGxldCBvYmplY3QgdG8gb2J0YWluIGtleXMgdG8gdmVyaWZ5IGFnYWluc3RcbiAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAqIEB0aHJvd3Mge1R4SW50ZW50TWlzbWF0Y2hFcnJvcn0gaWYgdHJhbnNhY3Rpb24gdmFsaWRhdGlvbiBmYWlsc1xuICAgKiBAdGhyb3dzIHtUeEludGVudE1pc21hdGNoUmVjaXBpZW50RXJyb3J9IGlmIHRyYW5zYWN0aW9uIHJlY2lwaWVudHMgZG9uJ3QgbWF0Y2ggdXNlciBpbnRlbnRcbiAgICovXG4gIGFzeW5jIHZlcmlmeVRyYW5zYWN0aW9uKHBhcmFtczogVmVyaWZ5RXRoVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgZXRoTmV0d29yayA9IHRoaXMuZ2V0TmV0d29yaygpO1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHdhbGxldCwgd2FsbGV0VHlwZSB9ID0gcGFyYW1zO1xuXG4gICAgaWYgKHdhbGxldFR5cGUgPT09ICd0c3MnKSB7XG4gICAgICByZXR1cm4gdGhpcy52ZXJpZnlUc3NUcmFuc2FjdGlvbihwYXJhbXMpO1xuICAgIH1cblxuICAgIC8vIEhlbHBlciB0byB0aHJvdyBUeEludGVudE1pc21hdGNoUmVjaXBpZW50RXJyb3Igd2l0aCByZWNpcGllbnQgZGV0YWlsc1xuICAgIGNvbnN0IHRocm93UmVjaXBpZW50TWlzbWF0Y2ggPSBhc3luYyAobWVzc2FnZTogc3RyaW5nLCBtaXNtYXRjaGVkUmVjaXBpZW50czogUmVjaXBpZW50W10pOiBQcm9taXNlPG5ldmVyPiA9PiB7XG4gICAgICBjb25zdCB0eEV4cGxhbmF0aW9uID0gYXdhaXQgdGhpcy5nZXRUeEV4cGxhbmF0aW9uKHR4UHJlYnVpbGQpO1xuICAgICAgdGhyb3cgbmV3IFR4SW50ZW50TWlzbWF0Y2hSZWNpcGllbnRFcnJvcihcbiAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICBbdHhQYXJhbXNdLFxuICAgICAgICB0eFByZWJ1aWxkPy50eEhleCxcbiAgICAgICAgbWlzbWF0Y2hlZFJlY2lwaWVudHMsXG4gICAgICAgIHR4RXhwbGFuYXRpb25cbiAgICAgICk7XG4gICAgfTtcblxuICAgIGlmICghdHhQYXJhbXM/LnJlY2lwaWVudHMgfHwgIXR4UHJlYnVpbGQ/LnJlY2lwaWVudHMgfHwgIXdhbGxldCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHBhcmFtcycpO1xuICAgIH1cblxuICAgIGNvbnN0IHJlY2lwaWVudHMgPSB0eFBhcmFtcy5yZWNpcGllbnRzITtcblxuICAgIGlmICh0eFBhcmFtcy5ob3AgJiYgcmVjaXBpZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4IGNhbm5vdCBiZSBib3RoIGEgYmF0Y2ggYW5kIGhvcCB0cmFuc2FjdGlvbicpO1xuICAgIH1cbiAgICBpZiAodHhQcmVidWlsZC5yZWNpcGllbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7dGhpcy5nZXRDaGFpbigpfSBkb2Vzbid0IHN1cHBvcnQgc2VuZGluZyB0byBtb3JlIHRoYW4gMSBkZXN0aW5hdGlvbiBhZGRyZXNzIHdpdGhpbiBhIHNpbmdsZSB0cmFuc2FjdGlvbi4gVHJ5IGFnYWluLCB1c2luZyBvbmx5IGEgc2luZ2xlIHJlY2lwaWVudC5gXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAodHhQYXJhbXMuaG9wICYmIHR4UHJlYnVpbGQuaG9wVHJhbnNhY3Rpb24pIHtcbiAgICAgIC8vIENoZWNrIHJlY2lwaWVudCBhbW91bnQgZm9yIGhvcCB0cmFuc2FjdGlvblxuICAgICAgaWYgKHJlY2lwaWVudHMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgaG9wIHRyYW5zYWN0aW9uIG9ubHkgc3VwcG9ydHMgMSByZWNpcGllbnQgYnV0ICR7cmVjaXBpZW50cy5sZW5ndGh9IGZvdW5kYCk7XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIHR4IHNlbmRzIHRvIGhvcCBhZGRyZXNzXG4gICAgICBjb25zdCBkZWNvZGVkSG9wVHggPSBvcHRpb25hbERlcHMuRXRoVHguVHJhbnNhY3Rpb25GYWN0b3J5LmZyb21TZXJpYWxpemVkRGF0YShcbiAgICAgICAgb3B0aW9uYWxEZXBzLmV0aFV0aWwudG9CdWZmZXIodHhQcmVidWlsZC5ob3BUcmFuc2FjdGlvbi50eClcbiAgICAgICk7XG4gICAgICBjb25zdCBleHBlY3RlZEhvcEFkZHJlc3MgPSBvcHRpb25hbERlcHMuZXRoVXRpbC5zdHJpcEhleFByZWZpeChkZWNvZGVkSG9wVHguZ2V0U2VuZGVyQWRkcmVzcygpLnRvU3RyaW5nKCkpO1xuICAgICAgY29uc3QgYWN0dWFsSG9wQWRkcmVzcyA9IG9wdGlvbmFsRGVwcy5ldGhVdGlsLnN0cmlwSGV4UHJlZml4KHR4UHJlYnVpbGQucmVjaXBpZW50c1swXS5hZGRyZXNzKTtcbiAgICAgIGlmIChleHBlY3RlZEhvcEFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gYWN0dWFsSG9wQWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgIGF3YWl0IHRocm93UmVjaXBpZW50TWlzbWF0Y2goJ3JlY2lwaWVudCBhZGRyZXNzIG9mIHR4UHJlYnVpbGQgZG9lcyBub3QgbWF0Y2ggaG9wIGFkZHJlc3MnLCBbXG4gICAgICAgICAgeyBhZGRyZXNzOiB0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYWRkcmVzcywgYW1vdW50OiB0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYW1vdW50LnRvU3RyaW5nKCkgfSxcbiAgICAgICAgXSk7XG4gICAgICB9XG5cbiAgICAgIC8vIENvbnZlcnQgVHJhbnNhY3Rpb25SZWNpcGllbnQgYXJyYXkgdG8gUmVjaXBpZW50IGFycmF5XG4gICAgICBjb25zdCBob3BSZWNpcGllbnRzOiBSZWNpcGllbnRbXSA9IHJlY2lwaWVudHMubWFwKChyKSA9PiB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYWRkcmVzczogci5hZGRyZXNzLFxuICAgICAgICAgIGFtb3VudDogdHlwZW9mIHIuYW1vdW50ID09PSAnbnVtYmVyJyA/IHIuYW1vdW50LnRvU3RyaW5nKCkgOiByLmFtb3VudCxcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuXG4gICAgICAvLyBDaGVjayBkZXN0aW5hdGlvbiBhZGRyZXNzIGFuZCBhbW91bnRcbiAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVIb3BQcmVidWlsZCh3YWxsZXQsIHR4UHJlYnVpbGQuaG9wVHJhbnNhY3Rpb24sIHsgcmVjaXBpZW50czogaG9wUmVjaXBpZW50cyB9KTtcbiAgICB9IGVsc2UgaWYgKHJlY2lwaWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgLy8gQ2hlY2sgdG90YWwgYW1vdW50IGZvciBiYXRjaCB0cmFuc2FjdGlvblxuICAgICAgaWYgKHR4UGFyYW1zLnRva2VuTmFtZSkge1xuICAgICAgICBjb25zdCBleHBlY3RlZFRvdGFsQW1vdW50ID0gbmV3IEJpZ051bWJlcigwKTtcbiAgICAgICAgaWYgKCFleHBlY3RlZFRvdGFsQW1vdW50LmlzRXF1YWxUbyh0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYW1vdW50KSkge1xuICAgICAgICAgIGF3YWl0IHRocm93UmVjaXBpZW50TWlzbWF0Y2goXG4gICAgICAgICAgICAnYmF0Y2ggdG9rZW4gdHJhbnNhY3Rpb24gYW1vdW50IGluIHR4UHJlYnVpbGQgc2hvdWxkIGJlIHplcm8gZm9yIHRva2VuIHRyYW5zZmVycycsXG4gICAgICAgICAgICBbeyBhZGRyZXNzOiB0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYWRkcmVzcywgYW1vdW50OiB0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYW1vdW50LnRvU3RyaW5nKCkgfV1cbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgZXhwZWN0ZWRUb3RhbEFtb3VudCA9IG5ldyBCaWdOdW1iZXIoMCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmVjaXBpZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGV4cGVjdGVkVG90YWxBbW91bnQgPSBleHBlY3RlZFRvdGFsQW1vdW50LnBsdXMocmVjaXBpZW50c1tpXS5hbW91bnQpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghZXhwZWN0ZWRUb3RhbEFtb3VudC5pc0VxdWFsVG8odHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFtb3VudCkpIHtcbiAgICAgICAgICBhd2FpdCB0aHJvd1JlY2lwaWVudE1pc21hdGNoKFxuICAgICAgICAgICAgJ2JhdGNoIHRyYW5zYWN0aW9uIGFtb3VudCBpbiB0eFByZWJ1aWxkIHJlY2VpdmVkIGZyb20gQml0R28gc2VydmVycyBkb2VzIG5vdCBtYXRjaCB0eFBhcmFtcyBzdXBwbGllZCBieSBjbGllbnQnLFxuICAgICAgICAgICAgW3sgYWRkcmVzczogdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFkZHJlc3MsIGFtb3VudDogdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFtb3VudC50b1N0cmluZygpIH1dXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBiYXRjaCB0cmFuc2FjdGlvbiBpcyBzZW50IHRvIHRoZSBiYXRjaGVyIGNvbnRyYWN0IGFkZHJlc3MgZm9yIHRoZSBjaGFpblxuICAgICAgY29uc3QgYmF0Y2hlckNvbnRyYWN0QWRkcmVzcyA9IGV0aE5ldHdvcms/LmJhdGNoZXJDb250cmFjdEFkZHJlc3M7XG4gICAgICBpZiAoXG4gICAgICAgICFiYXRjaGVyQ29udHJhY3RBZGRyZXNzIHx8XG4gICAgICAgIGJhdGNoZXJDb250cmFjdEFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFkZHJlc3MudG9Mb3dlckNhc2UoKVxuICAgICAgKSB7XG4gICAgICAgIGF3YWl0IHRocm93UmVjaXBpZW50TWlzbWF0Y2goJ3JlY2lwaWVudCBhZGRyZXNzIG9mIHR4UHJlYnVpbGQgZG9lcyBub3QgbWF0Y2ggYmF0Y2hlciBhZGRyZXNzJywgW1xuICAgICAgICAgIHsgYWRkcmVzczogdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFkZHJlc3MsIGFtb3VudDogdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFtb3VudC50b1N0cmluZygpIH0sXG4gICAgICAgIF0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBDaGVjayByZWNpcGllbnQgYWRkcmVzcyBhbmQgYW1vdW50IGZvciBub3JtYWwgdHJhbnNhY3Rpb25cbiAgICAgIGlmIChyZWNpcGllbnRzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYG5vcm1hbCB0cmFuc2FjdGlvbiBvbmx5IHN1cHBvcnRzIDEgcmVjaXBpZW50IGJ1dCAke3JlY2lwaWVudHMubGVuZ3RofSBmb3VuZGApO1xuICAgICAgfVxuICAgICAgY29uc3QgZXhwZWN0ZWRBbW91bnQgPSBuZXcgQmlnTnVtYmVyKHJlY2lwaWVudHNbMF0uYW1vdW50KTtcbiAgICAgIGlmICghZXhwZWN0ZWRBbW91bnQuaXNFcXVhbFRvKHR4UHJlYnVpbGQucmVjaXBpZW50c1swXS5hbW91bnQpKSB7XG4gICAgICAgIGF3YWl0IHRocm93UmVjaXBpZW50TWlzbWF0Y2goXG4gICAgICAgICAgJ25vcm1hbCB0cmFuc2FjdGlvbiBhbW91bnQgaW4gdHhQcmVidWlsZCByZWNlaXZlZCBmcm9tIEJpdEdvIHNlcnZlcnMgZG9lcyBub3QgbWF0Y2ggdHhQYXJhbXMgc3VwcGxpZWQgYnkgY2xpZW50JyxcbiAgICAgICAgICBbeyBhZGRyZXNzOiB0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYWRkcmVzcywgYW1vdW50OiB0eFByZWJ1aWxkLnJlY2lwaWVudHNbMF0uYW1vdW50LnRvU3RyaW5nKCkgfV1cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmlzRVRIQWRkcmVzcyhyZWNpcGllbnRzWzBdLmFkZHJlc3MpICYmIHJlY2lwaWVudHNbMF0uYWRkcmVzcyAhPT0gdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFkZHJlc3MpIHtcbiAgICAgICAgYXdhaXQgdGhyb3dSZWNpcGllbnRNaXNtYXRjaChcbiAgICAgICAgICAnZGVzdGluYXRpb24gYWRkcmVzcyBpbiBub3JtYWwgdHhQcmVidWlsZCBkb2VzIG5vdCBtYXRjaCB0aGF0IGluIHR4UGFyYW1zIHN1cHBsaWVkIGJ5IGNsaWVudCcsXG4gICAgICAgICAgW3sgYWRkcmVzczogdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFkZHJlc3MsIGFtb3VudDogdHhQcmVidWlsZC5yZWNpcGllbnRzWzBdLmFtb3VudC50b1N0cmluZygpIH1dXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIENoZWNrIGNvaW4gaXMgY29ycmVjdCBmb3IgYWxsIHRyYW5zYWN0aW9uIHR5cGVzXG4gICAgaWYgKCF0aGlzLnZlcmlmeUNvaW4odHhQcmVidWlsZCkpIHtcbiAgICAgIGNvbnN0IHR4RXhwbGFuYXRpb24gPSBhd2FpdCB0aGlzLmdldFR4RXhwbGFuYXRpb24odHhQcmVidWlsZCk7XG4gICAgICB0aHJvdyBuZXcgVHhJbnRlbnRNaXNtYXRjaEVycm9yKFxuICAgICAgICAnY29pbiBpbiB0eFByZWJ1aWxkIGRpZCBub3QgbWF0Y2ggdGhhdCBpbiB0eFBhcmFtcyBzdXBwbGllZCBieSBjbGllbnQnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIFt0eFBhcmFtc10sXG4gICAgICAgIHR4UHJlYnVpbGQ/LnR4SGV4LFxuICAgICAgICB0eEV4cGxhbmF0aW9uXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhZGRyZXNzIGlzIHZhbGlkIGV0aCBhZGRyZXNzXG4gICAqIEBwYXJhbSBhZGRyZXNzXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgcHJpdmF0ZSBpc0VUSEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhYWRkcmVzcy5tYXRjaCgvMHhbYS1mQS1GMC05XXs0MH0vKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2Zvcm0gbWVzc2FnZSB0byBhY2NvbW1vZGF0ZSBzcGVjaWZpYyBibG9ja2NoYWluIHJlcXVpcmVtZW50cy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSB0aGUgbWVzc2FnZSB0byBwcmVwYXJlXG4gICAqIEByZXR1cm4ge3N0cmluZ30gdGhlIHByZXBhcmVkIG1lc3NhZ2UgYXMgYSBoZXggZW5jb2RlZCBzdHJpbmcuXG4gICAqL1xuICBlbmNvZGVNZXNzYWdlKG1lc3NhZ2U6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcHJlZml4ID0gYFxcdTAwMTlFdGhlcmV1bSBTaWduZWQgTWVzc2FnZTpcXG4ke21lc3NhZ2UubGVuZ3RofWA7XG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKHByZWZpeC5jb25jYXQobWVzc2FnZSkpLnRvU3RyaW5nKCdoZXgnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2Zvcm0gdGhlIFR5cGVkIGRhdGEgdG8gYWNjb21vZGF0ZSB0aGUgYmxvY2tjaGFpbiByZXF1aXJlbWVudHMgKEVJUC03MTIpXG4gICAqIEBwYXJhbSB7VHlwZWREYXRhfSB0eXBlZERhdGEgLSB0aGUgdHlwZWQgZGF0YSB0byBwcmVwYXJlXG4gICAqIEByZXR1cm4ge0J1ZmZlcn0gYSBidWZmZXIgb2YgdGhlIHJlc3VsdFxuICAgKi9cbiAgZW5jb2RlVHlwZWREYXRhKHR5cGVkRGF0YTogVHlwZWREYXRhKTogQnVmZmVyIHtcbiAgICBjb25zdCB2ZXJzaW9uID0gdHlwZWREYXRhLnZlcnNpb247XG4gICAgaWYgKHZlcnNpb24gPT09IFNpZ25UeXBlZERhdGFWZXJzaW9uLlYxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NpZ25UeXBlZERhdGEgdjEgaXMgbm90IHN1cHBvcnRlZCBkdWUgdG8gc2VjdXJpdHkgY29uY2VybnMnKTtcbiAgICB9XG4gICAgY29uc3QgdHlwZWREYXRhUmF3ID0gSlNPTi5wYXJzZSh0eXBlZERhdGEudHlwZWREYXRhUmF3KTtcbiAgICBjb25zdCBzYW5pdGl6ZWREYXRhID0gVHlwZWREYXRhVXRpbHMuc2FuaXRpemVEYXRhKHR5cGVkRGF0YVJhdyBhcyB1bmtub3duIGFzIFR5cGVkTWVzc2FnZTxhbnk+KTtcbiAgICBjb25zdCBwYXJ0czogQnVmZmVyW10gPSBbQnVmZmVyLmZyb20oJzE5MDEnLCAnaGV4JyldO1xuICAgIGNvbnN0IGVpcDcxMkRvbWFpbiA9ICdFSVA3MTJEb21haW4nO1xuICAgIHBhcnRzLnB1c2goVHlwZWREYXRhVXRpbHMuaGFzaFN0cnVjdChlaXA3MTJEb21haW4sIHNhbml0aXplZERhdGEuZG9tYWluLCBzYW5pdGl6ZWREYXRhLnR5cGVzLCB2ZXJzaW9uKSk7XG5cbiAgICBpZiAoc2FuaXRpemVkRGF0YS5wcmltYXJ5VHlwZSAhPT0gZWlwNzEyRG9tYWluKSB7XG4gICAgICBwYXJ0cy5wdXNoKFxuICAgICAgICBUeXBlZERhdGFVdGlscy5oYXNoU3RydWN0KFxuICAgICAgICAgIHNhbml0aXplZERhdGEucHJpbWFyeVR5cGUgYXMgc3RyaW5nLFxuICAgICAgICAgIHNhbml0aXplZERhdGEubWVzc2FnZSxcbiAgICAgICAgICBzYW5pdGl6ZWREYXRhLnR5cGVzLFxuICAgICAgICAgIHZlcnNpb25cbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQocGFydHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIHRoZSBkYXRhIHRvIHRyYW5zZmVyIGFuIEVSQy03MjEgb3IgRVJDLTExNTUgdG9rZW4gdG8gYW5vdGhlciBhZGRyZXNzXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICovXG4gIGJ1aWxkTmZ0VHJhbnNmZXJEYXRhKHBhcmFtczogQnVpbGROZnRUcmFuc2ZlckRhdGFPcHRpb25zKTogc3RyaW5nIHtcbiAgICBjb25zdCB7IHRva2VuQ29udHJhY3RBZGRyZXNzLCByZWNpcGllbnRBZGRyZXNzLCBmcm9tQWRkcmVzcyB9ID0gcGFyYW1zO1xuICAgIHN3aXRjaCAocGFyYW1zLnR5cGUpIHtcbiAgICAgIGNhc2UgJ0VSQzcyMSc6IHtcbiAgICAgICAgY29uc3QgdG9rZW5JZCA9IHBhcmFtcy50b2tlbklkO1xuICAgICAgICBjb25zdCBjb250cmFjdERhdGEgPSBuZXcgRVJDNzIxVHJhbnNmZXJCdWlsZGVyKClcbiAgICAgICAgICAudG9rZW5Db250cmFjdEFkZHJlc3ModG9rZW5Db250cmFjdEFkZHJlc3MpXG4gICAgICAgICAgLnRvKHJlY2lwaWVudEFkZHJlc3MpXG4gICAgICAgICAgLmZyb20oZnJvbUFkZHJlc3MpXG4gICAgICAgICAgLnRva2VuSWQodG9rZW5JZClcbiAgICAgICAgICAuYnVpbGQoKTtcbiAgICAgICAgcmV0dXJuIGNvbnRyYWN0RGF0YTtcbiAgICAgIH1cblxuICAgICAgY2FzZSAnRVJDMTE1NSc6IHtcbiAgICAgICAgY29uc3QgZW50cmllcyA9IHBhcmFtcy5lbnRyaWVzO1xuICAgICAgICBjb25zdCB0cmFuc2ZlckJ1aWxkZXIgPSBuZXcgRVJDMTE1NVRyYW5zZmVyQnVpbGRlcigpXG4gICAgICAgICAgLnRva2VuQ29udHJhY3RBZGRyZXNzKHRva2VuQ29udHJhY3RBZGRyZXNzKVxuICAgICAgICAgIC50byhyZWNpcGllbnRBZGRyZXNzKVxuICAgICAgICAgIC5mcm9tKGZyb21BZGRyZXNzKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICB0cmFuc2ZlckJ1aWxkZXIuZW50cnkocGFyc2VJbnQoZW50cnkudG9rZW5JZCwgMTApLCBlbnRyeS5hbW91bnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRyYW5zZmVyQnVpbGRlci5idWlsZCgpO1xuICAgICAgfVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIE5GVCB0eXBlOiAke3BhcmFtcy50eXBlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaCB0aGUgZ2FzIHByaWNlIGZyb20gdGhlIGV4cGxvcmVyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB3cm9uZ0NoYWluQ29pbiAtIHRoZSBjb2luIHRoYXQgd2UncmUgZ2V0dGluZyBnYXMgcHJpY2UgZm9yXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcGlLZXkgLSBvcHRpb25hbCBBUEkga2V5IHRvIHVzZSBpbnN0ZWFkIG9mIHRoZSBvbmUgZnJvbSB0aGUgZW52aXJvbm1lbnRcbiAgICovXG4gIGFzeW5jIGdldEdhc1ByaWNlRnJvbUV4dGVybmFsQVBJKHdyb25nQ2hhaW5Db2luOiBzdHJpbmcsIGFwaUtleT86IHN0cmluZyk6IFByb21pc2U8Qk4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5yZWNvdmVyeUJsb2NrY2hhaW5FeHBsb3JlclF1ZXJ5KFxuICAgICAgICB7XG4gICAgICAgICAgY2hhaW5pZDogdGhpcy5nZXRDaGFpbklkKCkudG9TdHJpbmcoKSxcbiAgICAgICAgICBtb2R1bGU6ICdwcm94eScsXG4gICAgICAgICAgYWN0aW9uOiAnZXRoX2dhc1ByaWNlJyxcbiAgICAgICAgfSxcbiAgICAgICAgYXBpS2V5XG4gICAgICApO1xuICAgICAgY29uc3QgZ2FzUHJpY2UgPSBuZXcgQk4ocmVzLnJlc3VsdC5zbGljZSgyKSwgMTYpO1xuICAgICAgY29uc29sZS5sb2coYCBHb3QgZ2FzIHByaWNlOiAke2dhc1ByaWNlfWApO1xuICAgICAgcmV0dXJuIGdhc1ByaWNlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGdldCBnYXMgcHJpY2UuIFBsZWFzZSBtYWtlIHN1cmUgdG8gdXNlIHRoZSBhcGkga2V5IG9mICR7d3JvbmdDaGFpbkNvaW59YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoIHRoZSBnYXMgbGltaXQgZnJvbSB0aGUgZXhwbG9yZXJcbiAgICogQHBhcmFtIGludGVuZGVkQ2hhaW5cbiAgICogQHBhcmFtIGZyb21cbiAgICogQHBhcmFtIHRvXG4gICAqIEBwYXJhbSBkYXRhXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcGlLZXkgLSBvcHRpb25hbCBBUEkga2V5IHRvIHVzZSBpbnN0ZWFkIG9mIHRoZSBvbmUgZnJvbSB0aGUgZW52aXJvbm1lbnRcbiAgICovXG4gIGFzeW5jIGdldEdhc0xpbWl0RnJvbUV4dGVybmFsQVBJKFxuICAgIGludGVuZGVkQ2hhaW46IHN0cmluZyxcbiAgICBmcm9tOiBzdHJpbmcsXG4gICAgdG86IHN0cmluZyxcbiAgICBkYXRhOiBzdHJpbmcsXG4gICAgYXBpS2V5Pzogc3RyaW5nXG4gICk6IFByb21pc2U8Qk4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5yZWNvdmVyeUJsb2NrY2hhaW5FeHBsb3JlclF1ZXJ5KFxuICAgICAgICB7XG4gICAgICAgICAgY2hhaW5pZDogdGhpcy5nZXRDaGFpbklkKCkudG9TdHJpbmcoKSxcbiAgICAgICAgICBtb2R1bGU6ICdwcm94eScsXG4gICAgICAgICAgYWN0aW9uOiAnZXRoX2VzdGltYXRlR2FzJyxcbiAgICAgICAgICBmcm9tLFxuICAgICAgICAgIHRvLFxuICAgICAgICAgIGRhdGEsXG4gICAgICAgIH0sXG4gICAgICAgIGFwaUtleVxuICAgICAgKTtcbiAgICAgIGNvbnN0IGdhc0xpbWl0ID0gbmV3IEJOKHJlcy5yZXN1bHQuc2xpY2UoMiksIDE2KTtcbiAgICAgIGNvbnNvbGUubG9nKGBHb3QgZ2FzIGxpbWl0OiAke2dhc0xpbWl0fWApO1xuICAgICAgcmV0dXJuIGdhc0xpbWl0O1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZhaWxlZCB0byBnZXQgZ2FzIGxpbWl0LiBQbGVhc2UgbWFrZSBzdXJlIHRvIHVzZSB0aGUgcHJpdmF0ZUtleSBha2EgdXNlcktleSBvZiAke2ludGVuZGVkQ2hhaW59IHdhbGxldCAke3RvfWBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgYmFsYW5jZSBvZiBiaXRnb0ZlZUFkZHJlc3MgdG8gZW5zdXJlIGZ1bmRzIGFyZSBhdmFpbGFibGUgdG8gcGF5IGZlZXNcbiAgICogQHBhcmFtIGJpdGdvRmVlQWRkcmVzc1xuICAgKiBAcGFyYW0gZ2FzUHJpY2VcbiAgICogQHBhcmFtIGdhc0xpbWl0XG4gICAqIEBwYXJhbSBhcGlLZXkgLSBvcHRpb25hbCBBUEkga2V5IHRvIHVzZSBpbnN0ZWFkIG9mIHRoZSBvbmUgZnJvbSB0aGUgZW52aXJvbm1lbnRcbiAgICovXG4gIGFzeW5jIGVuc3VyZVN1ZmZpY2llbnRCYWxhbmNlKGJpdGdvRmVlQWRkcmVzczogc3RyaW5nLCBnYXNQcmljZTogQk4sIGdhc0xpbWl0OiBCTiwgYXBpS2V5Pzogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgYml0Z29GZWVBZGRyZXNzQmFsYW5jZSA9IGF3YWl0IHRoaXMucXVlcnlBZGRyZXNzQmFsYW5jZShiaXRnb0ZlZUFkZHJlc3MsIGFwaUtleSk7XG4gICAgY29uc3QgdG90YWxHYXNOZWVkZWQgPSBOdW1iZXIoZ2FzUHJpY2UubXVsKGdhc0xpbWl0KSk7XG4gICAgY29uc3Qgd2VpVG9Hd2VpID0gMTAgKiogOTtcbiAgICBpZiAoYml0Z29GZWVBZGRyZXNzQmFsYW5jZS5sdCh0b3RhbEdhc05lZWRlZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZlZSBhZGRyZXNzICR7Yml0Z29GZWVBZGRyZXNzfSBoYXMgYmFsYW5jZSAkeyhiaXRnb0ZlZUFkZHJlc3NCYWxhbmNlIC8gd2VpVG9Hd2VpKS50b1N0cmluZygpfSBHd2VpLmAgK1xuICAgICAgICAgIGBUaGlzIGFkZHJlc3MgbXVzdCBoYXZlIGEgYmFsYW5jZSBvZiBhdCBsZWFzdCAkeyh0b3RhbEdhc05lZWRlZCAvIHdlaVRvR3dlaSkudG9TdHJpbmcoKX1gICtcbiAgICAgICAgICBgIEd3ZWkgdG8gcGVyZm9ybSByZWNvdmVyaWVzLiBUcnkgc2VuZGluZyBzb21lICR7dGhpcy5nZXRDaGFpbigpfSB0byB0aGlzIGFkZHJlc3MgdGhlbiByZXRyeS5gXG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuIl19