cdk-nextjs 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1551 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +857 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +863 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +13 -5
- package/lib/nextjs-post-deploy.js +13 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1216 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1686 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41600 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +71 -0
- package/lib/runtime/next-modules.js +144 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41593 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
4
|
+
jest.mock("@aws-sdk/client-dynamodb");
|
|
5
|
+
const aws_cache_store_1 = require("./aws-cache-store");
|
|
6
|
+
const use_cache_common_1 = require("./use-cache-common");
|
|
7
|
+
/** A `TagMarkerTable` over a plain map, counting its calls. */
|
|
8
|
+
function fakeMarkers(rows = new Map()) {
|
|
9
|
+
const read = jest.fn(async (tags) => {
|
|
10
|
+
const found = new Map();
|
|
11
|
+
for (const tag of tags) {
|
|
12
|
+
const row = rows.get(tag);
|
|
13
|
+
if (row)
|
|
14
|
+
found.set(tag, { ...row });
|
|
15
|
+
}
|
|
16
|
+
return found;
|
|
17
|
+
});
|
|
18
|
+
const write = jest.fn(async (tag, at, durations) => {
|
|
19
|
+
const row = rows.get(tag) ?? {};
|
|
20
|
+
if (!durations) {
|
|
21
|
+
row.revalidatedAt = at;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
row.staleAt = at;
|
|
25
|
+
if (durations.expire !== undefined) {
|
|
26
|
+
row.expiredAt = at + durations.expire * 1000;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
rows.set(tag, row);
|
|
30
|
+
// `ReturnValues: "ALL_NEW"`, as the real table answers.
|
|
31
|
+
return { ...row };
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
rows,
|
|
35
|
+
read,
|
|
36
|
+
write,
|
|
37
|
+
table: { read, write },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A `RevalidationLog` over a plain array, counting its calls. Its query returns
|
|
42
|
+
* what the real one would: every row at or after `since`, oldest first.
|
|
43
|
+
*/
|
|
44
|
+
function fakeLog(rows = []) {
|
|
45
|
+
const put = jest.fn(async (tag, at, marker) => {
|
|
46
|
+
rows.push({
|
|
47
|
+
sk: `${String(at).padStart(15, "0")}#${tag}`,
|
|
48
|
+
at,
|
|
49
|
+
tag,
|
|
50
|
+
marker,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
const query = jest.fn(async (since) => ({
|
|
54
|
+
rows: rows.filter((row) => row.at >= since).sort((a, b) => a.at - b.at),
|
|
55
|
+
truncated: false,
|
|
56
|
+
}));
|
|
57
|
+
return {
|
|
58
|
+
rows,
|
|
59
|
+
put,
|
|
60
|
+
query,
|
|
61
|
+
log: { put, query },
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** A wall clock a test moves by hand. */
|
|
65
|
+
function fakeClock(start = 1_000_000) {
|
|
66
|
+
const clock = { at: start, now: () => clock.at };
|
|
67
|
+
return clock;
|
|
68
|
+
}
|
|
69
|
+
function streamOf(...chunks) {
|
|
70
|
+
return new ReadableStream({
|
|
71
|
+
start(controller) {
|
|
72
|
+
for (const chunk of chunks) {
|
|
73
|
+
controller.enqueue(new TextEncoder().encode(chunk));
|
|
74
|
+
}
|
|
75
|
+
controller.close();
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function stored(bytes, extra = {}) {
|
|
80
|
+
return {
|
|
81
|
+
value: new Uint8Array(bytes),
|
|
82
|
+
tags: [],
|
|
83
|
+
stale: 300,
|
|
84
|
+
timestamp: Date.now(),
|
|
85
|
+
expire: 3600,
|
|
86
|
+
revalidate: 900,
|
|
87
|
+
...extra,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
describe("TrackedTagMarkers", () => {
|
|
91
|
+
it("reads a tag the first time it is needed, and not again", async () => {
|
|
92
|
+
const markers = fakeMarkers(new Map([["a", { revalidatedAt: 50 }]]));
|
|
93
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
94
|
+
markers: markers.table,
|
|
95
|
+
log: fakeLog().log,
|
|
96
|
+
});
|
|
97
|
+
await Promise.all([tags.ensure(["a", "b"]), tags.ensure(["a", "b"])]);
|
|
98
|
+
await tags.ensure(["a", "b"]);
|
|
99
|
+
expect(markers.read).toHaveBeenCalledTimes(1);
|
|
100
|
+
expect(markers.read).toHaveBeenCalledWith(["a", "b"]);
|
|
101
|
+
expect(tags.state(["a"], 40)).toBe("expired");
|
|
102
|
+
expect(tags.state(["a"], 60)).toBe("fresh");
|
|
103
|
+
expect(tags.state(["b"], 40)).toBe("fresh");
|
|
104
|
+
});
|
|
105
|
+
it("applies its own revalidation at once, and writes it once for both handlers", async () => {
|
|
106
|
+
const markers = fakeMarkers();
|
|
107
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
108
|
+
markers: markers.table,
|
|
109
|
+
log: fakeLog().log,
|
|
110
|
+
});
|
|
111
|
+
const createdAt = Date.now() - 1000;
|
|
112
|
+
// What Next.js does: `updateTags` on the default and the remote handler.
|
|
113
|
+
await Promise.all([
|
|
114
|
+
tags.update(["a", "b"], { expire: 0 }),
|
|
115
|
+
tags.update(["a", "b"], { expire: 0 }),
|
|
116
|
+
]);
|
|
117
|
+
expect(markers.write).toHaveBeenCalledTimes(2);
|
|
118
|
+
expect(tags.state(["b"], createdAt)).toBe("expired");
|
|
119
|
+
expect(markers.rows.get("a")).toEqual({
|
|
120
|
+
staleAt: expect.any(Number),
|
|
121
|
+
expiredAt: expect.any(Number),
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
it("gives a later revalidation its own marker while the first is still writing", async () => {
|
|
125
|
+
const markers = fakeMarkers();
|
|
126
|
+
let release = () => { };
|
|
127
|
+
markers.write.mockImplementationOnce((_tag, at) => new Promise((resolve) => {
|
|
128
|
+
release = () => resolve({ revalidatedAt: at });
|
|
129
|
+
}));
|
|
130
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
131
|
+
markers: markers.table,
|
|
132
|
+
log: fakeLog().log,
|
|
133
|
+
});
|
|
134
|
+
const first = tags.update(["x"], undefined);
|
|
135
|
+
// Another request's `revalidateTag('x')`, a turn later.
|
|
136
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
137
|
+
const second = tags.update(["x"], undefined);
|
|
138
|
+
release();
|
|
139
|
+
await Promise.all([first, second]);
|
|
140
|
+
expect(markers.write).toHaveBeenCalledTimes(2);
|
|
141
|
+
const [[, firstAt], [, secondAt]] = markers.write.mock.calls;
|
|
142
|
+
expect(secondAt).toBeGreaterThan(firstAt);
|
|
143
|
+
});
|
|
144
|
+
it("puts a slow log row again under a fresh timestamp, so readers see it", async () => {
|
|
145
|
+
const clock = fakeClock();
|
|
146
|
+
const log = fakeLog();
|
|
147
|
+
log.put.mockImplementationOnce(async () => {
|
|
148
|
+
// Readers' cursors have moved past the row by the time it shows.
|
|
149
|
+
clock.at += 10_000;
|
|
150
|
+
});
|
|
151
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
152
|
+
markers: fakeMarkers().table,
|
|
153
|
+
log: log.log,
|
|
154
|
+
clock: clock.now,
|
|
155
|
+
});
|
|
156
|
+
expect(await tags.update(["x"], undefined)).toBe(true);
|
|
157
|
+
expect(log.put.mock.calls.map(([, at]) => at)).toEqual([
|
|
158
|
+
1_000_000, 1_010_000,
|
|
159
|
+
]);
|
|
160
|
+
});
|
|
161
|
+
it("reports a log row slow twice as not recorded", async () => {
|
|
162
|
+
const clock = fakeClock();
|
|
163
|
+
const log = fakeLog();
|
|
164
|
+
log.put.mockImplementation(async () => {
|
|
165
|
+
clock.at += 10_000;
|
|
166
|
+
});
|
|
167
|
+
const error = jest.spyOn(console, "error").mockImplementation(() => { });
|
|
168
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
169
|
+
markers: fakeMarkers().table,
|
|
170
|
+
log: log.log,
|
|
171
|
+
clock: clock.now,
|
|
172
|
+
});
|
|
173
|
+
expect(await tags.update(["x"], undefined)).toBe(false);
|
|
174
|
+
expect(log.put).toHaveBeenCalledTimes(2);
|
|
175
|
+
error.mockRestore();
|
|
176
|
+
});
|
|
177
|
+
it("tracks the whole row its own write returns, not just what it set", async () => {
|
|
178
|
+
// Another instance's `updateTag` for a tag this one does not track yet.
|
|
179
|
+
const createdAt = Date.now() - 1000;
|
|
180
|
+
const markers = fakeMarkers(new Map([["posts", { revalidatedAt: createdAt + 500 }]]));
|
|
181
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
182
|
+
markers: markers.table,
|
|
183
|
+
log: fakeLog().log,
|
|
184
|
+
});
|
|
185
|
+
await tags.update(["posts"], { expire: 3600 });
|
|
186
|
+
// Older than that `updateTag`, so a blocking render, not stale-while-revalidate.
|
|
187
|
+
expect(tags.state(["posts"], createdAt)).toBe("expired");
|
|
188
|
+
});
|
|
189
|
+
it("marks a profile's revalidation stale until its expire", async () => {
|
|
190
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({});
|
|
191
|
+
const createdAt = Date.now() - 1000;
|
|
192
|
+
await tags.update(["a"], { expire: 3600 });
|
|
193
|
+
expect(tags.state(["a"], createdAt)).toBe("stale");
|
|
194
|
+
// Not an expiration yet, so implicit tags are not affected either.
|
|
195
|
+
expect(tags.expiration(["a"])).toBe(0);
|
|
196
|
+
});
|
|
197
|
+
// Next.js stamps entries with `performance.timeOrigin + performance.now()`,
|
|
198
|
+
// which can run behind `Date.now()`. A marker stamped on the wall clock would
|
|
199
|
+
// then postdate an entry regenerated right after the revalidation, which
|
|
200
|
+
// would read as revalidated again, and again.
|
|
201
|
+
it("stamps markers on the clock entries are stamped with", async () => {
|
|
202
|
+
const wall = jest.spyOn(Date, "now").mockImplementation(() => (0, use_cache_common_1.now)() + 500);
|
|
203
|
+
try {
|
|
204
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({});
|
|
205
|
+
await tags.update(["a"], undefined);
|
|
206
|
+
const regenerated = (0, use_cache_common_1.now)() + 1;
|
|
207
|
+
expect(tags.state(["a"], regenerated)).toBe("fresh");
|
|
208
|
+
expect(tags.state(["a"], regenerated - 100)).toBe("expired");
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
wall.mockRestore();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
it("reports the latest past expiration of implicit tags", async () => {
|
|
215
|
+
const markers = fakeMarkers(new Map([
|
|
216
|
+
["_N_T_/a", { revalidatedAt: 100 }],
|
|
217
|
+
["_N_T_/b", { staleAt: 150, expiredAt: 200 }],
|
|
218
|
+
["_N_T_/c", { staleAt: 150, expiredAt: Date.now() + 60_000 }],
|
|
219
|
+
]));
|
|
220
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
221
|
+
markers: markers.table,
|
|
222
|
+
log: fakeLog().log,
|
|
223
|
+
});
|
|
224
|
+
await tags.ensure(["_N_T_/a", "_N_T_/b", "_N_T_/c", "_N_T_/d"]);
|
|
225
|
+
expect(tags.expiration(["_N_T_/a", "_N_T_/b", "_N_T_/c"])).toBe(200);
|
|
226
|
+
expect(tags.expiration(["_N_T_/d"])).toBe(0);
|
|
227
|
+
});
|
|
228
|
+
it("does not let an eventually consistent read undo its own write", async () => {
|
|
229
|
+
const markers = fakeMarkers();
|
|
230
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
231
|
+
markers: markers.table,
|
|
232
|
+
log: fakeLog().log,
|
|
233
|
+
refreshIntervalMs: 0,
|
|
234
|
+
});
|
|
235
|
+
await tags.update(["a"], undefined);
|
|
236
|
+
// The read does not show the write yet.
|
|
237
|
+
markers.rows.clear();
|
|
238
|
+
await tags.refresh();
|
|
239
|
+
expect(tags.state(["a"], Date.now() - 1000)).toBe("expired");
|
|
240
|
+
});
|
|
241
|
+
it("treats a failed read as fresh and tries again on the next refresh", async () => {
|
|
242
|
+
const markers = fakeMarkers(new Map([["a", { revalidatedAt: 50 }]]));
|
|
243
|
+
const error = jest.spyOn(console, "error").mockImplementation(() => { });
|
|
244
|
+
markers.read.mockRejectedValueOnce(new Error("throttled"));
|
|
245
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
246
|
+
markers: markers.table,
|
|
247
|
+
log: fakeLog().log,
|
|
248
|
+
refreshIntervalMs: 0,
|
|
249
|
+
});
|
|
250
|
+
await tags.ensure(["a"]);
|
|
251
|
+
expect(tags.state(["a"], 40)).toBe("fresh");
|
|
252
|
+
await tags.refresh();
|
|
253
|
+
expect(tags.state(["a"], 40)).toBe("expired");
|
|
254
|
+
error.mockRestore();
|
|
255
|
+
});
|
|
256
|
+
it("forgets the least recently used tag past its bound, and reads it again", async () => {
|
|
257
|
+
const markers = fakeMarkers();
|
|
258
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
259
|
+
markers: markers.table,
|
|
260
|
+
log: fakeLog().log,
|
|
261
|
+
maxTrackedTags: 2,
|
|
262
|
+
});
|
|
263
|
+
await tags.ensure(["a"]);
|
|
264
|
+
await tags.ensure(["b"]);
|
|
265
|
+
await tags.ensure(["a"]); // `b` is now the oldest
|
|
266
|
+
await tags.ensure(["c"]);
|
|
267
|
+
markers.read.mockClear();
|
|
268
|
+
await tags.ensure(["a", "b", "c"]);
|
|
269
|
+
expect(markers.read).toHaveBeenCalledWith(["b"]);
|
|
270
|
+
});
|
|
271
|
+
// Every path is a tag of its own, so an app of 1000 tagged pages needs 2000:
|
|
272
|
+
// tracked 1000 at most, half its requests re-read an evicted marker.
|
|
273
|
+
it("keeps 2000 tags a page each tracked, without reading them again", async () => {
|
|
274
|
+
const markers = fakeMarkers();
|
|
275
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
276
|
+
markers: markers.table,
|
|
277
|
+
log: fakeLog().log,
|
|
278
|
+
});
|
|
279
|
+
const pages = Array.from({ length: 1000 }, (_, n) => [
|
|
280
|
+
`item-${n}`,
|
|
281
|
+
`_N_T_/use-cache/${n}`,
|
|
282
|
+
]);
|
|
283
|
+
for (const page of pages)
|
|
284
|
+
await tags.ensure(page);
|
|
285
|
+
markers.read.mockClear();
|
|
286
|
+
for (const page of pages)
|
|
287
|
+
await tags.ensure(page);
|
|
288
|
+
expect(markers.read).not.toHaveBeenCalled();
|
|
289
|
+
});
|
|
290
|
+
it("keeps tags local to the process without a table", async () => {
|
|
291
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({});
|
|
292
|
+
await tags.ensure(["a"]);
|
|
293
|
+
await tags.refresh();
|
|
294
|
+
await tags.update(["a"], undefined);
|
|
295
|
+
expect(tags.state(["a"], Date.now() - 1000)).toBe("expired");
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
describe("TrackedTagMarkers with the revalidation log", () => {
|
|
299
|
+
const INTERVAL = 1000;
|
|
300
|
+
/** Two instances, `a` and `b`, over one table and one clock. */
|
|
301
|
+
function instances(options = {}) {
|
|
302
|
+
const markerRows = new Map();
|
|
303
|
+
const logRows = [];
|
|
304
|
+
const clock = fakeClock();
|
|
305
|
+
const instance = () => {
|
|
306
|
+
const markers = fakeMarkers(markerRows);
|
|
307
|
+
const log = fakeLog(logRows);
|
|
308
|
+
const tags = new aws_cache_store_1.TrackedTagMarkers({
|
|
309
|
+
markers: markers.table,
|
|
310
|
+
log: log.log,
|
|
311
|
+
refreshIntervalMs: INTERVAL,
|
|
312
|
+
clock: clock.now,
|
|
313
|
+
// Due at the full interval unless a test asks otherwise.
|
|
314
|
+
random: () => 0,
|
|
315
|
+
...options,
|
|
316
|
+
});
|
|
317
|
+
return { markers, log, tags };
|
|
318
|
+
};
|
|
319
|
+
return { clock, logRows, instance, a: instance(), b: instance() };
|
|
320
|
+
}
|
|
321
|
+
const createdAt = () => (0, use_cache_common_1.now)() - 1000;
|
|
322
|
+
it("reaches another instance within one interval, in one Query and no BatchGetItem", async () => {
|
|
323
|
+
const { clock, a, b } = instances();
|
|
324
|
+
await b.tags.ensure(["posts"]);
|
|
325
|
+
b.markers.read.mockClear();
|
|
326
|
+
await a.tags.update(["posts"], undefined);
|
|
327
|
+
expect(a.log.put).toHaveBeenCalledWith("posts", clock.at, expect.objectContaining({ revalidatedAt: expect.any(Number) }));
|
|
328
|
+
clock.at += INTERVAL;
|
|
329
|
+
await b.tags.refresh();
|
|
330
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("expired");
|
|
331
|
+
expect(b.log.query).toHaveBeenCalledTimes(1);
|
|
332
|
+
expect(b.markers.read).not.toHaveBeenCalled();
|
|
333
|
+
});
|
|
334
|
+
it("issues no read while the interval has not passed", async () => {
|
|
335
|
+
const { clock, b } = instances();
|
|
336
|
+
// Nothing tracked: nothing to ask.
|
|
337
|
+
clock.at += INTERVAL;
|
|
338
|
+
await b.tags.refresh();
|
|
339
|
+
expect(b.log.query).not.toHaveBeenCalled();
|
|
340
|
+
await b.tags.ensure(["posts"]);
|
|
341
|
+
b.markers.read.mockClear();
|
|
342
|
+
// That refresh still counts: what is tracked since was read, or is new.
|
|
343
|
+
await b.tags.refresh();
|
|
344
|
+
expect(b.log.query).not.toHaveBeenCalled();
|
|
345
|
+
clock.at += INTERVAL;
|
|
346
|
+
await Promise.all([b.tags.refresh(), b.tags.refresh()]);
|
|
347
|
+
expect(b.log.query).toHaveBeenCalledTimes(1);
|
|
348
|
+
clock.at += INTERVAL - 1;
|
|
349
|
+
await b.tags.refresh();
|
|
350
|
+
expect(b.log.query).toHaveBeenCalledTimes(1);
|
|
351
|
+
expect(b.markers.read).not.toHaveBeenCalled();
|
|
352
|
+
clock.at += 1;
|
|
353
|
+
await b.tags.refresh();
|
|
354
|
+
expect(b.log.query).toHaveBeenCalledTimes(2);
|
|
355
|
+
});
|
|
356
|
+
it("applies a row read again inside the lookback only once", async () => {
|
|
357
|
+
const { clock, logRows, b } = instances();
|
|
358
|
+
await b.tags.ensure(["posts"]);
|
|
359
|
+
b.markers.read.mockClear();
|
|
360
|
+
let reads = 0;
|
|
361
|
+
const row = {
|
|
362
|
+
sk: `${clock.at}#posts`,
|
|
363
|
+
at: clock.at,
|
|
364
|
+
tag: "posts",
|
|
365
|
+
get marker() {
|
|
366
|
+
reads++;
|
|
367
|
+
return { revalidatedAt: (0, use_cache_common_1.now)() };
|
|
368
|
+
},
|
|
369
|
+
};
|
|
370
|
+
// The same row twice in one page, and again on the next query.
|
|
371
|
+
logRows.push(row, row);
|
|
372
|
+
for (let i = 0; i < 3; i++) {
|
|
373
|
+
clock.at += INTERVAL;
|
|
374
|
+
await b.tags.refresh();
|
|
375
|
+
}
|
|
376
|
+
expect(b.log.query).toHaveBeenCalledTimes(3);
|
|
377
|
+
expect(reads).toBe(1);
|
|
378
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("expired");
|
|
379
|
+
});
|
|
380
|
+
// Replication lag, or a writer whose clock runs behind: the row shows up
|
|
381
|
+
// after a query that should have seen it, with a sort key before it.
|
|
382
|
+
it("still sees a row that appears up to the lookback late", async () => {
|
|
383
|
+
const { clock, logRows, b } = instances();
|
|
384
|
+
await b.tags.ensure(["late", "too-late"]);
|
|
385
|
+
b.markers.read.mockClear();
|
|
386
|
+
clock.at += INTERVAL;
|
|
387
|
+
const firstQuery = clock.at;
|
|
388
|
+
await b.tags.refresh();
|
|
389
|
+
const marker = { revalidatedAt: (0, use_cache_common_1.now)() };
|
|
390
|
+
logRows.push({ sk: "late", at: firstQuery - 5000, tag: "late", marker }, { sk: "too-late", at: firstQuery - 5001, tag: "too-late", marker });
|
|
391
|
+
clock.at += INTERVAL;
|
|
392
|
+
await b.tags.refresh();
|
|
393
|
+
expect(b.log.query).toHaveBeenLastCalledWith(firstQuery - 5000);
|
|
394
|
+
expect(b.tags.state(["late"], createdAt())).toBe("expired");
|
|
395
|
+
// Past the lookback: what the periodic re-read of the markers is for.
|
|
396
|
+
expect(b.tags.state(["too-late"], createdAt())).toBe("fresh");
|
|
397
|
+
});
|
|
398
|
+
it("forgets its tracked markers after a gap the log may not cover, and reads each as it is needed", async () => {
|
|
399
|
+
const { clock, a, b } = instances();
|
|
400
|
+
await b.tags.ensure(["posts", "other"]);
|
|
401
|
+
await a.tags.update(["posts"], undefined);
|
|
402
|
+
clock.at += aws_cache_store_1.MAX_REVALIDATION_LOG_GAP_MS + 1;
|
|
403
|
+
const gapEnd = clock.at;
|
|
404
|
+
await b.tags.refresh();
|
|
405
|
+
// No burst of re-reads, and no query of a log that may have lost rows.
|
|
406
|
+
expect(b.markers.read).toHaveBeenCalledTimes(1);
|
|
407
|
+
expect(b.log.query).not.toHaveBeenCalled();
|
|
408
|
+
await b.tags.ensure(["posts"]);
|
|
409
|
+
expect(b.markers.read).toHaveBeenLastCalledWith(["posts"]);
|
|
410
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("expired");
|
|
411
|
+
// Then back on the log, from just before the gap ended.
|
|
412
|
+
clock.at += INTERVAL;
|
|
413
|
+
await b.tags.refresh();
|
|
414
|
+
expect(b.log.query).toHaveBeenCalledWith(gapEnd - 5000);
|
|
415
|
+
});
|
|
416
|
+
// Re-reading every tracked marker at once is ~5,000 RCU at 10,000 tags: more
|
|
417
|
+
// than the one partition serves in a second.
|
|
418
|
+
it("re-reads each tracked marker once per resync interval, at most 100 a refresh", async () => {
|
|
419
|
+
const { clock, b } = instances({ resyncIntervalMs: 10 * INTERVAL });
|
|
420
|
+
await b.tags.ensure(Array.from({ length: 250 }, (_, i) => `t${i}`));
|
|
421
|
+
b.markers.read.mockClear();
|
|
422
|
+
const sizes = [];
|
|
423
|
+
for (let i = 1; i <= 14; i++) {
|
|
424
|
+
clock.at += INTERVAL;
|
|
425
|
+
b.markers.read.mockClear();
|
|
426
|
+
await b.tags.refresh();
|
|
427
|
+
sizes.push(b.markers.read.mock.calls[0]?.[0].length ?? 0);
|
|
428
|
+
}
|
|
429
|
+
expect(b.log.query).toHaveBeenCalledTimes(14);
|
|
430
|
+
// Due at 10 intervals, oldest first, 100 per refresh; then not again.
|
|
431
|
+
expect(sizes).toEqual([0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100, 50, 0, 0]);
|
|
432
|
+
expect(b.markers.read).not.toHaveBeenCalled();
|
|
433
|
+
});
|
|
434
|
+
// Tags first read together must not come due together every interval.
|
|
435
|
+
it("spreads when each tag comes due over the last quarter of the interval", async () => {
|
|
436
|
+
// Due at 10, 8.75 and 7.5 intervals, known in that order: the one due
|
|
437
|
+
// first is last, behind two that are not due yet.
|
|
438
|
+
const randoms = [0, 0.5, 1];
|
|
439
|
+
const { clock, b } = instances({
|
|
440
|
+
resyncIntervalMs: 10 * INTERVAL,
|
|
441
|
+
random: () => randoms.shift() ?? 0,
|
|
442
|
+
});
|
|
443
|
+
await b.tags.ensure(["late", "middle", "early"]);
|
|
444
|
+
b.markers.read.mockClear();
|
|
445
|
+
const readAt = {};
|
|
446
|
+
for (let i = 1; i <= 10; i++) {
|
|
447
|
+
clock.at += INTERVAL;
|
|
448
|
+
b.markers.read.mockClear();
|
|
449
|
+
await b.tags.refresh();
|
|
450
|
+
for (const tag of b.markers.read.mock.calls[0]?.[0] ?? []) {
|
|
451
|
+
readAt[tag] ??= i;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
expect(readAt).toEqual({ early: 8, middle: 9, late: 10 });
|
|
455
|
+
});
|
|
456
|
+
it("re-reads a marker it learned of from its own write only once that is due", async () => {
|
|
457
|
+
const { clock, a } = instances({ resyncIntervalMs: 10 * INTERVAL });
|
|
458
|
+
await a.tags.ensure(["posts"]);
|
|
459
|
+
clock.at += 9 * INTERVAL;
|
|
460
|
+
await a.tags.update(["posts"], undefined);
|
|
461
|
+
clock.at += 2 * INTERVAL;
|
|
462
|
+
await a.tags.refresh();
|
|
463
|
+
// Read 11 intervals ago, but written - so known - 2 intervals ago.
|
|
464
|
+
expect(a.markers.read).toHaveBeenCalledTimes(1);
|
|
465
|
+
});
|
|
466
|
+
it("reads a tag whose first read failed again on the next refresh", async () => {
|
|
467
|
+
const error = jest.spyOn(console, "error").mockImplementation(() => { });
|
|
468
|
+
const { clock, a, b } = instances();
|
|
469
|
+
// Only the marker row has it, so only reading the marker finds it.
|
|
470
|
+
a.log.put.mockRejectedValueOnce(new Error("throttled"));
|
|
471
|
+
await a.tags.update(["posts"], undefined);
|
|
472
|
+
b.markers.read.mockRejectedValueOnce(new Error("throttled"));
|
|
473
|
+
await b.tags.ensure(["posts"]);
|
|
474
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("fresh");
|
|
475
|
+
clock.at += INTERVAL;
|
|
476
|
+
await b.tags.refresh();
|
|
477
|
+
expect(b.markers.read).toHaveBeenLastCalledWith(["posts"]);
|
|
478
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("expired");
|
|
479
|
+
error.mockRestore();
|
|
480
|
+
});
|
|
481
|
+
it("forgets its tracked markers when the log has more rows than one query reads", async () => {
|
|
482
|
+
const { clock, b } = instances();
|
|
483
|
+
await b.tags.ensure(["posts"]);
|
|
484
|
+
b.log.query.mockResolvedValueOnce({ rows: [], truncated: true });
|
|
485
|
+
clock.at += INTERVAL;
|
|
486
|
+
await b.tags.refresh();
|
|
487
|
+
expect(b.markers.read).toHaveBeenCalledTimes(1);
|
|
488
|
+
await b.tags.ensure(["posts"]);
|
|
489
|
+
expect(b.markers.read).toHaveBeenCalledTimes(2);
|
|
490
|
+
});
|
|
491
|
+
// Tracking is per tag, not per entry: storing a new entry must not vouch for
|
|
492
|
+
// an older one with the same tag. B's log cursor starts after C's
|
|
493
|
+
// revalidation, so only reading the marker shows it.
|
|
494
|
+
it("still reads a tag's marker after storing an entry with it", async () => {
|
|
495
|
+
const { clock, instance, a: c } = instances();
|
|
496
|
+
const k1CreatedAt = createdAt();
|
|
497
|
+
await c.tags.update(["posts"], undefined);
|
|
498
|
+
clock.at += 10_000;
|
|
499
|
+
// Started after the revalidation: its log cursor is past C's row.
|
|
500
|
+
const b = instance();
|
|
501
|
+
b.tags.track(["posts"]);
|
|
502
|
+
await b.tags.ensure(["posts"]);
|
|
503
|
+
expect(b.markers.read).toHaveBeenCalledWith(["posts"]);
|
|
504
|
+
expect(b.tags.state(["posts"], k1CreatedAt)).toBe("expired");
|
|
505
|
+
});
|
|
506
|
+
it("still reads a tag's marker after storing an entry with it following a forget", async () => {
|
|
507
|
+
const { clock, a, b } = instances();
|
|
508
|
+
await b.tags.ensure(["posts"]);
|
|
509
|
+
const k1CreatedAt = createdAt();
|
|
510
|
+
// Revalidated while `b` was frozen past what the log covers.
|
|
511
|
+
clock.at += aws_cache_store_1.MAX_REVALIDATION_LOG_GAP_MS + 1;
|
|
512
|
+
a.log.put.mockRejectedValueOnce(new Error("lost"));
|
|
513
|
+
const error = jest.spyOn(console, "error").mockImplementation(() => { });
|
|
514
|
+
await a.tags.update(["posts"], undefined);
|
|
515
|
+
error.mockRestore();
|
|
516
|
+
await b.tags.refresh();
|
|
517
|
+
b.tags.track(["posts"]);
|
|
518
|
+
await b.tags.ensure(["posts"]);
|
|
519
|
+
expect(b.tags.state(["posts"], k1CreatedAt)).toBe("expired");
|
|
520
|
+
});
|
|
521
|
+
it("applies a log row that lands while the tag's first read is in flight", async () => {
|
|
522
|
+
const { clock, a, b } = instances();
|
|
523
|
+
// Something tracked, so the refresh queries the log.
|
|
524
|
+
await b.tags.ensure(["other"]);
|
|
525
|
+
let answer;
|
|
526
|
+
// Answered before the revalidation below, as a read racing it can be.
|
|
527
|
+
b.markers.read.mockImplementationOnce(() => new Promise((resolve) => (answer = resolve)));
|
|
528
|
+
const first = b.tags.ensure(["posts"]);
|
|
529
|
+
await a.tags.update(["posts"], undefined);
|
|
530
|
+
clock.at += INTERVAL;
|
|
531
|
+
await b.tags.refresh();
|
|
532
|
+
answer(new Map());
|
|
533
|
+
await first;
|
|
534
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("expired");
|
|
535
|
+
});
|
|
536
|
+
it("is visible at once on the instance that ran updateTag", async () => {
|
|
537
|
+
const { a } = instances();
|
|
538
|
+
a.tags.track(["posts"]);
|
|
539
|
+
await a.tags.update(["posts"], undefined);
|
|
540
|
+
expect(a.tags.state(["posts"], createdAt())).toBe("expired");
|
|
541
|
+
expect(a.markers.write).toHaveBeenCalledTimes(1);
|
|
542
|
+
expect(a.log.put).toHaveBeenCalledTimes(1);
|
|
543
|
+
});
|
|
544
|
+
it("keeps its tags through a failed query and asks again next interval", async () => {
|
|
545
|
+
const error = jest.spyOn(console, "error").mockImplementation(() => { });
|
|
546
|
+
const { clock, a, b } = instances();
|
|
547
|
+
await b.tags.ensure(["posts"]);
|
|
548
|
+
b.markers.read.mockClear();
|
|
549
|
+
await a.tags.update(["posts"], undefined);
|
|
550
|
+
b.log.query.mockRejectedValueOnce(new Error("throttled"));
|
|
551
|
+
clock.at += INTERVAL;
|
|
552
|
+
const cursor = clock.at - INTERVAL - 5000;
|
|
553
|
+
await b.tags.refresh();
|
|
554
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("fresh");
|
|
555
|
+
expect(error).toHaveBeenCalled();
|
|
556
|
+
clock.at += INTERVAL;
|
|
557
|
+
await b.tags.refresh();
|
|
558
|
+
// From the same cursor, so nothing written meanwhile is skipped.
|
|
559
|
+
expect(b.log.query).toHaveBeenLastCalledWith(cursor);
|
|
560
|
+
expect(b.tags.state(["posts"], createdAt())).toBe("expired");
|
|
561
|
+
expect(b.markers.read).not.toHaveBeenCalled();
|
|
562
|
+
error.mockRestore();
|
|
563
|
+
});
|
|
564
|
+
it("still writes the marker when the log row fails", async () => {
|
|
565
|
+
const error = jest.spyOn(console, "error").mockImplementation(() => { });
|
|
566
|
+
const { a } = instances();
|
|
567
|
+
a.log.put.mockRejectedValueOnce(new Error("throttled"));
|
|
568
|
+
await a.tags.update(["posts"], undefined);
|
|
569
|
+
expect(a.markers.rows.get("posts")?.revalidatedAt).toEqual(expect.any(Number));
|
|
570
|
+
expect(error).toHaveBeenCalledWith(expect.stringMatching(/revalidation log/), expect.any(Error));
|
|
571
|
+
error.mockRestore();
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
describe("EntryLru", () => {
|
|
575
|
+
it("evicts the least recently used entries past its byte bound", () => {
|
|
576
|
+
const lru = new use_cache_common_1.EntryLru(250);
|
|
577
|
+
lru.set("a", stored(100));
|
|
578
|
+
lru.set("b", stored(100));
|
|
579
|
+
lru.get("a");
|
|
580
|
+
lru.set("c", stored(100));
|
|
581
|
+
expect(lru.get("b")).toBeUndefined();
|
|
582
|
+
expect(lru.get("a")).toBeDefined();
|
|
583
|
+
expect(lru.get("c")).toBeDefined();
|
|
584
|
+
});
|
|
585
|
+
it("does not keep an entry larger than the whole bound", () => {
|
|
586
|
+
const lru = new use_cache_common_1.EntryLru(50);
|
|
587
|
+
lru.set("a", stored(100));
|
|
588
|
+
expect(lru.size).toBe(0);
|
|
589
|
+
});
|
|
590
|
+
it("accounts for a replaced entry", () => {
|
|
591
|
+
const lru = new use_cache_common_1.EntryLru(250);
|
|
592
|
+
lru.set("a", stored(200));
|
|
593
|
+
lru.set("a", stored(10));
|
|
594
|
+
lru.set("b", stored(200));
|
|
595
|
+
expect(lru.size).toBe(2);
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
describe("entries", () => {
|
|
599
|
+
it("reads a stream to the end", async () => {
|
|
600
|
+
const bytes = await (0, use_cache_common_1.readStream)(streamOf("ab", "cd"));
|
|
601
|
+
expect(new TextDecoder().decode(bytes)).toBe("abcd");
|
|
602
|
+
});
|
|
603
|
+
it("rejects a stream that errors part-way", async () => {
|
|
604
|
+
const failing = new ReadableStream({
|
|
605
|
+
start(controller) {
|
|
606
|
+
controller.enqueue(new Uint8Array([1]));
|
|
607
|
+
controller.error(new Error("render failed"));
|
|
608
|
+
},
|
|
609
|
+
});
|
|
610
|
+
await expect((0, use_cache_common_1.readStream)(failing)).rejects.toThrow("render failed");
|
|
611
|
+
});
|
|
612
|
+
it("hands every reader its own stream", async () => {
|
|
613
|
+
const entry = {
|
|
614
|
+
value: streamOf("payload"),
|
|
615
|
+
tags: ["t"],
|
|
616
|
+
stale: 1,
|
|
617
|
+
timestamp: 2,
|
|
618
|
+
expire: 3,
|
|
619
|
+
revalidate: 4,
|
|
620
|
+
};
|
|
621
|
+
const kept = await (0, use_cache_common_1.storedEntryOf)(Promise.resolve(entry));
|
|
622
|
+
const first = (0, use_cache_common_1.cacheEntryOf)(kept);
|
|
623
|
+
const second = (0, use_cache_common_1.cacheEntryOf)(kept, -1);
|
|
624
|
+
expect(second.revalidate).toBe(-1);
|
|
625
|
+
expect(first.tags).toEqual(["t"]);
|
|
626
|
+
expect(new TextDecoder().decode(await (0, use_cache_common_1.readStream)(first.value))).toBe("payload");
|
|
627
|
+
expect(new TextDecoder().decode(await (0, use_cache_common_1.readStream)(second.value))).toBe("payload");
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
describe("PendingSets", () => {
|
|
631
|
+
it("holds a get until the set for its key ends", async () => {
|
|
632
|
+
const pending = new use_cache_common_1.PendingSets();
|
|
633
|
+
const done = pending.begin("k");
|
|
634
|
+
let waited = false;
|
|
635
|
+
const wait = pending.wait("k").then(() => (waited = true));
|
|
636
|
+
await Promise.resolve();
|
|
637
|
+
expect(waited).toBe(false);
|
|
638
|
+
done();
|
|
639
|
+
await wait;
|
|
640
|
+
expect(waited).toBe(true);
|
|
641
|
+
// Nothing pending: no wait at all.
|
|
642
|
+
await pending.wait("k");
|
|
643
|
+
await pending.wait("other");
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlLWNhY2hlLWNvbW1vbi50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXIvdXNlLWNhY2hlLWNvbW1vbi50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsc0RBQXNEO0FBQ3RELElBQUksQ0FBQyxJQUFJLENBQUMsMEJBQTBCLENBQUMsQ0FBQztBQUd0Qyx1REFPMkI7QUFDM0IseURBUTRCO0FBRTVCLCtEQUErRDtBQUMvRCxTQUFTLFdBQVcsQ0FBQyxPQUFPLElBQUksR0FBRyxFQUFxQjtJQUN0RCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxJQUFjLEVBQUUsRUFBRTtRQUM1QyxNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBcUIsQ0FBQztRQUMzQyxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDMUIsSUFBSSxHQUFHO2dCQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUMsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FDbkIsS0FBSyxFQUFFLEdBQVcsRUFBRSxFQUFVLEVBQUUsU0FBK0IsRUFBRSxFQUFFO1FBQ2pFLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNmLEdBQUcsQ0FBQyxhQUFhLEdBQUcsRUFBRSxDQUFDO1FBQ3pCLENBQUM7YUFBTSxDQUFDO1lBQ04sR0FBRyxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDakIs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QU8sR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDNUIsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsR0FBRyxTQUFTLENBQUM7WUFDN0IsZ0JBQWdCLEVBQUUsRUFBRSxHQUFHLFFBQVE7WUFDL0IsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDO1NBQ25DLENBQUMsQ0FBQztRQUNILE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDM0IsTUFBTSxNQUFNLEdBQTJCLEVBQUUsQ0FBQztRQUMxQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDN0IsS0FBSyxDQUFDLEVBQUUsSUFBSSxRQUFRLENBQUM7WUFDckIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDM0IsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3ZCLEtBQUssTUFBTSxHQUFHLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO2dCQUMxRCxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3BCLENBQUM7UUFDSCxDQUFDO1FBQ0QsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM1RCxDQUFD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LENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDM0QsTUFBTSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDeEIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMzQixJQUFJLEVBQUUsQ0FBQztRQUNQLE1BQU0sSUFBSSxDQUFDO1FBQ1gsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxQixtQ0FBbUM7UUFDbkMsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hCLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM5QixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzICovXG5qZXN0Lm1vY2soXCJAYXdzLXNkay9jbGllbnQtZHluYW1vZGJcIik7XG5cbmltcG9ydCB0eXBlIHsgQ2FjaGVFbnRyeSB9IGZyb20gXCJuZXh0L2Rpc3Qvc2VydmVyL2xpYi9jYWNoZS1oYW5kbGVycy90eXBlc1wiO1xuaW1wb3J0IHtcbiAgTUFYX1JFVkFMSURBVElPTl9MT0dfR0FQX01TLFxuICBSZXZhbGlkYXRpb25Mb2csXG4gIFJldmFsaWRhdGlvbkxvZ1JvdyxcbiAgVGFnTWFya2VyLFxuICBUYWdNYXJrZXJUYWJsZSxcbiAgVHJhY2tlZFRhZ01hcmtlcnMsXG59IGZyb20gXCIuL2F3cy1jYWNoZS1zdG9yZVwiO1xuaW1wb3J0IHtcbiAgY2FjaGVFbnRyeU9mLFxuICBFbnRyeUxydSxcbiAgbm93LFxuICBQZW5kaW5nU2V0cyxcbiAgcmVhZFN0cmVhbSxcbiAgU3RvcmVkRW50cnksXG4gIHN0b3JlZEVudHJ5T2YsXG59IGZyb20gXCIuL3VzZS1jYWNoZS1jb21tb25cIjtcblxuLyoqIEEgYFRhZ01hcmtlclRhYmxlYCBvdmVyIGEgcGxhaW4gbWFwLCBjb3VudGluZyBpdHMgY2FsbHMuICovXG5mdW5jdGlvbiBmYWtlTWFya2Vycyhyb3dzID0gbmV3IE1hcDxzdHJpbmcsIFRhZ01hcmtlcj4oKSkge1xuICBjb25zdCByZWFkID0gamVzdC5mbihhc3luYyAodGFnczogc3RyaW5nW10pID0+IHtcbiAgICBjb25zdCBmb3VuZCA9IG5ldyBNYXA8c3RyaW5nLCBUYWdNYXJrZXI+KCk7XG4gICAgZm9yIChjb25zdCB0YWcgb2YgdGFncykge1xuICAgICAgY29uc3Qgcm93ID0gcm93cy5nZXQodGFnKTtcbiAgICAgIGlmIChyb3cpIGZvdW5kLnNldCh0YWcsIHsgLi4ucm93IH0pO1xuICAgIH1cbiAgICByZXR1cm4gZm91bmQ7XG4gIH0pO1xuICBjb25zdCB3cml0ZSA9IGplc3QuZm4oXG4gICAgYXN5bmMgKHRhZzogc3RyaW5nLCBhdDogbnVtYmVyLCBkdXJhdGlvbnM/OiB7IGV4cGlyZT86IG51bWJlciB9KSA9PiB7XG4gICAgICBjb25zdCByb3cgPSByb3dzLmdldCh0YWcpID8/IHt9O1xuICAgICAgaWYgKCFkdXJhdGlvbnMpIHtcbiAgICAgICAgcm93LnJldmFsaWRhdGVkQXQgPSBhdDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJvdy5zdGFsZUF0ID0gYXQ7XG4gICAgICAgIGlmIChkdXJhdGlvbnMuZXhwaXJlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICByb3cuZXhwaXJlZEF0ID0gYXQgKyBkdXJhdGlvbnMuZXhwaXJlICogMTAwMDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcm93cy5zZXQodGFnLCByb3cpO1xuICAgICAgLy8gYFJldHVyblZhbHVlczogXCJBTExfTkVXXCJgLCBhcyB0aGUgcmVhbCB0YWJsZSBhbnN3ZXJzLlxuICAgICAgcmV0dXJuIHsgLi4ucm93IH07XG4gICAgfSxcbiAgKTtcbiAgcmV0dXJuIHtcbiAgICByb3dzLFxuICAgIHJlYWQsXG4gICAgd3JpdGUsXG4gICAgdGFibGU6IHsgcmVhZCwgd3JpdGUgfSBhcyB1bmtub3duIGFzIFRhZ01hcmtlclRhYmxlLFxuICB9O1xufVxuXG4vKipcbiAqIEEgYFJldmFsaWRhdGlvbkxvZ2Agb3ZlciBhIHBsYWluIGFycmF5LCBjb3VudGluZyBpdHMgY2FsbHMuIEl0cyBxdWVyeSByZXR1cm5zXG4gKiB3aGF0IHRoZSByZWFsIG9uZSB3b3VsZDogZXZlcnkgcm93IGF0IG9yIGFmdGVyIGBzaW5jZWAsIG9sZGVzdCBmaXJzdC5cbiAqL1xuZnVuY3Rpb24gZmFrZUxvZyhyb3dzOiBSZXZhbGlkYXRpb25Mb2dSb3dbXSA9IFtdKSB7XG4gIGNvbnN0IHB1dCA9IGplc3QuZm4oYXN5bmMgKHRhZzogc3RyaW5nLCBhdDogbnVtYmVyLCBtYXJrZXI6IFRhZ01hcmtlcikgPT4ge1xuICAgIHJvd3MucHVzaCh7XG4gICAgICBzazogYCR7U3RyaW5nKGF0KS5wYWRTdGFydCgxNSwgXCIwXCIpfSMke3RhZ31gLFxuICAgICAgYXQsXG4gICAgICB0YWcsXG4gICAgICBtYXJrZXIsXG4gICAgfSk7XG4gIH0pO1xuICBjb25zdCBxdWVyeSA9IGplc3QuZm4oYXN5bmMgKHNpbmNlOiBudW1iZXIpID0+ICh7XG4gICAgcm93czogcm93cy5maWx0ZXIoKHJvdykgPT4gcm93LmF0ID49IHNpbmNlKS5zb3J0KChhLCBiKSA9PiBhLmF0IC0gYi5hdCksXG4gICAgdHJ1bmNhdGVkOiBmYWxzZSxcbiAgfSkpO1xuICByZXR1cm4ge1xuICAgIHJvd3MsXG4gICAgcHV0LFxuICAgIHF1ZXJ5LFxuICAgIGxvZzogeyBwdXQsIHF1ZXJ5IH0gYXMgdW5rbm93biBhcyBSZXZhbGlkYXRpb25Mb2csXG4gIH07XG59XG5cbi8qKiBBIHdhbGwgY2xvY2sgYSB0ZXN0IG1vdmVzIGJ5IGhhbmQuICovXG5mdW5jdGlvbiBmYWtlQ2xvY2soc3RhcnQgPSAxXzAwMF8wMDApIHtcbiAgY29uc3QgY2xvY2sgPSB7IGF0OiBzdGFydCwgbm93OiAoKSA9PiBjbG9jay5hdCB9O1xuICByZXR1cm4gY2xvY2s7XG59XG5cbmZ1bmN0aW9uIHN0cmVhbU9mKC4uLmNodW5rczogc3RyaW5nW10pOiBSZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5PiB7XG4gIHJldHVybiBuZXcgUmVhZGFibGVTdHJlYW0oe1xuICAgIHN0YXJ0KGNvbnRyb2xsZXIpIHtcbiAgICAgIGZvciAoY29uc3QgY2h1bmsgb2YgY2h1bmtzKSB7XG4gICAgICAgIGNvbnRyb2xsZXIuZW5xdWV1ZShuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoY2h1bmspKTtcbiAgICAgIH1cbiAgICAgIGNvbnRyb2xsZXIuY2xvc2UoKTtcbiAgICB9LFxuICB9KTtcbn1cblxuZnVuY3Rpb24gc3RvcmVkKGJ5dGVzOiBudW1iZXIsIGV4dHJhOiBQYXJ0aWFsPFN0b3JlZEVudHJ5PiA9IHt9KTogU3RvcmVkRW50cnkge1xuICByZXR1cm4ge1xuICAgIHZhbHVlOiBuZXcgVWludDhBcnJheShieXRlcyksXG4gICAgdGFnczogW10sXG4gICAgc3RhbGU6IDMwMCxcbiAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgZXhwaXJlOiAzNjAwLFxuICAgIHJldmFsaWRhdGU6IDkwMCxcbiAgICAuLi5leHRyYSxcbiAgfTtcbn1cblxuZGVzY3JpYmUoXCJUcmFja2VkVGFnTWFya2Vyc1wiLCAoKSA9PiB7XG4gIGl0KFwicmVhZHMgYSB0YWcgdGhlIGZpcnN0IHRpbWUgaXQgaXMgbmVlZGVkLCBhbmQgbm90IGFnYWluXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBtYXJrZXJzID0gZmFrZU1hcmtlcnMobmV3IE1hcChbW1wiYVwiLCB7IHJldmFsaWRhdGVkQXQ6IDUwIH1dXSkpO1xuICAgIGNvbnN0IHRhZ3MgPSBuZXcgVHJhY2tlZFRhZ01hcmtlcnMoe1xuICAgICAgbWFya2VyczogbWFya2Vycy50YWJsZSxcbiAgICAgIGxvZzogZmFrZUxvZygpLmxvZyxcbiAgICB9KTtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKFt0YWdzLmVuc3VyZShbXCJhXCIsIFwiYlwiXSksIHRhZ3MuZW5zdXJlKFtcImFcIiwgXCJiXCJdKV0pO1xuICAgIGF3YWl0IHRhZ3MuZW5zdXJlKFtcImFcIiwgXCJiXCJdKTtcblxuICAgIGV4cGVjdChtYXJrZXJzLnJlYWQpLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygxKTtcbiAgICBleHBlY3QobWFya2Vycy5yZWFkKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChbXCJhXCIsIFwiYlwiXSk7XG4gICAgZXhwZWN0KHRhZ3Muc3RhdGUoW1wiYVwiXSwgNDApKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgICBleHBlY3QodGFncy5zdGF0ZShbXCJhXCJdLCA2MCkpLnRvQmUoXCJmcmVzaFwiKTtcbiAgICBleHBlY3QodGFncy5zdGF0ZShbXCJiXCJdLCA0MCkpLnRvQmUoXCJmcmVzaFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJhcHBsaWVzIGl0cyBvd24gcmV2YWxpZGF0aW9uIGF0IG9uY2UsIGFuZCB3cml0ZXMgaXQgb25jZSBmb3IgYm90aCBoYW5kbGVyc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgbWFya2VycyA9IGZha2VNYXJrZXJzKCk7XG4gICAgY29uc3QgdGFncyA9IG5ldyBUcmFja2VkVGFnTWFya2Vycyh7XG4gICAgICBtYXJrZXJzOiBtYXJrZXJzLnRhYmxlLFxuICAgICAgbG9nOiBmYWtlTG9nKCkubG9nLFxuICAgIH0pO1xuICAgIGNvbnN0IGNyZWF0ZWRBdCA9IERhdGUubm93KCkgLSAxMDAwO1xuXG4gICAgLy8gV2hhdCBOZXh0LmpzIGRvZXM6IGB1cGRhdGVUYWdzYCBvbiB0aGUgZGVmYXVsdCBhbmQgdGhlIHJlbW90ZSBoYW5kbGVyLlxuICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIHRhZ3MudXBkYXRlKFtcImFcIiwgXCJiXCJdLCB7IGV4cGlyZTogMCB9KSxcbiAgICAgIHRhZ3MudXBkYXRlKFtcImFcIiwgXCJiXCJdLCB7IGV4cGlyZTogMCB9KSxcbiAgICBdKTtcblxuICAgIGV4cGVjdChtYXJrZXJzLndyaXRlKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMik7XG4gICAgZXhwZWN0KHRhZ3Muc3RhdGUoW1wiYlwiXSwgY3JlYXRlZEF0KSkudG9CZShcImV4cGlyZWRcIik7XG4gICAgZXhwZWN0KG1hcmtlcnMucm93cy5nZXQoXCJhXCIpKS50b0VxdWFsKHtcbiAgICAgIHN0YWxlQXQ6IGV4cGVjdC5hbnkoTnVtYmVyKSxcbiAgICAgIGV4cGlyZWRBdDogZXhwZWN0LmFueShOdW1iZXIpLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcImdpdmVzIGEgbGF0ZXIgcmV2YWxpZGF0aW9uIGl0cyBvd24gbWFya2VyIHdoaWxlIHRoZSBmaXJzdCBpcyBzdGlsbCB3cml0aW5nXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBtYXJrZXJzID0gZmFrZU1hcmtlcnMoKTtcbiAgICBsZXQgcmVsZWFzZSA9ICgpID0+IHt9O1xuICAgIG1hcmtlcnMud3JpdGUubW9ja0ltcGxlbWVudGF0aW9uT25jZShcbiAgICAgIChfdGFnLCBhdCkgPT5cbiAgICAgICAgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgICByZWxlYXNlID0gKCkgPT4gcmVzb2x2ZSh7IHJldmFsaWRhdGVkQXQ6IGF0IH0pO1xuICAgICAgICB9KSxcbiAgICApO1xuICAgIGNvbnN0IHRhZ3MgPSBuZXcgVHJhY2tlZFRhZ01hcmtlcnMoe1xuICAgICAgbWFya2VyczogbWFya2Vycy50YWJsZSxcbiAgICAgIGxvZzogZmFrZUxvZygpLmxvZyxcbiAgICB9KTtcblxuICAgIGNvbnN0IGZpcnN0ID0gdGFncy51cGRhdGUoW1wieFwiXSwgdW5kZWZpbmVkKTtcbiAgICAvLyBBbm90aGVyIHJlcXVlc3QncyBgcmV2YWxpZGF0ZVRhZygneCcpYCwgYSB0dXJuIGxhdGVyLlxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRJbW1lZGlhdGUocmVzb2x2ZSkpO1xuICAgIGNvbnN0IHNlY29uZCA9IHRhZ3MudXBkYXRlKFtcInhcIl0sIHVuZGVmaW5lZCk7XG4gICAgcmVsZWFzZSgpO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFtmaXJzdCwgc2Vjb25kXSk7XG5cbiAgICBleHBlY3QobWFya2Vycy53cml0ZSkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDIpO1xuICAgIGNvbnN0IFtbLCBmaXJzdEF0XSwgWywgc2Vjb25kQXRdXSA9IG1hcmtlcnMud3JpdGUubW9jay5jYWxscztcbiAgICBleHBlY3Qoc2Vjb25kQXQpLnRvQmVHcmVhdGVyVGhhbihmaXJzdEF0KTtcbiAgfSk7XG5cbiAgaXQoXCJwdXRzIGEgc2xvdyBsb2cgcm93IGFnYWluIHVuZGVyIGEgZnJlc2ggdGltZXN0YW1wLCBzbyByZWFkZXJzIHNlZSBpdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgY2xvY2sgPSBmYWtlQ2xvY2soKTtcbiAgICBjb25zdCBsb2cgPSBmYWtlTG9nKCk7XG4gICAgbG9nLnB1dC5tb2NrSW1wbGVtZW50YXRpb25PbmNlKGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFJlYWRlcnMnIGN1cnNvcnMgaGF2ZSBtb3ZlZCBwYXN0IHRoZSByb3cgYnkgdGhlIHRpbWUgaXQgc2hvd3MuXG4gICAgICBjbG9jay5hdCArPSAxMF8wMDA7XG4gICAgfSk7XG4gICAgY29uc3QgdGFncyA9IG5ldyBUcmFja2VkVGFnTWFya2Vycyh7XG4gICAgICBtYXJrZXJzOiBmYWtlTWFya2VycygpLnRhYmxlLFxuICAgICAgbG9nOiBsb2cubG9nLFxuICAgICAgY2xvY2s6IGNsb2NrLm5vdyxcbiAgICB9KTtcblxuICAgIGV4cGVjdChhd2FpdCB0YWdzLnVwZGF0ZShbXCJ4XCJdLCB1bmRlZmluZWQpKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChsb2cucHV0Lm1vY2suY2FsbHMubWFwKChbLCBhdF0pID0+IGF0KSkudG9FcXVhbChbXG4gICAgICAxXzAwMF8wMDAsIDFfMDEwXzAwMCxcbiAgICBdKTtcbiAgfSk7XG5cbiAgaXQoXCJyZXBvcnRzIGEgbG9nIHJvdyBzbG93IHR3aWNlIGFzIG5vdCByZWNvcmRlZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgY2xvY2sgPSBmYWtlQ2xvY2soKTtcbiAgICBjb25zdCBsb2cgPSBmYWtlTG9nKCk7XG4gICAgbG9nLnB1dC5tb2NrSW1wbGVtZW50YXRpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgY2xvY2suYXQgKz0gMTBfMDAwO1xuICAgIH0pO1xuICAgIGNvbnN0IGVycm9yID0gamVzdC5zcHlPbihjb25zb2xlLCBcImVycm9yXCIpLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiB7fSk7XG4gICAgY29uc3QgdGFncyA9IG5ldyBUcmFja2VkVGFnTWFya2Vycyh7XG4gICAgICBtYXJrZXJzOiBmYWtlTWFya2VycygpLnRhYmxlLFxuICAgICAgbG9nOiBsb2cubG9nLFxuICAgICAgY2xvY2s6IGNsb2NrLm5vdyxcbiAgICB9KTtcblxuICAgIGV4cGVjdChhd2FpdCB0YWdzLnVwZGF0ZShbXCJ4XCJdLCB1bmRlZmluZWQpKS50b0JlKGZhbHNlKTtcbiAgICBleHBlY3QobG9nLnB1dCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDIpO1xuICAgIGVycm9yLm1vY2tSZXN0b3JlKCk7XG4gIH0pO1xuXG4gIGl0KFwidHJhY2tzIHRoZSB3aG9sZSByb3cgaXRzIG93biB3cml0ZSByZXR1cm5zLCBub3QganVzdCB3aGF0IGl0IHNldFwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gQW5vdGhlciBpbnN0YW5jZSdzIGB1cGRhdGVUYWdgIGZvciBhIHRhZyB0aGlzIG9uZSBkb2VzIG5vdCB0cmFjayB5ZXQuXG4gICAgY29uc3QgY3JlYXRlZEF0ID0gRGF0ZS5ub3coKSAtIDEwMDA7XG4gICAgY29uc3QgbWFya2VycyA9IGZha2VNYXJrZXJzKFxuICAgICAgbmV3IE1hcChbW1wicG9zdHNcIiwgeyByZXZhbGlkYXRlZEF0OiBjcmVhdGVkQXQgKyA1MDAgfV1dKSxcbiAgICApO1xuICAgIGNvbnN0IHRhZ3MgPSBuZXcgVHJhY2tlZFRhZ01hcmtlcnMoe1xuICAgICAgbWFya2VyczogbWFya2Vycy50YWJsZSxcbiAgICAgIGxvZzogZmFrZUxvZygpLmxvZyxcbiAgICB9KTtcblxuICAgIGF3YWl0IHRhZ3MudXBkYXRlKFtcInBvc3RzXCJdLCB7IGV4cGlyZTogMzYwMCB9KTtcblxuICAgIC8vIE9sZGVyIHRoYW4gdGhhdCBgdXBkYXRlVGFnYCwgc28gYSBibG9ja2luZyByZW5kZXIsIG5vdCBzdGFsZS13aGlsZS1yZXZhbGlkYXRlLlxuICAgIGV4cGVjdCh0YWdzLnN0YXRlKFtcInBvc3RzXCJdLCBjcmVhdGVkQXQpKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJtYXJrcyBhIHByb2ZpbGUncyByZXZhbGlkYXRpb24gc3RhbGUgdW50aWwgaXRzIGV4cGlyZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgdGFncyA9IG5ldyBUcmFja2VkVGFnTWFya2Vycyh7fSk7XG4gICAgY29uc3QgY3JlYXRlZEF0ID0gRGF0ZS5ub3coKSAtIDEwMDA7XG4gICAgYXdhaXQgdGFncy51cGRhdGUoW1wiYVwiXSwgeyBleHBpcmU6IDM2MDAgfSk7XG4gICAgZXhwZWN0KHRhZ3Muc3RhdGUoW1wiYVwiXSwgY3JlYXRlZEF0KSkudG9CZShcInN0YWxlXCIpO1xuICAgIC8vIE5vdCBhbiBleHBpcmF0aW9uIHlldCwgc28gaW1wbGljaXQgdGFncyBhcmUgbm90IGFmZmVjdGVkIGVpdGhlci5cbiAgICBleHBlY3QodGFncy5leHBpcmF0aW9uKFtcImFcIl0pKS50b0JlKDApO1xuICB9KTtcblxuICAvLyBOZXh0LmpzIHN0YW1wcyBlbnRyaWVzIHdpdGggYHBlcmZvcm1hbmNlLnRpbWVPcmlnaW4gKyBwZXJmb3JtYW5jZS5ub3coKWAsXG4gIC8vIHdoaWNoIGNhbiBydW4gYmVoaW5kIGBEYXRlLm5vdygpYC4gQSBtYXJrZXIgc3RhbXBlZCBvbiB0aGUgd2FsbCBjbG9jayB3b3VsZFxuICAvLyB0aGVuIHBvc3RkYXRlIGFuIGVudHJ5IHJlZ2VuZXJhdGVkIHJpZ2h0IGFmdGVyIHRoZSByZXZhbGlkYXRpb24sIHdoaWNoXG4gIC8vIHdvdWxkIHJlYWQgYXMgcmV2YWxpZGF0ZWQgYWdhaW4sIGFuZCBhZ2Fpbi5cbiAgaXQoXCJzdGFtcHMgbWFya2VycyBvbiB0aGUgY2xvY2sgZW50cmllcyBhcmUgc3RhbXBlZCB3aXRoXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB3YWxsID0gamVzdC5zcHlPbihEYXRlLCBcIm5vd1wiKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4gbm93KCkgKyA1MDApO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB0YWdzID0gbmV3IFRyYWNrZWRUYWdNYXJrZXJzKHt9KTtcbiAgICAgIGF3YWl0IHRhZ3MudXBkYXRlKFtcImFcIl0sIHVuZGVmaW5lZCk7XG4gICAgICBjb25zdCByZWdlbmVyYXRlZCA9IG5vdygpICsgMTtcbiAgICAgIGV4cGVjdCh0YWdzLnN0YXRlKFtcImFcIl0sIHJlZ2VuZXJhdGVkKSkudG9CZShcImZyZXNoXCIpO1xuICAgICAgZXhwZWN0KHRhZ3Muc3RhdGUoW1wiYVwiXSwgcmVnZW5lcmF0ZWQgLSAxMDApKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgd2FsbC5tb2NrUmVzdG9yZSgpO1xuICAgIH1cbiAgfSk7XG5cbiAgaXQoXCJyZXBvcnRzIHRoZSBsYXRlc3QgcGFzdCBleHBpcmF0aW9uIG9mIGltcGxpY2l0IHRhZ3NcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IG1hcmtlcnMgPSBmYWtlTWFya2VycyhcbiAgICAgIG5ldyBNYXA8c3RyaW5nLCBUYWdNYXJrZXI+KFtcbiAgICAgICAgW1wiX05fVF8vYVwiLCB7IHJldmFsaWRhdGVkQXQ6IDEwMCB9XSxcbiAgICAgICAgW1wiX05fVF8vYlwiLCB7IHN0YWxlQXQ6IDE1MCwgZXhwaXJlZEF0OiAyMDAgfV0sXG4gICAgICAgIFtcIl9OX1RfL2NcIiwgeyBzdGFsZUF0OiAxNTAsIGV4cGlyZWRBdDogRGF0ZS5ub3coKSArIDYwXzAwMCB9XSxcbiAgICAgIF0pLFxuICAgICk7XG4gICAgY29uc3QgdGFncyA9IG5ldyBUcmFja2VkVGFnTWFya2Vycyh7XG4gICAgICBtYXJrZXJzOiBtYXJrZXJzLnRhYmxlLFxuICAgICAgbG9nOiBmYWtlTG9nKCkubG9nLFxuICAgIH0pO1xuICAgIGF3YWl0IHRhZ3MuZW5zdXJlKFtcIl9OX1RfL2FcIiwgXCJfTl9UXy9iXCIsIFwiX05fVF8vY1wiLCBcIl9OX1RfL2RcIl0pO1xuICAgIGV4cGVjdCh0YWdzLmV4cGlyYXRpb24oW1wiX05fVF8vYVwiLCBcIl9OX1RfL2JcIiwgXCJfTl9UXy9jXCJdKSkudG9CZSgyMDApO1xuICAgIGV4cGVjdCh0YWdzLmV4cGlyYXRpb24oW1wiX05fVF8vZFwiXSkpLnRvQmUoMCk7XG4gIH0pO1xuXG4gIGl0KFwiZG9lcyBub3QgbGV0IGFuIGV2ZW50dWFsbHkgY29uc2lzdGVudCByZWFkIHVuZG8gaXRzIG93biB3cml0ZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgbWFya2VycyA9IGZha2VNYXJrZXJzKCk7XG4gICAgY29uc3QgdGFncyA9IG5ldyBUcmFja2VkVGFnTWFya2Vycyh7XG4gICAgICBtYXJrZXJzOiBtYXJrZXJzLnRhYmxlLFxuICAgICAgbG9nOiBmYWtlTG9nKCkubG9nLFxuICAgICAgcmVmcmVzaEludGVydmFsTXM6IDAsXG4gICAgfSk7XG4gICAgYXdhaXQgdGFncy51cGRhdGUoW1wiYVwiXSwgdW5kZWZpbmVkKTtcbiAgICAvLyBUaGUgcmVhZCBkb2VzIG5vdCBzaG93IHRoZSB3cml0ZSB5ZXQuXG4gICAgbWFya2Vycy5yb3dzLmNsZWFyKCk7XG4gICAgYXdhaXQgdGFncy5yZWZyZXNoKCk7XG4gICAgZXhwZWN0KHRhZ3Muc3RhdGUoW1wiYVwiXSwgRGF0ZS5ub3coKSAtIDEwMDApKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJ0cmVhdHMgYSBmYWlsZWQgcmVhZCBhcyBmcmVzaCBhbmQgdHJpZXMgYWdhaW4gb24gdGhlIG5leHQgcmVmcmVzaFwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgbWFya2VycyA9IGZha2VNYXJrZXJzKG5ldyBNYXAoW1tcImFcIiwgeyByZXZhbGlkYXRlZEF0OiA1MCB9XV0pKTtcbiAgICBjb25zdCBlcnJvciA9IGplc3Quc3B5T24oY29uc29sZSwgXCJlcnJvclwiKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4ge30pO1xuICAgIG1hcmtlcnMucmVhZC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwidGhyb3R0bGVkXCIpKTtcbiAgICBjb25zdCB0YWdzID0gbmV3IFRyYWNrZWRUYWdNYXJrZXJzKHtcbiAgICAgIG1hcmtlcnM6IG1hcmtlcnMudGFibGUsXG4gICAgICBsb2c6IGZha2VMb2coKS5sb2csXG4gICAgICByZWZyZXNoSW50ZXJ2YWxNczogMCxcbiAgICB9KTtcblxuICAgIGF3YWl0IHRhZ3MuZW5zdXJlKFtcImFcIl0pO1xuICAgIGV4cGVjdCh0YWdzLnN0YXRlKFtcImFcIl0sIDQwKSkudG9CZShcImZyZXNoXCIpO1xuICAgIGF3YWl0IHRhZ3MucmVmcmVzaCgpO1xuICAgIGV4cGVjdCh0YWdzLnN0YXRlKFtcImFcIl0sIDQwKSkudG9CZShcImV4cGlyZWRcIik7XG4gICAgZXJyb3IubW9ja1Jlc3RvcmUoKTtcbiAgfSk7XG5cbiAgaXQoXCJmb3JnZXRzIHRoZSBsZWFzdCByZWNlbnRseSB1c2VkIHRhZyBwYXN0IGl0cyBib3VuZCwgYW5kIHJlYWRzIGl0IGFnYWluXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBtYXJrZXJzID0gZmFrZU1hcmtlcnMoKTtcbiAgICBjb25zdCB0YWdzID0gbmV3IFRyYWNrZWRUYWdNYXJrZXJzKHtcbiAgICAgIG1hcmtlcnM6IG1hcmtlcnMudGFibGUsXG4gICAgICBsb2c6IGZha2VMb2coKS5sb2csXG4gICAgICBtYXhUcmFja2VkVGFnczogMixcbiAgICB9KTtcbiAgICBhd2FpdCB0YWdzLmVuc3VyZShbXCJhXCJdKTtcbiAgICBhd2FpdCB0YWdzLmVuc3VyZShbXCJiXCJdKTtcbiAgICBhd2FpdCB0YWdzLmVuc3VyZShbXCJhXCJdKTsgLy8gYGJgIGlzIG5vdyB0aGUgb2xkZXN0XG4gICAgYXdhaXQgdGFncy5lbnN1cmUoW1wiY1wiXSk7XG4gICAgbWFya2Vycy5yZWFkLm1vY2tDbGVhcigpO1xuXG4gICAgYXdhaXQgdGFncy5lbnN1cmUoW1wiYVwiLCBcImJcIiwgXCJjXCJdKTtcbiAgICBleHBlY3QobWFya2Vycy5yZWFkKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChbXCJiXCJdKTtcbiAgfSk7XG5cbiAgLy8gRXZlcnkgcGF0aCBpcyBhIHRhZyBvZiBpdHMgb3duLCBzbyBhbiBhcHAgb2YgMTAwMCB0YWdnZWQgcGFnZXMgbmVlZHMgMjAwMDpcbiAgLy8gdHJhY2tlZCAxMDAwIGF0IG1vc3QsIGhhbGYgaXRzIHJlcXVlc3RzIHJlLXJlYWQgYW4gZXZpY3RlZCBtYXJrZXIuXG4gIGl0KFwia2VlcHMgMjAwMCB0YWdzIGEgcGFnZSBlYWNoIHRyYWNrZWQsIHdpdGhvdXQgcmVhZGluZyB0aGVtIGFnYWluXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBtYXJrZXJzID0gZmFrZU1hcmtlcnMoKTtcbiAgICBjb25zdCB0YWdzID0gbmV3IFRyYWNrZWRUYWdNYXJrZXJzKHtcbiAgICAgIG1hcmtlcnM6IG1hcmtlcnMudGFibGUsXG4gICAgICBsb2c6IGZha2VMb2coKS5sb2csXG4gICAgfSk7XG4gICAgY29uc3QgcGFnZXMgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiAxMDAwIH0sIChfLCBuKSA9PiBbXG4gICAgICBgaXRlbS0ke259YCxcbiAgICAgIGBfTl9UXy91c2UtY2FjaGUvJHtufWAsXG4gICAgXSk7XG4gICAgZm9yIChjb25zdCBwYWdlIG9mIHBhZ2VzKSBhd2FpdCB0YWdzLmVuc3VyZShwYWdlKTtcbiAgICBtYXJrZXJzLnJlYWQubW9ja0NsZWFyKCk7XG4gICAgZm9yIChjb25zdCBwYWdlIG9mIHBhZ2VzKSBhd2FpdCB0YWdzLmVuc3VyZShwYWdlKTtcbiAgICBleHBlY3QobWFya2Vycy5yZWFkKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICB9KTtcblxuICBpdChcImtlZXBzIHRhZ3MgbG9jYWwgdG8gdGhlIHByb2Nlc3Mgd2l0aG91dCBhIHRhYmxlXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB0YWdzID0gbmV3IFRyYWNrZWRUYWdNYXJrZXJzKHt9KTtcbiAgICBhd2FpdCB0YWdzLmVuc3VyZShbXCJhXCJdKTtcbiAgICBhd2FpdCB0YWdzLnJlZnJlc2goKTtcbiAgICBhd2FpdCB0YWdzLnVwZGF0ZShbXCJhXCJdLCB1bmRlZmluZWQpO1xuICAgIGV4cGVjdCh0YWdzLnN0YXRlKFtcImFcIl0sIERhdGUubm93KCkgLSAxMDAwKSkudG9CZShcImV4cGlyZWRcIik7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwiVHJhY2tlZFRhZ01hcmtlcnMgd2l0aCB0aGUgcmV2YWxpZGF0aW9uIGxvZ1wiLCAoKSA9PiB7XG4gIGNvbnN0IElOVEVSVkFMID0gMTAwMDtcblxuICAvKiogVHdvIGluc3RhbmNlcywgYGFgIGFuZCBgYmAsIG92ZXIgb25lIHRhYmxlIGFuZCBvbmUgY2xvY2suICovXG4gIGZ1bmN0aW9uIGluc3RhbmNlcyhcbiAgICBvcHRpb25zOiB7IHJlc3luY0ludGVydmFsTXM/OiBudW1iZXI7IHJhbmRvbT86ICgpID0+IG51bWJlciB9ID0ge30sXG4gICkge1xuICAgIGNvbnN0IG1hcmtlclJvd3MgPSBuZXcgTWFwPHN0cmluZywgVGFnTWFya2VyPigpO1xuICAgIGNvbnN0IGxvZ1Jvd3M6IFJldmFsaWRhdGlvbkxvZ1Jvd1tdID0gW107XG4gICAgY29uc3QgY2xvY2sgPSBmYWtlQ2xvY2soKTtcbiAgICBjb25zdCBpbnN0YW5jZSA9ICgpID0+IHtcbiAgICAgIGNvbnN0IG1hcmtlcnMgPSBmYWtlTWFya2VycyhtYXJrZXJSb3dzKTtcbiAgICAgIGNvbnN0IGxvZyA9IGZha2VMb2cobG9nUm93cyk7XG4gICAgICBjb25zdCB0YWdzID0gbmV3IFRyYWNrZWRUYWdNYXJrZXJzKHtcbiAgICAgICAgbWFya2VyczogbWFya2Vycy50YWJsZSxcbiAgICAgICAgbG9nOiBsb2cubG9nLFxuICAgICAgICByZWZyZXNoSW50ZXJ2YWxNczogSU5URVJWQUwsXG4gICAgICAgIGNsb2NrOiBjbG9jay5ub3csXG4gICAgICAgIC8vIER1ZSBhdCB0aGUgZnVsbCBpbnRlcnZhbCB1bmxlc3MgYSB0ZXN0IGFza3Mgb3RoZXJ3aXNlLlxuICAgICAgICByYW5kb206ICgpID0+IDAsXG4gICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7IG1hcmtlcnMsIGxvZywgdGFncyB9O1xuICAgIH07XG4gICAgcmV0dXJuIHsgY2xvY2ssIGxvZ1Jvd3MsIGluc3RhbmNlLCBhOiBpbnN0YW5jZSgpLCBiOiBpbnN0YW5jZSgpIH07XG4gIH1cblxuICBjb25zdCBjcmVhdGVkQXQgPSAoKSA9PiBub3coKSAtIDEwMDA7XG5cbiAgaXQoXCJyZWFjaGVzIGFub3RoZXIgaW5zdGFuY2Ugd2l0aGluIG9uZSBpbnRlcnZhbCwgaW4gb25lIFF1ZXJ5IGFuZCBubyBCYXRjaEdldEl0ZW1cIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY2xvY2ssIGEsIGIgfSA9IGluc3RhbmNlcygpO1xuICAgIGF3YWl0IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIl0pO1xuICAgIGIubWFya2Vycy5yZWFkLm1vY2tDbGVhcigpO1xuXG4gICAgYXdhaXQgYS50YWdzLnVwZGF0ZShbXCJwb3N0c1wiXSwgdW5kZWZpbmVkKTtcbiAgICBleHBlY3QoYS5sb2cucHV0KS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgIFwicG9zdHNcIixcbiAgICAgIGNsb2NrLmF0LFxuICAgICAgZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoeyByZXZhbGlkYXRlZEF0OiBleHBlY3QuYW55KE51bWJlcikgfSksXG4gICAgKTtcblxuICAgIGNsb2NrLmF0ICs9IElOVEVSVkFMO1xuICAgIGF3YWl0IGIudGFncy5yZWZyZXNoKCk7XG4gICAgZXhwZWN0KGIudGFncy5zdGF0ZShbXCJwb3N0c1wiXSwgY3JlYXRlZEF0KCkpKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgICBleHBlY3QoYi5sb2cucXVlcnkpLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygxKTtcbiAgICBleHBlY3QoYi5tYXJrZXJzLnJlYWQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gIH0pO1xuXG4gIGl0KFwiaXNzdWVzIG5vIHJlYWQgd2hpbGUgdGhlIGludGVydmFsIGhhcyBub3QgcGFzc2VkXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB7IGNsb2NrLCBiIH0gPSBpbnN0YW5jZXMoKTtcbiAgICAvLyBOb3RoaW5nIHRyYWNrZWQ6IG5vdGhpbmcgdG8gYXNrLlxuICAgIGNsb2NrLmF0ICs9IElOVEVSVkFMO1xuICAgIGF3YWl0IGIudGFncy5yZWZyZXNoKCk7XG4gICAgZXhwZWN0KGIubG9nLnF1ZXJ5KS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuXG4gICAgYXdhaXQgYi50YWdzLmVuc3VyZShbXCJwb3N0c1wiXSk7XG5cbiAgICBiLm1hcmtlcnMucmVhZC5tb2NrQ2xlYXIoKTtcbiAgICAvLyBUaGF0IHJlZnJlc2ggc3RpbGwgY291bnRzOiB3aGF0IGlzIHRyYWNrZWQgc2luY2Ugd2FzIHJlYWQsIG9yIGlzIG5ldy5cbiAgICBhd2FpdCBiLnRhZ3MucmVmcmVzaCgpO1xuICAgIGV4cGVjdChiLmxvZy5xdWVyeSkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcblxuICAgIGNsb2NrLmF0ICs9IElOVEVSVkFMO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFtiLnRhZ3MucmVmcmVzaCgpLCBiLnRhZ3MucmVmcmVzaCgpXSk7XG4gICAgZXhwZWN0KGIubG9nLnF1ZXJ5KS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMSk7XG5cbiAgICBjbG9jay5hdCArPSBJTlRFUlZBTCAtIDE7XG4gICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICBleHBlY3QoYi5sb2cucXVlcnkpLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygxKTtcbiAgICBleHBlY3QoYi5tYXJrZXJzLnJlYWQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG5cbiAgICBjbG9jay5hdCArPSAxO1xuICAgIGF3YWl0IGIudGFncy5yZWZyZXNoKCk7XG4gICAgZXhwZWN0KGIubG9nLnF1ZXJ5KS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMik7XG4gIH0pO1xuXG4gIGl0KFwiYXBwbGllcyBhIHJvdyByZWFkIGFnYWluIGluc2lkZSB0aGUgbG9va2JhY2sgb25seSBvbmNlXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB7IGNsb2NrLCBsb2dSb3dzLCBiIH0gPSBpbnN0YW5jZXMoKTtcbiAgICBhd2FpdCBiLnRhZ3MuZW5zdXJlKFtcInBvc3RzXCJdKTtcbiAgICBiLm1hcmtlcnMucmVhZC5tb2NrQ2xlYXIoKTtcbiAgICBsZXQgcmVhZHMgPSAwO1xuICAgIGNvbnN0IHJvdzogUmV2YWxpZGF0aW9uTG9nUm93ID0ge1xuICAgICAgc2s6IGAke2Nsb2NrLmF0fSNwb3N0c2AsXG4gICAgICBhdDogY2xvY2suYXQsXG4gICAgICB0YWc6IFwicG9zdHNcIixcbiAgICAgIGdldCBtYXJrZXIoKSB7XG4gICAgICAgIHJlYWRzKys7XG4gICAgICAgIHJldHVybiB7IHJldmFsaWRhdGVkQXQ6IG5vdygpIH07XG4gICAgICB9LFxuICAgIH07XG4gICAgLy8gVGhlIHNhbWUgcm93IHR3aWNlIGluIG9uZSBwYWdlLCBhbmQgYWdhaW4gb24gdGhlIG5leHQgcXVlcnkuXG4gICAgbG9nUm93cy5wdXNoKHJvdywgcm93KTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMzsgaSsrKSB7XG4gICAgICBjbG9jay5hdCArPSBJTlRFUlZBTDtcbiAgICAgIGF3YWl0IGIudGFncy5yZWZyZXNoKCk7XG4gICAgfVxuICAgIGV4cGVjdChiLmxvZy5xdWVyeSkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDMpO1xuICAgIGV4cGVjdChyZWFkcykudG9CZSgxKTtcbiAgICBleHBlY3QoYi50YWdzLnN0YXRlKFtcInBvc3RzXCJdLCBjcmVhdGVkQXQoKSkpLnRvQmUoXCJleHBpcmVkXCIpO1xuICB9KTtcblxuICAvLyBSZXBsaWNhdGlvbiBsYWcsIG9yIGEgd3JpdGVyIHdob3NlIGNsb2NrIHJ1bnMgYmVoaW5kOiB0aGUgcm93IHNob3dzIHVwXG4gIC8vIGFmdGVyIGEgcXVlcnkgdGhhdCBzaG91bGQgaGF2ZSBzZWVuIGl0LCB3aXRoIGEgc29ydCBrZXkgYmVmb3JlIGl0LlxuICBpdChcInN0aWxsIHNlZXMgYSByb3cgdGhhdCBhcHBlYXJzIHVwIHRvIHRoZSBsb29rYmFjayBsYXRlXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB7IGNsb2NrLCBsb2dSb3dzLCBiIH0gPSBpbnN0YW5jZXMoKTtcbiAgICBhd2FpdCBiLnRhZ3MuZW5zdXJlKFtcImxhdGVcIiwgXCJ0b28tbGF0ZVwiXSk7XG4gICAgYi5tYXJrZXJzLnJlYWQubW9ja0NsZWFyKCk7XG4gICAgY2xvY2suYXQgKz0gSU5URVJWQUw7XG4gICAgY29uc3QgZmlyc3RRdWVyeSA9IGNsb2NrLmF0O1xuICAgIGF3YWl0IGIudGFncy5yZWZyZXNoKCk7XG5cbiAgICBjb25zdCBtYXJrZXIgPSB7IHJldmFsaWRhdGVkQXQ6IG5vdygpIH07XG4gICAgbG9nUm93cy5wdXNoKFxuICAgICAgeyBzazogXCJsYXRlXCIsIGF0OiBmaXJzdFF1ZXJ5IC0gNTAwMCwgdGFnOiBcImxhdGVcIiwgbWFya2VyIH0sXG4gICAgICB7IHNrOiBcInRvby1sYXRlXCIsIGF0OiBmaXJzdFF1ZXJ5IC0gNTAwMSwgdGFnOiBcInRvby1sYXRlXCIsIG1hcmtlciB9LFxuICAgICk7XG4gICAgY2xvY2suYXQgKz0gSU5URVJWQUw7XG4gICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICBleHBlY3QoYi5sb2cucXVlcnkpLnRvSGF2ZUJlZW5MYXN0Q2FsbGVkV2l0aChmaXJzdFF1ZXJ5IC0gNTAwMCk7XG4gICAgZXhwZWN0KGIudGFncy5zdGF0ZShbXCJsYXRlXCJdLCBjcmVhdGVkQXQoKSkpLnRvQmUoXCJleHBpcmVkXCIpO1xuICAgIC8vIFBhc3QgdGhlIGxvb2tiYWNrOiB3aGF0IHRoZSBwZXJpb2RpYyByZS1yZWFkIG9mIHRoZSBtYXJrZXJzIGlzIGZvci5cbiAgICBleHBlY3QoYi50YWdzLnN0YXRlKFtcInRvby1sYXRlXCJdLCBjcmVhdGVkQXQoKSkpLnRvQmUoXCJmcmVzaFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJmb3JnZXRzIGl0cyB0cmFja2VkIG1hcmtlcnMgYWZ0ZXIgYSBnYXAgdGhlIGxvZyBtYXkgbm90IGNvdmVyLCBhbmQgcmVhZHMgZWFjaCBhcyBpdCBpcyBuZWVkZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY2xvY2ssIGEsIGIgfSA9IGluc3RhbmNlcygpO1xuICAgIGF3YWl0IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIiwgXCJvdGhlclwiXSk7XG4gICAgYXdhaXQgYS50YWdzLnVwZGF0ZShbXCJwb3N0c1wiXSwgdW5kZWZpbmVkKTtcblxuICAgIGNsb2NrLmF0ICs9IE1BWF9SRVZBTElEQVRJT05fTE9HX0dBUF9NUyArIDE7XG4gICAgY29uc3QgZ2FwRW5kID0gY2xvY2suYXQ7XG4gICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICAvLyBObyBidXJzdCBvZiByZS1yZWFkcywgYW5kIG5vIHF1ZXJ5IG9mIGEgbG9nIHRoYXQgbWF5IGhhdmUgbG9zdCByb3dzLlxuICAgIGV4cGVjdChiLm1hcmtlcnMucmVhZCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDEpO1xuICAgIGV4cGVjdChiLmxvZy5xdWVyeSkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcblxuICAgIGF3YWl0IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIl0pO1xuICAgIGV4cGVjdChiLm1hcmtlcnMucmVhZCkudG9IYXZlQmVlbkxhc3RDYWxsZWRXaXRoKFtcInBvc3RzXCJdKTtcbiAgICBleHBlY3QoYi50YWdzLnN0YXRlKFtcInBvc3RzXCJdLCBjcmVhdGVkQXQoKSkpLnRvQmUoXCJleHBpcmVkXCIpO1xuXG4gICAgLy8gVGhlbiBiYWNrIG9uIHRoZSBsb2csIGZyb20ganVzdCBiZWZvcmUgdGhlIGdhcCBlbmRlZC5cbiAgICBjbG9jay5hdCArPSBJTlRFUlZBTDtcbiAgICBhd2FpdCBiLnRhZ3MucmVmcmVzaCgpO1xuICAgIGV4cGVjdChiLmxvZy5xdWVyeSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoZ2FwRW5kIC0gNTAwMCk7XG4gIH0pO1xuXG4gIC8vIFJlLXJlYWRpbmcgZXZlcnkgdHJhY2tlZCBtYXJrZXIgYXQgb25jZSBpcyB+NSwwMDAgUkNVIGF0IDEwLDAwMCB0YWdzOiBtb3JlXG4gIC8vIHRoYW4gdGhlIG9uZSBwYXJ0aXRpb24gc2VydmVzIGluIGEgc2Vjb25kLlxuICBpdChcInJlLXJlYWRzIGVhY2ggdHJhY2tlZCBtYXJrZXIgb25jZSBwZXIgcmVzeW5jIGludGVydmFsLCBhdCBtb3N0IDEwMCBhIHJlZnJlc2hcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY2xvY2ssIGIgfSA9IGluc3RhbmNlcyh7IHJlc3luY0ludGVydmFsTXM6IDEwICogSU5URVJWQUwgfSk7XG4gICAgYXdhaXQgYi50YWdzLmVuc3VyZShBcnJheS5mcm9tKHsgbGVuZ3RoOiAyNTAgfSwgKF8sIGkpID0+IGB0JHtpfWApKTtcbiAgICBiLm1hcmtlcnMucmVhZC5tb2NrQ2xlYXIoKTtcbiAgICBjb25zdCBzaXplczogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8PSAxNDsgaSsrKSB7XG4gICAgICBjbG9jay5hdCArPSBJTlRFUlZBTDtcbiAgICAgIGIubWFya2Vycy5yZWFkLm1vY2tDbGVhcigpO1xuICAgICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICAgIHNpemVzLnB1c2goYi5tYXJrZXJzLnJlYWQubW9jay5jYWxsc1swXT8uWzBdLmxlbmd0aCA/PyAwKTtcbiAgICB9XG4gICAgZXhwZWN0KGIubG9nLnF1ZXJ5KS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMTQpO1xuICAgIC8vIER1ZSBhdCAxMCBpbnRlcnZhbHMsIG9sZGVzdCBmaXJzdCwgMTAwIHBlciByZWZyZXNoOyB0aGVuIG5vdCBhZ2Fpbi5cbiAgICBleHBlY3Qoc2l6ZXMpLnRvRXF1YWwoWzAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDEwMCwgMTAwLCA1MCwgMCwgMF0pO1xuICAgIGV4cGVjdChiLm1hcmtlcnMucmVhZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgfSk7XG5cbiAgLy8gVGFncyBmaXJzdCByZWFkIHRvZ2V0aGVyIG11c3Qgbm90IGNvbWUgZHVlIHRvZ2V0aGVyIGV2ZXJ5IGludGVydmFsLlxuICBpdChcInNwcmVhZHMgd2hlbiBlYWNoIHRhZyBjb21lcyBkdWUgb3ZlciB0aGUgbGFzdCBxdWFydGVyIG9mIHRoZSBpbnRlcnZhbFwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gRHVlIGF0IDEwLCA4Ljc1IGFuZCA3LjUgaW50ZXJ2YWxzLCBrbm93biBpbiB0aGF0IG9yZGVyOiB0aGUgb25lIGR1ZVxuICAgIC8vIGZpcnN0IGlzIGxhc3QsIGJlaGluZCB0d28gdGhhdCBhcmUgbm90IGR1ZSB5ZXQuXG4gICAgY29uc3QgcmFuZG9tcyA9IFswLCAwLjUsIDFdO1xuICAgIGNvbnN0IHsgY2xvY2ssIGIgfSA9IGluc3RhbmNlcyh7XG4gICAgICByZXN5bmNJbnRlcnZhbE1zOiAxMCAqIElOVEVSVkFMLFxuICAgICAgcmFuZG9tOiAoKSA9PiByYW5kb21zLnNoaWZ0KCkgPz8gMCxcbiAgICB9KTtcbiAgICBhd2FpdCBiLnRhZ3MuZW5zdXJlKFtcImxhdGVcIiwgXCJtaWRkbGVcIiwgXCJlYXJseVwiXSk7XG4gICAgYi5tYXJrZXJzLnJlYWQubW9ja0NsZWFyKCk7XG4gICAgY29uc3QgcmVhZEF0OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge307XG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gMTA7IGkrKykge1xuICAgICAgY2xvY2suYXQgKz0gSU5URVJWQUw7XG4gICAgICBiLm1hcmtlcnMucmVhZC5tb2NrQ2xlYXIoKTtcbiAgICAgIGF3YWl0IGIudGFncy5yZWZyZXNoKCk7XG4gICAgICBmb3IgKGNvbnN0IHRhZyBvZiBiLm1hcmtlcnMucmVhZC5tb2NrLmNhbGxzWzBdPy5bMF0gPz8gW10pIHtcbiAgICAgICAgcmVhZEF0W3RhZ10gPz89IGk7XG4gICAgICB9XG4gICAgfVxuICAgIGV4cGVjdChyZWFkQXQpLnRvRXF1YWwoeyBlYXJseTogOCwgbWlkZGxlOiA5LCBsYXRlOiAxMCB9KTtcbiAgfSk7XG5cbiAgaXQoXCJyZS1yZWFkcyBhIG1hcmtlciBpdCBsZWFybmVkIG9mIGZyb20gaXRzIG93biB3cml0ZSBvbmx5IG9uY2UgdGhhdCBpcyBkdWVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY2xvY2ssIGEgfSA9IGluc3RhbmNlcyh7IHJlc3luY0ludGVydmFsTXM6IDEwICogSU5URVJWQUwgfSk7XG4gICAgYXdhaXQgYS50YWdzLmVuc3VyZShbXCJwb3N0c1wiXSk7XG4gICAgY2xvY2suYXQgKz0gOSAqIElOVEVSVkFMO1xuICAgIGF3YWl0IGEudGFncy51cGRhdGUoW1wicG9zdHNcIl0sIHVuZGVmaW5lZCk7XG4gICAgY2xvY2suYXQgKz0gMiAqIElOVEVSVkFMO1xuICAgIGF3YWl0IGEudGFncy5yZWZyZXNoKCk7XG4gICAgLy8gUmVhZCAxMSBpbnRlcnZhbHMgYWdvLCBidXQgd3JpdHRlbiAtIHNvIGtub3duIC0gMiBpbnRlcnZhbHMgYWdvLlxuICAgIGV4cGVjdChhLm1hcmtlcnMucmVhZCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDEpO1xuICB9KTtcblxuICBpdChcInJlYWRzIGEgdGFnIHdob3NlIGZpcnN0IHJlYWQgZmFpbGVkIGFnYWluIG9uIHRoZSBuZXh0IHJlZnJlc2hcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGVycm9yID0gamVzdC5zcHlPbihjb25zb2xlLCBcImVycm9yXCIpLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiB7fSk7XG4gICAgY29uc3QgeyBjbG9jaywgYSwgYiB9ID0gaW5zdGFuY2VzKCk7XG4gICAgLy8gT25seSB0aGUgbWFya2VyIHJvdyBoYXMgaXQsIHNvIG9ubHkgcmVhZGluZyB0aGUgbWFya2VyIGZpbmRzIGl0LlxuICAgIGEubG9nLnB1dC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwidGhyb3R0bGVkXCIpKTtcbiAgICBhd2FpdCBhLnRhZ3MudXBkYXRlKFtcInBvc3RzXCJdLCB1bmRlZmluZWQpO1xuICAgIGIubWFya2Vycy5yZWFkLm1vY2tSZWplY3RlZFZhbHVlT25jZShuZXcgRXJyb3IoXCJ0aHJvdHRsZWRcIikpO1xuICAgIGF3YWl0IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIl0pO1xuICAgIGV4cGVjdChiLnRhZ3Muc3RhdGUoW1wicG9zdHNcIl0sIGNyZWF0ZWRBdCgpKSkudG9CZShcImZyZXNoXCIpO1xuICAgIGNsb2NrLmF0ICs9IElOVEVSVkFMO1xuXG4gICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICBleHBlY3QoYi5tYXJrZXJzLnJlYWQpLnRvSGF2ZUJlZW5MYXN0Q2FsbGVkV2l0aChbXCJwb3N0c1wiXSk7XG4gICAgZXhwZWN0KGIudGFncy5zdGF0ZShbXCJwb3N0c1wiXSwgY3JlYXRlZEF0KCkpKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgICBlcnJvci5tb2NrUmVzdG9yZSgpO1xuICB9KTtcblxuICBpdChcImZvcmdldHMgaXRzIHRyYWNrZWQgbWFya2VycyB3aGVuIHRoZSBsb2cgaGFzIG1vcmUgcm93cyB0aGFuIG9uZSBxdWVyeSByZWFkc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgeyBjbG9jaywgYiB9ID0gaW5zdGFuY2VzKCk7XG4gICAgYXdhaXQgYi50YWdzLmVuc3VyZShbXCJwb3N0c1wiXSk7XG4gICAgYi5sb2cucXVlcnkubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgcm93czogW10sIHRydW5jYXRlZDogdHJ1ZSB9KTtcbiAgICBjbG9jay5hdCArPSBJTlRFUlZBTDtcbiAgICBhd2FpdCBiLnRhZ3MucmVmcmVzaCgpO1xuICAgIGV4cGVjdChiLm1hcmtlcnMucmVhZCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDEpO1xuICAgIGF3YWl0IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIl0pO1xuICAgIGV4cGVjdChiLm1hcmtlcnMucmVhZCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDIpO1xuICB9KTtcblxuICAvLyBUcmFja2luZyBpcyBwZXIgdGFnLCBub3QgcGVyIGVudHJ5OiBzdG9yaW5nIGEgbmV3IGVudHJ5IG11c3Qgbm90IHZvdWNoIGZvclxuICAvLyBhbiBvbGRlciBvbmUgd2l0aCB0aGUgc2FtZSB0YWcuIEIncyBsb2cgY3Vyc29yIHN0YXJ0cyBhZnRlciBDJ3NcbiAgLy8gcmV2YWxpZGF0aW9uLCBzbyBvbmx5IHJlYWRpbmcgdGhlIG1hcmtlciBzaG93cyBpdC5cbiAgaXQoXCJzdGlsbCByZWFkcyBhIHRhZydzIG1hcmtlciBhZnRlciBzdG9yaW5nIGFuIGVudHJ5IHdpdGggaXRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY2xvY2ssIGluc3RhbmNlLCBhOiBjIH0gPSBpbnN0YW5jZXMoKTtcbiAgICBjb25zdCBrMUNyZWF0ZWRBdCA9IGNyZWF0ZWRBdCgpO1xuICAgIGF3YWl0IGMudGFncy51cGRhdGUoW1wicG9zdHNcIl0sIHVuZGVmaW5lZCk7XG4gICAgY2xvY2suYXQgKz0gMTBfMDAwO1xuICAgIC8vIFN0YXJ0ZWQgYWZ0ZXIgdGhlIHJldmFsaWRhdGlvbjogaXRzIGxvZyBjdXJzb3IgaXMgcGFzdCBDJ3Mgcm93LlxuICAgIGNvbnN0IGIgPSBpbnN0YW5jZSgpO1xuICAgIGIudGFncy50cmFjayhbXCJwb3N0c1wiXSk7XG4gICAgYXdhaXQgYi50YWdzLmVuc3VyZShbXCJwb3N0c1wiXSk7XG4gICAgZXhwZWN0KGIubWFya2Vycy5yZWFkKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChbXCJwb3N0c1wiXSk7XG4gICAgZXhwZWN0KGIudGFncy5zdGF0ZShbXCJwb3N0c1wiXSwgazFDcmVhdGVkQXQpKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJzdGlsbCByZWFkcyBhIHRhZydzIG1hcmtlciBhZnRlciBzdG9yaW5nIGFuIGVudHJ5IHdpdGggaXQgZm9sbG93aW5nIGEgZm9yZ2V0XCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB7IGNsb2NrLCBhLCBiIH0gPSBpbnN0YW5jZXMoKTtcbiAgICBhd2FpdCBiLnRhZ3MuZW5zdXJlKFtcInBvc3RzXCJdKTtcbiAgICBjb25zdCBrMUNyZWF0ZWRBdCA9IGNyZWF0ZWRBdCgpO1xuICAgIC8vIFJldmFsaWRhdGVkIHdoaWxlIGBiYCB3YXMgZnJvemVuIHBhc3Qgd2hhdCB0aGUgbG9nIGNvdmVycy5cbiAgICBjbG9jay5hdCArPSBNQVhfUkVWQUxJREFUSU9OX0xPR19HQVBfTVMgKyAxO1xuICAgIGEubG9nLnB1dC5tb2NrUmVqZWN0ZWRWYWx1ZU9uY2UobmV3IEVycm9yKFwibG9zdFwiKSk7XG4gICAgY29uc3QgZXJyb3IgPSBqZXN0LnNweU9uKGNvbnNvbGUsIFwiZXJyb3JcIikubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHt9KTtcbiAgICBhd2FpdCBhLnRhZ3MudXBkYXRlKFtcInBvc3RzXCJdLCB1bmRlZmluZWQpO1xuICAgIGVycm9yLm1vY2tSZXN0b3JlKCk7XG4gICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICBiLnRhZ3MudHJhY2soW1wicG9zdHNcIl0pO1xuICAgIGF3YWl0IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIl0pO1xuICAgIGV4cGVjdChiLnRhZ3Muc3RhdGUoW1wicG9zdHNcIl0sIGsxQ3JlYXRlZEF0KSkudG9CZShcImV4cGlyZWRcIik7XG4gIH0pO1xuXG4gIGl0KFwiYXBwbGllcyBhIGxvZyByb3cgdGhhdCBsYW5kcyB3aGlsZSB0aGUgdGFnJ3MgZmlyc3QgcmVhZCBpcyBpbiBmbGlnaHRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHsgY2xvY2ssIGEsIGIgfSA9IGluc3RhbmNlcygpO1xuICAgIC8vIFNvbWV0aGluZyB0cmFja2VkLCBzbyB0aGUgcmVmcmVzaCBxdWVyaWVzIHRoZSBsb2cuXG4gICAgYXdhaXQgYi50YWdzLmVuc3VyZShbXCJvdGhlclwiXSk7XG4gICAgbGV0IGFuc3dlciE6IChyZWFkOiBNYXA8c3RyaW5nLCBUYWdNYXJrZXI+KSA9PiB2b2lkO1xuICAgIC8vIEFuc3dlcmVkIGJlZm9yZSB0aGUgcmV2YWxpZGF0aW9uIGJlbG93LCBhcyBhIHJlYWQgcmFjaW5nIGl0IGNhbiBiZS5cbiAgICBiLm1hcmtlcnMucmVhZC5tb2NrSW1wbGVtZW50YXRpb25PbmNlKFxuICAgICAgKCkgPT4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IChhbnN3ZXIgPSByZXNvbHZlKSksXG4gICAgKTtcbiAgICBjb25zdCBmaXJzdCA9IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIl0pO1xuICAgIGF3YWl0IGEudGFncy51cGRhdGUoW1wicG9zdHNcIl0sIHVuZGVmaW5lZCk7XG4gICAgY2xvY2suYXQgKz0gSU5URVJWQUw7XG4gICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICBhbnN3ZXIobmV3IE1hcCgpKTtcbiAgICBhd2FpdCBmaXJzdDtcbiAgICBleHBlY3QoYi50YWdzLnN0YXRlKFtcInBvc3RzXCJdLCBjcmVhdGVkQXQoKSkpLnRvQmUoXCJleHBpcmVkXCIpO1xuICB9KTtcblxuICBpdChcImlzIHZpc2libGUgYXQgb25jZSBvbiB0aGUgaW5zdGFuY2UgdGhhdCByYW4gdXBkYXRlVGFnXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCB7IGEgfSA9IGluc3RhbmNlcygpO1xuICAgIGEudGFncy50cmFjayhbXCJwb3N0c1wiXSk7XG4gICAgYXdhaXQgYS50YWdzLnVwZGF0ZShbXCJwb3N0c1wiXSwgdW5kZWZpbmVkKTtcbiAgICBleHBlY3QoYS50YWdzLnN0YXRlKFtcInBvc3RzXCJdLCBjcmVhdGVkQXQoKSkpLnRvQmUoXCJleHBpcmVkXCIpO1xuICAgIGV4cGVjdChhLm1hcmtlcnMud3JpdGUpLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygxKTtcbiAgICBleHBlY3QoYS5sb2cucHV0KS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMSk7XG4gIH0pO1xuXG4gIGl0KFwia2VlcHMgaXRzIHRhZ3MgdGhyb3VnaCBhIGZhaWxlZCBxdWVyeSBhbmQgYXNrcyBhZ2FpbiBuZXh0IGludGVydmFsXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlcnJvciA9IGplc3Quc3B5T24oY29uc29sZSwgXCJlcnJvclwiKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4ge30pO1xuICAgIGNvbnN0IHsgY2xvY2ssIGEsIGIgfSA9IGluc3RhbmNlcygpO1xuICAgIGF3YWl0IGIudGFncy5lbnN1cmUoW1wicG9zdHNcIl0pO1xuICAgIGIubWFya2Vycy5yZWFkLm1vY2tDbGVhcigpO1xuICAgIGF3YWl0IGEudGFncy51cGRhdGUoW1wicG9zdHNcIl0sIHVuZGVmaW5lZCk7XG4gICAgYi5sb2cucXVlcnkubW9ja1JlamVjdGVkVmFsdWVPbmNlKG5ldyBFcnJvcihcInRocm90dGxlZFwiKSk7XG5cbiAgICBjbG9jay5hdCArPSBJTlRFUlZBTDtcbiAgICBjb25zdCBjdXJzb3IgPSBjbG9jay5hdCAtIElOVEVSVkFMIC0gNTAwMDtcbiAgICBhd2FpdCBiLnRhZ3MucmVmcmVzaCgpO1xuICAgIGV4cGVjdChiLnRhZ3Muc3RhdGUoW1wicG9zdHNcIl0sIGNyZWF0ZWRBdCgpKSkudG9CZShcImZyZXNoXCIpO1xuICAgIGV4cGVjdChlcnJvcikudG9IYXZlQmVlbkNhbGxlZCgpO1xuXG4gICAgY2xvY2suYXQgKz0gSU5URVJWQUw7XG4gICAgYXdhaXQgYi50YWdzLnJlZnJlc2goKTtcbiAgICAvLyBGcm9tIHRoZSBzYW1lIGN1cnNvciwgc28gbm90aGluZyB3cml0dGVuIG1lYW53aGlsZSBpcyBza2lwcGVkLlxuICAgIGV4cGVjdChiLmxvZy5xdWVyeSkudG9IYXZlQmVlbkxhc3RDYWxsZWRXaXRoKGN1cnNvcik7XG4gICAgZXhwZWN0KGIudGFncy5zdGF0ZShbXCJwb3N0c1wiXSwgY3JlYXRlZEF0KCkpKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgICBleHBlY3QoYi5tYXJrZXJzLnJlYWQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgZXJyb3IubW9ja1Jlc3RvcmUoKTtcbiAgfSk7XG5cbiAgaXQoXCJzdGlsbCB3cml0ZXMgdGhlIG1hcmtlciB3aGVuIHRoZSBsb2cgcm93IGZhaWxzXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlcnJvciA9IGplc3Quc3B5T24oY29uc29sZSwgXCJlcnJvclwiKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4ge30pO1xuICAgIGNvbnN0IHsgYSB9ID0gaW5zdGFuY2VzKCk7XG4gICAgYS5sb2cucHV0Lm1vY2tSZWplY3RlZFZhbHVlT25jZShuZXcgRXJyb3IoXCJ0aHJvdHRsZWRcIikpO1xuICAgIGF3YWl0IGEudGFncy51cGRhdGUoW1wicG9zdHNcIl0sIHVuZGVmaW5lZCk7XG4gICAgZXhwZWN0KGEubWFya2Vycy5yb3dzLmdldChcInBvc3RzXCIpPy5yZXZhbGlkYXRlZEF0KS50b0VxdWFsKFxuICAgICAgZXhwZWN0LmFueShOdW1iZXIpLFxuICAgICk7XG4gICAgZXhwZWN0KGVycm9yKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvcmV2YWxpZGF0aW9uIGxvZy8pLFxuICAgICAgZXhwZWN0LmFueShFcnJvciksXG4gICAgKTtcbiAgICBlcnJvci5tb2NrUmVzdG9yZSgpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcIkVudHJ5THJ1XCIsICgpID0+IHtcbiAgaXQoXCJldmljdHMgdGhlIGxlYXN0IHJlY2VudGx5IHVzZWQgZW50cmllcyBwYXN0IGl0cyBieXRlIGJvdW5kXCIsICgpID0+IHtcbiAgICBjb25zdCBscnUgPSBuZXcgRW50cnlMcnUoMjUwKTtcbiAgICBscnUuc2V0KFwiYVwiLCBzdG9yZWQoMTAwKSk7XG4gICAgbHJ1LnNldChcImJcIiwgc3RvcmVkKDEwMCkpO1xuICAgIGxydS5nZXQoXCJhXCIpO1xuICAgIGxydS5zZXQoXCJjXCIsIHN0b3JlZCgxMDApKTtcbiAgICBleHBlY3QobHJ1LmdldChcImJcIikpLnRvQmVVbmRlZmluZWQoKTtcbiAgICBleHBlY3QobHJ1LmdldChcImFcIikpLnRvQmVEZWZpbmVkKCk7XG4gICAgZXhwZWN0KGxydS5nZXQoXCJjXCIpKS50b0JlRGVmaW5lZCgpO1xuICB9KTtcblxuICBpdChcImRvZXMgbm90IGtlZXAgYW4gZW50cnkgbGFyZ2VyIHRoYW4gdGhlIHdob2xlIGJvdW5kXCIsICgpID0+IHtcbiAgICBjb25zdCBscnUgPSBuZXcgRW50cnlMcnUoNTApO1xuICAgIGxydS5zZXQoXCJhXCIsIHN0b3JlZCgxMDApKTtcbiAgICBleHBlY3QobHJ1LnNpemUpLnRvQmUoMCk7XG4gIH0pO1xuXG4gIGl0KFwiYWNjb3VudHMgZm9yIGEgcmVwbGFjZWQgZW50cnlcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGxydSA9IG5ldyBFbnRyeUxydSgyNTApO1xuICAgIGxydS5zZXQoXCJhXCIsIHN0b3JlZCgyMDApKTtcbiAgICBscnUuc2V0KFwiYVwiLCBzdG9yZWQoMTApKTtcbiAgICBscnUuc2V0KFwiYlwiLCBzdG9yZWQoMjAwKSk7XG4gICAgZXhwZWN0KGxydS5zaXplKS50b0JlKDIpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcImVudHJpZXNcIiwgKCkgPT4ge1xuICBpdChcInJlYWRzIGEgc3RyZWFtIHRvIHRoZSBlbmRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGJ5dGVzID0gYXdhaXQgcmVhZFN0cmVhbShzdHJlYW1PZihcImFiXCIsIFwiY2RcIikpO1xuICAgIGV4cGVjdChuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoYnl0ZXMpKS50b0JlKFwiYWJjZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJyZWplY3RzIGEgc3RyZWFtIHRoYXQgZXJyb3JzIHBhcnQtd2F5XCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBmYWlsaW5nID0gbmV3IFJlYWRhYmxlU3RyZWFtPFVpbnQ4QXJyYXk+KHtcbiAgICAgIHN0YXJ0KGNvbnRyb2xsZXIpIHtcbiAgICAgICAgY29udHJvbGxlci5lbnF1ZXVlKG5ldyBVaW50OEFycmF5KFsxXSkpO1xuICAgICAgICBjb250cm9sbGVyLmVycm9yKG5ldyBFcnJvcihcInJlbmRlciBmYWlsZWRcIikpO1xuICAgICAgfSxcbiAgICB9KTtcbiAgICBhd2FpdCBleHBlY3QocmVhZFN0cmVhbShmYWlsaW5nKSkucmVqZWN0cy50b1Rocm93KFwicmVuZGVyIGZhaWxlZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJoYW5kcyBldmVyeSByZWFkZXIgaXRzIG93biBzdHJlYW1cIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGVudHJ5OiBDYWNoZUVudHJ5ID0ge1xuICAgICAgdmFsdWU6IHN0cmVhbU9mKFwicGF5bG9hZFwiKSxcbiAgICAgIHRhZ3M6IFtcInRcIl0sXG4gICAgICBzdGFsZTogMSxcbiAgICAgIHRpbWVzdGFtcDogMixcbiAgICAgIGV4cGlyZTogMyxcbiAgICAgIHJldmFsaWRhdGU6IDQsXG4gICAgfTtcbiAgICBjb25zdCBrZXB0ID0gYXdhaXQgc3RvcmVkRW50cnlPZihQcm9taXNlLnJlc29sdmUoZW50cnkpKTtcbiAgICBjb25zdCBmaXJzdCA9IGNhY2hlRW50cnlPZihrZXB0KTtcbiAgICBjb25zdCBzZWNvbmQgPSBjYWNoZUVudHJ5T2Yoa2VwdCwgLTEpO1xuICAgIGV4cGVjdChzZWNvbmQucmV2YWxpZGF0ZSkudG9CZSgtMSk7XG4gICAgZXhwZWN0KGZpcnN0LnRhZ3MpLnRvRXF1YWwoW1widFwiXSk7XG4gICAgZXhwZWN0KG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShhd2FpdCByZWFkU3RyZWFtKGZpcnN0LnZhbHVlKSkpLnRvQmUoXG4gICAgICBcInBheWxvYWRcIixcbiAgICApO1xuICAgIGV4cGVjdChuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoYXdhaXQgcmVhZFN0cmVhbShzZWNvbmQudmFsdWUpKSkudG9CZShcbiAgICAgIFwicGF5bG9hZFwiLFxuICAgICk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwiUGVuZGluZ1NldHNcIiwgKCkgPT4ge1xuICBpdChcImhvbGRzIGEgZ2V0IHVudGlsIHRoZSBzZXQgZm9yIGl0cyBrZXkgZW5kc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcGVuZGluZyA9IG5ldyBQZW5kaW5nU2V0cygpO1xuICAgIGNvbnN0IGRvbmUgPSBwZW5kaW5nLmJlZ2luKFwia1wiKTtcbiAgICBsZXQgd2FpdGVkID0gZmFsc2U7XG4gICAgY29uc3Qgd2FpdCA9IHBlbmRpbmcud2FpdChcImtcIikudGhlbigoKSA9PiAod2FpdGVkID0gdHJ1ZSkpO1xuICAgIGF3YWl0IFByb21pc2UucmVzb2x2ZSgpO1xuICAgIGV4cGVjdCh3YWl0ZWQpLnRvQmUoZmFsc2UpO1xuICAgIGRvbmUoKTtcbiAgICBhd2FpdCB3YWl0O1xuICAgIGV4cGVjdCh3YWl0ZWQpLnRvQmUodHJ1ZSk7XG4gICAgLy8gTm90aGluZyBwZW5kaW5nOiBubyB3YWl0IGF0IGFsbC5cbiAgICBhd2FpdCBwZW5kaW5nLndhaXQoXCJrXCIpO1xuICAgIGF3YWl0IHBlbmRpbmcud2FpdChcIm90aGVyXCIpO1xuICB9KTtcbn0pO1xuIl19
|