cdk-nextjs 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1551 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +857 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +863 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +13 -5
- package/lib/nextjs-post-deploy.js +13 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1216 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1686 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41600 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +71 -0
- package/lib/runtime/next-modules.js +144 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41593 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
|
@@ -0,0 +1,857 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeBuildOutputs = writeBuildOutputs;
|
|
4
|
+
exports.buildAdapterManifest = buildAdapterManifest;
|
|
5
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_module_1 = require("node:module");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const function_groups_1 = require("./function-groups");
|
|
11
|
+
const constants_1 = require("../constants");
|
|
12
|
+
const manifest_1 = require("../runtime/manifest");
|
|
13
|
+
/**
|
|
14
|
+
* Env files `writeStandaloneDirectory` copies into the standalone tree and that
|
|
15
|
+
* `onBuildComplete` has no equivalent for. Dropping `output: "standalone"`
|
|
16
|
+
* silently drops these unless we stage them ourselves.
|
|
17
|
+
* @see https://nextjs.org/docs/app/api-reference/config/next-config-js/output
|
|
18
|
+
*/
|
|
19
|
+
const ENV_FILES = [".env", ".env.production"];
|
|
20
|
+
/**
|
|
21
|
+
* `next` submodules the *runtime* requires that no app ever reaches, so
|
|
22
|
+
* `next build`'s own trace never covers them. They are required from the app's
|
|
23
|
+
* `next` rather than bundled, deliberately — see `src/runtime/next-modules.ts`
|
|
24
|
+
* — which makes staging their closure this module's job.
|
|
25
|
+
*
|
|
26
|
+
* `serve-static` is in every group: `serveStaticFile`
|
|
27
|
+
* (`src/runtime/static-files.ts`) serves prerendered and static results with it
|
|
28
|
+
* wherever they land. `instrumentation-globals` is required by `loadRuntime`
|
|
29
|
+
* on every cold start (`registerInstrumentation`), so it is staged here rather
|
|
30
|
+
* than trusted to each group's entrypoint trace.
|
|
31
|
+
*/
|
|
32
|
+
const RUNTIME_NEXT_MODULES = [
|
|
33
|
+
"next/dist/server/serve-static.js",
|
|
34
|
+
"next/dist/server/lib/router-utils/instrumentation-globals.external.js",
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* next's image optimizer and the config helpers around it
|
|
38
|
+
* (`src/runtime/image.ts`), whose closure is what brings `sharp` in. Only the
|
|
39
|
+
* `default` group gets them: the edge sends every `/_next/image` request there.
|
|
40
|
+
*/
|
|
41
|
+
const IMAGE_NEXT_MODULES = [
|
|
42
|
+
"next/dist/server/config-shared.js",
|
|
43
|
+
"next/dist/shared/lib/image-config.js",
|
|
44
|
+
"next/dist/server/image-optimizer.js",
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* The file tracer `next build` itself uses, reached through the app's own `next`
|
|
48
|
+
* so that it is the version that matches the files being traced. Not a
|
|
49
|
+
* dependency of cdk-nextjs: bundling a second copy of `@vercel/nft` into the
|
|
50
|
+
* published adapter would add megabytes to every install to do the same job.
|
|
51
|
+
*/
|
|
52
|
+
const NEXT_FILE_TRACER = "next/dist/compiled/@vercel/nft";
|
|
53
|
+
/**
|
|
54
|
+
* Build the manifest and staging plan, stage the files, and write the manifest.
|
|
55
|
+
* Called from `onBuildComplete`, which is the only place that holds the build
|
|
56
|
+
* outputs.
|
|
57
|
+
*/
|
|
58
|
+
async function writeBuildOutputs(ctx, options = {}) {
|
|
59
|
+
const adapterDir = (0, node_path_1.join)(ctx.distDir, manifest_1.ADAPTER_DIR_NAME);
|
|
60
|
+
const manifestPath = (0, node_path_1.join)(adapterDir, manifest_1.MANIFEST_FILE_NAME);
|
|
61
|
+
const { manifest, groups } = buildAdapterManifest(ctx, options);
|
|
62
|
+
// Traced once, here: the trace is async, which is why it cannot happen inside
|
|
63
|
+
// `buildAdapterManifest`. `runtimeClosure` is merged into every group, and
|
|
64
|
+
// `imageClosure` into `default` only, the one group `/_next/image` reaches.
|
|
65
|
+
const runtimeClosure = new Map();
|
|
66
|
+
const imageClosure = new Map();
|
|
67
|
+
await addRuntimeNextClosure(ctx, runtimeClosure, imageClosure);
|
|
68
|
+
addRequiredServerFiles(ctx, runtimeClosure);
|
|
69
|
+
// A previous build's tree is never additive with this one's: a removed route
|
|
70
|
+
// leaves behind an entrypoint the manifest no longer mentions, a renamed chunk
|
|
71
|
+
// leaves dead bytes inside the 250 MB budget, and a regrouped build leaves a
|
|
72
|
+
// whole deployment root nothing deploys.
|
|
73
|
+
await (0, promises_1.rm)(adapterDir, { recursive: true, force: true });
|
|
74
|
+
const stagedGroups = [];
|
|
75
|
+
for (const group of groups) {
|
|
76
|
+
const groupStaging = merged(merged(group.staging, runtimeClosure), group.name === function_groups_1.DEFAULT_FUNCTION_GROUP ? imageClosure : new Map());
|
|
77
|
+
const path = (0, node_path_1.join)(adapterDir, ...group.dirName.split("/"));
|
|
78
|
+
await (0, promises_1.mkdir)(path, { recursive: true });
|
|
79
|
+
await stageFiles(groupStaging, path);
|
|
80
|
+
stagedGroups.push({ name: group.name, path, fileCount: groupStaging.size });
|
|
81
|
+
}
|
|
82
|
+
await (0, promises_1.writeFile)(manifestPath, JSON.stringify(manifest, null, 2));
|
|
83
|
+
return {
|
|
84
|
+
manifest,
|
|
85
|
+
groups,
|
|
86
|
+
adapterDir,
|
|
87
|
+
manifestPath,
|
|
88
|
+
stagedGroups,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Left wins, as everywhere else in this module: first writer of a key keeps it. */
|
|
92
|
+
function merged(base, additions) {
|
|
93
|
+
const result = new Map(base);
|
|
94
|
+
for (const [key, source] of additions) {
|
|
95
|
+
if (!result.has(key)) {
|
|
96
|
+
result.set(key, source);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The pure half of {@link writeBuildOutputs}: everything derived from the build
|
|
103
|
+
* outputs, with no writes. Split out so it can be unit tested against committed
|
|
104
|
+
* `onBuildComplete` fixtures.
|
|
105
|
+
*
|
|
106
|
+
* Throws on any non-Node output and on any staging key two outputs map to
|
|
107
|
+
* different content.
|
|
108
|
+
*/
|
|
109
|
+
function buildAdapterManifest(ctx, options = {}) {
|
|
110
|
+
const { outputs, repoRoot } = ctx;
|
|
111
|
+
const basePath = ctx.config.basePath || "";
|
|
112
|
+
assertBuildCwd(ctx, options.buildCwd ?? process.cwd());
|
|
113
|
+
const invocable = [
|
|
114
|
+
...outputs.pages,
|
|
115
|
+
...outputs.pagesApi,
|
|
116
|
+
...outputs.appPages,
|
|
117
|
+
...outputs.appRoutes,
|
|
118
|
+
...(outputs.middleware ? [outputs.middleware] : []),
|
|
119
|
+
];
|
|
120
|
+
assertNodeRuntimes(invocable, outputs.middleware);
|
|
121
|
+
warnOnDroppedRouteConfig(invocable);
|
|
122
|
+
const staticFiles = collectStaticFiles(ctx);
|
|
123
|
+
const entrypoints = {};
|
|
124
|
+
for (const { outputs: group, type } of [
|
|
125
|
+
{ outputs: outputs.pages, type: "page" },
|
|
126
|
+
{ outputs: outputs.pagesApi, type: "page-api" },
|
|
127
|
+
{ outputs: outputs.appPages, type: "app-page" },
|
|
128
|
+
{ outputs: outputs.appRoutes, type: "app-route" },
|
|
129
|
+
]) {
|
|
130
|
+
for (const output of group) {
|
|
131
|
+
addEntrypoint(entrypoints, repoRoot, output, type, basePath);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
addPrerenderPathnames(entrypoints, outputs.prerenders, ctx.routing.dynamicRoutes, basePath, `${basePath}/_next/data/${ctx.buildId}/`);
|
|
135
|
+
const pathnames = sortedUnique([
|
|
136
|
+
...Object.keys(entrypoints),
|
|
137
|
+
...Object.keys(staticFiles),
|
|
138
|
+
]);
|
|
139
|
+
const functionGroups = options.functionGroups ??
|
|
140
|
+
(0, function_groups_1.parseFunctionGroupsEnv)(process.env[function_groups_1.FUNCTION_GROUPS_ENV_VAR]);
|
|
141
|
+
// i18n is checked first: it rejects the combination outright, and running it
|
|
142
|
+
// after the assignment meant an i18n app got the assignment's "pattern matches
|
|
143
|
+
// no route" error instead — true, but about the wrong thing, since a localized
|
|
144
|
+
// template never matches an unlocalized pattern.
|
|
145
|
+
if (functionGroups) {
|
|
146
|
+
(0, function_groups_1.assertNoI18nSplitting)(ctx.config.i18n ?? null);
|
|
147
|
+
}
|
|
148
|
+
const assignment = functionGroups
|
|
149
|
+
? (0, function_groups_1.assignRoutesToGroups)(functionGroups,
|
|
150
|
+
// Keyed on the file, not the output `id`: a Pages Router page and its
|
|
151
|
+
// `/_next/data/<buildId>/<page>.json` route are separate outputs with
|
|
152
|
+
// separate ids backed by one file, and only the page's template matches
|
|
153
|
+
// a group pattern.
|
|
154
|
+
Object.entries(entrypoints).map(([template, entrypoint]) => ({
|
|
155
|
+
template,
|
|
156
|
+
entrypointId: entrypoint.filePath,
|
|
157
|
+
type: entrypoint.type,
|
|
158
|
+
})), {
|
|
159
|
+
basePath: ctx.config.basePath || "",
|
|
160
|
+
buildId: ctx.buildId,
|
|
161
|
+
trailingSlash: ctx.config.trailingSlash === true,
|
|
162
|
+
routing: ctx.routing,
|
|
163
|
+
})
|
|
164
|
+
: undefined;
|
|
165
|
+
const manifest = {
|
|
166
|
+
version: manifest_1.ADAPTER_MANIFEST_VERSION,
|
|
167
|
+
buildId: ctx.buildId,
|
|
168
|
+
relativeProjectDir: toPosix((0, node_path_1.relative)(repoRoot, ctx.projectDir)),
|
|
169
|
+
config: {
|
|
170
|
+
basePath: ctx.config.basePath || "",
|
|
171
|
+
trailingSlash: ctx.config.trailingSlash === true,
|
|
172
|
+
assetPrefix: ctx.config.assetPrefix || "",
|
|
173
|
+
distDir: toPosix((0, node_path_1.relative)(ctx.projectDir, ctx.distDir)),
|
|
174
|
+
compress: ctx.config.compress !== false,
|
|
175
|
+
generateEtags: ctx.config.generateEtags !== false,
|
|
176
|
+
i18n: ctx.config.i18n ?? null,
|
|
177
|
+
deploymentId: (ctx.config.deploymentId ?? "").replace(/[^A-Za-z0-9_-]/g, "-"),
|
|
178
|
+
},
|
|
179
|
+
routing: ctx.routing,
|
|
180
|
+
pathnames,
|
|
181
|
+
entrypoints,
|
|
182
|
+
middleware: buildMiddleware(repoRoot, outputs.middleware),
|
|
183
|
+
staticFiles,
|
|
184
|
+
...(assignment
|
|
185
|
+
? {
|
|
186
|
+
groups: assignment.templates,
|
|
187
|
+
behaviors: assignment.behaviors,
|
|
188
|
+
functionGroups: functionGroups.map(({ name, routes }) => ({
|
|
189
|
+
name,
|
|
190
|
+
routes,
|
|
191
|
+
})),
|
|
192
|
+
}
|
|
193
|
+
: {}),
|
|
194
|
+
};
|
|
195
|
+
const groups = assignment
|
|
196
|
+
? Object.entries(assignment.templates).map(([name, templates]) => ({
|
|
197
|
+
name,
|
|
198
|
+
dirName: (0, manifest_1.groupStagingDirName)(name),
|
|
199
|
+
staging: collectGroupStagingPlan(ctx, invocable, entrypoints, templates),
|
|
200
|
+
}))
|
|
201
|
+
: [
|
|
202
|
+
{
|
|
203
|
+
name: function_groups_1.DEFAULT_FUNCTION_GROUP,
|
|
204
|
+
dirName: (0, manifest_1.groupStagingDirName)(),
|
|
205
|
+
staging: servedStagingPlan(ctx, invocable),
|
|
206
|
+
},
|
|
207
|
+
];
|
|
208
|
+
return { manifest, groups };
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* One group's slice of the staging plan: the assets of the outputs it owns, and
|
|
212
|
+
* nothing else.
|
|
213
|
+
*
|
|
214
|
+
* Middleware is in every group, not just the default one — it runs on every
|
|
215
|
+
* request wherever that request lands, so it is duplicated by design, as is the
|
|
216
|
+
* `next` closure the entrypoints share. The same goes for the static files the
|
|
217
|
+
* runtime serves itself (`404.html`, `favicon.ico.body`): any group can be asked
|
|
218
|
+
* for them. And so are the not-found and error pages: the runtime renders a
|
|
219
|
+
* 404 or a 500 with whichever of them the shared manifest names
|
|
220
|
+
* (`statusTargets` in `runtime/dispatch.ts`), in whichever group the
|
|
221
|
+
* request reached, so a group without them answered a URL under its own
|
|
222
|
+
* pattern that matches no route with "the deployment package is incomplete".
|
|
223
|
+
*
|
|
224
|
+
* Ownership is matched on the entrypoint's `filePath`, not its `id` or
|
|
225
|
+
* pathname: the manifest's entrypoints are keyed by *template*, an output may
|
|
226
|
+
* back several templates, and {@link addPrerenderPathnames} synthesizes
|
|
227
|
+
* entrypoints that carry the *prerender's* id, which no invocable output has (the
|
|
228
|
+
* root-params app: entrypoint `/en` with `id: "/en"` backed by the output
|
|
229
|
+
* `/[locale]`). The synthesized entrypoint's `filePath` is the owning output's.
|
|
230
|
+
*/
|
|
231
|
+
function collectGroupStagingPlan(ctx, invocable, entrypoints, templates) {
|
|
232
|
+
const basePath = ctx.config.basePath || "";
|
|
233
|
+
const ownedEntrypoints = [
|
|
234
|
+
...templates,
|
|
235
|
+
...manifest_1.ERROR_PAGE_SUFFIXES.map((suffix) => `${basePath}${suffix}`),
|
|
236
|
+
]
|
|
237
|
+
.map((template) => entrypoints[template])
|
|
238
|
+
.filter((entry) => entry !== undefined);
|
|
239
|
+
const ownedFiles = new Set(ownedEntrypoints.map((entry) => entry.filePath));
|
|
240
|
+
const middleware = ctx.outputs.middleware;
|
|
241
|
+
const owned = invocable.filter((output) => ownedFiles.has(toPosix((0, node_path_1.relative)(ctx.repoRoot, output.filePath))) ||
|
|
242
|
+
output === middleware);
|
|
243
|
+
return servedStagingPlan(ctx, owned);
|
|
244
|
+
}
|
|
245
|
+
/** {@link collectStagingPlan} for `outputs`, plus the files the runtime serves. */
|
|
246
|
+
function servedStagingPlan(ctx, outputs) {
|
|
247
|
+
const staging = collectStagingPlan(ctx, outputs);
|
|
248
|
+
stageServedStaticFiles(ctx, staging);
|
|
249
|
+
return staging;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Job 1: reject non-Node outputs, everywhere.
|
|
253
|
+
*
|
|
254
|
+
* `export const runtime = 'edge'` on a page or route handler lands in
|
|
255
|
+
* `appPages`/`appRoutes`/`pages`/`pagesApi` with `runtime: 'edge'`,
|
|
256
|
+
* `assets: {}`, and an `edgeRuntime` descriptor needing `globalThis._ENTRIES`
|
|
257
|
+
* and a sandbox. Guarding middleware alone would leave a silent failure mode
|
|
258
|
+
* for edge pages: an entrypoint we can't invoke and no assets to invoke it
|
|
259
|
+
* with.
|
|
260
|
+
*/
|
|
261
|
+
function assertNodeRuntimes(invocable, middleware) {
|
|
262
|
+
const offending = invocable.filter((output) => output.runtime !== "nodejs");
|
|
263
|
+
if (offending.length === 0) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// Middleware is reported separately from routes. Its `sourcePage` is `/`, so
|
|
267
|
+
// folding it in with the routes produces the actively misleading advice to
|
|
268
|
+
// remove `export const runtime = "edge"` from the home page - which is where
|
|
269
|
+
// the edge runtime is not, and may not even exist.
|
|
270
|
+
const offendingMiddleware = middleware && offending.includes(middleware);
|
|
271
|
+
// `.rsc` variants share a `sourcePage` with their HTML sibling, so dedupe.
|
|
272
|
+
const routes = sortedUnique(offending
|
|
273
|
+
.filter((output) => output !== middleware)
|
|
274
|
+
.map((output) => `${output.sourcePage} (runtime: "${output.runtime}")`));
|
|
275
|
+
const reasons = [];
|
|
276
|
+
if (routes.length > 0) {
|
|
277
|
+
reasons.push(`cdk-nextjs cannot deploy routes built for the edge runtime. ` +
|
|
278
|
+
`Remove \`export const runtime = "edge"\` from:\n` +
|
|
279
|
+
routes.map((route) => ` - ${route}`).join("\n"));
|
|
280
|
+
}
|
|
281
|
+
if (offendingMiddleware) {
|
|
282
|
+
reasons.push(`cdk-nextjs cannot deploy middleware built for the edge runtime ` +
|
|
283
|
+
`(${middleware.filePath}, runtime: "${middleware.runtime}"). ` +
|
|
284
|
+
`Rename it to \`proxy.ts\` (Next.js 16 runs proxy on the Node ` +
|
|
285
|
+
`runtime), or keep \`middleware.ts\` and add ` +
|
|
286
|
+
`\`export const config = { runtime: "nodejs" }\` to it — ` +
|
|
287
|
+
`\`middleware.ts\` defaults to the edge runtime, but does not require it.`);
|
|
288
|
+
}
|
|
289
|
+
throw new Error(`${constants_1.LOG_PREFIX} ${reasons.join("\n")}\n` +
|
|
290
|
+
`The edge runtime is deprecated in Next.js: ` +
|
|
291
|
+
`https://nextjs.org/docs/messages/edge-runtime-deprecated`);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Warn on route config cdk-nextjs does not honor. An author who set these asked
|
|
295
|
+
* for something explicitly, so say so rather than ignoring it silently; never
|
|
296
|
+
* throw, because route-level `maxDuration` is valid Next.js.
|
|
297
|
+
*
|
|
298
|
+
* `NextjsBuild` runs `next build` with `stdio: "inherit"`, so this reaches the
|
|
299
|
+
* user's terminal. See the plan's "Decisions" for why neither is honored.
|
|
300
|
+
*/
|
|
301
|
+
function warnOnDroppedRouteConfig(invocable) {
|
|
302
|
+
const dropped = {
|
|
303
|
+
maxDuration: [],
|
|
304
|
+
preferredRegion: [],
|
|
305
|
+
};
|
|
306
|
+
for (const output of invocable) {
|
|
307
|
+
if (output.config?.maxDuration !== undefined) {
|
|
308
|
+
dropped.maxDuration.push(output.sourcePage);
|
|
309
|
+
}
|
|
310
|
+
if (output.config?.preferredRegion !== undefined) {
|
|
311
|
+
dropped.preferredRegion.push(output.sourcePage);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
const remedy = {
|
|
315
|
+
maxDuration: "Set the function timeout with the construct's `overrides` prop instead (e.g. `overrides: { nextjsFunctions: { functionProps: { timeout: Duration.seconds(30) } } }`); a Lambda timeout is per-function while `maxDuration` is per-route.",
|
|
316
|
+
preferredRegion: "Honoring it would require a multi-region deployment, which this construct does not model.",
|
|
317
|
+
};
|
|
318
|
+
for (const key of ["maxDuration", "preferredRegion"]) {
|
|
319
|
+
const routes = sortedUnique(dropped[key]);
|
|
320
|
+
if (routes.length === 0) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
console.warn(`${constants_1.LOG_PREFIX} \`${key}\` is not honored by cdk-nextjs. ` +
|
|
324
|
+
`${routes.length} route(s) set it, including: ${routes.slice(0, 5).join(", ")}` +
|
|
325
|
+
`${routes.length > 5 ? `, and ${routes.length - 5} more` : ""}. ` +
|
|
326
|
+
remedy[key]);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Jobs 2, 3 and 6: the deduped union of every shipped output's traced `assets`,
|
|
331
|
+
* plus each entrypoint file itself, plus the env files, with `assetsHashes` used
|
|
332
|
+
* as a conflict check.
|
|
333
|
+
*
|
|
334
|
+
* Dedup is by key: the traced `next` closure is merged into every output's
|
|
335
|
+
* `assets` (`getSharedNodeAssets` → `sharedNodeAssets`), so N outputs
|
|
336
|
+
* overwhelmingly repeat keys. What the hashes buy is detecting two outputs
|
|
337
|
+
* mapping the **same key to different content**, which is unpackageable into
|
|
338
|
+
* one Lambda — fail the build loudly rather than letting last-write-wins pick.
|
|
339
|
+
*/
|
|
340
|
+
function collectStagingPlan(ctx, invocable) {
|
|
341
|
+
const { repoRoot } = ctx;
|
|
342
|
+
const staging = new Map();
|
|
343
|
+
const hashes = new Map();
|
|
344
|
+
const add = (key, source, hash) => {
|
|
345
|
+
assertStagingKey(key, source);
|
|
346
|
+
const existingHash = hashes.get(key);
|
|
347
|
+
if (hash !== undefined &&
|
|
348
|
+
existingHash !== undefined &&
|
|
349
|
+
existingHash !== hash) {
|
|
350
|
+
throw new Error(`${constants_1.LOG_PREFIX} Two build outputs map "${key}" to different content ` +
|
|
351
|
+
`(hashes ${existingHash} and ${hash}). One deployment package cannot ` +
|
|
352
|
+
`hold both. This usually means two Next.js projects in the same repo ` +
|
|
353
|
+
`write the same repo-root-relative path.`);
|
|
354
|
+
}
|
|
355
|
+
if (hash !== undefined) {
|
|
356
|
+
hashes.set(key, hash);
|
|
357
|
+
}
|
|
358
|
+
if (!staging.has(key)) {
|
|
359
|
+
staging.set(key, source);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
for (const output of invocable) {
|
|
363
|
+
for (const [key, source] of Object.entries(output.assets)) {
|
|
364
|
+
add(key, source, output.assetsHashes[key]);
|
|
365
|
+
}
|
|
366
|
+
// The entrypoint's own file is deliberately absent from its `assets` — the
|
|
367
|
+
// NFT trace covers the closure it requires, not itself. `assetsHashes` does
|
|
368
|
+
// carry it (keyed the same way), which is also what pins the key format.
|
|
369
|
+
const entryKey = toPosix((0, node_path_1.relative)(repoRoot, output.filePath));
|
|
370
|
+
add(entryKey, output.filePath, output.assetsHashes[entryKey]);
|
|
371
|
+
}
|
|
372
|
+
// Job 2, second half: `writeStandaloneDirectory` filters `loadedEnvFiles` to
|
|
373
|
+
// exactly these two and copies them; `build-complete.js` has no env-file
|
|
374
|
+
// handling at all, so they are not in any `assets` map.
|
|
375
|
+
for (const envFile of ENV_FILES) {
|
|
376
|
+
const source = (0, node_path_1.join)(ctx.projectDir, envFile);
|
|
377
|
+
if ((0, node_fs_1.existsSync)(source)) {
|
|
378
|
+
add(toPosix((0, node_path_1.relative)(repoRoot, source)), source);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return staging;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Job 2, third part: the static files the *runtime* has to serve, and their
|
|
385
|
+
* sources.
|
|
386
|
+
*
|
|
387
|
+
* `outputs.staticFiles` mixes two populations with the same `STATIC_FILE` type:
|
|
388
|
+
*
|
|
389
|
+
* - **`<distDir>/static/**` and `public/**`** — uploaded to S3 by
|
|
390
|
+
* `NextjsStaticAssets`, and CloudFront / API Gateway answer them before the
|
|
391
|
+
* request ever reaches the compute. Not staged: `public/` alone can be
|
|
392
|
+
* hundreds of megabytes against a 250 MB unzipped Lambda cap, and it would be
|
|
393
|
+
* a second copy of bytes already in S3. `public/` is not in
|
|
394
|
+
* `outputs.staticFiles` at all — Next.js lists it only for `output: "export"`
|
|
395
|
+
* — and it is deliberately not added here: the container runtime lists it off
|
|
396
|
+
* disk at cold start instead, as `next start` does (`readPublicFiles` in
|
|
397
|
+
* `src/runtime/public-files.ts`), because only the disk knows what an app's
|
|
398
|
+
* `postbuild` wrote into it after this hook ran.
|
|
399
|
+
* - **everything else**, all of it under `<distDir>/server/` — `404.html`,
|
|
400
|
+
* `500.html`, `favicon.ico.body`, and fully-static Pages Router HTML. Nothing
|
|
401
|
+
* in front of the compute serves these, so they are staged. Bounded by route
|
|
402
|
+
* count and small.
|
|
403
|
+
*
|
|
404
|
+
* The pathname → key map is returned for *all* of them, because dispatch has to
|
|
405
|
+
* resolve a pathname to "static file, not a 404" either way; the runtime 404s if
|
|
406
|
+
* the file turns out not to be in the package, which is only reachable when the
|
|
407
|
+
* distribution is misrouted.
|
|
408
|
+
*
|
|
409
|
+
* Staging is {@link stageServedStaticFiles}, applied once per deployment root.
|
|
410
|
+
*/
|
|
411
|
+
function collectStaticFiles(ctx) {
|
|
412
|
+
const { repoRoot } = ctx;
|
|
413
|
+
const basePath = ctx.config.basePath || "";
|
|
414
|
+
const staticFiles = new Map();
|
|
415
|
+
const pagesDir = (0, node_path_1.join)(ctx.distDir, "server", "pages") + node_path_1.sep;
|
|
416
|
+
for (const output of ctx.outputs.staticFiles) {
|
|
417
|
+
const key = toPosix((0, node_path_1.relative)(repoRoot, output.filePath));
|
|
418
|
+
const pathnames = routablePathnames(output.pathname, basePath, output.filePath.startsWith(pagesDir));
|
|
419
|
+
for (const pathname of pathnames) {
|
|
420
|
+
const existing = staticFiles.get(pathname);
|
|
421
|
+
if (existing !== undefined && existing !== key) {
|
|
422
|
+
throw new Error(`${constants_1.LOG_PREFIX} Two static files claim the pathname ` +
|
|
423
|
+
`"${pathname}" ("${existing}" and "${key}"). Dispatch cannot ` +
|
|
424
|
+
`choose between them.`);
|
|
425
|
+
}
|
|
426
|
+
staticFiles.set(pathname, key);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// Sorted because object keys keep insertion order, and a byte-stable
|
|
430
|
+
// `manifest.json` is what keeps it diffable and the CDK asset hash from
|
|
431
|
+
// churning.
|
|
432
|
+
return Object.fromEntries([...staticFiles].sort(([a], [b]) => (a < b ? -1 : 1)));
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* The pathnames an output answers, which for one shape is not the pathname
|
|
436
|
+
* `next build` reported.
|
|
437
|
+
*
|
|
438
|
+
* **A Pages Router home page arrives as `/index`.** The adapter hook derives every
|
|
439
|
+
* Pages pathname with `normalizePagePath(page)`, and `normalizePagePath("/")` is
|
|
440
|
+
* `"/index"` (`next/dist/shared/lib/page-path/normalize-page-path.js`) — for the
|
|
441
|
+
* `PAGES` output of an SSG or SSR home page and for the `STATIC_FILE` of a
|
|
442
|
+
* fully-static one alike. `/index` is not a URL anyone requests, and nothing else
|
|
443
|
+
* in the outputs carries `/` for that page, so without this the home page is in
|
|
444
|
+
* neither `manifest.pathnames` nor `manifest.entrypoints`/`staticFiles`, and every
|
|
445
|
+
* request to `/` 404s while every other page of the same app serves. Measured
|
|
446
|
+
* against next.js's `test/e2e/new-link-behavior` (`/` returned the built-in 404,
|
|
447
|
+
* the six other pages were fine) and `test/e2e/prerender-preview` (the one case
|
|
448
|
+
* that fetches `/` got the 404 page's HTML, the eight that hit API routes passed).
|
|
449
|
+
*
|
|
450
|
+
* Pages Router outputs only, which is what `fromPagesRouter` says. App Router
|
|
451
|
+
* reports its home page as `/` and only the RSC sibling as `/index.rsc`, so an
|
|
452
|
+
* App Router `/index` is `app/index/page.tsx` — a real route at `/index`, and
|
|
453
|
+
* mapping it to `/` made an app with both pages fail the build on a pathname
|
|
454
|
+
* collision, and an app with only the second serve it at `/`. The same goes for
|
|
455
|
+
* a `public/index` file.
|
|
456
|
+
*
|
|
457
|
+
* Both pathnames are registered. `/` because it is the real one; `/index` because
|
|
458
|
+
* next's own minimal mode — the mode our runtime runs in — accepts it, rewriting
|
|
459
|
+
* `req.url` and `x-matched-path` from `/index` to `/` before matching
|
|
460
|
+
* (`base-server.ts`, "in minimal mode"), so dropping it would be a divergence in
|
|
461
|
+
* the other direction.
|
|
462
|
+
*
|
|
463
|
+
* Unambiguous within the Pages Router despite the collision it looks like:
|
|
464
|
+
* `normalizePagePath("/index")` is `"/index/index"`, so a reported `/index` can
|
|
465
|
+
* only have come from the page `/`.
|
|
466
|
+
* The data route of the same page, `/_next/data/<buildId>/index.json`, and an App
|
|
467
|
+
* Router `/index.rsc` are both real URLs and are left alone by the exact match.
|
|
468
|
+
*/
|
|
469
|
+
function routablePathnames(pathname, basePath, fromPagesRouter) {
|
|
470
|
+
if (!fromPagesRouter || pathname !== `${basePath}/index`) {
|
|
471
|
+
return [pathname];
|
|
472
|
+
}
|
|
473
|
+
// `basePath || "/"`, not `${basePath}/`: with `basePath: "/prod"` the home page
|
|
474
|
+
// is `/prod`, which is how the App Router fixtures report theirs.
|
|
475
|
+
return [basePath || "/", pathname];
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Add the static files the *runtime* serves to a staging plan — the "everything
|
|
479
|
+
* else" population described on {@link collectStaticFiles}, all of it under
|
|
480
|
+
* `<distDir>/server/`.
|
|
481
|
+
*
|
|
482
|
+
* Separate from building the manifest's `staticFiles` map because the map is the
|
|
483
|
+
* same for every group while the staging is applied once per deployment root:
|
|
484
|
+
* any group can be asked for `/404`, so every group ships these.
|
|
485
|
+
*/
|
|
486
|
+
function stageServedStaticFiles(ctx, staging) {
|
|
487
|
+
const { repoRoot, distDir } = ctx;
|
|
488
|
+
const clientStaticDir = (0, node_path_1.join)(distDir, "static") + node_path_1.sep;
|
|
489
|
+
for (const output of ctx.outputs.staticFiles) {
|
|
490
|
+
const servedByS3 = output.filePath.startsWith(clientStaticDir) ||
|
|
491
|
+
!output.filePath.startsWith(distDir + node_path_1.sep);
|
|
492
|
+
if (servedByS3) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
const key = toPosix((0, node_path_1.relative)(repoRoot, output.filePath));
|
|
496
|
+
assertStagingKey(key, output.filePath);
|
|
497
|
+
staging.set(key, output.filePath);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* The invariant behind `manifest.relativeProjectDir`: `next build` must run from
|
|
502
|
+
* the project directory.
|
|
503
|
+
*
|
|
504
|
+
* Next inlines `relative(process.cwd(), projectDir)` into every entrypoint
|
|
505
|
+
* (`define-env.js`) and the built code resolves it against the *runtime*
|
|
506
|
+
* `process.cwd()`. Keeping build cwd and project dir equal makes that inlined
|
|
507
|
+
* value `""`, so the runtime only has to `chdir` to the staged project dir. A
|
|
508
|
+
* build run from elsewhere would inline a non-empty relative path — often one
|
|
509
|
+
* pointing outside the staging tree — and every entrypoint would fail to find
|
|
510
|
+
* `required-server-files.json` at runtime with no hint as to why.
|
|
511
|
+
*/
|
|
512
|
+
function assertBuildCwd(ctx, buildCwd) {
|
|
513
|
+
const cwd = (0, node_path_1.resolve)(buildCwd);
|
|
514
|
+
if (cwd === (0, node_path_1.resolve)(ctx.projectDir)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
throw new Error(`${constants_1.LOG_PREFIX} \`next build\` must run from the Next.js project ` +
|
|
518
|
+
`directory. It ran from "${cwd}" with the project at ` +
|
|
519
|
+
`"${ctx.projectDir}". Next.js bakes the relative path between those two ` +
|
|
520
|
+
`into every built entrypoint, and cdk-nextjs cannot reproduce that layout ` +
|
|
521
|
+
`in the deployment package. Change directory first (\`cd ` +
|
|
522
|
+
`${(0, node_path_1.relative)(cwd, ctx.projectDir) || "."} && next build\`) instead of ` +
|
|
523
|
+
`passing the directory as an argument; in a monorepo, run the app's own ` +
|
|
524
|
+
`build script from its directory (e.g. \`pnpm --filter <app> build\`, ` +
|
|
525
|
+
`which runs in the package directory).`);
|
|
526
|
+
}
|
|
527
|
+
function addEntrypoint(entrypoints, repoRoot, output, type, basePath) {
|
|
528
|
+
const filePath = toPosix((0, node_path_1.relative)(repoRoot, output.filePath));
|
|
529
|
+
const pathnames = routablePathnames(output.pathname, basePath, type === "page");
|
|
530
|
+
for (const pathname of pathnames) {
|
|
531
|
+
const existing = entrypoints[pathname];
|
|
532
|
+
if (existing && existing.filePath !== filePath) {
|
|
533
|
+
throw new Error(`${constants_1.LOG_PREFIX} Two build outputs claim the pathname "${pathname}" ` +
|
|
534
|
+
`("${existing.filePath}" and "${filePath}"). Dispatch cannot choose ` +
|
|
535
|
+
`between them.`);
|
|
536
|
+
}
|
|
537
|
+
entrypoints[pathname] = { id: output.id, filePath, type };
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Add the *prerender* pathnames that no invocable output claims and that routing
|
|
542
|
+
* cannot otherwise reach.
|
|
543
|
+
*
|
|
544
|
+
* `resolveRoutes` can only match a pathname present in `manifest.pathnames`, and
|
|
545
|
+
* for a dynamic match it returns the **template** it matched. Routes and static
|
|
546
|
+
* files cover most of that; two shapes they miss:
|
|
547
|
+
*
|
|
548
|
+
* 1. **Templates.** A request for `/_next/data/<buildId>/fr/blog/hello.json` only
|
|
549
|
+
* resolves if `/_next/data/<buildId>/fr/blog/[slug].json` is listed, and that
|
|
550
|
+
* pathname exists solely as a `prerenders` entry.
|
|
551
|
+
* 1b. **A static `getStaticProps` page's data route.** `/_next/data/<buildId>/gsp.json`
|
|
552
|
+
* has no template to match and no rule of its own: `next build` only emits a
|
|
553
|
+
* `dynamicRoutes` rule for a data route when the page is dynamic *or* the app has
|
|
554
|
+
* middleware (`build-complete.ts`, `needsMiddlewareResolveRoutes`, which is also
|
|
555
|
+
* what `routing.shouldNormalizeNextData` reports). Without middleware Next.js
|
|
556
|
+
* expects the platform to serve the data route as an output, by pathname — so a
|
|
557
|
+
* concrete data-route prerender is registered whatever the rules say. Missing it
|
|
558
|
+
* turned every client-side navigation into such a page into a full page load,
|
|
559
|
+
* because the router's `.json` fetch 404'd: measured against
|
|
560
|
+
* `test/e2e/no-page-props`. Only when no *ungated* rule matches, for the reason
|
|
561
|
+
* below — a dynamic page's `/…/blog/hello.json` must keep resolving to its
|
|
562
|
+
* `[slug].json` template, which is where `nxtPslug` comes from.
|
|
563
|
+
* 2. **Concrete pathnames whose dynamic route rule is gated.** A route whose params
|
|
564
|
+
* can never be filled at request time — root params are the case that produced
|
|
565
|
+
* this, `app/[locale]/page.tsx` with `generateStaticParams()` and no
|
|
566
|
+
* `app/layout.tsx` — gets its `dynamicRoutes` rule emitted with a draft-mode
|
|
567
|
+
* `has` on `__prerender_bypass`. Next.js is saying: invoke the function only in
|
|
568
|
+
* draft mode, and otherwise serve the prerender you were handed. Vercel's CDN
|
|
569
|
+
* does that from the output itself; we route the request to the owning
|
|
570
|
+
* entrypoint, which answers it out of the seeded cache. Without this, `/en` is a
|
|
571
|
+
* 404 while `next start` renders it — and so is every `.rsc`/`.segments`
|
|
572
|
+
* variant, which is why a client-side navigation into such an app never
|
|
573
|
+
* completes.
|
|
574
|
+
*
|
|
575
|
+
* A concrete pathname is added only when a gated rule matches it and no ungated
|
|
576
|
+
* one does — the set that would 404 today *and* that routing can still produce.
|
|
577
|
+
* Adding them unconditionally was measured to be actively wrong twice over:
|
|
578
|
+
* `/isr/1` resolves to itself rather than to `/isr/[id]`, losing the `nxtPid`
|
|
579
|
+
* query param the route needs, and pathnames no rule matches at all (a static
|
|
580
|
+
* route's `.segments/…` outputs, which `resolveRoutes` never asks for) are dead
|
|
581
|
+
* manifest weight. Matching mirrors `resolveRoutes`, which is case-insensitive by
|
|
582
|
+
* default.
|
|
583
|
+
*
|
|
584
|
+
* The owning entrypoint comes from `prerender.route`, which is the unprefixed and
|
|
585
|
+
* unlocalized source route (`/blog/[slug]`), hence the basePath-then-bare ladder.
|
|
586
|
+
* Locale variants of one page share a `filePath`, so any locale's entrypoint is
|
|
587
|
+
* the right target. An RSC or segment-prefetch pathname prefers the route's `.rsc`
|
|
588
|
+
* entrypoint, because that is the key `resolveRoutes` resolves such a request to.
|
|
589
|
+
*/
|
|
590
|
+
function addPrerenderPathnames(entrypoints, prerenders, dynamicRoutes, basePath, dataRoutePrefix) {
|
|
591
|
+
const matchers = dynamicRoutes.map((route) => ({
|
|
592
|
+
regex: new RegExp(route.sourceRegex, "i"),
|
|
593
|
+
gated: Boolean(route.has?.length || route.missing?.length),
|
|
594
|
+
}));
|
|
595
|
+
const matchingRules = (pathname) => matchers.filter(({ regex }) => regex.test(pathname));
|
|
596
|
+
const onlyGatedRulesMatch = (pathname) => {
|
|
597
|
+
const matched = matchingRules(pathname);
|
|
598
|
+
return matched.length > 0 && matched.every(({ gated }) => gated);
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* Nothing reaches this pathname at request time: either no rule matches it or
|
|
602
|
+
* every rule that does is gated. The gated half is {@link onlyGatedRulesMatch};
|
|
603
|
+
* the "no rule at all" half only ever holds for a data route, because a page's
|
|
604
|
+
* own pathname is an output.
|
|
605
|
+
*/
|
|
606
|
+
const nothingUngatedMatches = (pathname) => matchingRules(pathname).every(({ gated }) => gated);
|
|
607
|
+
const orphans = [];
|
|
608
|
+
for (const prerender of prerenders) {
|
|
609
|
+
const { pathname } = prerender;
|
|
610
|
+
if (entrypoints[pathname]) {
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
const isTemplate = pathname.includes("[");
|
|
614
|
+
const isDataRoute = pathname.startsWith(dataRoutePrefix) && pathname.endsWith(".json");
|
|
615
|
+
const reachable = isDataRoute
|
|
616
|
+
? nothingUngatedMatches(pathname)
|
|
617
|
+
: onlyGatedRulesMatch(pathname);
|
|
618
|
+
if (!isTemplate && !reachable) {
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
const suffixes = pathname.endsWith(".rsc") ? [".rsc", ""] : [""];
|
|
622
|
+
const owner = suffixes
|
|
623
|
+
.flatMap((suffix) => [
|
|
624
|
+
`${basePath}${prerender.route}${suffix}`,
|
|
625
|
+
`${prerender.route}${suffix}`,
|
|
626
|
+
])
|
|
627
|
+
.map((key) => entrypoints[key])
|
|
628
|
+
.find(Boolean);
|
|
629
|
+
if (!owner) {
|
|
630
|
+
orphans.push(`${pathname} (route: "${prerender.route}")`);
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
entrypoints[pathname] = {
|
|
634
|
+
id: prerender.id,
|
|
635
|
+
filePath: owner.filePath,
|
|
636
|
+
type: owner.type,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
if (orphans.length > 0) {
|
|
640
|
+
// Warn rather than throw: an unmapped pathname degrades one URL shape to a
|
|
641
|
+
// 404, which is what would happen without this function at all. A throw
|
|
642
|
+
// would break the build outright on an output shape a future `next` minor
|
|
643
|
+
// might introduce.
|
|
644
|
+
console.warn(`${constants_1.LOG_PREFIX} ${orphans.length} prerender pathname(s) have no ` +
|
|
645
|
+
`matching route entrypoint and will 404: ` +
|
|
646
|
+
`${orphans.slice(0, 5).join(", ")}` +
|
|
647
|
+
`${orphans.length > 5 ? `, and ${orphans.length - 5} more` : ""}.`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function buildMiddleware(repoRoot, middleware) {
|
|
651
|
+
if (!middleware) {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
// `config.matchers` is deliberately not copied here: it arrives inside
|
|
655
|
+
// `ctx.routing.middlewareMatchers`, which `@next/routing` consumes directly.
|
|
656
|
+
return {
|
|
657
|
+
id: middleware.id,
|
|
658
|
+
filePath: toPosix((0, node_path_1.relative)(repoRoot, middleware.filePath)),
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Copy the staging plan into `stagingDir`.
|
|
663
|
+
*
|
|
664
|
+
* **Symlinks are recreated as symlinks, not dereferenced**, which is what
|
|
665
|
+
* Next.js's own `copyTracedFiles` does (`next/dist/build/utils.js`: `readlink`
|
|
666
|
+
* then `symlink`, with a Windows junction fallback). Under pnpm a traced asset
|
|
667
|
+
* key is frequently a *directory* symlink into the store
|
|
668
|
+
* (`node_modules/.pnpm/next@…/node_modules/react` → `../../react@19.2.3/…`), so
|
|
669
|
+
* `copyFile` fails outright with `ENOTSUP`. Dereferencing instead would triple
|
|
670
|
+
* the tree — `examples/app-playground` measures 32 MB staged versus 96 MB with
|
|
671
|
+
* `du -shL`, against a 250 MB unzipped Lambda cap — because whole packages are
|
|
672
|
+
* reachable through several such links. The link targets are themselves staged
|
|
673
|
+
* keys, so relative links resolve inside the deployment root.
|
|
674
|
+
*
|
|
675
|
+
* Regular files are staged first so that a symlink whose path was already
|
|
676
|
+
* materialized as a real directory is skipped rather than clobbering it.
|
|
677
|
+
*
|
|
678
|
+
* Nothing may dereference them afterwards: the Functions zip keeps them as
|
|
679
|
+
* links (`zipDirectory`), and the Containers `COPY` does too.
|
|
680
|
+
*/
|
|
681
|
+
/** Bounded so a large app doesn't exhaust file descriptors. */
|
|
682
|
+
const STAGING_CONCURRENCY = 32;
|
|
683
|
+
async function stageFiles(staging, stagingDir) {
|
|
684
|
+
const planned = [...staging];
|
|
685
|
+
// Links land by plan index, so the pass below creates them in the plan's
|
|
686
|
+
// order whatever order the workers finished in.
|
|
687
|
+
const links = new Array(planned.length);
|
|
688
|
+
let nextEntry = 0;
|
|
689
|
+
const worker = async () => {
|
|
690
|
+
while (nextEntry < planned.length) {
|
|
691
|
+
const index = nextEntry++;
|
|
692
|
+
const [key, source] = planned[index];
|
|
693
|
+
const linkTarget = await (0, promises_1.readlink)(source).catch(() => null);
|
|
694
|
+
if (linkTarget !== null) {
|
|
695
|
+
links[index] = [key, source, linkTarget];
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const dest = (0, node_path_1.join)(stagingDir, key);
|
|
699
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(dest), { recursive: true });
|
|
700
|
+
await (0, promises_1.copyFile)(source, dest);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
await Promise.all(Array.from({ length: Math.min(STAGING_CONCURRENCY, planned.length) }, worker));
|
|
704
|
+
for (const link of links) {
|
|
705
|
+
if (link === undefined) {
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
const [key, source, linkTarget] = link;
|
|
709
|
+
const dest = (0, node_path_1.join)(stagingDir, key);
|
|
710
|
+
if ((0, node_fs_1.existsSync)(dest)) {
|
|
711
|
+
// Already staged as real content by the pool above; the link would add
|
|
712
|
+
// nothing and would replace a directory we need.
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(dest), { recursive: true });
|
|
716
|
+
const resolved = (0, node_path_1.resolve)((0, node_path_1.dirname)(dest), linkTarget);
|
|
717
|
+
if (resolved === stagingDir || resolved.startsWith(stagingDir + node_path_1.sep)) {
|
|
718
|
+
await (0, promises_1.symlink)(linkTarget, dest);
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
// Points outside the deployment root, so the link would dangle in Lambda.
|
|
722
|
+
// Absolute store paths are the realistic case here.
|
|
723
|
+
await (0, promises_1.cp)(source, dest, { recursive: true, dereference: true });
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Adds {@link RUNTIME_NEXT_MODULES}, `@next/env`, and everything they require to
|
|
729
|
+
* `staging`, and {@link IMAGE_NEXT_MODULES} and theirs to `imageStaging`.
|
|
730
|
+
*
|
|
731
|
+
* Without this the deployment is complete for every route the app has and broken
|
|
732
|
+
* for `/_next/image`: the traced `assets` of a build output cover what the *app*
|
|
733
|
+
* reaches, and an app never reaches next's image optimizer, so
|
|
734
|
+
* `next/dist/server/image-optimizer.js` and its closure are simply absent and
|
|
735
|
+
* every image request 500s with a `MODULE_NOT_FOUND` from `nextModule`.
|
|
736
|
+
*
|
|
737
|
+
* Resolution is anchored inside `ctx.projectDir` for the same reason
|
|
738
|
+
* `useNextFrom` anchors there at runtime: it is the directory whose
|
|
739
|
+
* `node_modules` walk finds the app's `next`. A repo where that resolution fails
|
|
740
|
+
* is not a real `next build` — nothing else would have run — so it warns and
|
|
741
|
+
* continues rather than failing a build for a package it could not have needed.
|
|
742
|
+
* A missing *tracer* is different: `next` is right there and image optimization
|
|
743
|
+
* would silently 500 in production, so that throws.
|
|
744
|
+
*/
|
|
745
|
+
async function addRuntimeNextClosure(ctx, staging, imageStaging) {
|
|
746
|
+
// The anchor file needn't exist; `createRequire` only reads its directory.
|
|
747
|
+
const nextRequire = (0, node_module_1.createRequire)((0, node_path_1.join)(ctx.projectDir, "cdk-nextjs-next-resolver.cjs"));
|
|
748
|
+
let entries;
|
|
749
|
+
let imageEntries;
|
|
750
|
+
try {
|
|
751
|
+
entries = RUNTIME_NEXT_MODULES.map((specifier) => nextRequire.resolve(specifier));
|
|
752
|
+
imageEntries = IMAGE_NEXT_MODULES.map((specifier) => nextRequire.resolve(specifier));
|
|
753
|
+
}
|
|
754
|
+
catch (cause) {
|
|
755
|
+
console.warn(`${constants_1.LOG_PREFIX} Could not resolve next's image optimizer from ` +
|
|
756
|
+
`"${ctx.projectDir}" (${cause.message}). Requests to ` +
|
|
757
|
+
`/_next/image will fail at runtime.`);
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
// `loadEnvFiles` (runtime `next-modules.ts`) loads the staged env files with
|
|
761
|
+
// `@next/env`, which is `next`'s dependency, so resolved from `next`'s dir.
|
|
762
|
+
// An app never requires it, so no output's trace has it either.
|
|
763
|
+
const nextPackage = nextRequire.resolve("next/package.json");
|
|
764
|
+
try {
|
|
765
|
+
entries.push((0, node_module_1.createRequire)(nextPackage).resolve("@next/env"));
|
|
766
|
+
}
|
|
767
|
+
catch (cause) {
|
|
768
|
+
throw new Error(`${constants_1.LOG_PREFIX} Could not resolve "@next/env" from the app's \`next\`, ` +
|
|
769
|
+
`which the cdk-nextjs runtime uses to load .env files.`, { cause });
|
|
770
|
+
}
|
|
771
|
+
let nodeFileTrace;
|
|
772
|
+
try {
|
|
773
|
+
({ nodeFileTrace } = nextRequire(NEXT_FILE_TRACER));
|
|
774
|
+
}
|
|
775
|
+
catch (cause) {
|
|
776
|
+
throw new Error(`${constants_1.LOG_PREFIX} Could not load "${NEXT_FILE_TRACER}", which cdk-nextjs uses ` +
|
|
777
|
+
`to stage the \`next\` files its image optimizer requires. This Next.js ` +
|
|
778
|
+
`version may have moved it; please open an issue.`, { cause });
|
|
779
|
+
}
|
|
780
|
+
const add = (fileList, target) => {
|
|
781
|
+
for (const traced of fileList) {
|
|
782
|
+
const key = toPosix(traced);
|
|
783
|
+
if (target.has(key)) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const source = (0, node_path_1.join)(ctx.repoRoot, traced);
|
|
787
|
+
assertStagingKey(key, source);
|
|
788
|
+
target.set(key, source);
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
add((await nodeFileTrace(imageEntries, { base: ctx.repoRoot })).fileList, imageStaging);
|
|
792
|
+
const { fileList } = await nodeFileTrace(entries, { base: ctx.repoRoot });
|
|
793
|
+
// The trace starts from `@next/env`'s real path, so under pnpm it never
|
|
794
|
+
// passes through the `.pnpm/next@…/node_modules/@next/env` link that `next`
|
|
795
|
+
// resolves it by. Without the link, every request fails at cold start with
|
|
796
|
+
// "Cannot find module '@next/env'".
|
|
797
|
+
const nextEnvLink = (0, node_path_1.join)((0, node_path_1.dirname)(nextPackage), "..", "@next", "env");
|
|
798
|
+
if ((0, node_fs_1.lstatSync)(nextEnvLink, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
799
|
+
// `resolve` returns real paths, so relative to the real repo root.
|
|
800
|
+
fileList.add((0, node_path_1.relative)((0, node_fs_1.realpathSync)(ctx.repoRoot), nextEnvLink));
|
|
801
|
+
}
|
|
802
|
+
add(fileList, staging);
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Add `<distDir>/required-server-files.json` to a plan every group is merged with.
|
|
806
|
+
*
|
|
807
|
+
* It reaches a group otherwise only as a traced `asset` of some invocable output,
|
|
808
|
+
* which is not a guarantee: a group whose templates are all assigned elsewhere
|
|
809
|
+
* owns no outputs at all. That is reachable — a Pages-Router-only app whose every
|
|
810
|
+
* page falls under the configured `functionGroups` leaves the *default* group
|
|
811
|
+
* template-empty, and the default group is still what serves `/_next/image`, the
|
|
812
|
+
* static files, and the distribution's catch-all.
|
|
813
|
+
*
|
|
814
|
+
* Its absence is not a partial failure: `loadRuntime` probes for exactly this file
|
|
815
|
+
* before it will serve anything, and `image.ts` reads the image config out of it,
|
|
816
|
+
* so the whole root answers "the deployment package is incomplete". Cheap to make
|
|
817
|
+
* unconditional, so make it unconditional.
|
|
818
|
+
*
|
|
819
|
+
* Not traced like {@link RUNTIME_NEXT_MODULES}, because it is data rather than a
|
|
820
|
+
* module: nothing `require`s it, so no file tracer can find it.
|
|
821
|
+
*
|
|
822
|
+
* Absence is left to `loadRuntime`, which names the file and the layout contract
|
|
823
|
+
* it belongs to. `next build` always writes it, so there is no build-time error
|
|
824
|
+
* worth inventing here for a file this step does not own.
|
|
825
|
+
*/
|
|
826
|
+
function addRequiredServerFiles(ctx, staging) {
|
|
827
|
+
const source = (0, node_path_1.join)(ctx.distDir, "required-server-files.json");
|
|
828
|
+
const key = toPosix((0, node_path_1.relative)(ctx.repoRoot, source));
|
|
829
|
+
if (staging.has(key) || !(0, node_fs_1.existsSync)(source)) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
assertStagingKey(key, source);
|
|
833
|
+
staging.set(key, source);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Every staged path must land inside the staging tree and must not shadow the
|
|
837
|
+
* reserved directory cdk-nextjs copies its own runtime into at synth.
|
|
838
|
+
*/
|
|
839
|
+
function assertStagingKey(key, source) {
|
|
840
|
+
if (key === "" || key.startsWith("/") || key.startsWith("..")) {
|
|
841
|
+
throw new Error(`${constants_1.LOG_PREFIX} Build output asset "${source}" resolves to the staging key ` +
|
|
842
|
+
`"${key}", which is outside the deployment root. Set ` +
|
|
843
|
+
`\`outputFileTracingRoot\` so all traced files live under one root.`);
|
|
844
|
+
}
|
|
845
|
+
if (key === manifest_1.RUNTIME_DIR_NAME || key.startsWith(`${manifest_1.RUNTIME_DIR_NAME}/`)) {
|
|
846
|
+
throw new Error(`${constants_1.LOG_PREFIX} Build output asset "${source}" resolves to the staging key ` +
|
|
847
|
+
`"${key}", but "${manifest_1.RUNTIME_DIR_NAME}/" is reserved for cdk-nextjs's own ` +
|
|
848
|
+
`runtime files.`);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
function toPosix(path) {
|
|
852
|
+
return node_path_1.sep === "/" ? path : path.split(node_path_1.sep).join("/");
|
|
853
|
+
}
|
|
854
|
+
function sortedUnique(values) {
|
|
855
|
+
return [...new Set(values)].sort();
|
|
856
|
+
}
|
|
857
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtb3V0cHV0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVyL2J1aWxkLW91dHB1dHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUEyS0EsOENBNENDO0FBd0JELG9EQWtJQztBQWpYRCxzREFBc0Q7QUFDdEQscUNBQThEO0FBQzlELCtDQVEwQjtBQUMxQiw2Q0FBNEM7QUFDNUMseUNBQWtFO0FBRWxFLHVEQU8yQjtBQUMzQiw0Q0FBMEM7QUFDMUMsa0RBVzZCO0FBbUI3Qjs7Ozs7R0FLRztBQUNILE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBTSxFQUFFLGlCQUFpQixDQUFDLENBQUM7QUFFOUM7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLG9CQUFvQixHQUFHO0lBQzNCLGtDQUFrQztJQUNsQyx1RUFBdUU7Q0FDeEUsQ0FBQztBQUVGOzs7O0dBSUc7QUFDSCxNQUFNLGtCQUFrQixHQUFHO0lBQ3pCLG1DQUFtQztJQUNuQyxzQ0FBc0M7SUFDdEMscUNBQXFDO0NBQ3RDLENBQUM7QUFFRjs7Ozs7R0FLRztBQUNILE1BQU0sZ0JBQWdCLEdBQUcsZ0NBQWdDLENBQUM7QUF1RTFEOzs7O0dBSUc7QUFDSSxLQUFLLFVBQVUsaUJBQWlCLENBQ3JDLEdBQXlCLEVBQ3pCLFVBQStCLEVBQUU7SUFFakMsTUFBTSxVQUFVLEdBQUcsSUFBQSxnQkFBSSxFQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsMkJBQWdCLENBQUMsQ0FBQztJQUN2RCxNQUFNLFlBQVksR0FBRyxJQUFBLGdCQUFJLEVBQUMsVUFBVSxFQUFFLDZCQUFrQixDQUFDLENBQUM7SUFFMUQsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsR0FBRyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFFaEUsOEVBQThFO0lBQzlFLDJFQUEyRTtJQUMzRSw0RUFBNEU7SUFDNUUsTUFBTSxjQUFjLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENB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U0FBUyxPQUFPLENBQUMsSUFBWTtJQUMzQixPQUFPLGVBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxlQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDeEQsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUFDLE1BQWdCO0lBQ3BDLE9BQU8sQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDckMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuaW1wb3J0IHsgZXhpc3RzU3luYywgbHN0YXRTeW5jLCByZWFscGF0aFN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHtcbiAgY29weUZpbGUsXG4gIGNwLFxuICBta2RpcixcbiAgcmVhZGxpbmssXG4gIHJtLFxuICBzeW1saW5rLFxuICB3cml0ZUZpbGUsXG59IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSBcIm5vZGU6bW9kdWxlXCI7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luLCByZWxhdGl2ZSwgcmVzb2x2ZSwgc2VwIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgTmV4dEFkYXB0ZXIgfSBmcm9tIFwibmV4dFwiO1xuaW1wb3J0IHtcbiAgREVGQVVMVF9GVU5DVElPTl9HUk9VUCxcbiAgRlVOQ1RJT05fR1JPVVBTX0VOVl9WQVIsXG4gIEZ1bmN0aW9uR3JvdXBTcGVjLFxuICBhc3NlcnROb0kxOG5TcGxpdHRpbmcsXG4gIGFzc2lnblJvdXRlc1RvR3JvdXBzLFxuICBwYXJzZUZ1bmN0aW9uR3JvdXBzRW52LFxufSBmcm9tIFwiLi9mdW5jdGlvbi1ncm91cHNcIjtcbmltcG9ydCB7IExPR19QUkVGSVggfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBBREFQVEVSX0RJUl9OQU1FLFxuICBBREFQVEVSX01BTklGRVNUX1ZFUlNJT04sXG4gIEFkYXB0ZXJFbnRyeXBvaW50LFxuICBBZGFwdGVyRW50cnlwb2ludFR5cGUsXG4gIEFkYXB0ZXJNYW5pZmVzdCxcbiAgQWRhcHRlck1pZGRsZXdhcmUsXG4gIEVSUk9SX1BBR0VfU1VGRklYRVMsXG4gIE1BTklGRVNUX0ZJTEVfTkFNRSxcbiAgUlVOVElNRV9ESVJfTkFNRSxcbiAgZ3JvdXBTdGFnaW5nRGlyTmFtZSxcbn0gZnJvbSBcIi4uL3J1bnRpbWUvbWFuaWZlc3RcIjtcblxuLyoqXG4gKiBUaGUgYG9uQnVpbGRDb21wbGV0ZWAgYXJndW1lbnQuIERlcml2ZWQgZnJvbSB0aGUgYG5leHRgIHR5cGluZ3MgcmF0aGVyIHRoYW5cbiAqIHJlc3RhdGVkIHNvIGEgYG5leHRgIGJ1bXAgc3VyZmFjZXMgYXMgYSBjb21waWxlIGVycm9yIGhlcmUuXG4gKi9cbmV4cG9ydCB0eXBlIEJ1aWxkQ29tcGxldGVDb250ZXh0ID0gUGFyYW1ldGVyczxcbiAgTm9uTnVsbGFibGU8TmV4dEFkYXB0ZXJbXCJvbkJ1aWxkQ29tcGxldGVcIl0+XG4+WzBdO1xuXG50eXBlIEFkYXB0ZXJPdXRwdXRzID0gQnVpbGRDb21wbGV0ZUNvbnRleHRbXCJvdXRwdXRzXCJdO1xuLyoqIEFueSBvdXRwdXQgdGhhdCB3ZSBpbnZva2UgYXQgcmVxdWVzdCB0aW1lLCBpLmUuIG5vdCBhIHByZXJlbmRlci9zdGF0aWMgZmlsZS4gKi9cbnR5cGUgSW52b2NhYmxlT3V0cHV0ID1cbiAgfCBBZGFwdGVyT3V0cHV0c1tcInBhZ2VzXCJdW251bWJlcl1cbiAgfCBBZGFwdGVyT3V0cHV0c1tcInBhZ2VzQXBpXCJdW251bWJlcl1cbiAgfCBBZGFwdGVyT3V0cHV0c1tcImFwcFBhZ2VzXCJdW251bWJlcl1cbiAgfCBBZGFwdGVyT3V0cHV0c1tcImFwcFJvdXRlc1wiXVtudW1iZXJdXG4gIHwgTm9uTnVsbGFibGU8QWRhcHRlck91dHB1dHNbXCJtaWRkbGV3YXJlXCJdPjtcblxuLyoqXG4gKiBFbnYgZmlsZXMgYHdyaXRlU3RhbmRhbG9uZURpcmVjdG9yeWAgY29waWVzIGludG8gdGhlIHN0YW5kYWxvbmUgdHJlZSBhbmQgdGhhdFxuICogYG9uQnVpbGRDb21wbGV0ZWAgaGFzIG5vIGVxdWl2YWxlbnQgZm9yLiBEcm9wcGluZyBgb3V0cHV0OiBcInN0YW5kYWxvbmVcImBcbiAqIHNpbGVudGx5IGRyb3BzIHRoZXNlIHVubGVzcyB3ZSBzdGFnZSB0aGVtIG91cnNlbHZlcy5cbiAqIEBzZWUgaHR0cHM6Ly9uZXh0anMub3JnL2RvY3MvYXBwL2FwaS1yZWZlcmVuY2UvY29uZmlnL25leHQtY29uZmlnLWpzL291dHB1dFxuICovXG5jb25zdCBFTlZfRklMRVMgPSBbXCIuZW52XCIsIFwiLmVudi5wcm9kdWN0aW9uXCJdO1xuXG4vKipcbiAqIGBuZXh0YCBzdWJtb2R1bGVzIHRoZSAqcnVudGltZSogcmVxdWlyZXMgdGhhdCBubyBhcHAgZXZlciByZWFjaGVzLCBzb1xuICogYG5leHQgYnVpbGRgJ3Mgb3duIHRyYWNlIG5ldmVyIGNvdmVycyB0aGVtLiBUaGV5IGFyZSByZXF1aXJlZCBmcm9tIHRoZSBhcHAnc1xuICogYG5leHRgIHJhdGhlciB0aGFuIGJ1bmRsZWQsIGRlbGliZXJhdGVseSDigJQgc2VlIGBzcmMvcnVudGltZS9uZXh0LW1vZHVsZXMudHNgXG4gKiDigJQgd2hpY2ggbWFrZXMgc3RhZ2luZyB0aGVpciBjbG9zdXJlIHRoaXMgbW9kdWxlJ3Mgam9iLlxuICpcbiAqIGBzZXJ2ZS1zdGF0aWNgIGlzIGluIGV2ZXJ5IGdyb3VwOiBgc2VydmVTdGF0aWNGaWxlYFxuICogKGBzcmMvcnVudGltZS9zdGF0aWMtZmlsZXMudHNgKSBzZXJ2ZXMgcHJlcmVuZGVyZWQgYW5kIHN0YXRpYyByZXN1bHRzIHdpdGggaXRcbiAqIHdoZXJldmVyIHRoZXkgbGFuZC4gYGluc3RydW1lbnRhdGlvbi1nbG9iYWxzYCBpcyByZXF1aXJlZCBieSBgbG9hZFJ1bnRpbWVgXG4gKiBvbiBldmVyeSBjb2xkIHN0YXJ0IChgcmVnaXN0ZXJJbnN0cnVtZW50YXRpb25gKSwgc28gaXQgaXMgc3RhZ2VkIGhlcmUgcmF0aGVyXG4gKiB0aGFuIHRydXN0ZWQgdG8gZWFjaCBncm91cCdzIGVudHJ5cG9pbnQgdHJhY2UuXG4gKi9cbmNvbnN0IFJVTlRJTUVfTkVYVF9NT0RVTEVTID0gW1xuICBcIm5leHQvZGlzdC9zZXJ2ZXIvc2VydmUtc3RhdGljLmpzXCIsXG4gIFwibmV4dC9kaXN0L3NlcnZlci9saWIvcm91dGVyLXV0aWxzL2luc3RydW1lbnRhdGlvbi1nbG9iYWxzLmV4dGVybmFsLmpzXCIsXG5dO1xuXG4vKipcbiAqIG5leHQncyBpbWFnZSBvcHRpbWl6ZXIgYW5kIHRoZSBjb25maWcgaGVscGVycyBhcm91bmQgaXRcbiAqIChgc3JjL3J1bnRpbWUvaW1hZ2UudHNgKSwgd2hvc2UgY2xvc3VyZSBpcyB3aGF0IGJyaW5ncyBgc2hhcnBgIGluLiBPbmx5IHRoZVxuICogYGRlZmF1bHRgIGdyb3VwIGdldHMgdGhlbTogdGhlIGVkZ2Ugc2VuZHMgZXZlcnkgYC9fbmV4dC9pbWFnZWAgcmVxdWVzdCB0aGVyZS5cbiAqL1xuY29uc3QgSU1BR0VfTkVYVF9NT0RVTEVTID0gW1xuICBcIm5leHQvZGlzdC9zZXJ2ZXIvY29uZmlnLXNoYXJlZC5qc1wiLFxuICBcIm5leHQvZGlzdC9zaGFyZWQvbGliL2ltYWdlLWNvbmZpZy5qc1wiLFxuICBcIm5leHQvZGlzdC9zZXJ2ZXIvaW1hZ2Utb3B0aW1pemVyLmpzXCIsXG5dO1xuXG4vKipcbiAqIFRoZSBmaWxlIHRyYWNlciBgbmV4dCBidWlsZGAgaXRzZWxmIHVzZXMsIHJlYWNoZWQgdGhyb3VnaCB0aGUgYXBwJ3Mgb3duIGBuZXh0YFxuICogc28gdGhhdCBpdCBpcyB0aGUgdmVyc2lvbiB0aGF0IG1hdGNoZXMgdGhlIGZpbGVzIGJlaW5nIHRyYWNlZC4gTm90IGFcbiAqIGRlcGVuZGVuY3kgb2YgY2RrLW5leHRqczogYnVuZGxpbmcgYSBzZWNvbmQgY29weSBvZiBgQHZlcmNlbC9uZnRgIGludG8gdGhlXG4gKiBwdWJsaXNoZWQgYWRhcHRlciB3b3VsZCBhZGQgbWVnYWJ5dGVzIHRvIGV2ZXJ5IGluc3RhbGwgdG8gZG8gdGhlIHNhbWUgam9iLlxuICovXG5jb25zdCBORVhUX0ZJTEVfVFJBQ0VSID0gXCJuZXh0L2Rpc3QvY29tcGlsZWQvQHZlcmNlbC9uZnRcIjtcblxuLyoqIFRoZSBzdWJzZXQgb2YgYG5vZGVGaWxlVHJhY2VgIHRoaXMgbW9kdWxlIHVzZXMuICovXG50eXBlIE5vZGVGaWxlVHJhY2UgPSAoXG4gIGZpbGVzOiBzdHJpbmdbXSxcbiAgb3B0aW9uczogeyBiYXNlOiBzdHJpbmcgfSxcbikgPT4gUHJvbWlzZTx7IGZpbGVMaXN0OiBTZXQ8c3RyaW5nPiB9PjtcblxuLyoqXG4gKiBTdGFnaW5nIGtleSAocmVwby1yb290LXJlbGF0aXZlIFBPU0lYKSDihpIgYWJzb2x1dGUgc291cmNlIHBhdGggb24gdGhlIGJ1aWxkXG4gKiBtYWNoaW5lLiBUaGUgZGVkdXBlZCB1bmlvbiB0aGF0IHJlcGxhY2VzIHRoZSBzdGFuZGFsb25lIHRyZWUuXG4gKi9cbmV4cG9ydCB0eXBlIFN0YWdpbmdQbGFuID0gUmVhZG9ubHlNYXA8c3RyaW5nLCBzdHJpbmc+O1xuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkT3V0cHV0c09wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGRpcmVjdG9yeSBgbmV4dCBidWlsZGAgd2FzIGludm9rZWQgZnJvbS4gRGVmYXVsdHMgdG8gYHByb2Nlc3MuY3dkKClgLFxuICAgKiB3aGljaCBpcyB0aGUgcmVhbCBhbnN3ZXIgaW5zaWRlIGBvbkJ1aWxkQ29tcGxldGVgOyBhIHBhcmFtZXRlciBvbmx5IHNvIHRoZVxuICAgKiB1bml0IHRlc3RzIGNhbiBkcml2ZSB0aGUgZml4dHVyZXMnIHN5bnRoZXRpYyBwcm9qZWN0IGRpcnMuXG4gICAqL1xuICByZWFkb25seSBidWlsZEN3ZD86IHN0cmluZztcbiAgLyoqXG4gICAqIFJlc29sdmVkIGBmdW5jdGlvbkdyb3Vwc2AuIERlZmF1bHRzIHRvIHtAbGluayBGVU5DVElPTl9HUk9VUFNfRU5WX1ZBUn0sXG4gICAqIHdoaWNoIGlzIGhvdyB0aGUgY29uc3RydWN0cyBnZXQgdGhlbSBoZXJlOiBgb25CdWlsZENvbXBsZXRlYCBydW5zIGluc2lkZVxuICAgKiBgbmV4dCBidWlsZGAgYW5kIGNhbm5vdCByZWFkIENESyBwcm9wcy5cbiAgICpcbiAgICogYHVuZGVmaW5lZGAgbWVhbnMgb25lIGRlcGxveW1lbnQgcm9vdCBob2xkaW5nIGV2ZXJ5IHJvdXRlLCB3aGljaCBpcyB0aGVcbiAgICogZGVmYXVsdCBhbmQgdGhlIG9ubHkgdGhpbmcgdGhlIENvbnRhaW5lcnMgdHlwZXMgZXZlciBkby5cbiAgICovXG4gIHJlYWRvbmx5IGZ1bmN0aW9uR3JvdXBzPzogRnVuY3Rpb25Hcm91cFNwZWNbXTtcbn1cblxuLyoqIE9uZSBkZXBsb3ltZW50IHJvb3Q6IHRoZSBzdGFnaW5nIHBsYW4gZm9yIGl0LCBhbmQgd2hlcmUgaXQgZ29lcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhZ2VkR3JvdXAge1xuICAvKipcbiAgICogR3JvdXAgbmFtZSwgYGRlZmF1bHRgIGZvciB0aGUgaW1wbGljaXQgZ3JvdXAuIEFsd2F5cyBwcmVzZW50IOKAlCBhIGJ1aWxkIHdpdGhcbiAgICogbm8gYGZ1bmN0aW9uR3JvdXBzYCBwcm9kdWNlcyBleGFjdGx5IG9uZSB7QGxpbmsgU3RhZ2VkR3JvdXB9IG5hbWVkIGBkZWZhdWx0YCxcbiAgICogc28gY2FsbGVycyBuZXZlciBicmFuY2ggb24gXCJpcyB0aGlzIHNwbGl0XCIuXG4gICAqL1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBEaXJlY3RvcnkgaW5zaWRlIGBjZGstbmV4dGpzLWFkYXB0ZXJgLCBQT1NJWDogYGFwcGAgd2hlbiBub3Qgc3BsaXR0aW5nLFxuICAgKiBgZ3JvdXBzLzxuYW1lPmAgd2hlbiBzcGxpdHRpbmcuXG4gICAqL1xuICByZWFkb25seSBkaXJOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHN0YWdpbmc6IFN0YWdpbmdQbGFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkQWRhcHRlck1hbmlmZXN0UmVzdWx0IHtcbiAgcmVhZG9ubHkgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdDtcbiAgLyoqIE9uZSBlbnRyeSBwZXIgZGVwbG95bWVudCByb290IHRvIHN0YWdlLiBMZW5ndGggMSB1bmxlc3Mgc3BsaXR0aW5nLiAqL1xuICByZWFkb25seSBncm91cHM6IFN0YWdlZEdyb3VwW107XG59XG5cbi8qKiBBIHN0YWdlZCBkZXBsb3ltZW50IHJvb3Qgb24gZGlzay4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhZ2VkR3JvdXBSZXN1bHQge1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIC8qKiBBYnNvbHV0ZSBwYXRoIHRvIHRoZSBkZXBsb3ltZW50IHJvb3QuICovXG4gIHJlYWRvbmx5IHBhdGg6IHN0cmluZztcbiAgcmVhZG9ubHkgZmlsZUNvdW50OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV3JpdGVCdWlsZE91dHB1dHNSZXN1bHQgZXh0ZW5kcyBCdWlsZEFkYXB0ZXJNYW5pZmVzdFJlc3VsdCB7XG4gIC8qKiBBYnNvbHV0ZSBwYXRoIHRvIGA8ZGlzdERpcj4vY2RrLW5leHRqcy1hZGFwdGVyYC4gKi9cbiAgcmVhZG9ubHkgYWRhcHRlckRpcjogc3RyaW5nO1xuICAvKiogQWJzb2x1dGUgcGF0aCB0byB0aGUgd3JpdHRlbiBtYW5pZmVzdC4gKi9cbiAgcmVhZG9ubHkgbWFuaWZlc3RQYXRoOiBzdHJpbmc7XG4gIC8qKiBPbmUgcGVyIGRlcGxveW1lbnQgcm9vdCwgaW4gdGhlIG9yZGVyIHRoZXkgd2VyZSBzdGFnZWQuICovXG4gIHJlYWRvbmx5IHN0YWdlZEdyb3VwczogU3RhZ2VkR3JvdXBSZXN1bHRbXTtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgbWFuaWZlc3QgYW5kIHN0YWdpbmcgcGxhbiwgc3RhZ2UgdGhlIGZpbGVzLCBhbmQgd3JpdGUgdGhlIG1hbmlmZXN0LlxuICogQ2FsbGVkIGZyb20gYG9uQnVpbGRDb21wbGV0ZWAsIHdoaWNoIGlzIHRoZSBvbmx5IHBsYWNlIHRoYXQgaG9sZHMgdGhlIGJ1aWxkXG4gKiBvdXRwdXRzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGVCdWlsZE91dHB1dHMoXG4gIGN0eDogQnVpbGRDb21wbGV0ZUNvbnRleHQsXG4gIG9wdGlvbnM6IEJ1aWxkT3V0cHV0c09wdGlvbnMgPSB7fSxcbik6IFByb21pc2U8V3JpdGVCdWlsZE91dHB1dHNSZXN1bHQ+IHtcbiAgY29uc3QgYWRhcHRlckRpciA9IGpvaW4oY3R4LmRpc3REaXIsIEFEQVBURVJfRElSX05BTUUpO1xuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGFkYXB0ZXJEaXIsIE1BTklGRVNUX0ZJTEVfTkFNRSk7XG5cbiAgY29uc3QgeyBtYW5pZmVzdCwgZ3JvdXBzIH0gPSBidWlsZEFkYXB0ZXJNYW5pZmVzdChjdHgsIG9wdGlvbnMpO1xuXG4gIC8vIFRyYWNlZCBvbmNlLCBoZXJlOiB0aGUgdHJhY2UgaXMgYXN5bmMsIHdoaWNoIGlzIHdoeSBpdCBjYW5ub3QgaGFwcGVuIGluc2lkZVxuICAvLyBgYnVpbGRBZGFwdGVyTWFuaWZlc3RgLiBgcnVudGltZUNsb3N1cmVgIGlzIG1lcmdlZCBpbnRvIGV2ZXJ5IGdyb3VwLCBhbmRcbiAgLy8gYGltYWdlQ2xvc3VyZWAgaW50byBgZGVmYXVsdGAgb25seSwgdGhlIG9uZSBncm91cCBgL19uZXh0L2ltYWdlYCByZWFjaGVzLlxuICBjb25zdCBydW50aW1lQ2xvc3VyZSA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gIGNvbnN0IGltYWdlQ2xvc3VyZSA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gIGF3YWl0IGFkZFJ1bnRpbWVOZXh0Q2xvc3VyZShjdHgsIHJ1bnRpbWVDbG9zdXJlLCBpbWFnZUNsb3N1cmUpO1xuICBhZGRSZXF1aXJlZFNlcnZlckZpbGVzKGN0eCwgcnVudGltZUNsb3N1cmUpO1xuXG4gIC8vIEEgcHJldmlvdXMgYnVpbGQncyB0cmVlIGlzIG5ldmVyIGFkZGl0aXZlIHdpdGggdGhpcyBvbmUnczogYSByZW1vdmVkIHJvdXRlXG4gIC8vIGxlYXZlcyBiZWhpbmQgYW4gZW50cnlwb2ludCB0aGUgbWFuaWZlc3Qgbm8gbG9uZ2VyIG1lbnRpb25zLCBhIHJlbmFtZWQgY2h1bmtcbiAgLy8gbGVhdmVzIGRlYWQgYnl0ZXMgaW5zaWRlIHRoZSAyNTAgTUIgYnVkZ2V0LCBhbmQgYSByZWdyb3VwZWQgYnVpbGQgbGVhdmVzIGFcbiAgLy8gd2hvbGUgZGVwbG95bWVudCByb290IG5vdGhpbmcgZGVwbG95cy5cbiAgYXdhaXQgcm0oYWRhcHRlckRpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuXG4gIGNvbnN0IHN0YWdlZEdyb3VwczogU3RhZ2VkR3JvdXBSZXN1bHRbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGdyb3VwIG9mIGdyb3Vwcykge1xuICAgIGNvbnN0IGdyb3VwU3RhZ2luZyA9IG1lcmdlZChcbiAgICAgIG1lcmdlZChncm91cC5zdGFnaW5nLCBydW50aW1lQ2xvc3VyZSksXG4gICAgICBncm91cC5uYW1lID09PSBERUZBVUxUX0ZVTkNUSU9OX0dST1VQID8gaW1hZ2VDbG9zdXJlIDogbmV3IE1hcCgpLFxuICAgICk7XG4gICAgY29uc3QgcGF0aCA9IGpvaW4oYWRhcHRlckRpciwgLi4uZ3JvdXAuZGlyTmFtZS5zcGxpdChcIi9cIikpO1xuICAgIGF3YWl0IG1rZGlyKHBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGF3YWl0IHN0YWdlRmlsZXMoZ3JvdXBTdGFnaW5nLCBwYXRoKTtcbiAgICBzdGFnZWRHcm91cHMucHVzaCh7IG5hbWU6IGdyb3VwLm5hbWUsIHBhdGgsIGZpbGVDb3VudDogZ3JvdXBTdGFnaW5nLnNpemUgfSk7XG4gIH1cblxuICBhd2FpdCB3cml0ZUZpbGUobWFuaWZlc3RQYXRoLCBKU09OLnN0cmluZ2lmeShtYW5pZmVzdCwgbnVsbCwgMikpO1xuXG4gIHJldHVybiB7XG4gICAgbWFuaWZlc3QsXG4gICAgZ3JvdXBzLFxuICAgIGFkYXB0ZXJEaXIsXG4gICAgbWFuaWZlc3RQYXRoLFxuICAgIHN0YWdlZEdyb3VwcyxcbiAgfTtcbn1cblxuLyoqIExlZnQgd2lucywgYXMgZXZlcnl3aGVyZSBlbHNlIGluIHRoaXMgbW9kdWxlOiBmaXJzdCB3cml0ZXIgb2YgYSBrZXkga2VlcHMgaXQuICovXG5mdW5jdGlvbiBtZXJnZWQoXG4gIGJhc2U6IFN0YWdpbmdQbGFuLFxuICBhZGRpdGlvbnM6IFJlYWRvbmx5TWFwPHN0cmluZywgc3RyaW5nPixcbik6IE1hcDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCByZXN1bHQgPSBuZXcgTWFwKGJhc2UpO1xuICBmb3IgKGNvbnN0IFtrZXksIHNvdXJjZV0gb2YgYWRkaXRpb25zKSB7XG4gICAgaWYgKCFyZXN1bHQuaGFzKGtleSkpIHtcbiAgICAgIHJlc3VsdC5zZXQoa2V5LCBzb3VyY2UpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIFRoZSBwdXJlIGhhbGYgb2Yge0BsaW5rIHdyaXRlQnVpbGRPdXRwdXRzfTogZXZlcnl0aGluZyBkZXJpdmVkIGZyb20gdGhlIGJ1aWxkXG4gKiBvdXRwdXRzLCB3aXRoIG5vIHdyaXRlcy4gU3BsaXQgb3V0IHNvIGl0IGNhbiBiZSB1bml0IHRlc3RlZCBhZ2FpbnN0IGNvbW1pdHRlZFxuICogYG9uQnVpbGRDb21wbGV0ZWAgZml4dHVyZXMuXG4gKlxuICogVGhyb3dzIG9uIGFueSBub24tTm9kZSBvdXRwdXQgYW5kIG9uIGFueSBzdGFnaW5nIGtleSB0d28gb3V0cHV0cyBtYXAgdG9cbiAqIGRpZmZlcmVudCBjb250ZW50LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRBZGFwdGVyTWFuaWZlc3QoXG4gIGN0eDogQnVpbGRDb21wbGV0ZUNvbnRleHQsXG4gIG9wdGlvbnM6IEJ1aWxkT3V0cHV0c09wdGlvbnMgPSB7fSxcbik6IEJ1aWxkQWRhcHRlck1hbmlmZXN0UmVzdWx0IHtcbiAgY29uc3QgeyBvdXRwdXRzLCByZXBvUm9vdCB9ID0gY3R4O1xuICBjb25zdCBiYXNlUGF0aCA9IGN0eC5jb25maWcuYmFzZVBhdGggfHwgXCJcIjtcbiAgYXNzZXJ0QnVpbGRDd2QoY3R4LCBvcHRpb25zLmJ1aWxkQ3dkID8/IHByb2Nlc3MuY3dkKCkpO1xuICBjb25zdCBpbnZvY2FibGU6IEludm9jYWJsZU91dHB1dFtdID0gW1xuICAgIC4uLm91dHB1dHMucGFnZXMsXG4gICAgLi4ub3V0cHV0cy5wYWdlc0FwaSxcbiAgICAuLi5vdXRwdXRzLmFwcFBhZ2VzLFxuICAgIC4uLm91dHB1dHMuYXBwUm91dGVzLFxuICAgIC4uLihvdXRwdXRzLm1pZGRsZXdhcmUgPyBbb3V0cHV0cy5taWRkbGV3YXJlXSA6IFtdKSxcbiAgXTtcblxuICBhc3NlcnROb2RlUnVudGltZXMoaW52b2NhYmxlLCBvdXRwdXRzLm1pZGRsZXdhcmUpO1xuICB3YXJuT25Ecm9wcGVkUm91dGVDb25maWcoaW52b2NhYmxlKTtcblxuICBjb25zdCBzdGF0aWNGaWxlcyA9IGNvbGxlY3RTdGF0aWNGaWxlcyhjdHgpO1xuXG4gIGNvbnN0IGVudHJ5cG9pbnRzOiBSZWNvcmQ8c3RyaW5nLCBBZGFwdGVyRW50cnlwb2ludD4gPSB7fTtcbiAgZm9yIChjb25zdCB7IG91dHB1dHM6IGdyb3VwLCB0eXBlIH0gb2YgW1xuICAgIHsgb3V0cHV0czogb3V0cHV0cy5wYWdlcywgdHlwZTogXCJwYWdlXCIgYXMgY29uc3QgfSxcbiAgICB7IG91dHB1dHM6IG91dHB1dHMucGFnZXNBcGksIHR5cGU6IFwicGFnZS1hcGlcIiBhcyBjb25zdCB9LFxuICAgIHsgb3V0cHV0czogb3V0cHV0cy5hcHBQYWdlcywgdHlwZTogXCJhcHAtcGFnZVwiIGFzIGNvbnN0IH0sXG4gICAgeyBvdXRwdXRzOiBvdXRwdXRzLmFwcFJvdXRlcywgdHlwZTogXCJhcHAtcm91dGVcIiBhcyBjb25zdCB9LFxuICBdKSB7XG4gICAgZm9yIChjb25zdCBvdXRwdXQgb2YgZ3JvdXApIHtcbiAgICAgIGFkZEVudHJ5cG9pbnQoZW50cnlwb2ludHMsIHJlcG9Sb290LCBvdXRwdXQsIHR5cGUsIGJhc2VQYXRoKTtcbiAgICB9XG4gIH1cblxuICBhZGRQcmVyZW5kZXJQYXRobmFtZXMoXG4gICAgZW50cnlwb2ludHMsXG4gICAgb3V0cHV0cy5wcmVyZW5kZXJzLFxuICAgIGN0eC5yb3V0aW5nLmR5bmFtaWNSb3V0ZXMsXG4gICAgYmFzZVBhdGgsXG4gICAgYCR7YmFzZVBhdGh9L19uZXh0L2RhdGEvJHtjdHguYnVpbGRJZH0vYCxcbiAgKTtcblxuICBjb25zdCBwYXRobmFtZXMgPSBzb3J0ZWRVbmlxdWUoW1xuICAgIC4uLk9iamVjdC5rZXlzKGVudHJ5cG9pbnRzKSxcbiAgICAuLi5PYmplY3Qua2V5cyhzdGF0aWNGaWxlcyksXG4gIF0pO1xuXG4gIGNvbnN0IGZ1bmN0aW9uR3JvdXBzID1cbiAgICBvcHRpb25zLmZ1bmN0aW9uR3JvdXBzID8/XG4gICAgcGFyc2VGdW5jdGlvbkdyb3Vwc0Vudihwcm9jZXNzLmVudltGVU5DVElPTl9HUk9VUFNfRU5WX1ZBUl0pO1xuICAvLyBpMThuIGlzIGNoZWNrZWQgZmlyc3Q6IGl0IHJlamVjdHMgdGhlIGNvbWJpbmF0aW9uIG91dHJpZ2h0LCBhbmQgcnVubmluZyBpdFxuICAvLyBhZnRlciB0aGUgYXNzaWdubWVudCBtZWFudCBhbiBpMThuIGFwcCBnb3QgdGhlIGFzc2lnbm1lbnQncyBcInBhdHRlcm4gbWF0Y2hlc1xuICAvLyBubyByb3V0ZVwiIGVycm9yIGluc3RlYWQg4oCUIHRydWUsIGJ1dCBhYm91dCB0aGUgd3JvbmcgdGhpbmcsIHNpbmNlIGEgbG9jYWxpemVkXG4gIC8vIHRlbXBsYXRlIG5ldmVyIG1hdGNoZXMgYW4gdW5sb2NhbGl6ZWQgcGF0dGVybi5cbiAgaWYgKGZ1bmN0aW9uR3JvdXBzKSB7XG4gICAgYXNzZXJ0Tm9JMThuU3BsaXR0aW5nKGN0eC5jb25maWcuaTE4biA/PyBudWxsKTtcbiAgfVxuICBjb25zdCBhc3NpZ25tZW50ID0gZnVuY3Rpb25Hcm91cHNcbiAgICA/IGFzc2lnblJvdXRlc1RvR3JvdXBzKFxuICAgICAgICBmdW5jdGlvbkdyb3VwcyxcbiAgICAgICAgLy8gS2V5ZWQgb24gdGhlIGZpbGUsIG5vdCB0aGUgb3V0cHV0IGBpZGA6IGEgUGFnZXMgUm91dGVyIHBhZ2UgYW5kIGl0c1xuICAgICAgICAvLyBgL19uZXh0L2RhdGEvPGJ1aWxkSWQ+LzxwYWdlPi5qc29uYCByb3V0ZSBhcmUgc2VwYXJhdGUgb3V0cHV0cyB3aXRoXG4gICAgICAgIC8vIHNlcGFyYXRlIGlkcyBiYWNrZWQgYnkgb25lIGZpbGUsIGFuZCBvbmx5IHRoZSBwYWdlJ3MgdGVtcGxhdGUgbWF0Y2hlc1xuICAgICAgICAvLyBhIGdyb3VwIHBhdHRlcm4uXG4gICAgICAgIE9iamVjdC5lbnRyaWVzKGVudHJ5cG9pbnRzKS5tYXAoKFt0ZW1wbGF0ZSwgZW50cnlwb2ludF0pID0+ICh7XG4gICAgICAgICAgdGVtcGxhdGUsXG4gICAgICAgICAgZW50cnlwb2ludElkOiBlbnRyeXBvaW50LmZpbGVQYXRoLFxuICAgICAgICAgIHR5cGU6IGVudHJ5cG9pbnQudHlwZSxcbiAgICAgICAgfSkpLFxuICAgICAgICB7XG4gICAgICAgICAgYmFzZVBhdGg6IGN0eC5jb25maWcuYmFzZVBhdGggfHwgXCJcIixcbiAgICAgICAgICBidWlsZElkOiBjdHguYnVpbGRJZCxcbiAgICAgICAgICB0cmFpbGluZ1NsYXNoOiBjdHguY29uZmlnLnRyYWlsaW5nU2xhc2ggPT09IHRydWUsXG4gICAgICAgICAgcm91dGluZzogY3R4LnJvdXRpbmcsXG4gICAgICAgIH0sXG4gICAgICApXG4gICAgOiB1bmRlZmluZWQ7XG5cbiAgY29uc3QgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdCA9IHtcbiAgICB2ZXJzaW9uOiBBREFQVEVSX01BTklGRVNUX1ZFUlNJT04gYXMgMSxcbiAgICBidWlsZElkOiBjdHguYnVpbGRJZCxcbiAgICByZWxhdGl2ZVByb2plY3REaXI6IHRvUG9zaXgocmVsYXRpdmUocmVwb1Jvb3QsIGN0eC5wcm9qZWN0RGlyKSksXG4gICAgY29uZmlnOiB7XG4gICAgICBiYXNlUGF0aDogY3R4LmNvbmZpZy5iYXNlUGF0aCB8fCBcIlwiLFxuICAgICAgdHJhaWxpbmdTbGFzaDogY3R4LmNvbmZpZy50cmFpbGluZ1NsYXNoID09PSB0cnVlLFxuICAgICAgYXNzZXRQcmVmaXg6IGN0eC5jb25maWcuYXNzZXRQcmVmaXggfHwgXCJcIixcbiAgICAgIGRpc3REaXI6IHRvUG9zaXgocmVsYXRpdmUoY3R4LnByb2plY3REaXIsIGN0eC5kaXN0RGlyKSksXG4gICAgICBjb21wcmVzczogY3R4LmNvbmZpZy5jb21wcmVzcyAhPT0gZmFsc2UsXG4gICAgICBnZW5lcmF0ZUV0YWdzOiBjdHguY29uZmlnLmdlbmVyYXRlRXRhZ3MgIT09IGZhbHNlLFxuICAgICAgaTE4bjogY3R4LmNvbmZpZy5pMThuID8/IG51bGwsXG4gICAgICBkZXBsb3ltZW50SWQ6IChjdHguY29uZmlnLmRlcGxveW1lbnRJZCA/PyBcIlwiKS5yZXBsYWNlKFxuICAgICAgICAvW15BLVphLXowLTlfLV0vZyxcbiAgICAgICAgXCItXCIsXG4gICAgICApLFxuICAgIH0sXG4gICAgcm91dGluZzogY3R4LnJvdXRpbmcsXG4gICAgcGF0aG5hbWVzLFxuICAgIGVudHJ5cG9pbnRzLFxuICAgIG1pZGRsZXdhcmU6IGJ1aWxkTWlkZGxld2FyZShyZXBvUm9vdCwgb3V0cHV0cy5taWRkbGV3YXJlKSxcbiAgICBzdGF0aWNGaWxlcyxcbiAgICAuLi4oYXNzaWdubWVudFxuICAgICAgPyB7XG4gICAgICAgICAgZ3JvdXBzOiBhc3NpZ25tZW50LnRlbXBsYXRlcyxcbiAgICAgICAgICBiZWhhdmlvcnM6IGFzc2lnbm1lbnQuYmVoYXZpb3JzLFxuICAgICAgICAgIGZ1bmN0aW9uR3JvdXBzOiBmdW5jdGlvbkdyb3VwcyEubWFwKCh7IG5hbWUsIHJvdXRlcyB9KSA9PiAoe1xuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIHJvdXRlcyxcbiAgICAgICAgICB9KSksXG4gICAgICAgIH1cbiAgICAgIDoge30pLFxuICB9O1xuXG4gIGNvbnN0IGdyb3VwczogU3RhZ2VkR3JvdXBbXSA9IGFzc2lnbm1lbnRcbiAgICA/IE9iamVjdC5lbnRyaWVzKGFzc2lnbm1lbnQudGVtcGxhdGVzKS5tYXAoKFtuYW1lLCB0ZW1wbGF0ZXNdKSA9PiAoe1xuICAgICAgICBuYW1lLFxuICAgICAgICBkaXJOYW1lOiBncm91cFN0YWdpbmdEaXJOYW1lKG5hbWUpLFxuICAgICAgICBzdGFnaW5nOiBjb2xsZWN0R3JvdXBTdGFnaW5nUGxhbihcbiAgICAgICAgICBjdHgsXG4gICAgICAgICAgaW52b2NhYmxlLFxuICAgICAgICAgIGVudHJ5cG9pbnRzLFxuICAgICAgICAgIHRlbXBsYXRlcyxcbiAgICAgICAgKSxcbiAgICAgIH0pKVxuICAgIDogW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogREVGQVVMVF9GVU5DVElPTl9HUk9VUCxcbiAgICAgICAgICBkaXJOYW1lOiBncm91cFN0YWdpbmdEaXJOYW1lKCksXG4gICAgICAgICAgc3RhZ2luZzogc2VydmVkU3RhZ2luZ1BsYW4oY3R4LCBpbnZvY2FibGUpLFxuICAgICAgICB9LFxuICAgICAgXTtcblxuICByZXR1cm4geyBtYW5pZmVzdCwgZ3JvdXBzIH07XG59XG5cbi8qKlxuICogT25lIGdyb3VwJ3Mgc2xpY2Ugb2YgdGhlIHN0YWdpbmcgcGxhbjogdGhlIGFzc2V0cyBvZiB0aGUgb3V0cHV0cyBpdCBvd25zLCBhbmRcbiAqIG5vdGhpbmcgZWxzZS5cbiAqXG4gKiBNaWRkbGV3YXJlIGlzIGluIGV2ZXJ5IGdyb3VwLCBub3QganVzdCB0aGUgZGVmYXVsdCBvbmUg4oCUIGl0IHJ1bnMgb24gZXZlcnlcbiAqIHJlcXVlc3Qgd2hlcmV2ZXIgdGhhdCByZXF1ZXN0IGxhbmRzLCBzbyBpdCBpcyBkdXBsaWNhdGVkIGJ5IGRlc2lnbiwgYXMgaXMgdGhlXG4gKiBgbmV4dGAgY2xvc3VyZSB0aGUgZW50cnlwb2ludHMgc2hhcmUuIFRoZSBzYW1lIGdvZXMgZm9yIHRoZSBzdGF0aWMgZmlsZXMgdGhlXG4gKiBydW50aW1lIHNlcnZlcyBpdHNlbGYgKGA0MDQuaHRtbGAsIGBmYXZpY29uLmljby5ib2R5YCk6IGFueSBncm91cCBjYW4gYmUgYXNrZWRcbiAqIGZvciB0aGVtLiBBbmQgc28gYXJlIHRoZSBub3QtZm91bmQgYW5kIGVycm9yIHBhZ2VzOiB0aGUgcnVudGltZSByZW5kZXJzIGFcbiAqIDQwNCBvciBhIDUwMCB3aXRoIHdoaWNoZXZlciBvZiB0aGVtIHRoZSBzaGFyZWQgbWFuaWZlc3QgbmFtZXNcbiAqIChgc3RhdHVzVGFyZ2V0c2AgaW4gYHJ1bnRpbWUvZGlzcGF0Y2gudHNgKSwgaW4gd2hpY2hldmVyIGdyb3VwIHRoZVxuICogcmVxdWVzdCByZWFjaGVkLCBzbyBhIGdyb3VwIHdpdGhvdXQgdGhlbSBhbnN3ZXJlZCBhIFVSTCB1bmRlciBpdHMgb3duXG4gKiBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyBubyByb3V0ZSB3aXRoIFwidGhlIGRlcGxveW1lbnQgcGFja2FnZSBpcyBpbmNvbXBsZXRlXCIuXG4gKlxuICogT3duZXJzaGlwIGlzIG1hdGNoZWQgb24gdGhlIGVudHJ5cG9pbnQncyBgZmlsZVBhdGhgLCBub3QgaXRzIGBpZGAgb3JcbiAqIHBhdGhuYW1lOiB0aGUgbWFuaWZlc3QncyBlbnRyeXBvaW50cyBhcmUga2V5ZWQgYnkgKnRlbXBsYXRlKiwgYW4gb3V0cHV0IG1heVxuICogYmFjayBzZXZlcmFsIHRlbXBsYXRlcywgYW5kIHtAbGluayBhZGRQcmVyZW5kZXJQYXRobmFtZXN9IHN5bnRoZXNpemVzXG4gKiBlbnRyeXBvaW50cyB0aGF0IGNhcnJ5IHRoZSAqcHJlcmVuZGVyJ3MqIGlkLCB3aGljaCBubyBpbnZvY2FibGUgb3V0cHV0IGhhcyAodGhlXG4gKiByb290LXBhcmFtcyBhcHA6IGVudHJ5cG9pbnQgYC9lbmAgd2l0aCBgaWQ6IFwiL2VuXCJgIGJhY2tlZCBieSB0aGUgb3V0cHV0XG4gKiBgL1tsb2NhbGVdYCkuIFRoZSBzeW50aGVzaXplZCBlbnRyeXBvaW50J3MgYGZpbGVQYXRoYCBpcyB0aGUgb3duaW5nIG91dHB1dCdzLlxuICovXG5mdW5jdGlvbiBjb2xsZWN0R3JvdXBTdGFnaW5nUGxhbihcbiAgY3R4OiBCdWlsZENvbXBsZXRlQ29udGV4dCxcbiAgaW52b2NhYmxlOiBJbnZvY2FibGVPdXRwdXRbXSxcbiAgZW50cnlwb2ludHM6IFJlY29yZDxzdHJpbmcsIEFkYXB0ZXJFbnRyeXBvaW50PixcbiAgdGVtcGxhdGVzOiBzdHJpbmdbXSxcbik6IE1hcDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCBiYXNlUGF0aCA9IGN0eC5jb25maWcuYmFzZVBhdGggfHwgXCJcIjtcbiAgY29uc3Qgb3duZWRFbnRyeXBvaW50cyA9IFtcbiAgICAuLi50ZW1wbGF0ZXMsXG4gICAgLi4uRVJST1JfUEFHRV9TVUZGSVhFUy5tYXAoKHN1ZmZpeCkgPT4gYCR7YmFzZVBhdGh9JHtzdWZmaXh9YCksXG4gIF1cbiAgICAubWFwKCh0ZW1wbGF0ZSkgPT4gZW50cnlwb2ludHNbdGVtcGxhdGVdKVxuICAgIC5maWx0ZXIoKGVudHJ5KTogZW50cnkgaXMgQWRhcHRlckVudHJ5cG9pbnQgPT4gZW50cnkgIT09IHVuZGVmaW5lZCk7XG4gIGNvbnN0IG93bmVkRmlsZXMgPSBuZXcgU2V0KG93bmVkRW50cnlwb2ludHMubWFwKChlbnRyeSkgPT4gZW50cnkuZmlsZVBhdGgpKTtcbiAgY29uc3QgbWlkZGxld2FyZSA9IGN0eC5vdXRwdXRzLm1pZGRsZXdhcmU7XG4gIGNvbnN0IG93bmVkID0gaW52b2NhYmxlLmZpbHRlcihcbiAgICAob3V0cHV0KSA9PlxuICAgICAgb3duZWRGaWxlcy5oYXModG9Qb3NpeChyZWxhdGl2ZShjdHgucmVwb1Jvb3QsIG91dHB1dC5maWxlUGF0aCkpKSB8fFxuICAgICAgb3V0cHV0ID09PSBtaWRkbGV3YXJlLFxuICApO1xuICByZXR1cm4gc2VydmVkU3RhZ2luZ1BsYW4oY3R4LCBvd25lZCk7XG59XG5cbi8qKiB7QGxpbmsgY29sbGVjdFN0YWdpbmdQbGFufSBmb3IgYG91dHB1dHNgLCBwbHVzIHRoZSBmaWxlcyB0aGUgcnVudGltZSBzZXJ2ZXMuICovXG5mdW5jdGlvbiBzZXJ2ZWRTdGFnaW5nUGxhbihcbiAgY3R4OiBCdWlsZENvbXBsZXRlQ29udGV4dCxcbiAgb3V0cHV0czogSW52b2NhYmxlT3V0cHV0W10sXG4pOiBNYXA8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3Qgc3RhZ2luZyA9IGNvbGxlY3RTdGFnaW5nUGxhbihjdHgsIG91dHB1dHMpO1xuICBzdGFnZVNlcnZlZFN0YXRpY0ZpbGVzKGN0eCwgc3RhZ2luZyk7XG4gIHJldHVybiBzdGFnaW5nO1xufVxuXG4vKipcbiAqIEpvYiAxOiByZWplY3Qgbm9uLU5vZGUgb3V0cHV0cywgZXZlcnl3aGVyZS5cbiAqXG4gKiBgZXhwb3J0IGNvbnN0IHJ1bnRpbWUgPSAnZWRnZSdgIG9uIGEgcGFnZSBvciByb3V0ZSBoYW5kbGVyIGxhbmRzIGluXG4gKiBgYXBwUGFnZXNgL2BhcHBSb3V0ZXNgL2BwYWdlc2AvYHBhZ2VzQXBpYCB3aXRoIGBydW50aW1lOiAnZWRnZSdgLFxuICogYGFzc2V0czoge31gLCBhbmQgYW4gYGVkZ2VSdW50aW1lYCBkZXNjcmlwdG9yIG5lZWRpbmcgYGdsb2JhbFRoaXMuX0VOVFJJRVNgXG4gKiBhbmQgYSBzYW5kYm94LiBHdWFyZGluZyBtaWRkbGV3YXJlIGFsb25lIHdvdWxkIGxlYXZlIGEgc2lsZW50IGZhaWx1cmUgbW9kZVxuICogZm9yIGVkZ2UgcGFnZXM6IGFuIGVudHJ5cG9pbnQgd2UgY2FuJ3QgaW52b2tlIGFuZCBubyBhc3NldHMgdG8gaW52b2tlIGl0XG4gKiB3aXRoLlxuICovXG5mdW5jdGlvbiBhc3NlcnROb2RlUnVudGltZXMoXG4gIGludm9jYWJsZTogSW52b2NhYmxlT3V0cHV0W10sXG4gIG1pZGRsZXdhcmU6IEFkYXB0ZXJPdXRwdXRzW1wibWlkZGxld2FyZVwiXSxcbik6IHZvaWQge1xuICBjb25zdCBvZmZlbmRpbmcgPSBpbnZvY2FibGUuZmlsdGVyKChvdXRwdXQpID0+IG91dHB1dC5ydW50aW1lICE9PSBcIm5vZGVqc1wiKTtcbiAgaWYgKG9mZmVuZGluZy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBNaWRkbGV3YXJlIGlzIHJlcG9ydGVkIHNlcGFyYXRlbHkgZnJvbSByb3V0ZXMuIEl0cyBgc291cmNlUGFnZWAgaXMgYC9gLCBzb1xuICAvLyBmb2xkaW5nIGl0IGluIHdpdGggdGhlIHJvdXRlcyBwcm9kdWNlcyB0aGUgYWN0aXZlbHkgbWlzbGVhZGluZyBhZHZpY2UgdG9cbiAgLy8gcmVtb3ZlIGBleHBvcnQgY29uc3QgcnVudGltZSA9IFwiZWRnZVwiYCBmcm9tIHRoZSBob21lIHBhZ2UgLSB3aGljaCBpcyB3aGVyZVxuICAvLyB0aGUgZWRnZSBydW50aW1lIGlzIG5vdCwgYW5kIG1heSBub3QgZXZlbiBleGlzdC5cbiAgY29uc3Qgb2ZmZW5kaW5nTWlkZGxld2FyZSA9IG1pZGRsZXdhcmUgJiYgb2ZmZW5kaW5nLmluY2x1ZGVzKG1pZGRsZXdhcmUpO1xuICAvLyBgLnJzY2AgdmFyaWFudHMgc2hhcmUgYSBgc291cmNlUGFnZWAgd2l0aCB0aGVpciBIVE1MIHNpYmxpbmcsIHNvIGRlZHVwZS5cbiAgY29uc3Qgcm91dGVzID0gc29ydGVkVW5pcXVlKFxuICAgIG9mZmVuZGluZ1xuICAgICAgLmZpbHRlcigob3V0cHV0KSA9PiBvdXRwdXQgIT09IG1pZGRsZXdhcmUpXG4gICAgICAubWFwKChvdXRwdXQpID0+IGAke291dHB1dC5zb3VyY2VQYWdlfSAocnVudGltZTogXCIke291dHB1dC5ydW50aW1lfVwiKWApLFxuICApO1xuXG4gIGNvbnN0IHJlYXNvbnM6IHN0cmluZ1tdID0gW107XG4gIGlmIChyb3V0ZXMubGVuZ3RoID4gMCkge1xuICAgIHJlYXNvbnMucHVzaChcbiAgICAgIGBjZGstbmV4dGpzIGNhbm5vdCBkZXBsb3kgcm91dGVzIGJ1aWx0IGZvciB0aGUgZWRnZSBydW50aW1lLiBgICtcbiAgICAgICAgYFJlbW92ZSBcXGBleHBvcnQgY29uc3QgcnVudGltZSA9IFwiZWRnZVwiXFxgIGZyb206XFxuYCArXG4gICAgICAgIHJvdXRlcy5tYXAoKHJvdXRlKSA9PiBgICAtICR7cm91dGV9YCkuam9pbihcIlxcblwiKSxcbiAgICApO1xuICB9XG4gIGlmIChvZmZlbmRpbmdNaWRkbGV3YXJlKSB7XG4gICAgcmVhc29ucy5wdXNoKFxuICAgICAgYGNkay1uZXh0anMgY2Fubm90IGRlcGxveSBtaWRkbGV3YXJlIGJ1aWx0IGZvciB0aGUgZWRnZSBydW50aW1lIGAgK1xuICAgICAgICBgKCR7bWlkZGxld2FyZS5maWxlUGF0aH0sIHJ1bnRpbWU6IFwiJHttaWRkbGV3YXJlLnJ1bnRpbWV9XCIpLiBgICtcbiAgICAgICAgYFJlbmFtZSBpdCB0byBcXGBwcm94eS50c1xcYCAoTmV4dC5qcyAxNiBydW5zIHByb3h5IG9uIHRoZSBOb2RlIGAgK1xuICAgICAgICBgcnVudGltZSksIG9yIGtlZXAgXFxgbWlkZGxld2FyZS50c1xcYCBhbmQgYWRkIGAgK1xuICAgICAgICBgXFxgZXhwb3J0IGNvbnN0IGNvbmZpZyA9IHsgcnVudGltZTogXCJub2RlanNcIiB9XFxgIHRvIGl0IOKAlCBgICtcbiAgICAgICAgYFxcYG1pZGRsZXdhcmUudHNcXGAgZGVmYXVsdHMgdG8gdGhlIGVkZ2UgcnVudGltZSwgYnV0IGRvZXMgbm90IHJlcXVpcmUgaXQuYCxcbiAgICApO1xuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKFxuICAgIGAke0xPR19QUkVGSVh9ICR7cmVhc29ucy5qb2luKFwiXFxuXCIpfVxcbmAgK1xuICAgICAgYFRoZSBlZGdlIHJ1bnRpbWUgaXMgZGVwcmVjYXRlZCBpbiBOZXh0LmpzOiBgICtcbiAgICAgIGBodHRwczovL25leHRqcy5vcmcvZG9jcy9tZXNzYWdlcy9lZGdlLXJ1bnRpbWUtZGVwcmVjYXRlZGAsXG4gICk7XG59XG5cbi8qKlxuICogV2FybiBvbiByb3V0ZSBjb25maWcgY2RrLW5leHRqcyBkb2VzIG5vdCBob25vci4gQW4gYXV0aG9yIHdobyBzZXQgdGhlc2UgYXNrZWRcbiAqIGZvciBzb21ldGhpbmcgZXhwbGljaXRseSwgc28gc2F5IHNvIHJhdGhlciB0aGFuIGlnbm9yaW5nIGl0IHNpbGVudGx5OyBuZXZlclxuICogdGhyb3csIGJlY2F1c2Ugcm91dGUtbGV2ZWwgYG1heER1cmF0aW9uYCBpcyB2YWxpZCBOZXh0LmpzLlxuICpcbiAqIGBOZXh0anNCdWlsZGAgcnVucyBgbmV4dCBidWlsZGAgd2l0aCBgc3RkaW86IFwiaW5oZXJpdFwiYCwgc28gdGhpcyByZWFjaGVzIHRoZVxuICogdXNlcidzIHRlcm1pbmFsLiBTZWUgdGhlIHBsYW4ncyBcIkRlY2lzaW9uc1wiIGZvciB3aHkgbmVpdGhlciBpcyBob25vcmVkLlxuICovXG5mdW5jdGlvbiB3YXJuT25Ecm9wcGVkUm91dGVDb25maWcoaW52b2NhYmxlOiBJbnZvY2FibGVPdXRwdXRbXSk6IHZvaWQge1xuICBjb25zdCBkcm9wcGVkOiBSZWNvcmQ8XCJtYXhEdXJhdGlvblwiIHwgXCJwcmVmZXJyZWRSZWdpb25cIiwgc3RyaW5nW10+ID0ge1xuICAgIG1heER1cmF0aW9uOiBbXSxcbiAgICBwcmVmZXJyZWRSZWdpb246IFtdLFxuICB9O1xuICBmb3IgKGNvbnN0IG91dHB1dCBvZiBpbnZvY2FibGUpIHtcbiAgICBpZiAob3V0cHV0LmNvbmZpZz8ubWF4RHVyYXRpb24gIT09IHVuZGVmaW5lZCkge1xuICAgICAgZHJvcHBlZC5tYXhEdXJhdGlvbi5wdXNoKG91dHB1dC5zb3VyY2VQYWdlKTtcbiAgICB9XG4gICAgaWYgKG91dHB1dC5jb25maWc/LnByZWZlcnJlZFJlZ2lvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBkcm9wcGVkLnByZWZlcnJlZFJlZ2lvbi5wdXNoKG91dHB1dC5zb3VyY2VQYWdlKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCByZW1lZHk6IFJlY29yZDxcIm1heER1cmF0aW9uXCIgfCBcInByZWZlcnJlZFJlZ2lvblwiLCBzdHJpbmc+ID0ge1xuICAgIG1heER1cmF0aW9uOlxuICAgICAgXCJTZXQgdGhlIGZ1bmN0aW9uIHRpbWVvdXQgd2l0aCB0aGUgY29uc3RydWN0J3MgYG92ZXJyaWRlc2AgcHJvcCBpbnN0ZWFkIChlLmcuIGBvdmVycmlkZXM6IHsgbmV4dGpzRnVuY3Rpb25zOiB7IGZ1bmN0aW9uUHJvcHM6IHsgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygzMCkgfSB9IH1gKTsgYSBMYW1iZGEgdGltZW91dCBpcyBwZXItZnVuY3Rpb24gd2hpbGUgYG1heER1cmF0aW9uYCBpcyBwZXItcm91dGUuXCIsXG4gICAgcHJlZmVycmVkUmVnaW9uOlxuICAgICAgXCJIb25vcmluZyBpdCB3b3VsZCByZXF1aXJlIGEgbXVsdGktcmVnaW9uIGRlcGxveW1lbnQsIHdoaWNoIHRoaXMgY29uc3RydWN0IGRvZXMgbm90IG1vZGVsLlwiLFxuICB9O1xuXG4gIGZvciAoY29uc3Qga2V5IG9mIFtcIm1heER1cmF0aW9uXCIsIFwicHJlZmVycmVkUmVnaW9uXCJdIGFzIGNvbnN0KSB7XG4gICAgY29uc3Qgcm91dGVzID0gc29ydGVkVW5pcXVlKGRyb3BwZWRba2V5XSk7XG4gICAgaWYgKHJvdXRlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zb2xlLndhcm4oXG4gICAgICBgJHtMT0dfUFJFRklYfSBcXGAke2tleX1cXGAgaXMgbm90IGhvbm9yZWQgYnkgY2RrLW5leHRqcy4gYCArXG4gICAgICAgIGAke3JvdXRlcy5sZW5ndGh9IHJvdXRlKHMpIHNldCBpdCwgaW5jbHVkaW5nOiAke3JvdXRlcy5zbGljZSgwLCA1KS5qb2luKFwiLCBcIil9YCArXG4gICAgICAgIGAke3JvdXRlcy5sZW5ndGggPiA1ID8gYCwgYW5kICR7cm91dGVzLmxlbmd0aCAtIDV9IG1vcmVgIDogXCJcIn0uIGAgK1xuICAgICAgICByZW1lZHlba2V5XSxcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogSm9icyAyLCAzIGFuZCA2OiB0aGUgZGVkdXBlZCB1bmlvbiBvZiBldmVyeSBzaGlwcGVkIG91dHB1dCdzIHRyYWNlZCBgYXNzZXRzYCxcbiAqIHBsdXMgZWFjaCBlbnRyeXBvaW50IGZpbGUgaXRzZWxmLCBwbHVzIHRoZSBlbnYgZmlsZXMsIHdpdGggYGFzc2V0c0hhc2hlc2AgdXNlZFxuICogYXMgYSBjb25mbGljdCBjaGVjay5cbiAqXG4gKiBEZWR1cCBpcyBieSBrZXk6IHRoZSB0cmFjZWQgYG5leHRgIGNsb3N1cmUgaXMgbWVyZ2VkIGludG8gZXZlcnkgb3V0cHV0J3NcbiAqIGBhc3NldHNgIChgZ2V0U2hhcmVkTm9kZUFzc2V0c2Ag4oaSIGBzaGFyZWROb2RlQXNzZXRzYCksIHNvIE4gb3V0cHV0c1xuICogb3ZlcndoZWxtaW5nbHkgcmVwZWF0IGtleXMuIFdoYXQgdGhlIGhhc2hlcyBidXkgaXMgZGV0ZWN0aW5nIHR3byBvdXRwdXRzXG4gKiBtYXBwaW5nIHRoZSAqKnNhbWUga2V5IHRvIGRpZmZlcmVudCBjb250ZW50KiosIHdoaWNoIGlzIHVucGFja2FnZWFibGUgaW50b1xuICogb25lIExhbWJkYSDigJQgZmFpbCB0aGUgYnVpbGQgbG91ZGx5IHJhdGhlciB0aGFuIGxldHRpbmcgbGFzdC13cml0ZS13aW5zIHBpY2suXG4gKi9cbmZ1bmN0aW9uIGNvbGxlY3RTdGFnaW5nUGxhbihcbiAgY3R4OiBCdWlsZENvbXBsZXRlQ29udGV4dCxcbiAgaW52b2NhYmxlOiBJbnZvY2FibGVPdXRwdXRbXSxcbik6IE1hcDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCB7IHJlcG9Sb290IH0gPSBjdHg7XG4gIGNvbnN0IHN0YWdpbmcgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICBjb25zdCBoYXNoZXMgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuXG4gIGNvbnN0IGFkZCA9IChrZXk6IHN0cmluZywgc291cmNlOiBzdHJpbmcsIGhhc2g/OiBzdHJpbmcpID0+IHtcbiAgICBhc3NlcnRTdGFnaW5nS2V5KGtleSwgc291cmNlKTtcbiAgICBjb25zdCBleGlzdGluZ0hhc2ggPSBoYXNoZXMuZ2V0KGtleSk7XG4gICAgaWYgKFxuICAgICAgaGFzaCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICBleGlzdGluZ0hhc2ggIT09IHVuZGVmaW5lZCAmJlxuICAgICAgZXhpc3RpbmdIYXNoICE9PSBoYXNoXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke0xPR19QUkVGSVh9IFR3byBidWlsZCBvdXRwdXRzIG1hcCBcIiR7a2V5fVwiIHRvIGRpZmZlcmVudCBjb250ZW50IGAgK1xuICAgICAgICAgIGAoaGFzaGVzICR7ZXhpc3RpbmdIYXNofSBhbmQgJHtoYXNofSkuIE9uZSBkZXBsb3ltZW50IHBhY2thZ2UgY2Fubm90IGAgK1xuICAgICAgICAgIGBob2xkIGJvdGguIFRoaXMgdXN1YWxseSBtZWFucyB0d28gTmV4dC5qcyBwcm9qZWN0cyBpbiB0aGUgc2FtZSByZXBvIGAgK1xuICAgICAgICAgIGB3cml0ZSB0aGUgc2FtZSByZXBvLXJvb3QtcmVsYXRpdmUgcGF0aC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKGhhc2ggIT09IHVuZGVmaW5lZCkge1xuICAgICAgaGFzaGVzLnNldChrZXksIGhhc2gpO1xuICAgIH1cbiAgICBpZiAoIXN0YWdpbmcuaGFzKGtleSkpIHtcbiAgICAgIHN0YWdpbmcuc2V0KGtleSwgc291cmNlKTtcbiAgICB9XG4gIH07XG5cbiAgZm9yIChjb25zdCBvdXRwdXQgb2YgaW52b2NhYmxlKSB7XG4gICAgZm9yIChjb25zdCBba2V5LCBzb3VyY2VdIG9mIE9iamVjdC5lbnRyaWVzKG91dHB1dC5hc3NldHMpKSB7XG4gICAgICBhZGQoa2V5LCBzb3VyY2UsIG91dHB1dC5hc3NldHNIYXNoZXNba2V5XSk7XG4gICAgfVxuICAgIC8vIFRoZSBlbnRyeXBvaW50J3Mgb3duIGZpbGUgaXMgZGVsaWJlcmF0ZWx5IGFic2VudCBmcm9tIGl0cyBgYXNzZXRzYCDigJQgdGhlXG4gICAgLy8gTkZUIHRyYWNlIGNvdmVycyB0aGUgY2xvc3VyZSBpdCByZXF1aXJlcywgbm90IGl0c2VsZi4gYGFzc2V0c0hhc2hlc2AgZG9lc1xuICAgIC8vIGNhcnJ5IGl0IChrZXllZCB0aGUgc2FtZSB3YXkpLCB3aGljaCBpcyBhbHNvIHdoYXQgcGlucyB0aGUga2V5IGZvcm1hdC5cbiAgICBjb25zdCBlbnRyeUtleSA9IHRvUG9zaXgocmVsYXRpdmUocmVwb1Jvb3QsIG91dHB1dC5maWxlUGF0aCkpO1xuICAgIGFkZChlbnRyeUtleSwgb3V0cHV0LmZpbGVQYXRoLCBvdXRwdXQuYXNzZXRzSGFzaGVzW2VudHJ5S2V5XSk7XG4gIH1cblxuICAvLyBKb2IgMiwgc2Vjb25kIGhhbGY6IGB3cml0ZVN0YW5kYWxvbmVEaXJlY3RvcnlgIGZpbHRlcnMgYGxvYWRlZEVudkZpbGVzYCB0b1xuICAvLyBleGFjdGx5IHRoZXNlIHR3byBhbmQgY29waWVzIHRoZW07IGBidWlsZC1jb21wbGV0ZS5qc2AgaGFzIG5vIGVudi1maWxlXG4gIC8vIGhhbmRsaW5nIGF0IGFsbCwgc28gdGhleSBhcmUgbm90IGluIGFueSBgYXNzZXRzYCBtYXAuXG4gIGZvciAoY29uc3QgZW52RmlsZSBvZiBFTlZfRklMRVMpIHtcbiAgICBjb25zdCBzb3VyY2UgPSBqb2luKGN0eC5wcm9qZWN0RGlyLCBlbnZGaWxlKTtcbiAgICBpZiAoZXhpc3RzU3luYyhzb3VyY2UpKSB7XG4gICAgICBhZGQodG9Qb3NpeChyZWxhdGl2ZShyZXBvUm9vdCwgc291cmNlKSksIHNvdXJjZSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHN0YWdpbmc7XG59XG5cbi8qKlxuICogSm9iIDIsIHRoaXJkIHBhcnQ6IHRoZSBzdGF0aWMgZmlsZXMgdGhlICpydW50aW1lKiBoYXMgdG8gc2VydmUsIGFuZCB0aGVpclxuICogc291cmNlcy5cbiAqXG4gKiBgb3V0cHV0cy5zdGF0aWNGaWxlc2AgbWl4ZXMgdHdvIHBvcHVsYXRpb25zIHdpdGggdGhlIHNhbWUgYFNUQVRJQ19GSUxFYCB0eXBlOlxuICpcbiAqIC0gKipgPGRpc3REaXI+L3N0YXRpYy8qKmAgYW5kIGBwdWJsaWMvKipgKiog4oCUIHVwbG9hZGVkIHRvIFMzIGJ5XG4gKiAgIGBOZXh0anNTdGF0aWNBc3NldHNgLCBhbmQgQ2xvdWRGcm9udCAvIEFQSSBHYXRld2F5IGFuc3dlciB0aGVtIGJlZm9yZSB0aGVcbiAqICAgcmVxdWVzdCBldmVyIHJlYWNoZXMgdGhlIGNvbXB1dGUuIE5vdCBzdGFnZWQ6IGBwdWJsaWMvYCBhbG9uZSBjYW4gYmVcbiAqICAgaHVuZHJlZHMgb2YgbWVnYWJ5dGVzIGFnYWluc3QgYSAyNTAgTUIgdW56aXBwZWQgTGFtYmRhIGNhcCwgYW5kIGl0IHdvdWxkIGJlXG4gKiAgIGEgc2Vjb25kIGNvcHkgb2YgYnl0ZXMgYWxyZWFkeSBpbiBTMy4gYHB1YmxpYy9gIGlzIG5vdCBpblxuICogICBgb3V0cHV0cy5zdGF0aWNGaWxlc2AgYXQgYWxsIOKAlCBOZXh0LmpzIGxpc3RzIGl0IG9ubHkgZm9yIGBvdXRwdXQ6IFwiZXhwb3J0XCJgXG4gKiAgIOKAlCBhbmQgaXQgaXMgZGVsaWJlcmF0ZWx5IG5vdCBhZGRlZCBoZXJlOiB0aGUgY29udGFpbmVyIHJ1bnRpbWUgbGlzdHMgaXQgb2ZmXG4gKiAgIGRpc2sgYXQgY29sZCBzdGFydCBpbnN0ZWFkLCBhcyBgbmV4dCBzdGFydGAgZG9lcyAoYHJlYWRQdWJsaWNGaWxlc2AgaW5cbiAqICAgYHNyYy9ydW50aW1lL3B1YmxpYy1maWxlcy50c2ApLCBiZWNhdXNlIG9ubHkgdGhlIGRpc2sga25vd3Mgd2hhdCBhbiBhcHAnc1xuICogICBgcG9zdGJ1aWxkYCB3cm90ZSBpbnRvIGl0IGFmdGVyIHRoaXMgaG9vayByYW4uXG4gKiAtICoqZXZlcnl0aGluZyBlbHNlKiosIGFsbCBvZiBpdCB1bmRlciBgPGRpc3REaXI+L3NlcnZlci9gIOKAlCBgNDA0Lmh0bWxgLFxuICogICBgNTAwLmh0bWxgLCBgZmF2aWNvbi5pY28uYm9keWAsIGFuZCBmdWxseS1zdGF0aWMgUGFnZXMgUm91dGVyIEhUTUwuIE5vdGhpbmdcbiAqICAgaW4gZnJvbnQgb2YgdGhlIGNvbXB1dGUgc2VydmVzIHRoZXNlLCBzbyB0aGV5IGFyZSBzdGFnZWQuIEJvdW5kZWQgYnkgcm91dGVcbiAqICAgY291bnQgYW5kIHNtYWxsLlxuICpcbiAqIFRoZSBwYXRobmFtZSDihpIga2V5IG1hcCBpcyByZXR1cm5lZCBmb3IgKmFsbCogb2YgdGhlbSwgYmVjYXVzZSBkaXNwYXRjaCBoYXMgdG9cbiAqIHJlc29sdmUgYSBwYXRobmFtZSB0byBcInN0YXRpYyBmaWxlLCBub3QgYSA0MDRcIiBlaXRoZXIgd2F5OyB0aGUgcnVudGltZSA0MDRzIGlmXG4gKiB0aGUgZmlsZSB0dXJucyBvdXQgbm90IHRvIGJlIGluIHRoZSBwYWNrYWdlLCB3aGljaCBpcyBvbmx5IHJlYWNoYWJsZSB3aGVuIHRoZVxuICogZGlzdHJpYnV0aW9uIGlzIG1pc3JvdXRlZC5cbiAqXG4gKiBTdGFnaW5nIGlzIHtAbGluayBzdGFnZVNlcnZlZFN0YXRpY0ZpbGVzfSwgYXBwbGllZCBvbmNlIHBlciBkZXBsb3ltZW50IHJvb3QuXG4gKi9cbmZ1bmN0aW9uIGNvbGxlY3RTdGF0aWNGaWxlcyhjdHg6IEJ1aWxkQ29tcGxldGVDb250ZXh0KTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gIGNvbnN0IHsgcmVwb1Jvb3QgfSA9IGN0eDtcbiAgY29uc3QgYmFzZVBhdGggPSBjdHguY29uZmlnLmJhc2VQYXRoIHx8IFwiXCI7XG4gIGNvbnN0IHN0YXRpY0ZpbGVzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgY29uc3QgcGFnZXNEaXIgPSBqb2luKGN0eC5kaXN0RGlyLCBcInNlcnZlclwiLCBcInBhZ2VzXCIpICsgc2VwO1xuXG4gIGZvciAoY29uc3Qgb3V0cHV0IG9mIGN0eC5vdXRwdXRzLnN0YXRpY0ZpbGVzKSB7XG4gICAgY29uc3Qga2V5ID0gdG9Qb3NpeChyZWxhdGl2ZShyZXBvUm9vdCwgb3V0cHV0LmZpbGVQYXRoKSk7XG4gICAgY29uc3QgcGF0aG5hbWVzID0gcm91dGFibGVQYXRobmFtZXMoXG4gICAgICBvdXRwdXQucGF0aG5hbWUsXG4gICAgICBiYXNlUGF0aCxcbiAgICAgIG91dHB1dC5maWxlUGF0aC5zdGFydHNXaXRoKHBhZ2VzRGlyKSxcbiAgICApO1xuICAgIGZvciAoY29uc3QgcGF0aG5hbWUgb2YgcGF0aG5hbWVzKSB7XG4gICAgICBjb25zdCBleGlzdGluZyA9IHN0YXRpY0ZpbGVzLmdldChwYXRobmFtZSk7XG4gICAgICBpZiAoZXhpc3RpbmcgIT09IHVuZGVmaW5lZCAmJiBleGlzdGluZyAhPT0ga2V5KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgJHtMT0dfUFJFRklYfSBUd28gc3RhdGljIGZpbGVzIGNsYWltIHRoZSBwYXRobmFtZSBgICtcbiAgICAgICAgICAgIGBcIiR7cGF0aG5hbWV9XCIgKFwiJHtleGlzdGluZ31cIiBhbmQgXCIke2tleX1cIikuIERpc3BhdGNoIGNhbm5vdCBgICtcbiAgICAgICAgICAgIGBjaG9vc2UgYmV0d2VlbiB0aGVtLmAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBzdGF0aWNGaWxlcy5zZXQocGF0aG5hbWUsIGtleSk7XG4gICAgfVxuICB9XG5cbiAgLy8gU29ydGVkIGJlY2F1c2Ugb2JqZWN0IGtleXMga2VlcCBpbnNlcnRpb24gb3JkZXIsIGFuZCBhIGJ5dGUtc3RhYmxlXG4gIC8vIGBtYW5pZmVzdC5qc29uYCBpcyB3aGF0IGtlZXBzIGl0IGRpZmZhYmxlIGFuZCB0aGUgQ0RLIGFzc2V0IGhhc2ggZnJvbVxuICAvLyBjaHVybmluZy5cbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhcbiAgICBbLi4uc3RhdGljRmlsZXNdLnNvcnQoKFthXSwgW2JdKSA9PiAoYSA8IGIgPyAtMSA6IDEpKSxcbiAgKTtcbn1cblxuLyoqXG4gKiBUaGUgcGF0aG5hbWVzIGFuIG91dHB1dCBhbnN3ZXJzLCB3aGljaCBmb3Igb25lIHNoYXBlIGlzIG5vdCB0aGUgcGF0aG5hbWVcbiAqIGBuZXh0IGJ1aWxkYCByZXBvcnRlZC5cbiAqXG4gKiAqKkEgUGFnZXMgUm91dGVyIGhvbWUgcGFnZSBhcnJpdmVzIGFzIGAvaW5kZXhgLioqIFRoZSBhZGFwdGVyIGhvb2sgZGVyaXZlcyBldmVyeVxuICogUGFnZXMgcGF0aG5hbWUgd2l0aCBgbm9ybWFsaXplUGFnZVBhdGgocGFnZSlgLCBhbmQgYG5vcm1hbGl6ZVBhZ2VQYXRoKFwiL1wiKWAgaXNcbiAqIGBcIi9pbmRleFwiYCAoYG5leHQvZGlzdC9zaGFyZWQvbGliL3BhZ2UtcGF0aC9ub3JtYWxpemUtcGFnZS1wYXRoLmpzYCkg4oCUIGZvciB0aGVcbiAqIGBQQUdFU2Agb3V0cHV0IG9mIGFuIFNTRyBvciBTU1IgaG9tZSBwYWdlIGFuZCBmb3IgdGhlIGBTVEFUSUNfRklMRWAgb2YgYVxuICogZnVsbHktc3RhdGljIG9uZSBhbGlrZS4gYC9pbmRleGAgaXMgbm90IGEgVVJMIGFueW9uZSByZXF1ZXN0cywgYW5kIG5vdGhpbmcgZWxzZVxuICogaW4gdGhlIG91dHB1dHMgY2FycmllcyBgL2AgZm9yIHRoYXQgcGFnZSwgc28gd2l0aG91dCB0aGlzIHRoZSBob21lIHBhZ2UgaXMgaW5cbiAqIG5laXRoZXIgYG1hbmlmZXN0LnBhdGhuYW1lc2Agbm9yIGBtYW5pZmVzdC5lbnRyeXBvaW50c2AvYHN0YXRpY0ZpbGVzYCwgYW5kIGV2ZXJ5XG4gKiByZXF1ZXN0IHRvIGAvYCA0MDRzIHdoaWxlIGV2ZXJ5IG90aGVyIHBhZ2Ugb2YgdGhlIHNhbWUgYXBwIHNlcnZlcy4gTWVhc3VyZWRcbiAqIGFnYWluc3QgbmV4dC5qcydzIGB0ZXN0L2UyZS9uZXctbGluay1iZWhhdmlvcmAgKGAvYCByZXR1cm5lZCB0aGUgYnVpbHQtaW4gNDA0LFxuICogdGhlIHNpeCBvdGhlciBwYWdlcyB3ZXJlIGZpbmUpIGFuZCBgdGVzdC9lMmUvcHJlcmVuZGVyLXByZXZpZXdgICh0aGUgb25lIGNhc2VcbiAqIHRoYXQgZmV0Y2hlcyBgL2AgZ290IHRoZSA0MDQgcGFnZSdzIEhUTUwsIHRoZSBlaWdodCB0aGF0IGhpdCBBUEkgcm91dGVzIHBhc3NlZCkuXG4gKlxuICogUGFnZXMgUm91dGVyIG91dHB1dHMgb25seSwgd2hpY2ggaXMgd2hhdCBgZnJvbVBhZ2VzUm91dGVyYCBzYXlzLiBBcHAgUm91dGVyXG4gKiByZXBvcnRzIGl0cyBob21lIHBhZ2UgYXMgYC9gIGFuZCBvbmx5IHRoZSBSU0Mgc2libGluZyBhcyBgL2luZGV4LnJzY2AsIHNvIGFuXG4gKiBBcHAgUm91dGVyIGAvaW5kZXhgIGlzIGBhcHAvaW5kZXgvcGFnZS50c3hgIOKAlCBhIHJlYWwgcm91dGUgYXQgYC9pbmRleGAsIGFuZFxuICogbWFwcGluZyBpdCB0byBgL2AgbWFkZSBhbiBhcHAgd2l0aCBib3RoIHBhZ2VzIGZhaWwgdGhlIGJ1aWxkIG9uIGEgcGF0aG5hbWVcbiAqIGNvbGxpc2lvbiwgYW5kIGFuIGFwcCB3aXRoIG9ubHkgdGhlIHNlY29uZCBzZXJ2ZSBpdCBhdCBgL2AuIFRoZSBzYW1lIGdvZXMgZm9yXG4gKiBhIGBwdWJsaWMvaW5kZXhgIGZpbGUuXG4gKlxuICogQm90aCBwYXRobmFtZXMgYXJlIHJlZ2lzdGVyZWQuIGAvYCBiZWNhdXNlIGl0IGlzIHRoZSByZWFsIG9uZTsgYC9pbmRleGAgYmVjYXVzZVxuICogbmV4dCdzIG93biBtaW5pbWFsIG1vZGUg4oCUIHRoZSBtb2RlIG91ciBydW50aW1lIHJ1bnMgaW4g4oCUIGFjY2VwdHMgaXQsIHJld3JpdGluZ1xuICogYHJlcS51cmxgIGFuZCBgeC1tYXRjaGVkLXBhdGhgIGZyb20gYC9pbmRleGAgdG8gYC9gIGJlZm9yZSBtYXRjaGluZ1xuICogKGBiYXNlLXNlcnZlci50c2AsIFwiaW4gbWluaW1hbCBtb2RlXCIpLCBzbyBkcm9wcGluZyBpdCB3b3VsZCBiZSBhIGRpdmVyZ2VuY2UgaW5cbiAqIHRoZSBvdGhlciBkaXJlY3Rpb24uXG4gKlxuICogVW5hbWJpZ3VvdXMgd2l0aGluIHRoZSBQYWdlcyBSb3V0ZXIgZGVzcGl0ZSB0aGUgY29sbGlzaW9uIGl0IGxvb2tzIGxpa2U6XG4gKiBgbm9ybWFsaXplUGFnZVBhdGgoXCIvaW5kZXhcIilgIGlzIGBcIi9pbmRleC9pbmRleFwiYCwgc28gYSByZXBvcnRlZCBgL2luZGV4YCBjYW5cbiAqIG9ubHkgaGF2ZSBjb21lIGZyb20gdGhlIHBhZ2UgYC9gLlxuICogVGhlIGRhdGEgcm91dGUgb2YgdGhlIHNhbWUgcGFnZSwgYC9fbmV4dC9kYXRhLzxidWlsZElkPi9pbmRleC5qc29uYCwgYW5kIGFuIEFwcFxuICogUm91dGVyIGAvaW5kZXgucnNjYCBhcmUgYm90aCByZWFsIFVSTHMgYW5kIGFyZSBsZWZ0IGFsb25lIGJ5IHRoZSBleGFjdCBtYXRjaC5cbiAqL1xuZnVuY3Rpb24gcm91dGFibGVQYXRobmFtZXMoXG4gIHBhdGhuYW1lOiBzdHJpbmcsXG4gIGJhc2VQYXRoOiBzdHJpbmcsXG4gIGZyb21QYWdlc1JvdXRlcjogYm9vbGVhbixcbik6IHN0cmluZ1tdIHtcbiAgaWYgKCFmcm9tUGFnZXNSb3V0ZXIgfHwgcGF0aG5hbWUgIT09IGAke2Jhc2VQYXRofS9pbmRleGApIHtcbiAgICByZXR1cm4gW3BhdGhuYW1lXTtcbiAgfVxuICAvLyBgYmFzZVBhdGggfHwgXCIvXCJgLCBub3QgYCR7YmFzZVBhdGh9L2A6IHdpdGggYGJhc2VQYXRoOiBcIi9wcm9kXCJgIHRoZSBob21lIHBhZ2VcbiAgLy8gaXMgYC9wcm9kYCwgd2hpY2ggaXMgaG93IHRoZSBBcHAgUm91dGVyIGZpeHR1cmVzIHJlcG9ydCB0aGVpcnMuXG4gIHJldHVybiBbYmFzZVBhdGggfHwgXCIvXCIsIHBhdGhuYW1lXTtcbn1cblxuLyoqXG4gKiBBZGQgdGhlIHN0YXRpYyBmaWxlcyB0aGUgKnJ1bnRpbWUqIHNlcnZlcyB0byBhIHN0YWdpbmcgcGxhbiDigJQgdGhlIFwiZXZlcnl0aGluZ1xuICogZWxzZVwiIHBvcHVsYXRpb24gZGVzY3JpYmVkIG9uIHtAbGluayBjb2xsZWN0U3RhdGljRmlsZXN9LCBhbGwgb2YgaXQgdW5kZXJcbiAqIGA8ZGlzdERpcj4vc2VydmVyL2AuXG4gKlxuICogU2VwYXJhdGUgZnJvbSBidWlsZGluZyB0aGUgbWFuaWZlc3QncyBgc3RhdGljRmlsZXNgIG1hcCBiZWNhdXNlIHRoZSBtYXAgaXMgdGhlXG4gKiBzYW1lIGZvciBldmVyeSBncm91cCB3aGlsZSB0aGUgc3RhZ2luZyBpcyBhcHBsaWVkIG9uY2UgcGVyIGRlcGxveW1lbnQgcm9vdDpcbiAqIGFueSBncm91cCBjYW4gYmUgYXNrZWQgZm9yIGAvNDA0YCwgc28gZXZlcnkgZ3JvdXAgc2hpcHMgdGhlc2UuXG4gKi9cbmZ1bmN0aW9uIHN0YWdlU2VydmVkU3RhdGljRmlsZXMoXG4gIGN0eDogQnVpbGRDb21wbGV0ZUNvbnRleHQsXG4gIHN0YWdpbmc6IE1hcDxzdHJpbmcsIHN0cmluZz4sXG4pOiB2b2lkIHtcbiAgY29uc3QgeyByZXBvUm9vdCwgZGlzdERpciB9ID0gY3R4O1xuICBjb25zdCBjbGllbnRTdGF0aWNEaXIgPSBqb2luKGRpc3REaXIsIFwic3RhdGljXCIpICsgc2VwO1xuXG4gIGZvciAoY29uc3Qgb3V0cHV0IG9mIGN0eC5vdXRwdXRzLnN0YXRpY0ZpbGVzKSB7XG4gICAgY29uc3Qgc2VydmVkQnlTMyA9XG4gICAgICBvdXRwdXQuZmlsZVBhdGguc3RhcnRzV2l0aChjbGllbnRTdGF0aWNEaXIpIHx8XG4gICAgICAhb3V0cHV0LmZpbGVQYXRoLnN0YXJ0c1dpdGgoZGlzdERpciArIHNlcCk7XG4gICAgaWYgKHNlcnZlZEJ5UzMpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCBrZXkgPSB0b1Bvc2l4KHJlbGF0aXZlKHJlcG9Sb290LCBvdXRwdXQuZmlsZVBhdGgpKTtcbiAgICBhc3NlcnRTdGFnaW5nS2V5KGtleSwgb3V0cHV0LmZpbGVQYXRoKTtcbiAgICBzdGFnaW5nLnNldChrZXksIG91dHB1dC5maWxlUGF0aCk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgaW52YXJpYW50IGJlaGluZCBgbWFuaWZlc3QucmVsYXRpdmVQcm9qZWN0RGlyYDogYG5leHQgYnVpbGRgIG11c3QgcnVuIGZyb21cbiAqIHRoZSBwcm9qZWN0IGRpcmVjdG9yeS5cbiAqXG4gKiBOZXh0IGlubGluZXMgYHJlbGF0aXZlKHByb2Nlc3MuY3dkKCksIHByb2plY3REaXIpYCBpbnRvIGV2ZXJ5IGVudHJ5cG9pbnRcbiAqIChgZGVmaW5lLWVudi5qc2ApIGFuZCB0aGUgYnVpbHQgY29kZSByZXNvbHZlcyBpdCBhZ2FpbnN0IHRoZSAqcnVudGltZSpcbiAqIGBwcm9jZXNzLmN3ZCgpYC4gS2VlcGluZyBidWlsZCBjd2QgYW5kIHByb2plY3QgZGlyIGVxdWFsIG1ha2VzIHRoYXQgaW5saW5lZFxuICogdmFsdWUgYFwiXCJgLCBzbyB0aGUgcnVudGltZSBvbmx5IGhhcyB0byBgY2hkaXJgIHRvIHRoZSBzdGFnZWQgcHJvamVjdCBkaXIuIEFcbiAqIGJ1aWxkIHJ1biBmcm9tIGVsc2V3aGVyZSB3b3VsZCBpbmxpbmUgYSBub24tZW1wdHkgcmVsYXRpdmUgcGF0aCDigJQgb2Z0ZW4gb25lXG4gKiBwb2ludGluZyBvdXRzaWRlIHRoZSBzdGFnaW5nIHRyZWUg4oCUIGFuZCBldmVyeSBlbnRyeXBvaW50IHdvdWxkIGZhaWwgdG8gZmluZFxuICogYHJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYCBhdCBydW50aW1lIHdpdGggbm8gaGludCBhcyB0byB3aHkuXG4gKi9cbmZ1bmN0aW9uIGFzc2VydEJ1aWxkQ3dkKGN0eDogQnVpbGRDb21wbGV0ZUNvbnRleHQsIGJ1aWxkQ3dkOiBzdHJpbmcpOiB2b2lkIHtcbiAgY29uc3QgY3dkID0gcmVzb2x2ZShidWlsZEN3ZCk7XG4gIGlmIChjd2QgPT09IHJlc29sdmUoY3R4LnByb2plY3REaXIpKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgJHtMT0dfUFJFRklYfSBcXGBuZXh0IGJ1aWxkXFxgIG11c3QgcnVuIGZyb20gdGhlIE5leHQuanMgcHJvamVjdCBgICtcbiAgICAgIGBkaXJlY3RvcnkuIEl0IHJhbiBmcm9tIFwiJHtjd2R9XCIgd2l0aCB0aGUgcHJvamVjdCBhdCBgICtcbiAgICAgIGBcIiR7Y3R4LnByb2plY3REaXJ9XCIuIE5leHQuanMgYmFrZXMgdGhlIHJlbGF0aXZlIHBhdGggYmV0d2VlbiB0aG9zZSB0d28gYCArXG4gICAgICBgaW50byBldmVyeSBidWlsdCBlbnRyeXBvaW50LCBhbmQgY2RrLW5leHRqcyBjYW5ub3QgcmVwcm9kdWNlIHRoYXQgbGF5b3V0IGAgK1xuICAgICAgYGluIHRoZSBkZXBsb3ltZW50IHBhY2thZ2UuIENoYW5nZSBkaXJlY3RvcnkgZmlyc3QgKFxcYGNkIGAgK1xuICAgICAgYCR7cmVsYXRpdmUoY3dkLCBjdHgucHJvamVjdERpcikgfHwgXCIuXCJ9ICYmIG5leHQgYnVpbGRcXGApIGluc3RlYWQgb2YgYCArXG4gICAgICBgcGFzc2luZyB0aGUgZGlyZWN0b3J5IGFzIGFuIGFyZ3VtZW50OyBpbiBhIG1vbm9yZXBvLCBydW4gdGhlIGFwcCdzIG93biBgICtcbiAgICAgIGBidWlsZCBzY3JpcHQgZnJvbSBpdHMgZGlyZWN0b3J5IChlLmcuIFxcYHBucG0gLS1maWx0ZXIgPGFwcD4gYnVpbGRcXGAsIGAgK1xuICAgICAgYHdoaWNoIHJ1bnMgaW4gdGhlIHBhY2thZ2UgZGlyZWN0b3J5KS5gLFxuICApO1xufVxuXG5mdW5jdGlvbiBhZGRFbnRyeXBvaW50KFxuICBlbnRyeXBvaW50czogUmVjb3JkPHN0cmluZywgQWRhcHRlckVudHJ5cG9pbnQ+LFxuICByZXBvUm9vdDogc3RyaW5nLFxuICBvdXRwdXQ6IHsgaWQ6IHN0cmluZzsgcGF0aG5hbWU6IHN0cmluZzsgZmlsZVBhdGg6IHN0cmluZyB9LFxuICB0eXBlOiBBZGFwdGVyRW50cnlwb2ludFR5cGUsXG4gIGJhc2VQYXRoOiBzdHJpbmcsXG4pOiB2b2lkIHtcbiAgY29uc3QgZmlsZVBhdGggPSB0b1Bvc2l4KHJlbGF0aXZlKHJlcG9Sb290LCBvdXRwdXQuZmlsZVBhdGgpKTtcbiAgY29uc3QgcGF0aG5hbWVzID0gcm91dGFibGVQYXRobmFtZXMoXG4gICAgb3V0cHV0LnBhdGhuYW1lLFxuICAgIGJhc2VQYXRoLFxuICAgIHR5cGUgPT09IFwicGFnZVwiLFxuICApO1xuICBmb3IgKGNvbnN0IHBhdGhuYW1lIG9mIHBhdGhuYW1lcykge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gZW50cnlwb2ludHNbcGF0aG5hbWVdO1xuICAgIGlmIChleGlzdGluZyAmJiBleGlzdGluZy5maWxlUGF0aCAhPT0gZmlsZVBhdGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7TE9HX1BSRUZJWH0gVHdvIGJ1aWxkIG91dHB1dHMgY2xhaW0gdGhlIHBhdGhuYW1lIFwiJHtwYXRobmFtZX1cIiBgICtcbiAgICAgICAgICBgKFwiJHtleGlzdGluZy5maWxlUGF0aH1cIiBhbmQgXCIke2ZpbGVQYXRofVwiKS4gRGlzcGF0Y2ggY2Fubm90IGNob29zZSBgICtcbiAgICAgICAgICBgYmV0d2VlbiB0aGVtLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBlbnRyeXBvaW50c1twYXRobmFtZV0gPSB7IGlkOiBvdXRwdXQuaWQsIGZpbGVQYXRoLCB0eXBlIH07XG4gIH1cbn1cblxuLyoqXG4gKiBBZGQgdGhlICpwcmVyZW5kZXIqIHBhdGhuYW1lcyB0aGF0IG5vIGludm9jYWJsZSBvdXRwdXQgY2xhaW1zIGFuZCB0aGF0IHJvdXRpbmdcbiAqIGNhbm5vdCBvdGhlcndpc2UgcmVhY2guXG4gKlxuICogYHJlc29sdmVSb3V0ZXNgIGNhbiBvbmx5IG1hdGNoIGEgcGF0aG5hbWUgcHJlc2VudCBpbiBgbWFuaWZlc3QucGF0aG5hbWVzYCwgYW5kXG4gKiBmb3IgYSBkeW5hbWljIG1hdGNoIGl0IHJldHVybnMgdGhlICoqdGVtcGxhdGUqKiBpdCBtYXRjaGVkLiBSb3V0ZXMgYW5kIHN0YXRpY1xuICogZmlsZXMgY292ZXIgbW9zdCBvZiB0aGF0OyB0d28gc2hhcGVzIHRoZXkgbWlzczpcbiAqXG4gKiAxLiAqKlRlbXBsYXRlcy4qKiBBIHJlcXVlc3QgZm9yIGAvX25leHQvZGF0YS88YnVpbGRJZD4vZnIvYmxvZy9oZWxsby5qc29uYCBvbmx5XG4gKiAgICByZXNvbHZlcyBpZiBgL19uZXh0L2RhdGEvPGJ1aWxkSWQ+L2ZyL2Jsb2cvW3NsdWddLmpzb25gIGlzIGxpc3RlZCwgYW5kIHRoYXRcbiAqICAgIHBhdGhuYW1lIGV4aXN0cyBzb2xlbHkgYXMgYSBgcHJlcmVuZGVyc2AgZW50cnkuXG4gKiAxYi4gKipBIHN0YXRpYyBgZ2V0U3RhdGljUHJvcHNgIHBhZ2UncyBkYXRhIHJvdXRlLioqIGAvX25leHQvZGF0YS88YnVpbGRJZD4vZ3NwLmpzb25gXG4gKiAgICBoYXMgbm8gdGVtcGxhdGUgdG8gbWF0Y2ggYW5kIG5vIHJ1bGUgb2YgaXRzIG93bjogYG5leHQgYnVpbGRgIG9ubHkgZW1pdHMgYVxuICogICAgYGR5bmFtaWNSb3V0ZXNgIHJ1bGUgZm9yIGEgZGF0YSByb3V0ZSB3aGVuIHRoZSBwYWdlIGlzIGR5bmFtaWMgKm9yKiB0aGUgYXBwIGhhc1xuICogICAgbWlkZGxld2FyZSAoYGJ1aWxkLWNvbXBsZXRlLnRzYCwgYG5lZWRzTWlkZGxld2FyZVJlc29sdmVSb3V0ZXNgLCB3aGljaCBpcyBhbHNvXG4gKiAgICB3aGF0IGByb3V0aW5nLnNob3VsZE5vcm1hbGl6ZU5leHREYXRhYCByZXBvcnRzKS4gV2l0aG91dCBtaWRkbGV3YXJlIE5leHQuanNcbiAqICAgIGV4cGVjdHMgdGhlIHBsYXRmb3JtIHRvIHNlcnZlIHRoZSBkYXRhIHJvdXRlIGFzIGFuIG91dHB1dCwgYnkgcGF0aG5hbWUg4oCUIHNvIGFcbiAqICAgIGNvbmNyZXRlIGRhdGEtcm91dGUgcHJlcmVuZGVyIGlzIHJlZ2lzdGVyZWQgd2hhdGV2ZXIgdGhlIHJ1bGVzIHNheS4gTWlzc2luZyBpdFxuICogICAgdHVybmVkIGV2ZXJ5IGNsaWVudC1zaWRlIG5hdmlnYXRpb24gaW50byBzdWNoIGEgcGFnZSBpbnRvIGEgZnVsbCBwYWdlIGxvYWQsXG4gKiAgICBiZWNhdXNlIHRoZSByb3V0ZXIncyBgLmpzb25gIGZldGNoIDQwNCdkOiBtZWFzdXJlZCBhZ2FpbnN0XG4gKiAgICBgdGVzdC9lMmUvbm8tcGFnZS1wcm9wc2AuIE9ubHkgd2hlbiBubyAqdW5nYXRlZCogcnVsZSBtYXRjaGVzLCBmb3IgdGhlIHJlYXNvblxuICogICAgYmVsb3cg4oCUIGEgZHluYW1pYyBwYWdlJ3MgYC/igKYvYmxvZy9oZWxsby5qc29uYCBtdXN0IGtlZXAgcmVzb2x2aW5nIHRvIGl0c1xuICogICAgYFtzbHVnXS5qc29uYCB0ZW1wbGF0ZSwgd2hpY2ggaXMgd2hlcmUgYG54dFBzbHVnYCBjb21lcyBmcm9tLlxuICogMi4gKipDb25jcmV0ZSBwYXRobmFtZXMgd2hvc2UgZHluYW1pYyByb3V0ZSBydWxlIGlzIGdhdGVkLioqIEEgcm91dGUgd2hvc2UgcGFyYW1zXG4gKiAgICBjYW4gbmV2ZXIgYmUgZmlsbGVkIGF0IHJlcXVlc3QgdGltZSDigJQgcm9vdCBwYXJhbXMgYXJlIHRoZSBjYXNlIHRoYXQgcHJvZHVjZWRcbiAqICAgIHRoaXMsIGBhcHAvW2xvY2FsZV0vcGFnZS50c3hgIHdpdGggYGdlbmVyYXRlU3RhdGljUGFyYW1zKClgIGFuZCBub1xuICogICAgYGFwcC9sYXlvdXQudHN4YCDigJQgZ2V0cyBpdHMgYGR5bmFtaWNSb3V0ZXNgIHJ1bGUgZW1pdHRlZCB3aXRoIGEgZHJhZnQtbW9kZVxuICogICAgYGhhc2Agb24gYF9fcHJlcmVuZGVyX2J5cGFzc2AuIE5leHQuanMgaXMgc2F5aW5nOiBpbnZva2UgdGhlIGZ1bmN0aW9uIG9ubHkgaW5cbiAqICAgIGRyYWZ0IG1vZGUsIGFuZCBvdGhlcndpc2Ugc2VydmUgdGhlIHByZXJlbmRlciB5b3Ugd2VyZSBoYW5kZWQuIFZlcmNlbCdzIENETlxuICogICAgZG9lcyB0aGF0IGZyb20gdGhlIG91dHB1dCBpdHNlbGY7IHdlIHJvdXRlIHRoZSByZXF1ZXN0IHRvIHRoZSBvd25pbmdcbiAqICAgIGVudHJ5cG9pbnQsIHdoaWNoIGFuc3dlcnMgaXQgb3V0IG9mIHRoZSBzZWVkZWQgY2FjaGUuIFdpdGhvdXQgdGhpcywgYC9lbmAgaXMgYVxuICogICAgNDA0IHdoaWxlIGBuZXh0IHN0YXJ0YCByZW5kZXJzIGl0IOKAlCBhbmQgc28gaXMgZXZlcnkgYC5yc2NgL2Auc2VnbWVudHNgXG4gKiAgICB2YXJpYW50LCB3aGljaCBpcyB3aHkgYSBjbGllbnQtc2lkZSBuYXZpZ2F0aW9uIGludG8gc3VjaCBhbiBhcHAgbmV2ZXJcbiAqICAgIGNvbXBsZXRlcy5cbiAqXG4gKiBBIGNvbmNyZXRlIHBhdGhuYW1lIGlzIGFkZGVkIG9ubHkgd2hlbiBhIGdhdGVkIHJ1bGUgbWF0Y2hlcyBpdCBhbmQgbm8gdW5nYXRlZFxuICogb25lIGRvZXMg4oCUIHRoZSBzZXQgdGhhdCB3b3VsZCA0MDQgdG9kYXkgKmFuZCogdGhhdCByb3V0aW5nIGNhbiBzdGlsbCBwcm9kdWNlLlxuICogQWRkaW5nIHRoZW0gdW5jb25kaXRpb25hbGx5IHdhcyBtZWFzdXJlZCB0byBiZSBhY3RpdmVseSB3cm9uZyB0d2ljZSBvdmVyOlxuICogYC9pc3IvMWAgcmVzb2x2ZXMgdG8gaXRzZWxmIHJhdGhlciB0aGFuIHRvIGAvaXNyL1tpZF1gLCBsb3NpbmcgdGhlIGBueHRQaWRgXG4gKiBxdWVyeSBwYXJhbSB0aGUgcm91dGUgbmVlZHMsIGFuZCBwYXRobmFtZXMgbm8gcnVsZSBtYXRjaGVzIGF0IGFsbCAoYSBzdGF0aWNcbiAqIHJvdXRlJ3MgYC5zZWdtZW50cy/igKZgIG91dHB1dHMsIHdoaWNoIGByZXNvbHZlUm91dGVzYCBuZXZlciBhc2tzIGZvcikgYXJlIGRlYWRcbiAqIG1hbmlmZXN0IHdlaWdodC4gTWF0Y2hpbmcgbWlycm9ycyBgcmVzb2x2ZVJvdXRlc2AsIHdoaWNoIGlzIGNhc2UtaW5zZW5zaXRpdmUgYnlcbiAqIGRlZmF1bHQuXG4gKlxuICogVGhlIG93bmluZyBlbnRyeXBvaW50IGNvbWVzIGZyb20gYHByZXJlbmRlci5yb3V0ZWAsIHdoaWNoIGlzIHRoZSB1bnByZWZpeGVkIGFuZFxuICogdW5sb2NhbGl6ZWQgc291cmNlIHJvdXRlIChgL2Jsb2cvW3NsdWddYCksIGhlbmNlIHRoZSBiYXNlUGF0aC10aGVuLWJhcmUgbGFkZGVyLlxuICogTG9jYWxlIHZhcmlhbnRzIG9mIG9uZSBwYWdlIHNoYXJlIGEgYGZpbGVQYXRoYCwgc28gYW55IGxvY2FsZSdzIGVudHJ5cG9pbnQgaXNcbiAqIHRoZSByaWdodCB0YXJnZXQuIEFuIFJTQyBvciBzZWdtZW50LXByZWZldGNoIHBhdGhuYW1lIHByZWZlcnMgdGhlIHJvdXRlJ3MgYC5yc2NgXG4gKiBlbnRyeXBvaW50LCBiZWNhdXNlIHRoYXQgaXMgdGhlIGtleSBgcmVzb2x2ZVJvdXRlc2AgcmVzb2x2ZXMgc3VjaCBhIHJlcXVlc3QgdG8uXG4gKi9cbmZ1bmN0aW9uIGFkZFByZXJlbmRlclBhdGhuYW1lcyhcbiAgZW50cnlwb2ludHM6IFJlY29yZDxzdHJpbmcsIEFkYXB0ZXJFbnRyeXBvaW50PixcbiAgcHJlcmVuZGVyczogQWRhcHRlck91dHB1dHNbXCJwcmVyZW5kZXJzXCJdLFxuICBkeW5hbWljUm91dGVzOiB7XG4gICAgc291cmNlUmVnZXg6IHN0cmluZztcbiAgICBoYXM/OiB1bmtub3duW107XG4gICAgbWlzc2luZz86IHVua25vd25bXTtcbiAgfVtdLFxuICBiYXNlUGF0aDogc3RyaW5nLFxuICBkYXRhUm91dGVQcmVmaXg6IHN0cmluZyxcbik6IHZvaWQge1xuICBjb25zdCBtYXRjaGVycyA9IGR5bmFtaWNSb3V0ZXMubWFwKChyb3V0ZSkgPT4gKHtcbiAgICByZWdleDogbmV3IFJlZ0V4cChyb3V0ZS5zb3VyY2VSZWdleCwgXCJpXCIpLFxuICAgIGdhdGVkOiBCb29sZWFuKHJvdXRlLmhhcz8ubGVuZ3RoIHx8IHJvdXRlLm1pc3Npbmc/Lmxlbmd0aCksXG4gIH0pKTtcbiAgY29uc3QgbWF0Y2hpbmdSdWxlcyA9IChwYXRobmFtZTogc3RyaW5nKSA9PlxuICAgIG1hdGNoZXJzLmZpbHRlcigoeyByZWdleCB9KSA9PiByZWdleC50ZXN0KHBhdGhuYW1lKSk7XG4gIGNvbnN0IG9ubHlHYXRlZFJ1bGVzTWF0Y2ggPSAocGF0aG5hbWU6IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuICAgIGNvbnN0IG1hdGNoZWQgPSBtYXRjaGluZ1J1bGVzKHBhdGhuYW1lKTtcbiAgICByZXR1cm4gbWF0Y2hlZC5sZW5ndGggPiAwICYmIG1hdGNoZWQuZXZlcnkoKHsgZ2F0ZWQgfSkgPT4gZ2F0ZWQpO1xuICB9O1xuICAvKipcbiAgICogTm90aGluZyByZWFjaGVzIHRoaXMgcGF0aG5hbWUgYXQgcmVxdWVzdCB0aW1lOiBlaXRoZXIgbm8gcnVsZSBtYXRjaGVzIGl0IG9yXG4gICAqIGV2ZXJ5IHJ1bGUgdGhhdCBkb2VzIGlzIGdhdGVkLiBUaGUgZ2F0ZWQgaGFsZiBpcyB7QGxpbmsgb25seUdhdGVkUnVsZXNNYXRjaH07XG4gICAqIHRoZSBcIm5vIHJ1bGUgYXQgYWxsXCIgaGFsZiBvbmx5IGV2ZXIgaG9sZHMgZm9yIGEgZGF0YSByb3V0ZSwgYmVjYXVzZSBhIHBhZ2Unc1xuICAgKiBvd24gcGF0aG5hbWUgaXMgYW4gb3V0cHV0LlxuICAgKi9cbiAgY29uc3Qgbm90aGluZ1VuZ2F0ZWRNYXRjaGVzID0gKHBhdGhuYW1lOiBzdHJpbmcpOiBib29sZWFuID0+XG4gICAgbWF0Y2hpbmdSdWxlcyhwYXRobmFtZSkuZXZlcnkoKHsgZ2F0ZWQgfSkgPT4gZ2F0ZWQpO1xuXG4gIGNvbnN0IG9ycGhhbnM6IHN0cmluZ1tdID0gW107XG4gIGZvciAoY29uc3QgcHJlcmVuZGVyIG9mIHByZXJlbmRlcnMpIHtcbiAgICBjb25zdCB7IHBhdGhuYW1lIH0gPSBwcmVyZW5kZXI7XG4gICAgaWYgKGVudHJ5cG9pbnRzW3BhdGhuYW1lXSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IGlzVGVtcGxhdGUgPSBwYXRobmFtZS5pbmNsdWRlcyhcIltcIik7XG4gICAgY29uc3QgaXNEYXRhUm91dGUgPVxuICAgICAgcGF0aG5hbWUuc3RhcnRzV2l0aChkYXRhUm91dGVQcmVmaXgpICYmIHBhdGhuYW1lLmVuZHNXaXRoKFwiLmpzb25cIik7XG4gICAgY29uc3QgcmVhY2hhYmxlID0gaXNEYXRhUm91dGVcbiAgICAgID8gbm90aGluZ1VuZ2F0ZWRNYXRjaGVzKHBhdGhuYW1lKVxuICAgICAgOiBvbmx5R2F0ZWRSdWxlc01hdGNoKHBhdGhuYW1lKTtcbiAgICBpZiAoIWlzVGVtcGxhdGUgJiYgIXJlYWNoYWJsZSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IHN1ZmZpeGVzID0gcGF0aG5hbWUuZW5kc1dpdGgoXCIucnNjXCIpID8gW1wiLnJzY1wiLCBcIlwiXSA6IFtcIlwiXTtcbiAgICBjb25zdCBvd25lciA9IHN1ZmZpeGVzXG4gICAgICAuZmxhdE1hcCgoc3VmZml4KSA9PiBbXG4gICAgICAgIGAke2Jhc2VQYXRofSR7cHJlcmVuZGVyLnJvdXRlfSR7c3VmZml4fWAsXG4gICAgICAgIGAke3ByZXJlbmRlci5yb3V0ZX0ke3N1ZmZpeH1gLFxuICAgICAgXSlcbiAgICAgIC5tYXAoKGtleSkgPT4gZW50cnlwb2ludHNba2V5XSlcbiAgICAgIC5maW5kKEJvb2xlYW4pO1xuICAgIGlmICghb3duZXIpIHtcbiAgICAgIG9ycGhhbnMucHVzaChgJHtwYXRobmFtZX0gKHJvdXRlOiBcIiR7cHJlcmVuZGVyLnJvdXRlfVwiKWApO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGVudHJ5cG9pbnRzW3BhdGhuYW1lXSA9IHtcbiAgICAgIGlkOiBwcmVyZW5kZXIuaWQsXG4gICAgICBmaWxlUGF0aDogb3duZXIuZmlsZVBhdGgsXG4gICAgICB0eXBlOiBvd25lci50eXBlLFxuICAgIH07XG4gIH1cblxuICBpZiAob3JwaGFucy5sZW5ndGggPiAwKSB7XG4gICAgLy8gV2FybiByYXRoZXIgdGhhbiB0aHJvdzogYW4gdW5tYXBwZWQgcGF0aG5hbWUgZGVncmFkZXMgb25lIFVSTCBzaGFwZSB0byBhXG4gICAgLy8gNDA0LCB3aGljaCBpcyB3aGF0IHdvdWxkIGhhcHBlbiB3aXRob3V0IHRoaXMgZnVuY3Rpb24gYXQgYWxsLiBBIHRocm93XG4gICAgLy8gd291bGQgYnJlYWsgdGhlIGJ1aWxkIG91dHJpZ2h0IG9uIGFuIG91dHB1dCBzaGFwZSBhIGZ1dHVyZSBgbmV4dGAgbWlub3JcbiAgICAvLyBtaWdodCBpbnRyb2R1Y2UuXG4gICAgY29uc29sZS53YXJuKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gJHtvcnBoYW5zLmxlbmd0aH0gcHJlcmVuZGVyIHBhdGhuYW1lKHMpIGhhdmUgbm8gYCArXG4gICAgICAgIGBtYXRjaGluZyByb3V0ZSBlbnRyeXBvaW50IGFuZCB3aWxsIDQwNDogYCArXG4gICAgICAgIGAke29ycGhhbnMuc2xpY2UoMCwgNSkuam9pbihcIiwgXCIpfWAgK1xuICAgICAgICBgJHtvcnBoYW5zLmxlbmd0aCA+IDUgPyBgLCBhbmQgJHtvcnBoYW5zLmxlbmd0aCAtIDV9IG1vcmVgIDogXCJcIn0uYCxcbiAgICApO1xuICB9XG59XG5cbmZ1bmN0aW9uIGJ1aWxkTWlkZGxld2FyZShcbiAgcmVwb1Jvb3Q6IHN0cmluZyxcbiAgbWlkZGxld2FyZTogQWRhcHRlck91dHB1dHNbXCJtaWRkbGV3YXJlXCJdLFxuKTogQWRhcHRlck1pZGRsZXdhcmUgfCBudWxsIHtcbiAgaWYgKCFtaWRkbGV3YXJlKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgLy8gYGNvbmZpZy5tYXRjaGVyc2AgaXMgZGVsaWJlcmF0ZWx5IG5vdCBjb3BpZWQgaGVyZTogaXQgYXJyaXZlcyBpbnNpZGVcbiAgLy8gYGN0eC5yb3V0aW5nLm1pZGRsZXdhcmVNYXRjaGVyc2AsIHdoaWNoIGBAbmV4dC9yb3V0aW5nYCBjb25zdW1lcyBkaXJlY3RseS5cbiAgcmV0dXJuIHtcbiAgICBpZDogbWlkZGxld2FyZS5pZCxcbiAgICBmaWxlUGF0aDogdG9Qb3NpeChyZWxhdGl2ZShyZXBvUm9vdCwgbWlkZGxld2FyZS5maWxlUGF0aCkpLFxuICB9O1xufVxuXG4vKipcbiAqIENvcHkgdGhlIHN0YWdpbmcgcGxhbiBpbnRvIGBzdGFnaW5nRGlyYC5cbiAqXG4gKiAqKlN5bWxpbmtzIGFyZSByZWNyZWF0ZWQgYXMgc3ltbGlua3MsIG5vdCBkZXJlZmVyZW5jZWQqKiwgd2hpY2ggaXMgd2hhdFxuICogTmV4dC5qcydzIG93biBgY29weVRyYWNlZEZpbGVzYCBkb2VzIChgbmV4dC9kaXN0L2J1aWxkL3V0aWxzLmpzYDogYHJlYWRsaW5rYFxuICogdGhlbiBgc3ltbGlua2AsIHdpdGggYSBXaW5kb3dzIGp1bmN0aW9uIGZhbGxiYWNrKS4gVW5kZXIgcG5wbSBhIHRyYWNlZCBhc3NldFxuICoga2V5IGlzIGZyZXF1ZW50bHkgYSAqZGlyZWN0b3J5KiBzeW1saW5rIGludG8gdGhlIHN0b3JlXG4gKiAoYG5vZGVfbW9kdWxlcy8ucG5wbS9uZXh0QOKApi9ub2RlX21vZHVsZXMvcmVhY3RgIOKGkiBgLi4vLi4vcmVhY3RAMTkuMi4zL+KApmApLCBzb1xuICogYGNvcHlGaWxlYCBmYWlscyBvdXRyaWdodCB3aXRoIGBFTk9UU1VQYC4gRGVyZWZlcmVuY2luZyBpbnN0ZWFkIHdvdWxkIHRyaXBsZVxuICogdGhlIHRyZWUg4oCUIGBleGFtcGxlcy9hcHAtcGxheWdyb3VuZGAgbWVhc3VyZXMgMzIgTUIgc3RhZ2VkIHZlcnN1cyA5NiBNQiB3aXRoXG4gKiBgZHUgLXNoTGAsIGFnYWluc3QgYSAyNTAgTUIgdW56aXBwZWQgTGFtYmRhIGNhcCDigJQgYmVjYXVzZSB3aG9sZSBwYWNrYWdlcyBhcmVcbiAqIHJlYWNoYWJsZSB0aHJvdWdoIHNldmVyYWwgc3VjaCBsaW5rcy4gVGhlIGxpbmsgdGFyZ2V0cyBhcmUgdGhlbXNlbHZlcyBzdGFnZWRcbiAqIGtleXMsIHNvIHJlbGF0aXZlIGxpbmtzIHJlc29sdmUgaW5zaWRlIHRoZSBkZXBsb3ltZW50IHJvb3QuXG4gKlxuICogUmVndWxhciBmaWxlcyBhcmUgc3RhZ2VkIGZpcnN0IHNvIHRoYXQgYSBzeW1saW5rIHdob3NlIHBhdGggd2FzIGFscmVhZHlcbiAqIG1hdGVyaWFsaXplZCBhcyBhIHJlYWwgZGlyZWN0b3J5IGlzIHNraXBwZWQgcmF0aGVyIHRoYW4gY2xvYmJlcmluZyBpdC5cbiAqXG4gKiBOb3RoaW5nIG1heSBkZXJlZmVyZW5jZSB0aGVtIGFmdGVyd2FyZHM6IHRoZSBGdW5jdGlvbnMgemlwIGtlZXBzIHRoZW0gYXNcbiAqIGxpbmtzIChgemlwRGlyZWN0b3J5YCksIGFuZCB0aGUgQ29udGFpbmVycyBgQ09QWWAgZG9lcyB0b28uXG4gKi9cbi8qKiBCb3VuZGVkIHNvIGEgbGFyZ2UgYXBwIGRvZXNuJ3QgZXhoYXVzdCBmaWxlIGRlc2NyaXB0b3JzLiAqL1xuY29uc3QgU1RBR0lOR19DT05DVVJSRU5DWSA9IDMyO1xuXG5hc3luYyBmdW5jdGlvbiBzdGFnZUZpbGVzKFxuICBzdGFnaW5nOiBTdGFnaW5nUGxhbixcbiAgc3RhZ2luZ0Rpcjogc3RyaW5nLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHBsYW5uZWQgPSBbLi4uc3RhZ2luZ107XG4gIC8vIExpbmtzIGxhbmQgYnkgcGxhbiBpbmRleCwgc28gdGhlIHBhc3MgYmVsb3cgY3JlYXRlcyB0aGVtIGluIHRoZSBwbGFuJ3NcbiAgLy8gb3JkZXIgd2hhdGV2ZXIgb3JkZXIgdGhlIHdvcmtlcnMgZmluaXNoZWQgaW4uXG4gIGNvbnN0IGxpbmtzOiBBcnJheTxbc3RyaW5nLCBzdHJpbmcsIHN0cmluZ10gfCB1bmRlZmluZWQ+ID0gbmV3IEFycmF5KFxuICAgIHBsYW5uZWQubGVuZ3RoLFxuICApO1xuICBsZXQgbmV4dEVudHJ5ID0gMDtcbiAgY29uc3Qgd29ya2VyID0gYXN5bmMgKCkgPT4ge1xuICAgIHdoaWxlIChuZXh0RW50cnkgPCBwbGFubmVkLmxlbmd0aCkge1xuICAgICAgY29uc3QgaW5kZXggPSBuZXh0RW50cnkrKztcbiAgICAgIGNvbnN0IFtrZXksIHNvdXJjZV0gPSBwbGFubmVkW2luZGV4XTtcbiAgICAgIGNvbnN0IGxpbmtUYXJnZXQgPSBhd2FpdCByZWFkbGluayhzb3VyY2UpLmNhdGNoKCgpID0+IG51bGwpO1xuICAgICAgaWYgKGxpbmtUYXJnZXQgIT09IG51bGwpIHtcbiAgICAgICAgbGlua3NbaW5kZXhdID0gW2tleSwgc291cmNlLCBsaW5rVGFyZ2V0XTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBkZXN0ID0gam9pbihzdGFnaW5nRGlyLCBrZXkpO1xuICAgICAgYXdhaXQgbWtkaXIoZGlybmFtZShkZXN0KSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBhd2FpdCBjb3B5RmlsZShzb3VyY2UsIGRlc3QpO1xuICAgIH1cbiAgfTtcbiAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgQXJyYXkuZnJvbShcbiAgICAgIHsgbGVuZ3RoOiBNYXRoLm1pbihTVEFHSU5HX0NPTkNVUlJFTkNZLCBwbGFubmVkLmxlbmd0aCkgfSxcbiAgICAgIHdvcmtlcixcbiAgICApLFxuICApO1xuXG4gIGZvciAoY29uc3QgbGluayBvZiBsaW5rcykge1xuICAgIGlmIChsaW5rID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCBba2V5LCBzb3VyY2UsIGxpbmtUYXJnZXRdID0gbGluaztcbiAgICBjb25zdCBkZXN0ID0gam9pbihzdGFnaW5nRGlyLCBrZXkpO1xuICAgIGlmIChleGlzdHNTeW5jKGRlc3QpKSB7XG4gICAgICAvLyBBbHJlYWR5IHN0YWdlZCBhcyByZWFsIGNvbnRlbnQgYnkgdGhlIHBvb2wgYWJvdmU7IHRoZSBsaW5rIHdvdWxkIGFkZFxuICAgICAgLy8gbm90aGluZyBhbmQgd291bGQgcmVwbGFjZSBhIGRpcmVjdG9yeSB3ZSBuZWVkLlxuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGF3YWl0IG1rZGlyKGRpcm5hbWUoZGVzdCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZShkaXJuYW1lKGRlc3QpLCBsaW5rVGFyZ2V0KTtcbiAgICBpZiAocmVzb2x2ZWQgPT09IHN0YWdpbmdEaXIgfHwgcmVzb2x2ZWQuc3RhcnRzV2l0aChzdGFnaW5nRGlyICsgc2VwKSkge1xuICAgICAgYXdhaXQgc3ltbGluayhsaW5rVGFyZ2V0LCBkZXN0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUG9pbnRzIG91dHNpZGUgdGhlIGRlcGxveW1lbnQgcm9vdCwgc28gdGhlIGxpbmsgd291bGQgZGFuZ2xlIGluIExhbWJkYS5cbiAgICAgIC8vIEFic29sdXRlIHN0b3JlIHBhdGhzIGFyZSB0aGUgcmVhbGlzdGljIGNhc2UgaGVyZS5cbiAgICAgIGF3YWl0IGNwKHNvdXJjZSwgZGVzdCwgeyByZWN1cnNpdmU6IHRydWUsIGRlcmVmZXJlbmNlOiB0cnVlIH0pO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEFkZHMge0BsaW5rIFJVTlRJTUVfTkVYVF9NT0RVTEVTfSwgYEBuZXh0L2VudmAsIGFuZCBldmVyeXRoaW5nIHRoZXkgcmVxdWlyZSB0b1xuICogYHN0YWdpbmdgLCBhbmQge0BsaW5rIElNQUdFX05FWFRfTU9EVUxFU30gYW5kIHRoZWlycyB0byBgaW1hZ2VTdGFnaW5nYC5cbiAqXG4gKiBXaXRob3V0IHRoaXMgdGhlIGRlcGxveW1lbnQgaXMgY29tcGxldGUgZm9yIGV2ZXJ5IHJvdXRlIHRoZSBhcHAgaGFzIGFuZCBicm9rZW5cbiAqIGZvciBgL19uZXh0L2ltYWdlYDogdGhlIHRyYWNlZCBgYXNzZXRzYCBvZiBhIGJ1aWxkIG91dHB1dCBjb3ZlciB3aGF0IHRoZSAqYXBwKlxuICogcmVhY2hlcywgYW5kIGFuIGFwcCBuZXZlciByZWFjaGVzIG5leHQncyBpbWFnZSBvcHRpbWl6ZXIsIHNvXG4gKiBgbmV4dC9kaXN0L3NlcnZlci9pbWFnZS1vcHRpbWl6ZXIuanNgIGFuZCBpdHMgY2xvc3VyZSBhcmUgc2ltcGx5IGFic2VudCBhbmRcbiAqIGV2ZXJ5IGltYWdlIHJlcXVlc3QgNTAwcyB3aXRoIGEgYE1PRFVMRV9OT1RfRk9VTkRgIGZyb20gYG5leHRNb2R1bGVgLlxuICpcbiAqIFJlc29sdXRpb24gaXMgYW5jaG9yZWQgaW5zaWRlIGBjdHgucHJvamVjdERpcmAgZm9yIHRoZSBzYW1lIHJlYXNvblxuICogYHVzZU5leHRGcm9tYCBhbmNob3JzIHRoZXJlIGF0IHJ1bnRpbWU6IGl0IGlzIHRoZSBkaXJlY3Rvcnkgd2hvc2VcbiAqIGBub2RlX21vZHVsZXNgIHdhbGsgZmluZHMgdGhlIGFwcCdzIGBuZXh0YC4gQSByZXBvIHdoZXJlIHRoYXQgcmVzb2x1dGlvbiBmYWlsc1xuICogaXMgbm90IGEgcmVhbCBgbmV4dCBidWlsZGAg4oCUIG5vdGhpbmcgZWxzZSB3b3VsZCBoYXZlIHJ1biDigJQgc28gaXQgd2FybnMgYW5kXG4gKiBjb250aW51ZXMgcmF0aGVyIHRoYW4gZmFpbGluZyBhIGJ1aWxkIGZvciBhIHBhY2thZ2UgaXQgY291bGQgbm90IGhhdmUgbmVlZGVkLlxuICogQSBtaXNzaW5nICp0cmFjZXIqIGlzIGRpZmZlcmVudDogYG5leHRgIGlzIHJpZ2h0IHRoZXJlIGFuZCBpbWFnZSBvcHRpbWl6YXRpb25cbiAqIHdvdWxkIHNpbGVudGx5IDUwMCBpbiBwcm9kdWN0aW9uLCBzbyB0aGF0IHRocm93cy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYWRkUnVudGltZU5leHRDbG9zdXJlKFxuICBjdHg6IEJ1aWxkQ29tcGxldGVDb250ZXh0LFxuICBzdGFnaW5nOiBNYXA8c3RyaW5nLCBzdHJpbmc+LFxuICBpbWFnZVN0YWdpbmc6IE1hcDxzdHJpbmcsIHN0cmluZz4sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgLy8gVGhlIGFuY2hvciBmaWxlIG5lZWRuJ3QgZXhpc3Q7IGBjcmVhdGVSZXF1aXJlYCBvbmx5IHJlYWRzIGl0cyBkaXJlY3RvcnkuXG4gIGNvbnN0IG5leHRSZXF1aXJlID0gY3JlYXRlUmVxdWlyZShcbiAgICBqb2luKGN0eC5wcm9qZWN0RGlyLCBcImNkay1uZXh0anMtbmV4dC1yZXNvbHZlci5janNcIiksXG4gICk7XG5cbiAgbGV0IGVudHJpZXM6IHN0cmluZ1tdO1xuICBsZXQgaW1hZ2VFbnRyaWVzOiBzdHJpbmdbXTtcbiAgdHJ5IHtcbiAgICBlbnRyaWVzID0gUlVOVElNRV9ORVhUX01PRFVMRVMubWFwKChzcGVjaWZpZXIpID0+XG4gICAgICBuZXh0UmVxdWlyZS5yZXNvbHZlKHNwZWNpZmllciksXG4gICAgKTtcbiAgICBpbWFnZUVudHJpZXMgPSBJTUFHRV9ORVhUX01PRFVMRVMubWFwKChzcGVjaWZpZXIpID0+XG4gICAgICBuZXh0UmVxdWlyZS5yZXNvbHZlKHNwZWNpZmllciksXG4gICAgKTtcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICBgJHtMT0dfUFJFRklYfSBDb3VsZCBub3QgcmVzb2x2ZSBuZXh0J3MgaW1hZ2Ugb3B0aW1pemVyIGZyb20gYCArXG4gICAgICAgIGBcIiR7Y3R4LnByb2plY3REaXJ9XCIgKCR7KGNhdXNlIGFzIEVycm9yKS5tZXNzYWdlfSkuIFJlcXVlc3RzIHRvIGAgK1xuICAgICAgICBgL19uZXh0L2ltYWdlIHdpbGwgZmFpbCBhdCBydW50aW1lLmAsXG4gICAgKTtcbiAgICByZXR1cm47XG4gIH1cbiAgLy8gYGxvYWRFbnZGaWxlc2AgKHJ1bnRpbWUgYG5leHQtbW9kdWxlcy50c2ApIGxvYWRzIHRoZSBzdGFnZWQgZW52IGZpbGVzIHdpdGhcbiAgLy8gYEBuZXh0L2VudmAsIHdoaWNoIGlzIGBuZXh0YCdzIGRlcGVuZGVuY3ksIHNvIHJlc29sdmVkIGZyb20gYG5leHRgJ3MgZGlyLlxuICAvLyBBbiBhcHAgbmV2ZXIgcmVxdWlyZXMgaXQsIHNvIG5vIG91dHB1dCdzIHRyYWNlIGhhcyBpdCBlaXRoZXIuXG4gIGNvbnN0IG5leHRQYWNrYWdlID0gbmV4dFJlcXVpcmUucmVzb2x2ZShcIm5leHQvcGFja2FnZS5qc29uXCIpO1xuICB0cnkge1xuICAgIGVudHJpZXMucHVzaChjcmVhdGVSZXF1aXJlKG5leHRQYWNrYWdlKS5yZXNvbHZlKFwiQG5leHQvZW52XCIpKTtcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtMT0dfUFJFRklYfSBDb3VsZCBub3QgcmVzb2x2ZSBcIkBuZXh0L2VudlwiIGZyb20gdGhlIGFwcCdzIFxcYG5leHRcXGAsIGAgK1xuICAgICAgICBgd2hpY2ggdGhlIGNkay1uZXh0anMgcnVudGltZSB1c2VzIHRvIGxvYWQgLmVudiBmaWxlcy5gLFxuICAgICAgeyBjYXVzZSB9LFxuICAgICk7XG4gIH1cblxuICBsZXQgbm9kZUZpbGVUcmFjZTogTm9kZUZpbGVUcmFjZTtcbiAgdHJ5IHtcbiAgICAoeyBub2RlRmlsZVRyYWNlIH0gPSBuZXh0UmVxdWlyZShORVhUX0ZJTEVfVFJBQ0VSKSk7XG4gIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gQ291bGQgbm90IGxvYWQgXCIke05FWFRfRklMRV9UUkFDRVJ9XCIsIHdoaWNoIGNkay1uZXh0anMgdXNlcyBgICtcbiAgICAgICAgYHRvIHN0YWdlIHRoZSBcXGBuZXh0XFxgIGZpbGVzIGl0cyBpbWFnZSBvcHRpbWl6ZXIgcmVxdWlyZXMuIFRoaXMgTmV4dC5qcyBgICtcbiAgICAgICAgYHZlcnNpb24gbWF5IGhhdmUgbW92ZWQgaXQ7IHBsZWFzZSBvcGVuIGFuIGlzc3VlLmAsXG4gICAgICB7IGNhdXNlIH0sXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IGFkZCA9IChmaWxlTGlzdDogU2V0PHN0cmluZz4sIHRhcmdldDogTWFwPHN0cmluZywgc3RyaW5nPikgPT4ge1xuICAgIGZvciAoY29uc3QgdHJhY2VkIG9mIGZpbGVMaXN0KSB7XG4gICAgICBjb25zdCBrZXkgPSB0b1Bvc2l4KHRyYWNlZCk7XG4gICAgICBpZiAodGFyZ2V0LmhhcyhrZXkpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3Qgc291cmNlID0gam9pbihjdHgucmVwb1Jvb3QsIHRyYWNlZCk7XG4gICAgICBhc3NlcnRTdGFnaW5nS2V5KGtleSwgc291cmNlKTtcbiAgICAgIHRhcmdldC5zZXQoa2V5LCBzb3VyY2UpO1xuICAgIH1cbiAgfTtcbiAgYWRkKFxuICAgIChhd2FpdCBub2RlRmlsZVRyYWNlKGltYWdlRW50cmllcywgeyBiYXNlOiBjdHgucmVwb1Jvb3QgfSkpLmZpbGVMaXN0LFxuICAgIGltYWdlU3RhZ2luZyxcbiAgKTtcbiAgY29uc3QgeyBmaWxlTGlzdCB9ID0gYXdhaXQgbm9kZUZpbGVUcmFjZShlbnRyaWVzLCB7IGJhc2U6IGN0eC5yZXBvUm9vdCB9KTtcbiAgLy8gVGhlIHRyYWNlIHN0YXJ0cyBmcm9tIGBAbmV4dC9lbnZgJ3MgcmVhbCBwYXRoLCBzbyB1bmRlciBwbnBtIGl0IG5ldmVyXG4gIC8vIHBhc3NlcyB0aHJvdWdoIHRoZSBgLnBucG0vbmV4dEDigKYvbm9kZV9tb2R1bGVzL0BuZXh0L2VudmAgbGluayB0aGF0IGBuZXh0YFxuICAvLyByZXNvbHZlcyBpdCBieS4gV2l0aG91dCB0aGUgbGluaywgZXZlcnkgcmVxdWVzdCBmYWlscyBhdCBjb2xkIHN0YXJ0IHdpdGhcbiAgLy8gXCJDYW5ub3QgZmluZCBtb2R1bGUgJ0BuZXh0L2VudidcIi5cbiAgY29uc3QgbmV4dEVudkxpbmsgPSBqb2luKGRpcm5hbWUobmV4dFBhY2thZ2UpLCBcIi4uXCIsIFwiQG5leHRcIiwgXCJlbnZcIik7XG4gIGlmIChsc3RhdFN5bmMobmV4dEVudkxpbmssIHsgdGhyb3dJZk5vRW50cnk6IGZhbHNlIH0pPy5pc1N5bWJvbGljTGluaygpKSB7XG4gICAgLy8gYHJlc29sdmVgIHJldHVybnMgcmVhbCBwYXRocywgc28gcmVsYXRpdmUgdG8gdGhlIHJlYWwgcmVwbyByb290LlxuICAgIGZpbGVMaXN0LmFkZChyZWxhdGl2ZShyZWFscGF0aFN5bmMoY3R4LnJlcG9Sb290KSwgbmV4dEVudkxpbmspKTtcbiAgfVxuICBhZGQoZmlsZUxpc3QsIHN0YWdpbmcpO1xufVxuXG4vKipcbiAqIEFkZCBgPGRpc3REaXI+L3JlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYCB0byBhIHBsYW4gZXZlcnkgZ3JvdXAgaXMgbWVyZ2VkIHdpdGguXG4gKlxuICogSXQgcmVhY2hlcyBhIGdyb3VwIG90aGVyd2lzZSBvbmx5IGFzIGEgdHJhY2VkIGBhc3NldGAgb2Ygc29tZSBpbnZvY2FibGUgb3V0cHV0LFxuICogd2hpY2ggaXMgbm90IGEgZ3VhcmFudGVlOiBhIGdyb3VwIHdob3NlIHRlbXBsYXRlcyBhcmUgYWxsIGFzc2lnbmVkIGVsc2V3aGVyZVxuICogb3ducyBubyBvdXRwdXRzIGF0IGFsbC4gVGhhdCBpcyByZWFjaGFibGUg4oCUIGEgUGFnZXMtUm91dGVyLW9ubHkgYXBwIHdob3NlIGV2ZXJ5XG4gKiBwYWdlIGZhbGxzIHVuZGVyIHRoZSBjb25maWd1cmVkIGBmdW5jdGlvbkdyb3Vwc2AgbGVhdmVzIHRoZSAqZGVmYXVsdCogZ3JvdXBcbiAqIHRlbXBsYXRlLWVtcHR5LCBhbmQgdGhlIGRlZmF1bHQgZ3JvdXAgaXMgc3RpbGwgd2hhdCBzZXJ2ZXMgYC9fbmV4dC9pbWFnZWAsIHRoZVxuICogc3RhdGljIGZpbGVzLCBhbmQgdGhlIGRpc3RyaWJ1dGlvbidzIGNhdGNoLWFsbC5cbiAqXG4gKiBJdHMgYWJzZW5jZSBpcyBub3QgYSBwYXJ0aWFsIGZhaWx1cmU6IGBsb2FkUnVudGltZWAgcHJvYmVzIGZvciBleGFjdGx5IHRoaXMgZmlsZVxuICogYmVmb3JlIGl0IHdpbGwgc2VydmUgYW55dGhpbmcsIGFuZCBgaW1hZ2UudHNgIHJlYWRzIHRoZSBpbWFnZSBjb25maWcgb3V0IG9mIGl0LFxuICogc28gdGhlIHdob2xlIHJvb3QgYW5zd2VycyBcInRoZSBkZXBsb3ltZW50IHBhY2thZ2UgaXMgaW5jb21wbGV0ZVwiLiBDaGVhcCB0byBtYWtlXG4gKiB1bmNvbmRpdGlvbmFsLCBzbyBtYWtlIGl0IHVuY29uZGl0aW9uYWwuXG4gKlxuICogTm90IHRyYWNlZCBsaWtlIHtAbGluayBSVU5USU1FX05FWFRfTU9EVUxFU30sIGJlY2F1c2UgaXQgaXMgZGF0YSByYXRoZXIgdGhhbiBhXG4gKiBtb2R1bGU6IG5vdGhpbmcgYHJlcXVpcmVgcyBpdCwgc28gbm8gZmlsZSB0cmFjZXIgY2FuIGZpbmQgaXQuXG4gKlxuICogQWJzZW5jZSBpcyBsZWZ0IHRvIGBsb2FkUnVudGltZWAsIHdoaWNoIG5hbWVzIHRoZSBmaWxlIGFuZCB0aGUgbGF5b3V0IGNvbnRyYWN0XG4gKiBpdCBiZWxvbmdzIHRvLiBgbmV4dCBidWlsZGAgYWx3YXlzIHdyaXRlcyBpdCwgc28gdGhlcmUgaXMgbm8gYnVpbGQtdGltZSBlcnJvclxuICogd29ydGggaW52ZW50aW5nIGhlcmUgZm9yIGEgZmlsZSB0aGlzIHN0ZXAgZG9lcyBub3Qgb3duLlxuICovXG5mdW5jdGlvbiBhZGRSZXF1aXJlZFNlcnZlckZpbGVzKFxuICBjdHg6IEJ1aWxkQ29tcGxldGVDb250ZXh0LFxuICBzdGFnaW5nOiBNYXA8c3RyaW5nLCBzdHJpbmc+LFxuKTogdm9pZCB7XG4gIGNvbnN0IHNvdXJjZSA9IGpvaW4oY3R4LmRpc3REaXIsIFwicmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25cIik7XG4gIGNvbnN0IGtleSA9IHRvUG9zaXgocmVsYXRpdmUoY3R4LnJlcG9Sb290LCBzb3VyY2UpKTtcbiAgaWYgKHN0YWdpbmcuaGFzKGtleSkgfHwgIWV4aXN0c1N5bmMoc291cmNlKSkge1xuICAgIHJldHVybjtcbiAgfVxuICBhc3NlcnRTdGFnaW5nS2V5KGtleSwgc291cmNlKTtcbiAgc3RhZ2luZy5zZXQoa2V5LCBzb3VyY2UpO1xufVxuXG4vKipcbiAqIEV2ZXJ5IHN0YWdlZCBwYXRoIG11c3QgbGFuZCBpbnNpZGUgdGhlIHN0YWdpbmcgdHJlZSBhbmQgbXVzdCBub3Qgc2hhZG93IHRoZVxuICogcmVzZXJ2ZWQgZGlyZWN0b3J5IGNkay1uZXh0anMgY29waWVzIGl0cyBvd24gcnVudGltZSBpbnRvIGF0IHN5bnRoLlxuICovXG5mdW5jdGlvbiBhc3NlcnRTdGFnaW5nS2V5KGtleTogc3RyaW5nLCBzb3VyY2U6IHN0cmluZyk6IHZvaWQge1xuICBpZiAoa2V5ID09PSBcIlwiIHx8IGtleS5zdGFydHNXaXRoKFwiL1wiKSB8fCBrZXkuc3RhcnRzV2l0aChcIi4uXCIpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gQnVpbGQgb3V0cHV0IGFzc2V0IFwiJHtzb3VyY2V9XCIgcmVzb2x2ZXMgdG8gdGhlIHN0YWdpbmcga2V5IGAgK1xuICAgICAgICBgXCIke2tleX1cIiwgd2hpY2ggaXMgb3V0c2lkZSB0aGUgZGVwbG95bWVudCByb290LiBTZXQgYCArXG4gICAgICAgIGBcXGBvdXRwdXRGaWxlVHJhY2luZ1Jvb3RcXGAgc28gYWxsIHRyYWNlZCBmaWxlcyBsaXZlIHVuZGVyIG9uZSByb290LmAsXG4gICAgKTtcbiAgfVxuICBpZiAoa2V5ID09PSBSVU5USU1FX0RJUl9OQU1FIHx8IGtleS5zdGFydHNXaXRoKGAke1JVTlRJTUVfRElSX05BTUV9L2ApKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gQnVpbGQgb3V0cHV0IGFzc2V0IFwiJHtzb3VyY2V9XCIgcmVzb2x2ZXMgdG8gdGhlIHN0YWdpbmcga2V5IGAgK1xuICAgICAgICBgXCIke2tleX1cIiwgYnV0IFwiJHtSVU5USU1FX0RJUl9OQU1FfS9cIiBpcyByZXNlcnZlZCBmb3IgY2RrLW5leHRqcydzIG93biBgICtcbiAgICAgICAgYHJ1bnRpbWUgZmlsZXMuYCxcbiAgICApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHRvUG9zaXgocGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHNlcCA9PT0gXCIvXCIgPyBwYXRoIDogcGF0aC5zcGxpdChzZXApLmpvaW4oXCIvXCIpO1xufVxuXG5mdW5jdGlvbiBzb3J0ZWRVbmlxdWUodmFsdWVzOiBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIFsuLi5uZXcgU2V0KHZhbHVlcyldLnNvcnQoKTtcbn1cbiJdfQ==
|