cdk-nextjs 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1551 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +857 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +863 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +13 -5
- package/lib/nextjs-post-deploy.js +13 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1216 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1686 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41600 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +71 -0
- package/lib/runtime/next-modules.js +144 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41593 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
|
@@ -0,0 +1,853 @@
|
|
|
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
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_os_1 = require("node:os");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const dispatch_1 = require("./dispatch");
|
|
11
|
+
const public_files_1 = require("./public-files");
|
|
12
|
+
const app_playground_base_path_json_1 = __importDefault(require("../adapter/__fixtures__/app-playground-base-path.json"));
|
|
13
|
+
const app_playground_json_1 = __importDefault(require("../adapter/__fixtures__/app-playground.json"));
|
|
14
|
+
const pages_i18n_json_1 = __importDefault(require("../adapter/__fixtures__/pages-i18n.json"));
|
|
15
|
+
const build_outputs_1 = require("../adapter/build-outputs");
|
|
16
|
+
/**
|
|
17
|
+
* Dispatch is tested against the manifests that step 1 produces from real
|
|
18
|
+
* `onBuildComplete` captures, rather than against hand-written manifests: the
|
|
19
|
+
* thing most likely to break is the correspondence between how the build keys
|
|
20
|
+
* `entrypoints` and how `resolveRoutes` reports `resolvedPathname`, and a
|
|
21
|
+
* hand-written manifest would assume that correspondence instead of proving it.
|
|
22
|
+
*/
|
|
23
|
+
function manifestOf(fixture) {
|
|
24
|
+
const warn = jest.spyOn(console, "warn").mockImplementation(() => { });
|
|
25
|
+
try {
|
|
26
|
+
const ctx = structuredClone(fixture);
|
|
27
|
+
// The fixtures' project dirs are synthetic `/repo/…` paths, so the build cwd
|
|
28
|
+
// has to be stated; see `assertBuildCwd`.
|
|
29
|
+
return (0, build_outputs_1.buildAdapterManifest)(ctx, { buildCwd: ctx.projectDir }).manifest;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
warn.mockRestore();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The fixture with `app/params/optional/[[...rest]]` moved to `app/[[...rest]]`,
|
|
37
|
+
* a root optional catch-all: a route every request not claimed earlier falls
|
|
38
|
+
* into, `/_next/image` included unless dispatch puts it ahead of them. No example
|
|
39
|
+
* app has one, and a capture would add a whole app to cover one route, so the
|
|
40
|
+
* route is moved rather than captured.
|
|
41
|
+
*/
|
|
42
|
+
function withRootCatchAll(fixture) {
|
|
43
|
+
return JSON.parse(JSON.stringify(fixture)
|
|
44
|
+
.split("/params/optional/[[...rest]]")
|
|
45
|
+
.join("/[[...rest]]")
|
|
46
|
+
.split("[/]?/params/optional(?:")
|
|
47
|
+
.join("[/]?(?:"));
|
|
48
|
+
}
|
|
49
|
+
const manifests = {
|
|
50
|
+
"app-playground": manifestOf(app_playground_json_1.default),
|
|
51
|
+
"app-playground-base-path": manifestOf(app_playground_base_path_json_1.default),
|
|
52
|
+
"app-playground-root-catch-all": manifestOf(withRootCatchAll(app_playground_json_1.default)),
|
|
53
|
+
"app-playground-base-path-root-catch-all": manifestOf(withRootCatchAll(app_playground_base_path_json_1.default)),
|
|
54
|
+
"pages-i18n": manifestOf(pages_i18n_json_1.default),
|
|
55
|
+
};
|
|
56
|
+
const ORIGIN = "https://example.test";
|
|
57
|
+
function request(url, headers = {}) {
|
|
58
|
+
const result = {
|
|
59
|
+
method: "GET",
|
|
60
|
+
url: new URL(url, ORIGIN),
|
|
61
|
+
headers: new Headers({ host: "example.test", ...headers }),
|
|
62
|
+
// GET/HEAD have no body, but `resolveRoutes` requires a stream.
|
|
63
|
+
body: new ReadableStream({
|
|
64
|
+
start(controller) {
|
|
65
|
+
controller.close();
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
// Middleware that lets every request through.
|
|
69
|
+
invokeMiddleware: async () => ({ response: new Response() }),
|
|
70
|
+
};
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
/** A Dispatcher over `name`, whose middleware, if given, answers `middleware()`. */
|
|
74
|
+
function dispatcherFor(name, middleware) {
|
|
75
|
+
const dispatcher = new dispatch_1.Dispatcher({ manifest: manifests[name] });
|
|
76
|
+
return {
|
|
77
|
+
notFoundFor: dispatcher.notFoundFor,
|
|
78
|
+
dispatch: (req) => dispatcher.dispatch(middleware
|
|
79
|
+
? {
|
|
80
|
+
...req,
|
|
81
|
+
invokeMiddleware: async () => ({
|
|
82
|
+
...(await middleware()),
|
|
83
|
+
response: new Response(),
|
|
84
|
+
}),
|
|
85
|
+
}
|
|
86
|
+
: req),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** The 404 or 500 a request with no locale gets. */
|
|
90
|
+
function statusTargetOf(manifest, status) {
|
|
91
|
+
return (0, dispatch_1.statusTargets)(manifest, status)(undefined);
|
|
92
|
+
}
|
|
93
|
+
describe("Dispatcher entrypoint resolution", () => {
|
|
94
|
+
it("resolves a dynamic App Router page to its template entrypoint", async () => {
|
|
95
|
+
const result = await dispatcherFor("app-playground").dispatch(request("/isr/1"));
|
|
96
|
+
expect(result.kind).toBe("entrypoint");
|
|
97
|
+
if (result.kind !== "entrypoint")
|
|
98
|
+
return;
|
|
99
|
+
// `resolvedPathname` is the template; `invocationTarget` is concrete. Both
|
|
100
|
+
// are needed: the first picks the module, the second is what it renders.
|
|
101
|
+
expect(result.resolvedPathname).toBe("/isr/[id]");
|
|
102
|
+
expect(result.invocationTarget).toEqual({
|
|
103
|
+
pathname: "/isr/1",
|
|
104
|
+
query: { nxtPid: "1" },
|
|
105
|
+
});
|
|
106
|
+
expect(result.entrypoint.filePath).toContain("isr/[id]/page.js");
|
|
107
|
+
expect(result.entrypoint.type).toBe("app-page");
|
|
108
|
+
});
|
|
109
|
+
it("resolves an App Router route handler", async () => {
|
|
110
|
+
const result = await dispatcherFor("app-playground").dispatch(request("/api/health"));
|
|
111
|
+
expect(result.kind).toBe("entrypoint");
|
|
112
|
+
if (result.kind !== "entrypoint")
|
|
113
|
+
return;
|
|
114
|
+
expect(result.entrypoint.type).toBe("app-route");
|
|
115
|
+
expect(result.resolvedPathname).toBe("/api/health");
|
|
116
|
+
});
|
|
117
|
+
it("matches basePath-prefixed entrypoint keys without normalization", async () => {
|
|
118
|
+
// Step 1 keyed `entrypoints` by the basePath-prefixed `output.pathname` and
|
|
119
|
+
// left open whether `resolvedPathname` comes back prefixed. It does — this
|
|
120
|
+
// test is what closes that question.
|
|
121
|
+
const dispatcher = dispatcherFor("app-playground-base-path");
|
|
122
|
+
const result = await dispatcher.dispatch(request("/prod/isr/1"));
|
|
123
|
+
expect(result.kind).toBe("entrypoint");
|
|
124
|
+
if (result.kind !== "entrypoint")
|
|
125
|
+
return;
|
|
126
|
+
expect(result.resolvedPathname).toBe("/prod/isr/[id]");
|
|
127
|
+
expect(result.invocationTarget.pathname).toBe("/prod/isr/1");
|
|
128
|
+
// The same path without the prefix is not the app's.
|
|
129
|
+
const unprefixed = await dispatcher.dispatch(request("/isr/1"));
|
|
130
|
+
expect(unprefixed.kind).toBe("not-found");
|
|
131
|
+
});
|
|
132
|
+
it("resolves a Pages Router page and API route", async () => {
|
|
133
|
+
const dispatcher = dispatcherFor("pages-i18n");
|
|
134
|
+
const page = await dispatcher.dispatch(request("/en-US/ssr"));
|
|
135
|
+
expect(page.kind).toBe("entrypoint");
|
|
136
|
+
if (page.kind === "entrypoint") {
|
|
137
|
+
expect(page.entrypoint.type).toBe("page");
|
|
138
|
+
}
|
|
139
|
+
const api = await dispatcher.dispatch(request("/api/hello"));
|
|
140
|
+
expect(api.kind).toBe("entrypoint");
|
|
141
|
+
if (api.kind === "entrypoint") {
|
|
142
|
+
expect(api.entrypoint.type).toBe("page-api");
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
it("resolves a Pages Router ISR data URL via its prerender template", async () => {
|
|
146
|
+
// This only works because `buildAdapterManifest` adds dynamic *prerender*
|
|
147
|
+
// templates to `pathnames`/`entrypoints`: `/_next/data/…/[slug].json` is
|
|
148
|
+
// not a route output, so without it this URL 404s while `next start` serves
|
|
149
|
+
// it.
|
|
150
|
+
const { buildId } = manifests["pages-i18n"];
|
|
151
|
+
const result = await dispatcherFor("pages-i18n").dispatch(request(`/_next/data/${buildId}/fr/blog/hello.json`));
|
|
152
|
+
expect(result.kind).toBe("entrypoint");
|
|
153
|
+
if (result.kind !== "entrypoint")
|
|
154
|
+
return;
|
|
155
|
+
expect(result.resolvedPathname).toBe(`/_next/data/${buildId}/fr/blog/[slug].json`);
|
|
156
|
+
expect(result.entrypoint.filePath).toContain("blog/[slug]");
|
|
157
|
+
expect(result.invocationTarget.query).toMatchObject({ nxtPslug: "hello" });
|
|
158
|
+
});
|
|
159
|
+
it("resolves the canonical trailing-slash URL of a `trailingSlash` app", async () => {
|
|
160
|
+
// The build's pathnames never carry the slash, but `trailingSlash: true`
|
|
161
|
+
// makes `/a/` the URL Next.js's own 308 sends browsers to, and
|
|
162
|
+
// `@next/routing` matches pathnames by exact equality. Measured against
|
|
163
|
+
// next.js's `test/e2e/app-dir/trailingslash`: without this, 6 of 8 cases
|
|
164
|
+
// failed, including `fetch('/api/revalidate')` getting the 404 page.
|
|
165
|
+
const withSlash = structuredClone(app_playground_json_1.default);
|
|
166
|
+
withSlash.config.trailingSlash = true;
|
|
167
|
+
// All three captures are from apps with the default `trailingSlash: false`,
|
|
168
|
+
// so their `beforeMiddleware` carries the *strip*-slash 308 (`/a/` → `/a`).
|
|
169
|
+
// Leaving it in would make the clone incoherent — that redirect is what a
|
|
170
|
+
// real `trailingSlash: true` build replaces with the add-slash one — and it
|
|
171
|
+
// fires before any pathname is matched, so nothing below would be reached.
|
|
172
|
+
const routing = withSlash.routing;
|
|
173
|
+
routing.beforeMiddleware = routing.beforeMiddleware.filter((route) => route.status !== 308);
|
|
174
|
+
const dispatcher = new dispatch_1.Dispatcher({
|
|
175
|
+
manifest: manifestOf(withSlash),
|
|
176
|
+
});
|
|
177
|
+
const page = await dispatcher.dispatch(request("/isr/1/"));
|
|
178
|
+
expect(page.kind).toBe("entrypoint");
|
|
179
|
+
if (page.kind !== "entrypoint")
|
|
180
|
+
return;
|
|
181
|
+
// Normalized on the way out, because `entrypoints` is keyed without the
|
|
182
|
+
// slash and the render has to land on its prerender's cache key.
|
|
183
|
+
expect(page.resolvedPathname).toBe("/isr/[id]");
|
|
184
|
+
expect(page.invocationTarget).toEqual({
|
|
185
|
+
pathname: "/isr/1",
|
|
186
|
+
query: { nxtPid: "1" },
|
|
187
|
+
});
|
|
188
|
+
const route = await dispatcher.dispatch(request("/api/health/"));
|
|
189
|
+
expect(route.kind).toBe("entrypoint");
|
|
190
|
+
if (route.kind === "entrypoint") {
|
|
191
|
+
expect(route.resolvedPathname).toBe("/api/health");
|
|
192
|
+
}
|
|
193
|
+
// A static file keeps its extension-bearing pathname: Next.js compiles the
|
|
194
|
+
// *opposite* redirect for those, and shadowing it would serve `/x.js/`.
|
|
195
|
+
const asset = await dispatcher.dispatch(request("/favicon.ico"));
|
|
196
|
+
expect(asset.kind).toBe("static-file");
|
|
197
|
+
expect(await dispatcher.dispatch(request("/favicon.ico/"))).toMatchObject({
|
|
198
|
+
kind: "not-found",
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
it("gives a param whose name prefixes another param's its own value", async () => {
|
|
202
|
+
// `@next/routing` expands `$nxtPid2` by replacing group names in insertion
|
|
203
|
+
// order, so the `$nxtPid` prefix wins and leaves a literal `2`: the route is
|
|
204
|
+
// invoked with `nxtPid2=a2`. `repairRouteParamQuery` corrects it from
|
|
205
|
+
// `routeMatches`. Measured against `test/e2e/app-dir/use-params`, whose
|
|
206
|
+
// fixture is `app/[id]/[id2]/page.tsx`; app-playground's
|
|
207
|
+
// `app/params/prefix/[id]/[id2]` is the same shape.
|
|
208
|
+
const result = await dispatcherFor("app-playground").dispatch(request("/params/prefix/a/b"));
|
|
209
|
+
expect(result.kind).toBe("entrypoint");
|
|
210
|
+
if (result.kind !== "entrypoint")
|
|
211
|
+
return;
|
|
212
|
+
expect(result.resolvedPathname).toBe("/params/prefix/[id]/[id2]");
|
|
213
|
+
expect(result.invocationTarget).toEqual({
|
|
214
|
+
pathname: "/params/prefix/a/b",
|
|
215
|
+
query: { nxtPid: "a", nxtPid2: "b" },
|
|
216
|
+
});
|
|
217
|
+
expect(result.invocationTarget.query).toEqual({
|
|
218
|
+
nxtPid: "a",
|
|
219
|
+
nxtPid2: "b",
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
it("applies a gated beforeFiles rewrite from next.config.ts once", async () => {
|
|
223
|
+
// app-playground's one config rewrite: `/e2e/rewrite/:path(.*)` with
|
|
224
|
+
// `has: query json=true`, to `/e2e/rewrite/echo?from=/:path`. Its output
|
|
225
|
+
// matches it again, which is what Next.js re-applies inside the entrypoint
|
|
226
|
+
// - the Dispatcher's half is resolving it exactly once.
|
|
227
|
+
const dispatcher = dispatcherFor("app-playground");
|
|
228
|
+
const rewritten = await dispatcher.dispatch(request("/e2e/rewrite/some/route?json=true"));
|
|
229
|
+
expect(rewritten.kind).toBe("entrypoint");
|
|
230
|
+
if (rewritten.kind !== "entrypoint")
|
|
231
|
+
return;
|
|
232
|
+
expect(rewritten.resolvedPathname).toBe("/e2e/rewrite/echo");
|
|
233
|
+
expect(rewritten.invocationTarget.query).toMatchObject({
|
|
234
|
+
from: "/some/route",
|
|
235
|
+
json: "true",
|
|
236
|
+
});
|
|
237
|
+
// Without the `has` condition the rule does not fire and nothing else
|
|
238
|
+
// serves the path.
|
|
239
|
+
expect(await dispatcher.dispatch(request("/e2e/rewrite/some/route"))).toMatchObject({ kind: "not-found" });
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
describe("Dispatcher public/ files", () => {
|
|
243
|
+
/**
|
|
244
|
+
* A real `public/` on disk, listed by the same `readPublicFiles` the runtime
|
|
245
|
+
* calls at cold start, so the spellings under test are the ones the lister
|
|
246
|
+
* and the routing table actually produce between them.
|
|
247
|
+
*/
|
|
248
|
+
function publicDir(files) {
|
|
249
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "cdk-nextjs-dispatch-public-"));
|
|
250
|
+
for (const file of files) {
|
|
251
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)((0, node_path_1.join)(dir, file)), { recursive: true });
|
|
252
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, file), file);
|
|
253
|
+
}
|
|
254
|
+
return (0, public_files_1.readPublicFiles)(dir);
|
|
255
|
+
}
|
|
256
|
+
function dispatcherWithPublic(name, files) {
|
|
257
|
+
return new dispatch_1.Dispatcher({
|
|
258
|
+
manifest: manifests[name],
|
|
259
|
+
publicFiles: publicDir(files),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
it.each([
|
|
263
|
+
// A space is encoded by every client, so the two spellings agree.
|
|
264
|
+
["static/hello e2e.png", ["/static/hello%20e2e.png"]],
|
|
265
|
+
// These a browser sends as written, and `encodeURIComponent` does not.
|
|
266
|
+
["images/logo@2x.png", ["/images/logo@2x.png", "/images/logo%402x.png"]],
|
|
267
|
+
["c++.svg", ["/c++.svg", "/c%2B%2B.svg"]],
|
|
268
|
+
["icon[1].png", ["/icon[1].png", "/icon%5B1%5D.png"]],
|
|
269
|
+
["Q&A.pdf", ["/Q&A.pdf", "/Q%26A.pdf"]],
|
|
270
|
+
// A literal `%` can only be requested escaped.
|
|
271
|
+
["100%.png", ["/100%25.png"]],
|
|
272
|
+
["фото/a.jpg", ["/%D1%84%D0%BE%D1%82%D0%BE/a.jpg"]],
|
|
273
|
+
])("serves public/%s under every spelling a link can have", async (file, urls) => {
|
|
274
|
+
const dispatcher = dispatcherWithPublic("app-playground", [file]);
|
|
275
|
+
for (const url of urls) {
|
|
276
|
+
expect(await dispatcher.dispatch(request(url))).toMatchObject({
|
|
277
|
+
kind: "static-file",
|
|
278
|
+
source: "public",
|
|
279
|
+
filePath: `app-playground/public/${file}`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
it("serves public/ ahead of an app route at the same pathname", async () => {
|
|
284
|
+
// `app/favicon.ico` is a build output here; `next start` checks public/
|
|
285
|
+
// before app and page routes, so a leftover `public/favicon.ico` wins.
|
|
286
|
+
const result = await dispatcherWithPublic("app-playground", [
|
|
287
|
+
"favicon.ico",
|
|
288
|
+
]).dispatch(request("/favicon.ico"));
|
|
289
|
+
expect(result).toMatchObject({
|
|
290
|
+
kind: "static-file",
|
|
291
|
+
filePath: "app-playground/public/favicon.ico",
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
it("still serves the build output when public/ has no file there", async () => {
|
|
295
|
+
const result = await dispatcherWithPublic("app-playground", []).dispatch(request("/favicon.ico"));
|
|
296
|
+
expect(result).toMatchObject({ kind: "static-file", source: "server" });
|
|
297
|
+
});
|
|
298
|
+
it("serves public/ under basePath", async () => {
|
|
299
|
+
const dispatcher = dispatcherWithPublic("app-playground-base-path", [
|
|
300
|
+
"test.txt",
|
|
301
|
+
]);
|
|
302
|
+
expect(await dispatcher.dispatch(request("/prod/test.txt"))).toMatchObject({
|
|
303
|
+
kind: "static-file",
|
|
304
|
+
filePath: "app-playground/public/test.txt",
|
|
305
|
+
});
|
|
306
|
+
expect((await dispatcher.dispatch(request("/test.txt"))).kind).not.toBe("static-file");
|
|
307
|
+
});
|
|
308
|
+
it("serves public/ in an i18n app, bare and under a default locale only", async () => {
|
|
309
|
+
// `resolveRoutes` prefixes the locale before it matches, so `/test.txt` is
|
|
310
|
+
// looked up as `/en-US/test.txt`. `next start` strips the default locale,
|
|
311
|
+
// and each domain's, off a public/ request - `fr` is example.fr's - and no
|
|
312
|
+
// other.
|
|
313
|
+
const dispatcher = dispatcherWithPublic("pages-i18n", ["test.txt"]);
|
|
314
|
+
for (const url of ["/test.txt", "/en-US/test.txt", "/fr/test.txt"]) {
|
|
315
|
+
expect(await dispatcher.dispatch(request(url))).toMatchObject({
|
|
316
|
+
kind: "static-file",
|
|
317
|
+
filePath: "pages-i18n/public/test.txt",
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
expect((await dispatcher.dispatch(request("/nl-NL/test.txt"))).kind).not.toBe("static-file");
|
|
321
|
+
});
|
|
322
|
+
it("knows nothing of public/ when the deployment has none", async () => {
|
|
323
|
+
// The Lambda types: CloudFront or API Gateway answers public/ from S3, the
|
|
324
|
+
// package does not carry it, and a request that got through anyway takes
|
|
325
|
+
// the ordinary not-found path, middleware request headers and all.
|
|
326
|
+
expect(await dispatcherFor("app-playground").dispatch(request("/test.txt"))).toMatchObject({ kind: "not-found" });
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
describe("Dispatcher build-output spellings", () => {
|
|
330
|
+
it("serves a _next/static file whose name the HTML percent-encodes", async () => {
|
|
331
|
+
// webpack names an App Router chunk after its route segment, brackets and
|
|
332
|
+
// all, and Next.js reports the pathname unencoded; the `<script>` tag in
|
|
333
|
+
// the HTML asks for `%5Bid%5D`.
|
|
334
|
+
const base = manifests["app-playground"];
|
|
335
|
+
const pathname = "/_next/static/chunks/app/isr/[id]/page-0123abcd.js";
|
|
336
|
+
const filePath = "app-playground/.next/static/chunks/app/isr/[id]/page-0123abcd.js";
|
|
337
|
+
const manifest = {
|
|
338
|
+
...base,
|
|
339
|
+
staticFiles: { ...base.staticFiles, [pathname]: filePath },
|
|
340
|
+
pathnames: [...base.pathnames, pathname],
|
|
341
|
+
};
|
|
342
|
+
const dispatcher = new dispatch_1.Dispatcher({
|
|
343
|
+
manifest,
|
|
344
|
+
});
|
|
345
|
+
for (const url of [
|
|
346
|
+
"/_next/static/chunks/app/isr/%5Bid%5D/page-0123abcd.js",
|
|
347
|
+
pathname,
|
|
348
|
+
]) {
|
|
349
|
+
expect(await dispatcher.dispatch(request(url))).toMatchObject({
|
|
350
|
+
kind: "static-file",
|
|
351
|
+
source: "next-static",
|
|
352
|
+
filePath,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
describe("Dispatcher non-entrypoint outcomes", () => {
|
|
358
|
+
it("serves a build asset as a static file with its immutable cache header", async () => {
|
|
359
|
+
const manifest = manifests["app-playground"];
|
|
360
|
+
const pathname = Object.keys(manifest.staticFiles).find((file) => file.startsWith("/_next/static/"));
|
|
361
|
+
const result = await dispatcherFor("app-playground").dispatch(request(pathname));
|
|
362
|
+
expect(result.kind).toBe("static-file");
|
|
363
|
+
if (result.kind !== "static-file")
|
|
364
|
+
return;
|
|
365
|
+
expect(result.pathname).toBe(pathname);
|
|
366
|
+
expect(result.responseHeaders.get("cache-control")).toBe("public,max-age=31536000,immutable");
|
|
367
|
+
});
|
|
368
|
+
it("routes /_next/image to the optimizer, basePath included", async () => {
|
|
369
|
+
const query = "?url=%2Ffoo.png&w=640&q=75";
|
|
370
|
+
const plain = await dispatcherFor("app-playground").dispatch(request(`/_next/image${query}`));
|
|
371
|
+
expect(plain.kind).toBe("image-optimization");
|
|
372
|
+
const prefixed = await dispatcherFor("app-playground-base-path").dispatch(request(`/prod/_next/image${query}`));
|
|
373
|
+
expect(prefixed.kind).toBe("image-optimization");
|
|
374
|
+
if (prefixed.kind !== "image-optimization")
|
|
375
|
+
return;
|
|
376
|
+
expect(prefixed.url.searchParams.get("url")).toBe("/foo.png");
|
|
377
|
+
});
|
|
378
|
+
it("routes /_next/image to the optimizer ahead of a root catch-all", async () => {
|
|
379
|
+
const query = "?url=%2Ffoo.png&w=640&q=75";
|
|
380
|
+
const catchAll = dispatcherFor("app-playground-root-catch-all");
|
|
381
|
+
const image = await catchAll.dispatch(request(`/_next/image${query}`));
|
|
382
|
+
expect(image.kind).toBe("image-optimization");
|
|
383
|
+
if (image.kind !== "image-optimization")
|
|
384
|
+
return;
|
|
385
|
+
expect(image.url.searchParams.get("url")).toBe("/foo.png");
|
|
386
|
+
// The catch-all itself still takes everything else.
|
|
387
|
+
const page = await catchAll.dispatch(request("/a/b"));
|
|
388
|
+
expect(page.kind).toBe("entrypoint");
|
|
389
|
+
if (page.kind !== "entrypoint")
|
|
390
|
+
return;
|
|
391
|
+
expect(page.resolvedPathname).toBe("/[[...rest]]");
|
|
392
|
+
const prefixedCatchAll = dispatcherFor("app-playground-base-path-root-catch-all");
|
|
393
|
+
const prefixed = await prefixedCatchAll.dispatch(request(`/prod/_next/image${query}`));
|
|
394
|
+
expect(prefixed.kind).toBe("image-optimization");
|
|
395
|
+
// Without which the image assertion would pass on a fixture with no
|
|
396
|
+
// catch-all at all.
|
|
397
|
+
const prefixedPage = await prefixedCatchAll.dispatch(request("/prod/a/b"));
|
|
398
|
+
expect(prefixedPage.kind).toBe("entrypoint");
|
|
399
|
+
if (prefixedPage.kind !== "entrypoint")
|
|
400
|
+
return;
|
|
401
|
+
expect(prefixedPage.resolvedPathname).toBe("/prod/[[...rest]]");
|
|
402
|
+
});
|
|
403
|
+
it("optimizes the destination of a next.config rewrite onto /_next/image", async () => {
|
|
404
|
+
const manifest = manifests["app-playground-root-catch-all"];
|
|
405
|
+
const routing = manifest.routing;
|
|
406
|
+
const result = await new dispatch_1.Dispatcher({
|
|
407
|
+
manifest: {
|
|
408
|
+
...manifest,
|
|
409
|
+
routing: {
|
|
410
|
+
...routing,
|
|
411
|
+
beforeFiles: [
|
|
412
|
+
{
|
|
413
|
+
source: "/avatar/:id",
|
|
414
|
+
sourceRegex: "^\\/avatar(?:\\/([^\\/]+?))(?:\\/)?$",
|
|
415
|
+
destination: "/_next/image?url=%2Favatars%2F$1.png&w=64&q=75",
|
|
416
|
+
},
|
|
417
|
+
...routing.beforeFiles,
|
|
418
|
+
],
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
}).dispatch(request("/avatar/42"));
|
|
422
|
+
expect(result.kind).toBe("image-optimization");
|
|
423
|
+
if (result.kind !== "image-optimization")
|
|
424
|
+
return;
|
|
425
|
+
expect(result.url.pathname).toBe("/_next/image");
|
|
426
|
+
expect(result.url.searchParams.get("url")).toBe("/avatars/42.png");
|
|
427
|
+
expect(result.url.searchParams.get("w")).toBe("64");
|
|
428
|
+
});
|
|
429
|
+
it("redirects a trailing slash", async () => {
|
|
430
|
+
const result = await dispatcherFor("app-playground").dispatch(request("/isr/1/"));
|
|
431
|
+
expect(result).toMatchObject({
|
|
432
|
+
kind: "redirect",
|
|
433
|
+
status: 308,
|
|
434
|
+
location: "/isr/1",
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
it("serves the app's root in the default locale, with no redirect at all", async () => {
|
|
438
|
+
// `resolveRoutes` prefixes the locale as `${basePath}/${locale}${pathname}`,
|
|
439
|
+
// which turns the root into `/en-US/`, and the slash-stripping 308 every
|
|
440
|
+
// build compiles then answered `GET /` with a redirect no `next start`
|
|
441
|
+
// sends. Measured against `test/e2e/i18n-support-catchall`, whose `/` is a
|
|
442
|
+
// 200. See `Dispatcher.withRootLocale`.
|
|
443
|
+
const result = await dispatcherFor("pages-i18n").dispatch(request("/"));
|
|
444
|
+
expect(result).toMatchObject({ kind: "static-file", pathname: "/en-US" });
|
|
445
|
+
});
|
|
446
|
+
it("redirects the root to the locale the request asked for", async () => {
|
|
447
|
+
const result = await dispatcherFor("pages-i18n").dispatch(request("/", { "accept-language": "nl-NL" }));
|
|
448
|
+
// 307 and not 308, because the next request may detect a different locale.
|
|
449
|
+
// Relative and without the trailing slash `resolveRoutes` puts in the
|
|
450
|
+
// location it builds (`https://example.test/nl-NL/`), which is what
|
|
451
|
+
// `next start` sends and what a test asserting `headers.location` reads.
|
|
452
|
+
expect(result).toMatchObject({
|
|
453
|
+
kind: "redirect",
|
|
454
|
+
status: 307,
|
|
455
|
+
location: "/nl-NL",
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
it("keeps a redirect to another locale's domain absolute", async () => {
|
|
459
|
+
// The fixture maps `fr` onto example.fr, and an absolute location is the
|
|
460
|
+
// only way to leave the origin.
|
|
461
|
+
const result = await dispatcherFor("pages-i18n").dispatch(request("/", { cookie: "NEXT_LOCALE=fr" }));
|
|
462
|
+
expect(result).toMatchObject({
|
|
463
|
+
kind: "redirect",
|
|
464
|
+
status: 307,
|
|
465
|
+
location: "https://example.fr/",
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
it("serves the root of a `trailingSlash` i18n app with no redirect", async () => {
|
|
469
|
+
// With `trailingSlash: true`, `next build` compiles the slash-*adding* 308
|
|
470
|
+
// (`load-custom-routes`' `/:notfile(...)` → `/:notfile/`, `locale: false`)
|
|
471
|
+
// in place of the stripping one, and prefixing the root as `/en-US` made
|
|
472
|
+
// that rule answer `GET /` with a 308 to `/en-US/`, where `next start`
|
|
473
|
+
// answers 200.
|
|
474
|
+
const withSlash = structuredClone(pages_i18n_json_1.default);
|
|
475
|
+
withSlash.config.trailingSlash = true;
|
|
476
|
+
const routing = withSlash.routing;
|
|
477
|
+
routing.beforeMiddleware = [
|
|
478
|
+
{
|
|
479
|
+
source: "/:notfile((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/\\.]+)",
|
|
480
|
+
sourceRegex: "^(?:\\/((?!\\.well-known(?:\\/.*)?)(?:[^\\/]+\\/)*[^\\/\\.]+))$",
|
|
481
|
+
headers: { Location: "/$1/" },
|
|
482
|
+
status: 308,
|
|
483
|
+
priority: true,
|
|
484
|
+
},
|
|
485
|
+
...routing.beforeMiddleware.filter((route) => route.status !== 308),
|
|
486
|
+
];
|
|
487
|
+
const dispatcher = new dispatch_1.Dispatcher({ manifest: manifestOf(withSlash) });
|
|
488
|
+
expect(await dispatcher.dispatch(request("/"))).toMatchObject({
|
|
489
|
+
kind: "static-file",
|
|
490
|
+
pathname: "/en-US",
|
|
491
|
+
});
|
|
492
|
+
// The rule itself is live: the slashless locale root still gets it.
|
|
493
|
+
expect(await dispatcher.dispatch(request("/en-US"))).toMatchObject({
|
|
494
|
+
kind: "redirect",
|
|
495
|
+
status: 308,
|
|
496
|
+
location: "/en-US/",
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
it("still strips a trailing slash the request itself carried", async () => {
|
|
500
|
+
const result = await dispatcherFor("pages-i18n").dispatch(request("/nl-NL/"));
|
|
501
|
+
expect(result).toMatchObject({
|
|
502
|
+
kind: "redirect",
|
|
503
|
+
status: 308,
|
|
504
|
+
location: "/nl-NL",
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
it("returns a direct response for a route that forces a status", async () => {
|
|
508
|
+
const base = manifests["app-playground"];
|
|
509
|
+
const manifest = {
|
|
510
|
+
...base,
|
|
511
|
+
middleware: null,
|
|
512
|
+
routing: {
|
|
513
|
+
...base.routing,
|
|
514
|
+
beforeFiles: [
|
|
515
|
+
{
|
|
516
|
+
sourceRegex: "^/blocked$",
|
|
517
|
+
status: 403,
|
|
518
|
+
headers: { "x-why": "no" },
|
|
519
|
+
},
|
|
520
|
+
],
|
|
521
|
+
},
|
|
522
|
+
};
|
|
523
|
+
const result = await new dispatch_1.Dispatcher({ manifest }).dispatch(request("/blocked"));
|
|
524
|
+
expect(result).toMatchObject({ kind: "response", status: 403 });
|
|
525
|
+
expect(result.responseHeaders.get("x-why")).toBe("no");
|
|
526
|
+
});
|
|
527
|
+
it("reports an unknown path as not found", async () => {
|
|
528
|
+
const result = await dispatcherFor("app-playground").dispatch(request("/definitely-not-a-route"));
|
|
529
|
+
expect(result.kind).toBe("not-found");
|
|
530
|
+
if (result.kind !== "not-found")
|
|
531
|
+
return;
|
|
532
|
+
expect(result.pathname).toBe("/definitely-not-a-route");
|
|
533
|
+
});
|
|
534
|
+
it("resolves the 404 target per router flavor", () => {
|
|
535
|
+
expect(statusTargetOf(manifests["app-playground"], 404)).toMatchObject({
|
|
536
|
+
kind: "entrypoint",
|
|
537
|
+
pathname: "/_not-found",
|
|
538
|
+
});
|
|
539
|
+
expect(statusTargetOf(manifests["app-playground-base-path"], 404)).toMatchObject({
|
|
540
|
+
kind: "entrypoint",
|
|
541
|
+
pathname: "/prod/_not-found",
|
|
542
|
+
});
|
|
543
|
+
// Pages Router has no `/_not-found`, and `next build` prerenders its 404 —
|
|
544
|
+
// one per locale — which `next start` serves ahead of `/_error`.
|
|
545
|
+
expect(statusTargetOf(manifests["pages-i18n"], 404)).toEqual({
|
|
546
|
+
kind: "static-file",
|
|
547
|
+
pathname: "/en-US/404",
|
|
548
|
+
filePath: manifests["pages-i18n"].staticFiles["/en-US/404"],
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
it("serves the prerendered 404 of the request's locale", () => {
|
|
552
|
+
// Every Pages build has `/_error`, so checking it first made the
|
|
553
|
+
// prerendered 404 — the app's `pages/404.js` — dead code; and under i18n
|
|
554
|
+
// the prerender is only ever keyed by locale, never as a bare `/404`.
|
|
555
|
+
const dispatcher = dispatcherFor("pages-i18n");
|
|
556
|
+
const { staticFiles } = manifests["pages-i18n"];
|
|
557
|
+
const at = (url) => dispatcher.notFoundFor(new URL(url, ORIGIN));
|
|
558
|
+
expect(at("/fr/nope")).toMatchObject({ filePath: staticFiles["/fr/404"] });
|
|
559
|
+
expect(at("/NL-nl/nope")).toMatchObject({
|
|
560
|
+
filePath: staticFiles["/nl-NL/404"],
|
|
561
|
+
});
|
|
562
|
+
expect(at("/nope")).toMatchObject({ filePath: staticFiles["/en-US/404"] });
|
|
563
|
+
// No locale in the path: the domain's default, as `next start` renders it.
|
|
564
|
+
expect(at("https://example.fr/nope")).toMatchObject({
|
|
565
|
+
filePath: staticFiles["/fr/404"],
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
it("falls back to /_error when no 404 was prerendered", () => {
|
|
569
|
+
// What a `pages/_app.js` with `getInitialProps` builds without a
|
|
570
|
+
// `pages/404.js`: `next build` then prerenders no 404 at all.
|
|
571
|
+
const base = manifests["pages-i18n"];
|
|
572
|
+
const without404 = Object.fromEntries(Object.entries(base.staticFiles).filter(([key]) => !key.endsWith("/404")));
|
|
573
|
+
expect(statusTargetOf({ ...base, staticFiles: without404 }, 404)).toMatchObject({ kind: "entrypoint", pathname: "/_error" });
|
|
574
|
+
});
|
|
575
|
+
it("prefers an invocable custom /404 over /_error", () => {
|
|
576
|
+
// What `pages/404.js` plus a `pages/_app.js` with `getInitialProps` builds:
|
|
577
|
+
// the 404 cannot be prerendered, so it arrives as an entrypoint beside
|
|
578
|
+
// `/_error`. Serving `/_error` there means the built-in "404: This page
|
|
579
|
+
// could not be found" replaces the app's own — `test/e2e/404-page-app`.
|
|
580
|
+
const base = manifests["pages-i18n"];
|
|
581
|
+
const withCustom404 = {
|
|
582
|
+
...base,
|
|
583
|
+
entrypoints: {
|
|
584
|
+
...base.entrypoints,
|
|
585
|
+
"/404": { ...base.entrypoints["/_error"], id: "/404" },
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
expect(statusTargetOf(withCustom404, 404)).toMatchObject({
|
|
589
|
+
kind: "entrypoint",
|
|
590
|
+
pathname: "/404",
|
|
591
|
+
});
|
|
592
|
+
// App Router still wins over both: `/_not-found` is what next looks for
|
|
593
|
+
// first, and an app with both routers has all three.
|
|
594
|
+
expect(statusTargetOf({
|
|
595
|
+
...withCustom404,
|
|
596
|
+
entrypoints: {
|
|
597
|
+
...withCustom404.entrypoints,
|
|
598
|
+
"/_not-found": {
|
|
599
|
+
...base.entrypoints["/_error"],
|
|
600
|
+
id: "/_not-found",
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
}, 404)).toMatchObject({ kind: "entrypoint", pathname: "/_not-found" });
|
|
604
|
+
});
|
|
605
|
+
it("falls back to a prerendered 404, then to nothing", () => {
|
|
606
|
+
const base = manifests["app-playground"];
|
|
607
|
+
const withoutEntrypoints = {
|
|
608
|
+
...base,
|
|
609
|
+
entrypoints: {},
|
|
610
|
+
middleware: null,
|
|
611
|
+
};
|
|
612
|
+
expect(statusTargetOf(withoutEntrypoints, 404)).toEqual({
|
|
613
|
+
kind: "static-file",
|
|
614
|
+
pathname: "/404",
|
|
615
|
+
filePath: base.staticFiles["/404"],
|
|
616
|
+
});
|
|
617
|
+
expect(statusTargetOf({ ...withoutEntrypoints, staticFiles: {} }, 404)).toEqual({ kind: "none" });
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
describe("the 500 ladder", () => {
|
|
621
|
+
it("prefers the prerendered /500 next emits by default", () => {
|
|
622
|
+
const base = manifests["app-playground"];
|
|
623
|
+
expect(statusTargetOf(base, 500)).toEqual({
|
|
624
|
+
kind: "static-file",
|
|
625
|
+
pathname: "/500",
|
|
626
|
+
filePath: base.staticFiles["/500"],
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
it("prefers an invocable /500 over the prerendered one", () => {
|
|
630
|
+
// What a `pages/500.js` that cannot be static-optimized builds.
|
|
631
|
+
const base = manifests["pages-i18n"];
|
|
632
|
+
expect(statusTargetOf({
|
|
633
|
+
...base,
|
|
634
|
+
entrypoints: {
|
|
635
|
+
...base.entrypoints,
|
|
636
|
+
"/500": { ...base.entrypoints["/_error"], id: "/500" },
|
|
637
|
+
},
|
|
638
|
+
}, 500)).toMatchObject({ kind: "entrypoint", pathname: "/500" });
|
|
639
|
+
});
|
|
640
|
+
it("falls back to /_error, then to nothing", () => {
|
|
641
|
+
// `/_error` is where a custom error page lands when it has
|
|
642
|
+
// `getInitialProps` — the case `test/e2e/async-modules` measures.
|
|
643
|
+
const base = manifests["pages-i18n"];
|
|
644
|
+
expect(statusTargetOf({ ...base, staticFiles: {} }, 500)).toMatchObject({
|
|
645
|
+
kind: "entrypoint",
|
|
646
|
+
pathname: "/_error",
|
|
647
|
+
});
|
|
648
|
+
expect(statusTargetOf({ ...base, staticFiles: {}, entrypoints: {} }, 500)).toEqual({ kind: "none" });
|
|
649
|
+
});
|
|
650
|
+
it("serves the prerendered 500 of the request's locale", () => {
|
|
651
|
+
// Under i18n the prerendered 500 is keyed only by locale, never as a bare
|
|
652
|
+
// `/500`, so looking up `/500` alone always fell through to `/_error`.
|
|
653
|
+
const base = manifests["pages-i18n"];
|
|
654
|
+
const errorTargetFor = (0, dispatch_1.statusTargets)(base, 500);
|
|
655
|
+
const at = (url) => errorTargetFor(new URL(url, ORIGIN));
|
|
656
|
+
expect(at("/fr/ssr")).toEqual({
|
|
657
|
+
kind: "static-file",
|
|
658
|
+
pathname: "/fr/500",
|
|
659
|
+
filePath: base.staticFiles["/fr/500"],
|
|
660
|
+
});
|
|
661
|
+
expect(at("/ssr")).toMatchObject({ pathname: "/en-US/500" });
|
|
662
|
+
// No locale in the path: the domain's default, as `next start` renders it.
|
|
663
|
+
expect(at("https://example.fr/ssr")).toMatchObject({
|
|
664
|
+
pathname: "/fr/500",
|
|
665
|
+
});
|
|
666
|
+
// A request whose URL could not be parsed gets the default locale's.
|
|
667
|
+
expect(errorTargetFor(undefined)).toMatchObject({
|
|
668
|
+
pathname: "/en-US/500",
|
|
669
|
+
});
|
|
670
|
+
expect(statusTargetOf(base, 500)).toMatchObject({ pathname: "/en-US/500" });
|
|
671
|
+
});
|
|
672
|
+
it("looks for the error page under the app's basePath", () => {
|
|
673
|
+
const base = manifests["app-playground-base-path"];
|
|
674
|
+
expect(statusTargetOf(base, 500)).toMatchObject({ pathname: "/prod/500" });
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
describe("toRedirect", () => {
|
|
678
|
+
it("prefers the documented redirect field", () => {
|
|
679
|
+
// `resolveRoutes` does not populate `ResolveRoutesResult.redirect` in
|
|
680
|
+
// next 16.3.5 — every redirect arrives as bare status + `location` — so this
|
|
681
|
+
// is the only coverage that branch can have until it does.
|
|
682
|
+
expect((0, dispatch_1.toRedirect)({ redirect: { url: new URL("https://e.test/x"), status: 301 } }, new Headers())).toEqual({ location: "https://e.test/x", status: 301 });
|
|
683
|
+
});
|
|
684
|
+
it("ignores a location header on a non-3xx status", () => {
|
|
685
|
+
const headers = new Headers({ location: "/x" });
|
|
686
|
+
expect((0, dispatch_1.toRedirect)({ status: 200 }, headers)).toBeUndefined();
|
|
687
|
+
expect((0, dispatch_1.toRedirect)({ status: 403 }, headers)).toBeUndefined();
|
|
688
|
+
expect((0, dispatch_1.toRedirect)({}, headers)).toBeUndefined();
|
|
689
|
+
expect((0, dispatch_1.toRedirect)({ status: 308 }, new Headers())).toBeUndefined();
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
describe("Dispatcher middleware handling", () => {
|
|
693
|
+
it("reports a middleware response without resolving a route", async () => {
|
|
694
|
+
const result = await dispatcherFor("app-playground", async () => ({
|
|
695
|
+
bodySent: true,
|
|
696
|
+
responseHeaders: new Headers({ "x-mw": "responded" }),
|
|
697
|
+
})).dispatch(request("/isr/1"));
|
|
698
|
+
expect(result.kind).toBe("middleware-responded");
|
|
699
|
+
});
|
|
700
|
+
it("sends next.config headers() with a response middleware wrote", async () => {
|
|
701
|
+
// `app-playground`'s `headers()` sets this on `/api/echo`; `next start`
|
|
702
|
+
// sends it with a middleware 401 there too.
|
|
703
|
+
const result = await dispatcherFor("app-playground", async () => ({
|
|
704
|
+
bodySent: true,
|
|
705
|
+
})).dispatch(request("/api/echo"));
|
|
706
|
+
expect(result.kind).toBe("middleware-responded");
|
|
707
|
+
expect(result.responseHeaders.get("x-e2e-config-header")).toBe("from-next-config");
|
|
708
|
+
const other = await dispatcherFor("app-playground", async () => ({
|
|
709
|
+
bodySent: true,
|
|
710
|
+
})).dispatch(request("/isr/1"));
|
|
711
|
+
expect(other.responseHeaders.has("x-e2e-config-header")).toBe(false);
|
|
712
|
+
});
|
|
713
|
+
it("normalizes a middleware redirect to a same-origin path", async () => {
|
|
714
|
+
const result = await dispatcherFor("app-playground", async () => ({
|
|
715
|
+
redirect: { url: new URL("/login", ORIGIN), status: 307 },
|
|
716
|
+
})).dispatch(request("/isr/1"));
|
|
717
|
+
expect(result).toMatchObject({
|
|
718
|
+
kind: "redirect",
|
|
719
|
+
status: 307,
|
|
720
|
+
// `NextResponse.redirect(new URL("/login", request.url))` is how every
|
|
721
|
+
// middleware spells this, and Next.js sends the path: `@next/routing`'s
|
|
722
|
+
// own `getRelativeURL` does it for the header it sets, and only the
|
|
723
|
+
// `redirect.url` field this path reads keeps the absolute form.
|
|
724
|
+
location: "/login",
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
it("follows an internal middleware rewrite to the rewritten entrypoint", async () => {
|
|
728
|
+
const result = await dispatcherFor("app-playground", async () => ({
|
|
729
|
+
rewrite: new URL("/api/health", ORIGIN),
|
|
730
|
+
})).dispatch(request("/isr/1"));
|
|
731
|
+
expect(result.kind).toBe("entrypoint");
|
|
732
|
+
if (result.kind !== "entrypoint")
|
|
733
|
+
return;
|
|
734
|
+
expect(result.resolvedPathname).toBe("/api/health");
|
|
735
|
+
});
|
|
736
|
+
it("routes /_next/image when middleware is what put the request on it", async () => {
|
|
737
|
+
// The API Gateway examples' middleware rewrites `/x` to `/<stage>/x` so the
|
|
738
|
+
// build's `basePath` lines up. `resolveRoutes` never reports the rewritten
|
|
739
|
+
// URL back, so optimizing the URL as received would lose the rewrite.
|
|
740
|
+
const query = "?url=%2Ffoo.png&w=640&q=75";
|
|
741
|
+
const result = await dispatcherFor("app-playground-base-path", async () => ({ rewrite: new URL(`/prod/_next/image${query}`, ORIGIN) })).dispatch(request(`/_next/image${query}`));
|
|
742
|
+
expect(result.kind).toBe("image-optimization");
|
|
743
|
+
if (result.kind !== "image-optimization")
|
|
744
|
+
return;
|
|
745
|
+
expect(result.url.searchParams.get("url")).toBe("/foo.png");
|
|
746
|
+
});
|
|
747
|
+
it("does not leak the internal rewrite header it consumed", async () => {
|
|
748
|
+
const result = await dispatcherFor("app-playground", async () => ({
|
|
749
|
+
rewrite: new URL("/api/health", ORIGIN),
|
|
750
|
+
responseHeaders: new Headers({ "x-middleware-rewrite": "/api/health" }),
|
|
751
|
+
})).dispatch(request("/isr/1"));
|
|
752
|
+
expect(result.responseHeaders.has("x-middleware-rewrite")).toBe(false);
|
|
753
|
+
});
|
|
754
|
+
it("reports an external middleware rewrite as a proxy target", async () => {
|
|
755
|
+
const result = await dispatcherFor("app-playground", async () => ({
|
|
756
|
+
rewrite: new URL("https://upstream.test/x"),
|
|
757
|
+
})).dispatch(request("/isr/1"));
|
|
758
|
+
expect(result.kind).toBe("external-rewrite");
|
|
759
|
+
if (result.kind !== "external-rewrite")
|
|
760
|
+
return;
|
|
761
|
+
expect(result.url.href).toBe("https://upstream.test/x");
|
|
762
|
+
});
|
|
763
|
+
it("carries middleware request headers forward and response headers back", async () => {
|
|
764
|
+
// `resolveRoutes` drops `MiddlewareResult.requestHeaders`: it neither
|
|
765
|
+
// returns them nor mutates the `headers` it was given. Dispatch captures
|
|
766
|
+
// them from the callback, which is what keeps
|
|
767
|
+
// `NextResponse.next({ request: { headers } })` working.
|
|
768
|
+
const result = await dispatcherFor("app-playground", async () => ({
|
|
769
|
+
requestHeaders: new Headers({ host: "example.test", "x-user": "42" }),
|
|
770
|
+
responseHeaders: new Headers({ "x-mw": "ran" }),
|
|
771
|
+
})).dispatch(request("/isr/1"));
|
|
772
|
+
expect(result.kind).toBe("entrypoint");
|
|
773
|
+
if (result.kind !== "entrypoint")
|
|
774
|
+
return;
|
|
775
|
+
expect(result.requestHeaders.get("x-user")).toBe("42");
|
|
776
|
+
expect(result.responseHeaders.get("x-mw")).toBe("ran");
|
|
777
|
+
});
|
|
778
|
+
it("passes the caller's request headers through when middleware adds none", async () => {
|
|
779
|
+
const result = await dispatcherFor("app-playground").dispatch(request("/isr/1", { "x-caller": "yes" }));
|
|
780
|
+
expect(result.kind).toBe("entrypoint");
|
|
781
|
+
if (result.kind !== "entrypoint")
|
|
782
|
+
return;
|
|
783
|
+
expect(result.requestHeaders.get("x-caller")).toBe("yes");
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
describe("repairRouteParamQuery", () => {
|
|
787
|
+
it("drops an optional catchall's param when the request filled none", () => {
|
|
788
|
+
// Measured from `resolveRoutes` for `/optional-catchall` against
|
|
789
|
+
// `app/optional-catchall/[[...params]]`: *both* sides carry the key with no
|
|
790
|
+
// value, which the `@next/routing` types do not admit. The key alone is what
|
|
791
|
+
// makes `prepare()` invent a param, so the key has to go.
|
|
792
|
+
expect((0, dispatch_1.repairRouteParamQuery)({ nxtPparams: undefined }, {
|
|
793
|
+
nxtPparams: undefined,
|
|
794
|
+
})).toEqual({});
|
|
795
|
+
// The same shape with "" for the value, which the expansion can also produce.
|
|
796
|
+
expect((0, dispatch_1.repairRouteParamQuery)({ nxtPparams: "" }, {})).toEqual({});
|
|
797
|
+
// A filled one is left alone, whichever source it came from.
|
|
798
|
+
expect((0, dispatch_1.repairRouteParamQuery)({ nxtPparams: "a/b" }, { nxtPparams: "a/b" })).toEqual({ nxtPparams: "a/b" });
|
|
799
|
+
// No route param can be legitimately empty - a required segment captures
|
|
800
|
+
// `[^/]+?`, a required catchall `.+?`, and an optional catchall that matched
|
|
801
|
+
// nothing has no group for `routeMatches` to report - so an empty value goes
|
|
802
|
+
// whether or not `routeMatches` echoes it.
|
|
803
|
+
expect((0, dispatch_1.repairRouteParamQuery)({ nxtPid: "" }, { nxtPid: "" })).toEqual({});
|
|
804
|
+
// Not a route param, so not ours to touch.
|
|
805
|
+
expect((0, dispatch_1.repairRouteParamQuery)({ q: "" }, {})).toEqual({ q: "" });
|
|
806
|
+
});
|
|
807
|
+
it("repairs and drops in one pass", () => {
|
|
808
|
+
// The prefix collision and the unset optional catchall in the same query:
|
|
809
|
+
// `nxtPid2` is wrong and `nxtPrest` was never requested.
|
|
810
|
+
expect((0, dispatch_1.repairRouteParamQuery)({ nxtPid: "a", nxtPid2: "a2", nxtPrest: "" }, { nxtPid: "a", nxtPid2: "b" })).toEqual({ nxtPid: "a", nxtPid2: "b" });
|
|
811
|
+
});
|
|
812
|
+
});
|
|
813
|
+
describe("outOfBandRouteParams", () => {
|
|
814
|
+
it("leaves a query the contract can carry alone", () => {
|
|
815
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPrest: "a/b", q: "1" }, "/pages-cache/[...rest]")).toBeUndefined();
|
|
816
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPid: "42" }, "/isr/[id]")).toBeUndefined();
|
|
817
|
+
// An encoded delimiter in something that is not a route param is not ours.
|
|
818
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ q: "a%2Fb" }, "/pages-cache/[...rest]")).toBeUndefined();
|
|
819
|
+
});
|
|
820
|
+
it("restates a capture with an encoded delimiter as params, once decoded", () => {
|
|
821
|
+
// `test/e2e/incremental-cache-path-traversal`. Through the query contract
|
|
822
|
+
// this becomes three params and `normalizePagePath` throws on the pathname
|
|
823
|
+
// rebuilt from them; `next start` renders one param, which is this.
|
|
824
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPrest: "..%2F..%2Fserver-reference-manifest" }, "/_next/data/BUILD_ID/pages-cache/[...rest].json")).toEqual({
|
|
825
|
+
params: { rest: ["../../server-reference-manifest"] },
|
|
826
|
+
query: {},
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
it("splits a repeat on real delimiters only, and keeps a single param whole", () => {
|
|
830
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPrest: "a/b%2Fc/d" }, "/pages-cache/[[...rest]]")).toEqual({ params: { rest: ["a", "b/c", "d"] }, query: {} });
|
|
831
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPid: "a%2Fb" }, "/isr/[id]")).toEqual({
|
|
832
|
+
params: { id: "a/b" },
|
|
833
|
+
query: {},
|
|
834
|
+
});
|
|
835
|
+
});
|
|
836
|
+
it("keeps everything that is not a route param in the query", () => {
|
|
837
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPrest: "a%2Fb", from: "/x", page: "2" }, "/pages-cache/[...rest]")).toEqual({
|
|
838
|
+
params: { rest: ["a/b"] },
|
|
839
|
+
query: { from: "/x", page: "2" },
|
|
840
|
+
});
|
|
841
|
+
});
|
|
842
|
+
it("stays on the query contract when a param cannot be restated", () => {
|
|
843
|
+
// An optional catchall the request left unset. Half a param set is worse
|
|
844
|
+
// than none: `prepare` would interpolate a route with a missing segment.
|
|
845
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPrest: "a%2Fb", nxtPoptional: "" }, "/pages-cache/[...rest]/[[...optional]]")).toBeUndefined();
|
|
846
|
+
});
|
|
847
|
+
it("tolerates a capture that is not valid percent-encoding", () => {
|
|
848
|
+
// `decodeQueryPathParameter` is a try/catch for the same reason: `%2F` makes
|
|
849
|
+
// this reachable while `%zz` makes `decodeURIComponent` throw.
|
|
850
|
+
expect((0, dispatch_1.outOfBandRouteParams)({ nxtPrest: "a%2F%zz" }, "/pages-cache/[...rest]")).toEqual({ params: { rest: ["a%2F%zz"] }, query: {} });
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzcGF0Y2gudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2Rpc3BhdGNoLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxzREFBc0Q7QUFDdEQscUNBQWdFO0FBQ2hFLHFDQUFpQztBQUNqQyx5Q0FBMEM7QUFFMUMseUNBT29CO0FBRXBCLGlEQUFpRDtBQUNqRCwwSEFBMEY7QUFDMUYsc0dBQXdFO0FBQ3hFLDhGQUFnRTtBQUNoRSw0REFHa0M7QUFFbEM7Ozs7OztHQU1HO0FBQ0gsU0FBUyxVQUFVLENBQUMsT0FBZ0I7SUFDbEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUMsa0JBQWtCLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7SUFDdEUsSUFBSSxDQUFDO1FBQ0gsTUFBTSxHQUFHLEdBQUcsZUFBZSxDQUFDLE9BQU8sQ0FBeUIsQ0FBQztRQUM3RCw2RUFBNkU7UUFDN0UsMENBQTBDO1FBQzFDLE9BQU8sSUFBQSxvQ0FBb0IsRUFBQyxHQUFHLEVBQUUsRUFBRSxRQUFRLEVBQUUsR0FBRyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQzFFLENBQUM7WUFBUyxDQUFDO1FBQ1QsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3JCLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxPQUFnQjtJQUN4QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQ2YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUM7U0FDcEIsS0FBSyxDQUFDLDhCQUE4QixDQUFDO1NBQ3JDLElBQUksQ0FBQyxjQUFjLENBQUM7U0FDcEIsS0FBSyxDQUFDLHlCQUF5QixDQUFDO1NBQ2hDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FDbkIsQ0FBQztBQUNKLENBQUM7QUFF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Q0FBQztJQUVILEVBQUUsQ0FBQyx3REFBd0QsRUFBRSxHQUFHLEVBQUU7UUFDaEUsNkVBQTZFO1FBQzdFLCtEQUErRDtRQUMvRCxNQUFNLENBQ0osSUFBQSwrQkFBb0IsRUFBQyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsRUFBRSx3QkFBd0IsQ0FBQyxDQUN4RSxDQUFDLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUQsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuaW1wb3J0IHsgbWtkaXJTeW5jLCBta2R0ZW1wU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgZGlybmFtZSwgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IE1pZGRsZXdhcmVSZXN1bHQgfSBmcm9tIFwiQG5leHQvcm91dGluZ1wiO1xuaW1wb3J0IHtcbiAgRGlzcGF0Y2hSZXF1ZXN0LFxuICBEaXNwYXRjaGVyLFxuICBvdXRPZkJhbmRSb3V0ZVBhcmFtcyxcbiAgcmVwYWlyUm91dGVQYXJhbVF1ZXJ5LFxuICBzdGF0dXNUYXJnZXRzLFxuICB0b1JlZGlyZWN0LFxufSBmcm9tIFwiLi9kaXNwYXRjaFwiO1xuaW1wb3J0IHsgQWRhcHRlck1hbmlmZXN0IH0gZnJvbSBcIi4vbWFuaWZlc3RcIjtcbmltcG9ydCB7IHJlYWRQdWJsaWNGaWxlcyB9IGZyb20gXCIuL3B1YmxpYy1maWxlc1wiO1xuaW1wb3J0IGFwcFBsYXlncm91bmRCYXNlUGF0aCBmcm9tIFwiLi4vYWRhcHRlci9fX2ZpeHR1cmVzX18vYXBwLXBsYXlncm91bmQtYmFzZS1wYXRoLmpzb25cIjtcbmltcG9ydCBhcHBQbGF5Z3JvdW5kIGZyb20gXCIuLi9hZGFwdGVyL19fZml4dHVyZXNfXy9hcHAtcGxheWdyb3VuZC5qc29uXCI7XG5pbXBvcnQgcGFnZXNJMThuIGZyb20gXCIuLi9hZGFwdGVyL19fZml4dHVyZXNfXy9wYWdlcy1pMThuLmpzb25cIjtcbmltcG9ydCB7XG4gIEJ1aWxkQ29tcGxldGVDb250ZXh0LFxuICBidWlsZEFkYXB0ZXJNYW5pZmVzdCxcbn0gZnJvbSBcIi4uL2FkYXB0ZXIvYnVpbGQtb3V0cHV0c1wiO1xuXG4vKipcbiAqIERpc3BhdGNoIGlzIHRlc3RlZCBhZ2FpbnN0IHRoZSBtYW5pZmVzdHMgdGhhdCBzdGVwIDEgcHJvZHVjZXMgZnJvbSByZWFsXG4gKiBgb25CdWlsZENvbXBsZXRlYCBjYXB0dXJlcywgcmF0aGVyIHRoYW4gYWdhaW5zdCBoYW5kLXdyaXR0ZW4gbWFuaWZlc3RzOiB0aGVcbiAqIHRoaW5nIG1vc3QgbGlrZWx5IHRvIGJyZWFrIGlzIHRoZSBjb3JyZXNwb25kZW5jZSBiZXR3ZWVuIGhvdyB0aGUgYnVpbGQga2V5c1xuICogYGVudHJ5cG9pbnRzYCBhbmQgaG93IGByZXNvbHZlUm91dGVzYCByZXBvcnRzIGByZXNvbHZlZFBhdGhuYW1lYCwgYW5kIGFcbiAqIGhhbmQtd3JpdHRlbiBtYW5pZmVzdCB3b3VsZCBhc3N1bWUgdGhhdCBjb3JyZXNwb25kZW5jZSBpbnN0ZWFkIG9mIHByb3ZpbmcgaXQuXG4gKi9cbmZ1bmN0aW9uIG1hbmlmZXN0T2YoZml4dHVyZTogdW5rbm93bik6IEFkYXB0ZXJNYW5pZmVzdCB7XG4gIGNvbnN0IHdhcm4gPSBqZXN0LnNweU9uKGNvbnNvbGUsIFwid2FyblwiKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4ge30pO1xuICB0cnkge1xuICAgIGNvbnN0IGN0eCA9IHN0cnVjdHVyZWRDbG9uZShmaXh0dXJlKSBhcyBCdWlsZENvbXBsZXRlQ29udGV4dDtcbiAgICAvLyBUaGUgZml4dHVyZXMnIHByb2plY3QgZGlycyBhcmUgc3ludGhldGljIGAvcmVwby/igKZgIHBhdGhzLCBzbyB0aGUgYnVpbGQgY3dkXG4gICAgLy8gaGFzIHRvIGJlIHN0YXRlZDsgc2VlIGBhc3NlcnRCdWlsZEN3ZGAuXG4gICAgcmV0dXJuIGJ1aWxkQWRhcHRlck1hbmlmZXN0KGN0eCwgeyBidWlsZEN3ZDogY3R4LnByb2plY3REaXIgfSkubWFuaWZlc3Q7XG4gIH0gZmluYWxseSB7XG4gICAgd2Fybi5tb2NrUmVzdG9yZSgpO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGZpeHR1cmUgd2l0aCBgYXBwL3BhcmFtcy9vcHRpb25hbC9bWy4uLnJlc3RdXWAgbW92ZWQgdG8gYGFwcC9bWy4uLnJlc3RdXWAsXG4gKiBhIHJvb3Qgb3B0aW9uYWwgY2F0Y2gtYWxsOiBhIHJvdXRlIGV2ZXJ5IHJlcXVlc3Qgbm90IGNsYWltZWQgZWFybGllciBmYWxsc1xuICogaW50bywgYC9fbmV4dC9pbWFnZWAgaW5jbHVkZWQgdW5sZXNzIGRpc3BhdGNoIHB1dHMgaXQgYWhlYWQgb2YgdGhlbS4gTm8gZXhhbXBsZVxuICogYXBwIGhhcyBvbmUsIGFuZCBhIGNhcHR1cmUgd291bGQgYWRkIGEgd2hvbGUgYXBwIHRvIGNvdmVyIG9uZSByb3V0ZSwgc28gdGhlXG4gKiByb3V0ZSBpcyBtb3ZlZCByYXRoZXIgdGhhbiBjYXB0dXJlZC5cbiAqL1xuZnVuY3Rpb24gd2l0aFJvb3RDYXRjaEFsbChmaXh0dXJlOiB1bmtub3duKTogdW5rbm93biB7XG4gIHJldHVybiBKU09OLnBhcnNlKFxuICAgIEpTT04uc3RyaW5naWZ5KGZpeHR1cmUpXG4gICAgICAuc3BsaXQoXCIvcGFyYW1zL29wdGlvbmFsL1tbLi4ucmVzdF1dXCIpXG4gICAgICAuam9pbihcIi9bWy4uLnJlc3RdXVwiKVxuICAgICAgLnNwbGl0KFwiWy9dPy9wYXJhbXMvb3B0aW9uYWwoPzpcIilcbiAgICAgIC5qb2luKFwiWy9dPyg/OlwiKSxcbiAgKTtcbn1cblxuY29uc3QgbWFuaWZlc3RzID0ge1xuICBcImFwcC1wbGF5Z3JvdW5kXCI6IG1hbmlmZXN0T2YoYXBwUGxheWdyb3VuZCksXG4gIFwiYXBwLXBsYXlncm91bmQtYmFzZS1wYXRoXCI6IG1hbmlmZXN0T2YoYXBwUGxheWdyb3VuZEJhc2VQYXRoKSxcbiAgXCJhcHAtcGxheWdyb3VuZC1yb290LWNhdGNoLWFsbFwiOiBtYW5pZmVzdE9mKHdpdGhSb290Q2F0Y2hBbGwoYXBwUGxheWdyb3VuZCkpLFxuICBcImFwcC1wbGF5Z3JvdW5kLWJhc2UtcGF0aC1yb290LWNhdGNoLWFsbFwiOiBtYW5pZmVzdE9mKFxuICAgIHdpdGhSb290Q2F0Y2hBbGwoYXBwUGxheWdyb3VuZEJhc2VQYXRoKSxcbiAgKSxcbiAgXCJwYWdlcy1pMThuXCI6IG1hbmlmZXN0T2YocGFnZXNJMThuKSxcbn0gYXMgY29uc3Q7XG5cbmNvbnN0IE9SSUdJTiA9IFwiaHR0cHM6Ly9leGFtcGxlLnRlc3RcIjtcblxuZnVuY3Rpb24gcmVxdWVzdCh1cmw6IHN0cmluZywgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9KSB7XG4gIGNvbnN0IHJlc3VsdDogRGlzcGF0Y2hSZXF1ZXN0ID0ge1xuICAgIG1ldGhvZDogXCJHRVRcIixcbiAgICB1cmw6IG5ldyBVUkwodXJsLCBPUklHSU4pLFxuICAgIGhlYWRlcnM6IG5ldyBIZWFkZXJzKHsgaG9zdDogXCJleGFtcGxlLnRlc3RcIiwgLi4uaGVhZGVycyB9KSxcbiAgICAvLyBHRVQvSEVBRCBoYXZlIG5vIGJvZHksIGJ1dCBgcmVzb2x2ZVJvdXRlc2AgcmVxdWlyZXMgYSBzdHJlYW0uXG4gICAgYm9keTogbmV3IFJlYWRhYmxlU3RyZWFtKHtcbiAgICAgIHN0YXJ0KGNvbnRyb2xsZXIpIHtcbiAgICAgICAgY29udHJvbGxlci5jbG9zZSgpO1xuICAgICAgfSxcbiAgICB9KSxcbiAgICAvLyBNaWRkbGV3YXJlIHRoYXQgbGV0cyBldmVyeSByZXF1ZXN0IHRocm91Z2guXG4gICAgaW52b2tlTWlkZGxld2FyZTogYXN5bmMgKCkgPT4gKHsgcmVzcG9uc2U6IG5ldyBSZXNwb25zZSgpIH0pLFxuICB9O1xuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKiogQSBEaXNwYXRjaGVyIG92ZXIgYG5hbWVgLCB3aG9zZSBtaWRkbGV3YXJlLCBpZiBnaXZlbiwgYW5zd2VycyBgbWlkZGxld2FyZSgpYC4gKi9cbmZ1bmN0aW9uIGRpc3BhdGNoZXJGb3IoXG4gIG5hbWU6IGtleW9mIHR5cGVvZiBtYW5pZmVzdHMsXG4gIG1pZGRsZXdhcmU/OiAoKSA9PiBQcm9taXNlPE1pZGRsZXdhcmVSZXN1bHQ+LFxuKTogUGljazxEaXNwYXRjaGVyLCBcImRpc3BhdGNoXCIgfCBcIm5vdEZvdW5kRm9yXCI+IHtcbiAgY29uc3QgZGlzcGF0Y2hlciA9IG5ldyBEaXNwYXRjaGVyKHsgbWFuaWZlc3Q6IG1hbmlmZXN0c1tuYW1lXSB9KTtcbiAgcmV0dXJuIHtcbiAgICBub3RGb3VuZEZvcjogZGlzcGF0Y2hlci5ub3RGb3VuZEZvcixcbiAgICBkaXNwYXRjaDogKHJlcSkgPT5cbiAgICAgIGRpc3BhdGNoZXIuZGlzcGF0Y2goXG4gICAgICAgIG1pZGRsZXdhcmVcbiAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgLi4ucmVxLFxuICAgICAgICAgICAgICBpbnZva2VNaWRkbGV3YXJlOiBhc3luYyAoKSA9PiAoe1xuICAgICAgICAgICAgICAgIC4uLihhd2FpdCBtaWRkbGV3YXJlKCkpLFxuICAgICAgICAgICAgICAgIHJlc3BvbnNlOiBuZXcgUmVzcG9uc2UoKSxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB9XG4gICAgICAgICAgOiByZXEsXG4gICAgICApLFxuICB9O1xufVxuXG4vKiogVGhlIDQwNCBvciA1MDAgYSByZXF1ZXN0IHdpdGggbm8gbG9jYWxlIGdldHMuICovXG5mdW5jdGlvbiBzdGF0dXNUYXJnZXRPZihtYW5pZmVzdDogQWRhcHRlck1hbmlmZXN0LCBzdGF0dXM6IDQwNCB8IDUwMCkge1xuICByZXR1cm4gc3RhdHVzVGFyZ2V0cyhtYW5pZmVzdCwgc3RhdHVzKSh1bmRlZmluZWQpO1xufVxuXG5kZXNjcmliZShcIkRpc3BhdGNoZXIgZW50cnlwb2ludCByZXNvbHV0aW9uXCIsICgpID0+IHtcbiAgaXQoXCJyZXNvbHZlcyBhIGR5bmFtaWMgQXBwIFJvdXRlciBwYWdlIHRvIGl0cyB0ZW1wbGF0ZSBlbnRyeXBvaW50XCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIikuZGlzcGF0Y2goXG4gICAgICByZXF1ZXN0KFwiL2lzci8xXCIpLFxuICAgICk7XG4gICAgZXhwZWN0KHJlc3VsdC5raW5kKS50b0JlKFwiZW50cnlwb2ludFwiKTtcbiAgICBpZiAocmVzdWx0LmtpbmQgIT09IFwiZW50cnlwb2ludFwiKSByZXR1cm47XG4gICAgLy8gYHJlc29sdmVkUGF0aG5hbWVgIGlzIHRoZSB0ZW1wbGF0ZTsgYGludm9jYXRpb25UYXJnZXRgIGlzIGNvbmNyZXRlLiBCb3RoXG4gICAgLy8gYXJlIG5lZWRlZDogdGhlIGZpcnN0IHBpY2tzIHRoZSBtb2R1bGUsIHRoZSBzZWNvbmQgaXMgd2hhdCBpdCByZW5kZXJzLlxuICAgIGV4cGVjdChyZXN1bHQucmVzb2x2ZWRQYXRobmFtZSkudG9CZShcIi9pc3IvW2lkXVwiKTtcbiAgICBleHBlY3QocmVzdWx0Lmludm9jYXRpb25UYXJnZXQpLnRvRXF1YWwoe1xuICAgICAgcGF0aG5hbWU6IFwiL2lzci8xXCIsXG4gICAgICBxdWVyeTogeyBueHRQaWQ6IFwiMVwiIH0sXG4gICAgfSk7XG4gICAgZXhwZWN0KHJlc3VsdC5lbnRyeXBvaW50LmZpbGVQYXRoKS50b0NvbnRhaW4oXCJpc3IvW2lkXS9wYWdlLmpzXCIpO1xuICAgIGV4cGVjdChyZXN1bHQuZW50cnlwb2ludC50eXBlKS50b0JlKFwiYXBwLXBhZ2VcIik7XG4gIH0pO1xuXG4gIGl0KFwicmVzb2x2ZXMgYW4gQXBwIFJvdXRlciByb3V0ZSBoYW5kbGVyXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIikuZGlzcGF0Y2goXG4gICAgICByZXF1ZXN0KFwiL2FwaS9oZWFsdGhcIiksXG4gICAgKTtcbiAgICBleHBlY3QocmVzdWx0LmtpbmQpLnRvQmUoXCJlbnRyeXBvaW50XCIpO1xuICAgIGlmIChyZXN1bHQua2luZCAhPT0gXCJlbnRyeXBvaW50XCIpIHJldHVybjtcbiAgICBleHBlY3QocmVzdWx0LmVudHJ5cG9pbnQudHlwZSkudG9CZShcImFwcC1yb3V0ZVwiKTtcbiAgICBleHBlY3QocmVzdWx0LnJlc29sdmVkUGF0aG5hbWUpLnRvQmUoXCIvYXBpL2hlYWx0aFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJtYXRjaGVzIGJhc2VQYXRoLXByZWZpeGVkIGVudHJ5cG9pbnQga2V5cyB3aXRob3V0IG5vcm1hbGl6YXRpb25cIiwgYXN5bmMgKCkgPT4ge1xuICAgIC8vIFN0ZXAgMSBrZXllZCBgZW50cnlwb2ludHNgIGJ5IHRoZSBiYXNlUGF0aC1wcmVmaXhlZCBgb3V0cHV0LnBhdGhuYW1lYCBhbmRcbiAgICAvLyBsZWZ0IG9wZW4gd2hldGhlciBgcmVzb2x2ZWRQYXRobmFtZWAgY29tZXMgYmFjayBwcmVmaXhlZC4gSXQgZG9lcyDigJQgdGhpc1xuICAgIC8vIHRlc3QgaXMgd2hhdCBjbG9zZXMgdGhhdCBxdWVzdGlvbi5cbiAgICBjb25zdCBkaXNwYXRjaGVyID0gZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kLWJhc2UtcGF0aFwiKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvcHJvZC9pc3IvMVwiKSk7XG4gICAgZXhwZWN0KHJlc3VsdC5raW5kKS50b0JlKFwiZW50cnlwb2ludFwiKTtcbiAgICBpZiAocmVzdWx0LmtpbmQgIT09IFwiZW50cnlwb2ludFwiKSByZXR1cm47XG4gICAgZXhwZWN0KHJlc3VsdC5yZXNvbHZlZFBhdGhuYW1lKS50b0JlKFwiL3Byb2QvaXNyL1tpZF1cIik7XG4gICAgZXhwZWN0KHJlc3VsdC5pbnZvY2F0aW9uVGFyZ2V0LnBhdGhuYW1lKS50b0JlKFwiL3Byb2QvaXNyLzFcIik7XG5cbiAgICAvLyBUaGUgc2FtZSBwYXRoIHdpdGhvdXQgdGhlIHByZWZpeCBpcyBub3QgdGhlIGFwcCdzLlxuICAgIGNvbnN0IHVucHJlZml4ZWQgPSBhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvaXNyLzFcIikpO1xuICAgIGV4cGVjdCh1bnByZWZpeGVkLmtpbmQpLnRvQmUoXCJub3QtZm91bmRcIik7XG4gIH0pO1xuXG4gIGl0KFwicmVzb2x2ZXMgYSBQYWdlcyBSb3V0ZXIgcGFnZSBhbmQgQVBJIHJvdXRlXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBkaXNwYXRjaGVyID0gZGlzcGF0Y2hlckZvcihcInBhZ2VzLWkxOG5cIik7XG4gICAgY29uc3QgcGFnZSA9IGF3YWl0IGRpc3BhdGNoZXIuZGlzcGF0Y2gocmVxdWVzdChcIi9lbi1VUy9zc3JcIikpO1xuICAgIGV4cGVjdChwYWdlLmtpbmQpLnRvQmUoXCJlbnRyeXBvaW50XCIpO1xuICAgIGlmIChwYWdlLmtpbmQgPT09IFwiZW50cnlwb2ludFwiKSB7XG4gICAgICBleHBlY3QocGFnZS5lbnRyeXBvaW50LnR5cGUpLnRvQmUoXCJwYWdlXCIpO1xuICAgIH1cbiAgICBjb25zdCBhcGkgPSBhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvYXBpL2hlbGxvXCIpKTtcbiAgICBleHBlY3QoYXBpLmtpbmQpLnRvQmUoXCJlbnRyeXBvaW50XCIpO1xuICAgIGlmIChhcGkua2luZCA9PT0gXCJlbnRyeXBvaW50XCIpIHtcbiAgICAgIGV4cGVjdChhcGkuZW50cnlwb2ludC50eXBlKS50b0JlKFwicGFnZS1hcGlcIik7XG4gICAgfVxuICB9KTtcblxuICBpdChcInJlc29sdmVzIGEgUGFnZXMgUm91dGVyIElTUiBkYXRhIFVSTCB2aWEgaXRzIHByZXJlbmRlciB0ZW1wbGF0ZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gVGhpcyBvbmx5IHdvcmtzIGJlY2F1c2UgYGJ1aWxkQWRhcHRlck1hbmlmZXN0YCBhZGRzIGR5bmFtaWMgKnByZXJlbmRlcipcbiAgICAvLyB0ZW1wbGF0ZXMgdG8gYHBhdGhuYW1lc2AvYGVudHJ5cG9pbnRzYDogYC9fbmV4dC9kYXRhL+KApi9bc2x1Z10uanNvbmAgaXNcbiAgICAvLyBub3QgYSByb3V0ZSBvdXRwdXQsIHNvIHdpdGhvdXQgaXQgdGhpcyBVUkwgNDA0cyB3aGlsZSBgbmV4dCBzdGFydGAgc2VydmVzXG4gICAgLy8gaXQuXG4gICAgY29uc3QgeyBidWlsZElkIH0gPSBtYW5pZmVzdHNbXCJwYWdlcy1pMThuXCJdO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGRpc3BhdGNoZXJGb3IoXCJwYWdlcy1pMThuXCIpLmRpc3BhdGNoKFxuICAgICAgcmVxdWVzdChgL19uZXh0L2RhdGEvJHtidWlsZElkfS9mci9ibG9nL2hlbGxvLmpzb25gKSxcbiAgICApO1xuICAgIGV4cGVjdChyZXN1bHQua2luZCkudG9CZShcImVudHJ5cG9pbnRcIik7XG4gICAgaWYgKHJlc3VsdC5raW5kICE9PSBcImVudHJ5cG9pbnRcIikgcmV0dXJuO1xuICAgIGV4cGVjdChyZXN1bHQucmVzb2x2ZWRQYXRobmFtZSkudG9CZShcbiAgICAgIGAvX25leHQvZGF0YS8ke2J1aWxkSWR9L2ZyL2Jsb2cvW3NsdWddLmpzb25gLFxuICAgICk7XG4gICAgZXhwZWN0KHJlc3VsdC5lbnRyeXBvaW50LmZpbGVQYXRoKS50b0NvbnRhaW4oXCJibG9nL1tzbHVnXVwiKTtcbiAgICBleHBlY3QocmVzdWx0Lmludm9jYXRpb25UYXJnZXQucXVlcnkpLnRvTWF0Y2hPYmplY3QoeyBueHRQc2x1ZzogXCJoZWxsb1wiIH0pO1xuICB9KTtcblxuICBpdChcInJlc29sdmVzIHRoZSBjYW5vbmljYWwgdHJhaWxpbmctc2xhc2ggVVJMIG9mIGEgYHRyYWlsaW5nU2xhc2hgIGFwcFwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gVGhlIGJ1aWxkJ3MgcGF0aG5hbWVzIG5ldmVyIGNhcnJ5IHRoZSBzbGFzaCwgYnV0IGB0cmFpbGluZ1NsYXNoOiB0cnVlYFxuICAgIC8vIG1ha2VzIGAvYS9gIHRoZSBVUkwgTmV4dC5qcydzIG93biAzMDggc2VuZHMgYnJvd3NlcnMgdG8sIGFuZFxuICAgIC8vIGBAbmV4dC9yb3V0aW5nYCBtYXRjaGVzIHBhdGhuYW1lcyBieSBleGFjdCBlcXVhbGl0eS4gTWVhc3VyZWQgYWdhaW5zdFxuICAgIC8vIG5leHQuanMncyBgdGVzdC9lMmUvYXBwLWRpci90cmFpbGluZ3NsYXNoYDogd2l0aG91dCB0aGlzLCA2IG9mIDggY2FzZXNcbiAgICAvLyBmYWlsZWQsIGluY2x1ZGluZyBgZmV0Y2goJy9hcGkvcmV2YWxpZGF0ZScpYCBnZXR0aW5nIHRoZSA0MDQgcGFnZS5cbiAgICBjb25zdCB3aXRoU2xhc2ggPSBzdHJ1Y3R1cmVkQ2xvbmUoXG4gICAgICBhcHBQbGF5Z3JvdW5kIGFzIHVua25vd24sXG4gICAgKSBhcyBCdWlsZENvbXBsZXRlQ29udGV4dDtcbiAgICAod2l0aFNsYXNoLmNvbmZpZyBhcyB7IHRyYWlsaW5nU2xhc2g6IGJvb2xlYW4gfSkudHJhaWxpbmdTbGFzaCA9IHRydWU7XG4gICAgLy8gQWxsIHRocmVlIGNhcHR1cmVzIGFyZSBmcm9tIGFwcHMgd2l0aCB0aGUgZGVmYXVsdCBgdHJhaWxpbmdTbGFzaDogZmFsc2VgLFxuICAgIC8vIHNvIHRoZWlyIGBiZWZvcmVNaWRkbGV3YXJlYCBjYXJyaWVzIHRoZSAqc3RyaXAqLXNsYXNoIDMwOCAoYC9hL2Ag4oaSIGAvYWApLlxuICAgIC8vIExlYXZpbmcgaXQgaW4gd291bGQgbWFrZSB0aGUgY2xvbmUgaW5jb2hlcmVudCDigJQgdGhhdCByZWRpcmVjdCBpcyB3aGF0IGFcbiAgICAvLyByZWFsIGB0cmFpbGluZ1NsYXNoOiB0cnVlYCBidWlsZCByZXBsYWNlcyB3aXRoIHRoZSBhZGQtc2xhc2ggb25lIOKAlCBhbmQgaXRcbiAgICAvLyBmaXJlcyBiZWZvcmUgYW55IHBhdGhuYW1lIGlzIG1hdGNoZWQsIHNvIG5vdGhpbmcgYmVsb3cgd291bGQgYmUgcmVhY2hlZC5cbiAgICBjb25zdCByb3V0aW5nID0gd2l0aFNsYXNoLnJvdXRpbmcgYXMge1xuICAgICAgYmVmb3JlTWlkZGxld2FyZTogeyBzdGF0dXM/OiBudW1iZXIgfVtdO1xuICAgIH07XG4gICAgcm91dGluZy5iZWZvcmVNaWRkbGV3YXJlID0gcm91dGluZy5iZWZvcmVNaWRkbGV3YXJlLmZpbHRlcihcbiAgICAgIChyb3V0ZSkgPT4gcm91dGUuc3RhdHVzICE9PSAzMDgsXG4gICAgKTtcbiAgICBjb25zdCBkaXNwYXRjaGVyID0gbmV3IERpc3BhdGNoZXIoe1xuICAgICAgbWFuaWZlc3Q6IG1hbmlmZXN0T2Yod2l0aFNsYXNoKSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHBhZ2UgPSBhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvaXNyLzEvXCIpKTtcbiAgICBleHBlY3QocGFnZS5raW5kKS50b0JlKFwiZW50cnlwb2ludFwiKTtcbiAgICBpZiAocGFnZS5raW5kICE9PSBcImVudHJ5cG9pbnRcIikgcmV0dXJuO1xuICAgIC8vIE5vcm1hbGl6ZWQgb24gdGhlIHdheSBvdXQsIGJlY2F1c2UgYGVudHJ5cG9pbnRzYCBpcyBrZXllZCB3aXRob3V0IHRoZVxuICAgIC8vIHNsYXNoIGFuZCB0aGUgcmVuZGVyIGhhcyB0byBsYW5kIG9uIGl0cyBwcmVyZW5kZXIncyBjYWNoZSBrZXkuXG4gICAgZXhwZWN0KHBhZ2UucmVzb2x2ZWRQYXRobmFtZSkudG9CZShcIi9pc3IvW2lkXVwiKTtcbiAgICBleHBlY3QocGFnZS5pbnZvY2F0aW9uVGFyZ2V0KS50b0VxdWFsKHtcbiAgICAgIHBhdGhuYW1lOiBcIi9pc3IvMVwiLFxuICAgICAgcXVlcnk6IHsgbnh0UGlkOiBcIjFcIiB9LFxuICAgIH0pO1xuXG4gICAgY29uc3Qgcm91dGUgPSBhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvYXBpL2hlYWx0aC9cIikpO1xuICAgIGV4cGVjdChyb3V0ZS5raW5kKS50b0JlKFwiZW50cnlwb2ludFwiKTtcbiAgICBpZiAocm91dGUua2luZCA9PT0gXCJlbnRyeXBvaW50XCIpIHtcbiAgICAgIGV4cGVjdChyb3V0ZS5yZXNvbHZlZFBhdGhuYW1lKS50b0JlKFwiL2FwaS9oZWFsdGhcIik7XG4gICAgfVxuXG4gICAgLy8gQSBzdGF0aWMgZmlsZSBrZWVwcyBpdHMgZXh0ZW5zaW9uLWJlYXJpbmcgcGF0aG5hbWU6IE5leHQuanMgY29tcGlsZXMgdGhlXG4gICAgLy8gKm9wcG9zaXRlKiByZWRpcmVjdCBmb3IgdGhvc2UsIGFuZCBzaGFkb3dpbmcgaXQgd291bGQgc2VydmUgYC94LmpzL2AuXG4gICAgY29uc3QgYXNzZXQgPSBhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvZmF2aWNvbi5pY29cIikpO1xuICAgIGV4cGVjdChhc3NldC5raW5kKS50b0JlKFwic3RhdGljLWZpbGVcIik7XG4gICAgZXhwZWN0KGF3YWl0IGRpc3BhdGNoZXIuZGlzcGF0Y2gocmVxdWVzdChcIi9mYXZpY29uLmljby9cIikpKS50b01hdGNoT2JqZWN0KHtcbiAgICAgIGtpbmQ6IFwibm90LWZvdW5kXCIsXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwiZ2l2ZXMgYSBwYXJhbSB3aG9zZSBuYW1lIHByZWZpeGVzIGFub3RoZXIgcGFyYW0ncyBpdHMgb3duIHZhbHVlXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBgQG5leHQvcm91dGluZ2AgZXhwYW5kcyBgJG54dFBpZDJgIGJ5IHJlcGxhY2luZyBncm91cCBuYW1lcyBpbiBpbnNlcnRpb25cbiAgICAvLyBvcmRlciwgc28gdGhlIGAkbnh0UGlkYCBwcmVmaXggd2lucyBhbmQgbGVhdmVzIGEgbGl0ZXJhbCBgMmA6IHRoZSByb3V0ZSBpc1xuICAgIC8vIGludm9rZWQgd2l0aCBgbnh0UGlkMj1hMmAuIGByZXBhaXJSb3V0ZVBhcmFtUXVlcnlgIGNvcnJlY3RzIGl0IGZyb21cbiAgICAvLyBgcm91dGVNYXRjaGVzYC4gTWVhc3VyZWQgYWdhaW5zdCBgdGVzdC9lMmUvYXBwLWRpci91c2UtcGFyYW1zYCwgd2hvc2VcbiAgICAvLyBmaXh0dXJlIGlzIGBhcHAvW2lkXS9baWQyXS9wYWdlLnRzeGA7IGFwcC1wbGF5Z3JvdW5kJ3NcbiAgICAvLyBgYXBwL3BhcmFtcy9wcmVmaXgvW2lkXS9baWQyXWAgaXMgdGhlIHNhbWUgc2hhcGUuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kXCIpLmRpc3BhdGNoKFxuICAgICAgcmVxdWVzdChcIi9wYXJhbXMvcHJlZml4L2EvYlwiKSxcbiAgICApO1xuICAgIGV4cGVjdChyZXN1bHQua2luZCkudG9CZShcImVudHJ5cG9pbnRcIik7XG4gICAgaWYgKHJlc3VsdC5raW5kICE9PSBcImVudHJ5cG9pbnRcIikgcmV0dXJuO1xuICAgIGV4cGVjdChyZXN1bHQucmVzb2x2ZWRQYXRobmFtZSkudG9CZShcIi9wYXJhbXMvcHJlZml4L1tpZF0vW2lkMl1cIik7XG4gICAgZXhwZWN0KHJlc3VsdC5pbnZvY2F0aW9uVGFyZ2V0KS50b0VxdWFsKHtcbiAgICAgIHBhdGhuYW1lOiBcIi9wYXJhbXMvcHJlZml4L2EvYlwiLFxuICAgICAgcXVlcnk6IHsgbnh0UGlkOiBcImFcIiwgbnh0UGlkMjogXCJiXCIgfSxcbiAgICB9KTtcbiAgICBleHBlY3QocmVzdWx0Lmludm9jYXRpb25UYXJnZXQucXVlcnkpLnRvRXF1YWwoe1xuICAgICAgbnh0UGlkOiBcImFcIixcbiAgICAgIG54dFBpZDI6IFwiYlwiLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcImFwcGxpZXMgYSBnYXRlZCBiZWZvcmVGaWxlcyByZXdyaXRlIGZyb20gbmV4dC5jb25maWcudHMgb25jZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gYXBwLXBsYXlncm91bmQncyBvbmUgY29uZmlnIHJld3JpdGU6IGAvZTJlL3Jld3JpdGUvOnBhdGgoLiopYCB3aXRoXG4gICAgLy8gYGhhczogcXVlcnkganNvbj10cnVlYCwgdG8gYC9lMmUvcmV3cml0ZS9lY2hvP2Zyb209LzpwYXRoYC4gSXRzIG91dHB1dFxuICAgIC8vIG1hdGNoZXMgaXQgYWdhaW4sIHdoaWNoIGlzIHdoYXQgTmV4dC5qcyByZS1hcHBsaWVzIGluc2lkZSB0aGUgZW50cnlwb2ludFxuICAgIC8vIC0gdGhlIERpc3BhdGNoZXIncyBoYWxmIGlzIHJlc29sdmluZyBpdCBleGFjdGx5IG9uY2UuXG4gICAgY29uc3QgZGlzcGF0Y2hlciA9IGRpc3BhdGNoZXJGb3IoXCJhcHAtcGxheWdyb3VuZFwiKTtcbiAgICBjb25zdCByZXdyaXR0ZW4gPSBhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKFxuICAgICAgcmVxdWVzdChcIi9lMmUvcmV3cml0ZS9zb21lL3JvdXRlP2pzb249dHJ1ZVwiKSxcbiAgICApO1xuICAgIGV4cGVjdChyZXdyaXR0ZW4ua2luZCkudG9CZShcImVudHJ5cG9pbnRcIik7XG4gICAgaWYgKHJld3JpdHRlbi5raW5kICE9PSBcImVudHJ5cG9pbnRcIikgcmV0dXJuO1xuICAgIGV4cGVjdChyZXdyaXR0ZW4ucmVzb2x2ZWRQYXRobmFtZSkudG9CZShcIi9lMmUvcmV3cml0ZS9lY2hvXCIpO1xuICAgIGV4cGVjdChyZXdyaXR0ZW4uaW52b2NhdGlvblRhcmdldC5xdWVyeSkudG9NYXRjaE9iamVjdCh7XG4gICAgICBmcm9tOiBcIi9zb21lL3JvdXRlXCIsXG4gICAgICBqc29uOiBcInRydWVcIixcbiAgICB9KTtcblxuICAgIC8vIFdpdGhvdXQgdGhlIGBoYXNgIGNvbmRpdGlvbiB0aGUgcnVsZSBkb2VzIG5vdCBmaXJlIGFuZCBub3RoaW5nIGVsc2VcbiAgICAvLyBzZXJ2ZXMgdGhlIHBhdGguXG4gICAgZXhwZWN0KFxuICAgICAgYXdhaXQgZGlzcGF0Y2hlci5kaXNwYXRjaChyZXF1ZXN0KFwiL2UyZS9yZXdyaXRlL3NvbWUvcm91dGVcIikpLFxuICAgICkudG9NYXRjaE9iamVjdCh7IGtpbmQ6IFwibm90LWZvdW5kXCIgfSk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwiRGlzcGF0Y2hlciBwdWJsaWMvIGZpbGVzXCIsICgpID0+IHtcbiAgLyoqXG4gICAqIEEgcmVhbCBgcHVibGljL2Agb24gZGlzaywgbGlzdGVkIGJ5IHRoZSBzYW1lIGByZWFkUHVibGljRmlsZXNgIHRoZSBydW50aW1lXG4gICAqIGNhbGxzIGF0IGNvbGQgc3RhcnQsIHNvIHRoZSBzcGVsbGluZ3MgdW5kZXIgdGVzdCBhcmUgdGhlIG9uZXMgdGhlIGxpc3RlclxuICAgKiBhbmQgdGhlIHJvdXRpbmcgdGFibGUgYWN0dWFsbHkgcHJvZHVjZSBiZXR3ZWVuIHRoZW0uXG4gICAqL1xuICBmdW5jdGlvbiBwdWJsaWNEaXIoZmlsZXM6IHN0cmluZ1tdKTogcmVhZG9ubHkgc3RyaW5nW10ge1xuICAgIGNvbnN0IGRpciA9IG1rZHRlbXBTeW5jKGpvaW4odG1wZGlyKCksIFwiY2RrLW5leHRqcy1kaXNwYXRjaC1wdWJsaWMtXCIpKTtcbiAgICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgIG1rZGlyU3luYyhkaXJuYW1lKGpvaW4oZGlyLCBmaWxlKSksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgd3JpdGVGaWxlU3luYyhqb2luKGRpciwgZmlsZSksIGZpbGUpO1xuICAgIH1cbiAgICByZXR1cm4gcmVhZFB1YmxpY0ZpbGVzKGRpcik7XG4gIH1cblxuICBmdW5jdGlvbiBkaXNwYXRjaGVyV2l0aFB1YmxpYyhcbiAgICBuYW1lOiBrZXlvZiB0eXBlb2YgbWFuaWZlc3RzLFxuICAgIGZpbGVzOiBzdHJpbmdbXSxcbiAgKTogRGlzcGF0Y2hlciB7XG4gICAgcmV0dXJuIG5ldyBEaXNwYXRjaGVyKHtcbiAgICAgIG1hbmlmZXN0OiBtYW5pZmVzdHNbbmFtZV0sXG4gICAgICBwdWJsaWNGaWxlczogcHVibGljRGlyKGZpbGVzKSxcbiAgICB9KTtcbiAgfVxuXG4gIGl0LmVhY2goW1xuICAgIC8vIEEgc3BhY2UgaXMgZW5jb2RlZCBieSBldmVyeSBjbGllbnQsIHNvIHRoZSB0d28gc3BlbGxpbmdzIGFncmVlLlxuICAgIFtcInN0YXRpYy9oZWxsbyBlMmUucG5nXCIsIFtcIi9zdGF0aWMvaGVsbG8lMjBlMmUucG5nXCJdXSxcbiAgICAvLyBUaGVzZSBhIGJyb3dzZXIgc2VuZHMgYXMgd3JpdHRlbiwgYW5kIGBlbmNvZGVVUklDb21wb25lbnRgIGRvZXMgbm90LlxuICAgIFtcImltYWdlcy9sb2dvQDJ4LnBuZ1wiLCBbXCIvaW1hZ2VzL2xvZ29AMngucG5nXCIsIFwiL2ltYWdlcy9sb2dvJTQwMngucG5nXCJdXSxcbiAgICBbXCJjKysuc3ZnXCIsIFtcIi9jKysuc3ZnXCIsIFwiL2MlMkIlMkIuc3ZnXCJdXSxcbiAgICBbXCJpY29uWzFdLnBuZ1wiLCBbXCIvaWNvblsxXS5wbmdcIiwgXCIvaWNvbiU1QjElNUQucG5nXCJdXSxcbiAgICBbXCJRJkEucGRmXCIsIFtcIi9RJkEucGRmXCIsIFwiL1ElMjZBLnBkZlwiXV0sXG4gICAgLy8gQSBsaXRlcmFsIGAlYCBjYW4gb25seSBiZSByZXF1ZXN0ZWQgZXNjYXBlZC5cbiAgICBbXCIxMDAlLnBuZ1wiLCBbXCIvMTAwJTI1LnBuZ1wiXV0sXG4gICAgW1wi0YTQvtGC0L4vYS5qcGdcIiwgW1wiLyVEMSU4NCVEMCVCRSVEMSU4MiVEMCVCRS9hLmpwZ1wiXV0sXG4gIF0pKFxuICAgIFwic2VydmVzIHB1YmxpYy8lcyB1bmRlciBldmVyeSBzcGVsbGluZyBhIGxpbmsgY2FuIGhhdmVcIixcbiAgICBhc3luYyAoZmlsZSwgdXJscykgPT4ge1xuICAgICAgY29uc3QgZGlzcGF0Y2hlciA9IGRpc3BhdGNoZXJXaXRoUHVibGljKFwiYXBwLXBsYXlncm91bmRcIiwgW2ZpbGVdKTtcbiAgICAgIGZvciAoY29uc3QgdXJsIG9mIHVybHMpIHtcbiAgICAgICAgZXhwZWN0KGF3YWl0IGRpc3BhdGNoZXIuZGlzcGF0Y2gocmVxdWVzdCh1cmwpKSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgICAga2luZDogXCJzdGF0aWMtZmlsZVwiLFxuICAgICAgICAgIHNvdXJjZTogXCJwdWJsaWNcIixcbiAgICAgICAgICBmaWxlUGF0aDogYGFwcC1wbGF5Z3JvdW5kL3B1YmxpYy8ke2ZpbGV9YCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSxcbiAgKTtcblxuICBpdChcInNlcnZlcyBwdWJsaWMvIGFoZWFkIG9mIGFuIGFwcCByb3V0ZSBhdCB0aGUgc2FtZSBwYXRobmFtZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gYGFwcC9mYXZpY29uLmljb2AgaXMgYSBidWlsZCBvdXRwdXQgaGVyZTsgYG5leHQgc3RhcnRgIGNoZWNrcyBwdWJsaWMvXG4gICAgLy8gYmVmb3JlIGFwcCBhbmQgcGFnZSByb3V0ZXMsIHNvIGEgbGVmdG92ZXIgYHB1YmxpYy9mYXZpY29uLmljb2Agd2lucy5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyV2l0aFB1YmxpYyhcImFwcC1wbGF5Z3JvdW5kXCIsIFtcbiAgICAgIFwiZmF2aWNvbi5pY29cIixcbiAgICBdKS5kaXNwYXRjaChyZXF1ZXN0KFwiL2Zhdmljb24uaWNvXCIpKTtcbiAgICBleHBlY3QocmVzdWx0KS50b01hdGNoT2JqZWN0KHtcbiAgICAgIGtpbmQ6IFwic3RhdGljLWZpbGVcIixcbiAgICAgIGZpbGVQYXRoOiBcImFwcC1wbGF5Z3JvdW5kL3B1YmxpYy9mYXZpY29uLmljb1wiLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcInN0aWxsIHNlcnZlcyB0aGUgYnVpbGQgb3V0cHV0IHdoZW4gcHVibGljLyBoYXMgbm8gZmlsZSB0aGVyZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGlzcGF0Y2hlcldpdGhQdWJsaWMoXCJhcHAtcGxheWdyb3VuZFwiLCBbXSkuZGlzcGF0Y2goXG4gICAgICByZXF1ZXN0KFwiL2Zhdmljb24uaWNvXCIpLFxuICAgICk7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9NYXRjaE9iamVjdCh7IGtpbmQ6IFwic3RhdGljLWZpbGVcIiwgc291cmNlOiBcInNlcnZlclwiIH0pO1xuICB9KTtcblxuICBpdChcInNlcnZlcyBwdWJsaWMvIHVuZGVyIGJhc2VQYXRoXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBkaXNwYXRjaGVyID0gZGlzcGF0Y2hlcldpdGhQdWJsaWMoXCJhcHAtcGxheWdyb3VuZC1iYXNlLXBhdGhcIiwgW1xuICAgICAgXCJ0ZXN0LnR4dFwiLFxuICAgIF0pO1xuICAgIGV4cGVjdChhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvcHJvZC90ZXN0LnR4dFwiKSkpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAga2luZDogXCJzdGF0aWMtZmlsZVwiLFxuICAgICAgZmlsZVBhdGg6IFwiYXBwLXBsYXlncm91bmQvcHVibGljL3Rlc3QudHh0XCIsXG4gICAgfSk7XG4gICAgZXhwZWN0KChhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvdGVzdC50eHRcIikpKS5raW5kKS5ub3QudG9CZShcbiAgICAgIFwic3RhdGljLWZpbGVcIixcbiAgICApO1xuICB9KTtcblxuICBpdChcInNlcnZlcyBwdWJsaWMvIGluIGFuIGkxOG4gYXBwLCBiYXJlIGFuZCB1bmRlciBhIGRlZmF1bHQgbG9jYWxlIG9ubHlcIiwgYXN5bmMgKCkgPT4ge1xuICAgIC8vIGByZXNvbHZlUm91dGVzYCBwcmVmaXhlcyB0aGUgbG9jYWxlIGJlZm9yZSBpdCBtYXRjaGVzLCBzbyBgL3Rlc3QudHh0YCBpc1xuICAgIC8vIGxvb2tlZCB1cCBhcyBgL2VuLVVTL3Rlc3QudHh0YC4gYG5leHQgc3RhcnRgIHN0cmlwcyB0aGUgZGVmYXVsdCBsb2NhbGUsXG4gICAgLy8gYW5kIGVhY2ggZG9tYWluJ3MsIG9mZiBhIHB1YmxpYy8gcmVxdWVzdCAtIGBmcmAgaXMgZXhhbXBsZS5mcidzIC0gYW5kIG5vXG4gICAgLy8gb3RoZXIuXG4gICAgY29uc3QgZGlzcGF0Y2hlciA9IGRpc3BhdGNoZXJXaXRoUHVibGljKFwicGFnZXMtaTE4blwiLCBbXCJ0ZXN0LnR4dFwiXSk7XG4gICAgZm9yIChjb25zdCB1cmwgb2YgW1wiL3Rlc3QudHh0XCIsIFwiL2VuLVVTL3Rlc3QudHh0XCIsIFwiL2ZyL3Rlc3QudHh0XCJdKSB7XG4gICAgICBleHBlY3QoYXdhaXQgZGlzcGF0Y2hlci5kaXNwYXRjaChyZXF1ZXN0KHVybCkpKS50b01hdGNoT2JqZWN0KHtcbiAgICAgICAga2luZDogXCJzdGF0aWMtZmlsZVwiLFxuICAgICAgICBmaWxlUGF0aDogXCJwYWdlcy1pMThuL3B1YmxpYy90ZXN0LnR4dFwiLFxuICAgICAgfSk7XG4gICAgfVxuICAgIGV4cGVjdChcbiAgICAgIChhd2FpdCBkaXNwYXRjaGVyLmRpc3BhdGNoKHJlcXVlc3QoXCIvbmwtTkwvdGVzdC50eHRcIikpKS5raW5kLFxuICAgICkubm90LnRvQmUoXCJzdGF0aWMtZmlsZVwiKTtcbiAgfSk7XG5cbiAgaXQoXCJrbm93cyBub3RoaW5nIG9mIHB1YmxpYy8gd2hlbiB0aGUgZGVwbG95bWVudCBoYXMgbm9uZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gVGhlIExhbWJkYSB0eXBlczogQ2xvdWRGcm9udCBvciBBUEkgR2F0ZXdheSBhbnN3ZXJzIHB1YmxpYy8gZnJvbSBTMywgdGhlXG4gICAgLy8gcGFja2FnZSBkb2VzIG5vdCBjYXJyeSBpdCwgYW5kIGEgcmVxdWVzdCB0aGF0IGdvdCB0aHJvdWdoIGFueXdheSB0YWtlc1xuICAgIC8vIHRoZSBvcmRpbmFyeSBub3QtZm91bmQgcGF0aCwgbWlkZGxld2FyZSByZXF1ZXN0IGhlYWRlcnMgYW5kIGFsbC5cbiAgICBleHBlY3QoXG4gICAgICBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIikuZGlzcGF0Y2gocmVxdWVzdChcIi90ZXN0LnR4dFwiKSksXG4gICAgKS50b01hdGNoT2JqZWN0KHsga2luZDogXCJub3QtZm91bmRcIiB9KTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoXCJEaXNwYXRjaGVyIGJ1aWxkLW91dHB1dCBzcGVsbGluZ3NcIiwgKCkgPT4ge1xuICBpdChcInNlcnZlcyBhIF9uZXh0L3N0YXRpYyBmaWxlIHdob3NlIG5hbWUgdGhlIEhUTUwgcGVyY2VudC1lbmNvZGVzXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyB3ZWJwYWNrIG5hbWVzIGFuIEFwcCBSb3V0ZXIgY2h1bmsgYWZ0ZXIgaXRzIHJvdXRlIHNlZ21lbnQsIGJyYWNrZXRzIGFuZFxuICAgIC8vIGFsbCwgYW5kIE5leHQuanMgcmVwb3J0cyB0aGUgcGF0aG5hbWUgdW5lbmNvZGVkOyB0aGUgYDxzY3JpcHQ+YCB0YWcgaW5cbiAgICAvLyB0aGUgSFRNTCBhc2tzIGZvciBgJTVCaWQlNURgLlxuICAgIGNvbnN0IGJhc2UgPSBtYW5pZmVzdHNbXCJhcHAtcGxheWdyb3VuZFwiXTtcbiAgICBjb25zdCBwYXRobmFtZSA9IFwiL19uZXh0L3N0YXRpYy9jaHVua3MvYXBwL2lzci9baWRdL3BhZ2UtMDEyM2FiY2QuanNcIjtcbiAgICBjb25zdCBmaWxlUGF0aCA9XG4gICAgICBcImFwcC1wbGF5Z3JvdW5kLy5uZXh0L3N0YXRpYy9jaHVua3MvYXBwL2lzci9baWRdL3BhZ2UtMDEyM2FiY2QuanNcIjtcbiAgICBjb25zdCBtYW5pZmVzdDogQWRhcHRlck1hbmlmZXN0ID0ge1xuICAgICAgLi4uYmFzZSxcbiAgICAgIHN0YXRpY0ZpbGVzOiB7IC4uLmJhc2Uuc3RhdGljRmlsZXMsIFtwYXRobmFtZV06IGZpbGVQYXRoIH0sXG4gICAgICBwYXRobmFtZXM6IFsuLi5iYXNlLnBhdGhuYW1lcywgcGF0aG5hbWVdLFxuICAgIH07XG4gICAgY29uc3QgZGlzcGF0Y2hlciA9IG5ldyBEaXNwYXRjaGVyKHtcbiAgICAgIG1hbmlmZXN0LFxuICAgIH0pO1xuICAgIGZvciAoY29uc3QgdXJsIG9mIFtcbiAgICAgIFwiL19uZXh0L3N0YXRpYy9jaHVua3MvYXBwL2lzci8lNUJpZCU1RC9wYWdlLTAxMjNhYmNkLmpzXCIsXG4gICAgICBwYXRobmFtZSxcbiAgICBdKSB7XG4gICAgICBleHBlY3QoYXdhaXQgZGlzcGF0Y2hlci5kaXNwYXRjaChyZXF1ZXN0KHVybCkpKS50b01hdGNoT2JqZWN0KHtcbiAgICAgICAga2luZDogXCJzdGF0aWMtZmlsZVwiLFxuICAgICAgICBzb3VyY2U6IFwibmV4dC1zdGF0aWNcIixcbiAgICAgICAgZmlsZVBhdGgsXG4gICAgICB9KTtcbiAgICB9XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwiRGlzcGF0Y2hlciBub24tZW50cnlwb2ludCBvdXRjb21lc1wiLCAoKSA9PiB7XG4gIGl0KFwic2VydmVzIGEgYnVpbGQgYXNzZXQgYXMgYSBzdGF0aWMgZmlsZSB3aXRoIGl0cyBpbW11dGFibGUgY2FjaGUgaGVhZGVyXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBtYW5pZmVzdCA9IG1hbmlmZXN0c1tcImFwcC1wbGF5Z3JvdW5kXCJdO1xuICAgIGNvbnN0IHBhdGhuYW1lID0gT2JqZWN0LmtleXMobWFuaWZlc3Quc3RhdGljRmlsZXMpLmZpbmQoKGZpbGUpID0+XG4gICAgICBmaWxlLnN0YXJ0c1dpdGgoXCIvX25leHQvc3RhdGljL1wiKSxcbiAgICApITtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIikuZGlzcGF0Y2goXG4gICAgICByZXF1ZXN0KHBhdGhuYW1lKSxcbiAgICApO1xuICAgIGV4cGVjdChyZXN1bHQua2luZCkudG9CZShcInN0YXRpYy1maWxlXCIpO1xuICAgIGlmIChyZXN1bHQua2luZCAhPT0gXCJzdGF0aWMtZmlsZVwiKSByZXR1cm47XG4gICAgZXhwZWN0KHJlc3VsdC5wYXRobmFtZSkudG9CZShwYXRobmFtZSk7XG4gICAgZXhwZWN0KHJlc3VsdC5yZXNwb25zZUhlYWRlcnMuZ2V0KFwiY2FjaGUtY29udHJvbFwiKSkudG9CZShcbiAgICAgIFwicHVibGljLG1heC1hZ2U9MzE1MzYwMDAsaW1tdXRhYmxlXCIsXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoXCJyb3V0ZXMgL19uZXh0L2ltYWdlIHRvIHRoZSBvcHRpbWl6ZXIsIGJhc2VQYXRoIGluY2x1ZGVkXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBxdWVyeSA9IFwiP3VybD0lMkZmb28ucG5nJnc9NjQwJnE9NzVcIjtcbiAgICBjb25zdCBwbGFpbiA9IGF3YWl0IGRpc3BhdGNoZXJGb3IoXCJhcHAtcGxheWdyb3VuZFwiKS5kaXNwYXRjaChcbiAgICAgIHJlcXVlc3QoYC9fbmV4dC9pbWFnZSR7cXVlcnl9YCksXG4gICAgKTtcbiAgICBleHBlY3QocGxhaW4ua2luZCkudG9CZShcImltYWdlLW9wdGltaXphdGlvblwiKTtcblxuICAgIGNvbnN0IHByZWZpeGVkID0gYXdhaXQgZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kLWJhc2UtcGF0aFwiKS5kaXNwYXRjaChcbiAgICAgIHJlcXVlc3QoYC9wcm9kL19uZXh0L2ltYWdlJHtxdWVyeX1gKSxcbiAgICApO1xuICAgIGV4cGVjdChwcmVmaXhlZC5raW5kKS50b0JlKFwiaW1hZ2Utb3B0aW1pemF0aW9uXCIpO1xuICAgIGlmIChwcmVmaXhlZC5raW5kICE9PSBcImltYWdlLW9wdGltaXphdGlvblwiKSByZXR1cm47XG4gICAgZXhwZWN0KHByZWZpeGVkLnVybC5zZWFyY2hQYXJhbXMuZ2V0KFwidXJsXCIpKS50b0JlKFwiL2Zvby5wbmdcIik7XG4gIH0pO1xuXG4gIGl0KFwicm91dGVzIC9fbmV4dC9pbWFnZSB0byB0aGUgb3B0aW1pemVyIGFoZWFkIG9mIGEgcm9vdCBjYXRjaC1hbGxcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHF1ZXJ5ID0gXCI/dXJsPSUyRmZvby5wbmcmdz02NDAmcT03NVwiO1xuICAgIGNvbnN0IGNhdGNoQWxsID0gZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kLXJvb3QtY2F0Y2gtYWxsXCIpO1xuICAgIGNvbnN0IGltYWdlID0gYXdhaXQgY2F0Y2hBbGwuZGlzcGF0Y2gocmVxdWVzdChgL19uZXh0L2ltYWdlJHtxdWVyeX1gKSk7XG4gICAgZXhwZWN0KGltYWdlLmtpbmQpLnRvQmUoXCJpbWFnZS1vcHRpbWl6YXRpb25cIik7XG4gICAgaWYgKGltYWdlLmtpbmQgIT09IFwiaW1hZ2Utb3B0aW1pemF0aW9uXCIpIHJldHVybjtcbiAgICBleHBlY3QoaW1hZ2UudXJsLnNlYXJjaFBhcmFtcy5nZXQoXCJ1cmxcIikpLnRvQmUoXCIvZm9vLnBuZ1wiKTtcblxuICAgIC8vIFRoZSBjYXRjaC1hbGwgaXRzZWxmIHN0aWxsIHRha2VzIGV2ZXJ5dGhpbmcgZWxzZS5cbiAgICBjb25zdCBwYWdlID0gYXdhaXQgY2F0Y2hBbGwuZGlzcGF0Y2gocmVxdWVzdChcIi9hL2JcIikpO1xuICAgIGV4cGVjdChwYWdlLmtpbmQpLnRvQmUoXCJlbnRyeXBvaW50XCIpO1xuICAgIGlmIChwYWdlLmtpbmQgIT09IFwiZW50cnlwb2ludFwiKSByZXR1cm47XG4gICAgZXhwZWN0KHBhZ2UucmVzb2x2ZWRQYXRobmFtZSkudG9CZShcIi9bWy4uLnJlc3RdXVwiKTtcblxuICAgIGNvbnN0IHByZWZpeGVkQ2F0Y2hBbGwgPSBkaXNwYXRjaGVyRm9yKFxuICAgICAgXCJhcHAtcGxheWdyb3VuZC1iYXNlLXBhdGgtcm9vdC1jYXRjaC1hbGxcIixcbiAgICApO1xuICAgIGNvbnN0IHByZWZpeGVkID0gYXdhaXQgcHJlZml4ZWRDYXRjaEFsbC5kaXNwYXRjaChcbiAgICAgIHJlcXVlc3QoYC9wcm9kL19uZXh0L2ltYWdlJHtxdWVyeX1gKSxcbiAgICApO1xuICAgIGV4cGVjdChwcmVmaXhlZC5raW5kKS50b0JlKFwiaW1hZ2Utb3B0aW1pemF0aW9uXCIpO1xuICAgIC8vIFdpdGhvdXQgd2hpY2ggdGhlIGltYWdlIGFzc2VydGlvbiB3b3VsZCBwYXNzIG9uIGEgZml4dHVyZSB3aXRoIG5vXG4gICAgLy8gY2F0Y2gtYWxsIGF0IGFsbC5cbiAgICBjb25zdCBwcmVmaXhlZFBhZ2UgPSBhd2FpdCBwcmVmaXhlZENhdGNoQWxsLmRpc3BhdGNoKHJlcXVlc3QoXCIvcHJvZC9hL2JcIikpO1xuICAgIGV4cGVjdChwcmVmaXhlZFBhZ2Uua2luZCkudG9CZShcImVudHJ5cG9pbnRcIik7XG4gICAgaWYgKHByZWZpeGVkUGFnZS5raW5kICE9PSBcImVudHJ5cG9pbnRcIikgcmV0dXJuO1xuICAgIGV4cGVjdChwcmVmaXhlZFBhZ2UucmVzb2x2ZWRQYXRobmFtZSkudG9CZShcIi9wcm9kL1tbLi4ucmVzdF1dXCIpO1xuICB9KTtcblxuICBpdChcIm9wdGltaXplcyB0aGUgZGVzdGluYXRpb24gb2YgYSBuZXh0LmNvbmZpZyByZXdyaXRlIG9udG8gL19uZXh0L2ltYWdlXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBtYW5pZmVzdCA9IG1hbmlmZXN0c1tcImFwcC1wbGF5Z3JvdW5kLXJvb3QtY2F0Y2gtYWxsXCJdO1xuICAgIGNvbnN0IHJvdXRpbmcgPSBtYW5pZmVzdC5yb3V0aW5nIGFzIHsgYmVmb3JlRmlsZXM6IHVua25vd25bXSB9O1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG5ldyBEaXNwYXRjaGVyKHtcbiAgICAgIG1hbmlmZXN0OiB7XG4gICAgICAgIC4uLm1hbmlmZXN0LFxuICAgICAgICByb3V0aW5nOiB7XG4gICAgICAgICAgLi4ucm91dGluZyxcbiAgICAgICAgICBiZWZvcmVGaWxlczogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBzb3VyY2U6IFwiL2F2YXRhci86aWRcIixcbiAgICAgICAgICAgICAgc291cmNlUmVnZXg6IFwiXlxcXFwvYXZhdGFyKD86XFxcXC8oW15cXFxcL10rPykpKD86XFxcXC8pPyRcIixcbiAgICAgICAgICAgICAgZGVzdGluYXRpb246IFwiL19uZXh0L2ltYWdlP3VybD0lMkZhdmF0YXJzJTJGJDEucG5nJnc9NjQmcT03NVwiLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIC4uLnJvdXRpbmcuYmVmb3JlRmlsZXMsXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSkuZGlzcGF0Y2gocmVxdWVzdChcIi9hdmF0YXIvNDJcIikpO1xuICAgIGV4cGVjdChyZXN1bHQua2luZCkudG9CZShcImltYWdlLW9wdGltaXphdGlvblwiKTtcbiAgICBpZiAocmVzdWx0LmtpbmQgIT09IFwiaW1hZ2Utb3B0aW1pemF0aW9uXCIpIHJldHVybjtcbiAgICBleHBlY3QocmVzdWx0LnVybC5wYXRobmFtZSkudG9CZShcIi9fbmV4dC9pbWFnZVwiKTtcbiAgICBleHBlY3QocmVzdWx0LnVybC5zZWFyY2hQYXJhbXMuZ2V0KFwidXJsXCIpKS50b0JlKFwiL2F2YXRhcnMvNDIucG5nXCIpO1xuICAgIGV4cGVjdChyZXN1bHQudXJsLnNlYXJjaFBhcmFtcy5nZXQoXCJ3XCIpKS50b0JlKFwiNjRcIik7XG4gIH0pO1xuXG4gIGl0KFwicmVkaXJlY3RzIGEgdHJhaWxpbmcgc2xhc2hcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGRpc3BhdGNoZXJGb3IoXCJhcHAtcGxheWdyb3VuZFwiKS5kaXNwYXRjaChcbiAgICAgIHJlcXVlc3QoXCIvaXNyLzEvXCIpLFxuICAgICk7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9NYXRjaE9iamVjdCh7XG4gICAgICBraW5kOiBcInJlZGlyZWN0XCIsXG4gICAgICBzdGF0dXM6IDMwOCxcbiAgICAgIGxvY2F0aW9uOiBcIi9pc3IvMVwiLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcInNlcnZlcyB0aGUgYXBwJ3Mgcm9vdCBpbiB0aGUgZGVmYXVsdCBsb2NhbGUsIHdpdGggbm8gcmVkaXJlY3QgYXQgYWxsXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBgcmVzb2x2ZVJvdXRlc2AgcHJlZml4ZXMgdGhlIGxvY2FsZSBhcyBgJHtiYXNlUGF0aH0vJHtsb2NhbGV9JHtwYXRobmFtZX1gLFxuICAgIC8vIHdoaWNoIHR1cm5zIHRoZSByb290IGludG8gYC9lbi1VUy9gLCBhbmQgdGhlIHNsYXNoLXN0cmlwcGluZyAzMDggZXZlcnlcbiAgICAvLyBidWlsZCBjb21waWxlcyB0aGVuIGFuc3dlcmVkIGBHRVQgL2Agd2l0aCBhIHJlZGlyZWN0IG5vIGBuZXh0IHN0YXJ0YFxuICAgIC8vIHNlbmRzLiBNZWFzdXJlZCBhZ2FpbnN0IGB0ZXN0L2UyZS9pMThuLXN1cHBvcnQtY2F0Y2hhbGxgLCB3aG9zZSBgL2AgaXMgYVxuICAgIC8vIDIwMC4gU2VlIGBEaXNwYXRjaGVyLndpdGhSb290TG9jYWxlYC5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwicGFnZXMtaTE4blwiKS5kaXNwYXRjaChyZXF1ZXN0KFwiL1wiKSk7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9NYXRjaE9iamVjdCh7IGtpbmQ6IFwic3RhdGljLWZpbGVcIiwgcGF0aG5hbWU6IFwiL2VuLVVTXCIgfSk7XG4gIH0pO1xuXG4gIGl0KFwicmVkaXJlY3RzIHRoZSByb290IHRvIHRoZSBsb2NhbGUgdGhlIHJlcXVlc3QgYXNrZWQgZm9yXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwicGFnZXMtaTE4blwiKS5kaXNwYXRjaChcbiAgICAgIHJlcXVlc3QoXCIvXCIsIHsgXCJhY2NlcHQtbGFuZ3VhZ2VcIjogXCJubC1OTFwiIH0pLFxuICAgICk7XG4gICAgLy8gMzA3IGFuZCBub3QgMzA4LCBiZWNhdXNlIHRoZSBuZXh0IHJlcXVlc3QgbWF5IGRldGVjdCBhIGRpZmZlcmVudCBsb2NhbGUuXG4gICAgLy8gUmVsYXRpdmUgYW5kIHdpdGhvdXQgdGhlIHRyYWlsaW5nIHNsYXNoIGByZXNvbHZlUm91dGVzYCBwdXRzIGluIHRoZVxuICAgIC8vIGxvY2F0aW9uIGl0IGJ1aWxkcyAoYGh0dHBzOi8vZXhhbXBsZS50ZXN0L25sLU5ML2ApLCB3aGljaCBpcyB3aGF0XG4gICAgLy8gYG5leHQgc3RhcnRgIHNlbmRzIGFuZCB3aGF0IGEgdGVzdCBhc3NlcnRpbmcgYGhlYWRlcnMubG9jYXRpb25gIHJlYWRzLlxuICAgIGV4cGVjdChyZXN1bHQpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAga2luZDogXCJyZWRpcmVjdFwiLFxuICAgICAgc3RhdHVzOiAzMDcsXG4gICAgICBsb2NhdGlvbjogXCIvbmwtTkxcIixcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJrZWVwcyBhIHJlZGlyZWN0IHRvIGFub3RoZXIgbG9jYWxlJ3MgZG9tYWluIGFic29sdXRlXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBUaGUgZml4dHVyZSBtYXBzIGBmcmAgb250byBleGFtcGxlLmZyLCBhbmQgYW4gYWJzb2x1dGUgbG9jYXRpb24gaXMgdGhlXG4gICAgLy8gb25seSB3YXkgdG8gbGVhdmUgdGhlIG9yaWdpbi5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwicGFnZXMtaTE4blwiKS5kaXNwYXRjaChcbiAgICAgIHJlcXVlc3QoXCIvXCIsIHsgY29va2llOiBcIk5FWFRfTE9DQUxFPWZyXCIgfSksXG4gICAgKTtcbiAgICBleHBlY3QocmVzdWx0KS50b01hdGNoT2JqZWN0KHtcbiAgICAgIGtpbmQ6IFwicmVkaXJlY3RcIixcbiAgICAgIHN0YXR1czogMzA3LFxuICAgICAgbG9jYXRpb246IFwiaHR0cHM6Ly9leGFtcGxlLmZyL1wiLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcInNlcnZlcyB0aGUgcm9vdCBvZiBhIGB0cmFpbGluZ1NsYXNoYCBpMThuIGFwcCB3aXRoIG5vIHJlZGlyZWN0XCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBXaXRoIGB0cmFpbGluZ1NsYXNoOiB0cnVlYCwgYG5leHQgYnVpbGRgIGNvbXBpbGVzIHRoZSBzbGFzaC0qYWRkaW5nKiAzMDhcbiAgICAvLyAoYGxvYWQtY3VzdG9tLXJvdXRlc2AnIGAvOm5vdGZpbGUoLi4uKWAg4oaSIGAvOm5vdGZpbGUvYCwgYGxvY2FsZTogZmFsc2VgKVxuICAgIC8vIGluIHBsYWNlIG9mIHRoZSBzdHJpcHBpbmcgb25lLCBhbmQgcHJlZml4aW5nIHRoZSByb290IGFzIGAvZW4tVVNgIG1hZGVcbiAgICAvLyB0aGF0IHJ1bGUgYW5zd2VyIGBHRVQgL2Agd2l0aCBhIDMwOCB0byBgL2VuLVVTL2AsIHdoZXJlIGBuZXh0IHN0YXJ0YFxuICAgIC8vIGFuc3dlcnMgMjAwLlxuICAgIGNvbnN0IHdpdGhTbGFzaCA9IHN0cnVjdHVyZWRDbG9uZShcbiAgICAgIHBhZ2VzSTE4biBhcyB1bmtub3duLFxuICAgICkgYXMgQnVpbGRDb21wbGV0ZUNvbnRleHQ7XG4gICAgKHdpdGhTbGFzaC5jb25maWcgYXMgeyB0cmFpbGluZ1NsYXNoOiBib29sZWFuIH0pLnRyYWlsaW5nU2xhc2ggPSB0cnVlO1xuICAgIGNvbnN0IHJvdXRpbmcgPSB3aXRoU2xhc2gucm91dGluZyBhcyB7XG4gICAgICBiZWZvcmVNaWRkbGV3YXJlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdO1xuICAgIH07XG4gICAgcm91dGluZy5iZWZvcmVNaWRkbGV3YXJlID0gW1xuICAgICAge1xuICAgICAgICBzb3VyY2U6IFwiLzpub3RmaWxlKCg/IVxcXFwud2VsbC1rbm93big/Oi8uKik/KSg/OlteL10rLykqW14vXFxcXC5dKylcIixcbiAgICAgICAgc291cmNlUmVnZXg6XG4gICAgICAgICAgXCJeKD86XFxcXC8oKD8hXFxcXC53ZWxsLWtub3duKD86XFxcXC8uKik/KSg/OlteXFxcXC9dK1xcXFwvKSpbXlxcXFwvXFxcXC5dKykpJFwiLFxuICAgICAgICBoZWFkZXJzOiB7IExvY2F0aW9uOiBcIi8kMS9cIiB9LFxuICAgICAgICBzdGF0dXM6IDMwOCxcbiAgICAgICAgcHJpb3JpdHk6IHRydWUsXG4gICAgICB9LFxuICAgICAgLi4ucm91dGluZy5iZWZvcmVNaWRkbGV3YXJlLmZpbHRlcigocm91dGUpID0+IHJvdXRlLnN0YXR1cyAhPT0gMzA4KSxcbiAgICBdO1xuICAgIGNvbnN0IGRpc3BhdGNoZXIgPSBuZXcgRGlzcGF0Y2hlcih7IG1hbmlmZXN0OiBtYW5pZmVzdE9mKHdpdGhTbGFzaCkgfSk7XG5cbiAgICBleHBlY3QoYXdhaXQgZGlzcGF0Y2hlci5kaXNwYXRjaChyZXF1ZXN0KFwiL1wiKSkpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAga2luZDogXCJzdGF0aWMtZmlsZVwiLFxuICAgICAgcGF0aG5hbWU6IFwiL2VuLVVTXCIsXG4gICAgfSk7XG4gICAgLy8gVGhlIHJ1bGUgaXRzZWxmIGlzIGxpdmU6IHRoZSBzbGFzaGxlc3MgbG9jYWxlIHJvb3Qgc3RpbGwgZ2V0cyBpdC5cbiAgICBleHBlY3QoYXdhaXQgZGlzcGF0Y2hlci5kaXNwYXRjaChyZXF1ZXN0KFwiL2VuLVVTXCIpKSkudG9NYXRjaE9iamVjdCh7XG4gICAgICBraW5kOiBcInJlZGlyZWN0XCIsXG4gICAgICBzdGF0dXM6IDMwOCxcbiAgICAgIGxvY2F0aW9uOiBcIi9lbi1VUy9cIixcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJzdGlsbCBzdHJpcHMgYSB0cmFpbGluZyBzbGFzaCB0aGUgcmVxdWVzdCBpdHNlbGYgY2FycmllZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGlzcGF0Y2hlckZvcihcInBhZ2VzLWkxOG5cIikuZGlzcGF0Y2goXG4gICAgICByZXF1ZXN0KFwiL25sLU5ML1wiKSxcbiAgICApO1xuICAgIGV4cGVjdChyZXN1bHQpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAga2luZDogXCJyZWRpcmVjdFwiLFxuICAgICAgc3RhdHVzOiAzMDgsXG4gICAgICBsb2NhdGlvbjogXCIvbmwtTkxcIixcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJyZXR1cm5zIGEgZGlyZWN0IHJlc3BvbnNlIGZvciBhIHJvdXRlIHRoYXQgZm9yY2VzIGEgc3RhdHVzXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBiYXNlID0gbWFuaWZlc3RzW1wiYXBwLXBsYXlncm91bmRcIl07XG4gICAgY29uc3QgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdCA9IHtcbiAgICAgIC4uLmJhc2UsXG4gICAgICBtaWRkbGV3YXJlOiBudWxsLFxuICAgICAgcm91dGluZzoge1xuICAgICAgICAuLi4oYmFzZS5yb3V0aW5nIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSxcbiAgICAgICAgYmVmb3JlRmlsZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzb3VyY2VSZWdleDogXCJeL2Jsb2NrZWQkXCIsXG4gICAgICAgICAgICBzdGF0dXM6IDQwMyxcbiAgICAgICAgICAgIGhlYWRlcnM6IHsgXCJ4LXdoeVwiOiBcIm5vXCIgfSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG5ldyBEaXNwYXRjaGVyKHsgbWFuaWZlc3QgfSkuZGlzcGF0Y2goXG4gICAgICByZXF1ZXN0KFwiL2Jsb2NrZWRcIiksXG4gICAgKTtcbiAgICBleHBlY3QocmVzdWx0KS50b01hdGNoT2JqZWN0KHsga2luZDogXCJyZXNwb25zZVwiLCBzdGF0dXM6IDQwMyB9KTtcbiAgICBleHBlY3QocmVzdWx0LnJlc3BvbnNlSGVhZGVycy5nZXQoXCJ4LXdoeVwiKSkudG9CZShcIm5vXCIpO1xuICB9KTtcblxuICBpdChcInJlcG9ydHMgYW4gdW5rbm93biBwYXRoIGFzIG5vdCBmb3VuZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kXCIpLmRpc3BhdGNoKFxuICAgICAgcmVxdWVzdChcIi9kZWZpbml0ZWx5LW5vdC1hLXJvdXRlXCIpLFxuICAgICk7XG4gICAgZXhwZWN0KHJlc3VsdC5raW5kKS50b0JlKFwibm90LWZvdW5kXCIpO1xuICAgIGlmIChyZXN1bHQua2luZCAhPT0gXCJub3QtZm91bmRcIikgcmV0dXJuO1xuICAgIGV4cGVjdChyZXN1bHQucGF0aG5hbWUpLnRvQmUoXCIvZGVmaW5pdGVseS1ub3QtYS1yb3V0ZVwiKTtcbiAgfSk7XG5cbiAgaXQoXCJyZXNvbHZlcyB0aGUgNDA0IHRhcmdldCBwZXIgcm91dGVyIGZsYXZvclwiLCAoKSA9PiB7XG4gICAgZXhwZWN0KHN0YXR1c1RhcmdldE9mKG1hbmlmZXN0c1tcImFwcC1wbGF5Z3JvdW5kXCJdLCA0MDQpKS50b01hdGNoT2JqZWN0KHtcbiAgICAgIGtpbmQ6IFwiZW50cnlwb2ludFwiLFxuICAgICAgcGF0aG5hbWU6IFwiL19ub3QtZm91bmRcIixcbiAgICB9KTtcbiAgICBleHBlY3QoXG4gICAgICBzdGF0dXNUYXJnZXRPZihtYW5pZmVzdHNbXCJhcHAtcGxheWdyb3VuZC1iYXNlLXBhdGhcIl0sIDQwNCksXG4gICAgKS50b01hdGNoT2JqZWN0KHtcbiAgICAgIGtpbmQ6IFwiZW50cnlwb2ludFwiLFxuICAgICAgcGF0aG5hbWU6IFwiL3Byb2QvX25vdC1mb3VuZFwiLFxuICAgIH0pO1xuICAgIC8vIFBhZ2VzIFJvdXRlciBoYXMgbm8gYC9fbm90LWZvdW5kYCwgYW5kIGBuZXh0IGJ1aWxkYCBwcmVyZW5kZXJzIGl0cyA0MDQg4oCUXG4gICAgLy8gb25lIHBlciBsb2NhbGUg4oCUIHdoaWNoIGBuZXh0IHN0YXJ0YCBzZXJ2ZXMgYWhlYWQgb2YgYC9fZXJyb3JgLlxuICAgIGV4cGVjdChzdGF0dXNUYXJnZXRPZihtYW5pZmVzdHNbXCJwYWdlcy1pMThuXCJdLCA0MDQpKS50b0VxdWFsKHtcbiAgICAgIGtpbmQ6IFwic3RhdGljLWZpbGVcIixcbiAgICAgIHBhdGhuYW1lOiBcIi9lbi1VUy80MDRcIixcbiAgICAgIGZpbGVQYXRoOiBtYW5pZmVzdHNbXCJwYWdlcy1pMThuXCJdLnN0YXRpY0ZpbGVzW1wiL2VuLVVTLzQwNFwiXSxcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJzZXJ2ZXMgdGhlIHByZXJlbmRlcmVkIDQwNCBvZiB0aGUgcmVxdWVzdCdzIGxvY2FsZVwiLCAoKSA9PiB7XG4gICAgLy8gRXZlcnkgUGFnZXMgYnVpbGQgaGFzIGAvX2Vycm9yYCwgc28gY2hlY2tpbmcgaXQgZmlyc3QgbWFkZSB0aGVcbiAgICAvLyBwcmVyZW5kZXJlZCA0MDQg4oCUIHRoZSBhcHAncyBgcGFnZXMvNDA0LmpzYCDigJQgZGVhZCBjb2RlOyBhbmQgdW5kZXIgaTE4blxuICAgIC8vIHRoZSBwcmVyZW5kZXIgaXMgb25seSBldmVyIGtleWVkIGJ5IGxvY2FsZSwgbmV2ZXIgYXMgYSBiYXJlIGAvNDA0YC5cbiAgICBjb25zdCBkaXNwYXRjaGVyID0gZGlzcGF0Y2hlckZvcihcInBhZ2VzLWkxOG5cIik7XG4gICAgY29uc3QgeyBzdGF0aWNGaWxlcyB9ID0gbWFuaWZlc3RzW1wicGFnZXMtaTE4blwiXTtcbiAgICBjb25zdCBhdCA9ICh1cmw6IHN0cmluZykgPT4gZGlzcGF0Y2hlci5ub3RGb3VuZEZvcihuZXcgVVJMKHVybCwgT1JJR0lOKSk7XG5cbiAgICBleHBlY3QoYXQoXCIvZnIvbm9wZVwiKSkudG9NYXRjaE9iamVjdCh7IGZpbGVQYXRoOiBzdGF0aWNGaWxlc1tcIi9mci80MDRcIl0gfSk7XG4gICAgZXhwZWN0KGF0KFwiL05MLW5sL25vcGVcIikpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAgZmlsZVBhdGg6IHN0YXRpY0ZpbGVzW1wiL25sLU5MLzQwNFwiXSxcbiAgICB9KTtcbiAgICBleHBlY3QoYXQoXCIvbm9wZVwiKSkudG9NYXRjaE9iamVjdCh7IGZpbGVQYXRoOiBzdGF0aWNGaWxlc1tcIi9lbi1VUy80MDRcIl0gfSk7XG4gICAgLy8gTm8gbG9jYWxlIGluIHRoZSBwYXRoOiB0aGUgZG9tYWluJ3MgZGVmYXVsdCwgYXMgYG5leHQgc3RhcnRgIHJlbmRlcnMgaXQuXG4gICAgZXhwZWN0KGF0KFwiaHR0cHM6Ly9leGFtcGxlLmZyL25vcGVcIikpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAgZmlsZVBhdGg6IHN0YXRpY0ZpbGVzW1wiL2ZyLzQwNFwiXSxcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJmYWxscyBiYWNrIHRvIC9fZXJyb3Igd2hlbiBubyA0MDQgd2FzIHByZXJlbmRlcmVkXCIsICgpID0+IHtcbiAgICAvLyBXaGF0IGEgYHBhZ2VzL19hcHAuanNgIHdpdGggYGdldEluaXRpYWxQcm9wc2AgYnVpbGRzIHdpdGhvdXQgYVxuICAgIC8vIGBwYWdlcy80MDQuanNgOiBgbmV4dCBidWlsZGAgdGhlbiBwcmVyZW5kZXJzIG5vIDQwNCBhdCBhbGwuXG4gICAgY29uc3QgYmFzZSA9IG1hbmlmZXN0c1tcInBhZ2VzLWkxOG5cIl07XG4gICAgY29uc3Qgd2l0aG91dDQwNCA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgIE9iamVjdC5lbnRyaWVzKGJhc2Uuc3RhdGljRmlsZXMpLmZpbHRlcigoW2tleV0pID0+ICFrZXkuZW5kc1dpdGgoXCIvNDA0XCIpKSxcbiAgICApO1xuICAgIGV4cGVjdChcbiAgICAgIHN0YXR1c1RhcmdldE9mKHsgLi4uYmFzZSwgc3RhdGljRmlsZXM6IHdpdGhvdXQ0MDQgfSwgNDA0KSxcbiAgICApLnRvTWF0Y2hPYmplY3QoeyBraW5kOiBcImVudHJ5cG9pbnRcIiwgcGF0aG5hbWU6IFwiL19lcnJvclwiIH0pO1xuICB9KTtcblxuICBpdChcInByZWZlcnMgYW4gaW52b2NhYmxlIGN1c3RvbSAvNDA0IG92ZXIgL19lcnJvclwiLCAoKSA9PiB7XG4gICAgLy8gV2hhdCBgcGFnZXMvNDA0LmpzYCBwbHVzIGEgYHBhZ2VzL19hcHAuanNgIHdpdGggYGdldEluaXRpYWxQcm9wc2AgYnVpbGRzOlxuICAgIC8vIHRoZSA0MDQgY2Fubm90IGJlIHByZXJlbmRlcmVkLCBzbyBpdCBhcnJpdmVzIGFzIGFuIGVudHJ5cG9pbnQgYmVzaWRlXG4gICAgLy8gYC9fZXJyb3JgLiBTZXJ2aW5nIGAvX2Vycm9yYCB0aGVyZSBtZWFucyB0aGUgYnVpbHQtaW4gXCI0MDQ6IFRoaXMgcGFnZVxuICAgIC8vIGNvdWxkIG5vdCBiZSBmb3VuZFwiIHJlcGxhY2VzIHRoZSBhcHAncyBvd24g4oCUIGB0ZXN0L2UyZS80MDQtcGFnZS1hcHBgLlxuICAgIGNvbnN0IGJhc2UgPSBtYW5pZmVzdHNbXCJwYWdlcy1pMThuXCJdO1xuICAgIGNvbnN0IHdpdGhDdXN0b200MDQ6IEFkYXB0ZXJNYW5pZmVzdCA9IHtcbiAgICAgIC4uLmJhc2UsXG4gICAgICBlbnRyeXBvaW50czoge1xuICAgICAgICAuLi5iYXNlLmVudHJ5cG9pbnRzLFxuICAgICAgICBcIi80MDRcIjogeyAuLi5iYXNlLmVudHJ5cG9pbnRzW1wiL19lcnJvclwiXSwgaWQ6IFwiLzQwNFwiIH0sXG4gICAgICB9LFxuICAgIH07XG4gICAgZXhwZWN0KHN0YXR1c1RhcmdldE9mKHdpdGhDdXN0b200MDQsIDQwNCkpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAga2luZDogXCJlbnRyeXBvaW50XCIsXG4gICAgICBwYXRobmFtZTogXCIvNDA0XCIsXG4gICAgfSk7XG4gICAgLy8gQXBwIFJvdXRlciBzdGlsbCB3aW5zIG92ZXIgYm90aDogYC9fbm90LWZvdW5kYCBpcyB3aGF0IG5leHQgbG9va3MgZm9yXG4gICAgLy8gZmlyc3QsIGFuZCBhbiBhcHAgd2l0aCBib3RoIHJvdXRlcnMgaGFzIGFsbCB0aHJlZS5cbiAgICBleHBlY3QoXG4gICAgICBzdGF0dXNUYXJnZXRPZihcbiAgICAgICAge1xuICAgICAgICAgIC4uLndpdGhDdXN0b200MDQsXG4gICAgICAgICAgZW50cnlwb2ludHM6IHtcbiAgICAgICAgICAgIC4uLndpdGhDdXN0b200MDQuZW50cnlwb2ludHMsXG4gICAgICAgICAgICBcIi9fbm90LWZvdW5kXCI6IHtcbiAgICAgICAgICAgICAgLi4uYmFzZS5lbnRyeXBvaW50c1tcIi9fZXJyb3JcIl0sXG4gICAgICAgICAgICAgIGlkOiBcIi9fbm90LWZvdW5kXCIsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIDQwNCxcbiAgICAgICksXG4gICAgKS50b01hdGNoT2JqZWN0KHsga2luZDogXCJlbnRyeXBvaW50XCIsIHBhdGhuYW1lOiBcIi9fbm90LWZvdW5kXCIgfSk7XG4gIH0pO1xuXG4gIGl0KFwiZmFsbHMgYmFjayB0byBhIHByZXJlbmRlcmVkIDQwNCwgdGhlbiB0byBub3RoaW5nXCIsICgpID0+IHtcbiAgICBjb25zdCBiYXNlID0gbWFuaWZlc3RzW1wiYXBwLXBsYXlncm91bmRcIl07XG4gICAgY29uc3Qgd2l0aG91dEVudHJ5cG9pbnRzOiBBZGFwdGVyTWFuaWZlc3QgPSB7XG4gICAgICAuLi5iYXNlLFxuICAgICAgZW50cnlwb2ludHM6IHt9LFxuICAgICAgbWlkZGxld2FyZTogbnVsbCxcbiAgICB9O1xuICAgIGV4cGVjdChzdGF0dXNUYXJnZXRPZih3aXRob3V0RW50cnlwb2ludHMsIDQwNCkpLnRvRXF1YWwoe1xuICAgICAga2luZDogXCJzdGF0aWMtZmlsZVwiLFxuICAgICAgcGF0aG5hbWU6IFwiLzQwNFwiLFxuICAgICAgZmlsZVBhdGg6IGJhc2Uuc3RhdGljRmlsZXNbXCIvNDA0XCJdLFxuICAgIH0pO1xuICAgIGV4cGVjdChcbiAgICAgIHN0YXR1c1RhcmdldE9mKHsgLi4ud2l0aG91dEVudHJ5cG9pbnRzLCBzdGF0aWNGaWxlczoge30gfSwgNDA0KSxcbiAgICApLnRvRXF1YWwoeyBraW5kOiBcIm5vbmVcIiB9KTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoXCJ0aGUgNTAwIGxhZGRlclwiLCAoKSA9PiB7XG4gIGl0KFwicHJlZmVycyB0aGUgcHJlcmVuZGVyZWQgLzUwMCBuZXh0IGVtaXRzIGJ5IGRlZmF1bHRcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGJhc2UgPSBtYW5pZmVzdHNbXCJhcHAtcGxheWdyb3VuZFwiXTtcbiAgICBleHBlY3Qoc3RhdHVzVGFyZ2V0T2YoYmFzZSwgNTAwKSkudG9FcXVhbCh7XG4gICAgICBraW5kOiBcInN0YXRpYy1maWxlXCIsXG4gICAgICBwYXRobmFtZTogXCIvNTAwXCIsXG4gICAgICBmaWxlUGF0aDogYmFzZS5zdGF0aWNGaWxlc1tcIi81MDBcIl0sXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwicHJlZmVycyBhbiBpbnZvY2FibGUgLzUwMCBvdmVyIHRoZSBwcmVyZW5kZXJlZCBvbmVcIiwgKCkgPT4ge1xuICAgIC8vIFdoYXQgYSBgcGFnZXMvNTAwLmpzYCB0aGF0IGNhbm5vdCBiZSBzdGF0aWMtb3B0aW1pemVkIGJ1aWxkcy5cbiAgICBjb25zdCBiYXNlID0gbWFuaWZlc3RzW1wicGFnZXMtaTE4blwiXTtcbiAgICBleHBlY3QoXG4gICAgICBzdGF0dXNUYXJnZXRPZihcbiAgICAgICAge1xuICAgICAgICAgIC4uLmJhc2UsXG4gICAgICAgICAgZW50cnlwb2ludHM6IHtcbiAgICAgICAgICAgIC4uLmJhc2UuZW50cnlwb2ludHMsXG4gICAgICAgICAgICBcIi81MDBcIjogeyAuLi5iYXNlLmVudHJ5cG9pbnRzW1wiL19lcnJvclwiXSwgaWQ6IFwiLzUwMFwiIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgNTAwLFxuICAgICAgKSxcbiAgICApLnRvTWF0Y2hPYmplY3QoeyBraW5kOiBcImVudHJ5cG9pbnRcIiwgcGF0aG5hbWU6IFwiLzUwMFwiIH0pO1xuICB9KTtcblxuICBpdChcImZhbGxzIGJhY2sgdG8gL19lcnJvciwgdGhlbiB0byBub3RoaW5nXCIsICgpID0+IHtcbiAgICAvLyBgL19lcnJvcmAgaXMgd2hlcmUgYSBjdXN0b20gZXJyb3IgcGFnZSBsYW5kcyB3aGVuIGl0IGhhc1xuICAgIC8vIGBnZXRJbml0aWFsUHJvcHNgIOKAlCB0aGUgY2FzZSBgdGVzdC9lMmUvYXN5bmMtbW9kdWxlc2AgbWVhc3VyZXMuXG4gICAgY29uc3QgYmFzZSA9IG1hbmlmZXN0c1tcInBhZ2VzLWkxOG5cIl07XG4gICAgZXhwZWN0KHN0YXR1c1RhcmdldE9mKHsgLi4uYmFzZSwgc3RhdGljRmlsZXM6IHt9IH0sIDUwMCkpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAga2luZDogXCJlbnRyeXBvaW50XCIsXG4gICAgICBwYXRobmFtZTogXCIvX2Vycm9yXCIsXG4gICAgfSk7XG4gICAgZXhwZWN0KFxuICAgICAgc3RhdHVzVGFyZ2V0T2YoeyAuLi5iYXNlLCBzdGF0aWNGaWxlczoge30sIGVudHJ5cG9pbnRzOiB7fSB9LCA1MDApLFxuICAgICkudG9FcXVhbCh7IGtpbmQ6IFwibm9uZVwiIH0pO1xuICB9KTtcblxuICBpdChcInNlcnZlcyB0aGUgcHJlcmVuZGVyZWQgNTAwIG9mIHRoZSByZXF1ZXN0J3MgbG9jYWxlXCIsICgpID0+IHtcbiAgICAvLyBVbmRlciBpMThuIHRoZSBwcmVyZW5kZXJlZCA1MDAgaXMga2V5ZWQgb25seSBieSBsb2NhbGUsIG5ldmVyIGFzIGEgYmFyZVxuICAgIC8vIGAvNTAwYCwgc28gbG9va2luZyB1cCBgLzUwMGAgYWxvbmUgYWx3YXlzIGZlbGwgdGhyb3VnaCB0byBgL19lcnJvcmAuXG4gICAgY29uc3QgYmFzZSA9IG1hbmlmZXN0c1tcInBhZ2VzLWkxOG5cIl07XG4gICAgY29uc3QgZXJyb3JUYXJnZXRGb3IgPSBzdGF0dXNUYXJnZXRzKGJhc2UsIDUwMCk7XG4gICAgY29uc3QgYXQgPSAodXJsOiBzdHJpbmcpID0+IGVycm9yVGFyZ2V0Rm9yKG5ldyBVUkwodXJsLCBPUklHSU4pKTtcblxuICAgIGV4cGVjdChhdChcIi9mci9zc3JcIikpLnRvRXF1YWwoe1xuICAgICAga2luZDogXCJzdGF0aWMtZmlsZVwiLFxuICAgICAgcGF0aG5hbWU6IFwiL2ZyLzUwMFwiLFxuICAgICAgZmlsZVBhdGg6IGJhc2Uuc3RhdGljRmlsZXNbXCIvZnIvNTAwXCJdLFxuICAgIH0pO1xuICAgIGV4cGVjdChhdChcIi9zc3JcIikpLnRvTWF0Y2hPYmplY3QoeyBwYXRobmFtZTogXCIvZW4tVVMvNTAwXCIgfSk7XG4gICAgLy8gTm8gbG9jYWxlIGluIHRoZSBwYXRoOiB0aGUgZG9tYWluJ3MgZGVmYXVsdCwgYXMgYG5leHQgc3RhcnRgIHJlbmRlcnMgaXQuXG4gICAgZXhwZWN0KGF0KFwiaHR0cHM6Ly9leGFtcGxlLmZyL3NzclwiKSkudG9NYXRjaE9iamVjdCh7XG4gICAgICBwYXRobmFtZTogXCIvZnIvNTAwXCIsXG4gICAgfSk7XG4gICAgLy8gQSByZXF1ZXN0IHdob3NlIFVSTCBjb3VsZCBub3QgYmUgcGFyc2VkIGdldHMgdGhlIGRlZmF1bHQgbG9jYWxlJ3MuXG4gICAgZXhwZWN0KGVycm9yVGFyZ2V0Rm9yKHVuZGVmaW5lZCkpLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAgcGF0aG5hbWU6IFwiL2VuLVVTLzUwMFwiLFxuICAgIH0pO1xuICAgIGV4cGVjdChzdGF0dXNUYXJnZXRPZihiYXNlLCA1MDApKS50b01hdGNoT2JqZWN0KHsgcGF0aG5hbWU6IFwiL2VuLVVTLzUwMFwiIH0pO1xuICB9KTtcblxuICBpdChcImxvb2tzIGZvciB0aGUgZXJyb3IgcGFnZSB1bmRlciB0aGUgYXBwJ3MgYmFzZVBhdGhcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGJhc2UgPSBtYW5pZmVzdHNbXCJhcHAtcGxheWdyb3VuZC1iYXNlLXBhdGhcIl07XG4gICAgZXhwZWN0KHN0YXR1c1RhcmdldE9mKGJhc2UsIDUwMCkpLnRvTWF0Y2hPYmplY3QoeyBwYXRobmFtZTogXCIvcHJvZC81MDBcIiB9KTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoXCJ0b1JlZGlyZWN0XCIsICgpID0+IHtcbiAgaXQoXCJwcmVmZXJzIHRoZSBkb2N1bWVudGVkIHJlZGlyZWN0IGZpZWxkXCIsICgpID0+IHtcbiAgICAvLyBgcmVzb2x2ZVJvdXRlc2AgZG9lcyBub3QgcG9wdWxhdGUgYFJlc29sdmVSb3V0ZXNSZXN1bHQucmVkaXJlY3RgIGluXG4gICAgLy8gbmV4dCAxNi4zLjUg4oCUIGV2ZXJ5IHJlZGlyZWN0IGFycml2ZXMgYXMgYmFyZSBzdGF0dXMgKyBgbG9jYXRpb25gIOKAlCBzbyB0aGlzXG4gICAgLy8gaXMgdGhlIG9ubHkgY292ZXJhZ2UgdGhhdCBicmFuY2ggY2FuIGhhdmUgdW50aWwgaXQgZG9lcy5cbiAgICBleHBlY3QoXG4gICAgICB0b1JlZGlyZWN0KFxuICAgICAgICB7IHJlZGlyZWN0OiB7IHVybDogbmV3IFVSTChcImh0dHBzOi8vZS50ZXN0L3hcIiksIHN0YXR1czogMzAxIH0gfSxcbiAgICAgICAgbmV3IEhlYWRlcnMoKSxcbiAgICAgICksXG4gICAgKS50b0VxdWFsKHsgbG9jYXRpb246IFwiaHR0cHM6Ly9lLnRlc3QveFwiLCBzdGF0dXM6IDMwMSB9KTtcbiAgfSk7XG5cbiAgaXQoXCJpZ25vcmVzIGEgbG9jYXRpb24gaGVhZGVyIG9uIGEgbm9uLTN4eCBzdGF0dXNcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGhlYWRlcnMgPSBuZXcgSGVhZGVycyh7IGxvY2F0aW9uOiBcIi94XCIgfSk7XG4gICAgZXhwZWN0KHRvUmVkaXJlY3QoeyBzdGF0dXM6IDIwMCB9LCBoZWFkZXJzKSkudG9CZVVuZGVmaW5lZCgpO1xuICAgIGV4cGVjdCh0b1JlZGlyZWN0KHsgc3RhdHVzOiA0MDMgfSwgaGVhZGVycykpLnRvQmVVbmRlZmluZWQoKTtcbiAgICBleHBlY3QodG9SZWRpcmVjdCh7fSwgaGVhZGVycykpLnRvQmVVbmRlZmluZWQoKTtcbiAgICBleHBlY3QodG9SZWRpcmVjdCh7IHN0YXR1czogMzA4IH0sIG5ldyBIZWFkZXJzKCkpKS50b0JlVW5kZWZpbmVkKCk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwiRGlzcGF0Y2hlciBtaWRkbGV3YXJlIGhhbmRsaW5nXCIsICgpID0+IHtcbiAgaXQoXCJyZXBvcnRzIGEgbWlkZGxld2FyZSByZXNwb25zZSB3aXRob3V0IHJlc29sdmluZyBhIHJvdXRlXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIiwgYXN5bmMgKCkgPT4gKHtcbiAgICAgIGJvZHlTZW50OiB0cnVlLFxuICAgICAgcmVzcG9uc2VIZWFkZXJzOiBuZXcgSGVhZGVycyh7IFwieC1td1wiOiBcInJlc3BvbmRlZFwiIH0pLFxuICAgIH0pKS5kaXNwYXRjaChyZXF1ZXN0KFwiL2lzci8xXCIpKTtcbiAgICBleHBlY3QocmVzdWx0LmtpbmQpLnRvQmUoXCJtaWRkbGV3YXJlLXJlc3BvbmRlZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJzZW5kcyBuZXh0LmNvbmZpZyBoZWFkZXJzKCkgd2l0aCBhIHJlc3BvbnNlIG1pZGRsZXdhcmUgd3JvdGVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIC8vIGBhcHAtcGxheWdyb3VuZGAncyBgaGVhZGVycygpYCBzZXRzIHRoaXMgb24gYC9hcGkvZWNob2A7IGBuZXh0IHN0YXJ0YFxuICAgIC8vIHNlbmRzIGl0IHdpdGggYSBtaWRkbGV3YXJlIDQwMSB0aGVyZSB0b28uXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kXCIsIGFzeW5jICgpID0+ICh7XG4gICAgICBib2R5U2VudDogdHJ1ZSxcbiAgICB9KSkuZGlzcGF0Y2gocmVxdWVzdChcIi9hcGkvZWNob1wiKSk7XG4gICAgZXhwZWN0KHJlc3VsdC5raW5kKS50b0JlKFwibWlkZGxld2FyZS1yZXNwb25kZWRcIik7XG4gICAgZXhwZWN0KHJlc3VsdC5yZXNwb25zZUhlYWRlcnMuZ2V0KFwieC1lMmUtY29uZmlnLWhlYWRlclwiKSkudG9CZShcbiAgICAgIFwiZnJvbS1uZXh0LWNvbmZpZ1wiLFxuICAgICk7XG5cbiAgICBjb25zdCBvdGhlciA9IGF3YWl0IGRpc3BhdGNoZXJGb3IoXCJhcHAtcGxheWdyb3VuZFwiLCBhc3luYyAoKSA9PiAoe1xuICAgICAgYm9keVNlbnQ6IHRydWUsXG4gICAgfSkpLmRpc3BhdGNoKHJlcXVlc3QoXCIvaXNyLzFcIikpO1xuICAgIGV4cGVjdChvdGhlci5yZXNwb25zZUhlYWRlcnMuaGFzKFwieC1lMmUtY29uZmlnLWhlYWRlclwiKSkudG9CZShmYWxzZSk7XG4gIH0pO1xuXG4gIGl0KFwibm9ybWFsaXplcyBhIG1pZGRsZXdhcmUgcmVkaXJlY3QgdG8gYSBzYW1lLW9yaWdpbiBwYXRoXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIiwgYXN5bmMgKCkgPT4gKHtcbiAgICAgIHJlZGlyZWN0OiB7IHVybDogbmV3IFVSTChcIi9sb2dpblwiLCBPUklHSU4pLCBzdGF0dXM6IDMwNyB9LFxuICAgIH0pKS5kaXNwYXRjaChyZXF1ZXN0KFwiL2lzci8xXCIpKTtcbiAgICBleHBlY3QocmVzdWx0KS50b01hdGNoT2JqZWN0KHtcbiAgICAgIGtpbmQ6IFwicmVkaXJlY3RcIixcbiAgICAgIHN0YXR1czogMzA3LFxuICAgICAgLy8gYE5leHRSZXNwb25zZS5yZWRpcmVjdChuZXcgVVJMKFwiL2xvZ2luXCIsIHJlcXVlc3QudXJsKSlgIGlzIGhvdyBldmVyeVxuICAgICAgLy8gbWlkZGxld2FyZSBzcGVsbHMgdGhpcywgYW5kIE5leHQuanMgc2VuZHMgdGhlIHBhdGg6IGBAbmV4dC9yb3V0aW5nYCdzXG4gICAgICAvLyBvd24gYGdldFJlbGF0aXZlVVJMYCBkb2VzIGl0IGZvciB0aGUgaGVhZGVyIGl0IHNldHMsIGFuZCBvbmx5IHRoZVxuICAgICAgLy8gYHJlZGlyZWN0LnVybGAgZmllbGQgdGhpcyBwYXRoIHJlYWRzIGtlZXBzIHRoZSBhYnNvbHV0ZSBmb3JtLlxuICAgICAgbG9jYXRpb246IFwiL2xvZ2luXCIsXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwiZm9sbG93cyBhbiBpbnRlcm5hbCBtaWRkbGV3YXJlIHJld3JpdGUgdG8gdGhlIHJld3JpdHRlbiBlbnRyeXBvaW50XCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIiwgYXN5bmMgKCkgPT4gKHtcbiAgICAgIHJld3JpdGU6IG5ldyBVUkwoXCIvYXBpL2hlYWx0aFwiLCBPUklHSU4pLFxuICAgIH0pKS5kaXNwYXRjaChyZXF1ZXN0KFwiL2lzci8xXCIpKTtcbiAgICBleHBlY3QocmVzdWx0LmtpbmQpLnRvQmUoXCJlbnRyeXBvaW50XCIpO1xuICAgIGlmIChyZXN1bHQua2luZCAhPT0gXCJlbnRyeXBvaW50XCIpIHJldHVybjtcbiAgICBleHBlY3QocmVzdWx0LnJlc29sdmVkUGF0aG5hbWUpLnRvQmUoXCIvYXBpL2hlYWx0aFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJyb3V0ZXMgL19uZXh0L2ltYWdlIHdoZW4gbWlkZGxld2FyZSBpcyB3aGF0IHB1dCB0aGUgcmVxdWVzdCBvbiBpdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gVGhlIEFQSSBHYXRld2F5IGV4YW1wbGVzJyBtaWRkbGV3YXJlIHJld3JpdGVzIGAveGAgdG8gYC88c3RhZ2U+L3hgIHNvIHRoZVxuICAgIC8vIGJ1aWxkJ3MgYGJhc2VQYXRoYCBsaW5lcyB1cC4gYHJlc29sdmVSb3V0ZXNgIG5ldmVyIHJlcG9ydHMgdGhlIHJld3JpdHRlblxuICAgIC8vIFVSTCBiYWNrLCBzbyBvcHRpbWl6aW5nIHRoZSBVUkwgYXMgcmVjZWl2ZWQgd291bGQgbG9zZSB0aGUgcmV3cml0ZS5cbiAgICBjb25zdCBxdWVyeSA9IFwiP3VybD0lMkZmb28ucG5nJnc9NjQwJnE9NzVcIjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFxuICAgICAgXCJhcHAtcGxheWdyb3VuZC1iYXNlLXBhdGhcIixcbiAgICAgIGFzeW5jICgpID0+ICh7IHJld3JpdGU6IG5ldyBVUkwoYC9wcm9kL19uZXh0L2ltYWdlJHtxdWVyeX1gLCBPUklHSU4pIH0pLFxuICAgICkuZGlzcGF0Y2gocmVxdWVzdChgL19uZXh0L2ltYWdlJHtxdWVyeX1gKSk7XG4gICAgZXhwZWN0KHJlc3VsdC5raW5kKS50b0JlKFwiaW1hZ2Utb3B0aW1pemF0aW9uXCIpO1xuICAgIGlmIChyZXN1bHQua2luZCAhPT0gXCJpbWFnZS1vcHRpbWl6YXRpb25cIikgcmV0dXJuO1xuICAgIGV4cGVjdChyZXN1bHQudXJsLnNlYXJjaFBhcmFtcy5nZXQoXCJ1cmxcIikpLnRvQmUoXCIvZm9vLnBuZ1wiKTtcbiAgfSk7XG5cbiAgaXQoXCJkb2VzIG5vdCBsZWFrIHRoZSBpbnRlcm5hbCByZXdyaXRlIGhlYWRlciBpdCBjb25zdW1lZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kXCIsIGFzeW5jICgpID0+ICh7XG4gICAgICByZXdyaXRlOiBuZXcgVVJMKFwiL2FwaS9oZWFsdGhcIiwgT1JJR0lOKSxcbiAgICAgIHJlc3BvbnNlSGVhZGVyczogbmV3IEhlYWRlcnMoeyBcIngtbWlkZGxld2FyZS1yZXdyaXRlXCI6IFwiL2FwaS9oZWFsdGhcIiB9KSxcbiAgICB9KSkuZGlzcGF0Y2gocmVxdWVzdChcIi9pc3IvMVwiKSk7XG4gICAgZXhwZWN0KHJlc3VsdC5yZXNwb25zZUhlYWRlcnMuaGFzKFwieC1taWRkbGV3YXJlLXJld3JpdGVcIikpLnRvQmUoZmFsc2UpO1xuICB9KTtcblxuICBpdChcInJlcG9ydHMgYW4gZXh0ZXJuYWwgbWlkZGxld2FyZSByZXdyaXRlIGFzIGEgcHJveHkgdGFyZ2V0XCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIiwgYXN5bmMgKCkgPT4gKHtcbiAgICAgIHJld3JpdGU6IG5ldyBVUkwoXCJodHRwczovL3Vwc3RyZWFtLnRlc3QveFwiKSxcbiAgICB9KSkuZGlzcGF0Y2gocmVxdWVzdChcIi9pc3IvMVwiKSk7XG4gICAgZXhwZWN0KHJlc3VsdC5raW5kKS50b0JlKFwiZXh0ZXJuYWwtcmV3cml0ZVwiKTtcbiAgICBpZiAocmVzdWx0LmtpbmQgIT09IFwiZXh0ZXJuYWwtcmV3cml0ZVwiKSByZXR1cm47XG4gICAgZXhwZWN0KHJlc3VsdC51cmwuaHJlZikudG9CZShcImh0dHBzOi8vdXBzdHJlYW0udGVzdC94XCIpO1xuICB9KTtcblxuICBpdChcImNhcnJpZXMgbWlkZGxld2FyZSByZXF1ZXN0IGhlYWRlcnMgZm9yd2FyZCBhbmQgcmVzcG9uc2UgaGVhZGVycyBiYWNrXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBgcmVzb2x2ZVJvdXRlc2AgZHJvcHMgYE1pZGRsZXdhcmVSZXN1bHQucmVxdWVzdEhlYWRlcnNgOiBpdCBuZWl0aGVyXG4gICAgLy8gcmV0dXJucyB0aGVtIG5vciBtdXRhdGVzIHRoZSBgaGVhZGVyc2AgaXQgd2FzIGdpdmVuLiBEaXNwYXRjaCBjYXB0dXJlc1xuICAgIC8vIHRoZW0gZnJvbSB0aGUgY2FsbGJhY2ssIHdoaWNoIGlzIHdoYXQga2VlcHNcbiAgICAvLyBgTmV4dFJlc3BvbnNlLm5leHQoeyByZXF1ZXN0OiB7IGhlYWRlcnMgfSB9KWAgd29ya2luZy5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBkaXNwYXRjaGVyRm9yKFwiYXBwLXBsYXlncm91bmRcIiwgYXN5bmMgKCkgPT4gKHtcbiAgICAgIHJlcXVlc3RIZWFkZXJzOiBuZXcgSGVhZGVycyh7IGhvc3Q6IFwiZXhhbXBsZS50ZXN0XCIsIFwieC11c2VyXCI6IFwiNDJcIiB9KSxcbiAgICAgIHJlc3BvbnNlSGVhZGVyczogbmV3IEhlYWRlcnMoeyBcIngtbXdcIjogXCJyYW5cIiB9KSxcbiAgICB9KSkuZGlzcGF0Y2gocmVxdWVzdChcIi9pc3IvMVwiKSk7XG4gICAgZXhwZWN0KHJlc3VsdC5raW5kKS50b0JlKFwiZW50cnlwb2ludFwiKTtcbiAgICBpZiAocmVzdWx0LmtpbmQgIT09IFwiZW50cnlwb2ludFwiKSByZXR1cm47XG4gICAgZXhwZWN0KHJlc3VsdC5yZXF1ZXN0SGVhZGVycy5nZXQoXCJ4LXVzZXJcIikpLnRvQmUoXCI0MlwiKTtcbiAgICBleHBlY3QocmVzdWx0LnJlc3BvbnNlSGVhZGVycy5nZXQoXCJ4LW13XCIpKS50b0JlKFwicmFuXCIpO1xuICB9KTtcblxuICBpdChcInBhc3NlcyB0aGUgY2FsbGVyJ3MgcmVxdWVzdCBoZWFkZXJzIHRocm91Z2ggd2hlbiBtaWRkbGV3YXJlIGFkZHMgbm9uZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGlzcGF0Y2hlckZvcihcImFwcC1wbGF5Z3JvdW5kXCIpLmRpc3BhdGNoKFxuICAgICAgcmVxdWVzdChcIi9pc3IvMVwiLCB7IFwieC1jYWxsZXJcIjogXCJ5ZXNcIiB9KSxcbiAgICApO1xuICAgIGV4cGVjdChyZXN1bHQua2luZCkudG9CZShcImVudHJ5cG9pbnRcIik7XG4gICAgaWYgKHJlc3VsdC5raW5kICE9PSBcImVudHJ5cG9pbnRcIikgcmV0dXJuO1xuICAgIGV4cGVjdChyZXN1bHQucmVxdWVzdEhlYWRlcnMuZ2V0KFwieC1jYWxsZXJcIikpLnRvQmUoXCJ5ZXNcIik7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwicmVwYWlyUm91dGVQYXJhbVF1ZXJ5XCIsICgpID0+IHtcbiAgaXQoXCJkcm9wcyBhbiBvcHRpb25hbCBjYXRjaGFsbCdzIHBhcmFtIHdoZW4gdGhlIHJlcXVlc3QgZmlsbGVkIG5vbmVcIiwgKCkgPT4ge1xuICAgIC8vIE1lYXN1cmVkIGZyb20gYHJlc29sdmVSb3V0ZXNgIGZvciBgL29wdGlvbmFsLWNhdGNoYWxsYCBhZ2FpbnN0XG4gICAgLy8gYGFwcC9vcHRpb25hbC1jYXRjaGFsbC9bWy4uLnBhcmFtc11dYDogKmJvdGgqIHNpZGVzIGNhcnJ5IHRoZSBrZXkgd2l0aCBub1xuICAgIC8vIHZhbHVlLCB3aGljaCB0aGUgYEBuZXh0L3JvdXRpbmdgIHR5cGVzIGRvIG5vdCBhZG1pdC4gVGhlIGtleSBhbG9uZSBpcyB3aGF0XG4gICAgLy8gbWFrZXMgYHByZXBhcmUoKWAgaW52ZW50IGEgcGFyYW0sIHNvIHRoZSBrZXkgaGFzIHRvIGdvLlxuICAgIGV4cGVjdChcbiAgICAgIHJlcGFpclJvdXRlUGFyYW1RdWVyeShcbiAgICAgICAgeyBueHRQcGFyYW1zOiB1bmRlZmluZWQhIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBueHRQcGFyYW1zOiB1bmRlZmluZWQsXG4gICAgICAgIH0sXG4gICAgICApLFxuICAgICkudG9FcXVhbCh7fSk7XG4gICAgLy8gVGhlIHNhbWUgc2hhcGUgd2l0aCBcIlwiIGZvciB0aGUgdmFsdWUsIHdoaWNoIHRoZSBleHBhbnNpb24gY2FuIGFsc28gcHJvZHVjZS5cbiAgICBleHBlY3QocmVwYWlyUm91dGVQYXJhbVF1ZXJ5KHsgbnh0UHBhcmFtczogXCJcIiB9LCB7fSkpLnRvRXF1YWwoe30pO1xuICAgIC8vIEEgZmlsbGVkIG9uZSBpcyBsZWZ0IGFsb25lLCB3aGljaGV2ZXIgc291cmNlIGl0IGNhbWUgZnJvbS5cbiAgICBleHBlY3QoXG4gICAgICByZXBhaXJSb3V0ZVBhcmFtUXVlcnkoeyBueHRQcGFyYW1zOiBcImEvYlwiIH0sIHsgbnh0UHBhcmFtczogXCJhL2JcIiB9KSxcbiAgICApLnRvRXF1YWwoeyBueHRQcGFyYW1zOiBcImEvYlwiIH0pO1xuICAgIC8vIE5vIHJvdXRlIHBhcmFtIGNhbiBiZSBsZWdpdGltYXRlbHkgZW1wdHkgLSBhIHJlcXVpcmVkIHNlZ21lbnQgY2FwdHVyZXNcbiAgICAvLyBgW14vXSs/YCwgYSByZXF1aXJlZCBjYXRjaGFsbCBgLis/YCwgYW5kIGFuIG9wdGlvbmFsIGNhdGNoYWxsIHRoYXQgbWF0Y2hlZFxuICAgIC8vIG5vdGhpbmcgaGFzIG5vIGdyb3VwIGZvciBgcm91dGVNYXRjaGVzYCB0byByZXBvcnQgLSBzbyBhbiBlbXB0eSB2YWx1ZSBnb2VzXG4gICAgLy8gd2hldGhlciBvciBub3QgYHJvdXRlTWF0Y2hlc2AgZWNob2VzIGl0LlxuICAgIGV4cGVjdChyZXBhaXJSb3V0ZVBhcmFtUXVlcnkoeyBueHRQaWQ6IFwiXCIgfSwgeyBueHRQaWQ6IFwiXCIgfSkpLnRvRXF1YWwoe30pO1xuICAgIC8vIE5vdCBhIHJvdXRlIHBhcmFtLCBzbyBub3Qgb3VycyB0byB0b3VjaC5cbiAgICBleHBlY3QocmVwYWlyUm91dGVQYXJhbVF1ZXJ5KHsgcTogXCJcIiB9LCB7fSkpLnRvRXF1YWwoeyBxOiBcIlwiIH0pO1xuICB9KTtcblxuICBpdChcInJlcGFpcnMgYW5kIGRyb3BzIGluIG9uZSBwYXNzXCIsICgpID0+IHtcbiAgICAvLyBUaGUgcHJlZml4IGNvbGxpc2lvbiBhbmQgdGhlIHVuc2V0IG9wdGlvbmFsIGNhdGNoYWxsIGluIHRoZSBzYW1lIHF1ZXJ5OlxuICAgIC8vIGBueHRQaWQyYCBpcyB3cm9uZyBhbmQgYG54dFByZXN0YCB3YXMgbmV2ZXIgcmVxdWVzdGVkLlxuICAgIGV4cGVjdChcbiAgICAgIHJlcGFpclJvdXRlUGFyYW1RdWVyeShcbiAgICAgICAgeyBueHRQaWQ6IFwiYVwiLCBueHRQaWQyOiBcImEyXCIsIG54dFByZXN0OiBcIlwiIH0sXG4gICAgICAgIHsgbnh0UGlkOiBcImFcIiwgbnh0UGlkMjogXCJiXCIgfSxcbiAgICAgICksXG4gICAgKS50b0VxdWFsKHsgbnh0UGlkOiBcImFcIiwgbnh0UGlkMjogXCJiXCIgfSk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwib3V0T2ZCYW5kUm91dGVQYXJhbXNcIiwgKCkgPT4ge1xuICBpdChcImxlYXZlcyBhIHF1ZXJ5IHRoZSBjb250cmFjdCBjYW4gY2FycnkgYWxvbmVcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChcbiAgICAgIG91dE9mQmFuZFJvdXRlUGFyYW1zKFxuICAgICAgICB7IG54dFByZXN0OiBcImEvYlwiLCBxOiBcIjFcIiB9LFxuICAgICAgICBcIi9wYWdlcy1jYWNoZS9bLi4ucmVzdF1cIixcbiAgICAgICksXG4gICAgKS50b0JlVW5kZWZpbmVkKCk7XG4gICAgZXhwZWN0KG91dE9mQmFuZFJvdXRlUGFyYW1zKHsgbnh0UGlkOiBcIjQyXCIgfSwgXCIvaXNyL1tpZF1cIikpLnRvQmVVbmRlZmluZWQoKTtcbiAgICAvLyBBbiBlbmNvZGVkIGRlbGltaXRlciBpbiBzb21ldGhpbmcgdGhhdCBpcyBub3QgYSByb3V0ZSBwYXJhbSBpcyBub3Qgb3Vycy5cbiAgICBleHBlY3QoXG4gICAgICBvdXRPZkJhbmRSb3V0ZVBhcmFtcyh7IHE6IFwiYSUyRmJcIiB9LCBcIi9wYWdlcy1jYWNoZS9bLi4ucmVzdF1cIiksXG4gICAgKS50b0JlVW5kZWZpbmVkKCk7XG4gIH0pO1xuXG4gIGl0KFwicmVzdGF0ZXMgYSBjYXB0dXJlIHdpdGggYW4gZW5jb2RlZCBkZWxpbWl0ZXIgYXMgcGFyYW1zLCBvbmNlIGRlY29kZWRcIiwgKCkgPT4ge1xuICAgIC8vIGB0ZXN0L2UyZS9pbmNyZW1lbnRhbC1jYWNoZS1wYXRoLXRyYXZlcnNhbGAuIFRocm91Z2ggdGhlIHF1ZXJ5IGNvbnRyYWN0XG4gICAgLy8gdGhpcyBiZWNvbWVzIHRocmVlIHBhcmFtcyBhbmQgYG5vcm1hbGl6ZVBhZ2VQYXRoYCB0aHJvd3Mgb24gdGhlIHBhdGhuYW1lXG4gICAgLy8gcmVidWlsdCBmcm9tIHRoZW07IGBuZXh0IHN0YXJ0YCByZW5kZXJzIG9uZSBwYXJhbSwgd2hpY2ggaXMgdGhpcy5cbiAgICBleHBlY3QoXG4gICAgICBvdXRPZkJhbmRSb3V0ZVBhcmFtcyhcbiAgICAgICAgeyBueHRQcmVzdDogXCIuLiUyRi4uJTJGc2VydmVyLXJlZmVyZW5jZS1tYW5pZmVzdFwiIH0sXG4gICAgICAgIFwiL19uZXh0L2RhdGEvQlVJTERfSUQvcGFnZXMtY2FjaGUvWy4uLnJlc3RdLmpzb25cIixcbiAgICAgICksXG4gICAgKS50b0VxdWFsKHtcbiAgICAgIHBhcmFtczogeyByZXN0OiBbXCIuLi8uLi9zZXJ2ZXItcmVmZXJlbmNlLW1hbmlmZXN0XCJdIH0sXG4gICAgICBxdWVyeToge30sXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwic3BsaXRzIGEgcmVwZWF0IG9uIHJlYWwgZGVsaW1pdGVycyBvbmx5LCBhbmQga2VlcHMgYSBzaW5nbGUgcGFyYW0gd2hvbGVcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChcbiAgICAgIG91dE9mQmFuZFJvdXRlUGFyYW1zKFxuICAgICAgICB7IG54dFByZXN0OiBcImEvYiUyRmMvZFwiIH0sXG4gICAgICAgIFwiL3BhZ2VzLWNhY2hlL1tbLi4ucmVzdF1dXCIsXG4gICAgICApLFxuICAgICkudG9FcXVhbCh7IHBhcmFtczogeyByZXN0OiBbXCJhXCIsIFwiYi9jXCIsIFwiZFwiXSB9LCBxdWVyeToge30gfSk7XG4gICAgZXhwZWN0KG91dE9mQmFuZFJvdXRlUGFyYW1zKHsgbnh0UGlkOiBcImElMkZiXCIgfSwgXCIvaXNyL1tpZF1cIikpLnRvRXF1YWwoe1xuICAgICAgcGFyYW1zOiB7IGlkOiBcImEvYlwiIH0sXG4gICAgICBxdWVyeToge30sXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwia2VlcHMgZXZlcnl0aGluZyB0aGF0IGlzIG5vdCBhIHJvdXRlIHBhcmFtIGluIHRoZSBxdWVyeVwiLCAoKSA9PiB7XG4gICAgZXhwZWN0KFxuICAgICAgb3V0T2ZCYW5kUm91dGVQYXJhbXMoXG4gICAgICAgIHsgbnh0UHJlc3Q6IFwiYSUyRmJcIiwgZnJvbTogXCIveFwiLCBwYWdlOiBcIjJcIiB9LFxuICAgICAgICBcIi9wYWdlcy1jYWNoZS9bLi4ucmVzdF1cIixcbiAgICAgICksXG4gICAgKS50b0VxdWFsKHtcbiAgICAgIHBhcmFtczogeyByZXN0OiBbXCJhL2JcIl0gfSxcbiAgICAgIHF1ZXJ5OiB7IGZyb206IFwiL3hcIiwgcGFnZTogXCIyXCIgfSxcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJzdGF5cyBvbiB0aGUgcXVlcnkgY29udHJhY3Qgd2hlbiBhIHBhcmFtIGNhbm5vdCBiZSByZXN0YXRlZFwiLCAoKSA9PiB7XG4gICAgLy8gQW4gb3B0aW9uYWwgY2F0Y2hhbGwgdGhlIHJlcXVlc3QgbGVmdCB1bnNldC4gSGFsZiBhIHBhcmFtIHNldCBpcyB3b3JzZVxuICAgIC8vIHRoYW4gbm9uZTogYHByZXBhcmVgIHdvdWxkIGludGVycG9sYXRlIGEgcm91dGUgd2l0aCBhIG1pc3Npbmcgc2VnbWVudC5cbiAgICBleHBlY3QoXG4gICAgICBvdXRPZkJhbmRSb3V0ZVBhcmFtcyhcbiAgICAgICAgeyBueHRQcmVzdDogXCJhJTJGYlwiLCBueHRQb3B0aW9uYWw6IFwiXCIgfSxcbiAgICAgICAgXCIvcGFnZXMtY2FjaGUvWy4uLnJlc3RdL1tbLi4ub3B0aW9uYWxdXVwiLFxuICAgICAgKSxcbiAgICApLnRvQmVVbmRlZmluZWQoKTtcbiAgfSk7XG5cbiAgaXQoXCJ0b2xlcmF0ZXMgYSBjYXB0dXJlIHRoYXQgaXMgbm90IHZhbGlkIHBlcmNlbnQtZW5jb2RpbmdcIiwgKCkgPT4ge1xuICAgIC8vIGBkZWNvZGVRdWVyeVBhdGhQYXJhbWV0ZXJgIGlzIGEgdHJ5L2NhdGNoIGZvciB0aGUgc2FtZSByZWFzb246IGAlMkZgIG1ha2VzXG4gICAgLy8gdGhpcyByZWFjaGFibGUgd2hpbGUgYCV6emAgbWFrZXMgYGRlY29kZVVSSUNvbXBvbmVudGAgdGhyb3cuXG4gICAgZXhwZWN0KFxuICAgICAgb3V0T2ZCYW5kUm91dGVQYXJhbXMoeyBueHRQcmVzdDogXCJhJTJGJXp6XCIgfSwgXCIvcGFnZXMtY2FjaGUvWy4uLnJlc3RdXCIpLFxuICAgICkudG9FcXVhbCh7IHBhcmFtczogeyByZXN0OiBbXCJhJTJGJXp6XCJdIH0sIHF1ZXJ5OiB7fSB9KTtcbiAgfSk7XG59KTtcbiJdfQ==
|