cdk-nextjs 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2467 -2714
- package/.jsii.tabl.json +1 -1
- package/API.md +1725 -1909
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +152 -170
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +687 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1548 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +852 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +861 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +13 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +11 -2
- 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/post-deploy.lambda.js +3 -2
- 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 +19 -3
- package/lib/lambdas/post-deploy/prune-s3.js +54 -15
- package/lib/lambdas/post-deploy/prune-s3.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-s3.test.js +255 -0
- 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 +107 -18
- package/lib/nextjs-api.js +349 -39
- package/lib/nextjs-api.test.js +582 -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 +23 -3
- package/lib/nextjs-post-deploy.js +14 -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 +23 -4
- package/lib/nextjs-static-assets.js +29 -6
- package/lib/nextjs-static-assets.test.js +20 -1
- package/lib/root-constructs/nextjs-base-construct.d.ts +105 -45
- package/lib/root-constructs/nextjs-base-construct.js +144 -34
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -70
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -69
- package/lib/root-constructs/nextjs-regional-containers.d.ts +25 -5
- package/lib/root-constructs/nextjs-regional-containers.js +17 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -25
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1213 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1678 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41595 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +55 -0
- package/lib/runtime/next-modules.js +124 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41588 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +123 -11
- package/lib/utils/base-path.js +276 -39
- package/lib/utils/base-path.test.js +275 -50
- 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,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RuntimeImageOptimizer = void 0;
|
|
4
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
5
|
+
/**
|
|
6
|
+
* `/_next/image`, folded into the runtime core.
|
|
7
|
+
*
|
|
8
|
+
* The response is written to a {@link ShimServerResponse} rather than straight to
|
|
9
|
+
* a Lambda response stream, so it composes with routing: dispatch only classifies
|
|
10
|
+
* a request as image optimization *after* middleware has had it, which is what
|
|
11
|
+
* makes `NextResponse.rewrite()` onto an image work. That is also why there is no
|
|
12
|
+
* longer a dedicated image optimization Lambda — middleware never ran for it.
|
|
13
|
+
*/
|
|
14
|
+
const node_fs_1 = require("node:fs");
|
|
15
|
+
const node_path_1 = require("node:path");
|
|
16
|
+
const node_url_1 = require("node:url");
|
|
17
|
+
const response_1 = require("./http/response");
|
|
18
|
+
const image_utils_1 = require("./image-utils");
|
|
19
|
+
const next_modules_1 = require("./next-modules");
|
|
20
|
+
const util_1 = require("./util");
|
|
21
|
+
class RuntimeImageOptimizer {
|
|
22
|
+
options;
|
|
23
|
+
s3 = (0, util_1.s3Client)();
|
|
24
|
+
loaded;
|
|
25
|
+
imageCache;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Whether the app serves `/_next/image` at all. `next start` answers 404
|
|
31
|
+
* when `images.unoptimized` is set or a non-default `loader` is configured
|
|
32
|
+
* (`next-server.js`), and so does the runtime: otherwise anyone can make the
|
|
33
|
+
* compute run sharp and write the image cache on an endpoint the app turned
|
|
34
|
+
* off.
|
|
35
|
+
*/
|
|
36
|
+
isEnabled() {
|
|
37
|
+
this.loaded ??= loadImageRuntime(this.options);
|
|
38
|
+
const { imagesConfig } = this.loaded;
|
|
39
|
+
return imagesConfig.loader === "default" && !imagesConfig.unoptimized;
|
|
40
|
+
}
|
|
41
|
+
async handle(req, res, url, waitUntil) {
|
|
42
|
+
// Resolved on the first image request rather than at cold start: an app with
|
|
43
|
+
// no `<Image>` should pay neither the `next` module loads nor the
|
|
44
|
+
// `required-server-files.json` parse.
|
|
45
|
+
this.loaded ??= loadImageRuntime(this.options);
|
|
46
|
+
const { next, nextConfig, imagesConfig } = this.loaded;
|
|
47
|
+
const { ImageError, ImageOptimizerCache, fetchExternalImage, imageOptimizer, sendResponse, } = next.optimizer;
|
|
48
|
+
try {
|
|
49
|
+
const params = ImageOptimizerCache.validateParams(req, Object.fromEntries(url.searchParams), nextConfig, false);
|
|
50
|
+
if ("errorMessage" in params) {
|
|
51
|
+
return sendText(res, 400, params.errorMessage);
|
|
52
|
+
}
|
|
53
|
+
const { href, isAbsolute } = params;
|
|
54
|
+
const optimize = async (previousCacheEntry) => {
|
|
55
|
+
const upstream = isAbsolute
|
|
56
|
+
? await fetchExternalImage(href, imagesConfig.dangerouslyAllowLocalIP, imagesConfig.maximumResponseBody, imagesConfig.maximumRedirects)
|
|
57
|
+
: await this.fetchLocal(req, href, nextConfig, imagesConfig.maximumResponseBody, next.optimizer);
|
|
58
|
+
const optimized = await imageOptimizer(upstream, params, {
|
|
59
|
+
experimental: nextConfig.experimental,
|
|
60
|
+
images: {
|
|
61
|
+
dangerouslyAllowSVG: imagesConfig.dangerouslyAllowSVG,
|
|
62
|
+
minimumCacheTTL: imagesConfig.minimumCacheTTL,
|
|
63
|
+
},
|
|
64
|
+
}, { isDev: false, previousCacheEntry });
|
|
65
|
+
// `imageOptimizer` reports a failed optimization by returning the
|
|
66
|
+
// untouched upstream image alongside `error` rather than throwing, so
|
|
67
|
+
// without this a broken `sharp` install serves full-size originals with
|
|
68
|
+
// a 200 indefinitely and nothing in the logs says why.
|
|
69
|
+
if (optimized.error) {
|
|
70
|
+
console.error(`Failed to optimize ${href}, serving the unoptimized original:`, optimized.error);
|
|
71
|
+
}
|
|
72
|
+
return optimized;
|
|
73
|
+
};
|
|
74
|
+
// Next's own response writer, rather than a restatement of it, so the
|
|
75
|
+
// headers `next start` sends come with it: the year-long `immutable` for
|
|
76
|
+
// a `/_next/static/media` src, `If-None-Match` as `fresh` reads it (weak
|
|
77
|
+
// and listed tags, `Cache-Control: no-cache`), a `Content-Disposition`
|
|
78
|
+
// that RFC 5987-encodes a filename `writeHead` would reject as
|
|
79
|
+
// non-latin1, `Content-Length`, and no body for HEAD. The restated
|
|
80
|
+
// version had drifted on every one of those.
|
|
81
|
+
const send = (extension, buffer, etag, xCache, maxAge) => {
|
|
82
|
+
res.statusCode = 200;
|
|
83
|
+
sendResponse(req, (0, response_1.asServerResponse)(res), href, extension, buffer, etag, params.isStatic, xCache, imagesConfig, maxAge, false);
|
|
84
|
+
};
|
|
85
|
+
// `next start`'s `handleNextImageRequest`, step for step: a
|
|
86
|
+
// `ResponseCache` over an `ImageOptimizerCache` backed by the app's
|
|
87
|
+
// `cacheHandler`, so a hit skips the fetch and `sharp`, a stale entry is
|
|
88
|
+
// served while it is regenerated, and concurrent misses for one image
|
|
89
|
+
// optimize it once. The app's `cacheHandler` is the S3 cache, which the
|
|
90
|
+
// adapter turns on with `images.customCacheHandler`: with no CDN in front
|
|
91
|
+
// (the Regional types) every request would otherwise run `sharp` again,
|
|
92
|
+
// and behind CloudFront each edge miss is an S3 read instead.
|
|
93
|
+
const cache = await this.loadCache(this.loaded);
|
|
94
|
+
const entry = await cache.responses.get(ImageOptimizerCache.getCacheKey(params), async ({ previousCacheEntry }) => {
|
|
95
|
+
const { buffer, contentType, maxAge, etag, upstreamEtag } = await optimize(previousCacheEntry);
|
|
96
|
+
return {
|
|
97
|
+
value: {
|
|
98
|
+
kind: IMAGE_KIND,
|
|
99
|
+
buffer,
|
|
100
|
+
etag,
|
|
101
|
+
extension: next.serveStatic.getExtension(contentType) ?? "",
|
|
102
|
+
upstreamEtag,
|
|
103
|
+
},
|
|
104
|
+
cacheControl: { revalidate: maxAge, expire: undefined },
|
|
105
|
+
};
|
|
106
|
+
}, {
|
|
107
|
+
routeKind: IMAGE_KIND,
|
|
108
|
+
incrementalCache: deferWrites(cache.images, waitUntil),
|
|
109
|
+
isFallback: false,
|
|
110
|
+
// A stale entry is served at once and regenerated in the background;
|
|
111
|
+
// without this, a Lambda could freeze with the regeneration half done.
|
|
112
|
+
waitUntil,
|
|
113
|
+
});
|
|
114
|
+
const value = entry?.value;
|
|
115
|
+
if (value?.kind !== IMAGE_KIND) {
|
|
116
|
+
throw new Error("The image cache returned no image entry");
|
|
117
|
+
}
|
|
118
|
+
send(value.extension, value.buffer, value.etag, entry.isMiss ? "MISS" : entry.isStale ? "STALE" : "HIT", entry.cacheControl?.revalidate || 0);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
const { statusCode, message } = (0, image_utils_1.resolveErrorResponse)(error, ImageError);
|
|
122
|
+
if (statusCode >= 500) {
|
|
123
|
+
console.error("Image optimization failed:", error);
|
|
124
|
+
}
|
|
125
|
+
sendText(res, statusCode, message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Evicted on failure, as `EntrypointRegistry.load` evicts a failed module load:
|
|
130
|
+
* a transient failure importing the `cacheHandler` (EMFILE under a cold-start
|
|
131
|
+
* burst) would otherwise 500 every image request until the sandbox recycles.
|
|
132
|
+
*/
|
|
133
|
+
loadCache(loaded) {
|
|
134
|
+
if (!this.imageCache) {
|
|
135
|
+
const cache = loadImageCache(this.options, loaded);
|
|
136
|
+
this.imageCache = cache;
|
|
137
|
+
cache.catch(() => {
|
|
138
|
+
if (this.imageCache === cache) {
|
|
139
|
+
this.imageCache = undefined;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return this.imageCache;
|
|
144
|
+
}
|
|
145
|
+
async fetchLocal(req, href, nextConfig, maximumResponseBody, optimizer) {
|
|
146
|
+
const { bucket, fetchInternal } = this.options;
|
|
147
|
+
// No bucket when the sources are on disk (`NextjsRegionalContainers`), and
|
|
148
|
+
// the routes serve those as they serve anything S3 has no file for.
|
|
149
|
+
if (bucket) {
|
|
150
|
+
try {
|
|
151
|
+
const result = await (0, image_utils_1.fetchFromS3)(this.s3, bucket, href, {
|
|
152
|
+
urlBasePath: nextConfig.basePath,
|
|
153
|
+
keyPrefix: this.options.bucketKeyPrefix,
|
|
154
|
+
assetPrefix: nextConfig.assetPrefix,
|
|
155
|
+
}, maximumResponseBody);
|
|
156
|
+
return {
|
|
157
|
+
buffer: result.buffer,
|
|
158
|
+
contentType: result.contentType,
|
|
159
|
+
cacheControl: null,
|
|
160
|
+
etag: result.etag,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const missing = error instanceof Error && error.name === "NoSuchKey";
|
|
165
|
+
if (!missing)
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// What `fetchInternalImage` checks, and throws, for the same response.
|
|
170
|
+
const response = await fetchInternal(href, req, maximumResponseBody);
|
|
171
|
+
if (response.otherGroup !== undefined) {
|
|
172
|
+
// A deployment problem, not a bad `url`: leave the route in the default
|
|
173
|
+
// group, or serve the image as a file (public/ or a static import).
|
|
174
|
+
throw new optimizer.ImageError(502, '"url" parameter is valid but its source is a route in another ' +
|
|
175
|
+
`functionGroups group ("${response.otherGroup}"), which the image ` +
|
|
176
|
+
"optimizer cannot fetch");
|
|
177
|
+
}
|
|
178
|
+
if (response.tooLarge) {
|
|
179
|
+
throw new optimizer.ImageError(413, '"url" parameter is valid but internal response is invalid');
|
|
180
|
+
}
|
|
181
|
+
if (!response.statusCode || response.body.length === 0) {
|
|
182
|
+
throw new optimizer.ImageError(400, '"url" parameter is valid but internal response is invalid');
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
buffer: response.body,
|
|
186
|
+
contentType: (0, util_1.firstValue)(response.headers["content-type"]) ?? null,
|
|
187
|
+
cacheControl: (0, util_1.firstValue)(response.headers["cache-control"]) ?? null,
|
|
188
|
+
etag: optimizer.extractEtag((0, util_1.firstValue)(response.headers.etag) ?? null, response.body),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
exports.RuntimeImageOptimizer = RuntimeImageOptimizer;
|
|
193
|
+
/**
|
|
194
|
+
* `CachedRouteKind.IMAGE`, which is also `RouteKind.IMAGE`. Restated: the enum is
|
|
195
|
+
* a runtime value of `next`, which the bundle cannot import.
|
|
196
|
+
*/
|
|
197
|
+
const IMAGE_KIND = "IMAGE";
|
|
198
|
+
/**
|
|
199
|
+
* The app's `cacheHandler`, constructed the way `next start` constructs it for
|
|
200
|
+
* images (`next-server.js`, `handleNextImageRequest`): once, and kept, so its
|
|
201
|
+
* in-memory layer lasts across requests. Its path in `required-server-files.json`
|
|
202
|
+
* is relative to the dist dir; see {@link cacheHandlerUrl}.
|
|
203
|
+
*/
|
|
204
|
+
async function loadImageCache({ deploymentRoot, manifest, importModule }, loaded) {
|
|
205
|
+
const { next, nextConfig } = loaded;
|
|
206
|
+
const modules = {
|
|
207
|
+
responseCache: (0, next_modules_1.nextModule)("next/dist/server/response-cache/index.js"),
|
|
208
|
+
};
|
|
209
|
+
const distDir = (0, node_path_1.join)(deploymentRoot, manifest.relativeProjectDir, manifest.config.distDir);
|
|
210
|
+
let cacheHandler;
|
|
211
|
+
if (nextConfig.cacheHandler) {
|
|
212
|
+
const url = cacheHandlerUrl(distDir, nextConfig.cacheHandler);
|
|
213
|
+
const imported = (await (importModule
|
|
214
|
+
? importModule(url)
|
|
215
|
+
: import(url)));
|
|
216
|
+
const CacheHandler = imported.default ?? imported;
|
|
217
|
+
cacheHandler = new CacheHandler({
|
|
218
|
+
dev: false,
|
|
219
|
+
flushToDisk: nextConfig.experimental.isrFlushToDisk,
|
|
220
|
+
serverDistDir: (0, node_path_1.join)(distDir, "server"),
|
|
221
|
+
maxMemoryCacheSize: nextConfig.cacheMaxMemorySize,
|
|
222
|
+
revalidatedTags: [],
|
|
223
|
+
_requestHeaders: {},
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
responses: new modules.responseCache.default(false),
|
|
228
|
+
images: new next.optimizer.ImageOptimizerCache({
|
|
229
|
+
distDir,
|
|
230
|
+
nextConfig,
|
|
231
|
+
cacheHandler,
|
|
232
|
+
}),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* `formatDynamicImportPath` from `next/dist/lib/format-dynamic-import-path.js`,
|
|
237
|
+
* restated: `next build` doesn't trace that module into the deployment, so
|
|
238
|
+
* loading it failed every image request with the cache on.
|
|
239
|
+
*/
|
|
240
|
+
function cacheHandlerUrl(distDir, cacheHandler) {
|
|
241
|
+
const path = cacheHandler.startsWith("file://")
|
|
242
|
+
? (0, node_url_1.fileURLToPath)(cacheHandler)
|
|
243
|
+
: cacheHandler;
|
|
244
|
+
return (0, node_url_1.pathToFileURL)((0, node_path_1.isAbsolute)(path) ? path : (0, node_path_1.join)(distDir, path)).toString();
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* `images`, with its `set` moved off the response's critical path.
|
|
248
|
+
*
|
|
249
|
+
* `ResponseCache` awaits the write of a freshly optimized image before it hands
|
|
250
|
+
* the image back, so every miss paid an S3 `PutObject` (~30 ms measured) before
|
|
251
|
+
* its first byte. The write is registered with `waitUntil` instead, which the
|
|
252
|
+
* runtime drains before a Lambda invocation returns or a container shuts down,
|
|
253
|
+
* so it still lands. A failed write is logged; the next request optimizes the
|
|
254
|
+
* image again, which is what it would have done anyway.
|
|
255
|
+
*/
|
|
256
|
+
function deferWrites(images, waitUntil) {
|
|
257
|
+
const deferred = Object.create(images);
|
|
258
|
+
deferred.set = (...args) => {
|
|
259
|
+
waitUntil(images.set(...args).catch((error) => {
|
|
260
|
+
console.error("Failed to cache an optimized image:", error);
|
|
261
|
+
}));
|
|
262
|
+
return Promise.resolve();
|
|
263
|
+
};
|
|
264
|
+
return deferred;
|
|
265
|
+
}
|
|
266
|
+
function sendText(res, statusCode, body) {
|
|
267
|
+
res.statusCode = statusCode;
|
|
268
|
+
res.setHeader("Content-Type", "text/plain");
|
|
269
|
+
res.end(body);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* The image config comes from the app's own `required-server-files.json`, not the
|
|
273
|
+
* adapter manifest: `imageOptimizer` reads whole `experimental` and `images`
|
|
274
|
+
* objects, and mirroring those into the manifest would be a second definition of
|
|
275
|
+
* the same thing that silently goes stale on a `next` minor.
|
|
276
|
+
*/
|
|
277
|
+
function loadImageRuntime({ deploymentRoot, manifest }) {
|
|
278
|
+
const next = {
|
|
279
|
+
configShared: (0, next_modules_1.nextModule)("next/dist/server/config-shared.js"),
|
|
280
|
+
imageConfig: (0, next_modules_1.nextModule)("next/dist/shared/lib/image-config.js"),
|
|
281
|
+
optimizer: (0, next_modules_1.nextModule)("next/dist/server/image-optimizer.js"),
|
|
282
|
+
serveStatic: (0, next_modules_1.nextModule)("next/dist/server/serve-static.js"),
|
|
283
|
+
};
|
|
284
|
+
const path = (0, node_path_1.join)(deploymentRoot, manifest.relativeProjectDir, manifest.config.distDir, "required-server-files.json");
|
|
285
|
+
const required = JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
|
|
286
|
+
const nextConfig = next.configShared.getNextConfigRuntime(required.config);
|
|
287
|
+
return {
|
|
288
|
+
next,
|
|
289
|
+
nextConfig,
|
|
290
|
+
imagesConfig: {
|
|
291
|
+
...next.imageConfig.imageConfigDefault,
|
|
292
|
+
...nextConfig.images,
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9pbWFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxzREFBc0Q7QUFDdEQ7Ozs7Ozs7O0dBUUc7QUFDSCxxQ0FBdUM7QUFDdkMseUNBQStEO0FBQy9ELHVDQUF3RDtBQUl4RCw4Q0FBdUU7QUFDdkUsK0NBQWtFO0FBRWxFLGlEQUE0QztBQUM1QyxpQ0FBOEM7QUF5RjlDLE1BQWEscUJBQXFCO0lBS0k7SUFKbkIsRUFBRSxHQUFHLElBQUEsZUFBUSxHQUFFLENBQUM7SUFDekIsTUFBTSxDQUF1QztJQUM3QyxVQUFVLENBQXVCO0lBRXpDLFlBQW9DLE9BQThCO1FBQTlCLFlBQU8sR0FBUCxPQUFPLENBQXVCO0lBQUcsQ0FBQztJQUV0RTs7Ozs7O09BTUc7SUFDSSxTQUFTO1FBQ2QsSUFBSSxDQUFDLE1BQU0sS0FBSyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDL0MsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDckMsT0FBTyxZQUFZLENBQUMsTUFBTSxLQUFLLFNBQVMsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUM7SUFDeEUsQ0FBQztJQUVNLEtBQUssQ0FBQyxNQUFNLENBQ2pCLEdBQXdCLEVBQ3hCLEdBQXVCLEVBQ3ZCLEdBQVEsRUFDUixTQUE4QztRQUU5Qyw2RUFBNkU7UUFDN0Usa0VBQWtFO1FBQ2xFLHNDQUFzQztRQUN0QyxJQUFJLENBQUMsTUFBTSxLQUFLLGdCQUFnQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMvQyxNQUFNLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3ZELE1BQU0sRUFDSixVQUFVLEVBQ1YsbUJBQW1CLEVBQ25CLGtCQUFrQixFQUNsQixjQUFjLEVBQ2QsWUFBWSxHQUNiLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUVuQixJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxtQkFBbUIsQ0FBQyxjQUFjLENBQy9DLEdBRUksRUFDSixNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsRUFDcEMsVUFBVSxFQUNWLEtBQUssQ0FDTixDQUFDO1lBQ0YsSUFBSSxjQUFjLElBQUksTUFBTSxFQUFFLENBQUM7Z0JBQzdCLE9BQU8sUUFBUSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ2pELENBQUM7WUFFRCxNQUFNLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxHQUFHLE1BQU0sQ0FBQztZQUNwQyxNQUFNLFFBQVEsR0FBRyxLQUFLLEVBQUUsa0JBQXVDLEVBQUUsRUFBRTtnQkFDakUsTUFBTSxRQUFRLEdBQUcsVUFBVTtvQkFDekIsQ0FBQyxDQUFDLE1BQU0sa0JBQWtCLENBQ3RCLElBQUksRUFDSixZQUFZLENBQUMsdUJBQXVCLEVBQ3BDLFlBQVksQ0FBQyxtQkFBbUIsRUFDaEMsWUFBWSxDQUFDLGdCQUFnQixDQUM5QjtvQkFDSCxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUNuQixHQUFHLEVBQ0gsSUFBSSxFQUNKLFVBQVUsRUFDVixZQUFZLENBQUMsbUJBQW1CLEVBQ2hDLElBQUksQ0FBQyxTQUFTLENBQ2YsQ0FBQztnQkFFTixNQUFNLFNBQVMsR0FBRyxNQUFNLGNBQWMsQ0FDcEMsUUFBUSxFQUNSLE1BQU0sRUFDTjtvQkFDRSxZQUFZLEVBQUUsVUFBVSxDQUFDLFlBQVk7b0JBQ3JDLE1BQU0sRUFBRTt3QkFDTixtQkFBbUIsRUFBRSxZQUFZLENBQUMsbUJBQW1CO3dCQUNyRCxlQUFlLEVBQUUsWUFBWSxDQUFDLGVBQWU7cUJBQzlDO2lCQUNGLEVBQ0QsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLGtCQUFrQixFQUFFLENBQ3JDLENBQUM7Z0JBRUYsa0VBQWtFO2dCQUNsRSxzRUFBc0U7Z0JBQ3RFLHdFQUF3RTtnQkFDeEUsdURBQXVEO2dCQUN2RCxJQUFJLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztvQkFDcEIsT0FBTyxDQUFDLEtBQUssQ0FDWCxzQkFBc0IsSUFBSSxxQ0FBcUMsRUFDL0QsU0FBUyxDQUFDLEtBQUssQ0FDaEIsQ0FBQztnQkFDSixDQUFDO2dCQUNELE9BQU8sU0FBUyxDQUFDO1lBQ25CLENBQUMsQ0FBQztZQUVGLHNFQUFzRTtZQUN0RSx5RUFBeUU7WUFDekUseUVBQXlFO1lBQ3pFLHVFQUF1RTtZQUN2RSwrREFBK0Q7WUFDL0QsbUVBQW1FO1lBQ25FLDZDQUE2QztZQUM3QyxNQUFNLElBQUksR0FBRyxDQUNYLFNBQWlCLEVBQ2pCLE1BQWMsRUFDZCxJQUFZLEVBQ1osTUFBZ0MsRUFDaEMsTUFBYyxFQUNkLEVBQUU7Z0JBQ0YsR0FBRyxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUM7Z0JBQ3JCLFlBQVksQ0FDVixHQUFvRCxFQUNwRCxJQUFBLDJCQUFnQixFQUFDLEdBQUcsQ0FBQyxFQUNyQixJQUFJLEVBQ0osU0FBUyxFQUNULE1BQU0sRUFDTixJQUFJLEVBQ0osTUFBTSxDQUFDLFFBQVEsRUFDZixNQUFNLEVBQ04sWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLENBQ04sQ0FBQztZQUNKLENBQUMsQ0FBQztZQUVGLDREQUE0RDtZQUM1RCxvRUFBb0U7WUFDcEUseUVBQXlFO1lBQ3pFLHNFQUFzRTtZQUN0RSx3RUFBd0U7WUFDeEUsMEVBQTBFO1lBQzFFLHdFQUF3RTtZQUN4RSw4REFBOEQ7WUFDOUQsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNoRCxNQUFNLEtBQUssR0FBRyxNQUFNLEtBQUssQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUNyQyxtQkFBbUIsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQ3ZDLEtBQUssRUFBRSxFQUFFLGtCQUFrQixFQUFFLEVBQUUsRUFBRTtnQkFDL0IsTUFBTSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsR0FDdkQsTUFBTSxRQUFRLENBQUMsa0JBQXdDLENBQUMsQ0FBQztnQkFDM0QsT0FBTztvQkFDTCxLQUFLLEVBQUU7d0JBQ0wsSUFBSSxFQUFFLFVBQVU7d0JBQ2hCLE1BQU07d0JBQ04sSUFBSTt3QkFDSixTQUFTLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRTt3QkFDM0QsWUFBWTtxQkFDYjtvQkFDRCxZQUFZLEVBQUUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUU7aUJBQ3hELENBQUM7WUFDSixDQUFDLEVBQ0Q7Z0JBQ0UsU0FBUyxFQUFFLFVBQVU7Z0JBQ3JCLGdCQUFnQixFQUFFLFdBQVcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLFNBQVMsQ0FBQztnQkFDdEQsVUFBVSxFQUFFLEtBQUs7Z0JBQ2pCLHFFQUFxRTtnQkFDckUsdUVBQXVFO2dCQUN2RSxTQUFTO2FBQ2tELENBQzlELENBQUM7WUFDRixNQUFNLEtBQUssR0FBRyxLQUFLLEVBQUUsS0FRUixDQUFDO1lBQ2QsSUFBSSxLQUFLLEVBQUUsSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUMvQixNQUFNLElBQUksS0FBSyxDQUFDLHlDQUF5QyxDQUFDLENBQUM7WUFDN0QsQ0FBQztZQUNELElBQUksQ0FDRixLQUFLLENBQUMsU0FBUyxFQUNmLEtBQUssQ0FBQyxNQUFNLEVBQ1osS0FBSyxDQUFDLElBQUksRUFDVixLQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUN6RCxLQUFNLENBQUMsWUFBWSxFQUFFLFVBQVUsSUFBSSxDQUFDLENBQ3JDLENBQUM7UUFDSixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBQSxrQ0FBb0IsRUFBQyxLQUFLLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDeEUsSUFBSSxVQUFVLElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ3RCLE9BQU8sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDckQsQ0FBQztZQUNELFFBQVEsQ0FBQyxHQUFHLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3JDLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLFNBQVMsQ0FDZixNQUEyQztRQUUzQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3JCLE1BQU0sS0FBSyxHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ25ELElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDO1lBQ3hCLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFO2dCQUNmLElBQUksSUFBSSxDQUFDLFVBQVUsS0FBSyxLQUFLLEVBQUUsQ0FBQztvQkFDOUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxTQUFTLENBQUM7Z0JBQzlCLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDekIsQ0FBQztJQUVPLEtBQUssQ0FBQyxVQUFVLENBQ3RCLEdBQXdCLEVBQ3hCLElBQVksRUFDWixVQUE2RCxFQUM3RCxtQkFBMkIsRUFDM0IsU0FBd0M7UUFFeEMsTUFBTSxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQy9DLDJFQUEyRTtRQUMzRSxvRUFBb0U7UUFDcEUsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQztnQkFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUEseUJBQVcsRUFDOUIsSUFBSSxDQUFDLEVBQUUsRUFDUCxNQUFNLEVBQ04sSUFBSSxFQUNKO29CQUNFLFdBQVcsRUFBRSxVQUFVLENBQUMsUUFBUTtvQkFDaEMsU0FBUyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZTtvQkFDdkMsV0FBVyxFQUFFLFVBQVUsQ0FBQyxXQUFXO2lCQUNwQyxFQUNELG1CQUFtQixDQUNwQixDQUFDO2dCQUNGLE9BQU87b0JBQ0wsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNO29CQUNyQixXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVc7b0JBQy9CLFlBQVksRUFBRSxJQUFJO29CQUNsQixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7aUJBQ2xCLENBQUM7WUFDSixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLE9BQU8sR0FBRyxLQUFLLFlBQVksS0FBSyxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssV0FBVyxDQUFDO2dCQUNyRSxJQUFJLENBQUMsT0FBTztvQkFBRSxNQUFNLEtBQUssQ0FBQztZQUM1QixDQUFDO1FBQ0gsQ0FBQztRQUVELHVFQUF1RTtRQUN2RSxNQUFNLFFBQVEsR0FBRyxNQUFNLGFBQWEsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDckUsSUFBSSxRQUFRLENBQUMsVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3RDLHdFQUF3RTtZQUN4RSxvRUFBb0U7WUFDcEUsTUFBTSxJQUFJLFNBQVMsQ0FBQyxVQUFVLENBQzVCLEdBQUcsRUFDSCxnRUFBZ0U7Z0JBQzlELDBCQUEwQixRQUFRLENBQUMsVUFBVSxzQkFBc0I7Z0JBQ25FLHdCQUF3QixDQUMzQixDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxTQUFTLENBQUMsVUFBVSxDQUM1QixHQUFHLEVBQ0gsMkRBQTJELENBQzVELENBQUM7UUFDSixDQUFDO1FBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDdkQsTUFBTSxJQUFJLFNBQVMsQ0FBQyxVQUFVLENBQzVCLEdBQUcsRUFDSCwyREFBMkQsQ0FDNUQsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPO1lBQ0wsTUFBTSxFQUFFLFFBQVEsQ0FBQyxJQUFJO1lBQ3JCLFdBQVcsRUFBRSxJQUFBLGlCQUFVLEVBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLElBQUk7WUFDakUsWUFBWSxFQUFFLElBQUEsaUJBQVUsRUFBQyxRQUFRLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFDLElBQUksSUFBSTtZQUNuRSxJQUFJLEVBQUUsU0FBUyxDQUFDLFdBQVcsQ0FDekIsSUFBQSxpQkFBVSxFQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxFQUN6QyxRQUFRLENBQUMsSUFBSSxDQUNkO1NBQ0YsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQXBSRCxzREFvUkM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsR0FBRyxPQUFnQyxDQUFDO0FBZ0JwRDs7Ozs7R0FLRztBQUNILEtBQUssVUFBVSxjQUFjLENBQzNCLEVBQUUsY0FBYyxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQXlCLEVBQ2pFLE1BQTJDO0lBRTNDLE1BQU0sRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLEdBQUcsTUFBTSxDQUFDO0lBQ3BDLE1BQU0sT0FBTyxHQUEwQjtRQUNyQyxhQUFhLEVBQUUsSUFBQSx5QkFBVSxFQUFDLDBDQUEwQyxDQUFDO0tBQ3RFLENBQUM7SUFDRixNQUFNLE9BQU8sR0FBRyxJQUFBLGdCQUFJLEVBQ2xCLGNBQWMsRUFDZCxRQUFRLENBQUMsa0JBQWtCLEVBQzNCLFFBQVEsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUN4QixDQUFDO0lBQ0YsSUFBSSxZQUF5RCxDQUFDO0lBQzlELElBQUksVUFBVSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzVCLE1BQU0sR0FBRyxHQUFHLGVBQWUsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzlELE1BQU0sUUFBUSxHQUFHLENBQUMsTUFBTSxDQUFDLFlBQVk7WUFDbkMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUM7WUFDbkIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUF3RCxDQUFDO1FBQ3pFLE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxPQUFPLElBQUksUUFBUSxDQUFDO1FBQ2xELFlBQVksR0FBRyxJQUFJLFlBQVksQ0FBQztZQUM5QixHQUFHLEVBQUUsS0FBSztZQUNWLFdBQVcsRUFBRSxVQUFVLENBQUMsWUFBWSxDQUFDLGNBQWM7WUFDbkQsYUFBYSxFQUFFLElBQUEsZ0JBQUksRUFBQyxPQUFPLEVBQUUsUUFBUSxDQUFDO1lBQ3RDLGtCQUFrQixFQUFFLFVBQVUsQ0FBQyxrQkFBa0I7WUFDakQsZUFBZSxFQUFFLEVBQUU7WUFDbkIsZUFBZSxFQUFFLEVBQUU7U0FDcEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUNELE9BQU87UUFDTCxTQUFTLEVBQUUsSUFBSSxPQUFPLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7UUFDbkQsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQztZQUM3QyxPQUFPO1lBQ1AsVUFBVTtZQUNWLFlBQVk7U0FDYixDQUFDO0tBQ0gsQ0FBQztBQUNKLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxlQUFlLENBQUMsT0FBZSxFQUFFLFlBQW9CO0lBQzVELE1BQU0sSUFBSSxHQUFHLFlBQVksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDO1FBQzdDLENBQUMsQ0FBQyxJQUFBLHdCQUFhLEVBQUMsWUFBWSxDQUFDO1FBQzdCLENBQUMsQ0FBQyxZQUFZLENBQUM7SUFDakIsT0FBTyxJQUFBLHdCQUFhLEVBQ2xCLElBQUEsc0JBQWMsRUFBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFBLGdCQUFJLEVBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUNsRCxDQUFDLFFBQVEsRUFBRSxDQUFDO0FBQ2YsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQVMsV0FBVyxDQUNsQixNQUE0QixFQUM1QixTQUE4QztJQUU5QyxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBeUIsQ0FBQztJQUMvRCxRQUFRLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxJQUE2QyxFQUFFLEVBQUU7UUFDbEUsU0FBUyxDQUNQLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFjLEVBQUUsRUFBRTtZQUMzQyxPQUFPLENBQUMsS0FBSyxDQUFDLHFDQUFxQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzlELENBQUMsQ0FBQyxDQUNILENBQUM7UUFDRixPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUMzQixDQUFDLENBQUM7SUFDRixPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDO0FBRUQsU0FBUyxRQUFRLENBQ2YsR0FBdUIsRUFDdkIsVUFBa0IsRUFDbEIsSUFBWTtJQUVaLEdBQUcsQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQzVCLEdBQUcsQ0FBQyxTQUFTLENBQUMsY0FBYyxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQzVDLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDaEIsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQXlCO0lBQzNFLE1BQU0sSUFBSSxHQUFxQjtRQUM3QixZQUFZLEVBQUUsSUFBQSx5QkFBVSxFQUFDLG1DQUFtQyxDQUFDO1FBQzdELFdBQVcsRUFBRSxJQUFBLHlCQUFVLEVBQUMsc0NBQXNDLENBQUM7UUFDL0QsU0FBUyxFQUFFLElBQUEseUJBQVUsRUFBQyxxQ0FBcUMsQ0FBQztRQUM1RCxXQUFXLEVBQUUsSUFBQSx5QkFBVSxFQUFDLGtDQUFrQyxDQUFDO0tBQzVELENBQUM7SUFDRixNQUFNLElBQUksR0FBRyxJQUFBLGdCQUFJLEVBQ2YsY0FBYyxFQUNkLFFBQVEsQ0FBQyxrQkFBa0IsRUFDM0IsUUFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQ3ZCLDRCQUE0QixDQUM3QixDQUFDO0lBQ0YsTUFBTSxRQUFRLEdBQXdCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBQSxzQkFBWSxFQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQzlFLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzNFLE9BQU87UUFDTCxJQUFJO1FBQ0osVUFBVTtRQUNWLFlBQVksRUFBRTtZQUNaLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxrQkFBa0I7WUFDdEMsR0FBRyxVQUFVLENBQUMsTUFBTTtTQUNyQjtLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzICovXG4vKipcbiAqIGAvX25leHQvaW1hZ2VgLCBmb2xkZWQgaW50byB0aGUgcnVudGltZSBjb3JlLlxuICpcbiAqIFRoZSByZXNwb25zZSBpcyB3cml0dGVuIHRvIGEge0BsaW5rIFNoaW1TZXJ2ZXJSZXNwb25zZX0gcmF0aGVyIHRoYW4gc3RyYWlnaHQgdG9cbiAqIGEgTGFtYmRhIHJlc3BvbnNlIHN0cmVhbSwgc28gaXQgY29tcG9zZXMgd2l0aCByb3V0aW5nOiBkaXNwYXRjaCBvbmx5IGNsYXNzaWZpZXNcbiAqIGEgcmVxdWVzdCBhcyBpbWFnZSBvcHRpbWl6YXRpb24gKmFmdGVyKiBtaWRkbGV3YXJlIGhhcyBoYWQgaXQsIHdoaWNoIGlzIHdoYXRcbiAqIG1ha2VzIGBOZXh0UmVzcG9uc2UucmV3cml0ZSgpYCBvbnRvIGFuIGltYWdlIHdvcmsuIFRoYXQgaXMgYWxzbyB3aHkgdGhlcmUgaXMgbm9cbiAqIGxvbmdlciBhIGRlZGljYXRlZCBpbWFnZSBvcHRpbWl6YXRpb24gTGFtYmRhIOKAlCBtaWRkbGV3YXJlIG5ldmVyIHJhbiBmb3IgaXQuXG4gKi9cbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBpc0Fic29sdXRlIGFzIGlzQWJzb2x1dGVQYXRoLCBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCwgcGF0aFRvRmlsZVVSTCB9IGZyb20gXCJub2RlOnVybFwiO1xuaW1wb3J0IHR5cGUgeyBOZXh0Q29uZmlnQ29tcGxldGUgfSBmcm9tIFwibmV4dC9kaXN0L3NlcnZlci9jb25maWctc2hhcmVkLmpzXCI7XG5pbXBvcnQgdHlwZSB7IENhY2hlZFJvdXRlS2luZCB9IGZyb20gXCJuZXh0L2Rpc3Qvc2VydmVyL3Jlc3BvbnNlLWNhY2hlL3R5cGVzLmpzXCI7XG5pbXBvcnQgdHlwZSB7IFNoaW1JbmNvbWluZ01lc3NhZ2UgfSBmcm9tIFwiLi9odHRwL3JlcXVlc3RcIjtcbmltcG9ydCB7IGFzU2VydmVyUmVzcG9uc2UsIFNoaW1TZXJ2ZXJSZXNwb25zZSB9IGZyb20gXCIuL2h0dHAvcmVzcG9uc2VcIjtcbmltcG9ydCB7IGZldGNoRnJvbVMzLCByZXNvbHZlRXJyb3JSZXNwb25zZSB9IGZyb20gXCIuL2ltYWdlLXV0aWxzXCI7XG5pbXBvcnQgeyBBZGFwdGVyTWFuaWZlc3QgfSBmcm9tIFwiLi9tYW5pZmVzdFwiO1xuaW1wb3J0IHsgbmV4dE1vZHVsZSB9IGZyb20gXCIuL25leHQtbW9kdWxlc1wiO1xuaW1wb3J0IHsgZmlyc3RWYWx1ZSwgczNDbGllbnQgfSBmcm9tIFwiLi91dGlsXCI7XG5cbi8qKlxuICogUmVxdWlyZWQgdGhyb3VnaCB7QGxpbmsgbmV4dE1vZHVsZX0gcmF0aGVyIHRoYW4gaW1wb3J0ZWQsIGJlY2F1c2UgYG5leHRgIGlzXG4gKiBleHRlcm5hbCB0byB0aGUgc2hlbGwgYnVuZGxlcyBhbmQgZG9lcyBub3QgcmVzb2x2ZSBmcm9tIHdoZXJlIHRoZXkgc2l0LiBFdmVyeVxuICogdHlwZSBoZXJlIGlzIHN0aWxsIHRoZSByZWFsIG9uZTogYHR5cGVvZiBpbXBvcnQoLi4uKWAgaXMgZXJhc2VkLlxuICovXG5pbnRlcmZhY2UgTmV4dEltYWdlTW9kdWxlcyB7XG4gIHJlYWRvbmx5IGNvbmZpZ1NoYXJlZDogdHlwZW9mIGltcG9ydChcIm5leHQvZGlzdC9zZXJ2ZXIvY29uZmlnLXNoYXJlZC5qc1wiKTtcbiAgcmVhZG9ubHkgaW1hZ2VDb25maWc6IHR5cGVvZiBpbXBvcnQoXCJuZXh0L2Rpc3Qvc2hhcmVkL2xpYi9pbWFnZS1jb25maWcuanNcIik7XG4gIHJlYWRvbmx5IG9wdGltaXplcjogdHlwZW9mIGltcG9ydChcIm5leHQvZGlzdC9zZXJ2ZXIvaW1hZ2Utb3B0aW1pemVyLmpzXCIpO1xuICByZWFkb25seSBzZXJ2ZVN0YXRpYzogdHlwZW9mIGltcG9ydChcIm5leHQvZGlzdC9zZXJ2ZXIvc2VydmUtc3RhdGljLmpzXCIpO1xufVxuXG4vKiogVGhlIG1vZHVsZXMgb25seSB0aGUgaW1hZ2UgY2FjaGUgbmVlZHMsIGxvYWRlZCB3aXRoIGl0LiAqL1xuaW50ZXJmYWNlIE5leHRJbWFnZUNhY2hlTW9kdWxlcyB7XG4gIHJlYWRvbmx5IHJlc3BvbnNlQ2FjaGU6IHR5cGVvZiBpbXBvcnQoXCJuZXh0L2Rpc3Qvc2VydmVyL3Jlc3BvbnNlLWNhY2hlL2luZGV4LmpzXCIpO1xufVxuXG4vKiogQSBgY2FjaGVIYW5kbGVyYCBjbGFzcywgYXMgYG5leHQuY29uZmlnYCdzIGBjYWNoZUhhbmRsZXJgIG1vZHVsZSBleHBvcnRzIGl0LiAqL1xudHlwZSBDYWNoZUhhbmRsZXJDbGFzcyA9IG5ldyAoXG4gIG9wdGlvbnM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuKSA9PiBOb25OdWxsYWJsZTxcbiAgQ29uc3RydWN0b3JQYXJhbWV0ZXJzPFxuICAgIE5leHRJbWFnZU1vZHVsZXNbXCJvcHRpbWl6ZXJcIl1bXCJJbWFnZU9wdGltaXplckNhY2hlXCJdXG4gID5bMF1bXCJjYWNoZUhhbmRsZXJcIl1cbj47XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW1hZ2VPcHRpbWl6ZXJPcHRpb25zIHtcbiAgcmVhZG9ubHkgZGVwbG95bWVudFJvb3Q6IHN0cmluZztcbiAgcmVhZG9ubHkgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdDtcbiAgLyoqXG4gICAqIGBDREtfTkVYVEpTX1NUQVRJQ19BU1NFVFNfQlVDS0VUX05BTUVgLiBFbXB0eSB3aGVuIHRoZSBzb3VyY2VzIGFyZSBvbiBkaXNrXG4gICAqIChgTmV4dGpzUmVnaW9uYWxDb250YWluZXJzYCksIHdoaWNoIHNlbmRzIGV2ZXJ5IG9uZSB0byBgZmV0Y2hJbnRlcm5hbGAuXG4gICAqL1xuICByZWFkb25seSBidWNrZXQ6IHN0cmluZztcbiAgLyoqXG4gICAqIGBDREtfTkVYVEpTX1NUQVRJQ19BU1NFVFNfS0VZX1BSRUZJWGAuIEVtcHR5IHdoZW4gdGhlIGFzc2V0cyBzaXQgYXQgdGhlIHJvb3RcbiAgICogb2YgdGhlIGJ1Y2tldCwgd2hpY2ggaXMgdGhlIGRlZmF1bHQuXG4gICAqL1xuICByZWFkb25seSBidWNrZXRLZXlQcmVmaXg6IHN0cmluZztcbiAgLyoqXG4gICAqIFJlcXVlc3RzIGEgbG9jYWwgc291cmNlIGZyb20gdGhlIGFwcCdzIG93biByb3V0ZXMsIGZvciBvbmUgUzMgaGFzIG5vIGZpbGVcbiAgICogZm9yOiBgPEltYWdlIHNyYz1cIi9hcGkvYXZhdGFyP2lkPTQyXCI+YCwgc2VydmVkIGJ5IGEgcm91dGUgaGFuZGxlci4gYG5leHRcbiAgICogc3RhcnRgIGZldGNoZXMgZXZlcnkgbG9jYWwgc291cmNlIHRoYXQgd2F5IChgZmV0Y2hJbnRlcm5hbEltYWdlYCk7IGhlcmUgaXRcbiAgICogaXMgdGhlIGZhbGxiYWNrLCBzaW5jZSBuZWFybHkgZXZlcnkgc291cmNlIGlzIGEgZmlsZSwgYW5kIGEgYEdldE9iamVjdGAgaXNcbiAgICogZmFyIGNoZWFwZXIgdGhhbiBhIHJvdXRlIGludm9jYXRpb24uXG4gICAqXG4gICAqIEdpdmVuIHRoZSByZXF1ZXN0IGJlaW5nIG9wdGltaXplZCwgZm9yIGl0cyBhdXRob3JpdHk7IGxpa2UgYG5leHQgc3RhcnRgLFxuICAgKiB0aGUgdmlld2VyJ3MgY29va2llcyBhbmQgb3RoZXIgaGVhZGVycyBhcmUgbm90IHRoZSBpbXBsZW1lbnRhdGlvbidzIHRvXG4gICAqIGZvcndhcmQuIEFuZCBnaXZlbiBgaW1hZ2VzLm1heGltdW1SZXNwb25zZUJvZHlgLCBwYXN0IHdoaWNoIGl0IHN0b3BzXG4gICAqIHJlYWRpbmcgYW5kIGFuc3dlcnMge0BsaW5rIEludGVybmFsSW1hZ2VSZXNwb25zZS50b29MYXJnZX0uXG4gICAqL1xuICByZWFkb25seSBmZXRjaEludGVybmFsOiAoXG4gICAgaHJlZjogc3RyaW5nLFxuICAgIHJlcTogU2hpbUluY29taW5nTWVzc2FnZSxcbiAgICBtYXhpbXVtUmVzcG9uc2VCb2R5OiBudW1iZXIsXG4gICkgPT4gUHJvbWlzZTxJbnRlcm5hbEltYWdlUmVzcG9uc2U+O1xuICAvKipcbiAgICogTG9hZHMgdGhlIGBjYWNoZUhhbmRsZXJgIG1vZHVsZSBmcm9tIGl0cyBmaWxlIFVSTC4gQSBzZWFtIGZvciB0ZXN0cywgd2hpY2hcbiAgICogcnVuIGFzIENvbW1vbkpTIGFuZCBjYW5ub3QgYGltcG9ydCgpYCBhIFVSTC5cbiAgICogQGRlZmF1bHQgLSBgaW1wb3J0KClgXG4gICAqL1xuICByZWFkb25seSBpbXBvcnRNb2R1bGU/OiAodXJsOiBzdHJpbmcpID0+IFByb21pc2U8dW5rbm93bj47XG59XG5cbi8qKiBUaGUgcmVzcG9uc2Uge0BsaW5rIEltYWdlT3B0aW1pemVyT3B0aW9ucy5mZXRjaEludGVybmFsfSBnb3QuICovXG5leHBvcnQgaW50ZXJmYWNlIEludGVybmFsSW1hZ2VSZXNwb25zZSB7XG4gIHJlYWRvbmx5IHN0YXR1c0NvZGU6IG51bWJlcjtcbiAgcmVhZG9ubHkgaGVhZGVyczogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+PjtcbiAgcmVhZG9ubHkgYm9keTogQnVmZmVyO1xuICAvKipcbiAgICogVGhlIGBmdW5jdGlvbkdyb3Vwc2AgZ3JvdXAgd2hvc2UgcGFja2FnZSBoYXMgdGhlIHJvdXRlIHRoYXQgc2VydmVzIHRoZVxuICAgKiBzb3VyY2UsIHdoZW4gaXQgaXMgbm90IHRoaXMgZnVuY3Rpb24nczogdGhlcmUgaXMgbm8gcmVzcG9uc2UgdG8gdXNlLCBhbmRcbiAgICogdGhlIG9wdGltaXplciBhbnN3ZXJzIGFuIGV4cGxpY2l0IDUwMiByYXRoZXIgdGhhbiBhIFwibm90IGEgdmFsaWQgaW1hZ2VcIi5cbiAgICovXG4gIHJlYWRvbmx5IG90aGVyR3JvdXA/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgYm9keSBwYXNzZWQgYGltYWdlcy5tYXhpbXVtUmVzcG9uc2VCb2R5YCwgc28gaXQgd2FzIGN1dCBvZmY6IGEgNDEzLCBhc1xuICAgKiBgbmV4dCBzdGFydGAgYW5zd2Vycy5cbiAgICovXG4gIHJlYWRvbmx5IHRvb0xhcmdlPzogYm9vbGVhbjtcbn1cblxuLyoqIFdoYXQgYHJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYCBpcyByZWFkIGZvci4gKi9cbmludGVyZmFjZSBSZXF1aXJlZFNlcnZlckZpbGVzIHtcbiAgY29uZmlnOiBOZXh0Q29uZmlnQ29tcGxldGU7XG59XG5cbmV4cG9ydCBjbGFzcyBSdW50aW1lSW1hZ2VPcHRpbWl6ZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IHMzID0gczNDbGllbnQoKTtcbiAgcHJpdmF0ZSBsb2FkZWQ/OiBSZXR1cm5UeXBlPHR5cGVvZiBsb2FkSW1hZ2VSdW50aW1lPjtcbiAgcHJpdmF0ZSBpbWFnZUNhY2hlPzogUHJvbWlzZTxJbWFnZUNhY2hlPjtcblxuICBwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBJbWFnZU9wdGltaXplck9wdGlvbnMpIHt9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGFwcCBzZXJ2ZXMgYC9fbmV4dC9pbWFnZWAgYXQgYWxsLiBgbmV4dCBzdGFydGAgYW5zd2VycyA0MDRcbiAgICogd2hlbiBgaW1hZ2VzLnVub3B0aW1pemVkYCBpcyBzZXQgb3IgYSBub24tZGVmYXVsdCBgbG9hZGVyYCBpcyBjb25maWd1cmVkXG4gICAqIChgbmV4dC1zZXJ2ZXIuanNgKSwgYW5kIHNvIGRvZXMgdGhlIHJ1bnRpbWU6IG90aGVyd2lzZSBhbnlvbmUgY2FuIG1ha2UgdGhlXG4gICAqIGNvbXB1dGUgcnVuIHNoYXJwIGFuZCB3cml0ZSB0aGUgaW1hZ2UgY2FjaGUgb24gYW4gZW5kcG9pbnQgdGhlIGFwcCB0dXJuZWRcbiAgICogb2ZmLlxuICAgKi9cbiAgcHVibGljIGlzRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgICB0aGlzLmxvYWRlZCA/Pz0gbG9hZEltYWdlUnVudGltZSh0aGlzLm9wdGlvbnMpO1xuICAgIGNvbnN0IHsgaW1hZ2VzQ29uZmlnIH0gPSB0aGlzLmxvYWRlZDtcbiAgICByZXR1cm4gaW1hZ2VzQ29uZmlnLmxvYWRlciA9PT0gXCJkZWZhdWx0XCIgJiYgIWltYWdlc0NvbmZpZy51bm9wdGltaXplZDtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBoYW5kbGUoXG4gICAgcmVxOiBTaGltSW5jb21pbmdNZXNzYWdlLFxuICAgIHJlczogU2hpbVNlcnZlclJlc3BvbnNlLFxuICAgIHVybDogVVJMLFxuICAgIHdhaXRVbnRpbDogKHByb21pc2U6IFByb21pc2U8dW5rbm93bj4pID0+IHZvaWQsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIFJlc29sdmVkIG9uIHRoZSBmaXJzdCBpbWFnZSByZXF1ZXN0IHJhdGhlciB0aGFuIGF0IGNvbGQgc3RhcnQ6IGFuIGFwcCB3aXRoXG4gICAgLy8gbm8gYDxJbWFnZT5gIHNob3VsZCBwYXkgbmVpdGhlciB0aGUgYG5leHRgIG1vZHVsZSBsb2FkcyBub3IgdGhlXG4gICAgLy8gYHJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYCBwYXJzZS5cbiAgICB0aGlzLmxvYWRlZCA/Pz0gbG9hZEltYWdlUnVudGltZSh0aGlzLm9wdGlvbnMpO1xuICAgIGNvbnN0IHsgbmV4dCwgbmV4dENvbmZpZywgaW1hZ2VzQ29uZmlnIH0gPSB0aGlzLmxvYWRlZDtcbiAgICBjb25zdCB7XG4gICAgICBJbWFnZUVycm9yLFxuICAgICAgSW1hZ2VPcHRpbWl6ZXJDYWNoZSxcbiAgICAgIGZldGNoRXh0ZXJuYWxJbWFnZSxcbiAgICAgIGltYWdlT3B0aW1pemVyLFxuICAgICAgc2VuZFJlc3BvbnNlLFxuICAgIH0gPSBuZXh0Lm9wdGltaXplcjtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJhbXMgPSBJbWFnZU9wdGltaXplckNhY2hlLnZhbGlkYXRlUGFyYW1zKFxuICAgICAgICByZXEgYXMgdW5rbm93biBhcyBQYXJhbWV0ZXJzPFxuICAgICAgICAgIHR5cGVvZiBJbWFnZU9wdGltaXplckNhY2hlLnZhbGlkYXRlUGFyYW1zXG4gICAgICAgID5bMF0sXG4gICAgICAgIE9iamVjdC5mcm9tRW50cmllcyh1cmwuc2VhcmNoUGFyYW1zKSxcbiAgICAgICAgbmV4dENvbmZpZyxcbiAgICAgICAgZmFsc2UsXG4gICAgICApO1xuICAgICAgaWYgKFwiZXJyb3JNZXNzYWdlXCIgaW4gcGFyYW1zKSB7XG4gICAgICAgIHJldHVybiBzZW5kVGV4dChyZXMsIDQwMCwgcGFyYW1zLmVycm9yTWVzc2FnZSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHsgaHJlZiwgaXNBYnNvbHV0ZSB9ID0gcGFyYW1zO1xuICAgICAgY29uc3Qgb3B0aW1pemUgPSBhc3luYyAocHJldmlvdXNDYWNoZUVudHJ5PzogUHJldmlvdXNJbWFnZUVudHJ5KSA9PiB7XG4gICAgICAgIGNvbnN0IHVwc3RyZWFtID0gaXNBYnNvbHV0ZVxuICAgICAgICAgID8gYXdhaXQgZmV0Y2hFeHRlcm5hbEltYWdlKFxuICAgICAgICAgICAgICBocmVmLFxuICAgICAgICAgICAgICBpbWFnZXNDb25maWcuZGFuZ2Vyb3VzbHlBbGxvd0xvY2FsSVAsXG4gICAgICAgICAgICAgIGltYWdlc0NvbmZpZy5tYXhpbXVtUmVzcG9uc2VCb2R5LFxuICAgICAgICAgICAgICBpbWFnZXNDb25maWcubWF4aW11bVJlZGlyZWN0cyxcbiAgICAgICAgICAgIClcbiAgICAgICAgICA6IGF3YWl0IHRoaXMuZmV0Y2hMb2NhbChcbiAgICAgICAgICAgICAgcmVxLFxuICAgICAgICAgICAgICBocmVmLFxuICAgICAgICAgICAgICBuZXh0Q29uZmlnLFxuICAgICAgICAgICAgICBpbWFnZXNDb25maWcubWF4aW11bVJlc3BvbnNlQm9keSxcbiAgICAgICAgICAgICAgbmV4dC5vcHRpbWl6ZXIsXG4gICAgICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IG9wdGltaXplZCA9IGF3YWl0IGltYWdlT3B0aW1pemVyKFxuICAgICAgICAgIHVwc3RyZWFtLFxuICAgICAgICAgIHBhcmFtcyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBleHBlcmltZW50YWw6IG5leHRDb25maWcuZXhwZXJpbWVudGFsLFxuICAgICAgICAgICAgaW1hZ2VzOiB7XG4gICAgICAgICAgICAgIGRhbmdlcm91c2x5QWxsb3dTVkc6IGltYWdlc0NvbmZpZy5kYW5nZXJvdXNseUFsbG93U1ZHLFxuICAgICAgICAgICAgICBtaW5pbXVtQ2FjaGVUVEw6IGltYWdlc0NvbmZpZy5taW5pbXVtQ2FjaGVUVEwsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBpc0RldjogZmFsc2UsIHByZXZpb3VzQ2FjaGVFbnRyeSB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIGBpbWFnZU9wdGltaXplcmAgcmVwb3J0cyBhIGZhaWxlZCBvcHRpbWl6YXRpb24gYnkgcmV0dXJuaW5nIHRoZVxuICAgICAgICAvLyB1bnRvdWNoZWQgdXBzdHJlYW0gaW1hZ2UgYWxvbmdzaWRlIGBlcnJvcmAgcmF0aGVyIHRoYW4gdGhyb3dpbmcsIHNvXG4gICAgICAgIC8vIHdpdGhvdXQgdGhpcyBhIGJyb2tlbiBgc2hhcnBgIGluc3RhbGwgc2VydmVzIGZ1bGwtc2l6ZSBvcmlnaW5hbHMgd2l0aFxuICAgICAgICAvLyBhIDIwMCBpbmRlZmluaXRlbHkgYW5kIG5vdGhpbmcgaW4gdGhlIGxvZ3Mgc2F5cyB3aHkuXG4gICAgICAgIGlmIChvcHRpbWl6ZWQuZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgYEZhaWxlZCB0byBvcHRpbWl6ZSAke2hyZWZ9LCBzZXJ2aW5nIHRoZSB1bm9wdGltaXplZCBvcmlnaW5hbDpgLFxuICAgICAgICAgICAgb3B0aW1pemVkLmVycm9yLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG9wdGltaXplZDtcbiAgICAgIH07XG5cbiAgICAgIC8vIE5leHQncyBvd24gcmVzcG9uc2Ugd3JpdGVyLCByYXRoZXIgdGhhbiBhIHJlc3RhdGVtZW50IG9mIGl0LCBzbyB0aGVcbiAgICAgIC8vIGhlYWRlcnMgYG5leHQgc3RhcnRgIHNlbmRzIGNvbWUgd2l0aCBpdDogdGhlIHllYXItbG9uZyBgaW1tdXRhYmxlYCBmb3JcbiAgICAgIC8vIGEgYC9fbmV4dC9zdGF0aWMvbWVkaWFgIHNyYywgYElmLU5vbmUtTWF0Y2hgIGFzIGBmcmVzaGAgcmVhZHMgaXQgKHdlYWtcbiAgICAgIC8vIGFuZCBsaXN0ZWQgdGFncywgYENhY2hlLUNvbnRyb2w6IG5vLWNhY2hlYCksIGEgYENvbnRlbnQtRGlzcG9zaXRpb25gXG4gICAgICAvLyB0aGF0IFJGQyA1OTg3LWVuY29kZXMgYSBmaWxlbmFtZSBgd3JpdGVIZWFkYCB3b3VsZCByZWplY3QgYXNcbiAgICAgIC8vIG5vbi1sYXRpbjEsIGBDb250ZW50LUxlbmd0aGAsIGFuZCBubyBib2R5IGZvciBIRUFELiBUaGUgcmVzdGF0ZWRcbiAgICAgIC8vIHZlcnNpb24gaGFkIGRyaWZ0ZWQgb24gZXZlcnkgb25lIG9mIHRob3NlLlxuICAgICAgY29uc3Qgc2VuZCA9IChcbiAgICAgICAgZXh0ZW5zaW9uOiBzdHJpbmcsXG4gICAgICAgIGJ1ZmZlcjogQnVmZmVyLFxuICAgICAgICBldGFnOiBzdHJpbmcsXG4gICAgICAgIHhDYWNoZTogXCJNSVNTXCIgfCBcIkhJVFwiIHwgXCJTVEFMRVwiLFxuICAgICAgICBtYXhBZ2U6IG51bWJlcixcbiAgICAgICkgPT4ge1xuICAgICAgICByZXMuc3RhdHVzQ29kZSA9IDIwMDtcbiAgICAgICAgc2VuZFJlc3BvbnNlKFxuICAgICAgICAgIHJlcSBhcyB1bmtub3duIGFzIFBhcmFtZXRlcnM8dHlwZW9mIHNlbmRSZXNwb25zZT5bMF0sXG4gICAgICAgICAgYXNTZXJ2ZXJSZXNwb25zZShyZXMpLFxuICAgICAgICAgIGhyZWYsXG4gICAgICAgICAgZXh0ZW5zaW9uLFxuICAgICAgICAgIGJ1ZmZlcixcbiAgICAgICAgICBldGFnLFxuICAgICAgICAgIHBhcmFtcy5pc1N0YXRpYyxcbiAgICAgICAgICB4Q2FjaGUsXG4gICAgICAgICAgaW1hZ2VzQ29uZmlnLFxuICAgICAgICAgIG1heEFnZSxcbiAgICAgICAgICBmYWxzZSxcbiAgICAgICAgKTtcbiAgICAgIH07XG5cbiAgICAgIC8vIGBuZXh0IHN0YXJ0YCdzIGBoYW5kbGVOZXh0SW1hZ2VSZXF1ZXN0YCwgc3RlcCBmb3Igc3RlcDogYVxuICAgICAgLy8gYFJlc3BvbnNlQ2FjaGVgIG92ZXIgYW4gYEltYWdlT3B0aW1pemVyQ2FjaGVgIGJhY2tlZCBieSB0aGUgYXBwJ3NcbiAgICAgIC8vIGBjYWNoZUhhbmRsZXJgLCBzbyBhIGhpdCBza2lwcyB0aGUgZmV0Y2ggYW5kIGBzaGFycGAsIGEgc3RhbGUgZW50cnkgaXNcbiAgICAgIC8vIHNlcnZlZCB3aGlsZSBpdCBpcyByZWdlbmVyYXRlZCwgYW5kIGNvbmN1cnJlbnQgbWlzc2VzIGZvciBvbmUgaW1hZ2VcbiAgICAgIC8vIG9wdGltaXplIGl0IG9uY2UuIFRoZSBhcHAncyBgY2FjaGVIYW5kbGVyYCBpcyB0aGUgUzMgY2FjaGUsIHdoaWNoIHRoZVxuICAgICAgLy8gYWRhcHRlciB0dXJucyBvbiB3aXRoIGBpbWFnZXMuY3VzdG9tQ2FjaGVIYW5kbGVyYDogd2l0aCBubyBDRE4gaW4gZnJvbnRcbiAgICAgIC8vICh0aGUgUmVnaW9uYWwgdHlwZXMpIGV2ZXJ5IHJlcXVlc3Qgd291bGQgb3RoZXJ3aXNlIHJ1biBgc2hhcnBgIGFnYWluLFxuICAgICAgLy8gYW5kIGJlaGluZCBDbG91ZEZyb250IGVhY2ggZWRnZSBtaXNzIGlzIGFuIFMzIHJlYWQgaW5zdGVhZC5cbiAgICAgIGNvbnN0IGNhY2hlID0gYXdhaXQgdGhpcy5sb2FkQ2FjaGUodGhpcy5sb2FkZWQpO1xuICAgICAgY29uc3QgZW50cnkgPSBhd2FpdCBjYWNoZS5yZXNwb25zZXMuZ2V0KFxuICAgICAgICBJbWFnZU9wdGltaXplckNhY2hlLmdldENhY2hlS2V5KHBhcmFtcyksXG4gICAgICAgIGFzeW5jICh7IHByZXZpb3VzQ2FjaGVFbnRyeSB9KSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBidWZmZXIsIGNvbnRlbnRUeXBlLCBtYXhBZ2UsIGV0YWcsIHVwc3RyZWFtRXRhZyB9ID1cbiAgICAgICAgICAgIGF3YWl0IG9wdGltaXplKHByZXZpb3VzQ2FjaGVFbnRyeSBhcyBQcmV2aW91c0ltYWdlRW50cnkpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB2YWx1ZToge1xuICAgICAgICAgICAgICBraW5kOiBJTUFHRV9LSU5ELFxuICAgICAgICAgICAgICBidWZmZXIsXG4gICAgICAgICAgICAgIGV0YWcsXG4gICAgICAgICAgICAgIGV4dGVuc2lvbjogbmV4dC5zZXJ2ZVN0YXRpYy5nZXRFeHRlbnNpb24oY29udGVudFR5cGUpID8/IFwiXCIsXG4gICAgICAgICAgICAgIHVwc3RyZWFtRXRhZyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBjYWNoZUNvbnRyb2w6IHsgcmV2YWxpZGF0ZTogbWF4QWdlLCBleHBpcmU6IHVuZGVmaW5lZCB9LFxuICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICByb3V0ZUtpbmQ6IElNQUdFX0tJTkQsXG4gICAgICAgICAgaW5jcmVtZW50YWxDYWNoZTogZGVmZXJXcml0ZXMoY2FjaGUuaW1hZ2VzLCB3YWl0VW50aWwpLFxuICAgICAgICAgIGlzRmFsbGJhY2s6IGZhbHNlLFxuICAgICAgICAgIC8vIEEgc3RhbGUgZW50cnkgaXMgc2VydmVkIGF0IG9uY2UgYW5kIHJlZ2VuZXJhdGVkIGluIHRoZSBiYWNrZ3JvdW5kO1xuICAgICAgICAgIC8vIHdpdGhvdXQgdGhpcywgYSBMYW1iZGEgY291bGQgZnJlZXplIHdpdGggdGhlIHJlZ2VuZXJhdGlvbiBoYWxmIGRvbmUuXG4gICAgICAgICAgd2FpdFVudGlsLFxuICAgICAgICB9IGFzIHVua25vd24gYXMgUGFyYW1ldGVyczxJbWFnZUNhY2hlW1wicmVzcG9uc2VzXCJdW1wiZ2V0XCJdPlsyXSxcbiAgICAgICk7XG4gICAgICBjb25zdCB2YWx1ZSA9IGVudHJ5Py52YWx1ZSBhc1xuICAgICAgICB8IHtcbiAgICAgICAgICAgIGtpbmQ6IHN0cmluZztcbiAgICAgICAgICAgIGV4dGVuc2lvbjogc3RyaW5nO1xuICAgICAgICAgICAgYnVmZmVyOiBCdWZmZXI7XG4gICAgICAgICAgICBldGFnOiBzdHJpbmc7XG4gICAgICAgICAgfVxuICAgICAgICB8IG51bGxcbiAgICAgICAgfCB1bmRlZmluZWQ7XG4gICAgICBpZiAodmFsdWU/LmtpbmQgIT09IElNQUdFX0tJTkQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhlIGltYWdlIGNhY2hlIHJldHVybmVkIG5vIGltYWdlIGVudHJ5XCIpO1xuICAgICAgfVxuICAgICAgc2VuZChcbiAgICAgICAgdmFsdWUuZXh0ZW5zaW9uLFxuICAgICAgICB2YWx1ZS5idWZmZXIsXG4gICAgICAgIHZhbHVlLmV0YWcsXG4gICAgICAgIGVudHJ5IS5pc01pc3MgPyBcIk1JU1NcIiA6IGVudHJ5IS5pc1N0YWxlID8gXCJTVEFMRVwiIDogXCJISVRcIixcbiAgICAgICAgZW50cnkhLmNhY2hlQ29udHJvbD8ucmV2YWxpZGF0ZSB8fCAwLFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgeyBzdGF0dXNDb2RlLCBtZXNzYWdlIH0gPSByZXNvbHZlRXJyb3JSZXNwb25zZShlcnJvciwgSW1hZ2VFcnJvcik7XG4gICAgICBpZiAoc3RhdHVzQ29kZSA+PSA1MDApIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkltYWdlIG9wdGltaXphdGlvbiBmYWlsZWQ6XCIsIGVycm9yKTtcbiAgICAgIH1cbiAgICAgIHNlbmRUZXh0KHJlcywgc3RhdHVzQ29kZSwgbWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEV2aWN0ZWQgb24gZmFpbHVyZSwgYXMgYEVudHJ5cG9pbnRSZWdpc3RyeS5sb2FkYCBldmljdHMgYSBmYWlsZWQgbW9kdWxlIGxvYWQ6XG4gICAqIGEgdHJhbnNpZW50IGZhaWx1cmUgaW1wb3J0aW5nIHRoZSBgY2FjaGVIYW5kbGVyYCAoRU1GSUxFIHVuZGVyIGEgY29sZC1zdGFydFxuICAgKiBidXJzdCkgd291bGQgb3RoZXJ3aXNlIDUwMCBldmVyeSBpbWFnZSByZXF1ZXN0IHVudGlsIHRoZSBzYW5kYm94IHJlY3ljbGVzLlxuICAgKi9cbiAgcHJpdmF0ZSBsb2FkQ2FjaGUoXG4gICAgbG9hZGVkOiBSZXR1cm5UeXBlPHR5cGVvZiBsb2FkSW1hZ2VSdW50aW1lPixcbiAgKTogUHJvbWlzZTxJbWFnZUNhY2hlPiB7XG4gICAgaWYgKCF0aGlzLmltYWdlQ2FjaGUpIHtcbiAgICAgIGNvbnN0IGNhY2hlID0gbG9hZEltYWdlQ2FjaGUodGhpcy5vcHRpb25zLCBsb2FkZWQpO1xuICAgICAgdGhpcy5pbWFnZUNhY2hlID0gY2FjaGU7XG4gICAgICBjYWNoZS5jYXRjaCgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmltYWdlQ2FjaGUgPT09IGNhY2hlKSB7XG4gICAgICAgICAgdGhpcy5pbWFnZUNhY2hlID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaW1hZ2VDYWNoZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hMb2NhbChcbiAgICByZXE6IFNoaW1JbmNvbWluZ01lc3NhZ2UsXG4gICAgaHJlZjogc3RyaW5nLFxuICAgIG5leHRDb25maWc6IFJldHVyblR5cGU8dHlwZW9mIGxvYWRJbWFnZVJ1bnRpbWU+W1wibmV4dENvbmZpZ1wiXSxcbiAgICBtYXhpbXVtUmVzcG9uc2VCb2R5OiBudW1iZXIsXG4gICAgb3B0aW1pemVyOiBOZXh0SW1hZ2VNb2R1bGVzW1wib3B0aW1pemVyXCJdLFxuICApIHtcbiAgICBjb25zdCB7IGJ1Y2tldCwgZmV0Y2hJbnRlcm5hbCB9ID0gdGhpcy5vcHRpb25zO1xuICAgIC8vIE5vIGJ1Y2tldCB3aGVuIHRoZSBzb3VyY2VzIGFyZSBvbiBkaXNrIChgTmV4dGpzUmVnaW9uYWxDb250YWluZXJzYCksIGFuZFxuICAgIC8vIHRoZSByb3V0ZXMgc2VydmUgdGhvc2UgYXMgdGhleSBzZXJ2ZSBhbnl0aGluZyBTMyBoYXMgbm8gZmlsZSBmb3IuXG4gICAgaWYgKGJ1Y2tldCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZmV0Y2hGcm9tUzMoXG4gICAgICAgICAgdGhpcy5zMyxcbiAgICAgICAgICBidWNrZXQsXG4gICAgICAgICAgaHJlZixcbiAgICAgICAgICB7XG4gICAgICAgICAgICB1cmxCYXNlUGF0aDogbmV4dENvbmZpZy5iYXNlUGF0aCxcbiAgICAgICAgICAgIGtleVByZWZpeDogdGhpcy5vcHRpb25zLmJ1Y2tldEtleVByZWZpeCxcbiAgICAgICAgICAgIGFzc2V0UHJlZml4OiBuZXh0Q29uZmlnLmFzc2V0UHJlZml4LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgbWF4aW11bVJlc3BvbnNlQm9keSxcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBidWZmZXI6IHJlc3VsdC5idWZmZXIsXG4gICAgICAgICAgY29udGVudFR5cGU6IHJlc3VsdC5jb250ZW50VHlwZSxcbiAgICAgICAgICBjYWNoZUNvbnRyb2w6IG51bGwsXG4gICAgICAgICAgZXRhZzogcmVzdWx0LmV0YWcsXG4gICAgICAgIH07XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBtaXNzaW5nID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciAmJiBlcnJvci5uYW1lID09PSBcIk5vU3VjaEtleVwiO1xuICAgICAgICBpZiAoIW1pc3NpbmcpIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFdoYXQgYGZldGNoSW50ZXJuYWxJbWFnZWAgY2hlY2tzLCBhbmQgdGhyb3dzLCBmb3IgdGhlIHNhbWUgcmVzcG9uc2UuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaEludGVybmFsKGhyZWYsIHJlcSwgbWF4aW11bVJlc3BvbnNlQm9keSk7XG4gICAgaWYgKHJlc3BvbnNlLm90aGVyR3JvdXAgIT09IHVuZGVmaW5lZCkge1xuICAgICAgLy8gQSBkZXBsb3ltZW50IHByb2JsZW0sIG5vdCBhIGJhZCBgdXJsYDogbGVhdmUgdGhlIHJvdXRlIGluIHRoZSBkZWZhdWx0XG4gICAgICAvLyBncm91cCwgb3Igc2VydmUgdGhlIGltYWdlIGFzIGEgZmlsZSAocHVibGljLyBvciBhIHN0YXRpYyBpbXBvcnQpLlxuICAgICAgdGhyb3cgbmV3IG9wdGltaXplci5JbWFnZUVycm9yKFxuICAgICAgICA1MDIsXG4gICAgICAgICdcInVybFwiIHBhcmFtZXRlciBpcyB2YWxpZCBidXQgaXRzIHNvdXJjZSBpcyBhIHJvdXRlIGluIGFub3RoZXIgJyArXG4gICAgICAgICAgYGZ1bmN0aW9uR3JvdXBzIGdyb3VwIChcIiR7cmVzcG9uc2Uub3RoZXJHcm91cH1cIiksIHdoaWNoIHRoZSBpbWFnZSBgICtcbiAgICAgICAgICBcIm9wdGltaXplciBjYW5ub3QgZmV0Y2hcIixcbiAgICAgICk7XG4gICAgfVxuICAgIGlmIChyZXNwb25zZS50b29MYXJnZSkge1xuICAgICAgdGhyb3cgbmV3IG9wdGltaXplci5JbWFnZUVycm9yKFxuICAgICAgICA0MTMsXG4gICAgICAgICdcInVybFwiIHBhcmFtZXRlciBpcyB2YWxpZCBidXQgaW50ZXJuYWwgcmVzcG9uc2UgaXMgaW52YWxpZCcsXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoIXJlc3BvbnNlLnN0YXR1c0NvZGUgfHwgcmVzcG9uc2UuYm9keS5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBvcHRpbWl6ZXIuSW1hZ2VFcnJvcihcbiAgICAgICAgNDAwLFxuICAgICAgICAnXCJ1cmxcIiBwYXJhbWV0ZXIgaXMgdmFsaWQgYnV0IGludGVybmFsIHJlc3BvbnNlIGlzIGludmFsaWQnLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGJ1ZmZlcjogcmVzcG9uc2UuYm9keSxcbiAgICAgIGNvbnRlbnRUeXBlOiBmaXJzdFZhbHVlKHJlc3BvbnNlLmhlYWRlcnNbXCJjb250ZW50LXR5cGVcIl0pID8/IG51bGwsXG4gICAgICBjYWNoZUNvbnRyb2w6IGZpcnN0VmFsdWUocmVzcG9uc2UuaGVhZGVyc1tcImNhY2hlLWNvbnRyb2xcIl0pID8/IG51bGwsXG4gICAgICBldGFnOiBvcHRpbWl6ZXIuZXh0cmFjdEV0YWcoXG4gICAgICAgIGZpcnN0VmFsdWUocmVzcG9uc2UuaGVhZGVycy5ldGFnKSA/PyBudWxsLFxuICAgICAgICByZXNwb25zZS5ib2R5LFxuICAgICAgKSxcbiAgICB9O1xuICB9XG59XG5cbi8qKlxuICogYENhY2hlZFJvdXRlS2luZC5JTUFHRWAsIHdoaWNoIGlzIGFsc28gYFJvdXRlS2luZC5JTUFHRWAuIFJlc3RhdGVkOiB0aGUgZW51bSBpc1xuICogYSBydW50aW1lIHZhbHVlIG9mIGBuZXh0YCwgd2hpY2ggdGhlIGJ1bmRsZSBjYW5ub3QgaW1wb3J0LlxuICovXG5jb25zdCBJTUFHRV9LSU5EID0gXCJJTUFHRVwiIGFzIENhY2hlZFJvdXRlS2luZC5JTUFHRTtcblxuLyoqIGBpbWFnZU9wdGltaXplcmAncyBgcHJldmlvdXNDYWNoZUVudHJ5YC4gKi9cbnR5cGUgUHJldmlvdXNJbWFnZUVudHJ5ID0gUGFyYW1ldGVyczxcbiAgTmV4dEltYWdlTW9kdWxlc1tcIm9wdGltaXplclwiXVtcImltYWdlT3B0aW1pemVyXCJdXG4+WzNdW1wicHJldmlvdXNDYWNoZUVudHJ5XCJdO1xuXG5pbnRlcmZhY2UgSW1hZ2VDYWNoZSB7XG4gIHJlYWRvbmx5IHJlc3BvbnNlczogSW5zdGFuY2VUeXBlPFxuICAgIE5leHRJbWFnZUNhY2hlTW9kdWxlc1tcInJlc3BvbnNlQ2FjaGVcIl1bXCJkZWZhdWx0XCJdXG4gID47XG4gIHJlYWRvbmx5IGltYWdlczogSW5zdGFuY2VUeXBlPFxuICAgIE5leHRJbWFnZU1vZHVsZXNbXCJvcHRpbWl6ZXJcIl1bXCJJbWFnZU9wdGltaXplckNhY2hlXCJdXG4gID47XG59XG5cbi8qKlxuICogVGhlIGFwcCdzIGBjYWNoZUhhbmRsZXJgLCBjb25zdHJ1Y3RlZCB0aGUgd2F5IGBuZXh0IHN0YXJ0YCBjb25zdHJ1Y3RzIGl0IGZvclxuICogaW1hZ2VzIChgbmV4dC1zZXJ2ZXIuanNgLCBgaGFuZGxlTmV4dEltYWdlUmVxdWVzdGApOiBvbmNlLCBhbmQga2VwdCwgc28gaXRzXG4gKiBpbi1tZW1vcnkgbGF5ZXIgbGFzdHMgYWNyb3NzIHJlcXVlc3RzLiBJdHMgcGF0aCBpbiBgcmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25gXG4gKiBpcyByZWxhdGl2ZSB0byB0aGUgZGlzdCBkaXI7IHNlZSB7QGxpbmsgY2FjaGVIYW5kbGVyVXJsfS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gbG9hZEltYWdlQ2FjaGUoXG4gIHsgZGVwbG95bWVudFJvb3QsIG1hbmlmZXN0LCBpbXBvcnRNb2R1bGUgfTogSW1hZ2VPcHRpbWl6ZXJPcHRpb25zLFxuICBsb2FkZWQ6IFJldHVyblR5cGU8dHlwZW9mIGxvYWRJbWFnZVJ1bnRpbWU+LFxuKTogUHJvbWlzZTxJbWFnZUNhY2hlPiB7XG4gIGNvbnN0IHsgbmV4dCwgbmV4dENvbmZpZyB9ID0gbG9hZGVkO1xuICBjb25zdCBtb2R1bGVzOiBOZXh0SW1hZ2VDYWNoZU1vZHVsZXMgPSB7XG4gICAgcmVzcG9uc2VDYWNoZTogbmV4dE1vZHVsZShcIm5leHQvZGlzdC9zZXJ2ZXIvcmVzcG9uc2UtY2FjaGUvaW5kZXguanNcIiksXG4gIH07XG4gIGNvbnN0IGRpc3REaXIgPSBqb2luKFxuICAgIGRlcGxveW1lbnRSb290LFxuICAgIG1hbmlmZXN0LnJlbGF0aXZlUHJvamVjdERpcixcbiAgICBtYW5pZmVzdC5jb25maWcuZGlzdERpcixcbiAgKTtcbiAgbGV0IGNhY2hlSGFuZGxlcjogSW5zdGFuY2VUeXBlPENhY2hlSGFuZGxlckNsYXNzPiB8IHVuZGVmaW5lZDtcbiAgaWYgKG5leHRDb25maWcuY2FjaGVIYW5kbGVyKSB7XG4gICAgY29uc3QgdXJsID0gY2FjaGVIYW5kbGVyVXJsKGRpc3REaXIsIG5leHRDb25maWcuY2FjaGVIYW5kbGVyKTtcbiAgICBjb25zdCBpbXBvcnRlZCA9IChhd2FpdCAoaW1wb3J0TW9kdWxlXG4gICAgICA/IGltcG9ydE1vZHVsZSh1cmwpXG4gICAgICA6IGltcG9ydCh1cmwpKSkgYXMgeyBkZWZhdWx0PzogQ2FjaGVIYW5kbGVyQ2xhc3MgfSAmIENhY2hlSGFuZGxlckNsYXNzO1xuICAgIGNvbnN0IENhY2hlSGFuZGxlciA9IGltcG9ydGVkLmRlZmF1bHQgPz8gaW1wb3J0ZWQ7XG4gICAgY2FjaGVIYW5kbGVyID0gbmV3IENhY2hlSGFuZGxlcih7XG4gICAgICBkZXY6IGZhbHNlLFxuICAgICAgZmx1c2hUb0Rpc2s6IG5leHRDb25maWcuZXhwZXJpbWVudGFsLmlzckZsdXNoVG9EaXNrLFxuICAgICAgc2VydmVyRGlzdERpcjogam9pbihkaXN0RGlyLCBcInNlcnZlclwiKSxcbiAgICAgIG1heE1lbW9yeUNhY2hlU2l6ZTogbmV4dENvbmZpZy5jYWNoZU1heE1lbW9yeVNpemUsXG4gICAgICByZXZhbGlkYXRlZFRhZ3M6IFtdLFxuICAgICAgX3JlcXVlc3RIZWFkZXJzOiB7fSxcbiAgICB9KTtcbiAgfVxuICByZXR1cm4ge1xuICAgIHJlc3BvbnNlczogbmV3IG1vZHVsZXMucmVzcG9uc2VDYWNoZS5kZWZhdWx0KGZhbHNlKSxcbiAgICBpbWFnZXM6IG5ldyBuZXh0Lm9wdGltaXplci5JbWFnZU9wdGltaXplckNhY2hlKHtcbiAgICAgIGRpc3REaXIsXG4gICAgICBuZXh0Q29uZmlnLFxuICAgICAgY2FjaGVIYW5kbGVyLFxuICAgIH0pLFxuICB9O1xufVxuXG4vKipcbiAqIGBmb3JtYXREeW5hbWljSW1wb3J0UGF0aGAgZnJvbSBgbmV4dC9kaXN0L2xpYi9mb3JtYXQtZHluYW1pYy1pbXBvcnQtcGF0aC5qc2AsXG4gKiByZXN0YXRlZDogYG5leHQgYnVpbGRgIGRvZXNuJ3QgdHJhY2UgdGhhdCBtb2R1bGUgaW50byB0aGUgZGVwbG95bWVudCwgc29cbiAqIGxvYWRpbmcgaXQgZmFpbGVkIGV2ZXJ5IGltYWdlIHJlcXVlc3Qgd2l0aCB0aGUgY2FjaGUgb24uXG4gKi9cbmZ1bmN0aW9uIGNhY2hlSGFuZGxlclVybChkaXN0RGlyOiBzdHJpbmcsIGNhY2hlSGFuZGxlcjogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcGF0aCA9IGNhY2hlSGFuZGxlci5zdGFydHNXaXRoKFwiZmlsZTovL1wiKVxuICAgID8gZmlsZVVSTFRvUGF0aChjYWNoZUhhbmRsZXIpXG4gICAgOiBjYWNoZUhhbmRsZXI7XG4gIHJldHVybiBwYXRoVG9GaWxlVVJMKFxuICAgIGlzQWJzb2x1dGVQYXRoKHBhdGgpID8gcGF0aCA6IGpvaW4oZGlzdERpciwgcGF0aCksXG4gICkudG9TdHJpbmcoKTtcbn1cblxuLyoqXG4gKiBgaW1hZ2VzYCwgd2l0aCBpdHMgYHNldGAgbW92ZWQgb2ZmIHRoZSByZXNwb25zZSdzIGNyaXRpY2FsIHBhdGguXG4gKlxuICogYFJlc3BvbnNlQ2FjaGVgIGF3YWl0cyB0aGUgd3JpdGUgb2YgYSBmcmVzaGx5IG9wdGltaXplZCBpbWFnZSBiZWZvcmUgaXQgaGFuZHNcbiAqIHRoZSBpbWFnZSBiYWNrLCBzbyBldmVyeSBtaXNzIHBhaWQgYW4gUzMgYFB1dE9iamVjdGAgKH4zMCBtcyBtZWFzdXJlZCkgYmVmb3JlXG4gKiBpdHMgZmlyc3QgYnl0ZS4gVGhlIHdyaXRlIGlzIHJlZ2lzdGVyZWQgd2l0aCBgd2FpdFVudGlsYCBpbnN0ZWFkLCB3aGljaCB0aGVcbiAqIHJ1bnRpbWUgZHJhaW5zIGJlZm9yZSBhIExhbWJkYSBpbnZvY2F0aW9uIHJldHVybnMgb3IgYSBjb250YWluZXIgc2h1dHMgZG93bixcbiAqIHNvIGl0IHN0aWxsIGxhbmRzLiBBIGZhaWxlZCB3cml0ZSBpcyBsb2dnZWQ7IHRoZSBuZXh0IHJlcXVlc3Qgb3B0aW1pemVzIHRoZVxuICogaW1hZ2UgYWdhaW4sIHdoaWNoIGlzIHdoYXQgaXQgd291bGQgaGF2ZSBkb25lIGFueXdheS5cbiAqL1xuZnVuY3Rpb24gZGVmZXJXcml0ZXMoXG4gIGltYWdlczogSW1hZ2VDYWNoZVtcImltYWdlc1wiXSxcbiAgd2FpdFVudGlsOiAocHJvbWlzZTogUHJvbWlzZTx1bmtub3duPikgPT4gdm9pZCxcbik6IEltYWdlQ2FjaGVbXCJpbWFnZXNcIl0ge1xuICBjb25zdCBkZWZlcnJlZCA9IE9iamVjdC5jcmVhdGUoaW1hZ2VzKSBhcyBJbWFnZUNhY2hlW1wiaW1hZ2VzXCJdO1xuICBkZWZlcnJlZC5zZXQgPSAoLi4uYXJnczogUGFyYW1ldGVyczxJbWFnZUNhY2hlW1wiaW1hZ2VzXCJdW1wic2V0XCJdPikgPT4ge1xuICAgIHdhaXRVbnRpbChcbiAgICAgIGltYWdlcy5zZXQoLi4uYXJncykuY2F0Y2goKGVycm9yOiB1bmtub3duKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJGYWlsZWQgdG8gY2FjaGUgYW4gb3B0aW1pemVkIGltYWdlOlwiLCBlcnJvcik7XG4gICAgICB9KSxcbiAgICApO1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgfTtcbiAgcmV0dXJuIGRlZmVycmVkO1xufVxuXG5mdW5jdGlvbiBzZW5kVGV4dChcbiAgcmVzOiBTaGltU2VydmVyUmVzcG9uc2UsXG4gIHN0YXR1c0NvZGU6IG51bWJlcixcbiAgYm9keTogc3RyaW5nLFxuKTogdm9pZCB7XG4gIHJlcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcbiAgcmVzLnNldEhlYWRlcihcIkNvbnRlbnQtVHlwZVwiLCBcInRleHQvcGxhaW5cIik7XG4gIHJlcy5lbmQoYm9keSk7XG59XG5cbi8qKlxuICogVGhlIGltYWdlIGNvbmZpZyBjb21lcyBmcm9tIHRoZSBhcHAncyBvd24gYHJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYCwgbm90IHRoZVxuICogYWRhcHRlciBtYW5pZmVzdDogYGltYWdlT3B0aW1pemVyYCByZWFkcyB3aG9sZSBgZXhwZXJpbWVudGFsYCBhbmQgYGltYWdlc2BcbiAqIG9iamVjdHMsIGFuZCBtaXJyb3JpbmcgdGhvc2UgaW50byB0aGUgbWFuaWZlc3Qgd291bGQgYmUgYSBzZWNvbmQgZGVmaW5pdGlvbiBvZlxuICogdGhlIHNhbWUgdGhpbmcgdGhhdCBzaWxlbnRseSBnb2VzIHN0YWxlIG9uIGEgYG5leHRgIG1pbm9yLlxuICovXG5mdW5jdGlvbiBsb2FkSW1hZ2VSdW50aW1lKHsgZGVwbG95bWVudFJvb3QsIG1hbmlmZXN0IH06IEltYWdlT3B0aW1pemVyT3B0aW9ucykge1xuICBjb25zdCBuZXh0OiBOZXh0SW1hZ2VNb2R1bGVzID0ge1xuICAgIGNvbmZpZ1NoYXJlZDogbmV4dE1vZHVsZShcIm5leHQvZGlzdC9zZXJ2ZXIvY29uZmlnLXNoYXJlZC5qc1wiKSxcbiAgICBpbWFnZUNvbmZpZzogbmV4dE1vZHVsZShcIm5leHQvZGlzdC9zaGFyZWQvbGliL2ltYWdlLWNvbmZpZy5qc1wiKSxcbiAgICBvcHRpbWl6ZXI6IG5leHRNb2R1bGUoXCJuZXh0L2Rpc3Qvc2VydmVyL2ltYWdlLW9wdGltaXplci5qc1wiKSxcbiAgICBzZXJ2ZVN0YXRpYzogbmV4dE1vZHVsZShcIm5leHQvZGlzdC9zZXJ2ZXIvc2VydmUtc3RhdGljLmpzXCIpLFxuICB9O1xuICBjb25zdCBwYXRoID0gam9pbihcbiAgICBkZXBsb3ltZW50Um9vdCxcbiAgICBtYW5pZmVzdC5yZWxhdGl2ZVByb2plY3REaXIsXG4gICAgbWFuaWZlc3QuY29uZmlnLmRpc3REaXIsXG4gICAgXCJyZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvblwiLFxuICApO1xuICBjb25zdCByZXF1aXJlZDogUmVxdWlyZWRTZXJ2ZXJGaWxlcyA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGgsIFwidXRmLThcIikpO1xuICBjb25zdCBuZXh0Q29uZmlnID0gbmV4dC5jb25maWdTaGFyZWQuZ2V0TmV4dENvbmZpZ1J1bnRpbWUocmVxdWlyZWQuY29uZmlnKTtcbiAgcmV0dXJuIHtcbiAgICBuZXh0LFxuICAgIG5leHRDb25maWcsXG4gICAgaW1hZ2VzQ29uZmlnOiB7XG4gICAgICAuLi5uZXh0LmltYWdlQ29uZmlnLmltYWdlQ29uZmlnRGVmYXVsdCxcbiAgICAgIC4uLm5leHRDb25maWcuaW1hZ2VzLFxuICAgIH0sXG4gIH07XG59XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|