@assemora/database 0.1.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/dist/memory.js ADDED
@@ -0,0 +1,398 @@
1
+ /**
2
+ * In-memory adapter.
3
+ *
4
+ * SPEC.md §109 asks for a memory adapter so the data layer can be built and tested
5
+ * before PostgreSQL exists. It implements the same contract as any other adapter, so
6
+ * a query proven here runs unchanged against `@assemora/database-postgres`.
7
+ *
8
+ * Development and tests only — nothing here is durable.
9
+ */
10
+ import { AssemoraError } from '@assemora/core';
11
+ import { pivotAddress } from './join-table.js';
12
+ const compare = (left, right) => {
13
+ if (left === right)
14
+ return 0;
15
+ if (left === null || left === undefined)
16
+ return -1;
17
+ if (right === null || right === undefined)
18
+ return 1;
19
+ if (left instanceof Date && right instanceof Date)
20
+ return left.getTime() - right.getTime();
21
+ if (typeof left === 'number' && typeof right === 'number')
22
+ return left - right;
23
+ return String(left).localeCompare(String(right));
24
+ };
25
+ const likeToRegExp = (pattern) => new RegExp(`^${pattern
26
+ .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
27
+ .replace(/%/g, '.*')
28
+ .replace(/_/g, '.')}$`, 'i');
29
+ const evaluateComparison = (row, condition) => {
30
+ const actual = row[condition.field];
31
+ const expected = condition.value;
32
+ switch (condition.operator) {
33
+ case '=':
34
+ return compare(actual, expected) === 0;
35
+ case '!=':
36
+ return compare(actual, expected) !== 0;
37
+ case '>':
38
+ return compare(actual, expected) > 0;
39
+ case '>=':
40
+ return compare(actual, expected) >= 0;
41
+ case '<':
42
+ return compare(actual, expected) < 0;
43
+ case '<=':
44
+ return compare(actual, expected) <= 0;
45
+ case 'in':
46
+ return Array.isArray(expected) && expected.some((item) => compare(actual, item) === 0);
47
+ case 'not in':
48
+ return Array.isArray(expected) && !expected.some((item) => compare(actual, item) === 0);
49
+ case 'like':
50
+ return typeof actual === 'string' && likeToRegExp(String(expected)).test(actual);
51
+ case 'between':
52
+ return (Array.isArray(expected) &&
53
+ compare(actual, expected[0]) >= 0 &&
54
+ compare(actual, expected[1]) <= 0);
55
+ case 'is null':
56
+ return actual === null || actual === undefined;
57
+ case 'is not null':
58
+ return actual !== null && actual !== undefined;
59
+ }
60
+ };
61
+ const readPath = (value, path) => path.reduce((current, key) => typeof current === 'object' && current !== null
62
+ ? current[key]
63
+ : undefined, value);
64
+ /** A fragment is contained when every leaf it names matches the document. */
65
+ const contains = (document, fragment) => {
66
+ if (fragment === null || typeof fragment !== 'object')
67
+ return compare(document, fragment) === 0;
68
+ if (Array.isArray(fragment)) {
69
+ return (Array.isArray(document) &&
70
+ fragment.every((item) => document.some((candidate) => contains(candidate, item))));
71
+ }
72
+ if (typeof document !== 'object' || document === null)
73
+ return false;
74
+ return Object.entries(fragment).every(([key, value]) => contains(document[key], value));
75
+ };
76
+ /**
77
+ * Structural equality, so a document compares the same way it would in SQL.
78
+ *
79
+ * Comparing through `String()` made `['a','b']` equal to the text `a,b` here and to
80
+ * nothing at all in PostgreSQL — the same Query AST meaning two different things,
81
+ * which is exactly what SPEC.md §30 exists to prevent.
82
+ */
83
+ const deepEquals = (left, right) => {
84
+ if (left === right)
85
+ return true;
86
+ if (left === null || right === null || left === undefined || right === undefined)
87
+ return false;
88
+ if (typeof left !== 'object' || typeof right !== 'object')
89
+ return false;
90
+ if (Array.isArray(left) || Array.isArray(right)) {
91
+ return (Array.isArray(left) &&
92
+ Array.isArray(right) &&
93
+ left.length === right.length &&
94
+ left.every((item, index) => deepEquals(item, right[index])));
95
+ }
96
+ const a = left;
97
+ const b = right;
98
+ const keys = Object.keys(a);
99
+ return keys.length === Object.keys(b).length && keys.every((key) => deepEquals(a[key], b[key]));
100
+ };
101
+ const evaluateJson = (row, condition) => {
102
+ const document = row[condition.field];
103
+ if (condition.operator === 'contains')
104
+ return contains(document, condition.value);
105
+ const value = readPath(document, condition.path);
106
+ if (condition.operator === 'like') {
107
+ return typeof value === 'string' && likeToRegExp(String(condition.value)).test(value);
108
+ }
109
+ return deepEquals(value, condition.value);
110
+ };
111
+ const evaluate = (row, condition) => {
112
+ if (condition.kind === 'group')
113
+ return matches(row, condition.conditions);
114
+ if (condition.kind === 'json')
115
+ return evaluateJson(row, condition);
116
+ return evaluateComparison(row, condition);
117
+ };
118
+ const matches = (row, conditions) => {
119
+ let result = true;
120
+ for (const [index, condition] of conditions.entries()) {
121
+ const value = evaluate(row, condition);
122
+ if (index === 0) {
123
+ result = value;
124
+ }
125
+ else {
126
+ result = condition.combinator === 'or' ? result || value : result && value;
127
+ }
128
+ }
129
+ return result;
130
+ };
131
+ /**
132
+ * Whether a value can identify a row at all.
133
+ *
134
+ * A null key joins to nothing in SQL — `null = null` is unknown — so a row holding one
135
+ * has no related rows, rather than every row that also holds none.
136
+ */
137
+ const isKey = (value) => value !== null && value !== undefined;
138
+ /**
139
+ * The bucket a key falls in.
140
+ *
141
+ * Two keys share a bucket exactly when `compare` calls them equal, so relations
142
+ * matched in one pass through an index match the same rows a comparison per row did.
143
+ */
144
+ const bucketOf = (value) => value instanceof Date ? String(value.getTime()) : String(value);
145
+ /**
146
+ * Whether a key value falls in one of the buckets already indexed.
147
+ *
148
+ * A `Map` and a `Set` are both asked this, and a value that is no key at all answers
149
+ * no — otherwise a stored `null` would land in the bucket the text `"null"` occupies.
150
+ */
151
+ const isOneOf = (buckets, value) => isKey(value) && buckets.has(bucketOf(value));
152
+ const groupByKey = (rows, key) => {
153
+ const grouped = new Map();
154
+ for (const row of rows) {
155
+ const value = row[key];
156
+ if (!isKey(value))
157
+ continue;
158
+ const bucket = bucketOf(value);
159
+ const existing = grouped.get(bucket);
160
+ if (existing === undefined)
161
+ grouped.set(bucket, [row]);
162
+ else
163
+ existing.push(row);
164
+ }
165
+ return grouped;
166
+ };
167
+ /**
168
+ * The column on the far table that a join column copies, as the join table declares it.
169
+ *
170
+ * Read back off the derived descriptor rather than worked out again here: which column
171
+ * a pivot points at is decided in one place (`joinTableDescriptor`), and a second
172
+ * opinion is how a load comes to look where no write ever put a row.
173
+ */
174
+ const linkedKey = (join, column) => {
175
+ const link = join.relations.find((relation) => relation.foreignKey === column);
176
+ if (link === undefined) {
177
+ throw new AssemoraError('INVALID_JOIN_TABLE', `The join table "${join.name}" declares no foreign key on "${column}"`, { status: 500 });
178
+ }
179
+ return link.ownerKey;
180
+ };
181
+ const sort = (rows, order) => order.length === 0
182
+ ? rows
183
+ : [...rows].sort((left, right) => {
184
+ for (const step of order) {
185
+ const difference = compare(left[step.field], right[step.field]);
186
+ if (difference !== 0)
187
+ return step.direction === 'desc' ? -difference : difference;
188
+ }
189
+ return 0;
190
+ });
191
+ export const createMemoryAdapter = (seed = {}) => {
192
+ const tables = new Map();
193
+ let scans = 0;
194
+ for (const [table, rows] of Object.entries(seed)) {
195
+ tables.set(table, rows.map((row) => ({ ...row })));
196
+ }
197
+ const store = (table) => {
198
+ const existing = tables.get(table);
199
+ if (existing !== undefined)
200
+ return existing;
201
+ const created = [];
202
+ tables.set(table, created);
203
+ return created;
204
+ };
205
+ /**
206
+ * One pass over one table, and the only way rows are ever selected.
207
+ *
208
+ * Everything that reads goes through here, so `scanCount()` measures what a query
209
+ * costs: a batched relation load adds a fixed number of passes, and one loaded row
210
+ * by row adds a pass per row (SPEC.md §89).
211
+ */
212
+ const scan = (table, keep) => {
213
+ scans += 1;
214
+ return store(table).filter(keep);
215
+ };
216
+ const relationOf = (table, name) => {
217
+ const relation = table.relations.find((candidate) => candidate.name === name);
218
+ if (relation === undefined) {
219
+ throw new AssemoraError('UNKNOWN_RELATION', `Table "${table.name}" has no relation "${name}"`, { status: 500 });
220
+ }
221
+ return relation;
222
+ };
223
+ /**
224
+ * The rows a `belongsToMany` links, in two passes: one over the join table, one over
225
+ * the target (SPEC.md §23).
226
+ *
227
+ * The join table is derived rather than looked up in `related`: no model declares it,
228
+ * so nothing registers a descriptor for it, and deriving it from the same function
229
+ * the DDL and the schema diff use is what makes a load look where a write put the
230
+ * rows (SPEC.md §24).
231
+ */
232
+ const loadThroughJoinTable = (rows, table, relation, load, related) => {
233
+ const target = related[relation.target];
234
+ // Which column of the target the join table copies is the target's own business, so
235
+ // its descriptor has to be to hand. PostgreSQL refuses the same load for the same
236
+ // reason, and assuming `id` here would make the two adapters disagree quietly.
237
+ if (target === undefined) {
238
+ throw new AssemoraError('UNKNOWN_RELATION', `The descriptor for "${relation.target}" was not provided`, { status: 500 });
239
+ }
240
+ for (const row of rows)
241
+ row[relation.name] = [];
242
+ const owners = groupByKey(rows, relation.ownerKey);
243
+ const anchor = rows.find((row) => isKey(row[relation.ownerKey]));
244
+ if (anchor === undefined)
245
+ return;
246
+ // One row is enough to learn where the links live: the address is the same for
247
+ // every row of the table, and only `ownerValue` differs.
248
+ const pivot = pivotAddress(table, relation, anchor, target);
249
+ const links = scan(pivot.table.name, (link) => isOneOf(owners, link[pivot.ownerColumn]) && isKey(link[pivot.relatedColumn]));
250
+ /** Which owners hold each target, which is all a join table has to say. */
251
+ const heldBy = new Map();
252
+ for (const link of links) {
253
+ const ownerBucket = bucketOf(link[pivot.ownerColumn]);
254
+ const targetBucket = bucketOf(link[pivot.relatedColumn]);
255
+ const existing = heldBy.get(targetBucket);
256
+ if (existing === undefined)
257
+ heldBy.set(targetBucket, [ownerBucket]);
258
+ // The pair is unique in the table `joinTableDescriptor` describes, and nothing
259
+ // enforces that here. Counting a duplicate link twice would load the same role
260
+ // twice where PostgreSQL, holding the constraint, could not have stored it.
261
+ else if (!existing.includes(ownerBucket))
262
+ existing.push(ownerBucket);
263
+ }
264
+ if (heldBy.size === 0)
265
+ return;
266
+ const targetKey = linkedKey(pivot.table, pivot.relatedColumn);
267
+ const children = scan(relation.target, (candidate) => isOneOf(heldBy, candidate[targetKey]));
268
+ // A join table has no order of its own, so one has to be chosen or the two
269
+ // adapters answer with the same rows in different orders and every unit test that
270
+ // reads `user.roles[0]` proves nothing about production (ADR-0013). The far key is
271
+ // the column both ends of the link already agree on, and it is what PostgreSQL
272
+ // orders the join by. Sorted through the same comparator every other order in this
273
+ // adapter uses, so a pivot load is ordered the way `order` in the AST is.
274
+ const loaded = sort(loadRelations(children, target, load.nested, related), [
275
+ { field: targetKey, direction: 'asc' },
276
+ ]);
277
+ const collected = new Map();
278
+ for (const child of loaded) {
279
+ for (const ownerBucket of heldBy.get(bucketOf(child[targetKey])) ?? []) {
280
+ const existing = collected.get(ownerBucket);
281
+ if (existing === undefined)
282
+ collected.set(ownerBucket, [child]);
283
+ else
284
+ existing.push(child);
285
+ }
286
+ }
287
+ for (const [ownerBucket, matched] of owners) {
288
+ const linked = collected.get(ownerBucket) ?? [];
289
+ for (const row of matched)
290
+ row[relation.name] = linked;
291
+ }
292
+ };
293
+ /**
294
+ * Loads relations in batches: one pass per relation, never one per row.
295
+ *
296
+ * SPEC.md §89 asks for N+1 to be caught by tests rather than by review, and
297
+ * `diagnostics.scanCount()` is what those tests read.
298
+ */
299
+ const loadRelations = (rows, table, loads, related) => {
300
+ const enriched = rows.map((row) => ({ ...row }));
301
+ for (const load of loads) {
302
+ const relation = relationOf(table, load.relation);
303
+ if (relation.kind === 'belongsToMany') {
304
+ loadThroughJoinTable(enriched, table, relation, load, related);
305
+ continue;
306
+ }
307
+ const owned = relation.kind === 'belongsTo';
308
+ const localKey = owned ? relation.foreignKey : relation.ownerKey;
309
+ const remoteKey = owned ? relation.ownerKey : relation.foreignKey;
310
+ const keys = new Set(enriched.filter((row) => isKey(row[localKey])).map((row) => bucketOf(row[localKey])));
311
+ const target = related[relation.target];
312
+ const candidates = keys.size === 0
313
+ ? []
314
+ : scan(relation.target, (candidate) => isOneOf(keys, candidate[remoteKey]));
315
+ const loaded = target === undefined
316
+ ? candidates.map((candidate) => ({ ...candidate }))
317
+ : loadRelations(candidates, target, load.nested, related);
318
+ const grouped = groupByKey(loaded, remoteKey);
319
+ for (const row of enriched) {
320
+ const value = row[localKey];
321
+ const matched = (isKey(value) ? grouped.get(bucketOf(value)) : undefined) ?? [];
322
+ row[relation.name] = relation.kind === 'hasMany' ? matched : (matched[0] ?? null);
323
+ }
324
+ }
325
+ return enriched;
326
+ };
327
+ const adapter = {
328
+ async execute(query, context) {
329
+ const rows = store(query.model);
330
+ const related = context.related ?? {};
331
+ if (query.operation === 'insert') {
332
+ const inserted = { ...(query.data ?? {}) };
333
+ rows.push(inserted);
334
+ return { ...inserted };
335
+ }
336
+ const selected = scan(query.model, (row) => matches(row, query.where));
337
+ if (query.operation === 'count')
338
+ return selected.length;
339
+ if (query.operation === 'delete') {
340
+ for (const row of selected) {
341
+ const index = rows.indexOf(row);
342
+ if (index >= 0)
343
+ rows.splice(index, 1);
344
+ }
345
+ return selected.length;
346
+ }
347
+ if (query.operation === 'update') {
348
+ for (const row of selected)
349
+ Object.assign(row, query.data ?? {});
350
+ return selected.length;
351
+ }
352
+ const ordered = sort(selected, query.order);
353
+ const offset = query.offset ?? 0;
354
+ const limited = query.limit === undefined
355
+ ? ordered.slice(offset)
356
+ : ordered.slice(offset, offset + query.limit);
357
+ const materialised = limited.map((row) => ({ ...row }));
358
+ return (query.with.length > 0
359
+ ? loadRelations(materialised, context.table, query.with, related)
360
+ : materialised);
361
+ },
362
+ async transaction(callback) {
363
+ const snapshot = new Map();
364
+ for (const [table, rows] of tables)
365
+ snapshot.set(table, rows.map((row) => ({ ...row })));
366
+ try {
367
+ return await callback();
368
+ }
369
+ catch (error) {
370
+ // A failed transaction leaves nothing behind, exactly as a real one would.
371
+ tables.clear();
372
+ for (const [table, rows] of snapshot)
373
+ tables.set(table, rows);
374
+ throw error;
375
+ }
376
+ },
377
+ introspect() {
378
+ return Promise.resolve({ tables: [] });
379
+ },
380
+ rows(table) {
381
+ return store(table).map((row) => ({ ...row }));
382
+ },
383
+ seed(table, rows) {
384
+ tables.set(table, rows.map((row) => ({ ...row })));
385
+ },
386
+ reset() {
387
+ tables.clear();
388
+ },
389
+ diagnostics: {
390
+ scanCount: () => scans,
391
+ reset: () => {
392
+ scans = 0;
393
+ },
394
+ },
395
+ };
396
+ return adapter;
397
+ };
398
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Query AST (SPEC.md §30).
3
+ *
4
+ * The query builder never constructs adapter queries directly; it produces this
5
+ * neutral description instead. That keeps one stable contract between Assemora Data,
6
+ * database adapters, the policy layer and the AI query layer — and it is why an
7
+ * agent expresses a selection as structure rather than as SQL (SPEC.md §85).
8
+ */
9
+ export type ComparisonOperator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'in' | 'not in'
10
+ /** Case-insensitive, in every adapter: it exists to serve search. */
11
+ | 'like' | 'between' | 'is null' | 'is not null';
12
+ export type Combinator = 'and' | 'or';
13
+ export type Comparison = {
14
+ readonly kind: 'comparison';
15
+ readonly combinator: Combinator;
16
+ readonly field: string;
17
+ readonly operator: ComparisonOperator;
18
+ readonly value?: unknown;
19
+ };
20
+ /** A parenthesised set of conditions, produced by `where(q => ...)`. */
21
+ export type ConditionGroup = {
22
+ readonly kind: 'group';
23
+ readonly combinator: Combinator;
24
+ readonly conditions: readonly Condition[];
25
+ };
26
+ /**
27
+ * A condition on a JSON document (SPEC.md §38).
28
+ *
29
+ * `path` addresses a key inside the document; an empty path means the document
30
+ * itself. `contains` asks whether the document includes the given fragment.
31
+ */
32
+ export type JsonComparison = {
33
+ readonly kind: 'json';
34
+ readonly combinator: Combinator;
35
+ readonly field: string;
36
+ readonly path: readonly string[];
37
+ readonly operator: 'equals' | 'contains' | 'like';
38
+ readonly value: unknown;
39
+ };
40
+ export type Condition = Comparison | ConditionGroup | JsonComparison;
41
+ export type SortDirection = 'asc' | 'desc';
42
+ export type Order = {
43
+ readonly field: string;
44
+ readonly direction: SortDirection;
45
+ };
46
+ /**
47
+ * A relation to load alongside the row, addressed by its declared name.
48
+ *
49
+ * A load carries no order of its own — `order` above sorts the rows the query
50
+ * selects, not the rows hanging off them. One exception is stated rather than left to
51
+ * the adapter: a `belongsToMany` arrives ordered by the *target's* key, ascending.
52
+ * A join table has no natural order, so without a rule the two adapters answer with
53
+ * the same rows in different orders and a unit test that reads `user.roles[0]` passes
54
+ * against the memory adapter and is wrong against PostgreSQL (ADR-0013).
55
+ */
56
+ export type RelationLoad = {
57
+ readonly relation: string;
58
+ readonly nested: readonly RelationLoad[];
59
+ };
60
+ export type QueryOperation = 'select' | 'insert' | 'update' | 'delete' | 'count';
61
+ export type QueryAst = {
62
+ readonly model: string;
63
+ readonly operation: QueryOperation;
64
+ readonly where: readonly Condition[];
65
+ readonly order: readonly Order[];
66
+ readonly with: readonly RelationLoad[];
67
+ readonly limit?: number;
68
+ readonly offset?: number;
69
+ /** Values for an insert or an update. */
70
+ readonly data?: Readonly<Record<string, unknown>>;
71
+ };
72
+ export declare const emptyQuery: (model: string, operation?: QueryOperation) => QueryAst;
73
+ export declare const comparison: (field: string, operator: ComparisonOperator, value?: unknown) => Comparison;
74
+ export declare const orComparison: (field: string, operator: ComparisonOperator, value?: unknown) => Comparison;
75
+ export declare const jsonEquals: (field: string, path: readonly string[], value: unknown, combinator?: Combinator) => JsonComparison;
76
+ export declare const jsonLike: (field: string, path: readonly string[], pattern: string, combinator?: Combinator) => JsonComparison;
77
+ export declare const jsonContains: (field: string, value: unknown, combinator?: Combinator) => JsonComparison;
78
+ export declare const group: (conditions: readonly Condition[], combinator?: Combinator) => ConditionGroup;
79
+ //# sourceMappingURL=query-ast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-ast.d.ts","sourceRoot":"","sources":["../src/query-ast.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Query AST (SPEC.md §30).
3
+ *
4
+ * The query builder never constructs adapter queries directly; it produces this
5
+ * neutral description instead. That keeps one stable contract between Assemora Data,
6
+ * database adapters, the policy layer and the AI query layer — and it is why an
7
+ * agent expresses a selection as structure rather than as SQL (SPEC.md §85).
8
+ */
9
+ export const emptyQuery = (model, operation = 'select') => ({
10
+ model,
11
+ operation,
12
+ where: [],
13
+ order: [],
14
+ with: [],
15
+ });
16
+ const compare = (combinator, field, operator, value) => ({
17
+ kind: 'comparison',
18
+ combinator,
19
+ field,
20
+ operator,
21
+ ...(value === undefined ? {} : { value }),
22
+ });
23
+ export const comparison = (field, operator, value) => compare('and', field, operator, value);
24
+ export const orComparison = (field, operator, value) => compare('or', field, operator, value);
25
+ export const jsonEquals = (field, path, value, combinator = 'and') => ({ kind: 'json', combinator, field, path, operator: 'equals', value });
26
+ export const jsonLike = (field, path, pattern, combinator = 'and') => ({ kind: 'json', combinator, field, path, operator: 'like', value: pattern });
27
+ export const jsonContains = (field, value, combinator = 'and') => ({ kind: 'json', combinator, field, path: [], operator: 'contains', value });
28
+ export const group = (conditions, combinator = 'and') => ({ kind: 'group', combinator, conditions });
29
+ //# sourceMappingURL=query-ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-ast.js","sourceRoot":"","sources":["../src/query-ast.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAuFH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,SAAS,GAAmB,QAAQ,EAAY,EAAE,CAAC,CAAC;IAC5F,KAAK;IACL,SAAS;IACT,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;CACT,CAAC,CAAA;AAEF,MAAM,OAAO,GAAG,CACd,UAAsB,EACtB,KAAa,EACb,QAA4B,EAC5B,KAAe,EACH,EAAE,CAAC,CAAC;IAChB,IAAI,EAAE,YAAY;IAClB,UAAU;IACV,KAAK;IACL,QAAQ;IACR,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;CAC1C,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,KAAa,EACb,QAA4B,EAC5B,KAAe,EACH,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;AAEvD,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,KAAa,EACb,QAA4B,EAC5B,KAAe,EACH,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;AAEtD,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,KAAa,EACb,IAAuB,EACvB,KAAc,EACd,UAAU,GAAe,KAAK,EACd,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;AAE3F,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,KAAa,EACb,IAAuB,EACvB,OAAe,EACf,UAAU,GAAe,KAAK,EACd,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;AAElG,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,KAAa,EACb,KAAc,EACd,UAAU,GAAe,KAAK,EACd,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAA;AAEjG,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,UAAgC,EAChC,UAAU,GAAe,KAAK,EACd,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAA"}