@effect-app/infra 1.7.2 → 1.8.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.
- package/CHANGELOG.md +20 -0
- package/_cjs/api/routing/defaultErrorHandler.cjs +3 -3
- package/_cjs/api/routing/defaultErrorHandler.cjs.map +1 -1
- package/_cjs/api/routing/makeRequestHandler.cjs +2 -2
- package/_cjs/api/routing/makeRequestHandler.cjs.map +1 -1
- package/_cjs/api/routing/match.cjs +3 -1
- package/_cjs/api/routing/match.cjs.map +1 -1
- package/_cjs/errorReporter.cjs +2 -2
- package/_cjs/errorReporter.cjs.map +1 -1
- package/dist/RequestContext.d.ts +5 -4
- package/dist/RequestContext.d.ts.map +1 -1
- package/dist/api/codec.d.ts +1 -1
- package/dist/api/codec.d.ts.map +1 -1
- package/dist/api/routing/defaultErrorHandler.d.ts +2 -2
- package/dist/api/routing/defaultErrorHandler.d.ts.map +1 -1
- package/dist/api/routing/defaultErrorHandler.js +2 -2
- package/dist/api/routing/makeRequestHandler.d.ts +1 -1
- package/dist/api/routing/makeRequestHandler.d.ts.map +1 -1
- package/dist/api/routing/makeRequestHandler.js +3 -3
- package/dist/api/routing/match.d.ts +1 -1
- package/dist/api/routing/match.d.ts.map +1 -1
- package/dist/api/routing/match.js +2 -2
- package/dist/api/routing/schema/jwt.d.ts.map +1 -1
- package/dist/api/routing/schema/routing.d.ts.map +1 -1
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +3 -3
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/services/Emailer/service.d.ts +3 -3
- package/dist/services/Emailer/service.d.ts.map +1 -1
- package/dist/services/Operations.d.ts +14 -14
- package/dist/services/Operations.d.ts.map +1 -1
- package/dist/services/QueueMaker/errors.d.ts +1 -1
- package/dist/services/QueueMaker/errors.d.ts.map +1 -1
- package/dist/services/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/services/Repository/dsl.d.ts +2 -2
- package/dist/services/Repository/dsl.d.ts.map +1 -1
- package/dist/services/Repository/ext.d.ts.map +1 -1
- package/dist/services/RepositoryBase.d.ts +4 -4
- package/dist/services/RepositoryBase.d.ts.map +1 -1
- package/dist/services/RequestContextContainer.d.ts +4 -4
- package/dist/services/RequestContextContainer.d.ts.map +1 -1
- package/dist/services/Store/ContextMapContainer.d.ts +2 -2
- package/dist/services/Store/ContextMapContainer.d.ts.map +1 -1
- package/dist/services/Store/Disk.d.ts.map +1 -1
- package/dist/services/Store/Memory.d.ts.map +1 -1
- package/dist/services/Store/codeFilter.d.ts.map +1 -1
- package/dist/services/Store/service.d.ts +7 -7
- package/dist/services/Store/service.d.ts.map +1 -1
- package/dist/services/Store/utils.d.ts +1 -3
- package/dist/services/Store/utils.d.ts.map +1 -1
- package/dist/services/query/new-kid-interpreter.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/api/routing/defaultErrorHandler.ts +7 -7
- package/src/api/routing/makeRequestHandler.ts +10 -10
- package/src/api/routing/match.ts +6 -7
- package/src/errorReporter.ts +4 -2
- package/vitest.config.ts.timestamp-1711656440838-19c636fe320df.mjs +0 -0
- package/vitest.config.ts.timestamp-1711724061890-6ecedb0a07fdd.mjs +0 -0
- package/vitest.config.ts.timestamp-1711743489537-da8d9e5f66c9f.mjs +0 -0
- package/vitest.config.ts.timestamp-1711744615239-dcf257a844e01.mjs +37 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { logError } from "@effect-app/infra/errorReporter"
|
|
2
2
|
import type { Schema } from "@effect-app/schema"
|
|
3
|
-
import { setBody, setStatus } from "@effect/platform/
|
|
3
|
+
import { setBody, setStatus } from "@effect/platform/HttpServerResponse"
|
|
4
4
|
import { Cause, Data, Effect, S, Schedule } from "effect-app"
|
|
5
5
|
import type { SupportedErrors } from "effect-app/client/errors"
|
|
6
6
|
import {
|
|
@@ -31,9 +31,9 @@ export class JWTError extends Data.TaggedClass("JWTError")<{
|
|
|
31
31
|
const logRequestError = logError("Request")
|
|
32
32
|
|
|
33
33
|
export function defaultBasicErrorHandler<R>(
|
|
34
|
-
_req: HttpServerRequest.
|
|
35
|
-
res: HttpServerResponse.
|
|
36
|
-
r2: Effect<HttpServerResponse.
|
|
34
|
+
_req: HttpServerRequest.HttpServerRequest,
|
|
35
|
+
res: HttpServerResponse.HttpServerResponse,
|
|
36
|
+
r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError, R>
|
|
37
37
|
) {
|
|
38
38
|
const sendError = (code: number) => (body: unknown) =>
|
|
39
39
|
Effect.sync(() => setBody(res, HttpBody.unsafeJson(body)).pipe(setStatus(code)))
|
|
@@ -59,9 +59,9 @@ const optimisticConcurrencySchedule = Schedule.once
|
|
|
59
59
|
&& Schedule.recurWhile<SupportedErrors | JWTError>((a) => a._tag === "OptimisticConcurrencyException")
|
|
60
60
|
|
|
61
61
|
export function defaultErrorHandler<R>(
|
|
62
|
-
req: HttpServerRequest.
|
|
63
|
-
res: HttpServerResponse.
|
|
64
|
-
r2: Effect<HttpServerResponse.
|
|
62
|
+
req: HttpServerRequest.HttpServerRequest,
|
|
63
|
+
res: HttpServerResponse.HttpServerResponse,
|
|
64
|
+
r2: Effect<HttpServerResponse.HttpServerResponse, SupportedErrors | JWTError, R>
|
|
65
65
|
) {
|
|
66
66
|
const r3 = req.method === "PATCH"
|
|
67
67
|
? Effect.retry(r2, optimisticConcurrencySchedule)
|
|
@@ -111,17 +111,17 @@ export function makeRequestHandler<
|
|
|
111
111
|
Config
|
|
112
112
|
>,
|
|
113
113
|
errorHandler: <R>(
|
|
114
|
-
req: HttpServerRequest.
|
|
115
|
-
res: HttpServerResponse.
|
|
116
|
-
r2: Effect<HttpServerResponse.
|
|
117
|
-
) => Effect<HttpServerResponse.
|
|
114
|
+
req: HttpServerRequest.HttpServerRequest,
|
|
115
|
+
res: HttpServerResponse.HttpServerResponse,
|
|
116
|
+
r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | ResE | MiddlewareE, R>
|
|
117
|
+
) => Effect<HttpServerResponse.HttpServerResponse, never, RErr | R>,
|
|
118
118
|
middlewareLayer?: Layer<PR, MiddlewareE, R2>
|
|
119
119
|
): Effect<
|
|
120
|
-
HttpServerResponse.
|
|
120
|
+
HttpServerResponse.HttpServerResponse,
|
|
121
121
|
HttpServerError.RequestError,
|
|
122
122
|
| HttpRouter.RouteContext
|
|
123
123
|
| HttpServerRequest.ParsedSearchParams
|
|
124
|
-
| HttpServerRequest.
|
|
124
|
+
| HttpServerRequest.HttpServerRequest
|
|
125
125
|
| RequestContextContainer
|
|
126
126
|
| ContextMapContainer
|
|
127
127
|
| RequestFiberSet
|
|
@@ -154,7 +154,7 @@ export function makeRequestHandler<
|
|
|
154
154
|
rcx: HttpRouter.RouteContext,
|
|
155
155
|
searchParms: HttpServerRequest.ParsedSearchParams,
|
|
156
156
|
req: Effect.flatMap(
|
|
157
|
-
HttpServerRequest.
|
|
157
|
+
HttpServerRequest.HttpServerRequest,
|
|
158
158
|
(req) => req.json.pipe(Effect.map((body) => ({ body, headers: req.headers })))
|
|
159
159
|
)
|
|
160
160
|
}),
|
|
@@ -171,7 +171,7 @@ export function makeRequestHandler<
|
|
|
171
171
|
|
|
172
172
|
return Effect
|
|
173
173
|
.gen(function*($) {
|
|
174
|
-
const req = yield* $(HttpServerRequest.
|
|
174
|
+
const req = yield* $(HttpServerRequest.HttpServerRequest)
|
|
175
175
|
const res = HttpServerResponse
|
|
176
176
|
.empty()
|
|
177
177
|
.pipe((_) => req.method === "GET" ? HttpServerResponse.setHeader(_, "Cache-Control", "no-store") : _)
|
|
@@ -247,7 +247,7 @@ export function makeRequestHandler<
|
|
|
247
247
|
)
|
|
248
248
|
)
|
|
249
249
|
) as Effect<
|
|
250
|
-
HttpServerResponse.
|
|
250
|
+
HttpServerResponse.HttpServerResponse,
|
|
251
251
|
ValidationError | ResE,
|
|
252
252
|
Exclude<R, EnforceNonEmptyRecord<M>>
|
|
253
253
|
>
|
|
@@ -256,7 +256,7 @@ export function makeRequestHandler<
|
|
|
256
256
|
? Effect.provide(handleRequest, middlewareLayer)
|
|
257
257
|
// PR is not relevant here
|
|
258
258
|
: (handleRequest as Effect<
|
|
259
|
-
HttpServerResponse.
|
|
259
|
+
HttpServerResponse.HttpServerResponse,
|
|
260
260
|
ResE | MiddlewareE | ValidationError,
|
|
261
261
|
Exclude<Exclude<R, EnforceNonEmptyRecord<M>>, PR>
|
|
262
262
|
>)
|
package/src/api/routing/match.ts
CHANGED
|
@@ -51,13 +51,13 @@ export function match<
|
|
|
51
51
|
Config
|
|
52
52
|
>,
|
|
53
53
|
errorHandler: <R>(
|
|
54
|
-
req: HttpServerRequest.
|
|
55
|
-
res: HttpServerResponse.
|
|
56
|
-
r2: Effect<HttpServerResponse.
|
|
54
|
+
req: HttpServerRequest.HttpServerRequest,
|
|
55
|
+
res: HttpServerResponse.HttpServerResponse,
|
|
56
|
+
r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | MiddlewareE | ResE, R>
|
|
57
57
|
) => Effect<
|
|
58
|
-
HttpServerResponse.
|
|
58
|
+
HttpServerResponse.HttpServerResponse,
|
|
59
59
|
never,
|
|
60
|
-
Exclude<RErr | R, HttpServerRequest.
|
|
60
|
+
Exclude<RErr | R, HttpServerRequest.HttpServerRequest | HttpRouter.RouteContext | Scope>
|
|
61
61
|
>,
|
|
62
62
|
middleware?: Middleware<
|
|
63
63
|
R,
|
|
@@ -115,8 +115,7 @@ export function match<
|
|
|
115
115
|
requestHandler.Request.method,
|
|
116
116
|
requestHandler.Request.path,
|
|
117
117
|
handler,
|
|
118
|
-
|
|
119
|
-
requestHandler.Request.method !== "GET" // we don't want commands to be interruptible
|
|
118
|
+
{ uninterruptible: requestHandler.Request.method !== "GET" } // we don't want commands to be interruptible
|
|
120
119
|
)
|
|
121
120
|
// TODO
|
|
122
121
|
// rdesc.push(makeRouteDescriptor(
|
package/src/errorReporter.ts
CHANGED
|
@@ -42,7 +42,8 @@ export function reportError(
|
|
|
42
42
|
__cause__: tryToJson(error),
|
|
43
43
|
__error_name__: name
|
|
44
44
|
})),
|
|
45
|
-
Effect.
|
|
45
|
+
Effect.catchAllCause((cause) => Effect.logError("Failed to log error", cause)),
|
|
46
|
+
Effect.catchAllCause(() => Effect.logError("Failed to log error cause"))
|
|
46
47
|
)
|
|
47
48
|
)
|
|
48
49
|
error[ErrorReported] = true
|
|
@@ -83,7 +84,8 @@ export function logError<E>(
|
|
|
83
84
|
__cause__: tryToJson(error),
|
|
84
85
|
__error_name__: name
|
|
85
86
|
})),
|
|
86
|
-
Effect.
|
|
87
|
+
Effect.catchAllCause((cause) => Effect.logError("Failed to log error", cause)),
|
|
88
|
+
Effect.catchAllCause(() => Effect.logError("Failed to log error cause"))
|
|
87
89
|
)
|
|
88
90
|
)
|
|
89
91
|
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// packages/infra/vitest.config.ts
|
|
2
|
+
import { defineConfig } from "file:///Users/patrickroza/pj/effect-app/libs/node_modules/.pnpm/vite@5.2.6_@types+node@20.11.30/node_modules/vite/dist/node/index.js";
|
|
3
|
+
|
|
4
|
+
// vite.config.base.ts
|
|
5
|
+
import path from "path";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
var __vite_injected_original_dirname = "/Users/patrickroza/pj/effect-app/libs";
|
|
8
|
+
function makeConfig(dirName) {
|
|
9
|
+
const prefix = path.resolve(__vite_injected_original_dirname, "packages");
|
|
10
|
+
const packages = fs.readdirSync(prefix).map((f) => prefix + "/" + f).filter((f) => fs.lstatSync(f).isDirectory());
|
|
11
|
+
const cfg = {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
13
|
+
//plugins: [autoImport],
|
|
14
|
+
test: {
|
|
15
|
+
include: ["./test/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
16
|
+
reporters: "verbose",
|
|
17
|
+
globals: true
|
|
18
|
+
},
|
|
19
|
+
resolve: {
|
|
20
|
+
alias: packages.reduce((acc, cur) => {
|
|
21
|
+
acc[JSON.parse(fs.readFileSync(cur + "/package.json", "utf-8")).name] = path.resolve(cur, cur.endsWith("core") ? "dist" : "src");
|
|
22
|
+
return acc;
|
|
23
|
+
}, {})
|
|
24
|
+
// "@effect-app/core/Prelude": path.join(__dirname, "packages/core/src/Prelude.code.ts")
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
console.log(cfg);
|
|
28
|
+
return cfg;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// packages/infra/vitest.config.ts
|
|
32
|
+
var __vite_injected_original_dirname2 = "/Users/patrickroza/pj/effect-app/libs/packages/infra";
|
|
33
|
+
var vitest_config_default = defineConfig(makeConfig(__vite_injected_original_dirname2));
|
|
34
|
+
export {
|
|
35
|
+
vitest_config_default as default
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsicGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50cyIsICJ2aXRlLmNvbmZpZy5iYXNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYVwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYS92aXRlc3QuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvcGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gXCJ2aXRlXCJcbmltcG9ydCBtYWtlQ29uZmlnIGZyb20gXCIuLi8uLi92aXRlLmNvbmZpZy5iYXNlXCJcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKG1ha2VDb25maWcoX19kaXJuYW1lKSlcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlic1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy92aXRlLmNvbmZpZy5iYXNlLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvdml0ZS5jb25maWcuYmFzZS50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCJcbmltcG9ydCBmcyBmcm9tIFwiZnNcIlxuaW1wb3J0IEF1dG9JbXBvcnQgZnJvbSBcInVucGx1Z2luLWF1dG8taW1wb3J0L3ZpdGVcIlxuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInZpdGVzdC9jb25maWdcIlxuXG4vLyBjb25zdCBhdXRvSW1wb3J0ID0gQXV0b0ltcG9ydCh7XG4vLyAgIGR0czogXCIuL3Rlc3QvYXV0by1pbXBvcnRzLmQudHNcIixcbi8vICAgLy8gaW5jbHVkZTogW1xuLy8gICAvLyAgIC9cXC50ZXN0XFwuW3RqXXN4PyQvIC8vIC50cywgLnRzeCwgLmpzLCAuanN4XG4vLyAgIC8vIF0sXG4vLyAgIGltcG9ydHM6IFtcbi8vICAgICBcInZpdGVzdFwiXG4vLyAgIF1cbi8vIH0pXG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIG1ha2VDb25maWcoZGlyTmFtZT86IHN0cmluZykge1xuICBjb25zdCBwcmVmaXggPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBcInBhY2thZ2VzXCIpXG4gIGNvbnN0IHBhY2thZ2VzID0gZnMucmVhZGRpclN5bmMocHJlZml4KS5tYXAoZiA9PiBwcmVmaXggKyBcIi9cIiArIGYpLmZpbHRlcihmID0+IGZzLmxzdGF0U3luYyhmKS5pc0RpcmVjdG9yeSgpIClcbiAgY29uc3QgY2ZnID0ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdmFyLXJlcXVpcmVzXG4gICAgLy9wbHVnaW5zOiBbYXV0b0ltcG9ydF0sXG4gICAgdGVzdDoge1xuICAgICAgaW5jbHVkZTogIFtcIi4vdGVzdC8qKi8qLnRlc3Que2pzLG1qcyxjanMsdHMsbXRzLGN0cyxqc3gsdHN4fVwiXSxcbiAgICAgIHJlcG9ydGVyczogXCJ2ZXJib3NlXCIsXG4gICAgICBnbG9iYWxzOiB0cnVlXG4gICAgfSxcbiAgICByZXNvbHZlOiB7XG4gICAgICBhbGlhczogcGFja2FnZXMucmVkdWNlKChhY2MsIGN1cikgPT4geyAvLyB3b3JrYXJvdW5kIGZvciAvUHJlbHVkZSBpc3N1ZVxuICAgICAgYWNjW0pTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKGN1ciArIFwiL3BhY2thZ2UuanNvblwiLCBcInV0Zi04XCIpKS5uYW1lXSA9IHBhdGgucmVzb2x2ZShjdXIsIGN1ci5lbmRzV2l0aChcImNvcmVcIikgPyBcImRpc3RcIiA6IFwic3JjXCIpXG4gICAgICByZXR1cm4gYWNjXG4gICAgfSwgeyB9KSAvLyBcIkBlZmZlY3QtYXBwL2NvcmUvUHJlbHVkZVwiOiBwYXRoLmpvaW4oX19kaXJuYW1lLCBcInBhY2thZ2VzL2NvcmUvc3JjL1ByZWx1ZGUuY29kZS50c1wiKVxuICB9XG4gIH1cbiAgY29uc29sZS5sb2coY2ZnKVxuICByZXR1cm4gY2ZnXG59XG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQ0EsU0FBUyxvQkFBb0I7OztBQ0E3QixPQUFPLFVBQVU7QUFDakIsT0FBTyxRQUFRO0FBRmYsSUFBTSxtQ0FBbUM7QUFnQjFCLFNBQVIsV0FBNEIsU0FBa0I7QUFDbkQsUUFBTSxTQUFTLEtBQUssUUFBUSxrQ0FBVyxVQUFVO0FBQ2pELFFBQU0sV0FBVyxHQUFHLFlBQVksTUFBTSxFQUFFLElBQUksT0FBSyxTQUFTLE1BQU0sQ0FBQyxFQUFFLE9BQU8sT0FBSyxHQUFHLFVBQVUsQ0FBQyxFQUFFLFlBQVksQ0FBRTtBQUM3RyxRQUFNLE1BQU07QUFBQTtBQUFBO0FBQUEsSUFHVixNQUFNO0FBQUEsTUFDSixTQUFVLENBQUMsa0RBQWtEO0FBQUEsTUFDN0QsV0FBVztBQUFBLE1BQ1gsU0FBUztBQUFBLElBQ1g7QUFBQSxJQUNBLFNBQVM7QUFBQSxNQUNQLE9BQU8sU0FBUyxPQUFPLENBQUMsS0FBSyxRQUFRO0FBQ3JDLFlBQUksS0FBSyxNQUFNLEdBQUcsYUFBYSxNQUFNLGlCQUFpQixPQUFPLENBQUMsRUFBRSxJQUFJLElBQUksS0FBSyxRQUFRLEtBQUssSUFBSSxTQUFTLE1BQU0sSUFBSSxTQUFTLEtBQUs7QUFDL0gsZUFBTztBQUFBLE1BQ1QsR0FBRyxDQUFFLENBQUM7QUFBQTtBQUFBLElBQ1I7QUFBQSxFQUNBO0FBQ0EsVUFBUSxJQUFJLEdBQUc7QUFDZixTQUFPO0FBQ1Q7OztBRHBDQSxJQUFNQSxvQ0FBbUM7QUFJekMsSUFBTyx3QkFBUSxhQUFhLFdBQVdDLGlDQUFTLENBQUM7IiwKICAibmFtZXMiOiBbIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIiwgIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIl0KfQo=
|