cdk-nextjs 0.6.1 → 0.7.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 +2467 -2714
- package/.jsii.tabl.json +1 -1
- package/API.md +1725 -1909
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +152 -170
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +687 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1548 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +852 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +861 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +13 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +11 -2
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/post-deploy.lambda.js +3 -2
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +19 -3
- package/lib/lambdas/post-deploy/prune-s3.js +54 -15
- package/lib/lambdas/post-deploy/prune-s3.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-s3.test.js +255 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +107 -18
- package/lib/nextjs-api.js +349 -39
- package/lib/nextjs-api.test.js +582 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +23 -3
- package/lib/nextjs-post-deploy.js +14 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +23 -4
- package/lib/nextjs-static-assets.js +29 -6
- package/lib/nextjs-static-assets.test.js +20 -1
- package/lib/root-constructs/nextjs-base-construct.d.ts +105 -45
- package/lib/root-constructs/nextjs-base-construct.js +144 -34
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -70
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -69
- package/lib/root-constructs/nextjs-regional-containers.d.ts +25 -5
- package/lib/root-constructs/nextjs-regional-containers.js +17 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -25
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1213 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1678 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41595 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +55 -0
- package/lib/runtime/next-modules.js +124 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41588 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +123 -11
- package/lib/utils/base-path.js +276 -39
- package/lib/utils/base-path.test.js +275 -50
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
|
@@ -5,11 +5,13 @@ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
|
5
5
|
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
6
|
const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront");
|
|
7
7
|
const aws_cloudfront_origins_1 = require("aws-cdk-lib/aws-cloudfront-origins");
|
|
8
|
+
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
|
|
8
9
|
const constructs_1 = require("constructs");
|
|
10
|
+
const function_groups_1 = require("./adapter/function-groups");
|
|
9
11
|
const constants_1 = require("./constants");
|
|
10
12
|
const base_path_1 = require("./utils/base-path");
|
|
11
13
|
class NextjsDistribution extends constructs_1.Construct {
|
|
12
|
-
static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-nextjs.NextjsDistribution", version: "0.
|
|
14
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-nextjs.NextjsDistribution", version: "0.7.0" };
|
|
13
15
|
distribution;
|
|
14
16
|
props;
|
|
15
17
|
/**
|
|
@@ -19,6 +21,13 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
19
21
|
* relying on the caller having passed one.
|
|
20
22
|
*/
|
|
21
23
|
basePath;
|
|
24
|
+
/**
|
|
25
|
+
* `props.assetPrefix` normalized to a leading-slash path, `""` when the app
|
|
26
|
+
* sets none or sets one that already equals the `basePath` prefix — in which
|
|
27
|
+
* case the ordinary `_next/static*` behavior already covers it and a second one
|
|
28
|
+
* would be a duplicate pattern CloudFront rejects.
|
|
29
|
+
*/
|
|
30
|
+
assetPrefix;
|
|
22
31
|
/**
|
|
23
32
|
* Common security headers applied by default to all origins
|
|
24
33
|
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-response-headers-policies.html#managed-response-headers-policies-security
|
|
@@ -43,7 +52,6 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
43
52
|
};
|
|
44
53
|
staticOrigin;
|
|
45
54
|
dynamicOrigin;
|
|
46
|
-
imageOrigin;
|
|
47
55
|
dynamicOriginResponsePolicy;
|
|
48
56
|
dynamicCloudFrontFunctionAssociations;
|
|
49
57
|
isFunctionCompute;
|
|
@@ -54,10 +62,11 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
54
62
|
super(scope, id);
|
|
55
63
|
this.props = props;
|
|
56
64
|
this.basePath = (0, base_path_1.normalizeBasePath)(props.basePath);
|
|
65
|
+
this.assetPrefix = this.resolveAssetPrefix();
|
|
57
66
|
this.staticOrigin = this.createStaticOrigin();
|
|
58
67
|
this.isFunctionCompute = props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS;
|
|
68
|
+
this.validateFunctionGroupProps();
|
|
59
69
|
this.dynamicOrigin = this.createDynamicOrigin();
|
|
60
|
-
this.imageOrigin = this.createImageOrigin();
|
|
61
70
|
this.dynamicOriginResponsePolicy = this.createDynamicOriginRequestPolicy();
|
|
62
71
|
this.dynamicCloudFrontFunctionAssociations =
|
|
63
72
|
this.createDynamicCloudFrontFunctionAssociations();
|
|
@@ -65,6 +74,9 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
65
74
|
this.dynamicBehaviorOptions = this.createDynamicBehaviorOptions();
|
|
66
75
|
this.imageBehaviorOptions = this.createImageBehaviorOptions();
|
|
67
76
|
this.distribution = this.getDistribution();
|
|
77
|
+
if (this.isFunctionCompute) {
|
|
78
|
+
this.grantInvoke(function_groups_1.DEFAULT_FUNCTION_GROUP, props.functionUrl);
|
|
79
|
+
}
|
|
68
80
|
this.addStaticBehaviors();
|
|
69
81
|
this.addDynamicBehaviors();
|
|
70
82
|
}
|
|
@@ -80,7 +92,11 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
80
92
|
return fullComment.length < 128 ? fullComment : baseComment;
|
|
81
93
|
}
|
|
82
94
|
createStaticOrigin() {
|
|
83
|
-
return aws_cloudfront_origins_1.S3BucketOrigin.withOriginAccessControl(this.props.assetsBucket,
|
|
95
|
+
return aws_cloudfront_origins_1.S3BucketOrigin.withOriginAccessControl(this.props.assetsBucket, {
|
|
96
|
+
// LIST lets S3 answer a missing key with 404 instead of 403
|
|
97
|
+
originAccessLevels: [aws_cloudfront_1.AccessLevel.READ, aws_cloudfront_1.AccessLevel.LIST],
|
|
98
|
+
...this.props.overrides?.s3BucketOriginProps,
|
|
99
|
+
});
|
|
84
100
|
}
|
|
85
101
|
createDynamicOrigin() {
|
|
86
102
|
if (this.isFunctionCompute) {
|
|
@@ -102,35 +118,22 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
102
118
|
});
|
|
103
119
|
}
|
|
104
120
|
}
|
|
105
|
-
/**
|
|
106
|
-
* A dedicated image optimization Lambda is only wired up when
|
|
107
|
-
* {@link NextjsDistributionProps.imageFunctionUrl} is supplied, which today
|
|
108
|
-
* only `NextjsType.GLOBAL_FUNCTIONS` does. Otherwise `_next/image*` keeps
|
|
109
|
-
* going to the dynamic origin, where the Next.js server optimizes images
|
|
110
|
-
* itself.
|
|
111
|
-
*
|
|
112
|
-
* The `_next/image*` behavior is kept either way: its cache policy
|
|
113
|
-
* (`queryStringBehavior: all()`, `accept` in the cache key) is the right one
|
|
114
|
-
* for image requests regardless of which origin answers them.
|
|
115
|
-
*/
|
|
116
|
-
createImageOrigin() {
|
|
117
|
-
if (!this.isFunctionCompute || !this.props.imageFunctionUrl) {
|
|
118
|
-
return this.dynamicOrigin;
|
|
119
|
-
}
|
|
120
|
-
return aws_cloudfront_origins_1.FunctionUrlOrigin.withOriginAccessControl(this.props.imageFunctionUrl, {
|
|
121
|
-
...this.props.overrides?.dynamicFunctionUrlOriginWithOACProps,
|
|
122
|
-
...this.props.overrides?.imageFunctionUrlOriginWithOACProps,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
121
|
/**
|
|
126
122
|
* Lambda Function URLs "expect the `Host` header to contain the origin domain
|
|
127
123
|
* name, not the domain name of the CloudFront distribution."
|
|
124
|
+
*
|
|
125
|
+
* A container origin also gets CloudFront's own headers, for
|
|
126
|
+
* `CloudFront-Forwarded-Proto`: without a certificate CloudFront reaches the
|
|
127
|
+
* ALB over plain HTTP, so the ALB's `X-Forwarded-Proto` is `http`, and the
|
|
128
|
+
* runtime would build every absolute URL (`request.url`, the origin a server
|
|
129
|
+
* action is forwarded to) as `http://` behind a viewer on HTTPS.
|
|
128
130
|
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html#managed-origin-request-policy-all-viewer-except-host-header
|
|
131
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html#managed-origin-request-policy-all-viewer-and-cloudfront
|
|
129
132
|
*/
|
|
130
133
|
createDynamicOriginRequestPolicy() {
|
|
131
134
|
return this.isFunctionCompute
|
|
132
135
|
? aws_cloudfront_1.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER
|
|
133
|
-
: aws_cloudfront_1.OriginRequestPolicy.
|
|
136
|
+
: aws_cloudfront_1.OriginRequestPolicy.ALL_VIEWER_AND_CLOUDFRONT_2022;
|
|
134
137
|
}
|
|
135
138
|
/**
|
|
136
139
|
* Ensures Next.js `request.url` will be correct domain instead of URL of
|
|
@@ -141,9 +144,66 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
141
144
|
const associations = [];
|
|
142
145
|
if (this.isFunctionCompute) {
|
|
143
146
|
const cloudFrontFn = new aws_cloudfront_1.Function(this, "CloudFrontFn", {
|
|
147
|
+
// cloudfront-js-1.0, so ES5.1: `var`, no arrow functions, no template
|
|
148
|
+
// literals, no `Object.keys`.
|
|
144
149
|
code: aws_cloudfront_1.FunctionCode.fromInline(`
|
|
145
150
|
function handler(event) {
|
|
146
151
|
var request = event.request;
|
|
152
|
+
var uri = request.uri;
|
|
153
|
+
|
|
154
|
+
// Next.js answers any path containing a backslash or a repeated
|
|
155
|
+
// slash with a 308 to the collapsed path
|
|
156
|
+
// (\`normalizeRepeatedSlashes\`, called from \`base-server.ts\`), and so
|
|
157
|
+
// does this runtime. Behind a Lambda Function URL the origin never
|
|
158
|
+
// gets the chance: Origin Access Control signs the raw path while the
|
|
159
|
+
// Function URL canonicalizes it before verifying, so the origin
|
|
160
|
+
// answers 403 SignatureDoesNotMatch. Doing the redirect here is what
|
|
161
|
+
// makes \`/basepath//to-sv\` behave as it does under \`next start\`.
|
|
162
|
+
//
|
|
163
|
+
// A bare \`//\` reaches here too, and is answered the same way -
|
|
164
|
+
// measured, because \`//\` at the start of a request target is also the
|
|
165
|
+
// authority form and it was not obvious CloudFront would route it to a
|
|
166
|
+
// function at all. It does: \`GET //\` answers 308 to \`/\` with
|
|
167
|
+
// \`x-cache: FunctionGeneratedResponse\`, over both HTTP/1.1 and HTTP/2,
|
|
168
|
+
// which is what \`test/e2e/hydration\` asks for.
|
|
169
|
+
//
|
|
170
|
+
// Two things Next.js does that this cannot:
|
|
171
|
+
//
|
|
172
|
+
// - the body it sends with its own redirect (the destination, as
|
|
173
|
+
// text), because a generated response can only carry one on
|
|
174
|
+
// cloudfront-js-2.0. No known client reads it.
|
|
175
|
+
// - the original order of the query string. The event exposes
|
|
176
|
+
// \`querystring\` as an object, never as the raw string, so
|
|
177
|
+
// \`/x//y?a=1&b=2\` redirects to \`/x/y?b=2&a=1\`. The pairs all
|
|
178
|
+
// survive; only their order is CloudFront's rather than the
|
|
179
|
+
// client's, and a redirect target is not order-sensitive.
|
|
180
|
+
//
|
|
181
|
+
// A repeated key's \`multiValue\` already holds its first value, which
|
|
182
|
+
// \`value\` repeats, so it is one or the other, never both. Names and
|
|
183
|
+
// values arrive as the client sent them, still percent-encoded
|
|
184
|
+
// (measured: \`?a=%20b%26c&p=1+2\` reads back unchanged), so they are
|
|
185
|
+
// joined as-is; encoding them again would turn \`%20\` into \`%2520\`.
|
|
186
|
+
if (/\\\\|\\/\\//.test(uri)) {
|
|
187
|
+
var location = uri.replace(/\\\\/g, "/").replace(/\\/\\/+/g, "/");
|
|
188
|
+
var qs = [];
|
|
189
|
+
for (var name in request.querystring) {
|
|
190
|
+
var q = request.querystring[name];
|
|
191
|
+
var values = q.multiValue || [q];
|
|
192
|
+
for (var i = 0; i < values.length; i++) {
|
|
193
|
+
var v = values[i].value;
|
|
194
|
+
qs.push(v === "" ? name : name + "=" + v);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (qs.length) {
|
|
198
|
+
location = location + "?" + qs.join("&");
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
statusCode: 308,
|
|
202
|
+
statusDescription: "Permanent Redirect",
|
|
203
|
+
headers: { location: { value: location } },
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
147
207
|
request.headers["x-forwarded-host"] = request.headers.host;
|
|
148
208
|
return request;
|
|
149
209
|
}
|
|
@@ -176,30 +236,21 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
176
236
|
}
|
|
177
237
|
createDynamicBehaviorOptions() {
|
|
178
238
|
const dynamicBehaviorOptions = this.props.overrides?.dynamicBehaviorOptions;
|
|
239
|
+
const cachePolicyProps = this.props.overrides?.dynamicCachePolicyProps;
|
|
179
240
|
// create default cache policy if not provided
|
|
180
241
|
const cachePolicy = dynamicBehaviorOptions?.cachePolicy ??
|
|
181
242
|
new aws_cloudfront_1.CachePolicy(this, "DynamicCachePolicy", {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
"next-router-state-tree", // App Router navigation state
|
|
192
|
-
"next-router-prefetch", // prefetch behavior
|
|
193
|
-
"next-router-segment-prefetch", // segment-level prefetching
|
|
194
|
-
"x-matched-path", // dynamic routes and rewrites
|
|
195
|
-
"x-prerender-revalidate", // on-demand ISR revalidation
|
|
196
|
-
"x-next-cache-tags", // tag-based cache revalidation
|
|
197
|
-
"x-prerender-bypass"),
|
|
198
|
-
cookieBehavior: aws_cloudfront_1.CacheCookieBehavior.all(),
|
|
199
|
-
enableAcceptEncodingBrotli: true,
|
|
200
|
-
enableAcceptEncodingGzip: true,
|
|
243
|
+
...(isCachingDisabled(cachePolicyProps)
|
|
244
|
+
? DISABLED_CACHE_KEY
|
|
245
|
+
: DYNAMIC_CACHE_KEY),
|
|
246
|
+
// A response with no `Cache-Control` is not cached, which is what Next.js
|
|
247
|
+
// and every app written for it assume: a dynamic route handler sets none.
|
|
248
|
+
// CDK's default is a day, which cached `/api/*` responses at the edge for
|
|
249
|
+
// 24 hours. Anything Next.js *means* to cache - ISR, SSG, a PPR shell -
|
|
250
|
+
// says so with `s-maxage`, which `maxTtl` still honors.
|
|
251
|
+
defaultTtl: aws_cdk_lib_1.Duration.seconds(0),
|
|
201
252
|
comment: this.getComment("NextJS Dynamic Cache Policy", aws_cdk_lib_1.Stack.of(this).stackName),
|
|
202
|
-
...
|
|
253
|
+
...cachePolicyProps,
|
|
203
254
|
});
|
|
204
255
|
const responseHeadersPolicy = dynamicBehaviorOptions?.responseHeadersPolicy ??
|
|
205
256
|
new aws_cloudfront_1.ResponseHeadersPolicy(this, "DynamicResponseHeadersPolicy", {
|
|
@@ -210,14 +261,53 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
210
261
|
return {
|
|
211
262
|
allowedMethods: aws_cloudfront_1.AllowedMethods.ALLOW_ALL,
|
|
212
263
|
cachePolicy,
|
|
213
|
-
functionAssociations: this.dynamicCloudFrontFunctionAssociations,
|
|
214
264
|
origin: this.dynamicOrigin,
|
|
215
265
|
originRequestPolicy: this.dynamicOriginResponsePolicy,
|
|
216
266
|
responseHeadersPolicy,
|
|
217
267
|
viewerProtocolPolicy: aws_cloudfront_1.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
218
268
|
...dynamicBehaviorOptions,
|
|
269
|
+
functionAssociations: this.withDynamicFunctionAssociations("dynamicBehaviorOptions", dynamicBehaviorOptions?.functionAssociations),
|
|
219
270
|
};
|
|
220
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* The behavior's function associations: an override's, plus the viewer-request
|
|
274
|
+
* function Global Functions depends on.
|
|
275
|
+
*
|
|
276
|
+
* Spreading the override's `functionAssociations` over ours would silently
|
|
277
|
+
* drop that function, and with it the only thing standing between a viewer's
|
|
278
|
+
* own `X-Forwarded-Host` and the runtime, which trusts that header on Function
|
|
279
|
+
* URL events (`lambda-event.ts`): host injection into redirects and absolute
|
|
280
|
+
* URLs, cached for other viewers because the header is not in the cache key.
|
|
281
|
+
* So ours is kept, and an override claiming VIEWER_REQUEST — which CloudFront
|
|
282
|
+
* allows only one of per behavior — is an error rather than a replacement.
|
|
283
|
+
*/
|
|
284
|
+
withDynamicFunctionAssociations(overrideName, overridden) {
|
|
285
|
+
if (!overridden) {
|
|
286
|
+
return this.dynamicCloudFrontFunctionAssociations;
|
|
287
|
+
}
|
|
288
|
+
if (!this.isFunctionCompute) {
|
|
289
|
+
return overridden;
|
|
290
|
+
}
|
|
291
|
+
const claimed = overridden.some((association) => association.eventType === aws_cloudfront_1.FunctionEventType.VIEWER_REQUEST);
|
|
292
|
+
if (claimed) {
|
|
293
|
+
throw new Error(`${constants_1.LOG_PREFIX} \`overrides.${overrideName}.functionAssociations\` ` +
|
|
294
|
+
`associates a CloudFront function with ` +
|
|
295
|
+
`${aws_cloudfront_1.FunctionEventType.VIEWER_REQUEST}, but NextjsGlobalFunctions needs ` +
|
|
296
|
+
`that event type for its own function, which overwrites ` +
|
|
297
|
+
`\`x-forwarded-host\` with the viewer's \`Host\` (the runtime trusts ` +
|
|
298
|
+
`that header behind CloudFront) and redirects repeated slashes. ` +
|
|
299
|
+
`CloudFront permits only one function per event type per behavior. ` +
|
|
300
|
+
`Move the logic to ${aws_cloudfront_1.FunctionEventType.VIEWER_RESPONSE}, or into ` +
|
|
301
|
+
`the app's middleware.`);
|
|
302
|
+
}
|
|
303
|
+
return [...overridden, ...this.dynamicCloudFrontFunctionAssociations];
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* `_next/image*` goes to the same origin as everything else — the Next.js
|
|
307
|
+
* server optimizes images in-process — but keeps its own behavior for the
|
|
308
|
+
* cache policy: `queryStringBehavior: all()` plus `accept` in the cache key is
|
|
309
|
+
* right for image requests and wrong for the rest.
|
|
310
|
+
*/
|
|
221
311
|
createImageBehaviorOptions() {
|
|
222
312
|
const imageBehaviorOptions = this.props.overrides?.imageBehaviorOptions;
|
|
223
313
|
// add default cache policy if not provided
|
|
@@ -245,13 +335,13 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
245
335
|
return {
|
|
246
336
|
allowedMethods: aws_cloudfront_1.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
247
337
|
cachedMethods: aws_cloudfront_1.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
248
|
-
|
|
249
|
-
origin: this.imageOrigin,
|
|
338
|
+
origin: this.dynamicOrigin,
|
|
250
339
|
originRequestPolicy: this.dynamicOriginResponsePolicy,
|
|
251
340
|
cachePolicy,
|
|
252
341
|
responseHeadersPolicy,
|
|
253
342
|
viewerProtocolPolicy: aws_cloudfront_1.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
254
343
|
...imageBehaviorOptions,
|
|
344
|
+
functionAssociations: this.withDynamicFunctionAssociations("imageBehaviorOptions", imageBehaviorOptions?.functionAssociations),
|
|
255
345
|
};
|
|
256
346
|
}
|
|
257
347
|
/**
|
|
@@ -278,6 +368,10 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
278
368
|
addDynamicBehaviors() {
|
|
279
369
|
// Image Behavior
|
|
280
370
|
this.distribution.addBehavior(this.getPathPattern("_next/image*"), this.imageBehaviorOptions.origin, this.imageBehaviorOptions);
|
|
371
|
+
// Function group behaviors, before the basePath catch-all below and after
|
|
372
|
+
// `_next/image*` (no group pattern can match an image request, and keeping
|
|
373
|
+
// the order of the unsplit case byte-identical is worth more than symmetry).
|
|
374
|
+
this.addFunctionGroupBehaviors();
|
|
281
375
|
// Root Path Behaviors
|
|
282
376
|
if (this.basePath) {
|
|
283
377
|
// because we already have a basePath we don't use / instead we use /base-path
|
|
@@ -289,31 +383,410 @@ class NextjsDistribution extends constructs_1.Construct {
|
|
|
289
383
|
// if no base path, then default behavior will handle all other paths
|
|
290
384
|
}
|
|
291
385
|
}
|
|
386
|
+
/**
|
|
387
|
+
* Before any behavior is computed: the budget and the `public/` checks both
|
|
388
|
+
* generate the group patterns, and would otherwise fail first with a less
|
|
389
|
+
* useful message.
|
|
390
|
+
*/
|
|
391
|
+
validateFunctionGroupProps() {
|
|
392
|
+
if (!this.props.functionGroups?.length &&
|
|
393
|
+
!this.props.functionGroupBehaviors?.length) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (!this.isFunctionCompute) {
|
|
397
|
+
throw new Error("`functionGroups` is only supported by NextjsGlobalFunctions.");
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Every group behavior, final path pattern included, in the order
|
|
402
|
+
* {@link addFunctionGroupBehaviors} adds them.
|
|
403
|
+
*/
|
|
404
|
+
functionGroupBehaviors() {
|
|
405
|
+
return (this.props.functionGroupBehaviors ?? []).map((behavior) => {
|
|
406
|
+
const group = this.props.functionGroups?.find((it) => it.name === behavior.group);
|
|
407
|
+
if (!group) {
|
|
408
|
+
throw new Error(`${constants_1.LOG_PREFIX} \`functionGroupBehaviors\` routes to function group ` +
|
|
409
|
+
`"${behavior.group}", which is not in \`functionGroups\`.`);
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
...behavior,
|
|
413
|
+
group,
|
|
414
|
+
pathPattern: this.getPathPattern(behavior.pattern),
|
|
415
|
+
};
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* One behavior per group pattern, most specific first.
|
|
420
|
+
*
|
|
421
|
+
* The order is the whole mechanism. CloudFront evaluates behaviors in order
|
|
422
|
+
* and stops at the first whose path pattern matches, and `addBehavior`
|
|
423
|
+
* appends — so `api/*` added before `api/reports/*` would swallow every
|
|
424
|
+
* report request and send it to a function whose package has no report
|
|
425
|
+
* entrypoint. The adapter sorted the list when it checked it against how
|
|
426
|
+
* `assignRoutesToGroups` packaged the same routes, so it is added as it is.
|
|
427
|
+
*/
|
|
428
|
+
addFunctionGroupBehaviors() {
|
|
429
|
+
const originPerGroup = new Map();
|
|
430
|
+
for (const { group, pathPattern } of this.functionGroupBehaviors()) {
|
|
431
|
+
let origin = originPerGroup.get(group.name);
|
|
432
|
+
if (!origin) {
|
|
433
|
+
origin = aws_cloudfront_origins_1.FunctionUrlOrigin.withOriginAccessControl(group.functionUrl, this.props.overrides?.dynamicFunctionUrlOriginWithOACProps);
|
|
434
|
+
originPerGroup.set(group.name, origin);
|
|
435
|
+
this.grantInvoke(group.name, group.functionUrl);
|
|
436
|
+
}
|
|
437
|
+
// Same behavior options as every other dynamic route — only the origin
|
|
438
|
+
// differs, and it is passed separately.
|
|
439
|
+
const { origin: _ignored, ...behaviorOptions } = this.dynamicBehaviorOptions;
|
|
440
|
+
this.distribution.addBehavior(pathPattern, origin, behaviorOptions);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* `lambda:InvokeFunction` for CloudFront, which a Function URL behind OAC
|
|
445
|
+
* needs besides the `lambda:InvokeFunctionUrl` `FunctionUrlOrigin` grants,
|
|
446
|
+
* and scoped the same way: to this distribution, and to calls that come
|
|
447
|
+
* through the Function URL.
|
|
448
|
+
*/
|
|
449
|
+
grantInvoke(group, functionUrl) {
|
|
450
|
+
new aws_lambda_1.CfnPermission(this, `InvokeFunction-${group}`, {
|
|
451
|
+
action: "lambda:InvokeFunction",
|
|
452
|
+
principal: "cloudfront.amazonaws.com",
|
|
453
|
+
functionName: functionUrl.functionArn,
|
|
454
|
+
sourceArn: this.distribution.distributionArn,
|
|
455
|
+
invokedViaFunctionUrl: true,
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* The `assetPrefix` path that needs a behavior of its own, or `""` for none.
|
|
460
|
+
*
|
|
461
|
+
* An absolute prefix contributes its *path*: "https://cdn.example.com" needs no
|
|
462
|
+
* behavior, but "https://cdn.example.com/cdn" does, because `next build`
|
|
463
|
+
* compiles a `/cdn/_next/:path+` rewrite of its own and `next start` serves
|
|
464
|
+
* every bundle under that path — so a CDN fronting this distribution there has
|
|
465
|
+
* to be answered. A prefix equal to the `basePath` prefix is dropped — that is
|
|
466
|
+
* the Next.js default when `basePath` is set, and `_next/static*` already
|
|
467
|
+
* resolves under it, so adding a second identical pattern would make CloudFront
|
|
468
|
+
* reject the distribution.
|
|
469
|
+
*/
|
|
470
|
+
resolveAssetPrefix() {
|
|
471
|
+
const prefix = (0, base_path_1.assetPrefixPath)(this.props.assetPrefix ?? "");
|
|
472
|
+
return (0, base_path_1.normalizeBasePath)(prefix) === this.basePath ? "" : prefix;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Serves `<assetPrefix>/_next/static/*` from the same S3 objects as
|
|
476
|
+
* `_next/static/*`.
|
|
477
|
+
*
|
|
478
|
+
* Needed because Next.js puts `assetPrefix` in front of every bundle URL it
|
|
479
|
+
* emits while the objects keep their `<basePath>/_next/static/...` keys, and
|
|
480
|
+
* `assetPrefix` sits on top of `basePath` rather than under it, so
|
|
481
|
+
* `getPathPattern` is deliberately not used here. Without this behavior the
|
|
482
|
+
* request falls through to the default one, reaches the compute origin, and
|
|
483
|
+
* 404s: the deployment package carries no `.next/static` directory at all.
|
|
484
|
+
*
|
|
485
|
+
* A viewer-request function does the rewrite because an S3 origin keys on the
|
|
486
|
+
* request URI and `originPath` can only prepend. The prefix is a synth-time
|
|
487
|
+
* literal, so the function is a fixed-length string operation rather than a
|
|
488
|
+
* parse.
|
|
489
|
+
*/
|
|
490
|
+
addAssetPrefixBehavior() {
|
|
491
|
+
// CloudFront allows one function per event type per behavior, so an override
|
|
492
|
+
// that already claims VIEWER_REQUEST on the static behavior cannot coexist
|
|
493
|
+
// with the rewrite below — the distribution would synth and then be rejected
|
|
494
|
+
// at deploy, naming neither. Thrown here instead, where both halves are
|
|
495
|
+
// known.
|
|
496
|
+
const claimed = (this.staticBehaviorOptions.functionAssociations ?? []).some((association) => association.eventType === aws_cloudfront_1.FunctionEventType.VIEWER_REQUEST);
|
|
497
|
+
if (claimed) {
|
|
498
|
+
throw new Error(`${constants_1.LOG_PREFIX} \`overrides.staticBehaviorOptions.functionAssociations\` ` +
|
|
499
|
+
`already associates a CloudFront function with ` +
|
|
500
|
+
`${aws_cloudfront_1.FunctionEventType.VIEWER_REQUEST}, but serving \`assetPrefix\` ` +
|
|
501
|
+
`("${this.assetPrefix}") needs that event type to rewrite the request ` +
|
|
502
|
+
`URI to the object's key, and CloudFront permits only one function per ` +
|
|
503
|
+
`event type per behavior. Either drop the override, or fold its logic ` +
|
|
504
|
+
`into a single function and set \`assetPrefix\` to "" so this ` +
|
|
505
|
+
`construct adds no behavior of its own.`);
|
|
506
|
+
}
|
|
507
|
+
const rewrite = new aws_cloudfront_1.Function(this, "AssetPrefixFn", {
|
|
508
|
+
comment: this.getComment("NextJS assetPrefix rewrite", aws_cdk_lib_1.Stack.of(this).stackName),
|
|
509
|
+
code: aws_cloudfront_1.FunctionCode.fromInline(`
|
|
510
|
+
function handler(event) {
|
|
511
|
+
var request = event.request;
|
|
512
|
+
request.uri = ${JSON.stringify(this.basePath ? `/${this.basePath}` : "")} + request.uri.slice(${this.assetPrefix.length});
|
|
513
|
+
return request;
|
|
514
|
+
}
|
|
515
|
+
`),
|
|
516
|
+
});
|
|
517
|
+
this.distribution.addBehavior(`${this.assetPrefix}/_next/static*`, this.staticOrigin, {
|
|
518
|
+
...this.staticBehaviorOptions,
|
|
519
|
+
functionAssociations: [
|
|
520
|
+
...(this.staticBehaviorOptions.functionAssociations ?? []),
|
|
521
|
+
{ eventType: aws_cloudfront_1.FunctionEventType.VIEWER_REQUEST, function: rewrite },
|
|
522
|
+
],
|
|
523
|
+
});
|
|
524
|
+
}
|
|
292
525
|
addStaticBehaviors() {
|
|
293
526
|
this.distribution.addBehavior(this.getPathPattern("_next/static*"), this.staticOrigin, this.staticBehaviorOptions);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
throw new Error(`Too many public/ files in Next.js build. CloudFront limits Distributions to 25 Cache Behaviors. See documented limit here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-web-distributions. Try including all public files into 1 top level directory (i.e. static/*).`);
|
|
527
|
+
if (this.assetPrefix) {
|
|
528
|
+
this.addAssetPrefixBehavior();
|
|
297
529
|
}
|
|
530
|
+
const publicPathPatterns = this.publicPathPatterns();
|
|
531
|
+
this.assertBehaviorBudget(publicPathPatterns.length);
|
|
532
|
+
this.assertNoPublicCollisions(publicPathPatterns);
|
|
533
|
+
for (const pathPattern of publicPathPatterns) {
|
|
534
|
+
this.distribution.addBehavior(pathPattern, this.staticOrigin, this.staticBehaviorOptions);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* The behavior path pattern for each top-level `public/` entry, final form:
|
|
539
|
+
* `/*` for a directory and the basePath prefix both applied.
|
|
540
|
+
*
|
|
541
|
+
* An entry whose name has no character CloudFront can spell is left out, with
|
|
542
|
+
* a warning, rather than given a pattern of nothing but wildcards. `фото/` is
|
|
543
|
+
* `????????/*` — any 8-byte first segment — and public/ behaviors are added
|
|
544
|
+
* ahead of every compute behavior, so it would send `/products/42` and
|
|
545
|
+
* `/settings/*` to S3, which answers 403. Leaving the entry out costs its own
|
|
546
|
+
* files instead: those requests reach the compute, which does not have them,
|
|
547
|
+
* and 404. One literal character is enough to keep a pattern narrow —
|
|
548
|
+
* `????????.jpg` only matches `.jpg` requests — so only the all-wildcard ones
|
|
549
|
+
* go.
|
|
550
|
+
*
|
|
551
|
+
* The length limit is checked here, on the final pattern, rather than in
|
|
552
|
+
* {@link toPathPattern}: the `/*` and the basePath count against it too, and a
|
|
553
|
+
* pattern that passed without them failed at deploy instead.
|
|
554
|
+
*/
|
|
555
|
+
publicPathPatterns() {
|
|
556
|
+
const patterns = [];
|
|
557
|
+
const unmatchable = [];
|
|
298
558
|
for (const publicFile of this.props.publicDirEntries) {
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
559
|
+
const name = toPathPattern(publicFile.name);
|
|
560
|
+
if (!/[^?*/]/.test(name)) {
|
|
561
|
+
unmatchable.push(`"${publicFile.name}"`);
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
const pathPattern = this.getPathPattern(publicFile.isDirectory ? `${name}/*` : name);
|
|
565
|
+
if (pathPattern.length > MAX_PATH_PATTERN_LENGTH) {
|
|
566
|
+
throw new Error(`The public/ entry "${publicFile.name}" needs a ` +
|
|
567
|
+
`${pathPattern.length}-character CloudFront path pattern, over ` +
|
|
568
|
+
`the ${MAX_PATH_PATTERN_LENGTH}-character ` +
|
|
569
|
+
"limit. Rename it, or move it into a subdirectory of public/ whose " +
|
|
570
|
+
"own name is short enough. See " +
|
|
571
|
+
"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesCacheBehavior.html#DownloadDistValuesPathPattern");
|
|
304
572
|
}
|
|
305
|
-
|
|
306
|
-
|
|
573
|
+
patterns.push(pathPattern);
|
|
574
|
+
}
|
|
575
|
+
if (unmatchable.length > 0) {
|
|
576
|
+
aws_cdk_lib_1.Annotations.of(this).addWarning(`${constants_1.LOG_PREFIX} These top-level public/ entries have no character a ` +
|
|
577
|
+
"CloudFront path pattern can spell, so their pattern would be " +
|
|
578
|
+
"wildcards alone and would capture every app route of the same " +
|
|
579
|
+
`length. They get no behavior, so their requests reach the server, ` +
|
|
580
|
+
`which reads them from S3 instead: ${unmatchable.join(", ")}. To serve ` +
|
|
581
|
+
"them from S3 directly, rename them, or move them into a public/ " +
|
|
582
|
+
"subdirectory whose name has at least one ASCII letter or digit.");
|
|
307
583
|
}
|
|
584
|
+
return patterns;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Refuse a group behavior that a `public/` behavior would make unreachable.
|
|
588
|
+
*
|
|
589
|
+
* `public/` behaviors are added first, and CloudFront stops at the first match,
|
|
590
|
+
* so two cases send a group's route to S3 instead of its function — which is
|
|
591
|
+
* why this is checked at synth, where both sides are known:
|
|
592
|
+
* - the same pattern twice: `public/docs/` and `/docs/**` both deploy as
|
|
593
|
+
* `docs/*`. The synth succeeded and CloudFront rejected the deploy.
|
|
594
|
+
* - a group pattern under a public directory: `/docs/guide/**` behind
|
|
595
|
+
* `docs/*` deploys and never matches.
|
|
596
|
+
*/
|
|
597
|
+
assertNoPublicCollisions(publicPathPatterns) {
|
|
598
|
+
const publicRegexes = publicPathPatterns.map((pattern) => ({
|
|
599
|
+
pattern,
|
|
600
|
+
regex: (0, function_groups_1.cloudFrontPatternRegex)(`/${pattern.replace(/^\/+/, "")}`),
|
|
601
|
+
}));
|
|
602
|
+
for (const { group, route, pathPattern } of this.functionGroupBehaviors()) {
|
|
603
|
+
const duplicate = publicPathPatterns.includes(pathPattern);
|
|
604
|
+
// Matching the group pattern's own text is enough: its only wildcard is a
|
|
605
|
+
// trailing `*`, so a public pattern that matches the text up to and
|
|
606
|
+
// including it matches every URL the group pattern does.
|
|
607
|
+
const shadow = duplicate
|
|
608
|
+
? undefined
|
|
609
|
+
: publicRegexes.find(({ regex }) => regex.test(`/${pathPattern.replace(/^\/+/, "")}`));
|
|
610
|
+
if (!duplicate && !shadow) {
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
throw new Error(`${constants_1.LOG_PREFIX} \`functionGroups\` pattern "${route}" (group ` +
|
|
614
|
+
`"${group.name}") ` +
|
|
615
|
+
(duplicate
|
|
616
|
+
? `deploys as the path pattern "${pathPattern}", which a top-level ` +
|
|
617
|
+
`public/ entry already uses — CloudFront rejects a distribution ` +
|
|
618
|
+
`with two behaviors on one path pattern. `
|
|
619
|
+
: `deploys as "${pathPattern}", but the top-level public/ entry ` +
|
|
620
|
+
`behind "${shadow.pattern}" is matched first and sends every ` +
|
|
621
|
+
`such request to S3, so the group's function would never see ` +
|
|
622
|
+
`them. `) +
|
|
623
|
+
`Move those public/ files under a directory no route uses, or ` +
|
|
624
|
+
`group a different path.`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* CloudFront has a per-distribution cache behavior quota, counting the default
|
|
629
|
+
* one — 75 unless raised, and `maxCacheBehaviors` says which — and there are
|
|
630
|
+
* three things competing for it: `public/` entries, function groups, and
|
|
631
|
+
* cdk-nextjs's own fixed set.
|
|
632
|
+
* Checked in one place so the error can say which to cut.
|
|
633
|
+
*
|
|
634
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-web-distributions
|
|
635
|
+
*/
|
|
636
|
+
assertBehaviorBudget(publicPatterns) {
|
|
637
|
+
const limit = this.props.maxCacheBehaviors ?? DEFAULT_MAX_CACHE_BEHAVIORS;
|
|
638
|
+
if (aws_cdk_lib_1.Token.isUnresolved(limit)) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
const groupPatterns = this.functionGroupBehaviors().length;
|
|
642
|
+
// The default behavior, `_next/image*`, `_next/static*`, plus — with a
|
|
643
|
+
// basePath — the two that stand in for the default behavior's coverage, and
|
|
644
|
+
// — with a path-style assetPrefix — the one that serves bundles under it.
|
|
645
|
+
// `this.basePath`, not the raw prop: `basePath: "/"` normalizes to `""` and
|
|
646
|
+
// adds no behaviors, so counting it added 2 to the total and could throw
|
|
647
|
+
// "over the limit" on an app that is under it.
|
|
648
|
+
const fixed = 3 + (this.basePath ? 2 : 0) + (this.assetPrefix ? 1 : 0);
|
|
649
|
+
const total = fixed + publicPatterns + groupPatterns;
|
|
650
|
+
if (total <= limit) {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
const parts = [
|
|
654
|
+
`${fixed} used by cdk-nextjs itself`,
|
|
655
|
+
`${publicPatterns} for top-level public/ entries`,
|
|
656
|
+
];
|
|
657
|
+
if (groupPatterns) {
|
|
658
|
+
parts.push(`${groupPatterns} for \`functionGroups\` patterns`);
|
|
659
|
+
}
|
|
660
|
+
throw new Error(`This Next.js app needs ${total} CloudFront cache behaviors, over the ` +
|
|
661
|
+
`limit of ${limit} per distribution: ${parts.join(", ")}. ` +
|
|
662
|
+
`Move public/ files into a single top-level directory (one behavior ` +
|
|
663
|
+
`serves \`static/*\`)` +
|
|
664
|
+
(groupPatterns
|
|
665
|
+
? `, and prefer one subtree pattern per function group over several ` +
|
|
666
|
+
`exact paths`
|
|
667
|
+
: ``) +
|
|
668
|
+
`. If your account's quota is higher than ${limit}, set ` +
|
|
669
|
+
`\`maxCacheBehaviors\` to it. See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-web-distributions`);
|
|
308
670
|
}
|
|
309
671
|
/**
|
|
310
672
|
* Optionally prepends base path to given path pattern.
|
|
673
|
+
*
|
|
674
|
+
* A trailing slash on `pathPattern` is load-bearing and survives, which is why
|
|
675
|
+
* this concatenates rather than going through `joinPath`. The build's
|
|
676
|
+
* `functionGroupBehaviors` hold both "pricing" and "pricing/" for a
|
|
677
|
+
* `trailingSlash` app, and normalizing the second one collapsed it onto the
|
|
678
|
+
* first: `addBehavior` was
|
|
679
|
+
* then called twice with `/base/pricing`, which CloudFront rejects at deploy
|
|
680
|
+
* ("more than one cache behavior has the same path pattern"), and the
|
|
681
|
+
* canonical `/base/pricing/` was left to the `/base/*` catch-all — the misroute
|
|
682
|
+
* the second pattern exists to prevent.
|
|
311
683
|
*/
|
|
312
684
|
getPathPattern(pathPattern) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
685
|
+
if (!this.basePath) {
|
|
686
|
+
return pathPattern;
|
|
687
|
+
}
|
|
688
|
+
return `/${this.basePath}/${pathPattern.replace(/^\/+/, "")}`;
|
|
316
689
|
}
|
|
317
690
|
}
|
|
318
691
|
exports.NextjsDistribution = NextjsDistribution;
|
|
319
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWRpc3RyaWJ1dGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9uZXh0anMtZGlzdHJpYnV0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSw2Q0FBOEM7QUFFOUMsK0RBMkJvQztBQUNwQywrRUFNNEM7QUFJNUMsMkNBQXVDO0FBQ3ZDLDJDQUF5QztBQUl6QyxpREFBZ0U7QUE4RGhFLE1BQWEsa0JBQW1CLFNBQVEsc0JBQVM7O0lBQy9DLFlBQVksQ0FBZTtJQUVuQixLQUFLLENBQTBCO0lBQ3ZDOzs7OztPQUtHO0lBQ0ssUUFBUSxDQUFTO0lBQ3pCOzs7T0FHRztJQUNLLDZCQUE2QixHQUFvQztRQUN2RSxrQkFBa0IsRUFBRSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUU7UUFDdkMsWUFBWSxFQUFFO1lBQ1osV0FBVyxFQUFFLG1DQUFrQixDQUFDLFVBQVU7WUFDMUMsUUFBUSxFQUFFLEtBQUs7U0FDaEI7UUFDRCxjQUFjLEVBQUU7WUFDZCxRQUFRLEVBQUUsS0FBSztZQUNmLGNBQWMsRUFBRSxzQ0FBcUIsQ0FBQywrQkFBK0I7U0FDdEU7UUFFRCx1QkFBdUIsRUFBRTtZQUN2QixtQkFBbUIsRUFBRSxzQkFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7WUFDdkMsaUJBQWlCLEVBQUUsSUFBSTtZQUN2QixRQUFRLEVBQUUsS0FBSztZQUNmLE9BQU8sRUFBRSxJQUFJO1NBQ2Q7UUFDRCxhQUFhLEVBQUUsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRTtLQUN0RSxDQUFDO0lBQ00sWUFBWSxDQUFVO0lBQ3RCLGFBQWEsQ0FBVTtJQUN2QixXQUFXLENBQVU7SUFDckIsMkJBQTJCLENBQXVCO0lBQ2xELHFDQUFxQyxDQUF3QjtJQUM3RCxpQkFBaUIsQ0FBVTtJQUMzQixxQkFBcUIsQ0FBa0I7SUFDdkMsc0JBQXNCLENBQWtCO0lBQ3hD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QVUsQ0FBQyxJQUFJLElBQUk7Z0JBQ3hCLENBQUMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO1lBQ3BCLElBQUksQ0FBQywrQkFBK0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztnQkFDdkQsTUFBTSxJQUFJLEtBQUssQ0FDYixnRUFBZ0UsV0FBVyx3S0FBd0ssQ0FDcFAsQ0FBQztZQUNKLENBQUM7WUFDRCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDMUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQzNCLGdCQUFnQixFQUNoQixJQUFJLENBQUMsWUFBWSxFQUNqQixJQUFJLENBQUMscUJBQXFCLENBQzNCLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUNEOztPQUVHO0lBQ0ssY0FBYyxDQUFDLFdBQW1CO1FBQ3hDLE9BQU8sSUFBSSxDQUFDLFFBQVE7WUFDbEIsQ0FBQyxDQUFDLElBQUksSUFBQSxvQkFBUSxFQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLEVBQUU7WUFDNUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQztJQUNsQixDQUFDOztBQS9XSCxnREFnWEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEdXJhdGlvbiwgU3RhY2sgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IElDZXJ0aWZpY2F0ZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBBZGRCZWhhdmlvck9wdGlvbnMsXG4gIEFsbG93ZWRNZXRob2RzLFxuICBCZWhhdmlvck9wdGlvbnMsXG4gIENhY2hlQ29va2llQmVoYXZpb3IsXG4gIENhY2hlSGVhZGVyQmVoYXZpb3IsXG4gIENhY2hlUG9saWN5LFxuICBDYWNoZVBvbGljeVByb3BzLFxuICBDYWNoZVF1ZXJ5U3RyaW5nQmVoYXZpb3IsXG4gIENhY2hlZE1ldGhvZHMsXG4gIEZ1bmN0aW9uIGFzIENsb3VkRnJvbnRGdW5jdGlvbixcbiAgRGlzdHJpYnV0aW9uLFxuICBGdW5jdGlvbkFzc29jaWF0aW9uLFxuICBGdW5jdGlvbkNvZGUsXG4gIEZ1bmN0aW9uRXZlbnRUeXBlLFxuICBIZWFkZXJzRnJhbWVPcHRpb24sXG4gIEhlYWRlcnNSZWZlcnJlclBvbGljeSxcbiAgSHR0cFZlcnNpb24sXG4gIElPcmlnaW4sXG4gIElPcmlnaW5SZXF1ZXN0UG9saWN5LFxuICBPcmlnaW5Qcm90b2NvbFBvbGljeSxcbiAgT3JpZ2luUmVxdWVzdFBvbGljeSxcbiAgUmVzcG9uc2VIZWFkZXJzUG9saWN5LFxuICBSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcyxcbiAgUmVzcG9uc2VTZWN1cml0eUhlYWRlcnNCZWhhdmlvcixcbiAgU2VjdXJpdHlQb2xpY3lQcm90b2NvbCxcbiAgVmlld2VyUHJvdG9jb2xQb2xpY3ksXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udFwiO1xuaW1wb3J0IHtcbiAgRnVuY3Rpb25VcmxPcmlnaW4sXG4gIEZ1bmN0aW9uVXJsT3JpZ2luV2l0aE9BQ1Byb3BzLFxuICBTM0J1Y2tldE9yaWdpbixcbiAgVnBjT3JpZ2luLFxuICBWcGNPcmlnaW5XaXRoRW5kcG9pbnRQcm9wcyxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jbG91ZGZyb250LW9yaWdpbnNcIjtcbmltcG9ydCB7IElBcHBsaWNhdGlvbkxvYWRCYWxhbmNlciB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWxhc3RpY2xvYWRiYWxhbmNpbmd2MlwiO1xuaW1wb3J0IHsgSUZ1bmN0aW9uVXJsIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGFcIjtcbmltcG9ydCB7IElCdWNrZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXMzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgTmV4dGpzVHlwZSB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgT3B0aW9uYWxEaXN0cmlidXRpb25Qcm9wcyB9IGZyb20gXCIuL2dlbmVyYXRlZC1zdHJ1Y3RzL09wdGlvbmFsRGlzdHJpYnV0aW9uUHJvcHNcIjtcbmltcG9ydCB7IE9wdGlvbmFsUzNPcmlnaW5CdWNrZXRXaXRoT0FDUHJvcHMgfSBmcm9tIFwiLi9nZW5lcmF0ZWQtc3RydWN0cy9PcHRpb25hbFMzT3JpZ2luQnVja2V0V2l0aE9BQ1Byb3BzXCI7XG5pbXBvcnQgeyBQdWJsaWNEaXJFbnRyeSB9IGZyb20gXCIuL25leHRqcy1idWlsZC9uZXh0anMtYnVpbGRcIjtcbmltcG9ydCB7IGpvaW5QYXRoLCBub3JtYWxpemVCYXNlUGF0aCB9IGZyb20gXCIuL3V0aWxzL2Jhc2UtcGF0aFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0Rpc3RyaWJ1dGlvbk92ZXJyaWRlcyB7XG4gIHJlYWRvbmx5IGRpc3RyaWJ1dGlvblByb3BzPzogT3B0aW9uYWxEaXN0cmlidXRpb25Qcm9wcztcbiAgcmVhZG9ubHkgaW1hZ2VCZWhhdmlvck9wdGlvbnM/OiBBZGRCZWhhdmlvck9wdGlvbnM7XG4gIHJlYWRvbmx5IGltYWdlQ2FjaGVQb2xpY3lQcm9wcz86IENhY2hlUG9saWN5UHJvcHM7XG4gIHJlYWRvbmx5IGltYWdlUmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM/OiBSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcztcbiAgcmVhZG9ubHkgZHluYW1pY0JlaGF2aW9yT3B0aW9ucz86IEFkZEJlaGF2aW9yT3B0aW9ucztcbiAgcmVhZG9ubHkgZHluYW1pY0NhY2hlUG9saWN5UHJvcHM/OiBDYWNoZVBvbGljeVByb3BzO1xuICByZWFkb25seSBkeW5hbWljUmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM/OiBSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcztcbiAgcmVhZG9ubHkgZHluYW1pY0Z1bmN0aW9uVXJsT3JpZ2luV2l0aE9BQ1Byb3BzPzogRnVuY3Rpb25VcmxPcmlnaW5XaXRoT0FDUHJvcHM7XG4gIHJlYWRvbmx5IGR5bmFtaWNWcGNPcmlnaW5XaXRoRW5kcG9pbnRQcm9wcz86IFZwY09yaWdpbldpdGhFbmRwb2ludFByb3BzO1xuICByZWFkb25seSBpbWFnZUZ1bmN0aW9uVXJsT3JpZ2luV2l0aE9BQ1Byb3BzPzogRnVuY3Rpb25VcmxPcmlnaW5XaXRoT0FDUHJvcHM7XG4gIHJlYWRvbmx5IHN0YXRpY0JlaGF2aW9yT3B0aW9ucz86IEFkZEJlaGF2aW9yT3B0aW9ucztcbiAgcmVhZG9ubHkgc3RhdGljUmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM/OiBSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcztcbiAgcmVhZG9ubHkgczNCdWNrZXRPcmlnaW5Qcm9wcz86IE9wdGlvbmFsUzNPcmlnaW5CdWNrZXRXaXRoT0FDUHJvcHM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzRGlzdHJpYnV0aW9uUHJvcHMge1xuICAvKipcbiAgICogQnVja2V0IGNvbnRhaW5pbmcgc3RhdGljIGFzc2V0cy5cbiAgICogTXVzdCBiZSBwcm92aWRlZCBpZiB5b3Ugd2FudCB0byBzZXJ2ZSBzdGF0aWMgZmlsZXMuXG4gICAqL1xuICByZWFkb25seSBhc3NldHNCdWNrZXQ6IElCdWNrZXQ7XG4gIC8qKlxuICAgKiBVUkkgcGF0aCBwcmVmaXggdGhlIGFwcCBpcyBzZXJ2ZWQgYXQuIFN1cnJvdW5kaW5nIHNsYXNoZXMgYXJlIG5vcm1hbGl6ZWRcbiAgICogYXdheSwgc28gXCIvYmFzZVwiLCBcImJhc2VcIiBhbmQgXCIvYmFzZS9cIiBhbGwgcHJvZHVjZSB0aGUgc2FtZSBjYWNoZSBiZWhhdmlvcnMuXG4gICAqL1xuICByZWFkb25seSBiYXNlUGF0aD86IHN0cmluZztcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGJ1dCBvbmx5IGFwcGxpY2FibGUgZm9yIGBOZXh0anNUeXBlLkdMT0JBTF9DT05UQUlORVJTYFxuICAgKi9cbiAgcmVhZG9ubHkgY2VydGlmaWNhdGU/OiBJQ2VydGlmaWNhdGU7XG4gIHJlYWRvbmx5IGRpc3RyaWJ1dGlvbj86IERpc3RyaWJ1dGlvbjtcbiAgLyoqXG4gICAqIFJlcXVpcmVkIGlmIGBOZXh0anNUeXBlLkdMT0JBTF9GVU5DVElPTlNgXG4gICAqL1xuICByZWFkb25seSBmdW5jdGlvblVybD86IElGdW5jdGlvblVybDtcbiAgLyoqXG4gICAqIEZ1bmN0aW9uIFVSTCBvZiB0aGUgZGVkaWNhdGVkIGltYWdlIG9wdGltaXphdGlvbiBMYW1iZGEuIE9ubHkgYXBwbGljYWJsZVxuICAgKiB0byBgTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TYCwgYW5kIG9ubHkgd2hlbiB0aGUgZGVkaWNhdGVkIGltYWdlXG4gICAqIGZ1bmN0aW9uIGlzIGVuYWJsZWQuIFdoZW4gb21pdHRlZCwgdGhlIGBfbmV4dC9pbWFnZSpgIGJlaGF2aW9yIHBvaW50cyBhdFxuICAgKiB0aGUgZHluYW1pYyBvcmlnaW4sIHdoaWNoIHNlcnZlcyBpbWFnZSBvcHRpbWl6YXRpb24gZnJvbSB0aGUgTmV4dC5qc1xuICAgKiBzZXJ2ZXIgaXRzZWxmLlxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2VGdW5jdGlvblVybD86IElGdW5jdGlvblVybDtcbiAgLyoqXG4gICAqIFJlcXVpcmVkIGlmIGBOZXh0anNUeXBlLkdMT0JBTF9DT05UQUlORVJTYCBvciBgTmV4dGpzVHlwZS5SRUdJT05BTF9DT05UQUlORVJTYFxuICAgKi9cbiAgcmVhZG9ubHkgbG9hZEJhbGFuY2VyPzogSUFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyO1xuICByZWFkb25seSBuZXh0anNUeXBlOiBOZXh0anNUeXBlO1xuICAvKipcbiAgICogT3ZlcnJpZGUgcHJvcHMgZm9yIGV2ZXJ5IGNvbnN0cnVjdC5cbiAgICovXG4gIHJlYWRvbmx5IG92ZXJyaWRlcz86IE5leHRqc0Rpc3RyaWJ1dGlvbk92ZXJyaWRlcztcbiAgLyoqXG4gICAqIEVudHJpZXMgKGZpbGVzL2RpcmVjdG9yaWVzKSB3aXRoaW4gTmV4dC5qcyBhcHAncyBwdWJsaWMgZGlyZWN0b3J5LiBVc2VkIHRvXG4gICAqIGFkZCBzdGF0aWMgYmVoYXZpb3JzIHRvIGRpc3RyaWJ1dGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IHB1YmxpY0RpckVudHJpZXM6IFB1YmxpY0RpckVudHJ5W107XG59XG5cbmV4cG9ydCBjbGFzcyBOZXh0anNEaXN0cmlidXRpb24gZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBkaXN0cmlidXRpb246IERpc3RyaWJ1dGlvbjtcblxuICBwcml2YXRlIHByb3BzOiBOZXh0anNEaXN0cmlidXRpb25Qcm9wcztcbiAgLyoqXG4gICAqIGBwcm9wcy5iYXNlUGF0aGAgbm9ybWFsaXplZCB0byBhIGJhcmUgcGF0aCBzZWdtZW50LiBUaGlzIGNvbnN0cnVjdCBpcyB0aGVcbiAgICogb25lIHBsYWNlIHRoYXQgbmVlZHMgaXQgd2l0aCBhIGxlYWRpbmcgc2xhc2gg4oCUIENsb3VkRnJvbnQgcGF0aCBwYXR0ZXJucyBhcmVcbiAgICogd3JpdHRlbiBhZ2FpbnN0IHRoZSByZXF1ZXN0IHBhdGgg4oCUIHNvIGl0IHByZXBlbmRzIGl0cyBvd24gcmF0aGVyIHRoYW5cbiAgICogcmVseWluZyBvbiB0aGUgY2FsbGVyIGhhdmluZyBwYXNzZWQgb25lLlxuICAgKi9cbiAgcHJpdmF0ZSBiYXNlUGF0aDogc3RyaW5nO1xuICAvKipcbiAgICogQ29tbW9uIHNlY3VyaXR5IGhlYWRlcnMgYXBwbGllZCBieSBkZWZhdWx0IHRvIGFsbCBvcmlnaW5zXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkRnJvbnQvbGF0ZXN0L0RldmVsb3Blckd1aWRlL3VzaW5nLW1hbmFnZWQtcmVzcG9uc2UtaGVhZGVycy1wb2xpY2llcy5odG1sI21hbmFnZWQtcmVzcG9uc2UtaGVhZGVycy1wb2xpY2llcy1zZWN1cml0eVxuICAgKi9cbiAgcHJpdmF0ZSBjb21tb25TZWN1cml0eUhlYWRlcnNCZWhhdmlvcjogUmVzcG9uc2VTZWN1cml0eUhlYWRlcnNCZWhhdmlvciA9IHtcbiAgICBjb250ZW50VHlwZU9wdGlvbnM6IHsgb3ZlcnJpZGU6IGZhbHNlIH0sXG4gICAgZnJhbWVPcHRpb25zOiB7XG4gICAgICBmcmFtZU9wdGlvbjogSGVhZGVyc0ZyYW1lT3B0aW9uLlNBTUVPUklHSU4sXG4gICAgICBvdmVycmlkZTogZmFsc2UsXG4gICAgfSxcbiAgICByZWZlcnJlclBvbGljeToge1xuICAgICAgb3ZlcnJpZGU6IGZhbHNlLFxuICAgICAgcmVmZXJyZXJQb2xpY3k6IEhlYWRlcnNSZWZlcnJlclBvbGljeS5TVFJJQ1RfT1JJR0lOX1dIRU5fQ1JPU1NfT1JJR0lOLFxuICAgIH0sXG5cbiAgICBzdHJpY3RUcmFuc3BvcnRTZWN1cml0eToge1xuICAgICAgYWNjZXNzQ29udHJvbE1heEFnZTogRHVyYXRpb24uZGF5cygzNjUpLFxuICAgICAgaW5jbHVkZVN1YmRvbWFpbnM6IHRydWUsXG4gICAgICBvdmVycmlkZTogZmFsc2UsXG4gICAgICBwcmVsb2FkOiB0cnVlLFxuICAgIH0sXG4gICAgeHNzUHJvdGVjdGlvbjogeyBvdmVycmlkZTogZmFsc2UsIHByb3RlY3Rpb246IHRydWUsIG1vZGVCbG9jazogdHJ1ZSB9LFxuICB9O1xuICBwcml2YXRlIHN0YXRpY09yaWdpbjogSU9yaWdpbjtcbiAgcHJpdmF0ZSBkeW5hbWljT3JpZ2luOiBJT3JpZ2luO1xuICBwcml2YXRlIGltYWdlT3JpZ2luOiBJT3JpZ2luO1xuICBwcml2YXRlIGR5bmFtaWNPcmlnaW5SZXNwb25zZVBvbGljeTogSU9yaWdpblJlcXVlc3RQb2xpY3k7XG4gIHByaXZhdGUgZHluYW1pY0Nsb3VkRnJvbnRGdW5jdGlvbkFzc29jaWF0aW9uczogRnVuY3Rpb25Bc3NvY2lhdGlvbltdO1xuICBwcml2YXRlIGlzRnVuY3Rpb25Db21wdXRlOiBib29sZWFuO1xuICBwcml2YXRlIHN0YXRpY0JlaGF2aW9yT3B0aW9uczogQmVoYXZpb3JPcHRpb25zO1xuICBwcml2YXRlIGR5bmFtaWNCZWhhdmlvck9wdGlvbnM6IEJlaGF2aW9yT3B0aW9ucztcbiAgcHJpdmF0ZSBpbWFnZUJlaGF2aW9yT3B0aW9uczogQmVoYXZpb3JPcHRpb25zO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOZXh0anNEaXN0cmlidXRpb25Qcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuICAgIHRoaXMuYmFzZVBhdGggPSBub3JtYWxpemVCYXNlUGF0aChwcm9wcy5iYXNlUGF0aCk7XG4gICAgdGhpcy5zdGF0aWNPcmlnaW4gPSB0aGlzLmNyZWF0ZVN0YXRpY09yaWdpbigpO1xuICAgIHRoaXMuaXNGdW5jdGlvbkNvbXB1dGUgPSBwcm9wcy5uZXh0anNUeXBlID09PSBOZXh0anNUeXBlLkdMT0JBTF9GVU5DVElPTlM7XG4gICAgdGhpcy5keW5hbWljT3JpZ2luID0gdGhpcy5jcmVhdGVEeW5hbWljT3JpZ2luKCk7XG4gICAgdGhpcy5pbWFnZU9yaWdpbiA9IHRoaXMuY3JlYXRlSW1hZ2VPcmlnaW4oKTtcbiAgICB0aGlzLmR5bmFtaWNPcmlnaW5SZXNwb25zZVBvbGljeSA9IHRoaXMuY3JlYXRlRHluYW1pY09yaWdpblJlcXVlc3RQb2xpY3koKTtcbiAgICB0aGlzLmR5bmFtaWNDbG91ZEZyb250RnVuY3Rpb25Bc3NvY2lhdGlvbnMgPVxuICAgICAgdGhpcy5jcmVhdGVEeW5hbWljQ2xvdWRGcm9udEZ1bmN0aW9uQXNzb2NpYXRpb25zKCk7XG4gICAgdGhpcy5zdGF0aWNCZWhhdmlvck9wdGlvbnMgPSB0aGlzLmNyZWF0ZVN0YXRpY0JlaGF2aW9yT3B0aW9ucygpO1xuICAgIHRoaXMuZHluYW1pY0JlaGF2aW9yT3B0aW9ucyA9IHRoaXMuY3JlYXRlRHluYW1pY0JlaGF2aW9yT3B0aW9ucygpO1xuICAgIHRoaXMuaW1hZ2VCZWhhdmlvck9wdGlvbnMgPSB0aGlzLmNyZWF0ZUltYWdlQmVoYXZpb3JPcHRpb25zKCk7XG4gICAgdGhpcy5kaXN0cmlidXRpb24gPSB0aGlzLmdldERpc3RyaWJ1dGlvbigpO1xuICAgIHRoaXMuYWRkU3RhdGljQmVoYXZpb3JzKCk7XG4gICAgdGhpcy5hZGREeW5hbWljQmVoYXZpb3JzKCk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIENsb3VkRnJvbnQgY29tbWVudCB0aGF0IGlzIHNhZmUgZm9yIHRoZSAxMjggY2hhcmFjdGVyIGxpbWl0LlxuICAgKiBJZiB0aGUgZnVsbCBjb21tZW50IHdpdGggc3RhY2sgbmFtZSBleGNlZWRzIDEyOCBjaGFyYWN0ZXJzLCByZXR1cm5zIHRoZSBiYXNlIGNvbW1lbnQgb25seS5cbiAgICogQHBhcmFtIGJhc2VDb21tZW50IFRoZSBiYXNlIGNvbW1lbnQgdGV4dFxuICAgKiBAcGFyYW0gc3RhY2tOYW1lIFRoZSBzdGFjayBuYW1lIHRvIGFwcGVuZFxuICAgKiBAcmV0dXJucyBBIGNvbW1lbnQgc3RyaW5nIHRoYXQgaXMgZ3VhcmFudGVlZCB0byBiZSA8IDEyOCBjaGFyYWN0ZXJzXG4gICAqL1xuICBwcml2YXRlIGdldENvbW1lbnQoYmFzZUNvbW1lbnQ6IHN0cmluZywgc3RhY2tOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGZ1bGxDb21tZW50ID0gYCR7YmFzZUNvbW1lbnR9IGZvciAke3N0YWNrTmFtZX1gO1xuICAgIHJldHVybiBmdWxsQ29tbWVudC5sZW5ndGggPCAxMjggPyBmdWxsQ29tbWVudCA6IGJhc2VDb21tZW50O1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVTdGF0aWNPcmlnaW4oKTogSU9yaWdpbiB7XG4gICAgcmV0dXJuIFMzQnVja2V0T3JpZ2luLndpdGhPcmlnaW5BY2Nlc3NDb250cm9sKFxuICAgICAgdGhpcy5wcm9wcy5hc3NldHNCdWNrZXQsXG4gICAgICB0aGlzLnByb3BzLm92ZXJyaWRlcz8uczNCdWNrZXRPcmlnaW5Qcm9wcyxcbiAgICApO1xuICB9XG4gIHByaXZhdGUgY3JlYXRlRHluYW1pY09yaWdpbigpOiBJT3JpZ2luIHtcbiAgICBpZiAodGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZSkge1xuICAgICAgaWYgKCF0aGlzLnByb3BzLmZ1bmN0aW9uVXJsKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1pc3NpbmcgTmV4dGpzRGlzdHJpYnV0aW9uUHJvcHMuZnVuY3Rpb25VcmxcIik7XG4gICAgICB9XG4gICAgICByZXR1cm4gRnVuY3Rpb25VcmxPcmlnaW4ud2l0aE9yaWdpbkFjY2Vzc0NvbnRyb2woXG4gICAgICAgIHRoaXMucHJvcHMuZnVuY3Rpb25VcmwsXG4gICAgICAgIHRoaXMucHJvcHMub3ZlcnJpZGVzPy5keW5hbWljRnVuY3Rpb25VcmxPcmlnaW5XaXRoT0FDUHJvcHMsXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBsb2FkQmFsYW5jZXIgPSB0aGlzLnByb3BzLmxvYWRCYWxhbmNlcjtcbiAgICAgIGlmICghbG9hZEJhbGFuY2VyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1pc3NpbmcgTmV4dGpzRGlzdHJpYnV0aW9uUHJvcHMubG9hZEJhbGFuY2VyXCIpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIFZwY09yaWdpbi53aXRoQXBwbGljYXRpb25Mb2FkQmFsYW5jZXIobG9hZEJhbGFuY2VyLCB7XG4gICAgICAgIHByb3RvY29sUG9saWN5OiB0aGlzLnByb3BzLmNlcnRpZmljYXRlXG4gICAgICAgICAgPyBPcmlnaW5Qcm90b2NvbFBvbGljeS5IVFRQU19PTkxZXG4gICAgICAgICAgOiBPcmlnaW5Qcm90b2NvbFBvbGljeS5IVFRQX09OTFksXG4gICAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5keW5hbWljVnBjT3JpZ2luV2l0aEVuZHBvaW50UHJvcHMsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cbiAgLyoqXG4gICAqIEEgZGVkaWNhdGVkIGltYWdlIG9wdGltaXphdGlvbiBMYW1iZGEgaXMgb25seSB3aXJlZCB1cCB3aGVuXG4gICAqIHtAbGluayBOZXh0anNEaXN0cmlidXRpb25Qcm9wcy5pbWFnZUZ1bmN0aW9uVXJsfSBpcyBzdXBwbGllZCwgd2hpY2ggdG9kYXlcbiAgICogb25seSBgTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TYCBkb2VzLiBPdGhlcndpc2UgYF9uZXh0L2ltYWdlKmAga2VlcHNcbiAgICogZ29pbmcgdG8gdGhlIGR5bmFtaWMgb3JpZ2luLCB3aGVyZSB0aGUgTmV4dC5qcyBzZXJ2ZXIgb3B0aW1pemVzIGltYWdlc1xuICAgKiBpdHNlbGYuXG4gICAqXG4gICAqIFRoZSBgX25leHQvaW1hZ2UqYCBiZWhhdmlvciBpcyBrZXB0IGVpdGhlciB3YXk6IGl0cyBjYWNoZSBwb2xpY3lcbiAgICogKGBxdWVyeVN0cmluZ0JlaGF2aW9yOiBhbGwoKWAsIGBhY2NlcHRgIGluIHRoZSBjYWNoZSBrZXkpIGlzIHRoZSByaWdodCBvbmVcbiAgICogZm9yIGltYWdlIHJlcXVlc3RzIHJlZ2FyZGxlc3Mgb2Ygd2hpY2ggb3JpZ2luIGFuc3dlcnMgdGhlbS5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlSW1hZ2VPcmlnaW4oKTogSU9yaWdpbiB7XG4gICAgaWYgKCF0aGlzLmlzRnVuY3Rpb25Db21wdXRlIHx8ICF0aGlzLnByb3BzLmltYWdlRnVuY3Rpb25VcmwpIHtcbiAgICAgIHJldHVybiB0aGlzLmR5bmFtaWNPcmlnaW47XG4gICAgfVxuICAgIHJldHVybiBGdW5jdGlvblVybE9yaWdpbi53aXRoT3JpZ2luQWNjZXNzQ29udHJvbChcbiAgICAgIHRoaXMucHJvcHMuaW1hZ2VGdW5jdGlvblVybCxcbiAgICAgIHtcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmR5bmFtaWNGdW5jdGlvblVybE9yaWdpbldpdGhPQUNQcm9wcyxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmltYWdlRnVuY3Rpb25VcmxPcmlnaW5XaXRoT0FDUHJvcHMsXG4gICAgICB9LFxuICAgICk7XG4gIH1cbiAgLyoqXG4gICAqIExhbWJkYSBGdW5jdGlvbiBVUkxzIFwiZXhwZWN0IHRoZSBgSG9zdGAgaGVhZGVyIHRvIGNvbnRhaW4gdGhlIG9yaWdpbiBkb21haW5cbiAgICogbmFtZSwgbm90IHRoZSBkb21haW4gbmFtZSBvZiB0aGUgQ2xvdWRGcm9udCBkaXN0cmlidXRpb24uXCJcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvdXNpbmctbWFuYWdlZC1vcmlnaW4tcmVxdWVzdC1wb2xpY2llcy5odG1sI21hbmFnZWQtb3JpZ2luLXJlcXVlc3QtcG9saWN5LWFsbC12aWV3ZXItZXhjZXB0LWhvc3QtaGVhZGVyXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUR5bmFtaWNPcmlnaW5SZXF1ZXN0UG9saWN5KCk6IElPcmlnaW5SZXF1ZXN0UG9saWN5IHtcbiAgICByZXR1cm4gdGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZVxuICAgICAgPyBPcmlnaW5SZXF1ZXN0UG9saWN5LkFMTF9WSUVXRVJfRVhDRVBUX0hPU1RfSEVBREVSXG4gICAgICA6IE9yaWdpblJlcXVlc3RQb2xpY3kuQUxMX1ZJRVdFUjtcbiAgfVxuICAvKipcbiAgICogRW5zdXJlcyBOZXh0LmpzIGByZXF1ZXN0LnVybGAgd2lsbCBiZSBjb3JyZWN0IGRvbWFpbiBpbnN0ZWFkIG9mIFVSTCBvZlxuICAgKiBjb21wdXRlIChMYW1iZGEgb3IgRmFyZ2F0ZSlcbiAgICogQHNlZSBodHRwczovL29wZW4tbmV4dC5qcy5vcmcvYWR2YW5jZWQvd29ya2Fyb3VuZCN3b3JrYXJvdW5kLXNldC14LWZvcndhcmRlZC1ob3N0LWhlYWRlci1hd3Mtc3BlY2lmaWNcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlRHluYW1pY0Nsb3VkRnJvbnRGdW5jdGlvbkFzc29jaWF0aW9ucygpOiBGdW5jdGlvbkFzc29jaWF0aW9uW10ge1xuICAgIGNvbnN0IGFzc29jaWF0aW9uczogRnVuY3Rpb25Bc3NvY2lhdGlvbltdID0gW107XG4gICAgaWYgKHRoaXMuaXNGdW5jdGlvbkNvbXB1dGUpIHtcbiAgICAgIGNvbnN0IGNsb3VkRnJvbnRGbiA9IG5ldyBDbG91ZEZyb250RnVuY3Rpb24odGhpcywgXCJDbG91ZEZyb250Rm5cIiwge1xuICAgICAgICBjb2RlOiBGdW5jdGlvbkNvZGUuZnJvbUlubGluZShgXG4gICAgICAgICAgZnVuY3Rpb24gaGFuZGxlcihldmVudCkge1xuICAgICAgICAgICAgdmFyIHJlcXVlc3QgPSBldmVudC5yZXF1ZXN0O1xuICAgICAgICAgICAgcmVxdWVzdC5oZWFkZXJzW1wieC1mb3J3YXJkZWQtaG9zdFwiXSA9IHJlcXVlc3QuaGVhZGVycy5ob3N0O1xuICAgICAgICAgICAgcmV0dXJuIHJlcXVlc3Q7XG4gICAgICAgICAgfVxuICAgICAgICAgIGApLFxuICAgICAgfSk7XG4gICAgICBhc3NvY2lhdGlvbnMucHVzaCh7XG4gICAgICAgIGV2ZW50VHlwZTogRnVuY3Rpb25FdmVudFR5cGUuVklFV0VSX1JFUVVFU1QsXG4gICAgICAgIGZ1bmN0aW9uOiBjbG91ZEZyb250Rm4sXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIGFzc29jaWF0aW9ucztcbiAgfVxuICBwcml2YXRlIGNyZWF0ZVN0YXRpY0JlaGF2aW9yT3B0aW9ucygpOiBCZWhhdmlvck9wdGlvbnMge1xuICAgIGNvbnN0IHN0YXRpY0JlaGF2aW9yT3B0aW9ucyA9IHRoaXMucHJvcHMub3ZlcnJpZGVzPy5zdGF0aWNCZWhhdmlvck9wdGlvbnM7XG4gICAgY29uc3QgcmVzcG9uc2VIZWFkZXJzUG9saWN5ID1cbiAgICAgIHN0YXRpY0JlaGF2aW9yT3B0aW9ucz8ucmVzcG9uc2VIZWFkZXJzUG9saWN5ID8/XG4gICAgICBuZXcgUmVzcG9uc2VIZWFkZXJzUG9saWN5KHRoaXMsIFwiU3RhdGljUmVzcG9uc2VIZWFkZXJzUG9saWN5XCIsIHtcbiAgICAgICAgc2VjdXJpdHlIZWFkZXJzQmVoYXZpb3I6IHRoaXMuY29tbW9uU2VjdXJpdHlIZWFkZXJzQmVoYXZpb3IsXG4gICAgICAgIGNvbW1lbnQ6IHRoaXMuZ2V0Q29tbWVudChcbiAgICAgICAgICBcIk5leHRKUyBTdGF0aWMgUmVzcG9uc2UgSGVhZGVycyBQb2xpY3lcIixcbiAgICAgICAgICBTdGFjay5vZih0aGlzKS5zdGFja05hbWUsXG4gICAgICAgICksXG4gICAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5zdGF0aWNSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcyxcbiAgICAgIH0pO1xuICAgIHJldHVybiB7XG4gICAgICBhbGxvd2VkTWV0aG9kczogQWxsb3dlZE1ldGhvZHMuQUxMT1dfR0VUX0hFQURfT1BUSU9OUyxcbiAgICAgIGNhY2hlZE1ldGhvZHM6IENhY2hlZE1ldGhvZHMuQ0FDSEVfR0VUX0hFQURfT1BUSU9OUyxcbiAgICAgIGNhY2hlUG9saWN5OiBDYWNoZVBvbGljeS5DQUNISU5HX09QVElNSVpFRCxcbiAgICAgIG9yaWdpbjogdGhpcy5zdGF0aWNPcmlnaW4sXG4gICAgICByZXNwb25zZUhlYWRlcnNQb2xpY3ksXG4gICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICAuLi5zdGF0aWNCZWhhdmlvck9wdGlvbnMsXG4gICAgfTtcbiAgfVxuICBwcml2YXRlIGNyZWF0ZUR5bmFtaWNCZWhhdmlvck9wdGlvbnMoKTogQmVoYXZpb3JPcHRpb25zIHtcbiAgICBjb25zdCBkeW5hbWljQmVoYXZpb3JPcHRpb25zID0gdGhpcy5wcm9wcy5vdmVycmlkZXM/LmR5bmFtaWNCZWhhdmlvck9wdGlvbnM7XG4gICAgLy8gY3JlYXRlIGRlZmF1bHQgY2FjaGUgcG9saWN5IGlmIG5vdCBwcm92aWRlZFxuICAgIGNvbnN0IGNhY2hlUG9saWN5ID1cbiAgICAgIGR5bmFtaWNCZWhhdmlvck9wdGlvbnM/LmNhY2hlUG9saWN5ID8/XG4gICAgICBuZXcgQ2FjaGVQb2xpY3kodGhpcywgXCJEeW5hbWljQ2FjaGVQb2xpY3lcIiwge1xuICAgICAgICBxdWVyeVN0cmluZ0JlaGF2aW9yOiBDYWNoZVF1ZXJ5U3RyaW5nQmVoYXZpb3IuYWxsKCksXG4gICAgICAgIGhlYWRlckJlaGF2aW9yOiBDYWNoZUhlYWRlckJlaGF2aW9yLmFsbG93TGlzdChcbiAgICAgICAgICAvLyBOT1RFOiBDbG91ZEZyb250IEN1c3RvbSBDYWNoZSBQb2xpY2llcyBoYXZlIHNvZnQgbWF4IG9mIDEwIGhlYWRlcnNcbiAgICAgICAgICAvLyBjZGstbmV4dGpzIGluY2x1ZGVzIHRoZSBtb3N0IGVzc2VudGlhbCBoZWFkZXJzIGZvciBOZXh0LmpzIGZ1bmN0aW9uYWxpdHlcbiAgICAgICAgICAvLyBidXQgaXQncyByZWNvbW1lbmRlZCB0byByZXF1ZXN0IHF1b3RhIGluY3JlYXNlIHRvIGluY2x1ZGUgYWxsIGhlYWRlcnMgKGNvbW1lbnRlZCBvdXQgb25lcyBiZWxvdylcbiAgICAgICAgICAvLyBtb3JlIGhlcmU6IGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZEZyb250L2xhdGVzdC9EZXZlbG9wZXJHdWlkZS9jbG91ZGZyb250LWxpbWl0cy5odG1sI2xpbWl0cy1wb2xpY2llc1xuICAgICAgICAgIFwiYWNjZXB0XCIsIC8vIGNvbnRlbnQgbmVnb3RpYXRpb24gKEhUTUwgdnMgUlNDIHBheWxvYWQpXG4gICAgICAgICAgXCJyc2NcIiwgLy8gUmVhY3QgU2VydmVyIENvbXBvbmVudHMgcmVxdWVzdHNcbiAgICAgICAgICBcIm5leHQtdXJsXCIsIC8vIE5leHQuanMgcm91dGluZ1xuICAgICAgICAgIFwibmV4dC1yb3V0ZXItc3RhdGUtdHJlZVwiLCAvLyBBcHAgUm91dGVyIG5hdmlnYXRpb24gc3RhdGVcbiAgICAgICAgICBcIm5leHQtcm91dGVyLXByZWZldGNoXCIsIC8vIHByZWZldGNoIGJlaGF2aW9yXG4gICAgICAgICAgXCJuZXh0LXJvdXRlci1zZWdtZW50LXByZWZldGNoXCIsIC8vIHNlZ21lbnQtbGV2ZWwgcHJlZmV0Y2hpbmdcbiAgICAgICAgICBcIngtbWF0Y2hlZC1wYXRoXCIsIC8vIGR5bmFtaWMgcm91dGVzIGFuZCByZXdyaXRlc1xuICAgICAgICAgIFwieC1wcmVyZW5kZXItcmV2YWxpZGF0ZVwiLCAvLyBvbi1kZW1hbmQgSVNSIHJldmFsaWRhdGlvblxuICAgICAgICAgIFwieC1uZXh0LWNhY2hlLXRhZ3NcIiwgLy8gdGFnLWJhc2VkIGNhY2hlIHJldmFsaWRhdGlvblxuICAgICAgICAgIFwieC1wcmVyZW5kZXItYnlwYXNzXCIsIC8vIGRyYWZ0IG1vZGVcbiAgICAgICAgICAvLyBcIngtbmV4dGpzLXN0YWxlLXRpbWVcIiwgLy8gc3RhbGUtd2hpbGUtcmV2YWxpZGF0ZSBiZWhhdmlvclxuICAgICAgICAgIC8vIFwieC1uZXh0LWNhY2hlLXRhZy10b2tlblwiLCAvLyBhdXRoIHRva2VuIGZvciBjYWNoZSB0YWdzIChvbmx5IG5lZWRlZCB3aXRoIHJldmFsaWRhdGVUYWcgYXV0aClcbiAgICAgICAgICAvLyBcIngtbmV4dGpzLXBvc3Rwb25lZFwiLCAvLyBQYXJ0aWFsIFByZXJlbmRlcmluZyAoZXhwZXJpbWVudGFsIGZlYXR1cmUpXG4gICAgICAgICAgLy8gXCJ4LXByZXJlbmRlci1yZXZhbGlkYXRlLWlmLWdlbmVyYXRlZFwiLCAvLyBjb25kaXRpb25hbCByZXZhbGlkYXRpb24gKG5pY2hlIHVzZSBjYXNlKVxuICAgICAgICApLFxuICAgICAgICBjb29raWVCZWhhdmlvcjogQ2FjaGVDb29raWVCZWhhdmlvci5hbGwoKSxcbiAgICAgICAgZW5hYmxlQWNjZXB0RW5jb2RpbmdCcm90bGk6IHRydWUsXG4gICAgICAgIGVuYWJsZUFjY2VwdEVuY29kaW5nR3ppcDogdHJ1ZSxcbiAgICAgICAgY29tbWVudDogdGhpcy5nZXRDb21tZW50KFxuICAgICAgICAgIFwiTmV4dEpTIER5bmFtaWMgQ2FjaGUgUG9saWN5XCIsXG4gICAgICAgICAgU3RhY2sub2YodGhpcykuc3RhY2tOYW1lLFxuICAgICAgICApLFxuICAgICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8uZHluYW1pY0NhY2hlUG9saWN5UHJvcHMsXG4gICAgICB9KTtcbiAgICBjb25zdCByZXNwb25zZUhlYWRlcnNQb2xpY3kgPVxuICAgICAgZHluYW1pY0JlaGF2aW9yT3B0aW9ucz8ucmVzcG9uc2VIZWFkZXJzUG9saWN5ID8/XG4gICAgICBuZXcgUmVzcG9uc2VIZWFkZXJzUG9saWN5KHRoaXMsIFwiRHluYW1pY1Jlc3BvbnNlSGVhZGVyc1BvbGljeVwiLCB7XG4gICAgICAgIHNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yOiB0aGlzLmNvbW1vblNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yLFxuICAgICAgICBjb21tZW50OiB0aGlzLmdldENvbW1lbnQoXG4gICAgICAgICAgXCJOZXh0SlMgRHluYW1pYyBSZXNwb25zZSBIZWFkZXJzIFBvbGljeVwiLFxuICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgICAgKSxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmR5bmFtaWNSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcyxcbiAgICAgIH0pO1xuICAgIHJldHVybiB7XG4gICAgICBhbGxvd2VkTWV0aG9kczogQWxsb3dlZE1ldGhvZHMuQUxMT1dfQUxMLFxuICAgICAgY2FjaGVQb2xpY3ksXG4gICAgICBmdW5jdGlvbkFzc29jaWF0aW9uczogdGhpcy5keW5hbWljQ2xvdWRGcm9udEZ1bmN0aW9uQXNzb2NpYXRpb25zLFxuICAgICAgb3JpZ2luOiB0aGlzLmR5bmFtaWNPcmlnaW4sXG4gICAgICBvcmlnaW5SZXF1ZXN0UG9saWN5OiB0aGlzLmR5bmFtaWNPcmlnaW5SZXNwb25zZVBvbGljeSxcbiAgICAgIHJlc3BvbnNlSGVhZGVyc1BvbGljeSxcbiAgICAgIHZpZXdlclByb3RvY29sUG9saWN5OiBWaWV3ZXJQcm90b2NvbFBvbGljeS5SRURJUkVDVF9UT19IVFRQUyxcbiAgICAgIC4uLmR5bmFtaWNCZWhhdmlvck9wdGlvbnMsXG4gICAgfTtcbiAgfVxuICBwcml2YXRlIGNyZWF0ZUltYWdlQmVoYXZpb3JPcHRpb25zKCk6IEJlaGF2aW9yT3B0aW9ucyB7XG4gICAgY29uc3QgaW1hZ2VCZWhhdmlvck9wdGlvbnMgPSB0aGlzLnByb3BzLm92ZXJyaWRlcz8uaW1hZ2VCZWhhdmlvck9wdGlvbnM7XG4gICAgLy8gYWRkIGRlZmF1bHQgY2FjaGUgcG9saWN5IGlmIG5vdCBwcm92aWRlZFxuICAgIGNvbnN0IGNhY2hlUG9saWN5ID1cbiAgICAgIGltYWdlQmVoYXZpb3JPcHRpb25zPy5jYWNoZVBvbGljeSA/P1xuICAgICAgbmV3IENhY2hlUG9saWN5KHRoaXMsIFwiSW1hZ2VDYWNoZVBvbGljeVwiLCB7XG4gICAgICAgIC8vIFNFQ1VSSVRZIE5PVEU6IGJ5IGRlZmF1bHQgd2UgZG9uJ3QgaW5jbHVkZSBjb29raWVzIGluIGNhY2hlIGZvclxuICAgICAgICAvLyBpbWFnZXMgYi9jIGl0IHNpZ25pZmljYW50bHkgaW1wcm92ZXMgaW1hZ2UgcGVyZiBmb3IgbW9zdCBzaXRlcyBCVVRcbiAgICAgICAgLy8gaWYgeW91IGhhdmUgcHJpdmF0ZSBpbWFnZXMgbG9ja2VkIGJlaGluZCBhdXRoIGltcGxlbWVudGVkIHdpdGggY29va2llc1xuICAgICAgICAvLyB5b3UgbmVlZCB0byBvdmVycmlkZSB0aGlzLlxuICAgICAgICBxdWVyeVN0cmluZ0JlaGF2aW9yOiBDYWNoZVF1ZXJ5U3RyaW5nQmVoYXZpb3IuYWxsKCksXG4gICAgICAgIGhlYWRlckJlaGF2aW9yOiBDYWNoZUhlYWRlckJlaGF2aW9yLmFsbG93TGlzdChcImFjY2VwdFwiKSxcbiAgICAgICAgY29va2llQmVoYXZpb3I6IENhY2hlQ29va2llQmVoYXZpb3Iubm9uZSgpLFxuICAgICAgICBlbmFibGVBY2NlcHRFbmNvZGluZ0Jyb3RsaTogdHJ1ZSxcbiAgICAgICAgZW5hYmxlQWNjZXB0RW5jb2RpbmdHemlwOiB0cnVlLFxuICAgICAgICBjb21tZW50OiB0aGlzLmdldENvbW1lbnQoXG4gICAgICAgICAgXCJOZXh0SlMgSW1hZ2UgQ2FjaGUgUG9saWN5XCIsXG4gICAgICAgICAgU3RhY2sub2YodGhpcykuc3RhY2tOYW1lLFxuICAgICAgICApLFxuICAgICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8uaW1hZ2VDYWNoZVBvbGljeVByb3BzLFxuICAgICAgfSk7XG4gICAgLy8gYWRkIGRlZmF1bHQgcmVzcG9uc2UgaGVhZGVycyBwb2xpY3kgaWYgbm90IHByb3ZpZGVkXG4gICAgY29uc3QgcmVzcG9uc2VIZWFkZXJzUG9saWN5ID1cbiAgICAgIGltYWdlQmVoYXZpb3JPcHRpb25zPy5yZXNwb25zZUhlYWRlcnNQb2xpY3kgPz9cbiAgICAgIG5ldyBSZXNwb25zZUhlYWRlcnNQb2xpY3kodGhpcywgXCJJbWFnZVJlc3BvbnNlSGVhZGVyc1BvbGljeVwiLCB7XG4gICAgICAgIHNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yOiB0aGlzLmNvbW1vblNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yLFxuICAgICAgICBjb21tZW50OiB0aGlzLmdldENvbW1lbnQoXG4gICAgICAgICAgXCJOZXh0SlMgSW1hZ2UgUmVzcG9uc2UgSGVhZGVycyBQb2xpY3lcIixcbiAgICAgICAgICBTdGFjay5vZih0aGlzKS5zdGFja05hbWUsXG4gICAgICAgICksXG4gICAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5pbWFnZVJlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzLFxuICAgICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFsbG93ZWRNZXRob2RzOiBBbGxvd2VkTWV0aG9kcy5BTExPV19HRVRfSEVBRF9PUFRJT05TLFxuICAgICAgY2FjaGVkTWV0aG9kczogQ2FjaGVkTWV0aG9kcy5DQUNIRV9HRVRfSEVBRF9PUFRJT05TLFxuICAgICAgZnVuY3Rpb25Bc3NvY2lhdGlvbnM6IHRoaXMuZHluYW1pY0Nsb3VkRnJvbnRGdW5jdGlvbkFzc29jaWF0aW9ucyxcbiAgICAgIG9yaWdpbjogdGhpcy5pbWFnZU9yaWdpbixcbiAgICAgIG9yaWdpblJlcXVlc3RQb2xpY3k6IHRoaXMuZHluYW1pY09yaWdpblJlc3BvbnNlUG9saWN5LFxuICAgICAgY2FjaGVQb2xpY3ksXG4gICAgICByZXNwb25zZUhlYWRlcnNQb2xpY3ksXG4gICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICAuLi5pbWFnZUJlaGF2aW9yT3B0aW9ucyxcbiAgICB9O1xuICB9XG4gIC8qKlxuICAgKiBDcmVhdGVzIG9yIHVzZXMgdXNlciBzcGVjaWZpZWQgQ2xvdWRGcm9udCBEaXN0cmlidXRpb25cbiAgICovXG4gIHByaXZhdGUgZ2V0RGlzdHJpYnV0aW9uKCk6IERpc3RyaWJ1dGlvbiB7XG4gICAgbGV0IGRpc3RyaWJ1dGlvbjogRGlzdHJpYnV0aW9uO1xuICAgIGlmICh0aGlzLnByb3BzLmRpc3RyaWJ1dGlvbikge1xuICAgICAgZGlzdHJpYnV0aW9uID0gdGhpcy5wcm9wcy5kaXN0cmlidXRpb247XG4gICAgfSBlbHNlIHtcbiAgICAgIGRpc3RyaWJ1dGlvbiA9IG5ldyBEaXN0cmlidXRpb24odGhpcywgXCJEaXN0cmlidXRpb25cIiwge1xuICAgICAgICBtaW5pbXVtUHJvdG9jb2xWZXJzaW9uOiBTZWN1cml0eVBvbGljeVByb3RvY29sLlRMU19WMV8yXzIwMjEsXG4gICAgICAgIGRlZmF1bHRCZWhhdmlvcjogdGhpcy5keW5hbWljQmVoYXZpb3JPcHRpb25zLFxuICAgICAgICAvLyBiZXN0IHRvIHVzZSBIVFRQIDIgYW5kIDMgZm9yIGNvbXBhdGFiaWxpdHkgKEhUVFAgMikgYW5kIHBlcmZvcm1hbmNlIChIVFRQMylcbiAgICAgICAgLy8gQ2xvdWRGcm9udCB3aWxsIGNob29zZSBiZXN0IG9wdGlvbiBmb3IgY2xpZW50XG4gICAgICAgIGh0dHBWZXJzaW9uOiBIdHRwVmVyc2lvbi5IVFRQMl9BTkRfMyxcbiAgICAgICAgY29tbWVudDogdGhpcy5nZXRDb21tZW50KFxuICAgICAgICAgIFwiTmV4dEpTIERpc3RyaWJ1dGlvblwiLFxuICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgICAgKSxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmRpc3RyaWJ1dGlvblByb3BzLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBkaXN0cmlidXRpb247XG4gIH1cbiAgcHJpdmF0ZSBhZGREeW5hbWljQmVoYXZpb3JzKCkge1xuICAgIC8vIEltYWdlIEJlaGF2aW9yXG4gICAgdGhpcy5kaXN0cmlidXRpb24uYWRkQmVoYXZpb3IoXG4gICAgICB0aGlzLmdldFBhdGhQYXR0ZXJuKFwiX25leHQvaW1hZ2UqXCIpLFxuICAgICAgdGhpcy5pbWFnZUJlaGF2aW9yT3B0aW9ucy5vcmlnaW4sXG4gICAgICB0aGlzLmltYWdlQmVoYXZpb3JPcHRpb25zLFxuICAgICk7XG4gICAgLy8gUm9vdCBQYXRoIEJlaGF2aW9yc1xuICAgIGlmICh0aGlzLmJhc2VQYXRoKSB7XG4gICAgICAvLyBiZWNhdXNlIHdlIGFscmVhZHkgaGF2ZSBhIGJhc2VQYXRoIHdlIGRvbid0IHVzZSAvIGluc3RlYWQgd2UgdXNlIC9iYXNlLXBhdGhcbiAgICAgIHRoaXMuZGlzdHJpYnV0aW9uLmFkZEJlaGF2aW9yKFxuICAgICAgICBgLyR7dGhpcy5iYXNlUGF0aH1gLFxuICAgICAgICB0aGlzLmR5bmFtaWNCZWhhdmlvck9wdGlvbnMub3JpZ2luLFxuICAgICAgICB0aGlzLmR5bmFtaWNCZWhhdmlvck9wdGlvbnMsXG4gICAgICApO1xuICAgICAgLy8gd2hlbiBiYXNlUGF0aCBpcyBzZXQsIHdlIGVtdWxhdGUgdGhlIFwiZGVmYXVsdCBiZWhhdmlvclwiICgqKSBmb3IgdGhlIHNpdGUgYXMgYC9iYXNlLXBhdGgvKmBcbiAgICAgIHRoaXMuZGlzdHJpYnV0aW9uLmFkZEJlaGF2aW9yKFxuICAgICAgICB0aGlzLmdldFBhdGhQYXR0ZXJuKFwiKlwiKSxcbiAgICAgICAgdGhpcy5keW5hbWljQmVoYXZpb3JPcHRpb25zLm9yaWdpbixcbiAgICAgICAgdGhpcy5keW5hbWljQmVoYXZpb3JPcHRpb25zLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gaWYgbm8gYmFzZSBwYXRoLCB0aGVuIGRlZmF1bHQgYmVoYXZpb3Igd2lsbCBoYW5kbGUgYWxsIG90aGVyIHBhdGhzXG4gICAgfVxuICB9XG4gIHByaXZhdGUgYWRkU3RhdGljQmVoYXZpb3JzKCkge1xuICAgIHRoaXMuZGlzdHJpYnV0aW9uLmFkZEJlaGF2aW9yKFxuICAgICAgdGhpcy5nZXRQYXRoUGF0dGVybihcIl9uZXh0L3N0YXRpYypcIiksXG4gICAgICB0aGlzLnN0YXRpY09yaWdpbixcbiAgICAgIHRoaXMuc3RhdGljQmVoYXZpb3JPcHRpb25zLFxuICAgICk7XG4gICAgLy8gMjIgPSAyNSAobWF4KSAtIDEgKF9uZXh0L2ltYWdlKSAtIDEgKF9uZXh0L3N0YXRpYykgLSAxICgqKVxuICAgIGlmICh0aGlzLnByb3BzLnB1YmxpY0RpckVudHJpZXMubGVuZ3RoID49IDIyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBUb28gbWFueSBwdWJsaWMvIGZpbGVzIGluIE5leHQuanMgYnVpbGQuIENsb3VkRnJvbnQgbGltaXRzIERpc3RyaWJ1dGlvbnMgdG8gMjUgQ2FjaGUgQmVoYXZpb3JzLiBTZWUgZG9jdW1lbnRlZCBsaW1pdCBoZXJlOiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvY2xvdWRmcm9udC1saW1pdHMuaHRtbCNsaW1pdHMtd2ViLWRpc3RyaWJ1dGlvbnMuIFRyeSBpbmNsdWRpbmcgYWxsIHB1YmxpYyBmaWxlcyBpbnRvIDEgdG9wIGxldmVsIGRpcmVjdG9yeSAoaS5lLiBzdGF0aWMvKikuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgcHVibGljRmlsZSBvZiB0aGlzLnByb3BzLnB1YmxpY0RpckVudHJpZXMpIHtcbiAgICAgIGNvbnN0IHBhdGhQYXR0ZXJuID0gcHVibGljRmlsZS5pc0RpcmVjdG9yeVxuICAgICAgICA/IGAke3B1YmxpY0ZpbGUubmFtZX0vKmBcbiAgICAgICAgOiBwdWJsaWNGaWxlLm5hbWU7XG4gICAgICBpZiAoIS9eW2EtekEtWjAtOV9cXC0uKiQvflwiJ0A6Kz8mXSskLy50ZXN0KHBhdGhQYXR0ZXJuKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYEludmFsaWQgQ2xvdWRGcm9udCBEaXN0cmlidXRpb24gQ2FjaGUgQmVoYXZpb3IgUGF0aCBQYXR0ZXJuOiAke3BhdGhQYXR0ZXJufS4gUGxlYXNlIHNlZSBkb2N1bWVudGF0aW9uIGhlcmU6IGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZEZyb250L2xhdGVzdC9EZXZlbG9wZXJHdWlkZS9kaXN0cmlidXRpb24td2ViLXZhbHVlcy1zcGVjaWZ5Lmh0bWwjRG93bmxvYWREaXN0VmFsdWVzUGF0aFBhdHRlcm5gLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3QgZmluYWxQYXRoUGF0dGVybiA9IHRoaXMuZ2V0UGF0aFBhdHRlcm4ocGF0aFBhdHRlcm4pO1xuICAgICAgdGhpcy5kaXN0cmlidXRpb24uYWRkQmVoYXZpb3IoXG4gICAgICAgIGZpbmFsUGF0aFBhdHRlcm4sXG4gICAgICAgIHRoaXMuc3RhdGljT3JpZ2luLFxuICAgICAgICB0aGlzLnN0YXRpY0JlaGF2aW9yT3B0aW9ucyxcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBPcHRpb25hbGx5IHByZXBlbmRzIGJhc2UgcGF0aCB0byBnaXZlbiBwYXRoIHBhdHRlcm4uXG4gICAqL1xuICBwcml2YXRlIGdldFBhdGhQYXR0ZXJuKHBhdGhQYXR0ZXJuOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gdGhpcy5iYXNlUGF0aFxuICAgICAgPyBgLyR7am9pblBhdGgodGhpcy5iYXNlUGF0aCwgcGF0aFBhdHRlcm4pfWBcbiAgICAgIDogcGF0aFBhdHRlcm47XG4gIH1cbn1cbiJdfQ==
|
|
692
|
+
/**
|
|
693
|
+
* Whether `dynamicCachePolicyProps` turns the dynamic cache off, by capping every
|
|
694
|
+
* TTL at 0.
|
|
695
|
+
*
|
|
696
|
+
* CloudFront rejects a policy that caches nothing but still has a cache key
|
|
697
|
+
* ("HeaderBehavior is invalid for policy with caching disabled"), so such a
|
|
698
|
+
* policy has to drop the key. Until the default TTL became 0 this could not
|
|
699
|
+
* come up: CDK raises `maxTtl` to `defaultTtl` when it is lower, so an override
|
|
700
|
+
* of `maxTtl: 0` synthesized as a day and deployed. Now it is honored, and
|
|
701
|
+
* without this the upgrade deploy would fail.
|
|
702
|
+
*
|
|
703
|
+
* The TTLs are resolved the way CDK resolves them: `defaultTtl` raised to
|
|
704
|
+
* `minTtl`, then `maxTtl` raised to `defaultTtl`. Checking `maxTtl` alone called
|
|
705
|
+
* `{ maxTtl: 0, defaultTtl: 1h }` disabled, dropped the key, and CDK then
|
|
706
|
+
* synthesized a policy that caches for an hour keyed on nothing — one viewer's
|
|
707
|
+
* page served to every viewer.
|
|
708
|
+
*/
|
|
709
|
+
function isCachingDisabled(props) {
|
|
710
|
+
const ttls = [props?.maxTtl, props?.defaultTtl, props?.minTtl];
|
|
711
|
+
if (props?.maxTtl === undefined)
|
|
712
|
+
return false; // CDK's default is a year
|
|
713
|
+
return ttls.every((ttl) => ttl === undefined ||
|
|
714
|
+
(!aws_cdk_lib_1.Token.isUnresolved(ttl.toString()) && ttl.toSeconds() === 0));
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* What the dynamic cache policy keys on: every request input a Next.js response
|
|
718
|
+
* varies by.
|
|
719
|
+
*/
|
|
720
|
+
const DYNAMIC_CACHE_KEY = {
|
|
721
|
+
queryStringBehavior: aws_cloudfront_1.CacheQueryStringBehavior.all(),
|
|
722
|
+
headerBehavior: aws_cloudfront_1.CacheHeaderBehavior.allowList(
|
|
723
|
+
// NOTE: CloudFront Custom Cache Policies have soft max of 10 headers
|
|
724
|
+
// cdk-nextjs includes the most essential headers for Next.js functionality
|
|
725
|
+
// but it's recommended to request quota increase to include all headers (commented out ones below)
|
|
726
|
+
// more here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-policies
|
|
727
|
+
"accept", // content negotiation (HTML vs RSC payload)
|
|
728
|
+
"rsc", // React Server Components requests
|
|
729
|
+
"next-url", // Next.js routing
|
|
730
|
+
"next-router-state-tree", // App Router navigation state
|
|
731
|
+
"next-router-prefetch", // prefetch behavior
|
|
732
|
+
"next-router-segment-prefetch", // segment-level prefetching
|
|
733
|
+
"x-prerender-revalidate", // on-demand ISR revalidation
|
|
734
|
+
"x-prerender-bypass"),
|
|
735
|
+
cookieBehavior: aws_cloudfront_1.CacheCookieBehavior.all(),
|
|
736
|
+
enableAcceptEncodingBrotli: true,
|
|
737
|
+
enableAcceptEncodingGzip: true,
|
|
738
|
+
};
|
|
739
|
+
/**
|
|
740
|
+
* A cache key of nothing, for a policy that caches nothing. Forwarding is
|
|
741
|
+
* unaffected: the dynamic origin request policy sends every viewer header,
|
|
742
|
+
* cookie and query string regardless.
|
|
743
|
+
*/
|
|
744
|
+
const DISABLED_CACHE_KEY = {
|
|
745
|
+
queryStringBehavior: aws_cloudfront_1.CacheQueryStringBehavior.none(),
|
|
746
|
+
headerBehavior: aws_cloudfront_1.CacheHeaderBehavior.none(),
|
|
747
|
+
cookieBehavior: aws_cloudfront_1.CacheCookieBehavior.none(),
|
|
748
|
+
enableAcceptEncodingBrotli: false,
|
|
749
|
+
enableAcceptEncodingGzip: false,
|
|
750
|
+
};
|
|
751
|
+
/**
|
|
752
|
+
* CloudFront's default "Cache behaviors per distribution" quota, the default
|
|
753
|
+
* behavior included. Adjustable, hence `maxCacheBehaviors`.
|
|
754
|
+
*
|
|
755
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-web-distributions
|
|
756
|
+
*/
|
|
757
|
+
const DEFAULT_MAX_CACHE_BEHAVIORS = 75;
|
|
758
|
+
/**
|
|
759
|
+
* Whether `char` is in CloudFront's path pattern alphabet: the literals, plus the
|
|
760
|
+
* `*` and `?` wildcards. No space, no `%`, nothing non-ASCII.
|
|
761
|
+
*/
|
|
762
|
+
function isPathPatternChar(char) {
|
|
763
|
+
return char === "*" || char === "?" || function_groups_1.PATH_PATTERN_LITERAL.test(char);
|
|
764
|
+
}
|
|
765
|
+
/** CloudFront's path pattern length limit. */
|
|
766
|
+
const MAX_PATH_PATTERN_LENGTH = 255;
|
|
767
|
+
/**
|
|
768
|
+
* A `public/` entry's name as a CloudFront path pattern.
|
|
769
|
+
*
|
|
770
|
+
* `public/hello world.jpg` is a valid Next.js asset — `next start` serves it, and
|
|
771
|
+
* `next/image` points at it — but a space cannot appear in a path pattern, so
|
|
772
|
+
* cdk-nextjs used to throw at synth and the app could not be deployed at all
|
|
773
|
+
* (`next-image-legacy/unicode`, whose `public/` also holds `äöüščří.png`).
|
|
774
|
+
*
|
|
775
|
+
* CloudFront URL-decodes the request path before matching it, so the pattern is
|
|
776
|
+
* matched against `hello world.jpg`, not the `/hello%20world.jpg` on the wire.
|
|
777
|
+
* Each character outside the alphabet is replaced by one `?` per byte of its
|
|
778
|
+
* UTF-8 encoding, because that is what `?` matches: `hello?world.jpg` for the
|
|
779
|
+
* space, and two `?` for each character of `äöüščří.png`. Measured against a
|
|
780
|
+
* deployed distribution; a `?` per *percent-encoded* character (`hello???world`)
|
|
781
|
+
* synthesizes fine and never matches. A `*` would be shorter and much wider:
|
|
782
|
+
* `äöüščří.png` would become `*.png`, which would pull every `.png` request in
|
|
783
|
+
* the app onto the static origin.
|
|
784
|
+
*/
|
|
785
|
+
function toPathPattern(name) {
|
|
786
|
+
return [...name]
|
|
787
|
+
.map((char) => isPathPatternChar(char)
|
|
788
|
+
? char
|
|
789
|
+
: "?".repeat(Buffer.byteLength(char, "utf8")))
|
|
790
|
+
.join("");
|
|
791
|
+
}
|
|
792
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWRpc3RyaWJ1dGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9uZXh0anMtZGlzdHJpYnV0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSw2Q0FBa0U7QUFFbEUsK0RBNEJvQztBQUNwQywrRUFNNEM7QUFFNUMsdURBQXFFO0FBRXJFLDJDQUF1QztBQUN2QywrREFJbUM7QUFDbkMsMkNBQXFEO0FBT3JELGlEQUF1RTtBQXdHdkUsTUFBYSxrQkFBbUIsU0FBUSxzQkFBUzs7SUFDL0MsWUFBWSxDQUFlO0lBRW5CLEtBQUssQ0FBMEI7SUFDdkM7Ozs7O09BS0c7SUFDSyxRQUFRLENBQVM7SUFDekI7Ozs7O09BS0c7SUFDSyxXQUFXLENBQVM7SUFDNUI7OztPQUdHO0lBQ0ssNkJBQTZCLEdBQW9DO1FBQ3ZFLGtCQUFrQixFQUFFLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRTtRQUN2QyxZQUFZLEVBQUU7WUFDWixXQUFXLEVBQUUsbUNBQWtCLENBQUMsVUFBVTtZQUMxQyxRQUFRLEVBQUUsS0FBSztTQUNoQjtRQUNELGNBQWMsRUFBRTtZQUNkLFFBQVEsRUFBRSxLQUFLO1lBQ2YsY0FBYyxFQUFFLHNDQUFxQixDQUFDLCtCQUErQjtTQUN0RTtRQUVELHVCQUF1QixFQUFFO1lBQ3ZCLG1CQUFtQixFQUFFLHNCQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztZQUN2QyxpQkFBaUIsRUFBRSxJQUFJO1lBQ3ZCLFFBQVEsRUFBRSxLQUFLO1lBQ2YsT0FBTyxFQUFFLElBQUk7U0FDZDtRQUNELGFBQWEsRUFBRSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFO0tBQ3RFLENBQUM7SUFDTSxZQUFZLENBQVU7SUFDdEIsYUFBYSxDQUFVO0lBQ3ZCLDJCQUEyQixDQUF1QjtJQUNsRCxxQ0FBcUMsQ0FBd0I7SUFDN0QsaUJBQWlCLENBQVU7SUFD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b0NBQW1CLENBQUMsSUFBSSxFQUFFO0lBQzFDLGNBQWMsRUFBRSxvQ0FBbUIsQ0FBQyxJQUFJLEVBQUU7SUFDMUMsMEJBQTBCLEVBQUUsS0FBSztJQUNqQyx3QkFBd0IsRUFBRSxLQUFLO0NBQ2hDLENBQUM7QUFFRjs7Ozs7R0FLRztBQUNILE1BQU0sMkJBQTJCLEdBQUcsRUFBRSxDQUFDO0FBRXZDOzs7R0FHRztBQUNILFNBQVMsaUJBQWlCLENBQUMsSUFBWTtJQUNyQyxPQUFPLElBQUksS0FBSyxHQUFHLElBQUksSUFBSSxLQUFLLEdBQUcsSUFBSSxzQ0FBb0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDekUsQ0FBQztBQUNELDhDQUE4QztBQUM5QyxNQUFNLHVCQUF1QixHQUFHLEdBQUcsQ0FBQztBQUVwQzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxTQUFTLGFBQWEsQ0FBQyxJQUFZO0lBQ2pDLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQztTQUNiLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQ1osaUJBQWlCLENBQUMsSUFBSSxDQUFDO1FBQ3JCLENBQUMsQ0FBQyxJQUFJO1FBQ04sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FDaEQ7U0FDQSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQW5ub3RhdGlvbnMsIER1cmF0aW9uLCBTdGFjaywgVG9rZW4gfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IElDZXJ0aWZpY2F0ZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBBY2Nlc3NMZXZlbCxcbiAgQWRkQmVoYXZpb3JPcHRpb25zLFxuICBBbGxvd2VkTWV0aG9kcyxcbiAgQmVoYXZpb3JPcHRpb25zLFxuICBDYWNoZUNvb2tpZUJlaGF2aW9yLFxuICBDYWNoZUhlYWRlckJlaGF2aW9yLFxuICBDYWNoZVBvbGljeSxcbiAgQ2FjaGVQb2xpY3lQcm9wcyxcbiAgQ2FjaGVRdWVyeVN0cmluZ0JlaGF2aW9yLFxuICBDYWNoZWRNZXRob2RzLFxuICBGdW5jdGlvbiBhcyBDbG91ZEZyb250RnVuY3Rpb24sXG4gIERpc3RyaWJ1dGlvbixcbiAgRnVuY3Rpb25Bc3NvY2lhdGlvbixcbiAgRnVuY3Rpb25Db2RlLFxuICBGdW5jdGlvbkV2ZW50VHlwZSxcbiAgSGVhZGVyc0ZyYW1lT3B0aW9uLFxuICBIZWFkZXJzUmVmZXJyZXJQb2xpY3ksXG4gIEh0dHBWZXJzaW9uLFxuICBJT3JpZ2luLFxuICBJT3JpZ2luUmVxdWVzdFBvbGljeSxcbiAgT3JpZ2luUHJvdG9jb2xQb2xpY3ksXG4gIE9yaWdpblJlcXVlc3RQb2xpY3ksXG4gIFJlc3BvbnNlSGVhZGVyc1BvbGljeSxcbiAgUmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHMsXG4gIFJlc3BvbnNlU2VjdXJpdHlIZWFkZXJzQmVoYXZpb3IsXG4gIFNlY3VyaXR5UG9saWN5UHJvdG9jb2wsXG4gIFZpZXdlclByb3RvY29sUG9saWN5LFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnRcIjtcbmltcG9ydCB7XG4gIEZ1bmN0aW9uVXJsT3JpZ2luLFxuICBGdW5jdGlvblVybE9yaWdpbldpdGhPQUNQcm9wcyxcbiAgUzNCdWNrZXRPcmlnaW4sXG4gIFZwY09yaWdpbixcbiAgVnBjT3JpZ2luV2l0aEVuZHBvaW50UHJvcHMsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udC1vcmlnaW5zXCI7XG5pbXBvcnQgeyBJQXBwbGljYXRpb25Mb2FkQmFsYW5jZXIgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVsYXN0aWNsb2FkYmFsYW5jaW5ndjJcIjtcbmltcG9ydCB7IENmblBlcm1pc3Npb24sIElGdW5jdGlvblVybCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCI7XG5pbXBvcnQgeyBJQnVja2V0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zM1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7XG4gIGNsb3VkRnJvbnRQYXR0ZXJuUmVnZXgsXG4gIERFRkFVTFRfRlVOQ1RJT05fR1JPVVAsXG4gIFBBVEhfUEFUVEVSTl9MSVRFUkFMLFxufSBmcm9tIFwiLi9hZGFwdGVyL2Z1bmN0aW9uLWdyb3Vwc1wiO1xuaW1wb3J0IHsgTE9HX1BSRUZJWCwgTmV4dGpzVHlwZSB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgT3B0aW9uYWxEaXN0cmlidXRpb25Qcm9wcyB9IGZyb20gXCIuL2dlbmVyYXRlZC1zdHJ1Y3RzL09wdGlvbmFsRGlzdHJpYnV0aW9uUHJvcHNcIjtcbmltcG9ydCB7IE9wdGlvbmFsUzNPcmlnaW5CdWNrZXRXaXRoT0FDUHJvcHMgfSBmcm9tIFwiLi9nZW5lcmF0ZWQtc3RydWN0cy9PcHRpb25hbFMzT3JpZ2luQnVja2V0V2l0aE9BQ1Byb3BzXCI7XG5pbXBvcnQge1xuICBOZXh0anNGdW5jdGlvbkdyb3VwQmVoYXZpb3IsXG4gIFB1YmxpY0RpckVudHJ5LFxufSBmcm9tIFwiLi9uZXh0anMtYnVpbGQvbmV4dGpzLWJ1aWxkXCI7XG5pbXBvcnQgeyBhc3NldFByZWZpeFBhdGgsIG5vcm1hbGl6ZUJhc2VQYXRoIH0gZnJvbSBcIi4vdXRpbHMvYmFzZS1wYXRoXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzRGlzdHJpYnV0aW9uT3ZlcnJpZGVzIHtcbiAgcmVhZG9ubHkgZGlzdHJpYnV0aW9uUHJvcHM/OiBPcHRpb25hbERpc3RyaWJ1dGlvblByb3BzO1xuICByZWFkb25seSBpbWFnZUJlaGF2aW9yT3B0aW9ucz86IEFkZEJlaGF2aW9yT3B0aW9ucztcbiAgcmVhZG9ubHkgaW1hZ2VDYWNoZVBvbGljeVByb3BzPzogQ2FjaGVQb2xpY3lQcm9wcztcbiAgcmVhZG9ubHkgaW1hZ2VSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcz86IFJlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzO1xuICByZWFkb25seSBkeW5hbWljQmVoYXZpb3JPcHRpb25zPzogQWRkQmVoYXZpb3JPcHRpb25zO1xuICByZWFkb25seSBkeW5hbWljQ2FjaGVQb2xpY3lQcm9wcz86IENhY2hlUG9saWN5UHJvcHM7XG4gIHJlYWRvbmx5IGR5bmFtaWNSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcz86IFJlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzO1xuICByZWFkb25seSBkeW5hbWljRnVuY3Rpb25VcmxPcmlnaW5XaXRoT0FDUHJvcHM/OiBGdW5jdGlvblVybE9yaWdpbldpdGhPQUNQcm9wcztcbiAgcmVhZG9ubHkgZHluYW1pY1ZwY09yaWdpbldpdGhFbmRwb2ludFByb3BzPzogVnBjT3JpZ2luV2l0aEVuZHBvaW50UHJvcHM7XG4gIHJlYWRvbmx5IHN0YXRpY0JlaGF2aW9yT3B0aW9ucz86IEFkZEJlaGF2aW9yT3B0aW9ucztcbiAgcmVhZG9ubHkgc3RhdGljUmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM/OiBSZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wcztcbiAgcmVhZG9ubHkgczNCdWNrZXRPcmlnaW5Qcm9wcz86IE9wdGlvbmFsUzNPcmlnaW5CdWNrZXRXaXRoT0FDUHJvcHM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzRGlzdHJpYnV0aW9uUHJvcHMge1xuICAvKipcbiAgICogQnVja2V0IGNvbnRhaW5pbmcgc3RhdGljIGFzc2V0cy5cbiAgICogTXVzdCBiZSBwcm92aWRlZCBpZiB5b3Ugd2FudCB0byBzZXJ2ZSBzdGF0aWMgZmlsZXMuXG4gICAqL1xuICByZWFkb25seSBhc3NldHNCdWNrZXQ6IElCdWNrZXQ7XG4gIC8qKlxuICAgKiBUaGUgYXBwJ3Mgb3duIGBhc3NldFByZWZpeGAuIE5leHQuanMgZW1pdHMgYDxhc3NldFByZWZpeD4vX25leHQvc3RhdGljLy4uLmBcbiAgICogZm9yIGV2ZXJ5IGJ1bmRsZSB3aGlsZSB0aGUgb2JqZWN0cyBzdGF5IGF0IGA8YmFzZVBhdGg+L19uZXh0L3N0YXRpYy8uLi5gIGluXG4gICAqIFMzLCBzbyB0aGUgcHJlZml4J3MgcGF0aCBnZXRzIGEgY2FjaGUgYmVoYXZpb3Igb2YgaXRzIG93biB0aGF0IHJld3JpdGVzIGl0XG4gICAqIGF3YXkuXG4gICAqXG4gICAqIEVpdGhlciBmb3JtIGlzIGFjY2VwdGVkOiBhIHBhdGggKFwiL2NkblwiKSwgb3IgYW4gYWJzb2x1dGUgVVJMLCBpbiB3aGljaCBjYXNlXG4gICAqIG9ubHkgaXRzIHBhdGggY291bnRzIChcImh0dHBzOi8vY2RuLmV4YW1wbGUuY29tL2NkblwiIGJlaGF2ZXMgYXMgXCIvY2RuXCIsIGFuZFxuICAgKiBcImh0dHBzOi8vY2RuLmV4YW1wbGUuY29tXCIgbmVlZHMgbm8gYmVoYXZpb3IgYXQgYWxsKS4gQW4gYWJzb2x1dGUgcHJlZml4J3MgcGF0aFxuICAgKiBtYXR0ZXJzIGJlY2F1c2UgYG5leHQgYnVpbGRgIGNvbXBpbGVzIGEgYC9jZG4vX25leHQvOnBhdGgrYCByZXdyaXRlIG9mIGl0c1xuICAgKiBvd24sIHNvIGBuZXh0IHN0YXJ0YCBzZXJ2ZXMgZXZlcnkgYnVuZGxlIHVuZGVyIGl0IOKAlCBhIENETiBmcm9udGluZyB0aGlzXG4gICAqIGRpc3RyaWJ1dGlvbiB0aGVyZSBoYXMgdG8gYmUgYW5zd2VyZWQgdG9vLlxuICAgKlxuICAgKiBBcHBsaWVkIG9uIHRvcCBvZiBgYmFzZVBhdGhgLCBub3QgdW5kZXIgaXQsIGJlY2F1c2UgdGhhdCBpcyBob3cgTmV4dC5qc1xuICAgKiBidWlsZHMgdGhlIFVSTC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBub25lOyBwYXNzIGBOZXh0anNCdWlsZC5uZXh0Q29uZmlnQXNzZXRQcmVmaXhQYXRoYFxuICAgKi9cbiAgcmVhZG9ubHkgYXNzZXRQcmVmaXg/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBVUkkgcGF0aCBwcmVmaXggdGhlIGFwcCBpcyBzZXJ2ZWQgYXQuIFN1cnJvdW5kaW5nIHNsYXNoZXMgYXJlIG5vcm1hbGl6ZWRcbiAgICogYXdheSwgc28gXCIvYmFzZVwiLCBcImJhc2VcIiBhbmQgXCIvYmFzZS9cIiBhbGwgcHJvZHVjZSB0aGUgc2FtZSBjYWNoZSBiZWhhdmlvcnMuXG4gICAqL1xuICByZWFkb25seSBiYXNlUGF0aD86IHN0cmluZztcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGJ1dCBvbmx5IGFwcGxpY2FibGUgZm9yIGBOZXh0anNUeXBlLkdMT0JBTF9DT05UQUlORVJTYFxuICAgKi9cbiAgcmVhZG9ubHkgY2VydGlmaWNhdGU/OiBJQ2VydGlmaWNhdGU7XG4gIHJlYWRvbmx5IGRpc3RyaWJ1dGlvbj86IERpc3RyaWJ1dGlvbjtcbiAgLyoqXG4gICAqIFJlcXVpcmVkIGlmIGBOZXh0anNUeXBlLkdMT0JBTF9GVU5DVElPTlNgXG4gICAqL1xuICByZWFkb25seSBmdW5jdGlvblVybD86IElGdW5jdGlvblVybDtcbiAgLyoqXG4gICAqIFJlcXVpcmVkIGlmIGBOZXh0anNUeXBlLkdMT0JBTF9DT05UQUlORVJTYCBvciBgTmV4dGpzVHlwZS5SRUdJT05BTF9DT05UQUlORVJTYFxuICAgKi9cbiAgcmVhZG9ubHkgbG9hZEJhbGFuY2VyPzogSUFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyO1xuICByZWFkb25seSBuZXh0anNUeXBlOiBOZXh0anNUeXBlO1xuICAvKipcbiAgICogT3ZlcnJpZGUgcHJvcHMgZm9yIGV2ZXJ5IGNvbnN0cnVjdC5cbiAgICovXG4gIHJlYWRvbmx5IG92ZXJyaWRlcz86IE5leHRqc0Rpc3RyaWJ1dGlvbk92ZXJyaWRlcztcbiAgLyoqXG4gICAqIEVudHJpZXMgKGZpbGVzL2RpcmVjdG9yaWVzKSB3aXRoaW4gTmV4dC5qcyBhcHAncyBwdWJsaWMgZGlyZWN0b3J5LiBVc2VkIHRvXG4gICAqIGFkZCBzdGF0aWMgYmVoYXZpb3JzIHRvIGRpc3RyaWJ1dGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IHB1YmxpY0RpckVudHJpZXM6IFB1YmxpY0RpckVudHJ5W107XG4gIC8qKlxuICAgKiBUaGUgbm9uLWBkZWZhdWx0YCBmdW5jdGlvbiBncm91cHMsIHRoZSBvcmlnaW5zXG4gICAqIHtAbGluayBmdW5jdGlvbkdyb3VwQmVoYXZpb3JzfSByb3V0ZSB0by5cbiAgICogQGRlZmF1bHQgLSBubyBzcGxpdHRpbmc7IHRoZSBkZWZhdWx0IGJlaGF2aW9yIHNlcnZlcyBldmVyeSBkeW5hbWljIHJvdXRlXG4gICAqL1xuICByZWFkb25seSBmdW5jdGlvbkdyb3Vwcz86IE5leHRqc0Rpc3RyaWJ1dGlvbkZ1bmN0aW9uR3JvdXBbXTtcbiAgLyoqXG4gICAqIGBOZXh0anNCdWlsZC5mdW5jdGlvbkdyb3VwQmVoYXZpb3JzYDogb25lIGNhY2hlIGJlaGF2aW9yIGVhY2gsIGFkZGVkIGluXG4gICAqIG9yZGVyLCBzbyB0aGUgcm91dGVzIGVhY2ggZ3JvdXAgd2FzIHBhY2thZ2VkIHdpdGggcmVhY2ggaXQgcmF0aGVyIHRoYW4gdGhlXG4gICAqIGRlZmF1bHQgZnVuY3Rpb24uXG4gICAqIEBkZWZhdWx0IC0gbm9uZVxuICAgKi9cbiAgcmVhZG9ubHkgZnVuY3Rpb25Hcm91cEJlaGF2aW9ycz86IE5leHRqc0Z1bmN0aW9uR3JvdXBCZWhhdmlvcltdO1xuICAvKipcbiAgICogVGhlIG1vc3QgY2FjaGUgYmVoYXZpb3JzIHRoZSBkaXN0cmlidXRpb24gbWF5IGhhdmUsIHRoZSBkZWZhdWx0IG9uZVxuICAgKiBpbmNsdWRlZC4gY2RrLW5leHRqcyBjb3VudHMgd2hhdCBpdCBhZGRzIGFnYWluc3QgdGhpcyBhdCBzeW50aCwgc28gcnVubmluZ1xuICAgKiBvdXQgaXMgYSBzeW50aCBlcnJvciBuYW1pbmcgd2hhdCB1c2VkIHRoZW0gcmF0aGVyIHRoYW4gYSBmYWlsZWQgZGVwbG95LlxuICAgKlxuICAgKiBSYWlzZSBpdCBhZnRlciByYWlzaW5nIHRoZSBcIkNhY2hlIGJlaGF2aW9ycyBwZXIgZGlzdHJpYnV0aW9uXCIgcXVvdGEgZm9yXG4gICAqIHlvdXIgYWNjb3VudC4gTG93ZXIgaXQgYnkgdGhlIGJlaGF2aW9ycyBhIHN1cHBsaWVkIHtAbGluayBkaXN0cmlidXRpb259XG4gICAqIChvciBgb3ZlcnJpZGVzLmRpc3RyaWJ1dGlvblByb3BzYCkgYWxyZWFkeSBoYXMsIHdoaWNoIGFyZSBub3QgY291bnRlZC5cbiAgICogQGRlZmF1bHQgNzUgLSBDbG91ZEZyb250J3MgZGVmYXVsdCBxdW90YVxuICAgKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZEZyb250L2xhdGVzdC9EZXZlbG9wZXJHdWlkZS9jbG91ZGZyb250LWxpbWl0cy5odG1sI2xpbWl0cy13ZWItZGlzdHJpYnV0aW9uc1xuICAgKi9cbiAgcmVhZG9ubHkgbWF4Q2FjaGVCZWhhdmlvcnM/OiBudW1iZXI7XG59XG5cbi8qKiBBIG5vbi1kZWZhdWx0IGZ1bmN0aW9uIGdyb3VwIGFuZCB0aGUgb3JpZ2luIGl0cyByb3V0ZXMgbXVzdCByZWFjaC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzRGlzdHJpYnV0aW9uRnVuY3Rpb25Hcm91cCB7XG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgLyoqIFRoZSBncm91cCdzIExhbWJkYSBGdW5jdGlvbiBVUkwuICovXG4gIHJlYWRvbmx5IGZ1bmN0aW9uVXJsOiBJRnVuY3Rpb25Vcmw7XG59XG5cbmV4cG9ydCBjbGFzcyBOZXh0anNEaXN0cmlidXRpb24gZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBkaXN0cmlidXRpb246IERpc3RyaWJ1dGlvbjtcblxuICBwcml2YXRlIHByb3BzOiBOZXh0anNEaXN0cmlidXRpb25Qcm9wcztcbiAgLyoqXG4gICAqIGBwcm9wcy5iYXNlUGF0aGAgbm9ybWFsaXplZCB0byBhIGJhcmUgcGF0aCBzZWdtZW50LiBUaGlzIGNvbnN0cnVjdCBpcyB0aGVcbiAgICogb25lIHBsYWNlIHRoYXQgbmVlZHMgaXQgd2l0aCBhIGxlYWRpbmcgc2xhc2gg4oCUIENsb3VkRnJvbnQgcGF0aCBwYXR0ZXJucyBhcmVcbiAgICogd3JpdHRlbiBhZ2FpbnN0IHRoZSByZXF1ZXN0IHBhdGgg4oCUIHNvIGl0IHByZXBlbmRzIGl0cyBvd24gcmF0aGVyIHRoYW5cbiAgICogcmVseWluZyBvbiB0aGUgY2FsbGVyIGhhdmluZyBwYXNzZWQgb25lLlxuICAgKi9cbiAgcHJpdmF0ZSBiYXNlUGF0aDogc3RyaW5nO1xuICAvKipcbiAgICogYHByb3BzLmFzc2V0UHJlZml4YCBub3JtYWxpemVkIHRvIGEgbGVhZGluZy1zbGFzaCBwYXRoLCBgXCJcImAgd2hlbiB0aGUgYXBwXG4gICAqIHNldHMgbm9uZSBvciBzZXRzIG9uZSB0aGF0IGFscmVhZHkgZXF1YWxzIHRoZSBgYmFzZVBhdGhgIHByZWZpeCDigJQgaW4gd2hpY2hcbiAgICogY2FzZSB0aGUgb3JkaW5hcnkgYF9uZXh0L3N0YXRpYypgIGJlaGF2aW9yIGFscmVhZHkgY292ZXJzIGl0IGFuZCBhIHNlY29uZCBvbmVcbiAgICogd291bGQgYmUgYSBkdXBsaWNhdGUgcGF0dGVybiBDbG91ZEZyb250IHJlamVjdHMuXG4gICAqL1xuICBwcml2YXRlIGFzc2V0UHJlZml4OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBDb21tb24gc2VjdXJpdHkgaGVhZGVycyBhcHBsaWVkIGJ5IGRlZmF1bHQgdG8gYWxsIG9yaWdpbnNcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvdXNpbmctbWFuYWdlZC1yZXNwb25zZS1oZWFkZXJzLXBvbGljaWVzLmh0bWwjbWFuYWdlZC1yZXNwb25zZS1oZWFkZXJzLXBvbGljaWVzLXNlY3VyaXR5XG4gICAqL1xuICBwcml2YXRlIGNvbW1vblNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yOiBSZXNwb25zZVNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yID0ge1xuICAgIGNvbnRlbnRUeXBlT3B0aW9uczogeyBvdmVycmlkZTogZmFsc2UgfSxcbiAgICBmcmFtZU9wdGlvbnM6IHtcbiAgICAgIGZyYW1lT3B0aW9uOiBIZWFkZXJzRnJhbWVPcHRpb24uU0FNRU9SSUdJTixcbiAgICAgIG92ZXJyaWRlOiBmYWxzZSxcbiAgICB9LFxuICAgIHJlZmVycmVyUG9saWN5OiB7XG4gICAgICBvdmVycmlkZTogZmFsc2UsXG4gICAgICByZWZlcnJlclBvbGljeTogSGVhZGVyc1JlZmVycmVyUG9saWN5LlNUUklDVF9PUklHSU5fV0hFTl9DUk9TU19PUklHSU4sXG4gICAgfSxcblxuICAgIHN0cmljdFRyYW5zcG9ydFNlY3VyaXR5OiB7XG4gICAgICBhY2Nlc3NDb250cm9sTWF4QWdlOiBEdXJhdGlvbi5kYXlzKDM2NSksXG4gICAgICBpbmNsdWRlU3ViZG9tYWluczogdHJ1ZSxcbiAgICAgIG92ZXJyaWRlOiBmYWxzZSxcbiAgICAgIHByZWxvYWQ6IHRydWUsXG4gICAgfSxcbiAgICB4c3NQcm90ZWN0aW9uOiB7IG92ZXJyaWRlOiBmYWxzZSwgcHJvdGVjdGlvbjogdHJ1ZSwgbW9kZUJsb2NrOiB0cnVlIH0sXG4gIH07XG4gIHByaXZhdGUgc3RhdGljT3JpZ2luOiBJT3JpZ2luO1xuICBwcml2YXRlIGR5bmFtaWNPcmlnaW46IElPcmlnaW47XG4gIHByaXZhdGUgZHluYW1pY09yaWdpblJlc3BvbnNlUG9saWN5OiBJT3JpZ2luUmVxdWVzdFBvbGljeTtcbiAgcHJpdmF0ZSBkeW5hbWljQ2xvdWRGcm9udEZ1bmN0aW9uQXNzb2NpYXRpb25zOiBGdW5jdGlvbkFzc29jaWF0aW9uW107XG4gIHByaXZhdGUgaXNGdW5jdGlvbkNvbXB1dGU6IGJvb2xlYW47XG4gIHByaXZhdGUgc3RhdGljQmVoYXZpb3JPcHRpb25zOiBCZWhhdmlvck9wdGlvbnM7XG4gIHByaXZhdGUgZHluYW1pY0JlaGF2aW9yT3B0aW9uczogQmVoYXZpb3JPcHRpb25zO1xuICBwcml2YXRlIGltYWdlQmVoYXZpb3JPcHRpb25zOiBCZWhhdmlvck9wdGlvbnM7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE5leHRqc0Rpc3RyaWJ1dGlvblByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcbiAgICB0aGlzLnByb3BzID0gcHJvcHM7XG4gICAgdGhpcy5iYXNlUGF0aCA9IG5vcm1hbGl6ZUJhc2VQYXRoKHByb3BzLmJhc2VQYXRoKTtcbiAgICB0aGlzLmFzc2V0UHJlZml4ID0gdGhpcy5yZXNvbHZlQXNzZXRQcmVmaXgoKTtcbiAgICB0aGlzLnN0YXRpY09yaWdpbiA9IHRoaXMuY3JlYXRlU3RhdGljT3JpZ2luKCk7XG4gICAgdGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZSA9IHByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuR0xPQkFMX0ZVTkNUSU9OUztcbiAgICB0aGlzLnZhbGlkYXRlRnVuY3Rpb25Hcm91cFByb3BzKCk7XG4gICAgdGhpcy5keW5hbWljT3JpZ2luID0gdGhpcy5jcmVhdGVEeW5hbWljT3JpZ2luKCk7XG4gICAgdGhpcy5keW5hbWljT3JpZ2luUmVzcG9uc2VQb2xpY3kgPSB0aGlzLmNyZWF0ZUR5bmFtaWNPcmlnaW5SZXF1ZXN0UG9saWN5KCk7XG4gICAgdGhpcy5keW5hbWljQ2xvdWRGcm9udEZ1bmN0aW9uQXNzb2NpYXRpb25zID1cbiAgICAgIHRoaXMuY3JlYXRlRHluYW1pY0Nsb3VkRnJvbnRGdW5jdGlvbkFzc29jaWF0aW9ucygpO1xuICAgIHRoaXMuc3RhdGljQmVoYXZpb3JPcHRpb25zID0gdGhpcy5jcmVhdGVTdGF0aWNCZWhhdmlvck9wdGlvbnMoKTtcbiAgICB0aGlzLmR5bmFtaWNCZWhhdmlvck9wdGlvbnMgPSB0aGlzLmNyZWF0ZUR5bmFtaWNCZWhhdmlvck9wdGlvbnMoKTtcbiAgICB0aGlzLmltYWdlQmVoYXZpb3JPcHRpb25zID0gdGhpcy5jcmVhdGVJbWFnZUJlaGF2aW9yT3B0aW9ucygpO1xuICAgIHRoaXMuZGlzdHJpYnV0aW9uID0gdGhpcy5nZXREaXN0cmlidXRpb24oKTtcbiAgICBpZiAodGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZSkge1xuICAgICAgdGhpcy5ncmFudEludm9rZShERUZBVUxUX0ZVTkNUSU9OX0dST1VQLCBwcm9wcy5mdW5jdGlvblVybCEpO1xuICAgIH1cbiAgICB0aGlzLmFkZFN0YXRpY0JlaGF2aW9ycygpO1xuICAgIHRoaXMuYWRkRHluYW1pY0JlaGF2aW9ycygpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBDbG91ZEZyb250IGNvbW1lbnQgdGhhdCBpcyBzYWZlIGZvciB0aGUgMTI4IGNoYXJhY3RlciBsaW1pdC5cbiAgICogSWYgdGhlIGZ1bGwgY29tbWVudCB3aXRoIHN0YWNrIG5hbWUgZXhjZWVkcyAxMjggY2hhcmFjdGVycywgcmV0dXJucyB0aGUgYmFzZSBjb21tZW50IG9ubHkuXG4gICAqIEBwYXJhbSBiYXNlQ29tbWVudCBUaGUgYmFzZSBjb21tZW50IHRleHRcbiAgICogQHBhcmFtIHN0YWNrTmFtZSBUaGUgc3RhY2sgbmFtZSB0byBhcHBlbmRcbiAgICogQHJldHVybnMgQSBjb21tZW50IHN0cmluZyB0aGF0IGlzIGd1YXJhbnRlZWQgdG8gYmUgPCAxMjggY2hhcmFjdGVyc1xuICAgKi9cbiAgcHJpdmF0ZSBnZXRDb21tZW50KGJhc2VDb21tZW50OiBzdHJpbmcsIHN0YWNrTmFtZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBmdWxsQ29tbWVudCA9IGAke2Jhc2VDb21tZW50fSBmb3IgJHtzdGFja05hbWV9YDtcbiAgICByZXR1cm4gZnVsbENvbW1lbnQubGVuZ3RoIDwgMTI4ID8gZnVsbENvbW1lbnQgOiBiYXNlQ29tbWVudDtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlU3RhdGljT3JpZ2luKCk6IElPcmlnaW4ge1xuICAgIHJldHVybiBTM0J1Y2tldE9yaWdpbi53aXRoT3JpZ2luQWNjZXNzQ29udHJvbCh0aGlzLnByb3BzLmFzc2V0c0J1Y2tldCwge1xuICAgICAgLy8gTElTVCBsZXRzIFMzIGFuc3dlciBhIG1pc3Npbmcga2V5IHdpdGggNDA0IGluc3RlYWQgb2YgNDAzXG4gICAgICBvcmlnaW5BY2Nlc3NMZXZlbHM6IFtBY2Nlc3NMZXZlbC5SRUFELCBBY2Nlc3NMZXZlbC5MSVNUXSxcbiAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5zM0J1Y2tldE9yaWdpblByb3BzLFxuICAgIH0pO1xuICB9XG4gIHByaXZhdGUgY3JlYXRlRHluYW1pY09yaWdpbigpOiBJT3JpZ2luIHtcbiAgICBpZiAodGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZSkge1xuICAgICAgaWYgKCF0aGlzLnByb3BzLmZ1bmN0aW9uVXJsKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1pc3NpbmcgTmV4dGpzRGlzdHJpYnV0aW9uUHJvcHMuZnVuY3Rpb25VcmxcIik7XG4gICAgICB9XG4gICAgICByZXR1cm4gRnVuY3Rpb25VcmxPcmlnaW4ud2l0aE9yaWdpbkFjY2Vzc0NvbnRyb2woXG4gICAgICAgIHRoaXMucHJvcHMuZnVuY3Rpb25VcmwsXG4gICAgICAgIHRoaXMucHJvcHMub3ZlcnJpZGVzPy5keW5hbWljRnVuY3Rpb25VcmxPcmlnaW5XaXRoT0FDUHJvcHMsXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBsb2FkQmFsYW5jZXIgPSB0aGlzLnByb3BzLmxvYWRCYWxhbmNlcjtcbiAgICAgIGlmICghbG9hZEJhbGFuY2VyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1pc3NpbmcgTmV4dGpzRGlzdHJpYnV0aW9uUHJvcHMubG9hZEJhbGFuY2VyXCIpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIFZwY09yaWdpbi53aXRoQXBwbGljYXRpb25Mb2FkQmFsYW5jZXIobG9hZEJhbGFuY2VyLCB7XG4gICAgICAgIHByb3RvY29sUG9saWN5OiB0aGlzLnByb3BzLmNlcnRpZmljYXRlXG4gICAgICAgICAgPyBPcmlnaW5Qcm90b2NvbFBvbGljeS5IVFRQU19PTkxZXG4gICAgICAgICAgOiBPcmlnaW5Qcm90b2NvbFBvbGljeS5IVFRQX09OTFksXG4gICAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5keW5hbWljVnBjT3JpZ2luV2l0aEVuZHBvaW50UHJvcHMsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cbiAgLyoqXG4gICAqIExhbWJkYSBGdW5jdGlvbiBVUkxzIFwiZXhwZWN0IHRoZSBgSG9zdGAgaGVhZGVyIHRvIGNvbnRhaW4gdGhlIG9yaWdpbiBkb21haW5cbiAgICogbmFtZSwgbm90IHRoZSBkb21haW4gbmFtZSBvZiB0aGUgQ2xvdWRGcm9udCBkaXN0cmlidXRpb24uXCJcbiAgICpcbiAgICogQSBjb250YWluZXIgb3JpZ2luIGFsc28gZ2V0cyBDbG91ZEZyb250J3Mgb3duIGhlYWRlcnMsIGZvclxuICAgKiBgQ2xvdWRGcm9udC1Gb3J3YXJkZWQtUHJvdG9gOiB3aXRob3V0IGEgY2VydGlmaWNhdGUgQ2xvdWRGcm9udCByZWFjaGVzIHRoZVxuICAgKiBBTEIgb3ZlciBwbGFpbiBIVFRQLCBzbyB0aGUgQUxCJ3MgYFgtRm9yd2FyZGVkLVByb3RvYCBpcyBgaHR0cGAsIGFuZCB0aGVcbiAgICogcnVudGltZSB3b3VsZCBidWlsZCBldmVyeSBhYnNvbHV0ZSBVUkwgKGByZXF1ZXN0LnVybGAsIHRoZSBvcmlnaW4gYSBzZXJ2ZXJcbiAgICogYWN0aW9uIGlzIGZvcndhcmRlZCB0bykgYXMgYGh0dHA6Ly9gIGJlaGluZCBhIHZpZXdlciBvbiBIVFRQUy5cbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvdXNpbmctbWFuYWdlZC1vcmlnaW4tcmVxdWVzdC1wb2xpY2llcy5odG1sI21hbmFnZWQtb3JpZ2luLXJlcXVlc3QtcG9saWN5LWFsbC12aWV3ZXItZXhjZXB0LWhvc3QtaGVhZGVyXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkRnJvbnQvbGF0ZXN0L0RldmVsb3Blckd1aWRlL3VzaW5nLW1hbmFnZWQtb3JpZ2luLXJlcXVlc3QtcG9saWNpZXMuaHRtbCNtYW5hZ2VkLW9yaWdpbi1yZXF1ZXN0LXBvbGljeS1hbGwtdmlld2VyLWFuZC1jbG91ZGZyb250XG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUR5bmFtaWNPcmlnaW5SZXF1ZXN0UG9saWN5KCk6IElPcmlnaW5SZXF1ZXN0UG9saWN5IHtcbiAgICByZXR1cm4gdGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZVxuICAgICAgPyBPcmlnaW5SZXF1ZXN0UG9saWN5LkFMTF9WSUVXRVJfRVhDRVBUX0hPU1RfSEVBREVSXG4gICAgICA6IE9yaWdpblJlcXVlc3RQb2xpY3kuQUxMX1ZJRVdFUl9BTkRfQ0xPVURGUk9OVF8yMDIyO1xuICB9XG4gIC8qKlxuICAgKiBFbnN1cmVzIE5leHQuanMgYHJlcXVlc3QudXJsYCB3aWxsIGJlIGNvcnJlY3QgZG9tYWluIGluc3RlYWQgb2YgVVJMIG9mXG4gICAqIGNvbXB1dGUgKExhbWJkYSBvciBGYXJnYXRlKVxuICAgKiBAc2VlIGh0dHBzOi8vb3Blbi1uZXh0LmpzLm9yZy9hZHZhbmNlZC93b3JrYXJvdW5kI3dvcmthcm91bmQtc2V0LXgtZm9yd2FyZGVkLWhvc3QtaGVhZGVyLWF3cy1zcGVjaWZpY1xuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVEeW5hbWljQ2xvdWRGcm9udEZ1bmN0aW9uQXNzb2NpYXRpb25zKCk6IEZ1bmN0aW9uQXNzb2NpYXRpb25bXSB7XG4gICAgY29uc3QgYXNzb2NpYXRpb25zOiBGdW5jdGlvbkFzc29jaWF0aW9uW10gPSBbXTtcbiAgICBpZiAodGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZSkge1xuICAgICAgY29uc3QgY2xvdWRGcm9udEZuID0gbmV3IENsb3VkRnJvbnRGdW5jdGlvbih0aGlzLCBcIkNsb3VkRnJvbnRGblwiLCB7XG4gICAgICAgIC8vIGNsb3VkZnJvbnQtanMtMS4wLCBzbyBFUzUuMTogYHZhcmAsIG5vIGFycm93IGZ1bmN0aW9ucywgbm8gdGVtcGxhdGVcbiAgICAgICAgLy8gbGl0ZXJhbHMsIG5vIGBPYmplY3Qua2V5c2AuXG4gICAgICAgIGNvZGU6IEZ1bmN0aW9uQ29kZS5mcm9tSW5saW5lKGBcbiAgICAgICAgICBmdW5jdGlvbiBoYW5kbGVyKGV2ZW50KSB7XG4gICAgICAgICAgICB2YXIgcmVxdWVzdCA9IGV2ZW50LnJlcXVlc3Q7XG4gICAgICAgICAgICB2YXIgdXJpID0gcmVxdWVzdC51cmk7XG5cbiAgICAgICAgICAgIC8vIE5leHQuanMgYW5zd2VycyBhbnkgcGF0aCBjb250YWluaW5nIGEgYmFja3NsYXNoIG9yIGEgcmVwZWF0ZWRcbiAgICAgICAgICAgIC8vIHNsYXNoIHdpdGggYSAzMDggdG8gdGhlIGNvbGxhcHNlZCBwYXRoXG4gICAgICAgICAgICAvLyAoXFxgbm9ybWFsaXplUmVwZWF0ZWRTbGFzaGVzXFxgLCBjYWxsZWQgZnJvbSBcXGBiYXNlLXNlcnZlci50c1xcYCksIGFuZCBzb1xuICAgICAgICAgICAgLy8gZG9lcyB0aGlzIHJ1bnRpbWUuIEJlaGluZCBhIExhbWJkYSBGdW5jdGlvbiBVUkwgdGhlIG9yaWdpbiBuZXZlclxuICAgICAgICAgICAgLy8gZ2V0cyB0aGUgY2hhbmNlOiBPcmlnaW4gQWNjZXNzIENvbnRyb2wgc2lnbnMgdGhlIHJhdyBwYXRoIHdoaWxlIHRoZVxuICAgICAgICAgICAgLy8gRnVuY3Rpb24gVVJMIGNhbm9uaWNhbGl6ZXMgaXQgYmVmb3JlIHZlcmlmeWluZywgc28gdGhlIG9yaWdpblxuICAgICAgICAgICAgLy8gYW5zd2VycyA0MDMgU2lnbmF0dXJlRG9lc05vdE1hdGNoLiBEb2luZyB0aGUgcmVkaXJlY3QgaGVyZSBpcyB3aGF0XG4gICAgICAgICAgICAvLyBtYWtlcyBcXGAvYmFzZXBhdGgvL3RvLXN2XFxgIGJlaGF2ZSBhcyBpdCBkb2VzIHVuZGVyIFxcYG5leHQgc3RhcnRcXGAuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gQSBiYXJlIFxcYC8vXFxgIHJlYWNoZXMgaGVyZSB0b28sIGFuZCBpcyBhbnN3ZXJlZCB0aGUgc2FtZSB3YXkgLVxuICAgICAgICAgICAgLy8gbWVhc3VyZWQsIGJlY2F1c2UgXFxgLy9cXGAgYXQgdGhlIHN0YXJ0IG9mIGEgcmVxdWVzdCB0YXJnZXQgaXMgYWxzbyB0aGVcbiAgICAgICAgICAgIC8vIGF1dGhvcml0eSBmb3JtIGFuZCBpdCB3YXMgbm90IG9idmlvdXMgQ2xvdWRGcm9udCB3b3VsZCByb3V0ZSBpdCB0byBhXG4gICAgICAgICAgICAvLyBmdW5jdGlvbiBhdCBhbGwuIEl0IGRvZXM6IFxcYEdFVCAvL1xcYCBhbnN3ZXJzIDMwOCB0byBcXGAvXFxgIHdpdGhcbiAgICAgICAgICAgIC8vIFxcYHgtY2FjaGU6IEZ1bmN0aW9uR2VuZXJhdGVkUmVzcG9uc2VcXGAsIG92ZXIgYm90aCBIVFRQLzEuMSBhbmQgSFRUUC8yLFxuICAgICAgICAgICAgLy8gd2hpY2ggaXMgd2hhdCBcXGB0ZXN0L2UyZS9oeWRyYXRpb25cXGAgYXNrcyBmb3IuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gVHdvIHRoaW5ncyBOZXh0LmpzIGRvZXMgdGhhdCB0aGlzIGNhbm5vdDpcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyAtIHRoZSBib2R5IGl0IHNlbmRzIHdpdGggaXRzIG93biByZWRpcmVjdCAodGhlIGRlc3RpbmF0aW9uLCBhc1xuICAgICAgICAgICAgLy8gICB0ZXh0KSwgYmVjYXVzZSBhIGdlbmVyYXRlZCByZXNwb25zZSBjYW4gb25seSBjYXJyeSBvbmUgb25cbiAgICAgICAgICAgIC8vICAgY2xvdWRmcm9udC1qcy0yLjAuIE5vIGtub3duIGNsaWVudCByZWFkcyBpdC5cbiAgICAgICAgICAgIC8vIC0gdGhlIG9yaWdpbmFsIG9yZGVyIG9mIHRoZSBxdWVyeSBzdHJpbmcuIFRoZSBldmVudCBleHBvc2VzXG4gICAgICAgICAgICAvLyAgIFxcYHF1ZXJ5c3RyaW5nXFxgIGFzIGFuIG9iamVjdCwgbmV2ZXIgYXMgdGhlIHJhdyBzdHJpbmcsIHNvXG4gICAgICAgICAgICAvLyAgIFxcYC94Ly95P2E9MSZiPTJcXGAgcmVkaXJlY3RzIHRvIFxcYC94L3k/Yj0yJmE9MVxcYC4gVGhlIHBhaXJzIGFsbFxuICAgICAgICAgICAgLy8gICBzdXJ2aXZlOyBvbmx5IHRoZWlyIG9yZGVyIGlzIENsb3VkRnJvbnQncyByYXRoZXIgdGhhbiB0aGVcbiAgICAgICAgICAgIC8vICAgY2xpZW50J3MsIGFuZCBhIHJlZGlyZWN0IHRhcmdldCBpcyBub3Qgb3JkZXItc2Vuc2l0aXZlLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIEEgcmVwZWF0ZWQga2V5J3MgXFxgbXVsdGlWYWx1ZVxcYCBhbHJlYWR5IGhvbGRzIGl0cyBmaXJzdCB2YWx1ZSwgd2hpY2hcbiAgICAgICAgICAgIC8vIFxcYHZhbHVlXFxgIHJlcGVhdHMsIHNvIGl0IGlzIG9uZSBvciB0aGUgb3RoZXIsIG5ldmVyIGJvdGguIE5hbWVzIGFuZFxuICAgICAgICAgICAgLy8gdmFsdWVzIGFycml2ZSBhcyB0aGUgY2xpZW50IHNlbnQgdGhlbSwgc3RpbGwgcGVyY2VudC1lbmNvZGVkXG4gICAgICAgICAgICAvLyAobWVhc3VyZWQ6IFxcYD9hPSUyMGIlMjZjJnA9MSsyXFxgIHJlYWRzIGJhY2sgdW5jaGFuZ2VkKSwgc28gdGhleSBhcmVcbiAgICAgICAgICAgIC8vIGpvaW5lZCBhcy1pczsgZW5jb2RpbmcgdGhlbSBhZ2FpbiB3b3VsZCB0dXJuIFxcYCUyMFxcYCBpbnRvIFxcYCUyNTIwXFxgLlxuICAgICAgICAgICAgaWYgKC9cXFxcXFxcXHxcXFxcL1xcXFwvLy50ZXN0KHVyaSkpIHtcbiAgICAgICAgICAgICAgdmFyIGxvY2F0aW9uID0gdXJpLnJlcGxhY2UoL1xcXFxcXFxcL2csIFwiL1wiKS5yZXBsYWNlKC9cXFxcL1xcXFwvKy9nLCBcIi9cIik7XG4gICAgICAgICAgICAgIHZhciBxcyA9IFtdO1xuICAgICAgICAgICAgICBmb3IgKHZhciBuYW1lIGluIHJlcXVlc3QucXVlcnlzdHJpbmcpIHtcbiAgICAgICAgICAgICAgICB2YXIgcSA9IHJlcXVlc3QucXVlcnlzdHJpbmdbbmFtZV07XG4gICAgICAgICAgICAgICAgdmFyIHZhbHVlcyA9IHEubXVsdGlWYWx1ZSB8fCBbcV07XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2YWx1ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgIHZhciB2ID0gdmFsdWVzW2ldLnZhbHVlO1xuICAgICAgICAgICAgICAgICAgcXMucHVzaCh2ID09PSBcIlwiID8gbmFtZSA6IG5hbWUgKyBcIj1cIiArIHYpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAocXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgbG9jYXRpb24gPSBsb2NhdGlvbiArIFwiP1wiICsgcXMuam9pbihcIiZcIik7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAzMDgsXG4gICAgICAgICAgICAgICAgc3RhdHVzRGVzY3JpcHRpb246IFwiUGVybWFuZW50IFJlZGlyZWN0XCIsXG4gICAgICAgICAgICAgICAgaGVhZGVyczogeyBsb2NhdGlvbjogeyB2YWx1ZTogbG9jYXRpb24gfSB9LFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbXCJ4LWZvcndhcmRlZC1ob3N0XCJdID0gcmVxdWVzdC5oZWFkZXJzLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gcmVxdWVzdDtcbiAgICAgICAgICB9XG4gICAgICAgICAgYCksXG4gICAgICB9KTtcbiAgICAgIGFzc29jaWF0aW9ucy5wdXNoKHtcbiAgICAgICAgZXZlbnRUeXBlOiBGdW5jdGlvbkV2ZW50VHlwZS5WSUVXRVJfUkVRVUVTVCxcbiAgICAgICAgZnVuY3Rpb246IGNsb3VkRnJvbnRGbixcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gYXNzb2NpYXRpb25zO1xuICB9XG4gIHByaXZhdGUgY3JlYXRlU3RhdGljQmVoYXZpb3JPcHRpb25zKCk6IEJlaGF2aW9yT3B0aW9ucyB7XG4gICAgY29uc3Qgc3RhdGljQmVoYXZpb3JPcHRpb25zID0gdGhpcy5wcm9wcy5vdmVycmlkZXM/LnN0YXRpY0JlaGF2aW9yT3B0aW9ucztcbiAgICBjb25zdCByZXNwb25zZUhlYWRlcnNQb2xpY3kgPVxuICAgICAgc3RhdGljQmVoYXZpb3JPcHRpb25zPy5yZXNwb25zZUhlYWRlcnNQb2xpY3kgPz9cbiAgICAgIG5ldyBSZXNwb25zZUhlYWRlcnNQb2xpY3kodGhpcywgXCJTdGF0aWNSZXNwb25zZUhlYWRlcnNQb2xpY3lcIiwge1xuICAgICAgICBzZWN1cml0eUhlYWRlcnNCZWhhdmlvcjogdGhpcy5jb21tb25TZWN1cml0eUhlYWRlcnNCZWhhdmlvcixcbiAgICAgICAgY29tbWVudDogdGhpcy5nZXRDb21tZW50KFxuICAgICAgICAgIFwiTmV4dEpTIFN0YXRpYyBSZXNwb25zZSBIZWFkZXJzIFBvbGljeVwiLFxuICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgICAgKSxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LnN0YXRpY1Jlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzLFxuICAgICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFsbG93ZWRNZXRob2RzOiBBbGxvd2VkTWV0aG9kcy5BTExPV19HRVRfSEVBRF9PUFRJT05TLFxuICAgICAgY2FjaGVkTWV0aG9kczogQ2FjaGVkTWV0aG9kcy5DQUNIRV9HRVRfSEVBRF9PUFRJT05TLFxuICAgICAgY2FjaGVQb2xpY3k6IENhY2hlUG9saWN5LkNBQ0hJTkdfT1BUSU1JWkVELFxuICAgICAgb3JpZ2luOiB0aGlzLnN0YXRpY09yaWdpbixcbiAgICAgIHJlc3BvbnNlSGVhZGVyc1BvbGljeSxcbiAgICAgIHZpZXdlclByb3RvY29sUG9saWN5OiBWaWV3ZXJQcm90b2NvbFBvbGljeS5SRURJUkVDVF9UT19IVFRQUyxcbiAgICAgIC4uLnN0YXRpY0JlaGF2aW9yT3B0aW9ucyxcbiAgICB9O1xuICB9XG4gIHByaXZhdGUgY3JlYXRlRHluYW1pY0JlaGF2aW9yT3B0aW9ucygpOiBCZWhhdmlvck9wdGlvbnMge1xuICAgIGNvbnN0IGR5bmFtaWNCZWhhdmlvck9wdGlvbnMgPSB0aGlzLnByb3BzLm92ZXJyaWRlcz8uZHluYW1pY0JlaGF2aW9yT3B0aW9ucztcbiAgICBjb25zdCBjYWNoZVBvbGljeVByb3BzID0gdGhpcy5wcm9wcy5vdmVycmlkZXM/LmR5bmFtaWNDYWNoZVBvbGljeVByb3BzO1xuICAgIC8vIGNyZWF0ZSBkZWZhdWx0IGNhY2hlIHBvbGljeSBpZiBub3QgcHJvdmlkZWRcbiAgICBjb25zdCBjYWNoZVBvbGljeSA9XG4gICAgICBkeW5hbWljQmVoYXZpb3JPcHRpb25zPy5jYWNoZVBvbGljeSA/P1xuICAgICAgbmV3IENhY2hlUG9saWN5KHRoaXMsIFwiRHluYW1pY0NhY2hlUG9saWN5XCIsIHtcbiAgICAgICAgLi4uKGlzQ2FjaGluZ0Rpc2FibGVkKGNhY2hlUG9saWN5UHJvcHMpXG4gICAgICAgICAgPyBESVNBQkxFRF9DQUNIRV9LRVlcbiAgICAgICAgICA6IERZTkFNSUNfQ0FDSEVfS0VZKSxcbiAgICAgICAgLy8gQSByZXNwb25zZSB3aXRoIG5vIGBDYWNoZS1Db250cm9sYCBpcyBub3QgY2FjaGVkLCB3aGljaCBpcyB3aGF0IE5leHQuanNcbiAgICAgICAgLy8gYW5kIGV2ZXJ5IGFwcCB3cml0dGVuIGZvciBpdCBhc3N1bWU6IGEgZHluYW1pYyByb3V0ZSBoYW5kbGVyIHNldHMgbm9uZS5cbiAgICAgICAgLy8gQ0RLJ3MgZGVmYXVsdCBpcyBhIGRheSwgd2hpY2ggY2FjaGVkIGAvYXBpLypgIHJlc3BvbnNlcyBhdCB0aGUgZWRnZSBmb3JcbiAgICAgICAgLy8gMjQgaG91cnMuIEFueXRoaW5nIE5leHQuanMgKm1lYW5zKiB0byBjYWNoZSAtIElTUiwgU1NHLCBhIFBQUiBzaGVsbCAtXG4gICAgICAgIC8vIHNheXMgc28gd2l0aCBgcy1tYXhhZ2VgLCB3aGljaCBgbWF4VHRsYCBzdGlsbCBob25vcnMuXG4gICAgICAgIGRlZmF1bHRUdGw6IER1cmF0aW9uLnNlY29uZHMoMCksXG4gICAgICAgIGNvbW1lbnQ6IHRoaXMuZ2V0Q29tbWVudChcbiAgICAgICAgICBcIk5leHRKUyBEeW5hbWljIENhY2hlIFBvbGljeVwiLFxuICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgICAgKSxcbiAgICAgICAgLi4uY2FjaGVQb2xpY3lQcm9wcyxcbiAgICAgIH0pO1xuICAgIGNvbnN0IHJlc3BvbnNlSGVhZGVyc1BvbGljeSA9XG4gICAgICBkeW5hbWljQmVoYXZpb3JPcHRpb25zPy5yZXNwb25zZUhlYWRlcnNQb2xpY3kgPz9cbiAgICAgIG5ldyBSZXNwb25zZUhlYWRlcnNQb2xpY3kodGhpcywgXCJEeW5hbWljUmVzcG9uc2VIZWFkZXJzUG9saWN5XCIsIHtcbiAgICAgICAgc2VjdXJpdHlIZWFkZXJzQmVoYXZpb3I6IHRoaXMuY29tbW9uU2VjdXJpdHlIZWFkZXJzQmVoYXZpb3IsXG4gICAgICAgIGNvbW1lbnQ6IHRoaXMuZ2V0Q29tbWVudChcbiAgICAgICAgICBcIk5leHRKUyBEeW5hbWljIFJlc3BvbnNlIEhlYWRlcnMgUG9saWN5XCIsXG4gICAgICAgICAgU3RhY2sub2YodGhpcykuc3RhY2tOYW1lLFxuICAgICAgICApLFxuICAgICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8uZHluYW1pY1Jlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzLFxuICAgICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFsbG93ZWRNZXRob2RzOiBBbGxvd2VkTWV0aG9kcy5BTExPV19BTEwsXG4gICAgICBjYWNoZVBvbGljeSxcbiAgICAgIG9yaWdpbjogdGhpcy5keW5hbWljT3JpZ2luLFxuICAgICAgb3JpZ2luUmVxdWVzdFBvbGljeTogdGhpcy5keW5hbWljT3JpZ2luUmVzcG9uc2VQb2xpY3ksXG4gICAgICByZXNwb25zZUhlYWRlcnNQb2xpY3ksXG4gICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICAuLi5keW5hbWljQmVoYXZpb3JPcHRpb25zLFxuICAgICAgZnVuY3Rpb25Bc3NvY2lhdGlvbnM6IHRoaXMud2l0aER5bmFtaWNGdW5jdGlvbkFzc29jaWF0aW9ucyhcbiAgICAgICAgXCJkeW5hbWljQmVoYXZpb3JPcHRpb25zXCIsXG4gICAgICAgIGR5bmFtaWNCZWhhdmlvck9wdGlvbnM/LmZ1bmN0aW9uQXNzb2NpYXRpb25zLFxuICAgICAgKSxcbiAgICB9O1xuICB9XG4gIC8qKlxuICAgKiBUaGUgYmVoYXZpb3IncyBmdW5jdGlvbiBhc3NvY2lhdGlvbnM6IGFuIG92ZXJyaWRlJ3MsIHBsdXMgdGhlIHZpZXdlci1yZXF1ZXN0XG4gICAqIGZ1bmN0aW9uIEdsb2JhbCBGdW5jdGlvbnMgZGVwZW5kcyBvbi5cbiAgICpcbiAgICogU3ByZWFkaW5nIHRoZSBvdmVycmlkZSdzIGBmdW5jdGlvbkFzc29jaWF0aW9uc2Agb3ZlciBvdXJzIHdvdWxkIHNpbGVudGx5XG4gICAqIGRyb3AgdGhhdCBmdW5jdGlvbiwgYW5kIHdpdGggaXQgdGhlIG9ubHkgdGhpbmcgc3RhbmRpbmcgYmV0d2VlbiBhIHZpZXdlcidzXG4gICAqIG93biBgWC1Gb3J3YXJkZWQtSG9zdGAgYW5kIHRoZSBydW50aW1lLCB3aGljaCB0cnVzdHMgdGhhdCBoZWFkZXIgb24gRnVuY3Rpb25cbiAgICogVVJMIGV2ZW50cyAoYGxhbWJkYS1ldmVudC50c2ApOiBob3N0IGluamVjdGlvbiBpbnRvIHJlZGlyZWN0cyBhbmQgYWJzb2x1dGVcbiAgICogVVJMcywgY2FjaGVkIGZvciBvdGhlciB2aWV3ZXJzIGJlY2F1c2UgdGhlIGhlYWRlciBpcyBub3QgaW4gdGhlIGNhY2hlIGtleS5cbiAgICogU28gb3VycyBpcyBrZXB0LCBhbmQgYW4gb3ZlcnJpZGUgY2xhaW1pbmcgVklFV0VSX1JFUVVFU1Qg4oCUIHdoaWNoIENsb3VkRnJvbnRcbiAgICogYWxsb3dzIG9ubHkgb25lIG9mIHBlciBiZWhhdmlvciDigJQgaXMgYW4gZXJyb3IgcmF0aGVyIHRoYW4gYSByZXBsYWNlbWVudC5cbiAgICovXG4gIHByaXZhdGUgd2l0aER5bmFtaWNGdW5jdGlvbkFzc29jaWF0aW9ucyhcbiAgICBvdmVycmlkZU5hbWU6IHN0cmluZyxcbiAgICBvdmVycmlkZGVuOiBGdW5jdGlvbkFzc29jaWF0aW9uW10gfCB1bmRlZmluZWQsXG4gICk6IEZ1bmN0aW9uQXNzb2NpYXRpb25bXSB7XG4gICAgaWYgKCFvdmVycmlkZGVuKSB7XG4gICAgICByZXR1cm4gdGhpcy5keW5hbWljQ2xvdWRGcm9udEZ1bmN0aW9uQXNzb2NpYXRpb25zO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuaXNGdW5jdGlvbkNvbXB1dGUpIHtcbiAgICAgIHJldHVybiBvdmVycmlkZGVuO1xuICAgIH1cbiAgICBjb25zdCBjbGFpbWVkID0gb3ZlcnJpZGRlbi5zb21lKFxuICAgICAgKGFzc29jaWF0aW9uKSA9PlxuICAgICAgICBhc3NvY2lhdGlvbi5ldmVudFR5cGUgPT09IEZ1bmN0aW9uRXZlbnRUeXBlLlZJRVdFUl9SRVFVRVNULFxuICAgICk7XG4gICAgaWYgKGNsYWltZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7TE9HX1BSRUZJWH0gXFxgb3ZlcnJpZGVzLiR7b3ZlcnJpZGVOYW1lfS5mdW5jdGlvbkFzc29jaWF0aW9uc1xcYCBgICtcbiAgICAgICAgICBgYXNzb2NpYXRlcyBhIENsb3VkRnJvbnQgZnVuY3Rpb24gd2l0aCBgICtcbiAgICAgICAgICBgJHtGdW5jdGlvbkV2ZW50VHlwZS5WSUVXRVJfUkVRVUVTVH0sIGJ1dCBOZXh0anNHbG9iYWxGdW5jdGlvbnMgbmVlZHMgYCArXG4gICAgICAgICAgYHRoYXQgZXZlbnQgdHlwZSBmb3IgaXRzIG93biBmdW5jdGlvbiwgd2hpY2ggb3ZlcndyaXRlcyBgICtcbiAgICAgICAgICBgXFxgeC1mb3J3YXJkZWQtaG9zdFxcYCB3aXRoIHRoZSB2aWV3ZXIncyBcXGBIb3N0XFxgICh0aGUgcnVudGltZSB0cnVzdHMgYCArXG4gICAgICAgICAgYHRoYXQgaGVhZGVyIGJlaGluZCBDbG91ZEZyb250KSBhbmQgcmVkaXJlY3RzIHJlcGVhdGVkIHNsYXNoZXMuIGAgK1xuICAgICAgICAgIGBDbG91ZEZyb250IHBlcm1pdHMgb25seSBvbmUgZnVuY3Rpb24gcGVyIGV2ZW50IHR5cGUgcGVyIGJlaGF2aW9yLiBgICtcbiAgICAgICAgICBgTW92ZSB0aGUgbG9naWMgdG8gJHtGdW5jdGlvbkV2ZW50VHlwZS5WSUVXRVJfUkVTUE9OU0V9LCBvciBpbnRvIGAgK1xuICAgICAgICAgIGB0aGUgYXBwJ3MgbWlkZGxld2FyZS5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIFsuLi5vdmVycmlkZGVuLCAuLi50aGlzLmR5bmFtaWNDbG91ZEZyb250RnVuY3Rpb25Bc3NvY2lhdGlvbnNdO1xuICB9XG4gIC8qKlxuICAgKiBgX25leHQvaW1hZ2UqYCBnb2VzIHRvIHRoZSBzYW1lIG9yaWdpbiBhcyBldmVyeXRoaW5nIGVsc2Ug4oCUIHRoZSBOZXh0LmpzXG4gICAqIHNlcnZlciBvcHRpbWl6ZXMgaW1hZ2VzIGluLXByb2Nlc3Mg4oCUIGJ1dCBrZWVwcyBpdHMgb3duIGJlaGF2aW9yIGZvciB0aGVcbiAgICogY2FjaGUgcG9saWN5OiBgcXVlcnlTdHJpbmdCZWhhdmlvcjogYWxsKClgIHBsdXMgYGFjY2VwdGAgaW4gdGhlIGNhY2hlIGtleSBpc1xuICAgKiByaWdodCBmb3IgaW1hZ2UgcmVxdWVzdHMgYW5kIHdyb25nIGZvciB0aGUgcmVzdC5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlSW1hZ2VCZWhhdmlvck9wdGlvbnMoKTogQmVoYXZpb3JPcHRpb25zIHtcbiAgICBjb25zdCBpbWFnZUJlaGF2aW9yT3B0aW9ucyA9IHRoaXMucHJvcHMub3ZlcnJpZGVzPy5pbWFnZUJlaGF2aW9yT3B0aW9ucztcbiAgICAvLyBhZGQgZGVmYXVsdCBjYWNoZSBwb2xpY3kgaWYgbm90IHByb3ZpZGVkXG4gICAgY29uc3QgY2FjaGVQb2xpY3kgPVxuICAgICAgaW1hZ2VCZWhhdmlvck9wdGlvbnM/LmNhY2hlUG9saWN5ID8/XG4gICAgICBuZXcgQ2FjaGVQb2xpY3kodGhpcywgXCJJbWFnZUNhY2hlUG9saWN5XCIsIHtcbiAgICAgICAgLy8gU0VDVVJJVFkgTk9URTogYnkgZGVmYXVsdCB3ZSBkb24ndCBpbmNsdWRlIGNvb2tpZXMgaW4gY2FjaGUgZm9yXG4gICAgICAgIC8vIGltYWdlcyBiL2MgaXQgc2lnbmlmaWNhbnRseSBpbXByb3ZlcyBpbWFnZSBwZXJmIGZvciBtb3N0IHNpdGVzIEJVVFxuICAgICAgICAvLyBpZiB5b3UgaGF2ZSBwcml2YXRlIGltYWdlcyBsb2NrZWQgYmVoaW5kIGF1dGggaW1wbGVtZW50ZWQgd2l0aCBjb29raWVzXG4gICAgICAgIC8vIHlvdSBuZWVkIHRvIG92ZXJyaWRlIHRoaXMuXG4gICAgICAgIHF1ZXJ5U3RyaW5nQmVoYXZpb3I6IENhY2hlUXVlcnlTdHJpbmdCZWhhdmlvci5hbGwoKSxcbiAgICAgICAgaGVhZGVyQmVoYXZpb3I6IENhY2hlSGVhZGVyQmVoYXZpb3IuYWxsb3dMaXN0KFwiYWNjZXB0XCIpLFxuICAgICAgICBjb29raWVCZWhhdmlvcjogQ2FjaGVDb29raWVCZWhhdmlvci5ub25lKCksXG4gICAgICAgIGVuYWJsZUFjY2VwdEVuY29kaW5nQnJvdGxpOiB0cnVlLFxuICAgICAgICBlbmFibGVBY2NlcHRFbmNvZGluZ0d6aXA6IHRydWUsXG4gICAgICAgIGNvbW1lbnQ6IHRoaXMuZ2V0Q29tbWVudChcbiAgICAgICAgICBcIk5leHRKUyBJbWFnZSBDYWNoZSBQb2xpY3lcIixcbiAgICAgICAgICBTdGFjay5vZih0aGlzKS5zdGFja05hbWUsXG4gICAgICAgICksXG4gICAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5pbWFnZUNhY2hlUG9saWN5UHJvcHMsXG4gICAgICB9KTtcbiAgICAvLyBhZGQgZGVmYXVsdCByZXNwb25zZSBoZWFkZXJzIHBvbGljeSBpZiBub3QgcHJvdmlkZWRcbiAgICBjb25zdCByZXNwb25zZUhlYWRlcnNQb2xpY3kgPVxuICAgICAgaW1hZ2VCZWhhdmlvck9wdGlvbnM/LnJlc3BvbnNlSGVhZGVyc1BvbGljeSA/P1xuICAgICAgbmV3IFJlc3BvbnNlSGVhZGVyc1BvbGljeSh0aGlzLCBcIkltYWdlUmVzcG9uc2VIZWFkZXJzUG9saWN5XCIsIHtcbiAgICAgICAgc2VjdXJpdHlIZWFkZXJzQmVoYXZpb3I6IHRoaXMuY29tbW9uU2VjdXJpdHlIZWFkZXJzQmVoYXZpb3IsXG4gICAgICAgIGNvbW1lbnQ6IHRoaXMuZ2V0Q29tbWVudChcbiAgICAgICAgICBcIk5leHRKUyBJbWFnZSBSZXNwb25zZSBIZWFkZXJzIFBvbGljeVwiLFxuICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgICAgKSxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmltYWdlUmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHMsXG4gICAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgYWxsb3dlZE1ldGhvZHM6IEFsbG93ZWRNZXRob2RzLkFMTE9XX0dFVF9IRUFEX09QVElPTlMsXG4gICAgICBjYWNoZWRNZXRob2RzOiBDYWNoZWRNZXRob2RzLkNBQ0hFX0dFVF9IRUFEX09QVElPTlMsXG4gICAgICBvcmlnaW46IHRoaXMuZHluYW1pY09yaWdpbixcbiAgICAgIG9yaWdpblJlcXVlc3RQb2xpY3k6IHRoaXMuZHluYW1pY09yaWdpblJlc3BvbnNlUG9saWN5LFxuICAgICAgY2FjaGVQb2xpY3ksXG4gICAgICByZXNwb25zZUhlYWRlcnNQb2xpY3ksXG4gICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICAuLi5pbWFnZUJlaGF2aW9yT3B0aW9ucyxcbiAgICAgIGZ1bmN0aW9uQXNzb2NpYXRpb25zOiB0aGlzLndpdGhEeW5hbWljRnVuY3Rpb25Bc3NvY2lhdGlvbnMoXG4gICAgICAgIFwiaW1hZ2VCZWhhdmlvck9wdGlvbnNcIixcbiAgICAgICAgaW1hZ2VCZWhhdmlvck9wdGlvbnM/LmZ1bmN0aW9uQXNzb2NpYXRpb25zLFxuICAgICAgKSxcbiAgICB9O1xuICB9XG4gIC8qKlxuICAgKiBDcmVhdGVzIG9yIHVzZXMgdXNlciBzcGVjaWZpZWQgQ2xvdWRGcm9udCBEaXN0cmlidXRpb25cbiAgICovXG4gIHByaXZhdGUgZ2V0RGlzdHJpYnV0aW9uKCk6IERpc3RyaWJ1dGlvbiB7XG4gICAgbGV0IGRpc3RyaWJ1dGlvbjogRGlzdHJpYnV0aW9uO1xuICAgIGlmICh0aGlzLnByb3BzLmRpc3RyaWJ1dGlvbikge1xuICAgICAgZGlzdHJpYnV0aW9uID0gdGhpcy5wcm9wcy5kaXN0cmlidXRpb247XG4gICAgfSBlbHNlIHtcbiAgICAgIGRpc3RyaWJ1dGlvbiA9IG5ldyBEaXN0cmlidXRpb24odGhpcywgXCJEaXN0cmlidXRpb25cIiwge1xuICAgICAgICBtaW5pbXVtUHJvdG9jb2xWZXJzaW9uOiBTZWN1cml0eVBvbGljeVByb3RvY29sLlRMU19WMV8yXzIwMjEsXG4gICAgICAgIGRlZmF1bHRCZWhhdmlvcjogdGhpcy5keW5hbWljQmVoYXZpb3JPcHRpb25zLFxuICAgICAgICAvLyBiZXN0IHRvIHVzZSBIVFRQIDIgYW5kIDMgZm9yIGNvbXBhdGFiaWxpdHkgKEhUVFAgMikgYW5kIHBlcmZvcm1hbmNlIChIVFRQMylcbiAgICAgICAgLy8gQ2xvdWRGcm9udCB3aWxsIGNob29zZSBiZXN0IG9wdGlvbiBmb3IgY2xpZW50XG4gICAgICAgIGh0dHBWZXJzaW9uOiBIdHRwVmVyc2lvbi5IVFRQMl9BTkRfMyxcbiAgICAgICAgY29tbWVudDogdGhpcy5nZXRDb21tZW50KFxuICAgICAgICAgIFwiTmV4dEpTIERpc3RyaWJ1dGlvblwiLFxuICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgICAgKSxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmRpc3RyaWJ1dGlvblByb3BzLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBkaXN0cmlidXRpb247XG4gIH1cbiAgcHJpdmF0ZSBhZGREeW5hbWljQmVoYXZpb3JzKCkge1xuICAgIC8vIEltYWdlIEJlaGF2aW9yXG4gICAgdGhpcy5kaXN0cmlidXRpb24uYWRkQmVoYXZpb3IoXG4gICAgICB0aGlzLmdldFBhdGhQYXR0ZXJuKFwiX25leHQvaW1hZ2UqXCIpLFxuICAgICAgdGhpcy5pbWFnZUJlaGF2aW9yT3B0aW9ucy5vcmlnaW4sXG4gICAgICB0aGlzLmltYWdlQmVoYXZpb3JPcHRpb25zLFxuICAgICk7XG4gICAgLy8gRnVuY3Rpb24gZ3JvdXAgYmVoYXZpb3JzLCBiZWZvcmUgdGhlIGJhc2VQYXRoIGNhdGNoLWFsbCBiZWxvdyBhbmQgYWZ0ZXJcbiAgICAvLyBgX25leHQvaW1hZ2UqYCAobm8gZ3JvdXAgcGF0dGVybiBjYW4gbWF0Y2ggYW4gaW1hZ2UgcmVxdWVzdCwgYW5kIGtlZXBpbmdcbiAgICAvLyB0aGUgb3JkZXIgb2YgdGhlIHVuc3BsaXQgY2FzZSBieXRlLWlkZW50aWNhbCBpcyB3b3J0aCBtb3JlIHRoYW4gc3ltbWV0cnkpLlxuICAgIHRoaXMuYWRkRnVuY3Rpb25Hcm91cEJlaGF2aW9ycygpO1xuICAgIC8vIFJvb3QgUGF0aCBCZWhhdmlvcnNcbiAgICBpZiAodGhpcy5iYXNlUGF0aCkge1xuICAgICAgLy8gYmVjYXVzZSB3ZSBhbHJlYWR5IGhhdmUgYSBiYXNlUGF0aCB3ZSBkb24ndCB1c2UgLyBpbnN0ZWFkIHdlIHVzZSAvYmFzZS1wYXRoXG4gICAgICB0aGlzLmRpc3RyaWJ1dGlvbi5hZGRCZWhhdmlvcihcbiAgICAgICAgYC8ke3RoaXMuYmFzZVBhdGh9YCxcbiAgICAgICAgdGhpcy5keW5hbWljQmVoYXZpb3JPcHRpb25zLm9yaWdpbixcbiAgICAgICAgdGhpcy5keW5hbWljQmVoYXZpb3JPcHRpb25zLFxuICAgICAgKTtcbiAgICAgIC8vIHdoZW4gYmFzZVBhdGggaXMgc2V0LCB3ZSBlbXVsYXRlIHRoZSBcImRlZmF1bHQgYmVoYXZpb3JcIiAoKikgZm9yIHRoZSBzaXRlIGFzIGAvYmFzZS1wYXRoLypgXG4gICAgICB0aGlzLmRpc3RyaWJ1dGlvbi5hZGRCZWhhdmlvcihcbiAgICAgICAgdGhpcy5nZXRQYXRoUGF0dGVybihcIipcIiksXG4gICAgICAgIHRoaXMuZHluYW1pY0JlaGF2aW9yT3B0aW9ucy5vcmlnaW4sXG4gICAgICAgIHRoaXMuZHluYW1pY0JlaGF2aW9yT3B0aW9ucyxcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGlmIG5vIGJhc2UgcGF0aCwgdGhlbiBkZWZhdWx0IGJlaGF2aW9yIHdpbGwgaGFuZGxlIGFsbCBvdGhlciBwYXRoc1xuICAgIH1cbiAgfVxuICAvKipcbiAgICogQmVmb3JlIGFueSBiZWhhdmlvciBpcyBjb21wdXRlZDogdGhlIGJ1ZGdldCBhbmQgdGhlIGBwdWJsaWMvYCBjaGVja3MgYm90aFxuICAgKiBnZW5lcmF0ZSB0aGUgZ3JvdXAgcGF0dGVybnMsIGFuZCB3b3VsZCBvdGhlcndpc2UgZmFpbCBmaXJzdCB3aXRoIGEgbGVzc1xuICAgKiB1c2VmdWwgbWVzc2FnZS5cbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVGdW5jdGlvbkdyb3VwUHJvcHMoKSB7XG4gICAgaWYgKFxuICAgICAgIXRoaXMucHJvcHMuZnVuY3Rpb25Hcm91cHM/Lmxlbmd0aCAmJlxuICAgICAgIXRoaXMucHJvcHMuZnVuY3Rpb25Hcm91cEJlaGF2aW9ycz8ubGVuZ3RoXG4gICAgKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghdGhpcy5pc0Z1bmN0aW9uQ29tcHV0ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBcImBmdW5jdGlvbkdyb3Vwc2AgaXMgb25seSBzdXBwb3J0ZWQgYnkgTmV4dGpzR2xvYmFsRnVuY3Rpb25zLlwiLFxuICAgICAgKTtcbiAgICB9XG4gIH1cbiAgLyoqXG4gICAqIEV2ZXJ5IGdyb3VwIGJlaGF2aW9yLCBmaW5hbCBwYXRoIHBhdHRlcm4gaW5jbHVkZWQsIGluIHRoZSBvcmRlclxuICAgKiB7QGxpbmsgYWRkRnVuY3Rpb25Hcm91cEJlaGF2aW9yc30gYWRkcyB0aGVtLlxuICAgKi9cbiAgcHJpdmF0ZSBmdW5jdGlvbkdyb3VwQmVoYXZpb3JzKCkge1xuICAgIHJldHVybiAodGhpcy5wcm9wcy5mdW5jdGlvbkdyb3VwQmVoYXZpb3JzID8/IFtdKS5tYXAoKGJlaGF2aW9yKSA9PiB7XG4gICAgICBjb25zdCBncm91cCA9IHRoaXMucHJvcHMuZnVuY3Rpb25Hcm91cHM/LmZpbmQoXG4gICAgICAgIChpdCkgPT4gaXQubmFtZSA9PT0gYmVoYXZpb3IuZ3JvdXAsXG4gICAgICApO1xuICAgICAgaWYgKCFncm91cCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYCR7TE9HX1BSRUZJWH0gXFxgZnVuY3Rpb25Hcm91cEJlaGF2aW9yc1xcYCByb3V0ZXMgdG8gZnVuY3Rpb24gZ3JvdXAgYCArXG4gICAgICAgICAgICBgXCIke2JlaGF2aW9yLmdyb3VwfVwiLCB3aGljaCBpcyBub3QgaW4gXFxgZnVuY3Rpb25Hcm91cHNcXGAuYCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLmJlaGF2aW9yLFxuICAgICAgICBncm91cCxcbiAgICAgICAgcGF0aFBhdHRlcm46IHRoaXMuZ2V0UGF0aFBhdHRlcm4oYmVoYXZpb3IucGF0dGVybiksXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBPbmUgYmVoYXZpb3IgcGVyIGdyb3VwIHBhdHRlcm4sIG1vc3Qgc3BlY2lmaWMgZmlyc3QuXG4gICAqXG4gICAqIFRoZSBvcmRlciBpcyB0aGUgd2hvbGUgbWVjaGFuaXNtLiBDbG91ZEZyb250IGV2YWx1YXRlcyBiZWhhdmlvcnMgaW4gb3JkZXJcbiAgICogYW5kIHN0b3BzIGF0IHRoZSBmaXJzdCB3aG9zZSBwYXRoIHBhdHRlcm4gbWF0Y2hlcywgYW5kIGBhZGRCZWhhdmlvcmBcbiAgICogYXBwZW5kcyDigJQgc28gYGFwaS8qYCBhZGRlZCBiZWZvcmUgYGFwaS9yZXBvcnRzLypgIHdvdWxkIHN3YWxsb3cgZXZlcnlcbiAgICogcmVwb3J0IHJlcXVlc3QgYW5kIHNlbmQgaXQgdG8gYSBmdW5jdGlvbiB3aG9zZSBwYWNrYWdlIGhhcyBubyByZXBvcnRcbiAgICogZW50cnlwb2ludC4gVGhlIGFkYXB0ZXIgc29ydGVkIHRoZSBsaXN0IHdoZW4gaXQgY2hlY2tlZCBpdCBhZ2FpbnN0IGhvd1xuICAgKiBgYXNzaWduUm91dGVzVG9Hcm91cHNgIHBhY2thZ2VkIHRoZSBzYW1lIHJvdXRlcywgc28gaXQgaXMgYWRkZWQgYXMgaXQgaXMuXG4gICAqL1xuICBwcml2YXRlIGFkZEZ1bmN0aW9uR3JvdXBCZWhhdmlvcnMoKSB7XG4gICAgY29uc3Qgb3JpZ2luUGVyR3JvdXAgPSBuZXcgTWFwPHN0cmluZywgSU9yaWdpbj4oKTtcbiAgICBmb3IgKGNvbnN0IHsgZ3JvdXAsIHBhdGhQYXR0ZXJuIH0gb2YgdGhpcy5mdW5jdGlvbkdyb3VwQmVoYXZpb3JzKCkpIHtcbiAgICAgIGxldCBvcmlnaW4gPSBvcmlnaW5QZXJHcm91cC5nZXQoZ3JvdXAubmFtZSk7XG4gICAgICBpZiAoIW9yaWdpbikge1xuICAgICAgICBvcmlnaW4gPSBGdW5jdGlvblVybE9yaWdpbi53aXRoT3JpZ2luQWNjZXNzQ29udHJvbChcbiAgICAgICAgICBncm91cC5mdW5jdGlvblVybCxcbiAgICAgICAgICB0aGlzLnByb3BzLm92ZXJyaWRlcz8uZHluYW1pY0Z1bmN0aW9uVXJsT3JpZ2luV2l0aE9BQ1Byb3BzLFxuICAgICAgICApO1xuICAgICAgICBvcmlnaW5QZXJHcm91cC5zZXQoZ3JvdXAubmFtZSwgb3JpZ2luKTtcbiAgICAgICAgdGhpcy5ncmFudEludm9rZShncm91cC5uYW1lLCBncm91cC5mdW5jdGlvblVybCk7XG4gICAgICB9XG4gICAgICAvLyBTYW1lIGJlaGF2aW9yIG9wdGlvbnMgYXMgZXZlcnkgb3RoZXIgZHluYW1pYyByb3V0ZSDigJQgb25seSB0aGUgb3JpZ2luXG4gICAgICAvLyBkaWZmZXJzLCBhbmQgaXQgaXMgcGFzc2VkIHNlcGFyYXRlbHkuXG4gICAgICBjb25zdCB7IG9yaWdpbjogX2lnbm9yZWQsIC4uLmJlaGF2aW9yT3B0aW9ucyB9ID1cbiAgICAgICAgdGhpcy5keW5hbWljQmVoYXZpb3JPcHRpb25zO1xuICAgICAgdGhpcy5kaXN0cmlidXRpb24uYWRkQmVoYXZpb3IocGF0aFBhdHRlcm4sIG9yaWdpbiwgYmVoYXZpb3JPcHRpb25zKTtcbiAgICB9XG4gIH1cbiAgLyoqXG4gICAqIGBsYW1iZGE6SW52b2tlRnVuY3Rpb25gIGZvciBDbG91ZEZyb250LCB3aGljaCBhIEZ1bmN0aW9uIFVSTCBiZWhpbmQgT0FDXG4gICAqIG5lZWRzIGJlc2lkZXMgdGhlIGBsYW1iZGE6SW52b2tlRnVuY3Rpb25VcmxgIGBGdW5jdGlvblVybE9yaWdpbmAgZ3JhbnRzLFxuICAgKiBhbmQgc2NvcGVkIHRoZSBzYW1lIHdheTogdG8gdGhpcyBkaXN0cmlidXRpb24sIGFuZCB0byBjYWxscyB0aGF0IGNvbWVcbiAgICogdGhyb3VnaCB0aGUgRnVuY3Rpb24gVVJMLlxuICAgKi9cbiAgcHJpdmF0ZSBncmFudEludm9rZShncm91cDogc3RyaW5nLCBmdW5jdGlvblVybDogSUZ1bmN0aW9uVXJsKSB7XG4gICAgbmV3IENmblBlcm1pc3Npb24odGhpcywgYEludm9rZUZ1bmN0aW9uLSR7Z3JvdXB9YCwge1xuICAgICAgYWN0aW9uOiBcImxhbWJkYTpJbnZva2VGdW5jdGlvblwiLFxuICAgICAgcHJpbmNpcGFsOiBcImNsb3VkZnJvbnQuYW1hem9uYXdzLmNvbVwiLFxuICAgICAgZnVuY3Rpb25OYW1lOiBmdW5jdGlvblVybC5mdW5jdGlvbkFybixcbiAgICAgIHNvdXJjZUFybjogdGhpcy5kaXN0cmlidXRpb24uZGlzdHJpYnV0aW9uQXJuLFxuICAgICAgaW52b2tlZFZpYUZ1bmN0aW9uVXJsOiB0cnVlLFxuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBUaGUgYGFzc2V0UHJlZml4YCBwYXRoIHRoYXQgbmVlZHMgYSBiZWhhdmlvciBvZiBpdHMgb3duLCBvciBgXCJcImAgZm9yIG5vbmUuXG4gICAqXG4gICAqIEFuIGFic29sdXRlIHByZWZpeCBjb250cmlidXRlcyBpdHMgKnBhdGgqOiBcImh0dHBzOi8vY2RuLmV4YW1wbGUuY29tXCIgbmVlZHMgbm9cbiAgICogYmVoYXZpb3IsIGJ1dCBcImh0dHBzOi8vY2RuLmV4YW1wbGUuY29tL2NkblwiIGRvZXMsIGJlY2F1c2UgYG5leHQgYnVpbGRgXG4gICAqIGNvbXBpbGVzIGEgYC9jZG4vX25leHQvOnBhdGgrYCByZXdyaXRlIG9mIGl0cyBvd24gYW5kIGBuZXh0IHN0YXJ0YCBzZXJ2ZXNcbiAgICogZXZlcnkgYnVuZGxlIHVuZGVyIHRoYXQgcGF0aCDigJQgc28gYSBDRE4gZnJvbnRpbmcgdGhpcyBkaXN0cmlidXRpb24gdGhlcmUgaGFzXG4gICAqIHRvIGJlIGFuc3dlcmVkLiBBIHByZWZpeCBlcXVhbCB0byB0aGUgYGJhc2VQYXRoYCBwcmVmaXggaXMgZHJvcHBlZCDigJQgdGhhdCBpc1xuICAgKiB0aGUgTmV4dC5qcyBkZWZhdWx0IHdoZW4gYGJhc2VQYXRoYCBpcyBzZXQsIGFuZCBgX25leHQvc3RhdGljKmAgYWxyZWFkeVxuICAgKiByZXNvbHZlcyB1bmRlciBpdCwgc28gYWRkaW5nIGEgc2Vjb25kIGlkZW50aWNhbCBwYXR0ZXJuIHdvdWxkIG1ha2UgQ2xvdWRGcm9udFxuICAgKiByZWplY3QgdGhlIGRpc3RyaWJ1dGlvbi5cbiAgICovXG4gIHByaXZhdGUgcmVzb2x2ZUFzc2V0UHJlZml4KCk6IHN0cmluZyB7XG4gICAgY29uc3QgcHJlZml4ID0gYXNzZXRQcmVmaXhQYXRoKHRoaXMucHJvcHMuYXNzZXRQcmVmaXggPz8gXCJcIik7XG4gICAgcmV0dXJuIG5vcm1hbGl6ZUJhc2VQYXRoKHByZWZpeCkgPT09IHRoaXMuYmFzZVBhdGggPyBcIlwiIDogcHJlZml4O1xuICB9XG4gIC8qKlxuICAgKiBTZXJ2ZXMgYDxhc3NldFByZWZpeD4vX25leHQvc3RhdGljLypgIGZyb20gdGhlIHNhbWUgUzMgb2JqZWN0cyBhc1xuICAgKiBgX25leHQvc3RhdGljLypgLlxuICAgKlxuICAgKiBOZWVkZWQgYmVjYXVzZSBOZXh0LmpzIHB1dHMgYGFzc2V0UHJlZml4YCBpbiBmcm9udCBvZiBldmVyeSBidW5kbGUgVVJMIGl0XG4gICAqIGVtaXRzIHdoaWxlIHRoZSBvYmplY3RzIGtlZXAgdGhlaXIgYDxiYXNlUGF0aD4vX25leHQvc3RhdGljLy4uLmAga2V5cywgYW5kXG4gICAqIGBhc3NldFByZWZpeGAgc2l0cyBvbiB0b3Agb2YgYGJhc2VQYXRoYCByYXRoZXIgdGhhbiB1bmRlciBpdCwgc29cbiAgICogYGdldFBhdGhQYXR0ZXJuYCBpcyBkZWxpYmVyYXRlbHkgbm90IHVzZWQgaGVyZS4gV2l0aG91dCB0aGlzIGJlaGF2aW9yIHRoZVxuICAgKiByZXF1ZXN0IGZhbGxzIHRocm91Z2ggdG8gdGhlIGRlZmF1bHQgb25lLCByZWFjaGVzIHRoZSBjb21wdXRlIG9yaWdpbiwgYW5kXG4gICAqIDQwNHM6IHRoZSBkZXBsb3ltZW50IHBhY2thZ2UgY2FycmllcyBubyBgLm5leHQvc3RhdGljYCBkaXJlY3RvcnkgYXQgYWxsLlxuICAgKlxuICAgKiBBIHZpZXdlci1yZXF1ZXN0IGZ1bmN0aW9uIGRvZXMgdGhlIHJld3JpdGUgYmVjYXVzZSBhbiBTMyBvcmlnaW4ga2V5cyBvbiB0aGVcbiAgICogcmVxdWVzdCBVUkkgYW5kIGBvcmlnaW5QYXRoYCBjYW4gb25seSBwcmVwZW5kLiBUaGUgcHJlZml4IGlzIGEgc3ludGgtdGltZVxuICAgKiBsaXRlcmFsLCBzbyB0aGUgZnVuY3Rpb24gaXMgYSBmaXhlZC1sZW5ndGggc3RyaW5nIG9wZXJhdGlvbiByYXRoZXIgdGhhbiBhXG4gICAqIHBhcnNlLlxuICAgKi9cbiAgcHJpdmF0ZSBhZGRBc3NldFByZWZpeEJlaGF2aW9yKCkge1xuICAgIC8vIENsb3VkRnJvbnQgYWxsb3dzIG9uZSBmdW5jdGlvbiBwZXIgZXZlbnQgdHlwZSBwZXIgYmVoYXZpb3IsIHNvIGFuIG92ZXJyaWRlXG4gICAgLy8gdGhhdCBhbHJlYWR5IGNsYWltcyBWSUVXRVJfUkVRVUVTVCBvbiB0aGUgc3RhdGljIGJlaGF2aW9yIGNhbm5vdCBjb2V4aXN0XG4gICAgLy8gd2l0aCB0aGUgcmV3cml0ZSBiZWxvdyDigJQgdGhlIGRpc3RyaWJ1dGlvbiB3b3VsZCBzeW50aCBhbmQgdGhlbiBiZSByZWplY3RlZFxuICAgIC8vIGF0IGRlcGxveSwgbmFtaW5nIG5laXRoZXIuIFRocm93biBoZXJlIGluc3RlYWQsIHdoZXJlIGJvdGggaGFsdmVzIGFyZVxuICAgIC8vIGtub3duLlxuICAgIGNvbnN0IGNsYWltZWQgPSAoXG4gICAgICB0aGlzLnN0YXRpY0JlaGF2aW9yT3B0aW9ucy5mdW5jdGlvbkFzc29jaWF0aW9ucyA/PyBbXVxuICAgICkuc29tZShcbiAgICAgIChhc3NvY2lhdGlvbikgPT5cbiAgICAgICAgYXNzb2NpYXRpb24uZXZlbnRUeXBlID09PSBGdW5jdGlvbkV2ZW50VHlwZS5WSUVXRVJfUkVRVUVTVCxcbiAgICApO1xuICAgIGlmIChjbGFpbWVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke0xPR19QUkVGSVh9IFxcYG92ZXJyaWRlcy5zdGF0aWNCZWhhdmlvck9wdGlvbnMuZnVuY3Rpb25Bc3NvY2lhdGlvbnNcXGAgYCArXG4gICAgICAgICAgYGFscmVhZHkgYXNzb2NpYXRlcyBhIENsb3VkRnJvbnQgZnVuY3Rpb24gd2l0aCBgICtcbiAgICAgICAgICBgJHtGdW5jdGlvbkV2ZW50VHlwZS5WSUVXRVJfUkVRVUVTVH0sIGJ1dCBzZXJ2aW5nIFxcYGFzc2V0UHJlZml4XFxgIGAgK1xuICAgICAgICAgIGAoXCIke3RoaXMuYXNzZXRQcmVmaXh9XCIpIG5lZWRzIHRoYXQgZXZlbnQgdHlwZSB0byByZXdyaXRlIHRoZSByZXF1ZXN0IGAgK1xuICAgICAgICAgIGBVUkkgdG8gdGhlIG9iamVjdCdzIGtleSwgYW5kIENsb3VkRnJvbnQgcGVybWl0cyBvbmx5IG9uZSBmdW5jdGlvbiBwZXIgYCArXG4gICAgICAgICAgYGV2ZW50IHR5cGUgcGVyIGJlaGF2aW9yLiBFaXRoZXIgZHJvcCB0aGUgb3ZlcnJpZGUsIG9yIGZvbGQgaXRzIGxvZ2ljIGAgK1xuICAgICAgICAgIGBpbnRvIGEgc2luZ2xlIGZ1bmN0aW9uIGFuZCBzZXQgXFxgYXNzZXRQcmVmaXhcXGAgdG8gXCJcIiBzbyB0aGlzIGAgK1xuICAgICAgICAgIGBjb25zdHJ1Y3QgYWRkcyBubyBiZWhhdmlvciBvZiBpdHMgb3duLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCByZXdyaXRlID0gbmV3IENsb3VkRnJvbnRGdW5jdGlvbih0aGlzLCBcIkFzc2V0UHJlZml4Rm5cIiwge1xuICAgICAgY29tbWVudDogdGhpcy5nZXRDb21tZW50KFxuICAgICAgICBcIk5leHRKUyBhc3NldFByZWZpeCByZXdyaXRlXCIsXG4gICAgICAgIFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgICksXG4gICAgICBjb2RlOiBGdW5jdGlvbkNvZGUuZnJvbUlubGluZShgXG4gICAgICAgIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQpIHtcbiAgICAgICAgICB2YXIgcmVxdWVzdCA9IGV2ZW50LnJlcXVlc3Q7XG4gICAgICAgICAgcmVxdWVzdC51cmkgPSAke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgdGhpcy5iYXNlUGF0aCA/IGAvJHt0aGlzLmJhc2VQYXRofWAgOiBcIlwiLFxuICAgICAgICAgICl9ICsgcmVxdWVzdC51cmkuc2xpY2UoJHt0aGlzLmFzc2V0UHJlZml4Lmxlbmd0aH0pO1xuICAgICAgICAgIHJldHVybiByZXF1ZXN0O1xuICAgICAgICB9XG4gICAgICAgIGApLFxuICAgIH0pO1xuICAgIHRoaXMuZGlzdHJpYnV0aW9uLmFkZEJlaGF2aW9yKFxuICAgICAgYCR7dGhpcy5hc3NldFByZWZpeH0vX25leHQvc3RhdGljKmAsXG4gICAgICB0aGlzLnN0YXRpY09yaWdpbixcbiAgICAgIHtcbiAgICAgICAgLi4udGhpcy5zdGF0aWNCZWhhdmlvck9wdGlvbnMsXG4gICAgICAgIGZ1bmN0aW9uQXNzb2NpYXRpb25zOiBbXG4gICAgICAgICAgLi4uKHRoaXMuc3RhdGljQmVoYXZpb3JPcHRpb25zLmZ1bmN0aW9uQXNzb2NpYXRpb25zID8/IFtdKSxcbiAgICAgICAgICB7IGV2ZW50VHlwZTogRnVuY3Rpb25FdmVudFR5cGUuVklFV0VSX1JFUVVFU1QsIGZ1bmN0aW9uOiByZXdyaXRlIH0sXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgICk7XG4gIH1cbiAgcHJpdmF0ZSBhZGRTdGF0aWNCZWhhdmlvcnMoKSB7XG4gICAgdGhpcy5kaXN0cmlidXRpb24uYWRkQmVoYXZpb3IoXG4gICAgICB0aGlzLmdldFBhdGhQYXR0ZXJuKFwiX25leHQvc3RhdGljKlwiKSxcbiAgICAgIHRoaXMuc3RhdGljT3JpZ2luLFxuICAgICAgdGhpcy5zdGF0aWNCZWhhdmlvck9wdGlvbnMsXG4gICAgKTtcbiAgICBpZiAodGhpcy5hc3NldFByZWZpeCkge1xuICAgICAgdGhpcy5hZGRBc3NldFByZWZpeEJlaGF2aW9yKCk7XG4gICAgfVxuICAgIGNvbnN0IHB1YmxpY1BhdGhQYXR0ZXJucyA9IHRoaXMucHVibGljUGF0aFBhdHRlcm5zKCk7XG4gICAgdGhpcy5hc3NlcnRCZWhhdmlvckJ1ZGdldChwdWJsaWNQYXRoUGF0dGVybnMubGVuZ3RoKTtcbiAgICB0aGlzLmFzc2VydE5vUHVibGljQ29sbGlzaW9ucyhwdWJsaWNQYXRoUGF0dGVybnMpO1xuICAgIGZvciAoY29uc3QgcGF0aFBhdHRlcm4gb2YgcHVibGljUGF0aFBhdHRlcm5zKSB7XG4gICAgICB0aGlzLmRpc3RyaWJ1dGlvbi5hZGRCZWhhdmlvcihcbiAgICAgICAgcGF0aFBhdHRlcm4sXG4gICAgICAgIHRoaXMuc3RhdGljT3JpZ2luLFxuICAgICAgICB0aGlzLnN0YXRpY0JlaGF2aW9yT3B0aW9ucyxcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBUaGUgYmVoYXZpb3IgcGF0aCBwYXR0ZXJuIGZvciBlYWNoIHRvcC1sZXZlbCBgcHVibGljL2AgZW50cnksIGZpbmFsIGZvcm06XG4gICAqIGAvKmAgZm9yIGEgZGlyZWN0b3J5IGFuZCB0aGUgYmFzZVBhdGggcHJlZml4IGJvdGggYXBwbGllZC5cbiAgICpcbiAgICogQW4gZW50cnkgd2hvc2UgbmFtZSBoYXMgbm8gY2hhcmFjdGVyIENsb3VkRnJvbnQgY2FuIHNwZWxsIGlzIGxlZnQgb3V0LCB3aXRoXG4gICAqIGEgd2FybmluZywgcmF0aGVyIHRoYW4gZ2l2ZW4gYSBwYXR0ZXJuIG9mIG5vdGhpbmcgYnV0IHdpbGRjYXJkcy4gYNGE0L7RgtC+L2AgaXNcbiAgICogYD8/Pz8/Pz8/LypgIOKAlCBhbnkgOC1ieXRlIGZpcnN0IHNlZ21lbnQg4oCUIGFuZCBwdWJsaWMvIGJlaGF2aW9ycyBhcmUgYWRkZWRcbiAgICogYWhlYWQgb2YgZXZlcnkgY29tcHV0ZSBiZWhhdmlvciwgc28gaXQgd291bGQgc2VuZCBgL3Byb2R1Y3RzLzQyYCBhbmRcbiAgICogYC9zZXR0aW5ncy8qYCB0byBTMywgd2hpY2ggYW5zd2VycyA0MDMuIExlYXZpbmcgdGhlIGVudHJ5IG91dCBjb3N0cyBpdHMgb3duXG4gICAqIGZpbGVzIGluc3RlYWQ6IHRob3NlIHJlcXVlc3RzIHJlYWNoIHRoZSBjb21wdXRlLCB3aGljaCBkb2VzIG5vdCBoYXZlIHRoZW0sXG4gICAqIGFuZCA0MDQuIE9uZSBsaXRlcmFsIGNoYXJhY3RlciBpcyBlbm91Z2ggdG8ga2VlcCBhIHBhdHRlcm4gbmFycm93IOKAlFxuICAgKiBgPz8/Pz8/Pz8uanBnYCBvbmx5IG1hdGNoZXMgYC5qcGdgIHJlcXVlc3RzIOKAlCBzbyBvbmx5IHRoZSBhbGwtd2lsZGNhcmQgb25lc1xuICAgKiBnby5cbiAgICpcbiAgICogVGhlIGxlbmd0aCBsaW1pdCBpcyBjaGVja2VkIGhlcmUsIG9uIHRoZSBmaW5hbCBwYXR0ZXJuLCByYXRoZXIgdGhhbiBpblxuICAgKiB7QGxpbmsgdG9QYXRoUGF0dGVybn06IHRoZSBgLypgIGFuZCB0aGUgYmFzZVBhdGggY291bnQgYWdhaW5zdCBpdCB0b28sIGFuZCBhXG4gICAqIHBhdHRlcm4gdGhhdCBwYXNzZWQgd2l0aG91dCB0aGVtIGZhaWxlZCBhdCBkZXBsb3kgaW5zdGVhZC5cbiAgICovXG4gIHByaXZhdGUgcHVibGljUGF0aFBhdHRlcm5zKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBwYXR0ZXJuczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCB1bm1hdGNoYWJsZTogc3RyaW5nW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHB1YmxpY0ZpbGUgb2YgdGhpcy5wcm9wcy5wdWJsaWNEaXJFbnRyaWVzKSB7XG4gICAgICBjb25zdCBuYW1lID0gdG9QYXRoUGF0dGVybihwdWJsaWNGaWxlLm5hbWUpO1xuICAgICAgaWYgKCEvW14/Ki9dLy50ZXN0KG5hbWUpKSB7XG4gICAgICAgIHVubWF0Y2hhYmxlLnB1c2goYFwiJHtwdWJsaWNGaWxlLm5hbWV9XCJgKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBwYXRoUGF0dGVybiA9IHRoaXMuZ2V0UGF0aFBhdHRlcm4oXG4gICAgICAgIHB1YmxpY0ZpbGUuaXNEaXJlY3RvcnkgPyBgJHtuYW1lfS8qYCA6IG5hbWUsXG4gICAgICApO1xuICAgICAgaWYgKHBhdGhQYXR0ZXJuLmxlbmd0aCA+IE1BWF9QQVRIX1BBVFRFUk5fTEVOR1RIKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgVGhlIHB1YmxpYy8gZW50cnkgXCIke3B1YmxpY0ZpbGUubmFtZX1cIiBuZWVkcyBhIGAgK1xuICAgICAgICAgICAgYCR7cGF0aFBhdHRlcm4ubGVuZ3RofS1jaGFyYWN0ZXIgQ2xvdWRGcm9udCBwYXRoIHBhdHRlcm4sIG92ZXIgYCArXG4gICAgICAgICAgICBgdGhlICR7TUFYX1BBVEhfUEFUVEVSTl9MRU5HVEh9LWNoYXJhY3RlciBgICtcbiAgICAgICAgICAgIFwibGltaXQuIFJlbmFtZSBpdCwgb3IgbW92ZSBpdCBpbnRvIGEgc3ViZGlyZWN0b3J5IG9mIHB1YmxpYy8gd2hvc2UgXCIgK1xuICAgICAgICAgICAgXCJvd24gbmFtZSBpcyBzaG9ydCBlbm91Z2guIFNlZSBcIiArXG4gICAgICAgICAgICBcImh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZEZyb250L2xhdGVzdC9EZXZlbG9wZXJHdWlkZS9Eb3dubG9hZERpc3RWYWx1ZXNDYWNoZUJlaGF2aW9yLmh0bWwjRG93bmxvYWREaXN0VmFsdWVzUGF0aFBhdHRlcm5cIixcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHBhdHRlcm5zLnB1c2gocGF0aFBhdHRlcm4pO1xuICAgIH1cbiAgICBpZiAodW5tYXRjaGFibGUubGVuZ3RoID4gMCkge1xuICAgICAgQW5ub3RhdGlvbnMub2YodGhpcykuYWRkV2FybmluZyhcbiAgICAgICAgYCR7TE9HX1BSRUZJWH0gVGhlc2UgdG9wLWxldmVsIHB1YmxpYy8gZW50cmllcyBoYXZlIG5vIGNoYXJhY3RlciBhIGAgK1xuICAgICAgICAgIFwiQ2xvdWRGcm9udCBwYXRoIHBhdHRlcm4gY2FuIHNwZWxsLCBzbyB0aGVpciBwYXR0ZXJuIHdvdWxkIGJlIFwiICtcbiAgICAgICAgICBcIndpbGRjYXJkcyBhbG9uZSBhbmQgd291bGQgY2FwdHVyZSBldmVyeSBhcHAgcm91dGUgb2YgdGhlIHNhbWUgXCIgK1xuICAgICAgICAgIGBsZW5ndGguIFRoZXkgZ2V0IG5vIGJlaGF2aW9yLCBzbyB0aGVpciByZXF1ZXN0cyByZWFjaCB0aGUgc2VydmVyLCBgICtcbiAgICAgICAgICBgd2hpY2ggcmVhZHMgdGhlbSBmcm9tIFMzIGluc3RlYWQ6ICR7dW5tYXRjaGFibGUuam9pbihcIiwgXCIpfS4gVG8gc2VydmUgYCArXG4gICAgICAgICAgXCJ0aGVtIGZyb20gUzMgZGlyZWN0bHksIHJlbmFtZSB0aGVtLCBvciBtb3ZlIHRoZW0gaW50byBhIHB1YmxpYy8gXCIgK1xuICAgICAgICAgIFwic3ViZGlyZWN0b3J5IHdob3NlIG5hbWUgaGFzIGF0IGxlYXN0IG9uZSBBU0NJSSBsZXR0ZXIgb3IgZGlnaXQuXCIsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gcGF0dGVybnM7XG4gIH1cbiAgLyoqXG4gICAqIFJlZnVzZSBhIGdyb3VwIGJlaGF2aW9yIHRoYXQgYSBgcHVibGljL2AgYmVoYXZpb3Igd291bGQgbWFrZSB1bnJlYWNoYWJsZS5cbiAgICpcbiAgICogYHB1YmxpYy9gIGJlaGF2aW9ycyBhcmUgYWRkZWQgZmlyc3QsIGFuZCBDbG91ZEZyb250IHN0b3BzIGF0IHRoZSBmaXJzdCBtYXRjaCxcbiAgICogc28gdHdvIGNhc2VzIHNlbmQgYSBncm91cCdzIHJvdXRlIHRvIFMzIGluc3RlYWQgb2YgaXRzIGZ1bmN0aW9uIOKAlCB3aGljaCBpc1xuICAgKiB3aHkgdGhpcyBpcyBjaGVja2VkIGF0IHN5bnRoLCB3aGVyZSBib3RoIHNpZGVzIGFyZSBrbm93bjpcbiAgICogLSB0aGUgc2FtZSBwYXR0ZXJuIHR3aWNlOiBgcHVibGljL2RvY3MvYCBhbmQgYC9kb2NzLyoqYCBib3RoIGRlcGxveSBhc1xuICAgKiAgIGBkb2NzLypgLiBUaGUgc3ludGggc3VjY2VlZGVkIGFuZCBDbG91ZEZyb250IHJlamVjdGVkIHRoZSBkZXBsb3kuXG4gICAqIC0gYSBncm91cCBwYXR0ZXJuIHVuZGVyIGEgcHVibGljIGRpcmVjdG9yeTogYC9kb2NzL2d1aWRlLyoqYCBiZWhpbmRcbiAgICogICBgZG9jcy8qYCBkZXBsb3lzIGFuZCBuZXZlciBtYXRjaGVzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3NlcnROb1B1YmxpY0NvbGxpc2lvbnMocHVibGljUGF0aFBhdHRlcm5zOiBzdHJpbmdbXSkge1xuICAgIGNvbnN0IHB1YmxpY1JlZ2V4ZXMgPSBwdWJsaWNQYXRoUGF0dGVybnMubWFwKChwYXR0ZXJuKSA9PiAoe1xuICAgICAgcGF0dGVybixcbiAgICAgIHJlZ2V4OiBjbG91ZEZyb250UGF0dGVyblJlZ2V4KGAvJHtwYXR0ZXJuLnJlcGxhY2UoL15cXC8rLywgXCJcIil9YCksXG4gICAgfSkpO1xuICAgIGZvciAoY29uc3QgeyBncm91cCwgcm91dGUsIHBhdGhQYXR0ZXJuIH0gb2YgdGhpcy5mdW5jdGlvbkdyb3VwQmVoYXZpb3JzKCkpIHtcbiAgICAgIGNvbnN0IGR1cGxpY2F0ZSA9IHB1YmxpY1BhdGhQYXR0ZXJucy5pbmNsdWRlcyhwYXRoUGF0dGVybik7XG4gICAgICAvLyBNYXRjaGluZyB0aGUgZ3JvdXAgcGF0dGVybidzIG93biB0ZXh0IGlzIGVub3VnaDogaXRzIG9ubHkgd2lsZGNhcmQgaXMgYVxuICAgICAgLy8gdHJhaWxpbmcgYCpgLCBzbyBhIHB1YmxpYyBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyB0aGUgdGV4dCB1cCB0byBhbmRcbiAgICAgIC8vIGluY2x1ZGluZyBpdCBtYXRjaGVzIGV2ZXJ5IFVSTCB0aGUgZ3JvdXAgcGF0dGVybiBkb2VzLlxuICAgICAgY29uc3Qgc2hhZG93ID0gZHVwbGljYXRlXG4gICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgIDogcHVibGljUmVnZXhlcy5maW5kKCh7IHJlZ2V4IH0pID0+XG4gICAgICAgICAgICByZWdleC50ZXN0KGAvJHtwYXRoUGF0dGVybi5yZXBsYWNlKC9eXFwvKy8sIFwiXCIpfWApLFxuICAgICAgICAgICk7XG4gICAgICBpZiAoIWR1cGxpY2F0ZSAmJiAhc2hhZG93KSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSBcXGBmdW5jdGlvbkdyb3Vwc1xcYCBwYXR0ZXJuIFwiJHtyb3V0ZX1cIiAoZ3JvdXAgYCArXG4gICAgICAgICAgYFwiJHtncm91cC5uYW1lfVwiKSBgICtcbiAgICAgICAgICAoZHVwbGljYXRlXG4gICAgICAgICAgICA/IGBkZXBsb3lzIGFzIHRoZSBwYXRoIHBhdHRlcm4gXCIke3BhdGhQYXR0ZXJufVwiLCB3aGljaCBhIHRvcC1sZXZlbCBgICtcbiAgICAgICAgICAgICAgYHB1YmxpYy8gZW50cnkgYWxyZWFkeSB1c2VzIOKAlCBDbG91ZEZyb250IHJlamVjdHMgYSBkaXN0cmlidXRpb24gYCArXG4gICAgICAgICAgICAgIGB3aXRoIHR3byBiZWhhdmlvcnMgb24gb25lIHBhdGggcGF0dGVybi4gYFxuICAgICAgICAgICAgOiBgZGVwbG95cyBhcyBcIiR7cGF0aFBhdHRlcm59XCIsIGJ1dCB0aGUgdG9wLWxldmVsIHB1YmxpYy8gZW50cnkgYCArXG4gICAgICAgICAgICAgIGBiZWhpbmQgXCIke3NoYWRvdyEucGF0dGVybn1cIiBpcyBtYXRjaGVkIGZpcnN0IGFuZCBzZW5kcyBldmVyeSBgICtcbiAgICAgICAgICAgICAgYHN1Y2ggcmVxdWVzdCB0byBTMywgc28gdGhlIGdyb3VwJ3MgZnVuY3Rpb24gd291bGQgbmV2ZXIgc2VlIGAgK1xuICAgICAgICAgICAgICBgdGhlbS4gYCkgK1xuICAgICAgICAgIGBNb3ZlIHRob3NlIHB1YmxpYy8gZmlsZXMgdW5kZXIgYSBkaXJlY3Rvcnkgbm8gcm91dGUgdXNlcywgb3IgYCArXG4gICAgICAgICAgYGdyb3VwIGEgZGlmZmVyZW50IHBhdGguYCxcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBDbG91ZEZyb250IGhhcyBhIHBlci1kaXN0cmlidXRpb24gY2FjaGUgYmVoYXZpb3IgcXVvdGEsIGNvdW50aW5nIHRoZSBkZWZhdWx0XG4gICAqIG9uZSDigJQgNzUgdW5sZXNzIHJhaXNlZCwgYW5kIGBtYXhDYWNoZUJlaGF2aW9yc2Agc2F5cyB3aGljaCDigJQgYW5kIHRoZXJlIGFyZVxuICAgKiB0aHJlZSB0aGluZ3MgY29tcGV0aW5nIGZvciBpdDogYHB1YmxpYy9gIGVudHJpZXMsIGZ1bmN0aW9uIGdyb3VwcywgYW5kXG4gICAqIGNkay1uZXh0anMncyBvd24gZml4ZWQgc2V0LlxuICAgKiBDaGVja2VkIGluIG9uZSBwbGFjZSBzbyB0aGUgZXJyb3IgY2FuIHNheSB3aGljaCB0byBjdXQuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkRnJvbnQvbGF0ZXN0L0RldmVsb3Blckd1aWRlL2Nsb3VkZnJvbnQtbGltaXRzLmh0bWwjbGltaXRzLXdlYi1kaXN0cmlidXRpb25zXG4gICAqL1xuICBwcml2YXRlIGFzc2VydEJlaGF2aW9yQnVkZ2V0KHB1YmxpY1BhdHRlcm5zOiBudW1iZXIpIHtcbiAgICBjb25zdCBsaW1pdCA9IHRoaXMucHJvcHMubWF4Q2FjaGVCZWhhdmlvcnMgPz8gREVGQVVMVF9NQVhfQ0FDSEVfQkVIQVZJT1JTO1xuICAgIGlmIChUb2tlbi5pc1VucmVzb2x2ZWQobGltaXQpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGdyb3VwUGF0dGVybnMgPSB0aGlzLmZ1bmN0aW9uR3JvdXBCZWhhdmlvcnMoKS5sZW5ndGg7XG4gICAgLy8gVGhlIGRlZmF1bHQgYmVoYXZpb3IsIGBfbmV4dC9pbWFnZSpgLCBgX25leHQvc3RhdGljKmAsIHBsdXMg4oCUIHdpdGggYVxuICAgIC8vIGJhc2VQYXRoIOKAlCB0aGUgdHdvIHRoYXQgc3RhbmQgaW4gZm9yIHRoZSBkZWZhdWx0IGJlaGF2aW9yJ3MgY292ZXJhZ2UsIGFuZFxuICAgIC8vIOKAlCB3aXRoIGEgcGF0aC1zdHlsZSBhc3NldFByZWZpeCDigJQgdGhlIG9uZSB0aGF0IHNlcnZlcyBidW5kbGVzIHVuZGVyIGl0LlxuICAgIC8vIGB0aGlzLmJhc2VQYXRoYCwgbm90IHRoZSByYXcgcHJvcDogYGJhc2VQYXRoOiBcIi9cImAgbm9ybWFsaXplcyB0byBgXCJcImAgYW5kXG4gICAgLy8gYWRkcyBubyBiZWhhdmlvcnMsIHNvIGNvdW50aW5nIGl0IGFkZGVkIDIgdG8gdGhlIHRvdGFsIGFuZCBjb3VsZCB0aHJvd1xuICAgIC8vIFwib3ZlciB0aGUgbGltaXRcIiBvbiBhbiBhcHAgdGhhdCBpcyB1bmRlciBpdC5cbiAgICBjb25zdCBmaXhlZCA9IDMgKyAodGhpcy5iYXNlUGF0aCA/IDIgOiAwKSArICh0aGlzLmFzc2V0UHJlZml4ID8gMSA6IDApO1xuICAgIGNvbnN0IHRvdGFsID0gZml4ZWQgKyBwdWJsaWNQYXR0ZXJucyArIGdyb3VwUGF0dGVybnM7XG4gICAgaWYgKHRvdGFsIDw9IGxpbWl0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHBhcnRzID0gW1xuICAgICAgYCR7Zml4ZWR9IHVzZWQgYnkgY2RrLW5leHRqcyBpdHNlbGZgLFxuICAgICAgYCR7cHVibGljUGF0dGVybnN9IGZvciB0b3AtbGV2ZWwgcHVibGljLyBlbnRyaWVzYCxcbiAgICBdO1xuICAgIGlmIChncm91cFBhdHRlcm5zKSB7XG4gICAgICBwYXJ0cy5wdXNoKGAke2dyb3VwUGF0dGVybnN9IGZvciBcXGBmdW5jdGlvbkdyb3Vwc1xcYCBwYXR0ZXJuc2ApO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgVGhpcyBOZXh0LmpzIGFwcCBuZWVkcyAke3RvdGFsfSBDbG91ZEZyb250IGNhY2hlIGJlaGF2aW9ycywgb3ZlciB0aGUgYCArXG4gICAgICAgIGBsaW1pdCBvZiAke2xpbWl0fSBwZXIgZGlzdHJpYnV0aW9uOiAke3BhcnRzLmpvaW4oXCIsIFwiKX0uIGAgK1xuICAgICAgICBgTW92ZSBwdWJsaWMvIGZpbGVzIGludG8gYSBzaW5nbGUgdG9wLWxldmVsIGRpcmVjdG9yeSAob25lIGJlaGF2aW9yIGAgK1xuICAgICAgICBgc2VydmVzIFxcYHN0YXRpYy8qXFxgKWAgK1xuICAgICAgICAoZ3JvdXBQYXR0ZXJuc1xuICAgICAgICAgID8gYCwgYW5kIHByZWZlciBvbmUgc3VidHJlZSBwYXR0ZXJuIHBlciBmdW5jdGlvbiBncm91cCBvdmVyIHNldmVyYWwgYCArXG4gICAgICAgICAgICBgZXhhY3QgcGF0aHNgXG4gICAgICAgICAgOiBgYCkgK1xuICAgICAgICBgLiBJZiB5b3VyIGFjY291bnQncyBxdW90YSBpcyBoaWdoZXIgdGhhbiAke2xpbWl0fSwgc2V0IGAgK1xuICAgICAgICBgXFxgbWF4Q2FjaGVCZWhhdmlvcnNcXGAgdG8gaXQuIFNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvY2xvdWRmcm9udC1saW1pdHMuaHRtbCNsaW1pdHMtd2ViLWRpc3RyaWJ1dGlvbnNgLFxuICAgICk7XG4gIH1cbiAgLyoqXG4gICAqIE9wdGlvbmFsbHkgcHJlcGVuZHMgYmFzZSBwYXRoIHRvIGdpdmVuIHBhdGggcGF0dGVybi5cbiAgICpcbiAgICogQSB0cmFpbGluZyBzbGFzaCBvbiBgcGF0aFBhdHRlcm5gIGlzIGxvYWQtYmVhcmluZyBhbmQgc3Vydml2ZXMsIHdoaWNoIGlzIHdoeVxuICAgKiB0aGlzIGNvbmNhdGVuYXRlcyByYXRoZXIgdGhhbiBnb2luZyB0aHJvdWdoIGBqb2luUGF0aGAuIFRoZSBidWlsZCdzXG4gICAqIGBmdW5jdGlvbkdyb3VwQmVoYXZpb3JzYCBob2xkIGJvdGggXCJwcmljaW5nXCIgYW5kIFwicHJpY2luZy9cIiBmb3IgYVxuICAgKiBgdHJhaWxpbmdTbGFzaGAgYXBwLCBhbmQgbm9ybWFsaXppbmcgdGhlIHNlY29uZCBvbmUgY29sbGFwc2VkIGl0IG9udG8gdGhlXG4gICAqIGZpcnN0OiBgYWRkQmVoYXZpb3JgIHdhc1xuICAgKiB0aGVuIGNhbGxlZCB0d2ljZSB3aXRoIGAvYmFzZS9wcmljaW5nYCwgd2hpY2ggQ2xvdWRGcm9udCByZWplY3RzIGF0IGRlcGxveVxuICAgKiAoXCJtb3JlIHRoYW4gb25lIGNhY2hlIGJlaGF2aW9yIGhhcyB0aGUgc2FtZSBwYXRoIHBhdHRlcm5cIiksIGFuZCB0aGVcbiAgICogY2Fub25pY2FsIGAvYmFzZS9wcmljaW5nL2Agd2FzIGxlZnQgdG8gdGhlIGAvYmFzZS8qYCBjYXRjaC1hbGwg4oCUIHRoZSBtaXNyb3V0ZVxuICAgKiB0aGUgc2Vjb25kIHBhdHRlcm4gZXhpc3RzIHRvIHByZXZlbnQuXG4gICAqL1xuICBwcml2YXRlIGdldFBhdGhQYXR0ZXJuKHBhdGhQYXR0ZXJuOiBzdHJpbmcpIHtcbiAgICBpZiAoIXRoaXMuYmFzZVBhdGgpIHtcbiAgICAgIHJldHVybiBwYXRoUGF0dGVybjtcbiAgICB9XG4gICAgcmV0dXJuIGAvJHt0aGlzLmJhc2VQYXRofS8ke3BhdGhQYXR0ZXJuLnJlcGxhY2UoL15cXC8rLywgXCJcIil9YDtcbiAgfVxufVxuXG4vKipcbiAqIFdoZXRoZXIgYGR5bmFtaWNDYWNoZVBvbGljeVByb3BzYCB0dXJucyB0aGUgZHluYW1pYyBjYWNoZSBvZmYsIGJ5IGNhcHBpbmcgZXZlcnlcbiAqIFRUTCBhdCAwLlxuICpcbiAqIENsb3VkRnJvbnQgcmVqZWN0cyBhIHBvbGljeSB0aGF0IGNhY2hlcyBub3RoaW5nIGJ1dCBzdGlsbCBoYXMgYSBjYWNoZSBrZXlcbiAqIChcIkhlYWRlckJlaGF2aW9yIGlzIGludmFsaWQgZm9yIHBvbGljeSB3aXRoIGNhY2hpbmcgZGlzYWJsZWRcIiksIHNvIHN1Y2ggYVxuICogcG9saWN5IGhhcyB0byBkcm9wIHRoZSBrZXkuIFVudGlsIHRoZSBkZWZhdWx0IFRUTCBiZWNhbWUgMCB0aGlzIGNvdWxkIG5vdFxuICogY29tZSB1cDogQ0RLIHJhaXNlcyBgbWF4VHRsYCB0byBgZGVmYXVsdFR0bGAgd2hlbiBpdCBpcyBsb3dlciwgc28gYW4gb3ZlcnJpZGVcbiAqIG9mIGBtYXhUdGw6IDBgIHN5bnRoZXNpemVkIGFzIGEgZGF5IGFuZCBkZXBsb3llZC4gTm93IGl0IGlzIGhvbm9yZWQsIGFuZFxuICogd2l0aG91dCB0aGlzIHRoZSB1cGdyYWRlIGRlcGxveSB3b3VsZCBmYWlsLlxuICpcbiAqIFRoZSBUVExzIGFyZSByZXNvbHZlZCB0aGUgd2F5IENESyByZXNvbHZlcyB0aGVtOiBgZGVmYXVsdFR0bGAgcmFpc2VkIHRvXG4gKiBgbWluVHRsYCwgdGhlbiBgbWF4VHRsYCByYWlzZWQgdG8gYGRlZmF1bHRUdGxgLiBDaGVja2luZyBgbWF4VHRsYCBhbG9uZSBjYWxsZWRcbiAqIGB7IG1heFR0bDogMCwgZGVmYXVsdFR0bDogMWggfWAgZGlzYWJsZWQsIGRyb3BwZWQgdGhlIGtleSwgYW5kIENESyB0aGVuXG4gKiBzeW50aGVzaXplZCBhIHBvbGljeSB0aGF0IGNhY2hlcyBmb3IgYW4gaG91ciBrZXllZCBvbiBub3RoaW5nIOKAlCBvbmUgdmlld2VyJ3NcbiAqIHBhZ2Ugc2VydmVkIHRvIGV2ZXJ5IHZpZXdlci5cbiAqL1xuZnVuY3Rpb24gaXNDYWNoaW5nRGlzYWJsZWQocHJvcHM6IENhY2hlUG9saWN5UHJvcHMgfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgY29uc3QgdHRscyA9IFtwcm9wcz8ubWF4VHRsLCBwcm9wcz8uZGVmYXVsdFR0bCwgcHJvcHM/Lm1pblR0bF07XG4gIGlmIChwcm9wcz8ubWF4VHRsID09PSB1bmRlZmluZWQpIHJldHVybiBmYWxzZTsgLy8gQ0RLJ3MgZGVmYXVsdCBpcyBhIHllYXJcbiAgcmV0dXJuIHR0bHMuZXZlcnkoXG4gICAgKHR0bCkgPT5cbiAgICAgIHR0bCA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICAoIVRva2VuLmlzVW5yZXNvbHZlZCh0dGwudG9TdHJpbmcoKSkgJiYgdHRsLnRvU2Vjb25kcygpID09PSAwKSxcbiAgKTtcbn1cblxuLyoqIFRoZSBjYWNoZS1rZXkgaGFsZiBvZiB7QGxpbmsgQ2FjaGVQb2xpY3lQcm9wc30uICovXG5pbnRlcmZhY2UgQ2FjaGVLZXlQcm9wcyB7XG4gIHJlYWRvbmx5IHF1ZXJ5U3RyaW5nQmVoYXZpb3I6IENhY2hlUXVlcnlTdHJpbmdCZWhhdmlvcjtcbiAgcmVhZG9ubHkgaGVhZGVyQmVoYXZpb3I6IENhY2hlSGVhZGVyQmVoYXZpb3I7XG4gIHJlYWRvbmx5IGNvb2tpZUJlaGF2aW9yOiBDYWNoZUNvb2tpZUJlaGF2aW9yO1xuICByZWFkb25seSBlbmFibGVBY2NlcHRFbmNvZGluZ0Jyb3RsaTogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZW5hYmxlQWNjZXB0RW5jb2RpbmdHemlwOiBib29sZWFuO1xufVxuXG4vKipcbiAqIFdoYXQgdGhlIGR5bmFtaWMgY2FjaGUgcG9saWN5IGtleXMgb246IGV2ZXJ5IHJlcXVlc3QgaW5wdXQgYSBOZXh0LmpzIHJlc3BvbnNlXG4gKiB2YXJpZXMgYnkuXG4gKi9cbmNvbnN0IERZTkFNSUNfQ0FDSEVfS0VZOiBDYWNoZUtleVByb3BzID0ge1xuICBxdWVyeVN0cmluZ0JlaGF2aW9yOiBDYWNoZVF1ZXJ5U3RyaW5nQmVoYXZpb3IuYWxsKCksXG4gIGhlYWRlckJlaGF2aW9yOiBDYWNoZUhlYWRlckJlaGF2aW9yLmFsbG93TGlzdChcbiAgICAvLyBOT1RFOiBDbG91ZEZyb250IEN1c3RvbSBDYWNoZSBQb2xpY2llcyBoYXZlIHNvZnQgbWF4IG9mIDEwIGhlYWRlcnNcbiAgICAvLyBjZGstbmV4dGpzIGluY2x1ZGVzIHRoZSBtb3N0IGVzc2VudGlhbCBoZWFkZXJzIGZvciBOZXh0LmpzIGZ1bmN0aW9uYWxpdHlcbiAgICAvLyBidXQgaXQncyByZWNvbW1lbmRlZCB0byByZXF1ZXN0IHF1b3RhIGluY3JlYXNlIHRvIGluY2x1ZGUgYWxsIGhlYWRlcnMgKGNvbW1lbnRlZCBvdXQgb25lcyBiZWxvdylcbiAgICAvLyBtb3JlIGhlcmU6IGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZEZyb250L2xhdGVzdC9EZXZlbG9wZXJHdWlkZS9jbG91ZGZyb250LWxpbWl0cy5odG1sI2xpbWl0cy1wb2xpY2llc1xuICAgIFwiYWNjZXB0XCIsIC8vIGNvbnRlbnQgbmVnb3RpYXRpb24gKEhUTUwgdnMgUlNDIHBheWxvYWQpXG4gICAgXCJyc2NcIiwgLy8gUmVhY3QgU2VydmVyIENvbXBvbmVudHMgcmVxdWVzdHNcbiAgICBcIm5leHQtdXJsXCIsIC8vIE5leHQuanMgcm91dGluZ1xuICAgIFwibmV4dC1yb3V0ZXItc3RhdGUtdHJlZVwiLCAvLyBBcHAgUm91dGVyIG5hdmlnYXRpb24gc3RhdGVcbiAgICBcIm5leHQtcm91dGVyLXByZWZldGNoXCIsIC8vIHByZWZldGNoIGJlaGF2aW9yXG4gICAgXCJuZXh0LXJvdXRlci1zZWdtZW50LXByZWZldGNoXCIsIC8vIHNlZ21lbnQtbGV2ZWwgcHJlZmV0Y2hpbmdcbiAgICBcIngtcHJlcmVuZGVyLXJldmFsaWRhdGVcIiwgLy8gb24tZGVtYW5kIElTUiByZXZhbGlkYXRpb25cbiAgICBcIngtcHJlcmVuZGVyLWJ5cGFzc1wiLCAvLyBkcmFmdCBtb2RlXG4gICAgLy8gXCJ4LW5leHRqcy1zdGFsZS10aW1lXCIsIC8vIHN0YWxlLXdoaWxlLXJldmFsaWRhdGUgYmVoYXZpb3JcbiAgICAvLyBcIngtbmV4dC1jYWNoZS10YWctdG9rZW5cIiwgLy8gYXV0aCB0b2tlbiBmb3IgY2FjaGUgdGFncyAob25seSBuZWVkZWQgd2l0aCByZXZhbGlkYXRlVGFnIGF1dGgpXG4gICAgLy8gXCJ4LW5leHRqcy1wb3N0cG9uZWRcIiwgLy8gUGFydGlhbCBQcmVyZW5kZXJpbmcgKGV4cGVyaW1lbnRhbCBmZWF0dXJlKVxuICAgIC8vIFwieC1wcmVyZW5kZXItcmV2YWxpZGF0ZS1pZi1nZW5lcmF0ZWRcIiwgLy8gY29uZGl0aW9uYWwgcmV2YWxpZGF0aW9uIChuaWNoZSB1c2UgY2FzZSlcbiAgKSxcbiAgY29va2llQmVoYXZpb3I6IENhY2hlQ29va2llQmVoYXZpb3IuYWxsKCksXG4gIGVuYWJsZUFjY2VwdEVuY29kaW5nQnJvdGxpOiB0cnVlLFxuICBlbmFibGVBY2NlcHRFbmNvZGluZ0d6aXA6IHRydWUsXG59O1xuXG4vKipcbiAqIEEgY2FjaGUga2V5IG9mIG5vdGhpbmcsIGZvciBhIHBvbGljeSB0aGF0IGNhY2hlcyBub3RoaW5nLiBGb3J3YXJkaW5nIGlzXG4gKiB1bmFmZmVjdGVkOiB0aGUgZHluYW1pYyBvcmlnaW4gcmVxdWVzdCBwb2xpY3kgc2VuZHMgZXZlcnkgdmlld2VyIGhlYWRlcixcbiAqIGNvb2tpZSBhbmQgcXVlcnkgc3RyaW5nIHJlZ2FyZGxlc3MuXG4gKi9cbmNvbnN0IERJU0FCTEVEX0NBQ0hFX0tFWTogQ2FjaGVLZXlQcm9wcyA9IHtcbiAgcXVlcnlTdHJpbmdCZWhhdmlvcjogQ2FjaGVRdWVyeVN0cmluZ0JlaGF2aW9yLm5vbmUoKSxcbiAgaGVhZGVyQmVoYXZpb3I6IENhY2hlSGVhZGVyQmVoYXZpb3Iubm9uZSgpLFxuICBjb29raWVCZWhhdmlvcjogQ2FjaGVDb29raWVCZWhhdmlvci5ub25lKCksXG4gIGVuYWJsZUFjY2VwdEVuY29kaW5nQnJvdGxpOiBmYWxzZSxcbiAgZW5hYmxlQWNjZXB0RW5jb2RpbmdHemlwOiBmYWxzZSxcbn07XG5cbi8qKlxuICogQ2xvdWRGcm9udCdzIGRlZmF1bHQgXCJDYWNoZSBiZWhhdmlvcnMgcGVyIGRpc3RyaWJ1dGlvblwiIHF1b3RhLCB0aGUgZGVmYXVsdFxuICogYmVoYXZpb3IgaW5jbHVkZWQuIEFkanVzdGFibGUsIGhlbmNlIGBtYXhDYWNoZUJlaGF2aW9yc2AuXG4gKlxuICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvY2xvdWRmcm9udC1saW1pdHMuaHRtbCNsaW1pdHMtd2ViLWRpc3RyaWJ1dGlvbnNcbiAqL1xuY29uc3QgREVGQVVMVF9NQVhfQ0FDSEVfQkVIQVZJT1JTID0gNzU7XG5cbi8qKlxuICogV2hldGhlciBgY2hhcmAgaXMgaW4gQ2xvdWRGcm9udCdzIHBhdGggcGF0dGVybiBhbHBoYWJldDogdGhlIGxpdGVyYWxzLCBwbHVzIHRoZVxuICogYCpgIGFuZCBgP2Agd2lsZGNhcmRzLiBObyBzcGFjZSwgbm8gYCVgLCBub3RoaW5nIG5vbi1BU0NJSS5cbiAqL1xuZnVuY3Rpb24gaXNQYXRoUGF0dGVybkNoYXIoY2hhcjogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBjaGFyID09PSBcIipcIiB8fCBjaGFyID09PSBcIj9cIiB8fCBQQVRIX1BBVFRFUk5fTElURVJBTC50ZXN0KGNoYXIpO1xufVxuLyoqIENsb3VkRnJvbnQncyBwYXRoIHBhdHRlcm4gbGVuZ3RoIGxpbWl0LiAqL1xuY29uc3QgTUFYX1BBVEhfUEFUVEVSTl9MRU5HVEggPSAyNTU7XG5cbi8qKlxuICogQSBgcHVibGljL2AgZW50cnkncyBuYW1lIGFzIGEgQ2xvdWRGcm9udCBwYXRoIHBhdHRlcm4uXG4gKlxuICogYHB1YmxpYy9oZWxsbyB3b3JsZC5qcGdgIGlzIGEgdmFsaWQgTmV4dC5qcyBhc3NldCDigJQgYG5leHQgc3RhcnRgIHNlcnZlcyBpdCwgYW5kXG4gKiBgbmV4dC9pbWFnZWAgcG9pbnRzIGF0IGl0IOKAlCBidXQgYSBzcGFjZSBjYW5ub3QgYXBwZWFyIGluIGEgcGF0aCBwYXR0ZXJuLCBzb1xuICogY2RrLW5leHRqcyB1c2VkIHRvIHRocm93IGF0IHN5bnRoIGFuZCB0aGUgYXBwIGNvdWxkIG5vdCBiZSBkZXBsb3llZCBhdCBhbGxcbiAqIChgbmV4dC1pbWFnZS1sZWdhY3kvdW5pY29kZWAsIHdob3NlIGBwdWJsaWMvYCBhbHNvIGhvbGRzIGDDpMO2w7zFocSNxZnDrS5wbmdgKS5cbiAqXG4gKiBDbG91ZEZyb250IFVSTC1kZWNvZGVzIHRoZSByZXF1ZXN0IHBhdGggYmVmb3JlIG1hdGNoaW5nIGl0LCBzbyB0aGUgcGF0dGVybiBpc1xuICogbWF0Y2hlZCBhZ2FpbnN0IGBoZWxsbyB3b3JsZC5qcGdgLCBub3QgdGhlIGAvaGVsbG8lMjB3b3JsZC5qcGdgIG9uIHRoZSB3aXJlLlxuICogRWFjaCBjaGFyYWN0ZXIgb3V0c2lkZSB0aGUgYWxwaGFiZXQgaXMgcmVwbGFjZWQgYnkgb25lIGA/YCBwZXIgYnl0ZSBvZiBpdHNcbiAqIFVURi04IGVuY29kaW5nLCBiZWNhdXNlIHRoYXQgaXMgd2hhdCBgP2AgbWF0Y2hlczogYGhlbGxvP3dvcmxkLmpwZ2AgZm9yIHRoZVxuICogc3BhY2UsIGFuZCB0d28gYD9gIGZvciBlYWNoIGNoYXJhY3RlciBvZiBgw6TDtsO8xaHEjcWZw60ucG5nYC4gTWVhc3VyZWQgYWdhaW5zdCBhXG4gKiBkZXBsb3llZCBkaXN0cmlidXRpb247IGEgYD9gIHBlciAqcGVyY2VudC1lbmNvZGVkKiBjaGFyYWN0ZXIgKGBoZWxsbz8/P3dvcmxkYClcbiAqIHN5bnRoZXNpemVzIGZpbmUgYW5kIG5ldmVyIG1hdGNoZXMuIEEgYCpgIHdvdWxkIGJlIHNob3J0ZXIgYW5kIG11Y2ggd2lkZXI6XG4gKiBgw6TDtsO8xaHEjcWZw60ucG5nYCB3b3VsZCBiZWNvbWUgYCoucG5nYCwgd2hpY2ggd291bGQgcHVsbCBldmVyeSBgLnBuZ2AgcmVxdWVzdCBpblxuICogdGhlIGFwcCBvbnRvIHRoZSBzdGF0aWMgb3JpZ2luLlxuICovXG5mdW5jdGlvbiB0b1BhdGhQYXR0ZXJuKG5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBbLi4ubmFtZV1cbiAgICAubWFwKChjaGFyKSA9PlxuICAgICAgaXNQYXRoUGF0dGVybkNoYXIoY2hhcilcbiAgICAgICAgPyBjaGFyXG4gICAgICAgIDogXCI/XCIucmVwZWF0KEJ1ZmZlci5ieXRlTGVuZ3RoKGNoYXIsIFwidXRmOFwiKSksXG4gICAgKVxuICAgIC5qb2luKFwiXCIpO1xufVxuIl19
|