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
@@ -4,30 +4,91 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.NextjsBuild = void 0;
7
+ exports.deploymentArchitecture = deploymentArchitecture;
8
+ exports.deploymentBuildId = deploymentBuildId;
9
+ exports.pickStagedSharpPackage = pickStagedSharpPackage;
10
+ exports.resolveNextSharp = resolveNextSharp;
11
+ exports.isSharpBinaryPackage = isSharpBinaryPackage;
12
+ exports.sharpBinaryDir = sharpBinaryDir;
13
+ exports.listTree = listTree;
14
+ exports.writePublicFileList = writePublicFileList;
15
+ exports.storedSize = storedSize;
16
+ exports.patchClientChunk = patchClientChunk;
7
17
  const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
8
18
  const node_child_process_1 = require("node:child_process");
9
19
  const node_crypto_1 = require("node:crypto");
10
20
  const node_fs_1 = require("node:fs");
21
+ const node_module_1 = require("node:module");
11
22
  const node_os_1 = require("node:os");
12
23
  const node_path_1 = require("node:path");
13
24
  const posix_1 = require("node:path/posix");
14
25
  const constructs_1 = require("constructs");
15
26
  // eslint-disable-next-line import/no-extraneous-dependencies
16
27
  const debug_1 = __importDefault(require("debug"));
28
+ const function_groups_1 = require("../adapter/function-groups");
17
29
  const constants_1 = require("../constants");
30
+ const manifest_1 = require("../runtime/manifest");
31
+ const public_files_1 = require("../runtime/public-files");
18
32
  const base_path_1 = require("../utils/base-path");
19
- const experimental_flags_1 = require("../utils/experimental-flags");
20
33
  const get_architecture_1 = require("../utils/get-architecture");
34
+ /**
35
+ * Lambda's hard limit on the unzipped size of a function's code, which
36
+ * CloudFormation only enforces at deploy time. Measured at synth instead, so the
37
+ * error names the group and arrives in seconds rather than minutes.
38
+ * @see https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html
39
+ */
40
+ const LAMBDA_UNZIPPED_LIMIT_BYTES = 250 * 1024 * 1024;
41
+ /**
42
+ * Opens the patch `patchFetchInClientJs` prepends to a client chunk, followed by
43
+ * a hash of the patch itself, so a second synth over the same `.next` is a no-op
44
+ * while one by a cdk-nextjs with a different `patch-fetch.js` replaces it.
45
+ */
46
+ const PATCH_FETCH_MARKER = "/* cdk-nextjs:patch-fetch";
47
+ /** Closes the prepended patch; the chunk's own content starts after it. */
48
+ const PATCH_FETCH_END_MARKER = "/* cdk-nextjs:patch-fetch:end */";
21
49
  const debug = (0, debug_1.default)("cdk-nextjs:nextjs-build");
50
+ /**
51
+ * What every deployment root is staged for: the build's `architecture`, else
52
+ * the synth machine's. Containers ignore it: Docker builds their image
53
+ * natively, so it can only match the synth machine.
54
+ */
55
+ function deploymentArchitecture(props) {
56
+ const isFunctions = props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS ||
57
+ props.nextjsType === constants_1.NextjsType.REGIONAL_FUNCTIONS;
58
+ return (isFunctions && props.architecture) || (0, get_architecture_1.getLambdaArchitecture)();
59
+ }
60
+ /** {@link NextjsBuild.buildId}: Next.js's build ID, suffixed with the app's `deploymentId`. */
61
+ function deploymentBuildId(manifest) {
62
+ const { deploymentId } = manifest.config;
63
+ return deploymentId
64
+ ? `${manifest.buildId}-${deploymentId}`
65
+ : manifest.buildId;
66
+ }
22
67
  /**
23
68
  * Builds Next.js assets.
24
69
  * @link https://nextjs.org/docs/pages/api-reference/next-config-js/output
25
70
  */
26
71
  class NextjsBuild extends constructs_1.Construct {
27
- static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-nextjs.NextjsBuild", version: "0.6.2" };
72
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-nextjs.NextjsBuild", version: "0.7.1" };
28
73
  /**
29
- * Unique id for Next.js build. Used to partition cache storage and as
74
+ * Unique id for this deployment. Used to partition cache storage and as
30
75
  * metadata for static assets in S3 bucket.
76
+ *
77
+ * Next.js's build ID, suffixed with the app's `deploymentId` when it sets
78
+ * one. The build ID alone is not unique per deployment: setting
79
+ * `deploymentId` (or building with `NEXT_DEPLOYMENT_ID`) turns on skew
80
+ * protection, and next.js then *pins* the build ID to the constant
81
+ * `build-TfctsWXpff2fKS` — see `getBuildId` in `next/dist/build/index.js`,
82
+ * which does that deliberately so that tooling doing
83
+ * `.replace(escapedBuildId, …)` still has something to replace. Two
84
+ * successive deployments of such an app would share one cache prefix and one
85
+ * revalidation-table partition, and the new one would read the previous
86
+ * one's prerenders. Appending the deployment ID restores the "one
87
+ * deployment, one partition" invariant that ID exists to carry.
88
+ *
89
+ * Nothing routes on this value — the `/_next/data/<buildId>/…` URL space is
90
+ * routed on Next.js's own build ID, which is what the app's client bundles
91
+ * carry — so it is free to be longer than next.js's own.
31
92
  */
32
93
  buildId;
33
94
  /**
@@ -41,39 +102,71 @@ class NextjsBuild extends constructs_1.Construct {
41
102
  */
42
103
  publicDirEntries;
43
104
  /**
44
- * The entrypoint JavaScript file used as an argument for Node.js to run the
45
- * Next.js standalone server relative to the standalone directory.
46
- * @example "./server.js"
47
- * @example "./packages/ui/server.js" (monorepo)
105
+ * The JavaScript file Node.js runs to serve requests, relative to the
106
+ * deployment root. cdk-nextjs's own container shell, not `next build` output,
107
+ * so it is the same path for every app.
108
+ * @example "cdk-nextjs-runtime/server.mjs"
48
109
  */
49
110
  relativePathToEntrypoint;
50
- /**
51
- * Relative path from the standalone directory to the package containing the Next.js app.
52
- * This is automatically detected from the standalone build output.
53
- * @example "." for non-monorepo apps
54
- * @example "./apps/web" for monorepo apps
55
- */
56
- relativePathToPackage;
57
111
  /**
58
112
  * Absolute path to the .next directory containing Next.js build artifacts
59
113
  */
60
114
  dotNextPath;
61
115
  /**
62
116
  * The Next.js app's own `basePath` — the URL prefix it generates its links and
63
- * asset hrefs under — read out of the build's `required-server-files.json`.
64
- * Normalized to a bare path segment, empty when the app sets none. Exposed so
117
+ * asset hrefs under — as the adapter manifest recorded it. Normalized to a bare path segment, empty when the app sets none. Exposed so
65
118
  * root constructs can reconcile it with the CDK `basePath` prop, which is a
66
119
  * distinct thing; see `resolveBasePath`.
67
120
  */
68
121
  nextConfigBasePath;
69
122
  /**
70
- * Absolute path to the directory prepared for the image optimization Lambda
71
- * asset: bundled handler, glibc `sharp` binaries, and `required-server-files.json`.
72
- * Only set for {@link NextjsType.GLOBAL_FUNCTIONS} and
73
- * {@link NextjsType.REGIONAL_FUNCTIONS}, and only when the dedicated image
74
- * optimization Lambda is enabled.
123
+ * The Next.js app's own `assetPrefix`, as a path with a leading slash and no
124
+ * trailing one, empty when the app sets none or sets an absolute URL (which
125
+ * names an origin cdk-nextjs does not serve).
126
+ *
127
+ * Exposed because it is the shape of `assetPrefix` the regional
128
+ * `NextjsType`s cannot serve — see `warnUnservedAssetPrefix`. What the
129
+ * distribution has to answer on is {@link nextConfigAssetPrefixPath}, which
130
+ * also covers the path an absolute prefix carries.
131
+ */
132
+ nextConfigAssetPrefix;
133
+ /**
134
+ * The path portion of the app's `assetPrefix`, whichever form it takes: "/cdn"
135
+ * for both `assetPrefix: "/cdn"` and `assetPrefix:
136
+ * "https://cdn.example.com/cdn"`, empty when there is no path to answer on.
137
+ *
138
+ * Exposed because it is a URL prefix the distribution has to answer on: Next.js
139
+ * emits `<assetPrefix>/_next/static/...` for every bundle and compiles a rewrite
140
+ * that serves those URLs' paths itself, while the objects live in S3 under
141
+ * `<basePath>/_next/static/...`.
142
+ */
143
+ nextConfigAssetPrefixPath;
144
+ /**
145
+ * Every staged deployment root, one per function group, `default` first: the
146
+ * staged union of each group's shipped outputs and their traced assets,
147
+ * written by the adapter's `onBuildComplete`. Exactly one entry (named
148
+ * `default`, at `.next/cdk-nextjs-adapter/app`) unless `functionGroups`
149
+ * splits the app. The Lambda zip assets; Containers `COPY` the `default` one.
75
150
  */
76
- imageOptimizationAssetPath;
151
+ deploymentRoots;
152
+ /**
153
+ * What routes each non-default function group's URLs to it, most specific
154
+ * first — the order CloudFront has to see them in, since it stops at the
155
+ * first match. Empty unless `functionGroups` splits the app.
156
+ */
157
+ functionGroupBehaviors;
158
+ /**
159
+ * From the deployment root to the Next.js project dir, POSIX, `""` when
160
+ * the app is at the repo root. The runtime `chdir`s here; Containers pass it to
161
+ * their Dockerfile so `.next/static` and `public` land in the same place.
162
+ * @see AdapterManifest.relativeProjectDir
163
+ */
164
+ relativeProjectDir;
165
+ /**
166
+ * The architecture every deployment root's native dependencies (`sharp`)
167
+ * were staged for. The Lambdas deploying them must use the same one.
168
+ */
169
+ architecture;
77
170
  props;
78
171
  buildCommand;
79
172
  constructor(scope, id, props) {
@@ -83,6 +176,14 @@ class NextjsBuild extends constructs_1.Construct {
83
176
  this.buildCommand = props.buildCommand || "npm run build";
84
177
  // Set init cache directory path
85
178
  this.initCacheDir = (0, node_path_1.join)(props.buildDirectory, ".next", "cdk-nextjs-init-cache");
179
+ // Before the build, not after it: the build is minutes long, and the env var
180
+ // it passes groups through is only set for a non-empty array — so an invalid
181
+ // `functionGroups` (an empty array, a reserved name, a group owning no
182
+ // routes) would otherwise be reported as "the build staged the wrong
183
+ // groups", after paying for the build, instead of as the prop error it is.
184
+ if (props.functionGroups) {
185
+ (0, function_groups_1.validateFunctionGroups)(props.functionGroups);
186
+ }
86
187
  // Execute local build process
87
188
  if (props.skipBuild !== true) {
88
189
  this.runNextBuild();
@@ -90,36 +191,247 @@ class NextjsBuild extends constructs_1.Construct {
90
191
  else {
91
192
  debug(`${constants_1.LOG_PREFIX} Skipping: ${this.buildCommand}`);
92
193
  }
93
- // Validate build output and set validated paths
94
- this.validateNextBuildOutput();
95
- // Auto-detect relativePathToPackage from standalone build output
96
- this.relativePathToPackage = this.findRelativePathToServerJs();
97
- // Set entrypoint path using detected relativePathToPackage
98
- this.relativePathToEntrypoint = (0, posix_1.join)(this.relativePathToPackage === "." ? "" : this.relativePathToPackage, "server.js");
99
- this.buildId = this.getBuildId();
194
+ // First, before anything else reads `.next`: a missing manifest is the one
195
+ // error that names the cause (no build, or one without the adapter), where
196
+ // every later read fails with a bare ENOENT.
197
+ const manifest = this.readAdapterManifest();
198
+ // Deliberately outside the `skipBuild` gate. The patch is a property of
199
+ // *serving* through CloudFront, not of who ran `next build`: without it
200
+ // every POST with a body is rejected by the Lambda Function URL before it
201
+ // reaches the app (see `patchFetchInClientJs`). Running it only inside
202
+ // `runNextBuild` meant `skipBuild: true` silently shipped an app whose
203
+ // server actions and POST route handlers all returned 403.
204
+ if (props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS) {
205
+ this.patchFetchInClientJs();
206
+ }
207
+ this.buildId = deploymentBuildId(manifest);
100
208
  this.publicDirEntries = this.getLocalPublicDirEntries();
101
- this.nextConfigBasePath = (0, base_path_1.readNextConfigBasePath)(this.dotNextPath);
102
- const standalonePath = (0, node_path_1.join)(this.dotNextPath, "standalone");
209
+ // Next.js's resolved config, the same one it writes into
210
+ // `required-server-files.json`.
211
+ this.nextConfigBasePath = (0, base_path_1.normalizeBasePath)(manifest.config.basePath);
212
+ this.nextConfigAssetPrefix = (0, base_path_1.relativeAssetPrefix)(manifest.config.assetPrefix);
213
+ this.nextConfigAssetPrefixPath = (0, base_path_1.assetPrefixPath)(manifest.config.assetPrefix);
103
214
  const isFunctions = props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS ||
104
215
  props.nextjsType === constants_1.NextjsType.REGIONAL_FUNCTIONS;
105
- const dedicatedImageFunction = isFunctions && (0, experimental_flags_1.useDedicatedImageFunction)();
106
- // Strip whatever platform-specific Sharp binaries `next build`'s output
107
- // file tracing bundled in either way, since they're the host's (e.g.
108
- // macOS/glibc) rather than the deployment target's.
109
- this.removeExistingSharpBinaries(standalonePath);
110
- // The standalone server serves `_next/image` itself unless a dedicated
111
- // image optimization Lambda takes over that route, and it runs on
112
- // node:24-alpine (see functions.Dockerfile) / the same Alpine base for
113
- // Containers, so it needs musl binaries. Skipping this install when Sharp
114
- // *is* invoked from the server is silent: `imageOptimizer` catches the
115
- // load failure internally and returns the unoptimized original with an
116
- // HTTP 200.
117
- if (!dedicatedImageFunction) {
118
- this.downloadAndInstallSharpBinaries();
216
+ this.relativeProjectDir = manifest.relativeProjectDir;
217
+ this.relativePathToEntrypoint = (0, posix_1.join)(manifest_1.RUNTIME_DIR_NAME, "server.mjs");
218
+ this.architecture = deploymentArchitecture(props);
219
+ this.deploymentRoots = this.resolveDeploymentRoots(manifest);
220
+ this.functionGroupBehaviors = manifest.behaviors ?? [];
221
+ // Only the RegionalContainers image carries `public/`: nothing is in front
222
+ // of it to answer those paths from S3. Every other type lists it here and
223
+ // reads a file the edge didn't route to S3 (a rewrite onto it) from there.
224
+ const publicOnDisk = props.nextjsType === constants_1.NextjsType.REGIONAL_CONTAINERS;
225
+ if (publicOnDisk) {
226
+ // Its generated Dockerfile `COPY`s `public`, which fails the image build
227
+ // when the app has none. An empty directory is what `next start` sees
228
+ // for an app without one anyway, and git doesn't track it.
229
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(props.buildDirectory, "public"), { recursive: true });
230
+ }
231
+ for (const root of this.deploymentRoots) {
232
+ this.stageRuntime(root.path, isFunctions, publicOnDisk);
233
+ // Functions run on the Lambda managed runtime (Amazon Linux 2023, glibc),
234
+ // for the architecture their Lambda deploys, whatever this machine is;
235
+ // Containers run on node:24-alpine (musl).
236
+ this.stageSharpForTarget(root, (0, node_path_1.join)(root.path, this.relativeProjectDir), `${isFunctions ? "linux" : "linuxmusl"}-${(0, get_architecture_1.toNodeArchitecture)(this.architecture)}`);
237
+ if (isFunctions) {
238
+ this.assertUnderLambdaLimit(root);
239
+ }
119
240
  }
120
- if (dedicatedImageFunction) {
121
- this.imageOptimizationAssetPath =
122
- this.prepareImageOptimizationAssets(standalonePath);
241
+ }
242
+ /**
243
+ * Line up the groups the props asked for with the roots the build actually
244
+ * staged, and fail loudly when they disagree.
245
+ *
246
+ * They can disagree in both directions, and both mean the same thing — the
247
+ * `.next` on disk came from a build that did not see this `functionGroups` —
248
+ * but the causes differ: `skipBuild: true` with a build run by hand, or a
249
+ * stale `.next` from before the prop changed. Either way every later symptom
250
+ * (a Lambda missing an entrypoint, a CloudFront behavior pointing at a
251
+ * function that cannot serve it) is this, several steps downstream.
252
+ */
253
+ resolveDeploymentRoots(manifest) {
254
+ const staged = manifest.groups;
255
+ // Names *and* routes: moving `/reports/**` into an existing group keeps the
256
+ // names and still leaves that group's zip without the reports entrypoints.
257
+ // Order is not: assignment and CloudFront behaviors both go most specific
258
+ // first, and no two distinct patterns tie on a URL (`function-groups.ts`),
259
+ // so reordering groups or routes is the same split.
260
+ // Already validated in the constructor, so this is absent or non-empty.
261
+ const wanted = this.props.functionGroups?.length
262
+ ? toFunctionGroupSpecs(this.props.functionGroups)
263
+ : undefined;
264
+ const got = manifest.functionGroups;
265
+ if (JSON.stringify(sortedGroupSpecs(wanted)) !==
266
+ JSON.stringify(sortedGroupSpecs(got))) {
267
+ throw new Error(`${constants_1.LOG_PREFIX} \`functionGroups\` asks for ` +
268
+ `${wanted ? JSON.stringify(wanted) : "no splitting"} but the build ` +
269
+ `in ${this.dotNextPath} was split into ` +
270
+ `${got ? JSON.stringify(got) : "a single deployment root"}. ` +
271
+ `Groups are resolved during \`next build\` (cdk-nextjs passes them in ` +
272
+ `via ${function_groups_1.FUNCTION_GROUPS_ENV_VAR}), so this means the build output is ` +
273
+ `stale, or \`skipBuild: true\` and the build was run without that ` +
274
+ `variable set.`);
275
+ }
276
+ const names = staged ? Object.keys(staged) : [function_groups_1.DEFAULT_FUNCTION_GROUP];
277
+ const roots = names.map((name) => ({
278
+ name,
279
+ path: (0, node_path_1.join)(this.dotNextPath, manifest_1.ADAPTER_DIR_NAME, ...(0, manifest_1.groupStagingDirName)(staged ? name : undefined).split("/")),
280
+ routes: staged?.[name] ?? [],
281
+ }));
282
+ // `default` first, so any "the root" caller gets the group that owns
283
+ // everything unassigned.
284
+ roots.sort((a, b) => a.name === function_groups_1.DEFAULT_FUNCTION_GROUP
285
+ ? -1
286
+ : b.name === function_groups_1.DEFAULT_FUNCTION_GROUP
287
+ ? 1
288
+ : a.name.localeCompare(b.name));
289
+ for (const root of roots) {
290
+ if (!(0, node_fs_1.existsSync)(root.path)) {
291
+ throw new Error(`${constants_1.LOG_PREFIX} The deployment root for function group ` +
292
+ `"${root.name}" is missing from ${root.path}, though the adapter ` +
293
+ `manifest lists it. The \`.next\` directory has been modified since ` +
294
+ `\`next build\` ran.`);
295
+ }
296
+ }
297
+ return roots;
298
+ }
299
+ /**
300
+ * Lambda enforces 250 MB unzipped at CloudFormation time, which is minutes
301
+ * into a deploy and reports only a size. Splitting exists to stay under that
302
+ * cap, so the error that tells you to split further has to name the group, its
303
+ * size, and what to do — and arrive at synth.
304
+ */
305
+ assertUnderLambdaLimit(root) {
306
+ const bytes = storedSize(root.path);
307
+ debug(`${constants_1.LOG_PREFIX} Deployment root "${root.name}" is ${(bytes / 1e6).toFixed(1)} MB unzipped`);
308
+ if (bytes <= LAMBDA_UNZIPPED_LIMIT_BYTES) {
309
+ return;
310
+ }
311
+ const mb = (value) => `${(value / 1024 / 1024).toFixed(0)} MB`;
312
+ const isSplit = this.deploymentRoots.length > 1;
313
+ throw new Error(`${constants_1.LOG_PREFIX} Function group "${root.name}" is ${mb(bytes)} unzipped, ` +
314
+ `over Lambda's ${mb(LAMBDA_UNZIPPED_LIMIT_BYTES)} limit. ` +
315
+ (isSplit
316
+ ? `Split its routes further, or move some of them into another group: ` +
317
+ `the cap is per function, so the shared \`next\` closure every group ` +
318
+ `duplicates costs nothing against any single budget.`
319
+ : `Use the \`functionGroups\` prop to package routes into separate ` +
320
+ `functions. Note that splitting only removes route-local code — ` +
321
+ `anything reachable from a shared layout or the \`next\` runtime is ` +
322
+ `in every group.`));
323
+ }
324
+ /**
325
+ * Read the manifest the adapter's `onBuildComplete` wrote.
326
+ *
327
+ * Its absence means `next build` ran without cdk-nextjs's adapter registered
328
+ * (or with a stale `next.config`), which is worth saying plainly here: every
329
+ * later failure — a Lambda that cannot find `manifest.json`, an empty asset —
330
+ * is the same cause several steps downstream.
331
+ */
332
+ readAdapterManifest() {
333
+ const manifestPath = (0, node_path_1.join)(this.dotNextPath, manifest_1.ADAPTER_DIR_NAME, manifest_1.MANIFEST_FILE_NAME);
334
+ if (!(0, node_fs_1.existsSync)(manifestPath)) {
335
+ throw new Error(`cdk-nextjs adapter manifest not found at ${manifestPath}. ` +
336
+ `"${this.buildCommand}" must run a Next.js build with cdk-nextjs's ` +
337
+ `adapter registered. cdk-nextjs sets \`NEXT_ADAPTER_PATH\` on the ` +
338
+ `build it runs itself, so this usually means either the build command ` +
339
+ `does not reach \`next build\` (a wrapper that drops the environment, ` +
340
+ `or a cached build that did not re-run), or \`skipBuild: true\` and ` +
341
+ `the build happened outside CDK. For the latter, set ` +
342
+ `\`adapterPath: require.resolve("cdk-nextjs/adapter")\` in ` +
343
+ `next.config. A custom \`distDir\` is not supported either: ` +
344
+ `cdk-nextjs reads the build from \`.next\`.`);
345
+ }
346
+ const manifest = JSON.parse((0, node_fs_1.readFileSync)(manifestPath, "utf-8"));
347
+ if (manifest.version !== manifest_1.ADAPTER_MANIFEST_VERSION) {
348
+ throw new Error(`The cdk-nextjs adapter manifest at ${manifestPath} is version ` +
349
+ `${manifest.version}, but this version of cdk-nextjs reads version ` +
350
+ `${manifest_1.ADAPTER_MANIFEST_VERSION}. The adapter that wrote it and the ` +
351
+ `constructs reading it come from the same package, so this means two ` +
352
+ `cdk-nextjs versions are installed, or the build output is stale.`);
353
+ }
354
+ return manifest;
355
+ }
356
+ /**
357
+ * Copy cdk-nextjs's own bundled request-handling shell and the manifest into
358
+ * `<deploymentRoot>/cdk-nextjs-runtime/`, which is where
359
+ * `deploymentRootOf`/`deployedManifestPath` expect to find them.
360
+ *
361
+ * Only the shell the deployment type actually runs is copied — the Lambda
362
+ * handler for Functions, the `node:http` server for Containers — so nothing
363
+ * ships ~1.5 MB of dead code and the tree says which type produced it. Both
364
+ * are copied from this package's `lib/`, next to the compiled construct.
365
+ *
366
+ * Every group gets the same shell *and the same manifest*: a function only
367
+ * knows which routes it owns so it can say so when misrouted, and that comes
368
+ * from {@link FUNCTION_GROUP_ENV_VAR}, not from a per-group manifest.
369
+ */
370
+ stageRuntime(deploymentRoot, isFunctions, publicOnDisk) {
371
+ const shell = isFunctions ? "lambda.mjs" : "server.mjs";
372
+ const source = (0, node_path_1.join)(__dirname, "..", "runtime", shell);
373
+ const runtimeDir = (0, node_path_1.join)(deploymentRoot, manifest_1.RUNTIME_DIR_NAME);
374
+ // Removed rather than merged: a stale shell from the other deployment type
375
+ // would otherwise sit in the asset and change its hash for no reason.
376
+ (0, node_fs_1.rmSync)(runtimeDir, { recursive: true, force: true });
377
+ (0, node_fs_1.mkdirSync)(runtimeDir, { recursive: true });
378
+ (0, node_fs_1.cpSync)(source, (0, node_path_1.join)(runtimeDir, shell));
379
+ (0, node_fs_1.cpSync)((0, node_path_1.join)(this.dotNextPath, manifest_1.ADAPTER_DIR_NAME, manifest_1.MANIFEST_FILE_NAME), (0, node_path_1.join)(runtimeDir, manifest_1.MANIFEST_FILE_NAME));
380
+ if (!publicOnDisk) {
381
+ // The Lambda zips and the GlobalContainers image don't carry `public/`
382
+ // (its bytes are in S3), so the runtime can't list it at start the way
383
+ // the RegionalContainers image does.
384
+ // Listed here, after the build command, so `postbuild` output is in it:
385
+ // a rewrite onto a listed file is then served from S3 rather than 404ing.
386
+ writePublicFileList(runtimeDir, (0, node_path_1.join)(this.props.buildDirectory, "public"));
387
+ }
388
+ debug(`${constants_1.LOG_PREFIX} Staged ${shell} and ${manifest_1.MANIFEST_FILE_NAME} in ${runtimeDir}`);
389
+ }
390
+ /**
391
+ * `NEXT_ADAPTER_PATH` for the build, so `adapterPath` in `next.config` is
392
+ * optional.
393
+ *
394
+ * Next.js reads the variable as the *default* value of `adapterPath`
395
+ * (`next/dist/server/config-shared.js`, `defaultConfig`), so an app that does
396
+ * set `adapterPath` still wins and nothing existing changes.
397
+ *
398
+ * Resolved from the Next.js app, not from cdk-nextjs's own `__dirname` and not
399
+ * left as a bare specifier. Both alternatives were tried and both are wrong:
400
+ *
401
+ * - cdk-nextjs's own location loses because the adapter resolves its sibling
402
+ * cache handler relative to wherever *it* was loaded from. An adapter loaded
403
+ * from outside the app's tree hands Next.js a `cacheHandler` outside
404
+ * `turbopack.root`, which Turbopack rejects outright ("leaves the filesystem
405
+ * root").
406
+ * - A bare specifier loses because Next.js resolves `adapterPath` from inside
407
+ * its own config loader, i.e. from `next`'s realpath. Under pnpm that is the
408
+ * virtual store (`node_modules/.pnpm/next@…/node_modules/next/`), and the
409
+ * walk up from there never reaches the app's own `node_modules`.
410
+ *
411
+ * Unset when `cdk-nextjs` is not resolvable from the app, which is legitimate:
412
+ * the Next.js app and the CDK app can be separate packages, and only the CDK one
413
+ * necessarily depends on cdk-nextjs. {@link readAdapterManifest} reports the
414
+ * resulting failure and names this case.
415
+ *
416
+ * One setup this cannot serve, and the reason this repo's own examples still set
417
+ * `adapterPath`: a `link:`/`file:` dependency on a cdk-nextjs checkout *outside*
418
+ * the app's project root. The symlink resolves out of the project, so the
419
+ * `cacheHandler` escape above applies. Set `adapterPath` in `next.config` there
420
+ * — it is resolved by the build, after whatever put the adapter in place.
421
+ */
422
+ adapterPathEnv() {
423
+ try {
424
+ return {
425
+ NEXT_ADAPTER_PATH: require.resolve("cdk-nextjs/adapter", {
426
+ paths: [this.props.buildDirectory],
427
+ }),
428
+ };
429
+ }
430
+ catch {
431
+ debug(`${constants_1.LOG_PREFIX} Could not resolve "cdk-nextjs/adapter" from ` +
432
+ `${this.props.buildDirectory}; leaving NEXT_ADAPTER_PATH unset, so ` +
433
+ `next.config must set \`adapterPath\`.`);
434
+ return {};
123
435
  }
124
436
  }
125
437
  /**
@@ -139,33 +451,41 @@ class NextjsBuild extends constructs_1.Construct {
139
451
  env: {
140
452
  ...process.env,
141
453
  CDK_NEXTJS_INIT_CACHE_DIR: this.initCacheDir,
454
+ ...this.adapterPathEnv(),
455
+ // `onBuildComplete` runs inside this process and cannot read CDK
456
+ // props, so the resolved groups travel as JSON. Absent when not
457
+ // splitting, which the adapter reads as "one deployment root".
458
+ ...(this.props.functionGroups?.length
459
+ ? {
460
+ [function_groups_1.FUNCTION_GROUPS_ENV_VAR]: JSON.stringify(toFunctionGroupSpecs(this.props.functionGroups)),
461
+ }
462
+ : {}),
142
463
  },
143
464
  });
144
- // Copy patch-fetch.js into client JS bundle after build only for NextjsGlobalFunctions
145
- if (this.props.nextjsType === constants_1.NextjsType.GLOBAL_FUNCTIONS) {
146
- this.patchFetchInClientJs();
147
- }
148
465
  }
149
466
  catch (error) {
150
467
  throw new Error(`Local build failed: ${error}`);
151
468
  }
152
469
  }
153
470
  /**
154
- * Validate Next.js build output
155
- * All builds must be standalone - no fallback to regular builds
156
- */
157
- validateNextBuildOutput() {
158
- const standaloneDir = (0, node_path_1.join)(this.dotNextPath, "standalone");
159
- // Standalone directory is mandatory
160
- if (!(0, node_fs_1.existsSync)(standaloneDir)) {
161
- throw new Error(`Standalone build directory not found: ${standaloneDir}. ` +
162
- `All builds must be configured for standalone output. ` +
163
- `Please ensure your next.config.js includes 'output: "standalone"'.`);
164
- }
165
- // Additional validation (server.js with .next sibling) happens in findRelativePathToServerJs()
166
- }
167
- /**
168
- * Find entrypoint client side js files to patch `fetch` only for NextjsGlobalFunctions
471
+ * Prepend `patch-fetch.js` to the client entrypoint chunks, for
472
+ * `NextjsGlobalFunctions` only.
473
+ *
474
+ * This is what makes POST work at all on that type. CloudFront reaches the
475
+ * server through a Lambda Function URL with `AuthType: AWS_IAM`, signed by an
476
+ * origin access control, and AWS documents the consequence: "If you use PUT or
477
+ * POST methods with your Lambda function URL, your users must compute the
478
+ * SHA256 of the body and include the payload hash value of the request body in
479
+ * the `x-amz-content-sha256` header when sending the request to CloudFront.
480
+ * Lambda doesn't support unsigned payloads."
481
+ *
482
+ * CloudFront signs GETs itself (empty-body hash) but will not hash a body, and
483
+ * a browser has no way to add that header on its own, so an unpatched app
484
+ * answers every server action, form submission and POST route handler with
485
+ * `403 InvalidSignatureException` before the request reaches Next.js. The
486
+ * patch installs `fetch`/`XMLHttpRequest` wrappers that compute the hash.
487
+ *
488
+ * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-lambda.html
169
489
  */
170
490
  patchFetchInClientJs() {
171
491
  const staticChunksPath = (0, node_path_1.join)(this.dotNextPath, "static", "chunks");
@@ -178,69 +498,20 @@ class NextjsBuild extends constructs_1.Construct {
178
498
  }
179
499
  // Read the patch-fetch.js content
180
500
  const patchFetchPath = (0, node_path_1.join)(__dirname, "patch-fetch.js");
181
- if (!(0, node_fs_1.existsSync)(patchFetchPath)) {
182
- throw new Error("patch-fetch.js not found");
183
- }
184
501
  const patchFetchContent = (0, node_fs_1.readFileSync)(patchFetchPath, "utf-8");
185
- // Prepend patch-fetch logic to each entrypoint
502
+ // Prepend patch-fetch logic to each entrypoint, once. Now that this runs
503
+ // outside `runNextBuild`, the same `.next` can be synthesized more than
504
+ // once (`skipBuild: true`, `cdk synth` then `cdk deploy`, a retried
505
+ // deploy), and prepending twice would re-wrap the wrappers.
186
506
  for (const chunkFile of chunkFiles) {
187
507
  const chunkFilePath = (0, node_path_1.join)(staticChunksPath, chunkFile);
188
- const originalContent = (0, node_fs_1.readFileSync)(chunkFilePath, "utf-8");
189
- const patchedContent = patchFetchContent + "\n" + originalContent;
190
- (0, node_fs_1.writeFileSync)(chunkFilePath, patchedContent);
191
- }
192
- }
193
- /**
194
- * Automatically finds the relative path from standalone directory to the
195
- * package containing server.js by searching for server.js with a .next sibling.
196
- * @returns "." for non-monorepo apps, or relative path like "app-playground" for monorepo apps
197
- */
198
- findRelativePathToServerJs() {
199
- const standaloneDir = (0, node_path_1.join)(this.dotNextPath, "standalone");
200
- if (!(0, node_fs_1.existsSync)(standaloneDir)) {
201
- throw new Error(`Cannot detect relativePathToPackage: standalone directory not found at ${standaloneDir}`);
202
- }
203
- const findServerJs = (dir, relativePath = "") => {
204
- const entries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true });
205
- for (const entry of entries) {
206
- const fullPath = (0, node_path_1.join)(dir, entry.name);
207
- if (entry.isDirectory() && entry.name !== "node_modules") {
208
- // Recursively search directories (skip node_modules at root level)
209
- const result = findServerJs(fullPath, (0, node_path_1.join)(relativePath, entry.name));
210
- if (result !== null)
211
- return result;
212
- }
213
- else if (entry.isFile() && entry.name === "server.js") {
214
- // Check if this server.js has a .next sibling directory
215
- const parentDir = dir;
216
- const dotNextPath = (0, node_path_1.join)(parentDir, ".next");
217
- if ((0, node_fs_1.existsSync)(dotNextPath)) {
218
- return relativePath || ".";
219
- }
220
- }
508
+ const patchedContent = patchClientChunk((0, node_fs_1.readFileSync)(chunkFilePath, "utf-8"), patchFetchContent, chunkFilePath);
509
+ if (patchedContent === undefined) {
510
+ debug(`${constants_1.LOG_PREFIX} Already patched, skipping: ${chunkFilePath}`);
511
+ continue;
221
512
  }
222
- return null;
223
- };
224
- const result = findServerJs(standaloneDir);
225
- if (result === null) {
226
- throw new Error(`Cannot detect relativePathToPackage: Could not find server.js with .next sibling in ${standaloneDir}. ` +
227
- `Please ensure Next.js build completed successfully or provide relativePathToPackage manually.`);
228
- }
229
- debug(`${constants_1.LOG_PREFIX} Auto-detected relativePathToPackage: "${result}"`);
230
- return result;
231
- }
232
- /**
233
- * Get build ID from .next directory
234
- */
235
- getBuildId() {
236
- const buildIdPath = (0, node_path_1.join)(this.dotNextPath, "BUILD_ID");
237
- // Verify BUILD_ID exists (needed for cache partitioning)
238
- if (!(0, node_fs_1.existsSync)(buildIdPath)) {
239
- throw new Error(`BUILD_ID file not found at ${buildIdPath}. ` +
240
- `Ensure Next.js build completed successfully.`);
513
+ (0, node_fs_1.writeFileSync)(chunkFilePath, patchedContent);
241
514
  }
242
- // BUILD_ID existence is already validated in validateNextBuildOutput()
243
- return (0, node_fs_1.readFileSync)(buildIdPath, "utf-8").trim();
244
515
  }
245
516
  /**
246
517
  * Get public directory entries from local filesystem
@@ -250,190 +521,108 @@ class NextjsBuild extends constructs_1.Construct {
250
521
  if (!(0, node_fs_1.existsSync)(publicDirPath)) {
251
522
  return [];
252
523
  }
253
- try {
254
- return (0, node_fs_1.readdirSync)(publicDirPath, { withFileTypes: true }).map((entry) => ({
255
- name: entry.name,
256
- isDirectory: entry.isDirectory(),
257
- }));
258
- }
259
- catch (error) {
260
- console.warn(`${constants_1.LOG_PREFIX} Failed to read public directory: ${error}`);
261
- return [];
262
- }
263
- }
264
- /**
265
- * Recursively find and remove existing Sharp platform binaries
266
- */
267
- removeExistingSharpBinaries(standalonePath) {
268
- const nodeModulesPath = (0, node_path_1.join)(standalonePath, "node_modules");
269
- if (!(0, node_fs_1.existsSync)(nodeModulesPath)) {
270
- return;
271
- }
272
- try {
273
- // Use recursive readdirSync to find all Sharp binary directories and symlinks
274
- const allEntries = (0, node_fs_1.readdirSync)(nodeModulesPath, {
275
- recursive: true,
276
- withFileTypes: true,
277
- });
278
- const sharpBinaryPaths = [];
279
- for (const entry of allEntries) {
280
- // Check for both directories and symlinks (pnpm creates symlinks)
281
- if (entry.isDirectory() || entry.isSymbolicLink()) {
282
- // Match Sharp binary packages with more comprehensive patterns
283
- const isSharpBinary = entry.name.includes("sharp-") ||
284
- entry.name.includes("sharp-libvips");
285
- if (isSharpBinary) {
286
- // For recursive readdirSync, parentPath contains the full absolute path
287
- const fullPath = (0, node_path_1.join)(entry.parentPath, entry.name);
288
- sharpBinaryPaths.push(fullPath);
289
- }
290
- }
291
- }
292
- debug(`${constants_1.LOG_PREFIX} Found ${sharpBinaryPaths.length} Sharp binary directories/symlinks to remove`);
293
- // Remove all found Sharp binary directories and symlinks
294
- for (const path of sharpBinaryPaths) {
295
- try {
296
- (0, node_fs_1.rmSync)(path, { recursive: true, force: true });
297
- debug(`${constants_1.LOG_PREFIX} Removed: ${path}`);
298
- }
299
- catch (error) {
300
- console.warn(`${constants_1.LOG_PREFIX} Warning: Could not remove ${path}: ${error}`);
301
- }
302
- }
303
- }
304
- catch (error) {
305
- console.warn(`${constants_1.LOG_PREFIX} Warning: Could not read node_modules directory: ${error}`);
306
- }
307
- }
308
- /**
309
- * Download and install correct Sharp binaries for Linux MUSL
310
- */
311
- downloadAndInstallSharpBinaries() {
312
- const nodeModulesPath = (0, node_path_1.join)(this.dotNextPath, "standalone", "node_modules");
313
- const imgPath = (0, node_path_1.join)(nodeModulesPath, "@img");
314
- const arch = (0, get_architecture_1.getNodeArchitecture)();
315
- this.installSharpPackages(imgPath, this.getSharpBinaryPackages(this.findSharpPackage(nodeModulesPath), `linuxmusl-${arch}`));
524
+ return (0, node_fs_1.readdirSync)(publicDirPath, { withFileTypes: true }).map((entry) => ({
525
+ name: entry.name,
526
+ isDirectory: entry.isDirectory(),
527
+ }));
316
528
  }
317
529
  /**
318
- * Assemble the deployment asset for the dedicated image optimization
319
- * Lambda: the pre-bundled handler (from this package's own `lib/` output),
320
- * `sharp`'s JS wrapper (already dereferenced from the pnpm store by Next's
321
- * output file tracing into the standalone build), glibc `sharp` binaries
322
- * (the standard Lambda managed runtime is Amazon Linux 2023/glibc, unlike
323
- * the musl binaries the Docker/Lambda Web Adapter server function needs),
324
- * and `required-server-files.json` (read by the handler at cold start to
325
- * build `nextConfig`).
326
- */
327
- prepareImageOptimizationAssets(standalonePath) {
328
- const assetPath = (0, node_path_1.join)(this.dotNextPath, "cdk-nextjs-image-optimization");
329
- const nodeModulesPath = (0, node_path_1.join)(assetPath, "node_modules");
330
- const imgPath = (0, node_path_1.join)(nodeModulesPath, "@img");
331
- (0, node_fs_1.rmSync)(assetPath, { recursive: true, force: true });
332
- (0, node_fs_1.mkdirSync)(imgPath, { recursive: true });
333
- // Pre-bundled by esbuild into this package's own lib/ output.
334
- (0, node_fs_1.cpSync)((0, node_path_1.join)(__dirname, "..", "image-optimization"), assetPath, {
335
- recursive: true,
336
- });
337
- const sharpSource = this.findSharpPackage((0, node_path_1.join)(standalonePath, "node_modules"));
338
- if (sharpSource) {
339
- this.copySharpRuntime(sharpSource, nodeModulesPath);
340
- }
341
- else {
342
- console.warn(`${constants_1.LOG_PREFIX} "sharp" not found in standalone build output. Add "sharp" as a dependency of your Next.js app to enable image optimization.`);
343
- }
344
- const requiredServerFiles = (0, node_path_1.join)(this.dotNextPath, "required-server-files.json");
345
- if (!(0, node_fs_1.existsSync)(requiredServerFiles)) {
346
- throw new Error(`${constants_1.LOG_PREFIX} "required-server-files.json" not found at ${requiredServerFiles}. The image optimization Lambda reads it at cold start to build its Next.js config.`);
347
- }
348
- (0, node_fs_1.cpSync)(requiredServerFiles, (0, node_path_1.join)(assetPath, "required-server-files.json"));
349
- const arch = (0, get_architecture_1.getNodeArchitecture)();
350
- this.installSharpPackages(imgPath, this.getSharpBinaryPackages(sharpSource, `linux-${arch}`));
351
- return assetPath;
352
- }
353
- /**
354
- * Locate `sharp`'s JS wrapper inside a standalone `node_modules`.
530
+ * Strip whatever platform-specific Sharp binaries `next build`'s output file
531
+ * tracing staged, since they're the host's (e.g. macOS/glibc) rather than the
532
+ * deployment target's, then install the target's. Skipping this is silent:
533
+ * `imageOptimizer` catches the load failure internally and returns the
534
+ * unoptimized original with an HTTP 200.
355
535
  *
356
- * Next's output file tracing preserves the installer's on-disk layout, so
357
- * npm/yarn produce a hoisted `node_modules/sharp` while pnpm only
358
- * materializes `node_modules/.pnpm/sharp@<version>/node_modules/sharp`.
536
+ * Only a root with `sharp` staged gets the binaries: the image optimizer
537
+ * brings it into `default`, which serves every `/_next/image`, and another
538
+ * group has it only if its own routes use it. So only `default` warns when
539
+ * it's missing.
359
540
  */
360
- findSharpPackage(nodeModulesPath) {
361
- const hoisted = (0, node_path_1.join)(nodeModulesPath, "sharp");
362
- if ((0, node_fs_1.existsSync)((0, node_path_1.join)(hoisted, "package.json"))) {
363
- return hoisted;
364
- }
365
- const pnpmPath = (0, node_path_1.join)(nodeModulesPath, ".pnpm");
366
- if (!(0, node_fs_1.existsSync)(pnpmPath)) {
367
- return undefined;
368
- }
369
- const candidates = (0, node_fs_1.readdirSync)(pnpmPath)
370
- .filter((name) => name.startsWith("sharp@"))
371
- .sort();
372
- for (const candidate of candidates.reverse()) {
373
- const nested = (0, node_path_1.join)(pnpmPath, candidate, "node_modules", "sharp");
374
- if ((0, node_fs_1.existsSync)((0, node_path_1.join)(nested, "package.json"))) {
375
- return nested;
541
+ stageSharpForTarget(root, projectDir, platform) {
542
+ const sharpSource = this.removeExistingSharpBinaries(root.path, projectDir);
543
+ if (!sharpSource) {
544
+ if (root.name === function_groups_1.DEFAULT_FUNCTION_GROUP) {
545
+ console.warn(`${constants_1.LOG_PREFIX} "sharp" not found in the staged build output. Add "sharp" as a dependency of your Next.js app to enable image optimization.`);
376
546
  }
547
+ return;
377
548
  }
378
- return undefined;
549
+ this.installSharpPackages(sharpBinaryDir(root.path), this.getSharpBinaryPackages(sharpSource, platform));
379
550
  }
380
551
  /**
381
- * Copy `sharp` plus the transitive `dependencies` closure `require("sharp")`
382
- * pulls in (`@img/colour`, `detect-libc`, `semver`) into `targetPath`.
552
+ * Recursively find and remove existing Sharp platform binaries.
553
+ *
554
+ * `root` is walked whole rather than just its `node_modules`: the staged tree
555
+ * is keyed by repo-root-relative path, so in a monorepo the `node_modules`
556
+ * holding `sharp` is several directories down. {@link isSharpBinaryPackage} is
557
+ * what keeps that from reaching the app's own output — the staged root holds
558
+ * the compiled `.next` as well as the dependencies.
383
559
  *
384
- * Copying only `sharp` itself leaves those requires unresolvable, and
385
- * `imageOptimizer` swallows the resulting `MODULE_NOT_FOUND` by falling back
386
- * to serving the unoptimized original, so the omission is otherwise silent.
560
+ * @param projectDir the app's directory inside `root`, which `next` is
561
+ * resolved from.
562
+ * @returns the staged `sharp` JS wrapper to install next to, found in the same
563
+ * walk: a root can be hundreds of megabytes, and each group has one.
387
564
  */
388
- copySharpRuntime(sharpSource, targetPath) {
389
- // Under pnpm a package's dependencies are symlinked into the sibling
390
- // directory alongside it, which is also where a hoisted layout keeps
391
- // them, so the same lookup covers both.
392
- const lookupPath = (0, node_path_1.join)(sharpSource, "..");
393
- const queue = ["sharp"];
394
- const copied = new Set();
395
- while (queue.length > 0) {
396
- const name = queue.shift();
397
- if (copied.has(name)) {
565
+ removeExistingSharpBinaries(root, projectDir) {
566
+ const sharpCandidates = [];
567
+ // Links are listed, not followed: every link in a staged root points
568
+ // inside it (`stageFiles` copies the ones that don't), so its target is
569
+ // walked at its own path anyway, and following them is what let a
570
+ // workspace cycle hang the synth.
571
+ const allEntries = listTree(root);
572
+ // Symlinks are unlinked, not `rmSync`ed, and they go first. pnpm points
573
+ // several links at one store directory, and `rmSync(…, { recursive: true,
574
+ // force: true })` *silently no-ops* on a symlink whose target is already
575
+ // gone — `force` swallows the ENOENT its `rmdir` gets. Removing a store
576
+ // directory before its links therefore left dangling
577
+ // `@img/sharp-darwin-arm64` entries in the asset, which is a latent ENOENT
578
+ // in whatever next follows them (`sharp` does, when it looks for binaries).
579
+ const symlinks = [];
580
+ const directories = [];
581
+ for (const entry of allEntries) {
582
+ if (entry.isDirectory() && entry.name === "sharp") {
583
+ const path = (0, node_path_1.join)(entry.parentPath, entry.name);
584
+ if ((0, node_fs_1.existsSync)((0, node_path_1.join)(path, "package.json"))) {
585
+ sharpCandidates.push(path);
586
+ }
398
587
  continue;
399
588
  }
400
- const source = name === "sharp" ? sharpSource : (0, node_path_1.join)(lookupPath, name);
401
- if (!(0, node_fs_1.existsSync)((0, node_path_1.join)(source, "package.json"))) {
402
- console.warn(`${constants_1.LOG_PREFIX} "sharp" dependency "${name}" not found in standalone build output; image optimization may fall back to serving unoptimized images.`);
589
+ if (!isSharpBinaryPackage(entry.parentPath, entry.name))
403
590
  continue;
591
+ const fullPath = (0, node_path_1.join)(entry.parentPath, entry.name);
592
+ if (entry.isSymbolicLink()) {
593
+ symlinks.push(fullPath);
404
594
  }
405
- // `dereference` resolves pnpm's symlinks into real files, since the
406
- // Lambda asset is a standalone directory with no store to link into.
407
- (0, node_fs_1.cpSync)(source, (0, node_path_1.join)(targetPath, name), {
408
- recursive: true,
409
- dereference: true,
410
- });
411
- copied.add(name);
412
- const manifest = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(source, "package.json"), "utf-8"));
413
- // Platform binaries are optionalDependencies, installed separately at
414
- // the versions this same manifest pins, so only `dependencies` here.
415
- queue.push(...Object.keys(manifest.dependencies ?? {}));
595
+ else if (entry.isDirectory()) {
596
+ directories.push(fullPath);
597
+ }
598
+ }
599
+ debug(`${constants_1.LOG_PREFIX} Removing ${symlinks.length} Sharp binary symlinks and ${directories.length} directories`);
600
+ for (const path of symlinks) {
601
+ (0, node_fs_1.unlinkSync)(path);
602
+ debug(`${constants_1.LOG_PREFIX} Unlinked: ${path}`);
603
+ }
604
+ for (const path of directories) {
605
+ (0, node_fs_1.rmSync)(path, { recursive: true, force: true });
606
+ debug(`${constants_1.LOG_PREFIX} Removed: ${path}`);
416
607
  }
417
- debug(`${constants_1.LOG_PREFIX} Copied sharp runtime: ${[...copied].sort().join(", ")}`);
608
+ return pickStagedSharpPackage(sharpCandidates, resolveNextSharp(projectDir));
418
609
  }
419
610
  /**
420
611
  * Resolve the `@img/sharp-<platform>` and `@img/sharp-libvips-<platform>`
421
612
  * versions to install for a given platform.
422
613
  *
423
- * These must match the `sharp` JS wrapper that output file tracing put in
424
- * the standalone build: `sharp`'s `lib/libvips.js` compares the binary's
614
+ * These must match the `sharp` JS wrapper that output file tracing staged:
615
+ * `sharp`'s `lib/libvips.js` compares the binary's
425
616
  * reported libvips version against its own `minimumLibvipsVersion` and
426
617
  * throws at load when they disagree. `sharp` pins both in its
427
618
  * `optionalDependencies`, so that manifest is the authoritative source.
428
619
  */
429
620
  getSharpBinaryPackages(sharpSource, platform) {
621
+ // Only for a binary the staged `sharp` does not pin.
430
622
  const fallback = [
431
623
  { name: `sharp-libvips-${platform}`, version: "1.2.4" },
432
624
  { name: `sharp-${platform}`, version: "0.34.5" },
433
625
  ];
434
- if (!sharpSource) {
435
- return fallback;
436
- }
437
626
  const manifest = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(sharpSource, "package.json"), "utf-8"));
438
627
  const optionalDependencies = manifest.optionalDependencies ?? {};
439
628
  return fallback.map((pkg) => {
@@ -451,56 +640,56 @@ class NextjsBuild extends constructs_1.Construct {
451
640
  */
452
641
  installSharpPackages(imgPath, packages) {
453
642
  const cacheDir = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "cdk-nextjs-sharp-cache");
454
- if (!(0, node_fs_1.existsSync)(cacheDir)) {
455
- (0, node_fs_1.mkdirSync)(cacheDir, { recursive: true });
456
- }
643
+ (0, node_fs_1.mkdirSync)(cacheDir, { recursive: true });
457
644
  for (const pkg of packages) {
458
- try {
459
- const targetDir = (0, node_path_1.join)(imgPath, pkg.name);
460
- const url = `https://registry.npmjs.org/@img/${pkg.name}/-/${pkg.name}-${pkg.version}.tgz`;
461
- // Create a consistent filename based on package name and version
462
- const cacheFileName = `${pkg.name}-${pkg.version}.tgz`;
463
- const cachedFile = (0, node_path_1.join)(cacheDir, cacheFileName);
464
- // Check if we already have a valid package cached; re-download if
465
- // a previous run left behind a truncated/corrupt download
466
- if ((0, node_fs_1.existsSync)(cachedFile) && this.isCachedFileValid(cachedFile)) {
467
- debug(`${constants_1.LOG_PREFIX} Using cached ${pkg.name}@${pkg.version} from ${cachedFile}`);
468
- }
469
- else {
470
- debug(`${constants_1.LOG_PREFIX} Downloading ${pkg.name}@${pkg.version}...`);
471
- // Download to a process-unique temp file in the same directory,
472
- // then atomically rename it onto the shared cache path. Concurrent
473
- // synth processes (e.g. Turborepo running multiple `cdk` commands)
474
- // share this cache dir, so writing directly to `cachedFile` risks
475
- // another process extracting a half-written file. Renaming within
476
- // the same filesystem is atomic, so readers only ever see a
477
- // complete file, whichever process wins the race.
478
- const tempFile = (0, node_path_1.join)(cacheDir, `${cacheFileName}.${process.pid}-${(0, node_crypto_1.randomBytes)(6).toString("hex")}.tmp`);
479
- try {
480
- // --fail makes curl exit non-zero on HTTP errors and --retry
481
- // handles transient connection drops so a partial transfer
482
- // isn't cached as valid.
483
- (0, node_child_process_1.execSync)(`curl -L --fail --retry 3 --retry-delay 1 -o "${tempFile}" "${url}"`, { stdio: "pipe" });
484
- if (!this.isCachedFileValid(tempFile)) {
485
- throw new Error(`Downloaded file for ${pkg.name}@${pkg.version} is empty or missing: ${tempFile}`);
486
- }
487
- (0, node_fs_1.renameSync)(tempFile, cachedFile);
488
- }
489
- finally {
490
- if ((0, node_fs_1.existsSync)(tempFile)) {
491
- (0, node_fs_1.rmSync)(tempFile, { force: true });
492
- }
645
+ const targetDir = (0, node_path_1.join)(imgPath, pkg.name);
646
+ const url = `https://registry.npmjs.org/@img/${pkg.name}/-/${pkg.name}-${pkg.version}.tgz`;
647
+ // Create a consistent filename based on package name and version
648
+ const cacheFileName = `${pkg.name}-${pkg.version}.tgz`;
649
+ const cachedFile = (0, node_path_1.join)(cacheDir, cacheFileName);
650
+ // Check if we already have a valid package cached; re-download if
651
+ // a previous run left behind a truncated/corrupt download
652
+ if ((0, node_fs_1.existsSync)(cachedFile) && this.isCachedFileValid(cachedFile)) {
653
+ debug(`${constants_1.LOG_PREFIX} Using cached ${pkg.name}@${pkg.version} from ${cachedFile}`);
654
+ }
655
+ else {
656
+ debug(`${constants_1.LOG_PREFIX} Downloading ${pkg.name}@${pkg.version}...`);
657
+ // Download to a process-unique temp file in the same directory,
658
+ // then atomically rename it onto the shared cache path. Concurrent
659
+ // synth processes (e.g. Turborepo running multiple `cdk` commands)
660
+ // share this cache dir, so writing directly to `cachedFile` risks
661
+ // another process extracting a half-written file. Renaming within
662
+ // the same filesystem is atomic, so readers only ever see a
663
+ // complete file, whichever process wins the race.
664
+ const tempFile = (0, node_path_1.join)(cacheDir, `${cacheFileName}.${process.pid}-${(0, node_crypto_1.randomBytes)(6).toString("hex")}.tmp`);
665
+ try {
666
+ // --fail makes curl exit non-zero on HTTP errors and --retry
667
+ // handles transient connection drops so a partial transfer
668
+ // isn't cached as valid.
669
+ (0, node_child_process_1.execFileSync)("curl", [
670
+ "-L",
671
+ "--fail",
672
+ "--retry",
673
+ "3",
674
+ "--retry-delay",
675
+ "1",
676
+ "-o",
677
+ tempFile,
678
+ url,
679
+ ], { stdio: "pipe" });
680
+ if (!this.isCachedFileValid(tempFile)) {
681
+ throw new Error(`Downloaded file for ${pkg.name}@${pkg.version} is empty or missing: ${tempFile}`);
493
682
  }
494
- debug(`${constants_1.LOG_PREFIX} Cached ${pkg.name}@${pkg.version} to ${cachedFile}`);
683
+ (0, node_fs_1.renameSync)(tempFile, cachedFile);
495
684
  }
496
- (0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
497
- (0, node_child_process_1.execSync)(`tar -xzf "${cachedFile}" -C "${targetDir}" --strip-components=1`, { stdio: "pipe" });
498
- debug(`${constants_1.LOG_PREFIX} Installed ${pkg.name}@${pkg.version}`);
499
- }
500
- catch (error) {
501
- console.error(`${constants_1.LOG_PREFIX} Failed to install ${pkg.name}: ${error}`);
502
- throw error;
685
+ finally {
686
+ (0, node_fs_1.rmSync)(tempFile, { force: true });
687
+ }
688
+ debug(`${constants_1.LOG_PREFIX} Cached ${pkg.name}@${pkg.version} to ${cachedFile}`);
503
689
  }
690
+ (0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
691
+ (0, node_child_process_1.execFileSync)("tar", ["-xzf", cachedFile, "-C", targetDir, "--strip-components=1"], { stdio: "pipe" });
692
+ debug(`${constants_1.LOG_PREFIX} Installed ${pkg.name}@${pkg.version}`);
504
693
  }
505
694
  }
506
695
  /**
@@ -518,4 +707,172 @@ class NextjsBuild extends constructs_1.Construct {
518
707
  }
519
708
  }
520
709
  exports.NextjsBuild = NextjsBuild;
521
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25leHRqcy1idWlsZC9uZXh0anMtYnVpbGQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBLDJEQUE4QztBQUM5Qyw2Q0FBMEM7QUFDMUMscUNBVWlCO0FBQ2pCLHFDQUFpQztBQUNqQyx5Q0FBaUM7QUFDakMsMkNBQW9EO0FBQ3BELDJDQUF1QztBQUN2Qyw2REFBNkQ7QUFDN0Qsa0RBQTZCO0FBQzdCLDRDQUFzRDtBQUV0RCxrREFBNEQ7QUFDNUQsb0VBQXdFO0FBQ3hFLGdFQUFnRTtBQUVoRSxNQUFNLEtBQUssR0FBRyxJQUFBLGVBQVEsRUFBQyx5QkFBeUIsQ0FBQyxDQUFDO0FBd0JsRDs7O0dBR0c7QUFDSCxNQUFhLFdBQVksU0FBUSxzQkFBUzs7SUFDeEM7OztPQUdHO0lBQ0gsT0FBTyxDQUFTO0lBQ2hCOzs7T0FHRztJQUNILFlBQVksQ0FBUztJQUNyQjs7O09BR0c7SUFDSCxnQkFBZ0IsQ0FBbUI7SUFDbkM7Ozs7O09BS0c7SUFDSCx3QkFBd0IsQ0FBUztJQUNqQzs7Ozs7T0FLRztJQUNILHFCQUFxQixDQUFTO0lBQzlCOztPQUVHO0lBQ0gsV0FBVyxDQUFTO0lBQ3BCOzs7Ozs7T0FNRztJQUNILGtCQUFrQixDQUFTO0lBQzNCOzs7Ozs7T0FNRztJQUNILDBCQUEwQixDQUFVO0lBRTVCLEtBQUssQ0FBbUI7SUFDeEIsWUFBWSxDQUFTO0lBRTdCLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBdUI7UUFDL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUEsZ0JBQUksRUFBQyxLQUFLLENBQUMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXZELElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxD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LEtBQUssRUFBRSxDQUFDLENBQUM7Z0JBQ3ZFLE1BQU0sS0FBSyxDQUFDO1lBQ2QsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLGlCQUFpQixDQUFDLFFBQWdCO1FBQ3hDLElBQUksQ0FBQztZQUNILE9BQU8sSUFBQSxrQkFBUSxFQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7UUFDckMsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7O0FBL25CSCxrQ0Fnb0JDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhlY1N5bmMgfSBmcm9tIFwibm9kZTpjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHtcbiAgZXhpc3RzU3luYyxcbiAgcmVhZEZpbGVTeW5jLFxuICByZWFkZGlyU3luYyxcbiAgd3JpdGVGaWxlU3luYyxcbiAgcm1TeW5jLFxuICBta2RpclN5bmMsXG4gIGNwU3luYyxcbiAgcmVuYW1lU3luYyxcbiAgc3RhdFN5bmMsXG59IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGpvaW4gYXMgam9pblBvc2l4IH0gZnJvbSBcIm5vZGU6cGF0aC9wb3NpeFwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCBnZXREZWJ1ZyBmcm9tIFwiZGVidWdcIjtcbmltcG9ydCB7IExPR19QUkVGSVgsIE5leHRqc1R5cGUgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBOZXh0anNCYXNlUHJvcHMgfSBmcm9tIFwiLi4vcm9vdC1jb25zdHJ1Y3RzL25leHRqcy1iYXNlLWNvbnN0cnVjdFwiO1xuaW1wb3J0IHsgcmVhZE5leHRDb25maWdCYXNlUGF0aCB9IGZyb20gXCIuLi91dGlscy9iYXNlLXBhdGhcIjtcbmltcG9ydCB7IHVzZURlZGljYXRlZEltYWdlRnVuY3Rpb24gfSBmcm9tIFwiLi4vdXRpbHMvZXhwZXJpbWVudGFsLWZsYWdzXCI7XG5pbXBvcnQgeyBnZXROb2RlQXJjaGl0ZWN0dXJlIH0gZnJvbSBcIi4uL3V0aWxzL2dldC1hcmNoaXRlY3R1cmVcIjtcblxuY29uc3QgZGVidWcgPSBnZXREZWJ1ZyhcImNkay1uZXh0anM6bmV4dGpzLWJ1aWxkXCIpO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0J1aWxkUHJvcHMge1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQmFzZVByb3BzW1wiYnVpbGRDb21tYW5kXCJdfVxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGRDb21tYW5kOiBOZXh0anNCYXNlUHJvcHNbXCJidWlsZENvbW1hbmRcIl07XG4gIC8qKlxuICAgKiBEaXJlY3Rvcnkgd2hlcmUgdGhlIE5leHQuanMgYXBwbGljYXRpb24gaXMgbG9jYXRlZCBmb3IgbG9jYWwgYnVpbGRzLlxuICAgKiBUaGlzIHNob3VsZCBjb250YWluIHRoZSBwYWNrYWdlLmpzb24gYW5kIE5leHQuanMgYXBwbGljYXRpb24gZmlsZXMuXG4gICAqL1xuICByZWFkb25seSBidWlsZERpcmVjdG9yeTogc3RyaW5nO1xuICByZWFkb25seSBuZXh0anNUeXBlOiBOZXh0anNUeXBlO1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQmFzZVByb3BzLnNraXBCdWlsZH1cbiAgICovXG4gIHJlYWRvbmx5IHNraXBCdWlsZD86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHVibGljRGlyRW50cnkge1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGlzRGlyZWN0b3J5OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEJ1aWxkcyBOZXh0LmpzIGFzc2V0cy5cbiAqIEBsaW5rIGh0dHBzOi8vbmV4dGpzLm9yZy9kb2NzL3BhZ2VzL2FwaS1yZWZlcmVuY2UvbmV4dC1jb25maWctanMvb3V0cHV0XG4gKi9cbmV4cG9ydCBjbGFzcyBOZXh0anNCdWlsZCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBVbmlxdWUgaWQgZm9yIE5leHQuanMgYnVpbGQuIFVzZWQgdG8gcGFydGl0aW9uIGNhY2hlIHN0b3JhZ2UgYW5kIGFzXG4gICAqIG1ldGFkYXRhIGZvciBzdGF0aWMgYXNzZXRzIGluIFMzIGJ1Y2tldC5cbiAgICovXG4gIGJ1aWxkSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gdGhlIGluaXQgY2FjaGUgZGlyZWN0b3J5XG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvLm5leHQvY2RrLW5leHRqcy1pbml0LWNhY2hlXCJcbiAgICovXG4gIGluaXRDYWNoZURpcjogc3RyaW5nO1xuICAvKipcbiAgICogQWJzb2x1dGUgcGF0aCB0byBwdWJsaWMuIFVzZSBieSBDbG91ZEZyb250L0FMQiB0byBjcmVhdGUgYmVoYXZpb3JzL3J1bGVzXG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvcHVibGljXCJcbiAgICovXG4gIHB1YmxpY0RpckVudHJpZXM6IFB1YmxpY0RpckVudHJ5W107XG4gIC8qKlxuICAgKiBUaGUgZW50cnlwb2ludCBKYXZhU2NyaXB0IGZpbGUgdXNlZCBhcyBhbiBhcmd1bWVudCBmb3IgTm9kZS5qcyB0byBydW4gdGhlXG4gICAqIE5leHQuanMgc3RhbmRhbG9uZSBzZXJ2ZXIgcmVsYXRpdmUgdG8gdGhlIHN0YW5kYWxvbmUgZGlyZWN0b3J5LlxuICAgKiBAZXhhbXBsZSBcIi4vc2VydmVyLmpzXCJcbiAgICogQGV4YW1wbGUgXCIuL3BhY2thZ2VzL3VpL3NlcnZlci5qc1wiIChtb25vcmVwbylcbiAgICovXG4gIHJlbGF0aXZlUGF0aFRvRW50cnlwb2ludDogc3RyaW5nO1xuICAvKipcbiAgICogUmVsYXRpdmUgcGF0aCBmcm9tIHRoZSBzdGFuZGFsb25lIGRpcmVjdG9yeSB0byB0aGUgcGFja2FnZSBjb250YWluaW5nIHRoZSBOZXh0LmpzIGFwcC5cbiAgICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IGRldGVjdGVkIGZyb20gdGhlIHN0YW5kYWxvbmUgYnVpbGQgb3V0cHV0LlxuICAgKiBAZXhhbXBsZSBcIi5cIiBmb3Igbm9uLW1vbm9yZXBvIGFwcHNcbiAgICogQGV4YW1wbGUgXCIuL2FwcHMvd2ViXCIgZm9yIG1vbm9yZXBvIGFwcHNcbiAgICovXG4gIHJlbGF0aXZlUGF0aFRvUGFja2FnZTogc3RyaW5nO1xuICAvKipcbiAgICogQWJzb2x1dGUgcGF0aCB0byB0aGUgLm5leHQgZGlyZWN0b3J5IGNvbnRhaW5pbmcgTmV4dC5qcyBidWlsZCBhcnRpZmFjdHNcbiAgICovXG4gIGRvdE5leHRQYXRoOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgTmV4dC5qcyBhcHAncyBvd24gYGJhc2VQYXRoYCDigJQgdGhlIFVSTCBwcmVmaXggaXQgZ2VuZXJhdGVzIGl0cyBsaW5rcyBhbmRcbiAgICogYXNzZXQgaHJlZnMgdW5kZXIg4oCUIHJlYWQgb3V0IG9mIHRoZSBidWlsZCdzIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAuXG4gICAqIE5vcm1hbGl6ZWQgdG8gYSBiYXJlIHBhdGggc2VnbWVudCwgZW1wdHkgd2hlbiB0aGUgYXBwIHNldHMgbm9uZS4gRXhwb3NlZCBzb1xuICAgKiByb290IGNvbnN0cnVjdHMgY2FuIHJlY29uY2lsZSBpdCB3aXRoIHRoZSBDREsgYGJhc2VQYXRoYCBwcm9wLCB3aGljaCBpcyBhXG4gICAqIGRpc3RpbmN0IHRoaW5nOyBzZWUgYHJlc29sdmVCYXNlUGF0aGAuXG4gICAqL1xuICBuZXh0Q29uZmlnQmFzZVBhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gdGhlIGRpcmVjdG9yeSBwcmVwYXJlZCBmb3IgdGhlIGltYWdlIG9wdGltaXphdGlvbiBMYW1iZGFcbiAgICogYXNzZXQ6IGJ1bmRsZWQgaGFuZGxlciwgZ2xpYmMgYHNoYXJwYCBiaW5hcmllcywgYW5kIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAuXG4gICAqIE9ubHkgc2V0IGZvciB7QGxpbmsgTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TfSBhbmRcbiAgICoge0BsaW5rIE5leHRqc1R5cGUuUkVHSU9OQUxfRlVOQ1RJT05TfSwgYW5kIG9ubHkgd2hlbiB0aGUgZGVkaWNhdGVkIGltYWdlXG4gICAqIG9wdGltaXphdGlvbiBMYW1iZGEgaXMgZW5hYmxlZC5cbiAgICovXG4gIGltYWdlT3B0aW1pemF0aW9uQXNzZXRQYXRoPzogc3RyaW5nO1xuXG4gIHByaXZhdGUgcHJvcHM6IE5leHRqc0J1aWxkUHJvcHM7XG4gIHByaXZhdGUgYnVpbGRDb21tYW5kOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE5leHRqc0J1aWxkUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMucHJvcHMgPSBwcm9wcztcbiAgICB0aGlzLmRvdE5leHRQYXRoID0gam9pbihwcm9wcy5idWlsZERpcmVjdG9yeSwgXCIubmV4dFwiKTtcblxuICAgIHRoaXMuYnVpbGRDb21tYW5kID0gcHJvcHMuYnVpbGRDb21tYW5kIHx8IFwibnBtIHJ1biBidWlsZFwiO1xuXG4gICAgLy8gU2V0IGluaXQgY2FjaGUgZGlyZWN0b3J5IHBhdGhcbiAgICB0aGlzLmluaXRDYWNoZURpciA9IGpvaW4oXG4gICAgICBwcm9wcy5idWlsZERpcmVjdG9yeSxcbiAgICAgIFwiLm5leHRcIixcbiAgICAgIFwiY2RrLW5leHRqcy1pbml0LWNhY2hlXCIsXG4gICAgKTtcblxuICAgIC8vIEV4ZWN1dGUgbG9jYWwgYnVpbGQgcHJvY2Vzc1xuICAgIGlmIChwcm9wcy5za2lwQnVpbGQgIT09IHRydWUpIHtcbiAgICAgIHRoaXMucnVuTmV4dEJ1aWxkKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlYnVnKGAke0xPR19QUkVGSVh9IFNraXBwaW5nOiAke3RoaXMuYnVpbGRDb21tYW5kfWApO1xuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIGJ1aWxkIG91dHB1dCBhbmQgc2V0IHZhbGlkYXRlZCBwYXRoc1xuICAgIHRoaXMudmFsaWRhdGVOZXh0QnVpbGRPdXRwdXQoKTtcblxuICAgIC8vIEF1dG8tZGV0ZWN0IHJlbGF0aXZlUGF0aFRvUGFja2FnZSBmcm9tIHN0YW5kYWxvbmUgYnVpbGQgb3V0cHV0XG4gICAgdGhpcy5yZWxhdGl2ZVBhdGhUb1BhY2thZ2UgPSB0aGlzLmZpbmRSZWxhdGl2ZVBhdGhUb1NlcnZlckpzKCk7XG5cbiAgICAvLyBTZXQgZW50cnlwb2ludCBwYXRoIHVzaW5nIGRldGVjdGVkIHJlbGF0aXZlUGF0aFRvUGFja2FnZVxuICAgIHRoaXMucmVsYXRpdmVQYXRoVG9FbnRyeXBvaW50ID0gam9pblBvc2l4KFxuICAgICAgdGhpcy5yZWxhdGl2ZVBhdGhUb1BhY2thZ2UgPT09IFwiLlwiID8gXCJcIiA6IHRoaXMucmVsYXRpdmVQYXRoVG9QYWNrYWdlLFxuICAgICAgXCJzZXJ2ZXIuanNcIixcbiAgICApO1xuXG4gICAgdGhpcy5idWlsZElkID0gdGhpcy5nZXRCdWlsZElkKCk7XG4gICAgdGhpcy5wdWJsaWNEaXJFbnRyaWVzID0gdGhpcy5nZXRMb2NhbFB1YmxpY0RpckVudHJpZXMoKTtcbiAgICB0aGlzLm5leHRDb25maWdCYXNlUGF0aCA9IHJlYWROZXh0Q29uZmlnQmFzZVBhdGgodGhpcy5kb3ROZXh0UGF0aCk7XG5cbiAgICBjb25zdCBzdGFuZGFsb25lUGF0aCA9IGpvaW4odGhpcy5kb3ROZXh0UGF0aCwgXCJzdGFuZGFsb25lXCIpO1xuICAgIGNvbnN0IGlzRnVuY3Rpb25zID1cbiAgICAgIHByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuR0xPQkFMX0ZVTkNUSU9OUyB8fFxuICAgICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5SRUdJT05BTF9GVU5DVElPTlM7XG5cbiAgICBjb25zdCBkZWRpY2F0ZWRJbWFnZUZ1bmN0aW9uID0gaXNGdW5jdGlvbnMgJiYgdXNlRGVkaWNhdGVkSW1hZ2VGdW5jdGlvbigpO1xuXG4gICAgLy8gU3RyaXAgd2hhdGV2ZXIgcGxhdGZvcm0tc3BlY2lmaWMgU2hhcnAgYmluYXJpZXMgYG5leHQgYnVpbGRgJ3Mgb3V0cHV0XG4gICAgLy8gZmlsZSB0cmFjaW5nIGJ1bmRsZWQgaW4gZWl0aGVyIHdheSwgc2luY2UgdGhleSdyZSB0aGUgaG9zdCdzIChlLmcuXG4gICAgLy8gbWFjT1MvZ2xpYmMpIHJhdGhlciB0aGFuIHRoZSBkZXBsb3ltZW50IHRhcmdldCdzLlxuICAgIHRoaXMucmVtb3ZlRXhpc3RpbmdTaGFycEJpbmFyaWVzKHN0YW5kYWxvbmVQYXRoKTtcbiAgICAvLyBUaGUgc3RhbmRhbG9uZSBzZXJ2ZXIgc2VydmVzIGBfbmV4dC9pbWFnZWAgaXRzZWxmIHVubGVzcyBhIGRlZGljYXRlZFxuICAgIC8vIGltYWdlIG9wdGltaXphdGlvbiBMYW1iZGEgdGFrZXMgb3ZlciB0aGF0IHJvdXRlLCBhbmQgaXQgcnVucyBvblxuICAgIC8vIG5vZGU6MjQtYWxwaW5lIChzZWUgZnVuY3Rpb25zLkRvY2tlcmZpbGUpIC8gdGhlIHNhbWUgQWxwaW5lIGJhc2UgZm9yXG4gICAgLy8gQ29udGFpbmVycywgc28gaXQgbmVlZHMgbXVzbCBiaW5hcmllcy4gU2tpcHBpbmcgdGhpcyBpbnN0YWxsIHdoZW4gU2hhcnBcbiAgICAvLyAqaXMqIGludm9rZWQgZnJvbSB0aGUgc2VydmVyIGlzIHNpbGVudDogYGltYWdlT3B0aW1pemVyYCBjYXRjaGVzIHRoZVxuICAgIC8vIGxvYWQgZmFpbHVyZSBpbnRlcm5hbGx5IGFuZCByZXR1cm5zIHRoZSB1bm9wdGltaXplZCBvcmlnaW5hbCB3aXRoIGFuXG4gICAgLy8gSFRUUCAyMDAuXG4gICAgaWYgKCFkZWRpY2F0ZWRJbWFnZUZ1bmN0aW9uKSB7XG4gICAgICB0aGlzLmRvd25sb2FkQW5kSW5zdGFsbFNoYXJwQmluYXJpZXMoKTtcbiAgICB9XG5cbiAgICBpZiAoZGVkaWNhdGVkSW1hZ2VGdW5jdGlvbikge1xuICAgICAgdGhpcy5pbWFnZU9wdGltaXphdGlvbkFzc2V0UGF0aCA9XG4gICAgICAgIHRoaXMucHJlcGFyZUltYWdlT3B0aW1pemF0aW9uQXNzZXRzKHN0YW5kYWxvbmVQYXRoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSBsb2NhbCBidWlsZCBjb21tYW5kIGluIHRoZSBzcGVjaWZpZWQgZGlyZWN0b3J5XG4gICAqL1xuICBwcml2YXRlIHJ1bk5leHRCdWlsZCgpIHtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGAke0xPR19QUkVGSVh9IFJ1bm5pbmc6IFwiJHt0aGlzLmJ1aWxkQ29tbWFuZH1cIiBpbiBkaXJlY3Rvcnk6ICR7dGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeX1gLFxuICAgICk7XG5cbiAgICAvLyBDbGVhbiBleGlzdGluZyBjYWNoZSBkaXJlY3RvcnkgdG8gYXZvaWQgc3RhbGUgZGF0YSBmcm9tIHByZXZpb3VzIGJ1aWxkc1xuICAgIGlmIChleGlzdHNTeW5jKHRoaXMuaW5pdENhY2hlRGlyKSkge1xuICAgICAgcm1TeW5jKHRoaXMuaW5pdENhY2hlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICBkZWJ1ZyhgQ2xlYW5lZCBleGlzdGluZyBjYWNoZSBkaXJlY3Rvcnk6ICR7dGhpcy5pbml0Q2FjaGVEaXJ9YCk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKHRoaXMuYnVpbGRDb21tYW5kLCB7XG4gICAgICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgICAgICAgY3dkOiB0aGlzLnByb3BzLmJ1aWxkRGlyZWN0b3J5LFxuICAgICAgICBlbnY6IHtcbiAgICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgICBDREtfTkVYVEpTX0lOSVRfQ0FDSEVfRElSOiB0aGlzLmluaXRDYWNoZURpcixcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBDb3B5IHBhdGNoLWZldGNoLmpzIGludG8gY2xpZW50IEpTIGJ1bmRsZSBhZnRlciBidWlsZCBvbmx5IGZvciBOZXh0anNHbG9iYWxGdW5jdGlvbnNcbiAgICAgIGlmICh0aGlzLnByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuR0xPQkFMX0ZVTkNUSU9OUykge1xuICAgICAgICB0aGlzLnBhdGNoRmV0Y2hJbkNsaWVudEpzKCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTG9jYWwgYnVpbGQgZmFpbGVkOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBOZXh0LmpzIGJ1aWxkIG91dHB1dFxuICAgKiBBbGwgYnVpbGRzIG11c3QgYmUgc3RhbmRhbG9uZSAtIG5vIGZhbGxiYWNrIHRvIHJlZ3VsYXIgYnVpbGRzXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlTmV4dEJ1aWxkT3V0cHV0KCk6IHZvaWQge1xuICAgIGNvbnN0IHN0YW5kYWxvbmVEaXIgPSBqb2luKHRoaXMuZG90TmV4dFBhdGgsIFwic3RhbmRhbG9uZVwiKTtcbiAgICAvLyBTdGFuZGFsb25lIGRpcmVjdG9yeSBpcyBtYW5kYXRvcnlcbiAgICBpZiAoIWV4aXN0c1N5bmMoc3RhbmRhbG9uZURpcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFN0YW5kYWxvbmUgYnVpbGQgZGlyZWN0b3J5IG5vdCBmb3VuZDogJHtzdGFuZGFsb25lRGlyfS4gYCArXG4gICAgICAgICAgYEFsbCBidWlsZHMgbXVzdCBiZSBjb25maWd1cmVkIGZvciBzdGFuZGFsb25lIG91dHB1dC4gYCArXG4gICAgICAgICAgYFBsZWFzZSBlbnN1cmUgeW91ciBuZXh0LmNvbmZpZy5qcyBpbmNsdWRlcyAnb3V0cHV0OiBcInN0YW5kYWxvbmVcIicuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIEFkZGl0aW9uYWwgdmFsaWRhdGlvbiAoc2VydmVyLmpzIHdpdGggLm5leHQgc2libGluZykgaGFwcGVucyBpbiBmaW5kUmVsYXRpdmVQYXRoVG9TZXJ2ZXJKcygpXG4gIH1cblxuICAvKipcbiAgICogRmluZCBlbnRyeXBvaW50IGNsaWVudCBzaWRlIGpzIGZpbGVzIHRvIHBhdGNoIGBmZXRjaGAgb25seSBmb3IgTmV4dGpzR2xvYmFsRnVuY3Rpb25zXG4gICAqL1xuICBwcml2YXRlIHBhdGNoRmV0Y2hJbkNsaWVudEpzKCkge1xuICAgIGNvbnN0IHN0YXRpY0NodW5rc1BhdGggPSBqb2luKHRoaXMuZG90TmV4dFBhdGgsIFwic3RhdGljXCIsIFwiY2h1bmtzXCIpO1xuICAgIGNvbnN0IGNodW5rRmlsZXMgPSByZWFkZGlyU3luYyhzdGF0aWNDaHVua3NQYXRoKS5maWx0ZXIoXG4gICAgICAoZmlsZTogc3RyaW5nKSA9PlxuICAgICAgICAvLyBtYWluLWFwcC0gZm9yIHdlYnBhY2ssIHR1cmJvcGFjay0gZm9yIHR1cmJvXG4gICAgICAgIGZpbGUuc3RhcnRzV2l0aChcIm1haW4tYXBwLVwiKSB8fFxuICAgICAgICAoZmlsZS5zdGFydHNXaXRoKFwidHVyYm9wYWNrLVwiKSAmJiBmaWxlLmVuZHNXaXRoKFwiLmpzXCIpKSxcbiAgICApO1xuXG4gICAgaWYgKGNodW5rRmlsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBjbGllbnQgc2lkZSBqcyBlbnRyeXBvaW50IGZpbGVzIGZvdW5kXCIpO1xuICAgIH1cblxuICAgIC8vIFJlYWQgdGhlIHBhdGNoLWZldGNoLmpzIGNvbnRlbnRcbiAgICBjb25zdCBwYXRjaEZldGNoUGF0aCA9IGpvaW4oX19kaXJuYW1lLCBcInBhdGNoLWZldGNoLmpzXCIpO1xuICAgIGlmICghZXhpc3RzU3luYyhwYXRjaEZldGNoUGF0aCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInBhdGNoLWZldGNoLmpzIG5vdCBmb3VuZFwiKTtcbiAgICB9XG5cbiAgICBjb25zdCBwYXRjaEZldGNoQ29udGVudCA9IHJlYWRGaWxlU3luYyhwYXRjaEZldGNoUGF0aCwgXCJ1dGYtOFwiKTtcblxuICAgIC8vIFByZXBlbmQgcGF0Y2gtZmV0Y2ggbG9naWMgdG8gZWFjaCBlbnRyeXBvaW50XG4gICAgZm9yIChjb25zdCBjaHVua0ZpbGUgb2YgY2h1bmtGaWxlcykge1xuICAgICAgY29uc3QgY2h1bmtGaWxlUGF0aCA9IGpvaW4oc3RhdGljQ2h1bmtzUGF0aCwgY2h1bmtGaWxlKTtcbiAgICAgIGNvbnN0IG9yaWdpbmFsQ29udGVudCA9IHJlYWRGaWxlU3luYyhjaHVua0ZpbGVQYXRoLCBcInV0Zi04XCIpO1xuICAgICAgY29uc3QgcGF0Y2hlZENvbnRlbnQgPSBwYXRjaEZldGNoQ29udGVudCArIFwiXFxuXCIgKyBvcmlnaW5hbENvbnRlbnQ7XG4gICAgICB3cml0ZUZpbGVTeW5jKGNodW5rRmlsZVBhdGgsIHBhdGNoZWRDb250ZW50KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXV0b21hdGljYWxseSBmaW5kcyB0aGUgcmVsYXRpdmUgcGF0aCBmcm9tIHN0YW5kYWxvbmUgZGlyZWN0b3J5IHRvIHRoZVxuICAgKiBwYWNrYWdlIGNvbnRhaW5pbmcgc2VydmVyLmpzIGJ5IHNlYXJjaGluZyBmb3Igc2VydmVyLmpzIHdpdGggYSAubmV4dCBzaWJsaW5nLlxuICAgKiBAcmV0dXJucyBcIi5cIiBmb3Igbm9uLW1vbm9yZXBvIGFwcHMsIG9yIHJlbGF0aXZlIHBhdGggbGlrZSBcImFwcC1wbGF5Z3JvdW5kXCIgZm9yIG1vbm9yZXBvIGFwcHNcbiAgICovXG4gIHByaXZhdGUgZmluZFJlbGF0aXZlUGF0aFRvU2VydmVySnMoKTogc3RyaW5nIHtcbiAgICBjb25zdCBzdGFuZGFsb25lRGlyID0gam9pbih0aGlzLmRvdE5leHRQYXRoLCBcInN0YW5kYWxvbmVcIik7XG5cbiAgICBpZiAoIWV4aXN0c1N5bmMoc3RhbmRhbG9uZURpcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENhbm5vdCBkZXRlY3QgcmVsYXRpdmVQYXRoVG9QYWNrYWdlOiBzdGFuZGFsb25lIGRpcmVjdG9yeSBub3QgZm91bmQgYXQgJHtzdGFuZGFsb25lRGlyfWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGZpbmRTZXJ2ZXJKcyA9IChcbiAgICAgIGRpcjogc3RyaW5nLFxuICAgICAgcmVsYXRpdmVQYXRoOiBzdHJpbmcgPSBcIlwiLFxuICAgICk6IHN0cmluZyB8IG51bGwgPT4ge1xuICAgICAgY29uc3QgZW50cmllcyA9IHJlYWRkaXJTeW5jKGRpciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pO1xuXG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGRpciwgZW50cnkubmFtZSk7XG5cbiAgICAgICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkgJiYgZW50cnkubmFtZSAhPT0gXCJub2RlX21vZHVsZXNcIikge1xuICAgICAgICAgIC8vIFJlY3Vyc2l2ZWx5IHNlYXJjaCBkaXJlY3RvcmllcyAoc2tpcCBub2RlX21vZHVsZXMgYXQgcm9vdCBsZXZlbClcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBmaW5kU2VydmVySnMoZnVsbFBhdGgsIGpvaW4ocmVsYXRpdmVQYXRoLCBlbnRyeS5uYW1lKSk7XG4gICAgICAgICAgaWYgKHJlc3VsdCAhPT0gbnVsbCkgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSBlbHNlIGlmIChlbnRyeS5pc0ZpbGUoKSAmJiBlbnRyeS5uYW1lID09PSBcInNlcnZlci5qc1wiKSB7XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBzZXJ2ZXIuanMgaGFzIGEgLm5leHQgc2libGluZyBkaXJlY3RvcnlcbiAgICAgICAgICBjb25zdCBwYXJlbnREaXIgPSBkaXI7XG4gICAgICAgICAgY29uc3QgZG90TmV4dFBhdGggPSBqb2luKHBhcmVudERpciwgXCIubmV4dFwiKTtcbiAgICAgICAgICBpZiAoZXhpc3RzU3luYyhkb3ROZXh0UGF0aCkpIHtcbiAgICAgICAgICAgIHJldHVybiByZWxhdGl2ZVBhdGggfHwgXCIuXCI7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xuXG4gICAgY29uc3QgcmVzdWx0ID0gZmluZFNlcnZlckpzKHN0YW5kYWxvbmVEaXIpO1xuICAgIGlmIChyZXN1bHQgPT09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENhbm5vdCBkZXRlY3QgcmVsYXRpdmVQYXRoVG9QYWNrYWdlOiBDb3VsZCBub3QgZmluZCBzZXJ2ZXIuanMgd2l0aCAubmV4dCBzaWJsaW5nIGluICR7c3RhbmRhbG9uZURpcn0uIGAgK1xuICAgICAgICAgIGBQbGVhc2UgZW5zdXJlIE5leHQuanMgYnVpbGQgY29tcGxldGVkIHN1Y2Nlc3NmdWxseSBvciBwcm92aWRlIHJlbGF0aXZlUGF0aFRvUGFja2FnZSBtYW51YWxseS5gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBBdXRvLWRldGVjdGVkIHJlbGF0aXZlUGF0aFRvUGFja2FnZTogXCIke3Jlc3VsdH1cImApO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGJ1aWxkIElEIGZyb20gLm5leHQgZGlyZWN0b3J5XG4gICAqL1xuICBwcml2YXRlIGdldEJ1aWxkSWQoKTogc3RyaW5nIHtcbiAgICBjb25zdCBidWlsZElkUGF0aCA9IGpvaW4odGhpcy5kb3ROZXh0UGF0aCwgXCJCVUlMRF9JRFwiKTtcbiAgICAvLyBWZXJpZnkgQlVJTERfSUQgZXhpc3RzIChuZWVkZWQgZm9yIGNhY2hlIHBhcnRpdGlvbmluZylcbiAgICBpZiAoIWV4aXN0c1N5bmMoYnVpbGRJZFBhdGgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBCVUlMRF9JRCBmaWxlIG5vdCBmb3VuZCBhdCAke2J1aWxkSWRQYXRofS4gYCArXG4gICAgICAgICAgYEVuc3VyZSBOZXh0LmpzIGJ1aWxkIGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIEJVSUxEX0lEIGV4aXN0ZW5jZSBpcyBhbHJlYWR5IHZhbGlkYXRlZCBpbiB2YWxpZGF0ZU5leHRCdWlsZE91dHB1dCgpXG4gICAgcmV0dXJuIHJlYWRGaWxlU3luYyhidWlsZElkUGF0aCwgXCJ1dGYtOFwiKS50cmltKCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHB1YmxpYyBkaXJlY3RvcnkgZW50cmllcyBmcm9tIGxvY2FsIGZpbGVzeXN0ZW1cbiAgICovXG4gIHByaXZhdGUgZ2V0TG9jYWxQdWJsaWNEaXJFbnRyaWVzKCk6IFB1YmxpY0RpckVudHJ5W10ge1xuICAgIGNvbnN0IHB1YmxpY0RpclBhdGggPSBqb2luKHRoaXMucHJvcHMuYnVpbGREaXJlY3RvcnksIFwicHVibGljXCIpO1xuICAgIGlmICghZXhpc3RzU3luYyhwdWJsaWNEaXJQYXRoKSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gcmVhZGRpclN5bmMocHVibGljRGlyUGF0aCwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pLm1hcChcbiAgICAgICAgKGVudHJ5OiBhbnkpID0+ICh7XG4gICAgICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgICAgICBpc0RpcmVjdG9yeTogZW50cnkuaXNEaXJlY3RvcnkoKSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLndhcm4oYCR7TE9HX1BSRUZJWH0gRmFpbGVkIHRvIHJlYWQgcHVibGljIGRpcmVjdG9yeTogJHtlcnJvcn1gKTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVjdXJzaXZlbHkgZmluZCBhbmQgcmVtb3ZlIGV4aXN0aW5nIFNoYXJwIHBsYXRmb3JtIGJpbmFyaWVzXG4gICAqL1xuICBwcml2YXRlIHJlbW92ZUV4aXN0aW5nU2hhcnBCaW5hcmllcyhzdGFuZGFsb25lUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3Qgbm9kZU1vZHVsZXNQYXRoID0gam9pbihzdGFuZGFsb25lUGF0aCwgXCJub2RlX21vZHVsZXNcIik7XG4gICAgaWYgKCFleGlzdHNTeW5jKG5vZGVNb2R1bGVzUGF0aCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgLy8gVXNlIHJlY3Vyc2l2ZSByZWFkZGlyU3luYyB0byBmaW5kIGFsbCBTaGFycCBiaW5hcnkgZGlyZWN0b3JpZXMgYW5kIHN5bWxpbmtzXG4gICAgICBjb25zdCBhbGxFbnRyaWVzID0gcmVhZGRpclN5bmMobm9kZU1vZHVsZXNQYXRoLCB7XG4gICAgICAgIHJlY3Vyc2l2ZTogdHJ1ZSxcbiAgICAgICAgd2l0aEZpbGVUeXBlczogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBzaGFycEJpbmFyeVBhdGhzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGFsbEVudHJpZXMpIHtcbiAgICAgICAgLy8gQ2hlY2sgZm9yIGJvdGggZGlyZWN0b3JpZXMgYW5kIHN5bWxpbmtzIChwbnBtIGNyZWF0ZXMgc3ltbGlua3MpXG4gICAgICAgIGlmIChlbnRyeS5pc0RpcmVjdG9yeSgpIHx8IGVudHJ5LmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgICAvLyBNYXRjaCBTaGFycCBiaW5hcnkgcGFja2FnZXMgd2l0aCBtb3JlIGNvbXByZWhlbnNpdmUgcGF0dGVybnNcbiAgICAgICAgICBjb25zdCBpc1NoYXJwQmluYXJ5ID1cbiAgICAgICAgICAgIGVudHJ5Lm5hbWUuaW5jbHVkZXMoXCJzaGFycC1cIikgfHxcbiAgICAgICAgICAgIGVudHJ5Lm5hbWUuaW5jbHVkZXMoXCJzaGFycC1saWJ2aXBzXCIpO1xuXG4gICAgICAgICAgaWYgKGlzU2hhcnBCaW5hcnkpIHtcbiAgICAgICAgICAgIC8vIEZvciByZWN1cnNpdmUgcmVhZGRpclN5bmMsIHBhcmVudFBhdGggY29udGFpbnMgdGhlIGZ1bGwgYWJzb2x1dGUgcGF0aFxuICAgICAgICAgICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGVudHJ5LnBhcmVudFBhdGgsIGVudHJ5Lm5hbWUpO1xuICAgICAgICAgICAgc2hhcnBCaW5hcnlQYXRocy5wdXNoKGZ1bGxQYXRoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZGVidWcoXG4gICAgICAgIGAke0xPR19QUkVGSVh9IEZvdW5kICR7c2hhcnBCaW5hcnlQYXRocy5sZW5ndGh9IFNoYXJwIGJpbmFyeSBkaXJlY3Rvcmllcy9zeW1saW5rcyB0byByZW1vdmVgLFxuICAgICAgKTtcblxuICAgICAgLy8gUmVtb3ZlIGFsbCBmb3VuZCBTaGFycCBiaW5hcnkgZGlyZWN0b3JpZXMgYW5kIHN5bWxpbmtzXG4gICAgICBmb3IgKGNvbnN0IHBhdGggb2Ygc2hhcnBCaW5hcnlQYXRocykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHJtU3luYyhwYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICAgICAgZGVidWcoYCR7TE9HX1BSRUZJWH0gUmVtb3ZlZDogJHtwYXRofWApO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgIGAke0xPR19QUkVGSVh9IFdhcm5pbmc6IENvdWxkIG5vdCByZW1vdmUgJHtwYXRofTogJHtlcnJvcn1gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSBXYXJuaW5nOiBDb3VsZCBub3QgcmVhZCBub2RlX21vZHVsZXMgZGlyZWN0b3J5OiAke2Vycm9yfWAsXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEb3dubG9hZCBhbmQgaW5zdGFsbCBjb3JyZWN0IFNoYXJwIGJpbmFyaWVzIGZvciBMaW51eCBNVVNMXG4gICAqL1xuICBwcml2YXRlIGRvd25sb2FkQW5kSW5zdGFsbFNoYXJwQmluYXJpZXMoKTogdm9pZCB7XG4gICAgY29uc3Qgbm9kZU1vZHVsZXNQYXRoID0gam9pbihcbiAgICAgIHRoaXMuZG90TmV4dFBhdGgsXG4gICAgICBcInN0YW5kYWxvbmVcIixcbiAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgKTtcbiAgICBjb25zdCBpbWdQYXRoID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwiQGltZ1wiKTtcbiAgICBjb25zdCBhcmNoID0gZ2V0Tm9kZUFyY2hpdGVjdHVyZSgpO1xuXG4gICAgdGhpcy5pbnN0YWxsU2hhcnBQYWNrYWdlcyhcbiAgICAgIGltZ1BhdGgsXG4gICAgICB0aGlzLmdldFNoYXJwQmluYXJ5UGFja2FnZXMoXG4gICAgICAgIHRoaXMuZmluZFNoYXJwUGFja2FnZShub2RlTW9kdWxlc1BhdGgpLFxuICAgICAgICBgbGludXhtdXNsLSR7YXJjaH1gLFxuICAgICAgKSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIHRoZSBkZXBsb3ltZW50IGFzc2V0IGZvciB0aGUgZGVkaWNhdGVkIGltYWdlIG9wdGltaXphdGlvblxuICAgKiBMYW1iZGE6IHRoZSBwcmUtYnVuZGxlZCBoYW5kbGVyIChmcm9tIHRoaXMgcGFja2FnZSdzIG93biBgbGliL2Agb3V0cHV0KSxcbiAgICogYHNoYXJwYCdzIEpTIHdyYXBwZXIgKGFscmVhZHkgZGVyZWZlcmVuY2VkIGZyb20gdGhlIHBucG0gc3RvcmUgYnkgTmV4dCdzXG4gICAqIG91dHB1dCBmaWxlIHRyYWNpbmcgaW50byB0aGUgc3RhbmRhbG9uZSBidWlsZCksIGdsaWJjIGBzaGFycGAgYmluYXJpZXNcbiAgICogKHRoZSBzdGFuZGFyZCBMYW1iZGEgbWFuYWdlZCBydW50aW1lIGlzIEFtYXpvbiBMaW51eCAyMDIzL2dsaWJjLCB1bmxpa2VcbiAgICogdGhlIG11c2wgYmluYXJpZXMgdGhlIERvY2tlci9MYW1iZGEgV2ViIEFkYXB0ZXIgc2VydmVyIGZ1bmN0aW9uIG5lZWRzKSxcbiAgICogYW5kIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAgKHJlYWQgYnkgdGhlIGhhbmRsZXIgYXQgY29sZCBzdGFydCB0b1xuICAgKiBidWlsZCBgbmV4dENvbmZpZ2ApLlxuICAgKi9cbiAgcHJpdmF0ZSBwcmVwYXJlSW1hZ2VPcHRpbWl6YXRpb25Bc3NldHMoc3RhbmRhbG9uZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgYXNzZXRQYXRoID0gam9pbih0aGlzLmRvdE5leHRQYXRoLCBcImNkay1uZXh0anMtaW1hZ2Utb3B0aW1pemF0aW9uXCIpO1xuICAgIGNvbnN0IG5vZGVNb2R1bGVzUGF0aCA9IGpvaW4oYXNzZXRQYXRoLCBcIm5vZGVfbW9kdWxlc1wiKTtcbiAgICBjb25zdCBpbWdQYXRoID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwiQGltZ1wiKTtcblxuICAgIHJtU3luYyhhc3NldFBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBta2RpclN5bmMoaW1nUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICAvLyBQcmUtYnVuZGxlZCBieSBlc2J1aWxkIGludG8gdGhpcyBwYWNrYWdlJ3Mgb3duIGxpYi8gb3V0cHV0LlxuICAgIGNwU3luYyhqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcImltYWdlLW9wdGltaXphdGlvblwiKSwgYXNzZXRQYXRoLCB7XG4gICAgICByZWN1cnNpdmU6IHRydWUsXG4gICAgfSk7XG5cbiAgICBjb25zdCBzaGFycFNvdXJjZSA9IHRoaXMuZmluZFNoYXJwUGFja2FnZShcbiAgICAgIGpvaW4oc3RhbmRhbG9uZVBhdGgsIFwibm9kZV9tb2R1bGVzXCIpLFxuICAgICk7XG4gICAgaWYgKHNoYXJwU291cmNlKSB7XG4gICAgICB0aGlzLmNvcHlTaGFycFJ1bnRpbWUoc2hhcnBTb3VyY2UsIG5vZGVNb2R1bGVzUGF0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYCR7TE9HX1BSRUZJWH0gXCJzaGFycFwiIG5vdCBmb3VuZCBpbiBzdGFuZGFsb25lIGJ1aWxkIG91dHB1dC4gQWRkIFwic2hhcnBcIiBhcyBhIGRlcGVuZGVuY3kgb2YgeW91ciBOZXh0LmpzIGFwcCB0byBlbmFibGUgaW1hZ2Ugb3B0aW1pemF0aW9uLmAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcXVpcmVkU2VydmVyRmlsZXMgPSBqb2luKFxuICAgICAgdGhpcy5kb3ROZXh0UGF0aCxcbiAgICAgIFwicmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25cIixcbiAgICApO1xuICAgIGlmICghZXhpc3RzU3luYyhyZXF1aXJlZFNlcnZlckZpbGVzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSBcInJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uXCIgbm90IGZvdW5kIGF0ICR7cmVxdWlyZWRTZXJ2ZXJGaWxlc30uIFRoZSBpbWFnZSBvcHRpbWl6YXRpb24gTGFtYmRhIHJlYWRzIGl0IGF0IGNvbGQgc3RhcnQgdG8gYnVpbGQgaXRzIE5leHQuanMgY29uZmlnLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBjcFN5bmMocmVxdWlyZWRTZXJ2ZXJGaWxlcywgam9pbihhc3NldFBhdGgsIFwicmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25cIikpO1xuXG4gICAgY29uc3QgYXJjaCA9IGdldE5vZGVBcmNoaXRlY3R1cmUoKTtcbiAgICB0aGlzLmluc3RhbGxTaGFycFBhY2thZ2VzKFxuICAgICAgaW1nUGF0aCxcbiAgICAgIHRoaXMuZ2V0U2hhcnBCaW5hcnlQYWNrYWdlcyhzaGFycFNvdXJjZSwgYGxpbnV4LSR7YXJjaH1gKSxcbiAgICApO1xuXG4gICAgcmV0dXJuIGFzc2V0UGF0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2NhdGUgYHNoYXJwYCdzIEpTIHdyYXBwZXIgaW5zaWRlIGEgc3RhbmRhbG9uZSBgbm9kZV9tb2R1bGVzYC5cbiAgICpcbiAgICogTmV4dCdzIG91dHB1dCBmaWxlIHRyYWNpbmcgcHJlc2VydmVzIHRoZSBpbnN0YWxsZXIncyBvbi1kaXNrIGxheW91dCwgc29cbiAgICogbnBtL3lhcm4gcHJvZHVjZSBhIGhvaXN0ZWQgYG5vZGVfbW9kdWxlcy9zaGFycGAgd2hpbGUgcG5wbSBvbmx5XG4gICAqIG1hdGVyaWFsaXplcyBgbm9kZV9tb2R1bGVzLy5wbnBtL3NoYXJwQDx2ZXJzaW9uPi9ub2RlX21vZHVsZXMvc2hhcnBgLlxuICAgKi9cbiAgcHJpdmF0ZSBmaW5kU2hhcnBQYWNrYWdlKG5vZGVNb2R1bGVzUGF0aDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBob2lzdGVkID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwic2hhcnBcIik7XG4gICAgaWYgKGV4aXN0c1N5bmMoam9pbihob2lzdGVkLCBcInBhY2thZ2UuanNvblwiKSkpIHtcbiAgICAgIHJldHVybiBob2lzdGVkO1xuICAgIH1cblxuICAgIGNvbnN0IHBucG1QYXRoID0gam9pbihub2RlTW9kdWxlc1BhdGgsIFwiLnBucG1cIik7XG4gICAgaWYgKCFleGlzdHNTeW5jKHBucG1QYXRoKSkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBjb25zdCBjYW5kaWRhdGVzID0gcmVhZGRpclN5bmMocG5wbVBhdGgpXG4gICAgICAuZmlsdGVyKChuYW1lKSA9PiBuYW1lLnN0YXJ0c1dpdGgoXCJzaGFycEBcIikpXG4gICAgICAuc29ydCgpO1xuICAgIGZvciAoY29uc3QgY2FuZGlkYXRlIG9mIGNhbmRpZGF0ZXMucmV2ZXJzZSgpKSB7XG4gICAgICBjb25zdCBuZXN0ZWQgPSBqb2luKHBucG1QYXRoLCBjYW5kaWRhdGUsIFwibm9kZV9tb2R1bGVzXCIsIFwic2hhcnBcIik7XG4gICAgICBpZiAoZXhpc3RzU3luYyhqb2luKG5lc3RlZCwgXCJwYWNrYWdlLmpzb25cIikpKSB7XG4gICAgICAgIHJldHVybiBuZXN0ZWQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb3B5IGBzaGFycGAgcGx1cyB0aGUgdHJhbnNpdGl2ZSBgZGVwZW5kZW5jaWVzYCBjbG9zdXJlIGByZXF1aXJlKFwic2hhcnBcIilgXG4gICAqIHB1bGxzIGluIChgQGltZy9jb2xvdXJgLCBgZGV0ZWN0LWxpYmNgLCBgc2VtdmVyYCkgaW50byBgdGFyZ2V0UGF0aGAuXG4gICAqXG4gICAqIENvcHlpbmcgb25seSBgc2hhcnBgIGl0c2VsZiBsZWF2ZXMgdGhvc2UgcmVxdWlyZXMgdW5yZXNvbHZhYmxlLCBhbmRcbiAgICogYGltYWdlT3B0aW1pemVyYCBzd2FsbG93cyB0aGUgcmVzdWx0aW5nIGBNT0RVTEVfTk9UX0ZPVU5EYCBieSBmYWxsaW5nIGJhY2tcbiAgICogdG8gc2VydmluZyB0aGUgdW5vcHRpbWl6ZWQgb3JpZ2luYWwsIHNvIHRoZSBvbWlzc2lvbiBpcyBvdGhlcndpc2Ugc2lsZW50LlxuICAgKi9cbiAgcHJpdmF0ZSBjb3B5U2hhcnBSdW50aW1lKHNoYXJwU291cmNlOiBzdHJpbmcsIHRhcmdldFBhdGg6IHN0cmluZyk6IHZvaWQge1xuICAgIC8vIFVuZGVyIHBucG0gYSBwYWNrYWdlJ3MgZGVwZW5kZW5jaWVzIGFyZSBzeW1saW5rZWQgaW50byB0aGUgc2libGluZ1xuICAgIC8vIGRpcmVjdG9yeSBhbG9uZ3NpZGUgaXQsIHdoaWNoIGlzIGFsc28gd2hlcmUgYSBob2lzdGVkIGxheW91dCBrZWVwc1xuICAgIC8vIHRoZW0sIHNvIHRoZSBzYW1lIGxvb2t1cCBjb3ZlcnMgYm90aC5cbiAgICBjb25zdCBsb29rdXBQYXRoID0gam9pbihzaGFycFNvdXJjZSwgXCIuLlwiKTtcbiAgICBjb25zdCBxdWV1ZSA9IFtcInNoYXJwXCJdO1xuICAgIGNvbnN0IGNvcGllZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gICAgd2hpbGUgKHF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IG5hbWUgPSBxdWV1ZS5zaGlmdCgpITtcbiAgICAgIGlmIChjb3BpZWQuaGFzKG5hbWUpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzb3VyY2UgPSBuYW1lID09PSBcInNoYXJwXCIgPyBzaGFycFNvdXJjZSA6IGpvaW4obG9va3VwUGF0aCwgbmFtZSk7XG4gICAgICBpZiAoIWV4aXN0c1N5bmMoam9pbihzb3VyY2UsIFwicGFja2FnZS5qc29uXCIpKSkge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgYCR7TE9HX1BSRUZJWH0gXCJzaGFycFwiIGRlcGVuZGVuY3kgXCIke25hbWV9XCIgbm90IGZvdW5kIGluIHN0YW5kYWxvbmUgYnVpbGQgb3V0cHV0OyBpbWFnZSBvcHRpbWl6YXRpb24gbWF5IGZhbGwgYmFjayB0byBzZXJ2aW5nIHVub3B0aW1pemVkIGltYWdlcy5gLFxuICAgICAgICApO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gYGRlcmVmZXJlbmNlYCByZXNvbHZlcyBwbnBtJ3Mgc3ltbGlua3MgaW50byByZWFsIGZpbGVzLCBzaW5jZSB0aGVcbiAgICAgIC8vIExhbWJkYSBhc3NldCBpcyBhIHN0YW5kYWxvbmUgZGlyZWN0b3J5IHdpdGggbm8gc3RvcmUgdG8gbGluayBpbnRvLlxuICAgICAgY3BTeW5jKHNvdXJjZSwgam9pbih0YXJnZXRQYXRoLCBuYW1lKSwge1xuICAgICAgICByZWN1cnNpdmU6IHRydWUsXG4gICAgICAgIGRlcmVmZXJlbmNlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICBjb3BpZWQuYWRkKG5hbWUpO1xuXG4gICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICAgIHJlYWRGaWxlU3luYyhqb2luKHNvdXJjZSwgXCJwYWNrYWdlLmpzb25cIiksIFwidXRmLThcIiksXG4gICAgICApO1xuICAgICAgLy8gUGxhdGZvcm0gYmluYXJpZXMgYXJlIG9wdGlvbmFsRGVwZW5kZW5jaWVzLCBpbnN0YWxsZWQgc2VwYXJhdGVseSBhdFxuICAgICAgLy8gdGhlIHZlcnNpb25zIHRoaXMgc2FtZSBtYW5pZmVzdCBwaW5zLCBzbyBvbmx5IGBkZXBlbmRlbmNpZXNgIGhlcmUuXG4gICAgICBxdWV1ZS5wdXNoKC4uLk9iamVjdC5rZXlzKG1hbmlmZXN0LmRlcGVuZGVuY2llcyA/PyB7fSkpO1xuICAgIH1cblxuICAgIGRlYnVnKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gQ29waWVkIHNoYXJwIHJ1bnRpbWU6ICR7Wy4uLmNvcGllZF0uc29ydCgpLmpvaW4oXCIsIFwiKX1gLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSB0aGUgYEBpbWcvc2hhcnAtPHBsYXRmb3JtPmAgYW5kIGBAaW1nL3NoYXJwLWxpYnZpcHMtPHBsYXRmb3JtPmBcbiAgICogdmVyc2lvbnMgdG8gaW5zdGFsbCBmb3IgYSBnaXZlbiBwbGF0Zm9ybS5cbiAgICpcbiAgICogVGhlc2UgbXVzdCBtYXRjaCB0aGUgYHNoYXJwYCBKUyB3cmFwcGVyIHRoYXQgb3V0cHV0IGZpbGUgdHJhY2luZyBwdXQgaW5cbiAgICogdGhlIHN0YW5kYWxvbmUgYnVpbGQ6IGBzaGFycGAncyBgbGliL2xpYnZpcHMuanNgIGNvbXBhcmVzIHRoZSBiaW5hcnknc1xuICAgKiByZXBvcnRlZCBsaWJ2aXBzIHZlcnNpb24gYWdhaW5zdCBpdHMgb3duIGBtaW5pbXVtTGlidmlwc1ZlcnNpb25gIGFuZFxuICAgKiB0aHJvd3MgYXQgbG9hZCB3aGVuIHRoZXkgZGlzYWdyZWUuIGBzaGFycGAgcGlucyBib3RoIGluIGl0c1xuICAgKiBgb3B0aW9uYWxEZXBlbmRlbmNpZXNgLCBzbyB0aGF0IG1hbmlmZXN0IGlzIHRoZSBhdXRob3JpdGF0aXZlIHNvdXJjZS5cbiAgICovXG4gIHByaXZhdGUgZ2V0U2hhcnBCaW5hcnlQYWNrYWdlcyhcbiAgICBzaGFycFNvdXJjZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIHBsYXRmb3JtOiBzdHJpbmcsXG4gICk6IHsgbmFtZTogc3RyaW5nOyB2ZXJzaW9uOiBzdHJpbmcgfVtdIHtcbiAgICBjb25zdCBmYWxsYmFjayA9IFtcbiAgICAgIHsgbmFtZTogYHNoYXJwLWxpYnZpcHMtJHtwbGF0Zm9ybX1gLCB2ZXJzaW9uOiBcIjEuMi40XCIgfSxcbiAgICAgIHsgbmFtZTogYHNoYXJwLSR7cGxhdGZvcm19YCwgdmVyc2lvbjogXCIwLjM0LjVcIiB9LFxuICAgIF07XG5cbiAgICBpZiAoIXNoYXJwU291cmNlKSB7XG4gICAgICByZXR1cm4gZmFsbGJhY2s7XG4gICAgfVxuXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKFxuICAgICAgcmVhZEZpbGVTeW5jKGpvaW4oc2hhcnBTb3VyY2UsIFwicGFja2FnZS5qc29uXCIpLCBcInV0Zi04XCIpLFxuICAgICk7XG4gICAgY29uc3Qgb3B0aW9uYWxEZXBlbmRlbmNpZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPVxuICAgICAgbWFuaWZlc3Qub3B0aW9uYWxEZXBlbmRlbmNpZXMgPz8ge307XG5cbiAgICByZXR1cm4gZmFsbGJhY2subWFwKChwa2cpID0+IHtcbiAgICAgIGNvbnN0IHZlcnNpb24gPSBvcHRpb25hbERlcGVuZGVuY2llc1tgQGltZy8ke3BrZy5uYW1lfWBdO1xuICAgICAgaWYgKCF2ZXJzaW9uKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICBgJHtMT0dfUFJFRklYfSBzaGFycEAke21hbmlmZXN0LnZlcnNpb259IGRvZXMgbm90IHBpbiBcIkBpbWcvJHtwa2cubmFtZX1cIjsgZmFsbGluZyBiYWNrIHRvICR7cGtnLnZlcnNpb259LmAsXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBwa2c7XG4gICAgICB9XG4gICAgICByZXR1cm4geyBuYW1lOiBwa2cubmFtZSwgdmVyc2lvbiB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERvd25sb2FkICh3aXRoIGNhY2hpbmcpIGFuZCBleHRyYWN0IFNoYXJwJ3MgcGxhdGZvcm0tc3BlY2lmaWMgYmluYXJ5XG4gICAqIHBhY2thZ2VzIGludG8gYGltZ1BhdGhgLlxuICAgKi9cbiAgcHJpdmF0ZSBpbnN0YWxsU2hhcnBQYWNrYWdlcyhcbiAgICBpbWdQYXRoOiBzdHJpbmcsXG4gICAgcGFja2FnZXM6IHsgbmFtZTogc3RyaW5nOyB2ZXJzaW9uOiBzdHJpbmcgfVtdLFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBjYWNoZURpciA9IGpvaW4odG1wZGlyKCksIFwiY2RrLW5leHRqcy1zaGFycC1jYWNoZVwiKTtcbiAgICBpZiAoIWV4aXN0c1N5bmMoY2FjaGVEaXIpKSB7XG4gICAgICBta2RpclN5bmMoY2FjaGVEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgcGtnIG9mIHBhY2thZ2VzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB0YXJnZXREaXIgPSBqb2luKGltZ1BhdGgsIHBrZy5uYW1lKTtcbiAgICAgICAgY29uc3QgdXJsID0gYGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BpbWcvJHtwa2cubmFtZX0vLS8ke3BrZy5uYW1lfS0ke3BrZy52ZXJzaW9ufS50Z3pgO1xuXG4gICAgICAgIC8vIENyZWF0ZSBhIGNvbnNpc3RlbnQgZmlsZW5hbWUgYmFzZWQgb24gcGFja2FnZSBuYW1lIGFuZCB2ZXJzaW9uXG4gICAgICAgIGNvbnN0IGNhY2hlRmlsZU5hbWUgPSBgJHtwa2cubmFtZX0tJHtwa2cudmVyc2lvbn0udGd6YDtcbiAgICAgICAgY29uc3QgY2FjaGVkRmlsZSA9IGpvaW4oY2FjaGVEaXIsIGNhY2hlRmlsZU5hbWUpO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIHdlIGFscmVhZHkgaGF2ZSBhIHZhbGlkIHBhY2thZ2UgY2FjaGVkOyByZS1kb3dubG9hZCBpZlxuICAgICAgICAvLyBhIHByZXZpb3VzIHJ1biBsZWZ0IGJlaGluZCBhIHRydW5jYXRlZC9jb3JydXB0IGRvd25sb2FkXG4gICAgICAgIGlmIChleGlzdHNTeW5jKGNhY2hlZEZpbGUpICYmIHRoaXMuaXNDYWNoZWRGaWxlVmFsaWQoY2FjaGVkRmlsZSkpIHtcbiAgICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICAgIGAke0xPR19QUkVGSVh9IFVzaW5nIGNhY2hlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSBmcm9tICR7Y2FjaGVkRmlsZX1gLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZGVidWcoYCR7TE9HX1BSRUZJWH0gRG93bmxvYWRpbmcgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn0uLi5gKTtcblxuICAgICAgICAgIC8vIERvd25sb2FkIHRvIGEgcHJvY2Vzcy11bmlxdWUgdGVtcCBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeSxcbiAgICAgICAgICAvLyB0aGVuIGF0b21pY2FsbHkgcmVuYW1lIGl0IG9udG8gdGhlIHNoYXJlZCBjYWNoZSBwYXRoLiBDb25jdXJyZW50XG4gICAgICAgICAgLy8gc3ludGggcHJvY2Vzc2VzIChlLmcuIFR1cmJvcmVwbyBydW5uaW5nIG11bHRpcGxlIGBjZGtgIGNvbW1hbmRzKVxuICAgICAgICAgIC8vIHNoYXJlIHRoaXMgY2FjaGUgZGlyLCBzbyB3cml0aW5nIGRpcmVjdGx5IHRvIGBjYWNoZWRGaWxlYCByaXNrc1xuICAgICAgICAgIC8vIGFub3RoZXIgcHJvY2VzcyBleHRyYWN0aW5nIGEgaGFsZi13cml0dGVuIGZpbGUuIFJlbmFtaW5nIHdpdGhpblxuICAgICAgICAgIC8vIHRoZSBzYW1lIGZpbGVzeXN0ZW0gaXMgYXRvbWljLCBzbyByZWFkZXJzIG9ubHkgZXZlciBzZWUgYVxuICAgICAgICAgIC8vIGNvbXBsZXRlIGZpbGUsIHdoaWNoZXZlciBwcm9jZXNzIHdpbnMgdGhlIHJhY2UuXG4gICAgICAgICAgY29uc3QgdGVtcEZpbGUgPSBqb2luKFxuICAgICAgICAgICAgY2FjaGVEaXIsXG4gICAgICAgICAgICBgJHtjYWNoZUZpbGVOYW1lfS4ke3Byb2Nlc3MucGlkfS0ke3JhbmRvbUJ5dGVzKDYpLnRvU3RyaW5nKFwiaGV4XCIpfS50bXBgLFxuICAgICAgICAgICk7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIC0tZmFpbCBtYWtlcyBjdXJsIGV4aXQgbm9uLXplcm8gb24gSFRUUCBlcnJvcnMgYW5kIC0tcmV0cnlcbiAgICAgICAgICAgIC8vIGhhbmRsZXMgdHJhbnNpZW50IGNvbm5lY3Rpb24gZHJvcHMgc28gYSBwYXJ0aWFsIHRyYW5zZmVyXG4gICAgICAgICAgICAvLyBpc24ndCBjYWNoZWQgYXMgdmFsaWQuXG4gICAgICAgICAgICBleGVjU3luYyhcbiAgICAgICAgICAgICAgYGN1cmwgLUwgLS1mYWlsIC0tcmV0cnkgMyAtLXJldHJ5LWRlbGF5IDEgLW8gXCIke3RlbXBGaWxlfVwiIFwiJHt1cmx9XCJgLFxuICAgICAgICAgICAgICB7IHN0ZGlvOiBcInBpcGVcIiB9LFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgaWYgKCF0aGlzLmlzQ2FjaGVkRmlsZVZhbGlkKHRlbXBGaWxlKSkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgYERvd25sb2FkZWQgZmlsZSBmb3IgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn0gaXMgZW1wdHkgb3IgbWlzc2luZzogJHt0ZW1wRmlsZX1gLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZW5hbWVTeW5jKHRlbXBGaWxlLCBjYWNoZWRGaWxlKTtcbiAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgaWYgKGV4aXN0c1N5bmModGVtcEZpbGUpKSB7XG4gICAgICAgICAgICAgIHJtU3luYyh0ZW1wRmlsZSwgeyBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICAgIGAke0xPR19QUkVGSVh9IENhY2hlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSB0byAke2NhY2hlZEZpbGV9YCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgbWtkaXJTeW5jKHRhcmdldERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIGV4ZWNTeW5jKFxuICAgICAgICAgIGB0YXIgLXh6ZiBcIiR7Y2FjaGVkRmlsZX1cIiAtQyBcIiR7dGFyZ2V0RGlyfVwiIC0tc3RyaXAtY29tcG9uZW50cz0xYCxcbiAgICAgICAgICB7IHN0ZGlvOiBcInBpcGVcIiB9LFxuICAgICAgICApO1xuXG4gICAgICAgIGRlYnVnKGAke0xPR19QUkVGSVh9IEluc3RhbGxlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufWApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgJHtMT0dfUFJFRklYfSBGYWlsZWQgdG8gaW5zdGFsbCAke3BrZy5uYW1lfTogJHtlcnJvcn1gKTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyB0aGF0IGEgY2FjaGVkIFNoYXJwIGJpbmFyeSBhcmNoaXZlIGlzIG5vbi1lbXB0eS4gR3VhcmRzIGFnYWluc3RcbiAgICogYSB0cnVuY2F0ZWQvY29ycnVwdCBkb3dubG9hZCAoZS5nLiBmcm9tIGEgZHJvcHBlZCBjb25uZWN0aW9uKSBiZWluZ1xuICAgKiByZXVzZWQgYWNyb3NzIHN5bnRoIG9wZXJhdGlvbnMuXG4gICAqL1xuICBwcml2YXRlIGlzQ2FjaGVkRmlsZVZhbGlkKGZpbGVQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHN0YXRTeW5jKGZpbGVQYXRoKS5zaXplID4gMDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
710
+ /**
711
+ * What travels to the adapter in {@link FUNCTION_GROUPS_ENV_VAR}, and what it
712
+ * records back as `AdapterManifest.functionGroups`.
713
+ */
714
+ function toFunctionGroupSpecs(groups) {
715
+ return groups.map(({ name, routes }) => ({ name, routes }));
716
+ }
717
+ /** `groups` in a canonical order, for comparing two of them. */
718
+ function sortedGroupSpecs(groups) {
719
+ return groups
720
+ ?.map(({ name, routes }) => ({ name, routes: [...routes].sort() }))
721
+ .sort((a, b) => (a.name < b.name ? -1 : 1));
722
+ }
723
+ /**
724
+ * Pick the staged `sharp` JS wrapper out of every copy found in the tree.
725
+ *
726
+ * Unlike a standalone build there is no single `node_modules` to look in: the
727
+ * tree mirrors repo-root-relative paths, so the search is by directory name.
728
+ *
729
+ * An app can have two `sharp` copies at different versions (its own, hoisted,
730
+ * and next's, nested under `next/node_modules`), and every binary goes into the
731
+ * one root `@img`, so the copy pinning them has to be the one `next`'s image
732
+ * optimizer loads: `nextSharp`, when {@link resolveNextSharp} found it. Otherwise
733
+ * shortest path wins as the closest to a hoisted install, sorted for
734
+ * determinism.
735
+ */
736
+ function pickStagedSharpPackage(candidates, nextSharp) {
737
+ const used = nextSharp &&
738
+ candidates.find((candidate) => nextSharp.startsWith((0, node_fs_1.realpathSync)(candidate) + node_path_1.sep));
739
+ if (used) {
740
+ return used;
741
+ }
742
+ candidates.sort((a, b) => a.length - b.length || a.localeCompare(b));
743
+ if (candidates.length > 1) {
744
+ debug(`${constants_1.LOG_PREFIX} Multiple staged "sharp" copies; using ${candidates[0]}`);
745
+ }
746
+ return candidates[0];
747
+ }
748
+ /**
749
+ * The real path of the `sharp` entry point the staged `next` resolves from
750
+ * `projectDir`, `undefined` when either does not resolve.
751
+ */
752
+ function resolveNextSharp(projectDir) {
753
+ try {
754
+ // The anchor file needn't exist; `createRequire` only reads its directory.
755
+ const nextPackage = (0, node_module_1.createRequire)((0, node_path_1.join)(projectDir, "cdk-nextjs-next-resolver.cjs")).resolve("next/package.json");
756
+ return (0, node_module_1.createRequire)(nextPackage).resolve("sharp");
757
+ }
758
+ catch {
759
+ return undefined;
760
+ }
761
+ }
762
+ /**
763
+ * Whether the entry `name` in `parentPath` is an `@img/sharp-*` platform binary
764
+ * package, or pnpm's store entry for one.
765
+ *
766
+ * The name alone is not enough to delete a directory by. A route segment called
767
+ * `sharp-edges` stages `.next/server/app/sharp-edges/`, and removing it left the
768
+ * manifest listing an entrypoint that is no longer on disk — every request to
769
+ * that route 500ing with "Could not load the entrypoint". Nor is "a `sharp-`
770
+ * package": `sharp-ico` and `sharp-phash` are unrelated dependencies, and
771
+ * removing them failed the app at runtime with MODULE_NOT_FOUND. So both the
772
+ * scope and the place have to match:
773
+ *
774
+ * - `node_modules/@img/sharp-…`, where every platform binary actually lives
775
+ * - `node_modules/.pnpm/@img+sharp-…@0.35.4`, pnpm's store, whose entries are
776
+ * also what the `@img` links point at (`sharp-libvips-…` matches the same way)
777
+ *
778
+ * The `node_modules` segment is required as well, so an app directory that
779
+ * happens to be called `@img` or `.pnpm` is still left alone.
780
+ */
781
+ function isSharpBinaryPackage(parentPath, name) {
782
+ const segments = parentPath.split(node_path_1.sep);
783
+ const parent = segments[segments.length - 1];
784
+ const scoped = (parent === "@img" && name.startsWith("sharp-")) ||
785
+ (parent === ".pnpm" && name.startsWith("@img+sharp-"));
786
+ return scoped && segments.includes("node_modules");
787
+ }
788
+ /**
789
+ * Where the target's `@img/sharp-*` binaries go: `<root>/node_modules/@img`.
790
+ *
791
+ * Not next to the staged `sharp` package. Under pnpm that is
792
+ * `node_modules/.pnpm/sharp@x/node_modules/@img`, which only the store copy of
793
+ * `sharp` resolves from: a dereferenced link to `sharp` (a copy at
794
+ * `app/node_modules/sharp`, say) looks for `@img` from its own path and walks
795
+ * up, never into the store. Both the Functions zip (`zipDirectory`) and the
796
+ * Containers `COPY` keep the links, so it is the store copy that loads, and its
797
+ * walk up reaches the root `node_modules` too, so it serves either layout. It
798
+ * is also where main installed them.
799
+ */
800
+ function sharpBinaryDir(root) {
801
+ return (0, node_path_1.join)(root, "node_modules", "@img");
802
+ }
803
+ /**
804
+ * Every entry under `root`, links listed but not followed.
805
+ *
806
+ * An explicit walk rather than `readdirSync({ recursive: true })`, which on
807
+ * Node 24 descends into symlinked directories itself and so never returns on a
808
+ * cycle — two workspace packages that link each other, which is how pnpm wires a
809
+ * monorepo.
810
+ */
811
+ function listTree(root) {
812
+ const entries = [];
813
+ const pending = [root];
814
+ for (let dir = pending.pop(); dir !== undefined; dir = pending.pop()) {
815
+ for (const entry of (0, node_fs_1.readdirSync)(dir, { withFileTypes: true })) {
816
+ entries.push(entry);
817
+ if (entry.isDirectory()) {
818
+ pending.push((0, node_path_1.join)(dir, entry.name));
819
+ }
820
+ }
821
+ }
822
+ return entries;
823
+ }
824
+ /**
825
+ * Write {@link PUBLIC_FILES_FILE_NAME} into a deployment root's runtime
826
+ * directory: every file under `publicDir`, listed the way the runtime would
827
+ * list it off disk (`readPublicFiles`: symlinks followed, `/`-separated,
828
+ * sorted). An app without `public/` gets `[]`.
829
+ */
830
+ function writePublicFileList(runtimeDir, publicDir) {
831
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(runtimeDir, manifest_1.PUBLIC_FILES_FILE_NAME), JSON.stringify((0, public_files_1.readPublicFiles)(publicDir)));
832
+ }
833
+ /**
834
+ * Total bytes of a tree as its deployment zip stores it. `zipDirectory` keeps
835
+ * links as links, so each counts as its target path, not as the target, which
836
+ * is walked at its own path anyway (every link in a staged root points inside
837
+ * it).
838
+ */
839
+ function storedSize(root) {
840
+ let bytes = 0;
841
+ for (const entry of listTree(root)) {
842
+ if (!entry.isDirectory()) {
843
+ bytes += (0, node_fs_1.lstatSync)((0, node_path_1.join)(entry.parentPath, entry.name)).size;
844
+ }
845
+ }
846
+ return bytes;
847
+ }
848
+ /**
849
+ * `chunk` with `patch` prepended between `PATCH_FETCH_MARKER` and
850
+ * `PATCH_FETCH_END_MARKER`, or `undefined` when it already carries this exact
851
+ * patch.
852
+ *
853
+ * The opening marker carries a hash of the patch, so a chunk patched by a
854
+ * cdk-nextjs whose `patch-fetch.js` differs (an upgrade, over a `.next` reused
855
+ * with `skipBuild: true`) is not mistaken for current: the old patch is cut off
856
+ * at its end marker and this one put in its place, rather than the old one
857
+ * shipping or both stacking up.
858
+ */
859
+ function patchClientChunk(chunk, patch, chunkPath) {
860
+ const hash = (0, node_crypto_1.createHash)("sha256").update(patch).digest("hex").slice(0, 16);
861
+ const open = `${PATCH_FETCH_MARKER} ${hash} */`;
862
+ if (chunk.startsWith(`${open}\n`)) {
863
+ return undefined;
864
+ }
865
+ let original = chunk;
866
+ if (chunk.startsWith(PATCH_FETCH_MARKER)) {
867
+ const end = chunk.indexOf(`\n${PATCH_FETCH_END_MARKER}\n`);
868
+ if (end === -1) {
869
+ // Only a pre-release cdk-nextjs wrote the marker without an end, and
870
+ // where its patch stops cannot be told from the chunk's own code.
871
+ throw new Error(`${constants_1.LOG_PREFIX} ${chunkPath} carries a cdk-nextjs fetch patch this ` +
872
+ `version cannot replace. Re-run \`next build\` to regenerate it.`);
873
+ }
874
+ original = chunk.slice(end + PATCH_FETCH_END_MARKER.length + 2);
875
+ }
876
+ return `${open}\n${patch}\n${PATCH_FETCH_END_MARKER}\n${original}`;
877
+ }
878
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25leHRqcy1idWlsZC9uZXh0anMtYnVpbGQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBeUpBLHdEQUtDO0FBR0QsOENBUUM7QUFzMEJELHdEQW1CQztBQU1ELDRDQVVDO0FBcUJELG9EQVVDO0FBY0Qsd0NBRUM7QUFVRCw0QkFZQztBQVFELGtEQUtDO0FBUUQsZ0NBUUM7QUFhRCw0Q0F3QkM7O0FBenBDRCwyREFBNEQ7QUFDNUQsNkNBQXNEO0FBQ3RELHFDQWNpQjtBQUNqQiw2Q0FBNEM7QUFDNUMscUNBQWlDO0FBQ2pDLHlDQUFzQztBQUN0QywyQ0FBb0Q7QUFFcEQsMkNBQXVDO0FBQ3ZDLDZEQUE2RDtBQUM3RCxrREFBNkI7QUFDN0IsZ0VBS29DO0FBQ3BDLDRDQUFzRDtBQUV0RCxrREFRNkI7QUFDN0IsMERBQTBEO0FBQzFELGtEQUk0QjtBQUM1QixnRUFHbUM7QUFFbkM7Ozs7O0dBS0c7QUFDSCxNQUFNLDJCQUEyQixHQUFHLEdBQUcsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBRXREOzs7O0dBSUc7QUFDSCxNQUFNLGtCQUFrQixHQUFHLDJCQUEyQixDQUFDO0FBQ3ZELDJFQUEyRTtBQUMzRSxNQUFNLHNCQUFzQixHQUFHLGtDQUFrQyxDQUFDO0FBRWxFLE1BQU0sS0FBSyxHQUFHLElBQUEsZUFBUSxFQUFDLHlCQUF5QixDQUFDLENBQUM7QUE4RWxEOzs7O0dBSUc7QUFDSCxTQUFnQixzQkFBc0IsQ0FBQyxLQUF1QjtJQUM1RCxNQUFNLFdBQVcsR0FDZixLQUFLLENBQUMsVUFBVSxLQUFLLHNCQUFVLENBQUMsZ0JBQWdCO1FBQ2hELEtBQUssQ0FBQyxVQUFVLEtBQUssc0JBQVUsQ0FBQyxrQkFBa0IsQ0FBQztJQUNyRCxPQUFPLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFBLHdDQUFxQixHQUFFLENBQUM7QUFDeEUsQ0FBQztBQUVELCtGQUErRjtBQUMvRixTQUFnQixpQkFBaUIsQ0FBQyxRQUdqQztJQUNDLE1BQU0sRUFBRSxZQUFZLEVBQUUsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDO0lBQ3pDLE9BQU8sWUFBWTtRQUNqQixDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsT0FBTyxJQUFJLFlBQVksRUFBRTtRQUN2QyxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztBQUN2QixDQUFDO0FBT0Q7OztHQUdHO0FBQ0gsTUFBYSxXQUFZLFNBQVEsc0JBQVM7O0lBQ3hDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O09BbUJHO0lBQ0gsT0FBTyxDQUFTO0lBQ2hCOzs7T0FHRztJQUNILFlBQVksQ0FBUztJQUNyQjs7O09BR0c7SUFDSCxnQkFBZ0IsQ0FBbUI7SUFDbkM7Ozs7O09BS0c7SUFDSCx3QkFBd0IsQ0FBUztJQUNqQzs7T0FFRztJQUNILFdBQVcsQ0FBUztJQUNwQjs7Ozs7T0FLRztJQUNILGtCQUFrQixDQUFTO0lBQzNCOzs7Ozs7Ozs7T0FTRztJQUNILHFCQUFxQixDQUFTO0lBQzlCOzs7Ozs7Ozs7T0FTRztJQUNILHlCQUF5QixDQUFTO0lBQ2xDOzs7Ozs7T0FNRztJQUNILGVBQWUsQ0FBeUI7SUFDeEM7Ozs7T0FJRztJQUNILHNCQUFzQixDQUFnQztJQUN0RDs7Ozs7T0FLRztJQUNILGtCQUFrQixDQUFTO0lBQzNCOzs7T0FHRztJQUNILFlBQVksQ0FBZTtJQUVuQixLQUFLLENBQW1CO0lBQ3hCLFlBQVksQ0FBUztJQUU3QixZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXVCO1FBQy9ELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDakIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFBLGdCQUFJLEVBQUMsS0FBSyxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUV2RCxJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQyxZQUFZLElBQUksZUFBZSxDQUFDO1FBRTFELGdDQUFnQztRQUNoQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUEsZ0JBQUksRUFDdEIsS0FBSyxDQUFDLGNBQWMsRUFDcEIsT0FBTyxFQUNQLHVCQUF1QixDQUN4QixDQUFDO1FBRUYsNkVBQTZFO1FBQzdFLDZFQUE2RTtRQUM3RSx1RUFBdUU7UUFDdkUscUVBQXFFO1FBQ3JFLDJFQUEyRTtRQUMzRSxJQUFJLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixJQUFBLHdDQUFzQixFQUFDLEtBQUssQ0FBQyxjQUFxQyxDQUFDLENBQUM7UUFDdEUsQ0FBQztRQUVELDhCQUE4QjtRQUM5QixJQUFJLEtBQUssQ0FBQyxTQUFTLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDN0IsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3RCLENBQUM7YUFBTSxDQUFDO1lBQ04sS0FBSyxDQUFDLEdBQUcsc0JBQVUsY0FBYyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsQ0FBQztRQUN4RCxDQUFDO1FBRUQsMkVBQTJFO1FBQzNFLDJFQUEyRTtRQUMzRSw2Q0FBNkM7UUFDN0MsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFFNUMsd0VBQXdFO1FBQ3hFLHdFQUF3RTtRQUN4RSwwRUFBMEU7UUFDMUUsdUVBQXVFO1FBQ3ZFLHVFQUF1RTtRQUN2RSwyREFBMkQ7UUFDM0QsSUFBSSxLQUFLLENBQUMsVUFBVSxLQUFLLHNCQUFVLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUNyRCxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUM5QixDQUFDO1FBRUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMzQyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDeEQseURBQXlEO1FBQ3pELGdDQUFnQztRQUNoQyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBQSw2QkFBaUIsRUFBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3RFLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxJQUFBLCtCQUFtQixFQUM5QyxRQUFRLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FDNUIsQ0FBQztRQUNGLElBQUksQ0FBQyx5QkFBeUIsR0FBRyxJQUFBLDJCQUFlLEVBQzlDLFFBQVEsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUM1QixDQUFDO1FBRUYsTUFBTSxXQUFXLEdBQ2YsS0FBSyxDQUFDLFVBQVUsS0FBSyxzQkFBVSxDQUFDLGdCQUFnQjtZQUNoRCxLQUFLLENBQUMsVUFBVSxLQUFLLHNCQUFVLENBQUMsa0JBQWtCLENBQUM7UUFFckQsSUFBSSxDQUFDLGtCQUFrQixHQUFHLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQztRQUN0RCxJQUFJLENBQUMsd0JBQXdCLEdBQUcsSUFBQSxZQUFTLEVBQUMsMkJBQWdCLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDMUUsSUFBSSxDQUFDLFlBQVksR0FBRyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM3RCxJQUFJLENBQUMsc0JBQXNCLEdBQUcsUUFBUSxDQUFDLFNBQVMsSUFBSSxFQUFFLENBQUM7UUFFdkQsMkVBQTJFO1FBQzNFLDBFQUEwRTtRQUMxRSwyRUFBMkU7UUFDM0UsTUFBTSxZQUFZLEdBQUcsS0FBSyxDQUFDLFVBQVUsS0FBSyxzQkFBVSxDQUFDLG1CQUFtQixDQUFDO1FBQ3pFLElBQUksWUFBWSxFQUFFLENBQUM7WUFDakIseUVBQXlFO1lBQ3pFLHNFQUFzRTtZQUN0RSwyREFBMkQ7WUFDM0QsSUFBQSxtQkFBUyxFQUFDLElBQUEsZ0JBQUksRUFBQyxLQUFLLENBQUMsY0FBYyxFQUFFLFFBQVEsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDdkUsQ0FBQztRQUVELEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3hDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFDeEQsMEVBQTBFO1lBQzFFLHVFQUF1RTtZQUN2RSwyQ0FBMkM7WUFDM0MsSUFBSSxDQUFDLG1CQUFtQixDQUN0QixJQUFJLEVBQ0osSUFBQSxnQkFBSSxFQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEVBQ3hDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxJQUFBLHFDQUFrQixFQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUNsRixDQUFDO1lBRUYsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDaEIsSUFBSSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3BDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7Ozs7O09BVUc7SUFDSyxzQkFBc0IsQ0FDNUIsUUFBeUI7UUFFekIsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQztRQUUvQiw0RUFBNEU7UUFDNUUsMkVBQTJFO1FBQzNFLDBFQUEwRTtRQUMxRSwyRUFBMkU7UUFDM0Usb0RBQW9EO1FBQ3BELHdFQUF3RTtRQUN4RSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsRUFBRSxNQUFNO1lBQzlDLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQztZQUNqRCxDQUFDLENBQUMsU0FBUyxDQUFDO1FBQ2QsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQztRQUVwQyxJQUNFLElBQUksQ0FBQyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDeEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUNyQyxDQUFDO1lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FDYixHQUFHLHNCQUFVLCtCQUErQjtnQkFDMUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGNBQWMsaUJBQWlCO2dCQUNwRSxNQUFNLElBQUksQ0FBQyxXQUFXLGtCQUFrQjtnQkFDeEMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLDBCQUEwQixJQUFJO2dCQUM3RCx1RUFBdUU7Z0JBQ3ZFLE9BQU8seUNBQXVCLHVDQUF1QztnQkFDckUsbUVBQW1FO2dCQUNuRSxlQUFlLENBQ2xCLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLHdDQUFzQixDQUFDLENBQUM7UUFDdEUsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNqQyxJQUFJO1lBQ0osSUFBSSxFQUFFLElBQUEsZ0JBQUksRUFDUixJQUFJLENBQUMsV0FBVyxFQUNoQiwyQkFBZ0IsRUFDaEIsR0FBRyxJQUFBLDhCQUFtQixFQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQzdEO1lBQ0QsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUU7U0FDN0IsQ0FBQyxDQUFDLENBQUM7UUFFSixxRUFBcUU7UUFDckUseUJBQXlCO1FBQ3pCLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FDbEIsQ0FBQyxDQUFDLElBQUksS0FBSyx3Q0FBc0I7WUFDL0IsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNKLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLHdDQUFzQjtnQkFDakMsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FDbkMsQ0FBQztRQUVGLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLElBQUEsb0JBQVUsRUFBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDM0IsTUFBTSxJQUFJLEtBQUssQ0FDYixHQUFHLHNCQUFVLDBDQUEwQztvQkFDckQsSUFBSSxJQUFJLENBQUMsSUFBSSxxQkFBcUIsSUFBSSxDQUFDLElBQUksdUJBQXVCO29CQUNsRSxxRUFBcUU7b0JBQ3JFLHFCQUFxQixDQUN4QixDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLHNCQUFzQixDQUFDLElBQTBCO1FBQ3ZELE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDcEMsS0FBSyxDQUNILEdBQUcsc0JBQVUscUJBQXFCLElBQUksQ0FBQyxJQUFJLFFBQVEsQ0FBQyxLQUFLLEdBQUcsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQzFGLENBQUM7UUFDRixJQUFJLEtBQUssSUFBSSwyQkFBMkIsRUFBRSxDQUFDO1lBQ3pDLE9BQU87UUFDVCxDQUFDO1FBQ0QsTUFBTSxFQUFFLEdBQUcsQ0FBQyxLQUFhLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBQ3ZFLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUNoRCxNQUFNLElBQUksS0FBSyxDQUNiLEdBQUcsc0JBQVUsb0JBQW9CLElBQUksQ0FBQyxJQUFJLFFBQVEsRUFBRSxDQUFDLEtBQUssQ0FBQyxhQUFhO1lBQ3RFLGlCQUFpQixFQUFFLENBQUMsMkJBQTJCLENBQUMsVUFBVTtZQUMxRCxDQUFDLE9BQU87Z0JBQ04sQ0FBQyxDQUFDLHFFQUFxRTtvQkFDckUsc0VBQXNFO29CQUN0RSxxREFBcUQ7Z0JBQ3ZELENBQUMsQ0FBQyxrRUFBa0U7b0JBQ2xFLGlFQUFpRTtvQkFDakUscUVBQXFFO29CQUNyRSxpQkFBaUIsQ0FBQyxDQUN6QixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSyxtQkFBbUI7UUFDekIsTUFBTSxZQUFZLEdBQUcsSUFBQSxnQkFBSSxFQUN2QixJQUFJLENBQUMsV0FBVyxFQUNoQiwyQkFBZ0IsRUFDaEIsNkJBQWtCLENBQ25CLENBQUM7UUFDRixJQUFJLENBQUMsSUFBQSxvQkFBVSxFQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDOUIsTUFBTSxJQUFJLEtBQUssQ0FDYiw0Q0FBNEMsWUFBWSxJQUFJO2dCQUMxRCxJQUFJLElBQUksQ0FBQyxZQUFZLCtDQUErQztnQkFDcEUsbUVBQW1FO2dCQUNuRSx1RUFBdUU7Z0JBQ3ZFLHVFQUF1RTtnQkFDdkUscUVBQXFFO2dCQUNyRSxzREFBc0Q7Z0JBQ3RELDREQUE0RDtnQkFDNUQsNkRBQTZEO2dCQUM3RCw0Q0FBNEMsQ0FDL0MsQ0FBQztRQUNKLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBb0IsSUFBSSxDQUFDLEtBQUssQ0FDMUMsSUFBQSxzQkFBWSxFQUFDLFlBQVksRUFBRSxPQUFPLENBQUMsQ0FDcEMsQ0FBQztRQUNGLElBQUksUUFBUSxDQUFDLE9BQU8sS0FBSyxtQ0FBd0IsRUFBRSxDQUFDO1lBQ2xELE1BQU0sSUFBSSxLQUFLLENBQ2Isc0NBQXNDLFlBQVksY0FBYztnQkFDOUQsR0FBRyxRQUFRLENBQUMsT0FBTyxpREFBaUQ7Z0JBQ3BFLEdBQUcsbUNBQXdCLHNDQUFzQztnQkFDakUsc0VBQXNFO2dCQUN0RSxrRUFBa0UsQ0FDckUsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7T0FhRztJQUNLLFlBQVksQ0FDbEIsY0FBc0IsRUFDdEIsV0FBb0IsRUFDcEIsWUFBcUI7UUFFckIsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQztRQUN4RCxNQUFNLE1BQU0sR0FBRyxJQUFBLGdCQUFJLEVBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFdkQsTUFBTSxVQUFVLEdBQUcsSUFBQSxnQkFBSSxFQUFDLGNBQWMsRUFBRSwyQkFBZ0IsQ0FBQyxDQUFDO1FBQzFELDJFQUEyRTtRQUMzRSxzRUFBc0U7UUFDdEUsSUFBQSxnQkFBTSxFQUFDLFVBQVUsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDckQsSUFBQSxtQkFBUyxFQUFDLFVBQVUsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzNDLElBQUEsZ0JBQU0sRUFBQyxNQUFNLEVBQUUsSUFBQSxnQkFBSSxFQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ3hDLElBQUEsZ0JBQU0sRUFDSixJQUFBLGdCQUFJLEVBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSwyQkFBZ0IsRUFBRSw2QkFBa0IsQ0FBQyxFQUM1RCxJQUFBLGdCQUFJLEVBQUMsVUFBVSxFQUFFLDZCQUFrQixDQUFDLENBQ3JDLENBQUM7UUFDRixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDbEIsdUVBQXVFO1lBQ3ZFLHVFQUF1RTtZQUN2RSxxQ0FBcUM7WUFDckMsd0VBQXdFO1lBQ3hFLDBFQUEwRTtZQUMxRSxtQkFBbUIsQ0FDakIsVUFBVSxFQUNWLElBQUEsZ0JBQUksRUFBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsRUFBRSxRQUFRLENBQUMsQ0FDMUMsQ0FBQztRQUNKLENBQUM7UUFDRCxLQUFLLENBQ0gsR0FBRyxzQkFBVSxXQUFXLEtBQUssUUFBUSw2QkFBa0IsT0FBTyxVQUFVLEVBQUUsQ0FDM0UsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQStCRztJQUNLLGNBQWM7UUFDcEIsSUFBSSxDQUFDO1lBQ0gsT0FBTztnQkFDTCxpQkFBaUIsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLG9CQUFvQixFQUFFO29CQUN2RCxLQUFLLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQztpQkFDbkMsQ0FBQzthQUNILENBQUM7UUFDSixDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsS0FBSyxDQUNILEdBQUcsc0JBQVUsK0NBQStDO2dCQUMxRCxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyx3Q0FBd0M7Z0JBQ3BFLHVDQUF1QyxDQUMxQyxDQUFDO1lBQ0YsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWTtRQUNsQixPQUFPLENBQUMsR0FBRyxDQUNULEdBQUcsc0JBQVUsY0FBYyxJQUFJLENBQUMsWUFBWSxtQkFBbUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FDM0YsQ0FBQztRQUVGLDBFQUEwRTtRQUMxRSxJQUFJLElBQUEsb0JBQVUsRUFBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztZQUNsQyxJQUFBLGdCQUFNLEVBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFDNUQsS0FBSyxDQUFDLHFDQUFxQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsSUFBQSw2QkFBUSxFQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7Z0JBQzFCLEtBQUssRUFBRSxTQUFTO2dCQUNoQixHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjO2dCQUM5QixHQUFHLEVBQUU7b0JBQ0gsR0FBRyxPQUFPLENBQUMsR0FBRztvQkFDZCx5QkFBeUIsRUFBRSxJQUFJLENBQUMsWUFBWTtvQkFDNUMsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFO29CQUN4QixpRUFBaUU7b0JBQ2pFLGdFQUFnRTtvQkFDaEUsK0RBQStEO29CQUMvRCxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLEVBQUUsTUFBTTt3QkFDbkMsQ0FBQyxDQUFDOzRCQUNFLENBQUMseUNBQXVCLENBQUMsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUN2QyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUNoRDt5QkFDRjt3QkFDSCxDQUFDLENBQUMsRUFBRSxDQUFDO2lCQUNSO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FtQkc7SUFDSyxvQkFBb0I7UUFDMUIsTUFBTSxnQkFBZ0IsR0FBRyxJQUFBLGdCQUFJLEVBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDcEUsTUFBTSxVQUFVLEdBQUcsSUFBQSxxQkFBVyxFQUFDLGdCQUFnQixDQUFDLENBQUMsTUFBTSxDQUNyRCxDQUFDLElBQVksRUFBRSxFQUFFO1FBQ2YsOENBQThDO1FBQzlDLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDO1lBQzVCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQzFELENBQUM7UUFFRixJQUFJLFVBQVUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1FBQzlELENBQUM7UUFFRCxrQ0FBa0M7UUFDbEMsTUFBTSxjQUFjLEdBQUcsSUFBQSxnQkFBSSxFQUFDLFNBQVMsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3pELE1BQU0saUJBQWlCLEdBQUcsSUFBQSxzQkFBWSxFQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUVoRSx5RUFBeUU7UUFDekUsd0VBQXdFO1FBQ3hFLG9FQUFvRTtRQUNwRSw0REFBNEQ7UUFDNUQsS0FBSyxNQUFNLFNBQVMsSUFBSSxVQUFVLEVBQUUsQ0FBQztZQUNuQyxNQUFNLGFBQWEsR0FBRyxJQUFBLGdCQUFJLEVBQUMsZ0JBQWdCLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDeEQsTUFBTSxjQUFjLEdBQUcsZ0JBQWdCLENBQ3JDLElBQUEsc0JBQVksRUFBQyxhQUFhLEVBQUUsT0FBTyxDQUFDLEVBQ3BDLGlCQUFpQixFQUNqQixhQUFhLENBQ2QsQ0FBQztZQUNGLElBQUksY0FBYyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUNqQyxLQUFLLENBQUMsR0FBRyxzQkFBVSwrQkFBK0IsYUFBYSxFQUFFLENBQUMsQ0FBQztnQkFDbkUsU0FBUztZQUNYLENBQUM7WUFDRCxJQUFBLHVCQUFhLEVBQUMsYUFBYSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQy9DLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyx3QkFBd0I7UUFDOUIsTUFBTSxhQUFhLEdBQUcsSUFBQSxnQkFBSSxFQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ2hFLElBQUksQ0FBQyxJQUFBLG9CQUFVLEVBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUMvQixPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7UUFFRCxPQUFPLElBQUEscUJBQVcsRUFBQyxhQUFhLEVBQUUsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDekUsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO1lBQ2hCLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVyxFQUFFO1NBQ2pDLENBQUMsQ0FBQyxDQUFDO0lBQ04sQ0FBQztJQUVEOzs7Ozs7Ozs7OztPQVdHO0lBQ0ssbUJBQW1CLENBQ3pCLElBQTBCLEVBQzFCLFVBQWtCLEVBQ2xCLFFBQWdCO1FBRWhCLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQzVFLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNqQixJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssd0NBQXNCLEVBQUUsQ0FBQztnQkFDekMsT0FBTyxDQUFDLElBQUksQ0FDVixHQUFHLHNCQUFVLDhIQUE4SCxDQUM1SSxDQUFDO1lBQ0osQ0FBQztZQUNELE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLG9CQUFvQixDQUN2QixjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUN6QixJQUFJLENBQUMsc0JBQXNCLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxDQUNuRCxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7O09BYUc7SUFDSywyQkFBMkIsQ0FDakMsSUFBWSxFQUNaLFVBQWtCO1FBRWxCLE1BQU0sZUFBZSxHQUFhLEVBQUUsQ0FBQztRQUVyQyxxRUFBcUU7UUFDckUsd0VBQXdFO1FBQ3hFLGtFQUFrRTtRQUNsRSxrQ0FBa0M7UUFDbEMsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWxDLHdFQUF3RTtRQUN4RSwwRUFBMEU7UUFDMUUseUVBQXlFO1FBQ3pFLHdFQUF3RTtRQUN4RSxxREFBcUQ7UUFDckQsMkVBQTJFO1FBQzNFLDRFQUE0RTtRQUM1RSxNQUFNLFFBQVEsR0FBYSxFQUFFLENBQUM7UUFDOUIsTUFBTSxXQUFXLEdBQWEsRUFBRSxDQUFDO1FBRWpDLEtBQUssTUFBTSxLQUFLLElBQUksVUFBVSxFQUFFLENBQUM7WUFDL0IsSUFBSSxLQUFLLENBQUMsV0FBVyxFQUFFLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztnQkFDbEQsTUFBTSxJQUFJLEdBQUcsSUFBQSxnQkFBSSxFQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNoRCxJQUFJLElBQUEsb0JBQVUsRUFBQyxJQUFBLGdCQUFJLEVBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztvQkFDM0MsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDN0IsQ0FBQztnQkFDRCxTQUFTO1lBQ1gsQ0FBQztZQUNELElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUM7Z0JBQUUsU0FBUztZQUNsRSxNQUFNLFFBQVEsR0FBRyxJQUFBLGdCQUFJLEVBQUMsS0FBSyxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDcEQsSUFBSSxLQUFLLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQztnQkFDM0IsUUFBUSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUMxQixDQUFDO2lCQUFNLElBQUksS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7Z0JBQy9CLFdBQVcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDN0IsQ0FBQztRQUNILENBQUM7UUFFRCxLQUFLLENBQ0gsR0FBRyxzQkFBVSxhQUFhLFFBQVEsQ0FBQyxNQUFNLDhCQUE4QixXQUFXLENBQUMsTUFBTSxjQUFjLENBQ3hHLENBQUM7UUFFRixLQUFLLE1BQU0sSUFBSSxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzVCLElBQUEsb0JBQVUsRUFBQyxJQUFJLENBQUMsQ0FBQztZQUNqQixLQUFLLENBQUMsR0FBRyxzQkFBVSxjQUFjLElBQUksRUFBRSxDQUFDLENBQUM7UUFDM0MsQ0FBQztRQUNELEtBQUssTUFBTSxJQUFJLElBQUksV0FBVyxFQUFFLENBQUM7WUFDL0IsSUFBQSxnQkFBTSxFQUFDLElBQUksRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFDL0MsS0FBSyxDQUFDLEdBQUcsc0JBQVUsYUFBYSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzFDLENBQUM7UUFDRCxPQUFPLHNCQUFzQixDQUMzQixlQUFlLEVBQ2YsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLENBQzdCLENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0ssc0JBQXNCLENBQzVCLFdBQW1CLEVBQ25CLFFBQWdCO1FBRWhCLHFEQUFxRDtRQUNyRCxNQUFNLFFBQVEsR0FBRztZQUNmLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixRQUFRLEVBQUUsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFO1lBQ3ZELEVBQUUsSUFBSSxFQUFFLFNBQVMsUUFBUSxFQUFFLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRTtTQUNqRCxDQUFDO1FBRUYsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FDekIsSUFBQSxzQkFBWSxFQUFDLElBQUEsZ0JBQUksRUFBQyxXQUFXLEVBQUUsY0FBYyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQ3pELENBQUM7UUFDRixNQUFNLG9CQUFvQixHQUN4QixRQUFRLENBQUMsb0JBQW9CLElBQUksRUFBRSxDQUFDO1FBRXRDLE9BQU8sUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQzFCLE1BQU0sT0FBTyxHQUFHLG9CQUFvQixDQUFDLFFBQVEsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7WUFDekQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNiLE9BQU8sQ0FBQyxJQUFJLENBQ1YsR0FBRyxzQkFBVSxVQUFVLFFBQVEsQ0FBQyxPQUFPLHVCQUF1QixHQUFHLENBQUMsSUFBSSxzQkFBc0IsR0FBRyxDQUFDLE9BQU8sR0FBRyxDQUMzRyxDQUFDO2dCQUNGLE9BQU8sR0FBRyxDQUFDO1lBQ2IsQ0FBQztZQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUNyQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7O09BR0c7SUFDSyxvQkFBb0IsQ0FDMUIsT0FBZSxFQUNmLFFBQTZDO1FBRTdDLE1BQU0sUUFBUSxHQUFHLElBQUEsZ0JBQUksRUFBQyxJQUFBLGdCQUFNLEdBQUUsRUFBRSx3QkFBd0IsQ0FBQyxDQUFDO1FBQzFELElBQUEsbUJBQVMsRUFBQyxRQUFRLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUV6QyxLQUFLLE1BQU0sR0FBRyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzNCLE1BQU0sU0FBUyxHQUFHLElBQUEsZ0JBQUksRUFBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzFDLE1BQU0sR0FBRyxHQUFHLG1DQUFtQyxHQUFHLENBQUMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxJQUFJLElBQUksR0FBRyxDQUFDLE9BQU8sTUFBTSxDQUFDO1lBRTNGLGlFQUFpRTtZQUNqRSxNQUFNLGFBQWEsR0FBRyxHQUFHLEdBQUcsQ0FBQyxJQUFJLElBQUksR0FBRyxDQUFDLE9BQU8sTUFBTSxDQUFDO1lBQ3ZELE1BQU0sVUFBVSxHQUFHLElBQUEsZ0JBQUksRUFBQyxRQUFRLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFFakQsa0VBQWtFO1lBQ2xFLDBEQUEwRDtZQUMxRCxJQUFJLElBQUEsb0JBQVUsRUFBQyxVQUFVLENBQUMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztnQkFDakUsS0FBSyxDQUNILEdBQUcsc0JBQVUsaUJBQWlCLEdBQUcsQ0FBQyxJQUFJLElBQUksR0FBRyxDQUFDLE9BQU8sU0FBUyxVQUFVLEVBQUUsQ0FDM0UsQ0FBQztZQUNKLENBQUM7aUJBQU0sQ0FBQztnQkFDTixLQUFLLENBQUMsR0FBRyxzQkFBVSxnQkFBZ0IsR0FBRyxDQUFDLElBQUksSUFBSSxHQUFHLENBQUMsT0FBTyxLQUFLLENBQUMsQ0FBQztnQkFFakUsZ0VBQWdFO2dCQUNoRSxtRUFBbUU7Z0JBQ25FLG1FQUFtRTtnQkFDbkUsa0VBQWtFO2dCQUNsRSxrRUFBa0U7Z0JBQ2xFLDREQUE0RDtnQkFDNUQsa0RBQWtEO2dCQUNsRCxNQUFNLFFBQVEsR0FBRyxJQUFBLGdCQUFJLEVBQ25CLFFBQVEsRUFDUixHQUFHLGFBQWEsSUFBSSxPQUFPLENBQUMsR0FBRyxJQUFJLElBQUEseUJBQVcsRUFBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FDeEUsQ0FBQztnQkFDRixJQUFJLENBQUM7b0JBQ0gsNkRBQTZEO29CQUM3RCwyREFBMkQ7b0JBQzNELHlCQUF5QjtvQkFDekIsSUFBQSxpQ0FBWSxFQUNWLE1BQU0sRUFDTjt3QkFDRSxJQUFJO3dCQUNKLFFBQVE7d0JBQ1IsU0FBUzt3QkFDVCxHQUFHO3dCQUNILGVBQWU7d0JBQ2YsR0FBRzt3QkFDSCxJQUFJO3dCQUNKLFFBQVE7d0JBQ1IsR0FBRztxQkFDSixFQUNELEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUNsQixDQUFDO29CQUVGLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQzt3QkFDdEMsTUFBTSxJQUFJLEtBQUssQ0FDYix1QkFBdUIsR0FBRyxDQUFDLElBQUksSUFBSSxHQUFHLENBQUMsT0FBTyx5QkFBeUIsUUFBUSxFQUFFLENBQ2xGLENBQUM7b0JBQ0osQ0FBQztvQkFFRCxJQUFBLG9CQUFVLEVBQUMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUNuQyxDQUFDO3dCQUFTLENBQUM7b0JBQ1QsSUFBQSxnQkFBTSxFQUFDLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUNwQyxDQUFDO2dCQUVELEtBQUssQ0FDSCxHQUFHLHNCQUFVLFdBQVcsR0FBRyxDQUFDLElBQUksSUFBSSxHQUFHLENBQUMsT0FBTyxPQUFPLFVBQVUsRUFBRSxDQUNuRSxDQUFDO1lBQ0osQ0FBQztZQUVELElBQUEsbUJBQVMsRUFBQyxTQUFTLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUMxQyxJQUFBLGlDQUFZLEVBQ1YsS0FBSyxFQUNMLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLHNCQUFzQixDQUFDLEVBQzdELEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUNsQixDQUFDO1lBRUYsS0FBSyxDQUFDLEdBQUcsc0JBQVUsY0FBYyxHQUFHLENBQUMsSUFBSSxJQUFJLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQzlELENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLGlCQUFpQixDQUFDLFFBQWdCO1FBQ3hDLElBQUksQ0FBQztZQUNILE9BQU8sSUFBQSxrQkFBUSxFQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7UUFDckMsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7O0FBeHhCSCxrQ0F5eEJDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBUyxvQkFBb0IsQ0FDM0IsTUFBbUM7SUFFbkMsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQzlELENBQUM7QUFFRCxnRUFBZ0U7QUFDaEUsU0FBUyxnQkFBZ0IsQ0FDdkIsTUFBZ0Q7SUFFaEQsT0FBTyxNQUFNO1FBQ1gsRUFBRSxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztTQUNsRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDaEQsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILFNBQWdCLHNCQUFzQixDQUNwQyxVQUFvQixFQUNwQixTQUFrQjtJQUVsQixNQUFNLElBQUksR0FDUixTQUFTO1FBQ1QsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQzVCLFNBQVMsQ0FBQyxVQUFVLENBQUMsSUFBQSxzQkFBWSxFQUFDLFNBQVMsQ0FBQyxHQUFHLGVBQUcsQ0FBQyxDQUNwRCxDQUFDO0lBQ0osSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUNULE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUNELFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUMxQixLQUFLLENBQ0gsR0FBRyxzQkFBVSwwQ0FBMEMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQ3ZFLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDdkIsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLFVBQWtCO0lBQ2pELElBQUksQ0FBQztRQUNILDJFQUEyRTtRQUMzRSxNQUFNLFdBQVcsR0FBRyxJQUFBLDJCQUFhLEVBQy9CLElBQUEsZ0JBQUksRUFBQyxVQUFVLEVBQUUsOEJBQThCLENBQUMsQ0FDakQsQ0FBQyxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUMvQixPQUFPLElBQUEsMkJBQWEsRUFBQyxXQUFXLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILFNBQWdCLG9CQUFvQixDQUNsQyxVQUFrQixFQUNsQixJQUFZO0lBRVosTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxlQUFHLENBQUMsQ0FBQztJQUN2QyxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUM3QyxNQUFNLE1BQU0sR0FDVixDQUFDLE1BQU0sS0FBSyxNQUFNLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRCxDQUFDLE1BQU0sS0FBSyxPQUFPLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ3pELE9BQU8sTUFBTSxJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUM7QUFDckQsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLElBQVk7SUFDekMsT0FBTyxJQUFBLGdCQUFJLEVBQUMsSUFBSSxFQUFFLGNBQWMsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQWdCLFFBQVEsQ0FBQyxJQUFZO0lBQ25DLE1BQU0sT0FBTyxHQUFhLEVBQUUsQ0FBQztJQUM3QixNQUFNLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3ZCLEtBQUssSUFBSSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLEdBQUcsS0FBSyxTQUFTLEVBQUUsR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDO1FBQ3JFLEtBQUssTUFBTSxLQUFLLElBQUksSUFBQSxxQkFBVyxFQUFDLEdBQUcsRUFBRSxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDOUQsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNwQixJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO2dCQUN4QixPQUFPLENBQUMsSUFBSSxDQUFDLElBQUEsZ0JBQUksRUFBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDdEMsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQUMsVUFBa0IsRUFBRSxTQUFpQjtJQUN2RSxJQUFBLHVCQUFhLEVBQ1gsSUFBQSxnQkFBSSxFQUFDLFVBQVUsRUFBRSxpQ0FBc0IsQ0FBQyxFQUN4QyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUEsOEJBQWUsRUFBQyxTQUFTLENBQUMsQ0FBQyxDQUMzQyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLElBQVk7SUFDckMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ2QsS0FBSyxNQUFNLEtBQUssSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7WUFDekIsS0FBSyxJQUFJLElBQUEsbUJBQVMsRUFBQyxJQUFBLGdCQUFJLEVBQUMsS0FBSyxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDOUQsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsU0FBZ0IsZ0JBQWdCLENBQzlCLEtBQWEsRUFDYixLQUFhLEVBQ2IsU0FBaUI7SUFFakIsTUFBTSxJQUFJLEdBQUcsSUFBQSx3QkFBVSxFQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUMzRSxNQUFNLElBQUksR0FBRyxHQUFHLGtCQUFrQixJQUFJLElBQUksS0FBSyxDQUFDO0lBQ2hELElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNsQyxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUM7UUFDekMsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLHNCQUFzQixJQUFJLENBQUMsQ0FBQztRQUMzRCxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ2YscUVBQXFFO1lBQ3JFLGtFQUFrRTtZQUNsRSxNQUFNLElBQUksS0FBSyxDQUNiLEdBQUcsc0JBQVUsSUFBSSxTQUFTLHlDQUF5QztnQkFDakUsaUVBQWlFLENBQ3BFLENBQUM7UUFDSixDQUFDO1FBQ0QsUUFBUSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxHQUFHLHNCQUFzQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBQ0QsT0FBTyxHQUFHLElBQUksS0FBSyxLQUFLLEtBQUssc0JBQXNCLEtBQUssUUFBUSxFQUFFLENBQUM7QUFDckUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4ZWNGaWxlU3luYywgZXhlY1N5bmMgfSBmcm9tIFwibm9kZTpjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgeyBjcmVhdGVIYXNoLCByYW5kb21CeXRlcyB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHtcbiAgRGlyZW50LFxuICBleGlzdHNTeW5jLFxuICBsc3RhdFN5bmMsXG4gIHJlYWRGaWxlU3luYyxcbiAgcmVhZGRpclN5bmMsXG4gIHdyaXRlRmlsZVN5bmMsXG4gIHJtU3luYyxcbiAgbWtkaXJTeW5jLFxuICBjcFN5bmMsXG4gIHJlbmFtZVN5bmMsXG4gIHJlYWxwYXRoU3luYyxcbiAgc3RhdFN5bmMsXG4gIHVubGlua1N5bmMsXG59IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSBcIm5vZGU6bW9kdWxlXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgam9pbiwgc2VwIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgam9pbiBhcyBqb2luUG9zaXggfSBmcm9tIFwibm9kZTpwYXRoL3Bvc2l4XCI7XG5pbXBvcnQgeyBBcmNoaXRlY3R1cmUgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCBnZXREZWJ1ZyBmcm9tIFwiZGVidWdcIjtcbmltcG9ydCB7XG4gIERFRkFVTFRfRlVOQ1RJT05fR1JPVVAsXG4gIEZVTkNUSU9OX0dST1VQU19FTlZfVkFSLFxuICBGdW5jdGlvbkdyb3VwU3BlYyxcbiAgdmFsaWRhdGVGdW5jdGlvbkdyb3Vwcyxcbn0gZnJvbSBcIi4uL2FkYXB0ZXIvZnVuY3Rpb24tZ3JvdXBzXCI7XG5pbXBvcnQgeyBMT0dfUFJFRklYLCBOZXh0anNUeXBlIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgTmV4dGpzQmFzZVByb3BzIH0gZnJvbSBcIi4uL3Jvb3QtY29uc3RydWN0cy9uZXh0anMtYmFzZS1jb25zdHJ1Y3RcIjtcbmltcG9ydCB7XG4gIEFEQVBURVJfRElSX05BTUUsXG4gIEFEQVBURVJfTUFOSUZFU1RfVkVSU0lPTixcbiAgQWRhcHRlck1hbmlmZXN0LFxuICBNQU5JRkVTVF9GSUxFX05BTUUsXG4gIFBVQkxJQ19GSUxFU19GSUxFX05BTUUsXG4gIFJVTlRJTUVfRElSX05BTUUsXG4gIGdyb3VwU3RhZ2luZ0Rpck5hbWUsXG59IGZyb20gXCIuLi9ydW50aW1lL21hbmlmZXN0XCI7XG5pbXBvcnQgeyByZWFkUHVibGljRmlsZXMgfSBmcm9tIFwiLi4vcnVudGltZS9wdWJsaWMtZmlsZXNcIjtcbmltcG9ydCB7XG4gIGFzc2V0UHJlZml4UGF0aCxcbiAgbm9ybWFsaXplQmFzZVBhdGgsXG4gIHJlbGF0aXZlQXNzZXRQcmVmaXgsXG59IGZyb20gXCIuLi91dGlscy9iYXNlLXBhdGhcIjtcbmltcG9ydCB7XG4gIGdldExhbWJkYUFyY2hpdGVjdHVyZSxcbiAgdG9Ob2RlQXJjaGl0ZWN0dXJlLFxufSBmcm9tIFwiLi4vdXRpbHMvZ2V0LWFyY2hpdGVjdHVyZVwiO1xuXG4vKipcbiAqIExhbWJkYSdzIGhhcmQgbGltaXQgb24gdGhlIHVuemlwcGVkIHNpemUgb2YgYSBmdW5jdGlvbidzIGNvZGUsIHdoaWNoXG4gKiBDbG91ZEZvcm1hdGlvbiBvbmx5IGVuZm9yY2VzIGF0IGRlcGxveSB0aW1lLiBNZWFzdXJlZCBhdCBzeW50aCBpbnN0ZWFkLCBzbyB0aGVcbiAqIGVycm9yIG5hbWVzIHRoZSBncm91cCBhbmQgYXJyaXZlcyBpbiBzZWNvbmRzIHJhdGhlciB0aGFuIG1pbnV0ZXMuXG4gKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9sYW1iZGEvbGF0ZXN0L2RnL2dldHRpbmdzdGFydGVkLWxpbWl0cy5odG1sXG4gKi9cbmNvbnN0IExBTUJEQV9VTlpJUFBFRF9MSU1JVF9CWVRFUyA9IDI1MCAqIDEwMjQgKiAxMDI0O1xuXG4vKipcbiAqIE9wZW5zIHRoZSBwYXRjaCBgcGF0Y2hGZXRjaEluQ2xpZW50SnNgIHByZXBlbmRzIHRvIGEgY2xpZW50IGNodW5rLCBmb2xsb3dlZCBieVxuICogYSBoYXNoIG9mIHRoZSBwYXRjaCBpdHNlbGYsIHNvIGEgc2Vjb25kIHN5bnRoIG92ZXIgdGhlIHNhbWUgYC5uZXh0YCBpcyBhIG5vLW9wXG4gKiB3aGlsZSBvbmUgYnkgYSBjZGstbmV4dGpzIHdpdGggYSBkaWZmZXJlbnQgYHBhdGNoLWZldGNoLmpzYCByZXBsYWNlcyBpdC5cbiAqL1xuY29uc3QgUEFUQ0hfRkVUQ0hfTUFSS0VSID0gXCIvKiBjZGstbmV4dGpzOnBhdGNoLWZldGNoXCI7XG4vKiogQ2xvc2VzIHRoZSBwcmVwZW5kZWQgcGF0Y2g7IHRoZSBjaHVuaydzIG93biBjb250ZW50IHN0YXJ0cyBhZnRlciBpdC4gKi9cbmNvbnN0IFBBVENIX0ZFVENIX0VORF9NQVJLRVIgPSBcIi8qIGNkay1uZXh0anM6cGF0Y2gtZmV0Y2g6ZW5kICovXCI7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoXCJjZGstbmV4dGpzOm5leHRqcy1idWlsZFwiKTtcblxuZXhwb3J0IGludGVyZmFjZSBOZXh0anNCdWlsZFByb3BzIHtcbiAgLyoqXG4gICAqIEBzZWUge0BsaW5rIE5leHRqc0Jhc2VQcm9wc1tcImJ1aWxkQ29tbWFuZFwiXX1cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQ29tbWFuZDogTmV4dGpzQmFzZVByb3BzW1wiYnVpbGRDb21tYW5kXCJdO1xuICAvKipcbiAgICogRGlyZWN0b3J5IHdoZXJlIHRoZSBOZXh0LmpzIGFwcGxpY2F0aW9uIGlzIGxvY2F0ZWQgZm9yIGxvY2FsIGJ1aWxkcy5cbiAgICogVGhpcyBzaG91bGQgY29udGFpbiB0aGUgcGFja2FnZS5qc29uIGFuZCBOZXh0LmpzIGFwcGxpY2F0aW9uIGZpbGVzLlxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGREaXJlY3Rvcnk6IHN0cmluZztcbiAgcmVhZG9ubHkgbmV4dGpzVHlwZTogTmV4dGpzVHlwZTtcbiAgLyoqXG4gICAqIEBzZWUge0BsaW5rIE5leHRqc0Jhc2VQcm9wcy5za2lwQnVpbGR9XG4gICAqL1xuICByZWFkb25seSBza2lwQnVpbGQ/OiBib29sZWFuO1xuICAvKipcbiAgICogUm91dGUgZ3JvdXBzIHRvIHBhY2thZ2UgaW50byBzZXBhcmF0ZSBMYW1iZGEgZnVuY3Rpb25zLiBPbmx5IHRoZSB0d29cbiAgICogRnVuY3Rpb25zIGBOZXh0anNUeXBlYHMgcGFzcyB0aGlzOyBzZWUgYE5leHRqc0Z1bmN0aW9uR3JvdXBgLlxuICAgKi9cbiAgcmVhZG9ubHkgZnVuY3Rpb25Hcm91cHM/OiBOZXh0anNGdW5jdGlvbkdyb3VwUm91dGVzW107XG4gIC8qKlxuICAgKiBMYW1iZGEgYXJjaGl0ZWN0dXJlIHRoZSBGdW5jdGlvbnMgdHlwZXMgZGVwbG95LCB3aGljaCBkZWNpZGVzIHRoZSBgc2hhcnBgXG4gICAqIGJpbmFyaWVzIHN0YWdlZCBpbnRvIHRoZSBkZXBsb3ltZW50IHJvb3RzLiBJZ25vcmVkIGJ5IHRoZSBDb250YWluZXJzXG4gICAqIHR5cGVzLCB3aG9zZSBpbWFnZSBpcyBidWlsdCBmb3IgdGhlIHN5bnRoIG1hY2hpbmUuXG4gICAqIEBkZWZhdWx0IC0gdGhlIGFyY2hpdGVjdHVyZSBvZiB0aGUgbWFjaGluZSBydW5uaW5nIHN5bnRoXG4gICAqL1xuICByZWFkb25seSBhcmNoaXRlY3R1cmU/OiBBcmNoaXRlY3R1cmU7XG59XG5cbi8qKlxuICogVGhlIHBhcnQgb2YgYSBmdW5jdGlvbiBncm91cCBgTmV4dGpzQnVpbGRgIG5lZWRzOiB3aGljaCByb3V0ZXMgaXQgb3ducy4gVGhlXG4gKiBwZXItZ3JvdXAgTGFtYmRhIGBvdmVycmlkZXNgIGFyZSBgTmV4dGpzRnVuY3Rpb25zYCcgYnVzaW5lc3MuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzRnVuY3Rpb25Hcm91cFJvdXRlcyB7XG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgcm91dGVzOiBzdHJpbmdbXTtcbn1cblxuLyoqIE9uZSBzdGFnZWQgZGVwbG95bWVudCByb290LCBhbmQgdGhlIGZ1bmN0aW9uIGdyb3VwIGl0IGJlbG9uZ3MgdG8uICovXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0RlcGxveW1lbnRSb290IHtcbiAgLyoqXG4gICAqIEdyb3VwIG5hbWUsIGBkZWZhdWx0YCBmb3IgdGhlIGltcGxpY2l0IGdyb3VwIHRoYXQgb3ducyBldmVyeSB1bmFzc2lnbmVkXG4gICAqIHJvdXRlLiBUaGUgb25seSBlbnRyeSBpcyBgZGVmYXVsdGAgd2hlbiBgZnVuY3Rpb25Hcm91cHNgIGlzIG5vdCB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuICAvKiogQWJzb2x1dGUgcGF0aCB0byB0aGUgZGVwbG95bWVudCByb290OiB0aGUgTGFtYmRhIHppcCBhc3NldCdzIHNvdXJjZS4gKi9cbiAgcmVhZG9ubHkgcGF0aDogc3RyaW5nO1xuICAvKipcbiAgICogUm91dGUgdGVtcGxhdGVzIHRoaXMgcm9vdCdzIHBhY2thZ2UgaG9sZHMsIGFzIHRoZSBhZGFwdGVyIGFzc2lnbmVkIHRoZW0uXG4gICAqIEVtcHR5IGlzIGxlZ2FsOiB0aGUgZGVmYXVsdCBncm91cCBzdGlsbCBzZXJ2ZXMgYC9fbmV4dC9pbWFnZWAsIHRoZSBzdGF0aWNcbiAgICogZmlsZXMgdGhlIHJ1bnRpbWUgcmVhZHMgb2ZmIGRpc2ssIGFuZCBhbnl0aGluZyB0aGUgY2F0Y2gtYWxsIHJvdXRlcyB0byBpdC5cbiAgICovXG4gIHJlYWRvbmx5IHJvdXRlczogc3RyaW5nW107XG59XG5cbi8qKlxuICogT25lIGJlaGF2aW9yIHRoYXQgcm91dGVzIGEgZnVuY3Rpb24gZ3JvdXAncyBVUkxzIHRvIGl0LCBhcyB0aGUgYWRhcHRlclxuICogY2hlY2tlZCB0aGVtIGFnYWluc3Qgd2hhdCBlYWNoIGdyb3VwIHdhcyBwYWNrYWdlZCB3aXRoLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0Z1bmN0aW9uR3JvdXBCZWhhdmlvciB7XG4gIC8qKiBUaGUgZnVuY3Rpb24gZ3JvdXAgdGhlIGJlaGF2aW9yIHJvdXRlcyB0by4gKi9cbiAgcmVhZG9ubHkgZ3JvdXA6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBncm91cCBwYXR0ZXJuIGl0IGNhbWUgZnJvbSAoYC9ibG9nLyoqYCksIG9yIHRoZSBwYXJlbnQgb2YgYW4gb3B0aW9uYWxcbiAgICogY2F0Y2gtYWxsIGEgc3VidHJlZSBwYXR0ZXJuIG1vdmVkIGludG8gdGhlIGdyb3VwIChgL2Jsb2dgIGZvclxuICAgKiBgL2Jsb2cvW1suLi5zbHVnXV1gKSwgd2hpY2ggdGhhdCBzdWJ0cmVlJ3MgYmVoYXZpb3IgZG9lcyBub3QgbWF0Y2guXG4gICAqL1xuICByZWFkb25seSByb3V0ZTogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIENsb3VkRnJvbnQgcGF0aCBwYXR0ZXJuLCBiZWZvcmUgYmFzZVBhdGggYW5kIHdpdGhvdXQgYSBsZWFkaW5nIHNsYXNoOlxuICAgKiBgYmxvZy8qYCwgYHByaWNpbmdgLCBgcHJpY2luZy9gIGZvciBhIGB0cmFpbGluZ1NsYXNoYCBhcHAsIGFuZFxuICAgKiBgX25leHQvZGF0YS88YnVpbGRJZD4vYmxvZy8qYCBmb3IgYSBncm91cCBvd25pbmcgYSBQYWdlcyBSb3V0ZXIgcGFnZS5cbiAgICovXG4gIHJlYWRvbmx5IHBhdHRlcm46IHN0cmluZztcbn1cblxuLyoqXG4gKiBXaGF0IGV2ZXJ5IGRlcGxveW1lbnQgcm9vdCBpcyBzdGFnZWQgZm9yOiB0aGUgYnVpbGQncyBgYXJjaGl0ZWN0dXJlYCwgZWxzZVxuICogdGhlIHN5bnRoIG1hY2hpbmUncy4gQ29udGFpbmVycyBpZ25vcmUgaXQ6IERvY2tlciBidWlsZHMgdGhlaXIgaW1hZ2VcbiAqIG5hdGl2ZWx5LCBzbyBpdCBjYW4gb25seSBtYXRjaCB0aGUgc3ludGggbWFjaGluZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlcGxveW1lbnRBcmNoaXRlY3R1cmUocHJvcHM6IE5leHRqc0J1aWxkUHJvcHMpOiBBcmNoaXRlY3R1cmUge1xuICBjb25zdCBpc0Z1bmN0aW9ucyA9XG4gICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TIHx8XG4gICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5SRUdJT05BTF9GVU5DVElPTlM7XG4gIHJldHVybiAoaXNGdW5jdGlvbnMgJiYgcHJvcHMuYXJjaGl0ZWN0dXJlKSB8fCBnZXRMYW1iZGFBcmNoaXRlY3R1cmUoKTtcbn1cblxuLyoqIHtAbGluayBOZXh0anNCdWlsZC5idWlsZElkfTogTmV4dC5qcydzIGJ1aWxkIElELCBzdWZmaXhlZCB3aXRoIHRoZSBhcHAncyBgZGVwbG95bWVudElkYC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZXBsb3ltZW50QnVpbGRJZChtYW5pZmVzdDoge1xuICByZWFkb25seSBidWlsZElkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbmZpZzogeyByZWFkb25seSBkZXBsb3ltZW50SWQ6IHN0cmluZyB9O1xufSk6IHN0cmluZyB7XG4gIGNvbnN0IHsgZGVwbG95bWVudElkIH0gPSBtYW5pZmVzdC5jb25maWc7XG4gIHJldHVybiBkZXBsb3ltZW50SWRcbiAgICA/IGAke21hbmlmZXN0LmJ1aWxkSWR9LSR7ZGVwbG95bWVudElkfWBcbiAgICA6IG1hbmlmZXN0LmJ1aWxkSWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHVibGljRGlyRW50cnkge1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGlzRGlyZWN0b3J5OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEJ1aWxkcyBOZXh0LmpzIGFzc2V0cy5cbiAqIEBsaW5rIGh0dHBzOi8vbmV4dGpzLm9yZy9kb2NzL3BhZ2VzL2FwaS1yZWZlcmVuY2UvbmV4dC1jb25maWctanMvb3V0cHV0XG4gKi9cbmV4cG9ydCBjbGFzcyBOZXh0anNCdWlsZCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBVbmlxdWUgaWQgZm9yIHRoaXMgZGVwbG95bWVudC4gVXNlZCB0byBwYXJ0aXRpb24gY2FjaGUgc3RvcmFnZSBhbmQgYXNcbiAgICogbWV0YWRhdGEgZm9yIHN0YXRpYyBhc3NldHMgaW4gUzMgYnVja2V0LlxuICAgKlxuICAgKiBOZXh0LmpzJ3MgYnVpbGQgSUQsIHN1ZmZpeGVkIHdpdGggdGhlIGFwcCdzIGBkZXBsb3ltZW50SWRgIHdoZW4gaXQgc2V0c1xuICAgKiBvbmUuIFRoZSBidWlsZCBJRCBhbG9uZSBpcyBub3QgdW5pcXVlIHBlciBkZXBsb3ltZW50OiBzZXR0aW5nXG4gICAqIGBkZXBsb3ltZW50SWRgIChvciBidWlsZGluZyB3aXRoIGBORVhUX0RFUExPWU1FTlRfSURgKSB0dXJucyBvbiBza2V3XG4gICAqIHByb3RlY3Rpb24sIGFuZCBuZXh0LmpzIHRoZW4gKnBpbnMqIHRoZSBidWlsZCBJRCB0byB0aGUgY29uc3RhbnRcbiAgICogYGJ1aWxkLVRmY3RzV1hwZmYyZktTYCDigJQgc2VlIGBnZXRCdWlsZElkYCBpbiBgbmV4dC9kaXN0L2J1aWxkL2luZGV4LmpzYCxcbiAgICogd2hpY2ggZG9lcyB0aGF0IGRlbGliZXJhdGVseSBzbyB0aGF0IHRvb2xpbmcgZG9pbmdcbiAgICogYC5yZXBsYWNlKGVzY2FwZWRCdWlsZElkLCDigKYpYCBzdGlsbCBoYXMgc29tZXRoaW5nIHRvIHJlcGxhY2UuIFR3b1xuICAgKiBzdWNjZXNzaXZlIGRlcGxveW1lbnRzIG9mIHN1Y2ggYW4gYXBwIHdvdWxkIHNoYXJlIG9uZSBjYWNoZSBwcmVmaXggYW5kIG9uZVxuICAgKiByZXZhbGlkYXRpb24tdGFibGUgcGFydGl0aW9uLCBhbmQgdGhlIG5ldyBvbmUgd291bGQgcmVhZCB0aGUgcHJldmlvdXNcbiAgICogb25lJ3MgcHJlcmVuZGVycy4gQXBwZW5kaW5nIHRoZSBkZXBsb3ltZW50IElEIHJlc3RvcmVzIHRoZSBcIm9uZVxuICAgKiBkZXBsb3ltZW50LCBvbmUgcGFydGl0aW9uXCIgaW52YXJpYW50IHRoYXQgSUQgZXhpc3RzIHRvIGNhcnJ5LlxuICAgKlxuICAgKiBOb3RoaW5nIHJvdXRlcyBvbiB0aGlzIHZhbHVlIOKAlCB0aGUgYC9fbmV4dC9kYXRhLzxidWlsZElkPi/igKZgIFVSTCBzcGFjZSBpc1xuICAgKiByb3V0ZWQgb24gTmV4dC5qcydzIG93biBidWlsZCBJRCwgd2hpY2ggaXMgd2hhdCB0aGUgYXBwJ3MgY2xpZW50IGJ1bmRsZXNcbiAgICogY2Fycnkg4oCUIHNvIGl0IGlzIGZyZWUgdG8gYmUgbG9uZ2VyIHRoYW4gbmV4dC5qcydzIG93bi5cbiAgICovXG4gIGJ1aWxkSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gdGhlIGluaXQgY2FjaGUgZGlyZWN0b3J5XG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvLm5leHQvY2RrLW5leHRqcy1pbml0LWNhY2hlXCJcbiAgICovXG4gIGluaXRDYWNoZURpcjogc3RyaW5nO1xuICAvKipcbiAgICogQWJzb2x1dGUgcGF0aCB0byBwdWJsaWMuIFVzZSBieSBDbG91ZEZyb250L0FMQiB0byBjcmVhdGUgYmVoYXZpb3JzL3J1bGVzXG4gICAqIEBleGFtcGxlIFwiL1VzZXJzL2pvaG4vbXlhcHAvcHVibGljXCJcbiAgICovXG4gIHB1YmxpY0RpckVudHJpZXM6IFB1YmxpY0RpckVudHJ5W107XG4gIC8qKlxuICAgKiBUaGUgSmF2YVNjcmlwdCBmaWxlIE5vZGUuanMgcnVucyB0byBzZXJ2ZSByZXF1ZXN0cywgcmVsYXRpdmUgdG8gdGhlXG4gICAqIGRlcGxveW1lbnQgcm9vdC4gY2RrLW5leHRqcydzIG93biBjb250YWluZXIgc2hlbGwsIG5vdCBgbmV4dCBidWlsZGAgb3V0cHV0LFxuICAgKiBzbyBpdCBpcyB0aGUgc2FtZSBwYXRoIGZvciBldmVyeSBhcHAuXG4gICAqIEBleGFtcGxlIFwiY2RrLW5leHRqcy1ydW50aW1lL3NlcnZlci5tanNcIlxuICAgKi9cbiAgcmVsYXRpdmVQYXRoVG9FbnRyeXBvaW50OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBBYnNvbHV0ZSBwYXRoIHRvIHRoZSAubmV4dCBkaXJlY3RvcnkgY29udGFpbmluZyBOZXh0LmpzIGJ1aWxkIGFydGlmYWN0c1xuICAgKi9cbiAgZG90TmV4dFBhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBOZXh0LmpzIGFwcCdzIG93biBgYmFzZVBhdGhgIOKAlCB0aGUgVVJMIHByZWZpeCBpdCBnZW5lcmF0ZXMgaXRzIGxpbmtzIGFuZFxuICAgKiBhc3NldCBocmVmcyB1bmRlciDigJQgYXMgdGhlIGFkYXB0ZXIgbWFuaWZlc3QgcmVjb3JkZWQgaXQuIE5vcm1hbGl6ZWQgdG8gYSBiYXJlIHBhdGggc2VnbWVudCwgZW1wdHkgd2hlbiB0aGUgYXBwIHNldHMgbm9uZS4gRXhwb3NlZCBzb1xuICAgKiByb290IGNvbnN0cnVjdHMgY2FuIHJlY29uY2lsZSBpdCB3aXRoIHRoZSBDREsgYGJhc2VQYXRoYCBwcm9wLCB3aGljaCBpcyBhXG4gICAqIGRpc3RpbmN0IHRoaW5nOyBzZWUgYHJlc29sdmVCYXNlUGF0aGAuXG4gICAqL1xuICBuZXh0Q29uZmlnQmFzZVBhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBOZXh0LmpzIGFwcCdzIG93biBgYXNzZXRQcmVmaXhgLCBhcyBhIHBhdGggd2l0aCBhIGxlYWRpbmcgc2xhc2ggYW5kIG5vXG4gICAqIHRyYWlsaW5nIG9uZSwgZW1wdHkgd2hlbiB0aGUgYXBwIHNldHMgbm9uZSBvciBzZXRzIGFuIGFic29sdXRlIFVSTCAod2hpY2hcbiAgICogbmFtZXMgYW4gb3JpZ2luIGNkay1uZXh0anMgZG9lcyBub3Qgc2VydmUpLlxuICAgKlxuICAgKiBFeHBvc2VkIGJlY2F1c2UgaXQgaXMgdGhlIHNoYXBlIG9mIGBhc3NldFByZWZpeGAgdGhlIHJlZ2lvbmFsXG4gICAqIGBOZXh0anNUeXBlYHMgY2Fubm90IHNlcnZlIOKAlCBzZWUgYHdhcm5VbnNlcnZlZEFzc2V0UHJlZml4YC4gV2hhdCB0aGVcbiAgICogZGlzdHJpYnV0aW9uIGhhcyB0byBhbnN3ZXIgb24gaXMge0BsaW5rIG5leHRDb25maWdBc3NldFByZWZpeFBhdGh9LCB3aGljaFxuICAgKiBhbHNvIGNvdmVycyB0aGUgcGF0aCBhbiBhYnNvbHV0ZSBwcmVmaXggY2Fycmllcy5cbiAgICovXG4gIG5leHRDb25maWdBc3NldFByZWZpeDogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHBhdGggcG9ydGlvbiBvZiB0aGUgYXBwJ3MgYGFzc2V0UHJlZml4YCwgd2hpY2hldmVyIGZvcm0gaXQgdGFrZXM6IFwiL2NkblwiXG4gICAqIGZvciBib3RoIGBhc3NldFByZWZpeDogXCIvY2RuXCJgIGFuZCBgYXNzZXRQcmVmaXg6XG4gICAqIFwiaHR0cHM6Ly9jZG4uZXhhbXBsZS5jb20vY2RuXCJgLCBlbXB0eSB3aGVuIHRoZXJlIGlzIG5vIHBhdGggdG8gYW5zd2VyIG9uLlxuICAgKlxuICAgKiBFeHBvc2VkIGJlY2F1c2UgaXQgaXMgYSBVUkwgcHJlZml4IHRoZSBkaXN0cmlidXRpb24gaGFzIHRvIGFuc3dlciBvbjogTmV4dC5qc1xuICAgKiBlbWl0cyBgPGFzc2V0UHJlZml4Pi9fbmV4dC9zdGF0aWMvLi4uYCBmb3IgZXZlcnkgYnVuZGxlIGFuZCBjb21waWxlcyBhIHJld3JpdGVcbiAgICogdGhhdCBzZXJ2ZXMgdGhvc2UgVVJMcycgcGF0aHMgaXRzZWxmLCB3aGlsZSB0aGUgb2JqZWN0cyBsaXZlIGluIFMzIHVuZGVyXG4gICAqIGA8YmFzZVBhdGg+L19uZXh0L3N0YXRpYy8uLi5gLlxuICAgKi9cbiAgbmV4dENvbmZpZ0Fzc2V0UHJlZml4UGF0aDogc3RyaW5nO1xuICAvKipcbiAgICogRXZlcnkgc3RhZ2VkIGRlcGxveW1lbnQgcm9vdCwgb25lIHBlciBmdW5jdGlvbiBncm91cCwgYGRlZmF1bHRgIGZpcnN0OiB0aGVcbiAgICogc3RhZ2VkIHVuaW9uIG9mIGVhY2ggZ3JvdXAncyBzaGlwcGVkIG91dHB1dHMgYW5kIHRoZWlyIHRyYWNlZCBhc3NldHMsXG4gICAqIHdyaXR0ZW4gYnkgdGhlIGFkYXB0ZXIncyBgb25CdWlsZENvbXBsZXRlYC4gRXhhY3RseSBvbmUgZW50cnkgKG5hbWVkXG4gICAqIGBkZWZhdWx0YCwgYXQgYC5uZXh0L2Nkay1uZXh0anMtYWRhcHRlci9hcHBgKSB1bmxlc3MgYGZ1bmN0aW9uR3JvdXBzYFxuICAgKiBzcGxpdHMgdGhlIGFwcC4gVGhlIExhbWJkYSB6aXAgYXNzZXRzOyBDb250YWluZXJzIGBDT1BZYCB0aGUgYGRlZmF1bHRgIG9uZS5cbiAgICovXG4gIGRlcGxveW1lbnRSb290czogTmV4dGpzRGVwbG95bWVudFJvb3RbXTtcbiAgLyoqXG4gICAqIFdoYXQgcm91dGVzIGVhY2ggbm9uLWRlZmF1bHQgZnVuY3Rpb24gZ3JvdXAncyBVUkxzIHRvIGl0LCBtb3N0IHNwZWNpZmljXG4gICAqIGZpcnN0IOKAlCB0aGUgb3JkZXIgQ2xvdWRGcm9udCBoYXMgdG8gc2VlIHRoZW0gaW4sIHNpbmNlIGl0IHN0b3BzIGF0IHRoZVxuICAgKiBmaXJzdCBtYXRjaC4gRW1wdHkgdW5sZXNzIGBmdW5jdGlvbkdyb3Vwc2Agc3BsaXRzIHRoZSBhcHAuXG4gICAqL1xuICBmdW5jdGlvbkdyb3VwQmVoYXZpb3JzOiBOZXh0anNGdW5jdGlvbkdyb3VwQmVoYXZpb3JbXTtcbiAgLyoqXG4gICAqIEZyb20gdGhlIGRlcGxveW1lbnQgcm9vdCB0byB0aGUgTmV4dC5qcyBwcm9qZWN0IGRpciwgUE9TSVgsIGBcIlwiYCB3aGVuXG4gICAqIHRoZSBhcHAgaXMgYXQgdGhlIHJlcG8gcm9vdC4gVGhlIHJ1bnRpbWUgYGNoZGlyYHMgaGVyZTsgQ29udGFpbmVycyBwYXNzIGl0IHRvXG4gICAqIHRoZWlyIERvY2tlcmZpbGUgc28gYC5uZXh0L3N0YXRpY2AgYW5kIGBwdWJsaWNgIGxhbmQgaW4gdGhlIHNhbWUgcGxhY2UuXG4gICAqIEBzZWUgQWRhcHRlck1hbmlmZXN0LnJlbGF0aXZlUHJvamVjdERpclxuICAgKi9cbiAgcmVsYXRpdmVQcm9qZWN0RGlyOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgYXJjaGl0ZWN0dXJlIGV2ZXJ5IGRlcGxveW1lbnQgcm9vdCdzIG5hdGl2ZSBkZXBlbmRlbmNpZXMgKGBzaGFycGApXG4gICAqIHdlcmUgc3RhZ2VkIGZvci4gVGhlIExhbWJkYXMgZGVwbG95aW5nIHRoZW0gbXVzdCB1c2UgdGhlIHNhbWUgb25lLlxuICAgKi9cbiAgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmU7XG5cbiAgcHJpdmF0ZSBwcm9wczogTmV4dGpzQnVpbGRQcm9wcztcbiAgcHJpdmF0ZSBidWlsZENvbW1hbmQ6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogTmV4dGpzQnVpbGRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuICAgIHRoaXMuZG90TmV4dFBhdGggPSBqb2luKHByb3BzLmJ1aWxkRGlyZWN0b3J5LCBcIi5uZXh0XCIpO1xuXG4gICAgdGhpcy5idWlsZENvbW1hbmQgPSBwcm9wcy5idWlsZENvbW1hbmQgfHwgXCJucG0gcnVuIGJ1aWxkXCI7XG5cbiAgICAvLyBTZXQgaW5pdCBjYWNoZSBkaXJlY3RvcnkgcGF0aFxuICAgIHRoaXMuaW5pdENhY2hlRGlyID0gam9pbihcbiAgICAgIHByb3BzLmJ1aWxkRGlyZWN0b3J5LFxuICAgICAgXCIubmV4dFwiLFxuICAgICAgXCJjZGstbmV4dGpzLWluaXQtY2FjaGVcIixcbiAgICApO1xuXG4gICAgLy8gQmVmb3JlIHRoZSBidWlsZCwgbm90IGFmdGVyIGl0OiB0aGUgYnVpbGQgaXMgbWludXRlcyBsb25nLCBhbmQgdGhlIGVudiB2YXJcbiAgICAvLyBpdCBwYXNzZXMgZ3JvdXBzIHRocm91Z2ggaXMgb25seSBzZXQgZm9yIGEgbm9uLWVtcHR5IGFycmF5IOKAlCBzbyBhbiBpbnZhbGlkXG4gICAgLy8gYGZ1bmN0aW9uR3JvdXBzYCAoYW4gZW1wdHkgYXJyYXksIGEgcmVzZXJ2ZWQgbmFtZSwgYSBncm91cCBvd25pbmcgbm9cbiAgICAvLyByb3V0ZXMpIHdvdWxkIG90aGVyd2lzZSBiZSByZXBvcnRlZCBhcyBcInRoZSBidWlsZCBzdGFnZWQgdGhlIHdyb25nXG4gICAgLy8gZ3JvdXBzXCIsIGFmdGVyIHBheWluZyBmb3IgdGhlIGJ1aWxkLCBpbnN0ZWFkIG9mIGFzIHRoZSBwcm9wIGVycm9yIGl0IGlzLlxuICAgIGlmIChwcm9wcy5mdW5jdGlvbkdyb3Vwcykge1xuICAgICAgdmFsaWRhdGVGdW5jdGlvbkdyb3Vwcyhwcm9wcy5mdW5jdGlvbkdyb3VwcyBhcyBGdW5jdGlvbkdyb3VwU3BlY1tdKTtcbiAgICB9XG5cbiAgICAvLyBFeGVjdXRlIGxvY2FsIGJ1aWxkIHByb2Nlc3NcbiAgICBpZiAocHJvcHMuc2tpcEJ1aWxkICE9PSB0cnVlKSB7XG4gICAgICB0aGlzLnJ1bk5leHRCdWlsZCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBTa2lwcGluZzogJHt0aGlzLmJ1aWxkQ29tbWFuZH1gKTtcbiAgICB9XG5cbiAgICAvLyBGaXJzdCwgYmVmb3JlIGFueXRoaW5nIGVsc2UgcmVhZHMgYC5uZXh0YDogYSBtaXNzaW5nIG1hbmlmZXN0IGlzIHRoZSBvbmVcbiAgICAvLyBlcnJvciB0aGF0IG5hbWVzIHRoZSBjYXVzZSAobm8gYnVpbGQsIG9yIG9uZSB3aXRob3V0IHRoZSBhZGFwdGVyKSwgd2hlcmVcbiAgICAvLyBldmVyeSBsYXRlciByZWFkIGZhaWxzIHdpdGggYSBiYXJlIEVOT0VOVC5cbiAgICBjb25zdCBtYW5pZmVzdCA9IHRoaXMucmVhZEFkYXB0ZXJNYW5pZmVzdCgpO1xuXG4gICAgLy8gRGVsaWJlcmF0ZWx5IG91dHNpZGUgdGhlIGBza2lwQnVpbGRgIGdhdGUuIFRoZSBwYXRjaCBpcyBhIHByb3BlcnR5IG9mXG4gICAgLy8gKnNlcnZpbmcqIHRocm91Z2ggQ2xvdWRGcm9udCwgbm90IG9mIHdobyByYW4gYG5leHQgYnVpbGRgOiB3aXRob3V0IGl0XG4gICAgLy8gZXZlcnkgUE9TVCB3aXRoIGEgYm9keSBpcyByZWplY3RlZCBieSB0aGUgTGFtYmRhIEZ1bmN0aW9uIFVSTCBiZWZvcmUgaXRcbiAgICAvLyByZWFjaGVzIHRoZSBhcHAgKHNlZSBgcGF0Y2hGZXRjaEluQ2xpZW50SnNgKS4gUnVubmluZyBpdCBvbmx5IGluc2lkZVxuICAgIC8vIGBydW5OZXh0QnVpbGRgIG1lYW50IGBza2lwQnVpbGQ6IHRydWVgIHNpbGVudGx5IHNoaXBwZWQgYW4gYXBwIHdob3NlXG4gICAgLy8gc2VydmVyIGFjdGlvbnMgYW5kIFBPU1Qgcm91dGUgaGFuZGxlcnMgYWxsIHJldHVybmVkIDQwMy5cbiAgICBpZiAocHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5HTE9CQUxfRlVOQ1RJT05TKSB7XG4gICAgICB0aGlzLnBhdGNoRmV0Y2hJbkNsaWVudEpzKCk7XG4gICAgfVxuXG4gICAgdGhpcy5idWlsZElkID0gZGVwbG95bWVudEJ1aWxkSWQobWFuaWZlc3QpO1xuICAgIHRoaXMucHVibGljRGlyRW50cmllcyA9IHRoaXMuZ2V0TG9jYWxQdWJsaWNEaXJFbnRyaWVzKCk7XG4gICAgLy8gTmV4dC5qcydzIHJlc29sdmVkIGNvbmZpZywgdGhlIHNhbWUgb25lIGl0IHdyaXRlcyBpbnRvXG4gICAgLy8gYHJlcXVpcmVkLXNlcnZlci1maWxlcy5qc29uYC5cbiAgICB0aGlzLm5leHRDb25maWdCYXNlUGF0aCA9IG5vcm1hbGl6ZUJhc2VQYXRoKG1hbmlmZXN0LmNvbmZpZy5iYXNlUGF0aCk7XG4gICAgdGhpcy5uZXh0Q29uZmlnQXNzZXRQcmVmaXggPSByZWxhdGl2ZUFzc2V0UHJlZml4KFxuICAgICAgbWFuaWZlc3QuY29uZmlnLmFzc2V0UHJlZml4LFxuICAgICk7XG4gICAgdGhpcy5uZXh0Q29uZmlnQXNzZXRQcmVmaXhQYXRoID0gYXNzZXRQcmVmaXhQYXRoKFxuICAgICAgbWFuaWZlc3QuY29uZmlnLmFzc2V0UHJlZml4LFxuICAgICk7XG5cbiAgICBjb25zdCBpc0Z1bmN0aW9ucyA9XG4gICAgICBwcm9wcy5uZXh0anNUeXBlID09PSBOZXh0anNUeXBlLkdMT0JBTF9GVU5DVElPTlMgfHxcbiAgICAgIHByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuUkVHSU9OQUxfRlVOQ1RJT05TO1xuXG4gICAgdGhpcy5yZWxhdGl2ZVByb2plY3REaXIgPSBtYW5pZmVzdC5yZWxhdGl2ZVByb2plY3REaXI7XG4gICAgdGhpcy5yZWxhdGl2ZVBhdGhUb0VudHJ5cG9pbnQgPSBqb2luUG9zaXgoUlVOVElNRV9ESVJfTkFNRSwgXCJzZXJ2ZXIubWpzXCIpO1xuICAgIHRoaXMuYXJjaGl0ZWN0dXJlID0gZGVwbG95bWVudEFyY2hpdGVjdHVyZShwcm9wcyk7XG4gICAgdGhpcy5kZXBsb3ltZW50Um9vdHMgPSB0aGlzLnJlc29sdmVEZXBsb3ltZW50Um9vdHMobWFuaWZlc3QpO1xuICAgIHRoaXMuZnVuY3Rpb25Hcm91cEJlaGF2aW9ycyA9IG1hbmlmZXN0LmJlaGF2aW9ycyA/PyBbXTtcblxuICAgIC8vIE9ubHkgdGhlIFJlZ2lvbmFsQ29udGFpbmVycyBpbWFnZSBjYXJyaWVzIGBwdWJsaWMvYDogbm90aGluZyBpcyBpbiBmcm9udFxuICAgIC8vIG9mIGl0IHRvIGFuc3dlciB0aG9zZSBwYXRocyBmcm9tIFMzLiBFdmVyeSBvdGhlciB0eXBlIGxpc3RzIGl0IGhlcmUgYW5kXG4gICAgLy8gcmVhZHMgYSBmaWxlIHRoZSBlZGdlIGRpZG4ndCByb3V0ZSB0byBTMyAoYSByZXdyaXRlIG9udG8gaXQpIGZyb20gdGhlcmUuXG4gICAgY29uc3QgcHVibGljT25EaXNrID0gcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5SRUdJT05BTF9DT05UQUlORVJTO1xuICAgIGlmIChwdWJsaWNPbkRpc2spIHtcbiAgICAgIC8vIEl0cyBnZW5lcmF0ZWQgRG9ja2VyZmlsZSBgQ09QWWBzIGBwdWJsaWNgLCB3aGljaCBmYWlscyB0aGUgaW1hZ2UgYnVpbGRcbiAgICAgIC8vIHdoZW4gdGhlIGFwcCBoYXMgbm9uZS4gQW4gZW1wdHkgZGlyZWN0b3J5IGlzIHdoYXQgYG5leHQgc3RhcnRgIHNlZXNcbiAgICAgIC8vIGZvciBhbiBhcHAgd2l0aG91dCBvbmUgYW55d2F5LCBhbmQgZ2l0IGRvZXNuJ3QgdHJhY2sgaXQuXG4gICAgICBta2RpclN5bmMoam9pbihwcm9wcy5idWlsZERpcmVjdG9yeSwgXCJwdWJsaWNcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qgcm9vdCBvZiB0aGlzLmRlcGxveW1lbnRSb290cykge1xuICAgICAgdGhpcy5zdGFnZVJ1bnRpbWUocm9vdC5wYXRoLCBpc0Z1bmN0aW9ucywgcHVibGljT25EaXNrKTtcbiAgICAgIC8vIEZ1bmN0aW9ucyBydW4gb24gdGhlIExhbWJkYSBtYW5hZ2VkIHJ1bnRpbWUgKEFtYXpvbiBMaW51eCAyMDIzLCBnbGliYyksXG4gICAgICAvLyBmb3IgdGhlIGFyY2hpdGVjdHVyZSB0aGVpciBMYW1iZGEgZGVwbG95cywgd2hhdGV2ZXIgdGhpcyBtYWNoaW5lIGlzO1xuICAgICAgLy8gQ29udGFpbmVycyBydW4gb24gbm9kZToyNC1hbHBpbmUgKG11c2wpLlxuICAgICAgdGhpcy5zdGFnZVNoYXJwRm9yVGFyZ2V0KFxuICAgICAgICByb290LFxuICAgICAgICBqb2luKHJvb3QucGF0aCwgdGhpcy5yZWxhdGl2ZVByb2plY3REaXIpLFxuICAgICAgICBgJHtpc0Z1bmN0aW9ucyA/IFwibGludXhcIiA6IFwibGludXhtdXNsXCJ9LSR7dG9Ob2RlQXJjaGl0ZWN0dXJlKHRoaXMuYXJjaGl0ZWN0dXJlKX1gLFxuICAgICAgKTtcblxuICAgICAgaWYgKGlzRnVuY3Rpb25zKSB7XG4gICAgICAgIHRoaXMuYXNzZXJ0VW5kZXJMYW1iZGFMaW1pdChyb290KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTGluZSB1cCB0aGUgZ3JvdXBzIHRoZSBwcm9wcyBhc2tlZCBmb3Igd2l0aCB0aGUgcm9vdHMgdGhlIGJ1aWxkIGFjdHVhbGx5XG4gICAqIHN0YWdlZCwgYW5kIGZhaWwgbG91ZGx5IHdoZW4gdGhleSBkaXNhZ3JlZS5cbiAgICpcbiAgICogVGhleSBjYW4gZGlzYWdyZWUgaW4gYm90aCBkaXJlY3Rpb25zLCBhbmQgYm90aCBtZWFuIHRoZSBzYW1lIHRoaW5nIOKAlCB0aGVcbiAgICogYC5uZXh0YCBvbiBkaXNrIGNhbWUgZnJvbSBhIGJ1aWxkIHRoYXQgZGlkIG5vdCBzZWUgdGhpcyBgZnVuY3Rpb25Hcm91cHNgIOKAlFxuICAgKiBidXQgdGhlIGNhdXNlcyBkaWZmZXI6IGBza2lwQnVpbGQ6IHRydWVgIHdpdGggYSBidWlsZCBydW4gYnkgaGFuZCwgb3IgYVxuICAgKiBzdGFsZSBgLm5leHRgIGZyb20gYmVmb3JlIHRoZSBwcm9wIGNoYW5nZWQuIEVpdGhlciB3YXkgZXZlcnkgbGF0ZXIgc3ltcHRvbVxuICAgKiAoYSBMYW1iZGEgbWlzc2luZyBhbiBlbnRyeXBvaW50LCBhIENsb3VkRnJvbnQgYmVoYXZpb3IgcG9pbnRpbmcgYXQgYVxuICAgKiBmdW5jdGlvbiB0aGF0IGNhbm5vdCBzZXJ2ZSBpdCkgaXMgdGhpcywgc2V2ZXJhbCBzdGVwcyBkb3duc3RyZWFtLlxuICAgKi9cbiAgcHJpdmF0ZSByZXNvbHZlRGVwbG95bWVudFJvb3RzKFxuICAgIG1hbmlmZXN0OiBBZGFwdGVyTWFuaWZlc3QsXG4gICk6IE5leHRqc0RlcGxveW1lbnRSb290W10ge1xuICAgIGNvbnN0IHN0YWdlZCA9IG1hbmlmZXN0Lmdyb3VwcztcblxuICAgIC8vIE5hbWVzICphbmQqIHJvdXRlczogbW92aW5nIGAvcmVwb3J0cy8qKmAgaW50byBhbiBleGlzdGluZyBncm91cCBrZWVwcyB0aGVcbiAgICAvLyBuYW1lcyBhbmQgc3RpbGwgbGVhdmVzIHRoYXQgZ3JvdXAncyB6aXAgd2l0aG91dCB0aGUgcmVwb3J0cyBlbnRyeXBvaW50cy5cbiAgICAvLyBPcmRlciBpcyBub3Q6IGFzc2lnbm1lbnQgYW5kIENsb3VkRnJvbnQgYmVoYXZpb3JzIGJvdGggZ28gbW9zdCBzcGVjaWZpY1xuICAgIC8vIGZpcnN0LCBhbmQgbm8gdHdvIGRpc3RpbmN0IHBhdHRlcm5zIHRpZSBvbiBhIFVSTCAoYGZ1bmN0aW9uLWdyb3Vwcy50c2ApLFxuICAgIC8vIHNvIHJlb3JkZXJpbmcgZ3JvdXBzIG9yIHJvdXRlcyBpcyB0aGUgc2FtZSBzcGxpdC5cbiAgICAvLyBBbHJlYWR5IHZhbGlkYXRlZCBpbiB0aGUgY29uc3RydWN0b3IsIHNvIHRoaXMgaXMgYWJzZW50IG9yIG5vbi1lbXB0eS5cbiAgICBjb25zdCB3YW50ZWQgPSB0aGlzLnByb3BzLmZ1bmN0aW9uR3JvdXBzPy5sZW5ndGhcbiAgICAgID8gdG9GdW5jdGlvbkdyb3VwU3BlY3ModGhpcy5wcm9wcy5mdW5jdGlvbkdyb3VwcylcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IGdvdCA9IG1hbmlmZXN0LmZ1bmN0aW9uR3JvdXBzO1xuXG4gICAgaWYgKFxuICAgICAgSlNPTi5zdHJpbmdpZnkoc29ydGVkR3JvdXBTcGVjcyh3YW50ZWQpKSAhPT1cbiAgICAgIEpTT04uc3RyaW5naWZ5KHNvcnRlZEdyb3VwU3BlY3MoZ290KSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7TE9HX1BSRUZJWH0gXFxgZnVuY3Rpb25Hcm91cHNcXGAgYXNrcyBmb3IgYCArXG4gICAgICAgICAgYCR7d2FudGVkID8gSlNPTi5zdHJpbmdpZnkod2FudGVkKSA6IFwibm8gc3BsaXR0aW5nXCJ9IGJ1dCB0aGUgYnVpbGQgYCArXG4gICAgICAgICAgYGluICR7dGhpcy5kb3ROZXh0UGF0aH0gd2FzIHNwbGl0IGludG8gYCArXG4gICAgICAgICAgYCR7Z290ID8gSlNPTi5zdHJpbmdpZnkoZ290KSA6IFwiYSBzaW5nbGUgZGVwbG95bWVudCByb290XCJ9LiBgICtcbiAgICAgICAgICBgR3JvdXBzIGFyZSByZXNvbHZlZCBkdXJpbmcgXFxgbmV4dCBidWlsZFxcYCAoY2RrLW5leHRqcyBwYXNzZXMgdGhlbSBpbiBgICtcbiAgICAgICAgICBgdmlhICR7RlVOQ1RJT05fR1JPVVBTX0VOVl9WQVJ9KSwgc28gdGhpcyBtZWFucyB0aGUgYnVpbGQgb3V0cHV0IGlzIGAgK1xuICAgICAgICAgIGBzdGFsZSwgb3IgXFxgc2tpcEJ1aWxkOiB0cnVlXFxgIGFuZCB0aGUgYnVpbGQgd2FzIHJ1biB3aXRob3V0IHRoYXQgYCArXG4gICAgICAgICAgYHZhcmlhYmxlIHNldC5gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBuYW1lcyA9IHN0YWdlZCA/IE9iamVjdC5rZXlzKHN0YWdlZCkgOiBbREVGQVVMVF9GVU5DVElPTl9HUk9VUF07XG4gICAgY29uc3Qgcm9vdHMgPSBuYW1lcy5tYXAoKG5hbWUpID0+ICh7XG4gICAgICBuYW1lLFxuICAgICAgcGF0aDogam9pbihcbiAgICAgICAgdGhpcy5kb3ROZXh0UGF0aCxcbiAgICAgICAgQURBUFRFUl9ESVJfTkFNRSxcbiAgICAgICAgLi4uZ3JvdXBTdGFnaW5nRGlyTmFtZShzdGFnZWQgPyBuYW1lIDogdW5kZWZpbmVkKS5zcGxpdChcIi9cIiksXG4gICAgICApLFxuICAgICAgcm91dGVzOiBzdGFnZWQ/LltuYW1lXSA/PyBbXSxcbiAgICB9KSk7XG5cbiAgICAvLyBgZGVmYXVsdGAgZmlyc3QsIHNvIGFueSBcInRoZSByb290XCIgY2FsbGVyIGdldHMgdGhlIGdyb3VwIHRoYXQgb3duc1xuICAgIC8vIGV2ZXJ5dGhpbmcgdW5hc3NpZ25lZC5cbiAgICByb290cy5zb3J0KChhLCBiKSA9PlxuICAgICAgYS5uYW1lID09PSBERUZBVUxUX0ZVTkNUSU9OX0dST1VQXG4gICAgICAgID8gLTFcbiAgICAgICAgOiBiLm5hbWUgPT09IERFRkFVTFRfRlVOQ1RJT05fR1JPVVBcbiAgICAgICAgICA/IDFcbiAgICAgICAgICA6IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSksXG4gICAgKTtcblxuICAgIGZvciAoY29uc3Qgcm9vdCBvZiByb290cykge1xuICAgICAgaWYgKCFleGlzdHNTeW5jKHJvb3QucGF0aCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IFRoZSBkZXBsb3ltZW50IHJvb3QgZm9yIGZ1bmN0aW9uIGdyb3VwIGAgK1xuICAgICAgICAgICAgYFwiJHtyb290Lm5hbWV9XCIgaXMgbWlzc2luZyBmcm9tICR7cm9vdC5wYXRofSwgdGhvdWdoIHRoZSBhZGFwdGVyIGAgK1xuICAgICAgICAgICAgYG1hbmlmZXN0IGxpc3RzIGl0LiBUaGUgXFxgLm5leHRcXGAgZGlyZWN0b3J5IGhhcyBiZWVuIG1vZGlmaWVkIHNpbmNlIGAgK1xuICAgICAgICAgICAgYFxcYG5leHQgYnVpbGRcXGAgcmFuLmAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByb290cztcbiAgfVxuXG4gIC8qKlxuICAgKiBMYW1iZGEgZW5mb3JjZXMgMjUwIE1CIHVuemlwcGVkIGF0IENsb3VkRm9ybWF0aW9uIHRpbWUsIHdoaWNoIGlzIG1pbnV0ZXNcbiAgICogaW50byBhIGRlcGxveSBhbmQgcmVwb3J0cyBvbmx5IGEgc2l6ZS4gU3BsaXR0aW5nIGV4aXN0cyB0byBzdGF5IHVuZGVyIHRoYXRcbiAgICogY2FwLCBzbyB0aGUgZXJyb3IgdGhhdCB0ZWxscyB5b3UgdG8gc3BsaXQgZnVydGhlciBoYXMgdG8gbmFtZSB0aGUgZ3JvdXAsIGl0c1xuICAgKiBzaXplLCBhbmQgd2hhdCB0byBkbyDigJQgYW5kIGFycml2ZSBhdCBzeW50aC5cbiAgICovXG4gIHByaXZhdGUgYXNzZXJ0VW5kZXJMYW1iZGFMaW1pdChyb290OiBOZXh0anNEZXBsb3ltZW50Um9vdCk6IHZvaWQge1xuICAgIGNvbnN0IGJ5dGVzID0gc3RvcmVkU2l6ZShyb290LnBhdGgpO1xuICAgIGRlYnVnKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gRGVwbG95bWVudCByb290IFwiJHtyb290Lm5hbWV9XCIgaXMgJHsoYnl0ZXMgLyAxZTYpLnRvRml4ZWQoMSl9IE1CIHVuemlwcGVkYCxcbiAgICApO1xuICAgIGlmIChieXRlcyA8PSBMQU1CREFfVU5aSVBQRURfTElNSVRfQllURVMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbWIgPSAodmFsdWU6IG51bWJlcikgPT4gYCR7KHZhbHVlIC8gMTAyNCAvIDEwMjQpLnRvRml4ZWQoMCl9IE1CYDtcbiAgICBjb25zdCBpc1NwbGl0ID0gdGhpcy5kZXBsb3ltZW50Um9vdHMubGVuZ3RoID4gMTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtMT0dfUFJFRklYfSBGdW5jdGlvbiBncm91cCBcIiR7cm9vdC5uYW1lfVwiIGlzICR7bWIoYnl0ZXMpfSB1bnppcHBlZCwgYCArXG4gICAgICAgIGBvdmVyIExhbWJkYSdzICR7bWIoTEFNQkRBX1VOWklQUEVEX0xJTUlUX0JZVEVTKX0gbGltaXQuIGAgK1xuICAgICAgICAoaXNTcGxpdFxuICAgICAgICAgID8gYFNwbGl0IGl0cyByb3V0ZXMgZnVydGhlciwgb3IgbW92ZSBzb21lIG9mIHRoZW0gaW50byBhbm90aGVyIGdyb3VwOiBgICtcbiAgICAgICAgICAgIGB0aGUgY2FwIGlzIHBlciBmdW5jdGlvbiwgc28gdGhlIHNoYXJlZCBcXGBuZXh0XFxgIGNsb3N1cmUgZXZlcnkgZ3JvdXAgYCArXG4gICAgICAgICAgICBgZHVwbGljYXRlcyBjb3N0cyBub3RoaW5nIGFnYWluc3QgYW55IHNpbmdsZSBidWRnZXQuYFxuICAgICAgICAgIDogYFVzZSB0aGUgXFxgZnVuY3Rpb25Hcm91cHNcXGAgcHJvcCB0byBwYWNrYWdlIHJvdXRlcyBpbnRvIHNlcGFyYXRlIGAgK1xuICAgICAgICAgICAgYGZ1bmN0aW9ucy4gTm90ZSB0aGF0IHNwbGl0dGluZyBvbmx5IHJlbW92ZXMgcm91dGUtbG9jYWwgY29kZSDigJQgYCArXG4gICAgICAgICAgICBgYW55dGhpbmcgcmVhY2hhYmxlIGZyb20gYSBzaGFyZWQgbGF5b3V0IG9yIHRoZSBcXGBuZXh0XFxgIHJ1bnRpbWUgaXMgYCArXG4gICAgICAgICAgICBgaW4gZXZlcnkgZ3JvdXAuYCksXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWFkIHRoZSBtYW5pZmVzdCB0aGUgYWRhcHRlcidzIGBvbkJ1aWxkQ29tcGxldGVgIHdyb3RlLlxuICAgKlxuICAgKiBJdHMgYWJzZW5jZSBtZWFucyBgbmV4dCBidWlsZGAgcmFuIHdpdGhvdXQgY2RrLW5leHRqcydzIGFkYXB0ZXIgcmVnaXN0ZXJlZFxuICAgKiAob3Igd2l0aCBhIHN0YWxlIGBuZXh0LmNvbmZpZ2ApLCB3aGljaCBpcyB3b3J0aCBzYXlpbmcgcGxhaW5seSBoZXJlOiBldmVyeVxuICAgKiBsYXRlciBmYWlsdXJlIOKAlCBhIExhbWJkYSB0aGF0IGNhbm5vdCBmaW5kIGBtYW5pZmVzdC5qc29uYCwgYW4gZW1wdHkgYXNzZXQg4oCUXG4gICAqIGlzIHRoZSBzYW1lIGNhdXNlIHNldmVyYWwgc3RlcHMgZG93bnN0cmVhbS5cbiAgICovXG4gIHByaXZhdGUgcmVhZEFkYXB0ZXJNYW5pZmVzdCgpOiBBZGFwdGVyTWFuaWZlc3Qge1xuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oXG4gICAgICB0aGlzLmRvdE5leHRQYXRoLFxuICAgICAgQURBUFRFUl9ESVJfTkFNRSxcbiAgICAgIE1BTklGRVNUX0ZJTEVfTkFNRSxcbiAgICApO1xuICAgIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBjZGstbmV4dGpzIGFkYXB0ZXIgbWFuaWZlc3Qgbm90IGZvdW5kIGF0ICR7bWFuaWZlc3RQYXRofS4gYCArXG4gICAgICAgICAgYFwiJHt0aGlzLmJ1aWxkQ29tbWFuZH1cIiBtdXN0IHJ1biBhIE5leHQuanMgYnVpbGQgd2l0aCBjZGstbmV4dGpzJ3MgYCArXG4gICAgICAgICAgYGFkYXB0ZXIgcmVnaXN0ZXJlZC4gY2RrLW5leHRqcyBzZXRzIFxcYE5FWFRfQURBUFRFUl9QQVRIXFxgIG9uIHRoZSBgICtcbiAgICAgICAgICBgYnVpbGQgaXQgcnVucyBpdHNlbGYsIHNvIHRoaXMgdXN1YWxseSBtZWFucyBlaXRoZXIgdGhlIGJ1aWxkIGNvbW1hbmQgYCArXG4gICAgICAgICAgYGRvZXMgbm90IHJlYWNoIFxcYG5leHQgYnVpbGRcXGAgKGEgd3JhcHBlciB0aGF0IGRyb3BzIHRoZSBlbnZpcm9ubWVudCwgYCArXG4gICAgICAgICAgYG9yIGEgY2FjaGVkIGJ1aWxkIHRoYXQgZGlkIG5vdCByZS1ydW4pLCBvciBcXGBza2lwQnVpbGQ6IHRydWVcXGAgYW5kIGAgK1xuICAgICAgICAgIGB0aGUgYnVpbGQgaGFwcGVuZWQgb3V0c2lkZSBDREsuIEZvciB0aGUgbGF0dGVyLCBzZXQgYCArXG4gICAgICAgICAgYFxcYGFkYXB0ZXJQYXRoOiByZXF1aXJlLnJlc29sdmUoXCJjZGstbmV4dGpzL2FkYXB0ZXJcIilcXGAgaW4gYCArXG4gICAgICAgICAgYG5leHQuY29uZmlnLiBBIGN1c3RvbSBcXGBkaXN0RGlyXFxgIGlzIG5vdCBzdXBwb3J0ZWQgZWl0aGVyOiBgICtcbiAgICAgICAgICBgY2RrLW5leHRqcyByZWFkcyB0aGUgYnVpbGQgZnJvbSBcXGAubmV4dFxcYC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICByZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoLCBcInV0Zi04XCIpLFxuICAgICk7XG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IEFEQVBURVJfTUFOSUZFU1RfVkVSU0lPTikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgVGhlIGNkay1uZXh0anMgYWRhcHRlciBtYW5pZmVzdCBhdCAke21hbmlmZXN0UGF0aH0gaXMgdmVyc2lvbiBgICtcbiAgICAgICAgICBgJHttYW5pZmVzdC52ZXJzaW9ufSwgYnV0IHRoaXMgdmVyc2lvbiBvZiBjZGstbmV4dGpzIHJlYWRzIHZlcnNpb24gYCArXG4gICAgICAgICAgYCR7QURBUFRFUl9NQU5JRkVTVF9WRVJTSU9OfS4gVGhlIGFkYXB0ZXIgdGhhdCB3cm90ZSBpdCBhbmQgdGhlIGAgK1xuICAgICAgICAgIGBjb25zdHJ1Y3RzIHJlYWRpbmcgaXQgY29tZSBmcm9tIHRoZSBzYW1lIHBhY2thZ2UsIHNvIHRoaXMgbWVhbnMgdHdvIGAgK1xuICAgICAgICAgIGBjZGstbmV4dGpzIHZlcnNpb25zIGFyZSBpbnN0YWxsZWQsIG9yIHRoZSBidWlsZCBvdXRwdXQgaXMgc3RhbGUuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBtYW5pZmVzdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb3B5IGNkay1uZXh0anMncyBvd24gYnVuZGxlZCByZXF1ZXN0LWhhbmRsaW5nIHNoZWxsIGFuZCB0aGUgbWFuaWZlc3QgaW50b1xuICAgKiBgPGRlcGxveW1lbnRSb290Pi9jZGstbmV4dGpzLXJ1bnRpbWUvYCwgd2hpY2ggaXMgd2hlcmVcbiAgICogYGRlcGxveW1lbnRSb290T2ZgL2BkZXBsb3llZE1hbmlmZXN0UGF0aGAgZXhwZWN0IHRvIGZpbmQgdGhlbS5cbiAgICpcbiAgICogT25seSB0aGUgc2hlbGwgdGhlIGRlcGxveW1lbnQgdHlwZSBhY3R1YWxseSBydW5zIGlzIGNvcGllZCDigJQgdGhlIExhbWJkYVxuICAgKiBoYW5kbGVyIGZvciBGdW5jdGlvbnMsIHRoZSBgbm9kZTpodHRwYCBzZXJ2ZXIgZm9yIENvbnRhaW5lcnMg4oCUIHNvIG5vdGhpbmdcbiAgICogc2hpcHMgfjEuNSBNQiBvZiBkZWFkIGNvZGUgYW5kIHRoZSB0cmVlIHNheXMgd2hpY2ggdHlwZSBwcm9kdWNlZCBpdC4gQm90aFxuICAgKiBhcmUgY29waWVkIGZyb20gdGhpcyBwYWNrYWdlJ3MgYGxpYi9gLCBuZXh0IHRvIHRoZSBjb21waWxlZCBjb25zdHJ1Y3QuXG4gICAqXG4gICAqIEV2ZXJ5IGdyb3VwIGdldHMgdGhlIHNhbWUgc2hlbGwgKmFuZCB0aGUgc2FtZSBtYW5pZmVzdCo6IGEgZnVuY3Rpb24gb25seVxuICAgKiBrbm93cyB3aGljaCByb3V0ZXMgaXQgb3ducyBzbyBpdCBjYW4gc2F5IHNvIHdoZW4gbWlzcm91dGVkLCBhbmQgdGhhdCBjb21lc1xuICAgKiBmcm9tIHtAbGluayBGVU5DVElPTl9HUk9VUF9FTlZfVkFSfSwgbm90IGZyb20gYSBwZXItZ3JvdXAgbWFuaWZlc3QuXG4gICAqL1xuICBwcml2YXRlIHN0YWdlUnVudGltZShcbiAgICBkZXBsb3ltZW50Um9vdDogc3RyaW5nLFxuICAgIGlzRnVuY3Rpb25zOiBib29sZWFuLFxuICAgIHB1YmxpY09uRGlzazogYm9vbGVhbixcbiAgKTogdm9pZCB7XG4gICAgY29uc3Qgc2hlbGwgPSBpc0Z1bmN0aW9ucyA/IFwibGFtYmRhLm1qc1wiIDogXCJzZXJ2ZXIubWpzXCI7XG4gICAgY29uc3Qgc291cmNlID0gam9pbihfX2Rpcm5hbWUsIFwiLi5cIiwgXCJydW50aW1lXCIsIHNoZWxsKTtcblxuICAgIGNvbnN0IHJ1bnRpbWVEaXIgPSBqb2luKGRlcGxveW1lbnRSb290LCBSVU5USU1FX0RJUl9OQU1FKTtcbiAgICAvLyBSZW1vdmVkIHJhdGhlciB0aGFuIG1lcmdlZDogYSBzdGFsZSBzaGVsbCBmcm9tIHRoZSBvdGhlciBkZXBsb3ltZW50IHR5cGVcbiAgICAvLyB3b3VsZCBvdGhlcndpc2Ugc2l0IGluIHRoZSBhc3NldCBhbmQgY2hhbmdlIGl0cyBoYXNoIGZvciBubyByZWFzb24uXG4gICAgcm1TeW5jKHJ1bnRpbWVEaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBta2RpclN5bmMocnVudGltZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgY3BTeW5jKHNvdXJjZSwgam9pbihydW50aW1lRGlyLCBzaGVsbCkpO1xuICAgIGNwU3luYyhcbiAgICAgIGpvaW4odGhpcy5kb3ROZXh0UGF0aCwgQURBUFRFUl9ESVJfTkFNRSwgTUFOSUZFU1RfRklMRV9OQU1FKSxcbiAgICAgIGpvaW4ocnVudGltZURpciwgTUFOSUZFU1RfRklMRV9OQU1FKSxcbiAgICApO1xuICAgIGlmICghcHVibGljT25EaXNrKSB7XG4gICAgICAvLyBUaGUgTGFtYmRhIHppcHMgYW5kIHRoZSBHbG9iYWxDb250YWluZXJzIGltYWdlIGRvbid0IGNhcnJ5IGBwdWJsaWMvYFxuICAgICAgLy8gKGl0cyBieXRlcyBhcmUgaW4gUzMpLCBzbyB0aGUgcnVudGltZSBjYW4ndCBsaXN0IGl0IGF0IHN0YXJ0IHRoZSB3YXlcbiAgICAgIC8vIHRoZSBSZWdpb25hbENvbnRhaW5lcnMgaW1hZ2UgZG9lcy5cbiAgICAgIC8vIExpc3RlZCBoZXJlLCBhZnRlciB0aGUgYnVpbGQgY29tbWFuZCwgc28gYHBvc3RidWlsZGAgb3V0cHV0IGlzIGluIGl0OlxuICAgICAgLy8gYSByZXdyaXRlIG9udG8gYSBsaXN0ZWQgZmlsZSBpcyB0aGVuIHNlcnZlZCBmcm9tIFMzIHJhdGhlciB0aGFuIDQwNGluZy5cbiAgICAgIHdyaXRlUHVibGljRmlsZUxpc3QoXG4gICAgICAgIHJ1bnRpbWVEaXIsXG4gICAgICAgIGpvaW4odGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeSwgXCJwdWJsaWNcIiksXG4gICAgICApO1xuICAgIH1cbiAgICBkZWJ1ZyhcbiAgICAgIGAke0xPR19QUkVGSVh9IFN0YWdlZCAke3NoZWxsfSBhbmQgJHtNQU5JRkVTVF9GSUxFX05BTUV9IGluICR7cnVudGltZURpcn1gLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogYE5FWFRfQURBUFRFUl9QQVRIYCBmb3IgdGhlIGJ1aWxkLCBzbyBgYWRhcHRlclBhdGhgIGluIGBuZXh0LmNvbmZpZ2AgaXNcbiAgICogb3B0aW9uYWwuXG4gICAqXG4gICAqIE5leHQuanMgcmVhZHMgdGhlIHZhcmlhYmxlIGFzIHRoZSAqZGVmYXVsdCogdmFsdWUgb2YgYGFkYXB0ZXJQYXRoYFxuICAgKiAoYG5leHQvZGlzdC9zZXJ2ZXIvY29uZmlnLXNoYXJlZC5qc2AsIGBkZWZhdWx0Q29uZmlnYCksIHNvIGFuIGFwcCB0aGF0IGRvZXNcbiAgICogc2V0IGBhZGFwdGVyUGF0aGAgc3RpbGwgd2lucyBhbmQgbm90aGluZyBleGlzdGluZyBjaGFuZ2VzLlxuICAgKlxuICAgKiBSZXNvbHZlZCBmcm9tIHRoZSBOZXh0LmpzIGFwcCwgbm90IGZyb20gY2RrLW5leHRqcydzIG93biBgX19kaXJuYW1lYCBhbmQgbm90XG4gICAqIGxlZnQgYXMgYSBiYXJlIHNwZWNpZmllci4gQm90aCBhbHRlcm5hdGl2ZXMgd2VyZSB0cmllZCBhbmQgYm90aCBhcmUgd3Jvbmc6XG4gICAqXG4gICAqIC0gY2RrLW5leHRqcydzIG93biBsb2NhdGlvbiBsb3NlcyBiZWNhdXNlIHRoZSBhZGFwdGVyIHJlc29sdmVzIGl0cyBzaWJsaW5nXG4gICAqICAgY2FjaGUgaGFuZGxlciByZWxhdGl2ZSB0byB3aGVyZXZlciAqaXQqIHdhcyBsb2FkZWQgZnJvbS4gQW4gYWRhcHRlciBsb2FkZWRcbiAgICogICBmcm9tIG91dHNpZGUgdGhlIGFwcCdzIHRyZWUgaGFuZHMgTmV4dC5qcyBhIGBjYWNoZUhhbmRsZXJgIG91dHNpZGVcbiAgICogICBgdHVyYm9wYWNrLnJvb3RgLCB3aGljaCBUdXJib3BhY2sgcmVqZWN0cyBvdXRyaWdodCAoXCJsZWF2ZXMgdGhlIGZpbGVzeXN0ZW1cbiAgICogICByb290XCIpLlxuICAgKiAtIEEgYmFyZSBzcGVjaWZpZXIgbG9zZXMgYmVjYXVzZSBOZXh0LmpzIHJlc29sdmVzIGBhZGFwdGVyUGF0aGAgZnJvbSBpbnNpZGVcbiAgICogICBpdHMgb3duIGNvbmZpZyBsb2FkZXIsIGkuZS4gZnJvbSBgbmV4dGAncyByZWFscGF0aC4gVW5kZXIgcG5wbSB0aGF0IGlzIHRoZVxuICAgKiAgIHZpcnR1YWwgc3RvcmUgKGBub2RlX21vZHVsZXMvLnBucG0vbmV4dEDigKYvbm9kZV9tb2R1bGVzL25leHQvYCksIGFuZCB0aGVcbiAgICogICB3YWxrIHVwIGZyb20gdGhlcmUgbmV2ZXIgcmVhY2hlcyB0aGUgYXBwJ3Mgb3duIGBub2RlX21vZHVsZXNgLlxuICAgKlxuICAgKiBVbnNldCB3aGVuIGBjZGstbmV4dGpzYCBpcyBub3QgcmVzb2x2YWJsZSBmcm9tIHRoZSBhcHAsIHdoaWNoIGlzIGxlZ2l0aW1hdGU6XG4gICAqIHRoZSBOZXh0LmpzIGFwcCBhbmQgdGhlIENESyBhcHAgY2FuIGJlIHNlcGFyYXRlIHBhY2thZ2VzLCBhbmQgb25seSB0aGUgQ0RLIG9uZVxuICAgKiBuZWNlc3NhcmlseSBkZXBlbmRzIG9uIGNkay1uZXh0anMuIHtAbGluayByZWFkQWRhcHRlck1hbmlmZXN0fSByZXBvcnRzIHRoZVxuICAgKiByZXN1bHRpbmcgZmFpbHVyZSBhbmQgbmFtZXMgdGhpcyBjYXNlLlxuICAgKlxuICAgKiBPbmUgc2V0dXAgdGhpcyBjYW5ub3Qgc2VydmUsIGFuZCB0aGUgcmVhc29uIHRoaXMgcmVwbydzIG93biBleGFtcGxlcyBzdGlsbCBzZXRcbiAgICogYGFkYXB0ZXJQYXRoYDogYSBgbGluazpgL2BmaWxlOmAgZGVwZW5kZW5jeSBvbiBhIGNkay1uZXh0anMgY2hlY2tvdXQgKm91dHNpZGUqXG4gICAqIHRoZSBhcHAncyBwcm9qZWN0IHJvb3QuIFRoZSBzeW1saW5rIHJlc29sdmVzIG91dCBvZiB0aGUgcHJvamVjdCwgc28gdGhlXG4gICAqIGBjYWNoZUhhbmRsZXJgIGVzY2FwZSBhYm92ZSBhcHBsaWVzLiBTZXQgYGFkYXB0ZXJQYXRoYCBpbiBgbmV4dC5jb25maWdgIHRoZXJlXG4gICAqIOKAlCBpdCBpcyByZXNvbHZlZCBieSB0aGUgYnVpbGQsIGFmdGVyIHdoYXRldmVyIHB1dCB0aGUgYWRhcHRlciBpbiBwbGFjZS5cbiAgICovXG4gIHByaXZhdGUgYWRhcHRlclBhdGhFbnYoKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIE5FWFRfQURBUFRFUl9QQVRIOiByZXF1aXJlLnJlc29sdmUoXCJjZGstbmV4dGpzL2FkYXB0ZXJcIiwge1xuICAgICAgICAgIHBhdGhzOiBbdGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeV0sXG4gICAgICAgIH0pLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIGRlYnVnKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSBDb3VsZCBub3QgcmVzb2x2ZSBcImNkay1uZXh0anMvYWRhcHRlclwiIGZyb20gYCArXG4gICAgICAgICAgYCR7dGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeX07IGxlYXZpbmcgTkVYVF9BREFQVEVSX1BBVEggdW5zZXQsIHNvIGAgK1xuICAgICAgICAgIGBuZXh0LmNvbmZpZyBtdXN0IHNldCBcXGBhZGFwdGVyUGF0aFxcYC5gLFxuICAgICAgKTtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSBsb2NhbCBidWlsZCBjb21tYW5kIGluIHRoZSBzcGVjaWZpZWQgZGlyZWN0b3J5XG4gICAqL1xuICBwcml2YXRlIHJ1bk5leHRCdWlsZCgpIHtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGAke0xPR19QUkVGSVh9IFJ1bm5pbmc6IFwiJHt0aGlzLmJ1aWxkQ29tbWFuZH1cIiBpbiBkaXJlY3Rvcnk6ICR7dGhpcy5wcm9wcy5idWlsZERpcmVjdG9yeX1gLFxuICAgICk7XG5cbiAgICAvLyBDbGVhbiBleGlzdGluZyBjYWNoZSBkaXJlY3RvcnkgdG8gYXZvaWQgc3RhbGUgZGF0YSBmcm9tIHByZXZpb3VzIGJ1aWxkc1xuICAgIGlmIChleGlzdHNTeW5jKHRoaXMuaW5pdENhY2hlRGlyKSkge1xuICAgICAgcm1TeW5jKHRoaXMuaW5pdENhY2hlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICBkZWJ1ZyhgQ2xlYW5lZCBleGlzdGluZyBjYWNoZSBkaXJlY3Rvcnk6ICR7dGhpcy5pbml0Q2FjaGVEaXJ9YCk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKHRoaXMuYnVpbGRDb21tYW5kLCB7XG4gICAgICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgICAgICAgY3dkOiB0aGlzLnByb3BzLmJ1aWxkRGlyZWN0b3J5LFxuICAgICAgICBlbnY6IHtcbiAgICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgICBDREtfTkVYVEpTX0lOSVRfQ0FDSEVfRElSOiB0aGlzLmluaXRDYWNoZURpcixcbiAgICAgICAgICAuLi50aGlzLmFkYXB0ZXJQYXRoRW52KCksXG4gICAgICAgICAgLy8gYG9uQnVpbGRDb21wbGV0ZWAgcnVucyBpbnNpZGUgdGhpcyBwcm9jZXNzIGFuZCBjYW5ub3QgcmVhZCBDREtcbiAgICAgICAgICAvLyBwcm9wcywgc28gdGhlIHJlc29sdmVkIGdyb3VwcyB0cmF2ZWwgYXMgSlNPTi4gQWJzZW50IHdoZW4gbm90XG4gICAgICAgICAgLy8gc3BsaXR0aW5nLCB3aGljaCB0aGUgYWRhcHRlciByZWFkcyBhcyBcIm9uZSBkZXBsb3ltZW50IHJvb3RcIi5cbiAgICAgICAgICAuLi4odGhpcy5wcm9wcy5mdW5jdGlvbkdyb3Vwcz8ubGVuZ3RoXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBbRlVOQ1RJT05fR1JPVVBTX0VOVl9WQVJdOiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgIHRvRnVuY3Rpb25Hcm91cFNwZWNzKHRoaXMucHJvcHMuZnVuY3Rpb25Hcm91cHMpLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDoge30pLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTG9jYWwgYnVpbGQgZmFpbGVkOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQcmVwZW5kIGBwYXRjaC1mZXRjaC5qc2AgdG8gdGhlIGNsaWVudCBlbnRyeXBvaW50IGNodW5rcywgZm9yXG4gICAqIGBOZXh0anNHbG9iYWxGdW5jdGlvbnNgIG9ubHkuXG4gICAqXG4gICAqIFRoaXMgaXMgd2hhdCBtYWtlcyBQT1NUIHdvcmsgYXQgYWxsIG9uIHRoYXQgdHlwZS4gQ2xvdWRGcm9udCByZWFjaGVzIHRoZVxuICAgKiBzZXJ2ZXIgdGhyb3VnaCBhIExhbWJkYSBGdW5jdGlvbiBVUkwgd2l0aCBgQXV0aFR5cGU6IEFXU19JQU1gLCBzaWduZWQgYnkgYW5cbiAgICogb3JpZ2luIGFjY2VzcyBjb250cm9sLCBhbmQgQVdTIGRvY3VtZW50cyB0aGUgY29uc2VxdWVuY2U6IFwiSWYgeW91IHVzZSBQVVQgb3JcbiAgICogUE9TVCBtZXRob2RzIHdpdGggeW91ciBMYW1iZGEgZnVuY3Rpb24gVVJMLCB5b3VyIHVzZXJzIG11c3QgY29tcHV0ZSB0aGVcbiAgICogU0hBMjU2IG9mIHRoZSBib2R5IGFuZCBpbmNsdWRlIHRoZSBwYXlsb2FkIGhhc2ggdmFsdWUgb2YgdGhlIHJlcXVlc3QgYm9keSBpblxuICAgKiB0aGUgYHgtYW16LWNvbnRlbnQtc2hhMjU2YCBoZWFkZXIgd2hlbiBzZW5kaW5nIHRoZSByZXF1ZXN0IHRvIENsb3VkRnJvbnQuXG4gICAqIExhbWJkYSBkb2Vzbid0IHN1cHBvcnQgdW5zaWduZWQgcGF5bG9hZHMuXCJcbiAgICpcbiAgICogQ2xvdWRGcm9udCBzaWducyBHRVRzIGl0c2VsZiAoZW1wdHktYm9keSBoYXNoKSBidXQgd2lsbCBub3QgaGFzaCBhIGJvZHksIGFuZFxuICAgKiBhIGJyb3dzZXIgaGFzIG5vIHdheSB0byBhZGQgdGhhdCBoZWFkZXIgb24gaXRzIG93biwgc28gYW4gdW5wYXRjaGVkIGFwcFxuICAgKiBhbnN3ZXJzIGV2ZXJ5IHNlcnZlciBhY3Rpb24sIGZvcm0gc3VibWlzc2lvbiBhbmQgUE9TVCByb3V0ZSBoYW5kbGVyIHdpdGhcbiAgICogYDQwMyBJbnZhbGlkU2lnbmF0dXJlRXhjZXB0aW9uYCBiZWZvcmUgdGhlIHJlcXVlc3QgcmVhY2hlcyBOZXh0LmpzLiBUaGVcbiAgICogcGF0Y2ggaW5zdGFsbHMgYGZldGNoYC9gWE1MSHR0cFJlcXVlc3RgIHdyYXBwZXJzIHRoYXQgY29tcHV0ZSB0aGUgaGFzaC5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvcHJpdmF0ZS1jb250ZW50LXJlc3RyaWN0aW5nLWFjY2Vzcy10by1sYW1iZGEuaHRtbFxuICAgKi9cbiAgcHJpdmF0ZSBwYXRjaEZldGNoSW5DbGllbnRKcygpIHtcbiAgICBjb25zdCBzdGF0aWNDaHVua3NQYXRoID0gam9pbih0aGlzLmRvdE5leHRQYXRoLCBcInN0YXRpY1wiLCBcImNodW5rc1wiKTtcbiAgICBjb25zdCBjaHVua0ZpbGVzID0gcmVhZGRpclN5bmMoc3RhdGljQ2h1bmtzUGF0aCkuZmlsdGVyKFxuICAgICAgKGZpbGU6IHN0cmluZykgPT5cbiAgICAgICAgLy8gbWFpbi1hcHAtIGZvciB3ZWJwYWNrLCB0dXJib3BhY2stIGZvciB0dXJib1xuICAgICAgICBmaWxlLnN0YXJ0c1dpdGgoXCJtYWluLWFwcC1cIikgfHxcbiAgICAgICAgKGZpbGUuc3RhcnRzV2l0aChcInR1cmJvcGFjay1cIikgJiYgZmlsZS5lbmRzV2l0aChcIi5qc1wiKSksXG4gICAgKTtcblxuICAgIGlmIChjaHVua0ZpbGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gY2xpZW50IHNpZGUganMgZW50cnlwb2ludCBmaWxlcyBmb3VuZFwiKTtcbiAgICB9XG5cbiAgICAvLyBSZWFkIHRoZSBwYXRjaC1mZXRjaC5qcyBjb250ZW50XG4gICAgY29uc3QgcGF0Y2hGZXRjaFBhdGggPSBqb2luKF9fZGlybmFtZSwgXCJwYXRjaC1mZXRjaC5qc1wiKTtcbiAgICBjb25zdCBwYXRjaEZldGNoQ29udGVudCA9IHJlYWRGaWxlU3luYyhwYXRjaEZldGNoUGF0aCwgXCJ1dGYtOFwiKTtcblxuICAgIC8vIFByZXBlbmQgcGF0Y2gtZmV0Y2ggbG9naWMgdG8gZWFjaCBlbnRyeXBvaW50LCBvbmNlLiBOb3cgdGhhdCB0aGlzIHJ1bnNcbiAgICAvLyBvdXRzaWRlIGBydW5OZXh0QnVpbGRgLCB0aGUgc2FtZSBgLm5leHRgIGNhbiBiZSBzeW50aGVzaXplZCBtb3JlIHRoYW5cbiAgICAvLyBvbmNlIChgc2tpcEJ1aWxkOiB0cnVlYCwgYGNkayBzeW50aGAgdGhlbiBgY2RrIGRlcGxveWAsIGEgcmV0cmllZFxuICAgIC8vIGRlcGxveSksIGFuZCBwcmVwZW5kaW5nIHR3aWNlIHdvdWxkIHJlLXdyYXAgdGhlIHdyYXBwZXJzLlxuICAgIGZvciAoY29uc3QgY2h1bmtGaWxlIG9mIGNodW5rRmlsZXMpIHtcbiAgICAgIGNvbnN0IGNodW5rRmlsZVBhdGggPSBqb2luKHN0YXRpY0NodW5rc1BhdGgsIGNodW5rRmlsZSk7XG4gICAgICBjb25zdCBwYXRjaGVkQ29udGVudCA9IHBhdGNoQ2xpZW50Q2h1bmsoXG4gICAgICAgIHJlYWRGaWxlU3luYyhjaHVua0ZpbGVQYXRoLCBcInV0Zi04XCIpLFxuICAgICAgICBwYXRjaEZldGNoQ29udGVudCxcbiAgICAgICAgY2h1bmtGaWxlUGF0aCxcbiAgICAgICk7XG4gICAgICBpZiAocGF0Y2hlZENvbnRlbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBBbHJlYWR5IHBhdGNoZWQsIHNraXBwaW5nOiAke2NodW5rRmlsZVBhdGh9YCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgd3JpdGVGaWxlU3luYyhjaHVua0ZpbGVQYXRoLCBwYXRjaGVkQ29udGVudCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBwdWJsaWMgZGlyZWN0b3J5IGVudHJpZXMgZnJvbSBsb2NhbCBmaWxlc3lzdGVtXG4gICAqL1xuICBwcml2YXRlIGdldExvY2FsUHVibGljRGlyRW50cmllcygpOiBQdWJsaWNEaXJFbnRyeVtdIHtcbiAgICBjb25zdCBwdWJsaWNEaXJQYXRoID0gam9pbih0aGlzLnByb3BzLmJ1aWxkRGlyZWN0b3J5LCBcInB1YmxpY1wiKTtcbiAgICBpZiAoIWV4aXN0c1N5bmMocHVibGljRGlyUGF0aCkpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVhZGRpclN5bmMocHVibGljRGlyUGF0aCwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pLm1hcCgoZW50cnkpID0+ICh7XG4gICAgICBuYW1lOiBlbnRyeS5uYW1lLFxuICAgICAgaXNEaXJlY3Rvcnk6IGVudHJ5LmlzRGlyZWN0b3J5KCksXG4gICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0cmlwIHdoYXRldmVyIHBsYXRmb3JtLXNwZWNpZmljIFNoYXJwIGJpbmFyaWVzIGBuZXh0IGJ1aWxkYCdzIG91dHB1dCBmaWxlXG4gICAqIHRyYWNpbmcgc3RhZ2VkLCBzaW5jZSB0aGV5J3JlIHRoZSBob3N0J3MgKGUuZy4gbWFjT1MvZ2xpYmMpIHJhdGhlciB0aGFuIHRoZVxuICAgKiBkZXBsb3ltZW50IHRhcmdldCdzLCB0aGVuIGluc3RhbGwgdGhlIHRhcmdldCdzLiBTa2lwcGluZyB0aGlzIGlzIHNpbGVudDpcbiAgICogYGltYWdlT3B0aW1pemVyYCBjYXRjaGVzIHRoZSBsb2FkIGZhaWx1cmUgaW50ZXJuYWxseSBhbmQgcmV0dXJucyB0aGVcbiAgICogdW5vcHRpbWl6ZWQgb3JpZ2luYWwgd2l0aCBhbiBIVFRQIDIwMC5cbiAgICpcbiAgICogT25seSBhIHJvb3Qgd2l0aCBgc2hhcnBgIHN0YWdlZCBnZXRzIHRoZSBiaW5hcmllczogdGhlIGltYWdlIG9wdGltaXplclxuICAgKiBicmluZ3MgaXQgaW50byBgZGVmYXVsdGAsIHdoaWNoIHNlcnZlcyBldmVyeSBgL19uZXh0L2ltYWdlYCwgYW5kIGFub3RoZXJcbiAgICogZ3JvdXAgaGFzIGl0IG9ubHkgaWYgaXRzIG93biByb3V0ZXMgdXNlIGl0LiBTbyBvbmx5IGBkZWZhdWx0YCB3YXJucyB3aGVuXG4gICAqIGl0J3MgbWlzc2luZy5cbiAgICovXG4gIHByaXZhdGUgc3RhZ2VTaGFycEZvclRhcmdldChcbiAgICByb290OiBOZXh0anNEZXBsb3ltZW50Um9vdCxcbiAgICBwcm9qZWN0RGlyOiBzdHJpbmcsXG4gICAgcGxhdGZvcm06IHN0cmluZyxcbiAgKSB7XG4gICAgY29uc3Qgc2hhcnBTb3VyY2UgPSB0aGlzLnJlbW92ZUV4aXN0aW5nU2hhcnBCaW5hcmllcyhyb290LnBhdGgsIHByb2plY3REaXIpO1xuICAgIGlmICghc2hhcnBTb3VyY2UpIHtcbiAgICAgIGlmIChyb290Lm5hbWUgPT09IERFRkFVTFRfRlVOQ1RJT05fR1JPVVApIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IFwic2hhcnBcIiBub3QgZm91bmQgaW4gdGhlIHN0YWdlZCBidWlsZCBvdXRwdXQuIEFkZCBcInNoYXJwXCIgYXMgYSBkZXBlbmRlbmN5IG9mIHlvdXIgTmV4dC5qcyBhcHAgdG8gZW5hYmxlIGltYWdlIG9wdGltaXphdGlvbi5gLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmluc3RhbGxTaGFycFBhY2thZ2VzKFxuICAgICAgc2hhcnBCaW5hcnlEaXIocm9vdC5wYXRoKSxcbiAgICAgIHRoaXMuZ2V0U2hhcnBCaW5hcnlQYWNrYWdlcyhzaGFycFNvdXJjZSwgcGxhdGZvcm0pLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVjdXJzaXZlbHkgZmluZCBhbmQgcmVtb3ZlIGV4aXN0aW5nIFNoYXJwIHBsYXRmb3JtIGJpbmFyaWVzLlxuICAgKlxuICAgKiBgcm9vdGAgaXMgd2Fsa2VkIHdob2xlIHJhdGhlciB0aGFuIGp1c3QgaXRzIGBub2RlX21vZHVsZXNgOiB0aGUgc3RhZ2VkIHRyZWVcbiAgICogaXMga2V5ZWQgYnkgcmVwby1yb290LXJlbGF0aXZlIHBhdGgsIHNvIGluIGEgbW9ub3JlcG8gdGhlIGBub2RlX21vZHVsZXNgXG4gICAqIGhvbGRpbmcgYHNoYXJwYCBpcyBzZXZlcmFsIGRpcmVjdG9yaWVzIGRvd24uIHtAbGluayBpc1NoYXJwQmluYXJ5UGFja2FnZX0gaXNcbiAgICogd2hhdCBrZWVwcyB0aGF0IGZyb20gcmVhY2hpbmcgdGhlIGFwcCdzIG93biBvdXRwdXQg4oCUIHRoZSBzdGFnZWQgcm9vdCBob2xkc1xuICAgKiB0aGUgY29tcGlsZWQgYC5uZXh0YCBhcyB3ZWxsIGFzIHRoZSBkZXBlbmRlbmNpZXMuXG4gICAqXG4gICAqIEBwYXJhbSBwcm9qZWN0RGlyIHRoZSBhcHAncyBkaXJlY3RvcnkgaW5zaWRlIGByb290YCwgd2hpY2ggYG5leHRgIGlzXG4gICAqIHJlc29sdmVkIGZyb20uXG4gICAqIEByZXR1cm5zIHRoZSBzdGFnZWQgYHNoYXJwYCBKUyB3cmFwcGVyIHRvIGluc3RhbGwgbmV4dCB0bywgZm91bmQgaW4gdGhlIHNhbWVcbiAgICogd2FsazogYSByb290IGNhbiBiZSBodW5kcmVkcyBvZiBtZWdhYnl0ZXMsIGFuZCBlYWNoIGdyb3VwIGhhcyBvbmUuXG4gICAqL1xuICBwcml2YXRlIHJlbW92ZUV4aXN0aW5nU2hhcnBCaW5hcmllcyhcbiAgICByb290OiBzdHJpbmcsXG4gICAgcHJvamVjdERpcjogc3RyaW5nLFxuICApOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHNoYXJwQ2FuZGlkYXRlczogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIExpbmtzIGFyZSBsaXN0ZWQsIG5vdCBmb2xsb3dlZDogZXZlcnkgbGluayBpbiBhIHN0YWdlZCByb290IHBvaW50c1xuICAgIC8vIGluc2lkZSBpdCAoYHN0YWdlRmlsZXNgIGNvcGllcyB0aGUgb25lcyB0aGF0IGRvbid0KSwgc28gaXRzIHRhcmdldCBpc1xuICAgIC8vIHdhbGtlZCBhdCBpdHMgb3duIHBhdGggYW55d2F5LCBhbmQgZm9sbG93aW5nIHRoZW0gaXMgd2hhdCBsZXQgYVxuICAgIC8vIHdvcmtzcGFjZSBjeWNsZSBoYW5nIHRoZSBzeW50aC5cbiAgICBjb25zdCBhbGxFbnRyaWVzID0gbGlzdFRyZWUocm9vdCk7XG5cbiAgICAvLyBTeW1saW5rcyBhcmUgdW5saW5rZWQsIG5vdCBgcm1TeW5jYGVkLCBhbmQgdGhleSBnbyBmaXJzdC4gcG5wbSBwb2ludHNcbiAgICAvLyBzZXZlcmFsIGxpbmtzIGF0IG9uZSBzdG9yZSBkaXJlY3RvcnksIGFuZCBgcm1TeW5jKOKApiwgeyByZWN1cnNpdmU6IHRydWUsXG4gICAgLy8gZm9yY2U6IHRydWUgfSlgICpzaWxlbnRseSBuby1vcHMqIG9uIGEgc3ltbGluayB3aG9zZSB0YXJnZXQgaXMgYWxyZWFkeVxuICAgIC8vIGdvbmUg4oCUIGBmb3JjZWAgc3dhbGxvd3MgdGhlIEVOT0VOVCBpdHMgYHJtZGlyYCBnZXRzLiBSZW1vdmluZyBhIHN0b3JlXG4gICAgLy8gZGlyZWN0b3J5IGJlZm9yZSBpdHMgbGlua3MgdGhlcmVmb3JlIGxlZnQgZGFuZ2xpbmdcbiAgICAvLyBgQGltZy9zaGFycC1kYXJ3aW4tYXJtNjRgIGVudHJpZXMgaW4gdGhlIGFzc2V0LCB3aGljaCBpcyBhIGxhdGVudCBFTk9FTlRcbiAgICAvLyBpbiB3aGF0ZXZlciBuZXh0IGZvbGxvd3MgdGhlbSAoYHNoYXJwYCBkb2VzLCB3aGVuIGl0IGxvb2tzIGZvciBiaW5hcmllcykuXG4gICAgY29uc3Qgc3ltbGlua3M6IHN0cmluZ1tdID0gW107XG4gICAgY29uc3QgZGlyZWN0b3JpZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGFsbEVudHJpZXMpIHtcbiAgICAgIGlmIChlbnRyeS5pc0RpcmVjdG9yeSgpICYmIGVudHJ5Lm5hbWUgPT09IFwic2hhcnBcIikge1xuICAgICAgICBjb25zdCBwYXRoID0gam9pbihlbnRyeS5wYXJlbnRQYXRoLCBlbnRyeS5uYW1lKTtcbiAgICAgICAgaWYgKGV4aXN0c1N5bmMoam9pbihwYXRoLCBcInBhY2thZ2UuanNvblwiKSkpIHtcbiAgICAgICAgICBzaGFycENhbmRpZGF0ZXMucHVzaChwYXRoKTtcbiAgICAgICAgfVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmICghaXNTaGFycEJpbmFyeVBhY2thZ2UoZW50cnkucGFyZW50UGF0aCwgZW50cnkubmFtZSkpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGVudHJ5LnBhcmVudFBhdGgsIGVudHJ5Lm5hbWUpO1xuICAgICAgaWYgKGVudHJ5LmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgc3ltbGlua3MucHVzaChmdWxsUGF0aCk7XG4gICAgICB9IGVsc2UgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgZGlyZWN0b3JpZXMucHVzaChmdWxsUGF0aCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZGVidWcoXG4gICAgICBgJHtMT0dfUFJFRklYfSBSZW1vdmluZyAke3N5bWxpbmtzLmxlbmd0aH0gU2hhcnAgYmluYXJ5IHN5bWxpbmtzIGFuZCAke2RpcmVjdG9yaWVzLmxlbmd0aH0gZGlyZWN0b3JpZXNgLFxuICAgICk7XG5cbiAgICBmb3IgKGNvbnN0IHBhdGggb2Ygc3ltbGlua3MpIHtcbiAgICAgIHVubGlua1N5bmMocGF0aCk7XG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBVbmxpbmtlZDogJHtwYXRofWApO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IHBhdGggb2YgZGlyZWN0b3JpZXMpIHtcbiAgICAgIHJtU3luYyhwYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBSZW1vdmVkOiAke3BhdGh9YCk7XG4gICAgfVxuICAgIHJldHVybiBwaWNrU3RhZ2VkU2hhcnBQYWNrYWdlKFxuICAgICAgc2hhcnBDYW5kaWRhdGVzLFxuICAgICAgcmVzb2x2ZU5leHRTaGFycChwcm9qZWN0RGlyKSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgdGhlIGBAaW1nL3NoYXJwLTxwbGF0Zm9ybT5gIGFuZCBgQGltZy9zaGFycC1saWJ2aXBzLTxwbGF0Zm9ybT5gXG4gICAqIHZlcnNpb25zIHRvIGluc3RhbGwgZm9yIGEgZ2l2ZW4gcGxhdGZvcm0uXG4gICAqXG4gICAqIFRoZXNlIG11c3QgbWF0Y2ggdGhlIGBzaGFycGAgSlMgd3JhcHBlciB0aGF0IG91dHB1dCBmaWxlIHRyYWNpbmcgc3RhZ2VkOlxuICAgKiBgc2hhcnBgJ3MgYGxpYi9saWJ2aXBzLmpzYCBjb21wYXJlcyB0aGUgYmluYXJ5J3NcbiAgICogcmVwb3J0ZWQgbGlidmlwcyB2ZXJzaW9uIGFnYWluc3QgaXRzIG93biBgbWluaW11bUxpYnZpcHNWZXJzaW9uYCBhbmRcbiAgICogdGhyb3dzIGF0IGxvYWQgd2hlbiB0aGV5IGRpc2FncmVlLiBgc2hhcnBgIHBpbnMgYm90aCBpbiBpdHNcbiAgICogYG9wdGlvbmFsRGVwZW5kZW5jaWVzYCwgc28gdGhhdCBtYW5pZmVzdCBpcyB0aGUgYXV0aG9yaXRhdGl2ZSBzb3VyY2UuXG4gICAqL1xuICBwcml2YXRlIGdldFNoYXJwQmluYXJ5UGFja2FnZXMoXG4gICAgc2hhcnBTb3VyY2U6IHN0cmluZyxcbiAgICBwbGF0Zm9ybTogc3RyaW5nLFxuICApOiB7IG5hbWU6IHN0cmluZzsgdmVyc2lvbjogc3RyaW5nIH1bXSB7XG4gICAgLy8gT25seSBmb3IgYSBiaW5hcnkgdGhlIHN0YWdlZCBgc2hhcnBgIGRvZXMgbm90IHBpbi5cbiAgICBjb25zdCBmYWxsYmFjayA9IFtcbiAgICAgIHsgbmFtZTogYHNoYXJwLWxpYnZpcHMtJHtwbGF0Zm9ybX1gLCB2ZXJzaW9uOiBcIjEuMi40XCIgfSxcbiAgICAgIHsgbmFtZTogYHNoYXJwLSR7cGxhdGZvcm19YCwgdmVyc2lvbjogXCIwLjM0LjVcIiB9LFxuICAgIF07XG5cbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICByZWFkRmlsZVN5bmMoam9pbihzaGFycFNvdXJjZSwgXCJwYWNrYWdlLmpzb25cIiksIFwidXRmLThcIiksXG4gICAgKTtcbiAgICBjb25zdCBvcHRpb25hbERlcGVuZGVuY2llczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9XG4gICAgICBtYW5pZmVzdC5vcHRpb25hbERlcGVuZGVuY2llcyA/PyB7fTtcblxuICAgIHJldHVybiBmYWxsYmFjay5tYXAoKHBrZykgPT4ge1xuICAgICAgY29uc3QgdmVyc2lvbiA9IG9wdGlvbmFsRGVwZW5kZW5jaWVzW2BAaW1nLyR7cGtnLm5hbWV9YF07XG4gICAgICBpZiAoIXZlcnNpb24pIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IHNoYXJwQCR7bWFuaWZlc3QudmVyc2lvbn0gZG9lcyBub3QgcGluIFwiQGltZy8ke3BrZy5uYW1lfVwiOyBmYWxsaW5nIGJhY2sgdG8gJHtwa2cudmVyc2lvbn0uYCxcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHBrZztcbiAgICAgIH1cbiAgICAgIHJldHVybiB7IG5hbWU6IHBrZy5uYW1lLCB2ZXJzaW9uIH07XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRG93bmxvYWQgKHdpdGggY2FjaGluZykgYW5kIGV4dHJhY3QgU2hhcnAncyBwbGF0Zm9ybS1zcGVjaWZpYyBiaW5hcnlcbiAgICogcGFja2FnZXMgaW50byBgaW1nUGF0aGAuXG4gICAqL1xuICBwcml2YXRlIGluc3RhbGxTaGFycFBhY2thZ2VzKFxuICAgIGltZ1BhdGg6IHN0cmluZyxcbiAgICBwYWNrYWdlczogeyBuYW1lOiBzdHJpbmc7IHZlcnNpb246IHN0cmluZyB9W10sXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IGNhY2hlRGlyID0gam9pbih0bXBkaXIoKSwgXCJjZGstbmV4dGpzLXNoYXJwLWNhY2hlXCIpO1xuICAgIG1rZGlyU3luYyhjYWNoZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICBmb3IgKGNvbnN0IHBrZyBvZiBwYWNrYWdlcykge1xuICAgICAgY29uc3QgdGFyZ2V0RGlyID0gam9pbihpbWdQYXRoLCBwa2cubmFtZSk7XG4gICAgICBjb25zdCB1cmwgPSBgaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGltZy8ke3BrZy5uYW1lfS8tLyR7cGtnLm5hbWV9LSR7cGtnLnZlcnNpb259LnRnemA7XG5cbiAgICAgIC8vIENyZWF0ZSBhIGNvbnNpc3RlbnQgZmlsZW5hbWUgYmFzZWQgb24gcGFja2FnZSBuYW1lIGFuZCB2ZXJzaW9uXG4gICAgICBjb25zdCBjYWNoZUZpbGVOYW1lID0gYCR7cGtnLm5hbWV9LSR7cGtnLnZlcnNpb259LnRnemA7XG4gICAgICBjb25zdCBjYWNoZWRGaWxlID0gam9pbihjYWNoZURpciwgY2FjaGVGaWxlTmFtZSk7XG5cbiAgICAgIC8vIENoZWNrIGlmIHdlIGFscmVhZHkgaGF2ZSBhIHZhbGlkIHBhY2thZ2UgY2FjaGVkOyByZS1kb3dubG9hZCBpZlxuICAgICAgLy8gYSBwcmV2aW91cyBydW4gbGVmdCBiZWhpbmQgYSB0cnVuY2F0ZWQvY29ycnVwdCBkb3dubG9hZFxuICAgICAgaWYgKGV4aXN0c1N5bmMoY2FjaGVkRmlsZSkgJiYgdGhpcy5pc0NhY2hlZEZpbGVWYWxpZChjYWNoZWRGaWxlKSkge1xuICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICBgJHtMT0dfUFJFRklYfSBVc2luZyBjYWNoZWQgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn0gZnJvbSAke2NhY2hlZEZpbGV9YCxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlYnVnKGAke0xPR19QUkVGSVh9IERvd25sb2FkaW5nICR7cGtnLm5hbWV9QCR7cGtnLnZlcnNpb259Li4uYCk7XG5cbiAgICAgICAgLy8gRG93bmxvYWQgdG8gYSBwcm9jZXNzLXVuaXF1ZSB0ZW1wIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LFxuICAgICAgICAvLyB0aGVuIGF0b21pY2FsbHkgcmVuYW1lIGl0IG9udG8gdGhlIHNoYXJlZCBjYWNoZSBwYXRoLiBDb25jdXJyZW50XG4gICAgICAgIC8vIHN5bnRoIHByb2Nlc3NlcyAoZS5nLiBUdXJib3JlcG8gcnVubmluZyBtdWx0aXBsZSBgY2RrYCBjb21tYW5kcylcbiAgICAgICAgLy8gc2hhcmUgdGhpcyBjYWNoZSBkaXIsIHNvIHdyaXRpbmcgZGlyZWN0bHkgdG8gYGNhY2hlZEZpbGVgIHJpc2tzXG4gICAgICAgIC8vIGFub3RoZXIgcHJvY2VzcyBleHRyYWN0aW5nIGEgaGFsZi13cml0dGVuIGZpbGUuIFJlbmFtaW5nIHdpdGhpblxuICAgICAgICAvLyB0aGUgc2FtZSBmaWxlc3lzdGVtIGlzIGF0b21pYywgc28gcmVhZGVycyBvbmx5IGV2ZXIgc2VlIGFcbiAgICAgICAgLy8gY29tcGxldGUgZmlsZSwgd2hpY2hldmVyIHByb2Nlc3Mgd2lucyB0aGUgcmFjZS5cbiAgICAgICAgY29uc3QgdGVtcEZpbGUgPSBqb2luKFxuICAgICAgICAgIGNhY2hlRGlyLFxuICAgICAgICAgIGAke2NhY2hlRmlsZU5hbWV9LiR7cHJvY2Vzcy5waWR9LSR7cmFuZG9tQnl0ZXMoNikudG9TdHJpbmcoXCJoZXhcIil9LnRtcGAsXG4gICAgICAgICk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gLS1mYWlsIG1ha2VzIGN1cmwgZXhpdCBub24temVybyBvbiBIVFRQIGVycm9ycyBhbmQgLS1yZXRyeVxuICAgICAgICAgIC8vIGhhbmRsZXMgdHJhbnNpZW50IGNvbm5lY3Rpb24gZHJvcHMgc28gYSBwYXJ0aWFsIHRyYW5zZmVyXG4gICAgICAgICAgLy8gaXNuJ3QgY2FjaGVkIGFzIHZhbGlkLlxuICAgICAgICAgIGV4ZWNGaWxlU3luYyhcbiAgICAgICAgICAgIFwiY3VybFwiLFxuICAgICAgICAgICAgW1xuICAgICAgICAgICAgICBcIi1MXCIsXG4gICAgICAgICAgICAgIFwiLS1mYWlsXCIsXG4gICAgICAgICAgICAgIFwiLS1yZXRyeVwiLFxuICAgICAgICAgICAgICBcIjNcIixcbiAgICAgICAgICAgICAgXCItLXJldHJ5LWRlbGF5XCIsXG4gICAgICAgICAgICAgIFwiMVwiLFxuICAgICAgICAgICAgICBcIi1vXCIsXG4gICAgICAgICAgICAgIHRlbXBGaWxlLFxuICAgICAgICAgICAgICB1cmwsXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgeyBzdGRpbzogXCJwaXBlXCIgfSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKCF0aGlzLmlzQ2FjaGVkRmlsZVZhbGlkKHRlbXBGaWxlKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICBgRG93bmxvYWRlZCBmaWxlIGZvciAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSBpcyBlbXB0eSBvciBtaXNzaW5nOiAke3RlbXBGaWxlfWAsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlbmFtZVN5bmModGVtcEZpbGUsIGNhY2hlZEZpbGUpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIHJtU3luYyh0ZW1wRmlsZSwgeyBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlYnVnKFxuICAgICAgICAgIGAke0xPR19QUkVGSVh9IENhY2hlZCAke3BrZy5uYW1lfUAke3BrZy52ZXJzaW9ufSB0byAke2NhY2hlZEZpbGV9YCxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgbWtkaXJTeW5jKHRhcmdldERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBleGVjRmlsZVN5bmMoXG4gICAgICAgIFwidGFyXCIsXG4gICAgICAgIFtcIi14emZcIiwgY2FjaGVkRmlsZSwgXCItQ1wiLCB0YXJnZXREaXIsIFwiLS1zdHJpcC1jb21wb25lbnRzPTFcIl0sXG4gICAgICAgIHsgc3RkaW86IFwicGlwZVwiIH0sXG4gICAgICApO1xuXG4gICAgICBkZWJ1ZyhgJHtMT0dfUFJFRklYfSBJbnN0YWxsZWQgJHtwa2cubmFtZX1AJHtwa2cudmVyc2lvbn1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHRoYXQgYSBjYWNoZWQgU2hhcnAgYmluYXJ5IGFyY2hpdmUgaXMgbm9uLWVtcHR5LiBHdWFyZHMgYWdhaW5zdFxuICAgKiBhIHRydW5jYXRlZC9jb3JydXB0IGRvd25sb2FkIChlLmcuIGZyb20gYSBkcm9wcGVkIGNvbm5lY3Rpb24pIGJlaW5nXG4gICAqIHJldXNlZCBhY3Jvc3Mgc3ludGggb3BlcmF0aW9ucy5cbiAgICovXG4gIHByaXZhdGUgaXNDYWNoZWRGaWxlVmFsaWQoZmlsZVBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gc3RhdFN5bmMoZmlsZVBhdGgpLnNpemUgPiAwO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFdoYXQgdHJhdmVscyB0byB0aGUgYWRhcHRlciBpbiB7QGxpbmsgRlVOQ1RJT05fR1JPVVBTX0VOVl9WQVJ9LCBhbmQgd2hhdCBpdFxuICogcmVjb3JkcyBiYWNrIGFzIGBBZGFwdGVyTWFuaWZlc3QuZnVuY3Rpb25Hcm91cHNgLlxuICovXG5mdW5jdGlvbiB0b0Z1bmN0aW9uR3JvdXBTcGVjcyhcbiAgZ3JvdXBzOiBOZXh0anNGdW5jdGlvbkdyb3VwUm91dGVzW10sXG4pOiBGdW5jdGlvbkdyb3VwU3BlY1tdIHtcbiAgcmV0dXJuIGdyb3Vwcy5tYXAoKHsgbmFtZSwgcm91dGVzIH0pID0+ICh7IG5hbWUsIHJvdXRlcyB9KSk7XG59XG5cbi8qKiBgZ3JvdXBzYCBpbiBhIGNhbm9uaWNhbCBvcmRlciwgZm9yIGNvbXBhcmluZyB0d28gb2YgdGhlbS4gKi9cbmZ1bmN0aW9uIHNvcnRlZEdyb3VwU3BlY3MoXG4gIGdyb3VwczogcmVhZG9ubHkgRnVuY3Rpb25Hcm91cFNwZWNbXSB8IHVuZGVmaW5lZCxcbik6IEZ1bmN0aW9uR3JvdXBTcGVjW10gfCB1bmRlZmluZWQge1xuICByZXR1cm4gZ3JvdXBzXG4gICAgPy5tYXAoKHsgbmFtZSwgcm91dGVzIH0pID0+ICh7IG5hbWUsIHJvdXRlczogWy4uLnJvdXRlc10uc29ydCgpIH0pKVxuICAgIC5zb3J0KChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gLTEgOiAxKSk7XG59XG5cbi8qKlxuICogUGljayB0aGUgc3RhZ2VkIGBzaGFycGAgSlMgd3JhcHBlciBvdXQgb2YgZXZlcnkgY29weSBmb3VuZCBpbiB0aGUgdHJlZS5cbiAqXG4gKiBVbmxpa2UgYSBzdGFuZGFsb25lIGJ1aWxkIHRoZXJlIGlzIG5vIHNpbmdsZSBgbm9kZV9tb2R1bGVzYCB0byBsb29rIGluOiB0aGVcbiAqIHRyZWUgbWlycm9ycyByZXBvLXJvb3QtcmVsYXRpdmUgcGF0aHMsIHNvIHRoZSBzZWFyY2ggaXMgYnkgZGlyZWN0b3J5IG5hbWUuXG4gKlxuICogQW4gYXBwIGNhbiBoYXZlIHR3byBgc2hhcnBgIGNvcGllcyBhdCBkaWZmZXJlbnQgdmVyc2lvbnMgKGl0cyBvd24sIGhvaXN0ZWQsXG4gKiBhbmQgbmV4dCdzLCBuZXN0ZWQgdW5kZXIgYG5leHQvbm9kZV9tb2R1bGVzYCksIGFuZCBldmVyeSBiaW5hcnkgZ29lcyBpbnRvIHRoZVxuICogb25lIHJvb3QgYEBpbWdgLCBzbyB0aGUgY29weSBwaW5uaW5nIHRoZW0gaGFzIHRvIGJlIHRoZSBvbmUgYG5leHRgJ3MgaW1hZ2VcbiAqIG9wdGltaXplciBsb2FkczogYG5leHRTaGFycGAsIHdoZW4ge0BsaW5rIHJlc29sdmVOZXh0U2hhcnB9IGZvdW5kIGl0LiBPdGhlcndpc2VcbiAqIHNob3J0ZXN0IHBhdGggd2lucyBhcyB0aGUgY2xvc2VzdCB0byBhIGhvaXN0ZWQgaW5zdGFsbCwgc29ydGVkIGZvclxuICogZGV0ZXJtaW5pc20uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwaWNrU3RhZ2VkU2hhcnBQYWNrYWdlKFxuICBjYW5kaWRhdGVzOiBzdHJpbmdbXSxcbiAgbmV4dFNoYXJwPzogc3RyaW5nLFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgdXNlZCA9XG4gICAgbmV4dFNoYXJwICYmXG4gICAgY2FuZGlkYXRlcy5maW5kKChjYW5kaWRhdGUpID0+XG4gICAgICBuZXh0U2hhcnAuc3RhcnRzV2l0aChyZWFscGF0aFN5bmMoY2FuZGlkYXRlKSArIHNlcCksXG4gICAgKTtcbiAgaWYgKHVzZWQpIHtcbiAgICByZXR1cm4gdXNlZDtcbiAgfVxuICBjYW5kaWRhdGVzLnNvcnQoKGEsIGIpID0+IGEubGVuZ3RoIC0gYi5sZW5ndGggfHwgYS5sb2NhbGVDb21wYXJlKGIpKTtcbiAgaWYgKGNhbmRpZGF0ZXMubGVuZ3RoID4gMSkge1xuICAgIGRlYnVnKFxuICAgICAgYCR7TE9HX1BSRUZJWH0gTXVsdGlwbGUgc3RhZ2VkIFwic2hhcnBcIiBjb3BpZXM7IHVzaW5nICR7Y2FuZGlkYXRlc1swXX1gLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZXNbMF07XG59XG5cbi8qKlxuICogVGhlIHJlYWwgcGF0aCBvZiB0aGUgYHNoYXJwYCBlbnRyeSBwb2ludCB0aGUgc3RhZ2VkIGBuZXh0YCByZXNvbHZlcyBmcm9tXG4gKiBgcHJvamVjdERpcmAsIGB1bmRlZmluZWRgIHdoZW4gZWl0aGVyIGRvZXMgbm90IHJlc29sdmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlTmV4dFNoYXJwKHByb2plY3REaXI6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHRyeSB7XG4gICAgLy8gVGhlIGFuY2hvciBmaWxlIG5lZWRuJ3QgZXhpc3Q7IGBjcmVhdGVSZXF1aXJlYCBvbmx5IHJlYWRzIGl0cyBkaXJlY3RvcnkuXG4gICAgY29uc3QgbmV4dFBhY2thZ2UgPSBjcmVhdGVSZXF1aXJlKFxuICAgICAgam9pbihwcm9qZWN0RGlyLCBcImNkay1uZXh0anMtbmV4dC1yZXNvbHZlci5janNcIiksXG4gICAgKS5yZXNvbHZlKFwibmV4dC9wYWNrYWdlLmpzb25cIik7XG4gICAgcmV0dXJuIGNyZWF0ZVJlcXVpcmUobmV4dFBhY2thZ2UpLnJlc29sdmUoXCJzaGFycFwiKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIGVudHJ5IGBuYW1lYCBpbiBgcGFyZW50UGF0aGAgaXMgYW4gYEBpbWcvc2hhcnAtKmAgcGxhdGZvcm0gYmluYXJ5XG4gKiBwYWNrYWdlLCBvciBwbnBtJ3Mgc3RvcmUgZW50cnkgZm9yIG9uZS5cbiAqXG4gKiBUaGUgbmFtZSBhbG9uZSBpcyBub3QgZW5vdWdoIHRvIGRlbGV0ZSBhIGRpcmVjdG9yeSBieS4gQSByb3V0ZSBzZWdtZW50IGNhbGxlZFxuICogYHNoYXJwLWVkZ2VzYCBzdGFnZXMgYC5uZXh0L3NlcnZlci9hcHAvc2hhcnAtZWRnZXMvYCwgYW5kIHJlbW92aW5nIGl0IGxlZnQgdGhlXG4gKiBtYW5pZmVzdCBsaXN0aW5nIGFuIGVudHJ5cG9pbnQgdGhhdCBpcyBubyBsb25nZXIgb24gZGlzayDigJQgZXZlcnkgcmVxdWVzdCB0b1xuICogdGhhdCByb3V0ZSA1MDBpbmcgd2l0aCBcIkNvdWxkIG5vdCBsb2FkIHRoZSBlbnRyeXBvaW50XCIuIE5vciBpcyBcImEgYHNoYXJwLWBcbiAqIHBhY2thZ2VcIjogYHNoYXJwLWljb2AgYW5kIGBzaGFycC1waGFzaGAgYXJlIHVucmVsYXRlZCBkZXBlbmRlbmNpZXMsIGFuZFxuICogcmVtb3ZpbmcgdGhlbSBmYWlsZWQgdGhlIGFwcCBhdCBydW50aW1lIHdpdGggTU9EVUxFX05PVF9GT1VORC4gU28gYm90aCB0aGVcbiAqIHNjb3BlIGFuZCB0aGUgcGxhY2UgaGF2ZSB0byBtYXRjaDpcbiAqXG4gKiAtIGBub2RlX21vZHVsZXMvQGltZy9zaGFycC3igKZgLCB3aGVyZSBldmVyeSBwbGF0Zm9ybSBiaW5hcnkgYWN0dWFsbHkgbGl2ZXNcbiAqIC0gYG5vZGVfbW9kdWxlcy8ucG5wbS9AaW1nK3NoYXJwLeKApkAwLjM1LjRgLCBwbnBtJ3Mgc3RvcmUsIHdob3NlIGVudHJpZXMgYXJlXG4gKiAgIGFsc28gd2hhdCB0aGUgYEBpbWdgIGxpbmtzIHBvaW50IGF0IChgc2hhcnAtbGlidmlwcy3igKZgIG1hdGNoZXMgdGhlIHNhbWUgd2F5KVxuICpcbiAqIFRoZSBgbm9kZV9tb2R1bGVzYCBzZWdtZW50IGlzIHJlcXVpcmVkIGFzIHdlbGwsIHNvIGFuIGFwcCBkaXJlY3RvcnkgdGhhdFxuICogaGFwcGVucyB0byBiZSBjYWxsZWQgYEBpbWdgIG9yIGAucG5wbWAgaXMgc3RpbGwgbGVmdCBhbG9uZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2hhcnBCaW5hcnlQYWNrYWdlKFxuICBwYXJlbnRQYXRoOiBzdHJpbmcsXG4gIG5hbWU6IHN0cmluZyxcbik6IGJvb2xlYW4ge1xuICBjb25zdCBzZWdtZW50cyA9IHBhcmVudFBhdGguc3BsaXQoc2VwKTtcbiAgY29uc3QgcGFyZW50ID0gc2VnbWVudHNbc2VnbWVudHMubGVuZ3RoIC0gMV07XG4gIGNvbnN0IHNjb3BlZCA9XG4gICAgKHBhcmVudCA9PT0gXCJAaW1nXCIgJiYgbmFtZS5zdGFydHNXaXRoKFwic2hhcnAtXCIpKSB8fFxuICAgIChwYXJlbnQgPT09IFwiLnBucG1cIiAmJiBuYW1lLnN0YXJ0c1dpdGgoXCJAaW1nK3NoYXJwLVwiKSk7XG4gIHJldHVybiBzY29wZWQgJiYgc2VnbWVudHMuaW5jbHVkZXMoXCJub2RlX21vZHVsZXNcIik7XG59XG5cbi8qKlxuICogV2hlcmUgdGhlIHRhcmdldCdzIGBAaW1nL3NoYXJwLSpgIGJpbmFyaWVzIGdvOiBgPHJvb3Q+L25vZGVfbW9kdWxlcy9AaW1nYC5cbiAqXG4gKiBOb3QgbmV4dCB0byB0aGUgc3RhZ2VkIGBzaGFycGAgcGFja2FnZS4gVW5kZXIgcG5wbSB0aGF0IGlzXG4gKiBgbm9kZV9tb2R1bGVzLy5wbnBtL3NoYXJwQHgvbm9kZV9tb2R1bGVzL0BpbWdgLCB3aGljaCBvbmx5IHRoZSBzdG9yZSBjb3B5IG9mXG4gKiBgc2hhcnBgIHJlc29sdmVzIGZyb206IGEgZGVyZWZlcmVuY2VkIGxpbmsgdG8gYHNoYXJwYCAoYSBjb3B5IGF0XG4gKiBgYXBwL25vZGVfbW9kdWxlcy9zaGFycGAsIHNheSkgbG9va3MgZm9yIGBAaW1nYCBmcm9tIGl0cyBvd24gcGF0aCBhbmQgd2Fsa3NcbiAqIHVwLCBuZXZlciBpbnRvIHRoZSBzdG9yZS4gQm90aCB0aGUgRnVuY3Rpb25zIHppcCAoYHppcERpcmVjdG9yeWApIGFuZCB0aGVcbiAqIENvbnRhaW5lcnMgYENPUFlgIGtlZXAgdGhlIGxpbmtzLCBzbyBpdCBpcyB0aGUgc3RvcmUgY29weSB0aGF0IGxvYWRzLCBhbmQgaXRzXG4gKiB3YWxrIHVwIHJlYWNoZXMgdGhlIHJvb3QgYG5vZGVfbW9kdWxlc2AgdG9vLCBzbyBpdCBzZXJ2ZXMgZWl0aGVyIGxheW91dC4gSXRcbiAqIGlzIGFsc28gd2hlcmUgbWFpbiBpbnN0YWxsZWQgdGhlbS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNoYXJwQmluYXJ5RGlyKHJvb3Q6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBqb2luKHJvb3QsIFwibm9kZV9tb2R1bGVzXCIsIFwiQGltZ1wiKTtcbn1cblxuLyoqXG4gKiBFdmVyeSBlbnRyeSB1bmRlciBgcm9vdGAsIGxpbmtzIGxpc3RlZCBidXQgbm90IGZvbGxvd2VkLlxuICpcbiAqIEFuIGV4cGxpY2l0IHdhbGsgcmF0aGVyIHRoYW4gYHJlYWRkaXJTeW5jKHsgcmVjdXJzaXZlOiB0cnVlIH0pYCwgd2hpY2ggb25cbiAqIE5vZGUgMjQgZGVzY2VuZHMgaW50byBzeW1saW5rZWQgZGlyZWN0b3JpZXMgaXRzZWxmIGFuZCBzbyBuZXZlciByZXR1cm5zIG9uIGFcbiAqIGN5Y2xlIOKAlCB0d28gd29ya3NwYWNlIHBhY2thZ2VzIHRoYXQgbGluayBlYWNoIG90aGVyLCB3aGljaCBpcyBob3cgcG5wbSB3aXJlcyBhXG4gKiBtb25vcmVwby5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3RUcmVlKHJvb3Q6IHN0cmluZyk6IERpcmVudFtdIHtcbiAgY29uc3QgZW50cmllczogRGlyZW50W10gPSBbXTtcbiAgY29uc3QgcGVuZGluZyA9IFtyb290XTtcbiAgZm9yIChsZXQgZGlyID0gcGVuZGluZy5wb3AoKTsgZGlyICE9PSB1bmRlZmluZWQ7IGRpciA9IHBlbmRpbmcucG9wKCkpIHtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIHJlYWRkaXJTeW5jKGRpciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pKSB7XG4gICAgICBlbnRyaWVzLnB1c2goZW50cnkpO1xuICAgICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgcGVuZGluZy5wdXNoKGpvaW4oZGlyLCBlbnRyeS5uYW1lKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBlbnRyaWVzO1xufVxuXG4vKipcbiAqIFdyaXRlIHtAbGluayBQVUJMSUNfRklMRVNfRklMRV9OQU1FfSBpbnRvIGEgZGVwbG95bWVudCByb290J3MgcnVudGltZVxuICogZGlyZWN0b3J5OiBldmVyeSBmaWxlIHVuZGVyIGBwdWJsaWNEaXJgLCBsaXN0ZWQgdGhlIHdheSB0aGUgcnVudGltZSB3b3VsZFxuICogbGlzdCBpdCBvZmYgZGlzayAoYHJlYWRQdWJsaWNGaWxlc2A6IHN5bWxpbmtzIGZvbGxvd2VkLCBgL2Atc2VwYXJhdGVkLFxuICogc29ydGVkKS4gQW4gYXBwIHdpdGhvdXQgYHB1YmxpYy9gIGdldHMgYFtdYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdyaXRlUHVibGljRmlsZUxpc3QocnVudGltZURpcjogc3RyaW5nLCBwdWJsaWNEaXI6IHN0cmluZykge1xuICB3cml0ZUZpbGVTeW5jKFxuICAgIGpvaW4ocnVudGltZURpciwgUFVCTElDX0ZJTEVTX0ZJTEVfTkFNRSksXG4gICAgSlNPTi5zdHJpbmdpZnkocmVhZFB1YmxpY0ZpbGVzKHB1YmxpY0RpcikpLFxuICApO1xufVxuXG4vKipcbiAqIFRvdGFsIGJ5dGVzIG9mIGEgdHJlZSBhcyBpdHMgZGVwbG95bWVudCB6aXAgc3RvcmVzIGl0LiBgemlwRGlyZWN0b3J5YCBrZWVwc1xuICogbGlua3MgYXMgbGlua3MsIHNvIGVhY2ggY291bnRzIGFzIGl0cyB0YXJnZXQgcGF0aCwgbm90IGFzIHRoZSB0YXJnZXQsIHdoaWNoXG4gKiBpcyB3YWxrZWQgYXQgaXRzIG93biBwYXRoIGFueXdheSAoZXZlcnkgbGluayBpbiBhIHN0YWdlZCByb290IHBvaW50cyBpbnNpZGVcbiAqIGl0KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0b3JlZFNpemUocm9vdDogc3RyaW5nKTogbnVtYmVyIHtcbiAgbGV0IGJ5dGVzID0gMDtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBsaXN0VHJlZShyb290KSkge1xuICAgIGlmICghZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgYnl0ZXMgKz0gbHN0YXRTeW5jKGpvaW4oZW50cnkucGFyZW50UGF0aCwgZW50cnkubmFtZSkpLnNpemU7XG4gICAgfVxuICB9XG4gIHJldHVybiBieXRlcztcbn1cblxuLyoqXG4gKiBgY2h1bmtgIHdpdGggYHBhdGNoYCBwcmVwZW5kZWQgYmV0d2VlbiBgUEFUQ0hfRkVUQ0hfTUFSS0VSYCBhbmRcbiAqIGBQQVRDSF9GRVRDSF9FTkRfTUFSS0VSYCwgb3IgYHVuZGVmaW5lZGAgd2hlbiBpdCBhbHJlYWR5IGNhcnJpZXMgdGhpcyBleGFjdFxuICogcGF0Y2guXG4gKlxuICogVGhlIG9wZW5pbmcgbWFya2VyIGNhcnJpZXMgYSBoYXNoIG9mIHRoZSBwYXRjaCwgc28gYSBjaHVuayBwYXRjaGVkIGJ5IGFcbiAqIGNkay1uZXh0anMgd2hvc2UgYHBhdGNoLWZldGNoLmpzYCBkaWZmZXJzIChhbiB1cGdyYWRlLCBvdmVyIGEgYC5uZXh0YCByZXVzZWRcbiAqIHdpdGggYHNraXBCdWlsZDogdHJ1ZWApIGlzIG5vdCBtaXN0YWtlbiBmb3IgY3VycmVudDogdGhlIG9sZCBwYXRjaCBpcyBjdXQgb2ZmXG4gKiBhdCBpdHMgZW5kIG1hcmtlciBhbmQgdGhpcyBvbmUgcHV0IGluIGl0cyBwbGFjZSwgcmF0aGVyIHRoYW4gdGhlIG9sZCBvbmVcbiAqIHNoaXBwaW5nIG9yIGJvdGggc3RhY2tpbmcgdXAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXRjaENsaWVudENodW5rKFxuICBjaHVuazogc3RyaW5nLFxuICBwYXRjaDogc3RyaW5nLFxuICBjaHVua1BhdGg6IHN0cmluZyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGhhc2ggPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShwYXRjaCkuZGlnZXN0KFwiaGV4XCIpLnNsaWNlKDAsIDE2KTtcbiAgY29uc3Qgb3BlbiA9IGAke1BBVENIX0ZFVENIX01BUktFUn0gJHtoYXNofSAqL2A7XG4gIGlmIChjaHVuay5zdGFydHNXaXRoKGAke29wZW59XFxuYCkpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGxldCBvcmlnaW5hbCA9IGNodW5rO1xuICBpZiAoY2h1bmsuc3RhcnRzV2l0aChQQVRDSF9GRVRDSF9NQVJLRVIpKSB7XG4gICAgY29uc3QgZW5kID0gY2h1bmsuaW5kZXhPZihgXFxuJHtQQVRDSF9GRVRDSF9FTkRfTUFSS0VSfVxcbmApO1xuICAgIGlmIChlbmQgPT09IC0xKSB7XG4gICAgICAvLyBPbmx5IGEgcHJlLXJlbGVhc2UgY2RrLW5leHRqcyB3cm90ZSB0aGUgbWFya2VyIHdpdGhvdXQgYW4gZW5kLCBhbmRcbiAgICAgIC8vIHdoZXJlIGl0cyBwYXRjaCBzdG9wcyBjYW5ub3QgYmUgdG9sZCBmcm9tIHRoZSBjaHVuaydzIG93biBjb2RlLlxuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtMT0dfUFJFRklYfSAke2NodW5rUGF0aH0gY2FycmllcyBhIGNkay1uZXh0anMgZmV0Y2ggcGF0Y2ggdGhpcyBgICtcbiAgICAgICAgICBgdmVyc2lvbiBjYW5ub3QgcmVwbGFjZS4gUmUtcnVuIFxcYG5leHQgYnVpbGRcXGAgdG8gcmVnZW5lcmF0ZSBpdC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgb3JpZ2luYWwgPSBjaHVuay5zbGljZShlbmQgKyBQQVRDSF9GRVRDSF9FTkRfTUFSS0VSLmxlbmd0aCArIDIpO1xuICB9XG4gIHJldHVybiBgJHtvcGVufVxcbiR7cGF0Y2h9XFxuJHtQQVRDSF9GRVRDSF9FTkRfTUFSS0VSfVxcbiR7b3JpZ2luYWx9YDtcbn1cbiJdfQ==