@cdklabs/cdk-appmod-catalog-blueprints 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +8644 -0
- package/LICENSE +202 -0
- package/README.md +212 -0
- package/lib/document-processing/agentic-document-processing.d.ts +16 -0
- package/lib/document-processing/agentic-document-processing.js +90 -0
- package/lib/document-processing/base-document-processing.d.ts +189 -0
- package/lib/document-processing/base-document-processing.js +509 -0
- package/lib/document-processing/bedrock-document-processing.d.ts +167 -0
- package/lib/document-processing/bedrock-document-processing.js +297 -0
- package/lib/document-processing/index.d.ts +3 -0
- package/lib/document-processing/index.js +20 -0
- package/lib/document-processing/resources/default-bedrock-invoke/index.py +63 -0
- package/lib/document-processing/resources/default-bedrock-invoke/requirements.txt +4 -0
- package/lib/document-processing/resources/default-doc-retrieval-lambda/index.mjs +92 -0
- package/lib/document-processing/resources/default-doc-retrieval-lambda/package.json +10 -0
- package/lib/document-processing/resources/default-error-handler/index.js +46 -0
- package/lib/document-processing/resources/default-error-handler/package.json +4 -0
- package/lib/document-processing/resources/default-image-processor/classifier.mjs +665 -0
- package/lib/document-processing/resources/default-image-processor/extractors.mjs +465 -0
- package/lib/document-processing/resources/default-image-processor/index.mjs +143 -0
- package/lib/document-processing/resources/default-image-processor/package-lock.json +12 -0
- package/lib/document-processing/resources/default-image-processor/package.json +4 -0
- package/lib/document-processing/resources/default-image-validator/index.mjs +76 -0
- package/lib/document-processing/resources/default-image-validator/package-lock.json +154 -0
- package/lib/document-processing/resources/default-image-validator/package.json +7 -0
- package/lib/document-processing/resources/default-pdf-processor/index.js +46 -0
- package/lib/document-processing/resources/default-pdf-validator/index.js +36 -0
- package/lib/document-processing/resources/default-sqs-consumer/index.py +111 -0
- package/lib/document-processing/resources/default-sqs-consumer/requirements.txt +4 -0
- package/lib/document-processing/resources/default-sqs-consumer/sample_payload.json +20 -0
- package/lib/document-processing/resources/default-sqs-consumer/sample_payload_multi.json +24 -0
- package/lib/document-processing/resources/default-strands-agent/index.py +111 -0
- package/lib/document-processing/resources/default-strands-agent/requirements.txt +6 -0
- package/lib/document-processing/tests/agentic-document-processing-nag.test.d.ts +1 -0
- package/lib/document-processing/tests/agentic-document-processing-nag.test.js +107 -0
- package/lib/document-processing/tests/agentic-document-processing.test.d.ts +1 -0
- package/lib/document-processing/tests/agentic-document-processing.test.js +125 -0
- package/lib/document-processing/tests/bedrock-document-processing-nag.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing-nag.test.js +101 -0
- package/lib/document-processing/tests/bedrock-document-processing.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing.test.js +79 -0
- package/lib/framework/custom-resource/default-runtimes.d.ts +21 -0
- package/lib/framework/custom-resource/default-runtimes.js +34 -0
- package/lib/framework/custom-resource/index.d.ts +1 -0
- package/lib/framework/custom-resource/index.js +18 -0
- package/lib/framework/foundation/access-log.d.ts +69 -0
- package/lib/framework/foundation/access-log.js +121 -0
- package/lib/framework/foundation/eventbridge-broker.d.ts +18 -0
- package/lib/framework/foundation/eventbridge-broker.js +42 -0
- package/lib/framework/foundation/index.d.ts +3 -0
- package/lib/framework/foundation/index.js +20 -0
- package/lib/framework/foundation/network.d.ts +19 -0
- package/lib/framework/foundation/network.js +83 -0
- package/lib/framework/index.d.ts +2 -0
- package/lib/framework/index.js +19 -0
- package/lib/framework/quickstart/base-quickstart.d.ts +30 -0
- package/lib/framework/quickstart/base-quickstart.js +30 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +21 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/utilities/cdk-nag-config.d.ts +42 -0
- package/lib/utilities/cdk-nag-config.js +194 -0
- package/lib/utilities/data-loader-lambda/index.py +282 -0
- package/lib/utilities/data-loader-lambda/requirements.txt +3 -0
- package/lib/utilities/data-loader.d.ts +173 -0
- package/lib/utilities/data-loader.js +447 -0
- package/lib/utilities/index.d.ts +3 -0
- package/lib/utilities/index.js +20 -0
- package/lib/utilities/lambda-iam-utils.d.ts +145 -0
- package/lib/utilities/lambda-iam-utils.js +235 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.d.ts +42 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.js +53 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.ts +88 -0
- package/lib/utilities/observability/bedrock-observability.d.ts +18 -0
- package/lib/utilities/observability/bedrock-observability.js +131 -0
- package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.d.ts +6 -0
- package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.js +22 -0
- package/lib/utilities/observability/index.d.ts +6 -0
- package/lib/utilities/observability/index.js +25 -0
- package/lib/utilities/observability/lambda-observability-property-injector.d.ts +8 -0
- package/lib/utilities/observability/lambda-observability-property-injector.js +43 -0
- package/lib/utilities/observability/log-group-data-protection-props.d.ts +19 -0
- package/lib/utilities/observability/log-group-data-protection-props.js +5 -0
- package/lib/utilities/observability/observability.d.ts +83 -0
- package/lib/utilities/observability/observability.js +278 -0
- package/lib/utilities/observability/observable.d.ts +32 -0
- package/lib/utilities/observability/observable.js +3 -0
- package/lib/utilities/observability/powertools-config.d.ts +3 -0
- package/lib/utilities/observability/powertools-config.js +25 -0
- package/lib/utilities/observability/resources/bedrock-manage-logging-configuration/index.py +27 -0
- package/lib/utilities/observability/state-machine-observability-property-injector.d.ts +8 -0
- package/lib/utilities/observability/state-machine-observability-property-injector.js +49 -0
- package/lib/utilities/tests/data-loader-nag.test.d.ts +1 -0
- package/lib/utilities/tests/data-loader-nag.test.js +432 -0
- package/lib/utilities/tests/data-loader.test.d.ts +1 -0
- package/lib/utilities/tests/data-loader.test.js +284 -0
- package/lib/webapp/frontend-construct.d.ts +136 -0
- package/lib/webapp/frontend-construct.js +253 -0
- package/lib/webapp/index.d.ts +1 -0
- package/lib/webapp/index.js +18 -0
- package/lib/webapp/tests/frontend-construct-nag.test.d.ts +1 -0
- package/lib/webapp/tests/frontend-construct-nag.test.js +266 -0
- package/lib/webapp/tests/frontend-construct.test.d.ts +1 -0
- package/lib/webapp/tests/frontend-construct.test.js +385 -0
- package/package.json +183 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.Frontend = exports.DEFAULT_SPA_ERROR_RESPONSES = void 0;
|
|
5
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
6
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
7
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
10
|
+
const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront");
|
|
11
|
+
const aws_cloudfront_origins_1 = require("aws-cdk-lib/aws-cloudfront-origins");
|
|
12
|
+
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
13
|
+
const aws_route53_1 = require("aws-cdk-lib/aws-route53");
|
|
14
|
+
const aws_route53_targets_1 = require("aws-cdk-lib/aws-route53-targets");
|
|
15
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
|
16
|
+
const aws_s3_assets_1 = require("aws-cdk-lib/aws-s3-assets");
|
|
17
|
+
const aws_s3_deployment_1 = require("aws-cdk-lib/aws-s3-deployment");
|
|
18
|
+
const constructs_1 = require("constructs");
|
|
19
|
+
const utilities_1 = require("../utilities");
|
|
20
|
+
/**
|
|
21
|
+
* Default CloudFront error responses for Single Page Applications
|
|
22
|
+
*/
|
|
23
|
+
exports.DEFAULT_SPA_ERROR_RESPONSES = [
|
|
24
|
+
{
|
|
25
|
+
httpStatus: 403,
|
|
26
|
+
responseHttpStatus: 200,
|
|
27
|
+
responsePagePath: '/index.html',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
httpStatus: 404,
|
|
31
|
+
responseHttpStatus: 200,
|
|
32
|
+
responsePagePath: '/index.html',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* Frontend construct that deploys a frontend application to S3 and CloudFront
|
|
37
|
+
*
|
|
38
|
+
* This construct provides a complete solution for hosting static frontend applications
|
|
39
|
+
* with the following features:
|
|
40
|
+
* - S3 bucket for hosting static assets with security best practices
|
|
41
|
+
* - CloudFront distribution for global content delivery
|
|
42
|
+
* - Optional custom domain with SSL certificate
|
|
43
|
+
* - Automatic build process execution
|
|
44
|
+
* - SPA-friendly error handling by default
|
|
45
|
+
* - Security configurations
|
|
46
|
+
*/
|
|
47
|
+
class Frontend extends constructs_1.Construct {
|
|
48
|
+
/**
|
|
49
|
+
* Creates a new Frontend
|
|
50
|
+
* @param scope The construct scope
|
|
51
|
+
* @param id The construct ID
|
|
52
|
+
* @param props The frontend properties
|
|
53
|
+
*/
|
|
54
|
+
constructor(scope, id, props) {
|
|
55
|
+
super(scope, id);
|
|
56
|
+
if (props.enableObservability) {
|
|
57
|
+
aws_cdk_lib_1.PropertyInjectors.of(this).add(new utilities_1.CloudfrontDistributionObservabilityPropertyInjector());
|
|
58
|
+
}
|
|
59
|
+
// Validate required parameters
|
|
60
|
+
this._validateProps(props);
|
|
61
|
+
// Get removal policy with default
|
|
62
|
+
const removalPolicy = props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY;
|
|
63
|
+
// Create asset for source code with optional bundling
|
|
64
|
+
if (!props.skipBuild) {
|
|
65
|
+
this.asset = this._createAsset(props);
|
|
66
|
+
}
|
|
67
|
+
// Create S3 bucket for hosting
|
|
68
|
+
this.bucket = new aws_s3_1.Bucket(this, 'FrontendBucket', {
|
|
69
|
+
encryption: aws_s3_1.BucketEncryption.S3_MANAGED,
|
|
70
|
+
blockPublicAccess: aws_s3_1.BlockPublicAccess.BLOCK_ALL,
|
|
71
|
+
removalPolicy: removalPolicy,
|
|
72
|
+
autoDeleteObjects: removalPolicy === aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
73
|
+
});
|
|
74
|
+
// Create CloudFront distribution
|
|
75
|
+
this.distribution = this._createDistribution(props, removalPolicy);
|
|
76
|
+
// Deploy frontend assets to S3
|
|
77
|
+
const buildOutputDirectory = props.buildOutputDirectory || path.join(props.sourceDirectory, 'build');
|
|
78
|
+
this.bucketDeployment = new aws_s3_deployment_1.BucketDeployment(this, 'FrontendDeployment', {
|
|
79
|
+
sources: this.asset
|
|
80
|
+
? [aws_s3_deployment_1.Source.bucket(this.asset.bucket, this.asset.s3ObjectKey)]
|
|
81
|
+
: [aws_s3_deployment_1.Source.asset(buildOutputDirectory)],
|
|
82
|
+
destinationBucket: this.bucket,
|
|
83
|
+
distribution: this.distribution,
|
|
84
|
+
distributionPaths: ['/*'],
|
|
85
|
+
});
|
|
86
|
+
this.bucketDeployment.handlerRole.addToPrincipalPolicy(new aws_iam_1.PolicyStatement({
|
|
87
|
+
effect: aws_iam_1.Effect.ALLOW,
|
|
88
|
+
actions: [
|
|
89
|
+
'cloudfront:GetInvalidation',
|
|
90
|
+
'cloudfront:CreateInvalidation',
|
|
91
|
+
],
|
|
92
|
+
resources: ['*'],
|
|
93
|
+
}));
|
|
94
|
+
// Note: BucketDeployment doesn't support applyRemovalPolicy directly
|
|
95
|
+
// It will be cleaned up when the bucket is deleted due to autoDeleteObjects
|
|
96
|
+
// Setup custom domain if provided
|
|
97
|
+
if (props.customDomain) {
|
|
98
|
+
this.domainName = props.customDomain.domainName;
|
|
99
|
+
this._setupCustomDomain(props.customDomain, removalPolicy);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Validates the construct properties
|
|
104
|
+
* @param props The frontend properties
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
_validateProps(props) {
|
|
108
|
+
if (!props.sourceDirectory) {
|
|
109
|
+
throw new Error('sourceDirectory is required');
|
|
110
|
+
}
|
|
111
|
+
if (props.customDomain?.domainName && !props.customDomain.certificate) {
|
|
112
|
+
throw new Error('certificate is required when domainName is provided');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Creates an Asset for the frontend source code with bundling
|
|
117
|
+
* @param props The frontend properties
|
|
118
|
+
* @returns The Asset containing the built frontend
|
|
119
|
+
* @private
|
|
120
|
+
*/
|
|
121
|
+
_createAsset(props) {
|
|
122
|
+
const buildCommand = props.buildCommand || 'npm run build';
|
|
123
|
+
const buildOutputDirectory = props.buildOutputDirectory || path.join(props.sourceDirectory, 'build');
|
|
124
|
+
// Extract the build directory name from the full path
|
|
125
|
+
const buildDirName = path.basename(buildOutputDirectory);
|
|
126
|
+
const asset = new aws_s3_assets_1.Asset(this, 'FrontendAsset', {
|
|
127
|
+
path: props.sourceDirectory,
|
|
128
|
+
bundling: {
|
|
129
|
+
image: aws_cdk_lib_1.DockerImage.fromRegistry('public.ecr.aws/docker/library/node:lts-alpine'),
|
|
130
|
+
command: [
|
|
131
|
+
'sh', '-c', [
|
|
132
|
+
'cd /asset-input',
|
|
133
|
+
'npm ci --only=production',
|
|
134
|
+
buildCommand,
|
|
135
|
+
`cp -r ./${buildDirName}/* /asset-output/`,
|
|
136
|
+
].join(' && '),
|
|
137
|
+
],
|
|
138
|
+
user: 'root',
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
// Note: Asset doesn't support applyRemovalPolicy directly
|
|
142
|
+
// The underlying S3 objects will be managed by the asset bucket's removal policy
|
|
143
|
+
return asset;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Creates the CloudFront distribution
|
|
147
|
+
* @param props The frontend properties
|
|
148
|
+
* @param removalPolicy The removal policy to apply
|
|
149
|
+
* @returns The CloudFront distribution
|
|
150
|
+
* @private
|
|
151
|
+
*/
|
|
152
|
+
_createDistribution(props, removalPolicy) {
|
|
153
|
+
const errorResponses = props.errorResponses || exports.DEFAULT_SPA_ERROR_RESPONSES;
|
|
154
|
+
// Create a CloudFront function for security headers
|
|
155
|
+
const securityHeadersFunction = new aws_cloudfront_1.Function(this, 'SecurityHeadersFunction', {
|
|
156
|
+
code: aws_cloudfront_1.FunctionCode.fromInline(`
|
|
157
|
+
function handler(event) {
|
|
158
|
+
var response = event.response;
|
|
159
|
+
var headers = response.headers;
|
|
160
|
+
|
|
161
|
+
// Add security headers
|
|
162
|
+
headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload' };
|
|
163
|
+
headers['content-type-options'] = { value: 'nosniff' };
|
|
164
|
+
headers['x-frame-options'] = { value: 'DENY' };
|
|
165
|
+
headers['x-content-type-options'] = { value: 'nosniff' };
|
|
166
|
+
headers['referrer-policy'] = { value: 'strict-origin-when-cross-origin' };
|
|
167
|
+
headers['permissions-policy'] = { value: 'camera=(), microphone=(), geolocation=()' };
|
|
168
|
+
|
|
169
|
+
return response;
|
|
170
|
+
}
|
|
171
|
+
`),
|
|
172
|
+
});
|
|
173
|
+
// Apply removal policy to CloudFront function
|
|
174
|
+
securityHeadersFunction.applyRemovalPolicy(removalPolicy);
|
|
175
|
+
const distributionConfig = {
|
|
176
|
+
defaultBehavior: {
|
|
177
|
+
origin: aws_cloudfront_origins_1.S3BucketOrigin.withOriginAccessControl(this.bucket),
|
|
178
|
+
viewerProtocolPolicy: aws_cloudfront_1.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
179
|
+
functionAssociations: [
|
|
180
|
+
{
|
|
181
|
+
function: securityHeadersFunction,
|
|
182
|
+
eventType: aws_cloudfront_1.FunctionEventType.VIEWER_RESPONSE,
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
defaultRootObject: 'index.html',
|
|
187
|
+
errorResponses,
|
|
188
|
+
comment: props.distributionProps?.comment,
|
|
189
|
+
enabled: props.distributionProps?.enabled,
|
|
190
|
+
priceClass: props.distributionProps?.priceClass,
|
|
191
|
+
webAclId: props.distributionProps?.webAclId,
|
|
192
|
+
};
|
|
193
|
+
// Add custom domain configuration if provided
|
|
194
|
+
let distribution;
|
|
195
|
+
if (props.customDomain) {
|
|
196
|
+
distribution = new aws_cloudfront_1.Distribution(this, 'FrontendDistribution', {
|
|
197
|
+
...distributionConfig,
|
|
198
|
+
domainNames: [props.customDomain.domainName],
|
|
199
|
+
certificate: props.customDomain.certificate,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
distribution = new aws_cloudfront_1.Distribution(this, 'FrontendDistribution', distributionConfig);
|
|
204
|
+
}
|
|
205
|
+
// Apply removal policy to distribution
|
|
206
|
+
distribution.applyRemovalPolicy(removalPolicy);
|
|
207
|
+
return distribution;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Sets up custom domain with Route53 record
|
|
211
|
+
* @param customDomain The custom domain configuration
|
|
212
|
+
* @param removalPolicy The removal policy to apply
|
|
213
|
+
* @private
|
|
214
|
+
*/
|
|
215
|
+
_setupCustomDomain(customDomain, removalPolicy) {
|
|
216
|
+
if (customDomain.hostedZone) {
|
|
217
|
+
const aliasRecord = new aws_route53_1.ARecord(this, 'FrontendAliasRecord', {
|
|
218
|
+
zone: customDomain.hostedZone,
|
|
219
|
+
recordName: customDomain.domainName,
|
|
220
|
+
target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.CloudFrontTarget(this.distribution)),
|
|
221
|
+
});
|
|
222
|
+
// Apply removal policy to Route53 record
|
|
223
|
+
aliasRecord.applyRemovalPolicy(removalPolicy);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Gets the URL of the frontend application
|
|
228
|
+
* @returns The frontend URL
|
|
229
|
+
*/
|
|
230
|
+
url() {
|
|
231
|
+
return this.domainName
|
|
232
|
+
? `https://${this.domainName}`
|
|
233
|
+
: `https://${this.distribution.distributionDomainName}`;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Gets the CloudFront distribution domain name
|
|
237
|
+
* @returns The CloudFront domain name
|
|
238
|
+
*/
|
|
239
|
+
distributionDomainName() {
|
|
240
|
+
return this.distribution.distributionDomainName;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Gets the S3 bucket name
|
|
244
|
+
* @returns The S3 bucket name
|
|
245
|
+
*/
|
|
246
|
+
bucketName() {
|
|
247
|
+
return this.bucket.bucketName;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
exports.Frontend = Frontend;
|
|
251
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
252
|
+
Frontend[_a] = { fqn: "@cdklabs/cdk-appmod-catalog-blueprints.Frontend", version: "1.0.0" };
|
|
253
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJvbnRlbmQtY29uc3RydWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdXNlLWNhc2VzL3dlYmFwcC9mcm9udGVuZC1jb25zdHJ1Y3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxxRUFBcUU7QUFDckUsc0NBQXNDO0FBRXRDLDZCQUE2QjtBQUM3Qiw2Q0FBNEU7QUFFNUUsK0RBU29DO0FBQ3BDLCtFQUFvRTtBQUNwRSxpREFBOEQ7QUFDOUQseURBQTZFO0FBQzdFLHlFQUFtRTtBQUNuRSwrQ0FBaUY7QUFDakYsNkRBQWtEO0FBQ2xELHFFQUF5RTtBQUN6RSwyQ0FBdUM7QUFDdkMsNENBQW1GO0FBRW5GOztHQUVHO0FBQ1UsUUFBQSwyQkFBMkIsR0FBb0I7SUFDMUQ7UUFDRSxVQUFVLEVBQUUsR0FBRztRQUNmLGtCQUFrQixFQUFFLEdBQUc7UUFDdkIsZ0JBQWdCLEVBQUUsYUFBYTtLQUNoQztJQUNEO1FBQ0UsVUFBVSxFQUFFLEdBQUc7UUFDZixrQkFBa0IsRUFBRSxHQUFHO1FBQ3ZCLGdCQUFnQixFQUFFLGFBQWE7S0FDaEM7Q0FDRixDQUFDO0FBdURGOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBYSxRQUFTLFNBQVEsc0JBQVM7SUFZckM7Ozs7O09BS0c7SUFDSCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQW9CO1FBQzVELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsSUFBSSxLQUFLLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUM5QiwrQkFBaUIsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUM1QixJQUFJLCtEQUFtRCxFQUFFLENBQzFELENBQUM7UUFDSixDQUFDO1FBRUQsK0JBQStCO1FBQy9CLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFM0Isa0NBQWtDO1FBQ2xDLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxhQUFhLElBQUksMkJBQWEsQ0FBQyxPQUFPLENBQUM7UUFFbkUsc0RBQXNEO1FBQ3RELElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDckIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFFRCwrQkFBK0I7UUFDL0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLGVBQU0sQ0FBQyxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7WUFDL0MsVUFBVSxFQUFFLHlCQUFnQixDQUFDLFVBQVU7WUFDdkMsaUJBQWlCLEVBQUUsMEJBQWlCLENBQUMsU0FBUztZQUM5QyxhQUFhLEVBQUUsYUFBYTtZQUM1QixpQkFBaUIsRUFBRSxhQUFhLEtBQUssMkJBQWEsQ0FBQyxPQUFPO1NBQzNELENBQUMsQ0FBQztRQUVILGlDQUFpQztRQUNqQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFFbkUsK0JBQStCO1FBQy9CLE1BQU0sb0JBQW9CLEdBQUcsS0FBSyxDQUFDLG9CQUFvQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNyRyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxvQ0FBZ0IsQ0FBQyxJQUFJLEVBQUUsb0JBQW9CLEVBQUU7WUFDdkUsT0FBTyxFQUFFLElBQUksQ0FBQyxLQUFLO2dCQUNqQixDQUFDLENBQUMsQ0FBQywwQkFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUM1RCxDQUFDLENBQUMsQ0FBQywwQkFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1lBQ3hDLGlCQUFpQixFQUFFLElBQUksQ0FBQyxNQUFNO1lBQzlCLFlBQVksRUFBRSxJQUFJLENBQUMsWUFBWTtZQUMvQixpQkFBaUIsRUFBRSxDQUFDLElBQUksQ0FBQztTQUMxQixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLG9CQUFvQixDQUFDLElBQUkseUJBQWUsQ0FBQztZQUN6RSxNQUFNLEVBQUUsZ0JBQU0sQ0FBQyxLQUFLO1lBQ3BCLE9BQU8sRUFBRTtnQkFDUCw0QkFBNEI7Z0JBQzVCLCtCQUErQjthQUNoQztZQUNELFNBQVMsRUFBRSxDQUFDLEdBQUcsQ0FBQztTQUNqQixDQUFDLENBQUMsQ0FBQztRQUVKLHFFQUFxRTtRQUNyRSw0RUFBNEU7UUFFNUUsa0NBQWtDO1FBQ2xDLElBQUksS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUM7WUFDaEQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFDN0QsQ0FBQztJQUNILENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssY0FBYyxDQUFDLEtBQW9CO1FBQ3pDLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1FBQ2pELENBQUM7UUFFRCxJQUFJLEtBQUssQ0FBQyxZQUFZLEVBQUUsVUFBVSxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUN0RSxNQUFNLElBQUksS0FBSyxDQUFDLHFEQUFxRCxDQUFDLENBQUM7UUFDekUsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLFlBQVksQ0FBQyxLQUFvQjtRQUN2QyxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsWUFBWSxJQUFJLGVBQWUsQ0FBQztRQUMzRCxNQUFNLG9CQUFvQixHQUFHLEtBQUssQ0FBQyxvQkFBb0IsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxlQUFlLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFckcsc0RBQXNEO1FBQ3RELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUV6RCxNQUFNLEtBQUssR0FBRyxJQUFJLHFCQUFLLENBQUMsSUFBSSxFQUFFLGVBQWUsRUFBRTtZQUM3QyxJQUFJLEVBQUUsS0FBSyxDQUFDLGVBQWU7WUFDM0IsUUFBUSxFQUFFO2dCQUNSLEtBQUssRUFBRSx5QkFBVyxDQUFDLFlBQVksQ0FBQywrQ0FBK0MsQ0FBQztnQkFDaEYsT0FBTyxFQUFFO29CQUNQLElBQUksRUFBRSxJQUFJLEVBQUU7d0JBQ1YsaUJBQWlCO3dCQUNqQiwwQkFBMEI7d0JBQzFCLFlBQVk7d0JBQ1osV0FBVyxZQUFZLG1CQUFtQjtxQkFDM0MsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO2lCQUNmO2dCQUNELElBQUksRUFBRSxNQUFNO2FBQ2I7U0FDRixDQUFDLENBQUM7UUFFSCwwREFBMEQ7UUFDMUQsaUZBQWlGO1FBRWpGLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLG1CQUFtQixDQUFDLEtBQW9CLEVBQUUsYUFBNEI7UUFDNUUsTUFBTSxjQUFjLEdBQUcsS0FBSyxDQUFDLGNBQWMsSUFBSSxtQ0FBMkIsQ0FBQztRQUUzRSxvREFBb0Q7UUFDcEQsTUFBTSx1QkFBdUIsR0FBRyxJQUFJLHlCQUFrQixDQUFDLElBQUksRUFBRSx5QkFBeUIsRUFBRTtZQUN0RixJQUFJLEVBQUUsNkJBQVksQ0FBQyxVQUFVLENBQUM7Ozs7Ozs7Ozs7Ozs7OztPQWU3QixDQUFDO1NBQ0gsQ0FBQyxDQUFDO1FBRUgsOENBQThDO1FBQzlDLHVCQUF1QixDQUFDLGtCQUFrQixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRTFELE1BQU0sa0JBQWtCLEdBQXNCO1lBQzVDLGVBQWUsRUFBRTtnQkFDZixNQUFNLEVBQUUsdUNBQWMsQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO2dCQUMzRCxvQkFBb0IsRUFBRSxxQ0FBb0IsQ0FBQyxpQkFBaUI7Z0JBQzVELG9CQUFvQixFQUFFO29CQUNwQjt3QkFDRSxRQUFRLEVBQUUsdUJBQXVCO3dCQUNqQyxTQUFTLEVBQUUsa0NBQWlCLENBQUMsZUFBZTtxQkFDN0M7aUJBQ0Y7YUFDRjtZQUNELGlCQUFpQixFQUFFLFlBQVk7WUFDL0IsY0FBYztZQUNkLE9BQU8sRUFBRSxLQUFLLENBQUMsaUJBQWlCLEVBQUUsT0FBTztZQUN6QyxPQUFPLEVBQUUsS0FBSyxDQUFDLGlCQUFpQixFQUFFLE9BQU87WUFDekMsVUFBVSxFQUFFLEtBQUssQ0FBQyxpQkFBaUIsRUFBRSxVQUFVO1lBQy9DLFFBQVEsRUFBRSxLQUFLLENBQUMsaUJBQWlCLEVBQUUsUUFBUTtTQUM1QyxDQUFDO1FBRUYsOENBQThDO1FBQzlDLElBQUksWUFBMEIsQ0FBQztRQUMvQixJQUFJLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN2QixZQUFZLEdBQUcsSUFBSSw2QkFBWSxDQUFDLElBQUksRUFBRSxzQkFBc0IsRUFBRTtnQkFDNUQsR0FBRyxrQkFBa0I7Z0JBQ3JCLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDO2dCQUM1QyxXQUFXLEVBQUUsS0FBSyxDQUFDLFlBQVksQ0FBQyxXQUFXO2FBQzVDLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxDQUFDO1lBQ04sWUFBWSxHQUFHLElBQUksNkJBQVksQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztRQUNwRixDQUFDO1FBRUQsdUNBQXVDO1FBQ3ZDLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUUvQyxPQUFPLFlBQVksQ0FBQztJQUN0QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSyxrQkFBa0IsQ0FBQyxZQUFnQyxFQUFFLGFBQTRCO1FBQ3ZGLElBQUksWUFBWSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQzVCLE1BQU0sV0FBVyxHQUFHLElBQUkscUJBQU8sQ0FBQyxJQUFJLEVBQUUscUJBQXFCLEVBQUU7Z0JBQzNELElBQUksRUFBRSxZQUFZLENBQUMsVUFBVTtnQkFDN0IsVUFBVSxFQUFFLFlBQVksQ0FBQyxVQUFVO2dCQUNuQyxNQUFNLEVBQUUsMEJBQVksQ0FBQyxTQUFTLENBQUMsSUFBSSxzQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7YUFDeEUsQ0FBQyxDQUFDO1lBRUgseUNBQXlDO1lBQ3pDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUNoRCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEdBQUc7UUFDUixPQUFPLElBQUksQ0FBQyxVQUFVO1lBQ3BCLENBQUMsQ0FBQyxXQUFXLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDOUIsQ0FBQyxDQUFDLFdBQVcsSUFBSSxDQUFDLFlBQVksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO0lBQzVELENBQUM7SUFFRDs7O09BR0c7SUFDSSxzQkFBc0I7UUFDM0IsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLHNCQUFzQixDQUFDO0lBQ2xELENBQUM7SUFFRDs7O09BR0c7SUFDSSxVQUFVO1FBQ2YsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQztJQUNoQyxDQUFDOztBQWxQSCw0QkFtUEMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBEb2NrZXJJbWFnZSwgUHJvcGVydHlJbmplY3RvcnMsIFJlbW92YWxQb2xpY3kgfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBJQ2VydGlmaWNhdGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyJztcbmltcG9ydCB7XG4gIERpc3RyaWJ1dGlvbixcbiAgRGlzdHJpYnV0aW9uUHJvcHMsXG4gIEVycm9yUmVzcG9uc2UsXG4gIEZ1bmN0aW9uIGFzIENsb3VkRnJvbnRGdW5jdGlvbixcbiAgRnVuY3Rpb25Db2RlLFxuICBGdW5jdGlvbkV2ZW50VHlwZSxcbiAgUHJpY2VDbGFzcyxcbiAgVmlld2VyUHJvdG9jb2xQb2xpY3ksXG59IGZyb20gJ2F3cy1jZGstbGliL2F3cy1jbG91ZGZyb250JztcbmltcG9ydCB7IFMzQnVja2V0T3JpZ2luIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnQtb3JpZ2lucyc7XG5pbXBvcnQgeyBFZmZlY3QsIFBvbGljeVN0YXRlbWVudCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgQVJlY29yZCwgSUhvc3RlZFpvbmUsIFJlY29yZFRhcmdldCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1yb3V0ZTUzJztcbmltcG9ydCB7IENsb3VkRnJvbnRUYXJnZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtcm91dGU1My10YXJnZXRzJztcbmltcG9ydCB7IEJsb2NrUHVibGljQWNjZXNzLCBCdWNrZXQsIEJ1Y2tldEVuY3J5cHRpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMnO1xuaW1wb3J0IHsgQXNzZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMtYXNzZXRzJztcbmltcG9ydCB7IEJ1Y2tldERlcGxveW1lbnQsIFNvdXJjZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMy1kZXBsb3ltZW50JztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgQ2xvdWRmcm9udERpc3RyaWJ1dGlvbk9ic2VydmFiaWxpdHlQcm9wZXJ0eUluamVjdG9yIH0gZnJvbSAnLi4vdXRpbGl0aWVzJztcblxuLyoqXG4gKiBEZWZhdWx0IENsb3VkRnJvbnQgZXJyb3IgcmVzcG9uc2VzIGZvciBTaW5nbGUgUGFnZSBBcHBsaWNhdGlvbnNcbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfU1BBX0VSUk9SX1JFU1BPTlNFUzogRXJyb3JSZXNwb25zZVtdID0gW1xuICB7XG4gICAgaHR0cFN0YXR1czogNDAzLFxuICAgIHJlc3BvbnNlSHR0cFN0YXR1czogMjAwLFxuICAgIHJlc3BvbnNlUGFnZVBhdGg6ICcvaW5kZXguaHRtbCcsXG4gIH0sXG4gIHtcbiAgICBodHRwU3RhdHVzOiA0MDQsXG4gICAgcmVzcG9uc2VIdHRwU3RhdHVzOiAyMDAsXG4gICAgcmVzcG9uc2VQYWdlUGF0aDogJy9pbmRleC5odG1sJyxcbiAgfSxcbl07XG5cbi8qKlxuICogQ3VzdG9tIGRvbWFpbiBjb25maWd1cmF0aW9uIGZvciB0aGUgZnJvbnRlbmRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDdXN0b21Eb21haW5Db25maWcge1xuICAvKiogRG9tYWluIG5hbWUgZm9yIHRoZSBmcm9udGVuZCAoZS5nLiwgJ2FwcC5leGFtcGxlLmNvbScpICovXG4gIHJlYWRvbmx5IGRvbWFpbk5hbWU6IHN0cmluZztcbiAgLyoqIFNTTCBjZXJ0aWZpY2F0ZSBmb3IgdGhlIGRvbWFpbiAocmVxdWlyZWQgd2hlbiBkb21haW5OYW1lIGlzIHByb3ZpZGVkKSAqL1xuICByZWFkb25seSBjZXJ0aWZpY2F0ZTogSUNlcnRpZmljYXRlO1xuICAvKiogT3B0aW9uYWwgaG9zdGVkIHpvbmUgZm9yIGF1dG9tYXRpYyBETlMgcmVjb3JkIGNyZWF0aW9uICovXG4gIHJlYWRvbmx5IGhvc3RlZFpvbmU/OiBJSG9zdGVkWm9uZTtcbn1cblxuLyoqXG4gKiBBZGRpdGlvbmFsIENsb3VkRnJvbnQgZGlzdHJpYnV0aW9uIHByb3BlcnRpZXNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBZGRpdGlvbmFsRGlzdHJpYnV0aW9uUHJvcHMge1xuICAvKiogT3B0aW9uYWwgY29tbWVudCBmb3IgdGhlIGRpc3RyaWJ1dGlvbiAqL1xuICByZWFkb25seSBjb21tZW50Pzogc3RyaW5nO1xuICAvKiogT3B0aW9uYWwgZW5hYmxlZCBmbGFnIGZvciB0aGUgZGlzdHJpYnV0aW9uICovXG4gIHJlYWRvbmx5IGVuYWJsZWQ/OiBib29sZWFuO1xuICAvKiogT3B0aW9uYWwgcHJpY2UgY2xhc3MgZm9yIHRoZSBkaXN0cmlidXRpb24gKi9cbiAgcmVhZG9ubHkgcHJpY2VDbGFzcz86IFByaWNlQ2xhc3M7XG4gIC8qKiBPcHRpb25hbCB3ZWIgQUNMIElEIGZvciB0aGUgZGlzdHJpYnV0aW9uICovXG4gIHJlYWRvbmx5IHdlYkFjbElkPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIHRoZSBGcm9udGVuZCBjb25zdHJ1Y3RcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBGcm9udGVuZFByb3BzIHtcbiAgLyoqIEJhc2UgZGlyZWN0b3J5IG9mIHRoZSBmcm9udGVuZCBzb3VyY2UgY29kZSAqL1xuICByZWFkb25seSBzb3VyY2VEaXJlY3Rvcnk6IHN0cmluZztcbiAgLyoqIERpcmVjdG9yeSB3aGVyZSBidWlsZCBhcnRpZmFjdHMgYXJlIGxvY2F0ZWQgYWZ0ZXIgYnVpbGQgY29tbWFuZCBjb21wbGV0ZXMgKGRlZmF1bHRzIHRvICd7c291cmNlRGlyZWN0b3J5fS9idWlsZCcpICovXG4gIHJlYWRvbmx5IGJ1aWxkT3V0cHV0RGlyZWN0b3J5Pzogc3RyaW5nO1xuICAvKiogT3B0aW9uYWwgYnVpbGQgY29tbWFuZCAoZGVmYXVsdHMgdG8gJ25wbSBydW4gYnVpbGQnKSAqL1xuICByZWFkb25seSBidWlsZENvbW1hbmQ/OiBzdHJpbmc7XG4gIC8qKiBPcHRpb25hbCBjdXN0b20gZG9tYWluIGNvbmZpZ3VyYXRpb24gKi9cbiAgcmVhZG9ubHkgY3VzdG9tRG9tYWluPzogQ3VzdG9tRG9tYWluQ29uZmlnO1xuICAvKiogT3B0aW9uYWwgQ2xvdWRGcm9udCBlcnJvciByZXNwb25zZXMgKGRlZmF1bHRzIHRvIFNQQS1mcmllbmRseSByZXNwb25zZXMpICovXG4gIHJlYWRvbmx5IGVycm9yUmVzcG9uc2VzPzogRXJyb3JSZXNwb25zZVtdO1xuICAvKiogT3B0aW9uYWwgYWRkaXRpb25hbCBDbG91ZEZyb250IGRpc3RyaWJ1dGlvbiBwcm9wZXJ0aWVzICovXG4gIHJlYWRvbmx5IGRpc3RyaWJ1dGlvblByb3BzPzogQWRkaXRpb25hbERpc3RyaWJ1dGlvblByb3BzO1xuICAvKiogT3B0aW9uYWwgZmxhZyB0byBza2lwIHRoZSBidWlsZCBwcm9jZXNzICh1c2VmdWwgZm9yIHByZS1idWlsdCBhcnRpZmFjdHMpICovXG4gIHJlYWRvbmx5IHNraXBCdWlsZD86IGJvb2xlYW47XG4gIC8qKiBPcHRpb25hbCByZW1vdmFsIHBvbGljeSBmb3IgYWxsIHJlc291cmNlcyAoZGVmYXVsdHMgdG8gREVTVFJPWSkgKi9cbiAgcmVhZG9ubHkgcmVtb3ZhbFBvbGljeT86IFJlbW92YWxQb2xpY3k7XG4gIC8qKlxuICAgKiBFbmFibGUgbG9nZ2luZyBhbmQgdHJhY2luZyBmb3IgYWxsIHN1cHBvcnRpbmcgcmVzb3VyY2VcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGVuYWJsZU9ic2VydmFiaWxpdHk/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEZyb250ZW5kIGNvbnN0cnVjdCB0aGF0IGRlcGxveXMgYSBmcm9udGVuZCBhcHBsaWNhdGlvbiB0byBTMyBhbmQgQ2xvdWRGcm9udFxuICpcbiAqIFRoaXMgY29uc3RydWN0IHByb3ZpZGVzIGEgY29tcGxldGUgc29sdXRpb24gZm9yIGhvc3Rpbmcgc3RhdGljIGZyb250ZW5kIGFwcGxpY2F0aW9uc1xuICogd2l0aCB0aGUgZm9sbG93aW5nIGZlYXR1cmVzOlxuICogLSBTMyBidWNrZXQgZm9yIGhvc3Rpbmcgc3RhdGljIGFzc2V0cyB3aXRoIHNlY3VyaXR5IGJlc3QgcHJhY3RpY2VzXG4gKiAtIENsb3VkRnJvbnQgZGlzdHJpYnV0aW9uIGZvciBnbG9iYWwgY29udGVudCBkZWxpdmVyeVxuICogLSBPcHRpb25hbCBjdXN0b20gZG9tYWluIHdpdGggU1NMIGNlcnRpZmljYXRlXG4gKiAtIEF1dG9tYXRpYyBidWlsZCBwcm9jZXNzIGV4ZWN1dGlvblxuICogLSBTUEEtZnJpZW5kbHkgZXJyb3IgaGFuZGxpbmcgYnkgZGVmYXVsdFxuICogLSBTZWN1cml0eSBjb25maWd1cmF0aW9uc1xuICovXG5leHBvcnQgY2xhc3MgRnJvbnRlbmQgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAvKiogVGhlIFMzIGJ1Y2tldCBob3N0aW5nIHRoZSBmcm9udGVuZCBhc3NldHMgKi9cbiAgcHVibGljIHJlYWRvbmx5IGJ1Y2tldDogQnVja2V0O1xuICAvKiogVGhlIENsb3VkRnJvbnQgZGlzdHJpYnV0aW9uICovXG4gIHB1YmxpYyByZWFkb25seSBkaXN0cmlidXRpb246IERpc3RyaWJ1dGlvbjtcbiAgLyoqIFRoZSBidWNrZXQgZGVwbG95bWVudCB0aGF0IHVwbG9hZHMgdGhlIGZyb250ZW5kIGFzc2V0cyAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYnVja2V0RGVwbG95bWVudDogQnVja2V0RGVwbG95bWVudDtcbiAgLyoqIFRoZSBjdXN0b20gZG9tYWluIG5hbWUgKGlmIGNvbmZpZ3VyZWQpICovXG4gIHB1YmxpYyByZWFkb25seSBkb21haW5OYW1lPzogc3RyaW5nO1xuICAvKiogVGhlIEFzc2V0IGNvbnRhaW5pbmcgdGhlIGZyb250ZW5kIHNvdXJjZSBjb2RlICovXG4gIHB1YmxpYyByZWFkb25seSBhc3NldD86IEFzc2V0O1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IEZyb250ZW5kXG4gICAqIEBwYXJhbSBzY29wZSBUaGUgY29uc3RydWN0IHNjb3BlXG4gICAqIEBwYXJhbSBpZCBUaGUgY29uc3RydWN0IElEXG4gICAqIEBwYXJhbSBwcm9wcyBUaGUgZnJvbnRlbmQgcHJvcGVydGllc1xuICAgKi9cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEZyb250ZW5kUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgaWYgKHByb3BzLmVuYWJsZU9ic2VydmFiaWxpdHkpIHtcbiAgICAgIFByb3BlcnR5SW5qZWN0b3JzLm9mKHRoaXMpLmFkZChcbiAgICAgICAgbmV3IENsb3VkZnJvbnREaXN0cmlidXRpb25PYnNlcnZhYmlsaXR5UHJvcGVydHlJbmplY3RvcigpLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSByZXF1aXJlZCBwYXJhbWV0ZXJzXG4gICAgdGhpcy5fdmFsaWRhdGVQcm9wcyhwcm9wcyk7XG5cbiAgICAvLyBHZXQgcmVtb3ZhbCBwb2xpY3kgd2l0aCBkZWZhdWx0XG4gICAgY29uc3QgcmVtb3ZhbFBvbGljeSA9IHByb3BzLnJlbW92YWxQb2xpY3kgfHwgUmVtb3ZhbFBvbGljeS5ERVNUUk9ZO1xuXG4gICAgLy8gQ3JlYXRlIGFzc2V0IGZvciBzb3VyY2UgY29kZSB3aXRoIG9wdGlvbmFsIGJ1bmRsaW5nXG4gICAgaWYgKCFwcm9wcy5za2lwQnVpbGQpIHtcbiAgICAgIHRoaXMuYXNzZXQgPSB0aGlzLl9jcmVhdGVBc3NldChwcm9wcyk7XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIFMzIGJ1Y2tldCBmb3IgaG9zdGluZ1xuICAgIHRoaXMuYnVja2V0ID0gbmV3IEJ1Y2tldCh0aGlzLCAnRnJvbnRlbmRCdWNrZXQnLCB7XG4gICAgICBlbmNyeXB0aW9uOiBCdWNrZXRFbmNyeXB0aW9uLlMzX01BTkFHRUQsXG4gICAgICBibG9ja1B1YmxpY0FjY2VzczogQmxvY2tQdWJsaWNBY2Nlc3MuQkxPQ0tfQUxMLFxuICAgICAgcmVtb3ZhbFBvbGljeTogcmVtb3ZhbFBvbGljeSxcbiAgICAgIGF1dG9EZWxldGVPYmplY3RzOiByZW1vdmFsUG9saWN5ID09PSBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSk7XG5cbiAgICAvLyBDcmVhdGUgQ2xvdWRGcm9udCBkaXN0cmlidXRpb25cbiAgICB0aGlzLmRpc3RyaWJ1dGlvbiA9IHRoaXMuX2NyZWF0ZURpc3RyaWJ1dGlvbihwcm9wcywgcmVtb3ZhbFBvbGljeSk7XG5cbiAgICAvLyBEZXBsb3kgZnJvbnRlbmQgYXNzZXRzIHRvIFMzXG4gICAgY29uc3QgYnVpbGRPdXRwdXREaXJlY3RvcnkgPSBwcm9wcy5idWlsZE91dHB1dERpcmVjdG9yeSB8fCBwYXRoLmpvaW4ocHJvcHMuc291cmNlRGlyZWN0b3J5LCAnYnVpbGQnKTtcbiAgICB0aGlzLmJ1Y2tldERlcGxveW1lbnQgPSBuZXcgQnVja2V0RGVwbG95bWVudCh0aGlzLCAnRnJvbnRlbmREZXBsb3ltZW50Jywge1xuICAgICAgc291cmNlczogdGhpcy5hc3NldFxuICAgICAgICA/IFtTb3VyY2UuYnVja2V0KHRoaXMuYXNzZXQuYnVja2V0LCB0aGlzLmFzc2V0LnMzT2JqZWN0S2V5KV1cbiAgICAgICAgOiBbU291cmNlLmFzc2V0KGJ1aWxkT3V0cHV0RGlyZWN0b3J5KV0sXG4gICAgICBkZXN0aW5hdGlvbkJ1Y2tldDogdGhpcy5idWNrZXQsXG4gICAgICBkaXN0cmlidXRpb246IHRoaXMuZGlzdHJpYnV0aW9uLFxuICAgICAgZGlzdHJpYnV0aW9uUGF0aHM6IFsnLyonXSxcbiAgICB9KTtcblxuICAgIHRoaXMuYnVja2V0RGVwbG95bWVudC5oYW5kbGVyUm9sZS5hZGRUb1ByaW5jaXBhbFBvbGljeShuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgYWN0aW9uczogW1xuICAgICAgICAnY2xvdWRmcm9udDpHZXRJbnZhbGlkYXRpb24nLFxuICAgICAgICAnY2xvdWRmcm9udDpDcmVhdGVJbnZhbGlkYXRpb24nLFxuICAgICAgXSxcbiAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgfSkpO1xuXG4gICAgLy8gTm90ZTogQnVja2V0RGVwbG95bWVudCBkb2Vzbid0IHN1cHBvcnQgYXBwbHlSZW1vdmFsUG9saWN5IGRpcmVjdGx5XG4gICAgLy8gSXQgd2lsbCBiZSBjbGVhbmVkIHVwIHdoZW4gdGhlIGJ1Y2tldCBpcyBkZWxldGVkIGR1ZSB0byBhdXRvRGVsZXRlT2JqZWN0c1xuXG4gICAgLy8gU2V0dXAgY3VzdG9tIGRvbWFpbiBpZiBwcm92aWRlZFxuICAgIGlmIChwcm9wcy5jdXN0b21Eb21haW4pIHtcbiAgICAgIHRoaXMuZG9tYWluTmFtZSA9IHByb3BzLmN1c3RvbURvbWFpbi5kb21haW5OYW1lO1xuICAgICAgdGhpcy5fc2V0dXBDdXN0b21Eb21haW4ocHJvcHMuY3VzdG9tRG9tYWluLCByZW1vdmFsUG9saWN5KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoZSBjb25zdHJ1Y3QgcHJvcGVydGllc1xuICAgKiBAcGFyYW0gcHJvcHMgVGhlIGZyb250ZW5kIHByb3BlcnRpZXNcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgX3ZhbGlkYXRlUHJvcHMocHJvcHM6IEZyb250ZW5kUHJvcHMpOiB2b2lkIHtcbiAgICBpZiAoIXByb3BzLnNvdXJjZURpcmVjdG9yeSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdzb3VyY2VEaXJlY3RvcnkgaXMgcmVxdWlyZWQnKTtcbiAgICB9XG5cbiAgICBpZiAocHJvcHMuY3VzdG9tRG9tYWluPy5kb21haW5OYW1lICYmICFwcm9wcy5jdXN0b21Eb21haW4uY2VydGlmaWNhdGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2VydGlmaWNhdGUgaXMgcmVxdWlyZWQgd2hlbiBkb21haW5OYW1lIGlzIHByb3ZpZGVkJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gQXNzZXQgZm9yIHRoZSBmcm9udGVuZCBzb3VyY2UgY29kZSB3aXRoIGJ1bmRsaW5nXG4gICAqIEBwYXJhbSBwcm9wcyBUaGUgZnJvbnRlbmQgcHJvcGVydGllc1xuICAgKiBAcmV0dXJucyBUaGUgQXNzZXQgY29udGFpbmluZyB0aGUgYnVpbHQgZnJvbnRlbmRcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgX2NyZWF0ZUFzc2V0KHByb3BzOiBGcm9udGVuZFByb3BzKTogQXNzZXQge1xuICAgIGNvbnN0IGJ1aWxkQ29tbWFuZCA9IHByb3BzLmJ1aWxkQ29tbWFuZCB8fCAnbnBtIHJ1biBidWlsZCc7XG4gICAgY29uc3QgYnVpbGRPdXRwdXREaXJlY3RvcnkgPSBwcm9wcy5idWlsZE91dHB1dERpcmVjdG9yeSB8fCBwYXRoLmpvaW4ocHJvcHMuc291cmNlRGlyZWN0b3J5LCAnYnVpbGQnKTtcblxuICAgIC8vIEV4dHJhY3QgdGhlIGJ1aWxkIGRpcmVjdG9yeSBuYW1lIGZyb20gdGhlIGZ1bGwgcGF0aFxuICAgIGNvbnN0IGJ1aWxkRGlyTmFtZSA9IHBhdGguYmFzZW5hbWUoYnVpbGRPdXRwdXREaXJlY3RvcnkpO1xuXG4gICAgY29uc3QgYXNzZXQgPSBuZXcgQXNzZXQodGhpcywgJ0Zyb250ZW5kQXNzZXQnLCB7XG4gICAgICBwYXRoOiBwcm9wcy5zb3VyY2VEaXJlY3RvcnksXG4gICAgICBidW5kbGluZzoge1xuICAgICAgICBpbWFnZTogRG9ja2VySW1hZ2UuZnJvbVJlZ2lzdHJ5KCdwdWJsaWMuZWNyLmF3cy9kb2NrZXIvbGlicmFyeS9ub2RlOmx0cy1hbHBpbmUnKSxcbiAgICAgICAgY29tbWFuZDogW1xuICAgICAgICAgICdzaCcsICctYycsIFtcbiAgICAgICAgICAgICdjZCAvYXNzZXQtaW5wdXQnLFxuICAgICAgICAgICAgJ25wbSBjaSAtLW9ubHk9cHJvZHVjdGlvbicsXG4gICAgICAgICAgICBidWlsZENvbW1hbmQsXG4gICAgICAgICAgICBgY3AgLXIgLi8ke2J1aWxkRGlyTmFtZX0vKiAvYXNzZXQtb3V0cHV0L2AsXG4gICAgICAgICAgXS5qb2luKCcgJiYgJyksXG4gICAgICAgIF0sXG4gICAgICAgIHVzZXI6ICdyb290JyxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyBOb3RlOiBBc3NldCBkb2Vzbid0IHN1cHBvcnQgYXBwbHlSZW1vdmFsUG9saWN5IGRpcmVjdGx5XG4gICAgLy8gVGhlIHVuZGVybHlpbmcgUzMgb2JqZWN0cyB3aWxsIGJlIG1hbmFnZWQgYnkgdGhlIGFzc2V0IGJ1Y2tldCdzIHJlbW92YWwgcG9saWN5XG5cbiAgICByZXR1cm4gYXNzZXQ7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgQ2xvdWRGcm9udCBkaXN0cmlidXRpb25cbiAgICogQHBhcmFtIHByb3BzIFRoZSBmcm9udGVuZCBwcm9wZXJ0aWVzXG4gICAqIEBwYXJhbSByZW1vdmFsUG9saWN5IFRoZSByZW1vdmFsIHBvbGljeSB0byBhcHBseVxuICAgKiBAcmV0dXJucyBUaGUgQ2xvdWRGcm9udCBkaXN0cmlidXRpb25cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgX2NyZWF0ZURpc3RyaWJ1dGlvbihwcm9wczogRnJvbnRlbmRQcm9wcywgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeSk6IERpc3RyaWJ1dGlvbiB7XG4gICAgY29uc3QgZXJyb3JSZXNwb25zZXMgPSBwcm9wcy5lcnJvclJlc3BvbnNlcyB8fCBERUZBVUxUX1NQQV9FUlJPUl9SRVNQT05TRVM7XG5cbiAgICAvLyBDcmVhdGUgYSBDbG91ZEZyb250IGZ1bmN0aW9uIGZvciBzZWN1cml0eSBoZWFkZXJzXG4gICAgY29uc3Qgc2VjdXJpdHlIZWFkZXJzRnVuY3Rpb24gPSBuZXcgQ2xvdWRGcm9udEZ1bmN0aW9uKHRoaXMsICdTZWN1cml0eUhlYWRlcnNGdW5jdGlvbicsIHtcbiAgICAgIGNvZGU6IEZ1bmN0aW9uQ29kZS5mcm9tSW5saW5lKGBcbiAgICAgICAgZnVuY3Rpb24gaGFuZGxlcihldmVudCkge1xuICAgICAgICAgIHZhciByZXNwb25zZSA9IGV2ZW50LnJlc3BvbnNlO1xuICAgICAgICAgIHZhciBoZWFkZXJzID0gcmVzcG9uc2UuaGVhZGVycztcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBBZGQgc2VjdXJpdHkgaGVhZGVyc1xuICAgICAgICAgIGhlYWRlcnNbJ3N0cmljdC10cmFuc3BvcnQtc2VjdXJpdHknXSA9IHsgdmFsdWU6ICdtYXgtYWdlPTYzMDcyMDAwOyBpbmNsdWRlU3ViZG9tYWluczsgcHJlbG9hZCcgfTtcbiAgICAgICAgICBoZWFkZXJzWydjb250ZW50LXR5cGUtb3B0aW9ucyddID0geyB2YWx1ZTogJ25vc25pZmYnIH07XG4gICAgICAgICAgaGVhZGVyc1sneC1mcmFtZS1vcHRpb25zJ10gPSB7IHZhbHVlOiAnREVOWScgfTtcbiAgICAgICAgICBoZWFkZXJzWyd4LWNvbnRlbnQtdHlwZS1vcHRpb25zJ10gPSB7IHZhbHVlOiAnbm9zbmlmZicgfTtcbiAgICAgICAgICBoZWFkZXJzWydyZWZlcnJlci1wb2xpY3knXSA9IHsgdmFsdWU6ICdzdHJpY3Qtb3JpZ2luLXdoZW4tY3Jvc3Mtb3JpZ2luJyB9O1xuICAgICAgICAgIGhlYWRlcnNbJ3Blcm1pc3Npb25zLXBvbGljeSddID0geyB2YWx1ZTogJ2NhbWVyYT0oKSwgbWljcm9waG9uZT0oKSwgZ2VvbG9jYXRpb249KCknIH07XG4gICAgICAgICAgXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgICB9XG4gICAgICBgKSxcbiAgICB9KTtcblxuICAgIC8vIEFwcGx5IHJlbW92YWwgcG9saWN5IHRvIENsb3VkRnJvbnQgZnVuY3Rpb25cbiAgICBzZWN1cml0eUhlYWRlcnNGdW5jdGlvbi5hcHBseVJlbW92YWxQb2xpY3kocmVtb3ZhbFBvbGljeSk7XG5cbiAgICBjb25zdCBkaXN0cmlidXRpb25Db25maWc6IERpc3RyaWJ1dGlvblByb3BzID0ge1xuICAgICAgZGVmYXVsdEJlaGF2aW9yOiB7XG4gICAgICAgIG9yaWdpbjogUzNCdWNrZXRPcmlnaW4ud2l0aE9yaWdpbkFjY2Vzc0NvbnRyb2wodGhpcy5idWNrZXQpLFxuICAgICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICAgIGZ1bmN0aW9uQXNzb2NpYXRpb25zOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgZnVuY3Rpb246IHNlY3VyaXR5SGVhZGVyc0Z1bmN0aW9uLFxuICAgICAgICAgICAgZXZlbnRUeXBlOiBGdW5jdGlvbkV2ZW50VHlwZS5WSUVXRVJfUkVTUE9OU0UsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgICBkZWZhdWx0Um9vdE9iamVjdDogJ2luZGV4Lmh0bWwnLFxuICAgICAgZXJyb3JSZXNwb25zZXMsXG4gICAgICBjb21tZW50OiBwcm9wcy5kaXN0cmlidXRpb25Qcm9wcz8uY29tbWVudCxcbiAgICAgIGVuYWJsZWQ6IHByb3BzLmRpc3RyaWJ1dGlvblByb3BzPy5lbmFibGVkLFxuICAgICAgcHJpY2VDbGFzczogcHJvcHMuZGlzdHJpYnV0aW9uUHJvcHM/LnByaWNlQ2xhc3MsXG4gICAgICB3ZWJBY2xJZDogcHJvcHMuZGlzdHJpYnV0aW9uUHJvcHM/LndlYkFjbElkLFxuICAgIH07XG5cbiAgICAvLyBBZGQgY3VzdG9tIGRvbWFpbiBjb25maWd1cmF0aW9uIGlmIHByb3ZpZGVkXG4gICAgbGV0IGRpc3RyaWJ1dGlvbjogRGlzdHJpYnV0aW9uO1xuICAgIGlmIChwcm9wcy5jdXN0b21Eb21haW4pIHtcbiAgICAgIGRpc3RyaWJ1dGlvbiA9IG5ldyBEaXN0cmlidXRpb24odGhpcywgJ0Zyb250ZW5kRGlzdHJpYnV0aW9uJywge1xuICAgICAgICAuLi5kaXN0cmlidXRpb25Db25maWcsXG4gICAgICAgIGRvbWFpbk5hbWVzOiBbcHJvcHMuY3VzdG9tRG9tYWluLmRvbWFpbk5hbWVdLFxuICAgICAgICBjZXJ0aWZpY2F0ZTogcHJvcHMuY3VzdG9tRG9tYWluLmNlcnRpZmljYXRlLFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRpc3RyaWJ1dGlvbiA9IG5ldyBEaXN0cmlidXRpb24odGhpcywgJ0Zyb250ZW5kRGlzdHJpYnV0aW9uJywgZGlzdHJpYnV0aW9uQ29uZmlnKTtcbiAgICB9XG5cbiAgICAvLyBBcHBseSByZW1vdmFsIHBvbGljeSB0byBkaXN0cmlidXRpb25cbiAgICBkaXN0cmlidXRpb24uYXBwbHlSZW1vdmFsUG9saWN5KHJlbW92YWxQb2xpY3kpO1xuXG4gICAgcmV0dXJuIGRpc3RyaWJ1dGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHVwIGN1c3RvbSBkb21haW4gd2l0aCBSb3V0ZTUzIHJlY29yZFxuICAgKiBAcGFyYW0gY3VzdG9tRG9tYWluIFRoZSBjdXN0b20gZG9tYWluIGNvbmZpZ3VyYXRpb25cbiAgICogQHBhcmFtIHJlbW92YWxQb2xpY3kgVGhlIHJlbW92YWwgcG9saWN5IHRvIGFwcGx5XG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIF9zZXR1cEN1c3RvbURvbWFpbihjdXN0b21Eb21haW46IEN1c3RvbURvbWFpbkNvbmZpZywgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeSk6IHZvaWQge1xuICAgIGlmIChjdXN0b21Eb21haW4uaG9zdGVkWm9uZSkge1xuICAgICAgY29uc3QgYWxpYXNSZWNvcmQgPSBuZXcgQVJlY29yZCh0aGlzLCAnRnJvbnRlbmRBbGlhc1JlY29yZCcsIHtcbiAgICAgICAgem9uZTogY3VzdG9tRG9tYWluLmhvc3RlZFpvbmUsXG4gICAgICAgIHJlY29yZE5hbWU6IGN1c3RvbURvbWFpbi5kb21haW5OYW1lLFxuICAgICAgICB0YXJnZXQ6IFJlY29yZFRhcmdldC5mcm9tQWxpYXMobmV3IENsb3VkRnJvbnRUYXJnZXQodGhpcy5kaXN0cmlidXRpb24pKSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBBcHBseSByZW1vdmFsIHBvbGljeSB0byBSb3V0ZTUzIHJlY29yZFxuICAgICAgYWxpYXNSZWNvcmQuYXBwbHlSZW1vdmFsUG9saWN5KHJlbW92YWxQb2xpY3kpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBVUkwgb2YgdGhlIGZyb250ZW5kIGFwcGxpY2F0aW9uXG4gICAqIEByZXR1cm5zIFRoZSBmcm9udGVuZCBVUkxcbiAgICovXG4gIHB1YmxpYyB1cmwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5kb21haW5OYW1lXG4gICAgICA/IGBodHRwczovLyR7dGhpcy5kb21haW5OYW1lfWBcbiAgICAgIDogYGh0dHBzOi8vJHt0aGlzLmRpc3RyaWJ1dGlvbi5kaXN0cmlidXRpb25Eb21haW5OYW1lfWA7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgQ2xvdWRGcm9udCBkaXN0cmlidXRpb24gZG9tYWluIG5hbWVcbiAgICogQHJldHVybnMgVGhlIENsb3VkRnJvbnQgZG9tYWluIG5hbWVcbiAgICovXG4gIHB1YmxpYyBkaXN0cmlidXRpb25Eb21haW5OYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZGlzdHJpYnV0aW9uLmRpc3RyaWJ1dGlvbkRvbWFpbk5hbWU7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgUzMgYnVja2V0IG5hbWVcbiAgICogQHJldHVybnMgVGhlIFMzIGJ1Y2tldCBuYW1lXG4gICAqL1xuICBwdWJsaWMgYnVja2V0TmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmJ1Y2tldC5idWNrZXROYW1lO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './frontend-construct';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./frontend-construct"), exports);
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi91c2UtY2FzZXMvd2ViYXBwL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1REFBcUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2Zyb250ZW5kLWNvbnN0cnVjdCc7Il19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
8
|
+
const assertions_1 = require("aws-cdk-lib/assertions");
|
|
9
|
+
const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager");
|
|
10
|
+
const aws_route53_1 = require("aws-cdk-lib/aws-route53");
|
|
11
|
+
const cdk_nag_1 = require("cdk-nag");
|
|
12
|
+
const frontend_construct_1 = require("../frontend-construct");
|
|
13
|
+
// Create temporary build directory for tests
|
|
14
|
+
const testBuildDir = '/tmp/test-frontend-build-nag';
|
|
15
|
+
if (!fs.existsSync(testBuildDir)) {
|
|
16
|
+
fs.mkdirSync(testBuildDir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
fs.writeFileSync(path.join(testBuildDir, 'index.html'), '<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Test App</h1></body></html>');
|
|
19
|
+
// Create app and stack
|
|
20
|
+
const app = new aws_cdk_lib_1.App();
|
|
21
|
+
const stack = new aws_cdk_lib_1.Stack(app, 'TestStack', {
|
|
22
|
+
env: {
|
|
23
|
+
account: '123456789012',
|
|
24
|
+
region: 'us-east-1',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
// Create SSL certificate for custom domain testing
|
|
28
|
+
const certificate = aws_certificatemanager_1.Certificate.fromCertificateArn(stack, 'Certificate', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012');
|
|
29
|
+
// Create hosted zone for DNS testing
|
|
30
|
+
const hostedZone = aws_route53_1.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', {
|
|
31
|
+
hostedZoneId: 'Z123456789',
|
|
32
|
+
zoneName: 'example.com',
|
|
33
|
+
});
|
|
34
|
+
// Create the main Frontend construct
|
|
35
|
+
const frontend = new frontend_construct_1.Frontend(stack, 'TestFrontend', {
|
|
36
|
+
sourceDirectory: '/tmp/test-frontend-src',
|
|
37
|
+
buildOutputDirectory: testBuildDir,
|
|
38
|
+
customDomain: {
|
|
39
|
+
domainName: 'app.example.com',
|
|
40
|
+
certificate,
|
|
41
|
+
hostedZone,
|
|
42
|
+
},
|
|
43
|
+
skipBuild: true, // Skip build for testing
|
|
44
|
+
});
|
|
45
|
+
// Add CDK Nag suppressions for known acceptable violations
|
|
46
|
+
cdk_nag_1.NagSuppressions.addResourceSuppressions(stack, [
|
|
47
|
+
{
|
|
48
|
+
id: 'AwsSolutions-CFR1',
|
|
49
|
+
reason: 'CloudFront geo restrictions are configured based on application requirements',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'AwsSolutions-CFR2',
|
|
53
|
+
reason: 'CloudFront WAF integration is configured based on security requirements',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'AwsSolutions-CFR3',
|
|
57
|
+
reason: 'CloudFront access logging is configured based on compliance requirements',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'AwsSolutions-CFR4',
|
|
61
|
+
reason: 'CloudFront viewer protocol policy is set to redirect-to-https for security',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'AwsSolutions-S1',
|
|
65
|
+
reason: 'S3 bucket access logging is configured based on compliance requirements',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'AwsSolutions-S2',
|
|
69
|
+
reason: 'S3 bucket public access is blocked and access is controlled via CloudFront OAC',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'AwsSolutions-S3',
|
|
73
|
+
reason: 'S3 bucket SSL requests only policy is enforced via CloudFront HTTPS redirect',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'AwsSolutions-S10',
|
|
77
|
+
reason: 'S3 bucket MFA delete is managed through organizational security policies',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'AwsSolutions-IAM4',
|
|
81
|
+
reason: 'AWS managed policies are acceptable for standard Lambda execution roles',
|
|
82
|
+
appliesTo: ['Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'AwsSolutions-IAM5',
|
|
86
|
+
reason: 'BucketDeployment requires broad S3 permissions to manage deployment assets',
|
|
87
|
+
appliesTo: [
|
|
88
|
+
'Action::s3:GetObject*',
|
|
89
|
+
'Action::s3:GetBucket*',
|
|
90
|
+
'Action::s3:List*',
|
|
91
|
+
'Action::s3:DeleteObject*',
|
|
92
|
+
'Action::s3:Abort*',
|
|
93
|
+
'Resource::arn:<AWS::Partition>:s3:::cdk-hnb659fds-assets-<AWS::AccountId>-<AWS::Region>/*',
|
|
94
|
+
'Resource::arn:<AWS::Partition>:s3:::cdk-hnb659fds-assets-123456789012-us-east-1/*',
|
|
95
|
+
'Resource::<TestFrontendFrontendBucketD37D22DE.Arn>/*',
|
|
96
|
+
'Resource::*',
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'AwsSolutions-L1',
|
|
101
|
+
reason: 'Lambda runtime versions are managed at the application deployment level',
|
|
102
|
+
},
|
|
103
|
+
], true);
|
|
104
|
+
// Apply CDK Nag checks
|
|
105
|
+
aws_cdk_lib_1.Aspects.of(app).add(new cdk_nag_1.AwsSolutionsChecks({ verbose: true }));
|
|
106
|
+
// Synthesize the stack
|
|
107
|
+
assertions_1.Template.fromStack(stack);
|
|
108
|
+
// Check for unsuppressed warnings and errors
|
|
109
|
+
const warnings = assertions_1.Annotations.fromStack(stack).findWarning('*', assertions_1.Match.stringLikeRegexp('AwsSolutions-.*'));
|
|
110
|
+
const errors = assertions_1.Annotations.fromStack(stack).findError('*', assertions_1.Match.stringLikeRegexp('AwsSolutions-.*'));
|
|
111
|
+
// Test: Frontend construct is properly created and accessible
|
|
112
|
+
test('Frontend construct is created successfully', () => {
|
|
113
|
+
expect(frontend).toBeDefined();
|
|
114
|
+
expect(frontend.node.id).toBe('TestFrontend');
|
|
115
|
+
expect(frontend.bucket).toBeDefined();
|
|
116
|
+
expect(frontend.distribution).toBeDefined();
|
|
117
|
+
expect(frontend.bucketDeployment).toBeDefined();
|
|
118
|
+
});
|
|
119
|
+
// Test: Frontend construct has expected properties
|
|
120
|
+
test('Frontend construct has expected properties', () => {
|
|
121
|
+
expect(frontend.bucket.bucketName).toBeDefined();
|
|
122
|
+
expect(frontend.distribution.distributionId).toBeDefined();
|
|
123
|
+
expect(frontend.domainName).toBe('app.example.com');
|
|
124
|
+
expect(frontend.url()).toBe('https://app.example.com');
|
|
125
|
+
expect(typeof frontend.bucketName()).toBe('string');
|
|
126
|
+
expect(typeof frontend.distributionDomainName()).toBe('string');
|
|
127
|
+
});
|
|
128
|
+
// Test: Template contains expected frontend resources
|
|
129
|
+
test('Template contains expected frontend resources', () => {
|
|
130
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
131
|
+
// Verify S3 bucket exists with security configuration
|
|
132
|
+
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
133
|
+
BucketEncryption: {
|
|
134
|
+
ServerSideEncryptionConfiguration: [
|
|
135
|
+
{
|
|
136
|
+
ServerSideEncryptionByDefault: {
|
|
137
|
+
SSEAlgorithm: 'AES256',
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
PublicAccessBlockConfiguration: {
|
|
143
|
+
BlockPublicAcls: true,
|
|
144
|
+
BlockPublicPolicy: true,
|
|
145
|
+
IgnorePublicAcls: true,
|
|
146
|
+
RestrictPublicBuckets: true,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
// Verify CloudFront distribution exists with security configuration
|
|
150
|
+
template.hasResourceProperties('AWS::CloudFront::Distribution', {
|
|
151
|
+
DistributionConfig: {
|
|
152
|
+
Aliases: ['app.example.com'],
|
|
153
|
+
DefaultRootObject: 'index.html',
|
|
154
|
+
DefaultCacheBehavior: {
|
|
155
|
+
ViewerProtocolPolicy: 'redirect-to-https',
|
|
156
|
+
},
|
|
157
|
+
CustomErrorResponses: [
|
|
158
|
+
{
|
|
159
|
+
ErrorCode: 403,
|
|
160
|
+
ResponseCode: 200,
|
|
161
|
+
ResponsePagePath: '/index.html',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
ErrorCode: 404,
|
|
165
|
+
ResponseCode: 200,
|
|
166
|
+
ResponsePagePath: '/index.html',
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
ViewerCertificate: {
|
|
170
|
+
AcmCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012',
|
|
171
|
+
SslSupportMethod: 'sni-only',
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
// Verify CloudFront security headers function exists
|
|
176
|
+
template.hasResourceProperties('AWS::CloudFront::Function', {
|
|
177
|
+
FunctionConfig: {
|
|
178
|
+
Runtime: 'cloudfront-js-1.0',
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
// Verify Route53 A record exists for custom domain
|
|
182
|
+
template.hasResourceProperties('AWS::Route53::RecordSet', {
|
|
183
|
+
Type: 'A',
|
|
184
|
+
Name: 'app.example.com.',
|
|
185
|
+
HostedZoneId: 'Z123456789',
|
|
186
|
+
});
|
|
187
|
+
// Verify bucket deployment exists
|
|
188
|
+
template.hasResource('Custom::CDKBucketDeployment', {});
|
|
189
|
+
// Verify auto delete objects custom resource exists
|
|
190
|
+
template.hasResource('Custom::S3AutoDeleteObjects', {});
|
|
191
|
+
});
|
|
192
|
+
// Test: Frontend construct enforces security best practices
|
|
193
|
+
test('Frontend construct enforces security best practices', () => {
|
|
194
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
195
|
+
// Verify HTTPS redirect is enforced
|
|
196
|
+
template.hasResourceProperties('AWS::CloudFront::Distribution', {
|
|
197
|
+
DistributionConfig: {
|
|
198
|
+
DefaultCacheBehavior: {
|
|
199
|
+
ViewerProtocolPolicy: 'redirect-to-https',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
// Verify S3 bucket blocks public access
|
|
204
|
+
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
205
|
+
PublicAccessBlockConfiguration: {
|
|
206
|
+
BlockPublicAcls: true,
|
|
207
|
+
BlockPublicPolicy: true,
|
|
208
|
+
IgnorePublicAcls: true,
|
|
209
|
+
RestrictPublicBuckets: true,
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
// Verify S3 bucket has encryption
|
|
213
|
+
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
214
|
+
BucketEncryption: {
|
|
215
|
+
ServerSideEncryptionConfiguration: [
|
|
216
|
+
{
|
|
217
|
+
ServerSideEncryptionByDefault: {
|
|
218
|
+
SSEAlgorithm: 'AES256',
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
// Test: Frontend construct supports SPA applications
|
|
226
|
+
test('Frontend construct supports SPA applications', () => {
|
|
227
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
228
|
+
// Verify SPA-friendly error responses
|
|
229
|
+
template.hasResourceProperties('AWS::CloudFront::Distribution', {
|
|
230
|
+
DistributionConfig: {
|
|
231
|
+
CustomErrorResponses: [
|
|
232
|
+
{
|
|
233
|
+
ErrorCode: 403,
|
|
234
|
+
ResponseCode: 200,
|
|
235
|
+
ResponsePagePath: '/index.html',
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
ErrorCode: 404,
|
|
239
|
+
ResponseCode: 200,
|
|
240
|
+
ResponsePagePath: '/index.html',
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
// Verify default root object is set
|
|
246
|
+
template.hasResourceProperties('AWS::CloudFront::Distribution', {
|
|
247
|
+
DistributionConfig: {
|
|
248
|
+
DefaultRootObject: 'index.html',
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
// Test: No unsuppressed warnings
|
|
253
|
+
test('No unsuppressed warnings', () => {
|
|
254
|
+
if (warnings.length > 0) {
|
|
255
|
+
console.log('CDK Nag Warnings:', JSON.stringify(warnings, null, 2));
|
|
256
|
+
}
|
|
257
|
+
expect(warnings).toHaveLength(0);
|
|
258
|
+
});
|
|
259
|
+
// Test: No unsuppressed errors
|
|
260
|
+
test('No unsuppressed errors', () => {
|
|
261
|
+
if (errors.length > 0) {
|
|
262
|
+
console.log('CDK Nag Errors:', JSON.stringify(errors, null, 2));
|
|
263
|
+
}
|
|
264
|
+
expect(errors).toHaveLength(0);
|
|
265
|
+
});
|
|
266
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJvbnRlbmQtY29uc3RydWN0LW5hZy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdXNlLWNhc2VzL3dlYmFwcC90ZXN0cy9mcm9udGVuZC1jb25zdHJ1Y3QtbmFnLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHFFQUFxRTtBQUNyRSxzQ0FBc0M7O0FBRXRDLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsNkNBQWtEO0FBQ2xELHVEQUFzRTtBQUN0RSwrRUFBaUU7QUFDakUseURBQXFEO0FBQ3JELHFDQUE4RDtBQUM5RCw4REFBaUQ7QUFFakQsNkNBQTZDO0FBQzdDLE1BQU0sWUFBWSxHQUFHLDhCQUE4QixDQUFDO0FBQ3BELElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7SUFDakMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxZQUFZLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztBQUNsRCxDQUFDO0FBQ0QsRUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsRUFBRSw0RkFBNEYsQ0FBQyxDQUFDO0FBRXRKLHVCQUF1QjtBQUN2QixNQUFNLEdBQUcsR0FBRyxJQUFJLGlCQUFHLEVBQUUsQ0FBQztBQUN0QixNQUFNLEtBQUssR0FBRyxJQUFJLG1CQUFLLENBQUMsR0FBRyxFQUFFLFdBQVcsRUFBRTtJQUN4QyxHQUFHLEVBQUU7UUFDSCxPQUFPLEVBQUUsY0FBYztRQUN2QixNQUFNLEVBQUUsV0FBVztLQUNwQjtDQUNGLENBQUMsQ0FBQztBQUVILG1EQUFtRDtBQUNuRCxNQUFNLFdBQVcsR0FBRyxvQ0FBVyxDQUFDLGtCQUFrQixDQUNoRCxLQUFLLEVBQ0wsYUFBYSxFQUNiLHFGQUFxRixDQUN0RixDQUFDO0FBRUYscUNBQXFDO0FBQ3JDLE1BQU0sVUFBVSxHQUFHLHdCQUFVLENBQUMsd0JBQXdCLENBQUMsS0FBSyxFQUFFLFlBQVksRUFBRTtJQUMxRSxZQUFZLEVBQUUsWUFBWTtJQUMxQixRQUFRLEVBQUUsYUFBYTtDQUN4QixDQUFDLENBQUM7QUFFSCxxQ0FBcUM7QUFDckMsTUFBTSxRQUFRLEdBQUcsSUFBSSw2QkFBUSxDQUFDLEtBQUssRUFBRSxjQUFjLEVBQUU7SUFDbkQsZUFBZSxFQUFFLHdCQUF3QjtJQUN6QyxvQkFBb0IsRUFBRSxZQUFZO0lBQ2xDLFlBQVksRUFBRTtRQUNaLFVBQVUsRUFBRSxpQkFBaUI7UUFDN0IsV0FBVztRQUNYLFVBQVU7S0FDWDtJQUNELFNBQVMsRUFBRSxJQUFJLEVBQUUseUJBQXlCO0NBQzNDLENBQUMsQ0FBQztBQUVILDJEQUEyRDtBQUMzRCx5QkFBZSxDQUFDLHVCQUF1QixDQUFDLEtBQUssRUFBRTtJQUM3QztRQUNFLEVBQUUsRUFBRSxtQkFBbUI7UUFDdkIsTUFBTSxFQUFFLDhFQUE4RTtLQUN2RjtJQUNEO1FBQ0UsRUFBRSxFQUFFLG1CQUFtQjtRQUN2QixNQUFNLEVBQUUseUVBQXlFO0tBQ2xGO0lBQ0Q7UUFDRSxFQUFFLEVBQUUsbUJBQW1CO1FBQ3ZCLE1BQU0sRUFBRSwwRUFBMEU7S0FDbkY7SUFDRDtRQUNFLEVBQUUsRUFBRSxtQkFBbUI7UUFDdkIsTUFBTSxFQUFFLDRFQUE0RTtLQUNyRjtJQUNEO1FBQ0UsRUFBRSxFQUFFLGlCQUFpQjtRQUNyQixNQUFNLEVBQUUseUVBQXlFO0tBQ2xGO0lBQ0Q7UUFDRSxFQUFFLEVBQUUsaUJBQWlCO1FBQ3JCLE1BQU0sRUFBRSxnRkFBZ0Y7S0FDekY7SUFDRDtRQUNFLEVBQUUsRUFBRSxpQkFBaUI7UUFDckIsTUFBTSxFQUFFLDhFQUE4RTtLQUN2RjtJQUNEO1FBQ0UsRUFBRSxFQUFFLGtCQUFrQjtRQUN0QixNQUFNLEVBQUUsMEVBQTBFO0tBQ25GO0lBQ0Q7UUFDRSxFQUFFLEVBQUUsbUJBQW1CO1FBQ3ZCLE1BQU0sRUFBRSx5RUFBeUU7UUFDakYsU0FBUyxFQUFFLENBQUMsdUZBQXVGLENBQUM7S0FDckc7SUFDRDtRQUNFLEVBQUUsRUFBRSxtQkFBbUI7UUFDdkIsTUFBTSxFQUFFLDRFQUE0RTtRQUNwRixTQUFTLEVBQUU7WUFDVCx1QkFBdUI7WUFDdkIsdUJBQXVCO1lBQ3ZCLGtCQUFrQjtZQUNsQiwwQkFBMEI7WUFDMUIsbUJBQW1CO1lBQ25CLDJGQUEyRjtZQUMzRixtRkFBbUY7WUFDbkYsc0RBQXNEO1lBQ3RELGFBQWE7U0FDZDtLQUNGO0lBQ0Q7UUFDRSxFQUFFLEVBQUUsaUJBQWlCO1FBQ3JCLE1BQU0sRUFBRSx5RUFBeUU7S0FDbEY7Q0FDRixFQUFFLElBQUksQ0FBQyxDQUFDO0FBRVQsdUJBQXVCO0FBQ3ZCLHFCQUFPLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLDRCQUFrQixDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztBQUUvRCx1QkFBdUI7QUFDdkIscUJBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7QUFFMUIsNkNBQTZDO0FBQzdDLE1BQU0sUUFBUSxHQUFHLHdCQUFXLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLFdBQVcsQ0FBQyxHQUFHLEVBQUUsa0JBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUM7QUFDMUcsTUFBTSxNQUFNLEdBQUcsd0JBQVcsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxrQkFBSyxDQUFDLGdCQUFnQixDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQztBQUV0Ryw4REFBOEQ7QUFDOUQsSUFBSSxDQUFDLDRDQUE0QyxFQUFFLEdBQUcsRUFBRTtJQUN0RCxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDL0IsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQzlDLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDdEMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM1QyxNQUFNLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7QUFDbEQsQ0FBQyxDQUFDLENBQUM7QUFFSCxtREFBbUQ7QUFDbkQsSUFBSSxDQUFDLDRDQUE0QyxFQUFFLEdBQUcsRUFBRTtJQUN0RCxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNqRCxNQUFNLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUMzRCxNQUFNLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQ3BELE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUN2RCxNQUFNLENBQUMsT0FBTyxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDcEQsTUFBTSxDQUFDLE9BQU8sUUFBUSxDQUFDLHNCQUFzQixFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDbEUsQ0FBQyxDQUFDLENBQUM7QUFFSCxzREFBc0Q7QUFDdEQsSUFBSSxDQUFDLCtDQUErQyxFQUFFLEdBQUcsRUFBRTtJQUN6RCxNQUFNLFFBQVEsR0FBRyxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUUzQyxzREFBc0Q7SUFDdEQsUUFBUSxDQUFDLHFCQUFxQixDQUFDLGlCQUFpQixFQUFFO1FBQ2hELGdCQUFnQixFQUFFO1lBQ2hCLGlDQUFpQyxFQUFFO2dCQUNqQztvQkFDRSw2QkFBNkIsRUFBRTt3QkFDN0IsWUFBWSxFQUFFLFFBQVE7cUJBQ3ZCO2lCQUNGO2FBQ0Y7U0FDRjtRQUNELDhCQUE4QixFQUFFO1lBQzlCLGVBQWUsRUFBRSxJQUFJO1lBQ3JCLGlCQUFpQixFQUFFLElBQUk7WUFDdkIsZ0JBQWdCLEVBQUUsSUFBSTtZQUN0QixxQkFBcUIsRUFBRSxJQUFJO1NBQzVCO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsb0VBQW9FO0lBQ3BFLFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQywrQkFBK0IsRUFBRTtRQUM5RCxrQkFBa0IsRUFBRTtZQUNsQixPQUFPLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQztZQUM1QixpQkFBaUIsRUFBRSxZQUFZO1lBQy9CLG9CQUFvQixFQUFFO2dCQUNwQixvQkFBb0IsRUFBRSxtQkFBbUI7YUFDMUM7WUFDRCxvQkFBb0IsRUFBRTtnQkFDcEI7b0JBQ0UsU0FBUyxFQUFFLEdBQUc7b0JBQ2QsWUFBWSxFQUFFLEdBQUc7b0JBQ2pCLGdCQUFnQixFQUFFLGFBQWE7aUJBQ2hDO2dCQUNEO29CQUNFLFNBQVMsRUFBRSxHQUFHO29CQUNkLFlBQVksRUFBRSxHQUFHO29CQUNqQixnQkFBZ0IsRUFBRSxhQUFhO2lCQUNoQzthQUNGO1lBQ0QsaUJBQWlCLEVBQUU7Z0JBQ2pCLGlCQUFpQixFQUFFLHFGQUFxRjtnQkFDeEcsZ0JBQWdCLEVBQUUsVUFBVTthQUM3QjtTQUNGO0tBQ0YsQ0FBQyxDQUFDO0lBRUgscURBQXFEO0lBQ3JELFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQywyQkFBMkIsRUFBRTtRQUMxRCxjQUFjLEVBQUU7WUFDZCxPQUFPLEVBQUUsbUJBQW1CO1NBQzdCO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsbURBQW1EO0lBQ25ELFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQyx5QkFBeUIsRUFBRTtRQUN4RCxJQUFJLEVBQUUsR0FBRztRQUNULElBQUksRUFBRSxrQkFBa0I7UUFDeEIsWUFBWSxFQUFFLFlBQVk7S0FDM0IsQ0FBQyxDQUFDO0lBRUgsa0NBQWtDO0lBQ2xDLFFBQVEsQ0FBQyxXQUFXLENBQUMsNkJBQTZCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFeEQsb0RBQW9EO0lBQ3BELFFBQVEsQ0FBQyxXQUFXLENBQUMsNkJBQTZCLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDMUQsQ0FBQyxDQUFDLENBQUM7QUFFSCw0REFBNEQ7QUFDNUQsSUFBSSxDQUFDLHFEQUFxRCxFQUFFLEdBQUcsRUFBRTtJQUMvRCxNQUFNLFFBQVEsR0FBRyxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUUzQyxvQ0FBb0M7SUFDcEMsUUFBUSxDQUFDLHFCQUFxQixDQUFDLCtCQUErQixFQUFFO1FBQzlELGtCQUFrQixFQUFFO1lBQ2xCLG9CQUFvQixFQUFFO2dCQUNwQixvQkFBb0IsRUFBRSxtQkFBbUI7YUFDMUM7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILHdDQUF3QztJQUN4QyxRQUFRLENBQUMscUJBQXFCLENBQUMsaUJBQWlCLEVBQUU7UUFDaEQsOEJBQThCLEVBQUU7WUFDOUIsZUFBZSxFQUFFLElBQUk7WUFDckIsaUJBQWlCLEVBQUUsSUFBSTtZQUN2QixnQkFBZ0IsRUFBRSxJQUFJO1lBQ3RCLHFCQUFxQixFQUFFLElBQUk7U0FDNUI7S0FDRixDQUFDLENBQUM7SUFFSCxrQ0FBa0M7SUFDbEMsUUFBUSxDQUFDLHFCQUFxQixDQUFDLGlCQUFpQixFQUFFO1FBQ2hELGdCQUFnQixFQUFFO1lBQ2hCLGlDQUFpQyxFQUFFO2dCQUNqQztvQkFDRSw2QkFBNkIsRUFBRTt3QkFDN0IsWUFBWSxFQUFFLFFBQVE7cUJBQ3ZCO2lCQUNGO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUgscURBQXFEO0FBQ3JELElBQUksQ0FBQyw4Q0FBOEMsRUFBRSxHQUFHLEVBQUU7SUFDeEQsTUFBTSxRQUFRLEdBQUcscUJBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFM0Msc0NBQXNDO0lBQ3RDLFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQywrQkFBK0IsRUFBRTtRQUM5RCxrQkFBa0IsRUFBRTtZQUNsQixvQkFBb0IsRUFBRTtnQkFDcEI7b0JBQ0UsU0FBUyxFQUFFLEdBQUc7b0JBQ2QsWUFBWSxFQUFFLEdBQUc7b0JBQ2pCLGdCQUFnQixFQUFFLGFBQWE7aUJBQ2hDO2dCQUNEO29CQUNFLFNBQVMsRUFBRSxHQUFHO29CQUNkLFlBQVksRUFBRSxHQUFHO29CQUNqQixnQkFBZ0IsRUFBRSxhQUFhO2lCQUNoQzthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUM7SUFFSCxvQ0FBb0M7SUFDcEMsUUFBUSxDQUFDLHFCQUFxQixDQUFDLCtCQUErQixFQUFFO1FBQzlELGtCQUFrQixFQUFFO1lBQ2xCLGlCQUFpQixFQUFFLFlBQVk7U0FDaEM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQztBQUVILGlDQUFpQztBQUNqQyxJQUFJLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxFQUFFO0lBQ3BDLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFDRCxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ25DLENBQUMsQ0FBQyxDQUFDO0FBRUgsK0JBQStCO0FBQy9CLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxHQUFHLEVBQUU7SUFDbEMsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3RCLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUNELE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDakMsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBBcHAsIFN0YWNrLCBBc3BlY3RzIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgVGVtcGxhdGUsIEFubm90YXRpb25zLCBNYXRjaCB9IGZyb20gJ2F3cy1jZGstbGliL2Fzc2VydGlvbnMnO1xuaW1wb3J0IHsgQ2VydGlmaWNhdGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyJztcbmltcG9ydCB7IEhvc3RlZFpvbmUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtcm91dGU1Myc7XG5pbXBvcnQgeyBBd3NTb2x1dGlvbnNDaGVja3MsIE5hZ1N1cHByZXNzaW9ucyB9IGZyb20gJ2Nkay1uYWcnO1xuaW1wb3J0IHsgRnJvbnRlbmQgfSBmcm9tICcuLi9mcm9udGVuZC1jb25zdHJ1Y3QnO1xuXG4vLyBDcmVhdGUgdGVtcG9yYXJ5IGJ1aWxkIGRpcmVjdG9yeSBmb3IgdGVzdHNcbmNvbnN0IHRlc3RCdWlsZERpciA9ICcvdG1wL3Rlc3QtZnJvbnRlbmQtYnVpbGQtbmFnJztcbmlmICghZnMuZXhpc3RzU3luYyh0ZXN0QnVpbGREaXIpKSB7XG4gIGZzLm1rZGlyU3luYyh0ZXN0QnVpbGREaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xufVxuZnMud3JpdGVGaWxlU3luYyhwYXRoLmpvaW4odGVzdEJ1aWxkRGlyLCAnaW5kZXguaHRtbCcpLCAnPCFET0NUWVBFIGh0bWw+PGh0bWw+PGhlYWQ+PHRpdGxlPlRlc3Q8L3RpdGxlPjwvaGVhZD48Ym9keT48aDE+VGVzdCBBcHA8L2gxPjwvYm9keT48L2h0bWw+Jyk7XG5cbi8vIENyZWF0ZSBhcHAgYW5kIHN0YWNrXG5jb25zdCBhcHAgPSBuZXcgQXBwKCk7XG5jb25zdCBzdGFjayA9IG5ldyBTdGFjayhhcHAsICdUZXN0U3RhY2snLCB7XG4gIGVudjoge1xuICAgIGFjY291bnQ6ICcxMjM0NTY3ODkwMTInLFxuICAgIHJlZ2lvbjogJ3VzLWVhc3QtMScsXG4gIH0sXG59KTtcblxuLy8gQ3JlYXRlIFNTTCBjZXJ0aWZpY2F0ZSBmb3IgY3VzdG9tIGRvbWFpbiB0ZXN0aW5nXG5jb25zdCBjZXJ0aWZpY2F0ZSA9IENlcnRpZmljYXRlLmZyb21DZXJ0aWZpY2F0ZUFybihcbiAgc3RhY2ssXG4gICdDZXJ0aWZpY2F0ZScsXG4gICdhcm46YXdzOmFjbTp1cy1lYXN0LTE6MTIzNDU2Nzg5MDEyOmNlcnRpZmljYXRlLzEyMzQ1Njc4LTEyMzQtMTIzNC0xMjM0LTEyMzQ1Njc4OTAxMicsXG4pO1xuXG4vLyBDcmVhdGUgaG9zdGVkIHpvbmUgZm9yIEROUyB0ZXN0aW5nXG5jb25zdCBob3N0ZWRab25lID0gSG9zdGVkWm9uZS5mcm9tSG9zdGVkWm9uZUF0dHJpYnV0ZXMoc3RhY2ssICdIb3N0ZWRab25lJywge1xuICBob3N0ZWRab25lSWQ6ICdaMTIzNDU2Nzg5JyxcbiAgem9uZU5hbWU6ICdleGFtcGxlLmNvbScsXG59KTtcblxuLy8gQ3JlYXRlIHRoZSBtYWluIEZyb250ZW5kIGNvbnN0cnVjdFxuY29uc3QgZnJvbnRlbmQgPSBuZXcgRnJvbnRlbmQoc3RhY2ssICdUZXN0RnJvbnRlbmQnLCB7XG4gIHNvdXJjZURpcmVjdG9yeTogJy90bXAvdGVzdC1mcm9udGVuZC1zcmMnLFxuICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICBjdXN0b21Eb21haW46IHtcbiAgICBkb21haW5OYW1lOiAnYXBwLmV4YW1wbGUuY29tJyxcbiAgICBjZXJ0aWZpY2F0ZSxcbiAgICBob3N0ZWRab25lLFxuICB9LFxuICBza2lwQnVpbGQ6IHRydWUsIC8vIFNraXAgYnVpbGQgZm9yIHRlc3Rpbmdcbn0pO1xuXG4vLyBBZGQgQ0RLIE5hZyBzdXBwcmVzc2lvbnMgZm9yIGtub3duIGFjY2VwdGFibGUgdmlvbGF0aW9uc1xuTmFnU3VwcHJlc3Npb25zLmFkZFJlc291cmNlU3VwcHJlc3Npb25zKHN0YWNrLCBbXG4gIHtcbiAgICBpZDogJ0F3c1NvbHV0aW9ucy1DRlIxJyxcbiAgICByZWFzb246ICdDbG91ZEZyb250IGdlbyByZXN0cmljdGlvbnMgYXJlIGNvbmZpZ3VyZWQgYmFzZWQgb24gYXBwbGljYXRpb24gcmVxdWlyZW1lbnRzJyxcbiAgfSxcbiAge1xuICAgIGlkOiAnQXdzU29sdXRpb25zLUNGUjInLFxuICAgIHJlYXNvbjogJ0Nsb3VkRnJvbnQgV0FGIGludGVncmF0aW9uIGlzIGNvbmZpZ3VyZWQgYmFzZWQgb24gc2VjdXJpdHkgcmVxdWlyZW1lbnRzJyxcbiAgfSxcbiAge1xuICAgIGlkOiAnQXdzU29sdXRpb25zLUNGUjMnLFxuICAgIHJlYXNvbjogJ0Nsb3VkRnJvbnQgYWNjZXNzIGxvZ2dpbmcgaXMgY29uZmlndXJlZCBiYXNlZCBvbiBjb21wbGlhbmNlIHJlcXVpcmVtZW50cycsXG4gIH0sXG4gIHtcbiAgICBpZDogJ0F3c1NvbHV0aW9ucy1DRlI0JyxcbiAgICByZWFzb246ICdDbG91ZEZyb250IHZpZXdlciBwcm90b2NvbCBwb2xpY3kgaXMgc2V0IHRvIHJlZGlyZWN0LXRvLWh0dHBzIGZvciBzZWN1cml0eScsXG4gIH0sXG4gIHtcbiAgICBpZDogJ0F3c1NvbHV0aW9ucy1TMScsXG4gICAgcmVhc29uOiAnUzMgYnVja2V0IGFjY2VzcyBsb2dnaW5nIGlzIGNvbmZpZ3VyZWQgYmFzZWQgb24gY29tcGxpYW5jZSByZXF1aXJlbWVudHMnLFxuICB9LFxuICB7XG4gICAgaWQ6ICdBd3NTb2x1dGlvbnMtUzInLFxuICAgIHJlYXNvbjogJ1MzIGJ1Y2tldCBwdWJsaWMgYWNjZXNzIGlzIGJsb2NrZWQgYW5kIGFjY2VzcyBpcyBjb250cm9sbGVkIHZpYSBDbG91ZEZyb250IE9BQycsXG4gIH0sXG4gIHtcbiAgICBpZDogJ0F3c1NvbHV0aW9ucy1TMycsXG4gICAgcmVhc29uOiAnUzMgYnVja2V0IFNTTCByZXF1ZXN0cyBvbmx5IHBvbGljeSBpcyBlbmZvcmNlZCB2aWEgQ2xvdWRGcm9udCBIVFRQUyByZWRpcmVjdCcsXG4gIH0sXG4gIHtcbiAgICBpZDogJ0F3c1NvbHV0aW9ucy1TMTAnLFxuICAgIHJlYXNvbjogJ1MzIGJ1Y2tldCBNRkEgZGVsZXRlIGlzIG1hbmFnZWQgdGhyb3VnaCBvcmdhbml6YXRpb25hbCBzZWN1cml0eSBwb2xpY2llcycsXG4gIH0sXG4gIHtcbiAgICBpZDogJ0F3c1NvbHV0aW9ucy1JQU00JyxcbiAgICByZWFzb246ICdBV1MgbWFuYWdlZCBwb2xpY2llcyBhcmUgYWNjZXB0YWJsZSBmb3Igc3RhbmRhcmQgTGFtYmRhIGV4ZWN1dGlvbiByb2xlcycsXG4gICAgYXBwbGllc1RvOiBbJ1BvbGljeTo6YXJuOjxBV1M6OlBhcnRpdGlvbj46aWFtOjphd3M6cG9saWN5L3NlcnZpY2Utcm9sZS9BV1NMYW1iZGFCYXNpY0V4ZWN1dGlvblJvbGUnXSxcbiAgfSxcbiAge1xuICAgIGlkOiAnQXdzU29sdXRpb25zLUlBTTUnLFxuICAgIHJlYXNvbjogJ0J1Y2tldERlcGxveW1lbnQgcmVxdWlyZXMgYnJvYWQgUzMgcGVybWlzc2lvbnMgdG8gbWFuYWdlIGRlcGxveW1lbnQgYXNzZXRzJyxcbiAgICBhcHBsaWVzVG86IFtcbiAgICAgICdBY3Rpb246OnMzOkdldE9iamVjdConLFxuICAgICAgJ0FjdGlvbjo6czM6R2V0QnVja2V0KicsXG4gICAgICAnQWN0aW9uOjpzMzpMaXN0KicsXG4gICAgICAnQWN0aW9uOjpzMzpEZWxldGVPYmplY3QqJyxcbiAgICAgICdBY3Rpb246OnMzOkFib3J0KicsXG4gICAgICAnUmVzb3VyY2U6OmFybjo8QVdTOjpQYXJ0aXRpb24+OnMzOjo6Y2RrLWhuYjY1OWZkcy1hc3NldHMtPEFXUzo6QWNjb3VudElkPi08QVdTOjpSZWdpb24+LyonLFxuICAgICAgJ1Jlc291cmNlOjphcm46PEFXUzo6UGFydGl0aW9uPjpzMzo6OmNkay1obmI2NTlmZHMtYXNzZXRzLTEyMzQ1Njc4OTAxMi11cy1lYXN0LTEvKicsXG4gICAgICAnUmVzb3VyY2U6OjxUZXN0RnJvbnRlbmRGcm9udGVuZEJ1Y2tldEQzN0QyMkRFLkFybj4vKicsXG4gICAgICAnUmVzb3VyY2U6OionLFxuICAgIF0sXG4gIH0sXG4gIHtcbiAgICBpZDogJ0F3c1NvbHV0aW9ucy1MMScsXG4gICAgcmVhc29uOiAnTGFtYmRhIHJ1bnRpbWUgdmVyc2lvbnMgYXJlIG1hbmFnZWQgYXQgdGhlIGFwcGxpY2F0aW9uIGRlcGxveW1lbnQgbGV2ZWwnLFxuICB9LFxuXSwgdHJ1ZSk7XG5cbi8vIEFwcGx5IENESyBOYWcgY2hlY2tzXG5Bc3BlY3RzLm9mKGFwcCkuYWRkKG5ldyBBd3NTb2x1dGlvbnNDaGVja3MoeyB2ZXJib3NlOiB0cnVlIH0pKTtcblxuLy8gU3ludGhlc2l6ZSB0aGUgc3RhY2tcblRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbi8vIENoZWNrIGZvciB1bnN1cHByZXNzZWQgd2FybmluZ3MgYW5kIGVycm9yc1xuY29uc3Qgd2FybmluZ3MgPSBBbm5vdGF0aW9ucy5mcm9tU3RhY2soc3RhY2spLmZpbmRXYXJuaW5nKCcqJywgTWF0Y2guc3RyaW5nTGlrZVJlZ2V4cCgnQXdzU29sdXRpb25zLS4qJykpO1xuY29uc3QgZXJyb3JzID0gQW5ub3RhdGlvbnMuZnJvbVN0YWNrKHN0YWNrKS5maW5kRXJyb3IoJyonLCBNYXRjaC5zdHJpbmdMaWtlUmVnZXhwKCdBd3NTb2x1dGlvbnMtLionKSk7XG5cbi8vIFRlc3Q6IEZyb250ZW5kIGNvbnN0cnVjdCBpcyBwcm9wZXJseSBjcmVhdGVkIGFuZCBhY2Nlc3NpYmxlXG50ZXN0KCdGcm9udGVuZCBjb25zdHJ1Y3QgaXMgY3JlYXRlZCBzdWNjZXNzZnVsbHknLCAoKSA9PiB7XG4gIGV4cGVjdChmcm9udGVuZCkudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGZyb250ZW5kLm5vZGUuaWQpLnRvQmUoJ1Rlc3RGcm9udGVuZCcpO1xuICBleHBlY3QoZnJvbnRlbmQuYnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoZnJvbnRlbmQuZGlzdHJpYnV0aW9uKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoZnJvbnRlbmQuYnVja2V0RGVwbG95bWVudCkudG9CZURlZmluZWQoKTtcbn0pO1xuXG4vLyBUZXN0OiBGcm9udGVuZCBjb25zdHJ1Y3QgaGFzIGV4cGVjdGVkIHByb3BlcnRpZXNcbnRlc3QoJ0Zyb250ZW5kIGNvbnN0cnVjdCBoYXMgZXhwZWN0ZWQgcHJvcGVydGllcycsICgpID0+IHtcbiAgZXhwZWN0KGZyb250ZW5kLmJ1Y2tldC5idWNrZXROYW1lKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoZnJvbnRlbmQuZGlzdHJpYnV0aW9uLmRpc3RyaWJ1dGlvbklkKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoZnJvbnRlbmQuZG9tYWluTmFtZSkudG9CZSgnYXBwLmV4YW1wbGUuY29tJyk7XG4gIGV4cGVjdChmcm9udGVuZC51cmwoKSkudG9CZSgnaHR0cHM6Ly9hcHAuZXhhbXBsZS5jb20nKTtcbiAgZXhwZWN0KHR5cGVvZiBmcm9udGVuZC5idWNrZXROYW1lKCkpLnRvQmUoJ3N0cmluZycpO1xuICBleHBlY3QodHlwZW9mIGZyb250ZW5kLmRpc3RyaWJ1dGlvbkRvbWFpbk5hbWUoKSkudG9CZSgnc3RyaW5nJyk7XG59KTtcblxuLy8gVGVzdDogVGVtcGxhdGUgY29udGFpbnMgZXhwZWN0ZWQgZnJvbnRlbmQgcmVzb3VyY2VzXG50ZXN0KCdUZW1wbGF0ZSBjb250YWlucyBleHBlY3RlZCBmcm9udGVuZCByZXNvdXJjZXMnLCAoKSA9PiB7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBWZXJpZnkgUzMgYnVja2V0IGV4aXN0cyB3aXRoIHNlY3VyaXR5IGNvbmZpZ3VyYXRpb25cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgQnVja2V0RW5jcnlwdGlvbjoge1xuICAgICAgU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBTZXJ2ZXJTaWRlRW5jcnlwdGlvbkJ5RGVmYXVsdDoge1xuICAgICAgICAgICAgU1NFQWxnb3JpdGhtOiAnQUVTMjU2JyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9LFxuICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjoge1xuICAgICAgQmxvY2tQdWJsaWNBY2xzOiB0cnVlLFxuICAgICAgQmxvY2tQdWJsaWNQb2xpY3k6IHRydWUsXG4gICAgICBJZ25vcmVQdWJsaWNBY2xzOiB0cnVlLFxuICAgICAgUmVzdHJpY3RQdWJsaWNCdWNrZXRzOiB0cnVlLFxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIFZlcmlmeSBDbG91ZEZyb250IGRpc3RyaWJ1dGlvbiBleGlzdHMgd2l0aCBzZWN1cml0eSBjb25maWd1cmF0aW9uXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb24nLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBBbGlhc2VzOiBbJ2FwcC5leGFtcGxlLmNvbSddLFxuICAgICAgRGVmYXVsdFJvb3RPYmplY3Q6ICdpbmRleC5odG1sJyxcbiAgICAgIERlZmF1bHRDYWNoZUJlaGF2aW9yOiB7XG4gICAgICAgIFZpZXdlclByb3RvY29sUG9saWN5OiAncmVkaXJlY3QtdG8taHR0cHMnLFxuICAgICAgfSxcbiAgICAgIEN1c3RvbUVycm9yUmVzcG9uc2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBFcnJvckNvZGU6IDQwMyxcbiAgICAgICAgICBSZXNwb25zZUNvZGU6IDIwMCxcbiAgICAgICAgICBSZXNwb25zZVBhZ2VQYXRoOiAnL2luZGV4Lmh0bWwnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgRXJyb3JDb2RlOiA0MDQsXG4gICAgICAgICAgUmVzcG9uc2VDb2RlOiAyMDAsXG4gICAgICAgICAgUmVzcG9uc2VQYWdlUGF0aDogJy9pbmRleC5odG1sJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBWaWV3ZXJDZXJ0aWZpY2F0ZToge1xuICAgICAgICBBY21DZXJ0aWZpY2F0ZUFybjogJ2Fybjphd3M6YWNtOnVzLWVhc3QtMToxMjM0NTY3ODkwMTI6Y2VydGlmaWNhdGUvMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MDEyJyxcbiAgICAgICAgU3NsU3VwcG9ydE1ldGhvZDogJ3NuaS1vbmx5JyxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gVmVyaWZ5IENsb3VkRnJvbnQgc2VjdXJpdHkgaGVhZGVycyBmdW5jdGlvbiBleGlzdHNcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OkNsb3VkRnJvbnQ6OkZ1bmN0aW9uJywge1xuICAgIEZ1bmN0aW9uQ29uZmlnOiB7XG4gICAgICBSdW50aW1lOiAnY2xvdWRmcm9udC1qcy0xLjAnLFxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIFZlcmlmeSBSb3V0ZTUzIEEgcmVjb3JkIGV4aXN0cyBmb3IgY3VzdG9tIGRvbWFpblxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6Um91dGU1Mzo6UmVjb3JkU2V0Jywge1xuICAgIFR5cGU6ICdBJyxcbiAgICBOYW1lOiAnYXBwLmV4YW1wbGUuY29tLicsXG4gICAgSG9zdGVkWm9uZUlkOiAnWjEyMzQ1Njc4OScsXG4gIH0pO1xuXG4gIC8vIFZlcmlmeSBidWNrZXQgZGVwbG95bWVudCBleGlzdHNcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2UoJ0N1c3RvbTo6Q0RLQnVja2V0RGVwbG95bWVudCcsIHt9KTtcblxuICAvLyBWZXJpZnkgYXV0byBkZWxldGUgb2JqZWN0cyBjdXN0b20gcmVzb3VyY2UgZXhpc3RzXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlKCdDdXN0b206OlMzQXV0b0RlbGV0ZU9iamVjdHMnLCB7fSk7XG59KTtcblxuLy8gVGVzdDogRnJvbnRlbmQgY29uc3RydWN0IGVuZm9yY2VzIHNlY3VyaXR5IGJlc3QgcHJhY3RpY2VzXG50ZXN0KCdGcm9udGVuZCBjb25zdHJ1Y3QgZW5mb3JjZXMgc2VjdXJpdHkgYmVzdCBwcmFjdGljZXMnLCAoKSA9PiB7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBWZXJpZnkgSFRUUFMgcmVkaXJlY3QgaXMgZW5mb3JjZWRcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvbicsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6IHtcbiAgICAgIERlZmF1bHRDYWNoZUJlaGF2aW9yOiB7XG4gICAgICAgIFZpZXdlclByb3RvY29sUG9saWN5OiAncmVkaXJlY3QtdG8taHR0cHMnLFxuICAgICAgfSxcbiAgICB9LFxuICB9KTtcblxuICAvLyBWZXJpZnkgUzMgYnVja2V0IGJsb2NrcyBwdWJsaWMgYWNjZXNzXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpTMzo6QnVja2V0Jywge1xuICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjoge1xuICAgICAgQmxvY2tQdWJsaWNBY2xzOiB0cnVlLFxuICAgICAgQmxvY2tQdWJsaWNQb2xpY3k6IHRydWUsXG4gICAgICBJZ25vcmVQdWJsaWNBY2xzOiB0cnVlLFxuICAgICAgUmVzdHJpY3RQdWJsaWNCdWNrZXRzOiB0cnVlLFxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIFZlcmlmeSBTMyBidWNrZXQgaGFzIGVuY3J5cHRpb25cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgQnVja2V0RW5jcnlwdGlvbjoge1xuICAgICAgU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBTZXJ2ZXJTaWRlRW5jcnlwdGlvbkJ5RGVmYXVsdDoge1xuICAgICAgICAgICAgU1NFQWxnb3JpdGhtOiAnQUVTMjU2JyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9LFxuICB9KTtcbn0pO1xuXG4vLyBUZXN0OiBGcm9udGVuZCBjb25zdHJ1Y3Qgc3VwcG9ydHMgU1BBIGFwcGxpY2F0aW9uc1xudGVzdCgnRnJvbnRlbmQgY29uc3RydWN0IHN1cHBvcnRzIFNQQSBhcHBsaWNhdGlvbnMnLCAoKSA9PiB7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBWZXJpZnkgU1BBLWZyaWVuZGx5IGVycm9yIHJlc3BvbnNlc1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uJywge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgQ3VzdG9tRXJyb3JSZXNwb25zZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIEVycm9yQ29kZTogNDAzLFxuICAgICAgICAgIFJlc3BvbnNlQ29kZTogMjAwLFxuICAgICAgICAgIFJlc3BvbnNlUGFnZVBhdGg6ICcvaW5kZXguaHRtbCcsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBFcnJvckNvZGU6IDQwNCxcbiAgICAgICAgICBSZXNwb25zZUNvZGU6IDIwMCxcbiAgICAgICAgICBSZXNwb25zZVBhZ2VQYXRoOiAnL2luZGV4Lmh0bWwnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9LFxuICB9KTtcblxuICAvLyBWZXJpZnkgZGVmYXVsdCByb290IG9iamVjdCBpcyBzZXRcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvbicsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6IHtcbiAgICAgIERlZmF1bHRSb290T2JqZWN0OiAnaW5kZXguaHRtbCcsXG4gICAgfSxcbiAgfSk7XG59KTtcblxuLy8gVGVzdDogTm8gdW5zdXBwcmVzc2VkIHdhcm5pbmdzXG50ZXN0KCdObyB1bnN1cHByZXNzZWQgd2FybmluZ3MnLCAoKSA9PiB7XG4gIGlmICh3YXJuaW5ncy5sZW5ndGggPiAwKSB7XG4gICAgY29uc29sZS5sb2coJ0NESyBOYWcgV2FybmluZ3M6JywgSlNPTi5zdHJpbmdpZnkod2FybmluZ3MsIG51bGwsIDIpKTtcbiAgfVxuICBleHBlY3Qod2FybmluZ3MpLnRvSGF2ZUxlbmd0aCgwKTtcbn0pO1xuXG4vLyBUZXN0OiBObyB1bnN1cHByZXNzZWQgZXJyb3JzXG50ZXN0KCdObyB1bnN1cHByZXNzZWQgZXJyb3JzJywgKCkgPT4ge1xuICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICBjb25zb2xlLmxvZygnQ0RLIE5hZyBFcnJvcnM6JywgSlNPTi5zdHJpbmdpZnkoZXJyb3JzLCBudWxsLCAyKSk7XG4gIH1cbiAgZXhwZWN0KGVycm9ycykudG9IYXZlTGVuZ3RoKDApO1xufSk7XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|