cdk-nextjs 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/.jsii +2404 -2723
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1681 -1930
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
  7. package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
  8. package/docs/adapter-runtime.md +185 -0
  9. package/docs/breaking-changes.md +667 -4
  10. package/docs/caching-guide.md +156 -112
  11. package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
  12. package/docs/development-guide.md +1 -1
  13. package/docs/harness-coverage.md +598 -0
  14. package/docs/init-cache-deployment.md +32 -1
  15. package/docs/next-build-output-guide.md +30 -20
  16. package/examples/README.md +5 -1
  17. package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
  18. package/lib/adapter/__fixtures__/app-playground.json +4917 -0
  19. package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
  20. package/lib/adapter/adapter.mjs +1551 -185
  21. package/lib/adapter/adapter.test.js +106 -0
  22. package/lib/adapter/aws-cache-store.d.ts +489 -0
  23. package/lib/adapter/aws-cache-store.js +1004 -0
  24. package/lib/adapter/aws-cache-store.test.d.ts +1 -0
  25. package/lib/adapter/aws-cache-store.test.js +361 -0
  26. package/lib/adapter/build-outputs.d.ts +80 -0
  27. package/lib/adapter/build-outputs.js +857 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +863 -0
  30. package/lib/adapter/cache-handler.d.ts +9 -2
  31. package/lib/adapter/cache-handler.js +72 -96
  32. package/lib/adapter/cache-handler.mjs +18956 -17774
  33. package/lib/adapter/cache-handler.test.js +263 -31
  34. package/lib/adapter/cache-kinds.d.ts +32 -0
  35. package/lib/adapter/cache-kinds.js +35 -0
  36. package/lib/adapter/cache-kinds.test.d.ts +1 -0
  37. package/lib/adapter/cache-kinds.test.js +69 -0
  38. package/lib/adapter/cache-utils.d.ts +90 -0
  39. package/lib/adapter/cache-utils.js +199 -4
  40. package/lib/adapter/cache-utils.test.d.ts +1 -0
  41. package/lib/adapter/cache-utils.test.js +179 -0
  42. package/lib/adapter/function-groups.d.ts +215 -0
  43. package/lib/adapter/function-groups.js +1099 -0
  44. package/lib/adapter/function-groups.test.d.ts +1 -0
  45. package/lib/adapter/function-groups.test.js +743 -0
  46. package/lib/adapter/init-cache.d.ts +6 -0
  47. package/lib/adapter/init-cache.js +245 -0
  48. package/lib/adapter/init-cache.test.d.ts +1 -0
  49. package/lib/adapter/init-cache.test.js +137 -0
  50. package/lib/adapter/local-file-cache-handler.d.ts +23 -0
  51. package/lib/adapter/local-file-cache-handler.js +52 -1
  52. package/lib/adapter/memory-cache-handler.d.ts +26 -17
  53. package/lib/adapter/memory-cache-handler.js +32 -50
  54. package/lib/adapter/memory-cache-handler.test.js +105 -85
  55. package/lib/adapter/s3-cache-handler.d.ts +179 -40
  56. package/lib/adapter/s3-cache-handler.js +807 -277
  57. package/lib/adapter/s3-cache-handler.test.js +1186 -31
  58. package/lib/adapter/use-cache-common.d.ts +90 -0
  59. package/lib/adapter/use-cache-common.js +250 -0
  60. package/lib/adapter/use-cache-common.test.d.ts +1 -0
  61. package/lib/adapter/use-cache-common.test.js +646 -0
  62. package/lib/adapter/use-cache-default-handler.d.ts +24 -0
  63. package/lib/adapter/use-cache-default-handler.js +90 -0
  64. package/lib/adapter/use-cache-default-handler.mjs +38645 -0
  65. package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
  66. package/lib/adapter/use-cache-handlers.test.js +349 -0
  67. package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
  68. package/lib/adapter/use-cache-remote-handler.js +186 -0
  69. package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
  70. package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
  71. package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
  72. package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
  73. package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
  74. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
  75. package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
  76. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
  77. package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
  78. package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
  81. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
  82. package/lib/index.d.ts +6 -7
  83. package/lib/index.js +2 -4
  84. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  88. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  92. package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
  93. package/lib/lambdas/post-deploy/prune-s3.js +41 -12
  94. package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
  95. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  96. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  103. package/lib/nextjs-api.d.ts +102 -18
  104. package/lib/nextjs-api.js +338 -38
  105. package/lib/nextjs-api.test.js +537 -1
  106. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  107. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  108. package/lib/nextjs-build/nextjs-build.js +684 -327
  109. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  110. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  111. package/lib/nextjs-build/patch-fetch.js +1 -1
  112. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  113. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  114. package/lib/nextjs-cache.d.ts +82 -4
  115. package/lib/nextjs-cache.js +186 -10
  116. package/lib/nextjs-cache.test.js +176 -1
  117. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  118. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  120. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  121. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  122. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  123. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  124. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  125. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  126. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  127. package/lib/nextjs-distribution.d.ts +194 -23
  128. package/lib/nextjs-distribution.js +535 -62
  129. package/lib/nextjs-distribution.test.d.ts +1 -0
  130. package/lib/nextjs-distribution.test.js +697 -0
  131. package/lib/nextjs-post-deploy.d.ts +13 -5
  132. package/lib/nextjs-post-deploy.js +13 -10
  133. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  134. package/lib/nextjs-post-deploy.test.js +34 -0
  135. package/lib/nextjs-static-assets.d.ts +17 -4
  136. package/lib/nextjs-static-assets.js +22 -5
  137. package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
  138. package/lib/root-constructs/nextjs-base-construct.js +139 -47
  139. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  140. package/lib/root-constructs/nextjs-global-containers.js +20 -71
  141. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  142. package/lib/root-constructs/nextjs-global-functions.js +52 -70
  143. package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
  144. package/lib/root-constructs/nextjs-regional-containers.js +8 -15
  145. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  146. package/lib/root-constructs/nextjs-regional-functions.js +8 -26
  147. package/lib/runtime/api-gateway-path.d.ts +34 -0
  148. package/lib/runtime/api-gateway-path.js +71 -0
  149. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  150. package/lib/runtime/api-gateway-path.test.js +65 -0
  151. package/lib/runtime/case-redirect.d.ts +22 -0
  152. package/lib/runtime/case-redirect.js +63 -0
  153. package/lib/runtime/case-redirect.test.d.ts +1 -0
  154. package/lib/runtime/case-redirect.test.js +32 -0
  155. package/lib/runtime/core.d.ts +234 -0
  156. package/lib/runtime/core.js +1216 -0
  157. package/lib/runtime/core.test.d.ts +1 -0
  158. package/lib/runtime/core.test.js +1686 -0
  159. package/lib/runtime/deployment-root.d.ts +13 -0
  160. package/lib/runtime/deployment-root.js +29 -0
  161. package/lib/runtime/dispatch.d.ts +331 -0
  162. package/lib/runtime/dispatch.js +751 -0
  163. package/lib/runtime/dispatch.test.d.ts +1 -0
  164. package/lib/runtime/dispatch.test.js +853 -0
  165. package/lib/runtime/entrypoints.d.ts +57 -0
  166. package/lib/runtime/entrypoints.js +115 -0
  167. package/lib/runtime/http/abort-signal.d.ts +6 -0
  168. package/lib/runtime/http/abort-signal.js +19 -0
  169. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  170. package/lib/runtime/http/abort-signal.test.js +49 -0
  171. package/lib/runtime/http/node-server.d.ts +38 -0
  172. package/lib/runtime/http/node-server.js +99 -0
  173. package/lib/runtime/http/node-server.test.d.ts +1 -0
  174. package/lib/runtime/http/node-server.test.js +96 -0
  175. package/lib/runtime/http/node-sink.d.ts +16 -0
  176. package/lib/runtime/http/node-sink.js +48 -0
  177. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  178. package/lib/runtime/http/node-sink.test.js +66 -0
  179. package/lib/runtime/http/request.d.ts +62 -0
  180. package/lib/runtime/http/request.js +134 -0
  181. package/lib/runtime/http/request.test.d.ts +1 -0
  182. package/lib/runtime/http/request.test.js +103 -0
  183. package/lib/runtime/http/response.d.ts +77 -0
  184. package/lib/runtime/http/response.js +229 -0
  185. package/lib/runtime/http/response.test.d.ts +1 -0
  186. package/lib/runtime/http/response.test.js +178 -0
  187. package/lib/runtime/http/sink.d.ts +73 -0
  188. package/lib/runtime/http/sink.js +188 -0
  189. package/lib/runtime/http/sink.test.d.ts +1 -0
  190. package/lib/runtime/http/sink.test.js +257 -0
  191. package/lib/runtime/image-utils.d.ts +78 -0
  192. package/lib/runtime/image-utils.js +129 -0
  193. package/lib/runtime/image-utils.test.d.ts +1 -0
  194. package/lib/runtime/image-utils.test.js +237 -0
  195. package/lib/runtime/image.d.ts +76 -0
  196. package/lib/runtime/image.js +296 -0
  197. package/lib/runtime/image.test.d.ts +1 -0
  198. package/lib/runtime/image.test.js +405 -0
  199. package/lib/runtime/lambda-event.d.ts +4 -0
  200. package/lib/runtime/lambda-event.js +113 -0
  201. package/lib/runtime/lambda-event.test.d.ts +1 -0
  202. package/lib/runtime/lambda-event.test.js +119 -0
  203. package/lib/runtime/lambda.mjs +41600 -0
  204. package/lib/runtime/load-module.d.ts +8 -0
  205. package/lib/runtime/load-module.js +35 -0
  206. package/lib/runtime/manifest.d.ts +215 -0
  207. package/lib/runtime/manifest.js +118 -0
  208. package/lib/runtime/middleware.d.ts +43 -0
  209. package/lib/runtime/middleware.js +113 -0
  210. package/lib/runtime/middleware.test.d.ts +1 -0
  211. package/lib/runtime/middleware.test.js +259 -0
  212. package/lib/runtime/next-modules.d.ts +71 -0
  213. package/lib/runtime/next-modules.js +144 -0
  214. package/lib/runtime/next-modules.test.d.ts +1 -0
  215. package/lib/runtime/next-modules.test.js +34 -0
  216. package/lib/runtime/public-files.d.ts +32 -0
  217. package/lib/runtime/public-files.js +117 -0
  218. package/lib/runtime/public-files.test.d.ts +1 -0
  219. package/lib/runtime/public-files.test.js +97 -0
  220. package/lib/runtime/server.mjs +41593 -0
  221. package/lib/runtime/static-files.d.ts +50 -0
  222. package/lib/runtime/static-files.js +266 -0
  223. package/lib/runtime/static-files.test.d.ts +1 -0
  224. package/lib/runtime/static-files.test.js +118 -0
  225. package/lib/runtime/util.d.ts +28 -0
  226. package/lib/runtime/util.js +79 -0
  227. package/lib/utils/base-path.d.ts +106 -13
  228. package/lib/utils/base-path.js +254 -41
  229. package/lib/utils/base-path.test.js +219 -51
  230. package/lib/utils/get-architecture.d.ts +7 -8
  231. package/lib/utils/get-architecture.js +12 -13
  232. package/lib/utils/zip-directory.d.ts +14 -0
  233. package/lib/utils/zip-directory.js +121 -0
  234. package/lib/utils/zip-directory.test.d.ts +1 -0
  235. package/lib/utils/zip-directory.test.js +99 -0
  236. package/package.json +22 -3
  237. package/scripts/capture-adapter-fixture.mjs +325 -0
  238. package/scripts/e2e-deploy.sh +398 -0
  239. package/scripts/e2e-harness/README.md +707 -0
  240. package/scripts/e2e-harness/app.js +370 -0
  241. package/scripts/e2e-harness/common.sh +249 -0
  242. package/scripts/e2e-harness/screen.mjs +302 -0
  243. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  244. package/scripts/e2e-harness/type-filters.mjs +47 -0
  245. package/scripts/e2e-logs.sh +75 -0
  246. package/scripts/e2e-offline.sh +91 -0
  247. package/scripts/e2e-sweep.sh +370 -0
  248. package/scripts/e2e-warm.sh +114 -0
  249. package/scripts/zero-config-build.mjs +418 -0
  250. package/docs/1k-concurrent-users-executions.png +0 -0
  251. package/docs/plans/adapter-runtime-release.md +0 -362
  252. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  253. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  254. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  255. package/lib/image-optimization/handler-utils.d.ts +0 -34
  256. package/lib/image-optimization/handler-utils.js +0 -83
  257. package/lib/image-optimization/handler-utils.test.js +0 -178
  258. package/lib/nextjs-build/functions.Dockerfile +0 -31
  259. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  260. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  261. package/lib/utils/experimental-flags.d.ts +0 -24
  262. package/lib/utils/experimental-flags.js +0 -30
  263. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -0,0 +1,1004 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CacheBucket = exports.TrackedTagMarkers = exports.DEFAULT_MAX_TRACKED_TAGS = exports.MAX_REVALIDATION_LOG_GAP_MS = exports.DEFAULT_TAG_RESYNC_MS = exports.REVALIDATION_LOG_LOOKBACK_MS = exports.RevalidationLog = exports.REVALIDATION_LOG_MAX_PAGES = exports.REVALIDATION_LOG_TTL_MS = exports.TagMarkerTable = exports.DEFAULT_TAG_REFRESH_MS = exports.BATCH_GET_MAX_KEYS = exports.USE_CACHE_KEY_PREFIX = void 0;
4
+ exports.resolveAwsCacheConfig = resolveAwsCacheConfig;
5
+ exports.buildS3Key = buildS3Key;
6
+ exports.useCacheS3Key = useCacheS3Key;
7
+ exports.markerState = markerState;
8
+ exports.markerClock = markerClock;
9
+ exports.markerFor = markerFor;
10
+ exports.applyMarker = applyMarker;
11
+ exports.markerUpdate = markerUpdate;
12
+ exports.mergeMarkers = mergeMarkers;
13
+ /*
14
+ The S3 / DynamoDB plumbing shared by every cdk-nextjs cache handler: the
15
+ incremental `cacheHandler` (`S3CacheHandler`) and the `cacheHandlers` for
16
+ `'use cache'` / `'use cache: remote'`.
17
+
18
+ What lives here is what has to agree between them - where the configuration
19
+ comes from, how a cache key becomes an S3 key, and what a tag's marker row in
20
+ the revalidation table looks like and means. A `revalidateTag` reaches both
21
+ kinds of handler, and they must read each other's markers the same way.
22
+ */
23
+ /* eslint-disable import/no-extraneous-dependencies */
24
+ const node_path_1 = require("node:path");
25
+ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
26
+ const client_s3_1 = require("@aws-sdk/client-s3");
27
+ /** The configuration from the environment. */
28
+ function resolveAwsCacheConfig() {
29
+ return {
30
+ bucketName: process.env.CDK_NEXTJS_CACHE_BUCKET_NAME || "",
31
+ tableName: process.env.CDK_NEXTJS_REVALIDATION_TABLE_NAME || "",
32
+ region: process.env.AWS_REGION || "us-east-1",
33
+ buildId: process.env.CDK_NEXTJS_BUILD_ID || "",
34
+ };
35
+ }
36
+ /**
37
+ * `{buildId}/{cacheKey}.json`, the incremental cache's key convention.
38
+ *
39
+ * The root path becomes `index`, and a leading slash is dropped so there is no
40
+ * empty folder under the build prefix. Everything this returns ends in `.json`,
41
+ * which is what keeps it disjoint from {@link useCacheS3Key}.
42
+ */
43
+ function buildS3Key(buildId, cacheKey) {
44
+ let cleanCacheKey = cacheKey;
45
+ if (cacheKey === "/" || cacheKey === "") {
46
+ cleanCacheKey = "index";
47
+ }
48
+ else if (cacheKey.startsWith("/")) {
49
+ cleanCacheKey = cacheKey.slice(1);
50
+ }
51
+ return (0, node_path_1.join)(buildId, `${cleanCacheKey}.json`);
52
+ }
53
+ /**
54
+ * The folder under the build prefix that `'use cache'` entries are stored in.
55
+ * @see useCacheS3Key
56
+ */
57
+ exports.USE_CACHE_KEY_PREFIX = "_use-cache";
58
+ /**
59
+ * `{buildId}/_use-cache/{hash}.entry`, where a `cacheHandlers` entry is stored.
60
+ *
61
+ * Hashed because a `'use cache'` key is the serialized arguments of the call and
62
+ * has no length limit, where an S3 key stops at 1024 bytes. The `.entry` suffix
63
+ * rather than `.json` is what makes a collision with the incremental cache
64
+ * impossible rather than unlikely: every key {@link buildS3Key} writes ends in
65
+ * `.json`, including one for a route that happens to be named `/_use-cache/…`.
66
+ * Still under the build prefix, so post-deploy pruning drops them with the build.
67
+ */
68
+ function useCacheS3Key(buildId, keyHash) {
69
+ return (0, node_path_1.join)(buildId, exports.USE_CACHE_KEY_PREFIX, `${keyHash}.entry`);
70
+ }
71
+ /**
72
+ * What `marker` means for an entry created at `createdAt`, at `now`.
73
+ *
74
+ * `expiredAt` in the future is a profile's `expire` that has not come yet,
75
+ * compared the way Next.js's `areTagsExpired` does.
76
+ */
77
+ function markerState(marker, createdAt, now) {
78
+ const { revalidatedAt, expiredAt, staleAt } = marker;
79
+ if ((revalidatedAt !== undefined && revalidatedAt > createdAt) ||
80
+ (expiredAt !== undefined && expiredAt <= now && expiredAt > createdAt)) {
81
+ return "expired";
82
+ }
83
+ if (staleAt !== undefined && staleAt > createdAt) {
84
+ return "stale";
85
+ }
86
+ return "fresh";
87
+ }
88
+ /**
89
+ * The clock every tag marker is stamped with, and every entry timestamp it is
90
+ * compared against: the one Next.js stamps `CacheEntry.timestamp` with
91
+ * (`performance.timeOrigin + performance.now()`, in `use-cache-wrapper.js` and
92
+ * the default handler), rather than `Date.now()`. Both handlers write the same
93
+ * marker rows, so both have to use it: two clocks on one row let the last writer
94
+ * decide which clock the others compare against, and they drift apart for as
95
+ * long as a Lambda sandbox or Fargate task lives.
96
+ */
97
+ function markerClock() {
98
+ return performance.timeOrigin + performance.now();
99
+ }
100
+ /**
101
+ * The marker fields a tag revalidated at `now` sets.
102
+ *
103
+ * Without `durations` - `updateTag`, or `revalidateTag` with no profile - the
104
+ * tag's entries expire immediately (`revalidatedAt`). With them the entries go
105
+ * stale now and expire after the profile's `expire`, the same pair of
106
+ * timestamps Next.js's `FileSystemCache.revalidateTag` records. A profile with
107
+ * no `expire` sets only `staleAt`, and whatever `expiredAt` the tag had stays.
108
+ */
109
+ function markerFor(now, durations) {
110
+ if (!durations) {
111
+ return { revalidatedAt: now };
112
+ }
113
+ if (durations.expire === undefined) {
114
+ return { staleAt: now };
115
+ }
116
+ return { staleAt: now, expiredAt: now + durations.expire * 1000 };
117
+ }
118
+ const MARKER_FIELDS = ["revalidatedAt", "staleAt", "expiredAt"];
119
+ /**
120
+ * `existing` with the fields `update` sets, as a {@link markerUpdate} leaves
121
+ * the row: a field `update` does not set keeps its value.
122
+ */
123
+ function applyMarker(existing, update) {
124
+ const marker = { ...existing };
125
+ for (const field of MARKER_FIELDS) {
126
+ if (update[field] !== undefined) {
127
+ marker[field] = update[field];
128
+ }
129
+ }
130
+ return marker;
131
+ }
132
+ /** The marker-row update that sets {@link markerFor}'s fields. */
133
+ function markerUpdate(now, durations) {
134
+ const marker = markerFor(now, durations);
135
+ const fields = MARKER_FIELDS.filter((field) => marker[field] !== undefined);
136
+ return {
137
+ UpdateExpression: `SET ${fields.map((field) => `${field} = :${field}`).join(", ")}`,
138
+ ExpressionAttributeValues: Object.fromEntries(fields.map((field) => [`:${field}`, { N: String(marker[field]) }])),
139
+ };
140
+ }
141
+ /** A DynamoDB number attribute as a number, or `undefined` when absent. */
142
+ function numberAttribute(value) {
143
+ return value?.N === undefined ? undefined : Number(value.N);
144
+ }
145
+ /** The marker fields of a marker or log row. */
146
+ function markerOf(item) {
147
+ return {
148
+ revalidatedAt: numberAttribute(item.revalidatedAt),
149
+ staleAt: numberAttribute(item.staleAt),
150
+ expiredAt: numberAttribute(item.expiredAt),
151
+ };
152
+ }
153
+ /** DynamoDB's cap on keys in one `BatchGetItem`. */
154
+ exports.BATCH_GET_MAX_KEYS = 100;
155
+ /**
156
+ * How often, at most, an instance catches up on revalidations other instances
157
+ * ran, unless `CDK_NEXTJS_TAG_REFRESH_MS` says otherwise: the staleness window
158
+ * for a `revalidateTag` run elsewhere. Every cache hit checks its tags'
159
+ * markers, and every marker of a deployment shares one partition key, so
160
+ * reading them per request capped a route's cache hits at the partition's read
161
+ * throughput (~1,900 req/s on NextjsRegionalFunctions). Once a second, from the
162
+ * revalidation log, the reads scale with instances instead of requests or tags.
163
+ */
164
+ exports.DEFAULT_TAG_REFRESH_MS = 1000;
165
+ /**
166
+ * The bare-tag marker rows of the revalidation table (`pk = buildId`,
167
+ * `sk = tag`), which record when a tag was last revalidated and how.
168
+ *
169
+ * The table also holds the incremental cache's `tag#s3Key` mapping rows, which
170
+ * are its own business and stay in `S3CacheHandler`: only the markers mean the
171
+ * same thing to every handler. What an instance keeps of them between reads is
172
+ * {@link TrackedTagMarkers}.
173
+ */
174
+ class TagMarkerTable {
175
+ client;
176
+ tableName;
177
+ buildId;
178
+ constructor(client, tableName, buildId) {
179
+ this.client = client;
180
+ this.tableName = tableName;
181
+ this.buildId = buildId;
182
+ }
183
+ /**
184
+ * Record `tag`'s revalidation at `now`. See {@link markerUpdate}.
185
+ *
186
+ * Returns the row as this write left it, so the instance that wrote it can
187
+ * track it rather than read it back: reads are eventually consistent, and a
188
+ * read-back racing replication could return the marker from before the write.
189
+ */
190
+ async write(tag, now, durations) {
191
+ const response = await this.client.send(new client_dynamodb_1.UpdateItemCommand({
192
+ TableName: this.tableName,
193
+ Key: {
194
+ pk: { S: this.buildId },
195
+ sk: { S: tag },
196
+ },
197
+ ...markerUpdate(now, durations),
198
+ ReturnValues: "ALL_NEW",
199
+ }));
200
+ return response?.Attributes ? markerOf(response.Attributes) : undefined;
201
+ }
202
+ /**
203
+ * The marker rows for `tags` that exist, by tag, in one `BatchGetItem` per
204
+ * {@link BATCH_GET_MAX_KEYS} tags rather than a `GetItem` each: a page
205
+ * carries its whole implicit `_N_T_/…` chain plus the app's own tags, a
206
+ * page with a few fetches checks each of them too, and every one is on the
207
+ * request path. A tag with no row is absent from the result.
208
+ */
209
+ async read(tags) {
210
+ const { tableName, buildId } = this;
211
+ const unique = Array.from(new Set(tags));
212
+ const markers = new Map();
213
+ for (let i = 0; i < unique.length; i += exports.BATCH_GET_MAX_KEYS) {
214
+ let keys = unique
215
+ .slice(i, i + exports.BATCH_GET_MAX_KEYS)
216
+ .map((tag) => ({ pk: { S: buildId }, sk: { S: tag } }));
217
+ // `UnprocessedKeys` is DynamoDB declining part of the batch under load;
218
+ // a marker left unread is a revalidation missed, so it is asked again.
219
+ for (let attempt = 0; keys?.length && attempt < 3; attempt++) {
220
+ const response = await this.client.send(new client_dynamodb_1.BatchGetItemCommand({
221
+ RequestItems: {
222
+ [tableName]: {
223
+ Keys: keys,
224
+ ProjectionExpression: "sk, revalidatedAt, staleAt, expiredAt",
225
+ },
226
+ },
227
+ }));
228
+ for (const item of response.Responses?.[tableName] ?? []) {
229
+ const tag = item.sk?.S;
230
+ if (tag !== undefined) {
231
+ markers.set(tag, markerOf(item));
232
+ }
233
+ }
234
+ keys = response.UnprocessedKeys?.[tableName]?.Keys;
235
+ }
236
+ if (keys?.length) {
237
+ throw new Error(`DynamoDB left ${keys.length} tag markers unread after retrying`);
238
+ }
239
+ }
240
+ return markers;
241
+ }
242
+ }
243
+ exports.TagMarkerTable = TagMarkerTable;
244
+ /**
245
+ * How long a revalidation log row is kept (`ttl`, epoch seconds). DynamoDB never
246
+ * deletes an item before its TTL, only some time after, so a reader that last
247
+ * queried less than this long ago (less a margin for writers' clocks) is sure
248
+ * to find every row it has not seen yet.
249
+ */
250
+ exports.REVALIDATION_LOG_TTL_MS = 15 * 60 * 1000;
251
+ /** The most `Query` pages one {@link RevalidationLog.query} reads. */
252
+ exports.REVALIDATION_LOG_MAX_PAGES = 5;
253
+ /** How many sort keys {@link RevalidationLog.put} tries before giving up. */
254
+ const LOG_PUT_ATTEMPTS = 5;
255
+ /** Digits a log row's timestamp is zero-padded to, so sort keys sort by time. */
256
+ const LOG_SK_DIGITS = 15;
257
+ /**
258
+ * The revalidation log: one row per tag revalidation (`pk = <buildId>#log`,
259
+ * `sk = <Date.now(), zero-padded>#<tag>`), which expires after
260
+ * {@link REVALIDATION_LOG_TTL_MS}.
261
+ *
262
+ * The marker rows stay the source of truth. The log exists so an instance
263
+ * can ask "what was revalidated since I last looked?" in one `Query`, instead
264
+ * of re-reading every tag it tracks to find out that almost none changed. Every
265
+ * marker row of a deployment shares one partition, and those re-reads from a
266
+ * handful of busy instances were enough to throttle it.
267
+ *
268
+ * The sort key's timestamp is the writer's wall clock (`Date.now()`), not the
269
+ * performance clock ({@link markerClock}) the marker values are stamped with by both
270
+ * handlers: it only orders rows for readers' cursors, which are on their own
271
+ * wall clocks, and is never compared with an entry's timestamp.
272
+ */
273
+ class RevalidationLog {
274
+ client;
275
+ tableName;
276
+ pk;
277
+ constructor(client, tableName, buildId) {
278
+ this.client = client;
279
+ this.tableName = tableName;
280
+ this.pk = `${buildId}#log`;
281
+ }
282
+ /**
283
+ * Record that `tag` was revalidated at `at` (`Date.now()`), setting `marker`.
284
+ *
285
+ * Two revalidations of `tag` in the same millisecond would share a sort key,
286
+ * and the second would overwrite the first. So the row is only written where
287
+ * its key is free, and on a collision it moves to the next millisecond, up
288
+ * to {@link LOG_PUT_ATTEMPTS} times.
289
+ */
290
+ async put(tag, at, marker) {
291
+ for (let attempt = 1;; attempt++) {
292
+ const item = {
293
+ pk: { S: this.pk },
294
+ sk: { S: `${logSkPrefix(at)}#${tag}` },
295
+ ttl: { N: String(Math.ceil((at + exports.REVALIDATION_LOG_TTL_MS) / 1000)) },
296
+ };
297
+ for (const field of MARKER_FIELDS) {
298
+ const value = marker[field];
299
+ if (value !== undefined) {
300
+ item[field] = { N: String(value) };
301
+ }
302
+ }
303
+ try {
304
+ await this.client.send(new client_dynamodb_1.PutItemCommand({
305
+ TableName: this.tableName,
306
+ Item: item,
307
+ ConditionExpression: "attribute_not_exists(sk)",
308
+ }));
309
+ return;
310
+ }
311
+ catch (error) {
312
+ if (error?.name !==
313
+ "ConditionalCheckFailedException" ||
314
+ attempt >= LOG_PUT_ATTEMPTS) {
315
+ throw error;
316
+ }
317
+ at = Math.floor(at) + 1;
318
+ }
319
+ }
320
+ }
321
+ /**
322
+ * The rows written at or after `since` (`Date.now()`), oldest first.
323
+ * `truncated` when there were more than {@link REVALIDATION_LOG_MAX_PAGES}
324
+ * pages of them, and `rows` is only the start.
325
+ *
326
+ * Eventually consistent: a row written a moment ago may not show yet, which
327
+ * is what the reader's lookback is for.
328
+ */
329
+ async query(since) {
330
+ const rows = [];
331
+ let startKey;
332
+ for (let page = 0; page < exports.REVALIDATION_LOG_MAX_PAGES; page++) {
333
+ const response = await this.client.send(new client_dynamodb_1.QueryCommand({
334
+ TableName: this.tableName,
335
+ KeyConditionExpression: "pk = :pk AND sk >= :since",
336
+ ExpressionAttributeValues: {
337
+ ":pk": { S: this.pk },
338
+ ":since": { S: logSkPrefix(Math.max(0, since)) },
339
+ },
340
+ ProjectionExpression: "sk, revalidatedAt, staleAt, expiredAt",
341
+ ExclusiveStartKey: startKey,
342
+ }));
343
+ for (const item of response.Items ?? []) {
344
+ const sk = item.sk?.S;
345
+ // `<digits>#<tag>`: the tag is everything after the fixed-width
346
+ // timestamp, `#`s included.
347
+ if (sk === undefined || sk[LOG_SK_DIGITS] !== "#") {
348
+ continue;
349
+ }
350
+ rows.push({
351
+ sk,
352
+ at: Number(sk.slice(0, LOG_SK_DIGITS)),
353
+ tag: sk.slice(LOG_SK_DIGITS + 1),
354
+ marker: markerOf(item),
355
+ });
356
+ }
357
+ startKey = response.LastEvaluatedKey;
358
+ if (!startKey) {
359
+ return { rows, truncated: false };
360
+ }
361
+ }
362
+ return { rows, truncated: true };
363
+ }
364
+ }
365
+ exports.RevalidationLog = RevalidationLog;
366
+ function logSkPrefix(at) {
367
+ return String(Math.floor(at)).padStart(LOG_SK_DIGITS, "0");
368
+ }
369
+ /**
370
+ * How far behind the last query's start the next one starts reading the log:
371
+ * the room for the `Query` being eventually consistent and for writers' clocks
372
+ * running behind the reader's. Rows inside it are read again, and dropped as
373
+ * already applied.
374
+ */
375
+ exports.REVALIDATION_LOG_LOOKBACK_MS = 5000;
376
+ /**
377
+ * The longest {@link TrackedTagMarkers} trusts the log alone for a tag before
378
+ * reading its marker row again. The log is the fast path, but the marker rows
379
+ * are the source of truth: a log row whose write failed would otherwise be
380
+ * missed for as long as the tag stays tracked.
381
+ *
382
+ * Rolling, not all at once: each refresh re-reads at most
383
+ * {@link BATCH_GET_MAX_KEYS} of the tags due, oldest first. Re-reading them all
384
+ * together cost ~500 RCU at 1000 tags - a fleet started by one load test did it
385
+ * in the same minute, 12,800 RCU, and throttled - and would be ~5,000 RCU at
386
+ * {@link DEFAULT_MAX_TRACKED_TAGS}, past what the one partition serves in a
387
+ * second. Spread out, 10,000 tracked tags cost ~8 RCU a second per instance.
388
+ *
389
+ * Each tag is due at a random 75-100% of this after it was last read, so tags
390
+ * first read together - an instance warming up - do not all come due together
391
+ * again every interval: the load test that measured the rolling re-read saw
392
+ * its warm-up's reads return as a 30-36 RCU/s bump ten minutes later.
393
+ */
394
+ exports.DEFAULT_TAG_RESYNC_MS = 10 * 60 * 1000;
395
+ /** The fraction of {@link DEFAULT_TAG_RESYNC_MS} a tag may come due early by. */
396
+ const TAG_RESYNC_JITTER = 0.25;
397
+ /**
398
+ * How long since the last successful log query the log can still be trusted to
399
+ * hold every row not read yet: its TTL less a margin for writers' clocks. Past
400
+ * it - a Lambda frozen between invocations, a run of failed queries - the
401
+ * tracked markers are forgotten, to be read again as they are needed, and the
402
+ * log is followed from there.
403
+ */
404
+ exports.MAX_REVALIDATION_LOG_GAP_MS = exports.REVALIDATION_LOG_TTL_MS - 5 * 60 * 1000;
405
+ /**
406
+ * The most tags one instance tracks. Past it the least recently used is
407
+ * forgotten, which costs a read the next time it is needed: an untracked tag
408
+ * is read before it is trusted.
409
+ *
410
+ * A tracked tag costs memory (~2 MB at this bound) and its share of the rolling
411
+ * re-read, not a read every refresh, so the bound is set by how many tags an
412
+ * instance really uses. Every path is a tag of its own (`_N_T_/<path>`), and at
413
+ * 1000 an app of 1000 tagged pages kept evicting what it was about to need:
414
+ * half its requests re-read a marker.
415
+ */
416
+ exports.DEFAULT_MAX_TRACKED_TAGS = 10_000;
417
+ /**
418
+ * One instance's copy of the marker rows of the tags it has needed, kept
419
+ * current through the {@link RevalidationLog}: the process's one tag manifest
420
+ * (`sharedTagManifest`), for the `'use cache'` handlers and the incremental
421
+ * cache alike.
422
+ *
423
+ * Next.js's built-in `'use cache'` handler keeps tags in a module-level map
424
+ * (`tags-manifest.external.js`) that only its own `updateTags` writes, and its
425
+ * `refreshTags` is a no-op, so a `revalidateTag` on one instance never reaches
426
+ * the others: they keep serving the revalidated entry, including inside pages
427
+ * that are being re-rendered *because* of that revalidation. The
428
+ * `cacheHandlers` interface's answer is `refreshTags`, "called before starting
429
+ * a new request … to refresh the local tags manifest", and this is that
430
+ * manifest, backed by the same marker rows the incremental cache's
431
+ * `revalidateTag` writes (`pk = buildId`, `sk = tag`).
432
+ *
433
+ * The cost is bounded per instance, not per request:
434
+ * - {@link ensure} reads a tag's marker the first time it is needed and not
435
+ * again until it is evicted, so a tag costs one read per instance, not one
436
+ * per request.
437
+ * - {@link refresh}, at most once per `refreshIntervalMs`, sends one `Query`
438
+ * for the log rows written since the last one, and applies those of tags
439
+ * this instance tracks. Concurrent callers share it. Alongside, it re-reads
440
+ * the markers of up to {@link BATCH_GET_MAX_KEYS} tags not read for
441
+ * {@link DEFAULT_TAG_RESYNC_MS}, in one `BatchGetItem`.
442
+ * A revalidation on another instance is therefore seen within
443
+ * `refreshIntervalMs` (plus the query itself). The instance that ran it applies
444
+ * it itself, at once, with {@link set}.
445
+ */
446
+ class TrackedTagMarkers {
447
+ markers;
448
+ log;
449
+ refreshIntervalMs;
450
+ maxTrackedTags;
451
+ resyncIntervalMs;
452
+ clock;
453
+ random;
454
+ debug;
455
+ /** By tag, least recently used first. */
456
+ tags = new Map();
457
+ /**
458
+ * When each tracked tag's marker is due to be read again: a random 75-100%
459
+ * of `resyncIntervalMs` after it was last known from the table - read,
460
+ * written here, or new. In the order they became known, least recent first.
461
+ */
462
+ dueAt = new Map();
463
+ reading = new Map();
464
+ /**
465
+ * Log rows for tags whose first read is in flight, merged by tag: the read
466
+ * may have been answered before the revalidation, so they are applied to its
467
+ * result rather than dropped.
468
+ */
469
+ pendingRows = new Map();
470
+ /** Tracked tags whose read failed, for the next refresh to read again. */
471
+ unread = new Set();
472
+ lastRefresh = -Infinity;
473
+ refreshing;
474
+ /**
475
+ * Where the next log query starts (`clock()`): the last successful one's
476
+ * start, less {@link REVALIDATION_LOG_LOOKBACK_MS}.
477
+ */
478
+ cursor;
479
+ /** When the last successful log query started, or the log was first read. */
480
+ lastLogRead;
481
+ /** Log rows at or after the cursor already applied, by sort key. */
482
+ applied = new Map();
483
+ /** {@link update}s of the current turn, by their arguments. */
484
+ updating = new Map();
485
+ constructor(options) {
486
+ this.markers = options.markers;
487
+ this.log = options.log;
488
+ this.refreshIntervalMs =
489
+ options.refreshIntervalMs ?? exports.DEFAULT_TAG_REFRESH_MS;
490
+ this.maxTrackedTags = options.maxTrackedTags ?? exports.DEFAULT_MAX_TRACKED_TAGS;
491
+ this.resyncIntervalMs = options.resyncIntervalMs ?? exports.DEFAULT_TAG_RESYNC_MS;
492
+ // Looked up on each call rather than bound here, so a test's `Date.now`
493
+ // spy applies.
494
+ this.clock = options.clock ?? (() => Date.now());
495
+ this.random = options.random ?? Math.random;
496
+ this.debug = options.debug ?? (() => { });
497
+ // Nothing is tracked yet, so nothing before this can be missed: every tag
498
+ // is read from its marker the first time it is needed.
499
+ const at = this.clock();
500
+ this.cursor = at - exports.REVALIDATION_LOG_LOOKBACK_MS;
501
+ this.lastLogRead = at;
502
+ }
503
+ /** `tag`'s marker as this instance knows it, if it tracks `tag`. */
504
+ get(tag) {
505
+ return this.tags.get(tag);
506
+ }
507
+ /**
508
+ * Track `tag` with `marker`: what this instance just wrote, which it knows
509
+ * without reading it back.
510
+ */
511
+ set(tag, marker) {
512
+ this.remember(tag, marker);
513
+ this.known(tag, this.clock());
514
+ }
515
+ /**
516
+ * Note a use of `tags`: those of an entry this instance just stored.
517
+ *
518
+ * With the table, a tag not tracked yet is left untracked, to be read by
519
+ * {@link ensure} the first time an entry needs it. Nothing revalidated before
520
+ * the new entry was created applies to *it*, but tracking is per tag, not per
521
+ * entry: tracking the tag with an empty marker would also vouch for every
522
+ * older entry that carries it - one another instance stored in S3, or one
523
+ * this instance kept in memory across a {@link forget} - and a revalidation
524
+ * from before the log's cursor would go unseen until the rolling re-read.
525
+ *
526
+ * Without the table every revalidation is this process's own, applied with
527
+ * {@link set}, so a tag is tracked at once.
528
+ */
529
+ track(tags) {
530
+ if (!this.markers) {
531
+ this.trackUnread(tags);
532
+ return;
533
+ }
534
+ for (const tag of tags) {
535
+ this.touch(tag);
536
+ }
537
+ }
538
+ /**
539
+ * Track `tags` as they are known now, without reading them, with an empty
540
+ * marker for any not tracked yet.
541
+ */
542
+ trackUnread(tags) {
543
+ const at = this.clock();
544
+ for (const tag of tags) {
545
+ if (!this.tags.has(tag)) {
546
+ this.known(tag, at);
547
+ }
548
+ this.remember(tag, this.tags.get(tag) ?? {});
549
+ }
550
+ }
551
+ /**
552
+ * Read the markers of whichever of `tags` this instance does not track yet.
553
+ * Needed before judging an entry this instance did not create, since its
554
+ * tags may have been revalidated at any time before.
555
+ */
556
+ async ensure(tags) {
557
+ if (!this.markers) {
558
+ this.trackUnread(tags);
559
+ return;
560
+ }
561
+ const waits = [];
562
+ const unread = [];
563
+ for (const tag of new Set(tags)) {
564
+ const inFlight = this.reading.get(tag);
565
+ if (inFlight) {
566
+ waits.push(inFlight);
567
+ }
568
+ else if (this.tags.has(tag)) {
569
+ this.touch(tag);
570
+ }
571
+ else {
572
+ unread.push(tag);
573
+ }
574
+ }
575
+ if (unread.length > 0) {
576
+ // `readInto` never rejects: a failed read leaves the tags tracked.
577
+ const read = this.readInto(unread).then(() => {
578
+ for (const tag of unread) {
579
+ this.reading.delete(tag);
580
+ }
581
+ });
582
+ for (const tag of unread) {
583
+ this.reading.set(tag, read);
584
+ }
585
+ waits.push(read);
586
+ }
587
+ await Promise.all(waits);
588
+ }
589
+ /**
590
+ * Catch up on revalidations other instances ran, at most once per
591
+ * `refreshIntervalMs`. See {@link TrackedTagMarkers} for the cost.
592
+ */
593
+ async refresh() {
594
+ const log = this.log;
595
+ if (!log) {
596
+ return;
597
+ }
598
+ if (this.refreshing) {
599
+ return this.refreshing;
600
+ }
601
+ const at = this.clock();
602
+ if (at - this.lastRefresh < this.refreshIntervalMs) {
603
+ return;
604
+ }
605
+ this.lastRefresh = at;
606
+ // Whatever gets tracked before the next refresh is read from its marker,
607
+ // so there is nothing to catch up on yet.
608
+ if (this.tags.size === 0) {
609
+ return;
610
+ }
611
+ this.refreshing = this.sync(at, log).finally(() => {
612
+ this.refreshing = undefined;
613
+ });
614
+ return this.refreshing;
615
+ }
616
+ /**
617
+ * Record a revalidation of `tags`: here at once, and in the revalidation
618
+ * table for every other instance - the marker row plus a log row per tag.
619
+ *
620
+ * Next.js calls `revalidateTag` on the incremental cache and `updateTags` on
621
+ * every distinct `cacheHandlers` entry, all in one synchronous loop
622
+ * (`revalidation-utils`), and all of them share this manifest. So an
623
+ * identical call in the same turn joins the first instead of writing the
624
+ * rows again. One in a later turn is a revalidation of its own, even while
625
+ * the first one's writes are in flight, and gets its own, later, marker.
626
+ * Never rejects: resolves `false` when a row failed to write (the error is
627
+ * logged), so other instances may not see it.
628
+ */
629
+ async update(tags, durations) {
630
+ const key = JSON.stringify([tags, durations ?? null]);
631
+ const inFlight = this.updating.get(key);
632
+ if (inFlight) {
633
+ return inFlight;
634
+ }
635
+ const update = this.write(tags, durations);
636
+ this.updating.set(key, update);
637
+ // Forgotten as soon as the current turn's calls have been made.
638
+ void Promise.resolve().then(() => this.updating.delete(key));
639
+ return update;
640
+ }
641
+ /**
642
+ * What the tracked markers say about an entry carrying `tags`, created at
643
+ * `createdAt`: the most severe answer of any of them.
644
+ */
645
+ state(tags, createdAt) {
646
+ // `markerClock()`, not `Date.now()`, here and wherever a marker is stamped:
647
+ // `createdAt` is on Next.js's clock, and a marker on the wall clock would be
648
+ // compared across the two, so an entry regenerated just after a
649
+ // revalidation could still read as older than it wherever they drift.
650
+ const at = markerClock();
651
+ let state = "fresh";
652
+ for (const tag of tags) {
653
+ const marker = this.get(tag);
654
+ if (!marker) {
655
+ continue;
656
+ }
657
+ const tagState = markerState(marker, createdAt, at);
658
+ if (tagState === "expired") {
659
+ return "expired";
660
+ }
661
+ if (tagState === "stale") {
662
+ state = "stale";
663
+ }
664
+ }
665
+ return state;
666
+ }
667
+ /**
668
+ * `getExpiration`'s answer: the latest time any of `tags` expired, `0` if
669
+ * none has. Only expirations already past count - a profile's future
670
+ * `expire` is not an expiration yet - and a stale mark does not, matching
671
+ * Next.js's default handler, which reads only `expired` for implicit tags.
672
+ */
673
+ expiration(tags) {
674
+ const at = markerClock();
675
+ let latest = 0;
676
+ for (const tag of tags) {
677
+ const marker = this.get(tag);
678
+ if (!marker) {
679
+ continue;
680
+ }
681
+ if (marker.revalidatedAt !== undefined) {
682
+ latest = Math.max(latest, marker.revalidatedAt);
683
+ }
684
+ if (marker.expiredAt !== undefined && marker.expiredAt <= at) {
685
+ latest = Math.max(latest, marker.expiredAt);
686
+ }
687
+ }
688
+ return latest;
689
+ }
690
+ async write(tags, durations) {
691
+ const at = markerClock();
692
+ const marker = markerFor(at, durations);
693
+ for (const tag of tags) {
694
+ this.set(tag, applyMarker(this.get(tag), marker));
695
+ }
696
+ const { markers, log } = this;
697
+ if (!markers || !log) {
698
+ return true;
699
+ }
700
+ const writes = [];
701
+ for (const tag of new Set(tags)) {
702
+ writes.push([
703
+ "Error writing tag revalidation marker:",
704
+ // The row as it is now, which carries any earlier `revalidatedAt`
705
+ // another instance wrote: tracking only what this call set would
706
+ // hide that one until the rolling re-read, and an entry older than it
707
+ // would read as merely stale.
708
+ markers.write(tag, at, durations).then((row) => {
709
+ if (row) {
710
+ this.set(tag, mergeMarkers(this.get(tag), row));
711
+ }
712
+ }),
713
+ ]);
714
+ writes.push([
715
+ "Error writing tag revalidation log row:",
716
+ this.putLogRow(log, tag, marker),
717
+ ]);
718
+ }
719
+ const results = await Promise.allSettled(writes.map(([, write]) => write));
720
+ results.forEach((result, i) => {
721
+ if (result.status === "rejected") {
722
+ console.error(writes[i][0], result.reason);
723
+ }
724
+ });
725
+ return results.every((result) => result.status === "fulfilled");
726
+ }
727
+ /**
728
+ * Put `tag`'s log row, stamped on the wall clock (the marker values are on
729
+ * Next.js's: see {@link RevalidationLog}).
730
+ *
731
+ * Readers only look {@link REVALIDATION_LOG_LOOKBACK_MS} behind their last
732
+ * query, so a row that shows up much later than its timestamp - a slow
733
+ * connection, retries under throttling - is behind every cursor and never
734
+ * read. A slow put is therefore made again under a fresh timestamp, which
735
+ * readers will see; one slow twice is reported as a failure.
736
+ */
737
+ async putLogRow(log, tag, marker) {
738
+ for (let attempt = 0; attempt < 2; attempt++) {
739
+ const at = this.clock();
740
+ await log.put(tag, at, marker);
741
+ if (this.clock() - at <= MAX_LOG_PUT_MS) {
742
+ return;
743
+ }
744
+ }
745
+ throw new Error(`The revalidation log row for ${tag} took longer than readers look back`);
746
+ }
747
+ /**
748
+ * One refresh started at `at`: the log rows since the cursor, and the next
749
+ * slice of the rolling re-read.
750
+ *
751
+ * A failed query changes nothing but the log: the tags stay tracked as they
752
+ * were, and the next refresh asks again from the same cursor.
753
+ */
754
+ async sync(at, log) {
755
+ if (at - this.lastLogRead > exports.MAX_REVALIDATION_LOG_GAP_MS) {
756
+ this.forget(at, "the revalidation log may not cover the gap since it was last read");
757
+ return;
758
+ }
759
+ const [result] = await Promise.all([
760
+ log.query(this.cursor).catch((error) => {
761
+ console.error("Error reading tag revalidation log:", error);
762
+ return undefined;
763
+ }),
764
+ this.readInto(this.due(at)),
765
+ ]);
766
+ if (!result) {
767
+ return;
768
+ }
769
+ if (result.truncated) {
770
+ this.forget(at, "the revalidation log has more rows than one query reads");
771
+ return;
772
+ }
773
+ let applied = 0;
774
+ for (const row of result.rows) {
775
+ if (this.applied.has(row.sk)) {
776
+ continue;
777
+ }
778
+ const marker = this.tags.get(row.tag);
779
+ if (marker) {
780
+ // `set` on a key already there keeps its place in the LRU order: being
781
+ // revalidated elsewhere is not a use.
782
+ this.tags.set(row.tag, mergeMarkers(marker, row.marker));
783
+ }
784
+ else if (this.reading.has(row.tag)) {
785
+ this.pendingRows.set(row.tag, mergeMarkers(this.pendingRows.get(row.tag), row.marker));
786
+ }
787
+ else {
788
+ // A tag this instance does not track is read from its marker when it
789
+ // is next needed - but not yet marked applied, because that read may
790
+ // miss this very revalidation: the writer puts the log row and the
791
+ // marker at the same time, and the read is an eventually consistent
792
+ // `BatchGetItem` that can land milliseconds after the row showed here.
793
+ // Marked applied, the row was skipped by every query the lookback
794
+ // returned it to, and the pre-revalidation marker stood until the
795
+ // rolling re-read. Left unmarked, the next refresh applies it to
796
+ // whatever that read found; it costs no read, only the row being
797
+ // looked at again while it is inside the lookback.
798
+ continue;
799
+ }
800
+ this.applied.set(row.sk, row.at);
801
+ applied++;
802
+ }
803
+ this.lastLogRead = at;
804
+ this.advance(at - exports.REVALIDATION_LOG_LOOKBACK_MS);
805
+ this.debug(`read ${result.rows.length} revalidation log rows (${applied} applied)`);
806
+ }
807
+ /**
808
+ * The tags to read on this refresh, at most one `BatchGetItem`'s worth:
809
+ * those whose read failed, then those whose re-read has come due, in the
810
+ * order they were last read.
811
+ */
812
+ due(at) {
813
+ const due = [];
814
+ for (const tag of this.unread) {
815
+ if (due.length >= exports.BATCH_GET_MAX_KEYS)
816
+ return due;
817
+ due.push(tag);
818
+ }
819
+ // Known in time order, and each due at most `jitter` earlier than the
820
+ // tags after it: past a tag due more than that from now, none is due.
821
+ const jitter = this.resyncIntervalMs * TAG_RESYNC_JITTER;
822
+ for (const [tag, dueAt] of this.dueAt) {
823
+ if (due.length >= exports.BATCH_GET_MAX_KEYS || dueAt - jitter > at) {
824
+ break;
825
+ }
826
+ if (dueAt <= at && !this.unread.has(tag)) {
827
+ due.push(tag);
828
+ }
829
+ }
830
+ return due;
831
+ }
832
+ /**
833
+ * Forget every tracked marker, and follow the log from `at`: what is needed
834
+ * next is read from its marker as it is needed, spread over the requests
835
+ * that need it, rather than every tracked tag re-read at once.
836
+ */
837
+ forget(at, why) {
838
+ this.debug(`forgetting ${this.tags.size} tracked tags: ${why}`);
839
+ this.tags.clear();
840
+ this.dueAt.clear();
841
+ this.unread.clear();
842
+ this.applied.clear();
843
+ this.cursor = at - exports.REVALIDATION_LOG_LOOKBACK_MS;
844
+ this.lastLogRead = at;
845
+ }
846
+ /**
847
+ * Move the cursor forward to `cursor`, forgetting applied rows before it:
848
+ * no query returns them again.
849
+ */
850
+ advance(cursor) {
851
+ if (cursor <= this.cursor) {
852
+ return;
853
+ }
854
+ this.cursor = cursor;
855
+ for (const [sk, at] of this.applied) {
856
+ if (at < cursor) {
857
+ this.applied.delete(sk);
858
+ }
859
+ }
860
+ }
861
+ /**
862
+ * Read `tags` from the table, and report whether that worked. A read that
863
+ * fails leaves them tracked as they were, and the next refresh reads them
864
+ * again: the same "assume the entry is valid" the incremental cache has
865
+ * always answered with, rather than a read on every request while DynamoDB
866
+ * is unavailable.
867
+ */
868
+ async readInto(tags) {
869
+ if (tags.length === 0) {
870
+ return true;
871
+ }
872
+ const at = this.clock();
873
+ try {
874
+ const read = await this.markers.read(tags);
875
+ for (const tag of tags) {
876
+ this.unread.delete(tag);
877
+ this.remember(tag, mergeMarkers(mergeMarkers(this.tags.get(tag), read.get(tag)), this.takePendingRows(tag)));
878
+ this.known(tag, at);
879
+ }
880
+ this.debug(`read ${tags.length} tag markers (${read.size} set)`);
881
+ return true;
882
+ }
883
+ catch (error) {
884
+ console.error("Error reading tag markers:", error);
885
+ this.trackUnread(tags);
886
+ for (const tag of tags) {
887
+ this.unread.add(tag);
888
+ const pending = this.takePendingRows(tag);
889
+ if (pending) {
890
+ this.remember(tag, mergeMarkers(this.tags.get(tag), pending));
891
+ }
892
+ }
893
+ return false;
894
+ }
895
+ }
896
+ takePendingRows(tag) {
897
+ const pending = this.pendingRows.get(tag);
898
+ this.pendingRows.delete(tag);
899
+ return pending;
900
+ }
901
+ /** Record that `tag`'s marker was known from the table at `at`. */
902
+ known(tag, at) {
903
+ this.dueAt.delete(tag);
904
+ this.dueAt.set(tag, at + this.resyncIntervalMs * (1 - TAG_RESYNC_JITTER * this.random()));
905
+ }
906
+ remember(tag, marker) {
907
+ this.tags.delete(tag);
908
+ this.tags.set(tag, marker);
909
+ for (const oldest of this.tags.keys()) {
910
+ if (this.tags.size <= this.maxTrackedTags) {
911
+ break;
912
+ }
913
+ this.tags.delete(oldest);
914
+ this.dueAt.delete(oldest);
915
+ this.unread.delete(oldest);
916
+ }
917
+ }
918
+ touch(tag) {
919
+ const marker = this.tags.get(tag);
920
+ if (marker) {
921
+ this.remember(tag, marker);
922
+ }
923
+ }
924
+ }
925
+ exports.TrackedTagMarkers = TrackedTagMarkers;
926
+ /**
927
+ * The longest a log row's put may take and still be seen by every reader: half
928
+ * the lookback, leaving the rest for writers' clocks and eventually consistent
929
+ * queries.
930
+ */
931
+ const MAX_LOG_PUT_MS = exports.REVALIDATION_LOG_LOOKBACK_MS / 2;
932
+ /**
933
+ * A marker as read from the table or the log, keeping whatever this instance
934
+ * already knows that the read does not show yet: reads are eventually
935
+ * consistent, and a read straight after this instance's own revalidation could
936
+ * otherwise take it back.
937
+ */
938
+ function mergeMarkers(local, remote) {
939
+ if (!local) {
940
+ return remote ?? {};
941
+ }
942
+ if (!remote) {
943
+ return local;
944
+ }
945
+ // `expiredAt` is written with `staleAt`, so it belongs to whichever is
946
+ // newer - unless that revalidation's profile had no `expire` and left it.
947
+ const [older, newer] = (local.staleAt ?? -1) > (remote.staleAt ?? -1)
948
+ ? [remote, local]
949
+ : [local, remote];
950
+ return {
951
+ ...applyMarker(older, newer),
952
+ revalidatedAt: maxDefined(local.revalidatedAt, remote.revalidatedAt),
953
+ };
954
+ }
955
+ function maxDefined(a, b) {
956
+ if (a === undefined)
957
+ return b;
958
+ if (b === undefined)
959
+ return a;
960
+ return Math.max(a, b);
961
+ }
962
+ /**
963
+ * The cache bucket, as the handlers use it: whole objects read and written as
964
+ * UTF-8 text under the keys above.
965
+ */
966
+ class CacheBucket {
967
+ client;
968
+ bucketName;
969
+ constructor(client, bucketName) {
970
+ this.client = client;
971
+ this.bucketName = bucketName;
972
+ }
973
+ /**
974
+ * The body of the object at `key`, or `undefined` when there is none (`NoSuchKey`, or an
975
+ * empty response body). Any other error is thrown: the handlers disagree on
976
+ * whether one is worth logging.
977
+ */
978
+ async get(key) {
979
+ try {
980
+ const response = await this.client.send(new client_s3_1.GetObjectCommand({ Bucket: this.bucketName, Key: key }));
981
+ if (!response.Body) {
982
+ return undefined;
983
+ }
984
+ return await response.Body.transformToString("utf-8");
985
+ }
986
+ catch (error) {
987
+ if (error instanceof client_s3_1.NoSuchKey) {
988
+ return undefined;
989
+ }
990
+ throw error;
991
+ }
992
+ }
993
+ /** Write `body` as a JSON object at `key`. */
994
+ async putJson(key, body) {
995
+ await this.client.send(new client_s3_1.PutObjectCommand({
996
+ Bucket: this.bucketName,
997
+ Key: key,
998
+ Body: body,
999
+ ContentType: "application/json; charset=utf-8",
1000
+ }));
1001
+ }
1002
+ }
1003
+ exports.CacheBucket = CacheBucket;
1004
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLWNhY2hlLXN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXIvYXdzLWNhY2hlLXN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQThDQSxzREFPQztBQVNELGdDQVFDO0FBa0JELHNDQUVDO0FBcUNELGtDQWdCQztBQVdELGtDQUVDO0FBV0QsOEJBV0M7QUFRRCxrQ0FXQztBQUdELG9DQWVDO0FBdzVCRCxvQ0FvQkM7QUFub0NEOzs7Ozs7Ozs7RUFTRTtBQUNGLHNEQUFzRDtBQUN0RCx5Q0FBaUM7QUFDakMsOERBU2tDO0FBQ2xDLGtEQUs0QjtBQWtCNUIsOENBQThDO0FBQzlDLFNBQWdCLHFCQUFxQjtJQUNuQyxPQUFPO1FBQ0wsVUFBVSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLElBQUksRUFBRTtRQUMxRCxTQUFTLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0MsSUFBSSxFQUFFO1FBQy9ELE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxXQUFXO1FBQzdDLE9BQU8sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixJQUFJLEVBQUU7S0FDL0MsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFnQixVQUFVLENBQUMsT0FBZSxFQUFFLFFBQWdCO0lBQzFELElBQUksYUFBYSxHQUFHLFFBQVEsQ0FBQztJQUM3QixJQUFJLFFBQVEsS0FBSyxHQUFHLElBQUksUUFBUSxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ3hDLGFBQWEsR0FBRyxPQUFPLENBQUM7SUFDMUIsQ0FBQztTQUFNLElBQUksUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3BDLGFBQWEsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFDRCxPQUFPLElBQUEsZ0JBQUksRUFBQyxP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RUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUM1RCxDQUFDO1lBQ0YsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDbkIsT0FBTyxTQUFTLENBQUM7WUFDbkIsQ0FBQztZQUNELE9BQU8sTUFBTSxRQUFRLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3hELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxLQUFLLFlBQVkscUJBQVMsRUFBRSxDQUFDO2dCQUMvQixPQUFPLFNBQVMsQ0FBQztZQUNuQixDQUFDO1lBQ0QsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVELDhDQUE4QztJQUM5QyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQVcsRUFBRSxJQUFZO1FBQ3JDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ3BCLElBQUksNEJBQWdCLENBQUM7WUFDbkIsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQ3ZCLEdBQUcsRUFBRSxHQUFHO1lBQ1IsSUFBSSxFQUFFLElBQUk7WUFDVixXQUFXLEVBQUUsaUNBQWlDO1NBQy9DLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBdkNELGtDQXVDQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gIFRoZSBTMyAvIER5bmFtb0RCIHBsdW1iaW5nIHNoYXJlZCBieSBldmVyeSBjZGstbmV4dGpzIGNhY2hlIGhhbmRsZXI6IHRoZVxuICBpbmNyZW1lbnRhbCBgY2FjaGVIYW5kbGVyYCAoYFMzQ2FjaGVIYW5kbGVyYCkgYW5kIHRoZSBgY2FjaGVIYW5kbGVyc2AgZm9yXG4gIGAndXNlIGNhY2hlJ2AgLyBgJ3VzZSBjYWNoZTogcmVtb3RlJ2AuXG5cbiAgV2hhdCBsaXZlcyBoZXJlIGlzIHdoYXQgaGFzIHRvIGFncmVlIGJldHdlZW4gdGhlbSAtIHdoZXJlIHRoZSBjb25maWd1cmF0aW9uXG4gIGNvbWVzIGZyb20sIGhvdyBhIGNhY2hlIGtleSBiZWNvbWVzIGFuIFMzIGtleSwgYW5kIHdoYXQgYSB0YWcncyBtYXJrZXIgcm93IGluXG4gIHRoZSByZXZhbGlkYXRpb24gdGFibGUgbG9va3MgbGlrZSBhbmQgbWVhbnMuIEEgYHJldmFsaWRhdGVUYWdgIHJlYWNoZXMgYm90aFxuICBraW5kcyBvZiBoYW5kbGVyLCBhbmQgdGhleSBtdXN0IHJlYWQgZWFjaCBvdGhlcidzIG1hcmtlcnMgdGhlIHNhbWUgd2F5LlxuKi9cbi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7XG4gIEF0dHJpYnV0ZVZhbHVlLFxuICBCYXRjaEdldEl0ZW1Db21tYW5kLFxuICBCYXRjaEdldEl0ZW1Db21tYW5kT3V0cHV0LFxuICBEeW5hbW9EQkNsaWVudCxcbiAgUHV0SXRlbUNvbW1hbmQsXG4gIFF1ZXJ5Q29tbWFuZCxcbiAgUXVlcnlDb21tYW5kT3V0cHV0LFxuICBVcGRhdGVJdGVtQ29tbWFuZCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1keW5hbW9kYlwiO1xuaW1wb3J0IHtcbiAgR2V0T2JqZWN0Q29tbWFuZCxcbiAgTm9TdWNoS2V5LFxuICBQdXRPYmplY3RDb21tYW5kLFxuICBTM0NsaWVudCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuXG4vKipcbiAqIFdoZXJlIHRoZSBjYWNoZSBsaXZlcywgYXMgdGhlIGNvbnN0cnVjdHMgcGFzcyBpdCB0byB0aGUgY29tcHV0ZSB0aHJvdWdoIHRoZVxuICogZW52aXJvbm1lbnQgKGBOZXh0anNGdW5jdGlvbnNgLCBgTmV4dGpzQ29udGFpbmVyc2ApLiBFbXB0eSBzdHJpbmdzIGZvciB3aGF0IGlzXG4gKiBub3QgY29uZmlndXJlZCwgd2hpY2ggZWFjaCBoYW5kbGVyIHJlYWRzIGFzIFwidGhhdCBsYXllciBpcyBkaXNhYmxlZFwiLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEF3c0NhY2hlQ29uZmlnIHtcbiAgLyoqIGBDREtfTkVYVEpTX0NBQ0hFX0JVQ0tFVF9OQU1FYC4gKi9cbiAgYnVja2V0TmFtZTogc3RyaW5nO1xuICAvKiogYENES19ORVhUSlNfUkVWQUxJREFUSU9OX1RBQkxFX05BTUVgLiAqL1xuICB0YWJsZU5hbWU6IHN0cmluZztcbiAgLyoqIGBBV1NfUkVHSU9OYCwgYHVzLWVhc3QtMWAgd2hlbiB1bnNldC4gKi9cbiAgcmVnaW9uOiBzdHJpbmc7XG4gIC8qKiBgQ0RLX05FWFRKU19CVUlMRF9JRGA6IGV2ZXJ5IFMzIGtleSBhbmQgZXZlcnkgbWFya2VyIHJvdyBpcyBzY29wZWQgdG8gaXQuICovXG4gIGJ1aWxkSWQ6IHN0cmluZztcbn1cblxuLyoqIFRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlIGVudmlyb25tZW50LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVBd3NDYWNoZUNvbmZpZygpOiBBd3NDYWNoZUNvbmZpZyB7XG4gIHJldHVybiB7XG4gICAgYnVja2V0TmFtZTogcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19DQUNIRV9CVUNLRVRfTkFNRSB8fCBcIlwiLFxuICAgIHRhYmxlTmFtZTogcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19SRVZBTElEQVRJT05fVEFCTEVfTkFNRSB8fCBcIlwiLFxuICAgIHJlZ2lvbjogcHJvY2Vzcy5lbnYuQVdTX1JFR0lPTiB8fCBcInVzLWVhc3QtMVwiLFxuICAgIGJ1aWxkSWQ6IHByb2Nlc3MuZW52LkNES19ORVhUSlNfQlVJTERfSUQgfHwgXCJcIixcbiAgfTtcbn1cblxuLyoqXG4gKiBge2J1aWxkSWR9L3tjYWNoZUtleX0uanNvbmAsIHRoZSBpbmNyZW1lbnRhbCBjYWNoZSdzIGtleSBjb252ZW50aW9uLlxuICpcbiAqIFRoZSByb290IHBhdGggYmVjb21lcyBgaW5kZXhgLCBhbmQgYSBsZWFkaW5nIHNsYXNoIGlzIGRyb3BwZWQgc28gdGhlcmUgaXMgbm9cbiAqIGVtcHR5IGZvbGRlciB1bmRlciB0aGUgYnVpbGQgcHJlZml4LiBFdmVyeXRoaW5nIHRoaXMgcmV0dXJucyBlbmRzIGluIGAuanNvbmAsXG4gKiB3aGljaCBpcyB3aGF0IGtlZXBzIGl0IGRpc2pvaW50IGZyb20ge0BsaW5rIHVzZUNhY2hlUzNLZXl9LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRTM0tleShidWlsZElkOiBzdHJpbmcsIGNhY2hlS2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICBsZXQgY2xlYW5DYWNoZUtleSA9IGNhY2hlS2V5O1xuICBpZiAoY2FjaGVLZXkgPT09IFwiL1wiIHx8IGNhY2hlS2V5ID09PSBcIlwiKSB7XG4gICAgY2xlYW5DYWNoZUtleSA9IFwiaW5kZXhcIjtcbiAgfSBlbHNlIGlmIChjYWNoZUtleS5zdGFydHNXaXRoKFwiL1wiKSkge1xuICAgIGNsZWFuQ2FjaGVLZXkgPSBjYWNoZUtleS5zbGljZSgxKTtcbiAgfVxuICByZXR1cm4gam9pbihidWlsZElkLCBgJHtjbGVhbkNhY2hlS2V5fS5qc29uYCk7XG59XG5cbi8qKlxuICogVGhlIGZvbGRlciB1bmRlciB0aGUgYnVpbGQgcHJlZml4IHRoYXQgYCd1c2UgY2FjaGUnYCBlbnRyaWVzIGFyZSBzdG9yZWQgaW4uXG4gKiBAc2VlIHVzZUNhY2hlUzNLZXlcbiAqL1xuZXhwb3J0IGNvbnN0IFVTRV9DQUNIRV9LRVlfUFJFRklYID0gXCJfdXNlLWNhY2hlXCI7XG5cbi8qKlxuICogYHtidWlsZElkfS9fdXNlLWNhY2hlL3toYXNofS5lbnRyeWAsIHdoZXJlIGEgYGNhY2hlSGFuZGxlcnNgIGVudHJ5IGlzIHN0b3JlZC5cbiAqXG4gKiBIYXNoZWQgYmVjYXVzZSBhIGAndXNlIGNhY2hlJ2Aga2V5IGlzIHRoZSBzZXJpYWxpemVkIGFyZ3VtZW50cyBvZiB0aGUgY2FsbCBhbmRcbiAqIGhhcyBubyBsZW5ndGggbGltaXQsIHdoZXJlIGFuIFMzIGtleSBzdG9wcyBhdCAxMDI0IGJ5dGVzLiBUaGUgYC5lbnRyeWAgc3VmZml4XG4gKiByYXRoZXIgdGhhbiBgLmpzb25gIGlzIHdoYXQgbWFrZXMgYSBjb2xsaXNpb24gd2l0aCB0aGUgaW5jcmVtZW50YWwgY2FjaGVcbiAqIGltcG9zc2libGUgcmF0aGVyIHRoYW4gdW5saWtlbHk6IGV2ZXJ5IGtleSB7QGxpbmsgYnVpbGRTM0tleX0gd3JpdGVzIGVuZHMgaW5cbiAqIGAuanNvbmAsIGluY2x1ZGluZyBvbmUgZm9yIGEgcm91dGUgdGhhdCBoYXBwZW5zIHRvIGJlIG5hbWVkIGAvX3VzZS1jYWNoZS/igKZgLlxuICogU3RpbGwgdW5kZXIgdGhlIGJ1aWxkIHByZWZpeCwgc28gcG9zdC1kZXBsb3kgcHJ1bmluZyBkcm9wcyB0aGVtIHdpdGggdGhlIGJ1aWxkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlQ2FjaGVTM0tleShidWlsZElkOiBzdHJpbmcsIGtleUhhc2g6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBqb2luKGJ1aWxkSWQsIFVTRV9DQUNIRV9LRVlfUFJFRklYLCBgJHtrZXlIYXNofS5lbnRyeWApO1xufVxuXG4vKipcbiAqIFRoZSBgZHVyYXRpb25zYCBOZXh0LmpzIDE2IHBhc3NlcyBhIHRhZyByZXZhbGlkYXRpb24gZm9yIGEgcHJvZmlsZTpcbiAqIGByZXZhbGlkYXRlVGFnKFwicG9zdHNcIiwgXCJtYXhcIilgIGFycml2ZXMgYXMgYHsgZXhwaXJlOiA8dGhlIHByb2ZpbGUncyBleHBpcmU+IH1gLlxuICogQWJzZW50IGZvciBgdXBkYXRlVGFnYCBhbmQgYSBiYXJlIGByZXZhbGlkYXRlVGFnYCwgd2hpY2ggZXhwaXJlIGltbWVkaWF0ZWx5LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJldmFsaWRhdGVEdXJhdGlvbnMge1xuICBleHBpcmU/OiBudW1iZXI7XG59XG5cbi8qKlxuICogQSB0YWcncyBtYXJrZXIgcm93LCBhcyB0aW1lc3RhbXBzIGluIG1pbGxpc2Vjb25kcy4gV3JpdHRlbiBieVxuICoge0BsaW5rIG1hcmtlclVwZGF0ZX07IGVhY2ggZmllbGQgaXMgYWJzZW50IHVudGlsIGEgcmV2YWxpZGF0aW9uIG9mIHRoYXQgc2hhcGVcbiAqIGhhcyBoYXBwZW5lZC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUYWdNYXJrZXIge1xuICAvKiogRXhwaXJlZCBvdXRyaWdodDogYHVwZGF0ZVRhZ2AsIG9yIGByZXZhbGlkYXRlVGFnYCB3aXRoIG5vIHByb2ZpbGUuICovXG4gIHJldmFsaWRhdGVkQXQ/OiBudW1iZXI7XG4gIC8qKiBTdGFsZSBmcm9tIGhlcmU6IGByZXZhbGlkYXRlVGFnKHRhZywgcHJvZmlsZSlgLiAqL1xuICBzdGFsZUF0PzogbnVtYmVyO1xuICAvKiogV2hlbiB0aGUgcHJvZmlsZSdzIGBleHBpcmVgIHJ1bnMgb3V0LCB3aGljaCBtYXkgYmUgaW4gdGhlIGZ1dHVyZS4gKi9cbiAgZXhwaXJlZEF0PzogbnVtYmVyO1xufVxuXG4vKipcbiAqIFdoYXQgdGhlIHRhZyBtYXJrZXJzIHNheSBhYm91dCBhbiBlbnRyeTogdW50b3VjaGVkLCBzZXJ2ZWQgc3RhbGUgd2hpbGUgYVxuICogYmFja2dyb3VuZCByZW5kZXIgcmVwbGFjZXMgaXQsIG9yIGV4cGlyZWQgYW5kIHJlLXJlbmRlcmVkIGJlZm9yZSBhbnN3ZXJpbmcuXG4gKi9cbmV4cG9ydCB0eXBlIFJldmFsaWRhdGlvblN0YXRlID0gXCJmcmVzaFwiIHwgXCJzdGFsZVwiIHwgXCJleHBpcmVkXCI7XG5cbi8qKlxuICogV2hhdCBgbWFya2VyYCBtZWFucyBmb3IgYW4gZW50cnkgY3JlYXRlZCBhdCBgY3JlYXRlZEF0YCwgYXQgYG5vd2AuXG4gKlxuICogYGV4cGlyZWRBdGAgaW4gdGhlIGZ1dHVyZSBpcyBhIHByb2ZpbGUncyBgZXhwaXJlYCB0aGF0IGhhcyBub3QgY29tZSB5ZXQsXG4gKiBjb21wYXJlZCB0aGUgd2F5IE5leHQuanMncyBgYXJlVGFnc0V4cGlyZWRgIGRvZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXJrZXJTdGF0ZShcbiAgbWFya2VyOiBUYWdNYXJrZXIsXG4gIGNyZWF0ZWRBdDogbnVtYmVyLFxuICBub3c6IG51bWJlcixcbik6IFJldmFsaWRhdGlvblN0YXRlIHtcbiAgY29uc3QgeyByZXZhbGlkYXRlZEF0LCBleHBpcmVkQXQsIHN0YWxlQXQgfSA9IG1hcmtlcjtcbiAgaWYgKFxuICAgIChyZXZhbGlkYXRlZEF0ICE9PSB1bmRlZmluZWQgJiYgcmV2YWxpZGF0ZWRBdCA+IGNyZWF0ZWRBdCkgfHxcbiAgICAoZXhwaXJlZEF0ICE9PSB1bmRlZmluZWQgJiYgZXhwaXJlZEF0IDw9IG5vdyAmJiBleHBpcmVkQXQgPiBjcmVhdGVkQXQpXG4gICkge1xuICAgIHJldHVybiBcImV4cGlyZWRcIjtcbiAgfVxuICBpZiAoc3RhbGVBdCAhPT0gdW5kZWZpbmVkICYmIHN0YWxlQXQgPiBjcmVhdGVkQXQpIHtcbiAgICByZXR1cm4gXCJzdGFsZVwiO1xuICB9XG4gIHJldHVybiBcImZyZXNoXCI7XG59XG5cbi8qKlxuICogVGhlIGNsb2NrIGV2ZXJ5IHRhZyBtYXJrZXIgaXMgc3RhbXBlZCB3aXRoLCBhbmQgZXZlcnkgZW50cnkgdGltZXN0YW1wIGl0IGlzXG4gKiBjb21wYXJlZCBhZ2FpbnN0OiB0aGUgb25lIE5leHQuanMgc3RhbXBzIGBDYWNoZUVudHJ5LnRpbWVzdGFtcGAgd2l0aFxuICogKGBwZXJmb3JtYW5jZS50aW1lT3JpZ2luICsgcGVyZm9ybWFuY2Uubm93KClgLCBpbiBgdXNlLWNhY2hlLXdyYXBwZXIuanNgIGFuZFxuICogdGhlIGRlZmF1bHQgaGFuZGxlciksIHJhdGhlciB0aGFuIGBEYXRlLm5vdygpYC4gQm90aCBoYW5kbGVycyB3cml0ZSB0aGUgc2FtZVxuICogbWFya2VyIHJvd3MsIHNvIGJvdGggaGF2ZSB0byB1c2UgaXQ6IHR3byBjbG9ja3Mgb24gb25lIHJvdyBsZXQgdGhlIGxhc3Qgd3JpdGVyXG4gKiBkZWNpZGUgd2hpY2ggY2xvY2sgdGhlIG90aGVycyBjb21wYXJlIGFnYWluc3QsIGFuZCB0aGV5IGRyaWZ0IGFwYXJ0IGZvciBhc1xuICogbG9uZyBhcyBhIExhbWJkYSBzYW5kYm94IG9yIEZhcmdhdGUgdGFzayBsaXZlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcmtlckNsb2NrKCk6IG51bWJlciB7XG4gIHJldHVybiBwZXJmb3JtYW5jZS50aW1lT3JpZ2luICsgcGVyZm9ybWFuY2Uubm93KCk7XG59XG5cbi8qKlxuICogVGhlIG1hcmtlciBmaWVsZHMgYSB0YWcgcmV2YWxpZGF0ZWQgYXQgYG5vd2Agc2V0cy5cbiAqXG4gKiBXaXRob3V0IGBkdXJhdGlvbnNgIC0gYHVwZGF0ZVRhZ2AsIG9yIGByZXZhbGlkYXRlVGFnYCB3aXRoIG5vIHByb2ZpbGUgLSB0aGVcbiAqIHRhZydzIGVudHJpZXMgZXhwaXJlIGltbWVkaWF0ZWx5IChgcmV2YWxpZGF0ZWRBdGApLiBXaXRoIHRoZW0gdGhlIGVudHJpZXMgZ29cbiAqIHN0YWxlIG5vdyBhbmQgZXhwaXJlIGFmdGVyIHRoZSBwcm9maWxlJ3MgYGV4cGlyZWAsIHRoZSBzYW1lIHBhaXIgb2ZcbiAqIHRpbWVzdGFtcHMgTmV4dC5qcydzIGBGaWxlU3lzdGVtQ2FjaGUucmV2YWxpZGF0ZVRhZ2AgcmVjb3Jkcy4gQSBwcm9maWxlIHdpdGhcbiAqIG5vIGBleHBpcmVgIHNldHMgb25seSBgc3RhbGVBdGAsIGFuZCB3aGF0ZXZlciBgZXhwaXJlZEF0YCB0aGUgdGFnIGhhZCBzdGF5cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcmtlckZvcihcbiAgbm93OiBudW1iZXIsXG4gIGR1cmF0aW9uczogUmV2YWxpZGF0ZUR1cmF0aW9ucyB8IHVuZGVmaW5lZCxcbik6IFRhZ01hcmtlciB7XG4gIGlmICghZHVyYXRpb25zKSB7XG4gICAgcmV0dXJuIHsgcmV2YWxpZGF0ZWRBdDogbm93IH07XG4gIH1cbiAgaWYgKGR1cmF0aW9ucy5leHBpcmUgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB7IHN0YWxlQXQ6IG5vdyB9O1xuICB9XG4gIHJldHVybiB7IHN0YWxlQXQ6IG5vdywgZXhwaXJlZEF0OiBub3cgKyBkdXJhdGlvbnMuZXhwaXJlICogMTAwMCB9O1xufVxuXG5jb25zdCBNQVJLRVJfRklFTERTID0gW1wicmV2YWxpZGF0ZWRBdFwiLCBcInN0YWxlQXRcIiwgXCJleHBpcmVkQXRcIl0gYXMgY29uc3Q7XG5cbi8qKlxuICogYGV4aXN0aW5nYCB3aXRoIHRoZSBmaWVsZHMgYHVwZGF0ZWAgc2V0cywgYXMgYSB7QGxpbmsgbWFya2VyVXBkYXRlfSBsZWF2ZXNcbiAqIHRoZSByb3c6IGEgZmllbGQgYHVwZGF0ZWAgZG9lcyBub3Qgc2V0IGtlZXBzIGl0cyB2YWx1ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFwcGx5TWFya2VyKFxuICBleGlzdGluZzogVGFnTWFya2VyIHwgdW5kZWZpbmVkLFxuICB1cGRhdGU6IFRhZ01hcmtlcixcbik6IFRhZ01hcmtlciB7XG4gIGNvbnN0IG1hcmtlciA9IHsgLi4uZXhpc3RpbmcgfTtcbiAgZm9yIChjb25zdCBmaWVsZCBvZiBNQVJLRVJfRklFTERTKSB7XG4gICAgaWYgKHVwZGF0ZVtmaWVsZF0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgbWFya2VyW2ZpZWxkXSA9IHVwZGF0ZVtmaWVsZF07XG4gICAgfVxuICB9XG4gIHJldHVybiBtYXJrZXI7XG59XG5cbi8qKiBUaGUgbWFya2VyLXJvdyB1cGRhdGUgdGhhdCBzZXRzIHtAbGluayBtYXJrZXJGb3J9J3MgZmllbGRzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcmtlclVwZGF0ZShcbiAgbm93OiBudW1iZXIsXG4gIGR1cmF0aW9uczogUmV2YWxpZGF0ZUR1cmF0aW9ucyB8IHVuZGVmaW5lZCxcbik6IFBpY2s8XG4gIENvbnN0cnVjdG9yUGFyYW1ldGVyczx0eXBlb2YgVXBkYXRlSXRlbUNvbW1hbmQ+WzBdLFxuICBcIlVwZGF0ZUV4cHJlc3Npb25cIiB8IFwiRXhwcmVzc2lvbkF0dHJpYnV0ZVZhbHVlc1wiXG4+IHtcbiAgY29uc3QgbWFya2VyID0gbWFya2VyRm9yKG5vdywgZHVyYXRpb25zKTtcbiAgY29uc3QgZmllbGRzID0gTUFSS0VSX0ZJRUxEUy5maWx0ZXIoKGZpZWxkKSA9PiBtYXJrZXJbZmllbGRdICE9PSB1bmRlZmluZWQpO1xuICByZXR1cm4ge1xuICAgIFVwZGF0ZUV4cHJlc3Npb246IGBTRVQgJHtmaWVsZHMubWFwKChmaWVsZCkgPT4gYCR7ZmllbGR9ID0gOiR7ZmllbGR9YCkuam9pbihcIiwgXCIpfWAsXG4gICAgRXhwcmVzc2lvbkF0dHJpYnV0ZVZhbHVlczogT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgZmllbGRzLm1hcCgoZmllbGQpID0+IFtgOiR7ZmllbGR9YCwgeyBOOiBTdHJpbmcobWFya2VyW2ZpZWxkXSkgfV0pLFxuICAgICksXG4gIH07XG59XG5cbi8qKiBBIER5bmFtb0RCIG51bWJlciBhdHRyaWJ1dGUgYXMgYSBudW1iZXIsIG9yIGB1bmRlZmluZWRgIHdoZW4gYWJzZW50LiAqL1xuZnVuY3Rpb24gbnVtYmVyQXR0cmlidXRlKFxuICB2YWx1ZTogQXR0cmlidXRlVmFsdWUgfCB1bmRlZmluZWQsXG4pOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICByZXR1cm4gdmFsdWU/Lk4gPT09IHVuZGVmaW5lZCA/IHVuZGVmaW5lZCA6IE51bWJlcih2YWx1ZS5OKTtcbn1cblxuLyoqIFRoZSBtYXJrZXIgZmllbGRzIG9mIGEgbWFya2VyIG9yIGxvZyByb3cuICovXG5mdW5jdGlvbiBtYXJrZXJPZihpdGVtOiBSZWNvcmQ8c3RyaW5nLCBBdHRyaWJ1dGVWYWx1ZT4pOiBUYWdNYXJrZXIge1xuICByZXR1cm4ge1xuICAgIHJldmFsaWRhdGVkQXQ6IG51bWJlckF0dHJpYnV0ZShpdGVtLnJldmFsaWRhdGVkQXQpLFxuICAgIHN0YWxlQXQ6IG51bWJlckF0dHJpYnV0ZShpdGVtLnN0YWxlQXQpLFxuICAgIGV4cGlyZWRBdDogbnVtYmVyQXR0cmlidXRlKGl0ZW0uZXhwaXJlZEF0KSxcbiAgfTtcbn1cblxuLyoqIER5bmFtb0RCJ3MgY2FwIG9uIGtleXMgaW4gb25lIGBCYXRjaEdldEl0ZW1gLiAqL1xuZXhwb3J0IGNvbnN0IEJBVENIX0dFVF9NQVhfS0VZUyA9IDEwMDtcblxuLyoqXG4gKiBIb3cgb2Z0ZW4sIGF0IG1vc3QsIGFuIGluc3RhbmNlIGNhdGNoZXMgdXAgb24gcmV2YWxpZGF0aW9ucyBvdGhlciBpbnN0YW5jZXNcbiAqIHJhbiwgdW5sZXNzIGBDREtfTkVYVEpTX1RBR19SRUZSRVNIX01TYCBzYXlzIG90aGVyd2lzZTogdGhlIHN0YWxlbmVzcyB3aW5kb3dcbiAqIGZvciBhIGByZXZhbGlkYXRlVGFnYCBydW4gZWxzZXdoZXJlLiBFdmVyeSBjYWNoZSBoaXQgY2hlY2tzIGl0cyB0YWdzJ1xuICogbWFya2VycywgYW5kIGV2ZXJ5IG1hcmtlciBvZiBhIGRlcGxveW1lbnQgc2hhcmVzIG9uZSBwYXJ0aXRpb24ga2V5LCBzb1xuICogcmVhZGluZyB0aGVtIHBlciByZXF1ZXN0IGNhcHBlZCBhIHJvdXRlJ3MgY2FjaGUgaGl0cyBhdCB0aGUgcGFydGl0aW9uJ3MgcmVhZFxuICogdGhyb3VnaHB1dCAofjEsOTAwIHJlcS9zIG9uIE5leHRqc1JlZ2lvbmFsRnVuY3Rpb25zKS4gT25jZSBhIHNlY29uZCwgZnJvbSB0aGVcbiAqIHJldmFsaWRhdGlvbiBsb2csIHRoZSByZWFkcyBzY2FsZSB3aXRoIGluc3RhbmNlcyBpbnN0ZWFkIG9mIHJlcXVlc3RzIG9yIHRhZ3MuXG4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX1RBR19SRUZSRVNIX01TID0gMTAwMDtcblxuLyoqXG4gKiBUaGUgYmFyZS10YWcgbWFya2VyIHJvd3Mgb2YgdGhlIHJldmFsaWRhdGlvbiB0YWJsZSAoYHBrID0gYnVpbGRJZGAsXG4gKiBgc2sgPSB0YWdgKSwgd2hpY2ggcmVjb3JkIHdoZW4gYSB0YWcgd2FzIGxhc3QgcmV2YWxpZGF0ZWQgYW5kIGhvdy5cbiAqXG4gKiBUaGUgdGFibGUgYWxzbyBob2xkcyB0aGUgaW5jcmVtZW50YWwgY2FjaGUncyBgdGFnI3MzS2V5YCBtYXBwaW5nIHJvd3MsIHdoaWNoXG4gKiBhcmUgaXRzIG93biBidXNpbmVzcyBhbmQgc3RheSBpbiBgUzNDYWNoZUhhbmRsZXJgOiBvbmx5IHRoZSBtYXJrZXJzIG1lYW4gdGhlXG4gKiBzYW1lIHRoaW5nIHRvIGV2ZXJ5IGhhbmRsZXIuIFdoYXQgYW4gaW5zdGFuY2Uga2VlcHMgb2YgdGhlbSBiZXR3ZWVuIHJlYWRzIGlzXG4gKiB7QGxpbmsgVHJhY2tlZFRhZ01hcmtlcnN9LlxuICovXG5leHBvcnQgY2xhc3MgVGFnTWFya2VyVGFibGUge1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNsaWVudDogRHluYW1vREJDbGllbnQsXG4gICAgcHJpdmF0ZSByZWFkb25seSB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGJ1aWxkSWQ6IHN0cmluZyxcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgYHRhZ2AncyByZXZhbGlkYXRpb24gYXQgYG5vd2AuIFNlZSB7QGxpbmsgbWFya2VyVXBkYXRlfS5cbiAgICpcbiAgICogUmV0dXJucyB0aGUgcm93IGFzIHRoaXMgd3JpdGUgbGVmdCBpdCwgc28gdGhlIGluc3RhbmNlIHRoYXQgd3JvdGUgaXQgY2FuXG4gICAqIHRyYWNrIGl0IHJhdGhlciB0aGFuIHJlYWQgaXQgYmFjazogcmVhZHMgYXJlIGV2ZW50dWFsbHkgY29uc2lzdGVudCwgYW5kIGFcbiAgICogcmVhZC1iYWNrIHJhY2luZyByZXBsaWNhdGlvbiBjb3VsZCByZXR1cm4gdGhlIG1hcmtlciBmcm9tIGJlZm9yZSB0aGUgd3JpdGUuXG4gICAqL1xuICBhc3luYyB3cml0ZShcbiAgICB0YWc6IHN0cmluZyxcbiAgICBub3c6IG51bWJlcixcbiAgICBkdXJhdGlvbnM6IFJldmFsaWRhdGVEdXJhdGlvbnMgfCB1bmRlZmluZWQsXG4gICk6IFByb21pc2U8VGFnTWFya2VyIHwgdW5kZWZpbmVkPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmNsaWVudC5zZW5kKFxuICAgICAgbmV3IFVwZGF0ZUl0ZW1Db21tYW5kKHtcbiAgICAgICAgVGFibGVOYW1lOiB0aGlzLnRhYmxlTmFtZSxcbiAgICAgICAgS2V5OiB7XG4gICAgICAgICAgcGs6IHsgUzogdGhpcy5idWlsZElkIH0sXG4gICAgICAgICAgc2s6IHsgUzogdGFnIH0sXG4gICAgICAgIH0sXG4gICAgICAgIC4uLm1hcmtlclVwZGF0ZShub3csIGR1cmF0aW9ucyksXG4gICAgICAgIFJldHVyblZhbHVlczogXCJBTExfTkVXXCIsXG4gICAgICB9KSxcbiAgICApO1xuICAgIHJldHVybiByZXNwb25zZT8uQXR0cmlidXRlcyA/IG1hcmtlck9mKHJlc3BvbnNlLkF0dHJpYnV0ZXMpIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBtYXJrZXIgcm93cyBmb3IgYHRhZ3NgIHRoYXQgZXhpc3QsIGJ5IHRhZywgaW4gb25lIGBCYXRjaEdldEl0ZW1gIHBlclxuICAgKiB7QGxpbmsgQkFUQ0hfR0VUX01BWF9LRVlTfSB0YWdzIHJhdGhlciB0aGFuIGEgYEdldEl0ZW1gIGVhY2g6IGEgcGFnZVxuICAgKiBjYXJyaWVzIGl0cyB3aG9sZSBpbXBsaWNpdCBgX05fVF8v4oCmYCBjaGFpbiBwbHVzIHRoZSBhcHAncyBvd24gdGFncywgYVxuICAgKiBwYWdlIHdpdGggYSBmZXcgZmV0Y2hlcyBjaGVja3MgZWFjaCBvZiB0aGVtIHRvbywgYW5kIGV2ZXJ5IG9uZSBpcyBvbiB0aGVcbiAgICogcmVxdWVzdCBwYXRoLiBBIHRhZyB3aXRoIG5vIHJvdyBpcyBhYnNlbnQgZnJvbSB0aGUgcmVzdWx0LlxuICAgKi9cbiAgYXN5bmMgcmVhZCh0YWdzOiBzdHJpbmdbXSk6IFByb21pc2U8TWFwPHN0cmluZywgVGFnTWFya2VyPj4ge1xuICAgIGNvbnN0IHsgdGFibGVOYW1lLCBidWlsZElkIH0gPSB0aGlzO1xuICAgIGNvbnN0IHVuaXF1ZSA9IEFycmF5LmZyb20obmV3IFNldCh0YWdzKSk7XG4gICAgY29uc3QgbWFya2VycyA9IG5ldyBNYXA8c3RyaW5nLCBUYWdNYXJrZXI+KCk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHVuaXF1ZS5sZW5ndGg7IGkgKz0gQkFUQ0hfR0VUX01BWF9LRVlTKSB7XG4gICAgICBsZXQga2V5czogUmVjb3JkPHN0cmluZywgQXR0cmlidXRlVmFsdWU+W10gfCB1bmRlZmluZWQgPSB1bmlxdWVcbiAgICAgICAgLnNsaWNlKGksIGkgKyBCQVRDSF9HRVRfTUFYX0tFWVMpXG4gICAgICAgIC5tYXAoKHRhZykgPT4gKHsgcGs6IHsgUzogYnVpbGRJZCB9LCBzazogeyBTOiB0YWcgfSB9KSk7XG4gICAgICAvLyBgVW5wcm9jZXNzZWRLZXlzYCBpcyBEeW5hbW9EQiBkZWNsaW5pbmcgcGFydCBvZiB0aGUgYmF0Y2ggdW5kZXIgbG9hZDtcbiAgICAgIC8vIGEgbWFya2VyIGxlZnQgdW5yZWFkIGlzIGEgcmV2YWxpZGF0aW9uIG1pc3NlZCwgc28gaXQgaXMgYXNrZWQgYWdhaW4uXG4gICAgICBmb3IgKGxldCBhdHRlbXB0ID0gMDsga2V5cz8ubGVuZ3RoICYmIGF0dGVtcHQgPCAzOyBhdHRlbXB0KyspIHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2U6IEJhdGNoR2V0SXRlbUNvbW1hbmRPdXRwdXQgPSBhd2FpdCB0aGlzLmNsaWVudC5zZW5kKFxuICAgICAgICAgIG5ldyBCYXRjaEdldEl0ZW1Db21tYW5kKHtcbiAgICAgICAgICAgIFJlcXVlc3RJdGVtczoge1xuICAgICAgICAgICAgICBbdGFibGVOYW1lXToge1xuICAgICAgICAgICAgICAgIEtleXM6IGtleXMsXG4gICAgICAgICAgICAgICAgUHJvamVjdGlvbkV4cHJlc3Npb246IFwic2ssIHJldmFsaWRhdGVkQXQsIHN0YWxlQXQsIGV4cGlyZWRBdFwiLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICAgICAgZm9yIChjb25zdCBpdGVtIG9mIHJlc3BvbnNlLlJlc3BvbnNlcz8uW3RhYmxlTmFtZV0gPz8gW10pIHtcbiAgICAgICAgICBjb25zdCB0YWcgPSBpdGVtLnNrPy5TO1xuICAgICAgICAgIGlmICh0YWcgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgbWFya2Vycy5zZXQodGFnLCBtYXJrZXJPZihpdGVtKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGtleXMgPSByZXNwb25zZS5VbnByb2Nlc3NlZEtleXM/Llt0YWJsZU5hbWVdPy5LZXlzO1xuICAgICAgfVxuICAgICAgaWYgKGtleXM/Lmxlbmd0aCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYER5bmFtb0RCIGxlZnQgJHtrZXlzLmxlbmd0aH0gdGFnIG1hcmtlcnMgdW5yZWFkIGFmdGVyIHJldHJ5aW5nYCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG1hcmtlcnM7XG4gIH1cbn1cblxuLyoqXG4gKiBIb3cgbG9uZyBhIHJldmFsaWRhdGlvbiBsb2cgcm93IGlzIGtlcHQgKGB0dGxgLCBlcG9jaCBzZWNvbmRzKS4gRHluYW1vREIgbmV2ZXJcbiAqIGRlbGV0ZXMgYW4gaXRlbSBiZWZvcmUgaXRzIFRUTCwgb25seSBzb21lIHRpbWUgYWZ0ZXIsIHNvIGEgcmVhZGVyIHRoYXQgbGFzdFxuICogcXVlcmllZCBsZXNzIHRoYW4gdGhpcyBsb25nIGFnbyAobGVzcyBhIG1hcmdpbiBmb3Igd3JpdGVycycgY2xvY2tzKSBpcyBzdXJlXG4gKiB0byBmaW5kIGV2ZXJ5IHJvdyBpdCBoYXMgbm90IHNlZW4geWV0LlxuICovXG5leHBvcnQgY29uc3QgUkVWQUxJREFUSU9OX0xPR19UVExfTVMgPSAxNSAqIDYwICogMTAwMDtcblxuLyoqIFRoZSBtb3N0IGBRdWVyeWAgcGFnZXMgb25lIHtAbGluayBSZXZhbGlkYXRpb25Mb2cucXVlcnl9IHJlYWRzLiAqL1xuZXhwb3J0IGNvbnN0IFJFVkFMSURBVElPTl9MT0dfTUFYX1BBR0VTID0gNTtcblxuLyoqIEhvdyBtYW55IHNvcnQga2V5cyB7QGxpbmsgUmV2YWxpZGF0aW9uTG9nLnB1dH0gdHJpZXMgYmVmb3JlIGdpdmluZyB1cC4gKi9cbmNvbnN0IExPR19QVVRfQVRURU1QVFMgPSA1O1xuXG4vKiogRGlnaXRzIGEgbG9nIHJvdydzIHRpbWVzdGFtcCBpcyB6ZXJvLXBhZGRlZCB0bywgc28gc29ydCBrZXlzIHNvcnQgYnkgdGltZS4gKi9cbmNvbnN0IExPR19TS19ESUdJVFMgPSAxNTtcblxuLyoqIEEgcmV2YWxpZGF0aW9uIHJlYWQgYmFjayBmcm9tIHRoZSBsb2cuICovXG5leHBvcnQgaW50ZXJmYWNlIFJldmFsaWRhdGlvbkxvZ1JvdyB7XG4gIC8qKiBUaGUgcm93J3Mgc29ydCBrZXk6IHVuaXF1ZSBwZXIgcmV2YWxpZGF0aW9uIG9mIGEgdGFnLiAqL1xuICBzazogc3RyaW5nO1xuICAvKiogV2hlbiBpdCB3YXMgd3JpdHRlbiwgb24gdGhlIHdyaXRlcidzIGBEYXRlLm5vdygpYC4gKi9cbiAgYXQ6IG51bWJlcjtcbiAgdGFnOiBzdHJpbmc7XG4gIC8qKiBUaGUgbWFya2VyIGZpZWxkcyB0aGUgcmV2YWxpZGF0aW9uIHNldCwgYXMge0BsaW5rIG1hcmtlckZvcn0gcmV0dXJucyB0aGVtLiAqL1xuICBtYXJrZXI6IFRhZ01hcmtlcjtcbn1cblxuLyoqXG4gKiBUaGUgcmV2YWxpZGF0aW9uIGxvZzogb25lIHJvdyBwZXIgdGFnIHJldmFsaWRhdGlvbiAoYHBrID0gPGJ1aWxkSWQ+I2xvZ2AsXG4gKiBgc2sgPSA8RGF0ZS5ub3coKSwgemVyby1wYWRkZWQ+Izx0YWc+YCksIHdoaWNoIGV4cGlyZXMgYWZ0ZXJcbiAqIHtAbGluayBSRVZBTElEQVRJT05fTE9HX1RUTF9NU30uXG4gKlxuICogVGhlIG1hcmtlciByb3dzIHN0YXkgdGhlIHNvdXJjZSBvZiB0cnV0aC4gVGhlIGxvZyBleGlzdHMgc28gYW4gaW5zdGFuY2VcbiAqIGNhbiBhc2sgXCJ3aGF0IHdhcyByZXZhbGlkYXRlZCBzaW5jZSBJIGxhc3QgbG9va2VkP1wiIGluIG9uZSBgUXVlcnlgLCBpbnN0ZWFkXG4gKiBvZiByZS1yZWFkaW5nIGV2ZXJ5IHRhZyBpdCB0cmFja3MgdG8gZmluZCBvdXQgdGhhdCBhbG1vc3Qgbm9uZSBjaGFuZ2VkLiBFdmVyeVxuICogbWFya2VyIHJvdyBvZiBhIGRlcGxveW1lbnQgc2hhcmVzIG9uZSBwYXJ0aXRpb24sIGFuZCB0aG9zZSByZS1yZWFkcyBmcm9tIGFcbiAqIGhhbmRmdWwgb2YgYnVzeSBpbnN0YW5jZXMgd2VyZSBlbm91Z2ggdG8gdGhyb3R0bGUgaXQuXG4gKlxuICogVGhlIHNvcnQga2V5J3MgdGltZXN0YW1wIGlzIHRoZSB3cml0ZXIncyB3YWxsIGNsb2NrIChgRGF0ZS5ub3coKWApLCBub3QgdGhlXG4gKiBwZXJmb3JtYW5jZSBjbG9jayAoe0BsaW5rIG1hcmtlckNsb2NrfSkgdGhlIG1hcmtlciB2YWx1ZXMgYXJlIHN0YW1wZWQgd2l0aCBieSBib3RoXG4gKiBoYW5kbGVyczogaXQgb25seSBvcmRlcnMgcm93cyBmb3IgcmVhZGVycycgY3Vyc29ycywgd2hpY2ggYXJlIG9uIHRoZWlyIG93blxuICogd2FsbCBjbG9ja3MsIGFuZCBpcyBuZXZlciBjb21wYXJlZCB3aXRoIGFuIGVudHJ5J3MgdGltZXN0YW1wLlxuICovXG5leHBvcnQgY2xhc3MgUmV2YWxpZGF0aW9uTG9nIHtcbiAgcHJpdmF0ZSByZWFkb25seSBwazogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY2xpZW50OiBEeW5hbW9EQkNsaWVudCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHRhYmxlTmFtZTogc3RyaW5nLFxuICAgIGJ1aWxkSWQ6IHN0cmluZyxcbiAgKSB7XG4gICAgdGhpcy5wayA9IGAke2J1aWxkSWR9I2xvZ2A7XG4gIH1cblxuICAvKipcbiAgICogUmVjb3JkIHRoYXQgYHRhZ2Agd2FzIHJldmFsaWRhdGVkIGF0IGBhdGAgKGBEYXRlLm5vdygpYCksIHNldHRpbmcgYG1hcmtlcmAuXG4gICAqXG4gICAqIFR3byByZXZhbGlkYXRpb25zIG9mIGB0YWdgIGluIHRoZSBzYW1lIG1pbGxpc2Vjb25kIHdvdWxkIHNoYXJlIGEgc29ydCBrZXksXG4gICAqIGFuZCB0aGUgc2Vjb25kIHdvdWxkIG92ZXJ3cml0ZSB0aGUgZmlyc3QuIFNvIHRoZSByb3cgaXMgb25seSB3cml0dGVuIHdoZXJlXG4gICAqIGl0cyBrZXkgaXMgZnJlZSwgYW5kIG9uIGEgY29sbGlzaW9uIGl0IG1vdmVzIHRvIHRoZSBuZXh0IG1pbGxpc2Vjb25kLCB1cFxuICAgKiB0byB7QGxpbmsgTE9HX1BVVF9BVFRFTVBUU30gdGltZXMuXG4gICAqL1xuICBhc3luYyBwdXQodGFnOiBzdHJpbmcsIGF0OiBudW1iZXIsIG1hcmtlcjogVGFnTWFya2VyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IDsgYXR0ZW1wdCsrKSB7XG4gICAgICBjb25zdCBpdGVtOiBSZWNvcmQ8c3RyaW5nLCBBdHRyaWJ1dGVWYWx1ZT4gPSB7XG4gICAgICAgIHBrOiB7IFM6IHRoaXMucGsgfSxcbiAgICAgICAgc2s6IHsgUzogYCR7bG9nU2tQcmVmaXgoYXQpfSMke3RhZ31gIH0sXG4gICAgICAgIHR0bDogeyBOOiBTdHJpbmcoTWF0aC5jZWlsKChhdCArIFJFVkFMSURBVElPTl9MT0dfVFRMX01TKSAvIDEwMDApKSB9LFxuICAgICAgfTtcbiAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgTUFSS0VSX0ZJRUxEUykge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IG1hcmtlcltmaWVsZF07XG4gICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgaXRlbVtmaWVsZF0gPSB7IE46IFN0cmluZyh2YWx1ZSkgfTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5jbGllbnQuc2VuZChcbiAgICAgICAgICBuZXcgUHV0SXRlbUNvbW1hbmQoe1xuICAgICAgICAgICAgVGFibGVOYW1lOiB0aGlzLnRhYmxlTmFtZSxcbiAgICAgICAgICAgIEl0ZW06IGl0ZW0sXG4gICAgICAgICAgICBDb25kaXRpb25FeHByZXNzaW9uOiBcImF0dHJpYnV0ZV9ub3RfZXhpc3RzKHNrKVwiLFxuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgKGVycm9yIGFzIEVycm9yIHwgdW5kZWZpbmVkKT8ubmFtZSAhPT1cbiAgICAgICAgICAgIFwiQ29uZGl0aW9uYWxDaGVja0ZhaWxlZEV4Y2VwdGlvblwiIHx8XG4gICAgICAgICAgYXR0ZW1wdCA+PSBMT0dfUFVUX0FUVEVNUFRTXG4gICAgICAgICkge1xuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgICAgIGF0ID0gTWF0aC5mbG9vcihhdCkgKyAxO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgcm93cyB3cml0dGVuIGF0IG9yIGFmdGVyIGBzaW5jZWAgKGBEYXRlLm5vdygpYCksIG9sZGVzdCBmaXJzdC5cbiAgICogYHRydW5jYXRlZGAgd2hlbiB0aGVyZSB3ZXJlIG1vcmUgdGhhbiB7QGxpbmsgUkVWQUxJREFUSU9OX0xPR19NQVhfUEFHRVN9XG4gICAqIHBhZ2VzIG9mIHRoZW0sIGFuZCBgcm93c2AgaXMgb25seSB0aGUgc3RhcnQuXG4gICAqXG4gICAqIEV2ZW50dWFsbHkgY29uc2lzdGVudDogYSByb3cgd3JpdHRlbiBhIG1vbWVudCBhZ28gbWF5IG5vdCBzaG93IHlldCwgd2hpY2hcbiAgICogaXMgd2hhdCB0aGUgcmVhZGVyJ3MgbG9va2JhY2sgaXMgZm9yLlxuICAgKi9cbiAgYXN5bmMgcXVlcnkoXG4gICAgc2luY2U6IG51bWJlcixcbiAgKTogUHJvbWlzZTx7IHJvd3M6IFJldmFsaWRhdGlvbkxvZ1Jvd1tdOyB0cnVuY2F0ZWQ6IGJvb2xlYW4gfT4ge1xuICAgIGNvbnN0IHJvd3M6IFJldmFsaWRhdGlvbkxvZ1Jvd1tdID0gW107XG4gICAgbGV0IHN0YXJ0S2V5OiBSZWNvcmQ8c3RyaW5nLCBBdHRyaWJ1dGVWYWx1ZT4gfCB1bmRlZmluZWQ7XG4gICAgZm9yIChsZXQgcGFnZSA9IDA7IHBhZ2UgPCBSRVZBTElEQVRJT05fTE9HX01BWF9QQUdFUzsgcGFnZSsrKSB7XG4gICAgICBjb25zdCByZXNwb25zZTogUXVlcnlDb21tYW5kT3V0cHV0ID0gYXdhaXQgdGhpcy5jbGllbnQuc2VuZChcbiAgICAgICAgbmV3IFF1ZXJ5Q29tbWFuZCh7XG4gICAgICAgICAgVGFibGVOYW1lOiB0aGlzLnRhYmxlTmFtZSxcbiAgICAgICAgICBLZXlDb25kaXRpb25FeHByZXNzaW9uOiBcInBrID0gOnBrIEFORCBzayA+PSA6c2luY2VcIixcbiAgICAgICAgICBFeHByZXNzaW9uQXR0cmlidXRlVmFsdWVzOiB7XG4gICAgICAgICAgICBcIjpwa1wiOiB7IFM6IHRoaXMucGsgfSxcbiAgICAgICAgICAgIFwiOnNpbmNlXCI6IHsgUzogbG9nU2tQcmVmaXgoTWF0aC5tYXgoMCwgc2luY2UpKSB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgUHJvamVjdGlvbkV4cHJlc3Npb246IFwic2ssIHJldmFsaWRhdGVkQXQsIHN0YWxlQXQsIGV4cGlyZWRBdFwiLFxuICAgICAgICAgIEV4Y2x1c2l2ZVN0YXJ0S2V5OiBzdGFydEtleSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgICAgZm9yIChjb25zdCBpdGVtIG9mIHJlc3BvbnNlLkl0ZW1zID8/IFtdKSB7XG4gICAgICAgIGNvbnN0IHNrID0gaXRlbS5zaz8uUztcbiAgICAgICAgLy8gYDxkaWdpdHM+Izx0YWc+YDogdGhlIHRhZyBpcyBldmVyeXRoaW5nIGFmdGVyIHRoZSBmaXhlZC13aWR0aFxuICAgICAgICAvLyB0aW1lc3RhbXAsIGAjYHMgaW5jbHVkZWQuXG4gICAgICAgIGlmIChzayA9PT0gdW5kZWZpbmVkIHx8IHNrW0xPR19TS19ESUdJVFNdICE9PSBcIiNcIikge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHJvd3MucHVzaCh7XG4gICAgICAgICAgc2ssXG4gICAgICAgICAgYXQ6IE51bWJlcihzay5zbGljZSgwLCBMT0dfU0tfRElHSVRTKSksXG4gICAgICAgICAgdGFnOiBzay5zbGljZShMT0dfU0tfRElHSVRTICsgMSksXG4gICAgICAgICAgbWFya2VyOiBtYXJrZXJPZihpdGVtKSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBzdGFydEtleSA9IHJlc3BvbnNlLkxhc3RFdmFsdWF0ZWRLZXk7XG4gICAgICBpZiAoIXN0YXJ0S2V5KSB7XG4gICAgICAgIHJldHVybiB7IHJvd3MsIHRydW5jYXRlZDogZmFsc2UgfTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgcm93cywgdHJ1bmNhdGVkOiB0cnVlIH07XG4gIH1cbn1cblxuZnVuY3Rpb24gbG9nU2tQcmVmaXgoYXQ6IG51bWJlcik6IHN0cmluZyB7XG4gIHJldHVybiBTdHJpbmcoTWF0aC5mbG9vcihhdCkpLnBhZFN0YXJ0KExPR19TS19ESUdJVFMsIFwiMFwiKTtcbn1cblxuLyoqXG4gKiBIb3cgZmFyIGJlaGluZCB0aGUgbGFzdCBxdWVyeSdzIHN0YXJ0IHRoZSBuZXh0IG9uZSBzdGFydHMgcmVhZGluZyB0aGUgbG9nOlxuICogdGhlIHJvb20gZm9yIHRoZSBgUXVlcnlgIGJlaW5nIGV2ZW50dWFsbHkgY29uc2lzdGVudCBhbmQgZm9yIHdyaXRlcnMnIGNsb2Nrc1xuICogcnVubmluZyBiZWhpbmQgdGhlIHJlYWRlcidzLiBSb3dzIGluc2lkZSBpdCBhcmUgcmVhZCBhZ2FpbiwgYW5kIGRyb3BwZWQgYXNcbiAqIGFscmVhZHkgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGNvbnN0IFJFVkFMSURBVElPTl9MT0dfTE9PS0JBQ0tfTVMgPSA1MDAwO1xuXG4vKipcbiAqIFRoZSBsb25nZXN0IHtAbGluayBUcmFja2VkVGFnTWFya2Vyc30gdHJ1c3RzIHRoZSBsb2cgYWxvbmUgZm9yIGEgdGFnIGJlZm9yZVxuICogcmVhZGluZyBpdHMgbWFya2VyIHJvdyBhZ2Fpbi4gVGhlIGxvZyBpcyB0aGUgZmFzdCBwYXRoLCBidXQgdGhlIG1hcmtlciByb3dzXG4gKiBhcmUgdGhlIHNvdXJjZSBvZiB0cnV0aDogYSBsb2cgcm93IHdob3NlIHdyaXRlIGZhaWxlZCB3b3VsZCBvdGhlcndpc2UgYmVcbiAqIG1pc3NlZCBmb3IgYXMgbG9uZyBhcyB0aGUgdGFnIHN0YXlzIHRyYWNrZWQuXG4gKlxuICogUm9sbGluZywgbm90IGFsbCBhdCBvbmNlOiBlYWNoIHJlZnJlc2ggcmUtcmVhZHMgYXQgbW9zdFxuICoge0BsaW5rIEJBVENIX0dFVF9NQVhfS0VZU30gb2YgdGhlIHRhZ3MgZHVlLCBvbGRlc3QgZmlyc3QuIFJlLXJlYWRpbmcgdGhlbSBhbGxcbiAqIHRvZ2V0aGVyIGNvc3QgfjUwMCBSQ1UgYXQgMTAwMCB0YWdzIC0gYSBmbGVldCBzdGFydGVkIGJ5IG9uZSBsb2FkIHRlc3QgZGlkIGl0XG4gKiBpbiB0aGUgc2FtZSBtaW51dGUsIDEyLDgwMCBSQ1UsIGFuZCB0aHJvdHRsZWQgLSBhbmQgd291bGQgYmUgfjUsMDAwIFJDVSBhdFxuICoge0BsaW5rIERFRkFVTFRfTUFYX1RSQUNLRURfVEFHU30sIHBhc3Qgd2hhdCB0aGUgb25lIHBhcnRpdGlvbiBzZXJ2ZXMgaW4gYVxuICogc2Vjb25kLiBTcHJlYWQgb3V0LCAxMCwwMDAgdHJhY2tlZCB0YWdzIGNvc3QgfjggUkNVIGEgc2Vjb25kIHBlciBpbnN0YW5jZS5cbiAqXG4gKiBFYWNoIHRhZyBpcyBkdWUgYXQgYSByYW5kb20gNzUtMTAwJSBvZiB0aGlzIGFmdGVyIGl0IHdhcyBsYXN0IHJlYWQsIHNvIHRhZ3NcbiAqIGZpcnN0IHJlYWQgdG9nZXRoZXIgLSBhbiBpbnN0YW5jZSB3YXJtaW5nIHVwIC0gZG8gbm90IGFsbCBjb21lIGR1ZSB0b2dldGhlclxuICogYWdhaW4gZXZlcnkgaW50ZXJ2YWw6IHRoZSBsb2FkIHRlc3QgdGhhdCBtZWFzdXJlZCB0aGUgcm9sbGluZyByZS1yZWFkIHNhd1xuICogaXRzIHdhcm0tdXAncyByZWFkcyByZXR1cm4gYXMgYSAzMC0zNiBSQ1UvcyBidW1wIHRlbiBtaW51dGVzIGxhdGVyLlxuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9UQUdfUkVTWU5DX01TID0gMTAgKiA2MCAqIDEwMDA7XG5cbi8qKiBUaGUgZnJhY3Rpb24gb2Yge0BsaW5rIERFRkFVTFRfVEFHX1JFU1lOQ19NU30gYSB0YWcgbWF5IGNvbWUgZHVlIGVhcmx5IGJ5LiAqL1xuY29uc3QgVEFHX1JFU1lOQ19KSVRURVIgPSAwLjI1O1xuXG4vKipcbiAqIEhvdyBsb25nIHNpbmNlIHRoZSBsYXN0IHN1Y2Nlc3NmdWwgbG9nIHF1ZXJ5IHRoZSBsb2cgY2FuIHN0aWxsIGJlIHRydXN0ZWQgdG9cbiAqIGhvbGQgZXZlcnkgcm93IG5vdCByZWFkIHlldDogaXRzIFRUTCBsZXNzIGEgbWFyZ2luIGZvciB3cml0ZXJzJyBjbG9ja3MuIFBhc3RcbiAqIGl0IC0gYSBMYW1iZGEgZnJvemVuIGJldHdlZW4gaW52b2NhdGlvbnMsIGEgcnVuIG9mIGZhaWxlZCBxdWVyaWVzIC0gdGhlXG4gKiB0cmFja2VkIG1hcmtlcnMgYXJlIGZvcmdvdHRlbiwgdG8gYmUgcmVhZCBhZ2FpbiBhcyB0aGV5IGFyZSBuZWVkZWQsIGFuZCB0aGVcbiAqIGxvZyBpcyBmb2xsb3dlZCBmcm9tIHRoZXJlLlxuICovXG5leHBvcnQgY29uc3QgTUFYX1JFVkFMSURBVElPTl9MT0dfR0FQX01TID1cbiAgUkVWQUxJREFUSU9OX0xPR19UVExfTVMgLSA1ICogNjAgKiAxMDAwO1xuXG4vKipcbiAqIFRoZSBtb3N0IHRhZ3Mgb25lIGluc3RhbmNlIHRyYWNrcy4gUGFzdCBpdCB0aGUgbGVhc3QgcmVjZW50bHkgdXNlZCBpc1xuICogZm9yZ290dGVuLCB3aGljaCBjb3N0cyBhIHJlYWQgdGhlIG5leHQgdGltZSBpdCBpcyBuZWVkZWQ6IGFuIHVudHJhY2tlZCB0YWdcbiAqIGlzIHJlYWQgYmVmb3JlIGl0IGlzIHRydXN0ZWQuXG4gKlxuICogQSB0cmFja2VkIHRhZyBjb3N0cyBtZW1vcnkgKH4yIE1CIGF0IHRoaXMgYm91bmQpIGFuZCBpdHMgc2hhcmUgb2YgdGhlIHJvbGxpbmdcbiAqIHJlLXJlYWQsIG5vdCBhIHJlYWQgZXZlcnkgcmVmcmVzaCwgc28gdGhlIGJvdW5kIGlzIHNldCBieSBob3cgbWFueSB0YWdzIGFuXG4gKiBpbnN0YW5jZSByZWFsbHkgdXNlcy4gRXZlcnkgcGF0aCBpcyBhIHRhZyBvZiBpdHMgb3duIChgX05fVF8vPHBhdGg+YCksIGFuZCBhdFxuICogMTAwMCBhbiBhcHAgb2YgMTAwMCB0YWdnZWQgcGFnZXMga2VwdCBldmljdGluZyB3aGF0IGl0IHdhcyBhYm91dCB0byBuZWVkOlxuICogaGFsZiBpdHMgcmVxdWVzdHMgcmUtcmVhZCBhIG1hcmtlci5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfTUFYX1RSQUNLRURfVEFHUyA9IDEwXzAwMDtcblxuLyoqXG4gKiBUaGUgcmV2YWxpZGF0aW9uIHRhYmxlJ3MgbWFya2VyIHJvd3MgYW5kIGl0cyBsb2csIHdoaWNoIGFyZSBvbmx5IGV2ZXIgdXNlZFxuICogdG9nZXRoZXIsIG9yIG5laXRoZXIgZm9yIHRhZ3MgbG9jYWwgdG8gdGhpcyBwcm9jZXNzLlxuICovXG5leHBvcnQgdHlwZSBUYWdUYWJsZSA9XG4gIHwgeyBtYXJrZXJzOiBUYWdNYXJrZXJUYWJsZTsgbG9nOiBSZXZhbGlkYXRpb25Mb2cgfVxuICB8IHsgbWFya2Vycz86IHVuZGVmaW5lZDsgbG9nPzogdW5kZWZpbmVkIH07XG5cbi8qKiBIb3cge0BsaW5rIFRyYWNrZWRUYWdNYXJrZXJzfSBpcyBidWlsdC4gKi9cbmV4cG9ydCB0eXBlIFRyYWNrZWRUYWdNYXJrZXJzT3B0aW9ucyA9IFRhZ1RhYmxlICYge1xuICAvKipcbiAgICogSG93IG9mdGVuLCBhdCBtb3N0LCB7QGxpbmsgVHJhY2tlZFRhZ01hcmtlcnMucmVmcmVzaH0gcmVhZHMgYW55dGhpbmcuXG4gICAqIEBkZWZhdWx0IERFRkFVTFRfVEFHX1JFRlJFU0hfTVNcbiAgICovXG4gIHJlZnJlc2hJbnRlcnZhbE1zPzogbnVtYmVyO1xuICBtYXhUcmFja2VkVGFncz86IG51bWJlcjtcbiAgLyoqIEBzZWUgREVGQVVMVF9UQUdfUkVTWU5DX01TICovXG4gIHJlc3luY0ludGVydmFsTXM/OiBudW1iZXI7XG4gIC8qKiBUaGUgd2FsbCBjbG9jayB0aGUgbG9nJ3MgY3Vyc29yIGFuZCB0aGUgaW50ZXJ2YWxzIGFyZSBrZXB0IG9uLiAqL1xuICBjbG9jaz86ICgpID0+IG51bWJlcjtcbiAgLyoqIGBNYXRoLnJhbmRvbWAsIGZvciB3aGVuIGVhY2ggdGFnJ3MgcmUtcmVhZCBjb21lcyBkdWUuICovXG4gIHJhbmRvbT86ICgpID0+IG51bWJlcjtcbiAgZGVidWc/OiAobWVzc2FnZTogc3RyaW5nKSA9PiB2b2lkO1xufTtcblxuLyoqXG4gKiBPbmUgaW5zdGFuY2UncyBjb3B5IG9mIHRoZSBtYXJrZXIgcm93cyBvZiB0aGUgdGFncyBpdCBoYXMgbmVlZGVkLCBrZXB0XG4gKiBjdXJyZW50IHRocm91Z2ggdGhlIHtAbGluayBSZXZhbGlkYXRpb25Mb2d9OiB0aGUgcHJvY2VzcydzIG9uZSB0YWcgbWFuaWZlc3RcbiAqIChgc2hhcmVkVGFnTWFuaWZlc3RgKSwgZm9yIHRoZSBgJ3VzZSBjYWNoZSdgIGhhbmRsZXJzIGFuZCB0aGUgaW5jcmVtZW50YWxcbiAqIGNhY2hlIGFsaWtlLlxuICpcbiAqIE5leHQuanMncyBidWlsdC1pbiBgJ3VzZSBjYWNoZSdgIGhhbmRsZXIga2VlcHMgdGFncyBpbiBhIG1vZHVsZS1sZXZlbCBtYXBcbiAqIChgdGFncy1tYW5pZmVzdC5leHRlcm5hbC5qc2ApIHRoYXQgb25seSBpdHMgb3duIGB1cGRhdGVUYWdzYCB3cml0ZXMsIGFuZCBpdHNcbiAqIGByZWZyZXNoVGFnc2AgaXMgYSBuby1vcCwgc28gYSBgcmV2YWxpZGF0ZVRhZ2Agb24gb25lIGluc3RhbmNlIG5ldmVyIHJlYWNoZXNcbiAqIHRoZSBvdGhlcnM6IHRoZXkga2VlcCBzZXJ2aW5nIHRoZSByZXZhbGlkYXRlZCBlbnRyeSwgaW5jbHVkaW5nIGluc2lkZSBwYWdlc1xuICogdGhhdCBhcmUgYmVpbmcgcmUtcmVuZGVyZWQgKmJlY2F1c2UqIG9mIHRoYXQgcmV2YWxpZGF0aW9uLiBUaGVcbiAqIGBjYWNoZUhhbmRsZXJzYCBpbnRlcmZhY2UncyBhbnN3ZXIgaXMgYHJlZnJlc2hUYWdzYCwgXCJjYWxsZWQgYmVmb3JlIHN0YXJ0aW5nXG4gKiBhIG5ldyByZXF1ZXN0IOKApiB0byByZWZyZXNoIHRoZSBsb2NhbCB0YWdzIG1hbmlmZXN0XCIsIGFuZCB0aGlzIGlzIHRoYXRcbiAqIG1hbmlmZXN0LCBiYWNrZWQgYnkgdGhlIHNhbWUgbWFya2VyIHJvd3MgdGhlIGluY3JlbWVudGFsIGNhY2hlJ3NcbiAqIGByZXZhbGlkYXRlVGFnYCB3cml0ZXMgKGBwayA9IGJ1aWxkSWRgLCBgc2sgPSB0YWdgKS5cbiAqXG4gKiBUaGUgY29zdCBpcyBib3VuZGVkIHBlciBpbnN0YW5jZSwgbm90IHBlciByZXF1ZXN0OlxuICogLSB7QGxpbmsgZW5zdXJlfSByZWFkcyBhIHRhZydzIG1hcmtlciB0aGUgZmlyc3QgdGltZSBpdCBpcyBuZWVkZWQgYW5kIG5vdFxuICogICBhZ2FpbiB1bnRpbCBpdCBpcyBldmljdGVkLCBzbyBhIHRhZyBjb3N0cyBvbmUgcmVhZCBwZXIgaW5zdGFuY2UsIG5vdCBvbmVcbiAqICAgcGVyIHJlcXVlc3QuXG4gKiAtIHtAbGluayByZWZyZXNofSwgYXQgbW9zdCBvbmNlIHBlciBgcmVmcmVzaEludGVydmFsTXNgLCBzZW5kcyBvbmUgYFF1ZXJ5YFxuICogICBmb3IgdGhlIGxvZyByb3dzIHdyaXR0ZW4gc2luY2UgdGhlIGxhc3Qgb25lLCBhbmQgYXBwbGllcyB0aG9zZSBvZiB0YWdzXG4gKiAgIHRoaXMgaW5zdGFuY2UgdHJhY2tzLiBDb25jdXJyZW50IGNhbGxlcnMgc2hhcmUgaXQuIEFsb25nc2lkZSwgaXQgcmUtcmVhZHNcbiAqICAgdGhlIG1hcmtlcnMgb2YgdXAgdG8ge0BsaW5rIEJBVENIX0dFVF9NQVhfS0VZU30gdGFncyBub3QgcmVhZCBmb3JcbiAqICAge0BsaW5rIERFRkFVTFRfVEFHX1JFU1lOQ19NU30sIGluIG9uZSBgQmF0Y2hHZXRJdGVtYC5cbiAqIEEgcmV2YWxpZGF0aW9uIG9uIGFub3RoZXIgaW5zdGFuY2UgaXMgdGhlcmVmb3JlIHNlZW4gd2l0aGluXG4gKiBgcmVmcmVzaEludGVydmFsTXNgIChwbHVzIHRoZSBxdWVyeSBpdHNlbGYpLiBUaGUgaW5zdGFuY2UgdGhhdCByYW4gaXQgYXBwbGllc1xuICogaXQgaXRzZWxmLCBhdCBvbmNlLCB3aXRoIHtAbGluayBzZXR9LlxuICovXG5leHBvcnQgY2xhc3MgVHJhY2tlZFRhZ01hcmtlcnMge1xuICBwcml2YXRlIHJlYWRvbmx5IG1hcmtlcnM6IFRhZ01hcmtlclRhYmxlIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHJlYWRvbmx5IGxvZzogUmV2YWxpZGF0aW9uTG9nIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZnJlc2hJbnRlcnZhbE1zOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWF4VHJhY2tlZFRhZ3M6IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSByZXN5bmNJbnRlcnZhbE1zOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2xvY2s6ICgpID0+IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSByYW5kb206ICgpID0+IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBkZWJ1ZzogKG1lc3NhZ2U6IHN0cmluZykgPT4gdm9pZDtcbiAgLyoqIEJ5IHRhZywgbGVhc3QgcmVjZW50bHkgdXNlZCBmaXJzdC4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSB0YWdzID0gbmV3IE1hcDxzdHJpbmcsIFRhZ01hcmtlcj4oKTtcbiAgLyoqXG4gICAqIFdoZW4gZWFjaCB0cmFja2VkIHRhZydzIG1hcmtlciBpcyBkdWUgdG8gYmUgcmVhZCBhZ2FpbjogYSByYW5kb20gNzUtMTAwJVxuICAgKiBvZiBgcmVzeW5jSW50ZXJ2YWxNc2AgYWZ0ZXIgaXQgd2FzIGxhc3Qga25vd24gZnJvbSB0aGUgdGFibGUgLSByZWFkLFxuICAgKiB3cml0dGVuIGhlcmUsIG9yIG5ldy4gSW4gdGhlIG9yZGVyIHRoZXkgYmVjYW1lIGtub3duLCBsZWFzdCByZWNlbnQgZmlyc3QuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGR1ZUF0ID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSByZWFkaW5nID0gbmV3IE1hcDxzdHJpbmcsIFByb21pc2U8dm9pZD4+KCk7XG4gIC8qKlxuICAgKiBMb2cgcm93cyBmb3IgdGFncyB3aG9zZSBmaXJzdCByZWFkIGlzIGluIGZsaWdodCwgbWVyZ2VkIGJ5IHRhZzogdGhlIHJlYWRcbiAgICogbWF5IGhhdmUgYmVlbiBhbnN3ZXJlZCBiZWZvcmUgdGhlIHJldmFsaWRhdGlvbiwgc28gdGhleSBhcmUgYXBwbGllZCB0byBpdHNcbiAgICogcmVzdWx0IHJhdGhlciB0aGFuIGRyb3BwZWQuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHBlbmRpbmdSb3dzID0gbmV3IE1hcDxzdHJpbmcsIFRhZ01hcmtlcj4oKTtcbiAgLyoqIFRyYWNrZWQgdGFncyB3aG9zZSByZWFkIGZhaWxlZCwgZm9yIHRoZSBuZXh0IHJlZnJlc2ggdG8gcmVhZCBhZ2Fpbi4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSB1bnJlYWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSBsYXN0UmVmcmVzaCA9IC1JbmZpbml0eTtcbiAgcHJpdmF0ZSByZWZyZXNoaW5nOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogV2hlcmUgdGhlIG5leHQgbG9nIHF1ZXJ5IHN0YXJ0cyAoYGNsb2NrKClgKTogdGhlIGxhc3Qgc3VjY2Vzc2Z1bCBvbmUnc1xuICAgKiBzdGFydCwgbGVzcyB7QGxpbmsgUkVWQUxJREFUSU9OX0xPR19MT09LQkFDS19NU30uXG4gICAqL1xuICBwcml2YXRlIGN1cnNvcjogbnVtYmVyO1xuICAvKiogV2hlbiB0aGUgbGFzdCBzdWNjZXNzZnVsIGxvZyBxdWVyeSBzdGFydGVkLCBvciB0aGUgbG9nIHdhcyBmaXJzdCByZWFkLiAqL1xuICBwcml2YXRlIGxhc3RMb2dSZWFkOiBudW1iZXI7XG4gIC8qKiBMb2cgcm93cyBhdCBvciBhZnRlciB0aGUgY3Vyc29yIGFscmVhZHkgYXBwbGllZCwgYnkgc29ydCBrZXkuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgYXBwbGllZCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gIC8qKiB7QGxpbmsgdXBkYXRlfXMgb2YgdGhlIGN1cnJlbnQgdHVybiwgYnkgdGhlaXIgYXJndW1lbnRzLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHVwZGF0aW5nID0gbmV3IE1hcDxzdHJpbmcsIFByb21pc2U8Ym9vbGVhbj4+KCk7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogVHJhY2tlZFRhZ01hcmtlcnNPcHRpb25zKSB7XG4gICAgdGhpcy5tYXJrZXJzID0gb3B0aW9ucy5tYXJrZXJzO1xuICAgIHRoaXMubG9nID0gb3B0aW9ucy5sb2c7XG4gICAgdGhpcy5yZWZyZXNoSW50ZXJ2YWxNcyA9XG4gICAgICBvcHRpb25zLnJlZnJlc2hJbnRlcnZhbE1zID8/IERFRkFVTFRfVEFHX1JFRlJFU0hfTVM7XG4gICAgdGhpcy5tYXhUcmFja2VkVGFncyA9IG9wdGlvbnMubWF4VHJhY2tlZFRhZ3MgPz8gREVGQVVMVF9NQVhfVFJBQ0tFRF9UQUdTO1xuICAgIHRoaXMucmVzeW5jSW50ZXJ2YWxNcyA9IG9wdGlvbnMucmVzeW5jSW50ZXJ2YWxNcyA/PyBERUZBVUxUX1RBR19SRVNZTkNfTVM7XG4gICAgLy8gTG9va2VkIHVwIG9uIGVhY2ggY2FsbCByYXRoZXIgdGhhbiBib3VuZCBoZXJlLCBzbyBhIHRlc3QncyBgRGF0ZS5ub3dgXG4gICAgLy8gc3B5IGFwcGxpZXMuXG4gICAgdGhpcy5jbG9jayA9IG9wdGlvbnMuY2xvY2sgPz8gKCgpID0+IERhdGUubm93KCkpO1xuICAgIHRoaXMucmFuZG9tID0gb3B0aW9ucy5yYW5kb20gPz8gTWF0aC5yYW5kb207XG4gICAgdGhpcy5kZWJ1ZyA9IG9wdGlvbnMuZGVidWcgPz8gKCgpID0+IHt9KTtcbiAgICAvLyBOb3RoaW5nIGlzIHRyYWNrZWQgeWV0LCBzbyBub3RoaW5nIGJlZm9yZSB0aGlzIGNhbiBiZSBtaXNzZWQ6IGV2ZXJ5IHRhZ1xuICAgIC8vIGlzIHJlYWQgZnJvbSBpdHMgbWFya2VyIHRoZSBmaXJzdCB0aW1lIGl0IGlzIG5lZWRlZC5cbiAgICBjb25zdCBhdCA9IHRoaXMuY2xvY2soKTtcbiAgICB0aGlzLmN1cnNvciA9IGF0IC0gUkVWQUxJREFUSU9OX0xPR19MT09LQkFDS19NUztcbiAgICB0aGlzLmxhc3RMb2dSZWFkID0gYXQ7XG4gIH1cblxuICAvKiogYHRhZ2AncyBtYXJrZXIgYXMgdGhpcyBpbnN0YW5jZSBrbm93cyBpdCwgaWYgaXQgdHJhY2tzIGB0YWdgLiAqL1xuICBnZXQodGFnOiBzdHJpbmcpOiBUYWdNYXJrZXIgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnRhZ3MuZ2V0KHRhZyk7XG4gIH1cblxuICAvKipcbiAgICogVHJhY2sgYHRhZ2Agd2l0aCBgbWFya2VyYDogd2hhdCB0aGlzIGluc3RhbmNlIGp1c3Qgd3JvdGUsIHdoaWNoIGl0IGtub3dzXG4gICAqIHdpdGhvdXQgcmVhZGluZyBpdCBiYWNrLlxuICAgKi9cbiAgc2V0KHRhZzogc3RyaW5nLCBtYXJrZXI6IFRhZ01hcmtlcik6IHZvaWQge1xuICAgIHRoaXMucmVtZW1iZXIodGFnLCBtYXJrZXIpO1xuICAgIHRoaXMua25vd24odGFnLCB0aGlzLmNsb2NrKCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vdGUgYSB1c2Ugb2YgYHRhZ3NgOiB0aG9zZSBvZiBhbiBlbnRyeSB0aGlzIGluc3RhbmNlIGp1c3Qgc3RvcmVkLlxuICAgKlxuICAgKiBXaXRoIHRoZSB0YWJsZSwgYSB0YWcgbm90IHRyYWNrZWQgeWV0IGlzIGxlZnQgdW50cmFja2VkLCB0byBiZSByZWFkIGJ5XG4gICAqIHtAbGluayBlbnN1cmV9IHRoZSBmaXJzdCB0aW1lIGFuIGVudHJ5IG5lZWRzIGl0LiBOb3RoaW5nIHJldmFsaWRhdGVkIGJlZm9yZVxuICAgKiB0aGUgbmV3IGVudHJ5IHdhcyBjcmVhdGVkIGFwcGxpZXMgdG8gKml0KiwgYnV0IHRyYWNraW5nIGlzIHBlciB0YWcsIG5vdCBwZXJcbiAgICogZW50cnk6IHRyYWNraW5nIHRoZSB0YWcgd2l0aCBhbiBlbXB0eSBtYXJrZXIgd291bGQgYWxzbyB2b3VjaCBmb3IgZXZlcnlcbiAgICogb2xkZXIgZW50cnkgdGhhdCBjYXJyaWVzIGl0IC0gb25lIGFub3RoZXIgaW5zdGFuY2Ugc3RvcmVkIGluIFMzLCBvciBvbmVcbiAgICogdGhpcyBpbnN0YW5jZSBrZXB0IGluIG1lbW9yeSBhY3Jvc3MgYSB7QGxpbmsgZm9yZ2V0fSAtIGFuZCBhIHJldmFsaWRhdGlvblxuICAgKiBmcm9tIGJlZm9yZSB0aGUgbG9nJ3MgY3Vyc29yIHdvdWxkIGdvIHVuc2VlbiB1bnRpbCB0aGUgcm9sbGluZyByZS1yZWFkLlxuICAgKlxuICAgKiBXaXRob3V0IHRoZSB0YWJsZSBldmVyeSByZXZhbGlkYXRpb24gaXMgdGhpcyBwcm9jZXNzJ3Mgb3duLCBhcHBsaWVkIHdpdGhcbiAgICoge0BsaW5rIHNldH0sIHNvIGEgdGFnIGlzIHRyYWNrZWQgYXQgb25jZS5cbiAgICovXG4gIHRyYWNrKHRhZ3M6IHJlYWRvbmx5IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm1hcmtlcnMpIHtcbiAgICAgIHRoaXMudHJhY2tVbnJlYWQodGFncyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgIHRoaXMudG91Y2godGFnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVHJhY2sgYHRhZ3NgIGFzIHRoZXkgYXJlIGtub3duIG5vdywgd2l0aG91dCByZWFkaW5nIHRoZW0sIHdpdGggYW4gZW1wdHlcbiAgICogbWFya2VyIGZvciBhbnkgbm90IHRyYWNrZWQgeWV0LlxuICAgKi9cbiAgcHJpdmF0ZSB0cmFja1VucmVhZCh0YWdzOiByZWFkb25seSBzdHJpbmdbXSk6IHZvaWQge1xuICAgIGNvbnN0IGF0ID0gdGhpcy5jbG9jaygpO1xuICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgIGlmICghdGhpcy50YWdzLmhhcyh0YWcpKSB7XG4gICAgICAgIHRoaXMua25vd24odGFnLCBhdCk7XG4gICAgICB9XG4gICAgICB0aGlzLnJlbWVtYmVyKHRhZywgdGhpcy50YWdzLmdldCh0YWcpID8/IHt9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVhZCB0aGUgbWFya2VycyBvZiB3aGljaGV2ZXIgb2YgYHRhZ3NgIHRoaXMgaW5zdGFuY2UgZG9lcyBub3QgdHJhY2sgeWV0LlxuICAgKiBOZWVkZWQgYmVmb3JlIGp1ZGdpbmcgYW4gZW50cnkgdGhpcyBpbnN0YW5jZSBkaWQgbm90IGNyZWF0ZSwgc2luY2UgaXRzXG4gICAqIHRhZ3MgbWF5IGhhdmUgYmVlbiByZXZhbGlkYXRlZCBhdCBhbnkgdGltZSBiZWZvcmUuXG4gICAqL1xuICBhc3luYyBlbnN1cmUodGFnczogcmVhZG9ubHkgc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMubWFya2Vycykge1xuICAgICAgdGhpcy50cmFja1VucmVhZCh0YWdzKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3Qgd2FpdHM6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuICAgIGNvbnN0IHVucmVhZDogc3RyaW5nW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHRhZyBvZiBuZXcgU2V0KHRhZ3MpKSB7XG4gICAgICBjb25zdCBpbkZsaWdodCA9IHRoaXMucmVhZGluZy5nZXQodGFnKTtcbiAgICAgIGlmIChpbkZsaWdodCkge1xuICAgICAgICB3YWl0cy5wdXNoKGluRmxpZ2h0KTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy50YWdzLmhhcyh0YWcpKSB7XG4gICAgICAgIHRoaXMudG91Y2godGFnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHVucmVhZC5wdXNoKHRhZyk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh1bnJlYWQubGVuZ3RoID4gMCkge1xuICAgICAgLy8gYHJlYWRJbnRvYCBuZXZlciByZWplY3RzOiBhIGZhaWxlZCByZWFkIGxlYXZlcyB0aGUgdGFncyB0cmFja2VkLlxuICAgICAgY29uc3QgcmVhZCA9IHRoaXMucmVhZEludG8odW5yZWFkKS50aGVuKCgpID0+IHtcbiAgICAgICAgZm9yIChjb25zdCB0YWcgb2YgdW5yZWFkKSB7XG4gICAgICAgICAgdGhpcy5yZWFkaW5nLmRlbGV0ZSh0YWcpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGZvciAoY29uc3QgdGFnIG9mIHVucmVhZCkge1xuICAgICAgICB0aGlzLnJlYWRpbmcuc2V0KHRhZywgcmVhZCk7XG4gICAgICB9XG4gICAgICB3YWl0cy5wdXNoKHJlYWQpO1xuICAgIH1cbiAgICBhd2FpdCBQcm9taXNlLmFsbCh3YWl0cyk7XG4gIH1cblxuICAvKipcbiAgICogQ2F0Y2ggdXAgb24gcmV2YWxpZGF0aW9ucyBvdGhlciBpbnN0YW5jZXMgcmFuLCBhdCBtb3N0IG9uY2UgcGVyXG4gICAqIGByZWZyZXNoSW50ZXJ2YWxNc2AuIFNlZSB7QGxpbmsgVHJhY2tlZFRhZ01hcmtlcnN9IGZvciB0aGUgY29zdC5cbiAgICovXG4gIGFzeW5jIHJlZnJlc2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2c7XG4gICAgaWYgKCFsb2cpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHRoaXMucmVmcmVzaGluZykge1xuICAgICAgcmV0dXJuIHRoaXMucmVmcmVzaGluZztcbiAgICB9XG4gICAgY29uc3QgYXQgPSB0aGlzLmNsb2NrKCk7XG4gICAgaWYgKGF0IC0gdGhpcy5sYXN0UmVmcmVzaCA8IHRoaXMucmVmcmVzaEludGVydmFsTXMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5sYXN0UmVmcmVzaCA9IGF0O1xuICAgIC8vIFdoYXRldmVyIGdldHMgdHJhY2tlZCBiZWZvcmUgdGhlIG5leHQgcmVmcmVzaCBpcyByZWFkIGZyb20gaXRzIG1hcmtlcixcbiAgICAvLyBzbyB0aGVyZSBpcyBub3RoaW5nIHRvIGNhdGNoIHVwIG9uIHlldC5cbiAgICBpZiAodGhpcy50YWdzLnNpemUgPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5yZWZyZXNoaW5nID0gdGhpcy5zeW5jKGF0LCBsb2cpLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgdGhpcy5yZWZyZXNoaW5nID0gdW5kZWZpbmVkO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzLnJlZnJlc2hpbmc7XG4gIH1cblxuICAvKipcbiAgICogUmVjb3JkIGEgcmV2YWxpZGF0aW9uIG9mIGB0YWdzYDogaGVyZSBhdCBvbmNlLCBhbmQgaW4gdGhlIHJldmFsaWRhdGlvblxuICAgKiB0YWJsZSBmb3IgZXZlcnkgb3RoZXIgaW5zdGFuY2UgLSB0aGUgbWFya2VyIHJvdyBwbHVzIGEgbG9nIHJvdyBwZXIgdGFnLlxuICAgKlxuICAgKiBOZXh0LmpzIGNhbGxzIGByZXZhbGlkYXRlVGFnYCBvbiB0aGUgaW5jcmVtZW50YWwgY2FjaGUgYW5kIGB1cGRhdGVUYWdzYCBvblxuICAgKiBldmVyeSBkaXN0aW5jdCBgY2FjaGVIYW5kbGVyc2AgZW50cnksIGFsbCBpbiBvbmUgc3luY2hyb25vdXMgbG9vcFxuICAgKiAoYHJldmFsaWRhdGlvbi11dGlsc2ApLCBhbmQgYWxsIG9mIHRoZW0gc2hhcmUgdGhpcyBtYW5pZmVzdC4gU28gYW5cbiAgICogaWRlbnRpY2FsIGNhbGwgaW4gdGhlIHNhbWUgdHVybiBqb2lucyB0aGUgZmlyc3QgaW5zdGVhZCBvZiB3cml0aW5nIHRoZVxuICAgKiByb3dzIGFnYWluLiBPbmUgaW4gYSBsYXRlciB0dXJuIGlzIGEgcmV2YWxpZGF0aW9uIG9mIGl0cyBvd24sIGV2ZW4gd2hpbGVcbiAgICogdGhlIGZpcnN0IG9uZSdzIHdyaXRlcyBhcmUgaW4gZmxpZ2h0LCBhbmQgZ2V0cyBpdHMgb3duLCBsYXRlciwgbWFya2VyLlxuICAgKiBOZXZlciByZWplY3RzOiByZXNvbHZlcyBgZmFsc2VgIHdoZW4gYSByb3cgZmFpbGVkIHRvIHdyaXRlICh0aGUgZXJyb3IgaXNcbiAgICogbG9nZ2VkKSwgc28gb3RoZXIgaW5zdGFuY2VzIG1heSBub3Qgc2VlIGl0LlxuICAgKi9cbiAgYXN5bmMgdXBkYXRlKFxuICAgIHRhZ3M6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICAgIGR1cmF0aW9uczogUmV2YWxpZGF0ZUR1cmF0aW9ucyB8IHVuZGVmaW5lZCxcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3Qga2V5ID0gSlNPTi5zdHJpbmdpZnkoW3RhZ3MsIGR1cmF0aW9ucyA/PyBudWxsXSk7XG4gICAgY29uc3QgaW5GbGlnaHQgPSB0aGlzLnVwZGF0aW5nLmdldChrZXkpO1xuICAgIGlmIChpbkZsaWdodCkge1xuICAgICAgcmV0dXJuIGluRmxpZ2h0O1xuICAgIH1cbiAgICBjb25zdCB1cGRhdGUgPSB0aGlzLndyaXRlKHRhZ3MsIGR1cmF0aW9ucyk7XG4gICAgdGhpcy51cGRhdGluZy5zZXQoa2V5LCB1cGRhdGUpO1xuICAgIC8vIEZvcmdvdHRlbiBhcyBzb29uIGFzIHRoZSBjdXJyZW50IHR1cm4ncyBjYWxscyBoYXZlIGJlZW4gbWFkZS5cbiAgICB2b2lkIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gdGhpcy51cGRhdGluZy5kZWxldGUoa2V5KSk7XG4gICAgcmV0dXJuIHVwZGF0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGF0IHRoZSB0cmFja2VkIG1hcmtlcnMgc2F5IGFib3V0IGFuIGVudHJ5IGNhcnJ5aW5nIGB0YWdzYCwgY3JlYXRlZCBhdFxuICAgKiBgY3JlYXRlZEF0YDogdGhlIG1vc3Qgc2V2ZXJlIGFuc3dlciBvZiBhbnkgb2YgdGhlbS5cbiAgICovXG4gIHN0YXRlKHRhZ3M6IHJlYWRvbmx5IHN0cmluZ1tdLCBjcmVhdGVkQXQ6IG51bWJlcik6IFJldmFsaWRhdGlvblN0YXRlIHtcbiAgICAvLyBgbWFya2VyQ2xvY2soKWAsIG5vdCBgRGF0ZS5ub3coKWAsIGhlcmUgYW5kIHdoZXJldmVyIGEgbWFya2VyIGlzIHN0YW1wZWQ6XG4gICAgLy8gYGNyZWF0ZWRBdGAgaXMgb24gTmV4dC5qcydzIGNsb2NrLCBhbmQgYSBtYXJrZXIgb24gdGhlIHdhbGwgY2xvY2sgd291bGQgYmVcbiAgICAvLyBjb21wYXJlZCBhY3Jvc3MgdGhlIHR3bywgc28gYW4gZW50cnkgcmVnZW5lcmF0ZWQganVzdCBhZnRlciBhXG4gICAgLy8gcmV2YWxpZGF0aW9uIGNvdWxkIHN0aWxsIHJlYWQgYXMgb2xkZXIgdGhhbiBpdCB3aGVyZXZlciB0aGV5IGRyaWZ0LlxuICAgIGNvbnN0IGF0ID0gbWFya2VyQ2xvY2soKTtcbiAgICBsZXQgc3RhdGU6IFJldmFsaWRhdGlvblN0YXRlID0gXCJmcmVzaFwiO1xuICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgIGNvbnN0IG1hcmtlciA9IHRoaXMuZ2V0KHRhZyk7XG4gICAgICBpZiAoIW1hcmtlcikge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHRhZ1N0YXRlID0gbWFya2VyU3RhdGUobWFya2VyLCBjcmVhdGVkQXQsIGF0KTtcbiAgICAgIGlmICh0YWdTdGF0ZSA9PT0gXCJleHBpcmVkXCIpIHtcbiAgICAgICAgcmV0dXJuIFwiZXhwaXJlZFwiO1xuICAgICAgfVxuICAgICAgaWYgKHRhZ1N0YXRlID09PSBcInN0YWxlXCIpIHtcbiAgICAgICAgc3RhdGUgPSBcInN0YWxlXCI7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzdGF0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBgZ2V0RXhwaXJhdGlvbmAncyBhbnN3ZXI6IHRoZSBsYXRlc3QgdGltZSBhbnkgb2YgYHRhZ3NgIGV4cGlyZWQsIGAwYCBpZlxuICAgKiBub25lIGhhcy4gT25seSBleHBpcmF0aW9ucyBhbHJlYWR5IHBhc3QgY291bnQgLSBhIHByb2ZpbGUncyBmdXR1cmVcbiAgICogYGV4cGlyZWAgaXMgbm90IGFuIGV4cGlyYXRpb24geWV0IC0gYW5kIGEgc3RhbGUgbWFyayBkb2VzIG5vdCwgbWF0Y2hpbmdcbiAgICogTmV4dC5qcydzIGRlZmF1bHQgaGFuZGxlciwgd2hpY2ggcmVhZHMgb25seSBgZXhwaXJlZGAgZm9yIGltcGxpY2l0IHRhZ3MuXG4gICAqL1xuICBleHBpcmF0aW9uKHRhZ3M6IHJlYWRvbmx5IHN0cmluZ1tdKTogbnVtYmVyIHtcbiAgICBjb25zdCBhdCA9IG1hcmtlckNsb2NrKCk7XG4gICAgbGV0IGxhdGVzdCA9IDA7XG4gICAgZm9yIChjb25zdCB0YWcgb2YgdGFncykge1xuICAgICAgY29uc3QgbWFya2VyID0gdGhpcy5nZXQodGFnKTtcbiAgICAgIGlmICghbWFya2VyKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKG1hcmtlci5yZXZhbGlkYXRlZEF0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbGF0ZXN0ID0gTWF0aC5tYXgobGF0ZXN0LCBtYXJrZXIucmV2YWxpZGF0ZWRBdCk7XG4gICAgICB9XG4gICAgICBpZiAobWFya2VyLmV4cGlyZWRBdCAhPT0gdW5kZWZpbmVkICYmIG1hcmtlci5leHBpcmVkQXQgPD0gYXQpIHtcbiAgICAgICAgbGF0ZXN0ID0gTWF0aC5tYXgobGF0ZXN0LCBtYXJrZXIuZXhwaXJlZEF0KTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGxhdGVzdDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd3JpdGUoXG4gICAgdGFnczogcmVhZG9ubHkgc3RyaW5nW10sXG4gICAgZHVyYXRpb25zOiBSZXZhbGlkYXRlRHVyYXRpb25zIHwgdW5kZWZpbmVkLFxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBhdCA9IG1hcmtlckNsb2NrKCk7XG4gICAgY29uc3QgbWFya2VyID0gbWFya2VyRm9yKGF0LCBkdXJhdGlvbnMpO1xuICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgIHRoaXMuc2V0KHRhZywgYXBwbHlNYXJrZXIodGhpcy5nZXQodGFnKSwgbWFya2VyKSk7XG4gICAgfVxuICAgIGNvbnN0IHsgbWFya2VycywgbG9nIH0gPSB0aGlzO1xuICAgIGlmICghbWFya2VycyB8fCAhbG9nKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgY29uc3Qgd3JpdGVzOiBbc3RyaW5nLCBQcm9taXNlPHVua25vd24+XVtdID0gW107XG4gICAgZm9yIChjb25zdCB0YWcgb2YgbmV3IFNldCh0YWdzKSkge1xuICAgICAgd3JpdGVzLnB1c2goW1xuICAgICAgICBcIkVycm9yIHdyaXRpbmcgdGFnIHJldmFsaWRhdGlvbiBtYXJrZXI6XCIsXG4gICAgICAgIC8vIFRoZSByb3cgYXMgaXQgaXMgbm93LCB3aGljaCBjYXJyaWVzIGFueSBlYXJsaWVyIGByZXZhbGlkYXRlZEF0YFxuICAgICAgICAvLyBhbm90aGVyIGluc3RhbmNlIHdyb3RlOiB0cmFja2luZyBvbmx5IHdoYXQgdGhpcyBjYWxsIHNldCB3b3VsZFxuICAgICAgICAvLyBoaWRlIHRoYXQgb25lIHVudGlsIHRoZSByb2xsaW5nIHJlLXJlYWQsIGFuZCBhbiBlbnRyeSBvbGRlciB0aGFuIGl0XG4gICAgICAgIC8vIHdvdWxkIHJlYWQgYXMgbWVyZWx5IHN0YWxlLlxuICAgICAgICBtYXJrZXJzLndyaXRlKHRhZywgYXQsIGR1cmF0aW9ucykudGhlbigocm93KSA9PiB7XG4gICAgICAgICAgaWYgKHJvdykge1xuICAgICAgICAgICAgdGhpcy5zZXQodGFnLCBtZXJnZU1hcmtlcnModGhpcy5nZXQodGFnKSwgcm93KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgIF0pO1xuICAgICAgd3JpdGVzLnB1c2goW1xuICAgICAgICBcIkVycm9yIHdyaXRpbmcgdGFnIHJldmFsaWRhdGlvbiBsb2cgcm93OlwiLFxuICAgICAgICB0aGlzLnB1dExvZ1Jvdyhsb2csIHRhZywgbWFya2VyKSxcbiAgICAgIF0pO1xuICAgIH1cbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKHdyaXRlcy5tYXAoKFssIHdyaXRlXSkgPT4gd3JpdGUpKTtcbiAgICByZXN1bHRzLmZvckVhY2goKHJlc3VsdCwgaSkgPT4ge1xuICAgICAgaWYgKHJlc3VsdC5zdGF0dXMgPT09IFwicmVqZWN0ZWRcIikge1xuICAgICAgICBjb25zb2xlLmVycm9yKHdyaXRlc1tpXVswXSwgcmVzdWx0LnJlYXNvbik7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3VsdHMuZXZlcnkoKHJlc3VsdCkgPT4gcmVzdWx0LnN0YXR1cyA9PT0gXCJmdWxmaWxsZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogUHV0IGB0YWdgJ3MgbG9nIHJvdywgc3RhbXBlZCBvbiB0aGUgd2FsbCBjbG9jayAodGhlIG1hcmtlciB2YWx1ZXMgYXJlIG9uXG4gICAqIE5leHQuanMnczogc2VlIHtAbGluayBSZXZhbGlkYXRpb25Mb2d9KS5cbiAgICpcbiAgICogUmVhZGVycyBvbmx5IGxvb2sge0BsaW5rIFJFVkFMSURBVElPTl9MT0dfTE9PS0JBQ0tfTVN9IGJlaGluZCB0aGVpciBsYXN0XG4gICAqIHF1ZXJ5LCBzbyBhIHJvdyB0aGF0IHNob3dzIHVwIG11Y2ggbGF0ZXIgdGhhbiBpdHMgdGltZXN0YW1wIC0gYSBzbG93XG4gICAqIGNvbm5lY3Rpb24sIHJldHJpZXMgdW5kZXIgdGhyb3R0bGluZyAtIGlzIGJlaGluZCBldmVyeSBjdXJzb3IgYW5kIG5ldmVyXG4gICAqIHJlYWQuIEEgc2xvdyBwdXQgaXMgdGhlcmVmb3JlIG1hZGUgYWdhaW4gdW5kZXIgYSBmcmVzaCB0aW1lc3RhbXAsIHdoaWNoXG4gICAqIHJlYWRlcnMgd2lsbCBzZWU7IG9uZSBzbG93IHR3aWNlIGlzIHJlcG9ydGVkIGFzIGEgZmFpbHVyZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcHV0TG9nUm93KFxuICAgIGxvZzogUmV2YWxpZGF0aW9uTG9nLFxuICAgIHRhZzogc3RyaW5nLFxuICAgIG1hcmtlcjogVGFnTWFya2VyLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8IDI7IGF0dGVtcHQrKykge1xuICAgICAgY29uc3QgYXQgPSB0aGlzLmNsb2NrKCk7XG4gICAgICBhd2FpdCBsb2cucHV0KHRhZywgYXQsIG1hcmtlcik7XG4gICAgICBpZiAodGhpcy5jbG9jaygpIC0gYXQgPD0gTUFYX0xPR19QVVRfTVMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgVGhlIHJldmFsaWRhdGlvbiBsb2cgcm93IGZvciAke3RhZ30gdG9vayBsb25nZXIgdGhhbiByZWFkZXJzIGxvb2sgYmFja2AsXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPbmUgcmVmcmVzaCBzdGFydGVkIGF0IGBhdGA6IHRoZSBsb2cgcm93cyBzaW5jZSB0aGUgY3Vyc29yLCBhbmQgdGhlIG5leHRcbiAgICogc2xpY2Ugb2YgdGhlIHJvbGxpbmcgcmUtcmVhZC5cbiAgICpcbiAgICogQSBmYWlsZWQgcXVlcnkgY2hhbmdlcyBub3RoaW5nIGJ1dCB0aGUgbG9nOiB0aGUgdGFncyBzdGF5IHRyYWNrZWQgYXMgdGhleVxuICAgKiB3ZXJlLCBhbmQgdGhlIG5leHQgcmVmcmVzaCBhc2tzIGFnYWluIGZyb20gdGhlIHNhbWUgY3Vyc29yLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzeW5jKGF0OiBudW1iZXIsIGxvZzogUmV2YWxpZGF0aW9uTG9nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKGF0IC0gdGhpcy5sYXN0TG9nUmVhZCA+IE1BWF9SRVZBTElEQVRJT05fTE9HX0dBUF9NUykge1xuICAgICAgdGhpcy5mb3JnZXQoXG4gICAgICAgIGF0LFxuICAgICAgICBcInRoZSByZXZhbGlkYXRpb24gbG9nIG1heSBub3QgY292ZXIgdGhlIGdhcCBzaW5jZSBpdCB3YXMgbGFzdCByZWFkXCIsXG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBbcmVzdWx0XSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIGxvZy5xdWVyeSh0aGlzLmN1cnNvcikuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciByZWFkaW5nIHRhZyByZXZhbGlkYXRpb24gbG9nOlwiLCBlcnJvcik7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9KSxcbiAgICAgIHRoaXMucmVhZEludG8odGhpcy5kdWUoYXQpKSxcbiAgICBdKTtcbiAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAocmVzdWx0LnRydW5jYXRlZCkge1xuICAgICAgdGhpcy5mb3JnZXQoXG4gICAgICAgIGF0LFxuICAgICAgICBcInRoZSByZXZhbGlkYXRpb24gbG9nIGhhcyBtb3JlIHJvd3MgdGhhbiBvbmUgcXVlcnkgcmVhZHNcIixcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBhcHBsaWVkID0gMDtcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiByZXN1bHQucm93cykge1xuICAgICAgaWYgKHRoaXMuYXBwbGllZC5oYXMocm93LnNrKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IG1hcmtlciA9IHRoaXMudGFncy5nZXQocm93LnRhZyk7XG4gICAgICBpZiAobWFya2VyKSB7XG4gICAgICAgIC8vIGBzZXRgIG9uIGEga2V5IGFscmVhZHkgdGhlcmUga2VlcHMgaXRzIHBsYWNlIGluIHRoZSBMUlUgb3JkZXI6IGJlaW5nXG4gICAgICAgIC8vIHJldmFsaWRhdGVkIGVsc2V3aGVyZSBpcyBub3QgYSB1c2UuXG4gICAgICAgIHRoaXMudGFncy5zZXQocm93LnRhZywgbWVyZ2VNYXJrZXJzKG1hcmtlciwgcm93Lm1hcmtlcikpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnJlYWRpbmcuaGFzKHJvdy50YWcpKSB7XG4gICAgICAgIHRoaXMucGVuZGluZ1Jvd3Muc2V0KFxuICAgICAgICAgIHJvdy50YWcsXG4gICAgICAgICAgbWVyZ2VNYXJrZXJzKHRoaXMucGVuZGluZ1Jvd3MuZ2V0KHJvdy50YWcpLCByb3cubWFya2VyKSxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEEgdGFnIHRoaXMgaW5zdGFuY2UgZG9lcyBub3QgdHJhY2sgaXMgcmVhZCBmcm9tIGl0cyBtYXJrZXIgd2hlbiBpdFxuICAgICAgICAvLyBpcyBuZXh0IG5lZWRlZCAtIGJ1dCBub3QgeWV0IG1hcmtlZCBhcHBsaWVkLCBiZWNhdXNlIHRoYXQgcmVhZCBtYXlcbiAgICAgICAgLy8gbWlzcyB0aGlzIHZlcnkgcmV2YWxpZGF0aW9uOiB0aGUgd3JpdGVyIHB1dHMgdGhlIGxvZyByb3cgYW5kIHRoZVxuICAgICAgICAvLyBtYXJrZXIgYXQgdGhlIHNhbWUgdGltZSwgYW5kIHRoZSByZWFkIGlzIGFuIGV2ZW50dWFsbHkgY29uc2lzdGVudFxuICAgICAgICAvLyBgQmF0Y2hHZXRJdGVtYCB0aGF0IGNhbiBsYW5kIG1pbGxpc2Vjb25kcyBhZnRlciB0aGUgcm93IHNob3dlZCBoZXJlLlxuICAgICAgICAvLyBNYXJrZWQgYXBwbGllZCwgdGhlIHJvdyB3YXMgc2tpcHBlZCBieSBldmVyeSBxdWVyeSB0aGUgbG9va2JhY2tcbiAgICAgICAgLy8gcmV0dXJuZWQgaXQgdG8sIGFuZCB0aGUgcHJlLXJldmFsaWRhdGlvbiBtYXJrZXIgc3Rvb2QgdW50aWwgdGhlXG4gICAgICAgIC8vIHJvbGxpbmcgcmUtcmVhZC4gTGVmdCB1bm1hcmtlZCwgdGhlIG5leHQgcmVmcmVzaCBhcHBsaWVzIGl0IHRvXG4gICAgICAgIC8vIHdoYXRldmVyIHRoYXQgcmVhZCBmb3VuZDsgaXQgY29zdHMgbm8gcmVhZCwgb25seSB0aGUgcm93IGJlaW5nXG4gICAgICAgIC8vIGxvb2tlZCBhdCBhZ2FpbiB3aGlsZSBpdCBpcyBpbnNpZGUgdGhlIGxvb2tiYWNrLlxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHRoaXMuYXBwbGllZC5zZXQocm93LnNrLCByb3cuYXQpO1xuICAgICAgYXBwbGllZCsrO1xuICAgIH1cbiAgICB0aGlzLmxhc3RMb2dSZWFkID0gYXQ7XG4gICAgdGhpcy5hZHZhbmNlKGF0IC0gUkVWQUxJREFUSU9OX0xPR19MT09LQkFDS19NUyk7XG4gICAgdGhpcy5kZWJ1ZyhcbiAgICAgIGByZWFkICR7cmVzdWx0LnJvd3MubGVuZ3RofSByZXZhbGlkYXRpb24gbG9nIHJvd3MgKCR7YXBwbGllZH0gYXBwbGllZClgLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIHRhZ3MgdG8gcmVhZCBvbiB0aGlzIHJlZnJlc2gsIGF0IG1vc3Qgb25lIGBCYXRjaEdldEl0ZW1gJ3Mgd29ydGg6XG4gICAqIHRob3NlIHdob3NlIHJlYWQgZmFpbGVkLCB0aGVuIHRob3NlIHdob3NlIHJlLXJlYWQgaGFzIGNvbWUgZHVlLCBpbiB0aGVcbiAgICogb3JkZXIgdGhleSB3ZXJlIGxhc3QgcmVhZC5cbiAgICovXG4gIHByaXZhdGUgZHVlKGF0OiBudW1iZXIpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgZHVlOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgdGFnIG9mIHRoaXMudW5yZWFkKSB7XG4gICAgICBpZiAoZHVlLmxlbmd0aCA+PSBCQVRDSF9HRVRfTUFYX0tFWVMpIHJldHVybiBkdWU7XG4gICAgICBkdWUucHVzaCh0YWcpO1xuICAgIH1cbiAgICAvLyBLbm93biBpbiB0aW1lIG9yZGVyLCBhbmQgZWFjaCBkdWUgYXQgbW9zdCBgaml0dGVyYCBlYXJsaWVyIHRoYW4gdGhlXG4gICAgLy8gdGFncyBhZnRlciBpdDogcGFzdCBhIHRhZyBkdWUgbW9yZSB0aGFuIHRoYXQgZnJvbSBub3csIG5vbmUgaXMgZHVlLlxuICAgIGNvbnN0IGppdHRlciA9IHRoaXMucmVzeW5jSW50ZXJ2YWxNcyAqIFRBR19SRVNZTkNfSklUVEVSO1xuICAgIGZvciAoY29uc3QgW3RhZywgZHVlQXRdIG9mIHRoaXMuZHVlQXQpIHtcbiAgICAgIGlmIChkdWUubGVuZ3RoID49IEJBVENIX0dFVF9NQVhfS0VZUyB8fCBkdWVBdCAtIGppdHRlciA+IGF0KSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgaWYgKGR1ZUF0IDw9IGF0ICYmICF0aGlzLnVucmVhZC5oYXModGFnKSkge1xuICAgICAgICBkdWUucHVzaCh0YWcpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvcmdldCBldmVyeSB0cmFja2VkIG1hcmtlciwgYW5kIGZvbGxvdyB0aGUgbG9nIGZyb20gYGF0YDogd2hhdCBpcyBuZWVkZWRcbiAgICogbmV4dCBpcyByZWFkIGZyb20gaXRzIG1hcmtlciBhcyBpdCBpcyBuZWVkZWQsIHNwcmVhZCBvdmVyIHRoZSByZXF1ZXN0c1xuICAgKiB0aGF0IG5lZWQgaXQsIHJhdGhlciB0aGFuIGV2ZXJ5IHRyYWNrZWQgdGFnIHJlLXJlYWQgYXQgb25jZS5cbiAgICovXG4gIHByaXZhdGUgZm9yZ2V0KGF0OiBudW1iZXIsIHdoeTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5kZWJ1ZyhgZm9yZ2V0dGluZyAke3RoaXMudGFncy5zaXplfSB0cmFja2VkIHRhZ3M6ICR7d2h5fWApO1xuICAgIHRoaXMudGFncy5jbGVhcigpO1xuICAgIHRoaXMuZHVlQXQuY2xlYXIoKTtcbiAgICB0aGlzLnVucmVhZC5jbGVhcigpO1xuICAgIHRoaXMuYXBwbGllZC5jbGVhcigpO1xuICAgIHRoaXMuY3Vyc29yID0gYXQgLSBSRVZBTElEQVRJT05fTE9HX0xPT0tCQUNLX01TO1xuICAgIHRoaXMubGFzdExvZ1JlYWQgPSBhdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb3ZlIHRoZSBjdXJzb3IgZm9yd2FyZCB0byBgY3Vyc29yYCwgZm9yZ2V0dGluZyBhcHBsaWVkIHJvd3MgYmVmb3JlIGl0OlxuICAgKiBubyBxdWVyeSByZXR1cm5zIHRoZW0gYWdhaW4uXG4gICAqL1xuICBwcml2YXRlIGFkdmFuY2UoY3Vyc29yOiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAoY3Vyc29yIDw9IHRoaXMuY3Vyc29yKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuY3Vyc29yID0gY3Vyc29yO1xuICAgIGZvciAoY29uc3QgW3NrLCBhdF0gb2YgdGhpcy5hcHBsaWVkKSB7XG4gICAgICBpZiAoYXQgPCBjdXJzb3IpIHtcbiAgICAgICAgdGhpcy5hcHBsaWVkLmRlbGV0ZShzayk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlYWQgYHRhZ3NgIGZyb20gdGhlIHRhYmxlLCBhbmQgcmVwb3J0IHdoZXRoZXIgdGhhdCB3b3JrZWQuIEEgcmVhZCB0aGF0XG4gICAqIGZhaWxzIGxlYXZlcyB0aGVtIHRyYWNrZWQgYXMgdGhleSB3ZXJlLCBhbmQgdGhlIG5leHQgcmVmcmVzaCByZWFkcyB0aGVtXG4gICAqIGFnYWluOiB0aGUgc2FtZSBcImFzc3VtZSB0aGUgZW50cnkgaXMgdmFsaWRcIiB0aGUgaW5jcmVtZW50YWwgY2FjaGUgaGFzXG4gICAqIGFsd2F5cyBhbnN3ZXJlZCB3aXRoLCByYXRoZXIgdGhhbiBhIHJlYWQgb24gZXZlcnkgcmVxdWVzdCB3aGlsZSBEeW5hbW9EQlxuICAgKiBpcyB1bmF2YWlsYWJsZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVhZEludG8odGFnczogc3RyaW5nW10pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGFncy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBjb25zdCBhdCA9IHRoaXMuY2xvY2soKTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVhZCA9IGF3YWl0IHRoaXMubWFya2VycyEucmVhZCh0YWdzKTtcbiAgICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgICAgdGhpcy51bnJlYWQuZGVsZXRlKHRhZyk7XG4gICAgICAgIHRoaXMucmVtZW1iZXIoXG4gICAgICAgICAgdGFnLFxuICAgICAgICAgIG1lcmdlTWFya2VycyhcbiAgICAgICAgICAgIG1lcmdlTWFya2Vycyh0aGlzLnRhZ3MuZ2V0KHRhZyksIHJlYWQuZ2V0KHRhZykpLFxuICAgICAgICAgICAgdGhpcy50YWtlUGVuZGluZ1Jvd3ModGFnKSxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmtub3duKHRhZywgYXQpO1xuICAgICAgfVxuICAgICAgdGhpcy5kZWJ1ZyhgcmVhZCAke3RhZ3MubGVuZ3RofSB0YWcgbWFya2VycyAoJHtyZWFkLnNpemV9IHNldClgKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgcmVhZGluZyB0YWcgbWFya2VyczpcIiwgZXJyb3IpO1xuICAgICAgdGhpcy50cmFja1VucmVhZCh0YWdzKTtcbiAgICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgICAgdGhpcy51bnJlYWQuYWRkKHRhZyk7XG4gICAgICAgIGNvbnN0IHBlbmRpbmcgPSB0aGlzLnRha2VQZW5kaW5nUm93cyh0YWcpO1xuICAgICAgICBpZiAocGVuZGluZykge1xuICAgICAgICAgIHRoaXMucmVtZW1iZXIodGFnLCBtZXJnZU1hcmtlcnModGhpcy50YWdzLmdldCh0YWcpLCBwZW5kaW5nKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHRha2VQZW5kaW5nUm93cyh0YWc6IHN0cmluZyk6IFRhZ01hcmtlciB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgcGVuZGluZyA9IHRoaXMucGVuZGluZ1Jvd3MuZ2V0KHRhZyk7XG4gICAgdGhpcy5wZW5kaW5nUm93cy5kZWxldGUodGFnKTtcbiAgICByZXR1cm4gcGVuZGluZztcbiAgfVxuXG4gIC8qKiBSZWNvcmQgdGhhdCBgdGFnYCdzIG1hcmtlciB3YXMga25vd24gZnJvbSB0aGUgdGFibGUgYXQgYGF0YC4gKi9cbiAgcHJpdmF0ZSBrbm93bih0YWc6IHN0cmluZywgYXQ6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuZHVlQXQuZGVsZXRlKHRhZyk7XG4gICAgdGhpcy5kdWVBdC5zZXQoXG4gICAgICB0YWcsXG4gICAgICBhdCArIHRoaXMucmVzeW5jSW50ZXJ2YWxNcyAqICgxIC0gVEFHX1JFU1lOQ19KSVRURVIgKiB0aGlzLnJhbmRvbSgpKSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSByZW1lbWJlcih0YWc6IHN0cmluZywgbWFya2VyOiBUYWdNYXJrZXIpOiB2b2lkIHtcbiAgICB0aGlzLnRhZ3MuZGVsZXRlKHRhZyk7XG4gICAgdGhpcy50YWdzLnNldCh0YWcsIG1hcmtlcik7XG4gICAgZm9yIChjb25zdCBvbGRlc3Qgb2YgdGhpcy50YWdzLmtleXMoKSkge1xuICAgICAgaWYgKHRoaXMudGFncy5zaXplIDw9IHRoaXMubWF4VHJhY2tlZFRhZ3MpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICB0aGlzLnRhZ3MuZGVsZXRlKG9sZGVzdCk7XG4gICAgICB0aGlzLmR1ZUF0LmRlbGV0ZShvbGRlc3QpO1xuICAgICAgdGhpcy51bnJlYWQuZGVsZXRlKG9sZGVzdCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB0b3VjaCh0YWc6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IG1hcmtlciA9IHRoaXMudGFncy5nZXQodGFnKTtcbiAgICBpZiAobWFya2VyKSB7XG4gICAgICB0aGlzLnJlbWVtYmVyKHRhZywgbWFya2VyKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgbG9uZ2VzdCBhIGxvZyByb3cncyBwdXQgbWF5IHRha2UgYW5kIHN0aWxsIGJlIHNlZW4gYnkgZXZlcnkgcmVhZGVyOiBoYWxmXG4gKiB0aGUgbG9va2JhY2ssIGxlYXZpbmcgdGhlIHJlc3QgZm9yIHdyaXRlcnMnIGNsb2NrcyBhbmQgZXZlbnR1YWxseSBjb25zaXN0ZW50XG4gKiBxdWVyaWVzLlxuICovXG5jb25zdCBNQVhfTE9HX1BVVF9NUyA9IFJFVkFMSURBVElPTl9MT0dfTE9PS0JBQ0tfTVMgLyAyO1xuXG4vKipcbiAqIEEgbWFya2VyIGFzIHJlYWQgZnJvbSB0aGUgdGFibGUgb3IgdGhlIGxvZywga2VlcGluZyB3aGF0ZXZlciB0aGlzIGluc3RhbmNlXG4gKiBhbHJlYWR5IGtub3dzIHRoYXQgdGhlIHJlYWQgZG9lcyBub3Qgc2hvdyB5ZXQ6IHJlYWRzIGFyZSBldmVudHVhbGx5XG4gKiBjb25zaXN0ZW50LCBhbmQgYSByZWFkIHN0cmFpZ2h0IGFmdGVyIHRoaXMgaW5zdGFuY2UncyBvd24gcmV2YWxpZGF0aW9uIGNvdWxkXG4gKiBvdGhlcndpc2UgdGFrZSBpdCBiYWNrLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWVyZ2VNYXJrZXJzKFxuICBsb2NhbDogVGFnTWFya2VyIHwgdW5kZWZpbmVkLFxuICByZW1vdGU6IFRhZ01hcmtlciB8IHVuZGVmaW5lZCxcbik6IFRhZ01hcmtlciB7XG4gIGlmICghbG9jYWwpIHtcbiAgICByZXR1cm4gcmVtb3RlID8/IHt9O1xuICB9XG4gIGlmICghcmVtb3RlKSB7XG4gICAgcmV0dXJuIGxvY2FsO1xuICB9XG4gIC8vIGBleHBpcmVkQXRgIGlzIHdyaXR0ZW4gd2l0aCBgc3RhbGVBdGAsIHNvIGl0IGJlbG9uZ3MgdG8gd2hpY2hldmVyIGlzXG4gIC8vIG5ld2VyIC0gdW5sZXNzIHRoYXQgcmV2YWxpZGF0aW9uJ3MgcHJvZmlsZSBoYWQgbm8gYGV4cGlyZWAgYW5kIGxlZnQgaXQuXG4gIGNvbnN0IFtvbGRlciwgbmV3ZXJdID1cbiAgICAobG9jYWwuc3RhbGVBdCA/PyAtMSkgPiAocmVtb3RlLnN0YWxlQXQgPz8gLTEpXG4gICAgICA/IFtyZW1vdGUsIGxvY2FsXVxuICAgICAgOiBbbG9jYWwsIHJlbW90ZV07XG4gIHJldHVybiB7XG4gICAgLi4uYXBwbHlNYXJrZXIob2xkZXIsIG5ld2VyKSxcbiAgICByZXZhbGlkYXRlZEF0OiBtYXhEZWZpbmVkKGxvY2FsLnJldmFsaWRhdGVkQXQsIHJlbW90ZS5yZXZhbGlkYXRlZEF0KSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gbWF4RGVmaW5lZChhOiBudW1iZXIgfCB1bmRlZmluZWQsIGI6IG51bWJlciB8IHVuZGVmaW5lZCkge1xuICBpZiAoYSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gYjtcbiAgaWYgKGIgPT09IHVuZGVmaW5lZCkgcmV0dXJuIGE7XG4gIHJldHVybiBNYXRoLm1heChhLCBiKTtcbn1cblxuLyoqXG4gKiBUaGUgY2FjaGUgYnVja2V0LCBhcyB0aGUgaGFuZGxlcnMgdXNlIGl0OiB3aG9sZSBvYmplY3RzIHJlYWQgYW5kIHdyaXR0ZW4gYXNcbiAqIFVURi04IHRleHQgdW5kZXIgdGhlIGtleXMgYWJvdmUuXG4gKi9cbmV4cG9ydCBjbGFzcyBDYWNoZUJ1Y2tldCB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY2xpZW50OiBTM0NsaWVudCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGJ1Y2tldE5hbWU6IHN0cmluZyxcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBUaGUgYm9keSBvZiB0aGUgb2JqZWN0IGF0IGBrZXlgLCBvciBgdW5kZWZpbmVkYCB3aGVuIHRoZXJlIGlzIG5vbmUgKGBOb1N1Y2hLZXlgLCBvciBhblxuICAgKiBlbXB0eSByZXNwb25zZSBib2R5KS4gQW55IG90aGVyIGVycm9yIGlzIHRocm93bjogdGhlIGhhbmRsZXJzIGRpc2FncmVlIG9uXG4gICAqIHdoZXRoZXIgb25lIGlzIHdvcnRoIGxvZ2dpbmcuXG4gICAqL1xuICBhc3luYyBnZXQoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuY2xpZW50LnNlbmQoXG4gICAgICAgIG5ldyBHZXRPYmplY3RDb21tYW5kKHsgQnVja2V0OiB0aGlzLmJ1Y2tldE5hbWUsIEtleToga2V5IH0pLFxuICAgICAgKTtcbiAgICAgIGlmICghcmVzcG9uc2UuQm9keSkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGF3YWl0IHJlc3BvbnNlLkJvZHkudHJhbnNmb3JtVG9TdHJpbmcoXCJ1dGYtOFwiKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgTm9TdWNoS2V5KSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvKiogV3JpdGUgYGJvZHlgIGFzIGEgSlNPTiBvYmplY3QgYXQgYGtleWAuICovXG4gIGFzeW5jIHB1dEpzb24oa2V5OiBzdHJpbmcsIGJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuY2xpZW50LnNlbmQoXG4gICAgICBuZXcgUHV0T2JqZWN0Q29tbWFuZCh7XG4gICAgICAgIEJ1Y2tldDogdGhpcy5idWNrZXROYW1lLFxuICAgICAgICBLZXk6IGtleSxcbiAgICAgICAgQm9keTogYm9keSxcbiAgICAgICAgQ29udGVudFR5cGU6IFwiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOFwiLFxuICAgICAgfSksXG4gICAgKTtcbiAgfVxufVxuIl19