cdk-nextjs 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +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 +1548 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +852 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +861 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +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 +1213 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1678 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41595 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +55 -0
- package/lib/runtime/next-modules.js +124 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41588 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +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
|
@@ -4,30 +4,91 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.NextjsBuild = void 0;
|
|
7
|
+
exports.deploymentArchitecture = deploymentArchitecture;
|
|
8
|
+
exports.deploymentBuildId = deploymentBuildId;
|
|
9
|
+
exports.pickStagedSharpPackage = pickStagedSharpPackage;
|
|
10
|
+
exports.resolveNextSharp = resolveNextSharp;
|
|
11
|
+
exports.isSharpBinaryPackage = isSharpBinaryPackage;
|
|
12
|
+
exports.sharpBinaryDir = sharpBinaryDir;
|
|
13
|
+
exports.listTree = listTree;
|
|
14
|
+
exports.writePublicFileList = writePublicFileList;
|
|
15
|
+
exports.storedSize = storedSize;
|
|
16
|
+
exports.patchClientChunk = patchClientChunk;
|
|
7
17
|
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
8
18
|
const node_child_process_1 = require("node:child_process");
|
|
9
19
|
const node_crypto_1 = require("node:crypto");
|
|
10
20
|
const node_fs_1 = require("node:fs");
|
|
21
|
+
const node_module_1 = require("node:module");
|
|
11
22
|
const node_os_1 = require("node:os");
|
|
12
23
|
const node_path_1 = require("node:path");
|
|
13
24
|
const posix_1 = require("node:path/posix");
|
|
14
25
|
const constructs_1 = require("constructs");
|
|
15
26
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
16
27
|
const debug_1 = __importDefault(require("debug"));
|
|
28
|
+
const function_groups_1 = require("../adapter/function-groups");
|
|
17
29
|
const constants_1 = require("../constants");
|
|
30
|
+
const manifest_1 = require("../runtime/manifest");
|
|
31
|
+
const public_files_1 = require("../runtime/public-files");
|
|
18
32
|
const base_path_1 = require("../utils/base-path");
|
|
19
|
-
const experimental_flags_1 = require("../utils/experimental-flags");
|
|
20
33
|
const get_architecture_1 = require("../utils/get-architecture");
|
|
34
|
+
/**
|
|
35
|
+
* Lambda's hard limit on the unzipped size of a function's code, which
|
|
36
|
+
* CloudFormation only enforces at deploy time. Measured at synth instead, so the
|
|
37
|
+
* error names the group and arrives in seconds rather than minutes.
|
|
38
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html
|
|
39
|
+
*/
|
|
40
|
+
const LAMBDA_UNZIPPED_LIMIT_BYTES = 250 * 1024 * 1024;
|
|
41
|
+
/**
|
|
42
|
+
* Opens the patch `patchFetchInClientJs` prepends to a client chunk, followed by
|
|
43
|
+
* a hash of the patch itself, so a second synth over the same `.next` is a no-op
|
|
44
|
+
* while one by a cdk-nextjs with a different `patch-fetch.js` replaces it.
|
|
45
|
+
*/
|
|
46
|
+
const PATCH_FETCH_MARKER = "/* cdk-nextjs:patch-fetch";
|
|
47
|
+
/** Closes the prepended patch; the chunk's own content starts after it. */
|
|
48
|
+
const PATCH_FETCH_END_MARKER = "/* cdk-nextjs:patch-fetch:end */";
|
|
21
49
|
const debug = (0, debug_1.default)("cdk-nextjs:nextjs-build");
|
|
50
|
+
/**
|
|
51
|
+
* What every deployment root is staged for: the build's `architecture`, else
|
|
52
|
+
* the synth machine's. Containers ignore it: Docker builds their image
|
|
53
|
+
* natively, so it can only match the synth machine.
|
|
54
|
+
*/
|
|
55
|
+
function deploymentArchitecture(props) {
|
|
56
|
+
const isFunctions = props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS ||
|
|
57
|
+
props.nextjsType === constants_1.NextjsType.REGIONAL_FUNCTIONS;
|
|
58
|
+
return (isFunctions && props.architecture) || (0, get_architecture_1.getLambdaArchitecture)();
|
|
59
|
+
}
|
|
60
|
+
/** {@link NextjsBuild.buildId}: Next.js's build ID, suffixed with the app's `deploymentId`. */
|
|
61
|
+
function deploymentBuildId(manifest) {
|
|
62
|
+
const { deploymentId } = manifest.config;
|
|
63
|
+
return deploymentId
|
|
64
|
+
? `${manifest.buildId}-${deploymentId}`
|
|
65
|
+
: manifest.buildId;
|
|
66
|
+
}
|
|
22
67
|
/**
|
|
23
68
|
* Builds Next.js assets.
|
|
24
69
|
* @link https://nextjs.org/docs/pages/api-reference/next-config-js/output
|
|
25
70
|
*/
|
|
26
71
|
class NextjsBuild extends constructs_1.Construct {
|
|
27
|
-
static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-nextjs.NextjsBuild", version: "0.
|
|
72
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-nextjs.NextjsBuild", version: "0.7.0" };
|
|
28
73
|
/**
|
|
29
|
-
* Unique id for
|
|
74
|
+
* Unique id for this deployment. Used to partition cache storage and as
|
|
30
75
|
* metadata for static assets in S3 bucket.
|
|
76
|
+
*
|
|
77
|
+
* Next.js's build ID, suffixed with the app's `deploymentId` when it sets
|
|
78
|
+
* one. The build ID alone is not unique per deployment: setting
|
|
79
|
+
* `deploymentId` (or building with `NEXT_DEPLOYMENT_ID`) turns on skew
|
|
80
|
+
* protection, and next.js then *pins* the build ID to the constant
|
|
81
|
+
* `build-TfctsWXpff2fKS` — see `getBuildId` in `next/dist/build/index.js`,
|
|
82
|
+
* which does that deliberately so that tooling doing
|
|
83
|
+
* `.replace(escapedBuildId, …)` still has something to replace. Two
|
|
84
|
+
* successive deployments of such an app would share one cache prefix and one
|
|
85
|
+
* revalidation-table partition, and the new one would read the previous
|
|
86
|
+
* one's prerenders. Appending the deployment ID restores the "one
|
|
87
|
+
* deployment, one partition" invariant that ID exists to carry.
|
|
88
|
+
*
|
|
89
|
+
* Nothing routes on this value — the `/_next/data/<buildId>/…` URL space is
|
|
90
|
+
* routed on Next.js's own build ID, which is what the app's client bundles
|
|
91
|
+
* carry — so it is free to be longer than next.js's own.
|
|
31
92
|
*/
|
|
32
93
|
buildId;
|
|
33
94
|
/**
|
|
@@ -41,39 +102,71 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
41
102
|
*/
|
|
42
103
|
publicDirEntries;
|
|
43
104
|
/**
|
|
44
|
-
* The
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* @example "
|
|
105
|
+
* The JavaScript file Node.js runs to serve requests, relative to the
|
|
106
|
+
* deployment root. cdk-nextjs's own container shell, not `next build` output,
|
|
107
|
+
* so it is the same path for every app.
|
|
108
|
+
* @example "cdk-nextjs-runtime/server.mjs"
|
|
48
109
|
*/
|
|
49
110
|
relativePathToEntrypoint;
|
|
50
|
-
/**
|
|
51
|
-
* Relative path from the standalone directory to the package containing the Next.js app.
|
|
52
|
-
* This is automatically detected from the standalone build output.
|
|
53
|
-
* @example "." for non-monorepo apps
|
|
54
|
-
* @example "./apps/web" for monorepo apps
|
|
55
|
-
*/
|
|
56
|
-
relativePathToPackage;
|
|
57
111
|
/**
|
|
58
112
|
* Absolute path to the .next directory containing Next.js build artifacts
|
|
59
113
|
*/
|
|
60
114
|
dotNextPath;
|
|
61
115
|
/**
|
|
62
116
|
* The Next.js app's own `basePath` — the URL prefix it generates its links and
|
|
63
|
-
* asset hrefs under —
|
|
64
|
-
* Normalized to a bare path segment, empty when the app sets none. Exposed so
|
|
117
|
+
* asset hrefs under — as the adapter manifest recorded it. Normalized to a bare path segment, empty when the app sets none. Exposed so
|
|
65
118
|
* root constructs can reconcile it with the CDK `basePath` prop, which is a
|
|
66
119
|
* distinct thing; see `resolveBasePath`.
|
|
67
120
|
*/
|
|
68
121
|
nextConfigBasePath;
|
|
69
122
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
123
|
+
* The Next.js app's own `assetPrefix`, as a path with a leading slash and no
|
|
124
|
+
* trailing one, empty when the app sets none or sets an absolute URL (which
|
|
125
|
+
* names an origin cdk-nextjs does not serve).
|
|
126
|
+
*
|
|
127
|
+
* Exposed because it is the shape of `assetPrefix` the regional
|
|
128
|
+
* `NextjsType`s cannot serve — see `warnUnservedAssetPrefix`. What the
|
|
129
|
+
* distribution has to answer on is {@link nextConfigAssetPrefixPath}, which
|
|
130
|
+
* also covers the path an absolute prefix carries.
|
|
131
|
+
*/
|
|
132
|
+
nextConfigAssetPrefix;
|
|
133
|
+
/**
|
|
134
|
+
* The path portion of the app's `assetPrefix`, whichever form it takes: "/cdn"
|
|
135
|
+
* for both `assetPrefix: "/cdn"` and `assetPrefix:
|
|
136
|
+
* "https://cdn.example.com/cdn"`, empty when there is no path to answer on.
|
|
137
|
+
*
|
|
138
|
+
* Exposed because it is a URL prefix the distribution has to answer on: Next.js
|
|
139
|
+
* emits `<assetPrefix>/_next/static/...` for every bundle and compiles a rewrite
|
|
140
|
+
* that serves those URLs' paths itself, while the objects live in S3 under
|
|
141
|
+
* `<basePath>/_next/static/...`.
|
|
142
|
+
*/
|
|
143
|
+
nextConfigAssetPrefixPath;
|
|
144
|
+
/**
|
|
145
|
+
* Every staged deployment root, one per function group, `default` first: the
|
|
146
|
+
* staged union of each group's shipped outputs and their traced assets,
|
|
147
|
+
* written by the adapter's `onBuildComplete`. Exactly one entry (named
|
|
148
|
+
* `default`, at `.next/cdk-nextjs-adapter/app`) unless `functionGroups`
|
|
149
|
+
* splits the app. The Lambda zip assets; Containers `COPY` the `default` one.
|
|
75
150
|
*/
|
|
76
|
-
|
|
151
|
+
deploymentRoots;
|
|
152
|
+
/**
|
|
153
|
+
* What routes each non-default function group's URLs to it, most specific
|
|
154
|
+
* first — the order CloudFront has to see them in, since it stops at the
|
|
155
|
+
* first match. Empty unless `functionGroups` splits the app.
|
|
156
|
+
*/
|
|
157
|
+
functionGroupBehaviors;
|
|
158
|
+
/**
|
|
159
|
+
* From the deployment root to the Next.js project dir, POSIX, `""` when
|
|
160
|
+
* the app is at the repo root. The runtime `chdir`s here; Containers pass it to
|
|
161
|
+
* their Dockerfile so `.next/static` and `public` land in the same place.
|
|
162
|
+
* @see AdapterManifest.relativeProjectDir
|
|
163
|
+
*/
|
|
164
|
+
relativeProjectDir;
|
|
165
|
+
/**
|
|
166
|
+
* The architecture every deployment root's native dependencies (`sharp`)
|
|
167
|
+
* were staged for. The Lambdas deploying them must use the same one.
|
|
168
|
+
*/
|
|
169
|
+
architecture;
|
|
77
170
|
props;
|
|
78
171
|
buildCommand;
|
|
79
172
|
constructor(scope, id, props) {
|
|
@@ -83,6 +176,14 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
83
176
|
this.buildCommand = props.buildCommand || "npm run build";
|
|
84
177
|
// Set init cache directory path
|
|
85
178
|
this.initCacheDir = (0, node_path_1.join)(props.buildDirectory, ".next", "cdk-nextjs-init-cache");
|
|
179
|
+
// Before the build, not after it: the build is minutes long, and the env var
|
|
180
|
+
// it passes groups through is only set for a non-empty array — so an invalid
|
|
181
|
+
// `functionGroups` (an empty array, a reserved name, a group owning no
|
|
182
|
+
// routes) would otherwise be reported as "the build staged the wrong
|
|
183
|
+
// groups", after paying for the build, instead of as the prop error it is.
|
|
184
|
+
if (props.functionGroups) {
|
|
185
|
+
(0, function_groups_1.validateFunctionGroups)(props.functionGroups);
|
|
186
|
+
}
|
|
86
187
|
// Execute local build process
|
|
87
188
|
if (props.skipBuild !== true) {
|
|
88
189
|
this.runNextBuild();
|
|
@@ -90,36 +191,247 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
90
191
|
else {
|
|
91
192
|
debug(`${constants_1.LOG_PREFIX} Skipping: ${this.buildCommand}`);
|
|
92
193
|
}
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
194
|
+
// First, before anything else reads `.next`: a missing manifest is the one
|
|
195
|
+
// error that names the cause (no build, or one without the adapter), where
|
|
196
|
+
// every later read fails with a bare ENOENT.
|
|
197
|
+
const manifest = this.readAdapterManifest();
|
|
198
|
+
// Deliberately outside the `skipBuild` gate. The patch is a property of
|
|
199
|
+
// *serving* through CloudFront, not of who ran `next build`: without it
|
|
200
|
+
// every POST with a body is rejected by the Lambda Function URL before it
|
|
201
|
+
// reaches the app (see `patchFetchInClientJs`). Running it only inside
|
|
202
|
+
// `runNextBuild` meant `skipBuild: true` silently shipped an app whose
|
|
203
|
+
// server actions and POST route handlers all returned 403.
|
|
204
|
+
if (props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS) {
|
|
205
|
+
this.patchFetchInClientJs();
|
|
206
|
+
}
|
|
207
|
+
this.buildId = deploymentBuildId(manifest);
|
|
100
208
|
this.publicDirEntries = this.getLocalPublicDirEntries();
|
|
101
|
-
|
|
102
|
-
|
|
209
|
+
// Next.js's resolved config, the same one it writes into
|
|
210
|
+
// `required-server-files.json`.
|
|
211
|
+
this.nextConfigBasePath = (0, base_path_1.normalizeBasePath)(manifest.config.basePath);
|
|
212
|
+
this.nextConfigAssetPrefix = (0, base_path_1.relativeAssetPrefix)(manifest.config.assetPrefix);
|
|
213
|
+
this.nextConfigAssetPrefixPath = (0, base_path_1.assetPrefixPath)(manifest.config.assetPrefix);
|
|
103
214
|
const isFunctions = props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS ||
|
|
104
215
|
props.nextjsType === constants_1.NextjsType.REGIONAL_FUNCTIONS;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
216
|
+
this.relativeProjectDir = manifest.relativeProjectDir;
|
|
217
|
+
this.relativePathToEntrypoint = (0, posix_1.join)(manifest_1.RUNTIME_DIR_NAME, "server.mjs");
|
|
218
|
+
this.architecture = deploymentArchitecture(props);
|
|
219
|
+
this.deploymentRoots = this.resolveDeploymentRoots(manifest);
|
|
220
|
+
this.functionGroupBehaviors = manifest.behaviors ?? [];
|
|
221
|
+
// Only the RegionalContainers image carries `public/`: nothing is in front
|
|
222
|
+
// of it to answer those paths from S3. Every other type lists it here and
|
|
223
|
+
// reads a file the edge didn't route to S3 (a rewrite onto it) from there.
|
|
224
|
+
const publicOnDisk = props.nextjsType === constants_1.NextjsType.REGIONAL_CONTAINERS;
|
|
225
|
+
if (publicOnDisk) {
|
|
226
|
+
// Its generated Dockerfile `COPY`s `public`, which fails the image build
|
|
227
|
+
// when the app has none. An empty directory is what `next start` sees
|
|
228
|
+
// for an app without one anyway, and git doesn't track it.
|
|
229
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(props.buildDirectory, "public"), { recursive: true });
|
|
230
|
+
}
|
|
231
|
+
for (const root of this.deploymentRoots) {
|
|
232
|
+
this.stageRuntime(root.path, isFunctions, publicOnDisk);
|
|
233
|
+
// Functions run on the Lambda managed runtime (Amazon Linux 2023, glibc),
|
|
234
|
+
// for the architecture their Lambda deploys, whatever this machine is;
|
|
235
|
+
// Containers run on node:24-alpine (musl).
|
|
236
|
+
this.stageSharpForTarget(root, (0, node_path_1.join)(root.path, this.relativeProjectDir), `${isFunctions ? "linux" : "linuxmusl"}-${(0, get_architecture_1.toNodeArchitecture)(this.architecture)}`);
|
|
237
|
+
if (isFunctions) {
|
|
238
|
+
this.assertUnderLambdaLimit(root);
|
|
239
|
+
}
|
|
119
240
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Line up the groups the props asked for with the roots the build actually
|
|
244
|
+
* staged, and fail loudly when they disagree.
|
|
245
|
+
*
|
|
246
|
+
* They can disagree in both directions, and both mean the same thing — the
|
|
247
|
+
* `.next` on disk came from a build that did not see this `functionGroups` —
|
|
248
|
+
* but the causes differ: `skipBuild: true` with a build run by hand, or a
|
|
249
|
+
* stale `.next` from before the prop changed. Either way every later symptom
|
|
250
|
+
* (a Lambda missing an entrypoint, a CloudFront behavior pointing at a
|
|
251
|
+
* function that cannot serve it) is this, several steps downstream.
|
|
252
|
+
*/
|
|
253
|
+
resolveDeploymentRoots(manifest) {
|
|
254
|
+
const staged = manifest.groups;
|
|
255
|
+
// Names *and* routes: moving `/reports/**` into an existing group keeps the
|
|
256
|
+
// names and still leaves that group's zip without the reports entrypoints.
|
|
257
|
+
// Order is not: assignment and CloudFront behaviors both go most specific
|
|
258
|
+
// first, and no two distinct patterns tie on a URL (`function-groups.ts`),
|
|
259
|
+
// so reordering groups or routes is the same split.
|
|
260
|
+
// Already validated in the constructor, so this is absent or non-empty.
|
|
261
|
+
const wanted = this.props.functionGroups?.length
|
|
262
|
+
? toFunctionGroupSpecs(this.props.functionGroups)
|
|
263
|
+
: undefined;
|
|
264
|
+
const got = manifest.functionGroups;
|
|
265
|
+
if (JSON.stringify(sortedGroupSpecs(wanted)) !==
|
|
266
|
+
JSON.stringify(sortedGroupSpecs(got))) {
|
|
267
|
+
throw new Error(`${constants_1.LOG_PREFIX} \`functionGroups\` asks for ` +
|
|
268
|
+
`${wanted ? JSON.stringify(wanted) : "no splitting"} but the build ` +
|
|
269
|
+
`in ${this.dotNextPath} was split into ` +
|
|
270
|
+
`${got ? JSON.stringify(got) : "a single deployment root"}. ` +
|
|
271
|
+
`Groups are resolved during \`next build\` (cdk-nextjs passes them in ` +
|
|
272
|
+
`via ${function_groups_1.FUNCTION_GROUPS_ENV_VAR}), so this means the build output is ` +
|
|
273
|
+
`stale, or \`skipBuild: true\` and the build was run without that ` +
|
|
274
|
+
`variable set.`);
|
|
275
|
+
}
|
|
276
|
+
const names = staged ? Object.keys(staged) : [function_groups_1.DEFAULT_FUNCTION_GROUP];
|
|
277
|
+
const roots = names.map((name) => ({
|
|
278
|
+
name,
|
|
279
|
+
path: (0, node_path_1.join)(this.dotNextPath, manifest_1.ADAPTER_DIR_NAME, ...(0, manifest_1.groupStagingDirName)(staged ? name : undefined).split("/")),
|
|
280
|
+
routes: staged?.[name] ?? [],
|
|
281
|
+
}));
|
|
282
|
+
// `default` first, so any "the root" caller gets the group that owns
|
|
283
|
+
// everything unassigned.
|
|
284
|
+
roots.sort((a, b) => a.name === function_groups_1.DEFAULT_FUNCTION_GROUP
|
|
285
|
+
? -1
|
|
286
|
+
: b.name === function_groups_1.DEFAULT_FUNCTION_GROUP
|
|
287
|
+
? 1
|
|
288
|
+
: a.name.localeCompare(b.name));
|
|
289
|
+
for (const root of roots) {
|
|
290
|
+
if (!(0, node_fs_1.existsSync)(root.path)) {
|
|
291
|
+
throw new Error(`${constants_1.LOG_PREFIX} The deployment root for function group ` +
|
|
292
|
+
`"${root.name}" is missing from ${root.path}, though the adapter ` +
|
|
293
|
+
`manifest lists it. The \`.next\` directory has been modified since ` +
|
|
294
|
+
`\`next build\` ran.`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return roots;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Lambda enforces 250 MB unzipped at CloudFormation time, which is minutes
|
|
301
|
+
* into a deploy and reports only a size. Splitting exists to stay under that
|
|
302
|
+
* cap, so the error that tells you to split further has to name the group, its
|
|
303
|
+
* size, and what to do — and arrive at synth.
|
|
304
|
+
*/
|
|
305
|
+
assertUnderLambdaLimit(root) {
|
|
306
|
+
const bytes = storedSize(root.path);
|
|
307
|
+
debug(`${constants_1.LOG_PREFIX} Deployment root "${root.name}" is ${(bytes / 1e6).toFixed(1)} MB unzipped`);
|
|
308
|
+
if (bytes <= LAMBDA_UNZIPPED_LIMIT_BYTES) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const mb = (value) => `${(value / 1024 / 1024).toFixed(0)} MB`;
|
|
312
|
+
const isSplit = this.deploymentRoots.length > 1;
|
|
313
|
+
throw new Error(`${constants_1.LOG_PREFIX} Function group "${root.name}" is ${mb(bytes)} unzipped, ` +
|
|
314
|
+
`over Lambda's ${mb(LAMBDA_UNZIPPED_LIMIT_BYTES)} limit. ` +
|
|
315
|
+
(isSplit
|
|
316
|
+
? `Split its routes further, or move some of them into another group: ` +
|
|
317
|
+
`the cap is per function, so the shared \`next\` closure every group ` +
|
|
318
|
+
`duplicates costs nothing against any single budget.`
|
|
319
|
+
: `Use the \`functionGroups\` prop to package routes into separate ` +
|
|
320
|
+
`functions. Note that splitting only removes route-local code — ` +
|
|
321
|
+
`anything reachable from a shared layout or the \`next\` runtime is ` +
|
|
322
|
+
`in every group.`));
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Read the manifest the adapter's `onBuildComplete` wrote.
|
|
326
|
+
*
|
|
327
|
+
* Its absence means `next build` ran without cdk-nextjs's adapter registered
|
|
328
|
+
* (or with a stale `next.config`), which is worth saying plainly here: every
|
|
329
|
+
* later failure — a Lambda that cannot find `manifest.json`, an empty asset —
|
|
330
|
+
* is the same cause several steps downstream.
|
|
331
|
+
*/
|
|
332
|
+
readAdapterManifest() {
|
|
333
|
+
const manifestPath = (0, node_path_1.join)(this.dotNextPath, manifest_1.ADAPTER_DIR_NAME, manifest_1.MANIFEST_FILE_NAME);
|
|
334
|
+
if (!(0, node_fs_1.existsSync)(manifestPath)) {
|
|
335
|
+
throw new Error(`cdk-nextjs adapter manifest not found at ${manifestPath}. ` +
|
|
336
|
+
`"${this.buildCommand}" must run a Next.js build with cdk-nextjs's ` +
|
|
337
|
+
`adapter registered. cdk-nextjs sets \`NEXT_ADAPTER_PATH\` on the ` +
|
|
338
|
+
`build it runs itself, so this usually means either the build command ` +
|
|
339
|
+
`does not reach \`next build\` (a wrapper that drops the environment, ` +
|
|
340
|
+
`or a cached build that did not re-run), or \`skipBuild: true\` and ` +
|
|
341
|
+
`the build happened outside CDK. For the latter, set ` +
|
|
342
|
+
`\`adapterPath: require.resolve("cdk-nextjs/adapter")\` in ` +
|
|
343
|
+
`next.config. A custom \`distDir\` is not supported either: ` +
|
|
344
|
+
`cdk-nextjs reads the build from \`.next\`.`);
|
|
345
|
+
}
|
|
346
|
+
const manifest = JSON.parse((0, node_fs_1.readFileSync)(manifestPath, "utf-8"));
|
|
347
|
+
if (manifest.version !== manifest_1.ADAPTER_MANIFEST_VERSION) {
|
|
348
|
+
throw new Error(`The cdk-nextjs adapter manifest at ${manifestPath} is version ` +
|
|
349
|
+
`${manifest.version}, but this version of cdk-nextjs reads version ` +
|
|
350
|
+
`${manifest_1.ADAPTER_MANIFEST_VERSION}. The adapter that wrote it and the ` +
|
|
351
|
+
`constructs reading it come from the same package, so this means two ` +
|
|
352
|
+
`cdk-nextjs versions are installed, or the build output is stale.`);
|
|
353
|
+
}
|
|
354
|
+
return manifest;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Copy cdk-nextjs's own bundled request-handling shell and the manifest into
|
|
358
|
+
* `<deploymentRoot>/cdk-nextjs-runtime/`, which is where
|
|
359
|
+
* `deploymentRootOf`/`deployedManifestPath` expect to find them.
|
|
360
|
+
*
|
|
361
|
+
* Only the shell the deployment type actually runs is copied — the Lambda
|
|
362
|
+
* handler for Functions, the `node:http` server for Containers — so nothing
|
|
363
|
+
* ships ~1.5 MB of dead code and the tree says which type produced it. Both
|
|
364
|
+
* are copied from this package's `lib/`, next to the compiled construct.
|
|
365
|
+
*
|
|
366
|
+
* Every group gets the same shell *and the same manifest*: a function only
|
|
367
|
+
* knows which routes it owns so it can say so when misrouted, and that comes
|
|
368
|
+
* from {@link FUNCTION_GROUP_ENV_VAR}, not from a per-group manifest.
|
|
369
|
+
*/
|
|
370
|
+
stageRuntime(deploymentRoot, isFunctions, publicOnDisk) {
|
|
371
|
+
const shell = isFunctions ? "lambda.mjs" : "server.mjs";
|
|
372
|
+
const source = (0, node_path_1.join)(__dirname, "..", "runtime", shell);
|
|
373
|
+
const runtimeDir = (0, node_path_1.join)(deploymentRoot, manifest_1.RUNTIME_DIR_NAME);
|
|
374
|
+
// Removed rather than merged: a stale shell from the other deployment type
|
|
375
|
+
// would otherwise sit in the asset and change its hash for no reason.
|
|
376
|
+
(0, node_fs_1.rmSync)(runtimeDir, { recursive: true, force: true });
|
|
377
|
+
(0, node_fs_1.mkdirSync)(runtimeDir, { recursive: true });
|
|
378
|
+
(0, node_fs_1.cpSync)(source, (0, node_path_1.join)(runtimeDir, shell));
|
|
379
|
+
(0, node_fs_1.cpSync)((0, node_path_1.join)(this.dotNextPath, manifest_1.ADAPTER_DIR_NAME, manifest_1.MANIFEST_FILE_NAME), (0, node_path_1.join)(runtimeDir, manifest_1.MANIFEST_FILE_NAME));
|
|
380
|
+
if (!publicOnDisk) {
|
|
381
|
+
// The Lambda zips and the GlobalContainers image don't carry `public/`
|
|
382
|
+
// (its bytes are in S3), so the runtime can't list it at start the way
|
|
383
|
+
// the RegionalContainers image does.
|
|
384
|
+
// Listed here, after the build command, so `postbuild` output is in it:
|
|
385
|
+
// a rewrite onto a listed file is then served from S3 rather than 404ing.
|
|
386
|
+
writePublicFileList(runtimeDir, (0, node_path_1.join)(this.props.buildDirectory, "public"));
|
|
387
|
+
}
|
|
388
|
+
debug(`${constants_1.LOG_PREFIX} Staged ${shell} and ${manifest_1.MANIFEST_FILE_NAME} in ${runtimeDir}`);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* `NEXT_ADAPTER_PATH` for the build, so `adapterPath` in `next.config` is
|
|
392
|
+
* optional.
|
|
393
|
+
*
|
|
394
|
+
* Next.js reads the variable as the *default* value of `adapterPath`
|
|
395
|
+
* (`next/dist/server/config-shared.js`, `defaultConfig`), so an app that does
|
|
396
|
+
* set `adapterPath` still wins and nothing existing changes.
|
|
397
|
+
*
|
|
398
|
+
* Resolved from the Next.js app, not from cdk-nextjs's own `__dirname` and not
|
|
399
|
+
* left as a bare specifier. Both alternatives were tried and both are wrong:
|
|
400
|
+
*
|
|
401
|
+
* - cdk-nextjs's own location loses because the adapter resolves its sibling
|
|
402
|
+
* cache handler relative to wherever *it* was loaded from. An adapter loaded
|
|
403
|
+
* from outside the app's tree hands Next.js a `cacheHandler` outside
|
|
404
|
+
* `turbopack.root`, which Turbopack rejects outright ("leaves the filesystem
|
|
405
|
+
* root").
|
|
406
|
+
* - A bare specifier loses because Next.js resolves `adapterPath` from inside
|
|
407
|
+
* its own config loader, i.e. from `next`'s realpath. Under pnpm that is the
|
|
408
|
+
* virtual store (`node_modules/.pnpm/next@…/node_modules/next/`), and the
|
|
409
|
+
* walk up from there never reaches the app's own `node_modules`.
|
|
410
|
+
*
|
|
411
|
+
* Unset when `cdk-nextjs` is not resolvable from the app, which is legitimate:
|
|
412
|
+
* the Next.js app and the CDK app can be separate packages, and only the CDK one
|
|
413
|
+
* necessarily depends on cdk-nextjs. {@link readAdapterManifest} reports the
|
|
414
|
+
* resulting failure and names this case.
|
|
415
|
+
*
|
|
416
|
+
* One setup this cannot serve, and the reason this repo's own examples still set
|
|
417
|
+
* `adapterPath`: a `link:`/`file:` dependency on a cdk-nextjs checkout *outside*
|
|
418
|
+
* the app's project root. The symlink resolves out of the project, so the
|
|
419
|
+
* `cacheHandler` escape above applies. Set `adapterPath` in `next.config` there
|
|
420
|
+
* — it is resolved by the build, after whatever put the adapter in place.
|
|
421
|
+
*/
|
|
422
|
+
adapterPathEnv() {
|
|
423
|
+
try {
|
|
424
|
+
return {
|
|
425
|
+
NEXT_ADAPTER_PATH: require.resolve("cdk-nextjs/adapter", {
|
|
426
|
+
paths: [this.props.buildDirectory],
|
|
427
|
+
}),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
debug(`${constants_1.LOG_PREFIX} Could not resolve "cdk-nextjs/adapter" from ` +
|
|
432
|
+
`${this.props.buildDirectory}; leaving NEXT_ADAPTER_PATH unset, so ` +
|
|
433
|
+
`next.config must set \`adapterPath\`.`);
|
|
434
|
+
return {};
|
|
123
435
|
}
|
|
124
436
|
}
|
|
125
437
|
/**
|
|
@@ -139,33 +451,41 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
139
451
|
env: {
|
|
140
452
|
...process.env,
|
|
141
453
|
CDK_NEXTJS_INIT_CACHE_DIR: this.initCacheDir,
|
|
454
|
+
...this.adapterPathEnv(),
|
|
455
|
+
// `onBuildComplete` runs inside this process and cannot read CDK
|
|
456
|
+
// props, so the resolved groups travel as JSON. Absent when not
|
|
457
|
+
// splitting, which the adapter reads as "one deployment root".
|
|
458
|
+
...(this.props.functionGroups?.length
|
|
459
|
+
? {
|
|
460
|
+
[function_groups_1.FUNCTION_GROUPS_ENV_VAR]: JSON.stringify(toFunctionGroupSpecs(this.props.functionGroups)),
|
|
461
|
+
}
|
|
462
|
+
: {}),
|
|
142
463
|
},
|
|
143
464
|
});
|
|
144
|
-
// Copy patch-fetch.js into client JS bundle after build only for NextjsGlobalFunctions
|
|
145
|
-
if (this.props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS) {
|
|
146
|
-
this.patchFetchInClientJs();
|
|
147
|
-
}
|
|
148
465
|
}
|
|
149
466
|
catch (error) {
|
|
150
467
|
throw new Error(`Local build failed: ${error}`);
|
|
151
468
|
}
|
|
152
469
|
}
|
|
153
470
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
*
|
|
471
|
+
* Prepend `patch-fetch.js` to the client entrypoint chunks, for
|
|
472
|
+
* `NextjsGlobalFunctions` only.
|
|
473
|
+
*
|
|
474
|
+
* This is what makes POST work at all on that type. CloudFront reaches the
|
|
475
|
+
* server through a Lambda Function URL with `AuthType: AWS_IAM`, signed by an
|
|
476
|
+
* origin access control, and AWS documents the consequence: "If you use PUT or
|
|
477
|
+
* POST methods with your Lambda function URL, your users must compute the
|
|
478
|
+
* SHA256 of the body and include the payload hash value of the request body in
|
|
479
|
+
* the `x-amz-content-sha256` header when sending the request to CloudFront.
|
|
480
|
+
* Lambda doesn't support unsigned payloads."
|
|
481
|
+
*
|
|
482
|
+
* CloudFront signs GETs itself (empty-body hash) but will not hash a body, and
|
|
483
|
+
* a browser has no way to add that header on its own, so an unpatched app
|
|
484
|
+
* answers every server action, form submission and POST route handler with
|
|
485
|
+
* `403 InvalidSignatureException` before the request reaches Next.js. The
|
|
486
|
+
* patch installs `fetch`/`XMLHttpRequest` wrappers that compute the hash.
|
|
487
|
+
*
|
|
488
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-lambda.html
|
|
169
489
|
*/
|
|
170
490
|
patchFetchInClientJs() {
|
|
171
491
|
const staticChunksPath = (0, node_path_1.join)(this.dotNextPath, "static", "chunks");
|
|
@@ -178,69 +498,20 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
178
498
|
}
|
|
179
499
|
// Read the patch-fetch.js content
|
|
180
500
|
const patchFetchPath = (0, node_path_1.join)(__dirname, "patch-fetch.js");
|
|
181
|
-
if (!(0, node_fs_1.existsSync)(patchFetchPath)) {
|
|
182
|
-
throw new Error("patch-fetch.js not found");
|
|
183
|
-
}
|
|
184
501
|
const patchFetchContent = (0, node_fs_1.readFileSync)(patchFetchPath, "utf-8");
|
|
185
|
-
// Prepend patch-fetch logic to each entrypoint
|
|
502
|
+
// Prepend patch-fetch logic to each entrypoint, once. Now that this runs
|
|
503
|
+
// outside `runNextBuild`, the same `.next` can be synthesized more than
|
|
504
|
+
// once (`skipBuild: true`, `cdk synth` then `cdk deploy`, a retried
|
|
505
|
+
// deploy), and prepending twice would re-wrap the wrappers.
|
|
186
506
|
for (const chunkFile of chunkFiles) {
|
|
187
507
|
const chunkFilePath = (0, node_path_1.join)(staticChunksPath, chunkFile);
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Automatically finds the relative path from standalone directory to the
|
|
195
|
-
* package containing server.js by searching for server.js with a .next sibling.
|
|
196
|
-
* @returns "." for non-monorepo apps, or relative path like "app-playground" for monorepo apps
|
|
197
|
-
*/
|
|
198
|
-
findRelativePathToServerJs() {
|
|
199
|
-
const standaloneDir = (0, node_path_1.join)(this.dotNextPath, "standalone");
|
|
200
|
-
if (!(0, node_fs_1.existsSync)(standaloneDir)) {
|
|
201
|
-
throw new Error(`Cannot detect relativePathToPackage: standalone directory not found at ${standaloneDir}`);
|
|
202
|
-
}
|
|
203
|
-
const findServerJs = (dir, relativePath = "") => {
|
|
204
|
-
const entries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
205
|
-
for (const entry of entries) {
|
|
206
|
-
const fullPath = (0, node_path_1.join)(dir, entry.name);
|
|
207
|
-
if (entry.isDirectory() && entry.name !== "node_modules") {
|
|
208
|
-
// Recursively search directories (skip node_modules at root level)
|
|
209
|
-
const result = findServerJs(fullPath, (0, node_path_1.join)(relativePath, entry.name));
|
|
210
|
-
if (result !== null)
|
|
211
|
-
return result;
|
|
212
|
-
}
|
|
213
|
-
else if (entry.isFile() && entry.name === "server.js") {
|
|
214
|
-
// Check if this server.js has a .next sibling directory
|
|
215
|
-
const parentDir = dir;
|
|
216
|
-
const dotNextPath = (0, node_path_1.join)(parentDir, ".next");
|
|
217
|
-
if ((0, node_fs_1.existsSync)(dotNextPath)) {
|
|
218
|
-
return relativePath || ".";
|
|
219
|
-
}
|
|
220
|
-
}
|
|
508
|
+
const patchedContent = patchClientChunk((0, node_fs_1.readFileSync)(chunkFilePath, "utf-8"), patchFetchContent, chunkFilePath);
|
|
509
|
+
if (patchedContent === undefined) {
|
|
510
|
+
debug(`${constants_1.LOG_PREFIX} Already patched, skipping: ${chunkFilePath}`);
|
|
511
|
+
continue;
|
|
221
512
|
}
|
|
222
|
-
|
|
223
|
-
};
|
|
224
|
-
const result = findServerJs(standaloneDir);
|
|
225
|
-
if (result === null) {
|
|
226
|
-
throw new Error(`Cannot detect relativePathToPackage: Could not find server.js with .next sibling in ${standaloneDir}. ` +
|
|
227
|
-
`Please ensure Next.js build completed successfully or provide relativePathToPackage manually.`);
|
|
228
|
-
}
|
|
229
|
-
debug(`${constants_1.LOG_PREFIX} Auto-detected relativePathToPackage: "${result}"`);
|
|
230
|
-
return result;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Get build ID from .next directory
|
|
234
|
-
*/
|
|
235
|
-
getBuildId() {
|
|
236
|
-
const buildIdPath = (0, node_path_1.join)(this.dotNextPath, "BUILD_ID");
|
|
237
|
-
// Verify BUILD_ID exists (needed for cache partitioning)
|
|
238
|
-
if (!(0, node_fs_1.existsSync)(buildIdPath)) {
|
|
239
|
-
throw new Error(`BUILD_ID file not found at ${buildIdPath}. ` +
|
|
240
|
-
`Ensure Next.js build completed successfully.`);
|
|
513
|
+
(0, node_fs_1.writeFileSync)(chunkFilePath, patchedContent);
|
|
241
514
|
}
|
|
242
|
-
// BUILD_ID existence is already validated in validateNextBuildOutput()
|
|
243
|
-
return (0, node_fs_1.readFileSync)(buildIdPath, "utf-8").trim();
|
|
244
515
|
}
|
|
245
516
|
/**
|
|
246
517
|
* Get public directory entries from local filesystem
|
|
@@ -250,190 +521,108 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
250
521
|
if (!(0, node_fs_1.existsSync)(publicDirPath)) {
|
|
251
522
|
return [];
|
|
252
523
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}));
|
|
258
|
-
}
|
|
259
|
-
catch (error) {
|
|
260
|
-
console.warn(`${constants_1.LOG_PREFIX} Failed to read public directory: ${error}`);
|
|
261
|
-
return [];
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Recursively find and remove existing Sharp platform binaries
|
|
266
|
-
*/
|
|
267
|
-
removeExistingSharpBinaries(standalonePath) {
|
|
268
|
-
const nodeModulesPath = (0, node_path_1.join)(standalonePath, "node_modules");
|
|
269
|
-
if (!(0, node_fs_1.existsSync)(nodeModulesPath)) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
try {
|
|
273
|
-
// Use recursive readdirSync to find all Sharp binary directories and symlinks
|
|
274
|
-
const allEntries = (0, node_fs_1.readdirSync)(nodeModulesPath, {
|
|
275
|
-
recursive: true,
|
|
276
|
-
withFileTypes: true,
|
|
277
|
-
});
|
|
278
|
-
const sharpBinaryPaths = [];
|
|
279
|
-
for (const entry of allEntries) {
|
|
280
|
-
// Check for both directories and symlinks (pnpm creates symlinks)
|
|
281
|
-
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
282
|
-
// Match Sharp binary packages with more comprehensive patterns
|
|
283
|
-
const isSharpBinary = entry.name.includes("sharp-") ||
|
|
284
|
-
entry.name.includes("sharp-libvips");
|
|
285
|
-
if (isSharpBinary) {
|
|
286
|
-
// For recursive readdirSync, parentPath contains the full absolute path
|
|
287
|
-
const fullPath = (0, node_path_1.join)(entry.parentPath, entry.name);
|
|
288
|
-
sharpBinaryPaths.push(fullPath);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
debug(`${constants_1.LOG_PREFIX} Found ${sharpBinaryPaths.length} Sharp binary directories/symlinks to remove`);
|
|
293
|
-
// Remove all found Sharp binary directories and symlinks
|
|
294
|
-
for (const path of sharpBinaryPaths) {
|
|
295
|
-
try {
|
|
296
|
-
(0, node_fs_1.rmSync)(path, { recursive: true, force: true });
|
|
297
|
-
debug(`${constants_1.LOG_PREFIX} Removed: ${path}`);
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
console.warn(`${constants_1.LOG_PREFIX} Warning: Could not remove ${path}: ${error}`);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
catch (error) {
|
|
305
|
-
console.warn(`${constants_1.LOG_PREFIX} Warning: Could not read node_modules directory: ${error}`);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Download and install correct Sharp binaries for Linux MUSL
|
|
310
|
-
*/
|
|
311
|
-
downloadAndInstallSharpBinaries() {
|
|
312
|
-
const nodeModulesPath = (0, node_path_1.join)(this.dotNextPath, "standalone", "node_modules");
|
|
313
|
-
const imgPath = (0, node_path_1.join)(nodeModulesPath, "@img");
|
|
314
|
-
const arch = (0, get_architecture_1.getNodeArchitecture)();
|
|
315
|
-
this.installSharpPackages(imgPath, this.getSharpBinaryPackages(this.findSharpPackage(nodeModulesPath), `linuxmusl-${arch}`));
|
|
524
|
+
return (0, node_fs_1.readdirSync)(publicDirPath, { withFileTypes: true }).map((entry) => ({
|
|
525
|
+
name: entry.name,
|
|
526
|
+
isDirectory: entry.isDirectory(),
|
|
527
|
+
}));
|
|
316
528
|
}
|
|
317
529
|
/**
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
* the musl binaries the Docker/Lambda Web Adapter server function needs),
|
|
324
|
-
* and `required-server-files.json` (read by the handler at cold start to
|
|
325
|
-
* build `nextConfig`).
|
|
326
|
-
*/
|
|
327
|
-
prepareImageOptimizationAssets(standalonePath) {
|
|
328
|
-
const assetPath = (0, node_path_1.join)(this.dotNextPath, "cdk-nextjs-image-optimization");
|
|
329
|
-
const nodeModulesPath = (0, node_path_1.join)(assetPath, "node_modules");
|
|
330
|
-
const imgPath = (0, node_path_1.join)(nodeModulesPath, "@img");
|
|
331
|
-
(0, node_fs_1.rmSync)(assetPath, { recursive: true, force: true });
|
|
332
|
-
(0, node_fs_1.mkdirSync)(imgPath, { recursive: true });
|
|
333
|
-
// Pre-bundled by esbuild into this package's own lib/ output.
|
|
334
|
-
(0, node_fs_1.cpSync)((0, node_path_1.join)(__dirname, "..", "image-optimization"), assetPath, {
|
|
335
|
-
recursive: true,
|
|
336
|
-
});
|
|
337
|
-
const sharpSource = this.findSharpPackage((0, node_path_1.join)(standalonePath, "node_modules"));
|
|
338
|
-
if (sharpSource) {
|
|
339
|
-
this.copySharpRuntime(sharpSource, nodeModulesPath);
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
console.warn(`${constants_1.LOG_PREFIX} "sharp" not found in standalone build output. Add "sharp" as a dependency of your Next.js app to enable image optimization.`);
|
|
343
|
-
}
|
|
344
|
-
const requiredServerFiles = (0, node_path_1.join)(this.dotNextPath, "required-server-files.json");
|
|
345
|
-
if (!(0, node_fs_1.existsSync)(requiredServerFiles)) {
|
|
346
|
-
throw new Error(`${constants_1.LOG_PREFIX} "required-server-files.json" not found at ${requiredServerFiles}. The image optimization Lambda reads it at cold start to build its Next.js config.`);
|
|
347
|
-
}
|
|
348
|
-
(0, node_fs_1.cpSync)(requiredServerFiles, (0, node_path_1.join)(assetPath, "required-server-files.json"));
|
|
349
|
-
const arch = (0, get_architecture_1.getNodeArchitecture)();
|
|
350
|
-
this.installSharpPackages(imgPath, this.getSharpBinaryPackages(sharpSource, `linux-${arch}`));
|
|
351
|
-
return assetPath;
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Locate `sharp`'s JS wrapper inside a standalone `node_modules`.
|
|
530
|
+
* Strip whatever platform-specific Sharp binaries `next build`'s output file
|
|
531
|
+
* tracing staged, since they're the host's (e.g. macOS/glibc) rather than the
|
|
532
|
+
* deployment target's, then install the target's. Skipping this is silent:
|
|
533
|
+
* `imageOptimizer` catches the load failure internally and returns the
|
|
534
|
+
* unoptimized original with an HTTP 200.
|
|
355
535
|
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
536
|
+
* Only a root with `sharp` staged gets the binaries: the image optimizer
|
|
537
|
+
* brings it into `default`, which serves every `/_next/image`, and another
|
|
538
|
+
* group has it only if its own routes use it. So only `default` warns when
|
|
539
|
+
* it's missing.
|
|
359
540
|
*/
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
if (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const pnpmPath = (0, node_path_1.join)(nodeModulesPath, ".pnpm");
|
|
366
|
-
if (!(0, node_fs_1.existsSync)(pnpmPath)) {
|
|
367
|
-
return undefined;
|
|
368
|
-
}
|
|
369
|
-
const candidates = (0, node_fs_1.readdirSync)(pnpmPath)
|
|
370
|
-
.filter((name) => name.startsWith("sharp@"))
|
|
371
|
-
.sort();
|
|
372
|
-
for (const candidate of candidates.reverse()) {
|
|
373
|
-
const nested = (0, node_path_1.join)(pnpmPath, candidate, "node_modules", "sharp");
|
|
374
|
-
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(nested, "package.json"))) {
|
|
375
|
-
return nested;
|
|
541
|
+
stageSharpForTarget(root, projectDir, platform) {
|
|
542
|
+
const sharpSource = this.removeExistingSharpBinaries(root.path, projectDir);
|
|
543
|
+
if (!sharpSource) {
|
|
544
|
+
if (root.name === function_groups_1.DEFAULT_FUNCTION_GROUP) {
|
|
545
|
+
console.warn(`${constants_1.LOG_PREFIX} "sharp" not found in the staged build output. Add "sharp" as a dependency of your Next.js app to enable image optimization.`);
|
|
376
546
|
}
|
|
547
|
+
return;
|
|
377
548
|
}
|
|
378
|
-
|
|
549
|
+
this.installSharpPackages(sharpBinaryDir(root.path), this.getSharpBinaryPackages(sharpSource, platform));
|
|
379
550
|
}
|
|
380
551
|
/**
|
|
381
|
-
*
|
|
382
|
-
*
|
|
552
|
+
* Recursively find and remove existing Sharp platform binaries.
|
|
553
|
+
*
|
|
554
|
+
* `root` is walked whole rather than just its `node_modules`: the staged tree
|
|
555
|
+
* is keyed by repo-root-relative path, so in a monorepo the `node_modules`
|
|
556
|
+
* holding `sharp` is several directories down. {@link isSharpBinaryPackage} is
|
|
557
|
+
* what keeps that from reaching the app's own output — the staged root holds
|
|
558
|
+
* the compiled `.next` as well as the dependencies.
|
|
383
559
|
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
560
|
+
* @param projectDir the app's directory inside `root`, which `next` is
|
|
561
|
+
* resolved from.
|
|
562
|
+
* @returns the staged `sharp` JS wrapper to install next to, found in the same
|
|
563
|
+
* walk: a root can be hundreds of megabytes, and each group has one.
|
|
387
564
|
*/
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
//
|
|
391
|
-
//
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
565
|
+
removeExistingSharpBinaries(root, projectDir) {
|
|
566
|
+
const sharpCandidates = [];
|
|
567
|
+
// Links are listed, not followed: every link in a staged root points
|
|
568
|
+
// inside it (`stageFiles` copies the ones that don't), so its target is
|
|
569
|
+
// walked at its own path anyway, and following them is what let a
|
|
570
|
+
// workspace cycle hang the synth.
|
|
571
|
+
const allEntries = listTree(root);
|
|
572
|
+
// Symlinks are unlinked, not `rmSync`ed, and they go first. pnpm points
|
|
573
|
+
// several links at one store directory, and `rmSync(…, { recursive: true,
|
|
574
|
+
// force: true })` *silently no-ops* on a symlink whose target is already
|
|
575
|
+
// gone — `force` swallows the ENOENT its `rmdir` gets. Removing a store
|
|
576
|
+
// directory before its links therefore left dangling
|
|
577
|
+
// `@img/sharp-darwin-arm64` entries in the asset, which is a latent ENOENT
|
|
578
|
+
// in whatever next follows them (`sharp` does, when it looks for binaries).
|
|
579
|
+
const symlinks = [];
|
|
580
|
+
const directories = [];
|
|
581
|
+
for (const entry of allEntries) {
|
|
582
|
+
if (entry.isDirectory() && entry.name === "sharp") {
|
|
583
|
+
const path = (0, node_path_1.join)(entry.parentPath, entry.name);
|
|
584
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(path, "package.json"))) {
|
|
585
|
+
sharpCandidates.push(path);
|
|
586
|
+
}
|
|
398
587
|
continue;
|
|
399
588
|
}
|
|
400
|
-
|
|
401
|
-
if (!(0, node_fs_1.existsSync)((0, node_path_1.join)(source, "package.json"))) {
|
|
402
|
-
console.warn(`${constants_1.LOG_PREFIX} "sharp" dependency "${name}" not found in standalone build output; image optimization may fall back to serving unoptimized images.`);
|
|
589
|
+
if (!isSharpBinaryPackage(entry.parentPath, entry.name))
|
|
403
590
|
continue;
|
|
591
|
+
const fullPath = (0, node_path_1.join)(entry.parentPath, entry.name);
|
|
592
|
+
if (entry.isSymbolicLink()) {
|
|
593
|
+
symlinks.push(fullPath);
|
|
404
594
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
595
|
+
else if (entry.isDirectory()) {
|
|
596
|
+
directories.push(fullPath);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
debug(`${constants_1.LOG_PREFIX} Removing ${symlinks.length} Sharp binary symlinks and ${directories.length} directories`);
|
|
600
|
+
for (const path of symlinks) {
|
|
601
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
602
|
+
debug(`${constants_1.LOG_PREFIX} Unlinked: ${path}`);
|
|
603
|
+
}
|
|
604
|
+
for (const path of directories) {
|
|
605
|
+
(0, node_fs_1.rmSync)(path, { recursive: true, force: true });
|
|
606
|
+
debug(`${constants_1.LOG_PREFIX} Removed: ${path}`);
|
|
416
607
|
}
|
|
417
|
-
|
|
608
|
+
return pickStagedSharpPackage(sharpCandidates, resolveNextSharp(projectDir));
|
|
418
609
|
}
|
|
419
610
|
/**
|
|
420
611
|
* Resolve the `@img/sharp-<platform>` and `@img/sharp-libvips-<platform>`
|
|
421
612
|
* versions to install for a given platform.
|
|
422
613
|
*
|
|
423
|
-
* These must match the `sharp` JS wrapper that output file tracing
|
|
424
|
-
*
|
|
614
|
+
* These must match the `sharp` JS wrapper that output file tracing staged:
|
|
615
|
+
* `sharp`'s `lib/libvips.js` compares the binary's
|
|
425
616
|
* reported libvips version against its own `minimumLibvipsVersion` and
|
|
426
617
|
* throws at load when they disagree. `sharp` pins both in its
|
|
427
618
|
* `optionalDependencies`, so that manifest is the authoritative source.
|
|
428
619
|
*/
|
|
429
620
|
getSharpBinaryPackages(sharpSource, platform) {
|
|
621
|
+
// Only for a binary the staged `sharp` does not pin.
|
|
430
622
|
const fallback = [
|
|
431
623
|
{ name: `sharp-libvips-${platform}`, version: "1.2.4" },
|
|
432
624
|
{ name: `sharp-${platform}`, version: "0.34.5" },
|
|
433
625
|
];
|
|
434
|
-
if (!sharpSource) {
|
|
435
|
-
return fallback;
|
|
436
|
-
}
|
|
437
626
|
const manifest = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(sharpSource, "package.json"), "utf-8"));
|
|
438
627
|
const optionalDependencies = manifest.optionalDependencies ?? {};
|
|
439
628
|
return fallback.map((pkg) => {
|
|
@@ -451,56 +640,56 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
451
640
|
*/
|
|
452
641
|
installSharpPackages(imgPath, packages) {
|
|
453
642
|
const cacheDir = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "cdk-nextjs-sharp-cache");
|
|
454
|
-
|
|
455
|
-
(0, node_fs_1.mkdirSync)(cacheDir, { recursive: true });
|
|
456
|
-
}
|
|
643
|
+
(0, node_fs_1.mkdirSync)(cacheDir, { recursive: true });
|
|
457
644
|
for (const pkg of packages) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
645
|
+
const targetDir = (0, node_path_1.join)(imgPath, pkg.name);
|
|
646
|
+
const url = `https://registry.npmjs.org/@img/${pkg.name}/-/${pkg.name}-${pkg.version}.tgz`;
|
|
647
|
+
// Create a consistent filename based on package name and version
|
|
648
|
+
const cacheFileName = `${pkg.name}-${pkg.version}.tgz`;
|
|
649
|
+
const cachedFile = (0, node_path_1.join)(cacheDir, cacheFileName);
|
|
650
|
+
// Check if we already have a valid package cached; re-download if
|
|
651
|
+
// a previous run left behind a truncated/corrupt download
|
|
652
|
+
if ((0, node_fs_1.existsSync)(cachedFile) && this.isCachedFileValid(cachedFile)) {
|
|
653
|
+
debug(`${constants_1.LOG_PREFIX} Using cached ${pkg.name}@${pkg.version} from ${cachedFile}`);
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
debug(`${constants_1.LOG_PREFIX} Downloading ${pkg.name}@${pkg.version}...`);
|
|
657
|
+
// Download to a process-unique temp file in the same directory,
|
|
658
|
+
// then atomically rename it onto the shared cache path. Concurrent
|
|
659
|
+
// synth processes (e.g. Turborepo running multiple `cdk` commands)
|
|
660
|
+
// share this cache dir, so writing directly to `cachedFile` risks
|
|
661
|
+
// another process extracting a half-written file. Renaming within
|
|
662
|
+
// the same filesystem is atomic, so readers only ever see a
|
|
663
|
+
// complete file, whichever process wins the race.
|
|
664
|
+
const tempFile = (0, node_path_1.join)(cacheDir, `${cacheFileName}.${process.pid}-${(0, node_crypto_1.randomBytes)(6).toString("hex")}.tmp`);
|
|
665
|
+
try {
|
|
666
|
+
// --fail makes curl exit non-zero on HTTP errors and --retry
|
|
667
|
+
// handles transient connection drops so a partial transfer
|
|
668
|
+
// isn't cached as valid.
|
|
669
|
+
(0, node_child_process_1.execFileSync)("curl", [
|
|
670
|
+
"-L",
|
|
671
|
+
"--fail",
|
|
672
|
+
"--retry",
|
|
673
|
+
"3",
|
|
674
|
+
"--retry-delay",
|
|
675
|
+
"1",
|
|
676
|
+
"-o",
|
|
677
|
+
tempFile,
|
|
678
|
+
url,
|
|
679
|
+
], { stdio: "pipe" });
|
|
680
|
+
if (!this.isCachedFileValid(tempFile)) {
|
|
681
|
+
throw new Error(`Downloaded file for ${pkg.name}@${pkg.version} is empty or missing: ${tempFile}`);
|
|
493
682
|
}
|
|
494
|
-
|
|
683
|
+
(0, node_fs_1.renameSync)(tempFile, cachedFile);
|
|
495
684
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
catch (error) {
|
|
501
|
-
console.error(`${constants_1.LOG_PREFIX} Failed to install ${pkg.name}: ${error}`);
|
|
502
|
-
throw error;
|
|
685
|
+
finally {
|
|
686
|
+
(0, node_fs_1.rmSync)(tempFile, { force: true });
|
|
687
|
+
}
|
|
688
|
+
debug(`${constants_1.LOG_PREFIX} Cached ${pkg.name}@${pkg.version} to ${cachedFile}`);
|
|
503
689
|
}
|
|
690
|
+
(0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
|
|
691
|
+
(0, node_child_process_1.execFileSync)("tar", ["-xzf", cachedFile, "-C", targetDir, "--strip-components=1"], { stdio: "pipe" });
|
|
692
|
+
debug(`${constants_1.LOG_PREFIX} Installed ${pkg.name}@${pkg.version}`);
|
|
504
693
|
}
|
|
505
694
|
}
|
|
506
695
|
/**
|
|
@@ -518,4 +707,172 @@ class NextjsBuild extends constructs_1.Construct {
|
|
|
518
707
|
}
|
|
519
708
|
}
|
|
520
709
|
exports.NextjsBuild = NextjsBuild;
|
|
521
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25leHRqcy1idWlsZC9uZXh0anMtYnVpbGQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBLDJEQUE4QztBQUM5Qyw2Q0FBMEM7QUFDMUMscUNBVWlCO0FBQ2pCLHFDQUFpQztBQUNqQyx5Q0FBaUM7QUFDakMsMkNBQW9EO0FBQ3BELDJDQUF1QztBQUN2Qyw2REFBNkQ7QUFDN0Qsa0RBQTZCO0FBQzdCLDRDQUFzRDtBQUV0RCxrREFBNEQ7QUFDNUQsb0VBQXdFO0FBQ3hFLGdFQUFnRTtBQUVoRSxNQUFNLEtBQUssR0FBRyxJQUFBLGVBQVEsRUFBQyx5QkFBeUIsQ0FBQyxDQUFDO0FBd0JsRDs7O0dBR0c7QUFDSCxNQUFhLFdBQVksU0FBUSxzQkFBUzs7SUFDeEM7OztPQUdHO0lBQ0gsT0FBTyxDQUFTO0lBQ2hCOzs7T0FHRztJQUNILFlBQVksQ0FBUztJQUNyQjs7O09BR0c7SUFDSCxnQkFBZ0IsQ0FBbUI7SUFDbkM7Ozs7O09BS0c7SUFDSCx3QkFBd0IsQ0FBUztJQUNqQzs7Ozs7T0FLRztJQUNILHFCQUFxQixDQUFTO0lBQzlCOztPQUVHO0lBQ0gsV0FBVyxDQUFTO0lBQ3BCOzs7Ozs7T0FNRztJQUNILGtCQUFrQixDQUFTO0lBQzNCOzs7Ozs7T0FNRztJQUNILDBCQUEwQixDQUFVO0lBRTVCLEtBQUssQ0FBbUI7SUFDeEIsWUFBWSxDQUFTO0lBRTdCLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBdUI7UUFDL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUEsZ0JBQUksRUFBQyxLQUFLLENBQUMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXZELElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxD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LEtBQUssRUFBRSxDQUFDLENBQUM7Z0JBQ3ZFLE1BQU0sS0FBSyxDQUFDO1lBQ2QsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLGlCQUFpQixDQUFDLFFBQWdCO1FBQ3hDLElBQUksQ0FBQztZQUNILE9BQU8sSUFBQSxrQkFBUSxFQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7UUFDckMsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7O0FBL25CSCxrQ0Fnb0JDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhlY1N5bmMgfSBmcm9tIFwibm9kZTpjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHtcbiAgZXhpc3RzU3luYyxcbiAgcmVhZEZpbGVTeW5jLFxuICByZWFkZGlyU3luYyxcbiAgd3JpdGVGaWxlU3luYyxcbiAgcm1TeW5jLFxuICBta2RpclN5bmMsXG4gIGNwU3luYyxcbiAgcmVuYW1lU3luYyxcbiAgc3RhdFN5bmMsXG59IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGpvaW4gYXMgam9pblBvc2l4IH0gZnJvbSBcIm5vZGU6cGF0aC9wb3NpeFwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCBnZXREZWJ1ZyBmcm9tIFwiZGVidWdcIjtcbmltcG9ydCB7IExPR19QUkVGSVgsIE5leHRqc1R5cGUgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBOZXh0anNCYXNlUHJvcHMgfSBmcm9tIFwiLi4vcm9vdC1jb25zdHJ1Y3RzL25leHRqcy1iYXNlLWNvbnN0cnVjdFwiO1xuaW1wb3J0IHsgcmVhZE5leHRDb25maWdCYXNlUGF0aCB9IGZyb20gXCIuLi91dGlscy9iYXNlLXBhdGhcIjtcbmltcG9ydCB7IHVzZURlZGljYXRlZEltYWdlRnVuY3Rpb24gfSBmcm9tIFwiLi4vdXRpbHMvZXhwZXJpbWVudGFsLWZsYWdzXCI7XG5pbXBvcnQgeyBnZXROb2RlQXJjaGl0ZWN0dXJlIH0gZnJvbSBcIi4uL3V0aWxzL2dldC1hcmNoaXRlY3R1cmVcIjtcblxuY29uc3QgZGVidWcgPSBnZXREZWJ1ZyhcImNkay1uZXh0anM6bmV4dGpzLWJ1aWxkXCIpO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0J1aWxkUHJvcHMge1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQmFzZVByb3BzW1wiYnVpbGRDb21tYW5kXCJdfVxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGRDb21tYW5kOiBOZXh0anNCYXNlUHJvcHNbXCJidWlsZENvbW1hbmRcIl07XG4gIC8qKlxuICAgKiBEaXJlY3Rvcnkgd2hlcmUgdGhlIE5leHQuanMgYXBwbGljYXRpb24gaXMgbG9jYXRlZCBmb3IgbG9jYWwgYnVpbGRzLlxuICAgKiBUaGlzIHNob3VsZCBjb250YWluIHRoZSBwYWNrYWdlLmpzb24gYW5kIE5leHQuanMgYXBwbGljYXRpb24gZmlsZXMuXG4gICAqL1xuICByZWFkb25seSBidWlsZERpcmVjdG9yeTogc3RyaW5nO1xuICByZWFkb25seSBuZXh0anNUeXBlOiBOZXh0anNUeXBlO1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQmFzZVByb3BzLnNraXBCdWlsZH1cbiAgICovXG4gIHJlYWRvbmx5IHNraXBCdWlsZD86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHVibGljRGlyRW50cnkge1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGlzRGlyZWN0b3J5OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEJ1aWxkcyBOZXh0LmpzIGFzc2V0cy5cbiAqIEBsaW5rIGh0dHBzOi8vbmV4dGpzLm9yZy9kb2NzL3BhZ2VzL2FwaS1yZWZlcmVuY2UvbmV4dC1jb25maWctanMvb3V0cHV0XG4gKi9cbmV4cG9ydCBjbGFzcyBOZXh0anNCdWlsZCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBVbmlxdWUgaWQgZm9yIE5leHQuanMgYnVpbGQuIFVzZWQgdG8gcGFydGl0aW9uIGNhY2hlIHN0b3JhZ2UgYW5kIGFzXG4gICAqIG1ldGFkYXRhIGZvciBzdGF0aWMgYXNzZXRzIGluIFMzIGJ1Y2tldC5cbiAgICovXG4gIGJ1aWxkSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gdGhlIGluaXQgY2FjaGUgZGlyZWN0b3J5XG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvLm5leHQvY2RrLW5leHRqcy1pbml0LWNhY2hlXCJcbiAgICovXG4gIGluaXRDYWNoZURpcjogc3RyaW5nO1xuICAvKipcbiAgICogQWJzb2x1dGUgcGF0aCB0byBwdWJsaWMuIFVzZSBieSBDbG91ZEZyb250L0FMQiB0byBjcmVhdGUgYmVoYXZpb3JzL3J1bGVzXG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvcHVibGljXCJcbiAgICovXG4gIHB1YmxpY0RpckVudHJpZXM6IFB1YmxpY0RpckVudHJ5W107XG4gIC8qKlxuICAgKiBUaGUgZW50cnlwb2ludCBKYXZhU2NyaXB0IGZpbGUgdXNlZCBhcyBhbiBhcmd1bWVudCBmb3IgTm9kZS5qcyB0byBydW4gdGhlXG4gICAqIE5leHQuanMgc3RhbmRhbG9uZSBzZXJ2ZXIgcmVsYXRpdmUgdG8gdGhlIHN0YW5kYWxvbmUgZGlyZWN0b3J5LlxuICAgKiBAZXhhbXBsZSBcIi4vc2VydmVyLmpzXCJcbiAgICogQGV4YW1wbGUgXCIuL3BhY2thZ2VzL3VpL3NlcnZlci5qc1wiIChtb25vcmVwbylcbiAgICovXG4gIHJlbGF0aXZlUGF0aFRvRW50cnlwb2ludDogc3RyaW5nO1xuICAvKipcbiAgICogUmVsYXRpdmUgcGF0aCBmcm9tIHRoZSBzdGFuZGFsb25lIGRpcmVjdG9yeSB0byB0aGUgcGFja2FnZSBjb250YWluaW5nIHRoZSBOZXh0LmpzIGFwcC5cbiAgICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IGRldGVjdGVkIGZyb20gdGhlIHN0YW5kYWxvbmUgYnVpbGQgb3V0cHV0LlxuICAgKiBAZXhhbXBsZSBcIi5cIiBmb3Igbm9uLW1vbm9yZXBvIGFwcHNcbiAgICogQGV4YW1wbGUgXCIuL2FwcHMvd2ViXCIgZm9yIG1vbm9yZXBvIGFwcHNcbiAgICovXG4gIHJlbGF0aXZlUGF0aFRvUGFja2FnZTogc3RyaW5nO1xuICAvKipcbiAgICogQWJzb2x1dGUgcGF0aCB0byB0aGUgLm5leHQgZGlyZWN0b3J5IGNvbnRhaW5pbmcgTmV4dC5qcyBidWlsZCBhcnRpZmFjdHNcbiAgICovXG4gIGRvdE5leHRQYXRoOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgTmV4dC5qcyBhcHAncyBvd24gYGJhc2VQYXRoYCDigJQgdGhlIFVSTCBwcmVmaXggaXQgZ2VuZXJhdGVzIGl0cyBsaW5rcyBhbmRcbiAgICogYXNzZXQgaHJlZnMgdW5kZXIg4oCUIHJlYWQgb3V0IG9mIHRoZSBidWlsZCdzIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAuXG4gICAqIE5vcm1hbGl6ZWQgdG8gYSBiYXJlIHBhdGggc2VnbWVudCwgZW1wdHkgd2hlbiB0aGUgYXBwIHNldHMgbm9uZS4gRXhwb3NlZCBzb1xuICAgKiByb290IGNvbnN0cnVjdHMgY2FuIHJlY29uY2lsZSBpdCB3aXRoIHRoZSBDREsgYGJhc2VQYXRoYCBwcm9wLCB3aGljaCBpcyBhXG4gICAqIGRpc3RpbmN0IHRoaW5nOyBzZWUgYHJlc29sdmVCYXNlUGF0aGAuXG4gICAqL1xuICBuZXh0Q29uZmlnQmFzZVBhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gdGhlIGRpcmVjdG9yeSBwcmVwYXJlZCBmb3IgdGhlIGltYWdlIG9wdGltaXphdGlvbiBMYW1iZGFcbiAgICogYXNzZXQ6IGJ1bmRsZWQgaGFuZGxlciwgZ2xpYmMgYHNoYXJwYCBiaW5hcmllcywgYW5kIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAuXG4gICAqIE9ubHkgc2V0IGZvciB7QGxpbmsgTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TfSBhbmRcbiAgICoge0BsaW5rIE5leHRqc1R5cGUuUkVHSU9OQUxfRlVOQ1RJT05TfSwgYW5kIG9ubHkgd2hlbiB0aGUgZGVkaWNhdGVkIGltYWdlXG4gICAqIG9wdGltaXphdGlvbiBMYW1iZGEgaXMgZW5hYmxlZC5cbiAgICovXG4gIGltYWdlT3B0aW1pemF0aW9uQXNzZXRQYXRoPzogc3RyaW5nO1xuXG4gIHByaXZhdGUgcHJvcHM6IE5leHRqc0J1aWxkUHJvcHM7XG4gIHByaXZhdGUgYnVpbGRDb21tYW5kOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE5leHRqc0J1aWxkUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMucHJvcHMgPSBwcm9wcztcbiAgICB0aGlzLmRvdE5leHRQYXRoID0gam9pbihwcm9wcy5idWlsZERpcmVjdG9yeSwgXCIubmV4dFwiKTtcblxuICAgIHRoaXMuYnVpbGRDb21tYW5kID0gcHJvcHMuYnVpbGRDb21tYW5kIHx8IFwibnBtIHJ1biBidWlsZFwiO1xuXG4gICAgLy8gU2V0IGluaXQgY2FjaGUgZGlyZWN0b3J5IHBhdGhcbiAgICB0aGlzLmluaXRDYWNoZURpciA9IGpvaW4oXG4gICAgICBwcm9wcy5idWlsZERpcmVjdG9yeSxcbiAgICAgIFwiLm5leHRcIixcbiAgICAgIFwiY2RrLW5leHRqcy1pbml0LWNhY2hlXCIsXG4gICAgKTtcblxuICAgIC8vIEV4ZWN1dGUgbG9jYWwgYnVpbGQgcHJvY2Vzc1xuICAgIGlmIChwcm9wcy5za2lwQnVpbGQgIT09IHRydWUpIHtcbiAgICAgIHRoaXMucnVuTmV4dEJ1aWxkKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlYnVnKGAke0xPR19QUkVGSVh9IFNraXBwaW5nOiAke3RoaXMuYnVpbGRDb21tYW5kfWApO1xuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIGJ1aWxkIG91dHB1dCBhbmQgc2V0IHZhbGlkYXRlZCBwYXRoc1xuICAgIHRoaXMudmFsaWRhdGVOZXh0QnVpbGRPdXRwdXQoKTtcblxuICAgIC8vIEF1dG8tZGV0ZWN0IHJlbGF0aXZlUGF0aFRvUGFja2FnZSBmcm9tIHN0YW5kYWxvbmUgYnVpbGQgb3V0cHV0XG4gICAgdGhpcy5yZWxhdGl2ZVBhdGhUb1BhY2thZ2UgPSB0aGlzLmZpbmRSZWxhdGl2ZVBhdGhUb1NlcnZlckpzKCk7XG5cbiAgICAvLyBTZXQgZW50cnlwb2ludCBwYXRoIHVzaW5nIGRldGVjdGVkIHJlbGF0aXZlUGF0aFRvUGFja2FnZVxuICAgIHRoaXMucmVsYXRpdmVQYXRoVG9FbnRyeXBvaW50ID0gam9pblBvc2l4KFxuICAgICAgdGhpcy5yZWxhdGl2ZVBhdGhUb1BhY2thZ2UgPT09IFwiLlwiID8gXCJcIiA6IHRoaXMucmVsYXRpdmVQYXRoVG9QYWNrYWdlLFxuICAgICAgXCJzZXJ2ZXIuanNcIixcbiAgICApO1xuXG4gICAgdGhpcy5idWlsZElkID0gdGhpcy5nZXRCdWlsZElkKCk7XG4gICAgdGhpcy5wdWJsaWNEaXJFbnRyaWVzID0gdGhpcy5nZXRMb2NhbFB1YmxpY0RpckVudHJpZXMoKTtcbiAgICB0aGlzLm5leHRDb25maWdCYXNlUGF0aCA9IHJlYWROZXh0Q29uZmlnQmFzZVBhdGgodGhpcy5kb3ROZXh0UGF0aCk7XG5cbiAgICBjb25zdCBzdGFuZGFsb25lUGF0aCA9IGpvaW4odGhpcy5kb3ROZXh0UGF0aCwgXCJzdGFuZGFsb25lXCIpO1xuICAgIGNvbnN0IGlzRnVuY3Rpb25zID1cbiAgICAgIHByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuR0xPQkFMX0ZVTkNUSU9OUyB8fFxuICAgICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5SRUdJT05BTF9GVU5DVElPTlM7XG5cbiAgICBjb25zdCBkZWRpY2F0ZWRJbWFnZUZ1bmN0aW9uID0gaXNGdW5jdGlvbnMgJiYgdXNlRGVkaWNhdGVkSW1hZ2VGdW5jdGlvbigpO1xuXG4gICAgLy8gU3RyaXAgd2hhdGV2ZXIgcGxhdGZvcm0tc3BlY2lmaWMgU2hhcnAgYmluYXJpZXMgYG5leHQgYnVpbGRgJ3Mgb3V0cHV0XG4gICAgLy8gZmlsZSB0cmFjaW5nIGJ1bmRsZWQgaW4gZWl0aGVyIHdheSwgc2luY2UgdGhleSdyZSB0aGUgaG9zdCdzIChlLmcuXG4gICAgLy8gbWFjT1MvZ2xpYmMpIHJhdGhlciB0aGFuIHRoZSBkZXBsb3ltZW50IHRhcmdldCdzLlxuICAgIHRoaXMucmVtb3ZlRXhpc3RpbmdTaGFycEJpbmFyaWVzKHN0YW5kYWxvbmVQYXRoKTtcbiAgICAvLyBUaGUgc3RhbmRhbG9uZSBzZXJ2ZXIgc2VydmVzIGBfbmV4dC9pbWFnZWAgaXRzZWxmIHVubGVzcyBhIGRlZGljYXRlZFxuICAgIC8vIGltYWdlIG9wdGltaXphdGlvbiBMYW1iZGEgdGFrZXMgb3ZlciB0aGF0IHJvdXRlLCBhbmQgaXQgcnVucyBvblxuICAgIC8vIG5vZGU6MjQtYWxwaW5lIChzZWUgZnVuY3Rpb25zLkRvY2tlcmZpbGUpIC8gdGhlIHNhbWUgQWxwaW5lIGJhc2UgZm9yXG4gICAgLy8gQ29udGFpbmVycywgc28gaXQgbmVlZHMgbXVzbCBiaW5hcmllcy4gU2tpcHBpbmcgdGhpcyBpbnN0YWxsIHdoZW4gU2hhcnBcbiAgICAvLyAqaXMqIGludm9rZWQgZnJvbSB0aGUgc2VydmVyIGlzIHNpbGVudDogYGltYWdlT3B0aW1pemVyYCBjYXRjaGVzIHRoZVxuICAgIC8vIGxvYWQgZmFpbHVyZSBpbnRlcm5hbGx5IGFuZCByZXR1cm5zIHRoZSB1bm9wdGltaXplZCBvcmlnaW5hbCB3aXRoIGFuXG4gICAgLy8gSFRUUCAyMDAuXG4gICAgaWYgKCFkZWRpY2F0ZWRJbWFnZUZ1bmN0aW9uKSB7XG4gICAgICB0aGlzLmRvd25sb2FkQW5kSW5zdGFsbFNoYXJwQmluYXJpZXMoKTtcbiAgICB9XG5cbiAgICBpZiAoZGVkaWNhdGVkSW1hZ2VGdW5jdGlvbikge1xuICAgICAgdGhpcy5pbWFnZU9wdGltaXphdGlvbkFzc2V0UGF0aCA9XG4gICAgICAgIHRoaXMucHJlcGFyZUltYWdlT3B0aW1pemF0aW9uQXNzZXRzKHN0YW5kYWxvbmVQYXRoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSBsb2NhbCBidWlsZCBjb21tYW5kIGluIHRoZSBzcGVjaWZpZWQgZGlyZWN0b3J5XG4gICAqL1xuICBwcml2YXRlIHJ1bk5leHRCdWlsZCgpIHtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGAke0xPR19QUkVGSVh9IFJ1bm5pbmc6IFwiJHt0aGlzLmJ1aWxkQ29tbWFuZH1cIiBpbiBkaXJlY3Rvcnk6ICR7dGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeX1gLFxuICAgICk7XG5cbiAgICAvLyBDbGVhbiBleGlzdGluZyBjYWNoZSBkaXJlY3RvcnkgdG8gYXZvaWQgc3RhbGUgZGF0YSBmcm9tIHByZXZpb3VzIGJ1aWxkc1xuICAgIGlmIChleGlzdHNTeW5jKHRoaXMuaW5pdENhY2hlRGlyKSkge1xuICAgICAgcm1TeW5jKHRoaXMuaW5pdENhY2hlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICBkZWJ1ZyhgQ2xlYW5lZCBleGlzdGluZyBjYWNoZSBkaXJlY3Rvcnk6ICR7dGhpcy5pbml0Q2FjaGVEaXJ9YCk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKHRoaXMuYnVpbGRDb21tYW5kLCB7XG4gICAgICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgICAgICAgY3dkOiB0aGlzLnByb3BzLmJ1aWxkRGlyZWN0b3J5LFxuICAgICAgICBlbnY6IHtcbiAgICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgICBDREtfTkVYVEpTX0lOSVRfQ0FDSEVfRElSOiB0aGlzLmluaXRDYWNoZURpcixcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBDb3B5IHBhdGNoLWZldGNoLmpzIGludG8gY2xpZW50IEpTIGJ1bmRsZSBhZnRlciBidWlsZCBvbmx5IGZvciBOZXh0anNHbG9iYWxGdW5jdGlvbnNcbiAgICAgIGlmICh0aGlzLnByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuR0xPQkFMX0ZVTkNUSU9OUykge1xuICAgICAgICB0aGlzLnBhdGNoRmV0Y2hJbkNsaWVudEpzKCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTG9jYWwgYnVpbGQgZmFpbGVkOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBOZXh0LmpzIGJ1aWxkIG91dHB1dFxuICAgKiBBbGwgYnVpbGRzIG11c3QgYmUgc3RhbmRhbG9uZSAtIG5vIGZhbGxiYWNrIHRvIHJlZ3VsYXIgYnVpbGRzXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlTmV4dEJ1aWxkT3V0cHV0KCk6IHZvaWQge1xuICAgIGNvbnN0IHN0YW5kYWxvbmVEaXIgPSBqb2luKHRoaXMuZG90TmV4dFBhdGgsIFwic3RhbmRhbG9uZVwiKTtcbiAgICAvLyBTdGFuZGFsb25lIGRpcmVjdG9yeSBpcyBtYW5kYXRvcnlcbiAgICBpZiAoIWV4aXN0c1N5bmMoc3RhbmRhbG9uZURpcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFN0YW5kYWxvbmUgYnVpbGQgZGlyZWN0b3J5IG5vdCBmb3VuZDogJHtzdGFuZGFsb25lRGlyfS4gYCArXG4gICAgICAgICAgYEFsbCBidWlsZHMgbXVzdCBiZSBjb25maWd1cmVkIGZvciBzdGFuZGFsb25lIG91dHB1dC4gYCArXG4gICAgICAgICAgYFBsZWFzZSBlbnN1cmUgeW91ciBuZXh0LmNvbmZpZy5qcyBpbmNsdWRlcyAnb3V0cHV0OiBcInN0YW5kYWxvbmVcIicuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIEFkZGl0aW9uYWwgdmFsaWRhdGlvbiAoc2VydmVyLmpzIHdpdGggLm5leHQgc2libGluZykgaGFwcGVucyBpbiBmaW5kUmVsYXRpdmVQYXRoVG9TZXJ2ZXJKcygpXG4gIH1cblxuICAvKipcbiAgICogRmluZCBlbnRyeXBvaW50IGNsaWVudCBzaWRlIGpzIGZpbGVzIHRvIHBhdGNoIGBmZXRjaGAgb25seSBmb3IgTmV4dGpzR2xvYmFsRnVuY3Rpb25zXG4gICAqL1xuICBwcml2YXRlIHBhdGNoRmV0Y2hJbkNsaWVudEpzKCkge1xuICAgIGNvbnN0IHN0YXRpY0NodW5rc1BhdGggPSBqb2luKHRoaXMuZG90TmV4dFBhdGgsIFwic3RhdGljXCIsIFwiY2h1bmtzXCIpO1xuICAgIGNvbnN0IGNodW5rRmlsZXMgPSByZWFkZGlyU3luYyhzdGF0aWNDaHVua3NQYXRoKS5maWx0ZXIoXG4gICAgICAoZmlsZTogc3RyaW5nKSA9PlxuICAgICAgICAvLyBtYWluLWFwcC0gZm9yIHdlYnBhY2ssIHR1cmJvcGFjay0gZm9yIHR1cmJvXG4gICAgICAgIGZpbGUuc3RhcnRzV2l0aChcIm1haW4tYXBwLVwiKSB8fFxuICAgICAgICAoZmlsZS5zdGFydHNXaXRoKFwidHVyYm9wYWNrLVwiKSAmJiBmaWxlLmVuZHNXaXRoKFwiLmpzXCIpKSxcbiAgICApO1xuXG4gICAgaWYgKGNodW5rRmlsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBjbGllbnQgc2lkZSBqcyBlbnRyeXBvaW50IGZpbGVzIGZvdW5kXCIpO1xuICAgIH1cblxuICAgIC8vIFJlYWQgdGhlIHBhdGNoLWZldGNoLmpzIGNvbnRlbnRcbiAgICBjb25zdCBwYXRjaEZldGNoUGF0aCA9IGpvaW4oX19kaXJuYW1lLCBcInBhdGNoLWZldGNoLmpzXCIpO1xuICAgIGlmICghZXhpc3RzU3luYyhwYXRjaEZldGNoUGF0aCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInBhdGNoLWZldGNoLmpzIG5vdCBmb3VuZFwiKTtcbiAgICB9XG5cbiAgICBjb25zdCBwYXRjaEZldGNoQ29udGVudCA9IHJlYWRGaWxlU3luYyhwYXRjaEZldGNoUGF0aCwgXCJ1dGYtOFwiKTtcblxuICAgIC8vIFByZXBlbmQgcGF0Y2gtZmV0Y2ggbG9naWMgdG8gZWFjaCBlbnRyeXBvaW50XG4gICAgZm9yIChjb25zdCBjaHVua0ZpbGUgb2YgY2h1bmtGaWxlcykge1xuICAgICAgY29uc3QgY2h1bmtGaWxlUGF0aCA9IGpvaW4oc3RhdGljQ2h1bmtzUGF0aCwgY2h1bmtGaWxlKTtcbiAgICAgIGNvbnN0IG9yaWdpbmFsQ29udGVudCA9IHJlYWRGaWxlU3luYyhjaHVua0ZpbGVQYXRoLCBcInV0Zi04XCIpO1xuICAgICAgY29uc3QgcGF0Y2hlZENvbnRlbnQgPSBwYXRjaEZldGNoQ29udGVudCArIFwiXFxuXCIgKyBvcmlnaW5hbENvbnRlbnQ7XG4gICAgICB3cml0ZUZpbGVTeW5jKGNodW5rRmlsZVBhdGgsIHBhdGNoZWRDb250ZW50KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXV0b21hdGljYWxseSBmaW5kcyB0aGUgcmVsYXRpdmUgcGF0aCBmcm9tIHN0YW5kYWxvbmUgZGlyZWN0b3J5IHRvIHRoZVxuICAgKiBwYWNrYWdlIGNvbnRhaW5pbmcgc2VydmVyLmpzIGJ5IHNlYXJjaGluZyBmb3Igc2VydmVyLmpzIHdpdGggYSAubmV4dCBzaWJsaW5nLlxuICAgKiBAcmV0dXJucyBcIi5cIiBmb3Igbm9uLW1vbm9yZXBvIGFwcHMsIG9yIHJlbGF0aXZlIHBhdGggbGlrZSBcImFwcC1wbGF5Z3JvdW5kXCIgZm9yIG1vbm9yZXBvIGFwcHNcbiAgICovXG4gIHByaXZhdGUgZmluZFJlbGF0aXZlUGF0aFRvU2VydmVySnMoKTogc3RyaW5nIHtcbiAgICBjb25zdCBzdGFuZGFsb25lRGlyID0gam9pbih0aGlzLmRvdE5leHRQYXRoLCBcInN0YW5kYWxvbmVcIik7XG5cbiAgICBpZiAoIWV4aXN0c1N5bmMoc3RhbmRhbG9uZURpcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENhbm5vdCBkZXRlY3QgcmVsYXRpdmVQYXRoVG9QYWNrYWdlOiBzdGFuZGFsb25lIGRpcmVjdG9yeSBub3QgZm91bmQgYXQgJHtzdGFuZGFsb25lRGlyfWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGZpbmRTZXJ2ZXJKcyA9IChcbiAgICAgIGRpcjogc3RyaW5nLFxuICAgICAgcmVsYXRpdmVQYXRoOiBzdHJpbmcgPSBcIlwiLFxuICAgICk6IHN0cmluZyB8IG51bGwgPT4ge1xuICAgICAgY29uc3QgZW50cmllcyA9IHJlYWRkaXJTeW5jKGRpciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pO1xuXG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGRpciwgZW50cnkubmFtZSk7XG5cbiAgICAgICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkgJiYgZW50cnkubmFtZSAhPT0gXCJub2RlX21vZHVsZXNcIikge1xuICAgICAgICAgIC8vIFJlY3Vyc2l2ZWx5IHNlYXJjaCBkaXJlY3RvcmllcyAoc2tpcCBub2RlX21vZHVsZXMgYXQgcm9vdCBsZXZlbClcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBmaW5kU2VydmVySnMoZnVsbFBhdGgsIGpvaW4ocmVsYXRpdmVQYXRoLCBlbnRyeS5uYW1lKSk7XG4gICAgICAgICAgaWYgKHJlc3VsdCAhPT0gbnVsbCkgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSBlbHNlIGlmIChlbnRyeS5pc0ZpbGUoKSAmJiBlbnRyeS5uYW1lID09PSBcInNlcnZlci5qc1wiKSB7XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBzZXJ2ZXIuanMgaGFzIGEgLm5leHQgc2libGluZyBkaXJlY3RvcnlcbiAgICAgICAgICBjb25zdCBwYXJlbnREaXIgPSBkaXI7XG4gICAgICAgICAgY29uc3QgZG90TmV4dFBhdGggPSBqb2luKHBhcmVudERpciwgXCIubmV4dFwiKTtcbiAgICAgICAgICBpZiAoZXhpc3RzU3luYyhkb3ROZXh0UGF0aCkpIHtcbiAgICAgICAgICAgIHJldHVybiByZWxhdGl2ZVBhdGggfHwgXCIuXCI7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xuXG4gICAgY29uc3QgcmVzdWx0ID0gZmluZFNlcnZlckpzKHN0YW5kYWxvbmVEaXIpO1xuICAgIGlmIChyZXN1bHQgPT09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENhbm5vdCBkZXRlY3QgcmVsYXRpdmVQYXRoVG9QYWNrYWdlOiBDb3VsZCBub3QgZmluZCBzZXJ2ZXIuanMgd2l0aCAubmV4dCBzaWJsaW5nIGluICR7c3RhbmRhbG9uZURpcn0uIGAgK1xuICAgICAgICAgIGBQbGVhc2UgZW5zdXJlIE5leHQuanMgYnVpbGQgY29tcGxldGVkIHN1Y2Nlc3NmdWxseSBvciBwcm92aWRlIHJlbGF0aXZlUGF0aFRvUGFja2FnZSBtYW51YWxseS5gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBBdXRvLWRldGVjdGVkIHJlbGF0aXZlUGF0aFRvUGFja2FnZTogXCIke3Jlc3VsdH1cImApO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGJ1aWxkIElEIGZyb20gLm5leHQgZGlyZWN0b3J5XG4gICAqL1xuICBwcml2YXRlIGdldEJ1aWxkSWQoKTogc3RyaW5nIHtcbiAgICBjb25zdCBidWlsZElkUGF0aCA9IGpvaW4odGhpcy5kb3ROZXh0UGF0aCwgXCJCVUlMRF9JRFwiKTtcbiAgICAvLyBWZXJpZnkgQlVJTERfSUQgZXhpc3RzIChuZWVkZWQgZm9yIGNhY2hlIHBhcnRpdGlvbmluZylcbiAgICBpZiAoIWV4aXN0c1N5bmMoYnVpbGRJZFBhdGgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBCVUlMRF9JRCBmaWxlIG5vdCBmb3VuZCBhdCAke2J1aWxkSWRQYXRofS4gYCArXG4gICAgICAgICAgYEVuc3VyZSBOZXh0LmpzIGJ1aWxkIGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIEJVSUxEX0lEIGV4aXN0ZW5jZSBpcyBhbHJlYWR5IHZhbGlkYXRlZCBpbiB2YWxpZGF0ZU5leHRCdWlsZE91dHB1dCgpXG4gICAgcmV0dXJuIHJlYWRGaWxlU3luYyhidWlsZElkUGF0aCwgXCJ1dGYtOFwiKS50cmltKCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHB1YmxpYyBkaXJlY3RvcnkgZW50cmllcyBmcm9tIGxvY2FsIGZpbGVzeXN0ZW1cbiAgICovXG4gIHByaXZhdGUgZ2V0TG9jYWxQdWJsaWNEaXJFbnRyaWVzKCk6IFB1YmxpY0RpckVudHJ5W10ge1xuICAgIGNvbnN0IHB1YmxpY0RpclBhdGggPSBqb2luKHRoaXMucHJvcHMuYnVpbGREaXJlY3RvcnksIFwicHVibGljXCIpO1xuICAgIGlmICghZXhpc3RzU3luYyhwdWJsaWNEaXJQYXRoKSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gcmVhZGRpclN5bmMocHVibGljRGlyUGF0aCwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pLm1hcChcbiAgICAgICAgKGVudHJ5OiBhbnkpID0+ICh7XG4gICAgICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgICAgICBpc0RpcmVjdG9yeTogZW50cnkuaXNEaXJlY3RvcnkoKSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLndhcm4oYCR7TE9HX1BSRUZJWH0gRmFpbGVkIHRvIHJlYWQgcHVibGljIGRpcmVjdG9yeTogJHtlcnJvcn1gKTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVjdXJzaXZlbHkgZmluZCBhbmQgcmVtb3ZlIGV4aXN0aW5nIFNoYXJwIHBsYXRmb3JtIGJpbmFyaWVzXG4gICAqL1xuICBwcml2YXRlIHJlbW92ZUV4aXN0aW5nU2hhcnBCaW5hcmllcyhzdGFuZGFsb25lUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3Qgbm9kZU1vZHVsZXNQYXRoID0gam9pbihzdGFuZGFsb25lUGF0aCwgXCJub2RlX21vZHVsZXNcIik7XG4gICAgaWYgKCFleGlzdHNTeW5jKG5vZGVNb2R1bGVzUGF0aCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgLy8gVXNlIHJlY3Vyc2l2ZSByZWFkZGlyU3luYyB0byBmaW5kIGFsbCBTaGFycCBiaW5hcnkgZGlyZWN0b3JpZXMgYW5kIHN5bWxpbmtzXG4gICAgICBjb25zdCBhbGxFbnRyaWVzID0gcmVhZGRpclN5bmMobm9kZU1vZHVsZXNQYXRoLCB7XG4gICAgICAgIHJlY3Vyc2l2ZTogdHJ1ZSxcbiAgICAgICAgd2l0aEZpbGVUeXBlczogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBzaGFycEJpbmFyeVBhdGhzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGFsbEVudHJpZXMpIHtcbiAgICAgICAgLy8gQ2hlY2sgZm9yIGJvdGggZGlyZWN0b3JpZXMgYW5kIHN5bWxpbmtzIChwbnBtIGNyZWF0ZXMgc3ltbGlua3MpXG4gICAgICAgIGlmIChlbnRyeS5pc0RpcmVjdG9yeSgpIHx8IGVudHJ5LmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgICAvLyBNYXRjaCBTaGFycCBiaW5hcnkgcGFja2FnZXMgd2l0aCBtb3JlIGNvbXByZWhlbnNpdmUgcGF0dGVybnNcbiAgICAgICAgICBjb25zdCBpc1NoYXJwQmluYXJ5ID1cbiAgICAgICAgICAgIGVudHJ5Lm5hbWUuaW5jbHVkZXMoXCJzaGFycC1cIikgfHxcbiAgICAgICAgICAgIGVudHJ5Lm5hbWUuaW5jbHVkZXMoXCJzaGFycC1saWJ2aXBzXCIpO1xuXG4gICAgICAgICAgaWYgKGlzU2hhcnBCaW5hcnkpIHtcbiAgICAgICAgICAgIC8vIEZvciByZWN1cnNpdmUgcmVhZGRpclN5bmMsIHBhcmVudFBhdGggY29udGFpbnMgdGhlIGZ1bGwgYWJzb2x1dGUgcGF0aFxuICAgICAgICAgICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGVudHJ5LnBhcmVudFBhdGgsIGVudHJ5Lm5hbWUpO1xuICAgICAgICAgICAgc2hhcnBCaW5hcnlQYXRocy5wdXNoKGZ1bGxQYXRoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZGVidWcoXG4gICAgICAgIGAke0xPR19QUkVGSVh9IEZvdW5kICR7c2hhcnBCaW5hcnlQYXRocy5sZW5ndGh9IFNoYXJwIGJpbmFyeSBkaXJlY3Rvcmllcy9zeW1saW5rcyB0byByZW1vdmVgLFxuICAgICAgKTtcblxuICAgICAgLy8gUmVtb3ZlIGFsbCBmb3VuZCBTaGFycCBiaW5hcnkgZGlyZWN0b3JpZXMgYW5kIHN5bWxpbmtzXG4gICAgICBmb3IgKGNvbnN0IHBhdGggb2Ygc2hhcnBCaW5hcnlQYXRocykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHJtU3luYyhwYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICAgICAgZGVidWcoYCR7TE9HX1BSRUZJWH0gUmVtb3ZlZDogJHtwYXRofWApO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgIGAke0xPR19QUkVGSVh9IFdhcm5pbmc6IENvdWxkIG5vdCByZW1vdmUgJHtwYXRofTogJHtlcnJvcn1gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSBXYXJuaW5nOiBDb3VsZCBub3QgcmVhZCBub2RlX21vZHVsZXMgZGlyZWN0b3J5OiAke2Vycm9yfWAsXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEb3dubG9hZCBhbmQgaW5zdGFsbCBjb3JyZWN0IFNoYXJwIGJpbmFyaWVzIGZvciBMaW51eCBNVVNMXG4gICAqL1xuICBwcml2YXRlIGRvd25sb2FkQW5kSW5zdGFsbFNoYXJwQmluYXJpZXMoKTogdm9pZCB7XG4gICAgY29uc3Qgbm9kZU1vZHVsZXNQYXRoID0gam9pbihcbiAgICAgIHRoaXMuZG90TmV4dFBhdGgsXG4gICAgICBcInN0YW5kYWxvbmVcIixcbiAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgKTtcbiAgICBjb25zdCBpbWdQYXRoID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwiQGltZ1wiKTtcbiAgICBjb25zdCBhcmNoID0gZ2V0Tm9kZUFyY2hpdGVjdHVyZSgpO1xuXG4gICAgdGhpcy5pbnN0YWxsU2hhcnBQYWNrYWdlcyhcbiAgICAgIGltZ1BhdGgsXG4gICAgICB0aGlzLmdldFNoYXJwQmluYXJ5UGFja2FnZXMoXG4gICAgICAgIHRoaXMuZmluZFNoYXJwUGFja2FnZShub2RlTW9kdWxlc1BhdGgpLFxuICAgICAgICBgbGludXhtdXNsLSR7YXJjaH1gLFxuICAgICAgKSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIHRoZSBkZXBsb3ltZW50IGFzc2V0IGZvciB0aGUgZGVkaWNhdGVkIGltYWdlIG9wdGltaXphdGlvblxuICAgKiBMYW1iZGE6IHRoZSBwcmUtYnVuZGxlZCBoYW5kbGVyIChmcm9tIHRoaXMgcGFja2FnZSdzIG93biBgbGliL2Agb3V0cHV0KSxcbiAgICogYHNoYXJwYCdzIEpTIHdyYXBwZXIgKGFscmVhZHkgZGVyZWZlcmVuY2VkIGZyb20gdGhlIHBucG0gc3RvcmUgYnkgTmV4dCdzXG4gICAqIG91dHB1dCBmaWxlIHRyYWNpbmcgaW50byB0aGUgc3RhbmRhbG9uZSBidWlsZCksIGdsaWJjIGBzaGFycGAgYmluYXJpZXNcbiAgICogKHRoZSBzdGFuZGFyZCBMYW1iZGEgbWFuYWdlZCBydW50aW1lIGlzIEFtYXpvbiBMaW51eCAyMDIzL2dsaWJjLCB1bmxpa2VcbiAgICogdGhlIG11c2wgYmluYXJpZXMgdGhlIERvY2tlci9MYW1iZGEgV2ViIEFkYXB0ZXIgc2VydmVyIGZ1bmN0aW9uIG5lZWRzKSxcbiAgICogYW5kIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAgKHJlYWQgYnkgdGhlIGhhbmRsZXIgYXQgY29sZCBzdGFydCB0b1xuICAgKiBidWlsZCBgbmV4dENvbmZpZ2ApLlxuICAgKi9cbiAgcHJpdmF0ZSBwcmVwYXJlSW1hZ2VPcHRpbWl6YXRpb25Bc3NldHMoc3RhbmRhbG9uZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgYXNzZXRQYXRoID0gam9pbih0aGlzLmRvdE5leHRQYXRoLCBcImNkay1uZXh0anMtaW1hZ2Utb3B0aW1pemF0aW9uXCIpO1xuICAgIGNvbnN0IG5vZGVNb2R1bGVzUGF0aCA9IGpvaW4oYXNzZXRQYXRoLCBcIm5vZGVfbW9kdWxlc1wiKTtcbiAgICBjb25zdCBpbWdQYXRoID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwiQGltZ1wiKTtcblxuICAgIHJtU3luYyhhc3NldFBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBta2RpclN5bmMoaW1nUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICAvLyBQcmUtYnVuZGxlZCBieSBlc2J1aWxkIGludG8gdGhpcyBwYWNrYWdlJ3Mgb3duIGxpYi8gb3V0cHV0LlxuICAgIGNwU3luYyhqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcImltYWdlLW9wdGltaXphdGlvblwiKSwgYXNzZXRQYXRoLCB7XG4gICAgICByZWN1cnNpdmU6IHRydWUsXG4gICAgfSk7XG5cbiAgICBjb25zdCBzaGFycFNvdXJjZSA9IHRoaXMuZmluZFNoYXJwUGFja2FnZShcbiAgICAgIGpvaW4oc3RhbmRhbG9uZVBhdGgsIFwibm9kZV9tb2R1bGVzXCIpLFxuICAgICk7XG4gICAgaWYgKHNoYXJwU291cmNlKSB7XG4gICAgICB0aGlzLmNvcHlTaGFycFJ1bnRpbWUoc2hhcnBTb3VyY2UsIG5vZGVNb2R1bGVzUGF0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYCR7TE9HX1BSRUZJWH0gXCJzaGFycFwiIG5vdCBmb3VuZCBpbiBzdGFuZGFsb25lIGJ1aWxkIG91dHB1dC4gQWRkIFwic2hhcnBcIiBhcyBhIGRlcGVuZGVuY3kgb2YgeW91ciBOZXh0LmpzIGFwcCB0byBlbmFibGUgaW1hZ2Ugb3B0aW1pemF0aW9uLmAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcXVpcmVkU2VydmVyRmlsZXMgPSBqb2luKFxuICAgICAgdGhpcy5kb3ROZXh0UGF0aCxcbiAgICAgIFwicmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25cIixcbiAgICApO1xuICAgIGlmICghZXhpc3RzU3luYyhyZXF1aXJlZFNlcnZlckZpbGVzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSBcInJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uXCIgbm90IGZvdW5kIGF0ICR7cmVxdWlyZWRTZXJ2ZXJGaWxlc30uIFRoZSBpbWFnZSBvcHRpbWl6YXRpb24gTGFtYmRhIHJlYWRzIGl0IGF0IGNvbGQgc3RhcnQgdG8gYnVpbGQgaXRzIE5leHQuanMgY29uZmlnLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBjcFN5bmMocmVxdWlyZWRTZXJ2ZXJGaWxlcywgam9pbihhc3NldFBhdGgsIFwicmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25cIikpO1xuXG4gICAgY29uc3QgYXJjaCA9IGdldE5vZGVBcmNoaXRlY3R1cmUoKTtcbiAgICB0aGlzLmluc3RhbGxTaGFycFBhY2thZ2VzKFxuICAgICAgaW1nUGF0aCxcbiAgICAgIHRoaXMuZ2V0U2hhcnBCaW5hcnlQYWNrYWdlcyhzaGFycFNvdXJjZSwgYGxpbnV4LSR7YXJjaH1gKSxcbiAgICApO1xuXG4gICAgcmV0dXJuIGFzc2V0UGF0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2NhdGUgYHNoYXJwYCdzIEpTIHdyYXBwZXIgaW5zaWRlIGEgc3RhbmRhbG9uZSBgbm9kZV9tb2R1bGVzYC5cbiAgICpcbiAgICogTmV4dCdzIG91dHB1dCBmaWxlIHRyYWNpbmcgcHJlc2VydmVzIHRoZSBpbnN0YWxsZXIncyBvbi1kaXNrIGxheW91dCwgc29cbiAgICogbnBtL3lhcm4gcHJvZHVjZSBhIGhvaXN0ZWQgYG5vZGVfbW9kdWxlcy9zaGFycGAgd2hpbGUgcG5wbSBvbmx5XG4gICAqIG1hdGVyaWFsaXplcyBgbm9kZV9tb2R1bGVzLy5wbnBtL3NoYXJwQDx2ZXJzaW9uPi9ub2RlX21vZHVsZXMvc2hhcnBgLlxuICAgKi9cbiAgcHJpdmF0ZSBmaW5kU2hhcnBQYWNrYWdlKG5vZGVNb2R1bGVzUGF0aDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBob2lzdGVkID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwic2hhcnBcIik7XG4gICAgaWYgKGV4aXN0c1N5bmMoam9pbihob2lzdGVkLCBcInBhY2thZ2UuanNvblwiKSkpIHtcbiAgICAgIHJldHVybiBob2lzdGVkO1xuICAgIH1cblxuICAgIGNvbnN0IHBucG1QYXRoID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwiLnBucG1cIik7XG4gICAgaWYgKCFleGlzdHNTeW5jKHBucG1QYXRoKSkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBjb25zdCBjYW5kaWRhdGVzID0gcmVhZGRpclN5bmMocG5wbVBhdGgpXG4gICAgICAuZmlsdGVyKChuYW1lKSA9PiBuYW1lLnN0YXJ0c1dpdGgoXCJzaGFycEBcIikpXG4gICAgICAuc29ydCgpO1xuICAgIGZvciAoY29uc3QgY2FuZGlkYXRlIG9mIGNhbmRpZGF0ZXMucmV2ZXJzZSgpKSB7XG4gICAgICBjb25zdCBuZXN0ZWQgPSBqb2luKHBucG1QYXRoLCBjYW5kaWRhdGUsIFwibm9kZV9tb2R1bGVzXCIsIFwic2hhcnBcIik7XG4gICAgICBpZiAoZXhpc3RzU3luYyhqb2luKG5lc3RlZCwgXCJwYWNrYWdlLmpzb25cIikpKSB7XG4gICAgICAgIHJldHVybiBuZXN0ZWQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb3B5IGBzaGFycGAgcGx1cyB0aGUgdHJhbnNpdGl2ZSBgZGVwZW5kZW5jaWVzYCBjbG9zdXJlIGByZXF1aXJlKFwic2hhcnBcIilgXG4gICAqIHB1bGxzIGluIChgQGltZy9jb2xvdXJgLCBgZGV0ZWN0LWxpYmNgLCBgc2VtdmVyYCkgaW50byBgdGFyZ2V0UGF0aGAuXG4gICAqXG4gICAqIENvcHlpbmcgb25seSBgc2hhcnBgIGl0c2VsZiBsZWF2ZXMgdGhvc2UgcmVxdWlyZXMgdW5yZXNvbHZhYmxlLCBhbmRcbiAgICogYGltYWdlT3B0aW1pemVyYCBzd2FsbG93cyB0aGUgcmVzdWx0aW5nIGBNT0RVTEVfTk9UX0ZPVU5EYCBieSBmYWxsaW5nIGJhY2tcbiAgICogdG8gc2VydmluZyB0aGUgdW5vcHRpbWl6ZWQgb3JpZ2luYWwsIHNvIHRoZSBvbWlzc2lvbiBpcyBvdGhlcndpc2Ugc2lsZW50LlxuICAgKi9cbiAgcHJpdmF0ZSBjb3B5U2hhcnBSdW50aW1lKHNoYXJwU291cmNlOiBzdHJpbmcsIHRhcmdldFBhdGg6IHN0cmluZyk6IHZvaWQge1xuICAgIC8vIFVuZGVyIHBucG0gYSBwYWNrYWdlJ3MgZGVwZW5kZW5jaWVzIGFyZSBzeW1saW5rZWQgaW50byB0aGUgc2libGluZ1xuICAgIC8vIGRpcmVjdG9yeSBhbG9uZ3NpZGUgaXQsIHdoaWNoIGlzIGFsc28gd2hlcmUgYSBob2lzdGVkIGxheW91dCBrZWVwc1xuICAgIC8vIHRoZW0sIHNvIHRoZSBzYW1lIGxvb2t1cCBjb3ZlcnMgYm90aC5cbiAgICBjb25zdCBsb29rdXBQYXRoID0gam9pbihzaGFycFNvdXJjZSwgXCIuLlwiKTtcbiAgICBjb25zdCBxdWV1ZSA9IFtcInNoYXJwXCJdO1xuICAgIGNvbnN0IGNvcGllZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gICAgd2hpbGUgKHF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IG5hbWUgPSBxdWV1ZS5zaGlmdCgpITtcbiAgICAgIGlmIChjb3BpZWQuaGFzKG5hbWUpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzb3VyY2UgPSBuYW1lID09PSBcInNoYXJwXCIgPyBzaGFycFNvdXJjZSA6IGpvaW4obG9va3VwUGF0aCwgbmFtZSk7XG4gICAgICBpZiAoIWV4aXN0c1N5bmMoam9pbihzb3VyY2UsIFwicGFja2FnZS5qc29uXCIpKSkge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgYCR7TE9HX1BSRUZJWH0gXCJzaGFycFwiIGRlcGVuZGVuY3kgXCIke25hbWV9XCIgbm90IGZvdW5kIGluIHN0YW5kYWxvbmUgYnVpbGQgb3V0cHV0OyBpbWFnZSBvcHRpbWl6YXRpb24gbWF5IGZhbGwgYmFjayB0byBzZXJ2aW5nIHVub3B0aW1pemVkIGltYWdlcy5gLFxuICAgICAgICApO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gYGRlcmVmZXJlbmNlYCByZXNvbHZlcyBwbnBtJ3Mgc3ltbGlua3MgaW50byByZWFsIGZpbGVzLCBzaW5jZSB0aGVcbiAgICAgIC8vIExhbWJkYSBhc3NldCBpcyBhIHN0YW5kYWxvbmUgZGlyZWN0b3J5IHdpdGggbm8gc3RvcmUgdG8gbGluayBpbnRvLlxuICAgICAgY3BTeW5jKHNvdXJjZSwgam9pbih0YXJnZXRQYXRoLCBuYW1lKSwge1xuICAgICAgICByZWN1cnNpdmU6IHRydWUsXG4gICAgICAgIGRlcmVmZXJlbmNlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICBjb3BpZWQuYWRkKG5hbWUpO1xuXG4gICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICAgIHJlYWRGaWxlU3luYyhqb2luKHNvdXJjZSwgXCJwYWNrYWdlLmpzb25cIiksIFwidXRmLThcIiksXG4gICAgICApO1xuICAgICAgLy8gUGxhdGZvcm0gYmluYXJpZXMgYXJlIG9wdGlvbmFsRGVwZW5kZW5jaWVzLCBpbnN0YWxsZWQgc2VwYXJhdGVseSBhdFxuICAgICAgLy8gdGhlIHZlcnNpb25zIHRoaXMgc2FtZSBtYW5pZmVzdCBwaW5zLCBzbyBvbmx5IGBkZXBlbmRlbmNpZXNgIGhlcmUuXG4gICAgICBxdWV1ZS5wdXNoKC4uLk9iamVjdC5rZXlzKG1hbmlmZXN0LmRlcGVuZGVuY2llcyA/PyB7fSkpO1xuICAgIH1cblxuICAgIGRlYnVnKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gQ29waWVkIHNoYXJwIHJ1bnRpbWU6ICR7Wy4uLmNvcGllZF0uc29ydCgpLmpvaW4oXCIsIFwiKX1gLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSB0aGUgYEBpbWcvc2hhcnAtPHBsYXRmb3JtPmAgYW5kIGBAaW1nL3NoYXJwLWxpYnZpcHMtPHBsYXRmb3JtPmBcbiAgICogdmVyc2lvbnMgdG8gaW5zdGFsbCBmb3IgYSBnaXZlbiBwbGF0Zm9ybS5cbiAgICpcbiAgICogVGhlc2UgbXVzdCBtYXRjaCB0aGUgYHNoYXJwYCBKUyB3cmFwcGVyIHRoYXQgb3V0cHV0IGZpbGUgdHJhY2luZyBwdXQgaW5cbiAgICogdGhlIHN0YW5kYWxvbmUgYnVpbGQ6IGBzaGFycGAncyBgbGliL2xpYnZpcHMuanNgIGNvbXBhcmVzIHRoZSBiaW5hcnknc1xuICAgKiByZXBvcnRlZCBsaWJ2aXBzIHZlcnNpb24gYWdhaW5zdCBpdHMgb3duIGBtaW5pbXVtTGlidmlwc1ZlcnNpb25gIGFuZFxuICAgKiB0aHJvd3MgYXQgbG9hZCB3aGVuIHRoZXkgZGlzYWdyZWUuIGBzaGFycGAgcGlucyBib3RoIGluIGl0c1xuICAgKiBgb3B0aW9uYWxEZXBlbmRlbmNpZXNgLCBzbyB0aGF0IG1hbmlmZXN0IGlzIHRoZSBhdXRob3JpdGF0aXZlIHNvdXJjZS5cbiAgICovXG4gIHByaXZhdGUgZ2V0U2hhcnBCaW5hcnlQYWNrYWdlcyhcbiAgICBzaGFycFNvdXJjZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIHBsYXRmb3JtOiBzdHJpbmcsXG4gICk6IHsgbmFtZTogc3RyaW5nOyB2ZXJzaW9uOiBzdHJpbmcgfVtdIHtcbiAgICBjb25zdCBmYWxsYmFjayA9IFtcbiAgICAgIHsgbmFtZTogYHNoYXJwLWxpYnZpcHMtJHtwbGF0Zm9ybX1gLCB2ZXJzaW9uOiBcIjEuMi40XCIgfSxcbiAgICAgIHsgbmFtZTogYHNoYXJwLSR7cGxhdGZvcm19YCwgdmVyc2lvbjogXCIwLjM0LjVcIiB9LFxuICAgIF07XG5cbiAgICBpZiAoIXNoYXJwU291cmNlKSB7XG4gICAgICByZXR1cm4gZmFsbGJhY2s7XG4gICAgfVxuXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKFxuICAgICAgcmVhZEZpbGVTeW5jKGpvaW4oc2hhcnBTb3VyY2UsIFwicGFja2FnZS5qc29uXCIpLCBcInV0Zi04XCIpLFxuICAgICk7XG4gICAgY29uc3Qgb3B0aW9uYWxEZXBlbmRlbmNpZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPVxuICAgICAgbWFuaWZlc3Qub3B0aW9uYWxEZXBlbmRlbmNpZXMgPz8ge307XG5cbiAgICByZXR1cm4gZmFsbGJhY2subWFwKChwa2cpID0+IHtcbiAgICAgIGNvbnN0IHZlcnNpb24gPSBvcHRpb25hbERlcGVuZGVuY2llc1tgQGltZy8ke3BrZy5uYW1lfWBdO1xuICAgICAgaWYgKCF2ZXJzaW9uKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICBgJHtMT0dfUFJFRklYfSBzaGFycEAke21hbmlmZXN0LnZlcnNpb259IGRvZXMgbm90IHBpbiBcIkBpbWcvJHtwa2cubmFtZX1cIjsgZmFsbGluZyBiYWNrIHRvICR7cGtnLnZlcnNpb259LmAsXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBwa2c7XG4gICAgICB9XG4gICAgICByZXR1cm4geyBuYW1lOiBwa2cubmFtZSwgdmVyc2lvbiB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERvd25sb2FkICh3aXRoIGNhY2hpbmcpIGFuZCBleHRyYWN0IFNoYXJwJ3MgcGxhdGZvcm0tc3BlY2lmaWMgYmluYXJ5XG4gICAqIHBhY2thZ2VzIGludG8gYGltZ1BhdGhgLlxuICAgKi9cbiAgcHJpdmF0ZSBpbnN0YWxsU2hhcnBQYWNrYWdlcyhcbiAgICBpbWdQYXRoOiBzdHJpbmcsXG4gICAgcGFja2FnZXM6IHsgbmFtZTogc3RyaW5nOyB2ZXJzaW9uOiBzdHJpbmcgfVtdLFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBjYWNoZURpciA9IGpvaW4odG1wZGlyKCksIFwiY2RrLW5leHRqcy1zaGFycC1jYWNoZVwiKTtcbiAgICBpZiAoIWV4aXN0c1N5bmMoY2FjaGVEaXIpKSB7XG4gICAgICBta2RpclN5bmMoY2FjaGVEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgcGtnIG9mIHBhY2thZ2VzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB0YXJnZXREaXIgPSBqb2luKGltZ1BhdGgsIHBrZy5uYW1lKTtcbiAgICAgICAgY29uc3QgdXJsID0gYGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BpbWcvJHtwa2cubmFtZX0vLS8ke3BrZy5uYW1lfS0ke3BrZy52ZXJzaW9ufS50Z3pgO1xuXG4gICAgICAgIC8vIENyZWF0ZSBhIGNvbnNpc3RlbnQgZmlsZW5hbWUgYmFzZWQgb24gcGFja2FnZSBuYW1lIGFuZCB2ZXJzaW9uXG4gICAgICAgIGNvbnN0IGNhY2hlRmlsZU5hbWUgPSBgJHtwa2cubmFtZX0tJHtwa2cudmVyc2lvbn0udGd6YDtcbiAgICAgICAgY29uc3QgY2FjaGVkRmlsZSA9IGpvaW4oY2FjaGVEaXIsIGNhY2hlRmlsZU5hbWUpO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIHdlIGFscmVhZHkgaGF2ZSBhIHZhbGlkIHBhY2thZ2UgY2FjaGVkOyByZS1kb3dubG9hZCBpZlxuICAgICAgICAvLyBhIHByZXZpb3VzIHJ1biBsZWZ0IGJlaGluZCBhIHRydW5jYXRlZC9jb3JydXB0IGRvd25sb2FkXG4gICAgICAgIGlmIChleGlzdHNTeW5jKGNhY2hlZEZpbGUpICYmIHRoaXMuaXNDYWNoZWRGaWxlVmFsaWQoY2FjaGVkRmlsZSkpIHtcbiAgICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICAgIGAke0xPR19QUkVGSVh9IFVzaW5nIGNhY2hlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSBmcm9tICR7Y2FjaGVkRmlsZX1gLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZGVidWcoYCR7TE9HX1BSRUZJWH0gRG93bmxvYWRpbmcgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn0uLi5gKTtcblxuICAgICAgICAgIC8vIERvd25sb2FkIHRvIGEgcHJvY2Vzcy11bmlxdWUgdGVtcCBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeSxcbiAgICAgICAgICAvLyB0aGVuIGF0b21pY2FsbHkgcmVuYW1lIGl0IG9udG8gdGhlIHNoYXJlZCBjYWNoZSBwYXRoLiBDb25jdXJyZW50XG4gICAgICAgICAgLy8gc3ludGggcHJvY2Vzc2VzIChlLmcuIFR1cmJvcmVwbyBydW5uaW5nIG11bHRpcGxlIGBjZGtgIGNvbW1hbmRzKVxuICAgICAgICAgIC8vIHNoYXJlIHRoaXMgY2FjaGUgZGlyLCBzbyB3cml0aW5nIGRpcmVjdGx5IHRvIGBjYWNoZWRGaWxlYCByaXNrc1xuICAgICAgICAgIC8vIGFub3RoZXIgcHJvY2VzcyBleHRyYWN0aW5nIGEgaGFsZi13cml0dGVuIGZpbGUuIFJlbmFtaW5nIHdpdGhpblxuICAgICAgICAgIC8vIHRoZSBzYW1lIGZpbGVzeXN0ZW0gaXMgYXRvbWljLCBzbyByZWFkZXJzIG9ubHkgZXZlciBzZWUgYVxuICAgICAgICAgIC8vIGNvbXBsZXRlIGZpbGUsIHdoaWNoZXZlciBwcm9jZXNzIHdpbnMgdGhlIHJhY2UuXG4gICAgICAgICAgY29uc3QgdGVtcEZpbGUgPSBqb2luKFxuICAgICAgICAgICAgY2FjaGVEaXIsXG4gICAgICAgICAgICBgJHtjYWNoZUZpbGVOYW1lfS4ke3Byb2Nlc3MucGlkfS0ke3JhbmRvbUJ5dGVzKDYpLnRvU3RyaW5nKFwiaGV4XCIpfS50bXBgLFxuICAgICAgICAgICk7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIC0tZmFpbCBtYWtlcyBjdXJsIGV4aXQgbm9uLXplcm8gb24gSFRUUCBlcnJvcnMgYW5kIC0tcmV0cnlcbiAgICAgICAgICAgIC8vIGhhbmRsZXMgdHJhbnNpZW50IGNvbm5lY3Rpb24gZHJvcHMgc28gYSBwYXJ0aWFsIHRyYW5zZmVyXG4gICAgICAgICAgICAvLyBpc24ndCBjYWNoZWQgYXMgdmFsaWQuXG4gICAgICAgICAgICBleGVjU3luYyhcbiAgICAgICAgICAgICAgYGN1cmwgLUwgLS1mYWlsIC0tcmV0cnkgMyAtLXJldHJ5LWRlbGF5IDEgLW8gXCIke3RlbXBGaWxlfVwiIFwiJHt1cmx9XCJgLFxuICAgICAgICAgICAgICB7IHN0ZGlvOiBcInBpcGVcIiB9LFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgaWYgKCF0aGlzLmlzQ2FjaGVkRmlsZVZhbGlkKHRlbXBGaWxlKSkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgYERvd25sb2FkZWQgZmlsZSBmb3IgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn0gaXMgZW1wdHkgb3IgbWlzc2luZzogJHt0ZW1wRmlsZX1gLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZW5hbWVTeW5jKHRlbXBGaWxlLCBjYWNoZWRGaWxlKTtcbiAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgaWYgKGV4aXN0c1N5bmModGVtcEZpbGUpKSB7XG4gICAgICAgICAgICAgIHJtU3luYyh0ZW1wRmlsZSwgeyBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICAgIGAke0xPR19QUkVGSVh9IENhY2hlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSB0byAke2NhY2hlZEZpbGV9YCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgbWtkaXJTeW5jKHRhcmdldERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIGV4ZWNTeW5jKFxuICAgICAgICAgIGB0YXIgLXh6ZiBcIiR7Y2FjaGVkRmlsZX1cIiAtQyBcIiR7dGFyZ2V0RGlyfVwiIC0tc3RyaXAtY29tcG9uZW50cz0xYCxcbiAgICAgICAgICB7IHN0ZGlvOiBcInBpcGVcIiB9LFxuICAgICAgICApO1xuXG4gICAgICAgIGRlYnVnKGAke0xPR19QUkVGSVh9IEluc3RhbGxlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufWApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgJHtMT0dfUFJFRklYfSBGYWlsZWQgdG8gaW5zdGFsbCAke3BrZy5uYW1lfTogJHtlcnJvcn1gKTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyB0aGF0IGEgY2FjaGVkIFNoYXJwIGJpbmFyeSBhcmNoaXZlIGlzIG5vbi1lbXB0eS4gR3VhcmRzIGFnYWluc3RcbiAgICogYSB0cnVuY2F0ZWQvY29ycnVwdCBkb3dubG9hZCAoZS5nLiBmcm9tIGEgZHJvcHBlZCBjb25uZWN0aW9uKSBiZWluZ1xuICAgKiByZXVzZWQgYWNyb3NzIHN5bnRoIG9wZXJhdGlvbnMuXG4gICAqL1xuICBwcml2YXRlIGlzQ2FjaGVkRmlsZVZhbGlkKGZpbGVQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHN0YXRTeW5jKGZpbGVQYXRoKS5zaXplID4gMDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
710
|
+
/**
|
|
711
|
+
* What travels to the adapter in {@link FUNCTION_GROUPS_ENV_VAR}, and what it
|
|
712
|
+
* records back as `AdapterManifest.functionGroups`.
|
|
713
|
+
*/
|
|
714
|
+
function toFunctionGroupSpecs(groups) {
|
|
715
|
+
return groups.map(({ name, routes }) => ({ name, routes }));
|
|
716
|
+
}
|
|
717
|
+
/** `groups` in a canonical order, for comparing two of them. */
|
|
718
|
+
function sortedGroupSpecs(groups) {
|
|
719
|
+
return groups
|
|
720
|
+
?.map(({ name, routes }) => ({ name, routes: [...routes].sort() }))
|
|
721
|
+
.sort((a, b) => (a.name < b.name ? -1 : 1));
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Pick the staged `sharp` JS wrapper out of every copy found in the tree.
|
|
725
|
+
*
|
|
726
|
+
* Unlike a standalone build there is no single `node_modules` to look in: the
|
|
727
|
+
* tree mirrors repo-root-relative paths, so the search is by directory name.
|
|
728
|
+
*
|
|
729
|
+
* An app can have two `sharp` copies at different versions (its own, hoisted,
|
|
730
|
+
* and next's, nested under `next/node_modules`), and every binary goes into the
|
|
731
|
+
* one root `@img`, so the copy pinning them has to be the one `next`'s image
|
|
732
|
+
* optimizer loads: `nextSharp`, when {@link resolveNextSharp} found it. Otherwise
|
|
733
|
+
* shortest path wins as the closest to a hoisted install, sorted for
|
|
734
|
+
* determinism.
|
|
735
|
+
*/
|
|
736
|
+
function pickStagedSharpPackage(candidates, nextSharp) {
|
|
737
|
+
const used = nextSharp &&
|
|
738
|
+
candidates.find((candidate) => nextSharp.startsWith((0, node_fs_1.realpathSync)(candidate) + node_path_1.sep));
|
|
739
|
+
if (used) {
|
|
740
|
+
return used;
|
|
741
|
+
}
|
|
742
|
+
candidates.sort((a, b) => a.length - b.length || a.localeCompare(b));
|
|
743
|
+
if (candidates.length > 1) {
|
|
744
|
+
debug(`${constants_1.LOG_PREFIX} Multiple staged "sharp" copies; using ${candidates[0]}`);
|
|
745
|
+
}
|
|
746
|
+
return candidates[0];
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* The real path of the `sharp` entry point the staged `next` resolves from
|
|
750
|
+
* `projectDir`, `undefined` when either does not resolve.
|
|
751
|
+
*/
|
|
752
|
+
function resolveNextSharp(projectDir) {
|
|
753
|
+
try {
|
|
754
|
+
// The anchor file needn't exist; `createRequire` only reads its directory.
|
|
755
|
+
const nextPackage = (0, node_module_1.createRequire)((0, node_path_1.join)(projectDir, "cdk-nextjs-next-resolver.cjs")).resolve("next/package.json");
|
|
756
|
+
return (0, node_module_1.createRequire)(nextPackage).resolve("sharp");
|
|
757
|
+
}
|
|
758
|
+
catch {
|
|
759
|
+
return undefined;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Whether the entry `name` in `parentPath` is an `@img/sharp-*` platform binary
|
|
764
|
+
* package, or pnpm's store entry for one.
|
|
765
|
+
*
|
|
766
|
+
* The name alone is not enough to delete a directory by. A route segment called
|
|
767
|
+
* `sharp-edges` stages `.next/server/app/sharp-edges/`, and removing it left the
|
|
768
|
+
* manifest listing an entrypoint that is no longer on disk — every request to
|
|
769
|
+
* that route 500ing with "Could not load the entrypoint". Nor is "a `sharp-`
|
|
770
|
+
* package": `sharp-ico` and `sharp-phash` are unrelated dependencies, and
|
|
771
|
+
* removing them failed the app at runtime with MODULE_NOT_FOUND. So both the
|
|
772
|
+
* scope and the place have to match:
|
|
773
|
+
*
|
|
774
|
+
* - `node_modules/@img/sharp-…`, where every platform binary actually lives
|
|
775
|
+
* - `node_modules/.pnpm/@img+sharp-…@0.35.4`, pnpm's store, whose entries are
|
|
776
|
+
* also what the `@img` links point at (`sharp-libvips-…` matches the same way)
|
|
777
|
+
*
|
|
778
|
+
* The `node_modules` segment is required as well, so an app directory that
|
|
779
|
+
* happens to be called `@img` or `.pnpm` is still left alone.
|
|
780
|
+
*/
|
|
781
|
+
function isSharpBinaryPackage(parentPath, name) {
|
|
782
|
+
const segments = parentPath.split(node_path_1.sep);
|
|
783
|
+
const parent = segments[segments.length - 1];
|
|
784
|
+
const scoped = (parent === "@img" && name.startsWith("sharp-")) ||
|
|
785
|
+
(parent === ".pnpm" && name.startsWith("@img+sharp-"));
|
|
786
|
+
return scoped && segments.includes("node_modules");
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Where the target's `@img/sharp-*` binaries go: `<root>/node_modules/@img`.
|
|
790
|
+
*
|
|
791
|
+
* Not next to the staged `sharp` package. Under pnpm that is
|
|
792
|
+
* `node_modules/.pnpm/sharp@x/node_modules/@img`, which only the store copy of
|
|
793
|
+
* `sharp` resolves from: a dereferenced link to `sharp` (a copy at
|
|
794
|
+
* `app/node_modules/sharp`, say) looks for `@img` from its own path and walks
|
|
795
|
+
* up, never into the store. Both the Functions zip (`zipDirectory`) and the
|
|
796
|
+
* Containers `COPY` keep the links, so it is the store copy that loads, and its
|
|
797
|
+
* walk up reaches the root `node_modules` too, so it serves either layout. It
|
|
798
|
+
* is also where main installed them.
|
|
799
|
+
*/
|
|
800
|
+
function sharpBinaryDir(root) {
|
|
801
|
+
return (0, node_path_1.join)(root, "node_modules", "@img");
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Every entry under `root`, links listed but not followed.
|
|
805
|
+
*
|
|
806
|
+
* An explicit walk rather than `readdirSync({ recursive: true })`, which on
|
|
807
|
+
* Node 24 descends into symlinked directories itself and so never returns on a
|
|
808
|
+
* cycle — two workspace packages that link each other, which is how pnpm wires a
|
|
809
|
+
* monorepo.
|
|
810
|
+
*/
|
|
811
|
+
function listTree(root) {
|
|
812
|
+
const entries = [];
|
|
813
|
+
const pending = [root];
|
|
814
|
+
for (let dir = pending.pop(); dir !== undefined; dir = pending.pop()) {
|
|
815
|
+
for (const entry of (0, node_fs_1.readdirSync)(dir, { withFileTypes: true })) {
|
|
816
|
+
entries.push(entry);
|
|
817
|
+
if (entry.isDirectory()) {
|
|
818
|
+
pending.push((0, node_path_1.join)(dir, entry.name));
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return entries;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Write {@link PUBLIC_FILES_FILE_NAME} into a deployment root's runtime
|
|
826
|
+
* directory: every file under `publicDir`, listed the way the runtime would
|
|
827
|
+
* list it off disk (`readPublicFiles`: symlinks followed, `/`-separated,
|
|
828
|
+
* sorted). An app without `public/` gets `[]`.
|
|
829
|
+
*/
|
|
830
|
+
function writePublicFileList(runtimeDir, publicDir) {
|
|
831
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(runtimeDir, manifest_1.PUBLIC_FILES_FILE_NAME), JSON.stringify((0, public_files_1.readPublicFiles)(publicDir)));
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Total bytes of a tree as its deployment zip stores it. `zipDirectory` keeps
|
|
835
|
+
* links as links, so each counts as its target path, not as the target, which
|
|
836
|
+
* is walked at its own path anyway (every link in a staged root points inside
|
|
837
|
+
* it).
|
|
838
|
+
*/
|
|
839
|
+
function storedSize(root) {
|
|
840
|
+
let bytes = 0;
|
|
841
|
+
for (const entry of listTree(root)) {
|
|
842
|
+
if (!entry.isDirectory()) {
|
|
843
|
+
bytes += (0, node_fs_1.lstatSync)((0, node_path_1.join)(entry.parentPath, entry.name)).size;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return bytes;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* `chunk` with `patch` prepended between `PATCH_FETCH_MARKER` and
|
|
850
|
+
* `PATCH_FETCH_END_MARKER`, or `undefined` when it already carries this exact
|
|
851
|
+
* patch.
|
|
852
|
+
*
|
|
853
|
+
* The opening marker carries a hash of the patch, so a chunk patched by a
|
|
854
|
+
* cdk-nextjs whose `patch-fetch.js` differs (an upgrade, over a `.next` reused
|
|
855
|
+
* with `skipBuild: true`) is not mistaken for current: the old patch is cut off
|
|
856
|
+
* at its end marker and this one put in its place, rather than the old one
|
|
857
|
+
* shipping or both stacking up.
|
|
858
|
+
*/
|
|
859
|
+
function patchClientChunk(chunk, patch, chunkPath) {
|
|
860
|
+
const hash = (0, node_crypto_1.createHash)("sha256").update(patch).digest("hex").slice(0, 16);
|
|
861
|
+
const open = `${PATCH_FETCH_MARKER} ${hash} */`;
|
|
862
|
+
if (chunk.startsWith(`${open}\n`)) {
|
|
863
|
+
return undefined;
|
|
864
|
+
}
|
|
865
|
+
let original = chunk;
|
|
866
|
+
if (chunk.startsWith(PATCH_FETCH_MARKER)) {
|
|
867
|
+
const end = chunk.indexOf(`\n${PATCH_FETCH_END_MARKER}\n`);
|
|
868
|
+
if (end === -1) {
|
|
869
|
+
// Only a pre-release cdk-nextjs wrote the marker without an end, and
|
|
870
|
+
// where its patch stops cannot be told from the chunk's own code.
|
|
871
|
+
throw new Error(`${constants_1.LOG_PREFIX} ${chunkPath} carries a cdk-nextjs fetch patch this ` +
|
|
872
|
+
`version cannot replace. Re-run \`next build\` to regenerate it.`);
|
|
873
|
+
}
|
|
874
|
+
original = chunk.slice(end + PATCH_FETCH_END_MARKER.length + 2);
|
|
875
|
+
}
|
|
876
|
+
return `${open}\n${patch}\n${PATCH_FETCH_END_MARKER}\n${original}`;
|
|
877
|
+
}
|
|
878
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25leHRqcy1idWlsZC9uZXh0anMtYnVpbGQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBeUpBLHdEQUtDO0FBR0QsOENBUUM7QUFzMEJELHdEQW1CQztBQU1ELDRDQVVDO0FBcUJELG9EQVVDO0FBY0Qsd0NBRUM7QUFVRCw0QkFZQztBQVFELGtEQUtDO0FBUUQsZ0NBUUM7QUFhRCw0Q0F3QkM7O0FBenBDRCwyREFBNEQ7QUFDNUQsNkNBQXNEO0FBQ3RELHFDQWNpQjtBQUNqQiw2Q0FBNEM7QUFDNUMscUNBQWlDO0FBQ2pDLHlDQUFzQztBQUN0QywyQ0FBb0Q7QUFFcEQsMkNBQXVDO0FBQ3ZDLDZEQUE2RDtBQUM3RCxrREFBNkI7QUFDN0IsZ0VBS29DO0FBQ3BDLDRDQUFzRDtBQUV0RCxrREFRNkI7QUFDN0IsMERBQTBEO0FBQzFELGtEQUk0QjtBQUM1QixnRUFHbUM7QUFFbkM7Ozs7O0dBS0c7QUFDSCxNQUFNLDJCQUEyQixHQUFHLEdBQUcsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBRXREOzs7O0dBSUc7QUFDSCxNQUFNLGtCQUFrQixHQUFHLDJCQUEyQixDQUFDO0FBQ3ZELDJFQUEyRTtBQUMzRSxNQUFNLHNCQUFzQixHQUFHLGtDQUFrQyxDQUFDO0FBRWxFLE1BQU0sS0FBSyxHQUFHLElBQUEsZUFBUSxFQUFDLHlCQUF5QixDQUFDLENBQUM7QUE4RWxEOzs7O0dBSUc7QUFDSCxTQUFnQixzQkFBc0IsQ0FBQyxLQUF1QjtJQUM1RCxNQUFNLFdBQVcsR0FDZixLQUFLLENBQUMsVUFBVSxLQUFLLHNCQUFVLENBQUMsZ0JBQWdCO1FBQ2hELEtBQUssQ0FBQyxVQUFVLEtBQUssc0JBQVUsQ0FBQyxrQkFBa0IsQ0FBQztJQUNyRCxPQUFPLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFBLHdDQUFxQixHQUFFLENB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LENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBQ0QsT0FBTyxHQUFHLElBQUksS0FBSyxLQUFLLEtBQUssc0JBQXNCLEtBQUssUUFBUSxFQUFFLENBQUM7QUFDckUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4ZWNGaWxlU3luYywgZXhlY1N5bmMgfSBmcm9tIFwibm9kZTpjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgeyBjcmVhdGVIYXNoLCByYW5kb21CeXRlcyB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHtcbiAgRGlyZW50LFxuICBleGlzdHNTeW5jLFxuICBsc3RhdFN5bmMsXG4gIHJlYWRGaWxlU3luYyxcbiAgcmVhZGRpclN5bmMsXG4gIHdyaXRlRmlsZVN5bmMsXG4gIHJtU3luYyxcbiAgbWtkaXJTeW5jLFxuICBjcFN5bmMsXG4gIHJlbmFtZVN5bmMsXG4gIHJlYWxwYXRoU3luYyxcbiAgc3RhdFN5bmMsXG4gIHVubGlua1N5bmMsXG59IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSBcIm5vZGU6bW9kdWxlXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgam9pbiwgc2VwIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgam9pbiBhcyBqb2luUG9zaXggfSBmcm9tIFwibm9kZTpwYXRoL3Bvc2l4XCI7XG5pbXBvcnQgeyBBcmNoaXRlY3R1cmUgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCBnZXREZWJ1ZyBmcm9tIFwiZGVidWdcIjtcbmltcG9ydCB7XG4gIERFRkFVTFRfRlVOQ1RJT05fR1JPVVAsXG4gIEZVTkNUSU9OX0dST1VQU19FTlZfVkFSLFxuICBGdW5jdGlvbkdyb3VwU3BlYyxcbiAgdmFsaWRhdGVGdW5jdGlvbkdyb3Vwcyxcbn0gZnJvbSBcIi4uL2FkYXB0ZXIvZnVuY3Rpb24tZ3JvdXBzXCI7XG5pbXBvcnQgeyBMT0dfUFJFRklYLCBOZXh0anNUeXBlIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgTmV4dGpzQmFzZVByb3BzIH0gZnJvbSBcIi4uL3Jvb3QtY29uc3RydWN0cy9uZXh0anMtYmFzZS1jb25zdHJ1Y3RcIjtcbmltcG9ydCB7XG4gIEFEQVBURVJfRElSX05BTUUsXG4gIEFEQVBURVJfTUFOSUZFU1RfVkVSU0lPTixcbiAgQWRhcHRlck1hbmlmZXN0LFxuICBNQU5JRkVTVF9GSUxFX05BTUUsXG4gIFBVQkxJQ19GSUxFU19GSUxFX05BTUUsXG4gIFJVTlRJTUVfRElSX05BTUUsXG4gIGdyb3VwU3RhZ2luZ0Rpck5hbWUsXG59IGZyb20gXCIuLi9ydW50aW1lL21hbmlmZXN0XCI7XG5pbXBvcnQgeyByZWFkUHVibGljRmlsZXMgfSBmcm9tIFwiLi4vcnVudGltZS9wdWJsaWMtZmlsZXNcIjtcbmltcG9ydCB7XG4gIGFzc2V0UHJlZml4UGF0aCxcbiAgbm9ybWFsaXplQmFzZVBhdGgsXG4gIHJlbGF0aXZlQXNzZXRQcmVmaXgsXG59IGZyb20gXCIuLi91dGlscy9iYXNlLXBhdGhcIjtcbmltcG9ydCB7XG4gIGdldExhbWJkYUFyY2hpdGVjdHVyZSxcbiAgdG9Ob2RlQXJjaGl0ZWN0dXJlLFxufSBmcm9tIFwiLi4vdXRpbHMvZ2V0LWFyY2hpdGVjdHVyZVwiO1xuXG4vKipcbiAqIExhbWJkYSdzIGhhcmQgbGltaXQgb24gdGhlIHVuemlwcGVkIHNpemUgb2YgYSBmdW5jdGlvbidzIGNvZGUsIHdoaWNoXG4gKiBDbG91ZEZvcm1hdGlvbiBvbmx5IGVuZm9yY2VzIGF0IGRlcGxveSB0aW1lLiBNZWFzdXJlZCBhdCBzeW50aCBpbnN0ZWFkLCBzbyB0aGVcbiAqIGVycm9yIG5hbWVzIHRoZSBncm91cCBhbmQgYXJyaXZlcyBpbiBzZWNvbmRzIHJhdGhlciB0aGFuIG1pbnV0ZXMuXG4gKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9sYW1iZGEvbGF0ZXN0L2RnL2dldHRpbmdzdGFydGVkLWxpbWl0cy5odG1sXG4gKi9cbmNvbnN0IExBTUJEQV9VTlpJUFBFRF9MSU1JVF9CWVRFUyA9IDI1MCAqIDEwMjQgKiAxMDI0O1xuXG4vKipcbiAqIE9wZW5zIHRoZSBwYXRjaCBgcGF0Y2hGZXRjaEluQ2xpZW50SnNgIHByZXBlbmRzIHRvIGEgY2xpZW50IGNodW5rLCBmb2xsb3dlZCBieVxuICogYSBoYXNoIG9mIHRoZSBwYXRjaCBpdHNlbGYsIHNvIGEgc2Vjb25kIHN5bnRoIG92ZXIgdGhlIHNhbWUgYC5uZXh0YCBpcyBhIG5vLW9wXG4gKiB3aGlsZSBvbmUgYnkgYSBjZGstbmV4dGpzIHdpdGggYSBkaWZmZXJlbnQgYHBhdGNoLWZldGNoLmpzYCByZXBsYWNlcyBpdC5cbiAqL1xuY29uc3QgUEFUQ0hfRkVUQ0hfTUFSS0VSID0gXCIvKiBjZGstbmV4dGpzOnBhdGNoLWZldGNoXCI7XG4vKiogQ2xvc2VzIHRoZSBwcmVwZW5kZWQgcGF0Y2g7IHRoZSBjaHVuaydzIG93biBjb250ZW50IHN0YXJ0cyBhZnRlciBpdC4gKi9cbmNvbnN0IFBBVENIX0ZFVENIX0VORF9NQVJLRVIgPSBcIi8qIGNkay1uZXh0anM6cGF0Y2gtZmV0Y2g6ZW5kICovXCI7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoXCJjZGstbmV4dGpzOm5leHRqcy1idWlsZFwiKTtcblxuZXhwb3J0IGludGVyZmFjZSBOZXh0anNCdWlsZFByb3BzIHtcbiAgLyoqXG4gICAqIEBzZWUge0BsaW5rIE5leHRqc0Jhc2VQcm9wc1tcImJ1aWxkQ29tbWFuZFwiXX1cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQ29tbWFuZDogTmV4dGpzQmFzZVByb3BzW1wiYnVpbGRDb21tYW5kXCJdO1xuICAvKipcbiAgICogRGlyZWN0b3J5IHdoZXJlIHRoZSBOZXh0LmpzIGFwcGxpY2F0aW9uIGlzIGxvY2F0ZWQgZm9yIGxvY2FsIGJ1aWxkcy5cbiAgICogVGhpcyBzaG91bGQgY29udGFpbiB0aGUgcGFja2FnZS5qc29uIGFuZCBOZXh0LmpzIGFwcGxpY2F0aW9uIGZpbGVzLlxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGREaXJlY3Rvcnk6IHN0cmluZztcbiAgcmVhZG9ubHkgbmV4dGpzVHlwZTogTmV4dGpzVHlwZTtcbiAgLyoqXG4gICAqIEBzZWUge0BsaW5rIE5leHRqc0Jhc2VQcm9wcy5za2lwQnVpbGR9XG4gICAqL1xuICByZWFkb25seSBza2lwQnVpbGQ/OiBib29sZWFuO1xuICAvKipcbiAgICogUm91dGUgZ3JvdXBzIHRvIHBhY2thZ2UgaW50byBzZXBhcmF0ZSBMYW1iZGEgZnVuY3Rpb25zLiBPbmx5IHRoZSB0d29cbiAgICogRnVuY3Rpb25zIGBOZXh0anNUeXBlYHMgcGFzcyB0aGlzOyBzZWUgYE5leHRqc0Z1bmN0aW9uR3JvdXBgLlxuICAgKi9cbiAgcmVhZG9ubHkgZnVuY3Rpb25Hcm91cHM/OiBOZXh0anNGdW5jdGlvbkdyb3VwUm91dGVzW107XG4gIC8qKlxuICAgKiBMYW1iZGEgYXJjaGl0ZWN0dXJlIHRoZSBGdW5jdGlvbnMgdHlwZXMgZGVwbG95LCB3aGljaCBkZWNpZGVzIHRoZSBgc2hhcnBgXG4gICAqIGJpbmFyaWVzIHN0YWdlZCBpbnRvIHRoZSBkZXBsb3ltZW50IHJvb3RzLiBJZ25vcmVkIGJ5IHRoZSBDb250YWluZXJzXG4gICAqIHR5cGVzLCB3aG9zZSBpbWFnZSBpcyBidWlsdCBmb3IgdGhlIHN5bnRoIG1hY2hpbmUuXG4gICAqIEBkZWZhdWx0IC0gdGhlIGFyY2hpdGVjdHVyZSBvZiB0aGUgbWFjaGluZSBydW5uaW5nIHN5bnRoXG4gICAqL1xuICByZWFkb25seSBhcmNoaXRlY3R1cmU/OiBBcmNoaXRlY3R1cmU7XG59XG5cbi8qKlxuICogVGhlIHBhcnQgb2YgYSBmdW5jdGlvbiBncm91cCBgTmV4dGpzQnVpbGRgIG5lZWRzOiB3aGljaCByb3V0ZXMgaXQgb3ducy4gVGhlXG4gKiBwZXItZ3JvdXAgTGFtYmRhIGBvdmVycmlkZXNgIGFyZSBgTmV4dGpzRnVuY3Rpb25zYCcgYnVzaW5lc3MuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzRnVuY3Rpb25Hcm91cFJvdXRlcyB7XG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgcm91dGVzOiBzdHJpbmdbXTtcbn1cblxuLyoqIE9uZSBzdGFnZWQgZGVwbG95bWVudCByb290LCBhbmQgdGhlIGZ1bmN0aW9uIGdyb3VwIGl0IGJlbG9uZ3MgdG8uICovXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0RlcGxveW1lbnRSb290IHtcbiAgLyoqXG4gICAqIEdyb3VwIG5hbWUsIGBkZWZhdWx0YCBmb3IgdGhlIGltcGxpY2l0IGdyb3VwIHRoYXQgb3ducyBldmVyeSB1bmFzc2lnbmVkXG4gICAqIHJvdXRlLiBUaGUgb25seSBlbnRyeSBpcyBgZGVmYXVsdGAgd2hlbiBgZnVuY3Rpb25Hcm91cHNgIGlzIG5vdCB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuICAvKiogQWJzb2x1dGUgcGF0aCB0byB0aGUgZGVwbG95bWVudCByb290OiB0aGUgTGFtYmRhIHppcCBhc3NldCdzIHNvdXJjZS4gKi9cbiAgcmVhZG9ubHkgcGF0aDogc3RyaW5nO1xuICAvKipcbiAgICogUm91dGUgdGVtcGxhdGVzIHRoaXMgcm9vdCdzIHBhY2thZ2UgaG9sZHMsIGFzIHRoZSBhZGFwdGVyIGFzc2lnbmVkIHRoZW0uXG4gICAqIEVtcHR5IGlzIGxlZ2FsOiB0aGUgZGVmYXVsdCBncm91cCBzdGlsbCBzZXJ2ZXMgYC9fbmV4dC9pbWFnZWAsIHRoZSBzdGF0aWNcbiAgICogZmlsZXMgdGhlIHJ1bnRpbWUgcmVhZHMgb2ZmIGRpc2ssIGFuZCBhbnl0aGluZyB0aGUgY2F0Y2gtYWxsIHJvdXRlcyB0byBpdC5cbiAgICovXG4gIHJlYWRvbmx5IHJvdXRlczogc3RyaW5nW107XG59XG5cbi8qKlxuICogT25lIGJlaGF2aW9yIHRoYXQgcm91dGVzIGEgZnVuY3Rpb24gZ3JvdXAncyBVUkxzIHRvIGl0LCBhcyB0aGUgYWRhcHRlclxuICogY2hlY2tlZCB0aGVtIGFnYWluc3Qgd2hhdCBlYWNoIGdyb3VwIHdhcyBwYWNrYWdlZCB3aXRoLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0Z1bmN0aW9uR3JvdXBCZWhhdmlvciB7XG4gIC8qKiBUaGUgZnVuY3Rpb24gZ3JvdXAgdGhlIGJlaGF2aW9yIHJvdXRlcyB0by4gKi9cbiAgcmVhZG9ubHkgZ3JvdXA6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBncm91cCBwYXR0ZXJuIGl0IGNhbWUgZnJvbSAoYC9ibG9nLyoqYCksIG9yIHRoZSBwYXJlbnQgb2YgYW4gb3B0aW9uYWxcbiAgICogY2F0Y2gtYWxsIGEgc3VidHJlZSBwYXR0ZXJuIG1vdmVkIGludG8gdGhlIGdyb3VwIChgL2Jsb2dgIGZvclxuICAgKiBgL2Jsb2cvW1suLi5zbHVnXV1gKSwgd2hpY2ggdGhhdCBzdWJ0cmVlJ3MgYmVoYXZpb3IgZG9lcyBub3QgbWF0Y2guXG4gICAqL1xuICByZWFkb25seSByb3V0ZTogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIENsb3VkRnJvbnQgcGF0aCBwYXR0ZXJuLCBiZWZvcmUgYmFzZVBhdGggYW5kIHdpdGhvdXQgYSBsZWFkaW5nIHNsYXNoOlxuICAgKiBgYmxvZy8qYCwgYHByaWNpbmdgLCBgcHJpY2luZy9gIGZvciBhIGB0cmFpbGluZ1NsYXNoYCBhcHAsIGFuZFxuICAgKiBgX25leHQvZGF0YS88YnVpbGRJZD4vYmxvZy8qYCBmb3IgYSBncm91cCBvd25pbmcgYSBQYWdlcyBSb3V0ZXIgcGFnZS5cbiAgICovXG4gIHJlYWRvbmx5IHBhdHRlcm46IHN0cmluZztcbn1cblxuLyoqXG4gKiBXaGF0IGV2ZXJ5IGRlcGxveW1lbnQgcm9vdCBpcyBzdGFnZWQgZm9yOiB0aGUgYnVpbGQncyBgYXJjaGl0ZWN0dXJlYCwgZWxzZVxuICogdGhlIHN5bnRoIG1hY2hpbmUncy4gQ29udGFpbmVycyBpZ25vcmUgaXQ6IERvY2tlciBidWlsZHMgdGhlaXIgaW1hZ2VcbiAqIG5hdGl2ZWx5LCBzbyBpdCBjYW4gb25seSBtYXRjaCB0aGUgc3ludGggbWFjaGluZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlcGxveW1lbnRBcmNoaXRlY3R1cmUocHJvcHM6IE5leHRqc0J1aWxkUHJvcHMpOiBBcmNoaXRlY3R1cmUge1xuICBjb25zdCBpc0Z1bmN0aW9ucyA9XG4gICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TIHx8XG4gICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5SRUdJT05BTF9GVU5DVElPTlM7XG4gIHJldHVybiAoaXNGdW5jdGlvbnMgJiYgcHJvcHMuYXJjaGl0ZWN0dXJlKSB8fCBnZXRMYW1iZGFBcmNoaXRlY3R1cmUoKTtcbn1cblxuLyoqIHtAbGluayBOZXh0anNCdWlsZC5idWlsZElkfTogTmV4dC5qcydzIGJ1aWxkIElELCBzdWZmaXhlZCB3aXRoIHRoZSBhcHAncyBgZGVwbG95bWVudElkYC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZXBsb3ltZW50QnVpbGRJZChtYW5pZmVzdDoge1xuICByZWFkb25seSBidWlsZElkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbmZpZzogeyByZWFkb25seSBkZXBsb3ltZW50SWQ6IHN0cmluZyB9O1xufSk6IHN0cmluZyB7XG4gIGNvbnN0IHsgZGVwbG95bWVudElkIH0gPSBtYW5pZmVzdC5jb25maWc7XG4gIHJldHVybiBkZXBsb3ltZW50SWRcbiAgICA/IGAke21hbmlmZXN0LmJ1aWxkSWR9LSR7ZGVwbG95bWVudElkfWBcbiAgICA6IG1hbmlmZXN0LmJ1aWxkSWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHVibGljRGlyRW50cnkge1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGlzRGlyZWN0b3J5OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEJ1aWxkcyBOZXh0LmpzIGFzc2V0cy5cbiAqIEBsaW5rIGh0dHBzOi8vbmV4dGpzLm9yZy9kb2NzL3BhZ2VzL2FwaS1yZWZlcmVuY2UvbmV4dC1jb25maWctanMvb3V0cHV0XG4gKi9cbmV4cG9ydCBjbGFzcyBOZXh0anNCdWlsZCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBVbmlxdWUgaWQgZm9yIHRoaXMgZGVwbG95bWVudC4gVXNlZCB0byBwYXJ0aXRpb24gY2FjaGUgc3RvcmFnZSBhbmQgYXNcbiAgICogbWV0YWRhdGEgZm9yIHN0YXRpYyBhc3NldHMgaW4gUzMgYnVja2V0LlxuICAgKlxuICAgKiBOZXh0LmpzJ3MgYnVpbGQgSUQsIHN1ZmZpeGVkIHdpdGggdGhlIGFwcCdzIGBkZXBsb3ltZW50SWRgIHdoZW4gaXQgc2V0c1xuICAgKiBvbmUuIFRoZSBidWlsZCBJRCBhbG9uZSBpcyBub3QgdW5pcXVlIHBlciBkZXBsb3ltZW50OiBzZXR0aW5nXG4gICAqIGBkZXBsb3ltZW50SWRgIChvciBidWlsZGluZyB3aXRoIGBORVhUX0RFUExPWU1FTlRfSURgKSB0dXJucyBvbiBza2V3XG4gICAqIHByb3RlY3Rpb24sIGFuZCBuZXh0LmpzIHRoZW4gKnBpbnMqIHRoZSBidWlsZCBJRCB0byB0aGUgY29uc3RhbnRcbiAgICogYGJ1aWxkLVRmY3RzV1hwZmYyZktTYCDigJQgc2VlIGBnZXRCdWlsZElkYCBpbiBgbmV4dC9kaXN0L2J1aWxkL2luZGV4LmpzYCxcbiAgICogd2hpY2ggZG9lcyB0aGF0IGRlbGliZXJhdGVseSBzbyB0aGF0IHRvb2xpbmcgZG9pbmdcbiAgICogYC5yZXBsYWNlKGVzY2FwZWRCdWlsZElkLCDigKYpYCBzdGlsbCBoYXMgc29tZXRoaW5nIHRvIHJlcGxhY2UuIFR3b1xuICAgKiBzdWNjZXNzaXZlIGRlcGxveW1lbnRzIG9mIHN1Y2ggYW4gYXBwIHdvdWxkIHNoYXJlIG9uZSBjYWNoZSBwcmVmaXggYW5kIG9uZVxuICAgKiByZXZhbGlkYXRpb24tdGFibGUgcGFydGl0aW9uLCBhbmQgdGhlIG5ldyBvbmUgd291bGQgcmVhZCB0aGUgcHJldmlvdXNcbiAgICogb25lJ3MgcHJlcmVuZGVycy4gQXBwZW5kaW5nIHRoZSBkZXBsb3ltZW50IElEIHJlc3RvcmVzIHRoZSBcIm9uZVxuICAgKiBkZXBsb3ltZW50LCBvbmUgcGFydGl0aW9uXCIgaW52YXJpYW50IHRoYXQgSUQgZXhpc3RzIHRvIGNhcnJ5LlxuICAgKlxuICAgKiBOb3RoaW5nIHJvdXRlcyBvbiB0aGlzIHZhbHVlIOKAlCB0aGUgYC9fbmV4dC9kYXRhLzxidWlsZElkPi/igKZgIFVSTCBzcGFjZSBpc1xuICAgKiByb3V0ZWQgb24gTmV4dC5qcydzIG93biBidWlsZCBJRCwgd2hpY2ggaXMgd2hhdCB0aGUgYXBwJ3MgY2xpZW50IGJ1bmRsZXNcbiAgICogY2Fycnkg4oCUIHNvIGl0IGlzIGZyZWUgdG8gYmUgbG9uZ2VyIHRoYW4gbmV4dC5qcydzIG93bi5cbiAgICovXG4gIGJ1aWxkSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gdGhlIGluaXQgY2FjaGUgZGlyZWN0b3J5XG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvLm5leHQvY2RrLW5leHRqcy1pbml0LWNhY2hlXCJcbiAgICovXG4gIGluaXRDYWNoZURpcjogc3RyaW5nO1xuICAvKipcbiAgICogQWJzb2x1dGUgcGF0aCB0byBwdWJsaWMuIFVzZSBieSBDbG91ZEZyb250L0FMQiB0byBjcmVhdGUgYmVoYXZpb3JzL3J1bGVzXG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvcHVibGljXCJcbiAgICovXG4gIHB1YmxpY0RpckVudHJpZXM6IFB1YmxpY0RpckVudHJ5W107XG4gIC8qKlxuICAgKiBUaGUgSmF2YVNjcmlwdCBmaWxlIE5vZGUuanMgcnVucyB0byBzZXJ2ZSByZXF1ZXN0cywgcmVsYXRpdmUgdG8gdGhlXG4gICAqIGRlcGxveW1lbnQgcm9vdC4gY2RrLW5leHRqcydzIG93biBjb250YWluZXIgc2hlbGwsIG5vdCBgbmV4dCBidWlsZGAgb3V0cHV0LFxuICAgKiBzbyBpdCBpcyB0aGUgc2FtZSBwYXRoIGZvciBldmVyeSBhcHAuXG4gICAqIEBleGFtcGxlIFwiY2RrLW5leHRqcy1ydW50aW1lL3NlcnZlci5tanNcIlxuICAgKi9cbiAgcmVsYXRpdmVQYXRoVG9FbnRyeXBvaW50OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBBYnNvbHV0ZSBwYXRoIHRvIHRoZSAubmV4dCBkaXJlY3RvcnkgY29udGFpbmluZyBOZXh0LmpzIGJ1aWxkIGFydGlmYWN0c1xuICAgKi9cbiAgZG90TmV4dFBhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBOZXh0LmpzIGFwcCdzIG93biBgYmFzZVBhdGhgIOKAlCB0aGUgVVJMIHByZWZpeCBpdCBnZW5lcmF0ZXMgaXRzIGxpbmtzIGFuZFxuICAgKiBhc3NldCBocmVmcyB1bmRlciDigJQgYXMgdGhlIGFkYXB0ZXIgbWFuaWZlc3QgcmVjb3JkZWQgaXQuIE5vcm1hbGl6ZWQgdG8gYSBiYXJlIHBhdGggc2VnbWVudCwgZW1wdHkgd2hlbiB0aGUgYXBwIHNldHMgbm9uZS4gRXhwb3NlZCBzb1xuICAgKiByb290IGNvbnN0cnVjdHMgY2FuIHJlY29uY2lsZSBpdCB3aXRoIHRoZSBDREsgYGJhc2VQYXRoYCBwcm9wLCB3aGljaCBpcyBhXG4gICAqIGRpc3RpbmN0IHRoaW5nOyBzZWUgYHJlc29sdmVCYXNlUGF0aGAuXG4gICAqL1xuICBuZXh0Q29uZmlnQmFzZVBhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBOZXh0LmpzIGFwcCdzIG93biBgYXNzZXRQcmVmaXhgLCBhcyBhIHBhdGggd2l0aCBhIGxlYWRpbmcgc2xhc2ggYW5kIG5vXG4gICAqIHRyYWlsaW5nIG9uZSwgZW1wdHkgd2hlbiB0aGUgYXBwIHNldHMgbm9uZSBvciBzZXRzIGFuIGFic29sdXRlIFVSTCAod2hpY2hcbiAgICogbmFtZXMgYW4gb3JpZ2luIGNkay1uZXh0anMgZG9lcyBub3Qgc2VydmUpLlxuICAgKlxuICAgKiBFeHBvc2VkIGJlY2F1c2UgaXQgaXMgdGhlIHNoYXBlIG9mIGBhc3NldFByZWZpeGAgdGhlIHJlZ2lvbmFsXG4gICAqIGBOZXh0anNUeXBlYHMgY2Fubm90IHNlcnZlIOKAlCBzZWUgYHdhcm5VbnNlcnZlZEFzc2V0UHJlZml4YC4gV2hhdCB0aGVcbiAgICogZGlzdHJpYnV0aW9uIGhhcyB0byBhbnN3ZXIgb24gaXMge0BsaW5rIG5leHRDb25maWdBc3NldFByZWZpeFBhdGh9LCB3aGljaFxuICAgKiBhbHNvIGNvdmVycyB0aGUgcGF0aCBhbiBhYnNvbHV0ZSBwcmVmaXggY2Fycmllcy5cbiAgICovXG4gIG5leHRDb25maWdBc3NldFByZWZpeDogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHBhdGggcG9ydGlvbiBvZiB0aGUgYXBwJ3MgYGFzc2V0UHJlZml4YCwgd2hpY2hldmVyIGZvcm0gaXQgdGFrZXM6IFwiL2NkblwiXG4gICAqIGZvciBib3RoIGBhc3NldFByZWZpeDogXCIvY2RuXCJgIGFuZCBgYXNzZXRQcmVmaXg6XG4gICAqIFwiaHR0cHM6Ly9jZG4uZXhhbXBsZS5jb20vY2RuXCJgLCBlbXB0eSB3aGVuIHRoZXJlIGlzIG5vIHBhdGggdG8gYW5zd2VyIG9uLlxuICAgKlxuICAgKiBFeHBvc2VkIGJlY2F1c2UgaXQgaXMgYSBVUkwgcHJlZml4IHRoZSBkaXN0cmlidXRpb24gaGFzIHRvIGFuc3dlciBvbjogTmV4dC5qc1xuICAgKiBlbWl0cyBgPGFzc2V0UHJlZml4Pi9fbmV4dC9zdGF0aWMvLi4uYCBmb3IgZXZlcnkgYnVuZGxlIGFuZCBjb21waWxlcyBhIHJld3JpdGVcbiAgICogdGhhdCBzZXJ2ZXMgdGhvc2UgVVJMcycgcGF0aHMgaXRzZWxmLCB3aGlsZSB0aGUgb2JqZWN0cyBsaXZlIGluIFMzIHVuZGVyXG4gICAqIGA8YmFzZVBhdGg+L19uZXh0L3N0YXRpYy8uLi5gLlxuICAgKi9cbiAgbmV4dENvbmZpZ0Fzc2V0UHJlZml4UGF0aDogc3RyaW5nO1xuICAvKipcbiAgICogRXZlcnkgc3RhZ2VkIGRlcGxveW1lbnQgcm9vdCwgb25lIHBlciBmdW5jdGlvbiBncm91cCwgYGRlZmF1bHRgIGZpcnN0OiB0aGVcbiAgICogc3RhZ2VkIHVuaW9uIG9mIGVhY2ggZ3JvdXAncyBzaGlwcGVkIG91dHB1dHMgYW5kIHRoZWlyIHRyYWNlZCBhc3NldHMsXG4gICAqIHdyaXR0ZW4gYnkgdGhlIGFkYXB0ZXIncyBgb25CdWlsZENvbXBsZXRlYC4gRXhhY3RseSBvbmUgZW50cnkgKG5hbWVkXG4gICAqIGBkZWZhdWx0YCwgYXQgYC5uZXh0L2Nkay1uZXh0anMtYWRhcHRlci9hcHBgKSB1bmxlc3MgYGZ1bmN0aW9uR3JvdXBzYFxuICAgKiBzcGxpdHMgdGhlIGFwcC4gVGhlIExhbWJkYSB6aXAgYXNzZXRzOyBDb250YWluZXJzIGBDT1BZYCB0aGUgYGRlZmF1bHRgIG9uZS5cbiAgICovXG4gIGRlcGxveW1lbnRSb290czogTmV4dGpzRGVwbG95bWVudFJvb3RbXTtcbiAgLyoqXG4gICAqIFdoYXQgcm91dGVzIGVhY2ggbm9uLWRlZmF1bHQgZnVuY3Rpb24gZ3JvdXAncyBVUkxzIHRvIGl0LCBtb3N0IHNwZWNpZmljXG4gICAqIGZpcnN0IOKAlCB0aGUgb3JkZXIgQ2xvdWRGcm9udCBoYXMgdG8gc2VlIHRoZW0gaW4sIHNpbmNlIGl0IHN0b3BzIGF0IHRoZVxuICAgKiBmaXJzdCBtYXRjaC4gRW1wdHkgdW5sZXNzIGBmdW5jdGlvbkdyb3Vwc2Agc3BsaXRzIHRoZSBhcHAuXG4gICAqL1xuICBmdW5jdGlvbkdyb3VwQmVoYXZpb3JzOiBOZXh0anNGdW5jdGlvbkdyb3VwQmVoYXZpb3JbXTtcbiAgLyoqXG4gICAqIEZyb20gdGhlIGRlcGxveW1lbnQgcm9vdCB0byB0aGUgTmV4dC5qcyBwcm9qZWN0IGRpciwgUE9TSVgsIGBcIlwiYCB3aGVuXG4gICAqIHRoZSBhcHAgaXMgYXQgdGhlIHJlcG8gcm9vdC4gVGhlIHJ1bnRpbWUgYGNoZGlyYHMgaGVyZTsgQ29udGFpbmVycyBwYXNzIGl0IHRvXG4gICAqIHRoZWlyIERvY2tlcmZpbGUgc28gYC5uZXh0L3N0YXRpY2AgYW5kIGBwdWJsaWNgIGxhbmQgaW4gdGhlIHNhbWUgcGxhY2UuXG4gICAqIEBzZWUgQWRhcHRlck1hbmlmZXN0LnJlbGF0aXZlUHJvamVjdERpclxuICAgKi9cbiAgcmVsYXRpdmVQcm9qZWN0RGlyOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgYXJjaGl0ZWN0dXJlIGV2ZXJ5IGRlcGxveW1lbnQgcm9vdCdzIG5hdGl2ZSBkZXBlbmRlbmNpZXMgKGBzaGFycGApXG4gICAqIHdlcmUgc3RhZ2VkIGZvci4gVGhlIExhbWJkYXMgZGVwbG95aW5nIHRoZW0gbXVzdCB1c2UgdGhlIHNhbWUgb25lLlxuICAgKi9cbiAgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmU7XG5cbiAgcHJpdmF0ZSBwcm9wczogTmV4dGpzQnVpbGRQcm9wcztcbiAgcHJpdmF0ZSBidWlsZENvbW1hbmQ6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogTmV4dGpzQnVpbGRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuICAgIHRoaXMuZG90TmV4dFBhdGggPSBqb2luKHByb3BzLmJ1aWxkRGlyZWN0b3J5LCBcIi5uZXh0XCIpO1xuXG4gICAgdGhpcy5idWlsZENvbW1hbmQgPSBwcm9wcy5idWlsZENvbW1hbmQgfHwgXCJucG0gcnVuIGJ1aWxkXCI7XG5cbiAgICAvLyBTZXQgaW5pdCBjYWNoZSBkaXJlY3RvcnkgcGF0aFxuICAgIHRoaXMuaW5pdENhY2hlRGlyID0gam9pbihcbiAgICAgIHByb3BzLmJ1aWxkRGlyZWN0b3J5LFxuICAgICAgXCIubmV4dFwiLFxuICAgICAgXCJjZGstbmV4dGpzLWluaXQtY2FjaGVcIixcbiAgICApO1xuXG4gICAgLy8gQmVmb3JlIHRoZSBidWlsZCwgbm90IGFmdGVyIGl0OiB0aGUgYnVpbGQgaXMgbWludXRlcyBsb25nLCBhbmQgdGhlIGVudiB2YXJcbiAgICAvLyBpdCBwYXNzZXMgZ3JvdXBzIHRocm91Z2ggaXMgb25seSBzZXQgZm9yIGEgbm9uLWVtcHR5IGFycmF5IOKAlCBzbyBhbiBpbnZhbGlkXG4gICAgLy8gYGZ1bmN0aW9uR3JvdXBzYCAoYW4gZW1wdHkgYXJyYXksIGEgcmVzZXJ2ZWQgbmFtZSwgYSBncm91cCBvd25pbmcgbm9cbiAgICAvLyByb3V0ZXMpIHdvdWxkIG90aGVyd2lzZSBiZSByZXBvcnRlZCBhcyBcInRoZSBidWlsZCBzdGFnZWQgdGhlIHdyb25nXG4gICAgLy8gZ3JvdXBzXCIsIGFmdGVyIHBheWluZyBmb3IgdGhlIGJ1aWxkLCBpbnN0ZWFkIG9mIGFzIHRoZSBwcm9wIGVycm9yIGl0IGlzLlxuICAgIGlmIChwcm9wcy5mdW5jdGlvbkdyb3Vwcykge1xuICAgICAgdmFsaWRhdGVGdW5jdGlvbkdyb3Vwcyhwcm9wcy5mdW5jdGlvbkdyb3VwcyBhcyBGdW5jdGlvbkdyb3VwU3BlY1tdKTtcbiAgICB9XG5cbiAgICAvLyBFeGVjdXRlIGxvY2FsIGJ1aWxkIHByb2Nlc3NcbiAgICBpZiAocHJvcHMuc2tpcEJ1aWxkICE9PSB0cnVlKSB7XG4gICAgICB0aGlzLnJ1bk5leHRCdWlsZCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBTa2lwcGluZzogJHt0aGlzLmJ1aWxkQ29tbWFuZH1gKTtcbiAgICB9XG5cbiAgICAvLyBGaXJzdCwgYmVmb3JlIGFueXRoaW5nIGVsc2UgcmVhZHMgYC5uZXh0YDogYSBtaXNzaW5nIG1hbmlmZXN0IGlzIHRoZSBvbmVcbiAgICAvLyBlcnJvciB0aGF0IG5hbWVzIHRoZSBjYXVzZSAobm8gYnVpbGQsIG9yIG9uZSB3aXRob3V0IHRoZSBhZGFwdGVyKSwgd2hlcmVcbiAgICAvLyBldmVyeSBsYXRlciByZWFkIGZhaWxzIHdpdGggYSBiYXJlIEVOT0VOVC5cbiAgICBjb25zdCBtYW5pZmVzdCA9IHRoaXMucmVhZEFkYXB0ZXJNYW5pZmVzdCgpO1xuXG4gICAgLy8gRGVsaWJlcmF0ZWx5IG91dHNpZGUgdGhlIGBza2lwQnVpbGRgIGdhdGUuIFRoZSBwYXRjaCBpcyBhIHByb3BlcnR5IG9mXG4gICAgLy8gKnNlcnZpbmcqIHRocm91Z2ggQ2xvdWRGcm9udCwgbm90IG9mIHdobyByYW4gYG5leHQgYnVpbGRgOiB3aXRob3V0IGl0XG4gICAgLy8gZXZlcnkgUE9TVCB3aXRoIGEgYm9keSBpcyByZWplY3RlZCBieSB0aGUgTGFtYmRhIEZ1bmN0aW9uIFVSTCBiZWZvcmUgaXRcbiAgICAvLyByZWFjaGVzIHRoZSBhcHAgKHNlZSBgcGF0Y2hGZXRjaEluQ2xpZW50SnNgKS4gUnVubmluZyBpdCBvbmx5IGluc2lkZVxuICAgIC8vIGBydW5OZXh0QnVpbGRgIG1lYW50IGBza2lwQnVpbGQ6IHRydWVgIHNpbGVudGx5IHNoaXBwZWQgYW4gYXBwIHdob3NlXG4gICAgLy8gc2VydmVyIGFjdGlvbnMgYW5kIFBPU1Qgcm91dGUgaGFuZGxlcnMgYWxsIHJldHVybmVkIDQwMy5cbiAgICBpZiAocHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TKSB7XG4gICAgICB0aGlzLnBhdGNoRmV0Y2hJbkNsaWVudEpzKCk7XG4gICAgfVxuXG4gICAgdGhpcy5idWlsZElkID0gZGVwbG95bWVudEJ1aWxkSWQobWFuaWZlc3QpO1xuICAgIHRoaXMucHVibGljRGlyRW50cmllcyA9IHRoaXMuZ2V0TG9jYWxQdWJsaWNEaXJFbnRyaWVzKCk7XG4gICAgLy8gTmV4dC5qcydzIHJlc29sdmVkIGNvbmZpZywgdGhlIHNhbWUgb25lIGl0IHdyaXRlcyBpbnRvXG4gICAgLy8gYHJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYC5cbiAgICB0aGlzLm5leHRDb25maWdCYXNlUGF0aCA9IG5vcm1hbGl6ZUJhc2VQYXRoKG1hbmlmZXN0LmNvbmZpZy5iYXNlUGF0aCk7XG4gICAgdGhpcy5uZXh0Q29uZmlnQXNzZXRQcmVmaXggPSByZWxhdGl2ZUFzc2V0UHJlZml4KFxuICAgICAgbWFuaWZlc3QuY29uZmlnLmFzc2V0UHJlZml4LFxuICAgICk7XG4gICAgdGhpcy5uZXh0Q29uZmlnQXNzZXRQcmVmaXhQYXRoID0gYXNzZXRQcmVmaXhQYXRoKFxuICAgICAgbWFuaWZlc3QuY29uZmlnLmFzc2V0UHJlZml4LFxuICAgICk7XG5cbiAgICBjb25zdCBpc0Z1bmN0aW9ucyA9XG4gICAgICBwcm9wcy5uZXh0anNUeXBlID09PSBOZXh0anNUeXBlLkdMT0JBTF9GVU5DVElPTlMgfHxcbiAgICAgIHByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuUkVHSU9OQUxfRlVOQ1RJT05TO1xuXG4gICAgdGhpcy5yZWxhdGl2ZVByb2plY3REaXIgPSBtYW5pZmVzdC5yZWxhdGl2ZVByb2plY3REaXI7XG4gICAgdGhpcy5yZWxhdGl2ZVBhdGhUb0VudHJ5cG9pbnQgPSBqb2luUG9zaXgoUlVOVElNRV9ESVJfTkFNRSwgXCJzZXJ2ZXIubWpzXCIpO1xuICAgIHRoaXMuYXJjaGl0ZWN0dXJlID0gZGVwbG95bWVudEFyY2hpdGVjdHVyZShwcm9wcyk7XG4gICAgdGhpcy5kZXBsb3ltZW50Um9vdHMgPSB0aGlzLnJlc29sdmVEZXBsb3ltZW50Um9vdHMobWFuaWZlc3QpO1xuICAgIHRoaXMuZnVuY3Rpb25Hcm91cEJlaGF2aW9ycyA9IG1hbmlmZXN0LmJlaGF2aW9ycyA/PyBbXTtcblxuICAgIC8vIE9ubHkgdGhlIFJlZ2lvbmFsQ29udGFpbmVycyBpbWFnZSBjYXJyaWVzIGBwdWJsaWMvYDogbm90aGluZyBpcyBpbiBmcm9udFxuICAgIC8vIG9mIGl0IHRvIGFuc3dlciB0aG9zZSBwYXRocyBmcm9tIFMzLiBFdmVyeSBvdGhlciB0eXBlIGxpc3RzIGl0IGhlcmUgYW5kXG4gICAgLy8gcmVhZHMgYSBmaWxlIHRoZSBlZGdlIGRpZG4ndCByb3V0ZSB0byBTMyAoYSByZXdyaXRlIG9udG8gaXQpIGZyb20gdGhlcmUuXG4gICAgY29uc3QgcHVibGljT25EaXNrID0gcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5SRUdJT05BTF9DT05UQUlORVJTO1xuICAgIGlmIChwdWJsaWNPbkRpc2spIHtcbiAgICAgIC8vIEl0cyBnZW5lcmF0ZWQgRG9ja2VyZmlsZSBgQ09QWWBzIGBwdWJsaWNgLCB3aGljaCBmYWlscyB0aGUgaW1hZ2UgYnVpbGRcbiAgICAgIC8vIHdoZW4gdGhlIGFwcCBoYXMgbm9uZS4gQW4gZW1wdHkgZGlyZWN0b3J5IGlzIHdoYXQgYG5leHQgc3RhcnRgIHNlZXNcbiAgICAgIC8vIGZvciBhbiBhcHAgd2l0aG91dCBvbmUgYW55d2F5LCBhbmQgZ2l0IGRvZXNuJ3QgdHJhY2sgaXQuXG4gICAgICBta2RpclN5bmMoam9pbihwcm9wcy5idWlsZERpcmVjdG9yeSwgXCJwdWJsaWNcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qgcm9vdCBvZiB0aGlzLmRlcGxveW1lbnRSb290cykge1xuICAgICAgdGhpcy5zdGFnZVJ1bnRpbWUocm9vdC5wYXRoLCBpc0Z1bmN0aW9ucywgcHVibGljT25EaXNrKTtcbiAgICAgIC8vIEZ1bmN0aW9ucyBydW4gb24gdGhlIExhbWJkYSBtYW5hZ2VkIHJ1bnRpbWUgKEFtYXpvbiBMaW51eCAyMDIzLCBnbGliYyksXG4gICAgICAvLyBmb3IgdGhlIGFyY2hpdGVjdHVyZSB0aGVpciBMYW1iZGEgZGVwbG95cywgd2hhdGV2ZXIgdGhpcyBtYWNoaW5lIGlzO1xuICAgICAgLy8gQ29udGFpbmVycyBydW4gb24gbm9kZToyNC1hbHBpbmUgKG11c2wpLlxuICAgICAgdGhpcy5zdGFnZVNoYXJwRm9yVGFyZ2V0KFxuICAgICAgICByb290LFxuICAgICAgICBqb2luKHJvb3QucGF0aCwgdGhpcy5yZWxhdGl2ZVByb2plY3REaXIpLFxuICAgICAgICBgJHtpc0Z1bmN0aW9ucyA/IFwibGludXhcIiA6IFwibGludXhtdXNsXCJ9LSR7dG9Ob2RlQXJjaGl0ZWN0dXJlKHRoaXMuYXJjaGl0ZWN0dXJlKX1gLFxuICAgICAgKTtcblxuICAgICAgaWYgKGlzRnVuY3Rpb25zKSB7XG4gICAgICAgIHRoaXMuYXNzZXJ0VW5kZXJMYW1iZGFMaW1pdChyb290KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTGluZSB1cCB0aGUgZ3JvdXBzIHRoZSBwcm9wcyBhc2tlZCBmb3Igd2l0aCB0aGUgcm9vdHMgdGhlIGJ1aWxkIGFjdHVhbGx5XG4gICAqIHN0YWdlZCwgYW5kIGZhaWwgbG91ZGx5IHdoZW4gdGhleSBkaXNhZ3JlZS5cbiAgICpcbiAgICogVGhleSBjYW4gZGlzYWdyZWUgaW4gYm90aCBkaXJlY3Rpb25zLCBhbmQgYm90aCBtZWFuIHRoZSBzYW1lIHRoaW5nIOKAlCB0aGVcbiAgICogYC5uZXh0YCBvbiBkaXNrIGNhbWUgZnJvbSBhIGJ1aWxkIHRoYXQgZGlkIG5vdCBzZWUgdGhpcyBgZnVuY3Rpb25Hcm91cHNgIOKAlFxuICAgKiBidXQgdGhlIGNhdXNlcyBkaWZmZXI6IGBza2lwQnVpbGQ6IHRydWVgIHdpdGggYSBidWlsZCBydW4gYnkgaGFuZCwgb3IgYVxuICAgKiBzdGFsZSBgLm5leHRgIGZyb20gYmVmb3JlIHRoZSBwcm9wIGNoYW5nZWQuIEVpdGhlciB3YXkgZXZlcnkgbGF0ZXIgc3ltcHRvbVxuICAgKiAoYSBMYW1iZGEgbWlzc2luZyBhbiBlbnRyeXBvaW50LCBhIENsb3VkRnJvbnQgYmVoYXZpb3IgcG9pbnRpbmcgYXQgYVxuICAgKiBmdW5jdGlvbiB0aGF0IGNhbm5vdCBzZXJ2ZSBpdCkgaXMgdGhpcywgc2V2ZXJhbCBzdGVwcyBkb3duc3RyZWFtLlxuICAgKi9cbiAgcHJpdmF0ZSByZXNvbHZlRGVwbG95bWVudFJvb3RzKFxuICAgIG1hbmlmZXN0OiBBZGFwdGVyTWFuaWZlc3QsXG4gICk6IE5leHRqc0RlcGxveW1lbnRSb290W10ge1xuICAgIGNvbnN0IHN0YWdlZCA9IG1hbmlmZXN0Lmdyb3VwcztcblxuICAgIC8vIE5hbWVzICphbmQqIHJvdXRlczogbW92aW5nIGAvcmVwb3J0cy8qKmAgaW50byBhbiBleGlzdGluZyBncm91cCBrZWVwcyB0aGVcbiAgICAvLyBuYW1lcyBhbmQgc3RpbGwgbGVhdmVzIHRoYXQgZ3JvdXAncyB6aXAgd2l0aG91dCB0aGUgcmVwb3J0cyBlbnRyeXBvaW50cy5cbiAgICAvLyBPcmRlciBpcyBub3Q6IGFzc2lnbm1lbnQgYW5kIENsb3VkRnJvbnQgYmVoYXZpb3JzIGJvdGggZ28gbW9zdCBzcGVjaWZpY1xuICAgIC8vIGZpcnN0LCBhbmQgbm8gdHdvIGRpc3RpbmN0IHBhdHRlcm5zIHRpZSBvbiBhIFVSTCAoYGZ1bmN0aW9uLWdyb3Vwcy50c2ApLFxuICAgIC8vIHNvIHJlb3JkZXJpbmcgZ3JvdXBzIG9yIHJvdXRlcyBpcyB0aGUgc2FtZSBzcGxpdC5cbiAgICAvLyBBbHJlYWR5IHZhbGlkYXRlZCBpbiB0aGUgY29uc3RydWN0b3IsIHNvIHRoaXMgaXMgYWJzZW50IG9yIG5vbi1lbXB0eS5cbiAgICBjb25zdCB3YW50ZWQgPSB0aGlzLnByb3BzLmZ1bmN0aW9uR3JvdXBzPy5sZW5ndGhcbiAgICAgID8gdG9GdW5jdGlvbkdyb3VwU3BlY3ModGhpcy5wcm9wcy5mdW5jdGlvbkdyb3VwcylcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IGdvdCA9IG1hbmlmZXN0LmZ1bmN0aW9uR3JvdXBzO1xuXG4gICAgaWYgKFxuICAgICAgSlNPTi5zdHJpbmdpZnkoc29ydGVkR3JvdXBTcGVjcyh3YW50ZWQpKSAhPT1cbiAgICAgIEpTT04uc3RyaW5naWZ5KHNvcnRlZEdyb3VwU3BlY3MoZ290KSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7TE9HX1BSRUZJWH0gXFxgZnVuY3Rpb25Hcm91cHNcXGAgYXNrcyBmb3IgYCArXG4gICAgICAgICAgYCR7d2FudGVkID8gSlNPTi5zdHJpbmdpZnkod2FudGVkKSA6IFwibm8gc3BsaXR0aW5nXCJ9IGJ1dCB0aGUgYnVpbGQgYCArXG4gICAgICAgICAgYGluICR7dGhpcy5kb3ROZXh0UGF0aH0gd2FzIHNwbGl0IGludG8gYCArXG4gICAgICAgICAgYCR7Z290ID8gSlNPTi5zdHJpbmdpZnkoZ290KSA6IFwiYSBzaW5nbGUgZGVwbG95bWVudCByb290XCJ9LiBgICtcbiAgICAgICAgICBgR3JvdXBzIGFyZSByZXNvbHZlZCBkdXJpbmcgXFxgbmV4dCBidWlsZFxcYCAoY2RrLW5leHRqcyBwYXNzZXMgdGhlbSBpbiBgICtcbiAgICAgICAgICBgdmlhICR7RlVOQ1RJT05fR1JPVVBTX0VOVl9WQVJ9KSwgc28gdGhpcyBtZWFucyB0aGUgYnVpbGQgb3V0cHV0IGlzIGAgK1xuICAgICAgICAgIGBzdGFsZSwgb3IgXFxgc2tpcEJ1aWxkOiB0cnVlXFxgIGFuZCB0aGUgYnVpbGQgd2FzIHJ1biB3aXRob3V0IHRoYXQgYCArXG4gICAgICAgICAgYHZhcmlhYmxlIHNldC5gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBuYW1lcyA9IHN0YWdlZCA/IE9iamVjdC5rZXlzKHN0YWdlZCkgOiBbREVGQVVMVF9GVU5DVElPTl9HUk9VUF07XG4gICAgY29uc3Qgcm9vdHMgPSBuYW1lcy5tYXAoKG5hbWUpID0+ICh7XG4gICAgICBuYW1lLFxuICAgICAgcGF0aDogam9pbihcbiAgICAgICAgdGhpcy5kb3ROZXh0UGF0aCxcbiAgICAgICAgQURBUFRFUl9ESVJfTkFNRSxcbiAgICAgICAgLi4uZ3JvdXBTdGFnaW5nRGlyTmFtZShzdGFnZWQgPyBuYW1lIDogdW5kZWZpbmVkKS5zcGxpdChcIi9cIiksXG4gICAgICApLFxuICAgICAgcm91dGVzOiBzdGFnZWQ/LltuYW1lXSA/PyBbXSxcbiAgICB9KSk7XG5cbiAgICAvLyBgZGVmYXVsdGAgZmlyc3QsIHNvIGFueSBcInRoZSByb290XCIgY2FsbGVyIGdldHMgdGhlIGdyb3VwIHRoYXQgb3duc1xuICAgIC8vIGV2ZXJ5dGhpbmcgdW5hc3NpZ25lZC5cbiAgICByb290cy5zb3J0KChhLCBiKSA9PlxuICAgICAgYS5uYW1lID09PSBERUZBVUxUX0ZVTkNUSU9OX0dST1VQXG4gICAgICAgID8gLTFcbiAgICAgICAgOiBiLm5hbWUgPT09IERFRkFVTFRfRlVOQ1RJT05fR1JPVVBcbiAgICAgICAgICA/IDFcbiAgICAgICAgICA6IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSksXG4gICAgKTtcblxuICAgIGZvciAoY29uc3Qgcm9vdCBvZiByb290cykge1xuICAgICAgaWYgKCFleGlzdHNTeW5jKHJvb3QucGF0aCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IFRoZSBkZXBsb3ltZW50IHJvb3QgZm9yIGZ1bmN0aW9uIGdyb3VwIGAgK1xuICAgICAgICAgICAgYFwiJHtyb290Lm5hbWV9XCIgaXMgbWlzc2luZyBmcm9tICR7cm9vdC5wYXRofSwgdGhvdWdoIHRoZSBhZGFwdGVyIGAgK1xuICAgICAgICAgICAgYG1hbmlmZXN0IGxpc3RzIGl0LiBUaGUgXFxgLm5leHRcXGAgZGlyZWN0b3J5IGhhcyBiZWVuIG1vZGlmaWVkIHNpbmNlIGAgK1xuICAgICAgICAgICAgYFxcYG5leHQgYnVpbGRcXGAgcmFuLmAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByb290cztcbiAgfVxuXG4gIC8qKlxuICAgKiBMYW1iZGEgZW5mb3JjZXMgMjUwIE1CIHVuemlwcGVkIGF0IENsb3VkRm9ybWF0aW9uIHRpbWUsIHdoaWNoIGlzIG1pbnV0ZXNcbiAgICogaW50byBhIGRlcGxveSBhbmQgcmVwb3J0cyBvbmx5IGEgc2l6ZS4gU3BsaXR0aW5nIGV4aXN0cyB0byBzdGF5IHVuZGVyIHRoYXRcbiAgICogY2FwLCBzbyB0aGUgZXJyb3IgdGhhdCB0ZWxscyB5b3UgdG8gc3BsaXQgZnVydGhlciBoYXMgdG8gbmFtZSB0aGUgZ3JvdXAsIGl0c1xuICAgKiBzaXplLCBhbmQgd2hhdCB0byBkbyDigJQgYW5kIGFycml2ZSBhdCBzeW50aC5cbiAgICovXG4gIHByaXZhdGUgYXNzZXJ0VW5kZXJMYW1iZGFMaW1pdChyb290OiBOZXh0anNEZXBsb3ltZW50Um9vdCk6IHZvaWQge1xuICAgIGNvbnN0IGJ5dGVzID0gc3RvcmVkU2l6ZShyb290LnBhdGgpO1xuICAgIGRlYnVnKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gRGVwbG95bWVudCByb290IFwiJHtyb290Lm5hbWV9XCIgaXMgJHsoYnl0ZXMgLyAxZTYpLnRvRml4ZWQoMSl9IE1CIHVuemlwcGVkYCxcbiAgICApO1xuICAgIGlmIChieXRlcyA8PSBMQU1CREFfVU5aSVBQRURfTElNSVRfQllURVMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbWIgPSAodmFsdWU6IG51bWJlcikgPT4gYCR7KHZhbHVlIC8gMTAyNCAvIDEwMjQpLnRvRml4ZWQoMCl9IE1CYDtcbiAgICBjb25zdCBpc1NwbGl0ID0gdGhpcy5kZXBsb3ltZW50Um9vdHMubGVuZ3RoID4gMTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtMT0dfUFJFRklYfSBGdW5jdGlvbiBncm91cCBcIiR7cm9vdC5uYW1lfVwiIGlzICR7bWIoYnl0ZXMpfSB1bnppcHBlZCwgYCArXG4gICAgICAgIGBvdmVyIExhbWJkYSdzICR7bWIoTEFNQkRBX1VOWklQUEVEX0xJTUlUX0JZVEVTKX0gbGltaXQuIGAgK1xuICAgICAgICAoaXNTcGxpdFxuICAgICAgICAgID8gYFNwbGl0IGl0cyByb3V0ZXMgZnVydGhlciwgb3IgbW92ZSBzb21lIG9mIHRoZW0gaW50byBhbm90aGVyIGdyb3VwOiBgICtcbiAgICAgICAgICAgIGB0aGUgY2FwIGlzIHBlciBmdW5jdGlvbiwgc28gdGhlIHNoYXJlZCBcXGBuZXh0XFxgIGNsb3N1cmUgZXZlcnkgZ3JvdXAgYCArXG4gICAgICAgICAgICBgZHVwbGljYXRlcyBjb3N0cyBub3RoaW5nIGFnYWluc3QgYW55IHNpbmdsZSBidWRnZXQuYFxuICAgICAgICAgIDogYFVzZSB0aGUgXFxgZnVuY3Rpb25Hcm91cHNcXGAgcHJvcCB0byBwYWNrYWdlIHJvdXRlcyBpbnRvIHNlcGFyYXRlIGAgK1xuICAgICAgICAgICAgYGZ1bmN0aW9ucy4gTm90ZSB0aGF0IHNwbGl0dGluZyBvbmx5IHJlbW92ZXMgcm91dGUtbG9jYWwgY29kZSDigJQgYCArXG4gICAgICAgICAgICBgYW55dGhpbmcgcmVhY2hhYmxlIGZyb20gYSBzaGFyZWQgbGF5b3V0IG9yIHRoZSBcXGBuZXh0XFxgIHJ1bnRpbWUgaXMgYCArXG4gICAgICAgICAgICBgaW4gZXZlcnkgZ3JvdXAuYCksXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWFkIHRoZSBtYW5pZmVzdCB0aGUgYWRhcHRlcidzIGBvbkJ1aWxkQ29tcGxldGVgIHdyb3RlLlxuICAgKlxuICAgKiBJdHMgYWJzZW5jZSBtZWFucyBgbmV4dCBidWlsZGAgcmFuIHdpdGhvdXQgY2RrLW5leHRqcydzIGFkYXB0ZXIgcmVnaXN0ZXJlZFxuICAgKiAob3Igd2l0aCBhIHN0YWxlIGBuZXh0LmNvbmZpZ2ApLCB3aGljaCBpcyB3b3J0aCBzYXlpbmcgcGxhaW5seSBoZXJlOiBldmVyeVxuICAgKiBsYXRlciBmYWlsdXJlIOKAlCBhIExhbWJkYSB0aGF0IGNhbm5vdCBmaW5kIGBtYW5pZmVzdC5qc29uYCwgYW4gZW1wdHkgYXNzZXQg4oCUXG4gICAqIGlzIHRoZSBzYW1lIGNhdXNlIHNldmVyYWwgc3RlcHMgZG93bnN0cmVhbS5cbiAgICovXG4gIHByaXZhdGUgcmVhZEFkYXB0ZXJNYW5pZmVzdCgpOiBBZGFwdGVyTWFuaWZlc3Qge1xuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oXG4gICAgICB0aGlzLmRvdE5leHRQYXRoLFxuICAgICAgQURBUFRFUl9ESVJfTkFNRSxcbiAgICAgIE1BTklGRVNUX0ZJTEVfTkFNRSxcbiAgICApO1xuICAgIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBjZGstbmV4dGpzIGFkYXB0ZXIgbWFuaWZlc3Qgbm90IGZvdW5kIGF0ICR7bWFuaWZlc3RQYXRofS4gYCArXG4gICAgICAgICAgYFwiJHt0aGlzLmJ1aWxkQ29tbWFuZH1cIiBtdXN0IHJ1biBhIE5leHQuanMgYnVpbGQgd2l0aCBjZGstbmV4dGpzJ3MgYCArXG4gICAgICAgICAgYGFkYXB0ZXIgcmVnaXN0ZXJlZC4gY2RrLW5leHRqcyBzZXRzIFxcYE5FWFRfQURBUFRFUl9QQVRIXFxgIG9uIHRoZSBgICtcbiAgICAgICAgICBgYnVpbGQgaXQgcnVucyBpdHNlbGYsIHNvIHRoaXMgdXN1YWxseSBtZWFucyBlaXRoZXIgdGhlIGJ1aWxkIGNvbW1hbmQgYCArXG4gICAgICAgICAgYGRvZXMgbm90IHJlYWNoIFxcYG5leHQgYnVpbGRcXGAgKGEgd3JhcHBlciB0aGF0IGRyb3BzIHRoZSBlbnZpcm9ubWVudCwgYCArXG4gICAgICAgICAgYG9yIGEgY2FjaGVkIGJ1aWxkIHRoYXQgZGlkIG5vdCByZS1ydW4pLCBvciBcXGBza2lwQnVpbGQ6IHRydWVcXGAgYW5kIGAgK1xuICAgICAgICAgIGB0aGUgYnVpbGQgaGFwcGVuZWQgb3V0c2lkZSBDREsuIEZvciB0aGUgbGF0dGVyLCBzZXQgYCArXG4gICAgICAgICAgYFxcYGFkYXB0ZXJQYXRoOiByZXF1aXJlLnJlc29sdmUoXCJjZGstbmV4dGpzL2FkYXB0ZXJcIilcXGAgaW4gYCArXG4gICAgICAgICAgYG5leHQuY29uZmlnLiBBIGN1c3RvbSBcXGBkaXN0RGlyXFxgIGlzIG5vdCBzdXBwb3J0ZWQgZWl0aGVyOiBgICtcbiAgICAgICAgICBgY2RrLW5leHRqcyByZWFkcyB0aGUgYnVpbGQgZnJvbSBcXGAubmV4dFxcYC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICByZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoLCBcInV0Zi04XCIpLFxuICAgICk7XG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IEFEQVBURVJfTUFOSUZFU1RfVkVSU0lPTikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgVGhlIGNkay1uZXh0anMgYWRhcHRlciBtYW5pZmVzdCBhdCAke21hbmlmZXN0UGF0aH0gaXMgdmVyc2lvbiBgICtcbiAgICAgICAgICBgJHttYW5pZmVzdC52ZXJzaW9ufSwgYnV0IHRoaXMgdmVyc2lvbiBvZiBjZGstbmV4dGpzIHJlYWRzIHZlcnNpb24gYCArXG4gICAgICAgICAgYCR7QURBUFRFUl9NQU5JRkVTVF9WRVJTSU9OfS4gVGhlIGFkYXB0ZXIgdGhhdCB3cm90ZSBpdCBhbmQgdGhlIGAgK1xuICAgICAgICAgIGBjb25zdHJ1Y3RzIHJlYWRpbmcgaXQgY29tZSBmcm9tIHRoZSBzYW1lIHBhY2thZ2UsIHNvIHRoaXMgbWVhbnMgdHdvIGAgK1xuICAgICAgICAgIGBjZGstbmV4dGpzIHZlcnNpb25zIGFyZSBpbnN0YWxsZWQsIG9yIHRoZSBidWlsZCBvdXRwdXQgaXMgc3RhbGUuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBtYW5pZmVzdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb3B5IGNkay1uZXh0anMncyBvd24gYnVuZGxlZCByZXF1ZXN0LWhhbmRsaW5nIHNoZWxsIGFuZCB0aGUgbWFuaWZlc3QgaW50b1xuICAgKiBgPGRlcGxveW1lbnRSb290Pi9jZGstbmV4dGpzLXJ1bnRpbWUvYCwgd2hpY2ggaXMgd2hlcmVcbiAgICogYGRlcGxveW1lbnRSb290T2ZgL2BkZXBsb3llZE1hbmlmZXN0UGF0aGAgZXhwZWN0IHRvIGZpbmQgdGhlbS5cbiAgICpcbiAgICogT25seSB0aGUgc2hlbGwgdGhlIGRlcGxveW1lbnQgdHlwZSBhY3R1YWxseSBydW5zIGlzIGNvcGllZCDigJQgdGhlIExhbWJkYVxuICAgKiBoYW5kbGVyIGZvciBGdW5jdGlvbnMsIHRoZSBgbm9kZTpodHRwYCBzZXJ2ZXIgZm9yIENvbnRhaW5lcnMg4oCUIHNvIG5vdGhpbmdcbiAgICogc2hpcHMgfjEuNSBNQiBvZiBkZWFkIGNvZGUgYW5kIHRoZSB0cmVlIHNheXMgd2hpY2ggdHlwZSBwcm9kdWNlZCBpdC4gQm90aFxuICAgKiBhcmUgY29waWVkIGZyb20gdGhpcyBwYWNrYWdlJ3MgYGxpYi9gLCBuZXh0IHRvIHRoZSBjb21waWxlZCBjb25zdHJ1Y3QuXG4gICAqXG4gICAqIEV2ZXJ5IGdyb3VwIGdldHMgdGhlIHNhbWUgc2hlbGwgKmFuZCB0aGUgc2FtZSBtYW5pZmVzdCo6IGEgZnVuY3Rpb24gb25seVxuICAgKiBrbm93cyB3aGljaCByb3V0ZXMgaXQgb3ducyBzbyBpdCBjYW4gc2F5IHNvIHdoZW4gbWlzcm91dGVkLCBhbmQgdGhhdCBjb21lc1xuICAgKiBmcm9tIHtAbGluayBGVU5DVElPTl9HUk9VUF9FTlZfVkFSfSwgbm90IGZyb20gYSBwZXItZ3JvdXAgbWFuaWZlc3QuXG4gICAqL1xuICBwcml2YXRlIHN0YWdlUnVudGltZShcbiAgICBkZXBsb3ltZW50Um9vdDogc3RyaW5nLFxuICAgIGlzRnVuY3Rpb25zOiBib29sZWFuLFxuICAgIHB1YmxpY09uRGlzazogYm9vbGVhbixcbiAgKTogdm9pZCB7XG4gICAgY29uc3Qgc2hlbGwgPSBpc0Z1bmN0aW9ucyA/IFwibGFtYmRhLm1qc1wiIDogXCJzZXJ2ZXIubWpzXCI7XG4gICAgY29uc3Qgc291cmNlID0gam9pbihfX2Rpcm5hbWUsIFwiLi5cIiwgXCJydW50aW1lXCIsIHNoZWxsKTtcblxuICAgIGNvbnN0IHJ1bnRpbWVEaXIgPSBqb2luKGRlcGxveW1lbnRSb290LCBSVU5USU1FX0RJUl9OQU1FKTtcbiAgICAvLyBSZW1vdmVkIHJhdGhlciB0aGFuIG1lcmdlZDogYSBzdGFsZSBzaGVsbCBmcm9tIHRoZSBvdGhlciBkZXBsb3ltZW50IHR5cGVcbiAgICAvLyB3b3VsZCBvdGhlcndpc2Ugc2l0IGluIHRoZSBhc3NldCBhbmQgY2hhbmdlIGl0cyBoYXNoIGZvciBubyByZWFzb24uXG4gICAgcm1TeW5jKHJ1bnRpbWVEaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBta2RpclN5bmMocnVudGltZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgY3BTeW5jKHNvdXJjZSwgam9pbihydW50aW1lRGlyLCBzaGVsbCkpO1xuICAgIGNwU3luYyhcbiAgICAgIGpvaW4odGhpcy5kb3ROZXh0UGF0aCwgQURBUFRFUl9ESVJfTkFNRSwgTUFOSUZFU1RfRklMRV9OQU1FKSxcbiAgICAgIGpvaW4ocnVudGltZURpciwgTUFOSUZFU1RfRklMRV9OQU1FKSxcbiAgICApO1xuICAgIGlmICghcHVibGljT25EaXNrKSB7XG4gICAgICAvLyBUaGUgTGFtYmRhIHppcHMgYW5kIHRoZSBHbG9iYWxDb250YWluZXJzIGltYWdlIGRvbid0IGNhcnJ5IGBwdWJsaWMvYFxuICAgICAgLy8gKGl0cyBieXRlcyBhcmUgaW4gUzMpLCBzbyB0aGUgcnVudGltZSBjYW4ndCBsaXN0IGl0IGF0IHN0YXJ0IHRoZSB3YXlcbiAgICAgIC8vIHRoZSBSZWdpb25hbENvbnRhaW5lcnMgaW1hZ2UgZG9lcy5cbiAgICAgIC8vIExpc3RlZCBoZXJlLCBhZnRlciB0aGUgYnVpbGQgY29tbWFuZCwgc28gYHBvc3RidWlsZGAgb3V0cHV0IGlzIGluIGl0OlxuICAgICAgLy8gYSByZXdyaXRlIG9udG8gYSBsaXN0ZWQgZmlsZSBpcyB0aGVuIHNlcnZlZCBmcm9tIFMzIHJhdGhlciB0aGFuIDQwNGluZy5cbiAgICAgIHdyaXRlUHVibGljRmlsZUxpc3QoXG4gICAgICAgIHJ1bnRpbWVEaXIsXG4gICAgICAgIGpvaW4odGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeSwgXCJwdWJsaWNcIiksXG4gICAgICApO1xuICAgIH1cbiAgICBkZWJ1ZyhcbiAgICAgIGAke0xPR19QUkVGSVh9IFN0YWdlZCAke3NoZWxsfSBhbmQgJHtNQU5JRkVTVF9GSUxFX05BTUV9IGluICR7cnVudGltZURpcn1gLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogYE5FWFRfQURBUFRFUl9QQVRIYCBmb3IgdGhlIGJ1aWxkLCBzbyBgYWRhcHRlclBhdGhgIGluIGBuZXh0LmNvbmZpZ2AgaXNcbiAgICogb3B0aW9uYWwuXG4gICAqXG4gICAqIE5leHQuanMgcmVhZHMgdGhlIHZhcmlhYmxlIGFzIHRoZSAqZGVmYXVsdCogdmFsdWUgb2YgYGFkYXB0ZXJQYXRoYFxuICAgKiAoYG5leHQvZGlzdC9zZXJ2ZXIvY29uZmlnLXNoYXJlZC5qc2AsIGBkZWZhdWx0Q29uZmlnYCksIHNvIGFuIGFwcCB0aGF0IGRvZXNcbiAgICogc2V0IGBhZGFwdGVyUGF0aGAgc3RpbGwgd2lucyBhbmQgbm90aGluZyBleGlzdGluZyBjaGFuZ2VzLlxuICAgKlxuICAgKiBSZXNvbHZlZCBmcm9tIHRoZSBOZXh0LmpzIGFwcCwgbm90IGZyb20gY2RrLW5leHRqcydzIG93biBgX19kaXJuYW1lYCBhbmQgbm90XG4gICAqIGxlZnQgYXMgYSBiYXJlIHNwZWNpZmllci4gQm90aCBhbHRlcm5hdGl2ZXMgd2VyZSB0cmllZCBhbmQgYm90aCBhcmUgd3Jvbmc6XG4gICAqXG4gICAqIC0gY2RrLW5leHRqcydzIG93biBsb2NhdGlvbiBsb3NlcyBiZWNhdXNlIHRoZSBhZGFwdGVyIHJlc29sdmVzIGl0cyBzaWJsaW5nXG4gICAqICAgY2FjaGUgaGFuZGxlciByZWxhdGl2ZSB0byB3aGVyZXZlciAqaXQqIHdhcyBsb2FkZWQgZnJvbS4gQW4gYWRhcHRlciBsb2FkZWRcbiAgICogICBmcm9tIG91dHNpZGUgdGhlIGFwcCdzIHRyZWUgaGFuZHMgTmV4dC5qcyBhIGBjYWNoZUhhbmRsZXJgIG91dHNpZGVcbiAgICogICBgdHVyYm9wYWNrLnJvb3RgLCB3aGljaCBUdXJib3BhY2sgcmVqZWN0cyBvdXRyaWdodCAoXCJsZWF2ZXMgdGhlIGZpbGVzeXN0ZW1cbiAgICogICByb290XCIpLlxuICAgKiAtIEEgYmFyZSBzcGVjaWZpZXIgbG9zZXMgYmVjYXVzZSBOZXh0LmpzIHJlc29sdmVzIGBhZGFwdGVyUGF0aGAgZnJvbSBpbnNpZGVcbiAgICogICBpdHMgb3duIGNvbmZpZyBsb2FkZXIsIGkuZS4gZnJvbSBgbmV4dGAncyByZWFscGF0aC4gVW5kZXIgcG5wbSB0aGF0IGlzIHRoZVxuICAgKiAgIHZpcnR1YWwgc3RvcmUgKGBub2RlX21vZHVsZXMvLnBucG0vbmV4dEDigKYvbm9kZV9tb2R1bGVzL25leHQvYCksIGFuZCB0aGVcbiAgICogICB3YWxrIHVwIGZyb20gdGhlcmUgbmV2ZXIgcmVhY2hlcyB0aGUgYXBwJ3Mgb3duIGBub2RlX21vZHVsZXNgLlxuICAgKlxuICAgKiBVbnNldCB3aGVuIGBjZGstbmV4dGpzYCBpcyBub3QgcmVzb2x2YWJsZSBmcm9tIHRoZSBhcHAsIHdoaWNoIGlzIGxlZ2l0aW1hdGU6XG4gICAqIHRoZSBOZXh0LmpzIGFwcCBhbmQgdGhlIENESyBhcHAgY2FuIGJlIHNlcGFyYXRlIHBhY2thZ2VzLCBhbmQgb25seSB0aGUgQ0RLIG9uZVxuICAgKiBuZWNlc3NhcmlseSBkZXBlbmRzIG9uIGNkay1uZXh0anMuIHtAbGluayByZWFkQWRhcHRlck1hbmlmZXN0fSByZXBvcnRzIHRoZVxuICAgKiByZXN1bHRpbmcgZmFpbHVyZSBhbmQgbmFtZXMgdGhpcyBjYXNlLlxuICAgKlxuICAgKiBPbmUgc2V0dXAgdGhpcyBjYW5ub3Qgc2VydmUsIGFuZCB0aGUgcmVhc29uIHRoaXMgcmVwbydzIG93biBleGFtcGxlcyBzdGlsbCBzZXRcbiAgICogYGFkYXB0ZXJQYXRoYDogYSBgbGluazpgL2BmaWxlOmAgZGVwZW5kZW5jeSBvbiBhIGNkay1uZXh0anMgY2hlY2tvdXQgKm91dHNpZGUqXG4gICAqIHRoZSBhcHAncyBwcm9qZWN0IHJvb3QuIFRoZSBzeW1saW5rIHJlc29sdmVzIG91dCBvZiB0aGUgcHJvamVjdCwgc28gdGhlXG4gICAqIGBjYWNoZUhhbmRsZXJgIGVzY2FwZSBhYm92ZSBhcHBsaWVzLiBTZXQgYGFkYXB0ZXJQYXRoYCBpbiBgbmV4dC5jb25maWdgIHRoZXJlXG4gICAqIOKAlCBpdCBpcyByZXNvbHZlZCBieSB0aGUgYnVpbGQsIGFmdGVyIHdoYXRldmVyIHB1dCB0aGUgYWRhcHRlciBpbiBwbGFjZS5cbiAgICovXG4gIHByaXZhdGUgYWRhcHRlclBhdGhFbnYoKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIE5FWFRfQURBUFRFUl9QQVRIOiByZXF1aXJlLnJlc29sdmUoXCJjZGstbmV4dGpzL2FkYXB0ZXJcIiwge1xuICAgICAgICAgIHBhdGhzOiBbdGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeV0sXG4gICAgICAgIH0pLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIGRlYnVnKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSBDb3VsZCBub3QgcmVzb2x2ZSBcImNkay1uZXh0anMvYWRhcHRlclwiIGZyb20gYCArXG4gICAgICAgICAgYCR7dGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeX07IGxlYXZpbmcgTkVYVF9BREFQVEVSX1BBVEggdW5zZXQsIHNvIGAgK1xuICAgICAgICAgIGBuZXh0LmNvbmZpZyBtdXN0IHNldCBcXGBhZGFwdGVyUGF0aFxcYC5gLFxuICAgICAgKTtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSBsb2NhbCBidWlsZCBjb21tYW5kIGluIHRoZSBzcGVjaWZpZWQgZGlyZWN0b3J5XG4gICAqL1xuICBwcml2YXRlIHJ1bk5leHRCdWlsZCgpIHtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGAke0xPR19QUkVGSVh9IFJ1bm5pbmc6IFwiJHt0aGlzLmJ1aWxkQ29tbWFuZH1cIiBpbiBkaXJlY3Rvcnk6ICR7dGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeX1gLFxuICAgICk7XG5cbiAgICAvLyBDbGVhbiBleGlzdGluZyBjYWNoZSBkaXJlY3RvcnkgdG8gYXZvaWQgc3RhbGUgZGF0YSBmcm9tIHByZXZpb3VzIGJ1aWxkc1xuICAgIGlmIChleGlzdHNTeW5jKHRoaXMuaW5pdENhY2hlRGlyKSkge1xuICAgICAgcm1TeW5jKHRoaXMuaW5pdENhY2hlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICBkZWJ1ZyhgQ2xlYW5lZCBleGlzdGluZyBjYWNoZSBkaXJlY3Rvcnk6ICR7dGhpcy5pbml0Q2FjaGVEaXJ9YCk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKHRoaXMuYnVpbGRDb21tYW5kLCB7XG4gICAgICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgICAgICAgY3dkOiB0aGlzLnByb3BzLmJ1aWxkRGlyZWN0b3J5LFxuICAgICAgICBlbnY6IHtcbiAgICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgICBDREtfTkVYVEpTX0lOSVRfQ0FDSEVfRElSOiB0aGlzLmluaXRDYWNoZURpcixcbiAgICAgICAgICAuLi50aGlzLmFkYXB0ZXJQYXRoRW52KCksXG4gICAgICAgICAgLy8gYG9uQnVpbGRDb21wbGV0ZWAgcnVucyBpbnNpZGUgdGhpcyBwcm9jZXNzIGFuZCBjYW5ub3QgcmVhZCBDREtcbiAgICAgICAgICAvLyBwcm9wcywgc28gdGhlIHJlc29sdmVkIGdyb3VwcyB0cmF2ZWwgYXMgSlNPTi4gQWJzZW50IHdoZW4gbm90XG4gICAgICAgICAgLy8gc3BsaXR0aW5nLCB3aGljaCB0aGUgYWRhcHRlciByZWFkcyBhcyBcIm9uZSBkZXBsb3ltZW50IHJvb3RcIi5cbiAgICAgICAgICAuLi4odGhpcy5wcm9wcy5mdW5jdGlvbkdyb3Vwcz8ubGVuZ3RoXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBbRlVOQ1RJT05fR1JPVVBTX0VOVl9WQVJdOiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgIHRvRnVuY3Rpb25Hcm91cFNwZWNzKHRoaXMucHJvcHMuZnVuY3Rpb25Hcm91cHMpLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDoge30pLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTG9jYWwgYnVpbGQgZmFpbGVkOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQcmVwZW5kIGBwYXRjaC1mZXRjaC5qc2AgdG8gdGhlIGNsaWVudCBlbnRyeXBvaW50IGNodW5rcywgZm9yXG4gICAqIGBOZXh0anNHbG9iYWxGdW5jdGlvbnNgIG9ubHkuXG4gICAqXG4gICAqIFRoaXMgaXMgd2hhdCBtYWtlcyBQT1NUIHdvcmsgYXQgYWxsIG9uIHRoYXQgdHlwZS4gQ2xvdWRGcm9udCByZWFjaGVzIHRoZVxuICAgKiBzZXJ2ZXIgdGhyb3VnaCBhIExhbWJkYSBGdW5jdGlvbiBVUkwgd2l0aCBgQXV0aFR5cGU6IEFXU19JQU1gLCBzaWduZWQgYnkgYW5cbiAgICogb3JpZ2luIGFjY2VzcyBjb250cm9sLCBhbmQgQVdTIGRvY3VtZW50cyB0aGUgY29uc2VxdWVuY2U6IFwiSWYgeW91IHVzZSBQVVQgb3JcbiAgICogUE9TVCBtZXRob2RzIHdpdGggeW91ciBMYW1iZGEgZnVuY3Rpb24gVVJMLCB5b3VyIHVzZXJzIG11c3QgY29tcHV0ZSB0aGVcbiAgICogU0hBMjU2IG9mIHRoZSBib2R5IGFuZCBpbmNsdWRlIHRoZSBwYXlsb2FkIGhhc2ggdmFsdWUgb2YgdGhlIHJlcXVlc3QgYm9keSBpblxuICAgKiB0aGUgYHgtYW16LWNvbnRlbnQtc2hhMjU2YCBoZWFkZXIgd2hlbiBzZW5kaW5nIHRoZSByZXF1ZXN0IHRvIENsb3VkRnJvbnQuXG4gICAqIExhbWJkYSBkb2Vzbid0IHN1cHBvcnQgdW5zaWduZWQgcGF5bG9hZHMuXCJcbiAgICpcbiAgICogQ2xvdWRGcm9udCBzaWducyBHRVRzIGl0c2VsZiAoZW1wdHktYm9keSBoYXNoKSBidXQgd2lsbCBub3QgaGFzaCBhIGJvZHksIGFuZFxuICAgKiBhIGJyb3dzZXIgaGFzIG5vIHdheSB0byBhZGQgdGhhdCBoZWFkZXIgb24gaXRzIG93biwgc28gYW4gdW5wYXRjaGVkIGFwcFxuICAgKiBhbnN3ZXJzIGV2ZXJ5IHNlcnZlciBhY3Rpb24sIGZvcm0gc3VibWlzc2lvbiBhbmQgUE9TVCByb3V0ZSBoYW5kbGVyIHdpdGhcbiAgICogYDQwMyBJbnZhbGlkU2lnbmF0dXJlRXhjZXB0aW9uYCBiZWZvcmUgdGhlIHJlcXVlc3QgcmVhY2hlcyBOZXh0LmpzLiBUaGVcbiAgICogcGF0Y2ggaW5zdGFsbHMgYGZldGNoYC9gWE1MSHR0cFJlcXVlc3RgIHdyYXBwZXJzIHRoYXQgY29tcHV0ZSB0aGUgaGFzaC5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvcHJpdmF0ZS1jb250ZW50LXJlc3RyaWN0aW5nLWFjY2Vzcy10by1sYW1iZGEuaHRtbFxuICAgKi9cbiAgcHJpdmF0ZSBwYXRjaEZldGNoSW5DbGllbnRKcygpIHtcbiAgICBjb25zdCBzdGF0aWNDaHVua3NQYXRoID0gam9pbih0aGlzLmRvdE5leHRQYXRoLCBcInN0YXRpY1wiLCBcImNodW5rc1wiKTtcbiAgICBjb25zdCBjaHVua0ZpbGVzID0gcmVhZGRpclN5bmMoc3RhdGljQ2h1bmtzUGF0aCkuZmlsdGVyKFxuICAgICAgKGZpbGU6IHN0cmluZykgPT5cbiAgICAgICAgLy8gbWFpbi1hcHAtIGZvciB3ZWJwYWNrLCB0dXJib3BhY2stIGZvciB0dXJib1xuICAgICAgICBmaWxlLnN0YXJ0c1dpdGgoXCJtYWluLWFwcC1cIikgfHxcbiAgICAgICAgKGZpbGUuc3RhcnRzV2l0aChcInR1cmJvcGFjay1cIikgJiYgZmlsZS5lbmRzV2l0aChcIi5qc1wiKSksXG4gICAgKTtcblxuICAgIGlmIChjaHVua0ZpbGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gY2xpZW50IHNpZGUganMgZW50cnlwb2ludCBmaWxlcyBmb3VuZFwiKTtcbiAgICB9XG5cbiAgICAvLyBSZWFkIHRoZSBwYXRjaC1mZXRjaC5qcyBjb250ZW50XG4gICAgY29uc3QgcGF0Y2hGZXRjaFBhdGggPSBqb2luKF9fZGlybmFtZSwgXCJwYXRjaC1mZXRjaC5qc1wiKTtcbiAgICBjb25zdCBwYXRjaEZldGNoQ29udGVudCA9IHJlYWRGaWxlU3luYyhwYXRjaEZldGNoUGF0aCwgXCJ1dGYtOFwiKTtcblxuICAgIC8vIFByZXBlbmQgcGF0Y2gtZmV0Y2ggbG9naWMgdG8gZWFjaCBlbnRyeXBvaW50LCBvbmNlLiBOb3cgdGhhdCB0aGlzIHJ1bnNcbiAgICAvLyBvdXRzaWRlIGBydW5OZXh0QnVpbGRgLCB0aGUgc2FtZSBgLm5leHRgIGNhbiBiZSBzeW50aGVzaXplZCBtb3JlIHRoYW5cbiAgICAvLyBvbmNlIChgc2tpcEJ1aWxkOiB0cnVlYCwgYGNkayBzeW50aGAgdGhlbiBgY2RrIGRlcGxveWAsIGEgcmV0cmllZFxuICAgIC8vIGRlcGxveSksIGFuZCBwcmVwZW5kaW5nIHR3aWNlIHdvdWxkIHJlLXdyYXAgdGhlIHdyYXBwZXJzLlxuICAgIGZvciAoY29uc3QgY2h1bmtGaWxlIG9mIGNodW5rRmlsZXMpIHtcbiAgICAgIGNvbnN0IGNodW5rRmlsZVBhdGggPSBqb2luKHN0YXRpY0NodW5rc1BhdGgsIGNodW5rRmlsZSk7XG4gICAgICBjb25zdCBwYXRjaGVkQ29udGVudCA9IHBhdGNoQ2xpZW50Q2h1bmsoXG4gICAgICAgIHJlYWRGaWxlU3luYyhjaHVua0ZpbGVQYXRoLCBcInV0Zi04XCIpLFxuICAgICAgICBwYXRjaEZldGNoQ29udGVudCxcbiAgICAgICAgY2h1bmtGaWxlUGF0aCxcbiAgICAgICk7XG4gICAgICBpZiAocGF0Y2hlZENvbnRlbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBBbHJlYWR5IHBhdGNoZWQsIHNraXBwaW5nOiAke2NodW5rRmlsZVBhdGh9YCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgd3JpdGVGaWxlU3luYyhjaHVua0ZpbGVQYXRoLCBwYXRjaGVkQ29udGVudCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBwdWJsaWMgZGlyZWN0b3J5IGVudHJpZXMgZnJvbSBsb2NhbCBmaWxlc3lzdGVtXG4gICAqL1xuICBwcml2YXRlIGdldExvY2FsUHVibGljRGlyRW50cmllcygpOiBQdWJsaWNEaXJFbnRyeVtdIHtcbiAgICBjb25zdCBwdWJsaWNEaXJQYXRoID0gam9pbih0aGlzLnByb3BzLmJ1aWxkRGlyZWN0b3J5LCBcInB1YmxpY1wiKTtcbiAgICBpZiAoIWV4aXN0c1N5bmMocHVibGljRGlyUGF0aCkpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVhZGRpclN5bmMocHVibGljRGlyUGF0aCwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pLm1hcCgoZW50cnkpID0+ICh7XG4gICAgICBuYW1lOiBlbnRyeS5uYW1lLFxuICAgICAgaXNEaXJlY3Rvcnk6IGVudHJ5LmlzRGlyZWN0b3J5KCksXG4gICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0cmlwIHdoYXRldmVyIHBsYXRmb3JtLXNwZWNpZmljIFNoYXJwIGJpbmFyaWVzIGBuZXh0IGJ1aWxkYCdzIG91dHB1dCBmaWxlXG4gICAqIHRyYWNpbmcgc3RhZ2VkLCBzaW5jZSB0aGV5J3JlIHRoZSBob3N0J3MgKGUuZy4gbWFjT1MvZ2xpYmMpIHJhdGhlciB0aGFuIHRoZVxuICAgKiBkZXBsb3ltZW50IHRhcmdldCdzLCB0aGVuIGluc3RhbGwgdGhlIHRhcmdldCdzLiBTa2lwcGluZyB0aGlzIGlzIHNpbGVudDpcbiAgICogYGltYWdlT3B0aW1pemVyYCBjYXRjaGVzIHRoZSBsb2FkIGZhaWx1cmUgaW50ZXJuYWxseSBhbmQgcmV0dXJucyB0aGVcbiAgICogdW5vcHRpbWl6ZWQgb3JpZ2luYWwgd2l0aCBhbiBIVFRQIDIwMC5cbiAgICpcbiAgICogT25seSBhIHJvb3Qgd2l0aCBgc2hhcnBgIHN0YWdlZCBnZXRzIHRoZSBiaW5hcmllczogdGhlIGltYWdlIG9wdGltaXplclxuICAgKiBicmluZ3MgaXQgaW50byBgZGVmYXVsdGAsIHdoaWNoIHNlcnZlcyBldmVyeSBgL19uZXh0L2ltYWdlYCwgYW5kIGFub3RoZXJcbiAgICogZ3JvdXAgaGFzIGl0IG9ubHkgaWYgaXRzIG93biByb3V0ZXMgdXNlIGl0LiBTbyBvbmx5IGBkZWZhdWx0YCB3YXJucyB3aGVuXG4gICAqIGl0J3MgbWlzc2luZy5cbiAgICovXG4gIHByaXZhdGUgc3RhZ2VTaGFycEZvclRhcmdldChcbiAgICByb290OiBOZXh0anNEZXBsb3ltZW50Um9vdCxcbiAgICBwcm9qZWN0RGlyOiBzdHJpbmcsXG4gICAgcGxhdGZvcm06IHN0cmluZyxcbiAgKSB7XG4gICAgY29uc3Qgc2hhcnBTb3VyY2UgPSB0aGlzLnJlbW92ZUV4aXN0aW5nU2hhcnBCaW5hcmllcyhyb290LnBhdGgsIHByb2plY3REaXIpO1xuICAgIGlmICghc2hhcnBTb3VyY2UpIHtcbiAgICAgIGlmIChyb290Lm5hbWUgPT09IERFRkFVTFRfRlVOQ1RJT05fR1JPVVApIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IFwic2hhcnBcIiBub3QgZm91bmQgaW4gdGhlIHN0YWdlZCBidWlsZCBvdXRwdXQuIEFkZCBcInNoYXJwXCIgYXMgYSBkZXBlbmRlbmN5IG9mIHlvdXIgTmV4dC5qcyBhcHAgdG8gZW5hYmxlIGltYWdlIG9wdGltaXphdGlvbi5gLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmluc3RhbGxTaGFycFBhY2thZ2VzKFxuICAgICAgc2hhcnBCaW5hcnlEaXIocm9vdC5wYXRoKSxcbiAgICAgIHRoaXMuZ2V0U2hhcnBCaW5hcnlQYWNrYWdlcyhzaGFycFNvdXJjZSwgcGxhdGZvcm0pLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVjdXJzaXZlbHkgZmluZCBhbmQgcmVtb3ZlIGV4aXN0aW5nIFNoYXJwIHBsYXRmb3JtIGJpbmFyaWVzLlxuICAgKlxuICAgKiBgcm9vdGAgaXMgd2Fsa2VkIHdob2xlIHJhdGhlciB0aGFuIGp1c3QgaXRzIGBub2RlX21vZHVsZXNgOiB0aGUgc3RhZ2VkIHRyZWVcbiAgICogaXMga2V5ZWQgYnkgcmVwby1yb290LXJlbGF0aXZlIHBhdGgsIHNvIGluIGEgbW9ub3JlcG8gdGhlIGBub2RlX21vZHVsZXNgXG4gICAqIGhvbGRpbmcgYHNoYXJwYCBpcyBzZXZlcmFsIGRpcmVjdG9yaWVzIGRvd24uIHtAbGluayBpc1NoYXJwQmluYXJ5UGFja2FnZX0gaXNcbiAgICogd2hhdCBrZWVwcyB0aGF0IGZyb20gcmVhY2hpbmcgdGhlIGFwcCdzIG93biBvdXRwdXQg4oCUIHRoZSBzdGFnZWQgcm9vdCBob2xkc1xuICAgKiB0aGUgY29tcGlsZWQgYC5uZXh0YCBhcyB3ZWxsIGFzIHRoZSBkZXBlbmRlbmNpZXMuXG4gICAqXG4gICAqIEBwYXJhbSBwcm9qZWN0RGlyIHRoZSBhcHAncyBkaXJlY3RvcnkgaW5zaWRlIGByb290YCwgd2hpY2ggYG5leHRgIGlzXG4gICAqIHJlc29sdmVkIGZyb20uXG4gICAqIEByZXR1cm5zIHRoZSBzdGFnZWQgYHNoYXJwYCBKUyB3cmFwcGVyIHRvIGluc3RhbGwgbmV4dCB0bywgZm91bmQgaW4gdGhlIHNhbWVcbiAgICogd2FsazogYSByb290IGNhbiBiZSBodW5kcmVkcyBvZiBtZWdhYnl0ZXMsIGFuZCBlYWNoIGdyb3VwIGhhcyBvbmUuXG4gICAqL1xuICBwcml2YXRlIHJlbW92ZUV4aXN0aW5nU2hhcnBCaW5hcmllcyhcbiAgICByb290OiBzdHJpbmcsXG4gICAgcHJvamVjdERpcjogc3RyaW5nLFxuICApOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHNoYXJwQ2FuZGlkYXRlczogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIExpbmtzIGFyZSBsaXN0ZWQsIG5vdCBmb2xsb3dlZDogZXZlcnkgbGluayBpbiBhIHN0YWdlZCByb290IHBvaW50c1xuICAgIC8vIGluc2lkZSBpdCAoYHN0YWdlRmlsZXNgIGNvcGllcyB0aGUgb25lcyB0aGF0IGRvbid0KSwgc28gaXRzIHRhcmdldCBpc1xuICAgIC8vIHdhbGtlZCBhdCBpdHMgb3duIHBhdGggYW55d2F5LCBhbmQgZm9sbG93aW5nIHRoZW0gaXMgd2hhdCBsZXQgYVxuICAgIC8vIHdvcmtzcGFjZSBjeWNsZSBoYW5nIHRoZSBzeW50aC5cbiAgICBjb25zdCBhbGxFbnRyaWVzID0gbGlzdFRyZWUocm9vdCk7XG5cbiAgICAvLyBTeW1saW5rcyBhcmUgdW5saW5rZWQsIG5vdCBgcm1TeW5jYGVkLCBhbmQgdGhleSBnbyBmaXJzdC4gcG5wbSBwb2ludHNcbiAgICAvLyBzZXZlcmFsIGxpbmtzIGF0IG9uZSBzdG9yZSBkaXJlY3RvcnksIGFuZCBgcm1TeW5jKOKApiwgeyByZWN1cnNpdmU6IHRydWUsXG4gICAgLy8gZm9yY2U6IHRydWUgfSlgICpzaWxlbnRseSBuby1vcHMqIG9uIGEgc3ltbGluayB3aG9zZSB0YXJnZXQgaXMgYWxyZWFkeVxuICAgIC8vIGdvbmUg4oCUIGBmb3JjZWAgc3dhbGxvd3MgdGhlIEVOT0VOVCBpdHMgYHJtZGlyYCBnZXRzLiBSZW1vdmluZyBhIHN0b3JlXG4gICAgLy8gZGlyZWN0b3J5IGJlZm9yZSBpdHMgbGlua3MgdGhlcmVmb3JlIGxlZnQgZGFuZ2xpbmdcbiAgICAvLyBgQGltZy9zaGFycC1kYXJ3aW4tYXJtNjRgIGVudHJpZXMgaW4gdGhlIGFzc2V0LCB3aGljaCBpcyBhIGxhdGVudCBFTk9FTlRcbiAgICAvLyBpbiB3aGF0ZXZlciBuZXh0IGZvbGxvd3MgdGhlbSAoYHNoYXJwYCBkb2VzLCB3aGVuIGl0IGxvb2tzIGZvciBiaW5hcmllcykuXG4gICAgY29uc3Qgc3ltbGlua3M6IHN0cmluZ1tdID0gW107XG4gICAgY29uc3QgZGlyZWN0b3JpZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGFsbEVudHJpZXMpIHtcbiAgICAgIGlmIChlbnRyeS5pc0RpcmVjdG9yeSgpICYmIGVudHJ5Lm5hbWUgPT09IFwic2hhcnBcIikge1xuICAgICAgICBjb25zdCBwYXRoID0gam9pbihlbnRyeS5wYXJlbnRQYXRoLCBlbnRyeS5uYW1lKTtcbiAgICAgICAgaWYgKGV4aXN0c1N5bmMoam9pbihwYXRoLCBcInBhY2thZ2UuanNvblwiKSkpIHtcbiAgICAgICAgICBzaGFycENhbmRpZGF0ZXMucHVzaChwYXRoKTtcbiAgICAgICAgfVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmICghaXNTaGFycEJpbmFyeVBhY2thZ2UoZW50cnkucGFyZW50UGF0aCwgZW50cnkubmFtZSkpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGVudHJ5LnBhcmVudFBhdGgsIGVudHJ5Lm5hbWUpO1xuICAgICAgaWYgKGVudHJ5LmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgc3ltbGlua3MucHVzaChmdWxsUGF0aCk7XG4gICAgICB9IGVsc2UgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgZGlyZWN0b3JpZXMucHVzaChmdWxsUGF0aCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZGVidWcoXG4gICAgICBgJHtMT0dfUFJFRklYfSBSZW1vdmluZyAke3N5bWxpbmtzLmxlbmd0aH0gU2hhcnAgYmluYXJ5IHN5bWxpbmtzIGFuZCAke2RpcmVjdG9yaWVzLmxlbmd0aH0gZGlyZWN0b3JpZXNgLFxuICAgICk7XG5cbiAgICBmb3IgKGNvbnN0IHBhdGggb2Ygc3ltbGlua3MpIHtcbiAgICAgIHVubGlua1N5bmMocGF0aCk7XG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBVbmxpbmtlZDogJHtwYXRofWApO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IHBhdGggb2YgZGlyZWN0b3JpZXMpIHtcbiAgICAgIHJtU3luYyhwYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBSZW1vdmVkOiAke3BhdGh9YCk7XG4gICAgfVxuICAgIHJldHVybiBwaWNrU3RhZ2VkU2hhcnBQYWNrYWdlKFxuICAgICAgc2hhcnBDYW5kaWRhdGVzLFxuICAgICAgcmVzb2x2ZU5leHRTaGFycChwcm9qZWN0RGlyKSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgdGhlIGBAaW1nL3NoYXJwLTxwbGF0Zm9ybT5gIGFuZCBgQGltZy9zaGFycC1saWJ2aXBzLTxwbGF0Zm9ybT5gXG4gICAqIHZlcnNpb25zIHRvIGluc3RhbGwgZm9yIGEgZ2l2ZW4gcGxhdGZvcm0uXG4gICAqXG4gICAqIFRoZXNlIG11c3QgbWF0Y2ggdGhlIGBzaGFycGAgSlMgd3JhcHBlciB0aGF0IG91dHB1dCBmaWxlIHRyYWNpbmcgc3RhZ2VkOlxuICAgKiBgc2hhcnBgJ3MgYGxpYi9saWJ2aXBzLmpzYCBjb21wYXJlcyB0aGUgYmluYXJ5J3NcbiAgICogcmVwb3J0ZWQgbGlidmlwcyB2ZXJzaW9uIGFnYWluc3QgaXRzIG93biBgbWluaW11bUxpYnZpcHNWZXJzaW9uYCBhbmRcbiAgICogdGhyb3dzIGF0IGxvYWQgd2hlbiB0aGV5IGRpc2FncmVlLiBgc2hhcnBgIHBpbnMgYm90aCBpbiBpdHNcbiAgICogYG9wdGlvbmFsRGVwZW5kZW5jaWVzYCwgc28gdGhhdCBtYW5pZmVzdCBpcyB0aGUgYXV0aG9yaXRhdGl2ZSBzb3VyY2UuXG4gICAqL1xuICBwcml2YXRlIGdldFNoYXJwQmluYXJ5UGFja2FnZXMoXG4gICAgc2hhcnBTb3VyY2U6IHN0cmluZyxcbiAgICBwbGF0Zm9ybTogc3RyaW5nLFxuICApOiB7IG5hbWU6IHN0cmluZzsgdmVyc2lvbjogc3RyaW5nIH1bXSB7XG4gICAgLy8gT25seSBmb3IgYSBiaW5hcnkgdGhlIHN0YWdlZCBgc2hhcnBgIGRvZXMgbm90IHBpbi5cbiAgICBjb25zdCBmYWxsYmFjayA9IFtcbiAgICAgIHsgbmFtZTogYHNoYXJwLWxpYnZpcHMtJHtwbGF0Zm9ybX1gLCB2ZXJzaW9uOiBcIjEuMi40XCIgfSxcbiAgICAgIHsgbmFtZTogYHNoYXJwLSR7cGxhdGZvcm19YCwgdmVyc2lvbjogXCIwLjM0LjVcIiB9LFxuICAgIF07XG5cbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICByZWFkRmlsZVN5bmMoam9pbihzaGFycFNvdXJjZSwgXCJwYWNrYWdlLmpzb25cIiksIFwidXRmLThcIiksXG4gICAgKTtcbiAgICBjb25zdCBvcHRpb25hbERlcGVuZGVuY2llczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9XG4gICAgICBtYW5pZmVzdC5vcHRpb25hbERlcGVuZGVuY2llcyA/PyB7fTtcblxuICAgIHJldHVybiBmYWxsYmFjay5tYXAoKHBrZykgPT4ge1xuICAgICAgY29uc3QgdmVyc2lvbiA9IG9wdGlvbmFsRGVwZW5kZW5jaWVzW2BAaW1nLyR7cGtnLm5hbWV9YF07XG4gICAgICBpZiAoIXZlcnNpb24pIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IHNoYXJwQCR7bWFuaWZlc3QudmVyc2lvbn0gZG9lcyBub3QgcGluIFwiQGltZy8ke3BrZy5uYW1lfVwiOyBmYWxsaW5nIGJhY2sgdG8gJHtwa2cudmVyc2lvbn0uYCxcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHBrZztcbiAgICAgIH1cbiAgICAgIHJldHVybiB7IG5hbWU6IHBrZy5uYW1lLCB2ZXJzaW9uIH07XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRG93bmxvYWQgKHdpdGggY2FjaGluZykgYW5kIGV4dHJhY3QgU2hhcnAncyBwbGF0Zm9ybS1zcGVjaWZpYyBiaW5hcnlcbiAgICogcGFja2FnZXMgaW50byBgaW1nUGF0aGAuXG4gICAqL1xuICBwcml2YXRlIGluc3RhbGxTaGFycFBhY2thZ2VzKFxuICAgIGltZ1BhdGg6IHN0cmluZyxcbiAgICBwYWNrYWdlczogeyBuYW1lOiBzdHJpbmc7IHZlcnNpb246IHN0cmluZyB9W10sXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IGNhY2hlRGlyID0gam9pbih0bXBkaXIoKSwgXCJjZGstbmV4dGpzLXNoYXJwLWNhY2hlXCIpO1xuICAgIG1rZGlyU3luYyhjYWNoZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICBmb3IgKGNvbnN0IHBrZyBvZiBwYWNrYWdlcykge1xuICAgICAgY29uc3QgdGFyZ2V0RGlyID0gam9pbihpbWdQYXRoLCBwa2cubmFtZSk7XG4gICAgICBjb25zdCB1cmwgPSBgaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGltZy8ke3BrZy5uYW1lfS8tLyR7cGtnLm5hbWV9LSR7cGtnLnZlcnNpb259LnRnemA7XG5cbiAgICAgIC8vIENyZWF0ZSBhIGNvbnNpc3RlbnQgZmlsZW5hbWUgYmFzZWQgb24gcGFja2FnZSBuYW1lIGFuZCB2ZXJzaW9uXG4gICAgICBjb25zdCBjYWNoZUZpbGVOYW1lID0gYCR7cGtnLm5hbWV9LSR7cGtnLnZlcnNpb259LnRnemA7XG4gICAgICBjb25zdCBjYWNoZWRGaWxlID0gam9pbihjYWNoZURpciwgY2FjaGVGaWxlTmFtZSk7XG5cbiAgICAgIC8vIENoZWNrIGlmIHdlIGFscmVhZHkgaGF2ZSBhIHZhbGlkIHBhY2thZ2UgY2FjaGVkOyByZS1kb3dubG9hZCBpZlxuICAgICAgLy8gYSBwcmV2aW91cyBydW4gbGVmdCBiZWhpbmQgYSB0cnVuY2F0ZWQvY29ycnVwdCBkb3dubG9hZFxuICAgICAgaWYgKGV4aXN0c1N5bmMoY2FjaGVkRmlsZSkgJiYgdGhpcy5pc0NhY2hlZEZpbGVWYWxpZChjYWNoZWRGaWxlKSkge1xuICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICBgJHtMT0dfUFJFRklYfSBVc2luZyBjYWNoZWQgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn0gZnJvbSAke2NhY2hlZEZpbGV9YCxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlYnVnKGAke0xPR19QUkVGSVh9IERvd25sb2FkaW5nICR7cGtnLm5hbWV9QCR7cGtnLnZlcnNpb259Li4uYCk7XG5cbiAgICAgICAgLy8gRG93bmxvYWQgdG8gYSBwcm9jZXNzLXVuaXF1ZSB0ZW1wIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LFxuICAgICAgICAvLyB0aGVuIGF0b21pY2FsbHkgcmVuYW1lIGl0IG9udG8gdGhlIHNoYXJlZCBjYWNoZSBwYXRoLiBDb25jdXJyZW50XG4gICAgICAgIC8vIHN5bnRoIHByb2Nlc3NlcyAoZS5nLiBUdXJib3JlcG8gcnVubmluZyBtdWx0aXBsZSBgY2RrYCBjb21tYW5kcylcbiAgICAgICAgLy8gc2hhcmUgdGhpcyBjYWNoZSBkaXIsIHNvIHdyaXRpbmcgZGlyZWN0bHkgdG8gYGNhY2hlZEZpbGVgIHJpc2tzXG4gICAgICAgIC8vIGFub3RoZXIgcHJvY2VzcyBleHRyYWN0aW5nIGEgaGFsZi13cml0dGVuIGZpbGUuIFJlbmFtaW5nIHdpdGhpblxuICAgICAgICAvLyB0aGUgc2FtZSBmaWxlc3lzdGVtIGlzIGF0b21pYywgc28gcmVhZGVycyBvbmx5IGV2ZXIgc2VlIGFcbiAgICAgICAgLy8gY29tcGxldGUgZmlsZSwgd2hpY2hldmVyIHByb2Nlc3Mgd2lucyB0aGUgcmFjZS5cbiAgICAgICAgY29uc3QgdGVtcEZpbGUgPSBqb2luKFxuICAgICAgICAgIGNhY2hlRGlyLFxuICAgICAgICAgIGAke2NhY2hlRmlsZU5hbWV9LiR7cHJvY2Vzcy5waWR9LSR7cmFuZG9tQnl0ZXMoNikudG9TdHJpbmcoXCJoZXhcIil9LnRtcGAsXG4gICAgICAgICk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gLS1mYWlsIG1ha2VzIGN1cmwgZXhpdCBub24temVybyBvbiBIVFRQIGVycm9ycyBhbmQgLS1yZXRyeVxuICAgICAgICAgIC8vIGhhbmRsZXMgdHJhbnNpZW50IGNvbm5lY3Rpb24gZHJvcHMgc28gYSBwYXJ0aWFsIHRyYW5zZmVyXG4gICAgICAgICAgLy8gaXNuJ3QgY2FjaGVkIGFzIHZhbGlkLlxuICAgICAgICAgIGV4ZWNGaWxlU3luYyhcbiAgICAgICAgICAgIFwiY3VybFwiLFxuICAgICAgICAgICAgW1xuICAgICAgICAgICAgICBcIi1MXCIsXG4gICAgICAgICAgICAgIFwiLS1mYWlsXCIsXG4gICAgICAgICAgICAgIFwiLS1yZXRyeVwiLFxuICAgICAgICAgICAgICBcIjNcIixcbiAgICAgICAgICAgICAgXCItLXJldHJ5LWRlbGF5XCIsXG4gICAgICAgICAgICAgIFwiMVwiLFxuICAgICAgICAgICAgICBcIi1vXCIsXG4gICAgICAgICAgICAgIHRlbXBGaWxlLFxuICAgICAgICAgICAgICB1cmwsXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgeyBzdGRpbzogXCJwaXBlXCIgfSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKCF0aGlzLmlzQ2FjaGVkRmlsZVZhbGlkKHRlbXBGaWxlKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICBgRG93bmxvYWRlZCBmaWxlIGZvciAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSBpcyBlbXB0eSBvciBtaXNzaW5nOiAke3RlbXBGaWxlfWAsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlbmFtZVN5bmModGVtcEZpbGUsIGNhY2hlZEZpbGUpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIHJtU3luYyh0ZW1wRmlsZSwgeyBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlYnVnKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IENhY2hlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSB0byAke2NhY2hlZEZpbGV9YCxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgbWtkaXJTeW5jKHRhcmdldERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBleGVjRmlsZVN5bmMoXG4gICAgICAgIFwidGFyXCIsXG4gICAgICAgIFtcIi14emZcIiwgY2FjaGVkRmlsZSwgXCItQ1wiLCB0YXJnZXREaXIsIFwiLS1zdHJpcC1jb21wb25lbnRzPTFcIl0sXG4gICAgICAgIHsgc3RkaW86IFwicGlwZVwiIH0sXG4gICAgICApO1xuXG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBJbnN0YWxsZWQgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHRoYXQgYSBjYWNoZWQgU2hhcnAgYmluYXJ5IGFyY2hpdmUgaXMgbm9uLWVtcHR5LiBHdWFyZHMgYWdhaW5zdFxuICAgKiBhIHRydW5jYXRlZC9jb3JydXB0IGRvd25sb2FkIChlLmcuIGZyb20gYSBkcm9wcGVkIGNvbm5lY3Rpb24pIGJlaW5nXG4gICAqIHJldXNlZCBhY3Jvc3Mgc3ludGggb3BlcmF0aW9ucy5cbiAgICovXG4gIHByaXZhdGUgaXNDYWNoZWRGaWxlVmFsaWQoZmlsZVBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gc3RhdFN5bmMoZmlsZVBhdGgpLnNpemUgPiAwO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFdoYXQgdHJhdmVscyB0byB0aGUgYWRhcHRlciBpbiB7QGxpbmsgRlVOQ1RJT05fR1JPVVBTX0VOVl9WQVJ9LCBhbmQgd2hhdCBpdFxuICogcmVjb3JkcyBiYWNrIGFzIGBBZGFwdGVyTWFuaWZlc3QuZnVuY3Rpb25Hcm91cHNgLlxuICovXG5mdW5jdGlvbiB0b0Z1bmN0aW9uR3JvdXBTcGVjcyhcbiAgZ3JvdXBzOiBOZXh0anNGdW5jdGlvbkdyb3VwUm91dGVzW10sXG4pOiBGdW5jdGlvbkdyb3VwU3BlY1tdIHtcbiAgcmV0dXJuIGdyb3Vwcy5tYXAoKHsgbmFtZSwgcm91dGVzIH0pID0+ICh7IG5hbWUsIHJvdXRlcyB9KSk7XG59XG5cbi8qKiBgZ3JvdXBzYCBpbiBhIGNhbm9uaWNhbCBvcmRlciwgZm9yIGNvbXBhcmluZyB0d28gb2YgdGhlbS4gKi9cbmZ1bmN0aW9uIHNvcnRlZEdyb3VwU3BlY3MoXG4gIGdyb3VwczogcmVhZG9ubHkgRnVuY3Rpb25Hcm91cFNwZWNbXSB8IHVuZGVmaW5lZCxcbik6IEZ1bmN0aW9uR3JvdXBTcGVjW10gfCB1bmRlZmluZWQge1xuICByZXR1cm4gZ3JvdXBzXG4gICAgPy5tYXAoKHsgbmFtZSwgcm91dGVzIH0pID0+ICh7IG5hbWUsIHJvdXRlczogWy4uLnJvdXRlc10uc29ydCgpIH0pKVxuICAgIC5zb3J0KChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gLTEgOiAxKSk7XG59XG5cbi8qKlxuICogUGljayB0aGUgc3RhZ2VkIGBzaGFycGAgSlMgd3JhcHBlciBvdXQgb2YgZXZlcnkgY29weSBmb3VuZCBpbiB0aGUgdHJlZS5cbiAqXG4gKiBVbmxpa2UgYSBzdGFuZGFsb25lIGJ1aWxkIHRoZXJlIGlzIG5vIHNpbmdsZSBgbm9kZV9tb2R1bGVzYCB0byBsb29rIGluOiB0aGVcbiAqIHRyZWUgbWlycm9ycyByZXBvLXJvb3QtcmVsYXRpdmUgcGF0aHMsIHNvIHRoZSBzZWFyY2ggaXMgYnkgZGlyZWN0b3J5IG5hbWUuXG4gKlxuICogQW4gYXBwIGNhbiBoYXZlIHR3byBgc2hhcnBgIGNvcGllcyBhdCBkaWZmZXJlbnQgdmVyc2lvbnMgKGl0cyBvd24sIGhvaXN0ZWQsXG4gKiBhbmQgbmV4dCdzLCBuZXN0ZWQgdW5kZXIgYG5leHQvbm9kZV9tb2R1bGVzYCksIGFuZCBldmVyeSBiaW5hcnkgZ29lcyBpbnRvIHRoZVxuICogb25lIHJvb3QgYEBpbWdgLCBzbyB0aGUgY29weSBwaW5uaW5nIHRoZW0gaGFzIHRvIGJlIHRoZSBvbmUgYG5leHRgJ3MgaW1hZ2VcbiAqIG9wdGltaXplciBsb2FkczogYG5leHRTaGFycGAsIHdoZW4ge0BsaW5rIHJlc29sdmVOZXh0U2hhcnB9IGZvdW5kIGl0LiBPdGhlcndpc2VcbiAqIHNob3J0ZXN0IHBhdGggd2lucyBhcyB0aGUgY2xvc2VzdCB0byBhIGhvaXN0ZWQgaW5zdGFsbCwgc29ydGVkIGZvclxuICogZGV0ZXJtaW5pc20uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwaWNrU3RhZ2VkU2hhcnBQYWNrYWdlKFxuICBjYW5kaWRhdGVzOiBzdHJpbmdbXSxcbiAgbmV4dFNoYXJwPzogc3RyaW5nLFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgdXNlZCA9XG4gICAgbmV4dFNoYXJwICYmXG4gICAgY2FuZGlkYXRlcy5maW5kKChjYW5kaWRhdGUpID0+XG4gICAgICBuZXh0U2hhcnAuc3RhcnRzV2l0aChyZWFscGF0aFN5bmMoY2FuZGlkYXRlKSArIHNlcCksXG4gICAgKTtcbiAgaWYgKHVzZWQpIHtcbiAgICByZXR1cm4gdXNlZDtcbiAgfVxuICBjYW5kaWRhdGVzLnNvcnQoKGEsIGIpID0+IGEubGVuZ3RoIC0gYi5sZW5ndGggfHwgYS5sb2NhbGVDb21wYXJlKGIpKTtcbiAgaWYgKGNhbmRpZGF0ZXMubGVuZ3RoID4gMSkge1xuICAgIGRlYnVnKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gTXVsdGlwbGUgc3RhZ2VkIFwic2hhcnBcIiBjb3BpZXM7IHVzaW5nICR7Y2FuZGlkYXRlc1swXX1gLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZXNbMF07XG59XG5cbi8qKlxuICogVGhlIHJlYWwgcGF0aCBvZiB0aGUgYHNoYXJwYCBlbnRyeSBwb2ludCB0aGUgc3RhZ2VkIGBuZXh0YCByZXNvbHZlcyBmcm9tXG4gKiBgcHJvamVjdERpcmAsIGB1bmRlZmluZWRgIHdoZW4gZWl0aGVyIGRvZXMgbm90IHJlc29sdmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlTmV4dFNoYXJwKHByb2plY3REaXI6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHRyeSB7XG4gICAgLy8gVGhlIGFuY2hvciBmaWxlIG5lZWRuJ3QgZXhpc3Q7IGBjcmVhdGVSZXF1aXJlYCBvbmx5IHJlYWRzIGl0cyBkaXJlY3RvcnkuXG4gICAgY29uc3QgbmV4dFBhY2thZ2UgPSBjcmVhdGVSZXF1aXJlKFxuICAgICAgam9pbihwcm9qZWN0RGlyLCBcImNkay1uZXh0anMtbmV4dC1yZXNvbHZlci5janNcIiksXG4gICAgKS5yZXNvbHZlKFwibmV4dC9wYWNrYWdlLmpzb25cIik7XG4gICAgcmV0dXJuIGNyZWF0ZVJlcXVpcmUobmV4dFBhY2thZ2UpLnJlc29sdmUoXCJzaGFycFwiKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIGVudHJ5IGBuYW1lYCBpbiBgcGFyZW50UGF0aGAgaXMgYW4gYEBpbWcvc2hhcnAtKmAgcGxhdGZvcm0gYmluYXJ5XG4gKiBwYWNrYWdlLCBvciBwbnBtJ3Mgc3RvcmUgZW50cnkgZm9yIG9uZS5cbiAqXG4gKiBUaGUgbmFtZSBhbG9uZSBpcyBub3QgZW5vdWdoIHRvIGRlbGV0ZSBhIGRpcmVjdG9yeSBieS4gQSByb3V0ZSBzZWdtZW50IGNhbGxlZFxuICogYHNoYXJwLWVkZ2VzYCBzdGFnZXMgYC5uZXh0L3NlcnZlci9hcHAvc2hhcnAtZWRnZXMvYCwgYW5kIHJlbW92aW5nIGl0IGxlZnQgdGhlXG4gKiBtYW5pZmVzdCBsaXN0aW5nIGFuIGVudHJ5cG9pbnQgdGhhdCBpcyBubyBsb25nZXIgb24gZGlzayDigJQgZXZlcnkgcmVxdWVzdCB0b1xuICogdGhhdCByb3V0ZSA1MDBpbmcgd2l0aCBcIkNvdWxkIG5vdCBsb2FkIHRoZSBlbnRyeXBvaW50XCIuIE5vciBpcyBcImEgYHNoYXJwLWBcbiAqIHBhY2thZ2VcIjogYHNoYXJwLWljb2AgYW5kIGBzaGFycC1waGFzaGAgYXJlIHVucmVsYXRlZCBkZXBlbmRlbmNpZXMsIGFuZFxuICogcmVtb3ZpbmcgdGhlbSBmYWlsZWQgdGhlIGFwcCBhdCBydW50aW1lIHdpdGggTU9EVUxFX05PVF9GT1VORC4gU28gYm90aCB0aGVcbiAqIHNjb3BlIGFuZCB0aGUgcGxhY2UgaGF2ZSB0byBtYXRjaDpcbiAqXG4gKiAtIGBub2RlX21vZHVsZXMvQGltZy9zaGFycC3igKZgLCB3aGVyZSBldmVyeSBwbGF0Zm9ybSBiaW5hcnkgYWN0dWFsbHkgbGl2ZXNcbiAqIC0gYG5vZGVfbW9kdWxlcy8ucG5wbS9AaW1nK3NoYXJwLeKApkAwLjM1LjRgLCBwbnBtJ3Mgc3RvcmUsIHdob3NlIGVudHJpZXMgYXJlXG4gKiAgIGFsc28gd2hhdCB0aGUgYEBpbWdgIGxpbmtzIHBvaW50IGF0IChgc2hhcnAtbGlidmlwcy3igKZgIG1hdGNoZXMgdGhlIHNhbWUgd2F5KVxuICpcbiAqIFRoZSBgbm9kZV9tb2R1bGVzYCBzZWdtZW50IGlzIHJlcXVpcmVkIGFzIHdlbGwsIHNvIGFuIGFwcCBkaXJlY3RvcnkgdGhhdFxuICogaGFwcGVucyB0byBiZSBjYWxsZWQgYEBpbWdgIG9yIGAucG5wbWAgaXMgc3RpbGwgbGVmdCBhbG9uZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2hhcnBCaW5hcnlQYWNrYWdlKFxuICBwYXJlbnRQYXRoOiBzdHJpbmcsXG4gIG5hbWU6IHN0cmluZyxcbik6IGJvb2xlYW4ge1xuICBjb25zdCBzZWdtZW50cyA9IHBhcmVudFBhdGguc3BsaXQoc2VwKTtcbiAgY29uc3QgcGFyZW50ID0gc2VnbWVudHNbc2VnbWVudHMubGVuZ3RoIC0gMV07XG4gIGNvbnN0IHNjb3BlZCA9XG4gICAgKHBhcmVudCA9PT0gXCJAaW1nXCIgJiYgbmFtZS5zdGFydHNXaXRoKFwic2hhcnAtXCIpKSB8fFxuICAgIChwYXJlbnQgPT09IFwiLnBucG1cIiAmJiBuYW1lLnN0YXJ0c1dpdGgoXCJAaW1nK3NoYXJwLVwiKSk7XG4gIHJldHVybiBzY29wZWQgJiYgc2VnbWVudHMuaW5jbHVkZXMoXCJub2RlX21vZHVsZXNcIik7XG59XG5cbi8qKlxuICogV2hlcmUgdGhlIHRhcmdldCdzIGBAaW1nL3NoYXJwLSpgIGJpbmFyaWVzIGdvOiBgPHJvb3Q+L25vZGVfbW9kdWxlcy9AaW1nYC5cbiAqXG4gKiBOb3QgbmV4dCB0byB0aGUgc3RhZ2VkIGBzaGFycGAgcGFja2FnZS4gVW5kZXIgcG5wbSB0aGF0IGlzXG4gKiBgbm9kZV9tb2R1bGVzLy5wbnBtL3NoYXJwQHgvbm9kZV9tb2R1bGVzL0BpbWdgLCB3aGljaCBvbmx5IHRoZSBzdG9yZSBjb3B5IG9mXG4gKiBgc2hhcnBgIHJlc29sdmVzIGZyb206IGEgZGVyZWZlcmVuY2VkIGxpbmsgdG8gYHNoYXJwYCAoYSBjb3B5IGF0XG4gKiBgYXBwL25vZGVfbW9kdWxlcy9zaGFycGAsIHNheSkgbG9va3MgZm9yIGBAaW1nYCBmcm9tIGl0cyBvd24gcGF0aCBhbmQgd2Fsa3NcbiAqIHVwLCBuZXZlciBpbnRvIHRoZSBzdG9yZS4gQm90aCB0aGUgRnVuY3Rpb25zIHppcCAoYHppcERpcmVjdG9yeWApIGFuZCB0aGVcbiAqIENvbnRhaW5lcnMgYENPUFlgIGtlZXAgdGhlIGxpbmtzLCBzbyBpdCBpcyB0aGUgc3RvcmUgY29weSB0aGF0IGxvYWRzLCBhbmQgaXRzXG4gKiB3YWxrIHVwIHJlYWNoZXMgdGhlIHJvb3QgYG5vZGVfbW9kdWxlc2AgdG9vLCBzbyBpdCBzZXJ2ZXMgZWl0aGVyIGxheW91dC4gSXRcbiAqIGlzIGFsc28gd2hlcmUgbWFpbiBpbnN0YWxsZWQgdGhlbS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNoYXJwQmluYXJ5RGlyKHJvb3Q6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBqb2luKHJvb3QsIFwibm9kZV9tb2R1bGVzXCIsIFwiQGltZ1wiKTtcbn1cblxuLyoqXG4gKiBFdmVyeSBlbnRyeSB1bmRlciBgcm9vdGAsIGxpbmtzIGxpc3RlZCBidXQgbm90IGZvbGxvd2VkLlxuICpcbiAqIEFuIGV4cGxpY2l0IHdhbGsgcmF0aGVyIHRoYW4gYHJlYWRkaXJTeW5jKHsgcmVjdXJzaXZlOiB0cnVlIH0pYCwgd2hpY2ggb25cbiAqIE5vZGUgMjQgZGVzY2VuZHMgaW50byBzeW1saW5rZWQgZGlyZWN0b3JpZXMgaXRzZWxmIGFuZCBzbyBuZXZlciByZXR1cm5zIG9uIGFcbiAqIGN5Y2xlIOKAlCB0d28gd29ya3NwYWNlIHBhY2thZ2VzIHRoYXQgbGluayBlYWNoIG90aGVyLCB3aGljaCBpcyBob3cgcG5wbSB3aXJlcyBhXG4gKiBtb25vcmVwby5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3RUcmVlKHJvb3Q6IHN0cmluZyk6IERpcmVudFtdIHtcbiAgY29uc3QgZW50cmllczogRGlyZW50W10gPSBbXTtcbiAgY29uc3QgcGVuZGluZyA9IFtyb290XTtcbiAgZm9yIChsZXQgZGlyID0gcGVuZGluZy5wb3AoKTsgZGlyICE9PSB1bmRlZmluZWQ7IGRpciA9IHBlbmRpbmcucG9wKCkpIHtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIHJlYWRkaXJTeW5jKGRpciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pKSB7XG4gICAgICBlbnRyaWVzLnB1c2goZW50cnkpO1xuICAgICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgcGVuZGluZy5wdXNoKGpvaW4oZGlyLCBlbnRyeS5uYW1lKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBlbnRyaWVzO1xufVxuXG4vKipcbiAqIFdyaXRlIHtAbGluayBQVUJMSUNfRklMRVNfRklMRV9OQU1FfSBpbnRvIGEgZGVwbG95bWVudCByb290J3MgcnVudGltZVxuICogZGlyZWN0b3J5OiBldmVyeSBmaWxlIHVuZGVyIGBwdWJsaWNEaXJgLCBsaXN0ZWQgdGhlIHdheSB0aGUgcnVudGltZSB3b3VsZFxuICogbGlzdCBpdCBvZmYgZGlzayAoYHJlYWRQdWJsaWNGaWxlc2A6IHN5bWxpbmtzIGZvbGxvd2VkLCBgL2Atc2VwYXJhdGVkLFxuICogc29ydGVkKS4gQW4gYXBwIHdpdGhvdXQgYHB1YmxpYy9gIGdldHMgYFtdYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdyaXRlUHVibGljRmlsZUxpc3QocnVudGltZURpcjogc3RyaW5nLCBwdWJsaWNEaXI6IHN0cmluZykge1xuICB3cml0ZUZpbGVTeW5jKFxuICAgIGpvaW4ocnVudGltZURpciwgUFVCTElDX0ZJTEVTX0ZJTEVfTkFNRSksXG4gICAgSlNPTi5zdHJpbmdpZnkocmVhZFB1YmxpY0ZpbGVzKHB1YmxpY0RpcikpLFxuICApO1xufVxuXG4vKipcbiAqIFRvdGFsIGJ5dGVzIG9mIGEgdHJlZSBhcyBpdHMgZGVwbG95bWVudCB6aXAgc3RvcmVzIGl0LiBgemlwRGlyZWN0b3J5YCBrZWVwc1xuICogbGlua3MgYXMgbGlua3MsIHNvIGVhY2ggY291bnRzIGFzIGl0cyB0YXJnZXQgcGF0aCwgbm90IGFzIHRoZSB0YXJnZXQsIHdoaWNoXG4gKiBpcyB3YWxrZWQgYXQgaXRzIG93biBwYXRoIGFueXdheSAoZXZlcnkgbGluayBpbiBhIHN0YWdlZCByb290IHBvaW50cyBpbnNpZGVcbiAqIGl0KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0b3JlZFNpemUocm9vdDogc3RyaW5nKTogbnVtYmVyIHtcbiAgbGV0IGJ5dGVzID0gMDtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBsaXN0VHJlZShyb290KSkge1xuICAgIGlmICghZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgYnl0ZXMgKz0gbHN0YXRTeW5jKGpvaW4oZW50cnkucGFyZW50UGF0aCwgZW50cnkubmFtZSkpLnNpemU7XG4gICAgfVxuICB9XG4gIHJldHVybiBieXRlcztcbn1cblxuLyoqXG4gKiBgY2h1bmtgIHdpdGggYHBhdGNoYCBwcmVwZW5kZWQgYmV0d2VlbiBgUEFUQ0hfRkVUQ0hfTUFSS0VSYCBhbmRcbiAqIGBQQVRDSF9GRVRDSF9FTkRfTUFSS0VSYCwgb3IgYHVuZGVmaW5lZGAgd2hlbiBpdCBhbHJlYWR5IGNhcnJpZXMgdGhpcyBleGFjdFxuICogcGF0Y2guXG4gKlxuICogVGhlIG9wZW5pbmcgbWFya2VyIGNhcnJpZXMgYSBoYXNoIG9mIHRoZSBwYXRjaCwgc28gYSBjaHVuayBwYXRjaGVkIGJ5IGFcbiAqIGNkay1uZXh0anMgd2hvc2UgYHBhdGNoLWZldGNoLmpzYCBkaWZmZXJzIChhbiB1cGdyYWRlLCBvdmVyIGEgYC5uZXh0YCByZXVzZWRcbiAqIHdpdGggYHNraXBCdWlsZDogdHJ1ZWApIGlzIG5vdCBtaXN0YWtlbiBmb3IgY3VycmVudDogdGhlIG9sZCBwYXRjaCBpcyBjdXQgb2ZmXG4gKiBhdCBpdHMgZW5kIG1hcmtlciBhbmQgdGhpcyBvbmUgcHV0IGluIGl0cyBwbGFjZSwgcmF0aGVyIHRoYW4gdGhlIG9sZCBvbmVcbiAqIHNoaXBwaW5nIG9yIGJvdGggc3RhY2tpbmcgdXAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXRjaENsaWVudENodW5rKFxuICBjaHVuazogc3RyaW5nLFxuICBwYXRjaDogc3RyaW5nLFxuICBjaHVua1BhdGg6IHN0cmluZyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGhhc2ggPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShwYXRjaCkuZGlnZXN0KFwiaGV4XCIpLnNsaWNlKDAsIDE2KTtcbiAgY29uc3Qgb3BlbiA9IGAke1BBVENIX0ZFVENIX01BUktFUn0gJHtoYXNofSAqL2A7XG4gIGlmIChjaHVuay5zdGFydHNXaXRoKGAke29wZW59XFxuYCkpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGxldCBvcmlnaW5hbCA9IGNodW5rO1xuICBpZiAoY2h1bmsuc3RhcnRzV2l0aChQQVRDSF9GRVRDSF9NQVJLRVIpKSB7XG4gICAgY29uc3QgZW5kID0gY2h1bmsuaW5kZXhPZihgXFxuJHtQQVRDSF9GRVRDSF9FTkRfTUFSS0VSfVxcbmApO1xuICAgIGlmIChlbmQgPT09IC0xKSB7XG4gICAgICAvLyBPbmx5IGEgcHJlLXJlbGVhc2UgY2RrLW5leHRqcyB3cm90ZSB0aGUgbWFya2VyIHdpdGhvdXQgYW4gZW5kLCBhbmRcbiAgICAgIC8vIHdoZXJlIGl0cyBwYXRjaCBzdG9wcyBjYW5ub3QgYmUgdG9sZCBmcm9tIHRoZSBjaHVuaydzIG93biBjb2RlLlxuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSAke2NodW5rUGF0aH0gY2FycmllcyBhIGNkay1uZXh0anMgZmV0Y2ggcGF0Y2ggdGhpcyBgICtcbiAgICAgICAgICBgdmVyc2lvbiBjYW5ub3QgcmVwbGFjZS4gUmUtcnVuIFxcYG5leHQgYnVpbGRcXGAgdG8gcmVnZW5lcmF0ZSBpdC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgb3JpZ2luYWwgPSBjaHVuay5zbGljZShlbmQgKyBQQVRDSF9GRVRDSF9FTkRfTUFSS0VSLmxlbmd0aCArIDIpO1xuICB9XG4gIHJldHVybiBgJHtvcGVufVxcbiR7cGF0Y2h9XFxuJHtQQVRDSF9GRVRDSF9FTkRfTUFSS0VSfVxcbiR7b3JpZ2luYWx9YDtcbn1cbiJdfQ==
|