@bitgo-beta/sdk-coin-ada 2.3.14-beta.162 → 2.3.14-beta.1621

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 (113) hide show
  1. package/dist/src/ada.d.ts +15 -13
  2. package/dist/src/ada.d.ts.map +1 -1
  3. package/dist/src/ada.js +108 -32
  4. package/dist/src/adaToken.d.ts +16 -11
  5. package/dist/src/adaToken.d.ts.map +1 -1
  6. package/dist/src/adaToken.js +108 -3
  7. package/dist/src/index.js +6 -2
  8. package/dist/src/lib/index.d.ts +2 -0
  9. package/dist/src/lib/index.d.ts.map +1 -1
  10. package/dist/src/lib/index.js +29 -9
  11. package/dist/src/lib/keyPair.js +29 -16
  12. package/dist/src/lib/messages/cip8/cip8Message.d.ts +25 -0
  13. package/dist/src/lib/messages/cip8/cip8Message.d.ts.map +1 -0
  14. package/dist/src/lib/messages/cip8/cip8Message.js +140 -0
  15. package/dist/src/lib/messages/cip8/cip8MessageBuilder.d.ts +19 -0
  16. package/dist/src/lib/messages/cip8/cip8MessageBuilder.d.ts.map +1 -0
  17. package/dist/src/lib/messages/cip8/cip8MessageBuilder.js +27 -0
  18. package/dist/src/lib/messages/cip8/index.d.ts +4 -0
  19. package/dist/src/lib/messages/cip8/index.d.ts.map +1 -0
  20. package/dist/src/lib/messages/cip8/index.js +20 -0
  21. package/dist/src/lib/messages/cip8/utils.d.ts +24 -0
  22. package/dist/src/lib/messages/cip8/utils.d.ts.map +1 -0
  23. package/dist/src/lib/messages/cip8/utils.js +73 -0
  24. package/dist/src/lib/messages/index.d.ts +3 -0
  25. package/dist/src/lib/messages/index.d.ts.map +1 -0
  26. package/dist/src/lib/messages/index.js +19 -0
  27. package/dist/src/lib/messages/messageBuilderFactory.d.ts +7 -0
  28. package/dist/src/lib/messages/messageBuilderFactory.d.ts.map +1 -0
  29. package/dist/src/lib/messages/messageBuilderFactory.js +20 -0
  30. package/dist/src/lib/stakingActivateBuilder.d.ts +1 -1
  31. package/dist/src/lib/stakingActivateBuilder.d.ts.map +1 -1
  32. package/dist/src/lib/stakingActivateBuilder.js +30 -10
  33. package/dist/src/lib/stakingDeactivateBuilder.js +24 -10
  34. package/dist/src/lib/transaction.d.ts +13 -7
  35. package/dist/src/lib/transaction.d.ts.map +1 -1
  36. package/dist/src/lib/transaction.js +48 -16
  37. package/dist/src/lib/transactionBuilder.d.ts +82 -3
  38. package/dist/src/lib/transactionBuilder.d.ts.map +1 -1
  39. package/dist/src/lib/transactionBuilder.js +429 -27
  40. package/dist/src/lib/transactionBuilderFactory.d.ts +2 -0
  41. package/dist/src/lib/transactionBuilderFactory.d.ts.map +1 -1
  42. package/dist/src/lib/transactionBuilderFactory.js +7 -1
  43. package/dist/src/lib/utils.d.ts +23 -0
  44. package/dist/src/lib/utils.d.ts.map +1 -1
  45. package/dist/src/lib/utils.js +153 -17
  46. package/dist/src/lib/voteDelegationBuilder.d.ts +24 -0
  47. package/dist/src/lib/voteDelegationBuilder.d.ts.map +1 -0
  48. package/dist/src/lib/voteDelegationBuilder.js +84 -0
  49. package/dist/test/resources/cip8Resources.d.ts +25 -0
  50. package/dist/test/resources/cip8Resources.d.ts.map +1 -0
  51. package/dist/test/resources/cip8Resources.js +76 -0
  52. package/dist/test/resources/index.d.ts +458 -0
  53. package/dist/test/resources/index.d.ts.map +1 -0
  54. package/dist/test/resources/index.js +659 -0
  55. package/dist/test/unit/StakingActivateBuilder.d.ts +2 -0
  56. package/dist/test/unit/StakingActivateBuilder.d.ts.map +1 -0
  57. package/dist/test/unit/StakingActivateBuilder.js +213 -0
  58. package/dist/test/unit/StakingDeactivateBuilder.d.ts +2 -0
  59. package/dist/test/unit/StakingDeactivateBuilder.d.ts.map +1 -0
  60. package/dist/test/unit/StakingDeactivateBuilder.js +158 -0
  61. package/dist/test/unit/ada.d.ts +5 -0
  62. package/dist/test/unit/ada.d.ts.map +1 -0
  63. package/dist/test/unit/ada.js +1246 -0
  64. package/dist/test/unit/getBuilderFactory.d.ts +3 -0
  65. package/dist/test/unit/getBuilderFactory.d.ts.map +1 -0
  66. package/dist/test/unit/getBuilderFactory.js +10 -0
  67. package/dist/test/unit/index.d.ts +2 -0
  68. package/dist/test/unit/index.d.ts.map +1 -0
  69. package/dist/test/unit/index.js +32 -0
  70. package/dist/test/unit/keyPair.d.ts +2 -0
  71. package/dist/test/unit/keyPair.d.ts.map +1 -0
  72. package/dist/test/unit/keyPair.js +88 -0
  73. package/dist/test/unit/messages/cip8/cip8Message.d.ts +2 -0
  74. package/dist/test/unit/messages/cip8/cip8Message.d.ts.map +1 -0
  75. package/dist/test/unit/messages/cip8/cip8Message.js +131 -0
  76. package/dist/test/unit/messages/cip8/cip8MessageBuilder.d.ts +2 -0
  77. package/dist/test/unit/messages/cip8/cip8MessageBuilder.d.ts.map +1 -0
  78. package/dist/test/unit/messages/cip8/cip8MessageBuilder.js +132 -0
  79. package/dist/test/unit/messages/cip8/utils.d.ts +2 -0
  80. package/dist/test/unit/messages/cip8/utils.d.ts.map +1 -0
  81. package/dist/test/unit/messages/cip8/utils.js +127 -0
  82. package/dist/test/unit/messages/messageBuilderFactory.d.ts +2 -0
  83. package/dist/test/unit/messages/messageBuilderFactory.d.ts.map +1 -0
  84. package/dist/test/unit/messages/messageBuilderFactory.js +35 -0
  85. package/dist/test/unit/stakingClaimRewardsBuilder.d.ts +2 -0
  86. package/dist/test/unit/stakingClaimRewardsBuilder.d.ts.map +1 -0
  87. package/dist/test/unit/stakingClaimRewardsBuilder.js +70 -0
  88. package/dist/test/unit/stakingPledgeBuilder.d.ts +2 -0
  89. package/dist/test/unit/stakingPledgeBuilder.d.ts.map +1 -0
  90. package/dist/test/unit/stakingPledgeBuilder.js +141 -0
  91. package/dist/test/unit/stakingWithdrawBuilder.d.ts +2 -0
  92. package/dist/test/unit/stakingWithdrawBuilder.d.ts.map +1 -0
  93. package/dist/test/unit/stakingWithdrawBuilder.js +167 -0
  94. package/dist/test/unit/tokenWithdrawal.d.ts +2 -0
  95. package/dist/test/unit/tokenWithdrawal.d.ts.map +1 -0
  96. package/dist/test/unit/tokenWithdrawal.js +842 -0
  97. package/dist/test/unit/transaction.d.ts +2 -0
  98. package/dist/test/unit/transaction.d.ts.map +1 -0
  99. package/dist/test/unit/transaction.js +100 -0
  100. package/dist/test/unit/transactionBuilder.d.ts +2 -0
  101. package/dist/test/unit/transactionBuilder.d.ts.map +1 -0
  102. package/dist/test/unit/transactionBuilder.js +454 -0
  103. package/dist/test/unit/utils.d.ts +2 -0
  104. package/dist/test/unit/utils.d.ts.map +1 -0
  105. package/dist/test/unit/utils.js +138 -0
  106. package/dist/test/unit/voteDelegationBuilder.d.ts +2 -0
  107. package/dist/test/unit/voteDelegationBuilder.d.ts.map +1 -0
  108. package/dist/test/unit/voteDelegationBuilder.js +96 -0
  109. package/dist/tsconfig.tsbuildinfo +1 -0
  110. package/package.json +17 -12
  111. package/.eslintignore +0 -5
  112. package/.mocharc.yml +0 -8
  113. package/CHANGELOG.md +0 -353
@@ -0,0 +1,842 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const should_1 = __importDefault(require("should"));
40
+ const sdk_core_1 = require("@bitgo-beta/sdk-core");
41
+ const testData = __importStar(require("../resources"));
42
+ const src_1 = require("../../src");
43
+ const statics_1 = require("@bitgo-beta/statics");
44
+ const CardanoWasm = __importStar(require("@emurgo/cardano-serialization-lib-nodejs"));
45
+ const sdk_test_1 = require("@bitgo-beta/sdk-test");
46
+ const sdk_api_1 = require("@bitgo-beta/sdk-api");
47
+ describe('ADA Token Operations', async () => {
48
+ const factory = new src_1.TransactionBuilderFactory(statics_1.coins.get('tada'));
49
+ const receiverAddress = testData.rawTx.outputAddress2.address;
50
+ const senderAddress = testData.rawTx.outputAddress1.address;
51
+ const policyId = 'e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72';
52
+ const policyScriptHash = CardanoWasm.ScriptHash.from_hex(policyId);
53
+ const assetName = 'tada:water';
54
+ const name = 'WATER';
55
+ const asciiEncodedName = Buffer.from(name, 'ascii').toString('hex');
56
+ const fingerprint = 'asset1n69xf60d0760xvn8v2ffd5frvsm0cl2r8hfjf6';
57
+ const unsupportedPolicyId = '279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f';
58
+ const unsupportedPolicyScriptHash = CardanoWasm.ScriptHash.from_hex(unsupportedPolicyId);
59
+ const unsupportedName = 'BITGO';
60
+ const unsupportedAsciiEncodedName = Buffer.from(unsupportedName, 'ascii').toString('hex');
61
+ const unsupportedFingerprint = 'asset1m8h0gk7f6x5j5qg0x5m4q5f5j5qg0x5m4q5f5j';
62
+ it(`should build a transaction with token ${assetName} - ada + ${assetName}`, async () => {
63
+ const quantity = '20';
64
+ const totalInput = 20000000;
65
+ const totalAssetList = {
66
+ [fingerprint]: {
67
+ quantity: '100',
68
+ policy_id: policyId,
69
+ asset_name: asciiEncodedName,
70
+ },
71
+ };
72
+ const expectedChangeAda = (totalInput -
73
+ 1500000 /* min ada for change token utxo */ -
74
+ 1500000 /* min ada for recipient token utxo*/ -
75
+ 173597) /* fee */
76
+ .toString();
77
+ const expectedChangeToken = '80';
78
+ const txBuilder = factory.getTransferBuilder();
79
+ txBuilder.input({
80
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
81
+ transaction_index: 1,
82
+ });
83
+ txBuilder.output({
84
+ address: receiverAddress,
85
+ amount: '0', // Set ADA amount to 0 for token transfer (min ADA is handled in sdk build)
86
+ multiAssets: {
87
+ asset_name: asciiEncodedName,
88
+ policy_id: policyId,
89
+ quantity,
90
+ fingerprint,
91
+ },
92
+ });
93
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
94
+ txBuilder.ttl(800000000);
95
+ txBuilder.isTokenTransaction();
96
+ const tx = (await txBuilder.build());
97
+ should_1.default.equal(tx.type, sdk_core_1.TransactionType.Send);
98
+ const txData = tx.toJson();
99
+ // Check outputs (should include multi-asset and regular change)
100
+ txData.outputs.length.should.equal(3);
101
+ txData.inputs.length.should.equal(1);
102
+ // One output should have the multi-asset change and the other for the transfer
103
+ const assetOutput = txData.outputs.filter((output) => output.multiAssets !== undefined);
104
+ assetOutput.length.should.equal(2);
105
+ // Verify inputs and outputs
106
+ const input = txData.inputs[0];
107
+ input.transaction_id.should.equal('3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21');
108
+ input.transaction_index.should.equal(1);
109
+ // Validate receiver output
110
+ const receiverOutput = txData.outputs.filter((output) => output.address === receiverAddress);
111
+ receiverOutput.length.should.equal(1);
112
+ receiverOutput[0].amount.should.equal('1500000'); // Minimum ADA for asset output
113
+ receiverOutput[0].multiAssets
114
+ .get_asset(policyScriptHash, CardanoWasm.AssetName.new(Buffer.from(asciiEncodedName, 'hex')))
115
+ .to_str()
116
+ .should.equal(quantity);
117
+ // Validate change outputs (one with asset and one without)
118
+ const changeOutput = txData.outputs.filter((output) => output.address === senderAddress);
119
+ changeOutput.length.should.equal(2);
120
+ const changeWithAsset = changeOutput.find((output) => output.multiAssets !== undefined);
121
+ should_1.default.exist(changeWithAsset);
122
+ changeWithAsset.amount.should.equal('1500000'); // Minimum ADA for asset output
123
+ changeWithAsset.multiAssets
124
+ .get_asset(policyScriptHash, CardanoWasm.AssetName.new(Buffer.from(asciiEncodedName, 'hex')))
125
+ .to_str()
126
+ .should.equal(expectedChangeToken);
127
+ const changeWithoutAsset = changeOutput.find((output) => output.multiAssets === undefined);
128
+ should_1.default.exist(changeWithoutAsset);
129
+ changeWithoutAsset.amount.should.equal(expectedChangeAda); // Remaining ADA after fees and min ADAs
130
+ });
131
+ it(`should build a transaction with token ${assetName} - ada + ${assetName} + unsupported token`, async () => {
132
+ const quantity = '20';
133
+ const totalInput = 20000000;
134
+ const totalAssetList = {
135
+ [fingerprint]: {
136
+ quantity: '100',
137
+ policy_id: policyId,
138
+ asset_name: asciiEncodedName,
139
+ },
140
+ [unsupportedFingerprint]: {
141
+ quantity: '10000',
142
+ policy_id: unsupportedPolicyId,
143
+ asset_name: unsupportedAsciiEncodedName,
144
+ },
145
+ };
146
+ const expectedChangeAda = (totalInput -
147
+ 1500000 /* min ada for change token utxo */ -
148
+ 1500000 /* min ada for recipient token utxo*/ -
149
+ 1500000 /* min ada for unsupported token change utxo */ -
150
+ 179889) /* fee */
151
+ .toString();
152
+ const expectedChangeToken = '80';
153
+ const txBuilder = factory.getTransferBuilder();
154
+ txBuilder.input({
155
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
156
+ transaction_index: 1,
157
+ });
158
+ txBuilder.input({
159
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba22',
160
+ transaction_index: 1,
161
+ });
162
+ txBuilder.output({
163
+ address: receiverAddress,
164
+ amount: '0', // Set ADA amount to 0 for token transfer (min ADA is handled in sdk build)
165
+ multiAssets: {
166
+ asset_name: asciiEncodedName,
167
+ policy_id: policyId,
168
+ quantity,
169
+ fingerprint,
170
+ },
171
+ });
172
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
173
+ txBuilder.ttl(800000000);
174
+ txBuilder.isTokenTransaction();
175
+ const tx = (await txBuilder.build());
176
+ should_1.default.equal(tx.type, sdk_core_1.TransactionType.Send);
177
+ const txData = tx.toJson();
178
+ // Check outputs (should include multi-asset and regular change)
179
+ txData.outputs.length.should.equal(4);
180
+ txData.inputs.length.should.equal(2);
181
+ // One output should have the multi-asset change and the other for the transfer
182
+ const assetOutput = txData.outputs.filter((output) => output.multiAssets !== undefined);
183
+ assetOutput.length.should.equal(3);
184
+ // Verify inputs and outputs
185
+ txData.inputs[0].transaction_id.should.equal('3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21');
186
+ txData.inputs[0].transaction_index.should.equal(1);
187
+ txData.inputs[1].transaction_id.should.equal('3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba22');
188
+ txData.inputs[1].transaction_index.should.equal(1);
189
+ // Validate receiver output
190
+ const receiverOutput = txData.outputs.filter((output) => output.address === receiverAddress);
191
+ receiverOutput.length.should.equal(1);
192
+ receiverOutput[0].amount.should.equal('1500000'); // Minimum ADA for asset output
193
+ receiverOutput[0].multiAssets
194
+ .get_asset(policyScriptHash, CardanoWasm.AssetName.new(Buffer.from(asciiEncodedName, 'hex')))
195
+ .to_str()
196
+ .should.equal(quantity);
197
+ // Validate change outputs (one with supported token, one with unsupported token and one for pure ada)
198
+ const changeOutput = txData.outputs.filter((output) => output.address === senderAddress);
199
+ changeOutput.length.should.equal(3);
200
+ const changeWithAsset = changeOutput.filter((output) => output.multiAssets !== undefined);
201
+ changeWithAsset.length.should.equal(2);
202
+ let tokens = 0;
203
+ changeWithAsset.forEach((output) => {
204
+ output.amount.should.equal('1500000'); // Minimum ADA for asset output
205
+ const supportedTokenChangeQty = output.multiAssets
206
+ .get_asset(policyScriptHash, CardanoWasm.AssetName.new(Buffer.from(asciiEncodedName, 'hex')))
207
+ .to_str();
208
+ const unsupportedTokenChangeQty = output.multiAssets
209
+ .get_asset(unsupportedPolicyScriptHash, CardanoWasm.AssetName.new(Buffer.from(unsupportedAsciiEncodedName, 'hex')))
210
+ .to_str();
211
+ if (supportedTokenChangeQty !== '0') {
212
+ supportedTokenChangeQty.should.equal(expectedChangeToken);
213
+ tokens++;
214
+ }
215
+ else {
216
+ unsupportedTokenChangeQty.should.equal('10000');
217
+ tokens++;
218
+ }
219
+ });
220
+ tokens.should.equal(2);
221
+ const changeWithoutAsset = changeOutput.find((output) => output.multiAssets === undefined);
222
+ should_1.default.exist(changeWithoutAsset);
223
+ changeWithoutAsset.amount.should.equal(expectedChangeAda); // Remaining ADA after fees and min ADAs
224
+ });
225
+ it(`should fail to build a transaction with ${assetName} token and insufficient minimum ADA`, async () => {
226
+ const quantity = '20';
227
+ const totalInput = 2000000;
228
+ const totalAssetList = {
229
+ [fingerprint]: {
230
+ quantity: '100',
231
+ policy_id: policyId,
232
+ asset_name: asciiEncodedName,
233
+ },
234
+ };
235
+ const txBuilder = factory.getTransferBuilder();
236
+ txBuilder.input({
237
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
238
+ transaction_index: 1,
239
+ });
240
+ txBuilder.output({
241
+ address: receiverAddress,
242
+ amount: '0', // Set ADA amount to 0 for token transfer (min ADA is handled in sdk build)
243
+ multiAssets: {
244
+ asset_name: asciiEncodedName,
245
+ policy_id: policyId,
246
+ quantity,
247
+ fingerprint,
248
+ },
249
+ });
250
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
251
+ txBuilder.ttl(800000000);
252
+ txBuilder.isTokenTransaction();
253
+ await txBuilder
254
+ .build()
255
+ .should.rejectedWith('Insufficient funds: need a minimum of 1500000 lovelace per output to construct token transactions');
256
+ });
257
+ it(`should fail to build a transaction with ${assetName} and insufficient token qty`, async () => {
258
+ const quantity = '20';
259
+ const totalInput = 20000000;
260
+ const totalAssetList = {
261
+ [fingerprint]: {
262
+ quantity: '5',
263
+ policy_id: policyId,
264
+ asset_name: asciiEncodedName,
265
+ },
266
+ };
267
+ const txBuilder = factory.getTransferBuilder();
268
+ txBuilder.input({
269
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
270
+ transaction_index: 1,
271
+ });
272
+ txBuilder.output({
273
+ address: receiverAddress,
274
+ amount: '0', // Set ADA amount to 0 for token transfer (min ADA is handled in sdk build)
275
+ multiAssets: {
276
+ asset_name: asciiEncodedName,
277
+ policy_id: policyId,
278
+ quantity,
279
+ fingerprint,
280
+ },
281
+ });
282
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
283
+ txBuilder.ttl(800000000);
284
+ txBuilder.isTokenTransaction();
285
+ await txBuilder.build().should.rejectedWith('Insufficient qty: not enough token qty to cover receiver output');
286
+ });
287
+ it(`should build a transaction with ${assetName} when the token qty is exactly the qty in withdrawal`, async () => {
288
+ const quantity = '1';
289
+ const totalInput = 20000000;
290
+ const totalAssetList = {
291
+ [fingerprint]: {
292
+ quantity: '1',
293
+ policy_id: policyId,
294
+ asset_name: asciiEncodedName,
295
+ },
296
+ };
297
+ const txBuilder = factory.getTransferBuilder();
298
+ txBuilder.input({
299
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
300
+ transaction_index: 1,
301
+ });
302
+ txBuilder.output({
303
+ address: receiverAddress,
304
+ amount: '0', // Set ADA amount to 0 for token transfer (min ADA is handled in sdk build)
305
+ multiAssets: {
306
+ asset_name: asciiEncodedName,
307
+ policy_id: policyId,
308
+ quantity,
309
+ fingerprint,
310
+ },
311
+ });
312
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
313
+ txBuilder.ttl(800000000);
314
+ txBuilder.isTokenTransaction();
315
+ await txBuilder.build().should.not.be.rejected();
316
+ });
317
+ it(`should build a sponsored token transaction where fee address sponsors min ADA for receiver`, async () => {
318
+ const feeAddress = 'addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwq2ytjqp';
319
+ const quantity = '20';
320
+ const senderInputBalance = 5000000;
321
+ const feeAddressInputBalance = 20000000; // Fee address has enough ADA to sponsor
322
+ const totalAssetList = {
323
+ [fingerprint]: {
324
+ quantity: '100',
325
+ policy_id: policyId,
326
+ asset_name: asciiEncodedName,
327
+ },
328
+ };
329
+ const txBuilder = factory.getTransferBuilder();
330
+ // Sender input (has tokens)
331
+ txBuilder.input({
332
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
333
+ transaction_index: 1,
334
+ });
335
+ // Fee address input (sponsors fees and min ADA)
336
+ txBuilder.input({
337
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba22',
338
+ transaction_index: 0,
339
+ });
340
+ txBuilder.output({
341
+ address: receiverAddress,
342
+ amount: '0', // Set ADA amount to 0 for token transfer (min ADA is handled by fee address)
343
+ multiAssets: {
344
+ asset_name: asciiEncodedName,
345
+ policy_id: policyId,
346
+ quantity,
347
+ fingerprint,
348
+ },
349
+ });
350
+ txBuilder.changeAddress(senderAddress, senderInputBalance.toString(), totalAssetList);
351
+ txBuilder.sponsorshipInfo({
352
+ feeAddress: feeAddress,
353
+ feeAddressInputBalance: feeAddressInputBalance.toString(),
354
+ });
355
+ txBuilder.ttl(800000000);
356
+ txBuilder.isTokenTransaction();
357
+ const tx = (await txBuilder.build());
358
+ should_1.default.equal(tx.type, sdk_core_1.TransactionType.Send);
359
+ const txData = tx.toJson();
360
+ txData.inputs.length.should.equal(2);
361
+ txData.outputs.length.should.equal(4);
362
+ // Validate receiver output - min ADA should be sponsored by fee address
363
+ const receiverOutput = txData.outputs.filter((output) => output.address === receiverAddress);
364
+ receiverOutput.length.should.equal(1);
365
+ receiverOutput[0].amount.should.equal('1500000'); // Minimum ADA for asset output (sponsored by fee address)
366
+ receiverOutput[0].multiAssets
367
+ .get_asset(policyScriptHash, CardanoWasm.AssetName.new(Buffer.from(asciiEncodedName, 'hex')))
368
+ .to_str()
369
+ .should.equal(quantity);
370
+ // Validate sender change output - should have full sender balance (tokens only, no ADA deduction for receiver)
371
+ const senderChangeOutput = txData.outputs.filter((output) => output.address === senderAddress);
372
+ senderChangeOutput.length.should.be.equal(2);
373
+ // Validate fee address change output - should have remaining ADA after fees and min ADA for receiver
374
+ const feeAddressChangeOutput = txData.outputs.filter((output) => output.address === feeAddress);
375
+ feeAddressChangeOutput.length.should.equal(1);
376
+ // Fee address change should not have any tokens
377
+ should_1.default.not.exist(feeAddressChangeOutput[0].multiAssets);
378
+ tx.getFee.should.equal('182485'); // Fee with two witnesses
379
+ });
380
+ it(`should rebuild a sponsored transaction from hex with isRebuild flag`, async () => {
381
+ const feeAddress = 'addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwq2ytjqp';
382
+ const quantity = '20';
383
+ const senderInputBalance = 5000000;
384
+ const feeAddressInputBalance = 20000000;
385
+ const totalAssetList = {
386
+ [fingerprint]: {
387
+ quantity: '100',
388
+ policy_id: policyId,
389
+ asset_name: asciiEncodedName,
390
+ },
391
+ };
392
+ // Step 1: Build the initial sponsored transaction
393
+ const txBuilder = factory.getTransferBuilder();
394
+ txBuilder.input({
395
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
396
+ transaction_index: 1,
397
+ });
398
+ txBuilder.input({
399
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba22',
400
+ transaction_index: 0,
401
+ });
402
+ txBuilder.output({
403
+ address: receiverAddress,
404
+ amount: '0',
405
+ multiAssets: {
406
+ asset_name: asciiEncodedName,
407
+ policy_id: policyId,
408
+ quantity,
409
+ fingerprint,
410
+ },
411
+ });
412
+ txBuilder.changeAddress(senderAddress, senderInputBalance.toString(), totalAssetList);
413
+ txBuilder.sponsorshipInfo({
414
+ feeAddress: feeAddress,
415
+ feeAddressInputBalance: feeAddressInputBalance.toString(),
416
+ });
417
+ txBuilder.ttl(800000000);
418
+ txBuilder.isTokenTransaction();
419
+ const initialTx = (await txBuilder.build());
420
+ const initialFee = initialTx.getFee;
421
+ const initialTxData = initialTx.toJson();
422
+ // Step 2: Rebuild with isRebuild = true
423
+ // This simulates rebuilding from scratch but with isRebuild flag to add sponsor witness
424
+ const rebuildTxBuilder = factory.getTransferBuilder();
425
+ rebuildTxBuilder.input({
426
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
427
+ transaction_index: 1,
428
+ });
429
+ rebuildTxBuilder.input({
430
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba22',
431
+ transaction_index: 0,
432
+ });
433
+ rebuildTxBuilder.output({
434
+ address: receiverAddress,
435
+ amount: '0',
436
+ multiAssets: {
437
+ asset_name: asciiEncodedName,
438
+ policy_id: policyId,
439
+ quantity,
440
+ fingerprint,
441
+ },
442
+ });
443
+ rebuildTxBuilder.changeAddress(senderAddress, senderInputBalance.toString(), totalAssetList);
444
+ rebuildTxBuilder.sponsorshipInfo({
445
+ feeAddress: feeAddress,
446
+ feeAddressInputBalance: feeAddressInputBalance.toString(),
447
+ isRebuild: true,
448
+ });
449
+ rebuildTxBuilder.ttl(800000000);
450
+ rebuildTxBuilder.isTokenTransaction();
451
+ const rebuiltTx = (await rebuildTxBuilder.build());
452
+ const rebuiltTxData = rebuiltTx.toJson();
453
+ // Verify the rebuilt transaction preserves the same structure
454
+ rebuiltTxData.inputs.length.should.equal(initialTxData.inputs.length);
455
+ rebuiltTxData.outputs.length.should.equal(initialTxData.outputs.length);
456
+ // Fee should be preserved from the original transaction
457
+ rebuiltTx.getFee.should.equal(initialFee);
458
+ // Verify receiver output is preserved
459
+ const receiverOutput = rebuiltTxData.outputs.filter((output) => output.address === receiverAddress);
460
+ receiverOutput.length.should.equal(1);
461
+ receiverOutput[0].amount.should.equal('1500000');
462
+ });
463
+ describe('AdaToken verifyTransaction', () => {
464
+ let bitgo;
465
+ let adaToken;
466
+ before(function () {
467
+ bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
468
+ bitgo.initializeTestVars();
469
+ const tokenConfig = {
470
+ type: 'tada:water',
471
+ coin: 'tada',
472
+ network: 'Testnet',
473
+ name: 'WATER',
474
+ decimalPlaces: 0,
475
+ policyId: policyId,
476
+ assetName: name, // ASCII 'WATER', not hex-encoded
477
+ contractAddress: `${policyId}:${asciiEncodedName}`,
478
+ };
479
+ adaToken = new src_1.AdaToken(bitgo, tokenConfig);
480
+ });
481
+ it('should verify a token transaction with correct token amount', async () => {
482
+ const quantity = '20';
483
+ const totalInput = 20000000;
484
+ const totalAssetList = {
485
+ [fingerprint]: {
486
+ quantity: '100',
487
+ policy_id: policyId,
488
+ asset_name: asciiEncodedName,
489
+ },
490
+ };
491
+ const txBuilder = factory.getTransferBuilder();
492
+ txBuilder.input({
493
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
494
+ transaction_index: 1,
495
+ });
496
+ txBuilder.output({
497
+ address: receiverAddress,
498
+ amount: '0',
499
+ multiAssets: {
500
+ asset_name: asciiEncodedName,
501
+ policy_id: policyId,
502
+ quantity,
503
+ fingerprint,
504
+ },
505
+ });
506
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
507
+ txBuilder.ttl(800000000);
508
+ txBuilder.isTokenTransaction();
509
+ const tx = (await txBuilder.build());
510
+ const txHex = tx.toBroadcastFormat();
511
+ // Verify transaction with correct token amount
512
+ const txParams = {
513
+ recipients: [
514
+ {
515
+ address: receiverAddress,
516
+ amount: quantity, // Token amount, not ADA amount
517
+ },
518
+ ],
519
+ };
520
+ const txPrebuild = { txHex };
521
+ const mockWallet = { coinSpecific: () => ({ baseAddress: senderAddress }) };
522
+ const isVerified = await adaToken.verifyTransaction({ txParams, txPrebuild, wallet: mockWallet });
523
+ isVerified.should.equal(true);
524
+ });
525
+ it('should fail to verify a token transaction with incorrect token amount', async () => {
526
+ const quantity = '20';
527
+ const totalInput = 20000000;
528
+ const totalAssetList = {
529
+ [fingerprint]: {
530
+ quantity: '100',
531
+ policy_id: policyId,
532
+ asset_name: asciiEncodedName,
533
+ },
534
+ };
535
+ const txBuilder = factory.getTransferBuilder();
536
+ txBuilder.input({
537
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
538
+ transaction_index: 1,
539
+ });
540
+ txBuilder.output({
541
+ address: receiverAddress,
542
+ amount: '0',
543
+ multiAssets: {
544
+ asset_name: asciiEncodedName,
545
+ policy_id: policyId,
546
+ quantity,
547
+ fingerprint,
548
+ },
549
+ });
550
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
551
+ txBuilder.ttl(800000000);
552
+ txBuilder.isTokenTransaction();
553
+ const tx = (await txBuilder.build());
554
+ const txHex = tx.toBroadcastFormat();
555
+ // Verify transaction with WRONG token amount (should fail)
556
+ const txParams = {
557
+ recipients: [
558
+ {
559
+ address: receiverAddress,
560
+ amount: '999', // Wrong amount
561
+ },
562
+ ],
563
+ };
564
+ const txPrebuild = { txHex };
565
+ const mockWallet = { coinSpecific: () => ({ baseAddress: senderAddress }) };
566
+ await adaToken
567
+ .verifyTransaction({ txParams, txPrebuild, wallet: mockWallet })
568
+ .should.be.rejectedWith('cannot find recipient in expected output');
569
+ });
570
+ it('should fail to verify when address does not match', async () => {
571
+ const quantity = '20';
572
+ const totalInput = 20000000;
573
+ const totalAssetList = {
574
+ [fingerprint]: {
575
+ quantity: '100',
576
+ policy_id: policyId,
577
+ asset_name: asciiEncodedName,
578
+ },
579
+ };
580
+ const txBuilder = factory.getTransferBuilder();
581
+ txBuilder.input({
582
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
583
+ transaction_index: 1,
584
+ });
585
+ txBuilder.output({
586
+ address: receiverAddress,
587
+ amount: '0',
588
+ multiAssets: {
589
+ asset_name: asciiEncodedName,
590
+ policy_id: policyId,
591
+ quantity,
592
+ fingerprint,
593
+ },
594
+ });
595
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
596
+ txBuilder.ttl(800000000);
597
+ txBuilder.isTokenTransaction();
598
+ const tx = (await txBuilder.build());
599
+ const txHex = tx.toBroadcastFormat();
600
+ // Verify with wrong address (should fail)
601
+ const txParams = {
602
+ recipients: [
603
+ {
604
+ address: 'addr_test1qqa86e3d7lfpwu0k2rhjz76ecmfxdr74s9kf9yfcp5hj5vmnh6xccjcclrk8jtaw9jgeuy99p2n8smtdpylmy45qjjfsfmp3g6',
605
+ amount: quantity,
606
+ },
607
+ ],
608
+ };
609
+ const txPrebuild = { txHex };
610
+ const mockWallet = { coinSpecific: () => ({ baseAddress: senderAddress }) };
611
+ await adaToken
612
+ .verifyTransaction({ txParams, txPrebuild, wallet: mockWallet })
613
+ .should.be.rejectedWith('cannot find recipient in expected output');
614
+ });
615
+ it('should verify transaction when policyId has concatenated assetName (crypto compare format)', async () => {
616
+ // This tests the case where policyId in tokenConfig contains policyId + asciiEncodedAssetName
617
+ // which is consistent with crypto compare format
618
+ const concatenatedPolicyId = policyId + asciiEncodedName; // e.g., 'e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed725741544552'
619
+ const tokenConfigWithConcatenatedPolicyId = {
620
+ type: 'tada:water',
621
+ coin: 'tada',
622
+ network: 'Testnet',
623
+ name: 'WATER',
624
+ decimalPlaces: 0,
625
+ policyId: concatenatedPolicyId, // policyId + assetName hex
626
+ assetName: name, // ASCII name 'WATER' (not hex encoded)
627
+ contractAddress: `${policyId}:${asciiEncodedName}`,
628
+ };
629
+ const adaTokenWithConcatenatedPolicyId = new src_1.AdaToken(bitgo, tokenConfigWithConcatenatedPolicyId);
630
+ const quantity = '20';
631
+ const totalInput = 20000000;
632
+ const totalAssetList = {
633
+ [fingerprint]: {
634
+ quantity: '100',
635
+ policy_id: policyId,
636
+ asset_name: asciiEncodedName,
637
+ },
638
+ };
639
+ const txBuilder = factory.getTransferBuilder();
640
+ txBuilder.input({
641
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
642
+ transaction_index: 1,
643
+ });
644
+ txBuilder.output({
645
+ address: receiverAddress,
646
+ amount: '0',
647
+ multiAssets: {
648
+ asset_name: asciiEncodedName,
649
+ policy_id: policyId,
650
+ quantity,
651
+ fingerprint,
652
+ },
653
+ });
654
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
655
+ txBuilder.ttl(800000000);
656
+ txBuilder.isTokenTransaction();
657
+ const tx = (await txBuilder.build());
658
+ const txHex = tx.toBroadcastFormat();
659
+ // Verify transaction - the verifyTransaction should strip the assetName from policyId
660
+ const txParams = {
661
+ recipients: [
662
+ {
663
+ address: receiverAddress,
664
+ amount: quantity,
665
+ },
666
+ ],
667
+ };
668
+ const txPrebuild = { txHex };
669
+ const mockWallet = { coinSpecific: () => ({ baseAddress: senderAddress }) };
670
+ const isVerified = await adaTokenWithConcatenatedPolicyId.verifyTransaction({
671
+ txParams,
672
+ txPrebuild,
673
+ wallet: mockWallet,
674
+ });
675
+ isVerified.should.equal(true);
676
+ });
677
+ it('should verify transaction with policyId that does not have concatenated assetName', async () => {
678
+ // This tests the case where policyId is just the 28-byte policy ID (no assetName appended)
679
+ const tokenConfigWithPlainPolicyId = {
680
+ type: 'tada:water',
681
+ coin: 'tada',
682
+ network: 'Testnet',
683
+ name: 'WATER',
684
+ decimalPlaces: 0,
685
+ policyId: policyId, // Just the policy ID without assetName
686
+ assetName: name, // ASCII name 'WATER'
687
+ contractAddress: `${policyId}:${asciiEncodedName}`,
688
+ };
689
+ const adaTokenWithPlainPolicyId = new src_1.AdaToken(bitgo, tokenConfigWithPlainPolicyId);
690
+ const quantity = '20';
691
+ const totalInput = 20000000;
692
+ const totalAssetList = {
693
+ [fingerprint]: {
694
+ quantity: '100',
695
+ policy_id: policyId,
696
+ asset_name: asciiEncodedName,
697
+ },
698
+ };
699
+ const txBuilder = factory.getTransferBuilder();
700
+ txBuilder.input({
701
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
702
+ transaction_index: 1,
703
+ });
704
+ txBuilder.output({
705
+ address: receiverAddress,
706
+ amount: '0',
707
+ multiAssets: {
708
+ asset_name: asciiEncodedName,
709
+ policy_id: policyId,
710
+ quantity,
711
+ fingerprint,
712
+ },
713
+ });
714
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
715
+ txBuilder.ttl(800000000);
716
+ txBuilder.isTokenTransaction();
717
+ const tx = (await txBuilder.build());
718
+ const txHex = tx.toBroadcastFormat();
719
+ // Verify transaction - should work with plain policyId as well
720
+ const txParams = {
721
+ recipients: [
722
+ {
723
+ address: receiverAddress,
724
+ amount: quantity,
725
+ },
726
+ ],
727
+ };
728
+ const txPrebuild = { txHex };
729
+ const mockWallet = { coinSpecific: () => ({ baseAddress: senderAddress }) };
730
+ const isVerified = await adaTokenWithPlainPolicyId.verifyTransaction({
731
+ txParams,
732
+ txPrebuild,
733
+ wallet: mockWallet,
734
+ });
735
+ isVerified.should.equal(true);
736
+ });
737
+ it('should verify token consolidation transaction when all outputs go to base address', async () => {
738
+ const quantity = '100';
739
+ const totalInput = 20000000;
740
+ const totalAssetList = {
741
+ [fingerprint]: {
742
+ quantity: '100',
743
+ policy_id: policyId,
744
+ asset_name: asciiEncodedName,
745
+ },
746
+ };
747
+ // Build a consolidation transaction - all outputs go to sender (base) address
748
+ const txBuilder = factory.getTransferBuilder();
749
+ txBuilder.input({
750
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
751
+ transaction_index: 1,
752
+ });
753
+ // For consolidation, tokens go back to the sender's base address
754
+ txBuilder.output({
755
+ address: senderAddress,
756
+ amount: '0',
757
+ multiAssets: {
758
+ asset_name: asciiEncodedName,
759
+ policy_id: policyId,
760
+ quantity,
761
+ fingerprint,
762
+ },
763
+ });
764
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
765
+ txBuilder.ttl(800000000);
766
+ txBuilder.isTokenTransaction();
767
+ const tx = (await txBuilder.build());
768
+ const txHex = tx.toBroadcastFormat();
769
+ // Mock wallet with coinSpecific returning base address
770
+ const mockWallet = {
771
+ coinSpecific: () => ({
772
+ baseAddress: senderAddress,
773
+ }),
774
+ };
775
+ // Verify consolidation transaction - no recipients, but consolidationToBaseAddress is true
776
+ const txParams = {
777
+ recipients: undefined,
778
+ };
779
+ const txPrebuild = { txHex };
780
+ const verification = { consolidationToBaseAddress: true };
781
+ const isVerified = await adaToken.verifyTransaction({
782
+ txParams,
783
+ txPrebuild,
784
+ verification,
785
+ wallet: mockWallet,
786
+ });
787
+ isVerified.should.equal(true);
788
+ });
789
+ it('should fail token consolidation when output address does not match base address', async () => {
790
+ const quantity = '100';
791
+ const totalInput = 20000000;
792
+ const totalAssetList = {
793
+ [fingerprint]: {
794
+ quantity: '100',
795
+ policy_id: policyId,
796
+ asset_name: asciiEncodedName,
797
+ },
798
+ };
799
+ // Build a transaction with output to receiver (not base address)
800
+ const txBuilder = factory.getTransferBuilder();
801
+ txBuilder.input({
802
+ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21',
803
+ transaction_index: 1,
804
+ });
805
+ txBuilder.output({
806
+ address: receiverAddress, // Output goes to receiver, not base address
807
+ amount: '0',
808
+ multiAssets: {
809
+ asset_name: asciiEncodedName,
810
+ policy_id: policyId,
811
+ quantity,
812
+ fingerprint,
813
+ },
814
+ });
815
+ txBuilder.changeAddress(senderAddress, totalInput.toString(), totalAssetList);
816
+ txBuilder.ttl(800000000);
817
+ txBuilder.isTokenTransaction();
818
+ const tx = (await txBuilder.build());
819
+ const txHex = tx.toBroadcastFormat();
820
+ // Mock wallet with different base address
821
+ const mockWallet = {
822
+ coinSpecific: () => ({
823
+ baseAddress: senderAddress, // Base address is sender, but output goes to receiver
824
+ }),
825
+ };
826
+ const txParams = {
827
+ recipients: undefined,
828
+ };
829
+ const txPrebuild = { txHex };
830
+ const verification = { consolidationToBaseAddress: true };
831
+ await adaToken
832
+ .verifyTransaction({
833
+ txParams,
834
+ txPrebuild,
835
+ verification,
836
+ wallet: mockWallet,
837
+ })
838
+ .should.be.rejectedWith('tx outputs does not match with expected address');
839
+ });
840
+ });
841
+ });
842
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5XaXRoZHJhd2FsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdGVzdC91bml0L3Rva2VuV2l0aGRyYXdhbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG9EQUE0QjtBQUM1QixtREFBdUQ7QUFDdkQsdURBQXlDO0FBQ3pDLG1DQUFnRTtBQUNoRSxpREFBNEM7QUFDNUMsc0ZBQXdFO0FBRXhFLG1EQUErRDtBQUMvRCxpREFBK0M7QUFFL0MsUUFBUSxDQUFDLHNCQUFzQixFQUFFLEtBQUssSUFBSSxFQUFFO0lBQzFDLE1BQU0sT0FBTyxHQUFHLElBQUksK0JBQXlCLENBQUMsZUFBSyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBRWpFLE1BQU0sZUFBZSxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQztJQUM5RCxNQUFNLGFBQWEsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUM7SUFFNUQsTUFBTSxRQUFRLEdBQUcsMERBQTBELENBQUM7SUFDNUUsTUFBTSxnQkFBZ0IsR0FBRyxXQUFXLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNuRSxNQUFNLFNBQVMsR0FBRyxZQUFZLENBQUM7SUFDL0IsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDO0lBQ3JCLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3BFLE1BQU0sV0FBVyxHQUFHLDhDQUE4QyxDQUFDO0lBRW5FLE1BQU0sbUJBQW1CLEdBQUcsMERBQTBELENBQUM7SUFDdkYsTUFBTSwyQkFBMkIsR0FBRyxXQUFXLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIs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LEVBQUUsZ0JBQWdCO29CQUM1QixTQUFTLEVBQUUsUUFBUTtvQkFDbkIsUUFBUTtvQkFDUixXQUFXO2lCQUNaO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsU0FBUyxDQUFDLGFBQWEsQ0FBQyxhQUFhLEVBQUUsVUFBVSxDQUFDLFFBQVEsRUFBRSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQzlFLFNBQVMsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDekIsU0FBUyxDQUFDLGtCQUFrQixFQUFFLENBQUM7WUFDL0IsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBZ0IsQ0FBQztZQUNwRCxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUVyQywwQ0FBMEM7WUFDMUMsTUFBTSxVQUFVLEdBQUc7Z0JBQ2pCLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO29CQUNuQixXQUFXLEVBQUUsYUFBYSxFQUFFLHNEQUFzRDtpQkFDbkYsQ0FBQzthQUNILENBQUM7WUFFRixNQUFNLFFBQVEsR0FBRztnQkFDZixVQUFVLEVBQUUsU0FBUzthQUN0QixDQUFDO1lBRUYsTUFBTSxVQUFVLEdBQUcsRUFBRSxLQUFLLEVBQUUsQ0FBQztZQUM3QixNQUFNLFlBQVksR0FBRyxFQUFFLDBCQUEwQixFQUFFLElBQUksRUFBRSxDQUFDO1lBRTFELE1BQU0sUUFBUTtpQkFDWCxpQkFBaUIsQ0FBQztnQkFDakIsUUFBUTtnQkFDUixVQUFVO2dCQUNWLFlBQVk7Z0JBQ1osTUFBTSxFQUFFLFVBQWlCO2FBQzFCLENBQUM7aUJBQ0QsTUFBTSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsaURBQWlELENBQUMsQ0FBQztRQUMvRSxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc2hvdWxkIGZyb20gJ3Nob3VsZCc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvblR5cGUgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstY29yZSc7XG5pbXBvcnQgKiBhcyB0ZXN0RGF0YSBmcm9tICcuLi9yZXNvdXJjZXMnO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeSwgQWRhVG9rZW4gfSBmcm9tICcuLi8uLi9zcmMnO1xuaW1wb3J0IHsgY29pbnMgfSBmcm9tICdAYml0Z28tYmV0YS9zdGF0aWNzJztcbmltcG9ydCAqIGFzIENhcmRhbm9XYXNtIGZyb20gJ0BlbXVyZ28vY2FyZGFuby1zZXJpYWxpemF0aW9uLWxpYi1ub2RlanMnO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb24gfSBmcm9tICcuLi8uLi9zcmMvbGliL3RyYW5zYWN0aW9uJztcbmltcG9ydCB7IFRlc3RCaXRHbywgVGVzdEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLXRlc3QnO1xuaW1wb3J0IHsgQml0R29BUEkgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstYXBpJztcblxuZGVzY3JpYmUoJ0FEQSBUb2tlbiBPcGVyYXRpb25zJywgYXN5bmMgKCkgPT4ge1xuICBjb25zdCBmYWN0b3J5ID0gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KCd0YWRhJykpO1xuXG4gIGNvbnN0IHJlY2VpdmVyQWRkcmVzcyA9IHRlc3REYXRhLnJhd1R4Lm91dHB1dEFkZHJlc3MyLmFkZHJlc3M7XG4gIGNvbnN0IHNlbmRlckFkZHJlc3MgPSB0ZXN0RGF0YS5yYXdUeC5vdXRwdXRBZGRyZXNzMS5hZGRyZXNzO1xuXG4gIGNvbnN0IHBvbGljeUlkID0gJ2UxNmMyZGM4YWU5MzdlOGQzNzkwYzdmZDcxNjhkN2I5OTQ2MjFiYTE0Y2ExMTQxNWYzOWZlZDcyJztcbiAgY29uc3QgcG9saWN5U2NyaXB0SGFzaCA9IENhcmRhbm9XYXNtLlNjcmlwdEhhc2guZnJvbV9oZXgocG9saWN5SWQpO1xuICBjb25zdCBhc3NldE5hbWUgPSAndGFkYTp3YXRlcic7XG4gIGNvbnN0IG5hbWUgPSAnV0FURVInO1xuICBjb25zdCBhc2NpaUVuY29kZWROYW1lID0gQnVmZmVyLmZyb20obmFtZSwgJ2FzY2lpJykudG9TdHJpbmcoJ2hleCcpO1xuICBjb25zdCBmaW5nZXJwcmludCA9ICdhc3NldDFuNjl4ZjYwZDA3NjB4dm44djJmZmQ1ZnJ2c20wY2wycjhoZmpmNic7XG5cbiAgY29uc3QgdW5zdXBwb3J0ZWRQb2xpY3lJZCA9ICcyNzljOTA5ZjM0OGU1MzNkYTU4MDg4OThmODdmOWExNGJiMmMzZGZiYmFjY2NkNjMxZDkyN2EzZic7XG4gIGNvbnN0IHVuc3VwcG9ydGVkUG9saWN5U2NyaXB0SGFzaCA9IENhcmRhbm9XYXNtLlNjcmlwdEhhc2guZnJvbV9oZXgodW5zdXBwb3J0ZWRQb2xpY3lJZCk7XG4gIGNvbnN0IHVuc3VwcG9ydGVkTmFtZSA9ICdCSVRHTyc7XG4gIGNvbnN0IHVuc3VwcG9ydGVkQXNjaWlFbmNvZGVkTmFtZSA9IEJ1ZmZlci5mcm9tKHVuc3VwcG9ydGVkTmFtZSwgJ2FzY2lpJykudG9TdHJpbmcoJ2hleCcpO1xuICBjb25zdCB1bnN1cHBvcnRlZEZpbmdlcnByaW50ID0gJ2Fzc2V0MW04aDBnazdmNng1ajVxZzB4NW00cTVmNWo1cWcweDVtNHE1ZjVqJztcblxuICBpdChgc2hvdWxkIGJ1aWxkIGEgdHJhbnNhY3Rpb24gd2l0aCB0b2tlbiAke2Fzc2V0TmFtZX0gLSBhZGEgKyAke2Fzc2V0TmFtZX1gLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgIGNvbnN0IHRvdGFsSW5wdXQgPSAyMDAwMDAwMDtcbiAgICBjb25zdCB0b3RhbEFzc2V0TGlzdCA9IHtcbiAgICAgIFtmaW5nZXJwcmludF06IHtcbiAgICAgICAgcXVhbnRpdHk6ICcxMDAnLFxuICAgICAgICBwb2xpY3lfaWQ6IHBvbGljeUlkLFxuICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IGV4cGVjdGVkQ2hhbmdlQWRhID0gKFxuICAgICAgdG90YWxJbnB1dCAtXG4gICAgICAxNTAwMDAwIC8qIG1pbiBhZGEgZm9yIGNoYW5nZSB0b2tlbiB1dHhvICovIC1cbiAgICAgIDE1MDAwMDAgLyogbWluIGFkYSBmb3IgcmVjaXBpZW50IHRva2VuIHV0eG8qLyAtXG4gICAgICAxNzM1OTdcbiAgICApIC8qIGZlZSAqL1xuICAgICAgLnRvU3RyaW5nKCk7XG4gICAgY29uc3QgZXhwZWN0ZWRDaGFuZ2VUb2tlbiA9ICc4MCc7XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldFRyYW5zZmVyQnVpbGRlcigpO1xuICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICB0cmFuc2FjdGlvbl9pZDogJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjEnLFxuICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDEsXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIub3V0cHV0KHtcbiAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgIGFtb3VudDogJzAnLCAvLyBTZXQgQURBIGFtb3VudCB0byAwIGZvciB0b2tlbiB0cmFuc2ZlciAobWluIEFEQSBpcyBoYW5kbGVkIGluIHNkayBidWlsZClcbiAgICAgIG11bHRpQXNzZXRzOiB7XG4gICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgIHF1YW50aXR5LFxuICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICB0eEJ1aWxkZXIudHRsKDgwMDAwMDAwMCk7XG4gICAgdHhCdWlsZGVyLmlzVG9rZW5UcmFuc2FjdGlvbigpO1xuICAgIGNvbnN0IHR4ID0gKGF3YWl0IHR4QnVpbGRlci5idWlsZCgpKSBhcyBUcmFuc2FjdGlvbjtcblxuICAgIHNob3VsZC5lcXVhbCh0eC50eXBlLCBUcmFuc2FjdGlvblR5cGUuU2VuZCk7XG4gICAgY29uc3QgdHhEYXRhID0gdHgudG9Kc29uKCk7XG5cbiAgICAvLyBDaGVjayBvdXRwdXRzIChzaG91bGQgaW5jbHVkZSBtdWx0aS1hc3NldCBhbmQgcmVndWxhciBjaGFuZ2UpXG4gICAgdHhEYXRhLm91dHB1dHMubGVuZ3RoLnNob3VsZC5lcXVhbCgzKTtcbiAgICB0eERhdGEuaW5wdXRzLmxlbmd0aC5zaG91bGQuZXF1YWwoMSk7XG5cbiAgICAvLyBPbmUgb3V0cHV0IHNob3VsZCBoYXZlIHRoZSBtdWx0aS1hc3NldCBjaGFuZ2UgYW5kIHRoZSBvdGhlciBmb3IgdGhlIHRyYW5zZmVyXG4gICAgY29uc3QgYXNzZXRPdXRwdXQgPSB0eERhdGEub3V0cHV0cy5maWx0ZXIoKG91dHB1dCkgPT4gb3V0cHV0Lm11bHRpQXNzZXRzICE9PSB1bmRlZmluZWQpO1xuICAgIGFzc2V0T3V0cHV0IS5sZW5ndGguc2hvdWxkLmVxdWFsKDIpO1xuXG4gICAgLy8gVmVyaWZ5IGlucHV0cyBhbmQgb3V0cHV0c1xuICAgIGNvbnN0IGlucHV0ID0gdHhEYXRhLmlucHV0c1swXTtcbiAgICBpbnB1dC50cmFuc2FjdGlvbl9pZC5zaG91bGQuZXF1YWwoJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjEnKTtcbiAgICBpbnB1dC50cmFuc2FjdGlvbl9pbmRleC5zaG91bGQuZXF1YWwoMSk7XG5cbiAgICAvLyBWYWxpZGF0ZSByZWNlaXZlciBvdXRwdXRcbiAgICBjb25zdCByZWNlaXZlck91dHB1dCA9IHR4RGF0YS5vdXRwdXRzLmZpbHRlcigob3V0cHV0KSA9PiBvdXRwdXQuYWRkcmVzcyA9PT0gcmVjZWl2ZXJBZGRyZXNzKTtcbiAgICByZWNlaXZlck91dHB1dC5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuICAgIHJlY2VpdmVyT3V0cHV0WzBdLmFtb3VudC5zaG91bGQuZXF1YWwoJzE1MDAwMDAnKTsgLy8gTWluaW11bSBBREEgZm9yIGFzc2V0IG91dHB1dFxuICAgIChyZWNlaXZlck91dHB1dFswXS5tdWx0aUFzc2V0cyEgYXMgQ2FyZGFub1dhc20uTXVsdGlBc3NldClcbiAgICAgIC5nZXRfYXNzZXQocG9saWN5U2NyaXB0SGFzaCwgQ2FyZGFub1dhc20uQXNzZXROYW1lLm5ldyhCdWZmZXIuZnJvbShhc2NpaUVuY29kZWROYW1lLCAnaGV4JykpKVxuICAgICAgLnRvX3N0cigpXG4gICAgICAuc2hvdWxkLmVxdWFsKHF1YW50aXR5KTtcblxuICAgIC8vIFZhbGlkYXRlIGNoYW5nZSBvdXRwdXRzIChvbmUgd2l0aCBhc3NldCBhbmQgb25lIHdpdGhvdXQpXG4gICAgY29uc3QgY2hhbmdlT3V0cHV0ID0gdHhEYXRhLm91dHB1dHMuZmlsdGVyKChvdXRwdXQpID0+IG91dHB1dC5hZGRyZXNzID09PSBzZW5kZXJBZGRyZXNzKTtcbiAgICBjaGFuZ2VPdXRwdXQubGVuZ3RoLnNob3VsZC5lcXVhbCgyKTtcbiAgICBjb25zdCBjaGFuZ2VXaXRoQXNzZXQgPSBjaGFuZ2VPdXRwdXQuZmluZCgob3V0cHV0KSA9PiBvdXRwdXQubXVsdGlBc3NldHMgIT09IHVuZGVmaW5lZCk7XG4gICAgc2hvdWxkLmV4aXN0KGNoYW5nZVdpdGhBc3NldCk7XG4gICAgY2hhbmdlV2l0aEFzc2V0IS5hbW91bnQuc2hvdWxkLmVxdWFsKCcxNTAwMDAwJyk7IC8vIE1pbmltdW0gQURBIGZvciBhc3NldCBvdXRwdXRcbiAgICAoY2hhbmdlV2l0aEFzc2V0IS5tdWx0aUFzc2V0cyEgYXMgQ2FyZGFub1dhc20uTXVsdGlBc3NldClcbiAgICAgIC5nZXRfYXNzZXQocG9saWN5U2NyaXB0SGFzaCwgQ2FyZGFub1dhc20uQXNzZXROYW1lLm5ldyhCdWZmZXIuZnJvbShhc2NpaUVuY29kZWROYW1lLCAnaGV4JykpKVxuICAgICAgLnRvX3N0cigpXG4gICAgICAuc2hvdWxkLmVxdWFsKGV4cGVjdGVkQ2hhbmdlVG9rZW4pO1xuXG4gICAgY29uc3QgY2hhbmdlV2l0aG91dEFzc2V0ID0gY2hhbmdlT3V0cHV0LmZpbmQoKG91dHB1dCkgPT4gb3V0cHV0Lm11bHRpQXNzZXRzID09PSB1bmRlZmluZWQpO1xuICAgIHNob3VsZC5leGlzdChjaGFuZ2VXaXRob3V0QXNzZXQpO1xuICAgIGNoYW5nZVdpdGhvdXRBc3NldCEuYW1vdW50LnNob3VsZC5lcXVhbChleHBlY3RlZENoYW5nZUFkYSk7IC8vIFJlbWFpbmluZyBBREEgYWZ0ZXIgZmVlcyBhbmQgbWluIEFEQXNcbiAgfSk7XG5cbiAgaXQoYHNob3VsZCBidWlsZCBhIHRyYW5zYWN0aW9uIHdpdGggdG9rZW4gJHthc3NldE5hbWV9IC0gYWRhICsgJHthc3NldE5hbWV9ICsgdW5zdXBwb3J0ZWQgdG9rZW5gLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgIGNvbnN0IHRvdGFsSW5wdXQgPSAyMDAwMDAwMDtcbiAgICBjb25zdCB0b3RhbEFzc2V0TGlzdCA9IHtcbiAgICAgIFtmaW5nZXJwcmludF06IHtcbiAgICAgICAgcXVhbnRpdHk6ICcxMDAnLFxuICAgICAgICBwb2xpY3lfaWQ6IHBvbGljeUlkLFxuICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgfSxcbiAgICAgIFt1bnN1cHBvcnRlZEZpbmdlcnByaW50XToge1xuICAgICAgICBxdWFudGl0eTogJzEwMDAwJyxcbiAgICAgICAgcG9saWN5X2lkOiB1bnN1cHBvcnRlZFBvbGljeUlkLFxuICAgICAgICBhc3NldF9uYW1lOiB1bnN1cHBvcnRlZEFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICB9LFxuICAgIH07XG4gICAgY29uc3QgZXhwZWN0ZWRDaGFuZ2VBZGEgPSAoXG4gICAgICB0b3RhbElucHV0IC1cbiAgICAgIDE1MDAwMDAgLyogbWluIGFkYSBmb3IgY2hhbmdlIHRva2VuIHV0eG8gKi8gLVxuICAgICAgMTUwMDAwMCAvKiBtaW4gYWRhIGZvciByZWNpcGllbnQgdG9rZW4gdXR4byovIC1cbiAgICAgIDE1MDAwMDAgLyogbWluIGFkYSBmb3IgdW5zdXBwb3J0ZWQgdG9rZW4gY2hhbmdlIHV0eG8gKi8gLVxuICAgICAgMTc5ODg5XG4gICAgKSAvKiBmZWUgKi9cbiAgICAgIC50b1N0cmluZygpO1xuICAgIGNvbnN0IGV4cGVjdGVkQ2hhbmdlVG9rZW4gPSAnODAnO1xuXG4gICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRUcmFuc2ZlckJ1aWxkZXIoKTtcbiAgICB0eEJ1aWxkZXIuaW5wdXQoe1xuICAgICAgdHJhbnNhY3Rpb25faWQ6ICczNjc3ZTc1YzdiYTY5OWJmZGM2Y2Q1N2Q0MmYyNDZmODZmNjNhZWZkNzYwMjUwMDZhYzc4MzEzZmFkMmJiYTIxJyxcbiAgICAgIHRyYW5zYWN0aW9uX2luZGV4OiAxLFxuICAgIH0pO1xuICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICB0cmFuc2FjdGlvbl9pZDogJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjInLFxuICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDEsXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIub3V0cHV0KHtcbiAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgIGFtb3VudDogJzAnLCAvLyBTZXQgQURBIGFtb3VudCB0byAwIGZvciB0b2tlbiB0cmFuc2ZlciAobWluIEFEQSBpcyBoYW5kbGVkIGluIHNkayBidWlsZClcbiAgICAgIG11bHRpQXNzZXRzOiB7XG4gICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgIHF1YW50aXR5LFxuICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICB0eEJ1aWxkZXIudHRsKDgwMDAwMDAwMCk7XG4gICAgdHhCdWlsZGVyLmlzVG9rZW5UcmFuc2FjdGlvbigpO1xuICAgIGNvbnN0IHR4ID0gKGF3YWl0IHR4QnVpbGRlci5idWlsZCgpKSBhcyBUcmFuc2FjdGlvbjtcblxuICAgIHNob3VsZC5lcXVhbCh0eC50eXBlLCBUcmFuc2FjdGlvblR5cGUuU2VuZCk7XG4gICAgY29uc3QgdHhEYXRhID0gdHgudG9Kc29uKCk7XG5cbiAgICAvLyBDaGVjayBvdXRwdXRzIChzaG91bGQgaW5jbHVkZSBtdWx0aS1hc3NldCBhbmQgcmVndWxhciBjaGFuZ2UpXG4gICAgdHhEYXRhLm91dHB1dHMubGVuZ3RoLnNob3VsZC5lcXVhbCg0KTtcbiAgICB0eERhdGEuaW5wdXRzLmxlbmd0aC5zaG91bGQuZXF1YWwoMik7XG5cbiAgICAvLyBPbmUgb3V0cHV0IHNob3VsZCBoYXZlIHRoZSBtdWx0aS1hc3NldCBjaGFuZ2UgYW5kIHRoZSBvdGhlciBmb3IgdGhlIHRyYW5zZmVyXG4gICAgY29uc3QgYXNzZXRPdXRwdXQgPSB0eERhdGEub3V0cHV0cy5maWx0ZXIoKG91dHB1dCkgPT4gb3V0cHV0Lm11bHRpQXNzZXRzICE9PSB1bmRlZmluZWQpO1xuICAgIGFzc2V0T3V0cHV0IS5sZW5ndGguc2hvdWxkLmVxdWFsKDMpO1xuXG4gICAgLy8gVmVyaWZ5IGlucHV0cyBhbmQgb3V0cHV0c1xuICAgIHR4RGF0YS5pbnB1dHNbMF0udHJhbnNhY3Rpb25faWQuc2hvdWxkLmVxdWFsKCczNjc3ZTc1YzdiYTY5OWJmZGM2Y2Q1N2Q0MmYyNDZmODZmNjNhZWZkNzYwMjUwMDZhYzc4MzEzZmFkMmJiYTIxJyk7XG4gICAgdHhEYXRhLmlucHV0c1swXS50cmFuc2FjdGlvbl9pbmRleC5zaG91bGQuZXF1YWwoMSk7XG5cbiAgICB0eERhdGEuaW5wdXRzWzFdLnRyYW5zYWN0aW9uX2lkLnNob3VsZC5lcXVhbCgnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMicpO1xuICAgIHR4RGF0YS5pbnB1dHNbMV0udHJhbnNhY3Rpb25faW5kZXguc2hvdWxkLmVxdWFsKDEpO1xuXG4gICAgLy8gVmFsaWRhdGUgcmVjZWl2ZXIgb3V0cHV0XG4gICAgY29uc3QgcmVjZWl2ZXJPdXRwdXQgPSB0eERhdGEub3V0cHV0cy5maWx0ZXIoKG91dHB1dCkgPT4gb3V0cHV0LmFkZHJlc3MgPT09IHJlY2VpdmVyQWRkcmVzcyk7XG4gICAgcmVjZWl2ZXJPdXRwdXQubGVuZ3RoLnNob3VsZC5lcXVhbCgxKTtcbiAgICByZWNlaXZlck91dHB1dFswXS5hbW91bnQuc2hvdWxkLmVxdWFsKCcxNTAwMDAwJyk7IC8vIE1pbmltdW0gQURBIGZvciBhc3NldCBvdXRwdXRcbiAgICAocmVjZWl2ZXJPdXRwdXRbMF0ubXVsdGlBc3NldHMhIGFzIENhcmRhbm9XYXNtLk11bHRpQXNzZXQpXG4gICAgICAuZ2V0X2Fzc2V0KHBvbGljeVNjcmlwdEhhc2gsIENhcmRhbm9XYXNtLkFzc2V0TmFtZS5uZXcoQnVmZmVyLmZyb20oYXNjaWlFbmNvZGVkTmFtZSwgJ2hleCcpKSlcbiAgICAgIC50b19zdHIoKVxuICAgICAgLnNob3VsZC5lcXVhbChxdWFudGl0eSk7XG5cbiAgICAvLyBWYWxpZGF0ZSBjaGFuZ2Ugb3V0cHV0cyAob25lIHdpdGggc3VwcG9ydGVkIHRva2VuLCBvbmUgd2l0aCB1bnN1cHBvcnRlZCB0b2tlbiBhbmQgb25lIGZvciBwdXJlIGFkYSlcbiAgICBjb25zdCBjaGFuZ2VPdXRwdXQgPSB0eERhdGEub3V0cHV0cy5maWx0ZXIoKG91dHB1dCkgPT4gb3V0cHV0LmFkZHJlc3MgPT09IHNlbmRlckFkZHJlc3MpO1xuICAgIGNoYW5nZU91dHB1dC5sZW5ndGguc2hvdWxkLmVxdWFsKDMpO1xuXG4gICAgY29uc3QgY2hhbmdlV2l0aEFzc2V0ID0gY2hhbmdlT3V0cHV0LmZpbHRlcigob3V0cHV0KSA9PiBvdXRwdXQubXVsdGlBc3NldHMgIT09IHVuZGVmaW5lZCk7XG4gICAgY2hhbmdlV2l0aEFzc2V0Lmxlbmd0aC5zaG91bGQuZXF1YWwoMik7XG4gICAgbGV0IHRva2VucyA9IDA7XG4gICAgY2hhbmdlV2l0aEFzc2V0LmZvckVhY2goKG91dHB1dCkgPT4ge1xuICAgICAgb3V0cHV0IS5hbW91bnQuc2hvdWxkLmVxdWFsKCcxNTAwMDAwJyk7IC8vIE1pbmltdW0gQURBIGZvciBhc3NldCBvdXRwdXRcbiAgICAgIGNvbnN0IHN1cHBvcnRlZFRva2VuQ2hhbmdlUXR5ID0gKG91dHB1dCEubXVsdGlBc3NldHMhIGFzIENhcmRhbm9XYXNtLk11bHRpQXNzZXQpXG4gICAgICAgIC5nZXRfYXNzZXQocG9saWN5U2NyaXB0SGFzaCwgQ2FyZGFub1dhc20uQXNzZXROYW1lLm5ldyhCdWZmZXIuZnJvbShhc2NpaUVuY29kZWROYW1lLCAnaGV4JykpKVxuICAgICAgICAudG9fc3RyKCk7XG4gICAgICBjb25zdCB1bnN1cHBvcnRlZFRva2VuQ2hhbmdlUXR5ID0gKG91dHB1dCEubXVsdGlBc3NldHMhIGFzIENhcmRhbm9XYXNtLk11bHRpQXNzZXQpXG4gICAgICAgIC5nZXRfYXNzZXQoXG4gICAgICAgICAgdW5zdXBwb3J0ZWRQb2xpY3lTY3JpcHRIYXNoLFxuICAgICAgICAgIENhcmRhbm9XYXNtLkFzc2V0TmFtZS5uZXcoQnVmZmVyLmZyb20odW5zdXBwb3J0ZWRBc2NpaUVuY29kZWROYW1lLCAnaGV4JykpXG4gICAgICAgIClcbiAgICAgICAgLnRvX3N0cigpO1xuICAgICAgaWYgKHN1cHBvcnRlZFRva2VuQ2hhbmdlUXR5ICE9PSAnMCcpIHtcbiAgICAgICAgc3VwcG9ydGVkVG9rZW5DaGFuZ2VRdHkuc2hvdWxkLmVxdWFsKGV4cGVjdGVkQ2hhbmdlVG9rZW4pO1xuICAgICAgICB0b2tlbnMrKztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHVuc3VwcG9ydGVkVG9rZW5DaGFuZ2VRdHkhLnNob3VsZC5lcXVhbCgnMTAwMDAnKTtcbiAgICAgICAgdG9rZW5zKys7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdG9rZW5zLnNob3VsZC5lcXVhbCgyKTtcblxuICAgIGNvbnN0IGNoYW5nZVdpdGhvdXRBc3NldCA9IGNoYW5nZU91dHB1dC5maW5kKChvdXRwdXQpID0+IG91dHB1dC5tdWx0aUFzc2V0cyA9PT0gdW5kZWZpbmVkKTtcbiAgICBzaG91bGQuZXhpc3QoY2hhbmdlV2l0aG91dEFzc2V0KTtcbiAgICBjaGFuZ2VXaXRob3V0QXNzZXQhLmFtb3VudC5zaG91bGQuZXF1YWwoZXhwZWN0ZWRDaGFuZ2VBZGEpOyAvLyBSZW1haW5pbmcgQURBIGFmdGVyIGZlZXMgYW5kIG1pbiBBREFzXG4gIH0pO1xuXG4gIGl0KGBzaG91bGQgZmFpbCB0byBidWlsZCBhIHRyYW5zYWN0aW9uIHdpdGggJHthc3NldE5hbWV9IHRva2VuIGFuZCBpbnN1ZmZpY2llbnQgbWluaW11bSBBREFgLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgIGNvbnN0IHRvdGFsSW5wdXQgPSAyMDAwMDAwO1xuICAgIGNvbnN0IHRvdGFsQXNzZXRMaXN0ID0ge1xuICAgICAgW2ZpbmdlcnByaW50XToge1xuICAgICAgICBxdWFudGl0eTogJzEwMCcsXG4gICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICB9LFxuICAgIH07XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldFRyYW5zZmVyQnVpbGRlcigpO1xuICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICB0cmFuc2FjdGlvbl9pZDogJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjEnLFxuICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDEsXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIub3V0cHV0KHtcbiAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgIGFtb3VudDogJzAnLCAvLyBTZXQgQURBIGFtb3VudCB0byAwIGZvciB0b2tlbiB0cmFuc2ZlciAobWluIEFEQSBpcyBoYW5kbGVkIGluIHNkayBidWlsZClcbiAgICAgIG11bHRpQXNzZXRzOiB7XG4gICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgIHF1YW50aXR5LFxuICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICB0eEJ1aWxkZXIudHRsKDgwMDAwMDAwMCk7XG4gICAgdHhCdWlsZGVyLmlzVG9rZW5UcmFuc2FjdGlvbigpO1xuXG4gICAgYXdhaXQgdHhCdWlsZGVyXG4gICAgICAuYnVpbGQoKVxuICAgICAgLnNob3VsZC5yZWplY3RlZFdpdGgoXG4gICAgICAgICdJbnN1ZmZpY2llbnQgZnVuZHM6IG5lZWQgYSBtaW5pbXVtIG9mIDE1MDAwMDAgbG92ZWxhY2UgcGVyIG91dHB1dCB0byBjb25zdHJ1Y3QgdG9rZW4gdHJhbnNhY3Rpb25zJ1xuICAgICAgKTtcbiAgfSk7XG5cbiAgaXQoYHNob3VsZCBmYWlsIHRvIGJ1aWxkIGEgdHJhbnNhY3Rpb24gd2l0aCAke2Fzc2V0TmFtZX0gYW5kIGluc3VmZmljaWVudCB0b2tlbiBxdHlgLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgIGNvbnN0IHRvdGFsSW5wdXQgPSAyMDAwMDAwMDtcbiAgICBjb25zdCB0b3RhbEFzc2V0TGlzdCA9IHtcbiAgICAgIFtmaW5nZXJwcmludF06IHtcbiAgICAgICAgcXVhbnRpdHk6ICc1JyxcbiAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0VHJhbnNmZXJCdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLmlucHV0KHtcbiAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMScsXG4gICAgICB0cmFuc2FjdGlvbl9pbmRleDogMSxcbiAgICB9KTtcblxuICAgIHR4QnVpbGRlci5vdXRwdXQoe1xuICAgICAgYWRkcmVzczogcmVjZWl2ZXJBZGRyZXNzLFxuICAgICAgYW1vdW50OiAnMCcsIC8vIFNldCBBREEgYW1vdW50IHRvIDAgZm9yIHRva2VuIHRyYW5zZmVyIChtaW4gQURBIGlzIGhhbmRsZWQgaW4gc2RrIGJ1aWxkKVxuICAgICAgbXVsdGlBc3NldHM6IHtcbiAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgcXVhbnRpdHksXG4gICAgICAgIGZpbmdlcnByaW50LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHR4QnVpbGRlci5jaGFuZ2VBZGRyZXNzKHNlbmRlckFkZHJlc3MsIHRvdGFsSW5wdXQudG9TdHJpbmcoKSwgdG90YWxBc3NldExpc3QpO1xuICAgIHR4QnVpbGRlci50dGwoODAwMDAwMDAwKTtcbiAgICB0eEJ1aWxkZXIuaXNUb2tlblRyYW5zYWN0aW9uKCk7XG5cbiAgICBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKS5zaG91bGQucmVqZWN0ZWRXaXRoKCdJbnN1ZmZpY2llbnQgcXR5OiBub3QgZW5vdWdoIHRva2VuIHF0eSB0byBjb3ZlciByZWNlaXZlciBvdXRwdXQnKTtcbiAgfSk7XG5cbiAgaXQoYHNob3VsZCBidWlsZCBhIHRyYW5zYWN0aW9uIHdpdGggJHthc3NldE5hbWV9IHdoZW4gdGhlIHRva2VuIHF0eSBpcyBleGFjdGx5IHRoZSBxdHkgaW4gd2l0aGRyYXdhbGAsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBxdWFudGl0eSA9ICcxJztcbiAgICBjb25zdCB0b3RhbElucHV0ID0gMjAwMDAwMDA7XG4gICAgY29uc3QgdG90YWxBc3NldExpc3QgPSB7XG4gICAgICBbZmluZ2VycHJpbnRdOiB7XG4gICAgICAgIHF1YW50aXR5OiAnMScsXG4gICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICB9LFxuICAgIH07XG5cbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldFRyYW5zZmVyQnVpbGRlcigpO1xuICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICB0cmFuc2FjdGlvbl9pZDogJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjEnLFxuICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDEsXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIub3V0cHV0KHtcbiAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgIGFtb3VudDogJzAnLCAvLyBTZXQgQURBIGFtb3VudCB0byAwIGZvciB0b2tlbiB0cmFuc2ZlciAobWluIEFEQSBpcyBoYW5kbGVkIGluIHNkayBidWlsZClcbiAgICAgIG11bHRpQXNzZXRzOiB7XG4gICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgIHF1YW50aXR5LFxuICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICB0eEJ1aWxkZXIudHRsKDgwMDAwMDAwMCk7XG4gICAgdHhCdWlsZGVyLmlzVG9rZW5UcmFuc2FjdGlvbigpO1xuXG4gICAgYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkuc2hvdWxkLm5vdC5iZS5yZWplY3RlZCgpO1xuICB9KTtcblxuICBpdChgc2hvdWxkIGJ1aWxkIGEgc3BvbnNvcmVkIHRva2VuIHRyYW5zYWN0aW9uIHdoZXJlIGZlZSBhZGRyZXNzIHNwb25zb3JzIG1pbiBBREEgZm9yIHJlY2VpdmVyYCwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGZlZUFkZHJlc3MgPVxuICAgICAgJ2FkZHJfdGVzdDFxejJmeHYydW15aHR0a3h5eHA4eDBkbHBkdDNrNmN3bmc1cHhqM2poc3lkemVyM2pjdTVkOHBzN3pleDJrMnh0M3VxeGdqcW5uajgzd3M4bGhybjY0OGpqeHR3cTJ5dGpxcCc7XG4gICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgIGNvbnN0IHNlbmRlcklucHV0QmFsYW5jZSA9IDUwMDAwMDA7XG4gICAgY29uc3QgZmVlQWRkcmVzc0lucHV0QmFsYW5jZSA9IDIwMDAwMDAwOyAvLyBGZWUgYWRkcmVzcyBoYXMgZW5vdWdoIEFEQSB0byBzcG9uc29yXG4gICAgY29uc3QgdG90YWxBc3NldExpc3QgPSB7XG4gICAgICBbZmluZ2VycHJpbnRdOiB7XG4gICAgICAgIHF1YW50aXR5OiAnMTAwJyxcbiAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0VHJhbnNmZXJCdWlsZGVyKCk7XG4gICAgLy8gU2VuZGVyIGlucHV0IChoYXMgdG9rZW5zKVxuICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICB0cmFuc2FjdGlvbl9pZDogJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjEnLFxuICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDEsXG4gICAgfSk7XG4gICAgLy8gRmVlIGFkZHJlc3MgaW5wdXQgKHNwb25zb3JzIGZlZXMgYW5kIG1pbiBBREEpXG4gICAgdHhCdWlsZGVyLmlucHV0KHtcbiAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMicsXG4gICAgICB0cmFuc2FjdGlvbl9pbmRleDogMCxcbiAgICB9KTtcblxuICAgIHR4QnVpbGRlci5vdXRwdXQoe1xuICAgICAgYWRkcmVzczogcmVjZWl2ZXJBZGRyZXNzLFxuICAgICAgYW1vdW50OiAnMCcsIC8vIFNldCBBREEgYW1vdW50IHRvIDAgZm9yIHRva2VuIHRyYW5zZmVyIChtaW4gQURBIGlzIGhhbmRsZWQgYnkgZmVlIGFkZHJlc3MpXG4gICAgICBtdWx0aUFzc2V0czoge1xuICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgICBwb2xpY3lfaWQ6IHBvbGljeUlkLFxuICAgICAgICBxdWFudGl0eSxcbiAgICAgICAgZmluZ2VycHJpbnQsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgdHhCdWlsZGVyLmNoYW5nZUFkZHJlc3Moc2VuZGVyQWRkcmVzcywgc2VuZGVySW5wdXRCYWxhbmNlLnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICB0eEJ1aWxkZXIuc3BvbnNvcnNoaXBJbmZvKHtcbiAgICAgIGZlZUFkZHJlc3M6IGZlZUFkZHJlc3MsXG4gICAgICBmZWVBZGRyZXNzSW5wdXRCYWxhbmNlOiBmZWVBZGRyZXNzSW5wdXRCYWxhbmNlLnRvU3RyaW5nKCksXG4gICAgfSk7XG4gICAgdHhCdWlsZGVyLnR0bCg4MDAwMDAwMDApO1xuICAgIHR4QnVpbGRlci5pc1Rva2VuVHJhbnNhY3Rpb24oKTtcbiAgICBjb25zdCB0eCA9IChhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKSkgYXMgVHJhbnNhY3Rpb247XG5cbiAgICBzaG91bGQuZXF1YWwodHgudHlwZSwgVHJhbnNhY3Rpb25UeXBlLlNlbmQpO1xuICAgIGNvbnN0IHR4RGF0YSA9IHR4LnRvSnNvbigpO1xuXG4gICAgdHhEYXRhLmlucHV0cy5sZW5ndGguc2hvdWxkLmVxdWFsKDIpO1xuICAgIHR4RGF0YS5vdXRwdXRzLmxlbmd0aC5zaG91bGQuZXF1YWwoNCk7XG5cbiAgICAvLyBWYWxpZGF0ZSByZWNlaXZlciBvdXRwdXQgLSBtaW4gQURBIHNob3VsZCBiZSBzcG9uc29yZWQgYnkgZmVlIGFkZHJlc3NcbiAgICBjb25zdCByZWNlaXZlck91dHB1dCA9IHR4RGF0YS5vdXRwdXRzLmZpbHRlcigob3V0cHV0KSA9PiBvdXRwdXQuYWRkcmVzcyA9PT0gcmVjZWl2ZXJBZGRyZXNzKTtcbiAgICByZWNlaXZlck91dHB1dC5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuICAgIHJlY2VpdmVyT3V0cHV0WzBdLmFtb3VudC5zaG91bGQuZXF1YWwoJzE1MDAwMDAnKTsgLy8gTWluaW11bSBBREEgZm9yIGFzc2V0IG91dHB1dCAoc3BvbnNvcmVkIGJ5IGZlZSBhZGRyZXNzKVxuICAgIChyZWNlaXZlck91dHB1dFswXS5tdWx0aUFzc2V0cyEgYXMgQ2FyZGFub1dhc20uTXVsdGlBc3NldClcbiAgICAgIC5nZXRfYXNzZXQocG9saWN5U2NyaXB0SGFzaCwgQ2FyZGFub1dhc20uQXNzZXROYW1lLm5ldyhCdWZmZXIuZnJvbShhc2NpaUVuY29kZWROYW1lLCAnaGV4JykpKVxuICAgICAgLnRvX3N0cigpXG4gICAgICAuc2hvdWxkLmVxdWFsKHF1YW50aXR5KTtcblxuICAgIC8vIFZhbGlkYXRlIHNlbmRlciBjaGFuZ2Ugb3V0cHV0IC0gc2hvdWxkIGhhdmUgZnVsbCBzZW5kZXIgYmFsYW5jZSAodG9rZW5zIG9ubHksIG5vIEFEQSBkZWR1Y3Rpb24gZm9yIHJlY2VpdmVyKVxuICAgIGNvbnN0IHNlbmRlckNoYW5nZU91dHB1dCA9IHR4RGF0YS5vdXRwdXRzLmZpbHRlcigob3V0cHV0KSA9PiBvdXRwdXQuYWRkcmVzcyA9PT0gc2VuZGVyQWRkcmVzcyk7XG4gICAgc2VuZGVyQ2hhbmdlT3V0cHV0Lmxlbmd0aC5zaG91bGQuYmUuZXF1YWwoMik7XG5cbiAgICAvLyBWYWxpZGF0ZSBmZWUgYWRkcmVzcyBjaGFuZ2Ugb3V0cHV0IC0gc2hvdWxkIGhhdmUgcmVtYWluaW5nIEFEQSBhZnRlciBmZWVzIGFuZCBtaW4gQURBIGZvciByZWNlaXZlclxuICAgIGNvbnN0IGZlZUFkZHJlc3NDaGFuZ2VPdXRwdXQgPSB0eERhdGEub3V0cHV0cy5maWx0ZXIoKG91dHB1dCkgPT4gb3V0cHV0LmFkZHJlc3MgPT09IGZlZUFkZHJlc3MpO1xuICAgIGZlZUFkZHJlc3NDaGFuZ2VPdXRwdXQubGVuZ3RoLnNob3VsZC5lcXVhbCgxKTtcbiAgICAvLyBGZWUgYWRkcmVzcyBjaGFuZ2Ugc2hvdWxkIG5vdCBoYXZlIGFueSB0b2tlbnNcbiAgICBzaG91bGQubm90LmV4aXN0KGZlZUFkZHJlc3NDaGFuZ2VPdXRwdXRbMF0ubXVsdGlBc3NldHMpO1xuXG4gICAgdHguZ2V0RmVlLnNob3VsZC5lcXVhbCgnMTgyNDg1Jyk7IC8vIEZlZSB3aXRoIHR3byB3aXRuZXNzZXNcbiAgfSk7XG5cbiAgaXQoYHNob3VsZCByZWJ1aWxkIGEgc3BvbnNvcmVkIHRyYW5zYWN0aW9uIGZyb20gaGV4IHdpdGggaXNSZWJ1aWxkIGZsYWdgLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZmVlQWRkcmVzcyA9XG4gICAgICAnYWRkcl90ZXN0MXF6MmZ4djJ1bXlodHRreHl4cDh4MGRscGR0M2s2Y3duZzVweGozamhzeWR6ZXIzamN1NWQ4cHM3emV4MmsyeHQzdXF4Z2pxbm5qODN3czhsaHJuNjQ4amp4dHdxMnl0anFwJztcbiAgICBjb25zdCBxdWFudGl0eSA9ICcyMCc7XG4gICAgY29uc3Qgc2VuZGVySW5wdXRCYWxhbmNlID0gNTAwMDAwMDtcbiAgICBjb25zdCBmZWVBZGRyZXNzSW5wdXRCYWxhbmNlID0gMjAwMDAwMDA7XG4gICAgY29uc3QgdG90YWxBc3NldExpc3QgPSB7XG4gICAgICBbZmluZ2VycHJpbnRdOiB7XG4gICAgICAgIHF1YW50aXR5OiAnMTAwJyxcbiAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIC8vIFN0ZXAgMTogQnVpbGQgdGhlIGluaXRpYWwgc3BvbnNvcmVkIHRyYW5zYWN0aW9uXG4gICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRUcmFuc2ZlckJ1aWxkZXIoKTtcbiAgICB0eEJ1aWxkZXIuaW5wdXQoe1xuICAgICAgdHJhbnNhY3Rpb25faWQ6ICczNjc3ZTc1YzdiYTY5OWJmZGM2Y2Q1N2Q0MmYyNDZmODZmNjNhZWZkNzYwMjUwMDZhYzc4MzEzZmFkMmJiYTIxJyxcbiAgICAgIHRyYW5zYWN0aW9uX2luZGV4OiAxLFxuICAgIH0pO1xuICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICB0cmFuc2FjdGlvbl9pZDogJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjInLFxuICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDAsXG4gICAgfSk7XG5cbiAgICB0eEJ1aWxkZXIub3V0cHV0KHtcbiAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgIGFtb3VudDogJzAnLFxuICAgICAgbXVsdGlBc3NldHM6IHtcbiAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgcXVhbnRpdHksXG4gICAgICAgIGZpbmdlcnByaW50LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHR4QnVpbGRlci5jaGFuZ2VBZGRyZXNzKHNlbmRlckFkZHJlc3MsIHNlbmRlcklucHV0QmFsYW5jZS50b1N0cmluZygpLCB0b3RhbEFzc2V0TGlzdCk7XG4gICAgdHhCdWlsZGVyLnNwb25zb3JzaGlwSW5mbyh7XG4gICAgICBmZWVBZGRyZXNzOiBmZWVBZGRyZXNzLFxuICAgICAgZmVlQWRkcmVzc0lucHV0QmFsYW5jZTogZmVlQWRkcmVzc0lucHV0QmFsYW5jZS50b1N0cmluZygpLFxuICAgIH0pO1xuICAgIHR4QnVpbGRlci50dGwoODAwMDAwMDAwKTtcbiAgICB0eEJ1aWxkZXIuaXNUb2tlblRyYW5zYWN0aW9uKCk7XG4gICAgY29uc3QgaW5pdGlhbFR4ID0gKGF3YWl0IHR4QnVpbGRlci5idWlsZCgpKSBhcyBUcmFuc2FjdGlvbjtcbiAgICBjb25zdCBpbml0aWFsRmVlID0gaW5pdGlhbFR4LmdldEZlZTtcbiAgICBjb25zdCBpbml0aWFsVHhEYXRhID0gaW5pdGlhbFR4LnRvSnNvbigpO1xuXG4gICAgLy8gU3RlcCAyOiBSZWJ1aWxkIHdpdGggaXNSZWJ1aWxkID0gdHJ1ZVxuICAgIC8vIFRoaXMgc2ltdWxhdGVzIHJlYnVpbGRpbmcgZnJvbSBzY3JhdGNoIGJ1dCB3aXRoIGlzUmVidWlsZCBmbGFnIHRvIGFkZCBzcG9uc29yIHdpdG5lc3NcbiAgICBjb25zdCByZWJ1aWxkVHhCdWlsZGVyID0gZmFjdG9yeS5nZXRUcmFuc2ZlckJ1aWxkZXIoKTtcbiAgICByZWJ1aWxkVHhCdWlsZGVyLmlucHV0KHtcbiAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMScsXG4gICAgICB0cmFuc2FjdGlvbl9pbmRleDogMSxcbiAgICB9KTtcbiAgICByZWJ1aWxkVHhCdWlsZGVyLmlucHV0KHtcbiAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMicsXG4gICAgICB0cmFuc2FjdGlvbl9pbmRleDogMCxcbiAgICB9KTtcblxuICAgIHJlYnVpbGRUeEJ1aWxkZXIub3V0cHV0KHtcbiAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgIGFtb3VudDogJzAnLFxuICAgICAgbXVsdGlBc3NldHM6IHtcbiAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgcXVhbnRpdHksXG4gICAgICAgIGZpbmdlcnByaW50LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHJlYnVpbGRUeEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCBzZW5kZXJJbnB1dEJhbGFuY2UudG9TdHJpbmcoKSwgdG90YWxBc3NldExpc3QpO1xuICAgIHJlYnVpbGRUeEJ1aWxkZXIuc3BvbnNvcnNoaXBJbmZvKHtcbiAgICAgIGZlZUFkZHJlc3M6IGZlZUFkZHJlc3MsXG4gICAgICBmZWVBZGRyZXNzSW5wdXRCYWxhbmNlOiBmZWVBZGRyZXNzSW5wdXRCYWxhbmNlLnRvU3RyaW5nKCksXG4gICAgICBpc1JlYnVpbGQ6IHRydWUsXG4gICAgfSk7XG4gICAgcmVidWlsZFR4QnVpbGRlci50dGwoODAwMDAwMDAwKTtcbiAgICByZWJ1aWxkVHhCdWlsZGVyLmlzVG9rZW5UcmFuc2FjdGlvbigpO1xuXG4gICAgY29uc3QgcmVidWlsdFR4ID0gKGF3YWl0IHJlYnVpbGRUeEJ1aWxkZXIuYnVpbGQoKSkgYXMgVHJhbnNhY3Rpb247XG4gICAgY29uc3QgcmVidWlsdFR4RGF0YSA9IHJlYnVpbHRUeC50b0pzb24oKTtcblxuICAgIC8vIFZlcmlmeSB0aGUgcmVidWlsdCB0cmFuc2FjdGlvbiBwcmVzZXJ2ZXMgdGhlIHNhbWUgc3RydWN0dXJlXG4gICAgcmVidWlsdFR4RGF0YS5pbnB1dHMubGVuZ3RoLnNob3VsZC5lcXVhbChpbml0aWFsVHhEYXRhLmlucHV0cy5sZW5ndGgpO1xuICAgIHJlYnVpbHRUeERhdGEub3V0cHV0cy5sZW5ndGguc2hvdWxkLmVxdWFsKGluaXRpYWxUeERhdGEub3V0cHV0cy5sZW5ndGgpO1xuXG4gICAgLy8gRmVlIHNob3VsZCBiZSBwcmVzZXJ2ZWQgZnJvbSB0aGUgb3JpZ2luYWwgdHJhbnNhY3Rpb25cbiAgICByZWJ1aWx0VHguZ2V0RmVlLnNob3VsZC5lcXVhbChpbml0aWFsRmVlKTtcblxuICAgIC8vIFZlcmlmeSByZWNlaXZlciBvdXRwdXQgaXMgcHJlc2VydmVkXG4gICAgY29uc3QgcmVjZWl2ZXJPdXRwdXQgPSByZWJ1aWx0VHhEYXRhLm91dHB1dHMuZmlsdGVyKChvdXRwdXQpID0+IG91dHB1dC5hZGRyZXNzID09PSByZWNlaXZlckFkZHJlc3MpO1xuICAgIHJlY2VpdmVyT3V0cHV0Lmxlbmd0aC5zaG91bGQuZXF1YWwoMSk7XG4gICAgcmVjZWl2ZXJPdXRwdXRbMF0uYW1vdW50LnNob3VsZC5lcXVhbCgnMTUwMDAwMCcpO1xuICB9KTtcblxuICBkZXNjcmliZSgnQWRhVG9rZW4gdmVyaWZ5VHJhbnNhY3Rpb24nLCAoKSA9PiB7XG4gICAgbGV0IGJpdGdvOiBUZXN0Qml0R29BUEk7XG4gICAgbGV0IGFkYVRva2VuO1xuXG4gICAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvQVBJLCB7IGVudjogJ21vY2snIH0pO1xuICAgICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgICBjb25zdCB0b2tlbkNvbmZpZyA9IHtcbiAgICAgICAgdHlwZTogJ3RhZGE6d2F0ZXInLFxuICAgICAgICBjb2luOiAndGFkYScsXG4gICAgICAgIG5ldHdvcms6ICdUZXN0bmV0JyBhcyBjb25zdCxcbiAgICAgICAgbmFtZTogJ1dBVEVSJyxcbiAgICAgICAgZGVjaW1hbFBsYWNlczogMCxcbiAgICAgICAgcG9saWN5SWQ6IHBvbGljeUlkLFxuICAgICAgICBhc3NldE5hbWU6IG5hbWUsIC8vIEFTQ0lJICdXQVRFUicsIG5vdCBoZXgtZW5jb2RlZFxuICAgICAgICBjb250cmFjdEFkZHJlc3M6IGAke3BvbGljeUlkfToke2FzY2lpRW5jb2RlZE5hbWV9YCxcbiAgICAgIH07XG4gICAgICBhZGFUb2tlbiA9IG5ldyBBZGFUb2tlbihiaXRnbywgdG9rZW5Db25maWcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB2ZXJpZnkgYSB0b2tlbiB0cmFuc2FjdGlvbiB3aXRoIGNvcnJlY3QgdG9rZW4gYW1vdW50JywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgICAgY29uc3QgdG90YWxJbnB1dCA9IDIwMDAwMDAwO1xuICAgICAgY29uc3QgdG90YWxBc3NldExpc3QgPSB7XG4gICAgICAgIFtmaW5nZXJwcmludF06IHtcbiAgICAgICAgICBxdWFudGl0eTogJzEwMCcsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgICB9LFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRUcmFuc2ZlckJ1aWxkZXIoKTtcbiAgICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMScsXG4gICAgICAgIHRyYW5zYWN0aW9uX2luZGV4OiAxLFxuICAgICAgfSk7XG5cbiAgICAgIHR4QnVpbGRlci5vdXRwdXQoe1xuICAgICAgICBhZGRyZXNzOiByZWNlaXZlckFkZHJlc3MsXG4gICAgICAgIGFtb3VudDogJzAnLFxuICAgICAgICBtdWx0aUFzc2V0czoge1xuICAgICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBxdWFudGl0eSxcbiAgICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICAgIHR4QnVpbGRlci50dGwoODAwMDAwMDAwKTtcbiAgICAgIHR4QnVpbGRlci5pc1Rva2VuVHJhbnNhY3Rpb24oKTtcbiAgICAgIGNvbnN0IHR4ID0gKGF3YWl0IHR4QnVpbGRlci5idWlsZCgpKSBhcyBUcmFuc2FjdGlvbjtcbiAgICAgIGNvbnN0IHR4SGV4ID0gdHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgICAgLy8gVmVyaWZ5IHRyYW5zYWN0aW9uIHdpdGggY29ycmVjdCB0b2tlbiBhbW91bnRcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogcmVjZWl2ZXJBZGRyZXNzLFxuICAgICAgICAgICAgYW1vdW50OiBxdWFudGl0eSwgLy8gVG9rZW4gYW1vdW50LCBub3QgQURBIGFtb3VudFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0geyB0eEhleCB9O1xuICAgICAgY29uc3QgbW9ja1dhbGxldCA9IHsgY29pblNwZWNpZmljOiAoKSA9PiAoeyBiYXNlQWRkcmVzczogc2VuZGVyQWRkcmVzcyB9KSB9O1xuICAgICAgY29uc3QgaXNWZXJpZmllZCA9IGF3YWl0IGFkYVRva2VuLnZlcmlmeVRyYW5zYWN0aW9uKHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIHdhbGxldDogbW9ja1dhbGxldCBhcyBhbnkgfSk7XG4gICAgICBpc1ZlcmlmaWVkLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB0byB2ZXJpZnkgYSB0b2tlbiB0cmFuc2FjdGlvbiB3aXRoIGluY29ycmVjdCB0b2tlbiBhbW91bnQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBxdWFudGl0eSA9ICcyMCc7XG4gICAgICBjb25zdCB0b3RhbElucHV0ID0gMjAwMDAwMDA7XG4gICAgICBjb25zdCB0b3RhbEFzc2V0TGlzdCA9IHtcbiAgICAgICAgW2ZpbmdlcnByaW50XToge1xuICAgICAgICAgIHF1YW50aXR5OiAnMTAwJyxcbiAgICAgICAgICBwb2xpY3lfaWQ6IHBvbGljeUlkLFxuICAgICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgIH0sXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldFRyYW5zZmVyQnVpbGRlcigpO1xuICAgICAgdHhCdWlsZGVyLmlucHV0KHtcbiAgICAgICAgdHJhbnNhY3Rpb25faWQ6ICczNjc3ZTc1YzdiYTY5OWJmZGM2Y2Q1N2Q0MmYyNDZmODZmNjNhZWZkNzYwMjUwMDZhYzc4MzEzZmFkMmJiYTIxJyxcbiAgICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDEsXG4gICAgICB9KTtcblxuICAgICAgdHhCdWlsZGVyLm91dHB1dCh7XG4gICAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgICAgYW1vdW50OiAnMCcsXG4gICAgICAgIG11bHRpQXNzZXRzOiB7XG4gICAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgICAgICBwb2xpY3lfaWQ6IHBvbGljeUlkLFxuICAgICAgICAgIHF1YW50aXR5LFxuICAgICAgICAgIGZpbmdlcnByaW50LFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIHR4QnVpbGRlci5jaGFuZ2VBZGRyZXNzKHNlbmRlckFkZHJlc3MsIHRvdGFsSW5wdXQudG9TdHJpbmcoKSwgdG90YWxBc3NldExpc3QpO1xuICAgICAgdHhCdWlsZGVyLnR0bCg4MDAwMDAwMDApO1xuICAgICAgdHhCdWlsZGVyLmlzVG9rZW5UcmFuc2FjdGlvbigpO1xuICAgICAgY29uc3QgdHggPSAoYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkpIGFzIFRyYW5zYWN0aW9uO1xuICAgICAgY29uc3QgdHhIZXggPSB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuXG4gICAgICAvLyBWZXJpZnkgdHJhbnNhY3Rpb24gd2l0aCBXUk9ORyB0b2tlbiBhbW91bnQgKHNob3VsZCBmYWlsKVxuICAgICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICAgIHJlY2lwaWVudHM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhZGRyZXNzOiByZWNlaXZlckFkZHJlc3MsXG4gICAgICAgICAgICBhbW91bnQ6ICc5OTknLCAvLyBXcm9uZyBhbW91bnRcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHsgdHhIZXggfTtcbiAgICAgIGNvbnN0IG1vY2tXYWxsZXQgPSB7IGNvaW5TcGVjaWZpYzogKCkgPT4gKHsgYmFzZUFkZHJlc3M6IHNlbmRlckFkZHJlc3MgfSkgfTtcbiAgICAgIGF3YWl0IGFkYVRva2VuXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCB3YWxsZXQ6IG1vY2tXYWxsZXQgYXMgYW55IH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdjYW5ub3QgZmluZCByZWNpcGllbnQgaW4gZXhwZWN0ZWQgb3V0cHV0Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdG8gdmVyaWZ5IHdoZW4gYWRkcmVzcyBkb2VzIG5vdCBtYXRjaCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHF1YW50aXR5ID0gJzIwJztcbiAgICAgIGNvbnN0IHRvdGFsSW5wdXQgPSAyMDAwMDAwMDtcbiAgICAgIGNvbnN0IHRvdGFsQXNzZXRMaXN0ID0ge1xuICAgICAgICBbZmluZ2VycHJpbnRdOiB7XG4gICAgICAgICAgcXVhbnRpdHk6ICcxMDAnLFxuICAgICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgICAgYXNzZXRfbmFtZTogYXNjaWlFbmNvZGVkTmFtZSxcbiAgICAgICAgfSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZ2V0VHJhbnNmZXJCdWlsZGVyKCk7XG4gICAgICB0eEJ1aWxkZXIuaW5wdXQoe1xuICAgICAgICB0cmFuc2FjdGlvbl9pZDogJzM2NzdlNzVjN2JhNjk5YmZkYzZjZDU3ZDQyZjI0NmY4NmY2M2FlZmQ3NjAyNTAwNmFjNzgzMTNmYWQyYmJhMjEnLFxuICAgICAgICB0cmFuc2FjdGlvbl9pbmRleDogMSxcbiAgICAgIH0pO1xuXG4gICAgICB0eEJ1aWxkZXIub3V0cHV0KHtcbiAgICAgICAgYWRkcmVzczogcmVjZWl2ZXJBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6ICcwJyxcbiAgICAgICAgbXVsdGlBc3NldHM6IHtcbiAgICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgICAgcXVhbnRpdHksXG4gICAgICAgICAgZmluZ2VycHJpbnQsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgdHhCdWlsZGVyLmNoYW5nZUFkZHJlc3Moc2VuZGVyQWRkcmVzcywgdG90YWxJbnB1dC50b1N0cmluZygpLCB0b3RhbEFzc2V0TGlzdCk7XG4gICAgICB0eEJ1aWxkZXIudHRsKDgwMDAwMDAwMCk7XG4gICAgICB0eEJ1aWxkZXIuaXNUb2tlblRyYW5zYWN0aW9uKCk7XG4gICAgICBjb25zdCB0eCA9IChhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKSkgYXMgVHJhbnNhY3Rpb247XG4gICAgICBjb25zdCB0eEhleCA9IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgICAgIC8vIFZlcmlmeSB3aXRoIHdyb25nIGFkZHJlc3MgKHNob3VsZCBmYWlsKVxuICAgICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICAgIHJlY2lwaWVudHM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhZGRyZXNzOlxuICAgICAgICAgICAgICAnYWRkcl90ZXN0MXFxYTg2ZTNkN2xmcHd1MGsycmhqejc2ZWNtZnhkcjc0czlrZjl5ZmNwNWhqNXZtbmg2eGNjamNjbHJrOGp0YXc5amdldXk5OXAybjhzbXRkcHlsbXk0NXFqamZzZm1wM2c2JyxcbiAgICAgICAgICAgIGFtb3VudDogcXVhbnRpdHksXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSB7IHR4SGV4IH07XG4gICAgICBjb25zdCBtb2NrV2FsbGV0ID0geyBjb2luU3BlY2lmaWM6ICgpID0+ICh7IGJhc2VBZGRyZXNzOiBzZW5kZXJBZGRyZXNzIH0pIH07XG4gICAgICBhd2FpdCBhZGFUb2tlblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgd2FsbGV0OiBtb2NrV2FsbGV0IGFzIGFueSB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnY2Fubm90IGZpbmQgcmVjaXBpZW50IGluIGV4cGVjdGVkIG91dHB1dCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB2ZXJpZnkgdHJhbnNhY3Rpb24gd2hlbiBwb2xpY3lJZCBoYXMgY29uY2F0ZW5hdGVkIGFzc2V0TmFtZSAoY3J5cHRvIGNvbXBhcmUgZm9ybWF0KScsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFRoaXMgdGVzdHMgdGhlIGNhc2Ugd2hlcmUgcG9saWN5SWQgaW4gdG9rZW5Db25maWcgY29udGFpbnMgcG9saWN5SWQgKyBhc2NpaUVuY29kZWRBc3NldE5hbWVcbiAgICAgIC8vIHdoaWNoIGlzIGNvbnNpc3RlbnQgd2l0aCBjcnlwdG8gY29tcGFyZSBmb3JtYXRcbiAgICAgIGNvbnN0IGNvbmNhdGVuYXRlZFBvbGljeUlkID0gcG9saWN5SWQgKyBhc2NpaUVuY29kZWROYW1lOyAvLyBlLmcuLCAnZTE2YzJkYzhhZTkzN2U4ZDM3OTBjN2ZkNzE2OGQ3Yjk5NDYyMWJhMTRjYTExNDE1ZjM5ZmVkNzI1NzQxNTQ0NTUyJ1xuXG4gICAgICBjb25zdCB0b2tlbkNvbmZpZ1dpdGhDb25jYXRlbmF0ZWRQb2xpY3lJZCA9IHtcbiAgICAgICAgdHlwZTogJ3RhZGE6d2F0ZXInLFxuICAgICAgICBjb2luOiAndGFkYScsXG4gICAgICAgIG5ldHdvcms6ICdUZXN0bmV0JyBhcyBjb25zdCxcbiAgICAgICAgbmFtZTogJ1dBVEVSJyxcbiAgICAgICAgZGVjaW1hbFBsYWNlczogMCxcbiAgICAgICAgcG9saWN5SWQ6IGNvbmNhdGVuYXRlZFBvbGljeUlkLCAvLyBwb2xpY3lJZCArIGFzc2V0TmFtZSBoZXhcbiAgICAgICAgYXNzZXROYW1lOiBuYW1lLCAvLyBBU0NJSSBuYW1lICdXQVRFUicgKG5vdCBoZXggZW5jb2RlZClcbiAgICAgICAgY29udHJhY3RBZGRyZXNzOiBgJHtwb2xpY3lJZH06JHthc2NpaUVuY29kZWROYW1lfWAsXG4gICAgICB9O1xuICAgICAgY29uc3QgYWRhVG9rZW5XaXRoQ29uY2F0ZW5hdGVkUG9saWN5SWQgPSBuZXcgQWRhVG9rZW4oYml0Z28sIHRva2VuQ29uZmlnV2l0aENvbmNhdGVuYXRlZFBvbGljeUlkKTtcblxuICAgICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgICAgY29uc3QgdG90YWxJbnB1dCA9IDIwMDAwMDAwO1xuICAgICAgY29uc3QgdG90YWxBc3NldExpc3QgPSB7XG4gICAgICAgIFtmaW5nZXJwcmludF06IHtcbiAgICAgICAgICBxdWFudGl0eTogJzEwMCcsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgICB9LFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRUcmFuc2ZlckJ1aWxkZXIoKTtcbiAgICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMScsXG4gICAgICAgIHRyYW5zYWN0aW9uX2luZGV4OiAxLFxuICAgICAgfSk7XG5cbiAgICAgIHR4QnVpbGRlci5vdXRwdXQoe1xuICAgICAgICBhZGRyZXNzOiByZWNlaXZlckFkZHJlc3MsXG4gICAgICAgIGFtb3VudDogJzAnLFxuICAgICAgICBtdWx0aUFzc2V0czoge1xuICAgICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBxdWFudGl0eSxcbiAgICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICAgIHR4QnVpbGRlci50dGwoODAwMDAwMDAwKTtcbiAgICAgIHR4QnVpbGRlci5pc1Rva2VuVHJhbnNhY3Rpb24oKTtcbiAgICAgIGNvbnN0IHR4ID0gKGF3YWl0IHR4QnVpbGRlci5idWlsZCgpKSBhcyBUcmFuc2FjdGlvbjtcbiAgICAgIGNvbnN0IHR4SGV4ID0gdHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgICAgLy8gVmVyaWZ5IHRyYW5zYWN0aW9uIC0gdGhlIHZlcmlmeVRyYW5zYWN0aW9uIHNob3VsZCBzdHJpcCB0aGUgYXNzZXROYW1lIGZyb20gcG9saWN5SWRcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogcmVjZWl2ZXJBZGRyZXNzLFxuICAgICAgICAgICAgYW1vdW50OiBxdWFudGl0eSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHsgdHhIZXggfTtcbiAgICAgIGNvbnN0IG1vY2tXYWxsZXQgPSB7IGNvaW5TcGVjaWZpYzogKCkgPT4gKHsgYmFzZUFkZHJlc3M6IHNlbmRlckFkZHJlc3MgfSkgfTtcbiAgICAgIGNvbnN0IGlzVmVyaWZpZWQgPSBhd2FpdCBhZGFUb2tlbldpdGhDb25jYXRlbmF0ZWRQb2xpY3lJZC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zLFxuICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICB3YWxsZXQ6IG1vY2tXYWxsZXQgYXMgYW55LFxuICAgICAgfSk7XG4gICAgICBpc1ZlcmlmaWVkLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmVyaWZ5IHRyYW5zYWN0aW9uIHdpdGggcG9saWN5SWQgdGhhdCBkb2VzIG5vdCBoYXZlIGNvbmNhdGVuYXRlZCBhc3NldE5hbWUnLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBUaGlzIHRlc3RzIHRoZSBjYXNlIHdoZXJlIHBvbGljeUlkIGlzIGp1c3QgdGhlIDI4LWJ5dGUgcG9saWN5IElEIChubyBhc3NldE5hbWUgYXBwZW5kZWQpXG4gICAgICBjb25zdCB0b2tlbkNvbmZpZ1dpdGhQbGFpblBvbGljeUlkID0ge1xuICAgICAgICB0eXBlOiAndGFkYTp3YXRlcicsXG4gICAgICAgIGNvaW46ICd0YWRhJyxcbiAgICAgICAgbmV0d29yazogJ1Rlc3RuZXQnIGFzIGNvbnN0LFxuICAgICAgICBuYW1lOiAnV0FURVInLFxuICAgICAgICBkZWNpbWFsUGxhY2VzOiAwLFxuICAgICAgICBwb2xpY3lJZDogcG9saWN5SWQsIC8vIEp1c3QgdGhlIHBvbGljeSBJRCB3aXRob3V0IGFzc2V0TmFtZVxuICAgICAgICBhc3NldE5hbWU6IG5hbWUsIC8vIEFTQ0lJIG5hbWUgJ1dBVEVSJ1xuICAgICAgICBjb250cmFjdEFkZHJlc3M6IGAke3BvbGljeUlkfToke2FzY2lpRW5jb2RlZE5hbWV9YCxcbiAgICAgIH07XG4gICAgICBjb25zdCBhZGFUb2tlbldpdGhQbGFpblBvbGljeUlkID0gbmV3IEFkYVRva2VuKGJpdGdvLCB0b2tlbkNvbmZpZ1dpdGhQbGFpblBvbGljeUlkKTtcblxuICAgICAgY29uc3QgcXVhbnRpdHkgPSAnMjAnO1xuICAgICAgY29uc3QgdG90YWxJbnB1dCA9IDIwMDAwMDAwO1xuICAgICAgY29uc3QgdG90YWxBc3NldExpc3QgPSB7XG4gICAgICAgIFtmaW5nZXJwcmludF06IHtcbiAgICAgICAgICBxdWFudGl0eTogJzEwMCcsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgICB9LFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRUcmFuc2ZlckJ1aWxkZXIoKTtcbiAgICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMScsXG4gICAgICAgIHRyYW5zYWN0aW9uX2luZGV4OiAxLFxuICAgICAgfSk7XG5cbiAgICAgIHR4QnVpbGRlci5vdXRwdXQoe1xuICAgICAgICBhZGRyZXNzOiByZWNlaXZlckFkZHJlc3MsXG4gICAgICAgIGFtb3VudDogJzAnLFxuICAgICAgICBtdWx0aUFzc2V0czoge1xuICAgICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBxdWFudGl0eSxcbiAgICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICAgIHR4QnVpbGRlci50dGwoODAwMDAwMDAwKTtcbiAgICAgIHR4QnVpbGRlci5pc1Rva2VuVHJhbnNhY3Rpb24oKTtcbiAgICAgIGNvbnN0IHR4ID0gKGF3YWl0IHR4QnVpbGRlci5idWlsZCgpKSBhcyBUcmFuc2FjdGlvbjtcbiAgICAgIGNvbnN0IHR4SGV4ID0gdHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgICAgLy8gVmVyaWZ5IHRyYW5zYWN0aW9uIC0gc2hvdWxkIHdvcmsgd2l0aCBwbGFpbiBwb2xpY3lJZCBhcyB3ZWxsXG4gICAgICBjb25zdCB0eFBhcmFtcyA9IHtcbiAgICAgICAgcmVjaXBpZW50czogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgICAgICAgIGFtb3VudDogcXVhbnRpdHksXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSB7IHR4SGV4IH07XG4gICAgICBjb25zdCBtb2NrV2FsbGV0ID0geyBjb2luU3BlY2lmaWM6ICgpID0+ICh7IGJhc2VBZGRyZXNzOiBzZW5kZXJBZGRyZXNzIH0pIH07XG4gICAgICBjb25zdCBpc1ZlcmlmaWVkID0gYXdhaXQgYWRhVG9rZW5XaXRoUGxhaW5Qb2xpY3lJZC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zLFxuICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICB3YWxsZXQ6IG1vY2tXYWxsZXQgYXMgYW55LFxuICAgICAgfSk7XG4gICAgICBpc1ZlcmlmaWVkLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmVyaWZ5IHRva2VuIGNvbnNvbGlkYXRpb24gdHJhbnNhY3Rpb24gd2hlbiBhbGwgb3V0cHV0cyBnbyB0byBiYXNlIGFkZHJlc3MnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBxdWFudGl0eSA9ICcxMDAnO1xuICAgICAgY29uc3QgdG90YWxJbnB1dCA9IDIwMDAwMDAwO1xuICAgICAgY29uc3QgdG90YWxBc3NldExpc3QgPSB7XG4gICAgICAgIFtmaW5nZXJwcmludF06IHtcbiAgICAgICAgICBxdWFudGl0eTogJzEwMCcsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgICB9LFxuICAgICAgfTtcblxuICAgICAgLy8gQnVpbGQgYSBjb25zb2xpZGF0aW9uIHRyYW5zYWN0aW9uIC0gYWxsIG91dHB1dHMgZ28gdG8gc2VuZGVyIChiYXNlKSBhZGRyZXNzXG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldFRyYW5zZmVyQnVpbGRlcigpO1xuICAgICAgdHhCdWlsZGVyLmlucHV0KHtcbiAgICAgICAgdHJhbnNhY3Rpb25faWQ6ICczNjc3ZTc1YzdiYTY5OWJmZGM2Y2Q1N2Q0MmYyNDZmODZmNjNhZWZkNzYwMjUwMDZhYzc4MzEzZmFkMmJiYTIxJyxcbiAgICAgICAgdHJhbnNhY3Rpb25faW5kZXg6IDEsXG4gICAgICB9KTtcblxuICAgICAgLy8gRm9yIGNvbnNvbGlkYXRpb24sIHRva2VucyBnbyBiYWNrIHRvIHRoZSBzZW5kZXIncyBiYXNlIGFkZHJlc3NcbiAgICAgIHR4QnVpbGRlci5vdXRwdXQoe1xuICAgICAgICBhZGRyZXNzOiBzZW5kZXJBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6ICcwJyxcbiAgICAgICAgbXVsdGlBc3NldHM6IHtcbiAgICAgICAgICBhc3NldF9uYW1lOiBhc2NpaUVuY29kZWROYW1lLFxuICAgICAgICAgIHBvbGljeV9pZDogcG9saWN5SWQsXG4gICAgICAgICAgcXVhbnRpdHksXG4gICAgICAgICAgZmluZ2VycHJpbnQsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgdHhCdWlsZGVyLmNoYW5nZUFkZHJlc3Moc2VuZGVyQWRkcmVzcywgdG90YWxJbnB1dC50b1N0cmluZygpLCB0b3RhbEFzc2V0TGlzdCk7XG4gICAgICB0eEJ1aWxkZXIudHRsKDgwMDAwMDAwMCk7XG4gICAgICB0eEJ1aWxkZXIuaXNUb2tlblRyYW5zYWN0aW9uKCk7XG4gICAgICBjb25zdCB0eCA9IChhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKSkgYXMgVHJhbnNhY3Rpb247XG4gICAgICBjb25zdCB0eEhleCA9IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgICAgIC8vIE1vY2sgd2FsbGV0IHdpdGggY29pblNwZWNpZmljIHJldHVybmluZyBiYXNlIGFkZHJlc3NcbiAgICAgIGNvbnN0IG1vY2tXYWxsZXQgPSB7XG4gICAgICAgIGNvaW5TcGVjaWZpYzogKCkgPT4gKHtcbiAgICAgICAgICBiYXNlQWRkcmVzczogc2VuZGVyQWRkcmVzcyxcbiAgICAgICAgfSksXG4gICAgICB9O1xuXG4gICAgICAvLyBWZXJpZnkgY29uc29saWRhdGlvbiB0cmFuc2FjdGlvbiAtIG5vIHJlY2lwaWVudHMsIGJ1dCBjb25zb2xpZGF0aW9uVG9CYXNlQWRkcmVzcyBpcyB0cnVlXG4gICAgICBjb25zdCB0eFBhcmFtcyA9IHtcbiAgICAgICAgcmVjaXBpZW50czogdW5kZWZpbmVkLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHsgdHhIZXggfTtcbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHsgY29uc29saWRhdGlvblRvQmFzZUFkZHJlc3M6IHRydWUgfTtcblxuICAgICAgY29uc3QgaXNWZXJpZmllZCA9IGF3YWl0IGFkYVRva2VuLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXMsXG4gICAgICAgIHR4UHJlYnVpbGQsXG4gICAgICAgIHZlcmlmaWNhdGlvbixcbiAgICAgICAgd2FsbGV0OiBtb2NrV2FsbGV0IGFzIGFueSxcbiAgICAgIH0pO1xuICAgICAgaXNWZXJpZmllZC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdG9rZW4gY29uc29saWRhdGlvbiB3aGVuIG91dHB1dCBhZGRyZXNzIGRvZXMgbm90IG1hdGNoIGJhc2UgYWRkcmVzcycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHF1YW50aXR5ID0gJzEwMCc7XG4gICAgICBjb25zdCB0b3RhbElucHV0ID0gMjAwMDAwMDA7XG4gICAgICBjb25zdCB0b3RhbEFzc2V0TGlzdCA9IHtcbiAgICAgICAgW2ZpbmdlcnByaW50XToge1xuICAgICAgICAgIHF1YW50aXR5OiAnMTAwJyxcbiAgICAgICAgICBwb2xpY3lfaWQ6IHBvbGljeUlkLFxuICAgICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgIH0sXG4gICAgICB9O1xuXG4gICAgICAvLyBCdWlsZCBhIHRyYW5zYWN0aW9uIHdpdGggb3V0cHV0IHRvIHJlY2VpdmVyIChub3QgYmFzZSBhZGRyZXNzKVxuICAgICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeS5nZXRUcmFuc2ZlckJ1aWxkZXIoKTtcbiAgICAgIHR4QnVpbGRlci5pbnB1dCh7XG4gICAgICAgIHRyYW5zYWN0aW9uX2lkOiAnMzY3N2U3NWM3YmE2OTliZmRjNmNkNTdkNDJmMjQ2Zjg2ZjYzYWVmZDc2MDI1MDA2YWM3ODMxM2ZhZDJiYmEyMScsXG4gICAgICAgIHRyYW5zYWN0aW9uX2luZGV4OiAxLFxuICAgICAgfSk7XG5cbiAgICAgIHR4QnVpbGRlci5vdXRwdXQoe1xuICAgICAgICBhZGRyZXNzOiByZWNlaXZlckFkZHJlc3MsIC8vIE91dHB1dCBnb2VzIHRvIHJlY2VpdmVyLCBub3QgYmFzZSBhZGRyZXNzXG4gICAgICAgIGFtb3VudDogJzAnLFxuICAgICAgICBtdWx0aUFzc2V0czoge1xuICAgICAgICAgIGFzc2V0X25hbWU6IGFzY2lpRW5jb2RlZE5hbWUsXG4gICAgICAgICAgcG9saWN5X2lkOiBwb2xpY3lJZCxcbiAgICAgICAgICBxdWFudGl0eSxcbiAgICAgICAgICBmaW5nZXJwcmludCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICB0eEJ1aWxkZXIuY2hhbmdlQWRkcmVzcyhzZW5kZXJBZGRyZXNzLCB0b3RhbElucHV0LnRvU3RyaW5nKCksIHRvdGFsQXNzZXRMaXN0KTtcbiAgICAgIHR4QnVpbGRlci50dGwoODAwMDAwMDAwKTtcbiAgICAgIHR4QnVpbGRlci5pc1Rva2VuVHJhbnNhY3Rpb24oKTtcbiAgICAgIGNvbnN0IHR4ID0gKGF3YWl0IHR4QnVpbGRlci5idWlsZCgpKSBhcyBUcmFuc2FjdGlvbjtcbiAgICAgIGNvbnN0IHR4SGV4ID0gdHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgICAgLy8gTW9jayB3YWxsZXQgd2l0aCBkaWZmZXJlbnQgYmFzZSBhZGRyZXNzXG4gICAgICBjb25zdCBtb2NrV2FsbGV0ID0ge1xuICAgICAgICBjb2luU3BlY2lmaWM6ICgpID0+ICh7XG4gICAgICAgICAgYmFzZUFkZHJlc3M6IHNlbmRlckFkZHJlc3MsIC8vIEJhc2UgYWRkcmVzcyBpcyBzZW5kZXIsIGJ1dCBvdXRwdXQgZ29lcyB0byByZWNlaXZlclxuICAgICAgICB9KSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHR4UGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiB1bmRlZmluZWQsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0geyB0eEhleCB9O1xuICAgICAgY29uc3QgdmVyaWZpY2F0aW9uID0geyBjb25zb2xpZGF0aW9uVG9CYXNlQWRkcmVzczogdHJ1ZSB9O1xuXG4gICAgICBhd2FpdCBhZGFUb2tlblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UGFyYW1zLFxuICAgICAgICAgIHR4UHJlYnVpbGQsXG4gICAgICAgICAgdmVyaWZpY2F0aW9uLFxuICAgICAgICAgIHdhbGxldDogbW9ja1dhbGxldCBhcyBhbnksXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCd0eCBvdXRwdXRzIGRvZXMgbm90IG1hdGNoIHdpdGggZXhwZWN0ZWQgYWRkcmVzcycpO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19