@aws-solutions-constructs/aws-cloudfront-s3 2.99.0 → 2.100.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,859 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
6
+ * with the License. A copy of the License is located at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
11
+ * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
12
+ * and limitations under the License.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const assertions_1 = require("aws-cdk-lib/assertions");
16
+ const s3 = require("aws-cdk-lib/aws-s3");
17
+ const cdk = require("aws-cdk-lib");
18
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
19
+ const lib_1 = require("../lib");
20
+ const acm = require("aws-cdk-lib/aws-certificatemanager");
21
+ const defaults = require("@aws-solutions-constructs/core");
22
+ const aws_kms_1 = require("aws-cdk-lib/aws-kms");
23
+ const origins = require("aws-cdk-lib/aws-cloudfront-origins");
24
+ const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront");
25
+ function deploy(stack, props) {
26
+ return new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {
27
+ bucketProps: {
28
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
29
+ },
30
+ ...props
31
+ });
32
+ }
33
+ test('construct defaults set properties correctly', () => {
34
+ const stack = new cdk.Stack();
35
+ const construct = new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {});
36
+ expect(construct.cloudFrontWebDistribution).toBeDefined();
37
+ expect(construct.cloudFrontFunction).toBeDefined();
38
+ expect(construct.cloudFrontLoggingBucket).toBeDefined();
39
+ expect(construct.s3Bucket).toBeDefined();
40
+ expect(construct.s3LoggingBucket).toBeDefined();
41
+ expect(construct.s3BucketInterface).toBeDefined();
42
+ expect(construct.cloudFrontLoggingBucketAccessLogBucket).toBeDefined();
43
+ expect(construct.originAccessControl).toBeDefined();
44
+ });
45
+ test('check s3Bucket default encryption', () => {
46
+ const stack = new cdk.Stack();
47
+ deploy(stack);
48
+ const template = assertions_1.Template.fromStack(stack);
49
+ template.hasResourceProperties('AWS::S3::Bucket', {
50
+ BucketEncryption: {
51
+ ServerSideEncryptionConfiguration: [{
52
+ ServerSideEncryptionByDefault: {
53
+ SSEAlgorithm: "AES256"
54
+ }
55
+ }]
56
+ }
57
+ });
58
+ });
59
+ test('check s3Bucket public access block configuration', () => {
60
+ const stack = new cdk.Stack();
61
+ deploy(stack);
62
+ const template = assertions_1.Template.fromStack(stack);
63
+ template.hasResourceProperties('AWS::S3::Bucket', {
64
+ PublicAccessBlockConfiguration: {
65
+ BlockPublicAcls: true,
66
+ BlockPublicPolicy: true,
67
+ IgnorePublicAcls: true,
68
+ RestrictPublicBuckets: true
69
+ }
70
+ });
71
+ });
72
+ test('test s3Bucket override publicAccessBlockConfiguration', () => {
73
+ const stack = new cdk.Stack();
74
+ const props = {
75
+ bucketProps: {
76
+ blockPublicAccess: {
77
+ blockPublicAcls: false,
78
+ blockPublicPolicy: true,
79
+ ignorePublicAcls: false,
80
+ restrictPublicBuckets: true
81
+ }
82
+ }
83
+ };
84
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', props);
85
+ const template = assertions_1.Template.fromStack(stack);
86
+ template.hasResourceProperties("AWS::S3::Bucket", {
87
+ PublicAccessBlockConfiguration: {
88
+ BlockPublicAcls: false,
89
+ BlockPublicPolicy: true,
90
+ IgnorePublicAcls: false,
91
+ RestrictPublicBuckets: true
92
+ },
93
+ });
94
+ });
95
+ test('check existing bucket', () => {
96
+ const stack = new cdk.Stack();
97
+ const existingBucket = new s3.Bucket(stack, 'my-bucket', {
98
+ bucketName: 'my-bucket'
99
+ });
100
+ const props = {
101
+ existingBucketObj: existingBucket
102
+ };
103
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', props);
104
+ const template = assertions_1.Template.fromStack(stack);
105
+ template.hasResourceProperties("AWS::S3::Bucket", {
106
+ BucketName: "my-bucket"
107
+ });
108
+ });
109
+ test('check exception for Missing existingObj from props for deploy = false', () => {
110
+ const stack = new cdk.Stack();
111
+ try {
112
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {});
113
+ }
114
+ catch (e) {
115
+ expect(e).toBeInstanceOf(Error);
116
+ }
117
+ });
118
+ test('check properties', () => {
119
+ const stack = new cdk.Stack();
120
+ const construct = deploy(stack);
121
+ expect(construct.cloudFrontWebDistribution).toBeDefined();
122
+ expect(construct.s3Bucket).toBeDefined();
123
+ });
124
+ test("Confirm CheckS3Props is called", () => {
125
+ // Stack
126
+ const stack = new cdk.Stack();
127
+ const testBucket = new s3.Bucket(stack, 'test-bucket', {});
128
+ const app = () => {
129
+ // Helper declaration
130
+ new lib_1.CloudFrontToS3(stack, "bad-s3-args", {
131
+ existingBucketObj: testBucket,
132
+ bucketProps: {
133
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY
134
+ },
135
+ });
136
+ };
137
+ // Assertion
138
+ expect(app).toThrow('Error - Either provide bucketProps or existingBucketObj, but not both.\n');
139
+ });
140
+ test("Test existingBucketObj", () => {
141
+ // Stack
142
+ const stack = new cdk.Stack();
143
+ const construct = new lib_1.CloudFrontToS3(stack, "existingIBucket", {
144
+ existingBucketObj: s3.Bucket.fromBucketName(stack, 'mybucket', 'mybucket')
145
+ });
146
+ // Assertion
147
+ expect(construct.cloudFrontWebDistribution).toBeDefined();
148
+ const template = assertions_1.Template.fromStack(stack);
149
+ template.hasResourceProperties("AWS::CloudFront::Distribution", {
150
+ DistributionConfig: {
151
+ Origins: [
152
+ {
153
+ DomainName: {
154
+ "Fn::Join": [
155
+ "",
156
+ [
157
+ "mybucket.s3.",
158
+ {
159
+ Ref: "AWS::Region"
160
+ },
161
+ ".",
162
+ {
163
+ Ref: "AWS::URLSuffix"
164
+ }
165
+ ]
166
+ ]
167
+ },
168
+ Id: "existingIBucketCloudFrontDistributionOrigin1D5849125",
169
+ OriginAccessControlId: { "Fn::GetAtt": ["existingIBucketCloudFrontOacEB42E98F", "Id"] },
170
+ S3OriginConfig: {}
171
+ }
172
+ ]
173
+ }
174
+ });
175
+ });
176
+ test('test cloudfront with custom domain names', () => {
177
+ const stack = new cdk.Stack();
178
+ const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:${Aws.PARTITION}:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012');
179
+ const props = {
180
+ cloudFrontDistributionProps: {
181
+ domainNames: ['mydomains'],
182
+ certificate
183
+ }
184
+ };
185
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', props);
186
+ const template = assertions_1.Template.fromStack(stack);
187
+ template.hasResourceProperties("AWS::CloudFront::Distribution", {
188
+ DistributionConfig: {
189
+ Aliases: [
190
+ "mydomains"
191
+ ]
192
+ }
193
+ });
194
+ });
195
+ test('Cloudfront logging bucket with destroy removal policy and auto delete objects', () => {
196
+ const stack = new cdk.Stack();
197
+ const cloudfrontLogBucketName = 'cf-log-bucket';
198
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
199
+ cloudFrontLoggingBucketProps: {
200
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
201
+ autoDeleteObjects: true,
202
+ bucketName: cloudfrontLogBucketName
203
+ }
204
+ });
205
+ const template = assertions_1.Template.fromStack(stack);
206
+ template.hasResourceProperties("AWS::S3::Bucket", {
207
+ OwnershipControls: { Rules: [{ ObjectOwnership: "ObjectWriter" }] },
208
+ BucketName: cloudfrontLogBucketName,
209
+ });
210
+ template.hasResourceProperties("Custom::S3AutoDeleteObjects", {
211
+ ServiceToken: {
212
+ "Fn::GetAtt": [
213
+ "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F",
214
+ "Arn"
215
+ ]
216
+ },
217
+ BucketName: {
218
+ Ref: "cloudfronts3CloudfrontLoggingBucket5B845143"
219
+ }
220
+ });
221
+ });
222
+ test('s3 bucket with one content bucket and no access logging of CONTENT bucket', () => {
223
+ const stack = new cdk.Stack();
224
+ const construct = new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
225
+ bucketProps: {
226
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
227
+ },
228
+ logS3AccessLogs: false
229
+ });
230
+ const template = assertions_1.Template.fromStack(stack);
231
+ // Content bucket+Cloudfront Logs bucket+
232
+ // Access Log bucket for Cloudfront Logs bucket = 3 buckets
233
+ template.resourceCountIs("AWS::S3::Bucket", 3);
234
+ expect(construct.s3LoggingBucket).toEqual(undefined);
235
+ });
236
+ test('CloudFront origin path present when provided', () => {
237
+ const stack = new cdk.Stack();
238
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
239
+ originPath: '/testPath'
240
+ });
241
+ const template = assertions_1.Template.fromStack(stack);
242
+ template.hasResourceProperties("AWS::CloudFront::Distribution", {
243
+ DistributionConfig: {
244
+ Origins: [
245
+ {
246
+ OriginPath: "/testPath",
247
+ }
248
+ ]
249
+ }
250
+ });
251
+ });
252
+ test('CloudFront origin path should not be present if not provided', () => {
253
+ const stack = new cdk.Stack();
254
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {});
255
+ defaults.expectNonexistence(stack, "AWS::CloudFront::Distribution", {
256
+ DistributionConfig: {
257
+ Origins: [
258
+ {
259
+ OriginPath: "/testPath",
260
+ }
261
+ ]
262
+ }
263
+ });
264
+ });
265
+ test('Test the deployment with securityHeadersBehavior instead of HTTP security headers', () => {
266
+ // Initial setup
267
+ const stack = new aws_cdk_lib_1.Stack();
268
+ const cloudFrontToS3 = new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {
269
+ insertHttpSecurityHeaders: false,
270
+ responseHeadersPolicyProps: {
271
+ securityHeadersBehavior: {
272
+ strictTransportSecurity: {
273
+ accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
274
+ includeSubdomains: true,
275
+ override: true,
276
+ preload: true
277
+ },
278
+ contentSecurityPolicy: {
279
+ contentSecurityPolicy: "upgrade-insecure-requests; default-src 'none';",
280
+ override: true
281
+ },
282
+ }
283
+ }
284
+ });
285
+ // Assertion
286
+ const template = assertions_1.Template.fromStack(stack);
287
+ template.hasResourceProperties("AWS::CloudFront::ResponseHeadersPolicy", {
288
+ ResponseHeadersPolicyConfig: {
289
+ SecurityHeadersConfig: {
290
+ ContentSecurityPolicy: {
291
+ ContentSecurityPolicy: "upgrade-insecure-requests; default-src 'none';",
292
+ Override: true
293
+ },
294
+ StrictTransportSecurity: {
295
+ AccessControlMaxAgeSec: 63072,
296
+ IncludeSubdomains: true,
297
+ Override: true,
298
+ Preload: true
299
+ }
300
+ }
301
+ }
302
+ });
303
+ expect(cloudFrontToS3.cloudFrontFunction).toEqual(undefined);
304
+ });
305
+ test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProps are provided", () => {
306
+ const stack = new cdk.Stack();
307
+ expect(() => {
308
+ new lib_1.CloudFrontToS3(stack, "test-cloudfront-s3", {
309
+ insertHttpSecurityHeaders: true,
310
+ responseHeadersPolicyProps: {
311
+ securityHeadersBehavior: {
312
+ strictTransportSecurity: {
313
+ accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
314
+ includeSubdomains: true,
315
+ override: false,
316
+ preload: true
317
+ }
318
+ }
319
+ }
320
+ });
321
+ }).toThrow();
322
+ });
323
+ test("Confirm CheckCloudFrontProps is being called", () => {
324
+ const stack = new cdk.Stack();
325
+ expect(() => {
326
+ new lib_1.CloudFrontToS3(stack, "test-cloudfront-apigateway", {
327
+ insertHttpSecurityHeaders: true,
328
+ responseHeadersPolicyProps: {
329
+ securityHeadersBehavior: {
330
+ strictTransportSecurity: {
331
+ accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
332
+ includeSubdomains: true,
333
+ override: false,
334
+ preload: true
335
+ }
336
+ }
337
+ }
338
+ });
339
+ }).toThrow('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.');
340
+ });
341
+ test("Custom resource is provisioned if encryption key is provided as bucketProp", () => {
342
+ const stack = new cdk.Stack();
343
+ const encryptionKey = new aws_kms_1.Key(stack, 'cmkKey', {
344
+ enableKeyRotation: true,
345
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY
346
+ });
347
+ deploy(stack, {
348
+ bucketProps: {
349
+ encryptionKey,
350
+ encryption: s3.BucketEncryption.KMS
351
+ }
352
+ });
353
+ const template = assertions_1.Template.fromStack(stack);
354
+ // 2 Functions - our custom resource and a function created by the CDK
355
+ template.resourceCountIs('AWS::Lambda::Function', 2);
356
+ template.hasResourceProperties('AWS::Lambda::Function', {
357
+ Description: "Custom resource function that updates a provided key policy to allow CloudFront access.",
358
+ Role: {
359
+ "Fn::GetAtt": ["testcloudfronts3LambdaFunctionServiceRole2A43EA92", "Arn"]
360
+ }
361
+ });
362
+ });
363
+ test("Custom resource is provisioned if CMK was used to encrypt an existing bucket", () => {
364
+ const stack = new cdk.Stack();
365
+ const encryptionKey = new aws_kms_1.Key(stack, 'cmkKey', {
366
+ enableKeyRotation: true,
367
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY
368
+ });
369
+ const existingBucketObj = defaults.buildS3Bucket(stack, {
370
+ bucketProps: {
371
+ encryption: s3.BucketEncryption.KMS,
372
+ encryptionKey
373
+ }
374
+ }, 'existing-s3-bucket-encrypted-with-cmk').bucket;
375
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {
376
+ existingBucketObj
377
+ });
378
+ const template = assertions_1.Template.fromStack(stack);
379
+ // 2 Functions - our custom resource and a function created by the CDK
380
+ template.resourceCountIs('AWS::Lambda::Function', 2);
381
+ // ensure that our Function has the correct role attached
382
+ template.hasResourceProperties('AWS::Lambda::Function', {
383
+ Description: "Custom resource function that updates a provided key policy to allow CloudFront access.",
384
+ Role: {
385
+ "Fn::GetAtt": ["testcloudfronts3LambdaFunctionServiceRole2A43EA92", "Arn"]
386
+ }
387
+ });
388
+ });
389
+ test("Custom resource is not provisioned if encryption key is not provided as bucketProp", () => {
390
+ const stack = new cdk.Stack();
391
+ deploy(stack);
392
+ const template = assertions_1.Template.fromStack(stack);
393
+ template.resourceCountIs('AWS::Lambda::Function', 0);
394
+ });
395
+ test("Custom resource is not provisioned if CMK was not used to encrypt an existing bucket", () => {
396
+ const stack = new cdk.Stack();
397
+ const existingBucketObj = defaults.buildS3Bucket(stack, {}, 'existing-s3-bucket-encrypted-with-cmk').bucket;
398
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {
399
+ existingBucketObj
400
+ });
401
+ const template = assertions_1.Template.fromStack(stack);
402
+ template.resourceCountIs('AWS::Lambda::Function', 0);
403
+ });
404
+ test("HttpOrigin is provisioned if a static website bucket is used", () => {
405
+ const stack = new cdk.Stack();
406
+ const blockPublicAccess = false;
407
+ const props = {
408
+ bucketProps: {
409
+ enforceSSL: false,
410
+ publicReadAccess: true, // <-- required for isWebsite
411
+ blockPublicAccess: {
412
+ blockPublicAcls: blockPublicAccess,
413
+ restrictPublicBuckets: blockPublicAccess,
414
+ blockPublicPolicy: blockPublicAccess,
415
+ ignorePublicAcls: blockPublicAccess
416
+ },
417
+ websiteIndexDocument: "index.html" // <-- required for isWebsite
418
+ },
419
+ insertHttpSecurityHeaders: false
420
+ };
421
+ const construct = new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', props);
422
+ const template = assertions_1.Template.fromStack(stack);
423
+ // Assert resources
424
+ template.resourceCountIs('AWS::CloudFront::OriginAccessControl', 0);
425
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
426
+ DistributionConfig: {
427
+ Origins: [
428
+ {
429
+ CustomOriginConfig: {
430
+ OriginProtocolPolicy: "http-only"
431
+ }
432
+ }
433
+ ]
434
+ }
435
+ });
436
+ template.resourceCountIs('AWS::CloudFront::OriginAccessIdentity', 0);
437
+ // Assert pattern properties (output props)
438
+ expect(construct.originAccessControl).toBe(undefined);
439
+ });
440
+ test("OAC is provisioned in all other cases", () => {
441
+ const stack = new cdk.Stack();
442
+ const construct = new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {});
443
+ const template = assertions_1.Template.fromStack(stack);
444
+ // Assert resources
445
+ template.resourceCountIs('AWS::CloudFront::OriginAccessControl', 1);
446
+ template.resourceCountIs('AWS::CloudFront::OriginAccessIdentity', 0);
447
+ // Assert pattern properties (output props)
448
+ expect(construct.originAccessControl).not.toBe(undefined);
449
+ });
450
+ test("If a customer provides their own httpOrigin, or other origin type, use that one", () => {
451
+ const stack = new cdk.Stack();
452
+ const blockPublicAccess = false;
453
+ const props = {
454
+ bucketProps: {
455
+ enforceSSL: false,
456
+ publicReadAccess: true, // <-- required for isWebsite
457
+ blockPublicAccess: {
458
+ blockPublicAcls: blockPublicAccess,
459
+ restrictPublicBuckets: blockPublicAccess,
460
+ blockPublicPolicy: blockPublicAccess,
461
+ ignorePublicAcls: blockPublicAccess
462
+ },
463
+ websiteIndexDocument: "index.html" // <-- required for isWebsite
464
+ },
465
+ insertHttpSecurityHeaders: false,
466
+ cloudFrontDistributionProps: {
467
+ defaultBehavior: {
468
+ origin: new origins.HttpOrigin('example.com', {
469
+ originId: 'custom-http-origin-for-testing'
470
+ })
471
+ }
472
+ }
473
+ };
474
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', props);
475
+ const template = assertions_1.Template.fromStack(stack);
476
+ // Assert resources
477
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
478
+ DistributionConfig: {
479
+ Origins: [
480
+ {
481
+ DomainName: "example.com",
482
+ Id: "custom-http-origin-for-testing"
483
+ }
484
+ ]
485
+ }
486
+ });
487
+ });
488
+ test('Test that we do not create an Access Log bucket for CF logs if one is provided', () => {
489
+ const stack = new cdk.Stack();
490
+ const cfS3AccessLogBucket = new s3.Bucket(stack, 'cf-s3-access-logs');
491
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {
492
+ cloudFrontLoggingBucketProps: {
493
+ serverAccessLogsBucket: cfS3AccessLogBucket
494
+ }
495
+ });
496
+ const template = assertions_1.Template.fromStack(stack);
497
+ template.resourceCountIs("AWS::S3::Bucket", 4);
498
+ });
499
+ // =====================
500
+ // S3 Content Bucket Access Logs Bucket
501
+ // =====================
502
+ test('Providing loggingBucketProps and existingLoggingBucket is an error', () => {
503
+ const stack = new cdk.Stack();
504
+ const logBucket = new s3.Bucket(stack, 'log-bucket', {});
505
+ const app = () => {
506
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
507
+ bucketProps: {
508
+ serverAccessLogsBucket: logBucket,
509
+ },
510
+ loggingBucketProps: {
511
+ bucketName: 'anything'
512
+ }
513
+ });
514
+ };
515
+ expect(app).toThrow(/Error - bothlog bucket props and an existing log bucket were provided.\n/);
516
+ });
517
+ test('Providing existingLoggingBucket and logS3AccessLogs=false is an error', () => {
518
+ const stack = new cdk.Stack();
519
+ const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
520
+ const app = () => {
521
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
522
+ bucketProps: {
523
+ serverAccessLogsBucket: logBucket,
524
+ },
525
+ logS3AccessLogs: false
526
+ });
527
+ };
528
+ expect(app).toThrow(/Error - logS3AccessLogs is false, but a log bucket was provided in bucketProps.\n/);
529
+ });
530
+ test('Providing loggingBucketProps and logS3AccessLogs=false is an error', () => {
531
+ const stack = new cdk.Stack();
532
+ const app = () => {
533
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
534
+ loggingBucketProps: {
535
+ bucketName: 'anything'
536
+ },
537
+ logS3AccessLogs: false
538
+ });
539
+ };
540
+ // NOTE: This error is thrown by CheckS3Props(), not CheckConstructSpecificProps()
541
+ expect(app).toThrow(/Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n/);
542
+ });
543
+ // test('No new loggingBucket is created if existingLoggingBucket is supplied', () => {
544
+ test('loggingBucketProps is supplied is integrated into architecture correctly', () => {
545
+ const stack = new cdk.Stack();
546
+ const testName = "test-name";
547
+ const construct = new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
548
+ bucketProps: {
549
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
550
+ },
551
+ loggingBucketProps: {
552
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
553
+ autoDeleteObjects: true,
554
+ bucketName: testName
555
+ }
556
+ });
557
+ expect(construct.s3LoggingBucket).toBeDefined();
558
+ const template = assertions_1.Template.fromStack(stack);
559
+ template.resourceCountIs("AWS::S3::Bucket", 4);
560
+ template.hasResourceProperties("AWS::S3::Bucket", {
561
+ BucketName: testName
562
+ });
563
+ template.hasResourceProperties("AWS::S3::Bucket", {
564
+ LoggingConfiguration: {
565
+ DestinationBucketName: {
566
+ Ref: "cloudfronts3S3LoggingBucket52EEB708"
567
+ }
568
+ }
569
+ });
570
+ });
571
+ test('bucketProps:serverAccessLogsBucket is supplied is integrated into architecture correctly', () => {
572
+ const testName = 'some-name';
573
+ const stack = new cdk.Stack();
574
+ const logBucket = new s3.Bucket(stack, 'test-log', {
575
+ bucketName: testName,
576
+ });
577
+ const construct = new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
578
+ bucketProps: {
579
+ serverAccessLogsBucket: logBucket,
580
+ },
581
+ });
582
+ expect(construct.s3LoggingBucket).toBeDefined();
583
+ const template = assertions_1.Template.fromStack(stack);
584
+ template.resourceCountIs("AWS::S3::Bucket", 4);
585
+ template.hasResourceProperties("AWS::S3::Bucket", {
586
+ LoggingConfiguration: {
587
+ DestinationBucketName: {
588
+ Ref: "testlogE88B4C6B"
589
+ }
590
+ }
591
+ });
592
+ });
593
+ // =====================
594
+ // CloudFront Log Bucket
595
+ // =====================
596
+ test('Providing cloudFrontLoggingBucketProps and a log bucket in cloudFrontDistrbutionProps is an error', () => {
597
+ const stack = new cdk.Stack();
598
+ const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
599
+ const app = () => {
600
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
601
+ cloudFrontDistributionProps: {
602
+ logBucket
603
+ },
604
+ cloudFrontLoggingBucketProps: {
605
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
606
+ autoDeleteObjects: true
607
+ }
608
+ });
609
+ };
610
+ expect(app).toThrow();
611
+ });
612
+ test('cloudFrontLoggingBucketProps are used correctly', () => {
613
+ const stack = new cdk.Stack();
614
+ const testName = "test-name";
615
+ const construct = new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
616
+ cloudFrontLoggingBucketProps: {
617
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
618
+ autoDeleteObjects: true,
619
+ bucketName: testName
620
+ }
621
+ });
622
+ expect(construct.cloudFrontLoggingBucket).toBeDefined();
623
+ const template = assertions_1.Template.fromStack(stack);
624
+ template.resourceCountIs("AWS::S3::Bucket", 4);
625
+ template.hasResourceProperties("AWS::S3::Bucket", {
626
+ BucketName: testName
627
+ });
628
+ });
629
+ test('Logging disabled in CloudFront props is handled correctly', () => {
630
+ const stack = new cdk.Stack();
631
+ const construct = deploy(stack, { cloudFrontDistributionProps: { enableLogging: false } });
632
+ const template = assertions_1.Template.fromStack(stack);
633
+ // Only the content bucket and it S3 Access Log bucket (no Cloudfront log bucket)
634
+ template.resourceCountIs("AWS::S3::Bucket", 2);
635
+ // No logging is configured
636
+ template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", {
637
+ DistributionConfig: {
638
+ Logging: assertions_1.Match.anyValue()
639
+ }
640
+ }, 0);
641
+ expect(construct.cloudFrontLoggingBucket === undefined);
642
+ });
643
+ test('No new CloudFrontLoggingBucket is created if cloudFrontLoggingBucketProps:logBucket is supplied', () => {
644
+ const testName = 'random-value';
645
+ const stack = new cdk.Stack();
646
+ const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {
647
+ bucketName: testName
648
+ });
649
+ // const construct =
650
+ const construct = new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
651
+ cloudFrontDistributionProps: {
652
+ logBucket
653
+ },
654
+ });
655
+ expect(construct.cloudFrontLoggingBucket).toBeDefined();
656
+ const template = assertions_1.Template.fromStack(stack);
657
+ // Content bucket, Content bucket S3 Access Log bucket, cloudfront log bucket
658
+ template.resourceCountIs("AWS::S3::Bucket", 3);
659
+ // Ensure our existing bucket has been used for cloudfront logging
660
+ template.hasResourceProperties("AWS::CloudFront::Distribution", {
661
+ DistributionConfig: {
662
+ Logging: {
663
+ Bucket: {
664
+ "Fn::GetAtt": [
665
+ "cloudfrontlogbucketDF7058FB",
666
+ "RegionalDomainName"
667
+ ]
668
+ }
669
+ }
670
+ }
671
+ });
672
+ });
673
+ // =====================
674
+ // CloudFront Logs Bucket Access Log Bucket
675
+ // =====================
676
+ test('Providing cloudFrontLoggingBucketAccessLogBucketProps and cloudFrontLoggingBucketProps:serverAccessLogsBucket is an error', () => {
677
+ const stack = new cdk.Stack();
678
+ const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
679
+ const app = () => {
680
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
681
+ cloudFrontLoggingBucketProps: {
682
+ serverAccessLogsBucket: logBucket,
683
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
684
+ autoDeleteObjects: true
685
+ },
686
+ cloudFrontLoggingBucketAccessLogBucketProps: {
687
+ bucketName: 'specfic-name-is-inconsequential'
688
+ }
689
+ });
690
+ };
691
+ expect(app).toThrow(/Error - an existing CloudFront log bucket S3 access log bucket and cloudFrontLoggingBucketAccessLogBucketProps were provided\n/);
692
+ });
693
+ test('Providing cloudFrontLoggingBucketAccessLogBucketProps and logCloudFrontAccessLog=false is an error', () => {
694
+ const stack = new cdk.Stack();
695
+ const app = () => {
696
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
697
+ logCloudFrontAccessLog: false,
698
+ cloudFrontLoggingBucketAccessLogBucketProps: {
699
+ bucketName: 'specfic-name-is-inconsequential'
700
+ }
701
+ });
702
+ };
703
+ expect(app).toThrow(/Error - cloudFrontLoggingBucketAccessLogBucketProps were provided but logCloudFrontAccessLog was false\n/);
704
+ });
705
+ test('Providing logCloudFrontAccessLog=false and cloudFrontLoggingBucketProps:serverAccessLogsBucket is an error', () => {
706
+ const stack = new cdk.Stack();
707
+ const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
708
+ const app = () => {
709
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
710
+ cloudFrontLoggingBucketProps: {
711
+ serverAccessLogsBucket: logBucket,
712
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
713
+ autoDeleteObjects: true
714
+ },
715
+ logCloudFrontAccessLog: false,
716
+ });
717
+ };
718
+ expect(app).toThrow(/Error - props.cloudFrontLoggingBucketProps.serverAccessLogsBucket was provided but logCloudFrontAccessLog was false\n/);
719
+ });
720
+ test('cloudFrontLoggingBucketAccessLogBucketProps are used correctly', () => {
721
+ const stack = new cdk.Stack();
722
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
723
+ cloudFrontLoggingBucketAccessLogBucketProps: {
724
+ websiteErrorDocument: 'placeholder',
725
+ websiteIndexDocument: 'placeholde-two'
726
+ }
727
+ });
728
+ const template = assertions_1.Template.fromStack(stack);
729
+ // Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
730
+ template.resourceCountIs("AWS::S3::Bucket", 4);
731
+ template.hasResourceProperties("AWS::S3::Bucket", {
732
+ WebsiteConfiguration: {
733
+ ErrorDocument: 'placeholder',
734
+ IndexDocument: 'placeholde-two'
735
+ }
736
+ });
737
+ });
738
+ test('If existing CloudFront Log bucket S3 Access Logging bucket is provided, it is used correctly', () => {
739
+ const stack = new cdk.Stack();
740
+ const testName = 'cf-log-s3-log';
741
+ const cfLogS3AccessLogBucket = new s3.Bucket(stack, 'cf-log-s3-access-log-bucket', {
742
+ bucketName: testName
743
+ });
744
+ new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
745
+ cloudFrontLoggingBucketProps: {
746
+ serverAccessLogsBucket: cfLogS3AccessLogBucket
747
+ }
748
+ });
749
+ const template = assertions_1.Template.fromStack(stack);
750
+ // Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
751
+ template.resourceCountIs("AWS::S3::Bucket", 4);
752
+ template.hasResourceProperties("AWS::S3::Bucket", {
753
+ BucketName: testName
754
+ });
755
+ template.hasResourceProperties("AWS::S3::Bucket", {
756
+ LoggingConfiguration: {
757
+ DestinationBucketName: {
758
+ Ref: "cflogs3accesslogbucketDE374C27"
759
+ }
760
+ }
761
+ });
762
+ });
763
+ test('cloudFrontLoggingBucketAccessLogBucket property is set correctly', () => {
764
+ const stack = new cdk.Stack();
765
+ const construct = new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
766
+ cloudFrontLoggingBucketAccessLogBucketProps: {
767
+ websiteErrorDocument: 'placeholder',
768
+ websiteIndexDocument: 'placeholde-two'
769
+ }
770
+ });
771
+ const template = assertions_1.Template.fromStack(stack);
772
+ // Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
773
+ template.resourceCountIs("AWS::S3::Bucket", 4);
774
+ template.hasResourceProperties("AWS::S3::Bucket", {
775
+ WebsiteConfiguration: {
776
+ ErrorDocument: 'placeholder',
777
+ IndexDocument: 'placeholde-two'
778
+ }
779
+ });
780
+ expect(construct.cloudFrontLoggingBucketAccessLogBucket).toBeDefined();
781
+ expect(construct.cloudFrontLoggingBucketAccessLogBucket.bucketName).toBeDefined();
782
+ });
783
+ test('logCloudFrontAccessLog property is used correctly', () => {
784
+ const stack = new cdk.Stack();
785
+ const construct = new lib_1.CloudFrontToS3(stack, 'cloudfront-s3', {
786
+ logCloudFrontAccessLog: false
787
+ });
788
+ const template = assertions_1.Template.fromStack(stack);
789
+ // Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
790
+ template.resourceCountIs("AWS::S3::Bucket", 3);
791
+ expect(construct.cloudFrontLoggingBucket).toBeDefined();
792
+ expect(construct.cloudFrontLoggingBucketAccessLogBucket).not.toBeDefined();
793
+ });
794
+ test('additionalBehaviors have correct origin', () => {
795
+ const stack = new cdk.Stack();
796
+ const additionalBucket = defaults.CreateScrapBucket(stack, "scrapBucket", {
797
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
798
+ autoDeleteObjects: true,
799
+ });
800
+ const originAccessControl = new aws_cloudfront_1.CfnOriginAccessControl(stack, 'CloudFrontOac', {
801
+ originAccessControlConfig: {
802
+ name: defaults.generatePhysicalOacName('aws-cloudfront-s3-', [__filename]),
803
+ originAccessControlOriginType: 's3',
804
+ signingBehavior: 'always',
805
+ signingProtocol: 'sigv4',
806
+ description: 'Origin access control provisioned by aws-cloudfront-s3'
807
+ }
808
+ });
809
+ const additionalOrigin = new defaults.S3OacOrigin(additionalBucket, {
810
+ originAccessControl
811
+ });
812
+ new lib_1.CloudFrontToS3(stack, 'test-cloudfront-s3', {
813
+ cloudFrontDistributionProps: {
814
+ additionalBehaviors: {
815
+ '/assets/public/*': {
816
+ origin: additionalOrigin,
817
+ cachePolicy: aws_cloudfront_1.CachePolicy.CACHING_DISABLED,
818
+ },
819
+ 'ngsw.json': {
820
+ cachePolicy: aws_cloudfront_1.CachePolicy.CACHING_DISABLED,
821
+ }
822
+ }
823
+ }
824
+ });
825
+ const template = assertions_1.Template.fromStack(stack);
826
+ template.hasResourceProperties("AWS::CloudFront::Distribution", {
827
+ DistributionConfig: {
828
+ CacheBehaviors: [
829
+ {
830
+ CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
831
+ Compress: true,
832
+ PathPattern: "/assets/public/*",
833
+ TargetOriginId: "testcloudfronts3CloudFrontDistributionOrigin21D78391C",
834
+ ViewerProtocolPolicy: "allow-all"
835
+ },
836
+ {
837
+ CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
838
+ Compress: true,
839
+ PathPattern: "ngsw.json",
840
+ TargetOriginId: "testcloudfronts3CloudFrontDistributionOrigin124051039",
841
+ ViewerProtocolPolicy: "allow-all"
842
+ }
843
+ ],
844
+ }
845
+ });
846
+ });
847
+ test('Test that ValidateDistributionProps() is being called', () => {
848
+ const stack = new aws_cdk_lib_1.Stack();
849
+ const props = {
850
+ cloudFrontDistributionProps: {
851
+ invalidProperty: true
852
+ }
853
+ };
854
+ const app = () => {
855
+ new lib_1.CloudFrontToS3(stack, 'test-construct', props);
856
+ };
857
+ expect(app).toThrow(/ERROR - invalidProperty is not a valid property of DistributionProps/);
858
+ });
859
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmcm9udC1zMy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2xvdWRmcm9udC1zMy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7R0FXRzs7QUFFSCx1REFBeUQ7QUFDekQseUNBQXlDO0FBQ3pDLG1DQUFtQztBQUNuQyw2Q0FBNkQ7QUFDN0QsZ0NBQTZEO0FBQzdELDBEQUEwRDtBQUMxRCwyREFBMkQ7QUFDM0QsaURBQTBDO0FBQzFDLDhEQUE4RDtBQUM5RCwrREFBaUY7QUFFakYsU0FBUyxNQUFNLENBQUMsS0FBZ0IsRUFBRSxLQUEyQjtJQUMzRCxPQUFPLElBQUksb0JBQWMsQ0FBQyxLQUFLLEVBQUUsb0JBQW9CLEVBQUU7UUFDckQsV0FBVyxFQUFFO1lBQ1gsYUFBYSxFQUFFLEdBQUcsQ0FBQyxhQUFhLENBQUMsT0FBTztTQUN6QztRQUNELEdBQUcsS0FBSztLQUNULENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxJQUFJLENBQUMsNkNBQTZDLEVBQUUsR0FBRyxFQUFFO0lBQ3ZELE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzlCLE1BQU0sU0FBUyxHQUFHLElBQUksb0JBQWMsQ0FBQyxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFdEUsTUFBTSxDQUFDLFNBQVMsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzFELE1BQU0sQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNuRCxNQUFNLENBQUMsU0FBUyxDQUFDLHVCQUF1QixDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDeEQsTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUN6QyxNQUFNLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxDQUFDLFdBQVcsRUFB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YyxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNyRCxDQUFDLENBQUM7SUFFRixNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLHNFQUFzRSxDQUFDLENBQUM7QUFDOUYsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqICBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKS4gWW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZVxuICogIHdpdGggdGhlIExpY2Vuc2UuIEEgY29weSBvZiB0aGUgTGljZW5zZSBpcyBsb2NhdGVkIGF0XG4gKlxuICogICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiAgb3IgaW4gdGhlICdsaWNlbnNlJyBmaWxlIGFjY29tcGFueWluZyB0aGlzIGZpbGUuIFRoaXMgZmlsZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAnQVMgSVMnIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVNcbiAqICBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBleHByZXNzIG9yIGltcGxpZWQuIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xuICogIGFuZCBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5pbXBvcnQgeyBNYXRjaCwgVGVtcGxhdGUgfSBmcm9tIFwiYXdzLWNkay1saWIvYXNzZXJ0aW9uc1wiO1xuaW1wb3J0ICogYXMgczMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCAqIGFzIGNkayBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IER1cmF0aW9uLCBSZW1vdmFsUG9saWN5LCBTdGFjayB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgQ2xvdWRGcm9udFRvUzMsIENsb3VkRnJvbnRUb1MzUHJvcHMgfSBmcm9tIFwiLi4vbGliXCI7XG5pbXBvcnQgKiBhcyBhY20gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNlcnRpZmljYXRlbWFuYWdlcic7XG5pbXBvcnQgKiBhcyBkZWZhdWx0cyBmcm9tICdAYXdzLXNvbHV0aW9ucy1jb25zdHJ1Y3RzL2NvcmUnO1xuaW1wb3J0IHsgS2V5IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1rbXNcIjtcbmltcG9ydCAqIGFzIG9yaWdpbnMgZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnQtb3JpZ2lucyc7XG5pbXBvcnQgeyBDYWNoZVBvbGljeSwgQ2ZuT3JpZ2luQWNjZXNzQ29udHJvbCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udFwiO1xuXG5mdW5jdGlvbiBkZXBsb3koc3RhY2s6IGNkay5TdGFjaywgcHJvcHM/OiBDbG91ZEZyb250VG9TM1Byb3BzKSB7XG4gIHJldHVybiBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtczMnLCB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSxcbiAgICAuLi5wcm9wc1xuICB9KTtcbn1cblxudGVzdCgnY29uc3RydWN0IGRlZmF1bHRzIHNldCBwcm9wZXJ0aWVzIGNvcnJlY3RseScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1zMycsIHt9KTtcblxuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRXZWJEaXN0cmlidXRpb24pLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udEZ1bmN0aW9uKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LnMzQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LnMzTG9nZ2luZ0J1Y2tldCkudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0J1Y2tldEludGVyZmFjZSkudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldCkudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5vcmlnaW5BY2Nlc3NDb250cm9sKS50b0JlRGVmaW5lZCgpO1xufSk7XG5cbnRlc3QoJ2NoZWNrIHMzQnVja2V0IGRlZmF1bHQgZW5jcnlwdGlvbicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGRlcGxveShzdGFjayk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgQnVja2V0RW5jcnlwdGlvbjoge1xuICAgICAgU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uOiBbe1xuICAgICAgICBTZXJ2ZXJTaWRlRW5jcnlwdGlvbkJ5RGVmYXVsdDoge1xuICAgICAgICAgIFNTRUFsZ29yaXRobTogXCJBRVMyNTZcIlxuICAgICAgICB9XG4gICAgICB9XVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnY2hlY2sgczNCdWNrZXQgcHVibGljIGFjY2VzcyBibG9jayBjb25maWd1cmF0aW9uJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgZGVwbG95KHN0YWNrKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6UzM6OkJ1Y2tldCcsIHtcbiAgICBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246IHtcbiAgICAgIEJsb2NrUHVibGljQWNsczogdHJ1ZSxcbiAgICAgIEJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgSWdub3JlUHVibGljQWNsczogdHJ1ZSxcbiAgICAgIFJlc3RyaWN0UHVibGljQnVja2V0czogdHJ1ZVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgndGVzdCBzM0J1Y2tldCBvdmVycmlkZSBwdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb24nLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IHByb3BzOiBDbG91ZEZyb250VG9TM1Byb3BzID0ge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICBibG9ja1B1YmxpY0FjY2Vzczoge1xuICAgICAgICBibG9ja1B1YmxpY0FjbHM6IGZhbHNlLFxuICAgICAgICBibG9ja1B1YmxpY1BvbGljeTogdHJ1ZSxcbiAgICAgICAgaWdub3JlUHVibGljQWNsczogZmFsc2UsXG4gICAgICAgIHJlc3RyaWN0UHVibGljQnVja2V0czogdHJ1ZVxuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtczMnLCBwcm9wcyk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjoge1xuICAgICAgQmxvY2tQdWJsaWNBY2xzOiBmYWxzZSxcbiAgICAgIEJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgSWdub3JlUHVibGljQWNsczogZmFsc2UsXG4gICAgICBSZXN0cmljdFB1YmxpY0J1Y2tldHM6IHRydWVcbiAgICB9LFxuICB9KTtcbn0pO1xuXG50ZXN0KCdjaGVjayBleGlzdGluZyBidWNrZXQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGV4aXN0aW5nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ215LWJ1Y2tldCcsIHtcbiAgICBidWNrZXROYW1lOiAnbXktYnVja2V0J1xuICB9KTtcblxuICBjb25zdCBwcm9wczogQ2xvdWRGcm9udFRvUzNQcm9wcyA9IHtcbiAgICBleGlzdGluZ0J1Y2tldE9iajogZXhpc3RpbmdCdWNrZXRcbiAgfTtcblxuICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtczMnLCBwcm9wcyk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIEJ1Y2tldE5hbWU6IFwibXktYnVja2V0XCJcbiAgfSk7XG59KTtcblxudGVzdCgnY2hlY2sgZXhjZXB0aW9uIGZvciBNaXNzaW5nIGV4aXN0aW5nT2JqIGZyb20gcHJvcHMgZm9yIGRlcGxveSA9IGZhbHNlJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICB0cnkge1xuICAgIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1zMycsIHt9KTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGV4cGVjdChlKS50b0JlSW5zdGFuY2VPZihFcnJvcik7XG4gIH1cbn0pO1xuXG50ZXN0KCdjaGVjayBwcm9wZXJ0aWVzJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBjb25zdHJ1Y3Q6IENsb3VkRnJvbnRUb1MzID0gZGVwbG95KHN0YWNrKTtcblxuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRXZWJEaXN0cmlidXRpb24pLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuczNCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG59KTtcblxudGVzdChcIkNvbmZpcm0gQ2hlY2tTM1Byb3BzIGlzIGNhbGxlZFwiLCAoKSA9PiB7XG4gIC8vIFN0YWNrXG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IHRlc3RCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAndGVzdC1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIC8vIEhlbHBlciBkZWNsYXJhdGlvblxuICAgIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgXCJiYWQtczMtYXJnc1wiLCB7XG4gICAgICBleGlzdGluZ0J1Y2tldE9iajogdGVzdEJ1Y2tldCxcbiAgICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuREVTVFJPWVxuICAgICAgfSxcbiAgICB9KTtcbiAgfTtcbiAgLy8gQXNzZXJ0aW9uXG4gIGV4cGVjdChhcHApLnRvVGhyb3coJ0Vycm9yIC0gRWl0aGVyIHByb3ZpZGUgYnVja2V0UHJvcHMgb3IgZXhpc3RpbmdCdWNrZXRPYmosIGJ1dCBub3QgYm90aC5cXG4nKTtcbn0pO1xuXG50ZXN0KFwiVGVzdCBleGlzdGluZ0J1Y2tldE9ialwiLCAoKSA9PiB7XG4gIC8vIFN0YWNrXG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBjb25zdHJ1Y3Q6IENsb3VkRnJvbnRUb1MzID0gbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCBcImV4aXN0aW5nSUJ1Y2tldFwiLCB7XG4gICAgZXhpc3RpbmdCdWNrZXRPYmo6IHMzLkJ1Y2tldC5mcm9tQnVja2V0TmFtZShzdGFjaywgJ215YnVja2V0JywgJ215YnVja2V0JylcbiAgfSk7XG4gIC8vIEFzc2VydGlvblxuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRXZWJEaXN0cmlidXRpb24pLnRvQmVEZWZpbmVkKCk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgT3JpZ2luczogW1xuICAgICAgICB7XG4gICAgICAgICAgRG9tYWluTmFtZToge1xuICAgICAgICAgICAgXCJGbjo6Sm9pblwiOiBbXG4gICAgICAgICAgICAgIFwiXCIsXG4gICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICBcIm15YnVja2V0LnMzLlwiLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIFJlZjogXCJBV1M6OlJlZ2lvblwiXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBcIi5cIixcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBSZWY6IFwiQVdTOjpVUkxTdWZmaXhcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0sXG4gICAgICAgICAgSWQ6IFwiZXhpc3RpbmdJQnVja2V0Q2xvdWRGcm9udERpc3RyaWJ1dGlvbk9yaWdpbjFENTg0OTEyNVwiLFxuICAgICAgICAgIE9yaWdpbkFjY2Vzc0NvbnRyb2xJZDogeyBcIkZuOjpHZXRBdHRcIjogW1wiZXhpc3RpbmdJQnVja2V0Q2xvdWRGcm9udE9hY0VCNDJFOThGXCIsIFwiSWRcIl0gfSxcbiAgICAgICAgICBTM09yaWdpbkNvbmZpZzoge31cbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgndGVzdCBjbG91ZGZyb250IHdpdGggY3VzdG9tIGRvbWFpbiBuYW1lcycsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgY2VydGlmaWNhdGUgPSBhY20uQ2VydGlmaWNhdGUuZnJvbUNlcnRpZmljYXRlQXJuKHN0YWNrLCAnQ2VydCcsICdhcm46JHtBd3MuUEFSVElUSU9OfTphY206dXMtZWFzdC0xOjEyMzQ1Njc4OTAxMjpjZXJ0aWZpY2F0ZS8xMTExMjIyMi0zMzMzLTEyMzQtMTIzNC0xMjM0NTY3ODkwMTInKTtcblxuICBjb25zdCBwcm9wczogQ2xvdWRGcm9udFRvUzNQcm9wcyA9IHtcbiAgICBjbG91ZEZyb250RGlzdHJpYnV0aW9uUHJvcHM6IHtcbiAgICAgIGRvbWFpbk5hbWVzOiBbJ215ZG9tYWlucyddLFxuICAgICAgY2VydGlmaWNhdGVcbiAgICB9XG4gIH07XG5cbiAgbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LXMzJywgcHJvcHMpO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgQWxpYXNlczogW1xuICAgICAgICBcIm15ZG9tYWluc1wiXG4gICAgICBdXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCdDbG91ZGZyb250IGxvZ2dpbmcgYnVja2V0IHdpdGggZGVzdHJveSByZW1vdmFsIHBvbGljeSBhbmQgYXV0byBkZWxldGUgb2JqZWN0cycsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgY2xvdWRmcm9udExvZ0J1Y2tldE5hbWUgPSAnY2YtbG9nLWJ1Y2tldCc7XG4gIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlLFxuICAgICAgYnVja2V0TmFtZTogY2xvdWRmcm9udExvZ0J1Y2tldE5hbWVcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBPd25lcnNoaXBDb250cm9sczogeyBSdWxlczogW3sgT2JqZWN0T3duZXJzaGlwOiBcIk9iamVjdFdyaXRlclwiIH1dIH0sXG4gICAgQnVja2V0TmFtZTogY2xvdWRmcm9udExvZ0J1Y2tldE5hbWUsXG4gIH0pO1xuXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkN1c3RvbTo6UzNBdXRvRGVsZXRlT2JqZWN0c1wiLCB7XG4gICAgU2VydmljZVRva2VuOiB7XG4gICAgICBcIkZuOjpHZXRBdHRcIjogW1xuICAgICAgICBcIkN1c3RvbVMzQXV0b0RlbGV0ZU9iamVjdHNDdXN0b21SZXNvdXJjZVByb3ZpZGVySGFuZGxlcjlEOTAxODRGXCIsXG4gICAgICAgIFwiQXJuXCJcbiAgICAgIF1cbiAgICB9LFxuICAgIEJ1Y2tldE5hbWU6IHtcbiAgICAgIFJlZjogXCJjbG91ZGZyb250czNDbG91ZGZyb250TG9nZ2luZ0J1Y2tldDVCODQ1MTQzXCJcbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoJ3MzIGJ1Y2tldCB3aXRoIG9uZSBjb250ZW50IGJ1Y2tldCBhbmQgbm8gYWNjZXNzIGxvZ2dpbmcgb2YgQ09OVEVOVCBidWNrZXQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSxcbiAgICBsb2dTM0FjY2Vzc0xvZ3M6IGZhbHNlXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgLy8gQ29udGVudCBidWNrZXQrQ2xvdWRmcm9udCBMb2dzIGJ1Y2tldCtcbiAgLy8gQWNjZXNzIExvZyBidWNrZXQgZm9yIENsb3VkZnJvbnQgTG9ncyBidWNrZXQgPSAzIGJ1Y2tldHNcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDMpO1xuICBleHBlY3QoY29uc3RydWN0LnMzTG9nZ2luZ0J1Y2tldCkudG9FcXVhbCh1bmRlZmluZWQpO1xufSk7XG5cbnRlc3QoJ0Nsb3VkRnJvbnQgb3JpZ2luIHBhdGggcHJlc2VudCB3aGVuIHByb3ZpZGVkJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICdjbG91ZGZyb250LXMzJywge1xuICAgIG9yaWdpblBhdGg6ICcvdGVzdFBhdGgnXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzpcbiAgICB7XG4gICAgICBPcmlnaW5zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBPcmlnaW5QYXRoOiBcIi90ZXN0UGF0aFwiLFxuICAgICAgICB9XG4gICAgICBdXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCdDbG91ZEZyb250IG9yaWdpbiBwYXRoIHNob3VsZCBub3QgYmUgcHJlc2VudCBpZiBub3QgcHJvdmlkZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7fSk7XG5cbiAgZGVmYXVsdHMuZXhwZWN0Tm9uZXhpc3RlbmNlKHN0YWNrLCBcIkFXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uXCIsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6XG4gICAge1xuICAgICAgT3JpZ2luczogW1xuICAgICAgICB7XG4gICAgICAgICAgT3JpZ2luUGF0aDogXCIvdGVzdFBhdGhcIixcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnVGVzdCB0aGUgZGVwbG95bWVudCB3aXRoIHNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yIGluc3RlYWQgb2YgSFRUUCBzZWN1cml0eSBoZWFkZXJzJywgKCkgPT4ge1xuICAvLyBJbml0aWFsIHNldHVwXG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG4gIGNvbnN0IGNsb3VkRnJvbnRUb1MzID0gbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LXMzJywge1xuICAgIGluc2VydEh0dHBTZWN1cml0eUhlYWRlcnM6IGZhbHNlLFxuICAgIHJlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzOiB7XG4gICAgICBzZWN1cml0eUhlYWRlcnNCZWhhdmlvcjoge1xuICAgICAgICBzdHJpY3RUcmFuc3BvcnRTZWN1cml0eToge1xuICAgICAgICAgIGFjY2Vzc0NvbnRyb2xNYXhBZ2U6IER1cmF0aW9uLnNlY29uZHMoNjMwNzIpLFxuICAgICAgICAgIGluY2x1ZGVTdWJkb21haW5zOiB0cnVlLFxuICAgICAgICAgIG92ZXJyaWRlOiB0cnVlLFxuICAgICAgICAgIHByZWxvYWQ6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAgY29udGVudFNlY3VyaXR5UG9saWN5OiB7XG4gICAgICAgICAgY29udGVudFNlY3VyaXR5UG9saWN5OiBcInVwZ3JhZGUtaW5zZWN1cmUtcmVxdWVzdHM7IGRlZmF1bHQtc3JjICdub25lJztcIixcbiAgICAgICAgICBvdmVycmlkZTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgLy8gQXNzZXJ0aW9uXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpSZXNwb25zZUhlYWRlcnNQb2xpY3lcIiwge1xuICAgIFJlc3BvbnNlSGVhZGVyc1BvbGljeUNvbmZpZzoge1xuICAgICAgU2VjdXJpdHlIZWFkZXJzQ29uZmlnOiB7XG4gICAgICAgIENvbnRlbnRTZWN1cml0eVBvbGljeToge1xuICAgICAgICAgIENvbnRlbnRTZWN1cml0eVBvbGljeTogXCJ1cGdyYWRlLWluc2VjdXJlLXJlcXVlc3RzOyBkZWZhdWx0LXNyYyAnbm9uZSc7XCIsXG4gICAgICAgICAgT3ZlcnJpZGU6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAgU3RyaWN0VHJhbnNwb3J0U2VjdXJpdHk6IHtcbiAgICAgICAgICBBY2Nlc3NDb250cm9sTWF4QWdlU2VjOiA2MzA3MixcbiAgICAgICAgICBJbmNsdWRlU3ViZG9tYWluczogdHJ1ZSxcbiAgICAgICAgICBPdmVycmlkZTogdHJ1ZSxcbiAgICAgICAgICBQcmVsb2FkOiB0cnVlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuICBleHBlY3QoY2xvdWRGcm9udFRvUzMuY2xvdWRGcm9udEZ1bmN0aW9uKS50b0VxdWFsKHVuZGVmaW5lZCk7XG59KTtcblxudGVzdChcInRocm93IGV4Y2VwdGlvbiBpZiBpbnNlcnRIdHRwU2VjdXJpdHlIZWFkZXJzIGFuZCByZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcyBhcmUgcHJvdmlkZWRcIiwgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBleHBlY3QoKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgXCJ0ZXN0LWNsb3VkZnJvbnQtczNcIiwge1xuICAgICAgaW5zZXJ0SHR0cFNlY3VyaXR5SGVhZGVyczogdHJ1ZSxcbiAgICAgIHJlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzOiB7XG4gICAgICAgIHNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yOiB7XG4gICAgICAgICAgc3RyaWN0VHJhbnNwb3J0U2VjdXJpdHk6IHtcbiAgICAgICAgICAgIGFjY2Vzc0NvbnRyb2xNYXhBZ2U6IER1cmF0aW9uLnNlY29uZHMoNjMwNzIpLFxuICAgICAgICAgICAgaW5jbHVkZVN1YmRvbWFpbnM6IHRydWUsXG4gICAgICAgICAgICBvdmVycmlkZTogZmFsc2UsXG4gICAgICAgICAgICBwcmVsb2FkOiB0cnVlXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH0pLnRvVGhyb3coKTtcbn0pO1xuXG50ZXN0KFwiQ29uZmlybSBDaGVja0Nsb3VkRnJvbnRQcm9wcyBpcyBiZWluZyBjYWxsZWRcIiwgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBleHBlY3QoKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgXCJ0ZXN0LWNsb3VkZnJvbnQtYXBpZ2F0ZXdheVwiLCB7XG4gICAgICBpbnNlcnRIdHRwU2VjdXJpdHlIZWFkZXJzOiB0cnVlLFxuICAgICAgcmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM6IHtcbiAgICAgICAgc2VjdXJpdHlIZWFkZXJzQmVoYXZpb3I6IHtcbiAgICAgICAgICBzdHJpY3RUcmFuc3BvcnRTZWN1cml0eToge1xuICAgICAgICAgICAgYWNjZXNzQ29udHJvbE1heEFnZTogRHVyYXRpb24uc2Vjb25kcyg2MzA3MiksXG4gICAgICAgICAgICBpbmNsdWRlU3ViZG9tYWluczogdHJ1ZSxcbiAgICAgICAgICAgIG92ZXJyaWRlOiBmYWxzZSxcbiAgICAgICAgICAgIHByZWxvYWQ6IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfSkudG9UaHJvdygncmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHMuc2VjdXJpdHlIZWFkZXJzQmVoYXZpb3IgY2FuIG9ubHkgYmUgcGFzc2VkIGlmIGh0dHBTZWN1cml0eUhlYWRlcnMgaXMgc2V0IHRvIGBmYWxzZWAuJyk7XG59KTtcblxudGVzdChcIkN1c3RvbSByZXNvdXJjZSBpcyBwcm92aXNpb25lZCBpZiBlbmNyeXB0aW9uIGtleSBpcyBwcm92aWRlZCBhcyBidWNrZXRQcm9wXCIsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGVuY3J5cHRpb25LZXkgPSBuZXcgS2V5KHN0YWNrLCAnY21rS2V5Jywge1xuICAgIGVuYWJsZUtleVJvdGF0aW9uOiB0cnVlLFxuICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuREVTVFJPWVxuICB9KTtcbiAgZGVwbG95KHN0YWNrLCB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICBlbmNyeXB0aW9uOiBzMy5CdWNrZXRFbmNyeXB0aW9uLktNU1xuICAgIH1cbiAgfSk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgLy8gMiBGdW5jdGlvbnMgLSBvdXIgY3VzdG9tIHJlc291cmNlIGFuZCBhIGZ1bmN0aW9uIGNyZWF0ZWQgYnkgdGhlIENES1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsIDIpO1xuXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJywge1xuICAgIERlc2NyaXB0aW9uOiBcIkN1c3RvbSByZXNvdXJjZSBmdW5jdGlvbiB0aGF0IHVwZGF0ZXMgYSBwcm92aWRlZCBrZXkgcG9saWN5IHRvIGFsbG93IENsb3VkRnJvbnQgYWNjZXNzLlwiLFxuICAgIFJvbGU6IHtcbiAgICAgIFwiRm46OkdldEF0dFwiOiBbXCJ0ZXN0Y2xvdWRmcm9udHMzTGFtYmRhRnVuY3Rpb25TZXJ2aWNlUm9sZTJBNDNFQTkyXCIsIFwiQXJuXCJdXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KFwiQ3VzdG9tIHJlc291cmNlIGlzIHByb3Zpc2lvbmVkIGlmIENNSyB3YXMgdXNlZCB0byBlbmNyeXB0IGFuIGV4aXN0aW5nIGJ1Y2tldFwiLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBlbmNyeXB0aW9uS2V5ID0gbmV3IEtleShzdGFjaywgJ2Nta0tleScsIHtcbiAgICBlbmFibGVLZXlSb3RhdGlvbjogdHJ1ZSxcbiAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1lcbiAgfSk7XG4gIGNvbnN0IGV4aXN0aW5nQnVja2V0T2JqID0gZGVmYXVsdHMuYnVpbGRTM0J1Y2tldChzdGFjaywge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICBlbmNyeXB0aW9uOiBzMy5CdWNrZXRFbmNyeXB0aW9uLktNUyxcbiAgICAgIGVuY3J5cHRpb25LZXlcbiAgICB9XG4gIH0sICdleGlzdGluZy1zMy1idWNrZXQtZW5jcnlwdGVkLXdpdGgtY21rJykuYnVja2V0O1xuICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtczMnLCB7XG4gICAgZXhpc3RpbmdCdWNrZXRPYmpcbiAgfSk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgLy8gMiBGdW5jdGlvbnMgLSBvdXIgY3VzdG9tIHJlc291cmNlIGFuZCBhIGZ1bmN0aW9uIGNyZWF0ZWQgYnkgdGhlIENES1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsIDIpO1xuXG4gIC8vIGVuc3VyZSB0aGF0IG91ciBGdW5jdGlvbiBoYXMgdGhlIGNvcnJlY3Qgcm9sZSBhdHRhY2hlZFxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsIHtcbiAgICBEZXNjcmlwdGlvbjogXCJDdXN0b20gcmVzb3VyY2UgZnVuY3Rpb24gdGhhdCB1cGRhdGVzIGEgcHJvdmlkZWQga2V5IHBvbGljeSB0byBhbGxvdyBDbG91ZEZyb250IGFjY2Vzcy5cIixcbiAgICBSb2xlOiB7XG4gICAgICBcIkZuOjpHZXRBdHRcIjogW1widGVzdGNsb3VkZnJvbnRzM0xhbWJkYUZ1bmN0aW9uU2VydmljZVJvbGUyQTQzRUE5MlwiLCBcIkFyblwiXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdChcIkN1c3RvbSByZXNvdXJjZSBpcyBub3QgcHJvdmlzaW9uZWQgaWYgZW5jcnlwdGlvbiBrZXkgaXMgbm90IHByb3ZpZGVkIGFzIGJ1Y2tldFByb3BcIiwgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgZGVwbG95KHN0YWNrKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsIDApO1xufSk7XG5cbnRlc3QoXCJDdXN0b20gcmVzb3VyY2UgaXMgbm90IHByb3Zpc2lvbmVkIGlmIENNSyB3YXMgbm90IHVzZWQgdG8gZW5jcnlwdCBhbiBleGlzdGluZyBidWNrZXRcIiwgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgZXhpc3RpbmdCdWNrZXRPYmogPSBkZWZhdWx0cy5idWlsZFMzQnVja2V0KHN0YWNrLCB7fSwgJ2V4aXN0aW5nLXMzLWJ1Y2tldC1lbmNyeXB0ZWQtd2l0aC1jbWsnKS5idWNrZXQ7XG4gIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1zMycsIHtcbiAgICBleGlzdGluZ0J1Y2tldE9ialxuICB9KTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsIDApO1xufSk7XG5cbnRlc3QoXCJIdHRwT3JpZ2luIGlzIHByb3Zpc2lvbmVkIGlmIGEgc3RhdGljIHdlYnNpdGUgYnVja2V0IGlzIHVzZWRcIiwgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgYmxvY2tQdWJsaWNBY2Nlc3MgPSBmYWxzZTtcbiAgY29uc3QgcHJvcHM6IENsb3VkRnJvbnRUb1MzUHJvcHMgPSB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIGVuZm9yY2VTU0w6IGZhbHNlLFxuICAgICAgcHVibGljUmVhZEFjY2VzczogdHJ1ZSwgLy8gPC0tIHJlcXVpcmVkIGZvciBpc1dlYnNpdGVcbiAgICAgIGJsb2NrUHVibGljQWNjZXNzOiB7XG4gICAgICAgIGJsb2NrUHVibGljQWNsczogYmxvY2tQdWJsaWNBY2Nlc3MsXG4gICAgICAgIHJlc3RyaWN0UHVibGljQnVja2V0czogYmxvY2tQdWJsaWNBY2Nlc3MsXG4gICAgICAgIGJsb2NrUHVibGljUG9saWN5OiBibG9ja1B1YmxpY0FjY2VzcyxcbiAgICAgICAgaWdub3JlUHVibGljQWNsczogYmxvY2tQdWJsaWNBY2Nlc3NcbiAgICAgIH0sXG4gICAgICB3ZWJzaXRlSW5kZXhEb2N1bWVudDogXCJpbmRleC5odG1sXCIgLy8gPC0tIHJlcXVpcmVkIGZvciBpc1dlYnNpdGVcbiAgICB9LFxuICAgIGluc2VydEh0dHBTZWN1cml0eUhlYWRlcnM6IGZhbHNlXG4gIH07XG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1zMycsIHByb3BzKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICAvLyBBc3NlcnQgcmVzb3VyY2VzXG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcygnQVdTOjpDbG91ZEZyb250OjpPcmlnaW5BY2Nlc3NDb250cm9sJywgMCk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb24nLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBPcmlnaW5zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBDdXN0b21PcmlnaW5Db25maWc6IHtcbiAgICAgICAgICAgIE9yaWdpblByb3RvY29sUG9saWN5OiBcImh0dHAtb25seVwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdXG4gICAgfVxuICB9KTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKCdBV1M6OkNsb3VkRnJvbnQ6Ok9yaWdpbkFjY2Vzc0lkZW50aXR5JywgMCk7XG4gIC8vIEFzc2VydCBwYXR0ZXJuIHByb3BlcnRpZXMgKG91dHB1dCBwcm9wcylcbiAgZXhwZWN0KGNvbnN0cnVjdC5vcmlnaW5BY2Nlc3NDb250cm9sKS50b0JlKHVuZGVmaW5lZCk7XG59KTtcblxudGVzdChcIk9BQyBpcyBwcm92aXNpb25lZCBpbiBhbGwgb3RoZXIgY2FzZXNcIiwgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgY29uc3RydWN0ID0gbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LXMzJywge30pO1xuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIC8vIEFzc2VydCByZXNvdXJjZXNcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKCdBV1M6OkNsb3VkRnJvbnQ6Ok9yaWdpbkFjY2Vzc0NvbnRyb2wnLCAxKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKCdBV1M6OkNsb3VkRnJvbnQ6Ok9yaWdpbkFjY2Vzc0lkZW50aXR5JywgMCk7XG4gIC8vIEFzc2VydCBwYXR0ZXJuIHByb3BlcnRpZXMgKG91dHB1dCBwcm9wcylcbiAgZXhwZWN0KGNvbnN0cnVjdC5vcmlnaW5BY2Nlc3NDb250cm9sKS5ub3QudG9CZSh1bmRlZmluZWQpO1xufSk7XG5cbnRlc3QoXCJJZiBhIGN1c3RvbWVyIHByb3ZpZGVzIHRoZWlyIG93biBodHRwT3JpZ2luLCBvciBvdGhlciBvcmlnaW4gdHlwZSwgdXNlIHRoYXQgb25lXCIsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGJsb2NrUHVibGljQWNjZXNzID0gZmFsc2U7XG4gIGNvbnN0IHByb3BzOiBDbG91ZEZyb250VG9TM1Byb3BzID0ge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICBlbmZvcmNlU1NMOiBmYWxzZSxcbiAgICAgIHB1YmxpY1JlYWRBY2Nlc3M6IHRydWUsIC8vIDwtLSByZXF1aXJlZCBmb3IgaXNXZWJzaXRlXG4gICAgICBibG9ja1B1YmxpY0FjY2Vzczoge1xuICAgICAgICBibG9ja1B1YmxpY0FjbHM6IGJsb2NrUHVibGljQWNjZXNzLFxuICAgICAgICByZXN0cmljdFB1YmxpY0J1Y2tldHM6IGJsb2NrUHVibGljQWNjZXNzLFxuICAgICAgICBibG9ja1B1YmxpY1BvbGljeTogYmxvY2tQdWJsaWNBY2Nlc3MsXG4gICAgICAgIGlnbm9yZVB1YmxpY0FjbHM6IGJsb2NrUHVibGljQWNjZXNzXG4gICAgICB9LFxuICAgICAgd2Vic2l0ZUluZGV4RG9jdW1lbnQ6IFwiaW5kZXguaHRtbFwiIC8vIDwtLSByZXF1aXJlZCBmb3IgaXNXZWJzaXRlXG4gICAgfSxcbiAgICBpbnNlcnRIdHRwU2VjdXJpdHlIZWFkZXJzOiBmYWxzZSxcbiAgICBjbG91ZEZyb250RGlzdHJpYnV0aW9uUHJvcHM6IHtcbiAgICAgIGRlZmF1bHRCZWhhdmlvcjoge1xuICAgICAgICBvcmlnaW46IG5ldyBvcmlnaW5zLkh0dHBPcmlnaW4oJ2V4YW1wbGUuY29tJywge1xuICAgICAgICAgIG9yaWdpbklkOiAnY3VzdG9tLWh0dHAtb3JpZ2luLWZvci10ZXN0aW5nJ1xuICAgICAgICB9KVxuICAgICAgfVxuICAgIH1cbiAgfTtcbiAgbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LXMzJywgcHJvcHMpO1xuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIC8vIEFzc2VydCByZXNvdXJjZXNcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvbicsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6IHtcbiAgICAgIE9yaWdpbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIERvbWFpbk5hbWU6IFwiZXhhbXBsZS5jb21cIixcbiAgICAgICAgICBJZDogXCJjdXN0b20taHR0cC1vcmlnaW4tZm9yLXRlc3RpbmdcIlxuICAgICAgICB9XG4gICAgICBdXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCdUZXN0IHRoYXQgd2UgZG8gbm90IGNyZWF0ZSBhbiBBY2Nlc3MgTG9nIGJ1Y2tldCBmb3IgQ0YgbG9ncyBpZiBvbmUgaXMgcHJvdmlkZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBjZlMzQWNjZXNzTG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ2NmLXMzLWFjY2Vzcy1sb2dzJyk7XG4gIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1zMycsIHtcbiAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBjZlMzQWNjZXNzTG9nQnVja2V0XG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCA0KTtcblxufSk7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PVxuLy8gUzMgQ29udGVudCBCdWNrZXQgQWNjZXNzIExvZ3MgQnVja2V0XG4vLyA9PT09PT09PT09PT09PT09PT09PT1cbnRlc3QoJ1Byb3ZpZGluZyBsb2dnaW5nQnVja2V0UHJvcHMgYW5kIGV4aXN0aW5nTG9nZ2luZ0J1Y2tldCBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdsb2ctYnVja2V0Jywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICdjbG91ZGZyb250LXMzJywge1xuICAgICAgYnVja2V0UHJvcHM6IHtcbiAgICAgICAgc2VydmVyQWNjZXNzTG9nc0J1Y2tldDogbG9nQnVja2V0LFxuICAgICAgfSxcbiAgICAgIGxvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgICBidWNrZXROYW1lOiAnYW55dGhpbmcnXG4gICAgICB9XG4gICAgfSk7XG4gIH07XG4gIGV4cGVjdChhcHApLnRvVGhyb3coL0Vycm9yIC0gYm90aGxvZyBidWNrZXQgcHJvcHMgYW5kIGFuIGV4aXN0aW5nIGxvZyBidWNrZXQgd2VyZSBwcm92aWRlZC5cXG4vKTtcbn0pO1xuXG50ZXN0KCdQcm92aWRpbmcgZXhpc3RpbmdMb2dnaW5nQnVja2V0IGFuZCBsb2dTM0FjY2Vzc0xvZ3M9ZmFsc2UgaXMgYW4gZXJyb3InLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBsb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2xvdWRmcm9udC1sb2ctYnVja2V0Jywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICdjbG91ZGZyb250LXMzJywge1xuICAgICAgYnVja2V0UHJvcHM6IHtcbiAgICAgICAgc2VydmVyQWNjZXNzTG9nc0J1Y2tldDogbG9nQnVja2V0LFxuICAgICAgfSxcbiAgICAgIGxvZ1MzQWNjZXNzTG9nczogZmFsc2VcbiAgICB9KTtcbiAgfTtcbiAgZXhwZWN0KGFwcCkudG9UaHJvdygvRXJyb3IgLSBsb2dTM0FjY2Vzc0xvZ3MgaXMgZmFsc2UsIGJ1dCBhIGxvZyBidWNrZXQgd2FzIHByb3ZpZGVkIGluIGJ1Y2tldFByb3BzLlxcbi8pO1xufSk7XG5cbnRlc3QoJ1Byb3ZpZGluZyBsb2dnaW5nQnVja2V0UHJvcHMgYW5kIGxvZ1MzQWNjZXNzTG9ncz1mYWxzZSBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgICBsb2dnaW5nQnVja2V0UHJvcHM6IHtcbiAgICAgICAgYnVja2V0TmFtZTogJ2FueXRoaW5nJ1xuICAgICAgfSxcbiAgICAgIGxvZ1MzQWNjZXNzTG9nczogZmFsc2VcbiAgICB9KTtcbiAgfTtcbiAgLy8gTk9URTogVGhpcyBlcnJvciBpcyB0aHJvd24gYnkgQ2hlY2tTM1Byb3BzKCksIG5vdCBDaGVja0NvbnN0cnVjdFNwZWNpZmljUHJvcHMoKVxuICBleHBlY3QoYXBwKS50b1Rocm93KC9FcnJvciAtIElmIGxvZ1MzQWNjZXNzTG9ncyBpcyBmYWxzZSwgc3VwcGx5aW5nIGxvZ2dpbmdCdWNrZXRQcm9wcyBvciBleGlzdGluZ0xvZ2dpbmdCdWNrZXRPYmogaXMgaW52YWxpZC5cXG4vKTtcbn0pO1xuXG4vLyB0ZXN0KCdObyBuZXcgbG9nZ2luZ0J1Y2tldCBpcyBjcmVhdGVkIGlmIGV4aXN0aW5nTG9nZ2luZ0J1Y2tldCBpcyBzdXBwbGllZCcsICgpID0+IHtcbnRlc3QoJ2xvZ2dpbmdCdWNrZXRQcm9wcyBpcyBzdXBwbGllZCBpcyBpbnRlZ3JhdGVkIGludG8gYXJjaGl0ZWN0dXJlIGNvcnJlY3RseScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgdGVzdE5hbWUgPSBcInRlc3QtbmFtZVwiO1xuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICdjbG91ZGZyb250LXMzJywge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgIH0sXG4gICAgbG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWUsXG4gICAgICBidWNrZXROYW1lOiB0ZXN0TmFtZVxuICAgIH1cbiAgfSk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0xvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgNCk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBCdWNrZXROYW1lOiB0ZXN0TmFtZVxuICB9KTtcblxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIExvZ2dpbmdDb25maWd1cmF0aW9uOiB7XG4gICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6IHtcbiAgICAgICAgUmVmOiBcImNsb3VkZnJvbnRzM1MzTG9nZ2luZ0J1Y2tldDUyRUVCNzA4XCJcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufSk7XG50ZXN0KCdidWNrZXRQcm9wczpzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0IGlzIHN1cHBsaWVkIGlzIGludGVncmF0ZWQgaW50byBhcmNoaXRlY3R1cmUgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCB0ZXN0TmFtZSA9ICdzb21lLW5hbWUnO1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgbG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ3Rlc3QtbG9nJywge1xuICAgIGJ1Y2tldE5hbWU6IHRlc3ROYW1lLFxuICB9KTtcblxuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICdjbG91ZGZyb250LXMzJywge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBsb2dCdWNrZXQsXG4gICAgfSxcbiAgfSk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0xvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgNCk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCB7XG4gICAgTG9nZ2luZ0NvbmZpZ3VyYXRpb246IHtcbiAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZToge1xuICAgICAgICBSZWY6IFwidGVzdGxvZ0U4OEI0QzZCXCJcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufSk7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PVxuLy8gQ2xvdWRGcm9udCBMb2cgQnVja2V0XG4vLyA9PT09PT09PT09PT09PT09PT09PT1cbnRlc3QoJ1Byb3ZpZGluZyBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzIGFuZCBhIGxvZyBidWNrZXQgaW4gY2xvdWRGcm9udERpc3RyYnV0aW9uUHJvcHMgaXMgYW4gZXJyb3InLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBsb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2xvdWRmcm9udC1sb2ctYnVja2V0Jywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICdjbG91ZGZyb250LXMzJywge1xuICAgICAgY2xvdWRGcm9udERpc3RyaWJ1dGlvblByb3BzOiB7XG4gICAgICAgIGxvZ0J1Y2tldFxuICAgICAgfSxcbiAgICAgIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6IHtcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWVcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcblxuICBleHBlY3QoYXBwKS50b1Rocm93KCk7XG59KTtcbnRlc3QoJ2Nsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHMgYXJlIHVzZWQgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCB0ZXN0TmFtZSA9IFwidGVzdC1uYW1lXCI7XG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlLFxuICAgICAgYnVja2V0TmFtZTogdGVzdE5hbWVcbiAgICB9XG4gIH0pO1xuXG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgNCk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBCdWNrZXROYW1lOiB0ZXN0TmFtZVxuICB9KTtcblxufSk7XG50ZXN0KCdMb2dnaW5nIGRpc2FibGVkIGluIENsb3VkRnJvbnQgcHJvcHMgaXMgaGFuZGxlZCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IGRlcGxveShzdGFjaywgeyBjbG91ZEZyb250RGlzdHJpYnV0aW9uUHJvcHM6IHsgZW5hYmxlTG9nZ2luZzogZmFsc2UgfSB9KTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIE9ubHkgdGhlIGNvbnRlbnQgYnVja2V0IGFuZCBpdCBTMyBBY2Nlc3MgTG9nIGJ1Y2tldCAobm8gQ2xvdWRmcm9udCBsb2cgYnVja2V0KVxuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgMik7XG5cbiAgLy8gTm8gbG9nZ2luZyBpcyBjb25maWd1cmVkXG4gIHRlbXBsYXRlLnJlc291cmNlUHJvcGVydGllc0NvdW50SXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBMb2dnaW5nOiBNYXRjaC5hbnlWYWx1ZSgpXG4gICAgfVxuICB9LCAwKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250TG9nZ2luZ0J1Y2tldCA9PT0gdW5kZWZpbmVkKTtcbn0pO1xudGVzdCgnTm8gbmV3IENsb3VkRnJvbnRMb2dnaW5nQnVja2V0IGlzIGNyZWF0ZWQgaWYgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczpsb2dCdWNrZXQgaXMgc3VwcGxpZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHRlc3ROYW1lID0gJ3JhbmRvbS12YWx1ZSc7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBsb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2xvdWRmcm9udC1sb2ctYnVja2V0Jywge1xuICAgIGJ1Y2tldE5hbWU6IHRlc3ROYW1lXG4gIH0pO1xuXG4gIC8vIGNvbnN0IGNvbnN0cnVjdCA9XG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgY2xvdWRGcm9udERpc3RyaWJ1dGlvblByb3BzOiB7XG4gICAgICBsb2dCdWNrZXRcbiAgICB9LFxuICB9KTtcblxuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgLy8gQ29udGVudCBidWNrZXQsIENvbnRlbnQgYnVja2V0IFMzIEFjY2VzcyBMb2cgYnVja2V0LCBjbG91ZGZyb250IGxvZyBidWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDMpO1xuXG4gIC8vIEVuc3VyZSBvdXIgZXhpc3RpbmcgYnVja2V0IGhhcyBiZWVuIHVzZWQgZm9yIGNsb3VkZnJvbnQgbG9nZ2luZ1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBMb2dnaW5nOiB7XG4gICAgICAgIEJ1Y2tldDoge1xuICAgICAgICAgIFwiRm46OkdldEF0dFwiOiBbXG4gICAgICAgICAgICBcImNsb3VkZnJvbnRsb2didWNrZXRERjcwNThGQlwiLFxuICAgICAgICAgICAgXCJSZWdpb25hbERvbWFpbk5hbWVcIlxuICAgICAgICAgIF1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbn0pO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT1cbi8vIENsb3VkRnJvbnQgTG9ncyBCdWNrZXQgQWNjZXNzIExvZyBCdWNrZXRcbi8vID09PT09PT09PT09PT09PT09PT09PVxudGVzdCgnUHJvdmlkaW5nIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHMgYW5kIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6c2VydmVyQWNjZXNzTG9nc0J1Y2tldCBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdjbG91ZGZyb250LWxvZy1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIHNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQ6IGxvZ0J1Y2tldCxcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWVcbiAgICAgIH0sXG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6ICdzcGVjZmljLW5hbWUtaXMtaW5jb25zZXF1ZW50aWFsJ1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIGV4cGVjdChhcHApLnRvVGhyb3coXG4gICAgL0Vycm9yIC0gYW4gZXhpc3RpbmcgQ2xvdWRGcm9udCBsb2cgYnVja2V0IFMzIGFjY2VzcyBsb2cgYnVja2V0IGFuZCBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzIHdlcmUgcHJvdmlkZWRcXG4vKTtcbn0pO1xudGVzdCgnUHJvdmlkaW5nIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHMgYW5kIGxvZ0Nsb3VkRnJvbnRBY2Nlc3NMb2c9ZmFsc2UgaXMgYW4gZXJyb3InLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICdjbG91ZGZyb250LXMzJywge1xuICAgICAgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZzogZmFsc2UsXG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6ICdzcGVjZmljLW5hbWUtaXMtaW5jb25zZXF1ZW50aWFsJ1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIGV4cGVjdChhcHApLnRvVGhyb3coL0Vycm9yIC0gY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wcyB3ZXJlIHByb3ZpZGVkIGJ1dCBsb2dDbG91ZEZyb250QWNjZXNzTG9nIHdhcyBmYWxzZVxcbi8pO1xufSk7XG50ZXN0KCdQcm92aWRpbmcgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZz1mYWxzZSBhbmQgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczpzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0IGlzIGFuIGVycm9yJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgbG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ2Nsb3VkZnJvbnQtbG9nLWJ1Y2tldCcsIHt9KTtcblxuICBjb25zdCBhcHAgPSAoKSA9PiB7XG4gICAgbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1zMycsIHtcbiAgICAgIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6IHtcbiAgICAgICAgc2VydmVyQWNjZXNzTG9nc0J1Y2tldDogbG9nQnVja2V0LFxuICAgICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZVxuICAgICAgfSxcbiAgICAgIGxvZ0Nsb3VkRnJvbnRBY2Nlc3NMb2c6IGZhbHNlLFxuICAgIH0pO1xuICB9O1xuXG4gIGV4cGVjdChhcHApLnRvVGhyb3coL0Vycm9yIC0gcHJvcHMuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wcy5zZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0IHdhcyBwcm92aWRlZCBidXQgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZyB3YXMgZmFsc2VcXG4vKTtcbn0pO1xudGVzdCgnY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wcyBhcmUgdXNlZCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wczoge1xuICAgICAgd2Vic2l0ZUVycm9yRG9jdW1lbnQ6ICdwbGFjZWhvbGRlcicsXG4gICAgICB3ZWJzaXRlSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIENvbnRlbnQgQnVja2V0LCBDb250ZW50IEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIFdlYnNpdGVDb25maWd1cmF0aW9uOiB7XG4gICAgICBFcnJvckRvY3VtZW50OiAncGxhY2Vob2xkZXInLFxuICAgICAgSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG5cbn0pO1xudGVzdCgnSWYgZXhpc3RpbmcgQ2xvdWRGcm9udCBMb2cgYnVja2V0IFMzIEFjY2VzcyBMb2dnaW5nIGJ1Y2tldCBpcyBwcm92aWRlZCwgaXQgaXMgdXNlZCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCB0ZXN0TmFtZSA9ICdjZi1sb2ctczMtbG9nJztcbiAgY29uc3QgY2ZMb2dTM0FjY2Vzc0xvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdjZi1sb2ctczMtYWNjZXNzLWxvZy1idWNrZXQnLCB7XG4gICAgYnVja2V0TmFtZTogdGVzdE5hbWVcbiAgfSk7XG5cbiAgbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1zMycsIHtcbiAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBjZkxvZ1MzQWNjZXNzTG9nQnVja2V0XG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgLy8gQ29udGVudCBCdWNrZXQsIENvbnRlbnQgQnVja2V0IFMzIEFjY2VzcyBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQsIENsb3VkRnJvbnQgTG9nIEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldFxuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgNCk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBCdWNrZXROYW1lOiB0ZXN0TmFtZVxuICB9KTtcblxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIExvZ2dpbmdDb25maWd1cmF0aW9uOiB7XG4gICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6IHtcbiAgICAgICAgUmVmOiBcImNmbG9nczNhY2Nlc3Nsb2didWNrZXRERTM3NEMyN1wiXG4gICAgICB9XG4gICAgfVxuICB9KTtcblxufSk7XG5cbnRlc3QoJ2Nsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0IHByb3BlcnR5IGlzIHNldCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wczoge1xuICAgICAgd2Vic2l0ZUVycm9yRG9jdW1lbnQ6ICdwbGFjZWhvbGRlcicsXG4gICAgICB3ZWJzaXRlSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIENvbnRlbnQgQnVja2V0LCBDb250ZW50IEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIFdlYnNpdGVDb25maWd1cmF0aW9uOiB7XG4gICAgICBFcnJvckRvY3VtZW50OiAncGxhY2Vob2xkZXInLFxuICAgICAgSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXQhLmJ1Y2tldE5hbWUpLnRvQmVEZWZpbmVkKCk7XG59KTtcblxudGVzdCgnbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZyBwcm9wZXJ0eSBpcyB1c2VkIGNvcnJlY3RseScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgY29uc3RydWN0ID0gbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1zMycsIHtcbiAgICBsb2dDbG91ZEZyb250QWNjZXNzTG9nOiBmYWxzZVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgLy8gQ29udGVudCBCdWNrZXQsIENvbnRlbnQgQnVja2V0IFMzIEFjY2VzcyBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQsIENsb3VkRnJvbnQgTG9nIEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldFxuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgMyk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXQpLm5vdC50b0JlRGVmaW5lZCgpO1xufSk7XG5cbnRlc3QoJ2FkZGl0aW9uYWxCZWhhdmlvcnMgaGF2ZSBjb3JyZWN0IG9yaWdpbicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgYWRkaXRpb25hbEJ1Y2tldCA9IGRlZmF1bHRzLkNyZWF0ZVNjcmFwQnVja2V0KHN0YWNrLCBcInNjcmFwQnVja2V0XCIsIHtcbiAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWUsXG4gIH0pO1xuXG4gIGNvbnN0IG9yaWdpbkFjY2Vzc0NvbnRyb2wgPSBuZXcgQ2ZuT3JpZ2luQWNjZXNzQ29udHJvbChzdGFjaywgJ0Nsb3VkRnJvbnRPYWMnLCB7XG4gICAgb3JpZ2luQWNjZXNzQ29udHJvbENvbmZpZzoge1xuICAgICAgbmFtZTogZGVmYXVsdHMuZ2VuZXJhdGVQaHlzaWNhbE9hY05hbWUoJ2F3cy1jbG91ZGZyb250LXMzLScsIFtfX2ZpbGVuYW1lXSksXG4gICAgICBvcmlnaW5BY2Nlc3NDb250cm9sT3JpZ2luVHlwZTogJ3MzJyxcbiAgICAgIHNpZ25pbmdCZWhhdmlvcjogJ2Fsd2F5cycsXG4gICAgICBzaWduaW5nUHJvdG9jb2w6ICdzaWd2NCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ09yaWdpbiBhY2Nlc3MgY29udHJvbCBwcm92aXNpb25lZCBieSBhd3MtY2xvdWRmcm9udC1zMydcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IGFkZGl0aW9uYWxPcmlnaW4gPSBuZXcgZGVmYXVsdHMuUzNPYWNPcmlnaW4oYWRkaXRpb25hbEJ1Y2tldCwge1xuICAgIG9yaWdpbkFjY2Vzc0NvbnRyb2xcbiAgfSk7XG5cbiAgbmV3IENsb3VkRnJvbnRUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LXMzJywge1xuICAgIGNsb3VkRnJvbnREaXN0cmlidXRpb25Qcm9wczoge1xuICAgICAgYWRkaXRpb25hbEJlaGF2aW9yczoge1xuICAgICAgICAnL2Fzc2V0cy9wdWJsaWMvKic6IHtcbiAgICAgICAgICBvcmlnaW46IGFkZGl0aW9uYWxPcmlnaW4sXG4gICAgICAgICAgY2FjaGVQb2xpY3k6IENhY2hlUG9saWN5LkNBQ0hJTkdfRElTQUJMRUQsXG4gICAgICAgIH0sXG4gICAgICAgICduZ3N3Lmpzb24nOiB7XG4gICAgICAgICAgY2FjaGVQb2xpY3k6IENhY2hlUG9saWN5LkNBQ0hJTkdfRElTQUJMRUQsXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgQ2FjaGVCZWhhdmlvcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIENhY2hlUG9saWN5SWQ6IFwiNDEzNWVhMmQtNmRmOC00NGEzLTlkZjMtNGI1YTg0YmUzOWFkXCIsXG4gICAgICAgICAgQ29tcHJlc3M6IHRydWUsXG4gICAgICAgICAgUGF0aFBhdHRlcm46IFwiL2Fzc2V0cy9wdWJsaWMvKlwiLFxuICAgICAgICAgIFRhcmdldE9yaWdpbklkOiBcInRlc3RjbG91ZGZyb250czNDbG91ZEZyb250RGlzdHJpYnV0aW9uT3JpZ2luMjFENzgzOTFDXCIsXG4gICAgICAgICAgVmlld2VyUHJvdG9jb2xQb2xpY3k6IFwiYWxsb3ctYWxsXCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIENhY2hlUG9saWN5SWQ6IFwiNDEzNWVhMmQtNmRmOC00NGEzLTlkZjMtNGI1YTg0YmUzOWFkXCIsXG4gICAgICAgICAgQ29tcHJlc3M6IHRydWUsXG4gICAgICAgICAgUGF0aFBhdHRlcm46IFwibmdzdy5qc29uXCIsXG4gICAgICAgICAgVGFyZ2V0T3JpZ2luSWQ6IFwidGVzdGNsb3VkZnJvbnRzM0Nsb3VkRnJvbnREaXN0cmlidXRpb25PcmlnaW4xMjQwNTEwMzlcIixcbiAgICAgICAgICBWaWV3ZXJQcm90b2NvbFBvbGljeTogXCJhbGxvdy1hbGxcIlxuICAgICAgICB9XG4gICAgICBdLFxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnVGVzdCB0aGF0IFZhbGlkYXRlRGlzdHJpYnV0aW9uUHJvcHMoKSBpcyBiZWluZyBjYWxsZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG4gIGNvbnN0IHByb3BzOiBDbG91ZEZyb250VG9TM1Byb3BzID0ge1xuICAgIGNsb3VkRnJvbnREaXN0cmlidXRpb25Qcm9wczoge1xuICAgICAgaW52YWxpZFByb3BlcnR5OiB0cnVlXG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvUzMoc3RhY2ssICd0ZXN0LWNvbnN0cnVjdCcsIHByb3BzKTtcbiAgfTtcblxuICBleHBlY3QoYXBwKS50b1Rocm93KC9FUlJPUiAtIGludmFsaWRQcm9wZXJ0eSBpcyBub3QgYSB2YWxpZCBwcm9wZXJ0eSBvZiBEaXN0cmlidXRpb25Qcm9wcy8pO1xufSk7XG4iXX0=