@bitgo-beta/sdk-coin-eth 4.4.1-beta.209 → 4.4.1-beta.2090

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 (122) hide show
  1. package/dist/src/erc20Token.d.ts +1 -1
  2. package/dist/src/erc20Token.d.ts.map +1 -1
  3. package/dist/src/erc20Token.js +52 -28
  4. package/dist/src/erc721Token.d.ts +60 -0
  5. package/dist/src/erc721Token.d.ts.map +1 -0
  6. package/dist/src/erc721Token.js +337 -0
  7. package/dist/src/erc7984Token.d.ts +187 -0
  8. package/dist/src/erc7984Token.d.ts.map +1 -0
  9. package/dist/src/erc7984Token.js +946 -0
  10. package/dist/src/eth.d.ts +10 -8
  11. package/dist/src/eth.d.ts.map +1 -1
  12. package/dist/src/eth.js +63 -42
  13. package/dist/src/index.d.ts +3 -0
  14. package/dist/src/index.d.ts.map +1 -1
  15. package/dist/src/index.js +9 -2
  16. package/dist/src/lib/index.d.ts +1 -0
  17. package/dist/src/lib/index.d.ts.map +1 -1
  18. package/dist/src/lib/index.js +7 -2
  19. package/dist/src/lib/messages/index.d.ts +3 -0
  20. package/dist/src/lib/messages/index.d.ts.map +1 -0
  21. package/dist/src/lib/messages/index.js +6 -0
  22. package/dist/src/lib/transactionBuilder.d.ts +10 -5
  23. package/dist/src/lib/transactionBuilder.d.ts.map +1 -1
  24. package/dist/src/lib/transactionBuilder.js +17 -7
  25. package/dist/src/lib/transferBuilders/index.d.ts +2 -2
  26. package/dist/src/lib/transferBuilders/index.d.ts.map +1 -1
  27. package/dist/src/lib/transferBuilders/index.js +3 -2
  28. package/dist/src/register.d.ts +2 -0
  29. package/dist/src/register.d.ts.map +1 -1
  30. package/dist/src/register.js +39 -2
  31. package/dist/src/sepeth.d.ts +8 -0
  32. package/dist/src/sepeth.d.ts.map +1 -0
  33. package/dist/src/sepeth.js +14 -0
  34. package/dist/test/fixtures/eth.d.ts +39 -0
  35. package/dist/test/fixtures/eth.d.ts.map +1 -0
  36. package/dist/test/fixtures/eth.js +262 -0
  37. package/dist/test/resources/erc1155Abi.d.ts +40 -0
  38. package/dist/test/resources/erc1155Abi.d.ts.map +1 -0
  39. package/dist/test/resources/erc1155Abi.js +329 -0
  40. package/dist/test/resources/erc721Abi.d.ts +12 -0
  41. package/dist/test/resources/erc721Abi.d.ts.map +1 -0
  42. package/dist/test/resources/erc721Abi.js +34 -0
  43. package/dist/test/resources/eth.d.ts +51 -0
  44. package/dist/test/resources/eth.d.ts.map +1 -0
  45. package/dist/test/resources/eth.js +72 -0
  46. package/dist/test/resources/nftEncodings.d.ts +4 -0
  47. package/dist/test/resources/nftEncodings.d.ts.map +1 -0
  48. package/dist/test/resources/nftEncodings.js +7 -0
  49. package/dist/test/resources/walletSimpleAbi.d.ts +12 -0
  50. package/dist/test/resources/walletSimpleAbi.d.ts.map +1 -0
  51. package/dist/test/resources/walletSimpleAbi.js +44 -0
  52. package/dist/test/unit/erc7984Token.d.ts +2 -0
  53. package/dist/test/unit/erc7984Token.d.ts.map +1 -0
  54. package/dist/test/unit/erc7984Token.js +1589 -0
  55. package/dist/test/unit/eth.d.ts +2 -0
  56. package/dist/test/unit/eth.d.ts.map +1 -0
  57. package/dist/test/unit/eth.js +2916 -0
  58. package/dist/test/unit/ethWallet.d.ts +2 -0
  59. package/dist/test/unit/ethWallet.d.ts.map +1 -0
  60. package/dist/test/unit/ethWallet.js +552 -0
  61. package/dist/test/unit/fixtures/ethMultiSigBackupKey.d.ts +4 -0
  62. package/dist/test/unit/fixtures/ethMultiSigBackupKey.d.ts.map +1 -0
  63. package/dist/test/unit/fixtures/ethMultiSigBackupKey.js +10 -0
  64. package/dist/test/unit/fixtures/ethTssBackupKey.d.ts +5 -0
  65. package/dist/test/unit/fixtures/ethTssBackupKey.d.ts.map +1 -0
  66. package/dist/test/unit/fixtures/ethTssBackupKey.js +25 -0
  67. package/dist/test/unit/getBuilder.d.ts +3 -0
  68. package/dist/test/unit/getBuilder.d.ts.map +1 -0
  69. package/dist/test/unit/getBuilder.js +10 -0
  70. package/dist/test/unit/keyPair.d.ts +2 -0
  71. package/dist/test/unit/keyPair.d.ts.map +1 -0
  72. package/dist/test/unit/keyPair.js +175 -0
  73. package/dist/test/unit/register.d.ts +2 -0
  74. package/dist/test/unit/register.d.ts.map +1 -0
  75. package/dist/test/unit/register.js +75 -0
  76. package/dist/test/unit/transaction.d.ts +2 -0
  77. package/dist/test/unit/transaction.d.ts.map +1 -0
  78. package/dist/test/unit/transaction.js +117 -0
  79. package/dist/test/unit/transactionBuilder/addressInitialization.d.ts +2 -0
  80. package/dist/test/unit/transactionBuilder/addressInitialization.d.ts.map +1 -0
  81. package/dist/test/unit/transactionBuilder/addressInitialization.js +101 -0
  82. package/dist/test/unit/transactionBuilder/contractCall.d.ts +2 -0
  83. package/dist/test/unit/transactionBuilder/contractCall.d.ts.map +1 -0
  84. package/dist/test/unit/transactionBuilder/contractCall.js +101 -0
  85. package/dist/test/unit/transactionBuilder/decryptionDelegation.d.ts +2 -0
  86. package/dist/test/unit/transactionBuilder/decryptionDelegation.d.ts.map +1 -0
  87. package/dist/test/unit/transactionBuilder/decryptionDelegation.js +59 -0
  88. package/dist/test/unit/transactionBuilder/decryptionDelegationTxBuilder.d.ts +2 -0
  89. package/dist/test/unit/transactionBuilder/decryptionDelegationTxBuilder.d.ts.map +1 -0
  90. package/dist/test/unit/transactionBuilder/decryptionDelegationTxBuilder.js +136 -0
  91. package/dist/test/unit/transactionBuilder/flushCoins.d.ts +2 -0
  92. package/dist/test/unit/transactionBuilder/flushCoins.d.ts.map +1 -0
  93. package/dist/test/unit/transactionBuilder/flushCoins.js +133 -0
  94. package/dist/test/unit/transactionBuilder/flushTokens.d.ts +2 -0
  95. package/dist/test/unit/transactionBuilder/flushTokens.d.ts.map +1 -0
  96. package/dist/test/unit/transactionBuilder/flushTokens.js +298 -0
  97. package/dist/test/unit/transactionBuilder/send.d.ts +2 -0
  98. package/dist/test/unit/transactionBuilder/send.d.ts.map +1 -0
  99. package/dist/test/unit/transactionBuilder/send.js +331 -0
  100. package/dist/test/unit/transactionBuilder/sendERC7984Token.d.ts +2 -0
  101. package/dist/test/unit/transactionBuilder/sendERC7984Token.d.ts.map +1 -0
  102. package/dist/test/unit/transactionBuilder/sendERC7984Token.js +361 -0
  103. package/dist/test/unit/transactionBuilder/sendNFT.d.ts +2 -0
  104. package/dist/test/unit/transactionBuilder/sendNFT.d.ts.map +1 -0
  105. package/dist/test/unit/transactionBuilder/sendNFT.js +295 -0
  106. package/dist/test/unit/transactionBuilder/singleSigSend.d.ts +2 -0
  107. package/dist/test/unit/transactionBuilder/singleSigSend.d.ts.map +1 -0
  108. package/dist/test/unit/transactionBuilder/singleSigSend.js +196 -0
  109. package/dist/test/unit/transactionBuilder/walletInitialization.d.ts +2 -0
  110. package/dist/test/unit/transactionBuilder/walletInitialization.d.ts.map +1 -0
  111. package/dist/test/unit/transactionBuilder/walletInitialization.js +436 -0
  112. package/dist/test/unit/transferBuilder.d.ts +2 -0
  113. package/dist/test/unit/transferBuilder.d.ts.map +1 -0
  114. package/dist/test/unit/transferBuilder.js +124 -0
  115. package/dist/test/unit/utils.d.ts +2 -0
  116. package/dist/test/unit/utils.d.ts.map +1 -0
  117. package/dist/test/unit/utils.js +74 -0
  118. package/dist/tsconfig.tsbuildinfo +1 -0
  119. package/package.json +18 -13
  120. package/.eslintignore +0 -5
  121. package/.mocharc.yml +0 -8
  122. package/CHANGELOG.md +0 -881
@@ -0,0 +1,946 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Erc7984Token = void 0;
37
+ /**
38
+ * @prettier
39
+ */
40
+ const sdk_core_1 = require("@bitgo-beta/sdk-core");
41
+ const statics_1 = require("@bitgo-beta/statics");
42
+ const abstract_eth_1 = require("@bitgo-beta/abstract-eth");
43
+ const secp256k1_1 = require("@bitgo-beta/secp256k1");
44
+ const _ = __importStar(require("lodash"));
45
+ const eth_1 = require("./eth");
46
+ const lib_1 = require("./lib");
47
+ class Erc7984Token extends eth_1.Eth {
48
+ constructor(bitgo, tokenConfig) {
49
+ const staticsCoin = statics_1.coins.get(tokenConfig.coin);
50
+ super(bitgo, staticsCoin);
51
+ this.tokenConfig = tokenConfig;
52
+ // ERC7984 confidential transfers use sendMultiSig (not sendMultiSigToken) because
53
+ // the calldata parameter is required to carry confidentialTransfer(recipient, encryptedHandle, inputProof).
54
+ // sendMultiSigToken has no data parameter and cannot carry inner calldata.
55
+ this.sendMethodName = 'sendMultiSig';
56
+ }
57
+ static createTokenConstructor(config) {
58
+ return (bitgo) => new Erc7984Token(bitgo, config);
59
+ }
60
+ static createTokenConstructors(tokenConfigs = [
61
+ ...statics_1.tokens.bitcoin.eth.confidentialTokens,
62
+ ...statics_1.tokens.testnet.eth.confidentialTokens,
63
+ ]) {
64
+ const tokensCtors = [];
65
+ for (const token of tokenConfigs) {
66
+ const tokenConstructor = Erc7984Token.createTokenConstructor(token);
67
+ tokensCtors.push({ name: token.type, coinConstructor: tokenConstructor });
68
+ tokensCtors.push({ name: token.tokenContractAddress, coinConstructor: tokenConstructor });
69
+ }
70
+ return tokensCtors;
71
+ }
72
+ get type() {
73
+ return this.tokenConfig.type;
74
+ }
75
+ get name() {
76
+ return this.tokenConfig.name;
77
+ }
78
+ get coin() {
79
+ return this.tokenConfig.coin;
80
+ }
81
+ get network() {
82
+ return this.tokenConfig.network;
83
+ }
84
+ get tokenContractAddress() {
85
+ return this.tokenConfig.tokenContractAddress;
86
+ }
87
+ get decimalPlaces() {
88
+ return this.tokenConfig.decimalPlaces;
89
+ }
90
+ getChain() {
91
+ return this.tokenConfig.type;
92
+ }
93
+ getFullName() {
94
+ return 'ERC7984 Confidential Token';
95
+ }
96
+ getBaseFactor() {
97
+ return Math.pow(10, this.tokenConfig.decimalPlaces);
98
+ }
99
+ /**
100
+ * Flag for sending value of 0.
101
+ * ERC-7984 confidential transfers always carry an encrypted amount; zero-value sends are not meaningful.
102
+ */
103
+ valuelessTransferAllowed() {
104
+ return false;
105
+ }
106
+ /**
107
+ * Flag for sending data along with transactions via the standard token-send API.
108
+ * Returns false because ERC-7984 sends use confidentialTransfer() calldata built
109
+ * by WP, not an arbitrary data field on the send params.
110
+ * Note: this does not prevent calldata-based flows like getDelegationBuilder(),
111
+ * which bypass the token-send path entirely.
112
+ */
113
+ transactionDataAllowed() {
114
+ return false;
115
+ }
116
+ /** @inheritDoc */
117
+ supportsTss() {
118
+ return true;
119
+ }
120
+ /** @inheritDoc */
121
+ getMPCAlgorithm() {
122
+ return 'ecdsa';
123
+ }
124
+ getTransactionBuilder() {
125
+ return new lib_1.TransactionBuilder(statics_1.coins.get(this.getBaseChain()));
126
+ }
127
+ /** @inheritDoc */
128
+ async verifyTransaction(params) {
129
+ if (params.txParams?.type === 'enabletoken') {
130
+ return this.verifyEnableTokenTransaction(params);
131
+ }
132
+ if (params.txParams?.type === 'wrap') {
133
+ return this.verifyWrapTransaction(params);
134
+ }
135
+ if (params.txParams?.type === 'unwrap') {
136
+ return this.verifyUnwrapTransaction(params);
137
+ }
138
+ if (params.txParams?.type === 'finalizeUnwrap') {
139
+ return this.verifyFinalizeUnwrapTransaction(params);
140
+ }
141
+ if (this.isConsolidationTransaction(params)) {
142
+ return this.verifyConfidentialConsolidation(params);
143
+ }
144
+ return this.verifyConfidentialTransfer(params);
145
+ }
146
+ isConsolidationTransaction(params) {
147
+ const { txParams, txPrebuild, verification } = params;
148
+ return !!(verification?.consolidationToBaseAddress ||
149
+ txPrebuild?.consolidateId ||
150
+ txParams?.type === 'consolidate' ||
151
+ // TSS signing path: resolveEffectiveTxParams sets type from intent.intentType which is
152
+ // 'consolidateToken' for ERC-7984 token consolidations. txPrebuild has only txHex
153
+ // (no consolidateId) in this path.
154
+ txParams?.type === 'consolidateToken' ||
155
+ txParams?.prebuildTx?.consolidateId);
156
+ }
157
+ /**
158
+ * Verifies WrapERC7984 (shield) transactions.
159
+ *
160
+ * TSS / direct shape:
161
+ * tx.to = wrapper contract
162
+ * tx.data = wrap(baseAddress, amount)
163
+ *
164
+ * Multisig shape:
165
+ * tx.to = wallet contract
166
+ * tx.data = sendMultiSig(wrapper, 0, wrap(baseAddress, amount), ...)
167
+ *
168
+ * Checks: wrapper address, self-directed `to` == base, amount > 0, amount matches
169
+ * recipients, and floor(amount / rate) fits uint64 when statics rate is present.
170
+ */
171
+ async verifyWrapTransaction(params) {
172
+ const { txParams, txPrebuild, wallet } = params;
173
+ if (!txPrebuild?.txHex) {
174
+ throw new Error('verifyWrapTransaction: missing txHex in txPrebuild');
175
+ }
176
+ const txBuilder = this.getTransactionBuilder();
177
+ txBuilder.from(txPrebuild.txHex);
178
+ const tx = await txBuilder.build();
179
+ const txJson = tx.toJson();
180
+ let wrapperAddress;
181
+ let wrapCalldata;
182
+ try {
183
+ if (txJson.data.toLowerCase().startsWith(abstract_eth_1.sendMultisigMethodId.toLowerCase())) {
184
+ const decoded = (0, abstract_eth_1.decodeTransferData)(txJson.data);
185
+ wrapperAddress = decoded.to;
186
+ wrapCalldata = decoded.data;
187
+ if (decoded.amount !== '0') {
188
+ throw new Error(`expected sendMultiSig value 0 but got ${decoded.amount}`);
189
+ }
190
+ }
191
+ else if (txJson.data.toLowerCase().startsWith(abstract_eth_1.wrapMethodId.toLowerCase())) {
192
+ wrapperAddress = txJson.to;
193
+ wrapCalldata = txJson.data;
194
+ }
195
+ else {
196
+ throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
197
+ }
198
+ }
199
+ catch (e) {
200
+ throw new Error(`verifyWrapTransaction: failed to decode wrap calldata — ${e.message}`);
201
+ }
202
+ if (wrapperAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
203
+ throw new Error(`verifyWrapTransaction: wrapper address mismatch — ` +
204
+ `expected ${this.tokenContractAddress}, got ${wrapperAddress}`);
205
+ }
206
+ let to;
207
+ let amount;
208
+ try {
209
+ ({ to, amount } = (0, abstract_eth_1.decodeWrapCalldata)(wrapCalldata));
210
+ }
211
+ catch (e) {
212
+ throw new Error(`verifyWrapTransaction: invalid wrap inner calldata — ${e.message}`);
213
+ }
214
+ if (!Erc7984Token.isPositiveIntegerString(amount)) {
215
+ throw new Error(`verifyWrapTransaction: amount must be a positive integer string, got '${amount}'`);
216
+ }
217
+ const baseAddress = this.getWalletBaseAddress(wallet);
218
+ if (!baseAddress) {
219
+ throw new Error('verifyWrapTransaction: unable to determine wallet base address');
220
+ }
221
+ if (to.toLowerCase() !== baseAddress.toLowerCase()) {
222
+ throw new Error(`verifyWrapTransaction: wrap recipient must equal wallet base address — expected ${baseAddress}, got ${to}`);
223
+ }
224
+ const expectedAmount = txParams?.recipients?.[0]?.amount ?? txPrebuild.buildParams?.recipients?.[0]?.amount;
225
+ if (expectedAmount !== undefined && String(expectedAmount) !== amount) {
226
+ throw new Error(`verifyWrapTransaction: amount mismatch — calldata has '${amount}' but params have '${expectedAmount}'`);
227
+ }
228
+ const rate = this.tokenConfig.rate;
229
+ if (rate !== undefined) {
230
+ try {
231
+ (0, abstract_eth_1.assertWrapAmountFitsUint64)(amount, rate);
232
+ }
233
+ catch (e) {
234
+ throw new Error(`verifyWrapTransaction: ${e.message}`);
235
+ }
236
+ }
237
+ if (txJson.value !== undefined && txJson.value !== '0' && txJson.value !== 0) {
238
+ throw new Error(`verifyWrapTransaction: expected transaction value 0 but got ${txJson.value}`);
239
+ }
240
+ return true;
241
+ }
242
+ /**
243
+ * Verifies UnwrapERC7984 (unshield phase-1) transactions.
244
+ *
245
+ * TSS / direct shape:
246
+ * tx.to = wrapper contract
247
+ * tx.data = unwrap(base, base, encryptedAmount, inputProof)
248
+ *
249
+ * Multisig shape:
250
+ * tx.to = wallet contract
251
+ * tx.data = sendMultiSig(wrapper, 0, unwrap(base, base, ...), ...)
252
+ *
253
+ * v1 is self-directed only: from == to == wallet base address.
254
+ */
255
+ async verifyUnwrapTransaction(params) {
256
+ const { txPrebuild, wallet } = params;
257
+ if (!txPrebuild?.txHex) {
258
+ throw new Error('verifyUnwrapTransaction: missing txHex in txPrebuild');
259
+ }
260
+ const txBuilder = this.getTransactionBuilder();
261
+ txBuilder.from(txPrebuild.txHex);
262
+ const tx = await txBuilder.build();
263
+ const txJson = tx.toJson();
264
+ let wrapperAddress;
265
+ let unwrapCalldata;
266
+ try {
267
+ if (txJson.data.toLowerCase().startsWith(abstract_eth_1.sendMultisigMethodId.toLowerCase())) {
268
+ const decoded = (0, abstract_eth_1.decodeTransferData)(txJson.data);
269
+ wrapperAddress = decoded.to;
270
+ unwrapCalldata = decoded.data;
271
+ if (decoded.amount !== '0') {
272
+ throw new Error(`expected sendMultiSig value 0 but got ${decoded.amount}`);
273
+ }
274
+ }
275
+ else if (txJson.data.toLowerCase().startsWith(abstract_eth_1.unwrapMethodId.toLowerCase())) {
276
+ wrapperAddress = txJson.to;
277
+ unwrapCalldata = txJson.data;
278
+ }
279
+ else {
280
+ throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
281
+ }
282
+ }
283
+ catch (e) {
284
+ throw new Error(`verifyUnwrapTransaction: failed to decode unwrap calldata — ${e.message}`);
285
+ }
286
+ if (wrapperAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
287
+ throw new Error(`verifyUnwrapTransaction: wrapper address mismatch — expected ${this.tokenContractAddress}, got ${wrapperAddress}`);
288
+ }
289
+ let from;
290
+ let to;
291
+ let encryptedAmount;
292
+ let inputProof;
293
+ try {
294
+ ({ from, to, encryptedAmount, inputProof } = (0, abstract_eth_1.decodeUnwrapCalldata)(unwrapCalldata));
295
+ }
296
+ catch (e) {
297
+ throw new Error(`verifyUnwrapTransaction: invalid unwrap inner calldata — ${e.message}`);
298
+ }
299
+ const baseAddress = this.getWalletBaseAddress(wallet);
300
+ if (!baseAddress) {
301
+ throw new Error('verifyUnwrapTransaction: unable to determine wallet base address');
302
+ }
303
+ if (from.toLowerCase() !== baseAddress.toLowerCase()) {
304
+ throw new Error(`verifyUnwrapTransaction: unwrap from must equal wallet base address — expected ${baseAddress}, got ${from}`);
305
+ }
306
+ if (to.toLowerCase() !== baseAddress.toLowerCase()) {
307
+ throw new Error(`verifyUnwrapTransaction: unwrap to must equal wallet base address — expected ${baseAddress}, got ${to}`);
308
+ }
309
+ if (!encryptedAmount || encryptedAmount === '0x' || /^0x0+$/.test(encryptedAmount)) {
310
+ throw new Error('verifyUnwrapTransaction: encryptedAmount is missing or empty');
311
+ }
312
+ if (!inputProof || inputProof === '0x') {
313
+ throw new Error('verifyUnwrapTransaction: inputProof is missing or empty');
314
+ }
315
+ if (txJson.value !== undefined && txJson.value !== '0' && txJson.value !== 0) {
316
+ throw new Error(`verifyUnwrapTransaction: expected transaction value 0 but got ${txJson.value}`);
317
+ }
318
+ return true;
319
+ }
320
+ /**
321
+ * Verifies FinalizeUnwrapERC7984 (unshield phase-2) transactions.
322
+ *
323
+ * TSS / direct shape:
324
+ * tx.to = wrapper contract
325
+ * tx.data = finalizeUnwrap(requestId, cleartextAmount, decryptionProof)
326
+ *
327
+ * Multisig shape:
328
+ * tx.to = wallet contract
329
+ * tx.data = sendMultiSig(wrapper, 0, finalizeUnwrap(...), ...)
330
+ */
331
+ async verifyFinalizeUnwrapTransaction(params) {
332
+ const { txParams, txPrebuild } = params;
333
+ if (!txPrebuild?.txHex) {
334
+ throw new Error('verifyFinalizeUnwrapTransaction: missing txHex in txPrebuild');
335
+ }
336
+ const txBuilder = this.getTransactionBuilder();
337
+ txBuilder.from(txPrebuild.txHex);
338
+ const tx = await txBuilder.build();
339
+ const txJson = tx.toJson();
340
+ let wrapperAddress;
341
+ let finalizeCalldata;
342
+ try {
343
+ if (txJson.data.toLowerCase().startsWith(abstract_eth_1.sendMultisigMethodId.toLowerCase())) {
344
+ const decoded = (0, abstract_eth_1.decodeTransferData)(txJson.data);
345
+ wrapperAddress = decoded.to;
346
+ finalizeCalldata = decoded.data;
347
+ if (decoded.amount !== '0') {
348
+ throw new Error(`expected sendMultiSig value 0 but got ${decoded.amount}`);
349
+ }
350
+ }
351
+ else if (txJson.data.toLowerCase().startsWith(abstract_eth_1.finalizeUnwrapMethodId.toLowerCase())) {
352
+ wrapperAddress = txJson.to;
353
+ finalizeCalldata = txJson.data;
354
+ }
355
+ else {
356
+ throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
357
+ }
358
+ }
359
+ catch (e) {
360
+ throw new Error(`verifyFinalizeUnwrapTransaction: failed to decode finalizeUnwrap calldata — ${e.message}`);
361
+ }
362
+ if (wrapperAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
363
+ throw new Error(`verifyFinalizeUnwrapTransaction: wrapper address mismatch — expected ${this.tokenContractAddress}, got ${wrapperAddress}`);
364
+ }
365
+ let requestId;
366
+ let cleartextAmount;
367
+ let decryptionProof;
368
+ try {
369
+ ({ requestId, cleartextAmount, decryptionProof } = (0, abstract_eth_1.decodeFinalizeUnwrapCalldata)(finalizeCalldata));
370
+ }
371
+ catch (e) {
372
+ throw new Error(`verifyFinalizeUnwrapTransaction: invalid finalizeUnwrap inner calldata — ${e.message}`);
373
+ }
374
+ if (!requestId || requestId === '0x' || /^0x0+$/.test(requestId)) {
375
+ throw new Error('verifyFinalizeUnwrapTransaction: requestId is missing or empty');
376
+ }
377
+ if (!Erc7984Token.isPositiveIntegerString(cleartextAmount)) {
378
+ throw new Error(`verifyFinalizeUnwrapTransaction: cleartextAmount must be a positive integer string, got '${cleartextAmount}'`);
379
+ }
380
+ if (BigInt(cleartextAmount) > abstract_eth_1.UINT64_MAX) {
381
+ throw new Error('verifyFinalizeUnwrapTransaction: cleartextAmount exceeds uint64');
382
+ }
383
+ if (!decryptionProof || decryptionProof === '0x') {
384
+ throw new Error('verifyFinalizeUnwrapTransaction: decryptionProof is missing or empty');
385
+ }
386
+ const expectedAmount = txParams?.recipients?.[0]?.amount ?? txPrebuild.buildParams?.recipients?.[0]?.amount;
387
+ if (expectedAmount !== undefined && String(expectedAmount) !== cleartextAmount) {
388
+ throw new Error(`verifyFinalizeUnwrapTransaction: amount mismatch — calldata has '${cleartextAmount}' but params have '${expectedAmount}'`);
389
+ }
390
+ if (txJson.value !== undefined && txJson.value !== '0' && txJson.value !== 0) {
391
+ throw new Error(`verifyFinalizeUnwrapTransaction: expected transaction value 0 but got ${txJson.value}`);
392
+ }
393
+ return true;
394
+ }
395
+ getWalletBaseAddress(wallet) {
396
+ if (!wallet) {
397
+ return undefined;
398
+ }
399
+ const coinSpecific = typeof wallet.coinSpecific === 'function' ? wallet.coinSpecific() : wallet.coinSpecific;
400
+ const ethCoinSpecific = coinSpecific;
401
+ return ethCoinSpecific?.baseAddress ?? ethCoinSpecific?.rootAddress;
402
+ }
403
+ /**
404
+ * Verifies ERC-7984 forwarder consolidation (flush) transactions.
405
+ *
406
+ * Multisig shape:
407
+ * tx.to = wallet contract
408
+ * tx.data = sendMultiSig(forwarder, 0, callFromParent(token, 0, confidentialTransferNoProof(base, handle)), ...)
409
+ *
410
+ * TSS / direct shape:
411
+ * tx.to = forwarder contract
412
+ * tx.data = callFromParent(token, 0, confidentialTransferNoProof(base, handle))
413
+ */
414
+ async verifyConfidentialConsolidation(params) {
415
+ const { txParams, txPrebuild, wallet } = params;
416
+ if (!txPrebuild?.txHex) {
417
+ if (!txPrebuild?.consolidateId && !txParams?.prebuildTx?.consolidateId) {
418
+ throw new Error('verifyConfidentialConsolidation: missing consolidateId');
419
+ }
420
+ return true;
421
+ }
422
+ const txBuilder = this.getTransactionBuilder();
423
+ txBuilder.from(txPrebuild.txHex);
424
+ const tx = await txBuilder.build();
425
+ const txJson = tx.toJson();
426
+ let tokenContractAddress;
427
+ let parentAddress;
428
+ let encryptedHandle;
429
+ let forwarderAddress;
430
+ try {
431
+ if (txJson.data.startsWith(abstract_eth_1.sendMultisigMethodId)) {
432
+ const decoded = (0, abstract_eth_1.decodeSendMultiSigFlushERC7984Data)(txJson.data);
433
+ forwarderAddress = decoded.forwarderAddress;
434
+ tokenContractAddress = decoded.tokenContractAddress;
435
+ parentAddress = decoded.parentAddress;
436
+ encryptedHandle = decoded.encryptedHandle;
437
+ }
438
+ else if (txJson.data.startsWith(abstract_eth_1.callFromParentMethodId)) {
439
+ const decoded = (0, abstract_eth_1.decodeFlushERC7984ForwarderTokenCalldata)(txJson.data);
440
+ tokenContractAddress = decoded.tokenContractAddress;
441
+ parentAddress = decoded.parentAddress;
442
+ encryptedHandle = decoded.encryptedHandle;
443
+ forwarderAddress = txJson.to;
444
+ }
445
+ else {
446
+ throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
447
+ }
448
+ }
449
+ catch (e) {
450
+ throw new Error(`verifyConfidentialConsolidation: failed to decode consolidation calldata — ${e.message}`);
451
+ }
452
+ if (tokenContractAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
453
+ throw new Error(`verifyConfidentialConsolidation: token contract address mismatch — ` +
454
+ `expected ${this.tokenContractAddress}, got ${tokenContractAddress}`);
455
+ }
456
+ const baseAddress = this.getWalletBaseAddress(wallet);
457
+ if (!baseAddress) {
458
+ throw new Error('verifyConfidentialConsolidation: unable to determine wallet base address');
459
+ }
460
+ if (parentAddress.toLowerCase() !== baseAddress.toLowerCase()) {
461
+ throw new Error(`verifyConfidentialConsolidation: parent address mismatch — expected ${baseAddress}, got ${parentAddress}`);
462
+ }
463
+ if (!encryptedHandle || encryptedHandle === '0x') {
464
+ throw new Error('verifyConfidentialConsolidation: encryptedHandle is missing or empty in transaction calldata');
465
+ }
466
+ const expectedForwarder = txPrebuild.recipients?.[0]?.address ??
467
+ txPrebuild.txInfo?.recipients?.[0]?.address ??
468
+ txParams?.recipients?.[0]?.address;
469
+ if (forwarderAddress && expectedForwarder) {
470
+ if (forwarderAddress.toLowerCase() !== expectedForwarder.toLowerCase()) {
471
+ throw new Error(`verifyConfidentialConsolidation: forwarder address mismatch — ` +
472
+ `expected ${expectedForwarder}, got ${forwarderAddress}`);
473
+ }
474
+ }
475
+ return true;
476
+ }
477
+ /**
478
+ * Verifies a confidential token transfer (SendERC7984) transaction.
479
+ *
480
+ * With txHex — two on-chain shapes are supported:
481
+ *
482
+ * sendMultiSig-wrapped (multisig / smart-contract wallet):
483
+ * tx.to = wallet contract
484
+ * tx.data = sendMultiSig(tokenAddr, 0, confidentialTransfer(recipient, handle, proof), ...)
485
+ * Token contract address is decoded from the sendMultiSig inner calldata.
486
+ *
487
+ * Direct call (hot / TSS EOA wallet):
488
+ * tx.to = token contract
489
+ * tx.data = confidentialTransfer(recipient, handle, proof)
490
+ * Token contract address is taken from tx.to.
491
+ *
492
+ * For both shapes the verifier checks:
493
+ * 1. Token contract address matches this coin's tokenContractAddress.
494
+ * 2. Decoded recipient matches txParams.recipients[0].address or buildParams.recipients[0].address.
495
+ * 3. encryptedHandle and inputProof are structurally present (non-empty).
496
+ * 4. txParams.recipients[0].amount is a positive integer and matches buildParams when both present.
497
+ *
498
+ * Without txHex (first-signer / pre-signing path):
499
+ * 1. Requires exactly one recipient in txParams.
500
+ * 2. Validates txParams.recipients[0].address is a valid Ethereum address.
501
+ * 3. Validates txParams.recipients[0].amount is a positive integer.
502
+ * 4. Cross-checks address and amount against buildParams when the server has stored the intent.
503
+ */
504
+ async verifyConfidentialTransfer(params) {
505
+ const { txParams, txPrebuild } = params;
506
+ if (!txPrebuild?.txHex) {
507
+ // No raw tx available (multisig first-signer path).
508
+ // Validate ERC7984-specific invariants from txParams and buildParams.
509
+ const recipients = txParams?.recipients;
510
+ if (!recipients || recipients.length === 0) {
511
+ throw new Error('verifyConfidentialTransfer: recipients must contain at least one entry');
512
+ }
513
+ if (recipients.length !== 1) {
514
+ throw new Error(`verifyConfidentialTransfer: confidential transfers support exactly 1 recipient, got ${recipients.length}`);
515
+ }
516
+ const recipient = recipients[0];
517
+ if (!recipient.address || !this.isValidAddress(recipient.address)) {
518
+ throw new Error(`verifyConfidentialTransfer: recipient address is missing or invalid: ${recipient.address}`);
519
+ }
520
+ const amountStr = String(recipient.amount);
521
+ if (!Erc7984Token.isPositiveIntegerString(amountStr)) {
522
+ throw new Error(`verifyConfidentialTransfer: amount must be a positive integer string in base units, got '${amountStr}'`);
523
+ }
524
+ // Cross-check against buildParams when the server has already stored the intent
525
+ const buildParamsRecipient = txPrebuild?.buildParams?.recipients?.[0];
526
+ if (buildParamsRecipient?.address !== undefined) {
527
+ if (recipient.address.toLowerCase() !== buildParamsRecipient.address.toLowerCase()) {
528
+ throw new Error(`verifyConfidentialTransfer: recipient address mismatch — ` +
529
+ `txParams has '${recipient.address}' but buildParams has '${buildParamsRecipient.address}'`);
530
+ }
531
+ }
532
+ const buildParamsAmount = buildParamsRecipient?.amount;
533
+ if (buildParamsAmount !== undefined && buildParamsAmount !== amountStr) {
534
+ throw new Error(`verifyConfidentialTransfer: amount mismatch — txParams has '${amountStr}' but buildParams has '${buildParamsAmount}'`);
535
+ }
536
+ return true;
537
+ }
538
+ // Parse and decode the raw transaction
539
+ const txBuilder = this.getTransactionBuilder();
540
+ txBuilder.from(txPrebuild.txHex);
541
+ const tx = await txBuilder.build();
542
+ const txJson = tx.toJson();
543
+ let toAddress;
544
+ let tokenContractAddress;
545
+ let encryptedHandle;
546
+ let inputProof;
547
+ try {
548
+ if (txJson.data.startsWith(abstract_eth_1.sendMultisigMethodId)) {
549
+ // sendMultiSig-wrapped path: smart-contract wallet relays the confidentialTransfer call.
550
+ // Token contract address is encoded inside the sendMultiSig calldata.
551
+ const decoded = (0, abstract_eth_1.decodeConfidentialTransferData)(txJson.data);
552
+ toAddress = decoded.toAddress;
553
+ tokenContractAddress = decoded.tokenContractAddress;
554
+ encryptedHandle = decoded.encryptedHandle;
555
+ inputProof = decoded.inputProof;
556
+ }
557
+ else if (txJson.data.startsWith(abstract_eth_1.confidentialTransferWithProofMethodId)) {
558
+ // Direct call path: hot/TSS EOA wallet calls the token contract directly.
559
+ // The transaction's `to` field is the token contract address.
560
+ if (!txJson.to) {
561
+ throw new Error('direct confidentialTransfer call is missing transaction to address');
562
+ }
563
+ const decoded = (0, abstract_eth_1.decodeDirectConfidentialTransferCalldata)(txJson.data);
564
+ toAddress = decoded.toAddress;
565
+ tokenContractAddress = txJson.to;
566
+ encryptedHandle = decoded.encryptedHandle;
567
+ inputProof = decoded.inputProof;
568
+ }
569
+ else {
570
+ throw new Error(`unexpected method ID ${txJson.data.slice(0, 10)}`);
571
+ }
572
+ }
573
+ catch (e) {
574
+ throw new Error(`verifyConfidentialTransfer: failed to decode confidential transfer calldata — ${e.message}`);
575
+ }
576
+ // 1. Token contract address must match this coin
577
+ if (tokenContractAddress.toLowerCase() !== this.tokenContractAddress.toLowerCase()) {
578
+ throw new Error(`verifyConfidentialTransfer: token contract address mismatch — ` +
579
+ `expected ${this.tokenContractAddress}, got ${tokenContractAddress}`);
580
+ }
581
+ // 2. Recipient address must match txParams.recipients[0] or buildParams.recipients[0]
582
+ const expectedRecipient = txParams?.recipients?.[0]?.address ?? txPrebuild.buildParams?.recipients?.[0]?.address;
583
+ if (!expectedRecipient) {
584
+ throw new Error('verifyConfidentialTransfer: missing expected recipient (provide txParams.recipients or txPrebuild.buildParams.recipients)');
585
+ }
586
+ if (toAddress.toLowerCase() !== expectedRecipient.toLowerCase()) {
587
+ throw new Error(`verifyConfidentialTransfer: recipient address mismatch — ` + `expected ${expectedRecipient}, got ${toAddress}`);
588
+ }
589
+ // 3. encryptedHandle must be a non-trivial hex value (not bare '0x')
590
+ if (!encryptedHandle || encryptedHandle === '0x') {
591
+ throw new Error('verifyConfidentialTransfer: encryptedHandle is missing or empty in transaction calldata');
592
+ }
593
+ // 4. inputProof must be a non-trivial hex value
594
+ if (!inputProof || inputProof === '0x') {
595
+ throw new Error('verifyConfidentialTransfer: inputProof is missing or empty in transaction calldata');
596
+ }
597
+ // 5. Verify plaintext intent: txParams amount must be valid and consistent with buildParams
598
+ const rawTxParamsAmount = txParams?.recipients?.[0]?.amount;
599
+ if (rawTxParamsAmount !== undefined) {
600
+ const txParamsAmount = String(rawTxParamsAmount);
601
+ if (!Erc7984Token.isPositiveIntegerString(txParamsAmount)) {
602
+ throw new Error(`verifyConfidentialTransfer: amount must be a positive integer string in base units, got '${txParamsAmount}'`);
603
+ }
604
+ const buildParamsAmount = txPrebuild.buildParams?.recipients?.[0]?.amount;
605
+ if (buildParamsAmount !== undefined && txParamsAmount !== buildParamsAmount) {
606
+ throw new Error(`verifyConfidentialTransfer: amount mismatch — txParams has '${txParamsAmount}' but buildParams has '${buildParamsAmount}'`);
607
+ }
608
+ }
609
+ return true;
610
+ }
611
+ static isPositiveIntegerString(value) {
612
+ return /^\d+$/.test(value) && BigInt(value) > 0n;
613
+ }
614
+ /**
615
+ * Verifies a token enablement transaction for ERC-7984 decryption delegation.
616
+ *
617
+ * TSS path: decodes the raw tx and verifies it calls the ACL contract with
618
+ * calldata that covers all requested token contract addresses.
619
+ *
620
+ * Multisig path: verifies the buildParams recipients carry the correct tokenNames
621
+ * and zero amounts.
622
+ */
623
+ async verifyEnableTokenTransaction(params) {
624
+ const { txParams, txPrebuild, walletType } = params;
625
+ if (walletType === 'tss') {
626
+ // TSS path: full raw-tx decode
627
+ const enableTokens = txParams.enableTokens;
628
+ if (!enableTokens || enableTokens.length === 0) {
629
+ throw new Error('verifyEnableTokenTransaction: enableTokens must be non-empty for TSS path');
630
+ }
631
+ if (!txPrebuild.txHex) {
632
+ throw new Error('verifyEnableTokenTransaction: missing txHex in txPrebuild');
633
+ }
634
+ // Resolve requested token names → contract addresses
635
+ const requestedAddresses = enableTokens.map((t) => {
636
+ const tokenCoin = this.bitgo.coin(t.name);
637
+ return tokenCoin.tokenContractAddress.toLowerCase();
638
+ });
639
+ // Parse the raw transaction
640
+ const txBuilder = this.getTransactionBuilder();
641
+ txBuilder.from(txPrebuild.txHex);
642
+ const tx = await txBuilder.build();
643
+ const txJson = tx.toJson();
644
+ // Verify transaction targets the correct contract based on calldata shape
645
+ const network = this.getNetwork();
646
+ const aclContractAddress = network?.zamaAclContractAddress;
647
+ if (!aclContractAddress) {
648
+ throw new Error('verifyEnableTokenTransaction: zamaAclContractAddress not configured for this network');
649
+ }
650
+ if (!txJson.to) {
651
+ throw new Error('verifyEnableTokenTransaction: transaction is missing recipient address');
652
+ }
653
+ // Inspect calldata method ID to distinguish root wallet from forwarder wallet:
654
+ // aclMulticallMethodId → root wallet: to = ACL contract directly
655
+ // callFromParentMethodId → forwarder wallet: to = forwarder, ACL address is inside calldata
656
+ const calldataMethodId = txJson.data.slice(0, 10);
657
+ if (calldataMethodId === abstract_eth_1.aclMulticallMethodId) {
658
+ // Root wallet (base address): tx calls the ACL contract directly
659
+ if (txJson.to.toLowerCase() !== aclContractAddress.toLowerCase()) {
660
+ throw new Error(`verifyEnableTokenTransaction: transaction target ${txJson.to} does not match ACL contract ${aclContractAddress}`);
661
+ }
662
+ }
663
+ else if (calldataMethodId === abstract_eth_1.callFromParentMethodId) {
664
+ // Forwarder wallet: tx calls the forwarder, which calls the ACL via callFromParent.
665
+ // The forwarder address is wallet-specific and cannot be statically verified here;
666
+ // token address correctness is still verified below via calldata decoding.
667
+ }
668
+ else {
669
+ throw new Error(`verifyEnableTokenTransaction: unrecognised calldata method ID ${calldataMethodId}; expected multicall or callFromParent`);
670
+ }
671
+ // Verify value is 0
672
+ if (txJson.value !== '0') {
673
+ throw new Error(`verifyEnableTokenTransaction: expected transaction value 0 but got ${txJson.value}`);
674
+ }
675
+ // Decode token addresses from calldata and verify all requested tokens are present
676
+ const decodedAddresses = (0, abstract_eth_1.decodeTokenAddressesFromDelegationCalldata)(txJson.data);
677
+ for (const requested of requestedAddresses) {
678
+ if (!decodedAddresses.includes(requested)) {
679
+ throw new Error(`verifyEnableTokenTransaction: requested token ${requested} not found in delegation calldata`);
680
+ }
681
+ }
682
+ return true;
683
+ }
684
+ else {
685
+ // Multisig path: buildParams-level check
686
+ const recipients = txPrebuild.buildParams?.recipients;
687
+ if (!recipients || recipients.length === 0) {
688
+ throw new Error('verifyEnableTokenTransaction: missing buildParams.recipients for multisig path');
689
+ }
690
+ // Determine requested token names from txParams
691
+ const requestedTokenNames = [];
692
+ if (txParams.enableTokens && txParams.enableTokens.length > 0) {
693
+ requestedTokenNames.push(...txParams.enableTokens.map((t) => t.name));
694
+ }
695
+ else if (txParams.recipients && txParams.recipients.length > 0) {
696
+ requestedTokenNames.push(...txParams.recipients.map((r) => r.tokenName).filter(Boolean));
697
+ }
698
+ // Verify all recipients have tokenName and amount = '0'
699
+ for (const recipient of recipients) {
700
+ if (!recipient.tokenName) {
701
+ throw new Error('verifyEnableTokenTransaction: recipient is missing tokenName in buildParams');
702
+ }
703
+ if (recipient.amount !== '0') {
704
+ throw new Error(`verifyEnableTokenTransaction: expected amount 0 for token enablement but got ${recipient.amount}`);
705
+ }
706
+ }
707
+ // Verify requested token names are present in recipients
708
+ if (requestedTokenNames.length > 0) {
709
+ const recipientTokenNames = recipients.map((r) => r.tokenName);
710
+ for (const requested of requestedTokenNames) {
711
+ if (!recipientTokenNames.includes(requested)) {
712
+ throw new Error(`verifyEnableTokenTransaction: requested token ${requested} not found in buildParams recipients`);
713
+ }
714
+ }
715
+ }
716
+ return true;
717
+ }
718
+ }
719
+ /**
720
+ * Override gas limit for ERC-7984 confidential token recovery.
721
+ * Actual on-chain usage is ~506-530k gas based on testnet results.
722
+ * Default: 800,000 (comfortable buffer over observed usage).
723
+ */
724
+ setGasLimit(userGasLimit) {
725
+ if (!userGasLimit) {
726
+ return 800000;
727
+ }
728
+ return super.setGasLimit(userGasLimit);
729
+ }
730
+ /**
731
+ * Queries the encrypted balance handle for a wallet address via eth_call to the
732
+ * token contract's confidentialBalanceOf(address) function.
733
+ *
734
+ * @param walletAddress - the wallet contract address to query balance for
735
+ * @param apiKey - optional Etherscan API key
736
+ * @returns bytes32 encrypted handle (0x-prefixed, 66 chars).
737
+ * Note: handles are always non-zero even for zero balances (encrypted domain).
738
+ */
739
+ async queryConfidentialBalance(walletAddress, apiKey) {
740
+ const methodSignature = abstract_eth_1.optionalDeps.ethAbi.methodID('confidentialBalanceOf', ['address']);
741
+ const encodedArgs = abstract_eth_1.optionalDeps.ethAbi.rawEncode(['address'], [walletAddress]);
742
+ const calldata = Buffer.concat([methodSignature, encodedArgs]).toString('hex');
743
+ const result = await this.recoveryBlockchainExplorerQuery({
744
+ chainid: this.getChainId().toString(),
745
+ module: 'proxy',
746
+ action: 'eth_call',
747
+ to: this.tokenContractAddress,
748
+ data: calldata,
749
+ tag: 'latest',
750
+ }, apiKey);
751
+ if (!result || !result.result) {
752
+ throw new sdk_core_1.RecoveryProviderError(`Could not obtain confidential balance for ${walletAddress} from token ${this.tokenContractAddress}`);
753
+ }
754
+ const handle = result.result;
755
+ if (!handle.startsWith('0x') || handle.length !== 66) {
756
+ throw new sdk_core_1.RecoveryProviderError(`Unexpected confidentialBalanceOf response format: ${handle}`);
757
+ }
758
+ return handle;
759
+ }
760
+ /**
761
+ * Builds a non-BitGo recovery transaction for ERC-7984 confidential tokens.
762
+ *
763
+ * Uses the no-proof handle sweep: confidentialTransfer(recipient, handle) with 2 args.
764
+ * No FHE decryption or proof generation is needed — the wallet transfers its entire
765
+ * encrypted balance handle without knowing the plaintext amount.
766
+ *
767
+ * The outer transaction shape is:
768
+ * tx.to = walletContractAddress
769
+ * tx.data = sendMultiSig(tokenContractAddr, 0, confidentialTransfer(recoveryDest, handle), ...)
770
+ */
771
+ async recover(params) {
772
+ if (params.isTss === true) {
773
+ throw new Error('ERC-7984 TSS recovery is not yet supported');
774
+ }
775
+ if (_.isUndefined(params.userKey)) {
776
+ throw new Error('missing userKey');
777
+ }
778
+ if (_.isUndefined(params.backupKey)) {
779
+ throw new Error('missing backupKey');
780
+ }
781
+ if (_.isUndefined(params.walletPassphrase) && !params.userKey.startsWith('xpub')) {
782
+ throw new Error('missing wallet passphrase');
783
+ }
784
+ if (_.isUndefined(params.walletContractAddress) || !this.isValidAddress(params.walletContractAddress)) {
785
+ throw new Error('invalid walletContractAddress');
786
+ }
787
+ if (_.isUndefined(params.recoveryDestination) || !this.isValidAddress(params.recoveryDestination)) {
788
+ throw new Error('invalid recoveryDestination');
789
+ }
790
+ const isKrsRecovery = (0, sdk_core_1.getIsKrsRecovery)(params);
791
+ const isUnsignedSweep = (0, sdk_core_1.getIsUnsignedSweep)(params);
792
+ if (isKrsRecovery) {
793
+ (0, sdk_core_1.checkKrsProvider)(this, params.krsProvider, { checkCoinFamilySupport: false });
794
+ }
795
+ let userKey = params.userKey.replace(/\s/g, '');
796
+ const backupKey = params.backupKey.replace(/\s/g, '');
797
+ const gasPrice = params.eip1559
798
+ ? new abstract_eth_1.optionalDeps.ethUtil.BN(params.eip1559.maxFeePerGas)
799
+ : new abstract_eth_1.optionalDeps.ethUtil.BN(this.setGasPrice(params.gasPrice));
800
+ const gasLimit = new abstract_eth_1.optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit));
801
+ let userPrv;
802
+ if (!isUnsignedSweep) {
803
+ if (!userKey.startsWith('xpub') && !userKey.startsWith('xprv')) {
804
+ try {
805
+ userKey = await this.bitgo.decrypt({
806
+ input: userKey,
807
+ password: params.walletPassphrase,
808
+ });
809
+ }
810
+ catch (e) {
811
+ throw new Error(`Error decrypting user keychain: ${e.message}`);
812
+ }
813
+ }
814
+ userPrv = userKey;
815
+ }
816
+ let backupKeyAddress;
817
+ let backupSigningKey;
818
+ if (isKrsRecovery || isUnsignedSweep) {
819
+ const backupHDNode = secp256k1_1.bip32.fromBase58(backupKey);
820
+ backupSigningKey = backupHDNode.publicKey;
821
+ backupKeyAddress = `0x${abstract_eth_1.optionalDeps.ethUtil.publicToAddress(backupSigningKey, true).toString('hex')}`;
822
+ }
823
+ else {
824
+ let backupPrv;
825
+ try {
826
+ backupPrv = await this.bitgo.decrypt({
827
+ input: backupKey,
828
+ password: params.walletPassphrase,
829
+ });
830
+ }
831
+ catch (e) {
832
+ throw new Error(`Error decrypting backup keychain: ${e.message}`);
833
+ }
834
+ const backupHDNode = secp256k1_1.bip32.fromBase58(backupPrv);
835
+ backupSigningKey = backupHDNode.privateKey;
836
+ backupKeyAddress = `0x${abstract_eth_1.optionalDeps.ethUtil.privateToAddress(backupSigningKey).toString('hex')}`;
837
+ }
838
+ const backupKeyNonce = await this.getAddressNonce(backupKeyAddress, params.apiKey);
839
+ const backupKeyBalance = await this.queryAddressBalance(backupKeyAddress, params.apiKey);
840
+ const totalGasNeeded = gasPrice.mul(gasLimit);
841
+ const weiToGwei = 10 ** 9;
842
+ if (backupKeyBalance.lt(totalGasNeeded)) {
843
+ throw new Error(`Backup key address ${backupKeyAddress} has balance ${(backupKeyBalance / weiToGwei).toString()} Gwei.` +
844
+ `This address must have a balance of at least ${(totalGasNeeded / weiToGwei).toString()}` +
845
+ ` Gwei to perform recoveries. Try sending some ETH to this address then retry.`);
846
+ }
847
+ // Get the encrypted balance handle (auto-query or user-provided)
848
+ let encryptedHandle;
849
+ if (params.encryptedHandle) {
850
+ encryptedHandle = params.encryptedHandle;
851
+ }
852
+ else {
853
+ await new Promise((resolve) => setTimeout(resolve, 1000));
854
+ encryptedHandle = await this.queryConfidentialBalance(params.walletContractAddress, params.apiKey);
855
+ }
856
+ // Note: encrypted handles are always non-zero even for zero balances (encrypted domain).
857
+ // The transfer will execute but move 0 tokens if the wallet is empty.
858
+ // Build the inner calldata: confidentialTransfer(recoveryDestination, handle)
859
+ const innerCalldata = (0, abstract_eth_1.buildConfidentialTransferByHandleCalldata)(params.recoveryDestination, encryptedHandle);
860
+ // For sendMultiSig: recipient is the token contract, amount is 0, data carries the confidentialTransfer calldata
861
+ const recipients = [
862
+ {
863
+ address: this.tokenContractAddress,
864
+ amount: '0',
865
+ data: abstract_eth_1.optionalDeps.ethUtil.stripHexPrefix(innerCalldata),
866
+ },
867
+ ];
868
+ await new Promise((resolve) => setTimeout(resolve, 1000));
869
+ const sequenceId = await this.querySequenceId(params.walletContractAddress, params.apiKey);
870
+ let operationHash;
871
+ let signature;
872
+ if (!isUnsignedSweep) {
873
+ operationHash = this.getOperationSha3ForExecuteAndConfirm(recipients, this.getDefaultExpireTime(), sequenceId);
874
+ signature = sdk_core_1.Util.ethSignMsgHash(operationHash, sdk_core_1.Util.xprvToEthPrivateKey(userPrv));
875
+ try {
876
+ sdk_core_1.Util.ecRecoverEthAddress(operationHash, signature);
877
+ }
878
+ catch (e) {
879
+ throw new Error('Invalid signature');
880
+ }
881
+ }
882
+ const txInfo = {
883
+ recipient: recipients[0],
884
+ expireTime: this.getDefaultExpireTime(),
885
+ contractSequenceId: sequenceId,
886
+ operationHash: operationHash,
887
+ signature: signature ?? '',
888
+ gasLimit: gasLimit.toString(10),
889
+ };
890
+ const sendMethodArgs = this.getSendMethodArgs(txInfo);
891
+ const methodSignature = abstract_eth_1.optionalDeps.ethAbi.methodID(this.sendMethodName, _.map(sendMethodArgs, 'type'));
892
+ const encodedArgs = abstract_eth_1.optionalDeps.ethAbi.rawEncode(_.map(sendMethodArgs, 'type'), _.map(sendMethodArgs, 'value'));
893
+ const sendData = Buffer.concat([methodSignature, encodedArgs]);
894
+ let tx = eth_1.Eth.buildTransaction({
895
+ to: params.walletContractAddress,
896
+ nonce: backupKeyNonce,
897
+ value: 0,
898
+ gasPrice: gasPrice,
899
+ gasLimit: gasLimit,
900
+ data: sendData,
901
+ eip1559: params.eip1559,
902
+ replayProtectionOptions: params.replayProtectionOptions,
903
+ });
904
+ if (isUnsignedSweep) {
905
+ return this.formatForOfflineVault(txInfo, tx, userKey, backupKey, gasPrice, gasLimit, params.eip1559, params.replayProtectionOptions, params.apiKey);
906
+ }
907
+ if (!isKrsRecovery) {
908
+ tx = tx.sign(backupSigningKey);
909
+ }
910
+ const signedTx = {
911
+ id: abstract_eth_1.optionalDeps.ethUtil.bufferToHex(tx.hash()),
912
+ tx: tx.serialize().toString('hex'),
913
+ };
914
+ if (isKrsRecovery) {
915
+ signedTx.backupKey = backupKey;
916
+ signedTx.coin = this.getChain();
917
+ }
918
+ return signedTx;
919
+ }
920
+ /**
921
+ * Returns a DecryptionDelegationBuilder for constructing Zama ACL decryption
922
+ * delegation transactions.
923
+ *
924
+ * The builder produces a DecryptionDelegationTxRequest {to, data, value} that is
925
+ * wallet-type-agnostic — WP routes it to the correct signing path:
926
+ * - MPC: submit as a raw TSS transaction
927
+ * - Multisig: wrap in sendMultiSig(walletContract, to, 0, data, ...)
928
+ *
929
+ * Example:
930
+ * const req = coin.getDecryptionDelegationBuilder().build({
931
+ * aclContractAddress: '0xf0Ff...',
932
+ * delegateAddress: enterpriseViewingKey,
933
+ * tokenContractAddresses: [tokenAddress],
934
+ * expiryTimestamp: Math.floor(Date.now() / 1000) + 365 * 86400,
935
+ * });
936
+ */
937
+ getDecryptionDelegationBuilder() {
938
+ return new abstract_eth_1.DecryptionDelegationBuilder();
939
+ }
940
+ }
941
+ exports.Erc7984Token = Erc7984Token;
942
+ Erc7984Token.coinNames = {
943
+ Mainnet: 'eth',
944
+ Testnet: 'hteth',
945
+ };
946
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJjNzk4NFRva2VuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VyYzc5ODRUb2tlbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7R0FFRztBQUNILG1EQVU4QjtBQUM5QixpREFBeUY7QUFDekYsMkRBMkJrQztBQUNsQyxxREFBOEM7QUFDOUMsMENBQTRCO0FBRTVCLCtCQUE0QjtBQUM1QiwrQkFBMkM7QUFJM0MsTUFBYSxZQUFhLFNBQVEsU0FBRztJQVFuQyxZQUFZLEtBQWdCLEVBQUUsV0FBK0I7UUFDM0QsTUFBTSxXQUFXLEdBQUcsZUFBSyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsS0FBSyxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUMvQixrRkFBa0Y7UUFDbEYsNEdBQTRHO1FBQzVHLDJFQUEyRTtRQUMzRSxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztJQUN2QyxDQUFDO0lBRUQsTUFBTSxDQUFDLHNCQUFzQixDQUFDLE1BQTBCO1FBQ3RELE9BQU8sQ0FBQyxLQUFnQixFQUFFLEVBQUUsQ0FBQyxJQUFJLFlBQVksQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELE1BQU0sQ0FBQyx1QkFBdUIsQ0FDNUIsZUFBcUM7UUFDbkMsR0FBRyxnQkFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCO1FBQ3hDLEdBQUcsZ0JBQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQjtLQUN6QztRQUVELE1BQU0sV0FBVyxHQUEyQixFQUFFLENBQUM7UUFDL0MsS0FBSyxNQUFNLEtBQUssSUFBSSxZQUFZLEVBQUUsQ0FBQztZQUNqQyxNQUFNLGdCQUFnQixHQUFHLFlBQVksQ0FB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LGVBQWUsRUFBRSxDQUFDO1lBQ3BCLE9BQU8sSUFBSSxDQUFDLHFCQUFxQixDQUMvQixNQUFNLEVBQ04sRUFBRSxFQUNGLE9BQU8sRUFDUCxTQUFTLEVBQ1QsUUFBUSxFQUNSLFFBQVEsRUFDUixNQUFNLENBQUMsT0FBTyxFQUNkLE1BQU0sQ0FBQyx1QkFBdUIsRUFDOUIsTUFBTSxDQUFDLE1BQU0sQ0FDUCxDQUFDO1FBQ1gsQ0FBQztRQUVELElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNuQixFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ2pDLENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBaUI7WUFDN0IsRUFBRSxFQUFFLDJCQUFZLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDL0MsRUFBRSxFQUFFLEVBQUUsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO1NBQ25DLENBQUM7UUFFRixJQUFJLGFBQWEsRUFBRSxDQUFDO1lBQ2xCLFFBQVEsQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1lBQy9CLFFBQVEsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2xDLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSCw4QkFBOEI7UUFDNUIsT0FBTyxJQUFJLDBDQUEyQixFQUFFLENBQUM7SUFDM0MsQ0FBQzs7QUExakNILG9DQTJqQ0M7QUF4akNRLHNCQUFTLEdBQWM7SUFDNUIsT0FBTyxFQUFFLEtBQUs7SUFDZCxPQUFPLEVBQUUsT0FBTztDQUNqQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAcHJldHRpZXJcbiAqL1xuaW1wb3J0IHtcbiAgQml0R29CYXNlLFxuICBDb2luQ29uc3RydWN0b3IsXG4gIGNoZWNrS3JzUHJvdmlkZXIsXG4gIGdldElzS3JzUmVjb3ZlcnksXG4gIGdldElzVW5zaWduZWRTd2VlcCxcbiAgTVBDQWxnb3JpdGhtLFxuICBOYW1lZENvaW5Db25zdHJ1Y3RvcixcbiAgUmVjb3ZlcnlQcm92aWRlckVycm9yLFxuICBVdGlsLFxufSBmcm9tICdAYml0Z28tYmV0YS9zZGstY29yZSc7XG5pbXBvcnQgeyBjb2lucywgRXJjNzk4NFRva2VuQ29uZmlnLCBFdGhlcmV1bU5ldHdvcmssIHRva2VucyB9IGZyb20gJ0BiaXRnby1iZXRhL3N0YXRpY3MnO1xuaW1wb3J0IHtcbiAgQ29pbk5hbWVzLFxuICBEZWNyeXB0aW9uRGVsZWdhdGlvbkJ1aWxkZXIsXG4gIGRlY29kZVRva2VuQWRkcmVzc2VzRnJvbURlbGVnYXRpb25DYWxsZGF0YSxcbiAgZGVjb2RlQ29uZmlkZW50aWFsVHJhbnNmZXJEYXRhLFxuICBkZWNvZGVEaXJlY3RDb25maWRlbnRpYWxUcmFuc2ZlckNhbGxkYXRhLFxuICBkZWNvZGVGbHVzaEVSQzc5ODRGb3J3YXJkZXJUb2tlbkNhbGxkYXRhLFxuICBkZWNvZGVTZW5kTXVsdGlTaWdGbHVzaEVSQzc5ODREYXRhLFxuICBzZW5kTXVsdGlzaWdNZXRob2RJZCxcbiAgY29uZmlkZW50aWFsVHJhbnNmZXJXaXRoUHJvb2ZNZXRob2RJZCxcbiAgYnVpbGRDb25maWRlbnRpYWxUcmFuc2ZlckJ5SGFuZGxlQ2FsbGRhdGEsXG4gIG9wdGlvbmFsRGVwcyxcbiAgUmVjb3Zlck9wdGlvbnMsXG4gIFJlY292ZXJ5SW5mbyxcbiAgT2ZmbGluZVZhdWx0VHhJbmZvLFxuICBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnMsXG4gIGFjbE11bHRpY2FsbE1ldGhvZElkLFxuICBjYWxsRnJvbVBhcmVudE1ldGhvZElkLFxuICBkZWNvZGVXcmFwQ2FsbGRhdGEsXG4gIHdyYXBNZXRob2RJZCxcbiAgYXNzZXJ0V3JhcEFtb3VudEZpdHNVaW50NjQsXG4gIGRlY29kZVVud3JhcENhbGxkYXRhLFxuICB1bndyYXBNZXRob2RJZCxcbiAgZGVjb2RlRmluYWxpemVVbndyYXBDYWxsZGF0YSxcbiAgZmluYWxpemVVbndyYXBNZXRob2RJZCxcbiAgVUlOVDY0X01BWCxcbiAgZGVjb2RlVHJhbnNmZXJEYXRhLFxufSBmcm9tICdAYml0Z28tYmV0YS9hYnN0cmFjdC1ldGgnO1xuaW1wb3J0IHsgYmlwMzIgfSBmcm9tICdAYml0Z28tYmV0YS9zZWNwMjU2azEnO1xuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuXG5pbXBvcnQgeyBFdGggfSBmcm9tICcuL2V0aCc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvbkJ1aWxkZXIgfSBmcm9tICcuL2xpYic7XG5cbmV4cG9ydCB7IEVyYzc5ODRUb2tlbkNvbmZpZyB9O1xuXG5leHBvcnQgY2xhc3MgRXJjNzk4NFRva2VuIGV4dGVuZHMgRXRoIHtcbiAgcHVibGljIHJlYWRvbmx5IHRva2VuQ29uZmlnOiBFcmM3OTg0VG9rZW5Db25maWc7XG4gIHByb3RlY3RlZCByZWFkb25seSBzZW5kTWV0aG9kTmFtZTogJ3NlbmRNdWx0aVNpZycgfCAnc2VuZE11bHRpU2lnVG9rZW4nO1xuICBzdGF0aWMgY29pbk5hbWVzOiBDb2luTmFtZXMgPSB7XG4gICAgTWFpbm5ldDogJ2V0aCcsXG4gICAgVGVzdG5ldDogJ2h0ZXRoJyxcbiAgfTtcblxuICBjb25zdHJ1Y3RvcihiaXRnbzogQml0R29CYXNlLCB0b2tlbkNvbmZpZzogRXJjNzk4NFRva2VuQ29uZmlnKSB7XG4gICAgY29uc3Qgc3RhdGljc0NvaW4gPSBjb2lucy5nZXQodG9rZW5Db25maWcuY29pbik7XG4gICAgc3VwZXIoYml0Z28sIHN0YXRpY3NDb2luKTtcbiAgICB0aGlzLnRva2VuQ29uZmlnID0gdG9rZW5Db25maWc7XG4gICAgLy8gRVJDNzk4NCBjb25maWRlbnRpYWwgdHJhbnNmZXJzIHVzZSBzZW5kTXVsdGlTaWcgKG5vdCBzZW5kTXVsdGlTaWdUb2tlbikgYmVjYXVzZVxuICAgIC8vIHRoZSBjYWxsZGF0YSBwYXJhbWV0ZXIgaXMgcmVxdWlyZWQgdG8gY2FycnkgY29uZmlkZW50aWFsVHJhbnNmZXIocmVjaXBpZW50LCBlbmNyeXB0ZWRIYW5kbGUsIGlucHV0UHJvb2YpLlxuICAgIC8vIHNlbmRNdWx0aVNpZ1Rva2VuIGhhcyBubyBkYXRhIHBhcmFtZXRlciBhbmQgY2Fubm90IGNhcnJ5IGlubmVyIGNhbGxkYXRhLlxuICAgIHRoaXMuc2VuZE1ldGhvZE5hbWUgPSAnc2VuZE11bHRpU2lnJztcbiAgfVxuXG4gIHN0YXRpYyBjcmVhdGVUb2tlbkNvbnN0cnVjdG9yKGNvbmZpZzogRXJjNzk4NFRva2VuQ29uZmlnKTogQ29pbkNvbnN0cnVjdG9yIHtcbiAgICByZXR1cm4gKGJpdGdvOiBCaXRHb0Jhc2UpID0+IG5ldyBFcmM3OTg0VG9rZW4oYml0Z28sIGNvbmZpZyk7XG4gIH1cblxuICBzdGF0aWMgY3JlYXRlVG9rZW5Db25zdHJ1Y3RvcnMoXG4gICAgdG9rZW5Db25maWdzOiBFcmM3OTg0VG9rZW5Db25maWdbXSA9IFtcbiAgICAgIC4uLnRva2Vucy5iaXRjb2luLmV0aC5jb25maWRlbnRpYWxUb2tlbnMsXG4gICAgICAuLi50b2tlbnMudGVzdG5ldC5ldGguY29uZmlkZW50aWFsVG9rZW5zLFxuICAgIF1cbiAgKTogTmFtZWRDb2luQ29uc3RydWN0b3JbXSB7XG4gICAgY29uc3QgdG9rZW5zQ3RvcnM6IE5hbWVkQ29pbkNvbnN0cnVjdG9yW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHRva2VuIG9mIHRva2VuQ29uZmlncykge1xuICAgICAgY29uc3QgdG9rZW5Db25zdHJ1Y3RvciA9IEVyYzc5ODRUb2tlbi5jcmVhdGVUb2tlbkNvbnN0cnVjdG9yKHRva2VuKTtcbiAgICAgIHRva2Vuc0N0b3JzLnB1c2goeyBuYW1lOiB0b2tlbi50eXBlLCBjb2luQ29uc3RydWN0b3I6IHRva2VuQ29uc3RydWN0b3IgfSk7XG4gICAgICB0b2tlbnNDdG9ycy5wdXNoKHsgbmFtZTogdG9rZW4udG9rZW5Db250cmFjdEFkZHJlc3MsIGNvaW5Db25zdHJ1Y3RvcjogdG9rZW5Db25zdHJ1Y3RvciB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRva2Vuc0N0b3JzO1xuICB9XG5cbiAgZ2V0IHR5cGUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50b2tlbkNvbmZpZy50eXBlO1xuICB9XG5cbiAgZ2V0IG5hbWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50b2tlbkNvbmZpZy5uYW1lO1xuICB9XG5cbiAgZ2V0IGNvaW4oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50b2tlbkNvbmZpZy5jb2luO1xuICB9XG5cbiAgZ2V0IG5ldHdvcmsoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50b2tlbkNvbmZpZy5uZXR3b3JrO1xuICB9XG5cbiAgZ2V0IHRva2VuQ29udHJhY3RBZGRyZXNzKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMudG9rZW5Db25maWcudG9rZW5Db250cmFjdEFkZHJlc3M7XG4gIH1cblxuICBnZXQgZGVjaW1hbFBsYWNlcygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnRva2VuQ29uZmlnLmRlY2ltYWxQbGFjZXM7XG4gIH1cblxuICBnZXRDaGFpbigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRva2VuQ29uZmlnLnR5cGU7XG4gIH1cblxuICBnZXRGdWxsTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiAnRVJDNzk4NCBDb25maWRlbnRpYWwgVG9rZW4nO1xuICB9XG5cbiAgZ2V0QmFzZUZhY3RvcigpOiBudW1iZXIge1xuICAgIHJldHVybiBNYXRoLnBvdygxMCwgdGhpcy50b2tlbkNvbmZpZy5kZWNpbWFsUGxhY2VzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGbGFnIGZvciBzZW5kaW5nIHZhbHVlIG9mIDAuXG4gICAqIEVSQy03OTg0IGNvbmZpZGVudGlhbCB0cmFuc2ZlcnMgYWx3YXlzIGNhcnJ5IGFuIGVuY3J5cHRlZCBhbW91bnQ7IHplcm8tdmFsdWUgc2VuZHMgYXJlIG5vdCBtZWFuaW5nZnVsLlxuICAgKi9cbiAgdmFsdWVsZXNzVHJhbnNmZXJBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGbGFnIGZvciBzZW5kaW5nIGRhdGEgYWxvbmcgd2l0aCB0cmFuc2FjdGlvbnMgdmlhIHRoZSBzdGFuZGFyZCB0b2tlbi1zZW5kIEFQSS5cbiAgICogUmV0dXJucyBmYWxzZSBiZWNhdXNlIEVSQy03OTg0IHNlbmRzIHVzZSBjb25maWRlbnRpYWxUcmFuc2ZlcigpIGNhbGxkYXRhIGJ1aWx0XG4gICAqIGJ5IFdQLCBub3QgYW4gYXJiaXRyYXJ5IGRhdGEgZmllbGQgb24gdGhlIHNlbmQgcGFyYW1zLlxuICAgKiBOb3RlOiB0aGlzIGRvZXMgbm90IHByZXZlbnQgY2FsbGRhdGEtYmFzZWQgZmxvd3MgbGlrZSBnZXREZWxlZ2F0aW9uQnVpbGRlcigpLFxuICAgKiB3aGljaCBieXBhc3MgdGhlIHRva2VuLXNlbmQgcGF0aCBlbnRpcmVseS5cbiAgICovXG4gIHRyYW5zYWN0aW9uRGF0YUFsbG93ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICovXG4gIHN1cHBvcnRzVHNzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICovXG4gIGdldE1QQ0FsZ29yaXRobSgpOiBNUENBbGdvcml0aG0ge1xuICAgIHJldHVybiAnZWNkc2EnO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFRyYW5zYWN0aW9uQnVpbGRlcigpOiBUcmFuc2FjdGlvbkJ1aWxkZXIge1xuICAgIHJldHVybiBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyKGNvaW5zLmdldCh0aGlzLmdldEJhc2VDaGFpbigpKSk7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKi9cbiAgYXN5bmMgdmVyaWZ5VHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAocGFyYW1zLnR4UGFyYW1zPy50eXBlID09PSAnZW5hYmxldG9rZW4nKSB7XG4gICAgICByZXR1cm4gdGhpcy52ZXJpZnlFbmFibGVUb2tlblRyYW5zYWN0aW9uKHBhcmFtcyk7XG4gICAgfVxuICAgIGlmIChwYXJhbXMudHhQYXJhbXM/LnR5cGUgPT09ICd3cmFwJykge1xuICAgICAgcmV0dXJuIHRoaXMudmVyaWZ5V3JhcFRyYW5zYWN0aW9uKHBhcmFtcyk7XG4gICAgfVxuICAgIGlmIChwYXJhbXMudHhQYXJhbXM/LnR5cGUgPT09ICd1bndyYXAnKSB7XG4gICAgICByZXR1cm4gdGhpcy52ZXJpZnlVbndyYXBUcmFuc2FjdGlvbihwYXJhbXMpO1xuICAgIH1cbiAgICBpZiAocGFyYW1zLnR4UGFyYW1zPy50eXBlID09PSAnZmluYWxpemVVbndyYXAnKSB7XG4gICAgICByZXR1cm4gdGhpcy52ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uKHBhcmFtcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLmlzQ29uc29saWRhdGlvblRyYW5zYWN0aW9uKHBhcmFtcykpIHtcbiAgICAgIHJldHVybiB0aGlzLnZlcmlmeUNvbmZpZGVudGlhbENvbnNvbGlkYXRpb24ocGFyYW1zKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXIocGFyYW1zKTtcbiAgfVxuXG4gIHByaXZhdGUgaXNDb25zb2xpZGF0aW9uVHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnMpOiBib29sZWFuIHtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB2ZXJpZmljYXRpb24gfSA9IHBhcmFtcztcbiAgICByZXR1cm4gISEoXG4gICAgICB2ZXJpZmljYXRpb24/LmNvbnNvbGlkYXRpb25Ub0Jhc2VBZGRyZXNzIHx8XG4gICAgICB0eFByZWJ1aWxkPy5jb25zb2xpZGF0ZUlkIHx8XG4gICAgICB0eFBhcmFtcz8udHlwZSA9PT0gJ2NvbnNvbGlkYXRlJyB8fFxuICAgICAgLy8gVFNTIHNpZ25pbmcgcGF0aDogcmVzb2x2ZUVmZmVjdGl2ZVR4UGFyYW1zIHNldHMgdHlwZSBmcm9tIGludGVudC5pbnRlbnRUeXBlIHdoaWNoIGlzXG4gICAgICAvLyAnY29uc29saWRhdGVUb2tlbicgZm9yIEVSQy03OTg0IHRva2VuIGNvbnNvbGlkYXRpb25zLiB0eFByZWJ1aWxkIGhhcyBvbmx5IHR4SGV4XG4gICAgICAvLyAobm8gY29uc29saWRhdGVJZCkgaW4gdGhpcyBwYXRoLlxuICAgICAgdHhQYXJhbXM/LnR5cGUgPT09ICdjb25zb2xpZGF0ZVRva2VuJyB8fFxuICAgICAgdHhQYXJhbXM/LnByZWJ1aWxkVHg/LmNvbnNvbGlkYXRlSWRcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIFdyYXBFUkM3OTg0IChzaGllbGQpIHRyYW5zYWN0aW9ucy5cbiAgICpcbiAgICogVFNTIC8gZGlyZWN0IHNoYXBlOlxuICAgKiAgIHR4LnRvICAgPSB3cmFwcGVyIGNvbnRyYWN0XG4gICAqICAgdHguZGF0YSA9IHdyYXAoYmFzZUFkZHJlc3MsIGFtb3VudClcbiAgICpcbiAgICogTXVsdGlzaWcgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IHdhbGxldCBjb250cmFjdFxuICAgKiAgIHR4LmRhdGEgPSBzZW5kTXVsdGlTaWcod3JhcHBlciwgMCwgd3JhcChiYXNlQWRkcmVzcywgYW1vdW50KSwgLi4uKVxuICAgKlxuICAgKiBDaGVja3M6IHdyYXBwZXIgYWRkcmVzcywgc2VsZi1kaXJlY3RlZCBgdG9gID09IGJhc2UsIGFtb3VudCA+IDAsIGFtb3VudCBtYXRjaGVzXG4gICAqIHJlY2lwaWVudHMsIGFuZCBmbG9vcihhbW91bnQgLyByYXRlKSBmaXRzIHVpbnQ2NCB3aGVuIHN0YXRpY3MgcmF0ZSBpcyBwcmVzZW50LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlXcmFwVHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQgfSA9IHBhcmFtcztcblxuICAgIGlmICghdHhQcmVidWlsZD8udHhIZXgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5V3JhcFRyYW5zYWN0aW9uOiBtaXNzaW5nIHR4SGV4IGluIHR4UHJlYnVpbGQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgIHR4QnVpbGRlci5mcm9tKHR4UHJlYnVpbGQudHhIZXgpO1xuICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG5cbiAgICBsZXQgd3JhcHBlckFkZHJlc3M6IHN0cmluZztcbiAgICBsZXQgd3JhcENhbGxkYXRhOiBzdHJpbmc7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKHR4SnNvbi5kYXRhLnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aChzZW5kTXVsdGlzaWdNZXRob2RJZC50b0xvd2VyQ2FzZSgpKSkge1xuICAgICAgICBjb25zdCBkZWNvZGVkID0gZGVjb2RlVHJhbnNmZXJEYXRhKHR4SnNvbi5kYXRhKTtcbiAgICAgICAgd3JhcHBlckFkZHJlc3MgPSBkZWNvZGVkLnRvO1xuICAgICAgICB3cmFwQ2FsbGRhdGEgPSBkZWNvZGVkLmRhdGEgYXMgc3RyaW5nO1xuICAgICAgICBpZiAoZGVjb2RlZC5hbW91bnQgIT09ICcwJykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZXhwZWN0ZWQgc2VuZE11bHRpU2lnIHZhbHVlIDAgYnV0IGdvdCAke2RlY29kZWQuYW1vdW50fWApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHR4SnNvbi5kYXRhLnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aCh3cmFwTWV0aG9kSWQudG9Mb3dlckNhc2UoKSkpIHtcbiAgICAgICAgd3JhcHBlckFkZHJlc3MgPSB0eEpzb24udG8gYXMgc3RyaW5nO1xuICAgICAgICB3cmFwQ2FsbGRhdGEgPSB0eEpzb24uZGF0YTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdW5leHBlY3RlZCBtZXRob2QgSUQgJHt0eEpzb24uZGF0YS5zbGljZSgwLCAxMCl9YCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGB2ZXJpZnlXcmFwVHJhbnNhY3Rpb246IGZhaWxlZCB0byBkZWNvZGUgd3JhcCBjYWxsZGF0YSDigJQgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICB9XG5cbiAgICBpZiAod3JhcHBlckFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gdGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlXcmFwVHJhbnNhY3Rpb246IHdyYXBwZXIgYWRkcmVzcyBtaXNtYXRjaCDigJQgYCArXG4gICAgICAgICAgYGV4cGVjdGVkICR7dGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzc30sIGdvdCAke3dyYXBwZXJBZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IHRvOiBzdHJpbmc7XG4gICAgbGV0IGFtb3VudDogc3RyaW5nO1xuICAgIHRyeSB7XG4gICAgICAoeyB0bywgYW1vdW50IH0gPSBkZWNvZGVXcmFwQ2FsbGRhdGEod3JhcENhbGxkYXRhKSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGB2ZXJpZnlXcmFwVHJhbnNhY3Rpb246IGludmFsaWQgd3JhcCBpbm5lciBjYWxsZGF0YSDigJQgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICB9XG5cbiAgICBpZiAoIUVyYzc5ODRUb2tlbi5pc1Bvc2l0aXZlSW50ZWdlclN0cmluZyhhbW91bnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeVdyYXBUcmFuc2FjdGlvbjogYW1vdW50IG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIHN0cmluZywgZ290ICcke2Ftb3VudH0nYCk7XG4gICAgfVxuXG4gICAgY29uc3QgYmFzZUFkZHJlc3MgPSB0aGlzLmdldFdhbGxldEJhc2VBZGRyZXNzKHdhbGxldCk7XG4gICAgaWYgKCFiYXNlQWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlXcmFwVHJhbnNhY3Rpb246IHVuYWJsZSB0byBkZXRlcm1pbmUgd2FsbGV0IGJhc2UgYWRkcmVzcycpO1xuICAgIH1cbiAgICBpZiAodG8udG9Mb3dlckNhc2UoKSAhPT0gYmFzZUFkZHJlc3MudG9Mb3dlckNhc2UoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5V3JhcFRyYW5zYWN0aW9uOiB3cmFwIHJlY2lwaWVudCBtdXN0IGVxdWFsIHdhbGxldCBiYXNlIGFkZHJlc3Mg4oCUIGV4cGVjdGVkICR7YmFzZUFkZHJlc3N9LCBnb3QgJHt0b31gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGV4cGVjdGVkQW1vdW50ID0gdHhQYXJhbXM/LnJlY2lwaWVudHM/LlswXT8uYW1vdW50ID8/IHR4UHJlYnVpbGQuYnVpbGRQYXJhbXM/LnJlY2lwaWVudHM/LlswXT8uYW1vdW50O1xuICAgIGlmIChleHBlY3RlZEFtb3VudCAhPT0gdW5kZWZpbmVkICYmIFN0cmluZyhleHBlY3RlZEFtb3VudCkgIT09IGFtb3VudCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5V3JhcFRyYW5zYWN0aW9uOiBhbW91bnQgbWlzbWF0Y2gg4oCUIGNhbGxkYXRhIGhhcyAnJHthbW91bnR9JyBidXQgcGFyYW1zIGhhdmUgJyR7ZXhwZWN0ZWRBbW91bnR9J2BcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgcmF0ZSA9IHRoaXMudG9rZW5Db25maWcucmF0ZTtcbiAgICBpZiAocmF0ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhc3NlcnRXcmFwQW1vdW50Rml0c1VpbnQ2NChhbW91bnQsIHJhdGUpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeVdyYXBUcmFuc2FjdGlvbjogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodHhKc29uLnZhbHVlICE9PSB1bmRlZmluZWQgJiYgdHhKc29uLnZhbHVlICE9PSAnMCcgJiYgdHhKc29uLnZhbHVlICE9PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeVdyYXBUcmFuc2FjdGlvbjogZXhwZWN0ZWQgdHJhbnNhY3Rpb24gdmFsdWUgMCBidXQgZ290ICR7dHhKc29uLnZhbHVlfWApO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIFVud3JhcEVSQzc5ODQgKHVuc2hpZWxkIHBoYXNlLTEpIHRyYW5zYWN0aW9ucy5cbiAgICpcbiAgICogVFNTIC8gZGlyZWN0IHNoYXBlOlxuICAgKiAgIHR4LnRvICAgPSB3cmFwcGVyIGNvbnRyYWN0XG4gICAqICAgdHguZGF0YSA9IHVud3JhcChiYXNlLCBiYXNlLCBlbmNyeXB0ZWRBbW91bnQsIGlucHV0UHJvb2YpXG4gICAqXG4gICAqIE11bHRpc2lnIHNoYXBlOlxuICAgKiAgIHR4LnRvICAgPSB3YWxsZXQgY29udHJhY3RcbiAgICogICB0eC5kYXRhID0gc2VuZE11bHRpU2lnKHdyYXBwZXIsIDAsIHVud3JhcChiYXNlLCBiYXNlLCAuLi4pLCAuLi4pXG4gICAqXG4gICAqIHYxIGlzIHNlbGYtZGlyZWN0ZWQgb25seTogZnJvbSA9PSB0byA9PSB3YWxsZXQgYmFzZSBhZGRyZXNzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdHhQcmVidWlsZCwgd2FsbGV0IH0gPSBwYXJhbXM7XG5cbiAgICBpZiAoIXR4UHJlYnVpbGQ/LnR4SGV4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiBtaXNzaW5nIHR4SGV4IGluIHR4UHJlYnVpbGQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgIHR4QnVpbGRlci5mcm9tKHR4UHJlYnVpbGQudHhIZXgpO1xuICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG5cbiAgICBsZXQgd3JhcHBlckFkZHJlc3M6IHN0cmluZztcbiAgICBsZXQgdW53cmFwQ2FsbGRhdGE6IHN0cmluZztcblxuICAgIHRyeSB7XG4gICAgICBpZiAodHhKc29uLmRhdGEudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKHNlbmRNdWx0aXNpZ01ldGhvZElkLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVUcmFuc2ZlckRhdGEodHhKc29uLmRhdGEpO1xuICAgICAgICB3cmFwcGVyQWRkcmVzcyA9IGRlY29kZWQudG87XG4gICAgICAgIHVud3JhcENhbGxkYXRhID0gZGVjb2RlZC5kYXRhIGFzIHN0cmluZztcbiAgICAgICAgaWYgKGRlY29kZWQuYW1vdW50ICE9PSAnMCcpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGV4cGVjdGVkIHNlbmRNdWx0aVNpZyB2YWx1ZSAwIGJ1dCBnb3QgJHtkZWNvZGVkLmFtb3VudH1gKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0eEpzb24uZGF0YS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgodW53cmFwTWV0aG9kSWQudG9Mb3dlckNhc2UoKSkpIHtcbiAgICAgICAgd3JhcHBlckFkZHJlc3MgPSB0eEpzb24udG8gYXMgc3RyaW5nO1xuICAgICAgICB1bndyYXBDYWxsZGF0YSA9IHR4SnNvbi5kYXRhO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB1bmV4cGVjdGVkIG1ldGhvZCBJRCAke3R4SnNvbi5kYXRhLnNsaWNlKDAsIDEwKX1gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiBmYWlsZWQgdG8gZGVjb2RlIHVud3JhcCBjYWxsZGF0YSDigJQgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICB9XG5cbiAgICBpZiAod3JhcHBlckFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gdGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbjogd3JhcHBlciBhZGRyZXNzIG1pc21hdGNoIOKAlCBleHBlY3RlZCAke3RoaXMudG9rZW5Db250cmFjdEFkZHJlc3N9LCBnb3QgJHt3cmFwcGVyQWRkcmVzc31gXG4gICAgICApO1xuICAgIH1cblxuICAgIGxldCBmcm9tOiBzdHJpbmc7XG4gICAgbGV0IHRvOiBzdHJpbmc7XG4gICAgbGV0IGVuY3J5cHRlZEFtb3VudDogc3RyaW5nO1xuICAgIGxldCBpbnB1dFByb29mOiBzdHJpbmc7XG4gICAgdHJ5IHtcbiAgICAgICh7IGZyb20sIHRvLCBlbmNyeXB0ZWRBbW91bnQsIGlucHV0UHJvb2YgfSA9IGRlY29kZVVud3JhcENhbGxkYXRhKHVud3JhcENhbGxkYXRhKSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGB2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbjogaW52YWxpZCB1bndyYXAgaW5uZXIgY2FsbGRhdGEg4oCUICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgYmFzZUFkZHJlc3MgPSB0aGlzLmdldFdhbGxldEJhc2VBZGRyZXNzKHdhbGxldCk7XG4gICAgaWYgKCFiYXNlQWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbjogdW5hYmxlIHRvIGRldGVybWluZSB3YWxsZXQgYmFzZSBhZGRyZXNzJyk7XG4gICAgfVxuICAgIGlmIChmcm9tLnRvTG93ZXJDYXNlKCkgIT09IGJhc2VBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeVVud3JhcFRyYW5zYWN0aW9uOiB1bndyYXAgZnJvbSBtdXN0IGVxdWFsIHdhbGxldCBiYXNlIGFkZHJlc3Mg4oCUIGV4cGVjdGVkICR7YmFzZUFkZHJlc3N9LCBnb3QgJHtmcm9tfWBcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICh0by50b0xvd2VyQ2FzZSgpICE9PSBiYXNlQWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbjogdW53cmFwIHRvIG11c3QgZXF1YWwgd2FsbGV0IGJhc2UgYWRkcmVzcyDigJQgZXhwZWN0ZWQgJHtiYXNlQWRkcmVzc30sIGdvdCAke3RvfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFlbmNyeXB0ZWRBbW91bnQgfHwgZW5jcnlwdGVkQW1vdW50ID09PSAnMHgnIHx8IC9eMHgwKyQvLnRlc3QoZW5jcnlwdGVkQW1vdW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlVbndyYXBUcmFuc2FjdGlvbjogZW5jcnlwdGVkQW1vdW50IGlzIG1pc3Npbmcgb3IgZW1wdHknKTtcbiAgICB9XG4gICAgaWYgKCFpbnB1dFByb29mIHx8IGlucHV0UHJvb2YgPT09ICcweCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5VW53cmFwVHJhbnNhY3Rpb246IGlucHV0UHJvb2YgaXMgbWlzc2luZyBvciBlbXB0eScpO1xuICAgIH1cblxuICAgIGlmICh0eEpzb24udmFsdWUgIT09IHVuZGVmaW5lZCAmJiB0eEpzb24udmFsdWUgIT09ICcwJyAmJiB0eEpzb24udmFsdWUgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5VW53cmFwVHJhbnNhY3Rpb246IGV4cGVjdGVkIHRyYW5zYWN0aW9uIHZhbHVlIDAgYnV0IGdvdCAke3R4SnNvbi52YWx1ZX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmllcyBGaW5hbGl6ZVVud3JhcEVSQzc5ODQgKHVuc2hpZWxkIHBoYXNlLTIpIHRyYW5zYWN0aW9ucy5cbiAgICpcbiAgICogVFNTIC8gZGlyZWN0IHNoYXBlOlxuICAgKiAgIHR4LnRvICAgPSB3cmFwcGVyIGNvbnRyYWN0XG4gICAqICAgdHguZGF0YSA9IGZpbmFsaXplVW53cmFwKHJlcXVlc3RJZCwgY2xlYXJ0ZXh0QW1vdW50LCBkZWNyeXB0aW9uUHJvb2YpXG4gICAqXG4gICAqIE11bHRpc2lnIHNoYXBlOlxuICAgKiAgIHR4LnRvICAgPSB3YWxsZXQgY29udHJhY3RcbiAgICogICB0eC5kYXRhID0gc2VuZE11bHRpU2lnKHdyYXBwZXIsIDAsIGZpbmFsaXplVW53cmFwKC4uLiksIC4uLilcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdmVyaWZ5RmluYWxpemVVbndyYXBUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQgfSA9IHBhcmFtcztcblxuICAgIGlmICghdHhQcmVidWlsZD8udHhIZXgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5RmluYWxpemVVbndyYXBUcmFuc2FjdGlvbjogbWlzc2luZyB0eEhleCBpbiB0eFByZWJ1aWxkJyk7XG4gICAgfVxuXG4gICAgY29uc3QgdHhCdWlsZGVyID0gdGhpcy5nZXRUcmFuc2FjdGlvbkJ1aWxkZXIoKTtcbiAgICB0eEJ1aWxkZXIuZnJvbSh0eFByZWJ1aWxkLnR4SGV4KTtcbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIGNvbnN0IHR4SnNvbiA9IHR4LnRvSnNvbigpO1xuXG4gICAgbGV0IHdyYXBwZXJBZGRyZXNzOiBzdHJpbmc7XG4gICAgbGV0IGZpbmFsaXplQ2FsbGRhdGE6IHN0cmluZztcblxuICAgIHRyeSB7XG4gICAgICBpZiAodHhKc29uLmRhdGEudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKHNlbmRNdWx0aXNpZ01ldGhvZElkLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVUcmFuc2ZlckRhdGEodHhKc29uLmRhdGEpO1xuICAgICAgICB3cmFwcGVyQWRkcmVzcyA9IGRlY29kZWQudG87XG4gICAgICAgIGZpbmFsaXplQ2FsbGRhdGEgPSBkZWNvZGVkLmRhdGEgYXMgc3RyaW5nO1xuICAgICAgICBpZiAoZGVjb2RlZC5hbW91bnQgIT09ICcwJykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZXhwZWN0ZWQgc2VuZE11bHRpU2lnIHZhbHVlIDAgYnV0IGdvdCAke2RlY29kZWQuYW1vdW50fWApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHR4SnNvbi5kYXRhLnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aChmaW5hbGl6ZVVud3JhcE1ldGhvZElkLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIHdyYXBwZXJBZGRyZXNzID0gdHhKc29uLnRvIGFzIHN0cmluZztcbiAgICAgICAgZmluYWxpemVDYWxsZGF0YSA9IHR4SnNvbi5kYXRhO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB1bmV4cGVjdGVkIG1ldGhvZCBJRCAke3R4SnNvbi5kYXRhLnNsaWNlKDAsIDEwKX1gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uOiBmYWlsZWQgdG8gZGVjb2RlIGZpbmFsaXplVW53cmFwIGNhbGxkYXRhIOKAlCAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKHdyYXBwZXJBZGRyZXNzLnRvTG93ZXJDYXNlKCkgIT09IHRoaXMudG9rZW5Db250cmFjdEFkZHJlc3MudG9Mb3dlckNhc2UoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdmVyaWZ5RmluYWxpemVVbndyYXBUcmFuc2FjdGlvbjogd3JhcHBlciBhZGRyZXNzIG1pc21hdGNoIOKAlCBleHBlY3RlZCAke3RoaXMudG9rZW5Db250cmFjdEFkZHJlc3N9LCBnb3QgJHt3cmFwcGVyQWRkcmVzc31gXG4gICAgICApO1xuICAgIH1cblxuICAgIGxldCByZXF1ZXN0SWQ6IHN0cmluZztcbiAgICBsZXQgY2xlYXJ0ZXh0QW1vdW50OiBzdHJpbmc7XG4gICAgbGV0IGRlY3J5cHRpb25Qcm9vZjogc3RyaW5nO1xuICAgIHRyeSB7XG4gICAgICAoeyByZXF1ZXN0SWQsIGNsZWFydGV4dEFtb3VudCwgZGVjcnlwdGlvblByb29mIH0gPSBkZWNvZGVGaW5hbGl6ZVVud3JhcENhbGxkYXRhKGZpbmFsaXplQ2FsbGRhdGEpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uOiBpbnZhbGlkIGZpbmFsaXplVW53cmFwIGlubmVyIGNhbGxkYXRhIOKAlCAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFyZXF1ZXN0SWQgfHwgcmVxdWVzdElkID09PSAnMHgnIHx8IC9eMHgwKyQvLnRlc3QocmVxdWVzdElkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uOiByZXF1ZXN0SWQgaXMgbWlzc2luZyBvciBlbXB0eScpO1xuICAgIH1cbiAgICBpZiAoIUVyYzc5ODRUb2tlbi5pc1Bvc2l0aXZlSW50ZWdlclN0cmluZyhjbGVhcnRleHRBbW91bnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlGaW5hbGl6ZVVud3JhcFRyYW5zYWN0aW9uOiBjbGVhcnRleHRBbW91bnQgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIgc3RyaW5nLCBnb3QgJyR7Y2xlYXJ0ZXh0QW1vdW50fSdgXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoQmlnSW50KGNsZWFydGV4dEFtb3VudCkgPiBVSU5UNjRfTUFYKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb246IGNsZWFydGV4dEFtb3VudCBleGNlZWRzIHVpbnQ2NCcpO1xuICAgIH1cbiAgICBpZiAoIWRlY3J5cHRpb25Qcm9vZiB8fCBkZWNyeXB0aW9uUHJvb2YgPT09ICcweCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5RmluYWxpemVVbndyYXBUcmFuc2FjdGlvbjogZGVjcnlwdGlvblByb29mIGlzIG1pc3Npbmcgb3IgZW1wdHknKTtcbiAgICB9XG5cbiAgICBjb25zdCBleHBlY3RlZEFtb3VudCA9IHR4UGFyYW1zPy5yZWNpcGllbnRzPy5bMF0/LmFtb3VudCA/PyB0eFByZWJ1aWxkLmJ1aWxkUGFyYW1zPy5yZWNpcGllbnRzPy5bMF0/LmFtb3VudDtcbiAgICBpZiAoZXhwZWN0ZWRBbW91bnQgIT09IHVuZGVmaW5lZCAmJiBTdHJpbmcoZXhwZWN0ZWRBbW91bnQpICE9PSBjbGVhcnRleHRBbW91bnQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb246IGFtb3VudCBtaXNtYXRjaCDigJQgY2FsbGRhdGEgaGFzICcke2NsZWFydGV4dEFtb3VudH0nIGJ1dCBwYXJhbXMgaGF2ZSAnJHtleHBlY3RlZEFtb3VudH0nYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAodHhKc29uLnZhbHVlICE9PSB1bmRlZmluZWQgJiYgdHhKc29uLnZhbHVlICE9PSAnMCcgJiYgdHhKc29uLnZhbHVlICE9PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeUZpbmFsaXplVW53cmFwVHJhbnNhY3Rpb246IGV4cGVjdGVkIHRyYW5zYWN0aW9uIHZhbHVlIDAgYnV0IGdvdCAke3R4SnNvbi52YWx1ZX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0V2FsbGV0QmFzZUFkZHJlc3Mod2FsbGV0OiBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnNbJ3dhbGxldCddKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXdhbGxldCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY29uc3QgY29pblNwZWNpZmljID0gdHlwZW9mIHdhbGxldC5jb2luU3BlY2lmaWMgPT09ICdmdW5jdGlvbicgPyB3YWxsZXQuY29pblNwZWNpZmljKCkgOiB3YWxsZXQuY29pblNwZWNpZmljO1xuICAgIGNvbnN0IGV0aENvaW5TcGVjaWZpYyA9IGNvaW5TcGVjaWZpYyBhcyB7IGJhc2VBZGRyZXNzPzogc3RyaW5nOyByb290QWRkcmVzcz86IHN0cmluZyB9IHwgdW5kZWZpbmVkO1xuICAgIHJldHVybiBldGhDb2luU3BlY2lmaWM/LmJhc2VBZGRyZXNzID8/IGV0aENvaW5TcGVjaWZpYz8ucm9vdEFkZHJlc3M7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpZXMgRVJDLTc5ODQgZm9yd2FyZGVyIGNvbnNvbGlkYXRpb24gKGZsdXNoKSB0cmFuc2FjdGlvbnMuXG4gICAqXG4gICAqIE11bHRpc2lnIHNoYXBlOlxuICAgKiAgIHR4LnRvICAgPSB3YWxsZXQgY29udHJhY3RcbiAgICogICB0eC5kYXRhID0gc2VuZE11bHRpU2lnKGZvcndhcmRlciwgMCwgY2FsbEZyb21QYXJlbnQodG9rZW4sIDAsIGNvbmZpZGVudGlhbFRyYW5zZmVyTm9Qcm9vZihiYXNlLCBoYW5kbGUpKSwgLi4uKVxuICAgKlxuICAgKiBUU1MgLyBkaXJlY3Qgc2hhcGU6XG4gICAqICAgdHgudG8gICA9IGZvcndhcmRlciBjb250cmFjdFxuICAgKiAgIHR4LmRhdGEgPSBjYWxsRnJvbVBhcmVudCh0b2tlbiwgMCwgY29uZmlkZW50aWFsVHJhbnNmZXJOb1Byb29mKGJhc2UsIGhhbmRsZSkpXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZlcmlmeUNvbmZpZGVudGlhbENvbnNvbGlkYXRpb24ocGFyYW1zOiBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQgfSA9IHBhcmFtcztcblxuICAgIGlmICghdHhQcmVidWlsZD8udHhIZXgpIHtcbiAgICAgIGlmICghdHhQcmVidWlsZD8uY29uc29saWRhdGVJZCAmJiAhdHhQYXJhbXM/LnByZWJ1aWxkVHg/LmNvbnNvbGlkYXRlSWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlDb25maWRlbnRpYWxDb25zb2xpZGF0aW9uOiBtaXNzaW5nIGNvbnNvbGlkYXRlSWQnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25CdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLmZyb20odHhQcmVidWlsZC50eEhleCk7XG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBjb25zdCB0eEpzb24gPSB0eC50b0pzb24oKTtcblxuICAgIGxldCB0b2tlbkNvbnRyYWN0QWRkcmVzczogc3RyaW5nO1xuICAgIGxldCBwYXJlbnRBZGRyZXNzOiBzdHJpbmc7XG4gICAgbGV0IGVuY3J5cHRlZEhhbmRsZTogc3RyaW5nO1xuICAgIGxldCBmb3J3YXJkZXJBZGRyZXNzOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKHR4SnNvbi5kYXRhLnN0YXJ0c1dpdGgoc2VuZE11bHRpc2lnTWV0aG9kSWQpKSB7XG4gICAgICAgIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVTZW5kTXVsdGlTaWdGbHVzaEVSQzc5ODREYXRhKHR4SnNvbi5kYXRhKTtcbiAgICAgICAgZm9yd2FyZGVyQWRkcmVzcyA9IGRlY29kZWQuZm9yd2FyZGVyQWRkcmVzcztcbiAgICAgICAgdG9rZW5Db250cmFjdEFkZHJlc3MgPSBkZWNvZGVkLnRva2VuQ29udHJhY3RBZGRyZXNzO1xuICAgICAgICBwYXJlbnRBZGRyZXNzID0gZGVjb2RlZC5wYXJlbnRBZGRyZXNzO1xuICAgICAgICBlbmNyeXB0ZWRIYW5kbGUgPSBkZWNvZGVkLmVuY3J5cHRlZEhhbmRsZTtcbiAgICAgIH0gZWxzZSBpZiAodHhKc29uLmRhdGEuc3RhcnRzV2l0aChjYWxsRnJvbVBhcmVudE1ldGhvZElkKSkge1xuICAgICAgICBjb25zdCBkZWNvZGVkID0gZGVjb2RlRmx1c2hFUkM3OTg0Rm9yd2FyZGVyVG9rZW5DYWxsZGF0YSh0eEpzb24uZGF0YSk7XG4gICAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzID0gZGVjb2RlZC50b2tlbkNvbnRyYWN0QWRkcmVzcztcbiAgICAgICAgcGFyZW50QWRkcmVzcyA9IGRlY29kZWQucGFyZW50QWRkcmVzcztcbiAgICAgICAgZW5jcnlwdGVkSGFuZGxlID0gZGVjb2RlZC5lbmNyeXB0ZWRIYW5kbGU7XG4gICAgICAgIGZvcndhcmRlckFkZHJlc3MgPSB0eEpzb24udG87XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgbWV0aG9kIElEICR7dHhKc29uLmRhdGEuc2xpY2UoMCwgMTApfWApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbENvbnNvbGlkYXRpb246IGZhaWxlZCB0byBkZWNvZGUgY29uc29saWRhdGlvbiBjYWxsZGF0YSDigJQgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICh0b2tlbkNvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpICE9PSB0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbENvbnNvbGlkYXRpb246IHRva2VuIGNvbnRyYWN0IGFkZHJlc3MgbWlzbWF0Y2gg4oCUIGAgK1xuICAgICAgICAgIGBleHBlY3RlZCAke3RoaXMudG9rZW5Db250cmFjdEFkZHJlc3N9LCBnb3QgJHt0b2tlbkNvbnRyYWN0QWRkcmVzc31gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGJhc2VBZGRyZXNzID0gdGhpcy5nZXRXYWxsZXRCYXNlQWRkcmVzcyh3YWxsZXQpO1xuICAgIGlmICghYmFzZUFkZHJlc3MpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5Q29uZmlkZW50aWFsQ29uc29saWRhdGlvbjogdW5hYmxlIHRvIGRldGVybWluZSB3YWxsZXQgYmFzZSBhZGRyZXNzJyk7XG4gICAgfVxuICAgIGlmIChwYXJlbnRBZGRyZXNzLnRvTG93ZXJDYXNlKCkgIT09IGJhc2VBZGRyZXNzLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbENvbnNvbGlkYXRpb246IHBhcmVudCBhZGRyZXNzIG1pc21hdGNoIOKAlCBleHBlY3RlZCAke2Jhc2VBZGRyZXNzfSwgZ290ICR7cGFyZW50QWRkcmVzc31gXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghZW5jcnlwdGVkSGFuZGxlIHx8IGVuY3J5cHRlZEhhbmRsZSA9PT0gJzB4Jykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlDb25maWRlbnRpYWxDb25zb2xpZGF0aW9uOiBlbmNyeXB0ZWRIYW5kbGUgaXMgbWlzc2luZyBvciBlbXB0eSBpbiB0cmFuc2FjdGlvbiBjYWxsZGF0YScpO1xuICAgIH1cblxuICAgIGNvbnN0IGV4cGVjdGVkRm9yd2FyZGVyID1cbiAgICAgIHR4UHJlYnVpbGQucmVjaXBpZW50cz8uWzBdPy5hZGRyZXNzID8/XG4gICAgICB0eFByZWJ1aWxkLnR4SW5mbz8ucmVjaXBpZW50cz8uWzBdPy5hZGRyZXNzID8/XG4gICAgICB0eFBhcmFtcz8ucmVjaXBpZW50cz8uWzBdPy5hZGRyZXNzO1xuICAgIGlmIChmb3J3YXJkZXJBZGRyZXNzICYmIGV4cGVjdGVkRm9yd2FyZGVyKSB7XG4gICAgICBpZiAoZm9yd2FyZGVyQWRkcmVzcy50b0xvd2VyQ2FzZSgpICE9PSBleHBlY3RlZEZvcndhcmRlci50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgdmVyaWZ5Q29uZmlkZW50aWFsQ29uc29saWRhdGlvbjogZm9yd2FyZGVyIGFkZHJlc3MgbWlzbWF0Y2gg4oCUIGAgK1xuICAgICAgICAgICAgYGV4cGVjdGVkICR7ZXhwZWN0ZWRGb3J3YXJkZXJ9LCBnb3QgJHtmb3J3YXJkZXJBZGRyZXNzfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmllcyBhIGNvbmZpZGVudGlhbCB0b2tlbiB0cmFuc2ZlciAoU2VuZEVSQzc5ODQpIHRyYW5zYWN0aW9uLlxuICAgKlxuICAgKiBXaXRoIHR4SGV4IOKAlCB0d28gb24tY2hhaW4gc2hhcGVzIGFyZSBzdXBwb3J0ZWQ6XG4gICAqXG4gICAqICAgc2VuZE11bHRpU2lnLXdyYXBwZWQgKG11bHRpc2lnIC8gc21hcnQtY29udHJhY3Qgd2FsbGV0KTpcbiAgICogICAgIHR4LnRvICAgPSB3YWxsZXQgY29udHJhY3RcbiAgICogICAgIHR4LmRhdGEgPSBzZW5kTXVsdGlTaWcodG9rZW5BZGRyLCAwLCBjb25maWRlbnRpYWxUcmFuc2ZlcihyZWNpcGllbnQsIGhhbmRsZSwgcHJvb2YpLCAuLi4pXG4gICAqICAgICBUb2tlbiBjb250cmFjdCBhZGRyZXNzIGlzIGRlY29kZWQgZnJvbSB0aGUgc2VuZE11bHRpU2lnIGlubmVyIGNhbGxkYXRhLlxuICAgKlxuICAgKiAgIERpcmVjdCBjYWxsIChob3QgLyBUU1MgRU9BIHdhbGxldCk6XG4gICAqICAgICB0eC50byAgID0gdG9rZW4gY29udHJhY3RcbiAgICogICAgIHR4LmRhdGEgPSBjb25maWRlbnRpYWxUcmFuc2ZlcihyZWNpcGllbnQsIGhhbmRsZSwgcHJvb2YpXG4gICAqICAgICBUb2tlbiBjb250cmFjdCBhZGRyZXNzIGlzIHRha2VuIGZyb20gdHgudG8uXG4gICAqXG4gICAqICAgRm9yIGJvdGggc2hhcGVzIHRoZSB2ZXJpZmllciBjaGVja3M6XG4gICAqICAgICAxLiBUb2tlbiBjb250cmFjdCBhZGRyZXNzIG1hdGNoZXMgdGhpcyBjb2luJ3MgdG9rZW5Db250cmFjdEFkZHJlc3MuXG4gICAqICAgICAyLiBEZWNvZGVkIHJlY2lwaWVudCBtYXRjaGVzIHR4UGFyYW1zLnJlY2lwaWVudHNbMF0uYWRkcmVzcyBvciBidWlsZFBhcmFtcy5yZWNpcGllbnRzWzBdLmFkZHJlc3MuXG4gICAqICAgICAzLiBlbmNyeXB0ZWRIYW5kbGUgYW5kIGlucHV0UHJvb2YgYXJlIHN0cnVjdHVyYWxseSBwcmVzZW50IChub24tZW1wdHkpLlxuICAgKiAgICAgNC4gdHhQYXJhbXMucmVjaXBpZW50c1swXS5hbW91bnQgaXMgYSBwb3NpdGl2ZSBpbnRlZ2VyIGFuZCBtYXRjaGVzIGJ1aWxkUGFyYW1zIHdoZW4gYm90aCBwcmVzZW50LlxuICAgKlxuICAgKiBXaXRob3V0IHR4SGV4IChmaXJzdC1zaWduZXIgLyBwcmUtc2lnbmluZyBwYXRoKTpcbiAgICogIDEuIFJlcXVpcmVzIGV4YWN0bHkgb25lIHJlY2lwaWVudCBpbiB0eFBhcmFtcy5cbiAgICogIDIuIFZhbGlkYXRlcyB0eFBhcmFtcy5yZWNpcGllbnRzWzBdLmFkZHJlc3MgaXMgYSB2YWxpZCBFdGhlcmV1bSBhZGRyZXNzLlxuICAgKiAgMy4gVmFsaWRhdGVzIHR4UGFyYW1zLnJlY2lwaWVudHNbMF0uYW1vdW50IGlzIGEgcG9zaXRpdmUgaW50ZWdlci5cbiAgICogIDQuIENyb3NzLWNoZWNrcyBhZGRyZXNzIGFuZCBhbW91bnQgYWdhaW5zdCBidWlsZFBhcmFtcyB3aGVuIHRoZSBzZXJ2ZXIgaGFzIHN0b3JlZCB0aGUgaW50ZW50LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcihwYXJhbXM6IFZlcmlmeUV0aFRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQgfSA9IHBhcmFtcztcblxuICAgIGlmICghdHhQcmVidWlsZD8udHhIZXgpIHtcbiAgICAgIC8vIE5vIHJhdyB0eCBhdmFpbGFibGUgKG11bHRpc2lnIGZpcnN0LXNpZ25lciBwYXRoKS5cbiAgICAgIC8vIFZhbGlkYXRlIEVSQzc5ODQtc3BlY2lmaWMgaW52YXJpYW50cyBmcm9tIHR4UGFyYW1zIGFuZCBidWlsZFBhcmFtcy5cbiAgICAgIGNvbnN0IHJlY2lwaWVudHMgPSB0eFBhcmFtcz8ucmVjaXBpZW50cztcbiAgICAgIGlmICghcmVjaXBpZW50cyB8fCByZWNpcGllbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiByZWNpcGllbnRzIG11c3QgY29udGFpbiBhdCBsZWFzdCBvbmUgZW50cnknKTtcbiAgICAgIH1cbiAgICAgIGlmIChyZWNpcGllbnRzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBjb25maWRlbnRpYWwgdHJhbnNmZXJzIHN1cHBvcnQgZXhhY3RseSAxIHJlY2lwaWVudCwgZ290ICR7cmVjaXBpZW50cy5sZW5ndGh9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVjaXBpZW50ID0gcmVjaXBpZW50c1swXTtcbiAgICAgIGlmICghcmVjaXBpZW50LmFkZHJlc3MgfHwgIXRoaXMuaXNWYWxpZEFkZHJlc3MocmVjaXBpZW50LmFkZHJlc3MpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdmVyaWZ5Q29uZmlkZW50aWFsVHJhbnNmZXI6IHJlY2lwaWVudCBhZGRyZXNzIGlzIG1pc3Npbmcgb3IgaW52YWxpZDogJHtyZWNpcGllbnQuYWRkcmVzc31gKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGFtb3VudFN0ciA9IFN0cmluZyhyZWNpcGllbnQuYW1vdW50KTtcbiAgICAgIGlmICghRXJjNzk4NFRva2VuLmlzUG9zaXRpdmVJbnRlZ2VyU3RyaW5nKGFtb3VudFN0cikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcjogYW1vdW50IG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIHN0cmluZyBpbiBiYXNlIHVuaXRzLCBnb3QgJyR7YW1vdW50U3RyfSdgXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICAvLyBDcm9zcy1jaGVjayBhZ2FpbnN0IGJ1aWxkUGFyYW1zIHdoZW4gdGhlIHNlcnZlciBoYXMgYWxyZWFkeSBzdG9yZWQgdGhlIGludGVudFxuICAgICAgY29uc3QgYnVpbGRQYXJhbXNSZWNpcGllbnQgPSB0eFByZWJ1aWxkPy5idWlsZFBhcmFtcz8ucmVjaXBpZW50cz8uWzBdO1xuICAgICAgaWYgKGJ1aWxkUGFyYW1zUmVjaXBpZW50Py5hZGRyZXNzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKHJlY2lwaWVudC5hZGRyZXNzLnRvTG93ZXJDYXNlKCkgIT09IGJ1aWxkUGFyYW1zUmVjaXBpZW50LmFkZHJlc3MudG9Mb3dlckNhc2UoKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcjogcmVjaXBpZW50IGFkZHJlc3MgbWlzbWF0Y2gg4oCUIGAgK1xuICAgICAgICAgICAgICBgdHhQYXJhbXMgaGFzICcke3JlY2lwaWVudC5hZGRyZXNzfScgYnV0IGJ1aWxkUGFyYW1zIGhhcyAnJHtidWlsZFBhcmFtc1JlY2lwaWVudC5hZGRyZXNzfSdgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3QgYnVpbGRQYXJhbXNBbW91bnQgPSBidWlsZFBhcmFtc1JlY2lwaWVudD8uYW1vdW50O1xuICAgICAgaWYgKGJ1aWxkUGFyYW1zQW1vdW50ICE9PSB1bmRlZmluZWQgJiYgYnVpbGRQYXJhbXNBbW91bnQgIT09IGFtb3VudFN0cikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBhbW91bnQgbWlzbWF0Y2gg4oCUIHR4UGFyYW1zIGhhcyAnJHthbW91bnRTdHJ9JyBidXQgYnVpbGRQYXJhbXMgaGFzICcke2J1aWxkUGFyYW1zQW1vdW50fSdgXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBQYXJzZSBhbmQgZGVjb2RlIHRoZSByYXcgdHJhbnNhY3Rpb25cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgIHR4QnVpbGRlci5mcm9tKHR4UHJlYnVpbGQudHhIZXgpO1xuICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG5cbiAgICBsZXQgdG9BZGRyZXNzOiBzdHJpbmc7XG4gICAgbGV0IHRva2VuQ29udHJhY3RBZGRyZXNzOiBzdHJpbmc7XG4gICAgbGV0IGVuY3J5cHRlZEhhbmRsZTogc3RyaW5nO1xuICAgIGxldCBpbnB1dFByb29mOiBzdHJpbmc7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKHR4SnNvbi5kYXRhLnN0YXJ0c1dpdGgoc2VuZE11bHRpc2lnTWV0aG9kSWQpKSB7XG4gICAgICAgIC8vIHNlbmRNdWx0aVNpZy13cmFwcGVkIHBhdGg6IHNtYXJ0LWNvbnRyYWN0IHdhbGxldCByZWxheXMgdGhlIGNvbmZpZGVudGlhbFRyYW5zZmVyIGNhbGwuXG4gICAgICAgIC8vIFRva2VuIGNvbnRyYWN0IGFkZHJlc3MgaXMgZW5jb2RlZCBpbnNpZGUgdGhlIHNlbmRNdWx0aVNpZyBjYWxsZGF0YS5cbiAgICAgICAgY29uc3QgZGVjb2RlZCA9IGRlY29kZUNvbmZpZGVudGlhbFRyYW5zZmVyRGF0YSh0eEpzb24uZGF0YSk7XG4gICAgICAgIHRvQWRkcmVzcyA9IGRlY29kZWQudG9BZGRyZXNzO1xuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzcyA9IGRlY29kZWQudG9rZW5Db250cmFjdEFkZHJlc3M7XG4gICAgICAgIGVuY3J5cHRlZEhhbmRsZSA9IGRlY29kZWQuZW5jcnlwdGVkSGFuZGxlO1xuICAgICAgICBpbnB1dFByb29mID0gZGVjb2RlZC5pbnB1dFByb29mO1xuICAgICAgfSBlbHNlIGlmICh0eEpzb24uZGF0YS5zdGFydHNXaXRoKGNvbmZpZGVudGlhbFRyYW5zZmVyV2l0aFByb29mTWV0aG9kSWQpKSB7XG4gICAgICAgIC8vIERpcmVjdCBjYWxsIHBhdGg6IGhvdC9UU1MgRU9BIHdhbGxldCBjYWxscyB0aGUgdG9rZW4gY29udHJhY3QgZGlyZWN0bHkuXG4gICAgICAgIC8vIFRoZSB0cmFuc2FjdGlvbidzIGB0b2AgZmllbGQgaXMgdGhlIHRva2VuIGNvbnRyYWN0IGFkZHJlc3MuXG4gICAgICAgIGlmICghdHhKc29uLnRvKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdkaXJlY3QgY29uZmlkZW50aWFsVHJhbnNmZXIgY2FsbCBpcyBtaXNzaW5nIHRyYW5zYWN0aW9uIHRvIGFkZHJlc3MnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBkZWNvZGVkID0gZGVjb2RlRGlyZWN0Q29uZmlkZW50aWFsVHJhbnNmZXJDYWxsZGF0YSh0eEpzb24uZGF0YSk7XG4gICAgICAgIHRvQWRkcmVzcyA9IGRlY29kZWQudG9BZGRyZXNzO1xuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzcyA9IHR4SnNvbi50bztcbiAgICAgICAgZW5jcnlwdGVkSGFuZGxlID0gZGVjb2RlZC5lbmNyeXB0ZWRIYW5kbGU7XG4gICAgICAgIGlucHV0UHJvb2YgPSBkZWNvZGVkLmlucHV0UHJvb2Y7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgbWV0aG9kIElEICR7dHhKc29uLmRhdGEuc2xpY2UoMCwgMTApfWApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBmYWlsZWQgdG8gZGVjb2RlIGNvbmZpZGVudGlhbCB0cmFuc2ZlciBjYWxsZGF0YSDigJQgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIDEuIFRva2VuIGNvbnRyYWN0IGFkZHJlc3MgbXVzdCBtYXRjaCB0aGlzIGNvaW5cbiAgICBpZiAodG9rZW5Db250cmFjdEFkZHJlc3MudG9Mb3dlckNhc2UoKSAhPT0gdGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcjogdG9rZW4gY29udHJhY3QgYWRkcmVzcyBtaXNtYXRjaCDigJQgYCArXG4gICAgICAgICAgYGV4cGVjdGVkICR7dGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzc30sIGdvdCAke3Rva2VuQ29udHJhY3RBZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gMi4gUmVjaXBpZW50IGFkZHJlc3MgbXVzdCBtYXRjaCB0eFBhcmFtcy5yZWNpcGllbnRzWzBdIG9yIGJ1aWxkUGFyYW1zLnJlY2lwaWVudHNbMF1cbiAgICBjb25zdCBleHBlY3RlZFJlY2lwaWVudCA9IHR4UGFyYW1zPy5yZWNpcGllbnRzPy5bMF0/LmFkZHJlc3MgPz8gdHhQcmVidWlsZC5idWlsZFBhcmFtcz8ucmVjaXBpZW50cz8uWzBdPy5hZGRyZXNzO1xuICAgIGlmICghZXhwZWN0ZWRSZWNpcGllbnQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ3ZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBtaXNzaW5nIGV4cGVjdGVkIHJlY2lwaWVudCAocHJvdmlkZSB0eFBhcmFtcy5yZWNpcGllbnRzIG9yIHR4UHJlYnVpbGQuYnVpbGRQYXJhbXMucmVjaXBpZW50cyknXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAodG9BZGRyZXNzLnRvTG93ZXJDYXNlKCkgIT09IGV4cGVjdGVkUmVjaXBpZW50LnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYHZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiByZWNpcGllbnQgYWRkcmVzcyBtaXNtYXRjaCDigJQgYCArIGBleHBlY3RlZCAke2V4cGVjdGVkUmVjaXBpZW50fSwgZ290ICR7dG9BZGRyZXNzfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gMy4gZW5jcnlwdGVkSGFuZGxlIG11c3QgYmUgYSBub24tdHJpdmlhbCBoZXggdmFsdWUgKG5vdCBiYXJlICcweCcpXG4gICAgaWYgKCFlbmNyeXB0ZWRIYW5kbGUgfHwgZW5jcnlwdGVkSGFuZGxlID09PSAnMHgnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBlbmNyeXB0ZWRIYW5kbGUgaXMgbWlzc2luZyBvciBlbXB0eSBpbiB0cmFuc2FjdGlvbiBjYWxsZGF0YScpO1xuICAgIH1cblxuICAgIC8vIDQuIGlucHV0UHJvb2YgbXVzdCBiZSBhIG5vbi10cml2aWFsIGhleCB2YWx1ZVxuICAgIGlmICghaW5wdXRQcm9vZiB8fCBpbnB1dFByb29mID09PSAnMHgnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUNvbmZpZGVudGlhbFRyYW5zZmVyOiBpbnB1dFByb29mIGlzIG1pc3Npbmcgb3IgZW1wdHkgaW4gdHJhbnNhY3Rpb24gY2FsbGRhdGEnKTtcbiAgICB9XG5cbiAgICAvLyA1LiBWZXJpZnkgcGxhaW50ZXh0IGludGVudDogdHhQYXJhbXMgYW1vdW50IG11c3QgYmUgdmFsaWQgYW5kIGNvbnNpc3RlbnQgd2l0aCBidWlsZFBhcmFtc1xuICAgIGNvbnN0IHJhd1R4UGFyYW1zQW1vdW50ID0gdHhQYXJhbXM/LnJlY2lwaWVudHM/LlswXT8uYW1vdW50O1xuICAgIGlmIChyYXdUeFBhcmFtc0Ftb3VudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCB0eFBhcmFtc0Ftb3VudCA9IFN0cmluZyhyYXdUeFBhcmFtc0Ftb3VudCk7XG4gICAgICBpZiAoIUVyYzc5ODRUb2tlbi5pc1Bvc2l0aXZlSW50ZWdlclN0cmluZyh0eFBhcmFtc0Ftb3VudCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcjogYW1vdW50IG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIHN0cmluZyBpbiBiYXNlIHVuaXRzLCBnb3QgJyR7dHhQYXJhbXNBbW91bnR9J2BcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGJ1aWxkUGFyYW1zQW1vdW50ID0gdHhQcmVidWlsZC5idWlsZFBhcmFtcz8ucmVjaXBpZW50cz8uWzBdPy5hbW91bnQ7XG4gICAgICBpZiAoYnVpbGRQYXJhbXNBbW91bnQgIT09IHVuZGVmaW5lZCAmJiB0eFBhcmFtc0Ftb3VudCAhPT0gYnVpbGRQYXJhbXNBbW91bnQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGB2ZXJpZnlDb25maWRlbnRpYWxUcmFuc2ZlcjogYW1vdW50IG1pc21hdGNoIOKAlCB0eFBhcmFtcyBoYXMgJyR7dHhQYXJhbXNBbW91bnR9JyBidXQgYnVpbGRQYXJhbXMgaGFzICcke2J1aWxkUGFyYW1zQW1vdW50fSdgXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBpc1Bvc2l0aXZlSW50ZWdlclN0cmluZyh2YWx1ZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIC9eXFxkKyQvLnRlc3QodmFsdWUpICYmIEJpZ0ludCh2YWx1ZSkgPiAwbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmllcyBhIHRva2VuIGVuYWJsZW1lbnQgdHJhbnNhY3Rpb24gZm9yIEVSQy03OTg0IGRlY3J5cHRpb24gZGVsZWdhdGlvbi5cbiAgICpcbiAgICogVFNTIHBhdGg6IGRlY29kZXMgdGhlIHJhdyB0eCBhbmQgdmVyaWZpZXMgaXQgY2FsbHMgdGhlIEFDTCBjb250cmFjdCB3aXRoXG4gICAqIGNhbGxkYXRhIHRoYXQgY292ZXJzIGFsbCByZXF1ZXN0ZWQgdG9rZW4gY29udHJhY3QgYWRkcmVzc2VzLlxuICAgKlxuICAgKiBNdWx0aXNpZyBwYXRoOiB2ZXJpZmllcyB0aGUgYnVpbGRQYXJhbXMgcmVjaXBpZW50cyBjYXJyeSB0aGUgY29ycmVjdCB0b2tlbk5hbWVzXG4gICAqIGFuZCB6ZXJvIGFtb3VudHMuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlFdGhUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXRUeXBlIH0gPSBwYXJhbXM7XG5cbiAgICBpZiAod2FsbGV0VHlwZSA9PT0gJ3RzcycpIHtcbiAgICAgIC8vIFRTUyBwYXRoOiBmdWxsIHJhdy10eCBkZWNvZGVcbiAgICAgIGNvbnN0IGVuYWJsZVRva2VucyA9IHR4UGFyYW1zLmVuYWJsZVRva2VucztcbiAgICAgIGlmICghZW5hYmxlVG9rZW5zIHx8IGVuYWJsZVRva2Vucy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlFbmFibGVUb2tlblRyYW5zYWN0aW9uOiBlbmFibGVUb2tlbnMgbXVzdCBiZSBub24tZW1wdHkgZm9yIFRTUyBwYXRoJyk7XG4gICAgICB9XG4gICAgICBpZiAoIXR4UHJlYnVpbGQudHhIZXgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZnlFbmFibGVUb2tlblRyYW5zYWN0aW9uOiBtaXNzaW5nIHR4SGV4IGluIHR4UHJlYnVpbGQnKTtcbiAgICAgIH1cblxuICAgICAgLy8gUmVzb2x2ZSByZXF1ZXN0ZWQgdG9rZW4gbmFtZXMg4oaSIGNvbnRyYWN0IGFkZHJlc3Nlc1xuICAgICAgY29uc3QgcmVxdWVzdGVkQWRkcmVzc2VzID0gZW5hYmxlVG9rZW5zLm1hcCgodCkgPT4ge1xuICAgICAgICBjb25zdCB0b2tlbkNvaW4gPSB0aGlzLmJpdGdvLmNvaW4odC5uYW1lKSBhcyBFcmM3OTg0VG9rZW47XG4gICAgICAgIHJldHVybiB0b2tlbkNvaW4udG9rZW5Db250cmFjdEFkZHJlc3MudG9Mb3dlckNhc2UoKTtcbiAgICAgIH0pO1xuXG4gICAgICAvLyBQYXJzZSB0aGUgcmF3IHRyYW5zYWN0aW9uXG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSB0aGlzLmdldFRyYW5zYWN0aW9uQnVpbGRlcigpO1xuICAgICAgdHhCdWlsZGVyLmZyb20odHhQcmVidWlsZC50eEhleCk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG5cbiAgICAgIC8vIFZlcmlmeSB0cmFuc2FjdGlvbiB0YXJnZXRzIHRoZSBjb3JyZWN0IGNvbnRyYWN0IGJhc2VkIG9uIGNhbGxkYXRhIHNoYXBlXG4gICAgICBjb25zdCBuZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKCkgYXMgRXRoZXJldW1OZXR3b3JrO1xuICAgICAgY29uc3QgYWNsQ29udHJhY3RBZGRyZXNzID0gbmV0d29yaz8uemFtYUFjbENvbnRyYWN0QWRkcmVzcztcbiAgICAgIGlmICghYWNsQ29udHJhY3RBZGRyZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogemFtYUFjbENvbnRyYWN0QWRkcmVzcyBub3QgY29uZmlndXJlZCBmb3IgdGhpcyBuZXR3b3JrJyk7XG4gICAgICB9XG4gICAgICBpZiAoIXR4SnNvbi50bykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IHRyYW5zYWN0aW9uIGlzIG1pc3NpbmcgcmVjaXBpZW50IGFkZHJlc3MnKTtcbiAgICAgIH1cblxuICAgICAgLy8gSW5zcGVjdCBjYWxsZGF0YSBtZXRob2QgSUQgdG8gZGlzdGluZ3Vpc2ggcm9vdCB3YWxsZXQgZnJvbSBmb3J3YXJkZXIgd2FsbGV0OlxuICAgICAgLy8gICBhY2xNdWx0aWNhbGxNZXRob2RJZCAgIOKGkiByb290IHdhbGxldDogdG8gPSBBQ0wgY29udHJhY3QgZGlyZWN0bHlcbiAgICAgIC8vICAgY2FsbEZyb21QYXJlbnRNZXRob2RJZCDihpIgZm9yd2FyZGVyIHdhbGxldDogdG8gPSBmb3J3YXJkZXIsIEFDTCBhZGRyZXNzIGlzIGluc2lkZSBjYWxsZGF0YVxuICAgICAgY29uc3QgY2FsbGRhdGFNZXRob2RJZCA9IHR4SnNvbi5kYXRhLnNsaWNlKDAsIDEwKTtcbiAgICAgIGlmIChjYWxsZGF0YU1ldGhvZElkID09PSBhY2xNdWx0aWNhbGxNZXRob2RJZCkge1xuICAgICAgICAvLyBSb290IHdhbGxldCAoYmFzZSBhZGRyZXNzKTogdHggY2FsbHMgdGhlIEFDTCBjb250cmFjdCBkaXJlY3RseVxuICAgICAgICBpZiAodHhKc29uLnRvLnRvTG93ZXJDYXNlKCkgIT09IGFjbENvbnRyYWN0QWRkcmVzcy50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYHZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IHRyYW5zYWN0aW9uIHRhcmdldCAke3R4SnNvbi50b30gZG9lcyBub3QgbWF0Y2ggQUNMIGNvbnRyYWN0ICR7YWNsQ29udHJhY3RBZGRyZXNzfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGNhbGxkYXRhTWV0aG9kSWQgPT09IGNhbGxGcm9tUGFyZW50TWV0aG9kSWQpIHtcbiAgICAgICAgLy8gRm9yd2FyZGVyIHdhbGxldDogdHggY2FsbHMgdGhlIGZvcndhcmRlciwgd2hpY2ggY2FsbHMgdGhlIEFDTCB2aWEgY2FsbEZyb21QYXJlbnQuXG4gICAgICAgIC8vIFRoZSBmb3J3YXJkZXIgYWRkcmVzcyBpcyB3YWxsZXQtc3BlY2lmaWMgYW5kIGNhbm5vdCBiZSBzdGF0aWNhbGx5IHZlcmlmaWVkIGhlcmU7XG4gICAgICAgIC8vIHRva2VuIGFkZHJlc3MgY29ycmVjdG5lc3MgaXMgc3RpbGwgdmVyaWZpZWQgYmVsb3cgdmlhIGNhbGxkYXRhIGRlY29kaW5nLlxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGB2ZXJpZnlFbmFibGVUb2tlblRyYW5zYWN0aW9uOiB1bnJlY29nbmlzZWQgY2FsbGRhdGEgbWV0aG9kIElEICR7Y2FsbGRhdGFNZXRob2RJZH07IGV4cGVjdGVkIG11bHRpY2FsbCBvciBjYWxsRnJvbVBhcmVudGBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgLy8gVmVyaWZ5IHZhbHVlIGlzIDBcbiAgICAgIGlmICh0eEpzb24udmFsdWUgIT09ICcwJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IGV4cGVjdGVkIHRyYW5zYWN0aW9uIHZhbHVlIDAgYnV0IGdvdCAke3R4SnNvbi52YWx1ZX1gKTtcbiAgICAgIH1cblxuICAgICAgLy8gRGVjb2RlIHRva2VuIGFkZHJlc3NlcyBmcm9tIGNhbGxkYXRhIGFuZCB2ZXJpZnkgYWxsIHJlcXVlc3RlZCB0b2tlbnMgYXJlIHByZXNlbnRcbiAgICAgIGNvbnN0IGRlY29kZWRBZGRyZXNzZXMgPSBkZWNvZGVUb2tlbkFkZHJlc3Nlc0Zyb21EZWxlZ2F0aW9uQ2FsbGRhdGEodHhKc29uLmRhdGEpO1xuICAgICAgZm9yIChjb25zdCByZXF1ZXN0ZWQgb2YgcmVxdWVzdGVkQWRkcmVzc2VzKSB7XG4gICAgICAgIGlmICghZGVjb2RlZEFkZHJlc3Nlcy5pbmNsdWRlcyhyZXF1ZXN0ZWQpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYHZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IHJlcXVlc3RlZCB0b2tlbiAke3JlcXVlc3RlZH0gbm90IGZvdW5kIGluIGRlbGVnYXRpb24gY2FsbGRhdGFgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gTXVsdGlzaWcgcGF0aDogYnVpbGRQYXJhbXMtbGV2ZWwgY2hlY2tcbiAgICAgIGNvbnN0IHJlY2lwaWVudHMgPSB0eFByZWJ1aWxkLmJ1aWxkUGFyYW1zPy5yZWNpcGllbnRzIGFzXG4gICAgICAgIHwgQXJyYXk8eyB0b2tlbk5hbWU/OiBzdHJpbmc7IGFtb3VudD86IHN0cmluZyB9PlxuICAgICAgICB8IHVuZGVmaW5lZDtcbiAgICAgIGlmICghcmVjaXBpZW50cyB8fCByZWNpcGllbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IG1pc3NpbmcgYnVpbGRQYXJhbXMucmVjaXBpZW50cyBmb3IgbXVsdGlzaWcgcGF0aCcpO1xuICAgICAgfVxuXG4gICAgICAvLyBEZXRlcm1pbmUgcmVxdWVzdGVkIHRva2VuIG5hbWVzIGZyb20gdHhQYXJhbXNcbiAgICAgIGNvbnN0IHJlcXVlc3RlZFRva2VuTmFtZXM6IHN0cmluZ1tdID0gW107XG4gICAgICBpZiAodHhQYXJhbXMuZW5hYmxlVG9rZW5zICYmIHR4UGFyYW1zLmVuYWJsZVRva2Vucy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHJlcXVlc3RlZFRva2VuTmFtZXMucHVzaCguLi50eFBhcmFtcy5lbmFibGVUb2tlbnMubWFwKCh0KSA9PiB0Lm5hbWUpKTtcbiAgICAgIH0gZWxzZSBpZiAodHhQYXJhbXMucmVjaXBpZW50cyAmJiB0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmVxdWVzdGVkVG9rZW5OYW1lcy5wdXNoKC4uLnR4UGFyYW1zLnJlY2lwaWVudHMubWFwKChyOiBhbnkpID0+IHIudG9rZW5OYW1lKS5maWx0ZXIoQm9vbGVhbikpO1xuICAgICAgfVxuXG4gICAgICAvLyBWZXJpZnkgYWxsIHJlY2lwaWVudHMgaGF2ZSB0b2tlbk5hbWUgYW5kIGFtb3VudCA9ICcwJ1xuICAgICAgZm9yIChjb25zdCByZWNpcGllbnQgb2YgcmVjaXBpZW50cykge1xuICAgICAgICBpZiAoIXJlY2lwaWVudC50b2tlbk5hbWUpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IHJlY2lwaWVudCBpcyBtaXNzaW5nIHRva2VuTmFtZSBpbiBidWlsZFBhcmFtcycpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZWNpcGllbnQuYW1vdW50ICE9PSAnMCcpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgdmVyaWZ5RW5hYmxlVG9rZW5UcmFuc2FjdGlvbjogZXhwZWN0ZWQgYW1vdW50IDAgZm9yIHRva2VuIGVuYWJsZW1lbnQgYnV0IGdvdCAke3JlY2lwaWVudC5hbW91bnR9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gVmVyaWZ5IHJlcXVlc3RlZCB0b2tlbiBuYW1lcyBhcmUgcHJlc2VudCBpbiByZWNpcGllbnRzXG4gICAgICBpZiAocmVxdWVzdGVkVG9rZW5OYW1lcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHJlY2lwaWVudFRva2VuTmFtZXMgPSByZWNpcGllbnRzLm1hcCgocikgPT4gci50b2tlbk5hbWUpO1xuICAgICAgICBmb3IgKGNvbnN0IHJlcXVlc3RlZCBvZiByZXF1ZXN0ZWRUb2tlbk5hbWVzKSB7XG4gICAgICAgICAgaWYgKCFyZWNpcGllbnRUb2tlbk5hbWVzLmluY2x1ZGVzKHJlcXVlc3RlZCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgYHZlcmlmeUVuYWJsZVRva2VuVHJhbnNhY3Rpb246IHJlcXVlc3RlZCB0b2tlbiAke3JlcXVlc3RlZH0gbm90IGZvdW5kIGluIGJ1aWxkUGFyYW1zIHJlY2lwaWVudHNgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogT3ZlcnJpZGUgZ2FzIGxpbWl0IGZvciBFUkMtNzk4NCBjb25maWRlbnRpYWwgdG9rZW4gcmVjb3ZlcnkuXG4gICAqIEFjdHVhbCBvbi1jaGFpbiB1c2FnZSBpcyB+NTA2LTUzMGsgZ2FzIGJhc2VkIG9uIHRlc3RuZXQgcmVzdWx0cy5cbiAgICogRGVmYXVsdDogODAwLDAwMCAoY29tZm9ydGFibGUgYnVmZmVyIG92ZXIgb2JzZXJ2ZWQgdXNhZ2UpLlxuICAgKi9cbiAgc2V0R2FzTGltaXQodXNlckdhc0xpbWl0PzogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBpZiAoIXVzZXJHYXNMaW1pdCkge1xuICAgICAgcmV0dXJuIDgwMDAwMDtcbiAgICB9XG4gICAgcmV0dXJuIHN1cGVyLnNldEdhc0xpbWl0KHVzZXJHYXNMaW1pdCk7XG4gIH1cblxuICAvKipcbiAgICogUXVlcmllcyB0aGUgZW5jcnlwdGVkIGJhbGFuY2UgaGFuZGxlIGZvciBhIHdhbGxldCBhZGRyZXNzIHZpYSBldGhfY2FsbCB0byB0aGVcbiAgICogdG9rZW4gY29udHJhY3QncyBjb25maWRlbnRpYWxCYWxhbmNlT2YoYWRkcmVzcykgZnVuY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSB3YWxsZXRBZGRyZXNzIC0gdGhlIHdhbGxldCBjb250cmFjdCBhZGRyZXNzIHRvIHF1ZXJ5IGJhbGFuY2UgZm9yXG4gICAqIEBwYXJhbSBhcGlLZXkgLSBvcHRpb25hbCBFdGhlcnNjYW4gQVBJIGtleVxuICAgKiBAcmV0dXJucyBieXRlczMyIGVuY3J5cHRlZCBoYW5kbGUgKDB4LXByZWZpeGVkLCA2NiBjaGFycykuXG4gICAqICAgTm90ZTogaGFuZGxlcyBhcmUgYWx3YXlzIG5vbi16ZXJvIGV2ZW4gZm9yIHplcm8gYmFsYW5jZXMgKGVuY3J5cHRlZCBkb21haW4pLlxuICAgKi9cbiAgYXN5bmMgcXVlcnlDb25maWRlbnRpYWxCYWxhbmNlKHdhbGxldEFkZHJlc3M6IHN0cmluZywgYXBpS2V5Pzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBtZXRob2RTaWduYXR1cmUgPSBvcHRpb25hbERlcHMuZXRoQWJpLm1ldGhvZElEKCdjb25maWRlbnRpYWxCYWxhbmNlT2YnLCBbJ2FkZHJlc3MnXSk7XG4gICAgY29uc3QgZW5jb2RlZEFyZ3MgPSBvcHRpb25hbERlcHMuZXRoQWJpLnJhd0VuY29kZShbJ2FkZHJlc3MnXSwgW3dhbGxldEFkZHJlc3NdKTtcbiAgICBjb25zdCBjYWxsZGF0YSA9IEJ1ZmZlci5jb25jYXQoW21ldGhvZFNpZ25hdHVyZSwgZW5jb2RlZEFyZ3NdKS50b1N0cmluZygnaGV4Jyk7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoXG4gICAgICB7XG4gICAgICAgIGNoYWluaWQ6IHRoaXMuZ2V0Q2hhaW5JZCgpLnRvU3RyaW5nKCksXG4gICAgICAgIG1vZHVsZTogJ3Byb3h5JyxcbiAgICAgICAgYWN0aW9uOiAnZXRoX2NhbGwnLFxuICAgICAgICB0bzogdGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgZGF0YTogY2FsbGRhdGEsXG4gICAgICAgIHRhZzogJ2xhdGVzdCcsXG4gICAgICB9LFxuICAgICAgYXBpS2V5XG4gICAgKTtcblxuICAgIGlmICghcmVzdWx0IHx8ICFyZXN1bHQucmVzdWx0KSB7XG4gICAgICB0aHJvdyBuZXcgUmVjb3ZlcnlQcm92aWRlckVycm9yKFxuICAgICAgICBgQ291bGQgbm90IG9idGFpbiBjb25maWRlbnRpYWwgYmFsYW5jZSBmb3IgJHt3YWxsZXRBZGRyZXNzfSBmcm9tIHRva2VuICR7dGhpcy50b2tlbkNvbnRyYWN0QWRkcmVzc31gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGhhbmRsZSA9IHJlc3VsdC5yZXN1bHQgYXMgc3RyaW5nO1xuICAgIGlmICghaGFuZGxlLnN0YXJ0c1dpdGgoJzB4JykgfHwgaGFuZGxlLmxlbmd0aCAhPT0gNjYpIHtcbiAgICAgIHRocm93IG5ldyBSZWNvdmVyeVByb3ZpZGVyRXJyb3IoYFVuZXhwZWN0ZWQgY29uZmlkZW50aWFsQmFsYW5jZU9mIHJlc3BvbnNlIGZvcm1hdDogJHtoYW5kbGV9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGhhbmRsZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgYSBub24tQml0R28gcmVjb3ZlcnkgdHJhbnNhY3Rpb24gZm9yIEVSQy03OTg0IGNvbmZpZGVudGlhbCB0b2tlbnMuXG4gICAqXG4gICAqIFVzZXMgdGhlIG5vLXByb29mIGhhbmRsZSBzd2VlcDogY29uZmlkZW50aWFsVHJhbnNmZXIocmVjaXBpZW50LCBoYW5kbGUpIHdpdGggMiBhcmdzLlxuICAgKiBObyBGSEUgZGVjcnlwdGlvbiBvciBwcm9vZiBnZW5lcmF0aW9uIGlzIG5lZWRlZCDigJQgdGhlIHdhbGxldCB0cmFuc2ZlcnMgaXRzIGVudGlyZVxuICAgKiBlbmNyeXB0ZWQgYmFsYW5jZSBoYW5kbGUgd2l0aG91dCBrbm93aW5nIHRoZSBwbGFpbnRleHQgYW1vdW50LlxuICAgKlxuICAgKiBUaGUgb3V0ZXIgdHJhbnNhY3Rpb24gc2hhcGUgaXM6XG4gICAqICAgdHgudG8gICA9IHdhbGxldENvbnRyYWN0QWRkcmVzc1xuICAgKiAgIHR4LmRhdGEgPSBzZW5kTXVsdGlTaWcodG9rZW5Db250cmFjdEFkZHIsIDAsIGNvbmZpZGVudGlhbFRyYW5zZmVyKHJlY292ZXJ5RGVzdCwgaGFuZGxlKSwgLi4uKVxuICAgKi9cbiAgYXN5bmMgcmVjb3ZlcihwYXJhbXM6IFJlY292ZXJPcHRpb25zKTogUHJvbWlzZTxSZWNvdmVyeUluZm8gfCBPZmZsaW5lVmF1bHRUeEluZm8+IHtcbiAgICBpZiAocGFyYW1zLmlzVHNzID09PSB0cnVlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VSQy03OTg0IFRTUyByZWNvdmVyeSBpcyBub3QgeWV0IHN1cHBvcnRlZCcpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy51c2VyS2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHVzZXJLZXknKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMuYmFja3VwS2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIGJhY2t1cEtleScpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKSAmJiAhcGFyYW1zLnVzZXJLZXkuc3RhcnRzV2l0aCgneHB1YicpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3Npbmcgd2FsbGV0IHBhc3NwaHJhc2UnKTtcbiAgICB9XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzKSB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMud2FsbGV0Q29udHJhY3RBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHdhbGxldENvbnRyYWN0QWRkcmVzcycpO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKSB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCByZWNvdmVyeURlc3RpbmF0aW9uJyk7XG4gICAgfVxuXG4gICAgY29uc3QgaXNLcnNSZWNvdmVyeSA9IGdldElzS3JzUmVjb3ZlcnkocGFyYW1zKTtcbiAgICBjb25zdCBpc1Vuc2lnbmVkU3dlZXAgPSBnZXRJc1Vuc2lnbmVkU3dlZXAocGFyYW1zKTtcblxuICAgIGlmIChpc0tyc1JlY292ZXJ5KSB7XG4gICAgICBjaGVja0tyc1Byb3ZpZGVyKHRoaXMsIHBhcmFtcy5rcnNQcm92aWRlciwgeyBjaGVja0NvaW5GYW1pbHlTdXBwb3J0OiBmYWxzZSB9KTtcbiAgICB9XG5cbiAgICBsZXQgdXNlcktleSA9IHBhcmFtcy51c2VyS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgY29uc3QgYmFja3VwS2V5ID0gcGFyYW1zLmJhY2t1cEtleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuXG4gICAgY29uc3QgZ2FzUHJpY2UgPSBwYXJhbXMuZWlwMTU1OVxuICAgICAgPyBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4ocGFyYW1zLmVpcDE1NTkubWF4RmVlUGVyR2FzKVxuICAgICAgOiBuZXcgb3B0aW9uYWxEZXBzLmV0aFV0aWwuQk4odGhpcy5zZXRHYXNQcmljZShwYXJhbXMuZ2FzUHJpY2UpKTtcbiAgICBjb25zdCBnYXNMaW1pdCA9IG5ldyBvcHRpb25hbERlcHMuZXRoVXRpbC5CTih0aGlzLnNldEdhc0xpbWl0KHBhcmFtcy5nYXNMaW1pdCkpO1xuXG4gICAgbGV0IHVzZXJQcnY6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBpZiAoIWlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgaWYgKCF1c2VyS2V5LnN0YXJ0c1dpdGgoJ3hwdWInKSAmJiAhdXNlcktleS5zdGFydHNXaXRoKCd4cHJ2JykpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB1c2VyS2V5ID0gYXdhaXQgdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgICAgIGlucHV0OiB1c2VyS2V5LFxuICAgICAgICAgICAgcGFzc3dvcmQ6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBkZWNyeXB0aW5nIHVzZXIga2V5Y2hhaW46ICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHVzZXJQcnYgPSB1c2VyS2V5O1xuICAgIH1cblxuICAgIGxldCBiYWNrdXBLZXlBZGRyZXNzOiBzdHJpbmc7XG4gICAgbGV0IGJhY2t1cFNpZ25pbmdLZXk6IEJ1ZmZlcjtcblxuICAgIGlmIChpc0tyc1JlY292ZXJ5IHx8IGlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgY29uc3QgYmFja3VwSEROb2RlID0gYmlwMzIuZnJvbUJhc2U1OChiYWNrdXBLZXkpO1xuICAgICAgYmFja3VwU2lnbmluZ0tleSA9IGJhY2t1cEhETm9kZS5wdWJsaWNLZXk7XG4gICAgICBiYWNrdXBLZXlBZGRyZXNzID0gYDB4JHtvcHRpb25hbERlcHMuZXRoVXRpbC5wdWJsaWNUb0FkZHJlc3MoYmFja3VwU2lnbmluZ0tleSwgdHJ1ZSkudG9TdHJpbmcoJ2hleCcpfWA7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBiYWNrdXBQcnY6IHN0cmluZztcbiAgICAgIHRyeSB7XG4gICAgICAgIGJhY2t1cFBydiA9IGF3YWl0IHRoaXMuYml0Z28uZGVjcnlwdCh7XG4gICAgICAgICAgaW5wdXQ6IGJhY2t1cEtleSxcbiAgICAgICAgICBwYXNzd29yZDogcGFyYW1zLndhbGxldFBhc3NwaHJhc2UsXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIGRlY3J5cHRpbmcgYmFja3VwIGtleWNoYWluOiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBiYWNrdXBIRE5vZGUgPSBiaXAzMi5mcm9tQmFzZTU4KGJhY2t1cFBydik7XG4gICAgICBiYWNrdXBTaWduaW5nS2V5ID0gYmFja3VwSEROb2RlLnByaXZhdGVLZXkgYXMgQnVmZmVyO1xuICAgICAgYmFja3VwS2V5QWRkcmVzcyA9IGAweCR7b3B0aW9uYWxEZXBzLmV0aFV0aWwucHJpdmF0ZVRvQWRkcmVzcyhiYWNrdXBTaWduaW5nS2V5KS50b1N0cmluZygnaGV4Jyl9YDtcbiAgICB9XG5cbiAgICBjb25zdCBiYWNrdXBLZXlOb25jZSA9IGF3YWl0IHRoaXMuZ2V0QWRkcmVzc05vbmNlKGJhY2t1cEtleUFkZHJlc3MsIHBhcmFtcy5hcGlLZXkpO1xuXG4gICAgY29uc3QgYmFja3VwS2V5QmFsYW5jZSA9IGF3YWl0IHRoaXMucXVlcnlBZGRyZXNzQmFsYW5jZShiYWNrdXBLZXlBZGRyZXNzLCBwYXJhbXMuYXBpS2V5KTtcbiAgICBjb25zdCB0b3RhbEdhc05lZWRlZCA9IGdhc1ByaWNlLm11bChnYXNMaW1pdCk7XG4gICAgY29uc3Qgd2VpVG9Hd2VpID0gMTAgKiogOTtcbiAgICBpZiAoYmFja3VwS2V5QmFsYW5jZS5sdCh0b3RhbEdhc05lZWRlZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEJhY2t1cCBrZXkgYWRkcmVzcyAke2JhY2t1cEtleUFkZHJlc3N9IGhhcyBiYWxhbmNlICR7KGJhY2t1cEtleUJhbGFuY2UgLyB3ZWlUb0d3ZWkpLnRvU3RyaW5nKCl9IEd3ZWkuYCArXG4gICAgICAgICAgYFRoaXMgYWRkcmVzcyBtdXN0IGhhdmUgYSBiYWxhbmNlIG9mIGF0IGxlYXN0ICR7KHRvdGFsR2FzTmVlZGVkIC8gd2VpVG9Hd2VpKS50b1N0cmluZygpfWAgK1xuICAgICAgICAgIGAgR3dlaSB0byBwZXJmb3JtIHJlY292ZXJpZXMuIFRyeSBzZW5kaW5nIHNvbWUgRVRIIHRvIHRoaXMgYWRkcmVzcyB0aGVuIHJldHJ5LmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gR2V0IHRoZSBlbmNyeXB0ZWQgYmFsYW5jZSBoYW5kbGUgKGF1dG8tcXVlcnkgb3IgdXNlci1wcm92aWRlZClcbiAgICBsZXQgZW5jcnlwdGVkSGFuZGxlOiBzdHJpbmc7XG4gICAgaWYgKHBhcmFtcy5lbmNyeXB0ZWRIYW5kbGUpIHtcbiAgICAgIGVuY3J5cHRlZEhhbmRsZSA9IHBhcmFtcy5lbmNyeXB0ZWRIYW5kbGU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMDApKTtcbiAgICAgIGVuY3J5cHRlZEhhbmRsZSA9IGF3YWl0IHRoaXMucXVlcnlDb25maWRlbnRpYWxCYWxhbmNlKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MsIHBhcmFtcy5hcGlLZXkpO1xuICAgIH1cblxuICAgIC8vIE5vdGU6IGVuY3J5cHRlZCBoYW5kbGVzIGFyZSBhbHdheXMgbm9uLXplcm8gZXZlbiBmb3IgemVybyBiYWxhbmNlcyAoZW5jcnlwdGVkIGRvbWFpbikuXG4gICAgLy8gVGhlIHRyYW5zZmVyIHdpbGwgZXhlY3V0ZSBidXQgbW92ZSAwIHRva2VucyBpZiB0aGUgd2FsbGV0IGlzIGVtcHR5LlxuXG4gICAgLy8gQnVpbGQgdGhlIGlubmVyIGNhbGxkYXRhOiBjb25maWRlbnRpYWxUcmFuc2ZlcihyZWNvdmVyeURlc3RpbmF0aW9uLCBoYW5kbGUpXG4gICAgY29uc3QgaW5uZXJDYWxsZGF0YSA9IGJ1aWxkQ29uZmlkZW50aWFsVHJhbnNmZXJCeUhhbmRsZUNhbGxkYXRhKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLCBlbmNyeXB0ZWRIYW5kbGUpO1xuXG4gICAgLy8gRm9yIHNlbmRNdWx0aVNpZzogcmVjaXBpZW50IGlzIHRoZSB0b2tlbiBjb250cmFjdCwgYW1vdW50IGlzIDAsIGRhdGEgY2FycmllcyB0aGUgY29uZmlkZW50aWFsVHJhbnNmZXIgY2FsbGRhdGFcbiAgICBjb25zdCByZWNpcGllbnRzID0gW1xuICAgICAge1xuICAgICAgICBhZGRyZXNzOiB0aGlzLnRva2VuQ29udHJhY3RBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6ICcwJyxcbiAgICAgICAgZGF0YTogb3B0aW9uYWxEZXBzLmV0aFV0aWwuc3RyaXBIZXhQcmVmaXgoaW5uZXJDYWxsZGF0YSksXG4gICAgICB9LFxuICAgIF07XG5cbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxMDAwKSk7XG4gICAgY29uc3Qgc2VxdWVuY2VJZCA9IGF3YWl0IHRoaXMucXVlcnlTZXF1ZW5jZUlkKHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MsIHBhcmFtcy5hcGlLZXkpO1xuXG4gICAgbGV0IG9wZXJhdGlvbkhhc2g6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBsZXQgc2lnbmF0dXJlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgaWYgKCFpc1Vuc2lnbmVkU3dlZXApIHtcbiAgICAgIG9wZXJhdGlvbkhhc2ggPSB0aGlzLmdldE9wZXJhdGlvblNoYTNGb3JFeGVjdXRlQW5kQ29uZmlybShyZWNpcGllbnRzLCB0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCksIHNlcXVlbmNlSWQpO1xuICAgICAgc2lnbmF0dXJlID0gVXRpbC5ldGhTaWduTXNnSGFzaChvcGVyYXRpb25IYXNoLCBVdGlsLnhwcnZUb0V0aFByaXZhdGVLZXkodXNlclBydiEpKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgVXRpbC5lY1JlY292ZXJFdGhBZGRyZXNzKG9wZXJhdGlvbkhhc2gsIHNpZ25hdHVyZSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzaWduYXR1cmUnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCB0eEluZm8gPSB7XG4gICAgICByZWNpcGllbnQ6IHJlY2lwaWVudHNbMF0sXG4gICAgICBleHBpcmVUaW1lOiB0aGlzLmdldERlZmF1bHRFeHBpcmVUaW1lKCksXG4gICAgICBjb250cmFjdFNlcXVlbmNlSWQ6IHNlcXVlbmNlSWQsXG4gICAgICBvcGVyYXRpb25IYXNoOiBvcGVyYXRpb25IYXNoLFxuICAgICAgc2lnbmF0dXJlOiBzaWduYXR1cmUgPz8gJycsXG4gICAgICBnYXNMaW1pdDogZ2FzTGltaXQudG9TdHJpbmcoMTApLFxuICAgIH07XG5cbiAgICBjb25zdCBzZW5kTWV0aG9kQXJncyA9IHRoaXMuZ2V0U2VuZE1ldGhvZEFyZ3ModHhJbmZvKTtcbiAgICBjb25zdCBtZXRob2RTaWduYXR1cmUgPSBvcHRpb25hbERlcHMuZXRoQWJpLm1ldGhvZElEKHRoaXMuc2VuZE1ldGhvZE5hbWUsIF8ubWFwKHNlbmRNZXRob2RBcmdzLCAndHlwZScpKTtcbiAgICBjb25zdCBlbmNvZGVkQXJncyA9IG9wdGlvbmFsRGVwcy5ldGhBYmkucmF3RW5jb2RlKF8ubWFwKHNlbmRNZXRob2RBcmdzLCAndHlwZScpLCBfLm1hcChzZW5kTWV0aG9kQXJncywgJ3ZhbHVlJykpO1xuICAgIGNvbnN0IHNlbmREYXRhID0gQnVmZmVyLmNvbmNhdChbbWV0aG9kU2lnbmF0dXJlLCBlbmNvZGVkQXJnc10pO1xuXG4gICAgbGV0IHR4ID0gRXRoLmJ1aWxkVHJhbnNhY3Rpb24oe1xuICAgICAgdG86IHBhcmFtcy53YWxsZXRDb250cmFjdEFkZHJlc3MsXG4gICAgICBub25jZTogYmFja3VwS2V5Tm9uY2UsXG4gICAgICB2YWx1ZTogMCxcbiAgICAgIGdhc1ByaWNlOiBnYXNQcmljZSxcbiAgICAgIGdhc0xpbWl0OiBnYXNMaW1pdCxcbiAgICAgIGRhdGE6IHNlbmREYXRhLFxuICAgICAgZWlwMTU1OTogcGFyYW1zLmVpcDE1NTksXG4gICAgICByZXBsYXlQcm90ZWN0aW9uT3B0aW9uczogcGFyYW1zLnJlcGxheVByb3RlY3Rpb25PcHRpb25zLFxuICAgIH0pO1xuXG4gICAgaWYgKGlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgcmV0dXJuIHRoaXMuZm9ybWF0Rm9yT2ZmbGluZVZhdWx0KFxuICAgICAgICB0eEluZm8sXG4gICAgICAgIHR4LFxuICAgICAgICB1c2VyS2V5LFxuICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgIGdhc1ByaWNlLFxuICAgICAgICBnYXNMaW1pdCxcbiAgICAgICAgcGFyYW1zLmVpcDE1NTksXG4gICAgICAgIHBhcmFtcy5yZXBsYXlQcm90ZWN0aW9uT3B0aW9ucyxcbiAgICAgICAgcGFyYW1zLmFwaUtleVxuICAgICAgKSBhcyBhbnk7XG4gICAgfVxuXG4gICAgaWYgKCFpc0tyc1JlY292ZXJ5KSB7XG4gICAgICB0eCA9IHR4LnNpZ24oYmFja3VwU2lnbmluZ0tleSk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2lnbmVkVHg6IFJlY292ZXJ5SW5mbyA9IHtcbiAgICAgIGlkOiBvcHRpb25hbERlcHMuZXRoVXRpbC5idWZmZXJUb0hleCh0eC5oYXNoKCkpLFxuICAgICAgdHg6IHR4LnNlcmlhbGl6ZSgpLnRvU3RyaW5nKCdoZXgnKSxcbiAgICB9O1xuXG4gICAgaWYgKGlzS3JzUmVjb3ZlcnkpIHtcbiAgICAgIHNpZ25lZFR4LmJhY2t1cEtleSA9IGJhY2t1cEtleTtcbiAgICAgIHNpZ25lZFR4LmNvaW4gPSB0aGlzLmdldENoYWluKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNpZ25lZFR4O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBEZWNyeXB0aW9uRGVsZWdhdGlvbkJ1aWxkZXIgZm9yIGNvbnN0cnVjdGluZyBaYW1hIEFDTCBkZWNyeXB0aW9uXG4gICAqIGRlbGVnYXRpb24gdHJhbnNhY3Rpb25zLlxuICAgKlxuICAgKiBUaGUgYnVpbGRlciBwcm9kdWNlcyBhIERlY3J5cHRpb25EZWxlZ2F0aW9uVHhSZXF1ZXN0IHt0bywgZGF0YSwgdmFsdWV9IHRoYXQgaXNcbiAgICogd2FsbGV0LXR5cGUtYWdub3N0aWMg4oCUIFdQIHJvdXRlcyBpdCB0byB0aGUgY29ycmVjdCBzaWduaW5nIHBhdGg6XG4gICAqIC0gTVBDOiBzdWJtaXQgYXMgYSByYXcgVFNTIHRyYW5zYWN0aW9uXG4gICAqIC0gTXVsdGlzaWc6IHdyYXAgaW4gc2VuZE11bHRpU2lnKHdhbGxldENvbnRyYWN0LCB0bywgMCwgZGF0YSwgLi4uKVxuICAgKlxuICAgKiBFeGFtcGxlOlxuICAgKiAgIGNvbnN0IHJlcSA9IGNvaW4uZ2V0RGVjcnlwdGlvbkRlbGVnYXRpb25CdWlsZGVyKCkuYnVpbGQoe1xuICAgKiAgICAgYWNsQ29udHJhY3RBZGRyZXNzOiAnMHhmMEZmLi4uJyxcbiAgICogICAgIGRlbGVnYXRlQWRkcmVzczogICAgZW50ZXJwcmlzZVZpZXdpbmdLZXksXG4gICAqICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzc2VzOiBbdG9rZW5BZGRyZXNzXSxcbiAgICogICAgIGV4cGlyeVRpbWVzdGFtcDogICAgTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCkgKyAzNjUgKiA4NjQwMCxcbiAgICogICB9KTtcbiAgICovXG4gIGdldERlY3J5cHRpb25EZWxlZ2F0aW9uQnVpbGRlcigpOiBEZWNyeXB0aW9uRGVsZWdhdGlvbkJ1aWxkZXIge1xuICAgIHJldHVybiBuZXcgRGVjcnlwdGlvbkRlbGVnYXRpb25CdWlsZGVyKCk7XG4gIH1cbn1cbiJdfQ==