cdk-nextjs 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/.jsii +2467 -2714
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1725 -1909
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +152 -170
  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 +687 -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 +1548 -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 +852 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +861 -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 +13 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +11 -2
  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/post-deploy.lambda.js +3 -2
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  88. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  92. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  93. package/lib/lambdas/post-deploy/prune-s3.d.ts +19 -3
  94. package/lib/lambdas/post-deploy/prune-s3.js +54 -15
  95. package/lib/lambdas/post-deploy/prune-s3.test.d.ts +1 -0
  96. package/lib/lambdas/post-deploy/prune-s3.test.js +255 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  103. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  104. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  105. package/lib/nextjs-api.d.ts +107 -18
  106. package/lib/nextjs-api.js +349 -39
  107. package/lib/nextjs-api.test.js +582 -1
  108. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  109. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  110. package/lib/nextjs-build/nextjs-build.js +684 -327
  111. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  112. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  113. package/lib/nextjs-build/patch-fetch.js +1 -1
  114. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  115. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  116. package/lib/nextjs-cache.d.ts +82 -4
  117. package/lib/nextjs-cache.js +186 -10
  118. package/lib/nextjs-cache.test.js +176 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  120. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  121. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  122. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  123. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  124. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  125. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  126. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  127. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  128. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  129. package/lib/nextjs-distribution.d.ts +194 -23
  130. package/lib/nextjs-distribution.js +535 -62
  131. package/lib/nextjs-distribution.test.d.ts +1 -0
  132. package/lib/nextjs-distribution.test.js +697 -0
  133. package/lib/nextjs-post-deploy.d.ts +23 -3
  134. package/lib/nextjs-post-deploy.js +14 -10
  135. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  136. package/lib/nextjs-post-deploy.test.js +34 -0
  137. package/lib/nextjs-static-assets.d.ts +23 -4
  138. package/lib/nextjs-static-assets.js +29 -6
  139. package/lib/nextjs-static-assets.test.js +20 -1
  140. package/lib/root-constructs/nextjs-base-construct.d.ts +105 -45
  141. package/lib/root-constructs/nextjs-base-construct.js +144 -34
  142. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  143. package/lib/root-constructs/nextjs-global-containers.js +20 -70
  144. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  145. package/lib/root-constructs/nextjs-global-functions.js +52 -69
  146. package/lib/root-constructs/nextjs-regional-containers.d.ts +25 -5
  147. package/lib/root-constructs/nextjs-regional-containers.js +17 -15
  148. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  149. package/lib/root-constructs/nextjs-regional-functions.js +8 -25
  150. package/lib/runtime/api-gateway-path.d.ts +34 -0
  151. package/lib/runtime/api-gateway-path.js +71 -0
  152. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  153. package/lib/runtime/api-gateway-path.test.js +65 -0
  154. package/lib/runtime/case-redirect.d.ts +22 -0
  155. package/lib/runtime/case-redirect.js +63 -0
  156. package/lib/runtime/case-redirect.test.d.ts +1 -0
  157. package/lib/runtime/case-redirect.test.js +32 -0
  158. package/lib/runtime/core.d.ts +234 -0
  159. package/lib/runtime/core.js +1213 -0
  160. package/lib/runtime/core.test.d.ts +1 -0
  161. package/lib/runtime/core.test.js +1678 -0
  162. package/lib/runtime/deployment-root.d.ts +13 -0
  163. package/lib/runtime/deployment-root.js +29 -0
  164. package/lib/runtime/dispatch.d.ts +331 -0
  165. package/lib/runtime/dispatch.js +751 -0
  166. package/lib/runtime/dispatch.test.d.ts +1 -0
  167. package/lib/runtime/dispatch.test.js +853 -0
  168. package/lib/runtime/entrypoints.d.ts +57 -0
  169. package/lib/runtime/entrypoints.js +115 -0
  170. package/lib/runtime/http/abort-signal.d.ts +6 -0
  171. package/lib/runtime/http/abort-signal.js +19 -0
  172. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  173. package/lib/runtime/http/abort-signal.test.js +49 -0
  174. package/lib/runtime/http/node-server.d.ts +38 -0
  175. package/lib/runtime/http/node-server.js +99 -0
  176. package/lib/runtime/http/node-server.test.d.ts +1 -0
  177. package/lib/runtime/http/node-server.test.js +96 -0
  178. package/lib/runtime/http/node-sink.d.ts +16 -0
  179. package/lib/runtime/http/node-sink.js +48 -0
  180. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  181. package/lib/runtime/http/node-sink.test.js +66 -0
  182. package/lib/runtime/http/request.d.ts +62 -0
  183. package/lib/runtime/http/request.js +134 -0
  184. package/lib/runtime/http/request.test.d.ts +1 -0
  185. package/lib/runtime/http/request.test.js +103 -0
  186. package/lib/runtime/http/response.d.ts +77 -0
  187. package/lib/runtime/http/response.js +229 -0
  188. package/lib/runtime/http/response.test.d.ts +1 -0
  189. package/lib/runtime/http/response.test.js +178 -0
  190. package/lib/runtime/http/sink.d.ts +73 -0
  191. package/lib/runtime/http/sink.js +188 -0
  192. package/lib/runtime/http/sink.test.d.ts +1 -0
  193. package/lib/runtime/http/sink.test.js +257 -0
  194. package/lib/runtime/image-utils.d.ts +78 -0
  195. package/lib/runtime/image-utils.js +129 -0
  196. package/lib/runtime/image-utils.test.d.ts +1 -0
  197. package/lib/runtime/image-utils.test.js +237 -0
  198. package/lib/runtime/image.d.ts +76 -0
  199. package/lib/runtime/image.js +296 -0
  200. package/lib/runtime/image.test.d.ts +1 -0
  201. package/lib/runtime/image.test.js +405 -0
  202. package/lib/runtime/lambda-event.d.ts +4 -0
  203. package/lib/runtime/lambda-event.js +113 -0
  204. package/lib/runtime/lambda-event.test.d.ts +1 -0
  205. package/lib/runtime/lambda-event.test.js +119 -0
  206. package/lib/runtime/lambda.mjs +41595 -0
  207. package/lib/runtime/load-module.d.ts +8 -0
  208. package/lib/runtime/load-module.js +35 -0
  209. package/lib/runtime/manifest.d.ts +215 -0
  210. package/lib/runtime/manifest.js +118 -0
  211. package/lib/runtime/middleware.d.ts +43 -0
  212. package/lib/runtime/middleware.js +113 -0
  213. package/lib/runtime/middleware.test.d.ts +1 -0
  214. package/lib/runtime/middleware.test.js +259 -0
  215. package/lib/runtime/next-modules.d.ts +55 -0
  216. package/lib/runtime/next-modules.js +124 -0
  217. package/lib/runtime/next-modules.test.d.ts +1 -0
  218. package/lib/runtime/next-modules.test.js +34 -0
  219. package/lib/runtime/public-files.d.ts +32 -0
  220. package/lib/runtime/public-files.js +117 -0
  221. package/lib/runtime/public-files.test.d.ts +1 -0
  222. package/lib/runtime/public-files.test.js +97 -0
  223. package/lib/runtime/server.mjs +41588 -0
  224. package/lib/runtime/static-files.d.ts +50 -0
  225. package/lib/runtime/static-files.js +266 -0
  226. package/lib/runtime/static-files.test.d.ts +1 -0
  227. package/lib/runtime/static-files.test.js +118 -0
  228. package/lib/runtime/util.d.ts +28 -0
  229. package/lib/runtime/util.js +79 -0
  230. package/lib/utils/base-path.d.ts +123 -11
  231. package/lib/utils/base-path.js +276 -39
  232. package/lib/utils/base-path.test.js +275 -50
  233. package/lib/utils/get-architecture.d.ts +7 -8
  234. package/lib/utils/get-architecture.js +12 -13
  235. package/lib/utils/zip-directory.d.ts +14 -0
  236. package/lib/utils/zip-directory.js +121 -0
  237. package/lib/utils/zip-directory.test.d.ts +1 -0
  238. package/lib/utils/zip-directory.test.js +99 -0
  239. package/package.json +22 -3
  240. package/scripts/capture-adapter-fixture.mjs +325 -0
  241. package/scripts/e2e-deploy.sh +398 -0
  242. package/scripts/e2e-harness/README.md +707 -0
  243. package/scripts/e2e-harness/app.js +370 -0
  244. package/scripts/e2e-harness/common.sh +249 -0
  245. package/scripts/e2e-harness/screen.mjs +302 -0
  246. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  247. package/scripts/e2e-harness/type-filters.mjs +47 -0
  248. package/scripts/e2e-logs.sh +75 -0
  249. package/scripts/e2e-offline.sh +91 -0
  250. package/scripts/e2e-sweep.sh +370 -0
  251. package/scripts/e2e-warm.sh +114 -0
  252. package/scripts/zero-config-build.mjs +418 -0
  253. package/docs/1k-concurrent-users-executions.png +0 -0
  254. package/docs/plans/adapter-runtime-release.md +0 -362
  255. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  256. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  257. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  258. package/lib/image-optimization/handler-utils.d.ts +0 -34
  259. package/lib/image-optimization/handler-utils.js +0 -83
  260. package/lib/image-optimization/handler-utils.test.js +0 -178
  261. package/lib/nextjs-build/functions.Dockerfile +0 -31
  262. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  263. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  264. package/lib/utils/experimental-flags.d.ts +0 -24
  265. package/lib/utils/experimental-flags.js +0 -30
  266. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -1,6 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  /* eslint-disable import/no-extraneous-dependencies */
4
+ const node_fs_1 = require("node:fs");
5
+ const node_os_1 = require("node:os");
6
+ const node_path_1 = require("node:path");
7
+ // What `require.cache` holds in a running server. Jest's `createRequire` hands
8
+ // out a cache of its own that nothing is ever loaded into, so the handler's
9
+ // lookup of Next.js's tag manifest reads this stand-in instead.
10
+ const mockModuleCache = {};
11
+ jest.mock("node:module", () => ({
12
+ ...jest.requireActual("node:module"),
13
+ createRequire: () => ({ cache: mockModuleCache }),
14
+ }));
4
15
  // Mock AWS SDK
5
16
  jest.mock("@aws-sdk/client-s3");
6
17
  jest.mock("@aws-sdk/client-dynamodb");
@@ -11,6 +22,8 @@ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
11
22
  const client_s3_1 = require("@aws-sdk/client-s3");
12
23
  const client_ssm_1 = require("@aws-sdk/client-ssm");
13
24
  const s3_cache_handler_1 = require("./s3-cache-handler");
25
+ const use_cache_common_1 = require("./use-cache-common");
26
+ const manifest_1 = require("../runtime/manifest");
14
27
  const mockS3Send = jest.fn();
15
28
  const mockDynamoSend = jest.fn();
16
29
  const mockCloudFrontSend = jest.fn();
@@ -30,13 +43,60 @@ client_ssm_1.SSMClient.mockImplementation(() => ({
30
43
  describe("S3DynamoCacheHandler", () => {
31
44
  let handler;
32
45
  let mockContext;
46
+ let distDir;
47
+ /** Stage `required-server-files.json` for an app with `basePath: "/base"`. */
48
+ const useBasePath = () => {
49
+ distDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "s3-cache-handler-"));
50
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(distDir, "required-server-files.json"), JSON.stringify({ config: { basePath: "/base" } }));
51
+ mockContext.serverDistDir = (0, node_path_1.join)(distDir, "server");
52
+ };
33
53
  // Helper to create set context with tags
34
54
  const createSetContext = (tags) => ({
35
55
  fetchCache: true,
36
56
  tags,
37
57
  });
58
+ /**
59
+ * The input a mocked command was constructed with. The SDK's command classes
60
+ * are automocked, so an instance carries nothing of its own.
61
+ */
62
+ const commandInput = (command, type) => {
63
+ const mock = type;
64
+ return mock.mock.calls[mock.mock.instances.indexOf(command)][0];
65
+ };
66
+ /**
67
+ * Answer DynamoDB by command type rather than by call order: `revalidateTag`
68
+ * writes its tag marker before querying the tag's mapping rows, and which of
69
+ * those comes first is an implementation detail. `get` is the marker row every
70
+ * requested tag has, as a `GetItem` would have returned it.
71
+ */
72
+ const dynamoResponses = (responses) => {
73
+ mockDynamoSend.mockImplementation((command) => {
74
+ if (command instanceof client_dynamodb_1.QueryCommand) {
75
+ return Promise.resolve(responses.query ?? {});
76
+ }
77
+ if (command instanceof client_dynamodb_1.BatchGetItemCommand) {
78
+ const { RequestItems } = commandInput(command, client_dynamodb_1.BatchGetItemCommand);
79
+ const [[table, { Keys }]] = Object.entries(RequestItems);
80
+ const item = responses.get?.Item;
81
+ return Promise.resolve({
82
+ Responses: {
83
+ [table]: item ? Keys.map(({ sk }) => ({ ...item, sk })) : [],
84
+ },
85
+ });
86
+ }
87
+ return Promise.resolve({});
88
+ });
89
+ };
90
+ /**
91
+ * Drop the process's tag manifest, so the next handler starts with one of
92
+ * its own, as a new instance does.
93
+ */
94
+ const resetTagManifest = () => {
95
+ delete globalThis[Symbol.for("cdk-nextjs.use-cache.tag-manifest")];
96
+ };
38
97
  beforeEach(() => {
39
98
  mockContext = { dev: false };
99
+ resetTagManifest();
40
100
  // Set up environment variables
41
101
  process.env.CDK_NEXTJS_CACHE_BUCKET_NAME = "test-bucket";
42
102
  process.env.CDK_NEXTJS_REVALIDATION_TABLE_NAME = "test-table";
@@ -49,6 +109,8 @@ describe("S3DynamoCacheHandler", () => {
49
109
  });
50
110
  // Reset mocks
51
111
  mockS3Send.mockReset();
112
+ // An empty bucket: no object, such as no build tag manifest.
113
+ mockS3Send.mockResolvedValue({});
52
114
  mockDynamoSend.mockReset();
53
115
  mockCloudFrontSend.mockReset();
54
116
  mockSsmSend.mockReset();
@@ -60,6 +122,11 @@ describe("S3DynamoCacheHandler", () => {
60
122
  delete process.env.CDK_NEXTJS_BUILD_ID;
61
123
  delete process.env.AWS_REGION;
62
124
  delete process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME;
125
+ delete process.env.CDK_NEXTJS_DISTRIBUTION_ID;
126
+ if (distDir) {
127
+ (0, node_fs_1.rmSync)(distDir, { recursive: true, force: true });
128
+ distDir = undefined;
129
+ }
63
130
  // Restore console.warn
64
131
  jest.restoreAllMocks();
65
132
  });
@@ -114,6 +181,346 @@ describe("S3DynamoCacheHandler", () => {
114
181
  });
115
182
  expect(result).toBeNull();
116
183
  });
184
+ it("invalidates a seeded prerender only when its tag marker is newer", async () => {
185
+ // A build-time prerender is written as a file by the adapter's
186
+ // `onBuildComplete`, never through `set`, so it has no `tags` array and no
187
+ // DynamoDB mapping rows - its tags live in the render's
188
+ // `x-next-cache-tags` header. Two bugs met here: those header tags were
189
+ // ignored, so `revalidateTag` could not reach any static page; and the
190
+ // mapping rows `set` writes were stamped `revalidatedAt = now`, which is
191
+ // *after* the entry's own `lastModified`, so a tagged entry looked
192
+ // revalidated the moment it was stored and every request re-rendered.
193
+ // Measured against next.js's `test/e2e/app-dir/resume-data-cache`.
194
+ const lastModified = Date.now();
195
+ const seeded = {
196
+ lastModified,
197
+ value: {
198
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
199
+ html: "<html>seeded</html>",
200
+ headers: { "x-next-cache-tags": "_N_T_/,_N_T_/page,test" },
201
+ },
202
+ };
203
+ const s3Body = () => ({
204
+ Body: {
205
+ transformToString: jest
206
+ .fn()
207
+ .mockResolvedValue(JSON.stringify(seeded)),
208
+ },
209
+ ContentType: "application/json",
210
+ });
211
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand ? s3Body() : {}));
212
+ const getCtx = {
213
+ kind: "APP_PAGE" /* IncrementalCacheKind.APP_PAGE */,
214
+ isFallback: false,
215
+ };
216
+ // Each step below changes the markers DynamoDB holds; a new instance
217
+ // reads them afresh.
218
+ const freshHandler = () => {
219
+ resetTagManifest();
220
+ return new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
221
+ };
222
+ // No marker at all: the tag was never revalidated.
223
+ dynamoResponses({});
224
+ expect(await freshHandler().get("index", getCtx)).toMatchObject({
225
+ lastModified,
226
+ });
227
+ // A marker older than the entry means the entry already reflects it.
228
+ dynamoResponses({
229
+ get: { Item: { revalidatedAt: { N: String(lastModified - 1000) } } },
230
+ });
231
+ expect(await freshHandler().get("index", getCtx)).toMatchObject({
232
+ lastModified,
233
+ });
234
+ expect(mockS3Send).not.toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
235
+ // A newer marker: the entry comes back marked expired, and stays in S3.
236
+ dynamoResponses({
237
+ get: { Item: { revalidatedAt: { N: String(lastModified + 1000) } } },
238
+ });
239
+ expect(await freshHandler().get("index", getCtx)).toMatchObject({
240
+ lastModified: -1,
241
+ value: seeded.value,
242
+ });
243
+ expect(mockS3Send).not.toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
244
+ });
245
+ it("reports a revalidated response entry as expired rather than as a miss", async () => {
246
+ // `lastModified: -1` is how a cache handler says "expired, re-render
247
+ // before answering": `IncrementalCache.get` turns it into `isStale: -1`,
248
+ // which `app-page-runtime` reads as an on-demand revalidation and answers
249
+ // with a blocking render of this route, then stores it. Returning `null`
250
+ // is not equivalent. A miss on a PPR route whose `prerender-manifest.json`
251
+ // entry has a `fallback` (`compute: "resuming"`) is answered from the
252
+ // route's fallback shell - `cache-control: private, no-store`, no
253
+ // `x-nextjs-cache` - and without `partialPrefetching` nothing ever
254
+ // upgrades that back into a concrete entry. So the first `revalidateTag`
255
+ // to reach a page left it uncacheable and dynamically resumed per request
256
+ // for the rest of the deployment's life, which is what the isr e2e's
257
+ // missing `x-nextjs-cache` header was.
258
+ const lastModified = Date.now();
259
+ const stored = {
260
+ lastModified,
261
+ tags: ["collection"],
262
+ value: {
263
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
264
+ html: "<html>isr</html>",
265
+ headers: { "x-next-cache-tags": "collection" },
266
+ },
267
+ };
268
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
269
+ ? {
270
+ Body: {
271
+ transformToString: jest
272
+ .fn()
273
+ .mockResolvedValue(JSON.stringify(stored)),
274
+ },
275
+ ContentType: "application/json",
276
+ }
277
+ : {}));
278
+ dynamoResponses({
279
+ get: { Item: { revalidatedAt: { N: String(lastModified + 1000) } } },
280
+ });
281
+ const result = await handler.get("isr/1", {
282
+ kind: "APP_PAGE" /* IncrementalCacheKind.APP_PAGE */,
283
+ isFallback: false,
284
+ });
285
+ expect(result).toEqual({ lastModified: -1, value: stored.value });
286
+ // The body is still there for the render that fails, and `set` overwrites
287
+ // it with a `lastModified` past the marker.
288
+ expect(mockS3Send).not.toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
289
+ });
290
+ it("reports a revalidated fetch entry as a miss so the request refetches", async () => {
291
+ // The opposite of a response entry: reusing a revalidated `fetch` body is
292
+ // serving stale data, so this reads as a miss, like Next.js's own
293
+ // `FileSystemCache` does for its `revalidatedTags`.
294
+ const lastModified = Date.now();
295
+ const stored = {
296
+ lastModified,
297
+ tags: ["collection"],
298
+ value: {
299
+ kind: "FETCH" /* CachedRouteKind.FETCH */,
300
+ data: { headers: {}, body: "stale", status: 200, url: "/api" },
301
+ revalidate: 10,
302
+ },
303
+ };
304
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
305
+ ? {
306
+ Body: {
307
+ transformToString: jest
308
+ .fn()
309
+ .mockResolvedValue(JSON.stringify(stored)),
310
+ },
311
+ ContentType: "application/json",
312
+ }
313
+ : {}));
314
+ dynamoResponses({
315
+ get: { Item: { revalidatedAt: { N: String(lastModified + 1000) } } },
316
+ });
317
+ const result = await handler.get("fetch-key", {
318
+ kind: "FETCH" /* IncrementalCacheKind.FETCH */,
319
+ revalidate: 10,
320
+ fetchUrl: "https://example.test/api",
321
+ fetchIdx: 1,
322
+ tags: ["collection"],
323
+ softTags: [],
324
+ });
325
+ expect(result).toBeNull();
326
+ // Not deleted: the refetch this provokes overwrites it through `set`.
327
+ // Deleting it here raced that write, so a concurrent request's fresh
328
+ // entry could be the one removed.
329
+ expect(mockS3Send).not.toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
330
+ expect(client_dynamodb_1.DeleteItemCommand).not.toHaveBeenCalled();
331
+ });
332
+ it("checks a fetch entry against the request's implicit tags, not its own", async () => {
333
+ // An untagged `cache: "force-cache"` fetch is stored with no tags at all -
334
+ // the implicit `_N_T_/<path>` chain reaches the handler only as
335
+ // `ctx.softTags`, which is the source Next.js's own `FileSystemCache` reads
336
+ // for a `FETCH` get. Checking the stored tags instead left this entry with
337
+ // nothing to check and no `revalidatePath` could ever evict it.
338
+ const lastModified = Date.now();
339
+ const stored = {
340
+ lastModified,
341
+ tags: [],
342
+ value: {
343
+ kind: "FETCH" /* CachedRouteKind.FETCH */,
344
+ data: { headers: {}, body: "stale", status: 200, url: "/api" },
345
+ revalidate: 10,
346
+ },
347
+ };
348
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
349
+ ? {
350
+ Body: {
351
+ transformToString: jest
352
+ .fn()
353
+ .mockResolvedValue(JSON.stringify(stored)),
354
+ },
355
+ ContentType: "application/json",
356
+ }
357
+ : {}));
358
+ dynamoResponses({
359
+ get: { Item: { revalidatedAt: { N: String(lastModified + 1000) } } },
360
+ });
361
+ const result = await handler.get("fetch-key", {
362
+ kind: "FETCH" /* IncrementalCacheKind.FETCH */,
363
+ revalidate: 10,
364
+ fetchUrl: "https://next-data-api-endpoint.test/api/random",
365
+ fetchIdx: 1,
366
+ tags: [],
367
+ softTags: ["_N_T_/layout", "_N_T_/dynamic"],
368
+ });
369
+ expect(result).toBeNull();
370
+ const [{ RequestItems }] = client_dynamodb_1.BatchGetItemCommand
371
+ .mock.calls[0];
372
+ expect(RequestItems["test-table"].Keys.map((key) => key.sk.S)).toEqual(["_N_T_/layout", "_N_T_/dynamic"]);
373
+ });
374
+ describe("a tag revalidated with a profile", () => {
375
+ // `revalidateTag("posts", "max")` is stale-while-revalidate: the entry is
376
+ // served once more while a background render replaces it, and expires
377
+ // outright only after the profile's `expire`. Treating it as `updateTag`
378
+ // made every such call a blocking re-render.
379
+ const lastModified = Date.now() - 1000;
380
+ const stored = {
381
+ lastModified,
382
+ value: {
383
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
384
+ html: "<html>posts</html>",
385
+ headers: { "x-next-cache-tags": "posts" },
386
+ },
387
+ };
388
+ const getCtx = {
389
+ kind: "APP_PAGE" /* IncrementalCacheKind.APP_PAGE */,
390
+ isFallback: false,
391
+ };
392
+ const manifestPath = (0, node_path_1.join)("/deployment/node_modules/next/dist/server/lib/incremental-cache", "tags-manifest.external.js");
393
+ // The module the server loads, resolved for real, so a Next.js upgrade
394
+ // that moves or reshapes it fails here rather than silently turning
395
+ // stale-while-revalidate into blocking renders.
396
+ const realManifestPath = require.resolve("next/dist/server/lib/incremental-cache/tags-manifest.external.js");
397
+ beforeEach(() => {
398
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
399
+ ? {
400
+ Body: {
401
+ transformToString: jest
402
+ .fn()
403
+ .mockResolvedValue(JSON.stringify(stored)),
404
+ },
405
+ ContentType: "application/json",
406
+ }
407
+ : {}));
408
+ });
409
+ afterEach(() => {
410
+ delete mockModuleCache[manifestPath];
411
+ delete mockModuleCache[realManifestPath];
412
+ });
413
+ it("serves the entry and marks the tag stale in Next.js's manifest", async () => {
414
+ const next = jest.requireActual(realManifestPath);
415
+ mockModuleCache[realManifestPath] = { exports: next };
416
+ const staleAt = lastModified + 500;
417
+ dynamoResponses({
418
+ get: {
419
+ Item: {
420
+ staleAt: { N: String(staleAt) },
421
+ expiredAt: { N: String(Date.now() + 60_000) },
422
+ },
423
+ },
424
+ });
425
+ expect(await handler.get("posts", getCtx)).toEqual({
426
+ lastModified,
427
+ value: stored.value,
428
+ });
429
+ // Where `IncrementalCache.get` reads it, to answer `isStale: true`.
430
+ expect(next.tagsManifest.get("posts")).toEqual({ stale: staleAt });
431
+ expect(next.areTagsStale(["posts"], lastModified)).toBe(true);
432
+ });
433
+ it("expires the entry when Next.js's manifest cannot be found", async () => {
434
+ // A stale mark nothing reads would serve the entry as fresh; a blocking
435
+ // render is the safe side of that.
436
+ dynamoResponses({
437
+ get: { Item: { staleAt: { N: String(lastModified + 500) } } },
438
+ });
439
+ expect(await handler.get("posts", getCtx)).toMatchObject({
440
+ lastModified: -1,
441
+ });
442
+ });
443
+ it("expires the entry once the profile's expire has passed", async () => {
444
+ dynamoResponses({
445
+ get: {
446
+ Item: {
447
+ staleAt: { N: String(lastModified + 100) },
448
+ expiredAt: { N: String(lastModified + 500) },
449
+ },
450
+ },
451
+ });
452
+ expect(await handler.get("posts", getCtx)).toMatchObject({
453
+ lastModified: -1,
454
+ });
455
+ });
456
+ describe("behind a distribution", () => {
457
+ // `revalidateTag`'s invalidation goes out before the stale entry is
458
+ // served, and the stale response carries the entry's original
459
+ // `s-maxage`: CloudFront caches it again. Only the regeneration's `set`
460
+ // knows when the fresh entry exists to be fetched instead.
461
+ let cdnHandler;
462
+ const regenerated = stored.value;
463
+ const invalidatedPaths = () => client_cloudfront_1.CreateInvalidationCommand.mock.calls.map(([input]) => input.InvalidationBatch.Paths.Items);
464
+ beforeEach(() => {
465
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
466
+ cdnHandler = new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
467
+ mockModuleCache[manifestPath] = {
468
+ exports: { tagsManifest: new Map() },
469
+ };
470
+ dynamoResponses({
471
+ get: { Item: { staleAt: { N: String(lastModified + 500) } } },
472
+ });
473
+ mockSsmSend.mockResolvedValue({
474
+ Parameter: { Value: "test-distribution-id" },
475
+ });
476
+ mockCloudFrontSend.mockResolvedValue({});
477
+ });
478
+ it("invalidates the page again once its regeneration is stored", async () => {
479
+ await cdnHandler.get("posts", getCtx);
480
+ expect(invalidatedPaths()).toEqual([]);
481
+ await cdnHandler.set("posts", regenerated, {
482
+ cacheControl: { revalidate: false, expire: undefined },
483
+ isRoutePPREnabled: false,
484
+ isFallback: false,
485
+ });
486
+ expect(invalidatedPaths()).toEqual([["/posts*"]]);
487
+ // Once: a later write of the same page is an ordinary one.
488
+ await cdnHandler.set("posts", regenerated, {
489
+ cacheControl: { revalidate: false, expire: undefined },
490
+ isRoutePPREnabled: false,
491
+ isFallback: false,
492
+ });
493
+ expect(invalidatedPaths()).toHaveLength(1);
494
+ });
495
+ it("remembers a stale memory hit by the key it was read under", async () => {
496
+ await cdnHandler.isRevalidated(stored, getCtx, "posts");
497
+ await cdnHandler.set("posts", regenerated, {
498
+ isRoutePPREnabled: false,
499
+ isFallback: false,
500
+ });
501
+ expect(invalidatedPaths()).toEqual([["/posts*"]]);
502
+ });
503
+ it("does not invalidate after an ordinary write", async () => {
504
+ await cdnHandler.set("posts", regenerated, {
505
+ isRoutePPREnabled: false,
506
+ isFallback: false,
507
+ });
508
+ expect(invalidatedPaths()).toEqual([]);
509
+ });
510
+ it("forgets a stale page that is deleted instead of regenerated", async () => {
511
+ await cdnHandler.get("posts", getCtx);
512
+ await cdnHandler.set("posts", null, {
513
+ isRoutePPREnabled: false,
514
+ isFallback: false,
515
+ });
516
+ await cdnHandler.set("posts", regenerated, {
517
+ isRoutePPREnabled: false,
518
+ isFallback: false,
519
+ });
520
+ expect(invalidatedPaths()).toEqual([]);
521
+ });
522
+ });
523
+ });
117
524
  it("should handle S3 errors and return null", async () => {
118
525
  mockS3Send.mockRejectedValueOnce(new Error("S3 Error"));
119
526
  const result = await handler.get("error-key", {
@@ -123,7 +530,109 @@ describe("S3DynamoCacheHandler", () => {
123
530
  expect(result).toBeNull();
124
531
  });
125
532
  });
533
+ describe("tag marker cache", () => {
534
+ // Every cache hit checks its tags' markers, and all of a deployment's
535
+ // markers share one partition key: read per request, they capped a route's
536
+ // cache hits at ~1,900 req/s. Each instance holds them for a second.
537
+ const lastModified = Date.now() - 60_000;
538
+ const stored = {
539
+ lastModified,
540
+ value: {
541
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
542
+ html: "<html>cached</html>",
543
+ headers: { "x-next-cache-tags": "_N_T_/page,posts" },
544
+ },
545
+ };
546
+ const getCtx = {
547
+ kind: "APP_PAGE" /* IncrementalCacheKind.APP_PAGE */,
548
+ isFallback: false,
549
+ };
550
+ const markerReads = () => mockDynamoSend.mock.calls.filter(([command]) => command instanceof client_dynamodb_1.BatchGetItemCommand).length;
551
+ // What `get` answers for a revalidated page: expired, not a miss.
552
+ const expired = { lastModified: -1 };
553
+ const revalidatedAfterStore = {
554
+ get: { Item: { revalidatedAt: { N: String(lastModified + 1000) } } },
555
+ };
556
+ beforeEach(() => {
557
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
558
+ ? {
559
+ Body: {
560
+ transformToString: jest
561
+ .fn()
562
+ .mockResolvedValue(JSON.stringify(stored)),
563
+ },
564
+ ContentType: "application/json",
565
+ }
566
+ : {}));
567
+ dynamoResponses({});
568
+ });
569
+ it("answers checks within the TTL from the markers it already read", async () => {
570
+ await handler.get("page", getCtx);
571
+ await handler.get("page", getCtx);
572
+ expect(markerReads()).toBe(1);
573
+ });
574
+ it("shares one read between concurrent checks", async () => {
575
+ await Promise.all([
576
+ handler.get("page", getCtx),
577
+ handler.get("page", getCtx),
578
+ handler.get("page", getCtx),
579
+ ]);
580
+ expect(markerReads()).toBe(1);
581
+ });
582
+ it("sees its own revalidateTag at once, and logs it for the others", async () => {
583
+ expect(await handler.get("page", getCtx)).toMatchObject({ lastModified });
584
+ dynamoResponses(revalidatedAfterStore);
585
+ await handler.revalidateTag("posts");
586
+ expect(await handler.get("page", getCtx)).toMatchObject(expired);
587
+ const puts = mockDynamoSend.mock.calls.filter(([command]) => command instanceof client_dynamodb_1.PutItemCommand);
588
+ expect(puts).toHaveLength(1);
589
+ expect(commandInput(puts[0][0], client_dynamodb_1.PutItemCommand).Item).toMatchObject({
590
+ pk: { S: "test-build-id#log" },
591
+ sk: { S: expect.stringMatching(/^\d{15}#posts$/) },
592
+ revalidatedAt: { N: expect.any(String) },
593
+ ttl: { N: expect.any(String) },
594
+ });
595
+ });
596
+ it("writes each tag once when the 'use cache' handlers get the same call", async () => {
597
+ // Next.js calls `revalidateTag` here and `updateTags` on every
598
+ // `cacheHandlers` entry, and all of them share one manifest.
599
+ await Promise.all([
600
+ handler.revalidateTag(["posts"]),
601
+ (0, use_cache_common_1.sharedTagManifest)().update(["posts"], undefined),
602
+ ]);
603
+ const writes = mockDynamoSend.mock.calls.filter(([command]) => command instanceof client_dynamodb_1.UpdateItemCommand ||
604
+ command instanceof client_dynamodb_1.PutItemCommand);
605
+ expect(writes).toHaveLength(2);
606
+ });
607
+ });
126
608
  describe("set", () => {
609
+ // Mapping rows exist only to name CloudFront paths, so only a deployment
610
+ // with a distribution keeps them.
611
+ beforeEach(() => {
612
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
613
+ handler = new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
614
+ });
615
+ it("keeps no mapping rows without a distribution to invalidate", async () => {
616
+ // The Regional constructs have no CloudFront. A row per tag per `set`,
617
+ // and the S3 read before a delete to name them, bought nothing there.
618
+ delete process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME;
619
+ const regional = new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
620
+ mockS3Send.mockResolvedValue({});
621
+ mockDynamoSend.mockResolvedValue({});
622
+ await regional.set("/isr/1", {
623
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
624
+ html: "<p/>",
625
+ rscData: undefined,
626
+ headers: { "x-next-cache-tags": "tag" },
627
+ postponed: undefined,
628
+ segmentData: undefined,
629
+ status: undefined,
630
+ }, createSetContext([]));
631
+ await regional.set("/isr/1", null, { isFallback: false });
632
+ expect(mockDynamoSend).not.toHaveBeenCalled();
633
+ expect(mockS3Send).not.toHaveBeenCalledWith(expect.any(client_s3_1.GetObjectCommand));
634
+ expect(mockS3Send).toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
635
+ });
127
636
  it("should store cache value in S3", async () => {
128
637
  const testData = {
129
638
  kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
@@ -157,6 +666,124 @@ describe("S3DynamoCacheHandler", () => {
157
666
  await handlerWithoutBucket.set("no-bucket-key", testData, createSetContext([]));
158
667
  expect(mockS3Send).not.toHaveBeenCalled();
159
668
  });
669
+ it("maps the tags a page carries only in its x-next-cache-tags header", async () => {
670
+ // `ResponseCache.set` builds a page's `ctx` without tags, so the render's
671
+ // header is the only place they exist. No mapping row meant `revalidateTag`
672
+ // found nothing to invalidate and CloudFront kept the stale HTML.
673
+ const testData = {
674
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
675
+ html: "<html>tagged</html>",
676
+ rscData: undefined,
677
+ headers: { "x-next-cache-tags": "header-tag,other-tag" },
678
+ postponed: undefined,
679
+ segmentData: undefined,
680
+ status: undefined,
681
+ };
682
+ mockS3Send.mockResolvedValue({});
683
+ mockDynamoSend.mockResolvedValue({});
684
+ await handler.set("/isr/1", testData, createSetContext([]));
685
+ const mappingKeys = client_dynamodb_1.UpdateItemCommand.mock.calls
686
+ .map(([input]) => input.Key.sk.S)
687
+ .sort();
688
+ expect(mappingKeys).toEqual([
689
+ "header-tag#test-build-id/isr/1.json",
690
+ "other-tag#test-build-id/isr/1.json",
691
+ ]);
692
+ });
693
+ it("prefers the context's tags over the header when both are present", async () => {
694
+ const testData = {
695
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
696
+ html: "<html>tagged</html>",
697
+ rscData: undefined,
698
+ headers: { "x-next-cache-tags": "header-tag" },
699
+ postponed: undefined,
700
+ segmentData: undefined,
701
+ status: undefined,
702
+ };
703
+ mockS3Send.mockResolvedValue({});
704
+ mockDynamoSend.mockResolvedValue({});
705
+ await handler.set("/isr/1", testData, createSetContext(["ctx-tag"]));
706
+ const mappingKeys = client_dynamodb_1.UpdateItemCommand.mock.calls
707
+ .map(([input]) => input.Key.sk.S)
708
+ .sort();
709
+ expect(mappingKeys).toEqual(["ctx-tag#test-build-id/isr/1.json"]);
710
+ });
711
+ it("removes a deleted page's mapping rows, reading its tags from S3", async () => {
712
+ // A response delete - a cached route that starts answering `notFound()` -
713
+ // arrives as `set(key, null, { cacheControl, ... })` with no tags at all,
714
+ // so the entry itself is the only place its mapping rows can be named
715
+ // from. Left behind, they resolve on the next `revalidateTag` to a cache
716
+ // key whose object is gone and spend a CloudFront wildcard path on it.
717
+ const stored = {
718
+ lastModified: Date.now(),
719
+ tags: ["collection", "_N_T_/isr/1"],
720
+ value: {
721
+ kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
722
+ html: "<html>gone</html>",
723
+ },
724
+ };
725
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
726
+ ? {
727
+ Body: {
728
+ transformToString: jest
729
+ .fn()
730
+ .mockResolvedValue(JSON.stringify(stored)),
731
+ },
732
+ ContentType: "application/json",
733
+ }
734
+ : {}));
735
+ mockDynamoSend.mockResolvedValue({});
736
+ await handler.set("/isr/1", null, {
737
+ cacheControl: { revalidate: 60, expire: undefined },
738
+ isRoutePPREnabled: false,
739
+ isFallback: false,
740
+ });
741
+ expect(mockS3Send).toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
742
+ const deletedKeys = client_dynamodb_1.DeleteItemCommand.mock.calls
743
+ .map(([input]) => input.Key.sk.S)
744
+ .sort();
745
+ // Mapping rows only. The bare-tag marker row belongs to the tag, and
746
+ // `checkIfRevalidated` reads it for every other entry carrying it.
747
+ expect(deletedKeys).toEqual([
748
+ "_N_T_/isr/1#test-build-id/isr/1.json",
749
+ "collection#test-build-id/isr/1.json",
750
+ ]);
751
+ });
752
+ it("deletes a fetch entry's mapping rows from the context's tags alone", async () => {
753
+ // `ctx` carries them here, so the pre-delete read is skipped: only the
754
+ // DeleteObject reaches S3.
755
+ mockS3Send.mockResolvedValue({});
756
+ mockDynamoSend.mockResolvedValue({});
757
+ await handler.set("fetch-key", null, createSetContext(["ctx-tag"]));
758
+ expect(mockS3Send).not.toHaveBeenCalledWith(expect.any(client_s3_1.GetObjectCommand));
759
+ const deletedKeys = client_dynamodb_1.DeleteItemCommand.mock.calls.map(([input]) => input.Key.sk.S);
760
+ expect(deletedKeys).toEqual(["ctx-tag#test-build-id/fetch-key.json"]);
761
+ });
762
+ it("deletes no mapping rows for an untagged entry", async () => {
763
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
764
+ ? {
765
+ Body: {
766
+ transformToString: jest.fn().mockResolvedValue(JSON.stringify({
767
+ lastModified: Date.now(),
768
+ value: { kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */, html: "<p/>" },
769
+ })),
770
+ },
771
+ ContentType: "application/json",
772
+ }
773
+ : {}));
774
+ mockDynamoSend.mockResolvedValue({});
775
+ await handler.set("/untagged", null, { isFallback: false });
776
+ expect(mockS3Send).toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
777
+ expect(client_dynamodb_1.DeleteItemCommand).not.toHaveBeenCalled();
778
+ });
779
+ it("still deletes the object when its tags cannot be read", async () => {
780
+ mockS3Send.mockImplementation((command) => command instanceof client_s3_1.GetObjectCommand
781
+ ? Promise.reject(new Error("S3 Get Error"))
782
+ : Promise.resolve({}));
783
+ mockDynamoSend.mockResolvedValue({});
784
+ await expect(handler.set("/isr/1", null, { isFallback: false })).resolves.not.toThrow();
785
+ expect(mockS3Send).toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
786
+ });
160
787
  it("should handle S3 errors gracefully", async () => {
161
788
  const testData = {
162
789
  kind: "APP_PAGE" /* CachedRouteKind.APP_PAGE */,
@@ -173,20 +800,32 @@ describe("S3DynamoCacheHandler", () => {
173
800
  });
174
801
  });
175
802
  describe("revalidateTag", () => {
176
- it("should query DynamoDB and delete S3 entries", async () => {
803
+ it("should record the revalidation without deleting the tag's S3 entries", async () => {
177
804
  const mockQueryResponse = {
178
805
  Items: [
179
806
  { sk: { S: "test-tag#cache-key-1" } },
180
807
  { sk: { S: "test-tag#cache-key-2" } },
181
808
  ],
182
809
  };
183
- mockDynamoSend.mockResolvedValueOnce(mockQueryResponse);
184
- mockDynamoSend.mockResolvedValue({}); // For update commands
185
- mockS3Send.mockResolvedValue({}); // For delete commands
810
+ dynamoResponses({ query: mockQueryResponse });
811
+ mockS3Send.mockResolvedValue({});
186
812
  await handler.revalidateTag("test-tag");
187
- expect(mockDynamoSend).toHaveBeenCalledWith(expect.any(client_dynamodb_1.QueryCommand));
813
+ // No distribution, so no mapping rows to read: the marker is all of it.
814
+ expect(mockDynamoSend).not.toHaveBeenCalledWith(expect.any(client_dynamodb_1.QueryCommand));
188
815
  expect(mockDynamoSend).toHaveBeenCalledWith(expect.any(client_dynamodb_1.UpdateItemCommand));
189
- expect(mockS3Send).toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
816
+ // The marker row is the invalidation; `get` reads it and hands the entry
817
+ // back expired so Next.js re-renders the route and replaces the object.
818
+ // Deleting the objects here made the next request a hard miss, which on a
819
+ // PPR route is answered from the uncacheable fallback shell for good.
820
+ expect(mockS3Send).not.toHaveBeenCalledWith(expect.any(client_s3_1.DeleteObjectCommand));
821
+ // The tag marker `checkIfRevalidated` reads: keyed by the bare tag, so
822
+ // entries with no mapping row of their own still see the revalidation.
823
+ const markerWrite = client_dynamodb_1.UpdateItemCommand.mock.calls
824
+ .map(([input]) => input)
825
+ .find((input) => input.Key.sk.S === "test-tag");
826
+ expect(markerWrite).toMatchObject({
827
+ UpdateExpression: "SET revalidatedAt = :revalidatedAt",
828
+ });
190
829
  });
191
830
  it("should not revalidate when DynamoDB table is not configured", async () => {
192
831
  delete process.env.CDK_NEXTJS_REVALIDATION_TABLE_NAME;
@@ -212,8 +851,7 @@ describe("S3DynamoCacheHandler", () => {
212
851
  { sk: { S: "test-tag#test-build-id/isr/2.json" } },
213
852
  ],
214
853
  };
215
- mockDynamoSend.mockResolvedValueOnce(mockQueryResponse);
216
- mockDynamoSend.mockResolvedValue({}); // For update commands
854
+ dynamoResponses({ query: mockQueryResponse });
217
855
  mockS3Send.mockResolvedValue({}); // For delete commands
218
856
  mockSsmSend.mockResolvedValue({
219
857
  Parameter: { Value: "test-distribution-id" },
@@ -224,14 +862,146 @@ describe("S3DynamoCacheHandler", () => {
224
862
  expect(mockCloudFrontSend).toHaveBeenCalledWith(expect.any(client_cloudfront_1.CreateInvalidationCommand));
225
863
  const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
226
864
  expect(invalidationInput.DistributionId).toBe("test-distribution-id");
227
- expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual(expect.arrayContaining(["/isr/1", "/isr/2"]));
865
+ // One trailing wildcard per page: an invalidation path matches only the
866
+ // query string it spells out, and a page's RSC payload is cached under
867
+ // `?_rsc=<hash>` - `/isr/1*` covers it, and the slash variant, for one
868
+ // of the fifteen wildcards instead of two.
869
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual([
870
+ "/isr/1*",
871
+ "/isr/2*",
872
+ ]);
873
+ });
874
+ it("invalidates a distribution whose ID is in the environment without SSM", async () => {
875
+ // NextjsGlobalContainers: the task can name the distribution directly.
876
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID = "direct-distribution-id";
877
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
878
+ context: mockContext,
879
+ });
880
+ dynamoResponses({
881
+ query: { Items: [{ sk: { S: "test-tag#test-build-id/isr/1.json" } }] },
882
+ });
883
+ mockS3Send.mockResolvedValue({});
884
+ mockCloudFrontSend.mockResolvedValue({});
885
+ await handlerWithDistribution.revalidateTag("test-tag");
886
+ expect(mockSsmSend).not.toHaveBeenCalled();
887
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
888
+ expect(invalidationInput.DistributionId).toBe("direct-distribution-id");
889
+ });
890
+ it("splits a mapping row at the tag's length, so a tag containing # still resolves", async () => {
891
+ // A tag is app-defined: `revalidateTag("user#42")` is legal. Splitting at
892
+ // the first "#" left "42#test-build-id/account.json" as the S3 key, whose
893
+ // invalidation path names nothing CloudFront cached, so the page stayed
894
+ // stale while the row was stamped revalidated and never retried.
895
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
896
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
897
+ context: mockContext,
898
+ });
899
+ dynamoResponses({
900
+ query: { Items: [{ sk: { S: "user#42#test-build-id/account.json" } }] },
901
+ });
902
+ mockSsmSend.mockResolvedValue({
903
+ Parameter: { Value: "test-distribution-id" },
904
+ });
905
+ mockCloudFrontSend.mockResolvedValue({});
906
+ await handlerWithDistribution.revalidateTag("user#42");
907
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
908
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual([
909
+ "/account*",
910
+ ]);
911
+ });
912
+ it("invalidates the path a revalidatePath tag names even with no mapping rows", async () => {
913
+ // A build-time prerender has no mapping rows, so the query comes back
914
+ // empty and there is nothing to derive a CloudFront path from - except the
915
+ // tag, which for `revalidatePath` is `_N_T_<path>`. Without this the CDN
916
+ // answers with the pre-revalidation page until `s-maxage=31536000`
917
+ // expires. Measured against next.js's `test/e2e/app-dir/trailingslash`.
918
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
919
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
920
+ context: mockContext,
921
+ });
922
+ dynamoResponses({ query: { Items: [] } });
923
+ mockSsmSend.mockResolvedValue({
924
+ Parameter: { Value: "test-distribution-id" },
925
+ });
926
+ mockCloudFrontSend.mockResolvedValue({});
927
+ await handlerWithDistribution.revalidateTag("_N_T_/en/legacy/");
928
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
929
+ // Both slash variants, which the trailing wildcard covers: a
930
+ // `trailingSlash` app's cached URI is the redirect target, not the route.
931
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual([
932
+ "/en/legacy*",
933
+ ]);
934
+ });
935
+ it("invalidates the URI under the app's basePath, not the bare route", async () => {
936
+ // CloudFront cached `/base/isr/1`; the cache key and the `revalidatePath`
937
+ // tag both name `/isr/1`, because Next.js strips `basePath` before routing
938
+ // and never shows it to the cache handler. Invalidating the bare route
939
+ // matches nothing at the edge, so the stale page survives until
940
+ // `s-maxage` expires.
941
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
942
+ useBasePath();
943
+ const handlerWithBasePath = new s3_cache_handler_1.S3CacheHandler({
944
+ context: mockContext,
945
+ });
946
+ dynamoResponses({
947
+ query: {
948
+ Items: [
949
+ { sk: { S: "test-tag#test-build-id/isr/1.json" } },
950
+ { sk: { S: "test-tag#test-build-id/index.json" } },
951
+ ],
952
+ },
953
+ });
954
+ mockS3Send.mockResolvedValue({});
955
+ mockSsmSend.mockResolvedValue({
956
+ Parameter: { Value: "test-distribution-id" },
957
+ });
958
+ mockCloudFrontSend.mockResolvedValue({});
959
+ await handlerWithBasePath.revalidateTag("test-tag");
960
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
961
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual(expect.arrayContaining([
962
+ "/base/isr/1*",
963
+ // The app's root under a `basePath` is `/base`, not `/base/`, and
964
+ // spelled out: `/base*` would be the whole app.
965
+ "/base",
966
+ "/base?*",
967
+ "/base/",
968
+ "/base/?*",
969
+ ]));
970
+ expect(invalidationInput.InvalidationBatch.Paths.Items).not.toContain("/isr/1");
971
+ });
972
+ it("adds the basePath to a revalidatePath tag's path too", async () => {
973
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
974
+ useBasePath();
975
+ const handlerWithBasePath = new s3_cache_handler_1.S3CacheHandler({
976
+ context: mockContext,
977
+ });
978
+ dynamoResponses({ query: { Items: [] } });
979
+ mockSsmSend.mockResolvedValue({
980
+ Parameter: { Value: "test-distribution-id" },
981
+ });
982
+ mockCloudFrontSend.mockResolvedValue({});
983
+ await handlerWithBasePath.revalidateTag("_N_T_/blog");
984
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
985
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual([
986
+ "/base/blog*",
987
+ ]);
988
+ });
989
+ it("does not invalidate a CloudFront path for an app tag", async () => {
990
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
991
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
992
+ context: mockContext,
993
+ });
994
+ dynamoResponses({ query: { Items: [] } });
995
+ await handlerWithDistribution.revalidateTag("posts");
996
+ // Nothing to invalidate: an app tag names no path, and no entry is mapped
997
+ // to it.
998
+ expect(mockCloudFrontSend).not.toHaveBeenCalled();
228
999
  });
229
1000
  it("should not call SSM or CloudFront when no distribution parameter is configured", async () => {
230
1001
  const mockQueryResponse = {
231
1002
  Items: [{ sk: { S: "test-tag#test-build-id/isr/1.json" } }],
232
1003
  };
233
- mockDynamoSend.mockResolvedValueOnce(mockQueryResponse);
234
- mockDynamoSend.mockResolvedValue({});
1004
+ dynamoResponses({ query: mockQueryResponse });
235
1005
  mockS3Send.mockResolvedValue({});
236
1006
  await handler.revalidateTag("test-tag");
237
1007
  expect(mockSsmSend).not.toHaveBeenCalled();
@@ -245,35 +1015,420 @@ describe("S3DynamoCacheHandler", () => {
245
1015
  const mockQueryResponse = {
246
1016
  Items: [{ sk: { S: "test-tag#test-build-id/isr/1.json" } }],
247
1017
  };
248
- mockDynamoSend.mockResolvedValueOnce(mockQueryResponse);
249
- mockDynamoSend.mockResolvedValue({});
1018
+ dynamoResponses({ query: mockQueryResponse });
250
1019
  mockS3Send.mockResolvedValue({});
251
1020
  mockSsmSend.mockRejectedValueOnce(new Error("SSM Error"));
252
1021
  await expect(handlerWithDistribution.revalidateTag("test-tag")).resolves.not.toThrow();
253
1022
  });
254
- });
255
- describe("resetRequestCache", () => {
256
- it("should complete without errors", async () => {
257
- await expect(handler.resetRequestCache()).resolves.not.toThrow();
1023
+ it("invalidates the page itself for a revalidatePath(path, 'page') tag", async () => {
1024
+ // `revalidatePath(path, type)` appends the type to the implicit tag, so the
1025
+ // tag reads `_N_T_/pricing/page` - a path no URL has. Taking it literally
1026
+ // invalidated nothing that existed, which is the whole of the bug: the
1027
+ // second argument silently turned CDN invalidation off.
1028
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1029
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
1030
+ context: mockContext,
1031
+ });
1032
+ dynamoResponses({ query: { Items: [] } });
1033
+ mockSsmSend.mockResolvedValue({
1034
+ Parameter: { Value: "test-distribution-id" },
1035
+ });
1036
+ mockCloudFrontSend.mockResolvedValue({});
1037
+ await handlerWithDistribution.revalidateTag("_N_T_/pricing/page");
1038
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
1039
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual(expect.arrayContaining(["/pricing*"]));
258
1040
  });
259
- });
260
- describe("custom configuration", () => {
261
- it("should accept custom configuration options", () => {
262
- const customHandler = new s3_cache_handler_1.S3CacheHandler({
1041
+ it("skips mapping rows that name no cached URI", async () => {
1042
+ // A dynamic template and a fetch-cache entry are both rows a real tag
1043
+ // carries, and neither is a URL: `/blog/[slug]` matches nothing at the edge
1044
+ // (CloudFront has no such URI), and a fetch key is a hash of the request.
1045
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1046
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
263
1047
  context: mockContext,
264
- s3Config: {
265
- bucketName: "custom-bucket",
266
- region: "eu-west-1",
267
- buildId: "custom-build",
1048
+ });
1049
+ dynamoResponses({
1050
+ query: {
1051
+ Items: [
1052
+ { sk: { S: "test-tag#test-build-id/blog/[slug].json" } },
1053
+ {
1054
+ sk: {
1055
+ S: "test-tag#test-build-id/0123456789abcdef0123456789abcdef.json",
1056
+ },
1057
+ },
1058
+ { sk: { S: "test-tag#test-build-id/blog/hello.json" } },
1059
+ ],
268
1060
  },
269
- dynamoConfig: {
270
- tableName: "custom-table",
271
- region: "eu-west-1",
272
- buildId: "custom-build",
1061
+ });
1062
+ mockS3Send.mockResolvedValue({});
1063
+ mockSsmSend.mockResolvedValue({
1064
+ Parameter: { Value: "test-distribution-id" },
1065
+ });
1066
+ mockCloudFrontSend.mockResolvedValue({});
1067
+ await handlerWithDistribution.revalidateTag("test-tag");
1068
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
1069
+ const items = invalidationInput.InvalidationBatch.Paths.Items;
1070
+ expect(items).toEqual(["/blog/hello*"]);
1071
+ expect(items.some((path) => path.includes("["))).toBe(false);
1072
+ expect(items.some((path) => path.includes("0123456789abcdef"))).toBe(false);
1073
+ });
1074
+ it("walks every Query page of a tag's mapping rows", async () => {
1075
+ // One `Query` answers with at most 1 MB. A tag on a large app runs past
1076
+ // that, and taking only the first page deleted some of the tag's entries
1077
+ // and invalidated only some of its paths - a partial revalidation that
1078
+ // looks like a cache bug.
1079
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1080
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
1081
+ context: mockContext,
1082
+ });
1083
+ let queries = 0;
1084
+ mockDynamoSend.mockImplementation((command) => {
1085
+ if (command instanceof client_dynamodb_1.QueryCommand) {
1086
+ queries++;
1087
+ return Promise.resolve(queries === 1
1088
+ ? {
1089
+ Items: [{ sk: { S: "test-tag#test-build-id/isr/1.json" } }],
1090
+ LastEvaluatedKey: { pk: { S: "test-build-id" } },
1091
+ }
1092
+ : { Items: [{ sk: { S: "test-tag#test-build-id/isr/2.json" } }] });
1093
+ }
1094
+ return Promise.resolve({});
1095
+ });
1096
+ mockS3Send.mockResolvedValue({});
1097
+ mockSsmSend.mockResolvedValue({
1098
+ Parameter: { Value: "test-distribution-id" },
1099
+ });
1100
+ mockCloudFrontSend.mockResolvedValue({});
1101
+ await handlerWithDistribution.revalidateTag("test-tag");
1102
+ expect(queries).toBe(2);
1103
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
1104
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual([
1105
+ "/isr/1*",
1106
+ "/isr/2*",
1107
+ ]);
1108
+ });
1109
+ it("collapses to one app-wide wildcard rather than sending many invalidations", async () => {
1110
+ // CloudFront caps a request at 15 wildcard paths and allows 15
1111
+ // invalidations in progress. A tag covering hundreds of pages therefore
1112
+ // cannot be spelled out: sending a request per 15 paths throttles, and a
1113
+ // throttled request is a page that stays stale.
1114
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1115
+ const handlerWithDistribution = new s3_cache_handler_1.S3CacheHandler({
1116
+ context: mockContext,
1117
+ });
1118
+ dynamoResponses({
1119
+ query: {
1120
+ Items: Array.from({ length: 200 }, (_, i) => ({
1121
+ sk: { S: `test-tag#test-build-id/isr/${i}.json` },
1122
+ })),
273
1123
  },
274
1124
  });
275
- expect(customHandler).toBeDefined();
1125
+ mockS3Send.mockResolvedValue({});
1126
+ mockSsmSend.mockResolvedValue({
1127
+ Parameter: { Value: "test-distribution-id" },
1128
+ });
1129
+ mockCloudFrontSend.mockResolvedValue({});
1130
+ await handlerWithDistribution.revalidateTag("test-tag");
1131
+ expect(mockCloudFrontSend).toHaveBeenCalledTimes(1);
1132
+ const [invalidationInput] = client_cloudfront_1.CreateInvalidationCommand.mock.calls[0];
1133
+ expect(invalidationInput.InvalidationBatch.Paths.Items).toEqual(["/*"]);
1134
+ });
1135
+ /** A handler with a distribution, and DynamoDB answering `query` for it. */
1136
+ const withDistribution = (query) => {
1137
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1138
+ dynamoResponses({ query });
1139
+ mockSsmSend.mockResolvedValue({
1140
+ Parameter: { Value: "test-distribution-id" },
1141
+ });
1142
+ mockCloudFrontSend.mockResolvedValue({});
1143
+ return new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
1144
+ };
1145
+ const invalidations = () => client_cloudfront_1.CreateInvalidationCommand.mock.calls.map(([input]) => input.InvalidationBatch.Paths.Items);
1146
+ const pages = (tag, count) => ({
1147
+ Items: Array.from({ length: count }, (_, i) => ({
1148
+ sk: { S: `${tag}#test-build-id/isr/${i}.json` },
1149
+ })),
1150
+ });
1151
+ it("sends a tag's paths as one request while they fit", async () => {
1152
+ // CloudFront's wildcard quota is shared by every invalidation in
1153
+ // progress on the distribution. Splitting ten pages' twenty wildcards
1154
+ // into two back-to-back requests had the second rejected, and its pages
1155
+ // stayed stale at the edge.
1156
+ await withDistribution(pages("test-tag", 10)).revalidateTag("test-tag");
1157
+ expect(invalidations()).toHaveLength(1);
1158
+ expect(invalidations()[0]).toHaveLength(10);
1159
+ });
1160
+ it("collapses to the whole app past fifteen wildcards", async () => {
1161
+ await withDistribution(pages("test-tag", 16)).revalidateTag("test-tag");
1162
+ expect(invalidations()).toEqual([["/*"]]);
1163
+ });
1164
+ it("collapses to the whole app under a basePath, its root included", async () => {
1165
+ // Not `/base*`, which would also invalidate a sibling app at `/base2`.
1166
+ useBasePath();
1167
+ await withDistribution(pages("test-tag", 16)).revalidateTag("test-tag");
1168
+ expect(invalidations()).toEqual([["/base", "/base?*", "/base/*"]]);
1169
+ });
1170
+ it("invalidates the whole app under a basePath when a tag's rows cannot be read", async () => {
1171
+ useBasePath();
1172
+ jest.spyOn(console, "error").mockImplementation();
1173
+ const cdnHandler = withDistribution({ Items: [] });
1174
+ mockDynamoSend.mockImplementation((command) => command instanceof client_dynamodb_1.QueryCommand
1175
+ ? Promise.reject(new Error("ProvisionedThroughputExceeded"))
1176
+ : Promise.resolve({}));
1177
+ await cdnHandler.revalidateTag("posts");
1178
+ expect(invalidations()).toEqual([["/base", "/base?*", "/base/*"]]);
1179
+ });
1180
+ it("percent-encodes the routes it invalidates", async () => {
1181
+ // Cache keys are decoded pathnames, while CloudFront caches - and
1182
+ // invalidation paths match - the encoded URI the browser sent.
1183
+ await withDistribution({
1184
+ Items: [
1185
+ { sk: { S: "test-tag#test-build-id/blog/héllo.json" } },
1186
+ { sk: { S: "test-tag#test-build-id/blog/hello world.json" } },
1187
+ // Path delimiters Next.js re-escaped in the key stay as they are.
1188
+ { sk: { S: "test-tag#test-build-id/files/a%2Fb.json" } },
1189
+ { sk: { S: "test-tag#test-build-id/@user/50%.json" } },
1190
+ ],
1191
+ }).revalidateTag(["test-tag", "_N_T_/tags/c#?"]);
1192
+ expect(invalidations()).toEqual([
1193
+ [
1194
+ "/blog/h%C3%A9llo*",
1195
+ "/blog/hello%20world*",
1196
+ "/files/a%2Fb*",
1197
+ "/@user/50%25*",
1198
+ "/tags/c%23%3F*",
1199
+ ],
1200
+ ]);
1201
+ });
1202
+ it("invalidates every tag of one call in a single request", async () => {
1203
+ // `revalidateTag` hands the handler every tag a request revalidated at
1204
+ // once; a request per tag competes for the same quota.
1205
+ await withDistribution({ Items: [] }).revalidateTag([
1206
+ "_N_T_/a",
1207
+ "_N_T_/b",
1208
+ ]);
1209
+ expect(invalidations()).toEqual([["/a*", "/b*"]]);
1210
+ });
1211
+ it("invalidates the whole app when a tag has more rows than it walks", async () => {
1212
+ // The rows past the last page walked are pages too; invalidating only the
1213
+ // ones read left the rest stale at the edge for up to a year.
1214
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1215
+ mockDynamoSend.mockImplementation((command) => Promise.resolve(command instanceof client_dynamodb_1.QueryCommand
1216
+ ? {
1217
+ Items: [{ sk: { S: "test-tag#test-build-id/isr/1.json" } }],
1218
+ LastEvaluatedKey: { pk: { S: "test-build-id" } },
1219
+ }
1220
+ : {}));
1221
+ mockSsmSend.mockResolvedValue({
1222
+ Parameter: { Value: "test-distribution-id" },
1223
+ });
1224
+ mockCloudFrontSend.mockResolvedValue({});
1225
+ await new s3_cache_handler_1.S3CacheHandler({ context: mockContext }).revalidateTag("test-tag");
1226
+ expect(invalidations()).toEqual([["/*"]]);
1227
+ });
1228
+ it("ignores rows that another tag sharing the prefix owns", async () => {
1229
+ // `begins_with(sk, "user#")` also matches the tag `user#42`: its bare
1230
+ // marker row, and its mapping rows. Read as `user`'s, they became
1231
+ // invalidation paths like `/42` that name nothing.
1232
+ await withDistribution({
1233
+ Items: [
1234
+ { sk: { S: "user#42" } },
1235
+ { sk: { S: "user#42#test-build-id/account.json" } },
1236
+ { sk: { S: "user#test-build-id/profile.json" } },
1237
+ ],
1238
+ }).revalidateTag("user");
1239
+ expect(invalidations()).toEqual([["/profile*"]]);
1240
+ });
1241
+ it("adds the build-time prerenders the build's tag manifest names, reading it once", async () => {
1242
+ // A prerender is written by the adapter, never through `set`, so it has
1243
+ // no mapping row: the manifest is the only record of its tags.
1244
+ const cdnHandler = withDistribution({
1245
+ Items: [{ sk: { S: "posts#test-build-id/blog/b.json" } }],
1246
+ });
1247
+ const manifestGets = () => client_s3_1.GetObjectCommand.mock.calls.filter(([input]) => input.Key === "test-build-id/_cdk-nextjs-tag-manifest.json");
1248
+ mockS3Send.mockImplementation((command) => Promise.resolve(command instanceof client_s3_1.GetObjectCommand
1249
+ ? {
1250
+ Body: {
1251
+ transformToString: async () => JSON.stringify({ posts: ["blog/a", "index"] }),
1252
+ },
1253
+ }
1254
+ : {}));
1255
+ await cdnHandler.revalidateTag("posts");
1256
+ await cdnHandler.revalidateTag("constructor");
1257
+ expect(invalidations()).toEqual([["/blog/b*", "/blog/a*", "/", "/?*"]]);
1258
+ expect(manifestGets()).toHaveLength(1);
1259
+ });
1260
+ it("invalidates the whole app when the build's tag manifest cannot be read, and reads it again next time", async () => {
1261
+ const cdnHandler = withDistribution({ Items: [] });
1262
+ mockS3Send.mockRejectedValueOnce(new Error("AccessDenied"));
1263
+ await cdnHandler.revalidateTag("posts");
1264
+ await cdnHandler.revalidateTag("posts");
1265
+ expect(invalidations()).toEqual([["/*"]]);
1266
+ expect(mockS3Send).toHaveBeenCalledTimes(2);
1267
+ });
1268
+ it("invalidates the whole app when a tag's marker row cannot be written", async () => {
1269
+ // Other instances would never see the revalidation, so no path list is
1270
+ // enough.
1271
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1272
+ jest.spyOn(console, "error").mockImplementation();
1273
+ mockDynamoSend.mockImplementation((command) => command instanceof client_dynamodb_1.QueryCommand
1274
+ ? Promise.resolve({ Items: [] })
1275
+ : Promise.reject(new Error("ProvisionedThroughputExceeded")));
1276
+ mockSsmSend.mockResolvedValue({
1277
+ Parameter: { Value: "test-distribution-id" },
1278
+ });
1279
+ mockCloudFrontSend.mockResolvedValue({});
1280
+ await new s3_cache_handler_1.S3CacheHandler({ context: mockContext }).revalidateTag("posts");
1281
+ expect(invalidations()).toEqual([["/*"]]);
1282
+ });
1283
+ it("invalidates the whole app when a tag's mapping rows cannot be read", async () => {
1284
+ // The marker row is written before the Query, so a failed Query leaves
1285
+ // the tag revalidated at the origin with no paths named for the edge.
1286
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "test-param-name";
1287
+ jest.spyOn(console, "error").mockImplementation();
1288
+ mockDynamoSend.mockImplementation((command) => command instanceof client_dynamodb_1.QueryCommand
1289
+ ? Promise.reject(new Error("ProvisionedThroughputExceeded"))
1290
+ : Promise.resolve({}));
1291
+ mockSsmSend.mockResolvedValue({
1292
+ Parameter: { Value: "test-distribution-id" },
1293
+ });
1294
+ mockCloudFrontSend.mockResolvedValue({});
1295
+ await new s3_cache_handler_1.S3CacheHandler({ context: mockContext }).revalidateTag([
1296
+ "_N_T_/a",
1297
+ "posts",
1298
+ ]);
1299
+ expect(invalidations()).toEqual([["/*"]]);
1300
+ });
1301
+ describe("when CloudFront's invalidation quota is full", () => {
1302
+ beforeEach(() => {
1303
+ jest.useFakeTimers();
1304
+ });
1305
+ afterEach(() => {
1306
+ jest.useRealTimers();
1307
+ });
1308
+ const quotaError = () => Object.assign(new Error("Your request contains too many invalidations"), {
1309
+ name: "TooManyInvalidationsInProgress",
1310
+ });
1311
+ it("retries as one app-wide wildcard after a backoff", async () => {
1312
+ const cdnHandler = withDistribution(pages("test-tag", 2));
1313
+ mockCloudFrontSend
1314
+ .mockRejectedValueOnce(quotaError())
1315
+ .mockResolvedValueOnce({});
1316
+ const done = cdnHandler.revalidateTag("test-tag");
1317
+ await jest.advanceTimersByTimeAsync(1000);
1318
+ await done;
1319
+ expect(invalidations()).toEqual([["/isr/0*", "/isr/1*"], ["/*"]]);
1320
+ });
1321
+ it("gives up after the last retry", async () => {
1322
+ const cdnHandler = withDistribution(pages("test-tag", 1));
1323
+ mockCloudFrontSend.mockRejectedValue(quotaError());
1324
+ const done = cdnHandler.revalidateTag("test-tag");
1325
+ await jest.advanceTimersByTimeAsync(3000);
1326
+ await expect(done).resolves.toBeUndefined();
1327
+ expect(invalidations()).toEqual([["/isr/0*"], ["/*"], ["/*"]]);
1328
+ });
1329
+ it("does not retry any other error", async () => {
1330
+ const cdnHandler = withDistribution(pages("test-tag", 1));
1331
+ mockCloudFrontSend.mockRejectedValue(new Error("AccessDenied"));
1332
+ await cdnHandler.revalidateTag("test-tag");
1333
+ expect(invalidations()).toEqual([["/isr/0*"]]);
1334
+ });
1335
+ it("retries the app's root under a basePath too", async () => {
1336
+ // `/base/*` matches neither `/base` nor `/base?_rsc=…`: retrying
1337
+ // `revalidatePath("/")` as that left the home page stale at the edge.
1338
+ useBasePath();
1339
+ const cdnHandler = withDistribution({ Items: [] });
1340
+ mockCloudFrontSend
1341
+ .mockRejectedValueOnce(quotaError())
1342
+ .mockResolvedValueOnce({});
1343
+ const done = cdnHandler.revalidateTag("_N_T_/");
1344
+ await jest.advanceTimersByTimeAsync(1000);
1345
+ await done;
1346
+ expect(invalidations()[1]).toEqual(["/base", "/base?*", "/base/*"]);
1347
+ });
1348
+ });
1349
+ it("records a profile's revalidation as stale now, expiring later", async () => {
1350
+ const before = Date.now();
1351
+ await handler.revalidateTag("posts", { expire: 60 });
1352
+ const [input] = client_dynamodb_1.UpdateItemCommand.mock.calls[0];
1353
+ expect(input.Key.sk.S).toBe("posts");
1354
+ expect(input.UpdateExpression).toBe("SET staleAt = :staleAt, expiredAt = :expiredAt");
1355
+ const staleAt = Number(input.ExpressionAttributeValues[":staleAt"].N);
1356
+ expect(staleAt).toBeGreaterThanOrEqual(before);
1357
+ expect(Number(input.ExpressionAttributeValues[":expiredAt"].N)).toBe(staleAt + 60_000);
1358
+ });
1359
+ });
1360
+ /**
1361
+ * The cache handler's half of `res.revalidate()`'s CDN invalidation: the hook
1362
+ * it registers for `invalidateRevalidatedPage` in `runtime/core.ts`. The
1363
+ * runtime's half is in `core.test.ts`.
1364
+ */
1365
+ describe("the revalidated-page hook", () => {
1366
+ const HOOK = manifest_1.REVALIDATED_PAGE_HOOK;
1367
+ const globals = globalThis;
1368
+ beforeEach(() => {
1369
+ delete globals[HOOK];
1370
+ mockSsmSend.mockResolvedValue({ Parameter: { Value: "EDISTRIBUTION" } });
1371
+ mockCloudFrontSend.mockResolvedValue({});
1372
+ client_cloudfront_1.CreateInvalidationCommand.mockClear();
1373
+ });
1374
+ function invalidatedPaths() {
1375
+ const [input] = client_cloudfront_1.CreateInvalidationCommand.mock
1376
+ .calls[0];
1377
+ return input.InvalidationBatch.Paths.Items;
1378
+ }
1379
+ it("is registered only behind a distribution", () => {
1380
+ new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
1381
+ expect(globals[HOOK]).toBeUndefined();
1382
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "param";
1383
+ new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
1384
+ expect(typeof globals[HOOK]).toBe("function");
1385
+ });
1386
+ it("invalidates the page and its data route under basePath", async () => {
1387
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "param";
1388
+ new s3_cache_handler_1.S3CacheHandler({ context: mockContext, basePath: "base" });
1389
+ await globals[HOOK]([
1390
+ "/blog/hello",
1391
+ "/_next/data/test-build-id/blog/hello.json",
1392
+ ]);
1393
+ expect(invalidatedPaths()).toEqual([
1394
+ "/base/blog/hello*",
1395
+ "/base/_next/data/test-build-id/blog/hello.json*",
1396
+ ]);
1397
+ });
1398
+ it("spells out the root rather than invalidating the whole app", async () => {
1399
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "param";
1400
+ new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
1401
+ await globals[HOOK]([
1402
+ "/",
1403
+ "/_next/data/test-build-id/index.json",
1404
+ ]);
1405
+ expect(invalidatedPaths()).toEqual([
1406
+ "/",
1407
+ "/?*",
1408
+ "/_next/data/test-build-id/index.json*",
1409
+ ]);
1410
+ });
1411
+ it("sends every path once, in one invalidation", async () => {
1412
+ process.env.CDK_NEXTJS_DISTRIBUTION_ID_PARAM_NAME = "param";
1413
+ new s3_cache_handler_1.S3CacheHandler({ context: mockContext });
1414
+ await globals[HOOK]([
1415
+ "/blog",
1416
+ "/_next/data/test-build-id/en/blog.json",
1417
+ "/en/blog",
1418
+ "/blog",
1419
+ ]);
1420
+ expect(client_cloudfront_1.CreateInvalidationCommand).toHaveBeenCalledTimes(1);
1421
+ expect(invalidatedPaths()).toEqual([
1422
+ "/blog*",
1423
+ "/_next/data/test-build-id/en/blog.json*",
1424
+ "/en/blog*",
1425
+ ]);
1426
+ });
1427
+ });
1428
+ describe("resetRequestCache", () => {
1429
+ it("should complete without errors", async () => {
1430
+ await expect(handler.resetRequestCache()).resolves.not.toThrow();
276
1431
  });
277
1432
  });
278
1433
  });
279
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiczMtY2FjaGUtaGFuZGxlci50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXIvczMtY2FjaGUtaGFuZGxlci50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsc0RBQXNEO0FBQ3RELGVBQWU7QUFDZixJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7QUFDaEMsSUFBSSxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBQ3RDLElBQUksQ0FBQyxJQUFJLENBQUMsNEJBQTRCLENBQUMsQ0FBQztBQUN4QyxJQUFJLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUM7QUFFakMsa0VBR29DO0FBQ3BDLDhEQUlrQztBQUNsQyxrREFLNEI7QUFDNUIsb0RBQWdEO0FBT2hELHlEQUFvRDtBQUVwRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7QUFDN0IsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO0FBQ2pDLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO0FBQ3JDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUU3QixvQkFBc0IsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ2hELElBQUksRUFBRSxVQUFVO0NBQ2pCLENBQUMsQ0FBQyxDQUFDO0FBRUgsZ0NBQTRCLENBQUMsa0JBQWtCLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUN0RCxJQUFJLEVBQUUsY0FBYztDQUNyQixDQUFDLENBQUMsQ0FBQztBQUVILG9DQUE4QixDQUFDLGtCQUFrQixDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDeEQsSUFBSSxFQUFFLGtCQUFrQjtDQUN6QixDQUFDLENBQUMsQ0FBQztBQUVILHNCQUF1QixDQUFDLGtCQUFrQixDQUFDLEdBQUcs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QUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbkUsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyxzQkFBc0IsRUFBRSxHQUFHLEVBQUU7UUFDcEMsRUFBRSxDQUFDLDRDQUE0QyxFQUFFLEdBQUcsRUFBRTtZQUNwRCxNQUFNLGFBQWEsR0FBRyxJQUFJLGlDQUFjLENBQUM7Z0JBQ3ZDLE9BQU8sRUFBRSxXQUFXO2dCQUNwQixRQUFRLEVBQUU7b0JBQ1IsVUFBVSxFQUFFLGVBQWU7b0JBQzNCLE1BQU0sRUFBRSxXQUFXO29CQUNuQixPQUFPLEVBQUUsY0FBYztpQkFDeEI7Z0JBQ0QsWUFBWSxFQUFFO29CQUNaLFNBQVMsRUFBRSxjQUFjO29CQUN6QixNQUFNLEVBQUUsV0FBVztvQkFDbkIsT0FBTyxFQUFFLGNBQWM7aUJBQ3hCO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3RDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuLy8gTW9jayBBV1MgU0RLXG5qZXN0Lm1vY2soXCJAYXdzLXNkay9jbGllbnQtczNcIik7XG5qZXN0Lm1vY2soXCJAYXdzLXNkay9jbGllbnQtZHluYW1vZGJcIik7XG5qZXN0Lm1vY2soXCJAYXdzLXNkay9jbGllbnQtY2xvdWRmcm9udFwiKTtcbmplc3QubW9jayhcIkBhd3Mtc2RrL2NsaWVudC1zc21cIik7XG5cbmltcG9ydCB7XG4gIENsb3VkRnJvbnRDbGllbnQsXG4gIENyZWF0ZUludmFsaWRhdGlvbkNvbW1hbmQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtY2xvdWRmcm9udFwiO1xuaW1wb3J0IHtcbiAgRHluYW1vREJDbGllbnQsXG4gIFF1ZXJ5Q29tbWFuZCxcbiAgVXBkYXRlSXRlbUNvbW1hbmQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtZHluYW1vZGJcIjtcbmltcG9ydCB7XG4gIFMzQ2xpZW50LFxuICBHZXRPYmplY3RDb21tYW5kLFxuICBQdXRPYmplY3RDb21tYW5kLFxuICBEZWxldGVPYmplY3RDb21tYW5kLFxufSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXMzXCI7XG5pbXBvcnQgeyBTU01DbGllbnQgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXNzbVwiO1xuaW1wb3J0IHsgQ2FjaGVIYW5kbGVyQ29udGV4dCB9IGZyb20gXCJuZXh0L2Rpc3Qvc2VydmVyL2xpYi9pbmNyZW1lbnRhbC1jYWNoZVwiO1xuaW1wb3J0IHtcbiAgSW5jcmVtZW50YWxDYWNoZVZhbHVlLFxuICBDYWNoZWRSb3V0ZUtpbmQsXG4gIEluY3JlbWVudGFsQ2FjaGVLaW5kLFxufSBmcm9tIFwibmV4dC9kaXN0L3NlcnZlci9yZXNwb25zZS1jYWNoZVwiO1xuaW1wb3J0IHsgUzNDYWNoZUhhbmRsZXIgfSBmcm9tIFwiLi9zMy1jYWNoZS1oYW5kbGVyXCI7XG5cbmNvbnN0IG1vY2tTM1NlbmQgPSBqZXN0LmZuKCk7XG5jb25zdCBtb2NrRHluYW1vU2VuZCA9IGplc3QuZm4oKTtcbmNvbnN0IG1vY2tDbG91ZEZyb250U2VuZCA9IGplc3QuZm4oKTtcbmNvbnN0IG1vY2tTc21TZW5kID0gamVzdC5mbigpO1xuXG4oUzNDbGllbnQgYXMgamVzdC5Nb2NrKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4gKHtcbiAgc2VuZDogbW9ja1MzU2VuZCxcbn0pKTtcblxuKER5bmFtb0RCQ2xpZW50IGFzIGplc3QuTW9jaykubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+ICh7XG4gIHNlbmQ6IG1vY2tEeW5hbW9TZW5kLFxufSkpO1xuXG4oQ2xvdWRGcm9udENsaWVudCBhcyBqZXN0Lk1vY2spLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiAoe1xuICBzZW5kOiBtb2NrQ2xvdWRGcm9udFNlbmQsXG59KSk7XG5cbihTU01DbGllbnQgYXMgamVzdC5Nb2NrKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4gKHtcbiAgc2VuZDogbW9ja1NzbVNlbmQsXG59KSk7XG5cbmRlc2NyaWJlKFwiUzNEeW5hbW9DYWNoZUhhbmRsZXJcIiwgKCkgPT4ge1xuICBsZXQgaGFuZGxlcjogUzNDYWNoZUhhbmRsZXI7XG4gIGxldCBtb2NrQ29udGV4dDogQ2FjaGVIYW5kbGVyQ29udGV4dDtcblxuICAvLyBIZWxwZXIgdG8gY3JlYXRlIHNldCBjb250ZXh0IHdpdGggdGFnc1xuICBjb25zdCBjcmVhdGVTZXRDb250ZXh0ID0gKHRhZ3M6IHN0cmluZ1tdKSA9PiAoe1xuICAgIGZldGNoQ2FjaGU6IHRydWUgYXMgY29uc3QsXG4gICAgdGFncyxcbiAgfSk7XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgbW9ja0NvbnRleHQgPSB7IGRldjogZmFsc2UgfSBhcyBDYWNoZUhhbmRsZXJDb250ZXh0O1xuXG4gICAgLy8gU2V0IHVwIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQ0FDSEVfQlVDS0VUX05BTUUgPSBcInRlc3QtYnVja2V0XCI7XG4gICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19SRVZBTElEQVRJT05fVEFCTEVfTkFNRSA9IFwidGVzdC10YWJsZVwiO1xuICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQlVJTERfSUQgPSBcInRlc3QtYnVpbGQtaWRcIjtcbiAgICBwcm9jZXNzLmVudi5BV1NfUkVHSU9OID0gXCJ1cy1lYXN0LTFcIjtcblxuICAgIC8vIFN1cHByZXNzIGV4cGVjdGVkIHdhcm5pbmdzIGdsb2JhbGx5ICh0ZXN0cyBkZWxpYmVyYXRlbHkgdHJpZ2dlciB3YXJuaW5ncylcbiAgICBqZXN0LnNweU9uKGNvbnNvbGUsIFwid2FyblwiKS5tb2NrSW1wbGVtZW50YXRpb24oKTtcblxuICAgIGhhbmRsZXIgPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgfSk7XG5cbiAgICAvLyBSZXNldCBtb2Nrc1xuICAgIG1vY2tTM1NlbmQubW9ja1Jlc2V0KCk7XG4gICAgbW9ja0R5bmFtb1NlbmQubW9ja1Jlc2V0KCk7XG4gICAgbW9ja0Nsb3VkRnJvbnRTZW5kLm1vY2tSZXNldCgpO1xuICAgIG1vY2tTc21TZW5kLm1vY2tSZXNldCgpO1xuICB9KTtcblxuICBhZnRlckVhY2goKCkgPT4ge1xuICAgIC8vIENsZWFuIHVwIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0NBQ0hFX0JVQ0tFVF9OQU1FO1xuICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5DREtfTkVYVEpTX1JFVkFMSURBVElPTl9UQUJMRV9OQU1FO1xuICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0JVSUxEX0lEO1xuICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5BV1NfUkVHSU9OO1xuICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0RJU1RSSUJVVElPTl9JRF9QQVJBTV9OQU1FO1xuXG4gICAgLy8gUmVzdG9yZSBjb25zb2xlLndhcm5cbiAgICBqZXN0LnJlc3RvcmVBbGxNb2NrcygpO1xuICB9KTtcblxuICBkZXNjcmliZShcImdldFwiLCAoKSA9PiB7XG4gICAgaXQoXCJzaG91bGQgcmV0dXJuIG51bGwgd2hlbiBTMyBidWNrZXQgaXMgbm90IGNvbmZpZ3VyZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQ0FDSEVfQlVDS0VUX05BTUU7XG5cbiAgICAgIGNvbnN0IGhhbmRsZXJXaXRob3V0QnVja2V0ID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgaGFuZGxlcldpdGhvdXRCdWNrZXQuZ2V0KFwidGVzdC1rZXlcIiwge1xuICAgICAgICBraW5kOiBJbmNyZW1lbnRhbENhY2hlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaXNGYWxsYmFjazogZmFsc2UsXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVOdWxsKCk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCByZXRyaWV2ZSBhbmQgcGFyc2UgY2FjaGUgdmFsdWUgZnJvbSBTM1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0RGF0YTogSW5jcmVtZW50YWxDYWNoZVZhbHVlID0ge1xuICAgICAgICBraW5kOiBDYWNoZWRSb3V0ZUtpbmQuQVBQX1BBR0UsXG4gICAgICAgIGh0bWw6IFwiPGh0bWw+dGVzdDwvaHRtbD5cIixcbiAgICAgICAgcnNjRGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBoZWFkZXJzOiB1bmRlZmluZWQsXG4gICAgICAgIHBvc3Rwb25lZDogdW5kZWZpbmVkLFxuICAgICAgICBzZWdtZW50RGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBzdGF0dXM6IHVuZGVmaW5lZCxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGNhY2hlVmFsdWUgPSB7XG4gICAgICAgIGxhc3RNb2RpZmllZDogRGF0ZS5ub3coKSxcbiAgICAgICAgdmFsdWU6IHRlc3REYXRhLFxuICAgICAgfTtcblxuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgICBCb2R5OiB7XG4gICAgICAgICAgdHJhbnNmb3JtVG9TdHJpbmc6IGplc3RcbiAgICAgICAgICAgIC5mbigpXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUoSlNPTi5zdHJpbmdpZnkoY2FjaGVWYWx1ZSkpLFxuICAgICAgICB9LFxuICAgICAgICBDb250ZW50VHlwZTogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgaGFuZGxlci5nZXQoXCJ0ZXN0LWtleVwiLCB7XG4gICAgICAgIGtpbmQ6IEluY3JlbWVudGFsQ2FjaGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKGNhY2hlVmFsdWUpO1xuICAgICAgZXhwZWN0KG1vY2tTM1NlbmQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5hbnkoR2V0T2JqZWN0Q29tbWFuZCkpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgcmV0dXJuIG51bGwgd2hlbiBTMyBvYmplY3Qgbm90IGZvdW5kXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgICAgQm9keTogbnVsbCxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyLmdldChcIm1pc3Npbmcta2V5XCIsIHtcbiAgICAgICAga2luZDogSW5jcmVtZW50YWxDYWNoZUtpbmQuQVBQX1BBR0UsXG4gICAgICAgIGlzRmFsbGJhY2s6IGZhbHNlLFxuICAgICAgfSk7XG4gICAgICBleHBlY3QocmVzdWx0KS50b0JlTnVsbCgpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgaGFuZGxlIFMzIGVycm9ycyBhbmQgcmV0dXJuIG51bGxcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwiUzMgRXJyb3JcIikpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyLmdldChcImVycm9yLWtleVwiLCB7XG4gICAgICAgIGtpbmQ6IEluY3JlbWVudGFsQ2FjaGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZU51bGwoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoXCJzZXRcIiwgKCkgPT4ge1xuICAgIGl0KFwic2hvdWxkIHN0b3JlIGNhY2hlIHZhbHVlIGluIFMzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRlc3REYXRhOiBJbmNyZW1lbnRhbENhY2hlVmFsdWUgPSB7XG4gICAgICAgIGtpbmQ6IENhY2hlZFJvdXRlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaHRtbDogXCI8aHRtbD5zZXQgdGVzdDwvaHRtbD5cIixcbiAgICAgICAgcnNjRGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBoZWFkZXJzOiB1bmRlZmluZWQsXG4gICAgICAgIHBvc3Rwb25lZDogdW5kZWZpbmVkLFxuICAgICAgICBzZWdtZW50RGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBzdGF0dXM6IHVuZGVmaW5lZCxcbiAgICAgIH07XG5cbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHt9KTtcbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlci5zZXQoXCJzZXQta2V5XCIsIHRlc3REYXRhLCBjcmVhdGVTZXRDb250ZXh0KFtcInRhZzFcIl0pKTtcblxuICAgICAgZXhwZWN0KG1vY2tTM1NlbmQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5hbnkoUHV0T2JqZWN0Q29tbWFuZCkpO1xuICAgICAgZXhwZWN0KG1vY2tEeW5hbW9TZW5kKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgZXhwZWN0LmFueShVcGRhdGVJdGVtQ29tbWFuZCksXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgbm90IHN0b3JlIHdoZW4gUzMgYnVja2V0IGlzIG5vdCBjb25maWd1cmVkXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0NBQ0hFX0JVQ0tFVF9OQU1FO1xuXG4gICAgICBjb25zdCBoYW5kbGVyV2l0aG91dEJ1Y2tldCA9IG5ldyBTM0NhY2hlSGFuZGxlcih7XG4gICAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHRlc3REYXRhOiBJbmNyZW1lbnRhbENhY2hlVmFsdWUgPSB7XG4gICAgICAgIGtpbmQ6IENhY2hlZFJvdXRlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaHRtbDogXCI8aHRtbD5ubyBidWNrZXQ8L2h0bWw+XCIsXG4gICAgICAgIHJzY0RhdGE6IHVuZGVmaW5lZCxcbiAgICAgICAgaGVhZGVyczogdW5kZWZpbmVkLFxuICAgICAgICBwb3N0cG9uZWQ6IHVuZGVmaW5lZCxcbiAgICAgICAgc2VnbWVudERhdGE6IHVuZGVmaW5lZCxcbiAgICAgICAgc3RhdHVzOiB1bmRlZmluZWQsXG4gICAgICB9O1xuXG4gICAgICBhd2FpdCBoYW5kbGVyV2l0aG91dEJ1Y2tldC5zZXQoXG4gICAgICAgIFwibm8tYnVja2V0LWtleVwiLFxuICAgICAgICB0ZXN0RGF0YSxcbiAgICAgICAgY3JlYXRlU2V0Q29udGV4dChbXSksXG4gICAgICApO1xuXG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBTMyBlcnJvcnMgZ3JhY2VmdWxseVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0RGF0YTogSW5jcmVtZW50YWxDYWNoZVZhbHVlID0ge1xuICAgICAgICBraW5kOiBDYWNoZWRSb3V0ZUtpbmQuQVBQX1BBR0UsXG4gICAgICAgIGh0bWw6IFwiPGh0bWw+ZXJyb3IgdGVzdDwvaHRtbD5cIixcbiAgICAgICAgcnNjRGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBoZWFkZXJzOiB1bmRlZmluZWQsXG4gICAgICAgIHBvc3Rwb25lZDogdW5kZWZpbmVkLFxuICAgICAgICBzZWdtZW50RGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBzdGF0dXM6IHVuZGVmaW5lZCxcbiAgICAgIH07XG5cbiAgICAgIG1vY2tTM1NlbmQubW9ja1JlamVjdGVkVmFsdWVPbmNlKG5ldyBFcnJvcihcIlMzIFB1dCBFcnJvclwiKSk7XG5cbiAgICAgIC8vIFNob3VsZCBub3QgdGhyb3dcbiAgICAgIGF3YWl0IGV4cGVjdChcbiAgICAgICAgaGFuZGxlci5zZXQoXCJlcnJvci1rZXlcIiwgdGVzdERhdGEsIGNyZWF0ZVNldENvbnRleHQoW10pKSxcbiAgICAgICkucmVzb2x2ZXMubm90LnRvVGhyb3coKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoXCJyZXZhbGlkYXRlVGFnXCIsICgpID0+IHtcbiAgICBpdChcInNob3VsZCBxdWVyeSBEeW5hbW9EQiBhbmQgZGVsZXRlIFMzIGVudHJpZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1F1ZXJ5UmVzcG9uc2UgPSB7XG4gICAgICAgIEl0ZW1zOiBbXG4gICAgICAgICAgeyBzazogeyBTOiBcInRlc3QtdGFnI2NhY2hlLWtleS0xXCIgfSB9LFxuICAgICAgICAgIHsgc2s6IHsgUzogXCJ0ZXN0LXRhZyNjYWNoZS1rZXktMlwiIH0gfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG5cbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlT25jZShtb2NrUXVlcnlSZXNwb25zZSk7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7IC8vIEZvciB1cGRhdGUgY29tbWFuZHNcbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pOyAvLyBGb3IgZGVsZXRlIGNvbW1hbmRzXG5cbiAgICAgIGF3YWl0IGhhbmRsZXIucmV2YWxpZGF0ZVRhZyhcInRlc3QtdGFnXCIpO1xuXG4gICAgICBleHBlY3QobW9ja0R5bmFtb1NlbmQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5hbnkoUXVlcnlDb21tYW5kKSk7XG4gICAgICBleHBlY3QobW9ja0R5bmFtb1NlbmQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBleHBlY3QuYW55KFVwZGF0ZUl0ZW1Db21tYW5kKSxcbiAgICAgICk7XG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LmFueShEZWxldGVPYmplY3RDb21tYW5kKSk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCBub3QgcmV2YWxpZGF0ZSB3aGVuIER5bmFtb0RCIHRhYmxlIGlzIG5vdCBjb25maWd1cmVkXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5DREtfTkVYVEpTX1JFVkFMSURBVElPTl9UQUJMRV9OQU1FO1xuXG4gICAgICBjb25zdCBoYW5kbGVyV2l0aG91dFRhYmxlID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgICB9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlcldpdGhvdXRUYWJsZS5yZXZhbGlkYXRlVGFnKFwidGVzdC10YWdcIik7XG5cbiAgICAgIGV4cGVjdChtb2NrRHluYW1vU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBEeW5hbW9EQiBlcnJvcnMgZ3JhY2VmdWxseVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwiRHluYW1vREIgRXJyb3JcIikpO1xuXG4gICAgICAvLyBTaG91bGQgbm90IHRocm93XG4gICAgICBhd2FpdCBleHBlY3QoaGFuZGxlci5yZXZhbGlkYXRlVGFnKFwiZXJyb3ItdGFnXCIpKS5yZXNvbHZlcy5ub3QudG9UaHJvdygpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgY3JlYXRlIGEgQ2xvdWRGcm9udCBpbnZhbGlkYXRpb24gZm9yIGFmZmVjdGVkIHBhdGhzIHdoZW4gYSBkaXN0cmlidXRpb24gcGFyYW1ldGVyIGlzIGNvbmZpZ3VyZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwidGVzdC1wYXJhbS1uYW1lXCI7XG4gICAgICBjb25zdCBoYW5kbGVyV2l0aERpc3RyaWJ1dGlvbiA9IG5ldyBTM0NhY2hlSGFuZGxlcih7XG4gICAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IG1vY2tRdWVyeVJlc3BvbnNlID0ge1xuICAgICAgICBJdGVtczogW1xuICAgICAgICAgIHsgc2s6IHsgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkL2lzci8xLmpzb25cIiB9IH0sXG4gICAgICAgICAgeyBzazogeyBTOiBcInRlc3QtdGFnI3Rlc3QtYnVpbGQtaWQvaXNyLzIuanNvblwiIH0gfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG5cbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlT25jZShtb2NrUXVlcnlSZXNwb25zZSk7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7IC8vIEZvciB1cGRhdGUgY29tbWFuZHNcbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pOyAvLyBGb3IgZGVsZXRlIGNvbW1hbmRzXG4gICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIFBhcmFtZXRlcjogeyBWYWx1ZTogXCJ0ZXN0LWRpc3RyaWJ1dGlvbi1pZFwiIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKTtcblxuICAgICAgZXhwZWN0KG1vY2tTc21TZW5kKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3QuYW55KE9iamVjdCkpO1xuICAgICAgZXhwZWN0KG1vY2tDbG91ZEZyb250U2VuZCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICAgIGV4cGVjdC5hbnkoQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCksXG4gICAgICApO1xuICAgICAgY29uc3QgW2ludmFsaWRhdGlvbklucHV0XSA9IChcbiAgICAgICAgQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9ja1xuICAgICAgKS5tb2NrLmNhbGxzWzBdO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbklucHV0LkRpc3RyaWJ1dGlvbklkKS50b0JlKFwidGVzdC1kaXN0cmlidXRpb24taWRcIik7XG4gICAgICBleHBlY3QoaW52YWxpZGF0aW9uSW5wdXQuSW52YWxpZGF0aW9uQmF0Y2guUGF0aHMuSXRlbXMpLnRvRXF1YWwoXG4gICAgICAgIGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW1wiL2lzci8xXCIsIFwiL2lzci8yXCJdKSxcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCBub3QgY2FsbCBTU00gb3IgQ2xvdWRGcm9udCB3aGVuIG5vIGRpc3RyaWJ1dGlvbiBwYXJhbWV0ZXIgaXMgY29uZmlndXJlZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBtb2NrUXVlcnlSZXNwb25zZSA9IHtcbiAgICAgICAgSXRlbXM6IFt7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9pc3IvMS5qc29uXCIgfSB9XSxcbiAgICAgIH07XG5cbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlT25jZShtb2NrUXVlcnlSZXNwb25zZSk7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlci5yZXZhbGlkYXRlVGFnKFwidGVzdC10YWdcIik7XG5cbiAgICAgIGV4cGVjdChtb2NrU3NtU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICAgIGV4cGVjdChtb2NrQ2xvdWRGcm9udFNlbmQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCBoYW5kbGUgU1NNL0Nsb3VkRnJvbnQgaW52YWxpZGF0aW9uIGVycm9ycyBncmFjZWZ1bGx5XCIsIGFzeW5jICgpID0+IHtcbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgY29uc3QgaGFuZGxlcldpdGhEaXN0cmlidXRpb24gPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgICBjb250ZXh0OiBtb2NrQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBtb2NrUXVlcnlSZXNwb25zZSA9IHtcbiAgICAgICAgSXRlbXM6IFt7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9pc3IvMS5qc29uXCIgfSB9XSxcbiAgICAgIH07XG5cbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlT25jZShtb2NrUXVlcnlSZXNwb25zZSk7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcbiAgICAgIG1vY2tTc21TZW5kLm1vY2tSZWplY3RlZFZhbHVlT25jZShuZXcgRXJyb3IoXCJTU00gRXJyb3JcIikpO1xuXG4gICAgICBhd2FpdCBleHBlY3QoXG4gICAgICAgIGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKSxcbiAgICAgICkucmVzb2x2ZXMubm90LnRvVGhyb3coKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoXCJyZXNldFJlcXVlc3RDYWNoZVwiLCAoKSA9PiB7XG4gICAgaXQoXCJzaG91bGQgY29tcGxldGUgd2l0aG91dCBlcnJvcnNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgZXhwZWN0KGhhbmRsZXIucmVzZXRSZXF1ZXN0Q2FjaGUoKSkucmVzb2x2ZXMubm90LnRvVGhyb3coKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoXCJjdXN0b20gY29uZmlndXJhdGlvblwiLCAoKSA9PiB7XG4gICAgaXQoXCJzaG91bGQgYWNjZXB0IGN1c3RvbSBjb25maWd1cmF0aW9uIG9wdGlvbnNcIiwgKCkgPT4ge1xuICAgICAgY29uc3QgY3VzdG9tSGFuZGxlciA9IG5ldyBTM0NhY2hlSGFuZGxlcih7XG4gICAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgICAgICBzM0NvbmZpZzoge1xuICAgICAgICAgIGJ1Y2tldE5hbWU6IFwiY3VzdG9tLWJ1Y2tldFwiLFxuICAgICAgICAgIHJlZ2lvbjogXCJldS13ZXN0LTFcIixcbiAgICAgICAgICBidWlsZElkOiBcImN1c3RvbS1idWlsZFwiLFxuICAgICAgICB9LFxuICAgICAgICBkeW5hbW9Db25maWc6IHtcbiAgICAgICAgICB0YWJsZU5hbWU6IFwiY3VzdG9tLXRhYmxlXCIsXG4gICAgICAgICAgcmVnaW9uOiBcImV1LXdlc3QtMVwiLFxuICAgICAgICAgIGJ1aWxkSWQ6IFwiY3VzdG9tLWJ1aWxkXCIsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KGN1c3RvbUhhbmRsZXIpLnRvQmVEZWZpbmVkKCk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
1434
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiczMtY2FjaGUtaGFuZGxlci50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXIvczMtY2FjaGUtaGFuZGxlci50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsc0RBQXNEO0FBQ3RELHFDQUE2RDtBQUM3RCxxQ0FBaUM7QUFDakMseUNBQWlDO0FBQ2pDLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsZ0VBQWdFO0FBQ2hFLE1BQU0sZUFBZSxHQUE0QixFQUFFLENBQUM7QUFDcEQsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUM5QixHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDO0lBQ3BDLGFBQWEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxDQUFDO0NBQ2xELENBQUMsQ0FBQyxDQUFDO0FBQ0osZUFBZTtBQUNmLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztBQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLDBCQUEwQixDQUFDLENBQUM7QUFDdEMsSUFBSSxDQUFDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0FBQ3hDLElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUVqQyxrRUFHb0M7QUFDcEMsOERBT2tDO0FBQ2xDLGtEQUs0QjtBQUM1QixvREFBZ0Q7QUFPaEQseURBQW9EO0FBQ3BELHlEQUF1RDtBQUN2RCxrREFBNEQ7QUFFNUQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO0FBQzdCLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUNqQyxNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUNyQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsRUFBRSxF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LENBQUMsQ0FBQyxDQUFDO1lBQzNELE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDO2dCQUNqQyxRQUFRO2dCQUNSLHlDQUF5QztnQkFDekMsV0FBVzthQUNaLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxFQUFFO1FBQ2pDLEVBQUUsQ0FBQyxnQ0FBZ0MsRUFBRSxLQUFLLElBQUksRUFBRTtZQUM5QyxNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbkUsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzICovXG5pbXBvcnQgeyBta2R0ZW1wU3luYywgcm1TeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSBcIm5vZGU6ZnNcIjtcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuLy8gV2hhdCBgcmVxdWlyZS5jYWNoZWAgaG9sZHMgaW4gYSBydW5uaW5nIHNlcnZlci4gSmVzdCdzIGBjcmVhdGVSZXF1aXJlYCBoYW5kc1xuLy8gb3V0IGEgY2FjaGUgb2YgaXRzIG93biB0aGF0IG5vdGhpbmcgaXMgZXZlciBsb2FkZWQgaW50bywgc28gdGhlIGhhbmRsZXInc1xuLy8gbG9va3VwIG9mIE5leHQuanMncyB0YWcgbWFuaWZlc3QgcmVhZHMgdGhpcyBzdGFuZC1pbiBpbnN0ZWFkLlxuY29uc3QgbW9ja01vZHVsZUNhY2hlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuamVzdC5tb2NrKFwibm9kZTptb2R1bGVcIiwgKCkgPT4gKHtcbiAgLi4uamVzdC5yZXF1aXJlQWN0dWFsKFwibm9kZTptb2R1bGVcIiksXG4gIGNyZWF0ZVJlcXVpcmU6ICgpID0+ICh7IGNhY2hlOiBtb2NrTW9kdWxlQ2FjaGUgfSksXG59KSk7XG4vLyBNb2NrIEFXUyBTREtcbmplc3QubW9jayhcIkBhd3Mtc2RrL2NsaWVudC1zM1wiKTtcbmplc3QubW9jayhcIkBhd3Mtc2RrL2NsaWVudC1keW5hbW9kYlwiKTtcbmplc3QubW9jayhcIkBhd3Mtc2RrL2NsaWVudC1jbG91ZGZyb250XCIpO1xuamVzdC5tb2NrKFwiQGF3cy1zZGsvY2xpZW50LXNzbVwiKTtcblxuaW1wb3J0IHtcbiAgQ2xvdWRGcm9udENsaWVudCxcbiAgQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1jbG91ZGZyb250XCI7XG5pbXBvcnQge1xuICBCYXRjaEdldEl0ZW1Db21tYW5kLFxuICBEZWxldGVJdGVtQ29tbWFuZCxcbiAgRHluYW1vREJDbGllbnQsXG4gIFB1dEl0ZW1Db21tYW5kLFxuICBRdWVyeUNvbW1hbmQsXG4gIFVwZGF0ZUl0ZW1Db21tYW5kLFxufSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LWR5bmFtb2RiXCI7XG5pbXBvcnQge1xuICBTM0NsaWVudCxcbiAgR2V0T2JqZWN0Q29tbWFuZCxcbiAgUHV0T2JqZWN0Q29tbWFuZCxcbiAgRGVsZXRlT2JqZWN0Q29tbWFuZCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHsgU1NNQ2xpZW50IH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zc21cIjtcbmltcG9ydCB7IENhY2hlSGFuZGxlckNvbnRleHQgfSBmcm9tIFwibmV4dC9kaXN0L3NlcnZlci9saWIvaW5jcmVtZW50YWwtY2FjaGVcIjtcbmltcG9ydCB7XG4gIEluY3JlbWVudGFsQ2FjaGVWYWx1ZSxcbiAgQ2FjaGVkUm91dGVLaW5kLFxuICBJbmNyZW1lbnRhbENhY2hlS2luZCxcbn0gZnJvbSBcIm5leHQvZGlzdC9zZXJ2ZXIvcmVzcG9uc2UtY2FjaGVcIjtcbmltcG9ydCB7IFMzQ2FjaGVIYW5kbGVyIH0gZnJvbSBcIi4vczMtY2FjaGUtaGFuZGxlclwiO1xuaW1wb3J0IHsgc2hhcmVkVGFnTWFuaWZlc3QgfSBmcm9tIFwiLi91c2UtY2FjaGUtY29tbW9uXCI7XG5pbXBvcnQgeyBSRVZBTElEQVRFRF9QQUdFX0hPT0sgfSBmcm9tIFwiLi4vcnVudGltZS9tYW5pZmVzdFwiO1xuXG5jb25zdCBtb2NrUzNTZW5kID0gamVzdC5mbigpO1xuY29uc3QgbW9ja0R5bmFtb1NlbmQgPSBqZXN0LmZuKCk7XG5jb25zdCBtb2NrQ2xvdWRGcm9udFNlbmQgPSBqZXN0LmZuKCk7XG5jb25zdCBtb2NrU3NtU2VuZCA9IGplc3QuZm4oKTtcblxuKFMzQ2xpZW50IGFzIGplc3QuTW9jaykubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+ICh7XG4gIHNlbmQ6IG1vY2tTM1NlbmQsXG59KSk7XG5cbihEeW5hbW9EQkNsaWVudCBhcyBqZXN0Lk1vY2spLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiAoe1xuICBzZW5kOiBtb2NrRHluYW1vU2VuZCxcbn0pKTtcblxuKENsb3VkRnJvbnRDbGllbnQgYXMgamVzdC5Nb2NrKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4gKHtcbiAgc2VuZDogbW9ja0Nsb3VkRnJvbnRTZW5kLFxufSkpO1xuXG4oU1NNQ2xpZW50IGFzIGplc3QuTW9jaykubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+ICh7XG4gIHNlbmQ6IG1vY2tTc21TZW5kLFxufSkpO1xuXG5kZXNjcmliZShcIlMzRHluYW1vQ2FjaGVIYW5kbGVyXCIsICgpID0+IHtcbiAgbGV0IGhhbmRsZXI6IFMzQ2FjaGVIYW5kbGVyO1xuICBsZXQgbW9ja0NvbnRleHQ6IENhY2hlSGFuZGxlckNvbnRleHQ7XG4gIGxldCBkaXN0RGlyOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqIFN0YWdlIGByZXF1aXJlZC1zZXJ2ZXItZmlsZXMuanNvbmAgZm9yIGFuIGFwcCB3aXRoIGBiYXNlUGF0aDogXCIvYmFzZVwiYC4gKi9cbiAgY29uc3QgdXNlQmFzZVBhdGggPSAoKSA9PiB7XG4gICAgZGlzdERpciA9IG1rZHRlbXBTeW5jKGpvaW4odG1wZGlyKCksIFwiczMtY2FjaGUtaGFuZGxlci1cIikpO1xuICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICBqb2luKGRpc3REaXIsIFwicmVxdWlyZWQtc2VydmVyLWZpbGVzLmpzb25cIiksXG4gICAgICBKU09OLnN0cmluZ2lmeSh7IGNvbmZpZzogeyBiYXNlUGF0aDogXCIvYmFzZVwiIH0gfSksXG4gICAgKTtcbiAgICBtb2NrQ29udGV4dC5zZXJ2ZXJEaXN0RGlyID0gam9pbihkaXN0RGlyLCBcInNlcnZlclwiKTtcbiAgfTtcblxuICAvLyBIZWxwZXIgdG8gY3JlYXRlIHNldCBjb250ZXh0IHdpdGggdGFnc1xuICBjb25zdCBjcmVhdGVTZXRDb250ZXh0ID0gKHRhZ3M6IHN0cmluZ1tdKSA9PiAoe1xuICAgIGZldGNoQ2FjaGU6IHRydWUgYXMgY29uc3QsXG4gICAgdGFncyxcbiAgfSk7XG5cbiAgLyoqXG4gICAqIFRoZSBpbnB1dCBhIG1vY2tlZCBjb21tYW5kIHdhcyBjb25zdHJ1Y3RlZCB3aXRoLiBUaGUgU0RLJ3MgY29tbWFuZCBjbGFzc2VzXG4gICAqIGFyZSBhdXRvbW9ja2VkLCBzbyBhbiBpbnN0YW5jZSBjYXJyaWVzIG5vdGhpbmcgb2YgaXRzIG93bi5cbiAgICovXG4gIGNvbnN0IGNvbW1hbmRJbnB1dCA9IChjb21tYW5kOiB1bmtub3duLCB0eXBlOiB1bmtub3duKSA9PiB7XG4gICAgY29uc3QgbW9jayA9IHR5cGUgYXMgamVzdC5Nb2NrO1xuICAgIHJldHVybiBtb2NrLm1vY2suY2FsbHNbbW9jay5tb2NrLmluc3RhbmNlcy5pbmRleE9mKGNvbW1hbmQpXVswXTtcbiAgfTtcblxuICAvKipcbiAgICogQW5zd2VyIER5bmFtb0RCIGJ5IGNvbW1hbmQgdHlwZSByYXRoZXIgdGhhbiBieSBjYWxsIG9yZGVyOiBgcmV2YWxpZGF0ZVRhZ2BcbiAgICogd3JpdGVzIGl0cyB0YWcgbWFya2VyIGJlZm9yZSBxdWVyeWluZyB0aGUgdGFnJ3MgbWFwcGluZyByb3dzLCBhbmQgd2hpY2ggb2ZcbiAgICogdGhvc2UgY29tZXMgZmlyc3QgaXMgYW4gaW1wbGVtZW50YXRpb24gZGV0YWlsLiBgZ2V0YCBpcyB0aGUgbWFya2VyIHJvdyBldmVyeVxuICAgKiByZXF1ZXN0ZWQgdGFnIGhhcywgYXMgYSBgR2V0SXRlbWAgd291bGQgaGF2ZSByZXR1cm5lZCBpdC5cbiAgICovXG4gIGNvbnN0IGR5bmFtb1Jlc3BvbnNlcyA9IChyZXNwb25zZXM6IHtcbiAgICBxdWVyeT86IHVua25vd247XG4gICAgZ2V0PzogeyBJdGVtPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfTtcbiAgfSkgPT4ge1xuICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT4ge1xuICAgICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBRdWVyeUNvbW1hbmQpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyZXNwb25zZXMucXVlcnkgPz8ge30pO1xuICAgICAgfVxuICAgICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBCYXRjaEdldEl0ZW1Db21tYW5kKSB7XG4gICAgICAgIGNvbnN0IHsgUmVxdWVzdEl0ZW1zIH0gPSBjb21tYW5kSW5wdXQoY29tbWFuZCwgQmF0Y2hHZXRJdGVtQ29tbWFuZCk7XG4gICAgICAgIGNvbnN0IFtbdGFibGUsIHsgS2V5cyB9XV0gPSBPYmplY3QuZW50cmllcyhSZXF1ZXN0SXRlbXMpIGFzIFtcbiAgICAgICAgICBzdHJpbmcsXG4gICAgICAgICAgeyBLZXlzOiB7IHNrOiB1bmtub3duIH1bXSB9LFxuICAgICAgICBdW107XG4gICAgICAgIGNvbnN0IGl0ZW0gPSByZXNwb25zZXMuZ2V0Py5JdGVtO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBSZXNwb25zZXM6IHtcbiAgICAgICAgICAgIFt0YWJsZV06IGl0ZW0gPyBLZXlzLm1hcCgoeyBzayB9KSA9PiAoeyAuLi5pdGVtLCBzayB9KSkgOiBbXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe30pO1xuICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBEcm9wIHRoZSBwcm9jZXNzJ3MgdGFnIG1hbmlmZXN0LCBzbyB0aGUgbmV4dCBoYW5kbGVyIHN0YXJ0cyB3aXRoIG9uZSBvZlxuICAgKiBpdHMgb3duLCBhcyBhIG5ldyBpbnN0YW5jZSBkb2VzLlxuICAgKi9cbiAgY29uc3QgcmVzZXRUYWdNYW5pZmVzdCA9ICgpID0+IHtcbiAgICBkZWxldGUgKGdsb2JhbFRoaXMgYXMgUmVjb3JkPHN5bWJvbCwgdW5rbm93bj4pW1xuICAgICAgU3ltYm9sLmZvcihcImNkay1uZXh0anMudXNlLWNhY2hlLnRhZy1tYW5pZmVzdFwiKVxuICAgIF07XG4gIH07XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgbW9ja0NvbnRleHQgPSB7IGRldjogZmFsc2UgfSBhcyBDYWNoZUhhbmRsZXJDb250ZXh0O1xuICAgIHJlc2V0VGFnTWFuaWZlc3QoKTtcblxuICAgIC8vIFNldCB1cCBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0NBQ0hFX0JVQ0tFVF9OQU1FID0gXCJ0ZXN0LWJ1Y2tldFwiO1xuICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfUkVWQUxJREFUSU9OX1RBQkxFX05BTUUgPSBcInRlc3QtdGFibGVcIjtcbiAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0JVSUxEX0lEID0gXCJ0ZXN0LWJ1aWxkLWlkXCI7XG4gICAgcHJvY2Vzcy5lbnYuQVdTX1JFR0lPTiA9IFwidXMtZWFzdC0xXCI7XG5cbiAgICAvLyBTdXBwcmVzcyBleHBlY3RlZCB3YXJuaW5ncyBnbG9iYWxseSAodGVzdHMgZGVsaWJlcmF0ZWx5IHRyaWdnZXIgd2FybmluZ3MpXG4gICAgamVzdC5zcHlPbihjb25zb2xlLCBcIndhcm5cIikubW9ja0ltcGxlbWVudGF0aW9uKCk7XG5cbiAgICBoYW5kbGVyID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgIH0pO1xuXG4gICAgLy8gUmVzZXQgbW9ja3NcbiAgICBtb2NrUzNTZW5kLm1vY2tSZXNldCgpO1xuICAgIC8vIEFuIGVtcHR5IGJ1Y2tldDogbm8gb2JqZWN0LCBzdWNoIGFzIG5vIGJ1aWxkIHRhZyBtYW5pZmVzdC5cbiAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcbiAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVzZXQoKTtcbiAgICBtb2NrQ2xvdWRGcm9udFNlbmQubW9ja1Jlc2V0KCk7XG4gICAgbW9ja1NzbVNlbmQubW9ja1Jlc2V0KCk7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgLy8gQ2xlYW4gdXAgZW52aXJvbm1lbnQgdmFyaWFibGVzXG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQ0FDSEVfQlVDS0VUX05BTUU7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfUkVWQUxJREFUSU9OX1RBQkxFX05BTUU7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQlVJTERfSUQ7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkFXU19SRUdJT047XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUU7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEO1xuICAgIGlmIChkaXN0RGlyKSB7XG4gICAgICBybVN5bmMoZGlzdERpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgICAgZGlzdERpciA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICAvLyBSZXN0b3JlIGNvbnNvbGUud2FyblxuICAgIGplc3QucmVzdG9yZUFsbE1vY2tzKCk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKFwiZ2V0XCIsICgpID0+IHtcbiAgICBpdChcInNob3VsZCByZXR1cm4gbnVsbCB3aGVuIFMzIGJ1Y2tldCBpcyBub3QgY29uZmlndXJlZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBkZWxldGUgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19DQUNIRV9CVUNLRVRfTkFNRTtcblxuICAgICAgY29uc3QgaGFuZGxlcldpdGhvdXRCdWNrZXQgPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgICBjb250ZXh0OiBtb2NrQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyV2l0aG91dEJ1Y2tldC5nZXQoXCJ0ZXN0LWtleVwiLCB7XG4gICAgICAgIGtpbmQ6IEluY3JlbWVudGFsQ2FjaGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZU51bGwoKTtcbiAgICB9KTtcblxuICAgIGl0KFwic2hvdWxkIHJldHJpZXZlIGFuZCBwYXJzZSBjYWNoZSB2YWx1ZSBmcm9tIFMzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRlc3REYXRhOiBJbmNyZW1lbnRhbENhY2hlVmFsdWUgPSB7XG4gICAgICAgIGtpbmQ6IENhY2hlZFJvdXRlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaHRtbDogXCI8aHRtbD50ZXN0PC9odG1sPlwiLFxuICAgICAgICByc2NEYXRhOiB1bmRlZmluZWQsXG4gICAgICAgIGhlYWRlcnM6IHVuZGVmaW5lZCxcbiAgICAgICAgcG9zdHBvbmVkOiB1bmRlZmluZWQsXG4gICAgICAgIHNlZ21lbnREYXRhOiB1bmRlZmluZWQsXG4gICAgICAgIHN0YXR1czogdW5kZWZpbmVkLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgY2FjaGVWYWx1ZSA9IHtcbiAgICAgICAgbGFzdE1vZGlmaWVkOiBEYXRlLm5vdygpLFxuICAgICAgICB2YWx1ZTogdGVzdERhdGEsXG4gICAgICB9O1xuXG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICAgIEJvZHk6IHtcbiAgICAgICAgICB0cmFuc2Zvcm1Ub1N0cmluZzogamVzdFxuICAgICAgICAgICAgLmZuKClcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShKU09OLnN0cmluZ2lmeShjYWNoZVZhbHVlKSksXG4gICAgICAgIH0sXG4gICAgICAgIENvbnRlbnRUeXBlOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyLmdldChcInRlc3Qta2V5XCIsIHtcbiAgICAgICAga2luZDogSW5jcmVtZW50YWxDYWNoZUtpbmQuQVBQX1BBR0UsXG4gICAgICAgIGlzRmFsbGJhY2s6IGZhbHNlLFxuICAgICAgfSk7XG5cbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwoY2FjaGVWYWx1ZSk7XG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LmFueShHZXRPYmplY3RDb21tYW5kKSk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCByZXR1cm4gbnVsbCB3aGVuIFMzIG9iamVjdCBub3QgZm91bmRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgICBCb2R5OiBudWxsLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGhhbmRsZXIuZ2V0KFwibWlzc2luZy1rZXlcIiwge1xuICAgICAgICBraW5kOiBJbmNyZW1lbnRhbENhY2hlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaXNGYWxsYmFjazogZmFsc2UsXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVOdWxsKCk7XG4gICAgfSk7XG5cbiAgICBpdChcImludmFsaWRhdGVzIGEgc2VlZGVkIHByZXJlbmRlciBvbmx5IHdoZW4gaXRzIHRhZyBtYXJrZXIgaXMgbmV3ZXJcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gQSBidWlsZC10aW1lIHByZXJlbmRlciBpcyB3cml0dGVuIGFzIGEgZmlsZSBieSB0aGUgYWRhcHRlcidzXG4gICAgICAvLyBgb25CdWlsZENvbXBsZXRlYCwgbmV2ZXIgdGhyb3VnaCBgc2V0YCwgc28gaXQgaGFzIG5vIGB0YWdzYCBhcnJheSBhbmQgbm9cbiAgICAgIC8vIER5bmFtb0RCIG1hcHBpbmcgcm93cyAtIGl0cyB0YWdzIGxpdmUgaW4gdGhlIHJlbmRlcidzXG4gICAgICAvLyBgeC1uZXh0LWNhY2hlLXRhZ3NgIGhlYWRlci4gVHdvIGJ1Z3MgbWV0IGhlcmU6IHRob3NlIGhlYWRlciB0YWdzIHdlcmVcbiAgICAgIC8vIGlnbm9yZWQsIHNvIGByZXZhbGlkYXRlVGFnYCBjb3VsZCBub3QgcmVhY2ggYW55IHN0YXRpYyBwYWdlOyBhbmQgdGhlXG4gICAgICAvLyBtYXBwaW5nIHJvd3MgYHNldGAgd3JpdGVzIHdlcmUgc3RhbXBlZCBgcmV2YWxpZGF0ZWRBdCA9IG5vd2AsIHdoaWNoIGlzXG4gICAgICAvLyAqYWZ0ZXIqIHRoZSBlbnRyeSdzIG93biBgbGFzdE1vZGlmaWVkYCwgc28gYSB0YWdnZWQgZW50cnkgbG9va2VkXG4gICAgICAvLyByZXZhbGlkYXRlZCB0aGUgbW9tZW50IGl0IHdhcyBzdG9yZWQgYW5kIGV2ZXJ5IHJlcXVlc3QgcmUtcmVuZGVyZWQuXG4gICAgICAvLyBNZWFzdXJlZCBhZ2FpbnN0IG5leHQuanMncyBgdGVzdC9lMmUvYXBwLWRpci9yZXN1bWUtZGF0YS1jYWNoZWAuXG4gICAgICBjb25zdCBsYXN0TW9kaWZpZWQgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc2VlZGVkID0ge1xuICAgICAgICBsYXN0TW9kaWZpZWQsXG4gICAgICAgIHZhbHVlOiB7XG4gICAgICAgICAga2luZDogQ2FjaGVkUm91dGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICAgIGh0bWw6IFwiPGh0bWw+c2VlZGVkPC9odG1sPlwiLFxuICAgICAgICAgIGhlYWRlcnM6IHsgXCJ4LW5leHQtY2FjaGUtdGFnc1wiOiBcIl9OX1RfLyxfTl9UXy9wYWdlLHRlc3RcIiB9LFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHMzQm9keSA9ICgpID0+ICh7XG4gICAgICAgIEJvZHk6IHtcbiAgICAgICAgICB0cmFuc2Zvcm1Ub1N0cmluZzogamVzdFxuICAgICAgICAgICAgLmZuKClcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShKU09OLnN0cmluZ2lmeShzZWVkZWQpKSxcbiAgICAgICAgfSxcbiAgICAgICAgQ29udGVudFR5cGU6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgfSk7XG4gICAgICBtb2NrUzNTZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKGNvbW1hbmQgaW5zdGFuY2VvZiBHZXRPYmplY3RDb21tYW5kID8gczNCb2R5KCkgOiB7fSksXG4gICAgICApO1xuICAgICAgY29uc3QgZ2V0Q3R4ID0ge1xuICAgICAgICBraW5kOiBJbmNyZW1lbnRhbENhY2hlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaXNGYWxsYmFjazogZmFsc2UsXG4gICAgICB9IGFzIGNvbnN0O1xuICAgICAgLy8gRWFjaCBzdGVwIGJlbG93IGNoYW5nZXMgdGhlIG1hcmtlcnMgRHluYW1vREIgaG9sZHM7IGEgbmV3IGluc3RhbmNlXG4gICAgICAvLyByZWFkcyB0aGVtIGFmcmVzaC5cbiAgICAgIGNvbnN0IGZyZXNoSGFuZGxlciA9ICgpID0+IHtcbiAgICAgICAgcmVzZXRUYWdNYW5pZmVzdCgpO1xuICAgICAgICByZXR1cm4gbmV3IFMzQ2FjaGVIYW5kbGVyKHsgY29udGV4dDogbW9ja0NvbnRleHQgfSk7XG4gICAgICB9O1xuXG4gICAgICAvLyBObyBtYXJrZXIgYXQgYWxsOiB0aGUgdGFnIHdhcyBuZXZlciByZXZhbGlkYXRlZC5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7fSk7XG4gICAgICBleHBlY3QoYXdhaXQgZnJlc2hIYW5kbGVyKCkuZ2V0KFwiaW5kZXhcIiwgZ2V0Q3R4KSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgIGxhc3RNb2RpZmllZCxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBBIG1hcmtlciBvbGRlciB0aGFuIHRoZSBlbnRyeSBtZWFucyB0aGUgZW50cnkgYWxyZWFkeSByZWZsZWN0cyBpdC5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7XG4gICAgICAgIGdldDogeyBJdGVtOiB7IHJldmFsaWRhdGVkQXQ6IHsgTjogU3RyaW5nKGxhc3RNb2RpZmllZCAtIDEwMDApIH0gfSB9LFxuICAgICAgfSk7XG4gICAgICBleHBlY3QoYXdhaXQgZnJlc2hIYW5kbGVyKCkuZ2V0KFwiaW5kZXhcIiwgZ2V0Q3R4KSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgIGxhc3RNb2RpZmllZCxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KG1vY2tTM1NlbmQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgZXhwZWN0LmFueShEZWxldGVPYmplY3RDb21tYW5kKSxcbiAgICAgICk7XG5cbiAgICAgIC8vIEEgbmV3ZXIgbWFya2VyOiB0aGUgZW50cnkgY29tZXMgYmFjayBtYXJrZWQgZXhwaXJlZCwgYW5kIHN0YXlzIGluIFMzLlxuICAgICAgZHluYW1vUmVzcG9uc2VzKHtcbiAgICAgICAgZ2V0OiB7IEl0ZW06IHsgcmV2YWxpZGF0ZWRBdDogeyBOOiBTdHJpbmcobGFzdE1vZGlmaWVkICsgMTAwMCkgfSB9IH0sXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChhd2FpdCBmcmVzaEhhbmRsZXIoKS5nZXQoXCJpbmRleFwiLCBnZXRDdHgpKS50b01hdGNoT2JqZWN0KHtcbiAgICAgICAgbGFzdE1vZGlmaWVkOiAtMSxcbiAgICAgICAgdmFsdWU6IHNlZWRlZC52YWx1ZSxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KG1vY2tTM1NlbmQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgZXhwZWN0LmFueShEZWxldGVPYmplY3RDb21tYW5kKSxcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdChcInJlcG9ydHMgYSByZXZhbGlkYXRlZCByZXNwb25zZSBlbnRyeSBhcyBleHBpcmVkIHJhdGhlciB0aGFuIGFzIGEgbWlzc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBgbGFzdE1vZGlmaWVkOiAtMWAgaXMgaG93IGEgY2FjaGUgaGFuZGxlciBzYXlzIFwiZXhwaXJlZCwgcmUtcmVuZGVyXG4gICAgICAvLyBiZWZvcmUgYW5zd2VyaW5nXCI6IGBJbmNyZW1lbnRhbENhY2hlLmdldGAgdHVybnMgaXQgaW50byBgaXNTdGFsZTogLTFgLFxuICAgICAgLy8gd2hpY2ggYGFwcC1wYWdlLXJ1bnRpbWVgIHJlYWRzIGFzIGFuIG9uLWRlbWFuZCByZXZhbGlkYXRpb24gYW5kIGFuc3dlcnNcbiAgICAgIC8vIHdpdGggYSBibG9ja2luZyByZW5kZXIgb2YgdGhpcyByb3V0ZSwgdGhlbiBzdG9yZXMgaXQuIFJldHVybmluZyBgbnVsbGBcbiAgICAgIC8vIGlzIG5vdCBlcXVpdmFsZW50LiBBIG1pc3Mgb24gYSBQUFIgcm91dGUgd2hvc2UgYHByZXJlbmRlci1tYW5pZmVzdC5qc29uYFxuICAgICAgLy8gZW50cnkgaGFzIGEgYGZhbGxiYWNrYCAoYGNvbXB1dGU6IFwicmVzdW1pbmdcImApIGlzIGFuc3dlcmVkIGZyb20gdGhlXG4gICAgICAvLyByb3V0ZSdzIGZhbGxiYWNrIHNoZWxsIC0gYGNhY2hlLWNvbnRyb2w6IHByaXZhdGUsIG5vLXN0b3JlYCwgbm9cbiAgICAgIC8vIGB4LW5leHRqcy1jYWNoZWAgLSBhbmQgd2l0aG91dCBgcGFydGlhbFByZWZldGNoaW5nYCBub3RoaW5nIGV2ZXJcbiAgICAgIC8vIHVwZ3JhZGVzIHRoYXQgYmFjayBpbnRvIGEgY29uY3JldGUgZW50cnkuIFNvIHRoZSBmaXJzdCBgcmV2YWxpZGF0ZVRhZ2BcbiAgICAgIC8vIHRvIHJlYWNoIGEgcGFnZSBsZWZ0IGl0IHVuY2FjaGVhYmxlIGFuZCBkeW5hbWljYWxseSByZXN1bWVkIHBlciByZXF1ZXN0XG4gICAgICAvLyBmb3IgdGhlIHJlc3Qgb2YgdGhlIGRlcGxveW1lbnQncyBsaWZlLCB3aGljaCBpcyB3aGF0IHRoZSBpc3IgZTJlJ3NcbiAgICAgIC8vIG1pc3NpbmcgYHgtbmV4dGpzLWNhY2hlYCBoZWFkZXIgd2FzLlxuICAgICAgY29uc3QgbGFzdE1vZGlmaWVkID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHN0b3JlZCA9IHtcbiAgICAgICAgbGFzdE1vZGlmaWVkLFxuICAgICAgICB0YWdzOiBbXCJjb2xsZWN0aW9uXCJdLFxuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgIGtpbmQ6IENhY2hlZFJvdXRlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgICBodG1sOiBcIjxodG1sPmlzcjwvaHRtbD5cIixcbiAgICAgICAgICBoZWFkZXJzOiB7IFwieC1uZXh0LWNhY2hlLXRhZ3NcIjogXCJjb2xsZWN0aW9uXCIgfSxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBtb2NrUzNTZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKFxuICAgICAgICAgIGNvbW1hbmQgaW5zdGFuY2VvZiBHZXRPYmplY3RDb21tYW5kXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBCb2R5OiB7XG4gICAgICAgICAgICAgICAgICB0cmFuc2Zvcm1Ub1N0cmluZzogamVzdFxuICAgICAgICAgICAgICAgICAgICAuZm4oKVxuICAgICAgICAgICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUoSlNPTi5zdHJpbmdpZnkoc3RvcmVkKSksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBDb250ZW50VHlwZTogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDoge30sXG4gICAgICAgICksXG4gICAgICApO1xuICAgICAgZHluYW1vUmVzcG9uc2VzKHtcbiAgICAgICAgZ2V0OiB7IEl0ZW06IHsgcmV2YWxpZGF0ZWRBdDogeyBOOiBTdHJpbmcobGFzdE1vZGlmaWVkICsgMTAwMCkgfSB9IH0sXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgaGFuZGxlci5nZXQoXCJpc3IvMVwiLCB7XG4gICAgICAgIGtpbmQ6IEluY3JlbWVudGFsQ2FjaGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKHsgbGFzdE1vZGlmaWVkOiAtMSwgdmFsdWU6IHN0b3JlZC52YWx1ZSB9KTtcbiAgICAgIC8vIFRoZSBib2R5IGlzIHN0aWxsIHRoZXJlIGZvciB0aGUgcmVuZGVyIHRoYXQgZmFpbHMsIGFuZCBgc2V0YCBvdmVyd3JpdGVzXG4gICAgICAvLyBpdCB3aXRoIGEgYGxhc3RNb2RpZmllZGAgcGFzdCB0aGUgbWFya2VyLlxuICAgICAgZXhwZWN0KG1vY2tTM1NlbmQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgZXhwZWN0LmFueShEZWxldGVPYmplY3RDb21tYW5kKSxcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdChcInJlcG9ydHMgYSByZXZhbGlkYXRlZCBmZXRjaCBlbnRyeSBhcyBhIG1pc3Mgc28gdGhlIHJlcXVlc3QgcmVmZXRjaGVzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFRoZSBvcHBvc2l0ZSBvZiBhIHJlc3BvbnNlIGVudHJ5OiByZXVzaW5nIGEgcmV2YWxpZGF0ZWQgYGZldGNoYCBib2R5IGlzXG4gICAgICAvLyBzZXJ2aW5nIHN0YWxlIGRhdGEsIHNvIHRoaXMgcmVhZHMgYXMgYSBtaXNzLCBsaWtlIE5leHQuanMncyBvd25cbiAgICAgIC8vIGBGaWxlU3lzdGVtQ2FjaGVgIGRvZXMgZm9yIGl0cyBgcmV2YWxpZGF0ZWRUYWdzYC5cbiAgICAgIGNvbnN0IGxhc3RNb2RpZmllZCA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCBzdG9yZWQgPSB7XG4gICAgICAgIGxhc3RNb2RpZmllZCxcbiAgICAgICAgdGFnczogW1wiY29sbGVjdGlvblwiXSxcbiAgICAgICAgdmFsdWU6IHtcbiAgICAgICAgICBraW5kOiBDYWNoZWRSb3V0ZUtpbmQuRkVUQ0gsXG4gICAgICAgICAgZGF0YTogeyBoZWFkZXJzOiB7fSwgYm9keTogXCJzdGFsZVwiLCBzdGF0dXM6IDIwMCwgdXJsOiBcIi9hcGlcIiB9LFxuICAgICAgICAgIHJldmFsaWRhdGU6IDEwLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICAgIG1vY2tTM1NlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoXG4gICAgICAgICAgY29tbWFuZCBpbnN0YW5jZW9mIEdldE9iamVjdENvbW1hbmRcbiAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgIEJvZHk6IHtcbiAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybVRvU3RyaW5nOiBqZXN0XG4gICAgICAgICAgICAgICAgICAgIC5mbigpXG4gICAgICAgICAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShKU09OLnN0cmluZ2lmeShzdG9yZWQpKSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIENvbnRlbnRUeXBlOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7fSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgICBkeW5hbW9SZXNwb25zZXMoe1xuICAgICAgICBnZXQ6IHsgSXRlbTogeyByZXZhbGlkYXRlZEF0OiB7IE46IFN0cmluZyhsYXN0TW9kaWZpZWQgKyAxMDAwKSB9IH0gfSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyLmdldChcImZldGNoLWtleVwiLCB7XG4gICAgICAgIGtpbmQ6IEluY3JlbWVudGFsQ2FjaGVLaW5kLkZFVENILFxuICAgICAgICByZXZhbGlkYXRlOiAxMCxcbiAgICAgICAgZmV0Y2hVcmw6IFwiaHR0cHM6Ly9leGFtcGxlLnRlc3QvYXBpXCIsXG4gICAgICAgIGZldGNoSWR4OiAxLFxuICAgICAgICB0YWdzOiBbXCJjb2xsZWN0aW9uXCJdLFxuICAgICAgICBzb2Z0VGFnczogW10sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZU51bGwoKTtcbiAgICAgIC8vIE5vdCBkZWxldGVkOiB0aGUgcmVmZXRjaCB0aGlzIHByb3Zva2VzIG92ZXJ3cml0ZXMgaXQgdGhyb3VnaCBgc2V0YC5cbiAgICAgIC8vIERlbGV0aW5nIGl0IGhlcmUgcmFjZWQgdGhhdCB3cml0ZSwgc28gYSBjb25jdXJyZW50IHJlcXVlc3QncyBmcmVzaFxuICAgICAgLy8gZW50cnkgY291bGQgYmUgdGhlIG9uZSByZW1vdmVkLlxuICAgICAgZXhwZWN0KG1vY2tTM1NlbmQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgZXhwZWN0LmFueShEZWxldGVPYmplY3RDb21tYW5kKSxcbiAgICAgICk7XG4gICAgICBleHBlY3QoRGVsZXRlSXRlbUNvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgfSk7XG5cbiAgICBpdChcImNoZWNrcyBhIGZldGNoIGVudHJ5IGFnYWluc3QgdGhlIHJlcXVlc3QncyBpbXBsaWNpdCB0YWdzLCBub3QgaXRzIG93blwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBBbiB1bnRhZ2dlZCBgY2FjaGU6IFwiZm9yY2UtY2FjaGVcImAgZmV0Y2ggaXMgc3RvcmVkIHdpdGggbm8gdGFncyBhdCBhbGwgLVxuICAgICAgLy8gdGhlIGltcGxpY2l0IGBfTl9UXy88cGF0aD5gIGNoYWluIHJlYWNoZXMgdGhlIGhhbmRsZXIgb25seSBhc1xuICAgICAgLy8gYGN0eC5zb2Z0VGFnc2AsIHdoaWNoIGlzIHRoZSBzb3VyY2UgTmV4dC5qcydzIG93biBgRmlsZVN5c3RlbUNhY2hlYCByZWFkc1xuICAgICAgLy8gZm9yIGEgYEZFVENIYCBnZXQuIENoZWNraW5nIHRoZSBzdG9yZWQgdGFncyBpbnN0ZWFkIGxlZnQgdGhpcyBlbnRyeSB3aXRoXG4gICAgICAvLyBub3RoaW5nIHRvIGNoZWNrIGFuZCBubyBgcmV2YWxpZGF0ZVBhdGhgIGNvdWxkIGV2ZXIgZXZpY3QgaXQuXG4gICAgICBjb25zdCBsYXN0TW9kaWZpZWQgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc3RvcmVkID0ge1xuICAgICAgICBsYXN0TW9kaWZpZWQsXG4gICAgICAgIHRhZ3M6IFtdLFxuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgIGtpbmQ6IENhY2hlZFJvdXRlS2luZC5GRVRDSCxcbiAgICAgICAgICBkYXRhOiB7IGhlYWRlcnM6IHt9LCBib2R5OiBcInN0YWxlXCIsIHN0YXR1czogMjAwLCB1cmw6IFwiL2FwaVwiIH0sXG4gICAgICAgICAgcmV2YWxpZGF0ZTogMTAsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgbW9ja1MzU2VuZC5tb2NrSW1wbGVtZW50YXRpb24oKGNvbW1hbmQ6IHVua25vd24pID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZShcbiAgICAgICAgICBjb21tYW5kIGluc3RhbmNlb2YgR2V0T2JqZWN0Q29tbWFuZFxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgQm9keToge1xuICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtVG9TdHJpbmc6IGplc3RcbiAgICAgICAgICAgICAgICAgICAgLmZuKClcbiAgICAgICAgICAgICAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlKEpTT04uc3RyaW5naWZ5KHN0b3JlZCkpLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgQ29udGVudFR5cGU6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHt9LFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7XG4gICAgICAgIGdldDogeyBJdGVtOiB7IHJldmFsaWRhdGVkQXQ6IHsgTjogU3RyaW5nKGxhc3RNb2RpZmllZCArIDEwMDApIH0gfSB9LFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGhhbmRsZXIuZ2V0KFwiZmV0Y2gta2V5XCIsIHtcbiAgICAgICAga2luZDogSW5jcmVtZW50YWxDYWNoZUtpbmQuRkVUQ0gsXG4gICAgICAgIHJldmFsaWRhdGU6IDEwLFxuICAgICAgICBmZXRjaFVybDogXCJodHRwczovL25leHQtZGF0YS1hcGktZW5kcG9pbnQudGVzdC9hcGkvcmFuZG9tXCIsXG4gICAgICAgIGZldGNoSWR4OiAxLFxuICAgICAgICB0YWdzOiBbXSxcbiAgICAgICAgc29mdFRhZ3M6IFtcIl9OX1RfL2xheW91dFwiLCBcIl9OX1RfL2R5bmFtaWNcIl0sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZU51bGwoKTtcbiAgICAgIGNvbnN0IFt7IFJlcXVlc3RJdGVtcyB9XSA9IChCYXRjaEdldEl0ZW1Db21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrKVxuICAgICAgICAubW9jay5jYWxsc1swXTtcbiAgICAgIGV4cGVjdChcbiAgICAgICAgUmVxdWVzdEl0ZW1zW1widGVzdC10YWJsZVwiXS5LZXlzLm1hcChcbiAgICAgICAgICAoa2V5OiB7IHNrOiB7IFM6IHN0cmluZyB9IH0pID0+IGtleS5zay5TLFxuICAgICAgICApLFxuICAgICAgKS50b0VxdWFsKFtcIl9OX1RfL2xheW91dFwiLCBcIl9OX1RfL2R5bmFtaWNcIl0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJhIHRhZyByZXZhbGlkYXRlZCB3aXRoIGEgcHJvZmlsZVwiLCAoKSA9PiB7XG4gICAgICAvLyBgcmV2YWxpZGF0ZVRhZyhcInBvc3RzXCIsIFwibWF4XCIpYCBpcyBzdGFsZS13aGlsZS1yZXZhbGlkYXRlOiB0aGUgZW50cnkgaXNcbiAgICAgIC8vIHNlcnZlZCBvbmNlIG1vcmUgd2hpbGUgYSBiYWNrZ3JvdW5kIHJlbmRlciByZXBsYWNlcyBpdCwgYW5kIGV4cGlyZXNcbiAgICAgIC8vIG91dHJpZ2h0IG9ubHkgYWZ0ZXIgdGhlIHByb2ZpbGUncyBgZXhwaXJlYC4gVHJlYXRpbmcgaXQgYXMgYHVwZGF0ZVRhZ2BcbiAgICAgIC8vIG1hZGUgZXZlcnkgc3VjaCBjYWxsIGEgYmxvY2tpbmcgcmUtcmVuZGVyLlxuICAgICAgY29uc3QgbGFzdE1vZGlmaWVkID0gRGF0ZS5ub3coKSAtIDEwMDA7XG4gICAgICBjb25zdCBzdG9yZWQgPSB7XG4gICAgICAgIGxhc3RNb2RpZmllZCxcbiAgICAgICAgdmFsdWU6IHtcbiAgICAgICAgICBraW5kOiBDYWNoZWRSb3V0ZUtpbmQuQVBQX1BBR0UsXG4gICAgICAgICAgaHRtbDogXCI8aHRtbD5wb3N0czwvaHRtbD5cIixcbiAgICAgICAgICBoZWFkZXJzOiB7IFwieC1uZXh0LWNhY2hlLXRhZ3NcIjogXCJwb3N0c1wiIH0sXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgY29uc3QgZ2V0Q3R4ID0ge1xuICAgICAgICBraW5kOiBJbmNyZW1lbnRhbENhY2hlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaXNGYWxsYmFjazogZmFsc2UsXG4gICAgICB9IGFzIGNvbnN0O1xuICAgICAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihcbiAgICAgICAgXCIvZGVwbG95bWVudC9ub2RlX21vZHVsZXMvbmV4dC9kaXN0L3NlcnZlci9saWIvaW5jcmVtZW50YWwtY2FjaGVcIixcbiAgICAgICAgXCJ0YWdzLW1hbmlmZXN0LmV4dGVybmFsLmpzXCIsXG4gICAgICApO1xuICAgICAgLy8gVGhlIG1vZHVsZSB0aGUgc2VydmVyIGxvYWRzLCByZXNvbHZlZCBmb3IgcmVhbCwgc28gYSBOZXh0LmpzIHVwZ3JhZGVcbiAgICAgIC8vIHRoYXQgbW92ZXMgb3IgcmVzaGFwZXMgaXQgZmFpbHMgaGVyZSByYXRoZXIgdGhhbiBzaWxlbnRseSB0dXJuaW5nXG4gICAgICAvLyBzdGFsZS13aGlsZS1yZXZhbGlkYXRlIGludG8gYmxvY2tpbmcgcmVuZGVycy5cbiAgICAgIGNvbnN0IHJlYWxNYW5pZmVzdFBhdGggPVxuICAgICAgICByZXF1aXJlLnJlc29sdmUoXCJuZXh0L2Rpc3Qvc2VydmVyL2xpYi9pbmNyZW1lbnRhbC1jYWNoZS90YWdzLW1hbmlmZXN0LmV4dGVybmFsLmpzXCIpO1xuXG4gICAgICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAgICAgbW9ja1MzU2VuZC5tb2NrSW1wbGVtZW50YXRpb24oKGNvbW1hbmQ6IHVua25vd24pID0+XG4gICAgICAgICAgUHJvbWlzZS5yZXNvbHZlKFxuICAgICAgICAgICAgY29tbWFuZCBpbnN0YW5jZW9mIEdldE9iamVjdENvbW1hbmRcbiAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICBCb2R5OiB7XG4gICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybVRvU3RyaW5nOiBqZXN0XG4gICAgICAgICAgICAgICAgICAgICAgLmZuKClcbiAgICAgICAgICAgICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUoSlNPTi5zdHJpbmdpZnkoc3RvcmVkKSksXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgQ29udGVudFR5cGU6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgOiB7fSxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgICAgIGRlbGV0ZSBtb2NrTW9kdWxlQ2FjaGVbbWFuaWZlc3RQYXRoXTtcbiAgICAgICAgZGVsZXRlIG1vY2tNb2R1bGVDYWNoZVtyZWFsTWFuaWZlc3RQYXRoXTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInNlcnZlcyB0aGUgZW50cnkgYW5kIG1hcmtzIHRoZSB0YWcgc3RhbGUgaW4gTmV4dC5qcydzIG1hbmlmZXN0XCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgbmV4dCA9IGplc3QucmVxdWlyZUFjdHVhbChyZWFsTWFuaWZlc3RQYXRoKTtcbiAgICAgICAgbW9ja01vZHVsZUNhY2hlW3JlYWxNYW5pZmVzdFBhdGhdID0geyBleHBvcnRzOiBuZXh0IH07XG4gICAgICAgIGNvbnN0IHN0YWxlQXQgPSBsYXN0TW9kaWZpZWQgKyA1MDA7XG4gICAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7XG4gICAgICAgICAgZ2V0OiB7XG4gICAgICAgICAgICBJdGVtOiB7XG4gICAgICAgICAgICAgIHN0YWxlQXQ6IHsgTjogU3RyaW5nKHN0YWxlQXQpIH0sXG4gICAgICAgICAgICAgIGV4cGlyZWRBdDogeyBOOiBTdHJpbmcoRGF0ZS5ub3coKSArIDYwXzAwMCkgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZXhwZWN0KGF3YWl0IGhhbmRsZXIuZ2V0KFwicG9zdHNcIiwgZ2V0Q3R4KSkudG9FcXVhbCh7XG4gICAgICAgICAgbGFzdE1vZGlmaWVkLFxuICAgICAgICAgIHZhbHVlOiBzdG9yZWQudmFsdWUsXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBXaGVyZSBgSW5jcmVtZW50YWxDYWNoZS5nZXRgIHJlYWRzIGl0LCB0byBhbnN3ZXIgYGlzU3RhbGU6IHRydWVgLlxuICAgICAgICBleHBlY3QobmV4dC50YWdzTWFuaWZlc3QuZ2V0KFwicG9zdHNcIikpLnRvRXF1YWwoeyBzdGFsZTogc3RhbGVBdCB9KTtcbiAgICAgICAgZXhwZWN0KG5leHQuYXJlVGFnc1N0YWxlKFtcInBvc3RzXCJdLCBsYXN0TW9kaWZpZWQpKS50b0JlKHRydWUpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiZXhwaXJlcyB0aGUgZW50cnkgd2hlbiBOZXh0LmpzJ3MgbWFuaWZlc3QgY2Fubm90IGJlIGZvdW5kXCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgLy8gQSBzdGFsZSBtYXJrIG5vdGhpbmcgcmVhZHMgd291bGQgc2VydmUgdGhlIGVudHJ5IGFzIGZyZXNoOyBhIGJsb2NraW5nXG4gICAgICAgIC8vIHJlbmRlciBpcyB0aGUgc2FmZSBzaWRlIG9mIHRoYXQuXG4gICAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7XG4gICAgICAgICAgZ2V0OiB7IEl0ZW06IHsgc3RhbGVBdDogeyBOOiBTdHJpbmcobGFzdE1vZGlmaWVkICsgNTAwKSB9IH0gfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZXhwZWN0KGF3YWl0IGhhbmRsZXIuZ2V0KFwicG9zdHNcIiwgZ2V0Q3R4KSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgICAgbGFzdE1vZGlmaWVkOiAtMSxcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJleHBpcmVzIHRoZSBlbnRyeSBvbmNlIHRoZSBwcm9maWxlJ3MgZXhwaXJlIGhhcyBwYXNzZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgICBkeW5hbW9SZXNwb25zZXMoe1xuICAgICAgICAgIGdldDoge1xuICAgICAgICAgICAgSXRlbToge1xuICAgICAgICAgICAgICBzdGFsZUF0OiB7IE46IFN0cmluZyhsYXN0TW9kaWZpZWQgKyAxMDApIH0sXG4gICAgICAgICAgICAgIGV4cGlyZWRBdDogeyBOOiBTdHJpbmcobGFzdE1vZGlmaWVkICsgNTAwKSB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBleHBlY3QoYXdhaXQgaGFuZGxlci5nZXQoXCJwb3N0c1wiLCBnZXRDdHgpKS50b01hdGNoT2JqZWN0KHtcbiAgICAgICAgICBsYXN0TW9kaWZpZWQ6IC0xLFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZShcImJlaGluZCBhIGRpc3RyaWJ1dGlvblwiLCAoKSA9PiB7XG4gICAgICAgIC8vIGByZXZhbGlkYXRlVGFnYCdzIGludmFsaWRhdGlvbiBnb2VzIG91dCBiZWZvcmUgdGhlIHN0YWxlIGVudHJ5IGlzXG4gICAgICAgIC8vIHNlcnZlZCwgYW5kIHRoZSBzdGFsZSByZXNwb25zZSBjYXJyaWVzIHRoZSBlbnRyeSdzIG9yaWdpbmFsXG4gICAgICAgIC8vIGBzLW1heGFnZWA6IENsb3VkRnJvbnQgY2FjaGVzIGl0IGFnYWluLiBPbmx5IHRoZSByZWdlbmVyYXRpb24ncyBgc2V0YFxuICAgICAgICAvLyBrbm93cyB3aGVuIHRoZSBmcmVzaCBlbnRyeSBleGlzdHMgdG8gYmUgZmV0Y2hlZCBpbnN0ZWFkLlxuICAgICAgICBsZXQgY2RuSGFuZGxlcjogUzNDYWNoZUhhbmRsZXI7XG4gICAgICAgIGNvbnN0IHJlZ2VuZXJhdGVkID0gc3RvcmVkLnZhbHVlIGFzIHVua25vd24gYXMgSW5jcmVtZW50YWxDYWNoZVZhbHVlO1xuICAgICAgICBjb25zdCBpbnZhbGlkYXRlZFBhdGhzID0gKCk6IHN0cmluZ1tdW10gPT5cbiAgICAgICAgICAoQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubW9jay5jYWxscy5tYXAoXG4gICAgICAgICAgICAoW2lucHV0XSkgPT4gaW5wdXQuSW52YWxpZGF0aW9uQmF0Y2guUGF0aHMuSXRlbXMsXG4gICAgICAgICAgKTtcblxuICAgICAgICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAgICAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0RJU1RSSUJVVElPTl9JRF9QQVJBTV9OQU1FID0gXCJ0ZXN0LXBhcmFtLW5hbWVcIjtcbiAgICAgICAgICBjZG5IYW5kbGVyID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHsgY29udGV4dDogbW9ja0NvbnRleHQgfSk7XG4gICAgICAgICAgbW9ja01vZHVsZUNhY2hlW21hbmlmZXN0UGF0aF0gPSB7XG4gICAgICAgICAgICBleHBvcnRzOiB7IHRhZ3NNYW5pZmVzdDogbmV3IE1hcCgpIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgICBkeW5hbW9SZXNwb25zZXMoe1xuICAgICAgICAgICAgZ2V0OiB7IEl0ZW06IHsgc3RhbGVBdDogeyBOOiBTdHJpbmcobGFzdE1vZGlmaWVkICsgNTAwKSB9IH0gfSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgICAgICBQYXJhbWV0ZXI6IHsgVmFsdWU6IFwidGVzdC1kaXN0cmlidXRpb24taWRcIiB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiaW52YWxpZGF0ZXMgdGhlIHBhZ2UgYWdhaW4gb25jZSBpdHMgcmVnZW5lcmF0aW9uIGlzIHN0b3JlZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgY2RuSGFuZGxlci5nZXQoXCJwb3N0c1wiLCBnZXRDdHgpO1xuICAgICAgICAgIGV4cGVjdChpbnZhbGlkYXRlZFBhdGhzKCkpLnRvRXF1YWwoW10pO1xuXG4gICAgICAgICAgYXdhaXQgY2RuSGFuZGxlci5zZXQoXCJwb3N0c1wiLCByZWdlbmVyYXRlZCwge1xuICAgICAgICAgICAgY2FjaGVDb250cm9sOiB7IHJldmFsaWRhdGU6IGZhbHNlLCBleHBpcmU6IHVuZGVmaW5lZCB9LFxuICAgICAgICAgICAgaXNSb3V0ZVBQUkVuYWJsZWQ6IGZhbHNlLFxuICAgICAgICAgICAgaXNGYWxsYmFjazogZmFsc2UsXG4gICAgICAgICAgfSBhcyBhbnkpO1xuXG4gICAgICAgICAgZXhwZWN0KGludmFsaWRhdGVkUGF0aHMoKSkudG9FcXVhbChbW1wiL3Bvc3RzKlwiXV0pO1xuXG4gICAgICAgICAgLy8gT25jZTogYSBsYXRlciB3cml0ZSBvZiB0aGUgc2FtZSBwYWdlIGlzIGFuIG9yZGluYXJ5IG9uZS5cbiAgICAgICAgICBhd2FpdCBjZG5IYW5kbGVyLnNldChcInBvc3RzXCIsIHJlZ2VuZXJhdGVkLCB7XG4gICAgICAgICAgICBjYWNoZUNvbnRyb2w6IHsgcmV2YWxpZGF0ZTogZmFsc2UsIGV4cGlyZTogdW5kZWZpbmVkIH0sXG4gICAgICAgICAgICBpc1JvdXRlUFBSRW5hYmxlZDogZmFsc2UsXG4gICAgICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgICAgICB9IGFzIGFueSk7XG4gICAgICAgICAgZXhwZWN0KGludmFsaWRhdGVkUGF0aHMoKSkudG9IYXZlTGVuZ3RoKDEpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcInJlbWVtYmVycyBhIHN0YWxlIG1lbW9yeSBoaXQgYnkgdGhlIGtleSBpdCB3YXMgcmVhZCB1bmRlclwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgY2RuSGFuZGxlci5pc1JldmFsaWRhdGVkKHN0b3JlZCwgZ2V0Q3R4LCBcInBvc3RzXCIpO1xuICAgICAgICAgIGF3YWl0IGNkbkhhbmRsZXIuc2V0KFwicG9zdHNcIiwgcmVnZW5lcmF0ZWQsIHtcbiAgICAgICAgICAgIGlzUm91dGVQUFJFbmFibGVkOiBmYWxzZSxcbiAgICAgICAgICAgIGlzRmFsbGJhY2s6IGZhbHNlLFxuICAgICAgICAgIH0gYXMgYW55KTtcblxuICAgICAgICAgIGV4cGVjdChpbnZhbGlkYXRlZFBhdGhzKCkpLnRvRXF1YWwoW1tcIi9wb3N0cypcIl1dKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJkb2VzIG5vdCBpbnZhbGlkYXRlIGFmdGVyIGFuIG9yZGluYXJ5IHdyaXRlXCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBjZG5IYW5kbGVyLnNldChcInBvc3RzXCIsIHJlZ2VuZXJhdGVkLCB7XG4gICAgICAgICAgICBpc1JvdXRlUFBSRW5hYmxlZDogZmFsc2UsXG4gICAgICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgICAgICB9IGFzIGFueSk7XG5cbiAgICAgICAgICBleHBlY3QoaW52YWxpZGF0ZWRQYXRocygpKS50b0VxdWFsKFtdKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJmb3JnZXRzIGEgc3RhbGUgcGFnZSB0aGF0IGlzIGRlbGV0ZWQgaW5zdGVhZCBvZiByZWdlbmVyYXRlZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgY2RuSGFuZGxlci5nZXQoXCJwb3N0c1wiLCBnZXRDdHgpO1xuICAgICAgICAgIGF3YWl0IGNkbkhhbmRsZXIuc2V0KFwicG9zdHNcIiwgbnVsbCwge1xuICAgICAgICAgICAgaXNSb3V0ZVBQUkVuYWJsZWQ6IGZhbHNlLFxuICAgICAgICAgICAgaXNGYWxsYmFjazogZmFsc2UsXG4gICAgICAgICAgfSBhcyBhbnkpO1xuICAgICAgICAgIGF3YWl0IGNkbkhhbmRsZXIuc2V0KFwicG9zdHNcIiwgcmVnZW5lcmF0ZWQsIHtcbiAgICAgICAgICAgIGlzUm91dGVQUFJFbmFibGVkOiBmYWxzZSxcbiAgICAgICAgICAgIGlzRmFsbGJhY2s6IGZhbHNlLFxuICAgICAgICAgIH0gYXMgYW55KTtcblxuICAgICAgICAgIGV4cGVjdChpbnZhbGlkYXRlZFBhdGhzKCkpLnRvRXF1YWwoW10pO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgaGFuZGxlIFMzIGVycm9ycyBhbmQgcmV0dXJuIG51bGxcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwiUzMgRXJyb3JcIikpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyLmdldChcImVycm9yLWtleVwiLCB7XG4gICAgICAgIGtpbmQ6IEluY3JlbWVudGFsQ2FjaGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZU51bGwoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoXCJ0YWcgbWFya2VyIGNhY2hlXCIsICgpID0+IHtcbiAgICAvLyBFdmVyeSBjYWNoZSBoaXQgY2hlY2tzIGl0cyB0YWdzJyBtYXJrZXJzLCBhbmQgYWxsIG9mIGEgZGVwbG95bWVudCdzXG4gICAgLy8gbWFya2VycyBzaGFyZSBvbmUgcGFydGl0aW9uIGtleTogcmVhZCBwZXIgcmVxdWVzdCwgdGhleSBjYXBwZWQgYSByb3V0ZSdzXG4gICAgLy8gY2FjaGUgaGl0cyBhdCB+MSw5MDAgcmVxL3MuIEVhY2ggaW5zdGFuY2UgaG9sZHMgdGhlbSBmb3IgYSBzZWNvbmQuXG4gICAgY29uc3QgbGFzdE1vZGlmaWVkID0gRGF0ZS5ub3coKSAtIDYwXzAwMDtcbiAgICBjb25zdCBzdG9yZWQgPSB7XG4gICAgICBsYXN0TW9kaWZpZWQsXG4gICAgICB2YWx1ZToge1xuICAgICAgICBraW5kOiBDYWNoZWRSb3V0ZUtpbmQuQVBQX1BBR0UsXG4gICAgICAgIGh0bWw6IFwiPGh0bWw+Y2FjaGVkPC9odG1sPlwiLFxuICAgICAgICBoZWFkZXJzOiB7IFwieC1uZXh0LWNhY2hlLXRhZ3NcIjogXCJfTl9UXy9wYWdlLHBvc3RzXCIgfSxcbiAgICAgIH0sXG4gICAgfTtcbiAgICBjb25zdCBnZXRDdHggPSB7XG4gICAgICBraW5kOiBJbmNyZW1lbnRhbENhY2hlS2luZC5BUFBfUEFHRSxcbiAgICAgIGlzRmFsbGJhY2s6IGZhbHNlLFxuICAgIH0gYXMgY29uc3Q7XG4gICAgY29uc3QgbWFya2VyUmVhZHMgPSAoKSA9PlxuICAgICAgbW9ja0R5bmFtb1NlbmQubW9jay5jYWxscy5maWx0ZXIoXG4gICAgICAgIChbY29tbWFuZF0pID0+IGNvbW1hbmQgaW5zdGFuY2VvZiBCYXRjaEdldEl0ZW1Db21tYW5kLFxuICAgICAgKS5sZW5ndGg7XG4gICAgLy8gV2hhdCBgZ2V0YCBhbnN3ZXJzIGZvciBhIHJldmFsaWRhdGVkIHBhZ2U6IGV4cGlyZWQsIG5vdCBhIG1pc3MuXG4gICAgY29uc3QgZXhwaXJlZCA9IHsgbGFzdE1vZGlmaWVkOiAtMSB9O1xuICAgIGNvbnN0IHJldmFsaWRhdGVkQWZ0ZXJTdG9yZSA9IHtcbiAgICAgIGdldDogeyBJdGVtOiB7IHJldmFsaWRhdGVkQXQ6IHsgTjogU3RyaW5nKGxhc3RNb2RpZmllZCArIDEwMDApIH0gfSB9LFxuICAgIH07XG5cbiAgICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAgIG1vY2tTM1NlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoXG4gICAgICAgICAgY29tbWFuZCBpbnN0YW5jZW9mIEdldE9iamVjdENvbW1hbmRcbiAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgIEJvZHk6IHtcbiAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybVRvU3RyaW5nOiBqZXN0XG4gICAgICAgICAgICAgICAgICAgIC5mbigpXG4gICAgICAgICAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShKU09OLnN0cmluZ2lmeShzdG9yZWQpKSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIENvbnRlbnRUeXBlOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7fSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgICBkeW5hbW9SZXNwb25zZXMoe30pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJhbnN3ZXJzIGNoZWNrcyB3aXRoaW4gdGhlIFRUTCBmcm9tIHRoZSBtYXJrZXJzIGl0IGFscmVhZHkgcmVhZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBoYW5kbGVyLmdldChcInBhZ2VcIiwgZ2V0Q3R4KTtcbiAgICAgIGF3YWl0IGhhbmRsZXIuZ2V0KFwicGFnZVwiLCBnZXRDdHgpO1xuXG4gICAgICBleHBlY3QobWFya2VyUmVhZHMoKSkudG9CZSgxKTtcbiAgICB9KTtcblxuICAgIGl0KFwic2hhcmVzIG9uZSByZWFkIGJldHdlZW4gY29uY3VycmVudCBjaGVja3NcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICBoYW5kbGVyLmdldChcInBhZ2VcIiwgZ2V0Q3R4KSxcbiAgICAgICAgaGFuZGxlci5nZXQoXCJwYWdlXCIsIGdldEN0eCksXG4gICAgICAgIGhhbmRsZXIuZ2V0KFwicGFnZVwiLCBnZXRDdHgpLFxuICAgICAgXSk7XG5cbiAgICAgIGV4cGVjdChtYXJrZXJSZWFkcygpKS50b0JlKDEpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzZWVzIGl0cyBvd24gcmV2YWxpZGF0ZVRhZyBhdCBvbmNlLCBhbmQgbG9ncyBpdCBmb3IgdGhlIG90aGVyc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBleHBlY3QoYXdhaXQgaGFuZGxlci5nZXQoXCJwYWdlXCIsIGdldEN0eCkpLnRvTWF0Y2hPYmplY3QoeyBsYXN0TW9kaWZpZWQgfSk7XG5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyhyZXZhbGlkYXRlZEFmdGVyU3RvcmUpO1xuICAgICAgYXdhaXQgaGFuZGxlci5yZXZhbGlkYXRlVGFnKFwicG9zdHNcIik7XG5cbiAgICAgIGV4cGVjdChhd2FpdCBoYW5kbGVyLmdldChcInBhZ2VcIiwgZ2V0Q3R4KSkudG9NYXRjaE9iamVjdChleHBpcmVkKTtcbiAgICAgIGNvbnN0IHB1dHMgPSBtb2NrRHluYW1vU2VuZC5tb2NrLmNhbGxzLmZpbHRlcihcbiAgICAgICAgKFtjb21tYW5kXSkgPT4gY29tbWFuZCBpbnN0YW5jZW9mIFB1dEl0ZW1Db21tYW5kLFxuICAgICAgKTtcbiAgICAgIGV4cGVjdChwdXRzKS50b0hhdmVMZW5ndGgoMSk7XG4gICAgICBleHBlY3QoY29tbWFuZElucHV0KHB1dHNbMF1bMF0sIFB1dEl0ZW1Db21tYW5kKS5JdGVtKS50b01hdGNoT2JqZWN0KHtcbiAgICAgICAgcGs6IHsgUzogXCJ0ZXN0LWJ1aWxkLWlkI2xvZ1wiIH0sXG4gICAgICAgIHNrOiB7IFM6IGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXlxcZHsxNX0jcG9zdHMkLykgfSxcbiAgICAgICAgcmV2YWxpZGF0ZWRBdDogeyBOOiBleHBlY3QuYW55KFN0cmluZykgfSxcbiAgICAgICAgdHRsOiB7IE46IGV4cGVjdC5hbnkoU3RyaW5nKSB9LFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdChcIndyaXRlcyBlYWNoIHRhZyBvbmNlIHdoZW4gdGhlICd1c2UgY2FjaGUnIGhhbmRsZXJzIGdldCB0aGUgc2FtZSBjYWxsXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIE5leHQuanMgY2FsbHMgYHJldmFsaWRhdGVUYWdgIGhlcmUgYW5kIGB1cGRhdGVUYWdzYCBvbiBldmVyeVxuICAgICAgLy8gYGNhY2hlSGFuZGxlcnNgIGVudHJ5LCBhbmQgYWxsIG9mIHRoZW0gc2hhcmUgb25lIG1hbmlmZXN0LlxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICBoYW5kbGVyLnJldmFsaWRhdGVUYWcoW1wicG9zdHNcIl0pLFxuICAgICAgICBzaGFyZWRUYWdNYW5pZmVzdCgpLnVwZGF0ZShbXCJwb3N0c1wiXSwgdW5kZWZpbmVkKSxcbiAgICAgIF0pO1xuXG4gICAgICBjb25zdCB3cml0ZXMgPSBtb2NrRHluYW1vU2VuZC5tb2NrLmNhbGxzLmZpbHRlcihcbiAgICAgICAgKFtjb21tYW5kXSkgPT5cbiAgICAgICAgICBjb21tYW5kIGluc3RhbmNlb2YgVXBkYXRlSXRlbUNvbW1hbmQgfHxcbiAgICAgICAgICBjb21tYW5kIGluc3RhbmNlb2YgUHV0SXRlbUNvbW1hbmQsXG4gICAgICApO1xuICAgICAgZXhwZWN0KHdyaXRlcykudG9IYXZlTGVuZ3RoKDIpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZShcInNldFwiLCAoKSA9PiB7XG4gICAgLy8gTWFwcGluZyByb3dzIGV4aXN0IG9ubHkgdG8gbmFtZSBDbG91ZEZyb250IHBhdGhzLCBzbyBvbmx5IGEgZGVwbG95bWVudFxuICAgIC8vIHdpdGggYSBkaXN0cmlidXRpb24ga2VlcHMgdGhlbS5cbiAgICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgaGFuZGxlciA9IG5ldyBTM0NhY2hlSGFuZGxlcih7IGNvbnRleHQ6IG1vY2tDb250ZXh0IH0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJrZWVwcyBubyBtYXBwaW5nIHJvd3Mgd2l0aG91dCBhIGRpc3RyaWJ1dGlvbiB0byBpbnZhbGlkYXRlXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFRoZSBSZWdpb25hbCBjb25zdHJ1Y3RzIGhhdmUgbm8gQ2xvdWRGcm9udC4gQSByb3cgcGVyIHRhZyBwZXIgYHNldGAsXG4gICAgICAvLyBhbmQgdGhlIFMzIHJlYWQgYmVmb3JlIGEgZGVsZXRlIHRvIG5hbWUgdGhlbSwgYm91Z2h0IG5vdGhpbmcgdGhlcmUuXG4gICAgICBkZWxldGUgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRTtcbiAgICAgIGNvbnN0IHJlZ2lvbmFsID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHsgY29udGV4dDogbW9ja0NvbnRleHQgfSk7XG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgcmVnaW9uYWwuc2V0KFxuICAgICAgICBcIi9pc3IvMVwiLFxuICAgICAgICB7XG4gICAgICAgICAga2luZDogQ2FjaGVkUm91dGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICAgIGh0bWw6IFwiPHAvPlwiLFxuICAgICAgICAgIHJzY0RhdGE6IHVuZGVmaW5lZCxcbiAgICAgICAgICBoZWFkZXJzOiB7IFwieC1uZXh0LWNhY2hlLXRhZ3NcIjogXCJ0YWdcIiB9LFxuICAgICAgICAgIHBvc3Rwb25lZDogdW5kZWZpbmVkLFxuICAgICAgICAgIHNlZ21lbnREYXRhOiB1bmRlZmluZWQsXG4gICAgICAgICAgc3RhdHVzOiB1bmRlZmluZWQsXG4gICAgICAgIH0sXG4gICAgICAgIGNyZWF0ZVNldENvbnRleHQoW10pLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IHJlZ2lvbmFsLnNldChcIi9pc3IvMVwiLCBudWxsLCB7IGlzRmFsbGJhY2s6IGZhbHNlIH0pO1xuXG4gICAgICBleHBlY3QobW9ja0R5bmFtb1NlbmQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5hbnkoR2V0T2JqZWN0Q29tbWFuZCkpO1xuICAgICAgZXhwZWN0KG1vY2tTM1NlbmQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5hbnkoRGVsZXRlT2JqZWN0Q29tbWFuZCkpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgc3RvcmUgY2FjaGUgdmFsdWUgaW4gUzNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdERhdGE6IEluY3JlbWVudGFsQ2FjaGVWYWx1ZSA9IHtcbiAgICAgICAga2luZDogQ2FjaGVkUm91dGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBodG1sOiBcIjxodG1sPnNldCB0ZXN0PC9odG1sPlwiLFxuICAgICAgICByc2NEYXRhOiB1bmRlZmluZWQsXG4gICAgICAgIGhlYWRlcnM6IHVuZGVmaW5lZCxcbiAgICAgICAgcG9zdHBvbmVkOiB1bmRlZmluZWQsXG4gICAgICAgIHNlZ21lbnREYXRhOiB1bmRlZmluZWQsXG4gICAgICAgIHN0YXR1czogdW5kZWZpbmVkLFxuICAgICAgfTtcblxuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe30pO1xuICAgICAgbW9ja0R5bmFtb1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuXG4gICAgICBhd2FpdCBoYW5kbGVyLnNldChcInNldC1rZXlcIiwgdGVzdERhdGEsIGNyZWF0ZVNldENvbnRleHQoW1widGFnMVwiXSkpO1xuXG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LmFueShQdXRPYmplY3RDb21tYW5kKSk7XG4gICAgICBleHBlY3QobW9ja0R5bmFtb1NlbmQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBleHBlY3QuYW55KFVwZGF0ZUl0ZW1Db21tYW5kKSxcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCBub3Qgc3RvcmUgd2hlbiBTMyBidWNrZXQgaXMgbm90IGNvbmZpZ3VyZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQ0FDSEVfQlVDS0VUX05BTUU7XG5cbiAgICAgIGNvbnN0IGhhbmRsZXJXaXRob3V0QnVja2V0ID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgdGVzdERhdGE6IEluY3JlbWVudGFsQ2FjaGVWYWx1ZSA9IHtcbiAgICAgICAga2luZDogQ2FjaGVkUm91dGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBodG1sOiBcIjxodG1sPm5vIGJ1Y2tldDwvaHRtbD5cIixcbiAgICAgICAgcnNjRGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBoZWFkZXJzOiB1bmRlZmluZWQsXG4gICAgICAgIHBvc3Rwb25lZDogdW5kZWZpbmVkLFxuICAgICAgICBzZWdtZW50RGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBzdGF0dXM6IHVuZGVmaW5lZCxcbiAgICAgIH07XG5cbiAgICAgIGF3YWl0IGhhbmRsZXJXaXRob3V0QnVja2V0LnNldChcbiAgICAgICAgXCJuby1idWNrZXQta2V5XCIsXG4gICAgICAgIHRlc3REYXRhLFxuICAgICAgICBjcmVhdGVTZXRDb250ZXh0KFtdKSxcbiAgICAgICk7XG5cbiAgICAgIGV4cGVjdChtb2NrUzNTZW5kKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJtYXBzIHRoZSB0YWdzIGEgcGFnZSBjYXJyaWVzIG9ubHkgaW4gaXRzIHgtbmV4dC1jYWNoZS10YWdzIGhlYWRlclwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBgUmVzcG9uc2VDYWNoZS5zZXRgIGJ1aWxkcyBhIHBhZ2UncyBgY3R4YCB3aXRob3V0IHRhZ3MsIHNvIHRoZSByZW5kZXInc1xuICAgICAgLy8gaGVhZGVyIGlzIHRoZSBvbmx5IHBsYWNlIHRoZXkgZXhpc3QuIE5vIG1hcHBpbmcgcm93IG1lYW50IGByZXZhbGlkYXRlVGFnYFxuICAgICAgLy8gZm91bmQgbm90aGluZyB0byBpbnZhbGlkYXRlIGFuZCBDbG91ZEZyb250IGtlcHQgdGhlIHN0YWxlIEhUTUwuXG4gICAgICBjb25zdCB0ZXN0RGF0YTogSW5jcmVtZW50YWxDYWNoZVZhbHVlID0ge1xuICAgICAgICBraW5kOiBDYWNoZWRSb3V0ZUtpbmQuQVBQX1BBR0UsXG4gICAgICAgIGh0bWw6IFwiPGh0bWw+dGFnZ2VkPC9odG1sPlwiLFxuICAgICAgICByc2NEYXRhOiB1bmRlZmluZWQsXG4gICAgICAgIGhlYWRlcnM6IHsgXCJ4LW5leHQtY2FjaGUtdGFnc1wiOiBcImhlYWRlci10YWcsb3RoZXItdGFnXCIgfSxcbiAgICAgICAgcG9zdHBvbmVkOiB1bmRlZmluZWQsXG4gICAgICAgIHNlZ21lbnREYXRhOiB1bmRlZmluZWQsXG4gICAgICAgIHN0YXR1czogdW5kZWZpbmVkLFxuICAgICAgfTtcblxuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXIuc2V0KFwiL2lzci8xXCIsIHRlc3REYXRhLCBjcmVhdGVTZXRDb250ZXh0KFtdKSk7XG5cbiAgICAgIGNvbnN0IG1hcHBpbmdLZXlzID0gKFVwZGF0ZUl0ZW1Db21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrKS5tb2NrLmNhbGxzXG4gICAgICAgIC5tYXAoKFtpbnB1dF0pID0+IGlucHV0LktleS5zay5TKVxuICAgICAgICAuc29ydCgpO1xuICAgICAgZXhwZWN0KG1hcHBpbmdLZXlzKS50b0VxdWFsKFtcbiAgICAgICAgXCJoZWFkZXItdGFnI3Rlc3QtYnVpbGQtaWQvaXNyLzEuanNvblwiLFxuICAgICAgICBcIm90aGVyLXRhZyN0ZXN0LWJ1aWxkLWlkL2lzci8xLmpzb25cIixcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJwcmVmZXJzIHRoZSBjb250ZXh0J3MgdGFncyBvdmVyIHRoZSBoZWFkZXIgd2hlbiBib3RoIGFyZSBwcmVzZW50XCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRlc3REYXRhOiBJbmNyZW1lbnRhbENhY2hlVmFsdWUgPSB7XG4gICAgICAgIGtpbmQ6IENhY2hlZFJvdXRlS2luZC5BUFBfUEFHRSxcbiAgICAgICAgaHRtbDogXCI8aHRtbD50YWdnZWQ8L2h0bWw+XCIsXG4gICAgICAgIHJzY0RhdGE6IHVuZGVmaW5lZCxcbiAgICAgICAgaGVhZGVyczogeyBcIngtbmV4dC1jYWNoZS10YWdzXCI6IFwiaGVhZGVyLXRhZ1wiIH0sXG4gICAgICAgIHBvc3Rwb25lZDogdW5kZWZpbmVkLFxuICAgICAgICBzZWdtZW50RGF0YTogdW5kZWZpbmVkLFxuICAgICAgICBzdGF0dXM6IHVuZGVmaW5lZCxcbiAgICAgIH07XG5cbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuICAgICAgbW9ja0R5bmFtb1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuXG4gICAgICBhd2FpdCBoYW5kbGVyLnNldChcIi9pc3IvMVwiLCB0ZXN0RGF0YSwgY3JlYXRlU2V0Q29udGV4dChbXCJjdHgtdGFnXCJdKSk7XG5cbiAgICAgIGNvbnN0IG1hcHBpbmdLZXlzID0gKFVwZGF0ZUl0ZW1Db21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrKS5tb2NrLmNhbGxzXG4gICAgICAgIC5tYXAoKFtpbnB1dF0pID0+IGlucHV0LktleS5zay5TKVxuICAgICAgICAuc29ydCgpO1xuICAgICAgZXhwZWN0KG1hcHBpbmdLZXlzKS50b0VxdWFsKFtcImN0eC10YWcjdGVzdC1idWlsZC1pZC9pc3IvMS5qc29uXCJdKTtcbiAgICB9KTtcblxuICAgIGl0KFwicmVtb3ZlcyBhIGRlbGV0ZWQgcGFnZSdzIG1hcHBpbmcgcm93cywgcmVhZGluZyBpdHMgdGFncyBmcm9tIFMzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIEEgcmVzcG9uc2UgZGVsZXRlIC0gYSBjYWNoZWQgcm91dGUgdGhhdCBzdGFydHMgYW5zd2VyaW5nIGBub3RGb3VuZCgpYCAtXG4gICAgICAvLyBhcnJpdmVzIGFzIGBzZXQoa2V5LCBudWxsLCB7IGNhY2hlQ29udHJvbCwgLi4uIH0pYCB3aXRoIG5vIHRhZ3MgYXQgYWxsLFxuICAgICAgLy8gc28gdGhlIGVudHJ5IGl0c2VsZiBpcyB0aGUgb25seSBwbGFjZSBpdHMgbWFwcGluZyByb3dzIGNhbiBiZSBuYW1lZFxuICAgICAgLy8gZnJvbS4gTGVmdCBiZWhpbmQsIHRoZXkgcmVzb2x2ZSBvbiB0aGUgbmV4dCBgcmV2YWxpZGF0ZVRhZ2AgdG8gYSBjYWNoZVxuICAgICAgLy8ga2V5IHdob3NlIG9iamVjdCBpcyBnb25lIGFuZCBzcGVuZCBhIENsb3VkRnJvbnQgd2lsZGNhcmQgcGF0aCBvbiBpdC5cbiAgICAgIGNvbnN0IHN0b3JlZCA9IHtcbiAgICAgICAgbGFzdE1vZGlmaWVkOiBEYXRlLm5vdygpLFxuICAgICAgICB0YWdzOiBbXCJjb2xsZWN0aW9uXCIsIFwiX05fVF8vaXNyLzFcIl0sXG4gICAgICAgIHZhbHVlOiB7XG4gICAgICAgICAga2luZDogQ2FjaGVkUm91dGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICAgIGh0bWw6IFwiPGh0bWw+Z29uZTwvaHRtbD5cIixcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBtb2NrUzNTZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKFxuICAgICAgICAgIGNvbW1hbmQgaW5zdGFuY2VvZiBHZXRPYmplY3RDb21tYW5kXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBCb2R5OiB7XG4gICAgICAgICAgICAgICAgICB0cmFuc2Zvcm1Ub1N0cmluZzogamVzdFxuICAgICAgICAgICAgICAgICAgICAuZm4oKVxuICAgICAgICAgICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUoSlNPTi5zdHJpbmdpZnkoc3RvcmVkKSksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBDb250ZW50VHlwZTogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDoge30sXG4gICAgICAgICksXG4gICAgICApO1xuICAgICAgbW9ja0R5bmFtb1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuXG4gICAgICBhd2FpdCBoYW5kbGVyLnNldChcIi9pc3IvMVwiLCBudWxsLCB7XG4gICAgICAgIGNhY2hlQ29udHJvbDogeyByZXZhbGlkYXRlOiA2MCwgZXhwaXJlOiB1bmRlZmluZWQgfSxcbiAgICAgICAgaXNSb3V0ZVBQUkVuYWJsZWQ6IGZhbHNlLFxuICAgICAgICBpc0ZhbGxiYWNrOiBmYWxzZSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LmFueShEZWxldGVPYmplY3RDb21tYW5kKSk7XG4gICAgICBjb25zdCBkZWxldGVkS2V5cyA9IChEZWxldGVJdGVtQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubW9jay5jYWxsc1xuICAgICAgICAubWFwKChbaW5wdXRdKSA9PiBpbnB1dC5LZXkuc2suUylcbiAgICAgICAgLnNvcnQoKTtcbiAgICAgIC8vIE1hcHBpbmcgcm93cyBvbmx5LiBUaGUgYmFyZS10YWcgbWFya2VyIHJvdyBiZWxvbmdzIHRvIHRoZSB0YWcsIGFuZFxuICAgICAgLy8gYGNoZWNrSWZSZXZhbGlkYXRlZGAgcmVhZHMgaXQgZm9yIGV2ZXJ5IG90aGVyIGVudHJ5IGNhcnJ5aW5nIGl0LlxuICAgICAgZXhwZWN0KGRlbGV0ZWRLZXlzKS50b0VxdWFsKFtcbiAgICAgICAgXCJfTl9UXy9pc3IvMSN0ZXN0LWJ1aWxkLWlkL2lzci8xLmpzb25cIixcbiAgICAgICAgXCJjb2xsZWN0aW9uI3Rlc3QtYnVpbGQtaWQvaXNyLzEuanNvblwiLFxuICAgICAgXSk7XG4gICAgfSk7XG5cbiAgICBpdChcImRlbGV0ZXMgYSBmZXRjaCBlbnRyeSdzIG1hcHBpbmcgcm93cyBmcm9tIHRoZSBjb250ZXh0J3MgdGFncyBhbG9uZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBgY3R4YCBjYXJyaWVzIHRoZW0gaGVyZSwgc28gdGhlIHByZS1kZWxldGUgcmVhZCBpcyBza2lwcGVkOiBvbmx5IHRoZVxuICAgICAgLy8gRGVsZXRlT2JqZWN0IHJlYWNoZXMgUzMuXG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlci5zZXQoXCJmZXRjaC1rZXlcIiwgbnVsbCwgY3JlYXRlU2V0Q29udGV4dChbXCJjdHgtdGFnXCJdKSk7XG5cbiAgICAgIGV4cGVjdChtb2NrUzNTZW5kKS5ub3QudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LmFueShHZXRPYmplY3RDb21tYW5kKSk7XG4gICAgICBjb25zdCBkZWxldGVkS2V5cyA9IChcbiAgICAgICAgRGVsZXRlSXRlbUNvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2tcbiAgICAgICkubW9jay5jYWxscy5tYXAoKFtpbnB1dF0pID0+IGlucHV0LktleS5zay5TKTtcbiAgICAgIGV4cGVjdChkZWxldGVkS2V5cykudG9FcXVhbChbXCJjdHgtdGFnI3Rlc3QtYnVpbGQtaWQvZmV0Y2gta2V5Lmpzb25cIl0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJkZWxldGVzIG5vIG1hcHBpbmcgcm93cyBmb3IgYW4gdW50YWdnZWQgZW50cnlcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgbW9ja1MzU2VuZC5tb2NrSW1wbGVtZW50YXRpb24oKGNvbW1hbmQ6IHVua25vd24pID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZShcbiAgICAgICAgICBjb21tYW5kIGluc3RhbmNlb2YgR2V0T2JqZWN0Q29tbWFuZFxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgQm9keToge1xuICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtVG9TdHJpbmc6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShcbiAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICAgIGxhc3RNb2RpZmllZDogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogeyBraW5kOiBDYWNoZWRSb3V0ZUtpbmQuQVBQX1BBR0UsIGh0bWw6IFwiPHAvPlwiIH0sXG4gICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIENvbnRlbnRUeXBlOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7fSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXIuc2V0KFwiL3VudGFnZ2VkXCIsIG51bGwsIHsgaXNGYWxsYmFjazogZmFsc2UgfSk7XG5cbiAgICAgIGV4cGVjdChtb2NrUzNTZW5kKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3QuYW55KERlbGV0ZU9iamVjdENvbW1hbmQpKTtcbiAgICAgIGV4cGVjdChEZWxldGVJdGVtQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KFwic3RpbGwgZGVsZXRlcyB0aGUgb2JqZWN0IHdoZW4gaXRzIHRhZ3MgY2Fubm90IGJlIHJlYWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgbW9ja1MzU2VuZC5tb2NrSW1wbGVtZW50YXRpb24oKGNvbW1hbmQ6IHVua25vd24pID0+XG4gICAgICAgIGNvbW1hbmQgaW5zdGFuY2VvZiBHZXRPYmplY3RDb21tYW5kXG4gICAgICAgICAgPyBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoXCJTMyBHZXQgRXJyb3JcIikpXG4gICAgICAgICAgOiBQcm9taXNlLnJlc29sdmUoe30pLFxuICAgICAgKTtcbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgZXhwZWN0KFxuICAgICAgICBoYW5kbGVyLnNldChcIi9pc3IvMVwiLCBudWxsLCB7IGlzRmFsbGJhY2s6IGZhbHNlIH0pLFxuICAgICAgKS5yZXNvbHZlcy5ub3QudG9UaHJvdygpO1xuXG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LmFueShEZWxldGVPYmplY3RDb21tYW5kKSk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCBoYW5kbGUgUzMgZXJyb3JzIGdyYWNlZnVsbHlcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdERhdGE6IEluY3JlbWVudGFsQ2FjaGVWYWx1ZSA9IHtcbiAgICAgICAga2luZDogQ2FjaGVkUm91dGVLaW5kLkFQUF9QQUdFLFxuICAgICAgICBodG1sOiBcIjxodG1sPmVycm9yIHRlc3Q8L2h0bWw+XCIsXG4gICAgICAgIHJzY0RhdGE6IHVuZGVmaW5lZCxcbiAgICAgICAgaGVhZGVyczogdW5kZWZpbmVkLFxuICAgICAgICBwb3N0cG9uZWQ6IHVuZGVmaW5lZCxcbiAgICAgICAgc2VnbWVudERhdGE6IHVuZGVmaW5lZCxcbiAgICAgICAgc3RhdHVzOiB1bmRlZmluZWQsXG4gICAgICB9O1xuXG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZWplY3RlZFZhbHVlT25jZShuZXcgRXJyb3IoXCJTMyBQdXQgRXJyb3JcIikpO1xuXG4gICAgICAvLyBTaG91bGQgbm90IHRocm93XG4gICAgICBhd2FpdCBleHBlY3QoXG4gICAgICAgIGhhbmRsZXIuc2V0KFwiZXJyb3Ita2V5XCIsIHRlc3REYXRhLCBjcmVhdGVTZXRDb250ZXh0KFtdKSksXG4gICAgICApLnJlc29sdmVzLm5vdC50b1Rocm93KCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKFwicmV2YWxpZGF0ZVRhZ1wiLCAoKSA9PiB7XG4gICAgaXQoXCJzaG91bGQgcmVjb3JkIHRoZSByZXZhbGlkYXRpb24gd2l0aG91dCBkZWxldGluZyB0aGUgdGFnJ3MgUzMgZW50cmllc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBtb2NrUXVlcnlSZXNwb25zZSA9IHtcbiAgICAgICAgSXRlbXM6IFtcbiAgICAgICAgICB7IHNrOiB7IFM6IFwidGVzdC10YWcjY2FjaGUta2V5LTFcIiB9IH0sXG4gICAgICAgICAgeyBzazogeyBTOiBcInRlc3QtdGFnI2NhY2hlLWtleS0yXCIgfSB9LFxuICAgICAgICBdLFxuICAgICAgfTtcblxuICAgICAgZHluYW1vUmVzcG9uc2VzKHsgcXVlcnk6IG1vY2tRdWVyeVJlc3BvbnNlIH0pO1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXIucmV2YWxpZGF0ZVRhZyhcInRlc3QtdGFnXCIpO1xuXG4gICAgICAvLyBObyBkaXN0cmlidXRpb24sIHNvIG5vIG1hcHBpbmcgcm93cyB0byByZWFkOiB0aGUgbWFya2VyIGlzIGFsbCBvZiBpdC5cbiAgICAgIGV4cGVjdChtb2NrRHluYW1vU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5hbnkoUXVlcnlDb21tYW5kKSk7XG4gICAgICBleHBlY3QobW9ja0R5bmFtb1NlbmQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBleHBlY3QuYW55KFVwZGF0ZUl0ZW1Db21tYW5kKSxcbiAgICAgICk7XG4gICAgICAvLyBUaGUgbWFya2VyIHJvdyBpcyB0aGUgaW52YWxpZGF0aW9uOyBgZ2V0YCByZWFkcyBpdCBhbmQgaGFuZHMgdGhlIGVudHJ5XG4gICAgICAvLyBiYWNrIGV4cGlyZWQgc28gTmV4dC5qcyByZS1yZW5kZXJzIHRoZSByb3V0ZSBhbmQgcmVwbGFjZXMgdGhlIG9iamVjdC5cbiAgICAgIC8vIERlbGV0aW5nIHRoZSBvYmplY3RzIGhlcmUgbWFkZSB0aGUgbmV4dCByZXF1ZXN0IGEgaGFyZCBtaXNzLCB3aGljaCBvbiBhXG4gICAgICAvLyBQUFIgcm91dGUgaXMgYW5zd2VyZWQgZnJvbSB0aGUgdW5jYWNoZWFibGUgZmFsbGJhY2sgc2hlbGwgZm9yIGdvb2QuXG4gICAgICBleHBlY3QobW9ja1MzU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBleHBlY3QuYW55KERlbGV0ZU9iamVjdENvbW1hbmQpLFxuICAgICAgKTtcblxuICAgICAgLy8gVGhlIHRhZyBtYXJrZXIgYGNoZWNrSWZSZXZhbGlkYXRlZGAgcmVhZHM6IGtleWVkIGJ5IHRoZSBiYXJlIHRhZywgc29cbiAgICAgIC8vIGVudHJpZXMgd2l0aCBubyBtYXBwaW5nIHJvdyBvZiB0aGVpciBvd24gc3RpbGwgc2VlIHRoZSByZXZhbGlkYXRpb24uXG4gICAgICBjb25zdCBtYXJrZXJXcml0ZSA9IChVcGRhdGVJdGVtQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubW9jay5jYWxsc1xuICAgICAgICAubWFwKChbaW5wdXRdKSA9PiBpbnB1dClcbiAgICAgICAgLmZpbmQoKGlucHV0KSA9PiBpbnB1dC5LZXkuc2suUyA9PT0gXCJ0ZXN0LXRhZ1wiKTtcbiAgICAgIGV4cGVjdChtYXJrZXJXcml0ZSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgIFVwZGF0ZUV4cHJlc3Npb246IFwiU0VUIHJldmFsaWRhdGVkQXQgPSA6cmV2YWxpZGF0ZWRBdFwiLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCBub3QgcmV2YWxpZGF0ZSB3aGVuIER5bmFtb0RCIHRhYmxlIGlzIG5vdCBjb25maWd1cmVkXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5DREtfTkVYVEpTX1JFVkFMSURBVElPTl9UQUJMRV9OQU1FO1xuXG4gICAgICBjb25zdCBoYW5kbGVyV2l0aG91dFRhYmxlID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgICB9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlcldpdGhvdXRUYWJsZS5yZXZhbGlkYXRlVGFnKFwidGVzdC10YWdcIik7XG5cbiAgICAgIGV4cGVjdChtb2NrRHluYW1vU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBEeW5hbW9EQiBlcnJvcnMgZ3JhY2VmdWxseVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwiRHluYW1vREIgRXJyb3JcIikpO1xuXG4gICAgICAvLyBTaG91bGQgbm90IHRocm93XG4gICAgICBhd2FpdCBleHBlY3QoaGFuZGxlci5yZXZhbGlkYXRlVGFnKFwiZXJyb3ItdGFnXCIpKS5yZXNvbHZlcy5ub3QudG9UaHJvdygpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgY3JlYXRlIGEgQ2xvdWRGcm9udCBpbnZhbGlkYXRpb24gZm9yIGFmZmVjdGVkIHBhdGhzIHdoZW4gYSBkaXN0cmlidXRpb24gcGFyYW1ldGVyIGlzIGNvbmZpZ3VyZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwidGVzdC1wYXJhbS1uYW1lXCI7XG4gICAgICBjb25zdCBoYW5kbGVyV2l0aERpc3RyaWJ1dGlvbiA9IG5ldyBTM0NhY2hlSGFuZGxlcih7XG4gICAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IG1vY2tRdWVyeVJlc3BvbnNlID0ge1xuICAgICAgICBJdGVtczogW1xuICAgICAgICAgIHsgc2s6IHsgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkL2lzci8xLmpzb25cIiB9IH0sXG4gICAgICAgICAgeyBzazogeyBTOiBcInRlc3QtdGFnI3Rlc3QtYnVpbGQtaWQvaXNyLzIuanNvblwiIH0gfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7IHF1ZXJ5OiBtb2NrUXVlcnlSZXNwb25zZSB9KTtcbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pOyAvLyBGb3IgZGVsZXRlIGNvbW1hbmRzXG4gICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIFBhcmFtZXRlcjogeyBWYWx1ZTogXCJ0ZXN0LWRpc3RyaWJ1dGlvbi1pZFwiIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKTtcblxuICAgICAgZXhwZWN0KG1vY2tTc21TZW5kKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3QuYW55KE9iamVjdCkpO1xuICAgICAgZXhwZWN0KG1vY2tDbG91ZEZyb250U2VuZCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICAgIGV4cGVjdC5hbnkoQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCksXG4gICAgICApO1xuICAgICAgY29uc3QgW2ludmFsaWRhdGlvbklucHV0XSA9IChcbiAgICAgICAgQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9ja1xuICAgICAgKS5tb2NrLmNhbGxzWzBdO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbklucHV0LkRpc3RyaWJ1dGlvbklkKS50b0JlKFwidGVzdC1kaXN0cmlidXRpb24taWRcIik7XG4gICAgICAvLyBPbmUgdHJhaWxpbmcgd2lsZGNhcmQgcGVyIHBhZ2U6IGFuIGludmFsaWRhdGlvbiBwYXRoIG1hdGNoZXMgb25seSB0aGVcbiAgICAgIC8vIHF1ZXJ5IHN0cmluZyBpdCBzcGVsbHMgb3V0LCBhbmQgYSBwYWdlJ3MgUlNDIHBheWxvYWQgaXMgY2FjaGVkIHVuZGVyXG4gICAgICAvLyBgP19yc2M9PGhhc2g+YCAtIGAvaXNyLzEqYCBjb3ZlcnMgaXQsIGFuZCB0aGUgc2xhc2ggdmFyaWFudCwgZm9yIG9uZVxuICAgICAgLy8gb2YgdGhlIGZpZnRlZW4gd2lsZGNhcmRzIGluc3RlYWQgb2YgdHdvLlxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbklucHV0LkludmFsaWRhdGlvbkJhdGNoLlBhdGhzLkl0ZW1zKS50b0VxdWFsKFtcbiAgICAgICAgXCIvaXNyLzEqXCIsXG4gICAgICAgIFwiL2lzci8yKlwiLFxuICAgICAgXSk7XG4gICAgfSk7XG5cbiAgICBpdChcImludmFsaWRhdGVzIGEgZGlzdHJpYnV0aW9uIHdob3NlIElEIGlzIGluIHRoZSBlbnZpcm9ubWVudCB3aXRob3V0IFNTTVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBOZXh0anNHbG9iYWxDb250YWluZXJzOiB0aGUgdGFzayBjYW4gbmFtZSB0aGUgZGlzdHJpYnV0aW9uIGRpcmVjdGx5LlxuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSUQgPSBcImRpcmVjdC1kaXN0cmlidXRpb24taWRcIjtcbiAgICAgIGNvbnN0IGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgICB9KTtcbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7XG4gICAgICAgIHF1ZXJ5OiB7IEl0ZW1zOiBbeyBzazogeyBTOiBcInRlc3QtdGFnI3Rlc3QtYnVpbGQtaWQvaXNyLzEuanNvblwiIH0gfV0gfSxcbiAgICAgIH0pO1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG4gICAgICBtb2NrQ2xvdWRGcm9udFNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuXG4gICAgICBhd2FpdCBoYW5kbGVyV2l0aERpc3RyaWJ1dGlvbi5yZXZhbGlkYXRlVGFnKFwidGVzdC10YWdcIik7XG5cbiAgICAgIGV4cGVjdChtb2NrU3NtU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICAgIGNvbnN0IFtpbnZhbGlkYXRpb25JbnB1dF0gPSAoXG4gICAgICAgIENyZWF0ZUludmFsaWRhdGlvbkNvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2tcbiAgICAgICkubW9jay5jYWxsc1swXTtcbiAgICAgIGV4cGVjdChpbnZhbGlkYXRpb25JbnB1dC5EaXN0cmlidXRpb25JZCkudG9CZShcImRpcmVjdC1kaXN0cmlidXRpb24taWRcIik7XG4gICAgfSk7XG5cbiAgICBpdChcInNwbGl0cyBhIG1hcHBpbmcgcm93IGF0IHRoZSB0YWcncyBsZW5ndGgsIHNvIGEgdGFnIGNvbnRhaW5pbmcgIyBzdGlsbCByZXNvbHZlc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBBIHRhZyBpcyBhcHAtZGVmaW5lZDogYHJldmFsaWRhdGVUYWcoXCJ1c2VyIzQyXCIpYCBpcyBsZWdhbC4gU3BsaXR0aW5nIGF0XG4gICAgICAvLyB0aGUgZmlyc3QgXCIjXCIgbGVmdCBcIjQyI3Rlc3QtYnVpbGQtaWQvYWNjb3VudC5qc29uXCIgYXMgdGhlIFMzIGtleSwgd2hvc2VcbiAgICAgIC8vIGludmFsaWRhdGlvbiBwYXRoIG5hbWVzIG5vdGhpbmcgQ2xvdWRGcm9udCBjYWNoZWQsIHNvIHRoZSBwYWdlIHN0YXllZFxuICAgICAgLy8gc3RhbGUgd2hpbGUgdGhlIHJvdyB3YXMgc3RhbXBlZCByZXZhbGlkYXRlZCBhbmQgbmV2ZXIgcmV0cmllZC5cbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgY29uc3QgaGFuZGxlcldpdGhEaXN0cmlidXRpb24gPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgICBjb250ZXh0OiBtb2NrQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgICBkeW5hbW9SZXNwb25zZXMoe1xuICAgICAgICBxdWVyeTogeyBJdGVtczogW3sgc2s6IHsgUzogXCJ1c2VyIzQyI3Rlc3QtYnVpbGQtaWQvYWNjb3VudC5qc29uXCIgfSB9XSB9LFxuICAgICAgfSk7XG4gICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIFBhcmFtZXRlcjogeyBWYWx1ZTogXCJ0ZXN0LWRpc3RyaWJ1dGlvbi1pZFwiIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uLnJldmFsaWRhdGVUYWcoXCJ1c2VyIzQyXCIpO1xuXG4gICAgICBjb25zdCBbaW52YWxpZGF0aW9uSW5wdXRdID0gKFxuICAgICAgICBDcmVhdGVJbnZhbGlkYXRpb25Db21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrXG4gICAgICApLm1vY2suY2FsbHNbMF07XG4gICAgICBleHBlY3QoaW52YWxpZGF0aW9uSW5wdXQuSW52YWxpZGF0aW9uQmF0Y2guUGF0aHMuSXRlbXMpLnRvRXF1YWwoW1xuICAgICAgICBcIi9hY2NvdW50KlwiLFxuICAgICAgXSk7XG4gICAgfSk7XG5cbiAgICBpdChcImludmFsaWRhdGVzIHRoZSBwYXRoIGEgcmV2YWxpZGF0ZVBhdGggdGFnIG5hbWVzIGV2ZW4gd2l0aCBubyBtYXBwaW5nIHJvd3NcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gQSBidWlsZC10aW1lIHByZXJlbmRlciBoYXMgbm8gbWFwcGluZyByb3dzLCBzbyB0aGUgcXVlcnkgY29tZXMgYmFja1xuICAgICAgLy8gZW1wdHkgYW5kIHRoZXJlIGlzIG5vdGhpbmcgdG8gZGVyaXZlIGEgQ2xvdWRGcm9udCBwYXRoIGZyb20gLSBleGNlcHQgdGhlXG4gICAgICAvLyB0YWcsIHdoaWNoIGZvciBgcmV2YWxpZGF0ZVBhdGhgIGlzIGBfTl9UXzxwYXRoPmAuIFdpdGhvdXQgdGhpcyB0aGUgQ0ROXG4gICAgICAvLyBhbnN3ZXJzIHdpdGggdGhlIHByZS1yZXZhbGlkYXRpb24gcGFnZSB1bnRpbCBgcy1tYXhhZ2U9MzE1MzYwMDBgXG4gICAgICAvLyBleHBpcmVzLiBNZWFzdXJlZCBhZ2FpbnN0IG5leHQuanMncyBgdGVzdC9lMmUvYXBwLWRpci90cmFpbGluZ3NsYXNoYC5cbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgY29uc3QgaGFuZGxlcldpdGhEaXN0cmlidXRpb24gPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgICBjb250ZXh0OiBtb2NrQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgICBkeW5hbW9SZXNwb25zZXMoeyBxdWVyeTogeyBJdGVtczogW10gfSB9KTtcbiAgICAgIG1vY2tTc21TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgICAgUGFyYW1ldGVyOiB7IFZhbHVlOiBcInRlc3QtZGlzdHJpYnV0aW9uLWlkXCIgfSxcbiAgICAgIH0pO1xuICAgICAgbW9ja0Nsb3VkRnJvbnRTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlcldpdGhEaXN0cmlidXRpb24ucmV2YWxpZGF0ZVRhZyhcIl9OX1RfL2VuL2xlZ2FjeS9cIik7XG5cbiAgICAgIGNvbnN0IFtpbnZhbGlkYXRpb25JbnB1dF0gPSAoXG4gICAgICAgIENyZWF0ZUludmFsaWRhdGlvbkNvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2tcbiAgICAgICkubW9jay5jYWxsc1swXTtcbiAgICAgIC8vIEJvdGggc2xhc2ggdmFyaWFudHMsIHdoaWNoIHRoZSB0cmFpbGluZyB3aWxkY2FyZCBjb3ZlcnM6IGFcbiAgICAgIC8vIGB0cmFpbGluZ1NsYXNoYCBhcHAncyBjYWNoZWQgVVJJIGlzIHRoZSByZWRpcmVjdCB0YXJnZXQsIG5vdCB0aGUgcm91dGUuXG4gICAgICBleHBlY3QoaW52YWxpZGF0aW9uSW5wdXQuSW52YWxpZGF0aW9uQmF0Y2guUGF0aHMuSXRlbXMpLnRvRXF1YWwoW1xuICAgICAgICBcIi9lbi9sZWdhY3kqXCIsXG4gICAgICBdKTtcbiAgICB9KTtcblxuICAgIGl0KFwiaW52YWxpZGF0ZXMgdGhlIFVSSSB1bmRlciB0aGUgYXBwJ3MgYmFzZVBhdGgsIG5vdCB0aGUgYmFyZSByb3V0ZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBDbG91ZEZyb250IGNhY2hlZCBgL2Jhc2UvaXNyLzFgOyB0aGUgY2FjaGUga2V5IGFuZCB0aGUgYHJldmFsaWRhdGVQYXRoYFxuICAgICAgLy8gdGFnIGJvdGggbmFtZSBgL2lzci8xYCwgYmVjYXVzZSBOZXh0LmpzIHN0cmlwcyBgYmFzZVBhdGhgIGJlZm9yZSByb3V0aW5nXG4gICAgICAvLyBhbmQgbmV2ZXIgc2hvd3MgaXQgdG8gdGhlIGNhY2hlIGhhbmRsZXIuIEludmFsaWRhdGluZyB0aGUgYmFyZSByb3V0ZVxuICAgICAgLy8gbWF0Y2hlcyBub3RoaW5nIGF0IHRoZSBlZGdlLCBzbyB0aGUgc3RhbGUgcGFnZSBzdXJ2aXZlcyB1bnRpbFxuICAgICAgLy8gYHMtbWF4YWdlYCBleHBpcmVzLlxuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwidGVzdC1wYXJhbS1uYW1lXCI7XG4gICAgICB1c2VCYXNlUGF0aCgpO1xuICAgICAgY29uc3QgaGFuZGxlcldpdGhCYXNlUGF0aCA9IG5ldyBTM0NhY2hlSGFuZGxlcih7XG4gICAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgICAgfSk7XG5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7XG4gICAgICAgIHF1ZXJ5OiB7XG4gICAgICAgICAgSXRlbXM6IFtcbiAgICAgICAgICAgIHsgc2s6IHsgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkL2lzci8xLmpzb25cIiB9IH0sXG4gICAgICAgICAgICB7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9pbmRleC5qc29uXCIgfSB9LFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuICAgICAgbW9ja1NzbVNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgICBQYXJhbWV0ZXI6IHsgVmFsdWU6IFwidGVzdC1kaXN0cmlidXRpb24taWRcIiB9LFxuICAgICAgfSk7XG4gICAgICBtb2NrQ2xvdWRGcm9udFNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuXG4gICAgICBhd2FpdCBoYW5kbGVyV2l0aEJhc2VQYXRoLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKTtcblxuICAgICAgY29uc3QgW2ludmFsaWRhdGlvbklucHV0XSA9IChcbiAgICAgICAgQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9ja1xuICAgICAgKS5tb2NrLmNhbGxzWzBdO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbklucHV0LkludmFsaWRhdGlvbkJhdGNoLlBhdGhzLkl0ZW1zKS50b0VxdWFsKFxuICAgICAgICBleHBlY3QuYXJyYXlDb250YWluaW5nKFtcbiAgICAgICAgICBcIi9iYXNlL2lzci8xKlwiLFxuICAgICAgICAgIC8vIFRoZSBhcHAncyByb290IHVuZGVyIGEgYGJhc2VQYXRoYCBpcyBgL2Jhc2VgLCBub3QgYC9iYXNlL2AsIGFuZFxuICAgICAgICAgIC8vIHNwZWxsZWQgb3V0OiBgL2Jhc2UqYCB3b3VsZCBiZSB0aGUgd2hvbGUgYXBwLlxuICAgICAgICAgIFwiL2Jhc2VcIixcbiAgICAgICAgICBcIi9iYXNlPypcIixcbiAgICAgICAgICBcIi9iYXNlL1wiLFxuICAgICAgICAgIFwiL2Jhc2UvPypcIixcbiAgICAgICAgXSksXG4gICAgICApO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbklucHV0LkludmFsaWRhdGlvbkJhdGNoLlBhdGhzLkl0ZW1zKS5ub3QudG9Db250YWluKFxuICAgICAgICBcIi9pc3IvMVwiLFxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KFwiYWRkcyB0aGUgYmFzZVBhdGggdG8gYSByZXZhbGlkYXRlUGF0aCB0YWcncyBwYXRoIHRvb1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0RJU1RSSUJVVElPTl9JRF9QQVJBTV9OQU1FID0gXCJ0ZXN0LXBhcmFtLW5hbWVcIjtcbiAgICAgIHVzZUJhc2VQYXRoKCk7XG4gICAgICBjb25zdCBoYW5kbGVyV2l0aEJhc2VQYXRoID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgICB9KTtcblxuICAgICAgZHluYW1vUmVzcG9uc2VzKHsgcXVlcnk6IHsgSXRlbXM6IFtdIH0gfSk7XG4gICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIFBhcmFtZXRlcjogeyBWYWx1ZTogXCJ0ZXN0LWRpc3RyaWJ1dGlvbi1pZFwiIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXJXaXRoQmFzZVBhdGgucmV2YWxpZGF0ZVRhZyhcIl9OX1RfL2Jsb2dcIik7XG5cbiAgICAgIGNvbnN0IFtpbnZhbGlkYXRpb25JbnB1dF0gPSAoXG4gICAgICAgIENyZWF0ZUludmFsaWRhdGlvbkNvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2tcbiAgICAgICkubW9jay5jYWxsc1swXTtcbiAgICAgIGV4cGVjdChpbnZhbGlkYXRpb25JbnB1dC5JbnZhbGlkYXRpb25CYXRjaC5QYXRocy5JdGVtcykudG9FcXVhbChbXG4gICAgICAgIFwiL2Jhc2UvYmxvZypcIixcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJkb2VzIG5vdCBpbnZhbGlkYXRlIGEgQ2xvdWRGcm9udCBwYXRoIGZvciBhbiBhcHAgdGFnXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgY29uc3QgaGFuZGxlcldpdGhEaXN0cmlidXRpb24gPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgICBjb250ZXh0OiBtb2NrQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgICBkeW5hbW9SZXNwb25zZXMoeyBxdWVyeTogeyBJdGVtczogW10gfSB9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlcldpdGhEaXN0cmlidXRpb24ucmV2YWxpZGF0ZVRhZyhcInBvc3RzXCIpO1xuXG4gICAgICAvLyBOb3RoaW5nIHRvIGludmFsaWRhdGU6IGFuIGFwcCB0YWcgbmFtZXMgbm8gcGF0aCwgYW5kIG5vIGVudHJ5IGlzIG1hcHBlZFxuICAgICAgLy8gdG8gaXQuXG4gICAgICBleHBlY3QobW9ja0Nsb3VkRnJvbnRTZW5kKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzaG91bGQgbm90IGNhbGwgU1NNIG9yIENsb3VkRnJvbnQgd2hlbiBubyBkaXN0cmlidXRpb24gcGFyYW1ldGVyIGlzIGNvbmZpZ3VyZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1F1ZXJ5UmVzcG9uc2UgPSB7XG4gICAgICAgIEl0ZW1zOiBbeyBzazogeyBTOiBcInRlc3QtdGFnI3Rlc3QtYnVpbGQtaWQvaXNyLzEuanNvblwiIH0gfV0sXG4gICAgICB9O1xuXG4gICAgICBkeW5hbW9SZXNwb25zZXMoeyBxdWVyeTogbW9ja1F1ZXJ5UmVzcG9uc2UgfSk7XG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlci5yZXZhbGlkYXRlVGFnKFwidGVzdC10YWdcIik7XG5cbiAgICAgIGV4cGVjdChtb2NrU3NtU2VuZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICAgIGV4cGVjdChtb2NrQ2xvdWRGcm9udFNlbmQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgfSk7XG5cbiAgICBpdChcInNob3VsZCBoYW5kbGUgU1NNL0Nsb3VkRnJvbnQgaW52YWxpZGF0aW9uIGVycm9ycyBncmFjZWZ1bGx5XCIsIGFzeW5jICgpID0+IHtcbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgY29uc3QgaGFuZGxlcldpdGhEaXN0cmlidXRpb24gPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgICBjb250ZXh0OiBtb2NrQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBtb2NrUXVlcnlSZXNwb25zZSA9IHtcbiAgICAgICAgSXRlbXM6IFt7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9pc3IvMS5qc29uXCIgfSB9XSxcbiAgICAgIH07XG5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7IHF1ZXJ5OiBtb2NrUXVlcnlSZXNwb25zZSB9KTtcbiAgICAgIG1vY2tTM1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuICAgICAgbW9ja1NzbVNlbmQubW9ja1JlamVjdGVkVmFsdWVPbmNlKG5ldyBFcnJvcihcIlNTTSBFcnJvclwiKSk7XG5cbiAgICAgIGF3YWl0IGV4cGVjdChcbiAgICAgICAgaGFuZGxlcldpdGhEaXN0cmlidXRpb24ucmV2YWxpZGF0ZVRhZyhcInRlc3QtdGFnXCIpLFxuICAgICAgKS5yZXNvbHZlcy5ub3QudG9UaHJvdygpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJpbnZhbGlkYXRlcyB0aGUgcGFnZSBpdHNlbGYgZm9yIGEgcmV2YWxpZGF0ZVBhdGgocGF0aCwgJ3BhZ2UnKSB0YWdcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gYHJldmFsaWRhdGVQYXRoKHBhdGgsIHR5cGUpYCBhcHBlbmRzIHRoZSB0eXBlIHRvIHRoZSBpbXBsaWNpdCB0YWcsIHNvIHRoZVxuICAgICAgLy8gdGFnIHJlYWRzIGBfTl9UXy9wcmljaW5nL3BhZ2VgIC0gYSBwYXRoIG5vIFVSTCBoYXMuIFRha2luZyBpdCBsaXRlcmFsbHlcbiAgICAgIC8vIGludmFsaWRhdGVkIG5vdGhpbmcgdGhhdCBleGlzdGVkLCB3aGljaCBpcyB0aGUgd2hvbGUgb2YgdGhlIGJ1ZzogdGhlXG4gICAgICAvLyBzZWNvbmQgYXJndW1lbnQgc2lsZW50bHkgdHVybmVkIENETiBpbnZhbGlkYXRpb24gb2ZmLlxuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwidGVzdC1wYXJhbS1uYW1lXCI7XG4gICAgICBjb25zdCBoYW5kbGVyV2l0aERpc3RyaWJ1dGlvbiA9IG5ldyBTM0NhY2hlSGFuZGxlcih7XG4gICAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgICAgfSk7XG5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7IHF1ZXJ5OiB7IEl0ZW1zOiBbXSB9IH0pO1xuICAgICAgbW9ja1NzbVNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgICBQYXJhbWV0ZXI6IHsgVmFsdWU6IFwidGVzdC1kaXN0cmlidXRpb24taWRcIiB9LFxuICAgICAgfSk7XG4gICAgICBtb2NrQ2xvdWRGcm9udFNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuXG4gICAgICBhd2FpdCBoYW5kbGVyV2l0aERpc3RyaWJ1dGlvbi5yZXZhbGlkYXRlVGFnKFwiX05fVF8vcHJpY2luZy9wYWdlXCIpO1xuXG4gICAgICBjb25zdCBbaW52YWxpZGF0aW9uSW5wdXRdID0gKFxuICAgICAgICBDcmVhdGVJbnZhbGlkYXRpb25Db21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrXG4gICAgICApLm1vY2suY2FsbHNbMF07XG4gICAgICBleHBlY3QoaW52YWxpZGF0aW9uSW5wdXQuSW52YWxpZGF0aW9uQmF0Y2guUGF0aHMuSXRlbXMpLnRvRXF1YWwoXG4gICAgICAgIGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW1wiL3ByaWNpbmcqXCJdKSxcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBpdChcInNraXBzIG1hcHBpbmcgcm93cyB0aGF0IG5hbWUgbm8gY2FjaGVkIFVSSVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBBIGR5bmFtaWMgdGVtcGxhdGUgYW5kIGEgZmV0Y2gtY2FjaGUgZW50cnkgYXJlIGJvdGggcm93cyBhIHJlYWwgdGFnXG4gICAgICAvLyBjYXJyaWVzLCBhbmQgbmVpdGhlciBpcyBhIFVSTDogYC9ibG9nL1tzbHVnXWAgbWF0Y2hlcyBub3RoaW5nIGF0IHRoZSBlZGdlXG4gICAgICAvLyAoQ2xvdWRGcm9udCBoYXMgbm8gc3VjaCBVUkkpLCBhbmQgYSBmZXRjaCBrZXkgaXMgYSBoYXNoIG9mIHRoZSByZXF1ZXN0LlxuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwidGVzdC1wYXJhbS1uYW1lXCI7XG4gICAgICBjb25zdCBoYW5kbGVyV2l0aERpc3RyaWJ1dGlvbiA9IG5ldyBTM0NhY2hlSGFuZGxlcih7XG4gICAgICAgIGNvbnRleHQ6IG1vY2tDb250ZXh0LFxuICAgICAgfSk7XG5cbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7XG4gICAgICAgIHF1ZXJ5OiB7XG4gICAgICAgICAgSXRlbXM6IFtcbiAgICAgICAgICAgIHsgc2s6IHsgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkL2Jsb2cvW3NsdWddLmpzb25cIiB9IH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHNrOiB7XG4gICAgICAgICAgICAgICAgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkLzAxMjM0NTY3ODlhYmNkZWYwMTIzNDU2Nzg5YWJjZGVmLmpzb25cIixcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9ibG9nL2hlbGxvLmpzb25cIiB9IH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG4gICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIFBhcmFtZXRlcjogeyBWYWx1ZTogXCJ0ZXN0LWRpc3RyaWJ1dGlvbi1pZFwiIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKTtcblxuICAgICAgY29uc3QgW2ludmFsaWRhdGlvbklucHV0XSA9IChcbiAgICAgICAgQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9ja1xuICAgICAgKS5tb2NrLmNhbGxzWzBdO1xuICAgICAgY29uc3QgaXRlbXM6IHN0cmluZ1tdID0gaW52YWxpZGF0aW9uSW5wdXQuSW52YWxpZGF0aW9uQmF0Y2guUGF0aHMuSXRlbXM7XG4gICAgICBleHBlY3QoaXRlbXMpLnRvRXF1YWwoW1wiL2Jsb2cvaGVsbG8qXCJdKTtcbiAgICAgIGV4cGVjdChpdGVtcy5zb21lKChwYXRoKSA9PiBwYXRoLmluY2x1ZGVzKFwiW1wiKSkpLnRvQmUoZmFsc2UpO1xuICAgICAgZXhwZWN0KGl0ZW1zLnNvbWUoKHBhdGgpID0+IHBhdGguaW5jbHVkZXMoXCIwMTIzNDU2Nzg5YWJjZGVmXCIpKSkudG9CZShcbiAgICAgICAgZmFsc2UsXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoXCJ3YWxrcyBldmVyeSBRdWVyeSBwYWdlIG9mIGEgdGFnJ3MgbWFwcGluZyByb3dzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIE9uZSBgUXVlcnlgIGFuc3dlcnMgd2l0aCBhdCBtb3N0IDEgTUIuIEEgdGFnIG9uIGEgbGFyZ2UgYXBwIHJ1bnMgcGFzdFxuICAgICAgLy8gdGhhdCwgYW5kIHRha2luZyBvbmx5IHRoZSBmaXJzdCBwYWdlIGRlbGV0ZWQgc29tZSBvZiB0aGUgdGFnJ3MgZW50cmllc1xuICAgICAgLy8gYW5kIGludmFsaWRhdGVkIG9ubHkgc29tZSBvZiBpdHMgcGF0aHMgLSBhIHBhcnRpYWwgcmV2YWxpZGF0aW9uIHRoYXRcbiAgICAgIC8vIGxvb2tzIGxpa2UgYSBjYWNoZSBidWcuXG4gICAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0RJU1RSSUJVVElPTl9JRF9QQVJBTV9OQU1FID0gXCJ0ZXN0LXBhcmFtLW5hbWVcIjtcbiAgICAgIGNvbnN0IGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uID0gbmV3IFMzQ2FjaGVIYW5kbGVyKHtcbiAgICAgICAgY29udGV4dDogbW9ja0NvbnRleHQsXG4gICAgICB9KTtcblxuICAgICAgbGV0IHF1ZXJpZXMgPSAwO1xuICAgICAgbW9ja0R5bmFtb1NlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PiB7XG4gICAgICAgIGlmIChjb21tYW5kIGluc3RhbmNlb2YgUXVlcnlDb21tYW5kKSB7XG4gICAgICAgICAgcXVlcmllcysrO1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoXG4gICAgICAgICAgICBxdWVyaWVzID09PSAxXG4gICAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgICAgSXRlbXM6IFt7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9pc3IvMS5qc29uXCIgfSB9XSxcbiAgICAgICAgICAgICAgICAgIExhc3RFdmFsdWF0ZWRLZXk6IHsgcGs6IHsgUzogXCJ0ZXN0LWJ1aWxkLWlkXCIgfSB9LFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgOiB7IEl0ZW1zOiBbeyBzazogeyBTOiBcInRlc3QtdGFnI3Rlc3QtYnVpbGQtaWQvaXNyLzIuanNvblwiIH0gfV0gfSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe30pO1xuICAgICAgfSk7XG4gICAgICBtb2NrUzNTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcbiAgICAgIG1vY2tTc21TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgICAgUGFyYW1ldGVyOiB7IFZhbHVlOiBcInRlc3QtZGlzdHJpYnV0aW9uLWlkXCIgfSxcbiAgICAgIH0pO1xuICAgICAgbW9ja0Nsb3VkRnJvbnRTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgaGFuZGxlcldpdGhEaXN0cmlidXRpb24ucmV2YWxpZGF0ZVRhZyhcInRlc3QtdGFnXCIpO1xuXG4gICAgICBleHBlY3QocXVlcmllcykudG9CZSgyKTtcbiAgICAgIGNvbnN0IFtpbnZhbGlkYXRpb25JbnB1dF0gPSAoXG4gICAgICAgIENyZWF0ZUludmFsaWRhdGlvbkNvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2tcbiAgICAgICkubW9jay5jYWxsc1swXTtcbiAgICAgIGV4cGVjdChpbnZhbGlkYXRpb25JbnB1dC5JbnZhbGlkYXRpb25CYXRjaC5QYXRocy5JdGVtcykudG9FcXVhbChbXG4gICAgICAgIFwiL2lzci8xKlwiLFxuICAgICAgICBcIi9pc3IvMipcIixcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJjb2xsYXBzZXMgdG8gb25lIGFwcC13aWRlIHdpbGRjYXJkIHJhdGhlciB0aGFuIHNlbmRpbmcgbWFueSBpbnZhbGlkYXRpb25zXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIENsb3VkRnJvbnQgY2FwcyBhIHJlcXVlc3QgYXQgMTUgd2lsZGNhcmQgcGF0aHMgYW5kIGFsbG93cyAxNVxuICAgICAgLy8gaW52YWxpZGF0aW9ucyBpbiBwcm9ncmVzcy4gQSB0YWcgY292ZXJpbmcgaHVuZHJlZHMgb2YgcGFnZXMgdGhlcmVmb3JlXG4gICAgICAvLyBjYW5ub3QgYmUgc3BlbGxlZCBvdXQ6IHNlbmRpbmcgYSByZXF1ZXN0IHBlciAxNSBwYXRocyB0aHJvdHRsZXMsIGFuZCBhXG4gICAgICAvLyB0aHJvdHRsZWQgcmVxdWVzdCBpcyBhIHBhZ2UgdGhhdCBzdGF5cyBzdGFsZS5cbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgY29uc3QgaGFuZGxlcldpdGhEaXN0cmlidXRpb24gPSBuZXcgUzNDYWNoZUhhbmRsZXIoe1xuICAgICAgICBjb250ZXh0OiBtb2NrQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgICBkeW5hbW9SZXNwb25zZXMoe1xuICAgICAgICBxdWVyeToge1xuICAgICAgICAgIEl0ZW1zOiBBcnJheS5mcm9tKHsgbGVuZ3RoOiAyMDAgfSwgKF8sIGkpID0+ICh7XG4gICAgICAgICAgICBzazogeyBTOiBgdGVzdC10YWcjdGVzdC1idWlsZC1pZC9pc3IvJHtpfS5qc29uYCB9LFxuICAgICAgICAgIH0pKSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG4gICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIFBhcmFtZXRlcjogeyBWYWx1ZTogXCJ0ZXN0LWRpc3RyaWJ1dGlvbi1pZFwiIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IGhhbmRsZXJXaXRoRGlzdHJpYnV0aW9uLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKTtcblxuICAgICAgZXhwZWN0KG1vY2tDbG91ZEZyb250U2VuZCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDEpO1xuICAgICAgY29uc3QgW2ludmFsaWRhdGlvbklucHV0XSA9IChcbiAgICAgICAgQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9ja1xuICAgICAgKS5tb2NrLmNhbGxzWzBdO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbklucHV0LkludmFsaWRhdGlvbkJhdGNoLlBhdGhzLkl0ZW1zKS50b0VxdWFsKFtcIi8qXCJdKTtcbiAgICB9KTtcblxuICAgIC8qKiBBIGhhbmRsZXIgd2l0aCBhIGRpc3RyaWJ1dGlvbiwgYW5kIER5bmFtb0RCIGFuc3dlcmluZyBgcXVlcnlgIGZvciBpdC4gKi9cbiAgICBjb25zdCB3aXRoRGlzdHJpYnV0aW9uID0gKHF1ZXJ5OiB1bmtub3duKSA9PiB7XG4gICAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0RJU1RSSUJVVElPTl9JRF9QQVJBTV9OQU1FID0gXCJ0ZXN0LXBhcmFtLW5hbWVcIjtcbiAgICAgIGR5bmFtb1Jlc3BvbnNlcyh7IHF1ZXJ5IH0pO1xuICAgICAgbW9ja1NzbVNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgICBQYXJhbWV0ZXI6IHsgVmFsdWU6IFwidGVzdC1kaXN0cmlidXRpb24taWRcIiB9LFxuICAgICAgfSk7XG4gICAgICBtb2NrQ2xvdWRGcm9udFNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuICAgICAgcmV0dXJuIG5ldyBTM0NhY2hlSGFuZGxlcih7IGNvbnRleHQ6IG1vY2tDb250ZXh0IH0pO1xuICAgIH07XG4gICAgY29uc3QgaW52YWxpZGF0aW9ucyA9ICgpOiBzdHJpbmdbXVtdID0+XG4gICAgICAoQ3JlYXRlSW52YWxpZGF0aW9uQ29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubW9jay5jYWxscy5tYXAoXG4gICAgICAgIChbaW5wdXRdKSA9PiBpbnB1dC5JbnZhbGlkYXRpb25CYXRjaC5QYXRocy5JdGVtcyxcbiAgICAgICk7XG4gICAgY29uc3QgcGFnZXMgPSAodGFnOiBzdHJpbmcsIGNvdW50OiBudW1iZXIpID0+ICh7XG4gICAgICBJdGVtczogQXJyYXkuZnJvbSh7IGxlbmd0aDogY291bnQgfSwgKF8sIGkpID0+ICh7XG4gICAgICAgIHNrOiB7IFM6IGAke3RhZ30jdGVzdC1idWlsZC1pZC9pc3IvJHtpfS5qc29uYCB9LFxuICAgICAgfSkpLFxuICAgIH0pO1xuXG4gICAgaXQoXCJzZW5kcyBhIHRhZydzIHBhdGhzIGFzIG9uZSByZXF1ZXN0IHdoaWxlIHRoZXkgZml0XCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIENsb3VkRnJvbnQncyB3aWxkY2FyZCBxdW90YSBpcyBzaGFyZWQgYnkgZXZlcnkgaW52YWxpZGF0aW9uIGluXG4gICAgICAvLyBwcm9ncmVzcyBvbiB0aGUgZGlzdHJpYnV0aW9uLiBTcGxpdHRpbmcgdGVuIHBhZ2VzJyB0d2VudHkgd2lsZGNhcmRzXG4gICAgICAvLyBpbnRvIHR3byBiYWNrLXRvLWJhY2sgcmVxdWVzdHMgaGFkIHRoZSBzZWNvbmQgcmVqZWN0ZWQsIGFuZCBpdHMgcGFnZXNcbiAgICAgIC8vIHN0YXllZCBzdGFsZSBhdCB0aGUgZWRnZS5cbiAgICAgIGF3YWl0IHdpdGhEaXN0cmlidXRpb24ocGFnZXMoXCJ0ZXN0LXRhZ1wiLCAxMCkpLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9IYXZlTGVuZ3RoKDEpO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKVswXSkudG9IYXZlTGVuZ3RoKDEwKTtcbiAgICB9KTtcblxuICAgIGl0KFwiY29sbGFwc2VzIHRvIHRoZSB3aG9sZSBhcHAgcGFzdCBmaWZ0ZWVuIHdpbGRjYXJkc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB3aXRoRGlzdHJpYnV0aW9uKHBhZ2VzKFwidGVzdC10YWdcIiwgMTYpKS5yZXZhbGlkYXRlVGFnKFwidGVzdC10YWdcIik7XG5cbiAgICAgIGV4cGVjdChpbnZhbGlkYXRpb25zKCkpLnRvRXF1YWwoW1tcIi8qXCJdXSk7XG4gICAgfSk7XG5cbiAgICBpdChcImNvbGxhcHNlcyB0byB0aGUgd2hvbGUgYXBwIHVuZGVyIGEgYmFzZVBhdGgsIGl0cyByb290IGluY2x1ZGVkXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIE5vdCBgL2Jhc2UqYCwgd2hpY2ggd291bGQgYWxzbyBpbnZhbGlkYXRlIGEgc2libGluZyBhcHAgYXQgYC9iYXNlMmAuXG4gICAgICB1c2VCYXNlUGF0aCgpO1xuICAgICAgYXdhaXQgd2l0aERpc3RyaWJ1dGlvbihwYWdlcyhcInRlc3QtdGFnXCIsIDE2KSkucmV2YWxpZGF0ZVRhZyhcInRlc3QtdGFnXCIpO1xuXG4gICAgICBleHBlY3QoaW52YWxpZGF0aW9ucygpKS50b0VxdWFsKFtbXCIvYmFzZVwiLCBcIi9iYXNlPypcIiwgXCIvYmFzZS8qXCJdXSk7XG4gICAgfSk7XG5cbiAgICBpdChcImludmFsaWRhdGVzIHRoZSB3aG9sZSBhcHAgdW5kZXIgYSBiYXNlUGF0aCB3aGVuIGEgdGFnJ3Mgcm93cyBjYW5ub3QgYmUgcmVhZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICB1c2VCYXNlUGF0aCgpO1xuICAgICAgamVzdC5zcHlPbihjb25zb2xlLCBcImVycm9yXCIpLm1vY2tJbXBsZW1lbnRhdGlvbigpO1xuICAgICAgY29uc3QgY2RuSGFuZGxlciA9IHdpdGhEaXN0cmlidXRpb24oeyBJdGVtczogW10gfSk7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrSW1wbGVtZW50YXRpb24oKGNvbW1hbmQ6IHVua25vd24pID0+XG4gICAgICAgIGNvbW1hbmQgaW5zdGFuY2VvZiBRdWVyeUNvbW1hbmRcbiAgICAgICAgICA/IFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIlByb3Zpc2lvbmVkVGhyb3VnaHB1dEV4Y2VlZGVkXCIpKVxuICAgICAgICAgIDogUHJvbWlzZS5yZXNvbHZlKHt9KSxcbiAgICAgICk7XG5cbiAgICAgIGF3YWl0IGNkbkhhbmRsZXIucmV2YWxpZGF0ZVRhZyhcInBvc3RzXCIpO1xuXG4gICAgICBleHBlY3QoaW52YWxpZGF0aW9ucygpKS50b0VxdWFsKFtbXCIvYmFzZVwiLCBcIi9iYXNlPypcIiwgXCIvYmFzZS8qXCJdXSk7XG4gICAgfSk7XG5cbiAgICBpdChcInBlcmNlbnQtZW5jb2RlcyB0aGUgcm91dGVzIGl0IGludmFsaWRhdGVzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIENhY2hlIGtleXMgYXJlIGRlY29kZWQgcGF0aG5hbWVzLCB3aGlsZSBDbG91ZEZyb250IGNhY2hlcyAtIGFuZFxuICAgICAgLy8gaW52YWxpZGF0aW9uIHBhdGhzIG1hdGNoIC0gdGhlIGVuY29kZWQgVVJJIHRoZSBicm93c2VyIHNlbnQuXG4gICAgICBhd2FpdCB3aXRoRGlzdHJpYnV0aW9uKHtcbiAgICAgICAgSXRlbXM6IFtcbiAgICAgICAgICB7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9ibG9nL2jDqWxsby5qc29uXCIgfSB9LFxuICAgICAgICAgIHsgc2s6IHsgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkL2Jsb2cvaGVsbG8gd29ybGQuanNvblwiIH0gfSxcbiAgICAgICAgICAvLyBQYXRoIGRlbGltaXRlcnMgTmV4dC5qcyByZS1lc2NhcGVkIGluIHRoZSBrZXkgc3RheSBhcyB0aGV5IGFyZS5cbiAgICAgICAgICB7IHNrOiB7IFM6IFwidGVzdC10YWcjdGVzdC1idWlsZC1pZC9maWxlcy9hJTJGYi5qc29uXCIgfSB9LFxuICAgICAgICAgIHsgc2s6IHsgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkL0B1c2VyLzUwJS5qc29uXCIgfSB9LFxuICAgICAgICBdLFxuICAgICAgfSkucmV2YWxpZGF0ZVRhZyhbXCJ0ZXN0LXRhZ1wiLCBcIl9OX1RfL3RhZ3MvYyM/XCJdKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbXG4gICAgICAgIFtcbiAgICAgICAgICBcIi9ibG9nL2glQzMlQTlsbG8qXCIsXG4gICAgICAgICAgXCIvYmxvZy9oZWxsbyUyMHdvcmxkKlwiLFxuICAgICAgICAgIFwiL2ZpbGVzL2ElMkZiKlwiLFxuICAgICAgICAgIFwiL0B1c2VyLzUwJTI1KlwiLFxuICAgICAgICAgIFwiL3RhZ3MvYyUyMyUzRipcIixcbiAgICAgICAgXSxcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJpbnZhbGlkYXRlcyBldmVyeSB0YWcgb2Ygb25lIGNhbGwgaW4gYSBzaW5nbGUgcmVxdWVzdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBgcmV2YWxpZGF0ZVRhZ2AgaGFuZHMgdGhlIGhhbmRsZXIgZXZlcnkgdGFnIGEgcmVxdWVzdCByZXZhbGlkYXRlZCBhdFxuICAgICAgLy8gb25jZTsgYSByZXF1ZXN0IHBlciB0YWcgY29tcGV0ZXMgZm9yIHRoZSBzYW1lIHF1b3RhLlxuICAgICAgYXdhaXQgd2l0aERpc3RyaWJ1dGlvbih7IEl0ZW1zOiBbXSB9KS5yZXZhbGlkYXRlVGFnKFtcbiAgICAgICAgXCJfTl9UXy9hXCIsXG4gICAgICAgIFwiX05fVF8vYlwiLFxuICAgICAgXSk7XG5cbiAgICAgIGV4cGVjdChpbnZhbGlkYXRpb25zKCkpLnRvRXF1YWwoW1tcIi9hKlwiLCBcIi9iKlwiXV0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJpbnZhbGlkYXRlcyB0aGUgd2hvbGUgYXBwIHdoZW4gYSB0YWcgaGFzIG1vcmUgcm93cyB0aGFuIGl0IHdhbGtzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFRoZSByb3dzIHBhc3QgdGhlIGxhc3QgcGFnZSB3YWxrZWQgYXJlIHBhZ2VzIHRvbzsgaW52YWxpZGF0aW5nIG9ubHkgdGhlXG4gICAgICAvLyBvbmVzIHJlYWQgbGVmdCB0aGUgcmVzdCBzdGFsZSBhdCB0aGUgZWRnZSBmb3IgdXAgdG8gYSB5ZWFyLlxuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwidGVzdC1wYXJhbS1uYW1lXCI7XG4gICAgICBtb2NrRHluYW1vU2VuZC5tb2NrSW1wbGVtZW50YXRpb24oKGNvbW1hbmQ6IHVua25vd24pID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZShcbiAgICAgICAgICBjb21tYW5kIGluc3RhbmNlb2YgUXVlcnlDb21tYW5kXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBJdGVtczogW3sgc2s6IHsgUzogXCJ0ZXN0LXRhZyN0ZXN0LWJ1aWxkLWlkL2lzci8xLmpzb25cIiB9IH1dLFxuICAgICAgICAgICAgICAgIExhc3RFdmFsdWF0ZWRLZXk6IHsgcGs6IHsgUzogXCJ0ZXN0LWJ1aWxkLWlkXCIgfSB9LFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHt9LFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIG1vY2tTc21TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgICAgUGFyYW1ldGVyOiB7IFZhbHVlOiBcInRlc3QtZGlzdHJpYnV0aW9uLWlkXCIgfSxcbiAgICAgIH0pO1xuICAgICAgbW9ja0Nsb3VkRnJvbnRTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgbmV3IFMzQ2FjaGVIYW5kbGVyKHsgY29udGV4dDogbW9ja0NvbnRleHQgfSkucmV2YWxpZGF0ZVRhZyhcbiAgICAgICAgXCJ0ZXN0LXRhZ1wiLFxuICAgICAgKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbW1wiLypcIl1dKTtcbiAgICB9KTtcblxuICAgIGl0KFwiaWdub3JlcyByb3dzIHRoYXQgYW5vdGhlciB0YWcgc2hhcmluZyB0aGUgcHJlZml4IG93bnNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gYGJlZ2luc193aXRoKHNrLCBcInVzZXIjXCIpYCBhbHNvIG1hdGNoZXMgdGhlIHRhZyBgdXNlciM0MmA6IGl0cyBiYXJlXG4gICAgICAvLyBtYXJrZXIgcm93LCBhbmQgaXRzIG1hcHBpbmcgcm93cy4gUmVhZCBhcyBgdXNlcmAncywgdGhleSBiZWNhbWVcbiAgICAgIC8vIGludmFsaWRhdGlvbiBwYXRocyBsaWtlIGAvNDJgIHRoYXQgbmFtZSBub3RoaW5nLlxuICAgICAgYXdhaXQgd2l0aERpc3RyaWJ1dGlvbih7XG4gICAgICAgIEl0ZW1zOiBbXG4gICAgICAgICAgeyBzazogeyBTOiBcInVzZXIjNDJcIiB9IH0sXG4gICAgICAgICAgeyBzazogeyBTOiBcInVzZXIjNDIjdGVzdC1idWlsZC1pZC9hY2NvdW50Lmpzb25cIiB9IH0sXG4gICAgICAgICAgeyBzazogeyBTOiBcInVzZXIjdGVzdC1idWlsZC1pZC9wcm9maWxlLmpzb25cIiB9IH0sXG4gICAgICAgIF0sXG4gICAgICB9KS5yZXZhbGlkYXRlVGFnKFwidXNlclwiKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbW1wiL3Byb2ZpbGUqXCJdXSk7XG4gICAgfSk7XG5cbiAgICBpdChcImFkZHMgdGhlIGJ1aWxkLXRpbWUgcHJlcmVuZGVycyB0aGUgYnVpbGQncyB0YWcgbWFuaWZlc3QgbmFtZXMsIHJlYWRpbmcgaXQgb25jZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBBIHByZXJlbmRlciBpcyB3cml0dGVuIGJ5IHRoZSBhZGFwdGVyLCBuZXZlciB0aHJvdWdoIGBzZXRgLCBzbyBpdCBoYXNcbiAgICAgIC8vIG5vIG1hcHBpbmcgcm93OiB0aGUgbWFuaWZlc3QgaXMgdGhlIG9ubHkgcmVjb3JkIG9mIGl0cyB0YWdzLlxuICAgICAgY29uc3QgY2RuSGFuZGxlciA9IHdpdGhEaXN0cmlidXRpb24oe1xuICAgICAgICBJdGVtczogW3sgc2s6IHsgUzogXCJwb3N0cyN0ZXN0LWJ1aWxkLWlkL2Jsb2cvYi5qc29uXCIgfSB9XSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgbWFuaWZlc3RHZXRzID0gKCkgPT5cbiAgICAgICAgKEdldE9iamVjdENvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHMuZmlsdGVyKFxuICAgICAgICAgIChbaW5wdXRdKSA9PlxuICAgICAgICAgICAgaW5wdXQuS2V5ID09PSBcInRlc3QtYnVpbGQtaWQvX2Nkay1uZXh0anMtdGFnLW1hbmlmZXN0Lmpzb25cIixcbiAgICAgICAgKTtcbiAgICAgIG1vY2tTM1NlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoXG4gICAgICAgICAgY29tbWFuZCBpbnN0YW5jZW9mIEdldE9iamVjdENvbW1hbmRcbiAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgIEJvZHk6IHtcbiAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybVRvU3RyaW5nOiBhc3luYyAoKSA9PlxuICAgICAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeSh7IHBvc3RzOiBbXCJibG9nL2FcIiwgXCJpbmRleFwiXSB9KSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHt9LFxuICAgICAgICApLFxuICAgICAgKTtcblxuICAgICAgYXdhaXQgY2RuSGFuZGxlci5yZXZhbGlkYXRlVGFnKFwicG9zdHNcIik7XG4gICAgICBhd2FpdCBjZG5IYW5kbGVyLnJldmFsaWRhdGVUYWcoXCJjb25zdHJ1Y3RvclwiKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbW1wiL2Jsb2cvYipcIiwgXCIvYmxvZy9hKlwiLCBcIi9cIiwgXCIvPypcIl1dKTtcbiAgICAgIGV4cGVjdChtYW5pZmVzdEdldHMoKSkudG9IYXZlTGVuZ3RoKDEpO1xuICAgIH0pO1xuXG4gICAgaXQoXCJpbnZhbGlkYXRlcyB0aGUgd2hvbGUgYXBwIHdoZW4gdGhlIGJ1aWxkJ3MgdGFnIG1hbmlmZXN0IGNhbm5vdCBiZSByZWFkLCBhbmQgcmVhZHMgaXQgYWdhaW4gbmV4dCB0aW1lXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGNkbkhhbmRsZXIgPSB3aXRoRGlzdHJpYnV0aW9uKHsgSXRlbXM6IFtdIH0pO1xuICAgICAgbW9ja1MzU2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwiQWNjZXNzRGVuaWVkXCIpKTtcblxuICAgICAgYXdhaXQgY2RuSGFuZGxlci5yZXZhbGlkYXRlVGFnKFwicG9zdHNcIik7XG4gICAgICBhd2FpdCBjZG5IYW5kbGVyLnJldmFsaWRhdGVUYWcoXCJwb3N0c1wiKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbW1wiLypcIl1dKTtcbiAgICAgIGV4cGVjdChtb2NrUzNTZW5kKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMik7XG4gICAgfSk7XG5cbiAgICBpdChcImludmFsaWRhdGVzIHRoZSB3aG9sZSBhcHAgd2hlbiBhIHRhZydzIG1hcmtlciByb3cgY2Fubm90IGJlIHdyaXR0ZW5cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gT3RoZXIgaW5zdGFuY2VzIHdvdWxkIG5ldmVyIHNlZSB0aGUgcmV2YWxpZGF0aW9uLCBzbyBubyBwYXRoIGxpc3QgaXNcbiAgICAgIC8vIGVub3VnaC5cbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInRlc3QtcGFyYW0tbmFtZVwiO1xuICAgICAgamVzdC5zcHlPbihjb25zb2xlLCBcImVycm9yXCIpLm1vY2tJbXBsZW1lbnRhdGlvbigpO1xuICAgICAgbW9ja0R5bmFtb1NlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PlxuICAgICAgICBjb21tYW5kIGluc3RhbmNlb2YgUXVlcnlDb21tYW5kXG4gICAgICAgICAgPyBQcm9taXNlLnJlc29sdmUoeyBJdGVtczogW10gfSlcbiAgICAgICAgICA6IFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIlByb3Zpc2lvbmVkVGhyb3VnaHB1dEV4Y2VlZGVkXCIpKSxcbiAgICAgICk7XG4gICAgICBtb2NrU3NtU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIFBhcmFtZXRlcjogeyBWYWx1ZTogXCJ0ZXN0LWRpc3RyaWJ1dGlvbi1pZFwiIH0sXG4gICAgICB9KTtcbiAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7fSk7XG5cbiAgICAgIGF3YWl0IG5ldyBTM0NhY2hlSGFuZGxlcih7IGNvbnRleHQ6IG1vY2tDb250ZXh0IH0pLnJldmFsaWRhdGVUYWcoXCJwb3N0c1wiKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbW1wiLypcIl1dKTtcbiAgICB9KTtcblxuICAgIGl0KFwiaW52YWxpZGF0ZXMgdGhlIHdob2xlIGFwcCB3aGVuIGEgdGFnJ3MgbWFwcGluZyByb3dzIGNhbm5vdCBiZSByZWFkXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFRoZSBtYXJrZXIgcm93IGlzIHdyaXR0ZW4gYmVmb3JlIHRoZSBRdWVyeSwgc28gYSBmYWlsZWQgUXVlcnkgbGVhdmVzXG4gICAgICAvLyB0aGUgdGFnIHJldmFsaWRhdGVkIGF0IHRoZSBvcmlnaW4gd2l0aCBubyBwYXRocyBuYW1lZCBmb3IgdGhlIGVkZ2UuXG4gICAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0RJU1RSSUJVVElPTl9JRF9QQVJBTV9OQU1FID0gXCJ0ZXN0LXBhcmFtLW5hbWVcIjtcbiAgICAgIGplc3Quc3B5T24oY29uc29sZSwgXCJlcnJvclwiKS5tb2NrSW1wbGVtZW50YXRpb24oKTtcbiAgICAgIG1vY2tEeW5hbW9TZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT5cbiAgICAgICAgY29tbWFuZCBpbnN0YW5jZW9mIFF1ZXJ5Q29tbWFuZFxuICAgICAgICAgID8gUHJvbWlzZS5yZWplY3QobmV3IEVycm9yKFwiUHJvdmlzaW9uZWRUaHJvdWdocHV0RXhjZWVkZWRcIikpXG4gICAgICAgICAgOiBQcm9taXNlLnJlc29sdmUoe30pLFxuICAgICAgKTtcbiAgICAgIG1vY2tTc21TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgICAgUGFyYW1ldGVyOiB7IFZhbHVlOiBcInRlc3QtZGlzdHJpYnV0aW9uLWlkXCIgfSxcbiAgICAgIH0pO1xuICAgICAgbW9ja0Nsb3VkRnJvbnRTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcblxuICAgICAgYXdhaXQgbmV3IFMzQ2FjaGVIYW5kbGVyKHsgY29udGV4dDogbW9ja0NvbnRleHQgfSkucmV2YWxpZGF0ZVRhZyhbXG4gICAgICAgIFwiX05fVF8vYVwiLFxuICAgICAgICBcInBvc3RzXCIsXG4gICAgICBdKTtcblxuICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbW1wiLypcIl1dKTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBDbG91ZEZyb250J3MgaW52YWxpZGF0aW9uIHF1b3RhIGlzIGZ1bGxcIiwgKCkgPT4ge1xuICAgICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgICAgIGplc3QudXNlRmFrZVRpbWVycygpO1xuICAgICAgfSk7XG4gICAgICBhZnRlckVhY2goKCkgPT4ge1xuICAgICAgICBqZXN0LnVzZVJlYWxUaW1lcnMoKTtcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBxdW90YUVycm9yID0gKCkgPT5cbiAgICAgICAgT2JqZWN0LmFzc2lnbihcbiAgICAgICAgICBuZXcgRXJyb3IoXCJZb3VyIHJlcXVlc3QgY29udGFpbnMgdG9vIG1hbnkgaW52YWxpZGF0aW9uc1wiKSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBuYW1lOiBcIlRvb01hbnlJbnZhbGlkYXRpb25zSW5Qcm9ncmVzc1wiLFxuICAgICAgICAgIH0sXG4gICAgICAgICk7XG5cbiAgICAgIGl0KFwicmV0cmllcyBhcyBvbmUgYXBwLXdpZGUgd2lsZGNhcmQgYWZ0ZXIgYSBiYWNrb2ZmXCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgY2RuSGFuZGxlciA9IHdpdGhEaXN0cmlidXRpb24ocGFnZXMoXCJ0ZXN0LXRhZ1wiLCAyKSk7XG4gICAgICAgIG1vY2tDbG91ZEZyb250U2VuZFxuICAgICAgICAgIC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UocXVvdGFFcnJvcigpKVxuICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe30pO1xuXG4gICAgICAgIGNvbnN0IGRvbmUgPSBjZG5IYW5kbGVyLnJldmFsaWRhdGVUYWcoXCJ0ZXN0LXRhZ1wiKTtcbiAgICAgICAgYXdhaXQgamVzdC5hZHZhbmNlVGltZXJzQnlUaW1lQXN5bmMoMTAwMCk7XG4gICAgICAgIGF3YWl0IGRvbmU7XG5cbiAgICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKSkudG9FcXVhbChbW1wiL2lzci8wKlwiLCBcIi9pc3IvMSpcIl0sIFtcIi8qXCJdXSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJnaXZlcyB1cCBhZnRlciB0aGUgbGFzdCByZXRyeVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGNkbkhhbmRsZXIgPSB3aXRoRGlzdHJpYnV0aW9uKHBhZ2VzKFwidGVzdC10YWdcIiwgMSkpO1xuICAgICAgICBtb2NrQ2xvdWRGcm9udFNlbmQubW9ja1JlamVjdGVkVmFsdWUocXVvdGFFcnJvcigpKTtcblxuICAgICAgICBjb25zdCBkb25lID0gY2RuSGFuZGxlci5yZXZhbGlkYXRlVGFnKFwidGVzdC10YWdcIik7XG4gICAgICAgIGF3YWl0IGplc3QuYWR2YW5jZVRpbWVyc0J5VGltZUFzeW5jKDMwMDApO1xuICAgICAgICBhd2FpdCBleHBlY3QoZG9uZSkucmVzb2x2ZXMudG9CZVVuZGVmaW5lZCgpO1xuXG4gICAgICAgIGV4cGVjdChpbnZhbGlkYXRpb25zKCkpLnRvRXF1YWwoW1tcIi9pc3IvMCpcIl0sIFtcIi8qXCJdLCBbXCIvKlwiXV0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiZG9lcyBub3QgcmV0cnkgYW55IG90aGVyIGVycm9yXCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgY2RuSGFuZGxlciA9IHdpdGhEaXN0cmlidXRpb24ocGFnZXMoXCJ0ZXN0LXRhZ1wiLCAxKSk7XG4gICAgICAgIG1vY2tDbG91ZEZyb250U2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZShuZXcgRXJyb3IoXCJBY2Nlc3NEZW5pZWRcIikpO1xuXG4gICAgICAgIGF3YWl0IGNkbkhhbmRsZXIucmV2YWxpZGF0ZVRhZyhcInRlc3QtdGFnXCIpO1xuXG4gICAgICAgIGV4cGVjdChpbnZhbGlkYXRpb25zKCkpLnRvRXF1YWwoW1tcIi9pc3IvMCpcIl1dKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInJldHJpZXMgdGhlIGFwcCdzIHJvb3QgdW5kZXIgYSBiYXNlUGF0aCB0b29cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgICAvLyBgL2Jhc2UvKmAgbWF0Y2hlcyBuZWl0aGVyIGAvYmFzZWAgbm9yIGAvYmFzZT9fcnNjPeKApmA6IHJldHJ5aW5nXG4gICAgICAgIC8vIGByZXZhbGlkYXRlUGF0aChcIi9cIilgIGFzIHRoYXQgbGVmdCB0aGUgaG9tZSBwYWdlIHN0YWxlIGF0IHRoZSBlZGdlLlxuICAgICAgICB1c2VCYXNlUGF0aCgpO1xuICAgICAgICBjb25zdCBjZG5IYW5kbGVyID0gd2l0aERpc3RyaWJ1dGlvbih7IEl0ZW1zOiBbXSB9KTtcbiAgICAgICAgbW9ja0Nsb3VkRnJvbnRTZW5kXG4gICAgICAgICAgLm1vY2tSZWplY3RlZFZhbHVlT25jZShxdW90YUVycm9yKCkpXG4gICAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7fSk7XG5cbiAgICAgICAgY29uc3QgZG9uZSA9IGNkbkhhbmRsZXIucmV2YWxpZGF0ZVRhZyhcIl9OX1RfL1wiKTtcbiAgICAgICAgYXdhaXQgamVzdC5hZHZhbmNlVGltZXJzQnlUaW1lQXN5bmMoMTAwMCk7XG4gICAgICAgIGF3YWl0IGRvbmU7XG5cbiAgICAgICAgZXhwZWN0KGludmFsaWRhdGlvbnMoKVsxXSkudG9FcXVhbChbXCIvYmFzZVwiLCBcIi9iYXNlPypcIiwgXCIvYmFzZS8qXCJdKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJyZWNvcmRzIGEgcHJvZmlsZSdzIHJldmFsaWRhdGlvbiBhcyBzdGFsZSBub3csIGV4cGlyaW5nIGxhdGVyXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGJlZm9yZSA9IERhdGUubm93KCk7XG4gICAgICBhd2FpdCBoYW5kbGVyLnJldmFsaWRhdGVUYWcoXCJwb3N0c1wiLCB7IGV4cGlyZTogNjAgfSk7XG5cbiAgICAgIGNvbnN0IFtpbnB1dF0gPSAoVXBkYXRlSXRlbUNvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHNbMF07XG4gICAgICBleHBlY3QoaW5wdXQuS2V5LnNrLlMpLnRvQmUoXCJwb3N0c1wiKTtcbiAgICAgIGV4cGVjdChpbnB1dC5VcGRhdGVFeHByZXNzaW9uKS50b0JlKFxuICAgICAgICBcIlNFVCBzdGFsZUF0ID0gOnN0YWxlQXQsIGV4cGlyZWRBdCA9IDpleHBpcmVkQXRcIixcbiAgICAgICk7XG4gICAgICBjb25zdCBzdGFsZUF0ID0gTnVtYmVyKGlucHV0LkV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXNbXCI6c3RhbGVBdFwiXS5OKTtcbiAgICAgIGV4cGVjdChzdGFsZUF0KS50b0JlR3JlYXRlclRoYW5PckVxdWFsKGJlZm9yZSk7XG4gICAgICBleHBlY3QoTnVtYmVyKGlucHV0LkV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXNbXCI6ZXhwaXJlZEF0XCJdLk4pKS50b0JlKFxuICAgICAgICBzdGFsZUF0ICsgNjBfMDAwLFxuICAgICAgKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLyoqXG4gICAqIFRoZSBjYWNoZSBoYW5kbGVyJ3MgaGFsZiBvZiBgcmVzLnJldmFsaWRhdGUoKWAncyBDRE4gaW52YWxpZGF0aW9uOiB0aGUgaG9va1xuICAgKiBpdCByZWdpc3RlcnMgZm9yIGBpbnZhbGlkYXRlUmV2YWxpZGF0ZWRQYWdlYCBpbiBgcnVudGltZS9jb3JlLnRzYC4gVGhlXG4gICAqIHJ1bnRpbWUncyBoYWxmIGlzIGluIGBjb3JlLnRlc3QudHNgLlxuICAgKi9cbiAgZGVzY3JpYmUoXCJ0aGUgcmV2YWxpZGF0ZWQtcGFnZSBob29rXCIsICgpID0+IHtcbiAgICBjb25zdCBIT09LID0gUkVWQUxJREFURURfUEFHRV9IT09LO1xuICAgIGNvbnN0IGdsb2JhbHMgPSBnbG9iYWxUaGlzIGFzIFJlY29yZDxzeW1ib2wsIHVua25vd24+O1xuICAgIHR5cGUgSG9vayA9IChyb3V0ZXM6IHJlYWRvbmx5IHN0cmluZ1tdKSA9PiBQcm9taXNlPHZvaWQ+O1xuXG4gICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgICBkZWxldGUgZ2xvYmFsc1tIT09LXTtcbiAgICAgIG1vY2tTc21TZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHsgUGFyYW1ldGVyOiB7IFZhbHVlOiBcIkVESVNUUklCVVRJT05cIiB9IH0pO1xuICAgICAgbW9ja0Nsb3VkRnJvbnRTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHt9KTtcbiAgICAgIChDcmVhdGVJbnZhbGlkYXRpb25Db21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrKS5tb2NrQ2xlYXIoKTtcbiAgICB9KTtcblxuICAgIGZ1bmN0aW9uIGludmFsaWRhdGVkUGF0aHMoKTogc3RyaW5nW10ge1xuICAgICAgY29uc3QgW2lucHV0XSA9IChDcmVhdGVJbnZhbGlkYXRpb25Db21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrKS5tb2NrXG4gICAgICAgIC5jYWxsc1swXTtcbiAgICAgIHJldHVybiBpbnB1dC5JbnZhbGlkYXRpb25CYXRjaC5QYXRocy5JdGVtcztcbiAgICB9XG5cbiAgICBpdChcImlzIHJlZ2lzdGVyZWQgb25seSBiZWhpbmQgYSBkaXN0cmlidXRpb25cIiwgKCkgPT4ge1xuICAgICAgbmV3IFMzQ2FjaGVIYW5kbGVyKHsgY29udGV4dDogbW9ja0NvbnRleHQgfSk7XG4gICAgICBleHBlY3QoZ2xvYmFsc1tIT09LXSkudG9CZVVuZGVmaW5lZCgpO1xuXG4gICAgICBwcm9jZXNzLmVudi5DREtfTkVYVEpTX0RJU1RSSUJVVElPTl9JRF9QQVJBTV9OQU1FID0gXCJwYXJhbVwiO1xuICAgICAgbmV3IFMzQ2FjaGVIYW5kbGVyKHsgY29udGV4dDogbW9ja0NvbnRleHQgfSk7XG4gICAgICBleHBlY3QodHlwZW9mIGdsb2JhbHNbSE9PS10pLnRvQmUoXCJmdW5jdGlvblwiKTtcbiAgICB9KTtcblxuICAgIGl0KFwiaW52YWxpZGF0ZXMgdGhlIHBhZ2UgYW5kIGl0cyBkYXRhIHJvdXRlIHVuZGVyIGJhc2VQYXRoXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfRElTVFJJQlVUSU9OX0lEX1BBUkFNX05BTUUgPSBcInBhcmFtXCI7XG4gICAgICBuZXcgUzNDYWNoZUhhbmRsZXIoeyBjb250ZXh0OiBtb2NrQ29udGV4dCwgYmFzZVBhdGg6IFwiYmFzZVwiIH0pO1xuICAgICAgYXdhaXQgKGdsb2JhbHNbSE9PS10gYXMgSG9vaykoW1xuICAgICAgICBcIi9ibG9nL2hlbGxvXCIsXG4gICAgICAgIFwiL19uZXh0L2RhdGEvdGVzdC1idWlsZC1pZC9ibG9nL2hlbGxvLmpzb25cIixcbiAgICAgIF0pO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGVkUGF0aHMoKSkudG9FcXVhbChbXG4gICAgICAgIFwiL2Jhc2UvYmxvZy9oZWxsbypcIixcbiAgICAgICAgXCIvYmFzZS9fbmV4dC9kYXRhL3Rlc3QtYnVpbGQtaWQvYmxvZy9oZWxsby5qc29uKlwiLFxuICAgICAgXSk7XG4gICAgfSk7XG5cbiAgICBpdChcInNwZWxscyBvdXQgdGhlIHJvb3QgcmF0aGVyIHRoYW4gaW52YWxpZGF0aW5nIHRoZSB3aG9sZSBhcHBcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwicGFyYW1cIjtcbiAgICAgIG5ldyBTM0NhY2hlSGFuZGxlcih7IGNvbnRleHQ6IG1vY2tDb250ZXh0IH0pO1xuICAgICAgYXdhaXQgKGdsb2JhbHNbSE9PS10gYXMgSG9vaykoW1xuICAgICAgICBcIi9cIixcbiAgICAgICAgXCIvX25leHQvZGF0YS90ZXN0LWJ1aWxkLWlkL2luZGV4Lmpzb25cIixcbiAgICAgIF0pO1xuICAgICAgZXhwZWN0KGludmFsaWRhdGVkUGF0aHMoKSkudG9FcXVhbChbXG4gICAgICAgIFwiL1wiLFxuICAgICAgICBcIi8/KlwiLFxuICAgICAgICBcIi9fbmV4dC9kYXRhL3Rlc3QtYnVpbGQtaWQvaW5kZXguanNvbipcIixcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgaXQoXCJzZW5kcyBldmVyeSBwYXRoIG9uY2UsIGluIG9uZSBpbnZhbGlkYXRpb25cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19ESVNUUklCVVRJT05fSURfUEFSQU1fTkFNRSA9IFwicGFyYW1cIjtcbiAgICAgIG5ldyBTM0NhY2hlSGFuZGxlcih7IGNvbnRleHQ6IG1vY2tDb250ZXh0IH0pO1xuICAgICAgYXdhaXQgKGdsb2JhbHNbSE9PS10gYXMgSG9vaykoW1xuICAgICAgICBcIi9ibG9nXCIsXG4gICAgICAgIFwiL19uZXh0L2RhdGEvdGVzdC1idWlsZC1pZC9lbi9ibG9nLmpzb25cIixcbiAgICAgICAgXCIvZW4vYmxvZ1wiLFxuICAgICAgICBcIi9ibG9nXCIsXG4gICAgICBdKTtcbiAgICAgIGV4cGVjdChDcmVhdGVJbnZhbGlkYXRpb25Db21tYW5kKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMSk7XG4gICAgICBleHBlY3QoaW52YWxpZGF0ZWRQYXRocygpKS50b0VxdWFsKFtcbiAgICAgICAgXCIvYmxvZypcIixcbiAgICAgICAgXCIvX25leHQvZGF0YS90ZXN0LWJ1aWxkLWlkL2VuL2Jsb2cuanNvbipcIixcbiAgICAgICAgXCIvZW4vYmxvZypcIixcbiAgICAgIF0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZShcInJlc2V0UmVxdWVzdENhY2hlXCIsICgpID0+IHtcbiAgICBpdChcInNob3VsZCBjb21wbGV0ZSB3aXRob3V0IGVycm9yc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBleHBlY3QoaGFuZGxlci5yZXNldFJlcXVlc3RDYWNoZSgpKS5yZXNvbHZlcy5ub3QudG9UaHJvdygpO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19