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.
Files changed (263) hide show
  1. package/.jsii +2404 -2723
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1681 -1930
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
  7. package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
  8. package/docs/adapter-runtime.md +185 -0
  9. package/docs/breaking-changes.md +667 -4
  10. package/docs/caching-guide.md +156 -112
  11. package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
  12. package/docs/development-guide.md +1 -1
  13. package/docs/harness-coverage.md +598 -0
  14. package/docs/init-cache-deployment.md +32 -1
  15. package/docs/next-build-output-guide.md +30 -20
  16. package/examples/README.md +5 -1
  17. package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
  18. package/lib/adapter/__fixtures__/app-playground.json +4917 -0
  19. package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
  20. package/lib/adapter/adapter.mjs +1551 -185
  21. package/lib/adapter/adapter.test.js +106 -0
  22. package/lib/adapter/aws-cache-store.d.ts +489 -0
  23. package/lib/adapter/aws-cache-store.js +1004 -0
  24. package/lib/adapter/aws-cache-store.test.d.ts +1 -0
  25. package/lib/adapter/aws-cache-store.test.js +361 -0
  26. package/lib/adapter/build-outputs.d.ts +80 -0
  27. package/lib/adapter/build-outputs.js +857 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +863 -0
  30. package/lib/adapter/cache-handler.d.ts +9 -2
  31. package/lib/adapter/cache-handler.js +72 -96
  32. package/lib/adapter/cache-handler.mjs +18956 -17774
  33. package/lib/adapter/cache-handler.test.js +263 -31
  34. package/lib/adapter/cache-kinds.d.ts +32 -0
  35. package/lib/adapter/cache-kinds.js +35 -0
  36. package/lib/adapter/cache-kinds.test.d.ts +1 -0
  37. package/lib/adapter/cache-kinds.test.js +69 -0
  38. package/lib/adapter/cache-utils.d.ts +90 -0
  39. package/lib/adapter/cache-utils.js +199 -4
  40. package/lib/adapter/cache-utils.test.d.ts +1 -0
  41. package/lib/adapter/cache-utils.test.js +179 -0
  42. package/lib/adapter/function-groups.d.ts +215 -0
  43. package/lib/adapter/function-groups.js +1099 -0
  44. package/lib/adapter/function-groups.test.d.ts +1 -0
  45. package/lib/adapter/function-groups.test.js +743 -0
  46. package/lib/adapter/init-cache.d.ts +6 -0
  47. package/lib/adapter/init-cache.js +245 -0
  48. package/lib/adapter/init-cache.test.d.ts +1 -0
  49. package/lib/adapter/init-cache.test.js +137 -0
  50. package/lib/adapter/local-file-cache-handler.d.ts +23 -0
  51. package/lib/adapter/local-file-cache-handler.js +52 -1
  52. package/lib/adapter/memory-cache-handler.d.ts +26 -17
  53. package/lib/adapter/memory-cache-handler.js +32 -50
  54. package/lib/adapter/memory-cache-handler.test.js +105 -85
  55. package/lib/adapter/s3-cache-handler.d.ts +179 -40
  56. package/lib/adapter/s3-cache-handler.js +807 -277
  57. package/lib/adapter/s3-cache-handler.test.js +1186 -31
  58. package/lib/adapter/use-cache-common.d.ts +90 -0
  59. package/lib/adapter/use-cache-common.js +250 -0
  60. package/lib/adapter/use-cache-common.test.d.ts +1 -0
  61. package/lib/adapter/use-cache-common.test.js +646 -0
  62. package/lib/adapter/use-cache-default-handler.d.ts +24 -0
  63. package/lib/adapter/use-cache-default-handler.js +90 -0
  64. package/lib/adapter/use-cache-default-handler.mjs +38645 -0
  65. package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
  66. package/lib/adapter/use-cache-handlers.test.js +349 -0
  67. package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
  68. package/lib/adapter/use-cache-remote-handler.js +186 -0
  69. package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
  70. package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
  71. package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
  72. package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
  73. package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
  74. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
  75. package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
  76. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
  77. package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
  78. package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
  81. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
  82. package/lib/index.d.ts +6 -7
  83. package/lib/index.js +2 -4
  84. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  88. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  92. package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
  93. package/lib/lambdas/post-deploy/prune-s3.js +41 -12
  94. package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
  95. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  96. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  103. package/lib/nextjs-api.d.ts +102 -18
  104. package/lib/nextjs-api.js +338 -38
  105. package/lib/nextjs-api.test.js +537 -1
  106. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  107. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  108. package/lib/nextjs-build/nextjs-build.js +684 -327
  109. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  110. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  111. package/lib/nextjs-build/patch-fetch.js +1 -1
  112. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  113. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  114. package/lib/nextjs-cache.d.ts +82 -4
  115. package/lib/nextjs-cache.js +186 -10
  116. package/lib/nextjs-cache.test.js +176 -1
  117. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  118. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  120. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  121. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  122. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  123. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  124. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  125. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  126. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  127. package/lib/nextjs-distribution.d.ts +194 -23
  128. package/lib/nextjs-distribution.js +535 -62
  129. package/lib/nextjs-distribution.test.d.ts +1 -0
  130. package/lib/nextjs-distribution.test.js +697 -0
  131. package/lib/nextjs-post-deploy.d.ts +13 -5
  132. package/lib/nextjs-post-deploy.js +13 -10
  133. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  134. package/lib/nextjs-post-deploy.test.js +34 -0
  135. package/lib/nextjs-static-assets.d.ts +17 -4
  136. package/lib/nextjs-static-assets.js +22 -5
  137. package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
  138. package/lib/root-constructs/nextjs-base-construct.js +139 -47
  139. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  140. package/lib/root-constructs/nextjs-global-containers.js +20 -71
  141. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  142. package/lib/root-constructs/nextjs-global-functions.js +52 -70
  143. package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
  144. package/lib/root-constructs/nextjs-regional-containers.js +8 -15
  145. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  146. package/lib/root-constructs/nextjs-regional-functions.js +8 -26
  147. package/lib/runtime/api-gateway-path.d.ts +34 -0
  148. package/lib/runtime/api-gateway-path.js +71 -0
  149. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  150. package/lib/runtime/api-gateway-path.test.js +65 -0
  151. package/lib/runtime/case-redirect.d.ts +22 -0
  152. package/lib/runtime/case-redirect.js +63 -0
  153. package/lib/runtime/case-redirect.test.d.ts +1 -0
  154. package/lib/runtime/case-redirect.test.js +32 -0
  155. package/lib/runtime/core.d.ts +234 -0
  156. package/lib/runtime/core.js +1216 -0
  157. package/lib/runtime/core.test.d.ts +1 -0
  158. package/lib/runtime/core.test.js +1686 -0
  159. package/lib/runtime/deployment-root.d.ts +13 -0
  160. package/lib/runtime/deployment-root.js +29 -0
  161. package/lib/runtime/dispatch.d.ts +331 -0
  162. package/lib/runtime/dispatch.js +751 -0
  163. package/lib/runtime/dispatch.test.d.ts +1 -0
  164. package/lib/runtime/dispatch.test.js +853 -0
  165. package/lib/runtime/entrypoints.d.ts +57 -0
  166. package/lib/runtime/entrypoints.js +115 -0
  167. package/lib/runtime/http/abort-signal.d.ts +6 -0
  168. package/lib/runtime/http/abort-signal.js +19 -0
  169. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  170. package/lib/runtime/http/abort-signal.test.js +49 -0
  171. package/lib/runtime/http/node-server.d.ts +38 -0
  172. package/lib/runtime/http/node-server.js +99 -0
  173. package/lib/runtime/http/node-server.test.d.ts +1 -0
  174. package/lib/runtime/http/node-server.test.js +96 -0
  175. package/lib/runtime/http/node-sink.d.ts +16 -0
  176. package/lib/runtime/http/node-sink.js +48 -0
  177. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  178. package/lib/runtime/http/node-sink.test.js +66 -0
  179. package/lib/runtime/http/request.d.ts +62 -0
  180. package/lib/runtime/http/request.js +134 -0
  181. package/lib/runtime/http/request.test.d.ts +1 -0
  182. package/lib/runtime/http/request.test.js +103 -0
  183. package/lib/runtime/http/response.d.ts +77 -0
  184. package/lib/runtime/http/response.js +229 -0
  185. package/lib/runtime/http/response.test.d.ts +1 -0
  186. package/lib/runtime/http/response.test.js +178 -0
  187. package/lib/runtime/http/sink.d.ts +73 -0
  188. package/lib/runtime/http/sink.js +188 -0
  189. package/lib/runtime/http/sink.test.d.ts +1 -0
  190. package/lib/runtime/http/sink.test.js +257 -0
  191. package/lib/runtime/image-utils.d.ts +78 -0
  192. package/lib/runtime/image-utils.js +129 -0
  193. package/lib/runtime/image-utils.test.d.ts +1 -0
  194. package/lib/runtime/image-utils.test.js +237 -0
  195. package/lib/runtime/image.d.ts +76 -0
  196. package/lib/runtime/image.js +296 -0
  197. package/lib/runtime/image.test.d.ts +1 -0
  198. package/lib/runtime/image.test.js +405 -0
  199. package/lib/runtime/lambda-event.d.ts +4 -0
  200. package/lib/runtime/lambda-event.js +113 -0
  201. package/lib/runtime/lambda-event.test.d.ts +1 -0
  202. package/lib/runtime/lambda-event.test.js +119 -0
  203. package/lib/runtime/lambda.mjs +41600 -0
  204. package/lib/runtime/load-module.d.ts +8 -0
  205. package/lib/runtime/load-module.js +35 -0
  206. package/lib/runtime/manifest.d.ts +215 -0
  207. package/lib/runtime/manifest.js +118 -0
  208. package/lib/runtime/middleware.d.ts +43 -0
  209. package/lib/runtime/middleware.js +113 -0
  210. package/lib/runtime/middleware.test.d.ts +1 -0
  211. package/lib/runtime/middleware.test.js +259 -0
  212. package/lib/runtime/next-modules.d.ts +71 -0
  213. package/lib/runtime/next-modules.js +144 -0
  214. package/lib/runtime/next-modules.test.d.ts +1 -0
  215. package/lib/runtime/next-modules.test.js +34 -0
  216. package/lib/runtime/public-files.d.ts +32 -0
  217. package/lib/runtime/public-files.js +117 -0
  218. package/lib/runtime/public-files.test.d.ts +1 -0
  219. package/lib/runtime/public-files.test.js +97 -0
  220. package/lib/runtime/server.mjs +41593 -0
  221. package/lib/runtime/static-files.d.ts +50 -0
  222. package/lib/runtime/static-files.js +266 -0
  223. package/lib/runtime/static-files.test.d.ts +1 -0
  224. package/lib/runtime/static-files.test.js +118 -0
  225. package/lib/runtime/util.d.ts +28 -0
  226. package/lib/runtime/util.js +79 -0
  227. package/lib/utils/base-path.d.ts +106 -13
  228. package/lib/utils/base-path.js +254 -41
  229. package/lib/utils/base-path.test.js +219 -51
  230. package/lib/utils/get-architecture.d.ts +7 -8
  231. package/lib/utils/get-architecture.js +12 -13
  232. package/lib/utils/zip-directory.d.ts +14 -0
  233. package/lib/utils/zip-directory.js +121 -0
  234. package/lib/utils/zip-directory.test.d.ts +1 -0
  235. package/lib/utils/zip-directory.test.js +99 -0
  236. package/package.json +22 -3
  237. package/scripts/capture-adapter-fixture.mjs +325 -0
  238. package/scripts/e2e-deploy.sh +398 -0
  239. package/scripts/e2e-harness/README.md +707 -0
  240. package/scripts/e2e-harness/app.js +370 -0
  241. package/scripts/e2e-harness/common.sh +249 -0
  242. package/scripts/e2e-harness/screen.mjs +302 -0
  243. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  244. package/scripts/e2e-harness/type-filters.mjs +47 -0
  245. package/scripts/e2e-logs.sh +75 -0
  246. package/scripts/e2e-offline.sh +91 -0
  247. package/scripts/e2e-sweep.sh +370 -0
  248. package/scripts/e2e-warm.sh +114 -0
  249. package/scripts/zero-config-build.mjs +418 -0
  250. package/docs/1k-concurrent-users-executions.png +0 -0
  251. package/docs/plans/adapter-runtime-release.md +0 -362
  252. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  253. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  254. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  255. package/lib/image-optimization/handler-utils.d.ts +0 -34
  256. package/lib/image-optimization/handler-utils.js +0 -83
  257. package/lib/image-optimization/handler-utils.test.js +0 -178
  258. package/lib/nextjs-build/functions.Dockerfile +0 -31
  259. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  260. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  261. package/lib/utils/experimental-flags.d.ts +0 -24
  262. package/lib/utils/experimental-flags.js +0 -30
  263. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -0,0 +1,1216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NextjsRuntime = void 0;
4
+ exports.withoutInternalHeaders = withoutInternalHeaders;
5
+ exports.revalidatedPageRoutes = revalidatedPageRoutes;
6
+ exports.loadRuntime = loadRuntime;
7
+ exports.splitBody = splitBody;
8
+ /* eslint-disable import/no-extraneous-dependencies */
9
+ /**
10
+ * The runtime core: one `handle(request, sink)` that both shells wrap.
11
+ *
12
+ * The Lambda shell (`lambda.mts`) and the container shell (`server.mts`) do
13
+ * nothing but turn their input into a {@link RuntimeRequest} and their output into
14
+ * a {@link ResponseSink}. Everything else — synthesizing `req`/`res`, dispatch,
15
+ * middleware, entrypoint invocation, static files, image optimization, gzip,
16
+ * `waitUntil` — happens here, so the container e2e suite exercises the same code
17
+ * Lambda runs. That is deliberate: the container path used to get real
18
+ * `node:http` objects from Lambda Web Adapter, which meant container tests proved
19
+ * nothing about Lambda.
20
+ */
21
+ const promises_1 = require("node:fs/promises");
22
+ const node_path_1 = require("node:path");
23
+ const node_stream_1 = require("node:stream");
24
+ const case_redirect_1 = require("./case-redirect");
25
+ const dispatch_1 = require("./dispatch");
26
+ const entrypoints_1 = require("./entrypoints");
27
+ const request_1 = require("./http/request");
28
+ const response_1 = require("./http/response");
29
+ const sink_1 = require("./http/sink");
30
+ const image_1 = require("./image");
31
+ const manifest_1 = require("./manifest");
32
+ const middleware_1 = require("./middleware");
33
+ const next_modules_1 = require("./next-modules");
34
+ const public_files_1 = require("./public-files");
35
+ const static_files_1 = require("./static-files");
36
+ const util_1 = require("./util");
37
+ class NextjsRuntime {
38
+ options;
39
+ entrypoints;
40
+ dispatcher;
41
+ middleware;
42
+ images;
43
+ /** The 500 ladder; see `statusTargets`. */
44
+ errorTargetFor;
45
+ /** The assets bucket, when `public/` files are served from it. */
46
+ publicBucket;
47
+ constructor(options) {
48
+ this.options = options;
49
+ const { manifest, deploymentRoot } = options;
50
+ this.entrypoints = new entrypoints_1.EntrypointRegistry(deploymentRoot, manifest);
51
+ // Listed once, at cold start; see `resolvePublicFiles`.
52
+ const publicFiles = (0, public_files_1.resolvePublicFiles)(deploymentRoot, manifest);
53
+ this.dispatcher = new dispatch_1.Dispatcher({
54
+ manifest,
55
+ publicFiles: publicFiles.files,
56
+ });
57
+ // On disk otherwise, with `.next/static`.
58
+ this.publicBucket = publicFiles.inS3 ? options.bucket : undefined;
59
+ this.errorTargetFor = (0, dispatch_1.statusTargets)(manifest, 500);
60
+ this.images = new image_1.RuntimeImageOptimizer({
61
+ deploymentRoot,
62
+ manifest,
63
+ bucket: this.publicBucket ?? "",
64
+ bucketKeyPrefix: options.bucketKeyPrefix ?? "",
65
+ fetchInternal: (href, req, maximumBody) => this.fetchInternal(href, req, maximumBody),
66
+ });
67
+ // The runner is shared — it memoizes the loaded middleware module — while the
68
+ // `invokeMiddleware` callback it produces is per request.
69
+ this.middleware = manifest.middleware
70
+ ? new middleware_1.MiddlewareRunner({
71
+ middleware: manifest.middleware,
72
+ root: deploymentRoot,
73
+ })
74
+ : undefined;
75
+ }
76
+ get manifest() {
77
+ return this.options.manifest;
78
+ }
79
+ async handle(request, sink) {
80
+ const { manifest } = this.options;
81
+ const pending = [];
82
+ const waitUntil = (promise) => {
83
+ pending.push(promise);
84
+ };
85
+ const body = splitBody(request.body, this.middleware !== undefined);
86
+ const req = new request_1.ShimIncomingMessage({
87
+ method: request.method,
88
+ url: request.url,
89
+ headers: withoutInternalHeaders(request.headers, request.url, manifest.config.basePath),
90
+ body: body.forRequest,
91
+ remoteAddress: request.remoteAddress,
92
+ encrypted: request.encrypted,
93
+ trustForwardedHost: request.trustForwardedHost,
94
+ });
95
+ const res = new response_1.ShimServerResponse();
96
+ // Next.js reads `res.req` in a few error paths.
97
+ res.req = req;
98
+ request.signal?.addEventListener("abort", () => res.destroy(), {
99
+ once: true,
100
+ });
101
+ // The rejection handler is attached here rather than at the `await` below.
102
+ // `route()` awaits real I/O, so a stream that breaks while it runs would
103
+ // leave this promise rejected with no handler attached for a full event-loop
104
+ // turn — and Node 24 defaults to `--unhandled-rejections=throw`, which on
105
+ // the container shell takes the whole task down and aborts every other
106
+ // in-flight request on it. A mid-stream EPIPE from one client disconnect is
107
+ // not grounds for that.
108
+ //
109
+ // The error is logged, not rethrown: the stream broke after (or while) the
110
+ // head went out — a client disconnect, or `sendError` destroying a
111
+ // half-written response — and neither is an invocation failure. Rethrowing
112
+ // would make Lambda retry a request the client already abandoned.
113
+ const finished = (0, sink_1.pipeToSink)(req, res, sink, {
114
+ compress: manifest.config.compress,
115
+ }).catch((error) => {
116
+ console.error("The response stream did not complete:", error);
117
+ });
118
+ // For the error page's locale; unset when the throw is `absoluteUrl`'s.
119
+ let url;
120
+ try {
121
+ // Before anything parses the target, including `absoluteUrl` - `new URL`
122
+ // reads a leading `//` as protocol-relative and would take the first path
123
+ // segment for the host.
124
+ const collapsed = collapseRepeatedSlashes(request.url);
125
+ if (collapsed !== undefined) {
126
+ sendRedirect(res, collapsed, 308);
127
+ }
128
+ else {
129
+ // Inside the try: `absoluteUrl` builds a `URL` out of the request line
130
+ // and the forwarded headers, and a throw here has to reach the error
131
+ // ladder like any other. Outside it, on the Lambda shells — whose
132
+ // handlers wrap nothing — the same throw is an invocation error and a
133
+ // 502.
134
+ url = absoluteUrl(request);
135
+ await this.route(req, res, url, body, waitUntil, request);
136
+ }
137
+ }
138
+ catch (error) {
139
+ await this.sendError(req, res, waitUntil, error, url);
140
+ }
141
+ await finished;
142
+ // Lambda freezes the execution environment the moment the handler resolves —
143
+ // there is no post-response keepalive — so background work registered with
144
+ // `waitUntil` (notably ISR revalidation) has to be awaited here. After the
145
+ // response stream has closed, so client latency is unaffected; billed
146
+ // duration extends, which is the correct trade against a revalidation that
147
+ // never completes.
148
+ //
149
+ // Drained until nothing new arrives, not awaited once: `waitUntil` keeps
150
+ // being called after the response — Next's `AfterContext` registers its
151
+ // callback queue on the first `after()`, and an `after(promise)` made from
152
+ // inside a running callback, or a background regeneration that itself calls
153
+ // `after()`, registers more. A single `allSettled` snapshots the array and
154
+ // lets Lambda freeze on that late work.
155
+ let settledCount = 0;
156
+ while (settledCount < pending.length) {
157
+ const batch = pending.slice(settledCount);
158
+ settledCount = pending.length;
159
+ const settled = await Promise.allSettled(batch);
160
+ for (const result of settled) {
161
+ if (result.status === "rejected") {
162
+ console.error("A waitUntil() promise rejected:", result.reason);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ async route(req, res, url, body, waitUntil, request) {
168
+ const result = await this.dispatcher.dispatch({
169
+ method: req.method ?? "GET",
170
+ url,
171
+ headers: new Headers(toWebHeaders(req.headers)),
172
+ body: body.forDispatch,
173
+ invokeMiddleware: this.middleware?.invokerFor({
174
+ waitUntil,
175
+ signal: request.signal,
176
+ }),
177
+ });
178
+ body.releaseUnread(result.kind === "middleware-responded");
179
+ applyHeaders(res, result.responseHeaders);
180
+ if (result.status !== undefined) {
181
+ res.statusCode = result.status;
182
+ }
183
+ switch (result.kind) {
184
+ case "entrypoint": {
185
+ let handler;
186
+ try {
187
+ handler = await this.entrypoints.load(result.entrypoint);
188
+ }
189
+ catch (error) {
190
+ if (!(error instanceof entrypoints_1.RouteInOtherGroupError))
191
+ throw error;
192
+ // A URL the edge sent here only because of its case goes to its
193
+ // canonical spelling, which the edge routes to the owning group.
194
+ const canonical = (0, case_redirect_1.caseCanonicalPath)(url.pathname, result.resolvedPathname, this.options.manifest);
195
+ if (canonical) {
196
+ sendRedirect(res, `${canonical}${url.search}`, 308);
197
+ return;
198
+ }
199
+ if (request.onRouteInOtherGroup) {
200
+ // Explained by the caller of `handleInternally`, which knows why it
201
+ // happened.
202
+ request.onRouteInOtherGroup(error);
203
+ }
204
+ else {
205
+ // Logged, because it is also what a misrouted group looks like; see
206
+ // `RouteInOtherGroupError` for why it is a 404.
207
+ console.warn(error.message);
208
+ }
209
+ await this.sendUnmatched(req, res, waitUntil, { pathname: url.pathname, requestHeaders: result.requestHeaders }, url);
210
+ return;
211
+ }
212
+ // The invocation target, not the requested URL: `resolveRoutes` has
213
+ // applied rewrites, stripped i18n prefixes, and appended the `nxtP`
214
+ // route params as query values. That is exactly the contract Next.js
215
+ // documents for a proxy in front of a function — `RouteModule.prepare`
216
+ // recovers `params` from these query values — so that contract, not
217
+ // `requestMeta.params`, is how params get passed. The one exception is
218
+ // a capture the contract would corrupt; see `outOfBandRouteParams`.
219
+ const outOfBand = (0, dispatch_1.outOfBandRouteParams)(result.invocationTarget.query, result.resolvedPathname);
220
+ const invocationQuery = outOfBand?.query ?? result.invocationTarget.query;
221
+ const { pathname } = result.invocationTarget;
222
+ const search = (0, util_1.toSearch)(invocationQuery);
223
+ req.url = search ? `${pathname}?${search}` : pathname;
224
+ // Middleware may have rewritten request headers via
225
+ // `NextResponse.next({ request: { headers } })`.
226
+ req.headers = (0, request_1.toIncomingHttpHeaders)(result.requestHeaders);
227
+ await handler(req, (0, response_1.asServerResponse)(res), {
228
+ waitUntil,
229
+ requestMeta: {
230
+ // The resolved query, stated rather than left to be re-derived.
231
+ //
232
+ // `RouteModule.prepare` runs `handleRewrites` against `req.url`
233
+ // unconditionally, and `req.url` is the *already rewritten* target.
234
+ // A `beforeFiles` rewrite whose condition still holds after it has
235
+ // been applied therefore gets applied twice: in
236
+ // `test/e2e/link-with-api-rewrite` the rule
237
+ // `/:path(.*)` + `has: query json=true` -> `/api/json?from=/:path`
238
+ // matched `/api/json?json=true&from=/some/route/for` a second time
239
+ // and overwrote `from` with `/api/json`. `next start` escapes it
240
+ // because its router leaves `req.url` as the URL the client sent, so
241
+ // the one pass `prepare` makes is the only one.
242
+ //
243
+ // `prepare` prefers this meta over its own `parsedUrl.query`
244
+ // ("when deployed proxies will add query values from resolving the
245
+ // routes to pass to function"), which is the documented division of
246
+ // labour for a proxy in front of a function - and it is the same
247
+ // division the `req.url` above relies on. Setting it does not stop
248
+ // the second rewrite pass, it just stops that pass from being what
249
+ // the route sees.
250
+ query: { ...invocationQuery },
251
+ // Set only for a capture the query contract cannot carry, and then
252
+ // in place of it rather than alongside.
253
+ ...(outOfBand ? { params: outOfBand.params } : {}),
254
+ // Without this, `RouteModule.prepare` falls back to
255
+ // `http://localhost${req.url}` and every absolute URL a route
256
+ // handler builds is wrong. `relativeProjectDir` is deliberately
257
+ // *not* passed: the runtime `chdir`s to the project dir, so the
258
+ // value Next.js inlined at build time ("") is already correct, and
259
+ // `app-page-runtime.js` ignores the requestMeta override anyway.
260
+ initURL: url.href,
261
+ // Feeds `routerServerContext.hostname` (`route-module.js`
262
+ // `getRouterServerContext`). Includes the port, because it is
263
+ // concatenated into absolute URLs.
264
+ hostname: url.host,
265
+ // Both routers call this for a `notFound: true` / `notFound()` that
266
+ // the entrypoint itself cannot render, and fall back to
267
+ // `res.end('This page could not be found')` — no status, no app 404
268
+ // page — when it is absent. The `req`/`res` they pass are the ones
269
+ // handed in just above, so the captured pair is used instead of
270
+ // re-deriving them.
271
+ render404: async () => {
272
+ await this.sendNotFound(req, res, waitUntil, this.dispatcher.notFoundFor(url));
273
+ },
274
+ // `res.revalidate()` from a Pages API route. Without it, Next.js
275
+ // falls back to `fetch('https://' + req.headers.host + urlPath)` —
276
+ // and only when `experimental.trustHostHeader` is set, which it is
277
+ // not, so `res.revalidate()` threw
278
+ //
279
+ // Failed to revalidate /: Invariant: missing internal
280
+ // router-server-methods this is an internal bug
281
+ //
282
+ // and `test/e2e/revalidate-reason` saw `stale` where `next start`
283
+ // reports `on-demand`: the route still re-rendered, just as an
284
+ // ordinary stale regeneration rather than the on-demand one it
285
+ // asked for.
286
+ //
287
+ // Answering it in process rather than by setting
288
+ // `trustHostHeader`: the fetch path would leave the function, cross
289
+ // CloudFront and come back — a second billed invocation, a
290
+ // dependency on `x-prerender-revalidate` surviving the edge, and a
291
+ // reason to trust a client-supplied `Host`. Next.js's own
292
+ // non-serverless answer is the same shape as this one
293
+ // (`NextServer#revalidate` runs its request handler against a
294
+ // mocked `req`/`res`).
295
+ revalidate: (config) => this.revalidate(config, request),
296
+ },
297
+ });
298
+ // A Pages API route owns the end of its response: `stream.pipe(res)`,
299
+ // an `externalResolver` proxy, or a callback that calls `res.json()`
300
+ // later all return from the handler before they are done writing, and
301
+ // ending here sent an empty 200 and made their writes throw
302
+ // `ERR_STREAM_WRITE_AFTER_END`. `next start`'s `apiResolver` leaves it
303
+ // open too — one that never ends stalls, there as here. `handle` awaits
304
+ // the response itself, so nothing is cut short by returning.
305
+ if (!res.writableEnded && result.entrypoint.type !== "page-api") {
306
+ res.end();
307
+ }
308
+ return;
309
+ }
310
+ case "static-file": {
311
+ const statusPage = result.source === "server"
312
+ ? this.statusPageStatus(result.pathname)
313
+ : undefined;
314
+ // `next start` serves a `public/` or `_next/static` file to GET and
315
+ // HEAD only, and `send` would serve it to any method. The same goes for
316
+ // an auto-exported Pages Router page (`base-server.js`
317
+ // `renderToResponseWithComponentsImpl`: a string `Component` answers
318
+ // anything else with a 405), except the 404 and 500 pages.
319
+ if (req.method !== "GET" &&
320
+ req.method !== "HEAD" &&
321
+ (result.source !== "server" ||
322
+ (statusPage === undefined && result.filePath.endsWith(".html")))) {
323
+ sendMethodNotAllowed(res);
324
+ return;
325
+ }
326
+ // "ensure correct status is set when visiting a status page directly":
327
+ // `next start` answers `/404` with a 404 and `/500` with a 500, not the
328
+ // 200 their prerendered HTML would otherwise go out with.
329
+ if (statusPage !== undefined) {
330
+ res.statusCode = statusPage;
331
+ }
332
+ const etag = this.options.manifest.config.generateEtags;
333
+ const publicDir = `${(0, public_files_1.publicDirKey)(this.options.manifest)}/`;
334
+ const served = (await (0, static_files_1.serveStaticFile)(req, res, this.options.deploymentRoot, result.filePath, { etag })) ||
335
+ // Listed but not staged: a Lambda root, whose `public/` is in S3.
336
+ (result.source === "public" &&
337
+ !!this.publicBucket &&
338
+ (await (0, static_files_1.serveS3PublicFile)(req, res, {
339
+ bucket: this.publicBucket,
340
+ keyPrefix: this.options.bucketKeyPrefix ?? "",
341
+ file: result.filePath.slice(publicDir.length),
342
+ etag,
343
+ })));
344
+ if (!served) {
345
+ // The routing rule that matched a build asset already set its
346
+ // year-long `immutable` Cache-Control, which `sendUnmatched`
347
+ // replaces: under it the 404 would be cached at the edge and in
348
+ // browsers for that long, and a chunk that shows up on the next
349
+ // deploy would stay missing.
350
+ await this.sendUnmatched(req, res, waitUntil, result, url);
351
+ }
352
+ return;
353
+ }
354
+ case "image-optimization":
355
+ if (!this.images.isEnabled()) {
356
+ await this.sendUnmatched(req, res, waitUntil, { pathname: url.pathname, requestHeaders: result.requestHeaders }, url);
357
+ return;
358
+ }
359
+ req.headers = (0, request_1.toIncomingHttpHeaders)(result.requestHeaders);
360
+ await this.images.handle(req, res, result.url, waitUntil);
361
+ return;
362
+ case "redirect":
363
+ sendRedirect(res, result.location, result.status);
364
+ return;
365
+ case "external-rewrite":
366
+ await proxyExternal(req, res, result.url, result.requestHeaders);
367
+ return;
368
+ case "middleware-responded":
369
+ await sendWebResponse(res, result.response);
370
+ return;
371
+ case "response":
372
+ res.end();
373
+ return;
374
+ case "not-found":
375
+ await this.sendUnmatched(req, res, waitUntil, result, url);
376
+ return;
377
+ }
378
+ }
379
+ /**
380
+ * 404 or 500 when `pathname` is the prerendered `/404` or `/500` page — under
381
+ * `basePath` and, in an i18n app, any locale (`/fr/404`) — and `undefined`
382
+ * otherwise. `next start` matches the page, not the URL, so the locale does
383
+ * not matter.
384
+ */
385
+ statusPageStatus(pathname) {
386
+ const { basePath, i18n } = this.options.manifest.config;
387
+ let page = (0, util_1.withoutPathPrefix)(pathname, basePath);
388
+ const locales = i18n?.locales;
389
+ for (const locale of locales ?? []) {
390
+ const stripped = (0, util_1.withoutPathPrefix)(page, `/${locale}`);
391
+ if (stripped !== page) {
392
+ page = stripped;
393
+ break;
394
+ }
395
+ }
396
+ if (page === "/404")
397
+ return 404;
398
+ if (page === "/500")
399
+ return 500;
400
+ return undefined;
401
+ }
402
+ /**
403
+ * `next start`'s answer to a path nothing serves (`router-server.js`, the
404
+ * "404 case"), for both ways of getting here: dispatch matched nothing, or it
405
+ * matched a build asset that is not in the package.
406
+ *
407
+ * No-store, always. A prerendered `/_not-found` would otherwise send its
408
+ * cache entry's year-long `s-maxage`, and the CDN would keep the 404 past the
409
+ * deploy that adds the route. Set rather than forced: Next's page handlers
410
+ * only write a `Cache-Control` when none is set (`sendRenderResult`,
411
+ * `pages-handler.js`), which is exactly how `next start`'s own no-store here
412
+ * survives the render. `render404` is not this path: a `notFound()` from an
413
+ * ISR page is cacheable for that page's revalidate period.
414
+ *
415
+ * A missing `_next/static` file, and a GET or HEAD whose `Sec-Fetch-Dest`
416
+ * says it cannot display HTML (an `<img>`, a script, a font), get a
417
+ * plain-text `Not Found` instead of the rendered page — nothing would show
418
+ * it, and rendering it is the expensive part.
419
+ *
420
+ * Everything else renders the app's 404 as the path that was asked for, not
421
+ * as `/_not-found`: the App Router serializes the canonical URL into the RSC
422
+ * payload, so a client hydrated off a `/_not-found` payload reports the wrong
423
+ * `usePathname()` and pushes the wrong history entry. It renders with the
424
+ * request headers middleware set, too — a CSP nonce, say.
425
+ */
426
+ async sendUnmatched(req, res, waitUntil, result, url) {
427
+ res.setHeader("Cache-Control", NO_STORE);
428
+ const { basePath, assetPrefix } = this.options.manifest.config;
429
+ const pathname = (0, util_1.withoutPathPrefix)((0, util_1.withoutPathPrefix)(result.pathname, basePath), assetPrefix);
430
+ if (pathname.startsWith("/_next/static/") ||
431
+ ((req.method === "GET" || req.method === "HEAD") &&
432
+ NON_HTML_SEC_FETCH_DESTS.has((0, util_1.firstValue)(req.headers["sec-fetch-dest"]) ?? ""))) {
433
+ res.statusCode = 404;
434
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
435
+ res.end("Not Found");
436
+ return;
437
+ }
438
+ req.headers = (0, request_1.toIncomingHttpHeaders)(result.requestHeaders);
439
+ await this.sendNotFound(req, res, waitUntil, this.dispatcher.notFoundFor(url), `${result.pathname}${url.search}`);
440
+ }
441
+ /**
442
+ * One on-demand revalidation, run against this runtime rather than over the
443
+ * network. Wired in as `requestMeta.revalidate`; see the comment there.
444
+ *
445
+ * The response is thrown away — only its status matters — but it goes through
446
+ * the full {@link handle}, so the entrypoint sees a request with
447
+ * `x-prerender-revalidate` on it and writes the fresh entry through the cache
448
+ * handler exactly as a request from outside would. `handle` awaits its own
449
+ * `waitUntil` work, so the new entry is committed before `res.revalidate()`
450
+ * resolves, which is what callers that revalidate and then redirect depend on.
451
+ *
452
+ * The accept/throw rule is `NextServer#revalidate`'s, verbatim: a revalidation
453
+ * is successful if it was cached or answered 200, and `notFound: true`
454
+ * legitimately answers 404 for an `unstable_onlyGenerated` caller. Anything
455
+ * else throws, and `res.revalidate()` turns it into `Failed to revalidate
456
+ * <path>: <message>`.
457
+ */
458
+ async revalidate(config, origin) {
459
+ const { head, otherGroup } = await this.handleInternally({
460
+ method: "GET",
461
+ url: config.urlPath,
462
+ // The caller's authority, not the revalidated path's: it is what
463
+ // `absoluteUrl` builds the request URL from, and a revalidation is for
464
+ // the origin being served. The forwarded pair with it — behind
465
+ // CloudFront `host` is the Function URL, and a render that built its
466
+ // absolute URLs from that would cache links to the raw function.
467
+ headers: {
468
+ ...config.headers,
469
+ host: origin.headers.host,
470
+ ...pickDefined(origin.headers, [
471
+ "x-forwarded-host",
472
+ "x-forwarded-proto",
473
+ ]),
474
+ },
475
+ encrypted: origin.encrypted,
476
+ trustForwardedHost: origin.trustForwardedHost,
477
+ }, {});
478
+ const status = head?.statusCode ?? 500;
479
+ if (otherGroup) {
480
+ const self = process.env[manifest_1.FUNCTION_GROUP_ENV_VAR];
481
+ // A page packaged into another `functionGroups` group: it is rendered in
482
+ // process, and this function does not have the page's code. Checked
483
+ // first because it renders as a 404, which `unstable_onlyGenerated`
484
+ // would otherwise accept.
485
+ throw new Error(`Invalid response ${status}: "${config.urlPath}" belongs to ` +
486
+ `\`functionGroups\` group "${otherGroup.owner}", and ` +
487
+ `res.revalidate() can only revalidate pages in the group it runs ` +
488
+ `in ("${self}"). Call it from an API route in group ` +
489
+ `"${otherGroup.owner}", or use revalidatePath()/revalidateTag(), ` +
490
+ `which work from any group.`);
491
+ }
492
+ if (head?.headers["x-nextjs-cache"] !== "REVALIDATED" &&
493
+ status !== 200 &&
494
+ !(status === 404 && config.opts.unstable_onlyGenerated)) {
495
+ throw new Error(`Invalid response ${status}`);
496
+ }
497
+ await invalidateRevalidatedPage(config.urlPath, this.options.manifest);
498
+ }
499
+ /**
500
+ * An image optimization source that is not a file: `<Image src="/api/avatar">`
501
+ * served by a route handler. Wired in as the optimizer's `fetchInternal`, and
502
+ * run in process for the reasons {@link revalidate} is — `next start` fetches
503
+ * the source from itself over loopback, which here would be a second billed
504
+ * invocation through CloudFront.
505
+ *
506
+ * Only the authority is forwarded, as `next start`'s `fetchInternalImage`
507
+ * forwards none of the viewer's headers: the source is cached and served to
508
+ * everyone, so it must not depend on one viewer's cookies.
509
+ */
510
+ async fetchInternal(href, req, maximumBody) {
511
+ const request = {
512
+ method: "GET",
513
+ url: href,
514
+ headers: pickDefined(req.headers, [
515
+ "host",
516
+ "x-forwarded-host",
517
+ "x-forwarded-proto",
518
+ ]),
519
+ encrypted: req.socket?.encrypted,
520
+ trustForwardedHost: req.trustForwardedHost,
521
+ };
522
+ const { head, body, otherGroup, tooLarge } = await this.handleInternally(request, { maximumBody });
523
+ if (tooLarge) {
524
+ return { statusCode: 0, headers: {}, body: Buffer.alloc(0), tooLarge };
525
+ }
526
+ if (otherGroup) {
527
+ // The edge sends every `/_next/image` request to the default group, and
528
+ // the source is rendered in process, so a route packaged into another
529
+ // group is out of reach: the optimizer answers (and logs) a 502.
530
+ return {
531
+ statusCode: 0,
532
+ headers: {},
533
+ body: Buffer.alloc(0),
534
+ otherGroup: otherGroup.owner,
535
+ };
536
+ }
537
+ return {
538
+ statusCode: head?.statusCode ?? 0,
539
+ headers: head?.headers ?? {},
540
+ body,
541
+ };
542
+ }
543
+ /**
544
+ * One request through {@link handle}, answered to this runtime instead of a
545
+ * client: the head, the body when it is wanted, and the error when the route
546
+ * is packaged into another `functionGroups` group. `handle` awaits the
547
+ * request's `waitUntil` work too, so whatever the render wrote is committed by
548
+ * the time this resolves.
549
+ *
550
+ * The body is kept only when `maximumBody` is set. One past it fails the
551
+ * response stream, which stops the route writing, and comes back as
552
+ * `tooLarge` rather than held in memory.
553
+ */
554
+ async handleInternally(request, options) {
555
+ let head;
556
+ const chunks = [];
557
+ let size = 0;
558
+ let tooLarge = false;
559
+ let otherGroup;
560
+ const onRouteInOtherGroup = (error) => {
561
+ otherGroup = error;
562
+ };
563
+ await this.handle({ ...request, onRouteInOtherGroup }, {
564
+ begin(responseHead) {
565
+ head = responseHead;
566
+ return new node_stream_1.Writable({
567
+ write(chunk, _encoding, callback) {
568
+ if (options.maximumBody === undefined)
569
+ return callback();
570
+ size += chunk.byteLength;
571
+ if (size > options.maximumBody) {
572
+ tooLarge = true;
573
+ return callback(new Error("Over images.maximumResponseBody"));
574
+ }
575
+ chunks.push(Buffer.from(chunk));
576
+ callback();
577
+ },
578
+ });
579
+ },
580
+ });
581
+ return {
582
+ head,
583
+ body: tooLarge ? Buffer.alloc(0) : Buffer.concat(chunks),
584
+ otherGroup,
585
+ tooLarge,
586
+ };
587
+ }
588
+ /**
589
+ * App Router builds an invocable `/_not-found`, Pages Router a prerendered
590
+ * `404.html` (per locale under i18n) or else `/_error`; see `statusTargets`.
591
+ */
592
+ async sendNotFound(req, res, waitUntil, target,
593
+ /**
594
+ * What to render the 404 as. Omitted by `render404`, which is called
595
+ * mid-render with `req.url` already pointing at the route that gave up —
596
+ * the path Next.js would render that 404 for.
597
+ */
598
+ requestedUrl) {
599
+ res.statusCode = 404;
600
+ if (target.kind === "entrypoint") {
601
+ const handler = await this.entrypoints.load(target.entrypoint);
602
+ req.url = requestedUrl ?? req.url;
603
+ await handler(req, (0, response_1.asServerResponse)(res), { waitUntil });
604
+ if (!res.writableEnded) {
605
+ res.end();
606
+ }
607
+ return;
608
+ }
609
+ if (target.kind === "static-file" &&
610
+ (await this.sendHtmlFile(res, target))) {
611
+ return;
612
+ }
613
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
614
+ res.end("This page could not be found.");
615
+ }
616
+ /**
617
+ * Turn a thrown error into a response, rendering the app's error page when it
618
+ * has one.
619
+ *
620
+ * Next.js's own page handlers catch, report and then *rethrow* ("rethrow so
621
+ * that we can handle serving error page", `pages-handler.ts`), which makes the
622
+ * error page the host's job — the same division of labor as `render404`. Without
623
+ * this ladder every throw answered a bare `text/plain` 500 and a custom
624
+ * `pages/_error` was dead code (`test/e2e/async-modules`, whose `/make-error`
625
+ * throws in `getServerSideProps`).
626
+ *
627
+ * Once the head is out there is nothing to say — destroying the stream is what
628
+ * tells the client the response is truncated rather than complete.
629
+ */
630
+ async sendError(req, res, waitUntil, error,
631
+ /** The request, as received: which locale's prerendered 500 to send. */
632
+ url) {
633
+ console.error("Unhandled error while handling the request:", error);
634
+ if (res.headersSent) {
635
+ res.destroy(asError(error));
636
+ return;
637
+ }
638
+ res.statusCode = 500;
639
+ // A failed render may have set headers describing a body that never
640
+ // arrived. Every rung below sends a different body, so they go first: a
641
+ // stale `Content-Length` on a 500.html of another size hangs the client or
642
+ // desyncs a keep-alive connection.
643
+ res.removeHeader("Content-Length");
644
+ res.removeHeader("ETag");
645
+ // Every rung, the error-page entrypoint included: otherwise the throwing
646
+ // render's `s-maxage` (or a `headers()` rule's) rides along and CloudFront
647
+ // caches the 500. `next start` sets it before rendering the error page too.
648
+ res.setHeader("Cache-Control", NO_STORE);
649
+ const target = this.errorTargetFor(url);
650
+ if (target.kind === "entrypoint") {
651
+ try {
652
+ const handler = await this.entrypoints.load(target.entrypoint);
653
+ // `req.url` is left alone: the error page renders for the URL that was
654
+ // asked for, and `_error`'s `getInitialProps` reads the status off `res`,
655
+ // which is why the 500 above is set first.
656
+ await handler(req, (0, response_1.asServerResponse)(res), { waitUntil });
657
+ if (!res.writableEnded) {
658
+ res.end();
659
+ }
660
+ return;
661
+ }
662
+ catch (errorPageError) {
663
+ console.error("The error page itself failed to render:", errorPageError);
664
+ if (res.headersSent) {
665
+ res.destroy(asError(errorPageError));
666
+ return;
667
+ }
668
+ }
669
+ }
670
+ if (target.kind === "static-file" &&
671
+ (await this.sendHtmlFile(res, target))) {
672
+ return;
673
+ }
674
+ // Again: an error page that threw may have described its own body too.
675
+ res.removeHeader("Content-Length");
676
+ res.removeHeader("ETag");
677
+ res.statusCode = 500;
678
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
679
+ res.setHeader("Cache-Control", NO_STORE);
680
+ res.end("Internal Server Error");
681
+ }
682
+ /**
683
+ * A prerendered 404 or 500 page, or `false` when it cannot be read and the
684
+ * caller's plain-text fallback should answer. Read rather than `serveStatic`,
685
+ * which keeps the status already set but would answer a `Range` request with
686
+ * a 206 of the error page, and add `ETag`, `Last-Modified` and, where none is
687
+ * set yet, a public `Cache-Control` to it.
688
+ */
689
+ async sendHtmlFile(res, target) {
690
+ let html;
691
+ try {
692
+ html = await (0, promises_1.readFile)((0, node_path_1.join)(this.options.deploymentRoot, target.filePath));
693
+ }
694
+ catch {
695
+ return false;
696
+ }
697
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
698
+ res.end(html);
699
+ return true;
700
+ }
701
+ }
702
+ exports.NextjsRuntime = NextjsRuntime;
703
+ /**
704
+ * What next sends with an error it rendered itself. Without it a `Cache-Control`
705
+ * left behind by the render that threw can get a 500 cached at the edge.
706
+ */
707
+ const NO_STORE = "private, no-cache, no-store, max-age=0, must-revalidate";
708
+ /**
709
+ * `Sec-Fetch-Dest` values that can never display an HTML response, from
710
+ * `next/dist/server/lib/is-non-html-sec-fetch-dest.js`. Restated rather than
711
+ * required, because that module is recent and the app's `next` may predate it:
712
+ * a failed require here would turn every 404 into a 500. Excludes `document`,
713
+ * `iframe` and the like, and `empty` — `fetch()`, which is how RSC requests go.
714
+ */
715
+ const NON_HTML_SEC_FETCH_DESTS = new Set([
716
+ "audio",
717
+ "audioworklet",
718
+ "font",
719
+ "image",
720
+ "json",
721
+ "manifest",
722
+ "paintworklet",
723
+ "report",
724
+ "script",
725
+ "serviceworker",
726
+ "sharedworker",
727
+ "style",
728
+ "track",
729
+ "video",
730
+ "webidentity",
731
+ "worker",
732
+ "xslt",
733
+ ]);
734
+ /**
735
+ * `INTERNAL_HEADERS` from `next/dist/server/lib/server-ipc/utils.js` (Next
736
+ * 16.3), which `next start` deletes from every request before routing it
737
+ * (`filterInternalHeaders` in `router-server.js`). They are signals between
738
+ * Next's own router and render layers; honoring one a client sent lets it steer
739
+ * those layers — `next-resume` makes a PPR page resume from a postponed state
740
+ * the client supplies. Restated rather than required, like
741
+ * {@link NON_HTML_SEC_FETCH_DESTS}.
742
+ */
743
+ const INTERNAL_HEADERS = new Set([
744
+ "x-middleware-rewrite",
745
+ "x-middleware-redirect",
746
+ "x-middleware-set-cookie",
747
+ "x-middleware-skip",
748
+ "x-middleware-override-headers",
749
+ "x-middleware-next",
750
+ "x-now-route-matches",
751
+ "x-matched-path",
752
+ "x-nextjs-data",
753
+ "x-next-resume-state-length",
754
+ "next-resume",
755
+ ]);
756
+ /**
757
+ * The request headers with {@link INTERNAL_HEADERS} removed, and `x-nextjs-data`
758
+ * put back for a `_next/data` request, which is what `next start`'s
759
+ * `resolveRoutes` does (`setIsNextDataRequest`) right after stripping it: the
760
+ * header is internal, but Next's handlers and middleware still read it — it is
761
+ * how a data request gets `x-nextjs-matched-path` — so a real data request has
762
+ * to keep it.
763
+ */
764
+ function withoutInternalHeaders(headers, target, basePath) {
765
+ const filtered = {};
766
+ for (const [name, value] of Object.entries(headers)) {
767
+ if (!INTERNAL_HEADERS.has(name)) {
768
+ filtered[name] = value;
769
+ }
770
+ }
771
+ const pathname = (0, util_1.withoutPathPrefix)(target.split("?")[0], basePath);
772
+ if (pathname.startsWith("/_next/data/") && pathname.endsWith(".json")) {
773
+ filtered["x-nextjs-data"] = "1";
774
+ }
775
+ return filtered;
776
+ }
777
+ /**
778
+ * Invalidate the CDN copies of a page `res.revalidate()` just regenerated: its
779
+ * HTML and RSC payload, and its Pages Router `_next/data` JSON. Without this the
780
+ * fresh entry sat behind CloudFront's copy of the old one for the page's whole
781
+ * `s-maxage` — a year, for an on-demand-only ISR page. `revalidatePath` and
782
+ * `revalidateTag` go through the cache handler's `revalidateTag`, which already
783
+ * invalidates; `res.revalidate()` does not touch it.
784
+ *
785
+ * Every route is without `basePath`, which the hook prefixes. A no-op outside
786
+ * the Global constructs, where no hook is registered.
787
+ */
788
+ async function invalidateRevalidatedPage(urlPath, manifest) {
789
+ const hook = globalThis[manifest_1.REVALIDATED_PAGE_HOOK];
790
+ if (typeof hook !== "function") {
791
+ return;
792
+ }
793
+ const route = (0, util_1.withoutPathPrefix)(urlPath.split("?")[0], manifest.config.basePath);
794
+ try {
795
+ // One call, deduplicated: the default locale's two pairs share a data
796
+ // route, and each invalidation path counts against CloudFront's quota.
797
+ await hook([...new Set(revalidatedPageRoutes(route, manifest).flat())]);
798
+ }
799
+ catch (error) {
800
+ // The regeneration itself succeeded; the edge catches up at `s-maxage`.
801
+ console.warn(`Could not invalidate the CDN copy of ${urlPath}:`, error);
802
+ }
803
+ }
804
+ /**
805
+ * The `[route, dataRoute]` pairs a revalidated page is cached under at the edge.
806
+ *
807
+ * In an i18n app the Next client always puts the locale in a data href, the
808
+ * default locale included (`/_next/data/<id>/en/blog.json`, and `…/en.json` for
809
+ * the root), so the unprefixed data route names nothing CloudFront holds. The
810
+ * page is one locale's — `res.revalidate("/blog")` regenerates the default
811
+ * locale's, `"/fr/blog"` French — and the default locale's HTML is reachable,
812
+ * and cached, both with and without its prefix, so its two pairs share a data
813
+ * route, which the caller sends once.
814
+ */
815
+ function revalidatedPageRoutes(route, manifest) {
816
+ const dataRoute = (page) => `/_next/data/${manifest.buildId}${page === "/" ? "/index" : page.replace(/\/+$/, "")}.json`;
817
+ const i18n = manifest.config.i18n;
818
+ if (!i18n?.defaultLocale) {
819
+ return [[route, dataRoute(route)]];
820
+ }
821
+ const { defaultLocale } = i18n;
822
+ const segment = route.split("/")[1] ?? "";
823
+ const locale = (i18n.locales ?? []).includes(segment)
824
+ ? segment
825
+ : defaultLocale;
826
+ const page = locale === segment ? (0, util_1.withoutPathPrefix)(route, `/${segment}`) : route;
827
+ const localized = page === "/" ? `/${locale}` : `/${locale}${page}`;
828
+ // The root's data route is the locale itself, not `/<locale>/index`.
829
+ const localizedData = `/_next/data/${manifest.buildId}${localized.replace(/\/+$/, "")}.json`;
830
+ return locale === defaultLocale
831
+ ? [
832
+ [page, localizedData],
833
+ [localized, localizedData],
834
+ ]
835
+ : [[localized, localizedData]];
836
+ }
837
+ function asError(error) {
838
+ return error instanceof Error ? error : new Error(String(error));
839
+ }
840
+ /**
841
+ * Read the manifest and pin the layout it describes.
842
+ *
843
+ * `process.cwd()` is load-bearing and there is exactly one chance to get it
844
+ * right: Next.js inlines `relative(buildCwd, projectDir)` into every entrypoint
845
+ * and resolves it against the *runtime* cwd to find
846
+ * `required-server-files.json`, the prerender manifest, and the app's chunks.
847
+ * `assertBuildCwd` in `build-outputs.ts` keeps that inlined value `""`, so the
848
+ * whole invariant reduces to "cwd is the staged project dir" — asserted rather
849
+ * than assumed, because getting it wrong produces a
850
+ * `Cannot find module …/required-server-files.json` from inside compiled Next.js
851
+ * code with no indication that the layout is the problem.
852
+ */
853
+ async function loadRuntime(deploymentRoot) {
854
+ const manifestPath = (0, manifest_1.deployedManifestPath)(deploymentRoot);
855
+ let manifest;
856
+ try {
857
+ manifest = JSON.parse(await (0, promises_1.readFile)(manifestPath, "utf-8"));
858
+ }
859
+ catch (error) {
860
+ throw new Error(`Could not read the cdk-nextjs adapter manifest at "${manifestPath}". ` +
861
+ `The deployment package is incomplete: synth copies ` +
862
+ `${manifest_1.MANIFEST_FILE_NAME} in next to the bundled runtime.`, { cause: error });
863
+ }
864
+ const projectDir = (0, node_path_1.join)(deploymentRoot, manifest.relativeProjectDir);
865
+ const probe = (0, node_path_1.join)(projectDir, manifest.config.distDir, "required-server-files.json");
866
+ try {
867
+ await (0, promises_1.readFile)(probe);
868
+ }
869
+ catch (error) {
870
+ throw new Error(`The deployment root "${deploymentRoot}" does not contain the staged ` +
871
+ `Next.js project: expected "${probe}" to exist. Every built entrypoint ` +
872
+ `resolves its own paths against process.cwd(), so this layout is part ` +
873
+ `of the contract, not a convenience.`, { cause: error });
874
+ }
875
+ // `next start` forces this, and externalized packages (React for Pages Router
876
+ // SSR, anything in `serverExternalPackages`) pick their dev or prod build from
877
+ // it at require time. The Containers Dockerfiles set it and the Functions
878
+ // constructs do too; this covers a hand-wired function. Before any `require`.
879
+ // (`next`'s typings declare NODE_ENV read-only.)
880
+ process.env.NODE_ENV ??= "production";
881
+ process.chdir(projectDir);
882
+ // Before anything can serve a request: the runtime's own `next` imports resolve
883
+ // out of the staged app, not out of the shell's directory. See `next-modules.ts`.
884
+ (0, next_modules_1.useNextFrom)(projectDir);
885
+ // Before any entrypoint can read them at module scope.
886
+ (0, next_modules_1.loadEnvFiles)(projectDir);
887
+ // Then, before any entrypoint (or middleware) can be loaded: Next's own
888
+ // node-environment bootstrap. See `setupNodeEnvironment`.
889
+ (0, next_modules_1.setupNodeEnvironment)();
890
+ // And last, once the environment is ready: `register()`, before any entrypoint
891
+ // or middleware module is evaluated. See `registerInstrumentation`.
892
+ await (0, next_modules_1.registerInstrumentation)(projectDir, manifest.config.distDir);
893
+ return new NextjsRuntime({
894
+ deploymentRoot,
895
+ manifest,
896
+ bucket: process.env.CDK_NEXTJS_STATIC_ASSETS_BUCKET_NAME,
897
+ bucketKeyPrefix: process.env.CDK_NEXTJS_STATIC_ASSETS_KEY_PREFIX,
898
+ });
899
+ }
900
+ /**
901
+ * A syntactically valid `host[:port]`: a registered name or a bracketed IPv6
902
+ * literal, optionally with a port. Anything else cannot be the authority of a
903
+ * URL.
904
+ */
905
+ const HOST_AUTHORITY = /^(?:\[[0-9A-Fa-f:.]+\]|[0-9A-Za-z._-]+)(?::\d{1,5})?$/;
906
+ /**
907
+ * The first value that is actually usable as an authority, or `undefined`.
908
+ *
909
+ * `x-forwarded-host` can arrive as a list when more than one proxy appends to
910
+ * it. Validating is what keeps a malformed value from making the `URL`
911
+ * constructor throw — which on the Lambda shells is an invocation error and a
912
+ * 502, not a response.
913
+ */
914
+ function validAuthority(value) {
915
+ const candidate = (0, util_1.firstValue)(value)?.split(",")[0].trim();
916
+ return candidate && HOST_AUTHORITY.test(candidate) ? candidate : undefined;
917
+ }
918
+ /**
919
+ * `resolveRoutes` needs an absolute URL, and it becomes the origin every
920
+ * absolute URL the app builds starts with — `req.nextUrl.origin` in middleware,
921
+ * `initURL` for a route handler — so its host has to be one the client cannot
922
+ * pick.
923
+ *
924
+ * That is `Host` on every deployment but one: CloudFront forwards the viewer's
925
+ * `Host` to a container origin (`ALL_VIEWER`), an ALB passes it through, and API
926
+ * Gateway sets its own domain. The exception is a Lambda Function URL, where
927
+ * CloudFront has to send the URL's own domain as `Host` and puts the viewer's in
928
+ * `x-forwarded-host`; see {@link RuntimeRequest.trustForwardedHost}. Anywhere
929
+ * else the header is the client's, and honoring it let a request with
930
+ * `X-Forwarded-Host: evil.example` point a password-reset link at evil.example —
931
+ * and, on Global Containers, have CloudFront cache that page, since the header
932
+ * is not in its cache key.
933
+ */
934
+ function absoluteUrl(request) {
935
+ const host = (request.trustForwardedHost
936
+ ? validAuthority(request.headers["x-forwarded-host"])
937
+ : undefined) ??
938
+ validAuthority(request.headers.host) ??
939
+ "localhost";
940
+ // Behind CloudFront on Global Containers the container shell has already put
941
+ // the viewer's protocol here; see `trustCloudFrontProto` in http/node-server.ts.
942
+ const forwardedProto = (0, util_1.firstValue)(request.headers["x-forwarded-proto"])
943
+ ?.split(",")[0]
944
+ .trim()
945
+ .toLowerCase();
946
+ // Client-supplied where no proxy overwrites it, but harmless: the host is
947
+ // already fixed, and anything but these two would not parse.
948
+ const proto = forwardedProto === "http" || forwardedProto === "https"
949
+ ? forwardedProto
950
+ : request.encrypted === false
951
+ ? "http"
952
+ : "https";
953
+ return new URL(request.url, `${proto}://${host}`);
954
+ }
955
+ function pickDefined(headers, names) {
956
+ const picked = {};
957
+ for (const name of names) {
958
+ if (headers[name] !== undefined) {
959
+ picked[name] = headers[name];
960
+ }
961
+ }
962
+ return picked;
963
+ }
964
+ /**
965
+ * `normalizeRepeatedSlashes` (`next/dist/shared/lib/utils.js`), applied where
966
+ * Next.js applies it: before routing, as a 308 to the collapsed path.
967
+ * `base-server.ts` does `if (urlNoQuery?.match(/(\\|\/\/)/))
968
+ * res.redirect(normalizeRepeatedSlashes(req.url), 308)`, so `/a//b` and `/a\b`
969
+ * both answer a redirect to `/a/b` rather than a 404 - and `@next/routing`'s
970
+ * `resolveRoutes` does not do it for us, which is how `//` reached this runtime as
971
+ * a 500 and `/api//json` as a 404.
972
+ *
973
+ * Encoded backslashes are left alone, as Next.js leaves them: `%5C` is a literal
974
+ * character in a path segment, not a separator.
975
+ *
976
+ * Returns `undefined` when there is nothing to collapse, which is the common case.
977
+ */
978
+ function collapseRepeatedSlashes(target) {
979
+ const parts = target.split("?");
980
+ const pathname = parts[0];
981
+ if (!/\\|\/\//.test(pathname)) {
982
+ return undefined;
983
+ }
984
+ const query = parts.length > 1 ? `?${parts.slice(1).join("?")}` : "";
985
+ return pathname.replace(/\\/g, "/").replace(/\/\/+/g, "/") + query;
986
+ }
987
+ /**
988
+ * `resolveRoutes` hands `requestBody` to middleware, which consumes it, while the
989
+ * entrypoint needs the same bytes — the same problem `next-server` solves with
990
+ * `getCloneableBody()`. Only split when there is middleware to feed: teeing costs
991
+ * a buffer copy of every upload on a path that would otherwise be a straight pipe.
992
+ *
993
+ * A `tee()` buffers, for the branch that is behind, every chunk the other one
994
+ * has read — so a branch that is never read holds the whole body. Middleware
995
+ * that doesn't read the body is the common case (and its matcher may not even
996
+ * have run it), after which the entrypoint streaming an upload would pile all
997
+ * of it up in the middleware branch: the whole upload in memory, on a
998
+ * container that serves other requests. So once dispatch returns, the branch
999
+ * with no reader left is cancelled — the middleware one, or the entrypoint one
1000
+ * when middleware answered and `req` will never be read. Cancelling one
1001
+ * branch leaves the source and the other branch running.
1002
+ */
1003
+ function splitBody(body, hasMiddleware) {
1004
+ const releaseNothing = () => { };
1005
+ if (body === undefined) {
1006
+ return {
1007
+ forDispatch: new Blob([]).stream(),
1008
+ releaseUnread: releaseNothing,
1009
+ };
1010
+ }
1011
+ if (!hasMiddleware) {
1012
+ return {
1013
+ forRequest: body,
1014
+ forDispatch: new Blob([]).stream(),
1015
+ releaseUnread: releaseNothing,
1016
+ };
1017
+ }
1018
+ if (Buffer.isBuffer(body)) {
1019
+ // Already fully in memory, so "teeing" is just reading it twice.
1020
+ return {
1021
+ forRequest: body,
1022
+ forDispatch: new Blob([body]).stream(),
1023
+ releaseUnread: releaseNothing,
1024
+ };
1025
+ }
1026
+ const [forMiddleware, forEntrypoint] = node_stream_1.Readable.toWeb(body).tee();
1027
+ const forRequest = node_stream_1.Readable.fromWeb(forEntrypoint);
1028
+ return {
1029
+ forRequest,
1030
+ forDispatch: forMiddleware,
1031
+ releaseUnread(middlewareResponded) {
1032
+ if (middlewareResponded) {
1033
+ // `fromWeb` holds the branch's reader, so it is destroyed rather than
1034
+ // cancelled; its `_destroy` cancels the reader.
1035
+ forRequest.destroy();
1036
+ }
1037
+ else if (!forMiddleware.locked) {
1038
+ // Locked means middleware took a reader: it is reading, or has read,
1039
+ // the body itself, and a locked stream cannot be cancelled anyway.
1040
+ forMiddleware.cancel().catch(() => { });
1041
+ }
1042
+ },
1043
+ };
1044
+ }
1045
+ /** `IncomingHttpHeaders` → the flat entries a `Headers` constructor accepts. */
1046
+ function toWebHeaders(headers) {
1047
+ const entries = [];
1048
+ for (const [name, value] of Object.entries(headers)) {
1049
+ if (value === undefined) {
1050
+ continue;
1051
+ }
1052
+ for (const single of Array.isArray(value) ? value : [value]) {
1053
+ entries.push([name, single]);
1054
+ }
1055
+ }
1056
+ return entries;
1057
+ }
1058
+ /**
1059
+ * `headers()` rules, the immutable `cache-control` for build assets, and anything
1060
+ * middleware set with `NextResponse.next({ headers })`. Applied before the
1061
+ * entrypoint runs so that a route can still override its own.
1062
+ */
1063
+ function applyHeaders(res, headers) {
1064
+ for (const [name, value] of headers.entries()) {
1065
+ // `entries()` yields `set-cookie` once per cookie, so appending the whole
1066
+ // `getSetCookie()` array here would emit N² of them — two cookies set by
1067
+ // middleware arrived as ["a=1","b=2","a=1","b=2"]. Handled once, outside.
1068
+ if (name === "set-cookie") {
1069
+ continue;
1070
+ }
1071
+ res.setHeader(name, value);
1072
+ }
1073
+ for (const cookie of headers.getSetCookie()) {
1074
+ res.appendHeader("set-cookie", cookie);
1075
+ }
1076
+ }
1077
+ /**
1078
+ * Mirrors Next.js's own redirect response (`base-server.ts`): the destination is
1079
+ * also the body, and a 308 carries a `Refresh` header because some clients and
1080
+ * intermediaries still do not implement 308.
1081
+ */
1082
+ function sendRedirect(res, location, status) {
1083
+ res.statusCode = status;
1084
+ res.setHeader("Location", location);
1085
+ if (status === 308) {
1086
+ res.setHeader("Refresh", `0;url=${location}`);
1087
+ }
1088
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
1089
+ res.end(location);
1090
+ }
1091
+ /**
1092
+ * `next start`'s answer to a POST, PUT or DELETE for a static file: 405 with
1093
+ * `Allow: GET, HEAD` (`router-server.js`). It renders that through `/_error`;
1094
+ * this is the plain-text equivalent, since the status and `Allow` are what a
1095
+ * client acts on.
1096
+ */
1097
+ function sendMethodNotAllowed(res) {
1098
+ res.statusCode = 405;
1099
+ res.setHeader("Allow", "GET, HEAD");
1100
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
1101
+ res.end("Method Not Allowed");
1102
+ }
1103
+ /**
1104
+ * Request headers {@link proxyExternal} does not forward. The upstream's own
1105
+ * `Host` must win; the rest describe our connection, not the proxied one, and
1106
+ * undici throws on most of them, which would answer the request with a 500.
1107
+ * Next.js's list for the requests it makes with undici (`ipcForbiddenHeaders`,
1108
+ * `next/dist/server/lib/server-ipc/utils.js`), plus `host` and `upgrade`, minus
1109
+ * `content-encoding`: Next strips that over a body it has already decoded, while
1110
+ * this one is forwarded as received, still encoded.
1111
+ */
1112
+ const PROXY_DROPPED_HEADERS = [
1113
+ "host",
1114
+ "upgrade",
1115
+ "accept-encoding",
1116
+ "keepalive",
1117
+ "keep-alive",
1118
+ "transfer-encoding",
1119
+ "connection",
1120
+ "expect",
1121
+ ];
1122
+ /**
1123
+ * The SigV4 signature Origin Access Control put on a request to the Function
1124
+ * URL, also dropped by {@link proxyExternal} when the request was IAM-verified:
1125
+ * forwarded, it would let the third-party origin replay the request against
1126
+ * the Function URL. Anywhere else these are the client's own, and are
1127
+ * forwarded as `next start` forwards them.
1128
+ */
1129
+ const SIGV4_HEADERS = [
1130
+ "authorization",
1131
+ "x-amz-date",
1132
+ "x-amz-content-sha256",
1133
+ "x-amz-security-token",
1134
+ ];
1135
+ /** A `next.config` rewrite whose destination is another origin. */
1136
+ async function proxyExternal(req, res, url, requestHeaders) {
1137
+ const method = req.method ?? "GET";
1138
+ const hasBody = method !== "GET" && method !== "HEAD";
1139
+ const headers = new Headers(requestHeaders);
1140
+ for (const name of PROXY_DROPPED_HEADERS) {
1141
+ headers.delete(name);
1142
+ }
1143
+ if (req.trustForwardedHost) {
1144
+ for (const name of SIGV4_HEADERS) {
1145
+ headers.delete(name);
1146
+ }
1147
+ }
1148
+ const upstream = await fetch(url, {
1149
+ method,
1150
+ headers,
1151
+ body: hasBody ? node_stream_1.Readable.toWeb(req) : undefined,
1152
+ redirect: "manual",
1153
+ ...(hasBody ? { duplex: "half" } : {}),
1154
+ });
1155
+ await sendWebResponse(res, upstream);
1156
+ }
1157
+ /**
1158
+ * Headers describing the framing of a body that is no longer the body being
1159
+ * sent, dropped from every `Response` {@link sendWebResponse} forwards.
1160
+ *
1161
+ * A proxied origin's `Response` came back from `fetch`, and so, often, did
1162
+ * middleware's own (`return fetch(upstream)` in `proxy.ts`, since middleware
1163
+ * runs in process and its `fetch` is undici). undici decodes the body — gzip,
1164
+ * deflate, br, zstd — and leaves `content-encoding` and `content-length`
1165
+ * describing the encoded bytes it already threw away. Forwarding them emits
1166
+ * plaintext labelled `gzip` (the browser fails the whole response with
1167
+ * `ERR_CONTENT_DECODING_FAILED`) under a `Content-Length` that is too short,
1168
+ * and `shouldGzip` then declines to compress it because `content-encoding` is
1169
+ * already set, so nothing downstream repairs it. `transfer-encoding` is
1170
+ * hop-by-hop: it described the upstream connection, not this one.
1171
+ *
1172
+ * Stock Next.js drops the same three from every middleware response
1173
+ * (`FORBIDDEN_HEADERS` in `next/dist/server/web/sandbox/sandbox.js`), so
1174
+ * middleware cannot label a body it encoded itself there either.
1175
+ */
1176
+ const STALE_FRAMING_HEADERS = new Set([
1177
+ "content-encoding",
1178
+ "content-length",
1179
+ "transfer-encoding",
1180
+ ]);
1181
+ /** Stream a `Response` — middleware's own, or a proxied origin's — into `res`. */
1182
+ async function sendWebResponse(res, response) {
1183
+ res.statusCode = response.status;
1184
+ if (response.statusText) {
1185
+ res.statusMessage = response.statusText;
1186
+ }
1187
+ const headers = new Headers(response.headers);
1188
+ for (const name of STALE_FRAMING_HEADERS) {
1189
+ headers.delete(name);
1190
+ }
1191
+ applyHeaders(res, headers);
1192
+ if (!response.body) {
1193
+ res.end();
1194
+ return;
1195
+ }
1196
+ for await (const chunk of response.body) {
1197
+ // Leaving the loop cancels the body, which is what stops a proxied origin
1198
+ // from being read to the end for a client that has already gone.
1199
+ if (res.destroyed) {
1200
+ return;
1201
+ }
1202
+ // Paced by the client: without waiting for `drain`, a large proxied body
1203
+ // headed for a slow client is buffered whole in memory.
1204
+ const accepted = res.write(chunk);
1205
+ // Set by the sink when it compresses. Without it the chunk sits in zlib's
1206
+ // buffer, and a streamed body — server-sent events through a rewrite, a
1207
+ // middleware `ReadableStream` — reaches the client all at once, at the end.
1208
+ // Next.js flushes after every chunk for the same reason (`pipe-readable`).
1209
+ res.flush?.();
1210
+ if (!accepted && !(await (0, util_1.drained)(res))) {
1211
+ return;
1212
+ }
1213
+ }
1214
+ res.end();
1215
+ }
1216
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2NvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBMDlCQSx3REFnQkM7QUFtREQsc0RBK0JDO0FBbUJELGtDQTBEQztBQWlJRCw4QkEyQ0M7QUFyekNELHNEQUFzRDtBQUN0RDs7Ozs7Ozs7Ozs7R0FXRztBQUNILCtDQUE0QztBQUU1Qyx5Q0FBaUM7QUFDakMsNkNBQWlEO0FBQ2pELG1EQUFvRDtBQUNwRCx5Q0FLb0I7QUFDcEIsK0NBSXVCO0FBQ3ZCLDRDQUE0RTtBQUM1RSw4Q0FJeUI7QUFDekIsc0NBQXVEO0FBQ3ZELG1DQUF1RTtBQUN2RSx5Q0FNb0I7QUFDcEIsNkNBQWdEO0FBQ2hELGlEQUt3QjtBQUN4QixpREFBa0U7QUFDbEUsaURBQW9FO0FBQ3BFLGlDQUEwRTtBQStEMUUsTUFBYSxhQUFhO0lBVVk7SUFUbkIsV0FBVyxDQUFxQjtJQUNoQyxVQUFVLENBQWE7SUFDdkIsVUFBVSxDQUFvQjtJQUM5QixNQUFNLENBQXdCO0lBQy9DLDJDQUEyQztJQUMxQixjQUFjLENBQXlDO0lBQ3hFLGtFQUFrRTtJQUNqRCxZQUFZLENBQVU7SUFFdkMsWUFBb0MsT0FBNkI7UUFBN0IsWUFBTyxHQUFQLE9BQU8sQ0FBc0I7UUFDL0QsTUFBTSxFQUFFLFFBQVEsRUFBRSxjQUFjLEVBQUUsR0FBRyxPQUFPLENBQUM7UUFDN0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLGdDQUFrQixDQUFDLGNBQWMsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNwRSx3REFBd0Q7UUFDeEQsTUFBTSxXQUFXLEdBQUcsSUFBQSxpQ0FBa0IsRUFBQyxjQUFjLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDakUsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLHFCQUFVLENBQUM7WUFDL0IsUUFBUTtZQUNSLFdBQVcsRUFBRSxXQUFXLENBQUMsS0FBSztTQUMvQixDQUFDLENBQUM7UUFDSCww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QVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNuQixHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDVixPQUFPO0lBQ1QsQ0FBQztJQUNELElBQUksS0FBSyxFQUFFLE1BQU0sS0FBSyxJQUFJLFFBQVEsQ0FBQyxJQUE0QyxFQUFFLENBQUM7UUFDaEYsMEVBQTBFO1FBQzFFLGlFQUFpRTtRQUNqRSxJQUFJLEdBQUcsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNsQixPQUFPO1FBQ1QsQ0FBQztRQUNELHlFQUF5RTtRQUN6RSx3REFBd0Q7UUFDeEQsTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNsQywwRUFBMEU7UUFDMUUsd0VBQXdFO1FBQ3hFLDRFQUE0RTtRQUM1RSwyRUFBMkU7UUFDM0UsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUM7UUFDZCxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxNQUFNLElBQUEsY0FBTyxFQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN2QyxPQUFPO1FBQ1QsQ0FBQztJQUNILENBQUM7SUFDRCxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7QUFDWixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzICovXG4vKipcbiAqIFRoZSBydW50aW1lIGNvcmU6IG9uZSBgaGFuZGxlKHJlcXVlc3QsIHNpbmspYCB0aGF0IGJvdGggc2hlbGxzIHdyYXAuXG4gKlxuICogVGhlIExhbWJkYSBzaGVsbCAoYGxhbWJkYS5tdHNgKSBhbmQgdGhlIGNvbnRhaW5lciBzaGVsbCAoYHNlcnZlci5tdHNgKSBkb1xuICogbm90aGluZyBidXQgdHVybiB0aGVpciBpbnB1dCBpbnRvIGEge0BsaW5rIFJ1bnRpbWVSZXF1ZXN0fSBhbmQgdGhlaXIgb3V0cHV0IGludG9cbiAqIGEge0BsaW5rIFJlc3BvbnNlU2lua30uIEV2ZXJ5dGhpbmcgZWxzZSDigJQgc3ludGhlc2l6aW5nIGByZXFgL2ByZXNgLCBkaXNwYXRjaCxcbiAqIG1pZGRsZXdhcmUsIGVudHJ5cG9pbnQgaW52b2NhdGlvbiwgc3RhdGljIGZpbGVzLCBpbWFnZSBvcHRpbWl6YXRpb24sIGd6aXAsXG4gKiBgd2FpdFVudGlsYCDigJQgaGFwcGVucyBoZXJlLCBzbyB0aGUgY29udGFpbmVyIGUyZSBzdWl0ZSBleGVyY2lzZXMgdGhlIHNhbWUgY29kZVxuICogTGFtYmRhIHJ1bnMuIFRoYXQgaXMgZGVsaWJlcmF0ZTogdGhlIGNvbnRhaW5lciBwYXRoIHVzZWQgdG8gZ2V0IHJlYWxcbiAqIGBub2RlOmh0dHBgIG9iamVjdHMgZnJvbSBMYW1iZGEgV2ViIEFkYXB0ZXIsIHdoaWNoIG1lYW50IGNvbnRhaW5lciB0ZXN0cyBwcm92ZWRcbiAqIG5vdGhpbmcgYWJvdXQgTGFtYmRhLlxuICovXG5pbXBvcnQgeyByZWFkRmlsZSB9IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCI7XG5pbXBvcnQgdHlwZSB7IEluY29taW5nSHR0cEhlYWRlcnMgfSBmcm9tIFwibm9kZTpodHRwXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgUmVhZGFibGUsIFdyaXRhYmxlIH0gZnJvbSBcIm5vZGU6c3RyZWFtXCI7XG5pbXBvcnQgeyBjYXNlQ2Fub25pY2FsUGF0aCB9IGZyb20gXCIuL2Nhc2UtcmVkaXJlY3RcIjtcbmltcG9ydCB7XG4gIERpc3BhdGNoZXIsXG4gIG91dE9mQmFuZFJvdXRlUGFyYW1zLFxuICBTdGF0dXNUYXJnZXQsXG4gIHN0YXR1c1RhcmdldHMsXG59IGZyb20gXCIuL2Rpc3BhdGNoXCI7XG5pbXBvcnQge1xuICBFbnRyeXBvaW50SGFuZGxlcixcbiAgRW50cnlwb2ludFJlZ2lzdHJ5LFxuICBSb3V0ZUluT3RoZXJHcm91cEVycm9yLFxufSBmcm9tIFwiLi9lbnRyeXBvaW50c1wiO1xuaW1wb3J0IHsgU2hpbUluY29taW5nTWVzc2FnZSwgdG9JbmNvbWluZ0h0dHBIZWFkZXJzIH0gZnJvbSBcIi4vaHR0cC9yZXF1ZXN0XCI7XG5pbXBvcnQge1xuICBhc1NlcnZlclJlc3BvbnNlLFxuICBSZXNwb25zZUhlYWQsXG4gIFNoaW1TZXJ2ZXJSZXNwb25zZSxcbn0gZnJvbSBcIi4vaHR0cC9yZXNwb25zZVwiO1xuaW1wb3J0IHsgcGlwZVRvU2luaywgUmVzcG9uc2VTaW5rIH0gZnJvbSBcIi4vaHR0cC9zaW5rXCI7XG5pbXBvcnQgeyBJbnRlcm5hbEltYWdlUmVzcG9uc2UsIFJ1bnRpbWVJbWFnZU9wdGltaXplciB9IGZyb20gXCIuL2ltYWdlXCI7XG5pbXBvcnQge1xuICBBZGFwdGVyTWFuaWZlc3QsXG4gIGRlcGxveWVkTWFuaWZlc3RQYXRoLFxuICBGVU5DVElPTl9HUk9VUF9FTlZfVkFSLFxuICBNQU5JRkVTVF9GSUxFX05BTUUsXG4gIFJFVkFMSURBVEVEX1BBR0VfSE9PSyxcbn0gZnJvbSBcIi4vbWFuaWZlc3RcIjtcbmltcG9ydCB7IE1pZGRsZXdhcmVSdW5uZXIgfSBmcm9tIFwiLi9taWRkbGV3YXJlXCI7XG5pbXBvcnQge1xuICBsb2FkRW52RmlsZXMsXG4gIHJlZ2lzdGVySW5zdHJ1bWVudGF0aW9uLFxuICBzZXR1cE5vZGVFbnZpcm9ubWVudCxcbiAgdXNlTmV4dEZyb20sXG59IGZyb20gXCIuL25leHQtbW9kdWxlc1wiO1xuaW1wb3J0IHsgcHVibGljRGlyS2V5LCByZXNvbHZlUHVibGljRmlsZXMgfSBmcm9tIFwiLi9wdWJsaWMtZmlsZXNcIjtcbmltcG9ydCB7IHNlcnZlUzNQdWJsaWNGaWxlLCBzZXJ2ZVN0YXRpY0ZpbGUgfSBmcm9tIFwiLi9zdGF0aWMtZmlsZXNcIjtcbmltcG9ydCB7IGRyYWluZWQsIGZpcnN0VmFsdWUsIHRvU2VhcmNoLCB3aXRob3V0UGF0aFByZWZpeCB9IGZyb20gXCIuL3V0aWxcIjtcblxuLyoqIE9uZSByZXF1ZXN0LCBub3JtYWxpemVkIGJ5IGEgc2hlbGwuICovXG5leHBvcnQgaW50ZXJmYWNlIFJ1bnRpbWVSZXF1ZXN0IHtcbiAgcmVhZG9ubHkgbWV0aG9kOiBzdHJpbmc7XG4gIC8qKiBPcmlnaW4tZm9ybSB0YXJnZXQgZXhhY3RseSBhcyByZWNlaXZlZDogcGF0aCArIHF1ZXJ5LCBuZXZlciBhYnNvbHV0ZS4gKi9cbiAgcmVhZG9ubHkgdXJsOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGhlYWRlcnM6IEluY29taW5nSHR0cEhlYWRlcnM7XG4gIHJlYWRvbmx5IGJvZHk/OiBSZWFkYWJsZSB8IEJ1ZmZlcjtcbiAgcmVhZG9ubHkgcmVtb3RlQWRkcmVzcz86IHN0cmluZztcbiAgLyoqIGBmYWxzZWAgYmVoaW5kIGEgVExTLXRlcm1pbmF0aW5nIEFMQi4gT25seSBhZmZlY3RzIHRoZSBzeW50aGVzaXplZCBzb2NrZXQuICovXG4gIHJlYWRvbmx5IGVuY3J5cHRlZD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBBYm9ydGVkIHdoZW4gdGhlIGNsaWVudCBkaXNjb25uZWN0cy4gV2lyaW5nIGl0IHRvIGByZXMuZGVzdHJveSgpYCBpcyB3aGF0XG4gICAqIG1ha2VzIGByZXF1ZXN0LnNpZ25hbC5vbmFib3J0YCBmaXJlIGluc2lkZSByb3V0ZSBoYW5kbGVycy5cbiAgICovXG4gIHJlYWRvbmx5IHNpZ25hbD86IEFib3J0U2lnbmFsO1xuICAvKipcbiAgICogV2hldGhlciBgeC1mb3J3YXJkZWQtaG9zdGAgbmFtZXMgdGhlIGhvc3QgdGhlIGNsaWVudCBhc2tlZCBmb3IuIE9ubHkgdGhlXG4gICAqIHNoZWxsIGNhbiBrbm93OiBpdCBpcyBgdHJ1ZWAgZm9yIGEgRnVuY3Rpb24gVVJMIGV2ZW50IHdob3NlIFNpZ1Y0IExhbWJkYVxuICAgKiB2ZXJpZmllZC4gVGhhdCBpcyBhbnkgSUFNLWF1dGhvcml6ZWQgaW52b2tlciDigJQgaW4gcHJhY3RpY2UgQ2xvdWRGcm9udCdzXG4gICAqIE9yaWdpbiBBY2Nlc3MgQ29udHJvbCwgd2hvc2Ugdmlld2VyLXJlcXVlc3QgZnVuY3Rpb24gb3ZlcndyaXRlcyB0aGUgaGVhZGVyXG4gICAqIHdpdGggdGhlIHZpZXdlcidzIGBIb3N0YCAoQ2xvdWRGcm9udCBoYXMgdG8gcmVwbGFjZSBgSG9zdGAgaXRzZWxmIHdpdGggdGhlXG4gICAqIEZ1bmN0aW9uIFVSTCdzIGRvbWFpbiksIHBsdXMgcHJpbmNpcGFscyBncmFudGVkIGBsYW1iZGE6SW52b2tlRnVuY3Rpb25VcmxgLFxuICAgKiB3aG8gY291bGQgcmVwbGFjZSB0aGUgZnVuY3Rpb24ncyBjb2RlIGFueXdheS4gSXQgaXMgYWxzbyB3aGF0XG4gICAqIGBwcm94eUV4dGVybmFsYCBkcm9wcyBPQUMncyBzaWduYXR1cmUgb24uIEV2ZXJ5d2hlcmUgZWxzZSB0aGUgaGVhZGVyIGlzXG4gICAqIHdoYXRldmVyIHRoZSBjbGllbnQgc2VudCwgYW5kIGl0IGlzXG4gICAqIGlnbm9yZWQsIGFzIGBuZXh0IHN0YXJ0YCBpZ25vcmVzIGl0IHdpdGhvdXQgYGV4cGVyaW1lbnRhbC50cnVzdEhvc3RIZWFkZXJgLlxuICAgKi9cbiAgcmVhZG9ubHkgdHJ1c3RGb3J3YXJkZWRIb3N0PzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFNldCBieSB7QGxpbmsgTmV4dGpzUnVudGltZS5oYW5kbGVJbnRlcm5hbGx5fSBmb3IgdGhlIGluLXByb2Nlc3MgcmVxdWVzdHMgaXRcbiAgICogbWFrZXM6IGNhbGxlZCB3aXRoIHRoZSBgUm91dGVJbk90aGVyR3JvdXBFcnJvcmAgdGhlIHJvdXRlIHRocmV3LCBpbnN0ZWFkIG9mXG4gICAqIGxvZ2dpbmcgdGhlIG1pc3JvdXRlZC1yZXF1ZXN0IHdhcm5pbmcsIHdoaWNoIGRlc2NyaWJlcyBhIENsb3VkRnJvbnQgb3IgQVBJXG4gICAqIEdhdGV3YXkgcHJvYmxlbSB0aGlzIGlzIG5vdC5cbiAgICovXG4gIHJlYWRvbmx5IG9uUm91dGVJbk90aGVyR3JvdXA/OiAoZXJyb3I6IFJvdXRlSW5PdGhlckdyb3VwRXJyb3IpID0+IHZvaWQ7XG59XG5cbi8qKlxuICogYFJldmFsaWRhdGVGbmAncyBhcmd1bWVudCAoYG5leHQvZGlzdC9zZXJ2ZXIvbGliL3JvdXRlci11dGlscy9yb3V0ZXItc2VydmVyLWNvbnRleHRgKSxcbiAqIHJlc3RhdGVkIGJlY2F1c2UgdGhhdCBtb2R1bGUgaXMgbm90IHBhcnQgb2YgYG5leHRgJ3MgcHVibGlzaGVkIHR5cGUgc3VyZmFjZS5cbiAqL1xuaW50ZXJmYWNlIFJldmFsaWRhdGVDb25maWcge1xuICByZWFkb25seSB1cmxQYXRoOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGhlYWRlcnM6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW10gfTtcbiAgcmVhZG9ubHkgb3B0czogeyB1bnN0YWJsZV9vbmx5R2VuZXJhdGVkPzogYm9vbGVhbiB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc1J1bnRpbWVPcHRpb25zIHtcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gdGhlIGRlcGxveW1lbnQgcm9vdCDigJQgdGhlIHN0YWdlZCB0cmVlIGV2ZXJ5IG1hbmlmZXN0IGtleVxuICAgKiByZXNvbHZlcyBhZ2FpbnN0LiBgTEFNQkRBX1RBU0tfUk9PVGAgZm9yIEZ1bmN0aW9ucywgdGhlIGltYWdlIGBXT1JLRElSYCBmb3JcbiAgICogQ29udGFpbmVyczsgYm90aCBzaGVsbHMgZGVyaXZlIGl0IGZyb20gdGhlaXIgb3duIGxvY2F0aW9uIGluc3RlYWQuXG4gICAqL1xuICByZWFkb25seSBkZXBsb3ltZW50Um9vdDogc3RyaW5nO1xuICByZWFkb25seSBtYW5pZmVzdDogQWRhcHRlck1hbmlmZXN0O1xuICAvKiogYENES19ORVhUSlNfU1RBVElDX0FTU0VUU19CVUNLRVRfTkFNRWAuICovXG4gIHJlYWRvbmx5IGJ1Y2tldD86IHN0cmluZztcbiAgLyoqIGBDREtfTkVYVEpTX1NUQVRJQ19BU1NFVFNfS0VZX1BSRUZJWGAuICovXG4gIHJlYWRvbmx5IGJ1Y2tldEtleVByZWZpeD86IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIE5leHRqc1J1bnRpbWUge1xuICBwcml2YXRlIHJlYWRvbmx5IGVudHJ5cG9pbnRzOiBFbnRyeXBvaW50UmVnaXN0cnk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGlzcGF0Y2hlcjogRGlzcGF0Y2hlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBtaWRkbGV3YXJlPzogTWlkZGxld2FyZVJ1bm5lcjtcbiAgcHJpdmF0ZSByZWFkb25seSBpbWFnZXM6IFJ1bnRpbWVJbWFnZU9wdGltaXplcjtcbiAgLyoqIFRoZSA1MDAgbGFkZGVyOyBzZWUgYHN0YXR1c1RhcmdldHNgLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGVycm9yVGFyZ2V0Rm9yOiAodXJsOiBVUkwgfCB1bmRlZmluZWQpID0+IFN0YXR1c1RhcmdldDtcbiAgLyoqIFRoZSBhc3NldHMgYnVja2V0LCB3aGVuIGBwdWJsaWMvYCBmaWxlcyBhcmUgc2VydmVkIGZyb20gaXQuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgcHVibGljQnVja2V0Pzogc3RyaW5nO1xuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnM6IE5leHRqc1J1bnRpbWVPcHRpb25zKSB7XG4gICAgY29uc3QgeyBtYW5pZmVzdCwgZGVwbG95bWVudFJvb3QgfSA9IG9wdGlvbnM7XG4gICAgdGhpcy5lbnRyeXBvaW50cyA9IG5ldyBFbnRyeXBvaW50UmVnaXN0cnkoZGVwbG95bWVudFJvb3QsIG1hbmlmZXN0KTtcbiAgICAvLyBMaXN0ZWQgb25jZSwgYXQgY29sZCBzdGFydDsgc2VlIGByZXNvbHZlUHVibGljRmlsZXNgLlxuICAgIGNvbnN0IHB1YmxpY0ZpbGVzID0gcmVzb2x2ZVB1YmxpY0ZpbGVzKGRlcGxveW1lbnRSb290LCBtYW5pZmVzdCk7XG4gICAgdGhpcy5kaXNwYXRjaGVyID0gbmV3IERpc3BhdGNoZXIoe1xuICAgICAgbWFuaWZlc3QsXG4gICAgICBwdWJsaWNGaWxlczogcHVibGljRmlsZXMuZmlsZXMsXG4gICAgfSk7XG4gICAgLy8gT24gZGlzayBvdGhlcndpc2UsIHdpdGggYC5uZXh0L3N0YXRpY2AuXG4gICAgdGhpcy5wdWJsaWNCdWNrZXQgPSBwdWJsaWNGaWxlcy5pblMzID8gb3B0aW9ucy5idWNrZXQgOiB1bmRlZmluZWQ7XG4gICAgdGhpcy5lcnJvclRhcmdldEZvciA9IHN0YXR1c1RhcmdldHMobWFuaWZlc3QsIDUwMCk7XG4gICAgdGhpcy5pbWFnZXMgPSBuZXcgUnVudGltZUltYWdlT3B0aW1pemVyKHtcbiAgICAgIGRlcGxveW1lbnRSb290LFxuICAgICAgbWFuaWZlc3QsXG4gICAgICBidWNrZXQ6IHRoaXMucHVibGljQnVja2V0ID8/IFwiXCIsXG4gICAgICBidWNrZXRLZXlQcmVmaXg6IG9wdGlvbnMuYnVja2V0S2V5UHJlZml4ID8/IFwiXCIsXG4gICAgICBmZXRjaEludGVybmFsOiAoaHJlZiwgcmVxLCBtYXhpbXVtQm9keSkgPT5cbiAgICAgICAgdGhpcy5mZXRjaEludGVybmFsKGhyZWYsIHJlcSwgbWF4aW11bUJvZHkpLFxuICAgIH0pO1xuICAgIC8vIFRoZSBydW5uZXIgaXMgc2hhcmVkIOKAlCBpdCBtZW1vaXplcyB0aGUgbG9hZGVkIG1pZGRsZXdhcmUgbW9kdWxlIOKAlCB3aGlsZSB0aGVcbiAgICAvLyBgaW52b2tlTWlkZGxld2FyZWAgY2FsbGJhY2sgaXQgcHJvZHVjZXMgaXMgcGVyIHJlcXVlc3QuXG4gICAgdGhpcy5taWRkbGV3YXJlID0gbWFuaWZlc3QubWlkZGxld2FyZVxuICAgICAgPyBuZXcgTWlkZGxld2FyZVJ1bm5lcih7XG4gICAgICAgICAgbWlkZGxld2FyZTogbWFuaWZlc3QubWlkZGxld2FyZSxcbiAgICAgICAgICByb290OiBkZXBsb3ltZW50Um9vdCxcbiAgICAgICAgfSlcbiAgICAgIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgcHVibGljIGdldCBtYW5pZmVzdCgpOiBBZGFwdGVyTWFuaWZlc3Qge1xuICAgIHJldHVybiB0aGlzLm9wdGlvbnMubWFuaWZlc3Q7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgaGFuZGxlKFxuICAgIHJlcXVlc3Q6IFJ1bnRpbWVSZXF1ZXN0LFxuICAgIHNpbms6IFJlc3BvbnNlU2luayxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBtYW5pZmVzdCB9ID0gdGhpcy5vcHRpb25zO1xuICAgIGNvbnN0IHBlbmRpbmc6IEFycmF5PFByb21pc2U8dW5rbm93bj4+ID0gW107XG4gICAgY29uc3Qgd2FpdFVudGlsID0gKHByb21pc2U6IFByb21pc2U8dW5rbm93bj4pID0+IHtcbiAgICAgIHBlbmRpbmcucHVzaChwcm9taXNlKTtcbiAgICB9O1xuXG4gICAgY29uc3QgYm9keSA9IHNwbGl0Qm9keShyZXF1ZXN0LmJvZHksIHRoaXMubWlkZGxld2FyZSAhPT0gdW5kZWZpbmVkKTtcbiAgICBjb25zdCByZXEgPSBuZXcgU2hpbUluY29taW5nTWVzc2FnZSh7XG4gICAgICBtZXRob2Q6IHJlcXVlc3QubWV0aG9kLFxuICAgICAgdXJsOiByZXF1ZXN0LnVybCxcbiAgICAgIGhlYWRlcnM6IHdpdGhvdXRJbnRlcm5hbEhlYWRlcnMoXG4gICAgICAgIHJlcXVlc3QuaGVhZGVycyxcbiAgICAgICAgcmVxdWVzdC51cmwsXG4gICAgICAgIG1hbmlmZXN0LmNvbmZpZy5iYXNlUGF0aCxcbiAgICAgICksXG4gICAgICBib2R5OiBib2R5LmZvclJlcXVlc3QsXG4gICAgICByZW1vdGVBZGRyZXNzOiByZXF1ZXN0LnJlbW90ZUFkZHJlc3MsXG4gICAgICBlbmNyeXB0ZWQ6IHJlcXVlc3QuZW5jcnlwdGVkLFxuICAgICAgdHJ1c3RGb3J3YXJkZWRIb3N0OiByZXF1ZXN0LnRydXN0Rm9yd2FyZGVkSG9zdCxcbiAgICB9KTtcbiAgICBjb25zdCByZXMgPSBuZXcgU2hpbVNlcnZlclJlc3BvbnNlKCk7XG4gICAgLy8gTmV4dC5qcyByZWFkcyBgcmVzLnJlcWAgaW4gYSBmZXcgZXJyb3IgcGF0aHMuXG4gICAgcmVzLnJlcSA9IHJlcTtcbiAgICByZXF1ZXN0LnNpZ25hbD8uYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsICgpID0+IHJlcy5kZXN0cm95KCksIHtcbiAgICAgIG9uY2U6IHRydWUsXG4gICAgfSk7XG5cbiAgICAvLyBUaGUgcmVqZWN0aW9uIGhhbmRsZXIgaXMgYXR0YWNoZWQgaGVyZSByYXRoZXIgdGhhbiBhdCB0aGUgYGF3YWl0YCBiZWxvdy5cbiAgICAvLyBgcm91dGUoKWAgYXdhaXRzIHJlYWwgSS9PLCBzbyBhIHN0cmVhbSB0aGF0IGJyZWFrcyB3aGlsZSBpdCBydW5zIHdvdWxkXG4gICAgLy8gbGVhdmUgdGhpcyBwcm9taXNlIHJlamVjdGVkIHdpdGggbm8gaGFuZGxlciBhdHRhY2hlZCBmb3IgYSBmdWxsIGV2ZW50LWxvb3BcbiAgICAvLyB0dXJuIOKAlCBhbmQgTm9kZSAyNCBkZWZhdWx0cyB0byBgLS11bmhhbmRsZWQtcmVqZWN0aW9ucz10aHJvd2AsIHdoaWNoIG9uXG4gICAgLy8gdGhlIGNvbnRhaW5lciBzaGVsbCB0YWtlcyB0aGUgd2hvbGUgdGFzayBkb3duIGFuZCBhYm9ydHMgZXZlcnkgb3RoZXJcbiAgICAvLyBpbi1mbGlnaHQgcmVxdWVzdCBvbiBpdC4gQSBtaWQtc3RyZWFtIEVQSVBFIGZyb20gb25lIGNsaWVudCBkaXNjb25uZWN0IGlzXG4gICAgLy8gbm90IGdyb3VuZHMgZm9yIHRoYXQuXG4gICAgLy9cbiAgICAvLyBUaGUgZXJyb3IgaXMgbG9nZ2VkLCBub3QgcmV0aHJvd246IHRoZSBzdHJlYW0gYnJva2UgYWZ0ZXIgKG9yIHdoaWxlKSB0aGVcbiAgICAvLyBoZWFkIHdlbnQgb3V0IOKAlCBhIGNsaWVudCBkaXNjb25uZWN0LCBvciBgc2VuZEVycm9yYCBkZXN0cm95aW5nIGFcbiAgICAvLyBoYWxmLXdyaXR0ZW4gcmVzcG9uc2Ug4oCUIGFuZCBuZWl0aGVyIGlzIGFuIGludm9jYXRpb24gZmFpbHVyZS4gUmV0aHJvd2luZ1xuICAgIC8vIHdvdWxkIG1ha2UgTGFtYmRhIHJldHJ5IGEgcmVxdWVzdCB0aGUgY2xpZW50IGFscmVhZHkgYWJhbmRvbmVkLlxuICAgIGNvbnN0IGZpbmlzaGVkID0gcGlwZVRvU2luayhyZXEsIHJlcywgc2luaywge1xuICAgICAgY29tcHJlc3M6IG1hbmlmZXN0LmNvbmZpZy5jb21wcmVzcyxcbiAgICB9KS5jYXRjaCgoZXJyb3I6IHVua25vd24pID0+IHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJUaGUgcmVzcG9uc2Ugc3RyZWFtIGRpZCBub3QgY29tcGxldGU6XCIsIGVycm9yKTtcbiAgICB9KTtcblxuICAgIC8vIEZvciB0aGUgZXJyb3IgcGFnZSdzIGxvY2FsZTsgdW5zZXQgd2hlbiB0aGUgdGhyb3cgaXMgYGFic29sdXRlVXJsYCdzLlxuICAgIGxldCB1cmw6IFVSTCB8IHVuZGVmaW5lZDtcbiAgICB0cnkge1xuICAgICAgLy8gQmVmb3JlIGFueXRoaW5nIHBhcnNlcyB0aGUgdGFyZ2V0LCBpbmNsdWRpbmcgYGFic29sdXRlVXJsYCAtIGBuZXcgVVJMYFxuICAgICAgLy8gcmVhZHMgYSBsZWFkaW5nIGAvL2AgYXMgcHJvdG9jb2wtcmVsYXRpdmUgYW5kIHdvdWxkIHRha2UgdGhlIGZpcnN0IHBhdGhcbiAgICAgIC8vIHNlZ21lbnQgZm9yIHRoZSBob3N0LlxuICAgICAgY29uc3QgY29sbGFwc2VkID0gY29sbGFwc2VSZXBlYXRlZFNsYXNoZXMocmVxdWVzdC51cmwpO1xuICAgICAgaWYgKGNvbGxhcHNlZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHNlbmRSZWRpcmVjdChyZXMsIGNvbGxhcHNlZCwgMzA4KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEluc2lkZSB0aGUgdHJ5OiBgYWJzb2x1dGVVcmxgIGJ1aWxkcyBhIGBVUkxgIG91dCBvZiB0aGUgcmVxdWVzdCBsaW5lXG4gICAgICAgIC8vIGFuZCB0aGUgZm9yd2FyZGVkIGhlYWRlcnMsIGFuZCBhIHRocm93IGhlcmUgaGFzIHRvIHJlYWNoIHRoZSBlcnJvclxuICAgICAgICAvLyBsYWRkZXIgbGlrZSBhbnkgb3RoZXIuIE91dHNpZGUgaXQsIG9uIHRoZSBMYW1iZGEgc2hlbGxzIOKAlCB3aG9zZVxuICAgICAgICAvLyBoYW5kbGVycyB3cmFwIG5vdGhpbmcg4oCUIHRoZSBzYW1lIHRocm93IGlzIGFuIGludm9jYXRpb24gZXJyb3IgYW5kIGFcbiAgICAgICAgLy8gNTAyLlxuICAgICAgICB1cmwgPSBhYnNvbHV0ZVVybChyZXF1ZXN0KTtcbiAgICAgICAgYXdhaXQgdGhpcy5yb3V0ZShyZXEsIHJlcywgdXJsLCBib2R5LCB3YWl0VW50aWwsIHJlcXVlc3QpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBhd2FpdCB0aGlzLnNlbmRFcnJvcihyZXEsIHJlcywgd2FpdFVudGlsLCBlcnJvciwgdXJsKTtcbiAgICB9XG5cbiAgICBhd2FpdCBmaW5pc2hlZDtcblxuICAgIC8vIExhbWJkYSBmcmVlemVzIHRoZSBleGVjdXRpb24gZW52aXJvbm1lbnQgdGhlIG1vbWVudCB0aGUgaGFuZGxlciByZXNvbHZlcyDigJRcbiAgICAvLyB0aGVyZSBpcyBubyBwb3N0LXJlc3BvbnNlIGtlZXBhbGl2ZSDigJQgc28gYmFja2dyb3VuZCB3b3JrIHJlZ2lzdGVyZWQgd2l0aFxuICAgIC8vIGB3YWl0VW50aWxgIChub3RhYmx5IElTUiByZXZhbGlkYXRpb24pIGhhcyB0byBiZSBhd2FpdGVkIGhlcmUuIEFmdGVyIHRoZVxuICAgIC8vIHJlc3BvbnNlIHN0cmVhbSBoYXMgY2xvc2VkLCBzbyBjbGllbnQgbGF0ZW5jeSBpcyB1bmFmZmVjdGVkOyBiaWxsZWRcbiAgICAvLyBkdXJhdGlvbiBleHRlbmRzLCB3aGljaCBpcyB0aGUgY29ycmVjdCB0cmFkZSBhZ2FpbnN0IGEgcmV2YWxpZGF0aW9uIHRoYXRcbiAgICAvLyBuZXZlciBjb21wbGV0ZXMuXG4gICAgLy9cbiAgICAvLyBEcmFpbmVkIHVudGlsIG5vdGhpbmcgbmV3IGFycml2ZXMsIG5vdCBhd2FpdGVkIG9uY2U6IGB3YWl0VW50aWxgIGtlZXBzXG4gICAgLy8gYmVpbmcgY2FsbGVkIGFmdGVyIHRoZSByZXNwb25zZSDigJQgTmV4dCdzIGBBZnRlckNvbnRleHRgIHJlZ2lzdGVycyBpdHNcbiAgICAvLyBjYWxsYmFjayBxdWV1ZSBvbiB0aGUgZmlyc3QgYGFmdGVyKClgLCBhbmQgYW4gYGFmdGVyKHByb21pc2UpYCBtYWRlIGZyb21cbiAgICAvLyBpbnNpZGUgYSBydW5uaW5nIGNhbGxiYWNrLCBvciBhIGJhY2tncm91bmQgcmVnZW5lcmF0aW9uIHRoYXQgaXRzZWxmIGNhbGxzXG4gICAgLy8gYGFmdGVyKClgLCByZWdpc3RlcnMgbW9yZS4gQSBzaW5nbGUgYGFsbFNldHRsZWRgIHNuYXBzaG90cyB0aGUgYXJyYXkgYW5kXG4gICAgLy8gbGV0cyBMYW1iZGEgZnJlZXplIG9uIHRoYXQgbGF0ZSB3b3JrLlxuICAgIGxldCBzZXR0bGVkQ291bnQgPSAwO1xuICAgIHdoaWxlIChzZXR0bGVkQ291bnQgPCBwZW5kaW5nLmxlbmd0aCkge1xuICAgICAgY29uc3QgYmF0Y2ggPSBwZW5kaW5nLnNsaWNlKHNldHRsZWRDb3VudCk7XG4gICAgICBzZXR0bGVkQ291bnQgPSBwZW5kaW5nLmxlbmd0aDtcbiAgICAgIGNvbnN0IHNldHRsZWQgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoYmF0Y2gpO1xuICAgICAgZm9yIChjb25zdCByZXN1bHQgb2Ygc2V0dGxlZCkge1xuICAgICAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gXCJyZWplY3RlZFwiKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkEgd2FpdFVudGlsKCkgcHJvbWlzZSByZWplY3RlZDpcIiwgcmVzdWx0LnJlYXNvbik7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJvdXRlKFxuICAgIHJlcTogU2hpbUluY29taW5nTWVzc2FnZSxcbiAgICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgICB1cmw6IFVSTCxcbiAgICBib2R5OiBTcGxpdEJvZHksXG4gICAgd2FpdFVudGlsOiAocHJvbWlzZTogUHJvbWlzZTx1bmtub3duPikgPT4gdm9pZCxcbiAgICByZXF1ZXN0OiBSdW50aW1lUmVxdWVzdCxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5kaXNwYXRjaGVyLmRpc3BhdGNoKHtcbiAgICAgIG1ldGhvZDogcmVxLm1ldGhvZCA/PyBcIkdFVFwiLFxuICAgICAgdXJsLFxuICAgICAgaGVhZGVyczogbmV3IEhlYWRlcnModG9XZWJIZWFkZXJzKHJlcS5oZWFkZXJzKSksXG4gICAgICBib2R5OiBib2R5LmZvckRpc3BhdGNoLFxuICAgICAgaW52b2tlTWlkZGxld2FyZTogdGhpcy5taWRkbGV3YXJlPy5pbnZva2VyRm9yKHtcbiAgICAgICAgd2FpdFVudGlsLFxuICAgICAgICBzaWduYWw6IHJlcXVlc3Quc2lnbmFsLFxuICAgICAgfSksXG4gICAgfSk7XG4gICAgYm9keS5yZWxlYXNlVW5yZWFkKHJlc3VsdC5raW5kID09PSBcIm1pZGRsZXdhcmUtcmVzcG9uZGVkXCIpO1xuXG4gICAgYXBwbHlIZWFkZXJzKHJlcywgcmVzdWx0LnJlc3BvbnNlSGVhZGVycyk7XG4gICAgaWYgKHJlc3VsdC5zdGF0dXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmVzLnN0YXR1c0NvZGUgPSByZXN1bHQuc3RhdHVzO1xuICAgIH1cblxuICAgIHN3aXRjaCAocmVzdWx0LmtpbmQpIHtcbiAgICAgIGNhc2UgXCJlbnRyeXBvaW50XCI6IHtcbiAgICAgICAgbGV0IGhhbmRsZXI6IEVudHJ5cG9pbnRIYW5kbGVyO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGhhbmRsZXIgPSBhd2FpdCB0aGlzLmVudHJ5cG9pbnRzLmxvYWQocmVzdWx0LmVudHJ5cG9pbnQpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGlmICghKGVycm9yIGluc3RhbmNlb2YgUm91dGVJbk90aGVyR3JvdXBFcnJvcikpIHRocm93IGVycm9yO1xuICAgICAgICAgIC8vIEEgVVJMIHRoZSBlZGdlIHNlbnQgaGVyZSBvbmx5IGJlY2F1c2Ugb2YgaXRzIGNhc2UgZ29lcyB0byBpdHNcbiAgICAgICAgICAvLyBjYW5vbmljYWwgc3BlbGxpbmcsIHdoaWNoIHRoZSBlZGdlIHJvdXRlcyB0byB0aGUgb3duaW5nIGdyb3VwLlxuICAgICAgICAgIGNvbnN0IGNhbm9uaWNhbCA9IGNhc2VDYW5vbmljYWxQYXRoKFxuICAgICAgICAgICAgdXJsLnBhdGhuYW1lLFxuICAgICAgICAgICAgcmVzdWx0LnJlc29sdmVkUGF0aG5hbWUsXG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMubWFuaWZlc3QsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoY2Fub25pY2FsKSB7XG4gICAgICAgICAgICBzZW5kUmVkaXJlY3QocmVzLCBgJHtjYW5vbmljYWx9JHt1cmwuc2VhcmNofWAsIDMwOCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChyZXF1ZXN0Lm9uUm91dGVJbk90aGVyR3JvdXApIHtcbiAgICAgICAgICAgIC8vIEV4cGxhaW5lZCBieSB0aGUgY2FsbGVyIG9mIGBoYW5kbGVJbnRlcm5hbGx5YCwgd2hpY2gga25vd3Mgd2h5IGl0XG4gICAgICAgICAgICAvLyBoYXBwZW5lZC5cbiAgICAgICAgICAgIHJlcXVlc3Qub25Sb3V0ZUluT3RoZXJHcm91cChlcnJvcik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIExvZ2dlZCwgYmVjYXVzZSBpdCBpcyBhbHNvIHdoYXQgYSBtaXNyb3V0ZWQgZ3JvdXAgbG9va3MgbGlrZTsgc2VlXG4gICAgICAgICAgICAvLyBgUm91dGVJbk90aGVyR3JvdXBFcnJvcmAgZm9yIHdoeSBpdCBpcyBhIDQwNC5cbiAgICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvci5tZXNzYWdlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgdGhpcy5zZW5kVW5tYXRjaGVkKFxuICAgICAgICAgICAgcmVxLFxuICAgICAgICAgICAgcmVzLFxuICAgICAgICAgICAgd2FpdFVudGlsLFxuICAgICAgICAgICAgeyBwYXRobmFtZTogdXJsLnBhdGhuYW1lLCByZXF1ZXN0SGVhZGVyczogcmVzdWx0LnJlcXVlc3RIZWFkZXJzIH0sXG4gICAgICAgICAgICB1cmwsXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gVGhlIGludm9jYXRpb24gdGFyZ2V0LCBub3QgdGhlIHJlcXVlc3RlZCBVUkw6IGByZXNvbHZlUm91dGVzYCBoYXNcbiAgICAgICAgLy8gYXBwbGllZCByZXdyaXRlcywgc3RyaXBwZWQgaTE4biBwcmVmaXhlcywgYW5kIGFwcGVuZGVkIHRoZSBgbnh0UGBcbiAgICAgICAgLy8gcm91dGUgcGFyYW1zIGFzIHF1ZXJ5IHZhbHVlcy4gVGhhdCBpcyBleGFjdGx5IHRoZSBjb250cmFjdCBOZXh0LmpzXG4gICAgICAgIC8vIGRvY3VtZW50cyBmb3IgYSBwcm94eSBpbiBmcm9udCBvZiBhIGZ1bmN0aW9uIOKAlCBgUm91dGVNb2R1bGUucHJlcGFyZWBcbiAgICAgICAgLy8gcmVjb3ZlcnMgYHBhcmFtc2AgZnJvbSB0aGVzZSBxdWVyeSB2YWx1ZXMg4oCUIHNvIHRoYXQgY29udHJhY3QsIG5vdFxuICAgICAgICAvLyBgcmVxdWVzdE1ldGEucGFyYW1zYCwgaXMgaG93IHBhcmFtcyBnZXQgcGFzc2VkLiBUaGUgb25lIGV4Y2VwdGlvbiBpc1xuICAgICAgICAvLyBhIGNhcHR1cmUgdGhlIGNvbnRyYWN0IHdvdWxkIGNvcnJ1cHQ7IHNlZSBgb3V0T2ZCYW5kUm91dGVQYXJhbXNgLlxuICAgICAgICBjb25zdCBvdXRPZkJhbmQgPSBvdXRPZkJhbmRSb3V0ZVBhcmFtcyhcbiAgICAgICAgICByZXN1bHQuaW52b2NhdGlvblRhcmdldC5xdWVyeSxcbiAgICAgICAgICByZXN1bHQucmVzb2x2ZWRQYXRobmFtZSxcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgaW52b2NhdGlvblF1ZXJ5ID1cbiAgICAgICAgICBvdXRPZkJhbmQ/LnF1ZXJ5ID8/IHJlc3VsdC5pbnZvY2F0aW9uVGFyZ2V0LnF1ZXJ5O1xuICAgICAgICBjb25zdCB7IHBhdGhuYW1lIH0gPSByZXN1bHQuaW52b2NhdGlvblRhcmdldDtcbiAgICAgICAgY29uc3Qgc2VhcmNoID0gdG9TZWFyY2goaW52b2NhdGlvblF1ZXJ5KTtcbiAgICAgICAgcmVxLnVybCA9IHNlYXJjaCA/IGAke3BhdGhuYW1lfT8ke3NlYXJjaH1gIDogcGF0aG5hbWU7XG4gICAgICAgIC8vIE1pZGRsZXdhcmUgbWF5IGhhdmUgcmV3cml0dGVuIHJlcXVlc3QgaGVhZGVycyB2aWFcbiAgICAgICAgLy8gYE5leHRSZXNwb25zZS5uZXh0KHsgcmVxdWVzdDogeyBoZWFkZXJzIH0gfSlgLlxuICAgICAgICByZXEuaGVhZGVycyA9IHRvSW5jb21pbmdIdHRwSGVhZGVycyhyZXN1bHQucmVxdWVzdEhlYWRlcnMpO1xuICAgICAgICBhd2FpdCBoYW5kbGVyKHJlcSwgYXNTZXJ2ZXJSZXNwb25zZShyZXMpLCB7XG4gICAgICAgICAgd2FpdFVudGlsLFxuICAgICAgICAgIHJlcXVlc3RNZXRhOiB7XG4gICAgICAgICAgICAvLyBUaGUgcmVzb2x2ZWQgcXVlcnksIHN0YXRlZCByYXRoZXIgdGhhbiBsZWZ0IHRvIGJlIHJlLWRlcml2ZWQuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gYFJvdXRlTW9kdWxlLnByZXBhcmVgIHJ1bnMgYGhhbmRsZVJld3JpdGVzYCBhZ2FpbnN0IGByZXEudXJsYFxuICAgICAgICAgICAgLy8gdW5jb25kaXRpb25hbGx5LCBhbmQgYHJlcS51cmxgIGlzIHRoZSAqYWxyZWFkeSByZXdyaXR0ZW4qIHRhcmdldC5cbiAgICAgICAgICAgIC8vIEEgYGJlZm9yZUZpbGVzYCByZXdyaXRlIHdob3NlIGNvbmRpdGlvbiBzdGlsbCBob2xkcyBhZnRlciBpdCBoYXNcbiAgICAgICAgICAgIC8vIGJlZW4gYXBwbGllZCB0aGVyZWZvcmUgZ2V0cyBhcHBsaWVkIHR3aWNlOiBpblxuICAgICAgICAgICAgLy8gYHRlc3QvZTJlL2xpbmstd2l0aC1hcGktcmV3cml0ZWAgdGhlIHJ1bGVcbiAgICAgICAgICAgIC8vIGAvOnBhdGgoLiopYCArIGBoYXM6IHF1ZXJ5IGpzb249dHJ1ZWAgLT4gYC9hcGkvanNvbj9mcm9tPS86cGF0aGBcbiAgICAgICAgICAgIC8vIG1hdGNoZWQgYC9hcGkvanNvbj9qc29uPXRydWUmZnJvbT0vc29tZS9yb3V0ZS9mb3JgIGEgc2Vjb25kIHRpbWVcbiAgICAgICAgICAgIC8vIGFuZCBvdmVyd3JvdGUgYGZyb21gIHdpdGggYC9hcGkvanNvbmAuIGBuZXh0IHN0YXJ0YCBlc2NhcGVzIGl0XG4gICAgICAgICAgICAvLyBiZWNhdXNlIGl0cyByb3V0ZXIgbGVhdmVzIGByZXEudXJsYCBhcyB0aGUgVVJMIHRoZSBjbGllbnQgc2VudCwgc29cbiAgICAgICAgICAgIC8vIHRoZSBvbmUgcGFzcyBgcHJlcGFyZWAgbWFrZXMgaXMgdGhlIG9ubHkgb25lLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIGBwcmVwYXJlYCBwcmVmZXJzIHRoaXMgbWV0YSBvdmVyIGl0cyBvd24gYHBhcnNlZFVybC5xdWVyeWBcbiAgICAgICAgICAgIC8vIChcIndoZW4gZGVwbG95ZWQgcHJveGllcyB3aWxsIGFkZCBxdWVyeSB2YWx1ZXMgZnJvbSByZXNvbHZpbmcgdGhlXG4gICAgICAgICAgICAvLyByb3V0ZXMgdG8gcGFzcyB0byBmdW5jdGlvblwiKSwgd2hpY2ggaXMgdGhlIGRvY3VtZW50ZWQgZGl2aXNpb24gb2ZcbiAgICAgICAgICAgIC8vIGxhYm91ciBmb3IgYSBwcm94eSBpbiBmcm9udCBvZiBhIGZ1bmN0aW9uIC0gYW5kIGl0IGlzIHRoZSBzYW1lXG4gICAgICAgICAgICAvLyBkaXZpc2lvbiB0aGUgYHJlcS51cmxgIGFib3ZlIHJlbGllcyBvbi4gU2V0dGluZyBpdCBkb2VzIG5vdCBzdG9wXG4gICAgICAgICAgICAvLyB0aGUgc2Vjb25kIHJld3JpdGUgcGFzcywgaXQganVzdCBzdG9wcyB0aGF0IHBhc3MgZnJvbSBiZWluZyB3aGF0XG4gICAgICAgICAgICAvLyB0aGUgcm91dGUgc2Vlcy5cbiAgICAgICAgICAgIHF1ZXJ5OiB7IC4uLmludm9jYXRpb25RdWVyeSB9LFxuICAgICAgICAgICAgLy8gU2V0IG9ubHkgZm9yIGEgY2FwdHVyZSB0aGUgcXVlcnkgY29udHJhY3QgY2Fubm90IGNhcnJ5LCBhbmQgdGhlblxuICAgICAgICAgICAgLy8gaW4gcGxhY2Ugb2YgaXQgcmF0aGVyIHRoYW4gYWxvbmdzaWRlLlxuICAgICAgICAgICAgLi4uKG91dE9mQmFuZCA/IHsgcGFyYW1zOiBvdXRPZkJhbmQucGFyYW1zIH0gOiB7fSksXG4gICAgICAgICAgICAvLyBXaXRob3V0IHRoaXMsIGBSb3V0ZU1vZHVsZS5wcmVwYXJlYCBmYWxscyBiYWNrIHRvXG4gICAgICAgICAgICAvLyBgaHR0cDovL2xvY2FsaG9zdCR7cmVxLnVybH1gIGFuZCBldmVyeSBhYnNvbHV0ZSBVUkwgYSByb3V0ZVxuICAgICAgICAgICAgLy8gaGFuZGxlciBidWlsZHMgaXMgd3JvbmcuIGByZWxhdGl2ZVByb2plY3REaXJgIGlzIGRlbGliZXJhdGVseVxuICAgICAgICAgICAgLy8gKm5vdCogcGFzc2VkOiB0aGUgcnVudGltZSBgY2hkaXJgcyB0byB0aGUgcHJvamVjdCBkaXIsIHNvIHRoZVxuICAgICAgICAgICAgLy8gdmFsdWUgTmV4dC5qcyBpbmxpbmVkIGF0IGJ1aWxkIHRpbWUgKFwiXCIpIGlzIGFscmVhZHkgY29ycmVjdCwgYW5kXG4gICAgICAgICAgICAvLyBgYXBwLXBhZ2UtcnVudGltZS5qc2AgaWdub3JlcyB0aGUgcmVxdWVzdE1ldGEgb3ZlcnJpZGUgYW55d2F5LlxuICAgICAgICAgICAgaW5pdFVSTDogdXJsLmhyZWYsXG4gICAgICAgICAgICAvLyBGZWVkcyBgcm91dGVyU2VydmVyQ29udGV4dC5ob3N0bmFtZWAgKGByb3V0ZS1tb2R1bGUuanNgXG4gICAgICAgICAgICAvLyBgZ2V0Um91dGVyU2VydmVyQ29udGV4dGApLiBJbmNsdWRlcyB0aGUgcG9ydCwgYmVjYXVzZSBpdCBpc1xuICAgICAgICAgICAgLy8gY29uY2F0ZW5hdGVkIGludG8gYWJzb2x1dGUgVVJMcy5cbiAgICAgICAgICAgIGhvc3RuYW1lOiB1cmwuaG9zdCxcbiAgICAgICAgICAgIC8vIEJvdGggcm91dGVycyBjYWxsIHRoaXMgZm9yIGEgYG5vdEZvdW5kOiB0cnVlYCAvIGBub3RGb3VuZCgpYCB0aGF0XG4gICAgICAgICAgICAvLyB0aGUgZW50cnlwb2ludCBpdHNlbGYgY2Fubm90IHJlbmRlciwgYW5kIGZhbGwgYmFjayB0b1xuICAgICAgICAgICAgLy8gYHJlcy5lbmQoJ1RoaXMgcGFnZSBjb3VsZCBub3QgYmUgZm91bmQnKWAg4oCUIG5vIHN0YXR1cywgbm8gYXBwIDQwNFxuICAgICAgICAgICAgLy8gcGFnZSDigJQgd2hlbiBpdCBpcyBhYnNlbnQuIFRoZSBgcmVxYC9gcmVzYCB0aGV5IHBhc3MgYXJlIHRoZSBvbmVzXG4gICAgICAgICAgICAvLyBoYW5kZWQgaW4ganVzdCBhYm92ZSwgc28gdGhlIGNhcHR1cmVkIHBhaXIgaXMgdXNlZCBpbnN0ZWFkIG9mXG4gICAgICAgICAgICAvLyByZS1kZXJpdmluZyB0aGVtLlxuICAgICAgICAgICAgcmVuZGVyNDA0OiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgIGF3YWl0IHRoaXMuc2VuZE5vdEZvdW5kKFxuICAgICAgICAgICAgICAgIHJlcSxcbiAgICAgICAgICAgICAgICByZXMsXG4gICAgICAgICAgICAgICAgd2FpdFVudGlsLFxuICAgICAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hlci5ub3RGb3VuZEZvcih1cmwpLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIC8vIGByZXMucmV2YWxpZGF0ZSgpYCBmcm9tIGEgUGFnZXMgQVBJIHJvdXRlLiBXaXRob3V0IGl0LCBOZXh0LmpzXG4gICAgICAgICAgICAvLyBmYWxscyBiYWNrIHRvIGBmZXRjaCgnaHR0cHM6Ly8nICsgcmVxLmhlYWRlcnMuaG9zdCArIHVybFBhdGgpYCDigJRcbiAgICAgICAgICAgIC8vIGFuZCBvbmx5IHdoZW4gYGV4cGVyaW1lbnRhbC50cnVzdEhvc3RIZWFkZXJgIGlzIHNldCwgd2hpY2ggaXQgaXNcbiAgICAgICAgICAgIC8vIG5vdCwgc28gYHJlcy5yZXZhbGlkYXRlKClgIHRocmV3XG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gICBGYWlsZWQgdG8gcmV2YWxpZGF0ZSAvOiBJbnZhcmlhbnQ6IG1pc3NpbmcgaW50ZXJuYWxcbiAgICAgICAgICAgIC8vICAgcm91dGVyLXNlcnZlci1tZXRob2RzIHRoaXMgaXMgYW4gaW50ZXJuYWwgYnVnXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gYW5kIGB0ZXN0L2UyZS9yZXZhbGlkYXRlLXJlYXNvbmAgc2F3IGBzdGFsZWAgd2hlcmUgYG5leHQgc3RhcnRgXG4gICAgICAgICAgICAvLyByZXBvcnRzIGBvbi1kZW1hbmRgOiB0aGUgcm91dGUgc3RpbGwgcmUtcmVuZGVyZWQsIGp1c3QgYXMgYW5cbiAgICAgICAgICAgIC8vIG9yZGluYXJ5IHN0YWxlIHJlZ2VuZXJhdGlvbiByYXRoZXIgdGhhbiB0aGUgb24tZGVtYW5kIG9uZSBpdFxuICAgICAgICAgICAgLy8gYXNrZWQgZm9yLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIEFuc3dlcmluZyBpdCBpbiBwcm9jZXNzIHJhdGhlciB0aGFuIGJ5IHNldHRpbmdcbiAgICAgICAgICAgIC8vIGB0cnVzdEhvc3RIZWFkZXJgOiB0aGUgZmV0Y2ggcGF0aCB3b3VsZCBsZWF2ZSB0aGUgZnVuY3Rpb24sIGNyb3NzXG4gICAgICAgICAgICAvLyBDbG91ZEZyb250IGFuZCBjb21lIGJhY2sg4oCUIGEgc2Vjb25kIGJpbGxlZCBpbnZvY2F0aW9uLCBhXG4gICAgICAgICAgICAvLyBkZXBlbmRlbmN5IG9uIGB4LXByZXJlbmRlci1yZXZhbGlkYXRlYCBzdXJ2aXZpbmcgdGhlIGVkZ2UsIGFuZCBhXG4gICAgICAgICAgICAvLyByZWFzb24gdG8gdHJ1c3QgYSBjbGllbnQtc3VwcGxpZWQgYEhvc3RgLiBOZXh0LmpzJ3Mgb3duXG4gICAgICAgICAgICAvLyBub24tc2VydmVybGVzcyBhbnN3ZXIgaXMgdGhlIHNhbWUgc2hhcGUgYXMgdGhpcyBvbmVcbiAgICAgICAgICAgIC8vIChgTmV4dFNlcnZlciNyZXZhbGlkYXRlYCBydW5zIGl0cyByZXF1ZXN0IGhhbmRsZXIgYWdhaW5zdCBhXG4gICAgICAgICAgICAvLyBtb2NrZWQgYHJlcWAvYHJlc2ApLlxuICAgICAgICAgICAgcmV2YWxpZGF0ZTogKGNvbmZpZzogUmV2YWxpZGF0ZUNvbmZpZykgPT5cbiAgICAgICAgICAgICAgdGhpcy5yZXZhbGlkYXRlKGNvbmZpZywgcmVxdWVzdCksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIEEgUGFnZXMgQVBJIHJvdXRlIG93bnMgdGhlIGVuZCBvZiBpdHMgcmVzcG9uc2U6IGBzdHJlYW0ucGlwZShyZXMpYCxcbiAgICAgICAgLy8gYW4gYGV4dGVybmFsUmVzb2x2ZXJgIHByb3h5LCBvciBhIGNhbGxiYWNrIHRoYXQgY2FsbHMgYHJlcy5qc29uKClgXG4gICAgICAgIC8vIGxhdGVyIGFsbCByZXR1cm4gZnJvbSB0aGUgaGFuZGxlciBiZWZvcmUgdGhleSBhcmUgZG9uZSB3cml0aW5nLCBhbmRcbiAgICAgICAgLy8gZW5kaW5nIGhlcmUgc2VudCBhbiBlbXB0eSAyMDAgYW5kIG1hZGUgdGhlaXIgd3JpdGVzIHRocm93XG4gICAgICAgIC8vIGBFUlJfU1RSRUFNX1dSSVRFX0FGVEVSX0VORGAuIGBuZXh0IHN0YXJ0YCdzIGBhcGlSZXNvbHZlcmAgbGVhdmVzIGl0XG4gICAgICAgIC8vIG9wZW4gdG9vIOKAlCBvbmUgdGhhdCBuZXZlciBlbmRzIHN0YWxscywgdGhlcmUgYXMgaGVyZS4gYGhhbmRsZWAgYXdhaXRzXG4gICAgICAgIC8vIHRoZSByZXNwb25zZSBpdHNlbGYsIHNvIG5vdGhpbmcgaXMgY3V0IHNob3J0IGJ5IHJldHVybmluZy5cbiAgICAgICAgaWYgKCFyZXMud3JpdGFibGVFbmRlZCAmJiByZXN1bHQuZW50cnlwb2ludC50eXBlICE9PSBcInBhZ2UtYXBpXCIpIHtcbiAgICAgICAgICByZXMuZW5kKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjYXNlIFwic3RhdGljLWZpbGVcIjoge1xuICAgICAgICBjb25zdCBzdGF0dXNQYWdlID1cbiAgICAgICAgICByZXN1bHQuc291cmNlID09PSBcInNlcnZlclwiXG4gICAgICAgICAgICA/IHRoaXMuc3RhdHVzUGFnZVN0YXR1cyhyZXN1bHQucGF0aG5hbWUpXG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgICAgLy8gYG5leHQgc3RhcnRgIHNlcnZlcyBhIGBwdWJsaWMvYCBvciBgX25leHQvc3RhdGljYCBmaWxlIHRvIEdFVCBhbmRcbiAgICAgICAgLy8gSEVBRCBvbmx5LCBhbmQgYHNlbmRgIHdvdWxkIHNlcnZlIGl0IHRvIGFueSBtZXRob2QuIFRoZSBzYW1lIGdvZXMgZm9yXG4gICAgICAgIC8vIGFuIGF1dG8tZXhwb3J0ZWQgUGFnZXMgUm91dGVyIHBhZ2UgKGBiYXNlLXNlcnZlci5qc2BcbiAgICAgICAgLy8gYHJlbmRlclRvUmVzcG9uc2VXaXRoQ29tcG9uZW50c0ltcGxgOiBhIHN0cmluZyBgQ29tcG9uZW50YCBhbnN3ZXJzXG4gICAgICAgIC8vIGFueXRoaW5nIGVsc2Ugd2l0aCBhIDQwNSksIGV4Y2VwdCB0aGUgNDA0IGFuZCA1MDAgcGFnZXMuXG4gICAgICAgIGlmIChcbiAgICAgICAgICByZXEubWV0aG9kICE9PSBcIkdFVFwiICYmXG4gICAgICAgICAgcmVxLm1ldGhvZCAhPT0gXCJIRUFEXCIgJiZcbiAgICAgICAgICAocmVzdWx0LnNvdXJjZSAhPT0gXCJzZXJ2ZXJcIiB8fFxuICAgICAgICAgICAgKHN0YXR1c1BhZ2UgPT09IHVuZGVmaW5lZCAmJiByZXN1bHQuZmlsZVBhdGguZW5kc1dpdGgoXCIuaHRtbFwiKSkpXG4gICAgICAgICkge1xuICAgICAgICAgIHNlbmRNZXRob2ROb3RBbGxvd2VkKHJlcyk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIFwiZW5zdXJlIGNvcnJlY3Qgc3RhdHVzIGlzIHNldCB3aGVuIHZpc2l0aW5nIGEgc3RhdHVzIHBhZ2UgZGlyZWN0bHlcIjpcbiAgICAgICAgLy8gYG5leHQgc3RhcnRgIGFuc3dlcnMgYC80MDRgIHdpdGggYSA0MDQgYW5kIGAvNTAwYCB3aXRoIGEgNTAwLCBub3QgdGhlXG4gICAgICAgIC8vIDIwMCB0aGVpciBwcmVyZW5kZXJlZCBIVE1MIHdvdWxkIG90aGVyd2lzZSBnbyBvdXQgd2l0aC5cbiAgICAgICAgaWYgKHN0YXR1c1BhZ2UgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJlcy5zdGF0dXNDb2RlID0gc3RhdHVzUGFnZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBldGFnID0gdGhpcy5vcHRpb25zLm1hbmlmZXN0LmNvbmZpZy5nZW5lcmF0ZUV0YWdzO1xuICAgICAgICBjb25zdCBwdWJsaWNEaXIgPSBgJHtwdWJsaWNEaXJLZXkodGhpcy5vcHRpb25zLm1hbmlmZXN0KX0vYDtcbiAgICAgICAgY29uc3Qgc2VydmVkID1cbiAgICAgICAgICAoYXdhaXQgc2VydmVTdGF0aWNGaWxlKFxuICAgICAgICAgICAgcmVxLFxuICAgICAgICAgICAgcmVzLFxuICAgICAgICAgICAgdGhpcy5vcHRpb25zLmRlcGxveW1lbnRSb290LFxuICAgICAgICAgICAgcmVzdWx0LmZpbGVQYXRoLFxuICAgICAgICAgICAgeyBldGFnIH0sXG4gICAgICAgICAgKSkgfHxcbiAgICAgICAgICAvLyBMaXN0ZWQgYnV0IG5vdCBzdGFnZWQ6IGEgTGFtYmRhIHJvb3QsIHdob3NlIGBwdWJsaWMvYCBpcyBpbiBTMy5cbiAgICAgICAgICAocmVzdWx0LnNvdXJjZSA9PT0gXCJwdWJsaWNcIiAmJlxuICAgICAgICAgICAgISF0aGlzLnB1YmxpY0J1Y2tldCAmJlxuICAgICAgICAgICAgKGF3YWl0IHNlcnZlUzNQdWJsaWNGaWxlKHJlcSwgcmVzLCB7XG4gICAgICAgICAgICAgIGJ1Y2tldDogdGhpcy5wdWJsaWNCdWNrZXQsXG4gICAgICAgICAgICAgIGtleVByZWZpeDogdGhpcy5vcHRpb25zLmJ1Y2tldEtleVByZWZpeCA/PyBcIlwiLFxuICAgICAgICAgICAgICBmaWxlOiByZXN1bHQuZmlsZVBhdGguc2xpY2UocHVibGljRGlyLmxlbmd0aCksXG4gICAgICAgICAgICAgIGV0YWcsXG4gICAgICAgICAgICB9KSkpO1xuICAgICAgICBpZiAoIXNlcnZlZCkge1xuICAgICAgICAgIC8vIFRoZSByb3V0aW5nIHJ1bGUgdGhhdCBtYXRjaGVkIGEgYnVpbGQgYXNzZXQgYWxyZWFkeSBzZXQgaXRzXG4gICAgICAgICAgLy8geWVhci1sb25nIGBpbW11dGFibGVgIENhY2hlLUNvbnRyb2wsIHdoaWNoIGBzZW5kVW5tYXRjaGVkYFxuICAgICAgICAgIC8vIHJlcGxhY2VzOiB1bmRlciBpdCB0aGUgNDA0IHdvdWxkIGJlIGNhY2hlZCBhdCB0aGUgZWRnZSBhbmQgaW5cbiAgICAgICAgICAvLyBicm93c2VycyBmb3IgdGhhdCBsb25nLCBhbmQgYSBjaHVuayB0aGF0IHNob3dzIHVwIG9uIHRoZSBuZXh0XG4gICAgICAgICAgLy8gZGVwbG95IHdvdWxkIHN0YXkgbWlzc2luZy5cbiAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRVbm1hdGNoZWQocmVxLCByZXMsIHdhaXRVbnRpbCwgcmVzdWx0LCB1cmwpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY2FzZSBcImltYWdlLW9wdGltaXphdGlvblwiOlxuICAgICAgICBpZiAoIXRoaXMuaW1hZ2VzLmlzRW5hYmxlZCgpKSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5zZW5kVW5tYXRjaGVkKFxuICAgICAgICAgICAgcmVxLFxuICAgICAgICAgICAgcmVzLFxuICAgICAgICAgICAgd2FpdFVudGlsLFxuICAgICAgICAgICAgeyBwYXRobmFtZTogdXJsLnBhdGhuYW1lLCByZXF1ZXN0SGVhZGVyczogcmVzdWx0LnJlcXVlc3RIZWFkZXJzIH0sXG4gICAgICAgICAgICB1cmwsXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgcmVxLmhlYWRlcnMgPSB0b0luY29taW5nSHR0cEhlYWRlcnMocmVzdWx0LnJlcXVlc3RIZWFkZXJzKTtcbiAgICAgICAgYXdhaXQgdGhpcy5pbWFnZXMuaGFuZGxlKHJlcSwgcmVzLCByZXN1bHQudXJsLCB3YWl0VW50aWwpO1xuICAgICAgICByZXR1cm47XG5cbiAgICAgIGNhc2UgXCJyZWRpcmVjdFwiOlxuICAgICAgICBzZW5kUmVkaXJlY3QocmVzLCByZXN1bHQubG9jYXRpb24sIHJlc3VsdC5zdGF0dXMpO1xuICAgICAgICByZXR1cm47XG5cbiAgICAgIGNhc2UgXCJleHRlcm5hbC1yZXdyaXRlXCI6XG4gICAgICAgIGF3YWl0IHByb3h5RXh0ZXJuYWwocmVxLCByZXMsIHJlc3VsdC51cmwsIHJlc3VsdC5yZXF1ZXN0SGVhZGVycyk7XG4gICAgICAgIHJldHVybjtcblxuICAgICAgY2FzZSBcIm1pZGRsZXdhcmUtcmVzcG9uZGVkXCI6XG4gICAgICAgIGF3YWl0IHNlbmRXZWJSZXNwb25zZShyZXMsIHJlc3VsdC5yZXNwb25zZSk7XG4gICAgICAgIHJldHVybjtcblxuICAgICAgY2FzZSBcInJlc3BvbnNlXCI6XG4gICAgICAgIHJlcy5lbmQoKTtcbiAgICAgICAgcmV0dXJuO1xuXG4gICAgICBjYXNlIFwibm90LWZvdW5kXCI6XG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZFVubWF0Y2hlZChyZXEsIHJlcywgd2FpdFVudGlsLCByZXN1bHQsIHVybCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogNDA0IG9yIDUwMCB3aGVuIGBwYXRobmFtZWAgaXMgdGhlIHByZXJlbmRlcmVkIGAvNDA0YCBvciBgLzUwMGAgcGFnZSDigJQgdW5kZXJcbiAgICogYGJhc2VQYXRoYCBhbmQsIGluIGFuIGkxOG4gYXBwLCBhbnkgbG9jYWxlIChgL2ZyLzQwNGApIOKAlCBhbmQgYHVuZGVmaW5lZGBcbiAgICogb3RoZXJ3aXNlLiBgbmV4dCBzdGFydGAgbWF0Y2hlcyB0aGUgcGFnZSwgbm90IHRoZSBVUkwsIHNvIHRoZSBsb2NhbGUgZG9lc1xuICAgKiBub3QgbWF0dGVyLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0dXNQYWdlU3RhdHVzKHBhdGhuYW1lOiBzdHJpbmcpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHsgYmFzZVBhdGgsIGkxOG4gfSA9IHRoaXMub3B0aW9ucy5tYW5pZmVzdC5jb25maWc7XG4gICAgbGV0IHBhZ2UgPSB3aXRob3V0UGF0aFByZWZpeChwYXRobmFtZSwgYmFzZVBhdGgpO1xuICAgIGNvbnN0IGxvY2FsZXMgPSAoaTE4biBhcyB7IGxvY2FsZXM/OiByZWFkb25seSBzdHJpbmdbXSB9IHwgbnVsbCk/LmxvY2FsZXM7XG4gICAgZm9yIChjb25zdCBsb2NhbGUgb2YgbG9jYWxlcyA/PyBbXSkge1xuICAgICAgY29uc3Qgc3RyaXBwZWQgPSB3aXRob3V0UGF0aFByZWZpeChwYWdlLCBgLyR7bG9jYWxlfWApO1xuICAgICAgaWYgKHN0cmlwcGVkICE9PSBwYWdlKSB7XG4gICAgICAgIHBhZ2UgPSBzdHJpcHBlZDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChwYWdlID09PSBcIi80MDRcIikgcmV0dXJuIDQwNDtcbiAgICBpZiAocGFnZSA9PT0gXCIvNTAwXCIpIHJldHVybiA1MDA7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBgbmV4dCBzdGFydGAncyBhbnN3ZXIgdG8gYSBwYXRoIG5vdGhpbmcgc2VydmVzIChgcm91dGVyLXNlcnZlci5qc2AsIHRoZVxuICAgKiBcIjQwNCBjYXNlXCIpLCBmb3IgYm90aCB3YXlzIG9mIGdldHRpbmcgaGVyZTogZGlzcGF0Y2ggbWF0Y2hlZCBub3RoaW5nLCBvciBpdFxuICAgKiBtYXRjaGVkIGEgYnVpbGQgYXNzZXQgdGhhdCBpcyBub3QgaW4gdGhlIHBhY2thZ2UuXG4gICAqXG4gICAqIE5vLXN0b3JlLCBhbHdheXMuIEEgcHJlcmVuZGVyZWQgYC9fbm90LWZvdW5kYCB3b3VsZCBvdGhlcndpc2Ugc2VuZCBpdHNcbiAgICogY2FjaGUgZW50cnkncyB5ZWFyLWxvbmcgYHMtbWF4YWdlYCwgYW5kIHRoZSBDRE4gd291bGQga2VlcCB0aGUgNDA0IHBhc3QgdGhlXG4gICAqIGRlcGxveSB0aGF0IGFkZHMgdGhlIHJvdXRlLiBTZXQgcmF0aGVyIHRoYW4gZm9yY2VkOiBOZXh0J3MgcGFnZSBoYW5kbGVyc1xuICAgKiBvbmx5IHdyaXRlIGEgYENhY2hlLUNvbnRyb2xgIHdoZW4gbm9uZSBpcyBzZXQgKGBzZW5kUmVuZGVyUmVzdWx0YCxcbiAgICogYHBhZ2VzLWhhbmRsZXIuanNgKSwgd2hpY2ggaXMgZXhhY3RseSBob3cgYG5leHQgc3RhcnRgJ3Mgb3duIG5vLXN0b3JlIGhlcmVcbiAgICogc3Vydml2ZXMgdGhlIHJlbmRlci4gYHJlbmRlcjQwNGAgaXMgbm90IHRoaXMgcGF0aDogYSBgbm90Rm91bmQoKWAgZnJvbSBhblxuICAgKiBJU1IgcGFnZSBpcyBjYWNoZWFibGUgZm9yIHRoYXQgcGFnZSdzIHJldmFsaWRhdGUgcGVyaW9kLlxuICAgKlxuICAgKiBBIG1pc3NpbmcgYF9uZXh0L3N0YXRpY2AgZmlsZSwgYW5kIGEgR0VUIG9yIEhFQUQgd2hvc2UgYFNlYy1GZXRjaC1EZXN0YFxuICAgKiBzYXlzIGl0IGNhbm5vdCBkaXNwbGF5IEhUTUwgKGFuIGA8aW1nPmAsIGEgc2NyaXB0LCBhIGZvbnQpLCBnZXQgYVxuICAgKiBwbGFpbi10ZXh0IGBOb3QgRm91bmRgIGluc3RlYWQgb2YgdGhlIHJlbmRlcmVkIHBhZ2Ug4oCUIG5vdGhpbmcgd291bGQgc2hvd1xuICAgKiBpdCwgYW5kIHJlbmRlcmluZyBpdCBpcyB0aGUgZXhwZW5zaXZlIHBhcnQuXG4gICAqXG4gICAqIEV2ZXJ5dGhpbmcgZWxzZSByZW5kZXJzIHRoZSBhcHAncyA0MDQgYXMgdGhlIHBhdGggdGhhdCB3YXMgYXNrZWQgZm9yLCBub3RcbiAgICogYXMgYC9fbm90LWZvdW5kYDogdGhlIEFwcCBSb3V0ZXIgc2VyaWFsaXplcyB0aGUgY2Fub25pY2FsIFVSTCBpbnRvIHRoZSBSU0NcbiAgICogcGF5bG9hZCwgc28gYSBjbGllbnQgaHlkcmF0ZWQgb2ZmIGEgYC9fbm90LWZvdW5kYCBwYXlsb2FkIHJlcG9ydHMgdGhlIHdyb25nXG4gICAqIGB1c2VQYXRobmFtZSgpYCBhbmQgcHVzaGVzIHRoZSB3cm9uZyBoaXN0b3J5IGVudHJ5LiBJdCByZW5kZXJzIHdpdGggdGhlXG4gICAqIHJlcXVlc3QgaGVhZGVycyBtaWRkbGV3YXJlIHNldCwgdG9vIOKAlCBhIENTUCBub25jZSwgc2F5LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzZW5kVW5tYXRjaGVkKFxuICAgIHJlcTogU2hpbUluY29taW5nTWVzc2FnZSxcbiAgICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgICB3YWl0VW50aWw6IChwcm9taXNlOiBQcm9taXNlPHVua25vd24+KSA9PiB2b2lkLFxuICAgIHJlc3VsdDogeyByZWFkb25seSBwYXRobmFtZTogc3RyaW5nOyByZWFkb25seSByZXF1ZXN0SGVhZGVyczogSGVhZGVycyB9LFxuICAgIHVybDogVVJMLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXMuc2V0SGVhZGVyKFwiQ2FjaGUtQ29udHJvbFwiLCBOT19TVE9SRSk7XG4gICAgY29uc3QgeyBiYXNlUGF0aCwgYXNzZXRQcmVmaXggfSA9IHRoaXMub3B0aW9ucy5tYW5pZmVzdC5jb25maWc7XG4gICAgY29uc3QgcGF0aG5hbWUgPSB3aXRob3V0UGF0aFByZWZpeChcbiAgICAgIHdpdGhvdXRQYXRoUHJlZml4KHJlc3VsdC5wYXRobmFtZSwgYmFzZVBhdGgpLFxuICAgICAgYXNzZXRQcmVmaXgsXG4gICAgKTtcbiAgICBpZiAoXG4gICAgICBwYXRobmFtZS5zdGFydHNXaXRoKFwiL19uZXh0L3N0YXRpYy9cIikgfHxcbiAgICAgICgocmVxLm1ldGhvZCA9PT0gXCJHRVRcIiB8fCByZXEubWV0aG9kID09PSBcIkhFQURcIikgJiZcbiAgICAgICAgTk9OX0hUTUxfU0VDX0ZFVENIX0RFU1RTLmhhcyhcbiAgICAgICAgICBmaXJzdFZhbHVlKHJlcS5oZWFkZXJzW1wic2VjLWZldGNoLWRlc3RcIl0pID8/IFwiXCIsXG4gICAgICAgICkpXG4gICAgKSB7XG4gICAgICByZXMuc3RhdHVzQ29kZSA9IDQwNDtcbiAgICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgXCJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04XCIpO1xuICAgICAgcmVzLmVuZChcIk5vdCBGb3VuZFwiKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgcmVxLmhlYWRlcnMgPSB0b0luY29taW5nSHR0cEhlYWRlcnMocmVzdWx0LnJlcXVlc3RIZWFkZXJzKTtcbiAgICBhd2FpdCB0aGlzLnNlbmROb3RGb3VuZChcbiAgICAgIHJlcSxcbiAgICAgIHJlcyxcbiAgICAgIHdhaXRVbnRpbCxcbiAgICAgIHRoaXMuZGlzcGF0Y2hlci5ub3RGb3VuZEZvcih1cmwpLFxuICAgICAgYCR7cmVzdWx0LnBhdGhuYW1lfSR7dXJsLnNlYXJjaH1gLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogT25lIG9uLWRlbWFuZCByZXZhbGlkYXRpb24sIHJ1biBhZ2FpbnN0IHRoaXMgcnVudGltZSByYXRoZXIgdGhhbiBvdmVyIHRoZVxuICAgKiBuZXR3b3JrLiBXaXJlZCBpbiBhcyBgcmVxdWVzdE1ldGEucmV2YWxpZGF0ZWA7IHNlZSB0aGUgY29tbWVudCB0aGVyZS5cbiAgICpcbiAgICogVGhlIHJlc3BvbnNlIGlzIHRocm93biBhd2F5IOKAlCBvbmx5IGl0cyBzdGF0dXMgbWF0dGVycyDigJQgYnV0IGl0IGdvZXMgdGhyb3VnaFxuICAgKiB0aGUgZnVsbCB7QGxpbmsgaGFuZGxlfSwgc28gdGhlIGVudHJ5cG9pbnQgc2VlcyBhIHJlcXVlc3Qgd2l0aFxuICAgKiBgeC1wcmVyZW5kZXItcmV2YWxpZGF0ZWAgb24gaXQgYW5kIHdyaXRlcyB0aGUgZnJlc2ggZW50cnkgdGhyb3VnaCB0aGUgY2FjaGVcbiAgICogaGFuZGxlciBleGFjdGx5IGFzIGEgcmVxdWVzdCBmcm9tIG91dHNpZGUgd291bGQuIGBoYW5kbGVgIGF3YWl0cyBpdHMgb3duXG4gICAqIGB3YWl0VW50aWxgIHdvcmssIHNvIHRoZSBuZXcgZW50cnkgaXMgY29tbWl0dGVkIGJlZm9yZSBgcmVzLnJldmFsaWRhdGUoKWBcbiAgICogcmVzb2x2ZXMsIHdoaWNoIGlzIHdoYXQgY2FsbGVycyB0aGF0IHJldmFsaWRhdGUgYW5kIHRoZW4gcmVkaXJlY3QgZGVwZW5kIG9uLlxuICAgKlxuICAgKiBUaGUgYWNjZXB0L3Rocm93IHJ1bGUgaXMgYE5leHRTZXJ2ZXIjcmV2YWxpZGF0ZWAncywgdmVyYmF0aW06IGEgcmV2YWxpZGF0aW9uXG4gICAqIGlzIHN1Y2Nlc3NmdWwgaWYgaXQgd2FzIGNhY2hlZCBvciBhbnN3ZXJlZCAyMDAsIGFuZCBgbm90Rm91bmQ6IHRydWVgXG4gICAqIGxlZ2l0aW1hdGVseSBhbnN3ZXJzIDQwNCBmb3IgYW4gYHVuc3RhYmxlX29ubHlHZW5lcmF0ZWRgIGNhbGxlci4gQW55dGhpbmdcbiAgICogZWxzZSB0aHJvd3MsIGFuZCBgcmVzLnJldmFsaWRhdGUoKWAgdHVybnMgaXQgaW50byBgRmFpbGVkIHRvIHJldmFsaWRhdGVcbiAgICogPHBhdGg+OiA8bWVzc2FnZT5gLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXZhbGlkYXRlKFxuICAgIGNvbmZpZzogUmV2YWxpZGF0ZUNvbmZpZyxcbiAgICBvcmlnaW46IFJ1bnRpbWVSZXF1ZXN0LFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGhlYWQsIG90aGVyR3JvdXAgfSA9IGF3YWl0IHRoaXMuaGFuZGxlSW50ZXJuYWxseShcbiAgICAgIHtcbiAgICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgICB1cmw6IGNvbmZpZy51cmxQYXRoLFxuICAgICAgICAvLyBUaGUgY2FsbGVyJ3MgYXV0aG9yaXR5LCBub3QgdGhlIHJldmFsaWRhdGVkIHBhdGgnczogaXQgaXMgd2hhdFxuICAgICAgICAvLyBgYWJzb2x1dGVVcmxgIGJ1aWxkcyB0aGUgcmVxdWVzdCBVUkwgZnJvbSwgYW5kIGEgcmV2YWxpZGF0aW9uIGlzIGZvclxuICAgICAgICAvLyB0aGUgb3JpZ2luIGJlaW5nIHNlcnZlZC4gVGhlIGZvcndhcmRlZCBwYWlyIHdpdGggaXQg4oCUIGJlaGluZFxuICAgICAgICAvLyBDbG91ZEZyb250IGBob3N0YCBpcyB0aGUgRnVuY3Rpb24gVVJMLCBhbmQgYSByZW5kZXIgdGhhdCBidWlsdCBpdHNcbiAgICAgICAgLy8gYWJzb2x1dGUgVVJMcyBmcm9tIHRoYXQgd291bGQgY2FjaGUgbGlua3MgdG8gdGhlIHJhdyBmdW5jdGlvbi5cbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgIC4uLmNvbmZpZy5oZWFkZXJzLFxuICAgICAgICAgIGhvc3Q6IG9yaWdpbi5oZWFkZXJzLmhvc3QsXG4gICAgICAgICAgLi4ucGlja0RlZmluZWQob3JpZ2luLmhlYWRlcnMsIFtcbiAgICAgICAgICAgIFwieC1mb3J3YXJkZWQtaG9zdFwiLFxuICAgICAgICAgICAgXCJ4LWZvcndhcmRlZC1wcm90b1wiLFxuICAgICAgICAgIF0pLFxuICAgICAgICB9LFxuICAgICAgICBlbmNyeXB0ZWQ6IG9yaWdpbi5lbmNyeXB0ZWQsXG4gICAgICAgIHRydXN0Rm9yd2FyZGVkSG9zdDogb3JpZ2luLnRydXN0Rm9yd2FyZGVkSG9zdCxcbiAgICAgIH0sXG4gICAgICB7fSxcbiAgICApO1xuXG4gICAgY29uc3Qgc3RhdHVzID0gaGVhZD8uc3RhdHVzQ29kZSA/PyA1MDA7XG4gICAgaWYgKG90aGVyR3JvdXApIHtcbiAgICAgIGNvbnN0IHNlbGYgPSBwcm9jZXNzLmVudltGVU5DVElPTl9HUk9VUF9FTlZfVkFSXTtcbiAgICAgIC8vIEEgcGFnZSBwYWNrYWdlZCBpbnRvIGFub3RoZXIgYGZ1bmN0aW9uR3JvdXBzYCBncm91cDogaXQgaXMgcmVuZGVyZWQgaW5cbiAgICAgIC8vIHByb2Nlc3MsIGFuZCB0aGlzIGZ1bmN0aW9uIGRvZXMgbm90IGhhdmUgdGhlIHBhZ2UncyBjb2RlLiBDaGVja2VkXG4gICAgICAvLyBmaXJzdCBiZWNhdXNlIGl0IHJlbmRlcnMgYXMgYSA0MDQsIHdoaWNoIGB1bnN0YWJsZV9vbmx5R2VuZXJhdGVkYFxuICAgICAgLy8gd291bGQgb3RoZXJ3aXNlIGFjY2VwdC5cbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEludmFsaWQgcmVzcG9uc2UgJHtzdGF0dXN9OiBcIiR7Y29uZmlnLnVybFBhdGh9XCIgYmVsb25ncyB0byBgICtcbiAgICAgICAgICBgXFxgZnVuY3Rpb25Hcm91cHNcXGAgZ3JvdXAgXCIke290aGVyR3JvdXAub3duZXJ9XCIsIGFuZCBgICtcbiAgICAgICAgICBgcmVzLnJldmFsaWRhdGUoKSBjYW4gb25seSByZXZhbGlkYXRlIHBhZ2VzIGluIHRoZSBncm91cCBpdCBydW5zIGAgK1xuICAgICAgICAgIGBpbiAoXCIke3NlbGZ9XCIpLiBDYWxsIGl0IGZyb20gYW4gQVBJIHJvdXRlIGluIGdyb3VwIGAgK1xuICAgICAgICAgIGBcIiR7b3RoZXJHcm91cC5vd25lcn1cIiwgb3IgdXNlIHJldmFsaWRhdGVQYXRoKCkvcmV2YWxpZGF0ZVRhZygpLCBgICtcbiAgICAgICAgICBgd2hpY2ggd29yayBmcm9tIGFueSBncm91cC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKFxuICAgICAgaGVhZD8uaGVhZGVyc1tcIngtbmV4dGpzLWNhY2hlXCJdICE9PSBcIlJFVkFMSURBVEVEXCIgJiZcbiAgICAgIHN0YXR1cyAhPT0gMjAwICYmXG4gICAgICAhKHN0YXR1cyA9PT0gNDA0ICYmIGNvbmZpZy5vcHRzLnVuc3RhYmxlX29ubHlHZW5lcmF0ZWQpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgcmVzcG9uc2UgJHtzdGF0dXN9YCk7XG4gICAgfVxuXG4gICAgYXdhaXQgaW52YWxpZGF0ZVJldmFsaWRhdGVkUGFnZShjb25maWcudXJsUGF0aCwgdGhpcy5vcHRpb25zLm1hbmlmZXN0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbiBpbWFnZSBvcHRpbWl6YXRpb24gc291cmNlIHRoYXQgaXMgbm90IGEgZmlsZTogYDxJbWFnZSBzcmM9XCIvYXBpL2F2YXRhclwiPmBcbiAgICogc2VydmVkIGJ5IGEgcm91dGUgaGFuZGxlci4gV2lyZWQgaW4gYXMgdGhlIG9wdGltaXplcidzIGBmZXRjaEludGVybmFsYCwgYW5kXG4gICAqIHJ1biBpbiBwcm9jZXNzIGZvciB0aGUgcmVhc29ucyB7QGxpbmsgcmV2YWxpZGF0ZX0gaXMg4oCUIGBuZXh0IHN0YXJ0YCBmZXRjaGVzXG4gICAqIHRoZSBzb3VyY2UgZnJvbSBpdHNlbGYgb3ZlciBsb29wYmFjaywgd2hpY2ggaGVyZSB3b3VsZCBiZSBhIHNlY29uZCBiaWxsZWRcbiAgICogaW52b2NhdGlvbiB0aHJvdWdoIENsb3VkRnJvbnQuXG4gICAqXG4gICAqIE9ubHkgdGhlIGF1dGhvcml0eSBpcyBmb3J3YXJkZWQsIGFzIGBuZXh0IHN0YXJ0YCdzIGBmZXRjaEludGVybmFsSW1hZ2VgXG4gICAqIGZvcndhcmRzIG5vbmUgb2YgdGhlIHZpZXdlcidzIGhlYWRlcnM6IHRoZSBzb3VyY2UgaXMgY2FjaGVkIGFuZCBzZXJ2ZWQgdG9cbiAgICogZXZlcnlvbmUsIHNvIGl0IG11c3Qgbm90IGRlcGVuZCBvbiBvbmUgdmlld2VyJ3MgY29va2llcy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hJbnRlcm5hbChcbiAgICBocmVmOiBzdHJpbmcsXG4gICAgcmVxOiBTaGltSW5jb21pbmdNZXNzYWdlLFxuICAgIG1heGltdW1Cb2R5OiBudW1iZXIsXG4gICk6IFByb21pc2U8SW50ZXJuYWxJbWFnZVJlc3BvbnNlPiB7XG4gICAgY29uc3QgcmVxdWVzdDogUnVudGltZVJlcXVlc3QgPSB7XG4gICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICB1cmw6IGhyZWYsXG4gICAgICBoZWFkZXJzOiBwaWNrRGVmaW5lZChyZXEuaGVhZGVycywgW1xuICAgICAgICBcImhvc3RcIixcbiAgICAgICAgXCJ4LWZvcndhcmRlZC1ob3N0XCIsXG4gICAgICAgIFwieC1mb3J3YXJkZWQtcHJvdG9cIixcbiAgICAgIF0pLFxuICAgICAgZW5jcnlwdGVkOiAocmVxLnNvY2tldCBhcyB7IGVuY3J5cHRlZD86IGJvb2xlYW4gfSB8IHVuZGVmaW5lZCk/LmVuY3J5cHRlZCxcbiAgICAgIHRydXN0Rm9yd2FyZGVkSG9zdDogcmVxLnRydXN0Rm9yd2FyZGVkSG9zdCxcbiAgICB9O1xuICAgIGNvbnN0IHsgaGVhZCwgYm9keSwgb3RoZXJHcm91cCwgdG9vTGFyZ2UgfSA9IGF3YWl0IHRoaXMuaGFuZGxlSW50ZXJuYWxseShcbiAgICAgIHJlcXVlc3QsXG4gICAgICB7IG1heGltdW1Cb2R5IH0sXG4gICAgKTtcbiAgICBpZiAodG9vTGFyZ2UpIHtcbiAgICAgIHJldHVybiB7IHN0YXR1c0NvZGU6IDAsIGhlYWRlcnM6IHt9LCBib2R5OiBCdWZmZXIuYWxsb2MoMCksIHRvb0xhcmdlIH07XG4gICAgfVxuICAgIGlmIChvdGhlckdyb3VwKSB7XG4gICAgICAvLyBUaGUgZWRnZSBzZW5kcyBldmVyeSBgL19uZXh0L2ltYWdlYCByZXF1ZXN0IHRvIHRoZSBkZWZhdWx0IGdyb3VwLCBhbmRcbiAgICAgIC8vIHRoZSBzb3VyY2UgaXMgcmVuZGVyZWQgaW4gcHJvY2Vzcywgc28gYSByb3V0ZSBwYWNrYWdlZCBpbnRvIGFub3RoZXJcbiAgICAgIC8vIGdyb3VwIGlzIG91dCBvZiByZWFjaDogdGhlIG9wdGltaXplciBhbnN3ZXJzIChhbmQgbG9ncykgYSA1MDIuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdGF0dXNDb2RlOiAwLFxuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICAgICAgYm9keTogQnVmZmVyLmFsbG9jKDApLFxuICAgICAgICBvdGhlckdyb3VwOiBvdGhlckdyb3VwLm93bmVyLFxuICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIHN0YXR1c0NvZGU6IGhlYWQ/LnN0YXR1c0NvZGUgPz8gMCxcbiAgICAgIGhlYWRlcnM6IGhlYWQ/LmhlYWRlcnMgPz8ge30sXG4gICAgICBib2R5LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogT25lIHJlcXVlc3QgdGhyb3VnaCB7QGxpbmsgaGFuZGxlfSwgYW5zd2VyZWQgdG8gdGhpcyBydW50aW1lIGluc3RlYWQgb2YgYVxuICAgKiBjbGllbnQ6IHRoZSBoZWFkLCB0aGUgYm9keSB3aGVuIGl0IGlzIHdhbnRlZCwgYW5kIHRoZSBlcnJvciB3aGVuIHRoZSByb3V0ZVxuICAgKiBpcyBwYWNrYWdlZCBpbnRvIGFub3RoZXIgYGZ1bmN0aW9uR3JvdXBzYCBncm91cC4gYGhhbmRsZWAgYXdhaXRzIHRoZVxuICAgKiByZXF1ZXN0J3MgYHdhaXRVbnRpbGAgd29yayB0b28sIHNvIHdoYXRldmVyIHRoZSByZW5kZXIgd3JvdGUgaXMgY29tbWl0dGVkIGJ5XG4gICAqIHRoZSB0aW1lIHRoaXMgcmVzb2x2ZXMuXG4gICAqXG4gICAqIFRoZSBib2R5IGlzIGtlcHQgb25seSB3aGVuIGBtYXhpbXVtQm9keWAgaXMgc2V0LiBPbmUgcGFzdCBpdCBmYWlscyB0aGVcbiAgICogcmVzcG9uc2Ugc3RyZWFtLCB3aGljaCBzdG9wcyB0aGUgcm91dGUgd3JpdGluZywgYW5kIGNvbWVzIGJhY2sgYXNcbiAgICogYHRvb0xhcmdlYCByYXRoZXIgdGhhbiBoZWxkIGluIG1lbW9yeS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlSW50ZXJuYWxseShcbiAgICByZXF1ZXN0OiBSdW50aW1lUmVxdWVzdCxcbiAgICBvcHRpb25zOiB7IHJlYWRvbmx5IG1heGltdW1Cb2R5PzogbnVtYmVyIH0sXG4gICk6IFByb21pc2U8e1xuICAgIGhlYWQ/OiBSZXNwb25zZUhlYWQ7XG4gICAgYm9keTogQnVmZmVyO1xuICAgIG90aGVyR3JvdXA/OiBSb3V0ZUluT3RoZXJHcm91cEVycm9yO1xuICAgIHRvb0xhcmdlOiBib29sZWFuO1xuICB9PiB7XG4gICAgbGV0IGhlYWQ6IFJlc3BvbnNlSGVhZCB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCBjaHVua3M6IEJ1ZmZlcltdID0gW107XG4gICAgbGV0IHNpemUgPSAwO1xuICAgIGxldCB0b29MYXJnZSA9IGZhbHNlO1xuICAgIGxldCBvdGhlckdyb3VwOiBSb3V0ZUluT3RoZXJHcm91cEVycm9yIHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IG9uUm91dGVJbk90aGVyR3JvdXAgPSAoZXJyb3I6IFJvdXRlSW5PdGhlckdyb3VwRXJyb3IpID0+IHtcbiAgICAgIG90aGVyR3JvdXAgPSBlcnJvcjtcbiAgICB9O1xuICAgIGF3YWl0IHRoaXMuaGFuZGxlKFxuICAgICAgeyAuLi5yZXF1ZXN0LCBvblJvdXRlSW5PdGhlckdyb3VwIH0sXG4gICAgICB7XG4gICAgICAgIGJlZ2luKHJlc3BvbnNlSGVhZCkge1xuICAgICAgICAgIGhlYWQgPSByZXNwb25zZUhlYWQ7XG4gICAgICAgICAgcmV0dXJuIG5ldyBXcml0YWJsZSh7XG4gICAgICAgICAgICB3cml0ZShjaHVuazogQnVmZmVyLCBfZW5jb2RpbmcsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgIGlmIChvcHRpb25zLm1heGltdW1Cb2R5ID09PSB1bmRlZmluZWQpIHJldHVybiBjYWxsYmFjaygpO1xuICAgICAgICAgICAgICBzaXplICs9IGNodW5rLmJ5dGVMZW5ndGg7XG4gICAgICAgICAgICAgIGlmIChzaXplID4gb3B0aW9ucy5tYXhpbXVtQm9keSkge1xuICAgICAgICAgICAgICAgIHRvb0xhcmdlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobmV3IEVycm9yKFwiT3ZlciBpbWFnZXMubWF4aW11bVJlc3BvbnNlQm9keVwiKSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY2h1bmtzLnB1c2goQnVmZmVyLmZyb20oY2h1bmspKTtcbiAgICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWQsXG4gICAgICBib2R5OiB0b29MYXJnZSA/IEJ1ZmZlci5hbGxvYygwKSA6IEJ1ZmZlci5jb25jYXQoY2h1bmtzKSxcbiAgICAgIG90aGVyR3JvdXAsXG4gICAgICB0b29MYXJnZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcCBSb3V0ZXIgYnVpbGRzIGFuIGludm9jYWJsZSBgL19ub3QtZm91bmRgLCBQYWdlcyBSb3V0ZXIgYSBwcmVyZW5kZXJlZFxuICAgKiBgNDA0Lmh0bWxgIChwZXIgbG9jYWxlIHVuZGVyIGkxOG4pIG9yIGVsc2UgYC9fZXJyb3JgOyBzZWUgYHN0YXR1c1RhcmdldHNgLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzZW5kTm90Rm91bmQoXG4gICAgcmVxOiBTaGltSW5jb21pbmdNZXNzYWdlLFxuICAgIHJlczogU2hpbVNlcnZlclJlc3BvbnNlLFxuICAgIHdhaXRVbnRpbDogKHByb21pc2U6IFByb21pc2U8dW5rbm93bj4pID0+IHZvaWQsXG4gICAgdGFyZ2V0OiBTdGF0dXNUYXJnZXQsXG4gICAgLyoqXG4gICAgICogV2hhdCB0byByZW5kZXIgdGhlIDQwNCBhcy4gT21pdHRlZCBieSBgcmVuZGVyNDA0YCwgd2hpY2ggaXMgY2FsbGVkXG4gICAgICogbWlkLXJlbmRlciB3aXRoIGByZXEudXJsYCBhbHJlYWR5IHBvaW50aW5nIGF0IHRoZSByb3V0ZSB0aGF0IGdhdmUgdXAg4oCUXG4gICAgICogdGhlIHBhdGggTmV4dC5qcyB3b3VsZCByZW5kZXIgdGhhdCA0MDQgZm9yLlxuICAgICAqL1xuICAgIHJlcXVlc3RlZFVybD86IHN0cmluZyxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmVzLnN0YXR1c0NvZGUgPSA0MDQ7XG5cbiAgICBpZiAodGFyZ2V0LmtpbmQgPT09IFwiZW50cnlwb2ludFwiKSB7XG4gICAgICBjb25zdCBoYW5kbGVyID0gYXdhaXQgdGhpcy5lbnRyeXBvaW50cy5sb2FkKHRhcmdldC5lbnRyeXBvaW50KTtcbiAgICAgIHJlcS51cmwgPSByZXF1ZXN0ZWRVcmwgPz8gcmVxLnVybDtcbiAgICAgIGF3YWl0IGhhbmRsZXIocmVxLCBhc1NlcnZlclJlc3BvbnNlKHJlcyksIHsgd2FpdFVudGlsIH0pO1xuICAgICAgaWYgKCFyZXMud3JpdGFibGVFbmRlZCkge1xuICAgICAgICByZXMuZW5kKCk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgdGFyZ2V0LmtpbmQgPT09IFwic3RhdGljLWZpbGVcIiAmJlxuICAgICAgKGF3YWl0IHRoaXMuc2VuZEh0bWxGaWxlKHJlcywgdGFyZ2V0KSlcbiAgICApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICByZXMuc2V0SGVhZGVyKFwiQ29udGVudC1UeXBlXCIsIFwidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOFwiKTtcbiAgICByZXMuZW5kKFwiVGhpcyBwYWdlIGNvdWxkIG5vdCBiZSBmb3VuZC5cIik7XG4gIH1cblxuICAvKipcbiAgICogVHVybiBhIHRocm93biBlcnJvciBpbnRvIGEgcmVzcG9uc2UsIHJlbmRlcmluZyB0aGUgYXBwJ3MgZXJyb3IgcGFnZSB3aGVuIGl0XG4gICAqIGhhcyBvbmUuXG4gICAqXG4gICAqIE5leHQuanMncyBvd24gcGFnZSBoYW5kbGVycyBjYXRjaCwgcmVwb3J0IGFuZCB0aGVuICpyZXRocm93KiAoXCJyZXRocm93IHNvXG4gICAqIHRoYXQgd2UgY2FuIGhhbmRsZSBzZXJ2aW5nIGVycm9yIHBhZ2VcIiwgYHBhZ2VzLWhhbmRsZXIudHNgKSwgd2hpY2ggbWFrZXMgdGhlXG4gICAqIGVycm9yIHBhZ2UgdGhlIGhvc3QncyBqb2Ig4oCUIHRoZSBzYW1lIGRpdmlzaW9uIG9mIGxhYm9yIGFzIGByZW5kZXI0MDRgLiBXaXRob3V0XG4gICAqIHRoaXMgbGFkZGVyIGV2ZXJ5IHRocm93IGFuc3dlcmVkIGEgYmFyZSBgdGV4dC9wbGFpbmAgNTAwIGFuZCBhIGN1c3RvbVxuICAgKiBgcGFnZXMvX2Vycm9yYCB3YXMgZGVhZCBjb2RlIChgdGVzdC9lMmUvYXN5bmMtbW9kdWxlc2AsIHdob3NlIGAvbWFrZS1lcnJvcmBcbiAgICogdGhyb3dzIGluIGBnZXRTZXJ2ZXJTaWRlUHJvcHNgKS5cbiAgICpcbiAgICogT25jZSB0aGUgaGVhZCBpcyBvdXQgdGhlcmUgaXMgbm90aGluZyB0byBzYXkg4oCUIGRlc3Ryb3lpbmcgdGhlIHN0cmVhbSBpcyB3aGF0XG4gICAqIHRlbGxzIHRoZSBjbGllbnQgdGhlIHJlc3BvbnNlIGlzIHRydW5jYXRlZCByYXRoZXIgdGhhbiBjb21wbGV0ZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2VuZEVycm9yKFxuICAgIHJlcTogU2hpbUluY29taW5nTWVzc2FnZSxcbiAgICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgICB3YWl0VW50aWw6IChwcm9taXNlOiBQcm9taXNlPHVua25vd24+KSA9PiB2b2lkLFxuICAgIGVycm9yOiB1bmtub3duLFxuICAgIC8qKiBUaGUgcmVxdWVzdCwgYXMgcmVjZWl2ZWQ6IHdoaWNoIGxvY2FsZSdzIHByZXJlbmRlcmVkIDUwMCB0byBzZW5kLiAqL1xuICAgIHVybDogVVJMIHwgdW5kZWZpbmVkLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zb2xlLmVycm9yKFwiVW5oYW5kbGVkIGVycm9yIHdoaWxlIGhhbmRsaW5nIHRoZSByZXF1ZXN0OlwiLCBlcnJvcik7XG4gICAgaWYgKHJlcy5oZWFkZXJzU2VudCkge1xuICAgICAgcmVzLmRlc3Ryb3koYXNFcnJvcihlcnJvcikpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICByZXMuc3RhdHVzQ29kZSA9IDUwMDtcbiAgICAvLyBBIGZhaWxlZCByZW5kZXIgbWF5IGhhdmUgc2V0IGhlYWRlcnMgZGVzY3JpYmluZyBhIGJvZHkgdGhhdCBuZXZlclxuICAgIC8vIGFycml2ZWQuIEV2ZXJ5IHJ1bmcgYmVsb3cgc2VuZHMgYSBkaWZmZXJlbnQgYm9keSwgc28gdGhleSBnbyBmaXJzdDogYVxuICAgIC8vIHN0YWxlIGBDb250ZW50LUxlbmd0aGAgb24gYSA1MDAuaHRtbCBvZiBhbm90aGVyIHNpemUgaGFuZ3MgdGhlIGNsaWVudCBvclxuICAgIC8vIGRlc3luY3MgYSBrZWVwLWFsaXZlIGNvbm5lY3Rpb24uXG4gICAgcmVzLnJlbW92ZUhlYWRlcihcIkNvbnRlbnQtTGVuZ3RoXCIpO1xuICAgIHJlcy5yZW1vdmVIZWFkZXIoXCJFVGFnXCIpO1xuICAgIC8vIEV2ZXJ5IHJ1bmcsIHRoZSBlcnJvci1wYWdlIGVudHJ5cG9pbnQgaW5jbHVkZWQ6IG90aGVyd2lzZSB0aGUgdGhyb3dpbmdcbiAgICAvLyByZW5kZXIncyBgcy1tYXhhZ2VgIChvciBhIGBoZWFkZXJzKClgIHJ1bGUncykgcmlkZXMgYWxvbmcgYW5kIENsb3VkRnJvbnRcbiAgICAvLyBjYWNoZXMgdGhlIDUwMC4gYG5leHQgc3RhcnRgIHNldHMgaXQgYmVmb3JlIHJlbmRlcmluZyB0aGUgZXJyb3IgcGFnZSB0b28uXG4gICAgcmVzLnNldEhlYWRlcihcIkNhY2hlLUNvbnRyb2xcIiwgTk9fU1RPUkUpO1xuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuZXJyb3JUYXJnZXRGb3IodXJsKTtcblxuICAgIGlmICh0YXJnZXQua2luZCA9PT0gXCJlbnRyeXBvaW50XCIpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSBhd2FpdCB0aGlzLmVudHJ5cG9pbnRzLmxvYWQodGFyZ2V0LmVudHJ5cG9pbnQpO1xuICAgICAgICAvLyBgcmVxLnVybGAgaXMgbGVmdCBhbG9uZTogdGhlIGVycm9yIHBhZ2UgcmVuZGVycyBmb3IgdGhlIFVSTCB0aGF0IHdhc1xuICAgICAgICAvLyBhc2tlZCBmb3IsIGFuZCBgX2Vycm9yYCdzIGBnZXRJbml0aWFsUHJvcHNgIHJlYWRzIHRoZSBzdGF0dXMgb2ZmIGByZXNgLFxuICAgICAgICAvLyB3aGljaCBpcyB3aHkgdGhlIDUwMCBhYm92ZSBpcyBzZXQgZmlyc3QuXG4gICAgICAgIGF3YWl0IGhhbmRsZXIocmVxLCBhc1NlcnZlclJlc3BvbnNlKHJlcyksIHsgd2FpdFVudGlsIH0pO1xuICAgICAgICBpZiAoIXJlcy53cml0YWJsZUVuZGVkKSB7XG4gICAgICAgICAgcmVzLmVuZCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gY2F0Y2ggKGVycm9yUGFnZUVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgXCJUaGUgZXJyb3IgcGFnZSBpdHNlbGYgZmFpbGVkIHRvIHJlbmRlcjpcIixcbiAgICAgICAgICBlcnJvclBhZ2VFcnJvcixcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKHJlcy5oZWFkZXJzU2VudCkge1xuICAgICAgICAgIHJlcy5kZXN0cm95KGFzRXJyb3IoZXJyb3JQYWdlRXJyb3IpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICB0YXJnZXQua2luZCA9PT0gXCJzdGF0aWMtZmlsZVwiICYmXG4gICAgICAoYXdhaXQgdGhpcy5zZW5kSHRtbEZpbGUocmVzLCB0YXJnZXQpKVxuICAgICkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEFnYWluOiBhbiBlcnJvciBwYWdlIHRoYXQgdGhyZXcgbWF5IGhhdmUgZGVzY3JpYmVkIGl0cyBvd24gYm9keSB0b28uXG4gICAgcmVzLnJlbW92ZUhlYWRlcihcIkNvbnRlbnQtTGVuZ3RoXCIpO1xuICAgIHJlcy5yZW1vdmVIZWFkZXIoXCJFVGFnXCIpO1xuICAgIHJlcy5zdGF0dXNDb2RlID0gNTAwO1xuICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgXCJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04XCIpO1xuICAgIHJlcy5zZXRIZWFkZXIoXCJDYWNoZS1Db250cm9sXCIsIE5PX1NUT1JFKTtcbiAgICByZXMuZW5kKFwiSW50ZXJuYWwgU2VydmVyIEVycm9yXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgcHJlcmVuZGVyZWQgNDA0IG9yIDUwMCBwYWdlLCBvciBgZmFsc2VgIHdoZW4gaXQgY2Fubm90IGJlIHJlYWQgYW5kIHRoZVxuICAgKiBjYWxsZXIncyBwbGFpbi10ZXh0IGZhbGxiYWNrIHNob3VsZCBhbnN3ZXIuIFJlYWQgcmF0aGVyIHRoYW4gYHNlcnZlU3RhdGljYCxcbiAgICogd2hpY2gga2VlcHMgdGhlIHN0YXR1cyBhbHJlYWR5IHNldCBidXQgd291bGQgYW5zd2VyIGEgYFJhbmdlYCByZXF1ZXN0IHdpdGhcbiAgICogYSAyMDYgb2YgdGhlIGVycm9yIHBhZ2UsIGFuZCBhZGQgYEVUYWdgLCBgTGFzdC1Nb2RpZmllZGAgYW5kLCB3aGVyZSBub25lIGlzXG4gICAqIHNldCB5ZXQsIGEgcHVibGljIGBDYWNoZS1Db250cm9sYCB0byBpdC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2VuZEh0bWxGaWxlKFxuICAgIHJlczogU2hpbVNlcnZlclJlc3BvbnNlLFxuICAgIHRhcmdldDogeyByZWFkb25seSBmaWxlUGF0aDogc3RyaW5nIH0sXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGxldCBodG1sOiBCdWZmZXI7XG4gICAgdHJ5IHtcbiAgICAgIGh0bWwgPSBhd2FpdCByZWFkRmlsZShqb2luKHRoaXMub3B0aW9ucy5kZXBsb3ltZW50Um9vdCwgdGFyZ2V0LmZpbGVQYXRoKSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgXCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIik7XG4gICAgcmVzLmVuZChodG1sKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxufVxuXG4vKipcbiAqIFdoYXQgbmV4dCBzZW5kcyB3aXRoIGFuIGVycm9yIGl0IHJlbmRlcmVkIGl0c2VsZi4gV2l0aG91dCBpdCBhIGBDYWNoZS1Db250cm9sYFxuICogbGVmdCBiZWhpbmQgYnkgdGhlIHJlbmRlciB0aGF0IHRocmV3IGNhbiBnZXQgYSA1MDAgY2FjaGVkIGF0IHRoZSBlZGdlLlxuICovXG5jb25zdCBOT19TVE9SRSA9IFwicHJpdmF0ZSwgbm8tY2FjaGUsIG5vLXN0b3JlLCBtYXgtYWdlPTAsIG11c3QtcmV2YWxpZGF0ZVwiO1xuXG4vKipcbiAqIGBTZWMtRmV0Y2gtRGVzdGAgdmFsdWVzIHRoYXQgY2FuIG5ldmVyIGRpc3BsYXkgYW4gSFRNTCByZXNwb25zZSwgZnJvbVxuICogYG5leHQvZGlzdC9zZXJ2ZXIvbGliL2lzLW5vbi1odG1sLXNlYy1mZXRjaC1kZXN0LmpzYC4gUmVzdGF0ZWQgcmF0aGVyIHRoYW5cbiAqIHJlcXVpcmVkLCBiZWNhdXNlIHRoYXQgbW9kdWxlIGlzIHJlY2VudCBhbmQgdGhlIGFwcCdzIGBuZXh0YCBtYXkgcHJlZGF0ZSBpdDpcbiAqIGEgZmFpbGVkIHJlcXVpcmUgaGVyZSB3b3VsZCB0dXJuIGV2ZXJ5IDQwNCBpbnRvIGEgNTAwLiBFeGNsdWRlcyBgZG9jdW1lbnRgLFxuICogYGlmcmFtZWAgYW5kIHRoZSBsaWtlLCBhbmQgYGVtcHR5YCDigJQgYGZldGNoKClgLCB3aGljaCBpcyBob3cgUlNDIHJlcXVlc3RzIGdvLlxuICovXG5jb25zdCBOT05fSFRNTF9TRUNfRkVUQ0hfREVTVFM6IFJlYWRvbmx5U2V0PHN0cmluZz4gPSBuZXcgU2V0KFtcbiAgXCJhdWRpb1wiLFxuICBcImF1ZGlvd29ya2xldFwiLFxuICBcImZvbnRcIixcbiAgXCJpbWFnZVwiLFxuICBcImpzb25cIixcbiAgXCJtYW5pZmVzdFwiLFxuICBcInBhaW50d29ya2xldFwiLFxuICBcInJlcG9ydFwiLFxuICBcInNjcmlwdFwiLFxuICBcInNlcnZpY2V3b3JrZXJcIixcbiAgXCJzaGFyZWR3b3JrZXJcIixcbiAgXCJzdHlsZVwiLFxuICBcInRyYWNrXCIsXG4gIFwidmlkZW9cIixcbiAgXCJ3ZWJpZGVudGl0eVwiLFxuICBcIndvcmtlclwiLFxuICBcInhzbHRcIixcbl0pO1xuXG4vKipcbiAqIGBJTlRFUk5BTF9IRUFERVJTYCBmcm9tIGBuZXh0L2Rpc3Qvc2VydmVyL2xpYi9zZXJ2ZXItaXBjL3V0aWxzLmpzYCAoTmV4dFxuICogMTYuMyksIHdoaWNoIGBuZXh0IHN0YXJ0YCBkZWxldGVzIGZyb20gZXZlcnkgcmVxdWVzdCBiZWZvcmUgcm91dGluZyBpdFxuICogKGBmaWx0ZXJJbnRlcm5hbEhlYWRlcnNgIGluIGByb3V0ZXItc2VydmVyLmpzYCkuIFRoZXkgYXJlIHNpZ25hbHMgYmV0d2VlblxuICogTmV4dCdzIG93biByb3V0ZXIgYW5kIHJlbmRlciBsYXllcnM7IGhvbm9yaW5nIG9uZSBhIGNsaWVudCBzZW50IGxldHMgaXQgc3RlZXJcbiAqIHRob3NlIGxheWVycyDigJQgYG5leHQtcmVzdW1lYCBtYWtlcyBhIFBQUiBwYWdlIHJlc3VtZSBmcm9tIGEgcG9zdHBvbmVkIHN0YXRlXG4gKiB0aGUgY2xpZW50IHN1cHBsaWVzLiBSZXN0YXRlZCByYXRoZXIgdGhhbiByZXF1aXJlZCwgbGlrZVxuICoge0BsaW5rIE5PTl9IVE1MX1NFQ19GRVRDSF9ERVNUU30uXG4gKi9cbmNvbnN0IElOVEVSTkFMX0hFQURFUlM6IFJlYWRvbmx5U2V0PHN0cmluZz4gPSBuZXcgU2V0KFtcbiAgXCJ4LW1pZGRsZXdhcmUtcmV3cml0ZVwiLFxuICBcIngtbWlkZGxld2FyZS1yZWRpcmVjdFwiLFxuICBcIngtbWlkZGxld2FyZS1zZXQtY29va2llXCIsXG4gIFwieC1taWRkbGV3YXJlLXNraXBcIixcbiAgXCJ4LW1pZGRsZXdhcmUtb3ZlcnJpZGUtaGVhZGVyc1wiLFxuICBcIngtbWlkZGxld2FyZS1uZXh0XCIsXG4gIFwieC1ub3ctcm91dGUtbWF0Y2hlc1wiLFxuICBcIngtbWF0Y2hlZC1wYXRoXCIsXG4gIFwieC1uZXh0anMtZGF0YVwiLFxuICBcIngtbmV4dC1yZXN1bWUtc3RhdGUtbGVuZ3RoXCIsXG4gIFwibmV4dC1yZXN1bWVcIixcbl0pO1xuXG4vKipcbiAqIFRoZSByZXF1ZXN0IGhlYWRlcnMgd2l0aCB7QGxpbmsgSU5URVJOQUxfSEVBREVSU30gcmVtb3ZlZCwgYW5kIGB4LW5leHRqcy1kYXRhYFxuICogcHV0IGJhY2sgZm9yIGEgYF9uZXh0L2RhdGFgIHJlcXVlc3QsIHdoaWNoIGlzIHdoYXQgYG5leHQgc3RhcnRgJ3NcbiAqIGByZXNvbHZlUm91dGVzYCBkb2VzIChgc2V0SXNOZXh0RGF0YVJlcXVlc3RgKSByaWdodCBhZnRlciBzdHJpcHBpbmcgaXQ6IHRoZVxuICogaGVhZGVyIGlzIGludGVybmFsLCBidXQgTmV4dCdzIGhhbmRsZXJzIGFuZCBtaWRkbGV3YXJlIHN0aWxsIHJlYWQgaXQg4oCUIGl0IGlzXG4gKiBob3cgYSBkYXRhIHJlcXVlc3QgZ2V0cyBgeC1uZXh0anMtbWF0Y2hlZC1wYXRoYCDigJQgc28gYSByZWFsIGRhdGEgcmVxdWVzdCBoYXNcbiAqIHRvIGtlZXAgaXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3aXRob3V0SW50ZXJuYWxIZWFkZXJzKFxuICBoZWFkZXJzOiBJbmNvbWluZ0h0dHBIZWFkZXJzLFxuICB0YXJnZXQ6IHN0cmluZyxcbiAgYmFzZVBhdGg6IHN0cmluZyxcbik6IEluY29taW5nSHR0cEhlYWRlcnMge1xuICBjb25zdCBmaWx0ZXJlZDogSW5jb21pbmdIdHRwSGVhZGVycyA9IHt9O1xuICBmb3IgKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoaGVhZGVycykpIHtcbiAgICBpZiAoIUlOVEVSTkFMX0hFQURFUlMuaGFzKG5hbWUpKSB7XG4gICAgICBmaWx0ZXJlZFtuYW1lXSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuICBjb25zdCBwYXRobmFtZSA9IHdpdGhvdXRQYXRoUHJlZml4KHRhcmdldC5zcGxpdChcIj9cIilbMF0sIGJhc2VQYXRoKTtcbiAgaWYgKHBhdGhuYW1lLnN0YXJ0c1dpdGgoXCIvX25leHQvZGF0YS9cIikgJiYgcGF0aG5hbWUuZW5kc1dpdGgoXCIuanNvblwiKSkge1xuICAgIGZpbHRlcmVkW1wieC1uZXh0anMtZGF0YVwiXSA9IFwiMVwiO1xuICB9XG4gIHJldHVybiBmaWx0ZXJlZDtcbn1cblxuLyoqIEV2ZXJ5IHJvdXRlIHRvIGludmFsaWRhdGUsIGVhY2ggb25jZSwgaW4gb25lIENsb3VkRnJvbnQgaW52YWxpZGF0aW9uLiAqL1xudHlwZSBSZXZhbGlkYXRlZFBhZ2VIb29rID0gKHJvdXRlczogcmVhZG9ubHkgc3RyaW5nW10pID0+IFByb21pc2U8dm9pZD47XG5cbi8qKlxuICogSW52YWxpZGF0ZSB0aGUgQ0ROIGNvcGllcyBvZiBhIHBhZ2UgYHJlcy5yZXZhbGlkYXRlKClgIGp1c3QgcmVnZW5lcmF0ZWQ6IGl0c1xuICogSFRNTCBhbmQgUlNDIHBheWxvYWQsIGFuZCBpdHMgUGFnZXMgUm91dGVyIGBfbmV4dC9kYXRhYCBKU09OLiBXaXRob3V0IHRoaXMgdGhlXG4gKiBmcmVzaCBlbnRyeSBzYXQgYmVoaW5kIENsb3VkRnJvbnQncyBjb3B5IG9mIHRoZSBvbGQgb25lIGZvciB0aGUgcGFnZSdzIHdob2xlXG4gKiBgcy1tYXhhZ2VgIOKAlCBhIHllYXIsIGZvciBhbiBvbi1kZW1hbmQtb25seSBJU1IgcGFnZS4gYHJldmFsaWRhdGVQYXRoYCBhbmRcbiAqIGByZXZhbGlkYXRlVGFnYCBnbyB0aHJvdWdoIHRoZSBjYWNoZSBoYW5kbGVyJ3MgYHJldmFsaWRhdGVUYWdgLCB3aGljaCBhbHJlYWR5XG4gKiBpbnZhbGlkYXRlczsgYHJlcy5yZXZhbGlkYXRlKClgIGRvZXMgbm90IHRvdWNoIGl0LlxuICpcbiAqIEV2ZXJ5IHJvdXRlIGlzIHdpdGhvdXQgYGJhc2VQYXRoYCwgd2hpY2ggdGhlIGhvb2sgcHJlZml4ZXMuIEEgbm8tb3Agb3V0c2lkZVxuICogdGhlIEdsb2JhbCBjb25zdHJ1Y3RzLCB3aGVyZSBubyBob29rIGlzIHJlZ2lzdGVyZWQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGludmFsaWRhdGVSZXZhbGlkYXRlZFBhZ2UoXG4gIHVybFBhdGg6IHN0cmluZyxcbiAgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdCxcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBob29rID0gKGdsb2JhbFRoaXMgYXMgUmVjb3JkPHN5bWJvbCwgdW5rbm93bj4pW1xuICAgIFJFVkFMSURBVEVEX1BBR0VfSE9PS1xuICBdIGFzIFJldmFsaWRhdGVkUGFnZUhvb2sgfCB1bmRlZmluZWQ7XG4gIGlmICh0eXBlb2YgaG9vayAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IHJvdXRlID0gd2l0aG91dFBhdGhQcmVmaXgoXG4gICAgdXJsUGF0aC5zcGxpdChcIj9cIilbMF0sXG4gICAgbWFuaWZlc3QuY29uZmlnLmJhc2VQYXRoLFxuICApO1xuICB0cnkge1xuICAgIC8vIE9uZSBjYWxsLCBkZWR1cGxpY2F0ZWQ6IHRoZSBkZWZhdWx0IGxvY2FsZSdzIHR3byBwYWlycyBzaGFyZSBhIGRhdGFcbiAgICAvLyByb3V0ZSwgYW5kIGVhY2ggaW52YWxpZGF0aW9uIHBhdGggY291bnRzIGFnYWluc3QgQ2xvdWRGcm9udCdzIHF1b3RhLlxuICAgIGF3YWl0IGhvb2soWy4uLm5ldyBTZXQocmV2YWxpZGF0ZWRQYWdlUm91dGVzKHJvdXRlLCBtYW5pZmVzdCkuZmxhdCgpKV0pO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIC8vIFRoZSByZWdlbmVyYXRpb24gaXRzZWxmIHN1Y2NlZWRlZDsgdGhlIGVkZ2UgY2F0Y2hlcyB1cCBhdCBgcy1tYXhhZ2VgLlxuICAgIGNvbnNvbGUud2FybihgQ291bGQgbm90IGludmFsaWRhdGUgdGhlIENETiBjb3B5IG9mICR7dXJsUGF0aH06YCwgZXJyb3IpO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGBbcm91dGUsIGRhdGFSb3V0ZV1gIHBhaXJzIGEgcmV2YWxpZGF0ZWQgcGFnZSBpcyBjYWNoZWQgdW5kZXIgYXQgdGhlIGVkZ2UuXG4gKlxuICogSW4gYW4gaTE4biBhcHAgdGhlIE5leHQgY2xpZW50IGFsd2F5cyBwdXRzIHRoZSBsb2NhbGUgaW4gYSBkYXRhIGhyZWYsIHRoZVxuICogZGVmYXVsdCBsb2NhbGUgaW5jbHVkZWQgKGAvX25leHQvZGF0YS88aWQ+L2VuL2Jsb2cuanNvbmAsIGFuZCBg4oCmL2VuLmpzb25gIGZvclxuICogdGhlIHJvb3QpLCBzbyB0aGUgdW5wcmVmaXhlZCBkYXRhIHJvdXRlIG5hbWVzIG5vdGhpbmcgQ2xvdWRGcm9udCBob2xkcy4gVGhlXG4gKiBwYWdlIGlzIG9uZSBsb2NhbGUncyDigJQgYHJlcy5yZXZhbGlkYXRlKFwiL2Jsb2dcIilgIHJlZ2VuZXJhdGVzIHRoZSBkZWZhdWx0XG4gKiBsb2NhbGUncywgYFwiL2ZyL2Jsb2dcImAgRnJlbmNoIOKAlCBhbmQgdGhlIGRlZmF1bHQgbG9jYWxlJ3MgSFRNTCBpcyByZWFjaGFibGUsXG4gKiBhbmQgY2FjaGVkLCBib3RoIHdpdGggYW5kIHdpdGhvdXQgaXRzIHByZWZpeCwgc28gaXRzIHR3byBwYWlycyBzaGFyZSBhIGRhdGFcbiAqIHJvdXRlLCB3aGljaCB0aGUgY2FsbGVyIHNlbmRzIG9uY2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXZhbGlkYXRlZFBhZ2VSb3V0ZXMoXG4gIHJvdXRlOiBzdHJpbmcsXG4gIG1hbmlmZXN0OiBQaWNrPEFkYXB0ZXJNYW5pZmVzdCwgXCJidWlsZElkXCIgfCBcImNvbmZpZ1wiPixcbik6IEFycmF5PFtzdHJpbmcsIHN0cmluZ10+IHtcbiAgY29uc3QgZGF0YVJvdXRlID0gKHBhZ2U6IHN0cmluZykgPT5cbiAgICBgL19uZXh0L2RhdGEvJHttYW5pZmVzdC5idWlsZElkfSR7XG4gICAgICBwYWdlID09PSBcIi9cIiA/IFwiL2luZGV4XCIgOiBwYWdlLnJlcGxhY2UoL1xcLyskLywgXCJcIilcbiAgICB9Lmpzb25gO1xuICBjb25zdCBpMThuID0gbWFuaWZlc3QuY29uZmlnLmkxOG4gYXMge1xuICAgIHJlYWRvbmx5IGxvY2FsZXM/OiByZWFkb25seSBzdHJpbmdbXTtcbiAgICByZWFkb25seSBkZWZhdWx0TG9jYWxlPzogc3RyaW5nO1xuICB9IHwgbnVsbDtcbiAgaWYgKCFpMThuPy5kZWZhdWx0TG9jYWxlKSB7XG4gICAgcmV0dXJuIFtbcm91dGUsIGRhdGFSb3V0ZShyb3V0ZSldXTtcbiAgfVxuICBjb25zdCB7IGRlZmF1bHRMb2NhbGUgfSA9IGkxOG47XG4gIGNvbnN0IHNlZ21lbnQgPSByb3V0ZS5zcGxpdChcIi9cIilbMV0gPz8gXCJcIjtcbiAgY29uc3QgbG9jYWxlID0gKGkxOG4ubG9jYWxlcyA/PyBbXSkuaW5jbHVkZXMoc2VnbWVudClcbiAgICA/IHNlZ21lbnRcbiAgICA6IGRlZmF1bHRMb2NhbGU7XG4gIGNvbnN0IHBhZ2UgPVxuICAgIGxvY2FsZSA9PT0gc2VnbWVudCA/IHdpdGhvdXRQYXRoUHJlZml4KHJvdXRlLCBgLyR7c2VnbWVudH1gKSA6IHJvdXRlO1xuICBjb25zdCBsb2NhbGl6ZWQgPSBwYWdlID09PSBcIi9cIiA/IGAvJHtsb2NhbGV9YCA6IGAvJHtsb2NhbGV9JHtwYWdlfWA7XG4gIC8vIFRoZSByb290J3MgZGF0YSByb3V0ZSBpcyB0aGUgbG9jYWxlIGl0c2VsZiwgbm90IGAvPGxvY2FsZT4vaW5kZXhgLlxuICBjb25zdCBsb2NhbGl6ZWREYXRhID0gYC9fbmV4dC9kYXRhLyR7bWFuaWZlc3QuYnVpbGRJZH0ke2xvY2FsaXplZC5yZXBsYWNlKC9cXC8rJC8sIFwiXCIpfS5qc29uYDtcbiAgcmV0dXJuIGxvY2FsZSA9PT0gZGVmYXVsdExvY2FsZVxuICAgID8gW1xuICAgICAgICBbcGFnZSwgbG9jYWxpemVkRGF0YV0sXG4gICAgICAgIFtsb2NhbGl6ZWQsIGxvY2FsaXplZERhdGFdLFxuICAgICAgXVxuICAgIDogW1tsb2NhbGl6ZWQsIGxvY2FsaXplZERhdGFdXTtcbn1cblxuZnVuY3Rpb24gYXNFcnJvcihlcnJvcjogdW5rbm93bik6IEVycm9yIHtcbiAgcmV0dXJuIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKTtcbn1cblxuLyoqXG4gKiBSZWFkIHRoZSBtYW5pZmVzdCBhbmQgcGluIHRoZSBsYXlvdXQgaXQgZGVzY3JpYmVzLlxuICpcbiAqIGBwcm9jZXNzLmN3ZCgpYCBpcyBsb2FkLWJlYXJpbmcgYW5kIHRoZXJlIGlzIGV4YWN0bHkgb25lIGNoYW5jZSB0byBnZXQgaXRcbiAqIHJpZ2h0OiBOZXh0LmpzIGlubGluZXMgYHJlbGF0aXZlKGJ1aWxkQ3dkLCBwcm9qZWN0RGlyKWAgaW50byBldmVyeSBlbnRyeXBvaW50XG4gKiBhbmQgcmVzb2x2ZXMgaXQgYWdhaW5zdCB0aGUgKnJ1bnRpbWUqIGN3ZCB0byBmaW5kXG4gKiBgcmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25gLCB0aGUgcHJlcmVuZGVyIG1hbmlmZXN0LCBhbmQgdGhlIGFwcCdzIGNodW5rcy5cbiAqIGBhc3NlcnRCdWlsZEN3ZGAgaW4gYGJ1aWxkLW91dHB1dHMudHNgIGtlZXBzIHRoYXQgaW5saW5lZCB2YWx1ZSBgXCJcImAsIHNvIHRoZVxuICogd2hvbGUgaW52YXJpYW50IHJlZHVjZXMgdG8gXCJjd2QgaXMgdGhlIHN0YWdlZCBwcm9qZWN0IGRpclwiIOKAlCBhc3NlcnRlZCByYXRoZXJcbiAqIHRoYW4gYXNzdW1lZCwgYmVjYXVzZSBnZXR0aW5nIGl0IHdyb25nIHByb2R1Y2VzIGFcbiAqIGBDYW5ub3QgZmluZCBtb2R1bGUg4oCmL3JlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYCBmcm9tIGluc2lkZSBjb21waWxlZCBOZXh0LmpzXG4gKiBjb2RlIHdpdGggbm8gaW5kaWNhdGlvbiB0aGF0IHRoZSBsYXlvdXQgaXMgdGhlIHByb2JsZW0uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkUnVudGltZShcbiAgZGVwbG95bWVudFJvb3Q6IHN0cmluZyxcbik6IFByb21pc2U8TmV4dGpzUnVudGltZT4ge1xuICBjb25zdCBtYW5pZmVzdFBhdGggPSBkZXBsb3llZE1hbmlmZXN0UGF0aChkZXBsb3ltZW50Um9vdCk7XG4gIGxldCBtYW5pZmVzdDogQWRhcHRlck1hbmlmZXN0O1xuICB0cnkge1xuICAgIG1hbmlmZXN0ID0gSlNPTi5wYXJzZShhd2FpdCByZWFkRmlsZShtYW5pZmVzdFBhdGgsIFwidXRmLThcIikpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBDb3VsZCBub3QgcmVhZCB0aGUgY2RrLW5leHRqcyBhZGFwdGVyIG1hbmlmZXN0IGF0IFwiJHttYW5pZmVzdFBhdGh9XCIuIGAgK1xuICAgICAgICBgVGhlIGRlcGxveW1lbnQgcGFja2FnZSBpcyBpbmNvbXBsZXRlOiBzeW50aCBjb3BpZXMgYCArXG4gICAgICAgIGAke01BTklGRVNUX0ZJTEVfTkFNRX0gaW4gbmV4dCB0byB0aGUgYnVuZGxlZCBydW50aW1lLmAsXG4gICAgICB7IGNhdXNlOiBlcnJvciB9LFxuICAgICk7XG4gIH1cblxuICBjb25zdCBwcm9qZWN0RGlyID0gam9pbihkZXBsb3ltZW50Um9vdCwgbWFuaWZlc3QucmVsYXRpdmVQcm9qZWN0RGlyKTtcbiAgY29uc3QgcHJvYmUgPSBqb2luKFxuICAgIHByb2plY3REaXIsXG4gICAgbWFuaWZlc3QuY29uZmlnLmRpc3REaXIsXG4gICAgXCJyZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvblwiLFxuICApO1xuICB0cnkge1xuICAgIGF3YWl0IHJlYWRGaWxlKHByb2JlKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgVGhlIGRlcGxveW1lbnQgcm9vdCBcIiR7ZGVwbG95bWVudFJvb3R9XCIgZG9lcyBub3QgY29udGFpbiB0aGUgc3RhZ2VkIGAgK1xuICAgICAgICBgTmV4dC5qcyBwcm9qZWN0OiBleHBlY3RlZCBcIiR7cHJvYmV9XCIgdG8gZXhpc3QuIEV2ZXJ5IGJ1aWx0IGVudHJ5cG9pbnQgYCArXG4gICAgICAgIGByZXNvbHZlcyBpdHMgb3duIHBhdGhzIGFnYWluc3QgcHJvY2Vzcy5jd2QoKSwgc28gdGhpcyBsYXlvdXQgaXMgcGFydCBgICtcbiAgICAgICAgYG9mIHRoZSBjb250cmFjdCwgbm90IGEgY29udmVuaWVuY2UuYCxcbiAgICAgIHsgY2F1c2U6IGVycm9yIH0sXG4gICAgKTtcbiAgfVxuICAvLyBgbmV4dCBzdGFydGAgZm9yY2VzIHRoaXMsIGFuZCBleHRlcm5hbGl6ZWQgcGFja2FnZXMgKFJlYWN0IGZvciBQYWdlcyBSb3V0ZXJcbiAgLy8gU1NSLCBhbnl0aGluZyBpbiBgc2VydmVyRXh0ZXJuYWxQYWNrYWdlc2ApIHBpY2sgdGhlaXIgZGV2IG9yIHByb2QgYnVpbGQgZnJvbVxuICAvLyBpdCBhdCByZXF1aXJlIHRpbWUuIFRoZSBDb250YWluZXJzIERvY2tlcmZpbGVzIHNldCBpdCBhbmQgdGhlIEZ1bmN0aW9uc1xuICAvLyBjb25zdHJ1Y3RzIGRvIHRvbzsgdGhpcyBjb3ZlcnMgYSBoYW5kLXdpcmVkIGZ1bmN0aW9uLiBCZWZvcmUgYW55IGByZXF1aXJlYC5cbiAgLy8gKGBuZXh0YCdzIHR5cGluZ3MgZGVjbGFyZSBOT0RFX0VOViByZWFkLW9ubHkuKVxuICAocHJvY2Vzcy5lbnYgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPikuTk9ERV9FTlYgPz89IFwicHJvZHVjdGlvblwiO1xuICBwcm9jZXNzLmNoZGlyKHByb2plY3REaXIpO1xuICAvLyBCZWZvcmUgYW55dGhpbmcgY2FuIHNlcnZlIGEgcmVxdWVzdDogdGhlIHJ1bnRpbWUncyBvd24gYG5leHRgIGltcG9ydHMgcmVzb2x2ZVxuICAvLyBvdXQgb2YgdGhlIHN0YWdlZCBhcHAsIG5vdCBvdXQgb2YgdGhlIHNoZWxsJ3MgZGlyZWN0b3J5LiBTZWUgYG5leHQtbW9kdWxlcy50c2AuXG4gIHVzZU5leHRGcm9tKHByb2plY3REaXIpO1xuICAvLyBCZWZvcmUgYW55IGVudHJ5cG9pbnQgY2FuIHJlYWQgdGhlbSBhdCBtb2R1bGUgc2NvcGUuXG4gIGxvYWRFbnZGaWxlcyhwcm9qZWN0RGlyKTtcbiAgLy8gVGhlbiwgYmVmb3JlIGFueSBlbnRyeXBvaW50IChvciBtaWRkbGV3YXJlKSBjYW4gYmUgbG9hZGVkOiBOZXh0J3Mgb3duXG4gIC8vIG5vZGUtZW52aXJvbm1lbnQgYm9vdHN0cmFwLiBTZWUgYHNldHVwTm9kZUVudmlyb25tZW50YC5cbiAgc2V0dXBOb2RlRW52aXJvbm1lbnQoKTtcbiAgLy8gQW5kIGxhc3QsIG9uY2UgdGhlIGVudmlyb25tZW50IGlzIHJlYWR5OiBgcmVnaXN0ZXIoKWAsIGJlZm9yZSBhbnkgZW50cnlwb2ludFxuICAvLyBvciBtaWRkbGV3YXJlIG1vZHVsZSBpcyBldmFsdWF0ZWQuIFNlZSBgcmVnaXN0ZXJJbnN0cnVtZW50YXRpb25gLlxuICBhd2FpdCByZWdpc3Rlckluc3RydW1lbnRhdGlvbihwcm9qZWN0RGlyLCBtYW5pZmVzdC5jb25maWcuZGlzdERpcik7XG5cbiAgcmV0dXJuIG5ldyBOZXh0anNSdW50aW1lKHtcbiAgICBkZXBsb3ltZW50Um9vdCxcbiAgICBtYW5pZmVzdCxcbiAgICBidWNrZXQ6IHByb2Nlc3MuZW52LkNES19ORVhUSlNfU1RBVElDX0FTU0VUU19CVUNLRVRfTkFNRSxcbiAgICBidWNrZXRLZXlQcmVmaXg6IHByb2Nlc3MuZW52LkNES19ORVhUSlNfU1RBVElDX0FTU0VUU19LRVlfUFJFRklYLFxuICB9KTtcbn1cblxuLyoqXG4gKiBBIHN5bnRhY3RpY2FsbHkgdmFsaWQgYGhvc3RbOnBvcnRdYDogYSByZWdpc3RlcmVkIG5hbWUgb3IgYSBicmFja2V0ZWQgSVB2NlxuICogbGl0ZXJhbCwgb3B0aW9uYWxseSB3aXRoIGEgcG9ydC4gQW55dGhpbmcgZWxzZSBjYW5ub3QgYmUgdGhlIGF1dGhvcml0eSBvZiBhXG4gKiBVUkwuXG4gKi9cbmNvbnN0IEhPU1RfQVVUSE9SSVRZID0gL14oPzpcXFtbMC05QS1GYS1mOi5dK1xcXXxbMC05QS1aYS16Ll8tXSspKD86OlxcZHsxLDV9KT8kLztcblxuLyoqXG4gKiBUaGUgZmlyc3QgdmFsdWUgdGhhdCBpcyBhY3R1YWxseSB1c2FibGUgYXMgYW4gYXV0aG9yaXR5LCBvciBgdW5kZWZpbmVkYC5cbiAqXG4gKiBgeC1mb3J3YXJkZWQtaG9zdGAgY2FuIGFycml2ZSBhcyBhIGxpc3Qgd2hlbiBtb3JlIHRoYW4gb25lIHByb3h5IGFwcGVuZHMgdG9cbiAqIGl0LiBWYWxpZGF0aW5nIGlzIHdoYXQga2VlcHMgYSBtYWxmb3JtZWQgdmFsdWUgZnJvbSBtYWtpbmcgdGhlIGBVUkxgXG4gKiBjb25zdHJ1Y3RvciB0aHJvdyDigJQgd2hpY2ggb24gdGhlIExhbWJkYSBzaGVsbHMgaXMgYW4gaW52b2NhdGlvbiBlcnJvciBhbmQgYVxuICogNTAyLCBub3QgYSByZXNwb25zZS5cbiAqL1xuZnVuY3Rpb24gdmFsaWRBdXRob3JpdHkoXG4gIHZhbHVlOiBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZCxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGNhbmRpZGF0ZSA9IGZpcnN0VmFsdWUodmFsdWUpPy5zcGxpdChcIixcIilbMF0udHJpbSgpO1xuICByZXR1cm4gY2FuZGlkYXRlICYmIEhPU1RfQVVUSE9SSVRZLnRlc3QoY2FuZGlkYXRlKSA/IGNhbmRpZGF0ZSA6IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBgcmVzb2x2ZVJvdXRlc2AgbmVlZHMgYW4gYWJzb2x1dGUgVVJMLCBhbmQgaXQgYmVjb21lcyB0aGUgb3JpZ2luIGV2ZXJ5XG4gKiBhYnNvbHV0ZSBVUkwgdGhlIGFwcCBidWlsZHMgc3RhcnRzIHdpdGgg4oCUIGByZXEubmV4dFVybC5vcmlnaW5gIGluIG1pZGRsZXdhcmUsXG4gKiBgaW5pdFVSTGAgZm9yIGEgcm91dGUgaGFuZGxlciDigJQgc28gaXRzIGhvc3QgaGFzIHRvIGJlIG9uZSB0aGUgY2xpZW50IGNhbm5vdFxuICogcGljay5cbiAqXG4gKiBUaGF0IGlzIGBIb3N0YCBvbiBldmVyeSBkZXBsb3ltZW50IGJ1dCBvbmU6IENsb3VkRnJvbnQgZm9yd2FyZHMgdGhlIHZpZXdlcidzXG4gKiBgSG9zdGAgdG8gYSBjb250YWluZXIgb3JpZ2luIChgQUxMX1ZJRVdFUmApLCBhbiBBTEIgcGFzc2VzIGl0IHRocm91Z2gsIGFuZCBBUElcbiAqIEdhdGV3YXkgc2V0cyBpdHMgb3duIGRvbWFpbi4gVGhlIGV4Y2VwdGlvbiBpcyBhIExhbWJkYSBGdW5jdGlvbiBVUkwsIHdoZXJlXG4gKiBDbG91ZEZyb250IGhhcyB0byBzZW5kIHRoZSBVUkwncyBvd24gZG9tYWluIGFzIGBIb3N0YCBhbmQgcHV0cyB0aGUgdmlld2VyJ3MgaW5cbiAqIGB4LWZvcndhcmRlZC1ob3N0YDsgc2VlIHtAbGluayBSdW50aW1lUmVxdWVzdC50cnVzdEZvcndhcmRlZEhvc3R9LiBBbnl3aGVyZVxuICogZWxzZSB0aGUgaGVhZGVyIGlzIHRoZSBjbGllbnQncywgYW5kIGhvbm9yaW5nIGl0IGxldCBhIHJlcXVlc3Qgd2l0aFxuICogYFgtRm9yd2FyZGVkLUhvc3Q6IGV2aWwuZXhhbXBsZWAgcG9pbnQgYSBwYXNzd29yZC1yZXNldCBsaW5rIGF0IGV2aWwuZXhhbXBsZSDigJRcbiAqIGFuZCwgb24gR2xvYmFsIENvbnRhaW5lcnMsIGhhdmUgQ2xvdWRGcm9udCBjYWNoZSB0aGF0IHBhZ2UsIHNpbmNlIHRoZSBoZWFkZXJcbiAqIGlzIG5vdCBpbiBpdHMgY2FjaGUga2V5LlxuICovXG5mdW5jdGlvbiBhYnNvbHV0ZVVybChyZXF1ZXN0OiBSdW50aW1lUmVxdWVzdCk6IFVSTCB7XG4gIGNvbnN0IGhvc3QgPVxuICAgIChyZXF1ZXN0LnRydXN0Rm9yd2FyZGVkSG9zdFxuICAgICAgPyB2YWxpZEF1dGhvcml0eShyZXF1ZXN0LmhlYWRlcnNbXCJ4LWZvcndhcmRlZC1ob3N0XCJdKVxuICAgICAgOiB1bmRlZmluZWQpID8/XG4gICAgdmFsaWRBdXRob3JpdHkocmVxdWVzdC5oZWFkZXJzLmhvc3QpID8/XG4gICAgXCJsb2NhbGhvc3RcIjtcbiAgLy8gQmVoaW5kIENsb3VkRnJvbnQgb24gR2xvYmFsIENvbnRhaW5lcnMgdGhlIGNvbnRhaW5lciBzaGVsbCBoYXMgYWxyZWFkeSBwdXRcbiAgLy8gdGhlIHZpZXdlcidzIHByb3RvY29sIGhlcmU7IHNlZSBgdHJ1c3RDbG91ZEZyb250UHJvdG9gIGluIGh0dHAvbm9kZS1zZXJ2ZXIudHMuXG4gIGNvbnN0IGZvcndhcmRlZFByb3RvID0gZmlyc3RWYWx1ZShyZXF1ZXN0LmhlYWRlcnNbXCJ4LWZvcndhcmRlZC1wcm90b1wiXSlcbiAgICA/LnNwbGl0KFwiLFwiKVswXVxuICAgIC50cmltKClcbiAgICAudG9Mb3dlckNhc2UoKTtcbiAgLy8gQ2xpZW50LXN1cHBsaWVkIHdoZXJlIG5vIHByb3h5IG92ZXJ3cml0ZXMgaXQsIGJ1dCBoYXJtbGVzczogdGhlIGhvc3QgaXNcbiAgLy8gYWxyZWFkeSBmaXhlZCwgYW5kIGFueXRoaW5nIGJ1dCB0aGVzZSB0d28gd291bGQgbm90IHBhcnNlLlxuICBjb25zdCBwcm90byA9XG4gICAgZm9yd2FyZGVkUHJvdG8gPT09IFwiaHR0cFwiIHx8IGZvcndhcmRlZFByb3RvID09PSBcImh0dHBzXCJcbiAgICAgID8gZm9yd2FyZGVkUHJvdG9cbiAgICAgIDogcmVxdWVzdC5lbmNyeXB0ZWQgPT09IGZhbHNlXG4gICAgICAgID8gXCJodHRwXCJcbiAgICAgICAgOiBcImh0dHBzXCI7XG4gIHJldHVybiBuZXcgVVJMKHJlcXVlc3QudXJsLCBgJHtwcm90b306Ly8ke2hvc3R9YCk7XG59XG5cbmZ1bmN0aW9uIHBpY2tEZWZpbmVkKFxuICBoZWFkZXJzOiBJbmNvbWluZ0h0dHBIZWFkZXJzLFxuICBuYW1lczogcmVhZG9ubHkgc3RyaW5nW10sXG4pOiBJbmNvbWluZ0h0dHBIZWFkZXJzIHtcbiAgY29uc3QgcGlja2VkOiBJbmNvbWluZ0h0dHBIZWFkZXJzID0ge307XG4gIGZvciAoY29uc3QgbmFtZSBvZiBuYW1lcykge1xuICAgIGlmIChoZWFkZXJzW25hbWVdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHBpY2tlZFtuYW1lXSA9IGhlYWRlcnNbbmFtZV07XG4gICAgfVxuICB9XG4gIHJldHVybiBwaWNrZWQ7XG59XG5cbi8qKlxuICogYG5vcm1hbGl6ZVJlcGVhdGVkU2xhc2hlc2AgKGBuZXh0L2Rpc3Qvc2hhcmVkL2xpYi91dGlscy5qc2ApLCBhcHBsaWVkIHdoZXJlXG4gKiBOZXh0LmpzIGFwcGxpZXMgaXQ6IGJlZm9yZSByb3V0aW5nLCBhcyBhIDMwOCB0byB0aGUgY29sbGFwc2VkIHBhdGguXG4gKiBgYmFzZS1zZXJ2ZXIudHNgIGRvZXMgYGlmICh1cmxOb1F1ZXJ5Py5tYXRjaCgvKFxcXFx8XFwvXFwvKS8pKVxuICogcmVzLnJlZGlyZWN0KG5vcm1hbGl6ZVJlcGVhdGVkU2xhc2hlcyhyZXEudXJsKSwgMzA4KWAsIHNvIGAvYS8vYmAgYW5kIGAvYVxcYmBcbiAqIGJvdGggYW5zd2VyIGEgcmVkaXJlY3QgdG8gYC9hL2JgIHJhdGhlciB0aGFuIGEgNDA0IC0gYW5kIGBAbmV4dC9yb3V0aW5nYCdzXG4gKiBgcmVzb2x2ZVJvdXRlc2AgZG9lcyBub3QgZG8gaXQgZm9yIHVzLCB3aGljaCBpcyBob3cgYC8vYCByZWFjaGVkIHRoaXMgcnVudGltZSBhc1xuICogYSA1MDAgYW5kIGAvYXBpLy9qc29uYCBhcyBhIDQwNC5cbiAqXG4gKiBFbmNvZGVkIGJhY2tzbGFzaGVzIGFyZSBsZWZ0IGFsb25lLCBhcyBOZXh0LmpzIGxlYXZlcyB0aGVtOiBgJTVDYCBpcyBhIGxpdGVyYWxcbiAqIGNoYXJhY3RlciBpbiBhIHBhdGggc2VnbWVudCwgbm90IGEgc2VwYXJhdG9yLlxuICpcbiAqIFJldHVybnMgYHVuZGVmaW5lZGAgd2hlbiB0aGVyZSBpcyBub3RoaW5nIHRvIGNvbGxhcHNlLCB3aGljaCBpcyB0aGUgY29tbW9uIGNhc2UuXG4gKi9cbmZ1bmN0aW9uIGNvbGxhcHNlUmVwZWF0ZWRTbGFzaGVzKHRhcmdldDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcGFydHMgPSB0YXJnZXQuc3BsaXQoXCI/XCIpO1xuICBjb25zdCBwYXRobmFtZSA9IHBhcnRzWzBdO1xuICBpZiAoIS9cXFxcfFxcL1xcLy8udGVzdChwYXRobmFtZSkpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IHF1ZXJ5ID0gcGFydHMubGVuZ3RoID4gMSA/IGA/JHtwYXJ0cy5zbGljZSgxKS5qb2luKFwiP1wiKX1gIDogXCJcIjtcbiAgcmV0dXJuIHBhdGhuYW1lLnJlcGxhY2UoL1xcXFwvZywgXCIvXCIpLnJlcGxhY2UoL1xcL1xcLysvZywgXCIvXCIpICsgcXVlcnk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3BsaXRCb2R5IHtcbiAgLyoqIFdoYXQgYHJlcWAgcmVhZHM6IHRoZSBlbnRyeXBvaW50J3MgY29weS4gKi9cbiAgcmVhZG9ubHkgZm9yUmVxdWVzdD86IFJlYWRhYmxlIHwgQnVmZmVyO1xuICAvKiogV2hhdCBgcmVzb2x2ZVJvdXRlc2AgaGFuZHMgbWlkZGxld2FyZS4gKi9cbiAgcmVhZG9ubHkgZm9yRGlzcGF0Y2g6IFJlYWRhYmxlU3RyZWFtO1xuICAvKipcbiAgICogQ2FsbGVkIG9uY2UgZGlzcGF0Y2ggaGFzIHJldHVybmVkLCB3aXRoIHdoZXRoZXIgbWlkZGxld2FyZSBhbnN3ZXJlZCB0aGVcbiAgICogcmVxdWVzdCBpdHNlbGYuIExldHMgZ28gb2Ygd2hpY2hldmVyIGNvcHkgbm90aGluZyB3aWxsIHJlYWQgYW55IG1vcmUuXG4gICAqL1xuICByZWxlYXNlVW5yZWFkKG1pZGRsZXdhcmVSZXNwb25kZWQ6IGJvb2xlYW4pOiB2b2lkO1xufVxuXG4vKipcbiAqIGByZXNvbHZlUm91dGVzYCBoYW5kcyBgcmVxdWVzdEJvZHlgIHRvIG1pZGRsZXdhcmUsIHdoaWNoIGNvbnN1bWVzIGl0LCB3aGlsZSB0aGVcbiAqIGVudHJ5cG9pbnQgbmVlZHMgdGhlIHNhbWUgYnl0ZXMg4oCUIHRoZSBzYW1lIHByb2JsZW0gYG5leHQtc2VydmVyYCBzb2x2ZXMgd2l0aFxuICogYGdldENsb25lYWJsZUJvZHkoKWAuIE9ubHkgc3BsaXQgd2hlbiB0aGVyZSBpcyBtaWRkbGV3YXJlIHRvIGZlZWQ6IHRlZWluZyBjb3N0c1xuICogYSBidWZmZXIgY29weSBvZiBldmVyeSB1cGxvYWQgb24gYSBwYXRoIHRoYXQgd291bGQgb3RoZXJ3aXNlIGJlIGEgc3RyYWlnaHQgcGlwZS5cbiAqXG4gKiBBIGB0ZWUoKWAgYnVmZmVycywgZm9yIHRoZSBicmFuY2ggdGhhdCBpcyBiZWhpbmQsIGV2ZXJ5IGNodW5rIHRoZSBvdGhlciBvbmVcbiAqIGhhcyByZWFkIOKAlCBzbyBhIGJyYW5jaCB0aGF0IGlzIG5ldmVyIHJlYWQgaG9sZHMgdGhlIHdob2xlIGJvZHkuIE1pZGRsZXdhcmVcbiAqIHRoYXQgZG9lc24ndCByZWFkIHRoZSBib2R5IGlzIHRoZSBjb21tb24gY2FzZSAoYW5kIGl0cyBtYXRjaGVyIG1heSBub3QgZXZlblxuICogaGF2ZSBydW4gaXQpLCBhZnRlciB3aGljaCB0aGUgZW50cnlwb2ludCBzdHJlYW1pbmcgYW4gdXBsb2FkIHdvdWxkIHBpbGUgYWxsXG4gKiBvZiBpdCB1cCBpbiB0aGUgbWlkZGxld2FyZSBicmFuY2g6IHRoZSB3aG9sZSB1cGxvYWQgaW4gbWVtb3J5LCBvbiBhXG4gKiBjb250YWluZXIgdGhhdCBzZXJ2ZXMgb3RoZXIgcmVxdWVzdHMuIFNvIG9uY2UgZGlzcGF0Y2ggcmV0dXJucywgdGhlIGJyYW5jaFxuICogd2l0aCBubyByZWFkZXIgbGVmdCBpcyBjYW5jZWxsZWQg4oCUIHRoZSBtaWRkbGV3YXJlIG9uZSwgb3IgdGhlIGVudHJ5cG9pbnQgb25lXG4gKiB3aGVuIG1pZGRsZXdhcmUgYW5zd2VyZWQgYW5kIGByZXFgIHdpbGwgbmV2ZXIgYmUgcmVhZC4gQ2FuY2VsbGluZyBvbmVcbiAqIGJyYW5jaCBsZWF2ZXMgdGhlIHNvdXJjZSBhbmQgdGhlIG90aGVyIGJyYW5jaCBydW5uaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc3BsaXRCb2R5KFxuICBib2R5OiBSZWFkYWJsZSB8IEJ1ZmZlciB8IHVuZGVmaW5lZCxcbiAgaGFzTWlkZGxld2FyZTogYm9vbGVhbixcbik6IFNwbGl0Qm9keSB7XG4gIGNvbnN0IHJlbGVhc2VOb3RoaW5nID0gKCk6IHZvaWQgPT4ge307XG4gIGlmIChib2R5ID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgZm9yRGlzcGF0Y2g6IG5ldyBCbG9iKFtdKS5zdHJlYW0oKSxcbiAgICAgIHJlbGVhc2VVbnJlYWQ6IHJlbGVhc2VOb3RoaW5nLFxuICAgIH07XG4gIH1cbiAgaWYgKCFoYXNNaWRkbGV3YXJlKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZvclJlcXVlc3Q6IGJvZHksXG4gICAgICBmb3JEaXNwYXRjaDogbmV3IEJsb2IoW10pLnN0cmVhbSgpLFxuICAgICAgcmVsZWFzZVVucmVhZDogcmVsZWFzZU5vdGhpbmcsXG4gICAgfTtcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKGJvZHkpKSB7XG4gICAgLy8gQWxyZWFkeSBmdWxseSBpbiBtZW1vcnksIHNvIFwidGVlaW5nXCIgaXMganVzdCByZWFkaW5nIGl0IHR3aWNlLlxuICAgIHJldHVybiB7XG4gICAgICBmb3JSZXF1ZXN0OiBib2R5LFxuICAgICAgZm9yRGlzcGF0Y2g6IG5ldyBCbG9iKFtib2R5XSkuc3RyZWFtKCksXG4gICAgICByZWxlYXNlVW5yZWFkOiByZWxlYXNlTm90aGluZyxcbiAgICB9O1xuICB9XG4gIGNvbnN0IFtmb3JNaWRkbGV3YXJlLCBmb3JFbnRyeXBvaW50XSA9IFJlYWRhYmxlLnRvV2ViKGJvZHkpLnRlZSgpO1xuICBjb25zdCBmb3JSZXF1ZXN0ID0gUmVhZGFibGUuZnJvbVdlYihmb3JFbnRyeXBvaW50IGFzIG5ldmVyKTtcbiAgcmV0dXJuIHtcbiAgICBmb3JSZXF1ZXN0LFxuICAgIGZvckRpc3BhdGNoOiBmb3JNaWRkbGV3YXJlIGFzIFJlYWRhYmxlU3RyZWFtLFxuICAgIHJlbGVhc2VVbnJlYWQobWlkZGxld2FyZVJlc3BvbmRlZCkge1xuICAgICAgaWYgKG1pZGRsZXdhcmVSZXNwb25kZWQpIHtcbiAgICAgICAgLy8gYGZyb21XZWJgIGhvbGRzIHRoZSBicmFuY2gncyByZWFkZXIsIHNvIGl0IGlzIGRlc3Ryb3llZCByYXRoZXIgdGhhblxuICAgICAgICAvLyBjYW5jZWxsZWQ7IGl0cyBgX2Rlc3Ryb3lgIGNhbmNlbHMgdGhlIHJlYWRlci5cbiAgICAgICAgZm9yUmVxdWVzdC5kZXN0cm95KCk7XG4gICAgICB9IGVsc2UgaWYgKCFmb3JNaWRkbGV3YXJlLmxvY2tlZCkge1xuICAgICAgICAvLyBMb2NrZWQgbWVhbnMgbWlkZGxld2FyZSB0b29rIGEgcmVhZGVyOiBpdCBpcyByZWFkaW5nLCBvciBoYXMgcmVhZCxcbiAgICAgICAgLy8gdGhlIGJvZHkgaXRzZWxmLCBhbmQgYSBsb2NrZWQgc3RyZWFtIGNhbm5vdCBiZSBjYW5jZWxsZWQgYW55d2F5LlxuICAgICAgICBmb3JNaWRkbGV3YXJlLmNhbmNlbCgpLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgIH1cbiAgICB9LFxuICB9O1xufVxuXG4vKiogYEluY29taW5nSHR0cEhlYWRlcnNgIOKGkiB0aGUgZmxhdCBlbnRyaWVzIGEgYEhlYWRlcnNgIGNvbnN0cnVjdG9yIGFjY2VwdHMuICovXG5mdW5jdGlvbiB0b1dlYkhlYWRlcnMoaGVhZGVyczogSW5jb21pbmdIdHRwSGVhZGVycyk6IEFycmF5PFtzdHJpbmcsIHN0cmluZ10+IHtcbiAgY29uc3QgZW50cmllczogQXJyYXk8W3N0cmluZywgc3RyaW5nXT4gPSBbXTtcbiAgZm9yIChjb25zdCBbbmFtZSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGhlYWRlcnMpKSB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IHNpbmdsZSBvZiBBcnJheS5pc0FycmF5KHZhbHVlKSA/IHZhbHVlIDogW3ZhbHVlXSkge1xuICAgICAgZW50cmllcy5wdXNoKFtuYW1lLCBzaW5nbGVdKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGVudHJpZXM7XG59XG5cbi8qKlxuICogYGhlYWRlcnMoKWAgcnVsZXMsIHRoZSBpbW11dGFibGUgYGNhY2hlLWNvbnRyb2xgIGZvciBidWlsZCBhc3NldHMsIGFuZCBhbnl0aGluZ1xuICogbWlkZGxld2FyZSBzZXQgd2l0aCBgTmV4dFJlc3BvbnNlLm5leHQoeyBoZWFkZXJzIH0pYC4gQXBwbGllZCBiZWZvcmUgdGhlXG4gKiBlbnRyeXBvaW50IHJ1bnMgc28gdGhhdCBhIHJvdXRlIGNhbiBzdGlsbCBvdmVycmlkZSBpdHMgb3duLlxuICovXG5mdW5jdGlvbiBhcHBseUhlYWRlcnMocmVzOiBTaGltU2VydmVyUmVzcG9uc2UsIGhlYWRlcnM6IEhlYWRlcnMpOiB2b2lkIHtcbiAgZm9yIChjb25zdCBbbmFtZSwgdmFsdWVdIG9mIGhlYWRlcnMuZW50cmllcygpKSB7XG4gICAgLy8gYGVudHJpZXMoKWAgeWllbGRzIGBzZXQtY29va2llYCBvbmNlIHBlciBjb29raWUsIHNvIGFwcGVuZGluZyB0aGUgd2hvbGVcbiAgICAvLyBgZ2V0U2V0Q29va2llKClgIGFycmF5IGhlcmUgd291bGQgZW1pdCBOwrIgb2YgdGhlbSDigJQgdHdvIGNvb2tpZXMgc2V0IGJ5XG4gICAgLy8gbWlkZGxld2FyZSBhcnJpdmVkIGFzIFtcImE9MVwiLFwiYj0yXCIsXCJhPTFcIixcImI9MlwiXS4gSGFuZGxlZCBvbmNlLCBvdXRzaWRlLlxuICAgIGlmIChuYW1lID09PSBcInNldC1jb29raWVcIikge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHJlcy5zZXRIZWFkZXIobmFtZSwgdmFsdWUpO1xuICB9XG4gIGZvciAoY29uc3QgY29va2llIG9mIGhlYWRlcnMuZ2V0U2V0Q29va2llKCkpIHtcbiAgICByZXMuYXBwZW5kSGVhZGVyKFwic2V0LWNvb2tpZVwiLCBjb29raWUpO1xuICB9XG59XG5cbi8qKlxuICogTWlycm9ycyBOZXh0LmpzJ3Mgb3duIHJlZGlyZWN0IHJlc3BvbnNlIChgYmFzZS1zZXJ2ZXIudHNgKTogdGhlIGRlc3RpbmF0aW9uIGlzXG4gKiBhbHNvIHRoZSBib2R5LCBhbmQgYSAzMDggY2FycmllcyBhIGBSZWZyZXNoYCBoZWFkZXIgYmVjYXVzZSBzb21lIGNsaWVudHMgYW5kXG4gKiBpbnRlcm1lZGlhcmllcyBzdGlsbCBkbyBub3QgaW1wbGVtZW50IDMwOC5cbiAqL1xuZnVuY3Rpb24gc2VuZFJlZGlyZWN0KFxuICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgbG9jYXRpb246IHN0cmluZyxcbiAgc3RhdHVzOiBudW1iZXIsXG4pOiB2b2lkIHtcbiAgcmVzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XG4gIHJlcy5zZXRIZWFkZXIoXCJMb2NhdGlvblwiLCBsb2NhdGlvbik7XG4gIGlmIChzdGF0dXMgPT09IDMwOCkge1xuICAgIHJlcy5zZXRIZWFkZXIoXCJSZWZyZXNoXCIsIGAwO3VybD0ke2xvY2F0aW9ufWApO1xuICB9XG4gIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgXCJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04XCIpO1xuICByZXMuZW5kKGxvY2F0aW9uKTtcbn1cblxuLyoqXG4gKiBgbmV4dCBzdGFydGAncyBhbnN3ZXIgdG8gYSBQT1NULCBQVVQgb3IgREVMRVRFIGZvciBhIHN0YXRpYyBmaWxlOiA0MDUgd2l0aFxuICogYEFsbG93OiBHRVQsIEhFQURgIChgcm91dGVyLXNlcnZlci5qc2ApLiBJdCByZW5kZXJzIHRoYXQgdGhyb3VnaCBgL19lcnJvcmA7XG4gKiB0aGlzIGlzIHRoZSBwbGFpbi10ZXh0IGVxdWl2YWxlbnQsIHNpbmNlIHRoZSBzdGF0dXMgYW5kIGBBbGxvd2AgYXJlIHdoYXQgYVxuICogY2xpZW50IGFjdHMgb24uXG4gKi9cbmZ1bmN0aW9uIHNlbmRNZXRob2ROb3RBbGxvd2VkKHJlczogU2hpbVNlcnZlclJlc3BvbnNlKTogdm9pZCB7XG4gIHJlcy5zdGF0dXNDb2RlID0gNDA1O1xuICByZXMuc2V0SGVhZGVyKFwiQWxsb3dcIiwgXCJHRVQsIEhFQURcIik7XG4gIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgXCJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04XCIpO1xuICByZXMuZW5kKFwiTWV0aG9kIE5vdCBBbGxvd2VkXCIpO1xufVxuXG4vKipcbiAqIFJlcXVlc3QgaGVhZGVycyB7QGxpbmsgcHJveHlFeHRlcm5hbH0gZG9lcyBub3QgZm9yd2FyZC4gVGhlIHVwc3RyZWFtJ3Mgb3duXG4gKiBgSG9zdGAgbXVzdCB3aW47IHRoZSByZXN0IGRlc2NyaWJlIG91ciBjb25uZWN0aW9uLCBub3QgdGhlIHByb3hpZWQgb25lLCBhbmRcbiAqIHVuZGljaSB0aHJvd3Mgb24gbW9zdCBvZiB0aGVtLCB3aGljaCB3b3VsZCBhbnN3ZXIgdGhlIHJlcXVlc3Qgd2l0aCBhIDUwMC5cbiAqIE5leHQuanMncyBsaXN0IGZvciB0aGUgcmVxdWVzdHMgaXQgbWFrZXMgd2l0aCB1bmRpY2kgKGBpcGNGb3JiaWRkZW5IZWFkZXJzYCxcbiAqIGBuZXh0L2Rpc3Qvc2VydmVyL2xpYi9zZXJ2ZXItaXBjL3V0aWxzLmpzYCksIHBsdXMgYGhvc3RgIGFuZCBgdXBncmFkZWAsIG1pbnVzXG4gKiBgY29udGVudC1lbmNvZGluZ2A6IE5leHQgc3RyaXBzIHRoYXQgb3ZlciBhIGJvZHkgaXQgaGFzIGFscmVhZHkgZGVjb2RlZCwgd2hpbGVcbiAqIHRoaXMgb25lIGlzIGZvcndhcmRlZCBhcyByZWNlaXZlZCwgc3RpbGwgZW5jb2RlZC5cbiAqL1xuY29uc3QgUFJPWFlfRFJPUFBFRF9IRUFERVJTOiByZWFkb25seSBzdHJpbmdbXSA9IFtcbiAgXCJob3N0XCIsXG4gIFwidXBncmFkZVwiLFxuICBcImFjY2VwdC1lbmNvZGluZ1wiLFxuICBcImtlZXBhbGl2ZVwiLFxuICBcImtlZXAtYWxpdmVcIixcbiAgXCJ0cmFuc2Zlci1lbmNvZGluZ1wiLFxuICBcImNvbm5lY3Rpb25cIixcbiAgXCJleHBlY3RcIixcbl07XG5cbi8qKlxuICogVGhlIFNpZ1Y0IHNpZ25hdHVyZSBPcmlnaW4gQWNjZXNzIENvbnRyb2wgcHV0IG9uIGEgcmVxdWVzdCB0byB0aGUgRnVuY3Rpb25cbiAqIFVSTCwgYWxzbyBkcm9wcGVkIGJ5IHtAbGluayBwcm94eUV4dGVybmFsfSB3aGVuIHRoZSByZXF1ZXN0IHdhcyBJQU0tdmVyaWZpZWQ6XG4gKiBmb3J3YXJkZWQsIGl0IHdvdWxkIGxldCB0aGUgdGhpcmQtcGFydHkgb3JpZ2luIHJlcGxheSB0aGUgcmVxdWVzdCBhZ2FpbnN0XG4gKiB0aGUgRnVuY3Rpb24gVVJMLiBBbnl3aGVyZSBlbHNlIHRoZXNlIGFyZSB0aGUgY2xpZW50J3Mgb3duLCBhbmQgYXJlXG4gKiBmb3J3YXJkZWQgYXMgYG5leHQgc3RhcnRgIGZvcndhcmRzIHRoZW0uXG4gKi9cbmNvbnN0IFNJR1Y0X0hFQURFUlM6IHJlYWRvbmx5IHN0cmluZ1tdID0gW1xuICBcImF1dGhvcml6YXRpb25cIixcbiAgXCJ4LWFtei1kYXRlXCIsXG4gIFwieC1hbXotY29udGVudC1zaGEyNTZcIixcbiAgXCJ4LWFtei1zZWN1cml0eS10b2tlblwiLFxuXTtcblxuLyoqIEEgYG5leHQuY29uZmlnYCByZXdyaXRlIHdob3NlIGRlc3RpbmF0aW9uIGlzIGFub3RoZXIgb3JpZ2luLiAqL1xuYXN5bmMgZnVuY3Rpb24gcHJveHlFeHRlcm5hbChcbiAgcmVxOiBTaGltSW5jb21pbmdNZXNzYWdlLFxuICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgdXJsOiBVUkwsXG4gIHJlcXVlc3RIZWFkZXJzOiBIZWFkZXJzLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IG1ldGhvZCA9IHJlcS5tZXRob2QgPz8gXCJHRVRcIjtcbiAgY29uc3QgaGFzQm9keSA9IG1ldGhvZCAhPT0gXCJHRVRcIiAmJiBtZXRob2QgIT09IFwiSEVBRFwiO1xuICBjb25zdCBoZWFkZXJzID0gbmV3IEhlYWRlcnMocmVxdWVzdEhlYWRlcnMpO1xuICBmb3IgKGNvbnN0IG5hbWUgb2YgUFJPWFlfRFJPUFBFRF9IRUFERVJTKSB7XG4gICAgaGVhZGVycy5kZWxldGUobmFtZSk7XG4gIH1cbiAgaWYgKHJlcS50cnVzdEZvcndhcmRlZEhvc3QpIHtcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgU0lHVjRfSEVBREVSUykge1xuICAgICAgaGVhZGVycy5kZWxldGUobmFtZSk7XG4gICAgfVxuICB9XG4gIGNvbnN0IHVwc3RyZWFtID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgbWV0aG9kLFxuICAgIGhlYWRlcnMsXG4gICAgYm9keTogaGFzQm9keSA/IChSZWFkYWJsZS50b1dlYihyZXEpIGFzIFJlYWRhYmxlU3RyZWFtKSA6IHVuZGVmaW5lZCxcbiAgICByZWRpcmVjdDogXCJtYW51YWxcIixcbiAgICAuLi4oaGFzQm9keSA/IHsgZHVwbGV4OiBcImhhbGZcIiB9IDoge30pLFxuICB9IGFzIFJlcXVlc3RJbml0KTtcbiAgYXdhaXQgc2VuZFdlYlJlc3BvbnNlKHJlcywgdXBzdHJlYW0pO1xufVxuXG4vKipcbiAqIEhlYWRlcnMgZGVzY3JpYmluZyB0aGUgZnJhbWluZyBvZiBhIGJvZHkgdGhhdCBpcyBubyBsb25nZXIgdGhlIGJvZHkgYmVpbmdcbiAqIHNlbnQsIGRyb3BwZWQgZnJvbSBldmVyeSBgUmVzcG9uc2VgIHtAbGluayBzZW5kV2ViUmVzcG9uc2V9IGZvcndhcmRzLlxuICpcbiAqIEEgcHJveGllZCBvcmlnaW4ncyBgUmVzcG9uc2VgIGNhbWUgYmFjayBmcm9tIGBmZXRjaGAsIGFuZCBzbywgb2Z0ZW4sIGRpZFxuICogbWlkZGxld2FyZSdzIG93biAoYHJldHVybiBmZXRjaCh1cHN0cmVhbSlgIGluIGBwcm94eS50c2AsIHNpbmNlIG1pZGRsZXdhcmVcbiAqIHJ1bnMgaW4gcHJvY2VzcyBhbmQgaXRzIGBmZXRjaGAgaXMgdW5kaWNpKS4gdW5kaWNpIGRlY29kZXMgdGhlIGJvZHkg4oCUIGd6aXAsXG4gKiBkZWZsYXRlLCBiciwgenN0ZCDigJQgYW5kIGxlYXZlcyBgY29udGVudC1lbmNvZGluZ2AgYW5kIGBjb250ZW50LWxlbmd0aGBcbiAqIGRlc2NyaWJpbmcgdGhlIGVuY29kZWQgYnl0ZXMgaXQgYWxyZWFkeSB0aHJldyBhd2F5LiBGb3J3YXJkaW5nIHRoZW0gZW1pdHNcbiAqIHBsYWludGV4dCBsYWJlbGxlZCBgZ3ppcGAgKHRoZSBicm93c2VyIGZhaWxzIHRoZSB3aG9sZSByZXNwb25zZSB3aXRoXG4gKiBgRVJSX0NPTlRFTlRfREVDT0RJTkdfRkFJTEVEYCkgdW5kZXIgYSBgQ29udGVudC1MZW5ndGhgIHRoYXQgaXMgdG9vIHNob3J0LFxuICogYW5kIGBzaG91bGRHemlwYCB0aGVuIGRlY2xpbmVzIHRvIGNvbXByZXNzIGl0IGJlY2F1c2UgYGNvbnRlbnQtZW5jb2RpbmdgIGlzXG4gKiBhbHJlYWR5IHNldCwgc28gbm90aGluZyBkb3duc3RyZWFtIHJlcGFpcnMgaXQuIGB0cmFuc2Zlci1lbmNvZGluZ2AgaXNcbiAqIGhvcC1ieS1ob3A6IGl0IGRlc2NyaWJlZCB0aGUgdXBzdHJlYW0gY29ubmVjdGlvbiwgbm90IHRoaXMgb25lLlxuICpcbiAqIFN0b2NrIE5leHQuanMgZHJvcHMgdGhlIHNhbWUgdGhyZWUgZnJvbSBldmVyeSBtaWRkbGV3YXJlIHJlc3BvbnNlXG4gKiAoYEZPUkJJRERFTl9IRUFERVJTYCBpbiBgbmV4dC9kaXN0L3NlcnZlci93ZWIvc2FuZGJveC9zYW5kYm94LmpzYCksIHNvXG4gKiBtaWRkbGV3YXJlIGNhbm5vdCBsYWJlbCBhIGJvZHkgaXQgZW5jb2RlZCBpdHNlbGYgdGhlcmUgZWl0aGVyLlxuICovXG5jb25zdCBTVEFMRV9GUkFNSU5HX0hFQURFUlM6IFJlYWRvbmx5U2V0PHN0cmluZz4gPSBuZXcgU2V0KFtcbiAgXCJjb250ZW50LWVuY29kaW5nXCIsXG4gIFwiY29udGVudC1sZW5ndGhcIixcbiAgXCJ0cmFuc2Zlci1lbmNvZGluZ1wiLFxuXSk7XG5cbi8qKiBTdHJlYW0gYSBgUmVzcG9uc2VgIOKAlCBtaWRkbGV3YXJlJ3Mgb3duLCBvciBhIHByb3hpZWQgb3JpZ2luJ3Mg4oCUIGludG8gYHJlc2AuICovXG5hc3luYyBmdW5jdGlvbiBzZW5kV2ViUmVzcG9uc2UoXG4gIHJlczogU2hpbVNlcnZlclJlc3BvbnNlLFxuICByZXNwb25zZTogUmVzcG9uc2UsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmVzLnN0YXR1c0NvZGUgPSByZXNwb25zZS5zdGF0dXM7XG4gIGlmIChyZXNwb25zZS5zdGF0dXNUZXh0KSB7XG4gICAgcmVzLnN0YXR1c01lc3NhZ2UgPSByZXNwb25zZS5zdGF0dXNUZXh0O1xuICB9XG4gIGNvbnN0IGhlYWRlcnMgPSBuZXcgSGVhZGVycyhyZXNwb25zZS5oZWFkZXJzKTtcbiAgZm9yIChjb25zdCBuYW1lIG9mIFNUQUxFX0ZSQU1JTkdfSEVBREVSUykge1xuICAgIGhlYWRlcnMuZGVsZXRlKG5hbWUpO1xuICB9XG4gIGFwcGx5SGVhZGVycyhyZXMsIGhlYWRlcnMpO1xuICBpZiAoIXJlc3BvbnNlLmJvZHkpIHtcbiAgICByZXMuZW5kKCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGZvciBhd2FpdCAoY29uc3QgY2h1bmsgb2YgcmVzcG9uc2UuYm9keSBhcyB1bmtub3duIGFzIEFzeW5jSXRlcmFibGU8VWludDhBcnJheT4pIHtcbiAgICAvLyBMZWF2aW5nIHRoZSBsb29wIGNhbmNlbHMgdGhlIGJvZHksIHdoaWNoIGlzIHdoYXQgc3RvcHMgYSBwcm94aWVkIG9yaWdpblxuICAgIC8vIGZyb20gYmVpbmcgcmVhZCB0byB0aGUgZW5kIGZvciBhIGNsaWVudCB0aGF0IGhhcyBhbHJlYWR5IGdvbmUuXG4gICAgaWYgKHJlcy5kZXN0cm95ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gUGFjZWQgYnkgdGhlIGNsaWVudDogd2l0aG91dCB3YWl0aW5nIGZvciBgZHJhaW5gLCBhIGxhcmdlIHByb3hpZWQgYm9keVxuICAgIC8vIGhlYWRlZCBmb3IgYSBzbG93IGNsaWVudCBpcyBidWZmZXJlZCB3aG9sZSBpbiBtZW1vcnkuXG4gICAgY29uc3QgYWNjZXB0ZWQgPSByZXMud3JpdGUoY2h1bmspO1xuICAgIC8vIFNldCBieSB0aGUgc2luayB3aGVuIGl0IGNvbXByZXNzZXMuIFdpdGhvdXQgaXQgdGhlIGNodW5rIHNpdHMgaW4gemxpYidzXG4gICAgLy8gYnVmZmVyLCBhbmQgYSBzdHJlYW1lZCBib2R5IOKAlCBzZXJ2ZXItc2VudCBldmVudHMgdGhyb3VnaCBhIHJld3JpdGUsIGFcbiAgICAvLyBtaWRkbGV3YXJlIGBSZWFkYWJsZVN0cmVhbWAg4oCUIHJlYWNoZXMgdGhlIGNsaWVudCBhbGwgYXQgb25jZSwgYXQgdGhlIGVuZC5cbiAgICAvLyBOZXh0LmpzIGZsdXNoZXMgYWZ0ZXIgZXZlcnkgY2h1bmsgZm9yIHRoZSBzYW1lIHJlYXNvbiAoYHBpcGUtcmVhZGFibGVgKS5cbiAgICByZXMuZmx1c2g/LigpO1xuICAgIGlmICghYWNjZXB0ZWQgJiYgIShhd2FpdCBkcmFpbmVkKHJlcykpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG4gIHJlcy5lbmQoKTtcbn1cbiJdfQ==