@bitgo-beta/abstract-eth 1.0.2-beta.234 → 1.0.2-beta.2340

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