@bitgo-beta/sdk-coin-hbar 1.0.2-beta.232 → 1.0.2-beta.2321

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 (93) hide show
  1. package/dist/src/hbar.d.ts +82 -11
  2. package/dist/src/hbar.d.ts.map +1 -1
  3. package/dist/src/hbar.js +392 -25
  4. package/dist/src/hbarToken.d.ts +4 -1
  5. package/dist/src/hbarToken.d.ts.map +1 -1
  6. package/dist/src/hbarToken.js +12 -3
  7. package/dist/src/index.js +6 -2
  8. package/dist/src/lib/accountUpdateBuilder.d.ts +49 -0
  9. package/dist/src/lib/accountUpdateBuilder.d.ts.map +1 -0
  10. package/dist/src/lib/accountUpdateBuilder.js +122 -0
  11. package/dist/src/lib/coinTransferBuilder.d.ts +1 -1
  12. package/dist/src/lib/coinTransferBuilder.d.ts.map +1 -1
  13. package/dist/src/lib/coinTransferBuilder.js +12 -28
  14. package/dist/src/lib/constants.d.ts +2 -1
  15. package/dist/src/lib/constants.d.ts.map +1 -1
  16. package/dist/src/lib/constants.js +3 -2
  17. package/dist/src/lib/iface.d.ts +10 -1
  18. package/dist/src/lib/iface.d.ts.map +1 -1
  19. package/dist/src/lib/iface.js +1 -1
  20. package/dist/src/lib/index.d.ts +2 -0
  21. package/dist/src/lib/index.d.ts.map +1 -1
  22. package/dist/src/lib/index.js +26 -10
  23. package/dist/src/lib/keyPair.d.ts +1 -0
  24. package/dist/src/lib/keyPair.d.ts.map +1 -1
  25. package/dist/src/lib/keyPair.js +7 -7
  26. package/dist/src/lib/tokenAssociateBuilder.js +9 -28
  27. package/dist/src/lib/tokenTransferBuilder.d.ts +1 -1
  28. package/dist/src/lib/tokenTransferBuilder.d.ts.map +1 -1
  29. package/dist/src/lib/tokenTransferBuilder.js +15 -31
  30. package/dist/src/lib/transaction.d.ts +7 -1
  31. package/dist/src/lib/transaction.d.ts.map +1 -1
  32. package/dist/src/lib/transaction.js +97 -41
  33. package/dist/src/lib/transactionBuilder.d.ts +1 -1
  34. package/dist/src/lib/transactionBuilder.d.ts.map +1 -1
  35. package/dist/src/lib/transactionBuilder.js +18 -37
  36. package/dist/src/lib/transactionBuilderFactory.d.ts +5 -0
  37. package/dist/src/lib/transactionBuilderFactory.d.ts.map +1 -1
  38. package/dist/src/lib/transactionBuilderFactory.js +12 -3
  39. package/dist/src/lib/transferBuilder.d.ts +1 -1
  40. package/dist/src/lib/transferBuilder.d.ts.map +1 -1
  41. package/dist/src/lib/transferBuilder.js +5 -24
  42. package/dist/src/lib/utils.d.ts +18 -1
  43. package/dist/src/lib/utils.d.ts.map +1 -1
  44. package/dist/src/lib/utils.js +112 -41
  45. package/dist/src/lib/walletInitializationBuilder.js +12 -28
  46. package/dist/src/seedValidator.js +24 -10
  47. package/dist/test/fixtures/hbar.d.ts +6 -0
  48. package/dist/test/fixtures/hbar.d.ts.map +1 -0
  49. package/dist/test/fixtures/hbar.js +9 -0
  50. package/dist/test/resources/hbar.d.ts +67 -0
  51. package/dist/test/resources/hbar.d.ts.map +1 -0
  52. package/dist/test/resources/hbar.js +73 -0
  53. package/dist/test/unit/fixtures/hbarBackupKey.d.ts +4 -0
  54. package/dist/test/unit/fixtures/hbarBackupKey.d.ts.map +1 -0
  55. package/dist/test/unit/fixtures/hbarBackupKey.js +10 -0
  56. package/dist/test/unit/getBuilderFactory.d.ts +3 -0
  57. package/dist/test/unit/getBuilderFactory.d.ts.map +1 -0
  58. package/dist/test/unit/getBuilderFactory.js +10 -0
  59. package/dist/test/unit/hbar.d.ts +2 -0
  60. package/dist/test/unit/hbar.d.ts.map +1 -0
  61. package/dist/test/unit/hbar.js +1510 -0
  62. package/dist/test/unit/hbarToken.d.ts +2 -0
  63. package/dist/test/unit/hbarToken.d.ts.map +1 -0
  64. package/dist/test/unit/hbarToken.js +34 -0
  65. package/dist/test/unit/keyPair.d.ts +2 -0
  66. package/dist/test/unit/keyPair.d.ts.map +1 -0
  67. package/dist/test/unit/keyPair.js +179 -0
  68. package/dist/test/unit/transaction.d.ts +2 -0
  69. package/dist/test/unit/transaction.d.ts.map +1 -0
  70. package/dist/test/unit/transaction.js +94 -0
  71. package/dist/test/unit/transactionBuilder/accountUpdateBuilder.d.ts +2 -0
  72. package/dist/test/unit/transactionBuilder/accountUpdateBuilder.d.ts.map +1 -0
  73. package/dist/test/unit/transactionBuilder/accountUpdateBuilder.js +295 -0
  74. package/dist/test/unit/transactionBuilder/tokenAssociateBuilder.d.ts +2 -0
  75. package/dist/test/unit/transactionBuilder/tokenAssociateBuilder.d.ts.map +1 -0
  76. package/dist/test/unit/transactionBuilder/tokenAssociateBuilder.js +215 -0
  77. package/dist/test/unit/transactionBuilder/tokenTransferBuilder.d.ts +2 -0
  78. package/dist/test/unit/transactionBuilder/tokenTransferBuilder.d.ts.map +1 -0
  79. package/dist/test/unit/transactionBuilder/tokenTransferBuilder.js +329 -0
  80. package/dist/test/unit/transactionBuilder/transferBuilder.d.ts +2 -0
  81. package/dist/test/unit/transactionBuilder/transferBuilder.d.ts.map +1 -0
  82. package/dist/test/unit/transactionBuilder/transferBuilder.js +353 -0
  83. package/dist/test/unit/transactionBuilder/walletInitialization.d.ts +2 -0
  84. package/dist/test/unit/transactionBuilder/walletInitialization.d.ts.map +1 -0
  85. package/dist/test/unit/transactionBuilder/walletInitialization.js +214 -0
  86. package/dist/test/unit/utils.d.ts +2 -0
  87. package/dist/test/unit/utils.d.ts.map +1 -0
  88. package/dist/test/unit/utils.js +275 -0
  89. package/dist/tsconfig.tsbuildinfo +1 -0
  90. package/package.json +17 -14
  91. package/.eslintignore +0 -5
  92. package/.mocharc.yml +0 -8
  93. package/CHANGELOG.md +0 -106
@@ -0,0 +1,1510 @@
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 assert_1 = __importDefault(require("assert"));
40
+ const _ = __importStar(require("lodash"));
41
+ const nock_1 = __importDefault(require("nock"));
42
+ const sinon_1 = __importDefault(require("sinon"));
43
+ const crypto_1 = require("crypto");
44
+ const bignumber_js_1 = require("bignumber.js");
45
+ const sdk_test_1 = require("@bitgo-beta/sdk-test");
46
+ const sdk_api_1 = require("@bitgo-beta/sdk-api");
47
+ const sdk_core_1 = require("@bitgo-beta/sdk-core");
48
+ const TestData = __importStar(require("../fixtures/hbar"));
49
+ const src_1 = require("../../src");
50
+ const getBuilderFactory_1 = require("./getBuilderFactory");
51
+ const hbarBackupKey_1 = require("./fixtures/hbarBackupKey");
52
+ describe('Hedera Hashgraph:', function () {
53
+ let bitgo;
54
+ let basecoin;
55
+ let token;
56
+ before(function () {
57
+ bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
58
+ bitgo.safeRegister('thbar', src_1.Thbar.createInstance);
59
+ bitgo.safeRegister('hbar', src_1.Hbar.createInstance);
60
+ src_1.HbarToken.createTokenConstructors().forEach(({ name, coinConstructor }) => {
61
+ bitgo.safeRegister(name, coinConstructor);
62
+ });
63
+ bitgo.initializeTestVars();
64
+ basecoin = bitgo.coin('thbar');
65
+ token = bitgo.coin('thbar:usdc');
66
+ });
67
+ it('should instantiate the coin', function () {
68
+ const basecoin = bitgo.coin('hbar');
69
+ basecoin.should.be.an.instanceof(src_1.Hbar);
70
+ });
71
+ it('should check valid addresses', async function () {
72
+ const badAddresses = [
73
+ '',
74
+ '0.0',
75
+ 'YZ09fd-',
76
+ '0.0.0.a',
77
+ 'sadasdfggg',
78
+ '0.2.a.b',
79
+ '0.0.100?=sksjd',
80
+ '0.0.41098?memoId=',
81
+ ];
82
+ const goodAddresses = [
83
+ '0',
84
+ '0.0.0',
85
+ '0.0.41098',
86
+ '0.0.0?memoId=84',
87
+ '0.0.41098',
88
+ '0.0.41098?memoId=2aaaaa',
89
+ '0.0.41098?memoId=1',
90
+ ];
91
+ badAddresses.map((addr) => {
92
+ basecoin.isValidAddress(addr).should.equal(false);
93
+ });
94
+ goodAddresses.map((addr) => {
95
+ basecoin.isValidAddress(addr).should.equal(true);
96
+ });
97
+ const hexAddress = '0x23C3E227BE97281A70A549c7dDB8d5Caad3E7C84';
98
+ basecoin.isValidAddress(hexAddress).should.equal(false);
99
+ });
100
+ it('should explain a transaction', async function () {
101
+ const tx = JSON.parse(TestData.rawTransactionForExplain);
102
+ const explain = await basecoin.explainTransaction(tx);
103
+ explain.id.should.equal('0.0.43285@1600529800.643093586');
104
+ explain.outputAmount.should.equal('2200000000');
105
+ explain.timestamp.should.equal('1600529800.643093586');
106
+ explain.expiration.should.equal('180');
107
+ explain.outputs[0].amount.should.equal('2200000000');
108
+ explain.outputs[0].address.should.equal('0.0.43283');
109
+ explain.outputs[0].memo.should.equal('1');
110
+ explain.fee.should.equal(1160407);
111
+ explain.changeAmount.should.equal('0');
112
+ });
113
+ it('should explain a token transfer transaction', async function () {
114
+ const tokenTransferParam = {
115
+ txHex: TestData.UNSIGNED_TOKEN_TRANSFER,
116
+ feeInfo: {
117
+ size: 1000,
118
+ fee: 1160407,
119
+ feeRate: 1160407,
120
+ },
121
+ };
122
+ const explain = await basecoin.explainTransaction(tokenTransferParam);
123
+ explain.id.should.equal('0.0.81320@1596110493.372646570');
124
+ explain.outputAmount.should.equal('0');
125
+ explain.timestamp.should.equal('1596110493.372646570');
126
+ explain.expiration.should.equal('180');
127
+ explain.outputs[0].amount.should.equal('10');
128
+ explain.outputs[0].address.should.equal('0.0.75861');
129
+ explain.outputs[0].memo.should.equal('');
130
+ explain.outputs[0].tokenName.should.equal('thbar:usdc');
131
+ explain.fee.should.equal(1160407);
132
+ explain.changeAmount.should.equal('0');
133
+ });
134
+ it('should explain a multirecipients transfer transaction', async function () {
135
+ const multiTransferParam = {
136
+ txHex: TestData.UNSIGNED_MULTI_TRANSFER,
137
+ feeInfo: {
138
+ size: 1000,
139
+ fee: 1160407,
140
+ feeRate: 1160407,
141
+ },
142
+ };
143
+ const explain = await basecoin.explainTransaction(multiTransferParam);
144
+ explain.id.should.equal('0.0.81320@1596110493.372646570');
145
+ explain.outputAmount.should.equal('25');
146
+ explain.expiration.should.equal('180');
147
+ explain.outputs[0].amount.should.equal('10');
148
+ explain.outputs[0].address.should.equal('0.0.75861');
149
+ explain.outputs[0].memo.should.equal('');
150
+ explain.outputs[1].amount.should.equal('15');
151
+ explain.outputs[1].address.should.equal('0.0.78963');
152
+ explain.fee.should.equal(1160407);
153
+ explain.changeAmount.should.equal('0');
154
+ });
155
+ it('should explain a multirecipients token transfer transaction', async function () {
156
+ const tokenMultiTransferParam = {
157
+ txHex: TestData.UNSIGNED_TOKEN_MULTI_TRANSFER,
158
+ feeInfo: {
159
+ size: 1000,
160
+ fee: 1160407,
161
+ feeRate: 1160407,
162
+ },
163
+ };
164
+ const explain = await basecoin.explainTransaction(tokenMultiTransferParam);
165
+ explain.id.should.equal('0.0.81320@1596110493.372646570');
166
+ explain.outputAmount.should.equal('0');
167
+ explain.timestamp.should.equal('1596110493.372646570');
168
+ explain.expiration.should.equal('180');
169
+ explain.outputs[0].amount.should.equal('10');
170
+ explain.outputs[0].address.should.equal('0.0.75861');
171
+ explain.outputs[0].memo.should.equal('');
172
+ explain.outputs[0].tokenName.should.equal('thbar:usdc');
173
+ explain.outputs[1].amount.should.equal('15');
174
+ explain.outputs[1].address.should.equal('0.0.78963');
175
+ explain.outputs[1].tokenName.should.equal('thbar:usdc');
176
+ explain.fee.should.equal(1160407);
177
+ explain.changeAmount.should.equal('0');
178
+ });
179
+ it('should explain a token associate transaction', async function () {
180
+ const tokenAssociateParam = {
181
+ txHex: TestData.UNSIGNED_TOKEN_ASSOCIATE,
182
+ feeInfo: {
183
+ size: 1000,
184
+ fee: 1160407,
185
+ feeRate: 1160407,
186
+ },
187
+ };
188
+ const explain = await basecoin.explainTransaction(tokenAssociateParam);
189
+ explain.id.should.equal('0.0.81320@1596110493.372646570');
190
+ explain.outputAmount.should.equal('0');
191
+ explain.timestamp.should.equal('1596110493.372646570');
192
+ explain.expiration.should.equal('180');
193
+ explain.outputs[0].amount.should.equal('0');
194
+ explain.outputs[0].address.should.equal('0.0.81320');
195
+ explain.outputs[0].memo.should.equal('');
196
+ explain.outputs[0].tokenName.should.equal('thbar:usdc');
197
+ explain.fee.should.equal(1160407);
198
+ explain.changeAmount.should.equal('0');
199
+ });
200
+ it('should explain an account update (staking) transaction', async function () {
201
+ const sourceAccountId = '0.0.81320';
202
+ const factory = (0, getBuilderFactory_1.getBuilderFactory)('thbar');
203
+ const txBuilder = factory.getAccountUpdateBuilder();
204
+ txBuilder.fee({ fee: '1000000000' });
205
+ txBuilder.source({ address: sourceAccountId });
206
+ txBuilder.stakedNodeId(3);
207
+ txBuilder.declineStakingReward(false);
208
+ txBuilder.node({ nodeId: '0.0.2345' });
209
+ txBuilder.startTime('1596110493.372646570');
210
+ const tx = await txBuilder.build();
211
+ const txHex = tx.toBroadcastFormat();
212
+ const explain = await basecoin.explainTransaction({
213
+ txHex,
214
+ feeInfo: {
215
+ size: 1000,
216
+ fee: 1160407,
217
+ feeRate: 1160407,
218
+ },
219
+ });
220
+ explain.id.should.equal(sourceAccountId + '@1596110493.372646570');
221
+ explain.outputAmount.should.equal('0');
222
+ explain.timestamp.should.equal('1596110493.372646570');
223
+ explain.outputs.length.should.equal(1);
224
+ explain.outputs[0].amount.should.equal('0');
225
+ explain.outputs[0].address.should.equal(sourceAccountId);
226
+ explain.outputs[0].memo.should.equal('');
227
+ explain.fee.should.equal(1160407);
228
+ explain.changeAmount.should.equal('0');
229
+ });
230
+ it('should explain an unstake (account update with nodeId -1) transaction', async function () {
231
+ const sourceAccountId = '0.0.81320';
232
+ const factory = (0, getBuilderFactory_1.getBuilderFactory)('thbar');
233
+ const txBuilder = factory.getAccountUpdateBuilder();
234
+ txBuilder.fee({ fee: '1000000000' });
235
+ txBuilder.source({ address: sourceAccountId });
236
+ txBuilder.stakedNodeId(-1);
237
+ txBuilder.node({ nodeId: '0.0.2345' });
238
+ txBuilder.startTime('1596110493.372646570');
239
+ const tx = await txBuilder.build();
240
+ const txHex = tx.toBroadcastFormat();
241
+ const explain = await basecoin.explainTransaction({
242
+ txHex,
243
+ feeInfo: {
244
+ size: 1000,
245
+ fee: 1160407,
246
+ feeRate: 1160407,
247
+ },
248
+ });
249
+ explain.id.should.equal(sourceAccountId + '@1596110493.372646570');
250
+ explain.outputAmount.should.equal('0');
251
+ explain.timestamp.should.equal('1596110493.372646570');
252
+ explain.outputs.length.should.equal(1);
253
+ explain.outputs[0].amount.should.equal('0');
254
+ explain.outputs[0].address.should.equal(sourceAccountId);
255
+ explain.outputs[0].memo.should.equal('');
256
+ explain.fee.should.equal(1160407);
257
+ explain.changeAmount.should.equal('0');
258
+ });
259
+ it('should verify isWalletAddress', async function () {
260
+ const baseAddress = '0.0.41098';
261
+ const validAddress1 = '0.0.41098?memoId=1';
262
+ const validAddress2 = '0.0.41098?memoId=2';
263
+ const unrelatedValidAddress = '0.1.41098?memoId=1';
264
+ const invalidAddress = '0.0.0.a';
265
+ (await basecoin.isWalletAddress({ address: validAddress1, baseAddress })).should.true();
266
+ (await basecoin.isWalletAddress({ address: validAddress2, baseAddress })).should.true();
267
+ (await basecoin.isWalletAddress({ address: validAddress2, baseAddress: validAddress1 })).should.true();
268
+ (await basecoin.isWalletAddress({ address: unrelatedValidAddress, baseAddress })).should.false();
269
+ assert_1.default.rejects(async () => basecoin.isWalletAddress({ address: invalidAddress, baseAddress }), `invalid address ${invalidAddress}`);
270
+ });
271
+ describe('Keypairs:', () => {
272
+ it('should generate a keypair from random seed', function () {
273
+ const keyPair = basecoin.generateKeyPair();
274
+ keyPair.should.have.property('pub');
275
+ keyPair.should.have.property('prv');
276
+ basecoin.isValidPub(keyPair.pub).should.equal(true);
277
+ });
278
+ it('should generate a keypair from a seed', function () {
279
+ const seedText = '80350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f';
280
+ const seed = Buffer.from(seedText, 'hex');
281
+ const keyPair = basecoin.generateKeyPair(seed);
282
+ keyPair.prv.should.equal('302e020100300506032b65700422042080350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f');
283
+ keyPair.pub.should.equal('302a300506032b65700321009cc402b5c75214269c2826e3c6119377cab6c367601338661c87a4e07c6e0333');
284
+ });
285
+ it('should validate a stellar seed', function () {
286
+ basecoin.isStellarSeed('SBMWLNV75BPI2VB4G27RWOMABVRTSSF7352CCYGVELZDSHCXWCYFKXIX').should.ok();
287
+ });
288
+ it('should convert a stellar seed to an hbar prv', function () {
289
+ const seed = basecoin.convertFromStellarSeed('SBMWLNV75BPI2VB4G27RWOMABVRTSSF7352CCYGVELZDSHCXWCYFKXIX');
290
+ seed.should.equal('302e020100300506032b6570042204205965b6bfe85e8d543c36bf1b39800d633948bfdf742160d522f2391c57b0b055');
291
+ });
292
+ });
293
+ describe('Verify Transaction:', () => {
294
+ let newTxPrebuild;
295
+ let newTxParams;
296
+ let newTxParamsWithError;
297
+ let newTxParamsWithExtraData;
298
+ const txPrebuild = {
299
+ recipients: [
300
+ {
301
+ address: 'lionteste212',
302
+ amount: '1000',
303
+ },
304
+ ],
305
+ txHex: TestData.UNSIGNED_MULTI_TRANSFER,
306
+ txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2',
307
+ isVotingTransaction: false,
308
+ coin: 'thbar',
309
+ feeInfo: {
310
+ size: 1000,
311
+ fee: 1160407,
312
+ feeRate: 1160407,
313
+ },
314
+ };
315
+ const txParams = {
316
+ txPrebuild,
317
+ recipients: [
318
+ {
319
+ address: '0.0.75861',
320
+ amount: '10',
321
+ },
322
+ {
323
+ address: '0.0.78963',
324
+ amount: '15',
325
+ },
326
+ ],
327
+ };
328
+ const memo = { value: '' };
329
+ const txParamsWithError = {
330
+ txPrebuild,
331
+ recipients: [
332
+ {
333
+ address: '0.0.75861',
334
+ amount: '1000',
335
+ },
336
+ ],
337
+ };
338
+ const txParamsWithExtraData = {
339
+ txPrebuild,
340
+ recipients: [
341
+ {
342
+ address: '0.0.75861',
343
+ amount: '10',
344
+ data: undefined,
345
+ },
346
+ {
347
+ address: '0.0.78963',
348
+ amount: '15',
349
+ data: undefined,
350
+ },
351
+ ],
352
+ };
353
+ const walletData = {
354
+ id: '5b34252f1bf349930e34020a00000000',
355
+ coin: 'thbar',
356
+ keys: [
357
+ '5b3424f91bf349930e34017500000000',
358
+ '5b3424f91bf349930e34017600000000',
359
+ '5b3424f91bf349930e34017700000000',
360
+ ],
361
+ coinSpecific: {
362
+ baseAddress: '0.0.2935',
363
+ },
364
+ multisigType: 'onchain',
365
+ };
366
+ const walletObj = new sdk_core_1.Wallet(bitgo, basecoin, walletData);
367
+ before(function () {
368
+ newTxPrebuild = () => {
369
+ return _.cloneDeep(txPrebuild);
370
+ };
371
+ newTxParams = () => {
372
+ return _.cloneDeep(txParams);
373
+ };
374
+ newTxParamsWithError = () => {
375
+ return _.cloneDeep(txParamsWithError);
376
+ };
377
+ newTxParamsWithExtraData = () => {
378
+ return _.cloneDeep(txParamsWithExtraData);
379
+ };
380
+ });
381
+ it('should verify native transfer transactions', async function () {
382
+ const txParams = newTxParams();
383
+ const txPrebuild = newTxPrebuild();
384
+ const validTransaction = await basecoin.verifyTransaction({
385
+ txParams,
386
+ txPrebuild,
387
+ memo,
388
+ wallet: walletObj,
389
+ });
390
+ validTransaction.should.equal(true);
391
+ });
392
+ it('should fail verify when input `recipients` is absent', async function () {
393
+ const txParams = newTxParams();
394
+ txParams.recipients = undefined;
395
+ const txPrebuild = newTxPrebuild();
396
+ await basecoin
397
+ .verifyTransaction({ txParams, txPrebuild, memo: memo, wallet: walletObj })
398
+ .should.be.rejectedWith('missing required tx params property recipients');
399
+ });
400
+ it('should fail verify transactions when have different recipients', async function () {
401
+ const txParams = newTxParamsWithError();
402
+ const txPrebuild = newTxPrebuild();
403
+ await basecoin
404
+ .verifyTransaction({ txParams, txPrebuild, memo, wallet: walletObj })
405
+ .should.be.rejectedWith('Tx outputs does not match with expected txParams recipients');
406
+ });
407
+ it('should succeed to verify transactions when recipients has extra data', async function () {
408
+ const txParams = newTxParamsWithExtraData();
409
+ const txPrebuild = newTxPrebuild();
410
+ const validTransaction = await basecoin.verifyTransaction({
411
+ txParams,
412
+ txPrebuild,
413
+ memo,
414
+ wallet: walletObj,
415
+ });
416
+ validTransaction.should.equal(true);
417
+ });
418
+ it('should verify create associated token account transaction', async function () {
419
+ const txParams = newTxParams();
420
+ const txPrebuild = newTxPrebuild();
421
+ txPrebuild.txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
422
+ txParams.type = 'enabletoken';
423
+ txParams.recipients = [
424
+ {
425
+ address: '0.0.81320',
426
+ amount: '0',
427
+ tokenName: 'thbar:usdc',
428
+ },
429
+ ];
430
+ const validTransaction = await basecoin.verifyTransaction({
431
+ txParams,
432
+ txPrebuild,
433
+ memo,
434
+ wallet: walletObj,
435
+ verification: { verifyTokenEnablement: true },
436
+ });
437
+ validTransaction.should.equal(true);
438
+ });
439
+ it('should fail verify create associated token account transaction with mismatch recipients', async function () {
440
+ const txParams = newTxParams();
441
+ const txPrebuild = newTxPrebuild();
442
+ txPrebuild.txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
443
+ txParams.type = 'enabletoken';
444
+ txParams.recipients = [
445
+ {
446
+ address: '0.0.81321',
447
+ amount: '0',
448
+ tokenName: 'thbar:usdc',
449
+ },
450
+ ];
451
+ await basecoin
452
+ .verifyTransaction({
453
+ txParams,
454
+ txPrebuild,
455
+ memo,
456
+ wallet: walletObj,
457
+ verification: { verifyTokenEnablement: true },
458
+ })
459
+ .should.be.rejectedWith('Invalid token enablement transaction: Expected account 0.0.81321, got 0.0.81320');
460
+ });
461
+ it('should verify token transfer transaction', async function () {
462
+ const txParams = newTxParams();
463
+ const txPrebuild = newTxPrebuild();
464
+ txPrebuild.txHex = TestData.UNSIGNED_TOKEN_MULTI_TRANSFER;
465
+ txParams.recipients = [
466
+ {
467
+ address: '0.0.75861',
468
+ amount: '10',
469
+ tokenName: 'thbar:usdc',
470
+ },
471
+ {
472
+ address: '0.0.78963',
473
+ amount: '15',
474
+ tokenName: 'thbar:usdc',
475
+ },
476
+ ];
477
+ const validTransaction = await token.verifyTransaction({
478
+ txParams,
479
+ txPrebuild,
480
+ memo,
481
+ wallet: walletObj,
482
+ });
483
+ validTransaction.should.equal(true);
484
+ });
485
+ it('should verify token transfer transaction with any token name on token base coin', async function () {
486
+ const txParams = newTxParams();
487
+ const txPrebuild = newTxPrebuild();
488
+ txPrebuild.txHex = TestData.UNSIGNED_TOKEN_MULTI_TRANSFER;
489
+ txParams.recipients = [
490
+ {
491
+ address: '0.0.75861',
492
+ amount: '10',
493
+ tokenName: 'thbar:usdc',
494
+ },
495
+ {
496
+ address: '0.0.78963',
497
+ amount: '15',
498
+ },
499
+ ];
500
+ (await token.verifyTransaction({ txParams, txPrebuild, memo, wallet: walletObj })).should.equal(true);
501
+ });
502
+ it('should fail to verify token transfer with mismatched recipients', async function () {
503
+ const txParams = newTxParams();
504
+ const txPrebuild = newTxPrebuild();
505
+ txPrebuild.txHex = TestData.UNSIGNED_TOKEN_MULTI_TRANSFER;
506
+ txParams.recipients = [
507
+ {
508
+ address: '0.0.75861',
509
+ amount: '11',
510
+ tokenName: 'thbar:usdc',
511
+ },
512
+ {
513
+ address: '0.0.78963',
514
+ amount: '15',
515
+ },
516
+ ];
517
+ await token
518
+ .verifyTransaction({ txParams, txPrebuild, memo, wallet: walletObj })
519
+ .should.be.rejectedWith('Tx outputs does not match with expected txParams recipients');
520
+ });
521
+ it('should fail to verify token transfer with incorrect token name', async function () {
522
+ const txParams = newTxParams();
523
+ const txPrebuild = newTxPrebuild();
524
+ txPrebuild.txHex = TestData.UNSIGNED_TOKEN_MULTI_TRANSFER;
525
+ txParams.recipients = [
526
+ {
527
+ address: '0.0.75861',
528
+ amount: '11',
529
+ tokenName: 'thbar:usdc',
530
+ },
531
+ {
532
+ address: '0.0.78963',
533
+ amount: '15',
534
+ tokenName: 'invalidtoken',
535
+ },
536
+ ];
537
+ await token
538
+ .verifyTransaction({ txParams, txPrebuild, memo, wallet: walletObj })
539
+ .should.be.rejectedWith('Incorrect token name specified in recipients');
540
+ });
541
+ it('should success to verify transfer having address with memo id', async function () {
542
+ const txParams = newTxParams();
543
+ const txPrebuild = newTxPrebuild();
544
+ txPrebuild.txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
545
+ txParams.type = 'enabletoken';
546
+ txParams.recipients = [
547
+ {
548
+ address: '0.0.81320?memoId=1',
549
+ amount: '0',
550
+ tokenName: 'thbar:usdc',
551
+ },
552
+ ];
553
+ const validTransaction = await basecoin.verifyTransaction({
554
+ txParams,
555
+ txPrebuild,
556
+ memo,
557
+ wallet: walletObj,
558
+ verification: { verifyTokenEnablement: true },
559
+ });
560
+ validTransaction.should.equal(true);
561
+ });
562
+ });
563
+ describe('Verify Token Enablement Transaction:', () => {
564
+ it('should verify a valid token enablement transaction with tokenName', async function () {
565
+ const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
566
+ const expectedToken = { tokenName: 'thbar:usdc' };
567
+ const expectedAccountId = '0.0.81320';
568
+ await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId);
569
+ });
570
+ it('should verify a valid token enablement transaction with tokenId', async function () {
571
+ const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
572
+ const expectedToken = { tokenId: '0.0.429274' }; // Actual tokenId for thbar:usdc
573
+ const expectedAccountId = '0.0.81320';
574
+ await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId);
575
+ });
576
+ it('should fail when txHex is missing', async function () {
577
+ await basecoin
578
+ .verifyTokenEnablementTransaction('', { tokenName: 'thbar:usdc' }, '0.0.81320')
579
+ .should.be.rejectedWith('Missing required parameters: txHex');
580
+ });
581
+ it('should fail when expectedAccountId is missing', async function () {
582
+ await basecoin
583
+ .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_ASSOCIATE, { tokenName: 'thbar:usdc' }, '')
584
+ .should.be.rejectedWith('Missing required parameters: expectedAccountId');
585
+ });
586
+ it('should fail when wallet platform sends spoofed transaction hex for token enablement', async function () {
587
+ // Create a valid transaction response structure from wallet platform with spoofed txHex
588
+ // The txHex looks like valid hex but contains malicious/invalid transaction data
589
+ const spoofedTxHex = '0a0c0a080800100018a8fb0410130a0c0a080800100018d5d0041014'; // Valid hex but invalid transaction
590
+ // Mock the API endpoints that will be called during token enablement
591
+ const bgUrl = sdk_core_1.common.Environments['mock'].uri;
592
+ // Mock the key endpoint needed for signing
593
+ (0, nock_1.default)(bgUrl)
594
+ .post('/api/v2/thbar/key/5b3424f91bf34993006eae94')
595
+ .reply(200, [
596
+ {
597
+ encryptedPrv: 'fakePrv',
598
+ },
599
+ ]);
600
+ // Mock the prebuild API response to return spoofed txHex
601
+ (0, nock_1.default)(bgUrl)
602
+ .post('/api/v2/thbar/wallet/5b34252f1bf34993006eae96/tx/build')
603
+ .reply(200, {
604
+ txHex: spoofedTxHex,
605
+ txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2',
606
+ recipients: [
607
+ {
608
+ address: '0.0.81320',
609
+ amount: '0', // Valid amount for token enablement
610
+ },
611
+ ],
612
+ coin: 'thbar',
613
+ feeInfo: {
614
+ size: 1000,
615
+ fee: 1160407,
616
+ feeRate: 1160407,
617
+ },
618
+ });
619
+ // This should fail because the spoofed transaction hex contains invalid transaction data
620
+ // The verification logic should catch this when trying to validate the transaction
621
+ await assert_1.default.rejects(async () => {
622
+ // Test the verification directly instead of going through the wallet flow
623
+ await basecoin.verifyTokenEnablementTransaction(spoofedTxHex, { tokenName: 'thbar:usdc' }, '0.0.81320');
624
+ }, (error) => {
625
+ // The error should indicate that the transaction is invalid
626
+ return error.message.includes('Invalid token enablement transaction');
627
+ });
628
+ });
629
+ it('should fail when both tokenId and tokenName are missing', async function () {
630
+ await basecoin
631
+ .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_ASSOCIATE, {}, '0.0.81320')
632
+ .should.be.rejectedWith('Missing required parameters: expectedToken.tokenId|tokenName');
633
+ });
634
+ it('should fail when token name does not match', async function () {
635
+ await basecoin
636
+ .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_ASSOCIATE, { tokenName: 'thbar:wrongtoken' }, '0.0.81320')
637
+ .should.be.rejectedWith(/Expected token name thbar:wrongtoken, got thbar:usdc/);
638
+ });
639
+ it('should fail when account ID does not match', async function () {
640
+ await basecoin
641
+ .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_ASSOCIATE, { tokenName: 'thbar:usdc' }, '0.0.99999')
642
+ .should.be.rejectedWith(/Expected account 0.0.99999, got 0.0.81320/);
643
+ });
644
+ it('should fail when transaction is not a token enablement (has non-zero amount)', async function () {
645
+ // Use a regular transfer transaction which has non-zero amount
646
+ await basecoin
647
+ .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_TRANSFER, { tokenName: 'thbar:usdc' }, '0.0.81320')
648
+ .should.be.rejectedWith(/Expected output amount '0'/);
649
+ });
650
+ it('should fail when transaction type is not tokenAssociate', async function () {
651
+ // Use a regular transfer transaction which is not tokenAssociate
652
+ // This will fail on amount validation first, but that's expected behavior
653
+ await basecoin
654
+ .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_TRANSFER, { tokenName: 'thbar:usdc' }, '0.0.81320')
655
+ .should.be.rejectedWith(/Expected output amount '0'/);
656
+ });
657
+ it('should validate transaction type for valid token associate transaction', async function () {
658
+ // This test ensures the transaction type validation works for valid token associate transactions
659
+ const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
660
+ const expectedToken = { tokenName: 'thbar:usdc' };
661
+ const expectedAccountId = '0.0.81320';
662
+ await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId);
663
+ });
664
+ it('should fail with invalid transaction hex', async function () {
665
+ await basecoin
666
+ .verifyTokenEnablementTransaction('invalid_hex', { tokenName: 'thbar:usdc' }, '0.0.81320')
667
+ .should.be.rejectedWith(/Invalid token enablement transaction/);
668
+ });
669
+ it('should fail when txHex contains wrong tokenId compared to expected', async function () {
670
+ // This test ensures direct txHex validation catches spoofed tokenIds
671
+ const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
672
+ const wrongTokenId = '0.0.999999'; // Wrong tokenId
673
+ const expectedAccountId = '0.0.81320';
674
+ await basecoin
675
+ .verifyTokenEnablementTransaction(txHex, { tokenId: wrongTokenId }, expectedAccountId)
676
+ .should.be.rejectedWith(new RegExp(`Expected tokenId ${_.escapeRegExp(wrongTokenId)}, but transaction contains tokenId`));
677
+ });
678
+ it('should fail when txHex contains wrong accountId compared to expected', async function () {
679
+ // This test ensures direct txHex validation catches spoofed accountIds
680
+ const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
681
+ const expectedToken = { tokenName: 'thbar:usdc' };
682
+ const wrongAccountId = '0.0.999999'; // Wrong accountId
683
+ await basecoin
684
+ .verifyTokenEnablementTransaction(txHex, expectedToken, wrongAccountId)
685
+ .should.be.rejectedWith(new RegExp(`Expected account ${_.escapeRegExp(wrongAccountId)}, got`));
686
+ });
687
+ it('should pass verification for valid token enablement transaction without throwing error', async function () {
688
+ // This test ensures that a valid token enablement transaction passes all validations
689
+ const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
690
+ const expectedToken = { tokenName: 'thbar:usdc' };
691
+ const expectedAccountId = '0.0.81320';
692
+ // This should complete without throwing any errors
693
+ await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId);
694
+ // If we reach this point, the test passed
695
+ assert_1.default.ok(true, 'Valid token enablement transaction should not throw any errors');
696
+ });
697
+ it('should successfully complete sendTokenEnablements with valid transaction response from wallet platform', async function () {
698
+ const validTxHex = TestData.UNSIGNED_TOKEN_ASSOCIATE;
699
+ const wallet = {
700
+ id: () => '5b34252f1bf34993006eae96',
701
+ coin: () => 'thbar',
702
+ prebuildTransaction: async () => ({
703
+ txHex: validTxHex, // Valid token associate transaction
704
+ txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2',
705
+ recipients: [{ address: '0.0.81320', amount: '0' }],
706
+ coin: 'thbar',
707
+ feeInfo: { size: 1000, fee: 1160407, feeRate: 1160407 },
708
+ }),
709
+ sendTokenEnablements: async (params) => {
710
+ const txPrebuild = await wallet.prebuildTransaction();
711
+ await basecoin.verifyTransaction({
712
+ txParams: {
713
+ type: 'enabletoken',
714
+ recipients: [{ address: '0.0.81320', amount: '0', tokenName: 'thbar:usdc' }],
715
+ },
716
+ txPrebuild,
717
+ verification: { verifyTokenEnablement: true },
718
+ });
719
+ return {
720
+ success: [{ txid: txPrebuild.txid, status: 'success' }],
721
+ failure: [],
722
+ };
723
+ },
724
+ };
725
+ await wallet.sendTokenEnablements({
726
+ recipients: [{ address: '0.0.81320', tokenName: 'thbar:usdc' }],
727
+ });
728
+ assert_1.default.ok(true, 'Valid token enablement transaction should complete successfully through sendTokenEnablements flow');
729
+ });
730
+ it('should detect spoofed transaction hex through sendTokenEnablements flow', async function () {
731
+ // Use a valid transfer transaction hex instead of a token associate transaction
732
+ // This will parse correctly but fail validation because it's not a token associate transaction
733
+ const spoofedTxHex = TestData.UNSIGNED_TOKEN_TRANSFER; // Valid transfer transaction, not token associate
734
+ // Create a wallet mock for the sendTokenEnablements flow
735
+ const wallet = {
736
+ id: () => '5b34252f1bf34993006eae96',
737
+ coin: () => 'thbar',
738
+ prebuildTransaction: async () => ({
739
+ txHex: spoofedTxHex,
740
+ txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2',
741
+ recipients: [{ address: '0.0.81320', amount: '0' }],
742
+ coin: 'thbar',
743
+ feeInfo: { size: 1000, fee: 1160407, feeRate: 1160407 },
744
+ }),
745
+ sendTokenEnablements: async (params) => {
746
+ // This should trigger the verification and fail
747
+ const txPrebuild = await wallet.prebuildTransaction();
748
+ return basecoin.verifyTransaction({
749
+ txParams: {
750
+ type: 'enabletoken',
751
+ recipients: [{ address: '0.0.81320', amount: '0', tokenName: 'thbar:usdc' }],
752
+ },
753
+ txPrebuild,
754
+ verification: { verifyTokenEnablement: true },
755
+ });
756
+ },
757
+ };
758
+ // This should fail because the spoofed transaction hex contains a transfer transaction, not a token associate
759
+ await assert_1.default.rejects(async () => {
760
+ await wallet.sendTokenEnablements({
761
+ recipients: [{ address: '0.0.81320', tokenName: 'thbar:usdc' }],
762
+ });
763
+ }, (error) => {
764
+ // The error should indicate that the transaction is invalid for token enablement
765
+ return (error.message.includes('Invalid token enablement transaction') ||
766
+ error.message.includes('Token enablement transaction missing tokenId') ||
767
+ error.message.includes("Expected output amount '0'") ||
768
+ error.message.includes('Transaction is not a TokenAssociate transaction'));
769
+ });
770
+ });
771
+ });
772
+ describe('Sign Message', () => {
773
+ it('should be performed', async () => {
774
+ const keyPair = new src_1.KeyPair();
775
+ const messageToSign = Buffer.from((0, crypto_1.randomBytes)(32)).toString('hex');
776
+ const signature = await basecoin.signMessage(keyPair.getKeys(), messageToSign);
777
+ keyPair.verifySignature(messageToSign, Uint8Array.from(Buffer.from(signature, 'hex'))).should.equals(true);
778
+ });
779
+ it('should fail with missing private key', async () => {
780
+ const keyPair = new src_1.KeyPair({
781
+ pub: '302a300506032b6570032100d8fd745361df270776a3ab1b55d5590ec00a26ab45eea37197dc9894a81fcb82',
782
+ }).getKeys();
783
+ const messageToSign = Buffer.from((0, crypto_1.randomBytes)(32)).toString('hex');
784
+ await basecoin.signMessage(keyPair, messageToSign).should.be.rejectedWith('Invalid key pair options');
785
+ });
786
+ });
787
+ describe('Sign transaction:', () => {
788
+ const destination = '0.0.129369';
789
+ const source = '0.0.1234';
790
+ const amount = '100000';
791
+ /**
792
+ * Build an unsigned account-lib multi-signature send transaction
793
+ * @param destination The destination address of the transaction
794
+ * @param source The account sending thist ransaction
795
+ * @param amount The amount to send to the recipient
796
+ */
797
+ const buildUnsignedTransaction = async function ({ destination, source, amount = '100000' }) {
798
+ const factory = (0, getBuilderFactory_1.getBuilderFactory)('thbar');
799
+ const txBuilder = factory.getTransferBuilder();
800
+ txBuilder.fee({
801
+ fee: '100000',
802
+ });
803
+ txBuilder.source({ address: source });
804
+ txBuilder.send({ address: destination, amount });
805
+ return await txBuilder.build();
806
+ };
807
+ it('should sign transaction', async function () {
808
+ const key = new src_1.KeyPair();
809
+ const unsignedTransaction = await buildUnsignedTransaction({
810
+ destination,
811
+ source,
812
+ amount,
813
+ });
814
+ const tx = await basecoin.signTransaction({
815
+ prv: key.getKeys().prv.toString(),
816
+ txPrebuild: {
817
+ txHex: unsignedTransaction.toBroadcastFormat(),
818
+ },
819
+ });
820
+ const factory = (0, getBuilderFactory_1.getBuilderFactory)('thbar');
821
+ const txBuilder = factory.from(tx.halfSigned.txHex);
822
+ const signedTx = await txBuilder.build();
823
+ const txJson = signedTx.toJson();
824
+ txJson.should.have.properties('to', 'amount');
825
+ txJson.to?.should.equal(destination);
826
+ txJson.from.should.equal(source);
827
+ txJson.amount?.should.equal(amount);
828
+ txJson.instructionsData.params.recipients[0].should.deepEqual({
829
+ address: destination,
830
+ amount,
831
+ });
832
+ signedTx.signature.length.should.equal(1);
833
+ });
834
+ it('should fully sign transaction with root key', async function () {
835
+ const key1 = basecoin.generateRootKeyPair();
836
+ const key2 = basecoin.generateRootKeyPair();
837
+ const unsignedTransaction = await buildUnsignedTransaction({
838
+ destination,
839
+ source,
840
+ amount,
841
+ });
842
+ const txHalfSigned = await basecoin.signTransaction({
843
+ prv: key1.prv,
844
+ txPrebuild: {
845
+ txHex: unsignedTransaction.toBroadcastFormat(),
846
+ },
847
+ });
848
+ const factory = (0, getBuilderFactory_1.getBuilderFactory)('thbar');
849
+ const txBuilderHalfSigned = factory.from(txHalfSigned.halfSigned.txHex);
850
+ const halfSignedTx = await txBuilderHalfSigned.build();
851
+ const halfSignedTxJson = halfSignedTx.toJson();
852
+ halfSignedTxJson.should.have.properties('to', 'amount');
853
+ halfSignedTxJson.to?.should.equal(destination);
854
+ halfSignedTxJson.from.should.equal(source);
855
+ halfSignedTxJson.amount?.should.equal(amount);
856
+ halfSignedTxJson.instructionsData.params.recipients[0].should.deepEqual({
857
+ address: destination,
858
+ amount,
859
+ });
860
+ halfSignedTx.signature.length.should.equal(1);
861
+ const txSigned = await basecoin.signTransaction({
862
+ prv: key2.prv,
863
+ txPrebuild: {
864
+ txHex: halfSignedTx.toBroadcastFormat(),
865
+ },
866
+ });
867
+ const txBuilderSigned = factory.from(txSigned.txHex);
868
+ const signedTx = await txBuilderSigned.build();
869
+ const signedTxJson = signedTx.toJson();
870
+ signedTxJson.should.have.properties('to', 'amount');
871
+ signedTxJson.to?.should.equal(destination);
872
+ signedTxJson.from.should.equal(source);
873
+ signedTxJson.amount?.should.equal(amount);
874
+ signedTxJson.instructionsData.params.recipients[0].should.deepEqual({
875
+ address: destination,
876
+ amount,
877
+ });
878
+ signedTx.signature.length.should.equal(2);
879
+ });
880
+ });
881
+ describe('Recovery', function () {
882
+ const defaultValidDuration = '180';
883
+ const defaultFee = 10000000;
884
+ const defaultNodeId = '0.0.3';
885
+ const userKey = '{"iv":"WlPuJOejRWgj/NTd3UMgrw==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"6yAVFvreHSQ=","ct":"8j/lBVkFByKlVhaS9JWmmLja5yTokjaIiLDxMIDjMojVEim9T36WAm5qW6v1V0A7QcEuGiVl3PKMDa+Gr6tI/HT58DW5RE+pHzya9MUQpAgNrJr8VEWjrXWqZECVtra1/bKCyB+mozc="}';
886
+ const userPub = '302a300506032b6570032100ddd53a1591d72b181109bd3e57b18603740490b9ab4d37bc7fa27480e6b8c911';
887
+ const backupKey = '{"iv":"D5DVDozQx9B02JeFV0/OVA==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"7FUNF8M35bo=","ct":"ZiPsu5Qe/AIS4JQXt+rrusHnYCy4CqurM16R5wJrd4CEx7u85y3yy5ErnsdyYYcc3txyNmUIQ2/CBq/LKoKO/VIeU++CnKxzGuHGcNI47BPk3RQK42a66uIQn/yTR++XgdK1KhvUL3U="}';
888
+ const backupPub = '302a300506032b65700321006293e4ec9bf1b2d8fae631119107248a65e2207a05d32a11f42cc3d9a3005d4a';
889
+ const rootAddress = '0.0.7671186';
890
+ const walletPassphrase = 'TestPasswordPleaseIgnore';
891
+ const recoveryDestination = '0.0.7651908';
892
+ const bitgoKey = '5a93b01ea87e963f61c974a89d62e3841392f1ba020fbbcc65a8089ca025abbb';
893
+ const memo = '4';
894
+ const balance = '1000000000';
895
+ const formatBalanceResponse = (balance) => new bignumber_js_1.BigNumber(balance).dividedBy(basecoin.getBaseFactor()).toFixed(9) + ' ℏ';
896
+ const tokenId = '0.0.429274';
897
+ describe('Non-BitGo', async function () {
898
+ const sandBox = sinon_1.default.createSandbox();
899
+ afterEach(function () {
900
+ sandBox.verifyAndRestore();
901
+ });
902
+ it('should build and sign the recovery tx', async function () {
903
+ const expectedAmount = new bignumber_js_1.BigNumber(balance).minus(defaultFee).toString();
904
+ const getBalanceStub = sandBox
905
+ .stub(src_1.Hbar.prototype, 'getAccountBalance')
906
+ .resolves({ hbars: formatBalanceResponse(balance), tokens: [] });
907
+ const recovery = await basecoin.recover({
908
+ userKey,
909
+ backupKey,
910
+ rootAddress,
911
+ walletPassphrase,
912
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
913
+ });
914
+ recovery.should.not.be.undefined();
915
+ recovery.should.have.property('id');
916
+ recovery.should.have.property('tx');
917
+ recovery.should.have.property('coin', 'thbar');
918
+ recovery.should.have.property('nodeId', defaultNodeId);
919
+ getBalanceStub.callCount.should.equal(1);
920
+ const txBuilder = basecoin.getBuilderFactory().from(recovery.tx);
921
+ const tx = await txBuilder.build();
922
+ tx.toBroadcastFormat().should.equal(recovery.tx);
923
+ const txJson = tx.toJson();
924
+ txJson.amount.should.equal(expectedAmount);
925
+ txJson.to.should.equal(recoveryDestination);
926
+ txJson.from.should.equal(rootAddress);
927
+ txJson.fee.should.equal(defaultFee);
928
+ txJson.node.should.equal(defaultNodeId);
929
+ txJson.memo.should.equal(memo);
930
+ txJson.validDuration.should.equal(defaultValidDuration);
931
+ txJson.should.have.property('startTime');
932
+ recovery.should.have.property('startTime', txJson.startTime);
933
+ recovery.should.have.property('id', rootAddress + '@' + txJson.startTime);
934
+ });
935
+ it('should throw for invalid rootAddress', async function () {
936
+ const invalidRootAddress = 'randomstring';
937
+ await assert_1.default.rejects(async () => {
938
+ await basecoin.recover({
939
+ userKey,
940
+ backupKey,
941
+ rootAddress: 'randomstring',
942
+ walletPassphrase,
943
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
944
+ });
945
+ }, { message: 'invalid rootAddress, got: ' + invalidRootAddress });
946
+ });
947
+ it('should throw for invalid recoveryDestination', async function () {
948
+ const invalidRecoveryDestination = 'randomstring';
949
+ await assert_1.default.rejects(async () => {
950
+ await basecoin.recover({
951
+ userKey,
952
+ backupKey,
953
+ rootAddress,
954
+ walletPassphrase,
955
+ recoveryDestination: 'randomstring',
956
+ });
957
+ }, { message: 'invalid recoveryDestination, got: ' + invalidRecoveryDestination });
958
+ });
959
+ it('should throw for invalid nodeId', async function () {
960
+ const invalidNodeId = 'a.2.3';
961
+ await assert_1.default.rejects(async () => {
962
+ await basecoin.recover({
963
+ userKey,
964
+ backupKey,
965
+ rootAddress,
966
+ walletPassphrase,
967
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
968
+ nodeId: invalidNodeId,
969
+ });
970
+ }, { message: 'invalid nodeId, got: ' + invalidNodeId });
971
+ });
972
+ it('should throw for invalid maxFee', async function () {
973
+ const invalidMaxFee = '-32';
974
+ await assert_1.default.rejects(async () => {
975
+ await basecoin.recover({
976
+ userKey,
977
+ backupKey,
978
+ rootAddress,
979
+ walletPassphrase,
980
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
981
+ maxFee: invalidMaxFee,
982
+ });
983
+ }, { message: 'invalid maxFee, got: ' + invalidMaxFee });
984
+ });
985
+ it('should throw if there is no enough balance to recover', async function () {
986
+ const getBalanceStub = sandBox
987
+ .stub(src_1.Hbar.prototype, 'getAccountBalance')
988
+ .resolves({ hbars: formatBalanceResponse('100'), tokens: [] });
989
+ await assert_1.default.rejects(async () => {
990
+ await basecoin.recover({
991
+ userKey,
992
+ backupKey,
993
+ rootAddress,
994
+ walletPassphrase,
995
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
996
+ });
997
+ }, sdk_core_1.ErrorNoInputToRecover);
998
+ getBalanceStub.callCount.should.equal(1);
999
+ });
1000
+ it('should throw if the walletPassphrase is undefined', async function () {
1001
+ await assert_1.default.rejects(async () => {
1002
+ await basecoin.recover({
1003
+ userKey,
1004
+ backupKey,
1005
+ rootAddress,
1006
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1007
+ });
1008
+ }, { message: 'walletPassphrase is required for non-bitgo recovery' });
1009
+ });
1010
+ it('should throw if the walletPassphrase is wrong', async function () {
1011
+ await assert_1.default.rejects(async () => {
1012
+ await basecoin.recover({
1013
+ userKey,
1014
+ backupKey,
1015
+ rootAddress,
1016
+ walletPassphrase: 'randompassword',
1017
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1018
+ });
1019
+ }, {
1020
+ message: 'unable to decrypt userKey or backupKey with the walletPassphrase provided, got error: incorrect password',
1021
+ });
1022
+ });
1023
+ it('should build and sign the recovery tx for tokens', async function () {
1024
+ const balance = '100';
1025
+ const data = {
1026
+ hbars: '1',
1027
+ tokens: [{ tokenId: tokenId, balance: balance, decimals: 6 }],
1028
+ };
1029
+ const getBalanceStub = sandBox.stub(src_1.Hbar.prototype, 'getAccountBalance').resolves(data);
1030
+ const recovery = await basecoin.recover({
1031
+ userKey,
1032
+ backupKey,
1033
+ rootAddress,
1034
+ walletPassphrase,
1035
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1036
+ tokenId: tokenId,
1037
+ });
1038
+ recovery.should.not.be.undefined();
1039
+ recovery.should.have.property('id');
1040
+ recovery.should.have.property('tx');
1041
+ recovery.should.have.property('coin', 'thbar');
1042
+ recovery.should.have.property('nodeId', defaultNodeId);
1043
+ getBalanceStub.callCount.should.equal(1);
1044
+ const txBuilder = basecoin.getBuilderFactory().from(recovery.tx);
1045
+ const tx = await txBuilder.build();
1046
+ tx.toBroadcastFormat().should.equal(recovery.tx);
1047
+ const txJson = tx.toJson();
1048
+ txJson.amount.should.equal(balance);
1049
+ txJson.to.should.equal(recoveryDestination);
1050
+ txJson.from.should.equal(rootAddress);
1051
+ txJson.fee.should.equal(defaultFee);
1052
+ txJson.node.should.equal(defaultNodeId);
1053
+ txJson.memo.should.equal(memo);
1054
+ txJson.validDuration.should.equal(defaultValidDuration);
1055
+ txJson.should.have.property('startTime');
1056
+ recovery.should.have.property('startTime', txJson.startTime);
1057
+ recovery.should.have.property('id', rootAddress + '@' + txJson.startTime);
1058
+ });
1059
+ it('should throw error for non supported invalid tokenId', async function () {
1060
+ const invalidTokenId = 'randomstring';
1061
+ const data = {
1062
+ hbars: '1',
1063
+ tokens: [{ tokenId: tokenId, balance: '100', decimals: 6 }],
1064
+ };
1065
+ sandBox.stub(src_1.Hbar.prototype, 'getAccountBalance').resolves(data);
1066
+ await assert_1.default.rejects(async () => {
1067
+ await basecoin.recover({
1068
+ userKey,
1069
+ backupKey,
1070
+ rootAddress: rootAddress,
1071
+ walletPassphrase,
1072
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1073
+ tokenId: invalidTokenId,
1074
+ });
1075
+ }, { message: 'Unsupported token: ' + invalidTokenId });
1076
+ });
1077
+ it('should throw error for insufficient balance for tokenId if token balance not exist', async function () {
1078
+ const data = {
1079
+ hbars: '100',
1080
+ tokens: [{ tokenId: 'randomString', balance: '100', decimals: 6 }],
1081
+ };
1082
+ sandBox.stub(src_1.Hbar.prototype, 'getAccountBalance').resolves(data);
1083
+ await assert_1.default.rejects(async () => {
1084
+ await basecoin.recover({
1085
+ userKey,
1086
+ backupKey,
1087
+ rootAddress: rootAddress,
1088
+ walletPassphrase,
1089
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1090
+ tokenId: tokenId,
1091
+ });
1092
+ }, sdk_core_1.ErrorNoInputToRecover);
1093
+ });
1094
+ it('should throw error for insufficient balance for tokenId if token balance exist with 0 amount', async function () {
1095
+ const data = {
1096
+ hbars: '100',
1097
+ tokens: [{ tokenId: 'randomString', balance: '0', decimals: 6 }],
1098
+ };
1099
+ sandBox.stub(src_1.Hbar.prototype, 'getAccountBalance').resolves(data);
1100
+ await assert_1.default.rejects(async () => {
1101
+ await basecoin.recover({
1102
+ userKey,
1103
+ backupKey,
1104
+ rootAddress: rootAddress,
1105
+ walletPassphrase,
1106
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1107
+ tokenId: tokenId,
1108
+ });
1109
+ }, sdk_core_1.ErrorNoInputToRecover);
1110
+ });
1111
+ it('should throw error for insufficient native balance for token transfer', async function () {
1112
+ const data = {
1113
+ hbars: '0.01',
1114
+ tokens: [{ tokenId: tokenId, balance: '10', decimals: 6 }],
1115
+ };
1116
+ sandBox.stub(src_1.Hbar.prototype, 'getAccountBalance').resolves(data);
1117
+ await assert_1.default.rejects(async () => {
1118
+ await basecoin.recover({
1119
+ userKey,
1120
+ backupKey,
1121
+ rootAddress: rootAddress,
1122
+ walletPassphrase,
1123
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1124
+ tokenId: tokenId,
1125
+ });
1126
+ }, { message: 'Insufficient native balance to recover tokens, got native balance: 1000000 fee: ' + defaultFee });
1127
+ });
1128
+ it('should throw RecoveryProviderError when the account balance query fails', async function () {
1129
+ sandBox
1130
+ .stub(src_1.Hbar.prototype, 'getAccountBalance')
1131
+ .rejects(new sdk_core_1.RecoveryProviderError('Failed to get account balance'));
1132
+ await assert_1.default.rejects(async () => {
1133
+ await basecoin.recover({
1134
+ userKey,
1135
+ backupKey,
1136
+ rootAddress,
1137
+ walletPassphrase,
1138
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1139
+ });
1140
+ }, sdk_core_1.RecoveryProviderError);
1141
+ });
1142
+ });
1143
+ describe('Unsigned Sweep', function () {
1144
+ const sandBox = sinon_1.default.createSandbox();
1145
+ let getBalanceStub;
1146
+ afterEach(function () {
1147
+ sandBox.verifyAndRestore();
1148
+ });
1149
+ it('should build unsigned sweep tx', async function () {
1150
+ getBalanceStub = sandBox
1151
+ .stub(src_1.Hbar.prototype, 'getAccountBalance')
1152
+ .resolves({ hbars: formatBalanceResponse(balance), tokens: [] });
1153
+ const startTime = (Date.now() / 1000 + 10).toFixed(); // timestamp in seconds, 10 seconds from now
1154
+ const expectedAmount = new bignumber_js_1.BigNumber(balance).minus(defaultFee).toString();
1155
+ const recovery = await basecoin.recover({
1156
+ userKey: userPub,
1157
+ backupKey: backupPub,
1158
+ rootAddress,
1159
+ bitgoKey,
1160
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1161
+ startTime,
1162
+ });
1163
+ getBalanceStub.callCount.should.equal(1);
1164
+ recovery.should.not.be.undefined();
1165
+ recovery.should.have.property('txHex');
1166
+ recovery.should.have.property('id', rootAddress + '@' + startTime + '.0');
1167
+ recovery.should.have.property('userKey', userPub);
1168
+ recovery.should.have.property('backupKey', backupPub);
1169
+ recovery.should.have.property('bitgoKey', bitgoKey);
1170
+ recovery.should.have.property('address', rootAddress);
1171
+ recovery.should.have.property('coin', 'thbar');
1172
+ recovery.should.have.property('maxFee', defaultFee.toString());
1173
+ recovery.should.have.property('recipients', [{ address: recoveryDestination, amount: expectedAmount }]);
1174
+ recovery.should.have.property('amount', expectedAmount);
1175
+ recovery.should.have.property('validDuration', defaultValidDuration);
1176
+ recovery.should.have.property('nodeId', defaultNodeId);
1177
+ recovery.should.have.property('memo', memo);
1178
+ recovery.should.have.property('startTime', startTime + '.0');
1179
+ const txBuilder = basecoin.getBuilderFactory().from(recovery.txHex);
1180
+ const tx = await txBuilder.build();
1181
+ const txJson = tx.toJson();
1182
+ txJson.id.should.equal(rootAddress + '@' + startTime + '.0');
1183
+ txJson.amount.should.equal(expectedAmount);
1184
+ txJson.to.should.equal(recoveryDestination);
1185
+ txJson.from.should.equal(rootAddress);
1186
+ txJson.fee.should.equal(defaultFee);
1187
+ txJson.node.should.equal(defaultNodeId);
1188
+ txJson.memo.should.equal(memo);
1189
+ txJson.validDuration.should.equal(defaultValidDuration);
1190
+ txJson.startTime.should.equal(startTime + '.0');
1191
+ txJson.validDuration.should.equal(defaultValidDuration);
1192
+ });
1193
+ it('should build unsigned sweep tx for tokens', async function () {
1194
+ const balance = '100';
1195
+ const data = {
1196
+ hbars: '1',
1197
+ tokens: [{ tokenId: tokenId, balance: balance, decimals: 6 }],
1198
+ };
1199
+ getBalanceStub = sandBox.stub(src_1.Hbar.prototype, 'getAccountBalance').resolves(data);
1200
+ const startTime = (Date.now() / 1000 + 10).toFixed(); // timestamp in seconds, 10 seconds from now
1201
+ const recovery = await basecoin.recover({
1202
+ userKey: userPub,
1203
+ backupKey: backupPub,
1204
+ rootAddress,
1205
+ bitgoKey,
1206
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1207
+ startTime,
1208
+ tokenId: tokenId,
1209
+ });
1210
+ getBalanceStub.callCount.should.equal(1);
1211
+ recovery.should.not.be.undefined();
1212
+ recovery.should.have.property('txHex');
1213
+ recovery.should.have.property('id', rootAddress + '@' + startTime + '.0');
1214
+ recovery.should.have.property('userKey', userPub);
1215
+ recovery.should.have.property('backupKey', backupPub);
1216
+ recovery.should.have.property('bitgoKey', bitgoKey);
1217
+ recovery.should.have.property('address', rootAddress);
1218
+ recovery.should.have.property('coin', 'thbar');
1219
+ recovery.should.have.property('maxFee', defaultFee.toString());
1220
+ recovery.should.have.property('recipients', [
1221
+ { address: recoveryDestination, amount: balance, tokenName: 'thbar:usdc' },
1222
+ ]);
1223
+ recovery.should.have.property('amount', balance);
1224
+ recovery.should.have.property('validDuration', defaultValidDuration);
1225
+ recovery.should.have.property('nodeId', defaultNodeId);
1226
+ recovery.should.have.property('memo', memo);
1227
+ recovery.should.have.property('startTime', startTime + '.0');
1228
+ const txBuilder = basecoin.getBuilderFactory().from(recovery.txHex);
1229
+ const tx = await txBuilder.build();
1230
+ const txJson = tx.toJson();
1231
+ txJson.id.should.equal(rootAddress + '@' + startTime + '.0');
1232
+ txJson.amount.should.equal(balance);
1233
+ txJson.to.should.equal(recoveryDestination);
1234
+ txJson.from.should.equal(rootAddress);
1235
+ txJson.fee.should.equal(defaultFee);
1236
+ txJson.node.should.equal(defaultNodeId);
1237
+ txJson.memo.should.equal(memo);
1238
+ txJson.validDuration.should.equal(defaultValidDuration);
1239
+ txJson.startTime.should.equal(startTime + '.0');
1240
+ txJson.validDuration.should.equal(defaultValidDuration);
1241
+ });
1242
+ it('should throw if startTime is undefined', async function () {
1243
+ const startTime = undefined;
1244
+ await assert_1.default.rejects(async () => {
1245
+ await basecoin.recover({
1246
+ userKey: userPub,
1247
+ backupKey: backupPub,
1248
+ rootAddress,
1249
+ bitgoKey,
1250
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1251
+ startTime,
1252
+ });
1253
+ }, { message: 'start time is required for unsigned sweep' });
1254
+ });
1255
+ it('should throw for invalid userKey', async function () {
1256
+ const startTime = (Date.now() / 1000 + 10).toFixed();
1257
+ const invalidUserPub = '302a300506032b6570032100randomstring';
1258
+ await assert_1.default.rejects(async () => {
1259
+ await basecoin.recover({
1260
+ userKey: invalidUserPub,
1261
+ backupKey: backupPub,
1262
+ bitgoKey,
1263
+ rootAddress,
1264
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1265
+ startTime,
1266
+ });
1267
+ }, { message: 'invalid userKey, got: ' + invalidUserPub });
1268
+ });
1269
+ it('should throw for invalid backupKey', async function () {
1270
+ const invalidBackupPub = '302a300506032b6570032100randomstring';
1271
+ const startTime = (Date.now() / 1000 + 10).toFixed();
1272
+ await assert_1.default.rejects(async () => {
1273
+ await basecoin.recover({
1274
+ userKey: userPub,
1275
+ backupKey: invalidBackupPub,
1276
+ bitgoKey,
1277
+ rootAddress,
1278
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1279
+ startTime,
1280
+ });
1281
+ }, { message: 'invalid backupKey, got: ' + invalidBackupPub });
1282
+ });
1283
+ it('should throw if startTime is a valid timestamp', async function () {
1284
+ const startTime = 'asd';
1285
+ await assert_1.default.rejects(async () => {
1286
+ await basecoin.recover({
1287
+ userKey: userPub,
1288
+ backupKey: backupPub,
1289
+ rootAddress,
1290
+ bitgoKey,
1291
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1292
+ startTime,
1293
+ });
1294
+ }, { message: 'invalid startTime, got: ' + startTime });
1295
+ });
1296
+ it('should throw if startTime is not a future date', async function () {
1297
+ const startTime = (Date.now() / 1000 - 1).toString(); // timestamp in seconds, 1 second ago
1298
+ await assert_1.default.rejects(async () => {
1299
+ await basecoin.recover({
1300
+ userKey: userPub,
1301
+ backupKey: backupPub,
1302
+ rootAddress,
1303
+ bitgoKey,
1304
+ recoveryDestination: recoveryDestination + '?memoId=' + memo,
1305
+ startTime,
1306
+ });
1307
+ }, { message: 'startTime must be a future timestamp, got: ' + startTime });
1308
+ });
1309
+ });
1310
+ describe('Recovery with root keys', function () {
1311
+ const sandBox = sinon_1.default.createSandbox();
1312
+ let getBalanceStub;
1313
+ const walletPassphrase = 'testbtcpassword1999';
1314
+ const userEddsaRootXPrv = '{"iv":"lHOTkiuucR2JWFD1x1gqpQ==","v":1,"iter":10000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"HkFrDVH++d8=","ct":"NBtbYdFEK84oH9uxwl/UrhRsW5nGJPnMSpRAo8Blrc7WTSPxGXmVS/EpUYEV03HG06/EnyBR0/Y6bjLQz4gkL6cGJD9hgyKqDvc9RtKHagEbo75oxPr0zP+r1HMUGBW38Ttgor674gBeb1Myew69xcS9KgguNxwz77X6fdeBhrfogLY22vcuLA=="}';
1315
+ const userEddsaRootPub = 'd9cb9c9c617cfa0b715849516bb054a2b5d78c0e3eeef011176fb8bc0108c531';
1316
+ const backupEddsaRootXprv = '{"iv":"sBoEFBBNoi2YVICPf16/BQ==","v":1,"iter":10000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"HkFrDVH++d8=","ct":"GscOqJC+Iq+Lr39plQp5ZCamVlpJHOltGTZ7/UnUunIhFmZWMBLxjEVnMOtPreb0NZ4/SFqO/N3mZvq6JbB7vWRxJuqkBIiVcIRwkSWdW55cboKx2ec3ajg8+uO2pbvNDs26Q+9NtZ4jZnKNqSUXiCmtJXLRHQ32oyD+olKRpIR2NQo2+7kIEw=="}';
1317
+ const backupEddsaRootPub = 'f163b1b8ee4c3343a97ac1d2470b967e967ac7b4e3731cacf02f28a1434a2f99';
1318
+ const rootAddress = '0.0.3644667';
1319
+ const memoId = '0';
1320
+ beforeEach(function () {
1321
+ getBalanceStub = sandBox
1322
+ .stub(src_1.Hbar.prototype, 'getAccountBalance')
1323
+ .resolves({ hbars: formatBalanceResponse(balance), tokens: [] });
1324
+ });
1325
+ afterEach(function () {
1326
+ sandBox.verifyAndRestore();
1327
+ });
1328
+ it('should build and sign non-bitgo recovery tx with root keys', async function () {
1329
+ const expectedAmount = new bignumber_js_1.BigNumber(balance).minus(defaultFee).toString();
1330
+ const recovery = await basecoin.recover({
1331
+ userKey: userEddsaRootXPrv,
1332
+ backupKey: backupEddsaRootXprv,
1333
+ rootAddress,
1334
+ walletPassphrase,
1335
+ recoveryDestination: recoveryDestination + '?memoId=' + memoId,
1336
+ });
1337
+ getBalanceStub.callCount.should.equal(1);
1338
+ recovery.should.not.be.undefined();
1339
+ recovery.should.have.property('id');
1340
+ recovery.should.have.property('tx');
1341
+ recovery.should.have.property('coin', 'thbar');
1342
+ recovery.should.have.property('nodeId', defaultNodeId);
1343
+ getBalanceStub.callCount.should.equal(1);
1344
+ const txBuilder = basecoin.getBuilderFactory().from(recovery.tx);
1345
+ const tx = await txBuilder.build();
1346
+ tx.toBroadcastFormat().should.equal(recovery.tx);
1347
+ const txJson = tx.toJson();
1348
+ txJson.amount.should.equal(expectedAmount);
1349
+ txJson.to.should.equal(recoveryDestination);
1350
+ txJson.from.should.equal(rootAddress);
1351
+ txJson.fee.should.equal(defaultFee);
1352
+ txJson.node.should.equal(defaultNodeId);
1353
+ txJson.memo.should.equal(memoId);
1354
+ txJson.validDuration.should.equal(defaultValidDuration);
1355
+ txJson.should.have.property('startTime');
1356
+ recovery.should.have.property('startTime', txJson.startTime);
1357
+ recovery.should.have.property('id', rootAddress + '@' + txJson.startTime);
1358
+ });
1359
+ it('should build unsigned sweep tx', async function () {
1360
+ const startTime = (Date.now() / 1000 + 10).toFixed(); // timestamp in seconds, 10 seconds from now
1361
+ const expectedAmount = new bignumber_js_1.BigNumber(balance).minus(defaultFee).toString();
1362
+ const recovery = await basecoin.recover({
1363
+ userKey: userEddsaRootPub,
1364
+ backupKey: backupEddsaRootPub,
1365
+ rootAddress,
1366
+ bitgoKey,
1367
+ recoveryDestination: recoveryDestination + '?memoId=' + memoId,
1368
+ startTime,
1369
+ });
1370
+ getBalanceStub.callCount.should.equal(1);
1371
+ recovery.should.not.be.undefined();
1372
+ recovery.should.have.property('txHex');
1373
+ recovery.should.have.property('id', rootAddress + '@' + startTime + '.0');
1374
+ recovery.should.have.property('userKey', userEddsaRootPub);
1375
+ recovery.should.have.property('backupKey', backupEddsaRootPub);
1376
+ recovery.should.have.property('bitgoKey', bitgoKey);
1377
+ recovery.should.have.property('address', rootAddress);
1378
+ recovery.should.have.property('coin', 'thbar');
1379
+ recovery.should.have.property('maxFee', defaultFee.toString());
1380
+ recovery.should.have.property('recipients', [{ address: recoveryDestination, amount: expectedAmount }]);
1381
+ recovery.should.have.property('amount', expectedAmount);
1382
+ recovery.should.have.property('validDuration', defaultValidDuration);
1383
+ recovery.should.have.property('nodeId', defaultNodeId);
1384
+ recovery.should.have.property('memo', memoId);
1385
+ recovery.should.have.property('startTime', startTime + '.0');
1386
+ const txBuilder = basecoin.getBuilderFactory().from(recovery.txHex);
1387
+ const tx = await txBuilder.build();
1388
+ const txJson = tx.toJson();
1389
+ txJson.id.should.equal(rootAddress + '@' + startTime + '.0');
1390
+ txJson.amount.should.equal(expectedAmount);
1391
+ txJson.to.should.equal(recoveryDestination);
1392
+ txJson.from.should.equal(rootAddress);
1393
+ txJson.fee.should.equal(defaultFee);
1394
+ txJson.node.should.equal(defaultNodeId);
1395
+ txJson.memo.should.equal(memoId);
1396
+ txJson.validDuration.should.equal(defaultValidDuration);
1397
+ txJson.startTime.should.equal(startTime + '.0');
1398
+ txJson.validDuration.should.equal(defaultValidDuration);
1399
+ });
1400
+ });
1401
+ });
1402
+ describe('broadcastTransaction', function () {
1403
+ const sandBox = sinon_1.default.createSandbox();
1404
+ afterEach(function () {
1405
+ sandBox.verifyAndRestore();
1406
+ });
1407
+ it('should succeed if the startTime and serializedSignedTransaction are valid', async function () {
1408
+ const startTime = (Date.now() / 1000 - 3).toFixed(); // timestamp in seconds, -3 seconds from now so it's valid after 2 seconds
1409
+ const expectedResponse = { txId: '0.0.7668465@' + startTime + '.0', status: 'SUCCESS' };
1410
+ const broadcastStub = sandBox.stub(src_1.Hbar.prototype, 'clientBroadcastTransaction').resolves(expectedResponse);
1411
+ const serializedSignedTransaction = '1acc010a640a20592a4fbb7263c59d450e651df96620dc9208ee7c7d9d6f2fdcb91c53f88312611a40105b7d250c81f3705bc0b85168ce3fd00330131bb7701378681c8c2e6a09a91828715e7334f4ef28d20ff09887c6e87c0a5c693e23824c26f3ba161fce0448050a640a20a6905095616c3cfaa1bf61b53de30e938ce4112c3cc4d25393ec6b9bf4dea0631a40bf98c5b89b7a08544edaa1f4c08a0dfa6ec3f78b7e2fd27049283984050f38ccf0303ee57a377cc0a725ffd99d69e9fd914770ab0949ba556d84b3b00cb07e0d22500a130a0608cea8c1ad0612090800100018f185d40312060800100018031880c2d72f220308b40132013472240a220a0f0a090800100018f185d40310d3b0510a0f0a090800100018c484d30310d4b051';
1412
+ const result = await basecoin.broadcastTransaction({ serializedSignedTransaction, startTime });
1413
+ broadcastStub.callCount.should.equal(1);
1414
+ result.should.deepEqual(expectedResponse);
1415
+ });
1416
+ it('should throw if the startTime is expired', async function () {
1417
+ const startTime = (Date.now() / 1000 - 2000).toFixed(); // timestamp in seconds, 2000 seconds from now
1418
+ const serializedSignedTransaction = '1acc010a640a20592a4fbb7263c59d450e651df96620dc9208ee7c7d9d6f2fdcb91c53f88312611a40105b7d250c81f3705bc0b85168ce3fd00330131bb7701378681c8c2e6a09a91828715e7334f4ef28d20ff09887c6e87c0a5c693e23824c26f3ba161fce0448050a640a20a6905095616c3cfaa1bf61b53de30e938ce4112c3cc4d25393ec6b9bf4dea0631a40bf98c5b89b7a08544edaa1f4c08a0dfa6ec3f78b7e2fd27049283984050f38ccf0303ee57a377cc0a725ffd99d69e9fd914770ab0949ba556d84b3b00cb07e0d22500a130a0608cea8c1ad0612090800100018f185d40312060800100018031880c2d72f220308b40132013472240a220a0f0a090800100018f185d40310d3b0510a0f0a090800100018c484d30310d4b051';
1419
+ await assert_1.default.rejects(async () => {
1420
+ await basecoin.broadcastTransaction({ serializedSignedTransaction, startTime });
1421
+ }, (error) => {
1422
+ assert_1.default.ok(error.message.includes('Failed to broadcast transaction, error: startTime window expired'));
1423
+ return true;
1424
+ });
1425
+ });
1426
+ it('should throw if the serializedSignedTransaction is invalid', async function () {
1427
+ const startTime = (Date.now() / 1000 - 10).toFixed(); // timestamp in seconds, 10 seconds from now
1428
+ const serializedSignedTransaction = 'randomstring';
1429
+ await assert_1.default.rejects(async () => {
1430
+ await basecoin.broadcastTransaction({ serializedSignedTransaction, startTime });
1431
+ });
1432
+ });
1433
+ it('should throw if the startTime in the tx is invalid', async function () {
1434
+ const expectedResponse = 'transaction 0.0.7668465@1706056301.000000000 failed precheck with status INVALID_TRANSACTION_START';
1435
+ sandBox.stub(src_1.Hbar.prototype, 'clientBroadcastTransaction').rejects(new Error(expectedResponse));
1436
+ const serializedSignedTransaction = '1acc010a640a20592a4fbb7263c59d450e651df96620dc9208ee7c7d9d6f2fdcb91c53f88312611a40105b7d250c81f3705bc0b85168ce3fd00330131bb7701378681c8c2e6a09a91828715e7334f4ef28d20ff09887c6e87c0a5c693e23824c26f3ba161fce0448050a640a20a6905095616c3cfaa1bf61b53de30e938ce4112c3cc4d25393ec6b9bf4dea0631a40bf98c5b89b7a08544edaa1f4c08a0dfa6ec3f78b7e2fd27049283984050f38ccf0303ee57a377cc0a725ffd99d69e9fd914770ab0949ba556d84b3b00cb07e0d22500a130a0608cea8c1ad0612090800100018f185d40312060800100018031880c2d72f220308b40132013472240a220a0f0a090800100018f185d40310d3b0510a0f0a090800100018c484d30310d4b051';
1437
+ await assert_1.default.rejects(async () => {
1438
+ await basecoin.broadcastTransaction({ serializedSignedTransaction });
1439
+ }, { message: expectedResponse });
1440
+ });
1441
+ });
1442
+ describe('deriveKeyWithSeed', function () {
1443
+ it('should derive key with seed', function () {
1444
+ (() => {
1445
+ basecoin.deriveKeyWithSeed('test');
1446
+ }).should.throw('method deriveKeyWithSeed not supported for eddsa curve');
1447
+ });
1448
+ });
1449
+ describe('Generate wallet Root key pair: ', () => {
1450
+ it('should generate key pair', () => {
1451
+ const kp = basecoin.generateRootKeyPair();
1452
+ basecoin.isValidPub(kp.pub).should.equal(true);
1453
+ const keypair = new src_1.KeyPair({ prv: kp.prv }).getKeys(true);
1454
+ keypair.should.have.property('prv');
1455
+ keypair.prv?.should.equal(kp.prv.slice(0, 64));
1456
+ keypair.pub.should.equal(kp.pub);
1457
+ });
1458
+ it('should generate key pair from seed', () => {
1459
+ const seed = Buffer.from('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', 'hex');
1460
+ const kp = basecoin.generateRootKeyPair(seed);
1461
+ basecoin.isValidPub(kp.pub).should.equal(true);
1462
+ kp.pub.should.equal('d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a');
1463
+ kp.prv.should.equal('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a');
1464
+ const keypair = new src_1.KeyPair({ prv: kp.prv }).getKeys(true);
1465
+ keypair.should.have.property('prv');
1466
+ keypair.prv?.should.equal(kp.prv.slice(0, 64));
1467
+ keypair.pub.should.equal(kp.pub);
1468
+ });
1469
+ });
1470
+ describe('AuditKey', () => {
1471
+ const { key } = hbarBackupKey_1.hbarBackupKey;
1472
+ const walletPassphrase = 'kAm[EFQ6o=SxlcLFDw%,';
1473
+ it('should return for valid inputs', () => {
1474
+ basecoin.assertIsValidKey({
1475
+ coinName: 'hbar',
1476
+ encryptedPrv: key,
1477
+ walletPassphrase,
1478
+ });
1479
+ });
1480
+ it('should throw error if the walletPassphrase is incorrect', async () => {
1481
+ await assert_1.default.rejects(() => basecoin.assertIsValidKey({
1482
+ coinName: 'hbar',
1483
+ encryptedPrv: key,
1484
+ walletPassphrase: 'foo',
1485
+ }), { message: 'failed to decrypt prv: incorrect password' });
1486
+ });
1487
+ it('should throw error if the key is altered', async () => {
1488
+ const alteredKey = key.replace(/[0-9]/g, '0');
1489
+ await assert_1.default.rejects(() => basecoin.assertIsValidKey({
1490
+ coinName: 'hbar',
1491
+ encryptedPrv: alteredKey,
1492
+ walletPassphrase,
1493
+ }), {
1494
+ message: 'failed to decrypt prv: decrypt: ciphertext is not valid JSON',
1495
+ });
1496
+ });
1497
+ it('should throw error if the key is not a valid key', async () => {
1498
+ const invalidKey = '#@)$#($*@)#($*';
1499
+ const encryptedPrv = await (0, sdk_api_1.encrypt)(walletPassphrase, invalidKey);
1500
+ await assert_1.default.rejects(() => basecoin.assertIsValidKey({
1501
+ coinName: 'hbar',
1502
+ encryptedPrv,
1503
+ walletPassphrase,
1504
+ }), {
1505
+ message: 'Invalid private key: Invalid private key length. Must be a hex and multiple of 2',
1506
+ });
1507
+ });
1508
+ });
1509
+ });
1510
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGJhci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Rlc3QvdW5pdC9oYmFyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsb0RBQTRCO0FBRTVCLDBDQUE0QjtBQUM1QixnREFBd0I7QUFDeEIsa0RBQXlDO0FBQ3pDLG1DQUFxQztBQUNyQywrQ0FBeUM7QUFDekMsbURBQStEO0FBQy9ELGlEQUF3RDtBQUN4RCxtREFBb0c7QUFHcEcsMkRBQTZDO0FBQzdDLG1DQUE0RDtBQUM1RCwyREFBd0Q7QUFDeEQsNERBQXlEO0FBRXpELFFBQVEsQ0FBQyxtQkFBbUIsRUFBRTtJQUM1QixJQUFJLEtBQW1CLENBQUM7SUFDeEIsSUFBSSxRQUFRLENBQUM7SUFDYixJQUFJLEtBQUssQ0FBQztJQUVWLE1BQU0sQ0FBQztRQUNMLEtBQUssR0FBRyxvQkFBUyxDQUFDLFFBQVEsQ0FBQyxrQkFBUSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDdEQsS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsV0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2xELEtBQUssQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLFVBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUNoRCxlQUFTLENBQUMsdUJBQXVCLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsRUFBRSxFQUFFO1lBQ3hFLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQzVDLENBQUMsQ0FBQyxDQUFDO1FBQ0gsS0FBSyxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDM0IsUUFBUSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDL0IsS0FBSyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMs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QUFFO1lBQ2hFLE1BQU0sVUFBVSxHQUFHLGdCQUFnQixDQUFDO1lBQ3BDLE1BQU0sWUFBWSxHQUFHLE1BQU0sSUFBQSxpQkFBTyxFQUFDLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ2pFLE1BQU0sZ0JBQU0sQ0FBQyxPQUFPLENBQ2xCLEdBQUcsRUFBRSxDQUNILFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDeEIsUUFBUSxFQUFFLE1BQU07Z0JBQ2hCLFlBQVk7Z0JBQ1osZ0JBQWdCO2FBQ2pCLENBQUMsRUFDSjtnQkFDRSxPQUFPLEVBQUUsa0ZBQWtGO2FBQzVGLENBQ0YsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcblxuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IG5vY2sgZnJvbSAnbm9jayc7XG5pbXBvcnQgU2lub24sIHsgU2lub25TdHViIH0gZnJvbSAnc2lub24nO1xuaW1wb3J0IHsgcmFuZG9tQnl0ZXMgfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgQmlnTnVtYmVyIH0gZnJvbSAnYmlnbnVtYmVyLmpzJztcbmltcG9ydCB7IFRlc3RCaXRHbywgVGVzdEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLXRlc3QnO1xuaW1wb3J0IHsgQml0R29BUEksIGVuY3J5cHQgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstYXBpJztcbmltcG9ydCB7IGNvbW1vbiwgRXJyb3JOb0lucHV0VG9SZWNvdmVyLCBSZWNvdmVyeVByb3ZpZGVyRXJyb3IsIFdhbGxldCB9IGZyb20gJ0BiaXRnby1iZXRhL3Nkay1jb3JlJztcbmltcG9ydCB7IFR4RGF0YSwgVHJhbnNmZXIgfSBmcm9tICcuLi8uLi9zcmMvbGliL2lmYWNlJztcblxuaW1wb3J0ICogYXMgVGVzdERhdGEgZnJvbSAnLi4vZml4dHVyZXMvaGJhcic7XG5pbXBvcnQgeyBIYmFyLCBUaGJhciwgS2V5UGFpciwgSGJhclRva2VuIH0gZnJvbSAnLi4vLi4vc3JjJztcbmltcG9ydCB7IGdldEJ1aWxkZXJGYWN0b3J5IH0gZnJvbSAnLi9nZXRCdWlsZGVyRmFjdG9yeSc7XG5pbXBvcnQgeyBoYmFyQmFja3VwS2V5IH0gZnJvbSAnLi9maXh0dXJlcy9oYmFyQmFja3VwS2V5JztcblxuZGVzY3JpYmUoJ0hlZGVyYSBIYXNoZ3JhcGg6JywgZnVuY3Rpb24gKCkge1xuICBsZXQgYml0Z286IFRlc3RCaXRHb0FQSTtcbiAgbGV0IGJhc2Vjb2luO1xuICBsZXQgdG9rZW47XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHb0FQSSwgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIoJ3RoYmFyJywgVGhiYXIuY3JlYXRlSW5zdGFuY2UpO1xuICAgIGJpdGdvLnNhZmVSZWdpc3RlcignaGJhcicsIEhiYXIuY3JlYXRlSW5zdGFuY2UpO1xuICAgIEhiYXJUb2tlbi5jcmVhdGVUb2tlbkNvbnN0cnVjdG9ycygpLmZvckVhY2goKHsgbmFtZSwgY29pbkNvbnN0cnVjdG9yIH0pID0+IHtcbiAgICAgIGJpdGdvLnNhZmVSZWdpc3RlcihuYW1lLCBjb2luQ29uc3RydWN0b3IpO1xuICAgIH0pO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIGJhc2Vjb2luID0gYml0Z28uY29pbigndGhiYXInKTtcbiAgICB0b2tlbiA9IGJpdGdvLmNvaW4oJ3RoYmFyOnVzZGMnKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBpbnN0YW50aWF0ZSB0aGUgY29pbicsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBiYXNlY29pbiA9IGJpdGdvLmNvaW4oJ2hiYXInKTtcbiAgICBiYXNlY29pbi5zaG91bGQuYmUuYW4uaW5zdGFuY2VvZihIYmFyKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBjaGVjayB2YWxpZCBhZGRyZXNzZXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgYmFkQWRkcmVzc2VzID0gW1xuICAgICAgJycsXG4gICAgICAnMC4wJyxcbiAgICAgICdZWjA5ZmQtJyxcbiAgICAgICcwLjAuMC5hJyxcbiAgICAgICdzYWRhc2RmZ2dnJyxcbiAgICAgICcwLjIuYS5iJyxcbiAgICAgICcwLjAuMTAwPz1za3NqZCcsXG4gICAgICAnMC4wLjQxMDk4P21lbW9JZD0nLFxuICAgIF07XG4gICAgY29uc3QgZ29vZEFkZHJlc3NlcyA9IFtcbiAgICAgICcwJyxcbiAgICAgICcwLjAuMCcsXG4gICAgICAnMC4wLjQxMDk4JyxcbiAgICAgICcwLjAuMD9tZW1vSWQ9ODQnLFxuICAgICAgJzAuMC40MTA5OCcsXG4gICAgICAnMC4wLjQxMDk4P21lbW9JZD0yYWFhYWEnLFxuICAgICAgJzAuMC40MTA5OD9tZW1vSWQ9MScsXG4gICAgXTtcblxuICAgIGJhZEFkZHJlc3Nlcy5tYXAoKGFkZHIpID0+IHtcbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKGFkZHIpLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgfSk7XG4gICAgZ29vZEFkZHJlc3Nlcy5tYXAoKGFkZHIpID0+IHtcbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKGFkZHIpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGNvbnN0IGhleEFkZHJlc3MgPSAnMHgyM0MzRTIyN0JFOTcyODFBNzBBNTQ5YzdkREI4ZDVDYWFkM0U3Qzg0JztcbiAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcyhoZXhBZGRyZXNzKS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIGV4cGxhaW4gYSB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0eCA9IEpTT04ucGFyc2UoVGVzdERhdGEucmF3VHJhbnNhY3Rpb25Gb3JFeHBsYWluKTtcbiAgICBjb25zdCBleHBsYWluID0gYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKHR4KTtcblxuICAgIGV4cGxhaW4uaWQuc2hvdWxkLmVxdWFsKCcwLjAuNDMyODVAMTYwMDUyOTgwMC42NDMwOTM1ODYnKTtcbiAgICBleHBsYWluLm91dHB1dEFtb3VudC5zaG91bGQuZXF1YWwoJzIyMDAwMDAwMDAnKTtcbiAgICBleHBsYWluLnRpbWVzdGFtcC5zaG91bGQuZXF1YWwoJzE2MDA1Mjk4MDAuNjQzMDkzNTg2Jyk7XG4gICAgZXhwbGFpbi5leHBpcmF0aW9uLnNob3VsZC5lcXVhbCgnMTgwJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzBdLmFtb3VudC5zaG91bGQuZXF1YWwoJzIyMDAwMDAwMDAnKTtcbiAgICBleHBsYWluLm91dHB1dHNbMF0uYWRkcmVzcy5zaG91bGQuZXF1YWwoJzAuMC40MzI4MycpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5tZW1vLnNob3VsZC5lcXVhbCgnMScpO1xuICAgIGV4cGxhaW4uZmVlLnNob3VsZC5lcXVhbCgxMTYwNDA3KTtcbiAgICBleHBsYWluLmNoYW5nZUFtb3VudC5zaG91bGQuZXF1YWwoJzAnKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBleHBsYWluIGEgdG9rZW4gdHJhbnNmZXIgdHJhbnNhY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgdG9rZW5UcmFuc2ZlclBhcmFtID0ge1xuICAgICAgdHhIZXg6IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX1RSQU5TRkVSLFxuICAgICAgZmVlSW5mbzoge1xuICAgICAgICBzaXplOiAxMDAwLFxuICAgICAgICBmZWU6IDExNjA0MDcsXG4gICAgICAgIGZlZVJhdGU6IDExNjA0MDcsXG4gICAgICB9LFxuICAgIH07XG4gICAgY29uc3QgZXhwbGFpbiA9IGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbih0b2tlblRyYW5zZmVyUGFyYW0pO1xuXG4gICAgZXhwbGFpbi5pZC5zaG91bGQuZXF1YWwoJzAuMC44MTMyMEAxNTk2MTEwNDkzLjM3MjY0NjU3MCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0QW1vdW50LnNob3VsZC5lcXVhbCgnMCcpO1xuICAgIGV4cGxhaW4udGltZXN0YW1wLnNob3VsZC5lcXVhbCgnMTU5NjExMDQ5My4zNzI2NDY1NzAnKTtcbiAgICBleHBsYWluLmV4cGlyYXRpb24uc2hvdWxkLmVxdWFsKCcxODAnKTtcbiAgICBleHBsYWluLm91dHB1dHNbMF0uYW1vdW50LnNob3VsZC5lcXVhbCgnMTAnKTtcbiAgICBleHBsYWluLm91dHB1dHNbMF0uYWRkcmVzcy5zaG91bGQuZXF1YWwoJzAuMC43NTg2MScpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5tZW1vLnNob3VsZC5lcXVhbCgnJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzBdLnRva2VuTmFtZS5zaG91bGQuZXF1YWwoJ3RoYmFyOnVzZGMnKTtcbiAgICBleHBsYWluLmZlZS5zaG91bGQuZXF1YWwoMTE2MDQwNyk7XG4gICAgZXhwbGFpbi5jaGFuZ2VBbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgZXhwbGFpbiBhIG11bHRpcmVjaXBpZW50cyB0cmFuc2ZlciB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBtdWx0aVRyYW5zZmVyUGFyYW0gPSB7XG4gICAgICB0eEhleDogVGVzdERhdGEuVU5TSUdORURfTVVMVElfVFJBTlNGRVIsXG4gICAgICBmZWVJbmZvOiB7XG4gICAgICAgIHNpemU6IDEwMDAsXG4gICAgICAgIGZlZTogMTE2MDQwNyxcbiAgICAgICAgZmVlUmF0ZTogMTE2MDQwNyxcbiAgICAgIH0sXG4gICAgfTtcbiAgICBjb25zdCBleHBsYWluID0gYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKG11bHRpVHJhbnNmZXJQYXJhbSk7XG5cbiAgICBleHBsYWluLmlkLnNob3VsZC5lcXVhbCgnMC4wLjgxMzIwQDE1OTYxMTA0OTMuMzcyNjQ2NTcwJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKCcyNScpO1xuICAgIGV4cGxhaW4uZXhwaXJhdGlvbi5zaG91bGQuZXF1YWwoJzE4MCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5hbW91bnQuc2hvdWxkLmVxdWFsKCcxMCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbCgnMC4wLjc1ODYxJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzBdLm1lbW8uc2hvdWxkLmVxdWFsKCcnKTtcbiAgICBleHBsYWluLm91dHB1dHNbMV0uYW1vdW50LnNob3VsZC5lcXVhbCgnMTUnKTtcbiAgICBleHBsYWluLm91dHB1dHNbMV0uYWRkcmVzcy5zaG91bGQuZXF1YWwoJzAuMC43ODk2MycpO1xuICAgIGV4cGxhaW4uZmVlLnNob3VsZC5lcXVhbCgxMTYwNDA3KTtcbiAgICBleHBsYWluLmNoYW5nZUFtb3VudC5zaG91bGQuZXF1YWwoJzAnKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBleHBsYWluIGEgbXVsdGlyZWNpcGllbnRzIHRva2VuIHRyYW5zZmVyIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHRva2VuTXVsdGlUcmFuc2ZlclBhcmFtID0ge1xuICAgICAgdHhIZXg6IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX01VTFRJX1RSQU5TRkVSLFxuICAgICAgZmVlSW5mbzoge1xuICAgICAgICBzaXplOiAxMDAwLFxuICAgICAgICBmZWU6IDExNjA0MDcsXG4gICAgICAgIGZlZVJhdGU6IDExNjA0MDcsXG4gICAgICB9LFxuICAgIH07XG4gICAgY29uc3QgZXhwbGFpbiA9IGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbih0b2tlbk11bHRpVHJhbnNmZXJQYXJhbSk7XG5cbiAgICBleHBsYWluLmlkLnNob3VsZC5lcXVhbCgnMC4wLjgxMzIwQDE1OTYxMTA0OTMuMzcyNjQ2NTcwJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gICAgZXhwbGFpbi50aW1lc3RhbXAuc2hvdWxkLmVxdWFsKCcxNTk2MTEwNDkzLjM3MjY0NjU3MCcpO1xuICAgIGV4cGxhaW4uZXhwaXJhdGlvbi5zaG91bGQuZXF1YWwoJzE4MCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5hbW91bnQuc2hvdWxkLmVxdWFsKCcxMCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbCgnMC4wLjc1ODYxJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzBdLm1lbW8uc2hvdWxkLmVxdWFsKCcnKTtcbiAgICBleHBsYWluLm91dHB1dHNbMF0udG9rZW5OYW1lLnNob3VsZC5lcXVhbCgndGhiYXI6dXNkYycpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1sxXS5hbW91bnQuc2hvdWxkLmVxdWFsKCcxNScpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1sxXS5hZGRyZXNzLnNob3VsZC5lcXVhbCgnMC4wLjc4OTYzJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzFdLnRva2VuTmFtZS5zaG91bGQuZXF1YWwoJ3RoYmFyOnVzZGMnKTtcbiAgICBleHBsYWluLmZlZS5zaG91bGQuZXF1YWwoMTE2MDQwNyk7XG4gICAgZXhwbGFpbi5jaGFuZ2VBbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgZXhwbGFpbiBhIHRva2VuIGFzc29jaWF0ZSB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB0b2tlbkFzc29jaWF0ZVBhcmFtID0ge1xuICAgICAgdHhIZXg6IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX0FTU09DSUFURSxcbiAgICAgIGZlZUluZm86IHtcbiAgICAgICAgc2l6ZTogMTAwMCxcbiAgICAgICAgZmVlOiAxMTYwNDA3LFxuICAgICAgICBmZWVSYXRlOiAxMTYwNDA3LFxuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IGV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24odG9rZW5Bc3NvY2lhdGVQYXJhbSk7XG5cbiAgICBleHBsYWluLmlkLnNob3VsZC5lcXVhbCgnMC4wLjgxMzIwQDE1OTYxMTA0OTMuMzcyNjQ2NTcwJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gICAgZXhwbGFpbi50aW1lc3RhbXAuc2hvdWxkLmVxdWFsKCcxNTk2MTEwNDkzLjM3MjY0NjU3MCcpO1xuICAgIGV4cGxhaW4uZXhwaXJhdGlvbi5zaG91bGQuZXF1YWwoJzE4MCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5hbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzBdLmFkZHJlc3Muc2hvdWxkLmVxdWFsKCcwLjAuODEzMjAnKTtcbiAgICBleHBsYWluLm91dHB1dHNbMF0ubWVtby5zaG91bGQuZXF1YWwoJycpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS50b2tlbk5hbWUuc2hvdWxkLmVxdWFsKCd0aGJhcjp1c2RjJyk7XG4gICAgZXhwbGFpbi5mZWUuc2hvdWxkLmVxdWFsKDExNjA0MDcpO1xuICAgIGV4cGxhaW4uY2hhbmdlQW1vdW50LnNob3VsZC5lcXVhbCgnMCcpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIGV4cGxhaW4gYW4gYWNjb3VudCB1cGRhdGUgKHN0YWtpbmcpIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHNvdXJjZUFjY291bnRJZCA9ICcwLjAuODEzMjAnO1xuICAgIGNvbnN0IGZhY3RvcnkgPSBnZXRCdWlsZGVyRmFjdG9yeSgndGhiYXInKTtcbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldEFjY291bnRVcGRhdGVCdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLmZlZSh7IGZlZTogJzEwMDAwMDAwMDAnIH0pO1xuICAgIHR4QnVpbGRlci5zb3VyY2UoeyBhZGRyZXNzOiBzb3VyY2VBY2NvdW50SWQgfSk7XG4gICAgdHhCdWlsZGVyLnN0YWtlZE5vZGVJZCgzKTtcbiAgICB0eEJ1aWxkZXIuZGVjbGluZVN0YWtpbmdSZXdhcmQoZmFsc2UpO1xuICAgIHR4QnVpbGRlci5ub2RlKHsgbm9kZUlkOiAnMC4wLjIzNDUnIH0pO1xuICAgIHR4QnVpbGRlci5zdGFydFRpbWUoJzE1OTYxMTA0OTMuMzcyNjQ2NTcwJyk7XG4gICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBjb25zdCB0eEhleCA9IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG5cbiAgICBjb25zdCBleHBsYWluID0gYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKHtcbiAgICAgIHR4SGV4LFxuICAgICAgZmVlSW5mbzoge1xuICAgICAgICBzaXplOiAxMDAwLFxuICAgICAgICBmZWU6IDExNjA0MDcsXG4gICAgICAgIGZlZVJhdGU6IDExNjA0MDcsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgZXhwbGFpbi5pZC5zaG91bGQuZXF1YWwoc291cmNlQWNjb3VudElkICsgJ0AxNTk2MTEwNDkzLjM3MjY0NjU3MCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0QW1vdW50LnNob3VsZC5lcXVhbCgnMCcpO1xuICAgIGV4cGxhaW4udGltZXN0YW1wLnNob3VsZC5lcXVhbCgnMTU5NjExMDQ5My4zNzI2NDY1NzAnKTtcbiAgICBleHBsYWluLm91dHB1dHMubGVuZ3RoLnNob3VsZC5lcXVhbCgxKTtcbiAgICBleHBsYWluLm91dHB1dHNbMF0uYW1vdW50LnNob3VsZC5lcXVhbCgnMCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbChzb3VyY2VBY2NvdW50SWQpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5tZW1vLnNob3VsZC5lcXVhbCgnJyk7XG4gICAgZXhwbGFpbi5mZWUuc2hvdWxkLmVxdWFsKDExNjA0MDcpO1xuICAgIGV4cGxhaW4uY2hhbmdlQW1vdW50LnNob3VsZC5lcXVhbCgnMCcpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIGV4cGxhaW4gYW4gdW5zdGFrZSAoYWNjb3VudCB1cGRhdGUgd2l0aCBub2RlSWQgLTEpIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHNvdXJjZUFjY291bnRJZCA9ICcwLjAuODEzMjAnO1xuICAgIGNvbnN0IGZhY3RvcnkgPSBnZXRCdWlsZGVyRmFjdG9yeSgndGhiYXInKTtcbiAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldEFjY291bnRVcGRhdGVCdWlsZGVyKCk7XG4gICAgdHhCdWlsZGVyLmZlZSh7IGZlZTogJzEwMDAwMDAwMDAnIH0pO1xuICAgIHR4QnVpbGRlci5zb3VyY2UoeyBhZGRyZXNzOiBzb3VyY2VBY2NvdW50SWQgfSk7XG4gICAgdHhCdWlsZGVyLnN0YWtlZE5vZGVJZCgtMSk7XG4gICAgdHhCdWlsZGVyLm5vZGUoeyBub2RlSWQ6ICcwLjAuMjM0NScgfSk7XG4gICAgdHhCdWlsZGVyLnN0YXJ0VGltZSgnMTU5NjExMDQ5My4zNzI2NDY1NzAnKTtcbiAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIGNvbnN0IHR4SGV4ID0gdHgudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgIGNvbnN0IGV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oe1xuICAgICAgdHhIZXgsXG4gICAgICBmZWVJbmZvOiB7XG4gICAgICAgIHNpemU6IDEwMDAsXG4gICAgICAgIGZlZTogMTE2MDQwNyxcbiAgICAgICAgZmVlUmF0ZTogMTE2MDQwNyxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBsYWluLmlkLnNob3VsZC5lcXVhbChzb3VyY2VBY2NvdW50SWQgKyAnQDE1OTYxMTA0OTMuMzcyNjQ2NTcwJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gICAgZXhwbGFpbi50aW1lc3RhbXAuc2hvdWxkLmVxdWFsKCcxNTk2MTEwNDkzLjM3MjY0NjU3MCcpO1xuICAgIGV4cGxhaW4ub3V0cHV0cy5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuICAgIGV4cGxhaW4ub3V0cHV0c1swXS5hbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzBdLmFkZHJlc3Muc2hvdWxkLmVxdWFsKHNvdXJjZUFjY291bnRJZCk7XG4gICAgZXhwbGFpbi5vdXRwdXRzWzBdLm1lbW8uc2hvdWxkLmVxdWFsKCcnKTtcbiAgICBleHBsYWluLmZlZS5zaG91bGQuZXF1YWwoMTE2MDQwNyk7XG4gICAgZXhwbGFpbi5jaGFuZ2VBbW91bnQuc2hvdWxkLmVxdWFsKCcwJyk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdmVyaWZ5IGlzV2FsbGV0QWRkcmVzcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBiYXNlQWRkcmVzcyA9ICcwLjAuNDEwOTgnO1xuICAgIGNvbnN0IHZhbGlkQWRkcmVzczEgPSAnMC4wLjQxMDk4P21lbW9JZD0xJztcbiAgICBjb25zdCB2YWxpZEFkZHJlc3MyID0gJzAuMC40MTA5OD9tZW1vSWQ9Mic7XG4gICAgY29uc3QgdW5yZWxhdGVkVmFsaWRBZGRyZXNzID0gJzAuMS40MTA5OD9tZW1vSWQ9MSc7XG4gICAgY29uc3QgaW52YWxpZEFkZHJlc3MgPSAnMC4wLjAuYSc7XG4gICAgKGF3YWl0IGJhc2Vjb2luLmlzV2FsbGV0QWRkcmVzcyh7IGFkZHJlc3M6IHZhbGlkQWRkcmVzczEsIGJhc2VBZGRyZXNzIH0pKS5zaG91bGQudHJ1ZSgpO1xuICAgIChhd2FpdCBiYXNlY29pbi5pc1dhbGxldEFkZHJlc3MoeyBhZGRyZXNzOiB2YWxpZEFkZHJlc3MyLCBiYXNlQWRkcmVzcyB9KSkuc2hvdWxkLnRydWUoKTtcbiAgICAoYXdhaXQgYmFzZWNvaW4uaXNXYWxsZXRBZGRyZXNzKHsgYWRkcmVzczogdmFsaWRBZGRyZXNzMiwgYmFzZUFkZHJlc3M6IHZhbGlkQWRkcmVzczEgfSkpLnNob3VsZC50cnVlKCk7XG4gICAgKGF3YWl0IGJhc2Vjb2luLmlzV2FsbGV0QWRkcmVzcyh7IGFkZHJlc3M6IHVucmVsYXRlZFZhbGlkQWRkcmVzcywgYmFzZUFkZHJlc3MgfSkpLnNob3VsZC5mYWxzZSgpO1xuXG4gICAgYXNzZXJ0LnJlamVjdHMoXG4gICAgICBhc3luYyAoKSA9PiBiYXNlY29pbi5pc1dhbGxldEFkZHJlc3MoeyBhZGRyZXNzOiBpbnZhbGlkQWRkcmVzcywgYmFzZUFkZHJlc3MgfSksXG4gICAgICBgaW52YWxpZCBhZGRyZXNzICR7aW52YWxpZEFkZHJlc3N9YFxuICAgICk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdLZXlwYWlyczonLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBhIGtleXBhaXIgZnJvbSByYW5kb20gc2VlZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGtleVBhaXIgPSBiYXNlY29pbi5nZW5lcmF0ZUtleVBhaXIoKTtcbiAgICAgIGtleVBhaXIuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3B1YicpO1xuICAgICAga2V5UGFpci5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgncHJ2Jyk7XG5cbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoa2V5UGFpci5wdWIpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgYSBrZXlwYWlyIGZyb20gYSBzZWVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgc2VlZFRleHQgPSAnODAzNTBiNDIwOGQzODFmYmZlMjI3NmEzMjY2MDMwNDlmZTUwMDczMWM0NmQzYzk5MzZiNWNlMDM2YjUxMzc3Zic7XG4gICAgICBjb25zdCBzZWVkID0gQnVmZmVyLmZyb20oc2VlZFRleHQsICdoZXgnKTtcbiAgICAgIGNvbnN0IGtleVBhaXIgPSBiYXNlY29pbi5nZW5lcmF0ZUtleVBhaXIoc2VlZCk7XG5cbiAgICAgIGtleVBhaXIucHJ2LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzMwMmUwMjAxMDAzMDA1MDYwMzJiNjU3MDA0MjIwNDIwODAzNTBiNDIwOGQzODFmYmZlMjI3NmEzMjY2MDMwNDlmZTUwMDczMWM0NmQzYzk5MzZiNWNlMDM2YjUxMzc3ZidcbiAgICAgICk7XG4gICAgICBrZXlQYWlyLnB1Yi5zaG91bGQuZXF1YWwoXG4gICAgICAgICczMDJhMzAwNTA2MDMyYjY1NzAwMzIxMDA5Y2M0MDJiNWM3NTIxNDI2OWMyODI2ZTNjNjExOTM3N2NhYjZjMzY3NjAxMzM4NjYxYzg3YTRlMDdjNmUwMzMzJ1xuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmFsaWRhdGUgYSBzdGVsbGFyIHNlZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBiYXNlY29pbi5pc1N0ZWxsYXJTZWVkKCdTQk1XTE5WNzVCUEkyVkI0RzI3UldPTUFCVlJUU1NGNzM1MkNDWUdWRUxaRFNIQ1hXQ1lGS1hJWCcpLnNob3VsZC5vaygpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBjb252ZXJ0IGEgc3RlbGxhciBzZWVkIHRvIGFuIGhiYXIgcHJ2JywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgc2VlZCA9IGJhc2Vjb2luLmNvbnZlcnRGcm9tU3RlbGxhclNlZWQoJ1NCTVdMTlY3NUJQSTJWQjRHMjdSV09NQUJWUlRTU0Y3MzUyQ0NZR1ZFTFpEU0hDWFdDWUZLWElYJyk7XG4gICAgICBzZWVkLnNob3VsZC5lcXVhbChcbiAgICAgICAgJzMwMmUwMjAxMDAzMDA1MDYwMzJiNjU3MDA0MjIwNDIwNTk2NWI2YmZlODVlOGQ1NDNjMzZiZjFiMzk4MDBkNjMzOTQ4YmZkZjc0MjE2MGQ1MjJmMjM5MWM1N2IwYjA1NSdcbiAgICAgICk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdWZXJpZnkgVHJhbnNhY3Rpb246JywgKCkgPT4ge1xuICAgIGxldCBuZXdUeFByZWJ1aWxkO1xuICAgIGxldCBuZXdUeFBhcmFtcztcbiAgICBsZXQgbmV3VHhQYXJhbXNXaXRoRXJyb3I7XG4gICAgbGV0IG5ld1R4UGFyYW1zV2l0aEV4dHJhRGF0YTtcbiAgICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgICAgcmVjaXBpZW50czogW1xuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogJ2xpb250ZXN0ZTIxMicsXG4gICAgICAgICAgYW1vdW50OiAnMTAwMCcsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgdHhIZXg6IFRlc3REYXRhLlVOU0lHTkVEX01VTFRJX1RSQU5TRkVSLFxuICAgICAgdHhpZDogJzU4NmM1YjU5YjEwYjEzNGQwNGMxNmFjMWIyNzNmZTNjNTUyOWYzNGFlZjc1ZGI0NDU2Y2Q0NjljNWNkYWM3ZTInLFxuICAgICAgaXNWb3RpbmdUcmFuc2FjdGlvbjogZmFsc2UsXG4gICAgICBjb2luOiAndGhiYXInLFxuICAgICAgZmVlSW5mbzoge1xuICAgICAgICBzaXplOiAxMDAwLFxuICAgICAgICBmZWU6IDExNjA0MDcsXG4gICAgICAgIGZlZVJhdGU6IDExNjA0MDcsXG4gICAgICB9LFxuICAgIH07XG4gICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICB0eFByZWJ1aWxkLFxuICAgICAgcmVjaXBpZW50czogW1xuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogJzAuMC43NTg2MScsXG4gICAgICAgICAgYW1vdW50OiAnMTAnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogJzAuMC43ODk2MycsXG4gICAgICAgICAgYW1vdW50OiAnMTUnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9O1xuICAgIGNvbnN0IG1lbW8gPSB7IHZhbHVlOiAnJyB9O1xuICAgIGNvbnN0IHR4UGFyYW1zV2l0aEVycm9yID0ge1xuICAgICAgdHhQcmVidWlsZCxcbiAgICAgIHJlY2lwaWVudHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICcwLjAuNzU4NjEnLFxuICAgICAgICAgIGFtb3VudDogJzEwMDAnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9O1xuICAgIGNvbnN0IHR4UGFyYW1zV2l0aEV4dHJhRGF0YSA9IHtcbiAgICAgIHR4UHJlYnVpbGQsXG4gICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiAnMC4wLjc1ODYxJyxcbiAgICAgICAgICBhbW91bnQ6ICcxMCcsXG4gICAgICAgICAgZGF0YTogdW5kZWZpbmVkLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogJzAuMC43ODk2MycsXG4gICAgICAgICAgYW1vdW50OiAnMTUnLFxuICAgICAgICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfTtcbiAgICBjb25zdCB3YWxsZXREYXRhID0ge1xuICAgICAgaWQ6ICc1YjM0MjUyZjFiZjM0OTkzMGUzNDAyMGEwMDAwMDAwMCcsXG4gICAgICBjb2luOiAndGhiYXInLFxuICAgICAga2V5czogW1xuICAgICAgICAnNWIzNDI0ZjkxYmYzNDk5MzBlMzQwMTc1MDAwMDAwMDAnLFxuICAgICAgICAnNWIzNDI0ZjkxYmYzNDk5MzBlMzQwMTc2MDAwMDAwMDAnLFxuICAgICAgICAnNWIzNDI0ZjkxYmYzNDk5MzBlMzQwMTc3MDAwMDAwMDAnLFxuICAgICAgXSxcbiAgICAgIGNvaW5TcGVjaWZpYzoge1xuICAgICAgICBiYXNlQWRkcmVzczogJzAuMC4yOTM1JyxcbiAgICAgIH0sXG4gICAgICBtdWx0aXNpZ1R5cGU6ICdvbmNoYWluJyxcbiAgICB9O1xuICAgIGNvbnN0IHdhbGxldE9iaiA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2Vjb2luLCB3YWxsZXREYXRhKTtcblxuICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICBuZXdUeFByZWJ1aWxkID0gKCkgPT4ge1xuICAgICAgICByZXR1cm4gXy5jbG9uZURlZXAodHhQcmVidWlsZCk7XG4gICAgICB9O1xuICAgICAgbmV3VHhQYXJhbXMgPSAoKSA9PiB7XG4gICAgICAgIHJldHVybiBfLmNsb25lRGVlcCh0eFBhcmFtcyk7XG4gICAgICB9O1xuICAgICAgbmV3VHhQYXJhbXNXaXRoRXJyb3IgPSAoKSA9PiB7XG4gICAgICAgIHJldHVybiBfLmNsb25lRGVlcCh0eFBhcmFtc1dpdGhFcnJvcik7XG4gICAgICB9O1xuICAgICAgbmV3VHhQYXJhbXNXaXRoRXh0cmFEYXRhID0gKCkgPT4ge1xuICAgICAgICByZXR1cm4gXy5jbG9uZURlZXAodHhQYXJhbXNXaXRoRXh0cmFEYXRhKTtcbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZlcmlmeSBuYXRpdmUgdHJhbnNmZXIgdHJhbnNhY3Rpb25zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIGNvbnN0IHZhbGlkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zLFxuICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICBtZW1vLFxuICAgICAgICB3YWxsZXQ6IHdhbGxldE9iaixcbiAgICAgIH0gYXMgYW55KTtcbiAgICAgIHZhbGlkVHJhbnNhY3Rpb24uc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHZlcmlmeSB3aGVuIGlucHV0IGByZWNpcGllbnRzYCBpcyBhYnNlbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFBhcmFtcyA9IG5ld1R4UGFyYW1zKCk7XG4gICAgICB0eFBhcmFtcy5yZWNpcGllbnRzID0gdW5kZWZpbmVkO1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCBtZW1vOiBtZW1vLCB3YWxsZXQ6IHdhbGxldE9iaiB9IGFzIGFueSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ21pc3NpbmcgcmVxdWlyZWQgdHggcGFyYW1zIHByb3BlcnR5IHJlY2lwaWVudHMnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB2ZXJpZnkgdHJhbnNhY3Rpb25zIHdoZW4gaGF2ZSBkaWZmZXJlbnQgcmVjaXBpZW50cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0gbmV3VHhQYXJhbXNXaXRoRXJyb3IoKTtcbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSBuZXdUeFByZWJ1aWxkKCk7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCwgbWVtbywgd2FsbGV0OiB3YWxsZXRPYmogfSBhcyBhbnkpXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdUeCBvdXRwdXRzIGRvZXMgbm90IG1hdGNoIHdpdGggZXhwZWN0ZWQgdHhQYXJhbXMgcmVjaXBpZW50cycpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBzdWNjZWVkIHRvIHZlcmlmeSB0cmFuc2FjdGlvbnMgd2hlbiByZWNpcGllbnRzIGhhcyBleHRyYSBkYXRhJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtc1dpdGhFeHRyYURhdGEoKTtcbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSBuZXdUeFByZWJ1aWxkKCk7XG4gICAgICBjb25zdCB2YWxpZFRyYW5zYWN0aW9uID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtcyxcbiAgICAgICAgdHhQcmVidWlsZCxcbiAgICAgICAgbWVtbyxcbiAgICAgICAgd2FsbGV0OiB3YWxsZXRPYmosXG4gICAgICB9IGFzIGFueSk7XG4gICAgICB2YWxpZFRyYW5zYWN0aW9uLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmVyaWZ5IGNyZWF0ZSBhc3NvY2lhdGVkIHRva2VuIGFjY291bnQgdHJhbnNhY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFBhcmFtcyA9IG5ld1R4UGFyYW1zKCk7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0gbmV3VHhQcmVidWlsZCgpO1xuICAgICAgdHhQcmVidWlsZC50eEhleCA9IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX0FTU09DSUFURTtcbiAgICAgIHR4UGFyYW1zLnR5cGUgPSAnZW5hYmxldG9rZW4nO1xuICAgICAgdHhQYXJhbXMucmVjaXBpZW50cyA9IFtcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICcwLjAuODEzMjAnLFxuICAgICAgICAgIGFtb3VudDogJzAnLFxuICAgICAgICAgIHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnLFxuICAgICAgICB9LFxuICAgICAgXTtcbiAgICAgIGNvbnN0IHZhbGlkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UGFyYW1zLFxuICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICBtZW1vLFxuICAgICAgICB3YWxsZXQ6IHdhbGxldE9iaixcbiAgICAgICAgdmVyaWZpY2F0aW9uOiB7IHZlcmlmeVRva2VuRW5hYmxlbWVudDogdHJ1ZSB9LFxuICAgICAgfSBhcyBhbnkpO1xuICAgICAgdmFsaWRUcmFuc2FjdGlvbi5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdmVyaWZ5IGNyZWF0ZSBhc3NvY2lhdGVkIHRva2VuIGFjY291bnQgdHJhbnNhY3Rpb24gd2l0aCBtaXNtYXRjaCByZWNpcGllbnRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIHR4UHJlYnVpbGQudHhIZXggPSBUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9BU1NPQ0lBVEU7XG4gICAgICB0eFBhcmFtcy50eXBlID0gJ2VuYWJsZXRva2VuJztcbiAgICAgIHR4UGFyYW1zLnJlY2lwaWVudHMgPSBbXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiAnMC4wLjgxMzIxJyxcbiAgICAgICAgICBhbW91bnQ6ICcwJyxcbiAgICAgICAgICB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UGFyYW1zLFxuICAgICAgICAgIHR4UHJlYnVpbGQsXG4gICAgICAgICAgbWVtbyxcbiAgICAgICAgICB3YWxsZXQ6IHdhbGxldE9iaixcbiAgICAgICAgICB2ZXJpZmljYXRpb246IHsgdmVyaWZ5VG9rZW5FbmFibGVtZW50OiB0cnVlIH0sXG4gICAgICAgIH0gYXMgYW55KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnSW52YWxpZCB0b2tlbiBlbmFibGVtZW50IHRyYW5zYWN0aW9uOiBFeHBlY3RlZCBhY2NvdW50IDAuMC44MTMyMSwgZ290IDAuMC44MTMyMCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB2ZXJpZnkgdG9rZW4gdHJhbnNmZXIgdHJhbnNhY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFBhcmFtcyA9IG5ld1R4UGFyYW1zKCk7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0gbmV3VHhQcmVidWlsZCgpO1xuICAgICAgdHhQcmVidWlsZC50eEhleCA9IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX01VTFRJX1RSQU5TRkVSO1xuICAgICAgdHhQYXJhbXMucmVjaXBpZW50cyA9IFtcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICcwLjAuNzU4NjEnLFxuICAgICAgICAgIGFtb3VudDogJzEwJyxcbiAgICAgICAgICB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICcwLjAuNzg5NjMnLFxuICAgICAgICAgIGFtb3VudDogJzE1JyxcbiAgICAgICAgICB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgICBjb25zdCB2YWxpZFRyYW5zYWN0aW9uID0gYXdhaXQgdG9rZW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFBhcmFtcyxcbiAgICAgICAgdHhQcmVidWlsZCxcbiAgICAgICAgbWVtbyxcbiAgICAgICAgd2FsbGV0OiB3YWxsZXRPYmosXG4gICAgICB9IGFzIGFueSk7XG4gICAgICB2YWxpZFRyYW5zYWN0aW9uLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmVyaWZ5IHRva2VuIHRyYW5zZmVyIHRyYW5zYWN0aW9uIHdpdGggYW55IHRva2VuIG5hbWUgb24gdG9rZW4gYmFzZSBjb2luJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIHR4UHJlYnVpbGQudHhIZXggPSBUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9NVUxUSV9UUkFOU0ZFUjtcbiAgICAgIHR4UGFyYW1zLnJlY2lwaWVudHMgPSBbXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiAnMC4wLjc1ODYxJyxcbiAgICAgICAgICBhbW91bnQ6ICcxMCcsXG4gICAgICAgICAgdG9rZW5OYW1lOiAndGhiYXI6dXNkYycsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiAnMC4wLjc4OTYzJyxcbiAgICAgICAgICBhbW91bnQ6ICcxNScsXG4gICAgICAgIH0sXG4gICAgICBdO1xuICAgICAgKGF3YWl0IHRva2VuLnZlcmlmeVRyYW5zYWN0aW9uKHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQsIG1lbW8sIHdhbGxldDogd2FsbGV0T2JqIH0gYXMgYW55KSkuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHRvIHZlcmlmeSB0b2tlbiB0cmFuc2ZlciB3aXRoIG1pc21hdGNoZWQgcmVjaXBpZW50cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0gbmV3VHhQYXJhbXMoKTtcbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSBuZXdUeFByZWJ1aWxkKCk7XG4gICAgICB0eFByZWJ1aWxkLnR4SGV4ID0gVGVzdERhdGEuVU5TSUdORURfVE9LRU5fTVVMVElfVFJBTlNGRVI7XG4gICAgICB0eFBhcmFtcy5yZWNpcGllbnRzID0gW1xuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogJzAuMC43NTg2MScsXG4gICAgICAgICAgYW1vdW50OiAnMTEnLFxuICAgICAgICAgIHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogJzAuMC43ODk2MycsXG4gICAgICAgICAgYW1vdW50OiAnMTUnLFxuICAgICAgICB9LFxuICAgICAgXTtcbiAgICAgIGF3YWl0IHRva2VuXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCBtZW1vLCB3YWxsZXQ6IHdhbGxldE9iaiB9IGFzIGFueSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ1R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCB0eFBhcmFtcyByZWNpcGllbnRzJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdG8gdmVyaWZ5IHRva2VuIHRyYW5zZmVyIHdpdGggaW5jb3JyZWN0IHRva2VuIG5hbWUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFBhcmFtcyA9IG5ld1R4UGFyYW1zKCk7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0gbmV3VHhQcmVidWlsZCgpO1xuICAgICAgdHhQcmVidWlsZC50eEhleCA9IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX01VTFRJX1RSQU5TRkVSO1xuICAgICAgdHhQYXJhbXMucmVjaXBpZW50cyA9IFtcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICcwLjAuNzU4NjEnLFxuICAgICAgICAgIGFtb3VudDogJzExJyxcbiAgICAgICAgICB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICcwLjAuNzg5NjMnLFxuICAgICAgICAgIGFtb3VudDogJzE1JyxcbiAgICAgICAgICB0b2tlbk5hbWU6ICdpbnZhbGlkdG9rZW4nLFxuICAgICAgICB9LFxuICAgICAgXTtcbiAgICAgIGF3YWl0IHRva2VuXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7IHR4UGFyYW1zLCB0eFByZWJ1aWxkLCBtZW1vLCB3YWxsZXQ6IHdhbGxldE9iaiB9IGFzIGFueSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ0luY29ycmVjdCB0b2tlbiBuYW1lIHNwZWNpZmllZCBpbiByZWNpcGllbnRzJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN1Y2Nlc3MgdG8gdmVyaWZ5IHRyYW5zZmVyIGhhdmluZyBhZGRyZXNzIHdpdGggbWVtbyBpZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0gbmV3VHhQYXJhbXMoKTtcbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSBuZXdUeFByZWJ1aWxkKCk7XG4gICAgICB0eFByZWJ1aWxkLnR4SGV4ID0gVGVzdERhdGEuVU5TSUdORURfVE9LRU5fQVNTT0NJQVRFO1xuICAgICAgdHhQYXJhbXMudHlwZSA9ICdlbmFibGV0b2tlbic7XG4gICAgICB0eFBhcmFtcy5yZWNpcGllbnRzID0gW1xuICAgICAgICB7XG4gICAgICAgICAgYWRkcmVzczogJzAuMC44MTMyMD9tZW1vSWQ9MScsXG4gICAgICAgICAgYW1vdW50OiAnMCcsXG4gICAgICAgICAgdG9rZW5OYW1lOiAndGhiYXI6dXNkYycsXG4gICAgICAgIH0sXG4gICAgICBdO1xuICAgICAgY29uc3QgdmFsaWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQYXJhbXMsXG4gICAgICAgIHR4UHJlYnVpbGQsXG4gICAgICAgIG1lbW8sXG4gICAgICAgIHdhbGxldDogd2FsbGV0T2JqLFxuICAgICAgICB2ZXJpZmljYXRpb246IHsgdmVyaWZ5VG9rZW5FbmFibGVtZW50OiB0cnVlIH0sXG4gICAgICB9IGFzIGFueSk7XG4gICAgICB2YWxpZFRyYW5zYWN0aW9uLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1ZlcmlmeSBUb2tlbiBFbmFibGVtZW50IFRyYW5zYWN0aW9uOicsICgpID0+IHtcbiAgICBpdCgnc2hvdWxkIHZlcmlmeSBhIHZhbGlkIHRva2VuIGVuYWJsZW1lbnQgdHJhbnNhY3Rpb24gd2l0aCB0b2tlbk5hbWUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eEhleCA9IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX0FTU09DSUFURTtcbiAgICAgIGNvbnN0IGV4cGVjdGVkVG9rZW4gPSB7IHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH07XG4gICAgICBjb25zdCBleHBlY3RlZEFjY291bnRJZCA9ICcwLjAuODEzMjAnO1xuXG4gICAgICBhd2FpdCBiYXNlY29pbi52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbih0eEhleCwgZXhwZWN0ZWRUb2tlbiwgZXhwZWN0ZWRBY2NvdW50SWQpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB2ZXJpZnkgYSB2YWxpZCB0b2tlbiBlbmFibGVtZW50IHRyYW5zYWN0aW9uIHdpdGggdG9rZW5JZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gVGVzdERhdGEuVU5TSUdORURfVE9LRU5fQVNTT0NJQVRFO1xuICAgICAgY29uc3QgZXhwZWN0ZWRUb2tlbiA9IHsgdG9rZW5JZDogJzAuMC40MjkyNzQnIH07IC8vIEFjdHVhbCB0b2tlbklkIGZvciB0aGJhcjp1c2RjXG4gICAgICBjb25zdCBleHBlY3RlZEFjY291bnRJZCA9ICcwLjAuODEzMjAnO1xuXG4gICAgICBhd2FpdCBiYXNlY29pbi52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbih0eEhleCwgZXhwZWN0ZWRUb2tlbiwgZXhwZWN0ZWRBY2NvdW50SWQpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdoZW4gdHhIZXggaXMgbWlzc2luZycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbignJywgeyB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyB9LCAnMC4wLjgxMzIwJylcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ01pc3NpbmcgcmVxdWlyZWQgcGFyYW1ldGVyczogdHhIZXgnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB3aGVuIGV4cGVjdGVkQWNjb3VudElkIGlzIG1pc3NpbmcnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VG9rZW5FbmFibGVtZW50VHJhbnNhY3Rpb24oVGVzdERhdGEuVU5TSUdORURfVE9LRU5fQVNTT0NJQVRFLCB7IHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH0sICcnKVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnTWlzc2luZyByZXF1aXJlZCBwYXJhbWV0ZXJzOiBleHBlY3RlZEFjY291bnRJZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdoZW4gd2FsbGV0IHBsYXRmb3JtIHNlbmRzIHNwb29mZWQgdHJhbnNhY3Rpb24gaGV4IGZvciB0b2tlbiBlbmFibGVtZW50JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gQ3JlYXRlIGEgdmFsaWQgdHJhbnNhY3Rpb24gcmVzcG9uc2Ugc3RydWN0dXJlIGZyb20gd2FsbGV0IHBsYXRmb3JtIHdpdGggc3Bvb2ZlZCB0eEhleFxuICAgICAgLy8gVGhlIHR4SGV4IGxvb2tzIGxpa2UgdmFsaWQgaGV4IGJ1dCBjb250YWlucyBtYWxpY2lvdXMvaW52YWxpZCB0cmFuc2FjdGlvbiBkYXRhXG4gICAgICBjb25zdCBzcG9vZmVkVHhIZXggPSAnMGEwYzBhMDgwODAwMTAwMDE4YThmYjA0MTAxMzBhMGMwYTA4MDgwMDEwMDAxOGQ1ZDAwNDEwMTQnOyAvLyBWYWxpZCBoZXggYnV0IGludmFsaWQgdHJhbnNhY3Rpb25cblxuICAgICAgLy8gTW9jayB0aGUgQVBJIGVuZHBvaW50cyB0aGF0IHdpbGwgYmUgY2FsbGVkIGR1cmluZyB0b2tlbiBlbmFibGVtZW50XG4gICAgICBjb25zdCBiZ1VybCA9IGNvbW1vbi5FbnZpcm9ubWVudHNbJ21vY2snXS51cmk7XG5cbiAgICAgIC8vIE1vY2sgdGhlIGtleSBlbmRwb2ludCBuZWVkZWQgZm9yIHNpZ25pbmdcbiAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgIC5wb3N0KCcvYXBpL3YyL3RoYmFyL2tleS81YjM0MjRmOTFiZjM0OTkzMDA2ZWFlOTQnKVxuICAgICAgICAucmVwbHkoMjAwLCBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgZW5jcnlwdGVkUHJ2OiAnZmFrZVBydicsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSk7XG5cbiAgICAgIC8vIE1vY2sgdGhlIHByZWJ1aWxkIEFQSSByZXNwb25zZSB0byByZXR1cm4gc3Bvb2ZlZCB0eEhleFxuICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgLnBvc3QoJy9hcGkvdjIvdGhiYXIvd2FsbGV0LzViMzQyNTJmMWJmMzQ5OTMwMDZlYWU5Ni90eC9idWlsZCcpXG4gICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICB0eEhleDogc3Bvb2ZlZFR4SGV4LFxuICAgICAgICAgIHR4aWQ6ICc1ODZjNWI1OWIxMGIxMzRkMDRjMTZhYzFiMjczZmUzYzU1MjlmMzRhZWY3NWRiNDQ1NmNkNDY5YzVjZGFjN2UyJyxcbiAgICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGFkZHJlc3M6ICcwLjAuODEzMjAnLFxuICAgICAgICAgICAgICBhbW91bnQ6ICcwJywgLy8gVmFsaWQgYW1vdW50IGZvciB0b2tlbiBlbmFibGVtZW50XG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgICAgY29pbjogJ3RoYmFyJyxcbiAgICAgICAgICBmZWVJbmZvOiB7XG4gICAgICAgICAgICBzaXplOiAxMDAwLFxuICAgICAgICAgICAgZmVlOiAxMTYwNDA3LFxuICAgICAgICAgICAgZmVlUmF0ZTogMTE2MDQwNyxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgLy8gVGhpcyBzaG91bGQgZmFpbCBiZWNhdXNlIHRoZSBzcG9vZmVkIHRyYW5zYWN0aW9uIGhleCBjb250YWlucyBpbnZhbGlkIHRyYW5zYWN0aW9uIGRhdGFcbiAgICAgIC8vIFRoZSB2ZXJpZmljYXRpb24gbG9naWMgc2hvdWxkIGNhdGNoIHRoaXMgd2hlbiB0cnlpbmcgdG8gdmFsaWRhdGUgdGhlIHRyYW5zYWN0aW9uXG4gICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyhcbiAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIC8vIFRlc3QgdGhlIHZlcmlmaWNhdGlvbiBkaXJlY3RseSBpbnN0ZWFkIG9mIGdvaW5nIHRocm91Z2ggdGhlIHdhbGxldCBmbG93XG4gICAgICAgICAgYXdhaXQgYmFzZWNvaW4udmVyaWZ5VG9rZW5FbmFibGVtZW50VHJhbnNhY3Rpb24oc3Bvb2ZlZFR4SGV4LCB7IHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH0sICcwLjAuODEzMjAnKTtcbiAgICAgICAgfSxcbiAgICAgICAgKGVycm9yOiBhbnkpID0+IHtcbiAgICAgICAgICAvLyBUaGUgZXJyb3Igc2hvdWxkIGluZGljYXRlIHRoYXQgdGhlIHRyYW5zYWN0aW9uIGlzIGludmFsaWRcbiAgICAgICAgICByZXR1cm4gZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnSW52YWxpZCB0b2tlbiBlbmFibGVtZW50IHRyYW5zYWN0aW9uJyk7XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2hlbiBib3RoIHRva2VuSWQgYW5kIHRva2VuTmFtZSBhcmUgbWlzc2luZycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbihUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9BU1NPQ0lBVEUsIHt9LCAnMC4wLjgxMzIwJylcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ01pc3NpbmcgcmVxdWlyZWQgcGFyYW1ldGVyczogZXhwZWN0ZWRUb2tlbi50b2tlbklkfHRva2VuTmFtZScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdoZW4gdG9rZW4gbmFtZSBkb2VzIG5vdCBtYXRjaCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbihcbiAgICAgICAgICBUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9BU1NPQ0lBVEUsXG4gICAgICAgICAgeyB0b2tlbk5hbWU6ICd0aGJhcjp3cm9uZ3Rva2VuJyB9LFxuICAgICAgICAgICcwLjAuODEzMjAnXG4gICAgICAgIClcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL0V4cGVjdGVkIHRva2VuIG5hbWUgdGhiYXI6d3Jvbmd0b2tlbiwgZ290IHRoYmFyOnVzZGMvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB3aGVuIGFjY291bnQgSUQgZG9lcyBub3QgbWF0Y2gnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VG9rZW5FbmFibGVtZW50VHJhbnNhY3Rpb24oVGVzdERhdGEuVU5TSUdORURfVE9LRU5fQVNTT0NJQVRFLCB7IHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH0sICcwLjAuOTk5OTknKVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvRXhwZWN0ZWQgYWNjb3VudCAwLjAuOTk5OTksIGdvdCAwLjAuODEzMjAvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB3aGVuIHRyYW5zYWN0aW9uIGlzIG5vdCBhIHRva2VuIGVuYWJsZW1lbnQgKGhhcyBub24temVybyBhbW91bnQpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gVXNlIGEgcmVndWxhciB0cmFuc2ZlciB0cmFuc2FjdGlvbiB3aGljaCBoYXMgbm9uLXplcm8gYW1vdW50XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VG9rZW5FbmFibGVtZW50VHJhbnNhY3Rpb24oVGVzdERhdGEuVU5TSUdORURfVE9LRU5fVFJBTlNGRVIsIHsgdG9rZW5OYW1lOiAndGhiYXI6dXNkYycgfSwgJzAuMC44MTMyMCcpXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9FeHBlY3RlZCBvdXRwdXQgYW1vdW50ICcwJy8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdoZW4gdHJhbnNhY3Rpb24gdHlwZSBpcyBub3QgdG9rZW5Bc3NvY2lhdGUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBVc2UgYSByZWd1bGFyIHRyYW5zZmVyIHRyYW5zYWN0aW9uIHdoaWNoIGlzIG5vdCB0b2tlbkFzc29jaWF0ZVxuICAgICAgLy8gVGhpcyB3aWxsIGZhaWwgb24gYW1vdW50IHZhbGlkYXRpb24gZmlyc3QsIGJ1dCB0aGF0J3MgZXhwZWN0ZWQgYmVoYXZpb3JcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbihUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9UUkFOU0ZFUiwgeyB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyB9LCAnMC4wLjgxMzIwJylcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL0V4cGVjdGVkIG91dHB1dCBhbW91bnQgJzAnLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZhbGlkYXRlIHRyYW5zYWN0aW9uIHR5cGUgZm9yIHZhbGlkIHRva2VuIGFzc29jaWF0ZSB0cmFuc2FjdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIFRoaXMgdGVzdCBlbnN1cmVzIHRoZSB0cmFuc2FjdGlvbiB0eXBlIHZhbGlkYXRpb24gd29ya3MgZm9yIHZhbGlkIHRva2VuIGFzc29jaWF0ZSB0cmFuc2FjdGlvbnNcbiAgICAgIGNvbnN0IHR4SGV4ID0gVGVzdERhdGEuVU5TSUdORURfVE9LRU5fQVNTT0NJQVRFO1xuICAgICAgY29uc3QgZXhwZWN0ZWRUb2tlbiA9IHsgdG9rZW5OYW1lOiAndGhiYXI6dXNkYycgfTtcbiAgICAgIGNvbnN0IGV4cGVjdGVkQWNjb3VudElkID0gJzAuMC44MTMyMCc7XG5cbiAgICAgIGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRva2VuRW5hYmxlbWVudFRyYW5zYWN0aW9uKHR4SGV4LCBleHBlY3RlZFRva2VuLCBleHBlY3RlZEFjY291bnRJZCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2l0aCBpbnZhbGlkIHRyYW5zYWN0aW9uIGhleCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbignaW52YWxpZF9oZXgnLCB7IHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH0sICcwLjAuODEzMjAnKVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvSW52YWxpZCB0b2tlbiBlbmFibGVtZW50IHRyYW5zYWN0aW9uLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2hlbiB0eEhleCBjb250YWlucyB3cm9uZyB0b2tlbklkIGNvbXBhcmVkIHRvIGV4cGVjdGVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gVGhpcyB0ZXN0IGVuc3VyZXMgZGlyZWN0IHR4SGV4IHZhbGlkYXRpb24gY2F0Y2hlcyBzcG9vZmVkIHRva2VuSWRzXG4gICAgICBjb25zdCB0eEhleCA9IFRlc3REYXRhLlVOU0lHTkVEX1RPS0VOX0FTU09DSUFURTtcbiAgICAgIGNvbnN0IHdyb25nVG9rZW5JZCA9ICcwLjAuOTk5OTk5JzsgLy8gV3JvbmcgdG9rZW5JZFxuICAgICAgY29uc3QgZXhwZWN0ZWRBY2NvdW50SWQgPSAnMC4wLjgxMzIwJztcblxuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnZlcmlmeVRva2VuRW5hYmxlbWVudFRyYW5zYWN0aW9uKHR4SGV4LCB7IHRva2VuSWQ6IHdyb25nVG9rZW5JZCB9LCBleHBlY3RlZEFjY291bnRJZClcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoXG4gICAgICAgICAgbmV3IFJlZ0V4cChgRXhwZWN0ZWQgdG9rZW5JZCAke18uZXNjYXBlUmVnRXhwKHdyb25nVG9rZW5JZCl9LCBidXQgdHJhbnNhY3Rpb24gY29udGFpbnMgdG9rZW5JZGApXG4gICAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2hlbiB0eEhleCBjb250YWlucyB3cm9uZyBhY2NvdW50SWQgY29tcGFyZWQgdG8gZXhwZWN0ZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBUaGlzIHRlc3QgZW5zdXJlcyBkaXJlY3QgdHhIZXggdmFsaWRhdGlvbiBjYXRjaGVzIHNwb29mZWQgYWNjb3VudElkc1xuICAgICAgY29uc3QgdHhIZXggPSBUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9BU1NPQ0lBVEU7XG4gICAgICBjb25zdCBleHBlY3RlZFRva2VuID0geyB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyB9O1xuICAgICAgY29uc3Qgd3JvbmdBY2NvdW50SWQgPSAnMC4wLjk5OTk5OSc7IC8vIFdyb25nIGFjY291bnRJZFxuXG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VG9rZW5FbmFibGVtZW50VHJhbnNhY3Rpb24odHhIZXgsIGV4cGVjdGVkVG9rZW4sIHdyb25nQWNjb3VudElkKVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aChuZXcgUmVnRXhwKGBFeHBlY3RlZCBhY2NvdW50ICR7Xy5lc2NhcGVSZWdFeHAod3JvbmdBY2NvdW50SWQpfSwgZ290YCkpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBwYXNzIHZlcmlmaWNhdGlvbiBmb3IgdmFsaWQgdG9rZW4gZW5hYmxlbWVudCB0cmFuc2FjdGlvbiB3aXRob3V0IHRocm93aW5nIGVycm9yJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gVGhpcyB0ZXN0IGVuc3VyZXMgdGhhdCBhIHZhbGlkIHRva2VuIGVuYWJsZW1lbnQgdHJhbnNhY3Rpb24gcGFzc2VzIGFsbCB2YWxpZGF0aW9uc1xuICAgICAgY29uc3QgdHhIZXggPSBUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9BU1NPQ0lBVEU7XG4gICAgICBjb25zdCBleHBlY3RlZFRva2VuID0geyB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyB9O1xuICAgICAgY29uc3QgZXhwZWN0ZWRBY2NvdW50SWQgPSAnMC4wLjgxMzIwJztcblxuICAgICAgLy8gVGhpcyBzaG91bGQgY29tcGxldGUgd2l0aG91dCB0aHJvd2luZyBhbnkgZXJyb3JzXG4gICAgICBhd2FpdCBiYXNlY29pbi52ZXJpZnlUb2tlbkVuYWJsZW1lbnRUcmFuc2FjdGlvbih0eEhleCwgZXhwZWN0ZWRUb2tlbiwgZXhwZWN0ZWRBY2NvdW50SWQpO1xuXG4gICAgICAvLyBJZiB3ZSByZWFjaCB0aGlzIHBvaW50LCB0aGUgdGVzdCBwYXNzZWRcbiAgICAgIGFzc2VydC5vayh0cnVlLCAnVmFsaWQgdG9rZW4gZW5hYmxlbWVudCB0cmFuc2FjdGlvbiBzaG91bGQgbm90IHRocm93IGFueSBlcnJvcnMnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc3VjY2Vzc2Z1bGx5IGNvbXBsZXRlIHNlbmRUb2tlbkVuYWJsZW1lbnRzIHdpdGggdmFsaWQgdHJhbnNhY3Rpb24gcmVzcG9uc2UgZnJvbSB3YWxsZXQgcGxhdGZvcm0nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB2YWxpZFR4SGV4ID0gVGVzdERhdGEuVU5TSUdORURfVE9LRU5fQVNTT0NJQVRFO1xuXG4gICAgICBjb25zdCB3YWxsZXQgPSB7XG4gICAgICAgIGlkOiAoKSA9PiAnNWIzNDI1MmYxYmYzNDk5MzAwNmVhZTk2JyxcbiAgICAgICAgY29pbjogKCkgPT4gJ3RoYmFyJyxcbiAgICAgICAgcHJlYnVpbGRUcmFuc2FjdGlvbjogYXN5bmMgKCkgPT4gKHtcbiAgICAgICAgICB0eEhleDogdmFsaWRUeEhleCwgLy8gVmFsaWQgdG9rZW4gYXNzb2NpYXRlIHRyYW5zYWN0aW9uXG4gICAgICAgICAgdHhpZDogJzU4NmM1YjU5YjEwYjEzNGQwNGMxNmFjMWIyNzNmZTNjNTUyOWYzNGFlZjc1ZGI0NDU2Y2Q0NjljNWNkYWM3ZTInLFxuICAgICAgICAgIHJlY2lwaWVudHM6IFt7IGFkZHJlc3M6ICcwLjAuODEzMjAnLCBhbW91bnQ6ICcwJyB9XSxcbiAgICAgICAgICBjb2luOiAndGhiYXInLFxuICAgICAgICAgIGZlZUluZm86IHsgc2l6ZTogMTAwMCwgZmVlOiAxMTYwNDA3LCBmZWVSYXRlOiAxMTYwNDA3IH0sXG4gICAgICAgIH0pLFxuICAgICAgICBzZW5kVG9rZW5FbmFibGVtZW50czogYXN5bmMgKHBhcmFtczogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3QgdHhQcmVidWlsZCA9IGF3YWl0IHdhbGxldC5wcmVidWlsZFRyYW5zYWN0aW9uKCk7XG4gICAgICAgICAgYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgICAgcmVjaXBpZW50czogW3sgYWRkcmVzczogJzAuMC44MTMyMCcsIGFtb3VudDogJzAnLCB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyB9XSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICAgICAgdmVyaWZpY2F0aW9uOiB7IHZlcmlmeVRva2VuRW5hYmxlbWVudDogdHJ1ZSB9LFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IFt7IHR4aWQ6IHR4UHJlYnVpbGQudHhpZCwgc3RhdHVzOiAnc3VjY2VzcycgfV0sXG4gICAgICAgICAgICBmYWlsdXJlOiBbXSxcbiAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgfTtcblxuICAgICAgYXdhaXQgd2FsbGV0LnNlbmRUb2tlbkVuYWJsZW1lbnRzKHtcbiAgICAgICAgcmVjaXBpZW50czogW3sgYWRkcmVzczogJzAuMC44MTMyMCcsIHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH1dLFxuICAgICAgfSk7XG5cbiAgICAgIGFzc2VydC5vayhcbiAgICAgICAgdHJ1ZSxcbiAgICAgICAgJ1ZhbGlkIHRva2VuIGVuYWJsZW1lbnQgdHJhbnNhY3Rpb24gc2hvdWxkIGNvbXBsZXRlIHN1Y2Nlc3NmdWxseSB0aHJvdWdoIHNlbmRUb2tlbkVuYWJsZW1lbnRzIGZsb3cnXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBkZXRlY3Qgc3Bvb2ZlZCB0cmFuc2FjdGlvbiBoZXggdGhyb3VnaCBzZW5kVG9rZW5FbmFibGVtZW50cyBmbG93JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gVXNlIGEgdmFsaWQgdHJhbnNmZXIgdHJhbnNhY3Rpb24gaGV4IGluc3RlYWQgb2YgYSB0b2tlbiBhc3NvY2lhdGUgdHJhbnNhY3Rpb25cbiAgICAgIC8vIFRoaXMgd2lsbCBwYXJzZSBjb3JyZWN0bHkgYnV0IGZhaWwgdmFsaWRhdGlvbiBiZWNhdXNlIGl0J3Mgbm90IGEgdG9rZW4gYXNzb2NpYXRlIHRyYW5zYWN0aW9uXG4gICAgICBjb25zdCBzcG9vZmVkVHhIZXggPSBUZXN0RGF0YS5VTlNJR05FRF9UT0tFTl9UUkFOU0ZFUjsgLy8gVmFsaWQgdHJhbnNmZXIgdHJhbnNhY3Rpb24sIG5vdCB0b2tlbiBhc3NvY2lhdGVcblxuICAgICAgLy8gQ3JlYXRlIGEgd2FsbGV0IG1vY2sgZm9yIHRoZSBzZW5kVG9rZW5FbmFibGVtZW50cyBmbG93XG4gICAgICBjb25zdCB3YWxsZXQgPSB7XG4gICAgICAgIGlkOiAoKSA9PiAnNWIzNDI1MmYxYmYzNDk5MzAwNmVhZTk2JyxcbiAgICAgICAgY29pbjogKCkgPT4gJ3RoYmFyJyxcbiAgICAgICAgcHJlYnVpbGRUcmFuc2FjdGlvbjogYXN5bmMgKCkgPT4gKHtcbiAgICAgICAgICB0eEhleDogc3Bvb2ZlZFR4SGV4LFxuICAgICAgICAgIHR4aWQ6ICc1ODZjNWI1OWIxMGIxMzRkMDRjMTZhYzFiMjczZmUzYzU1MjlmMzRhZWY3NWRiNDQ1NmNkNDY5YzVjZGFjN2UyJyxcbiAgICAgICAgICByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiAnMC4wLjgxMzIwJywgYW1vdW50OiAnMCcgfV0sXG4gICAgICAgICAgY29pbjogJ3RoYmFyJyxcbiAgICAgICAgICBmZWVJbmZvOiB7IHNpemU6IDEwMDAsIGZlZTogMTE2MDQwNywgZmVlUmF0ZTogMTE2MDQwNyB9LFxuICAgICAgICB9KSxcbiAgICAgICAgc2VuZFRva2VuRW5hYmxlbWVudHM6IGFzeW5jIChwYXJhbXM6IGFueSkgPT4ge1xuICAgICAgICAgIC8vIFRoaXMgc2hvdWxkIHRyaWdnZXIgdGhlIHZlcmlmaWNhdGlvbiBhbmQgZmFpbFxuICAgICAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSBhd2FpdCB3YWxsZXQucHJlYnVpbGRUcmFuc2FjdGlvbigpO1xuICAgICAgICAgIHJldHVybiBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgICAgICByZWNpcGllbnRzOiBbeyBhZGRyZXNzOiAnMC4wLjgxMzIwJywgYW1vdW50OiAnMCcsIHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH1dLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHR4UHJlYnVpbGQsXG4gICAgICAgICAgICB2ZXJpZmljYXRpb246IHsgdmVyaWZ5VG9rZW5FbmFibGVtZW50OiB0cnVlIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICB9O1xuXG4gICAgICAvLyBUaGlzIHNob3VsZCBmYWlsIGJlY2F1c2UgdGhlIHNwb29mZWQgdHJhbnNhY3Rpb24gaGV4IGNvbnRhaW5zIGEgdHJhbnNmZXIgdHJhbnNhY3Rpb24sIG5vdCBhIHRva2VuIGFzc29jaWF0ZVxuICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCB3YWxsZXQuc2VuZFRva2VuRW5hYmxlbWVudHMoe1xuICAgICAgICAgICAgcmVjaXBpZW50czogW3sgYWRkcmVzczogJzAuMC44MTMyMCcsIHRva2VuTmFtZTogJ3RoYmFyOnVzZGMnIH1dLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuICAgICAgICAoZXJyb3I6IGFueSkgPT4ge1xuICAgICAgICAgIC8vIFRoZSBlcnJvciBzaG91bGQgaW5kaWNhdGUgdGhhdCB0aGUgdHJhbnNhY3Rpb24gaXMgaW52YWxpZCBmb3IgdG9rZW4gZW5hYmxlbWVudFxuICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBlcnJvci5tZXNzYWdlLmluY2x1ZGVzKCdJbnZhbGlkIHRva2VuIGVuYWJsZW1lbnQgdHJhbnNhY3Rpb24nKSB8fFxuICAgICAgICAgICAgZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnVG9rZW4gZW5hYmxlbWVudCB0cmFuc2FjdGlvbiBtaXNzaW5nIHRva2VuSWQnKSB8fFxuICAgICAgICAgICAgZXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcIkV4cGVjdGVkIG91dHB1dCBhbW91bnQgJzAnXCIpIHx8XG4gICAgICAgICAgICBlcnJvci5tZXNzYWdlLmluY2x1ZGVzKCdUcmFuc2FjdGlvbiBpcyBub3QgYSBUb2tlbkFzc29jaWF0ZSB0cmFuc2FjdGlvbicpXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1NpZ24gTWVzc2FnZScsICgpID0+IHtcbiAgICBpdCgnc2hvdWxkIGJlIHBlcmZvcm1lZCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGtleVBhaXIgPSBuZXcgS2V5UGFpcigpO1xuICAgICAgY29uc3QgbWVzc2FnZVRvU2lnbiA9IEJ1ZmZlci5mcm9tKHJhbmRvbUJ5dGVzKDMyKSkudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gYXdhaXQgYmFzZWNvaW4uc2lnbk1lc3NhZ2Uoa2V5UGFpci5nZXRLZXlzKCksIG1lc3NhZ2VUb1NpZ24pO1xuICAgICAga2V5UGFpci52ZXJpZnlTaWduYXR1cmUobWVzc2FnZVRvU2lnbiwgVWludDhBcnJheS5mcm9tKEJ1ZmZlci5mcm9tKHNpZ25hdHVyZSwgJ2hleCcpKSkuc2hvdWxkLmVxdWFscyh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB3aXRoIG1pc3NpbmcgcHJpdmF0ZSBrZXknLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBrZXlQYWlyID0gbmV3IEtleVBhaXIoe1xuICAgICAgICBwdWI6ICczMDJhMzAwNTA2MDMyYjY1NzAwMzIxMDBkOGZkNzQ1MzYxZGYyNzA3NzZhM2FiMWI1NWQ1NTkwZWMwMGEyNmFiNDVlZWEzNzE5N2RjOTg5NGE4MWZjYjgyJyxcbiAgICAgIH0pLmdldEtleXMoKTtcbiAgICAgIGNvbnN0IG1lc3NhZ2VUb1NpZ24gPSBCdWZmZXIuZnJvbShyYW5kb21CeXRlcygzMikpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGF3YWl0IGJhc2Vjb2luLnNpZ25NZXNzYWdlKGtleVBhaXIsIG1lc3NhZ2VUb1NpZ24pLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ0ludmFsaWQga2V5IHBhaXIgb3B0aW9ucycpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnU2lnbiB0cmFuc2FjdGlvbjonLCAoKSA9PiB7XG4gICAgY29uc3QgZGVzdGluYXRpb24gPSAnMC4wLjEyOTM2OSc7XG4gICAgY29uc3Qgc291cmNlID0gJzAuMC4xMjM0JztcbiAgICBjb25zdCBhbW91bnQgPSAnMTAwMDAwJztcbiAgICAvKipcbiAgICAgKiBCdWlsZCBhbiB1bnNpZ25lZCBhY2NvdW50LWxpYiBtdWx0aS1zaWduYXR1cmUgc2VuZCB0cmFuc2FjdGlvblxuICAgICAqIEBwYXJhbSBkZXN0aW5hdGlvbiBUaGUgZGVzdGluYXRpb24gYWRkcmVzcyBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICAgKiBAcGFyYW0gc291cmNlIFRoZSBhY2NvdW50IHNlbmRpbmcgdGhpc3QgcmFuc2FjdGlvblxuICAgICAqIEBwYXJhbSBhbW91bnQgVGhlIGFtb3VudCB0byBzZW5kIHRvIHRoZSByZWNpcGllbnRcbiAgICAgKi9cbiAgICBjb25zdCBidWlsZFVuc2lnbmVkVHJhbnNhY3Rpb24gPSBhc3luYyBmdW5jdGlvbiAoeyBkZXN0aW5hdGlvbiwgc291cmNlLCBhbW91bnQgPSAnMTAwMDAwJyB9KSB7XG4gICAgICBjb25zdCBmYWN0b3J5ID0gZ2V0QnVpbGRlckZhY3RvcnkoJ3RoYmFyJyk7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmdldFRyYW5zZmVyQnVpbGRlcigpO1xuICAgICAgdHhCdWlsZGVyLmZlZSh7XG4gICAgICAgIGZlZTogJzEwMDAwMCcsXG4gICAgICB9KTtcbiAgICAgIHR4QnVpbGRlci5zb3VyY2UoeyBhZGRyZXNzOiBzb3VyY2UgfSk7XG4gICAgICB0eEJ1aWxkZXIuc2VuZCh7IGFkZHJlc3M6IGRlc3RpbmF0aW9uLCBhbW91bnQgfSk7XG5cbiAgICAgIHJldHVybiBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICB9O1xuXG4gICAgaXQoJ3Nob3VsZCBzaWduIHRyYW5zYWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qga2V5ID0gbmV3IEtleVBhaXIoKTtcbiAgICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBidWlsZFVuc2lnbmVkVHJhbnNhY3Rpb24oe1xuICAgICAgICBkZXN0aW5hdGlvbixcbiAgICAgICAgc291cmNlLFxuICAgICAgICBhbW91bnQsXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgdHggPSBhd2FpdCBiYXNlY29pbi5zaWduVHJhbnNhY3Rpb24oe1xuICAgICAgICBwcnY6IGtleS5nZXRLZXlzKCkucHJ2IS50b1N0cmluZygpLFxuICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgdHhIZXg6IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBmYWN0b3J5ID0gZ2V0QnVpbGRlckZhY3RvcnkoJ3RoYmFyJyk7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5LmZyb20odHguaGFsZlNpZ25lZC50eEhleCk7XG4gICAgICBjb25zdCBzaWduZWRUeCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgY29uc3QgdHhKc29uID0gc2lnbmVkVHgudG9Kc29uKCkgYXMgVHhEYXRhO1xuICAgICAgdHhKc29uLnNob3VsZC5oYXZlLnByb3BlcnRpZXMoJ3RvJywgJ2Ftb3VudCcpO1xuICAgICAgdHhKc29uLnRvPy5zaG91bGQuZXF1YWwoZGVzdGluYXRpb24pO1xuICAgICAgdHhKc29uLmZyb20uc2hvdWxkLmVxdWFsKHNvdXJjZSk7XG4gICAgICB0eEpzb24uYW1vdW50Py5zaG91bGQuZXF1YWwoYW1vdW50KTtcbiAgICAgICh0eEpzb24uaW5zdHJ1Y3Rpb25zRGF0YSBhcyBUcmFuc2ZlcikucGFyYW1zLnJlY2lwaWVudHNbMF0uc2hvdWxkLmRlZXBFcXVhbCh7XG4gICAgICAgIGFkZHJlc3M6IGRlc3RpbmF0aW9uLFxuICAgICAgICBhbW91bnQsXG4gICAgICB9KTtcbiAgICAgIHNpZ25lZFR4LnNpZ25hdHVyZS5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmdWxseSBzaWduIHRyYW5zYWN0aW9uIHdpdGggcm9vdCBrZXknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBrZXkxID0gYmFzZWNvaW4uZ2VuZXJhdGVSb290S2V5UGFpcigpO1xuICAgICAgY29uc3Qga2V5MiA9IGJhc2Vjb2luLmdlbmVyYXRlUm9vdEtleVBhaXIoKTtcblxuICAgICAgY29uc3QgdW5zaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IGJ1aWxkVW5zaWduZWRUcmFuc2FjdGlvbih7XG4gICAgICAgIGRlc3RpbmF0aW9uLFxuICAgICAgICBzb3VyY2UsXG4gICAgICAgIGFtb3VudCxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCB0eEhhbGZTaWduZWQgPSBhd2FpdCBiYXNlY29pbi5zaWduVHJhbnNhY3Rpb24oe1xuICAgICAgICBwcnY6IGtleTEucHJ2LFxuICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgdHhIZXg6IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBmYWN0b3J5ID0gZ2V0QnVpbGRlckZhY3RvcnkoJ3RoYmFyJyk7XG4gICAgICBjb25zdCB0eEJ1aWxkZXJIYWxmU2lnbmVkID0gZmFjdG9yeS5mcm9tKHR4SGFsZlNpZ25lZC5oYWxmU2lnbmVkLnR4SGV4KTtcbiAgICAgIGNvbnN0IGhhbGZTaWduZWRUeCA9IGF3YWl0IHR4QnVpbGRlckhhbGZTaWduZWQuYnVpbGQoKTtcbiAgICAgIGNvbnN0IGhhbGZTaWduZWRUeEpzb24gPSBoYWxmU2lnbmVkVHgudG9Kc29uKCkgYXMgVHhEYXRhO1xuICAgICAgaGFsZlNpZ25lZFR4SnNvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0aWVzKCd0bycsICdhbW91bnQnKTtcbiAgICAgIGhhbGZTaWduZWRUeEpzb24udG8/LnNob3VsZC5lcXVhbChkZXN0aW5hdGlvbik7XG4gICAgICBoYWxmU2lnbmVkVHhKc29uLmZyb20uc2hvdWxkLmVxdWFsKHNvdXJjZSk7XG4gICAgICBoYWxmU2lnbmVkVHhKc29uLmFtb3VudD8uc2hvdWxkLmVxdWFsKGFtb3VudCk7XG4gICAgICAoaGFsZlNpZ25lZFR4SnNvbi5pbnN0cnVjdGlvbnNEYXRhIGFzIFRyYW5zZmVyKS5wYXJhbXMucmVjaXBpZW50c1swXS5zaG91bGQuZGVlcEVxdWFsKHtcbiAgICAgICAgYWRkcmVzczogZGVzdGluYXRpb24sXG4gICAgICAgIGFtb3VudCxcbiAgICAgIH0pO1xuICAgICAgaGFsZlNpZ25lZFR4LnNpZ25hdHVyZS5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuXG4gICAgICBjb25zdCB0eFNpZ25lZCA9IGF3YWl0IGJhc2Vjb2luLnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgIHBydjoga2V5Mi5wcnYsXG4gICAgICAgIHR4UHJlYnVpbGQ6IHtcbiAgICAgICAgICB0eEhleDogaGFsZlNpZ25lZFR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgdHhCdWlsZGVyU2lnbmVkID0gZmFjdG9yeS5mcm9tKHR4U2lnbmVkLnR4SGV4KTtcbiAgICAgIGNvbnN0IHNpZ25lZFR4ID0gYXdhaXQgdHhCdWlsZGVyU2lnbmVkLmJ1aWxkKCk7XG4gICAgICBjb25zdCBzaWduZWRUeEpzb24gPSBzaWduZWRUeC50b0pzb24oKSBhcyBUeERhdGE7XG4gICAgICBzaWduZWRUeEpzb24uc2hvdWxkLmhhdmUucHJvcGVydGllcygndG8nLCAnYW1vdW50Jyk7XG4gICAgICBzaWduZWRUeEpzb24udG8/LnNob3VsZC5lcXVhbChkZXN0aW5hdGlvbik7XG4gICAgICBzaWduZWRUeEpzb24uZnJvbS5zaG91bGQuZXF1YWwoc291cmNlKTtcbiAgICAgIHNpZ25lZFR4SnNvbi5hbW91bnQ/LnNob3VsZC5lcXVhbChhbW91bnQpO1xuICAgICAgKHNpZ25lZFR4SnNvbi5pbnN0cnVjdGlvbnNEYXRhIGFzIFRyYW5zZmVyKS5wYXJhbXMucmVjaXBpZW50c1swXS5zaG91bGQuZGVlcEVxdWFsKHtcbiAgICAgICAgYWRkcmVzczogZGVzdGluYXRpb24sXG4gICAgICAgIGFtb3VudCxcbiAgICAgIH0pO1xuICAgICAgc2lnbmVkVHguc2lnbmF0dXJlLmxlbmd0aC5zaG91bGQuZXF1YWwoMik7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdSZWNvdmVyeScsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBkZWZhdWx0VmFsaWREdXJhdGlvbiA9ICcxODAnO1xuICAgIGNvbnN0IGRlZmF1bHRGZWUgPSAxMDAwMDAwMDtcbiAgICBjb25zdCBkZWZhdWx0Tm9kZUlkID0gJzAuMC4zJztcbiAgICBjb25zdCB1c2VyS2V5ID1cbiAgICAgICd7XCJpdlwiOlwiV2xQdUpPZWpSV2dqL05UZDNVTWdydz09XCIsXCJ2XCI6MSxcIml0ZXJcIjoxMDAwMCxcImtzXCI6MjU2LFwidHNcIjo2NCxcIm1vZGVcIjpcImNjbVwiLFwiYWRhdGFcIjpcIlwiLFwiY2lwaGVyXCI6XCJhZXNcIixcInNhbHRcIjpcIjZ5QVZGdnJlSFNRPVwiLFwiY3RcIjpcIjhqL2xCVmtGQnlLbFZoYVM5SldtbUxqYTV5VG9ramFJaUxEeE1JRGpNb2pWRWltOVQzNldBbTVxVzZ2MVYwQTdRY0V1R2lWbDNQS01EYStHcjZ0SS9IVDU4RFc1UkUrcEh6eWE5TVVRcEFnTnJKcjhWRVdqclhXcVpFQ1Z0cmExL2JLQ3lCK21vemM9XCJ9JztcbiAgICBjb25zdCB1c2VyUHViID0gJzMwMmEzMDA1MDYwMzJiNjU3MDAzMjEwMGRkZDUzYTE1OTFkNzJiMTgxMTA5YmQzZTU3YjE4NjAzNzQwNDkwYjlhYjRkMzdiYzdmYTI3NDgwZTZiOGM5MTEnO1xuICAgIGNvbnN0IGJhY2t1cEtleSA9XG4gICAgICAne1wiaXZcIjpcIkQ1RFZEb3pReDlCMDJKZUZWMC9PVkE9PVwiLFwidlwiOjEsXCJpdGVyXCI6MTAwMDAsXCJrc1wiOjI1NixcInRzXCI6NjQsXCJtb2RlXCI6XCJjY21cIixcImFkYXRhXCI6XCJcIixcImNpcGhlclwiOlwiYWVzXCIsXCJzYWx0XCI6XCI3RlVORjhNMzVibz1cIixcImN0XCI6XCJaaVBzdTVRZS9BSVM0SlFYdCtycnVzSG5ZQ3k0Q3F1ck0xNlI1d0pyZDRDRXg3dTg1eTN5eTVFcm5zZHlZWWNjM3R4eU5tVUlRMi9DQnEvTEtvS08vVkllVSsrQ25LeHpHdUhHY05JNDdCUGszUlFLNDJhNjZ1SVFuL3lUUisrWGdkSzFLaHZVTDNVPVwifSc7XG4gICAgY29uc3QgYmFja3VwUHViID0gJzMwMmEzMDA1MDYwMzJiNjU3MDAzMjEwMDYyOTNlNGVjOWJmMWIyZDhmYWU2MzExMTkxMDcyNDhhNjVlMjIwN2EwNWQzMmExMWY0MmNjM2Q5YTMwMDVkNGEnO1xuICAgIGNvbnN0IHJvb3RBZGRyZXNzID0gJzAuMC43NjcxMTg2JztcbiAgICBjb25zdCB3YWxsZXRQYXNzcGhyYXNlID0gJ1Rlc3RQYXNzd29yZFBsZWFzZUlnbm9yZSc7XG4gICAgY29uc3QgcmVjb3ZlcnlEZXN0aW5hdGlvbiA9ICcwLjAuNzY1MTkwOCc7XG4gICAgY29uc3QgYml0Z29LZXkgPSAnNWE5M2IwMWVhODdlOTYzZjYxYzk3NGE4OWQ2MmUzODQxMzkyZjFiYTAyMGZiYmNjNjVhODA4OWNhMDI1YWJiYic7XG4gICAgY29uc3QgbWVtbyA9ICc0JztcbiAgICBjb25zdCBiYWxhbmNlID0gJzEwMDAwMDAwMDAnO1xuICAgIGNvbnN0IGZvcm1hdEJhbGFuY2VSZXNwb25zZSA9IChiYWxhbmNlOiBzdHJpbmcpID0+XG4gICAgICBuZXcgQmlnTnVtYmVyKGJhbGFuY2UpLmRpdmlkZWRCeShiYXNlY29pbi5nZXRCYXNlRmFjdG9yKCkpLnRvRml4ZWQoOSkgKyAnIOKEjyc7XG4gICAgY29uc3QgdG9rZW5JZCA9ICcwLjAuNDI5Mjc0JztcblxuICAgIGRlc2NyaWJlKCdOb24tQml0R28nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBzYW5kQm94ID0gU2lub24uY3JlYXRlU2FuZGJveCgpO1xuXG4gICAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICBzYW5kQm94LnZlcmlmeUFuZFJlc3RvcmUoKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIGJ1aWxkIGFuZCBzaWduIHRoZSByZWNvdmVyeSB0eCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgZXhwZWN0ZWRBbW91bnQgPSBuZXcgQmlnTnVtYmVyKGJhbGFuY2UpLm1pbnVzKGRlZmF1bHRGZWUpLnRvU3RyaW5nKCk7XG4gICAgICAgIGNvbnN0IGdldEJhbGFuY2VTdHViID0gc2FuZEJveFxuICAgICAgICAgIC5zdHViKEhiYXIucHJvdG90eXBlLCAnZ2V0QWNjb3VudEJhbGFuY2UnKVxuICAgICAgICAgIC5yZXNvbHZlcyh7IGhiYXJzOiBmb3JtYXRCYWxhbmNlUmVzcG9uc2UoYmFsYW5jZSksIHRva2VuczogW10gfSk7XG5cbiAgICAgICAgY29uc3QgcmVjb3ZlcnkgPSBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgICB1c2VyS2V5LFxuICAgICAgICAgIGJhY2t1cEtleSxcbiAgICAgICAgICByb290QWRkcmVzcyxcbiAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHJlY292ZXJ5RGVzdGluYXRpb24gKyAnP21lbW9JZD0nICsgbWVtbyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLm5vdC5iZS51bmRlZmluZWQoKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2lkJyk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eCcpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnY29pbicsICd0aGJhcicpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbm9kZUlkJywgZGVmYXVsdE5vZGVJZCk7XG4gICAgICAgIGdldEJhbGFuY2VTdHViLmNhbGxDb3VudC5zaG91bGQuZXF1YWwoMSk7XG4gICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGJhc2Vjb2luLmdldEJ1aWxkZXJGYWN0b3J5KCkuZnJvbShyZWNvdmVyeS50eCk7XG4gICAgICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgIHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCkuc2hvdWxkLmVxdWFsKHJlY292ZXJ5LnR4KTtcbiAgICAgICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG4gICAgICAgIHR4SnNvbi5hbW91bnQuc2hvdWxkLmVxdWFsKGV4cGVjdGVkQW1vdW50KTtcbiAgICAgICAgdHhKc29uLnRvLnNob3VsZC5lcXVhbChyZWNvdmVyeURlc3RpbmF0aW9uKTtcbiAgICAgICAgdHhKc29uLmZyb20uc2hvdWxkLmVxdWFsKHJvb3RBZGRyZXNzKTtcbiAgICAgICAgdHhKc29uLmZlZS5zaG91bGQuZXF1YWwoZGVmYXVsdEZlZSk7XG4gICAgICAgIHR4SnNvbi5ub2RlLnNob3VsZC5lcXVhbChkZWZhdWx0Tm9kZUlkKTtcbiAgICAgICAgdHhKc29uLm1lbW8uc2hvdWxkLmVxdWFsKG1lbW8pO1xuICAgICAgICB0eEpzb24udmFsaWREdXJhdGlvbi5zaG91bGQuZXF1YWwoZGVmYXVsdFZhbGlkRHVyYXRpb24pO1xuICAgICAgICB0eEpzb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ3N0YXJ0VGltZScpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnc3RhcnRUaW1lJywgdHhKc29uLnN0YXJ0VGltZSk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdpZCcsIHJvb3RBZGRyZXNzICsgJ0AnICsgdHhKc29uLnN0YXJ0VGltZSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCB0aHJvdyBmb3IgaW52YWxpZCByb290QWRkcmVzcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgaW52YWxpZFJvb3RBZGRyZXNzID0gJ3JhbmRvbXN0cmluZyc7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgICAgICB1c2VyS2V5LFxuICAgICAgICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgICAgICAgIHJvb3RBZGRyZXNzOiAncmFuZG9tc3RyaW5nJyxcbiAgICAgICAgICAgICAgd2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogcmVjb3ZlcnlEZXN0aW5hdGlvbiArICc/bWVtb0lkPScgKyBtZW1vLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICB7IG1lc3NhZ2U6ICdpbnZhbGlkIHJvb3RBZGRyZXNzLCBnb3Q6ICcgKyBpbnZhbGlkUm9vdEFkZHJlc3MgfVxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgZm9yIGludmFsaWQgcmVjb3ZlcnlEZXN0aW5hdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgaW52YWxpZFJlY292ZXJ5RGVzdGluYXRpb24gPSAncmFuZG9tc3RyaW5nJztcbiAgICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgICAgIHVzZXJLZXksXG4gICAgICAgICAgICAgIGJhY2t1cEtleSxcbiAgICAgICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2UsXG4gICAgICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246ICdyYW5kb21zdHJpbmcnLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICB7IG1lc3NhZ2U6ICdpbnZhbGlkIHJlY292ZXJ5RGVzdGluYXRpb24sIGdvdDogJyArIGludmFsaWRSZWNvdmVyeURlc3RpbmF0aW9uIH1cbiAgICAgICAgKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGZvciBpbnZhbGlkIG5vZGVJZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgaW52YWxpZE5vZGVJZCA9ICdhLjIuMyc7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgICAgICB1c2VyS2V5LFxuICAgICAgICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgICAgICAgIHJvb3RBZGRyZXNzLFxuICAgICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgICAgIG5vZGVJZDogaW52YWxpZE5vZGVJZCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBtZXNzYWdlOiAnaW52YWxpZCBub2RlSWQsIGdvdDogJyArIGludmFsaWROb2RlSWQgfVxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgZm9yIGludmFsaWQgbWF4RmVlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBpbnZhbGlkTWF4RmVlID0gJy0zMic7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgICAgICB1c2VyS2V5LFxuICAgICAgICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgICAgICAgIHJvb3RBZGRyZXNzLFxuICAgICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgICAgIG1heEZlZTogaW52YWxpZE1heEZlZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBtZXNzYWdlOiAnaW52YWxpZCBtYXhGZWUsIGdvdDogJyArIGludmFsaWRNYXhGZWUgfVxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgaWYgdGhlcmUgaXMgbm8gZW5vdWdoIGJhbGFuY2UgdG8gcmVjb3ZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgZ2V0QmFsYW5jZVN0dWIgPSBzYW5kQm94XG4gICAgICAgICAgLnN0dWIoSGJhci5wcm90b3R5cGUsICdnZXRBY2NvdW50QmFsYW5jZScpXG4gICAgICAgICAgLnJlc29sdmVzKHsgaGJhcnM6IGZvcm1hdEJhbGFuY2VSZXNwb25zZSgnMTAwJyksIHRva2VuczogW10gfSk7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgICAgIHVzZXJLZXksXG4gICAgICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgICAgICByb290QWRkcmVzcyxcbiAgICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2UsXG4gICAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0sIEVycm9yTm9JbnB1dFRvUmVjb3Zlcik7XG5cbiAgICAgICAgZ2V0QmFsYW5jZVN0dWIuY2FsbENvdW50LnNob3VsZC5lcXVhbCgxKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGlmIHRoZSB3YWxsZXRQYXNzcGhyYXNlIGlzIHVuZGVmaW5lZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgICAgIHVzZXJLZXksXG4gICAgICAgICAgICAgIGJhY2t1cEtleSxcbiAgICAgICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHJlY292ZXJ5RGVzdGluYXRpb24gKyAnP21lbW9JZD0nICsgbWVtbyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBtZXNzYWdlOiAnd2FsbGV0UGFzc3BocmFzZSBpcyByZXF1aXJlZCBmb3Igbm9uLWJpdGdvIHJlY292ZXJ5JyB9XG4gICAgICAgICk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiB0aGUgd2FsbGV0UGFzc3BocmFzZSBpcyB3cm9uZycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgICAgIHVzZXJLZXksXG4gICAgICAgICAgICAgIGJhY2t1cEtleSxcbiAgICAgICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2U6ICdyYW5kb21wYXNzd29yZCcsXG4gICAgICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHJlY292ZXJ5RGVzdGluYXRpb24gKyAnP21lbW9JZD0nICsgbWVtbyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgJ3VuYWJsZSB0byBkZWNyeXB0IHVzZXJLZXkgb3IgYmFja3VwS2V5IHdpdGggdGhlIHdhbGxldFBhc3NwaHJhc2UgcHJvdmlkZWQsIGdvdCBlcnJvcjogaW5jb3JyZWN0IHBhc3N3b3JkJyxcbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCBidWlsZCBhbmQgc2lnbiB0aGUgcmVjb3ZlcnkgdHggZm9yIHRva2VucycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgYmFsYW5jZSA9ICcxMDAnO1xuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgIGhiYXJzOiAnMScsXG4gICAgICAgICAgdG9rZW5zOiBbeyB0b2tlbklkOiB0b2tlbklkLCBiYWxhbmNlOiBiYWxhbmNlLCBkZWNpbWFsczogNiB9XSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgZ2V0QmFsYW5jZVN0dWIgPSBzYW5kQm94LnN0dWIoSGJhci5wcm90b3R5cGUsICdnZXRBY2NvdW50QmFsYW5jZScpLnJlc29sdmVzKGRhdGEpO1xuXG4gICAgICAgIGNvbnN0IHJlY292ZXJ5ID0gYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgdXNlcktleSxcbiAgICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgdG9rZW5JZDogdG9rZW5JZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLm5vdC5iZS51bmRlZmluZWQoKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2lkJyk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eCcpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnY29pbicsICd0aGJhcicpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbm9kZUlkJywgZGVmYXVsdE5vZGVJZCk7XG4gICAgICAgIGdldEJhbGFuY2VTdHViLmNhbGxDb3VudC5zaG91bGQuZXF1YWwoMSk7XG4gICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGJhc2Vjb2luLmdldEJ1aWxkZXJGYWN0b3J5KCkuZnJvbShyZWNvdmVyeS50eCk7XG4gICAgICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgIHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCkuc2hvdWxkLmVxdWFsKHJlY292ZXJ5LnR4KTtcbiAgICAgICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG4gICAgICAgIHR4SnNvbi5hbW91bnQuc2hvdWxkLmVxdWFsKGJhbGFuY2UpO1xuICAgICAgICB0eEpzb24udG8uc2hvdWxkLmVxdWFsKHJlY292ZXJ5RGVzdGluYXRpb24pO1xuICAgICAgICB0eEpzb24uZnJvbS5zaG91bGQuZXF1YWwocm9vdEFkZHJlc3MpO1xuICAgICAgICB0eEpzb24uZmVlLnNob3VsZC5lcXVhbChkZWZhdWx0RmVlKTtcbiAgICAgICAgdHhKc29uLm5vZGUuc2hvdWxkLmVxdWFsKGRlZmF1bHROb2RlSWQpO1xuICAgICAgICB0eEpzb24ubWVtby5zaG91bGQuZXF1YWwobWVtbyk7XG4gICAgICAgIHR4SnNvbi52YWxpZER1cmF0aW9uLnNob3VsZC5lcXVhbChkZWZhdWx0VmFsaWREdXJhdGlvbik7XG4gICAgICAgIHR4SnNvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnc3RhcnRUaW1lJyk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdzdGFydFRpbWUnLCB0eEpzb24uc3RhcnRUaW1lKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2lkJywgcm9vdEFkZHJlc3MgKyAnQCcgKyB0eEpzb24uc3RhcnRUaW1lKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGVycm9yIGZvciBub24gc3VwcG9ydGVkIGludmFsaWQgdG9rZW5JZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgaW52YWxpZFRva2VuSWQgPSAncmFuZG9tc3RyaW5nJztcbiAgICAgICAgY29uc3QgZGF0YSA9IHtcbiAgICAgICAgICBoYmFyczogJzEnLFxuICAgICAgICAgIHRva2VuczogW3sgdG9rZW5JZDogdG9rZW5JZCwgYmFsYW5jZTogJzEwMCcsIGRlY2ltYWxzOiA2IH1dLFxuICAgICAgICB9O1xuICAgICAgICBzYW5kQm94LnN0dWIoSGJhci5wcm90b3R5cGUsICdnZXRBY2NvdW50QmFsYW5jZScpLnJlc29sdmVzKGRhdGEpO1xuICAgICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyhcbiAgICAgICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgICAgICAgdXNlcktleSxcbiAgICAgICAgICAgICAgYmFja3VwS2V5LFxuICAgICAgICAgICAgICByb290QWRkcmVzczogcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2UsXG4gICAgICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHJlY292ZXJ5RGVzdGluYXRpb24gKyAnP21lbW9JZD0nICsgbWVtbyxcbiAgICAgICAgICAgICAgdG9rZW5JZDogaW52YWxpZFRva2VuSWQsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHsgbWVzc2FnZTogJ1Vuc3VwcG9ydGVkIHRva2VuOiAnICsgaW52YWxpZFRva2VuSWQgfVxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3IgZm9yIGluc3VmZmljaWVudCBiYWxhbmNlIGZvciB0b2tlbklkIGlmIHRva2VuIGJhbGFuY2Ugbm90IGV4aXN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgIGhiYXJzOiAnMTAwJyxcbiAgICAgICAgICB0b2tlbnM6IFt7IHRva2VuSWQ6ICdyYW5kb21TdHJpbmcnLCBiYWxhbmNlOiAnMTAwJywgZGVjaW1hbHM6IDYgfV0sXG4gICAgICAgIH07XG4gICAgICAgIHNhbmRCb3guc3R1YihIYmFyLnByb3RvdHlwZSwgJ2dldEFjY291bnRCYWxhbmNlJykucmVzb2x2ZXMoZGF0YSk7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgICAgIHVzZXJLZXksXG4gICAgICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgICAgICByb290QWRkcmVzczogcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogcmVjb3ZlcnlEZXN0aW5hdGlvbiArICc/bWVtb0lkPScgKyBtZW1vLFxuICAgICAgICAgICAgdG9rZW5JZDogdG9rZW5JZCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgRXJyb3JOb0lucHV0VG9SZWNvdmVyKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGVycm9yIGZvciBpbnN1ZmZpY2llbnQgYmFsYW5jZSBmb3IgdG9rZW5JZCBpZiB0b2tlbiBiYWxhbmNlIGV4aXN0IHdpdGggMCBhbW91bnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSB7XG4gICAgICAgICAgaGJhcnM6ICcxMDAnLFxuICAgICAgICAgIHRva2VuczogW3sgdG9rZW5JZDogJ3JhbmRvbVN0cmluZycsIGJhbGFuY2U6ICcwJywgZGVjaW1hbHM6IDYgfV0sXG4gICAgICAgIH07XG4gICAgICAgIHNhbmRCb3guc3R1YihIYmFyLnByb3RvdHlwZSwgJ2dldEFjY291bnRCYWxhbmNlJykucmVzb2x2ZXMoZGF0YSk7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgICAgIHVzZXJLZXksXG4gICAgICAgICAgICBiYWNrdXBLZXksXG4gICAgICAgICAgICByb290QWRkcmVzczogcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogcmVjb3ZlcnlEZXN0aW5hdGlvbiArICc/bWVtb0lkPScgKyBtZW1vLFxuICAgICAgICAgICAgdG9rZW5JZDogdG9rZW5JZCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgRXJyb3JOb0lucHV0VG9SZWNvdmVyKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGVycm9yIGZvciBpbnN1ZmZpY2llbnQgbmF0aXZlIGJhbGFuY2UgZm9yIHRva2VuIHRyYW5zZmVyJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgIGhiYXJzOiAnMC4wMScsXG4gICAgICAgICAgdG9rZW5zOiBbeyB0b2tlbklkOiB0b2tlbklkLCBiYWxhbmNlOiAnMTAnLCBkZWNpbWFsczogNiB9XSxcbiAgICAgICAgfTtcbiAgICAgICAgc2FuZEJveC5zdHViKEhiYXIucHJvdG90eXBlLCAnZ2V0QWNjb3VudEJhbGFuY2UnKS5yZXNvbHZlcyhkYXRhKTtcbiAgICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgICAgIHVzZXJLZXksXG4gICAgICAgICAgICAgIGJhY2t1cEtleSxcbiAgICAgICAgICAgICAgcm9vdEFkZHJlc3M6IHJvb3RBZGRyZXNzLFxuICAgICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgICAgIHRva2VuSWQ6IHRva2VuSWQsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHsgbWVzc2FnZTogJ0luc3VmZmljaWVudCBuYXRpdmUgYmFsYW5jZSB0byByZWNvdmVyIHRva2VucywgZ290IG5hdGl2ZSBiYWxhbmNlOiAxMDAwMDAwIGZlZTogJyArIGRlZmF1bHRGZWUgfVxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgUmVjb3ZlcnlQcm92aWRlckVycm9yIHdoZW4gdGhlIGFjY291bnQgYmFsYW5jZSBxdWVyeSBmYWlscycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc2FuZEJveFxuICAgICAgICAgIC5zdHViKEhiYXIucHJvdG90eXBlLCAnZ2V0QWNjb3VudEJhbGFuY2UnKVxuICAgICAgICAgIC5yZWplY3RzKG5ldyBSZWNvdmVyeVByb3ZpZGVyRXJyb3IoJ0ZhaWxlZCB0byBnZXQgYWNjb3VudCBiYWxhbmNlJykpO1xuICAgICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgICB1c2VyS2V5LFxuICAgICAgICAgICAgYmFja3VwS2V5LFxuICAgICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogcmVjb3ZlcnlEZXN0aW5hdGlvbiArICc/bWVtb0lkPScgKyBtZW1vLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9LCBSZWNvdmVyeVByb3ZpZGVyRXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnVW5zaWduZWQgU3dlZXAnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBzYW5kQm94ID0gU2lub24uY3JlYXRlU2FuZGJveCgpO1xuICAgICAgbGV0IGdldEJhbGFuY2VTdHViOiBTaW5vblN0dWI7XG5cbiAgICAgIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNhbmRCb3gudmVyaWZ5QW5kUmVzdG9yZSgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgYnVpbGQgdW5zaWduZWQgc3dlZXAgdHgnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGdldEJhbGFuY2VTdHViID0gc2FuZEJveFxuICAgICAgICAgIC5zdHViKEhiYXIucHJvdG90eXBlLCAnZ2V0QWNjb3VudEJhbGFuY2UnKVxuICAgICAgICAgIC5yZXNvbHZlcyh7IGhiYXJzOiBmb3JtYXRCYWxhbmNlUmVzcG9uc2UoYmFsYW5jZSksIHRva2VuczogW10gfSk7XG4gICAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IChEYXRlLm5vdygpIC8gMTAwMCArIDEwKS50b0ZpeGVkKCk7IC8vIHRpbWVzdGFtcCBpbiBzZWNvbmRzLCAxMCBzZWNvbmRzIGZyb20gbm93XG4gICAgICAgIGNvbnN0IGV4cGVjdGVkQW1vdW50ID0gbmV3IEJpZ051bWJlcihiYWxhbmNlKS5taW51cyhkZWZhdWx0RmVlKS50b1N0cmluZygpO1xuXG4gICAgICAgIGNvbnN0IHJlY292ZXJ5ID0gYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgdXNlcktleTogdXNlclB1YixcbiAgICAgICAgICBiYWNrdXBLZXk6IGJhY2t1cFB1YixcbiAgICAgICAgICByb290QWRkcmVzcyxcbiAgICAgICAgICBiaXRnb0tleSxcbiAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgc3RhcnRUaW1lLFxuICAgICAgICB9KTtcblxuICAgICAgICBnZXRCYWxhbmNlU3R1Yi5jYWxsQ291bnQuc2hvdWxkLmVxdWFsKDEpO1xuXG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5ub3QuYmUudW5kZWZpbmVkKCk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eEhleCcpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaWQnLCByb290QWRkcmVzcyArICdAJyArIHN0YXJ0VGltZSArICcuMCcpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndXNlcktleScsIHVzZXJQdWIpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnYmFja3VwS2V5JywgYmFja3VwUHViKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2JpdGdvS2V5JywgYml0Z29LZXkpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnYWRkcmVzcycsIHJvb3RBZGRyZXNzKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2NvaW4nLCAndGhiYXInKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ21heEZlZScsIGRlZmF1bHRGZWUudG9TdHJpbmcoKSk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdyZWNpcGllbnRzJywgW3sgYWRkcmVzczogcmVjb3ZlcnlEZXN0aW5hdGlvbiwgYW1vdW50OiBleHBlY3RlZEFtb3VudCB9XSk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdhbW91bnQnLCBleHBlY3RlZEFtb3VudCk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCd2YWxpZER1cmF0aW9uJywgZGVmYXVsdFZhbGlkRHVyYXRpb24pO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbm9kZUlkJywgZGVmYXVsdE5vZGVJZCk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdtZW1vJywgbWVtbyk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdzdGFydFRpbWUnLCBzdGFydFRpbWUgKyAnLjAnKTtcbiAgICAgICAgY29uc3QgdHhCdWlsZGVyID0gYmFzZWNvaW4uZ2V0QnVpbGRlckZhY3RvcnkoKS5mcm9tKHJlY292ZXJ5LnR4SGV4KTtcbiAgICAgICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG4gICAgICAgIHR4SnNvbi5pZC5zaG91bGQuZXF1YWwocm9vdEFkZHJlc3MgKyAnQCcgKyBzdGFydFRpbWUgKyAnLjAnKTtcbiAgICAgICAgdHhKc29uLmFtb3VudC5zaG91bGQuZXF1YWwoZXhwZWN0ZWRBbW91bnQpO1xuICAgICAgICB0eEpzb24udG8uc2hvdWxkLmVxdWFsKHJlY292ZXJ5RGVzdGluYXRpb24pO1xuICAgICAgICB0eEpzb24uZnJvbS5zaG91bGQuZXF1YWwocm9vdEFkZHJlc3MpO1xuICAgICAgICB0eEpzb24uZmVlLnNob3VsZC5lcXVhbChkZWZhdWx0RmVlKTtcbiAgICAgICAgdHhKc29uLm5vZGUuc2hvdWxkLmVxdWFsKGRlZmF1bHROb2RlSWQpO1xuICAgICAgICB0eEpzb24ubWVtby5zaG91bGQuZXF1YWwobWVtbyk7XG4gICAgICAgIHR4SnNvbi52YWxpZER1cmF0aW9uLnNob3VsZC5lcXVhbChkZWZhdWx0VmFsaWREdXJhdGlvbik7XG4gICAgICAgIHR4SnNvbi5zdGFydFRpbWUuc2hvdWxkLmVxdWFsKHN0YXJ0VGltZSArICcuMCcpO1xuICAgICAgICB0eEpzb24udmFsaWREdXJhdGlvbi5zaG91bGQuZXF1YWwoZGVmYXVsdFZhbGlkRHVyYXRpb24pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgYnVpbGQgdW5zaWduZWQgc3dlZXAgdHggZm9yIHRva2VucycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgYmFsYW5jZSA9ICcxMDAnO1xuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgIGhiYXJzOiAnMScsXG4gICAgICAgICAgdG9rZW5zOiBbeyB0b2tlbklkOiB0b2tlbklkLCBiYWxhbmNlOiBiYWxhbmNlLCBkZWNpbWFsczogNiB9XSxcbiAgICAgICAgfTtcbiAgICAgICAgZ2V0QmFsYW5jZVN0dWIgPSBzYW5kQm94LnN0dWIoSGJhci5wcm90b3R5cGUsICdnZXRBY2NvdW50QmFsYW5jZScpLnJlc29sdmVzKGRhdGEpO1xuICAgICAgICBjb25zdCBzdGFydFRpbWUgPSAoRGF0ZS5ub3coKSAvIDEwMDAgKyAxMCkudG9GaXhlZCgpOyAvLyB0aW1lc3RhbXAgaW4gc2Vjb25kcywgMTAgc2Vjb25kcyBmcm9tIG5vd1xuICAgICAgICBjb25zdCByZWNvdmVyeSA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgIHVzZXJLZXk6IHVzZXJQdWIsXG4gICAgICAgICAgYmFja3VwS2V5OiBiYWNrdXBQdWIsXG4gICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgYml0Z29LZXksXG4gICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogcmVjb3ZlcnlEZXN0aW5hdGlvbiArICc/bWVtb0lkPScgKyBtZW1vLFxuICAgICAgICAgIHN0YXJ0VGltZSxcbiAgICAgICAgICB0b2tlbklkOiB0b2tlbklkLFxuICAgICAgICB9KTtcblxuICAgICAgICBnZXRCYWxhbmNlU3R1Yi5jYWxsQ291bnQuc2hvdWxkLmVxdWFsKDEpO1xuXG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5ub3QuYmUudW5kZWZpbmVkKCk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eEhleCcpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaWQnLCByb290QWRkcmVzcyArICdAJyArIHN0YXJ0VGltZSArICcuMCcpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndXNlcktleScsIHVzZXJQdWIpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnYmFja3VwS2V5JywgYmFja3VwUHViKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2JpdGdvS2V5JywgYml0Z29LZXkpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnYWRkcmVzcycsIHJvb3RBZGRyZXNzKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2NvaW4nLCAndGhiYXInKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ21heEZlZScsIGRlZmF1bHRGZWUudG9TdHJpbmcoKSk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdyZWNpcGllbnRzJywgW1xuICAgICAgICAgIHsgYWRkcmVzczogcmVjb3ZlcnlEZXN0aW5hdGlvbiwgYW1vdW50OiBiYWxhbmNlLCB0b2tlbk5hbWU6ICd0aGJhcjp1c2RjJyB9LFxuICAgICAgICBdKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2Ftb3VudCcsIGJhbGFuY2UpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndmFsaWREdXJhdGlvbicsIGRlZmF1bHRWYWxpZER1cmF0aW9uKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ25vZGVJZCcsIGRlZmF1bHROb2RlSWQpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbWVtbycsIG1lbW8pO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnc3RhcnRUaW1lJywgc3RhcnRUaW1lICsgJy4wJyk7XG4gICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IGJhc2Vjb2luLmdldEJ1aWxkZXJGYWN0b3J5KCkuZnJvbShyZWNvdmVyeS50eEhleCk7XG4gICAgICAgIGNvbnN0IHR4ID0gYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgIGNvbnN0IHR4SnNvbiA9IHR4LnRvSnNvbigpO1xuICAgICAgICB0eEpzb24uaWQuc2hvdWxkLmVxdWFsKHJvb3RBZGRyZXNzICsgJ0AnICsgc3RhcnRUaW1lICsgJy4wJyk7XG4gICAgICAgIHR4SnNvbi5hbW91bnQuc2hvdWxkLmVxdWFsKGJhbGFuY2UpO1xuICAgICAgICB0eEpzb24udG8uc2hvdWxkLmVxdWFsKHJlY292ZXJ5RGVzdGluYXRpb24pO1xuICAgICAgICB0eEpzb24uZnJvbS5zaG91bGQuZXF1YWwocm9vdEFkZHJlc3MpO1xuICAgICAgICB0eEpzb24uZmVlLnNob3VsZC5lcXVhbChkZWZhdWx0RmVlKTtcbiAgICAgICAgdHhKc29uLm5vZGUuc2hvdWxkLmVxdWFsKGRlZmF1bHROb2RlSWQpO1xuICAgICAgICB0eEpzb24ubWVtby5zaG91bGQuZXF1YWwobWVtbyk7XG4gICAgICAgIHR4SnNvbi52YWxpZER1cmF0aW9uLnNob3VsZC5lcXVhbChkZWZhdWx0VmFsaWREdXJhdGlvbik7XG4gICAgICAgIHR4SnNvbi5zdGFydFRpbWUuc2hvdWxkLmVxdWFsKHN0YXJ0VGltZSArICcuMCcpO1xuICAgICAgICB0eEpzb24udmFsaWREdXJhdGlvbi5zaG91bGQuZXF1YWwoZGVmYXVsdFZhbGlkRHVyYXRpb24pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgaWYgc3RhcnRUaW1lIGlzIHVuZGVmaW5lZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gdW5kZWZpbmVkO1xuXG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgICAgICB1c2VyS2V5OiB1c2VyUHViLFxuICAgICAgICAgICAgICBiYWNrdXBLZXk6IGJhY2t1cFB1YixcbiAgICAgICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICAgIGJpdGdvS2V5LFxuICAgICAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgICAgIHN0YXJ0VGltZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBtZXNzYWdlOiAnc3RhcnQgdGltZSBpcyByZXF1aXJlZCBmb3IgdW5zaWduZWQgc3dlZXAnIH1cbiAgICAgICAgKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGZvciBpbnZhbGlkIHVzZXJLZXknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IChEYXRlLm5vdygpIC8gMTAwMCArIDEwKS50b0ZpeGVkKCk7XG4gICAgICAgIGNvbnN0IGludmFsaWRVc2VyUHViID0gJzMwMmEzMDA1MDYwMzJiNjU3MDAzMjEwMHJhbmRvbXN0cmluZyc7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgICAgICB1c2VyS2V5OiBpbnZhbGlkVXNlclB1YixcbiAgICAgICAgICAgICAgYmFja3VwS2V5OiBiYWNrdXBQdWIsXG4gICAgICAgICAgICAgIGJpdGdvS2V5LFxuICAgICAgICAgICAgICByb290QWRkcmVzcyxcbiAgICAgICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogcmVjb3ZlcnlEZXN0aW5hdGlvbiArICc/bWVtb0lkPScgKyBtZW1vLFxuICAgICAgICAgICAgICBzdGFydFRpbWUsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHsgbWVzc2FnZTogJ2ludmFsaWQgdXNlcktleSwgZ290OiAnICsgaW52YWxpZFVzZXJQdWIgfVxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgZm9yIGludmFsaWQgYmFja3VwS2V5JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBpbnZhbGlkQmFja3VwUHViID0gJzMwMmEzMDA1MDYwMzJiNjU3MDAzMjEwMHJhbmRvbXN0cmluZyc7XG4gICAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IChEYXRlLm5vdygpIC8gMTAwMCArIDEwKS50b0ZpeGVkKCk7XG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgICAgICB1c2VyS2V5OiB1c2VyUHViLFxuICAgICAgICAgICAgICBiYWNrdXBLZXk6IGludmFsaWRCYWNrdXBQdWIsXG4gICAgICAgICAgICAgIGJpdGdvS2V5LFxuICAgICAgICAgICAgICByb290QWRkcmVzcyxcbiAgICAgICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogcmVjb3ZlcnlEZXN0aW5hdGlvbiArICc/bWVtb0lkPScgKyBtZW1vLFxuICAgICAgICAgICAgICBzdGFydFRpbWUsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHsgbWVzc2FnZTogJ2ludmFsaWQgYmFja3VwS2V5LCBnb3Q6ICcgKyBpbnZhbGlkQmFja3VwUHViIH1cbiAgICAgICAgKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGlmIHN0YXJ0VGltZSBpcyBhIHZhbGlkIHRpbWVzdGFtcCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gJ2FzZCc7XG5cbiAgICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgICAgICAgIHVzZXJLZXk6IHVzZXJQdWIsXG4gICAgICAgICAgICAgIGJhY2t1cEtleTogYmFja3VwUHViLFxuICAgICAgICAgICAgICByb290QWRkcmVzcyxcbiAgICAgICAgICAgICAgYml0Z29LZXksXG4gICAgICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHJlY292ZXJ5RGVzdGluYXRpb24gKyAnP21lbW9JZD0nICsgbWVtbyxcbiAgICAgICAgICAgICAgc3RhcnRUaW1lLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICB7IG1lc3NhZ2U6ICdpbnZhbGlkIHN0YXJ0VGltZSwgZ290OiAnICsgc3RhcnRUaW1lIH1cbiAgICAgICAgKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IGlmIHN0YXJ0VGltZSBpcyBub3QgYSBmdXR1cmUgZGF0ZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gKERhdGUubm93KCkgLyAxMDAwIC0gMSkudG9TdHJpbmcoKTsgLy8gdGltZXN0YW1wIGluIHNlY29uZHMsIDEgc2Vjb25kIGFnb1xuXG4gICAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgICAgICB1c2VyS2V5OiB1c2VyUHViLFxuICAgICAgICAgICAgICBiYWNrdXBLZXk6IGJhY2t1cFB1YixcbiAgICAgICAgICAgICAgcm9vdEFkZHJlc3MsXG4gICAgICAgICAgICAgIGJpdGdvS2V5LFxuICAgICAgICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiByZWNvdmVyeURlc3RpbmF0aW9uICsgJz9tZW1vSWQ9JyArIG1lbW8sXG4gICAgICAgICAgICAgIHN0YXJ0VGltZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBtZXNzYWdlOiAnc3RhcnRUaW1lIG11c3QgYmUgYSBmdXR1cmUgdGltZXN0YW1wLCBnb3Q6ICcgKyBzdGFydFRpbWUgfVxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnUmVjb3Zlcnkgd2l0aCByb290IGtleXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBzYW5kQm94ID0gU2lub24uY3JlYXRlU2FuZGJveCgpO1xuICAgICAgbGV0IGdldEJhbGFuY2VTdHViOiBTaW5vblN0dWI7XG4gICAgICBjb25zdCB3YWxsZXRQYXNzcGhyYXNlID0gJ3Rlc3RidGNwYXNzd29yZDE5OTknO1xuICAgICAgY29uc3QgdXNlckVkZHNhUm9vdFhQcnYgPVxuICAgICAgICAne1wiaXZcIjpcImxIT1RraXV1Y1IySldGRDF4MWdxcFE9PVwiLFwidlwiOjEsXCJpdGVyXCI6MTAwMDAsXCJrc1wiOjEyOCxcInRzXCI6NjQsXCJtb2RlXCI6XCJjY21cIixcImFkYXRhXCI6XCJcIixcImNpcGhlclwiOlwiYWVzXCIsXCJzYWx0XCI6XCJIa0ZyRFZIKytkOD1cIixcImN0XCI6XCJOQnRiWWRGRUs4NG9IOXV4d2wvVXJoUnNXNW5HSlBuTVNwUkFvOEJscmM3V1RTUHhHWG1WUy9FcFVZRVYwM0hHMDYvRW55QlIwL1k2YmpMUXo0Z2tMNmNHSkQ5aGd5S3FEdmM5UnRLSGFnRWJvNzVveFByMHpQK3IxSE1VR0JXMzhUdGdvcjY3NGdCZWIxTXlldzY5eGNTOUtnZ3VOeHd6NzdYNmZkZUJocmZvZ0xZMjJ2Y3VMQT09XCJ9JztcbiAgICAgIGNvbnN0IHVzZXJFZGRzYVJvb3RQdWIgPSAnZDljYjljOWM2MTdjZmEwYjcxNTg0OTUxNmJiMDU0YTJiNWQ3OGMwZTNlZWVmMDExMTc2ZmI4YmMwMTA4YzUzMSc7XG4gICAgICBjb25zdCBiYWNrdXBFZGRzYVJvb3RYcHJ2ID1cbiAgICAgICAgJ3tcIml2XCI6XCJzQm9FRkJCTm9pMllWSUNQZjE2L0JRPT1cIixcInZcIjoxLFwiaXRlclwiOjEwMDAwLFwia3NcIjoxMjgsXCJ0c1wiOjY0LFwibW9kZVwiOlwiY2NtXCIsXCJhZGF0YVwiOlwiXCIsXCJjaXBoZXJcIjpcImFlc1wiLFwic2FsdFwiOlwiSGtGckRWSCsrZDg9XCIsXCJjdFwiOlwiR3NjT3FKQytJcStMcjM5cGxRcDVaQ2FtVmxwSkhPbHRHVFo3L1VuVXVuSWhGbVpXTUJMeGpFVm5NT3RQcmViME5aNC9TRnFPL04zbVp2cTZKYkI3dldSeEp1cWtCSWlWY0lSd2tTV2RXNTVjYm9LeDJlYzNhamc4K3VPMnBidk5EczI2USs5TnRaNGpabktOcVNVWGlDbXRKWExSSFEzMm95RCtvbEtScElSMk5RbzIrN2tJRXc9PVwifSc7XG4gICAgICBjb25zdCBiYWNrdXBFZGRzYVJvb3RQdWIgPSAnZjE2M2IxYjhlZTRjMzM0M2E5N2FjMWQyNDcwYjk2N2U5NjdhYzdiNGUzNzMxY2FjZjAyZjI4YTE0MzRhMmY5OSc7XG4gICAgICBjb25zdCByb290QWRkcmVzcyA9ICcwLjAuMzY0NDY2Nyc7XG4gICAgICBjb25zdCBtZW1vSWQgPSAnMCc7XG5cbiAgICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICBnZXRCYWxhbmNlU3R1YiA9IHNhbmRCb3hcbiAgICAgICAgICAuc3R1YihIYmFyLnByb3RvdHlwZSwgJ2dldEFjY291bnRCYWxhbmNlJylcbiAgICAgICAgICAucmVzb2x2ZXMoeyBoYmFyczogZm9ybWF0QmFsYW5jZVJlc3BvbnNlKGJhbGFuY2UpLCB0b2tlbnM6IFtdIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNhbmRCb3gudmVyaWZ5QW5kUmVzdG9yZSgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgYnVpbGQgYW5kIHNpZ24gbm9uLWJpdGdvIHJlY292ZXJ5IHR4IHdpdGggcm9vdCBrZXlzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBleHBlY3RlZEFtb3VudCA9IG5ldyBCaWdOdW1iZXIoYmFsYW5jZSkubWludXMoZGVmYXVsdEZlZSkudG9TdHJpbmcoKTtcblxuICAgICAgICBjb25zdCByZWNvdmVyeSA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXIoe1xuICAgICAgICAgIHVzZXJLZXk6IHVzZXJFZGRzYVJvb3RYUHJ2LFxuICAgICAgICAgIGJhY2t1cEtleTogYmFja3VwRWRkc2FSb290WHBydixcbiAgICAgICAgICByb290QWRkcmVzcyxcbiAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHJlY292ZXJ5RGVzdGluYXRpb24gKyAnP21lbW9JZD0nICsgbWVtb0lkLFxuICAgICAgICB9KTtcblxuICAgICAgICBnZXRCYWxhbmNlU3R1Yi5jYWxsQ291bnQuc2hvdWxkLmVxdWFsKDEpO1xuXG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5ub3QuYmUudW5kZWZpbmVkKCk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdpZCcpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndHgnKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2NvaW4nLCAndGhiYXInKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ25vZGVJZCcsIGRlZmF1bHROb2RlSWQpO1xuICAgICAgICBnZXRCYWxhbmNlU3R1Yi5jYWxsQ291bnQuc2hvdWxkLmVxdWFsKDEpO1xuICAgICAgICBjb25zdCB0eEJ1aWxkZXIgPSBiYXNlY29pbi5nZXRCdWlsZGVyRmFjdG9yeSgpLmZyb20ocmVjb3ZlcnkudHgpO1xuICAgICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgICAgICB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpLnNob3VsZC5lcXVhbChyZWNvdmVyeS50eCk7XG4gICAgICAgIGNvbnN0IHR4SnNvbiA9IHR4LnRvSnNvbigpO1xuICAgICAgICB0eEpzb24uYW1vdW50LnNob3VsZC5lcXVhbChleHBlY3RlZEFtb3VudCk7XG4gICAgICAgIHR4SnNvbi50by5zaG91bGQuZXF1YWwocmVjb3ZlcnlEZXN0aW5hdGlvbik7XG4gICAgICAgIHR4SnNvbi5mcm9tLnNob3VsZC5lcXVhbChyb290QWRkcmVzcyk7XG4gICAgICAgIHR4SnNvbi5mZWUuc2hvdWxkLmVxdWFsKGRlZmF1bHRGZWUpO1xuICAgICAgICB0eEpzb24ubm9kZS5zaG91bGQuZXF1YWwoZGVmYXVsdE5vZGVJZCk7XG4gICAgICAgIHR4SnNvbi5tZW1vLnNob3VsZC5lcXVhbChtZW1vSWQpO1xuICAgICAgICB0eEpzb24udmFsaWREdXJhdGlvbi5zaG91bGQuZXF1YWwoZGVmYXVsdFZhbGlkRHVyYXRpb24pO1xuICAgICAgICB0eEpzb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ3N0YXJ0VGltZScpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnc3RhcnRUaW1lJywgdHhKc29uLnN0YXJ0VGltZSk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdpZCcsIHJvb3RBZGRyZXNzICsgJ0AnICsgdHhKc29uLnN0YXJ0VGltZSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCBidWlsZCB1bnNpZ25lZCBzd2VlcCB0eCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gKERhdGUubm93KCkgLyAxMDAwICsgMTApLnRvRml4ZWQoKTsgLy8gdGltZXN0YW1wIGluIHNlY29uZHMsIDEwIHNlY29uZHMgZnJvbSBub3dcbiAgICAgICAgY29uc3QgZXhwZWN0ZWRBbW91bnQgPSBuZXcgQmlnTnVtYmVyKGJhbGFuY2UpLm1pbnVzKGRlZmF1bHRGZWUpLnRvU3RyaW5nKCk7XG5cbiAgICAgICAgY29uc3QgcmVjb3ZlcnkgPSBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgICB1c2VyS2V5OiB1c2VyRWRkc2FSb290UHViLFxuICAgICAgICAgIGJhY2t1cEtleTogYmFja3VwRWRkc2FSb290UHViLFxuICAgICAgICAgIHJvb3RBZGRyZXNzLFxuICAgICAgICAgIGJpdGdvS2V5LFxuICAgICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IHJlY292ZXJ5RGVzdGluYXRpb24gKyAnP21lbW9JZD0nICsgbWVtb0lkLFxuICAgICAgICAgIHN0YXJ0VGltZSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZ2V0QmFsYW5jZVN0dWIuY2FsbENvdW50LnNob3VsZC5lcXVhbCgxKTtcblxuICAgICAgICByZWNvdmVyeS5zaG91bGQubm90LmJlLnVuZGVmaW5lZCgpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndHhIZXgnKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2lkJywgcm9vdEFkZHJlc3MgKyAnQCcgKyBzdGFydFRpbWUgKyAnLjAnKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3VzZXJLZXknLCB1c2VyRWRkc2FSb290UHViKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2JhY2t1cEtleScsIGJhY2t1cEVkZHNhUm9vdFB1Yik7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdiaXRnb0tleScsIGJpdGdvS2V5KTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2FkZHJlc3MnLCByb290QWRkcmVzcyk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdjb2luJywgJ3RoYmFyJyk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdtYXhGZWUnLCBkZWZhdWx0RmVlLnRvU3RyaW5nKCkpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgncmVjaXBpZW50cycsIFt7IGFkZHJlc3M6IHJlY292ZXJ5RGVzdGluYXRpb24sIGFtb3VudDogZXhwZWN0ZWRBbW91bnQgfV0pO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnYW1vdW50JywgZXhwZWN0ZWRBbW91bnQpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndmFsaWREdXJhdGlvbicsIGRlZmF1bHRWYWxpZER1cmF0aW9uKTtcbiAgICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ25vZGVJZCcsIGRlZmF1bHROb2RlSWQpO1xuICAgICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbWVtbycsIG1lbW9JZCk7XG4gICAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCdzdGFydFRpbWUnLCBzdGFydFRpbWUgKyAnLjAnKTtcbiAgICAgICAgY29uc3QgdHhCdWlsZGVyID0gYmFzZWNvaW4uZ2V0QnVpbGRlckZhY3RvcnkoKS5mcm9tKHJlY292ZXJ5LnR4SGV4KTtcbiAgICAgICAgY29uc3QgdHggPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgICAgY29uc3QgdHhKc29uID0gdHgudG9Kc29uKCk7XG4gICAgICAgIHR4SnNvbi5pZC5zaG91bGQuZXF1YWwocm9vdEFkZHJlc3MgKyAnQCcgKyBzdGFydFRpbWUgKyAnLjAnKTtcbiAgICAgICAgdHhKc29uLmFtb3VudC5zaG91bGQuZXF1YWwoZXhwZWN0ZWRBbW91bnQpO1xuICAgICAgICB0eEpzb24udG8uc2hvdWxkLmVxdWFsKHJlY292ZXJ5RGVzdGluYXRpb24pO1xuICAgICAgICB0eEpzb24uZnJvbS5zaG91bGQuZXF1YWwocm9vdEFkZHJlc3MpO1xuICAgICAgICB0eEpzb24uZmVlLnNob3VsZC5lcXVhbChkZWZhdWx0RmVlKTtcbiAgICAgICAgdHhKc29uLm5vZGUuc2hvdWxkLmVxdWFsKGRlZmF1bHROb2RlSWQpO1xuICAgICAgICB0eEpzb24ubWVtby5zaG91bGQuZXF1YWwobWVtb0lkKTtcbiAgICAgICAgdHhKc29uLnZhbGlkRHVyYXRpb24uc2hvdWxkLmVxdWFsKGRlZmF1bHRWYWxpZER1cmF0aW9uKTtcbiAgICAgICAgdHhKc29uLnN0YXJ0VGltZS5zaG91bGQuZXF1YWwoc3RhcnRUaW1lICsgJy4wJyk7XG4gICAgICAgIHR4SnNvbi52YWxpZER1cmF0aW9uLnNob3VsZC5lcXVhbChkZWZhdWx0VmFsaWREdXJhdGlvbik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2Jyb2FkY2FzdFRyYW5zYWN0aW9uJywgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHNhbmRCb3ggPSBTaW5vbi5jcmVhdGVTYW5kYm94KCk7XG5cbiAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgc2FuZEJveC52ZXJpZnlBbmRSZXN0b3JlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN1Y2NlZWQgaWYgdGhlIHN0YXJ0VGltZSBhbmQgc2VyaWFsaXplZFNpZ25lZFRyYW5zYWN0aW9uIGFyZSB2YWxpZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IChEYXRlLm5vdygpIC8gMTAwMCAtIDMpLnRvRml4ZWQoKTsgLy8gdGltZXN0YW1wIGluIHNlY29uZHMsIC0zIHNlY29uZHMgZnJvbSBub3cgc28gaXQncyB2YWxpZCBhZnRlciAyIHNlY29uZHNcbiAgICAgIGNvbnN0IGV4cGVjdGVkUmVzcG9uc2UgPSB7IHR4SWQ6ICcwLjAuNzY2ODQ2NUAnICsgc3RhcnRUaW1lICsgJy4wJywgc3RhdHVzOiAnU1VDQ0VTUycgfTtcbiAgICAgIGNvbnN0IGJyb2FkY2FzdFN0dWIgPSBzYW5kQm94LnN0dWIoSGJhci5wcm90b3R5cGUsICdjbGllbnRCcm9hZGNhc3RUcmFuc2FjdGlvbicpLnJlc29sdmVzKGV4cGVjdGVkUmVzcG9uc2UpO1xuICAgICAgY29uc3Qgc2VyaWFsaXplZFNpZ25lZFRyYW5zYWN0aW9uID1cbiAgICAgICAgJzFhY2MwMTBhNjQwYTIwNTkyYTRmYmI3MjYzYzU5ZDQ1MGU2NTFkZjk2NjIwZGM5MjA4ZWU3YzdkOWQ2ZjJmZGNiOTFjNTNmODgzMTI2MTFhNDAxMDViN2QyNTBjODFmMzcwNWJjMGI4NTE2OGNlM2ZkMDAzMzAxMzFiYjc3MDEzNzg2ODFjOGMyZTZhMDlhOTE4Mjg3MTVlNzMzNGY0ZWYyOGQyMGZmMDk4ODdjNmU4N2MwYTVjNjkzZTIzODI0YzI2ZjNiYTE2MWZjZTA0NDgwNTBhNjQwYTIwYTY5MDUwOTU2MTZjM2NmYWExYmY2MWI1M2RlMzBlOTM4Y2U0MTEyYzNjYzRkMjUzOTNlYzZiOWJmNGRlYTA2MzFhNDBiZjk4YzViODliN2EwODU0NGVkYWExZjRjMDhhMGRmYTZlYzNmNzhiN2UyZmQyNzA0OTI4Mzk4NDA1MGYzOGNjZjAzMDNlZTU3YTM3N2NjMGE3MjVmZmQ5OWQ2OWU5ZmQ5MTQ3NzBhYjA5NDliYTU1NmQ4NGIzYjAwY2IwN2UwZDIyNTAwYTEzMGEwNjA4Y2VhOGMxYWQwNjEyMDkwODAwMTAwMDE4ZjE4NWQ0MDMxMjA2MDgwMDEwMDAxODAzMTg4MGMyZDcyZjIyMDMwOGI0MDEzMjAxMzQ3MjI0MGEyMjBhMGYwYTA5MDgwMDEwMDAxOGYxODVkNDAzMTBkM2IwNTEwYTBmMGEwOTA4MDAxMDAwMThjNDg0ZDMwMzEwZDRiMDUxJztcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLmJyb2FkY2FzdFRyYW5zYWN0aW9uKHsgc2VyaWFsaXplZFNpZ25lZFRyYW5zYWN0aW9uLCBzdGFydFRpbWUgfSk7XG4gICAgICBicm9hZGNhc3RTdHViLmNhbGxDb3VudC5zaG91bGQuZXF1YWwoMSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmRlZXBFcXVhbChleHBlY3RlZFJlc3BvbnNlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgaWYgdGhlIHN0YXJ0VGltZSBpcyBleHBpcmVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgc3RhcnRUaW1lID0gKERhdGUubm93KCkgLyAxMDAwIC0gMjAwMCkudG9GaXhlZCgpOyAvLyB0aW1lc3RhbXAgaW4gc2Vjb25kcywgMjAwMCBzZWNvbmRzIGZyb20gbm93XG4gICAgICBjb25zdCBzZXJpYWxpemVkU2lnbmVkVHJhbnNhY3Rpb24gPVxuICAgICAgICAnMWFjYzAxMGE2NDBhMjA1OTJhNGZiYjcyNjNjNTlkNDUwZTY1MWRmOTY2MjBkYzkyMDhlZTdjN2Q5ZDZmMmZkY2I5MWM1M2Y4ODMxMjYxMWE0MDEwNWI3ZDI1MGM4MWYzNzA1YmMwYjg1MTY4Y2UzZmQwMDMzMDEzMWJiNzcwMTM3ODY4MWM4YzJlNmEwOWE5MTgyODcxNWU3MzM0ZjRlZjI4ZDIwZmYwOTg4N2M2ZTg3YzBhNWM2OTNlMjM4MjRjMjZmM2JhMTYxZmNlMDQ0ODA1MGE2NDBhMjBhNjkwNTA5NTYxNmMzY2ZhYTFiZjYxYjUzZGUzMGU5MzhjZTQxMTJjM2NjNGQyNTM5M2VjNmI5YmY0ZGVhMDYzMWE0MGJmOThjNWI4OWI3YTA4NTQ0ZWRhYTFmNGMwOGEwZGZhNmVjM2Y3OGI3ZTJmZDI3MDQ5MjgzOTg0MDUwZjM4Y2NmMDMwM2VlNTdhMzc3Y2MwYTcyNWZmZDk5ZDY5ZTlmZDkxNDc3MGFiMDk0OWJhNTU2ZDg0YjNiMDBjYjA3ZTBkMjI1MDBhMTMwYTA2MDhjZWE4YzFhZDA2MTIwOTA4MDAxMDAwMThmMTg1ZDQwMzEyMDYwODAwMTAwMDE4MDMxODgwYzJkNzJmMjIwMzA4YjQwMTMyMDEzNDcyMjQwYTIyMGEwZjBhMDkwODAwMTAwMDE4ZjE4NWQ0MDMxMGQzYjA1MTBhMGYwYTA5MDgwMDEwMDAxOGM0ODRkMzAzMTBkNGIwNTEnO1xuICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBiYXNlY29pbi5icm9hZGNhc3RUcmFuc2FjdGlvbih7IHNlcmlhbGl6ZWRTaWduZWRUcmFuc2FjdGlvbiwgc3RhcnRUaW1lIH0pO1xuICAgICAgICB9LFxuICAgICAgICAoZXJyb3I6IGFueSkgPT4ge1xuICAgICAgICAgIGFzc2VydC5vayhlcnJvci5tZXNzYWdlLmluY2x1ZGVzKCdGYWlsZWQgdG8gYnJvYWRjYXN0IHRyYW5zYWN0aW9uLCBlcnJvcjogc3RhcnRUaW1lIHdpbmRvdyBleHBpcmVkJykpO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiB0aGUgc2VyaWFsaXplZFNpZ25lZFRyYW5zYWN0aW9uIGlzIGludmFsaWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBzdGFydFRpbWUgPSAoRGF0ZS5ub3coKSAvIDEwMDAgLSAxMCkudG9GaXhlZCgpOyAvLyB0aW1lc3RhbXAgaW4gc2Vjb25kcywgMTAgc2Vjb25kcyBmcm9tIG5vd1xuICAgICAgY29uc3Qgc2VyaWFsaXplZFNpZ25lZFRyYW5zYWN0aW9uID0gJ3JhbmRvbXN0cmluZyc7XG4gICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyhhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IGJhc2Vjb2luLmJyb2FkY2FzdFRyYW5zYWN0aW9uKHsgc2VyaWFsaXplZFNpZ25lZFRyYW5zYWN0aW9uLCBzdGFydFRpbWUgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgaWYgdGhlIHN0YXJ0VGltZSBpbiB0aGUgdHggaXMgaW52YWxpZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGV4cGVjdGVkUmVzcG9uc2UgPVxuICAgICAgICAndHJhbnNhY3Rpb24gMC4wLjc2Njg0NjVAMTcwNjA1NjMwMS4wMDAwMDAwMDAgZmFpbGVkIHByZWNoZWNrIHdpdGggc3RhdHVzIElOVkFMSURfVFJBTlNBQ1RJT05fU1RBUlQnO1xuICAgICAgc2FuZEJveC5zdHViKEhiYXIucHJvdG90eXBlLCAnY2xpZW50QnJvYWRjYXN0VHJhbnNhY3Rpb24nKS5yZWplY3RzKG5ldyBFcnJvcihleHBlY3RlZFJlc3BvbnNlKSk7XG4gICAgICBjb25zdCBzZXJpYWxpemVkU2lnbmVkVHJhbnNhY3Rpb24gPVxuICAgICAgICAnMWFjYzAxMGE2NDBhMjA1OTJhNGZiYjcyNjNjNTlkNDUwZTY1MWRmOTY2MjBkYzkyMDhlZTdjN2Q5ZDZmMmZkY2I5MWM1M2Y4ODMxMjYxMWE0MDEwNWI3ZDI1MGM4MWYzNzA1YmMwYjg1MTY4Y2UzZmQwMDMzMDEzMWJiNzcwMTM3ODY4MWM4YzJlNmEwOWE5MTgyODcxNWU3MzM0ZjRlZjI4ZDIwZmYwOTg4N2M2ZTg3YzBhNWM2OTNlMjM4MjRjMjZmM2JhMTYxZmNlMDQ0ODA1MGE2NDBhMjBhNjkwNTA5NTYxNmMzY2ZhYTFiZjYxYjUzZGUzMGU5MzhjZTQxMTJjM2NjNGQyNTM5M2VjNmI5YmY0ZGVhMDYzMWE0MGJmOThjNWI4OWI3YTA4NTQ0ZWRhYTFmNGMwOGEwZGZhNmVjM2Y3OGI3ZTJmZDI3MDQ5MjgzOTg0MDUwZjM4Y2NmMDMwM2VlNTdhMzc3Y2MwYTcyNWZmZDk5ZDY5ZTlmZDkxNDc3MGFiMDk0OWJhNTU2ZDg0YjNiMDBjYjA3ZTBkMjI1MDBhMTMwYTA2MDhjZWE4YzFhZDA2MTIwOTA4MDAxMDAwMThmMTg1ZDQwMzEyMDYwODAwMTAwMDE4MDMxODgwYzJkNzJmMjIwMzA4YjQwMTMyMDEzNDcyMjQwYTIyMGEwZjBhMDkwODAwMTAwMDE4ZjE4NWQ0MDMxMGQzYjA1MTBhMGYwYTA5MDgwMDEwMDAxOGM0ODRkMzAzMTBkNGIwNTEnO1xuXG4gICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyhcbiAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGF3YWl0IGJhc2Vjb2luLmJyb2FkY2FzdFRyYW5zYWN0aW9uKHsgc2VyaWFsaXplZFNpZ25lZFRyYW5zYWN0aW9uIH0pO1xuICAgICAgICB9LFxuICAgICAgICB7IG1lc3NhZ2U6IGV4cGVjdGVkUmVzcG9uc2UgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2Rlcml2ZUtleVdpdGhTZWVkJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgZGVyaXZlIGtleSB3aXRoIHNlZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAoKCkgPT4ge1xuICAgICAgICBiYXNlY29pbi5kZXJpdmVLZXlXaXRoU2VlZCgndGVzdCcpO1xuICAgICAgfSkuc2hvdWxkLnRocm93KCdtZXRob2QgZGVyaXZlS2V5V2l0aFNlZWQgbm90IHN1cHBvcnRlZCBmb3IgZWRkc2EgY3VydmUnKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0dlbmVyYXRlIHdhbGxldCBSb290IGtleSBwYWlyOiAnLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBrZXkgcGFpcicsICgpID0+IHtcbiAgICAgIGNvbnN0IGtwID0gYmFzZWNvaW4uZ2VuZXJhdGVSb290S2V5UGFpcigpO1xuICAgICAgYmFzZWNvaW4uaXNWYWxpZFB1YihrcC5wdWIpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgIGNvbnN0IGtleXBhaXIgPSBuZXcgS2V5UGFpcih7IHBydjoga3AucHJ2IH0pLmdldEtleXModHJ1ZSk7XG4gICAgICBrZXlwYWlyLnNob3VsZC5oYXZlLnByb3BlcnR5KCdwcnYnKTtcbiAgICAgIGtleXBhaXIucHJ2Py5zaG91bGQuZXF1YWwoa3AucHJ2LnNsaWNlKDAsIDY0KSk7XG4gICAgICBrZXlwYWlyLnB1Yi5zaG91bGQuZXF1YWwoa3AucHViKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUga2V5IHBhaXIgZnJvbSBzZWVkJywgKCkgPT4ge1xuICAgICAgY29uc3Qgc2VlZCA9IEJ1ZmZlci5mcm9tKCc5ZDYxYjE5ZGVmZmQ1YTYwYmE4NDRhZjQ5MmVjMmNjNDQ0NDljNTY5N2IzMjY5MTk3MDNiYWMwMzFjYWU3ZjYwJywgJ2hleCcpO1xuICAgICAgY29uc3Qga3AgPSBiYXNlY29pbi5nZW5lcmF0ZVJvb3RLZXlQYWlyKHNlZWQpO1xuICAgICAgYmFzZWNvaW4uaXNWYWxpZFB1YihrcC5wdWIpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgIGtwLnB1Yi5zaG91bGQuZXF1YWwoJ2Q3NWE5ODAxODJiMTBhYjdkNTRiZmVkM2M5NjQwNzNhMGVlMTcyZjNkYWE2MjMyNWFmMDIxYTY4ZjcwNzUxMWEnKTtcbiAgICAgIGtwLnBydi5zaG91bGQuZXF1YWwoXG4gICAgICAgICc5ZDYxYjE5ZGVmZmQ1YTYwYmE4NDRhZjQ5MmVjMmNjNDQ0NDljNTY5N2IzMjY5MTk3MDNiYWMwMzFjYWU3ZjYwZDc1YTk4MDE4MmIxMGFiN2Q1NGJmZWQzYzk2NDA3M2EwZWUxNzJmM2RhYTYyMzI1YWYwMjFhNjhmNzA3NTExYSdcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGtleXBhaXIgPSBuZXcgS2V5UGFpcih7IHBydjoga3AucHJ2IH0pLmdldEtleXModHJ1ZSk7XG4gICAgICBrZXlwYWlyLnNob3VsZC5oYXZlLnByb3BlcnR5KCdwcnYnKTtcbiAgICAgIGtleXBhaXIucHJ2Py5zaG91bGQuZXF1YWwoa3AucHJ2LnNsaWNlKDAsIDY0KSk7XG4gICAgICBrZXlwYWlyLnB1Yi5zaG91bGQuZXF1YWwoa3AucHViKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0F1ZGl0S2V5JywgKCkgPT4ge1xuICAgIGNvbnN0IHsga2V5IH0gPSBoYmFyQmFja3VwS2V5O1xuICAgIGNvbnN0IHdhbGxldFBhc3NwaHJhc2UgPSAna0FtW0VGUTZvPVN4bGNMRkR3JSwnO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gZm9yIHZhbGlkIGlucHV0cycsICgpID0+IHtcbiAgICAgIGJhc2Vjb2luLmFzc2VydElzVmFsaWRLZXkoe1xuICAgICAgICBjb2luTmFtZTogJ2hiYXInLFxuICAgICAgICBlbmNyeXB0ZWRQcnY6IGtleSxcbiAgICAgICAgd2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBlcnJvciBpZiB0aGUgd2FsbGV0UGFzc3BocmFzZSBpcyBpbmNvcnJlY3QnLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyhcbiAgICAgICAgKCkgPT5cbiAgICAgICAgICBiYXNlY29pbi5hc3NlcnRJc1ZhbGlkS2V5KHtcbiAgICAgICAgICAgIGNvaW5OYW1lOiAnaGJhcicsXG4gICAgICAgICAgICBlbmNyeXB0ZWRQcnY6IGtleSxcbiAgICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2U6ICdmb28nLFxuICAgICAgICAgIH0pLFxuICAgICAgICB7IG1lc3NhZ2U6ICdmYWlsZWQgdG8gZGVjcnlwdCBwcnY6IGluY29ycmVjdCBwYXNzd29yZCcgfVxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3IgaWYgdGhlIGtleSBpcyBhbHRlcmVkJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgYWx0ZXJlZEtleSA9IGtleS5yZXBsYWNlKC9bMC05XS9nLCAnMCcpO1xuICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgICgpID0+XG4gICAgICAgICAgYmFzZWNvaW4uYXNzZXJ0SXNWYWxpZEtleSh7XG4gICAgICAgICAgICBjb2luTmFtZTogJ2hiYXInLFxuICAgICAgICAgICAgZW5jcnlwdGVkUHJ2OiBhbHRlcmVkS2V5LFxuICAgICAgICAgICAgd2FsbGV0UGFzc3BocmFzZSxcbiAgICAgICAgICB9KSxcbiAgICAgICAge1xuICAgICAgICAgIG1lc3NhZ2U6ICdmYWlsZWQgdG8gZGVjcnlwdCBwcnY6IGRlY3J5cHQ6IGNpcGhlcnRleHQgaXMgbm90IHZhbGlkIEpTT04nLFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBlcnJvciBpZiB0aGUga2V5IGlzIG5vdCBhIHZhbGlkIGtleScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGludmFsaWRLZXkgPSAnI0ApJCMoJCpAKSMoJConO1xuICAgICAgY29uc3QgZW5jcnlwdGVkUHJ2ID0gYXdhaXQgZW5jcnlwdCh3YWxsZXRQYXNzcGhyYXNlLCBpbnZhbGlkS2V5KTtcbiAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICAoKSA9PlxuICAgICAgICAgIGJhc2Vjb2luLmFzc2VydElzVmFsaWRLZXkoe1xuICAgICAgICAgICAgY29pbk5hbWU6ICdoYmFyJyxcbiAgICAgICAgICAgIGVuY3J5cHRlZFBydixcbiAgICAgICAgICAgIHdhbGxldFBhc3NwaHJhc2UsXG4gICAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBtZXNzYWdlOiAnSW52YWxpZCBwcml2YXRlIGtleTogSW52YWxpZCBwcml2YXRlIGtleSBsZW5ndGguIE11c3QgYmUgYSBoZXggYW5kIG11bHRpcGxlIG9mIDInLFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19