@effect-app/infra 2.16.6 → 2.16.7

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.
@@ -36,9 +36,10 @@ const q = make<Something.Encoded>()
36
36
  ),
37
37
  order("displayName"),
38
38
  page({ take: 10 }),
39
+ // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
39
40
  project(
40
41
  S.transformToOrFail(
41
- S.Struct({ id: S.StringId, displayName: S.String }), // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
42
+ S.Struct(Struct.pick(Something.fields, "id", "displayName")),
42
43
  S.Struct(Struct.pick(Something.fields, "id", "displayName")),
43
44
  (_) => Effect.andThen(SomeService, _)
44
45
  )
@@ -84,7 +85,12 @@ it("works", () => {
84
85
  const interpreted = toFilter(q)
85
86
  console.log("interpreted", inspect(interpreted, undefined, 25))
86
87
 
87
- const processed = memFilter(interpreted)(items.map((_) => S.encodeSync(Something)(_)))
88
+ const processed = memFilter(interpreted)(items.map((_) =>
89
+ S.encodeUnknownSync(S.Struct({
90
+ ...Something.omit("displayName"),
91
+ displayName: S.Literal("Verona", "Riley")
92
+ }))(_)
93
+ ))
88
94
 
89
95
  expect(processed).toEqual(items.slice(0, 2).toReversed().map(Struct.pick("id", "displayName")))
90
96
  })
@@ -114,7 +120,6 @@ it("works with repo", () =>
114
120
  yield* somethingRepo.saveAndPublish(items)
115
121
 
116
122
  const q1 = yield* somethingRepo.query(() => q)
117
- // same as above, but with the `flow` helper
118
123
  const q2 = yield* somethingRepo
119
124
  .query(
120
125
  where("displayName", "Verona"),
@@ -124,9 +129,10 @@ it("works with repo", () =>
124
129
  ),
125
130
  order("displayName"),
126
131
  page({ take: 10 }),
132
+ // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
127
133
  project(
128
134
  S.transformToOrFail(
129
- S.Struct({ displayName: S.String }), // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
135
+ S.Struct(Struct.pick(Something.fields, "displayName")),
130
136
  S.Struct(Struct.pick(Something.fields, "displayName")),
131
137
  (_) => Effect.andThen(SomeService, _)
132
138
  )
@@ -156,10 +162,13 @@ it("collect", () =>
156
162
  .query(
157
163
  where("displayName", "Riley"), // TODO: work with To type translation, so Date?
158
164
  // one,
165
+ // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
159
166
  project(
160
167
  S.transformTo(
161
- // TODO: sample case with narrowing down a union?
162
- S.encodedSchema(S.Struct(Struct.pick(Something.fields, "displayName", "n"))), // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
168
+ S.encodedSchema(S.Struct({
169
+ ...Struct.pick(Something.fields, "n"),
170
+ displayName: S.String
171
+ })),
163
172
  S.typeSchema(S.Option(S.String)),
164
173
  (_) =>
165
174
  _.displayName === "Riley" && _.n === "2020-01-01T00:00:00.000Z"
@@ -172,26 +181,39 @@ it("collect", () =>
172
181
  )
173
182
  .toEqual(["Riley-2020-01-01T00:00:00.000Z"])
174
183
 
175
- expect(
176
- yield* somethingRepo
177
- .query(
178
- where("union._tag", "string"),
179
- one,
180
- project(
181
- S.transformTo(
182
- // TODO: sample case with narrowing down a union?
183
- S.encodedSchema(S.Struct(Struct.pick(Something.fields, "union"))), // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
184
- S.typeSchema(S.Option(S.String)),
185
- (_) =>
186
- _.union._tag === "string"
187
- ? Option.some(_.union.value)
188
- : Option.none()
189
- ),
190
- "collect"
191
- )
192
- )
184
+ const queryRes = make<Something.Encoded>().pipe(
185
+ where("union._tag", "string"),
186
+ one
193
187
  )
194
- .toEqual("hi")
188
+
189
+ expectTypeOf(queryRes).toEqualTypeOf<
190
+ QueryEnd<{
191
+ readonly id: string
192
+ readonly displayName: string
193
+ readonly n: string
194
+ readonly union: {
195
+ readonly _tag: "string"
196
+ readonly value: string
197
+ }
198
+ }, "one">
199
+ >()
200
+
201
+ const fromRepo = yield* somethingRepo.query(
202
+ where("union._tag", "string"),
203
+ one,
204
+ project(
205
+ S.Struct({
206
+ union: S.Struct({
207
+ _tag: S.Literal("string"),
208
+ value: S.String
209
+ })
210
+ })
211
+ )
212
+ )
213
+ const value = fromRepo.union.value
214
+
215
+ expectTypeOf(value).toEqualTypeOf<string>()
216
+ expect(value).toEqual("hi")
195
217
  })
196
218
  .pipe(Effect.provide(Layer.mergeAll(SomethingRepo.Test, SomeService.toLayer())), Effect.runPromise))
197
219
 
@@ -229,8 +251,11 @@ it(
229
251
  Effect
230
252
  .gen(function*() {
231
253
  const repo = yield* makeRepo("test", TestUnion, {})
232
- const result = (yield* repo.query(where("id", "123"), and("_tag", "animal"))) satisfies readonly Animal[]
233
- const result2 = (yield* repo.query(where("_tag", "animal"))) satisfies readonly Animal[]
254
+ const result = yield* repo.query(where("id", "123"), and("_tag", "animal"))
255
+ const result2 = yield* repo.query(where("_tag", "animal"))
256
+
257
+ expectTypeOf(result).toEqualTypeOf<readonly Animal[]>()
258
+ expectTypeOf(result2).toEqualTypeOf<readonly Animal[]>()
234
259
 
235
260
  expect(result).toEqual([])
236
261
  expect(result2).toEqual([])
@@ -263,19 +288,34 @@ it(
263
288
  d: S.Unknown
264
289
  }) {}
265
290
 
291
+ // const repo = yield* makeRepo("test", S.Union(AA, BB, CC, DD), {})
292
+
266
293
  type Union = AA | BB | CC | DD
267
294
 
268
295
  const query1 = make<Union>().pipe(
269
296
  where("id", "bla"),
270
297
  and("_tag", "AA")
271
298
  )
272
- expectTypeOf(query1).toEqualTypeOf<QueryWhere<Union, AA>>()
299
+ expectTypeOf(query1).toEqualTypeOf<
300
+ QueryWhere<Union, AA>
301
+ >()
273
302
 
274
303
  const query2 = make<Union>().pipe(
275
304
  where("_tag", "AA")
276
305
  )
277
306
  expectTypeOf(query2).toEqualTypeOf<QueryWhere<Union, AA>>()
278
307
 
308
+ const query2a = make<Union>().pipe(
309
+ where("c", "something")
310
+ )
311
+ expectTypeOf(query2a).toEqualTypeOf<
312
+ QueryWhere<Union, {
313
+ readonly id: string
314
+ readonly _tag: "CC"
315
+ readonly c: {} // from unknown to {} because "something" means that it's not null or undefined
316
+ }>
317
+ >()
318
+
279
319
  const query3 = make<Union>().pipe(
280
320
  where("_tag", "AA"),
281
321
  or(
@@ -283,7 +323,12 @@ it(
283
323
  and("_tag", "BB")
284
324
  )
285
325
  )
286
- expectTypeOf(query3).toEqualTypeOf<QueryWhere<Union, AA | BB>>()
326
+ expectTypeOf(query3).toEqualTypeOf<
327
+ QueryWhere<
328
+ Union,
329
+ AA | BB
330
+ >
331
+ >()
287
332
 
288
333
  const query3b = make<Union>().pipe(
289
334
  where("_tag", "AA"),
@@ -329,7 +374,12 @@ it(
329
374
  and("_tag", "neq", "BB")
330
375
  )
331
376
  )
332
- expectTypeOf(query7).toEqualTypeOf<QueryWhere<Union, AA | CC | DD>>()
377
+ expectTypeOf(query7).toEqualTypeOf<
378
+ QueryWhere<
379
+ Union,
380
+ AA | CC | DD
381
+ >
382
+ >()
333
383
 
334
384
  const query8 = make<Union>().pipe(
335
385
  where("_tag", "neq", "AA"),
@@ -348,7 +398,12 @@ it(
348
398
  )
349
399
  )
350
400
  )
351
- expectTypeOf(query9).toEqualTypeOf<QueryWhere<Union, AA | BB | CC>>()
401
+ expectTypeOf(query9).toEqualTypeOf<
402
+ QueryWhere<
403
+ Union,
404
+ AA | BB | CC
405
+ >
406
+ >()
352
407
 
353
408
  const query10 = make<Union>().pipe(
354
409
  where("id", "AA"),
@@ -361,7 +416,14 @@ it(
361
416
  page({ take: 10 }),
362
417
  count
363
418
  )
364
- expectTypeOf(query10).toEqualTypeOf<QueryProjection<AA | BB, S.NonNegativeInt, never, "count">>()
419
+ expectTypeOf(query10).toEqualTypeOf<
420
+ QueryProjection<
421
+ AA | BB,
422
+ S.NonNegativeInt,
423
+ never,
424
+ "count"
425
+ >
426
+ >()
365
427
 
366
428
  const query11 = make<Union>().pipe(
367
429
  where("id", "AA"),
@@ -374,11 +436,16 @@ it(
374
436
  page({ take: 10 }),
375
437
  one
376
438
  )
377
- expectTypeOf(query11).toEqualTypeOf<QueryEnd<AA | BB, "one">>()
439
+ expectTypeOf(query11).toEqualTypeOf<
440
+ QueryEnd<
441
+ AA | BB,
442
+ "one"
443
+ >
444
+ >()
378
445
 
379
446
  expect([]).toEqual([])
380
447
  })
381
- .pipe(Effect.runPromise)
448
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
382
449
  )
383
450
 
384
451
  it(
@@ -408,14 +475,20 @@ it(
408
475
 
409
476
  type Union = AA | BB | CC | DD
410
477
 
478
+ const repo = yield* makeRepo("test", S.Union(AA, BB, CC, DD), {})
479
+
411
480
  const query1 = make<Union>().pipe(
412
481
  where("id", "AA")
413
482
  )
414
483
  expectTypeOf(query1).toEqualTypeOf<QueryWhere<Union, AA>>()
415
484
 
485
+ const res = yield* repo.query(() => query1)
486
+
487
+ expectTypeOf(res).toEqualTypeOf<readonly AA[]>()
488
+
416
489
  expect([]).toEqual([])
417
490
  })
418
- .pipe(Effect.runPromise)
491
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
419
492
  )
420
493
 
421
494
  it(
@@ -437,7 +510,16 @@ it(
437
510
  {}
438
511
  )
439
512
 
440
- const result = yield* repo.query(where("id", "123"), project(schema))
513
+ const outputSchema = S.Struct({
514
+ id: S.Literal("123"),
515
+ createdAt: S
516
+ .optional(S.Date)
517
+ .pipe(
518
+ S.withDefaults({ constructor: () => new Date(), decoding: () => new Date() })
519
+ )
520
+ })
521
+
522
+ const result = yield* repo.query(where("id", "123"), project(outputSchema))
441
523
 
442
524
  expect(result).toEqual([])
443
525
  })
@@ -473,3 +555,270 @@ it(
473
555
  })
474
556
  .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
475
557
  )
558
+
559
+ it(
560
+ "remove null 1",
561
+ () =>
562
+ Effect
563
+ .gen(function*() {
564
+ const schema = S.Struct({
565
+ id: S.String,
566
+ literals: S.Union(S.Literal("a", "b", "c"), S.Null)
567
+ })
568
+
569
+ type Schema = typeof schema.Type
570
+
571
+ const repo = yield* makeRepo(
572
+ "test",
573
+ schema,
574
+ {}
575
+ )
576
+
577
+ const expected = make<Schema>().pipe(
578
+ where("literals", "neq", null)
579
+ )
580
+ expectTypeOf(expected).toEqualTypeOf<
581
+ QueryWhere<Schema, {
582
+ readonly id: string
583
+ readonly literals: "a" | "b" | "c"
584
+ }>
585
+ >()
586
+
587
+ const result = yield* repo.query(
588
+ where("literals", "neq", null)
589
+ )
590
+
591
+ expectTypeOf(result).toEqualTypeOf<
592
+ readonly {
593
+ readonly id: string
594
+ readonly literals: "a" | "b" | "c"
595
+ }[]
596
+ >()
597
+
598
+ expect(result).toEqual([])
599
+ })
600
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
601
+ )
602
+
603
+ it(
604
+ "remove null 2",
605
+ () =>
606
+ Effect
607
+ .gen(function*() {
608
+ const schema = S.Struct({
609
+ id: S.String,
610
+ literals: S.Union(S.String, S.Null)
611
+ })
612
+
613
+ type Schema = typeof schema.Type
614
+
615
+ const repo = yield* makeRepo(
616
+ "test",
617
+ schema,
618
+ {}
619
+ )
620
+
621
+ const expected = make<Schema>().pipe(
622
+ where("literals", "ciao")
623
+ )
624
+ expectTypeOf(expected).toEqualTypeOf<
625
+ QueryWhere<Schema, {
626
+ readonly id: string
627
+ readonly literals: string
628
+ }>
629
+ >()
630
+
631
+ const result = yield* repo.query(
632
+ where("literals", "neq", null)
633
+ )
634
+
635
+ expectTypeOf(result).toEqualTypeOf<
636
+ readonly {
637
+ readonly id: string
638
+ readonly literals: string
639
+ }[]
640
+ >()
641
+
642
+ expect(result).toEqual([])
643
+ })
644
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
645
+ )
646
+
647
+ it("remove null from one constituent of a tagged union", () =>
648
+ Effect
649
+ .gen(function*() {
650
+ class AA extends S.Class<AA>()({
651
+ id: S.Literal("AA"),
652
+ a: S.String
653
+ }) {}
654
+
655
+ class BB extends S.Class<BB>()({
656
+ id: S.Literal("BB"),
657
+ b: S.NullOr(S.Number)
658
+ }) {}
659
+
660
+ type Union = AA | BB
661
+
662
+ const repo = yield* makeRepo("test", S.Union(AA, BB), {})
663
+
664
+ const query1 = make<Union>().pipe(
665
+ where("id", "AA"),
666
+ or(
667
+ where("b", "neq", null)
668
+ )
669
+ )
670
+
671
+ expectTypeOf(query1).toEqualTypeOf<
672
+ QueryWhere<
673
+ Union,
674
+ AA | {
675
+ readonly id: "BB"
676
+ readonly b: number
677
+ }
678
+ >
679
+ >()
680
+
681
+ const resQuer1 = yield* repo.query(() => query1)
682
+
683
+ expectTypeOf(resQuer1).toEqualTypeOf<
684
+ readonly ({
685
+ readonly id: "AA"
686
+ readonly a: string
687
+ } | {
688
+ readonly id: "BB"
689
+ readonly b: number
690
+ })[]
691
+ >()
692
+ })
693
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
694
+
695
+ it("refine 3", () =>
696
+ Effect
697
+ .gen(function*() {
698
+ class AA extends S.Class<AA>()({
699
+ id: S.Literal("AA"),
700
+ a: S.Unknown
701
+ }) {}
702
+
703
+ class BB extends S.Class<BB>()({
704
+ id: S.Literal("BB"),
705
+ b: S.Unknown
706
+ }) {}
707
+
708
+ class CC extends S.Class<CC>()({
709
+ id: S.Literal("CC"),
710
+ c: S.Unknown
711
+ }) {}
712
+
713
+ class DD extends S.Class<DD>()({
714
+ id: S.Literal("DD"),
715
+ d: S.Unknown
716
+ }) {}
717
+
718
+ type Union = AA | BB | CC | DD
719
+
720
+ const repo = yield* makeRepo("test", S.Union(AA, BB, CC, DD), {})
721
+
722
+ const query1 = make<Union>().pipe(
723
+ where("id", "AA")
724
+ )
725
+
726
+ expectTypeOf(query1).toEqualTypeOf<QueryWhere<Union, AA>>()
727
+
728
+ const resQuer1 = yield* repo.query(where("id", "AA"))
729
+ expectTypeOf(resQuer1).toEqualTypeOf<readonly AA[]>()
730
+ })
731
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
732
+
733
+ it("my test", () =>
734
+ Effect
735
+ .gen(function*() {
736
+ class AA extends S.Class<AA>()({
737
+ id: S.String,
738
+ as: S.Array(S.String)
739
+ }) {}
740
+
741
+ const repo = yield* makeRepo("test", AA, {})
742
+
743
+ const resQuer1 = yield* repo.query(
744
+ where("id", "in", ["id1", "id2"]),
745
+ and(`as.-1`, "startsWith", "a")
746
+ )
747
+ expectTypeOf(resQuer1).toEqualTypeOf<readonly AA[]>()
748
+ })
749
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
750
+
751
+ it("refine inner without imposing a projection", () =>
752
+ Effect
753
+ .gen(function*() {
754
+ class AA extends S.TaggedClass<AA>()("AA", {
755
+ a: S.Unknown
756
+ }) {}
757
+
758
+ class BB extends S.TaggedClass<BB>()("BB", {
759
+ b: S.Unknown
760
+ }) {}
761
+
762
+ class Data extends S.Class<Data>()({
763
+ id: S.String,
764
+ union: S.Union(AA, BB)
765
+ }) {}
766
+
767
+ const repo = yield* makeRepo("data", Data, {})
768
+
769
+ const query1 = make<Data>().pipe(
770
+ where("union._tag", "AA"),
771
+ // I can refine the overall output by providing a proper projection
772
+ // that mimics the internal refinement of the encoding type
773
+ project(S.Struct({ union: AA }))
774
+ )
775
+ expectTypeOf(query1).toEqualTypeOf<
776
+ QueryProjection<
777
+ {
778
+ readonly id: string
779
+ readonly union: AA
780
+ },
781
+ {
782
+ readonly union: AA
783
+ },
784
+ never,
785
+ "many"
786
+ >
787
+ >()
788
+
789
+ const query2 = make<Data>().pipe(
790
+ where("union._tag", "AA"),
791
+ // But if I wanna the whole Data as output ignoring the inner refinement
792
+ // I wanna be able to do so
793
+ project(S.Struct(Data.pick("union")))
794
+ )
795
+
796
+ expectTypeOf(query2).toEqualTypeOf<
797
+ QueryProjection<
798
+ {
799
+ readonly id: string
800
+ readonly union: AA
801
+ },
802
+ {
803
+ readonly union: AA | BB
804
+ },
805
+ never,
806
+ "many"
807
+ >
808
+ >()
809
+
810
+ const resQuer1 = yield* repo.query(() => query1)
811
+ expectTypeOf(resQuer1).toEqualTypeOf<
812
+ readonly {
813
+ readonly union: AA
814
+ }[]
815
+ >()
816
+
817
+ const resQuer2 = yield* repo.query(() => query2)
818
+ expectTypeOf(resQuer2).toEqualTypeOf<
819
+ readonly {
820
+ readonly union: AA | BB
821
+ }[]
822
+ >()
823
+ })
824
+ .pipe(Effect.provide(MemoryStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterApi.test.d.ts","sourceRoot":"","sources":["../filterApi.test.ts"],"names":[],"mappings":""}
@@ -1,37 +0,0 @@
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=