@bitgo-beta/sdk-coin-flrp 1.0.1-beta.369 → 1.0.1-beta.370

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 (59) hide show
  1. package/dist/src/lib/ExportInCTxBuilder.d.ts +5 -13
  2. package/dist/src/lib/ExportInCTxBuilder.d.ts.map +1 -1
  3. package/dist/src/lib/ExportInCTxBuilder.js +24 -64
  4. package/dist/src/lib/ExportInPTxBuilder.d.ts +2 -25
  5. package/dist/src/lib/ExportInPTxBuilder.d.ts.map +1 -1
  6. package/dist/src/lib/ExportInPTxBuilder.js +34 -160
  7. package/dist/src/lib/ImportInCTxBuilder.d.ts +1 -19
  8. package/dist/src/lib/ImportInCTxBuilder.d.ts.map +1 -1
  9. package/dist/src/lib/ImportInCTxBuilder.js +32 -134
  10. package/dist/src/lib/ImportInPTxBuilder.d.ts +13 -12
  11. package/dist/src/lib/ImportInPTxBuilder.d.ts.map +1 -1
  12. package/dist/src/lib/ImportInPTxBuilder.js +81 -100
  13. package/dist/src/lib/atomicInCTransactionBuilder.d.ts +0 -6
  14. package/dist/src/lib/atomicInCTransactionBuilder.d.ts.map +1 -1
  15. package/dist/src/lib/atomicInCTransactionBuilder.js +1 -14
  16. package/dist/src/lib/atomicTransactionBuilder.d.ts +15 -17
  17. package/dist/src/lib/atomicTransactionBuilder.d.ts.map +1 -1
  18. package/dist/src/lib/atomicTransactionBuilder.js +22 -138
  19. package/dist/src/lib/iface.d.ts +31 -0
  20. package/dist/src/lib/iface.d.ts.map +1 -1
  21. package/dist/src/lib/iface.js +9 -2
  22. package/dist/src/lib/permissionlessValidatorTxBuilder.d.ts +0 -2
  23. package/dist/src/lib/permissionlessValidatorTxBuilder.d.ts.map +1 -1
  24. package/dist/src/lib/permissionlessValidatorTxBuilder.js +1 -7
  25. package/dist/src/lib/transaction.d.ts +10 -6
  26. package/dist/src/lib/transaction.d.ts.map +1 -1
  27. package/dist/src/lib/transaction.js +10 -13
  28. package/dist/src/lib/transactionBuilder.d.ts +24 -16
  29. package/dist/src/lib/transactionBuilder.d.ts.map +1 -1
  30. package/dist/src/lib/transactionBuilder.js +46 -28
  31. package/dist/src/lib/utils.d.ts +31 -2
  32. package/dist/src/lib/utils.d.ts.map +1 -1
  33. package/dist/src/lib/utils.js +71 -1
  34. package/dist/test/resources/account.d.ts +30 -0
  35. package/dist/test/resources/account.d.ts.map +1 -1
  36. package/dist/test/resources/account.js +27 -2
  37. package/dist/test/resources/transactionData/exportInC.d.ts +30 -0
  38. package/dist/test/resources/transactionData/exportInC.d.ts.map +1 -1
  39. package/dist/test/resources/transactionData/exportInC.js +32 -13
  40. package/dist/test/resources/transactionData/exportInP.d.ts +39 -48
  41. package/dist/test/resources/transactionData/exportInP.d.ts.map +1 -1
  42. package/dist/test/resources/transactionData/exportInP.js +70 -109
  43. package/dist/test/resources/transactionData/importInC.d.ts +39 -10
  44. package/dist/test/resources/transactionData/importInC.d.ts.map +1 -1
  45. package/dist/test/resources/transactionData/importInC.js +102 -25
  46. package/dist/test/resources/transactionData/importInP.d.ts +46 -15
  47. package/dist/test/resources/transactionData/importInP.d.ts.map +1 -1
  48. package/dist/test/resources/transactionData/importInP.js +65 -39
  49. package/dist/test/unit/flrp.js +15 -12
  50. package/dist/test/unit/lib/exportInCTxBuilder.js +32 -31
  51. package/dist/test/unit/lib/exportInPTxBuilder.js +50 -253
  52. package/dist/test/unit/lib/importInCTxBuilder.js +470 -363
  53. package/dist/test/unit/lib/importInPTxBuilder.js +46 -227
  54. package/dist/test/unit/lib/signFlowTestSuit.d.ts.map +1 -1
  55. package/dist/test/unit/lib/signFlowTestSuit.js +1 -1
  56. package/dist/test/unit/lib/transactionBuilderFactory.js +2 -2
  57. package/dist/test/unit/lib/utils.js +94 -32
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/package.json +7 -6
@@ -9,20 +9,98 @@ const lib_1 = require("../../../src/lib");
9
9
  const statics_1 = require("@bitgo-beta/statics");
10
10
  const importInC_1 = require("../../resources/transactionData/importInC");
11
11
  const signFlowTestSuit_1 = __importDefault(require("./signFlowTestSuit"));
12
- const utils_1 = __importDefault(require("../../../src/lib/utils"));
13
12
  describe('Flrp Import In C Tx Builder', () => {
14
13
  const factory = new lib_1.TransactionBuilderFactory(statics_1.coins.get('tflrp'));
15
14
  describe('validate txBuilder fields', () => {
16
- const txBuilder = factory.getImportInCBuilder();
17
- it('should fail validate Utxos empty string', () => {
15
+ it('should fail validate Utxos empty array', () => {
16
+ const txBuilder = factory.getImportInCBuilder();
18
17
  assert_1.default.throws(() => {
19
18
  txBuilder.validateUtxos([]);
20
19
  }, (e) => e.message === 'UTXOs array cannot be empty');
21
20
  });
22
- it('should fail validate Utxos without amount field', () => {
21
+ it('should throw if to address is not set', async () => {
22
+ const txBuilder = factory
23
+ .getImportInCBuilder()
24
+ .threshold(importInC_1.IMPORT_IN_C.threshold)
25
+ .fromPubKey(importInC_1.IMPORT_IN_C.pAddresses)
26
+ .decodedUtxos(importInC_1.IMPORT_IN_C.utxos)
27
+ .fee(importInC_1.IMPORT_IN_C.fee)
28
+ .context(importInC_1.IMPORT_IN_C.context);
29
+ // to is NOT set
30
+ await txBuilder.build().should.be.rejectedWith('to is required');
31
+ });
32
+ it('should throw if context is not set', async () => {
33
+ const txBuilder = factory
34
+ .getImportInCBuilder()
35
+ .threshold(importInC_1.IMPORT_IN_C.threshold)
36
+ .fromPubKey(importInC_1.IMPORT_IN_C.pAddresses)
37
+ .decodedUtxos(importInC_1.IMPORT_IN_C.utxos)
38
+ .to(importInC_1.IMPORT_IN_C.to)
39
+ .fee(importInC_1.IMPORT_IN_C.fee);
40
+ // context is NOT set
41
+ await txBuilder.build().should.be.rejectedWith('context is required');
42
+ });
43
+ it('should throw if fromAddresses is not set', async () => {
44
+ const txBuilder = factory
45
+ .getImportInCBuilder()
46
+ .threshold(importInC_1.IMPORT_IN_C.threshold)
47
+ .decodedUtxos(importInC_1.IMPORT_IN_C.utxos)
48
+ .to(importInC_1.IMPORT_IN_C.to)
49
+ .fee(importInC_1.IMPORT_IN_C.fee)
50
+ .context(importInC_1.IMPORT_IN_C.context);
51
+ // fromPubKey is NOT set
52
+ await txBuilder.build().should.be.rejectedWith('fromAddresses are required');
53
+ });
54
+ it('should throw if UTXOs are not set', async () => {
55
+ const txBuilder = factory
56
+ .getImportInCBuilder()
57
+ .threshold(importInC_1.IMPORT_IN_C.threshold)
58
+ .fromPubKey(importInC_1.IMPORT_IN_C.pAddresses)
59
+ .to(importInC_1.IMPORT_IN_C.to)
60
+ .fee(importInC_1.IMPORT_IN_C.fee)
61
+ .context(importInC_1.IMPORT_IN_C.context);
62
+ // utxos is NOT set
63
+ await txBuilder.build().should.be.rejectedWith('UTXOs are required');
64
+ });
65
+ it('should fail when utxos hex array is empty', () => {
66
+ const txBuilder = factory.getImportInCBuilder();
67
+ assert_1.default.throws(() => {
68
+ txBuilder.decodedUtxos([]);
69
+ }, (e) => e.message === 'UTXOs array cannot be empty');
70
+ });
71
+ it('should fail with invalid threshold value (0)', () => {
72
+ const txBuilder = factory.getImportInCBuilder();
73
+ assert_1.default.throws(() => {
74
+ txBuilder.threshold(0);
75
+ }, (e) => e.message.includes('threshold') || e.message.includes('greater'));
76
+ });
77
+ it('should fail with invalid threshold value (negative)', () => {
78
+ const txBuilder = factory.getImportInCBuilder();
79
+ assert_1.default.throws(() => {
80
+ txBuilder.threshold(-1);
81
+ }, (e) => e.message.includes('threshold') || e.message.includes('greater'));
82
+ });
83
+ it('should fail with invalid to address format', () => {
84
+ const txBuilder = factory.getImportInCBuilder();
23
85
  assert_1.default.throws(() => {
24
- txBuilder.validateUtxos([{ outputID: '' }]);
25
- }, (e) => e.message === 'UTXO missing required field: amount');
86
+ txBuilder.to('invalid-address');
87
+ }, (e) => e.message.includes('Invalid') || e.message.includes('address'));
88
+ });
89
+ it('should accept valid to address', () => {
90
+ const txBuilder = factory.getImportInCBuilder();
91
+ (() => txBuilder.to(importInC_1.IMPORT_IN_C.to)).should.not.throw();
92
+ });
93
+ it('should accept valid threshold', () => {
94
+ const txBuilder = factory.getImportInCBuilder();
95
+ (() => txBuilder.threshold(2)).should.not.throw();
96
+ });
97
+ it('should accept valid context', () => {
98
+ const txBuilder = factory.getImportInCBuilder();
99
+ (() => txBuilder.context(importInC_1.IMPORT_IN_C.context)).should.not.throw();
100
+ });
101
+ it('should accept valid fromPubKey addresses', () => {
102
+ const txBuilder = factory.getImportInCBuilder();
103
+ (() => txBuilder.fromPubKey(importInC_1.IMPORT_IN_C.pAddresses)).should.not.throw();
26
104
  });
27
105
  });
28
106
  (0, signFlowTestSuit_1.default)({
@@ -32,369 +110,398 @@ describe('Flrp Import In C Tx Builder', () => {
32
110
  .getImportInCBuilder()
33
111
  .threshold(importInC_1.IMPORT_IN_C.threshold)
34
112
  .fromPubKey(importInC_1.IMPORT_IN_C.pAddresses)
35
- .utxos(importInC_1.IMPORT_IN_C.outputs)
113
+ .decodedUtxos(importInC_1.IMPORT_IN_C.utxos)
36
114
  .to(importInC_1.IMPORT_IN_C.to)
37
- .feeRate(importInC_1.IMPORT_IN_C.fee),
115
+ .fee(importInC_1.IMPORT_IN_C.fee)
116
+ .context(importInC_1.IMPORT_IN_C.context),
38
117
  unsignedTxHex: importInC_1.IMPORT_IN_C.unsignedHex,
39
118
  halfSignedTxHex: importInC_1.IMPORT_IN_C.halfSigntxHex,
40
119
  fullSignedTxHex: importInC_1.IMPORT_IN_C.fullSigntxHex,
41
120
  privateKey: {
42
- prv1: importInC_1.IMPORT_IN_C.privateKeys[0],
43
- prv2: importInC_1.IMPORT_IN_C.privateKeys[1],
121
+ prv1: importInC_1.IMPORT_IN_C.privateKeys[2],
122
+ prv2: importInC_1.IMPORT_IN_C.privateKeys[0],
44
123
  },
45
124
  txHash: importInC_1.IMPORT_IN_C.txhash,
46
125
  });
47
- describe('fee calculation - insufficient unlocked funds fix', () => {
48
- /**
49
- * This test verifies the fix for the "insufficient unlocked funds" error that occurred
50
- * during P-to-C chain transactions.
51
- *
52
- * Real-world transaction data:
53
- * - Input: 100,000,000 nanoFLRP (from P-chain export)
54
- * - Original feeRate: 500, which caused "needs 280000 more" error
55
- * - Old (buggy) calculation:
56
- * - Size: 12,234 (only unsignedTx.toBytes())
57
- * - Fee: 500 × 12,234 = 6,117,000
58
- * - Error: "insufficient unlocked funds: needs 280000 more"
59
- * - Required fee: 6,117,000 + 280,000 = 6,397,000
60
- *
61
- * The fix has two parts:
62
- * 1. Use getSignedTx().toBytes() to include credentials in size calculation (~140+ bytes)
63
- * 2. Increase feeRate from 500 to 550 to provide additional buffer
64
- *
65
- * With fix: size ~12,376 × feeRate 550 = 6,806,800 > 6,397,000 ✓
66
- */
67
- it('should calculate sufficient fee to avoid "insufficient unlocked funds" error', async () => {
68
- const inputAmount = '100000000';
69
- const feeRate = 550;
70
- const threshold = 2;
71
- const pAddresses = [
72
- 'P-costwo1060n6skw5lsz7ch8z4vnv2s24vetjv5w73g4k2',
73
- 'P-costwo1kt5hrl4kr5dt92ayxjash6uujkf4nh5ex0y9rj',
74
- 'P-costwo1eys86hynecjn8400j30e7y706aecv8wz0l875x',
75
- ];
76
- const cChainDestination = '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e';
77
- const utxo = {
78
- outputID: 7,
79
- amount: inputAmount,
80
- txid: '2b2A4CyaRawiVAycUhpfvaxizymUT3TwRUbrzwiy3qp7DnKznj',
81
- outputidx: '0',
82
- addresses: [
83
- '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e',
84
- 'C9207d5c93ce2533d5ef945f9f13cfd773861dc2',
85
- 'b2e971feb61d1ab2aba434bb0beb9c959359de99',
86
- ],
87
- threshold: threshold,
88
- };
89
- const txBuilder = factory
90
- .getImportInCBuilder()
91
- .threshold(threshold)
92
- .fromPubKey(pAddresses)
93
- .utxos([utxo])
94
- .to(cChainDestination)
95
- .feeRate(feeRate.toString());
96
- const tx = await txBuilder.build();
97
- const feeInfo = tx.fee;
98
- const calculatedFee = BigInt(feeInfo.fee);
99
- const calculatedSize = feeInfo.size;
100
- const oldBuggyFeeAt500 = BigInt(12234) * BigInt(500);
101
- const shortfall = BigInt(280000);
102
- const requiredFee = oldBuggyFeeAt500 + shortfall;
103
- (0, assert_1.default)(calculatedFee >= requiredFee, `Fee ${calculatedFee} should be at least ${requiredFee} (old fee ${oldBuggyFeeAt500} + shortfall ${shortfall})`);
104
- const oldBuggySize = 12234;
105
- (0, assert_1.default)(calculatedSize > oldBuggySize, `Size ${calculatedSize} should be greater than old buggy size ${oldBuggySize}`);
106
- const outputAmount = BigInt(tx.outputs[0].value);
107
- (0, assert_1.default)(outputAmount > BigInt(0), 'Output amount should be positive');
108
- const inputBigInt = BigInt(inputAmount);
109
- const expectedOutput = inputBigInt - calculatedFee;
110
- (0, assert_1.default)(outputAmount === expectedOutput, `Output ${outputAmount} should equal input ${inputBigInt} minus fee ${calculatedFee}`);
111
- });
112
- it('should match AVAXP costImportTx formula: bytesCost + inputCosts + fixedFee', async () => {
113
- const inputAmount = '100000000';
114
- const feeRate = 500;
115
- const threshold = 2;
116
- const utxo = {
117
- outputID: 7,
118
- amount: inputAmount,
119
- txid: '2b2A4CyaRawiVAycUhpfvaxizymUT3TwRUbrzwiy3qp7DnKznj',
120
- outputidx: '0',
121
- addresses: [
122
- '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e',
123
- 'C9207d5c93ce2533d5ef945f9f13cfd773861dc2',
124
- 'b2e971feb61d1ab2aba434bb0beb9c959359de99',
125
- ],
126
- threshold: threshold,
127
- };
128
- const txBuilder = factory
129
- .getImportInCBuilder()
130
- .threshold(threshold)
131
- .fromPubKey(importInC_1.IMPORT_IN_C.pAddresses)
132
- .utxos([utxo])
133
- .to(importInC_1.IMPORT_IN_C.to)
134
- .feeRate(feeRate.toString());
135
- const tx = await txBuilder.build();
136
- const feeInfo = tx.fee;
137
- const calculatedSize = feeInfo.size;
138
- const expectedInputCost = 1000 * threshold;
139
- const fixedFee = 10000;
140
- const expectedMinBytesCost = 200;
141
- const impliedBytesCost = calculatedSize - expectedInputCost - fixedFee;
142
- (0, assert_1.default)(impliedBytesCost >= expectedMinBytesCost, `Implied bytes cost ${impliedBytesCost} should be at least ${expectedMinBytesCost}`);
143
- const expectedMinTotalSize = expectedMinBytesCost + expectedInputCost + fixedFee;
144
- (0, assert_1.default)(calculatedSize >= expectedMinTotalSize, `Total size ${calculatedSize} should be at least ${expectedMinTotalSize} (bytes + inputCost + fixedFee)`);
145
- });
146
- it('should produce consistent fees between build and parse (initBuilder vs buildFlareTransaction)', async () => {
147
- const inputAmount = '100000000';
148
- const feeRate = 500;
149
- const threshold = 2;
150
- const utxo = {
151
- outputID: 7,
152
- amount: inputAmount,
153
- txid: '2b2A4CyaRawiVAycUhpfvaxizymUT3TwRUbrzwiy3qp7DnKznj',
154
- outputidx: '0',
155
- addresses: [
156
- '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e',
157
- 'C9207d5c93ce2533d5ef945f9f13cfd773861dc2',
158
- 'b2e971feb61d1ab2aba434bb0beb9c959359de99',
159
- ],
160
- threshold: threshold,
161
- };
162
- const txBuilder = factory
163
- .getImportInCBuilder()
164
- .threshold(threshold)
165
- .fromPubKey(importInC_1.IMPORT_IN_C.pAddresses)
166
- .utxos([utxo])
167
- .to(importInC_1.IMPORT_IN_C.to)
168
- .feeRate(feeRate.toString());
169
- const originalTx = await txBuilder.build();
170
- const originalFeeInfo = originalTx.fee;
171
- const originalSize = originalFeeInfo.size;
172
- const txHex = originalTx.toBroadcastFormat();
173
- const parsedBuilder = factory.from(txHex);
174
- const parsedTx = await parsedBuilder.build();
175
- const parsedFeeInfo = parsedTx.fee;
176
- const parsedFeeRate = parsedFeeInfo.feeRate;
177
- const parsedSize = parsedFeeInfo.size;
178
- const feeRateDiff = Math.abs(parsedFeeRate - feeRate);
179
- const maxAllowedDiff = 50;
180
- (0, assert_1.default)(feeRateDiff <= maxAllowedDiff, `Parsed feeRate ${parsedFeeRate} should be close to original ${feeRate} (diff: ${feeRateDiff})`);
181
- const sizeDiff = Math.abs(parsedSize - originalSize);
182
- const maxSizeDiff = 100;
183
- (0, assert_1.default)(sizeDiff <= maxSizeDiff, `Parsed size ${parsedSize} should be close to original ${originalSize} (diff: ${sizeDiff})`);
184
- });
185
- });
186
- describe('on-chain verified transactions', () => {
187
- it('should verify on-chain tx id for signed C-chain import', async () => {
188
- const signedImportHex = '0x0000000000000000007278db5c30bed04c05ce209179812850bbb3fe6d46d7eef3744d814c0da555247900000000000000000000000000000000000000000000000000000000000000000000000162ef0c8ced5668d1230c82e274f5c19357df8c005743367421e8a2b48c73989a0000000158734f94af871c3d131b56131b6fb7a0291eacadd261e69dfb42a9cdf6f7fddd000000050000000002faf0800000000200000000000000010000000117dbd11b9dd1c9be337353db7c14f9fb3662e5b50000000002aea54058734f94af871c3d131b56131b6fb7a0291eacadd261e69dfb42a9cdf6f7fddd000000010000000900000002ab32c15c75c763b24adf26eee85aa7d6a76b366e6b88e34b94f76baec91bae7336a32ed637fc232cccb2f772d3092eee66594070a2be92751148feffc76005b1013ee78fb11f3f9ffd90d970cd5c95e9dee611bb4feafaa0b0220cc641ef054c9f5701fde4fad2fe7f2594db9dafd858c62f9cf6fe6b58334d73da40a5a8412d4600';
189
- const txBuilder = new lib_1.TransactionBuilderFactory(statics_1.coins.get('tflrp')).from(signedImportHex);
190
- const tx = await txBuilder.build();
191
- const rawTx = tx.toBroadcastFormat();
192
- rawTx.should.equal(signedImportHex);
193
- tx.id.should.equal('2ks9vW1SVWD4KsNPHgXnV5dpJaCcaxVNbQW4H7t9BMDxApGvfa');
194
- });
195
- it('should FAIL with unsorted UTXO addresses - demonstrates AddressMap mismatch issue for import in C-chain tx', async () => {
196
- // This test uses UTXO addresses in UNSORTED order to demonstrate the issue.
197
- // With unsorted addresses, the current implementation will create AddressMaps incorrectly
198
- // because it uses sequential indices, not UTXO address order.
199
- //
200
- // Expected: AddressMap should map addresses to signature slots based on UTXO order (addressesIndex)
201
- // Current (WRONG): AddressMap uses sequential indices (0, 1, 2...)
202
- //
203
- // This test WILL FAIL with current implementation because AddressMaps don't match credential order
204
- // UTXO addresses in UNSORTED order (different from sorted)
205
- // Sorted would be: [0x3329... (smallest), 0x7e91... (middle), 0xc732... (largest)]
206
- // Unsorted: [0xc732... (largest), 0x3329... (smallest), 0x7e91... (middle)]
207
- const unsortedUtxoAddresses = [
208
- '0xc7324437c96c7c8a6a152da2385c1db5c3ab1f91', // Largest (would be index 2 if sorted)
209
- '0x3329be7d01cd3ebaae6654d7327dd9f17a2e1581', // Smallest (would be index 0 if sorted)
210
- '0x7e918a5e8083ae4c9f2f0ed77055c24bf3665001', // Middle (would be index 1 if sorted)
211
- ];
212
- // Corresponding P-chain addresses (in same order as _fromAddresses)
213
- const pAddresses = [
214
- 'P-costwo1xv5mulgpe5lt4tnx2ntnylwe79azu9vpja6lut', // Maps to 0xc732... (UTXO index 0 in unsorted)
215
- 'P-costwo106gc5h5qswhye8e0pmthq4wzf0ekv5qppsrvpu', // Maps to 0x3329... (UTXO index 1 in unsorted)
216
- 'P-costwo1cueygd7fd37g56s49k3rshqakhp6k8u3adzt6m', // Maps to 0x7e91... (UTXO index 2 in unsorted)
217
- ];
218
- // Create UTXO with UNSORTED addresses
219
- const amount = '500000000'; // 0.5 FLR
220
- const fee = '5000000'; // Example fee
221
- const utxoAmount = (BigInt(amount) + BigInt(fee) + BigInt('10000000')).toString(); // amount + fee + some buffer
222
- const utxo = {
223
- outputID: 0,
224
- amount: utxoAmount,
225
- txid: '2vPMx8P63adgBae7GAWFx7qvJDwRmMnDCyKddHRBXWhysjX4BP',
226
- outputidx: '1',
227
- addresses: unsortedUtxoAddresses, // UNSORTED order
228
- threshold: 2,
229
- };
230
- // Build transaction
231
- const txBuilder = factory
232
- .getImportInCBuilder()
233
- .threshold(2)
234
- .fromPubKey(pAddresses)
235
- .utxos([utxo])
236
- .to(importInC_1.IMPORT_IN_C.to)
237
- .feeRate(importInC_1.IMPORT_IN_C.fee);
238
- // Build unsigned transaction
239
- const unsignedTx = await txBuilder.build();
240
- const unsignedHex = unsignedTx.toBroadcastFormat();
241
- // Get AddressMaps from the ORIGINAL transaction (before parsing)
242
- // The parsed transaction's AddressMap only contains the output address, not _fromAddresses
243
- const originalFlareTx = unsignedTx._flareTransaction;
244
- const originalAddressMaps = originalFlareTx.addressMaps;
245
- // Parse it back to inspect AddressMaps and credentials
246
- const parsedBuilder = factory.from(unsignedHex);
247
- const parsedTx = await parsedBuilder.build();
248
- const flareTx = parsedTx._flareTransaction;
249
- // Get the input to check sigIndicies (for C-chain imports, inputs are importedInputs)
250
- const importTx = flareTx.tx;
251
- const input = importTx.importedInputs[0];
252
- const sigIndicies = input.sigIndicies();
253
- // sigIndicies tells us: sigIndicies[slotIndex] = utxoAddressIndex
254
- // For threshold=2, we need signatures for first 2 addresses in UTXO order
255
- // UTXO order: [0xc732... (index 0), 0x3329... (index 1), 0x7e91... (index 2)]
256
- // So sigIndicies should be [0, 1] meaning: slot 0 = UTXO index 0, slot 1 = UTXO index 1
257
- // Verify sigIndicies are [0, 1] (first 2 addresses in UTXO order, NOT sorted order)
258
- sigIndicies.length.should.equal(2);
259
- sigIndicies[0].should.equal(0, 'First signature slot should be UTXO address index 0 (0xc732...)');
260
- sigIndicies[1].should.equal(1, 'Second signature slot should be UTXO address index 1 (0x3329...)');
261
- // The critical test: Verify that signature slots have embedded addresses based on UTXO order
262
- // With unsorted UTXO addresses, this will FAIL if AddressMaps don't match UTXO order
263
- //
264
- // Parse the credential to see which slots have which embedded addresses
265
- const credential = flareTx.credentials[0];
266
- const signatures = credential.getSignatures();
267
- // Extract embedded addresses from signature slots
268
- const embeddedAddresses = [];
269
- const isEmptySignature = (signature) => {
270
- return !!signature && utils_1.default.removeHexPrefix(signature).startsWith('0'.repeat(90));
271
- };
272
- const hasEmbeddedAddress = (signature) => {
273
- if (!isEmptySignature(signature))
274
- return false;
275
- const cleanSig = utils_1.default.removeHexPrefix(signature);
276
- if (cleanSig.length < 130)
277
- return false;
278
- const embeddedPart = cleanSig.substring(90, 130);
279
- // Check if embedded part is not all zeros
280
- return embeddedPart !== '0'.repeat(40);
281
- };
282
- signatures.forEach((sig, slotIndex) => {
283
- if (hasEmbeddedAddress(sig)) {
284
- // Extract embedded address (after position 90, 40 chars = 20 bytes)
285
- const cleanSig = utils_1.default.removeHexPrefix(sig);
286
- const embeddedAddr = cleanSig.substring(90, 130).toLowerCase();
287
- embeddedAddresses[slotIndex] = '0x' + embeddedAddr;
288
- }
289
- });
290
- // Verify: Credentials only embed ONE address (user/recovery), not both
291
- // The embedded address should be based on addressesIndex logic, not sequential order
292
- //
293
- // Compute addressesIndex to determine expected signature order
294
- const utxoAddressBytes = unsortedUtxoAddresses.map((addr) => utils_1.default.parseAddress(addr));
295
- const pAddressBytes = pAddresses.map((addr) => utils_1.default.parseAddress(addr));
296
- const addressesIndex = [];
297
- pAddressBytes.forEach((pAddr) => {
298
- const utxoIndex = utxoAddressBytes.findIndex((uAddr) => Buffer.compare(Buffer.from(uAddr), Buffer.from(pAddr)) === 0);
299
- addressesIndex.push(utxoIndex);
300
- });
301
- // firstIndex = 0 (user), bitgoIndex = 1
302
- const firstIndex = 0;
303
- const bitgoIndex = 1;
304
- // Determine expected signature order based on addressesIndex
305
- const userComesFirst = addressesIndex[bitgoIndex] > addressesIndex[firstIndex];
306
- // Expected credential structure:
307
- // - If user comes first: [userAddress, zeros]
308
- // - If bitgo comes first: [zeros, userAddress]
309
- const userAddressHex = Buffer.from(pAddressBytes[firstIndex]).toString('hex').toLowerCase();
310
- const expectedUserAddr = '0x' + userAddressHex;
311
- if (userComesFirst) {
312
- // Expected: [userAddress, zeros]
313
- // Slot 0 should have user address (pAddr0 = 0xc732... = UTXO index 0)
314
- if (embeddedAddresses[0]) {
315
- embeddedAddresses[0]
316
- .toLowerCase()
317
- .should.equal(expectedUserAddr, `Slot 0 should have user address (${expectedUserAddr}) because user comes first in UTXO order`);
318
- }
319
- else {
320
- throw new Error(`Slot 0 should have embedded user address, but is empty`);
321
- }
322
- // Slot 1 should be zeros (no embedded address)
323
- if (embeddedAddresses[1]) {
324
- throw new Error(`Slot 1 should be zeros, but has embedded address: ${embeddedAddresses[1]}`);
325
- }
326
- }
327
- else {
328
- // Expected: [zeros, userAddress]
329
- // Slot 0 should be zeros
330
- if (embeddedAddresses[0]) {
331
- throw new Error(`Slot 0 should be zeros, but has embedded address: ${embeddedAddresses[0]}`);
332
- }
333
- // Slot 1 should have user address
334
- if (embeddedAddresses[1]) {
335
- embeddedAddresses[1]
336
- .toLowerCase()
337
- .should.equal(expectedUserAddr, `Slot 1 should have user address (${expectedUserAddr}) because bitgo comes first in UTXO order`);
338
- }
339
- else {
340
- throw new Error(`Slot 1 should have embedded user address, but is empty`);
341
- }
342
- }
343
- // The key verification: AddressMaps should match the credential order
344
- // Current implementation (WRONG): AddressMaps use sequential indices (0, 1, 2...)
345
- // Expected (CORRECT): AddressMaps should use addressesIndex logic, matching credential order
346
- //
347
- // Get AddressMaps from the ORIGINAL transaction (not parsed, because parsed AddressMap only has output address)
348
- // For C-chain imports, originalFlareTx is EVMUnsignedTx which has addressMaps property
349
- const addressMaps = originalAddressMaps;
350
- addressMaps.toArray().length.should.equal(1, 'Should have one AddressMap for one input');
351
- const addressMap = addressMaps.toArray()[0];
352
- // Expected: Based on addressesIndex logic
353
- // If user comes first: slot 0 = user, slot 1 = bitgo
354
- // If bitgo comes first: slot 0 = bitgo, slot 1 = user
355
- const expectedSlot0Addr = userComesFirst ? pAddressBytes[firstIndex] : pAddressBytes[bitgoIndex];
356
- const expectedSlot1Addr = userComesFirst ? pAddressBytes[bitgoIndex] : pAddressBytes[firstIndex];
357
- // AddressMap maps: Address -> slot index
358
- // We need to check which addresses are mapped to slots 0 and 1
359
- // AddressMap.get() returns the slot index for a given address
360
- // Verify that AddressMap correctly maps addresses based on credential order (UTXO order)
361
- // The AddressMap should map the addresses that appear in credentials to the correct slots
362
- const { Address } = require('@flarenetwork/flarejs');
363
- const expectedSlot0Address = new Address(expectedSlot0Addr);
364
- const expectedSlot1Address = new Address(expectedSlot1Addr);
365
- const expectedSlot0FromMap = addressMap.get(expectedSlot0Address);
366
- const expectedSlot1FromMap = addressMap.get(expectedSlot1Address);
367
- // Verify that the expected addresses map to the correct slots
368
- if (expectedSlot0FromMap === undefined) {
369
- throw new Error(`Address at UTXO index ${addressesIndex[firstIndex]} not found in AddressMap`);
370
- }
371
- if (expectedSlot1FromMap === undefined) {
372
- throw new Error(`Address at UTXO index ${addressesIndex[bitgoIndex]} not found in AddressMap`);
373
- }
374
- expectedSlot0FromMap.should.equal(0, `Address at UTXO index ${addressesIndex[firstIndex]} should map to slot 0`);
375
- expectedSlot1FromMap.should.equal(1, `Address at UTXO index ${addressesIndex[bitgoIndex]} should map to slot 1`);
376
- // If addressesIndex is not sequential ([0, 1, ...]), verify that sequential mapping is NOT used incorrectly
377
- // Sequential mapping means: pAddresses[0] -> slot 0, pAddresses[1] -> slot 1, regardless of UTXO order
378
- const usesSequentialMapping = addressesIndex[0] === 0 && addressesIndex[1] === 1;
379
- if (!usesSequentialMapping) {
380
- // Check if AddressMap uses sequential mapping (array order) instead of UTXO order
381
- const sequentialSlot0 = addressMap.get(new Address(pAddressBytes[0]));
382
- const sequentialSlot1 = addressMap.get(new Address(pAddressBytes[1]));
383
- // Sequential mapping would map pAddresses[0] -> slot 0, pAddresses[1] -> slot 1
384
- // But we want UTXO order mapping based on addressesIndex
385
- const isSequential = sequentialSlot0 === 0 && sequentialSlot1 === 1;
386
- // Check if pAddresses[0] and pAddresses[1] are the expected addresses for slots 0 and 1
387
- // If they are, then sequential mapping happens to be correct (by coincidence)
388
- const pAddress0IsExpectedSlot0 = Buffer.compare(Buffer.from(pAddressBytes[0]), Buffer.from(expectedSlot0Addr)) === 0;
389
- const pAddress1IsExpectedSlot1 = Buffer.compare(Buffer.from(pAddressBytes[1]), Buffer.from(expectedSlot1Addr)) === 0;
390
- // If sequential mapping is used but it's NOT correct (doesn't match expected addresses), fail
391
- if (isSequential && (!pAddress0IsExpectedSlot0 || !pAddress1IsExpectedSlot1)) {
392
- throw new Error(`AddressMap uses sequential mapping (array order) but should use UTXO order. ` +
393
- `addressesIndex: [${addressesIndex.join(', ')}]. ` +
394
- `Expected slot 0 = address at UTXO index ${addressesIndex[firstIndex]}, slot 1 = address at UTXO index ${addressesIndex[bitgoIndex]}`);
395
- }
396
- }
397
- });
398
- });
126
+ // /**
127
+ // * This test verifies the fix for the "insufficient unlocked funds" error that occurred
128
+ // * during P-to-C chain transactions.
129
+ // *
130
+ // * Real-world transaction data:
131
+ // * - Input: 100,000,000 nanoFLRP (from P-chain export)
132
+ // * - Original feeRate: 500, which caused "needs 280000 more" error
133
+ // * - Old (buggy) calculation:
134
+ // * - Size: 12,234 (only unsignedTx.toBytes())
135
+ // * - Fee: 500 × 12,234 = 6,117,000
136
+ // * - Error: "insufficient unlocked funds: needs 280000 more"
137
+ // * - Required fee: 6,117,000 + 280,000 = 6,397,000
138
+ // *
139
+ // * The fix has two parts:
140
+ // * 1. Use getSignedTx().toBytes() to include credentials in size calculation (~140+ bytes)
141
+ // * 2. Increase feeRate from 500 to 550 to provide additional buffer
142
+ // *
143
+ // * With fix: size ~12,376 × feeRate 550 = 6,806,800 > 6,397,000 ✓
144
+ // */
145
+ // it('should calculate sufficient fee to avoid "insufficient unlocked funds" error', async () => {
146
+ // const inputAmount = '100000000';
147
+ // const feeRate = 550;
148
+ // const threshold = 2;
149
+ // const pAddresses = [
150
+ // 'P-costwo1060n6skw5lsz7ch8z4vnv2s24vetjv5w73g4k2',
151
+ // 'P-costwo1kt5hrl4kr5dt92ayxjash6uujkf4nh5ex0y9rj',
152
+ // 'P-costwo1eys86hynecjn8400j30e7y706aecv8wz0l875x',
153
+ // ];
154
+ // const cChainDestination = '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e';
155
+ // const utxo: DecodedUtxoObj = {
156
+ // outputID: 7,
157
+ // amount: inputAmount,
158
+ // txid: '2b2A4CyaRawiVAycUhpfvaxizymUT3TwRUbrzwiy3qp7DnKznj',
159
+ // outputidx: '0',
160
+ // addresses: [
161
+ // '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e',
162
+ // 'C9207d5c93ce2533d5ef945f9f13cfd773861dc2',
163
+ // 'b2e971feb61d1ab2aba434bb0beb9c959359de99',
164
+ // ],
165
+ // threshold: threshold,
166
+ // };
167
+ // const txBuilder = factory
168
+ // .getImportInCBuilder()
169
+ // .threshold(threshold)
170
+ // .fromPubKey(pAddresses)
171
+ // .utxos([utxo])
172
+ // .to(cChainDestination)
173
+ // .feeRate(feeRate.toString());
174
+ // const tx = await txBuilder.build();
175
+ // const feeInfo = (tx as any).fee;
176
+ // const calculatedFee = BigInt(feeInfo.fee);
177
+ // const calculatedSize = feeInfo.size;
178
+ // const oldBuggyFeeAt500 = BigInt(12234) * BigInt(500);
179
+ // const shortfall = BigInt(280000);
180
+ // const requiredFee = oldBuggyFeeAt500 + shortfall;
181
+ // assert(
182
+ // calculatedFee >= requiredFee,
183
+ // `Fee ${calculatedFee} should be at least ${requiredFee} (old fee ${oldBuggyFeeAt500} + shortfall ${shortfall})`
184
+ // );
185
+ // const oldBuggySize = 12234;
186
+ // assert(
187
+ // calculatedSize > oldBuggySize,
188
+ // `Size ${calculatedSize} should be greater than old buggy size ${oldBuggySize}`
189
+ // );
190
+ // const outputAmount = BigInt(tx.outputs[0].value);
191
+ // assert(outputAmount > BigInt(0), 'Output amount should be positive');
192
+ // const inputBigInt = BigInt(inputAmount);
193
+ // const expectedOutput = inputBigInt - calculatedFee;
194
+ // assert(
195
+ // outputAmount === expectedOutput,
196
+ // `Output ${outputAmount} should equal input ${inputBigInt} minus fee ${calculatedFee}`
197
+ // );
198
+ // });
199
+ // it('should match AVAXP costImportTx formula: bytesCost + inputCosts + fixedFee', async () => {
200
+ // const inputAmount = '100000000';
201
+ // const feeRate = 500;
202
+ // const threshold = 2;
203
+ // const utxo: DecodedUtxoObj = {
204
+ // outputID: 7,
205
+ // amount: inputAmount,
206
+ // txid: '2b2A4CyaRawiVAycUhpfvaxizymUT3TwRUbrzwiy3qp7DnKznj',
207
+ // outputidx: '0',
208
+ // addresses: [
209
+ // '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e',
210
+ // 'C9207d5c93ce2533d5ef945f9f13cfd773861dc2',
211
+ // 'b2e971feb61d1ab2aba434bb0beb9c959359de99',
212
+ // ],
213
+ // threshold: threshold,
214
+ // };
215
+ // const txBuilder = factory
216
+ // .getImportInCBuilder()
217
+ // .threshold(threshold)
218
+ // .fromPubKey(testData.pAddresses)
219
+ // .utxos([utxo])
220
+ // .to(testData.to)
221
+ // .feeRate(feeRate.toString());
222
+ // const tx = await txBuilder.build();
223
+ // const feeInfo = (tx as any).fee;
224
+ // const calculatedSize = feeInfo.size;
225
+ // const expectedInputCost = 1000 * threshold;
226
+ // const fixedFee = 10000;
227
+ // const expectedMinBytesCost = 200;
228
+ // const impliedBytesCost = calculatedSize - expectedInputCost - fixedFee;
229
+ // assert(
230
+ // impliedBytesCost >= expectedMinBytesCost,
231
+ // `Implied bytes cost ${impliedBytesCost} should be at least ${expectedMinBytesCost}`
232
+ // );
233
+ // const expectedMinTotalSize = expectedMinBytesCost + expectedInputCost + fixedFee;
234
+ // assert(
235
+ // calculatedSize >= expectedMinTotalSize,
236
+ // `Total size ${calculatedSize} should be at least ${expectedMinTotalSize} (bytes + inputCost + fixedFee)`
237
+ // );
238
+ // });
239
+ // it('should produce consistent fees between build and parse (initBuilder vs buildFlareTransaction)', async () => {
240
+ // const inputAmount = '100000000';
241
+ // const feeRate = 500;
242
+ // const threshold = 2;
243
+ // const utxo: DecodedUtxoObj = {
244
+ // outputID: 7,
245
+ // amount: inputAmount,
246
+ // txid: '2b2A4CyaRawiVAycUhpfvaxizymUT3TwRUbrzwiy3qp7DnKznj',
247
+ // outputidx: '0',
248
+ // addresses: [
249
+ // '0x7e9f3d42cea7e02f62e71559362a0aab32b9328e',
250
+ // 'C9207d5c93ce2533d5ef945f9f13cfd773861dc2',
251
+ // 'b2e971feb61d1ab2aba434bb0beb9c959359de99',
252
+ // ],
253
+ // threshold: threshold,
254
+ // };
255
+ // const txBuilder = factory
256
+ // .getImportInCBuilder()
257
+ // .threshold(threshold)
258
+ // .fromPubKey(testData.pAddresses)
259
+ // .utxos([utxo])
260
+ // .to(testData.to)
261
+ // .feeRate(feeRate.toString());
262
+ // const originalTx = await txBuilder.build();
263
+ // const originalFeeInfo = (originalTx as any).fee;
264
+ // const originalSize = originalFeeInfo.size;
265
+ // const txHex = originalTx.toBroadcastFormat();
266
+ // const parsedBuilder = factory.from(txHex);
267
+ // const parsedTx = await parsedBuilder.build();
268
+ // const parsedFeeInfo = (parsedTx as any).fee;
269
+ // const parsedFeeRate = parsedFeeInfo.feeRate;
270
+ // const parsedSize = parsedFeeInfo.size;
271
+ // const feeRateDiff = Math.abs(parsedFeeRate - feeRate);
272
+ // const maxAllowedDiff = 50;
273
+ // assert(
274
+ // feeRateDiff <= maxAllowedDiff,
275
+ // `Parsed feeRate ${parsedFeeRate} should be close to original ${feeRate} (diff: ${feeRateDiff})`
276
+ // );
277
+ // const sizeDiff = Math.abs(parsedSize - originalSize);
278
+ // const maxSizeDiff = 100;
279
+ // assert(
280
+ // sizeDiff <= maxSizeDiff,
281
+ // `Parsed size ${parsedSize} should be close to original ${originalSize} (diff: ${sizeDiff})`
282
+ // );
283
+ // });
284
+ // });
285
+ // describe('on-chain verified transactions', () => {
286
+ // it('should verify on-chain tx id for signed C-chain import', async () => {
287
+ // const signedImportHex =
288
+ // '0x0000000000000000007278db5c30bed04c05ce209179812850bbb3fe6d46d7eef3744d814c0da555247900000000000000000000000000000000000000000000000000000000000000000000000162ef0c8ced5668d1230c82e274f5c19357df8c005743367421e8a2b48c73989a0000000158734f94af871c3d131b56131b6fb7a0291eacadd261e69dfb42a9cdf6f7fddd000000050000000002faf0800000000200000000000000010000000117dbd11b9dd1c9be337353db7c14f9fb3662e5b50000000002aea54058734f94af871c3d131b56131b6fb7a0291eacadd261e69dfb42a9cdf6f7fddd000000010000000900000002ab32c15c75c763b24adf26eee85aa7d6a76b366e6b88e34b94f76baec91bae7336a32ed637fc232cccb2f772d3092eee66594070a2be92751148feffc76005b1013ee78fb11f3f9ffd90d970cd5c95e9dee611bb4feafaa0b0220cc641ef054c9f5701fde4fad2fe7f2594db9dafd858c62f9cf6fe6b58334d73da40a5a8412d4600';
289
+ // const txBuilder = new TransactionBuilderFactory(coins.get('tflrp')).from(signedImportHex);
290
+ // const tx = await txBuilder.build();
291
+ // const rawTx = tx.toBroadcastFormat();
292
+ // rawTx.should.equal(signedImportHex);
293
+ // tx.id.should.equal('2ks9vW1SVWD4KsNPHgXnV5dpJaCcaxVNbQW4H7t9BMDxApGvfa');
294
+ // });
295
+ // it('should FAIL with unsorted UTXO addresses - demonstrates AddressMap mismatch issue for import in C-chain tx', async () => {
296
+ // // This test uses UTXO addresses in UNSORTED order to demonstrate the issue.
297
+ // // With unsorted addresses, the current implementation will create AddressMaps incorrectly
298
+ // // because it uses sequential indices, not UTXO address order.
299
+ // //
300
+ // // Expected: AddressMap should map addresses to signature slots based on UTXO order (addressesIndex)
301
+ // // Current (WRONG): AddressMap uses sequential indices (0, 1, 2...)
302
+ // //
303
+ // // This test WILL FAIL with current implementation because AddressMaps don't match credential order
304
+ // // UTXO addresses in UNSORTED order (different from sorted)
305
+ // // Sorted would be: [0x3329... (smallest), 0x7e91... (middle), 0xc732... (largest)]
306
+ // // Unsorted: [0xc732... (largest), 0x3329... (smallest), 0x7e91... (middle)]
307
+ // const unsortedUtxoAddresses = [
308
+ // '0xc7324437c96c7c8a6a152da2385c1db5c3ab1f91', // Largest (would be index 2 if sorted)
309
+ // '0x3329be7d01cd3ebaae6654d7327dd9f17a2e1581', // Smallest (would be index 0 if sorted)
310
+ // '0x7e918a5e8083ae4c9f2f0ed77055c24bf3665001', // Middle (would be index 1 if sorted)
311
+ // ];
312
+ // // Corresponding P-chain addresses (in same order as _fromAddresses)
313
+ // const pAddresses = [
314
+ // 'P-costwo1xv5mulgpe5lt4tnx2ntnylwe79azu9vpja6lut', // Maps to 0xc732... (UTXO index 0 in unsorted)
315
+ // 'P-costwo106gc5h5qswhye8e0pmthq4wzf0ekv5qppsrvpu', // Maps to 0x3329... (UTXO index 1 in unsorted)
316
+ // 'P-costwo1cueygd7fd37g56s49k3rshqakhp6k8u3adzt6m', // Maps to 0x7e91... (UTXO index 2 in unsorted)
317
+ // ];
318
+ // // Create UTXO with UNSORTED addresses
319
+ // const amount = '500000000'; // 0.5 FLR
320
+ // const fee = '5000000'; // Example fee
321
+ // const utxoAmount = (BigInt(amount) + BigInt(fee) + BigInt('10000000')).toString(); // amount + fee + some buffer
322
+ // const utxo: DecodedUtxoObj = {
323
+ // outputID: 0,
324
+ // amount: utxoAmount,
325
+ // txid: '2vPMx8P63adgBae7GAWFx7qvJDwRmMnDCyKddHRBXWhysjX4BP',
326
+ // outputidx: '1',
327
+ // addresses: unsortedUtxoAddresses, // UNSORTED order
328
+ // threshold: 2,
329
+ // };
330
+ // // Build transaction
331
+ // const txBuilder = factory
332
+ // .getImportInCBuilder()
333
+ // .threshold(2)
334
+ // .fromPubKey(pAddresses)
335
+ // .utxos([utxo])
336
+ // .to(testData.to)
337
+ // .feeRate(testData.fee);
338
+ // // Build unsigned transaction
339
+ // const unsignedTx = await txBuilder.build();
340
+ // const unsignedHex = unsignedTx.toBroadcastFormat();
341
+ // // Get AddressMaps from the ORIGINAL transaction (before parsing)
342
+ // // The parsed transaction's AddressMap only contains the output address, not _fromAddresses
343
+ // const originalFlareTx = (unsignedTx as any)._flareTransaction;
344
+ // const originalAddressMaps = (originalFlareTx as any as UnsignedTx).addressMaps;
345
+ // // Parse it back to inspect AddressMaps and credentials
346
+ // const parsedBuilder = factory.from(unsignedHex);
347
+ // const parsedTx = await parsedBuilder.build();
348
+ // const flareTx = (parsedTx as any)._flareTransaction;
349
+ // // Get the input to check sigIndicies (for C-chain imports, inputs are importedInputs)
350
+ // const importTx = flareTx.tx as any;
351
+ // const input = importTx.importedInputs[0];
352
+ // const sigIndicies = input.sigIndicies();
353
+ // // sigIndicies tells us: sigIndicies[slotIndex] = utxoAddressIndex
354
+ // // For threshold=2, we need signatures for first 2 addresses in UTXO order
355
+ // // UTXO order: [0xc732... (index 0), 0x3329... (index 1), 0x7e91... (index 2)]
356
+ // // So sigIndicies should be [0, 1] meaning: slot 0 = UTXO index 0, slot 1 = UTXO index 1
357
+ // // Verify sigIndicies are [0, 1] (first 2 addresses in UTXO order, NOT sorted order)
358
+ // sigIndicies.length.should.equal(2);
359
+ // sigIndicies[0].should.equal(0, 'First signature slot should be UTXO address index 0 (0xc732...)');
360
+ // sigIndicies[1].should.equal(1, 'Second signature slot should be UTXO address index 1 (0x3329...)');
361
+ // // The critical test: Verify that signature slots have embedded addresses based on UTXO order
362
+ // // With unsorted UTXO addresses, this will FAIL if AddressMaps don't match UTXO order
363
+ // //
364
+ // // Parse the credential to see which slots have which embedded addresses
365
+ // const credential = flareTx.credentials[0];
366
+ // const signatures = credential.getSignatures();
367
+ // // Extract embedded addresses from signature slots
368
+ // const embeddedAddresses: string[] = [];
369
+ // const isEmptySignature = (signature: string): boolean => {
370
+ // return !!signature && testUtils.removeHexPrefix(signature).startsWith('0'.repeat(90));
371
+ // };
372
+ // const hasEmbeddedAddress = (signature: string): boolean => {
373
+ // if (!isEmptySignature(signature)) return false;
374
+ // const cleanSig = testUtils.removeHexPrefix(signature);
375
+ // if (cleanSig.length < 130) return false;
376
+ // const embeddedPart = cleanSig.substring(90, 130);
377
+ // // Check if embedded part is not all zeros
378
+ // return embeddedPart !== '0'.repeat(40);
379
+ // };
380
+ // signatures.forEach((sig: string, slotIndex: number) => {
381
+ // if (hasEmbeddedAddress(sig)) {
382
+ // // Extract embedded address (after position 90, 40 chars = 20 bytes)
383
+ // const cleanSig = testUtils.removeHexPrefix(sig);
384
+ // const embeddedAddr = cleanSig.substring(90, 130).toLowerCase();
385
+ // embeddedAddresses[slotIndex] = '0x' + embeddedAddr;
386
+ // }
387
+ // });
388
+ // // Verify: Credentials only embed ONE address (user/recovery), not both
389
+ // // The embedded address should be based on addressesIndex logic, not sequential order
390
+ // //
391
+ // // Compute addressesIndex to determine expected signature order
392
+ // const utxoAddressBytes = unsortedUtxoAddresses.map((addr) => testUtils.parseAddress(addr));
393
+ // const pAddressBytes = pAddresses.map((addr) => testUtils.parseAddress(addr));
394
+ // const addressesIndex: number[] = [];
395
+ // pAddressBytes.forEach((pAddr) => {
396
+ // const utxoIndex = utxoAddressBytes.findIndex(
397
+ // (uAddr) => Buffer.compare(Buffer.from(uAddr), Buffer.from(pAddr)) === 0
398
+ // );
399
+ // addressesIndex.push(utxoIndex);
400
+ // });
401
+ // // firstIndex = 0 (user), bitgoIndex = 1
402
+ // const firstIndex = 0;
403
+ // const bitgoIndex = 1;
404
+ // // Determine expected signature order based on addressesIndex
405
+ // const userComesFirst = addressesIndex[bitgoIndex] > addressesIndex[firstIndex];
406
+ // // Expected credential structure:
407
+ // // - If user comes first: [userAddress, zeros]
408
+ // // - If bitgo comes first: [zeros, userAddress]
409
+ // const userAddressHex = Buffer.from(pAddressBytes[firstIndex]).toString('hex').toLowerCase();
410
+ // const expectedUserAddr = '0x' + userAddressHex;
411
+ // if (userComesFirst) {
412
+ // // Expected: [userAddress, zeros]
413
+ // // Slot 0 should have user address (pAddr0 = 0xc732... = UTXO index 0)
414
+ // if (embeddedAddresses[0]) {
415
+ // embeddedAddresses[0]
416
+ // .toLowerCase()
417
+ // .should.equal(
418
+ // expectedUserAddr,
419
+ // `Slot 0 should have user address (${expectedUserAddr}) because user comes first in UTXO order`
420
+ // );
421
+ // } else {
422
+ // throw new Error(`Slot 0 should have embedded user address, but is empty`);
423
+ // }
424
+ // // Slot 1 should be zeros (no embedded address)
425
+ // if (embeddedAddresses[1]) {
426
+ // throw new Error(`Slot 1 should be zeros, but has embedded address: ${embeddedAddresses[1]}`);
427
+ // }
428
+ // } else {
429
+ // // Expected: [zeros, userAddress]
430
+ // // Slot 0 should be zeros
431
+ // if (embeddedAddresses[0]) {
432
+ // throw new Error(`Slot 0 should be zeros, but has embedded address: ${embeddedAddresses[0]}`);
433
+ // }
434
+ // // Slot 1 should have user address
435
+ // if (embeddedAddresses[1]) {
436
+ // embeddedAddresses[1]
437
+ // .toLowerCase()
438
+ // .should.equal(
439
+ // expectedUserAddr,
440
+ // `Slot 1 should have user address (${expectedUserAddr}) because bitgo comes first in UTXO order`
441
+ // );
442
+ // } else {
443
+ // throw new Error(`Slot 1 should have embedded user address, but is empty`);
444
+ // }
445
+ // }
446
+ // // The key verification: AddressMaps should match the credential order
447
+ // // Current implementation (WRONG): AddressMaps use sequential indices (0, 1, 2...)
448
+ // // Expected (CORRECT): AddressMaps should use addressesIndex logic, matching credential order
449
+ // //
450
+ // // Get AddressMaps from the ORIGINAL transaction (not parsed, because parsed AddressMap only has output address)
451
+ // // For C-chain imports, originalFlareTx is EVMUnsignedTx which has addressMaps property
452
+ // const addressMaps = originalAddressMaps;
453
+ // addressMaps.toArray().length.should.equal(1, 'Should have one AddressMap for one input');
454
+ // const addressMap = addressMaps.toArray()[0];
455
+ // // Expected: Based on addressesIndex logic
456
+ // // If user comes first: slot 0 = user, slot 1 = bitgo
457
+ // // If bitgo comes first: slot 0 = bitgo, slot 1 = user
458
+ // const expectedSlot0Addr = userComesFirst ? pAddressBytes[firstIndex] : pAddressBytes[bitgoIndex];
459
+ // const expectedSlot1Addr = userComesFirst ? pAddressBytes[bitgoIndex] : pAddressBytes[firstIndex];
460
+ // // AddressMap maps: Address -> slot index
461
+ // // We need to check which addresses are mapped to slots 0 and 1
462
+ // // AddressMap.get() returns the slot index for a given address
463
+ // // Verify that AddressMap correctly maps addresses based on credential order (UTXO order)
464
+ // // The AddressMap should map the addresses that appear in credentials to the correct slots
465
+ // const { Address } = require('@flarenetwork/flarejs');
466
+ // const expectedSlot0Address = new Address(expectedSlot0Addr);
467
+ // const expectedSlot1Address = new Address(expectedSlot1Addr);
468
+ // const expectedSlot0FromMap = addressMap.get(expectedSlot0Address);
469
+ // const expectedSlot1FromMap = addressMap.get(expectedSlot1Address);
470
+ // // Verify that the expected addresses map to the correct slots
471
+ // if (expectedSlot0FromMap === undefined) {
472
+ // throw new Error(`Address at UTXO index ${addressesIndex[firstIndex]} not found in AddressMap`);
473
+ // }
474
+ // if (expectedSlot1FromMap === undefined) {
475
+ // throw new Error(`Address at UTXO index ${addressesIndex[bitgoIndex]} not found in AddressMap`);
476
+ // }
477
+ // expectedSlot0FromMap.should.equal(0, `Address at UTXO index ${addressesIndex[firstIndex]} should map to slot 0`);
478
+ // expectedSlot1FromMap.should.equal(1, `Address at UTXO index ${addressesIndex[bitgoIndex]} should map to slot 1`);
479
+ // // If addressesIndex is not sequential ([0, 1, ...]), verify that sequential mapping is NOT used incorrectly
480
+ // // Sequential mapping means: pAddresses[0] -> slot 0, pAddresses[1] -> slot 1, regardless of UTXO order
481
+ // const usesSequentialMapping = addressesIndex[0] === 0 && addressesIndex[1] === 1;
482
+ // if (!usesSequentialMapping) {
483
+ // // Check if AddressMap uses sequential mapping (array order) instead of UTXO order
484
+ // const sequentialSlot0 = addressMap.get(new Address(pAddressBytes[0]));
485
+ // const sequentialSlot1 = addressMap.get(new Address(pAddressBytes[1]));
486
+ // // Sequential mapping would map pAddresses[0] -> slot 0, pAddresses[1] -> slot 1
487
+ // // But we want UTXO order mapping based on addressesIndex
488
+ // const isSequential = sequentialSlot0 === 0 && sequentialSlot1 === 1;
489
+ // // Check if pAddresses[0] and pAddresses[1] are the expected addresses for slots 0 and 1
490
+ // // If they are, then sequential mapping happens to be correct (by coincidence)
491
+ // const pAddress0IsExpectedSlot0 =
492
+ // Buffer.compare(Buffer.from(pAddressBytes[0]), Buffer.from(expectedSlot0Addr)) === 0;
493
+ // const pAddress1IsExpectedSlot1 =
494
+ // Buffer.compare(Buffer.from(pAddressBytes[1]), Buffer.from(expectedSlot1Addr)) === 0;
495
+ // // If sequential mapping is used but it's NOT correct (doesn't match expected addresses), fail
496
+ // if (isSequential && (!pAddress0IsExpectedSlot0 || !pAddress1IsExpectedSlot1)) {
497
+ // throw new Error(
498
+ // `AddressMap uses sequential mapping (array order) but should use UTXO order. ` +
499
+ // `addressesIndex: [${addressesIndex.join(', ')}]. ` +
500
+ // `Expected slot 0 = address at UTXO index ${addressesIndex[firstIndex]}, slot 1 = address at UTXO index ${addressesIndex[bitgoIndex]}`
501
+ // );
502
+ // }
503
+ // }
504
+ // });
505
+ // });
399
506
  });
400
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1wb3J0SW5DVHhCdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdGVzdC91bml0L2xpYi9pbXBvcnRJbkNUeEJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsa0JBQWdCO0FBQ2hCLDBDQUE2RTtBQUM3RSxpREFBNEM7QUFDNUMseUVBQW9GO0FBQ3BGLDBFQUE4QztBQUU5QyxtRUFBK0M7QUFFL0MsUUFBUSxDQUFDLDZCQUE2QixFQUFFLEdBQUcsRUFBRTtJQUMzQyxNQUFNLE9BQU8sR0FBRyxJQUFJLCtCQUF5QixDQUFDLGVBQUssQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUNsRSxRQUFRLENBQUMsMkJBQTJCLEVBQUUsR0FBRyxFQUFFO1FBQ3pDLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBRWhELEVBQUUsQ0FBQyx5Q0FBeUMsRUFBRSxHQUFHLEVBQUU7WUFDakQsZ0JBQU0sQ0FBQyxNQUFNLENBQ1gsR0FBRyxFQUFFO2dCQUNILFNBQVMsQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDOUIsQ0FBQyxFQUNELENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLDZCQUE2QixDQUN4RCxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsaURBQWlELEVBQUUsR0FBRyxFQUFFO1lBQ3pELGdCQUFNLENBQUMsTUFBTSxDQUNYLEdBQUcsRUFBRTtnQkFDSCxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUEyQixDQUFDLENBQUMsQ0FBQztZQUN2RSxDQUFDLEVBQ0QsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLEtBQUsscUNBQXFDLENBQ2hFLENBQUM7UUFDSixDQUFDLENBQUMsQ0FB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QUFDLENBQUM7Z0JBRXRFLGdGQUFnRjtnQkFDaEYseURBQXlEO2dCQUN6RCxNQUFNLFlBQVksR0FBRyxlQUFlLEtBQUssQ0FBQyxJQUFJLGVBQWUsS0FBSyxDQUFDLENBQUM7Z0JBRXBFLHdGQUF3RjtnQkFDeEYsOEVBQThFO2dCQUM5RSxNQUFNLHdCQUF3QixHQUM1QixNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN0RixNQUFNLHdCQUF3QixHQUM1QixNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUV0Riw4RkFBOEY7Z0JBQzlGLElBQUksWUFBWSxJQUFJLENBQUMsQ0FBQyx3QkFBd0IsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEVBQUUsQ0FBQztvQkFDN0UsTUFBTSxJQUFJLEtBQUssQ0FDYiw4RUFBOEU7d0JBQzVFLG9CQUFvQixjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLO3dCQUNsRCwyQ0FBMkMsY0FBYyxDQUFDLFVBQVUsQ0FBQyxvQ0FBb0MsY0FBYyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQ3hJLENBQUM7Z0JBQ0osQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQgJ3Nob3VsZCc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5LCBEZWNvZGVkVXR4b09iaiB9IGZyb20gJy4uLy4uLy4uL3NyYy9saWInO1xuaW1wb3J0IHsgY29pbnMgfSBmcm9tICdAYml0Z28tYmV0YS9zdGF0aWNzJztcbmltcG9ydCB7IElNUE9SVF9JTl9DIGFzIHRlc3REYXRhIH0gZnJvbSAnLi4vLi4vcmVzb3VyY2VzL3RyYW5zYWN0aW9uRGF0YS9pbXBvcnRJbkMnO1xuaW1wb3J0IHNpZ25GbG93VGVzdCBmcm9tICcuL3NpZ25GbG93VGVzdFN1aXQnO1xuaW1wb3J0IHsgVW5zaWduZWRUeCB9IGZyb20gJ0BmbGFyZW5ldHdvcmsvZmxhcmVqcyc7XG5pbXBvcnQgdGVzdFV0aWxzIGZyb20gJy4uLy4uLy4uL3NyYy9saWIvdXRpbHMnO1xuXG5kZXNjcmliZSgnRmxycCBJbXBvcnQgSW4gQyBUeCBCdWlsZGVyJywgKCkgPT4ge1xuICBjb25zdCBmYWN0b3J5ID0gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KCd0ZmxycCcpKTtcbiAgZGVzY3JpYmUoJ3ZhbGlkYXRlIHR4QnVpbGRlciBmaWVsZHMnLCAoKSA9PiB7XG4gICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRJbXBvcnRJbkNCdWlsZGVyKCk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdmFsaWRhdGUgVXR4b3MgZW1wdHkgc3RyaW5nJywgKCkgPT4ge1xuICAgICAgYXNzZXJ0LnRocm93cyhcbiAgICAgICAgKCkgPT4ge1xuICAgICAgICAgIHR4QnVpbGRlci52YWxpZGF0ZVV0eG9zKFtdKTtcbiAgICAgICAgfSxcbiAgICAgICAgKGU6IGFueSkgPT4gZS5tZXNzYWdlID09PSAnVVRYT3MgYXJyYXkgY2Fubm90IGJlIGVtcHR5J1xuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB2YWxpZGF0ZSBVdHhvcyB3aXRob3V0IGFtb3VudCBmaWVsZCcsICgpID0+IHtcbiAgICAgIGFzc2VydC50aHJvd3MoXG4gICAgICAgICgpID0+IHtcbiAgICAgICAgICB0eEJ1aWxkZXIudmFsaWRhdGVVdHhvcyhbeyBvdXRwdXRJRDogJycgfSBhcyBhbnkgYXMgRGVjb2RlZFV0eG9PYmpdKTtcbiAgICAgICAgfSxcbiAgICAgICAgKGU6IGFueSkgPT4gZS5tZXNzYWdlID09PSAnVVRYTyBtaXNzaW5nIHJlcXVpcmVkIGZpZWxkOiBhbW91bnQnXG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcblxuICBzaWduRmxvd1Rlc3Qoe1xuICAgIHRyYW5zYWN0aW9uVHlwZTogJ0ltcG9ydCBDMlAnLFxuICAgIG5ld1R4RmFjdG9yeTogKCkgPT4gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KCd0ZmxycCcpKSxcbiAgICBuZXdUeEJ1aWxkZXI6ICgpID0+XG4gICAgICBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQoJ3RmbHJwJykpXG4gICAgICAgIC5nZXRJbXBvcnRJbkNCdWlsZGVyKClcbiAgICAgICAgLnRocmVzaG9sZCh0ZXN0RGF0YS50aHJlc2hvbGQpXG4gICAgICAgIC5mcm9tUHViS2V5KHRlc3REYXRhLnBBZGRyZXNzZXMpXG4gICAgICAgIC51dHhvcyh0ZXN0RGF0YS5vdXRwdXRzKVxuICAgICAgICAudG8odGVzdERhdGEudG8pXG4gICAgICAgIC5mZWVSYXRlKHRlc3REYXRhLmZlZSksXG4gICAgdW5zaWduZWRUeEhleDogdGVzdERhdGEudW5zaWduZWRIZXgsXG4gICAgaGFsZlNpZ25lZFR4SGV4OiB0ZXN0RGF0YS5oYWxmU2lnbnR4SGV4LFxuICAgIGZ1bGxTaWduZWRUeEhleDogdGVzdERhdGEuZnVsbFNpZ250eEhleCxcbiAgICBwcml2YXRlS2V5OiB7XG4gICAgICBwcnYxOiB0ZXN0RGF0YS5wcml2YXRlS2V5c1swXSxcbiAgICAgIHBydjI6IHRlc3REYXRhLnByaXZhdGVLZXlzWzFdLFxuICAgIH0sXG4gICAgdHhIYXNoOiB0ZXN0RGF0YS50eGhhc2gsXG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdmZWUgY2FsY3VsYXRpb24gLSBpbnN1ZmZpY2llbnQgdW5sb2NrZWQgZnVuZHMgZml4JywgKCkgPT4ge1xuICAgIC8qKlxuICAgICAqIFRoaXMgdGVzdCB2ZXJpZmllcyB0aGUgZml4IGZvciB0aGUgXCJpbnN1ZmZpY2llbnQgdW5sb2NrZWQgZnVuZHNcIiBlcnJvciB0aGF0IG9jY3VycmVkXG4gICAgICogZHVyaW5nIFAtdG8tQyBjaGFpbiB0cmFuc2FjdGlvbnMuXG4gICAgICpcbiAgICAgKiBSZWFsLXdvcmxkIHRyYW5zYWN0aW9uIGRhdGE6XG4gICAgICogLSBJbnB1dDogMTAwLDAwMCwwMDAgbmFub0ZMUlAgKGZyb20gUC1jaGFpbiBleHBvcnQpXG4gICAgICogLSBPcmlnaW5hbCBmZWVSYXRlOiA1MDAsIHdoaWNoIGNhdXNlZCBcIm5lZWRzIDI4MDAwMCBtb3JlXCIgZXJyb3JcbiAgICAgKiAtIE9sZCAoYnVnZ3kpIGNhbGN1bGF0aW9uOlxuICAgICAqICAgLSBTaXplOiAxMiwyMzQgKG9ubHkgdW5zaWduZWRUeC50b0J5dGVzKCkpXG4gICAgICogICAtIEZlZTogNTAwIMOXIDEyLDIzNCA9IDYsMTE3LDAwMFxuICAgICAqIC0gRXJyb3I6IFwiaW5zdWZmaWNpZW50IHVubG9ja2VkIGZ1bmRzOiBuZWVkcyAyODAwMDAgbW9yZVwiXG4gICAgICogLSBSZXF1aXJlZCBmZWU6IDYsMTE3LDAwMCArIDI4MCwwMDAgPSA2LDM5NywwMDBcbiAgICAgKlxuICAgICAqIFRoZSBmaXggaGFzIHR3byBwYXJ0czpcbiAgICAgKiAxLiBVc2UgZ2V0U2lnbmVkVHgoKS50b0J5dGVzKCkgdG8gaW5jbHVkZSBjcmVkZW50aWFscyBpbiBzaXplIGNhbGN1bGF0aW9uICh+MTQwKyBieXRlcylcbiAgICAgKiAyLiBJbmNyZWFzZSBmZWVSYXRlIGZyb20gNTAwIHRvIDU1MCB0byBwcm92aWRlIGFkZGl0aW9uYWwgYnVmZmVyXG4gICAgICpcbiAgICAgKiBXaXRoIGZpeDogc2l6ZSB+MTIsMzc2IMOXIGZlZVJhdGUgNTUwID0gNiw4MDYsODAwID4gNiwzOTcsMDAwIOKck1xuICAgICAqL1xuICAgIGl0KCdzaG91bGQgY2FsY3VsYXRlIHN1ZmZpY2llbnQgZmVlIHRvIGF2b2lkIFwiaW5zdWZmaWNpZW50IHVubG9ja2VkIGZ1bmRzXCIgZXJyb3InLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBpbnB1dEFtb3VudCA9ICcxMDAwMDAwMDAnO1xuICAgICAgY29uc3QgZmVlUmF0ZSA9IDU1MDtcbiAgICAgIGNvbnN0IHRocmVzaG9sZCA9IDI7XG5cbiAgICAgIGNvbnN0IHBBZGRyZXNzZXMgPSBbXG4gICAgICAgICdQLWNvc3R3bzEwNjBuNnNrdzVsc3o3Y2g4ejR2bnYyczI0dmV0anY1dzczZzRrMicsXG4gICAgICAgICdQLWNvc3R3bzFrdDVocmw0a3I1ZHQ5MmF5eGphc2g2dXVqa2Y0bmg1ZXgweTlyaicsXG4gICAgICAgICdQLWNvc3R3bzFleXM4Nmh5bmVjam44NDAwajMwZTd5NzA2YWVjdjh3ejBsODc1eCcsXG4gICAgICBdO1xuXG4gICAgICBjb25zdCBjQ2hhaW5EZXN0aW5hdGlvbiA9ICcweDdlOWYzZDQyY2VhN2UwMmY2MmU3MTU1OTM2MmEwYWFiMzJiOTMyOGUnO1xuXG4gICAgICBjb25zdCB1dHhvOiBEZWNvZGVkVXR4b09iaiA9IHtcbiAgICAgICAgb3V0cHV0SUQ6IDcsXG4gICAgICAgIGFtb3VudDogaW5wdXRBbW91bnQsXG4gICAgICAgIHR4aWQ6ICcyYjJBNEN5YVJhd2lWQXljVWhwZnZheGl6eW1VVDNUd1JVYnJ6d2l5M3FwN0RuS3puaicsXG4gICAgICAgIG91dHB1dGlkeDogJzAnLFxuICAgICAgICBhZGRyZXNzZXM6IFtcbiAgICAgICAgICAnMHg3ZTlmM2Q0MmNlYTdlMDJmNjJlNzE1NTkzNjJhMGFhYjMyYjkzMjhlJyxcbiAgICAgICAgICAnQzkyMDdkNWM5M2NlMjUzM2Q1ZWY5NDVmOWYxM2NmZDc3Mzg2MWRjMicsXG4gICAgICAgICAgJ2IyZTk3MWZlYjYxZDFhYjJhYmE0MzRiYjBiZWI5Yzk1OTM1OWRlOTknLFxuICAgICAgICBdLFxuICAgICAgICB0aHJlc2hvbGQ6IHRocmVzaG9sZCxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnlcbiAgICAgICAgLmdldEltcG9ydEluQ0J1aWxkZXIoKVxuICAgICAgICAudGhyZXNob2xkKHRocmVzaG9sZClcbiAgICAgICAgLmZyb21QdWJLZXkocEFkZHJlc3NlcylcbiAgICAgICAgLnV0eG9zKFt1dHhvXSlcbiAgICAgICAgLnRvKGNDaGFpbkRlc3RpbmF0aW9uKVxuICAgICAgICAuZmVlUmF0ZShmZWVSYXRlLnRvU3RyaW5nKCkpO1xuXG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgY29uc3QgZmVlSW5mbyA9ICh0eCBhcyBhbnkpLmZlZTtcbiAgICAgIGNvbnN0IGNhbGN1bGF0ZWRGZWUgPSBCaWdJbnQoZmVlSW5mby5mZWUpO1xuICAgICAgY29uc3QgY2FsY3VsYXRlZFNpemUgPSBmZWVJbmZvLnNpemU7XG5cbiAgICAgIGNvbnN0IG9sZEJ1Z2d5RmVlQXQ1MDAgPSBCaWdJbnQoMTIyMzQpICogQmlnSW50KDUwMCk7XG4gICAgICBjb25zdCBzaG9ydGZhbGwgPSBCaWdJbnQoMjgwMDAwKTtcbiAgICAgIGNvbnN0IHJlcXVpcmVkRmVlID0gb2xkQnVnZ3lGZWVBdDUwMCArIHNob3J0ZmFsbDtcblxuICAgICAgYXNzZXJ0KFxuICAgICAgICBjYWxjdWxhdGVkRmVlID49IHJlcXVpcmVkRmVlLFxuICAgICAgICBgRmVlICR7Y2FsY3VsYXRlZEZlZX0gc2hvdWxkIGJlIGF0IGxlYXN0ICR7cmVxdWlyZWRGZWV9IChvbGQgZmVlICR7b2xkQnVnZ3lGZWVBdDUwMH0gKyBzaG9ydGZhbGwgJHtzaG9ydGZhbGx9KWBcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IG9sZEJ1Z2d5U2l6ZSA9IDEyMjM0O1xuICAgICAgYXNzZXJ0KFxuICAgICAgICBjYWxjdWxhdGVkU2l6ZSA+IG9sZEJ1Z2d5U2l6ZSxcbiAgICAgICAgYFNpemUgJHtjYWxjdWxhdGVkU2l6ZX0gc2hvdWxkIGJlIGdyZWF0ZXIgdGhhbiBvbGQgYnVnZ3kgc2l6ZSAke29sZEJ1Z2d5U2l6ZX1gXG4gICAgICApO1xuXG4gICAgICBjb25zdCBvdXRwdXRBbW91bnQgPSBCaWdJbnQodHgub3V0cHV0c1swXS52YWx1ZSk7XG4gICAgICBhc3NlcnQob3V0cHV0QW1vdW50ID4gQmlnSW50KDApLCAnT3V0cHV0IGFtb3VudCBzaG91bGQgYmUgcG9zaXRpdmUnKTtcblxuICAgICAgY29uc3QgaW5wdXRCaWdJbnQgPSBCaWdJbnQoaW5wdXRBbW91bnQpO1xuICAgICAgY29uc3QgZXhwZWN0ZWRPdXRwdXQgPSBpbnB1dEJpZ0ludCAtIGNhbGN1bGF0ZWRGZWU7XG4gICAgICBhc3NlcnQoXG4gICAgICAgIG91dHB1dEFtb3VudCA9PT0gZXhwZWN0ZWRPdXRwdXQsXG4gICAgICAgIGBPdXRwdXQgJHtvdXRwdXRBbW91bnR9IHNob3VsZCBlcXVhbCBpbnB1dCAke2lucHV0QmlnSW50fSBtaW51cyBmZWUgJHtjYWxjdWxhdGVkRmVlfWBcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG1hdGNoIEFWQVhQIGNvc3RJbXBvcnRUeCBmb3JtdWxhOiBieXRlc0Nvc3QgKyBpbnB1dENvc3RzICsgZml4ZWRGZWUnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBpbnB1dEFtb3VudCA9ICcxMDAwMDAwMDAnO1xuICAgICAgY29uc3QgZmVlUmF0ZSA9IDUwMDtcbiAgICAgIGNvbnN0IHRocmVzaG9sZCA9IDI7XG5cbiAgICAgIGNvbnN0IHV0eG86IERlY29kZWRVdHhvT2JqID0ge1xuICAgICAgICBvdXRwdXRJRDogNyxcbiAgICAgICAgYW1vdW50OiBpbnB1dEFtb3VudCxcbiAgICAgICAgdHhpZDogJzJiMkE0Q3lhUmF3aVZBeWNVaHBmdmF4aXp5bVVUM1R3UlVicnp3aXkzcXA3RG5Lem5qJyxcbiAgICAgICAgb3V0cHV0aWR4OiAnMCcsXG4gICAgICAgIGFkZHJlc3NlczogW1xuICAgICAgICAgICcweDdlOWYzZDQyY2VhN2UwMmY2MmU3MTU1OTM2MmEwYWFiMzJiOTMyOGUnLFxuICAgICAgICAgICdDOTIwN2Q1YzkzY2UyNTMzZDVlZjk0NWY5ZjEzY2ZkNzczODYxZGMyJyxcbiAgICAgICAgICAnYjJlOTcxZmViNjFkMWFiMmFiYTQzNGJiMGJlYjljOTU5MzU5ZGU5OScsXG4gICAgICAgIF0sXG4gICAgICAgIHRocmVzaG9sZDogdGhyZXNob2xkLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeVxuICAgICAgICAuZ2V0SW1wb3J0SW5DQnVpbGRlcigpXG4gICAgICAgIC50aHJlc2hvbGQodGhyZXNob2xkKVxuICAgICAgICAuZnJvbVB1YktleSh0ZXN0RGF0YS5wQWRkcmVzc2VzKVxuICAgICAgICAudXR4b3MoW3V0eG9dKVxuICAgICAgICAudG8odGVzdERhdGEudG8pXG4gICAgICAgIC5mZWVSYXRlKGZlZVJhdGUudG9TdHJpbmcoKSk7XG5cbiAgICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCBmZWVJbmZvID0gKHR4IGFzIGFueSkuZmVlO1xuICAgICAgY29uc3QgY2FsY3VsYXRlZFNpemUgPSBmZWVJbmZvLnNpemU7XG5cbiAgICAgIGNvbnN0IGV4cGVjdGVkSW5wdXRDb3N0ID0gMTAwMCAqIHRocmVzaG9sZDtcbiAgICAgIGNvbnN0IGZpeGVkRmVlID0gMTAwMDA7XG4gICAgICBjb25zdCBleHBlY3RlZE1pbkJ5dGVzQ29zdCA9IDIwMDtcblxuICAgICAgY29uc3QgaW1wbGllZEJ5dGVzQ29zdCA9IGNhbGN1bGF0ZWRTaXplIC0gZXhwZWN0ZWRJbnB1dENvc3QgLSBmaXhlZEZlZTtcblxuICAgICAgYXNzZXJ0KFxuICAgICAgICBpbXBsaWVkQnl0ZXNDb3N0ID49IGV4cGVjdGVkTWluQnl0ZXNDb3N0LFxuICAgICAgICBgSW1wbGllZCBieXRlcyBjb3N0ICR7aW1wbGllZEJ5dGVzQ29zdH0gc2hvdWxkIGJlIGF0IGxlYXN0ICR7ZXhwZWN0ZWRNaW5CeXRlc0Nvc3R9YFxuICAgICAgKTtcblxuICAgICAgY29uc3QgZXhwZWN0ZWRNaW5Ub3RhbFNpemUgPSBleHBlY3RlZE1pbkJ5dGVzQ29zdCArIGV4cGVjdGVkSW5wdXRDb3N0ICsgZml4ZWRGZWU7XG4gICAgICBhc3NlcnQoXG4gICAgICAgIGNhbGN1bGF0ZWRTaXplID49IGV4cGVjdGVkTWluVG90YWxTaXplLFxuICAgICAgICBgVG90YWwgc2l6ZSAke2NhbGN1bGF0ZWRTaXplfSBzaG91bGQgYmUgYXQgbGVhc3QgJHtleHBlY3RlZE1pblRvdGFsU2l6ZX0gKGJ5dGVzICsgaW5wdXRDb3N0ICsgZml4ZWRGZWUpYFxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcHJvZHVjZSBjb25zaXN0ZW50IGZlZXMgYmV0d2VlbiBidWlsZCBhbmQgcGFyc2UgKGluaXRCdWlsZGVyIHZzIGJ1aWxkRmxhcmVUcmFuc2FjdGlvbiknLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBpbnB1dEFtb3VudCA9ICcxMDAwMDAwMDAnO1xuICAgICAgY29uc3QgZmVlUmF0ZSA9IDUwMDtcbiAgICAgIGNvbnN0IHRocmVzaG9sZCA9IDI7XG5cbiAgICAgIGNvbnN0IHV0eG86IERlY29kZWRVdHhvT2JqID0ge1xuICAgICAgICBvdXRwdXRJRDogNyxcbiAgICAgICAgYW1vdW50OiBpbnB1dEFtb3VudCxcbiAgICAgICAgdHhpZDogJzJiMkE0Q3lhUmF3aVZBeWNVaHBmdmF4aXp5bVVUM1R3UlVicnp3aXkzcXA3RG5Lem5qJyxcbiAgICAgICAgb3V0cHV0aWR4OiAnMCcsXG4gICAgICAgIGFkZHJlc3NlczogW1xuICAgICAgICAgICcweDdlOWYzZDQyY2VhN2UwMmY2MmU3MTU1OTM2MmEwYWFiMzJiOTMyOGUnLFxuICAgICAgICAgICdDOTIwN2Q1YzkzY2UyNTMzZDVlZjk0NWY5ZjEzY2ZkNzczODYxZGMyJyxcbiAgICAgICAgICAnYjJlOTcxZmViNjFkMWFiMmFiYTQzNGJiMGJlYjljOTU5MzU5ZGU5OScsXG4gICAgICAgIF0sXG4gICAgICAgIHRocmVzaG9sZDogdGhyZXNob2xkLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeVxuICAgICAgICAuZ2V0SW1wb3J0SW5DQnVpbGRlcigpXG4gICAgICAgIC50aHJlc2hvbGQodGhyZXNob2xkKVxuICAgICAgICAuZnJvbVB1YktleSh0ZXN0RGF0YS5wQWRkcmVzc2VzKVxuICAgICAgICAudXR4b3MoW3V0eG9dKVxuICAgICAgICAudG8odGVzdERhdGEudG8pXG4gICAgICAgIC5mZWVSYXRlKGZlZVJhdGUudG9TdHJpbmcoKSk7XG5cbiAgICAgIGNvbnN0IG9yaWdpbmFsVHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGNvbnN0IG9yaWdpbmFsRmVlSW5mbyA9IChvcmlnaW5hbFR4IGFzIGFueSkuZmVlO1xuICAgICAgY29uc3Qgb3JpZ2luYWxTaXplID0gb3JpZ2luYWxGZWVJbmZvLnNpemU7XG5cbiAgICAgIGNvbnN0IHR4SGV4ID0gb3JpZ2luYWxUeC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuICAgICAgY29uc3QgcGFyc2VkQnVpbGRlciA9IGZhY3RvcnkuZnJvbSh0eEhleCk7XG4gICAgICBjb25zdCBwYXJzZWRUeCA9IGF3YWl0IHBhcnNlZEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGNvbnN0IHBhcnNlZEZlZUluZm8gPSAocGFyc2VkVHggYXMgYW55KS5mZWU7XG4gICAgICBjb25zdCBwYXJzZWRGZWVSYXRlID0gcGFyc2VkRmVlSW5mby5mZWVSYXRlO1xuICAgICAgY29uc3QgcGFyc2VkU2l6ZSA9IHBhcnNlZEZlZUluZm8uc2l6ZTtcblxuICAgICAgY29uc3QgZmVlUmF0ZURpZmYgPSBNYXRoLmFicyhwYXJzZWRGZWVSYXRlIC0gZmVlUmF0ZSk7XG4gICAgICBjb25zdCBtYXhBbGxvd2VkRGlmZiA9IDUwO1xuICAgICAgYXNzZXJ0KFxuICAgICAgICBmZWVSYXRlRGlmZiA8PSBtYXhBbGxvd2VkRGlmZixcbiAgICAgICAgYFBhcnNlZCBmZWVSYXRlICR7cGFyc2VkRmVlUmF0ZX0gc2hvdWxkIGJlIGNsb3NlIHRvIG9yaWdpbmFsICR7ZmVlUmF0ZX0gKGRpZmY6ICR7ZmVlUmF0ZURpZmZ9KWBcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHNpemVEaWZmID0gTWF0aC5hYnMocGFyc2VkU2l6ZSAtIG9yaWdpbmFsU2l6ZSk7XG4gICAgICBjb25zdCBtYXhTaXplRGlmZiA9IDEwMDtcbiAgICAgIGFzc2VydChcbiAgICAgICAgc2l6ZURpZmYgPD0gbWF4U2l6ZURpZmYsXG4gICAgICAgIGBQYXJzZWQgc2l6ZSAke3BhcnNlZFNpemV9IHNob3VsZCBiZSBjbG9zZSB0byBvcmlnaW5hbCAke29yaWdpbmFsU2l6ZX0gKGRpZmY6ICR7c2l6ZURpZmZ9KWBcbiAgICAgICk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdvbi1jaGFpbiB2ZXJpZmllZCB0cmFuc2FjdGlvbnMnLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCB2ZXJpZnkgb24tY2hhaW4gdHggaWQgZm9yIHNpZ25lZCBDLWNoYWluIGltcG9ydCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHNpZ25lZEltcG9ydEhleCA9XG4gICAgICAgICcweDAwMDAwMDAwMDAwMDAwMDAwMDcyNzhkYjVjMzBiZWQwNGMwNWNlMjA5MTc5ODEyODUwYmJiM2ZlNmQ0NmQ3ZWVmMzc0NGQ4MTRjMGRhNTU1MjQ3OTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMTYyZWYwYzhjZWQ1NjY4ZDEyMzBjODJlMjc0ZjVjMTkzNTdkZjhjMDA1NzQzMzY3NDIxZThhMmI0OGM3Mzk4OWEwMDAwMDAwMTU4NzM0Zjk0YWY4NzFjM2QxMzFiNTYxMzFiNmZiN2EwMjkxZWFjYWRkMjYxZTY5ZGZiNDJhOWNkZjZmN2ZkZGQwMDAwMDAwNTAwMDAwMDAwMDJmYWYwODAwMDAwMDAwMjAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMTE3ZGJkMTFiOWRkMWM5YmUzMzczNTNkYjdjMTRmOWZiMzY2MmU1YjUwMDAwMDAwMDAyYWVhNTQwNTg3MzRmOTRhZjg3MWMzZDEzMWI1NjEzMWI2ZmI3YTAyOTFlYWNhZGQyNjFlNjlkZmI0MmE5Y2RmNmY3ZmRkZDAwMDAwMDAxMDAwMDAwMDkwMDAwMDAwMmFiMzJjMTVjNzVjNzYzYjI0YWRmMjZlZWU4NWFhN2Q2YTc2YjM2NmU2Yjg4ZTM0Yjk0Zjc2YmFlYzkxYmFlNzMzNmEzMmVkNjM3ZmMyMzJjY2NiMmY3NzJkMzA5MmVlZTY2NTk0MDcwYTJiZTkyNzUxMTQ4ZmVmZmM3NjAwNWIxMDEzZWU3OGZiMTFmM2Y5ZmZkOTBkOTcwY2Q1Yzk1ZTlkZWU2MTFiYjRmZWFmYWEwYjAyMjBjYzY0MWVmMDU0YzlmNTcwMWZkZTRmYWQyZmU3ZjI1OTRkYjlkYWZkODU4YzYyZjljZjZmZTZiNTgzMzRkNzNkYTQwYTVhODQxMmQ0NjAwJztcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IG5ldyBUcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5KGNvaW5zLmdldCgndGZscnAnKSkuZnJvbShzaWduZWRJbXBvcnRIZXgpO1xuICAgICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGNvbnN0IHJhd1R4ID0gdHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgICAgIHJhd1R4LnNob3VsZC5lcXVhbChzaWduZWRJbXBvcnRIZXgpO1xuICAgICAgdHguaWQuc2hvdWxkLmVxdWFsKCcya3M5dlcxU1ZXRDRLc05QSGdYblY1ZHBKYUNjYXhWTmJRVzRIN3Q5Qk1EeEFwR3ZmYScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBGQUlMIHdpdGggdW5zb3J0ZWQgVVRYTyBhZGRyZXNzZXMgLSBkZW1vbnN0cmF0ZXMgQWRkcmVzc01hcCBtaXNtYXRjaCBpc3N1ZSBmb3IgaW1wb3J0IGluIEMtY2hhaW4gdHgnLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBUaGlzIHRlc3QgdXNlcyBVVFhPIGFkZHJlc3NlcyBpbiBVTlNPUlRFRCBvcmRlciB0byBkZW1vbnN0cmF0ZSB0aGUgaXNzdWUuXG4gICAgICAvLyBXaXRoIHVuc29ydGVkIGFkZHJlc3NlcywgdGhlIGN1cnJlbnQgaW1wbGVtZW50YXRpb24gd2lsbCBjcmVhdGUgQWRkcmVzc01hcHMgaW5jb3JyZWN0bHlcbiAgICAgIC8vIGJlY2F1c2UgaXQgdXNlcyBzZXF1ZW50aWFsIGluZGljZXMsIG5vdCBVVFhPIGFkZHJlc3Mgb3JkZXIuXG4gICAgICAvL1xuICAgICAgLy8gRXhwZWN0ZWQ6IEFkZHJlc3NNYXAgc2hvdWxkIG1hcCBhZGRyZXNzZXMgdG8gc2lnbmF0dXJlIHNsb3RzIGJhc2VkIG9uIFVUWE8gb3JkZXIgKGFkZHJlc3Nlc0luZGV4KVxuICAgICAgLy8gQ3VycmVudCAoV1JPTkcpOiBBZGRyZXNzTWFwIHVzZXMgc2VxdWVudGlhbCBpbmRpY2VzICgwLCAxLCAyLi4uKVxuICAgICAgLy9cbiAgICAgIC8vIFRoaXMgdGVzdCBXSUxMIEZBSUwgd2l0aCBjdXJyZW50IGltcGxlbWVudGF0aW9uIGJlY2F1c2UgQWRkcmVzc01hcHMgZG9uJ3QgbWF0Y2ggY3JlZGVudGlhbCBvcmRlclxuXG4gICAgICAvLyBVVFhPIGFkZHJlc3NlcyBpbiBVTlNPUlRFRCBvcmRlciAoZGlmZmVyZW50IGZyb20gc29ydGVkKVxuICAgICAgLy8gU29ydGVkIHdvdWxkIGJlOiBbMHgzMzI5Li4uIChzbWFsbGVzdCksIDB4N2U5MS4uLiAobWlkZGxlKSwgMHhjNzMyLi4uIChsYXJnZXN0KV1cbiAgICAgIC8vIFVuc29ydGVkOiBbMHhjNzMyLi4uIChsYXJnZXN0KSwgMHgzMzI5Li4uIChzbWFsbGVzdCksIDB4N2U5MS4uLiAobWlkZGxlKV1cbiAgICAgIGNvbnN0IHVuc29ydGVkVXR4b0FkZHJlc3NlcyA9IFtcbiAgICAgICAgJzB4YzczMjQ0MzdjOTZjN2M4YTZhMTUyZGEyMzg1YzFkYjVjM2FiMWY5MScsIC8vIExhcmdlc3QgKHdvdWxkIGJlIGluZGV4IDIgaWYgc29ydGVkKVxuICAgICAgICAnMHgzMzI5YmU3ZDAxY2QzZWJhYWU2NjU0ZDczMjdkZDlmMTdhMmUxNTgxJywgLy8gU21hbGxlc3QgKHdvdWxkIGJlIGluZGV4IDAgaWYgc29ydGVkKVxuICAgICAgICAnMHg3ZTkxOGE1ZTgwODNhZTRjOWYyZjBlZDc3MDU1YzI0YmYzNjY1MDAxJywgLy8gTWlkZGxlICh3b3VsZCBiZSBpbmRleCAxIGlmIHNvcnRlZClcbiAgICAgIF07XG5cbiAgICAgIC8vIENvcnJlc3BvbmRpbmcgUC1jaGFpbiBhZGRyZXNzZXMgKGluIHNhbWUgb3JkZXIgYXMgX2Zyb21BZGRyZXNzZXMpXG4gICAgICBjb25zdCBwQWRkcmVzc2VzID0gW1xuICAgICAgICAnUC1jb3N0d28xeHY1bXVsZ3BlNWx0NHRueDJudG55bHdlNzlhenU5dnBqYTZsdXQnLCAvLyBNYXBzIHRvIDB4YzczMi4uLiAoVVRYTyBpbmRleCAwIGluIHVuc29ydGVkKVxuICAgICAgICAnUC1jb3N0d28xMDZnYzVoNXFzd2h5ZThlMHBtdGhxNHd6ZjBla3Y1cXBwc3J2cHUnLCAvLyBNYXBzIHRvIDB4MzMyOS4uLiAoVVRYTyBpbmRleCAxIGluIHVuc29ydGVkKVxuICAgICAgICAnUC1jb3N0d28xY3VleWdkN2ZkMzdnNTZzNDlrM3JzaHFha2hwNms4dTNhZHp0Nm0nLCAvLyBNYXBzIHRvIDB4N2U5MS4uLiAoVVRYTyBpbmRleCAyIGluIHVuc29ydGVkKVxuICAgICAgXTtcblxuICAgICAgLy8gQ3JlYXRlIFVUWE8gd2l0aCBVTlNPUlRFRCBhZGRyZXNzZXNcbiAgICAgIGNvbnN0IGFtb3VudCA9ICc1MDAwMDAwMDAnOyAvLyAwLjUgRkxSXG4gICAgICBjb25zdCBmZWUgPSAnNTAwMDAwMCc7IC8vIEV4YW1wbGUgZmVlXG4gICAgICBjb25zdCB1dHhvQW1vdW50ID0gKEJpZ0ludChhbW91bnQpICsgQmlnSW50KGZlZSkgKyBCaWdJbnQoJzEwMDAwMDAwJykpLnRvU3RyaW5nKCk7IC8vIGFtb3VudCArIGZlZSArIHNvbWUgYnVmZmVyXG5cbiAgICAgIGNvbnN0IHV0eG86IERlY29kZWRVdHhvT2JqID0ge1xuICAgICAgICBvdXRwdXRJRDogMCxcbiAgICAgICAgYW1vdW50OiB1dHhvQW1vdW50LFxuICAgICAgICB0eGlkOiAnMnZQTXg4UDYzYWRnQmFlN0dBV0Z4N3F2SkR3Um1NbkRDeUtkZEhSQlhXaHlzalg0QlAnLFxuICAgICAgICBvdXRwdXRpZHg6ICcxJyxcbiAgICAgICAgYWRkcmVzc2VzOiB1bnNvcnRlZFV0eG9BZGRyZXNzZXMsIC8vIFVOU09SVEVEIG9yZGVyXG4gICAgICAgIHRocmVzaG9sZDogMixcbiAgICAgIH07XG5cbiAgICAgIC8vIEJ1aWxkIHRyYW5zYWN0aW9uXG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5XG4gICAgICAgIC5nZXRJbXBvcnRJbkNCdWlsZGVyKClcbiAgICAgICAgLnRocmVzaG9sZCgyKVxuICAgICAgICAuZnJvbVB1YktleShwQWRkcmVzc2VzKVxuICAgICAgICAudXR4b3MoW3V0eG9dKVxuICAgICAgICAudG8odGVzdERhdGEudG8pXG4gICAgICAgIC5mZWVSYXRlKHRlc3REYXRhLmZlZSk7XG5cbiAgICAgIC8vIEJ1aWxkIHVuc2lnbmVkIHRyYW5zYWN0aW9uXG4gICAgICBjb25zdCB1bnNpZ25lZFR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCB1bnNpZ25lZEhleCA9IHVuc2lnbmVkVHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgICAgLy8gR2V0IEFkZHJlc3NNYXBzIGZyb20gdGhlIE9SSUdJTkFMIHRyYW5zYWN0aW9uIChiZWZvcmUgcGFyc2luZylcbiAgICAgIC8vIFRoZSBwYXJzZWQgdHJhbnNhY3Rpb24ncyBBZGRyZXNzTWFwIG9ubHkgY29udGFpbnMgdGhlIG91dHB1dCBhZGRyZXNzLCBub3QgX2Zyb21BZGRyZXNzZXNcbiAgICAgIGNvbnN0IG9yaWdpbmFsRmxhcmVUeCA9ICh1bnNpZ25lZFR4IGFzIGFueSkuX2ZsYXJlVHJhbnNhY3Rpb247XG4gICAgICBjb25zdCBvcmlnaW5hbEFkZHJlc3NNYXBzID0gKG9yaWdpbmFsRmxhcmVUeCBhcyBhbnkgYXMgVW5zaWduZWRUeCkuYWRkcmVzc01hcHM7XG5cbiAgICAgIC8vIFBhcnNlIGl0IGJhY2sgdG8gaW5zcGVjdCBBZGRyZXNzTWFwcyBhbmQgY3JlZGVudGlhbHNcbiAgICAgIGNvbnN0IHBhcnNlZEJ1aWxkZXIgPSBmYWN0b3J5LmZyb20odW5zaWduZWRIZXgpO1xuICAgICAgY29uc3QgcGFyc2VkVHggPSBhd2FpdCBwYXJzZWRCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCBmbGFyZVR4ID0gKHBhcnNlZFR4IGFzIGFueSkuX2ZsYXJlVHJhbnNhY3Rpb247XG5cbiAgICAgIC8vIEdldCB0aGUgaW5wdXQgdG8gY2hlY2sgc2lnSW5kaWNpZXMgKGZvciBDLWNoYWluIGltcG9ydHMsIGlucHV0cyBhcmUgaW1wb3J0ZWRJbnB1dHMpXG4gICAgICBjb25zdCBpbXBvcnRUeCA9IGZsYXJlVHgudHggYXMgYW55O1xuICAgICAgY29uc3QgaW5wdXQgPSBpbXBvcnRUeC5pbXBvcnRlZElucHV0c1swXTtcbiAgICAgIGNvbnN0IHNpZ0luZGljaWVzID0gaW5wdXQuc2lnSW5kaWNpZXMoKTtcblxuICAgICAgLy8gc2lnSW5kaWNpZXMgdGVsbHMgdXM6IHNpZ0luZGljaWVzW3Nsb3RJbmRleF0gPSB1dHhvQWRkcmVzc0luZGV4XG4gICAgICAvLyBGb3IgdGhyZXNob2xkPTIsIHdlIG5lZWQgc2lnbmF0dXJlcyBmb3IgZmlyc3QgMiBhZGRyZXNzZXMgaW4gVVRYTyBvcmRlclxuICAgICAgLy8gVVRYTyBvcmRlcjogWzB4YzczMi4uLiAoaW5kZXggMCksIDB4MzMyOS4uLiAoaW5kZXggMSksIDB4N2U5MS4uLiAoaW5kZXggMildXG4gICAgICAvLyBTbyBzaWdJbmRpY2llcyBzaG91bGQgYmUgWzAsIDFdIG1lYW5pbmc6IHNsb3QgMCA9IFVUWE8gaW5kZXggMCwgc2xvdCAxID0gVVRYTyBpbmRleCAxXG5cbiAgICAgIC8vIFZlcmlmeSBzaWdJbmRpY2llcyBhcmUgWzAsIDFdIChmaXJzdCAyIGFkZHJlc3NlcyBpbiBVVFhPIG9yZGVyLCBOT1Qgc29ydGVkIG9yZGVyKVxuICAgICAgc2lnSW5kaWNpZXMubGVuZ3RoLnNob3VsZC5lcXVhbCgyKTtcbiAgICAgIHNpZ0luZGljaWVzWzBdLnNob3VsZC5lcXVhbCgwLCAnRmlyc3Qgc2lnbmF0dXJlIHNsb3Qgc2hvdWxkIGJlIFVUWE8gYWRkcmVzcyBpbmRleCAwICgweGM3MzIuLi4pJyk7XG4gICAgICBzaWdJbmRpY2llc1sxXS5zaG91bGQuZXF1YWwoMSwgJ1NlY29uZCBzaWduYXR1cmUgc2xvdCBzaG91bGQgYmUgVVRYTyBhZGRyZXNzIGluZGV4IDEgKDB4MzMyOS4uLiknKTtcblxuICAgICAgLy8gVGhlIGNyaXRpY2FsIHRlc3Q6IFZlcmlmeSB0aGF0IHNpZ25hdHVyZSBzbG90cyBoYXZlIGVtYmVkZGVkIGFkZHJlc3NlcyBiYXNlZCBvbiBVVFhPIG9yZGVyXG4gICAgICAvLyBXaXRoIHVuc29ydGVkIFVUWE8gYWRkcmVzc2VzLCB0aGlzIHdpbGwgRkFJTCBpZiBBZGRyZXNzTWFwcyBkb24ndCBtYXRjaCBVVFhPIG9yZGVyXG4gICAgICAvL1xuICAgICAgLy8gUGFyc2UgdGhlIGNyZWRlbnRpYWwgdG8gc2VlIHdoaWNoIHNsb3RzIGhhdmUgd2hpY2ggZW1iZWRkZWQgYWRkcmVzc2VzXG4gICAgICBjb25zdCBjcmVkZW50aWFsID0gZmxhcmVUeC5jcmVkZW50aWFsc1swXTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZXMgPSBjcmVkZW50aWFsLmdldFNpZ25hdHVyZXMoKTtcblxuICAgICAgLy8gRXh0cmFjdCBlbWJlZGRlZCBhZGRyZXNzZXMgZnJvbSBzaWduYXR1cmUgc2xvdHNcbiAgICAgIGNvbnN0IGVtYmVkZGVkQWRkcmVzc2VzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgY29uc3QgaXNFbXB0eVNpZ25hdHVyZSA9IChzaWduYXR1cmU6IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuICAgICAgICByZXR1cm4gISFzaWduYXR1cmUgJiYgdGVzdFV0aWxzLnJlbW92ZUhleFByZWZpeChzaWduYXR1cmUpLnN0YXJ0c1dpdGgoJzAnLnJlcGVhdCg5MCkpO1xuICAgICAgfTtcblxuICAgICAgY29uc3QgaGFzRW1iZWRkZWRBZGRyZXNzID0gKHNpZ25hdHVyZTogc3RyaW5nKTogYm9vbGVhbiA9PiB7XG4gICAgICAgIGlmICghaXNFbXB0eVNpZ25hdHVyZShzaWduYXR1cmUpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIGNvbnN0IGNsZWFuU2lnID0gdGVzdFV0aWxzLnJlbW92ZUhleFByZWZpeChzaWduYXR1cmUpO1xuICAgICAgICBpZiAoY2xlYW5TaWcubGVuZ3RoIDwgMTMwKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIGNvbnN0IGVtYmVkZGVkUGFydCA9IGNsZWFuU2lnLnN1YnN0cmluZyg5MCwgMTMwKTtcbiAgICAgICAgLy8gQ2hlY2sgaWYgZW1iZWRkZWQgcGFydCBpcyBub3QgYWxsIHplcm9zXG4gICAgICAgIHJldHVybiBlbWJlZGRlZFBhcnQgIT09ICcwJy5yZXBlYXQoNDApO1xuICAgICAgfTtcblxuICAgICAgc2lnbmF0dXJlcy5mb3JFYWNoKChzaWc6IHN0cmluZywgc2xvdEluZGV4OiBudW1iZXIpID0+IHtcbiAgICAgICAgaWYgKGhhc0VtYmVkZGVkQWRkcmVzcyhzaWcpKSB7XG4gICAgICAgICAgLy8gRXh0cmFjdCBlbWJlZGRlZCBhZGRyZXNzIChhZnRlciBwb3NpdGlvbiA5MCwgNDAgY2hhcnMgPSAyMCBieXRlcylcbiAgICAgICAgICBjb25zdCBjbGVhblNpZyA9IHRlc3RVdGlscy5yZW1vdmVIZXhQcmVmaXgoc2lnKTtcbiAgICAgICAgICBjb25zdCBlbWJlZGRlZEFkZHIgPSBjbGVhblNpZy5zdWJzdHJpbmcoOTAsIDEzMCkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICBlbWJlZGRlZEFkZHJlc3Nlc1tzbG90SW5kZXhdID0gJzB4JyArIGVtYmVkZGVkQWRkcjtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIC8vIFZlcmlmeTogQ3JlZGVudGlhbHMgb25seSBlbWJlZCBPTkUgYWRkcmVzcyAodXNlci9yZWNvdmVyeSksIG5vdCBib3RoXG4gICAgICAvLyBUaGUgZW1iZWRkZWQgYWRkcmVzcyBzaG91bGQgYmUgYmFzZWQgb24gYWRkcmVzc2VzSW5kZXggbG9naWMsIG5vdCBzZXF1ZW50aWFsIG9yZGVyXG4gICAgICAvL1xuICAgICAgLy8gQ29tcHV0ZSBhZGRyZXNzZXNJbmRleCB0byBkZXRlcm1pbmUgZXhwZWN0ZWQgc2lnbmF0dXJlIG9yZGVyXG4gICAgICBjb25zdCB1dHhvQWRkcmVzc0J5dGVzID0gdW5zb3J0ZWRVdHhvQWRkcmVzc2VzLm1hcCgoYWRkcikgPT4gdGVzdFV0aWxzLnBhcnNlQWRkcmVzcyhhZGRyKSk7XG4gICAgICBjb25zdCBwQWRkcmVzc0J5dGVzID0gcEFkZHJlc3Nlcy5tYXAoKGFkZHIpID0+IHRlc3RVdGlscy5wYXJzZUFkZHJlc3MoYWRkcikpO1xuXG4gICAgICBjb25zdCBhZGRyZXNzZXNJbmRleDogbnVtYmVyW10gPSBbXTtcbiAgICAgIHBBZGRyZXNzQnl0ZXMuZm9yRWFjaCgocEFkZHIpID0+IHtcbiAgICAgICAgY29uc3QgdXR4b0luZGV4ID0gdXR4b0FkZHJlc3NCeXRlcy5maW5kSW5kZXgoXG4gICAgICAgICAgKHVBZGRyKSA9PiBCdWZmZXIuY29tcGFyZShCdWZmZXIuZnJvbSh1QWRkciksIEJ1ZmZlci5mcm9tKHBBZGRyKSkgPT09IDBcbiAgICAgICAgKTtcbiAgICAgICAgYWRkcmVzc2VzSW5kZXgucHVzaCh1dHhvSW5kZXgpO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIGZpcnN0SW5kZXggPSAwICh1c2VyKSwgYml0Z29JbmRleCA9IDFcbiAgICAgIGNvbnN0IGZpcnN0SW5kZXggPSAwO1xuICAgICAgY29uc3QgYml0Z29JbmRleCA9IDE7XG5cbiAgICAgIC8vIERldGVybWluZSBleHBlY3RlZCBzaWduYXR1cmUgb3JkZXIgYmFzZWQgb24gYWRkcmVzc2VzSW5kZXhcbiAgICAgIGNvbnN0IHVzZXJDb21lc0ZpcnN0ID0gYWRkcmVzc2VzSW5kZXhbYml0Z29JbmRleF0gPiBhZGRyZXNzZXNJbmRleFtmaXJzdEluZGV4XTtcblxuICAgICAgLy8gRXhwZWN0ZWQgY3JlZGVudGlhbCBzdHJ1Y3R1cmU6XG4gICAgICAvLyAtIElmIHVzZXIgY29tZXMgZmlyc3Q6IFt1c2VyQWRkcmVzcywgemVyb3NdXG4gICAgICAvLyAtIElmIGJpdGdvIGNvbWVzIGZpcnN0OiBbemVyb3MsIHVzZXJBZGRyZXNzXVxuICAgICAgY29uc3QgdXNlckFkZHJlc3NIZXggPSBCdWZmZXIuZnJvbShwQWRkcmVzc0J5dGVzW2ZpcnN0SW5kZXhdKS50b1N0cmluZygnaGV4JykudG9Mb3dlckNhc2UoKTtcbiAgICAgIGNvbnN0IGV4cGVjdGVkVXNlckFkZHIgPSAnMHgnICsgdXNlckFkZHJlc3NIZXg7XG5cbiAgICAgIGlmICh1c2VyQ29tZXNGaXJzdCkge1xuICAgICAgICAvLyBFeHBlY3RlZDogW3VzZXJBZGRyZXNzLCB6ZXJvc11cbiAgICAgICAgLy8gU2xvdCAwIHNob3VsZCBoYXZlIHVzZXIgYWRkcmVzcyAocEFkZHIwID0gMHhjNzMyLi4uID0gVVRYTyBpbmRleCAwKVxuICAgICAgICBpZiAoZW1iZWRkZWRBZGRyZXNzZXNbMF0pIHtcbiAgICAgICAgICBlbWJlZGRlZEFkZHJlc3Nlc1swXVxuICAgICAgICAgICAgLnRvTG93ZXJDYXNlKClcbiAgICAgICAgICAgIC5zaG91bGQuZXF1YWwoXG4gICAgICAgICAgICAgIGV4cGVjdGVkVXNlckFkZHIsXG4gICAgICAgICAgICAgIGBTbG90IDAgc2hvdWxkIGhhdmUgdXNlciBhZGRyZXNzICgke2V4cGVjdGVkVXNlckFkZHJ9KSBiZWNhdXNlIHVzZXIgY29tZXMgZmlyc3QgaW4gVVRYTyBvcmRlcmBcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTbG90IDAgc2hvdWxkIGhhdmUgZW1iZWRkZWQgdXNlciBhZGRyZXNzLCBidXQgaXMgZW1wdHlgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBTbG90IDEgc2hvdWxkIGJlIHplcm9zIChubyBlbWJlZGRlZCBhZGRyZXNzKVxuICAgICAgICBpZiAoZW1iZWRkZWRBZGRyZXNzZXNbMV0pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFNsb3QgMSBzaG91bGQgYmUgemVyb3MsIGJ1dCBoYXMgZW1iZWRkZWQgYWRkcmVzczogJHtlbWJlZGRlZEFkZHJlc3Nlc1sxXX1gKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gRXhwZWN0ZWQ6IFt6ZXJvcywgdXNlckFkZHJlc3NdXG4gICAgICAgIC8vIFNsb3QgMCBzaG91bGQgYmUgemVyb3NcbiAgICAgICAgaWYgKGVtYmVkZGVkQWRkcmVzc2VzWzBdKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTbG90IDAgc2hvdWxkIGJlIHplcm9zLCBidXQgaGFzIGVtYmVkZGVkIGFkZHJlc3M6ICR7ZW1iZWRkZWRBZGRyZXNzZXNbMF19YCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gU2xvdCAxIHNob3VsZCBoYXZlIHVzZXIgYWRkcmVzc1xuICAgICAgICBpZiAoZW1iZWRkZWRBZGRyZXNzZXNbMV0pIHtcbiAgICAgICAgICBlbWJlZGRlZEFkZHJlc3Nlc1sxXVxuICAgICAgICAgICAgLnRvTG93ZXJDYXNlKClcbiAgICAgICAgICAgIC5zaG91bGQuZXF1YWwoXG4gICAgICAgICAgICAgIGV4cGVjdGVkVXNlckFkZHIsXG4gICAgICAgICAgICAgIGBTbG90IDEgc2hvdWxkIGhhdmUgdXNlciBhZGRyZXNzICgke2V4cGVjdGVkVXNlckFkZHJ9KSBiZWNhdXNlIGJpdGdvIGNvbWVzIGZpcnN0IGluIFVUWE8gb3JkZXJgXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU2xvdCAxIHNob3VsZCBoYXZlIGVtYmVkZGVkIHVzZXIgYWRkcmVzcywgYnV0IGlzIGVtcHR5YCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gVGhlIGtleSB2ZXJpZmljYXRpb246IEFkZHJlc3NNYXBzIHNob3VsZCBtYXRjaCB0aGUgY3JlZGVudGlhbCBvcmRlclxuICAgICAgLy8gQ3VycmVudCBpbXBsZW1lbnRhdGlvbiAoV1JPTkcpOiBBZGRyZXNzTWFwcyB1c2Ugc2VxdWVudGlhbCBpbmRpY2VzICgwLCAxLCAyLi4uKVxuICAgICAgLy8gRXhwZWN0ZWQgKENPUlJFQ1QpOiBBZGRyZXNzTWFwcyBzaG91bGQgdXNlIGFkZHJlc3Nlc0luZGV4IGxvZ2ljLCBtYXRjaGluZyBjcmVkZW50aWFsIG9yZGVyXG4gICAgICAvL1xuICAgICAgLy8gR2V0IEFkZHJlc3NNYXBzIGZyb20gdGhlIE9SSUdJTkFMIHRyYW5zYWN0aW9uIChub3QgcGFyc2VkLCBiZWNhdXNlIHBhcnNlZCBBZGRyZXNzTWFwIG9ubHkgaGFzIG91dHB1dCBhZGRyZXNzKVxuICAgICAgLy8gRm9yIEMtY2hhaW4gaW1wb3J0cywgb3JpZ2luYWxGbGFyZVR4IGlzIEVWTVVuc2lnbmVkVHggd2hpY2ggaGFzIGFkZHJlc3NNYXBzIHByb3BlcnR5XG5cbiAgICAgIGNvbnN0IGFkZHJlc3NNYXBzID0gb3JpZ2luYWxBZGRyZXNzTWFwcztcbiAgICAgIGFkZHJlc3NNYXBzLnRvQXJyYXkoKS5sZW5ndGguc2hvdWxkLmVxdWFsKDEsICdTaG91bGQgaGF2ZSBvbmUgQWRkcmVzc01hcCBmb3Igb25lIGlucHV0Jyk7XG5cbiAgICAgIGNvbnN0IGFkZHJlc3NNYXAgPSBhZGRyZXNzTWFwcy50b0FycmF5KClbMF07XG5cbiAgICAgIC8vIEV4cGVjdGVkOiBCYXNlZCBvbiBhZGRyZXNzZXNJbmRleCBsb2dpY1xuICAgICAgLy8gSWYgdXNlciBjb21lcyBmaXJzdDogc2xvdCAwID0gdXNlciwgc2xvdCAxID0gYml0Z29cbiAgICAgIC8vIElmIGJpdGdvIGNvbWVzIGZpcnN0OiBzbG90IDAgPSBiaXRnbywgc2xvdCAxID0gdXNlclxuICAgICAgY29uc3QgZXhwZWN0ZWRTbG90MEFkZHIgPSB1c2VyQ29tZXNGaXJzdCA/IHBBZGRyZXNzQnl0ZXNbZmlyc3RJbmRleF0gOiBwQWRkcmVzc0J5dGVzW2JpdGdvSW5kZXhdO1xuICAgICAgY29uc3QgZXhwZWN0ZWRTbG90MUFkZHIgPSB1c2VyQ29tZXNGaXJzdCA/IHBBZGRyZXNzQnl0ZXNbYml0Z29JbmRleF0gOiBwQWRkcmVzc0J5dGVzW2ZpcnN0SW5kZXhdO1xuXG4gICAgICAvLyBBZGRyZXNzTWFwIG1hcHM6IEFkZHJlc3MgLT4gc2xvdCBpbmRleFxuICAgICAgLy8gV2UgbmVlZCB0byBjaGVjayB3aGljaCBhZGRyZXNzZXMgYXJlIG1hcHBlZCB0byBzbG90cyAwIGFuZCAxXG4gICAgICAvLyBBZGRyZXNzTWFwLmdldCgpIHJldHVybnMgdGhlIHNsb3QgaW5kZXggZm9yIGEgZ2l2ZW4gYWRkcmVzc1xuXG4gICAgICAvLyBWZXJpZnkgdGhhdCBBZGRyZXNzTWFwIGNvcnJlY3RseSBtYXBzIGFkZHJlc3NlcyBiYXNlZCBvbiBjcmVkZW50aWFsIG9yZGVyIChVVFhPIG9yZGVyKVxuICAgICAgLy8gVGhlIEFkZHJlc3NNYXAgc2hvdWxkIG1hcCB0aGUgYWRkcmVzc2VzIHRoYXQgYXBwZWFyIGluIGNyZWRlbnRpYWxzIHRvIHRoZSBjb3JyZWN0IHNsb3RzXG4gICAgICBjb25zdCB7IEFkZHJlc3MgfSA9IHJlcXVpcmUoJ0BmbGFyZW5ldHdvcmsvZmxhcmVqcycpO1xuICAgICAgY29uc3QgZXhwZWN0ZWRTbG90MEFkZHJlc3MgPSBuZXcgQWRkcmVzcyhleHBlY3RlZFNsb3QwQWRkcik7XG4gICAgICBjb25zdCBleHBlY3RlZFNsb3QxQWRkcmVzcyA9IG5ldyBBZGRyZXNzKGV4cGVjdGVkU2xvdDFBZGRyKTtcbiAgICAgIGNvbnN0IGV4cGVjdGVkU2xvdDBGcm9tTWFwID0gYWRkcmVzc01hcC5nZXQoZXhwZWN0ZWRTbG90MEFkZHJlc3MpO1xuICAgICAgY29uc3QgZXhwZWN0ZWRTbG90MUZyb21NYXAgPSBhZGRyZXNzTWFwLmdldChleHBlY3RlZFNsb3QxQWRkcmVzcyk7XG5cbiAgICAgIC8vIFZlcmlmeSB0aGF0IHRoZSBleHBlY3RlZCBhZGRyZXNzZXMgbWFwIHRvIHRoZSBjb3JyZWN0IHNsb3RzXG4gICAgICBpZiAoZXhwZWN0ZWRTbG90MEZyb21NYXAgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEFkZHJlc3MgYXQgVVRYTyBpbmRleCAke2FkZHJlc3Nlc0luZGV4W2ZpcnN0SW5kZXhdfSBub3QgZm91bmQgaW4gQWRkcmVzc01hcGApO1xuICAgICAgfVxuICAgICAgaWYgKGV4cGVjdGVkU2xvdDFGcm9tTWFwID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBBZGRyZXNzIGF0IFVUWE8gaW5kZXggJHthZGRyZXNzZXNJbmRleFtiaXRnb0luZGV4XX0gbm90IGZvdW5kIGluIEFkZHJlc3NNYXBgKTtcbiAgICAgIH1cbiAgICAgIGV4cGVjdGVkU2xvdDBGcm9tTWFwLnNob3VsZC5lcXVhbCgwLCBgQWRkcmVzcyBhdCBVVFhPIGluZGV4ICR7YWRkcmVzc2VzSW5kZXhbZmlyc3RJbmRleF19IHNob3VsZCBtYXAgdG8gc2xvdCAwYCk7XG4gICAgICBleHBlY3RlZFNsb3QxRnJvbU1hcC5zaG91bGQuZXF1YWwoMSwgYEFkZHJlc3MgYXQgVVRYTyBpbmRleCAke2FkZHJlc3Nlc0luZGV4W2JpdGdvSW5kZXhdfSBzaG91bGQgbWFwIHRvIHNsb3QgMWApO1xuXG4gICAgICAvLyBJZiBhZGRyZXNzZXNJbmRleCBpcyBub3Qgc2VxdWVudGlhbCAoWzAsIDEsIC4uLl0pLCB2ZXJpZnkgdGhhdCBzZXF1ZW50aWFsIG1hcHBpbmcgaXMgTk9UIHVzZWQgaW5jb3JyZWN0bHlcbiAgICAgIC8vIFNlcXVlbnRpYWwgbWFwcGluZyBtZWFuczogcEFkZHJlc3Nlc1swXSAtPiBzbG90IDAsIHBBZGRyZXNzZXNbMV0gLT4gc2xvdCAxLCByZWdhcmRsZXNzIG9mIFVUWE8gb3JkZXJcbiAgICAgIGNvbnN0IHVzZXNTZXF1ZW50aWFsTWFwcGluZyA9IGFkZHJlc3Nlc0luZGV4WzBdID09PSAwICYmIGFkZHJlc3Nlc0luZGV4WzFdID09PSAxO1xuXG4gICAgICBpZiAoIXVzZXNTZXF1ZW50aWFsTWFwcGluZykge1xuICAgICAgICAvLyBDaGVjayBpZiBBZGRyZXNzTWFwIHVzZXMgc2VxdWVudGlhbCBtYXBwaW5nIChhcnJheSBvcmRlcikgaW5zdGVhZCBvZiBVVFhPIG9yZGVyXG4gICAgICAgIGNvbnN0IHNlcXVlbnRpYWxTbG90MCA9IGFkZHJlc3NNYXAuZ2V0KG5ldyBBZGRyZXNzKHBBZGRyZXNzQnl0ZXNbMF0pKTtcbiAgICAgICAgY29uc3Qgc2VxdWVudGlhbFNsb3QxID0gYWRkcmVzc01hcC5nZXQobmV3IEFkZHJlc3MocEFkZHJlc3NCeXRlc1sxXSkpO1xuXG4gICAgICAgIC8vIFNlcXVlbnRpYWwgbWFwcGluZyB3b3VsZCBtYXAgcEFkZHJlc3Nlc1swXSAtPiBzbG90IDAsIHBBZGRyZXNzZXNbMV0gLT4gc2xvdCAxXG4gICAgICAgIC8vIEJ1dCB3ZSB3YW50IFVUWE8gb3JkZXIgbWFwcGluZyBiYXNlZCBvbiBhZGRyZXNzZXNJbmRleFxuICAgICAgICBjb25zdCBpc1NlcXVlbnRpYWwgPSBzZXF1ZW50aWFsU2xvdDAgPT09IDAgJiYgc2VxdWVudGlhbFNsb3QxID09PSAxO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIHBBZGRyZXNzZXNbMF0gYW5kIHBBZGRyZXNzZXNbMV0gYXJlIHRoZSBleHBlY3RlZCBhZGRyZXNzZXMgZm9yIHNsb3RzIDAgYW5kIDFcbiAgICAgICAgLy8gSWYgdGhleSBhcmUsIHRoZW4gc2VxdWVudGlhbCBtYXBwaW5nIGhhcHBlbnMgdG8gYmUgY29ycmVjdCAoYnkgY29pbmNpZGVuY2UpXG4gICAgICAgIGNvbnN0IHBBZGRyZXNzMElzRXhwZWN0ZWRTbG90MCA9XG4gICAgICAgICAgQnVmZmVyLmNvbXBhcmUoQnVmZmVyLmZyb20ocEFkZHJlc3NCeXRlc1swXSksIEJ1ZmZlci5mcm9tKGV4cGVjdGVkU2xvdDBBZGRyKSkgPT09IDA7XG4gICAgICAgIGNvbnN0IHBBZGRyZXNzMUlzRXhwZWN0ZWRTbG90MSA9XG4gICAgICAgICAgQnVmZmVyLmNvbXBhcmUoQnVmZmVyLmZyb20ocEFkZHJlc3NCeXRlc1sxXSksIEJ1ZmZlci5mcm9tKGV4cGVjdGVkU2xvdDFBZGRyKSkgPT09IDA7XG5cbiAgICAgICAgLy8gSWYgc2VxdWVudGlhbCBtYXBwaW5nIGlzIHVzZWQgYnV0IGl0J3MgTk9UIGNvcnJlY3QgKGRvZXNuJ3QgbWF0Y2ggZXhwZWN0ZWQgYWRkcmVzc2VzKSwgZmFpbFxuICAgICAgICBpZiAoaXNTZXF1ZW50aWFsICYmICghcEFkZHJlc3MwSXNFeHBlY3RlZFNsb3QwIHx8ICFwQWRkcmVzczFJc0V4cGVjdGVkU2xvdDEpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEFkZHJlc3NNYXAgdXNlcyBzZXF1ZW50aWFsIG1hcHBpbmcgKGFycmF5IG9yZGVyKSBidXQgc2hvdWxkIHVzZSBVVFhPIG9yZGVyLiBgICtcbiAgICAgICAgICAgICAgYGFkZHJlc3Nlc0luZGV4OiBbJHthZGRyZXNzZXNJbmRleC5qb2luKCcsICcpfV0uIGAgK1xuICAgICAgICAgICAgICBgRXhwZWN0ZWQgc2xvdCAwID0gYWRkcmVzcyBhdCBVVFhPIGluZGV4ICR7YWRkcmVzc2VzSW5kZXhbZmlyc3RJbmRleF19LCBzbG90IDEgPSBhZGRyZXNzIGF0IFVUWE8gaW5kZXggJHthZGRyZXNzZXNJbmRleFtiaXRnb0luZGV4XX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19
507
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1wb3J0SW5DVHhCdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdGVzdC91bml0L2xpYi9pbXBvcnRJbkNUeEJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsa0JBQWdCO0FBQ2hCLDBDQUE2RDtBQUM3RCxpREFBNEM7QUFDNUMseUVBQW9GO0FBQ3BGLDBFQUE4QztBQUU5QyxRQUFRLENBQUMsNkJBQTZCLEVBQUUsR0FBRyxFQUFFO0lBQzNDLE1BQU0sT0FBTyxHQUFHLElBQUksK0JBQXlCLENBQUMsZUFBSyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBRWxFLFFBQVEsQ0FBQywyQkFBMkIsRUFBRSxHQUFHLEVBQUU7UUFDekMsRUFBRSxDQUFDLHdDQUF3QyxFQUFFLEdBQUcsRUFBRTtZQUNoRCxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUNoRCxnQkFBTSxDQUFDLE1BQU0sQ0FDWCxHQUFHLEVBQUU7Z0JBQ0gsU0FBUyxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUM5QixDQUFDLEVBQ0QsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLEtBQUssNkJBQTZCLENBQ3hELENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyx1Q0FBdUMsRUFBRSxLQUFLLElBQUksRUFBRTtZQUNyRCxNQUFNLFNBQVMsR0FBRyxPQUFPO2lCQUN0QixtQkFBbUIsRUFBRTtpQkFDckIsU0FBUyxDQUFDLHVCQUFRLENBQUMsU0FBUyxDQUFDO2lCQUM3QixVQUFVLENBQUMsdUJBQVEsQ0FBQyxVQUFVLENBQUM7aUJBQy9CLFlBQVksQ0FBQyx1QkFBUSxDQUFDLEtBQUssQ0FBQztpQkFDNUIsR0FBRyxDQUFDLHVCQUFRLENBQUMsR0FBRyxDQUFDO2lCQUNqQixPQUFPLENBQUMs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O1xuaW1wb3J0IHsgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeSB9IGZyb20gJy4uLy4uLy4uL3NyYy9saWInO1xuaW1wb3J0IHsgY29pbnMgfSBmcm9tICdAYml0Z28tYmV0YS9zdGF0aWNzJztcbmltcG9ydCB7IElNUE9SVF9JTl9DIGFzIHRlc3REYXRhIH0gZnJvbSAnLi4vLi4vcmVzb3VyY2VzL3RyYW5zYWN0aW9uRGF0YS9pbXBvcnRJbkMnO1xuaW1wb3J0IHNpZ25GbG93VGVzdCBmcm9tICcuL3NpZ25GbG93VGVzdFN1aXQnO1xuXG5kZXNjcmliZSgnRmxycCBJbXBvcnQgSW4gQyBUeCBCdWlsZGVyJywgKCkgPT4ge1xuICBjb25zdCBmYWN0b3J5ID0gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KCd0ZmxycCcpKTtcblxuICBkZXNjcmliZSgndmFsaWRhdGUgdHhCdWlsZGVyIGZpZWxkcycsICgpID0+IHtcbiAgICBpdCgnc2hvdWxkIGZhaWwgdmFsaWRhdGUgVXR4b3MgZW1wdHkgYXJyYXknLCAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldEltcG9ydEluQ0J1aWxkZXIoKTtcbiAgICAgIGFzc2VydC50aHJvd3MoXG4gICAgICAgICgpID0+IHtcbiAgICAgICAgICB0eEJ1aWxkZXIudmFsaWRhdGVVdHhvcyhbXSk7XG4gICAgICAgIH0sXG4gICAgICAgIChlOiBhbnkpID0+IGUubWVzc2FnZSA9PT0gJ1VUWE9zIGFycmF5IGNhbm5vdCBiZSBlbXB0eSdcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIHRvIGFkZHJlc3MgaXMgbm90IHNldCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnlcbiAgICAgICAgLmdldEltcG9ydEluQ0J1aWxkZXIoKVxuICAgICAgICAudGhyZXNob2xkKHRlc3REYXRhLnRocmVzaG9sZClcbiAgICAgICAgLmZyb21QdWJLZXkodGVzdERhdGEucEFkZHJlc3NlcylcbiAgICAgICAgLmRlY29kZWRVdHhvcyh0ZXN0RGF0YS51dHhvcylcbiAgICAgICAgLmZlZSh0ZXN0RGF0YS5mZWUpXG4gICAgICAgIC5jb250ZXh0KHRlc3REYXRhLmNvbnRleHQpO1xuICAgICAgLy8gdG8gaXMgTk9UIHNldFxuXG4gICAgICBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCd0byBpcyByZXF1aXJlZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiBjb250ZXh0IGlzIG5vdCBzZXQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5XG4gICAgICAgIC5nZXRJbXBvcnRJbkNCdWlsZGVyKClcbiAgICAgICAgLnRocmVzaG9sZCh0ZXN0RGF0YS50aHJlc2hvbGQpXG4gICAgICAgIC5mcm9tUHViS2V5KHRlc3REYXRhLnBBZGRyZXNzZXMpXG4gICAgICAgIC5kZWNvZGVkVXR4b3ModGVzdERhdGEudXR4b3MpXG4gICAgICAgIC50byh0ZXN0RGF0YS50bylcbiAgICAgICAgLmZlZSh0ZXN0RGF0YS5mZWUpO1xuICAgICAgLy8gY29udGV4dCBpcyBOT1Qgc2V0XG5cbiAgICAgIGF3YWl0IHR4QnVpbGRlci5idWlsZCgpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ2NvbnRleHQgaXMgcmVxdWlyZWQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgaWYgZnJvbUFkZHJlc3NlcyBpcyBub3Qgc2V0JywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeVxuICAgICAgICAuZ2V0SW1wb3J0SW5DQnVpbGRlcigpXG4gICAgICAgIC50aHJlc2hvbGQodGVzdERhdGEudGhyZXNob2xkKVxuICAgICAgICAuZGVjb2RlZFV0eG9zKHRlc3REYXRhLnV0eG9zKVxuICAgICAgICAudG8odGVzdERhdGEudG8pXG4gICAgICAgIC5mZWUodGVzdERhdGEuZmVlKVxuICAgICAgICAuY29udGV4dCh0ZXN0RGF0YS5jb250ZXh0KTtcbiAgICAgIC8vIGZyb21QdWJLZXkgaXMgTk9UIHNldFxuXG4gICAgICBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdmcm9tQWRkcmVzc2VzIGFyZSByZXF1aXJlZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiBVVFhPcyBhcmUgbm90IHNldCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnlcbiAgICAgICAgLmdldEltcG9ydEluQ0J1aWxkZXIoKVxuICAgICAgICAudGhyZXNob2xkKHRlc3REYXRhLnRocmVzaG9sZClcbiAgICAgICAgLmZyb21QdWJLZXkodGVzdERhdGEucEFkZHJlc3NlcylcbiAgICAgICAgLnRvKHRlc3REYXRhLnRvKVxuICAgICAgICAuZmVlKHRlc3REYXRhLmZlZSlcbiAgICAgICAgLmNvbnRleHQodGVzdERhdGEuY29udGV4dCk7XG4gICAgICAvLyB1dHhvcyBpcyBOT1Qgc2V0XG5cbiAgICAgIGF3YWl0IHR4QnVpbGRlci5idWlsZCgpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ1VUWE9zIGFyZSByZXF1aXJlZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdoZW4gdXR4b3MgaGV4IGFycmF5IGlzIGVtcHR5JywgKCkgPT4ge1xuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRJbXBvcnRJbkNCdWlsZGVyKCk7XG4gICAgICBhc3NlcnQudGhyb3dzKFxuICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgdHhCdWlsZGVyLmRlY29kZWRVdHhvcyhbXSk7XG4gICAgICAgIH0sXG4gICAgICAgIChlOiBhbnkpID0+IGUubWVzc2FnZSA9PT0gJ1VUWE9zIGFycmF5IGNhbm5vdCBiZSBlbXB0eSdcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2l0aCBpbnZhbGlkIHRocmVzaG9sZCB2YWx1ZSAoMCknLCAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldEltcG9ydEluQ0J1aWxkZXIoKTtcbiAgICAgIGFzc2VydC50aHJvd3MoXG4gICAgICAgICgpID0+IHtcbiAgICAgICAgICB0eEJ1aWxkZXIudGhyZXNob2xkKDApO1xuICAgICAgICB9LFxuICAgICAgICAoZTogYW55KSA9PiBlLm1lc3NhZ2UuaW5jbHVkZXMoJ3RocmVzaG9sZCcpIHx8IGUubWVzc2FnZS5pbmNsdWRlcygnZ3JlYXRlcicpXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdpdGggaW52YWxpZCB0aHJlc2hvbGQgdmFsdWUgKG5lZ2F0aXZlKScsICgpID0+IHtcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0SW1wb3J0SW5DQnVpbGRlcigpO1xuICAgICAgYXNzZXJ0LnRocm93cyhcbiAgICAgICAgKCkgPT4ge1xuICAgICAgICAgIHR4QnVpbGRlci50aHJlc2hvbGQoLTEpO1xuICAgICAgICB9LFxuICAgICAgICAoZTogYW55KSA9PiBlLm1lc3NhZ2UuaW5jbHVkZXMoJ3RocmVzaG9sZCcpIHx8IGUubWVzc2FnZS5pbmNsdWRlcygnZ3JlYXRlcicpXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdpdGggaW52YWxpZCB0byBhZGRyZXNzIGZvcm1hdCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0SW1wb3J0SW5DQnVpbGRlcigpO1xuICAgICAgYXNzZXJ0LnRocm93cyhcbiAgICAgICAgKCkgPT4ge1xuICAgICAgICAgIHR4QnVpbGRlci50bygnaW52YWxpZC1hZGRyZXNzJyk7XG4gICAgICAgIH0sXG4gICAgICAgIChlOiBhbnkpID0+IGUubWVzc2FnZS5pbmNsdWRlcygnSW52YWxpZCcpIHx8IGUubWVzc2FnZS5pbmNsdWRlcygnYWRkcmVzcycpXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhY2NlcHQgdmFsaWQgdG8gYWRkcmVzcycsICgpID0+IHtcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0SW1wb3J0SW5DQnVpbGRlcigpO1xuICAgICAgKCgpID0+IHR4QnVpbGRlci50byh0ZXN0RGF0YS50bykpLnNob3VsZC5ub3QudGhyb3coKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWNjZXB0IHZhbGlkIHRocmVzaG9sZCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0SW1wb3J0SW5DQnVpbGRlcigpO1xuICAgICAgKCgpID0+IHR4QnVpbGRlci50aHJlc2hvbGQoMikpLnNob3VsZC5ub3QudGhyb3coKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWNjZXB0IHZhbGlkIGNvbnRleHQnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldEltcG9ydEluQ0J1aWxkZXIoKTtcbiAgICAgICgoKSA9PiB0eEJ1aWxkZXIuY29udGV4dCh0ZXN0RGF0YS5jb250ZXh0KSkuc2hvdWxkLm5vdC50aHJvdygpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhY2NlcHQgdmFsaWQgZnJvbVB1YktleSBhZGRyZXNzZXMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldEltcG9ydEluQ0J1aWxkZXIoKTtcbiAgICAgICgoKSA9PiB0eEJ1aWxkZXIuZnJvbVB1YktleSh0ZXN0RGF0YS5wQWRkcmVzc2VzKSkuc2hvdWxkLm5vdC50aHJvdygpO1xuICAgIH0pO1xuICB9KTtcblxuICBzaWduRmxvd1Rlc3Qoe1xuICAgIHRyYW5zYWN0aW9uVHlwZTogJ0ltcG9ydCBDMlAnLFxuICAgIG5ld1R4RmFjdG9yeTogKCkgPT4gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KCd0ZmxycCcpKSxcbiAgICBuZXdUeEJ1aWxkZXI6ICgpID0+XG4gICAgICBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQoJ3RmbHJwJykpXG4gICAgICAgIC5nZXRJbXBvcnRJbkNCdWlsZGVyKClcbiAgICAgICAgLnRocmVzaG9sZCh0ZXN0RGF0YS50aHJlc2hvbGQpXG4gICAgICAgIC5mcm9tUHViS2V5KHRlc3REYXRhLnBBZGRyZXNzZXMpXG4gICAgICAgIC5kZWNvZGVkVXR4b3ModGVzdERhdGEudXR4b3MpXG4gICAgICAgIC50byh0ZXN0RGF0YS50bylcbiAgICAgICAgLmZlZSh0ZXN0RGF0YS5mZWUpXG4gICAgICAgIC5jb250ZXh0KHRlc3REYXRhLmNvbnRleHQpLFxuICAgIHVuc2lnbmVkVHhIZXg6IHRlc3REYXRhLnVuc2lnbmVkSGV4LFxuICAgIGhhbGZTaWduZWRUeEhleDogdGVzdERhdGEuaGFsZlNpZ250eEhleCxcbiAgICBmdWxsU2lnbmVkVHhIZXg6IHRlc3REYXRhLmZ1bGxTaWdudHhIZXgsXG4gICAgcHJpdmF0ZUtleToge1xuICAgICAgcHJ2MTogdGVzdERhdGEucHJpdmF0ZUtleXNbMl0sXG4gICAgICBwcnYyOiB0ZXN0RGF0YS5wcml2YXRlS2V5c1swXSxcbiAgICB9LFxuICAgIHR4SGFzaDogdGVzdERhdGEudHhoYXNoLFxuICB9KTtcbiAgLy8gICAvKipcbiAgLy8gICAgKiBUaGlzIHRlc3QgdmVyaWZpZXMgdGhlIGZpeCBmb3IgdGhlIFwiaW5zdWZmaWNpZW50IHVubG9ja2VkIGZ1bmRzXCIgZXJyb3IgdGhhdCBvY2N1cnJlZFxuICAvLyAgICAqIGR1cmluZyBQLXRvLUMgY2hhaW4gdHJhbnNhY3Rpb25zLlxuICAvLyAgICAqXG4gIC8vICAgICogUmVhbC13b3JsZCB0cmFuc2FjdGlvbiBkYXRhOlxuICAvLyAgICAqIC0gSW5wdXQ6IDEwMCwwMDAsMDAwIG5hbm9GTFJQIChmcm9tIFAtY2hhaW4gZXhwb3J0KVxuICAvLyAgICAqIC0gT3JpZ2luYWwgZmVlUmF0ZTogNTAwLCB3aGljaCBjYXVzZWQgXCJuZWVkcyAyODAwMDAgbW9yZVwiIGVycm9yXG4gIC8vICAgICogLSBPbGQgKGJ1Z2d5KSBjYWxjdWxhdGlvbjpcbiAgLy8gICAgKiAgIC0gU2l6ZTogMTIsMjM0IChvbmx5IHVuc2lnbmVkVHgudG9CeXRlcygpKVxuICAvLyAgICAqICAgLSBGZWU6IDUwMCDDlyAxMiwyMzQgPSA2LDExNywwMDBcbiAgLy8gICAgKiAtIEVycm9yOiBcImluc3VmZmljaWVudCB1bmxvY2tlZCBmdW5kczogbmVlZHMgMjgwMDAwIG1vcmVcIlxuICAvLyAgICAqIC0gUmVxdWlyZWQgZmVlOiA2LDExNywwMDAgKyAyODAsMDAwID0gNiwzOTcsMDAwXG4gIC8vICAgICpcbiAgLy8gICAgKiBUaGUgZml4IGhhcyB0d28gcGFydHM6XG4gIC8vICAgICogMS4gVXNlIGdldFNpZ25lZFR4KCkudG9CeXRlcygpIHRvIGluY2x1ZGUgY3JlZGVudGlhbHMgaW4gc2l6ZSBjYWxjdWxhdGlvbiAofjE0MCsgYnl0ZXMpXG4gIC8vICAgICogMi4gSW5jcmVhc2UgZmVlUmF0ZSBmcm9tIDUwMCB0byA1NTAgdG8gcHJvdmlkZSBhZGRpdGlvbmFsIGJ1ZmZlclxuICAvLyAgICAqXG4gIC8vICAgICogV2l0aCBmaXg6IHNpemUgfjEyLDM3NiDDlyBmZWVSYXRlIDU1MCA9IDYsODA2LDgwMCA+IDYsMzk3LDAwMCDinJNcbiAgLy8gICAgKi9cbiAgLy8gICBpdCgnc2hvdWxkIGNhbGN1bGF0ZSBzdWZmaWNpZW50IGZlZSB0byBhdm9pZCBcImluc3VmZmljaWVudCB1bmxvY2tlZCBmdW5kc1wiIGVycm9yJywgYXN5bmMgKCkgPT4ge1xuICAvLyAgICAgY29uc3QgaW5wdXRBbW91bnQgPSAnMTAwMDAwMDAwJztcbiAgLy8gICAgIGNvbnN0IGZlZVJhdGUgPSA1NTA7XG4gIC8vICAgICBjb25zdCB0aHJlc2hvbGQgPSAyO1xuXG4gIC8vICAgICBjb25zdCBwQWRkcmVzc2VzID0gW1xuICAvLyAgICAgICAnUC1jb3N0d28xMDYwbjZza3c1bHN6N2NoOHo0dm52MnMyNHZldGp2NXc3M2c0azInLFxuICAvLyAgICAgICAnUC1jb3N0d28xa3Q1aHJsNGtyNWR0OTJheXhqYXNoNnV1amtmNG5oNWV4MHk5cmonLFxuICAvLyAgICAgICAnUC1jb3N0d28xZXlzODZoeW5lY2puODQwMGozMGU3eTcwNmFlY3Y4d3owbDg3NXgnLFxuICAvLyAgICAgXTtcblxuICAvLyAgICAgY29uc3QgY0NoYWluRGVzdGluYXRpb24gPSAnMHg3ZTlmM2Q0MmNlYTdlMDJmNjJlNzE1NTkzNjJhMGFhYjMyYjkzMjhlJztcblxuICAvLyAgICAgY29uc3QgdXR4bzogRGVjb2RlZFV0eG9PYmogPSB7XG4gIC8vICAgICAgIG91dHB1dElEOiA3LFxuICAvLyAgICAgICBhbW91bnQ6IGlucHV0QW1vdW50LFxuICAvLyAgICAgICB0eGlkOiAnMmIyQTRDeWFSYXdpVkF5Y1VocGZ2YXhpenltVVQzVHdSVWJyendpeTNxcDdEbkt6bmonLFxuICAvLyAgICAgICBvdXRwdXRpZHg6ICcwJyxcbiAgLy8gICAgICAgYWRkcmVzc2VzOiBbXG4gIC8vICAgICAgICAgJzB4N2U5ZjNkNDJjZWE3ZTAyZjYyZTcxNTU5MzYyYTBhYWIzMmI5MzI4ZScsXG4gIC8vICAgICAgICAgJ0M5MjA3ZDVjOTNjZTI1MzNkNWVmOTQ1ZjlmMTNjZmQ3NzM4NjFkYzInLFxuICAvLyAgICAgICAgICdiMmU5NzFmZWI2MWQxYWIyYWJhNDM0YmIwYmViOWM5NTkzNTlkZTk5JyxcbiAgLy8gICAgICAgXSxcbiAgLy8gICAgICAgdGhyZXNob2xkOiB0aHJlc2hvbGQsXG4gIC8vICAgICB9O1xuXG4gIC8vICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5XG4gIC8vICAgICAgIC5nZXRJbXBvcnRJbkNCdWlsZGVyKClcbiAgLy8gICAgICAgLnRocmVzaG9sZCh0aHJlc2hvbGQpXG4gIC8vICAgICAgIC5mcm9tUHViS2V5KHBBZGRyZXNzZXMpXG4gIC8vICAgICAgIC51dHhvcyhbdXR4b10pXG4gIC8vICAgICAgIC50byhjQ2hhaW5EZXN0aW5hdGlvbilcbiAgLy8gICAgICAgLmZlZVJhdGUoZmVlUmF0ZS50b1N0cmluZygpKTtcblxuICAvLyAgICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgLy8gICAgIGNvbnN0IGZlZUluZm8gPSAodHggYXMgYW55KS5mZWU7XG4gIC8vICAgICBjb25zdCBjYWxjdWxhdGVkRmVlID0gQmlnSW50KGZlZUluZm8uZmVlKTtcbiAgLy8gICAgIGNvbnN0IGNhbGN1bGF0ZWRTaXplID0gZmVlSW5mby5zaXplO1xuXG4gIC8vICAgICBjb25zdCBvbGRCdWdneUZlZUF0NTAwID0gQmlnSW50KDEyMjM0KSAqIEJpZ0ludCg1MDApO1xuICAvLyAgICAgY29uc3Qgc2hvcnRmYWxsID0gQmlnSW50KDI4MDAwMCk7XG4gIC8vICAgICBjb25zdCByZXF1aXJlZEZlZSA9IG9sZEJ1Z2d5RmVlQXQ1MDAgKyBzaG9ydGZhbGw7XG5cbiAgLy8gICAgIGFzc2VydChcbiAgLy8gICAgICAgY2FsY3VsYXRlZEZlZSA+PSByZXF1aXJlZEZlZSxcbiAgLy8gICAgICAgYEZlZSAke2NhbGN1bGF0ZWRGZWV9IHNob3VsZCBiZSBhdCBsZWFzdCAke3JlcXVpcmVkRmVlfSAob2xkIGZlZSAke29sZEJ1Z2d5RmVlQXQ1MDB9ICsgc2hvcnRmYWxsICR7c2hvcnRmYWxsfSlgXG4gIC8vICAgICApO1xuXG4gIC8vICAgICBjb25zdCBvbGRCdWdneVNpemUgPSAxMjIzNDtcbiAgLy8gICAgIGFzc2VydChcbiAgLy8gICAgICAgY2FsY3VsYXRlZFNpemUgPiBvbGRCdWdneVNpemUsXG4gIC8vICAgICAgIGBTaXplICR7Y2FsY3VsYXRlZFNpemV9IHNob3VsZCBiZSBncmVhdGVyIHRoYW4gb2xkIGJ1Z2d5IHNpemUgJHtvbGRCdWdneVNpemV9YFxuICAvLyAgICAgKTtcblxuICAvLyAgICAgY29uc3Qgb3V0cHV0QW1vdW50ID0gQmlnSW50KHR4Lm91dHB1dHNbMF0udmFsdWUpO1xuICAvLyAgICAgYXNzZXJ0KG91dHB1dEFtb3VudCA+IEJpZ0ludCgwKSwgJ091dHB1dCBhbW91bnQgc2hvdWxkIGJlIHBvc2l0aXZlJyk7XG5cbiAgLy8gICAgIGNvbnN0IGlucHV0QmlnSW50ID0gQmlnSW50KGlucHV0QW1vdW50KTtcbiAgLy8gICAgIGNvbnN0IGV4cGVjdGVkT3V0cHV0ID0gaW5wdXRCaWdJbnQgLSBjYWxjdWxhdGVkRmVlO1xuICAvLyAgICAgYXNzZXJ0KFxuICAvLyAgICAgICBvdXRwdXRBbW91bnQgPT09IGV4cGVjdGVkT3V0cHV0LFxuICAvLyAgICAgICBgT3V0cHV0ICR7b3V0cHV0QW1vdW50fSBzaG91bGQgZXF1YWwgaW5wdXQgJHtpbnB1dEJpZ0ludH0gbWludXMgZmVlICR7Y2FsY3VsYXRlZEZlZX1gXG4gIC8vICAgICApO1xuICAvLyAgIH0pO1xuXG4gIC8vICAgaXQoJ3Nob3VsZCBtYXRjaCBBVkFYUCBjb3N0SW1wb3J0VHggZm9ybXVsYTogYnl0ZXNDb3N0ICsgaW5wdXRDb3N0cyArIGZpeGVkRmVlJywgYXN5bmMgKCkgPT4ge1xuICAvLyAgICAgY29uc3QgaW5wdXRBbW91bnQgPSAnMTAwMDAwMDAwJztcbiAgLy8gICAgIGNvbnN0IGZlZVJhdGUgPSA1MDA7XG4gIC8vICAgICBjb25zdCB0aHJlc2hvbGQgPSAyO1xuXG4gIC8vICAgICBjb25zdCB1dHhvOiBEZWNvZGVkVXR4b09iaiA9IHtcbiAgLy8gICAgICAgb3V0cHV0SUQ6IDcsXG4gIC8vICAgICAgIGFtb3VudDogaW5wdXRBbW91bnQsXG4gIC8vICAgICAgIHR4aWQ6ICcyYjJBNEN5YVJhd2lWQXljVWhwZnZheGl6eW1VVDNUd1JVYnJ6d2l5M3FwN0RuS3puaicsXG4gIC8vICAgICAgIG91dHB1dGlkeDogJzAnLFxuICAvLyAgICAgICBhZGRyZXNzZXM6IFtcbiAgLy8gICAgICAgICAnMHg3ZTlmM2Q0MmNlYTdlMDJmNjJlNzE1NTkzNjJhMGFhYjMyYjkzMjhlJyxcbiAgLy8gICAgICAgICAnQzkyMDdkNWM5M2NlMjUzM2Q1ZWY5NDVmOWYxM2NmZDc3Mzg2MWRjMicsXG4gIC8vICAgICAgICAgJ2IyZTk3MWZlYjYxZDFhYjJhYmE0MzRiYjBiZWI5Yzk1OTM1OWRlOTknLFxuICAvLyAgICAgICBdLFxuICAvLyAgICAgICB0aHJlc2hvbGQ6IHRocmVzaG9sZCxcbiAgLy8gICAgIH07XG5cbiAgLy8gICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnlcbiAgLy8gICAgICAgLmdldEltcG9ydEluQ0J1aWxkZXIoKVxuICAvLyAgICAgICAudGhyZXNob2xkKHRocmVzaG9sZClcbiAgLy8gICAgICAgLmZyb21QdWJLZXkodGVzdERhdGEucEFkZHJlc3NlcylcbiAgLy8gICAgICAgLnV0eG9zKFt1dHhvXSlcbiAgLy8gICAgICAgLnRvKHRlc3REYXRhLnRvKVxuICAvLyAgICAgICAuZmVlUmF0ZShmZWVSYXRlLnRvU3RyaW5nKCkpO1xuXG4gIC8vICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAvLyAgICAgY29uc3QgZmVlSW5mbyA9ICh0eCBhcyBhbnkpLmZlZTtcbiAgLy8gICAgIGNvbnN0IGNhbGN1bGF0ZWRTaXplID0gZmVlSW5mby5zaXplO1xuXG4gIC8vICAgICBjb25zdCBleHBlY3RlZElucHV0Q29zdCA9IDEwMDAgKiB0aHJlc2hvbGQ7XG4gIC8vICAgICBjb25zdCBmaXhlZEZlZSA9IDEwMDAwO1xuICAvLyAgICAgY29uc3QgZXhwZWN0ZWRNaW5CeXRlc0Nvc3QgPSAyMDA7XG5cbiAgLy8gICAgIGNvbnN0IGltcGxpZWRCeXRlc0Nvc3QgPSBjYWxjdWxhdGVkU2l6ZSAtIGV4cGVjdGVkSW5wdXRDb3N0IC0gZml4ZWRGZWU7XG5cbiAgLy8gICAgIGFzc2VydChcbiAgLy8gICAgICAgaW1wbGllZEJ5dGVzQ29zdCA+PSBleHBlY3RlZE1pbkJ5dGVzQ29zdCxcbiAgLy8gICAgICAgYEltcGxpZWQgYnl0ZXMgY29zdCAke2ltcGxpZWRCeXRlc0Nvc3R9IHNob3VsZCBiZSBhdCBsZWFzdCAke2V4cGVjdGVkTWluQnl0ZXNDb3N0fWBcbiAgLy8gICAgICk7XG5cbiAgLy8gICAgIGNvbnN0IGV4cGVjdGVkTWluVG90YWxTaXplID0gZXhwZWN0ZWRNaW5CeXRlc0Nvc3QgKyBleHBlY3RlZElucHV0Q29zdCArIGZpeGVkRmVlO1xuICAvLyAgICAgYXNzZXJ0KFxuICAvLyAgICAgICBjYWxjdWxhdGVkU2l6ZSA+PSBleHBlY3RlZE1pblRvdGFsU2l6ZSxcbiAgLy8gICAgICAgYFRvdGFsIHNpemUgJHtjYWxjdWxhdGVkU2l6ZX0gc2hvdWxkIGJlIGF0IGxlYXN0ICR7ZXhwZWN0ZWRNaW5Ub3RhbFNpemV9IChieXRlcyArIGlucHV0Q29zdCArIGZpeGVkRmVlKWBcbiAgLy8gICAgICk7XG4gIC8vICAgfSk7XG5cbiAgLy8gICBpdCgnc2hvdWxkIHByb2R1Y2UgY29uc2lzdGVudCBmZWVzIGJldHdlZW4gYnVpbGQgYW5kIHBhcnNlIChpbml0QnVpbGRlciB2cyBidWlsZEZsYXJlVHJhbnNhY3Rpb24pJywgYXN5bmMgKCkgPT4ge1xuICAvLyAgICAgY29uc3QgaW5wdXRBbW91bnQgPSAnMTAwMDAwMDAwJztcbiAgLy8gICAgIGNvbnN0IGZlZVJhdGUgPSA1MDA7XG4gIC8vICAgICBjb25zdCB0aHJlc2hvbGQgPSAyO1xuXG4gIC8vICAgICBjb25zdCB1dHhvOiBEZWNvZGVkVXR4b09iaiA9IHtcbiAgLy8gICAgICAgb3V0cHV0SUQ6IDcsXG4gIC8vICAgICAgIGFtb3VudDogaW5wdXRBbW91bnQsXG4gIC8vICAgICAgIHR4aWQ6ICcyYjJBNEN5YVJhd2lWQXljVWhwZnZheGl6eW1VVDNUd1JVYnJ6d2l5M3FwN0RuS3puaicsXG4gIC8vICAgICAgIG91dHB1dGlkeDogJzAnLFxuICAvLyAgICAgICBhZGRyZXNzZXM6IFtcbiAgLy8gICAgICAgICAnMHg3ZTlmM2Q0MmNlYTdlMDJmNjJlNzE1NTkzNjJhMGFhYjMyYjkzMjhlJyxcbiAgLy8gICAgICAgICAnQzkyMDdkNWM5M2NlMjUzM2Q1ZWY5NDVmOWYxM2NmZDc3Mzg2MWRjMicsXG4gIC8vICAgICAgICAgJ2IyZTk3MWZlYjYxZDFhYjJhYmE0MzRiYjBiZWI5Yzk1OTM1OWRlOTknLFxuICAvLyAgICAgICBdLFxuICAvLyAgICAgICB0aHJlc2hvbGQ6IHRocmVzaG9sZCxcbiAgLy8gICAgIH07XG5cbiAgLy8gICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnlcbiAgLy8gICAgICAgLmdldEltcG9ydEluQ0J1aWxkZXIoKVxuICAvLyAgICAgICAudGhyZXNob2xkKHRocmVzaG9sZClcbiAgLy8gICAgICAgLmZyb21QdWJLZXkodGVzdERhdGEucEFkZHJlc3NlcylcbiAgLy8gICAgICAgLnV0eG9zKFt1dHhvXSlcbiAgLy8gICAgICAgLnRvKHRlc3REYXRhLnRvKVxuICAvLyAgICAgICAuZmVlUmF0ZShmZWVSYXRlLnRvU3RyaW5nKCkpO1xuXG4gIC8vICAgICBjb25zdCBvcmlnaW5hbFR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gIC8vICAgICBjb25zdCBvcmlnaW5hbEZlZUluZm8gPSAob3JpZ2luYWxUeCBhcyBhbnkpLmZlZTtcbiAgLy8gICAgIGNvbnN0IG9yaWdpbmFsU2l6ZSA9IG9yaWdpbmFsRmVlSW5mby5zaXplO1xuXG4gIC8vICAgICBjb25zdCB0eEhleCA9IG9yaWdpbmFsVHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgLy8gICAgIGNvbnN0IHBhcnNlZEJ1aWxkZXIgPSBmYWN0b3J5LmZyb20odHhIZXgpO1xuICAvLyAgICAgY29uc3QgcGFyc2VkVHggPSBhd2FpdCBwYXJzZWRCdWlsZGVyLmJ1aWxkKCk7XG4gIC8vICAgICBjb25zdCBwYXJzZWRGZWVJbmZvID0gKHBhcnNlZFR4IGFzIGFueSkuZmVlO1xuICAvLyAgICAgY29uc3QgcGFyc2VkRmVlUmF0ZSA9IHBhcnNlZEZlZUluZm8uZmVlUmF0ZTtcbiAgLy8gICAgIGNvbnN0IHBhcnNlZFNpemUgPSBwYXJzZWRGZWVJbmZvLnNpemU7XG5cbiAgLy8gICAgIGNvbnN0IGZlZVJhdGVEaWZmID0gTWF0aC5hYnMocGFyc2VkRmVlUmF0ZSAtIGZlZVJhdGUpO1xuICAvLyAgICAgY29uc3QgbWF4QWxsb3dlZERpZmYgPSA1MDtcbiAgLy8gICAgIGFzc2VydChcbiAgLy8gICAgICAgZmVlUmF0ZURpZmYgPD0gbWF4QWxsb3dlZERpZmYsXG4gIC8vICAgICAgIGBQYXJzZWQgZmVlUmF0ZSAke3BhcnNlZEZlZVJhdGV9IHNob3VsZCBiZSBjbG9zZSB0byBvcmlnaW5hbCAke2ZlZVJhdGV9IChkaWZmOiAke2ZlZVJhdGVEaWZmfSlgXG4gIC8vICAgICApO1xuXG4gIC8vICAgICBjb25zdCBzaXplRGlmZiA9IE1hdGguYWJzKHBhcnNlZFNpemUgLSBvcmlnaW5hbFNpemUpO1xuICAvLyAgICAgY29uc3QgbWF4U2l6ZURpZmYgPSAxMDA7XG4gIC8vICAgICBhc3NlcnQoXG4gIC8vICAgICAgIHNpemVEaWZmIDw9IG1heFNpemVEaWZmLFxuICAvLyAgICAgICBgUGFyc2VkIHNpemUgJHtwYXJzZWRTaXplfSBzaG91bGQgYmUgY2xvc2UgdG8gb3JpZ2luYWwgJHtvcmlnaW5hbFNpemV9IChkaWZmOiAke3NpemVEaWZmfSlgXG4gIC8vICAgICApO1xuICAvLyAgIH0pO1xuICAvLyB9KTtcblxuICAvLyBkZXNjcmliZSgnb24tY2hhaW4gdmVyaWZpZWQgdHJhbnNhY3Rpb25zJywgKCkgPT4ge1xuICAvLyAgIGl0KCdzaG91bGQgdmVyaWZ5IG9uLWNoYWluIHR4IGlkIGZvciBzaWduZWQgQy1jaGFpbiBpbXBvcnQnLCBhc3luYyAoKSA9PiB7XG4gIC8vICAgICBjb25zdCBzaWduZWRJbXBvcnRIZXggPVxuICAvLyAgICAgICAnMHgwMDAwMDAwMDAwMDAwMDAwMDA3Mjc4ZGI1YzMwYmVkMDRjMDVjZTIwOTE3OTgxMjg1MGJiYjNmZTZkNDZkN2VlZjM3NDRkODE0YzBkYTU1NTI0NzkwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDE2MmVmMGM4Y2VkNTY2OGQxMjMwYzgyZTI3NGY1YzE5MzU3ZGY4YzAwNTc0MzM2NzQyMWU4YTJiNDhjNzM5ODlhMDAwMDAwMDE1ODczNGY5NGFmODcxYzNkMTMxYjU2MTMxYjZmYjdhMDI5MWVhY2FkZDI2MWU2OWRmYjQyYTljZGY2ZjdmZGRkMDAwMDAwMDUwMDAwMDAwMDAyZmFmMDgwMDAwMDAwMDIwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDExN2RiZDExYjlkZDFjOWJlMzM3MzUzZGI3YzE0ZjlmYjM2NjJlNWI1MDAwMDAwMDAwMmFlYTU0MDU4NzM0Zjk0YWY4NzFjM2QxMzFiNTYxMzFiNmZiN2EwMjkxZWFjYWRkMjYxZTY5ZGZiNDJhOWNkZjZmN2ZkZGQwMDAwMDAwMTAwMDAwMDA5MDAwMDAwMDJhYjMyYzE1Yzc1Yzc2M2IyNGFkZjI2ZWVlODVhYTdkNmE3NmIzNjZlNmI4OGUzNGI5NGY3NmJhZWM5MWJhZTczMzZhMzJlZDYzN2ZjMjMyY2NjYjJmNzcyZDMwOTJlZWU2NjU5NDA3MGEyYmU5Mjc1MTE0OGZlZmZjNzYwMDViMTAxM2VlNzhmYjExZjNmOWZmZDkwZDk3MGNkNWM5NWU5ZGVlNjExYmI0ZmVhZmFhMGIwMjIwY2M2NDFlZjA1NGM5ZjU3MDFmZGU0ZmFkMmZlN2YyNTk0ZGI5ZGFmZDg1OGM2MmY5Y2Y2ZmU2YjU4MzM0ZDczZGE0MGE1YTg0MTJkNDYwMCc7XG4gIC8vICAgICBjb25zdCB0eEJ1aWxkZXIgPSBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQoJ3RmbHJwJykpLmZyb20oc2lnbmVkSW1wb3J0SGV4KTtcbiAgLy8gICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gIC8vICAgICBjb25zdCByYXdUeCA9IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG4gIC8vICAgICByYXdUeC5zaG91bGQuZXF1YWwoc2lnbmVkSW1wb3J0SGV4KTtcbiAgLy8gICAgIHR4LmlkLnNob3VsZC5lcXVhbCgnMmtzOXZXMVNWV0Q0S3NOUEhnWG5WNWRwSmFDY2F4Vk5iUVc0SDd0OUJNRHhBcEd2ZmEnKTtcbiAgLy8gICB9KTtcblxuICAvLyAgIGl0KCdzaG91bGQgRkFJTCB3aXRoIHVuc29ydGVkIFVUWE8gYWRkcmVzc2VzIC0gZGVtb25zdHJhdGVzIEFkZHJlc3NNYXAgbWlzbWF0Y2ggaXNzdWUgZm9yIGltcG9ydCBpbiBDLWNoYWluIHR4JywgYXN5bmMgKCkgPT4ge1xuICAvLyAgICAgLy8gVGhpcyB0ZXN0IHVzZXMgVVRYTyBhZGRyZXNzZXMgaW4gVU5TT1JURUQgb3JkZXIgdG8gZGVtb25zdHJhdGUgdGhlIGlzc3VlLlxuICAvLyAgICAgLy8gV2l0aCB1bnNvcnRlZCBhZGRyZXNzZXMsIHRoZSBjdXJyZW50IGltcGxlbWVudGF0aW9uIHdpbGwgY3JlYXRlIEFkZHJlc3NNYXBzIGluY29ycmVjdGx5XG4gIC8vICAgICAvLyBiZWNhdXNlIGl0IHVzZXMgc2VxdWVudGlhbCBpbmRpY2VzLCBub3QgVVRYTyBhZGRyZXNzIG9yZGVyLlxuICAvLyAgICAgLy9cbiAgLy8gICAgIC8vIEV4cGVjdGVkOiBBZGRyZXNzTWFwIHNob3VsZCBtYXAgYWRkcmVzc2VzIHRvIHNpZ25hdHVyZSBzbG90cyBiYXNlZCBvbiBVVFhPIG9yZGVyIChhZGRyZXNzZXNJbmRleClcbiAgLy8gICAgIC8vIEN1cnJlbnQgKFdST05HKTogQWRkcmVzc01hcCB1c2VzIHNlcXVlbnRpYWwgaW5kaWNlcyAoMCwgMSwgMi4uLilcbiAgLy8gICAgIC8vXG4gIC8vICAgICAvLyBUaGlzIHRlc3QgV0lMTCBGQUlMIHdpdGggY3VycmVudCBpbXBsZW1lbnRhdGlvbiBiZWNhdXNlIEFkZHJlc3NNYXBzIGRvbid0IG1hdGNoIGNyZWRlbnRpYWwgb3JkZXJcblxuICAvLyAgICAgLy8gVVRYTyBhZGRyZXNzZXMgaW4gVU5TT1JURUQgb3JkZXIgKGRpZmZlcmVudCBmcm9tIHNvcnRlZClcbiAgLy8gICAgIC8vIFNvcnRlZCB3b3VsZCBiZTogWzB4MzMyOS4uLiAoc21hbGxlc3QpLCAweDdlOTEuLi4gKG1pZGRsZSksIDB4YzczMi4uLiAobGFyZ2VzdCldXG4gIC8vICAgICAvLyBVbnNvcnRlZDogWzB4YzczMi4uLiAobGFyZ2VzdCksIDB4MzMyOS4uLiAoc21hbGxlc3QpLCAweDdlOTEuLi4gKG1pZGRsZSldXG4gIC8vICAgICBjb25zdCB1bnNvcnRlZFV0eG9BZGRyZXNzZXMgPSBbXG4gIC8vICAgICAgICcweGM3MzI0NDM3Yzk2YzdjOGE2YTE1MmRhMjM4NWMxZGI1YzNhYjFmOTEnLCAvLyBMYXJnZXN0ICh3b3VsZCBiZSBpbmRleCAyIGlmIHNvcnRlZClcbiAgLy8gICAgICAgJzB4MzMyOWJlN2QwMWNkM2ViYWFlNjY1NGQ3MzI3ZGQ5ZjE3YTJlMTU4MScsIC8vIFNtYWxsZXN0ICh3b3VsZCBiZSBpbmRleCAwIGlmIHNvcnRlZClcbiAgLy8gICAgICAgJzB4N2U5MThhNWU4MDgzYWU0YzlmMmYwZWQ3NzA1NWMyNGJmMzY2NTAwMScsIC8vIE1pZGRsZSAod291bGQgYmUgaW5kZXggMSBpZiBzb3J0ZWQpXG4gIC8vICAgICBdO1xuXG4gIC8vICAgICAvLyBDb3JyZXNwb25kaW5nIFAtY2hhaW4gYWRkcmVzc2VzIChpbiBzYW1lIG9yZGVyIGFzIF9mcm9tQWRkcmVzc2VzKVxuICAvLyAgICAgY29uc3QgcEFkZHJlc3NlcyA9IFtcbiAgLy8gICAgICAgJ1AtY29zdHdvMXh2NW11bGdwZTVsdDR0bngybnRueWx3ZTc5YXp1OXZwamE2bHV0JywgLy8gTWFwcyB0byAweGM3MzIuLi4gKFVUWE8gaW5kZXggMCBpbiB1bnNvcnRlZClcbiAgLy8gICAgICAgJ1AtY29zdHdvMTA2Z2M1aDVxc3doeWU4ZTBwbXRocTR3emYwZWt2NXFwcHNydnB1JywgLy8gTWFwcyB0byAweDMzMjkuLi4gKFVUWE8gaW5kZXggMSBpbiB1bnNvcnRlZClcbiAgLy8gICAgICAgJ1AtY29zdHdvMWN1ZXlnZDdmZDM3ZzU2czQ5azNyc2hxYWtocDZrOHUzYWR6dDZtJywgLy8gTWFwcyB0byAweDdlOTEuLi4gKFVUWE8gaW5kZXggMiBpbiB1bnNvcnRlZClcbiAgLy8gICAgIF07XG5cbiAgLy8gICAgIC8vIENyZWF0ZSBVVFhPIHdpdGggVU5TT1JURUQgYWRkcmVzc2VzXG4gIC8vICAgICBjb25zdCBhbW91bnQgPSAnNTAwMDAwMDAwJzsgLy8gMC41IEZMUlxuICAvLyAgICAgY29uc3QgZmVlID0gJzUwMDAwMDAnOyAvLyBFeGFtcGxlIGZlZVxuICAvLyAgICAgY29uc3QgdXR4b0Ftb3VudCA9IChCaWdJbnQoYW1vdW50KSArIEJpZ0ludChmZWUpICsgQmlnSW50KCcxMDAwMDAwMCcpKS50b1N0cmluZygpOyAvLyBhbW91bnQgKyBmZWUgKyBzb21lIGJ1ZmZlclxuXG4gIC8vICAgICBjb25zdCB1dHhvOiBEZWNvZGVkVXR4b09iaiA9IHtcbiAgLy8gICAgICAgb3V0cHV0SUQ6IDAsXG4gIC8vICAgICAgIGFtb3VudDogdXR4b0Ftb3VudCxcbiAgLy8gICAgICAgdHhpZDogJzJ2UE14OFA2M2FkZ0JhZTdHQVdGeDdxdkpEd1JtTW5EQ3lLZGRIUkJYV2h5c2pYNEJQJyxcbiAgLy8gICAgICAgb3V0cHV0aWR4OiAnMScsXG4gIC8vICAgICAgIGFkZHJlc3NlczogdW5zb3J0ZWRVdHhvQWRkcmVzc2VzLCAvLyBVTlNPUlRFRCBvcmRlclxuICAvLyAgICAgICB0aHJlc2hvbGQ6IDIsXG4gIC8vICAgICB9O1xuXG4gIC8vICAgICAvLyBCdWlsZCB0cmFuc2FjdGlvblxuICAvLyAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeVxuICAvLyAgICAgICAuZ2V0SW1wb3J0SW5DQnVpbGRlcigpXG4gIC8vICAgICAgIC50aHJlc2hvbGQoMilcbiAgLy8gICAgICAgLmZyb21QdWJLZXkocEFkZHJlc3NlcylcbiAgLy8gICAgICAgLnV0eG9zKFt1dHhvXSlcbiAgLy8gICAgICAgLnRvKHRlc3REYXRhLnRvKVxuICAvLyAgICAgICAuZmVlUmF0ZSh0ZXN0RGF0YS5mZWUpO1xuXG4gIC8vICAgICAvLyBCdWlsZCB1bnNpZ25lZCB0cmFuc2FjdGlvblxuICAvLyAgICAgY29uc3QgdW5zaWduZWRUeCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAvLyAgICAgY29uc3QgdW5zaWduZWRIZXggPSB1bnNpZ25lZFR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgLy8gICAgIC8vIEdldCBBZGRyZXNzTWFwcyBmcm9tIHRoZSBPUklHSU5BTCB0cmFuc2FjdGlvbiAoYmVmb3JlIHBhcnNpbmcpXG4gIC8vICAgICAvLyBUaGUgcGFyc2VkIHRyYW5zYWN0aW9uJ3MgQWRkcmVzc01hcCBvbmx5IGNvbnRhaW5zIHRoZSBvdXRwdXQgYWRkcmVzcywgbm90IF9mcm9tQWRkcmVzc2VzXG4gIC8vICAgICBjb25zdCBvcmlnaW5hbEZsYXJlVHggPSAodW5zaWduZWRUeCBhcyBhbnkpLl9mbGFyZVRyYW5zYWN0aW9uO1xuICAvLyAgICAgY29uc3Qgb3JpZ2luYWxBZGRyZXNzTWFwcyA9IChvcmlnaW5hbEZsYXJlVHggYXMgYW55IGFzIFVuc2lnbmVkVHgpLmFkZHJlc3NNYXBzO1xuXG4gIC8vICAgICAvLyBQYXJzZSBpdCBiYWNrIHRvIGluc3BlY3QgQWRkcmVzc01hcHMgYW5kIGNyZWRlbnRpYWxzXG4gIC8vICAgICBjb25zdCBwYXJzZWRCdWlsZGVyID0gZmFjdG9yeS5mcm9tKHVuc2lnbmVkSGV4KTtcbiAgLy8gICAgIGNvbnN0IHBhcnNlZFR4ID0gYXdhaXQgcGFyc2VkQnVpbGRlci5idWlsZCgpO1xuICAvLyAgICAgY29uc3QgZmxhcmVUeCA9IChwYXJzZWRUeCBhcyBhbnkpLl9mbGFyZVRyYW5zYWN0aW9uO1xuXG4gIC8vICAgICAvLyBHZXQgdGhlIGlucHV0IHRvIGNoZWNrIHNpZ0luZGljaWVzIChmb3IgQy1jaGFpbiBpbXBvcnRzLCBpbnB1dHMgYXJlIGltcG9ydGVkSW5wdXRzKVxuICAvLyAgICAgY29uc3QgaW1wb3J0VHggPSBmbGFyZVR4LnR4IGFzIGFueTtcbiAgLy8gICAgIGNvbnN0IGlucHV0ID0gaW1wb3J0VHguaW1wb3J0ZWRJbnB1dHNbMF07XG4gIC8vICAgICBjb25zdCBzaWdJbmRpY2llcyA9IGlucHV0LnNpZ0luZGljaWVzKCk7XG5cbiAgLy8gICAgIC8vIHNpZ0luZGljaWVzIHRlbGxzIHVzOiBzaWdJbmRpY2llc1tzbG90SW5kZXhdID0gdXR4b0FkZHJlc3NJbmRleFxuICAvLyAgICAgLy8gRm9yIHRocmVzaG9sZD0yLCB3ZSBuZWVkIHNpZ25hdHVyZXMgZm9yIGZpcnN0IDIgYWRkcmVzc2VzIGluIFVUWE8gb3JkZXJcbiAgLy8gICAgIC8vIFVUWE8gb3JkZXI6IFsweGM3MzIuLi4gKGluZGV4IDApLCAweDMzMjkuLi4gKGluZGV4IDEpLCAweDdlOTEuLi4gKGluZGV4IDIpXVxuICAvLyAgICAgLy8gU28gc2lnSW5kaWNpZXMgc2hvdWxkIGJlIFswLCAxXSBtZWFuaW5nOiBzbG90IDAgPSBVVFhPIGluZGV4IDAsIHNsb3QgMSA9IFVUWE8gaW5kZXggMVxuXG4gIC8vICAgICAvLyBWZXJpZnkgc2lnSW5kaWNpZXMgYXJlIFswLCAxXSAoZmlyc3QgMiBhZGRyZXNzZXMgaW4gVVRYTyBvcmRlciwgTk9UIHNvcnRlZCBvcmRlcilcbiAgLy8gICAgIHNpZ0luZGljaWVzLmxlbmd0aC5zaG91bGQuZXF1YWwoMik7XG4gIC8vICAgICBzaWdJbmRpY2llc1swXS5zaG91bGQuZXF1YWwoMCwgJ0ZpcnN0IHNpZ25hdHVyZSBzbG90IHNob3VsZCBiZSBVVFhPIGFkZHJlc3MgaW5kZXggMCAoMHhjNzMyLi4uKScpO1xuICAvLyAgICAgc2lnSW5kaWNpZXNbMV0uc2hvdWxkLmVxdWFsKDEsICdTZWNvbmQgc2lnbmF0dXJlIHNsb3Qgc2hvdWxkIGJlIFVUWE8gYWRkcmVzcyBpbmRleCAxICgweDMzMjkuLi4pJyk7XG5cbiAgLy8gICAgIC8vIFRoZSBjcml0aWNhbCB0ZXN0OiBWZXJpZnkgdGhhdCBzaWduYXR1cmUgc2xvdHMgaGF2ZSBlbWJlZGRlZCBhZGRyZXNzZXMgYmFzZWQgb24gVVRYTyBvcmRlclxuICAvLyAgICAgLy8gV2l0aCB1bnNvcnRlZCBVVFhPIGFkZHJlc3NlcywgdGhpcyB3aWxsIEZBSUwgaWYgQWRkcmVzc01hcHMgZG9uJ3QgbWF0Y2ggVVRYTyBvcmRlclxuICAvLyAgICAgLy9cbiAgLy8gICAgIC8vIFBhcnNlIHRoZSBjcmVkZW50aWFsIHRvIHNlZSB3aGljaCBzbG90cyBoYXZlIHdoaWNoIGVtYmVkZGVkIGFkZHJlc3Nlc1xuICAvLyAgICAgY29uc3QgY3JlZGVudGlhbCA9IGZsYXJlVHguY3JlZGVudGlhbHNbMF07XG4gIC8vICAgICBjb25zdCBzaWduYXR1cmVzID0gY3JlZGVudGlhbC5nZXRTaWduYXR1cmVzKCk7XG5cbiAgLy8gICAgIC8vIEV4dHJhY3QgZW1iZWRkZWQgYWRkcmVzc2VzIGZyb20gc2lnbmF0dXJlIHNsb3RzXG4gIC8vICAgICBjb25zdCBlbWJlZGRlZEFkZHJlc3Nlczogc3RyaW5nW10gPSBbXTtcbiAgLy8gICAgIGNvbnN0IGlzRW1wdHlTaWduYXR1cmUgPSAoc2lnbmF0dXJlOiBzdHJpbmcpOiBib29sZWFuID0+IHtcbiAgLy8gICAgICAgcmV0dXJuICEhc2lnbmF0dXJlICYmIHRlc3RVdGlscy5yZW1vdmVIZXhQcmVmaXgoc2lnbmF0dXJlKS5zdGFydHNXaXRoKCcwJy5yZXBlYXQoOTApKTtcbiAgLy8gICAgIH07XG5cbiAgLy8gICAgIGNvbnN0IGhhc0VtYmVkZGVkQWRkcmVzcyA9IChzaWduYXR1cmU6IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuICAvLyAgICAgICBpZiAoIWlzRW1wdHlTaWduYXR1cmUoc2lnbmF0dXJlKSkgcmV0dXJuIGZhbHNlO1xuICAvLyAgICAgICBjb25zdCBjbGVhblNpZyA9IHRlc3RVdGlscy5yZW1vdmVIZXhQcmVmaXgoc2lnbmF0dXJlKTtcbiAgLy8gICAgICAgaWYgKGNsZWFuU2lnLmxlbmd0aCA8IDEzMCkgcmV0dXJuIGZhbHNlO1xuICAvLyAgICAgICBjb25zdCBlbWJlZGRlZFBhcnQgPSBjbGVhblNpZy5zdWJzdHJpbmcoOTAsIDEzMCk7XG4gIC8vICAgICAgIC8vIENoZWNrIGlmIGVtYmVkZGVkIHBhcnQgaXMgbm90IGFsbCB6ZXJvc1xuICAvLyAgICAgICByZXR1cm4gZW1iZWRkZWRQYXJ0ICE9PSAnMCcucmVwZWF0KDQwKTtcbiAgLy8gICAgIH07XG5cbiAgLy8gICAgIHNpZ25hdHVyZXMuZm9yRWFjaCgoc2lnOiBzdHJpbmcsIHNsb3RJbmRleDogbnVtYmVyKSA9PiB7XG4gIC8vICAgICAgIGlmIChoYXNFbWJlZGRlZEFkZHJlc3Moc2lnKSkge1xuICAvLyAgICAgICAgIC8vIEV4dHJhY3QgZW1iZWRkZWQgYWRkcmVzcyAoYWZ0ZXIgcG9zaXRpb24gOTAsIDQwIGNoYXJzID0gMjAgYnl0ZXMpXG4gIC8vICAgICAgICAgY29uc3QgY2xlYW5TaWcgPSB0ZXN0VXRpbHMucmVtb3ZlSGV4UHJlZml4KHNpZyk7XG4gIC8vICAgICAgICAgY29uc3QgZW1iZWRkZWRBZGRyID0gY2xlYW5TaWcuc3Vic3RyaW5nKDkwLCAxMzApLnRvTG93ZXJDYXNlKCk7XG4gIC8vICAgICAgICAgZW1iZWRkZWRBZGRyZXNzZXNbc2xvdEluZGV4XSA9ICcweCcgKyBlbWJlZGRlZEFkZHI7XG4gIC8vICAgICAgIH1cbiAgLy8gICAgIH0pO1xuXG4gIC8vICAgICAvLyBWZXJpZnk6IENyZWRlbnRpYWxzIG9ubHkgZW1iZWQgT05FIGFkZHJlc3MgKHVzZXIvcmVjb3ZlcnkpLCBub3QgYm90aFxuICAvLyAgICAgLy8gVGhlIGVtYmVkZGVkIGFkZHJlc3Mgc2hvdWxkIGJlIGJhc2VkIG9uIGFkZHJlc3Nlc0luZGV4IGxvZ2ljLCBub3Qgc2VxdWVudGlhbCBvcmRlclxuICAvLyAgICAgLy9cbiAgLy8gICAgIC8vIENvbXB1dGUgYWRkcmVzc2VzSW5kZXggdG8gZGV0ZXJtaW5lIGV4cGVjdGVkIHNpZ25hdHVyZSBvcmRlclxuICAvLyAgICAgY29uc3QgdXR4b0FkZHJlc3NCeXRlcyA9IHVuc29ydGVkVXR4b0FkZHJlc3Nlcy5tYXAoKGFkZHIpID0+IHRlc3RVdGlscy5wYXJzZUFkZHJlc3MoYWRkcikpO1xuICAvLyAgICAgY29uc3QgcEFkZHJlc3NCeXRlcyA9IHBBZGRyZXNzZXMubWFwKChhZGRyKSA9PiB0ZXN0VXRpbHMucGFyc2VBZGRyZXNzKGFkZHIpKTtcblxuICAvLyAgICAgY29uc3QgYWRkcmVzc2VzSW5kZXg6IG51bWJlcltdID0gW107XG4gIC8vICAgICBwQWRkcmVzc0J5dGVzLmZvckVhY2goKHBBZGRyKSA9PiB7XG4gIC8vICAgICAgIGNvbnN0IHV0eG9JbmRleCA9IHV0eG9BZGRyZXNzQnl0ZXMuZmluZEluZGV4KFxuICAvLyAgICAgICAgICh1QWRkcikgPT4gQnVmZmVyLmNvbXBhcmUoQnVmZmVyLmZyb20odUFkZHIpLCBCdWZmZXIuZnJvbShwQWRkcikpID09PSAwXG4gIC8vICAgICAgICk7XG4gIC8vICAgICAgIGFkZHJlc3Nlc0luZGV4LnB1c2godXR4b0luZGV4KTtcbiAgLy8gICAgIH0pO1xuXG4gIC8vICAgICAvLyBmaXJzdEluZGV4ID0gMCAodXNlciksIGJpdGdvSW5kZXggPSAxXG4gIC8vICAgICBjb25zdCBmaXJzdEluZGV4ID0gMDtcbiAgLy8gICAgIGNvbnN0IGJpdGdvSW5kZXggPSAxO1xuXG4gIC8vICAgICAvLyBEZXRlcm1pbmUgZXhwZWN0ZWQgc2lnbmF0dXJlIG9yZGVyIGJhc2VkIG9uIGFkZHJlc3Nlc0luZGV4XG4gIC8vICAgICBjb25zdCB1c2VyQ29tZXNGaXJzdCA9IGFkZHJlc3Nlc0luZGV4W2JpdGdvSW5kZXhdID4gYWRkcmVzc2VzSW5kZXhbZmlyc3RJbmRleF07XG5cbiAgLy8gICAgIC8vIEV4cGVjdGVkIGNyZWRlbnRpYWwgc3RydWN0dXJlOlxuICAvLyAgICAgLy8gLSBJZiB1c2VyIGNvbWVzIGZpcnN0OiBbdXNlckFkZHJlc3MsIHplcm9zXVxuICAvLyAgICAgLy8gLSBJZiBiaXRnbyBjb21lcyBmaXJzdDogW3plcm9zLCB1c2VyQWRkcmVzc11cbiAgLy8gICAgIGNvbnN0IHVzZXJBZGRyZXNzSGV4ID0gQnVmZmVyLmZyb20ocEFkZHJlc3NCeXRlc1tmaXJzdEluZGV4XSkudG9TdHJpbmcoJ2hleCcpLnRvTG93ZXJDYXNlKCk7XG4gIC8vICAgICBjb25zdCBleHBlY3RlZFVzZXJBZGRyID0gJzB4JyArIHVzZXJBZGRyZXNzSGV4O1xuXG4gIC8vICAgICBpZiAodXNlckNvbWVzRmlyc3QpIHtcbiAgLy8gICAgICAgLy8gRXhwZWN0ZWQ6IFt1c2VyQWRkcmVzcywgemVyb3NdXG4gIC8vICAgICAgIC8vIFNsb3QgMCBzaG91bGQgaGF2ZSB1c2VyIGFkZHJlc3MgKHBBZGRyMCA9IDB4YzczMi4uLiA9IFVUWE8gaW5kZXggMClcbiAgLy8gICAgICAgaWYgKGVtYmVkZGVkQWRkcmVzc2VzWzBdKSB7XG4gIC8vICAgICAgICAgZW1iZWRkZWRBZGRyZXNzZXNbMF1cbiAgLy8gICAgICAgICAgIC50b0xvd2VyQ2FzZSgpXG4gIC8vICAgICAgICAgICAuc2hvdWxkLmVxdWFsKFxuICAvLyAgICAgICAgICAgICBleHBlY3RlZFVzZXJBZGRyLFxuICAvLyAgICAgICAgICAgICBgU2xvdCAwIHNob3VsZCBoYXZlIHVzZXIgYWRkcmVzcyAoJHtleHBlY3RlZFVzZXJBZGRyfSkgYmVjYXVzZSB1c2VyIGNvbWVzIGZpcnN0IGluIFVUWE8gb3JkZXJgXG4gIC8vICAgICAgICAgICApO1xuICAvLyAgICAgICB9IGVsc2Uge1xuICAvLyAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU2xvdCAwIHNob3VsZCBoYXZlIGVtYmVkZGVkIHVzZXIgYWRkcmVzcywgYnV0IGlzIGVtcHR5YCk7XG4gIC8vICAgICAgIH1cbiAgLy8gICAgICAgLy8gU2xvdCAxIHNob3VsZCBiZSB6ZXJvcyAobm8gZW1iZWRkZWQgYWRkcmVzcylcbiAgLy8gICAgICAgaWYgKGVtYmVkZGVkQWRkcmVzc2VzWzFdKSB7XG4gIC8vICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTbG90IDEgc2hvdWxkIGJlIHplcm9zLCBidXQgaGFzIGVtYmVkZGVkIGFkZHJlc3M6ICR7ZW1iZWRkZWRBZGRyZXNzZXNbMV19YCk7XG4gIC8vICAgICAgIH1cbiAgLy8gICAgIH0gZWxzZSB7XG4gIC8vICAgICAgIC8vIEV4cGVjdGVkOiBbemVyb3MsIHVzZXJBZGRyZXNzXVxuICAvLyAgICAgICAvLyBTbG90IDAgc2hvdWxkIGJlIHplcm9zXG4gIC8vICAgICAgIGlmIChlbWJlZGRlZEFkZHJlc3Nlc1swXSkge1xuICAvLyAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU2xvdCAwIHNob3VsZCBiZSB6ZXJvcywgYnV0IGhhcyBlbWJlZGRlZCBhZGRyZXNzOiAke2VtYmVkZGVkQWRkcmVzc2VzWzBdfWApO1xuICAvLyAgICAgICB9XG4gIC8vICAgICAgIC8vIFNsb3QgMSBzaG91bGQgaGF2ZSB1c2VyIGFkZHJlc3NcbiAgLy8gICAgICAgaWYgKGVtYmVkZGVkQWRkcmVzc2VzWzFdKSB7XG4gIC8vICAgICAgICAgZW1iZWRkZWRBZGRyZXNzZXNbMV1cbiAgLy8gICAgICAgICAgIC50b0xvd2VyQ2FzZSgpXG4gIC8vICAgICAgICAgICAuc2hvdWxkLmVxdWFsKFxuICAvLyAgICAgICAgICAgICBleHBlY3RlZFVzZXJBZGRyLFxuICAvLyAgICAgICAgICAgICBgU2xvdCAxIHNob3VsZCBoYXZlIHVzZXIgYWRkcmVzcyAoJHtleHBlY3RlZFVzZXJBZGRyfSkgYmVjYXVzZSBiaXRnbyBjb21lcyBmaXJzdCBpbiBVVFhPIG9yZGVyYFxuICAvLyAgICAgICAgICAgKTtcbiAgLy8gICAgICAgfSBlbHNlIHtcbiAgLy8gICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFNsb3QgMSBzaG91bGQgaGF2ZSBlbWJlZGRlZCB1c2VyIGFkZHJlc3MsIGJ1dCBpcyBlbXB0eWApO1xuICAvLyAgICAgICB9XG4gIC8vICAgICB9XG5cbiAgLy8gICAgIC8vIFRoZSBrZXkgdmVyaWZpY2F0aW9uOiBBZGRyZXNzTWFwcyBzaG91bGQgbWF0Y2ggdGhlIGNyZWRlbnRpYWwgb3JkZXJcbiAgLy8gICAgIC8vIEN1cnJlbnQgaW1wbGVtZW50YXRpb24gKFdST05HKTogQWRkcmVzc01hcHMgdXNlIHNlcXVlbnRpYWwgaW5kaWNlcyAoMCwgMSwgMi4uLilcbiAgLy8gICAgIC8vIEV4cGVjdGVkIChDT1JSRUNUKTogQWRkcmVzc01hcHMgc2hvdWxkIHVzZSBhZGRyZXNzZXNJbmRleCBsb2dpYywgbWF0Y2hpbmcgY3JlZGVudGlhbCBvcmRlclxuICAvLyAgICAgLy9cbiAgLy8gICAgIC8vIEdldCBBZGRyZXNzTWFwcyBmcm9tIHRoZSBPUklHSU5BTCB0cmFuc2FjdGlvbiAobm90IHBhcnNlZCwgYmVjYXVzZSBwYXJzZWQgQWRkcmVzc01hcCBvbmx5IGhhcyBvdXRwdXQgYWRkcmVzcylcbiAgLy8gICAgIC8vIEZvciBDLWNoYWluIGltcG9ydHMsIG9yaWdpbmFsRmxhcmVUeCBpcyBFVk1VbnNpZ25lZFR4IHdoaWNoIGhhcyBhZGRyZXNzTWFwcyBwcm9wZXJ0eVxuXG4gIC8vICAgICBjb25zdCBhZGRyZXNzTWFwcyA9IG9yaWdpbmFsQWRkcmVzc01hcHM7XG4gIC8vICAgICBhZGRyZXNzTWFwcy50b0FycmF5KCkubGVuZ3RoLnNob3VsZC5lcXVhbCgxLCAnU2hvdWxkIGhhdmUgb25lIEFkZHJlc3NNYXAgZm9yIG9uZSBpbnB1dCcpO1xuXG4gIC8vICAgICBjb25zdCBhZGRyZXNzTWFwID0gYWRkcmVzc01hcHMudG9BcnJheSgpWzBdO1xuXG4gIC8vICAgICAvLyBFeHBlY3RlZDogQmFzZWQgb24gYWRkcmVzc2VzSW5kZXggbG9naWNcbiAgLy8gICAgIC8vIElmIHVzZXIgY29tZXMgZmlyc3Q6IHNsb3QgMCA9IHVzZXIsIHNsb3QgMSA9IGJpdGdvXG4gIC8vICAgICAvLyBJZiBiaXRnbyBjb21lcyBmaXJzdDogc2xvdCAwID0gYml0Z28sIHNsb3QgMSA9IHVzZXJcbiAgLy8gICAgIGNvbnN0IGV4cGVjdGVkU2xvdDBBZGRyID0gdXNlckNvbWVzRmlyc3QgPyBwQWRkcmVzc0J5dGVzW2ZpcnN0SW5kZXhdIDogcEFkZHJlc3NCeXRlc1tiaXRnb0luZGV4XTtcbiAgLy8gICAgIGNvbnN0IGV4cGVjdGVkU2xvdDFBZGRyID0gdXNlckNvbWVzRmlyc3QgPyBwQWRkcmVzc0J5dGVzW2JpdGdvSW5kZXhdIDogcEFkZHJlc3NCeXRlc1tmaXJzdEluZGV4XTtcblxuICAvLyAgICAgLy8gQWRkcmVzc01hcCBtYXBzOiBBZGRyZXNzIC0+IHNsb3QgaW5kZXhcbiAgLy8gICAgIC8vIFdlIG5lZWQgdG8gY2hlY2sgd2hpY2ggYWRkcmVzc2VzIGFyZSBtYXBwZWQgdG8gc2xvdHMgMCBhbmQgMVxuICAvLyAgICAgLy8gQWRkcmVzc01hcC5nZXQoKSByZXR1cm5zIHRoZSBzbG90IGluZGV4IGZvciBhIGdpdmVuIGFkZHJlc3NcblxuICAvLyAgICAgLy8gVmVyaWZ5IHRoYXQgQWRkcmVzc01hcCBjb3JyZWN0bHkgbWFwcyBhZGRyZXNzZXMgYmFzZWQgb24gY3JlZGVudGlhbCBvcmRlciAoVVRYTyBvcmRlcilcbiAgLy8gICAgIC8vIFRoZSBBZGRyZXNzTWFwIHNob3VsZCBtYXAgdGhlIGFkZHJlc3NlcyB0aGF0IGFwcGVhciBpbiBjcmVkZW50aWFscyB0byB0aGUgY29ycmVjdCBzbG90c1xuICAvLyAgICAgY29uc3QgeyBBZGRyZXNzIH0gPSByZXF1aXJlKCdAZmxhcmVuZXR3b3JrL2ZsYXJlanMnKTtcbiAgLy8gICAgIGNvbnN0IGV4cGVjdGVkU2xvdDBBZGRyZXNzID0gbmV3IEFkZHJlc3MoZXhwZWN0ZWRTbG90MEFkZHIpO1xuICAvLyAgICAgY29uc3QgZXhwZWN0ZWRTbG90MUFkZHJlc3MgPSBuZXcgQWRkcmVzcyhleHBlY3RlZFNsb3QxQWRkcik7XG4gIC8vICAgICBjb25zdCBleHBlY3RlZFNsb3QwRnJvbU1hcCA9IGFkZHJlc3NNYXAuZ2V0KGV4cGVjdGVkU2xvdDBBZGRyZXNzKTtcbiAgLy8gICAgIGNvbnN0IGV4cGVjdGVkU2xvdDFGcm9tTWFwID0gYWRkcmVzc01hcC5nZXQoZXhwZWN0ZWRTbG90MUFkZHJlc3MpO1xuXG4gIC8vICAgICAvLyBWZXJpZnkgdGhhdCB0aGUgZXhwZWN0ZWQgYWRkcmVzc2VzIG1hcCB0byB0aGUgY29ycmVjdCBzbG90c1xuICAvLyAgICAgaWYgKGV4cGVjdGVkU2xvdDBGcm9tTWFwID09PSB1bmRlZmluZWQpIHtcbiAgLy8gICAgICAgdGhyb3cgbmV3IEVycm9yKGBBZGRyZXNzIGF0IFVUWE8gaW5kZXggJHthZGRyZXNzZXNJbmRleFtmaXJzdEluZGV4XX0gbm90IGZvdW5kIGluIEFkZHJlc3NNYXBgKTtcbiAgLy8gICAgIH1cbiAgLy8gICAgIGlmIChleHBlY3RlZFNsb3QxRnJvbU1hcCA9PT0gdW5kZWZpbmVkKSB7XG4gIC8vICAgICAgIHRocm93IG5ldyBFcnJvcihgQWRkcmVzcyBhdCBVVFhPIGluZGV4ICR7YWRkcmVzc2VzSW5kZXhbYml0Z29JbmRleF19IG5vdCBmb3VuZCBpbiBBZGRyZXNzTWFwYCk7XG4gIC8vICAgICB9XG4gIC8vICAgICBleHBlY3RlZFNsb3QwRnJvbU1hcC5zaG91bGQuZXF1YWwoMCwgYEFkZHJlc3MgYXQgVVRYTyBpbmRleCAke2FkZHJlc3Nlc0luZGV4W2ZpcnN0SW5kZXhdfSBzaG91bGQgbWFwIHRvIHNsb3QgMGApO1xuICAvLyAgICAgZXhwZWN0ZWRTbG90MUZyb21NYXAuc2hvdWxkLmVxdWFsKDEsIGBBZGRyZXNzIGF0IFVUWE8gaW5kZXggJHthZGRyZXNzZXNJbmRleFtiaXRnb0luZGV4XX0gc2hvdWxkIG1hcCB0byBzbG90IDFgKTtcblxuICAvLyAgICAgLy8gSWYgYWRkcmVzc2VzSW5kZXggaXMgbm90IHNlcXVlbnRpYWwgKFswLCAxLCAuLi5dKSwgdmVyaWZ5IHRoYXQgc2VxdWVudGlhbCBtYXBwaW5nIGlzIE5PVCB1c2VkIGluY29ycmVjdGx5XG4gIC8vICAgICAvLyBTZXF1ZW50aWFsIG1hcHBpbmcgbWVhbnM6IHBBZGRyZXNzZXNbMF0gLT4gc2xvdCAwLCBwQWRkcmVzc2VzWzFdIC0+IHNsb3QgMSwgcmVnYXJkbGVzcyBvZiBVVFhPIG9yZGVyXG4gIC8vICAgICBjb25zdCB1c2VzU2VxdWVudGlhbE1hcHBpbmcgPSBhZGRyZXNzZXNJbmRleFswXSA9PT0gMCAmJiBhZGRyZXNzZXNJbmRleFsxXSA9PT0gMTtcblxuICAvLyAgICAgaWYgKCF1c2VzU2VxdWVudGlhbE1hcHBpbmcpIHtcbiAgLy8gICAgICAgLy8gQ2hlY2sgaWYgQWRkcmVzc01hcCB1c2VzIHNlcXVlbnRpYWwgbWFwcGluZyAoYXJyYXkgb3JkZXIpIGluc3RlYWQgb2YgVVRYTyBvcmRlclxuICAvLyAgICAgICBjb25zdCBzZXF1ZW50aWFsU2xvdDAgPSBhZGRyZXNzTWFwLmdldChuZXcgQWRkcmVzcyhwQWRkcmVzc0J5dGVzWzBdKSk7XG4gIC8vICAgICAgIGNvbnN0IHNlcXVlbnRpYWxTbG90MSA9IGFkZHJlc3NNYXAuZ2V0KG5ldyBBZGRyZXNzKHBBZGRyZXNzQnl0ZXNbMV0pKTtcblxuICAvLyAgICAgICAvLyBTZXF1ZW50aWFsIG1hcHBpbmcgd291bGQgbWFwIHBBZGRyZXNzZXNbMF0gLT4gc2xvdCAwLCBwQWRkcmVzc2VzWzFdIC0+IHNsb3QgMVxuICAvLyAgICAgICAvLyBCdXQgd2Ugd2FudCBVVFhPIG9yZGVyIG1hcHBpbmcgYmFzZWQgb24gYWRkcmVzc2VzSW5kZXhcbiAgLy8gICAgICAgY29uc3QgaXNTZXF1ZW50aWFsID0gc2VxdWVudGlhbFNsb3QwID09PSAwICYmIHNlcXVlbnRpYWxTbG90MSA9PT0gMTtcblxuICAvLyAgICAgICAvLyBDaGVjayBpZiBwQWRkcmVzc2VzWzBdIGFuZCBwQWRkcmVzc2VzWzFdIGFyZSB0aGUgZXhwZWN0ZWQgYWRkcmVzc2VzIGZvciBzbG90cyAwIGFuZCAxXG4gIC8vICAgICAgIC8vIElmIHRoZXkgYXJlLCB0aGVuIHNlcXVlbnRpYWwgbWFwcGluZyBoYXBwZW5zIHRvIGJlIGNvcnJlY3QgKGJ5IGNvaW5jaWRlbmNlKVxuICAvLyAgICAgICBjb25zdCBwQWRkcmVzczBJc0V4cGVjdGVkU2xvdDAgPVxuICAvLyAgICAgICAgIEJ1ZmZlci5jb21wYXJlKEJ1ZmZlci5mcm9tKHBBZGRyZXNzQnl0ZXNbMF0pLCBCdWZmZXIuZnJvbShleHBlY3RlZFNsb3QwQWRkcikpID09PSAwO1xuICAvLyAgICAgICBjb25zdCBwQWRkcmVzczFJc0V4cGVjdGVkU2xvdDEgPVxuICAvLyAgICAgICAgIEJ1ZmZlci5jb21wYXJlKEJ1ZmZlci5mcm9tKHBBZGRyZXNzQnl0ZXNbMV0pLCBCdWZmZXIuZnJvbShleHBlY3RlZFNsb3QxQWRkcikpID09PSAwO1xuXG4gIC8vICAgICAgIC8vIElmIHNlcXVlbnRpYWwgbWFwcGluZyBpcyB1c2VkIGJ1dCBpdCdzIE5PVCBjb3JyZWN0IChkb2Vzbid0IG1hdGNoIGV4cGVjdGVkIGFkZHJlc3NlcyksIGZhaWxcbiAgLy8gICAgICAgaWYgKGlzU2VxdWVudGlhbCAmJiAoIXBBZGRyZXNzMElzRXhwZWN0ZWRTbG90MCB8fCAhcEFkZHJlc3MxSXNFeHBlY3RlZFNsb3QxKSkge1xuICAvLyAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgLy8gICAgICAgICAgIGBBZGRyZXNzTWFwIHVzZXMgc2VxdWVudGlhbCBtYXBwaW5nIChhcnJheSBvcmRlcikgYnV0IHNob3VsZCB1c2UgVVRYTyBvcmRlci4gYCArXG4gIC8vICAgICAgICAgICAgIGBhZGRyZXNzZXNJbmRleDogWyR7YWRkcmVzc2VzSW5kZXguam9pbignLCAnKX1dLiBgICtcbiAgLy8gICAgICAgICAgICAgYEV4cGVjdGVkIHNsb3QgMCA9IGFkZHJlc3MgYXQgVVRYTyBpbmRleCAke2FkZHJlc3Nlc0luZGV4W2ZpcnN0SW5kZXhdfSwgc2xvdCAxID0gYWRkcmVzcyBhdCBVVFhPIGluZGV4ICR7YWRkcmVzc2VzSW5kZXhbYml0Z29JbmRleF19YFxuICAvLyAgICAgICAgICk7XG4gIC8vICAgICAgIH1cbiAgLy8gICAgIH1cbiAgLy8gICB9KTtcbiAgLy8gfSk7XG59KTtcbiJdfQ==