cdk-nextjs 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -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 +1551 -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 +857 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +863 -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 +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- 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/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 +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- 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 +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -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 +13 -5
- package/lib/nextjs-post-deploy.js +13 -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 +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- 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 +1216 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1686 -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 +41600 -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 +71 -0
- package/lib/runtime/next-modules.js +144 -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 +41593 -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 +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- 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
|
@@ -0,0 +1,1099 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PATH_PATTERN_LITERAL = exports.FUNCTION_GROUPS_ENV_VAR = exports.DEFAULT_FUNCTION_GROUP = void 0;
|
|
4
|
+
exports.parseFunctionGroupsEnv = parseFunctionGroupsEnv;
|
|
5
|
+
exports.assertNoI18nSplitting = assertNoI18nSplitting;
|
|
6
|
+
exports.validateFunctionGroups = validateFunctionGroups;
|
|
7
|
+
exports.assignRoutesToGroups = assignRoutesToGroups;
|
|
8
|
+
exports.routedPatterns = routedPatterns;
|
|
9
|
+
exports.pathPatternsFor = pathPatternsFor;
|
|
10
|
+
exports.interceptedRoute = interceptedRoute;
|
|
11
|
+
exports.cloudFrontPatternRegex = cloudFrontPatternRegex;
|
|
12
|
+
/**
|
|
13
|
+
* `functionGroups` resolution: the rules shared by `next build` and synth.
|
|
14
|
+
*
|
|
15
|
+
* Splitting spans two processes. `onBuildComplete` stages one deployment tree
|
|
16
|
+
* per group while `next build` is still running; the constructs turn the groups
|
|
17
|
+
* into CloudFront behaviors or API Gateway resources at synth. If the two
|
|
18
|
+
* disagree, CloudFront sends a request to a function whose zip lacks its
|
|
19
|
+
* entrypoint — so the build decides both, here, and records the behaviors it
|
|
20
|
+
* checked in the manifest for synth to deploy as they are. Synth still runs
|
|
21
|
+
* {@link validateFunctionGroups}, to fail before a `next build` it would
|
|
22
|
+
* otherwise pay for.
|
|
23
|
+
*
|
|
24
|
+
* Nothing in this file imports `aws-cdk-lib`: it is bundled into the adapter by
|
|
25
|
+
* esbuild. The public JSII struct consumers actually write (`NextjsFunctionGroup`,
|
|
26
|
+
* which adds per-group `overrides`) is in `src/nextjs-compute/nextjs-functions.ts`
|
|
27
|
+
* and is structurally assignable to {@link FunctionGroupSpec}.
|
|
28
|
+
*/
|
|
29
|
+
const constants_1 = require("../constants");
|
|
30
|
+
const manifest_1 = require("../runtime/manifest");
|
|
31
|
+
const base_path_1 = require("../utils/base-path");
|
|
32
|
+
/**
|
|
33
|
+
* The implicit group every unassigned route falls into. Reserved as a group
|
|
34
|
+
* name: it is also the construct id suffix and the function whose URL backs the
|
|
35
|
+
* distribution's default behavior.
|
|
36
|
+
*/
|
|
37
|
+
exports.DEFAULT_FUNCTION_GROUP = "default";
|
|
38
|
+
/**
|
|
39
|
+
* How the resolved groups reach `onBuildComplete`, which cannot read CDK props —
|
|
40
|
+
* it runs inside `next build`. `CDK_NEXTJS_INIT_CACHE_DIR` is the precedent.
|
|
41
|
+
*/
|
|
42
|
+
exports.FUNCTION_GROUPS_ENV_VAR = "CDK_NEXTJS_FUNCTION_GROUPS";
|
|
43
|
+
const ERROR_PREFIX = `${constants_1.LOG_PREFIX} \`functionGroups\`: `;
|
|
44
|
+
const NAME_PATTERN = /^[a-zA-Z0-9-]+$/;
|
|
45
|
+
const SUBTREE_SUFFIX = "/**";
|
|
46
|
+
/**
|
|
47
|
+
* The literal characters a CloudFront path pattern may contain: its alphabet
|
|
48
|
+
* (`A-Z a-z 0-9 _ - . * $ / ~ " ' @ : +` and `&`) less the two wildcards, which
|
|
49
|
+
* `validateRoutePattern` only accepts as a trailing `/**`. `nextjs-distribution.ts`
|
|
50
|
+
* adds the wildcards back to encode `public/` names.
|
|
51
|
+
*
|
|
52
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesCacheBehavior.html#DownloadDistValuesPathPattern
|
|
53
|
+
*/
|
|
54
|
+
exports.PATH_PATTERN_LITERAL = /[a-zA-Z0-9_\-.$/~"'@:+&]/;
|
|
55
|
+
/**
|
|
56
|
+
* Read {@link FUNCTION_GROUPS_ENV_VAR}. `undefined` — not the empty array — when
|
|
57
|
+
* unset, because "no splitting" and "split into nothing" are different requests
|
|
58
|
+
* and only the first is valid.
|
|
59
|
+
*/
|
|
60
|
+
function parseFunctionGroupsEnv(value) {
|
|
61
|
+
return value ? JSON.parse(value) : undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Splitting and `i18n` are mutually exclusive, and it is a CloudFront limit
|
|
65
|
+
* again.
|
|
66
|
+
*
|
|
67
|
+
* With `i18n` configured, every route template is locale-prefixed
|
|
68
|
+
* (`/en/pricing`, `/de/pricing`), so honoring a `/pricing` group would take one
|
|
69
|
+
* behavior *per locale per pattern* — a budget of 75 behaviors spent in a handful
|
|
70
|
+
* of routes. The alternative, a `*` in the locale position, matches any first
|
|
71
|
+
* segment and would capture routes belonging to other groups. Neither is
|
|
72
|
+
* something to do silently, so refuse instead.
|
|
73
|
+
*/
|
|
74
|
+
function assertNoI18nSplitting(i18n) {
|
|
75
|
+
if (i18n === null || i18n === undefined) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
throw new Error(`${ERROR_PREFIX}\`functionGroups\` cannot be combined with \`i18n\`. ` +
|
|
79
|
+
`With i18n every route is locale-prefixed, so routing a group at the edge ` +
|
|
80
|
+
`would need one CloudFront behavior per locale per pattern, against a ` +
|
|
81
|
+
`quota of 75 for the whole distribution. Deploy one function for every ` +
|
|
82
|
+
`route (omit \`functionGroups\`), or drop \`i18n\`.`);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Reject everything that cannot be honored, at the earliest of the two sides to
|
|
86
|
+
* see it. Called from both, because either can be the first: `next build` runs
|
|
87
|
+
* before synth reads the manifest, but a `skipBuild: true` consumer inverts that.
|
|
88
|
+
*/
|
|
89
|
+
function validateFunctionGroups(groups) {
|
|
90
|
+
if (groups.length === 0) {
|
|
91
|
+
throw new Error(`${ERROR_PREFIX}\`functionGroups\` is an empty array. Omit the prop ` +
|
|
92
|
+
`entirely to deploy one function for every route, which is the default.`);
|
|
93
|
+
}
|
|
94
|
+
const seenNames = new Set();
|
|
95
|
+
const patternOwner = new Map();
|
|
96
|
+
for (const group of groups) {
|
|
97
|
+
if (group.name === exports.DEFAULT_FUNCTION_GROUP) {
|
|
98
|
+
throw new Error(`${ERROR_PREFIX}"${exports.DEFAULT_FUNCTION_GROUP}" is a reserved group name: ` +
|
|
99
|
+
`it is the implicit group every unassigned route falls into.`);
|
|
100
|
+
}
|
|
101
|
+
if (!NAME_PATTERN.test(group.name)) {
|
|
102
|
+
throw new Error(`${ERROR_PREFIX}Group name "${group.name}" must match ` +
|
|
103
|
+
`${NAME_PATTERN} — it becomes a construct id and part of a Lambda ` +
|
|
104
|
+
`function name.`);
|
|
105
|
+
}
|
|
106
|
+
if (seenNames.has(group.name)) {
|
|
107
|
+
throw new Error(`${ERROR_PREFIX}Two groups are both named "${group.name}".`);
|
|
108
|
+
}
|
|
109
|
+
seenNames.add(group.name);
|
|
110
|
+
if (group.routes.length === 0) {
|
|
111
|
+
throw new Error(`${ERROR_PREFIX}Group "${group.name}" owns no routes. Every group is a ` +
|
|
112
|
+
`Lambda function, so an empty one would deploy and never be reached.`);
|
|
113
|
+
}
|
|
114
|
+
for (const route of group.routes) {
|
|
115
|
+
validateRoutePattern(route, group.name);
|
|
116
|
+
const owner = patternOwner.get(route);
|
|
117
|
+
if (owner !== undefined) {
|
|
118
|
+
throw new Error(`${ERROR_PREFIX}Pattern "${route}" appears in both group "${owner}" ` +
|
|
119
|
+
`and group "${group.name}". A route can only be packaged into one ` +
|
|
120
|
+
`function. (Overlapping-but-different patterns are fine: "/api/**" ` +
|
|
121
|
+
`in one group and "/api/reports/**" in another resolves ` +
|
|
122
|
+
`longest-first.)`);
|
|
123
|
+
}
|
|
124
|
+
patternOwner.set(route, group.name);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* A pattern is an exact static path (`/pricing`) or a subtree (`/api/reports/**`).
|
|
130
|
+
*
|
|
131
|
+
* **Dynamic segments are rejected**, and the reason is CloudFront rather than
|
|
132
|
+
* anything about Next.js. Patterns become behavior path patterns, and CloudFront
|
|
133
|
+
* supports only `*` and `?`, so `/dashboard/[id]` could only ever deploy as
|
|
134
|
+
* `/dashboard/*` — which also matches `/dashboard/settings` and
|
|
135
|
+
* `/dashboard/a/b/c`. If those are in another group, CloudFront routes them to a
|
|
136
|
+
* function whose zip lacks their entrypoint: a crash on a route the consumer
|
|
137
|
+
* explicitly assigned elsewhere. Accepting a syntax whose granularity cannot be
|
|
138
|
+
* honored would be worse than rejecting it.
|
|
139
|
+
*
|
|
140
|
+
* The restriction costs nothing that was achievable anyway. `/dashboard/**` →
|
|
141
|
+
* `/dashboard/*` is the same URL space exactly, and isolating one heavy dynamic
|
|
142
|
+
* route still works as a subtree: `/api/report/**` covers `/api/report/[id]`.
|
|
143
|
+
*
|
|
144
|
+
* `NextjsRegionalFunctions` gets the same restriction even though API Gateway
|
|
145
|
+
* REST could express `/{id}` precisely — so that switching deployment type (to
|
|
146
|
+
* Regional for GovCloud, say) never silently changes how routes are grouped.
|
|
147
|
+
* That one is a consistency choice, not a technical limit.
|
|
148
|
+
*/
|
|
149
|
+
function validateRoutePattern(route, groupName) {
|
|
150
|
+
const where = `Group "${groupName}" pattern "${route}"`;
|
|
151
|
+
if (!route.startsWith("/")) {
|
|
152
|
+
throw new Error(`${ERROR_PREFIX}${where} must start with "/". Patterns are URL paths as ` +
|
|
153
|
+
`the browser requests them.`);
|
|
154
|
+
}
|
|
155
|
+
// `/index` is deliberately allowed. For the App Router it is a real route of
|
|
156
|
+
// its own (`app/index/page.tsx`), which `routablePathnames` keeps apart from
|
|
157
|
+
// `/`. For the Pages Router it is the home page under the name `next build`
|
|
158
|
+
// reports it by, one entrypoint registered under `/` as well — and grouping
|
|
159
|
+
// that would leave `/` on the default behavior with a function that lacks the
|
|
160
|
+
// file. Only the assignment can tell the two apart, and its coverage check
|
|
161
|
+
// (`assertEdgeReachesEveryFile`) rejects the second.
|
|
162
|
+
if (route === "/") {
|
|
163
|
+
throw new Error(`${ERROR_PREFIX}${where} cannot be routed. CloudFront has no path ` +
|
|
164
|
+
`pattern that matches only "/" — the default behavior serves it — so the ` +
|
|
165
|
+
`home page always belongs to the "${exports.DEFAULT_FUNCTION_GROUP}" group. ` +
|
|
166
|
+
`Group the routes around it instead.`);
|
|
167
|
+
}
|
|
168
|
+
// `/_next/…` is Next's own URL space — build assets, `/_next/image`, and the
|
|
169
|
+
// Pages Router data routes — and each has its behavior already: the data route
|
|
170
|
+
// of a grouped page follows it (see `pathPatternsFor`), and a `_next/*` behavior
|
|
171
|
+
// would compete with the static-asset and image ones for everything else.
|
|
172
|
+
if (route === "/_next" || route.startsWith("/_next/")) {
|
|
173
|
+
throw new Error(`${ERROR_PREFIX}${where} is under "/_next", which Next.js reserves for ` +
|
|
174
|
+
`build assets, image optimization and data routes. A Pages Router ` +
|
|
175
|
+
`page's "/_next/data/…" route follows the page into its group, so ` +
|
|
176
|
+
`group the page itself instead.`);
|
|
177
|
+
}
|
|
178
|
+
if (route === SUBTREE_SUFFIX) {
|
|
179
|
+
throw new Error(`${ERROR_PREFIX}${where} would own every route, leaving the default ` +
|
|
180
|
+
`group empty. Splitting exists to divide routes between functions; ` +
|
|
181
|
+
`omit \`functionGroups\` to deploy them all in one.`);
|
|
182
|
+
}
|
|
183
|
+
if (/[[\]]/.test(route)) {
|
|
184
|
+
throw new Error(`${ERROR_PREFIX}${where} contains a dynamic segment. Patterns become ` +
|
|
185
|
+
`CloudFront behavior path patterns, which support only "*" and "?", so ` +
|
|
186
|
+
`"${route}" could only deploy as a wildcard that also captures its ` +
|
|
187
|
+
`siblings. Use a subtree instead: "/blog/**" owns "/blog/[slug]".`);
|
|
188
|
+
}
|
|
189
|
+
if (/\((.*)\)/.test(route)) {
|
|
190
|
+
throw new Error(`${ERROR_PREFIX}${where} contains a route group segment. Route groups ` +
|
|
191
|
+
`like "(marketing)" organize files and never appear in a URL, so they ` +
|
|
192
|
+
`cannot be routed on. Use the URL path the route is served at.`);
|
|
193
|
+
}
|
|
194
|
+
const withoutSubtree = route.endsWith(SUBTREE_SUFFIX)
|
|
195
|
+
? route.slice(0, -SUBTREE_SUFFIX.length)
|
|
196
|
+
: route;
|
|
197
|
+
if (/[*?]/.test(withoutSubtree)) {
|
|
198
|
+
throw new Error(`${ERROR_PREFIX}${where} contains a wildcard somewhere other than a ` +
|
|
199
|
+
`trailing "/**". The only two forms are an exact path ("/pricing") and ` +
|
|
200
|
+
`a subtree ("/api/reports/**").`);
|
|
201
|
+
}
|
|
202
|
+
if (route.includes("//")) {
|
|
203
|
+
throw new Error(`${ERROR_PREFIX}${where} contains an empty path segment.`);
|
|
204
|
+
}
|
|
205
|
+
// A route Next.js serves can still hold a character no path pattern can:
|
|
206
|
+
// `app/über/page.tsx`, `app/a b/page.tsx`, `app/a,b/page.tsx` all build, and
|
|
207
|
+
// the pattern passes every check above. `pathPatternsFor` copies it verbatim,
|
|
208
|
+
// so it reached `addBehavior` untouched and was left for CloudFront to reject,
|
|
209
|
+
// in an error naming neither the group nor the route. The `public/`
|
|
210
|
+
// workaround, one `?` per UTF-8 byte, is not available here: `?` matches *any*
|
|
211
|
+
// byte, so `/über` would deploy as `/??ber` and also send `/xyber` to this
|
|
212
|
+
// group's function, whose zip lacks its entrypoint. That is the sibling capture
|
|
213
|
+
// dynamic segments are rejected for, so the same answer applies.
|
|
214
|
+
const invalid = [...new Set(withoutSubtree)].filter((char) => !exports.PATH_PATTERN_LITERAL.test(char));
|
|
215
|
+
if (invalid.length > 0) {
|
|
216
|
+
throw new Error(`${ERROR_PREFIX}${where} contains ` +
|
|
217
|
+
`${invalid.map((char) => JSON.stringify(char)).join(", ")}, which a ` +
|
|
218
|
+
`CloudFront behavior path pattern cannot contain (allowed: A-Z a-z 0-9 ` +
|
|
219
|
+
`_ - . $ / ~ " ' @ : + &). Escaping it with "?" would also match other ` +
|
|
220
|
+
`routes of the same length. Use a subtree on a parent segment whose ` +
|
|
221
|
+
`name is plain ASCII instead: "/intl/**" owns "/intl/über".`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Split every route template across the groups, longest matching pattern first,
|
|
226
|
+
* then prove that the edge routes every URL each file serves to the group that
|
|
227
|
+
* file was packaged into.
|
|
228
|
+
*
|
|
229
|
+
* Its `templates` are keyed by group name and always contain
|
|
230
|
+
* {@link DEFAULT_FUNCTION_GROUP}, so callers can iterate them as the complete set
|
|
231
|
+
* of functions to deploy. The default group is allowed to be empty of *templates*
|
|
232
|
+
* — it still serves `/_next/image`, any static file, and anything the
|
|
233
|
+
* distribution's catch-all behavior sends it.
|
|
234
|
+
*
|
|
235
|
+
* `basePath` is prepended to each pattern before matching, because manifest
|
|
236
|
+
* templates are basePath-prefixed and consumers write the routes their app
|
|
237
|
+
* declares.
|
|
238
|
+
*
|
|
239
|
+
* Packaging matches patterns against *templates*, but CloudFront routes *URLs*,
|
|
240
|
+
* and a file answers URLs none of its templates spells: an optional catch-all's
|
|
241
|
+
* parent, the `trailingSlash` form, a Pages Router data URL, every other
|
|
242
|
+
* template it shares (root params synthesize `/en` and `/de` from one
|
|
243
|
+
* `[locale]` page). An interception route is worse: it is never requested at its
|
|
244
|
+
* own path at all. So after matching, intercepting files move to the group of
|
|
245
|
+
* the URL they intercept ({@link reassignInterceptingFiles}), and the result is
|
|
246
|
+
* replayed through the same behaviors `NextjsDistribution` deploys
|
|
247
|
+
* ({@link assertEdgeReachesEveryFile}, {@link assertRewritesStayInGroup}). A URL
|
|
248
|
+
* that would reach a function without its file throws here, during `next build`,
|
|
249
|
+
* rather than answering 404 once deployed.
|
|
250
|
+
*/
|
|
251
|
+
function assignRoutesToGroups(groups, entries, options) {
|
|
252
|
+
validateFunctionGroups(groups);
|
|
253
|
+
const basePath = (0, base_path_1.basePathPrefix)(options.basePath);
|
|
254
|
+
// Matched with the very behaviors `NextjsDistribution` deploys for the
|
|
255
|
+
// declared patterns, most specific first, so packaging and the edge share one
|
|
256
|
+
// routing model and the first match is the winner. Data routes are left out:
|
|
257
|
+
// no template is under `/_next`, and which groups have them is decided by
|
|
258
|
+
// this assignment.
|
|
259
|
+
const edgeBase = {
|
|
260
|
+
basePath,
|
|
261
|
+
buildId: options.buildId,
|
|
262
|
+
trailingSlash: options.trailingSlash ?? false,
|
|
263
|
+
};
|
|
264
|
+
const patterns = edgeBehaviors(groups, {}, { ...edgeBase, dataRouteGroups: new Set() });
|
|
265
|
+
const matchedPatterns = new Set();
|
|
266
|
+
// An entrypoint is a *file*; two templates can share one (a Pages Router page
|
|
267
|
+
// and its `/_next/data/<buildId>/…json` sibling). Splitting them across zips
|
|
268
|
+
// would stage the same file twice and route one of them to a function that
|
|
269
|
+
// has it by accident, so ownership is recorded per entrypoint and reused.
|
|
270
|
+
const groupOfEntrypoint = new Map();
|
|
271
|
+
// Which `patterns` index won the entrypoint. `patterns` is sorted
|
|
272
|
+
// most-specific-first, so a lower index is the better claim, and keeping it
|
|
273
|
+
// stops a second template that shares the entrypoint from taking it over with
|
|
274
|
+
// a *broader* pattern. Without it the owner was whichever of the two templates
|
|
275
|
+
// `entries` happened to visit last — the same build grouped differently
|
|
276
|
+
// depending on manifest key order.
|
|
277
|
+
const winningIndexOfEntrypoint = new Map();
|
|
278
|
+
for (const entry of entries) {
|
|
279
|
+
let winner;
|
|
280
|
+
for (const [index, pattern] of patterns.entries()) {
|
|
281
|
+
if (!pattern.regex.test(entry.template)) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
// Every match is recorded, not only the winning one. A pattern fully
|
|
285
|
+
// shadowed by a narrower pattern in another group never wins anything —
|
|
286
|
+
// "/api/**" against an app whose only API routes are under
|
|
287
|
+
// "/api/reports/**" — so recording just the winner left it looking like a
|
|
288
|
+
// typo and threw below, rejecting the very layout the duplicate-pattern
|
|
289
|
+
// error a few lines up documents as supported.
|
|
290
|
+
matchedPatterns.add(`${pattern.group}\u0000${pattern.route}`);
|
|
291
|
+
winner ??= index;
|
|
292
|
+
}
|
|
293
|
+
// An intercepting file's own template (`/feed/(..)photo/[id]`) is not a URL
|
|
294
|
+
// anyone requests, so it does not decide the file's group; the URL it
|
|
295
|
+
// intercepts does, below. Its match still counts against the typo check.
|
|
296
|
+
if (winner === undefined || isInterceptionTemplate(entry.template)) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const incumbent = winningIndexOfEntrypoint.get(entry.entrypointId);
|
|
300
|
+
if (incumbent === undefined || winner < incumbent) {
|
|
301
|
+
winningIndexOfEntrypoint.set(entry.entrypointId, winner);
|
|
302
|
+
groupOfEntrypoint.set(entry.entrypointId, patterns[winner].group);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// A pattern matching nothing is a typo, and a typo here is invisible: the
|
|
306
|
+
// route stays in the default group and the split silently does less than it
|
|
307
|
+
// was asked to. Cheap to catch, so catch it.
|
|
308
|
+
for (const group of groups) {
|
|
309
|
+
for (const route of group.routes) {
|
|
310
|
+
if (!matchedPatterns.has(`${group.name}\u0000${route}`)) {
|
|
311
|
+
throw new Error(`${ERROR_PREFIX}Group "${group.name}" pattern "${route}" matches no ` +
|
|
312
|
+
`route in this build. ` +
|
|
313
|
+
optionalCatchAllParentHint(route, entries, basePath) +
|
|
314
|
+
`Patterns match route templates as Next.js declares them (e.g. ` +
|
|
315
|
+
`"/blog/[slug]" is matched by "/blog/**"), and prerendered pages and ` +
|
|
316
|
+
`static assets are served from S3 and need no group.`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const edge = {
|
|
321
|
+
...edgeBase,
|
|
322
|
+
// Only a group that owns a Pages Router page has data URLs to route. Read
|
|
323
|
+
// before interception moves files: those are App Router, never pages.
|
|
324
|
+
dataRouteGroups: new Set(entries
|
|
325
|
+
.filter((entry) => entry.type === "page")
|
|
326
|
+
.map((entry) => groupOfEntrypoint.get(entry.entrypointId) ?? exports.DEFAULT_FUNCTION_GROUP)),
|
|
327
|
+
};
|
|
328
|
+
reassignInterceptingFiles(entries, groupOfEntrypoint, edgeBehaviors(groups, templatesByGroup(groups, entries, groupOfEntrypoint), edge), edge);
|
|
329
|
+
const assigned = templatesByGroup(groups, entries, groupOfEntrypoint);
|
|
330
|
+
// Rebuilt rather than reused: an intercepting file never adds an optional
|
|
331
|
+
// catch-all parent, so this is the same list, but only by that argument.
|
|
332
|
+
const behaviors = edgeBehaviors(groups, assigned, edge);
|
|
333
|
+
const router = {
|
|
334
|
+
fileOfTemplate: fileOfTemplate(entries),
|
|
335
|
+
routing: options.routing,
|
|
336
|
+
};
|
|
337
|
+
assertEdgeReachesEveryFile(entries, groupOfEntrypoint, behaviors, edge, router);
|
|
338
|
+
assertRewritesStayInGroup(groupOfEntrypoint, behaviors, router);
|
|
339
|
+
for (const key of Object.keys(assigned)) {
|
|
340
|
+
assigned[key] = [...assigned[key]].sort();
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
templates: assigned,
|
|
344
|
+
behaviors: behaviors.map(({ group, route, pattern }) => ({
|
|
345
|
+
group,
|
|
346
|
+
route,
|
|
347
|
+
pattern,
|
|
348
|
+
})),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* The patterns a group is *routed* on: the ones it declares, plus the parent
|
|
353
|
+
* path of every optional catch-all a subtree pattern moved into it.
|
|
354
|
+
*
|
|
355
|
+
* `/blog/[[...slug]]` serves `/blog` as well as everything under it, and
|
|
356
|
+
* `/blog/**` moves the whole file — but deploys as `blog/*`, which does not
|
|
357
|
+
* match `/blog`. So the parent is routed automatically, as an exact pattern of
|
|
358
|
+
* its own; declaring `/blog` by hand is a pattern with no route of its own and
|
|
359
|
+
* is rejected as a typo, with a hint pointing here. Nothing else a subtree owns
|
|
360
|
+
* needs this: a file whose parent URL is its subtree's base can only be an
|
|
361
|
+
* optional catch-all, since Next.js rejects `app/blog/page.tsx` next to it.
|
|
362
|
+
*
|
|
363
|
+
* @param ownedTemplates the templates assigned to the group, basePath-prefixed
|
|
364
|
+
* as `manifest.groups` records them
|
|
365
|
+
*/
|
|
366
|
+
function routedPatterns(routes, ownedTemplates, basePath) {
|
|
367
|
+
const result = [...routes];
|
|
368
|
+
for (const route of routes) {
|
|
369
|
+
if (!route.endsWith(SUBTREE_SUFFIX)) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const parent = route.slice(0, -SUBTREE_SUFFIX.length);
|
|
373
|
+
const prefix = `${prefixBasePath(parent, basePath)}/`;
|
|
374
|
+
const ownsOptionalCatchAll = ownedTemplates.some((template) => template.startsWith(prefix) &&
|
|
375
|
+
OPTIONAL_CATCH_ALL_SEGMENT.test(template.slice(prefix.length)));
|
|
376
|
+
if (ownsOptionalCatchAll && !result.includes(parent)) {
|
|
377
|
+
result.push(parent);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* CloudFront path patterns for one group pattern, without a leading slash —
|
|
384
|
+
* the form `NextjsDistribution.getPathPattern` expects, so the basePath is
|
|
385
|
+
* added there rather than here.
|
|
386
|
+
*
|
|
387
|
+
* Two patterns come back when the group owns a Pages Router route: its RSC-era
|
|
388
|
+
* equivalent is a second URL space, `/_next/data/<buildId>/<route>.json`, which
|
|
389
|
+
* the default behavior would otherwise send to the default group.
|
|
390
|
+
*
|
|
391
|
+
* A third comes back for an exact route in a `trailingSlash` app, where the
|
|
392
|
+
* canonical URL is `/pricing/` rather than `/pricing`: the bare pattern does not
|
|
393
|
+
* match it, so without this every request for the route the user actually links to
|
|
394
|
+
* falls through to the default group's function — which, for a Pages Router API
|
|
395
|
+
* route, has no entrypoint for it at all. Subtree patterns need no variant
|
|
396
|
+
* (`pricing/*` already matches `/pricing/`), and neither do the data URLs, which
|
|
397
|
+
* never carry the slash.
|
|
398
|
+
*/
|
|
399
|
+
function pathPatternsFor(route, options) {
|
|
400
|
+
const isSubtree = route.endsWith(SUBTREE_SUFFIX);
|
|
401
|
+
const base = isSubtree ? route.slice(0, -SUBTREE_SUFFIX.length) : route;
|
|
402
|
+
const bare = base.replace(/^\//, "");
|
|
403
|
+
const patterns = [isSubtree ? `${bare}/*` : bare];
|
|
404
|
+
if (!isSubtree && options.trailingSlash && bare) {
|
|
405
|
+
patterns.push(`${bare}/`);
|
|
406
|
+
}
|
|
407
|
+
if (options.hasDataRoutes) {
|
|
408
|
+
// The literal build ID, not a `*` for it. CloudFront's `*` also matches
|
|
409
|
+
// `/`, so `_next/data/*/blog/*` claimed `/_next/data/<id>/docs/blog/x.json`
|
|
410
|
+
// too — another group's page, sent to a function without it. Every other
|
|
411
|
+
// pattern is anchored at the start of the path; this one now is as well.
|
|
412
|
+
//
|
|
413
|
+
// It makes these behaviors change whenever the build ID does, which is every
|
|
414
|
+
// deploy unless `deploymentId` pins it. A client still holding the previous
|
|
415
|
+
// build requests `/_next/data/<old id>/…`, which no behavior matches, so it
|
|
416
|
+
// reaches the default function. That is correct rather than merely
|
|
417
|
+
// harmless: `next start` 404s a data request for another build ID
|
|
418
|
+
// (`handleNextDataRequest` in `next/dist/server/base-server.js`) and so does
|
|
419
|
+
// the runtime, which has no pathname for it, and the Pages Router client
|
|
420
|
+
// treats a data 404 as an asset error and hard-navigates to the page
|
|
421
|
+
// (`fetchNextData` → `markAssetError` → `handleRouteInfoError` in
|
|
422
|
+
// `next/dist/shared/lib/router/router.js`), which gets the new build.
|
|
423
|
+
patterns.push(isSubtree
|
|
424
|
+
? `_next/data/${dataBuildId(options.buildId)}/${bare}/*`
|
|
425
|
+
: `_next/data/${dataBuildId(options.buildId)}/${bare}.json`);
|
|
426
|
+
}
|
|
427
|
+
return patterns;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Rank a CloudFront path pattern so the most specific is added first: literal
|
|
431
|
+
* segments before the first `*` dominate, then an exact pattern before a
|
|
432
|
+
* wildcard one, then total segments, then length. {@link edgeBehaviors} sorts
|
|
433
|
+
* on it.
|
|
434
|
+
*
|
|
435
|
+
* Ranking on the leading literal is what a CloudFront wildcard forces, because
|
|
436
|
+
* it matches across `/` rather than within one segment: an exact `a/b` has to
|
|
437
|
+
* precede the subtree `a/*` that would otherwise swallow it, though the two are
|
|
438
|
+
* the same length and depth. At equal literal depth the exact one still goes
|
|
439
|
+
* first, since a trailingSlash `a/b/` is otherwise outranked by the subtree
|
|
440
|
+
* `a/b/*`, one segment longer, that matches it. Since the data patterns carry
|
|
441
|
+
* the literal build ID, no pattern has a wildcard anywhere but at its end.
|
|
442
|
+
*/
|
|
443
|
+
function behaviorSpecificity(pattern) {
|
|
444
|
+
const segments = pattern.split("/").filter(Boolean);
|
|
445
|
+
const firstWildcard = segments.findIndex((segment) => segment.includes("*"));
|
|
446
|
+
const literalDepth = firstWildcard === -1 ? segments.length : firstWildcard;
|
|
447
|
+
const exact = firstWildcard === -1 ? 1 : 0;
|
|
448
|
+
return ((literalDepth * 2 + exact) * 1000000 +
|
|
449
|
+
segments.length * 10000 +
|
|
450
|
+
pattern.length);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* The build ID as it goes into a path pattern. A custom `generateBuildId` can
|
|
454
|
+
* return anything, and a character CloudFront cannot spell would otherwise fail
|
|
455
|
+
* the deploy naming neither the build ID nor the group.
|
|
456
|
+
*/
|
|
457
|
+
function dataBuildId(buildId) {
|
|
458
|
+
if (!buildId) {
|
|
459
|
+
throw new Error(`${ERROR_PREFIX}Routing a Pages Router app's "/_next/data/<buildId>/…" ` +
|
|
460
|
+
`URLs needs its build ID, and none was passed. This is a cdk-nextjs ` +
|
|
461
|
+
`bug: the build ID comes from the adapter manifest.`);
|
|
462
|
+
}
|
|
463
|
+
const invalid = [...new Set(buildId)].filter((char) => !exports.PATH_PATTERN_LITERAL.test(char) || char === "/");
|
|
464
|
+
if (invalid.length > 0) {
|
|
465
|
+
throw new Error(`${ERROR_PREFIX}The build ID "${buildId}" contains ` +
|
|
466
|
+
`${invalid.map((char) => JSON.stringify(char)).join(", ")}, which a ` +
|
|
467
|
+
`CloudFront path pattern cannot hold, so its "/_next/data" URLs cannot ` +
|
|
468
|
+
`be routed to a group. Make \`generateBuildId\` return only A-Z a-z ` +
|
|
469
|
+
`0-9 _ - . characters.`);
|
|
470
|
+
}
|
|
471
|
+
return buildId;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* The typo check's hint for the one exact pattern that was the documented
|
|
475
|
+
* workaround: the parent of an optional catch-all, which has no template.
|
|
476
|
+
*/
|
|
477
|
+
function optionalCatchAllParentHint(route, entries, basePath) {
|
|
478
|
+
if (route.endsWith(SUBTREE_SUFFIX)) {
|
|
479
|
+
return "";
|
|
480
|
+
}
|
|
481
|
+
const prefix = `${prefixBasePath(route, basePath)}/`;
|
|
482
|
+
const catchAll = entries.find((entry) => entry.template.startsWith(prefix) &&
|
|
483
|
+
OPTIONAL_CATCH_ALL_SEGMENT.test(entry.template.slice(prefix.length)));
|
|
484
|
+
if (!catchAll) {
|
|
485
|
+
return "";
|
|
486
|
+
}
|
|
487
|
+
return (`"${route}" is served by the optional catch-all "${catchAll.template}", ` +
|
|
488
|
+
`whose subtree pattern "${route}${SUBTREE_SUFFIX}" routes "${route}" as ` +
|
|
489
|
+
`well — use that instead. `);
|
|
490
|
+
}
|
|
491
|
+
/** `/blog/[[...slug]]`'s last segment. */
|
|
492
|
+
const OPTIONAL_CATCH_ALL_SEGMENT = /^\[\[\.\.\.[^\]/]+\]\]$/;
|
|
493
|
+
/**
|
|
494
|
+
* Next.js's interception markers, longest-overlapping first, exactly as
|
|
495
|
+
* `INTERCEPTION_ROUTE_MARKERS` in
|
|
496
|
+
* `next/dist/shared/lib/router/utils/interception-routes.js` orders them.
|
|
497
|
+
*/
|
|
498
|
+
const INTERCEPTION_MARKERS = ["(..)(..)", "(.)", "(..)", "(...)"];
|
|
499
|
+
function interceptionMarkerOf(path) {
|
|
500
|
+
for (const segment of path.split("/")) {
|
|
501
|
+
const marker = INTERCEPTION_MARKERS.find((it) => segment.startsWith(it));
|
|
502
|
+
if (marker) {
|
|
503
|
+
return marker;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
function isInterceptionTemplate(template) {
|
|
509
|
+
return interceptionMarkerOf(template) !== undefined;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* The route an interception route intercepts: `/feed/(..)photo/[id]` →
|
|
513
|
+
* `/photo/[id]`. `extractInterceptionRouteInformation` from
|
|
514
|
+
* `next/dist/shared/lib/router/utils/interception-routes.js`, restated because
|
|
515
|
+
* this file is bundled without `next`. The template is already a normalized app
|
|
516
|
+
* path (no route groups, no `@slot`s), so none of its normalization is needed.
|
|
517
|
+
* Next.js's interception rewrite matches exactly this path, and only with a
|
|
518
|
+
* `Next-Url` header — which CloudFront does not route on.
|
|
519
|
+
*/
|
|
520
|
+
function interceptedRoute(path) {
|
|
521
|
+
const marker = interceptionMarkerOf(path);
|
|
522
|
+
if (marker === undefined) {
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
525
|
+
const at = path.indexOf(marker);
|
|
526
|
+
const intercepting = path.slice(0, at).split("/").filter(Boolean);
|
|
527
|
+
const rest = path
|
|
528
|
+
.slice(at + marker.length)
|
|
529
|
+
.split("/")
|
|
530
|
+
.filter(Boolean);
|
|
531
|
+
const parent = marker === "(.)"
|
|
532
|
+
? intercepting
|
|
533
|
+
: marker === "(..)"
|
|
534
|
+
? intercepting.slice(0, -1)
|
|
535
|
+
: marker === "(..)(..)"
|
|
536
|
+
? intercepting.slice(0, -2)
|
|
537
|
+
: [];
|
|
538
|
+
return `/${[...parent, ...rest].join("/")}`;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Templates that name what a request is *rewritten* to inside Next.js, never
|
|
542
|
+
* what the browser asks for: the RSC payload (`/pricing.rsc`) and segment
|
|
543
|
+
* prefetches (`/pricing.segments/…`) are requested as `/pricing` with an `RSC`
|
|
544
|
+
* header, which is why `pricing` alone has always routed them.
|
|
545
|
+
*/
|
|
546
|
+
function isInternalTemplate(path) {
|
|
547
|
+
return path.endsWith(".rsc") || path.includes(".segments/");
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Every group behavior, most specific first: the order CloudFront has to see
|
|
551
|
+
* them in, since it stops at the first match. The assignment returns this list
|
|
552
|
+
* and the constructs deploy it as it is.
|
|
553
|
+
*/
|
|
554
|
+
function edgeBehaviors(groups, assigned, edge) {
|
|
555
|
+
return groups
|
|
556
|
+
.flatMap((group) => routedPatterns(group.routes, assigned[group.name] ?? [], edge.basePath).flatMap((route) => pathPatternsFor(route, {
|
|
557
|
+
trailingSlash: edge.trailingSlash,
|
|
558
|
+
buildId: edge.buildId,
|
|
559
|
+
hasDataRoutes: edge.dataRouteGroups.has(group.name),
|
|
560
|
+
}).map((pattern) => ({
|
|
561
|
+
group: group.name,
|
|
562
|
+
route,
|
|
563
|
+
pattern,
|
|
564
|
+
regex: cloudFrontPatternRegex(`${edge.basePath}/${pattern}`),
|
|
565
|
+
}))))
|
|
566
|
+
.sort((a, b) => behaviorSpecificity(b.pattern) - behaviorSpecificity(a.pattern));
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* CloudFront path pattern matching: anchored at both ends, `*` for any run of
|
|
570
|
+
* characters `/` included, `?` for exactly one, case-sensitive. `pattern` has to
|
|
571
|
+
* carry the leading slash CloudFront implies.
|
|
572
|
+
*
|
|
573
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesCacheBehavior.html#DownloadDistValuesPathPattern
|
|
574
|
+
*/
|
|
575
|
+
function cloudFrontPatternRegex(pattern) {
|
|
576
|
+
const source = [...pattern]
|
|
577
|
+
.map((char) => char === "*"
|
|
578
|
+
? ".*"
|
|
579
|
+
: char === "?"
|
|
580
|
+
? "."
|
|
581
|
+
: char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
582
|
+
.join("");
|
|
583
|
+
return new RegExp(`^${source}$`);
|
|
584
|
+
}
|
|
585
|
+
/** The behavior CloudFront would pick for `url`, `undefined` for the default one. */
|
|
586
|
+
function edgeBehaviorFor(behaviors, url) {
|
|
587
|
+
return behaviors.find((behavior) => behavior.regex.test(url));
|
|
588
|
+
}
|
|
589
|
+
function templatesByGroup(groups, entries, groupOfEntrypoint) {
|
|
590
|
+
const assigned = {
|
|
591
|
+
[exports.DEFAULT_FUNCTION_GROUP]: [],
|
|
592
|
+
};
|
|
593
|
+
for (const group of groups) {
|
|
594
|
+
assigned[group.name] = [];
|
|
595
|
+
}
|
|
596
|
+
for (const entry of entries) {
|
|
597
|
+
const group = groupOfEntrypoint.get(entry.entrypointId) ?? exports.DEFAULT_FUNCTION_GROUP;
|
|
598
|
+
assigned[group].push(entry.template);
|
|
599
|
+
}
|
|
600
|
+
return assigned;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Put each intercepting file in the group of the URL it intercepts.
|
|
604
|
+
*
|
|
605
|
+
* With `/feed/**` grouped, `app/feed/(..)photo/[id]/page.tsx` matched it and
|
|
606
|
+
* moved to the feed group. But the soft navigation it exists for requests
|
|
607
|
+
* `/photo/1` with a `Next-Url: /feed` header; CloudFront routes on the URL alone,
|
|
608
|
+
* so the request reaches whichever function owns `/photo/*`, where Next.js's
|
|
609
|
+
* interception rewrite (a `beforeFiles` rule on that header) resolves it to the
|
|
610
|
+
* intercepting file — which that function did not have.
|
|
611
|
+
*
|
|
612
|
+
* Moving the file there is always possible unless the intercepted URL space is
|
|
613
|
+
* itself split: `/photo/[id]` in the default group with `/photo/1` grouped
|
|
614
|
+
* elsewhere would need the file in both. That throws.
|
|
615
|
+
*/
|
|
616
|
+
function reassignInterceptingFiles(entries, groupOfEntrypoint, behaviors, edge) {
|
|
617
|
+
for (const entry of entries) {
|
|
618
|
+
const path = stripBasePath(entry.template, edge.basePath);
|
|
619
|
+
if (path === undefined || isInternalTemplate(path)) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const target = interceptedRoute(path);
|
|
623
|
+
if (target === undefined) {
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
const url = withBasePath(target, edge.basePath);
|
|
627
|
+
const group = edgeBehaviorFor(behaviors, url)?.group ?? exports.DEFAULT_FUNCTION_GROUP;
|
|
628
|
+
const intercepted = templateRegex(url);
|
|
629
|
+
const split = behaviors.find((behavior) => behavior.group !== group &&
|
|
630
|
+
!behavior.pattern.startsWith("_next/data/") &&
|
|
631
|
+
sampleUrl(behavior.route, edge.basePath).some((it) => intercepted.test(it)));
|
|
632
|
+
if (split) {
|
|
633
|
+
throw new Error(`${ERROR_PREFIX}"${entry.entrypointId}" is the interception route ` +
|
|
634
|
+
`"${entry.template}", which Next.js reaches by rewriting a request for ` +
|
|
635
|
+
`"${url}" inside whichever function CloudFront sent it to — so it is ` +
|
|
636
|
+
`packaged with the group that owns "${url}". That URL space is split, ` +
|
|
637
|
+
`though: most of it reaches ${groupLabel(group)}, but group ` +
|
|
638
|
+
`"${split.group}"'s pattern "${split.route}" claims part of it, and ` +
|
|
639
|
+
`one file cannot be in both. Route all of "${target}" to one group.`);
|
|
640
|
+
}
|
|
641
|
+
groupOfEntrypoint.set(entry.entrypointId, group);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
/** A URL a group pattern routes, to test against another route's URL space. */
|
|
645
|
+
function sampleUrl(route, basePath) {
|
|
646
|
+
return route.endsWith(SUBTREE_SUFFIX)
|
|
647
|
+
? [`${basePath}${route.slice(0, -SUBTREE_SUFFIX.length)}/_`]
|
|
648
|
+
: [`${basePath}${route}`];
|
|
649
|
+
}
|
|
650
|
+
/** The URLs a template stands for, as a regex: `[id]` is one segment, and so on. */
|
|
651
|
+
function templateRegex(template) {
|
|
652
|
+
const source = template
|
|
653
|
+
.split("/")
|
|
654
|
+
.filter(Boolean)
|
|
655
|
+
.map((segment) => [
|
|
656
|
+
`/${segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`,
|
|
657
|
+
"/[^/]+",
|
|
658
|
+
"/.+",
|
|
659
|
+
"(?:/.+)?",
|
|
660
|
+
][segmentKind(segment)])
|
|
661
|
+
.join("");
|
|
662
|
+
return new RegExp(`^${source || "/"}$`);
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Throw unless every URL each file serves reaches the group holding it.
|
|
666
|
+
*
|
|
667
|
+
* Checked for every file, the default group's included: the invariant is "the
|
|
668
|
+
* edge never sends a request to a function without its file", and a group
|
|
669
|
+
* pattern can break it by claiming a URL of a file left in the default group as
|
|
670
|
+
* easily as by leaving one behind. A dynamic template stands for a URL space,
|
|
671
|
+
* not one URL, so it is also checked against the part of that space other
|
|
672
|
+
* groups' patterns capture ({@link capturedDynamicUrls}): a `/[...slug]` left in
|
|
673
|
+
* the default group answers `/blog/a/b` too, which `/blog/**` sends elsewhere.
|
|
674
|
+
*
|
|
675
|
+
* Only the URLs as Next.js spells them are replayed, and that is a known gap
|
|
676
|
+
* rather than an oversight: CloudFront path patterns and API Gateway resources
|
|
677
|
+
* both match case-sensitively, while `@next/routing` matches templates
|
|
678
|
+
* case-insensitively. `/API/reports/1` therefore misses a `/api/reports/**`
|
|
679
|
+
* group and reaches the default function, which resolves it to a template it
|
|
680
|
+
* does not have. Neither edge can be told to fold case, and lowercasing at the
|
|
681
|
+
* edge would break the case-sensitive S3 keys behind `public/`, so there is
|
|
682
|
+
* nothing to check here that could pass; the runtime answers such a request
|
|
683
|
+
* itself (see `ownedRouteError`).
|
|
684
|
+
*/
|
|
685
|
+
function assertEdgeReachesEveryFile(entries, groupOfEntrypoint, behaviors, edge, router) {
|
|
686
|
+
const files = new Map();
|
|
687
|
+
for (const entry of entries) {
|
|
688
|
+
const list = files.get(entry.entrypointId) ?? [];
|
|
689
|
+
list.push(entry);
|
|
690
|
+
files.set(entry.entrypointId, list);
|
|
691
|
+
}
|
|
692
|
+
// Deep enough for a sample to get past every template a capturing group
|
|
693
|
+
// could shadow it with.
|
|
694
|
+
const deepest = Math.max(0, ...entries.map((entry) => {
|
|
695
|
+
const path = stripBasePath(entry.template, edge.basePath);
|
|
696
|
+
return path !== undefined && isRoutablePath(path)
|
|
697
|
+
? path.split("/").filter(Boolean).length
|
|
698
|
+
: 0;
|
|
699
|
+
})) + 1;
|
|
700
|
+
for (const [file, fileEntries] of files) {
|
|
701
|
+
const owner = groupOfEntrypoint.get(file) ?? exports.DEFAULT_FUNCTION_GROUP;
|
|
702
|
+
const misrouted = [];
|
|
703
|
+
for (const entry of fileEntries) {
|
|
704
|
+
for (const url of servedUrls(entry.template, entry.type, edge)) {
|
|
705
|
+
const behavior = edgeBehaviorFor(behaviors, url);
|
|
706
|
+
const group = behavior?.group ?? exports.DEFAULT_FUNCTION_GROUP;
|
|
707
|
+
if (group !== owner && !misrouted.some((it) => it.url === url)) {
|
|
708
|
+
misrouted.push({ url, group, route: behavior?.route });
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
for (const it of capturedDynamicUrls(entry, owner, deepest, behaviors, edge, router)) {
|
|
712
|
+
if (!misrouted.some((known) => known.url === it.url)) {
|
|
713
|
+
misrouted.push(it);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (misrouted.length > 0) {
|
|
718
|
+
throw new Error(misroutedFileMessage(file, owner, misrouted, edge));
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Stands in for "any value" of a dynamic segment in a sample URL. A literal
|
|
724
|
+
* template of that exact name would shadow it, which can only hide a misroute,
|
|
725
|
+
* never invent one.
|
|
726
|
+
*/
|
|
727
|
+
const ANY_SEGMENT = "_";
|
|
728
|
+
/**
|
|
729
|
+
* Whether a request can resolve to `path` (basePath stripped) directly: not an
|
|
730
|
+
* RSC or segment rewrite, an interception route, or a data-URL alias (a data URL
|
|
731
|
+
* resolves to the page it names).
|
|
732
|
+
*/
|
|
733
|
+
function isRoutablePath(path) {
|
|
734
|
+
return (!isInternalTemplate(path) &&
|
|
735
|
+
!isInterceptionTemplate(path) &&
|
|
736
|
+
!path.startsWith("/_next/data/"));
|
|
737
|
+
}
|
|
738
|
+
/** 0 static, 1 `[param]`, 2 `[...catchAll]`, 3 `[[...optional]]`. */
|
|
739
|
+
function segmentKind(segment) {
|
|
740
|
+
if (OPTIONAL_CATCH_ALL_SEGMENT.test(segment)) {
|
|
741
|
+
return 3;
|
|
742
|
+
}
|
|
743
|
+
if (/^\[\.\.\.[^\]]+\]$/.test(segment)) {
|
|
744
|
+
return 2;
|
|
745
|
+
}
|
|
746
|
+
return /^\[[^\]]+\]$/.test(segment) ? 1 : 0;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* The URLs of a *dynamic* template's space that another group's behavior
|
|
750
|
+
* captures, and that Next.js — running in that group's function — still
|
|
751
|
+
* resolves to this template's file.
|
|
752
|
+
*
|
|
753
|
+
* `servedUrls` replays the template as spelled, which is exact for a static
|
|
754
|
+
* route but not for `/[...slug]`: the text `/[...slug]` never matches `blog/*`,
|
|
755
|
+
* yet `/blog/a/b` does, reaches the blog function, and resolves there to
|
|
756
|
+
* `/[...slug]`, which the blog zip lacks. So each other group's behavior is
|
|
757
|
+
* intersected with the template's URL space, one sample URL per shape
|
|
758
|
+
* ({@link sampleTemplatePaths}), and each sample is resolved the way Next.js
|
|
759
|
+
* resolves it ({@link resolveFile}). A more specific template in the capturing
|
|
760
|
+
* group legitimately shadows the sample (`/blog/[slug]` answers `/blog/_`, so
|
|
761
|
+
* only `/blog/_/_` is a misroute); anything it does not shadow is flagged.
|
|
762
|
+
*/
|
|
763
|
+
function capturedDynamicUrls(entry, owner, deepest, behaviors, edge, router) {
|
|
764
|
+
const path = stripBasePath(entry.template, edge.basePath);
|
|
765
|
+
if (path === undefined ||
|
|
766
|
+
!path.includes("[") ||
|
|
767
|
+
manifest_1.ERROR_PAGE_SUFFIXES.includes(path) ||
|
|
768
|
+
!isRoutablePath(path)) {
|
|
769
|
+
return [];
|
|
770
|
+
}
|
|
771
|
+
const segments = path.split("/").filter(Boolean);
|
|
772
|
+
const samples = new Set();
|
|
773
|
+
for (const behavior of behaviors) {
|
|
774
|
+
if (behavior.group === owner ||
|
|
775
|
+
behavior.pattern.startsWith("_next/data/")) {
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
const bare = behavior.pattern.replace(/\/$/, "");
|
|
779
|
+
const isSubtree = bare.endsWith("/*");
|
|
780
|
+
const prefix = (isSubtree ? bare.slice(0, -2) : bare)
|
|
781
|
+
.split("/")
|
|
782
|
+
.filter(Boolean);
|
|
783
|
+
for (const sample of sampleTemplatePaths(segments, prefix, isSubtree, Math.max(deepest, prefix.length + 1))) {
|
|
784
|
+
samples.add(sample);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
const misrouted = [];
|
|
788
|
+
// `resolved` is `url` as Next.js matches it: without the trailing slash.
|
|
789
|
+
const check = (url, resolved) => {
|
|
790
|
+
const behavior = edgeBehaviorFor(behaviors, url);
|
|
791
|
+
const group = behavior?.group ?? exports.DEFAULT_FUNCTION_GROUP;
|
|
792
|
+
if (group === owner || misrouted.some((it) => it.url === url)) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (resolveFile(resolved, router) === entry.entrypointId) {
|
|
796
|
+
misrouted.push({
|
|
797
|
+
url,
|
|
798
|
+
group,
|
|
799
|
+
route: behavior?.route,
|
|
800
|
+
servedAs: entry.template,
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
for (const sample of samples) {
|
|
805
|
+
for (const { url, resolved } of urlVariants(sample, entry.type, edge)) {
|
|
806
|
+
check(url, resolved);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
return misrouted;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Sample paths in both a template's URL space and a behavior's: for a subtree
|
|
813
|
+
* `prefix/*`, every way the template's segments can line up with `prefix` and
|
|
814
|
+
* continue past it, one sample per resulting length up to `maxDepth`, with
|
|
815
|
+
* {@link ANY_SEGMENT} for each dynamic value beyond the prefix. For an exact
|
|
816
|
+
* pattern, the pattern's own path if the template matches it.
|
|
817
|
+
*/
|
|
818
|
+
function sampleTemplatePaths(template, prefix, isSubtree, maxDepth) {
|
|
819
|
+
if (!isSubtree) {
|
|
820
|
+
const path = `/${prefix.join("/")}`;
|
|
821
|
+
return templateRegex(`/${template.join("/")}`).test(path) ? [path] : [];
|
|
822
|
+
}
|
|
823
|
+
const valueAt = (at) => at < prefix.length ? prefix[at] : ANY_SEGMENT;
|
|
824
|
+
const results = [];
|
|
825
|
+
const walk = (index, acc) => {
|
|
826
|
+
if (index === template.length) {
|
|
827
|
+
// Exactly the prefix is kept too: `prefix/*` matches its trailing-slash
|
|
828
|
+
// form, which `check` adds for a `trailingSlash` app.
|
|
829
|
+
if (acc.length >= prefix.length) {
|
|
830
|
+
results.push(`/${acc.join("/")}`);
|
|
831
|
+
}
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const segment = template[index];
|
|
835
|
+
const at = acc.length;
|
|
836
|
+
const kind = segmentKind(segment);
|
|
837
|
+
if (kind === 0) {
|
|
838
|
+
if (at >= prefix.length || prefix[at] === segment) {
|
|
839
|
+
walk(index + 1, [...acc, segment]);
|
|
840
|
+
}
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
if (kind === 1) {
|
|
844
|
+
walk(index + 1, [...acc, valueAt(at)]);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
for (let count = kind === 2 ? 1 : 0; at + count <= maxDepth; count++) {
|
|
848
|
+
const taken = Array.from({ length: count }, (_, i) => valueAt(at + i));
|
|
849
|
+
walk(index + 1, [...acc, ...taken]);
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
walk(0, []);
|
|
853
|
+
return results;
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* The URLs one template's file answers at the edge.
|
|
857
|
+
*
|
|
858
|
+
* Nothing for the error pages (every group stages them), the RSC and
|
|
859
|
+
* segment-prefetch rewrites (requested at the page's own URL), and interception
|
|
860
|
+
* routes (reached only through the intercepted URL's rewrite). Otherwise the
|
|
861
|
+
* template itself, an optional catch-all's parent, and for each of those the
|
|
862
|
+
* `trailingSlash` form and a Pages Router page's data URL. Only the slash-less
|
|
863
|
+
* data URL: the client never adds one.
|
|
864
|
+
*/
|
|
865
|
+
function servedUrls(template, type, edge) {
|
|
866
|
+
const path = stripBasePath(template, edge.basePath);
|
|
867
|
+
if (path === undefined ||
|
|
868
|
+
manifest_1.ERROR_PAGE_SUFFIXES.includes(path) ||
|
|
869
|
+
isInternalTemplate(path) ||
|
|
870
|
+
isInterceptionTemplate(path)) {
|
|
871
|
+
return [];
|
|
872
|
+
}
|
|
873
|
+
if (path.startsWith("/_next/data/")) {
|
|
874
|
+
return [template];
|
|
875
|
+
}
|
|
876
|
+
const paths = [path];
|
|
877
|
+
const optional = /^(.*)\/(\[\[\.\.\.[^\]/]+\]\])$/.exec(path);
|
|
878
|
+
if (optional) {
|
|
879
|
+
paths.push(optional[1] || "/");
|
|
880
|
+
}
|
|
881
|
+
return paths.flatMap((it) => urlVariants(it, type, edge).map(({ url }) => url));
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* A path's URL, its `trailingSlash` form and a Pages Router page's data URL,
|
|
885
|
+
* each with `resolved`: the URL as Next.js matches it, without the trailing slash.
|
|
886
|
+
*/
|
|
887
|
+
function urlVariants(path, type, edge) {
|
|
888
|
+
const url = withBasePath(path, edge.basePath);
|
|
889
|
+
const variants = [{ url, resolved: url }];
|
|
890
|
+
if (edge.trailingSlash && path !== "/") {
|
|
891
|
+
variants.push({ url: `${url}/`, resolved: url });
|
|
892
|
+
}
|
|
893
|
+
if (type === "page" && edge.buildId) {
|
|
894
|
+
const data = `${edge.basePath}/_next/data/${edge.buildId}${path === "/" ? "/index" : path}.json`;
|
|
895
|
+
variants.push({ url: data, resolved: data });
|
|
896
|
+
}
|
|
897
|
+
return variants;
|
|
898
|
+
}
|
|
899
|
+
function misroutedFileMessage(file, owner, misrouted, edge) {
|
|
900
|
+
const where = misrouted
|
|
901
|
+
.map((it) => `"${it.url}" to ${groupLabel(it.group)}` +
|
|
902
|
+
(it.route ? ` (its pattern "${it.route}")` : ""))
|
|
903
|
+
.join(", ");
|
|
904
|
+
const head = `${ERROR_PREFIX}"${file}" is packaged into ${groupLabel(owner)}, but ` +
|
|
905
|
+
`CloudFront would send ${where}, whose function does not have it: a 404 on ` +
|
|
906
|
+
`every such request. Every URL one file serves has to reach the group that ` +
|
|
907
|
+
`holds the file.`;
|
|
908
|
+
const captured = misrouted.filter((it) => it.servedAs !== undefined);
|
|
909
|
+
if (captured.length > 0) {
|
|
910
|
+
const templates = [...new Set(captured.map((it) => `"${it.servedAs}"`))];
|
|
911
|
+
return (`${head} Those URLs are part of the dynamic route ` +
|
|
912
|
+
`${templates.join(", ")} ("${ANY_SEGMENT}" stands for any segment ` +
|
|
913
|
+
`value): the pattern captures them at the edge, and no route packaged ` +
|
|
914
|
+
`into the capturing group is more specific, so Next.js still resolves ` +
|
|
915
|
+
`them to this file. Give that group a route that answers them (a ` +
|
|
916
|
+
`catch-all under its pattern, say), or narrow the pattern.`);
|
|
917
|
+
}
|
|
918
|
+
if (owner === exports.DEFAULT_FUNCTION_GROUP) {
|
|
919
|
+
return (`${head} A pattern claims a URL of a file that no pattern moved: narrow ` +
|
|
920
|
+
`it, or give the group the file's other routes too.`);
|
|
921
|
+
}
|
|
922
|
+
const unroutable = misrouted.filter((it) => suggestedPattern(it.url, edge) === undefined);
|
|
923
|
+
if (unroutable.length > 0) {
|
|
924
|
+
return (`${head} ${unroutable.map((it) => `"${it.url}"`).join(", ")} cannot be ` +
|
|
925
|
+
`routed to any group — CloudFront has no pattern for the home page alone, ` +
|
|
926
|
+
`and a dynamic first segment would need "/**" — so this file can only be ` +
|
|
927
|
+
`served by the "${exports.DEFAULT_FUNCTION_GROUP}" group. Remove the pattern that ` +
|
|
928
|
+
`moved it. (A Pages Router home page is also "/index": one file.)`);
|
|
929
|
+
}
|
|
930
|
+
const suggestions = [
|
|
931
|
+
...new Set(misrouted.map((it) => suggestedPattern(it.url, edge))),
|
|
932
|
+
];
|
|
933
|
+
return (`${head} Add ${suggestions.map((it) => `"${it}"`).join(", ")} to group ` +
|
|
934
|
+
`"${owner}"'s routes.`);
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* The group pattern that would route `url`, `undefined` when none can: a static
|
|
938
|
+
* path routes as itself, a dynamic one as the subtree above its first dynamic
|
|
939
|
+
* segment, and a data URL or `trailingSlash` form as the page it belongs to.
|
|
940
|
+
*/
|
|
941
|
+
function suggestedPattern(url, edge) {
|
|
942
|
+
let path = stripBasePath(url, edge.basePath) ?? url;
|
|
943
|
+
const dataPrefix = `/_next/data/${edge.buildId}/`;
|
|
944
|
+
if (path.startsWith(dataPrefix) && path.endsWith(".json")) {
|
|
945
|
+
path = `/${path.slice(dataPrefix.length, -".json".length)}`;
|
|
946
|
+
path = path === "/index" ? "/" : path;
|
|
947
|
+
}
|
|
948
|
+
if (path.length > 1 && path.endsWith("/")) {
|
|
949
|
+
path = path.slice(0, -1);
|
|
950
|
+
}
|
|
951
|
+
const segments = path.split("/").filter(Boolean);
|
|
952
|
+
const firstDynamic = segments.findIndex((segment) => segment.startsWith("["));
|
|
953
|
+
if (segments.length === 0 || firstDynamic === 0) {
|
|
954
|
+
return undefined;
|
|
955
|
+
}
|
|
956
|
+
return firstDynamic === -1
|
|
957
|
+
? path
|
|
958
|
+
: `/${segments.slice(0, firstDynamic).join("/")}${SUBTREE_SUFFIX}`;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Throw on a `next.config` rewrite whose source reaches one group and whose
|
|
962
|
+
* destination is packaged into another.
|
|
963
|
+
*
|
|
964
|
+
* A rewrite runs inside the function that received the request, so
|
|
965
|
+
* `/old/:path*` → `/new` with `/new/**` grouped and `/old` not sends `/old/x` to
|
|
966
|
+
* the default function, which rewrites it to a file it lacks.
|
|
967
|
+
*
|
|
968
|
+
* Only the rewrites whose destination is a literal path can be resolved to a
|
|
969
|
+
* file here; one built from the source's parameters (`/blog/:slug` →
|
|
970
|
+
* `/posts/:slug`) is skipped, as are external ones. The source is checked at the
|
|
971
|
+
* granularity of its literal prefix: each parameter stands in as a dynamic
|
|
972
|
+
* segment. Rewrites done by middleware (`NextResponse.rewrite`) are code, not
|
|
973
|
+
* config, and cannot be checked at all.
|
|
974
|
+
*/
|
|
975
|
+
function assertRewritesStayInGroup(groupOfEntrypoint, behaviors, router) {
|
|
976
|
+
const { routing } = router;
|
|
977
|
+
const phases = [
|
|
978
|
+
[routing.beforeFiles, false],
|
|
979
|
+
// `afterFiles` and `fallback` only apply when no file matched the URL, so a
|
|
980
|
+
// source that is itself a route never reaches the destination.
|
|
981
|
+
[routing.afterFiles, true],
|
|
982
|
+
[routing.fallback, true],
|
|
983
|
+
];
|
|
984
|
+
for (const [rules, yieldsToFiles] of phases) {
|
|
985
|
+
for (const rule of rules ?? []) {
|
|
986
|
+
const destination = literalDestination(rule.destination);
|
|
987
|
+
// Next.js's own interception rewrites are here too, on `Next-Url`;
|
|
988
|
+
// `reassignInterceptingFiles` has already put their files in place.
|
|
989
|
+
if (destination === undefined || isInterceptionTemplate(destination)) {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
const file = resolveFile(destination, router);
|
|
993
|
+
if (file === undefined) {
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
const target = groupOfEntrypoint.get(file) ?? exports.DEFAULT_FUNCTION_GROUP;
|
|
997
|
+
for (const url of rewriteSourceUrls(rule.source)) {
|
|
998
|
+
if (yieldsToFiles && router.fileOfTemplate.has(url)) {
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
const behavior = edgeBehaviorFor(behaviors, url);
|
|
1002
|
+
const group = behavior?.group ?? exports.DEFAULT_FUNCTION_GROUP;
|
|
1003
|
+
if (group === target) {
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
throw new Error(`${ERROR_PREFIX}The next.config rewrite from "${rule.source}" to ` +
|
|
1007
|
+
`"${rule.destination}" crosses groups: CloudFront sends "${url}" to ` +
|
|
1008
|
+
`${groupLabel(group)}` +
|
|
1009
|
+
(behavior ? ` (its pattern "${behavior.route}")` : "") +
|
|
1010
|
+
`, and Next.js then serves it with "${file}", which is packaged ` +
|
|
1011
|
+
`into ${groupLabel(target)}. A rewrite is applied inside the ` +
|
|
1012
|
+
`function that received the request, so its source and its ` +
|
|
1013
|
+
`destination have to be routed to the same group.`);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
/** A rewrite destination's pathname, `undefined` unless it is a literal local path. */
|
|
1019
|
+
function literalDestination(destination) {
|
|
1020
|
+
if (!destination?.startsWith("/")) {
|
|
1021
|
+
return undefined;
|
|
1022
|
+
}
|
|
1023
|
+
const pathname = destination.split(/[?#]/)[0];
|
|
1024
|
+
if (/[$:]/.test(pathname)) {
|
|
1025
|
+
return undefined;
|
|
1026
|
+
}
|
|
1027
|
+
return pathname.length > 1 ? pathname.replace(/\/$/, "") : pathname;
|
|
1028
|
+
}
|
|
1029
|
+
function fileOfTemplate(entries) {
|
|
1030
|
+
return new Map(entries
|
|
1031
|
+
.filter((entry) => !isInternalTemplate(entry.template))
|
|
1032
|
+
.map((entry) => [entry.template, entry.entrypointId]));
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* The file Next.js serves `pathname` with: a template of that exact name, or
|
|
1036
|
+
* else the first of Next.js's own dynamic route rules that matches — matched
|
|
1037
|
+
* case-insensitively, as `resolveRoutes` does. `dynamicRoutes` is in Next.js's
|
|
1038
|
+
* priority order (static segment before `[param]` before `[...catchAll]`
|
|
1039
|
+
* before `[[...optional]]`), Pages Router data URLs included.
|
|
1040
|
+
*/
|
|
1041
|
+
function resolveFile(pathname, { fileOfTemplate: files, routing }) {
|
|
1042
|
+
const exact = files.get(pathname);
|
|
1043
|
+
if (exact !== undefined) {
|
|
1044
|
+
return exact;
|
|
1045
|
+
}
|
|
1046
|
+
for (const route of routing.dynamicRoutes ?? []) {
|
|
1047
|
+
if (new RegExp(route.sourceRegex, "i").test(pathname)) {
|
|
1048
|
+
const template = route.destination?.split("?")[0];
|
|
1049
|
+
return template === undefined ? undefined : files.get(template);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return undefined;
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* The URL shapes a path-to-regexp rewrite source matches, as template-like
|
|
1056
|
+
* paths: each literal segment kept, each parameter replaced by `[name]`, and —
|
|
1057
|
+
* when the last one is optional (`:path*`, `:slug?`) — the path without it too.
|
|
1058
|
+
*/
|
|
1059
|
+
function rewriteSourceUrls(source) {
|
|
1060
|
+
if (!source?.startsWith("/")) {
|
|
1061
|
+
return [];
|
|
1062
|
+
}
|
|
1063
|
+
const segments = [];
|
|
1064
|
+
let optionalFrom;
|
|
1065
|
+
for (const segment of source.split("/").slice(1)) {
|
|
1066
|
+
if (!/[:()*?+{}[\]]/.test(segment)) {
|
|
1067
|
+
segments.push(segment);
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
optionalFrom = /^:\w+[*?]$/.test(segment) ? segments.length : undefined;
|
|
1071
|
+
segments.push(`[${/:(\w+)/.exec(segment)?.[1] ?? "param"}]`);
|
|
1072
|
+
}
|
|
1073
|
+
const urls = [`/${segments.join("/")}`];
|
|
1074
|
+
if (optionalFrom !== undefined) {
|
|
1075
|
+
urls.push(`/${segments.slice(0, optionalFrom).join("/")}`);
|
|
1076
|
+
}
|
|
1077
|
+
return urls;
|
|
1078
|
+
}
|
|
1079
|
+
function groupLabel(group) {
|
|
1080
|
+
return group === exports.DEFAULT_FUNCTION_GROUP
|
|
1081
|
+
? `the "${exports.DEFAULT_FUNCTION_GROUP}" group`
|
|
1082
|
+
: `group "${group}"`;
|
|
1083
|
+
}
|
|
1084
|
+
function prefixBasePath(route, basePath) {
|
|
1085
|
+
return `${(0, base_path_1.basePathPrefix)(basePath)}${route}`;
|
|
1086
|
+
}
|
|
1087
|
+
/** `template` without `basePath` (`/` for the base itself), `undefined` if outside it. */
|
|
1088
|
+
function stripBasePath(template, basePath) {
|
|
1089
|
+
if (!basePath) {
|
|
1090
|
+
return template;
|
|
1091
|
+
}
|
|
1092
|
+
return (0, base_path_1.hasPathPrefix)(template, basePath)
|
|
1093
|
+
? template.slice(basePath.length) || "/"
|
|
1094
|
+
: undefined;
|
|
1095
|
+
}
|
|
1096
|
+
function withBasePath(path, basePath) {
|
|
1097
|
+
return path === "/" ? basePath || "/" : `${basePath}${path}`;
|
|
1098
|
+
}
|
|
1099
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb24tZ3JvdXBzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXIvZnVuY3Rpb24tZ3JvdXBzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQWtKQSx3REFJQztBQWFELHNEQVdDO0FBT0Qsd0RBdURDO0FBZ0pELG9EQXVJQztBQWlCRCx3Q0FzQkM7QUFtQkQsMENBc0NDO0FBcUhELDRDQW9CQztBQW9FRCx3REFXQztBQTN6QkQ7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCw0Q0FBMEM7QUFDMUMsa0RBQTBEO0FBQzFELGtEQUFtRTtBQUVuRTs7OztHQUlHO0FBQ1UsUUFBQSxzQkFBc0IsR0FBRyxTQUFTLENBQUM7QUFFaEQ7OztHQUdHO0FBQ1UsUUFBQSx1QkFBdUIsR0FBRyw0QkFBNEIsQ0FBQztBQWdHcEUsTUFBTSxZQUFZLEdBQUcsR0FBRyxzQkFBVSx1QkFBdUIsQ0FBQztBQUMxRCxNQUFNLFlBQVksR0FBRyxpQkFBaUIsQ0FBQztBQUN2QyxNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUM7QUFDN0I7Ozs7Ozs7R0FPRztBQUNVLFFBQUEsb0JBQW9CLEdBQUcsMEJBQTBCLENBQUM7QUFFL0Q7Ozs7R0FJRztBQUNILFNBQWdCLHNCQUFzQixDQUNwQyxLQUF5QjtJQUV6QixPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQy9DLENBQUM7QUFFRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsU0FBZ0IscUJBQXFCLENBQUMsSUFBYTtJQUNqRCxJQUFJLElBQUksS0FBSyxJQUFJLElBQUksSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3hDLE9BQU87SUFDVCxDQUFDO0lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FDYixHQUFHLFlBQVksdURBQXVEO1FBQ3BFLDJFQUEyRTtRQUMzRSx1RUFBdUU7UUFDdkUsd0VBQXdFO1FB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QUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxHQUFHO1FBQ3hDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDaEIsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUFDLElBQVksRUFBRSxRQUFnQjtJQUNsRCxPQUFPLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxHQUFHLElBQUksRUFBRSxDQUFDO0FBQy9ELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGBmdW5jdGlvbkdyb3Vwc2AgcmVzb2x1dGlvbjogdGhlIHJ1bGVzIHNoYXJlZCBieSBgbmV4dCBidWlsZGAgYW5kIHN5bnRoLlxuICpcbiAqIFNwbGl0dGluZyBzcGFucyB0d28gcHJvY2Vzc2VzLiBgb25CdWlsZENvbXBsZXRlYCBzdGFnZXMgb25lIGRlcGxveW1lbnQgdHJlZVxuICogcGVyIGdyb3VwIHdoaWxlIGBuZXh0IGJ1aWxkYCBpcyBzdGlsbCBydW5uaW5nOyB0aGUgY29uc3RydWN0cyB0dXJuIHRoZSBncm91cHNcbiAqIGludG8gQ2xvdWRGcm9udCBiZWhhdmlvcnMgb3IgQVBJIEdhdGV3YXkgcmVzb3VyY2VzIGF0IHN5bnRoLiBJZiB0aGUgdHdvXG4gKiBkaXNhZ3JlZSwgQ2xvdWRGcm9udCBzZW5kcyBhIHJlcXVlc3QgdG8gYSBmdW5jdGlvbiB3aG9zZSB6aXAgbGFja3MgaXRzXG4gKiBlbnRyeXBvaW50IOKAlCBzbyB0aGUgYnVpbGQgZGVjaWRlcyBib3RoLCBoZXJlLCBhbmQgcmVjb3JkcyB0aGUgYmVoYXZpb3JzIGl0XG4gKiBjaGVja2VkIGluIHRoZSBtYW5pZmVzdCBmb3Igc3ludGggdG8gZGVwbG95IGFzIHRoZXkgYXJlLiBTeW50aCBzdGlsbCBydW5zXG4gKiB7QGxpbmsgdmFsaWRhdGVGdW5jdGlvbkdyb3Vwc30sIHRvIGZhaWwgYmVmb3JlIGEgYG5leHQgYnVpbGRgIGl0IHdvdWxkXG4gKiBvdGhlcndpc2UgcGF5IGZvci5cbiAqXG4gKiBOb3RoaW5nIGluIHRoaXMgZmlsZSBpbXBvcnRzIGBhd3MtY2RrLWxpYmA6IGl0IGlzIGJ1bmRsZWQgaW50byB0aGUgYWRhcHRlciBieVxuICogZXNidWlsZC4gVGhlIHB1YmxpYyBKU0lJIHN0cnVjdCBjb25zdW1lcnMgYWN0dWFsbHkgd3JpdGUgKGBOZXh0anNGdW5jdGlvbkdyb3VwYCxcbiAqIHdoaWNoIGFkZHMgcGVyLWdyb3VwIGBvdmVycmlkZXNgKSBpcyBpbiBgc3JjL25leHRqcy1jb21wdXRlL25leHRqcy1mdW5jdGlvbnMudHNgXG4gKiBhbmQgaXMgc3RydWN0dXJhbGx5IGFzc2lnbmFibGUgdG8ge0BsaW5rIEZ1bmN0aW9uR3JvdXBTcGVjfS5cbiAqL1xuaW1wb3J0IHsgTE9HX1BSRUZJWCB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IEVSUk9SX1BBR0VfU1VGRklYRVMgfSBmcm9tIFwiLi4vcnVudGltZS9tYW5pZmVzdFwiO1xuaW1wb3J0IHsgYmFzZVBhdGhQcmVmaXgsIGhhc1BhdGhQcmVmaXggfSBmcm9tIFwiLi4vdXRpbHMvYmFzZS1wYXRoXCI7XG5cbi8qKlxuICogVGhlIGltcGxpY2l0IGdyb3VwIGV2ZXJ5IHVuYXNzaWduZWQgcm91dGUgZmFsbHMgaW50by4gUmVzZXJ2ZWQgYXMgYSBncm91cFxuICogbmFtZTogaXQgaXMgYWxzbyB0aGUgY29uc3RydWN0IGlkIHN1ZmZpeCBhbmQgdGhlIGZ1bmN0aW9uIHdob3NlIFVSTCBiYWNrcyB0aGVcbiAqIGRpc3RyaWJ1dGlvbidzIGRlZmF1bHQgYmVoYXZpb3IuXG4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX0ZVTkNUSU9OX0dST1VQID0gXCJkZWZhdWx0XCI7XG5cbi8qKlxuICogSG93IHRoZSByZXNvbHZlZCBncm91cHMgcmVhY2ggYG9uQnVpbGRDb21wbGV0ZWAsIHdoaWNoIGNhbm5vdCByZWFkIENESyBwcm9wcyDigJRcbiAqIGl0IHJ1bnMgaW5zaWRlIGBuZXh0IGJ1aWxkYC4gYENES19ORVhUSlNfSU5JVF9DQUNIRV9ESVJgIGlzIHRoZSBwcmVjZWRlbnQuXG4gKi9cbmV4cG9ydCBjb25zdCBGVU5DVElPTl9HUk9VUFNfRU5WX1ZBUiA9IFwiQ0RLX05FWFRKU19GVU5DVElPTl9HUk9VUFNcIjtcblxuLyoqIFRoZSBwYXJ0IG9mIGEgZ3JvdXAgdGhlIGJ1aWxkIHNpZGUgbmVlZHMuICovXG5leHBvcnQgaW50ZXJmYWNlIEZ1bmN0aW9uR3JvdXBTcGVjIHtcbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuICByZWFkb25seSByb3V0ZXM6IHN0cmluZ1tdO1xufVxuXG4vKiogT25lIHJvdXRlIHRlbXBsYXRlIGFuZCB0aGUgZW50cnlwb2ludCBpdCBpbnZva2VzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb3V0ZUVudHJ5IHtcbiAgLyoqIEJhc2VwYXRoLXByZWZpeGVkIHJvdXRlIHRlbXBsYXRlLCBleGFjdGx5IGFzIGBtYW5pZmVzdC5lbnRyeXBvaW50c2Aga2V5cyBpdC4gKi9cbiAgcmVhZG9ubHkgdGVtcGxhdGU6IHN0cmluZztcbiAgLyoqXG4gICAqIFdoYXQgaWRlbnRpZmllcyB0aGUgZW50cnlwb2ludDogdGhlIGJ1aWxkIHNpZGUgcGFzc2VzIGl0cyBgZmlsZVBhdGhgLCBzaW5jZVxuICAgKiB0aGF0IGlzIHdoYXQgZ2V0cyBzdGFnZWQuIFR3byB0ZW1wbGF0ZXMgc2hhcmluZyBvbmUgYXJlIG5ldmVyIHNwbGl0IGFwYXJ0LlxuICAgKi9cbiAgcmVhZG9ubHkgZW50cnlwb2ludElkOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgZW50cnlwb2ludCdzIGBBZGFwdGVyRW50cnlwb2ludFR5cGVgLiBPbmx5IGBcInBhZ2VcImAgY2hhbmdlcyBhbnl0aGluZzogYVxuICAgKiBQYWdlcyBSb3V0ZXIgcGFnZSBpcyBhbHNvIHJlcXVlc3RlZCBhdCBgL19uZXh0L2RhdGEvPGJ1aWxkSWQ+LzxwYWdlPi5qc29uYCxcbiAgICogc28gdGhhdCBVUkwgaGFzIHRvIHJlYWNoIHRoZSBwYWdlJ3MgZ3JvdXAgdG9vLlxuICAgKi9cbiAgcmVhZG9ubHkgdHlwZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBPbmUgYmVoYXZpb3IgdGhlIGVkZ2Ugcm91dGVzIGEgZ3JvdXAgb24uIFRoZSBGdW5jdGlvbnMgcm9vdCBjb25zdHJ1Y3RzIGRlcGxveVxuICogZXhhY3RseSB0aGVzZSwgaW4gb3JkZXI6IGEgQ2xvdWRGcm9udCBiZWhhdmlvciBlYWNoLCBvciB0aGUgQVBJIEdhdGV3YXlcbiAqIHJlc291cmNlcyBmb3IgZWFjaCBkaXN0aW5jdCBgcm91dGVgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdyb3VwQmVoYXZpb3Ige1xuICByZWFkb25seSBncm91cDogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGdyb3VwIHBhdHRlcm4gKGAvYmxvZy8qKmApIHRoZSBiZWhhdmlvciB3YXMgZ2VuZXJhdGVkIGZyb20sIG9yIHRoZVxuICAgKiBvcHRpb25hbCBjYXRjaC1hbGwgcGFyZW50IHtAbGluayByb3V0ZWRQYXR0ZXJuc30gYWRkZWQuXG4gICAqL1xuICByZWFkb25seSByb3V0ZTogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIENsb3VkRnJvbnQgcGF0aCBwYXR0ZXJuLCBiZWZvcmUgYmFzZVBhdGggYW5kIHdpdGhvdXQgYSBsZWFkaW5nIHNsYXNoXG4gICAqIChgYmxvZy8qYCwgYF9uZXh0L2RhdGEvPGJ1aWxkSWQ+L2Jsb2cvKmApLlxuICAgKi9cbiAgcmVhZG9ubHkgcGF0dGVybjogc3RyaW5nO1xufVxuXG4vKiogV2hhdCB7QGxpbmsgYXNzaWduUm91dGVzVG9Hcm91cHN9IGRlY2lkZWQuICovXG5leHBvcnQgaW50ZXJmYWNlIEdyb3VwQXNzaWdubWVudCB7XG4gIC8qKiBHcm91cCBuYW1lIOKGkiB0aGUgdGVtcGxhdGVzIHBhY2thZ2VkIGludG8gaXQsIGBkZWZhdWx0YCBpbmNsdWRlZC4gKi9cbiAgcmVhZG9ubHkgdGVtcGxhdGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT47XG4gIC8qKlxuICAgKiBFdmVyeSBncm91cCBiZWhhdmlvciwgbW9zdCBzcGVjaWZpYyBmaXJzdDogdGhlIG9yZGVyIENsb3VkRnJvbnQgaGFzIHRvIHNlZVxuICAgKiB0aGVtIGluLCBzaW5jZSBpdCBzdG9wcyBhdCB0aGUgZmlyc3QgbWF0Y2guIFJlY29yZGVkIHJhdGhlciB0aGFuXG4gICAqIHJlY29tcHV0ZWQgYXQgc3ludGgsIHNvIHRoZSBiZWhhdmlvcnMgZGVwbG95ZWQgYXJlIHRoZSBvbmVzIHRoaXNcbiAgICogYXNzaWdubWVudCB3YXMgY2hlY2tlZCBhZ2FpbnN0LlxuICAgKi9cbiAgcmVhZG9ubHkgYmVoYXZpb3JzOiBHcm91cEJlaGF2aW9yW107XG59XG5cbi8qKiBXaGF0IHtAbGluayBhc3NpZ25Sb3V0ZXNUb0dyb3Vwc30gbmVlZHMgdG8ga25vdyBiZXNpZGVzIHRoZSByb3V0ZXMuICovXG5leHBvcnQgaW50ZXJmYWNlIEFzc2lnblJvdXRlc09wdGlvbnMge1xuICAvKiogYG5leHQuY29uZmlnYCBgYmFzZVBhdGhgLCB3aGljaCBldmVyeSBtYW5pZmVzdCB0ZW1wbGF0ZSBjYXJyaWVzLiAqL1xuICByZWFkb25seSBiYXNlUGF0aDogc3RyaW5nO1xuICAvKipcbiAgICogTmV4dC5qcydzIGJ1aWxkIElEIOKAlCB0aGUgc2VnbWVudCBpbiBgL19uZXh0L2RhdGEvPGJ1aWxkSWQ+L+KApmAgVVJMcywgd2hpY2ggaXNcbiAgICogYGN0eC5idWlsZElkYCBhbmQgYC5uZXh0L0JVSUxEX0lEYCwgbm90IGNkay1uZXh0anMncyBkZXBsb3ltZW50LXN1ZmZpeGVkXG4gICAqIG9uZS4gUmVxdWlyZWQgd2hlbiBhbnkgZW50cnkgaXMgYSBQYWdlcyBSb3V0ZXIgcGFnZS5cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkSWQ/OiBzdHJpbmc7XG4gIC8qKiBgbmV4dC5jb25maWdgIGB0cmFpbGluZ1NsYXNoYC4gKi9cbiAgcmVhZG9ubHkgdHJhaWxpbmdTbGFzaD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBgY3R4LnJvdXRpbmdgOiB0aGUgYG5leHQuY29uZmlnYCByZXdyaXRlcyB3aG9zZSBzb3VyY2UgYW5kIGRlc3RpbmF0aW9uXG4gICAqIGhhdmUgdG8gbGFuZCBpbiBvbmUgZ3JvdXAsIGFuZCBOZXh0LmpzJ3Mgb3duIGR5bmFtaWMgcm91dGUgb3JkZXIsIHdoaWNoXG4gICAqIGRlY2lkZXMgdGhlIHRlbXBsYXRlIGEgVVJMIHJlc29sdmVzIHRvLlxuICAgKi9cbiAgcmVhZG9ubHkgcm91dGluZzogUm91dGluZ1J1bGVzO1xufVxuXG4vKiogT25lIGBjdHgucm91dGluZ2AgcmV3cml0ZSwgcmVkdWNlZCB0byB0aGUgZmllbGRzIHJlYWQgaGVyZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmV3cml0ZVJ1bGUge1xuICAvKiogVGhlIHBhdGgtdG8tcmVnZXhwIHNvdXJjZSwgYmFzZVBhdGggaW5jbHVkZWQgKGAvb2xkLzpwYXRoKmApLiAqL1xuICByZWFkb25seSBzb3VyY2U/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlc3RpbmF0aW9uPzogc3RyaW5nO1xufVxuXG4vKiogVGhlIHBhcnQgb2YgYGN0eC5yb3V0aW5nYCB7QGxpbmsgYXNzaWduUm91dGVzVG9Hcm91cHN9IHJlYWRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb3V0aW5nUnVsZXMge1xuICByZWFkb25seSBiZWZvcmVGaWxlcz86IHJlYWRvbmx5IFJld3JpdGVSdWxlW107XG4gIHJlYWRvbmx5IGFmdGVyRmlsZXM/OiByZWFkb25seSBSZXdyaXRlUnVsZVtdO1xuICByZWFkb25seSBmYWxsYmFjaz86IHJlYWRvbmx5IFJld3JpdGVSdWxlW107XG4gIC8qKiBOZXh0LmpzJ3Mgb3duIHRlbXBsYXRlIG1hdGNoZXJzLCB1c2VkIHRvIHJlc29sdmUgYSByZXdyaXRlJ3MgZGVzdGluYXRpb24uICovXG4gIHJlYWRvbmx5IGR5bmFtaWNSb3V0ZXM/OiByZWFkb25seSB7XG4gICAgcmVhZG9ubHkgc291cmNlUmVnZXg6IHN0cmluZztcbiAgICByZWFkb25seSBkZXN0aW5hdGlvbj86IHN0cmluZztcbiAgfVtdO1xufVxuXG5jb25zdCBFUlJPUl9QUkVGSVggPSBgJHtMT0dfUFJFRklYfSBcXGBmdW5jdGlvbkdyb3Vwc1xcYDogYDtcbmNvbnN0IE5BTUVfUEFUVEVSTiA9IC9eW2EtekEtWjAtOS1dKyQvO1xuY29uc3QgU1VCVFJFRV9TVUZGSVggPSBcIi8qKlwiO1xuLyoqXG4gKiBUaGUgbGl0ZXJhbCBjaGFyYWN0ZXJzIGEgQ2xvdWRGcm9udCBwYXRoIHBhdHRlcm4gbWF5IGNvbnRhaW46IGl0cyBhbHBoYWJldFxuICogKGBBLVogYS16IDAtOSBfIC0gLiAqICQgLyB+IFwiICcgQCA6ICtgIGFuZCBgJmApIGxlc3MgdGhlIHR3byB3aWxkY2FyZHMsIHdoaWNoXG4gKiBgdmFsaWRhdGVSb3V0ZVBhdHRlcm5gIG9ubHkgYWNjZXB0cyBhcyBhIHRyYWlsaW5nIGAvKipgLiBgbmV4dGpzLWRpc3RyaWJ1dGlvbi50c2BcbiAqIGFkZHMgdGhlIHdpbGRjYXJkcyBiYWNrIHRvIGVuY29kZSBgcHVibGljL2AgbmFtZXMuXG4gKlxuICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvRG93bmxvYWREaXN0VmFsdWVzQ2FjaGVCZWhhdmlvci5odG1sI0Rvd25sb2FkRGlzdFZhbHVlc1BhdGhQYXR0ZXJuXG4gKi9cbmV4cG9ydCBjb25zdCBQQVRIX1BBVFRFUk5fTElURVJBTCA9IC9bYS16QS1aMC05X1xcLS4kL35cIidAOismXS87XG5cbi8qKlxuICogUmVhZCB7QGxpbmsgRlVOQ1RJT05fR1JPVVBTX0VOVl9WQVJ9LiBgdW5kZWZpbmVkYCDigJQgbm90IHRoZSBlbXB0eSBhcnJheSDigJQgd2hlblxuICogdW5zZXQsIGJlY2F1c2UgXCJubyBzcGxpdHRpbmdcIiBhbmQgXCJzcGxpdCBpbnRvIG5vdGhpbmdcIiBhcmUgZGlmZmVyZW50IHJlcXVlc3RzXG4gKiBhbmQgb25seSB0aGUgZmlyc3QgaXMgdmFsaWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUZ1bmN0aW9uR3JvdXBzRW52KFxuICB2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogRnVuY3Rpb25Hcm91cFNwZWNbXSB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiB2YWx1ZSA/IEpTT04ucGFyc2UodmFsdWUpIDogdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFNwbGl0dGluZyBhbmQgYGkxOG5gIGFyZSBtdXR1YWxseSBleGNsdXNpdmUsIGFuZCBpdCBpcyBhIENsb3VkRnJvbnQgbGltaXRcbiAqIGFnYWluLlxuICpcbiAqIFdpdGggYGkxOG5gIGNvbmZpZ3VyZWQsIGV2ZXJ5IHJvdXRlIHRlbXBsYXRlIGlzIGxvY2FsZS1wcmVmaXhlZFxuICogKGAvZW4vcHJpY2luZ2AsIGAvZGUvcHJpY2luZ2ApLCBzbyBob25vcmluZyBhIGAvcHJpY2luZ2AgZ3JvdXAgd291bGQgdGFrZSBvbmVcbiAqIGJlaGF2aW9yICpwZXIgbG9jYWxlIHBlciBwYXR0ZXJuKiDigJQgYSBidWRnZXQgb2YgNzUgYmVoYXZpb3JzIHNwZW50IGluIGEgaGFuZGZ1bFxuICogb2Ygcm91dGVzLiBUaGUgYWx0ZXJuYXRpdmUsIGEgYCpgIGluIHRoZSBsb2NhbGUgcG9zaXRpb24sIG1hdGNoZXMgYW55IGZpcnN0XG4gKiBzZWdtZW50IGFuZCB3b3VsZCBjYXB0dXJlIHJvdXRlcyBiZWxvbmdpbmcgdG8gb3RoZXIgZ3JvdXBzLiBOZWl0aGVyIGlzXG4gKiBzb21ldGhpbmcgdG8gZG8gc2lsZW50bHksIHNvIHJlZnVzZSBpbnN0ZWFkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0Tm9JMThuU3BsaXR0aW5nKGkxOG46IHVua25vd24pOiB2b2lkIHtcbiAgaWYgKGkxOG4gPT09IG51bGwgfHwgaTE4biA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgJHtFUlJPUl9QUkVGSVh9XFxgZnVuY3Rpb25Hcm91cHNcXGAgY2Fubm90IGJlIGNvbWJpbmVkIHdpdGggXFxgaTE4blxcYC4gYCArXG4gICAgICBgV2l0aCBpMThuIGV2ZXJ5IHJvdXRlIGlzIGxvY2FsZS1wcmVmaXhlZCwgc28gcm91dGluZyBhIGdyb3VwIGF0IHRoZSBlZGdlIGAgK1xuICAgICAgYHdvdWxkIG5lZWQgb25lIENsb3VkRnJvbnQgYmVoYXZpb3IgcGVyIGxvY2FsZSBwZXIgcGF0dGVybiwgYWdhaW5zdCBhIGAgK1xuICAgICAgYHF1b3RhIG9mIDc1IGZvciB0aGUgd2hvbGUgZGlzdHJpYnV0aW9uLiBEZXBsb3kgb25lIGZ1bmN0aW9uIGZvciBldmVyeSBgICtcbiAgICAgIGByb3V0ZSAob21pdCBcXGBmdW5jdGlvbkdyb3Vwc1xcYCksIG9yIGRyb3AgXFxgaTE4blxcYC5gLFxuICApO1xufVxuXG4vKipcbiAqIFJlamVjdCBldmVyeXRoaW5nIHRoYXQgY2Fubm90IGJlIGhvbm9yZWQsIGF0IHRoZSBlYXJsaWVzdCBvZiB0aGUgdHdvIHNpZGVzIHRvXG4gKiBzZWUgaXQuIENhbGxlZCBmcm9tIGJvdGgsIGJlY2F1c2UgZWl0aGVyIGNhbiBiZSB0aGUgZmlyc3Q6IGBuZXh0IGJ1aWxkYCBydW5zXG4gKiBiZWZvcmUgc3ludGggcmVhZHMgdGhlIG1hbmlmZXN0LCBidXQgYSBgc2tpcEJ1aWxkOiB0cnVlYCBjb25zdW1lciBpbnZlcnRzIHRoYXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUZ1bmN0aW9uR3JvdXBzKFxuICBncm91cHM6IHJlYWRvbmx5IEZ1bmN0aW9uR3JvdXBTcGVjW10sXG4pOiB2b2lkIHtcbiAgaWYgKGdyb3Vwcy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtFUlJPUl9QUkVGSVh9XFxgZnVuY3Rpb25Hcm91cHNcXGAgaXMgYW4gZW1wdHkgYXJyYXkuIE9taXQgdGhlIHByb3AgYCArXG4gICAgICAgIGBlbnRpcmVseSB0byBkZXBsb3kgb25lIGZ1bmN0aW9uIGZvciBldmVyeSByb3V0ZSwgd2hpY2ggaXMgdGhlIGRlZmF1bHQuYCxcbiAgICApO1xuICB9XG5cbiAgY29uc3Qgc2Vlbk5hbWVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGNvbnN0IHBhdHRlcm5Pd25lciA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG5cbiAgZm9yIChjb25zdCBncm91cCBvZiBncm91cHMpIHtcbiAgICBpZiAoZ3JvdXAubmFtZSA9PT0gREVGQVVMVF9GVU5DVElPTl9HUk9VUCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtFUlJPUl9QUkVGSVh9XCIke0RFRkFVTFRfRlVOQ1RJT05fR1JPVVB9XCIgaXMgYSByZXNlcnZlZCBncm91cCBuYW1lOiBgICtcbiAgICAgICAgICBgaXQgaXMgdGhlIGltcGxpY2l0IGdyb3VwIGV2ZXJ5IHVuYXNzaWduZWQgcm91dGUgZmFsbHMgaW50by5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCFOQU1FX1BBVFRFUk4udGVzdChncm91cC5uYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtFUlJPUl9QUkVGSVh9R3JvdXAgbmFtZSBcIiR7Z3JvdXAubmFtZX1cIiBtdXN0IG1hdGNoIGAgK1xuICAgICAgICAgIGAke05BTUVfUEFUVEVSTn0g4oCUIGl0IGJlY29tZXMgYSBjb25zdHJ1Y3QgaWQgYW5kIHBhcnQgb2YgYSBMYW1iZGEgYCArXG4gICAgICAgICAgYGZ1bmN0aW9uIG5hbWUuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGlmIChzZWVuTmFtZXMuaGFzKGdyb3VwLm5hbWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke0VSUk9SX1BSRUZJWH1Ud28gZ3JvdXBzIGFyZSBib3RoIG5hbWVkIFwiJHtncm91cC5uYW1lfVwiLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBzZWVuTmFtZXMuYWRkKGdyb3VwLm5hbWUpO1xuXG4gICAgaWYgKGdyb3VwLnJvdXRlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7RVJST1JfUFJFRklYfUdyb3VwIFwiJHtncm91cC5uYW1lfVwiIG93bnMgbm8gcm91dGVzLiBFdmVyeSBncm91cCBpcyBhIGAgK1xuICAgICAgICAgIGBMYW1iZGEgZnVuY3Rpb24sIHNvIGFuIGVtcHR5IG9uZSB3b3VsZCBkZXBsb3kgYW5kIG5ldmVyIGJlIHJlYWNoZWQuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGZvciAoY29uc3Qgcm91dGUgb2YgZ3JvdXAucm91dGVzKSB7XG4gICAgICB2YWxpZGF0ZVJvdXRlUGF0dGVybihyb3V0ZSwgZ3JvdXAubmFtZSk7XG4gICAgICBjb25zdCBvd25lciA9IHBhdHRlcm5Pd25lci5nZXQocm91dGUpO1xuICAgICAgaWYgKG93bmVyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGAke0VSUk9SX1BSRUZJWH1QYXR0ZXJuIFwiJHtyb3V0ZX1cIiBhcHBlYXJzIGluIGJvdGggZ3JvdXAgXCIke293bmVyfVwiIGAgK1xuICAgICAgICAgICAgYGFuZCBncm91cCBcIiR7Z3JvdXAubmFtZX1cIi4gQSByb3V0ZSBjYW4gb25seSBiZSBwYWNrYWdlZCBpbnRvIG9uZSBgICtcbiAgICAgICAgICAgIGBmdW5jdGlvbi4gKE92ZXJsYXBwaW5nLWJ1dC1kaWZmZXJlbnQgcGF0dGVybnMgYXJlIGZpbmU6IFwiL2FwaS8qKlwiIGAgK1xuICAgICAgICAgICAgYGluIG9uZSBncm91cCBhbmQgXCIvYXBpL3JlcG9ydHMvKipcIiBpbiBhbm90aGVyIHJlc29sdmVzIGAgK1xuICAgICAgICAgICAgYGxvbmdlc3QtZmlyc3QuKWAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBwYXR0ZXJuT3duZXIuc2V0KHJvdXRlLCBncm91cC5uYW1lKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBBIHBhdHRlcm4gaXMgYW4gZXhhY3Qgc3RhdGljIHBhdGggKGAvcHJpY2luZ2ApIG9yIGEgc3VidHJlZSAoYC9hcGkvcmVwb3J0cy8qKmApLlxuICpcbiAqICoqRHluYW1pYyBzZWdtZW50cyBhcmUgcmVqZWN0ZWQqKiwgYW5kIHRoZSByZWFzb24gaXMgQ2xvdWRGcm9udCByYXRoZXIgdGhhblxuICogYW55dGhpbmcgYWJvdXQgTmV4dC5qcy4gUGF0dGVybnMgYmVjb21lIGJlaGF2aW9yIHBhdGggcGF0dGVybnMsIGFuZCBDbG91ZEZyb250XG4gKiBzdXBwb3J0cyBvbmx5IGAqYCBhbmQgYD9gLCBzbyBgL2Rhc2hib2FyZC9baWRdYCBjb3VsZCBvbmx5IGV2ZXIgZGVwbG95IGFzXG4gKiBgL2Rhc2hib2FyZC8qYCDigJQgd2hpY2ggYWxzbyBtYXRjaGVzIGAvZGFzaGJvYXJkL3NldHRpbmdzYCBhbmRcbiAqIGAvZGFzaGJvYXJkL2EvYi9jYC4gSWYgdGhvc2UgYXJlIGluIGFub3RoZXIgZ3JvdXAsIENsb3VkRnJvbnQgcm91dGVzIHRoZW0gdG8gYVxuICogZnVuY3Rpb24gd2hvc2UgemlwIGxhY2tzIHRoZWlyIGVudHJ5cG9pbnQ6IGEgY3Jhc2ggb24gYSByb3V0ZSB0aGUgY29uc3VtZXJcbiAqIGV4cGxpY2l0bHkgYXNzaWduZWQgZWxzZXdoZXJlLiBBY2NlcHRpbmcgYSBzeW50YXggd2hvc2UgZ3JhbnVsYXJpdHkgY2Fubm90IGJlXG4gKiBob25vcmVkIHdvdWxkIGJlIHdvcnNlIHRoYW4gcmVqZWN0aW5nIGl0LlxuICpcbiAqIFRoZSByZXN0cmljdGlvbiBjb3N0cyBub3RoaW5nIHRoYXQgd2FzIGFjaGlldmFibGUgYW55d2F5LiBgL2Rhc2hib2FyZC8qKmAg4oaSXG4gKiBgL2Rhc2hib2FyZC8qYCBpcyB0aGUgc2FtZSBVUkwgc3BhY2UgZXhhY3RseSwgYW5kIGlzb2xhdGluZyBvbmUgaGVhdnkgZHluYW1pY1xuICogcm91dGUgc3RpbGwgd29ya3MgYXMgYSBzdWJ0cmVlOiBgL2FwaS9yZXBvcnQvKipgIGNvdmVycyBgL2FwaS9yZXBvcnQvW2lkXWAuXG4gKlxuICogYE5leHRqc1JlZ2lvbmFsRnVuY3Rpb25zYCBnZXRzIHRoZSBzYW1lIHJlc3RyaWN0aW9uIGV2ZW4gdGhvdWdoIEFQSSBHYXRld2F5XG4gKiBSRVNUIGNvdWxkIGV4cHJlc3MgYC97aWR9YCBwcmVjaXNlbHkg4oCUIHNvIHRoYXQgc3dpdGNoaW5nIGRlcGxveW1lbnQgdHlwZSAodG9cbiAqIFJlZ2lvbmFsIGZvciBHb3ZDbG91ZCwgc2F5KSBuZXZlciBzaWxlbnRseSBjaGFuZ2VzIGhvdyByb3V0ZXMgYXJlIGdyb3VwZWQuXG4gKiBUaGF0IG9uZSBpcyBhIGNvbnNpc3RlbmN5IGNob2ljZSwgbm90IGEgdGVjaG5pY2FsIGxpbWl0LlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVJvdXRlUGF0dGVybihyb3V0ZTogc3RyaW5nLCBncm91cE5hbWU6IHN0cmluZyk6IHZvaWQge1xuICBjb25zdCB3aGVyZSA9IGBHcm91cCBcIiR7Z3JvdXBOYW1lfVwiIHBhdHRlcm4gXCIke3JvdXRlfVwiYDtcbiAgaWYgKCFyb3V0ZS5zdGFydHNXaXRoKFwiL1wiKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGAke0VSUk9SX1BSRUZJWH0ke3doZXJlfSBtdXN0IHN0YXJ0IHdpdGggXCIvXCIuIFBhdHRlcm5zIGFyZSBVUkwgcGF0aHMgYXMgYCArXG4gICAgICAgIGB0aGUgYnJvd3NlciByZXF1ZXN0cyB0aGVtLmAsXG4gICAgKTtcbiAgfVxuICAvLyBgL2luZGV4YCBpcyBkZWxpYmVyYXRlbHkgYWxsb3dlZC4gRm9yIHRoZSBBcHAgUm91dGVyIGl0IGlzIGEgcmVhbCByb3V0ZSBvZlxuICAvLyBpdHMgb3duIChgYXBwL2luZGV4L3BhZ2UudHN4YCksIHdoaWNoIGByb3V0YWJsZVBhdGhuYW1lc2Aga2VlcHMgYXBhcnQgZnJvbVxuICAvLyBgL2AuIEZvciB0aGUgUGFnZXMgUm91dGVyIGl0IGlzIHRoZSBob21lIHBhZ2UgdW5kZXIgdGhlIG5hbWUgYG5leHQgYnVpbGRgXG4gIC8vIHJlcG9ydHMgaXQgYnksIG9uZSBlbnRyeXBvaW50IHJlZ2lzdGVyZWQgdW5kZXIgYC9gIGFzIHdlbGwg4oCUIGFuZCBncm91cGluZ1xuICAvLyB0aGF0IHdvdWxkIGxlYXZlIGAvYCBvbiB0aGUgZGVmYXVsdCBiZWhhdmlvciB3aXRoIGEgZnVuY3Rpb24gdGhhdCBsYWNrcyB0aGVcbiAgLy8gZmlsZS4gT25seSB0aGUgYXNzaWdubWVudCBjYW4gdGVsbCB0aGUgdHdvIGFwYXJ0LCBhbmQgaXRzIGNvdmVyYWdlIGNoZWNrXG4gIC8vIChgYXNzZXJ0RWRnZVJlYWNoZXNFdmVyeUZpbGVgKSByZWplY3RzIHRoZSBzZWNvbmQuXG4gIGlmIChyb3V0ZSA9PT0gXCIvXCIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtFUlJPUl9QUkVGSVh9JHt3aGVyZX0gY2Fubm90IGJlIHJvdXRlZC4gQ2xvdWRGcm9udCBoYXMgbm8gcGF0aCBgICtcbiAgICAgICAgYHBhdHRlcm4gdGhhdCBtYXRjaGVzIG9ubHkgXCIvXCIg4oCUIHRoZSBkZWZhdWx0IGJlaGF2aW9yIHNlcnZlcyBpdCDigJQgc28gdGhlIGAgK1xuICAgICAgICBgaG9tZSBwYWdlIGFsd2F5cyBiZWxvbmdzIHRvIHRoZSBcIiR7REVGQVVMVF9GVU5DVElPTl9HUk9VUH1cIiBncm91cC4gYCArXG4gICAgICAgIGBHcm91cCB0aGUgcm91dGVzIGFyb3VuZCBpdCBpbnN0ZWFkLmAsXG4gICAgKTtcbiAgfVxuICAvLyBgL19uZXh0L+KApmAgaXMgTmV4dCdzIG93biBVUkwgc3BhY2Ug4oCUIGJ1aWxkIGFzc2V0cywgYC9fbmV4dC9pbWFnZWAsIGFuZCB0aGVcbiAgLy8gUGFnZXMgUm91dGVyIGRhdGEgcm91dGVzIOKAlCBhbmQgZWFjaCBoYXMgaXRzIGJlaGF2aW9yIGFscmVhZHk6IHRoZSBkYXRhIHJvdXRlXG4gIC8vIG9mIGEgZ3JvdXBlZCBwYWdlIGZvbGxvd3MgaXQgKHNlZSBgcGF0aFBhdHRlcm5zRm9yYCksIGFuZCBhIGBfbmV4dC8qYCBiZWhhdmlvclxuICAvLyB3b3VsZCBjb21wZXRlIHdpdGggdGhlIHN0YXRpYy1hc3NldCBhbmQgaW1hZ2Ugb25lcyBmb3IgZXZlcnl0aGluZyBlbHNlLlxuICBpZiAocm91dGUgPT09IFwiL19uZXh0XCIgfHwgcm91dGUuc3RhcnRzV2l0aChcIi9fbmV4dC9cIikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtFUlJPUl9QUkVGSVh9JHt3aGVyZX0gaXMgdW5kZXIgXCIvX25leHRcIiwgd2hpY2ggTmV4dC5qcyByZXNlcnZlcyBmb3IgYCArXG4gICAgICAgIGBidWlsZCBhc3NldHMsIGltYWdlIG9wdGltaXphdGlvbiBhbmQgZGF0YSByb3V0ZXMuIEEgUGFnZXMgUm91dGVyIGAgK1xuICAgICAgICBgcGFnZSdzIFwiL19uZXh0L2RhdGEv4oCmXCIgcm91dGUgZm9sbG93cyB0aGUgcGFnZSBpbnRvIGl0cyBncm91cCwgc28gYCArXG4gICAgICAgIGBncm91cCB0aGUgcGFnZSBpdHNlbGYgaW5zdGVhZC5gLFxuICAgICk7XG4gIH1cbiAgaWYgKHJvdXRlID09PSBTVUJUUkVFX1NVRkZJWCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGAke0VSUk9SX1BSRUZJWH0ke3doZXJlfSB3b3VsZCBvd24gZXZlcnkgcm91dGUsIGxlYXZpbmcgdGhlIGRlZmF1bHQgYCArXG4gICAgICAgIGBncm91cCBlbXB0eS4gU3BsaXR0aW5nIGV4aXN0cyB0byBkaXZpZGUgcm91dGVzIGJldHdlZW4gZnVuY3Rpb25zOyBgICtcbiAgICAgICAgYG9taXQgXFxgZnVuY3Rpb25Hcm91cHNcXGAgdG8gZGVwbG95IHRoZW0gYWxsIGluIG9uZS5gLFxuICAgICk7XG4gIH1cbiAgaWYgKC9bW1xcXV0vLnRlc3Qocm91dGUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7RVJST1JfUFJFRklYfSR7d2hlcmV9IGNvbnRhaW5zIGEgZHluYW1pYyBzZWdtZW50LiBQYXR0ZXJucyBiZWNvbWUgYCArXG4gICAgICAgIGBDbG91ZEZyb250IGJlaGF2aW9yIHBhdGggcGF0dGVybnMsIHdoaWNoIHN1cHBvcnQgb25seSBcIipcIiBhbmQgXCI/XCIsIHNvIGAgK1xuICAgICAgICBgXCIke3JvdXRlfVwiIGNvdWxkIG9ubHkgZGVwbG95IGFzIGEgd2lsZGNhcmQgdGhhdCBhbHNvIGNhcHR1cmVzIGl0cyBgICtcbiAgICAgICAgYHNpYmxpbmdzLiBVc2UgYSBzdWJ0cmVlIGluc3RlYWQ6IFwiL2Jsb2cvKipcIiBvd25zIFwiL2Jsb2cvW3NsdWddXCIuYCxcbiAgICApO1xuICB9XG4gIGlmICgvXFwoKC4qKVxcKS8udGVzdChyb3V0ZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtFUlJPUl9QUkVGSVh9JHt3aGVyZX0gY29udGFpbnMgYSByb3V0ZSBncm91cCBzZWdtZW50LiBSb3V0ZSBncm91cHMgYCArXG4gICAgICAgIGBsaWtlIFwiKG1hcmtldGluZylcIiBvcmdhbml6ZSBmaWxlcyBhbmQgbmV2ZXIgYXBwZWFyIGluIGEgVVJMLCBzbyB0aGV5IGAgK1xuICAgICAgICBgY2Fubm90IGJlIHJvdXRlZCBvbi4gVXNlIHRoZSBVUkwgcGF0aCB0aGUgcm91dGUgaXMgc2VydmVkIGF0LmAsXG4gICAgKTtcbiAgfVxuICBjb25zdCB3aXRob3V0U3VidHJlZSA9IHJvdXRlLmVuZHNXaXRoKFNVQlRSRUVfU1VGRklYKVxuICAgID8gcm91dGUuc2xpY2UoMCwgLVNVQlRSRUVfU1VGRklYLmxlbmd0aClcbiAgICA6IHJvdXRlO1xuICBpZiAoL1sqP10vLnRlc3Qod2l0aG91dFN1YnRyZWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7RVJST1JfUFJFRklYfSR7d2hlcmV9IGNvbnRhaW5zIGEgd2lsZGNhcmQgc29tZXdoZXJlIG90aGVyIHRoYW4gYSBgICtcbiAgICAgICAgYHRyYWlsaW5nIFwiLyoqXCIuIFRoZSBvbmx5IHR3byBmb3JtcyBhcmUgYW4gZXhhY3QgcGF0aCAoXCIvcHJpY2luZ1wiKSBhbmQgYCArXG4gICAgICAgIGBhIHN1YnRyZWUgKFwiL2FwaS9yZXBvcnRzLyoqXCIpLmAsXG4gICAgKTtcbiAgfVxuICBpZiAocm91dGUuaW5jbHVkZXMoXCIvL1wiKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHtFUlJPUl9QUkVGSVh9JHt3aGVyZX0gY29udGFpbnMgYW4gZW1wdHkgcGF0aCBzZWdtZW50LmApO1xuICB9XG4gIC8vIEEgcm91dGUgTmV4dC5qcyBzZXJ2ZXMgY2FuIHN0aWxsIGhvbGQgYSBjaGFyYWN0ZXIgbm8gcGF0aCBwYXR0ZXJuIGNhbjpcbiAgLy8gYGFwcC/DvGJlci9wYWdlLnRzeGAsIGBhcHAvYSBiL3BhZ2UudHN4YCwgYGFwcC9hLGIvcGFnZS50c3hgIGFsbCBidWlsZCwgYW5kXG4gIC8vIHRoZSBwYXR0ZXJuIHBhc3NlcyBldmVyeSBjaGVjayBhYm92ZS4gYHBhdGhQYXR0ZXJuc0ZvcmAgY29waWVzIGl0IHZlcmJhdGltLFxuICAvLyBzbyBpdCByZWFjaGVkIGBhZGRCZWhhdmlvcmAgdW50b3VjaGVkIGFuZCB3YXMgbGVmdCBmb3IgQ2xvdWRGcm9udCB0byByZWplY3QsXG4gIC8vIGluIGFuIGVycm9yIG5hbWluZyBuZWl0aGVyIHRoZSBncm91cCBub3IgdGhlIHJvdXRlLiBUaGUgYHB1YmxpYy9gXG4gIC8vIHdvcmthcm91bmQsIG9uZSBgP2AgcGVyIFVURi04IGJ5dGUsIGlzIG5vdCBhdmFpbGFibGUgaGVyZTogYD9gIG1hdGNoZXMgKmFueSpcbiAgLy8gYnl0ZSwgc28gYC/DvGJlcmAgd291bGQgZGVwbG95IGFzIGAvPz9iZXJgIGFuZCBhbHNvIHNlbmQgYC94eWJlcmAgdG8gdGhpc1xuICAvLyBncm91cCdzIGZ1bmN0aW9uLCB3aG9zZSB6aXAgbGFja3MgaXRzIGVudHJ5cG9pbnQuIFRoYXQgaXMgdGhlIHNpYmxpbmcgY2FwdHVyZVxuICAvLyBkeW5hbWljIHNlZ21lbnRzIGFyZSByZWplY3RlZCBmb3IsIHNvIHRoZSBzYW1lIGFuc3dlciBhcHBsaWVzLlxuICBjb25zdCBpbnZhbGlkID0gWy4uLm5ldyBTZXQod2l0aG91dFN1YnRyZWUpXS5maWx0ZXIoXG4gICAgKGNoYXIpID0+ICFQQVRIX1BBVFRFUk5fTElURVJBTC50ZXN0KGNoYXIpLFxuICApO1xuICBpZiAoaW52YWxpZC5sZW5ndGggPiAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7RVJST1JfUFJFRklYfSR7d2hlcmV9IGNvbnRhaW5zIGAgK1xuICAgICAgICBgJHtpbnZhbGlkLm1hcCgoY2hhcikgPT4gSlNPTi5zdHJpbmdpZnkoY2hhcikpLmpvaW4oXCIsIFwiKX0sIHdoaWNoIGEgYCArXG4gICAgICAgIGBDbG91ZEZyb250IGJlaGF2aW9yIHBhdGggcGF0dGVybiBjYW5ub3QgY29udGFpbiAoYWxsb3dlZDogQS1aIGEteiAwLTkgYCArXG4gICAgICAgIGBfIC0gLiAkIC8gfiBcIiAnIEAgOiArICYpLiBFc2NhcGluZyBpdCB3aXRoIFwiP1wiIHdvdWxkIGFsc28gbWF0Y2ggb3RoZXIgYCArXG4gICAgICAgIGByb3V0ZXMgb2YgdGhlIHNhbWUgbGVuZ3RoLiBVc2UgYSBzdWJ0cmVlIG9uIGEgcGFyZW50IHNlZ21lbnQgd2hvc2UgYCArXG4gICAgICAgIGBuYW1lIGlzIHBsYWluIEFTQ0lJIGluc3RlYWQ6IFwiL2ludGwvKipcIiBvd25zIFwiL2ludGwvw7xiZXJcIi5gLFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBTcGxpdCBldmVyeSByb3V0ZSB0ZW1wbGF0ZSBhY3Jvc3MgdGhlIGdyb3VwcywgbG9uZ2VzdCBtYXRjaGluZyBwYXR0ZXJuIGZpcnN0LFxuICogdGhlbiBwcm92ZSB0aGF0IHRoZSBlZGdlIHJvdXRlcyBldmVyeSBVUkwgZWFjaCBmaWxlIHNlcnZlcyB0byB0aGUgZ3JvdXAgdGhhdFxuICogZmlsZSB3YXMgcGFja2FnZWQgaW50by5cbiAqXG4gKiBJdHMgYHRlbXBsYXRlc2AgYXJlIGtleWVkIGJ5IGdyb3VwIG5hbWUgYW5kIGFsd2F5cyBjb250YWluXG4gKiB7QGxpbmsgREVGQVVMVF9GVU5DVElPTl9HUk9VUH0sIHNvIGNhbGxlcnMgY2FuIGl0ZXJhdGUgdGhlbSBhcyB0aGUgY29tcGxldGUgc2V0XG4gKiBvZiBmdW5jdGlvbnMgdG8gZGVwbG95LiBUaGUgZGVmYXVsdCBncm91cCBpcyBhbGxvd2VkIHRvIGJlIGVtcHR5IG9mICp0ZW1wbGF0ZXMqXG4gKiDigJQgaXQgc3RpbGwgc2VydmVzIGAvX25leHQvaW1hZ2VgLCBhbnkgc3RhdGljIGZpbGUsIGFuZCBhbnl0aGluZyB0aGVcbiAqIGRpc3RyaWJ1dGlvbidzIGNhdGNoLWFsbCBiZWhhdmlvciBzZW5kcyBpdC5cbiAqXG4gKiBgYmFzZVBhdGhgIGlzIHByZXBlbmRlZCB0byBlYWNoIHBhdHRlcm4gYmVmb3JlIG1hdGNoaW5nLCBiZWNhdXNlIG1hbmlmZXN0XG4gKiB0ZW1wbGF0ZXMgYXJlIGJhc2VQYXRoLXByZWZpeGVkIGFuZCBjb25zdW1lcnMgd3JpdGUgdGhlIHJvdXRlcyB0aGVpciBhcHBcbiAqIGRlY2xhcmVzLlxuICpcbiAqIFBhY2thZ2luZyBtYXRjaGVzIHBhdHRlcm5zIGFnYWluc3QgKnRlbXBsYXRlcyosIGJ1dCBDbG91ZEZyb250IHJvdXRlcyAqVVJMcyosXG4gKiBhbmQgYSBmaWxlIGFuc3dlcnMgVVJMcyBub25lIG9mIGl0cyB0ZW1wbGF0ZXMgc3BlbGxzOiBhbiBvcHRpb25hbCBjYXRjaC1hbGwnc1xuICogcGFyZW50LCB0aGUgYHRyYWlsaW5nU2xhc2hgIGZvcm0sIGEgUGFnZXMgUm91dGVyIGRhdGEgVVJMLCBldmVyeSBvdGhlclxuICogdGVtcGxhdGUgaXQgc2hhcmVzIChyb290IHBhcmFtcyBzeW50aGVzaXplIGAvZW5gIGFuZCBgL2RlYCBmcm9tIG9uZVxuICogYFtsb2NhbGVdYCBwYWdlKS4gQW4gaW50ZXJjZXB0aW9uIHJvdXRlIGlzIHdvcnNlOiBpdCBpcyBuZXZlciByZXF1ZXN0ZWQgYXQgaXRzXG4gKiBvd24gcGF0aCBhdCBhbGwuIFNvIGFmdGVyIG1hdGNoaW5nLCBpbnRlcmNlcHRpbmcgZmlsZXMgbW92ZSB0byB0aGUgZ3JvdXAgb2ZcbiAqIHRoZSBVUkwgdGhleSBpbnRlcmNlcHQgKHtAbGluayByZWFzc2lnbkludGVyY2VwdGluZ0ZpbGVzfSksIGFuZCB0aGUgcmVzdWx0IGlzXG4gKiByZXBsYXllZCB0aHJvdWdoIHRoZSBzYW1lIGJlaGF2aW9ycyBgTmV4dGpzRGlzdHJpYnV0aW9uYCBkZXBsb3lzXG4gKiAoe0BsaW5rIGFzc2VydEVkZ2VSZWFjaGVzRXZlcnlGaWxlfSwge0BsaW5rIGFzc2VydFJld3JpdGVzU3RheUluR3JvdXB9KS4gQSBVUkxcbiAqIHRoYXQgd291bGQgcmVhY2ggYSBmdW5jdGlvbiB3aXRob3V0IGl0cyBmaWxlIHRocm93cyBoZXJlLCBkdXJpbmcgYG5leHQgYnVpbGRgLFxuICogcmF0aGVyIHRoYW4gYW5zd2VyaW5nIDQwNCBvbmNlIGRlcGxveWVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzaWduUm91dGVzVG9Hcm91cHMoXG4gIGdyb3VwczogcmVhZG9ubHkgRnVuY3Rpb25Hcm91cFNwZWNbXSxcbiAgZW50cmllczogcmVhZG9ubHkgUm91dGVFbnRyeVtdLFxuICBvcHRpb25zOiBBc3NpZ25Sb3V0ZXNPcHRpb25zLFxuKTogR3JvdXBBc3NpZ25tZW50IHtcbiAgdmFsaWRhdGVGdW5jdGlvbkdyb3Vwcyhncm91cHMpO1xuICBjb25zdCBiYXNlUGF0aCA9IGJhc2VQYXRoUHJlZml4KG9wdGlvbnMuYmFzZVBhdGgpO1xuXG4gIC8vIE1hdGNoZWQgd2l0aCB0aGUgdmVyeSBiZWhhdmlvcnMgYE5leHRqc0Rpc3RyaWJ1dGlvbmAgZGVwbG95cyBmb3IgdGhlXG4gIC8vIGRlY2xhcmVkIHBhdHRlcm5zLCBtb3N0IHNwZWNpZmljIGZpcnN0LCBzbyBwYWNrYWdpbmcgYW5kIHRoZSBlZGdlIHNoYXJlIG9uZVxuICAvLyByb3V0aW5nIG1vZGVsIGFuZCB0aGUgZmlyc3QgbWF0Y2ggaXMgdGhlIHdpbm5lci4gRGF0YSByb3V0ZXMgYXJlIGxlZnQgb3V0OlxuICAvLyBubyB0ZW1wbGF0ZSBpcyB1bmRlciBgL19uZXh0YCwgYW5kIHdoaWNoIGdyb3VwcyBoYXZlIHRoZW0gaXMgZGVjaWRlZCBieVxuICAvLyB0aGlzIGFzc2lnbm1lbnQuXG4gIGNvbnN0IGVkZ2VCYXNlID0ge1xuICAgIGJhc2VQYXRoLFxuICAgIGJ1aWxkSWQ6IG9wdGlvbnMuYnVpbGRJZCxcbiAgICB0cmFpbGluZ1NsYXNoOiBvcHRpb25zLnRyYWlsaW5nU2xhc2ggPz8gZmFsc2UsXG4gIH07XG4gIGNvbnN0IHBhdHRlcm5zID0gZWRnZUJlaGF2aW9ycyhcbiAgICBncm91cHMsXG4gICAge30sXG4gICAgeyAuLi5lZGdlQmFzZSwgZGF0YVJvdXRlR3JvdXBzOiBuZXcgU2V0KCkgfSxcbiAgKTtcblxuICBjb25zdCBtYXRjaGVkUGF0dGVybnMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgLy8gQW4gZW50cnlwb2ludCBpcyBhICpmaWxlKjsgdHdvIHRlbXBsYXRlcyBjYW4gc2hhcmUgb25lIChhIFBhZ2VzIFJvdXRlciBwYWdlXG4gIC8vIGFuZCBpdHMgYC9fbmV4dC9kYXRhLzxidWlsZElkPi/igKZqc29uYCBzaWJsaW5nKS4gU3BsaXR0aW5nIHRoZW0gYWNyb3NzIHppcHNcbiAgLy8gd291bGQgc3RhZ2UgdGhlIHNhbWUgZmlsZSB0d2ljZSBhbmQgcm91dGUgb25lIG9mIHRoZW0gdG8gYSBmdW5jdGlvbiB0aGF0XG4gIC8vIGhhcyBpdCBieSBhY2NpZGVudCwgc28gb3duZXJzaGlwIGlzIHJlY29yZGVkIHBlciBlbnRyeXBvaW50IGFuZCByZXVzZWQuXG4gIGNvbnN0IGdyb3VwT2ZFbnRyeXBvaW50ID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgLy8gV2hpY2ggYHBhdHRlcm5zYCBpbmRleCB3b24gdGhlIGVudHJ5cG9pbnQuIGBwYXR0ZXJuc2AgaXMgc29ydGVkXG4gIC8vIG1vc3Qtc3BlY2lmaWMtZmlyc3QsIHNvIGEgbG93ZXIgaW5kZXggaXMgdGhlIGJldHRlciBjbGFpbSwgYW5kIGtlZXBpbmcgaXRcbiAgLy8gc3RvcHMgYSBzZWNvbmQgdGVtcGxhdGUgdGhhdCBzaGFyZXMgdGhlIGVudHJ5cG9pbnQgZnJvbSB0YWtpbmcgaXQgb3ZlciB3aXRoXG4gIC8vIGEgKmJyb2FkZXIqIHBhdHRlcm4uIFdpdGhvdXQgaXQgdGhlIG93bmVyIHdhcyB3aGljaGV2ZXIgb2YgdGhlIHR3byB0ZW1wbGF0ZXNcbiAgLy8gYGVudHJpZXNgIGhhcHBlbmVkIHRvIHZpc2l0IGxhc3Qg4oCUIHRoZSBzYW1lIGJ1aWxkIGdyb3VwZWQgZGlmZmVyZW50bHlcbiAgLy8gZGVwZW5kaW5nIG9uIG1hbmlmZXN0IGtleSBvcmRlci5cbiAgY29uc3Qgd2lubmluZ0luZGV4T2ZFbnRyeXBvaW50ID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcblxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBsZXQgd2lubmVyOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gICAgZm9yIChjb25zdCBbaW5kZXgsIHBhdHRlcm5dIG9mIHBhdHRlcm5zLmVudHJpZXMoKSkge1xuICAgICAgaWYgKCFwYXR0ZXJuLnJlZ2V4LnRlc3QoZW50cnkudGVtcGxhdGUpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgLy8gRXZlcnkgbWF0Y2ggaXMgcmVjb3JkZWQsIG5vdCBvbmx5IHRoZSB3aW5uaW5nIG9uZS4gQSBwYXR0ZXJuIGZ1bGx5XG4gICAgICAvLyBzaGFkb3dlZCBieSBhIG5hcnJvd2VyIHBhdHRlcm4gaW4gYW5vdGhlciBncm91cCBuZXZlciB3aW5zIGFueXRoaW5nIOKAlFxuICAgICAgLy8gXCIvYXBpLyoqXCIgYWdhaW5zdCBhbiBhcHAgd2hvc2Ugb25seSBBUEkgcm91dGVzIGFyZSB1bmRlclxuICAgICAgLy8gXCIvYXBpL3JlcG9ydHMvKipcIiDigJQgc28gcmVjb3JkaW5nIGp1c3QgdGhlIHdpbm5lciBsZWZ0IGl0IGxvb2tpbmcgbGlrZSBhXG4gICAgICAvLyB0eXBvIGFuZCB0aHJldyBiZWxvdywgcmVqZWN0aW5nIHRoZSB2ZXJ5IGxheW91dCB0aGUgZHVwbGljYXRlLXBhdHRlcm5cbiAgICAgIC8vIGVycm9yIGEgZmV3IGxpbmVzIHVwIGRvY3VtZW50cyBhcyBzdXBwb3J0ZWQuXG4gICAgICBtYXRjaGVkUGF0dGVybnMuYWRkKGAke3BhdHRlcm4uZ3JvdXB9XFx1MDAwMCR7cGF0dGVybi5yb3V0ZX1gKTtcbiAgICAgIHdpbm5lciA/Pz0gaW5kZXg7XG4gICAgfVxuICAgIC8vIEFuIGludGVyY2VwdGluZyBmaWxlJ3Mgb3duIHRlbXBsYXRlIChgL2ZlZWQvKC4uKXBob3RvL1tpZF1gKSBpcyBub3QgYSBVUkxcbiAgICAvLyBhbnlvbmUgcmVxdWVzdHMsIHNvIGl0IGRvZXMgbm90IGRlY2lkZSB0aGUgZmlsZSdzIGdyb3VwOyB0aGUgVVJMIGl0XG4gICAgLy8gaW50ZXJjZXB0cyBkb2VzLCBiZWxvdy4gSXRzIG1hdGNoIHN0aWxsIGNvdW50cyBhZ2FpbnN0IHRoZSB0eXBvIGNoZWNrLlxuICAgIGlmICh3aW5uZXIgPT09IHVuZGVmaW5lZCB8fCBpc0ludGVyY2VwdGlvblRlbXBsYXRlKGVudHJ5LnRlbXBsYXRlKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IGluY3VtYmVudCA9IHdpbm5pbmdJbmRleE9mRW50cnlwb2ludC5nZXQoZW50cnkuZW50cnlwb2ludElkKTtcbiAgICBpZiAoaW5jdW1iZW50ID09PSB1bmRlZmluZWQgfHwgd2lubmVyIDwgaW5jdW1iZW50KSB7XG4gICAgICB3aW5uaW5nSW5kZXhPZkVudHJ5cG9pbnQuc2V0KGVudHJ5LmVudHJ5cG9pbnRJZCwgd2lubmVyKTtcbiAgICAgIGdyb3VwT2ZFbnRyeXBvaW50LnNldChlbnRyeS5lbnRyeXBvaW50SWQsIHBhdHRlcm5zW3dpbm5lcl0uZ3JvdXApO1xuICAgIH1cbiAgfVxuXG4gIC8vIEEgcGF0dGVybiBtYXRjaGluZyBub3RoaW5nIGlzIGEgdHlwbywgYW5kIGEgdHlwbyBoZXJlIGlzIGludmlzaWJsZTogdGhlXG4gIC8vIHJvdXRlIHN0YXlzIGluIHRoZSBkZWZhdWx0IGdyb3VwIGFuZCB0aGUgc3BsaXQgc2lsZW50bHkgZG9lcyBsZXNzIHRoYW4gaXRcbiAgLy8gd2FzIGFza2VkIHRvLiBDaGVhcCB0byBjYXRjaCwgc28gY2F0Y2ggaXQuXG4gIGZvciAoY29uc3QgZ3JvdXAgb2YgZ3JvdXBzKSB7XG4gICAgZm9yIChjb25zdCByb3V0ZSBvZiBncm91cC5yb3V0ZXMpIHtcbiAgICAgIGlmICghbWF0Y2hlZFBhdHRlcm5zLmhhcyhgJHtncm91cC5uYW1lfVxcdTAwMDAke3JvdXRlfWApKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgJHtFUlJPUl9QUkVGSVh9R3JvdXAgXCIke2dyb3VwLm5hbWV9XCIgcGF0dGVybiBcIiR7cm91dGV9XCIgbWF0Y2hlcyBubyBgICtcbiAgICAgICAgICAgIGByb3V0ZSBpbiB0aGlzIGJ1aWxkLiBgICtcbiAgICAgICAgICAgIG9wdGlvbmFsQ2F0Y2hBbGxQYXJlbnRIaW50KHJvdXRlLCBlbnRyaWVzLCBiYXNlUGF0aCkgK1xuICAgICAgICAgICAgYFBhdHRlcm5zIG1hdGNoIHJvdXRlIHRlbXBsYXRlcyBhcyBOZXh0LmpzIGRlY2xhcmVzIHRoZW0gKGUuZy4gYCArXG4gICAgICAgICAgICBgXCIvYmxvZy9bc2x1Z11cIiBpcyBtYXRjaGVkIGJ5IFwiL2Jsb2cvKipcIiksIGFuZCBwcmVyZW5kZXJlZCBwYWdlcyBhbmQgYCArXG4gICAgICAgICAgICBgc3RhdGljIGFzc2V0cyBhcmUgc2VydmVkIGZyb20gUzMgYW5kIG5lZWQgbm8gZ3JvdXAuYCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCBlZGdlOiBFZGdlT3B0aW9ucyA9IHtcbiAgICAuLi5lZGdlQmFzZSxcbiAgICAvLyBPbmx5IGEgZ3JvdXAgdGhhdCBvd25zIGEgUGFnZXMgUm91dGVyIHBhZ2UgaGFzIGRhdGEgVVJMcyB0byByb3V0ZS4gUmVhZFxuICAgIC8vIGJlZm9yZSBpbnRlcmNlcHRpb24gbW92ZXMgZmlsZXM6IHRob3NlIGFyZSBBcHAgUm91dGVyLCBuZXZlciBwYWdlcy5cbiAgICBkYXRhUm91dGVHcm91cHM6IG5ldyBTZXQoXG4gICAgICBlbnRyaWVzXG4gICAgICAgIC5maWx0ZXIoKGVudHJ5KSA9PiBlbnRyeS50eXBlID09PSBcInBhZ2VcIilcbiAgICAgICAgLm1hcChcbiAgICAgICAgICAoZW50cnkpID0+XG4gICAgICAgICAgICBncm91cE9mRW50cnlwb2ludC5nZXQoZW50cnkuZW50cnlwb2ludElkKSA/PyBERUZBVUxUX0ZVTkNUSU9OX0dST1VQLFxuICAgICAgICApLFxuICAgICksXG4gIH07XG4gIHJlYXNzaWduSW50ZXJjZXB0aW5nRmlsZXMoXG4gICAgZW50cmllcyxcbiAgICBncm91cE9mRW50cnlwb2ludCxcbiAgICBlZGdlQmVoYXZpb3JzKFxuICAgICAgZ3JvdXBzLFxuICAgICAgdGVtcGxhdGVzQnlHcm91cChncm91cHMsIGVudHJpZXMsIGdyb3VwT2ZFbnRyeXBvaW50KSxcbiAgICAgIGVkZ2UsXG4gICAgKSxcbiAgICBlZGdlLFxuICApO1xuICBjb25zdCBhc3NpZ25lZCA9IHRlbXBsYXRlc0J5R3JvdXAoZ3JvdXBzLCBlbnRyaWVzLCBncm91cE9mRW50cnlwb2ludCk7XG4gIC8vIFJlYnVpbHQgcmF0aGVyIHRoYW4gcmV1c2VkOiBhbiBpbnRlcmNlcHRpbmcgZmlsZSBuZXZlciBhZGRzIGFuIG9wdGlvbmFsXG4gIC8vIGNhdGNoLWFsbCBwYXJlbnQsIHNvIHRoaXMgaXMgdGhlIHNhbWUgbGlzdCwgYnV0IG9ubHkgYnkgdGhhdCBhcmd1bWVudC5cbiAgY29uc3QgYmVoYXZpb3JzID0gZWRnZUJlaGF2aW9ycyhncm91cHMsIGFzc2lnbmVkLCBlZGdlKTtcbiAgY29uc3Qgcm91dGVyOiBSb3V0ZXIgPSB7XG4gICAgZmlsZU9mVGVtcGxhdGU6IGZpbGVPZlRlbXBsYXRlKGVudHJpZXMpLFxuICAgIHJvdXRpbmc6IG9wdGlvbnMucm91dGluZyxcbiAgfTtcbiAgYXNzZXJ0RWRnZVJlYWNoZXNFdmVyeUZpbGUoXG4gICAgZW50cmllcyxcbiAgICBncm91cE9mRW50cnlwb2ludCxcbiAgICBiZWhhdmlvcnMsXG4gICAgZWRnZSxcbiAgICByb3V0ZXIsXG4gICk7XG4gIGFzc2VydFJld3JpdGVzU3RheUluR3JvdXAoZ3JvdXBPZkVudHJ5cG9pbnQsIGJlaGF2aW9ycywgcm91dGVyKTtcblxuICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhhc3NpZ25lZCkpIHtcbiAgICBhc3NpZ25lZFtrZXldID0gWy4uLmFzc2lnbmVkW2tleV1dLnNvcnQoKTtcbiAgfVxuICByZXR1cm4ge1xuICAgIHRlbXBsYXRlczogYXNzaWduZWQsXG4gICAgYmVoYXZpb3JzOiBiZWhhdmlvcnMubWFwKCh7IGdyb3VwLCByb3V0ZSwgcGF0dGVybiB9KSA9PiAoe1xuICAgICAgZ3JvdXAsXG4gICAgICByb3V0ZSxcbiAgICAgIHBhdHRlcm4sXG4gICAgfSkpLFxuICB9O1xufVxuXG4vKipcbiAqIFRoZSBwYXR0ZXJucyBhIGdyb3VwIGlzICpyb3V0ZWQqIG9uOiB0aGUgb25lcyBpdCBkZWNsYXJlcywgcGx1cyB0aGUgcGFyZW50XG4gKiBwYXRoIG9mIGV2ZXJ5IG9wdGlvbmFsIGNhdGNoLWFsbCBhIHN1YnRyZWUgcGF0dGVybiBtb3ZlZCBpbnRvIGl0LlxuICpcbiAqIGAvYmxvZy9bWy4uLnNsdWddXWAgc2VydmVzIGAvYmxvZ2AgYXMgd2VsbCBhcyBldmVyeXRoaW5nIHVuZGVyIGl0LCBhbmRcbiAqIGAvYmxvZy8qKmAgbW92ZXMgdGhlIHdob2xlIGZpbGUg4oCUIGJ1dCBkZXBsb3lzIGFzIGBibG9nLypgLCB3aGljaCBkb2VzIG5vdFxuICogbWF0Y2ggYC9ibG9nYC4gU28gdGhlIHBhcmVudCBpcyByb3V0ZWQgYXV0b21hdGljYWxseSwgYXMgYW4gZXhhY3QgcGF0dGVybiBvZlxuICogaXRzIG93bjsgZGVjbGFyaW5nIGAvYmxvZ2AgYnkgaGFuZCBpcyBhIHBhdHRlcm4gd2l0aCBubyByb3V0ZSBvZiBpdHMgb3duIGFuZFxuICogaXMgcmVqZWN0ZWQgYXMgYSB0eXBvLCB3aXRoIGEgaGludCBwb2ludGluZyBoZXJlLiBOb3RoaW5nIGVsc2UgYSBzdWJ0cmVlIG93bnNcbiAqIG5lZWRzIHRoaXM6IGEgZmlsZSB3aG9zZSBwYXJlbnQgVVJMIGlzIGl0cyBzdWJ0cmVlJ3MgYmFzZSBjYW4gb25seSBiZSBhblxuICogb3B0aW9uYWwgY2F0Y2gtYWxsLCBzaW5jZSBOZXh0LmpzIHJlamVjdHMgYGFwcC9ibG9nL3BhZ2UudHN4YCBuZXh0IHRvIGl0LlxuICpcbiAqIEBwYXJhbSBvd25lZFRlbXBsYXRlcyB0aGUgdGVtcGxhdGVzIGFzc2lnbmVkIHRvIHRoZSBncm91cCwgYmFzZVBhdGgtcHJlZml4ZWRcbiAqICAgYXMgYG1hbmlmZXN0Lmdyb3Vwc2AgcmVjb3JkcyB0aGVtXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByb3V0ZWRQYXR0ZXJucyhcbiAgcm91dGVzOiByZWFkb25seSBzdHJpbmdbXSxcbiAgb3duZWRUZW1wbGF0ZXM6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICBiYXNlUGF0aDogc3RyaW5nLFxuKTogc3RyaW5nW10ge1xuICBjb25zdCByZXN1bHQgPSBbLi4ucm91dGVzXTtcbiAgZm9yIChjb25zdCByb3V0ZSBvZiByb3V0ZXMpIHtcbiAgICBpZiAoIXJvdXRlLmVuZHNXaXRoKFNVQlRSRUVfU1VGRklYKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IHBhcmVudCA9IHJvdXRlLnNsaWNlKDAsIC1TVUJUUkVFX1NVRkZJWC5sZW5ndGgpO1xuICAgIGNvbnN0IHByZWZpeCA9IGAke3ByZWZpeEJhc2VQYXRoKHBhcmVudCwgYmFzZVBhdGgpfS9gO1xuICAgIGNvbnN0IG93bnNPcHRpb25hbENhdGNoQWxsID0gb3duZWRUZW1wbGF0ZXMuc29tZShcbiAgICAgICh0ZW1wbGF0ZSkgPT5cbiAgICAgICAgdGVtcGxhdGUuc3RhcnRzV2l0aChwcmVmaXgpICYmXG4gICAgICAgIE9QVElPTkFMX0NBVENIX0FMTF9TRUdNRU5ULnRlc3QodGVtcGxhdGUuc2xpY2UocHJlZml4Lmxlbmd0aCkpLFxuICAgICk7XG4gICAgaWYgKG93bnNPcHRpb25hbENhdGNoQWxsICYmICFyZXN1bHQuaW5jbHVkZXMocGFyZW50KSkge1xuICAgICAgcmVzdWx0LnB1c2gocGFyZW50KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBDbG91ZEZyb250IHBhdGggcGF0dGVybnMgZm9yIG9uZSBncm91cCBwYXR0ZXJuLCB3aXRob3V0IGEgbGVhZGluZyBzbGFzaCDigJRcbiAqIHRoZSBmb3JtIGBOZXh0anNEaXN0cmlidXRpb24uZ2V0UGF0aFBhdHRlcm5gIGV4cGVjdHMsIHNvIHRoZSBiYXNlUGF0aCBpc1xuICogYWRkZWQgdGhlcmUgcmF0aGVyIHRoYW4gaGVyZS5cbiAqXG4gKiBUd28gcGF0dGVybnMgY29tZSBiYWNrIHdoZW4gdGhlIGdyb3VwIG93bnMgYSBQYWdlcyBSb3V0ZXIgcm91dGU6IGl0cyBSU0MtZXJhXG4gKiBlcXVpdmFsZW50IGlzIGEgc2Vjb25kIFVSTCBzcGFjZSwgYC9fbmV4dC9kYXRhLzxidWlsZElkPi88cm91dGU+Lmpzb25gLCB3aGljaFxuICogdGhlIGRlZmF1bHQgYmVoYXZpb3Igd291bGQgb3RoZXJ3aXNlIHNlbmQgdG8gdGhlIGRlZmF1bHQgZ3JvdXAuXG4gKlxuICogQSB0aGlyZCBjb21lcyBiYWNrIGZvciBhbiBleGFjdCByb3V0ZSBpbiBhIGB0cmFpbGluZ1NsYXNoYCBhcHAsIHdoZXJlIHRoZVxuICogY2Fub25pY2FsIFVSTCBpcyBgL3ByaWNpbmcvYCByYXRoZXIgdGhhbiBgL3ByaWNpbmdgOiB0aGUgYmFyZSBwYXR0ZXJuIGRvZXMgbm90XG4gKiBtYXRjaCBpdCwgc28gd2l0aG91dCB0aGlzIGV2ZXJ5IHJlcXVlc3QgZm9yIHRoZSByb3V0ZSB0aGUgdXNlciBhY3R1YWxseSBsaW5rcyB0b1xuICogZmFsbHMgdGhyb3VnaCB0byB0aGUgZGVmYXVsdCBncm91cCdzIGZ1bmN0aW9uIOKAlCB3aGljaCwgZm9yIGEgUGFnZXMgUm91dGVyIEFQSVxuICogcm91dGUsIGhhcyBubyBlbnRyeXBvaW50IGZvciBpdCBhdCBhbGwuIFN1YnRyZWUgcGF0dGVybnMgbmVlZCBubyB2YXJpYW50XG4gKiAoYHByaWNpbmcvKmAgYWxyZWFkeSBtYXRjaGVzIGAvcHJpY2luZy9gKSwgYW5kIG5laXRoZXIgZG8gdGhlIGRhdGEgVVJMcywgd2hpY2hcbiAqIG5ldmVyIGNhcnJ5IHRoZSBzbGFzaC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhdGhQYXR0ZXJuc0ZvcihcbiAgcm91dGU6IHN0cmluZyxcbiAgb3B0aW9uczoge1xuICAgIGhhc0RhdGFSb3V0ZXM6IGJvb2xlYW47XG4gICAgdHJhaWxpbmdTbGFzaD86IGJvb2xlYW47XG4gICAgYnVpbGRJZD86IHN0cmluZztcbiAgfSxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgaXNTdWJ0cmVlID0gcm91dGUuZW5kc1dpdGgoU1VCVFJFRV9TVUZGSVgpO1xuICBjb25zdCBiYXNlID0gaXNTdWJ0cmVlID8gcm91dGUuc2xpY2UoMCwgLVNVQlRSRUVfU1VGRklYLmxlbmd0aCkgOiByb3V0ZTtcbiAgY29uc3QgYmFyZSA9IGJhc2UucmVwbGFjZSgvXlxcLy8sIFwiXCIpO1xuICBjb25zdCBwYXR0ZXJucyA9IFtpc1N1YnRyZWUgPyBgJHtiYXJlfS8qYCA6IGJhcmVdO1xuICBpZiAoIWlzU3VidHJlZSAmJiBvcHRpb25zLnRyYWlsaW5nU2xhc2ggJiYgYmFyZSkge1xuICAgIHBhdHRlcm5zLnB1c2goYCR7YmFyZX0vYCk7XG4gIH1cbiAgaWYgKG9wdGlvbnMuaGFzRGF0YVJvdXRlcykge1xuICAgIC8vIFRoZSBsaXRlcmFsIGJ1aWxkIElELCBub3QgYSBgKmAgZm9yIGl0LiBDbG91ZEZyb250J3MgYCpgIGFsc28gbWF0Y2hlc1xuICAgIC8vIGAvYCwgc28gYF9uZXh0L2RhdGEvKi9ibG9nLypgIGNsYWltZWQgYC9fbmV4dC9kYXRhLzxpZD4vZG9jcy9ibG9nL3guanNvbmBcbiAgICAvLyB0b28g4oCUIGFub3RoZXIgZ3JvdXAncyBwYWdlLCBzZW50IHRvIGEgZnVuY3Rpb24gd2l0aG91dCBpdC4gRXZlcnkgb3RoZXJcbiAgICAvLyBwYXR0ZXJuIGlzIGFuY2hvcmVkIGF0IHRoZSBzdGFydCBvZiB0aGUgcGF0aDsgdGhpcyBvbmUgbm93IGlzIGFzIHdlbGwuXG4gICAgLy9cbiAgICAvLyBJdCBtYWtlcyB0aGVzZSBiZWhhdmlvcnMgY2hhbmdlIHdoZW5ldmVyIHRoZSBidWlsZCBJRCBkb2VzLCB3aGljaCBpcyBldmVyeVxuICAgIC8vIGRlcGxveSB1bmxlc3MgYGRlcGxveW1lbnRJZGAgcGlucyBpdC4gQSBjbGllbnQgc3RpbGwgaG9sZGluZyB0aGUgcHJldmlvdXNcbiAgICAvLyBidWlsZCByZXF1ZXN0cyBgL19uZXh0L2RhdGEvPG9sZCBpZD4v4oCmYCwgd2hpY2ggbm8gYmVoYXZpb3IgbWF0Y2hlcywgc28gaXRcbiAgICAvLyByZWFjaGVzIHRoZSBkZWZhdWx0IGZ1bmN0aW9uLiBUaGF0IGlzIGNvcnJlY3QgcmF0aGVyIHRoYW4gbWVyZWx5XG4gICAgLy8gaGFybWxlc3M6IGBuZXh0IHN0YXJ0YCA0MDRzIGEgZGF0YSByZXF1ZXN0IGZvciBhbm90aGVyIGJ1aWxkIElEXG4gICAgLy8gKGBoYW5kbGVOZXh0RGF0YVJlcXVlc3RgIGluIGBuZXh0L2Rpc3Qvc2VydmVyL2Jhc2Utc2VydmVyLmpzYCkgYW5kIHNvIGRvZXNcbiAgICAvLyB0aGUgcnVudGltZSwgd2hpY2ggaGFzIG5vIHBhdGhuYW1lIGZvciBpdCwgYW5kIHRoZSBQYWdlcyBSb3V0ZXIgY2xpZW50XG4gICAgLy8gdHJlYXRzIGEgZGF0YSA0MDQgYXMgYW4gYXNzZXQgZXJyb3IgYW5kIGhhcmQtbmF2aWdhdGVzIHRvIHRoZSBwYWdlXG4gICAgLy8gKGBmZXRjaE5leHREYXRhYCDihpIgYG1hcmtBc3NldEVycm9yYCDihpIgYGhhbmRsZVJvdXRlSW5mb0Vycm9yYCBpblxuICAgIC8vIGBuZXh0L2Rpc3Qvc2hhcmVkL2xpYi9yb3V0ZXIvcm91dGVyLmpzYCksIHdoaWNoIGdldHMgdGhlIG5ldyBidWlsZC5cbiAgICBwYXR0ZXJucy5wdXNoKFxuICAgICAgaXNTdWJ0cmVlXG4gICAgICAgID8gYF9uZXh0L2RhdGEvJHtkYXRhQnVpbGRJZChvcHRpb25zLmJ1aWxkSWQpfS8ke2JhcmV9LypgXG4gICAgICAgIDogYF9uZXh0L2RhdGEvJHtkYXRhQnVpbGRJZChvcHRpb25zLmJ1aWxkSWQpfS8ke2JhcmV9Lmpzb25gLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHBhdHRlcm5zO1xufVxuXG4vKipcbiAqIFJhbmsgYSBDbG91ZEZyb250IHBhdGggcGF0dGVybiBzbyB0aGUgbW9zdCBzcGVjaWZpYyBpcyBhZGRlZCBmaXJzdDogbGl0ZXJhbFxuICogc2VnbWVudHMgYmVmb3JlIHRoZSBmaXJzdCBgKmAgZG9taW5hdGUsIHRoZW4gYW4gZXhhY3QgcGF0dGVybiBiZWZvcmUgYVxuICogd2lsZGNhcmQgb25lLCB0aGVuIHRvdGFsIHNlZ21lbnRzLCB0aGVuIGxlbmd0aC4ge0BsaW5rIGVkZ2VCZWhhdmlvcnN9IHNvcnRzXG4gKiBvbiBpdC5cbiAqXG4gKiBSYW5raW5nIG9uIHRoZSBsZWFkaW5nIGxpdGVyYWwgaXMgd2hhdCBhIENsb3VkRnJvbnQgd2lsZGNhcmQgZm9yY2VzLCBiZWNhdXNlXG4gKiBpdCBtYXRjaGVzIGFjcm9zcyBgL2AgcmF0aGVyIHRoYW4gd2l0aGluIG9uZSBzZWdtZW50OiBhbiBleGFjdCBgYS9iYCBoYXMgdG9cbiAqIHByZWNlZGUgdGhlIHN1YnRyZWUgYGEvKmAgdGhhdCB3b3VsZCBvdGhlcndpc2Ugc3dhbGxvdyBpdCwgdGhvdWdoIHRoZSB0d28gYXJlXG4gKiB0aGUgc2FtZSBsZW5ndGggYW5kIGRlcHRoLiBBdCBlcXVhbCBsaXRlcmFsIGRlcHRoIHRoZSBleGFjdCBvbmUgc3RpbGwgZ29lc1xuICogZmlyc3QsIHNpbmNlIGEgdHJhaWxpbmdTbGFzaCBgYS9iL2AgaXMgb3RoZXJ3aXNlIG91dHJhbmtlZCBieSB0aGUgc3VidHJlZVxuICogYGEvYi8qYCwgb25lIHNlZ21lbnQgbG9uZ2VyLCB0aGF0IG1hdGNoZXMgaXQuIFNpbmNlIHRoZSBkYXRhIHBhdHRlcm5zIGNhcnJ5XG4gKiB0aGUgbGl0ZXJhbCBidWlsZCBJRCwgbm8gcGF0dGVybiBoYXMgYSB3aWxkY2FyZCBhbnl3aGVyZSBidXQgYXQgaXRzIGVuZC5cbiAqL1xuZnVuY3Rpb24gYmVoYXZpb3JTcGVjaWZpY2l0eShwYXR0ZXJuOiBzdHJpbmcpOiBudW1iZXIge1xuICBjb25zdCBzZWdtZW50cyA9IHBhdHRlcm4uc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgY29uc3QgZmlyc3RXaWxkY2FyZCA9IHNlZ21lbnRzLmZpbmRJbmRleCgoc2VnbWVudCkgPT4gc2VnbWVudC5pbmNsdWRlcyhcIipcIikpO1xuICBjb25zdCBsaXRlcmFsRGVwdGggPSBmaXJzdFdpbGRjYXJkID09PSAtMSA/IHNlZ21lbnRzLmxlbmd0aCA6IGZpcnN0V2lsZGNhcmQ7XG4gIGNvbnN0IGV4YWN0ID0gZmlyc3RXaWxkY2FyZCA9PT0gLTEgPyAxIDogMDtcbiAgcmV0dXJuIChcbiAgICAobGl0ZXJhbERlcHRoICogMiArIGV4YWN0KSAqIDEwMDAwMDAgK1xuICAgIHNlZ21lbnRzLmxlbmd0aCAqIDEwMDAwICtcbiAgICBwYXR0ZXJuLmxlbmd0aFxuICApO1xufVxuXG4vKipcbiAqIFRoZSBidWlsZCBJRCBhcyBpdCBnb2VzIGludG8gYSBwYXRoIHBhdHRlcm4uIEEgY3VzdG9tIGBnZW5lcmF0ZUJ1aWxkSWRgIGNhblxuICogcmV0dXJuIGFueXRoaW5nLCBhbmQgYSBjaGFyYWN0ZXIgQ2xvdWRGcm9udCBjYW5ub3Qgc3BlbGwgd291bGQgb3RoZXJ3aXNlIGZhaWxcbiAqIHRoZSBkZXBsb3kgbmFtaW5nIG5laXRoZXIgdGhlIGJ1aWxkIElEIG5vciB0aGUgZ3JvdXAuXG4gKi9cbmZ1bmN0aW9uIGRhdGFCdWlsZElkKGJ1aWxkSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gIGlmICghYnVpbGRJZCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGAke0VSUk9SX1BSRUZJWH1Sb3V0aW5nIGEgUGFnZXMgUm91dGVyIGFwcCdzIFwiL19uZXh0L2RhdGEvPGJ1aWxkSWQ+L+KAplwiIGAgK1xuICAgICAgICBgVVJMcyBuZWVkcyBpdHMgYnVpbGQgSUQsIGFuZCBub25lIHdhcyBwYXNzZWQuIFRoaXMgaXMgYSBjZGstbmV4dGpzIGAgK1xuICAgICAgICBgYnVnOiB0aGUgYnVpbGQgSUQgY29tZXMgZnJvbSB0aGUgYWRhcHRlciBtYW5pZmVzdC5gLFxuICAgICk7XG4gIH1cbiAgY29uc3QgaW52YWxpZCA9IFsuLi5uZXcgU2V0KGJ1aWxkSWQpXS5maWx0ZXIoXG4gICAgKGNoYXIpID0+ICFQQVRIX1BBVFRFUk5fTElURVJBTC50ZXN0KGNoYXIpIHx8IGNoYXIgPT09IFwiL1wiLFxuICApO1xuICBpZiAoaW52YWxpZC5sZW5ndGggPiAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7RVJST1JfUFJFRklYfVRoZSBidWlsZCBJRCBcIiR7YnVpbGRJZH1cIiBjb250YWlucyBgICtcbiAgICAgICAgYCR7aW52YWxpZC5tYXAoKGNoYXIpID0+IEpTT04uc3RyaW5naWZ5KGNoYXIpKS5qb2luKFwiLCBcIil9LCB3aGljaCBhIGAgK1xuICAgICAgICBgQ2xvdWRGcm9udCBwYXRoIHBhdHRlcm4gY2Fubm90IGhvbGQsIHNvIGl0cyBcIi9fbmV4dC9kYXRhXCIgVVJMcyBjYW5ub3QgYCArXG4gICAgICAgIGBiZSByb3V0ZWQgdG8gYSBncm91cC4gTWFrZSBcXGBnZW5lcmF0ZUJ1aWxkSWRcXGAgcmV0dXJuIG9ubHkgQS1aIGEteiBgICtcbiAgICAgICAgYDAtOSBfIC0gLiBjaGFyYWN0ZXJzLmAsXG4gICAgKTtcbiAgfVxuICByZXR1cm4gYnVpbGRJZDtcbn1cblxuLyoqXG4gKiBUaGUgdHlwbyBjaGVjaydzIGhpbnQgZm9yIHRoZSBvbmUgZXhhY3QgcGF0dGVybiB0aGF0IHdhcyB0aGUgZG9jdW1lbnRlZFxuICogd29ya2Fyb3VuZDogdGhlIHBhcmVudCBvZiBhbiBvcHRpb25hbCBjYXRjaC1hbGwsIHdoaWNoIGhhcyBubyB0ZW1wbGF0ZS5cbiAqL1xuZnVuY3Rpb24gb3B0aW9uYWxDYXRjaEFsbFBhcmVudEhpbnQoXG4gIHJvdXRlOiBzdHJpbmcsXG4gIGVudHJpZXM6IHJlYWRvbmx5IFJvdXRlRW50cnlbXSxcbiAgYmFzZVBhdGg6IHN0cmluZyxcbik6IHN0cmluZyB7XG4gIGlmIChyb3V0ZS5lbmRzV2l0aChTVUJUUkVFX1NVRkZJWCkpIHtcbiAgICByZXR1cm4gXCJcIjtcbiAgfVxuICBjb25zdCBwcmVmaXggPSBgJHtwcmVmaXhCYXNlUGF0aChyb3V0ZSwgYmFzZVBhdGgpfS9gO1xuICBjb25zdCBjYXRjaEFsbCA9IGVudHJpZXMuZmluZChcbiAgICAoZW50cnkpID0+XG4gICAgICBlbnRyeS50ZW1wbGF0ZS5zdGFydHNXaXRoKHByZWZpeCkgJiZcbiAgICAgIE9QVElPTkFMX0NBVENIX0FMTF9TRUdNRU5ULnRlc3QoZW50cnkudGVtcGxhdGUuc2xpY2UocHJlZml4Lmxlbmd0aCkpLFxuICApO1xuICBpZiAoIWNhdGNoQWxsKSB7XG4gICAgcmV0dXJuIFwiXCI7XG4gIH1cbiAgcmV0dXJuIChcbiAgICBgXCIke3JvdXRlfVwiIGlzIHNlcnZlZCBieSB0aGUgb3B0aW9uYWwgY2F0Y2gtYWxsIFwiJHtjYXRjaEFsbC50ZW1wbGF0ZX1cIiwgYCArXG4gICAgYHdob3NlIHN1YnRyZWUgcGF0dGVybiBcIiR7cm91dGV9JHtTVUJUUkVFX1NVRkZJWH1cIiByb3V0ZXMgXCIke3JvdXRlfVwiIGFzIGAgK1xuICAgIGB3ZWxsIOKAlCB1c2UgdGhhdCBpbnN0ZWFkLiBgXG4gICk7XG59XG5cbi8qKiBgL2Jsb2cvW1suLi5zbHVnXV1gJ3MgbGFzdCBzZWdtZW50LiAqL1xuY29uc3QgT1BUSU9OQUxfQ0FUQ0hfQUxMX1NFR01FTlQgPSAvXlxcW1xcW1xcLlxcLlxcLlteXFxdL10rXFxdXFxdJC87XG5cbi8qKlxuICogTmV4dC5qcydzIGludGVyY2VwdGlvbiBtYXJrZXJzLCBsb25nZXN0LW92ZXJsYXBwaW5nIGZpcnN0LCBleGFjdGx5IGFzXG4gKiBgSU5URVJDRVBUSU9OX1JPVVRFX01BUktFUlNgIGluXG4gKiBgbmV4dC9kaXN0L3NoYXJlZC9saWIvcm91dGVyL3V0aWxzL2ludGVyY2VwdGlvbi1yb3V0ZXMuanNgIG9yZGVycyB0aGVtLlxuICovXG5jb25zdCBJTlRFUkNFUFRJT05fTUFSS0VSUyA9IFtcIiguLikoLi4pXCIsIFwiKC4pXCIsIFwiKC4uKVwiLCBcIiguLi4pXCJdO1xuXG5mdW5jdGlvbiBpbnRlcmNlcHRpb25NYXJrZXJPZihwYXRoOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBmb3IgKGNvbnN0IHNlZ21lbnQgb2YgcGF0aC5zcGxpdChcIi9cIikpIHtcbiAgICBjb25zdCBtYXJrZXIgPSBJTlRFUkNFUFRJT05fTUFSS0VSUy5maW5kKChpdCkgPT4gc2VnbWVudC5zdGFydHNXaXRoKGl0KSk7XG4gICAgaWYgKG1hcmtlcikge1xuICAgICAgcmV0dXJuIG1hcmtlcjtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gaXNJbnRlcmNlcHRpb25UZW1wbGF0ZSh0ZW1wbGF0ZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBpbnRlcmNlcHRpb25NYXJrZXJPZih0ZW1wbGF0ZSkgIT09IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBUaGUgcm91dGUgYW4gaW50ZXJjZXB0aW9uIHJvdXRlIGludGVyY2VwdHM6IGAvZmVlZC8oLi4pcGhvdG8vW2lkXWAg4oaSXG4gKiBgL3Bob3RvL1tpZF1gLiBgZXh0cmFjdEludGVyY2VwdGlvblJvdXRlSW5mb3JtYXRpb25gIGZyb21cbiAqIGBuZXh0L2Rpc3Qvc2hhcmVkL2xpYi9yb3V0ZXIvdXRpbHMvaW50ZXJjZXB0aW9uLXJvdXRlcy5qc2AsIHJlc3RhdGVkIGJlY2F1c2VcbiAqIHRoaXMgZmlsZSBpcyBidW5kbGVkIHdpdGhvdXQgYG5leHRgLiBUaGUgdGVtcGxhdGUgaXMgYWxyZWFkeSBhIG5vcm1hbGl6ZWQgYXBwXG4gKiBwYXRoIChubyByb3V0ZSBncm91cHMsIG5vIGBAc2xvdGBzKSwgc28gbm9uZSBvZiBpdHMgbm9ybWFsaXphdGlvbiBpcyBuZWVkZWQuXG4gKiBOZXh0LmpzJ3MgaW50ZXJjZXB0aW9uIHJld3JpdGUgbWF0Y2hlcyBleGFjdGx5IHRoaXMgcGF0aCwgYW5kIG9ubHkgd2l0aCBhXG4gKiBgTmV4dC1VcmxgIGhlYWRlciDigJQgd2hpY2ggQ2xvdWRGcm9udCBkb2VzIG5vdCByb3V0ZSBvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGludGVyY2VwdGVkUm91dGUocGF0aDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgbWFya2VyID0gaW50ZXJjZXB0aW9uTWFya2VyT2YocGF0aCk7XG4gIGlmIChtYXJrZXIgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgYXQgPSBwYXRoLmluZGV4T2YobWFya2VyKTtcbiAgY29uc3QgaW50ZXJjZXB0aW5nID0gcGF0aC5zbGljZSgwLCBhdCkuc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgY29uc3QgcmVzdCA9IHBhdGhcbiAgICAuc2xpY2UoYXQgKyBtYXJrZXIubGVuZ3RoKVxuICAgIC5zcGxpdChcIi9cIilcbiAgICAuZmlsdGVyKEJvb2xlYW4pO1xuICBjb25zdCBwYXJlbnQgPVxuICAgIG1hcmtlciA9PT0gXCIoLilcIlxuICAgICAgPyBpbnRlcmNlcHRpbmdcbiAgICAgIDogbWFya2VyID09PSBcIiguLilcIlxuICAgICAgICA/IGludGVyY2VwdGluZy5zbGljZSgwLCAtMSlcbiAgICAgICAgOiBtYXJrZXIgPT09IFwiKC4uKSguLilcIlxuICAgICAgICAgID8gaW50ZXJjZXB0aW5nLnNsaWNlKDAsIC0yKVxuICAgICAgICAgIDogW107XG4gIHJldHVybiBgLyR7Wy4uLnBhcmVudCwgLi4ucmVzdF0uam9pbihcIi9cIil9YDtcbn1cblxuLyoqXG4gKiBUZW1wbGF0ZXMgdGhhdCBuYW1lIHdoYXQgYSByZXF1ZXN0IGlzICpyZXdyaXR0ZW4qIHRvIGluc2lkZSBOZXh0LmpzLCBuZXZlclxuICogd2hhdCB0aGUgYnJvd3NlciBhc2tzIGZvcjogdGhlIFJTQyBwYXlsb2FkIChgL3ByaWNpbmcucnNjYCkgYW5kIHNlZ21lbnRcbiAqIHByZWZldGNoZXMgKGAvcHJpY2luZy5zZWdtZW50cy/igKZgKSBhcmUgcmVxdWVzdGVkIGFzIGAvcHJpY2luZ2Agd2l0aCBhbiBgUlNDYFxuICogaGVhZGVyLCB3aGljaCBpcyB3aHkgYHByaWNpbmdgIGFsb25lIGhhcyBhbHdheXMgcm91dGVkIHRoZW0uXG4gKi9cbmZ1bmN0aW9uIGlzSW50ZXJuYWxUZW1wbGF0ZShwYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHBhdGguZW5kc1dpdGgoXCIucnNjXCIpIHx8IHBhdGguaW5jbHVkZXMoXCIuc2VnbWVudHMvXCIpO1xufVxuXG4vKiogV2hhdCB0aGUgZWRnZSByb3V0ZXMgb24uICovXG5pbnRlcmZhY2UgRWRnZU9wdGlvbnMge1xuICAvKiogV2l0aCBhIGxlYWRpbmcgc2xhc2gsIGBcIlwiYCBmb3Igbm9uZS4gKi9cbiAgcmVhZG9ubHkgYmFzZVBhdGg6IHN0cmluZztcbiAgcmVhZG9ubHkgYnVpbGRJZD86IHN0cmluZztcbiAgcmVhZG9ubHkgdHJhaWxpbmdTbGFzaDogYm9vbGVhbjtcbiAgLyoqIFRoZSBncm91cHMgdGhhdCBvd24gYSBQYWdlcyBSb3V0ZXIgcGFnZSwgYW5kIHNvIGhhdmUgZGF0YSBVUkxzLiAqL1xuICByZWFkb25seSBkYXRhUm91dGVHcm91cHM6IFJlYWRvbmx5U2V0PHN0cmluZz47XG59XG5cbi8qKiBBIHtAbGluayBHcm91cEJlaGF2aW9yfSwgd2l0aCB0aGUgcmVnZXggQ2xvdWRGcm9udCBtYXRjaGVzIGl0IGFzLiAqL1xuaW50ZXJmYWNlIEVkZ2VCZWhhdmlvciBleHRlbmRzIEdyb3VwQmVoYXZpb3Ige1xuICByZWFkb25seSByZWdleDogUmVnRXhwO1xufVxuXG4vKipcbiAqIEV2ZXJ5IGdyb3VwIGJlaGF2aW9yLCBtb3N0IHNwZWNpZmljIGZpcnN0OiB0aGUgb3JkZXIgQ2xvdWRGcm9udCBoYXMgdG8gc2VlXG4gKiB0aGVtIGluLCBzaW5jZSBpdCBzdG9wcyBhdCB0aGUgZmlyc3QgbWF0Y2guIFRoZSBhc3NpZ25tZW50IHJldHVybnMgdGhpcyBsaXN0XG4gKiBhbmQgdGhlIGNvbnN0cnVjdHMgZGVwbG95IGl0IGFzIGl0IGlzLlxuICovXG5mdW5jdGlvbiBlZGdlQmVoYXZpb3JzKFxuICBncm91cHM6IHJlYWRvbmx5IEZ1bmN0aW9uR3JvdXBTcGVjW10sXG4gIGFzc2lnbmVkOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT4sXG4gIGVkZ2U6IEVkZ2VPcHRpb25zLFxuKTogRWRnZUJlaGF2aW9yW10ge1xuICByZXR1cm4gZ3JvdXBzXG4gICAgLmZsYXRNYXAoKGdyb3VwKSA9PlxuICAgICAgcm91dGVkUGF0dGVybnMoXG4gICAgICAgIGdyb3VwLnJvdXRlcyxcbiAgICAgICAgYXNzaWduZWRbZ3JvdXAubmFtZV0gPz8gW10sXG4gICAgICAgIGVkZ2UuYmFzZVBhdGgsXG4gICAgICApLmZsYXRNYXAoKHJvdXRlKSA9PlxuICAgICAgICBwYXRoUGF0dGVybnNGb3Iocm91dGUsIHtcbiAgICAgICAgICB0cmFpbGluZ1NsYXNoOiBlZGdlLnRyYWlsaW5nU2xhc2gsXG4gICAgICAgICAgYnVpbGRJZDogZWRnZS5idWlsZElkLFxuICAgICAgICAgIGhhc0RhdGFSb3V0ZXM6IGVkZ2UuZGF0YVJvdXRlR3JvdXBzLmhhcyhncm91cC5uYW1lKSxcbiAgICAgICAgfSkubWFwKChwYXR0ZXJuKSA9PiAoe1xuICAgICAgICAgIGdyb3VwOiBncm91cC5uYW1lLFxuICAgICAgICAgIHJvdXRlLFxuICAgICAgICAgIHBhdHRlcm4sXG4gICAgICAgICAgcmVnZXg6IGNsb3VkRnJvbnRQYXR0ZXJuUmVnZXgoYCR7ZWRnZS5iYXNlUGF0aH0vJHtwYXR0ZXJufWApLFxuICAgICAgICB9KSksXG4gICAgICApLFxuICAgIClcbiAgICAuc29ydChcbiAgICAgIChhLCBiKSA9PiBiZWhhdmlvclNwZWNpZmljaXR5KGIucGF0dGVybikgLSBiZWhhdmlvclNwZWNpZmljaXR5KGEucGF0dGVybiksXG4gICAgKTtcbn1cblxuLyoqXG4gKiBDbG91ZEZyb250IHBhdGggcGF0dGVybiBtYXRjaGluZzogYW5jaG9yZWQgYXQgYm90aCBlbmRzLCBgKmAgZm9yIGFueSBydW4gb2ZcbiAqIGNoYXJhY3RlcnMgYC9gIGluY2x1ZGVkLCBgP2AgZm9yIGV4YWN0bHkgb25lLCBjYXNlLXNlbnNpdGl2ZS4gYHBhdHRlcm5gIGhhcyB0b1xuICogY2FycnkgdGhlIGxlYWRpbmcgc2xhc2ggQ2xvdWRGcm9udCBpbXBsaWVzLlxuICpcbiAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkRnJvbnQvbGF0ZXN0L0RldmVsb3Blckd1aWRlL0Rvd25sb2FkRGlzdFZhbHVlc0NhY2hlQmVoYXZpb3IuaHRtbCNEb3dubG9hZERpc3RWYWx1ZXNQYXRoUGF0dGVyblxuICovXG5leHBvcnQgZnVuY3Rpb24gY2xvdWRGcm9udFBhdHRlcm5SZWdleChwYXR0ZXJuOiBzdHJpbmcpOiBSZWdFeHAge1xuICBjb25zdCBzb3VyY2UgPSBbLi4ucGF0dGVybl1cbiAgICAubWFwKChjaGFyKSA9PlxuICAgICAgY2hhciA9PT0gXCIqXCJcbiAgICAgICAgPyBcIi4qXCJcbiAgICAgICAgOiBjaGFyID09PSBcIj9cIlxuICAgICAgICAgID8gXCIuXCJcbiAgICAgICAgICA6IGNoYXIucmVwbGFjZSgvWy4qKz9eJHt9KCl8W1xcXVxcXFxdL2csIFwiXFxcXCQmXCIpLFxuICAgIClcbiAgICAuam9pbihcIlwiKTtcbiAgcmV0dXJuIG5ldyBSZWdFeHAoYF4ke3NvdXJjZX0kYCk7XG59XG5cbi8qKiBUaGUgYmVoYXZpb3IgQ2xvdWRGcm9udCB3b3VsZCBwaWNrIGZvciBgdXJsYCwgYHVuZGVmaW5lZGAgZm9yIHRoZSBkZWZhdWx0IG9uZS4gKi9cbmZ1bmN0aW9uIGVkZ2VCZWhhdmlvckZvcihcbiAgYmVoYXZpb3JzOiByZWFkb25seSBFZGdlQmVoYXZpb3JbXSxcbiAgdXJsOiBzdHJpbmcsXG4pOiBFZGdlQmVoYXZpb3IgfCB1bmRlZmluZWQge1xuICByZXR1cm4gYmVoYXZpb3JzLmZpbmQoKGJlaGF2aW9yKSA9PiBiZWhhdmlvci5yZWdleC50ZXN0KHVybCkpO1xufVxuXG5mdW5jdGlvbiB0ZW1wbGF0ZXNCeUdyb3VwKFxuICBncm91cHM6IHJlYWRvbmx5IEZ1bmN0aW9uR3JvdXBTcGVjW10sXG4gIGVudHJpZXM6IHJlYWRvbmx5IFJvdXRlRW50cnlbXSxcbiAgZ3JvdXBPZkVudHJ5cG9pbnQ6IFJlYWRvbmx5TWFwPHN0cmluZywgc3RyaW5nPixcbik6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPiB7XG4gIGNvbnN0IGFzc2lnbmVkOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT4gPSB7XG4gICAgW0RFRkFVTFRfRlVOQ1RJT05fR1JPVVBdOiBbXSxcbiAgfTtcbiAgZm9yIChjb25zdCBncm91cCBvZiBncm91cHMpIHtcbiAgICBhc3NpZ25lZFtncm91cC5uYW1lXSA9IFtdO1xuICB9XG4gIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgIGNvbnN0IGdyb3VwID1cbiAgICAgIGdyb3VwT2ZFbnRyeXBvaW50LmdldChlbnRyeS5lbnRyeXBvaW50SWQpID8/IERFRkFVTFRfRlVOQ1RJT05fR1JPVVA7XG4gICAgYXNzaWduZWRbZ3JvdXBdLnB1c2goZW50cnkudGVtcGxhdGUpO1xuICB9XG4gIHJldHVybiBhc3NpZ25lZDtcbn1cblxuLyoqXG4gKiBQdXQgZWFjaCBpbnRlcmNlcHRpbmcgZmlsZSBpbiB0aGUgZ3JvdXAgb2YgdGhlIFVSTCBpdCBpbnRlcmNlcHRzLlxuICpcbiAqIFdpdGggYC9mZWVkLyoqYCBncm91cGVkLCBgYXBwL2ZlZWQvKC4uKXBob3RvL1tpZF0vcGFnZS50c3hgIG1hdGNoZWQgaXQgYW5kXG4gKiBtb3ZlZCB0byB0aGUgZmVlZCBncm91cC4gQnV0IHRoZSBzb2Z0IG5hdmlnYXRpb24gaXQgZXhpc3RzIGZvciByZXF1ZXN0c1xuICogYC9waG90by8xYCB3aXRoIGEgYE5leHQtVXJsOiAvZmVlZGAgaGVhZGVyOyBDbG91ZEZyb250IHJvdXRlcyBvbiB0aGUgVVJMIGFsb25lLFxuICogc28gdGhlIHJlcXVlc3QgcmVhY2hlcyB3aGljaGV2ZXIgZnVuY3Rpb24gb3ducyBgL3Bob3RvLypgLCB3aGVyZSBOZXh0LmpzJ3NcbiAqIGludGVyY2VwdGlvbiByZXdyaXRlIChhIGBiZWZvcmVGaWxlc2AgcnVsZSBvbiB0aGF0IGhlYWRlcikgcmVzb2x2ZXMgaXQgdG8gdGhlXG4gKiBpbnRlcmNlcHRpbmcgZmlsZSDigJQgd2hpY2ggdGhhdCBmdW5jdGlvbiBkaWQgbm90IGhhdmUuXG4gKlxuICogTW92aW5nIHRoZSBmaWxlIHRoZXJlIGlzIGFsd2F5cyBwb3NzaWJsZSB1bmxlc3MgdGhlIGludGVyY2VwdGVkIFVSTCBzcGFjZSBpc1xuICogaXRzZWxmIHNwbGl0OiBgL3Bob3RvL1tpZF1gIGluIHRoZSBkZWZhdWx0IGdyb3VwIHdpdGggYC9waG90by8xYCBncm91cGVkXG4gKiBlbHNld2hlcmUgd291bGQgbmVlZCB0aGUgZmlsZSBpbiBib3RoLiBUaGF0IHRocm93cy5cbiAqL1xuZnVuY3Rpb24gcmVhc3NpZ25JbnRlcmNlcHRpbmdGaWxlcyhcbiAgZW50cmllczogcmVhZG9ubHkgUm91dGVFbnRyeVtdLFxuICBncm91cE9mRW50cnlwb2ludDogTWFwPHN0cmluZywgc3RyaW5nPixcbiAgYmVoYXZpb3JzOiByZWFkb25seSBFZGdlQmVoYXZpb3JbXSxcbiAgZWRnZTogRWRnZU9wdGlvbnMsXG4pOiB2b2lkIHtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgY29uc3QgcGF0aCA9IHN0cmlwQmFzZVBhdGgoZW50cnkudGVtcGxhdGUsIGVkZ2UuYmFzZVBhdGgpO1xuICAgIGlmIChwYXRoID09PSB1bmRlZmluZWQgfHwgaXNJbnRlcm5hbFRlbXBsYXRlKHBhdGgpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgdGFyZ2V0ID0gaW50ZXJjZXB0ZWRSb3V0ZShwYXRoKTtcbiAgICBpZiAodGFyZ2V0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCB1cmwgPSB3aXRoQmFzZVBhdGgodGFyZ2V0LCBlZGdlLmJhc2VQYXRoKTtcbiAgICBjb25zdCBncm91cCA9XG4gICAgICBlZGdlQmVoYXZpb3JGb3IoYmVoYXZpb3JzLCB1cmwpPy5ncm91cCA/PyBERUZBVUxUX0ZVTkNUSU9OX0dST1VQO1xuICAgIGNvbnN0IGludGVyY2VwdGVkID0gdGVtcGxhdGVSZWdleCh1cmwpO1xuICAgIGNvbnN0IHNwbGl0ID0gYmVoYXZpb3JzLmZpbmQoXG4gICAgICAoYmVoYXZpb3IpID0+XG4gICAgICAgIGJlaGF2aW9yLmdyb3VwICE9PSBncm91cCAmJlxuICAgICAgICAhYmVoYXZpb3IucGF0dGVybi5zdGFydHNXaXRoKFwiX25leHQvZGF0YS9cIikgJiZcbiAgICAgICAgc2FtcGxlVXJsKGJlaGF2aW9yLnJvdXRlLCBlZGdlLmJhc2VQYXRoKS5zb21lKChpdCkgPT5cbiAgICAgICAgICBpbnRlcmNlcHRlZC50ZXN0KGl0KSxcbiAgICAgICAgKSxcbiAgICApO1xuICAgIGlmIChzcGxpdCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtFUlJPUl9QUkVGSVh9XCIke2VudHJ5LmVudHJ5cG9pbnRJZH1cIiBpcyB0aGUgaW50ZXJjZXB0aW9uIHJvdXRlIGAgK1xuICAgICAgICAgIGBcIiR7ZW50cnkudGVtcGxhdGV9XCIsIHdoaWNoIE5leHQuanMgcmVhY2hlcyBieSByZXdyaXRpbmcgYSByZXF1ZXN0IGZvciBgICtcbiAgICAgICAgICBgXCIke3VybH1cIiBpbnNpZGUgd2hpY2hldmVyIGZ1bmN0aW9uIENsb3VkRnJvbnQgc2VudCBpdCB0byDigJQgc28gaXQgaXMgYCArXG4gICAgICAgICAgYHBhY2thZ2VkIHdpdGggdGhlIGdyb3VwIHRoYXQgb3ducyBcIiR7dXJsfVwiLiBUaGF0IFVSTCBzcGFjZSBpcyBzcGxpdCwgYCArXG4gICAgICAgICAgYHRob3VnaDogbW9zdCBvZiBpdCByZWFjaGVzICR7Z3JvdXBMYWJlbChncm91cCl9LCBidXQgZ3JvdXAgYCArXG4gICAgICAgICAgYFwiJHtzcGxpdC5ncm91cH1cIidzIHBhdHRlcm4gXCIke3NwbGl0LnJvdXRlfVwiIGNsYWltcyBwYXJ0IG9mIGl0LCBhbmQgYCArXG4gICAgICAgICAgYG9uZSBmaWxlIGNhbm5vdCBiZSBpbiBib3RoLiBSb3V0ZSBhbGwgb2YgXCIke3RhcmdldH1cIiB0byBvbmUgZ3JvdXAuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGdyb3VwT2ZFbnRyeXBvaW50LnNldChlbnRyeS5lbnRyeXBvaW50SWQsIGdyb3VwKTtcbiAgfVxufVxuXG4vKiogQSBVUkwgYSBncm91cCBwYXR0ZXJuIHJvdXRlcywgdG8gdGVzdCBhZ2FpbnN0IGFub3RoZXIgcm91dGUncyBVUkwgc3BhY2UuICovXG5mdW5jdGlvbiBzYW1wbGVVcmwocm91dGU6IHN0cmluZywgYmFzZVBhdGg6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIHJvdXRlLmVuZHNXaXRoKFNVQlRSRUVfU1VGRklYKVxuICAgID8gW2Ake2Jhc2VQYXRofSR7cm91dGUuc2xpY2UoMCwgLVNVQlRSRUVfU1VGRklYLmxlbmd0aCl9L19gXVxuICAgIDogW2Ake2Jhc2VQYXRofSR7cm91dGV9YF07XG59XG5cbi8qKiBUaGUgVVJMcyBhIHRlbXBsYXRlIHN0YW5kcyBmb3IsIGFzIGEgcmVnZXg6IGBbaWRdYCBpcyBvbmUgc2VnbWVudCwgYW5kIHNvIG9uLiAqL1xuZnVuY3Rpb24gdGVtcGxhdGVSZWdleCh0ZW1wbGF0ZTogc3RyaW5nKTogUmVnRXhwIHtcbiAgY29uc3Qgc291cmNlID0gdGVtcGxhdGVcbiAgICAuc3BsaXQoXCIvXCIpXG4gICAgLmZpbHRlcihCb29sZWFuKVxuICAgIC5tYXAoXG4gICAgICAoc2VnbWVudCkgPT5cbiAgICAgICAgW1xuICAgICAgICAgIGAvJHtzZWdtZW50LnJlcGxhY2UoL1suKis/XiR7fSgpfFtcXF1cXFxcXS9nLCBcIlxcXFwkJlwiKX1gLFxuICAgICAgICAgIFwiL1teL10rXCIsXG4gICAgICAgICAgXCIvLitcIixcbiAgICAgICAgICBcIig/Oi8uKyk/XCIsXG4gICAgICAgIF1bc2VnbWVudEtpbmQoc2VnbWVudCldLFxuICAgIClcbiAgICAuam9pbihcIlwiKTtcbiAgcmV0dXJuIG5ldyBSZWdFeHAoYF4ke3NvdXJjZSB8fCBcIi9cIn0kYCk7XG59XG5cbi8qKlxuICogVGhyb3cgdW5sZXNzIGV2ZXJ5IFVSTCBlYWNoIGZpbGUgc2VydmVzIHJlYWNoZXMgdGhlIGdyb3VwIGhvbGRpbmcgaXQuXG4gKlxuICogQ2hlY2tlZCBmb3IgZXZlcnkgZmlsZSwgdGhlIGRlZmF1bHQgZ3JvdXAncyBpbmNsdWRlZDogdGhlIGludmFyaWFudCBpcyBcInRoZVxuICogZWRnZSBuZXZlciBzZW5kcyBhIHJlcXVlc3QgdG8gYSBmdW5jdGlvbiB3aXRob3V0IGl0cyBmaWxlXCIsIGFuZCBhIGdyb3VwXG4gKiBwYXR0ZXJuIGNhbiBicmVhayBpdCBieSBjbGFpbWluZyBhIFVSTCBvZiBhIGZpbGUgbGVmdCBpbiB0aGUgZGVmYXVsdCBncm91cCBhc1xuICogZWFzaWx5IGFzIGJ5IGxlYXZpbmcgb25lIGJlaGluZC4gQSBkeW5hbWljIHRlbXBsYXRlIHN0YW5kcyBmb3IgYSBVUkwgc3BhY2UsXG4gKiBub3Qgb25lIFVSTCwgc28gaXQgaXMgYWxzbyBjaGVja2VkIGFnYWluc3QgdGhlIHBhcnQgb2YgdGhhdCBzcGFjZSBvdGhlclxuICogZ3JvdXBzJyBwYXR0ZXJucyBjYXB0dXJlICh7QGxpbmsgY2FwdHVyZWREeW5hbWljVXJsc30pOiBhIGAvWy4uLnNsdWddYCBsZWZ0IGluXG4gKiB0aGUgZGVmYXVsdCBncm91cCBhbnN3ZXJzIGAvYmxvZy9hL2JgIHRvbywgd2hpY2ggYC9ibG9nLyoqYCBzZW5kcyBlbHNld2hlcmUuXG4gKlxuICogT25seSB0aGUgVVJMcyBhcyBOZXh0LmpzIHNwZWxscyB0aGVtIGFyZSByZXBsYXllZCwgYW5kIHRoYXQgaXMgYSBrbm93biBnYXBcbiAqIHJhdGhlciB0aGFuIGFuIG92ZXJzaWdodDogQ2xvdWRGcm9udCBwYXRoIHBhdHRlcm5zIGFuZCBBUEkgR2F0ZXdheSByZXNvdXJjZXNcbiAqIGJvdGggbWF0Y2ggY2FzZS1zZW5zaXRpdmVseSwgd2hpbGUgYEBuZXh0L3JvdXRpbmdgIG1hdGNoZXMgdGVtcGxhdGVzXG4gKiBjYXNlLWluc2Vuc2l0aXZlbHkuIGAvQVBJL3JlcG9ydHMvMWAgdGhlcmVmb3JlIG1pc3NlcyBhIGAvYXBpL3JlcG9ydHMvKipgXG4gKiBncm91cCBhbmQgcmVhY2hlcyB0aGUgZGVmYXVsdCBmdW5jdGlvbiwgd2hpY2ggcmVzb2x2ZXMgaXQgdG8gYSB0ZW1wbGF0ZSBpdFxuICogZG9lcyBub3QgaGF2ZS4gTmVpdGhlciBlZGdlIGNhbiBiZSB0b2xkIHRvIGZvbGQgY2FzZSwgYW5kIGxvd2VyY2FzaW5nIGF0IHRoZVxuICogZWRnZSB3b3VsZCBicmVhayB0aGUgY2FzZS1zZW5zaXRpdmUgUzMga2V5cyBiZWhpbmQgYHB1YmxpYy9gLCBzbyB0aGVyZSBpc1xuICogbm90aGluZyB0byBjaGVjayBoZXJlIHRoYXQgY291bGQgcGFzczsgdGhlIHJ1bnRpbWUgYW5zd2VycyBzdWNoIGEgcmVxdWVzdFxuICogaXRzZWxmIChzZWUgYG93bmVkUm91dGVFcnJvcmApLlxuICovXG5mdW5jdGlvbiBhc3NlcnRFZGdlUmVhY2hlc0V2ZXJ5RmlsZShcbiAgZW50cmllczogcmVhZG9ubHkgUm91dGVFbnRyeVtdLFxuICBncm91cE9mRW50cnlwb2ludDogUmVhZG9ubHlNYXA8c3RyaW5nLCBzdHJpbmc+LFxuICBiZWhhdmlvcnM6IHJlYWRvbmx5IEVkZ2VCZWhhdmlvcltdLFxuICBlZGdlOiBFZGdlT3B0aW9ucyxcbiAgcm91dGVyOiBSb3V0ZXIsXG4pOiB2b2lkIHtcbiAgY29uc3QgZmlsZXMgPSBuZXcgTWFwPHN0cmluZywgUm91dGVFbnRyeVtdPigpO1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBjb25zdCBsaXN0ID0gZmlsZXMuZ2V0KGVudHJ5LmVudHJ5cG9pbnRJZCkgPz8gW107XG4gICAgbGlzdC5wdXNoKGVudHJ5KTtcbiAgICBmaWxlcy5zZXQoZW50cnkuZW50cnlwb2ludElkLCBsaXN0KTtcbiAgfVxuICAvLyBEZWVwIGVub3VnaCBmb3IgYSBzYW1wbGUgdG8gZ2V0IHBhc3QgZXZlcnkgdGVtcGxhdGUgYSBjYXB0dXJpbmcgZ3JvdXBcbiAgLy8gY291bGQgc2hhZG93IGl0IHdpdGguXG4gIGNvbnN0IGRlZXBlc3QgPVxuICAgIE1hdGgubWF4KFxuICAgICAgMCxcbiAgICAgIC4uLmVudHJpZXMubWFwKChlbnRyeSkgPT4ge1xuICAgICAgICBjb25zdCBwYXRoID0gc3RyaXBCYXNlUGF0aChlbnRyeS50ZW1wbGF0ZSwgZWRnZS5iYXNlUGF0aCk7XG4gICAgICAgIHJldHVybiBwYXRoICE9PSB1bmRlZmluZWQgJiYgaXNSb3V0YWJsZVBhdGgocGF0aClcbiAgICAgICAgICA/IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKS5sZW5ndGhcbiAgICAgICAgICA6IDA7XG4gICAgICB9KSxcbiAgICApICsgMTtcbiAgZm9yIChjb25zdCBbZmlsZSwgZmlsZUVudHJpZXNdIG9mIGZpbGVzKSB7XG4gICAgY29uc3Qgb3duZXIgPSBncm91cE9mRW50cnlwb2ludC5nZXQoZmlsZSkgPz8gREVGQVVMVF9GVU5DVElPTl9HUk9VUDtcbiAgICBjb25zdCBtaXNyb3V0ZWQ6IE1pc3JvdXRlW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGZpbGVFbnRyaWVzKSB7XG4gICAgICBmb3IgKGNvbnN0IHVybCBvZiBzZXJ2ZWRVcmxzKGVudHJ5LnRlbXBsYXRlLCBlbnRyeS50eXBlLCBlZGdlKSkge1xuICAgICAgICBjb25zdCBiZWhhdmlvciA9IGVkZ2VCZWhhdmlvckZvcihiZWhhdmlvcnMsIHVybCk7XG4gICAgICAgIGNvbnN0IGdyb3VwID0gYmVoYXZpb3I/Lmdyb3VwID8/IERFRkFVTFRfRlVOQ1RJT05fR1JPVVA7XG4gICAgICAgIGlmIChncm91cCAhPT0gb3duZXIgJiYgIW1pc3JvdXRlZC5zb21lKChpdCkgPT4gaXQudXJsID09PSB1cmwpKSB7XG4gICAgICAgICAgbWlzcm91dGVkLnB1c2goeyB1cmwsIGdyb3VwLCByb3V0ZTogYmVoYXZpb3I/LnJvdXRlIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBmb3IgKGNvbnN0IGl0IG9mIGNhcHR1cmVkRHluYW1pY1VybHMoXG4gICAgICAgIGVudHJ5LFxuICAgICAgICBvd25lcixcbiAgICAgICAgZGVlcGVzdCxcbiAgICAgICAgYmVoYXZpb3JzLFxuICAgICAgICBlZGdlLFxuICAgICAgICByb3V0ZXIsXG4gICAgICApKSB7XG4gICAgICAgIGlmICghbWlzcm91dGVkLnNvbWUoKGtub3duKSA9PiBrbm93bi51cmwgPT09IGl0LnVybCkpIHtcbiAgICAgICAgICBtaXNyb3V0ZWQucHVzaChpdCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKG1pc3JvdXRlZC5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IobWlzcm91dGVkRmlsZU1lc3NhZ2UoZmlsZSwgb3duZXIsIG1pc3JvdXRlZCwgZWRnZSkpO1xuICAgIH1cbiAgfVxufVxuXG5pbnRlcmZhY2UgTWlzcm91dGUge1xuICByZWFkb25seSB1cmw6IHN0cmluZztcbiAgLyoqIFdoZXJlIENsb3VkRnJvbnQgc2VuZHMgaXQuICovXG4gIHJlYWRvbmx5IGdyb3VwOiBzdHJpbmc7XG4gIC8qKiBUaGUgcGF0dGVybiB0aGF0IHNlbnQgaXQgdGhlcmUsIGB1bmRlZmluZWRgIGZvciB0aGUgZGVmYXVsdCBiZWhhdmlvci4gKi9cbiAgcmVhZG9ubHkgcm91dGU/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBTZXQgd2hlbiBgdXJsYCBpcyBhIHNhbXBsZSBvZiBhIGR5bmFtaWMgdGVtcGxhdGUncyBVUkwgc3BhY2UgcmF0aGVyIHRoYW5cbiAgICogYSBVUkwgdGhlIHRlbXBsYXRlIHNwZWxsczogdGhlIHRlbXBsYXRlIE5leHQuanMgcmVzb2x2ZXMgaXQgdG8gdGhlcmUuXG4gICAqL1xuICByZWFkb25seSBzZXJ2ZWRBcz86IHN0cmluZztcbn1cblxuLyoqXG4gKiBTdGFuZHMgaW4gZm9yIFwiYW55IHZhbHVlXCIgb2YgYSBkeW5hbWljIHNlZ21lbnQgaW4gYSBzYW1wbGUgVVJMLiBBIGxpdGVyYWxcbiAqIHRlbXBsYXRlIG9mIHRoYXQgZXhhY3QgbmFtZSB3b3VsZCBzaGFkb3cgaXQsIHdoaWNoIGNhbiBvbmx5IGhpZGUgYSBtaXNyb3V0ZSxcbiAqIG5ldmVyIGludmVudCBvbmUuXG4gKi9cbmNvbnN0IEFOWV9TRUdNRU5UID0gXCJfXCI7XG5cbi8qKlxuICogV2hldGhlciBhIHJlcXVlc3QgY2FuIHJlc29sdmUgdG8gYHBhdGhgIChiYXNlUGF0aCBzdHJpcHBlZCkgZGlyZWN0bHk6IG5vdCBhblxuICogUlNDIG9yIHNlZ21lbnQgcmV3cml0ZSwgYW4gaW50ZXJjZXB0aW9uIHJvdXRlLCBvciBhIGRhdGEtVVJMIGFsaWFzIChhIGRhdGEgVVJMXG4gKiByZXNvbHZlcyB0byB0aGUgcGFnZSBpdCBuYW1lcykuXG4gKi9cbmZ1bmN0aW9uIGlzUm91dGFibGVQYXRoKHBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgICFpc0ludGVybmFsVGVtcGxhdGUocGF0aCkgJiZcbiAgICAhaXNJbnRlcmNlcHRpb25UZW1wbGF0ZShwYXRoKSAmJlxuICAgICFwYXRoLnN0YXJ0c1dpdGgoXCIvX25leHQvZGF0YS9cIilcbiAgKTtcbn1cblxuLyoqIDAgc3RhdGljLCAxIGBbcGFyYW1dYCwgMiBgWy4uLmNhdGNoQWxsXWAsIDMgYFtbLi4ub3B0aW9uYWxdXWAuICovXG5mdW5jdGlvbiBzZWdtZW50S2luZChzZWdtZW50OiBzdHJpbmcpOiBudW1iZXIge1xuICBpZiAoT1BUSU9OQUxfQ0FUQ0hfQUxMX1NFR01FTlQudGVzdChzZWdtZW50KSkge1xuICAgIHJldHVybiAzO1xuICB9XG4gIGlmICgvXlxcW1xcLlxcLlxcLlteXFxdXStcXF0kLy50ZXN0KHNlZ21lbnQpKSB7XG4gICAgcmV0dXJuIDI7XG4gIH1cbiAgcmV0dXJuIC9eXFxbW15cXF1dK1xcXSQvLnRlc3Qoc2VnbWVudCkgPyAxIDogMDtcbn1cblxuLyoqXG4gKiBUaGUgVVJMcyBvZiBhICpkeW5hbWljKiB0ZW1wbGF0ZSdzIHNwYWNlIHRoYXQgYW5vdGhlciBncm91cCdzIGJlaGF2aW9yXG4gKiBjYXB0dXJlcywgYW5kIHRoYXQgTmV4dC5qcyDigJQgcnVubmluZyBpbiB0aGF0IGdyb3VwJ3MgZnVuY3Rpb24g4oCUIHN0aWxsXG4gKiByZXNvbHZlcyB0byB0aGlzIHRlbXBsYXRlJ3MgZmlsZS5cbiAqXG4gKiBgc2VydmVkVXJsc2AgcmVwbGF5cyB0aGUgdGVtcGxhdGUgYXMgc3BlbGxlZCwgd2hpY2ggaXMgZXhhY3QgZm9yIGEgc3RhdGljXG4gKiByb3V0ZSBidXQgbm90IGZvciBgL1suLi5zbHVnXWA6IHRoZSB0ZXh0IGAvWy4uLnNsdWddYCBuZXZlciBtYXRjaGVzIGBibG9nLypgLFxuICogeWV0IGAvYmxvZy9hL2JgIGRvZXMsIHJlYWNoZXMgdGhlIGJsb2cgZnVuY3Rpb24sIGFuZCByZXNvbHZlcyB0aGVyZSB0b1xuICogYC9bLi4uc2x1Z11gLCB3aGljaCB0aGUgYmxvZyB6aXAgbGFja3MuIFNvIGVhY2ggb3RoZXIgZ3JvdXAncyBiZWhhdmlvciBpc1xuICogaW50ZXJzZWN0ZWQgd2l0aCB0aGUgdGVtcGxhdGUncyBVUkwgc3BhY2UsIG9uZSBzYW1wbGUgVVJMIHBlciBzaGFwZVxuICogKHtAbGluayBzYW1wbGVUZW1wbGF0ZVBhdGhzfSksIGFuZCBlYWNoIHNhbXBsZSBpcyByZXNvbHZlZCB0aGUgd2F5IE5leHQuanNcbiAqIHJlc29sdmVzIGl0ICh7QGxpbmsgcmVzb2x2ZUZpbGV9KS4gQSBtb3JlIHNwZWNpZmljIHRlbXBsYXRlIGluIHRoZSBjYXB0dXJpbmdcbiAqIGdyb3VwIGxlZ2l0aW1hdGVseSBzaGFkb3dzIHRoZSBzYW1wbGUgKGAvYmxvZy9bc2x1Z11gIGFuc3dlcnMgYC9ibG9nL19gLCBzb1xuICogb25seSBgL2Jsb2cvXy9fYCBpcyBhIG1pc3JvdXRlKTsgYW55dGhpbmcgaXQgZG9lcyBub3Qgc2hhZG93IGlzIGZsYWdnZWQuXG4gKi9cbmZ1bmN0aW9uIGNhcHR1cmVkRHluYW1pY1VybHMoXG4gIGVudHJ5OiBSb3V0ZUVudHJ5LFxuICBvd25lcjogc3RyaW5nLFxuICBkZWVwZXN0OiBudW1iZXIsXG4gIGJlaGF2aW9yczogcmVhZG9ubHkgRWRnZUJlaGF2aW9yW10sXG4gIGVkZ2U6IEVkZ2VPcHRpb25zLFxuICByb3V0ZXI6IFJvdXRlcixcbik6IE1pc3JvdXRlW10ge1xuICBjb25zdCBwYXRoID0gc3RyaXBCYXNlUGF0aChlbnRyeS50ZW1wbGF0ZSwgZWRnZS5iYXNlUGF0aCk7XG4gIGlmIChcbiAgICBwYXRoID09PSB1bmRlZmluZWQgfHxcbiAgICAhcGF0aC5pbmNsdWRlcyhcIltcIikgfHxcbiAgICBFUlJPUl9QQUdFX1NVRkZJWEVTLmluY2x1ZGVzKHBhdGgpIHx8XG4gICAgIWlzUm91dGFibGVQYXRoKHBhdGgpXG4gICkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICBjb25zdCBzZWdtZW50cyA9IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgY29uc3Qgc2FtcGxlcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBmb3IgKGNvbnN0IGJlaGF2aW9yIG9mIGJlaGF2aW9ycykge1xuICAgIGlmIChcbiAgICAgIGJlaGF2aW9yLmdyb3VwID09PSBvd25lciB8fFxuICAgICAgYmVoYXZpb3IucGF0dGVybi5zdGFydHNXaXRoKFwiX25leHQvZGF0YS9cIilcbiAgICApIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCBiYXJlID0gYmVoYXZpb3IucGF0dGVybi5yZXBsYWNlKC9cXC8kLywgXCJcIik7XG4gICAgY29uc3QgaXNTdWJ0cmVlID0gYmFyZS5lbmRzV2l0aChcIi8qXCIpO1xuICAgIGNvbnN0IHByZWZpeCA9IChpc1N1YnRyZWUgPyBiYXJlLnNsaWNlKDAsIC0yKSA6IGJhcmUpXG4gICAgICAuc3BsaXQoXCIvXCIpXG4gICAgICAuZmlsdGVyKEJvb2xlYW4pO1xuICAgIGZvciAoY29uc3Qgc2FtcGxlIG9mIHNhbXBsZVRlbXBsYXRlUGF0aHMoXG4gICAgICBzZWdtZW50cyxcbiAgICAgIHByZWZpeCxcbiAgICAgIGlzU3VidHJlZSxcbiAgICAgIE1hdGgubWF4KGRlZXBlc3QsIHByZWZpeC5sZW5ndGggKyAxKSxcbiAgICApKSB7XG4gICAgICBzYW1wbGVzLmFkZChzYW1wbGUpO1xuICAgIH1cbiAgfVxuICBjb25zdCBtaXNyb3V0ZWQ6IE1pc3JvdXRlW10gPSBbXTtcbiAgLy8gYHJlc29sdmVkYCBpcyBgdXJsYCBhcyBOZXh0LmpzIG1hdGNoZXMgaXQ6IHdpdGhvdXQgdGhlIHRyYWlsaW5nIHNsYXNoLlxuICBjb25zdCBjaGVjayA9ICh1cmw6IHN0cmluZywgcmVzb2x2ZWQ6IHN0cmluZykgPT4ge1xuICAgIGNvbnN0IGJlaGF2aW9yID0gZWRnZUJlaGF2aW9yRm9yKGJlaGF2aW9ycywgdXJsKTtcbiAgICBjb25zdCBncm91cCA9IGJlaGF2aW9yPy5ncm91cCA/PyBERUZBVUxUX0ZVTkNUSU9OX0dST1VQO1xuICAgIGlmIChncm91cCA9PT0gb3duZXIgfHwgbWlzcm91dGVkLnNvbWUoKGl0KSA9PiBpdC51cmwgPT09IHVybCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHJlc29sdmVGaWxlKHJlc29sdmVkLCByb3V0ZXIpID09PSBlbnRyeS5lbnRyeXBvaW50SWQpIHtcbiAgICAgIG1pc3JvdXRlZC5wdXNoKHtcbiAgICAgICAgdXJsLFxuICAgICAgICBncm91cCxcbiAgICAgICAgcm91dGU6IGJlaGF2aW9yPy5yb3V0ZSxcbiAgICAgICAgc2VydmVkQXM6IGVudHJ5LnRlbXBsYXRlLFxuICAgICAgfSk7XG4gICAgfVxuICB9O1xuICBmb3IgKGNvbnN0IHNhbXBsZSBvZiBzYW1wbGVzKSB7XG4gICAgZm9yIChjb25zdCB7IHVybCwgcmVzb2x2ZWQgfSBvZiB1cmxWYXJpYW50cyhzYW1wbGUsIGVudHJ5LnR5cGUsIGVkZ2UpKSB7XG4gICAgICBjaGVjayh1cmwsIHJlc29sdmVkKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG1pc3JvdXRlZDtcbn1cblxuLyoqXG4gKiBTYW1wbGUgcGF0aHMgaW4gYm90aCBhIHRlbXBsYXRlJ3MgVVJMIHNwYWNlIGFuZCBhIGJlaGF2aW9yJ3M6IGZvciBhIHN1YnRyZWVcbiAqIGBwcmVmaXgvKmAsIGV2ZXJ5IHdheSB0aGUgdGVtcGxhdGUncyBzZWdtZW50cyBjYW4gbGluZSB1cCB3aXRoIGBwcmVmaXhgIGFuZFxuICogY29udGludWUgcGFzdCBpdCwgb25lIHNhbXBsZSBwZXIgcmVzdWx0aW5nIGxlbmd0aCB1cCB0byBgbWF4RGVwdGhgLCB3aXRoXG4gKiB7QGxpbmsgQU5ZX1NFR01FTlR9IGZvciBlYWNoIGR5bmFtaWMgdmFsdWUgYmV5b25kIHRoZSBwcmVmaXguIEZvciBhbiBleGFjdFxuICogcGF0dGVybiwgdGhlIHBhdHRlcm4ncyBvd24gcGF0aCBpZiB0aGUgdGVtcGxhdGUgbWF0Y2hlcyBpdC5cbiAqL1xuZnVuY3Rpb24gc2FtcGxlVGVtcGxhdGVQYXRocyhcbiAgdGVtcGxhdGU6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICBwcmVmaXg6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICBpc1N1YnRyZWU6IGJvb2xlYW4sXG4gIG1heERlcHRoOiBudW1iZXIsXG4pOiBzdHJpbmdbXSB7XG4gIGlmICghaXNTdWJ0cmVlKSB7XG4gICAgY29uc3QgcGF0aCA9IGAvJHtwcmVmaXguam9pbihcIi9cIil9YDtcbiAgICByZXR1cm4gdGVtcGxhdGVSZWdleChgLyR7dGVtcGxhdGUuam9pbihcIi9cIil9YCkudGVzdChwYXRoKSA/IFtwYXRoXSA6IFtdO1xuICB9XG4gIGNvbnN0IHZhbHVlQXQgPSAoYXQ6IG51bWJlcikgPT5cbiAgICBhdCA8IHByZWZpeC5sZW5ndGggPyBwcmVmaXhbYXRdIDogQU5ZX1NFR01FTlQ7XG4gIGNvbnN0IHJlc3VsdHM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IHdhbGsgPSAoaW5kZXg6IG51bWJlciwgYWNjOiByZWFkb25seSBzdHJpbmdbXSk6IHZvaWQgPT4ge1xuICAgIGlmIChpbmRleCA9PT0gdGVtcGxhdGUubGVuZ3RoKSB7XG4gICAgICAvLyBFeGFjdGx5IHRoZSBwcmVmaXggaXMga2VwdCB0b286IGBwcmVmaXgvKmAgbWF0Y2hlcyBpdHMgdHJhaWxpbmctc2xhc2hcbiAgICAgIC8vIGZvcm0sIHdoaWNoIGBjaGVja2AgYWRkcyBmb3IgYSBgdHJhaWxpbmdTbGFzaGAgYXBwLlxuICAgICAgaWYgKGFjYy5sZW5ndGggPj0gcHJlZml4Lmxlbmd0aCkge1xuICAgICAgICByZXN1bHRzLnB1c2goYC8ke2FjYy5qb2luKFwiL1wiKX1gKTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3Qgc2VnbWVudCA9IHRlbXBsYXRlW2luZGV4XTtcbiAgICBjb25zdCBhdCA9IGFjYy5sZW5ndGg7XG4gICAgY29uc3Qga2luZCA9IHNlZ21lbnRLaW5kKHNlZ21lbnQpO1xuICAgIGlmIChraW5kID09PSAwKSB7XG4gICAgICBpZiAoYXQgPj0gcHJlZml4Lmxlbmd0aCB8fCBwcmVmaXhbYXRdID09PSBzZWdtZW50KSB7XG4gICAgICAgIHdhbGsoaW5kZXggKyAxLCBbLi4uYWNjLCBzZWdtZW50XSk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChraW5kID09PSAxKSB7XG4gICAgICB3YWxrKGluZGV4ICsgMSwgWy4uLmFjYywgdmFsdWVBdChhdCldKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZm9yIChsZXQgY291bnQgPSBraW5kID09PSAyID8gMSA6IDA7IGF0ICsgY291bnQgPD0gbWF4RGVwdGg7IGNvdW50KyspIHtcbiAgICAgIGNvbnN0IHRha2VuID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogY291bnQgfSwgKF8sIGkpID0+IHZhbHVlQXQoYXQgKyBpKSk7XG4gICAgICB3YWxrKGluZGV4ICsgMSwgWy4uLmFjYywgLi4udGFrZW5dKTtcbiAgICB9XG4gIH07XG4gIHdhbGsoMCwgW10pO1xuICByZXR1cm4gcmVzdWx0cztcbn1cblxuLyoqXG4gKiBUaGUgVVJMcyBvbmUgdGVtcGxhdGUncyBmaWxlIGFuc3dlcnMgYXQgdGhlIGVkZ2UuXG4gKlxuICogTm90aGluZyBmb3IgdGhlIGVycm9yIHBhZ2VzIChldmVyeSBncm91cCBzdGFnZXMgdGhlbSksIHRoZSBSU0MgYW5kXG4gKiBzZWdtZW50LXByZWZldGNoIHJld3JpdGVzIChyZXF1ZXN0ZWQgYXQgdGhlIHBhZ2UncyBvd24gVVJMKSwgYW5kIGludGVyY2VwdGlvblxuICogcm91dGVzIChyZWFjaGVkIG9ubHkgdGhyb3VnaCB0aGUgaW50ZXJjZXB0ZWQgVVJMJ3MgcmV3cml0ZSkuIE90aGVyd2lzZSB0aGVcbiAqIHRlbXBsYXRlIGl0c2VsZiwgYW4gb3B0aW9uYWwgY2F0Y2gtYWxsJ3MgcGFyZW50LCBhbmQgZm9yIGVhY2ggb2YgdGhvc2UgdGhlXG4gKiBgdHJhaWxpbmdTbGFzaGAgZm9ybSBhbmQgYSBQYWdlcyBSb3V0ZXIgcGFnZSdzIGRhdGEgVVJMLiBPbmx5IHRoZSBzbGFzaC1sZXNzXG4gKiBkYXRhIFVSTDogdGhlIGNsaWVudCBuZXZlciBhZGRzIG9uZS5cbiAqL1xuZnVuY3Rpb24gc2VydmVkVXJscyhcbiAgdGVtcGxhdGU6IHN0cmluZyxcbiAgdHlwZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBlZGdlOiBFZGdlT3B0aW9ucyxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgcGF0aCA9IHN0cmlwQmFzZVBhdGgodGVtcGxhdGUsIGVkZ2UuYmFzZVBhdGgpO1xuICBpZiAoXG4gICAgcGF0aCA9PT0gdW5kZWZpbmVkIHx8XG4gICAgRVJST1JfUEFHRV9TVUZGSVhFUy5pbmNsdWRlcyhwYXRoKSB8fFxuICAgIGlzSW50ZXJuYWxUZW1wbGF0ZShwYXRoKSB8fFxuICAgIGlzSW50ZXJjZXB0aW9uVGVtcGxhdGUocGF0aClcbiAgKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCIvX25leHQvZGF0YS9cIikpIHtcbiAgICByZXR1cm4gW3RlbXBsYXRlXTtcbiAgfVxuICBjb25zdCBwYXRocyA9IFtwYXRoXTtcbiAgY29uc3Qgb3B0aW9uYWwgPSAvXiguKilcXC8oXFxbXFxbXFwuXFwuXFwuW15cXF0vXStcXF1cXF0pJC8uZXhlYyhwYXRoKTtcbiAgaWYgKG9wdGlvbmFsKSB7XG4gICAgcGF0aHMucHVzaChvcHRpb25hbFsxXSB8fCBcIi9cIik7XG4gIH1cbiAgcmV0dXJuIHBhdGhzLmZsYXRNYXAoKGl0KSA9PlxuICAgIHVybFZhcmlhbnRzKGl0LCB0eXBlLCBlZGdlKS5tYXAoKHsgdXJsIH0pID0+IHVybCksXG4gICk7XG59XG5cbi8qKlxuICogQSBwYXRoJ3MgVVJMLCBpdHMgYHRyYWlsaW5nU2xhc2hgIGZvcm0gYW5kIGEgUGFnZXMgUm91dGVyIHBhZ2UncyBkYXRhIFVSTCxcbiAqIGVhY2ggd2l0aCBgcmVzb2x2ZWRgOiB0aGUgVVJMIGFzIE5leHQuanMgbWF0Y2hlcyBpdCwgd2l0aG91dCB0aGUgdHJhaWxpbmcgc2xhc2guXG4gKi9cbmZ1bmN0aW9uIHVybFZhcmlhbnRzKFxuICBwYXRoOiBzdHJpbmcsXG4gIHR5cGU6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgZWRnZTogRWRnZU9wdGlvbnMsXG4pOiB7IHVybDogc3RyaW5nOyByZXNvbHZlZDogc3RyaW5nIH1bXSB7XG4gIGNvbnN0IHVybCA9IHdpdGhCYXNlUGF0aChwYXRoLCBlZGdlLmJhc2VQYXRoKTtcbiAgY29uc3QgdmFyaWFudHMgPSBbeyB1cmwsIHJlc29sdmVkOiB1cmwgfV07XG4gIGlmIChlZGdlLnRyYWlsaW5nU2xhc2ggJiYgcGF0aCAhPT0gXCIvXCIpIHtcbiAgICB2YXJpYW50cy5wdXNoKHsgdXJsOiBgJHt1cmx9L2AsIHJlc29sdmVkOiB1cmwgfSk7XG4gIH1cbiAgaWYgKHR5cGUgPT09IFwicGFnZVwiICYmIGVkZ2UuYnVpbGRJZCkge1xuICAgIGNvbnN0IGRhdGEgPSBgJHtlZGdlLmJhc2VQYXRofS9fbmV4dC9kYXRhLyR7ZWRnZS5idWlsZElkfSR7cGF0aCA9PT0gXCIvXCIgPyBcIi9pbmRleFwiIDogcGF0aH0uanNvbmA7XG4gICAgdmFyaWFudHMucHVzaCh7IHVybDogZGF0YSwgcmVzb2x2ZWQ6IGRhdGEgfSk7XG4gIH1cbiAgcmV0dXJuIHZhcmlhbnRzO1xufVxuXG5mdW5jdGlvbiBtaXNyb3V0ZWRGaWxlTWVzc2FnZShcbiAgZmlsZTogc3RyaW5nLFxuICBvd25lcjogc3RyaW5nLFxuICBtaXNyb3V0ZWQ6IHJlYWRvbmx5IE1pc3JvdXRlW10sXG4gIGVkZ2U6IEVkZ2VPcHRpb25zLFxuKTogc3RyaW5nIHtcbiAgY29uc3Qgd2hlcmUgPSBtaXNyb3V0ZWRcbiAgICAubWFwKFxuICAgICAgKGl0KSA9PlxuICAgICAgICBgXCIke2l0LnVybH1cIiB0byAke2dyb3VwTGFiZWwoaXQuZ3JvdXApfWAgK1xuICAgICAgICAoaXQucm91dGUgPyBgIChpdHMgcGF0dGVybiBcIiR7aXQucm91dGV9XCIpYCA6IFwiXCIpLFxuICAgIClcbiAgICAuam9pbihcIiwgXCIpO1xuICBjb25zdCBoZWFkID1cbiAgICBgJHtFUlJPUl9QUkVGSVh9XCIke2ZpbGV9XCIgaXMgcGFja2FnZWQgaW50byAke2dyb3VwTGFiZWwob3duZXIpfSwgYnV0IGAgK1xuICAgIGBDbG91ZEZyb250IHdvdWxkIHNlbmQgJHt3aGVyZX0sIHdob3NlIGZ1bmN0aW9uIGRvZXMgbm90IGhhdmUgaXQ6IGEgNDA0IG9uIGAgK1xuICAgIGBldmVyeSBzdWNoIHJlcXVlc3QuIEV2ZXJ5IFVSTCBvbmUgZmlsZSBzZXJ2ZXMgaGFzIHRvIHJlYWNoIHRoZSBncm91cCB0aGF0IGAgK1xuICAgIGBob2xkcyB0aGUgZmlsZS5gO1xuICBjb25zdCBjYXB0dXJlZCA9IG1pc3JvdXRlZC5maWx0ZXIoKGl0KSA9PiBpdC5zZXJ2ZWRBcyAhPT0gdW5kZWZpbmVkKTtcbiAgaWYgKGNhcHR1cmVkLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCB0ZW1wbGF0ZXMgPSBbLi4ubmV3IFNldChjYXB0dXJlZC5tYXAoKGl0KSA9PiBgXCIke2l0LnNlcnZlZEFzfVwiYCkpXTtcbiAgICByZXR1cm4gKFxuICAgICAgYCR7aGVhZH0gVGhvc2UgVVJMcyBhcmUgcGFydCBvZiB0aGUgZHluYW1pYyByb3V0ZSBgICtcbiAgICAgIGAke3RlbXBsYXRlcy5qb2luKFwiLCBcIil9IChcIiR7QU5ZX1NFR01FTlR9XCIgc3RhbmRzIGZvciBhbnkgc2VnbWVudCBgICtcbiAgICAgIGB2YWx1ZSk6IHRoZSBwYXR0ZXJuIGNhcHR1cmVzIHRoZW0gYXQgdGhlIGVkZ2UsIGFuZCBubyByb3V0ZSBwYWNrYWdlZCBgICtcbiAgICAgIGBpbnRvIHRoZSBjYXB0dXJpbmcgZ3JvdXAgaXMgbW9yZSBzcGVjaWZpYywgc28gTmV4dC5qcyBzdGlsbCByZXNvbHZlcyBgICtcbiAgICAgIGB0aGVtIHRvIHRoaXMgZmlsZS4gR2l2ZSB0aGF0IGdyb3VwIGEgcm91dGUgdGhhdCBhbnN3ZXJzIHRoZW0gKGEgYCArXG4gICAgICBgY2F0Y2gtYWxsIHVuZGVyIGl0cyBwYXR0ZXJuLCBzYXkpLCBvciBuYXJyb3cgdGhlIHBhdHRlcm4uYFxuICAgICk7XG4gIH1cbiAgaWYgKG93bmVyID09PSBERUZBVUxUX0ZVTkNUSU9OX0dST1VQKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIGAke2hlYWR9IEEgcGF0dGVybiBjbGFpbXMgYSBVUkwgb2YgYSBmaWxlIHRoYXQgbm8gcGF0dGVybiBtb3ZlZDogbmFycm93IGAgK1xuICAgICAgYGl0LCBvciBnaXZlIHRoZSBncm91cCB0aGUgZmlsZSdzIG90aGVyIHJvdXRlcyB0b28uYFxuICAgICk7XG4gIH1cbiAgY29uc3QgdW5yb3V0YWJsZSA9IG1pc3JvdXRlZC5maWx0ZXIoXG4gICAgKGl0KSA9PiBzdWdnZXN0ZWRQYXR0ZXJuKGl0LnVybCwgZWRnZSkgPT09IHVuZGVmaW5lZCxcbiAgKTtcbiAgaWYgKHVucm91dGFibGUubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiAoXG4gICAgICBgJHtoZWFkfSAke3Vucm91dGFibGUubWFwKChpdCkgPT4gYFwiJHtpdC51cmx9XCJgKS5qb2luKFwiLCBcIil9IGNhbm5vdCBiZSBgICtcbiAgICAgIGByb3V0ZWQgdG8gYW55IGdyb3VwIOKAlCBDbG91ZEZyb250IGhhcyBubyBwYXR0ZXJuIGZvciB0aGUgaG9tZSBwYWdlIGFsb25lLCBgICtcbiAgICAgIGBhbmQgYSBkeW5hbWljIGZpcnN0IHNlZ21lbnQgd291bGQgbmVlZCBcIi8qKlwiIOKAlCBzbyB0aGlzIGZpbGUgY2FuIG9ubHkgYmUgYCArXG4gICAgICBgc2VydmVkIGJ5IHRoZSBcIiR7REVGQVVMVF9GVU5DVElPTl9HUk9VUH1cIiBncm91cC4gUmVtb3ZlIHRoZSBwYXR0ZXJuIHRoYXQgYCArXG4gICAgICBgbW92ZWQgaXQuIChBIFBhZ2VzIFJvdXRlciBob21lIHBhZ2UgaXMgYWxzbyBcIi9pbmRleFwiOiBvbmUgZmlsZS4pYFxuICAgICk7XG4gIH1cbiAgY29uc3Qgc3VnZ2VzdGlvbnMgPSBbXG4gICAgLi4ubmV3IFNldChtaXNyb3V0ZWQubWFwKChpdCkgPT4gc3VnZ2VzdGVkUGF0dGVybihpdC51cmwsIGVkZ2UpISkpLFxuICBdO1xuICByZXR1cm4gKFxuICAgIGAke2hlYWR9IEFkZCAke3N1Z2dlc3Rpb25zLm1hcCgoaXQpID0+IGBcIiR7aXR9XCJgKS5qb2luKFwiLCBcIil9IHRvIGdyb3VwIGAgK1xuICAgIGBcIiR7b3duZXJ9XCIncyByb3V0ZXMuYFxuICApO1xufVxuXG4vKipcbiAqIFRoZSBncm91cCBwYXR0ZXJuIHRoYXQgd291bGQgcm91dGUgYHVybGAsIGB1bmRlZmluZWRgIHdoZW4gbm9uZSBjYW46IGEgc3RhdGljXG4gKiBwYXRoIHJvdXRlcyBhcyBpdHNlbGYsIGEgZHluYW1pYyBvbmUgYXMgdGhlIHN1YnRyZWUgYWJvdmUgaXRzIGZpcnN0IGR5bmFtaWNcbiAqIHNlZ21lbnQsIGFuZCBhIGRhdGEgVVJMIG9yIGB0cmFpbGluZ1NsYXNoYCBmb3JtIGFzIHRoZSBwYWdlIGl0IGJlbG9uZ3MgdG8uXG4gKi9cbmZ1bmN0aW9uIHN1Z2dlc3RlZFBhdHRlcm4odXJsOiBzdHJpbmcsIGVkZ2U6IEVkZ2VPcHRpb25zKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgbGV0IHBhdGggPSBzdHJpcEJhc2VQYXRoKHVybCwgZWRnZS5iYXNlUGF0aCkgPz8gdXJsO1xuICBjb25zdCBkYXRhUHJlZml4ID0gYC9fbmV4dC9kYXRhLyR7ZWRnZS5idWlsZElkfS9gO1xuICBpZiAocGF0aC5zdGFydHNXaXRoKGRhdGFQcmVmaXgpICYmIHBhdGguZW5kc1dpdGgoXCIuanNvblwiKSkge1xuICAgIHBhdGggPSBgLyR7cGF0aC5zbGljZShkYXRhUHJlZml4Lmxlbmd0aCwgLVwiLmpzb25cIi5sZW5ndGgpfWA7XG4gICAgcGF0aCA9IHBhdGggPT09IFwiL2luZGV4XCIgPyBcIi9cIiA6IHBhdGg7XG4gIH1cbiAgaWYgKHBhdGgubGVuZ3RoID4gMSAmJiBwYXRoLmVuZHNXaXRoKFwiL1wiKSkge1xuICAgIHBhdGggPSBwYXRoLnNsaWNlKDAsIC0xKTtcbiAgfVxuICBjb25zdCBzZWdtZW50cyA9IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgY29uc3QgZmlyc3REeW5hbWljID0gc2VnbWVudHMuZmluZEluZGV4KChzZWdtZW50KSA9PiBzZWdtZW50LnN0YXJ0c1dpdGgoXCJbXCIpKTtcbiAgaWYgKHNlZ21lbnRzLmxlbmd0aCA9PT0gMCB8fCBmaXJzdER5bmFtaWMgPT09IDApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiBmaXJzdER5bmFtaWMgPT09IC0xXG4gICAgPyBwYXRoXG4gICAgOiBgLyR7c2VnbWVudHMuc2xpY2UoMCwgZmlyc3REeW5hbWljKS5qb2luKFwiL1wiKX0ke1NVQlRSRUVfU1VGRklYfWA7XG59XG5cbi8qKlxuICogVGhyb3cgb24gYSBgbmV4dC5jb25maWdgIHJld3JpdGUgd2hvc2Ugc291cmNlIHJlYWNoZXMgb25lIGdyb3VwIGFuZCB3aG9zZVxuICogZGVzdGluYXRpb24gaXMgcGFja2FnZWQgaW50byBhbm90aGVyLlxuICpcbiAqIEEgcmV3cml0ZSBydW5zIGluc2lkZSB0aGUgZnVuY3Rpb24gdGhhdCByZWNlaXZlZCB0aGUgcmVxdWVzdCwgc29cbiAqIGAvb2xkLzpwYXRoKmAg4oaSIGAvbmV3YCB3aXRoIGAvbmV3LyoqYCBncm91cGVkIGFuZCBgL29sZGAgbm90IHNlbmRzIGAvb2xkL3hgIHRvXG4gKiB0aGUgZGVmYXVsdCBmdW5jdGlvbiwgd2hpY2ggcmV3cml0ZXMgaXQgdG8gYSBmaWxlIGl0IGxhY2tzLlxuICpcbiAqIE9ubHkgdGhlIHJld3JpdGVzIHdob3NlIGRlc3RpbmF0aW9uIGlzIGEgbGl0ZXJhbCBwYXRoIGNhbiBiZSByZXNvbHZlZCB0byBhXG4gKiBmaWxlIGhlcmU7IG9uZSBidWlsdCBmcm9tIHRoZSBzb3VyY2UncyBwYXJhbWV0ZXJzIChgL2Jsb2cvOnNsdWdgIOKGklxuICogYC9wb3N0cy86c2x1Z2ApIGlzIHNraXBwZWQsIGFzIGFyZSBleHRlcm5hbCBvbmVzLiBUaGUgc291cmNlIGlzIGNoZWNrZWQgYXQgdGhlXG4gKiBncmFudWxhcml0eSBvZiBpdHMgbGl0ZXJhbCBwcmVmaXg6IGVhY2ggcGFyYW1ldGVyIHN0YW5kcyBpbiBhcyBhIGR5bmFtaWNcbiAqIHNlZ21lbnQuIFJld3JpdGVzIGRvbmUgYnkgbWlkZGxld2FyZSAoYE5leHRSZXNwb25zZS5yZXdyaXRlYCkgYXJlIGNvZGUsIG5vdFxuICogY29uZmlnLCBhbmQgY2Fubm90IGJlIGNoZWNrZWQgYXQgYWxsLlxuICovXG5mdW5jdGlvbiBhc3NlcnRSZXdyaXRlc1N0YXlJbkdyb3VwKFxuICBncm91cE9mRW50cnlwb2ludDogUmVhZG9ubHlNYXA8c3RyaW5nLCBzdHJpbmc+LFxuICBiZWhhdmlvcnM6IHJlYWRvbmx5IEVkZ2VCZWhhdmlvcltdLFxuICByb3V0ZXI6IFJvdXRlcixcbik6IHZvaWQge1xuICBjb25zdCB7IHJvdXRpbmcgfSA9IHJvdXRlcjtcbiAgY29uc3QgcGhhc2VzOiBbcmVhZG9ubHkgUmV3cml0ZVJ1bGVbXSB8IHVuZGVmaW5lZCwgYm9vbGVhbl1bXSA9IFtcbiAgICBbcm91dGluZy5iZWZvcmVGaWxlcywgZmFsc2VdLFxuICAgIC8vIGBhZnRlckZpbGVzYCBhbmQgYGZhbGxiYWNrYCBvbmx5IGFwcGx5IHdoZW4gbm8gZmlsZSBtYXRjaGVkIHRoZSBVUkwsIHNvIGFcbiAgICAvLyBzb3VyY2UgdGhhdCBpcyBpdHNlbGYgYSByb3V0ZSBuZXZlciByZWFjaGVzIHRoZSBkZXN0aW5hdGlvbi5cbiAgICBbcm91dGluZy5hZnRlckZpbGVzLCB0cnVlXSxcbiAgICBbcm91dGluZy5mYWxsYmFjaywgdHJ1ZV0sXG4gIF07XG4gIGZvciAoY29uc3QgW3J1bGVzLCB5aWVsZHNUb0ZpbGVzXSBvZiBwaGFzZXMpIHtcbiAgICBmb3IgKGNvbnN0IHJ1bGUgb2YgcnVsZXMgPz8gW10pIHtcbiAgICAgIGNvbnN0IGRlc3RpbmF0aW9uID0gbGl0ZXJhbERlc3RpbmF0aW9uKHJ1bGUuZGVzdGluYXRpb24pO1xuICAgICAgLy8gTmV4dC5qcydzIG93biBpbnRlcmNlcHRpb24gcmV3cml0ZXMgYXJlIGhlcmUgdG9vLCBvbiBgTmV4dC1VcmxgO1xuICAgICAgLy8gYHJlYXNzaWduSW50ZXJjZXB0aW5nRmlsZXNgIGhhcyBhbHJlYWR5IHB1dCB0aGVpciBmaWxlcyBpbiBwbGFjZS5cbiAgICAgIGlmIChkZXN0aW5hdGlvbiA9PT0gdW5kZWZpbmVkIHx8IGlzSW50ZXJjZXB0aW9uVGVtcGxhdGUoZGVzdGluYXRpb24pKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgZmlsZSA9IHJlc29sdmVGaWxlKGRlc3RpbmF0aW9uLCByb3V0ZXIpO1xuICAgICAgaWYgKGZpbGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHRhcmdldCA9IGdyb3VwT2ZFbnRyeXBvaW50LmdldChmaWxlKSA/PyBERUZBVUxUX0ZVTkNUSU9OX0dST1VQO1xuICAgICAgZm9yIChjb25zdCB1cmwgb2YgcmV3cml0ZVNvdXJjZVVybHMocnVsZS5zb3VyY2UpKSB7XG4gICAgICAgIGlmICh5aWVsZHNUb0ZpbGVzICYmIHJvdXRlci5maWxlT2ZUZW1wbGF0ZS5oYXModXJsKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGJlaGF2aW9yID0gZWRnZUJlaGF2aW9yRm9yKGJlaGF2aW9ycywgdXJsKTtcbiAgICAgICAgY29uc3QgZ3JvdXAgPSBiZWhhdmlvcj8uZ3JvdXAgPz8gREVGQVVMVF9GVU5DVElPTl9HUk9VUDtcbiAgICAgICAgaWYgKGdyb3VwID09PSB0YXJnZXQpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYCR7RVJST1JfUFJFRklYfVRoZSBuZXh0LmNvbmZpZyByZXdyaXRlIGZyb20gXCIke3J1bGUuc291cmNlfVwiIHRvIGAgK1xuICAgICAgICAgICAgYFwiJHtydWxlLmRlc3RpbmF0aW9ufVwiIGNyb3NzZXMgZ3JvdXBzOiBDbG91ZEZyb250IHNlbmRzIFwiJHt1cmx9XCIgdG8gYCArXG4gICAgICAgICAgICBgJHtncm91cExhYmVsKGdyb3VwKX1gICtcbiAgICAgICAgICAgIChiZWhhdmlvciA/IGAgKGl0cyBwYXR0ZXJuIFwiJHtiZWhhdmlvci5yb3V0ZX1cIilgIDogXCJcIikgK1xuICAgICAgICAgICAgYCwgYW5kIE5leHQuanMgdGhlbiBzZXJ2ZXMgaXQgd2l0aCBcIiR7ZmlsZX1cIiwgd2hpY2ggaXMgcGFja2FnZWQgYCArXG4gICAgICAgICAgICBgaW50byAke2dyb3VwTGFiZWwodGFyZ2V0KX0uIEEgcmV3cml0ZSBpcyBhcHBsaWVkIGluc2lkZSB0aGUgYCArXG4gICAgICAgICAgICBgZnVuY3Rpb24gdGhhdCByZWNlaXZlZCB0aGUgcmVxdWVzdCwgc28gaXRzIHNvdXJjZSBhbmQgaXRzIGAgK1xuICAgICAgICAgICAgYGRlc3RpbmF0aW9uIGhhdmUgdG8gYmUgcm91dGVkIHRvIHRoZSBzYW1lIGdyb3VwLmAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi8qKiBBIHJld3JpdGUgZGVzdGluYXRpb24ncyBwYXRobmFtZSwgYHVuZGVmaW5lZGAgdW5sZXNzIGl0IGlzIGEgbGl0ZXJhbCBsb2NhbCBwYXRoLiAqL1xuZnVuY3Rpb24gbGl0ZXJhbERlc3RpbmF0aW9uKFxuICBkZXN0aW5hdGlvbjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFkZXN0aW5hdGlvbj8uc3RhcnRzV2l0aChcIi9cIikpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IHBhdGhuYW1lID0gZGVzdGluYXRpb24uc3BsaXQoL1s/I10vKVswXTtcbiAgaWYgKC9bJDpdLy50ZXN0KHBhdGhuYW1lKSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIHBhdGhuYW1lLmxlbmd0aCA+IDEgPyBwYXRobmFtZS5yZXBsYWNlKC9cXC8kLywgXCJcIikgOiBwYXRobmFtZTtcbn1cblxuLyoqIFdoYXQge0BsaW5rIHJlc29sdmVGaWxlfSByZXNvbHZlcyBhZ2FpbnN0LiAqL1xuaW50ZXJmYWNlIFJvdXRlciB7XG4gIC8qKiBUZW1wbGF0ZSDihpIgdGhlIGZpbGUgYmVoaW5kIGl0LCBsZXNzIHRoZSBSU0MgYW5kIHNlZ21lbnQgcmV3cml0ZXMuICovXG4gIHJlYWRvbmx5IGZpbGVPZlRlbXBsYXRlOiBSZWFkb25seU1hcDxzdHJpbmcsIHN0cmluZz47XG4gIHJlYWRvbmx5IHJvdXRpbmc6IFJvdXRpbmdSdWxlcztcbn1cblxuZnVuY3Rpb24gZmlsZU9mVGVtcGxhdGUoZW50cmllczogcmVhZG9ubHkgUm91dGVFbnRyeVtdKTogTWFwPHN0cmluZywgc3RyaW5nPiB7XG4gIHJldHVybiBuZXcgTWFwKFxuICAgIGVudHJpZXNcbiAgICAgIC5maWx0ZXIoKGVudHJ5KSA9PiAhaXNJbnRlcm5hbFRlbXBsYXRlKGVudHJ5LnRlbXBsYXRlKSlcbiAgICAgIC5tYXAoKGVudHJ5KSA9PiBbZW50cnkudGVtcGxhdGUsIGVudHJ5LmVudHJ5cG9pbnRJZF0pLFxuICApO1xufVxuXG4vKipcbiAqIFRoZSBmaWxlIE5leHQuanMgc2VydmVzIGBwYXRobmFtZWAgd2l0aDogYSB0ZW1wbGF0ZSBvZiB0aGF0IGV4YWN0IG5hbWUsIG9yXG4gKiBlbHNlIHRoZSBmaXJzdCBvZiBOZXh0LmpzJ3Mgb3duIGR5bmFtaWMgcm91dGUgcnVsZXMgdGhhdCBtYXRjaGVzIOKAlCBtYXRjaGVkXG4gKiBjYXNlLWluc2Vuc2l0aXZlbHksIGFzIGByZXNvbHZlUm91dGVzYCBkb2VzLiBgZHluYW1pY1JvdXRlc2AgaXMgaW4gTmV4dC5qcydzXG4gKiBwcmlvcml0eSBvcmRlciAoc3RhdGljIHNlZ21lbnQgYmVmb3JlIGBbcGFyYW1dYCBiZWZvcmUgYFsuLi5jYXRjaEFsbF1gXG4gKiBiZWZvcmUgYFtbLi4ub3B0aW9uYWxdXWApLCBQYWdlcyBSb3V0ZXIgZGF0YSBVUkxzIGluY2x1ZGVkLlxuICovXG5mdW5jdGlvbiByZXNvbHZlRmlsZShcbiAgcGF0aG5hbWU6IHN0cmluZyxcbiAgeyBmaWxlT2ZUZW1wbGF0ZTogZmlsZXMsIHJvdXRpbmcgfTogUm91dGVyLFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZXhhY3QgPSBmaWxlcy5nZXQocGF0aG5hbWUpO1xuICBpZiAoZXhhY3QgIT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBleGFjdDtcbiAgfVxuICBmb3IgKGNvbnN0IHJvdXRlIG9mIHJvdXRpbmcuZHluYW1pY1JvdXRlcyA/PyBbXSkge1xuICAgIGlmIChuZXcgUmVnRXhwKHJvdXRlLnNvdXJjZVJlZ2V4LCBcImlcIikudGVzdChwYXRobmFtZSkpIHtcbiAgICAgIGNvbnN0IHRlbXBsYXRlID0gcm91dGUuZGVzdGluYXRpb24/LnNwbGl0KFwiP1wiKVswXTtcbiAgICAgIHJldHVybiB0ZW1wbGF0ZSA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogZmlsZXMuZ2V0KHRlbXBsYXRlKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBUaGUgVVJMIHNoYXBlcyBhIHBhdGgtdG8tcmVnZXhwIHJld3JpdGUgc291cmNlIG1hdGNoZXMsIGFzIHRlbXBsYXRlLWxpa2VcbiAqIHBhdGhzOiBlYWNoIGxpdGVyYWwgc2VnbWVudCBrZXB0LCBlYWNoIHBhcmFtZXRlciByZXBsYWNlZCBieSBgW25hbWVdYCwgYW5kIOKAlFxuICogd2hlbiB0aGUgbGFzdCBvbmUgaXMgb3B0aW9uYWwgKGA6cGF0aCpgLCBgOnNsdWc/YCkg4oCUIHRoZSBwYXRoIHdpdGhvdXQgaXQgdG9vLlxuICovXG5mdW5jdGlvbiByZXdyaXRlU291cmNlVXJscyhzb3VyY2U6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZ1tdIHtcbiAgaWYgKCFzb3VyY2U/LnN0YXJ0c1dpdGgoXCIvXCIpKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIGNvbnN0IHNlZ21lbnRzOiBzdHJpbmdbXSA9IFtdO1xuICBsZXQgb3B0aW9uYWxGcm9tOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGZvciAoY29uc3Qgc2VnbWVudCBvZiBzb3VyY2Uuc3BsaXQoXCIvXCIpLnNsaWNlKDEpKSB7XG4gICAgaWYgKCEvWzooKSo/K3t9W1xcXV0vLnRlc3Qoc2VnbWVudCkpIHtcbiAgICAgIHNlZ21lbnRzLnB1c2goc2VnbWVudCk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgb3B0aW9uYWxGcm9tID0gL146XFx3K1sqP10kLy50ZXN0KHNlZ21lbnQpID8gc2VnbWVudHMubGVuZ3RoIDogdW5kZWZpbmVkO1xuICAgIHNlZ21lbnRzLnB1c2goYFskey86KFxcdyspLy5leGVjKHNlZ21lbnQpPy5bMV0gPz8gXCJwYXJhbVwifV1gKTtcbiAgfVxuICBjb25zdCB1cmxzID0gW2AvJHtzZWdtZW50cy5qb2luKFwiL1wiKX1gXTtcbiAgaWYgKG9wdGlvbmFsRnJvbSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdXJscy5wdXNoKGAvJHtzZWdtZW50cy5zbGljZSgwLCBvcHRpb25hbEZyb20pLmpvaW4oXCIvXCIpfWApO1xuICB9XG4gIHJldHVybiB1cmxzO1xufVxuXG5mdW5jdGlvbiBncm91cExhYmVsKGdyb3VwOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gZ3JvdXAgPT09IERFRkFVTFRfRlVOQ1RJT05fR1JPVVBcbiAgICA/IGB0aGUgXCIke0RFRkFVTFRfRlVOQ1RJT05fR1JPVVB9XCIgZ3JvdXBgXG4gICAgOiBgZ3JvdXAgXCIke2dyb3VwfVwiYDtcbn1cblxuZnVuY3Rpb24gcHJlZml4QmFzZVBhdGgocm91dGU6IHN0cmluZywgYmFzZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgJHtiYXNlUGF0aFByZWZpeChiYXNlUGF0aCl9JHtyb3V0ZX1gO1xufVxuXG4vKiogYHRlbXBsYXRlYCB3aXRob3V0IGBiYXNlUGF0aGAgKGAvYCBmb3IgdGhlIGJhc2UgaXRzZWxmKSwgYHVuZGVmaW5lZGAgaWYgb3V0c2lkZSBpdC4gKi9cbmZ1bmN0aW9uIHN0cmlwQmFzZVBhdGgodGVtcGxhdGU6IHN0cmluZywgYmFzZVBhdGg6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghYmFzZVBhdGgpIHtcbiAgICByZXR1cm4gdGVtcGxhdGU7XG4gIH1cbiAgcmV0dXJuIGhhc1BhdGhQcmVmaXgodGVtcGxhdGUsIGJhc2VQYXRoKVxuICAgID8gdGVtcGxhdGUuc2xpY2UoYmFzZVBhdGgubGVuZ3RoKSB8fCBcIi9cIlxuICAgIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiB3aXRoQmFzZVBhdGgocGF0aDogc3RyaW5nLCBiYXNlUGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHBhdGggPT09IFwiL1wiID8gYmFzZVBhdGggfHwgXCIvXCIgOiBgJHtiYXNlUGF0aH0ke3BhdGh9YDtcbn1cbiJdfQ==
|