@aws-solutions-constructs/aws-cloudfront-oai-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.
|
@@ -1,703 +0,0 @@
|
|
|
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
|
-
function deploy(stack, props) {
|
|
24
|
-
return new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {
|
|
25
|
-
bucketProps: {
|
|
26
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
27
|
-
},
|
|
28
|
-
...props
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
test('construct defaults set properties correctly', () => {
|
|
32
|
-
const stack = new cdk.Stack();
|
|
33
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {});
|
|
34
|
-
expect(construct.cloudFrontWebDistribution).toBeDefined();
|
|
35
|
-
expect(construct.cloudFrontFunction).toBeDefined();
|
|
36
|
-
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
37
|
-
expect(construct.s3Bucket).toBeDefined();
|
|
38
|
-
expect(construct.s3LoggingBucket).toBeDefined();
|
|
39
|
-
expect(construct.s3BucketInterface).toBeDefined();
|
|
40
|
-
expect(construct.cloudFrontLoggingBucketAccessLogBucket).toBeDefined();
|
|
41
|
-
expect(construct.originAccessIdentity).toBeDefined();
|
|
42
|
-
});
|
|
43
|
-
test('check s3Bucket default encryption', () => {
|
|
44
|
-
const stack = new cdk.Stack();
|
|
45
|
-
deploy(stack);
|
|
46
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
47
|
-
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
48
|
-
BucketEncryption: {
|
|
49
|
-
ServerSideEncryptionConfiguration: [{
|
|
50
|
-
ServerSideEncryptionByDefault: {
|
|
51
|
-
SSEAlgorithm: "AES256"
|
|
52
|
-
}
|
|
53
|
-
}]
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
test('check that an OAI is created', () => {
|
|
58
|
-
const stack = new cdk.Stack();
|
|
59
|
-
deploy(stack);
|
|
60
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
61
|
-
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
62
|
-
DistributionConfig: {
|
|
63
|
-
Origins: [
|
|
64
|
-
{
|
|
65
|
-
S3OriginConfig: {
|
|
66
|
-
OriginAccessIdentity: assertions_1.Match.anyValue()
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
test('confirm NO OAC is created', () => {
|
|
74
|
-
const stack = new cdk.Stack();
|
|
75
|
-
deploy(stack);
|
|
76
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
77
|
-
template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", {
|
|
78
|
-
DistributionConfig: {
|
|
79
|
-
Origins: [
|
|
80
|
-
{
|
|
81
|
-
OriginAccessControlId: assertions_1.Match.anyValue(),
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
}
|
|
85
|
-
}, 0);
|
|
86
|
-
});
|
|
87
|
-
test('check s3Bucket public access block configuration', () => {
|
|
88
|
-
const stack = new cdk.Stack();
|
|
89
|
-
deploy(stack);
|
|
90
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
91
|
-
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
92
|
-
PublicAccessBlockConfiguration: {
|
|
93
|
-
BlockPublicAcls: true,
|
|
94
|
-
BlockPublicPolicy: true,
|
|
95
|
-
IgnorePublicAcls: true,
|
|
96
|
-
RestrictPublicBuckets: true
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
test('test s3Bucket override publicAccessBlockConfiguration', () => {
|
|
101
|
-
const stack = new cdk.Stack();
|
|
102
|
-
const props = {
|
|
103
|
-
bucketProps: {
|
|
104
|
-
blockPublicAccess: {
|
|
105
|
-
blockPublicAcls: false,
|
|
106
|
-
blockPublicPolicy: true,
|
|
107
|
-
ignorePublicAcls: false,
|
|
108
|
-
restrictPublicBuckets: true
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', props);
|
|
113
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
114
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
115
|
-
PublicAccessBlockConfiguration: {
|
|
116
|
-
BlockPublicAcls: false,
|
|
117
|
-
BlockPublicPolicy: true,
|
|
118
|
-
IgnorePublicAcls: false,
|
|
119
|
-
RestrictPublicBuckets: true
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
test('check existing bucket', () => {
|
|
124
|
-
const bucketName = "my-bucket";
|
|
125
|
-
const stack = new cdk.Stack();
|
|
126
|
-
const existingBucket = new s3.Bucket(stack, bucketName, {
|
|
127
|
-
bucketName: 'my-bucket'
|
|
128
|
-
});
|
|
129
|
-
const props = {
|
|
130
|
-
existingBucketObj: existingBucket
|
|
131
|
-
};
|
|
132
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', props);
|
|
133
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
134
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
135
|
-
BucketName: bucketName
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
test('check properties', () => {
|
|
139
|
-
const stack = new cdk.Stack();
|
|
140
|
-
const construct = deploy(stack);
|
|
141
|
-
expect(construct.cloudFrontWebDistribution).toBeDefined();
|
|
142
|
-
expect(construct.s3Bucket).toBeDefined();
|
|
143
|
-
});
|
|
144
|
-
test("Confirm CheckS3Props is called", () => {
|
|
145
|
-
// Stack
|
|
146
|
-
const stack = new cdk.Stack();
|
|
147
|
-
const testBucket = new s3.Bucket(stack, 'test-bucket', {});
|
|
148
|
-
const app = () => {
|
|
149
|
-
// Helper declaration
|
|
150
|
-
new lib_1.CloudFrontToOaiToS3(stack, "bad-s3-args", {
|
|
151
|
-
existingBucketObj: testBucket,
|
|
152
|
-
bucketProps: {
|
|
153
|
-
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
};
|
|
157
|
-
// Assertion
|
|
158
|
-
expect(app).toThrowError('Error - Either provide bucketProps or existingBucketObj, but not both.\n');
|
|
159
|
-
});
|
|
160
|
-
test("Test existingBucketObj", () => {
|
|
161
|
-
// Stack
|
|
162
|
-
const stack = new cdk.Stack();
|
|
163
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, "existingIBucket", {
|
|
164
|
-
existingBucketObj: s3.Bucket.fromBucketName(stack, 'mybucket', 'mybucket')
|
|
165
|
-
});
|
|
166
|
-
// Assertion
|
|
167
|
-
expect(construct.cloudFrontWebDistribution).toBeDefined();
|
|
168
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
169
|
-
template.resourceCountIs("AWS::S3::Bucket", 2);
|
|
170
|
-
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
171
|
-
DistributionConfig: {
|
|
172
|
-
Origins: [
|
|
173
|
-
{
|
|
174
|
-
DomainName: {
|
|
175
|
-
"Fn::Join": [
|
|
176
|
-
"",
|
|
177
|
-
[
|
|
178
|
-
"mybucket.s3.",
|
|
179
|
-
{
|
|
180
|
-
Ref: "AWS::Region"
|
|
181
|
-
},
|
|
182
|
-
".",
|
|
183
|
-
{
|
|
184
|
-
Ref: "AWS::URLSuffix"
|
|
185
|
-
}
|
|
186
|
-
]
|
|
187
|
-
]
|
|
188
|
-
},
|
|
189
|
-
Id: "existingIBucketCloudFrontDistributionOrigin1D5849125",
|
|
190
|
-
S3OriginConfig: {
|
|
191
|
-
OriginAccessIdentity: assertions_1.Match.anyValue()
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
]
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
test('test cloudfront with custom domain names', () => {
|
|
199
|
-
const stack = new cdk.Stack();
|
|
200
|
-
const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:${Aws.PARTITION}:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012');
|
|
201
|
-
const props = {
|
|
202
|
-
cloudFrontDistributionProps: {
|
|
203
|
-
domainNames: ['mydomains'],
|
|
204
|
-
certificate
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', props);
|
|
208
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
209
|
-
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
210
|
-
DistributionConfig: {
|
|
211
|
-
Aliases: [
|
|
212
|
-
"mydomains"
|
|
213
|
-
]
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
test("Test that a CMK on the bucket throws an error", () => {
|
|
218
|
-
// Stack
|
|
219
|
-
const stack = new cdk.Stack();
|
|
220
|
-
const existingBucket = defaults.CreateScrapBucket(stack, "encrypted", {
|
|
221
|
-
encryption: s3.BucketEncryption.KMS,
|
|
222
|
-
encryptionKey: new aws_kms_1.Key(stack, 'Key', {
|
|
223
|
-
enableKeyRotation: true
|
|
224
|
-
})
|
|
225
|
-
});
|
|
226
|
-
const app = () => {
|
|
227
|
-
new lib_1.CloudFrontToOaiToS3(stack, "existingIBucket", {
|
|
228
|
-
existingBucketObj: existingBucket
|
|
229
|
-
});
|
|
230
|
-
};
|
|
231
|
-
expect(app).toThrowError(/Error - buckets cannot use CMKs with OAIs\n/);
|
|
232
|
-
});
|
|
233
|
-
test("Test that a CMK in the props throws an error", () => {
|
|
234
|
-
// Stack
|
|
235
|
-
const stack = new cdk.Stack();
|
|
236
|
-
const encryptionKey = new aws_kms_1.Key(stack, 'cmkKey', {
|
|
237
|
-
enableKeyRotation: true,
|
|
238
|
-
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY
|
|
239
|
-
});
|
|
240
|
-
const app = () => {
|
|
241
|
-
new lib_1.CloudFrontToOaiToS3(stack, "existingIBucket", {
|
|
242
|
-
bucketProps: {
|
|
243
|
-
enforceSSL: true,
|
|
244
|
-
encryption: s3.BucketEncryption.KMS,
|
|
245
|
-
encryptionKey
|
|
246
|
-
},
|
|
247
|
-
});
|
|
248
|
-
};
|
|
249
|
-
expect(app).toThrowError(/Error - buckets cannot use CMKs with OAIs\n/);
|
|
250
|
-
});
|
|
251
|
-
test('Cloudfront logging bucket with destroy removal policy and auto delete objects', () => {
|
|
252
|
-
const stack = new cdk.Stack();
|
|
253
|
-
const cloudfrontLogBucketName = 'cf-log-bucket';
|
|
254
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
255
|
-
cloudFrontLoggingBucketProps: {
|
|
256
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
257
|
-
autoDeleteObjects: true,
|
|
258
|
-
bucketName: cloudfrontLogBucketName
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
262
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
263
|
-
OwnershipControls: { Rules: [{ ObjectOwnership: "ObjectWriter" }] },
|
|
264
|
-
BucketName: cloudfrontLogBucketName,
|
|
265
|
-
});
|
|
266
|
-
template.hasResourceProperties("Custom::S3AutoDeleteObjects", {
|
|
267
|
-
ServiceToken: {
|
|
268
|
-
"Fn::GetAtt": [
|
|
269
|
-
"CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F",
|
|
270
|
-
"Arn"
|
|
271
|
-
]
|
|
272
|
-
},
|
|
273
|
-
BucketName: {
|
|
274
|
-
Ref: assertions_1.Match.stringLikeRegexp("cloudfrontoais3CloudfrontLoggingBucket")
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
test('s3 bucket with one content bucket and no access logging of CONTENT bucket', () => {
|
|
279
|
-
const stack = new cdk.Stack();
|
|
280
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
281
|
-
bucketProps: {
|
|
282
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
283
|
-
},
|
|
284
|
-
logS3AccessLogs: false
|
|
285
|
-
});
|
|
286
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
287
|
-
// Content bucket+Cloudfront Logs bucket+
|
|
288
|
-
// Access Log bucket for Cloudfront Logs bucket = 3 buckets
|
|
289
|
-
template.resourceCountIs("AWS::S3::Bucket", 3);
|
|
290
|
-
expect(construct.s3LoggingBucket).toEqual(undefined);
|
|
291
|
-
});
|
|
292
|
-
test('CloudFront origin path present when provided', () => {
|
|
293
|
-
const stack = new cdk.Stack();
|
|
294
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
295
|
-
originPath: '/testPath'
|
|
296
|
-
});
|
|
297
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
298
|
-
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
299
|
-
DistributionConfig: {
|
|
300
|
-
Origins: [
|
|
301
|
-
{
|
|
302
|
-
OriginPath: "/testPath",
|
|
303
|
-
}
|
|
304
|
-
]
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
});
|
|
308
|
-
test('CloudFront origin path should not be present if not provided', () => {
|
|
309
|
-
const stack = new cdk.Stack();
|
|
310
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {});
|
|
311
|
-
defaults.expectNonexistence(stack, "AWS::CloudFront::Distribution", {
|
|
312
|
-
DistributionConfig: {
|
|
313
|
-
Origins: [
|
|
314
|
-
{
|
|
315
|
-
OriginPath: assertions_1.Match.anyValue(),
|
|
316
|
-
}
|
|
317
|
-
]
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
});
|
|
321
|
-
test('Test the deployment with securityHeadersBehavior instead of HTTP security headers', () => {
|
|
322
|
-
// Initial setup
|
|
323
|
-
const stack = new aws_cdk_lib_1.Stack();
|
|
324
|
-
const testConstruct = new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {
|
|
325
|
-
insertHttpSecurityHeaders: false,
|
|
326
|
-
responseHeadersPolicyProps: {
|
|
327
|
-
securityHeadersBehavior: {
|
|
328
|
-
strictTransportSecurity: {
|
|
329
|
-
accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
|
|
330
|
-
includeSubdomains: true,
|
|
331
|
-
override: true,
|
|
332
|
-
preload: true
|
|
333
|
-
},
|
|
334
|
-
contentSecurityPolicy: {
|
|
335
|
-
contentSecurityPolicy: "upgrade-insecure-requests; default-src 'none';",
|
|
336
|
-
override: true
|
|
337
|
-
},
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
// Assertion
|
|
342
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
343
|
-
template.hasResourceProperties("AWS::CloudFront::ResponseHeadersPolicy", {
|
|
344
|
-
ResponseHeadersPolicyConfig: {
|
|
345
|
-
SecurityHeadersConfig: {
|
|
346
|
-
ContentSecurityPolicy: {
|
|
347
|
-
ContentSecurityPolicy: "upgrade-insecure-requests; default-src 'none';",
|
|
348
|
-
Override: true
|
|
349
|
-
},
|
|
350
|
-
StrictTransportSecurity: {
|
|
351
|
-
AccessControlMaxAgeSec: 63072,
|
|
352
|
-
IncludeSubdomains: true,
|
|
353
|
-
Override: true,
|
|
354
|
-
Preload: true
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
expect(testConstruct.cloudFrontFunction).toEqual(undefined);
|
|
360
|
-
});
|
|
361
|
-
test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProps are provided", () => {
|
|
362
|
-
const stack = new cdk.Stack();
|
|
363
|
-
expect(() => {
|
|
364
|
-
new lib_1.CloudFrontToOaiToS3(stack, "test-cloudfront-oai-s3", {
|
|
365
|
-
insertHttpSecurityHeaders: true,
|
|
366
|
-
responseHeadersPolicyProps: {
|
|
367
|
-
securityHeadersBehavior: {
|
|
368
|
-
strictTransportSecurity: {
|
|
369
|
-
accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
|
|
370
|
-
includeSubdomains: true,
|
|
371
|
-
override: false,
|
|
372
|
-
preload: true
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
}).toThrowError();
|
|
378
|
-
});
|
|
379
|
-
test("Confirm CheckCloudFrontProps is being called", () => {
|
|
380
|
-
const stack = new cdk.Stack();
|
|
381
|
-
expect(() => {
|
|
382
|
-
new lib_1.CloudFrontToOaiToS3(stack, "test-cloudfront-apigateway", {
|
|
383
|
-
insertHttpSecurityHeaders: true,
|
|
384
|
-
responseHeadersPolicyProps: {
|
|
385
|
-
securityHeadersBehavior: {
|
|
386
|
-
strictTransportSecurity: {
|
|
387
|
-
accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
|
|
388
|
-
includeSubdomains: true,
|
|
389
|
-
override: false,
|
|
390
|
-
preload: true
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
}).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.');
|
|
396
|
-
});
|
|
397
|
-
test('Test that we do not create an Access Log bucket for CF logs if one is provided', () => {
|
|
398
|
-
const stack = new cdk.Stack();
|
|
399
|
-
const cfS3AccessLogBucket = new s3.Bucket(stack, 'cf-s3-access-logs');
|
|
400
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {
|
|
401
|
-
cloudFrontLoggingBucketProps: {
|
|
402
|
-
serverAccessLogsBucket: cfS3AccessLogBucket
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
406
|
-
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
407
|
-
});
|
|
408
|
-
// =====================
|
|
409
|
-
// S3 Content Bucket Access Logs Bucket
|
|
410
|
-
// =====================
|
|
411
|
-
test('Providing loggingBucketProps and existingLoggingBucket is an error', () => {
|
|
412
|
-
const stack = new cdk.Stack();
|
|
413
|
-
const logBucket = new s3.Bucket(stack, 'log-bucket', {});
|
|
414
|
-
const app = () => {
|
|
415
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
416
|
-
bucketProps: {
|
|
417
|
-
serverAccessLogsBucket: logBucket,
|
|
418
|
-
},
|
|
419
|
-
loggingBucketProps: {
|
|
420
|
-
bucketName: 'anything'
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
};
|
|
424
|
-
expect(app).toThrowError(/Error - bothlog bucket props and an existing log bucket were provided.\n/);
|
|
425
|
-
});
|
|
426
|
-
test('Providing existingLoggingBucket and logS3AccessLogs=false is an error', () => {
|
|
427
|
-
const stack = new cdk.Stack();
|
|
428
|
-
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
429
|
-
const app = () => {
|
|
430
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
431
|
-
bucketProps: {
|
|
432
|
-
serverAccessLogsBucket: logBucket,
|
|
433
|
-
},
|
|
434
|
-
logS3AccessLogs: false
|
|
435
|
-
});
|
|
436
|
-
};
|
|
437
|
-
expect(app).toThrowError(/Error - logS3AccessLogs is false, but a log bucket was provided in bucketProps.\n/);
|
|
438
|
-
});
|
|
439
|
-
test('Providing loggingBucketProps and logS3AccessLogs=false is an error', () => {
|
|
440
|
-
const stack = new cdk.Stack();
|
|
441
|
-
const app = () => {
|
|
442
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
443
|
-
loggingBucketProps: {
|
|
444
|
-
bucketName: 'anything'
|
|
445
|
-
},
|
|
446
|
-
logS3AccessLogs: false
|
|
447
|
-
});
|
|
448
|
-
};
|
|
449
|
-
// NOTE: This error is thrown by CheckS3Props(), not CheckConstructSpecificProps()
|
|
450
|
-
expect(app).toThrowError(/Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n/);
|
|
451
|
-
});
|
|
452
|
-
// test('No new loggingBucket is created if existingLoggingBucket is supplied', () => {
|
|
453
|
-
test('loggingBucketProps is supplied is integrated into architecture correctly', () => {
|
|
454
|
-
const stack = new cdk.Stack();
|
|
455
|
-
const testName = "test-name";
|
|
456
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
457
|
-
bucketProps: {
|
|
458
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
459
|
-
},
|
|
460
|
-
loggingBucketProps: {
|
|
461
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
462
|
-
autoDeleteObjects: true,
|
|
463
|
-
bucketName: testName
|
|
464
|
-
}
|
|
465
|
-
});
|
|
466
|
-
expect(construct.s3LoggingBucket).toBeDefined();
|
|
467
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
468
|
-
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
469
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
470
|
-
BucketName: testName
|
|
471
|
-
});
|
|
472
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
473
|
-
LoggingConfiguration: {
|
|
474
|
-
DestinationBucketName: {
|
|
475
|
-
Ref: assertions_1.Match.stringLikeRegexp('cloudfrontoais3S3LoggingBucket')
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
});
|
|
480
|
-
test('bucketProps:serverAccessLogsBucket is supplied is integrated into architecture correctly', () => {
|
|
481
|
-
const testName = 'some-name';
|
|
482
|
-
const stack = new cdk.Stack();
|
|
483
|
-
const logBucket = new s3.Bucket(stack, 'test-log', {
|
|
484
|
-
bucketName: testName,
|
|
485
|
-
});
|
|
486
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
487
|
-
bucketProps: {
|
|
488
|
-
serverAccessLogsBucket: logBucket,
|
|
489
|
-
},
|
|
490
|
-
});
|
|
491
|
-
expect(construct.s3LoggingBucket).toBeDefined();
|
|
492
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
493
|
-
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
494
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
495
|
-
LoggingConfiguration: {
|
|
496
|
-
DestinationBucketName: {
|
|
497
|
-
Ref: "testlogE88B4C6B"
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
});
|
|
502
|
-
// =====================
|
|
503
|
-
// CloudFront Log Bucket
|
|
504
|
-
// =====================
|
|
505
|
-
test('Providing cloudFrontLoggingBucketProps and a log bucket in cloudFrontDistrbutionProps is an error', () => {
|
|
506
|
-
const stack = new cdk.Stack();
|
|
507
|
-
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
508
|
-
const app = () => {
|
|
509
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
510
|
-
cloudFrontDistributionProps: {
|
|
511
|
-
logBucket
|
|
512
|
-
},
|
|
513
|
-
cloudFrontLoggingBucketProps: {
|
|
514
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
515
|
-
autoDeleteObjects: true
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
};
|
|
519
|
-
expect(app).toThrowError();
|
|
520
|
-
});
|
|
521
|
-
test('cloudFrontLoggingBucketProps are used correctly', () => {
|
|
522
|
-
const stack = new cdk.Stack();
|
|
523
|
-
const testName = "test-name";
|
|
524
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
525
|
-
cloudFrontLoggingBucketProps: {
|
|
526
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
527
|
-
autoDeleteObjects: true,
|
|
528
|
-
bucketName: testName
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
532
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
533
|
-
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
534
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
535
|
-
BucketName: testName
|
|
536
|
-
});
|
|
537
|
-
});
|
|
538
|
-
test('Logging disabled in CloudFront props is handled correctly', () => {
|
|
539
|
-
const stack = new cdk.Stack();
|
|
540
|
-
const construct = deploy(stack, { cloudFrontDistributionProps: { enableLogging: false } });
|
|
541
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
542
|
-
// Only the content bucket and it S3 Access Log bucket (no Cloudfront log bucket)
|
|
543
|
-
template.resourceCountIs("AWS::S3::Bucket", 2);
|
|
544
|
-
// No logging is configured
|
|
545
|
-
template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", {
|
|
546
|
-
DistributionConfig: {
|
|
547
|
-
Logging: assertions_1.Match.anyValue()
|
|
548
|
-
}
|
|
549
|
-
}, 0);
|
|
550
|
-
expect(construct.cloudFrontLoggingBucket === undefined);
|
|
551
|
-
});
|
|
552
|
-
test('No new CloudFrontLoggingBucket is created if cloudFrontLoggingBucketProps:logBucket is supplied', () => {
|
|
553
|
-
const testName = 'random-value';
|
|
554
|
-
const stack = new cdk.Stack();
|
|
555
|
-
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {
|
|
556
|
-
bucketName: testName
|
|
557
|
-
});
|
|
558
|
-
// const construct =
|
|
559
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
560
|
-
cloudFrontDistributionProps: {
|
|
561
|
-
logBucket
|
|
562
|
-
},
|
|
563
|
-
});
|
|
564
|
-
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
565
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
566
|
-
// Content bucket, Content bucket S3 Access Log bucket, cloudfront log bucket
|
|
567
|
-
template.resourceCountIs("AWS::S3::Bucket", 3);
|
|
568
|
-
// Ensure our existing bucket has been used for cloudfront logging
|
|
569
|
-
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
570
|
-
DistributionConfig: {
|
|
571
|
-
Logging: {
|
|
572
|
-
Bucket: {
|
|
573
|
-
"Fn::GetAtt": [
|
|
574
|
-
"cloudfrontlogbucketDF7058FB",
|
|
575
|
-
"RegionalDomainName"
|
|
576
|
-
]
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
});
|
|
582
|
-
// =====================
|
|
583
|
-
// CloudFront Logs Bucket Access Log Bucket
|
|
584
|
-
// =====================
|
|
585
|
-
test('Providing cloudFrontLoggingBucketAccessLogBucketProps and cloudFrontLoggingBucketProps:serverAccessLogsBucket is an error', () => {
|
|
586
|
-
const stack = new cdk.Stack();
|
|
587
|
-
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
588
|
-
const app = () => {
|
|
589
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
590
|
-
cloudFrontLoggingBucketProps: {
|
|
591
|
-
serverAccessLogsBucket: logBucket,
|
|
592
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
593
|
-
autoDeleteObjects: true
|
|
594
|
-
},
|
|
595
|
-
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
596
|
-
bucketName: 'specfic-name-is-inconsequential'
|
|
597
|
-
}
|
|
598
|
-
});
|
|
599
|
-
};
|
|
600
|
-
expect(app).toThrowError(/Error - an existing CloudFront log bucket S3 access log bucket and cloudFrontLoggingBucketAccessLogBucketProps were provided\n/);
|
|
601
|
-
});
|
|
602
|
-
test('Providing cloudFrontLoggingBucketAccessLogBucketProps and logCloudFrontAccessLog=false is an error', () => {
|
|
603
|
-
const stack = new cdk.Stack();
|
|
604
|
-
const app = () => {
|
|
605
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
606
|
-
logCloudFrontAccessLog: false,
|
|
607
|
-
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
608
|
-
bucketName: 'specfic-name-is-inconsequential'
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
};
|
|
612
|
-
expect(app).toThrowError(/Error - cloudFrontLoggingBucketAccessLogBucketProps were provided but logCloudFrontAccessLog was false\n/);
|
|
613
|
-
});
|
|
614
|
-
test('Providing logCloudFrontAccessLog=false and cloudFrontLoggingBucketProps:serverAccessLogsBucket is an error', () => {
|
|
615
|
-
const stack = new cdk.Stack();
|
|
616
|
-
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
617
|
-
const app = () => {
|
|
618
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
619
|
-
cloudFrontLoggingBucketProps: {
|
|
620
|
-
serverAccessLogsBucket: logBucket,
|
|
621
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
622
|
-
autoDeleteObjects: true
|
|
623
|
-
},
|
|
624
|
-
logCloudFrontAccessLog: false,
|
|
625
|
-
});
|
|
626
|
-
};
|
|
627
|
-
expect(app).toThrowError(/Error - props.cloudFrontLoggingBucketProps.serverAccessLogsBucket was provided but logCloudFrontAccessLog was false\n/);
|
|
628
|
-
});
|
|
629
|
-
test('cloudFrontLoggingBucketAccessLogBucketProps are used correctly', () => {
|
|
630
|
-
const stack = new cdk.Stack();
|
|
631
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
632
|
-
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
633
|
-
websiteErrorDocument: 'placeholder',
|
|
634
|
-
websiteIndexDocument: 'placeholde-two'
|
|
635
|
-
}
|
|
636
|
-
});
|
|
637
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
638
|
-
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
639
|
-
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
640
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
641
|
-
WebsiteConfiguration: {
|
|
642
|
-
ErrorDocument: 'placeholder',
|
|
643
|
-
IndexDocument: 'placeholde-two'
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
|
-
});
|
|
647
|
-
test('If existing CloudFront Log bucket S3 Access Logging bucket is provided, it is used correctly', () => {
|
|
648
|
-
const stack = new cdk.Stack();
|
|
649
|
-
const testName = 'cf-log-s3-log';
|
|
650
|
-
const cfLogS3AccessLogBucket = new s3.Bucket(stack, 'cf-log-s3-access-log-bucket', {
|
|
651
|
-
bucketName: testName
|
|
652
|
-
});
|
|
653
|
-
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
654
|
-
cloudFrontLoggingBucketProps: {
|
|
655
|
-
serverAccessLogsBucket: cfLogS3AccessLogBucket
|
|
656
|
-
}
|
|
657
|
-
});
|
|
658
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
659
|
-
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
660
|
-
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
661
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
662
|
-
BucketName: testName
|
|
663
|
-
});
|
|
664
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
665
|
-
LoggingConfiguration: {
|
|
666
|
-
DestinationBucketName: {
|
|
667
|
-
Ref: "cflogs3accesslogbucketDE374C27"
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
});
|
|
672
|
-
test('cloudFrontLoggingBucketAccessLogBucket property is set correctly', () => {
|
|
673
|
-
const stack = new cdk.Stack();
|
|
674
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
675
|
-
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
676
|
-
websiteErrorDocument: 'placeholder',
|
|
677
|
-
websiteIndexDocument: 'placeholde-two'
|
|
678
|
-
}
|
|
679
|
-
});
|
|
680
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
681
|
-
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
682
|
-
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
683
|
-
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
684
|
-
WebsiteConfiguration: {
|
|
685
|
-
ErrorDocument: 'placeholder',
|
|
686
|
-
IndexDocument: 'placeholde-two'
|
|
687
|
-
}
|
|
688
|
-
});
|
|
689
|
-
expect(construct.cloudFrontLoggingBucketAccessLogBucket).toBeDefined();
|
|
690
|
-
expect(construct.cloudFrontLoggingBucketAccessLogBucket.bucketName).toBeDefined();
|
|
691
|
-
});
|
|
692
|
-
test('logCloudFrontAccessLog property is used correctly', () => {
|
|
693
|
-
const stack = new cdk.Stack();
|
|
694
|
-
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
695
|
-
logCloudFrontAccessLog: false
|
|
696
|
-
});
|
|
697
|
-
const template = assertions_1.Template.fromStack(stack);
|
|
698
|
-
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
699
|
-
template.resourceCountIs("AWS::S3::Bucket", 3);
|
|
700
|
-
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
701
|
-
expect(construct.cloudFrontLoggingBucketAccessLogBucket).not.toBeDefined();
|
|
702
|
-
});
|
|
703
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5jbG91ZGZyb250LW9haS1zMy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGVzdC5jbG91ZGZyb250LW9haS1zMy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7R0FXRzs7QUFFSCx1REFBeUQ7QUFDekQseUNBQXlDO0FBQ3pDLG1DQUFtQztBQUNuQyw2Q0FBNkQ7QUFDN0QsZ0NBQXVFO0FBQ3ZFLDBEQUEwRDtBQUMxRCwyREFBMkQ7QUFDM0QsaURBQTBDO0FBRTFDLFNBQVMsTUFBTSxDQUFDLEtBQWdCLEVBQUUsS0FBZ0M7SUFDaEUsT0FBTyxJQUFJLHlCQUFtQixDQUFDLEtBQUssRUFBRSx3QkFBd0IsRUFBRTtRQUM5RCxXQUFXLEVBQUU7WUFDWCxhQUFhLEVBQUUsR0FBRyxDQUFDLGFBQWEsQ0FBQyxPQUFPO1NBQ3pDO1FBQ0QsR0FBRyxLQUFLO0tBQ1QsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELElBQUksQ0FBQyw2Q0FBNkMsRUFBRSxHQUFHLEVBQUU7SUFDdkQsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDOUIsTUFBTSxTQUFTLEdBQUcsSUFBSSx5QkFBbUIsQ0FBQyxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFL0UsTUFBTSxDQUFDLFNBQVMsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzFELE1BQU0sQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNuRCxNQUFNLENBQUMsU0FBUyxDQUFDLHVCQUF1QixDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDeEQsTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUN6QyxNQUFNLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFD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QVcsRUFBRSxDQUFDO0FBQ3JGLENBQUMsQ0FBQyxDQUFDO0FBRUgsSUFBSSxDQUFDLG1EQUFtRCxFQUFFLEdBQUcsRUFBRTtJQUM3RCxNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUU5QixNQUFNLFNBQVMsR0FBRyxJQUFJLHlCQUFtQixDQUFDLEtBQUssRUFBRSxtQkFBbUIsRUFBRTtRQUNwRSxzQkFBc0IsRUFBRSxLQUFLO0tBQzlCLENBQUMsQ0FBQztJQUVILE1BQU0sUUFBUSxHQUFHLHFCQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBRTNDLHlIQUF5SDtJQUN6SCxRQUFRLENBQUMsZUFBZSxDQUFDLGlCQUFpQixFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sQ0FBQyxTQUFTLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUN4RCxNQUFNLENBQUMsU0FBUyxDQUFDLHNDQUFzQyxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQzdFLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiAgQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIikuIFlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2VcbiAqICB3aXRoIHRoZSBMaWNlbnNlLiBBIGNvcHkgb2YgdGhlIExpY2Vuc2UgaXMgbG9jYXRlZCBhdFxuICpcbiAqICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogIG9yIGluIHRoZSAnbGljZW5zZScgZmlsZSBhY2NvbXBhbnlpbmcgdGhpcyBmaWxlLiBUaGlzIGZpbGUgaXMgZGlzdHJpYnV0ZWQgb24gYW4gJ0FTIElTJyBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTXG4gKiAgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZXhwcmVzcyBvciBpbXBsaWVkLiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnNcbiAqICBhbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHsgTWF0Y2gsIFRlbXBsYXRlIH0gZnJvbSBcImF3cy1jZGstbGliL2Fzc2VydGlvbnNcIjtcbmltcG9ydCAqIGFzIHMzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgKiBhcyBjZGsgZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgeyBEdXJhdGlvbiwgUmVtb3ZhbFBvbGljeSwgU3RhY2sgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IENsb3VkRnJvbnRUb09haVRvUzMsIENsb3VkRnJvbnRUb09haVRvUzNQcm9wcyB9IGZyb20gXCIuLi9saWJcIjtcbmltcG9ydCAqIGFzIGFjbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyJztcbmltcG9ydCAqIGFzIGRlZmF1bHRzIGZyb20gJ0Bhd3Mtc29sdXRpb25zLWNvbnN0cnVjdHMvY29yZSc7XG5pbXBvcnQgeyBLZXkgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWttc1wiO1xuXG5mdW5jdGlvbiBkZXBsb3koc3RhY2s6IGNkay5TdGFjaywgcHJvcHM/OiBDbG91ZEZyb250VG9PYWlUb1MzUHJvcHMpIHtcbiAgcmV0dXJuIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LW9haS1zMycsIHtcbiAgICBidWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICB9LFxuICAgIC4uLnByb3BzXG4gIH0pO1xufVxuXG50ZXN0KCdjb25zdHJ1Y3QgZGVmYXVsdHMgc2V0IHByb3BlcnRpZXMgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgY29uc3RydWN0ID0gbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtb2FpLXMzJywge30pO1xuXG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udFdlYkRpc3RyaWJ1dGlvbikudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250RnVuY3Rpb24pLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuczNCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuczNMb2dnaW5nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LnMzQnVja2V0SW50ZXJmYWNlKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0Lm9yaWdpbkFjY2Vzc0lkZW50aXR5KS50b0JlRGVmaW5lZCgpO1xufSk7XG5cbnRlc3QoJ2NoZWNrIHMzQnVja2V0IGRlZmF1bHQgZW5jcnlwdGlvbicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGRlcGxveShzdGFjayk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgQnVja2V0RW5jcnlwdGlvbjoge1xuICAgICAgU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uOiBbe1xuICAgICAgICBTZXJ2ZXJTaWRlRW5jcnlwdGlvbkJ5RGVmYXVsdDoge1xuICAgICAgICAgIFNTRUFsZ29yaXRobTogXCJBRVMyNTZcIlxuICAgICAgICB9XG4gICAgICB9XVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnY2hlY2sgdGhhdCBhbiBPQUkgaXMgY3JlYXRlZCcsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGRlcGxveShzdGFjayk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgT3JpZ2luczogW1xuICAgICAgICB7XG4gICAgICAgICAgUzNPcmlnaW5Db25maWc6IHtcbiAgICAgICAgICAgIE9yaWdpbkFjY2Vzc0lkZW50aXR5OiBNYXRjaC5hbnlWYWx1ZSgpXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCdjb25maXJtIE5PIE9BQyBpcyBjcmVhdGVkJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgZGVwbG95KHN0YWNrKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIHRlbXBsYXRlLnJlc291cmNlUHJvcGVydGllc0NvdW50SXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBPcmlnaW5zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBPcmlnaW5BY2Nlc3NDb250cm9sSWQ6IE1hdGNoLmFueVZhbHVlKCksXG4gICAgICAgIH1cbiAgICAgIF1cbiAgICB9XG4gIH0sIDApO1xufSk7XG5cbnRlc3QoJ2NoZWNrIHMzQnVja2V0IHB1YmxpYyBhY2Nlc3MgYmxvY2sgY29uZmlndXJhdGlvbicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGRlcGxveShzdGFjayk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgUHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uOiB7XG4gICAgICBCbG9ja1B1YmxpY0FjbHM6IHRydWUsXG4gICAgICBCbG9ja1B1YmxpY1BvbGljeTogdHJ1ZSxcbiAgICAgIElnbm9yZVB1YmxpY0FjbHM6IHRydWUsXG4gICAgICBSZXN0cmljdFB1YmxpY0J1Y2tldHM6IHRydWVcbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoJ3Rlc3QgczNCdWNrZXQgb3ZlcnJpZGUgcHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBwcm9wczogQ2xvdWRGcm9udFRvT2FpVG9TM1Byb3BzID0ge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICBibG9ja1B1YmxpY0FjY2Vzczoge1xuICAgICAgICBibG9ja1B1YmxpY0FjbHM6IGZhbHNlLFxuICAgICAgICBibG9ja1B1YmxpY1BvbGljeTogdHJ1ZSxcbiAgICAgICAgaWdub3JlUHVibGljQWNsczogZmFsc2UsXG4gICAgICAgIHJlc3RyaWN0UHVibGljQnVja2V0czogdHJ1ZVxuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1vYWktczMnLCBwcm9wcyk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjoge1xuICAgICAgQmxvY2tQdWJsaWNBY2xzOiBmYWxzZSxcbiAgICAgIEJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgSWdub3JlUHVibGljQWNsczogZmFsc2UsXG4gICAgICBSZXN0cmljdFB1YmxpY0J1Y2tldHM6IHRydWVcbiAgICB9LFxuICB9KTtcbn0pO1xuXG50ZXN0KCdjaGVjayBleGlzdGluZyBidWNrZXQnLCAoKSA9PiB7XG4gIGNvbnN0IGJ1Y2tldE5hbWUgPSBcIm15LWJ1Y2tldFwiO1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBleGlzdGluZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssIGJ1Y2tldE5hbWUsIHtcbiAgICBidWNrZXROYW1lOiAnbXktYnVja2V0J1xuICB9KTtcblxuICBjb25zdCBwcm9wczogQ2xvdWRGcm9udFRvT2FpVG9TM1Byb3BzID0ge1xuICAgIGV4aXN0aW5nQnVja2V0T2JqOiBleGlzdGluZ0J1Y2tldFxuICB9O1xuXG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LW9haS1zMycsIHByb3BzKTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCB7XG4gICAgQnVja2V0TmFtZTogYnVja2V0TmFtZVxuICB9KTtcbn0pO1xuXG50ZXN0KCdjaGVjayBwcm9wZXJ0aWVzJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBjb25zdHJ1Y3Q6IENsb3VkRnJvbnRUb09haVRvUzMgPSBkZXBsb3koc3RhY2spO1xuXG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udFdlYkRpc3RyaWJ1dGlvbikudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0J1Y2tldCkudG9CZURlZmluZWQoKTtcbn0pO1xuXG50ZXN0KFwiQ29uZmlybSBDaGVja1MzUHJvcHMgaXMgY2FsbGVkXCIsICgpID0+IHtcbiAgLy8gU3RhY2tcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgdGVzdEJ1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICd0ZXN0LWJ1Y2tldCcsIHt9KTtcblxuICBjb25zdCBhcHAgPSAoKSA9PiB7XG4gICAgLy8gSGVscGVyIGRlY2xhcmF0aW9uXG4gICAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssIFwiYmFkLXMzLWFyZ3NcIiwge1xuICAgICAgZXhpc3RpbmdCdWNrZXRPYmo6IHRlc3RCdWNrZXQsXG4gICAgICBidWNrZXRQcm9wczoge1xuICAgICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1lcbiAgICAgIH0sXG4gICAgfSk7XG4gIH07XG4gIC8vIEFzc2VydGlvblxuICBleHBlY3QoYXBwKS50b1Rocm93RXJyb3IoJ0Vycm9yIC0gRWl0aGVyIHByb3ZpZGUgYnVja2V0UHJvcHMgb3IgZXhpc3RpbmdCdWNrZXRPYmosIGJ1dCBub3QgYm90aC5cXG4nKTtcbn0pO1xuXG50ZXN0KFwiVGVzdCBleGlzdGluZ0J1Y2tldE9ialwiLCAoKSA9PiB7XG4gIC8vIFN0YWNrXG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBjb25zdHJ1Y3Q6IENsb3VkRnJvbnRUb09haVRvUzMgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgXCJleGlzdGluZ0lCdWNrZXRcIiwge1xuICAgIGV4aXN0aW5nQnVja2V0T2JqOiBzMy5CdWNrZXQuZnJvbUJ1Y2tldE5hbWUoc3RhY2ssICdteWJ1Y2tldCcsICdteWJ1Y2tldCcpXG4gIH0pO1xuICAvLyBBc3NlcnRpb25cbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250V2ViRGlzdHJpYnV0aW9uKS50b0JlRGVmaW5lZCgpO1xuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCAyKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgT3JpZ2luczogW1xuICAgICAgICB7XG4gICAgICAgICAgRG9tYWluTmFtZToge1xuICAgICAgICAgICAgXCJGbjo6Sm9pblwiOiBbXG4gICAgICAgICAgICAgIFwiXCIsXG4gICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICBcIm15YnVja2V0LnMzLlwiLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIFJlZjogXCJBV1M6OlJlZ2lvblwiXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBcIi5cIixcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBSZWY6IFwiQVdTOjpVUkxTdWZmaXhcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0sXG4gICAgICAgICAgSWQ6IFwiZXhpc3RpbmdJQnVja2V0Q2xvdWRGcm9udERpc3RyaWJ1dGlvbk9yaWdpbjFENTg0OTEyNVwiLFxuICAgICAgICAgIFMzT3JpZ2luQ29uZmlnOiB7XG4gICAgICAgICAgICBPcmlnaW5BY2Nlc3NJZGVudGl0eTogTWF0Y2guYW55VmFsdWUoKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgndGVzdCBjbG91ZGZyb250IHdpdGggY3VzdG9tIGRvbWFpbiBuYW1lcycsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgY2VydGlmaWNhdGUgPSBhY20uQ2VydGlmaWNhdGUuZnJvbUNlcnRpZmljYXRlQXJuKHN0YWNrLCAnQ2VydCcsICdhcm46JHtBd3MuUEFSVElUSU9OfTphY206dXMtZWFzdC0xOjEyMzQ1Njc4OTAxMjpjZXJ0aWZpY2F0ZS8xMTExMjIyMi0zMzMzLTEyMzQtMTIzNC0xMjM0NTY3ODkwMTInKTtcblxuICBjb25zdCBwcm9wczogQ2xvdWRGcm9udFRvT2FpVG9TM1Byb3BzID0ge1xuICAgIGNsb3VkRnJvbnREaXN0cmlidXRpb25Qcm9wczoge1xuICAgICAgZG9tYWluTmFtZXM6IFsnbXlkb21haW5zJ10sXG4gICAgICBjZXJ0aWZpY2F0ZVxuICAgIH1cbiAgfTtcblxuICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1vYWktczMnLCBwcm9wcyk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBBbGlhc2VzOiBbXG4gICAgICAgIFwibXlkb21haW5zXCJcbiAgICAgIF1cbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoXCJUZXN0IHRoYXQgYSBDTUsgb24gdGhlIGJ1Y2tldCB0aHJvd3MgYW4gZXJyb3JcIiwgKCkgPT4ge1xuICAvLyBTdGFja1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgZXhpc3RpbmdCdWNrZXQgPSBkZWZhdWx0cy5DcmVhdGVTY3JhcEJ1Y2tldChzdGFjaywgXCJlbmNyeXB0ZWRcIiwge1xuICAgIGVuY3J5cHRpb246IHMzLkJ1Y2tldEVuY3J5cHRpb24uS01TLFxuICAgIGVuY3J5cHRpb25LZXk6IG5ldyBLZXkoc3RhY2ssICdLZXknLCB7XG4gICAgICBlbmFibGVLZXlSb3RhdGlvbjogdHJ1ZVxuICAgIH0pXG4gIH0pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgXCJleGlzdGluZ0lCdWNrZXRcIiwge1xuICAgICAgZXhpc3RpbmdCdWNrZXRPYmo6IGV4aXN0aW5nQnVja2V0XG4gICAgfSk7XG4gIH07XG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcigvRXJyb3IgLSBidWNrZXRzIGNhbm5vdCB1c2UgQ01LcyB3aXRoIE9BSXNcXG4vKTtcbn0pO1xuXG50ZXN0KFwiVGVzdCB0aGF0IGEgQ01LIGluIHRoZSBwcm9wcyB0aHJvd3MgYW4gZXJyb3JcIiwgKCkgPT4ge1xuICAvLyBTdGFja1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgZW5jcnlwdGlvbktleSA9IG5ldyBLZXkoc3RhY2ssICdjbWtLZXknLCB7XG4gICAgZW5hYmxlS2V5Um90YXRpb246IHRydWUsXG4gICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZXG4gIH0pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgXCJleGlzdGluZ0lCdWNrZXRcIiwge1xuICAgICAgYnVja2V0UHJvcHM6IHtcbiAgICAgICAgZW5mb3JjZVNTTDogdHJ1ZSxcbiAgICAgICAgZW5jcnlwdGlvbjogczMuQnVja2V0RW5jcnlwdGlvbi5LTVMsXG4gICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgIH0sXG4gICAgfSk7XG4gIH07XG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcigvRXJyb3IgLSBidWNrZXRzIGNhbm5vdCB1c2UgQ01LcyB3aXRoIE9BSXNcXG4vKTtcbn0pO1xuXG50ZXN0KCdDbG91ZGZyb250IGxvZ2dpbmcgYnVja2V0IHdpdGggZGVzdHJveSByZW1vdmFsIHBvbGljeSBhbmQgYXV0byBkZWxldGUgb2JqZWN0cycsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgY2xvdWRmcm9udExvZ0J1Y2tldE5hbWUgPSAnY2YtbG9nLWJ1Y2tldCc7XG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlLFxuICAgICAgYnVja2V0TmFtZTogY2xvdWRmcm9udExvZ0J1Y2tldE5hbWVcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBPd25lcnNoaXBDb250cm9sczogeyBSdWxlczogW3sgT2JqZWN0T3duZXJzaGlwOiBcIk9iamVjdFdyaXRlclwiIH1dIH0sXG4gICAgQnVja2V0TmFtZTogY2xvdWRmcm9udExvZ0J1Y2tldE5hbWUsXG4gIH0pO1xuXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkN1c3RvbTo6UzNBdXRvRGVsZXRlT2JqZWN0c1wiLCB7XG4gICAgU2VydmljZVRva2VuOiB7XG4gICAgICBcIkZuOjpHZXRBdHRcIjogW1xuICAgICAgICBcIkN1c3RvbVMzQXV0b0RlbGV0ZU9iamVjdHNDdXN0b21SZXNvdXJjZVByb3ZpZGVySGFuZGxlcjlEOTAxODRGXCIsXG4gICAgICAgIFwiQXJuXCJcbiAgICAgIF1cbiAgICB9LFxuICAgIEJ1Y2tldE5hbWU6IHtcbiAgICAgIFJlZjogTWF0Y2guc3RyaW5nTGlrZVJlZ2V4cChcImNsb3VkZnJvbnRvYWlzM0Nsb3VkZnJvbnRMb2dnaW5nQnVja2V0XCIpXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCdzMyBidWNrZXQgd2l0aCBvbmUgY29udGVudCBidWNrZXQgYW5kIG5vIGFjY2VzcyBsb2dnaW5nIG9mIENPTlRFTlQgYnVja2V0JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgIH0sXG4gICAgbG9nUzNBY2Nlc3NMb2dzOiBmYWxzZVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIC8vIENvbnRlbnQgYnVja2V0K0Nsb3VkZnJvbnQgTG9ncyBidWNrZXQrXG4gIC8vIEFjY2VzcyBMb2cgYnVja2V0IGZvciBDbG91ZGZyb250IExvZ3MgYnVja2V0ID0gMyBidWNrZXRzXG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCAzKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0xvZ2dpbmdCdWNrZXQpLnRvRXF1YWwodW5kZWZpbmVkKTtcbn0pO1xuXG50ZXN0KCdDbG91ZEZyb250IG9yaWdpbiBwYXRoIHByZXNlbnQgd2hlbiBwcm92aWRlZCcsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICdjbG91ZGZyb250LW9haS1zMycsIHtcbiAgICBvcmlnaW5QYXRoOiAnL3Rlc3RQYXRoJ1xuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uXCIsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6XG4gICAge1xuICAgICAgT3JpZ2luczogW1xuICAgICAgICB7XG4gICAgICAgICAgT3JpZ2luUGF0aDogXCIvdGVzdFBhdGhcIixcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnQ2xvdWRGcm9udCBvcmlnaW4gcGF0aCBzaG91bGQgbm90IGJlIHByZXNlbnQgaWYgbm90IHByb3ZpZGVkJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge30pO1xuXG4gIGRlZmF1bHRzLmV4cGVjdE5vbmV4aXN0ZW5jZShzdGFjaywgXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOlxuICAgIHtcbiAgICAgIE9yaWdpbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIE9yaWdpblBhdGg6IE1hdGNoLmFueVZhbHVlKCksXG4gICAgICAgIH1cbiAgICAgIF1cbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoJ1Rlc3QgdGhlIGRlcGxveW1lbnQgd2l0aCBzZWN1cml0eUhlYWRlcnNCZWhhdmlvciBpbnN0ZWFkIG9mIEhUVFAgc2VjdXJpdHkgaGVhZGVycycsICgpID0+IHtcbiAgLy8gSW5pdGlhbCBzZXR1cFxuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuICBjb25zdCB0ZXN0Q29uc3RydWN0ID0gbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGluc2VydEh0dHBTZWN1cml0eUhlYWRlcnM6IGZhbHNlLFxuICAgIHJlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzOiB7XG4gICAgICBzZWN1cml0eUhlYWRlcnNCZWhhdmlvcjoge1xuICAgICAgICBzdHJpY3RUcmFuc3BvcnRTZWN1cml0eToge1xuICAgICAgICAgIGFjY2Vzc0NvbnRyb2xNYXhBZ2U6IER1cmF0aW9uLnNlY29uZHMoNjMwNzIpLFxuICAgICAgICAgIGluY2x1ZGVTdWJkb21haW5zOiB0cnVlLFxuICAgICAgICAgIG92ZXJyaWRlOiB0cnVlLFxuICAgICAgICAgIHByZWxvYWQ6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAgY29udGVudFNlY3VyaXR5UG9saWN5OiB7XG4gICAgICAgICAgY29udGVudFNlY3VyaXR5UG9saWN5OiBcInVwZ3JhZGUtaW5zZWN1cmUtcmVxdWVzdHM7IGRlZmF1bHQtc3JjICdub25lJztcIixcbiAgICAgICAgICBvdmVycmlkZTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgLy8gQXNzZXJ0aW9uXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpSZXNwb25zZUhlYWRlcnNQb2xpY3lcIiwge1xuICAgIFJlc3BvbnNlSGVhZGVyc1BvbGljeUNvbmZpZzoge1xuICAgICAgU2VjdXJpdHlIZWFkZXJzQ29uZmlnOiB7XG4gICAgICAgIENvbnRlbnRTZWN1cml0eVBvbGljeToge1xuICAgICAgICAgIENvbnRlbnRTZWN1cml0eVBvbGljeTogXCJ1cGdyYWRlLWluc2VjdXJlLXJlcXVlc3RzOyBkZWZhdWx0LXNyYyAnbm9uZSc7XCIsXG4gICAgICAgICAgT3ZlcnJpZGU6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAgU3RyaWN0VHJhbnNwb3J0U2VjdXJpdHk6IHtcbiAgICAgICAgICBBY2Nlc3NDb250cm9sTWF4QWdlU2VjOiA2MzA3MixcbiAgICAgICAgICBJbmNsdWRlU3ViZG9tYWluczogdHJ1ZSxcbiAgICAgICAgICBPdmVycmlkZTogdHJ1ZSxcbiAgICAgICAgICBQcmVsb2FkOiB0cnVlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuICBleHBlY3QodGVzdENvbnN0cnVjdC5jbG91ZEZyb250RnVuY3Rpb24pLnRvRXF1YWwodW5kZWZpbmVkKTtcbn0pO1xuXG50ZXN0KFwidGhyb3cgZXhjZXB0aW9uIGlmIGluc2VydEh0dHBTZWN1cml0eUhlYWRlcnMgYW5kIHJlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzIGFyZSBwcm92aWRlZFwiLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGV4cGVjdCgoKSA9PiB7XG4gICAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssIFwidGVzdC1jbG91ZGZyb250LW9haS1zM1wiLCB7XG4gICAgICBpbnNlcnRIdHRwU2VjdXJpdHlIZWFkZXJzOiB0cnVlLFxuICAgICAgcmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM6IHtcbiAgICAgICAgc2VjdXJpdHlIZWFkZXJzQmVoYXZpb3I6IHtcbiAgICAgICAgICBzdHJpY3RUcmFuc3BvcnRTZWN1cml0eToge1xuICAgICAgICAgICAgYWNjZXNzQ29udHJvbE1heEFnZTogRHVyYXRpb24uc2Vjb25kcyg2MzA3MiksXG4gICAgICAgICAgICBpbmNsdWRlU3ViZG9tYWluczogdHJ1ZSxcbiAgICAgICAgICAgIG92ZXJyaWRlOiBmYWxzZSxcbiAgICAgICAgICAgIHByZWxvYWQ6IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfSkudG9UaHJvd0Vycm9yKCk7XG59KTtcblxudGVzdChcIkNvbmZpcm0gQ2hlY2tDbG91ZEZyb250UHJvcHMgaXMgYmVpbmcgY2FsbGVkXCIsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgZXhwZWN0KCgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgXCJ0ZXN0LWNsb3VkZnJvbnQtYXBpZ2F0ZXdheVwiLCB7XG4gICAgICBpbnNlcnRIdHRwU2VjdXJpdHlIZWFkZXJzOiB0cnVlLFxuICAgICAgcmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM6IHtcbiAgICAgICAgc2VjdXJpdHlIZWFkZXJzQmVoYXZpb3I6IHtcbiAgICAgICAgICBzdHJpY3RUcmFuc3BvcnRTZWN1cml0eToge1xuICAgICAgICAgICAgYWNjZXNzQ29udHJvbE1heEFnZTogRHVyYXRpb24uc2Vjb25kcyg2MzA3MiksXG4gICAgICAgICAgICBpbmNsdWRlU3ViZG9tYWluczogdHJ1ZSxcbiAgICAgICAgICAgIG92ZXJyaWRlOiBmYWxzZSxcbiAgICAgICAgICAgIHByZWxvYWQ6IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfSkudG9UaHJvd0Vycm9yKCdyZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcy5zZWN1cml0eUhlYWRlcnNCZWhhdmlvciBjYW4gb25seSBiZSBwYXNzZWQgaWYgaHR0cFNlY3VyaXR5SGVhZGVycyBpcyBzZXQgdG8gYGZhbHNlYC4nKTtcbn0pO1xuXG50ZXN0KCdUZXN0IHRoYXQgd2UgZG8gbm90IGNyZWF0ZSBhbiBBY2Nlc3MgTG9nIGJ1Y2tldCBmb3IgQ0YgbG9ncyBpZiBvbmUgaXMgcHJvdmlkZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBjZlMzQWNjZXNzTG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ2NmLXMzLWFjY2Vzcy1sb2dzJyk7XG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LW9haS1zMycsIHtcbiAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBjZlMzQWNjZXNzTG9nQnVja2V0XG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCA0KTtcblxufSk7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PVxuLy8gUzMgQ29udGVudCBCdWNrZXQgQWNjZXNzIExvZ3MgQnVja2V0XG4vLyA9PT09PT09PT09PT09PT09PT09PT1cbnRlc3QoJ1Byb3ZpZGluZyBsb2dnaW5nQnVja2V0UHJvcHMgYW5kIGV4aXN0aW5nTG9nZ2luZ0J1Y2tldCBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdsb2ctYnVja2V0Jywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgICAgYnVja2V0UHJvcHM6IHtcbiAgICAgICAgc2VydmVyQWNjZXNzTG9nc0J1Y2tldDogbG9nQnVja2V0LFxuICAgICAgfSxcbiAgICAgIGxvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgICBidWNrZXROYW1lOiAnYW55dGhpbmcnXG4gICAgICB9XG4gICAgfSk7XG4gIH07XG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcigvRXJyb3IgLSBib3RobG9nIGJ1Y2tldCBwcm9wcyBhbmQgYW4gZXhpc3RpbmcgbG9nIGJ1Y2tldCB3ZXJlIHByb3ZpZGVkLlxcbi8pO1xufSk7XG5cbnRlc3QoJ1Byb3ZpZGluZyBleGlzdGluZ0xvZ2dpbmdCdWNrZXQgYW5kIGxvZ1MzQWNjZXNzTG9ncz1mYWxzZSBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdjbG91ZGZyb250LWxvZy1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgICBidWNrZXRQcm9wczoge1xuICAgICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBsb2dCdWNrZXQsXG4gICAgICB9LFxuICAgICAgbG9nUzNBY2Nlc3NMb2dzOiBmYWxzZVxuICAgIH0pO1xuICB9O1xuICBleHBlY3QoYXBwKS50b1Rocm93RXJyb3IoL0Vycm9yIC0gbG9nUzNBY2Nlc3NMb2dzIGlzIGZhbHNlLCBidXQgYSBsb2cgYnVja2V0IHdhcyBwcm92aWRlZCBpbiBidWNrZXRQcm9wcy5cXG4vKTtcbn0pO1xuXG50ZXN0KCdQcm92aWRpbmcgbG9nZ2luZ0J1Y2tldFByb3BzIGFuZCBsb2dTM0FjY2Vzc0xvZ3M9ZmFsc2UgaXMgYW4gZXJyb3InLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgICAgbG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6ICdhbnl0aGluZydcbiAgICAgIH0sXG4gICAgICBsb2dTM0FjY2Vzc0xvZ3M6IGZhbHNlXG4gICAgfSk7XG4gIH07XG4gIC8vIE5PVEU6IFRoaXMgZXJyb3IgaXMgdGhyb3duIGJ5IENoZWNrUzNQcm9wcygpLCBub3QgQ2hlY2tDb25zdHJ1Y3RTcGVjaWZpY1Byb3BzKClcbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKC9FcnJvciAtIElmIGxvZ1MzQWNjZXNzTG9ncyBpcyBmYWxzZSwgc3VwcGx5aW5nIGxvZ2dpbmdCdWNrZXRQcm9wcyBvciBleGlzdGluZ0xvZ2dpbmdCdWNrZXRPYmogaXMgaW52YWxpZC5cXG4vKTtcbn0pO1xuXG4vLyB0ZXN0KCdObyBuZXcgbG9nZ2luZ0J1Y2tldCBpcyBjcmVhdGVkIGlmIGV4aXN0aW5nTG9nZ2luZ0J1Y2tldCBpcyBzdXBwbGllZCcsICgpID0+IHtcbnRlc3QoJ2xvZ2dpbmdCdWNrZXRQcm9wcyBpcyBzdXBwbGllZCBpcyBpbnRlZ3JhdGVkIGludG8gYXJjaGl0ZWN0dXJlIGNvcnJlY3RseScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgdGVzdE5hbWUgPSBcInRlc3QtbmFtZVwiO1xuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgIH0sXG4gICAgbG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWUsXG4gICAgICBidWNrZXROYW1lOiB0ZXN0TmFtZVxuICAgIH1cbiAgfSk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0xvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgNCk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBCdWNrZXROYW1lOiB0ZXN0TmFtZVxuICB9KTtcblxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIExvZ2dpbmdDb25maWd1cmF0aW9uOiB7XG4gICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6IHtcbiAgICAgICAgUmVmOiBNYXRjaC5zdHJpbmdMaWtlUmVnZXhwKCdjbG91ZGZyb250b2FpczNTM0xvZ2dpbmdCdWNrZXQnKVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG59KTtcbnRlc3QoJ2J1Y2tldFByb3BzOnNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQgaXMgc3VwcGxpZWQgaXMgaW50ZWdyYXRlZCBpbnRvIGFyY2hpdGVjdHVyZSBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHRlc3ROYW1lID0gJ3NvbWUtbmFtZSc7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBsb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAndGVzdC1sb2cnLCB7XG4gICAgYnVja2V0TmFtZTogdGVzdE5hbWUsXG4gIH0pO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIHNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQ6IGxvZ0J1Y2tldCxcbiAgICB9LFxuICB9KTtcblxuICBleHBlY3QoY29uc3RydWN0LnMzTG9nZ2luZ0J1Y2tldCkudG9CZURlZmluZWQoKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCA0KTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBMb2dnaW5nQ29uZmlndXJhdGlvbjoge1xuICAgICAgRGVzdGluYXRpb25CdWNrZXROYW1lOiB7XG4gICAgICAgIFJlZjogXCJ0ZXN0bG9nRTg4QjRDNkJcIlxuICAgICAgfVxuICAgIH1cbiAgfSk7XG59KTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09XG4vLyBDbG91ZEZyb250IExvZyBCdWNrZXRcbi8vID09PT09PT09PT09PT09PT09PT09PVxudGVzdCgnUHJvdmlkaW5nIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHMgYW5kIGEgbG9nIGJ1Y2tldCBpbiBjbG91ZEZyb250RGlzdHJidXRpb25Qcm9wcyBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdjbG91ZGZyb250LWxvZy1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgICBjbG91ZEZyb250RGlzdHJpYnV0aW9uUHJvcHM6IHtcbiAgICAgICAgbG9nQnVja2V0XG4gICAgICB9LFxuICAgICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZVxuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcigpO1xufSk7XG50ZXN0KCdjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzIGFyZSB1c2VkIGNvcnJlY3RseScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgdGVzdE5hbWUgPSBcInRlc3QtbmFtZVwiO1xuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZSxcbiAgICAgIGJ1Y2tldE5hbWU6IHRlc3ROYW1lXG4gICAgfVxuICB9KTtcblxuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCB7XG4gICAgQnVja2V0TmFtZTogdGVzdE5hbWVcbiAgfSk7XG5cbn0pO1xudGVzdCgnTG9nZ2luZyBkaXNhYmxlZCBpbiBDbG91ZEZyb250IHByb3BzIGlzIGhhbmRsZWQgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBjb25zdHJ1Y3QgPSBkZXBsb3koc3RhY2ssIHsgY2xvdWRGcm9udERpc3RyaWJ1dGlvblByb3BzOiB7IGVuYWJsZUxvZ2dpbmc6IGZhbHNlIH0gfSk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBPbmx5IHRoZSBjb250ZW50IGJ1Y2tldCBhbmQgaXQgUzMgQWNjZXNzIExvZyBidWNrZXQgKG5vIENsb3VkZnJvbnQgbG9nIGJ1Y2tldClcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDIpO1xuXG4gIC8vIE5vIGxvZ2dpbmcgaXMgY29uZmlndXJlZFxuICB0ZW1wbGF0ZS5yZXNvdXJjZVByb3BlcnRpZXNDb3VudElzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgTG9nZ2luZzogTWF0Y2guYW55VmFsdWUoKVxuICAgIH1cbiAgfSwgMCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXQgPT09IHVuZGVmaW5lZCk7XG59KTtcbnRlc3QoJ05vIG5ldyBDbG91ZEZyb250TG9nZ2luZ0J1Y2tldCBpcyBjcmVhdGVkIGlmIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6bG9nQnVja2V0IGlzIHN1cHBsaWVkJywgKCkgPT4ge1xuICBjb25zdCB0ZXN0TmFtZSA9ICdyYW5kb20tdmFsdWUnO1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgbG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ2Nsb3VkZnJvbnQtbG9nLWJ1Y2tldCcsIHtcbiAgICBidWNrZXROYW1lOiB0ZXN0TmFtZVxuICB9KTtcblxuICAvLyBjb25zdCBjb25zdHJ1Y3QgPVxuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGNsb3VkRnJvbnREaXN0cmlidXRpb25Qcm9wczoge1xuICAgICAgbG9nQnVja2V0XG4gICAgfSxcbiAgfSk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250TG9nZ2luZ0J1Y2tldCkudG9CZURlZmluZWQoKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIENvbnRlbnQgYnVja2V0LCBDb250ZW50IGJ1Y2tldCBTMyBBY2Nlc3MgTG9nIGJ1Y2tldCwgY2xvdWRmcm9udCBsb2cgYnVja2V0XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCAzKTtcblxuICAvLyBFbnN1cmUgb3VyIGV4aXN0aW5nIGJ1Y2tldCBoYXMgYmVlbiB1c2VkIGZvciBjbG91ZGZyb250IGxvZ2dpbmdcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgTG9nZ2luZzoge1xuICAgICAgICBCdWNrZXQ6IHtcbiAgICAgICAgICBcIkZuOjpHZXRBdHRcIjogW1xuICAgICAgICAgICAgXCJjbG91ZGZyb250bG9nYnVja2V0REY3MDU4RkJcIixcbiAgICAgICAgICAgIFwiUmVnaW9uYWxEb21haW5OYW1lXCJcbiAgICAgICAgICBdXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuXG59KTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09XG4vLyBDbG91ZEZyb250IExvZ3MgQnVja2V0IEFjY2VzcyBMb2cgQnVja2V0XG4vLyA9PT09PT09PT09PT09PT09PT09PT1cbnRlc3QoJ1Byb3ZpZGluZyBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzIGFuZCBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOnNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQgaXMgYW4gZXJyb3InLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBsb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2xvdWRmcm9udC1sb2ctYnVja2V0Jywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBsb2dCdWNrZXQsXG4gICAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlXG4gICAgICB9LFxuICAgICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wczoge1xuICAgICAgICBidWNrZXROYW1lOiAnc3BlY2ZpYy1uYW1lLWlzLWluY29uc2VxdWVudGlhbCdcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcblxuICBleHBlY3QoYXBwKS50b1Rocm93RXJyb3IoXG4gICAgL0Vycm9yIC0gYW4gZXhpc3RpbmcgQ2xvdWRGcm9udCBsb2cgYnVja2V0IFMzIGFjY2VzcyBsb2cgYnVja2V0IGFuZCBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzIHdlcmUgcHJvdmlkZWRcXG4vKTtcbn0pO1xudGVzdCgnUHJvdmlkaW5nIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHMgYW5kIGxvZ0Nsb3VkRnJvbnRBY2Nlc3NMb2c9ZmFsc2UgaXMgYW4gZXJyb3InLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgICAgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZzogZmFsc2UsXG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6ICdzcGVjZmljLW5hbWUtaXMtaW5jb25zZXF1ZW50aWFsJ1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcigvRXJyb3IgLSBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzIHdlcmUgcHJvdmlkZWQgYnV0IGxvZ0Nsb3VkRnJvbnRBY2Nlc3NMb2cgd2FzIGZhbHNlXFxuLyk7XG59KTtcbnRlc3QoJ1Byb3ZpZGluZyBsb2dDbG91ZEZyb250QWNjZXNzTG9nPWZhbHNlIGFuZCBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOnNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQgaXMgYW4gZXJyb3InLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBsb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2xvdWRmcm9udC1sb2ctYnVja2V0Jywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBsb2dCdWNrZXQsXG4gICAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlXG4gICAgICB9LFxuICAgICAgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZzogZmFsc2UsXG4gICAgfSk7XG4gIH07XG5cbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKC9FcnJvciAtIHByb3BzLmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHMuc2VydmVyQWNjZXNzTG9nc0J1Y2tldCB3YXMgcHJvdmlkZWQgYnV0IGxvZ0Nsb3VkRnJvbnRBY2Nlc3NMb2cgd2FzIGZhbHNlXFxuLyk7XG59KTtcbnRlc3QoJ2Nsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHMgYXJlIHVzZWQgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHM6IHtcbiAgICAgIHdlYnNpdGVFcnJvckRvY3VtZW50OiAncGxhY2Vob2xkZXInLFxuICAgICAgd2Vic2l0ZUluZGV4RG9jdW1lbnQ6ICdwbGFjZWhvbGRlLXR3bydcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBDb250ZW50IEJ1Y2tldCwgQ29udGVudCBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXQsIENsb3VkRnJvbnQgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0IFMzIEFjY2VzcyBMb2cgQnVja2V0XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCA0KTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBXZWJzaXRlQ29uZmlndXJhdGlvbjoge1xuICAgICAgRXJyb3JEb2N1bWVudDogJ3BsYWNlaG9sZGVyJyxcbiAgICAgIEluZGV4RG9jdW1lbnQ6ICdwbGFjZWhvbGRlLXR3bydcbiAgICB9XG4gIH0pO1xuXG59KTtcbnRlc3QoJ0lmIGV4aXN0aW5nIENsb3VkRnJvbnQgTG9nIGJ1Y2tldCBTMyBBY2Nlc3MgTG9nZ2luZyBidWNrZXQgaXMgcHJvdmlkZWQsIGl0IGlzIHVzZWQgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgdGVzdE5hbWUgPSAnY2YtbG9nLXMzLWxvZyc7XG4gIGNvbnN0IGNmTG9nUzNBY2Nlc3NMb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2YtbG9nLXMzLWFjY2Vzcy1sb2ctYnVja2V0Jywge1xuICAgIGJ1Y2tldE5hbWU6IHRlc3ROYW1lXG4gIH0pO1xuXG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgc2VydmVyQWNjZXNzTG9nc0J1Y2tldDogY2ZMb2dTM0FjY2Vzc0xvZ0J1Y2tldFxuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIENvbnRlbnQgQnVja2V0LCBDb250ZW50IEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCB7XG4gICAgQnVja2V0TmFtZTogdGVzdE5hbWVcbiAgfSk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBMb2dnaW5nQ29uZmlndXJhdGlvbjoge1xuICAgICAgRGVzdGluYXRpb25CdWNrZXROYW1lOiB7XG4gICAgICAgIFJlZjogXCJjZmxvZ3MzYWNjZXNzbG9nYnVja2V0REUzNzRDMjdcIlxuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbn0pO1xuXG50ZXN0KCdjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldCBwcm9wZXJ0eSBpcyBzZXQgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHM6IHtcbiAgICAgIHdlYnNpdGVFcnJvckRvY3VtZW50OiAncGxhY2Vob2xkZXInLFxuICAgICAgd2Vic2l0ZUluZGV4RG9jdW1lbnQ6ICdwbGFjZWhvbGRlLXR3bydcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBDb250ZW50IEJ1Y2tldCwgQ29udGVudCBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXQsIENsb3VkRnJvbnQgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0IFMzIEFjY2VzcyBMb2cgQnVja2V0XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCA0KTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBXZWJzaXRlQ29uZmlndXJhdGlvbjoge1xuICAgICAgRXJyb3JEb2N1bWVudDogJ3BsYWNlaG9sZGVyJyxcbiAgICAgIEluZGV4RG9jdW1lbnQ6ICdwbGFjZWhvbGRlLXR3bydcbiAgICB9XG4gIH0pO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0IS5idWNrZXROYW1lKS50b0JlRGVmaW5lZCgpO1xufSk7XG5cbnRlc3QoJ2xvZ0Nsb3VkRnJvbnRBY2Nlc3NMb2cgcHJvcGVydHkgaXMgdXNlZCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZzogZmFsc2VcbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIENvbnRlbnQgQnVja2V0LCBDb250ZW50IEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDMpO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0KS5ub3QudG9CZURlZmluZWQoKTtcbn0pO1xuIl19
|