@rindle/client 0.1.0-rc.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.
Files changed (58) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +65 -0
  3. package/dist/ast.d.ts +83 -0
  4. package/dist/ast.d.ts.map +1 -0
  5. package/dist/ast.js +5 -0
  6. package/dist/ast.js.map +1 -0
  7. package/dist/compare.d.ts +17 -0
  8. package/dist/compare.d.ts.map +1 -0
  9. package/dist/compare.js +81 -0
  10. package/dist/compare.js.map +1 -0
  11. package/dist/index.d.ts +12 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +13 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/key.d.ts +2 -0
  16. package/dist/key.d.ts.map +1 -0
  17. package/dist/key.js +26 -0
  18. package/dist/key.js.map +1 -0
  19. package/dist/operators.d.ts +39 -0
  20. package/dist/operators.d.ts.map +1 -0
  21. package/dist/operators.js +45 -0
  22. package/dist/operators.js.map +1 -0
  23. package/dist/query.d.ts +280 -0
  24. package/dist/query.d.ts.map +1 -0
  25. package/dist/query.js +348 -0
  26. package/dist/query.js.map +1 -0
  27. package/dist/schema.d.ts +111 -0
  28. package/dist/schema.d.ts.map +1 -0
  29. package/dist/schema.js +92 -0
  30. package/dist/schema.js.map +1 -0
  31. package/dist/ssr.d.ts +73 -0
  32. package/dist/ssr.d.ts.map +1 -0
  33. package/dist/ssr.js +66 -0
  34. package/dist/ssr.js.map +1 -0
  35. package/dist/store.d.ts +90 -0
  36. package/dist/store.d.ts.map +1 -0
  37. package/dist/store.js +225 -0
  38. package/dist/store.js.map +1 -0
  39. package/dist/types.d.ts +250 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +20 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/view.d.ts +88 -0
  44. package/dist/view.d.ts.map +1 -0
  45. package/dist/view.js +294 -0
  46. package/dist/view.js.map +1 -0
  47. package/package.json +36 -0
  48. package/src/ast.ts +94 -0
  49. package/src/compare.ts +85 -0
  50. package/src/index.ts +57 -0
  51. package/src/key.ts +23 -0
  52. package/src/operators.ts +68 -0
  53. package/src/query.ts +734 -0
  54. package/src/schema.ts +181 -0
  55. package/src/ssr.ts +115 -0
  56. package/src/store.ts +279 -0
  57. package/src/types.ts +234 -0
  58. package/src/view.ts +348 -0
@@ -0,0 +1,250 @@
1
+ /** A bare wire cell. (JSON columns arrive as their raw JSON string.) */
2
+ export type WireValue = number | string | boolean | null;
3
+ /** Declared column type (from the typed schema) — drives the comparator + JSON parsing. */
4
+ export type ColType = "string" | "number" | "boolean" | "json";
5
+ /** A scalar-projection annotation on a relationship slot (REDUCE-DESIGN.md §9): a
6
+ * relationship aggregate (`issue { commentCount: count(comments) }`) lives as a singular
7
+ * one-row relationship whose child is the aggregate row; this tells the receiver to unwrap
8
+ * it into a scalar field — `commentCount: 5` instead of `commentCount: [{ count: 5 }]`. */
9
+ export interface WireProjection {
10
+ /** Which CHILD column to surface as the scalar value (the aggregate column). */
11
+ col: number;
12
+ /** The value to emit when the relationship is empty (a childless parent) — the
13
+ * aggregate identity (`0` for count, `null` for sum/avg). */
14
+ identity: WireValue;
15
+ }
16
+ export interface WireRel {
17
+ name: string;
18
+ slot: number;
19
+ /** `null` ⇒ an out-of-view / gating slot (the in-view gate drops `Child`s addressed here). */
20
+ child: WireSchema | null;
21
+ /** Non-null ⇒ a scalar-projected relationship aggregate the receiver unwraps to a scalar
22
+ * (REDUCE-DESIGN.md §9). Absent/`null` for an ordinary (plural or `.one()`) relationship. */
23
+ project?: WireProjection | null;
24
+ }
25
+ export interface WireSchema {
26
+ columns: string[];
27
+ primaryKey: number[];
28
+ /** Resolved, PK-completed sort: `[columnIndex, ascending]` pairs (the comparator input). */
29
+ sort: [number, boolean][];
30
+ singular: boolean;
31
+ relationships: WireRel[];
32
+ }
33
+ export interface WireNode {
34
+ row: WireValue[];
35
+ rels: {
36
+ rel: number;
37
+ children: WireNode[];
38
+ }[];
39
+ }
40
+ export interface PathSeg {
41
+ rel: number;
42
+ parentRow: WireValue[];
43
+ }
44
+ export type FlatOp = {
45
+ tag: "add";
46
+ node: WireNode;
47
+ } | {
48
+ tag: "remove";
49
+ row: WireValue[];
50
+ } | {
51
+ tag: "edit";
52
+ old: WireValue[];
53
+ new: WireValue[];
54
+ };
55
+ export interface FlatChange {
56
+ path: PathSeg[];
57
+ op: FlatOp;
58
+ }
59
+ /**
60
+ * What a {@link Backend} pushes per query: the handshake (`hello`), the (possibly
61
+ * chunked) hydrate `snapshot`, then incremental `batch`es. The core builds an ArrayView
62
+ * on `hello`, hydrates on `snapshot`, folds on `batch` — identically for any backend.
63
+ */
64
+ export type ChangeEvent = {
65
+ type: "hello";
66
+ schema: WireSchema;
67
+ comparatorVersion: number;
68
+ } | {
69
+ type: "snapshot";
70
+ adds: FlatChange[];
71
+ last: boolean;
72
+ } | {
73
+ type: "batch";
74
+ events: FlatChange[];
75
+ };
76
+ export type Mutation = {
77
+ op: "add";
78
+ table: string;
79
+ row: WireValue[];
80
+ } | {
81
+ op: "remove";
82
+ table: string;
83
+ row: WireValue[];
84
+ } | {
85
+ op: "edit";
86
+ table: string;
87
+ old: WireValue[];
88
+ new: WireValue[];
89
+ };
90
+ /**
91
+ * A table-tagged, path-free row delta — the **normalized** wire payload (the path-free twin
92
+ * of {@link FlatChange}; NORMALIZED-CHANGES-DESIGN.md §3). Rows are positional (bare cells; a
93
+ * json column is its raw JSON string). `op` is the discriminant. Lives here (not in
94
+ * `@rindle/normalized`) so both the protocol (`@rindle/remote`) and the sync layer share one type.
95
+ */
96
+ export type NormalizedOp = {
97
+ table: string;
98
+ op: "add";
99
+ row: WireValue[];
100
+ } | {
101
+ table: string;
102
+ op: "remove";
103
+ row: WireValue[];
104
+ } | {
105
+ table: string;
106
+ op: "edit";
107
+ old: WireValue[];
108
+ new: WireValue[];
109
+ };
110
+ /** One base table's flat schema on the normalized `hello` (§3): column names (in order) +
111
+ * primary-key column indices. Wire rows are positional against `columns`. */
112
+ export interface NormalizedTableSchema {
113
+ name: string;
114
+ columns: string[];
115
+ primaryKey: number[];
116
+ }
117
+ /**
118
+ * A per-query NORMALIZED stream event — the path-free twin of {@link ChangeEvent}. The
119
+ * `hello` carries the flat per-table schemas (no nested view schema, §3); `snapshot`/`batch`
120
+ * carry table-tagged {@link NormalizedOp}s. The `NormalizedSync` layer folds these into the
121
+ * local engine's base tables.
122
+ *
123
+ * `cv` (the global commit version the frame's data reflects — OPTIMISTIC-WRITES-DESIGN.md
124
+ * §8.3/§8.6) is present on sources that speak the optimistic protocol; the plain normalized
125
+ * path may omit it.
126
+ */
127
+ export type NormalizedEvent = {
128
+ type: "hello";
129
+ tables: NormalizedTableSchema[];
130
+ comparatorVersion: number;
131
+ normalizedFp: string;
132
+ } | {
133
+ type: "snapshot";
134
+ ops: NormalizedOp[];
135
+ cv?: number;
136
+ } | {
137
+ type: "batch";
138
+ ops: NormalizedOp[];
139
+ cv?: number;
140
+ };
141
+ export type QueryId = number;
142
+ /** A query's SERVER-CHANNEL state, surfaced on its {@link ArrayView} (FOLDED-MUTATIONS-DESIGN §7 —
143
+ * formerly conflated with pending-ness, OPTIMISTIC-WRITES-DESIGN.md §6):
144
+ * - `unknown` — not hydrated: the server has not produced a first result for this query yet;
145
+ * - `complete` — the server has answered. STAYS `complete` while a local mutation is pending (the
146
+ * prediction is the client's best current answer); reversion on rejection is an
147
+ * event (`onRejected`), not a downgrade of completeness;
148
+ * - `error` — RESERVED for a future server-side, query-level error signal
149
+ * (see `designs/QUERY-ERRORS-DESIGN.md`); no longer produced by a pending mutation.
150
+ * "Is a prediction pending here?" is now a separate reactive axis (the backend's `pending(qid)` /
151
+ * `onPending`), not folded into this type. A backend with no server lifecycle (the in-process
152
+ * engine) leaves every view `complete`. */
153
+ export type ResultType = "unknown" | "complete" | "error";
154
+ /** The network identity for a named query subscription. The local AST remains local; remote
155
+ * normalized/optimistic sources use only this `(name,args)` pair upstream. */
156
+ export interface RemoteQuery {
157
+ name: string;
158
+ args: unknown;
159
+ }
160
+ /**
161
+ * The seam the core talks to. Backend-agnostic: the same interface for the in-process
162
+ * WASM backend and a remote (network) backend. The core never knows which. A backend
163
+ * pushes a per-query {@link ChangeEvent} stream via {@link Backend.onEvent}; the remote
164
+ * backend additionally owns the epoch/seq/gap protocol and emits only clean, in-order
165
+ * events (so the ArrayView never sees the wire protocol).
166
+ */
167
+ export interface Backend {
168
+ registerQuery(queryId: QueryId, ast: unknown, remote?: RemoteQuery): void;
169
+ unregisterQuery(queryId: QueryId): void;
170
+ /** Optional split path for local-first backends: retain/release a named remote footprint
171
+ * without creating another local materialized view. `localQueryId`, when provided, names
172
+ * the local AST view this remote footprint feeds. */
173
+ retainRemoteQuery?(queryId: QueryId, remote: RemoteQuery, localQueryId?: QueryId): void;
174
+ releaseRemoteQuery?(queryId: QueryId): void;
175
+ /** Local: applies now (changes flow back on the stream). Remote: sends to the server. */
176
+ mutate(mutations: Mutation[]): Promise<void>;
177
+ onEvent(handler: (queryId: QueryId, event: ChangeEvent) => void): void;
178
+ /** Optional: the backend pushes per-query {@link ResultType} changes here and the core routes
179
+ * each to the matching view (so `view.resultType` tracks it). Backends with no lifecycle (the
180
+ * in-process engine) omit it and every view stays `complete`. */
181
+ onResultType?(handler: (queryId: QueryId, resultType: ResultType) => void): void;
182
+ }
183
+ /**
184
+ * The server side of the **normalized** local-first path (NORMALIZED-CHANGES-DESIGN.md §5/§7):
185
+ * registers queries and pushes each one's normalized footprint stream ({@link NormalizedEvent}s).
186
+ * Both the in-process native (`@rindle/replica`) source and the ws (`@rindle/remote`
187
+ * `RemoteNormalizedSource`) implement it; `@rindle/normalized`'s `NormalizedBackend` consumes one,
188
+ * never knowing which — a sibling seam of {@link Backend} for the normalized composition.
189
+ */
190
+ export interface NormalizedSource {
191
+ registerQuery(queryId: QueryId, remote: RemoteQuery): void;
192
+ unregisterQuery(queryId: QueryId): void;
193
+ /** Send base-table writes to the server; the authoritative stream flows back. */
194
+ mutate(mutations: Mutation[]): Promise<void>;
195
+ onNormalized(handler: (queryId: QueryId, event: NormalizedEvent) => void): void;
196
+ /** Optional: the backend hands its OWN typed per-table schemas so the source can validate
197
+ * each server `hello` against them (column order / PK by name) and reject a schema skew
198
+ * rather than silently transposing positional cells (CRIT#4 / §3 "drift ⇒ re-subscribe").
199
+ * Sources that can't skew (the in-process native source) may omit it. */
200
+ expectClientSchema?(tables: NormalizedTableSchema[]): void;
201
+ }
202
+ /** The upstream named-mutator envelope (OPTIMISTIC-WRITES-DESIGN.md §8.1): the wire
203
+ * carries the name + JSON args, never code; `mid` totally orders a client's mutations. */
204
+ export interface MutationEnvelope {
205
+ clientID: string;
206
+ mid: number;
207
+ name: string;
208
+ args: unknown;
209
+ }
210
+ /** The connection-level progress frame (§8.6): advances the coherent-apply release point
211
+ * (`cvMin`). A pure release signal — mutation confirmation does NOT ride it: `lmid` is a
212
+ * row in {@link CLIENT_MUTATIONS_TABLE}, delivered through the client's own per-client
213
+ * system query ({@link LMID_QUERY_NAME}) like any data, so it is released by the same
214
+ * `cvMin` as the commit's effects (transactionally coherent by construction). */
215
+ export interface ProgressFrame {
216
+ cvMin: number;
217
+ }
218
+ /** The replicated bookkeeping table carrying each client's high-water mutation id
219
+ * (`lmid`). Engine-hosted and served like any base table; reserved (never part of a
220
+ * user schema). Columns: `[client_id, last_mutation_id]`, PK `client_id`. */
221
+ export declare const CLIENT_MUTATIONS_TABLE = "_rindle_client_mutations";
222
+ /** The reserved server-query name every optimistic client subscribes at connect: the
223
+ * one-row system query `CLIENT_MUTATIONS_TABLE WHERE client_id = <me>`. The server
224
+ * derives the identity from the connection (args are ignored). */
225
+ export declare const LMID_QUERY_NAME = "_rindle/clientLmid";
226
+ /** The system table's wire schema — appended to the client's expected schemas so the
227
+ * lmid query's `hello` passes CRIT#4 validation. */
228
+ export declare const CLIENT_MUTATIONS_SCHEMA: NormalizedTableSchema;
229
+ /**
230
+ * The server side of the OPTIMISTIC path (OPTIMISTIC-WRITES-DESIGN.md §8): the
231
+ * {@link NormalizedSource} stream with `cv`-tagged data frames, plus the connection-level
232
+ * {@link ProgressFrame} channel and the named-mutator upstream. The client buffers data
233
+ * frames by `cv` and applies all `cv ≤ cvMin` as one coherent release (§8.5).
234
+ */
235
+ export interface OptimisticSource {
236
+ registerQuery(queryId: QueryId, remote: RemoteQuery): void;
237
+ unregisterQuery(queryId: QueryId): void;
238
+ /** Ship one named-mutator invocation upstream (§8.1). Confirmation rides the progress frames. */
239
+ pushMutation(envelope: MutationEnvelope): Promise<void>;
240
+ onNormalized(handler: (queryId: QueryId, event: NormalizedEvent) => void): void;
241
+ onProgress(handler: (frame: ProgressFrame) => void): void;
242
+ /** Optional: the backend hands its OWN typed per-table schemas so the source validates each
243
+ * server `hello` against them and rejects a schema skew (CRIT#4); see {@link NormalizedSource}. */
244
+ expectClientSchema?(tables: NormalizedTableSchema[]): void;
245
+ /** Optional: fired when the server restarts (a transport that can detect it, e.g. via a daemon
246
+ * boot id). The backend resets its `cv` watermark so the server's reset `cv` sequence is
247
+ * accepted rather than dropped as stale. In-process sources never restart and omit it. */
248
+ onRestart?(handler: () => void): void;
249
+ }
250
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,20 @@
1
+ // Wire + protocol types for the flat-change client core (WASM-CLIENT-DESIGN.md §2, §6).
2
+ //
3
+ // Cells cross the boundary BARE (the host has a typed schema, so per-column types are
4
+ // known here, not per-cell). JSON columns cross as their raw JSON string.
5
+ /** The replicated bookkeeping table carrying each client's high-water mutation id
6
+ * (`lmid`). Engine-hosted and served like any base table; reserved (never part of a
7
+ * user schema). Columns: `[client_id, last_mutation_id]`, PK `client_id`. */
8
+ export const CLIENT_MUTATIONS_TABLE = "_rindle_client_mutations";
9
+ /** The reserved server-query name every optimistic client subscribes at connect: the
10
+ * one-row system query `CLIENT_MUTATIONS_TABLE WHERE client_id = <me>`. The server
11
+ * derives the identity from the connection (args are ignored). */
12
+ export const LMID_QUERY_NAME = "_rindle/clientLmid";
13
+ /** The system table's wire schema — appended to the client's expected schemas so the
14
+ * lmid query's `hello` passes CRIT#4 validation. */
15
+ export const CLIENT_MUTATIONS_SCHEMA = {
16
+ name: CLIENT_MUTATIONS_TABLE,
17
+ columns: ["client_id", "last_mutation_id"],
18
+ primaryKey: [0],
19
+ };
20
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,EAAE;AACF,sFAAsF;AACtF,0EAA0E;AAgM1E;;8EAE8E;AAC9E,MAAM,CAAC,MAAM,sBAAsB,GAAG,0BAA0B,CAAC;AAEjE;;mEAEmE;AACnE,MAAM,CAAC,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAEpD;qDACqD;AACrD,MAAM,CAAC,MAAM,uBAAuB,GAA0B;IAC5D,IAAI,EAAE,sBAAsB;IAC5B,OAAO,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAC1C,UAAU,EAAE,CAAC,CAAC,CAAC;CAChB,CAAC"}
package/dist/view.d.ts ADDED
@@ -0,0 +1,88 @@
1
+ import type { ColType, FlatChange, ResultType, WireSchema } from "./types.ts";
2
+ /** Per-level column types (parallel to the WireSchema), used to JSON.parse json columns on
3
+ * projection. Built by the Store from the typed schema; absent ⇒ no parsing (bare values). */
4
+ export interface ViewTypes {
5
+ columnTypes: ColType[];
6
+ rels: Record<number, ViewTypes>;
7
+ }
8
+ /** The public ArrayView contract `materialize()` returns. */
9
+ export interface ArrayView<R> {
10
+ /** The current materialized result (reference-stable where data is unchanged). */
11
+ readonly data: readonly R[];
12
+ /** The query's SERVER-CHANNEL state (`unknown` while loading, `complete` once server-authoritative;
13
+ * the `error` variant is reserved and currently unproduced). A pending optimistic mutation no
14
+ * longer moves this — it is a separate axis (FOLDED-MUTATIONS-DESIGN §7). `complete` for backends
15
+ * with no server lifecycle. Changes notify subscribers. */
16
+ readonly resultType: ResultType;
17
+ /** Subscribe; fires immediately with the current data, then after each applied batch (and after
18
+ * a {@link resultType} change — re-read `resultType` in the listener). */
19
+ subscribe(listener: (data: readonly R[]) => void): () => void;
20
+ /** Tear down + stop receiving updates. */
21
+ destroy(): void;
22
+ }
23
+ /** What a top-level `.one()` query materializes to: the single row (or `null`), not an array.
24
+ * A thin adapter over a {@link FlatArrayView} — all the folding is shared; only the result
25
+ * boundary unwraps (`data[0] ?? null`). Reference identity of the row is preserved. */
26
+ export interface SingularArrayView<R> {
27
+ /** The single current row, or `null` when the query matches nothing. */
28
+ readonly data: R | null;
29
+ /** The query's lifecycle state — see {@link ArrayView.resultType}. */
30
+ readonly resultType: ResultType;
31
+ /** Subscribe; fires immediately with the current row, then after each applied batch (and after
32
+ * a {@link resultType} change). */
33
+ subscribe(listener: (data: R | null) => void): () => void;
34
+ /** Tear down + stop receiving updates. */
35
+ destroy(): void;
36
+ }
37
+ /** Wrap a plural {@link FlatArrayView} as a {@link SingularArrayView} for a `.one()` query
38
+ * (the engine caps it to `limit = 1`, so the top list holds at most one node). */
39
+ export declare class SingularView<R> implements SingularArrayView<R> {
40
+ private readonly inner;
41
+ constructor(inner: ArrayView<R>);
42
+ get data(): R | null;
43
+ get resultType(): ResultType;
44
+ subscribe(listener: (data: R | null) => void): () => void;
45
+ destroy(): void;
46
+ }
47
+ export declare class FlatArrayView<R = unknown> implements ArrayView<R> {
48
+ private schema;
49
+ private types?;
50
+ private seeded;
51
+ private top;
52
+ private dirty;
53
+ private cached;
54
+ private rt;
55
+ private readonly listeners;
56
+ constructor(schema?: WireSchema, types?: ViewTypes);
57
+ get resultType(): ResultType;
58
+ /** Set the query's lifecycle state (the Store routes the backend's per-query signal here).
59
+ * Notifies subscribers on a change so a status-bound listener (React `useQueryStatus`) re-reads,
60
+ * WITHOUT re-projecting data (it is unchanged). */
61
+ setResultType(rt: ResultType): void;
62
+ /** (Re)bind to a schema and clear the tree IN PLACE. The first `hello` (pending → ready)
63
+ * and a re-hydrate (gap → new epoch — FLAT-CHANGES-DESIGN.md §2.3) both go through here, so
64
+ * the caller's view reference and its subscribers survive a re-subscribe. Does NOT notify —
65
+ * the snapshot that follows (`applyChanges`) does, avoiding an empty-then-filled flicker. */
66
+ reset(schema: WireSchema, types?: ViewTypes): void;
67
+ /** Install a pre-projected SSR first-paint snapshot (SSR-DESIGN.md §6). The rows are already
68
+ * in result shape (json columns parsed, relationships nested), so a view with no live backend
69
+ * (the server one-shot Store) reads them directly, and a browser view shows them until its
70
+ * first live `hello` (`reset`) swaps in the maintained tree. Does NOT notify — it is set at
71
+ * materialize time, before any subscriber, and the live snapshot that follows notifies. */
72
+ seed(rows: readonly R[]): void;
73
+ /** Apply a batch (the hydrate snapshot or one transaction's events) in order, then
74
+ * notify subscribers once. Order is significant (FLAT-CHANGES-DESIGN.md §5.4). A no-op
75
+ * while pending (changes never precede the `hello` that resets the schema). */
76
+ applyChanges(events: FlatChange[]): void;
77
+ get data(): readonly R[];
78
+ subscribe(listener: (data: readonly R[]) => void): () => void;
79
+ destroy(): void;
80
+ private applyAt;
81
+ private applyOp;
82
+ private applyAdd;
83
+ private applyRemove;
84
+ private applyEdit;
85
+ private project;
86
+ private notify;
87
+ }
88
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAU,UAAU,EAAY,UAAU,EAAa,MAAM,YAAY,CAAC;AAE3G;+FAC+F;AAC/F,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACjC;AAED,6DAA6D;AAC7D,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;IAC5B;;;gEAG4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC;+EAC2E;IAC3E,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC9D,0CAA0C;IAC1C,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;wFAEwF;AACxF,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC;wCACoC;IACpC,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC1D,0CAA0C;IAC1C,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;mFACmF;AACnF,qBAAa,YAAY,CAAC,CAAC,CAAE,YAAW,iBAAiB,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;gBAEzB,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;IAI/B,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAEnB;IAED,IAAI,UAAU,IAAI,UAAU,CAE3B;IAED,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI;IAIzD,OAAO,IAAI,IAAI;CAGhB;AAqDD,qBAAa,aAAa,CAAC,CAAC,GAAG,OAAO,CAAE,YAAW,SAAS,CAAC,CAAC,CAAC;IAG7D,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,KAAK,CAAC,CAAY;IAI1B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAA6B;IAI3C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2C;gBAEzD,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,SAAS;IAKlD,IAAI,UAAU,IAAI,UAAU,CAE3B;IAED;;wDAEoD;IACpD,aAAa,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI;IAMnC;;;kGAG8F;IAC9F,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI;IASlD;;;;gGAI4F;IAC5F,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI;IAI9B;;oFAEgF;IAChF,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI;IAOxC,IAAI,IAAI,IAAI,SAAS,CAAC,EAAE,CAMvB;IAED,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI;IAQ7D,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,OAAO;IAef,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,SAAS;IAsDjB,OAAO,CAAC,OAAO;IAoCf,OAAO,CAAC,MAAM;CAIf"}