@effect-app/infra 2.9.3 → 2.9.5
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 +12 -0
- package/_cjs/Model/Repository/makeRepo.cjs +10 -2
- package/_cjs/Model/Repository/makeRepo.cjs.map +1 -1
- package/_cjs/Store/Cosmos.cjs +9 -3
- package/_cjs/Store/Cosmos.cjs.map +1 -1
- package/_cjs/Store/service.cjs.map +1 -1
- package/_cjs/api/routing.cjs +3 -1
- package/_cjs/api/routing.cjs.map +1 -1
- package/_cjs/api/routing4.cjs +3 -1
- package/_cjs/api/routing4.cjs.map +1 -1
- package/dist/Model/Repository/makeRepo.d.ts +40 -19
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.js +12 -3
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +9 -4
- package/dist/Store/service.d.ts +18 -4
- package/dist/Store/service.d.ts.map +1 -1
- package/dist/Store/service.js +1 -1
- package/dist/adapters/SQL/Model.d.ts +18 -18
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +4 -2
- package/dist/api/routing4.d.ts.map +1 -1
- package/dist/api/routing4.js +4 -2
- package/package.json +1 -1
- package/src/Model/Repository/makeRepo.ts +56 -32
- package/src/Store/Cosmos.ts +8 -3
- package/src/Store/service.ts +19 -3
- package/src/api/routing.ts +1 -0
- package/src/api/routing4.ts +1 -0
- 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
|
@@ -151,7 +151,9 @@ export function makeRepoInternal<
|
|
|
151
151
|
return pipe(
|
|
152
152
|
encodeId({ [idKey]: id } as any),
|
|
153
153
|
Effect.orDie,
|
|
154
|
-
|
|
154
|
+
// we will have idKey because the transform is undone again by the encode schema mumbo jumbo above
|
|
155
|
+
// TODO: make reliable. (Security: isin: PrimaryKey(ISIN), idKey: "isin", does end up with "id")
|
|
156
|
+
Effect.map((_) => (_ as any)[idKey] ?? (_ as any).id),
|
|
155
157
|
Effect.flatMap(findEId)
|
|
156
158
|
)
|
|
157
159
|
}
|
|
@@ -489,6 +491,54 @@ export interface Repos<
|
|
|
489
491
|
|
|
490
492
|
export type GetRepoType<T> = T extends { type: infer R } ? R : never
|
|
491
493
|
|
|
494
|
+
export interface RepositoryOptions<
|
|
495
|
+
IdKey extends keyof T,
|
|
496
|
+
Encoded extends {
|
|
497
|
+
id: string
|
|
498
|
+
},
|
|
499
|
+
T,
|
|
500
|
+
Evt = never,
|
|
501
|
+
RPublish = never,
|
|
502
|
+
E = never,
|
|
503
|
+
RInitial = never,
|
|
504
|
+
RCtx = never
|
|
505
|
+
> {
|
|
506
|
+
/**
|
|
507
|
+
* Specify the idKey of the Type side, if it's different from the default "id".
|
|
508
|
+
* Does not change the Encoded side, which is always "id" to support database drivers.
|
|
509
|
+
* At this time as queries are operating on the Encoded side, the queries must still specify "id" regardless.
|
|
510
|
+
*/
|
|
511
|
+
idKey: IdKey
|
|
512
|
+
/**
|
|
513
|
+
* just in time Migration: for complex migrations that aren't just default simple values
|
|
514
|
+
* use the config.defaultValues instead for simple default values
|
|
515
|
+
*/
|
|
516
|
+
jitM?: (pm: Encoded) => Encoded
|
|
517
|
+
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
518
|
+
partitionValue?: (a: Encoded) => string
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Optional handler to be able to publish events after successfull save.
|
|
522
|
+
*/
|
|
523
|
+
publishEvents?: (evt: NonEmptyReadonlyArray<Evt>) => Effect<void, never, RPublish>
|
|
524
|
+
/**
|
|
525
|
+
* Optional creator for initial data in the table when it's created for the first itme.
|
|
526
|
+
*/
|
|
527
|
+
makeInitial?: Effect<readonly T[], E, RInitial>
|
|
528
|
+
/**
|
|
529
|
+
* Optional context to be provided to Schema decode/encode.
|
|
530
|
+
* Useful for effectful transformations like XWithItems, where items is a transformation retrieving elements from another database table or other source.
|
|
531
|
+
*/
|
|
532
|
+
schemaContext?: Context.Context<RCtx>
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Create a repository instance.
|
|
537
|
+
* @param itemType an identifier used for the table name and e.g NotFoundError
|
|
538
|
+
* @param schema the Schema used for this Repository
|
|
539
|
+
* @param options @see RepositoryOptions
|
|
540
|
+
* @returns a Repository
|
|
541
|
+
*/
|
|
492
542
|
export const makeRepo: {
|
|
493
543
|
<
|
|
494
544
|
ItemType extends string,
|
|
@@ -504,16 +554,7 @@ export const makeRepo: {
|
|
|
504
554
|
>(
|
|
505
555
|
itemType: ItemType,
|
|
506
556
|
schema: S.Schema<T, Encoded, RSchema>,
|
|
507
|
-
options:
|
|
508
|
-
idKey: IdKey
|
|
509
|
-
jitM?: (pm: Encoded) => Encoded
|
|
510
|
-
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
511
|
-
partitionValue?: (a: Encoded) => string
|
|
512
|
-
}
|
|
513
|
-
publishEvents?: (evt: NonEmptyReadonlyArray<Evt>) => Effect<void, never, RPublish>
|
|
514
|
-
makeInitial?: Effect<readonly T[], E, RInitial>
|
|
515
|
-
schemaContext?: Context.Context<RCtx>
|
|
516
|
-
}
|
|
557
|
+
options: RepositoryOptions<IdKey, Encoded, T, Evt, RPublish, E, RInitial, RCtx>
|
|
517
558
|
): Effect.Effect<
|
|
518
559
|
ExtendedRepository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>,
|
|
519
560
|
E,
|
|
@@ -532,15 +573,7 @@ export const makeRepo: {
|
|
|
532
573
|
>(
|
|
533
574
|
itemType: ItemType,
|
|
534
575
|
schema: S.Schema<T, Encoded, RSchema>,
|
|
535
|
-
options:
|
|
536
|
-
jitM?: (pm: Encoded) => Encoded
|
|
537
|
-
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
538
|
-
partitionValue?: (a: Encoded) => string
|
|
539
|
-
}
|
|
540
|
-
publishEvents?: (evt: NonEmptyReadonlyArray<Evt>) => Effect<void, never, RPublish>
|
|
541
|
-
makeInitial?: Effect<readonly T[], E, RInitial>
|
|
542
|
-
schemaContext?: Context.Context<RCtx>
|
|
543
|
-
}
|
|
576
|
+
options: Omit<RepositoryOptions<"id", Encoded, T, Evt, RPublish, E, RInitial, RCtx>, "idKey">
|
|
544
577
|
): Effect.Effect<
|
|
545
578
|
ExtendedRepository<T, Encoded, Evt, ItemType, "id", Exclude<RSchema, RCtx>, RPublish>,
|
|
546
579
|
E,
|
|
@@ -554,22 +587,13 @@ export const makeRepo: {
|
|
|
554
587
|
IdKey extends keyof T,
|
|
555
588
|
E = never,
|
|
556
589
|
RInitial = never,
|
|
557
|
-
|
|
590
|
+
RPublish = never,
|
|
558
591
|
Evt = never,
|
|
559
592
|
RCtx = never
|
|
560
593
|
>(
|
|
561
594
|
itemType: ItemType,
|
|
562
595
|
schema: S.Schema<T, Encoded, R>,
|
|
563
|
-
options: {
|
|
564
|
-
idKey?: IdKey
|
|
565
|
-
jitM?: (pm: Encoded) => Encoded
|
|
566
|
-
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
567
|
-
partitionValue?: (a: Encoded) => string
|
|
568
|
-
}
|
|
569
|
-
publishEvents?: (evt: NonEmptyReadonlyArray<Evt>) => Effect<void, never, R2>
|
|
570
|
-
makeInitial?: Effect<readonly T[], E, RInitial>
|
|
571
|
-
schemaContext?: Context.Context<RCtx>
|
|
572
|
-
}
|
|
596
|
+
options: Omit<RepositoryOptions<IdKey, Encoded, T, Evt, RPublish, E, RInitial, RCtx>, "idKey"> & { idKey?: IdKey }
|
|
573
597
|
) =>
|
|
574
598
|
Effect.gen(function*() {
|
|
575
599
|
const mkRepo = makeRepoInternal<Evt>()(
|
|
@@ -579,7 +603,7 @@ export const makeRepo: {
|
|
|
579
603
|
(e, _etag) => ({ ...e, _etag }),
|
|
580
604
|
options.idKey ?? "id" as any
|
|
581
605
|
)
|
|
582
|
-
const r = yield* mkRepo.make<RInitial, E,
|
|
606
|
+
const r = yield* mkRepo.make<RInitial, E, RPublish, RCtx>(options as any)
|
|
583
607
|
const repo = extendRepo(r)
|
|
584
608
|
return repo
|
|
585
609
|
})
|
package/src/Store/Cosmos.ts
CHANGED
|
@@ -272,7 +272,12 @@ function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
272
272
|
.pipe(Effect
|
|
273
273
|
.withSpan("Cosmos.find [effect-app/infra/Store]", {
|
|
274
274
|
captureStackTrace: false,
|
|
275
|
-
attributes: {
|
|
275
|
+
attributes: {
|
|
276
|
+
"repository.container_id": containerId,
|
|
277
|
+
"repository.model_name": name,
|
|
278
|
+
partitionValue: config?.partitionValue({ id } as Encoded),
|
|
279
|
+
id
|
|
280
|
+
}
|
|
276
281
|
})),
|
|
277
282
|
set: (e) =>
|
|
278
283
|
Option
|
|
@@ -322,7 +327,7 @@ function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
322
327
|
Effect
|
|
323
328
|
.withSpan("Cosmos.set [effect-app/infra/Store]", {
|
|
324
329
|
captureStackTrace: false,
|
|
325
|
-
attributes: { "repository.container_id": containerId, "repository.model_name": name }
|
|
330
|
+
attributes: { "repository.container_id": containerId, "repository.model_name": name, id: e.id }
|
|
326
331
|
})
|
|
327
332
|
),
|
|
328
333
|
batchSet,
|
|
@@ -333,7 +338,7 @@ function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
333
338
|
.pipe(Effect
|
|
334
339
|
.withSpan("Cosmos.remove [effect-app/infra/Store]", {
|
|
335
340
|
captureStackTrace: false,
|
|
336
|
-
attributes: { "repository.container_id": containerId, "repository.model_name": name }
|
|
341
|
+
attributes: { "repository.container_id": containerId, "repository.model_name": name, id: e.id }
|
|
337
342
|
}))
|
|
338
343
|
}
|
|
339
344
|
|
package/src/Store/service.ts
CHANGED
|
@@ -7,12 +7,28 @@ import type { FilterResult } from "../Model/filter/filterApi.js"
|
|
|
7
7
|
import type { FieldValues } from "../Model/filter/types.js"
|
|
8
8
|
import type { FieldPath } from "../Model/filter/types/path/index.js"
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
uniqueKeys?: UniqueKey[]
|
|
12
|
-
maxBulkSize?: number
|
|
10
|
+
export interface StoreConfig<E> {
|
|
13
11
|
partitionValue: (e: E) => string | undefined
|
|
12
|
+
/**
|
|
13
|
+
* Primarily used for testing, creating namespaces in the database to separate data e.g to run multiple tests in isolation within the same database
|
|
14
|
+
* currently only supported in disk/memory. CosmosDB is TODO.
|
|
15
|
+
*/
|
|
14
16
|
allowNamespace?: (namespace: string) => boolean
|
|
17
|
+
/**
|
|
18
|
+
* just in time migrations, supported by the database driver, supporting queries, for simple default values
|
|
19
|
+
*/
|
|
15
20
|
defaultValues?: Partial<E>
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* How many items can be processed in one batch at a time.
|
|
24
|
+
* Defaults to 100 for CosmosDB.
|
|
25
|
+
*/
|
|
26
|
+
maxBulkSize?: number
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Unique indexes, mainly for CosmosDB
|
|
30
|
+
*/
|
|
31
|
+
uniqueKeys?: UniqueKey[]
|
|
16
32
|
}
|
|
17
33
|
|
|
18
34
|
export type SupportedValues = string | boolean | number | null
|
package/src/api/routing.ts
CHANGED
package/src/api/routing4.ts
CHANGED
|
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=
|