aws-cdk 2.14.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +2 -1
  2. package/build-info.json +2 -2
  3. package/does-not-exist.json +1 -0
  4. package/lib/api/cloudformation-deployments.d.ts +1 -6
  5. package/lib/api/cloudformation-deployments.js +6 -72
  6. package/lib/api/evaluate-cloudformation-template.d.ts +9 -2
  7. package/lib/api/evaluate-cloudformation-template.js +14 -2
  8. package/lib/api/hotswap-deployments.js +34 -7
  9. package/lib/api/logs/find-cloudwatch-logs.js +2 -2
  10. package/lib/api/nested-stack-helpers.d.ts +28 -0
  11. package/lib/api/nested-stack-helpers.js +97 -0
  12. package/lib/cli.js +2 -2
  13. package/lib/index.js +1139 -389
  14. package/lib/notices.js +16 -7
  15. package/package.json +9 -9
  16. package/test/api/hotswap/hotswap-deployments.test.js +38 -2
  17. package/test/api/hotswap/hotswap-test-setup.d.ts +6 -4
  18. package/test/api/hotswap/hotswap-test-setup.js +46 -6
  19. package/test/api/hotswap/nested-stacks-hotswap.test.d.ts +1 -0
  20. package/test/api/hotswap/nested-stacks-hotswap.test.js +840 -0
  21. package/test/api/hotswap/state-machine-hotswap-deployments.test.js +2 -2
  22. package/test/integ/cli/cli.integtest.js +2 -2
  23. package/test/nested-stack-templates/one-lambda-one-stack-stack-with-asset-parameters.nested.template.json +52 -0
  24. package/test/nested-stack-templates/one-lambda-one-stack-stack.nested.template.json +26 -0
  25. package/test/nested-stack-templates/one-lambda-stack-with-asset-parameters.nested.template.json +29 -0
  26. package/test/nested-stack-templates/one-lambda-stack.nested.template.json +17 -0
  27. package/test/nested-stack-templates/one-lambda-version-stack.nested.template.json +20 -0
  28. package/test/{diff-nested-stacks-templates → nested-stack-templates}/one-output-one-param-stack.nested.template.json +0 -0
  29. package/test/{diff-nested-stacks-templates → nested-stack-templates}/one-resource-one-stack-stack.nested.template.json +0 -0
  30. package/test/{diff-nested-stacks-templates → nested-stack-templates}/one-resource-stack.nested.template.json +0 -0
  31. package/test/{diff-nested-stacks-templates → nested-stack-templates}/one-resource-two-stacks-stack.nested.template.json +0 -0
  32. package/test/nested-stack-templates/one-unnamed-lambda-stack.nested.template.json +16 -0
  33. package/test/nested-stack-templates/one-unnamed-lambda-two-stacks-stack.nested.template.json +34 -0
  34. package/test/notices.test.js +26 -3
  35. package/test/util.js +2 -2
@@ -0,0 +1,840 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const util_1 = require("../../util");
4
+ const setup = require("./hotswap-test-setup");
5
+ let mockUpdateLambdaCode;
6
+ let mockPublishVersion;
7
+ let hotswapMockSdkProvider;
8
+ test('can hotswap a lambda function in a 1-level nested stack', async () => {
9
+ // GIVEN
10
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('LambdaRoot');
11
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
12
+ hotswapMockSdkProvider.stubLambda({
13
+ updateFunctionCode: mockUpdateLambdaCode,
14
+ });
15
+ const rootStack = util_1.testStack({
16
+ stackName: 'LambdaRoot',
17
+ template: {
18
+ Resources: {
19
+ NestedStack: {
20
+ Type: 'AWS::CloudFormation::Stack',
21
+ Properties: {
22
+ TemplateURL: 'https://www.magic-url.com',
23
+ },
24
+ Metadata: {
25
+ 'aws:asset:path': 'one-lambda-stack.nested.template.json',
26
+ },
27
+ },
28
+ },
29
+ },
30
+ });
31
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
32
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
33
+ stackName: 'NestedStack',
34
+ template: {
35
+ Resources: {
36
+ Func: {
37
+ Type: 'AWS::Lambda::Function',
38
+ Properties: {
39
+ Code: {
40
+ S3Bucket: 'current-bucket',
41
+ S3Key: 'current-key',
42
+ },
43
+ FunctionName: 'my-function',
44
+ },
45
+ Metadata: {
46
+ 'aws:asset:path': 'old-path',
47
+ },
48
+ },
49
+ },
50
+ },
51
+ }));
52
+ setup.pushNestedStackResourceSummaries('LambdaRoot', setup.stackSummaryOf('NestedStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/NestedStack/abcd'));
53
+ const cdkStackArtifact = util_1.testStack({ stackName: 'LambdaRoot', template: rootStack.template });
54
+ // WHEN
55
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
56
+ // THEN
57
+ expect(deployStackResult).not.toBeUndefined();
58
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
59
+ FunctionName: 'my-function',
60
+ S3Bucket: 'current-bucket',
61
+ S3Key: 'new-key',
62
+ });
63
+ });
64
+ test('hotswappable changes do not override hotswappable changes in their ancestors', async () => {
65
+ // GIVEN
66
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('TwoLevelLambdaRoot');
67
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
68
+ hotswapMockSdkProvider.stubLambda({
69
+ updateFunctionCode: mockUpdateLambdaCode,
70
+ });
71
+ const rootStack = util_1.testStack({
72
+ stackName: 'TwoLevelLambdaRoot',
73
+ template: {
74
+ Resources: {
75
+ ChildStack: {
76
+ Type: 'AWS::CloudFormation::Stack',
77
+ Properties: {
78
+ TemplateURL: 'https://www.magic-url.com',
79
+ },
80
+ Metadata: {
81
+ 'aws:asset:path': 'one-lambda-one-stack-stack.nested.template.json',
82
+ },
83
+ },
84
+ },
85
+ },
86
+ });
87
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
88
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
89
+ stackName: 'ChildStack',
90
+ template: {
91
+ Resources: {
92
+ Func: {
93
+ Type: 'AWS::Lambda::Function',
94
+ Properties: {
95
+ Code: {
96
+ S3Bucket: 'current-bucket',
97
+ S3Key: 'current-key',
98
+ },
99
+ FunctionName: 'child-function',
100
+ },
101
+ Metadata: {
102
+ 'aws:asset:path': 'old-path',
103
+ },
104
+ },
105
+ GrandChildStack: {
106
+ Type: 'AWS::CloudFormation::Stack',
107
+ Properties: {
108
+ TemplateURL: 'https://www.magic-url.com',
109
+ },
110
+ Metadata: {
111
+ 'aws:asset:path': 'one-lambda-stack.nested.template.json',
112
+ },
113
+ },
114
+ },
115
+ },
116
+ }));
117
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
118
+ stackName: 'GrandChildStack',
119
+ template: {
120
+ Resources: {
121
+ Func: {
122
+ Type: 'AWS::Lambda::Function',
123
+ Properties: {
124
+ Code: {
125
+ S3Bucket: 'current-bucket',
126
+ S3Key: 'current-key',
127
+ },
128
+ FunctionName: 'my-function',
129
+ },
130
+ Metadata: {
131
+ 'aws:asset:path': 'old-path',
132
+ },
133
+ },
134
+ },
135
+ },
136
+ }));
137
+ setup.pushNestedStackResourceSummaries('TwoLevelLambdaRoot', setup.stackSummaryOf('ChildStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/ChildStack/abcd'));
138
+ setup.pushNestedStackResourceSummaries('ChildStack', setup.stackSummaryOf('GrandChildStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/GrandChildStack/abcd'));
139
+ const cdkStackArtifact = util_1.testStack({ stackName: 'TwoLevelLambdaRoot', template: rootStack.template });
140
+ // WHEN
141
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
142
+ // THEN
143
+ expect(deployStackResult).not.toBeUndefined();
144
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
145
+ FunctionName: 'child-function',
146
+ S3Bucket: 'new-bucket',
147
+ S3Key: 'current-key',
148
+ });
149
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
150
+ FunctionName: 'my-function',
151
+ S3Bucket: 'current-bucket',
152
+ S3Key: 'new-key',
153
+ });
154
+ });
155
+ test('hotswappable changes in nested stacks do not override hotswappable changes in their parent stack', async () => {
156
+ // GIVEN
157
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('SiblingLambdaRoot');
158
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
159
+ hotswapMockSdkProvider.stubLambda({
160
+ updateFunctionCode: mockUpdateLambdaCode,
161
+ });
162
+ const rootStack = util_1.testStack({
163
+ stackName: 'SiblingLambdaRoot',
164
+ template: {
165
+ Resources: {
166
+ NestedStack: {
167
+ Type: 'AWS::CloudFormation::Stack',
168
+ Properties: {
169
+ TemplateURL: 'https://www.magic-url.com',
170
+ },
171
+ Metadata: {
172
+ 'aws:asset:path': 'one-lambda-stack.nested.template.json',
173
+ },
174
+ },
175
+ Func: {
176
+ Type: 'AWS::Lambda::Function',
177
+ Properties: {
178
+ Code: {
179
+ S3Bucket: 'current-bucket',
180
+ S3Key: 'current-key',
181
+ },
182
+ FunctionName: 'root-function',
183
+ },
184
+ Metadata: {
185
+ 'aws:asset:path': 'old-path',
186
+ },
187
+ },
188
+ },
189
+ },
190
+ });
191
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
192
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
193
+ stackName: 'NestedStack',
194
+ template: {
195
+ Resources: {
196
+ Func: {
197
+ Type: 'AWS::Lambda::Function',
198
+ Properties: {
199
+ Code: {
200
+ S3Bucket: 'current-bucket',
201
+ S3Key: 'current-key',
202
+ },
203
+ FunctionName: 'my-function',
204
+ },
205
+ Metadata: {
206
+ 'aws:asset:path': 'old-path',
207
+ },
208
+ },
209
+ },
210
+ },
211
+ }));
212
+ setup.pushNestedStackResourceSummaries('SiblingLambdaRoot', setup.stackSummaryOf('NestedStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/NestedStack/abcd'));
213
+ rootStack.template.Resources.Func.Properties.Code.S3Bucket = 'new-bucket';
214
+ const cdkStackArtifact = util_1.testStack({ stackName: 'SiblingLambdaRoot', template: rootStack.template });
215
+ // WHEN
216
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
217
+ // THEN
218
+ expect(deployStackResult).not.toBeUndefined();
219
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
220
+ FunctionName: 'root-function',
221
+ S3Bucket: 'new-bucket',
222
+ S3Key: 'current-key',
223
+ });
224
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
225
+ FunctionName: 'my-function',
226
+ S3Bucket: 'current-bucket',
227
+ S3Key: 'new-key',
228
+ });
229
+ });
230
+ test('non-hotswappable changes in nested stacks result in a full deployment, even if their parent contains a hotswappable change', async () => {
231
+ // GIVEN
232
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('NonHotswappableRoot');
233
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
234
+ hotswapMockSdkProvider.stubLambda({
235
+ updateFunctionCode: mockUpdateLambdaCode,
236
+ });
237
+ const rootStack = util_1.testStack({
238
+ stackName: 'NonHotswappableRoot',
239
+ template: {
240
+ Resources: {
241
+ NestedStack: {
242
+ Type: 'AWS::CloudFormation::Stack',
243
+ Properties: {
244
+ TemplateURL: 'https://www.magic-url.com',
245
+ },
246
+ Metadata: {
247
+ 'aws:asset:path': 'one-lambda-stack.nested.template.json',
248
+ },
249
+ },
250
+ Func: {
251
+ Type: 'AWS::Lambda::Function',
252
+ Properties: {
253
+ Code: {
254
+ S3Bucket: 'current-bucket',
255
+ S3Key: 'current-key',
256
+ },
257
+ FunctionName: 'root-function',
258
+ },
259
+ Metadata: {
260
+ 'aws:asset:path': 'old-path',
261
+ },
262
+ },
263
+ },
264
+ },
265
+ });
266
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
267
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
268
+ stackName: 'NestedStack',
269
+ template: {
270
+ Resources: {
271
+ Func: {
272
+ Type: 'AWS::Lambda::Function',
273
+ Properties: {
274
+ Code: {
275
+ S3Bucket: 'current-bucket',
276
+ S3Key: 'current-key',
277
+ },
278
+ PackageType: 'Image',
279
+ FunctionName: 'my-function',
280
+ },
281
+ Metadata: {
282
+ 'aws:asset:path': 'old-path',
283
+ },
284
+ },
285
+ },
286
+ },
287
+ }));
288
+ setup.pushNestedStackResourceSummaries('NonHotswappableRoot', setup.stackSummaryOf('NestedStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/NestedStack/abcd'));
289
+ rootStack.template.Resources.Func.Properties.Code.S3Bucket = 'new-bucket';
290
+ const cdkStackArtifact = util_1.testStack({ stackName: 'NonHotswappableRoot', template: rootStack.template });
291
+ // WHEN
292
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
293
+ // THEN
294
+ expect(deployStackResult).toBeUndefined();
295
+ expect(mockUpdateLambdaCode).not.toHaveBeenCalled();
296
+ });
297
+ test('deleting a nested stack results in a full deployment, even if their parent contains a hotswappable change', async () => {
298
+ // GIVEN
299
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('NestedStackDeletionRoot');
300
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
301
+ hotswapMockSdkProvider.stubLambda({
302
+ updateFunctionCode: mockUpdateLambdaCode,
303
+ });
304
+ const rootStack = util_1.testStack({
305
+ stackName: 'NestedStackDeletionRoot',
306
+ template: {
307
+ Resources: {
308
+ NestedStack: {
309
+ Type: 'AWS::CloudFormation::Stack',
310
+ Properties: {
311
+ TemplateURL: 'https://www.magic-url.com',
312
+ },
313
+ Metadata: {
314
+ 'aws:asset:path': 'one-lambda-stack.nested.template.json',
315
+ },
316
+ },
317
+ Func: {
318
+ Type: 'AWS::Lambda::Function',
319
+ Properties: {
320
+ Code: {
321
+ S3Bucket: 'current-bucket',
322
+ S3Key: 'current-key',
323
+ },
324
+ FunctionName: 'root-function',
325
+ },
326
+ Metadata: {
327
+ 'aws:asset:path': 'old-path',
328
+ },
329
+ },
330
+ },
331
+ },
332
+ });
333
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
334
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
335
+ stackName: 'NestedStack',
336
+ template: {
337
+ Resources: {
338
+ Func: {
339
+ Type: 'AWS::Lambda::Function',
340
+ Properties: {
341
+ Code: {
342
+ S3Bucket: 'current-bucket',
343
+ S3Key: 'current-key',
344
+ },
345
+ FunctionName: 'my-function',
346
+ },
347
+ Metadata: {
348
+ 'aws:asset:path': 'old-path',
349
+ },
350
+ },
351
+ },
352
+ },
353
+ }));
354
+ setup.pushNestedStackResourceSummaries('NestedStackDeletionRoot', setup.stackSummaryOf('NestedStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/NestedStack/abcd'));
355
+ rootStack.template.Resources.Func.Properties.Code.S3Bucket = 'new-bucket';
356
+ delete rootStack.template.Resources.NestedStack;
357
+ const cdkStackArtifact = util_1.testStack({ stackName: 'NestedStackDeletionRoot', template: rootStack.template });
358
+ // WHEN
359
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
360
+ // THEN
361
+ expect(deployStackResult).toBeUndefined();
362
+ expect(mockUpdateLambdaCode).not.toHaveBeenCalled();
363
+ });
364
+ test('creating a nested stack results in a full deployment, even if their parent contains a hotswappable change', async () => {
365
+ // GIVEN
366
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('NestedStackCreationRoot');
367
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
368
+ hotswapMockSdkProvider.stubLambda({
369
+ updateFunctionCode: mockUpdateLambdaCode,
370
+ });
371
+ const rootStack = util_1.testStack({
372
+ stackName: 'NestedStackCreationRoot',
373
+ template: {
374
+ Resources: {
375
+ Func: {
376
+ Type: 'AWS::Lambda::Function',
377
+ Properties: {
378
+ Code: {
379
+ S3Bucket: 'current-bucket',
380
+ S3Key: 'current-key',
381
+ },
382
+ FunctionName: 'root-function',
383
+ },
384
+ Metadata: {
385
+ 'aws:asset:path': 'old-path',
386
+ },
387
+ },
388
+ },
389
+ },
390
+ });
391
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
392
+ rootStack.template.Resources.Func.Properties.Code.S3Bucket = 'new-bucket';
393
+ rootStack.template.Resources.NestedStack = {
394
+ Type: 'AWS::CloudFormation::Stack',
395
+ Properties: {
396
+ TemplateURL: 'https://www.magic-url.com',
397
+ },
398
+ Metadata: {
399
+ 'aws:asset:path': 'one-lambda-stack.nested.template.json',
400
+ },
401
+ };
402
+ const cdkStackArtifact = util_1.testStack({ stackName: 'NestedStackCreationRoot', template: rootStack.template });
403
+ // WHEN
404
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
405
+ // THEN
406
+ expect(deployStackResult).toBeUndefined();
407
+ expect(mockUpdateLambdaCode).not.toHaveBeenCalled();
408
+ });
409
+ test('attempting to hotswap a newly created nested stack with the same logical ID as a resource with a different type results in a full deployment', async () => {
410
+ // GIVEN
411
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('NestedStackTypeChangeRoot');
412
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
413
+ hotswapMockSdkProvider.stubLambda({
414
+ updateFunctionCode: mockUpdateLambdaCode,
415
+ });
416
+ const rootStack = util_1.testStack({
417
+ stackName: 'NestedStackTypeChangeRoot',
418
+ template: {
419
+ Resources: {
420
+ Func: {
421
+ Type: 'AWS::Lambda::Function',
422
+ Properties: {
423
+ Code: {
424
+ S3Bucket: 'current-bucket',
425
+ S3Key: 'current-key',
426
+ },
427
+ FunctionName: 'root-function',
428
+ },
429
+ Metadata: {
430
+ 'aws:asset:path': 'old-path',
431
+ },
432
+ },
433
+ FutureNestedStack: {
434
+ Type: 'AWS::Lambda::Function',
435
+ Properties: {
436
+ Code: {
437
+ S3Bucket: 'current-bucket',
438
+ S3Key: 'new-key',
439
+ },
440
+ FunctionName: 'spooky-function',
441
+ },
442
+ Metadata: {
443
+ 'aws:asset:path': 'old-path',
444
+ },
445
+ },
446
+ },
447
+ },
448
+ });
449
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
450
+ rootStack.template.Resources.Func.Properties.Code.S3Bucket = 'new-bucket';
451
+ rootStack.template.Resources.FutureNestedStack = {
452
+ Type: 'AWS::CloudFormation::Stack',
453
+ Properties: {
454
+ TemplateURL: 'https://www.magic-url.com',
455
+ },
456
+ Metadata: {
457
+ 'aws:asset:path': 'one-lambda-stack.nested.template.json',
458
+ },
459
+ };
460
+ const cdkStackArtifact = util_1.testStack({ stackName: 'NestedStackTypeChangeRoot', template: rootStack.template });
461
+ // WHEN
462
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
463
+ // THEN
464
+ expect(deployStackResult).toBeUndefined();
465
+ expect(mockUpdateLambdaCode).not.toHaveBeenCalled();
466
+ });
467
+ test('multi-sibling + 3-layer nested stack structure is hotswappable', async () => {
468
+ // GIVEN
469
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('MultiLayerRoot');
470
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
471
+ hotswapMockSdkProvider.stubLambda({
472
+ updateFunctionCode: mockUpdateLambdaCode,
473
+ });
474
+ const lambdaFunctionResource = {
475
+ Type: 'AWS::Lambda::Function',
476
+ Properties: {
477
+ Code: {
478
+ S3Bucket: 'current-bucket',
479
+ S3Key: 'current-key',
480
+ },
481
+ },
482
+ Metadata: {
483
+ 'aws:asset:path': 'old-path',
484
+ },
485
+ };
486
+ const rootStack = util_1.testStack({
487
+ stackName: 'MultiLayerRoot',
488
+ template: {
489
+ Resources: {
490
+ ChildStack: {
491
+ Type: 'AWS::CloudFormation::Stack',
492
+ Properties: {
493
+ TemplateURL: 'https://www.magic-url.com',
494
+ },
495
+ Metadata: {
496
+ 'aws:asset:path': 'one-unnamed-lambda-two-stacks-stack.nested.template.json',
497
+ },
498
+ },
499
+ Func: lambdaFunctionResource,
500
+ },
501
+ },
502
+ });
503
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
504
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
505
+ stackName: 'ChildStack',
506
+ template: {
507
+ Resources: {
508
+ GrandChildStackA: {
509
+ Type: 'AWS::CloudFormation::Stack',
510
+ Properties: {
511
+ TemplateURL: 'https://www.magic-url.com',
512
+ },
513
+ Metadata: {
514
+ 'aws:asset:path': 'one-unnamed-lambda-stack.nested.template.json',
515
+ },
516
+ },
517
+ GrandChildStackB: {
518
+ Type: 'AWS::CloudFormation::Stack',
519
+ Properties: {
520
+ TemplateURL: 'https://www.magic-url.com',
521
+ },
522
+ Metadata: {
523
+ 'aws:asset:path': 'one-unnamed-lambda-stack.nested.template.json',
524
+ },
525
+ },
526
+ Func: lambdaFunctionResource,
527
+ },
528
+ },
529
+ }));
530
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
531
+ stackName: 'GrandChildStackA',
532
+ template: {
533
+ Resources: {
534
+ Func: lambdaFunctionResource,
535
+ },
536
+ },
537
+ }));
538
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
539
+ stackName: 'GrandChildStackB',
540
+ template: {
541
+ Resources: {
542
+ Func: lambdaFunctionResource,
543
+ },
544
+ },
545
+ }));
546
+ setup.pushNestedStackResourceSummaries('MultiLayerRoot', setup.stackSummaryOf('ChildStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/ChildStack/abcd'), setup.stackSummaryOf('Func', 'AWS::Lambda::Function', 'root-function'));
547
+ setup.pushNestedStackResourceSummaries('ChildStack', setup.stackSummaryOf('GrandChildStackA', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/GrandChildStackA/abcd'), setup.stackSummaryOf('GrandChildStackB', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/GrandChildStackB/abcd'), setup.stackSummaryOf('Func', 'AWS::Lambda::Function', 'child-function'));
548
+ setup.pushNestedStackResourceSummaries('GrandChildStackA', setup.stackSummaryOf('Func', 'AWS::Lambda::Function', 'grandchild-A-function'));
549
+ setup.pushNestedStackResourceSummaries('GrandChildStackB', setup.stackSummaryOf('Func', 'AWS::Lambda::Function', 'grandchild-B-function'));
550
+ rootStack.template.Resources.Func.Properties.Code.S3Key = 'new-key';
551
+ const cdkStackArtifact = util_1.testStack({ stackName: 'MultiLayerRoot', template: rootStack.template });
552
+ // WHEN
553
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
554
+ // THEN
555
+ expect(deployStackResult).not.toBeUndefined();
556
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
557
+ FunctionName: 'root-function',
558
+ S3Bucket: 'current-bucket',
559
+ S3Key: 'new-key',
560
+ });
561
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
562
+ FunctionName: 'child-function',
563
+ S3Bucket: 'current-bucket',
564
+ S3Key: 'new-key',
565
+ });
566
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
567
+ FunctionName: 'grandchild-A-function',
568
+ S3Bucket: 'current-bucket',
569
+ S3Key: 'new-key',
570
+ });
571
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
572
+ FunctionName: 'grandchild-B-function',
573
+ S3Bucket: 'current-bucket',
574
+ S3Key: 'new-key',
575
+ });
576
+ });
577
+ test('can hotswap a lambda function in a 1-level nested stack with asset parameters', async () => {
578
+ // GIVEN
579
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('LambdaRoot');
580
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
581
+ hotswapMockSdkProvider.stubLambda({
582
+ updateFunctionCode: mockUpdateLambdaCode,
583
+ });
584
+ const rootStack = util_1.testStack({
585
+ stackName: 'LambdaRoot',
586
+ template: {
587
+ Resources: {
588
+ NestedStack: {
589
+ Type: 'AWS::CloudFormation::Stack',
590
+ Properties: {
591
+ TemplateURL: 'https://www.magic-url.com',
592
+ Parameters: {
593
+ referencetoS3BucketParam: {
594
+ Ref: 'S3BucketParam',
595
+ },
596
+ referencetoS3KeyParam: {
597
+ Ref: 'S3KeyParam',
598
+ },
599
+ },
600
+ },
601
+ Metadata: {
602
+ 'aws:asset:path': 'one-lambda-stack-with-asset-parameters.nested.template.json',
603
+ },
604
+ },
605
+ },
606
+ Parameters: {
607
+ S3BucketParam: {
608
+ Type: 'String',
609
+ Description: 'S3 bucket for asset',
610
+ },
611
+ S3KeyParam: {
612
+ Type: 'String',
613
+ Description: 'S3 bucket for asset',
614
+ },
615
+ },
616
+ },
617
+ });
618
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
619
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
620
+ stackName: 'NestedStack',
621
+ template: {
622
+ Resources: {
623
+ Func: {
624
+ Type: 'AWS::Lambda::Function',
625
+ Properties: {
626
+ Code: {
627
+ S3Bucket: 'current-bucket',
628
+ S3Key: 'current-key',
629
+ },
630
+ FunctionName: 'my-function',
631
+ },
632
+ Metadata: {
633
+ 'aws:asset:path': 'old-path',
634
+ },
635
+ },
636
+ },
637
+ },
638
+ }));
639
+ setup.pushNestedStackResourceSummaries('LambdaRoot', setup.stackSummaryOf('NestedStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/NestedStack/abcd'));
640
+ const cdkStackArtifact = util_1.testStack({ stackName: 'LambdaRoot', template: rootStack.template });
641
+ // WHEN
642
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact, {
643
+ S3BucketParam: 'bucket-param-value',
644
+ S3KeyParam: 'key-param-value',
645
+ });
646
+ // THEN
647
+ expect(deployStackResult).not.toBeUndefined();
648
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
649
+ FunctionName: 'my-function',
650
+ S3Bucket: 'bucket-param-value',
651
+ S3Key: 'key-param-value',
652
+ });
653
+ });
654
+ test('can hotswap a lambda function in a 2-level nested stack with asset parameters', async () => {
655
+ // GIVEN
656
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('LambdaRoot');
657
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
658
+ hotswapMockSdkProvider.stubLambda({
659
+ updateFunctionCode: mockUpdateLambdaCode,
660
+ });
661
+ const rootStack = util_1.testStack({
662
+ stackName: 'LambdaRoot',
663
+ template: {
664
+ Resources: {
665
+ ChildStack: {
666
+ Type: 'AWS::CloudFormation::Stack',
667
+ Properties: {
668
+ TemplateURL: 'https://www.magic-url.com',
669
+ Parameters: {
670
+ referencetoGrandChildS3BucketParam: {
671
+ Ref: 'GrandChildS3BucketParam',
672
+ },
673
+ referencetoGrandChildS3KeyParam: {
674
+ Ref: 'GrandChildS3KeyParam',
675
+ },
676
+ referencetoChildS3BucketParam: {
677
+ Ref: 'ChildS3BucketParam',
678
+ },
679
+ referencetoChildS3KeyParam: {
680
+ Ref: 'ChildS3KeyParam',
681
+ },
682
+ },
683
+ },
684
+ Metadata: {
685
+ 'aws:asset:path': 'one-lambda-one-stack-stack-with-asset-parameters.nested.template.json',
686
+ },
687
+ },
688
+ },
689
+ Parameters: {
690
+ GrandChildS3BucketParam: {
691
+ Type: 'String',
692
+ Description: 'S3 bucket for asset',
693
+ },
694
+ GrandChildS3KeyParam: {
695
+ Type: 'String',
696
+ Description: 'S3 bucket for asset',
697
+ },
698
+ ChildS3BucketParam: {
699
+ Type: 'String',
700
+ Description: 'S3 bucket for asset',
701
+ },
702
+ ChildS3KeyParam: {
703
+ Type: 'String',
704
+ Description: 'S3 bucket for asset',
705
+ },
706
+ },
707
+ },
708
+ });
709
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
710
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
711
+ stackName: 'ChildStack',
712
+ template: {
713
+ Resources: {
714
+ Func: {
715
+ Type: 'AWS::Lambda::Function',
716
+ Properties: {
717
+ Code: {
718
+ S3Bucket: 'current-bucket',
719
+ S3Key: 'current-key',
720
+ },
721
+ FunctionName: 'my-function',
722
+ },
723
+ Metadata: {
724
+ 'aws:asset:path': 'old-path',
725
+ },
726
+ },
727
+ GrandChildStack: {
728
+ Type: 'AWS::CloudFormation::Stack',
729
+ Properties: {
730
+ TemplateURL: 'https://www.magic-url.com',
731
+ },
732
+ Metadata: {
733
+ 'aws:asset:path': 'one-lambda-stack-with-asset-parameters.nested.template.json',
734
+ },
735
+ },
736
+ },
737
+ },
738
+ }));
739
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
740
+ stackName: 'GrandChildStack',
741
+ template: {
742
+ Resources: {
743
+ Func: {
744
+ Type: 'AWS::Lambda::Function',
745
+ Properties: {
746
+ Code: {
747
+ S3Bucket: 'current-bucket',
748
+ S3Key: 'current-key',
749
+ },
750
+ FunctionName: 'my-function',
751
+ },
752
+ Metadata: {
753
+ 'aws:asset:path': 'old-path',
754
+ },
755
+ },
756
+ },
757
+ },
758
+ }));
759
+ setup.pushNestedStackResourceSummaries('LambdaRoot', setup.stackSummaryOf('ChildStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/ChildStack/abcd'));
760
+ setup.pushNestedStackResourceSummaries('ChildStack', setup.stackSummaryOf('GrandChildStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/GrandChildStack/abcd'));
761
+ const cdkStackArtifact = util_1.testStack({ stackName: 'LambdaRoot', template: rootStack.template });
762
+ // WHEN
763
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact, {
764
+ GrandChildS3BucketParam: 'child-bucket-param-value',
765
+ GrandChildS3KeyParam: 'child-key-param-value',
766
+ ChildS3BucketParam: 'bucket-param-value',
767
+ ChildS3KeyParam: 'key-param-value',
768
+ });
769
+ // THEN
770
+ expect(deployStackResult).not.toBeUndefined();
771
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
772
+ FunctionName: 'my-function',
773
+ S3Bucket: 'bucket-param-value',
774
+ S3Key: 'key-param-value',
775
+ });
776
+ expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
777
+ FunctionName: 'my-function',
778
+ S3Bucket: 'child-bucket-param-value',
779
+ S3Key: 'child-key-param-value',
780
+ });
781
+ });
782
+ test('looking up objects in nested stacks works', async () => {
783
+ hotswapMockSdkProvider = setup.setupHotswapNestedStackTests('LambdaRoot');
784
+ mockUpdateLambdaCode = jest.fn().mockReturnValue({});
785
+ mockPublishVersion = jest.fn();
786
+ hotswapMockSdkProvider.stubLambda({
787
+ updateFunctionCode: mockUpdateLambdaCode,
788
+ publishVersion: mockPublishVersion,
789
+ });
790
+ const rootStack = util_1.testStack({
791
+ stackName: 'LambdaRoot',
792
+ template: {
793
+ Resources: {
794
+ NestedStack: {
795
+ Type: 'AWS::CloudFormation::Stack',
796
+ Properties: {
797
+ TemplateURL: 'https://www.magic-url.com',
798
+ },
799
+ Metadata: {
800
+ 'aws:asset:path': 'one-lambda-version-stack.nested.template.json',
801
+ },
802
+ },
803
+ },
804
+ },
805
+ });
806
+ setup.addTemplateToCloudFormationLookupMock(rootStack);
807
+ setup.addTemplateToCloudFormationLookupMock(util_1.testStack({
808
+ stackName: 'NestedStack',
809
+ template: {
810
+ Resources: {
811
+ Func: {
812
+ Type: 'AWS::Lambda::Function',
813
+ Properties: {
814
+ Code: {
815
+ S3Bucket: 'current-bucket',
816
+ S3Key: 'current-key',
817
+ },
818
+ FunctionName: 'my-function',
819
+ },
820
+ },
821
+ Version: {
822
+ Type: 'AWS::Lambda::Version',
823
+ Properties: {
824
+ FunctionName: { Ref: 'Func' },
825
+ },
826
+ },
827
+ },
828
+ },
829
+ }));
830
+ setup.pushNestedStackResourceSummaries('LambdaRoot', setup.stackSummaryOf('NestedStack', 'AWS::CloudFormation::Stack', 'arn:aws:cloudformation:bermuda-triangle-1337:123456789012:stack/NestedStack/abcd'));
831
+ const cdkStackArtifact = util_1.testStack({ stackName: 'LambdaRoot', template: rootStack.template });
832
+ // WHEN
833
+ const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
834
+ // THEN
835
+ expect(deployStackResult).not.toBeUndefined();
836
+ expect(mockPublishVersion).toHaveBeenCalledWith({
837
+ FunctionName: 'my-function',
838
+ });
839
+ });
840
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVzdGVkLXN0YWNrcy1ob3Rzd2FwLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJuZXN0ZWQtc3RhY2tzLWhvdHN3YXAudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLHFDQUF1QztBQUN2Qyw4Q0FBOEM7QUFFOUMsSUFBSSxvQkFBNEcsQ0FBQztBQUNqSCxJQUFJLGtCQUEyRixDQUFDO0FBQ2hHLElBQUksc0JBQW9ELENBQUM7QUFFekQsSUFBSSxDQUFDLHlEQUF5RCxFQUFFLEtBQUssSUFBSSxFQUFFO0lBQ3pFLFFBQVE7SUFDUixzQkFBc0IsR0FBRyxLQUFLLENBQUMsNEJBQTRCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDMUUsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyRCxzQkFBc0IsQ0FBQyxVQUFVLENBQUM7UUFDaEMsa0JBQWtCLEVBQUUsb0JBQW9CO0tBQ3pDLENBQUMsQ0FBQztJQUVILE1BQU0sU0FBUyxHQUFHLGdCQUFTLENBQUM7UUFDMUIsU0FBUyxFQUFFLFlBQVk7UUFDdkIsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULFdBQVcsRUFBRTtvQkFDWCxJQUFJLEVBQUUsNEJBQTRCO29CQUNsQyxVQUFVLEVBQUU7d0JBQ1YsV0FBVyxFQUFFLDJCQUEyQjtxQkFDekM7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLHVDQUF1QztxQkFDMUQ7aUJBQ0Y7YUFDRjtTQUNGO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3ZELEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxnQkFBUyxDQUFDO1FBQ3BELFNBQVMsRUFBRSxhQUFhO1FBQ3hCLFFBQVEsRUFBRTtZQUNSLFNBQVMsRUFBRTtnQkFDVCxJQUFJLEVBQUU7b0JBQ0osSUFBSSxFQUFFLHVCQUF1QjtvQkFDN0IsVUFBVSxFQUFFO3dCQUNWLElBQUksRUFBRTs0QkFDSixRQUFRLEVBQUUsZ0JBQWdCOzRCQUMxQixLQUFLLEVBQUUsYUFBYTt5QkFDckI7d0JBQ0QsWUFBWSxFQUFFLGFBQWE7cUJBQzVCO29CQUNELFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSxVQUFVO3FCQUM3QjtpQkFDRjthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUMsQ0FBQztJQUVKLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxZQUFZLEVBQ2pELEtBQUssQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFLDRCQUE0QixFQUM5RCxrRkFBa0YsQ0FDbkYsQ0FDRixDQUFDO0lBRUYsTUFBTSxnQkFBZ0IsR0FBRyxnQkFBUyxDQUFDLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFFOUYsT0FBTztJQUNQLE1BQU0saUJBQWlCLEdBQUcsTUFBTSxzQkFBc0IsQ0FBQyxvQkFBb0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBRTlGLE9BQU87SUFDUCxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDOUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUMsb0JBQW9CLENBQUM7UUFDaEQsWUFBWSxFQUFFLGFBQWE7UUFDM0IsUUFBUSxFQUFFLGdCQUFnQjtRQUMxQixLQUFLLEVBQUUsU0FBUztLQUNqQixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyw4RUFBOEUsRUFBRSxLQUFLLElBQUksRUFBRTtJQUM5RixRQUFRO0lBQ1Isc0JBQXNCLEdBQUcsS0FBSyxDQUFDLDRCQUE0QixDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFDbEYsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyRCxzQkFBc0IsQ0FBQyxVQUFVLENBQUM7UUFDaEMsa0JBQWtCLEVBQUUsb0JBQW9CO0tBQ3pDLENBQUMsQ0FBQztJQUVILE1BQU0sU0FBUyxHQUFHLGdCQUFTLENBQUM7UUFDMUIsU0FBUyxFQUFFLG9CQUFvQjtRQUMvQixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsVUFBVSxFQUFFO29CQUNWLElBQUksRUFBRSw0QkFBNEI7b0JBQ2xDLFVBQVUsRUFBRTt3QkFDVixXQUFXLEVBQUUsMkJBQTJCO3FCQUN6QztvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsaURBQWlEO3FCQUNwRTtpQkFDRjthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUM7SUFFSCxLQUFLLENBQUMscUNBQXFDLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkQsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLGdCQUFTLENBQUM7UUFDcEQsU0FBUyxFQUFFLFlBQVk7UUFDdkIsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsdUJBQXVCO29CQUM3QixVQUFVLEVBQUU7d0JBQ1YsSUFBSSxFQUFFOzRCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7NEJBQzFCLEtBQUssRUFBRSxhQUFhO3lCQUNyQjt3QkFDRCxZQUFZLEVBQUUsZ0JBQWdCO3FCQUMvQjtvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsVUFBVTtxQkFDN0I7aUJBQ0Y7Z0JBQ0QsZUFBZSxFQUFFO29CQUNmLElBQUksRUFBRSw0QkFBNEI7b0JBQ2xDLFVBQVUsRUFBRTt3QkFDVixXQUFXLEVBQUUsMkJBQTJCO3FCQUN6QztvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsdUNBQXVDO3FCQUMxRDtpQkFDRjthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUMsQ0FBQztJQUNKLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxnQkFBUyxDQUFDO1FBQ3BELFNBQVMsRUFBRSxpQkFBaUI7UUFDNUIsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsdUJBQXVCO29CQUM3QixVQUFVLEVBQUU7d0JBQ1YsSUFBSSxFQUFFOzRCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7NEJBQzFCLEtBQUssRUFBRSxhQUFhO3lCQUNyQjt3QkFDRCxZQUFZLEVBQUUsYUFBYTtxQkFDNUI7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQyxDQUFDO0lBRUosS0FBSyxDQUFDLGdDQUFnQyxDQUFDLG9CQUFvQixFQUN6RCxLQUFLLENBQUMsY0FBYyxDQUFDLFlBQVksRUFBRSw0QkFBNEIsRUFDN0QsaUZBQWlGLENBQ2xGLENBQ0YsQ0FBQztJQUNGLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxZQUFZLEVBQ2pELEtBQUssQ0FBQyxjQUFjLENBQUMsaUJBQWlCLEVBQUUsNEJBQTRCLEVBQ2xFLHNGQUFzRixDQUN2RixDQUNGLENBQUM7SUFFRixNQUFNLGdCQUFnQixHQUFHLGdCQUFTLENBQUMsRUFBRSxTQUFTLEVBQUUsb0JBQW9CLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRXRHLE9BQU87SUFDUCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sc0JBQXNCLENBQUMsb0JBQW9CLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUU5RixPQUFPO0lBQ1AsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQzlDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLG9CQUFvQixDQUFDO1FBQ2hELFlBQVksRUFBRSxnQkFBZ0I7UUFDOUIsUUFBUSxFQUFFLFlBQVk7UUFDdEIsS0FBSyxFQUFFLGFBQWE7S0FDckIsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUMsb0JBQW9CLENBQUM7UUFDaEQsWUFBWSxFQUFFLGFBQWE7UUFDM0IsUUFBUSxFQUFFLGdCQUFnQjtRQUMxQixLQUFLLEVBQUUsU0FBUztLQUNqQixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyxrR0FBa0csRUFBRSxLQUFLLElBQUksRUFBRTtJQUNsSCxRQUFRO0lBQ1Isc0JBQXNCLEdBQUcsS0FBSyxDQUFDLDRCQUE0QixDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDakYsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyRCxzQkFBc0IsQ0FBQyxVQUFVLENBQUM7UUFDaEMsa0JBQWtCLEVBQUUsb0JBQW9CO0tBQ3pDLENBQUMsQ0FBQztJQUVILE1BQU0sU0FBUyxHQUFHLGdCQUFTLENBQUM7UUFDMUIsU0FBUyxFQUFFLG1CQUFtQjtRQUM5QixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsV0FBVyxFQUFFO29CQUNYLElBQUksRUFBRSw0QkFBNEI7b0JBQ2xDLFVBQVUsRUFBRTt3QkFDVixXQUFXLEVBQUUsMkJBQTJCO3FCQUN6QztvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsdUNBQXVDO3FCQUMxRDtpQkFDRjtnQkFDRCxJQUFJLEVBQUU7b0JBQ0osSUFBSSxFQUFFLHVCQUF1QjtvQkFDN0IsVUFBVSxFQUFFO3dCQUNWLElBQUksRUFBRTs0QkFDSixRQUFRLEVBQUUsZ0JBQWdCOzRCQUMxQixLQUFLLEVBQUUsYUFBYTt5QkFDckI7d0JBQ0QsWUFBWSxFQUFFLGVBQWU7cUJBQzlCO29CQUNELFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSxVQUFVO3FCQUM3QjtpQkFDRjthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUM7SUFFSCxLQUFLLENBQUMscUNBQXFDLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkQsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLGdCQUFTLENBQUM7UUFDcEQsU0FBUyxFQUFFLGFBQWE7UUFDeEIsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsdUJBQXVCO29CQUM3QixVQUFVLEVBQUU7d0JBQ1YsSUFBSSxFQUFFOzRCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7NEJBQzFCLEtBQUssRUFBRSxhQUFhO3lCQUNyQjt3QkFDRCxZQUFZLEVBQUUsYUFBYTtxQkFDNUI7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQyxDQUFDO0lBRUosS0FBSyxDQUFDLGdDQUFnQyxDQUFDLG1CQUFtQixFQUN4RCxLQUFLLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSw0QkFBNEIsRUFDOUQsa0ZBQWtGLENBQ25GLENBQ0YsQ0FBQztJQUVGLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxZQUFZLENBQUM7SUFDMUUsTUFBTSxnQkFBZ0IsR0FBRyxnQkFBUyxDQUFDLEVBQUUsU0FBUyxFQUFFLG1CQUFtQixFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUVyRyxPQUFPO0lBQ1AsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLHNCQUFzQixDQUFDLG9CQUFvQixDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFFOUYsT0FBTztJQUNQLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUM5QyxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQztRQUNoRCxZQUFZLEVBQUUsZUFBZTtRQUM3QixRQUFRLEVBQUUsWUFBWTtRQUN0QixLQUFLLEVBQUUsYUFBYTtLQUNyQixDQUFDLENBQUM7SUFDSCxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQztRQUNoRCxZQUFZLEVBQUUsYUFBYTtRQUMzQixRQUFRLEVBQUUsZ0JBQWdCO1FBQzFCLEtBQUssRUFBRSxTQUFTO0tBQ2pCLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUgsSUFBSSxDQUFDLDRIQUE0SCxFQUFFLEtBQUssSUFBSSxFQUFFO0lBQzVJLFFBQVE7SUFDUixzQkFBc0IsR0FBRyxLQUFLLENBQUMsNEJBQTRCLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUNuRixvQkFBb0IsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3JELHNCQUFzQixDQUFDLFVBQVUsQ0FBQztRQUNoQyxrQkFBa0IsRUFBRSxvQkFBb0I7S0FDekMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxTQUFTLEdBQUcsZ0JBQVMsQ0FBQztRQUMxQixTQUFTLEVBQUUscUJBQXFCO1FBQ2hDLFFBQVEsRUFBRTtZQUNSLFNBQVMsRUFBRTtnQkFDVCxXQUFXLEVBQUU7b0JBQ1gsSUFBSSxFQUFFLDRCQUE0QjtvQkFDbEMsVUFBVSxFQUFFO3dCQUNWLFdBQVcsRUFBRSwyQkFBMkI7cUJBQ3pDO29CQUNELFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSx1Q0FBdUM7cUJBQzFEO2lCQUNGO2dCQUNELElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsdUJBQXVCO29CQUM3QixVQUFVLEVBQUU7d0JBQ1YsSUFBSSxFQUFFOzRCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7NEJBQzFCLEtBQUssRUFBRSxhQUFhO3lCQUNyQjt3QkFDRCxZQUFZLEVBQUUsZUFBZTtxQkFDOUI7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN2RCxLQUFLLENBQUMscUNBQXFDLENBQUMsZ0JBQVMsQ0FBQztRQUNwRCxTQUFTLEVBQUUsYUFBYTtRQUN4QixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsSUFBSSxFQUFFO29CQUNKLElBQUksRUFBRSx1QkFBdUI7b0JBQzdCLFVBQVUsRUFBRTt3QkFDVixJQUFJLEVBQUU7NEJBQ0osUUFBUSxFQUFFLGdCQUFnQjs0QkFDMUIsS0FBSyxFQUFFLGFBQWE7eUJBQ3JCO3dCQUNELFdBQVcsRUFBRSxPQUFPO3dCQUNwQixZQUFZLEVBQUUsYUFBYTtxQkFDNUI7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQyxDQUFDO0lBRUosS0FBSyxDQUFDLGdDQUFnQyxDQUFDLHFCQUFxQixFQUMxRCxLQUFLLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSw0QkFBNEIsRUFDOUQsa0ZBQWtGLENBQ25GLENBQ0YsQ0FBQztJQUVGLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxZQUFZLENBQUM7SUFDMUUsTUFBTSxnQkFBZ0IsR0FBRyxnQkFBUyxDQUFDLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUV2RyxPQUFPO0lBQ1AsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLHNCQUFzQixDQUFDLG9CQUFvQixDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFFOUYsT0FBTztJQUNQLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQzFDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0FBQ3RELENBQUMsQ0FBQyxDQUFDO0FBRUgsSUFBSSxDQUFDLDJHQUEyRyxFQUFFLEtBQUssSUFBSSxFQUFFO0lBQzNILFFBQVE7SUFDUixzQkFBc0IsR0FBRyxLQUFLLENBQUMsNEJBQTRCLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUN2RixvQkFBb0IsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3JELHNCQUFzQixDQUFDLFVBQVUsQ0FBQztRQUNoQyxrQkFBa0IsRUFBRSxvQkFBb0I7S0FDekMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxTQUFTLEdBQUcsZ0JBQVMsQ0FBQztRQUMxQixTQUFTLEVBQUUseUJBQXlCO1FBQ3BDLFFBQVEsRUFBRTtZQUNSLFNBQVMsRUFBRTtnQkFDVCxXQUFXLEVBQUU7b0JBQ1gsSUFBSSxFQUFFLDRCQUE0QjtvQkFDbEMsVUFBVSxFQUFFO3dCQUNWLFdBQVcsRUFBRSwyQkFBMkI7cUJBQ3pDO29CQUNELFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSx1Q0FBdUM7cUJBQzFEO2lCQUNGO2dCQUNELElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsdUJBQXVCO29CQUM3QixVQUFVLEVBQUU7d0JBQ1YsSUFBSSxFQUFFOzRCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7NEJBQzFCLEtBQUssRUFBRSxhQUFhO3lCQUNyQjt3QkFDRCxZQUFZLEVBQUUsZUFBZTtxQkFDOUI7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN2RCxLQUFLLENBQUMscUNBQXFDLENBQUMsZ0JBQVMsQ0FBQztRQUNwRCxTQUFTLEVBQUUsYUFBYTtRQUN4QixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsSUFBSSxFQUFFO29CQUNKLElBQUksRUFBRSx1QkFBdUI7b0JBQzdCLFVBQVUsRUFBRTt3QkFDVixJQUFJLEVBQUU7NEJBQ0osUUFBUSxFQUFFLGdCQUFnQjs0QkFDMUIsS0FBSyxFQUFFLGFBQWE7eUJBQ3JCO3dCQUNELFlBQVksRUFBRSxhQUFhO3FCQUM1QjtvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsVUFBVTtxQkFDN0I7aUJBQ0Y7YUFDRjtTQUNGO0tBQ0YsQ0FBQyxDQUFDLENBQUM7SUFFSixLQUFLLENBQUMsZ0NBQWdDLENBQUMseUJBQXlCLEVBQzlELEtBQUssQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFLDRCQUE0QixFQUM5RCxrRkFBa0YsQ0FDbkYsQ0FDRixDQUFDO0lBRUYsU0FBUyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLFlBQVksQ0FBQztJQUMxRSxPQUFPLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQztJQUNoRCxNQUFNLGdCQUFnQixHQUFHLGdCQUFTLENBQUMsRUFBRSxTQUFTLEVBQUUseUJBQXlCLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRTNHLE9BQU87SUFDUCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sc0JBQXNCLENBQUMsb0JBQW9CLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUU5RixPQUFPO0lBQ1AsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDMUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLENBQUM7QUFDdEQsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsMkdBQTJHLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDM0gsUUFBUTtJQUNSLHNCQUFzQixHQUFHLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0lBQ3ZGLG9CQUFvQixHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDckQsc0JBQXNCLENBQUMsVUFBVSxDQUFDO1FBQ2hDLGtCQUFrQixFQUFFLG9CQUFvQjtLQUN6QyxDQUFDLENBQUM7SUFFSCxNQUFNLFNBQVMsR0FBRyxnQkFBUyxDQUFDO1FBQzFCLFNBQVMsRUFBRSx5QkFBeUI7UUFDcEMsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsdUJBQXVCO29CQUM3QixVQUFVLEVBQUU7d0JBQ1YsSUFBSSxFQUFFOzRCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7NEJBQzFCLEtBQUssRUFBRSxhQUFhO3lCQUNyQjt3QkFDRCxZQUFZLEVBQUUsZUFBZTtxQkFDOUI7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUV2RCxTQUFTLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLEdBQUcsWUFBWSxDQUFDO0lBQzFFLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLFdBQVcsR0FBRztRQUN6QyxJQUFJLEVBQUUsNEJBQTRCO1FBQ2xDLFVBQVUsRUFBRTtZQUNWLFdBQVcsRUFBRSwyQkFBMkI7U0FDekM7UUFDRCxRQUFRLEVBQUU7WUFDUixnQkFBZ0IsRUFBRSx1Q0FBdUM7U0FDMUQ7S0FDRixDQUFDO0lBQ0YsTUFBTSxnQkFBZ0IsR0FBRyxnQkFBUyxDQUFDLEVBQUUsU0FBUyxFQUFFLHlCQUF5QixFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUUzRyxPQUFPO0lBQ1AsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLHNCQUFzQixDQUFDLG9CQUFvQixDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFFOUYsT0FBTztJQUNQLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQzFDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0FBQ3RELENBQUMsQ0FBQyxDQUFDO0FBRUgsSUFBSSxDQUFDLDhJQUE4SSxFQUFFLEtBQUssSUFBSSxFQUFFO0lBQzlKLFFBQVE7SUFDUixzQkFBc0IsR0FBRyxLQUFLLENBQUMsNEJBQTRCLENBQUMsMkJBQTJCLENBQUMsQ0FBQztJQUN6RixvQkFBb0IsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3JELHNCQUFzQixDQUFDLFVBQVUsQ0FBQztRQUNoQyxrQkFBa0IsRUFBRSxvQkFBb0I7S0FDekMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxTQUFTLEdBQUcsZ0JBQVMsQ0FBQztRQUMxQixTQUFTLEVBQUUsMkJBQTJCO1FBQ3RDLFFBQVEsRUFBRTtZQUNSLFNBQVMsRUFBRTtnQkFDVCxJQUFJLEVBQUU7b0JBQ0osSUFBSSxFQUFFLHVCQUF1QjtvQkFDN0IsVUFBVSxFQUFFO3dCQUNWLElBQUksRUFBRTs0QkFDSixRQUFRLEVBQUUsZ0JBQWdCOzRCQUMxQixLQUFLLEVBQUUsYUFBYTt5QkFDckI7d0JBQ0QsWUFBWSxFQUFFLGVBQWU7cUJBQzlCO29CQUNELFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSxVQUFVO3FCQUM3QjtpQkFDRjtnQkFDRCxpQkFBaUIsRUFBRTtvQkFDakIsSUFBSSxFQUFFLHVCQUF1QjtvQkFDN0IsVUFBVSxFQUFFO3dCQUNWLElBQUksRUFBRTs0QkFDSixRQUFRLEVBQUUsZ0JBQWdCOzRCQUMxQixLQUFLLEVBQUUsU0FBUzt5QkFDakI7d0JBQ0QsWUFBWSxFQUFFLGlCQUFpQjtxQkFDaEM7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUV2RCxTQUFTLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLEdBQUcsWUFBWSxDQUFDO0lBQzFFLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLGlCQUFpQixHQUFHO1FBQy9DLElBQUksRUFBRSw0QkFBNEI7UUFDbEMsVUFBVSxFQUFFO1lBQ1YsV0FBVyxFQUFFLDJCQUEyQjtTQUN6QztRQUNELFFBQVEsRUFBRTtZQUNSLGdCQUFnQixFQUFFLHVDQUF1QztTQUMxRDtLQUNGLENBQUM7SUFDRixNQUFNLGdCQUFnQixHQUFHLGdCQUFTLENBQUMsRUFBRSxTQUFTLEVBQUUsMkJBQTJCLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRTdHLE9BQU87SUFDUCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sc0JBQXNCLENBQUMsb0JBQW9CLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUU5RixPQUFPO0lBQ1AsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDMUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLENBQUM7QUFDdEQsQ0FBQyxDQUFDLENBQUM7QUFHSCxJQUFJLENBQUMsZ0VBQWdFLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDaEYsUUFBUTtJQUNSLHNCQUFzQixHQUFHLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzlFLG9CQUFvQixHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDckQsc0JBQXNCLENBQUMsVUFBVSxDQUFDO1FBQ2hDLGtCQUFrQixFQUFFLG9CQUFvQjtLQUN6QyxDQUFDLENBQUM7SUFFSCxNQUFNLHNCQUFzQixHQUFHO1FBQzdCLElBQUksRUFBRSx1QkFBdUI7UUFDN0IsVUFBVSxFQUFFO1lBQ1YsSUFBSSxFQUFFO2dCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7Z0JBQzFCLEtBQUssRUFBRSxhQUFhO2FBQ3JCO1NBQ0Y7UUFDRCxRQUFRLEVBQUU7WUFDUixnQkFBZ0IsRUFBRSxVQUFVO1NBQzdCO0tBQ0YsQ0FBQztJQUVGLE1BQU0sU0FBUyxHQUFHLGdCQUFTLENBQUM7UUFDMUIsU0FBUyxFQUFFLGdCQUFnQjtRQUMzQixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsVUFBVSxFQUFFO29CQUNWLElBQUksRUFBRSw0QkFBNEI7b0JBQ2xDLFVBQVUsRUFBRTt3QkFDVixXQUFXLEVBQUUsMkJBQTJCO3FCQUN6QztvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsMERBQTBEO3FCQUM3RTtpQkFDRjtnQkFDRCxJQUFJLEVBQUUsc0JBQXNCO2FBQzdCO1NBQ0Y7S0FDRixDQUFDLENBQUM7SUFFSCxLQUFLLENBQUMscUNBQXFDLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkQsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLGdCQUFTLENBQUM7UUFDcEQsU0FBUyxFQUFFLFlBQVk7UUFDdkIsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULGdCQUFnQixFQUFFO29CQUNoQixJQUFJLEVBQUUsNEJBQTRCO29CQUNsQyxVQUFVLEVBQUU7d0JBQ1YsV0FBVyxFQUFFLDJCQUEyQjtxQkFDekM7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLCtDQUErQztxQkFDbEU7aUJBQ0Y7Z0JBQ0QsZ0JBQWdCLEVBQUU7b0JBQ2hCLElBQUksRUFBRSw0QkFBNEI7b0JBQ2xDLFVBQVUsRUFBRTt3QkFDVixXQUFXLEVBQUUsMkJBQTJCO3FCQUN6QztvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsK0NBQStDO3FCQUNsRTtpQkFDRjtnQkFDRCxJQUFJLEVBQUUsc0JBQXNCO2FBQzdCO1NBQ0Y7S0FDRixDQUFDLENBQUMsQ0FBQztJQUNKLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxnQkFBUyxDQUFDO1FBQ3BELFNBQVMsRUFBRSxrQkFBa0I7UUFDN0IsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRSxzQkFBc0I7YUFDN0I7U0FDRjtLQUNGLENBQUMsQ0FBQyxDQUFDO0lBQ0osS0FBSyxDQUFDLHFDQUFxQyxDQUFDLGdCQUFTLENBQUM7UUFDcEQsU0FBUyxFQUFFLGtCQUFrQjtRQUM3QixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsSUFBSSxFQUFFLHNCQUFzQjthQUM3QjtTQUNGO0tBQ0YsQ0FBQyxDQUFDLENBQUM7SUFFSixLQUFLLENBQUMsZ0NBQWdDLENBQUMsZ0JBQWdCLEVBQ3JELEtBQUssQ0FBQyxjQUFjLENBQUMsWUFBWSxFQUFFLDRCQUE0QixFQUM3RCxpRkFBaUYsQ0FDbEYsRUFDRCxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSx1QkFBdUIsRUFBRSxlQUFlLENBQUMsQ0FDdkUsQ0FBQztJQUNGLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxZQUFZLEVBQ2pELEtBQUssQ0FBQyxjQUFjLENBQUMsa0JBQWtCLEVBQUUsNEJBQTRCLEVBQ25FLHVGQUF1RixDQUN4RixFQUNELEtBQUssQ0FBQyxjQUFjLENBQUMsa0JBQWtCLEVBQUUsNEJBQTRCLEVBQ25FLHVGQUF1RixDQUN4RixFQUNELEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLHVCQUF1QixFQUFFLGdCQUFnQixDQUFDLENBQ3hFLENBQUM7SUFDRixLQUFLLENBQUMsZ0NBQWdDLENBQUMsa0JBQWtCLEVBQ3ZELEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLHVCQUF1QixFQUFFLHVCQUF1QixDQUFDLENBQy9FLENBQUM7SUFDRixLQUFLLENBQUMsZ0NBQWdDLENBQUMsa0JBQWtCLEVBQ3ZELEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLHVCQUF1QixFQUFFLHVCQUF1QixDQUFDLENBQy9FLENBQUM7SUFFRixTQUFTLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUcsU0FBUyxDQUFDO0lBQ3BFLE1BQU0sZ0JBQWdCLEdBQUcsZ0JBQVMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxRQUFRLEVBQUUsU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFFbEcsT0FBTztJQUNQLE1BQU0saUJBQWlCLEdBQUcsTUFBTSxzQkFBc0IsQ0FBQyxvQkFBb0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBRTlGLE9BQU87SUFDUCxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDOUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUMsb0JBQW9CLENBQUM7UUFDaEQsWUFBWSxFQUFFLGVBQWU7UUFDN0IsUUFBUSxFQUFFLGdCQUFnQjtRQUMxQixLQUFLLEVBQUUsU0FBUztLQUNqQixDQUFDLENBQUM7SUFDSCxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQztRQUNoRCxZQUFZLEVBQUUsZ0JBQWdCO1FBQzlCLFFBQVEsRUFBRSxnQkFBZ0I7UUFDMUIsS0FBSyxFQUFFLFNBQVM7S0FDakIsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUMsb0JBQW9CLENBQUM7UUFDaEQsWUFBWSxFQUFFLHVCQUF1QjtRQUNyQyxRQUFRLEVBQUUsZ0JBQWdCO1FBQzFCLEtBQUssRUFBRSxTQUFTO0tBQ2pCLENBQUMsQ0FBQztJQUNILE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLG9CQUFvQixDQUFDO1FBQ2hELFlBQVksRUFBRSx1QkFBdUI7UUFDckMsUUFBUSxFQUFFLGdCQUFnQjtRQUMxQixLQUFLLEVBQUUsU0FBUztLQUNqQixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQywrRUFBK0UsRUFBRSxLQUFLLElBQUksRUFBRTtJQUMvRixRQUFRO0lBQ1Isc0JBQXNCLEdBQUcsS0FBSyxDQUFDLDRCQUE0QixDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzFFLG9CQUFvQixHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDckQsc0JBQXNCLENBQUMsVUFBVSxDQUFDO1FBQ2hDLGtCQUFrQixFQUFFLG9CQUFvQjtLQUN6QyxDQUFDLENBQUM7SUFFSCxNQUFNLFNBQVMsR0FBRyxnQkFBUyxDQUFDO1FBQzFCLFNBQVMsRUFBRSxZQUFZO1FBQ3ZCLFFBQVEsRUFBRTtZQUNSLFNBQVMsRUFBRTtnQkFDVCxXQUFXLEVBQUU7b0JBQ1gsSUFBSSxFQUFFLDRCQUE0QjtvQkFDbEMsVUFBVSxFQUFFO3dCQUNWLFdBQVcsRUFBRSwyQkFBMkI7d0JBQ3hDLFVBQVUsRUFBRTs0QkFDVix3QkFBd0IsRUFBRTtnQ0FDeEIsR0FBRyxFQUFFLGVBQWU7NkJBQ3JCOzRCQUNELHFCQUFxQixFQUFFO2dDQUNyQixHQUFHLEVBQUUsWUFBWTs2QkFDbEI7eUJBQ0Y7cUJBQ0Y7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLDZEQUE2RDtxQkFDaEY7aUJBQ0Y7YUFDRjtZQUNELFVBQVUsRUFBRTtnQkFDVixhQUFhLEVBQUU7b0JBQ2IsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsV0FBVyxFQUFFLHFCQUFxQjtpQkFDbkM7Z0JBQ0QsVUFBVSxFQUFFO29CQUNWLElBQUksRUFBRSxRQUFRO29CQUNkLFdBQVcsRUFBRSxxQkFBcUI7aUJBQ25DO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN2RCxLQUFLLENBQUMscUNBQXFDLENBQUMsZ0JBQVMsQ0FBQztRQUNwRCxTQUFTLEVBQUUsYUFBYTtRQUN4QixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsSUFBSSxFQUFFO29CQUNKLElBQUksRUFBRSx1QkFBdUI7b0JBQzdCLFVBQVUsRUFBRTt3QkFDVixJQUFJLEVBQUU7NEJBQ0osUUFBUSxFQUFFLGdCQUFnQjs0QkFDMUIsS0FBSyxFQUFFLGFBQWE7eUJBQ3JCO3dCQUNELFlBQVksRUFBRSxhQUFhO3FCQUM1QjtvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsVUFBVTtxQkFDN0I7aUJBQ0Y7YUFDRjtTQUNGO0tBQ0YsQ0FBQyxDQUFDLENBQUM7SUFFSixLQUFLLENBQUMsZ0NBQWdDLENBQUMsWUFBWSxFQUNqRCxLQUFLLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSw0QkFBNEIsRUFDOUQsa0ZBQWtGLENBQ25GLENBQ0YsQ0FBQztJQUVGLE1BQU0sZ0JBQWdCLEdBQUcsZ0JBQVMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRTlGLE9BQU87SUFDUCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sc0JBQXNCLENBQUMsb0JBQW9CLENBQUMsZ0JBQWdCLEVBQUU7UUFDNUYsYUFBYSxFQUFFLG9CQUFvQjtRQUNuQyxVQUFVLEVBQUUsaUJBQWlCO0tBQzlCLENBQUMsQ0FBQztJQUVILE9BQU87SUFDUCxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDOUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUMsb0JBQW9CLENBQUM7UUFDaEQsWUFBWSxFQUFFLGFBQWE7UUFDM0IsUUFBUSxFQUFFLG9CQUFvQjtRQUM5QixLQUFLLEVBQUUsaUJBQWlCO0tBQ3pCLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUgsSUFBSSxDQUFDLCtFQUErRSxFQUFFLEtBQUssSUFBSSxFQUFFO0lBQy9GLFFBQVE7SUFDUixzQkFBc0IsR0FBRyxLQUFLLENBQUMsNEJBQTRCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDMUUsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyRCxzQkFBc0IsQ0FBQyxVQUFVLENBQUM7UUFDaEMsa0JBQWtCLEVBQUUsb0JBQW9CO0tBQ3pDLENBQUMsQ0FBQztJQUVILE1BQU0sU0FBUyxHQUFHLGdCQUFTLENBQUM7UUFDMUIsU0FBUyxFQUFFLFlBQVk7UUFDdkIsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULFVBQVUsRUFBRTtvQkFDVixJQUFJLEVBQUUsNEJBQTRCO29CQUNsQyxVQUFVLEVBQUU7d0JBQ1YsV0FBVyxFQUFFLDJCQUEyQjt3QkFDeEMsVUFBVSxFQUFFOzRCQUNWLGtDQUFrQyxFQUFFO2dDQUNsQyxHQUFHLEVBQUUseUJBQXlCOzZCQUMvQjs0QkFDRCwrQkFBK0IsRUFBRTtnQ0FDL0IsR0FBRyxFQUFFLHNCQUFzQjs2QkFDNUI7NEJBQ0QsNkJBQTZCLEVBQUU7Z0NBQzdCLEdBQUcsRUFBRSxvQkFBb0I7NkJBQzFCOzRCQUNELDBCQUEwQixFQUFFO2dDQUMxQixHQUFHLEVBQUUsaUJBQWlCOzZCQUN2Qjt5QkFDRjtxQkFDRjtvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsZ0JBQWdCLEVBQUUsdUVBQXVFO3FCQUMxRjtpQkFDRjthQUNGO1lBQ0QsVUFBVSxFQUFFO2dCQUNWLHVCQUF1QixFQUFFO29CQUN2QixJQUFJLEVBQUUsUUFBUTtvQkFDZCxXQUFXLEVBQUUscUJBQXFCO2lCQUNuQztnQkFDRCxvQkFBb0IsRUFBRTtvQkFDcEIsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsV0FBVyxFQUFFLHFCQUFxQjtpQkFDbkM7Z0JBQ0Qsa0JBQWtCLEVBQUU7b0JBQ2xCLElBQUksRUFBRSxRQUFRO29CQUNkLFdBQVcsRUFBRSxxQkFBcUI7aUJBQ25DO2dCQUNELGVBQWUsRUFBRTtvQkFDZixJQUFJLEVBQUUsUUFBUTtvQkFDZCxXQUFXLEVBQUUscUJBQXFCO2lCQUNuQzthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUM7SUFFSCxLQUFLLENBQUMscUNBQXFDLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkQsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLGdCQUFTLENBQUM7UUFDcEQsU0FBUyxFQUFFLFlBQVk7UUFDdkIsUUFBUSxFQUFFO1lBQ1IsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsdUJBQXVCO29CQUM3QixVQUFVLEVBQUU7d0JBQ1YsSUFBSSxFQUFFOzRCQUNKLFFBQVEsRUFBRSxnQkFBZ0I7NEJBQzFCLEtBQUssRUFBRSxhQUFhO3lCQUNyQjt3QkFDRCxZQUFZLEVBQUUsYUFBYTtxQkFDNUI7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLFVBQVU7cUJBQzdCO2lCQUNGO2dCQUNELGVBQWUsRUFBRTtvQkFDZixJQUFJLEVBQUUsNEJBQTRCO29CQUNsQyxVQUFVLEVBQUU7d0JBQ1YsV0FBVyxFQUFFLDJCQUEyQjtxQkFDekM7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLGdCQUFnQixFQUFFLDZEQUE2RDtxQkFDaEY7aUJBQ0Y7YUFDRjtTQUNGO0tBQ0YsQ0FBQyxDQUFDLENBQUM7SUFDSixLQUFLLENBQUMscUNBQXFDLENBQUMsZ0JBQVMsQ0FBQztRQUNwRCxTQUFTLEVBQUUsaUJBQWlCO1FBQzVCLFFBQVEsRUFBRTtZQUNSLFNBQVMsRUFBRTtnQkFDVCxJQUFJLEVBQUU7b0JBQ0osSUFBSSxFQUFFLHVCQUF1QjtvQkFDN0IsVUFBVSxFQUFFO3dCQUNWLElBQUksRUFBRTs0QkFDSixRQUFRLEVBQUUsZ0JBQWdCOzRCQUMxQixLQUFLLEVBQUUsYUFBYTt5QkFDckI7d0JBQ0QsWUFBWSxFQUFFLGFBQWE7cUJBQzVCO29CQUNELFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSxVQUFVO3FCQUM3QjtpQkFDRjthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUMsQ0FBQztJQUdKLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxZQUFZLEVBQ2pELEtBQUssQ0FBQyxjQUFjLENBQUMsWUFBWSxFQUFFLDRCQUE0QixFQUM3RCxpRkFBaUYsQ0FDbEYsQ0FDRixDQUFDO0lBRUYsS0FBSyxDQUFDLGdDQUFnQyxDQUFDLFlBQVksRUFDakQsS0FBSyxDQUFDLGNBQWMsQ0FBQyxpQkFBaUIsRUFBRSw0QkFBNEIsRUFDbEUsc0ZBQXNGLENBQ3ZGLENBQ0YsQ0FBQztJQUNGLE1BQU0sZ0JBQWdCLEdBQUcsZ0JBQVMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRTlGLE9BQU87SUFDUCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sc0JBQXNCLENBQUMsb0JBQW9CLENBQUMsZ0JBQWdCLEVBQUU7UUFDNUYsdUJBQXVCLEVBQUUsMEJBQTBCO1FBQ25ELG9CQUFvQixFQUFFLHVCQUF1QjtRQUM3QyxrQkFBa0IsRUFBRSxvQkFBb0I7UUFDeEMsZUFBZSxFQUFFLGlCQUFpQjtLQUNuQyxDQUFDLENBQUM7SUFFSCxPQUFPO0lBQ1AsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQzlDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLG9CQUFvQixDQUFDO1FBQ2hELFlBQVksRUFBRSxhQUFhO1FBQzNCLFFBQVEsRUFBRSxvQkFBb0I7UUFDOUIsS0FBSyxFQUFFLGlCQUFpQjtLQUN6QixDQUFDLENBQUM7SUFDSCxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQztRQUNoRCxZQUFZLEVBQUUsYUFBYTtRQUMzQixRQUFRLEVBQUUsMEJBQTBCO1FBQ3BDLEtBQUssRUFBRSx1QkFBdUI7S0FDL0IsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsMkNBQTJDLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDM0Qsc0JBQXNCLEdBQUcsS0FBSyxDQUFDLDRCQUE0QixDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzFFLG9CQUFvQixHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDckQsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQy9CLHNCQUFzQixDQUFDLFVBQVUsQ0FBQztRQUNoQyxrQkFBa0IsRUFBRSxvQkFBb0I7UUFDeEMsY0FBYyxFQUFFLGtCQUFrQjtLQUNuQyxDQUFDLENBQUM7SUFFSCxNQUFNLFNBQVMsR0FBRyxnQkFBUyxDQUFDO1FBQzFCLFNBQVMsRUFBRSxZQUFZO1FBQ3ZCLFFBQVEsRUFBRTtZQUNSLFNBQVMsRUFBRTtnQkFDVCxXQUFXLEVBQUU7b0JBQ1gsSUFBSSxFQUFFLDRCQUE0QjtvQkFDbEMsVUFBVSxFQUFFO3dCQUNWLFdBQVcsRUFBRSwyQkFBMkI7cUJBQ3pDO29CQUNELFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSwrQ0FBK0M7cUJBQ2xFO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN2RCxLQUFLLENBQUMscUNBQXFDLENBQUMsZ0JBQVMsQ0FBQztRQUNwRCxTQUFTLEVBQUUsYUFBYTtRQUN4QixRQUFRLEVBQUU7WUFDUixTQUFTLEVBQUU7Z0JBQ1QsSUFBSSxFQUFFO29CQUNKLElBQUksRUFBRSx1QkFBdUI7b0JBQzdCLFVBQVUsRUFBRTt3QkFDVixJQUFJLEVBQUU7NEJBQ0osUUFBUSxFQUFFLGdCQUFnQjs0QkFDMUIsS0FBSyxFQUFFLGFBQWE7eUJBQ3JCO3dCQUNELFlBQVksRUFBRSxhQUFhO3FCQUM1QjtpQkFDRjtnQkFDRCxPQUFPLEVBQUU7b0JBQ1AsSUFBSSxFQUFFLHNCQUFzQjtvQkFDNUIsVUFBVSxFQUFFO3dCQUNWLFlBQVksRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUU7cUJBQzlCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQyxDQUFDO0lBRUosS0FBSyxDQUFDLGdDQUFnQyxDQUFDLFlBQVksRUFDakQsS0FBSyxDQUFDLGNBQWMsQ0FBQyxhQUFhLEVBQUUsNEJBQTRCLEVBQzlELGtGQUFrRixDQUNuRixDQUNGLENBQUM7SUFFRixNQUFNLGdCQUFnQixHQUFHLGdCQUFTLENBQUMsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUU5RixPQUFPO0lBQ1AsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLHNCQUFzQixDQUFDLG9CQUFvQixDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFFOUYsT0FBTztJQUNQLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUM5QyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQztRQUM5QyxZQUFZLEVBQUUsYUFBYTtLQUM1QixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IExhbWJkYSB9IGZyb20gJ2F3cy1zZGsnO1xuaW1wb3J0IHsgdGVzdFN0YWNrIH0gZnJvbSAnLi4vLi4vdXRpbCc7XG5pbXBvcnQgKiBhcyBzZXR1cCBmcm9tICcuL2hvdHN3YXAtdGVzdC1zZXR1cCc7XG5cbmxldCBtb2NrVXBkYXRlTGFtYmRhQ29kZTogKHBhcmFtczogTGFtYmRhLlR5cGVzLlVwZGF0ZUZ1bmN0aW9uQ29kZVJlcXVlc3QpID0+IExhbWJkYS5UeXBlcy5GdW5jdGlvbkNvbmZpZ3VyYXRpb247XG5sZXQgbW9ja1B1Ymxpc2hWZXJzaW9uOiBqZXN0Lk1vY2s8TGFtYmRhLkZ1bmN0aW9uQ29uZmlndXJhdGlvbiwgTGFtYmRhLlB1Ymxpc2hWZXJzaW9uUmVxdWVzdFtdPjtcbmxldCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyOiBzZXR1cC5Ib3Rzd2FwTW9ja1Nka1Byb3ZpZGVyO1xuXG50ZXN0KCdjYW4gaG90c3dhcCBhIGxhbWJkYSBmdW5jdGlvbiBpbiBhIDEtbGV2ZWwgbmVzdGVkIHN0YWNrJywgYXN5bmMgKCkgPT4ge1xuICAvLyBHSVZFTlxuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyID0gc2V0dXAuc2V0dXBIb3Rzd2FwTmVzdGVkU3RhY2tUZXN0cygnTGFtYmRhUm9vdCcpO1xuICBtb2NrVXBkYXRlTGFtYmRhQ29kZSA9IGplc3QuZm4oKS5tb2NrUmV0dXJuVmFsdWUoe30pO1xuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnN0dWJMYW1iZGEoe1xuICAgIHVwZGF0ZUZ1bmN0aW9uQ29kZTogbW9ja1VwZGF0ZUxhbWJkYUNvZGUsXG4gIH0pO1xuXG4gIGNvbnN0IHJvb3RTdGFjayA9IHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnTGFtYmRhUm9vdCcsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBOZXN0ZWRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb25lLWxhbWJkYS1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayhyb290U3RhY2spO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnTmVzdGVkU3RhY2snLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgRnVuYzoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pKTtcblxuICBzZXR1cC5wdXNoTmVzdGVkU3RhY2tSZXNvdXJjZVN1bW1hcmllcygnTGFtYmRhUm9vdCcsXG4gICAgc2V0dXAuc3RhY2tTdW1tYXJ5T2YoJ05lc3RlZFN0YWNrJywgJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICdhcm46YXdzOmNsb3VkZm9ybWF0aW9uOmJlcm11ZGEtdHJpYW5nbGUtMTMzNzoxMjM0NTY3ODkwMTI6c3RhY2svTmVzdGVkU3RhY2svYWJjZCcsXG4gICAgKSxcbiAgKTtcblxuICBjb25zdCBjZGtTdGFja0FydGlmYWN0ID0gdGVzdFN0YWNrKHsgc3RhY2tOYW1lOiAnTGFtYmRhUm9vdCcsIHRlbXBsYXRlOiByb290U3RhY2sudGVtcGxhdGUgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLm5vdC50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChtb2NrVXBkYXRlTGFtYmRhQ29kZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoe1xuICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICBTM0J1Y2tldDogJ2N1cnJlbnQtYnVja2V0JyxcbiAgICBTM0tleTogJ25ldy1rZXknLFxuICB9KTtcbn0pO1xuXG50ZXN0KCdob3Rzd2FwcGFibGUgY2hhbmdlcyBkbyBub3Qgb3ZlcnJpZGUgaG90c3dhcHBhYmxlIGNoYW5nZXMgaW4gdGhlaXIgYW5jZXN0b3JzJywgYXN5bmMgKCkgPT4ge1xuICAvLyBHSVZFTlxuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyID0gc2V0dXAuc2V0dXBIb3Rzd2FwTmVzdGVkU3RhY2tUZXN0cygnVHdvTGV2ZWxMYW1iZGFSb290Jyk7XG4gIG1vY2tVcGRhdGVMYW1iZGFDb2RlID0gamVzdC5mbigpLm1vY2tSZXR1cm5WYWx1ZSh7fSk7XG4gIGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIuc3R1YkxhbWJkYSh7XG4gICAgdXBkYXRlRnVuY3Rpb25Db2RlOiBtb2NrVXBkYXRlTGFtYmRhQ29kZSxcbiAgfSk7XG5cbiAgY29uc3Qgcm9vdFN0YWNrID0gdGVzdFN0YWNrKHtcbiAgICBzdGFja05hbWU6ICdUd29MZXZlbExhbWJkYVJvb3QnLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgQ2hpbGRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb25lLWxhbWJkYS1vbmUtc3RhY2stc3RhY2submVzdGVkLnRlbXBsYXRlLmpzb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pO1xuXG4gIHNldHVwLmFkZFRlbXBsYXRlVG9DbG91ZEZvcm1hdGlvbkxvb2t1cE1vY2socm9vdFN0YWNrKTtcbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayh0ZXN0U3RhY2soe1xuICAgIHN0YWNrTmFtZTogJ0NoaWxkU3RhY2snLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgRnVuYzoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ2NoaWxkLWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIEdyYW5kQ2hpbGRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb25lLWxhbWJkYS1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSkpO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnR3JhbmRDaGlsZFN0YWNrJyxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgIEZ1bmM6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBDb2RlOiB7XG4gICAgICAgICAgICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgICAgICAgICAgICBTM0tleTogJ2N1cnJlbnQta2V5JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBGdW5jdGlvbk5hbWU6ICdteS1mdW5jdGlvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29sZC1wYXRoJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICB9KSk7XG5cbiAgc2V0dXAucHVzaE5lc3RlZFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoJ1R3b0xldmVsTGFtYmRhUm9vdCcsXG4gICAgc2V0dXAuc3RhY2tTdW1tYXJ5T2YoJ0NoaWxkU3RhY2snLCAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgICAgJ2Fybjphd3M6Y2xvdWRmb3JtYXRpb246YmVybXVkYS10cmlhbmdsZS0xMzM3OjEyMzQ1Njc4OTAxMjpzdGFjay9DaGlsZFN0YWNrL2FiY2QnLFxuICAgICksXG4gICk7XG4gIHNldHVwLnB1c2hOZXN0ZWRTdGFja1Jlc291cmNlU3VtbWFyaWVzKCdDaGlsZFN0YWNrJyxcbiAgICBzZXR1cC5zdGFja1N1bW1hcnlPZignR3JhbmRDaGlsZFN0YWNrJywgJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICdhcm46YXdzOmNsb3VkZm9ybWF0aW9uOmJlcm11ZGEtdHJpYW5nbGUtMTMzNzoxMjM0NTY3ODkwMTI6c3RhY2svR3JhbmRDaGlsZFN0YWNrL2FiY2QnLFxuICAgICksXG4gICk7XG5cbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHRlc3RTdGFjayh7IHN0YWNrTmFtZTogJ1R3b0xldmVsTGFtYmRhUm9vdCcsIHRlbXBsYXRlOiByb290U3RhY2sudGVtcGxhdGUgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLm5vdC50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChtb2NrVXBkYXRlTGFtYmRhQ29kZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoe1xuICAgIEZ1bmN0aW9uTmFtZTogJ2NoaWxkLWZ1bmN0aW9uJyxcbiAgICBTM0J1Y2tldDogJ25ldy1idWNrZXQnLFxuICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICB9KTtcbiAgZXhwZWN0KG1vY2tVcGRhdGVMYW1iZGFDb2RlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgRnVuY3Rpb25OYW1lOiAnbXktZnVuY3Rpb24nLFxuICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgIFMzS2V5OiAnbmV3LWtleScsXG4gIH0pO1xufSk7XG5cbnRlc3QoJ2hvdHN3YXBwYWJsZSBjaGFuZ2VzIGluIG5lc3RlZCBzdGFja3MgZG8gbm90IG92ZXJyaWRlIGhvdHN3YXBwYWJsZSBjaGFuZ2VzIGluIHRoZWlyIHBhcmVudCBzdGFjaycsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlciA9IHNldHVwLnNldHVwSG90c3dhcE5lc3RlZFN0YWNrVGVzdHMoJ1NpYmxpbmdMYW1iZGFSb290Jyk7XG4gIG1vY2tVcGRhdGVMYW1iZGFDb2RlID0gamVzdC5mbigpLm1vY2tSZXR1cm5WYWx1ZSh7fSk7XG4gIGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIuc3R1YkxhbWJkYSh7XG4gICAgdXBkYXRlRnVuY3Rpb25Db2RlOiBtb2NrVXBkYXRlTGFtYmRhQ29kZSxcbiAgfSk7XG5cbiAgY29uc3Qgcm9vdFN0YWNrID0gdGVzdFN0YWNrKHtcbiAgICBzdGFja05hbWU6ICdTaWJsaW5nTGFtYmRhUm9vdCcsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBOZXN0ZWRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb25lLWxhbWJkYS1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgRnVuYzoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ3Jvb3QtZnVuY3Rpb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICdhd3M6YXNzZXQ6cGF0aCc6ICdvbGQtcGF0aCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayhyb290U3RhY2spO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnTmVzdGVkU3RhY2snLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgRnVuYzoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pKTtcblxuICBzZXR1cC5wdXNoTmVzdGVkU3RhY2tSZXNvdXJjZVN1bW1hcmllcygnU2libGluZ0xhbWJkYVJvb3QnLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdOZXN0ZWRTdGFjaycsICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAnYXJuOmF3czpjbG91ZGZvcm1hdGlvbjpiZXJtdWRhLXRyaWFuZ2xlLTEzMzc6MTIzNDU2Nzg5MDEyOnN0YWNrL05lc3RlZFN0YWNrL2FiY2QnLFxuICAgICksXG4gICk7XG5cbiAgcm9vdFN0YWNrLnRlbXBsYXRlLlJlc291cmNlcy5GdW5jLlByb3BlcnRpZXMuQ29kZS5TM0J1Y2tldCA9ICduZXctYnVja2V0JztcbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHRlc3RTdGFjayh7IHN0YWNrTmFtZTogJ1NpYmxpbmdMYW1iZGFSb290JywgdGVtcGxhdGU6IHJvb3RTdGFjay50ZW1wbGF0ZSB9KTtcblxuICAvLyBXSEVOXG4gIGNvbnN0IGRlcGxveVN0YWNrUmVzdWx0ID0gYXdhaXQgaG90c3dhcE1vY2tTZGtQcm92aWRlci50cnlIb3Rzd2FwRGVwbG95bWVudChjZGtTdGFja0FydGlmYWN0KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChkZXBsb3lTdGFja1Jlc3VsdCkubm90LnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KG1vY2tVcGRhdGVMYW1iZGFDb2RlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgRnVuY3Rpb25OYW1lOiAncm9vdC1mdW5jdGlvbicsXG4gICAgUzNCdWNrZXQ6ICduZXctYnVja2V0JyxcbiAgICBTM0tleTogJ2N1cnJlbnQta2V5JyxcbiAgfSk7XG4gIGV4cGVjdChtb2NrVXBkYXRlTGFtYmRhQ29kZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoe1xuICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICBTM0J1Y2tldDogJ2N1cnJlbnQtYnVja2V0JyxcbiAgICBTM0tleTogJ25ldy1rZXknLFxuICB9KTtcbn0pO1xuXG50ZXN0KCdub24taG90c3dhcHBhYmxlIGNoYW5nZXMgaW4gbmVzdGVkIHN0YWNrcyByZXN1bHQgaW4gYSBmdWxsIGRlcGxveW1lbnQsIGV2ZW4gaWYgdGhlaXIgcGFyZW50IGNvbnRhaW5zIGEgaG90c3dhcHBhYmxlIGNoYW5nZScsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlciA9IHNldHVwLnNldHVwSG90c3dhcE5lc3RlZFN0YWNrVGVzdHMoJ05vbkhvdHN3YXBwYWJsZVJvb3QnKTtcbiAgbW9ja1VwZGF0ZUxhbWJkYUNvZGUgPSBqZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKHt9KTtcbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlci5zdHViTGFtYmRhKHtcbiAgICB1cGRhdGVGdW5jdGlvbkNvZGU6IG1vY2tVcGRhdGVMYW1iZGFDb2RlLFxuICB9KTtcblxuICBjb25zdCByb290U3RhY2sgPSB0ZXN0U3RhY2soe1xuICAgIHN0YWNrTmFtZTogJ05vbkhvdHN3YXBwYWJsZVJvb3QnLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgTmVzdGVkU3RhY2s6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIFRlbXBsYXRlVVJMOiAnaHR0cHM6Ly93d3cubWFnaWMtdXJsLmNvbScsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29uZS1sYW1iZGEtc3RhY2submVzdGVkLnRlbXBsYXRlLmpzb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIEZ1bmM6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBDb2RlOiB7XG4gICAgICAgICAgICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgICAgICAgICAgICBTM0tleTogJ2N1cnJlbnQta2V5JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBGdW5jdGlvbk5hbWU6ICdyb290LWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pO1xuXG4gIHNldHVwLmFkZFRlbXBsYXRlVG9DbG91ZEZvcm1hdGlvbkxvb2t1cE1vY2socm9vdFN0YWNrKTtcbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayh0ZXN0U3RhY2soe1xuICAgIHN0YWNrTmFtZTogJ05lc3RlZFN0YWNrJyxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgIEZ1bmM6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBDb2RlOiB7XG4gICAgICAgICAgICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgICAgICAgICAgICBTM0tleTogJ2N1cnJlbnQta2V5JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBQYWNrYWdlVHlwZTogJ0ltYWdlJyxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pKTtcblxuICBzZXR1cC5wdXNoTmVzdGVkU3RhY2tSZXNvdXJjZVN1bW1hcmllcygnTm9uSG90c3dhcHBhYmxlUm9vdCcsXG4gICAgc2V0dXAuc3RhY2tTdW1tYXJ5T2YoJ05lc3RlZFN0YWNrJywgJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICdhcm46YXdzOmNsb3VkZm9ybWF0aW9uOmJlcm11ZGEtdHJpYW5nbGUtMTMzNzoxMjM0NTY3ODkwMTI6c3RhY2svTmVzdGVkU3RhY2svYWJjZCcsXG4gICAgKSxcbiAgKTtcblxuICByb290U3RhY2sudGVtcGxhdGUuUmVzb3VyY2VzLkZ1bmMuUHJvcGVydGllcy5Db2RlLlMzQnVja2V0ID0gJ25ldy1idWNrZXQnO1xuICBjb25zdCBjZGtTdGFja0FydGlmYWN0ID0gdGVzdFN0YWNrKHsgc3RhY2tOYW1lOiAnTm9uSG90c3dhcHBhYmxlUm9vdCcsIHRlbXBsYXRlOiByb290U3RhY2sudGVtcGxhdGUgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KG1vY2tVcGRhdGVMYW1iZGFDb2RlKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xufSk7XG5cbnRlc3QoJ2RlbGV0aW5nIGEgbmVzdGVkIHN0YWNrIHJlc3VsdHMgaW4gYSBmdWxsIGRlcGxveW1lbnQsIGV2ZW4gaWYgdGhlaXIgcGFyZW50IGNvbnRhaW5zIGEgaG90c3dhcHBhYmxlIGNoYW5nZScsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlciA9IHNldHVwLnNldHVwSG90c3dhcE5lc3RlZFN0YWNrVGVzdHMoJ05lc3RlZFN0YWNrRGVsZXRpb25Sb290Jyk7XG4gIG1vY2tVcGRhdGVMYW1iZGFDb2RlID0gamVzdC5mbigpLm1vY2tSZXR1cm5WYWx1ZSh7fSk7XG4gIGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIuc3R1YkxhbWJkYSh7XG4gICAgdXBkYXRlRnVuY3Rpb25Db2RlOiBtb2NrVXBkYXRlTGFtYmRhQ29kZSxcbiAgfSk7XG5cbiAgY29uc3Qgcm9vdFN0YWNrID0gdGVzdFN0YWNrKHtcbiAgICBzdGFja05hbWU6ICdOZXN0ZWRTdGFja0RlbGV0aW9uUm9vdCcsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBOZXN0ZWRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb25lLWxhbWJkYS1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgRnVuYzoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ3Jvb3QtZnVuY3Rpb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICdhd3M6YXNzZXQ6cGF0aCc6ICdvbGQtcGF0aCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayhyb290U3RhY2spO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnTmVzdGVkU3RhY2snLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgRnVuYzoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pKTtcblxuICBzZXR1cC5wdXNoTmVzdGVkU3RhY2tSZXNvdXJjZVN1bW1hcmllcygnTmVzdGVkU3RhY2tEZWxldGlvblJvb3QnLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdOZXN0ZWRTdGFjaycsICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAnYXJuOmF3czpjbG91ZGZvcm1hdGlvbjpiZXJtdWRhLXRyaWFuZ2xlLTEzMzc6MTIzNDU2Nzg5MDEyOnN0YWNrL05lc3RlZFN0YWNrL2FiY2QnLFxuICAgICksXG4gICk7XG5cbiAgcm9vdFN0YWNrLnRlbXBsYXRlLlJlc291cmNlcy5GdW5jLlByb3BlcnRpZXMuQ29kZS5TM0J1Y2tldCA9ICduZXctYnVja2V0JztcbiAgZGVsZXRlIHJvb3RTdGFjay50ZW1wbGF0ZS5SZXNvdXJjZXMuTmVzdGVkU3RhY2s7XG4gIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSB0ZXN0U3RhY2soeyBzdGFja05hbWU6ICdOZXN0ZWRTdGFja0RlbGV0aW9uUm9vdCcsIHRlbXBsYXRlOiByb290U3RhY2sudGVtcGxhdGUgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KG1vY2tVcGRhdGVMYW1iZGFDb2RlKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xufSk7XG5cbnRlc3QoJ2NyZWF0aW5nIGEgbmVzdGVkIHN0YWNrIHJlc3VsdHMgaW4gYSBmdWxsIGRlcGxveW1lbnQsIGV2ZW4gaWYgdGhlaXIgcGFyZW50IGNvbnRhaW5zIGEgaG90c3dhcHBhYmxlIGNoYW5nZScsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlciA9IHNldHVwLnNldHVwSG90c3dhcE5lc3RlZFN0YWNrVGVzdHMoJ05lc3RlZFN0YWNrQ3JlYXRpb25Sb290Jyk7XG4gIG1vY2tVcGRhdGVMYW1iZGFDb2RlID0gamVzdC5mbigpLm1vY2tSZXR1cm5WYWx1ZSh7fSk7XG4gIGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIuc3R1YkxhbWJkYSh7XG4gICAgdXBkYXRlRnVuY3Rpb25Db2RlOiBtb2NrVXBkYXRlTGFtYmRhQ29kZSxcbiAgfSk7XG5cbiAgY29uc3Qgcm9vdFN0YWNrID0gdGVzdFN0YWNrKHtcbiAgICBzdGFja05hbWU6ICdOZXN0ZWRTdGFja0NyZWF0aW9uUm9vdCcsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBGdW5jOiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgQ29kZToge1xuICAgICAgICAgICAgICBTM0J1Y2tldDogJ2N1cnJlbnQtYnVja2V0JyxcbiAgICAgICAgICAgICAgUzNLZXk6ICdjdXJyZW50LWtleScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgRnVuY3Rpb25OYW1lOiAncm9vdC1mdW5jdGlvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29sZC1wYXRoJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICB9KTtcblxuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHJvb3RTdGFjayk7XG5cbiAgcm9vdFN0YWNrLnRlbXBsYXRlLlJlc291cmNlcy5GdW5jLlByb3BlcnRpZXMuQ29kZS5TM0J1Y2tldCA9ICduZXctYnVja2V0JztcbiAgcm9vdFN0YWNrLnRlbXBsYXRlLlJlc291cmNlcy5OZXN0ZWRTdGFjayA9IHtcbiAgICBUeXBlOiAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgIFByb3BlcnRpZXM6IHtcbiAgICAgIFRlbXBsYXRlVVJMOiAnaHR0cHM6Ly93d3cubWFnaWMtdXJsLmNvbScsXG4gICAgfSxcbiAgICBNZXRhZGF0YToge1xuICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29uZS1sYW1iZGEtc3RhY2submVzdGVkLnRlbXBsYXRlLmpzb24nLFxuICAgIH0sXG4gIH07XG4gIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSB0ZXN0U3RhY2soeyBzdGFja05hbWU6ICdOZXN0ZWRTdGFja0NyZWF0aW9uUm9vdCcsIHRlbXBsYXRlOiByb290U3RhY2sudGVtcGxhdGUgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KG1vY2tVcGRhdGVMYW1iZGFDb2RlKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xufSk7XG5cbnRlc3QoJ2F0dGVtcHRpbmcgdG8gaG90c3dhcCBhIG5ld2x5IGNyZWF0ZWQgbmVzdGVkIHN0YWNrIHdpdGggdGhlIHNhbWUgbG9naWNhbCBJRCBhcyBhIHJlc291cmNlIHdpdGggYSBkaWZmZXJlbnQgdHlwZSByZXN1bHRzIGluIGEgZnVsbCBkZXBsb3ltZW50JywgYXN5bmMgKCkgPT4ge1xuICAvLyBHSVZFTlxuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyID0gc2V0dXAuc2V0dXBIb3Rzd2FwTmVzdGVkU3RhY2tUZXN0cygnTmVzdGVkU3RhY2tUeXBlQ2hhbmdlUm9vdCcpO1xuICBtb2NrVXBkYXRlTGFtYmRhQ29kZSA9IGplc3QuZm4oKS5tb2NrUmV0dXJuVmFsdWUoe30pO1xuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnN0dWJMYW1iZGEoe1xuICAgIHVwZGF0ZUZ1bmN0aW9uQ29kZTogbW9ja1VwZGF0ZUxhbWJkYUNvZGUsXG4gIH0pO1xuXG4gIGNvbnN0IHJvb3RTdGFjayA9IHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnTmVzdGVkU3RhY2tUeXBlQ2hhbmdlUm9vdCcsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBGdW5jOiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgQ29kZToge1xuICAgICAgICAgICAgICBTM0J1Y2tldDogJ2N1cnJlbnQtYnVja2V0JyxcbiAgICAgICAgICAgICAgUzNLZXk6ICdjdXJyZW50LWtleScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgRnVuY3Rpb25OYW1lOiAncm9vdC1mdW5jdGlvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29sZC1wYXRoJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBGdXR1cmVOZXN0ZWRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnbmV3LWtleScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgRnVuY3Rpb25OYW1lOiAnc3Bvb2t5LWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pO1xuXG4gIHNldHVwLmFkZFRlbXBsYXRlVG9DbG91ZEZvcm1hdGlvbkxvb2t1cE1vY2socm9vdFN0YWNrKTtcblxuICByb290U3RhY2sudGVtcGxhdGUuUmVzb3VyY2VzLkZ1bmMuUHJvcGVydGllcy5Db2RlLlMzQnVja2V0ID0gJ25ldy1idWNrZXQnO1xuICByb290U3RhY2sudGVtcGxhdGUuUmVzb3VyY2VzLkZ1dHVyZU5lc3RlZFN0YWNrID0ge1xuICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgUHJvcGVydGllczoge1xuICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICB9LFxuICAgIE1ldGFkYXRhOiB7XG4gICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb25lLWxhbWJkYS1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgfSxcbiAgfTtcbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHRlc3RTdGFjayh7IHN0YWNrTmFtZTogJ05lc3RlZFN0YWNrVHlwZUNoYW5nZVJvb3QnLCB0ZW1wbGF0ZTogcm9vdFN0YWNrLnRlbXBsYXRlIH0pO1xuXG4gIC8vIFdIRU5cbiAgY29uc3QgZGVwbG95U3RhY2tSZXN1bHQgPSBhd2FpdCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QpO1xuXG4gIC8vIFRIRU5cbiAgZXhwZWN0KGRlcGxveVN0YWNrUmVzdWx0KS50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChtb2NrVXBkYXRlTGFtYmRhQ29kZSkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbn0pO1xuXG5cbnRlc3QoJ211bHRpLXNpYmxpbmcgKyAzLWxheWVyIG5lc3RlZCBzdGFjayBzdHJ1Y3R1cmUgaXMgaG90c3dhcHBhYmxlJywgYXN5bmMgKCkgPT4ge1xuICAvLyBHSVZFTlxuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyID0gc2V0dXAuc2V0dXBIb3Rzd2FwTmVzdGVkU3RhY2tUZXN0cygnTXVsdGlMYXllclJvb3QnKTtcbiAgbW9ja1VwZGF0ZUxhbWJkYUNvZGUgPSBqZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKHt9KTtcbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlci5zdHViTGFtYmRhKHtcbiAgICB1cGRhdGVGdW5jdGlvbkNvZGU6IG1vY2tVcGRhdGVMYW1iZGFDb2RlLFxuICB9KTtcblxuICBjb25zdCBsYW1iZGFGdW5jdGlvblJlc291cmNlID0ge1xuICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgIFByb3BlcnRpZXM6IHtcbiAgICAgIENvZGU6IHtcbiAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgfSxcbiAgICB9LFxuICAgIE1ldGFkYXRhOiB7XG4gICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3Qgcm9vdFN0YWNrID0gdGVzdFN0YWNrKHtcbiAgICBzdGFja05hbWU6ICdNdWx0aUxheWVyUm9vdCcsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBDaGlsZFN0YWNrOiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBUZW1wbGF0ZVVSTDogJ2h0dHBzOi8vd3d3Lm1hZ2ljLXVybC5jb20nLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICdhd3M6YXNzZXQ6cGF0aCc6ICdvbmUtdW5uYW1lZC1sYW1iZGEtdHdvLXN0YWNrcy1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgRnVuYzogbGFtYmRhRnVuY3Rpb25SZXNvdXJjZSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayhyb290U3RhY2spO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnQ2hpbGRTdGFjaycsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBHcmFuZENoaWxkU3RhY2tBOiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBUZW1wbGF0ZVVSTDogJ2h0dHBzOi8vd3d3Lm1hZ2ljLXVybC5jb20nLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICdhd3M6YXNzZXQ6cGF0aCc6ICdvbmUtdW5uYW1lZC1sYW1iZGEtc3RhY2submVzdGVkLnRlbXBsYXRlLmpzb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIEdyYW5kQ2hpbGRTdGFja0I6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIFRlbXBsYXRlVVJMOiAnaHR0cHM6Ly93d3cubWFnaWMtdXJsLmNvbScsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29uZS11bm5hbWVkLWxhbWJkYS1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgRnVuYzogbGFtYmRhRnVuY3Rpb25SZXNvdXJjZSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSkpO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnR3JhbmRDaGlsZFN0YWNrQScsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBGdW5jOiBsYW1iZGFGdW5jdGlvblJlc291cmNlLFxuICAgICAgfSxcbiAgICB9LFxuICB9KSk7XG4gIHNldHVwLmFkZFRlbXBsYXRlVG9DbG91ZEZvcm1hdGlvbkxvb2t1cE1vY2sodGVzdFN0YWNrKHtcbiAgICBzdGFja05hbWU6ICdHcmFuZENoaWxkU3RhY2tCJyxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgIEZ1bmM6IGxhbWJkYUZ1bmN0aW9uUmVzb3VyY2UsXG4gICAgICB9LFxuICAgIH0sXG4gIH0pKTtcblxuICBzZXR1cC5wdXNoTmVzdGVkU3RhY2tSZXNvdXJjZVN1bW1hcmllcygnTXVsdGlMYXllclJvb3QnLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdDaGlsZFN0YWNrJywgJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICdhcm46YXdzOmNsb3VkZm9ybWF0aW9uOmJlcm11ZGEtdHJpYW5nbGUtMTMzNzoxMjM0NTY3ODkwMTI6c3RhY2svQ2hpbGRTdGFjay9hYmNkJyxcbiAgICApLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdGdW5jJywgJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsICdyb290LWZ1bmN0aW9uJyksXG4gICk7XG4gIHNldHVwLnB1c2hOZXN0ZWRTdGFja1Jlc291cmNlU3VtbWFyaWVzKCdDaGlsZFN0YWNrJyxcbiAgICBzZXR1cC5zdGFja1N1bW1hcnlPZignR3JhbmRDaGlsZFN0YWNrQScsICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAnYXJuOmF3czpjbG91ZGZvcm1hdGlvbjpiZXJtdWRhLXRyaWFuZ2xlLTEzMzc6MTIzNDU2Nzg5MDEyOnN0YWNrL0dyYW5kQ2hpbGRTdGFja0EvYWJjZCcsXG4gICAgKSxcbiAgICBzZXR1cC5zdGFja1N1bW1hcnlPZignR3JhbmRDaGlsZFN0YWNrQicsICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAnYXJuOmF3czpjbG91ZGZvcm1hdGlvbjpiZXJtdWRhLXRyaWFuZ2xlLTEzMzc6MTIzNDU2Nzg5MDEyOnN0YWNrL0dyYW5kQ2hpbGRTdGFja0IvYWJjZCcsXG4gICAgKSxcbiAgICBzZXR1cC5zdGFja1N1bW1hcnlPZignRnVuYycsICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLCAnY2hpbGQtZnVuY3Rpb24nKSxcbiAgKTtcbiAgc2V0dXAucHVzaE5lc3RlZFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoJ0dyYW5kQ2hpbGRTdGFja0EnLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdGdW5jJywgJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsICdncmFuZGNoaWxkLUEtZnVuY3Rpb24nKSxcbiAgKTtcbiAgc2V0dXAucHVzaE5lc3RlZFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoJ0dyYW5kQ2hpbGRTdGFja0InLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdGdW5jJywgJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsICdncmFuZGNoaWxkLUItZnVuY3Rpb24nKSxcbiAgKTtcblxuICByb290U3RhY2sudGVtcGxhdGUuUmVzb3VyY2VzLkZ1bmMuUHJvcGVydGllcy5Db2RlLlMzS2V5ID0gJ25ldy1rZXknO1xuICBjb25zdCBjZGtTdGFja0FydGlmYWN0ID0gdGVzdFN0YWNrKHsgc3RhY2tOYW1lOiAnTXVsdGlMYXllclJvb3QnLCB0ZW1wbGF0ZTogcm9vdFN0YWNrLnRlbXBsYXRlIH0pO1xuXG4gIC8vIFdIRU5cbiAgY29uc3QgZGVwbG95U3RhY2tSZXN1bHQgPSBhd2FpdCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QpO1xuXG4gIC8vIFRIRU5cbiAgZXhwZWN0KGRlcGxveVN0YWNrUmVzdWx0KS5ub3QudG9CZVVuZGVmaW5lZCgpO1xuICBleHBlY3QobW9ja1VwZGF0ZUxhbWJkYUNvZGUpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICBGdW5jdGlvbk5hbWU6ICdyb290LWZ1bmN0aW9uJyxcbiAgICBTM0J1Y2tldDogJ2N1cnJlbnQtYnVja2V0JyxcbiAgICBTM0tleTogJ25ldy1rZXknLFxuICB9KTtcbiAgZXhwZWN0KG1vY2tVcGRhdGVMYW1iZGFDb2RlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgRnVuY3Rpb25OYW1lOiAnY2hpbGQtZnVuY3Rpb24nLFxuICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgIFMzS2V5OiAnbmV3LWtleScsXG4gIH0pO1xuICBleHBlY3QobW9ja1VwZGF0ZUxhbWJkYUNvZGUpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICBGdW5jdGlvbk5hbWU6ICdncmFuZGNoaWxkLUEtZnVuY3Rpb24nLFxuICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgIFMzS2V5OiAnbmV3LWtleScsXG4gIH0pO1xuICBleHBlY3QobW9ja1VwZGF0ZUxhbWJkYUNvZGUpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICBGdW5jdGlvbk5hbWU6ICdncmFuZGNoaWxkLUItZnVuY3Rpb24nLFxuICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgIFMzS2V5OiAnbmV3LWtleScsXG4gIH0pO1xufSk7XG5cbnRlc3QoJ2NhbiBob3Rzd2FwIGEgbGFtYmRhIGZ1bmN0aW9uIGluIGEgMS1sZXZlbCBuZXN0ZWQgc3RhY2sgd2l0aCBhc3NldCBwYXJhbWV0ZXJzJywgYXN5bmMgKCkgPT4ge1xuICAvLyBHSVZFTlxuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyID0gc2V0dXAuc2V0dXBIb3Rzd2FwTmVzdGVkU3RhY2tUZXN0cygnTGFtYmRhUm9vdCcpO1xuICBtb2NrVXBkYXRlTGFtYmRhQ29kZSA9IGplc3QuZm4oKS5tb2NrUmV0dXJuVmFsdWUoe30pO1xuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnN0dWJMYW1iZGEoe1xuICAgIHVwZGF0ZUZ1bmN0aW9uQ29kZTogbW9ja1VwZGF0ZUxhbWJkYUNvZGUsXG4gIH0pO1xuXG4gIGNvbnN0IHJvb3RTdGFjayA9IHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnTGFtYmRhUm9vdCcsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBOZXN0ZWRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICAgICAgICAgIFBhcmFtZXRlcnM6IHtcbiAgICAgICAgICAgICAgcmVmZXJlbmNldG9TM0J1Y2tldFBhcmFtOiB7XG4gICAgICAgICAgICAgICAgUmVmOiAnUzNCdWNrZXRQYXJhbScsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHJlZmVyZW5jZXRvUzNLZXlQYXJhbToge1xuICAgICAgICAgICAgICAgIFJlZjogJ1MzS2V5UGFyYW0nLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb25lLWxhbWJkYS1zdGFjay13aXRoLWFzc2V0LXBhcmFtZXRlcnMubmVzdGVkLnRlbXBsYXRlLmpzb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgUGFyYW1ldGVyczoge1xuICAgICAgICBTM0J1Y2tldFBhcmFtOiB7XG4gICAgICAgICAgVHlwZTogJ1N0cmluZycsXG4gICAgICAgICAgRGVzY3JpcHRpb246ICdTMyBidWNrZXQgZm9yIGFzc2V0JyxcbiAgICAgICAgfSxcbiAgICAgICAgUzNLZXlQYXJhbToge1xuICAgICAgICAgIFR5cGU6ICdTdHJpbmcnLFxuICAgICAgICAgIERlc2NyaXB0aW9uOiAnUzMgYnVja2V0IGZvciBhc3NldCcsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0pO1xuXG4gIHNldHVwLmFkZFRlbXBsYXRlVG9DbG91ZEZvcm1hdGlvbkxvb2t1cE1vY2socm9vdFN0YWNrKTtcbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayh0ZXN0U3RhY2soe1xuICAgIHN0YWNrTmFtZTogJ05lc3RlZFN0YWNrJyxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgIEZ1bmM6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBDb2RlOiB7XG4gICAgICAgICAgICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgICAgICAgICAgICBTM0tleTogJ2N1cnJlbnQta2V5JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBGdW5jdGlvbk5hbWU6ICdteS1mdW5jdGlvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29sZC1wYXRoJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICB9KSk7XG5cbiAgc2V0dXAucHVzaE5lc3RlZFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoJ0xhbWJkYVJvb3QnLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdOZXN0ZWRTdGFjaycsICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAnYXJuOmF3czpjbG91ZGZvcm1hdGlvbjpiZXJtdWRhLXRyaWFuZ2xlLTEzMzc6MTIzNDU2Nzg5MDEyOnN0YWNrL05lc3RlZFN0YWNrL2FiY2QnLFxuICAgICksXG4gICk7XG5cbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHRlc3RTdGFjayh7IHN0YWNrTmFtZTogJ0xhbWJkYVJvb3QnLCB0ZW1wbGF0ZTogcm9vdFN0YWNrLnRlbXBsYXRlIH0pO1xuXG4gIC8vIFdIRU5cbiAgY29uc3QgZGVwbG95U3RhY2tSZXN1bHQgPSBhd2FpdCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QsIHtcbiAgICBTM0J1Y2tldFBhcmFtOiAnYnVja2V0LXBhcmFtLXZhbHVlJyxcbiAgICBTM0tleVBhcmFtOiAna2V5LXBhcmFtLXZhbHVlJyxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLm5vdC50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChtb2NrVXBkYXRlTGFtYmRhQ29kZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoe1xuICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICBTM0J1Y2tldDogJ2J1Y2tldC1wYXJhbS12YWx1ZScsXG4gICAgUzNLZXk6ICdrZXktcGFyYW0tdmFsdWUnLFxuICB9KTtcbn0pO1xuXG50ZXN0KCdjYW4gaG90c3dhcCBhIGxhbWJkYSBmdW5jdGlvbiBpbiBhIDItbGV2ZWwgbmVzdGVkIHN0YWNrIHdpdGggYXNzZXQgcGFyYW1ldGVycycsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlciA9IHNldHVwLnNldHVwSG90c3dhcE5lc3RlZFN0YWNrVGVzdHMoJ0xhbWJkYVJvb3QnKTtcbiAgbW9ja1VwZGF0ZUxhbWJkYUNvZGUgPSBqZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKHt9KTtcbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlci5zdHViTGFtYmRhKHtcbiAgICB1cGRhdGVGdW5jdGlvbkNvZGU6IG1vY2tVcGRhdGVMYW1iZGFDb2RlLFxuICB9KTtcblxuICBjb25zdCByb290U3RhY2sgPSB0ZXN0U3RhY2soe1xuICAgIHN0YWNrTmFtZTogJ0xhbWJkYVJvb3QnLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgQ2hpbGRTdGFjazoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgVGVtcGxhdGVVUkw6ICdodHRwczovL3d3dy5tYWdpYy11cmwuY29tJyxcbiAgICAgICAgICAgIFBhcmFtZXRlcnM6IHtcbiAgICAgICAgICAgICAgcmVmZXJlbmNldG9HcmFuZENoaWxkUzNCdWNrZXRQYXJhbToge1xuICAgICAgICAgICAgICAgIFJlZjogJ0dyYW5kQ2hpbGRTM0J1Y2tldFBhcmFtJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgcmVmZXJlbmNldG9HcmFuZENoaWxkUzNLZXlQYXJhbToge1xuICAgICAgICAgICAgICAgIFJlZjogJ0dyYW5kQ2hpbGRTM0tleVBhcmFtJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgcmVmZXJlbmNldG9DaGlsZFMzQnVja2V0UGFyYW06IHtcbiAgICAgICAgICAgICAgICBSZWY6ICdDaGlsZFMzQnVja2V0UGFyYW0nLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICByZWZlcmVuY2V0b0NoaWxkUzNLZXlQYXJhbToge1xuICAgICAgICAgICAgICAgIFJlZjogJ0NoaWxkUzNLZXlQYXJhbScsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICdhd3M6YXNzZXQ6cGF0aCc6ICdvbmUtbGFtYmRhLW9uZS1zdGFjay1zdGFjay13aXRoLWFzc2V0LXBhcmFtZXRlcnMubmVzdGVkLnRlbXBsYXRlLmpzb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgUGFyYW1ldGVyczoge1xuICAgICAgICBHcmFuZENoaWxkUzNCdWNrZXRQYXJhbToge1xuICAgICAgICAgIFR5cGU6ICdTdHJpbmcnLFxuICAgICAgICAgIERlc2NyaXB0aW9uOiAnUzMgYnVja2V0IGZvciBhc3NldCcsXG4gICAgICAgIH0sXG4gICAgICAgIEdyYW5kQ2hpbGRTM0tleVBhcmFtOiB7XG4gICAgICAgICAgVHlwZTogJ1N0cmluZycsXG4gICAgICAgICAgRGVzY3JpcHRpb246ICdTMyBidWNrZXQgZm9yIGFzc2V0JyxcbiAgICAgICAgfSxcbiAgICAgICAgQ2hpbGRTM0J1Y2tldFBhcmFtOiB7XG4gICAgICAgICAgVHlwZTogJ1N0cmluZycsXG4gICAgICAgICAgRGVzY3JpcHRpb246ICdTMyBidWNrZXQgZm9yIGFzc2V0JyxcbiAgICAgICAgfSxcbiAgICAgICAgQ2hpbGRTM0tleVBhcmFtOiB7XG4gICAgICAgICAgVHlwZTogJ1N0cmluZycsXG4gICAgICAgICAgRGVzY3JpcHRpb246ICdTMyBidWNrZXQgZm9yIGFzc2V0JyxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayhyb290U3RhY2spO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnQ2hpbGRTdGFjaycsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBGdW5jOiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgQ29kZToge1xuICAgICAgICAgICAgICBTM0J1Y2tldDogJ2N1cnJlbnQtYnVja2V0JyxcbiAgICAgICAgICAgICAgUzNLZXk6ICdjdXJyZW50LWtleScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgRnVuY3Rpb25OYW1lOiAnbXktZnVuY3Rpb24nLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICdhd3M6YXNzZXQ6cGF0aCc6ICdvbGQtcGF0aCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgR3JhbmRDaGlsZFN0YWNrOiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBUZW1wbGF0ZVVSTDogJ2h0dHBzOi8vd3d3Lm1hZ2ljLXVybC5jb20nLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICdhd3M6YXNzZXQ6cGF0aCc6ICdvbmUtbGFtYmRhLXN0YWNrLXdpdGgtYXNzZXQtcGFyYW1ldGVycy5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSkpO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnR3JhbmRDaGlsZFN0YWNrJyxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgIEZ1bmM6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBDb2RlOiB7XG4gICAgICAgICAgICAgIFMzQnVja2V0OiAnY3VycmVudC1idWNrZXQnLFxuICAgICAgICAgICAgICBTM0tleTogJ2N1cnJlbnQta2V5JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBGdW5jdGlvbk5hbWU6ICdteS1mdW5jdGlvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29sZC1wYXRoJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICB9KSk7XG5cblxuICBzZXR1cC5wdXNoTmVzdGVkU3RhY2tSZXNvdXJjZVN1bW1hcmllcygnTGFtYmRhUm9vdCcsXG4gICAgc2V0dXAuc3RhY2tTdW1tYXJ5T2YoJ0NoaWxkU3RhY2snLCAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgICAgJ2Fybjphd3M6Y2xvdWRmb3JtYXRpb246YmVybXVkYS10cmlhbmdsZS0xMzM3OjEyMzQ1Njc4OTAxMjpzdGFjay9DaGlsZFN0YWNrL2FiY2QnLFxuICAgICksXG4gICk7XG5cbiAgc2V0dXAucHVzaE5lc3RlZFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoJ0NoaWxkU3RhY2snLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdHcmFuZENoaWxkU3RhY2snLCAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgICAgJ2Fybjphd3M6Y2xvdWRmb3JtYXRpb246YmVybXVkYS10cmlhbmdsZS0xMzM3OjEyMzQ1Njc4OTAxMjpzdGFjay9HcmFuZENoaWxkU3RhY2svYWJjZCcsXG4gICAgKSxcbiAgKTtcbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHRlc3RTdGFjayh7IHN0YWNrTmFtZTogJ0xhbWJkYVJvb3QnLCB0ZW1wbGF0ZTogcm9vdFN0YWNrLnRlbXBsYXRlIH0pO1xuXG4gIC8vIFdIRU5cbiAgY29uc3QgZGVwbG95U3RhY2tSZXN1bHQgPSBhd2FpdCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QsIHtcbiAgICBHcmFuZENoaWxkUzNCdWNrZXRQYXJhbTogJ2NoaWxkLWJ1Y2tldC1wYXJhbS12YWx1ZScsXG4gICAgR3JhbmRDaGlsZFMzS2V5UGFyYW06ICdjaGlsZC1rZXktcGFyYW0tdmFsdWUnLFxuICAgIENoaWxkUzNCdWNrZXRQYXJhbTogJ2J1Y2tldC1wYXJhbS12YWx1ZScsXG4gICAgQ2hpbGRTM0tleVBhcmFtOiAna2V5LXBhcmFtLXZhbHVlJyxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLm5vdC50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChtb2NrVXBkYXRlTGFtYmRhQ29kZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoe1xuICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICBTM0J1Y2tldDogJ2J1Y2tldC1wYXJhbS12YWx1ZScsXG4gICAgUzNLZXk6ICdrZXktcGFyYW0tdmFsdWUnLFxuICB9KTtcbiAgZXhwZWN0KG1vY2tVcGRhdGVMYW1iZGFDb2RlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgRnVuY3Rpb25OYW1lOiAnbXktZnVuY3Rpb24nLFxuICAgIFMzQnVja2V0OiAnY2hpbGQtYnVja2V0LXBhcmFtLXZhbHVlJyxcbiAgICBTM0tleTogJ2NoaWxkLWtleS1wYXJhbS12YWx1ZScsXG4gIH0pO1xufSk7XG5cbnRlc3QoJ2xvb2tpbmcgdXAgb2JqZWN0cyBpbiBuZXN0ZWQgc3RhY2tzIHdvcmtzJywgYXN5bmMgKCkgPT4ge1xuICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyID0gc2V0dXAuc2V0dXBIb3Rzd2FwTmVzdGVkU3RhY2tUZXN0cygnTGFtYmRhUm9vdCcpO1xuICBtb2NrVXBkYXRlTGFtYmRhQ29kZSA9IGplc3QuZm4oKS5tb2NrUmV0dXJuVmFsdWUoe30pO1xuICBtb2NrUHVibGlzaFZlcnNpb24gPSBqZXN0LmZuKCk7XG4gIGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIuc3R1YkxhbWJkYSh7XG4gICAgdXBkYXRlRnVuY3Rpb25Db2RlOiBtb2NrVXBkYXRlTGFtYmRhQ29kZSxcbiAgICBwdWJsaXNoVmVyc2lvbjogbW9ja1B1Ymxpc2hWZXJzaW9uLFxuICB9KTtcblxuICBjb25zdCByb290U3RhY2sgPSB0ZXN0U3RhY2soe1xuICAgIHN0YWNrTmFtZTogJ0xhbWJkYVJvb3QnLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgTmVzdGVkU3RhY2s6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIFRlbXBsYXRlVVJMOiAnaHR0cHM6Ly93d3cubWFnaWMtdXJsLmNvbScsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNZXRhZGF0YToge1xuICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ29uZS1sYW1iZGEtdmVyc2lvbi1zdGFjay5uZXN0ZWQudGVtcGxhdGUuanNvbicsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgc2V0dXAuYWRkVGVtcGxhdGVUb0Nsb3VkRm9ybWF0aW9uTG9va3VwTW9jayhyb290U3RhY2spO1xuICBzZXR1cC5hZGRUZW1wbGF0ZVRvQ2xvdWRGb3JtYXRpb25Mb29rdXBNb2NrKHRlc3RTdGFjayh7XG4gICAgc3RhY2tOYW1lOiAnTmVzdGVkU3RhY2snLFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgRnVuYzoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIENvZGU6IHtcbiAgICAgICAgICAgICAgUzNCdWNrZXQ6ICdjdXJyZW50LWJ1Y2tldCcsXG4gICAgICAgICAgICAgIFMzS2V5OiAnY3VycmVudC1rZXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogJ215LWZ1bmN0aW9uJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBWZXJzaW9uOiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6TGFtYmRhOjpWZXJzaW9uJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBGdW5jdGlvbk5hbWU6IHsgUmVmOiAnRnVuYycgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICB9KSk7XG5cbiAgc2V0dXAucHVzaE5lc3RlZFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoJ0xhbWJkYVJvb3QnLFxuICAgIHNldHVwLnN0YWNrU3VtbWFyeU9mKCdOZXN0ZWRTdGFjaycsICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAnYXJuOmF3czpjbG91ZGZvcm1hdGlvbjpiZXJtdWRhLXRyaWFuZ2xlLTEzMzc6MTIzNDU2Nzg5MDEyOnN0YWNrL05lc3RlZFN0YWNrL2FiY2QnLFxuICAgICksXG4gICk7XG5cbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHRlc3RTdGFjayh7IHN0YWNrTmFtZTogJ0xhbWJkYVJvb3QnLCB0ZW1wbGF0ZTogcm9vdFN0YWNrLnRlbXBsYXRlIH0pO1xuXG4gIC8vIFdIRU5cbiAgY29uc3QgZGVwbG95U3RhY2tSZXN1bHQgPSBhd2FpdCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QpO1xuXG4gIC8vIFRIRU5cbiAgZXhwZWN0KGRlcGxveVN0YWNrUmVzdWx0KS5ub3QudG9CZVVuZGVmaW5lZCgpO1xuICBleHBlY3QobW9ja1B1Ymxpc2hWZXJzaW9uKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgRnVuY3Rpb25OYW1lOiAnbXktZnVuY3Rpb24nLFxuICB9KTtcbn0pO1xuIl19