cdk-nextjs 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1548 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +852 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +861 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +13 -5
- package/lib/nextjs-post-deploy.js +13 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1213 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1678 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41595 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +55 -0
- package/lib/runtime/next-modules.js +124 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41588 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
|
@@ -0,0 +1,861 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const node_os_1 = require("node:os");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const app_playground_base_path_json_1 = __importDefault(require("./__fixtures__/app-playground-base-path.json"));
|
|
10
|
+
const app_playground_json_1 = __importDefault(require("./__fixtures__/app-playground.json"));
|
|
11
|
+
const pages_i18n_json_1 = __importDefault(require("./__fixtures__/pages-i18n.json"));
|
|
12
|
+
const build_outputs_1 = require("./build-outputs");
|
|
13
|
+
const manifest_1 = require("../runtime/manifest");
|
|
14
|
+
/**
|
|
15
|
+
* The fixtures are real `onBuildComplete` contexts captured by
|
|
16
|
+
* `scripts/capture-adapter-fixture.mjs`, with absolute paths rewritten to a
|
|
17
|
+
* `/repo` placeholder. Regenerate them when `next` is upgraded.
|
|
18
|
+
*/
|
|
19
|
+
const fixtures = {
|
|
20
|
+
"app-playground": app_playground_json_1.default,
|
|
21
|
+
"app-playground-base-path": app_playground_base_path_json_1.default,
|
|
22
|
+
"pages-i18n": pages_i18n_json_1.default,
|
|
23
|
+
};
|
|
24
|
+
/** Fixtures are JSON, so the structural cast is the point of the cast. */
|
|
25
|
+
const asContext = (fixture) => structuredClone(fixture);
|
|
26
|
+
/**
|
|
27
|
+
* `buildAdapterManifest` requires the build cwd to be the project dir — see
|
|
28
|
+
* `assertBuildCwd`. The fixtures' project dirs are synthetic `/repo/…` paths, so
|
|
29
|
+
* every call supplies it rather than letting it default to `process.cwd()`. The
|
|
30
|
+
* assertion itself is covered separately below.
|
|
31
|
+
*/
|
|
32
|
+
const build = (ctx) => (0, build_outputs_1.buildAdapterManifest)(ctx, { buildCwd: ctx.projectDir });
|
|
33
|
+
const write = (ctx) => (0, build_outputs_1.writeBuildOutputs)(ctx, { buildCwd: ctx.projectDir });
|
|
34
|
+
/**
|
|
35
|
+
* The one deployment root an unsplit build stages. Asserted rather than indexed
|
|
36
|
+
* so a regression that starts splitting unasked fails here instead of silently
|
|
37
|
+
* checking group 0.
|
|
38
|
+
*/
|
|
39
|
+
const soleRoot = (result) => {
|
|
40
|
+
expect(result.stagedGroups).toHaveLength(1);
|
|
41
|
+
return result.stagedGroups[0].path;
|
|
42
|
+
};
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
// `maxDuration` warnings are expected from the pages-i18n fixture.
|
|
45
|
+
jest.spyOn(console, "warn").mockImplementation(() => { });
|
|
46
|
+
});
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
jest.restoreAllMocks();
|
|
49
|
+
});
|
|
50
|
+
describe.each(Object.keys(fixtures))("buildAdapterManifest(%s)", (name) => {
|
|
51
|
+
const ctx = asContext(fixtures[name]);
|
|
52
|
+
const { manifest, groups: [{ staging }], } = build(ctx);
|
|
53
|
+
it("stamps the manifest version and build identity", () => {
|
|
54
|
+
expect(manifest.version).toBe(1);
|
|
55
|
+
expect(manifest.buildId).toBe(ctx.buildId);
|
|
56
|
+
expect(manifest.relativeProjectDir).toBe(name.startsWith("pages-i18n") ? "pages-i18n" : "app-playground");
|
|
57
|
+
});
|
|
58
|
+
it("copies the config fields the runtime router needs", () => {
|
|
59
|
+
expect(manifest.config).toEqual({
|
|
60
|
+
basePath: ctx.config.basePath ?? "",
|
|
61
|
+
trailingSlash: ctx.config.trailingSlash === true,
|
|
62
|
+
assetPrefix: ctx.config.assetPrefix ?? "",
|
|
63
|
+
distDir: ".next",
|
|
64
|
+
compress: true,
|
|
65
|
+
generateEtags: true,
|
|
66
|
+
i18n: ctx.config.i18n ?? null,
|
|
67
|
+
deploymentId: "",
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
it("persists ctx.routing verbatim", () => {
|
|
71
|
+
// `@next/routing`'s `resolveRoutes` consumes this whole object; anything we
|
|
72
|
+
// reshape here is a behavior difference from `next start`.
|
|
73
|
+
expect(manifest.routing).toEqual(ctx.routing);
|
|
74
|
+
expect(manifest.routing).toHaveProperty("middlewareMatchers");
|
|
75
|
+
});
|
|
76
|
+
it("maps every invocable output pathname to an entrypoint", () => {
|
|
77
|
+
const expected = [
|
|
78
|
+
...ctx.outputs.pages,
|
|
79
|
+
...ctx.outputs.pagesApi,
|
|
80
|
+
...ctx.outputs.appPages,
|
|
81
|
+
...ctx.outputs.appRoutes,
|
|
82
|
+
].map((o) => o.pathname);
|
|
83
|
+
// Plus dynamic prerender templates, which `addPrerenderPathnames` maps to
|
|
84
|
+
// the entrypoint of the route that owns them. None of these fixtures has a
|
|
85
|
+
// gated dynamic route, so no *concrete* prerender pathname is added - see
|
|
86
|
+
// the root-params test below.
|
|
87
|
+
const templates = ctx.outputs.prerenders
|
|
88
|
+
.filter((o) => o.pathname.includes("["))
|
|
89
|
+
.map((o) => o.pathname);
|
|
90
|
+
expect(Object.keys(manifest.entrypoints).sort()).toEqual([...new Set([...expected, ...templates])].sort());
|
|
91
|
+
for (const [pathname, entry] of Object.entries(manifest.entrypoints)) {
|
|
92
|
+
expect(entry.filePath).toMatch(/^[^/]/);
|
|
93
|
+
expect(entry.filePath).not.toContain("\\");
|
|
94
|
+
expect(staging.has(entry.filePath)).toBe(true);
|
|
95
|
+
expect(entry.id).toBeTruthy();
|
|
96
|
+
expect(["app-page", "app-route", "page", "page-api"]).toContain(entry.type);
|
|
97
|
+
expect(pathname).toBeTruthy();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
it("lists pathnames as the sorted union of entrypoints and static files", () => {
|
|
101
|
+
expect(manifest.pathnames).toEqual([...manifest.pathnames].sort());
|
|
102
|
+
expect(new Set(manifest.pathnames).size).toBe(manifest.pathnames.length);
|
|
103
|
+
for (const key of Object.keys(manifest.entrypoints)) {
|
|
104
|
+
expect(manifest.pathnames).toContain(key);
|
|
105
|
+
}
|
|
106
|
+
for (const file of ctx.outputs.staticFiles) {
|
|
107
|
+
expect(manifest.pathnames).toContain(file.pathname);
|
|
108
|
+
}
|
|
109
|
+
// One reported pathname can produce two keys - a `/index` static file is
|
|
110
|
+
// also served at `/`, see the static-home-page tests below. None of these
|
|
111
|
+
// fixtures has one, so here the two sets coincide.
|
|
112
|
+
expect(Object.keys(manifest.staticFiles)).toEqual([...new Set(ctx.outputs.staticFiles.map((f) => f.pathname))].sort());
|
|
113
|
+
});
|
|
114
|
+
it("maps each static file to a repo-root-relative key", () => {
|
|
115
|
+
for (const [pathname, key] of Object.entries(manifest.staticFiles)) {
|
|
116
|
+
const output = ctx.outputs.staticFiles.find((f) => f.pathname === pathname);
|
|
117
|
+
expect(key).toBe(output.filePath.replace("/repo/", ""));
|
|
118
|
+
expect(key.startsWith("/")).toBe(false);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
it("stages the static files nothing in front of the compute serves", () => {
|
|
122
|
+
// `<distDir>/static` goes to S3; `<distDir>/server/**` (404.html,
|
|
123
|
+
// favicon.ico.body, fully-static Pages Router HTML) does not, so the
|
|
124
|
+
// runtime must be able to read it off disk.
|
|
125
|
+
for (const [pathname, key] of Object.entries(manifest.staticFiles)) {
|
|
126
|
+
const servedByS3 = pathname.includes("/_next/static/");
|
|
127
|
+
expect(staging.has(key)).toBe(!servedByS3);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
it("stages only keys that land inside the deployment root", () => {
|
|
131
|
+
expect(staging.size).toBeGreaterThan(0);
|
|
132
|
+
for (const key of staging.keys()) {
|
|
133
|
+
expect(key).not.toBe("");
|
|
134
|
+
expect(key.startsWith("/")).toBe(false);
|
|
135
|
+
expect(key.startsWith("..")).toBe(false);
|
|
136
|
+
expect(key.startsWith(`${manifest_1.RUNTIME_DIR_NAME}/`)).toBe(false);
|
|
137
|
+
}
|
|
138
|
+
// The traced `next` closure is merged into every output, so staging is far
|
|
139
|
+
// smaller than the sum of the per-output `assets` maps.
|
|
140
|
+
expect(staging.size).toBeLessThan(ctx.outputs.appPages.length * 100 +
|
|
141
|
+
ctx.outputs.pages.length * 100 +
|
|
142
|
+
1000);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe("buildAdapterManifest edge cases", () => {
|
|
146
|
+
it("throws when `next build` ran from outside the project directory", () => {
|
|
147
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
148
|
+
expect(() => (0, build_outputs_1.buildAdapterManifest)(ctx, { buildCwd: "/repo" })).toThrow(/must run from the Next.js project directory/);
|
|
149
|
+
});
|
|
150
|
+
it("defaults the build cwd to process.cwd()", () => {
|
|
151
|
+
// Which is this package's root, never a fixture's `/repo/…` project dir, so
|
|
152
|
+
// the assertion fires — proving the default is wired and not just the option.
|
|
153
|
+
expect(() => (0, build_outputs_1.buildAdapterManifest)(asContext(app_playground_json_1.default))).toThrow(/must run from the Next.js project directory/);
|
|
154
|
+
});
|
|
155
|
+
it("records the deploymentId, reduced to what a cache key prefix can hold", () => {
|
|
156
|
+
// `NextjsBuild` suffixes its `buildId` with it: next pins the build ID
|
|
157
|
+
// itself once `deploymentId` is set.
|
|
158
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
159
|
+
const { manifest } = build({
|
|
160
|
+
...ctx,
|
|
161
|
+
config: { ...ctx.config, deploymentId: "v1.2/main" },
|
|
162
|
+
});
|
|
163
|
+
expect(manifest.config.deploymentId).toBe("v1-2-main");
|
|
164
|
+
});
|
|
165
|
+
it("keys locale variants of one page to the same entrypoint file", () => {
|
|
166
|
+
const { manifest } = build(asContext(pages_i18n_json_1.default));
|
|
167
|
+
// i18n fans one page out into one output per locale, plus a
|
|
168
|
+
// `/_next/data/<buildId>/…json` sibling each. They share `filePath` and
|
|
169
|
+
// `type`; `id` stays per-pathname (locale-prefixed), so it is not a dedup key.
|
|
170
|
+
const ssr = [
|
|
171
|
+
"/ssr",
|
|
172
|
+
"/en-US/ssr",
|
|
173
|
+
"/fr/ssr",
|
|
174
|
+
"/nl-NL/ssr",
|
|
175
|
+
`/_next/data/${manifest.buildId}/fr/ssr.json`,
|
|
176
|
+
];
|
|
177
|
+
for (const pathname of ssr) {
|
|
178
|
+
expect(manifest.entrypoints[pathname]).toMatchObject({
|
|
179
|
+
filePath: manifest.entrypoints["/ssr"].filePath,
|
|
180
|
+
type: "page",
|
|
181
|
+
});
|
|
182
|
+
expect(manifest.entrypoints[pathname].id).toBe(pathname);
|
|
183
|
+
}
|
|
184
|
+
expect(manifest.entrypoints["/ssr"].type).toBe("page");
|
|
185
|
+
expect(manifest.entrypoints["/api/hello"].type).toBe("page-api");
|
|
186
|
+
});
|
|
187
|
+
it("carries basePath in pathnames but not in entrypoint ids", () => {
|
|
188
|
+
// `output.pathname` is basePath-prefixed while `output.id` is not. Dispatch
|
|
189
|
+
// keys off the pathname, so the prefix has to stay.
|
|
190
|
+
const { manifest } = build(asContext(app_playground_base_path_json_1.default));
|
|
191
|
+
expect(manifest.config.basePath).toBe("/prod");
|
|
192
|
+
expect(manifest.entrypoints["/prod/api/health"]).toBeDefined();
|
|
193
|
+
expect(manifest.entrypoints["/prod/api/health"].id).toBe("/api/health");
|
|
194
|
+
expect(manifest.entrypoints["/api/health"]).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
/**
|
|
197
|
+
* A Pages Router home page reaches us as `/index`, whichever population it lands
|
|
198
|
+
* in: `normalizePagePath("/")` is `"/index"`, and the adapter hook uses it for a
|
|
199
|
+
* fully-static page's `STATIC_FILE` and for an SSG/SSR page's `PAGES` output
|
|
200
|
+
* alike. Nothing else in the outputs carries `/`, so the mapping under test is
|
|
201
|
+
* the only thing that makes the home page routable.
|
|
202
|
+
*/
|
|
203
|
+
function withHomePage(basePath, kind) {
|
|
204
|
+
const ctx = asContext(pages_i18n_json_1.default);
|
|
205
|
+
ctx.config.i18n = null;
|
|
206
|
+
ctx.config.basePath = basePath;
|
|
207
|
+
ctx.outputs.staticFiles = [];
|
|
208
|
+
ctx.outputs.prerenders = [];
|
|
209
|
+
const page = ctx.outputs.pages.find((o) => o.pathname === "/ssr");
|
|
210
|
+
ctx.outputs.pages =
|
|
211
|
+
kind === "invocable"
|
|
212
|
+
? [{ ...page, id: "/index", pathname: `${basePath}/index` }]
|
|
213
|
+
: [];
|
|
214
|
+
if (kind === "static") {
|
|
215
|
+
ctx.outputs.staticFiles = [
|
|
216
|
+
{
|
|
217
|
+
id: "/",
|
|
218
|
+
pathname: `${basePath}/index`,
|
|
219
|
+
type: "STATIC_FILE",
|
|
220
|
+
filePath: "/repo/pages-i18n/.next/server/pages/index.html",
|
|
221
|
+
},
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
return build(ctx);
|
|
225
|
+
}
|
|
226
|
+
it("routes a fully-static Pages Router home page at `/`, not `/index`", () => {
|
|
227
|
+
const { manifest } = withHomePage("", "static");
|
|
228
|
+
const html = "pages-i18n/.next/server/pages/index.html";
|
|
229
|
+
expect(manifest.staticFiles["/"]).toBe(html);
|
|
230
|
+
expect(manifest.pathnames).toContain("/");
|
|
231
|
+
// Kept as well as `/`: next's minimal mode rewrites `/index` to `/` before
|
|
232
|
+
// matching, so it answers there too.
|
|
233
|
+
expect(manifest.staticFiles["/index"]).toBe(html);
|
|
234
|
+
});
|
|
235
|
+
it("routes an SSG or SSR home page's entrypoint at `/` as well", () => {
|
|
236
|
+
const { manifest } = withHomePage("", "invocable");
|
|
237
|
+
expect(manifest.entrypoints["/"]).toEqual(manifest.entrypoints["/index"]);
|
|
238
|
+
expect(manifest.pathnames).toContain("/");
|
|
239
|
+
// The output's own `id` is what next reported, and only names the entrypoint
|
|
240
|
+
// in diagnostics and group ownership - it is not a key into anything.
|
|
241
|
+
expect(manifest.entrypoints["/"].id).toBe("/index");
|
|
242
|
+
});
|
|
243
|
+
it("routes that home page under basePath at the basePath itself", () => {
|
|
244
|
+
// `/prod`, not `/prod/` — which is how the App Router fixture reports its own
|
|
245
|
+
// home page.
|
|
246
|
+
const { manifest } = withHomePage("/prod", "static");
|
|
247
|
+
expect(Object.keys(manifest.staticFiles)).toEqual(["/prod", "/prod/index"]);
|
|
248
|
+
});
|
|
249
|
+
it("leaves an App Router `/index` route at `/index`", () => {
|
|
250
|
+
// `app/index/page.tsx` is a real route. Only the Pages Router reports its
|
|
251
|
+
// home page as `/index`.
|
|
252
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
253
|
+
const home = ctx.outputs.appPages.find((o) => o.pathname === "/");
|
|
254
|
+
const indexFile = home.filePath.replace(/page\.js$/, "index/page.js");
|
|
255
|
+
ctx.outputs.appPages.push({
|
|
256
|
+
...home,
|
|
257
|
+
id: "/index",
|
|
258
|
+
pathname: "/index",
|
|
259
|
+
filePath: indexFile,
|
|
260
|
+
});
|
|
261
|
+
const { manifest } = build(ctx);
|
|
262
|
+
expect(manifest.entrypoints["/"].filePath).not.toBe(manifest.entrypoints["/index"].filePath);
|
|
263
|
+
expect(manifest.entrypoints["/index"].filePath).toMatch(/index\/page\.js$/);
|
|
264
|
+
});
|
|
265
|
+
it("records middleware without duplicating its matchers", () => {
|
|
266
|
+
const { manifest, groups: [{ staging }], } = build(asContext(app_playground_json_1.default));
|
|
267
|
+
expect(manifest.middleware).not.toBeNull();
|
|
268
|
+
expect(manifest.middleware.filePath).toMatch(/^[^/]/);
|
|
269
|
+
expect(staging.has(manifest.middleware.filePath)).toBe(true);
|
|
270
|
+
expect(manifest.middleware).not.toHaveProperty("matchers");
|
|
271
|
+
const { manifest: noMiddleware } = build(asContext(pages_i18n_json_1.default));
|
|
272
|
+
expect(noMiddleware.middleware).toBeNull();
|
|
273
|
+
});
|
|
274
|
+
it("maps a Pages Router data-route template to its owning route", () => {
|
|
275
|
+
// `/_next/data/<buildId>/<locale>/blog/[slug].json` exists only as a
|
|
276
|
+
// prerender. Without it, the ISR data URLs `next start` serves would 404.
|
|
277
|
+
const { manifest } = build(asContext(pages_i18n_json_1.default));
|
|
278
|
+
const dataTemplate = `/_next/data/${manifest.buildId}/fr/blog/[slug].json`;
|
|
279
|
+
expect(manifest.entrypoints[dataTemplate]).toEqual({
|
|
280
|
+
id: dataTemplate,
|
|
281
|
+
filePath: manifest.entrypoints["/fr/blog/[slug]"].filePath,
|
|
282
|
+
type: "page",
|
|
283
|
+
});
|
|
284
|
+
expect(manifest.pathnames).toContain(dataTemplate);
|
|
285
|
+
});
|
|
286
|
+
it("registers a static getStaticProps page's data route, which no rule reaches", () => {
|
|
287
|
+
// `test/e2e/no-page-props`: `/_next/data/<buildId>/gsp.json` 404'd while
|
|
288
|
+
// `next start` serves it 200, so every client-side navigation into the page
|
|
289
|
+
// fell back to a full page load. `next build` emits a `dynamicRoutes` rule for
|
|
290
|
+
// a data route only when the page is dynamic or the app has middleware, so
|
|
291
|
+
// without middleware a *static* page's data route arrives as a concrete
|
|
292
|
+
// prerender pathname with nothing to match it. Reproduced on `pages-i18n`,
|
|
293
|
+
// whose captured prerenders are all dynamic, by renaming one.
|
|
294
|
+
const ctx = asContext(pages_i18n_json_1.default);
|
|
295
|
+
const dataRoute = `/_next/data/${ctx.buildId}/en-US/gsp.json`;
|
|
296
|
+
const concrete = ctx.outputs.prerenders.find((it) => it.pathname.endsWith("hello.json"));
|
|
297
|
+
concrete.pathname = dataRoute;
|
|
298
|
+
concrete.id = dataRoute;
|
|
299
|
+
const { manifest } = build(ctx);
|
|
300
|
+
expect(manifest.entrypoints[dataRoute]).toEqual({
|
|
301
|
+
id: dataRoute,
|
|
302
|
+
filePath: manifest.entrypoints["/en-US/blog/[slug]"].filePath,
|
|
303
|
+
type: "page",
|
|
304
|
+
});
|
|
305
|
+
// And the dynamic page's own concrete data pathname stays out: the ungated
|
|
306
|
+
// `…/blog/[slug].json` rule already reaches it, and that rule is where the
|
|
307
|
+
// `nxtPslug` param comes from — resolving the request to itself would drop it.
|
|
308
|
+
const { manifest: captured } = build(asContext(pages_i18n_json_1.default));
|
|
309
|
+
expect(captured.entrypoints[`/_next/data/${captured.buildId}/en-US/blog/hello.json`]).toBeUndefined();
|
|
310
|
+
});
|
|
311
|
+
it("leaves an App Router fallback template on its own entrypoint", () => {
|
|
312
|
+
// `/isr/[id]` is a prerender *and* an appPages output. The output wins, so
|
|
313
|
+
// `id` stays the route's own rather than being rewritten.
|
|
314
|
+
const { manifest } = build(asContext(app_playground_json_1.default));
|
|
315
|
+
expect(manifest.entrypoints["/isr/[id]"].id).toBe("/isr/[id]");
|
|
316
|
+
expect(manifest.entrypoints["/isr/[id].rsc"]).toBeDefined();
|
|
317
|
+
});
|
|
318
|
+
it("adds a concrete prerender pathname when only a gated rule matches it", () => {
|
|
319
|
+
// What a root-params app produces: `app/[locale]/page.tsx` with
|
|
320
|
+
// `generateStaticParams()` and no `app/layout.tsx`. The params can never be
|
|
321
|
+
// filled at request time, so `next build` emits the `dynamicRoutes` rule with a
|
|
322
|
+
// draft-mode `has` and expects the platform to serve `/en` from the prerender.
|
|
323
|
+
// Measured against `test/e2e/app-dir/parallel-routes-root-param-dynamic-child`,
|
|
324
|
+
// where every URL of the app 404'd. Reproduced here by gating
|
|
325
|
+
// `app-playground`'s `/isr/[id]` rules, which no committed capture does.
|
|
326
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
327
|
+
for (const route of ctx.routing.dynamicRoutes) {
|
|
328
|
+
if (route.sourceRegex.includes("isr")) {
|
|
329
|
+
route.has = [
|
|
330
|
+
{ type: "cookie", key: "__prerender_bypass", value: "secret" },
|
|
331
|
+
];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const { manifest } = build(ctx);
|
|
335
|
+
expect(manifest.entrypoints["/isr/1"]).toEqual({
|
|
336
|
+
id: "/isr/1",
|
|
337
|
+
filePath: manifest.entrypoints["/isr/[id]"].filePath,
|
|
338
|
+
type: "app-page",
|
|
339
|
+
});
|
|
340
|
+
// The RSC and segment-prefetch variants too: they are the URLs a client-side
|
|
341
|
+
// navigation asks for, so without them the app renders and never hydrates.
|
|
342
|
+
expect(manifest.entrypoints["/isr/1.rsc"]).toBeDefined();
|
|
343
|
+
expect(manifest.entrypoints["/isr/1.segments/isr/$d$id/__PAGE__.segment.rsc"]).toBeDefined();
|
|
344
|
+
// Unmutated, the same pathnames stay out: the ungated rule already reaches
|
|
345
|
+
// `/isr/[id]`, which is where the `nxtPid` param comes from.
|
|
346
|
+
const { manifest: ungated } = build(asContext(app_playground_json_1.default));
|
|
347
|
+
expect(ungated.entrypoints["/isr/1"]).toBeUndefined();
|
|
348
|
+
expect(ungated.entrypoints["/isr/1.rsc"]).toBeUndefined();
|
|
349
|
+
// And a pathname no rule matches at all stays out either way: `resolveRoutes`
|
|
350
|
+
// never resolves a static route's segment outputs, so listing them is weight.
|
|
351
|
+
expect(manifest.entrypoints["/index.segments/_tree.segment.rsc"]).toBeUndefined();
|
|
352
|
+
});
|
|
353
|
+
it("leaves public/ out of the manifest and the staging plan", async () => {
|
|
354
|
+
// The container runtime lists `public/` off disk at cold start
|
|
355
|
+
// (`readPublicFiles`), because only the disk has what a `postbuild` wrote
|
|
356
|
+
// into it after this hook ran; and the Lambda types never serve it.
|
|
357
|
+
const repoRoot = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "cdk-nextjs-public-"));
|
|
358
|
+
// Every path in the fixture, rebased from `/repo` onto a real directory.
|
|
359
|
+
const ctx = asContext(JSON.parse(JSON.stringify(app_playground_base_path_json_1.default).replaceAll('"/repo', `"${repoRoot}`)));
|
|
360
|
+
await (0, promises_1.mkdir)((0, node_path_1.join)(ctx.projectDir, "public"), { recursive: true });
|
|
361
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(ctx.projectDir, "public", "test.txt"), "hello");
|
|
362
|
+
const { manifest, groups: [{ staging }], } = build(ctx);
|
|
363
|
+
expect(Object.values(manifest.staticFiles).filter((key) => key.includes("/public/"))).toEqual([]);
|
|
364
|
+
expect(manifest.pathnames).not.toContain("/prod/test.txt");
|
|
365
|
+
expect([...staging.keys()].filter((key) => key.includes("/public/"))).toEqual([]);
|
|
366
|
+
});
|
|
367
|
+
it("warns instead of throwing when a template has no owning route", () => {
|
|
368
|
+
const warn = jest.spyOn(console, "warn").mockImplementation(() => { });
|
|
369
|
+
const ctx = asContext(pages_i18n_json_1.default);
|
|
370
|
+
ctx.outputs.prerenders[0].route = "/gone/[slug]";
|
|
371
|
+
ctx.outputs.prerenders[0].pathname = "/gone/[slug]";
|
|
372
|
+
const { manifest } = build(ctx);
|
|
373
|
+
expect(manifest.entrypoints["/gone/[slug]"]).toBeUndefined();
|
|
374
|
+
expect(warn.mock.calls
|
|
375
|
+
.map((call) => String(call[0]))
|
|
376
|
+
.filter((message) => message.includes("will 404"))).toEqual([
|
|
377
|
+
expect.stringContaining('/gone/[slug] (route: "/gone/[slug]")'),
|
|
378
|
+
]);
|
|
379
|
+
});
|
|
380
|
+
it("warns once per unsupported route config key", () => {
|
|
381
|
+
const warn = jest.spyOn(console, "warn").mockImplementation(() => { });
|
|
382
|
+
build(asContext(pages_i18n_json_1.default));
|
|
383
|
+
const messages = warn.mock.calls.map((call) => String(call[0]));
|
|
384
|
+
expect(messages.filter((m) => m.includes("`maxDuration`"))).toHaveLength(1);
|
|
385
|
+
expect(messages[0]).toContain("ssr");
|
|
386
|
+
expect(messages[0]).toContain("overrides");
|
|
387
|
+
expect(messages.some((m) => m.includes("`preferredRegion`"))).toBe(false);
|
|
388
|
+
});
|
|
389
|
+
it("throws on an edge-runtime output", () => {
|
|
390
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
391
|
+
ctx.outputs.appRoutes[0].runtime = "edge";
|
|
392
|
+
expect(() => build(ctx)).toThrow(/cannot deploy routes built for the edge runtime/);
|
|
393
|
+
expect(() => build(ctx)).toThrow(ctx.outputs.appRoutes[0].sourcePage);
|
|
394
|
+
});
|
|
395
|
+
it("blames middleware, not `/`, for edge-runtime middleware", () => {
|
|
396
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
397
|
+
const middleware = ctx.outputs.middleware;
|
|
398
|
+
if (!middleware) {
|
|
399
|
+
throw new Error("fixture has no middleware output");
|
|
400
|
+
}
|
|
401
|
+
// What a legacy `middleware.ts` builds to. Its `sourcePage` is `/`, so the
|
|
402
|
+
// regression guarded here is the message telling an author to edit the home
|
|
403
|
+
// page.
|
|
404
|
+
middleware.runtime = "edge";
|
|
405
|
+
expect(() => build(ctx)).toThrow(/cannot deploy middleware built for the edge runtime/);
|
|
406
|
+
expect(() => build(ctx)).toThrow(middleware.filePath);
|
|
407
|
+
// Both ways out: `middleware.ts` only defaults to edge.
|
|
408
|
+
expect(() => build(ctx)).toThrow(/runtime: "nodejs"/);
|
|
409
|
+
expect(() => build(ctx)).toThrow(/proxy\.ts/);
|
|
410
|
+
expect(() => build(ctx)).not.toThrow(/edge-only/);
|
|
411
|
+
expect(() => build(ctx)).not.toThrow(/cannot deploy routes built for the edge runtime/);
|
|
412
|
+
});
|
|
413
|
+
it("throws when two outputs map one key to different content", () => {
|
|
414
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
415
|
+
const [first, second] = ctx.outputs.appPages;
|
|
416
|
+
const key = Object.keys(first.assets)[0];
|
|
417
|
+
first.assetsHashes[key] = "hash-a";
|
|
418
|
+
second.assets[key] = first.assets[key];
|
|
419
|
+
second.assetsHashes[key] = "hash-b";
|
|
420
|
+
expect(() => build(ctx)).toThrow(/map "[^"]+" to different content/);
|
|
421
|
+
});
|
|
422
|
+
it("throws on an asset key outside the deployment root", () => {
|
|
423
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
424
|
+
ctx.outputs.appPages[0].assets["../escape.js"] = "/elsewhere/escape.js";
|
|
425
|
+
expect(() => build(ctx)).toThrow(/outside the deployment root/);
|
|
426
|
+
});
|
|
427
|
+
it("throws on an asset key shadowing the reserved runtime directory", () => {
|
|
428
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
429
|
+
ctx.outputs.appPages[0].assets[`${manifest_1.RUNTIME_DIR_NAME}/lambda.mjs`] =
|
|
430
|
+
"/repo/whatever.mjs";
|
|
431
|
+
expect(() => build(ctx)).toThrow(new RegExp(`"${manifest_1.RUNTIME_DIR_NAME}/" is reserved`));
|
|
432
|
+
});
|
|
433
|
+
it("throws when two outputs claim one pathname from different files", () => {
|
|
434
|
+
const ctx = asContext(app_playground_json_1.default);
|
|
435
|
+
ctx.outputs.appRoutes[0].pathname = ctx.outputs.appPages[0].pathname;
|
|
436
|
+
expect(() => build(ctx)).toThrow(/claim the pathname "[^"]+"/);
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
describe("writeBuildOutputs", () => {
|
|
440
|
+
/**
|
|
441
|
+
* Builds a throwaway repo on disk so staging can be exercised for real:
|
|
442
|
+
* fixture sources are `/repo` placeholders and cannot be copied.
|
|
443
|
+
*/
|
|
444
|
+
/**
|
|
445
|
+
* A `next` install just real enough for {@link addRuntimeNextClosure}: the
|
|
446
|
+
* modules `src/runtime/image.ts` requires, one file only the trace reaches, and
|
|
447
|
+
* a stand-in for next's vendored `@vercel/nft` that reports them. Tracing for
|
|
448
|
+
* real is next's job, not ours; what is under test is that the closure is
|
|
449
|
+
* resolved from the project dir and staged under repo-root-relative keys.
|
|
450
|
+
*/
|
|
451
|
+
async function installFakeNext(repoRoot, options = {}) {
|
|
452
|
+
// Under pnpm, `next` lives in the virtual store behind a link, and its own
|
|
453
|
+
// dependencies are links beside it.
|
|
454
|
+
const storeModules = (0, node_path_1.join)(repoRoot, "node_modules", ".pnpm", "next@1.0.0", "node_modules");
|
|
455
|
+
const nextRoot = options.pnpm
|
|
456
|
+
? (0, node_path_1.join)(storeModules, "next")
|
|
457
|
+
: (0, node_path_1.join)(repoRoot, "node_modules", "next");
|
|
458
|
+
if (options.pnpm) {
|
|
459
|
+
const nextEnv = (0, node_path_1.join)(repoRoot, "node_modules", ".pnpm", "@next+env@1.0.0", "node_modules", "@next", "env");
|
|
460
|
+
await (0, promises_1.mkdir)(nextEnv, { recursive: true });
|
|
461
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(nextEnv, "index.js"), "// @next/env\n");
|
|
462
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(nextEnv, "package.json"), JSON.stringify({ name: "@next/env", main: "index.js" }));
|
|
463
|
+
await (0, promises_1.mkdir)((0, node_path_1.join)(storeModules, "@next"), { recursive: true });
|
|
464
|
+
await (0, promises_1.symlink)("../../../@next+env@1.0.0/node_modules/@next/env", (0, node_path_1.join)(storeModules, "@next", "env"));
|
|
465
|
+
await (0, promises_1.mkdir)(nextRoot, { recursive: true });
|
|
466
|
+
await (0, promises_1.symlink)(".pnpm/next@1.0.0/node_modules/next", (0, node_path_1.join)(repoRoot, "node_modules", "next"));
|
|
467
|
+
}
|
|
468
|
+
const files = [
|
|
469
|
+
"dist/server/config-shared.js",
|
|
470
|
+
"dist/shared/lib/image-config.js",
|
|
471
|
+
"dist/server/image-optimizer.js",
|
|
472
|
+
"dist/server/serve-static.js",
|
|
473
|
+
// Reached only through the trace, i.e. the reason tracing is needed.
|
|
474
|
+
"dist/shared/lib/match-remote-pattern.js",
|
|
475
|
+
];
|
|
476
|
+
for (const file of files) {
|
|
477
|
+
const path = (0, node_path_1.join)(nextRoot, file);
|
|
478
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(path), { recursive: true });
|
|
479
|
+
await (0, promises_1.writeFile)(path, `// ${file}\n`);
|
|
480
|
+
}
|
|
481
|
+
// No `exports` field: `next/dist/**` is required by path.
|
|
482
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(nextRoot, "package.json"), JSON.stringify({ name: "next", version: "0.0.0-test" }));
|
|
483
|
+
const tracer = (0, node_path_1.join)(nextRoot, "dist", "compiled", "@vercel", "nft");
|
|
484
|
+
await (0, promises_1.mkdir)(tracer, { recursive: true });
|
|
485
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(tracer, "package.json"), JSON.stringify({ name: "@vercel/nft", main: "index.js" }));
|
|
486
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(tracer, "index.js"),
|
|
487
|
+
// Real nft returns paths relative to `base`, which is the repo root the
|
|
488
|
+
// adapter passes.
|
|
489
|
+
`const prefix = ${JSON.stringify((0, node_path_1.relative)(repoRoot, nextRoot).split(node_path_1.sep).join("/"))};\n` +
|
|
490
|
+
"const { realpathSync } = require('node:fs');\n" +
|
|
491
|
+
"const { relative } = require('node:path');\n" +
|
|
492
|
+
"exports.nodeFileTrace = async (entries, { base }) => {\n" +
|
|
493
|
+
// Like real nft, the entries themselves are in the list.
|
|
494
|
+
" const traced = entries\n" +
|
|
495
|
+
" .map((e) => relative(realpathSync(base), e))\n" +
|
|
496
|
+
" .filter((e) => !e.startsWith('..'));\n" +
|
|
497
|
+
" if (traced.some((e) => e.endsWith('image-optimizer.js'))) {\n" +
|
|
498
|
+
" traced.push(`${prefix}/dist/shared/lib/match-remote-pattern.js`);\n" +
|
|
499
|
+
" }\n" +
|
|
500
|
+
" return { fileList: new Set(traced) };\n" +
|
|
501
|
+
"};\n");
|
|
502
|
+
}
|
|
503
|
+
async function makeRepo(options = {}) {
|
|
504
|
+
const repoRoot = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "cdk-nextjs-staging-"));
|
|
505
|
+
if (options.withNext || options.pnpmNext) {
|
|
506
|
+
await installFakeNext(repoRoot, { pnpm: options.pnpmNext });
|
|
507
|
+
}
|
|
508
|
+
const projectDir = (0, node_path_1.join)(repoRoot, "app");
|
|
509
|
+
const distDir = (0, node_path_1.join)(projectDir, ".next");
|
|
510
|
+
const entry = (0, node_path_1.join)(distDir, "server", "app", "page.js");
|
|
511
|
+
const dep = (0, node_path_1.join)(projectDir, "node_modules", "dep");
|
|
512
|
+
const store = (0, node_path_1.join)(repoRoot, "store", "pkg");
|
|
513
|
+
// pnpm's virtual store: one package reachable only from inside it, and one
|
|
514
|
+
// that also has a logical path (`app/node_modules/dep`).
|
|
515
|
+
const virtualStore = (0, node_path_1.join)(repoRoot, "node_modules", ".pnpm");
|
|
516
|
+
const hidden = (0, node_path_1.join)(virtualStore, "helpers@1.0.0", "node_modules", "@scope", "helpers");
|
|
517
|
+
const depInStore = (0, node_path_1.join)(virtualStore, "dep@1.0.0", "node_modules", "dep");
|
|
518
|
+
// The shape that makes a store package reachable from another store
|
|
519
|
+
// package: a link between two store directories, no files of its own.
|
|
520
|
+
const hiddenLink = (0, node_path_1.join)(virtualStore, "dep@1.0.0", "node_modules", "@scope", "helpers");
|
|
521
|
+
await (0, promises_1.mkdir)((0, node_path_1.join)(distDir, "server", "app"), { recursive: true });
|
|
522
|
+
// Every deployment root needs this, and `loadRuntime` refuses to serve
|
|
523
|
+
// without it, so the staging plan carries it independently of any output's
|
|
524
|
+
// traced assets.
|
|
525
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(distDir, "required-server-files.json"), "{}\n");
|
|
526
|
+
await (0, promises_1.mkdir)(dep, { recursive: true });
|
|
527
|
+
await (0, promises_1.mkdir)(store, { recursive: true });
|
|
528
|
+
await (0, promises_1.mkdir)(hidden, { recursive: true });
|
|
529
|
+
await (0, promises_1.mkdir)(depInStore, { recursive: true });
|
|
530
|
+
await (0, promises_1.writeFile)(entry, "module.exports = {};\n");
|
|
531
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(dep, "index.js"), "// dep\n");
|
|
532
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(store, "index.js"), "// store\n");
|
|
533
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(hidden, "index.js"), "// helpers\n");
|
|
534
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(depInStore, "index.js"), "// dep\n");
|
|
535
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(hiddenLink), { recursive: true });
|
|
536
|
+
await (0, promises_1.symlink)((0, node_path_1.join)("..", "..", "..", "helpers@1.0.0", "node_modules", "@scope", "helpers"), hiddenLink);
|
|
537
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(projectDir, ".env"), "SHARED=1\n");
|
|
538
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(projectDir, ".env.production"), "PROD=1\n");
|
|
539
|
+
// A relative link whose target is itself staged: pnpm's common shape.
|
|
540
|
+
await (0, promises_1.symlink)("dep", (0, node_path_1.join)(projectDir, "node_modules", "rel-link"));
|
|
541
|
+
// An absolute link out of the tree: staging must materialize it instead.
|
|
542
|
+
await (0, promises_1.symlink)(store, (0, node_path_1.join)(projectDir, "node_modules", "abs-link"));
|
|
543
|
+
const output = {
|
|
544
|
+
id: "/",
|
|
545
|
+
pathname: "/",
|
|
546
|
+
sourcePage: "/page",
|
|
547
|
+
filePath: entry,
|
|
548
|
+
runtime: "nodejs",
|
|
549
|
+
config: {},
|
|
550
|
+
assets: {
|
|
551
|
+
"app/node_modules/dep/index.js": (0, node_path_1.join)(dep, "index.js"),
|
|
552
|
+
"app/node_modules/rel-link": (0, node_path_1.join)(projectDir, "node_modules", "rel-link"),
|
|
553
|
+
"app/node_modules/abs-link": (0, node_path_1.join)(projectDir, "node_modules", "abs-link"),
|
|
554
|
+
"node_modules/.pnpm/helpers@1.0.0/node_modules/@scope/helpers/index.js": (0, node_path_1.join)(hidden, "index.js"),
|
|
555
|
+
"node_modules/.pnpm/dep@1.0.0/node_modules/dep/index.js": (0, node_path_1.join)(depInStore, "index.js"),
|
|
556
|
+
"node_modules/.pnpm/dep@1.0.0/node_modules/@scope/helpers": hiddenLink,
|
|
557
|
+
},
|
|
558
|
+
assetsHashes: {},
|
|
559
|
+
};
|
|
560
|
+
const ctx = {
|
|
561
|
+
repoRoot,
|
|
562
|
+
projectDir,
|
|
563
|
+
distDir,
|
|
564
|
+
buildId: "test-build",
|
|
565
|
+
nextVersion: "16.3.5",
|
|
566
|
+
config: {
|
|
567
|
+
basePath: "",
|
|
568
|
+
trailingSlash: false,
|
|
569
|
+
assetPrefix: "",
|
|
570
|
+
i18n: null,
|
|
571
|
+
},
|
|
572
|
+
routing: { dynamicRoutes: [] },
|
|
573
|
+
outputs: {
|
|
574
|
+
pages: [],
|
|
575
|
+
pagesApi: [],
|
|
576
|
+
appPages: [output],
|
|
577
|
+
appRoutes: [],
|
|
578
|
+
prerenders: [],
|
|
579
|
+
staticFiles: [],
|
|
580
|
+
middleware: undefined,
|
|
581
|
+
},
|
|
582
|
+
};
|
|
583
|
+
return { ctx, repoRoot };
|
|
584
|
+
}
|
|
585
|
+
it("stages the tree, preserves symlinks, and writes the manifest", async () => {
|
|
586
|
+
const { ctx } = await makeRepo();
|
|
587
|
+
const result = await write(ctx);
|
|
588
|
+
expect(soleRoot(result)).toBe((0, node_path_1.join)(ctx.distDir, "cdk-nextjs-adapter", "app"));
|
|
589
|
+
const staged = (...parts) => (0, node_path_1.join)(soleRoot(result), ...parts);
|
|
590
|
+
await expect((0, promises_1.readFile)(staged("app", ".next", "server", "app", "page.js"), "utf8")).resolves.toContain("module.exports");
|
|
591
|
+
await expect((0, promises_1.readFile)(staged("app", "node_modules", "dep", "index.js"), "utf8")).resolves.toContain("dep");
|
|
592
|
+
// `copyFile` fails outright on a directory symlink, and dereferencing the
|
|
593
|
+
// pnpm store triples the tree against the 250 MB unzipped Lambda limit.
|
|
594
|
+
await expect((0, promises_1.lstat)(staged("app", "node_modules", "rel-link")).then((s) => s.isSymbolicLink())).resolves.toBe(true);
|
|
595
|
+
// Points outside the deployment root, so it would dangle in Lambda.
|
|
596
|
+
await expect((0, promises_1.lstat)(staged("app", "node_modules", "abs-link")).then((s) => s.isSymbolicLink())).resolves.toBe(false);
|
|
597
|
+
await expect((0, promises_1.readFile)(staged("app", "node_modules", "abs-link", "index.js"), "utf8")).resolves.toContain("store");
|
|
598
|
+
// `writeStandaloneDirectory` copies these; `onBuildComplete` has no
|
|
599
|
+
// equivalent, so dropping `output: "standalone"` drops them silently.
|
|
600
|
+
await expect((0, promises_1.readFile)(staged("app", ".env"), "utf8")).resolves.toContain("SHARED=1");
|
|
601
|
+
await expect((0, promises_1.readFile)(staged("app", ".env.production"), "utf8")).resolves.toContain("PROD=1");
|
|
602
|
+
const written = JSON.parse(await (0, promises_1.readFile)(result.manifestPath, "utf8"));
|
|
603
|
+
expect(written).toEqual(JSON.parse(JSON.stringify(result.manifest)));
|
|
604
|
+
expect(written.relativeProjectDir).toBe("app");
|
|
605
|
+
});
|
|
606
|
+
it("leaves store-only packages in the store, behind their links", async () => {
|
|
607
|
+
const { ctx } = await makeRepo();
|
|
608
|
+
const result = await write(ctx);
|
|
609
|
+
const staged = (...parts) => (0, node_path_1.join)(soleRoot(result), ...parts);
|
|
610
|
+
// Node resolves `@scope/helpers` from `dep` through the store link, as it
|
|
611
|
+
// does in the workspace, so long as nothing dereferences the tree (the
|
|
612
|
+
// Functions zip keeps links as links). A copy at the root is dead weight.
|
|
613
|
+
await expect((0, promises_1.lstat)(staged("node_modules", "@scope", "helpers"))).rejects.toThrow(/ENOENT/);
|
|
614
|
+
await expect((0, promises_1.lstat)(staged("node_modules", ".pnpm", "dep@1.0.0", "node_modules", "@scope", "helpers")).then((s) => s.isSymbolicLink())).resolves.toBe(true);
|
|
615
|
+
await expect((0, promises_1.readFile)(staged("node_modules", ".pnpm", "dep@1.0.0", "node_modules", "@scope", "helpers", "index.js"), "utf8")).resolves.toContain("helpers");
|
|
616
|
+
});
|
|
617
|
+
it("stages the next closure the runtime's image optimizer requires", async () => {
|
|
618
|
+
// `next build` traces what the *app* reaches, and no app reaches next's
|
|
619
|
+
// image optimizer, so without this every /_next/image request 500s on a
|
|
620
|
+
// MODULE_NOT_FOUND that nothing in the build warned about.
|
|
621
|
+
const { ctx } = await makeRepo({ withNext: true });
|
|
622
|
+
const result = await write(ctx);
|
|
623
|
+
const staged = (...parts) => (0, node_path_1.join)(soleRoot(result), ...parts);
|
|
624
|
+
await expect((0, promises_1.readFile)(staged("node_modules", "next", "dist", "server", "image-optimizer.js"), "utf8")).resolves.toContain("image-optimizer");
|
|
625
|
+
await expect((0, promises_1.readFile)(staged("node_modules", "next", "dist", "shared", "lib", "match-remote-pattern.js"), "utf8")).resolves.toContain("match-remote-pattern");
|
|
626
|
+
});
|
|
627
|
+
it("stages the link next resolves @next/env through under pnpm", async () => {
|
|
628
|
+
// The trace starts at `@next/env`'s real path and so never records the
|
|
629
|
+
// link beside `next`; without it every cold start threw "Cannot find
|
|
630
|
+
// module '@next/env'".
|
|
631
|
+
const { ctx } = await makeRepo({ pnpmNext: true });
|
|
632
|
+
const result = await write(ctx);
|
|
633
|
+
const link = (0, node_path_1.join)(soleRoot(result), "node_modules", ".pnpm", "next@1.0.0", "node_modules", "@next", "env");
|
|
634
|
+
expect((await (0, promises_1.lstat)(link)).isSymbolicLink()).toBe(true);
|
|
635
|
+
await expect((0, promises_1.readFile)((0, node_path_1.join)(link, "index.js"), "utf8")).resolves.toContain("@next/env");
|
|
636
|
+
});
|
|
637
|
+
it("warns instead of failing when next cannot be resolved for tracing", async () => {
|
|
638
|
+
const { ctx } = await makeRepo();
|
|
639
|
+
const warn = jest.spyOn(console, "warn").mockImplementation(() => { });
|
|
640
|
+
await expect(write(ctx)).resolves.toBeDefined();
|
|
641
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining("/_next/image will fail at runtime"));
|
|
642
|
+
});
|
|
643
|
+
it("removes a previous build's tree before staging", async () => {
|
|
644
|
+
const { ctx } = await makeRepo();
|
|
645
|
+
const first = await write(ctx);
|
|
646
|
+
const stale = (0, node_path_1.join)(soleRoot(first), "app", "stale.js");
|
|
647
|
+
await (0, promises_1.writeFile)(stale, "// removed route\n");
|
|
648
|
+
await write(ctx);
|
|
649
|
+
await expect((0, promises_1.lstat)(stale)).rejects.toThrow(/ENOENT/);
|
|
650
|
+
});
|
|
651
|
+
describe("with functionGroups", () => {
|
|
652
|
+
/**
|
|
653
|
+
* Two routes with one asset each, so "the group's tree holds its own route
|
|
654
|
+
* and not the other's" is checkable by file. Deliberately not `makeRepo`'s
|
|
655
|
+
* repo: its single output cannot be split.
|
|
656
|
+
*/
|
|
657
|
+
async function makeSplittableRepo(options = {}) {
|
|
658
|
+
const repoRoot = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "cdk-nextjs-groups-"));
|
|
659
|
+
if (options.withNext) {
|
|
660
|
+
await installFakeNext(repoRoot);
|
|
661
|
+
}
|
|
662
|
+
const projectDir = (0, node_path_1.join)(repoRoot, "app");
|
|
663
|
+
const distDir = (0, node_path_1.join)(projectDir, ".next");
|
|
664
|
+
await (0, promises_1.mkdir)((0, node_path_1.join)(distDir, "server", "app"), { recursive: true });
|
|
665
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(distDir, "required-server-files.json"), "{}\n");
|
|
666
|
+
const outputFor = async (name, pathname) => {
|
|
667
|
+
const entry = (0, node_path_1.join)(distDir, "server", "app", `${name}.js`);
|
|
668
|
+
const asset = (0, node_path_1.join)(projectDir, "node_modules", name, "index.js");
|
|
669
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(asset), { recursive: true });
|
|
670
|
+
await (0, promises_1.writeFile)(entry, `// ${name}\n`);
|
|
671
|
+
await (0, promises_1.writeFile)(asset, `// ${name} dep\n`);
|
|
672
|
+
return {
|
|
673
|
+
id: pathname,
|
|
674
|
+
pathname,
|
|
675
|
+
sourcePage: pathname,
|
|
676
|
+
filePath: entry,
|
|
677
|
+
runtime: "nodejs",
|
|
678
|
+
config: {},
|
|
679
|
+
assets: { [`app/node_modules/${name}/index.js`]: asset },
|
|
680
|
+
assetsHashes: {},
|
|
681
|
+
};
|
|
682
|
+
};
|
|
683
|
+
const ctx = {
|
|
684
|
+
repoRoot,
|
|
685
|
+
projectDir,
|
|
686
|
+
distDir,
|
|
687
|
+
buildId: "test-build",
|
|
688
|
+
nextVersion: "16.3.5",
|
|
689
|
+
config: {
|
|
690
|
+
basePath: "",
|
|
691
|
+
trailingSlash: false,
|
|
692
|
+
assetPrefix: "",
|
|
693
|
+
i18n: null,
|
|
694
|
+
},
|
|
695
|
+
routing: { dynamicRoutes: [] },
|
|
696
|
+
outputs: {
|
|
697
|
+
pages: options.withPagesSsr
|
|
698
|
+
? await (async () => {
|
|
699
|
+
const page = await outputFor("ssr", "/ssr");
|
|
700
|
+
// A separate output, with its own id, backed by the same file.
|
|
701
|
+
const dataRoute = "/_next/data/test-build/ssr.json";
|
|
702
|
+
return [page, { ...page, id: dataRoute, pathname: dataRoute }];
|
|
703
|
+
})()
|
|
704
|
+
: [],
|
|
705
|
+
pagesApi: [],
|
|
706
|
+
appPages: [
|
|
707
|
+
await outputFor("home", "/"),
|
|
708
|
+
...(options.withNotFound
|
|
709
|
+
? [await outputFor("not-found", "/_not-found")]
|
|
710
|
+
: []),
|
|
711
|
+
],
|
|
712
|
+
appRoutes: [await outputFor("reports", "/api/reports/[id]")],
|
|
713
|
+
prerenders: [],
|
|
714
|
+
staticFiles: [],
|
|
715
|
+
middleware: undefined,
|
|
716
|
+
},
|
|
717
|
+
};
|
|
718
|
+
return { ctx };
|
|
719
|
+
}
|
|
720
|
+
const groups = [{ name: "reports", routes: ["/api/reports/**"] }];
|
|
721
|
+
it("records the assignment in the manifest every group shares", async () => {
|
|
722
|
+
const { ctx } = await makeSplittableRepo();
|
|
723
|
+
const { manifest } = (0, build_outputs_1.buildAdapterManifest)(ctx, {
|
|
724
|
+
buildCwd: ctx.projectDir,
|
|
725
|
+
functionGroups: groups,
|
|
726
|
+
});
|
|
727
|
+
expect(manifest.groups).toEqual({
|
|
728
|
+
default: ["/"],
|
|
729
|
+
reports: ["/api/reports/[id]"],
|
|
730
|
+
});
|
|
731
|
+
// What synth compares its own props with, to catch a stale build.
|
|
732
|
+
expect(manifest.functionGroups).toEqual(groups);
|
|
733
|
+
// And what it deploys, as the assignment checked it.
|
|
734
|
+
expect(manifest.behaviors).toEqual([
|
|
735
|
+
{
|
|
736
|
+
group: "reports",
|
|
737
|
+
route: "/api/reports/**",
|
|
738
|
+
pattern: "api/reports/*",
|
|
739
|
+
},
|
|
740
|
+
]);
|
|
741
|
+
});
|
|
742
|
+
it("stages one tree per group, each holding only its own routes", async () => {
|
|
743
|
+
const { ctx } = await makeSplittableRepo();
|
|
744
|
+
const result = await (0, build_outputs_1.writeBuildOutputs)(ctx, {
|
|
745
|
+
buildCwd: ctx.projectDir,
|
|
746
|
+
functionGroups: groups,
|
|
747
|
+
});
|
|
748
|
+
expect(result.stagedGroups.map((group) => group.name).sort()).toEqual([
|
|
749
|
+
"default",
|
|
750
|
+
"reports",
|
|
751
|
+
]);
|
|
752
|
+
const pathOf = (name) => {
|
|
753
|
+
const group = result.stagedGroups.find((it) => it.name === name);
|
|
754
|
+
if (!group) {
|
|
755
|
+
throw new Error(`No staged group "${name}"`);
|
|
756
|
+
}
|
|
757
|
+
return group.path;
|
|
758
|
+
};
|
|
759
|
+
// Under `groups/<name>/`, so neither can collide with the unsplit layout.
|
|
760
|
+
expect(pathOf("reports")).toBe((0, node_path_1.join)(ctx.distDir, "cdk-nextjs-adapter", "groups", "reports"));
|
|
761
|
+
expect(pathOf("default")).toBe((0, node_path_1.join)(ctx.distDir, "cdk-nextjs-adapter", "groups", "default"));
|
|
762
|
+
const has = (name, ...parts) => (0, promises_1.lstat)((0, node_path_1.join)(pathOf(name), ...parts)).then(() => true, () => false);
|
|
763
|
+
await expect(has("reports", "app", ".next", "server", "app", "reports.js")).resolves.toBe(true);
|
|
764
|
+
await expect(has("reports", "app", "node_modules", "reports", "index.js")).resolves.toBe(true);
|
|
765
|
+
// The point of splitting: the other group's route is absent.
|
|
766
|
+
await expect(has("reports", "app", ".next", "server", "app", "home.js")).resolves.toBe(false);
|
|
767
|
+
await expect(has("default", "app", ".next", "server", "app", "home.js")).resolves.toBe(true);
|
|
768
|
+
await expect(has("default", "app", ".next", "server", "app", "reports.js")).resolves.toBe(false);
|
|
769
|
+
// The manifest is written once, above the groups; `NextjsBuild` copies it
|
|
770
|
+
// and the runtime shell into each group's reserved runtime dir afterwards,
|
|
771
|
+
// so no group's staged tree may contain that directory yet.
|
|
772
|
+
expect(result.manifestPath).toBe((0, node_path_1.join)(ctx.distDir, "cdk-nextjs-adapter", "manifest.json"));
|
|
773
|
+
for (const name of ["default", "reports"]) {
|
|
774
|
+
await expect(has(name, manifest_1.RUNTIME_DIR_NAME)).resolves.toBe(false);
|
|
775
|
+
}
|
|
776
|
+
// `required-server-files.json` is not any output's traced asset, so a
|
|
777
|
+
// group that reaches it only through the outputs it owns does not get it -
|
|
778
|
+
// and `loadRuntime` probes for it before serving anything, so the whole
|
|
779
|
+
// root answers "the deployment package is incomplete" without it.
|
|
780
|
+
for (const name of ["default", "reports"]) {
|
|
781
|
+
await expect(has(name, "app", ".next", "required-server-files.json")).resolves.toBe(true);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
it("stages the image optimizer into default only, serve-static into every group", async () => {
|
|
785
|
+
// Only `default` answers `/_next/image`, and the optimizer is what pulls
|
|
786
|
+
// `sharp` in; prerendered and static results are served with
|
|
787
|
+
// `serve-static` in whichever group they land.
|
|
788
|
+
const { ctx } = await makeSplittableRepo({ withNext: true });
|
|
789
|
+
const result = await (0, build_outputs_1.writeBuildOutputs)(ctx, {
|
|
790
|
+
buildCwd: ctx.projectDir,
|
|
791
|
+
functionGroups: groups,
|
|
792
|
+
});
|
|
793
|
+
const has = (name, file) => (0, promises_1.lstat)((0, node_path_1.join)(result.stagedGroups.find((it) => it.name === name).path, "node_modules", "next", "dist", file)).then(() => true, () => false);
|
|
794
|
+
for (const file of [
|
|
795
|
+
"server/image-optimizer.js",
|
|
796
|
+
"shared/lib/image-config.js",
|
|
797
|
+
"server/config-shared.js",
|
|
798
|
+
"shared/lib/match-remote-pattern.js",
|
|
799
|
+
]) {
|
|
800
|
+
await expect(has("default", file)).resolves.toBe(true);
|
|
801
|
+
await expect(has("reports", file)).resolves.toBe(false);
|
|
802
|
+
}
|
|
803
|
+
for (const name of ["default", "reports"]) {
|
|
804
|
+
await expect(has(name, "server/serve-static.js")).resolves.toBe(true);
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
it("stages the not-found page into every group, not only its owner", async () => {
|
|
808
|
+
// The runtime renders a 404 with the manifest's `/_not-found` wherever the
|
|
809
|
+
// request landed, so `/api/reports/nope` needs it in the reports group.
|
|
810
|
+
const { ctx } = await makeSplittableRepo({ withNotFound: true });
|
|
811
|
+
const { groups: staged, manifest } = (0, build_outputs_1.buildAdapterManifest)(ctx, {
|
|
812
|
+
buildCwd: ctx.projectDir,
|
|
813
|
+
functionGroups: groups,
|
|
814
|
+
});
|
|
815
|
+
expect(manifest.groups?.default).toContain("/_not-found");
|
|
816
|
+
expect(staged.map((group) => group.name).sort()).toEqual([
|
|
817
|
+
"default",
|
|
818
|
+
"reports",
|
|
819
|
+
]);
|
|
820
|
+
for (const group of staged) {
|
|
821
|
+
expect([...group.staging.keys()]).toContain("app/.next/server/app/not-found.js");
|
|
822
|
+
}
|
|
823
|
+
});
|
|
824
|
+
it("keeps a Pages Router page's data route in the page's group", async () => {
|
|
825
|
+
const { ctx } = await makeSplittableRepo({ withPagesSsr: true });
|
|
826
|
+
const { groups: staged, manifest } = (0, build_outputs_1.buildAdapterManifest)(ctx, {
|
|
827
|
+
buildCwd: ctx.projectDir,
|
|
828
|
+
functionGroups: [{ name: "ssr", routes: ["/ssr"] }],
|
|
829
|
+
});
|
|
830
|
+
expect(manifest.groups?.ssr).toEqual([
|
|
831
|
+
"/_next/data/test-build/ssr.json",
|
|
832
|
+
"/ssr",
|
|
833
|
+
]);
|
|
834
|
+
const defaultGroup = staged.find((group) => group.name === "default");
|
|
835
|
+
// Otherwise the page and its trace ship in the default zip as well.
|
|
836
|
+
expect([...defaultGroup.staging.keys()]).not.toContain("app/.next/server/app/ssr.js");
|
|
837
|
+
});
|
|
838
|
+
it("refuses to split an i18n app, whose routes are locale-prefixed", async () => {
|
|
839
|
+
const { ctx } = await makeSplittableRepo();
|
|
840
|
+
const i18nCtx = {
|
|
841
|
+
...ctx,
|
|
842
|
+
config: {
|
|
843
|
+
...ctx.config,
|
|
844
|
+
i18n: { locales: ["en"], defaultLocale: "en" },
|
|
845
|
+
},
|
|
846
|
+
};
|
|
847
|
+
expect(() => (0, build_outputs_1.buildAdapterManifest)(i18nCtx, {
|
|
848
|
+
buildCwd: ctx.projectDir,
|
|
849
|
+
functionGroups: groups,
|
|
850
|
+
})).toThrow(/cannot be combined with `i18n`/);
|
|
851
|
+
});
|
|
852
|
+
it("throws on a pattern that matches nothing, rather than silently not splitting", async () => {
|
|
853
|
+
const { ctx } = await makeSplittableRepo();
|
|
854
|
+
expect(() => (0, build_outputs_1.buildAdapterManifest)(ctx, {
|
|
855
|
+
buildCwd: ctx.projectDir,
|
|
856
|
+
functionGroups: [{ name: "typo", routes: ["/api/report/**"] }],
|
|
857
|
+
})).toThrow(/matches no route in this build/);
|
|
858
|
+
});
|
|
859
|
+
});
|
|
860
|
+
});
|
|
861
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtb3V0cHV0cy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXIvYnVpbGQtb3V0cHV0cy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsK0NBTzBCO0FBQzFCLHFDQUFpQztBQUNqQyx5Q0FBeUQ7QUFDekQsaUhBQWlGO0FBQ2pGLDZGQUErRDtBQUMvRCxxRkFBdUQ7QUFDdkQsbURBSXlCO0FBQ3pCLGtEQUF1RDtBQUV2RDs7OztHQUlHO0FBQ0gsTUFBTSxRQUFRLEdBQUc7SUFDZixnQkFBZ0IsRUFBRSw2QkFBYTtJQUMvQiwwQkFBMEIsRUFBRSx1Q0FBcUI7SUFDakQsWUFBWSxFQUFFLHlCQUFTO0NBQ2YsQ0FBQztBQUVYLDBFQUEwRTtBQUMxRSxNQUFNLFNBQVMsR0FBRyxDQUFDLE9BQWdCLEVBQXdCLEVBQUUsQ0FDM0QsZUFBZSxDQUFDLE9BQU8sQ0FBeUIsQ0FBQztBQUVuRDs7Ozs7R0FLRztBQUNILE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBeUIsRUFBRSxFQUFFLENBQzFDLElBQUEsb0NBQW9CLEVBQUMsR0FBRyxFQUFFLEVBQUUsUUFBUSxFQUFFLEdBQUcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0FBQzFELE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBeUIsRUFBRSxFQUFFLENBQzFDLElBQUEsaUNBQWlCLEVBQUMsR0FBRyxFQUFFLEVBQUUsUUFBUSxFQUFFLEdBQUcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0FBRXZEOzs7O0dBSUc7QUFDSCxNQUFNLFFBQVEsR0FBRyxDQUFDLE1BQWlELEVBQUUsRUFBRTtJQUNyRSxNQUFNLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1QyxPQUFPLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0FBQ3JDLENBQUMsQ0FBQztBQUVGLFVB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QUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsTUFBTSxrQkFBa0IsRUFBRSxDQUFDO1lBQzNDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FDVixJQUFBLG9DQUFvQixFQUFDLEdBQUcsRUFBRTtnQkFDeEIsUUFBUSxFQUFFLEdBQUcsQ0FBQyxVQUFVO2dCQUN4QixjQUFjLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxDQUFDO2FBQy9ELENBQUMsQ0FDSCxDQUFDLE9BQU8sQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQzlDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIGxzdGF0LFxuICBta2RpcixcbiAgbWtkdGVtcCxcbiAgcmVhZEZpbGUsXG4gIHN5bWxpbmssXG4gIHdyaXRlRmlsZSxcbn0gZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luLCByZWxhdGl2ZSwgc2VwIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IGFwcFBsYXlncm91bmRCYXNlUGF0aCBmcm9tIFwiLi9fX2ZpeHR1cmVzX18vYXBwLXBsYXlncm91bmQtYmFzZS1wYXRoLmpzb25cIjtcbmltcG9ydCBhcHBQbGF5Z3JvdW5kIGZyb20gXCIuL19fZml4dHVyZXNfXy9hcHAtcGxheWdyb3VuZC5qc29uXCI7XG5pbXBvcnQgcGFnZXNJMThuIGZyb20gXCIuL19fZml4dHVyZXNfXy9wYWdlcy1pMThuLmpzb25cIjtcbmltcG9ydCB7XG4gIEJ1aWxkQ29tcGxldGVDb250ZXh0LFxuICBidWlsZEFkYXB0ZXJNYW5pZmVzdCxcbiAgd3JpdGVCdWlsZE91dHB1dHMsXG59IGZyb20gXCIuL2J1aWxkLW91dHB1dHNcIjtcbmltcG9ydCB7IFJVTlRJTUVfRElSX05BTUUgfSBmcm9tIFwiLi4vcnVudGltZS9tYW5pZmVzdFwiO1xuXG4vKipcbiAqIFRoZSBmaXh0dXJlcyBhcmUgcmVhbCBgb25CdWlsZENvbXBsZXRlYCBjb250ZXh0cyBjYXB0dXJlZCBieVxuICogYHNjcmlwdHMvY2FwdHVyZS1hZGFwdGVyLWZpeHR1cmUubWpzYCwgd2l0aCBhYnNvbHV0ZSBwYXRocyByZXdyaXR0ZW4gdG8gYVxuICogYC9yZXBvYCBwbGFjZWhvbGRlci4gUmVnZW5lcmF0ZSB0aGVtIHdoZW4gYG5leHRgIGlzIHVwZ3JhZGVkLlxuICovXG5jb25zdCBmaXh0dXJlcyA9IHtcbiAgXCJhcHAtcGxheWdyb3VuZFwiOiBhcHBQbGF5Z3JvdW5kLFxuICBcImFwcC1wbGF5Z3JvdW5kLWJhc2UtcGF0aFwiOiBhcHBQbGF5Z3JvdW5kQmFzZVBhdGgsXG4gIFwicGFnZXMtaTE4blwiOiBwYWdlc0kxOG4sXG59IGFzIGNvbnN0O1xuXG4vKiogRml4dHVyZXMgYXJlIEpTT04sIHNvIHRoZSBzdHJ1Y3R1cmFsIGNhc3QgaXMgdGhlIHBvaW50IG9mIHRoZSBjYXN0LiAqL1xuY29uc3QgYXNDb250ZXh0ID0gKGZpeHR1cmU6IHVua25vd24pOiBCdWlsZENvbXBsZXRlQ29udGV4dCA9PlxuICBzdHJ1Y3R1cmVkQ2xvbmUoZml4dHVyZSkgYXMgQnVpbGRDb21wbGV0ZUNvbnRleHQ7XG5cbi8qKlxuICogYGJ1aWxkQWRhcHRlck1hbmlmZXN0YCByZXF1aXJlcyB0aGUgYnVpbGQgY3dkIHRvIGJlIHRoZSBwcm9qZWN0IGRpciDigJQgc2VlXG4gKiBgYXNzZXJ0QnVpbGRDd2RgLiBUaGUgZml4dHVyZXMnIHByb2plY3QgZGlycyBhcmUgc3ludGhldGljIGAvcmVwby/igKZgIHBhdGhzLCBzb1xuICogZXZlcnkgY2FsbCBzdXBwbGllcyBpdCByYXRoZXIgdGhhbiBsZXR0aW5nIGl0IGRlZmF1bHQgdG8gYHByb2Nlc3MuY3dkKClgLiBUaGVcbiAqIGFzc2VydGlvbiBpdHNlbGYgaXMgY292ZXJlZCBzZXBhcmF0ZWx5IGJlbG93LlxuICovXG5jb25zdCBidWlsZCA9IChjdHg6IEJ1aWxkQ29tcGxldGVDb250ZXh0KSA9PlxuICBidWlsZEFkYXB0ZXJNYW5pZmVzdChjdHgsIHsgYnVpbGRDd2Q6IGN0eC5wcm9qZWN0RGlyIH0pO1xuY29uc3Qgd3JpdGUgPSAoY3R4OiBCdWlsZENvbXBsZXRlQ29udGV4dCkgPT5cbiAgd3JpdGVCdWlsZE91dHB1dHMoY3R4LCB7IGJ1aWxkQ3dkOiBjdHgucHJvamVjdERpciB9KTtcblxuLyoqXG4gKiBUaGUgb25lIGRlcGxveW1lbnQgcm9vdCBhbiB1bnNwbGl0IGJ1aWxkIHN0YWdlcy4gQXNzZXJ0ZWQgcmF0aGVyIHRoYW4gaW5kZXhlZFxuICogc28gYSByZWdyZXNzaW9uIHRoYXQgc3RhcnRzIHNwbGl0dGluZyB1bmFza2VkIGZhaWxzIGhlcmUgaW5zdGVhZCBvZiBzaWxlbnRseVxuICogY2hlY2tpbmcgZ3JvdXAgMC5cbiAqL1xuY29uc3Qgc29sZVJvb3QgPSAocmVzdWx0OiB7IHN0YWdlZEdyb3VwczogQXJyYXk8eyBwYXRoOiBzdHJpbmcgfT4gfSkgPT4ge1xuICBleHBlY3QocmVzdWx0LnN0YWdlZEdyb3VwcykudG9IYXZlTGVuZ3RoKDEpO1xuICByZXR1cm4gcmVzdWx0LnN0YWdlZEdyb3Vwc1swXS5wYXRoO1xufTtcblxuYmVmb3JlRWFjaCgoKSA9PiB7XG4gIC8vIGBtYXhEdXJhdGlvbmAgd2FybmluZ3MgYXJlIGV4cGVjdGVkIGZyb20gdGhlIHBhZ2VzLWkxOG4gZml4dHVyZS5cbiAgamVzdC5zcHlPbihjb25zb2xlLCBcIndhcm5cIikubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHt9KTtcbn0pO1xuXG5hZnRlckVhY2goKCkgPT4ge1xuICBqZXN0LnJlc3RvcmVBbGxNb2NrcygpO1xufSk7XG5cbmRlc2NyaWJlLmVhY2goT2JqZWN0LmtleXMoZml4dHVyZXMpIGFzIEFycmF5PGtleW9mIHR5cGVvZiBmaXh0dXJlcz4pKFxuICBcImJ1aWxkQWRhcHRlck1hbmlmZXN0KCVzKVwiLFxuICAobmFtZSkgPT4ge1xuICAgIGNvbnN0IGN0eCA9IGFzQ29udGV4dChmaXh0dXJlc1tuYW1lXSk7XG4gICAgY29uc3Qge1xuICAgICAgbWFuaWZlc3QsXG4gICAgICBncm91cHM6IFt7IHN0YWdpbmcgfV0sXG4gICAgfSA9IGJ1aWxkKGN0eCk7XG5cbiAgICBpdChcInN0YW1wcyB0aGUgbWFuaWZlc3QgdmVyc2lvbiBhbmQgYnVpbGQgaWRlbnRpdHlcIiwgKCkgPT4ge1xuICAgICAgZXhwZWN0KG1hbmlmZXN0LnZlcnNpb24pLnRvQmUoMSk7XG4gICAgICBleHBlY3QobWFuaWZlc3QuYnVpbGRJZCkudG9CZShjdHguYnVpbGRJZCk7XG4gICAgICBleHBlY3QobWFuaWZlc3QucmVsYXRpdmVQcm9qZWN0RGlyKS50b0JlKFxuICAgICAgICBuYW1lLnN0YXJ0c1dpdGgoXCJwYWdlcy1pMThuXCIpID8gXCJwYWdlcy1pMThuXCIgOiBcImFwcC1wbGF5Z3JvdW5kXCIsXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoXCJjb3BpZXMgdGhlIGNvbmZpZyBmaWVsZHMgdGhlIHJ1bnRpbWUgcm91dGVyIG5lZWRzXCIsICgpID0+IHtcbiAgICAgIGV4cGVjdChtYW5pZmVzdC5jb25maWcpLnRvRXF1YWwoe1xuICAgICAgICBiYXNlUGF0aDogY3R4LmNvbmZpZy5iYXNlUGF0aCA/PyBcIlwiLFxuICAgICAgICB0cmFpbGluZ1NsYXNoOiBjdHguY29uZmlnLnRyYWlsaW5nU2xhc2ggPT09IHRydWUsXG4gICAgICAgIGFzc2V0UHJlZml4OiBjdHguY29uZmlnLmFzc2V0UHJlZml4ID8/IFwiXCIsXG4gICAgICAgIGRpc3REaXI6IFwiLm5leHRcIixcbiAgICAgICAgY29tcHJlc3M6IHRydWUsXG4gICAgICAgIGdlbmVyYXRlRXRhZ3M6IHRydWUsXG4gICAgICAgIGkxOG46IGN0eC5jb25maWcuaTE4biA/PyBudWxsLFxuICAgICAgICBkZXBsb3ltZW50SWQ6IFwiXCIsXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KFwicGVyc2lzdHMgY3R4LnJvdXRpbmcgdmVyYmF0aW1cIiwgKCkgPT4ge1xuICAgICAgLy8gYEBuZXh0L3JvdXRpbmdgJ3MgYHJlc29sdmVSb3V0ZXNgIGNvbnN1bWVzIHRoaXMgd2hvbGUgb2JqZWN0OyBhbnl0aGluZyB3ZVxuICAgICAgLy8gcmVzaGFwZSBoZXJlIGlzIGEgYmVoYXZpb3IgZGlmZmVyZW5jZSBmcm9tIGBuZXh0IHN0YXJ0YC5cbiAgICAgIGV4cGVjdChtYW5pZmVzdC5yb3V0aW5nKS50b0VxdWFsKGN0eC5yb3V0aW5nKTtcbiAgICAgIGV4cGVjdChtYW5pZmVzdC5yb3V0aW5nKS50b0hhdmVQcm9wZXJ0eShcIm1pZGRsZXdhcmVNYXRjaGVyc1wiKTtcbiAgICB9KTtcblxuICAgIGl0KFwibWFwcyBldmVyeSBpbnZvY2FibGUgb3V0cHV0IHBhdGhuYW1lIHRvIGFuIGVudHJ5cG9pbnRcIiwgKCkgPT4ge1xuICAgICAgY29uc3QgZXhwZWN0ZWQgPSBbXG4gICAgICAgIC4uLmN0eC5vdXRwdXRzLnBhZ2VzLFxuICAgICAgICAuLi5jdHgub3V0cHV0cy5wYWdlc0FwaSxcbiAgICAgICAgLi4uY3R4Lm91dHB1dHMuYXBwUGFnZXMsXG4gICAgICAgIC4uLmN0eC5vdXRwdXRzLmFwcFJvdXRlcyxcbiAgICAgIF0ubWFwKChvKSA9PiBvLnBhdGhuYW1lKTtcbiAgICAgIC8vIFBsdXMgZHluYW1pYyBwcmVyZW5kZXIgdGVtcGxhdGVzLCB3aGljaCBgYWRkUHJlcmVuZGVyUGF0aG5hbWVzYCBtYXBzIHRvXG4gICAgICAvLyB0aGUgZW50cnlwb2ludCBvZiB0aGUgcm91dGUgdGhhdCBvd25zIHRoZW0uIE5vbmUgb2YgdGhlc2UgZml4dHVyZXMgaGFzIGFcbiAgICAgIC8vIGdhdGVkIGR5bmFtaWMgcm91dGUsIHNvIG5vICpjb25jcmV0ZSogcHJlcmVuZGVyIHBhdGhuYW1lIGlzIGFkZGVkIC0gc2VlXG4gICAgICAvLyB0aGUgcm9vdC1wYXJhbXMgdGVzdCBiZWxvdy5cbiAgICAgIGNvbnN0IHRlbXBsYXRlcyA9IGN0eC5vdXRwdXRzLnByZXJlbmRlcnNcbiAgICAgICAgLmZpbHRlcigobykgPT4gby5wYXRobmFtZS5pbmNsdWRlcyhcIltcIikpXG4gICAgICAgIC5tYXAoKG8pID0+IG8ucGF0aG5hbWUpO1xuICAgICAgZXhwZWN0KE9iamVjdC5rZXlzKG1hbmlmZXN0LmVudHJ5cG9pbnRzKS5zb3J0KCkpLnRvRXF1YWwoXG4gICAgICAgIFsuLi5uZXcgU2V0KFsuLi5leHBlY3RlZCwgLi4udGVtcGxhdGVzXSldLnNvcnQoKSxcbiAgICAgICk7XG4gICAgICBmb3IgKGNvbnN0IFtwYXRobmFtZSwgZW50cnldIG9mIE9iamVjdC5lbnRyaWVzKG1hbmlmZXN0LmVudHJ5cG9pbnRzKSkge1xuICAgICAgICBleHBlY3QoZW50cnkuZmlsZVBhdGgpLnRvTWF0Y2goL15bXi9dLyk7XG4gICAgICAgIGV4cGVjdChlbnRyeS5maWxlUGF0aCkubm90LnRvQ29udGFpbihcIlxcXFxcIik7XG4gICAgICAgIGV4cGVjdChzdGFnaW5nLmhhcyhlbnRyeS5maWxlUGF0aCkpLnRvQmUodHJ1ZSk7XG4gICAgICAgIGV4cGVjdChlbnRyeS5pZCkudG9CZVRydXRoeSgpO1xuICAgICAgICBleHBlY3QoW1wiYXBwLXBhZ2VcIiwgXCJhcHAtcm91dGVcIiwgXCJwYWdlXCIsIFwicGFnZS1hcGlcIl0pLnRvQ29udGFpbihcbiAgICAgICAgICBlbnRyeS50eXBlLFxuICAgICAgICApO1xuICAgICAgICBleHBlY3QocGF0aG5hbWUpLnRvQmVUcnV0aHkoKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGl0KFwibGlzdHMgcGF0aG5hbWVzIGFzIHRoZSBzb3J0ZWQgdW5pb24gb2YgZW50cnlwb2ludHMgYW5kIHN0YXRpYyBmaWxlc1wiLCAoKSA9PiB7XG4gICAgICBleHBlY3QobWFuaWZlc3QucGF0aG5hbWVzKS50b0VxdWFsKFsuLi5tYW5pZmVzdC5wYXRobmFtZXNdLnNvcnQoKSk7XG4gICAgICBleHBlY3QobmV3IFNldChtYW5pZmVzdC5wYXRobmFtZXMpLnNpemUpLnRvQmUobWFuaWZlc3QucGF0aG5hbWVzLmxlbmd0aCk7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhtYW5pZmVzdC5lbnRyeXBvaW50cykpIHtcbiAgICAgICAgZXhwZWN0KG1hbmlmZXN0LnBhdGhuYW1lcykudG9Db250YWluKGtleSk7XG4gICAgICB9XG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgY3R4Lm91dHB1dHMuc3RhdGljRmlsZXMpIHtcbiAgICAgICAgZXhwZWN0KG1hbmlmZXN0LnBhdGhuYW1lcykudG9Db250YWluKGZpbGUucGF0aG5hbWUpO1xuICAgICAgfVxuICAgICAgLy8gT25lIHJlcG9ydGVkIHBhdGhuYW1lIGNhbiBwcm9kdWNlIHR3byBrZXlzIC0gYSBgL2luZGV4YCBzdGF0aWMgZmlsZSBpc1xuICAgICAgLy8gYWxzbyBzZXJ2ZWQgYXQgYC9gLCBzZWUgdGhlIHN0YXRpYy1ob21lLXBhZ2UgdGVzdHMgYmVsb3cuIE5vbmUgb2YgdGhlc2VcbiAgICAgIC8vIGZpeHR1cmVzIGhhcyBvbmUsIHNvIGhlcmUgdGhlIHR3byBzZXRzIGNvaW5jaWRlLlxuICAgICAgZXhwZWN0KE9iamVjdC5rZXlzKG1hbmlmZXN0LnN0YXRpY0ZpbGVzKSkudG9FcXVhbChcbiAgICAgICAgWy4uLm5ldyBTZXQoY3R4Lm91dHB1dHMuc3RhdGljRmlsZXMubWFwKChmKSA9PiBmLnBhdGhuYW1lKSldLnNvcnQoKSxcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdChcIm1hcHMgZWFjaCBzdGF0aWMgZmlsZSB0byBhIHJlcG8tcm9vdC1yZWxhdGl2ZSBrZXlcIiwgKCkgPT4ge1xuICAgICAgZm9yIChjb25zdCBbcGF0aG5hbWUsIGtleV0gb2YgT2JqZWN0LmVudHJpZXMobWFuaWZlc3Quc3RhdGljRmlsZXMpKSB7XG4gICAgICAgIGNvbnN0IG91dHB1dCA9IGN0eC5vdXRwdXRzLnN0YXRpY0ZpbGVzLmZpbmQoXG4gICAgICAgICAgKGYpID0+IGYucGF0aG5hbWUgPT09IHBhdGhuYW1lLFxuICAgICAgICApITtcbiAgICAgICAgZXhwZWN0KGtleSkudG9CZShvdXRwdXQuZmlsZVBhdGgucmVwbGFjZShcIi9yZXBvL1wiLCBcIlwiKSk7XG4gICAgICAgIGV4cGVjdChrZXkuc3RhcnRzV2l0aChcIi9cIikpLnRvQmUoZmFsc2UpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaXQoXCJzdGFnZXMgdGhlIHN0YXRpYyBmaWxlcyBub3RoaW5nIGluIGZyb250IG9mIHRoZSBjb21wdXRlIHNlcnZlc1wiLCAoKSA9PiB7XG4gICAgICAvLyBgPGRpc3REaXI+L3N0YXRpY2AgZ29lcyB0byBTMzsgYDxkaXN0RGlyPi9zZXJ2ZXIvKipgICg0MDQuaHRtbCxcbiAgICAgIC8vIGZhdmljb24uaWNvLmJvZHksIGZ1bGx5LXN0YXRpYyBQYWdlcyBSb3V0ZXIgSFRNTCkgZG9lcyBub3QsIHNvIHRoZVxuICAgICAgLy8gcnVudGltZSBtdXN0IGJlIGFibGUgdG8gcmVhZCBpdCBvZmYgZGlzay5cbiAgICAgIGZvciAoY29uc3QgW3BhdGhuYW1lLCBrZXldIG9mIE9iamVjdC5lbnRyaWVzKG1hbmlmZXN0LnN0YXRpY0ZpbGVzKSkge1xuICAgICAgICBjb25zdCBzZXJ2ZWRCeVMzID0gcGF0aG5hbWUuaW5jbHVkZXMoXCIvX25leHQvc3RhdGljL1wiKTtcbiAgICAgICAgZXhwZWN0KHN0YWdpbmcuaGFzKGtleSkpLnRvQmUoIXNlcnZlZEJ5UzMpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaXQoXCJzdGFnZXMgb25seSBrZXlzIHRoYXQgbGFuZCBpbnNpZGUgdGhlIGRlcGxveW1lbnQgcm9vdFwiLCAoKSA9PiB7XG4gICAgICBleHBlY3Qoc3RhZ2luZy5zaXplKS50b0JlR3JlYXRlclRoYW4oMCk7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBzdGFnaW5nLmtleXMoKSkge1xuICAgICAgICBleHBlY3Qoa2V5KS5ub3QudG9CZShcIlwiKTtcbiAgICAgICAgZXhwZWN0KGtleS5zdGFydHNXaXRoKFwiL1wiKSkudG9CZShmYWxzZSk7XG4gICAgICAgIGV4cGVjdChrZXkuc3RhcnRzV2l0aChcIi4uXCIpKS50b0JlKGZhbHNlKTtcbiAgICAgICAgZXhwZWN0KGtleS5zdGFydHNXaXRoKGAke1JVTlRJTUVfRElSX05BTUV9L2ApKS50b0JlKGZhbHNlKTtcbiAgICAgIH1cbiAgICAgIC8vIFRoZSB0cmFjZWQgYG5leHRgIGNsb3N1cmUgaXMgbWVyZ2VkIGludG8gZXZlcnkgb3V0cHV0LCBzbyBzdGFnaW5nIGlzIGZhclxuICAgICAgLy8gc21hbGxlciB0aGFuIHRoZSBzdW0gb2YgdGhlIHBlci1vdXRwdXQgYGFzc2V0c2AgbWFwcy5cbiAgICAgIGV4cGVjdChzdGFnaW5nLnNpemUpLnRvQmVMZXNzVGhhbihcbiAgICAgICAgY3R4Lm91dHB1dHMuYXBwUGFnZXMubGVuZ3RoICogMTAwICtcbiAgICAgICAgICBjdHgub3V0cHV0cy5wYWdlcy5sZW5ndGggKiAxMDAgK1xuICAgICAgICAgIDEwMDAsXG4gICAgICApO1xuICAgIH0pO1xuICB9LFxuKTtcblxuZGVzY3JpYmUoXCJidWlsZEFkYXB0ZXJNYW5pZmVzdCBlZGdlIGNhc2VzXCIsICgpID0+IHtcbiAgaXQoXCJ0aHJvd3Mgd2hlbiBgbmV4dCBidWlsZGAgcmFuIGZyb20gb3V0c2lkZSB0aGUgcHJvamVjdCBkaXJlY3RvcnlcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGN0eCA9IGFzQ29udGV4dChhcHBQbGF5Z3JvdW5kKTtcbiAgICBleHBlY3QoKCkgPT4gYnVpbGRBZGFwdGVyTWFuaWZlc3QoY3R4LCB7IGJ1aWxkQ3dkOiBcIi9yZXBvXCIgfSkpLnRvVGhyb3coXG4gICAgICAvbXVzdCBydW4gZnJvbSB0aGUgTmV4dC5qcyBwcm9qZWN0IGRpcmVjdG9yeS8sXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoXCJkZWZhdWx0cyB0aGUgYnVpbGQgY3dkIHRvIHByb2Nlc3MuY3dkKClcIiwgKCkgPT4ge1xuICAgIC8vIFdoaWNoIGlzIHRoaXMgcGFja2FnZSdzIHJvb3QsIG5ldmVyIGEgZml4dHVyZSdzIGAvcmVwby/igKZgIHByb2plY3QgZGlyLCBzb1xuICAgIC8vIHRoZSBhc3NlcnRpb24gZmlyZXMg4oCUIHByb3ZpbmcgdGhlIGRlZmF1bHQgaXMgd2lyZWQgYW5kIG5vdCBqdXN0IHRoZSBvcHRpb24uXG4gICAgZXhwZWN0KCgpID0+IGJ1aWxkQWRhcHRlck1hbmlmZXN0KGFzQ29udGV4dChhcHBQbGF5Z3JvdW5kKSkpLnRvVGhyb3coXG4gICAgICAvbXVzdCBydW4gZnJvbSB0aGUgTmV4dC5qcyBwcm9qZWN0IGRpcmVjdG9yeS8sXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoXCJyZWNvcmRzIHRoZSBkZXBsb3ltZW50SWQsIHJlZHVjZWQgdG8gd2hhdCBhIGNhY2hlIGtleSBwcmVmaXggY2FuIGhvbGRcIiwgKCkgPT4ge1xuICAgIC8vIGBOZXh0anNCdWlsZGAgc3VmZml4ZXMgaXRzIGBidWlsZElkYCB3aXRoIGl0OiBuZXh0IHBpbnMgdGhlIGJ1aWxkIElEXG4gICAgLy8gaXRzZWxmIG9uY2UgYGRlcGxveW1lbnRJZGAgaXMgc2V0LlxuICAgIGNvbnN0IGN0eCA9IGFzQ29udGV4dChhcHBQbGF5Z3JvdW5kKTtcbiAgICBjb25zdCB7IG1hbmlmZXN0IH0gPSBidWlsZCh7XG4gICAgICAuLi5jdHgsXG4gICAgICBjb25maWc6IHsgLi4uY3R4LmNvbmZpZywgZGVwbG95bWVudElkOiBcInYxLjIvbWFpblwiIH0sXG4gICAgfSk7XG4gICAgZXhwZWN0KG1hbmlmZXN0LmNvbmZpZy5kZXBsb3ltZW50SWQpLnRvQmUoXCJ2MS0yLW1haW5cIik7XG4gIH0pO1xuXG4gIGl0KFwia2V5cyBsb2NhbGUgdmFyaWFudHMgb2Ygb25lIHBhZ2UgdG8gdGhlIHNhbWUgZW50cnlwb2ludCBmaWxlXCIsICgpID0+IHtcbiAgICBjb25zdCB7IG1hbmlmZXN0IH0gPSBidWlsZChhc0NvbnRleHQocGFnZXNJMThuKSk7XG4gICAgLy8gaTE4biBmYW5zIG9uZSBwYWdlIG91dCBpbnRvIG9uZSBvdXRwdXQgcGVyIGxvY2FsZSwgcGx1cyBhXG4gICAgLy8gYC9fbmV4dC9kYXRhLzxidWlsZElkPi/igKZqc29uYCBzaWJsaW5nIGVhY2guIFRoZXkgc2hhcmUgYGZpbGVQYXRoYCBhbmRcbiAgICAvLyBgdHlwZWA7IGBpZGAgc3RheXMgcGVyLXBhdGhuYW1lIChsb2NhbGUtcHJlZml4ZWQpLCBzbyBpdCBpcyBub3QgYSBkZWR1cCBrZXkuXG4gICAgY29uc3Qgc3NyID0gW1xuICAgICAgXCIvc3NyXCIsXG4gICAgICBcIi9lbi1VUy9zc3JcIixcbiAgICAgIFwiL2ZyL3NzclwiLFxuICAgICAgXCIvbmwtTkwvc3NyXCIsXG4gICAgICBgL19uZXh0L2RhdGEvJHttYW5pZmVzdC5idWlsZElkfS9mci9zc3IuanNvbmAsXG4gICAgXTtcbiAgICBmb3IgKGNvbnN0IHBhdGhuYW1lIG9mIHNzcikge1xuICAgICAgZXhwZWN0KG1hbmlmZXN0LmVudHJ5cG9pbnRzW3BhdGhuYW1lXSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgIGZpbGVQYXRoOiBtYW5pZmVzdC5lbnRyeXBvaW50c1tcIi9zc3JcIl0uZmlsZVBhdGgsXG4gICAgICAgIHR5cGU6IFwicGFnZVwiLFxuICAgICAgfSk7XG4gICAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbcGF0aG5hbWVdLmlkKS50b0JlKHBhdGhuYW1lKTtcbiAgICB9XG4gICAgZXhwZWN0KG1hbmlmZXN0LmVudHJ5cG9pbnRzW1wiL3NzclwiXS50eXBlKS50b0JlKFwicGFnZVwiKTtcbiAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbXCIvYXBpL2hlbGxvXCJdLnR5cGUpLnRvQmUoXCJwYWdlLWFwaVwiKTtcbiAgfSk7XG5cbiAgaXQoXCJjYXJyaWVzIGJhc2VQYXRoIGluIHBhdGhuYW1lcyBidXQgbm90IGluIGVudHJ5cG9pbnQgaWRzXCIsICgpID0+IHtcbiAgICAvLyBgb3V0cHV0LnBhdGhuYW1lYCBpcyBiYXNlUGF0aC1wcmVmaXhlZCB3aGlsZSBgb3V0cHV0LmlkYCBpcyBub3QuIERpc3BhdGNoXG4gICAgLy8ga2V5cyBvZmYgdGhlIHBhdGhuYW1lLCBzbyB0aGUgcHJlZml4IGhhcyB0byBzdGF5LlxuICAgIGNvbnN0IHsgbWFuaWZlc3QgfSA9IGJ1aWxkKGFzQ29udGV4dChhcHBQbGF5Z3JvdW5kQmFzZVBhdGgpKTtcbiAgICBleHBlY3QobWFuaWZlc3QuY29uZmlnLmJhc2VQYXRoKS50b0JlKFwiL3Byb2RcIik7XG4gICAgZXhwZWN0KG1hbmlmZXN0LmVudHJ5cG9pbnRzW1wiL3Byb2QvYXBpL2hlYWx0aFwiXSkudG9CZURlZmluZWQoKTtcbiAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbXCIvcHJvZC9hcGkvaGVhbHRoXCJdLmlkKS50b0JlKFwiL2FwaS9oZWFsdGhcIik7XG4gICAgZXhwZWN0KG1hbmlmZXN0LmVudHJ5cG9pbnRzW1wiL2FwaS9oZWFsdGhcIl0pLnRvQmVVbmRlZmluZWQoKTtcbiAgfSk7XG5cbiAgLyoqXG4gICAqIEEgUGFnZXMgUm91dGVyIGhvbWUgcGFnZSByZWFjaGVzIHVzIGFzIGAvaW5kZXhgLCB3aGljaGV2ZXIgcG9wdWxhdGlvbiBpdCBsYW5kc1xuICAgKiBpbjogYG5vcm1hbGl6ZVBhZ2VQYXRoKFwiL1wiKWAgaXMgYFwiL2luZGV4XCJgLCBhbmQgdGhlIGFkYXB0ZXIgaG9vayB1c2VzIGl0IGZvciBhXG4gICAqIGZ1bGx5LXN0YXRpYyBwYWdlJ3MgYFNUQVRJQ19GSUxFYCBhbmQgZm9yIGFuIFNTRy9TU1IgcGFnZSdzIGBQQUdFU2Agb3V0cHV0XG4gICAqIGFsaWtlLiBOb3RoaW5nIGVsc2UgaW4gdGhlIG91dHB1dHMgY2FycmllcyBgL2AsIHNvIHRoZSBtYXBwaW5nIHVuZGVyIHRlc3QgaXNcbiAgICogdGhlIG9ubHkgdGhpbmcgdGhhdCBtYWtlcyB0aGUgaG9tZSBwYWdlIHJvdXRhYmxlLlxuICAgKi9cbiAgZnVuY3Rpb24gd2l0aEhvbWVQYWdlKFxuICAgIGJhc2VQYXRoOiBzdHJpbmcsXG4gICAga2luZDogXCJzdGF0aWNcIiB8IFwiaW52b2NhYmxlXCIsXG4gICk6IFJldHVyblR5cGU8dHlwZW9mIGJ1aWxkPiB7XG4gICAgY29uc3QgY3R4ID0gYXNDb250ZXh0KHBhZ2VzSTE4bik7XG4gICAgY3R4LmNvbmZpZy5pMThuID0gbnVsbDtcbiAgICBjdHguY29uZmlnLmJhc2VQYXRoID0gYmFzZVBhdGg7XG4gICAgY3R4Lm91dHB1dHMuc3RhdGljRmlsZXMgPSBbXTtcbiAgICBjdHgub3V0cHV0cy5wcmVyZW5kZXJzID0gW107XG4gICAgY29uc3QgcGFnZSA9IGN0eC5vdXRwdXRzLnBhZ2VzLmZpbmQoKG8pID0+IG8ucGF0aG5hbWUgPT09IFwiL3NzclwiKSE7XG4gICAgY3R4Lm91dHB1dHMucGFnZXMgPVxuICAgICAga2luZCA9PT0gXCJpbnZvY2FibGVcIlxuICAgICAgICA/IFt7IC4uLnBhZ2UsIGlkOiBcIi9pbmRleFwiLCBwYXRobmFtZTogYCR7YmFzZVBhdGh9L2luZGV4YCB9XVxuICAgICAgICA6IFtdO1xuICAgIGlmIChraW5kID09PSBcInN0YXRpY1wiKSB7XG4gICAgICBjdHgub3V0cHV0cy5zdGF0aWNGaWxlcyA9IFtcbiAgICAgICAge1xuICAgICAgICAgIGlkOiBcIi9cIixcbiAgICAgICAgICBwYXRobmFtZTogYCR7YmFzZVBhdGh9L2luZGV4YCxcbiAgICAgICAgICB0eXBlOiBcIlNUQVRJQ19GSUxFXCIsXG4gICAgICAgICAgZmlsZVBhdGg6IFwiL3JlcG8vcGFnZXMtaTE4bi8ubmV4dC9zZXJ2ZXIvcGFnZXMvaW5kZXguaHRtbFwiLFxuICAgICAgICB9LFxuICAgICAgXSBhcyB0eXBlb2YgY3R4Lm91dHB1dHMuc3RhdGljRmlsZXM7XG4gICAgfVxuICAgIHJldHVybiBidWlsZChjdHgpO1xuICB9XG5cbiAgaXQoXCJyb3V0ZXMgYSBmdWxseS1zdGF0aWMgUGFnZXMgUm91dGVyIGhvbWUgcGFnZSBhdCBgL2AsIG5vdCBgL2luZGV4YFwiLCAoKSA9PiB7XG4gICAgY29uc3QgeyBtYW5pZmVzdCB9ID0gd2l0aEhvbWVQYWdlKFwiXCIsIFwic3RhdGljXCIpO1xuICAgIGNvbnN0IGh0bWwgPSBcInBhZ2VzLWkxOG4vLm5leHQvc2VydmVyL3BhZ2VzL2luZGV4Lmh0bWxcIjtcblxuICAgIGV4cGVjdChtYW5pZmVzdC5zdGF0aWNGaWxlc1tcIi9cIl0pLnRvQmUoaHRtbCk7XG4gICAgZXhwZWN0KG1hbmlmZXN0LnBhdGhuYW1lcykudG9Db250YWluKFwiL1wiKTtcbiAgICAvLyBLZXB0IGFzIHdlbGwgYXMgYC9gOiBuZXh0J3MgbWluaW1hbCBtb2RlIHJld3JpdGVzIGAvaW5kZXhgIHRvIGAvYCBiZWZvcmVcbiAgICAvLyBtYXRjaGluZywgc28gaXQgYW5zd2VycyB0aGVyZSB0b28uXG4gICAgZXhwZWN0KG1hbmlmZXN0LnN0YXRpY0ZpbGVzW1wiL2luZGV4XCJdKS50b0JlKGh0bWwpO1xuICB9KTtcblxuICBpdChcInJvdXRlcyBhbiBTU0cgb3IgU1NSIGhvbWUgcGFnZSdzIGVudHJ5cG9pbnQgYXQgYC9gIGFzIHdlbGxcIiwgKCkgPT4ge1xuICAgIGNvbnN0IHsgbWFuaWZlc3QgfSA9IHdpdGhIb21lUGFnZShcIlwiLCBcImludm9jYWJsZVwiKTtcbiAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbXCIvXCJdKS50b0VxdWFsKG1hbmlmZXN0LmVudHJ5cG9pbnRzW1wiL2luZGV4XCJdKTtcbiAgICBleHBlY3QobWFuaWZlc3QucGF0aG5hbWVzKS50b0NvbnRhaW4oXCIvXCIpO1xuICAgIC8vIFRoZSBvdXRwdXQncyBvd24gYGlkYCBpcyB3aGF0IG5leHQgcmVwb3J0ZWQsIGFuZCBvbmx5IG5hbWVzIHRoZSBlbnRyeXBvaW50XG4gICAgLy8gaW4gZGlhZ25vc3RpY3MgYW5kIGdyb3VwIG93bmVyc2hpcCAtIGl0IGlzIG5vdCBhIGtleSBpbnRvIGFueXRoaW5nLlxuICAgIGV4cGVjdChtYW5pZmVzdC5lbnRyeXBvaW50c1tcIi9cIl0uaWQpLnRvQmUoXCIvaW5kZXhcIik7XG4gIH0pO1xuXG4gIGl0KFwicm91dGVzIHRoYXQgaG9tZSBwYWdlIHVuZGVyIGJhc2VQYXRoIGF0IHRoZSBiYXNlUGF0aCBpdHNlbGZcIiwgKCkgPT4ge1xuICAgIC8vIGAvcHJvZGAsIG5vdCBgL3Byb2QvYCDigJQgd2hpY2ggaXMgaG93IHRoZSBBcHAgUm91dGVyIGZpeHR1cmUgcmVwb3J0cyBpdHMgb3duXG4gICAgLy8gaG9tZSBwYWdlLlxuICAgIGNvbnN0IHsgbWFuaWZlc3QgfSA9IHdpdGhIb21lUGFnZShcIi9wcm9kXCIsIFwic3RhdGljXCIpO1xuICAgIGV4cGVjdChPYmplY3Qua2V5cyhtYW5pZmVzdC5zdGF0aWNGaWxlcykpLnRvRXF1YWwoW1wiL3Byb2RcIiwgXCIvcHJvZC9pbmRleFwiXSk7XG4gIH0pO1xuXG4gIGl0KFwibGVhdmVzIGFuIEFwcCBSb3V0ZXIgYC9pbmRleGAgcm91dGUgYXQgYC9pbmRleGBcIiwgKCkgPT4ge1xuICAgIC8vIGBhcHAvaW5kZXgvcGFnZS50c3hgIGlzIGEgcmVhbCByb3V0ZS4gT25seSB0aGUgUGFnZXMgUm91dGVyIHJlcG9ydHMgaXRzXG4gICAgLy8gaG9tZSBwYWdlIGFzIGAvaW5kZXhgLlxuICAgIGNvbnN0IGN0eCA9IGFzQ29udGV4dChhcHBQbGF5Z3JvdW5kKTtcbiAgICBjb25zdCBob21lID0gY3R4Lm91dHB1dHMuYXBwUGFnZXMuZmluZCgobykgPT4gby5wYXRobmFtZSA9PT0gXCIvXCIpITtcbiAgICBjb25zdCBpbmRleEZpbGUgPSBob21lLmZpbGVQYXRoLnJlcGxhY2UoL3BhZ2VcXC5qcyQvLCBcImluZGV4L3BhZ2UuanNcIik7XG4gICAgY3R4Lm91dHB1dHMuYXBwUGFnZXMucHVzaCh7XG4gICAgICAuLi5ob21lLFxuICAgICAgaWQ6IFwiL2luZGV4XCIsXG4gICAgICBwYXRobmFtZTogXCIvaW5kZXhcIixcbiAgICAgIGZpbGVQYXRoOiBpbmRleEZpbGUsXG4gICAgfSk7XG4gICAgY29uc3QgeyBtYW5pZmVzdCB9ID0gYnVpbGQoY3R4KTtcbiAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbXCIvXCJdLmZpbGVQYXRoKS5ub3QudG9CZShcbiAgICAgIG1hbmlmZXN0LmVudHJ5cG9pbnRzW1wiL2luZGV4XCJdLmZpbGVQYXRoLFxuICAgICk7XG4gICAgZXhwZWN0KG1hbmlmZXN0LmVudHJ5cG9pbnRzW1wiL2luZGV4XCJdLmZpbGVQYXRoKS50b01hdGNoKC9pbmRleFxcL3BhZ2VcXC5qcyQvKTtcbiAgfSk7XG5cbiAgaXQoXCJyZWNvcmRzIG1pZGRsZXdhcmUgd2l0aG91dCBkdXBsaWNhdGluZyBpdHMgbWF0Y2hlcnNcIiwgKCkgPT4ge1xuICAgIGNvbnN0IHtcbiAgICAgIG1hbmlmZXN0LFxuICAgICAgZ3JvdXBzOiBbeyBzdGFnaW5nIH1dLFxuICAgIH0gPSBidWlsZChhc0NvbnRleHQoYXBwUGxheWdyb3VuZCkpO1xuICAgIGV4cGVjdChtYW5pZmVzdC5taWRkbGV3YXJlKS5ub3QudG9CZU51bGwoKTtcbiAgICBleHBlY3QobWFuaWZlc3QubWlkZGxld2FyZSEuZmlsZVBhdGgpLnRvTWF0Y2goL15bXi9dLyk7XG4gICAgZXhwZWN0KHN0YWdpbmcuaGFzKG1hbmlmZXN0Lm1pZGRsZXdhcmUhLmZpbGVQYXRoKSkudG9CZSh0cnVlKTtcbiAgICBleHBlY3QobWFuaWZlc3QubWlkZGxld2FyZSkubm90LnRvSGF2ZVByb3BlcnR5KFwibWF0Y2hlcnNcIik7XG5cbiAgICBjb25zdCB7IG1hbmlmZXN0OiBub01pZGRsZXdhcmUgfSA9IGJ1aWxkKGFzQ29udGV4dChwYWdlc0kxOG4pKTtcbiAgICBleHBlY3Qobm9NaWRkbGV3YXJlLm1pZGRsZXdhcmUpLnRvQmVOdWxsKCk7XG4gIH0pO1xuXG4gIGl0KFwibWFwcyBhIFBhZ2VzIFJvdXRlciBkYXRhLXJvdXRlIHRlbXBsYXRlIHRvIGl0cyBvd25pbmcgcm91dGVcIiwgKCkgPT4ge1xuICAgIC8vIGAvX25leHQvZGF0YS88YnVpbGRJZD4vPGxvY2FsZT4vYmxvZy9bc2x1Z10uanNvbmAgZXhpc3RzIG9ubHkgYXMgYVxuICAgIC8vIHByZXJlbmRlci4gV2l0aG91dCBpdCwgdGhlIElTUiBkYXRhIFVSTHMgYG5leHQgc3RhcnRgIHNlcnZlcyB3b3VsZCA0MDQuXG4gICAgY29uc3QgeyBtYW5pZmVzdCB9ID0gYnVpbGQoYXNDb250ZXh0KHBhZ2VzSTE4bikpO1xuICAgIGNvbnN0IGRhdGFUZW1wbGF0ZSA9IGAvX25leHQvZGF0YS8ke21hbmlmZXN0LmJ1aWxkSWR9L2ZyL2Jsb2cvW3NsdWddLmpzb25gO1xuICAgIGV4cGVjdChtYW5pZmVzdC5lbnRyeXBvaW50c1tkYXRhVGVtcGxhdGVdKS50b0VxdWFsKHtcbiAgICAgIGlkOiBkYXRhVGVtcGxhdGUsXG4gICAgICBmaWxlUGF0aDogbWFuaWZlc3QuZW50cnlwb2ludHNbXCIvZnIvYmxvZy9bc2x1Z11cIl0uZmlsZVBhdGgsXG4gICAgICB0eXBlOiBcInBhZ2VcIixcbiAgICB9KTtcbiAgICBleHBlY3QobWFuaWZlc3QucGF0aG5hbWVzKS50b0NvbnRhaW4oZGF0YVRlbXBsYXRlKTtcbiAgfSk7XG5cbiAgaXQoXCJyZWdpc3RlcnMgYSBzdGF0aWMgZ2V0U3RhdGljUHJvcHMgcGFnZSdzIGRhdGEgcm91dGUsIHdoaWNoIG5vIHJ1bGUgcmVhY2hlc1wiLCAoKSA9PiB7XG4gICAgLy8gYHRlc3QvZTJlL25vLXBhZ2UtcHJvcHNgOiBgL19uZXh0L2RhdGEvPGJ1aWxkSWQ+L2dzcC5qc29uYCA0MDQnZCB3aGlsZVxuICAgIC8vIGBuZXh0IHN0YXJ0YCBzZXJ2ZXMgaXQgMjAwLCBzbyBldmVyeSBjbGllbnQtc2lkZSBuYXZpZ2F0aW9uIGludG8gdGhlIHBhZ2VcbiAgICAvLyBmZWxsIGJhY2sgdG8gYSBmdWxsIHBhZ2UgbG9hZC4gYG5leHQgYnVpbGRgIGVtaXRzIGEgYGR5bmFtaWNSb3V0ZXNgIHJ1bGUgZm9yXG4gICAgLy8gYSBkYXRhIHJvdXRlIG9ubHkgd2hlbiB0aGUgcGFnZSBpcyBkeW5hbWljIG9yIHRoZSBhcHAgaGFzIG1pZGRsZXdhcmUsIHNvXG4gICAgLy8gd2l0aG91dCBtaWRkbGV3YXJlIGEgKnN0YXRpYyogcGFnZSdzIGRhdGEgcm91dGUgYXJyaXZlcyBhcyBhIGNvbmNyZXRlXG4gICAgLy8gcHJlcmVuZGVyIHBhdGhuYW1lIHdpdGggbm90aGluZyB0byBtYXRjaCBpdC4gUmVwcm9kdWNlZCBvbiBgcGFnZXMtaTE4bmAsXG4gICAgLy8gd2hvc2UgY2FwdHVyZWQgcHJlcmVuZGVycyBhcmUgYWxsIGR5bmFtaWMsIGJ5IHJlbmFtaW5nIG9uZS5cbiAgICBjb25zdCBjdHggPSBhc0NvbnRleHQocGFnZXNJMThuKTtcbiAgICBjb25zdCBkYXRhUm91dGUgPSBgL19uZXh0L2RhdGEvJHtjdHguYnVpbGRJZH0vZW4tVVMvZ3NwLmpzb25gO1xuICAgIGNvbnN0IGNvbmNyZXRlID0gY3R4Lm91dHB1dHMucHJlcmVuZGVycy5maW5kKChpdCkgPT5cbiAgICAgIGl0LnBhdGhuYW1lLmVuZHNXaXRoKFwiaGVsbG8uanNvblwiKSxcbiAgICApITtcbiAgICBjb25jcmV0ZS5wYXRobmFtZSA9IGRhdGFSb3V0ZTtcbiAgICBjb25jcmV0ZS5pZCA9IGRhdGFSb3V0ZTtcbiAgICBjb25zdCB7IG1hbmlmZXN0IH0gPSBidWlsZChjdHgpO1xuICAgIGV4cGVjdChtYW5pZmVzdC5lbnRyeXBvaW50c1tkYXRhUm91dGVdKS50b0VxdWFsKHtcbiAgICAgIGlkOiBkYXRhUm91dGUsXG4gICAgICBmaWxlUGF0aDogbWFuaWZlc3QuZW50cnlwb2ludHNbXCIvZW4tVVMvYmxvZy9bc2x1Z11cIl0uZmlsZVBhdGgsXG4gICAgICB0eXBlOiBcInBhZ2VcIixcbiAgICB9KTtcblxuICAgIC8vIEFuZCB0aGUgZHluYW1pYyBwYWdlJ3Mgb3duIGNvbmNyZXRlIGRhdGEgcGF0aG5hbWUgc3RheXMgb3V0OiB0aGUgdW5nYXRlZFxuICAgIC8vIGDigKYvYmxvZy9bc2x1Z10uanNvbmAgcnVsZSBhbHJlYWR5IHJlYWNoZXMgaXQsIGFuZCB0aGF0IHJ1bGUgaXMgd2hlcmUgdGhlXG4gICAgLy8gYG54dFBzbHVnYCBwYXJhbSBjb21lcyBmcm9tIOKAlCByZXNvbHZpbmcgdGhlIHJlcXVlc3QgdG8gaXRzZWxmIHdvdWxkIGRyb3AgaXQuXG4gICAgY29uc3QgeyBtYW5pZmVzdDogY2FwdHVyZWQgfSA9IGJ1aWxkKGFzQ29udGV4dChwYWdlc0kxOG4pKTtcbiAgICBleHBlY3QoXG4gICAgICBjYXB0dXJlZC5lbnRyeXBvaW50c1tcbiAgICAgICAgYC9fbmV4dC9kYXRhLyR7Y2FwdHVyZWQuYnVpbGRJZH0vZW4tVVMvYmxvZy9oZWxsby5qc29uYFxuICAgICAgXSxcbiAgICApLnRvQmVVbmRlZmluZWQoKTtcbiAgfSk7XG5cbiAgaXQoXCJsZWF2ZXMgYW4gQXBwIFJvdXRlciBmYWxsYmFjayB0ZW1wbGF0ZSBvbiBpdHMgb3duIGVudHJ5cG9pbnRcIiwgKCkgPT4ge1xuICAgIC8vIGAvaXNyL1tpZF1gIGlzIGEgcHJlcmVuZGVyICphbmQqIGFuIGFwcFBhZ2VzIG91dHB1dC4gVGhlIG91dHB1dCB3aW5zLCBzb1xuICAgIC8vIGBpZGAgc3RheXMgdGhlIHJvdXRlJ3Mgb3duIHJhdGhlciB0aGFuIGJlaW5nIHJld3JpdHRlbi5cbiAgICBjb25zdCB7IG1hbmlmZXN0IH0gPSBidWlsZChhc0NvbnRleHQoYXBwUGxheWdyb3VuZCkpO1xuICAgIGV4cGVjdChtYW5pZmVzdC5lbnRyeXBvaW50c1tcIi9pc3IvW2lkXVwiXS5pZCkudG9CZShcIi9pc3IvW2lkXVwiKTtcbiAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbXCIvaXNyL1tpZF0ucnNjXCJdKS50b0JlRGVmaW5lZCgpO1xuICB9KTtcblxuICBpdChcImFkZHMgYSBjb25jcmV0ZSBwcmVyZW5kZXIgcGF0aG5hbWUgd2hlbiBvbmx5IGEgZ2F0ZWQgcnVsZSBtYXRjaGVzIGl0XCIsICgpID0+IHtcbiAgICAvLyBXaGF0IGEgcm9vdC1wYXJhbXMgYXBwIHByb2R1Y2VzOiBgYXBwL1tsb2NhbGVdL3BhZ2UudHN4YCB3aXRoXG4gICAgLy8gYGdlbmVyYXRlU3RhdGljUGFyYW1zKClgIGFuZCBubyBgYXBwL2xheW91dC50c3hgLiBUaGUgcGFyYW1zIGNhbiBuZXZlciBiZVxuICAgIC8vIGZpbGxlZCBhdCByZXF1ZXN0IHRpbWUsIHNvIGBuZXh0IGJ1aWxkYCBlbWl0cyB0aGUgYGR5bmFtaWNSb3V0ZXNgIHJ1bGUgd2l0aCBhXG4gICAgLy8gZHJhZnQtbW9kZSBgaGFzYCBhbmQgZXhwZWN0cyB0aGUgcGxhdGZvcm0gdG8gc2VydmUgYC9lbmAgZnJvbSB0aGUgcHJlcmVuZGVyLlxuICAgIC8vIE1lYXN1cmVkIGFnYWluc3QgYHRlc3QvZTJlL2FwcC1kaXIvcGFyYWxsZWwtcm91dGVzLXJvb3QtcGFyYW0tZHluYW1pYy1jaGlsZGAsXG4gICAgLy8gd2hlcmUgZXZlcnkgVVJMIG9mIHRoZSBhcHAgNDA0J2QuIFJlcHJvZHVjZWQgaGVyZSBieSBnYXRpbmdcbiAgICAvLyBgYXBwLXBsYXlncm91bmRgJ3MgYC9pc3IvW2lkXWAgcnVsZXMsIHdoaWNoIG5vIGNvbW1pdHRlZCBjYXB0dXJlIGRvZXMuXG4gICAgY29uc3QgY3R4ID0gYXNDb250ZXh0KGFwcFBsYXlncm91bmQpO1xuICAgIGZvciAoY29uc3Qgcm91dGUgb2YgY3R4LnJvdXRpbmcuZHluYW1pY1JvdXRlcykge1xuICAgICAgaWYgKHJvdXRlLnNvdXJjZVJlZ2V4LmluY2x1ZGVzKFwiaXNyXCIpKSB7XG4gICAgICAgIHJvdXRlLmhhcyA9IFtcbiAgICAgICAgICB7IHR5cGU6IFwiY29va2llXCIsIGtleTogXCJfX3ByZXJlbmRlcl9ieXBhc3NcIiwgdmFsdWU6IFwic2VjcmV0XCIgfSxcbiAgICAgICAgXTtcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgeyBtYW5pZmVzdCB9ID0gYnVpbGQoY3R4KTtcbiAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbXCIvaXNyLzFcIl0pLnRvRXF1YWwoe1xuICAgICAgaWQ6IFwiL2lzci8xXCIsXG4gICAgICBmaWxlUGF0aDogbWFuaWZlc3QuZW50cnlwb2ludHNbXCIvaXNyL1tpZF1cIl0uZmlsZVBhdGgsXG4gICAgICB0eXBlOiBcImFwcC1wYWdlXCIsXG4gICAgfSk7XG4gICAgLy8gVGhlIFJTQyBhbmQgc2VnbWVudC1wcmVmZXRjaCB2YXJpYW50cyB0b286IHRoZXkgYXJlIHRoZSBVUkxzIGEgY2xpZW50LXNpZGVcbiAgICAvLyBuYXZpZ2F0aW9uIGFza3MgZm9yLCBzbyB3aXRob3V0IHRoZW0gdGhlIGFwcCByZW5kZXJzIGFuZCBuZXZlciBoeWRyYXRlcy5cbiAgICBleHBlY3QobWFuaWZlc3QuZW50cnlwb2ludHNbXCIvaXNyLzEucnNjXCJdKS50b0JlRGVmaW5lZCgpO1xuICAgIGV4cGVjdChcbiAgICAgIG1hbmlmZXN0LmVudHJ5cG9pbnRzW1wiL2lzci8xLnNlZ21lbnRzL2lzci8kZCRpZC9fX1BBR0VfXy5zZWdtZW50LnJzY1wiXSxcbiAgICApLnRvQmVEZWZpbmVkKCk7XG4gICAgLy8gVW5tdXRhdGVkLCB0aGUgc2FtZSBwYXRobmFtZXMgc3RheSBvdXQ6IHRoZSB1bmdhdGVkIHJ1bGUgYWxyZWFkeSByZWFjaGVzXG4gICAgLy8gYC9pc3IvW2lkXWAsIHdoaWNoIGlzIHdoZXJlIHRoZSBgbnh0UGlkYCBwYXJhbSBjb21lcyBmcm9tLlxuICAgIGNvbnN0IHsgbWFuaWZlc3Q6IHVuZ2F0ZWQgfSA9IGJ1aWxkKGFzQ29udGV4dChhcHBQbGF5Z3JvdW5kKSk7XG4gICAgZXhwZWN0KHVuZ2F0ZWQuZW50cnlwb2ludHNbXCIvaXNyLzFcIl0pLnRvQmVVbmRlZmluZWQoKTtcbiAgICBleHBlY3QodW5nYXRlZC5lbnRyeXBvaW50c1tcIi9pc3IvMS5yc2NcIl0pLnRvQmVVbmRlZmluZWQoKTtcbiAgICAvLyBBbmQgYSBwYXRobmFtZSBubyBydWxlIG1hdGNoZXMgYXQgYWxsIHN0YXlzIG91dCBlaXRoZXIgd2F5OiBgcmVzb2x2ZVJvdXRlc2BcbiAgICAvLyBuZXZlciByZXNvbHZlcyBhIHN0YXRpYyByb3V0ZSdzIHNlZ21lbnQgb3V0cHV0cywgc28gbGlzdGluZyB0aGVtIGlzIHdlaWdodC5cbiAgICBleHBlY3QoXG4gICAgICBtYW5pZmVzdC5lbnRyeXBvaW50c1tcIi9pbmRleC5zZWdtZW50cy9fdHJlZS5zZWdtZW50LnJzY1wiXSxcbiAgICApLnRvQmVVbmRlZmluZWQoKTtcbiAgfSk7XG5cbiAgaXQoXCJsZWF2ZXMgcHVibGljLyBvdXQgb2YgdGhlIG1hbmlmZXN0IGFuZCB0aGUgc3RhZ2luZyBwbGFuXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBUaGUgY29udGFpbmVyIHJ1bnRpbWUgbGlzdHMgYHB1YmxpYy9gIG9mZiBkaXNrIGF0IGNvbGQgc3RhcnRcbiAgICAvLyAoYHJlYWRQdWJsaWNGaWxlc2ApLCBiZWNhdXNlIG9ubHkgdGhlIGRpc2sgaGFzIHdoYXQgYSBgcG9zdGJ1aWxkYCB3cm90ZVxuICAgIC8vIGludG8gaXQgYWZ0ZXIgdGhpcyBob29rIHJhbjsgYW5kIHRoZSBMYW1iZGEgdHlwZXMgbmV2ZXIgc2VydmUgaXQuXG4gICAgY29uc3QgcmVwb1Jvb3QgPSBhd2FpdCBta2R0ZW1wKGpvaW4odG1wZGlyKCksIFwiY2RrLW5leHRqcy1wdWJsaWMtXCIpKTtcbiAgICAvLyBFdmVyeSBwYXRoIGluIHRoZSBmaXh0dXJlLCByZWJhc2VkIGZyb20gYC9yZXBvYCBvbnRvIGEgcmVhbCBkaXJlY3RvcnkuXG4gICAgY29uc3QgY3R4ID0gYXNDb250ZXh0KFxuICAgICAgSlNPTi5wYXJzZShcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoYXBwUGxheWdyb3VuZEJhc2VQYXRoKS5yZXBsYWNlQWxsKFxuICAgICAgICAgICdcIi9yZXBvJyxcbiAgICAgICAgICBgXCIke3JlcG9Sb290fWAsXG4gICAgICAgICksXG4gICAgICApLFxuICAgICk7XG4gICAgYXdhaXQgbWtkaXIoam9pbihjdHgucHJvamVjdERpciwgXCJwdWJsaWNcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGF3YWl0IHdyaXRlRmlsZShqb2luKGN0eC5wcm9qZWN0RGlyLCBcInB1YmxpY1wiLCBcInRlc3QudHh0XCIpLCBcImhlbGxvXCIpO1xuXG4gICAgY29uc3Qge1xuICAgICAgbWFuaWZlc3QsXG4gICAgICBncm91cHM6IFt7IHN0YWdpbmcgfV0sXG4gICAgfSA9IGJ1aWxkKGN0eCk7XG4gICAgZXhwZWN0KFxuICAgICAgT2JqZWN0LnZhbHVlcyhtYW5pZmVzdC5zdGF0aWNGaWxlcykuZmlsdGVyKChrZXkpID0+XG4gICAgICAgIGtleS5pbmNsdWRlcyhcIi9wdWJsaWMvXCIpLFxuICAgICAgKSxcbiAgICApLnRvRXF1YWwoW10pO1xuICAgIGV4cGVjdChtYW5pZmVzdC5wYXRobmFtZXMpLm5vdC50b0NvbnRhaW4oXCIvcHJvZC90ZXN0LnR4dFwiKTtcbiAgICBleHBlY3QoXG4gICAgICBbLi4uc3RhZ2luZy5rZXlzKCldLmZpbHRlcigoa2V5KSA9PiBrZXkuaW5jbHVkZXMoXCIvcHVibGljL1wiKSksXG4gICAgKS50b0VxdWFsKFtdKTtcbiAgfSk7XG5cbiAgaXQoXCJ3YXJucyBpbnN0ZWFkIG9mIHRocm93aW5nIHdoZW4gYSB0ZW1wbGF0ZSBoYXMgbm8gb3duaW5nIHJvdXRlXCIsICgpID0+IHtcbiAgICBjb25zdCB3YXJuID0gamVzdC5zcHlPbihjb25zb2xlLCBcIndhcm5cIikubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHt9KTtcbiAgICBjb25zdCBjdHggPSBhc0NvbnRleHQocGFnZXNJMThuKTtcbiAgICBjdHgub3V0cHV0cy5wcmVyZW5kZXJzWzBdLnJvdXRlID0gXCIvZ29uZS9bc2x1Z11cIjtcbiAgICBjdHgub3V0cHV0cy5wcmVyZW5kZXJzWzBdLnBhdGhuYW1lID0gXCIvZ29uZS9bc2x1Z11cIjtcbiAgICBjb25zdCB7IG1hbmlmZXN0IH0gPSBidWlsZChjdHgpO1xuICAgIGV4cGVjdChtYW5pZmVzdC5lbnRyeXBvaW50c1tcIi9nb25lL1tzbHVnXVwiXSkudG9CZVVuZGVmaW5lZCgpO1xuICAgIGV4cGVjdChcbiAgICAgIHdhcm4ubW9jay5jYWxsc1xuICAgICAgICAubWFwKChjYWxsKSA9PiBTdHJpbmcoY2FsbFswXSkpXG4gICAgICAgIC5maWx0ZXIoKG1lc3NhZ2UpID0+IG1lc3NhZ2UuaW5jbHVkZXMoXCJ3aWxsIDQwNFwiKSksXG4gICAgKS50b0VxdWFsKFtcbiAgICAgIGV4cGVjdC5zdHJpbmdDb250YWluaW5nKCcvZ29uZS9bc2x1Z10gKHJvdXRlOiBcIi9nb25lL1tzbHVnXVwiKScpLFxuICAgIF0pO1xuICB9KTtcblxuICBpdChcIndhcm5zIG9uY2UgcGVyIHVuc3VwcG9ydGVkIHJvdXRlIGNvbmZpZyBrZXlcIiwgKCkgPT4ge1xuICAgIGNvbnN0IHdhcm4gPSBqZXN0LnNweU9uKGNvbnNvbGUsIFwid2FyblwiKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4ge30pO1xuICAgIGJ1aWxkKGFzQ29udGV4dChwYWdlc0kxOG4pKTtcbiAgICBjb25zdCBtZXNzYWdlcyA9IHdhcm4ubW9jay5jYWxscy5tYXAoKGNhbGwpID0+IFN0cmluZyhjYWxsWzBdKSk7XG4gICAgZXhwZWN0KG1lc3NhZ2VzLmZpbHRlcigobSkgPT4gbS5pbmNsdWRlcyhcImBtYXhEdXJhdGlvbmBcIikpKS50b0hhdmVMZW5ndGgoMSk7XG4gICAgZXhwZWN0KG1lc3NhZ2VzWzBdKS50b0NvbnRhaW4oXCJzc3JcIik7XG4gICAgZXhwZWN0KG1lc3NhZ2VzWzBdKS50b0NvbnRhaW4oXCJvdmVycmlkZXNcIik7XG4gICAgZXhwZWN0KG1lc3NhZ2VzLnNvbWUoKG0pID0+IG0uaW5jbHVkZXMoXCJgcHJlZmVycmVkUmVnaW9uYFwiKSkpLnRvQmUoZmFsc2UpO1xuICB9KTtcblxuICBpdChcInRocm93cyBvbiBhbiBlZGdlLXJ1bnRpbWUgb3V0cHV0XCIsICgpID0+IHtcbiAgICBjb25zdCBjdHggPSBhc0NvbnRleHQoYXBwUGxheWdyb3VuZCk7XG4gICAgY3R4Lm91dHB1dHMuYXBwUm91dGVzWzBdLnJ1bnRpbWUgPSBcImVkZ2VcIjtcbiAgICBleHBlY3QoKCkgPT4gYnVpbGQoY3R4KSkudG9UaHJvdyhcbiAgICAgIC9jYW5ub3QgZGVwbG95IHJvdXRlcyBidWlsdCBmb3IgdGhlIGVkZ2UgcnVudGltZS8sXG4gICAgKTtcbiAgICBleHBlY3QoKCkgPT4gYnVpbGQoY3R4KSkudG9UaHJvdyhjdHgub3V0cHV0cy5hcHBSb3V0ZXNbMF0uc291cmNlUGFnZSk7XG4gIH0pO1xuXG4gIGl0KFwiYmxhbWVzIG1pZGRsZXdhcmUsIG5vdCBgL2AsIGZvciBlZGdlLXJ1bnRpbWUgbWlkZGxld2FyZVwiLCAoKSA9PiB7XG4gICAgY29uc3QgY3R4ID0gYXNDb250ZXh0KGFwcFBsYXlncm91bmQpO1xuICAgIGNvbnN0IG1pZGRsZXdhcmUgPSBjdHgub3V0cHV0cy5taWRkbGV3YXJlO1xuICAgIGlmICghbWlkZGxld2FyZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiZml4dHVyZSBoYXMgbm8gbWlkZGxld2FyZSBvdXRwdXRcIik7XG4gICAgfVxuICAgIC8vIFdoYXQgYSBsZWdhY3kgYG1pZGRsZXdhcmUudHNgIGJ1aWxkcyB0by4gSXRzIGBzb3VyY2VQYWdlYCBpcyBgL2AsIHNvIHRoZVxuICAgIC8vIHJlZ3Jlc3Npb24gZ3VhcmRlZCBoZXJlIGlzIHRoZSBtZXNzYWdlIHRlbGxpbmcgYW4gYXV0aG9yIHRvIGVkaXQgdGhlIGhvbWVcbiAgICAvLyBwYWdlLlxuICAgIG1pZGRsZXdhcmUucnVudGltZSA9IFwiZWRnZVwiO1xuXG4gICAgZXhwZWN0KCgpID0+IGJ1aWxkKGN0eCkpLnRvVGhyb3coXG4gICAgICAvY2Fubm90IGRlcGxveSBtaWRkbGV3YXJlIGJ1aWx0IGZvciB0aGUgZWRnZSBydW50aW1lLyxcbiAgICApO1xuICAgIGV4cGVjdCgoKSA9PiBidWlsZChjdHgpKS50b1Rocm93KG1pZGRsZXdhcmUuZmlsZVBhdGgpO1xuICAgIC8vIEJvdGggd2F5cyBvdXQ6IGBtaWRkbGV3YXJlLnRzYCBvbmx5IGRlZmF1bHRzIHRvIGVkZ2UuXG4gICAgZXhwZWN0KCgpID0+IGJ1aWxkKGN0eCkpLnRvVGhyb3coL3J1bnRpbWU6IFwibm9kZWpzXCIvKTtcbiAgICBleHBlY3QoKCkgPT4gYnVpbGQoY3R4KSkudG9UaHJvdygvcHJveHlcXC50cy8pO1xuICAgIGV4cGVjdCgoKSA9PiBidWlsZChjdHgpKS5ub3QudG9UaHJvdygvZWRnZS1vbmx5Lyk7XG4gICAgZXhwZWN0KCgpID0+IGJ1aWxkKGN0eCkpLm5vdC50b1Rocm93KFxuICAgICAgL2Nhbm5vdCBkZXBsb3kgcm91dGVzIGJ1aWx0IGZvciB0aGUgZWRnZSBydW50aW1lLyxcbiAgICApO1xuICB9KTtcblxuICBpdChcInRocm93cyB3aGVuIHR3byBvdXRwdXRzIG1hcCBvbmUga2V5IHRvIGRpZmZlcmVudCBjb250ZW50XCIsICgpID0+IHtcbiAgICBjb25zdCBjdHggPSBhc0NvbnRleHQoYXBwUGxheWdyb3VuZCk7XG4gICAgY29uc3QgW2ZpcnN0LCBzZWNvbmRdID0gY3R4Lm91dHB1dHMuYXBwUGFnZXM7XG4gICAgY29uc3Qga2V5ID0gT2JqZWN0LmtleXMoZmlyc3QuYXNzZXRzKVswXTtcbiAgICBmaXJzdC5hc3NldHNIYXNoZXNba2V5XSA9IFwiaGFzaC1hXCI7XG4gICAgc2Vjb25kLmFzc2V0c1trZXldID0gZmlyc3QuYXNzZXRzW2tleV07XG4gICAgc2Vjb25kLmFzc2V0c0hhc2hlc1trZXldID0gXCJoYXNoLWJcIjtcbiAgICBleHBlY3QoKCkgPT4gYnVpbGQoY3R4KSkudG9UaHJvdygvbWFwIFwiW15cIl0rXCIgdG8gZGlmZmVyZW50IGNvbnRlbnQvKTtcbiAgfSk7XG5cbiAgaXQoXCJ0aHJvd3Mgb24gYW4gYXNzZXQga2V5IG91dHNpZGUgdGhlIGRlcGxveW1lbnQgcm9vdFwiLCAoKSA9PiB7XG4gICAgY29uc3QgY3R4ID0gYXNDb250ZXh0KGFwcFBsYXlncm91bmQpO1xuICAgIGN0eC5vdXRwdXRzLmFwcFBhZ2VzWzBdLmFzc2V0c1tcIi4uL2VzY2FwZS5qc1wiXSA9IFwiL2Vsc2V3aGVyZS9lc2NhcGUuanNcIjtcbiAgICBleHBlY3QoKCkgPT4gYnVpbGQoY3R4KSkudG9UaHJvdygvb3V0c2lkZSB0aGUgZGVwbG95bWVudCByb290Lyk7XG4gIH0pO1xuXG4gIGl0KFwidGhyb3dzIG9uIGFuIGFzc2V0IGtleSBzaGFkb3dpbmcgdGhlIHJlc2VydmVkIHJ1bnRpbWUgZGlyZWN0b3J5XCIsICgpID0+IHtcbiAgICBjb25zdCBjdHggPSBhc0NvbnRleHQoYXBwUGxheWdyb3VuZCk7XG4gICAgY3R4Lm91dHB1dHMuYXBwUGFnZXNbMF0uYXNzZXRzW2Ake1JVTlRJTUVfRElSX05BTUV9L2xhbWJkYS5tanNgXSA9XG4gICAgICBcIi9yZXBvL3doYXRldmVyLm1qc1wiO1xuICAgIGV4cGVjdCgoKSA9PiBidWlsZChjdHgpKS50b1Rocm93KFxuICAgICAgbmV3IFJlZ0V4cChgXCIke1JVTlRJTUVfRElSX05BTUV9L1wiIGlzIHJlc2VydmVkYCksXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoXCJ0aHJvd3Mgd2hlbiB0d28gb3V0cHV0cyBjbGFpbSBvbmUgcGF0aG5hbWUgZnJvbSBkaWZmZXJlbnQgZmlsZXNcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGN0eCA9IGFzQ29udGV4dChhcHBQbGF5Z3JvdW5kKTtcbiAgICBjdHgub3V0cHV0cy5hcHBSb3V0ZXNbMF0ucGF0aG5hbWUgPSBjdHgub3V0cHV0cy5hcHBQYWdlc1swXS5wYXRobmFtZTtcbiAgICBleHBlY3QoKCkgPT4gYnVpbGQoY3R4KSkudG9UaHJvdygvY2xhaW0gdGhlIHBhdGhuYW1lIFwiW15cIl0rXCIvKTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoXCJ3cml0ZUJ1aWxkT3V0cHV0c1wiLCAoKSA9PiB7XG4gIC8qKlxuICAgKiBCdWlsZHMgYSB0aHJvd2F3YXkgcmVwbyBvbiBkaXNrIHNvIHN0YWdpbmcgY2FuIGJlIGV4ZXJjaXNlZCBmb3IgcmVhbDpcbiAgICogZml4dHVyZSBzb3VyY2VzIGFyZSBgL3JlcG9gIHBsYWNlaG9sZGVycyBhbmQgY2Fubm90IGJlIGNvcGllZC5cbiAgICovXG4gIC8qKlxuICAgKiBBIGBuZXh0YCBpbnN0YWxsIGp1c3QgcmVhbCBlbm91Z2ggZm9yIHtAbGluayBhZGRSdW50aW1lTmV4dENsb3N1cmV9OiB0aGVcbiAgICogbW9kdWxlcyBgc3JjL3J1bnRpbWUvaW1hZ2UudHNgIHJlcXVpcmVzLCBvbmUgZmlsZSBvbmx5IHRoZSB0cmFjZSByZWFjaGVzLCBhbmRcbiAgICogYSBzdGFuZC1pbiBmb3IgbmV4dCdzIHZlbmRvcmVkIGBAdmVyY2VsL25mdGAgdGhhdCByZXBvcnRzIHRoZW0uIFRyYWNpbmcgZm9yXG4gICAqIHJlYWwgaXMgbmV4dCdzIGpvYiwgbm90IG91cnM7IHdoYXQgaXMgdW5kZXIgdGVzdCBpcyB0aGF0IHRoZSBjbG9zdXJlIGlzXG4gICAqIHJlc29sdmVkIGZyb20gdGhlIHByb2plY3QgZGlyIGFuZCBzdGFnZWQgdW5kZXIgcmVwby1yb290LXJlbGF0aXZlIGtleXMuXG4gICAqL1xuICBhc3luYyBmdW5jdGlvbiBpbnN0YWxsRmFrZU5leHQoXG4gICAgcmVwb1Jvb3Q6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7IHBucG0/OiBib29sZWFuIH0gPSB7fSxcbiAgKSB7XG4gICAgLy8gVW5kZXIgcG5wbSwgYG5leHRgIGxpdmVzIGluIHRoZSB2aXJ0dWFsIHN0b3JlIGJlaGluZCBhIGxpbmssIGFuZCBpdHMgb3duXG4gICAgLy8gZGVwZW5kZW5jaWVzIGFyZSBsaW5rcyBiZXNpZGUgaXQuXG4gICAgY29uc3Qgc3RvcmVNb2R1bGVzID0gam9pbihcbiAgICAgIHJlcG9Sb290LFxuICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICAgIFwiLnBucG1cIixcbiAgICAgIFwibmV4dEAxLjAuMFwiLFxuICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICApO1xuICAgIGNvbnN0IG5leHRSb290ID0gb3B0aW9ucy5wbnBtXG4gICAgICA/IGpvaW4oc3RvcmVNb2R1bGVzLCBcIm5leHRcIilcbiAgICAgIDogam9pbihyZXBvUm9vdCwgXCJub2RlX21vZHVsZXNcIiwgXCJuZXh0XCIpO1xuICAgIGlmIChvcHRpb25zLnBucG0pIHtcbiAgICAgIGNvbnN0IG5leHRFbnYgPSBqb2luKFxuICAgICAgICByZXBvUm9vdCxcbiAgICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICAgICAgXCIucG5wbVwiLFxuICAgICAgICBcIkBuZXh0K2VudkAxLjAuMFwiLFxuICAgICAgICBcIm5vZGVfbW9kdWxlc1wiLFxuICAgICAgICBcIkBuZXh0XCIsXG4gICAgICAgIFwiZW52XCIsXG4gICAgICApO1xuICAgICAgYXdhaXQgbWtkaXIobmV4dEVudiwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihuZXh0RW52LCBcImluZGV4LmpzXCIpLCBcIi8vIEBuZXh0L2VudlxcblwiKTtcbiAgICAgIGF3YWl0IHdyaXRlRmlsZShcbiAgICAgICAgam9pbihuZXh0RW52LCBcInBhY2thZ2UuanNvblwiKSxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoeyBuYW1lOiBcIkBuZXh0L2VudlwiLCBtYWluOiBcImluZGV4LmpzXCIgfSksXG4gICAgICApO1xuICAgICAgYXdhaXQgbWtkaXIoam9pbihzdG9yZU1vZHVsZXMsIFwiQG5leHRcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgYXdhaXQgc3ltbGluayhcbiAgICAgICAgXCIuLi8uLi8uLi9AbmV4dCtlbnZAMS4wLjAvbm9kZV9tb2R1bGVzL0BuZXh0L2VudlwiLFxuICAgICAgICBqb2luKHN0b3JlTW9kdWxlcywgXCJAbmV4dFwiLCBcImVudlwiKSxcbiAgICAgICk7XG4gICAgICBhd2FpdCBta2RpcihuZXh0Um9vdCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBhd2FpdCBzeW1saW5rKFxuICAgICAgICBcIi5wbnBtL25leHRAMS4wLjAvbm9kZV9tb2R1bGVzL25leHRcIixcbiAgICAgICAgam9pbihyZXBvUm9vdCwgXCJub2RlX21vZHVsZXNcIiwgXCJuZXh0XCIpLFxuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgZmlsZXMgPSBbXG4gICAgICBcImRpc3Qvc2VydmVyL2NvbmZpZy1zaGFyZWQuanNcIixcbiAgICAgIFwiZGlzdC9zaGFyZWQvbGliL2ltYWdlLWNvbmZpZy5qc1wiLFxuICAgICAgXCJkaXN0L3NlcnZlci9pbWFnZS1vcHRpbWl6ZXIuanNcIixcbiAgICAgIFwiZGlzdC9zZXJ2ZXIvc2VydmUtc3RhdGljLmpzXCIsXG4gICAgICAvLyBSZWFjaGVkIG9ubHkgdGhyb3VnaCB0aGUgdHJhY2UsIGkuZS4gdGhlIHJlYXNvbiB0cmFjaW5nIGlzIG5lZWRlZC5cbiAgICAgIFwiZGlzdC9zaGFyZWQvbGliL21hdGNoLXJlbW90ZS1wYXR0ZXJuLmpzXCIsXG4gICAgXTtcbiAgICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgIGNvbnN0IHBhdGggPSBqb2luKG5leHRSb290LCBmaWxlKTtcbiAgICAgIGF3YWl0IG1rZGlyKGRpcm5hbWUocGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgYXdhaXQgd3JpdGVGaWxlKHBhdGgsIGAvLyAke2ZpbGV9XFxuYCk7XG4gICAgfVxuICAgIC8vIE5vIGBleHBvcnRzYCBmaWVsZDogYG5leHQvZGlzdC8qKmAgaXMgcmVxdWlyZWQgYnkgcGF0aC5cbiAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICBqb2luKG5leHRSb290LCBcInBhY2thZ2UuanNvblwiKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHsgbmFtZTogXCJuZXh0XCIsIHZlcnNpb246IFwiMC4wLjAtdGVzdFwiIH0pLFxuICAgICk7XG5cbiAgICBjb25zdCB0cmFjZXIgPSBqb2luKG5leHRSb290LCBcImRpc3RcIiwgXCJjb21waWxlZFwiLCBcIkB2ZXJjZWxcIiwgXCJuZnRcIik7XG4gICAgYXdhaXQgbWtkaXIodHJhY2VyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICBqb2luKHRyYWNlciwgXCJwYWNrYWdlLmpzb25cIiksXG4gICAgICBKU09OLnN0cmluZ2lmeSh7IG5hbWU6IFwiQHZlcmNlbC9uZnRcIiwgbWFpbjogXCJpbmRleC5qc1wiIH0pLFxuICAgICk7XG4gICAgYXdhaXQgd3JpdGVGaWxlKFxuICAgICAgam9pbih0cmFjZXIsIFwiaW5kZXguanNcIiksXG4gICAgICAvLyBSZWFsIG5mdCByZXR1cm5zIHBhdGhzIHJlbGF0aXZlIHRvIGBiYXNlYCwgd2hpY2ggaXMgdGhlIHJlcG8gcm9vdCB0aGVcbiAgICAgIC8vIGFkYXB0ZXIgcGFzc2VzLlxuICAgICAgYGNvbnN0IHByZWZpeCA9ICR7SlNPTi5zdHJpbmdpZnkocmVsYXRpdmUocmVwb1Jvb3QsIG5leHRSb290KS5zcGxpdChzZXApLmpvaW4oXCIvXCIpKX07XFxuYCArXG4gICAgICAgIFwiY29uc3QgeyByZWFscGF0aFN5bmMgfSA9IHJlcXVpcmUoJ25vZGU6ZnMnKTtcXG5cIiArXG4gICAgICAgIFwiY29uc3QgeyByZWxhdGl2ZSB9ID0gcmVxdWlyZSgnbm9kZTpwYXRoJyk7XFxuXCIgK1xuICAgICAgICBcImV4cG9ydHMubm9kZUZpbGVUcmFjZSA9IGFzeW5jIChlbnRyaWVzLCB7IGJhc2UgfSkgPT4ge1xcblwiICtcbiAgICAgICAgLy8gTGlrZSByZWFsIG5mdCwgdGhlIGVudHJpZXMgdGhlbXNlbHZlcyBhcmUgaW4gdGhlIGxpc3QuXG4gICAgICAgIFwiICBjb25zdCB0cmFjZWQgPSBlbnRyaWVzXFxuXCIgK1xuICAgICAgICBcIiAgICAubWFwKChlKSA9PiByZWxhdGl2ZShyZWFscGF0aFN5bmMoYmFzZSksIGUpKVxcblwiICtcbiAgICAgICAgXCIgICAgLmZpbHRlcigoZSkgPT4gIWUuc3RhcnRzV2l0aCgnLi4nKSk7XFxuXCIgK1xuICAgICAgICBcIiAgaWYgKHRyYWNlZC5zb21lKChlKSA9PiBlLmVuZHNXaXRoKCdpbWFnZS1vcHRpbWl6ZXIuanMnKSkpIHtcXG5cIiArXG4gICAgICAgIFwiICAgIHRyYWNlZC5wdXNoKGAke3ByZWZpeH0vZGlzdC9zaGFyZWQvbGliL21hdGNoLXJlbW90ZS1wYXR0ZXJuLmpzYCk7XFxuXCIgK1xuICAgICAgICBcIiAgfVxcblwiICtcbiAgICAgICAgXCIgIHJldHVybiB7IGZpbGVMaXN0OiBuZXcgU2V0KHRyYWNlZCkgfTtcXG5cIiArXG4gICAgICAgIFwifTtcXG5cIixcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gbWFrZVJlcG8oXG4gICAgb3B0aW9uczogeyB3aXRoTmV4dD86IGJvb2xlYW47IHBucG1OZXh0PzogYm9vbGVhbiB9ID0ge30sXG4gICkge1xuICAgIGNvbnN0IHJlcG9Sb290ID0gYXdhaXQgbWtkdGVtcChqb2luKHRtcGRpcigpLCBcImNkay1uZXh0anMtc3RhZ2luZy1cIikpO1xuICAgIGlmIChvcHRpb25zLndpdGhOZXh0IHx8IG9wdGlvbnMucG5wbU5leHQpIHtcbiAgICAgIGF3YWl0IGluc3RhbGxGYWtlTmV4dChyZXBvUm9vdCwgeyBwbnBtOiBvcHRpb25zLnBucG1OZXh0IH0pO1xuICAgIH1cbiAgICBjb25zdCBwcm9qZWN0RGlyID0gam9pbihyZXBvUm9vdCwgXCJhcHBcIik7XG4gICAgY29uc3QgZGlzdERpciA9IGpvaW4ocHJvamVjdERpciwgXCIubmV4dFwiKTtcbiAgICBjb25zdCBlbnRyeSA9IGpvaW4oZGlzdERpciwgXCJzZXJ2ZXJcIiwgXCJhcHBcIiwgXCJwYWdlLmpzXCIpO1xuICAgIGNvbnN0IGRlcCA9IGpvaW4ocHJvamVjdERpciwgXCJub2RlX21vZHVsZXNcIiwgXCJkZXBcIik7XG4gICAgY29uc3Qgc3RvcmUgPSBqb2luKHJlcG9Sb290LCBcInN0b3JlXCIsIFwicGtnXCIpO1xuICAgIC8vIHBucG0ncyB2aXJ0dWFsIHN0b3JlOiBvbmUgcGFja2FnZSByZWFjaGFibGUgb25seSBmcm9tIGluc2lkZSBpdCwgYW5kIG9uZVxuICAgIC8vIHRoYXQgYWxzbyBoYXMgYSBsb2dpY2FsIHBhdGggKGBhcHAvbm9kZV9tb2R1bGVzL2RlcGApLlxuICAgIGNvbnN0IHZpcnR1YWxTdG9yZSA9IGpvaW4ocmVwb1Jvb3QsIFwibm9kZV9tb2R1bGVzXCIsIFwiLnBucG1cIik7XG4gICAgY29uc3QgaGlkZGVuID0gam9pbihcbiAgICAgIHZpcnR1YWxTdG9yZSxcbiAgICAgIFwiaGVscGVyc0AxLjAuMFwiLFxuICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICAgIFwiQHNjb3BlXCIsXG4gICAgICBcImhlbHBlcnNcIixcbiAgICApO1xuICAgIGNvbnN0IGRlcEluU3RvcmUgPSBqb2luKHZpcnR1YWxTdG9yZSwgXCJkZXBAMS4wLjBcIiwgXCJub2RlX21vZHVsZXNcIiwgXCJkZXBcIik7XG4gICAgLy8gVGhlIHNoYXBlIHRoYXQgbWFrZXMgYSBzdG9yZSBwYWNrYWdlIHJlYWNoYWJsZSBmcm9tIGFub3RoZXIgc3RvcmVcbiAgICAvLyBwYWNrYWdlOiBhIGxpbmsgYmV0d2VlbiB0d28gc3RvcmUgZGlyZWN0b3JpZXMsIG5vIGZpbGVzIG9mIGl0cyBvd24uXG4gICAgY29uc3QgaGlkZGVuTGluayA9IGpvaW4oXG4gICAgICB2aXJ0dWFsU3RvcmUsXG4gICAgICBcImRlcEAxLjAuMFwiLFxuICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICAgIFwiQHNjb3BlXCIsXG4gICAgICBcImhlbHBlcnNcIixcbiAgICApO1xuXG4gICAgYXdhaXQgbWtkaXIoam9pbihkaXN0RGlyLCBcInNlcnZlclwiLCBcImFwcFwiKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgLy8gRXZlcnkgZGVwbG95bWVudCByb290IG5lZWRzIHRoaXMsIGFuZCBgbG9hZFJ1bnRpbWVgIHJlZnVzZXMgdG8gc2VydmVcbiAgICAvLyB3aXRob3V0IGl0LCBzbyB0aGUgc3RhZ2luZyBwbGFuIGNhcnJpZXMgaXQgaW5kZXBlbmRlbnRseSBvZiBhbnkgb3V0cHV0J3NcbiAgICAvLyB0cmFjZWQgYXNzZXRzLlxuICAgIGF3YWl0IHdyaXRlRmlsZShqb2luKGRpc3REaXIsIFwicmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25cIiksIFwie31cXG5cIik7XG4gICAgYXdhaXQgbWtkaXIoZGVwLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBhd2FpdCBta2RpcihzdG9yZSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgYXdhaXQgbWtkaXIoaGlkZGVuLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBhd2FpdCBta2RpcihkZXBJblN0b3JlLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBhd2FpdCB3cml0ZUZpbGUoZW50cnksIFwibW9kdWxlLmV4cG9ydHMgPSB7fTtcXG5cIik7XG4gICAgYXdhaXQgd3JpdGVGaWxlKGpvaW4oZGVwLCBcImluZGV4LmpzXCIpLCBcIi8vIGRlcFxcblwiKTtcbiAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihzdG9yZSwgXCJpbmRleC5qc1wiKSwgXCIvLyBzdG9yZVxcblwiKTtcbiAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihoaWRkZW4sIFwiaW5kZXguanNcIiksIFwiLy8gaGVscGVyc1xcblwiKTtcbiAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihkZXBJblN0b3JlLCBcImluZGV4LmpzXCIpLCBcIi8vIGRlcFxcblwiKTtcbiAgICBhd2FpdCBta2RpcihkaXJuYW1lKGhpZGRlbkxpbmspLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBhd2FpdCBzeW1saW5rKFxuICAgICAgam9pbihcbiAgICAgICAgXCIuLlwiLFxuICAgICAgICBcIi4uXCIsXG4gICAgICAgIFwiLi5cIixcbiAgICAgICAgXCJoZWxwZXJzQDEuMC4wXCIsXG4gICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgIFwiQHNjb3BlXCIsXG4gICAgICAgIFwiaGVscGVyc1wiLFxuICAgICAgKSxcbiAgICAgIGhpZGRlbkxpbmssXG4gICAgKTtcbiAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihwcm9qZWN0RGlyLCBcIi5lbnZcIiksIFwiU0hBUkVEPTFcXG5cIik7XG4gICAgYXdhaXQgd3JpdGVGaWxlKGpvaW4ocHJvamVjdERpciwgXCIuZW52LnByb2R1Y3Rpb25cIiksIFwiUFJPRD0xXFxuXCIpO1xuICAgIC8vIEEgcmVsYXRpdmUgbGluayB3aG9zZSB0YXJnZXQgaXMgaXRzZWxmIHN0YWdlZDogcG5wbSdzIGNvbW1vbiBzaGFwZS5cbiAgICBhd2FpdCBzeW1saW5rKFwiZGVwXCIsIGpvaW4ocHJvamVjdERpciwgXCJub2RlX21vZHVsZXNcIiwgXCJyZWwtbGlua1wiKSk7XG4gICAgLy8gQW4gYWJzb2x1dGUgbGluayBvdXQgb2YgdGhlIHRyZWU6IHN0YWdpbmcgbXVzdCBtYXRlcmlhbGl6ZSBpdCBpbnN0ZWFkLlxuICAgIGF3YWl0IHN5bWxpbmsoc3RvcmUsIGpvaW4ocHJvamVjdERpciwgXCJub2RlX21vZHVsZXNcIiwgXCJhYnMtbGlua1wiKSk7XG5cbiAgICBjb25zdCBvdXRwdXQgPSB7XG4gICAgICBpZDogXCIvXCIsXG4gICAgICBwYXRobmFtZTogXCIvXCIsXG4gICAgICBzb3VyY2VQYWdlOiBcIi9wYWdlXCIsXG4gICAgICBmaWxlUGF0aDogZW50cnksXG4gICAgICBydW50aW1lOiBcIm5vZGVqc1wiLFxuICAgICAgY29uZmlnOiB7fSxcbiAgICAgIGFzc2V0czoge1xuICAgICAgICBcImFwcC9ub2RlX21vZHVsZXMvZGVwL2luZGV4LmpzXCI6IGpvaW4oZGVwLCBcImluZGV4LmpzXCIpLFxuICAgICAgICBcImFwcC9ub2RlX21vZHVsZXMvcmVsLWxpbmtcIjogam9pbihcbiAgICAgICAgICBwcm9qZWN0RGlyLFxuICAgICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgICAgXCJyZWwtbGlua1wiLFxuICAgICAgICApLFxuICAgICAgICBcImFwcC9ub2RlX21vZHVsZXMvYWJzLWxpbmtcIjogam9pbihcbiAgICAgICAgICBwcm9qZWN0RGlyLFxuICAgICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgICAgXCJhYnMtbGlua1wiLFxuICAgICAgICApLFxuICAgICAgICBcIm5vZGVfbW9kdWxlcy8ucG5wbS9oZWxwZXJzQDEuMC4wL25vZGVfbW9kdWxlcy9Ac2NvcGUvaGVscGVycy9pbmRleC5qc1wiOlxuICAgICAgICAgIGpvaW4oaGlkZGVuLCBcImluZGV4LmpzXCIpLFxuICAgICAgICBcIm5vZGVfbW9kdWxlcy8ucG5wbS9kZXBAMS4wLjAvbm9kZV9tb2R1bGVzL2RlcC9pbmRleC5qc1wiOiBqb2luKFxuICAgICAgICAgIGRlcEluU3RvcmUsXG4gICAgICAgICAgXCJpbmRleC5qc1wiLFxuICAgICAgICApLFxuICAgICAgICBcIm5vZGVfbW9kdWxlcy8ucG5wbS9kZXBAMS4wLjAvbm9kZV9tb2R1bGVzL0BzY29wZS9oZWxwZXJzXCI6IGhpZGRlbkxpbmssXG4gICAgICB9LFxuICAgICAgYXNzZXRzSGFzaGVzOiB7fSxcbiAgICB9O1xuXG4gICAgY29uc3QgY3R4ID0ge1xuICAgICAgcmVwb1Jvb3QsXG4gICAgICBwcm9qZWN0RGlyLFxuICAgICAgZGlzdERpcixcbiAgICAgIGJ1aWxkSWQ6IFwidGVzdC1idWlsZFwiLFxuICAgICAgbmV4dFZlcnNpb246IFwiMTYuMy41XCIsXG4gICAgICBjb25maWc6IHtcbiAgICAgICAgYmFzZVBhdGg6IFwiXCIsXG4gICAgICAgIHRyYWlsaW5nU2xhc2g6IGZhbHNlLFxuICAgICAgICBhc3NldFByZWZpeDogXCJcIixcbiAgICAgICAgaTE4bjogbnVsbCxcbiAgICAgIH0sXG4gICAgICByb3V0aW5nOiB7IGR5bmFtaWNSb3V0ZXM6IFtdIH0sXG4gICAgICBvdXRwdXRzOiB7XG4gICAgICAgIHBhZ2VzOiBbXSxcbiAgICAgICAgcGFnZXNBcGk6IFtdLFxuICAgICAgICBhcHBQYWdlczogW291dHB1dF0sXG4gICAgICAgIGFwcFJvdXRlczogW10sXG4gICAgICAgIHByZXJlbmRlcnM6IFtdLFxuICAgICAgICBzdGF0aWNGaWxlczogW10sXG4gICAgICAgIG1pZGRsZXdhcmU6IHVuZGVmaW5lZCxcbiAgICAgIH0sXG4gICAgfSBhcyB1bmtub3duIGFzIEJ1aWxkQ29tcGxldGVDb250ZXh0O1xuXG4gICAgcmV0dXJuIHsgY3R4LCByZXBvUm9vdCB9O1xuICB9XG5cbiAgaXQoXCJzdGFnZXMgdGhlIHRyZWUsIHByZXNlcnZlcyBzeW1saW5rcywgYW5kIHdyaXRlcyB0aGUgbWFuaWZlc3RcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCBtYWtlUmVwbygpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdyaXRlKGN0eCk7XG5cbiAgICBleHBlY3Qoc29sZVJvb3QocmVzdWx0KSkudG9CZShcbiAgICAgIGpvaW4oY3R4LmRpc3REaXIsIFwiY2RrLW5leHRqcy1hZGFwdGVyXCIsIFwiYXBwXCIpLFxuICAgICk7XG5cbiAgICBjb25zdCBzdGFnZWQgPSAoLi4ucGFydHM6IHN0cmluZ1tdKSA9PiBqb2luKHNvbGVSb290KHJlc3VsdCksIC4uLnBhcnRzKTtcbiAgICBhd2FpdCBleHBlY3QoXG4gICAgICByZWFkRmlsZShzdGFnZWQoXCJhcHBcIiwgXCIubmV4dFwiLCBcInNlcnZlclwiLCBcImFwcFwiLCBcInBhZ2UuanNcIiksIFwidXRmOFwiKSxcbiAgICApLnJlc29sdmVzLnRvQ29udGFpbihcIm1vZHVsZS5leHBvcnRzXCIpO1xuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIHJlYWRGaWxlKHN0YWdlZChcImFwcFwiLCBcIm5vZGVfbW9kdWxlc1wiLCBcImRlcFwiLCBcImluZGV4LmpzXCIpLCBcInV0ZjhcIiksXG4gICAgKS5yZXNvbHZlcy50b0NvbnRhaW4oXCJkZXBcIik7XG5cbiAgICAvLyBgY29weUZpbGVgIGZhaWxzIG91dHJpZ2h0IG9uIGEgZGlyZWN0b3J5IHN5bWxpbmssIGFuZCBkZXJlZmVyZW5jaW5nIHRoZVxuICAgIC8vIHBucG0gc3RvcmUgdHJpcGxlcyB0aGUgdHJlZSBhZ2FpbnN0IHRoZSAyNTAgTUIgdW56aXBwZWQgTGFtYmRhIGxpbWl0LlxuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIGxzdGF0KHN0YWdlZChcImFwcFwiLCBcIm5vZGVfbW9kdWxlc1wiLCBcInJlbC1saW5rXCIpKS50aGVuKChzKSA9PlxuICAgICAgICBzLmlzU3ltYm9saWNMaW5rKCksXG4gICAgICApLFxuICAgICkucmVzb2x2ZXMudG9CZSh0cnVlKTtcbiAgICAvLyBQb2ludHMgb3V0c2lkZSB0aGUgZGVwbG95bWVudCByb290LCBzbyBpdCB3b3VsZCBkYW5nbGUgaW4gTGFtYmRhLlxuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIGxzdGF0KHN0YWdlZChcImFwcFwiLCBcIm5vZGVfbW9kdWxlc1wiLCBcImFicy1saW5rXCIpKS50aGVuKChzKSA9PlxuICAgICAgICBzLmlzU3ltYm9saWNMaW5rKCksXG4gICAgICApLFxuICAgICkucmVzb2x2ZXMudG9CZShmYWxzZSk7XG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgcmVhZEZpbGUoc3RhZ2VkKFwiYXBwXCIsIFwibm9kZV9tb2R1bGVzXCIsIFwiYWJzLWxpbmtcIiwgXCJpbmRleC5qc1wiKSwgXCJ1dGY4XCIpLFxuICAgICkucmVzb2x2ZXMudG9Db250YWluKFwic3RvcmVcIik7XG5cbiAgICAvLyBgd3JpdGVTdGFuZGFsb25lRGlyZWN0b3J5YCBjb3BpZXMgdGhlc2U7IGBvbkJ1aWxkQ29tcGxldGVgIGhhcyBub1xuICAgIC8vIGVxdWl2YWxlbnQsIHNvIGRyb3BwaW5nIGBvdXRwdXQ6IFwic3RhbmRhbG9uZVwiYCBkcm9wcyB0aGVtIHNpbGVudGx5LlxuICAgIGF3YWl0IGV4cGVjdChyZWFkRmlsZShzdGFnZWQoXCJhcHBcIiwgXCIuZW52XCIpLCBcInV0ZjhcIikpLnJlc29sdmVzLnRvQ29udGFpbihcbiAgICAgIFwiU0hBUkVEPTFcIixcbiAgICApO1xuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIHJlYWRGaWxlKHN0YWdlZChcImFwcFwiLCBcIi5lbnYucHJvZHVjdGlvblwiKSwgXCJ1dGY4XCIpLFxuICAgICkucmVzb2x2ZXMudG9Db250YWluKFwiUFJPRD0xXCIpO1xuXG4gICAgY29uc3Qgd3JpdHRlbiA9IEpTT04ucGFyc2UoYXdhaXQgcmVhZEZpbGUocmVzdWx0Lm1hbmlmZXN0UGF0aCwgXCJ1dGY4XCIpKTtcbiAgICBleHBlY3Qod3JpdHRlbikudG9FcXVhbChKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KHJlc3VsdC5tYW5pZmVzdCkpKTtcbiAgICBleHBlY3Qod3JpdHRlbi5yZWxhdGl2ZVByb2plY3REaXIpLnRvQmUoXCJhcHBcIik7XG4gIH0pO1xuXG4gIGl0KFwibGVhdmVzIHN0b3JlLW9ubHkgcGFja2FnZXMgaW4gdGhlIHN0b3JlLCBiZWhpbmQgdGhlaXIgbGlua3NcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCBtYWtlUmVwbygpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdyaXRlKGN0eCk7XG4gICAgY29uc3Qgc3RhZ2VkID0gKC4uLnBhcnRzOiBzdHJpbmdbXSkgPT4gam9pbihzb2xlUm9vdChyZXN1bHQpLCAuLi5wYXJ0cyk7XG5cbiAgICAvLyBOb2RlIHJlc29sdmVzIGBAc2NvcGUvaGVscGVyc2AgZnJvbSBgZGVwYCB0aHJvdWdoIHRoZSBzdG9yZSBsaW5rLCBhcyBpdFxuICAgIC8vIGRvZXMgaW4gdGhlIHdvcmtzcGFjZSwgc28gbG9uZyBhcyBub3RoaW5nIGRlcmVmZXJlbmNlcyB0aGUgdHJlZSAodGhlXG4gICAgLy8gRnVuY3Rpb25zIHppcCBrZWVwcyBsaW5rcyBhcyBsaW5rcykuIEEgY29weSBhdCB0aGUgcm9vdCBpcyBkZWFkIHdlaWdodC5cbiAgICBhd2FpdCBleHBlY3QoXG4gICAgICBsc3RhdChzdGFnZWQoXCJub2RlX21vZHVsZXNcIiwgXCJAc2NvcGVcIiwgXCJoZWxwZXJzXCIpKSxcbiAgICApLnJlamVjdHMudG9UaHJvdygvRU5PRU5ULyk7XG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgbHN0YXQoXG4gICAgICAgIHN0YWdlZChcbiAgICAgICAgICBcIm5vZGVfbW9kdWxlc1wiLFxuICAgICAgICAgIFwiLnBucG1cIixcbiAgICAgICAgICBcImRlcEAxLjAuMFwiLFxuICAgICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgICAgXCJAc2NvcGVcIixcbiAgICAgICAgICBcImhlbHBlcnNcIixcbiAgICAgICAgKSxcbiAgICAgICkudGhlbigocykgPT4gcy5pc1N5bWJvbGljTGluaygpKSxcbiAgICApLnJlc29sdmVzLnRvQmUodHJ1ZSk7XG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgcmVhZEZpbGUoXG4gICAgICAgIHN0YWdlZChcbiAgICAgICAgICBcIm5vZGVfbW9kdWxlc1wiLFxuICAgICAgICAgIFwiLnBucG1cIixcbiAgICAgICAgICBcImRlcEAxLjAuMFwiLFxuICAgICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgICAgXCJAc2NvcGVcIixcbiAgICAgICAgICBcImhlbHBlcnNcIixcbiAgICAgICAgICBcImluZGV4LmpzXCIsXG4gICAgICAgICksXG4gICAgICAgIFwidXRmOFwiLFxuICAgICAgKSxcbiAgICApLnJlc29sdmVzLnRvQ29udGFpbihcImhlbHBlcnNcIik7XG4gIH0pO1xuXG4gIGl0KFwic3RhZ2VzIHRoZSBuZXh0IGNsb3N1cmUgdGhlIHJ1bnRpbWUncyBpbWFnZSBvcHRpbWl6ZXIgcmVxdWlyZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIC8vIGBuZXh0IGJ1aWxkYCB0cmFjZXMgd2hhdCB0aGUgKmFwcCogcmVhY2hlcywgYW5kIG5vIGFwcCByZWFjaGVzIG5leHQnc1xuICAgIC8vIGltYWdlIG9wdGltaXplciwgc28gd2l0aG91dCB0aGlzIGV2ZXJ5IC9fbmV4dC9pbWFnZSByZXF1ZXN0IDUwMHMgb24gYVxuICAgIC8vIE1PRFVMRV9OT1RfRk9VTkQgdGhhdCBub3RoaW5nIGluIHRoZSBidWlsZCB3YXJuZWQgYWJvdXQuXG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IG1ha2VSZXBvKHsgd2l0aE5leHQ6IHRydWUgfSk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgd3JpdGUoY3R4KTtcbiAgICBjb25zdCBzdGFnZWQgPSAoLi4ucGFydHM6IHN0cmluZ1tdKSA9PiBqb2luKHNvbGVSb290KHJlc3VsdCksIC4uLnBhcnRzKTtcblxuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIHJlYWRGaWxlKFxuICAgICAgICBzdGFnZWQoXCJub2RlX21vZHVsZXNcIiwgXCJuZXh0XCIsIFwiZGlzdFwiLCBcInNlcnZlclwiLCBcImltYWdlLW9wdGltaXplci5qc1wiKSxcbiAgICAgICAgXCJ1dGY4XCIsXG4gICAgICApLFxuICAgICkucmVzb2x2ZXMudG9Db250YWluKFwiaW1hZ2Utb3B0aW1pemVyXCIpO1xuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIHJlYWRGaWxlKFxuICAgICAgICBzdGFnZWQoXG4gICAgICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICAgICAgICBcIm5leHRcIixcbiAgICAgICAgICBcImRpc3RcIixcbiAgICAgICAgICBcInNoYXJlZFwiLFxuICAgICAgICAgIFwibGliXCIsXG4gICAgICAgICAgXCJtYXRjaC1yZW1vdGUtcGF0dGVybi5qc1wiLFxuICAgICAgICApLFxuICAgICAgICBcInV0ZjhcIixcbiAgICAgICksXG4gICAgKS5yZXNvbHZlcy50b0NvbnRhaW4oXCJtYXRjaC1yZW1vdGUtcGF0dGVyblwiKTtcbiAgfSk7XG5cbiAgaXQoXCJzdGFnZXMgdGhlIGxpbmsgbmV4dCByZXNvbHZlcyBAbmV4dC9lbnYgdGhyb3VnaCB1bmRlciBwbnBtXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBUaGUgdHJhY2Ugc3RhcnRzIGF0IGBAbmV4dC9lbnZgJ3MgcmVhbCBwYXRoIGFuZCBzbyBuZXZlciByZWNvcmRzIHRoZVxuICAgIC8vIGxpbmsgYmVzaWRlIGBuZXh0YDsgd2l0aG91dCBpdCBldmVyeSBjb2xkIHN0YXJ0IHRocmV3IFwiQ2Fubm90IGZpbmRcbiAgICAvLyBtb2R1bGUgJ0BuZXh0L2VudidcIi5cbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgbWFrZVJlcG8oeyBwbnBtTmV4dDogdHJ1ZSB9KTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB3cml0ZShjdHgpO1xuICAgIGNvbnN0IGxpbmsgPSBqb2luKFxuICAgICAgc29sZVJvb3QocmVzdWx0KSxcbiAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICBcIi5wbnBtXCIsXG4gICAgICBcIm5leHRAMS4wLjBcIixcbiAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICBcIkBuZXh0XCIsXG4gICAgICBcImVudlwiLFxuICAgICk7XG4gICAgZXhwZWN0KChhd2FpdCBsc3RhdChsaW5rKSkuaXNTeW1ib2xpY0xpbmsoKSkudG9CZSh0cnVlKTtcbiAgICBhd2FpdCBleHBlY3QocmVhZEZpbGUoam9pbihsaW5rLCBcImluZGV4LmpzXCIpLCBcInV0ZjhcIikpLnJlc29sdmVzLnRvQ29udGFpbihcbiAgICAgIFwiQG5leHQvZW52XCIsXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoXCJ3YXJucyBpbnN0ZWFkIG9mIGZhaWxpbmcgd2hlbiBuZXh0IGNhbm5vdCBiZSByZXNvbHZlZCBmb3IgdHJhY2luZ1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IG1ha2VSZXBvKCk7XG4gICAgY29uc3Qgd2FybiA9IGplc3Quc3B5T24oY29uc29sZSwgXCJ3YXJuXCIpLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiB7fSk7XG4gICAgYXdhaXQgZXhwZWN0KHdyaXRlKGN0eCkpLnJlc29sdmVzLnRvQmVEZWZpbmVkKCk7XG4gICAgZXhwZWN0KHdhcm4pLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgZXhwZWN0LnN0cmluZ0NvbnRhaW5pbmcoXCIvX25leHQvaW1hZ2Ugd2lsbCBmYWlsIGF0IHJ1bnRpbWVcIiksXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoXCJyZW1vdmVzIGEgcHJldmlvdXMgYnVpbGQncyB0cmVlIGJlZm9yZSBzdGFnaW5nXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgbWFrZVJlcG8oKTtcbiAgICBjb25zdCBmaXJzdCA9IGF3YWl0IHdyaXRlKGN0eCk7XG4gICAgY29uc3Qgc3RhbGUgPSBqb2luKHNvbGVSb290KGZpcnN0KSwgXCJhcHBcIiwgXCJzdGFsZS5qc1wiKTtcbiAgICBhd2FpdCB3cml0ZUZpbGUoc3RhbGUsIFwiLy8gcmVtb3ZlZCByb3V0ZVxcblwiKTtcblxuICAgIGF3YWl0IHdyaXRlKGN0eCk7XG4gICAgYXdhaXQgZXhwZWN0KGxzdGF0KHN0YWxlKSkucmVqZWN0cy50b1Rocm93KC9FTk9FTlQvKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoXCJ3aXRoIGZ1bmN0aW9uR3JvdXBzXCIsICgpID0+IHtcbiAgICAvKipcbiAgICAgKiBUd28gcm91dGVzIHdpdGggb25lIGFzc2V0IGVhY2gsIHNvIFwidGhlIGdyb3VwJ3MgdHJlZSBob2xkcyBpdHMgb3duIHJvdXRlXG4gICAgICogYW5kIG5vdCB0aGUgb3RoZXInc1wiIGlzIGNoZWNrYWJsZSBieSBmaWxlLiBEZWxpYmVyYXRlbHkgbm90IGBtYWtlUmVwb2Anc1xuICAgICAqIHJlcG86IGl0cyBzaW5nbGUgb3V0cHV0IGNhbm5vdCBiZSBzcGxpdC5cbiAgICAgKi9cbiAgICBhc3luYyBmdW5jdGlvbiBtYWtlU3BsaXR0YWJsZVJlcG8oXG4gICAgICBvcHRpb25zOiB7XG4gICAgICAgIHdpdGhOb3RGb3VuZD86IGJvb2xlYW47XG4gICAgICAgIHdpdGhQYWdlc1Nzcj86IGJvb2xlYW47XG4gICAgICAgIHdpdGhOZXh0PzogYm9vbGVhbjtcbiAgICAgIH0gPSB7fSxcbiAgICApIHtcbiAgICAgIGNvbnN0IHJlcG9Sb290ID0gYXdhaXQgbWtkdGVtcChqb2luKHRtcGRpcigpLCBcImNkay1uZXh0anMtZ3JvdXBzLVwiKSk7XG4gICAgICBpZiAob3B0aW9ucy53aXRoTmV4dCkge1xuICAgICAgICBhd2FpdCBpbnN0YWxsRmFrZU5leHQocmVwb1Jvb3QpO1xuICAgICAgfVxuICAgICAgY29uc3QgcHJvamVjdERpciA9IGpvaW4ocmVwb1Jvb3QsIFwiYXBwXCIpO1xuICAgICAgY29uc3QgZGlzdERpciA9IGpvaW4ocHJvamVjdERpciwgXCIubmV4dFwiKTtcbiAgICAgIGF3YWl0IG1rZGlyKGpvaW4oZGlzdERpciwgXCJzZXJ2ZXJcIiwgXCJhcHBcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgYXdhaXQgd3JpdGVGaWxlKGpvaW4oZGlzdERpciwgXCJyZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvblwiKSwgXCJ7fVxcblwiKTtcblxuICAgICAgY29uc3Qgb3V0cHV0Rm9yID0gYXN5bmMgKG5hbWU6IHN0cmluZywgcGF0aG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICBjb25zdCBlbnRyeSA9IGpvaW4oZGlzdERpciwgXCJzZXJ2ZXJcIiwgXCJhcHBcIiwgYCR7bmFtZX0uanNgKTtcbiAgICAgICAgY29uc3QgYXNzZXQgPSBqb2luKHByb2plY3REaXIsIFwibm9kZV9tb2R1bGVzXCIsIG5hbWUsIFwiaW5kZXguanNcIik7XG4gICAgICAgIGF3YWl0IG1rZGlyKGRpcm5hbWUoYXNzZXQpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgYXdhaXQgd3JpdGVGaWxlKGVudHJ5LCBgLy8gJHtuYW1lfVxcbmApO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoYXNzZXQsIGAvLyAke25hbWV9IGRlcFxcbmApO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGlkOiBwYXRobmFtZSxcbiAgICAgICAgICBwYXRobmFtZSxcbiAgICAgICAgICBzb3VyY2VQYWdlOiBwYXRobmFtZSxcbiAgICAgICAgICBmaWxlUGF0aDogZW50cnksXG4gICAgICAgICAgcnVudGltZTogXCJub2RlanNcIixcbiAgICAgICAgICBjb25maWc6IHt9LFxuICAgICAgICAgIGFzc2V0czogeyBbYGFwcC9ub2RlX21vZHVsZXMvJHtuYW1lfS9pbmRleC5qc2BdOiBhc3NldCB9LFxuICAgICAgICAgIGFzc2V0c0hhc2hlczoge30sXG4gICAgICAgIH07XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBjdHggPSB7XG4gICAgICAgIHJlcG9Sb290LFxuICAgICAgICBwcm9qZWN0RGlyLFxuICAgICAgICBkaXN0RGlyLFxuICAgICAgICBidWlsZElkOiBcInRlc3QtYnVpbGRcIixcbiAgICAgICAgbmV4dFZlcnNpb246IFwiMTYuMy41XCIsXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgIGJhc2VQYXRoOiBcIlwiLFxuICAgICAgICAgIHRyYWlsaW5nU2xhc2g6IGZhbHNlLFxuICAgICAgICAgIGFzc2V0UHJlZml4OiBcIlwiLFxuICAgICAgICAgIGkxOG46IG51bGwsXG4gICAgICAgIH0sXG4gICAgICAgIHJvdXRpbmc6IHsgZHluYW1pY1JvdXRlczogW10gfSxcbiAgICAgICAgb3V0cHV0czoge1xuICAgICAgICAgIHBhZ2VzOiBvcHRpb25zLndpdGhQYWdlc1NzclxuICAgICAgICAgICAgPyBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHBhZ2UgPSBhd2FpdCBvdXRwdXRGb3IoXCJzc3JcIiwgXCIvc3NyXCIpO1xuICAgICAgICAgICAgICAgIC8vIEEgc2VwYXJhdGUgb3V0cHV0LCB3aXRoIGl0cyBvd24gaWQsIGJhY2tlZCBieSB0aGUgc2FtZSBmaWxlLlxuICAgICAgICAgICAgICAgIGNvbnN0IGRhdGFSb3V0ZSA9IFwiL19uZXh0L2RhdGEvdGVzdC1idWlsZC9zc3IuanNvblwiO1xuICAgICAgICAgICAgICAgIHJldHVybiBbcGFnZSwgeyAuLi5wYWdlLCBpZDogZGF0YVJvdXRlLCBwYXRobmFtZTogZGF0YVJvdXRlIH1dO1xuICAgICAgICAgICAgICB9KSgpXG4gICAgICAgICAgICA6IFtdLFxuICAgICAgICAgIHBhZ2VzQXBpOiBbXSxcbiAgICAgICAgICBhcHBQYWdlczogW1xuICAgICAgICAgICAgYXdhaXQgb3V0cHV0Rm9yKFwiaG9tZVwiLCBcIi9cIiksXG4gICAgICAgICAgICAuLi4ob3B0aW9ucy53aXRoTm90Rm91bmRcbiAgICAgICAgICAgICAgPyBbYXdhaXQgb3V0cHV0Rm9yKFwibm90LWZvdW5kXCIsIFwiL19ub3QtZm91bmRcIildXG4gICAgICAgICAgICAgIDogW10pLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgYXBwUm91dGVzOiBbYXdhaXQgb3V0cHV0Rm9yKFwicmVwb3J0c1wiLCBcIi9hcGkvcmVwb3J0cy9baWRdXCIpXSxcbiAgICAgICAgICBwcmVyZW5kZXJzOiBbXSxcbiAgICAgICAgICBzdGF0aWNGaWxlczogW10sXG4gICAgICAgICAgbWlkZGxld2FyZTogdW5kZWZpbmVkLFxuICAgICAgICB9LFxuICAgICAgfSBhcyB1bmtub3duIGFzIEJ1aWxkQ29tcGxldGVDb250ZXh0O1xuICAgICAgcmV0dXJuIHsgY3R4IH07XG4gICAgfVxuXG4gICAgY29uc3QgZ3JvdXBzID0gW3sgbmFtZTogXCJyZXBvcnRzXCIsIHJvdXRlczogW1wiL2FwaS9yZXBvcnRzLyoqXCJdIH1dO1xuXG4gICAgaXQoXCJyZWNvcmRzIHRoZSBhc3NpZ25tZW50IGluIHRoZSBtYW5pZmVzdCBldmVyeSBncm91cCBzaGFyZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IG1ha2VTcGxpdHRhYmxlUmVwbygpO1xuICAgICAgY29uc3QgeyBtYW5pZmVzdCB9ID0gYnVpbGRBZGFwdGVyTWFuaWZlc3QoY3R4LCB7XG4gICAgICAgIGJ1aWxkQ3dkOiBjdHgucHJvamVjdERpcixcbiAgICAgICAgZnVuY3Rpb25Hcm91cHM6IGdyb3VwcyxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KG1hbmlmZXN0Lmdyb3VwcykudG9FcXVhbCh7XG4gICAgICAgIGRlZmF1bHQ6IFtcIi9cIl0sXG4gICAgICAgIHJlcG9ydHM6IFtcIi9hcGkvcmVwb3J0cy9baWRdXCJdLFxuICAgICAgfSk7XG4gICAgICAvLyBXaGF0IHN5bnRoIGNvbXBhcmVzIGl0cyBvd24gcHJvcHMgd2l0aCwgdG8gY2F0Y2ggYSBzdGFsZSBidWlsZC5cbiAgICAgIGV4cGVjdChtYW5pZmVzdC5mdW5jdGlvbkdyb3VwcykudG9FcXVhbChncm91cHMpO1xuICAgICAgLy8gQW5kIHdoYXQgaXQgZGVwbG95cywgYXMgdGhlIGFzc2lnbm1lbnQgY2hlY2tlZCBpdC5cbiAgICAgIGV4cGVjdChtYW5pZmVzdC5iZWhhdmlvcnMpLnRvRXF1YWwoW1xuICAgICAgICB7XG4gICAgICAgICAgZ3JvdXA6IFwicmVwb3J0c1wiLFxuICAgICAgICAgIHJvdXRlOiBcIi9hcGkvcmVwb3J0cy8qKlwiLFxuICAgICAgICAgIHBhdHRlcm46IFwiYXBpL3JlcG9ydHMvKlwiLFxuICAgICAgICB9LFxuICAgICAgXSk7XG4gICAgfSk7XG5cbiAgICBpdChcInN0YWdlcyBvbmUgdHJlZSBwZXIgZ3JvdXAsIGVhY2ggaG9sZGluZyBvbmx5IGl0cyBvd24gcm91dGVzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCBtYWtlU3BsaXR0YWJsZVJlcG8oKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdyaXRlQnVpbGRPdXRwdXRzKGN0eCwge1xuICAgICAgICBidWlsZEN3ZDogY3R4LnByb2plY3REaXIsXG4gICAgICAgIGZ1bmN0aW9uR3JvdXBzOiBncm91cHMsXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KHJlc3VsdC5zdGFnZWRHcm91cHMubWFwKChncm91cCkgPT4gZ3JvdXAubmFtZSkuc29ydCgpKS50b0VxdWFsKFtcbiAgICAgICAgXCJkZWZhdWx0XCIsXG4gICAgICAgIFwicmVwb3J0c1wiLFxuICAgICAgXSk7XG4gICAgICBjb25zdCBwYXRoT2YgPSAobmFtZTogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IGdyb3VwID0gcmVzdWx0LnN0YWdlZEdyb3Vwcy5maW5kKChpdCkgPT4gaXQubmFtZSA9PT0gbmFtZSk7XG4gICAgICAgIGlmICghZ3JvdXApIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHN0YWdlZCBncm91cCBcIiR7bmFtZX1cImApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBncm91cC5wYXRoO1xuICAgICAgfTtcbiAgICAgIC8vIFVuZGVyIGBncm91cHMvPG5hbWU+L2AsIHNvIG5laXRoZXIgY2FuIGNvbGxpZGUgd2l0aCB0aGUgdW5zcGxpdCBsYXlvdXQuXG4gICAgICBleHBlY3QocGF0aE9mKFwicmVwb3J0c1wiKSkudG9CZShcbiAgICAgICAgam9pbihjdHguZGlzdERpciwgXCJjZGstbmV4dGpzLWFkYXB0ZXJcIiwgXCJncm91cHNcIiwgXCJyZXBvcnRzXCIpLFxuICAgICAgKTtcbiAgICAgIGV4cGVjdChwYXRoT2YoXCJkZWZhdWx0XCIpKS50b0JlKFxuICAgICAgICBqb2luKGN0eC5kaXN0RGlyLCBcImNkay1uZXh0anMtYWRhcHRlclwiLCBcImdyb3Vwc1wiLCBcImRlZmF1bHRcIiksXG4gICAgICApO1xuXG4gICAgICBjb25zdCBoYXMgPSAobmFtZTogc3RyaW5nLCAuLi5wYXJ0czogc3RyaW5nW10pID0+XG4gICAgICAgIGxzdGF0KGpvaW4ocGF0aE9mKG5hbWUpLCAuLi5wYXJ0cykpLnRoZW4oXG4gICAgICAgICAgKCkgPT4gdHJ1ZSxcbiAgICAgICAgICAoKSA9PiBmYWxzZSxcbiAgICAgICAgKTtcbiAgICAgIGF3YWl0IGV4cGVjdChcbiAgICAgICAgaGFzKFwicmVwb3J0c1wiLCBcImFwcFwiLCBcIi5uZXh0XCIsIFwic2VydmVyXCIsIFwiYXBwXCIsIFwicmVwb3J0cy5qc1wiKSxcbiAgICAgICkucmVzb2x2ZXMudG9CZSh0cnVlKTtcbiAgICAgIGF3YWl0IGV4cGVjdChcbiAgICAgICAgaGFzKFwicmVwb3J0c1wiLCBcImFwcFwiLCBcIm5vZGVfbW9kdWxlc1wiLCBcInJlcG9ydHNcIiwgXCJpbmRleC5qc1wiKSxcbiAgICAgICkucmVzb2x2ZXMudG9CZSh0cnVlKTtcbiAgICAgIC8vIFRoZSBwb2ludCBvZiBzcGxpdHRpbmc6IHRoZSBvdGhlciBncm91cCdzIHJvdXRlIGlzIGFic2VudC5cbiAgICAgIGF3YWl0IGV4cGVjdChcbiAgICAgICAgaGFzKFwicmVwb3J0c1wiLCBcImFwcFwiLCBcIi5uZXh0XCIsIFwic2VydmVyXCIsIFwiYXBwXCIsIFwiaG9tZS5qc1wiKSxcbiAgICAgICkucmVzb2x2ZXMudG9CZShmYWxzZSk7XG4gICAgICBhd2FpdCBleHBlY3QoXG4gICAgICAgIGhhcyhcImRlZmF1bHRcIiwgXCJhcHBcIiwgXCIubmV4dFwiLCBcInNlcnZlclwiLCBcImFwcFwiLCBcImhvbWUuanNcIiksXG4gICAgICApLnJlc29sdmVzLnRvQmUodHJ1ZSk7XG4gICAgICBhd2FpdCBleHBlY3QoXG4gICAgICAgIGhhcyhcImRlZmF1bHRcIiwgXCJhcHBcIiwgXCIubmV4dFwiLCBcInNlcnZlclwiLCBcImFwcFwiLCBcInJlcG9ydHMuanNcIiksXG4gICAgICApLnJlc29sdmVzLnRvQmUoZmFsc2UpO1xuICAgICAgLy8gVGhlIG1hbmlmZXN0IGlzIHdyaXR0ZW4gb25jZSwgYWJvdmUgdGhlIGdyb3VwczsgYE5leHRqc0J1aWxkYCBjb3BpZXMgaXRcbiAgICAgIC8vIGFuZCB0aGUgcnVudGltZSBzaGVsbCBpbnRvIGVhY2ggZ3JvdXAncyByZXNlcnZlZCBydW50aW1lIGRpciBhZnRlcndhcmRzLFxuICAgICAgLy8gc28gbm8gZ3JvdXAncyBzdGFnZWQgdHJlZSBtYXkgY29udGFpbiB0aGF0IGRpcmVjdG9yeSB5ZXQuXG4gICAgICBleHBlY3QocmVzdWx0Lm1hbmlmZXN0UGF0aCkudG9CZShcbiAgICAgICAgam9pbihjdHguZGlzdERpciwgXCJjZGstbmV4dGpzLWFkYXB0ZXJcIiwgXCJtYW5pZmVzdC5qc29uXCIpLFxuICAgICAgKTtcbiAgICAgIGZvciAoY29uc3QgbmFtZSBvZiBbXCJkZWZhdWx0XCIsIFwicmVwb3J0c1wiXSkge1xuICAgICAgICBhd2FpdCBleHBlY3QoaGFzKG5hbWUsIFJVTlRJTUVfRElSX05BTUUpKS5yZXNvbHZlcy50b0JlKGZhbHNlKTtcbiAgICAgIH1cbiAgICAgIC8vIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAgaXMgbm90IGFueSBvdXRwdXQncyB0cmFjZWQgYXNzZXQsIHNvIGFcbiAgICAgIC8vIGdyb3VwIHRoYXQgcmVhY2hlcyBpdCBvbmx5IHRocm91Z2ggdGhlIG91dHB1dHMgaXQgb3ducyBkb2VzIG5vdCBnZXQgaXQgLVxuICAgICAgLy8gYW5kIGBsb2FkUnVudGltZWAgcHJvYmVzIGZvciBpdCBiZWZvcmUgc2VydmluZyBhbnl0aGluZywgc28gdGhlIHdob2xlXG4gICAgICAvLyByb290IGFuc3dlcnMgXCJ0aGUgZGVwbG95bWVudCBwYWNrYWdlIGlzIGluY29tcGxldGVcIiB3aXRob3V0IGl0LlxuICAgICAgZm9yIChjb25zdCBuYW1lIG9mIFtcImRlZmF1bHRcIiwgXCJyZXBvcnRzXCJdKSB7XG4gICAgICAgIGF3YWl0IGV4cGVjdChcbiAgICAgICAgICBoYXMobmFtZSwgXCJhcHBcIiwgXCIubmV4dFwiLCBcInJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uXCIpLFxuICAgICAgICApLnJlc29sdmVzLnRvQmUodHJ1ZSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpdChcInN0YWdlcyB0aGUgaW1hZ2Ugb3B0aW1pemVyIGludG8gZGVmYXVsdCBvbmx5LCBzZXJ2ZS1zdGF0aWMgaW50byBldmVyeSBncm91cFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBPbmx5IGBkZWZhdWx0YCBhbnN3ZXJzIGAvX25leHQvaW1hZ2VgLCBhbmQgdGhlIG9wdGltaXplciBpcyB3aGF0IHB1bGxzXG4gICAgICAvLyBgc2hhcnBgIGluOyBwcmVyZW5kZXJlZCBhbmQgc3RhdGljIHJlc3VsdHMgYXJlIHNlcnZlZCB3aXRoXG4gICAgICAvLyBgc2VydmUtc3RhdGljYCBpbiB3aGljaGV2ZXIgZ3JvdXAgdGhleSBsYW5kLlxuICAgICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IG1ha2VTcGxpdHRhYmxlUmVwbyh7IHdpdGhOZXh0OiB0cnVlIH0pO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgd3JpdGVCdWlsZE91dHB1dHMoY3R4LCB7XG4gICAgICAgIGJ1aWxkQ3dkOiBjdHgucHJvamVjdERpcixcbiAgICAgICAgZnVuY3Rpb25Hcm91cHM6IGdyb3VwcyxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgaGFzID0gKG5hbWU6IHN0cmluZywgZmlsZTogc3RyaW5nKSA9PlxuICAgICAgICBsc3RhdChcbiAgICAgICAgICBqb2luKFxuICAgICAgICAgICAgcmVzdWx0LnN0YWdlZEdyb3Vwcy5maW5kKChpdCkgPT4gaXQubmFtZSA9PT0gbmFtZSkhLnBhdGgsXG4gICAgICAgICAgICBcIm5vZGVfbW9kdWxlc1wiLFxuICAgICAgICAgICAgXCJuZXh0XCIsXG4gICAgICAgICAgICBcImRpc3RcIixcbiAgICAgICAgICAgIGZpbGUsXG4gICAgICAgICAgKSxcbiAgICAgICAgKS50aGVuKFxuICAgICAgICAgICgpID0+IHRydWUsXG4gICAgICAgICAgKCkgPT4gZmFsc2UsXG4gICAgICAgICk7XG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgW1xuICAgICAgICBcInNlcnZlci9pbWFnZS1vcHRpbWl6ZXIuanNcIixcbiAgICAgICAgXCJzaGFyZWQvbGliL2ltYWdlLWNvbmZpZy5qc1wiLFxuICAgICAgICBcInNlcnZlci9jb25maWctc2hhcmVkLmpzXCIsXG4gICAgICAgIFwic2hhcmVkL2xpYi9tYXRjaC1yZW1vdGUtcGF0dGVybi5qc1wiLFxuICAgICAgXSkge1xuICAgICAgICBhd2FpdCBleHBlY3QoaGFzKFwiZGVmYXVsdFwiLCBmaWxlKSkucmVzb2x2ZXMudG9CZSh0cnVlKTtcbiAgICAgICAgYXdhaXQgZXhwZWN0KGhhcyhcInJlcG9ydHNcIiwgZmlsZSkpLnJlc29sdmVzLnRvQmUoZmFsc2UpO1xuICAgICAgfVxuICAgICAgZm9yIChjb25zdCBuYW1lIG9mIFtcImRlZmF1bHRcIiwgXCJyZXBvcnRzXCJdKSB7XG4gICAgICAgIGF3YWl0IGV4cGVjdChoYXMobmFtZSwgXCJzZXJ2ZXIvc2VydmUtc3RhdGljLmpzXCIpKS5yZXNvbHZlcy50b0JlKHRydWUpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaXQoXCJzdGFnZXMgdGhlIG5vdC1mb3VuZCBwYWdlIGludG8gZXZlcnkgZ3JvdXAsIG5vdCBvbmx5IGl0cyBvd25lclwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBUaGUgcnVudGltZSByZW5kZXJzIGEgNDA0IHdpdGggdGhlIG1hbmlmZXN0J3MgYC9fbm90LWZvdW5kYCB3aGVyZXZlciB0aGVcbiAgICAgIC8vIHJlcXVlc3QgbGFuZGVkLCBzbyBgL2FwaS9yZXBvcnRzL25vcGVgIG5lZWRzIGl0IGluIHRoZSByZXBvcnRzIGdyb3VwLlxuICAgICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IG1ha2VTcGxpdHRhYmxlUmVwbyh7IHdpdGhOb3RGb3VuZDogdHJ1ZSB9KTtcbiAgICAgIGNvbnN0IHsgZ3JvdXBzOiBzdGFnZWQsIG1hbmlmZXN0IH0gPSBidWlsZEFkYXB0ZXJNYW5pZmVzdChjdHgsIHtcbiAgICAgICAgYnVpbGRDd2Q6IGN0eC5wcm9qZWN0RGlyLFxuICAgICAgICBmdW5jdGlvbkdyb3VwczogZ3JvdXBzLFxuICAgICAgfSk7XG4gICAgICBleHBlY3QobWFuaWZlc3QuZ3JvdXBzPy5kZWZhdWx0KS50b0NvbnRhaW4oXCIvX25vdC1mb3VuZFwiKTtcbiAgICAgIGV4cGVjdChzdGFnZWQubWFwKChncm91cCkgPT4gZ3JvdXAubmFtZSkuc29ydCgpKS50b0VxdWFsKFtcbiAgICAgICAgXCJkZWZhdWx0XCIsXG4gICAgICAgIFwicmVwb3J0c1wiLFxuICAgICAgXSk7XG4gICAgICBmb3IgKGNvbnN0IGdyb3VwIG9mIHN0YWdlZCkge1xuICAgICAgICBleHBlY3QoWy4uLmdyb3VwLnN0YWdpbmcua2V5cygpXSkudG9Db250YWluKFxuICAgICAgICAgIFwiYXBwLy5uZXh0L3NlcnZlci9hcHAvbm90LWZvdW5kLmpzXCIsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpdChcImtlZXBzIGEgUGFnZXMgUm91dGVyIHBhZ2UncyBkYXRhIHJvdXRlIGluIHRoZSBwYWdlJ3MgZ3JvdXBcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IG1ha2VTcGxpdHRhYmxlUmVwbyh7IHdpdGhQYWdlc1NzcjogdHJ1ZSB9KTtcbiAgICAgIGNvbnN0IHsgZ3JvdXBzOiBzdGFnZWQsIG1hbmlmZXN0IH0gPSBidWlsZEFkYXB0ZXJNYW5pZmVzdChjdHgsIHtcbiAgICAgICAgYnVpbGRDd2Q6IGN0eC5wcm9qZWN0RGlyLFxuICAgICAgICBmdW5jdGlvbkdyb3VwczogW3sgbmFtZTogXCJzc3JcIiwgcm91dGVzOiBbXCIvc3NyXCJdIH1dLFxuICAgICAgfSk7XG4gICAgICBleHBlY3QobWFuaWZlc3QuZ3JvdXBzPy5zc3IpLnRvRXF1YWwoW1xuICAgICAgICBcIi9fbmV4dC9kYXRhL3Rlc3QtYnVpbGQvc3NyLmpzb25cIixcbiAgICAgICAgXCIvc3NyXCIsXG4gICAgICBdKTtcbiAgICAgIGNvbnN0IGRlZmF1bHRHcm91cCA9IHN0YWdlZC5maW5kKChncm91cCkgPT4gZ3JvdXAubmFtZSA9PT0gXCJkZWZhdWx0XCIpITtcbiAgICAgIC8vIE90aGVyd2lzZSB0aGUgcGFnZSBhbmQgaXRzIHRyYWNlIHNoaXAgaW4gdGhlIGRlZmF1bHQgemlwIGFzIHdlbGwuXG4gICAgICBleHBlY3QoWy4uLmRlZmF1bHRHcm91cC5zdGFnaW5nLmtleXMoKV0pLm5vdC50b0NvbnRhaW4oXG4gICAgICAgIFwiYXBwLy5uZXh0L3NlcnZlci9hcHAvc3NyLmpzXCIsXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoXCJyZWZ1c2VzIHRvIHNwbGl0IGFuIGkxOG4gYXBwLCB3aG9zZSByb3V0ZXMgYXJlIGxvY2FsZS1wcmVmaXhlZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgbWFrZVNwbGl0dGFibGVSZXBvKCk7XG4gICAgICBjb25zdCBpMThuQ3R4ID0ge1xuICAgICAgICAuLi5jdHgsXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgIC4uLmN0eC5jb25maWcsXG4gICAgICAgICAgaTE4bjogeyBsb2NhbGVzOiBbXCJlblwiXSwgZGVmYXVsdExvY2FsZTogXCJlblwiIH0sXG4gICAgICAgIH0sXG4gICAgICB9IGFzIHVua25vd24gYXMgQnVpbGRDb21wbGV0ZUNvbnRleHQ7XG4gICAgICBleHBlY3QoKCkgPT5cbiAgICAgICAgYnVpbGRBZGFwdGVyTWFuaWZlc3QoaTE4bkN0eCwge1xuICAgICAgICAgIGJ1aWxkQ3dkOiBjdHgucHJvamVjdERpcixcbiAgICAgICAgICBmdW5jdGlvbkdyb3VwczogZ3JvdXBzLFxuICAgICAgICB9KSxcbiAgICAgICkudG9UaHJvdygvY2Fubm90IGJlIGNvbWJpbmVkIHdpdGggYGkxOG5gLyk7XG4gICAgfSk7XG5cbiAgICBpdChcInRocm93cyBvbiBhIHBhdHRlcm4gdGhhdCBtYXRjaGVzIG5vdGhpbmcsIHJhdGhlciB0aGFuIHNpbGVudGx5IG5vdCBzcGxpdHRpbmdcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IG1ha2VTcGxpdHRhYmxlUmVwbygpO1xuICAgICAgZXhwZWN0KCgpID0+XG4gICAgICAgIGJ1aWxkQWRhcHRlck1hbmlmZXN0KGN0eCwge1xuICAgICAgICAgIGJ1aWxkQ3dkOiBjdHgucHJvamVjdERpcixcbiAgICAgICAgICBmdW5jdGlvbkdyb3VwczogW3sgbmFtZTogXCJ0eXBvXCIsIHJvdXRlczogW1wiL2FwaS9yZXBvcnQvKipcIl0gfV0sXG4gICAgICAgIH0pLFxuICAgICAgKS50b1Rocm93KC9tYXRjaGVzIG5vIHJvdXRlIGluIHRoaXMgYnVpbGQvKTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==
|