@bitgo-beta/sdk-coin-irys 0.0.1-alpha.0

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.
@@ -0,0 +1,402 @@
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 sinon = __importStar(require("sinon"));
41
+ const nock_1 = __importDefault(require("nock"));
42
+ const commitmentTransactionBuilder_1 = require("../../src/lib/commitmentTransactionBuilder");
43
+ const iface_1 = require("../../src/lib/iface");
44
+ const utils_1 = require("../../src/lib/utils");
45
+ describe('IrysCommitmentTransactionBuilder', function () {
46
+ // Common test fixtures
47
+ const testAnchor = new Uint8Array(32).fill(1); // 32 bytes of 0x01
48
+ const testSigner = new Uint8Array(20).fill(2); // 20 bytes of 0x02
49
+ const testChainId = iface_1.IRYS_TESTNET_CHAIN_ID; // 1270n
50
+ const testFee = 1000n;
51
+ const testValue = 5000n;
52
+ const testApiUrl = 'https://testnet-node1.irys.xyz/v1';
53
+ let builder;
54
+ beforeEach(function () {
55
+ builder = new commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder(testApiUrl, testChainId);
56
+ });
57
+ afterEach(function () {
58
+ sinon.restore();
59
+ nock_1.default.cleanAll();
60
+ });
61
+ // === Commitment Type Encoding Tests ===
62
+ describe('encodeCommitmentTypeForSigning', function () {
63
+ it('should encode STAKE as a flat number (not array)', function () {
64
+ const result = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.encodeCommitmentTypeForSigning({
65
+ type: iface_1.CommitmentTypeId.STAKE,
66
+ });
67
+ result.should.equal(1);
68
+ Array.isArray(result).should.be.false();
69
+ });
70
+ it('should encode PLEDGE as a nested array [type, pledgeCount]', function () {
71
+ const result = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.encodeCommitmentTypeForSigning({
72
+ type: iface_1.CommitmentTypeId.PLEDGE,
73
+ pledgeCount: 42n,
74
+ });
75
+ Array.isArray(result).should.be.true();
76
+ result.length.should.equal(2);
77
+ result[0].should.equal(2);
78
+ result[1].should.equal(42n);
79
+ });
80
+ });
81
+ // === Commitment Type Broadcast Encoding Tests ===
82
+ describe('encodeCommitmentTypeForBroadcast', function () {
83
+ it('should encode STAKE as { type: "stake" }', function () {
84
+ const result = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.encodeCommitmentTypeForBroadcast({
85
+ type: iface_1.CommitmentTypeId.STAKE,
86
+ });
87
+ should_1.default.deepEqual(result, { type: 'stake' });
88
+ });
89
+ it('should encode PLEDGE with pledgeCountBeforeExecuting', function () {
90
+ const result = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.encodeCommitmentTypeForBroadcast({
91
+ type: iface_1.CommitmentTypeId.PLEDGE,
92
+ pledgeCount: 42n,
93
+ });
94
+ should_1.default.deepEqual(result, { type: 'pledge', pledgeCountBeforeExecuting: '42' });
95
+ });
96
+ });
97
+ // === RLP Encoding Tests ===
98
+ describe('rlpEncode', function () {
99
+ it('should RLP encode a STAKE transaction with correct field order', function () {
100
+ const fields = {
101
+ version: iface_1.COMMITMENT_TX_VERSION,
102
+ anchor: testAnchor,
103
+ signer: testSigner,
104
+ commitmentType: { type: iface_1.CommitmentTypeId.STAKE },
105
+ chainId: testChainId,
106
+ fee: testFee,
107
+ value: testValue,
108
+ };
109
+ const encoded = builder.rlpEncode(fields);
110
+ encoded.should.be.instanceOf(Uint8Array);
111
+ encoded.length.should.be.greaterThan(0);
112
+ // The encoded output should be deterministic
113
+ const encoded2 = builder.rlpEncode(fields);
114
+ Buffer.from(encoded).equals(Buffer.from(encoded2)).should.be.true();
115
+ });
116
+ it('should RLP encode a PLEDGE transaction with nested array commitment type', function () {
117
+ const fields = {
118
+ version: iface_1.COMMITMENT_TX_VERSION,
119
+ anchor: testAnchor,
120
+ signer: testSigner,
121
+ commitmentType: { type: iface_1.CommitmentTypeId.PLEDGE, pledgeCount: 42n },
122
+ chainId: testChainId,
123
+ fee: testFee,
124
+ value: testValue,
125
+ };
126
+ const encoded = builder.rlpEncode(fields);
127
+ encoded.should.be.instanceOf(Uint8Array);
128
+ encoded.length.should.be.greaterThan(0);
129
+ });
130
+ it('should produce different encodings for STAKE vs PLEDGE', function () {
131
+ const stakeFields = {
132
+ version: iface_1.COMMITMENT_TX_VERSION,
133
+ anchor: testAnchor,
134
+ signer: testSigner,
135
+ commitmentType: { type: iface_1.CommitmentTypeId.STAKE },
136
+ chainId: testChainId,
137
+ fee: testFee,
138
+ value: testValue,
139
+ };
140
+ const pledgeFields = {
141
+ ...stakeFields,
142
+ commitmentType: { type: iface_1.CommitmentTypeId.PLEDGE, pledgeCount: 1n },
143
+ };
144
+ const stakeEncoded = builder.rlpEncode(stakeFields);
145
+ const pledgeEncoded = builder.rlpEncode(pledgeFields);
146
+ Buffer.from(stakeEncoded).equals(Buffer.from(pledgeEncoded)).should.be.false();
147
+ });
148
+ });
149
+ // === Prehash Tests ===
150
+ describe('computePrehash', function () {
151
+ it('should return a 32-byte keccak256 hash', function () {
152
+ const rlpEncoded = new Uint8Array([0xc0]); // minimal RLP
153
+ const prehash = builder.computePrehash(rlpEncoded);
154
+ prehash.should.be.instanceOf(Uint8Array);
155
+ prehash.length.should.equal(32);
156
+ });
157
+ it('should produce deterministic output', function () {
158
+ const rlpEncoded = new Uint8Array([0xc8, 0x02, 0x01, 0x02, 0x03]);
159
+ const hash1 = builder.computePrehash(rlpEncoded);
160
+ const hash2 = builder.computePrehash(rlpEncoded);
161
+ Buffer.from(hash1).equals(Buffer.from(hash2)).should.be.true();
162
+ });
163
+ it('should produce different hashes for different inputs', function () {
164
+ const input1 = new Uint8Array([0x01]);
165
+ const input2 = new Uint8Array([0x02]);
166
+ const hash1 = builder.computePrehash(input1);
167
+ const hash2 = builder.computePrehash(input2);
168
+ Buffer.from(hash1).equals(Buffer.from(hash2)).should.be.false();
169
+ });
170
+ });
171
+ // === Build Tests ===
172
+ describe('build', function () {
173
+ it('should build a STAKE transaction with manually set anchor', async function () {
174
+ builder
175
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.STAKE })
176
+ .setFee(testFee)
177
+ .setValue(testValue)
178
+ .setSigner(testSigner)
179
+ .setAnchor(testAnchor);
180
+ const result = await builder.build();
181
+ result.prehash.should.be.instanceOf(Uint8Array);
182
+ result.prehash.length.should.equal(32);
183
+ result.rlpEncoded.should.be.instanceOf(Uint8Array);
184
+ result.rlpEncoded.length.should.be.greaterThan(0);
185
+ result.fields.version.should.equal(iface_1.COMMITMENT_TX_VERSION);
186
+ result.fields.chainId.should.equal(testChainId);
187
+ });
188
+ it('should build a PLEDGE transaction with manually set anchor', async function () {
189
+ builder
190
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.PLEDGE, pledgeCount: 5n })
191
+ .setFee(testFee)
192
+ .setValue(testValue)
193
+ .setSigner(testSigner)
194
+ .setAnchor(testAnchor);
195
+ const result = await builder.build();
196
+ result.prehash.length.should.equal(32);
197
+ result.fields.commitmentType.should.deepEqual({ type: iface_1.CommitmentTypeId.PLEDGE, pledgeCount: 5n });
198
+ });
199
+ it('should fetch anchor from API when not manually set', async function () {
200
+ const mockAnchorBase58 = (0, utils_1.encodeBase58)(testAnchor);
201
+ const scope = (0, nock_1.default)('https://testnet-node1.irys.xyz')
202
+ .get('/v1/anchor')
203
+ .reply(200, { blockHash: mockAnchorBase58 });
204
+ builder
205
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.STAKE })
206
+ .setFee(testFee)
207
+ .setValue(testValue)
208
+ .setSigner(testSigner);
209
+ const result = await builder.build();
210
+ result.prehash.length.should.equal(32);
211
+ Buffer.from(result.fields.anchor).equals(Buffer.from(testAnchor)).should.be.true();
212
+ scope.done();
213
+ });
214
+ it('should throw if commitment type is not set', async function () {
215
+ builder.setFee(testFee).setValue(testValue).setSigner(testSigner).setAnchor(testAnchor);
216
+ await builder.build().should.be.rejectedWith('Commitment type is required');
217
+ });
218
+ it('should throw if fee is not set', async function () {
219
+ builder
220
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.STAKE })
221
+ .setValue(testValue)
222
+ .setSigner(testSigner)
223
+ .setAnchor(testAnchor);
224
+ await builder.build().should.be.rejectedWith('Fee is required');
225
+ });
226
+ it('should throw if value is not set', async function () {
227
+ builder
228
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.STAKE })
229
+ .setFee(testFee)
230
+ .setSigner(testSigner)
231
+ .setAnchor(testAnchor);
232
+ await builder.build().should.be.rejectedWith('Value is required');
233
+ });
234
+ it('should throw if signer is not set', async function () {
235
+ builder
236
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.STAKE })
237
+ .setFee(testFee)
238
+ .setValue(testValue)
239
+ .setAnchor(testAnchor);
240
+ await builder.build().should.be.rejectedWith('Signer is required');
241
+ });
242
+ });
243
+ // === Validation Tests ===
244
+ describe('input validation', function () {
245
+ it('should reject signer with wrong length', function () {
246
+ (() => builder.setSigner(new Uint8Array(19))).should.throw(/Signer must be 20 bytes/);
247
+ (() => builder.setSigner(new Uint8Array(21))).should.throw(/Signer must be 20 bytes/);
248
+ });
249
+ it('should reject anchor with wrong length', function () {
250
+ (() => builder.setAnchor(new Uint8Array(31))).should.throw(/Anchor must be 32 bytes/);
251
+ (() => builder.setAnchor(new Uint8Array(33))).should.throw(/Anchor must be 32 bytes/);
252
+ });
253
+ });
254
+ // === Transaction ID Tests ===
255
+ describe('computeTxId', function () {
256
+ it('should compute base58(keccak256(signature))', function () {
257
+ const fakeSignature = new Uint8Array(65).fill(0xab);
258
+ const txId = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.computeTxId(fakeSignature);
259
+ txId.should.be.a.String();
260
+ txId.length.should.be.greaterThan(0);
261
+ });
262
+ it('should produce deterministic output', function () {
263
+ const sig = new Uint8Array(65).fill(0xcd);
264
+ const id1 = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.computeTxId(sig);
265
+ const id2 = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.computeTxId(sig);
266
+ id1.should.equal(id2);
267
+ });
268
+ it('should reject non-65-byte signatures', function () {
269
+ (() => commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.computeTxId(new Uint8Array(64))).should.throw(/Signature must be 65 bytes/);
270
+ });
271
+ });
272
+ // === Broadcast Payload Tests ===
273
+ describe('createBroadcastPayload', function () {
274
+ it('should create valid JSON payload for STAKE', function () {
275
+ const fields = {
276
+ version: iface_1.COMMITMENT_TX_VERSION,
277
+ anchor: testAnchor,
278
+ signer: testSigner,
279
+ commitmentType: { type: iface_1.CommitmentTypeId.STAKE },
280
+ chainId: testChainId,
281
+ fee: testFee,
282
+ value: testValue,
283
+ };
284
+ const signature = new Uint8Array(65).fill(0xab);
285
+ const payload = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.createBroadcastPayload(fields, signature);
286
+ payload.version.should.equal(2);
287
+ payload.anchor.should.be.a.String();
288
+ payload.signer.should.be.a.String();
289
+ should_1.default.deepEqual(payload.commitmentType, { type: 'stake' });
290
+ payload.chainId.should.equal('1270');
291
+ payload.fee.should.equal('1000');
292
+ payload.value.should.equal('5000');
293
+ payload.id.should.be.a.String();
294
+ payload.signature.should.be.a.String();
295
+ });
296
+ it('should create valid JSON payload for PLEDGE with pledgeCountBeforeExecuting', function () {
297
+ const fields = {
298
+ version: iface_1.COMMITMENT_TX_VERSION,
299
+ anchor: testAnchor,
300
+ signer: testSigner,
301
+ commitmentType: { type: iface_1.CommitmentTypeId.PLEDGE, pledgeCount: 42n },
302
+ chainId: testChainId,
303
+ fee: testFee,
304
+ value: testValue,
305
+ };
306
+ const signature = new Uint8Array(65).fill(0xcd);
307
+ const payload = commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder.createBroadcastPayload(fields, signature);
308
+ should_1.default.deepEqual(payload.commitmentType, { type: 'pledge', pledgeCountBeforeExecuting: '42' });
309
+ });
310
+ });
311
+ // === Known-Good Test Vectors (from successful testnet transactions) ===
312
+ //
313
+ // These vectors were captured from actual STAKE and PLEDGE transactions
314
+ // submitted to the Irys testnet using coins-sandbox/eth/irys/stake.ts.
315
+ // They verify our RLP encoding + prehash match the protocol exactly.
316
+ describe('known-good test vectors', function () {
317
+ const testnetSigner = '0x22f9C9f1845D9b6C22b96Ef35E46E265aC4Af30c';
318
+ const testnetSignerBytes = Uint8Array.from(Buffer.from(testnetSigner.slice(2), 'hex'));
319
+ const testnetChainId = 1270n;
320
+ it('should match known STAKE RLP encoding and prehash', async function () {
321
+ // From stake_pledge.txt - successful STAKE transaction
322
+ // TX ID: 4XhUTrkhxr1RmUQbXUVRwbNZ6pKEYrAVo5ymdMY41fS5
323
+ const anchorBase58 = '8JR2rD5DejnM2NuVSqqGa68dfye6ZKruT9rdh2Cn4B8y';
324
+ const anchorBytes = (0, utils_1.decodeBase58)(anchorBase58);
325
+ const stakeBuilder = new commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder(testApiUrl, testnetChainId);
326
+ stakeBuilder
327
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.STAKE })
328
+ .setFee(100n)
329
+ .setValue(20000000000000000000000n) // 20000 IRYS
330
+ .setSigner(testnetSignerBytes)
331
+ .setAnchor(anchorBytes);
332
+ const result = await stakeBuilder.build();
333
+ const expectedRlp = '0xf84702a06c77daebc2db4e572e4f296983d1413fc10d4852e0fabfdb8323c9c69a2b85' +
334
+ '9e9422f9c9f1845d9b6c22b96ef35e46e265ac4af30c018204f6648a043c33c1937564800000';
335
+ const actualRlp = '0x' + Buffer.from(result.rlpEncoded).toString('hex');
336
+ actualRlp.should.equal(expectedRlp);
337
+ const expectedPrehash = '0xe6fe57810c12785e3ce5fa64e2eb4da120b89ec0e469213715916abf36358d01';
338
+ const actualPrehash = '0x' + Buffer.from(result.prehash).toString('hex');
339
+ actualPrehash.should.equal(expectedPrehash);
340
+ });
341
+ it('should match known PLEDGE RLP encoding and prehash', async function () {
342
+ // From stake_pledge.txt - successful PLEDGE transaction
343
+ // TX ID: EsdiesC58S8eeY1SHM5jTfy84zYxFMUdKF89Ytr6PyNb
344
+ const anchorBase58 = 'jUShJPUACW4bxUSvZji65Q96MaqKDh7AFFALKnkapBn';
345
+ const anchorBytes = (0, utils_1.decodeBase58)(anchorBase58);
346
+ const pledgeBuilder = new commitmentTransactionBuilder_1.IrysCommitmentTransactionBuilder(testApiUrl, testnetChainId);
347
+ pledgeBuilder
348
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.PLEDGE, pledgeCount: 0n })
349
+ .setFee(100n)
350
+ .setValue(950000000000000000000n) // 950 IRYS
351
+ .setSigner(testnetSignerBytes)
352
+ .setAnchor(anchorBytes);
353
+ const result = await pledgeBuilder.build();
354
+ const expectedRlp = '0xf84802a00ae16c8476bbde2f28b2e4629d393dfe6fa7affcf0a0c4654f8246a9ba78970594' +
355
+ '22f9c9f1845d9b6c22b96ef35e46e265ac4af30cc202808204f66489337fe5feaf2d180000';
356
+ const actualRlp = '0x' + Buffer.from(result.rlpEncoded).toString('hex');
357
+ actualRlp.should.equal(expectedRlp);
358
+ const expectedPrehash = '0xfe07c2f3c6e50d9c9e2cff57f6d7015b4528f425b6132f567e26bba745228102';
359
+ const actualPrehash = '0x' + Buffer.from(result.prehash).toString('hex');
360
+ actualPrehash.should.equal(expectedPrehash);
361
+ });
362
+ });
363
+ // === Edge Case Tests ===
364
+ describe('edge cases', function () {
365
+ it('should handle zero fee and value', async function () {
366
+ builder
367
+ .setCommitmentType({ type: iface_1.CommitmentTypeId.STAKE })
368
+ .setFee(0n)
369
+ .setValue(0n)
370
+ .setSigner(testSigner)
371
+ .setAnchor(testAnchor);
372
+ const result = await builder.build();
373
+ result.prehash.length.should.equal(32);
374
+ });
375
+ });
376
+ // === Anchor Fetch Tests ===
377
+ describe('fetchAnchor', function () {
378
+ it('should fetch and decode base58 anchor from API', async function () {
379
+ const mockAnchorBase58 = (0, utils_1.encodeBase58)(testAnchor);
380
+ const scope = (0, nock_1.default)('https://testnet-node1.irys.xyz')
381
+ .get('/v1/anchor')
382
+ .reply(200, { blockHash: mockAnchorBase58 });
383
+ const anchor = await builder.fetchAnchor();
384
+ anchor.should.be.instanceOf(Uint8Array);
385
+ anchor.length.should.equal(32);
386
+ Buffer.from(anchor).equals(Buffer.from(testAnchor)).should.be.true();
387
+ scope.done();
388
+ });
389
+ it('should throw on non-200 response', async function () {
390
+ const scope = (0, nock_1.default)('https://testnet-node1.irys.xyz').get('/v1/anchor').reply(500, 'Internal Server Error');
391
+ await builder.fetchAnchor().should.be.rejectedWith(/Internal Server Error/);
392
+ scope.done();
393
+ });
394
+ it('should throw if anchor decodes to wrong length', async function () {
395
+ const shortAnchor = (0, utils_1.encodeBase58)(new Uint8Array(16)); // 16 bytes instead of 32
396
+ const scope = (0, nock_1.default)('https://testnet-node1.irys.xyz').get('/v1/anchor').reply(200, { blockHash: shortAnchor });
397
+ await builder.fetchAnchor().should.be.rejectedWith(/Expected 32 bytes/);
398
+ scope.done();
399
+ });
400
+ });
401
+ });
402
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWl0bWVudFRyYW5zYWN0aW9uQnVpbGRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Rlc3QvdW5pdC9jb21taXRtZW50VHJhbnNhY3Rpb25CdWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsb0RBQTRCO0FBQzVCLDZDQUErQjtBQUMvQixnREFBd0I7QUFDeEIsNkZBQThGO0FBQzlGLCtDQUFxRztBQUNyRywrQ0FBaUU7QUFFakUsUUFBUSxDQUFDLGtDQUFrQyxFQUFFO0lBQzNDLHVCQUF1QjtJQUN2QixNQUFNLFVBQVUsR0FBRyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxtQkFBbUI7SUFDbEUsTUFBTSxVQUFVLEdBQUcsSUFBSSxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsbUJBQW1CO0lBQ2xFLE1BQU0sV0FBVyxHQUFHLDZCQUFxQixDQUFDLENBQUMsUUFBUTtJQUNuRCxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDdEIsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDO0lBQ3hCLE1BQU0sVUFBVSxHQUFHLG1DQUFtQyxDQUFDO0lBRXZELElBQUksT0FBeUMsQ0FBQztJQUU5QyxVQUFVLENBQUM7UUFDVCxPQUFPLEdBQUcsSUFBSSwrREFBZ0MsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDMUUsQ0FBQyxDQUFDLENBQUM7SUFFSCxTQUFTLENBQUM7UUFDUixLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDaEIsY0FBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBRUgseUNBQXlDO0lBRXpDLFFBQVEsQ0FBQyxnQ0FBZ0MsRUFBRTtRQUN6QyxFQUFFLENBQUMsa0RB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QUUsS0FBSztZQUMxQyxNQUFNLEtBQUssR0FBRyxJQUFBLGNBQUksRUFBQyxnQ0FBZ0MsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLHVCQUF1QixDQUFDLENBQUM7WUFFM0csTUFBTSxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsdUJBQXVCLENBQUMsQ0FBQztZQUM1RSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDZixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxnREFBZ0QsRUFBRSxLQUFLO1lBQ3hELE1BQU0sV0FBVyxHQUFHLElBQUEsb0JBQVksRUFBQyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMseUJBQXlCO1lBQy9FLE1BQU0sS0FBSyxHQUFHLElBQUEsY0FBSSxFQUFDLGdDQUFnQyxDQUFDLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztZQUU5RyxNQUFNLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ3hFLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNmLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBzaG91bGQgZnJvbSAnc2hvdWxkJztcbmltcG9ydCAqIGFzIHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCBub2NrIGZyb20gJ25vY2snO1xuaW1wb3J0IHsgSXJ5c0NvbW1pdG1lbnRUcmFuc2FjdGlvbkJ1aWxkZXIgfSBmcm9tICcuLi8uLi9zcmMvbGliL2NvbW1pdG1lbnRUcmFuc2FjdGlvbkJ1aWxkZXInO1xuaW1wb3J0IHsgQ29tbWl0bWVudFR5cGVJZCwgQ09NTUlUTUVOVF9UWF9WRVJTSU9OLCBJUllTX1RFU1RORVRfQ0hBSU5fSUQgfSBmcm9tICcuLi8uLi9zcmMvbGliL2lmYWNlJztcbmltcG9ydCB7IGVuY29kZUJhc2U1OCwgZGVjb2RlQmFzZTU4IH0gZnJvbSAnLi4vLi4vc3JjL2xpYi91dGlscyc7XG5cbmRlc2NyaWJlKCdJcnlzQ29tbWl0bWVudFRyYW5zYWN0aW9uQnVpbGRlcicsIGZ1bmN0aW9uICgpIHtcbiAgLy8gQ29tbW9uIHRlc3QgZml4dHVyZXNcbiAgY29uc3QgdGVzdEFuY2hvciA9IG5ldyBVaW50OEFycmF5KDMyKS5maWxsKDEpOyAvLyAzMiBieXRlcyBvZiAweDAxXG4gIGNvbnN0IHRlc3RTaWduZXIgPSBuZXcgVWludDhBcnJheSgyMCkuZmlsbCgyKTsgLy8gMjAgYnl0ZXMgb2YgMHgwMlxuICBjb25zdCB0ZXN0Q2hhaW5JZCA9IElSWVNfVEVTVE5FVF9DSEFJTl9JRDsgLy8gMTI3MG5cbiAgY29uc3QgdGVzdEZlZSA9IDEwMDBuO1xuICBjb25zdCB0ZXN0VmFsdWUgPSA1MDAwbjtcbiAgY29uc3QgdGVzdEFwaVVybCA9ICdodHRwczovL3Rlc3RuZXQtbm9kZTEuaXJ5cy54eXovdjEnO1xuXG4gIGxldCBidWlsZGVyOiBJcnlzQ29tbWl0bWVudFRyYW5zYWN0aW9uQnVpbGRlcjtcblxuICBiZWZvcmVFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICBidWlsZGVyID0gbmV3IElyeXNDb21taXRtZW50VHJhbnNhY3Rpb25CdWlsZGVyKHRlc3RBcGlVcmwsIHRlc3RDaGFpbklkKTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICBzaW5vbi5yZXN0b3JlKCk7XG4gICAgbm9jay5jbGVhbkFsbCgpO1xuICB9KTtcblxuICAvLyA9PT0gQ29tbWl0bWVudCBUeXBlIEVuY29kaW5nIFRlc3RzID09PVxuXG4gIGRlc2NyaWJlKCdlbmNvZGVDb21taXRtZW50VHlwZUZvclNpZ25pbmcnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBlbmNvZGUgU1RBS0UgYXMgYSBmbGF0IG51bWJlciAobm90IGFycmF5KScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IElyeXNDb21taXRtZW50VHJhbnNhY3Rpb25CdWlsZGVyLmVuY29kZUNvbW1pdG1lbnRUeXBlRm9yU2lnbmluZyh7XG4gICAgICAgIHR5cGU6IENvbW1pdG1lbnRUeXBlSWQuU1RBS0UsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwoMSk7XG4gICAgICBBcnJheS5pc0FycmF5KHJlc3VsdCkuc2hvdWxkLmJlLmZhbHNlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGVuY29kZSBQTEVER0UgYXMgYSBuZXN0ZWQgYXJyYXkgW3R5cGUsIHBsZWRnZUNvdW50XScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IElyeXNDb21taXRtZW50VHJhbnNhY3Rpb25CdWlsZGVyLmVuY29kZUNvbW1pdG1lbnRUeXBlRm9yU2lnbmluZyh7XG4gICAgICAgIHR5cGU6IENvbW1pdG1lbnRUeXBlSWQuUExFREdFLFxuICAgICAgICBwbGVkZ2VDb3VudDogNDJuLFxuICAgICAgfSk7XG4gICAgICBBcnJheS5pc0FycmF5KHJlc3VsdCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICAgIChyZXN1bHQgYXMgYW55W10pLmxlbmd0aC5zaG91bGQuZXF1YWwoMik7XG4gICAgICAocmVzdWx0IGFzIGFueVtdKVswXS5zaG91bGQuZXF1YWwoMik7XG4gICAgICAocmVzdWx0IGFzIGFueVtdKVsxXS5zaG91bGQuZXF1YWwoNDJuKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gPT09IENvbW1pdG1lbnQgVHlwZSBCcm9hZGNhc3QgRW5jb2RpbmcgVGVzdHMgPT09XG5cbiAgZGVzY3JpYmUoJ2VuY29kZUNvbW1pdG1lbnRUeXBlRm9yQnJvYWRjYXN0JywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgZW5jb2RlIFNUQUtFIGFzIHsgdHlwZTogXCJzdGFrZVwiIH0nLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBJcnlzQ29tbWl0bWVudFRyYW5zYWN0aW9uQnVpbGRlci5lbmNvZGVDb21taXRtZW50VHlwZUZvckJyb2FkY2FzdCh7XG4gICAgICAgIHR5cGU6IENvbW1pdG1lbnRUeXBlSWQuU1RBS0UsXG4gICAgICB9KTtcbiAgICAgIHNob3VsZC5kZWVwRXF1YWwocmVzdWx0LCB7IHR5cGU6ICdzdGFrZScgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGVuY29kZSBQTEVER0Ugd2l0aCBwbGVkZ2VDb3VudEJlZm9yZUV4ZWN1dGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IElyeXNDb21taXRtZW50VHJhbnNhY3Rpb25CdWlsZGVyLmVuY29kZUNvbW1pdG1lbnRUeXBlRm9yQnJvYWRjYXN0KHtcbiAgICAgICAgdHlwZTogQ29tbWl0bWVudFR5cGVJZC5QTEVER0UsXG4gICAgICAgIHBsZWRnZUNvdW50OiA0Mm4sXG4gICAgICB9KTtcbiAgICAgIHNob3VsZC5kZWVwRXF1YWwocmVzdWx0LCB7IHR5cGU6ICdwbGVkZ2UnLCBwbGVkZ2VDb3VudEJlZm9yZUV4ZWN1dGluZzogJzQyJyB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gPT09IFJMUCBFbmNvZGluZyBUZXN0cyA9PT1cblxuICBkZXNjcmliZSgncmxwRW5jb2RlJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgUkxQIGVuY29kZSBhIFNUQUtFIHRyYW5zYWN0aW9uIHdpdGggY29ycmVjdCBmaWVsZCBvcmRlcicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGZpZWxkcyA9IHtcbiAgICAgICAgdmVyc2lvbjogQ09NTUlUTUVOVF9UWF9WRVJTSU9OLFxuICAgICAgICBhbmNob3I6IHRlc3RBbmNob3IsXG4gICAgICAgIHNpZ25lcjogdGVzdFNpZ25lcixcbiAgICAgICAgY29tbWl0bWVudFR5cGU6IHsgdHlwZTogQ29tbWl0bWVudFR5cGVJZC5TVEFLRSBhcyBjb25zdCB9LFxuICAgICAgICBjaGFpbklkOiB0ZXN0Q2hhaW5JZCxcbiAgICAgICAgZmVlOiB0ZXN0RmVlLFxuICAgICAgICB2YWx1ZTogdGVzdFZhbHVlLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZW5jb2RlZCA9IGJ1aWxkZXIucmxwRW5jb2RlKGZpZWxkcyk7XG4gICAgICBlbmNvZGVkLnNob3VsZC5iZS5pbnN0YW5jZU9mKFVpbnQ4QXJyYXkpO1xuICAgICAgZW5jb2RlZC5sZW5ndGguc2hvdWxkLmJlLmdyZWF0ZXJUaGFuKDApO1xuXG4gICAgICAvLyBUaGUgZW5jb2RlZCBvdXRwdXQgc2hvdWxkIGJlIGRldGVybWluaXN0aWNcbiAgICAgIGNvbnN0IGVuY29kZWQyID0gYnVpbGRlci5ybHBFbmNvZGUoZmllbGRzKTtcbiAgICAgIEJ1ZmZlci5mcm9tKGVuY29kZWQpLmVxdWFscyhCdWZmZXIuZnJvbShlbmNvZGVkMikpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIFJMUCBlbmNvZGUgYSBQTEVER0UgdHJhbnNhY3Rpb24gd2l0aCBuZXN0ZWQgYXJyYXkgY29tbWl0bWVudCB0eXBlJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmllbGRzID0ge1xuICAgICAgICB2ZXJzaW9uOiBDT01NSVRNRU5UX1RYX1ZFUlNJT04sXG4gICAgICAgIGFuY2hvcjogdGVzdEFuY2hvcixcbiAgICAgICAgc2lnbmVyOiB0ZXN0U2lnbmVyLFxuICAgICAgICBjb21taXRtZW50VHlwZTogeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlBMRURHRSBhcyBjb25zdCwgcGxlZGdlQ291bnQ6IDQybiB9LFxuICAgICAgICBjaGFpbklkOiB0ZXN0Q2hhaW5JZCxcbiAgICAgICAgZmVlOiB0ZXN0RmVlLFxuICAgICAgICB2YWx1ZTogdGVzdFZhbHVlLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZW5jb2RlZCA9IGJ1aWxkZXIucmxwRW5jb2RlKGZpZWxkcyk7XG4gICAgICBlbmNvZGVkLnNob3VsZC5iZS5pbnN0YW5jZU9mKFVpbnQ4QXJyYXkpO1xuICAgICAgZW5jb2RlZC5sZW5ndGguc2hvdWxkLmJlLmdyZWF0ZXJUaGFuKDApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBwcm9kdWNlIGRpZmZlcmVudCBlbmNvZGluZ3MgZm9yIFNUQUtFIHZzIFBMRURHRScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHN0YWtlRmllbGRzID0ge1xuICAgICAgICB2ZXJzaW9uOiBDT01NSVRNRU5UX1RYX1ZFUlNJT04sXG4gICAgICAgIGFuY2hvcjogdGVzdEFuY2hvcixcbiAgICAgICAgc2lnbmVyOiB0ZXN0U2lnbmVyLFxuICAgICAgICBjb21taXRtZW50VHlwZTogeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlNUQUtFIGFzIGNvbnN0IH0sXG4gICAgICAgIGNoYWluSWQ6IHRlc3RDaGFpbklkLFxuICAgICAgICBmZWU6IHRlc3RGZWUsXG4gICAgICAgIHZhbHVlOiB0ZXN0VmFsdWUsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBwbGVkZ2VGaWVsZHMgPSB7XG4gICAgICAgIC4uLnN0YWtlRmllbGRzLFxuICAgICAgICBjb21taXRtZW50VHlwZTogeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlBMRURHRSBhcyBjb25zdCwgcGxlZGdlQ291bnQ6IDFuIH0sXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBzdGFrZUVuY29kZWQgPSBidWlsZGVyLnJscEVuY29kZShzdGFrZUZpZWxkcyk7XG4gICAgICBjb25zdCBwbGVkZ2VFbmNvZGVkID0gYnVpbGRlci5ybHBFbmNvZGUocGxlZGdlRmllbGRzKTtcbiAgICAgIEJ1ZmZlci5mcm9tKHN0YWtlRW5jb2RlZCkuZXF1YWxzKEJ1ZmZlci5mcm9tKHBsZWRnZUVuY29kZWQpKS5zaG91bGQuYmUuZmFsc2UoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gPT09IFByZWhhc2ggVGVzdHMgPT09XG5cbiAgZGVzY3JpYmUoJ2NvbXB1dGVQcmVoYXNoJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgcmV0dXJuIGEgMzItYnl0ZSBrZWNjYWsyNTYgaGFzaCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJscEVuY29kZWQgPSBuZXcgVWludDhBcnJheShbMHhjMF0pOyAvLyBtaW5pbWFsIFJMUFxuICAgICAgY29uc3QgcHJlaGFzaCA9IGJ1aWxkZXIuY29tcHV0ZVByZWhhc2gocmxwRW5jb2RlZCk7XG4gICAgICBwcmVoYXNoLnNob3VsZC5iZS5pbnN0YW5jZU9mKFVpbnQ4QXJyYXkpO1xuICAgICAgcHJlaGFzaC5sZW5ndGguc2hvdWxkLmVxdWFsKDMyKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcHJvZHVjZSBkZXRlcm1pbmlzdGljIG91dHB1dCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJscEVuY29kZWQgPSBuZXcgVWludDhBcnJheShbMHhjOCwgMHgwMiwgMHgwMSwgMHgwMiwgMHgwM10pO1xuICAgICAgY29uc3QgaGFzaDEgPSBidWlsZGVyLmNvbXB1dGVQcmVoYXNoKHJscEVuY29kZWQpO1xuICAgICAgY29uc3QgaGFzaDIgPSBidWlsZGVyLmNvbXB1dGVQcmVoYXNoKHJscEVuY29kZWQpO1xuICAgICAgQnVmZmVyLmZyb20oaGFzaDEpLmVxdWFscyhCdWZmZXIuZnJvbShoYXNoMikpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHByb2R1Y2UgZGlmZmVyZW50IGhhc2hlcyBmb3IgZGlmZmVyZW50IGlucHV0cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGlucHV0MSA9IG5ldyBVaW50OEFycmF5KFsweDAxXSk7XG4gICAgICBjb25zdCBpbnB1dDIgPSBuZXcgVWludDhBcnJheShbMHgwMl0pO1xuICAgICAgY29uc3QgaGFzaDEgPSBidWlsZGVyLmNvbXB1dGVQcmVoYXNoKGlucHV0MSk7XG4gICAgICBjb25zdCBoYXNoMiA9IGJ1aWxkZXIuY29tcHV0ZVByZWhhc2goaW5wdXQyKTtcbiAgICAgIEJ1ZmZlci5mcm9tKGhhc2gxKS5lcXVhbHMoQnVmZmVyLmZyb20oaGFzaDIpKS5zaG91bGQuYmUuZmFsc2UoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gPT09IEJ1aWxkIFRlc3RzID09PVxuXG4gIGRlc2NyaWJlKCdidWlsZCcsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIGJ1aWxkIGEgU1RBS0UgdHJhbnNhY3Rpb24gd2l0aCBtYW51YWxseSBzZXQgYW5jaG9yJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYnVpbGRlclxuICAgICAgICAuc2V0Q29tbWl0bWVudFR5cGUoeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlNUQUtFIH0pXG4gICAgICAgIC5zZXRGZWUodGVzdEZlZSlcbiAgICAgICAgLnNldFZhbHVlKHRlc3RWYWx1ZSlcbiAgICAgICAgLnNldFNpZ25lcih0ZXN0U2lnbmVyKVxuICAgICAgICAuc2V0QW5jaG9yKHRlc3RBbmNob3IpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBidWlsZGVyLmJ1aWxkKCk7XG4gICAgICByZXN1bHQucHJlaGFzaC5zaG91bGQuYmUuaW5zdGFuY2VPZihVaW50OEFycmF5KTtcbiAgICAgIHJlc3VsdC5wcmVoYXNoLmxlbmd0aC5zaG91bGQuZXF1YWwoMzIpO1xuICAgICAgcmVzdWx0LnJscEVuY29kZWQuc2hvdWxkLmJlLmluc3RhbmNlT2YoVWludDhBcnJheSk7XG4gICAgICByZXN1bHQucmxwRW5jb2RlZC5sZW5ndGguc2hvdWxkLmJlLmdyZWF0ZXJUaGFuKDApO1xuICAgICAgcmVzdWx0LmZpZWxkcy52ZXJzaW9uLnNob3VsZC5lcXVhbChDT01NSVRNRU5UX1RYX1ZFUlNJT04pO1xuICAgICAgcmVzdWx0LmZpZWxkcy5jaGFpbklkLnNob3VsZC5lcXVhbCh0ZXN0Q2hhaW5JZCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGJ1aWxkIGEgUExFREdFIHRyYW5zYWN0aW9uIHdpdGggbWFudWFsbHkgc2V0IGFuY2hvcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGJ1aWxkZXJcbiAgICAgICAgLnNldENvbW1pdG1lbnRUeXBlKHsgdHlwZTogQ29tbWl0bWVudFR5cGVJZC5QTEVER0UsIHBsZWRnZUNvdW50OiA1biB9KVxuICAgICAgICAuc2V0RmVlKHRlc3RGZWUpXG4gICAgICAgIC5zZXRWYWx1ZSh0ZXN0VmFsdWUpXG4gICAgICAgIC5zZXRTaWduZXIodGVzdFNpZ25lcilcbiAgICAgICAgLnNldEFuY2hvcih0ZXN0QW5jaG9yKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYnVpbGRlci5idWlsZCgpO1xuICAgICAgcmVzdWx0LnByZWhhc2gubGVuZ3RoLnNob3VsZC5lcXVhbCgzMik7XG4gICAgICByZXN1bHQuZmllbGRzLmNvbW1pdG1lbnRUeXBlLnNob3VsZC5kZWVwRXF1YWwoeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlBMRURHRSwgcGxlZGdlQ291bnQ6IDVuIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmZXRjaCBhbmNob3IgZnJvbSBBUEkgd2hlbiBub3QgbWFudWFsbHkgc2V0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgbW9ja0FuY2hvckJhc2U1OCA9IGVuY29kZUJhc2U1OCh0ZXN0QW5jaG9yKTtcbiAgICAgIGNvbnN0IHNjb3BlID0gbm9jaygnaHR0cHM6Ly90ZXN0bmV0LW5vZGUxLmlyeXMueHl6JylcbiAgICAgICAgLmdldCgnL3YxL2FuY2hvcicpXG4gICAgICAgIC5yZXBseSgyMDAsIHsgYmxvY2tIYXNoOiBtb2NrQW5jaG9yQmFzZTU4IH0pO1xuXG4gICAgICBidWlsZGVyXG4gICAgICAgIC5zZXRDb21taXRtZW50VHlwZSh7IHR5cGU6IENvbW1pdG1lbnRUeXBlSWQuU1RBS0UgfSlcbiAgICAgICAgLnNldEZlZSh0ZXN0RmVlKVxuICAgICAgICAuc2V0VmFsdWUodGVzdFZhbHVlKVxuICAgICAgICAuc2V0U2lnbmVyKHRlc3RTaWduZXIpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBidWlsZGVyLmJ1aWxkKCk7XG4gICAgICByZXN1bHQucHJlaGFzaC5sZW5ndGguc2hvdWxkLmVxdWFsKDMyKTtcbiAgICAgIEJ1ZmZlci5mcm9tKHJlc3VsdC5maWVsZHMuYW5jaG9yKS5lcXVhbHMoQnVmZmVyLmZyb20odGVzdEFuY2hvcikpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgICBzY29wZS5kb25lKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIGNvbW1pdG1lbnQgdHlwZSBpcyBub3Qgc2V0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYnVpbGRlci5zZXRGZWUodGVzdEZlZSkuc2V0VmFsdWUodGVzdFZhbHVlKS5zZXRTaWduZXIodGVzdFNpZ25lcikuc2V0QW5jaG9yKHRlc3RBbmNob3IpO1xuXG4gICAgICBhd2FpdCBidWlsZGVyLmJ1aWxkKCkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnQ29tbWl0bWVudCB0eXBlIGlzIHJlcXVpcmVkJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIGZlZSBpcyBub3Qgc2V0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYnVpbGRlclxuICAgICAgICAuc2V0Q29tbWl0bWVudFR5cGUoeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlNUQUtFIH0pXG4gICAgICAgIC5zZXRWYWx1ZSh0ZXN0VmFsdWUpXG4gICAgICAgIC5zZXRTaWduZXIodGVzdFNpZ25lcilcbiAgICAgICAgLnNldEFuY2hvcih0ZXN0QW5jaG9yKTtcblxuICAgICAgYXdhaXQgYnVpbGRlci5idWlsZCgpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ0ZlZSBpcyByZXF1aXJlZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiB2YWx1ZSBpcyBub3Qgc2V0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYnVpbGRlclxuICAgICAgICAuc2V0Q29tbWl0bWVudFR5cGUoeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlNUQUtFIH0pXG4gICAgICAgIC5zZXRGZWUodGVzdEZlZSlcbiAgICAgICAgLnNldFNpZ25lcih0ZXN0U2lnbmVyKVxuICAgICAgICAuc2V0QW5jaG9yKHRlc3RBbmNob3IpO1xuXG4gICAgICBhd2FpdCBidWlsZGVyLmJ1aWxkKCkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnVmFsdWUgaXMgcmVxdWlyZWQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgaWYgc2lnbmVyIGlzIG5vdCBzZXQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBidWlsZGVyXG4gICAgICAgIC5zZXRDb21taXRtZW50VHlwZSh7IHR5cGU6IENvbW1pdG1lbnRUeXBlSWQuU1RBS0UgfSlcbiAgICAgICAgLnNldEZlZSh0ZXN0RmVlKVxuICAgICAgICAuc2V0VmFsdWUodGVzdFZhbHVlKVxuICAgICAgICAuc2V0QW5jaG9yKHRlc3RBbmNob3IpO1xuXG4gICAgICBhd2FpdCBidWlsZGVyLmJ1aWxkKCkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnU2lnbmVyIGlzIHJlcXVpcmVkJyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vID09PSBWYWxpZGF0aW9uIFRlc3RzID09PVxuXG4gIGRlc2NyaWJlKCdpbnB1dCB2YWxpZGF0aW9uJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgcmVqZWN0IHNpZ25lciB3aXRoIHdyb25nIGxlbmd0aCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICgoKSA9PiBidWlsZGVyLnNldFNpZ25lcihuZXcgVWludDhBcnJheSgxOSkpKS5zaG91bGQudGhyb3coL1NpZ25lciBtdXN0IGJlIDIwIGJ5dGVzLyk7XG4gICAgICAoKCkgPT4gYnVpbGRlci5zZXRTaWduZXIobmV3IFVpbnQ4QXJyYXkoMjEpKSkuc2hvdWxkLnRocm93KC9TaWduZXIgbXVzdCBiZSAyMCBieXRlcy8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZWplY3QgYW5jaG9yIHdpdGggd3JvbmcgbGVuZ3RoJywgZnVuY3Rpb24gKCkge1xuICAgICAgKCgpID0+IGJ1aWxkZXIuc2V0QW5jaG9yKG5ldyBVaW50OEFycmF5KDMxKSkpLnNob3VsZC50aHJvdygvQW5jaG9yIG11c3QgYmUgMzIgYnl0ZXMvKTtcbiAgICAgICgoKSA9PiBidWlsZGVyLnNldEFuY2hvcihuZXcgVWludDhBcnJheSgzMykpKS5zaG91bGQudGhyb3coL0FuY2hvciBtdXN0IGJlIDMyIGJ5dGVzLyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vID09PSBUcmFuc2FjdGlvbiBJRCBUZXN0cyA9PT1cblxuICBkZXNjcmliZSgnY29tcHV0ZVR4SWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBjb21wdXRlIGJhc2U1OChrZWNjYWsyNTYoc2lnbmF0dXJlKSknLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBmYWtlU2lnbmF0dXJlID0gbmV3IFVpbnQ4QXJyYXkoNjUpLmZpbGwoMHhhYik7XG4gICAgICBjb25zdCB0eElkID0gSXJ5c0NvbW1pdG1lbnRUcmFuc2FjdGlvbkJ1aWxkZXIuY29tcHV0ZVR4SWQoZmFrZVNpZ25hdHVyZSk7XG4gICAgICB0eElkLnNob3VsZC5iZS5hLlN0cmluZygpO1xuICAgICAgdHhJZC5sZW5ndGguc2hvdWxkLmJlLmdyZWF0ZXJUaGFuKDApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBwcm9kdWNlIGRldGVybWluaXN0aWMgb3V0cHV0JywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgc2lnID0gbmV3IFVpbnQ4QXJyYXkoNjUpLmZpbGwoMHhjZCk7XG4gICAgICBjb25zdCBpZDEgPSBJcnlzQ29tbWl0bWVudFRyYW5zYWN0aW9uQnVpbGRlci5jb21wdXRlVHhJZChzaWcpO1xuICAgICAgY29uc3QgaWQyID0gSXJ5c0NvbW1pdG1lbnRUcmFuc2FjdGlvbkJ1aWxkZXIuY29tcHV0ZVR4SWQoc2lnKTtcbiAgICAgIGlkMS5zaG91bGQuZXF1YWwoaWQyKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IG5vbi02NS1ieXRlIHNpZ25hdHVyZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAoKCkgPT4gSXJ5c0NvbW1pdG1lbnRUcmFuc2FjdGlvbkJ1aWxkZXIuY29tcHV0ZVR4SWQobmV3IFVpbnQ4QXJyYXkoNjQpKSkuc2hvdWxkLnRocm93KFxuICAgICAgICAvU2lnbmF0dXJlIG11c3QgYmUgNjUgYnl0ZXMvXG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcblxuICAvLyA9PT0gQnJvYWRjYXN0IFBheWxvYWQgVGVzdHMgPT09XG5cbiAgZGVzY3JpYmUoJ2NyZWF0ZUJyb2FkY2FzdFBheWxvYWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBjcmVhdGUgdmFsaWQgSlNPTiBwYXlsb2FkIGZvciBTVEFLRScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGZpZWxkcyA9IHtcbiAgICAgICAgdmVyc2lvbjogQ09NTUlUTUVOVF9UWF9WRVJTSU9OLFxuICAgICAgICBhbmNob3I6IHRlc3RBbmNob3IsXG4gICAgICAgIHNpZ25lcjogdGVzdFNpZ25lcixcbiAgICAgICAgY29tbWl0bWVudFR5cGU6IHsgdHlwZTogQ29tbWl0bWVudFR5cGVJZC5TVEFLRSBhcyBjb25zdCB9LFxuICAgICAgICBjaGFpbklkOiB0ZXN0Q2hhaW5JZCxcbiAgICAgICAgZmVlOiB0ZXN0RmVlLFxuICAgICAgICB2YWx1ZTogdGVzdFZhbHVlLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IG5ldyBVaW50OEFycmF5KDY1KS5maWxsKDB4YWIpO1xuXG4gICAgICBjb25zdCBwYXlsb2FkID0gSXJ5c0NvbW1pdG1lbnRUcmFuc2FjdGlvbkJ1aWxkZXIuY3JlYXRlQnJvYWRjYXN0UGF5bG9hZChmaWVsZHMsIHNpZ25hdHVyZSk7XG5cbiAgICAgIHBheWxvYWQudmVyc2lvbi5zaG91bGQuZXF1YWwoMik7XG4gICAgICBwYXlsb2FkLmFuY2hvci5zaG91bGQuYmUuYS5TdHJpbmcoKTtcbiAgICAgIHBheWxvYWQuc2lnbmVyLnNob3VsZC5iZS5hLlN0cmluZygpO1xuICAgICAgc2hvdWxkLmRlZXBFcXVhbChwYXlsb2FkLmNvbW1pdG1lbnRUeXBlLCB7IHR5cGU6ICdzdGFrZScgfSk7XG4gICAgICBwYXlsb2FkLmNoYWluSWQuc2hvdWxkLmVxdWFsKCcxMjcwJyk7XG4gICAgICBwYXlsb2FkLmZlZS5zaG91bGQuZXF1YWwoJzEwMDAnKTtcbiAgICAgIHBheWxvYWQudmFsdWUuc2hvdWxkLmVxdWFsKCc1MDAwJyk7XG4gICAgICBwYXlsb2FkLmlkLnNob3VsZC5iZS5hLlN0cmluZygpO1xuICAgICAgcGF5bG9hZC5zaWduYXR1cmUuc2hvdWxkLmJlLmEuU3RyaW5nKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGNyZWF0ZSB2YWxpZCBKU09OIHBheWxvYWQgZm9yIFBMRURHRSB3aXRoIHBsZWRnZUNvdW50QmVmb3JlRXhlY3V0aW5nJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmllbGRzID0ge1xuICAgICAgICB2ZXJzaW9uOiBDT01NSVRNRU5UX1RYX1ZFUlNJT04sXG4gICAgICAgIGFuY2hvcjogdGVzdEFuY2hvcixcbiAgICAgICAgc2lnbmVyOiB0ZXN0U2lnbmVyLFxuICAgICAgICBjb21taXRtZW50VHlwZTogeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlBMRURHRSBhcyBjb25zdCwgcGxlZGdlQ291bnQ6IDQybiB9LFxuICAgICAgICBjaGFpbklkOiB0ZXN0Q2hhaW5JZCxcbiAgICAgICAgZmVlOiB0ZXN0RmVlLFxuICAgICAgICB2YWx1ZTogdGVzdFZhbHVlLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IG5ldyBVaW50OEFycmF5KDY1KS5maWxsKDB4Y2QpO1xuXG4gICAgICBjb25zdCBwYXlsb2FkID0gSXJ5c0NvbW1pdG1lbnRUcmFuc2FjdGlvbkJ1aWxkZXIuY3JlYXRlQnJvYWRjYXN0UGF5bG9hZChmaWVsZHMsIHNpZ25hdHVyZSk7XG5cbiAgICAgIHNob3VsZC5kZWVwRXF1YWwocGF5bG9hZC5jb21taXRtZW50VHlwZSwgeyB0eXBlOiAncGxlZGdlJywgcGxlZGdlQ291bnRCZWZvcmVFeGVjdXRpbmc6ICc0MicgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vID09PSBLbm93bi1Hb29kIFRlc3QgVmVjdG9ycyAoZnJvbSBzdWNjZXNzZnVsIHRlc3RuZXQgdHJhbnNhY3Rpb25zKSA9PT1cbiAgLy9cbiAgLy8gVGhlc2UgdmVjdG9ycyB3ZXJlIGNhcHR1cmVkIGZyb20gYWN0dWFsIFNUQUtFIGFuZCBQTEVER0UgdHJhbnNhY3Rpb25zXG4gIC8vIHN1Ym1pdHRlZCB0byB0aGUgSXJ5cyB0ZXN0bmV0IHVzaW5nIGNvaW5zLXNhbmRib3gvZXRoL2lyeXMvc3Rha2UudHMuXG4gIC8vIFRoZXkgdmVyaWZ5IG91ciBSTFAgZW5jb2RpbmcgKyBwcmVoYXNoIG1hdGNoIHRoZSBwcm90b2NvbCBleGFjdGx5LlxuXG4gIGRlc2NyaWJlKCdrbm93bi1nb29kIHRlc3QgdmVjdG9ycycsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0ZXN0bmV0U2lnbmVyID0gJzB4MjJmOUM5ZjE4NDVEOWI2QzIyYjk2RWYzNUU0NkUyNjVhQzRBZjMwYyc7XG4gICAgY29uc3QgdGVzdG5ldFNpZ25lckJ5dGVzID0gVWludDhBcnJheS5mcm9tKEJ1ZmZlci5mcm9tKHRlc3RuZXRTaWduZXIuc2xpY2UoMiksICdoZXgnKSk7XG4gICAgY29uc3QgdGVzdG5ldENoYWluSWQgPSAxMjcwbjtcblxuICAgIGl0KCdzaG91bGQgbWF0Y2gga25vd24gU1RBS0UgUkxQIGVuY29kaW5nIGFuZCBwcmVoYXNoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gRnJvbSBzdGFrZV9wbGVkZ2UudHh0IC0gc3VjY2Vzc2Z1bCBTVEFLRSB0cmFuc2FjdGlvblxuICAgICAgLy8gVFggSUQ6IDRYaFVUcmtoeHIxUm1VUWJYVVZSd2JOWjZwS0VZckFWbzV5bWRNWTQxZlM1XG4gICAgICBjb25zdCBhbmNob3JCYXNlNTggPSAnOEpSMnJENURlam5NMk51VlNxcUdhNjhkZnllNlpLcnVUOXJkaDJDbjRCOHknO1xuICAgICAgY29uc3QgYW5jaG9yQnl0ZXMgPSBkZWNvZGVCYXNlNTgoYW5jaG9yQmFzZTU4KTtcblxuICAgICAgY29uc3Qgc3Rha2VCdWlsZGVyID0gbmV3IElyeXNDb21taXRtZW50VHJhbnNhY3Rpb25CdWlsZGVyKHRlc3RBcGlVcmwsIHRlc3RuZXRDaGFpbklkKTtcblxuICAgICAgc3Rha2VCdWlsZGVyXG4gICAgICAgIC5zZXRDb21taXRtZW50VHlwZSh7IHR5cGU6IENvbW1pdG1lbnRUeXBlSWQuU1RBS0UgfSlcbiAgICAgICAgLnNldEZlZSgxMDBuKVxuICAgICAgICAuc2V0VmFsdWUoMjAwMDAwMDAwMDAwMDAwMDAwMDAwMDBuKSAvLyAyMDAwMCBJUllTXG4gICAgICAgIC5zZXRTaWduZXIodGVzdG5ldFNpZ25lckJ5dGVzKVxuICAgICAgICAuc2V0QW5jaG9yKGFuY2hvckJ5dGVzKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc3Rha2VCdWlsZGVyLmJ1aWxkKCk7XG5cbiAgICAgIGNvbnN0IGV4cGVjdGVkUmxwID1cbiAgICAgICAgJzB4Zjg0NzAyYTA2Yzc3ZGFlYmMyZGI0ZTU3MmU0ZjI5Njk4M2QxNDEzZmMxMGQ0ODUyZTBmYWJmZGI4MzIzYzljNjlhMmI4NScgK1xuICAgICAgICAnOWU5NDIyZjljOWYxODQ1ZDliNmMyMmI5NmVmMzVlNDZlMjY1YWM0YWYzMGMwMTgyMDRmNjY0OGEwNDNjMzNjMTkzNzU2NDgwMDAwMCc7XG4gICAgICBjb25zdCBhY3R1YWxSbHAgPSAnMHgnICsgQnVmZmVyLmZyb20ocmVzdWx0LnJscEVuY29kZWQpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGFjdHVhbFJscC5zaG91bGQuZXF1YWwoZXhwZWN0ZWRSbHApO1xuXG4gICAgICBjb25zdCBleHBlY3RlZFByZWhhc2ggPSAnMHhlNmZlNTc4MTBjMTI3ODVlM2NlNWZhNjRlMmViNGRhMTIwYjg5ZWMwZTQ2OTIxMzcxNTkxNmFiZjM2MzU4ZDAxJztcbiAgICAgIGNvbnN0IGFjdHVhbFByZWhhc2ggPSAnMHgnICsgQnVmZmVyLmZyb20ocmVzdWx0LnByZWhhc2gpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGFjdHVhbFByZWhhc2guc2hvdWxkLmVxdWFsKGV4cGVjdGVkUHJlaGFzaCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG1hdGNoIGtub3duIFBMRURHRSBSTFAgZW5jb2RpbmcgYW5kIHByZWhhc2gnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBGcm9tIHN0YWtlX3BsZWRnZS50eHQgLSBzdWNjZXNzZnVsIFBMRURHRSB0cmFuc2FjdGlvblxuICAgICAgLy8gVFggSUQ6IEVzZGllc0M1OFM4ZWVZMVNITTVqVGZ5ODR6WXhGTVVkS0Y4OVl0cjZQeU5iXG4gICAgICBjb25zdCBhbmNob3JCYXNlNTggPSAnalVTaEpQVUFDVzRieFVTdlpqaTY1UTk2TWFxS0RoN0FGRkFMS25rYXBCbic7XG4gICAgICBjb25zdCBhbmNob3JCeXRlcyA9IGRlY29kZUJhc2U1OChhbmNob3JCYXNlNTgpO1xuXG4gICAgICBjb25zdCBwbGVkZ2VCdWlsZGVyID0gbmV3IElyeXNDb21taXRtZW50VHJhbnNhY3Rpb25CdWlsZGVyKHRlc3RBcGlVcmwsIHRlc3RuZXRDaGFpbklkKTtcblxuICAgICAgcGxlZGdlQnVpbGRlclxuICAgICAgICAuc2V0Q29tbWl0bWVudFR5cGUoeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlBMRURHRSwgcGxlZGdlQ291bnQ6IDBuIH0pXG4gICAgICAgIC5zZXRGZWUoMTAwbilcbiAgICAgICAgLnNldFZhbHVlKDk1MDAwMDAwMDAwMDAwMDAwMDAwMG4pIC8vIDk1MCBJUllTXG4gICAgICAgIC5zZXRTaWduZXIodGVzdG5ldFNpZ25lckJ5dGVzKVxuICAgICAgICAuc2V0QW5jaG9yKGFuY2hvckJ5dGVzKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGxlZGdlQnVpbGRlci5idWlsZCgpO1xuXG4gICAgICBjb25zdCBleHBlY3RlZFJscCA9XG4gICAgICAgICcweGY4NDgwMmEwMGFlMTZjODQ3NmJiZGUyZjI4YjJlNDYyOWQzOTNkZmU2ZmE3YWZmY2YwYTBjNDY1NGY4MjQ2YTliYTc4OTcwNTk0JyArXG4gICAgICAgICcyMmY5YzlmMTg0NWQ5YjZjMjJiOTZlZjM1ZTQ2ZTI2NWFjNGFmMzBjYzIwMjgwODIwNGY2NjQ4OTMzN2ZlNWZlYWYyZDE4MDAwMCc7XG4gICAgICBjb25zdCBhY3R1YWxSbHAgPSAnMHgnICsgQnVmZmVyLmZyb20ocmVzdWx0LnJscEVuY29kZWQpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGFjdHVhbFJscC5zaG91bGQuZXF1YWwoZXhwZWN0ZWRSbHApO1xuXG4gICAgICBjb25zdCBleHBlY3RlZFByZWhhc2ggPSAnMHhmZTA3YzJmM2M2ZTUwZDljOWUyY2ZmNTdmNmQ3MDE1YjQ1MjhmNDI1YjYxMzJmNTY3ZTI2YmJhNzQ1MjI4MTAyJztcbiAgICAgIGNvbnN0IGFjdHVhbFByZWhhc2ggPSAnMHgnICsgQnVmZmVyLmZyb20ocmVzdWx0LnByZWhhc2gpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGFjdHVhbFByZWhhc2guc2hvdWxkLmVxdWFsKGV4cGVjdGVkUHJlaGFzaCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vID09PSBFZGdlIENhc2UgVGVzdHMgPT09XG5cbiAgZGVzY3JpYmUoJ2VkZ2UgY2FzZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBoYW5kbGUgemVybyBmZWUgYW5kIHZhbHVlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYnVpbGRlclxuICAgICAgICAuc2V0Q29tbWl0bWVudFR5cGUoeyB0eXBlOiBDb21taXRtZW50VHlwZUlkLlNUQUtFIH0pXG4gICAgICAgIC5zZXRGZWUoMG4pXG4gICAgICAgIC5zZXRWYWx1ZSgwbilcbiAgICAgICAgLnNldFNpZ25lcih0ZXN0U2lnbmVyKVxuICAgICAgICAuc2V0QW5jaG9yKHRlc3RBbmNob3IpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBidWlsZGVyLmJ1aWxkKCk7XG4gICAgICByZXN1bHQucHJlaGFzaC5sZW5ndGguc2hvdWxkLmVxdWFsKDMyKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gPT09IEFuY2hvciBGZXRjaCBUZXN0cyA9PT1cblxuICBkZXNjcmliZSgnZmV0Y2hBbmNob3InLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBmZXRjaCBhbmQgZGVjb2RlIGJhc2U1OCBhbmNob3IgZnJvbSBBUEknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBtb2NrQW5jaG9yQmFzZTU4ID0gZW5jb2RlQmFzZTU4KHRlc3RBbmNob3IpO1xuICAgICAgY29uc3Qgc2NvcGUgPSBub2NrKCdodHRwczovL3Rlc3RuZXQtbm9kZTEuaXJ5cy54eXonKVxuICAgICAgICAuZ2V0KCcvdjEvYW5jaG9yJylcbiAgICAgICAgLnJlcGx5KDIwMCwgeyBibG9ja0hhc2g6IG1vY2tBbmNob3JCYXNlNTggfSk7XG5cbiAgICAgIGNvbnN0IGFuY2hvciA9IGF3YWl0IGJ1aWxkZXIuZmV0Y2hBbmNob3IoKTtcbiAgICAgIGFuY2hvci5zaG91bGQuYmUuaW5zdGFuY2VPZihVaW50OEFycmF5KTtcbiAgICAgIGFuY2hvci5sZW5ndGguc2hvdWxkLmVxdWFsKDMyKTtcbiAgICAgIEJ1ZmZlci5mcm9tKGFuY2hvcikuZXF1YWxzKEJ1ZmZlci5mcm9tKHRlc3RBbmNob3IpKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgc2NvcGUuZG9uZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBub24tMjAwIHJlc3BvbnNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgc2NvcGUgPSBub2NrKCdodHRwczovL3Rlc3RuZXQtbm9kZTEuaXJ5cy54eXonKS5nZXQoJy92MS9hbmNob3InKS5yZXBseSg1MDAsICdJbnRlcm5hbCBTZXJ2ZXIgRXJyb3InKTtcblxuICAgICAgYXdhaXQgYnVpbGRlci5mZXRjaEFuY2hvcigpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL0ludGVybmFsIFNlcnZlciBFcnJvci8pO1xuICAgICAgc2NvcGUuZG9uZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiBhbmNob3IgZGVjb2RlcyB0byB3cm9uZyBsZW5ndGgnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBzaG9ydEFuY2hvciA9IGVuY29kZUJhc2U1OChuZXcgVWludDhBcnJheSgxNikpOyAvLyAxNiBieXRlcyBpbnN0ZWFkIG9mIDMyXG4gICAgICBjb25zdCBzY29wZSA9IG5vY2soJ2h0dHBzOi8vdGVzdG5ldC1ub2RlMS5pcnlzLnh5eicpLmdldCgnL3YxL2FuY2hvcicpLnJlcGx5KDIwMCwgeyBibG9ja0hhc2g6IHNob3J0QW5jaG9yIH0pO1xuXG4gICAgICBhd2FpdCBidWlsZGVyLmZldGNoQW5jaG9yKCkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvRXhwZWN0ZWQgMzIgYnl0ZXMvKTtcbiAgICAgIHNjb3BlLmRvbmUoKTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==