@agentshouse/mdruntime-adapter 0.1.0-ce3fe65a95f49 → 0.1.0-ce5ef9afd7e9a

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 (50) hide show
  1. package/AGENTS.md +289 -279
  2. package/dist/actions.d.ts +13 -5
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +85 -115
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +292 -130
  8. package/dist/discovery.d.ts +5 -3
  9. package/dist/discovery.d.ts.map +1 -1
  10. package/dist/discovery.js +29 -10
  11. package/dist/gather.d.ts +1 -1
  12. package/dist/gather.d.ts.map +1 -1
  13. package/dist/gather.js +4 -14
  14. package/dist/index.d.ts +3 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/part.d.ts +13 -0
  18. package/dist/part.d.ts.map +1 -0
  19. package/dist/part.js +80 -0
  20. package/dist/read.d.ts +64 -20
  21. package/dist/read.d.ts.map +1 -1
  22. package/dist/read.js +296 -105
  23. package/dist/referrer.d.ts +2 -0
  24. package/dist/referrer.d.ts.map +1 -1
  25. package/dist/referrer.js +8 -2
  26. package/dist/room-types.d.ts +6 -0
  27. package/dist/room-types.d.ts.map +1 -0
  28. package/dist/room-types.js +66 -0
  29. package/dist/site.d.ts +1 -1
  30. package/dist/site.d.ts.map +1 -1
  31. package/dist/site.js +143 -118
  32. package/dist/stream.d.ts +5 -4
  33. package/dist/stream.d.ts.map +1 -1
  34. package/dist/stream.js +275 -77
  35. package/dist/transport.d.ts +46 -7
  36. package/dist/transport.d.ts.map +1 -1
  37. package/dist/transport.js +1 -0
  38. package/dist/upload.d.ts +12 -0
  39. package/dist/upload.d.ts.map +1 -0
  40. package/dist/upload.js +52 -0
  41. package/dist/version.d.ts +1 -0
  42. package/dist/version.d.ts.map +1 -1
  43. package/dist/version.js +1 -1
  44. package/dist/write.d.ts +12 -1
  45. package/dist/write.d.ts.map +1 -1
  46. package/dist/write.js +96 -44
  47. package/package.json +2 -2
  48. package/dist/handed.d.ts +0 -15
  49. package/dist/handed.d.ts.map +0 -1
  50. package/dist/handed.js +0 -38
package/dist/site.js CHANGED
@@ -1,126 +1,127 @@
1
+ import { stepped } from '@agentshouse/mdruntime';
1
2
  import { actionOutcome, SITE_SUBMIT } from './actions.js';
2
3
  import { mapDiscovery, parseSiteDiscovery, siteCapabilities, siteTracked, } from './discovery.js';
3
4
  import { partModels, streamedModels, viewModels } from './model.js';
4
- import { advancedScope, bootstrapOf, parseEnumeration, parseSiteBootstrap, refreshFrom, siteBootstrapNext, siteBootstrapOffset, viewOf, } from './read.js';
5
- import { sha256Hex } from './digest.js';
5
+ import { advancedScope, bootstrapping, emptyScope, housePart, parseEnumeration, parseSiteParted, refreshFrom, viewOf, wholeView, } from './read.js';
6
+ import { PART_ATTEMPTS, unverifiedPart } from './part.js';
6
7
  import { classifyDoor, classifyRead, discoveryFailure } from './refusal.js';
8
+ import { HOUSE_ROOM_TYPES } from './room-types.js';
7
9
  import { houseNotifications } from './stream.js';
8
10
  import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, SITE_FILE_RECORD, SITE_FILES, } from './transport.js';
9
11
  import { houseReferrer } from './referrer.js';
10
12
  import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
11
13
  const UNCERTAIN = { kind: 'transport-uncertainty' };
14
+ function unfound() {
15
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
16
+ }
12
17
  function siteRoom(tracked) {
13
18
  return {
14
19
  name: tracked.handle,
15
20
  locator: tracked.locator,
16
21
  handle: tracked.handle,
17
22
  roomVersion: roomVersion(tracked),
18
- operations: { read: [''], sync: [''], write: [], delete: [] },
19
- replica: { selection: tracked.locator, admission: 'admitted' },
23
+ operations: { write: [], delete: [] },
24
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
20
25
  providerOwnedPaths: [],
21
26
  };
22
27
  }
23
28
  function settled(refused) {
24
29
  return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
25
30
  }
26
- export function createSiteAdapter(transport) {
31
+ export function createSiteAdapter(transport, snapshot = false) {
27
32
  const notifications = houseNotifications(transport, 'site');
28
33
  const tracked = new Map();
34
+ const expired = new Map();
29
35
  function published(referrer) {
30
36
  const named = houseReferrer(referrer, tracked);
31
37
  return named === null || !tracked.has(named.locator) ? null : named;
32
38
  }
33
- async function enumeration(entry, from) {
39
+ function fileRoute(request) {
40
+ const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
41
+ if (named === null) {
42
+ return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
43
+ }
44
+ if (request.fileRef === undefined)
45
+ return unfound();
46
+ const { room_ref, path, record } = named.referrer;
47
+ return `${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
48
+ ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
49
+ : encodeURIComponent(path)}`;
50
+ }
51
+ async function enumerated(entry, from, page) {
34
52
  const answer = await transport.door(SITE_DOOR_ENUMERATE, {
35
- positions: [presented(entry.authority, from)],
53
+ positions: [
54
+ page === undefined
55
+ ? presented(entry.authority, from)
56
+ : {
57
+ ...presented(entry.authority, { position: page.after, logEpoch: from.logEpoch }),
58
+ page: { through: page.through, read: page.read },
59
+ },
60
+ ],
36
61
  });
37
62
  const classified = classifyRead(answer.status, answer.body, entry.locator);
38
63
  if (classified !== null)
39
64
  return classified;
40
- return parseEnumeration(answer.body, 'site') ?? UNCERTAIN;
65
+ const found = parseEnumeration(answer.body, 'site');
66
+ if (found === null)
67
+ return UNCERTAIN;
68
+ return viewOf(found, entry) ?? { kind: 'room-not-readable', locator: entry.locator };
69
+ }
70
+ async function enumeration(entry, from) {
71
+ const first = await enumerated(entry, from);
72
+ return 'kind' in first ? first : wholeView(first, (page) => enumerated(entry, from, page));
41
73
  }
42
- async function bootstrapPart(entry, after, offset) {
43
- const query = [
44
- ...(after === null ? [] : [`after=${encodeURIComponent(after)}`]),
45
- ...(offset === null ? [] : [`offset=${offset}`]),
46
- ];
47
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${query.length === 0 ? '' : `?${query.join('&')}`}`);
74
+ async function partedRoom(entry) {
75
+ const cut = expired.get(entry.locator);
76
+ const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`);
48
77
  const classified = classifyDoor(answer.status, answer.body, entry.locator);
49
78
  if (classified !== null)
50
- return { failure: classified };
51
- const scope = parseSiteBootstrap(answer.body);
52
- return scope === null ? { failure: UNCERTAIN } : { body: answer.body, scope };
79
+ return classified;
80
+ const room = parseSiteParted(answer.body);
81
+ return room === null || room.anchor !== entry.authority ? UNCERTAIN : room;
53
82
  }
54
- async function assembled(entry, scope, path, offset) {
55
- const opened = scope.contents.at(-1);
56
- if (opened === undefined || opened.path !== path || opened.content.length !== offset) {
57
- return UNCERTAIN;
58
- }
59
- let text = opened.content;
60
- for (;;) {
61
- const part = await bootstrapPart(entry, path, text.length);
62
- if ('failure' in part)
63
- return part.failure;
64
- const [piece] = part.scope.contents;
65
- if (piece === undefined ||
66
- part.scope.contents.length !== 1 ||
67
- piece.path !== path ||
68
- piece.content.length === 0) {
69
- return UNCERTAIN;
70
- }
71
- text += piece.content;
72
- const more = siteBootstrapOffset(part.body);
73
- if (more === null)
74
- break;
75
- if (more !== text.length)
76
- return UNCERTAIN;
83
+ async function fetchedPart(entry, room, listed) {
84
+ for (let attempt = 0; attempt < PART_ATTEMPTS; attempt += 1) {
85
+ const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}?part=${encodeURIComponent(listed.part)}`);
86
+ const failure = classifyRead(answer.status, answer.body, entry.locator);
87
+ if (failure?.kind === 'beyond-horizon')
88
+ expired.set(entry.locator, room.position);
89
+ if (failure !== null)
90
+ return failure;
91
+ const scope = await housePart(room, answer.body, listed, 'site');
92
+ if (scope !== null)
93
+ return scope;
77
94
  }
78
- const file = scope.files.find((held) => held.path === path);
79
- if (file === undefined || (await sha256Hex(text)) !== file.version)
80
- return UNCERTAIN;
81
- return { ...scope, contents: [...scope.contents.slice(0, -1), { path, content: text }] };
95
+ return unverifiedPart(entry.locator);
82
96
  }
83
- async function caughtUp(entry, after) {
84
- const part = await bootstrapPart(entry, after, null);
85
- if ('failure' in part)
86
- return part;
87
- const next = siteBootstrapNext(part.body);
88
- const offset = siteBootstrapOffset(part.body);
89
- if (offset !== null) {
90
- if (next === null)
91
- return { failure: UNCERTAIN };
92
- const scope = await assembled(entry, part.scope, next, offset);
93
- return 'kind' in scope ? { failure: scope } : { scope, next };
94
- }
95
- const { scope } = part;
96
- if (after !== null || next !== null || roomVersion(scope) === roomVersion(entry)) {
97
- return { scope, next };
98
- }
99
- const found = await enumeration(entry, scope);
100
- if ('kind' in found)
101
- return { failure: settled(found) };
102
- const view = viewOf(found, entry);
103
- if (view === undefined)
104
- return { failure: { kind: 'room-not-readable', locator: entry.locator } };
105
- return { scope: advancedScope(scope, view), next: null };
97
+ async function caughtUp(entry, continued) {
98
+ const listed = continued.room.parts[continued.next];
99
+ const scope = listed === undefined
100
+ ? emptyScope(continued.room)
101
+ : await fetchedPart(entry, continued.room, listed);
102
+ if ('kind' in scope)
103
+ return scope;
104
+ if (continued.room.parts.length > 1 || roomVersion(scope) === roomVersion(entry))
105
+ return scope;
106
+ const view = await enumeration(entry, scope);
107
+ if ('kind' in view)
108
+ return settled(view);
109
+ return stepped(advancedScope(scope, view));
106
110
  }
107
111
  async function refreshed(entry, fromRoomVersion) {
108
112
  const from = logPosition(fromRoomVersion);
109
113
  if (from === null)
110
114
  return { kind: 'beyond-horizon' };
111
- const streamed = notifications.advance(entry, from);
115
+ const streamed = await stepped(notifications.advance(entry, from));
112
116
  if (streamed !== null) {
113
117
  const models = await streamedModels(streamed.schemas, entry, 'site');
114
118
  return models === undefined ? streamed.page : { ...streamed.page, models };
115
119
  }
116
- const found = await enumeration(entry, from);
117
- if ('kind' in found)
118
- return found;
119
- const view = viewOf(found, entry);
120
- if (view === undefined)
121
- return { kind: 'room-not-readable', locator: entry.locator };
120
+ const view = await enumeration(entry, from);
121
+ if ('kind' in view)
122
+ return view;
122
123
  notifications.reach(entry.authority, view);
123
- const answer = refreshFrom(view, fromRoomVersion);
124
+ const answer = await refreshFrom(view, fromRoomVersion);
124
125
  if (answer.kind !== 'net-advancement')
125
126
  return answer;
126
127
  const models = await viewModels(view, entry);
@@ -128,6 +129,8 @@ export function createSiteAdapter(transport) {
128
129
  }
129
130
  return {
130
131
  localSaves: true,
132
+ exhaustiveDiscovery: true,
133
+ roomTypes: HOUSE_ROOM_TYPES,
131
134
  async authorize() {
132
135
  return {};
133
136
  },
@@ -150,23 +153,31 @@ export function createSiteAdapter(transport) {
150
153
  const entry = tracked.get(request.locator);
151
154
  if (entry === undefined)
152
155
  return { kind: 'room-not-readable', locator: request.locator };
153
- const continued = request.pageToken === undefined
154
- ? null
155
- : JSON.parse(request.pageToken);
156
- const held = await caughtUp(entry, continued?.after ?? null);
157
- if ('failure' in held)
158
- return held.failure;
159
- notifications.reach(entry.authority, held.scope);
156
+ let continued;
157
+ if (request.pageToken === undefined) {
158
+ const room = await partedRoom(entry);
159
+ if ('kind' in room)
160
+ return room;
161
+ continued = { room, next: 0, seen: [] };
162
+ }
163
+ else
164
+ continued = JSON.parse(request.pageToken);
165
+ const scope = await caughtUp(entry, continued);
166
+ if ('kind' in scope)
167
+ return scope;
168
+ notifications.reach(entry.authority, scope);
169
+ const next = continued.next + 1;
170
+ const more = next < continued.room.parts.length;
160
171
  const seen = [
161
- ...(continued?.seen ?? []),
162
- ...entry.schemas.filter((schema) => held.scope.files.some((file) => file.path === schema)),
172
+ ...continued.seen,
173
+ ...entry.schemas.filter((schema) => scope.files.some((file) => file.path === schema)),
163
174
  ];
164
- const models = await partModels(held.scope, entry, new Set(seen), held.next === null);
165
- const continuation = held.next === null ? null : { after: held.next, seen };
175
+ const models = await partModels(scope, entry, new Set(seen), !more);
176
+ const { folders: _folders, ...page } = await stepped(bootstrapping(scope));
166
177
  return {
167
- ...bootstrapOf(held.scope),
178
+ ...page,
168
179
  ...(models === undefined ? {} : { models }),
169
- ...(continuation === null ? {} : { pageToken: JSON.stringify(continuation) }),
180
+ ...(more ? { pageToken: JSON.stringify({ ...continued, next, seen }) } : {}),
170
181
  };
171
182
  },
172
183
  async refresh(_authorization, request) {
@@ -175,6 +186,11 @@ export function createSiteAdapter(transport) {
175
186
  return { kind: 'room-not-readable', locator: request.locator };
176
187
  if (request.pageToken !== undefined)
177
188
  return UNCERTAIN;
189
+ if (snapshot) {
190
+ return request.fromRoomVersion === roomVersion(entry)
191
+ ? { kind: 'still-current' }
192
+ : { kind: 'beyond-horizon' };
193
+ }
178
194
  return refreshed(entry, request.fromRoomVersion);
179
195
  },
180
196
  async mutate() {
@@ -184,30 +200,32 @@ export function createSiteAdapter(transport) {
184
200
  return { kind: 'no-history' };
185
201
  },
186
202
  async binary(_authorization, request) {
187
- const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
188
- if (named === null) {
189
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
190
- }
191
- if (request.fileRef === undefined) {
192
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
193
- }
194
- const { room_ref, path, record } = named.referrer;
195
- const read = await transport.download(`${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
196
- ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
197
- : encodeURIComponent(path)}`);
198
- if (read.status === 404) {
199
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
200
- }
201
- return read.status === 200 && read.blob !== null
202
- ? { kind: 'binary', blob: read.blob }
203
+ const route = fileRoute(request);
204
+ if (typeof route !== 'string')
205
+ return route;
206
+ const read = await transport.download(route);
207
+ if (read.status === 404)
208
+ return unfound();
209
+ return read.status === 200 && read.body !== null
210
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
203
211
  : UNCERTAIN;
204
212
  },
213
+ async link(_authorization, request) {
214
+ const route = fileRoute(request);
215
+ if (typeof route !== 'string')
216
+ return route;
217
+ return {
218
+ kind: 'link',
219
+ url: route,
220
+ name: request.path.slice(request.path.lastIndexOf('/') + 1),
221
+ };
222
+ },
205
223
  referrerScope(referrer) {
206
224
  const named = published(referrer);
207
225
  if (named === null)
208
226
  return null;
209
227
  const { path } = named.referrer;
210
- return { kind: 'room', locator: named.locator, ...(path === undefined ? {} : { path }) };
228
+ return { locator: named.locator, ...(path === undefined ? {} : { path }) };
211
229
  },
212
230
  reached(locator, version, target) {
213
231
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
@@ -228,20 +246,27 @@ export function createSiteAdapter(transport) {
228
246
  return UNCERTAIN;
229
247
  return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMIT);
230
248
  },
231
- roomStream: {
232
- hold(rooms) {
233
- notifications.send(rooms.flatMap((room) => {
234
- const entry = tracked.get(room.locator);
235
- const at = logPosition(room.roomVersion);
236
- if (entry === undefined || at === null)
237
- return [];
238
- notifications.reach(entry.authority, at);
239
- return [presented(entry.authority, at)];
240
- }));
249
+ roomStream: snapshot
250
+ ? undefined
251
+ : {
252
+ hold(rooms) {
253
+ notifications.send(rooms.flatMap((room) => {
254
+ const entry = tracked.get(room.locator);
255
+ const at = logPosition(room.roomVersion);
256
+ if (entry === undefined || at === null)
257
+ return [];
258
+ notifications.reach(entry.authority, at);
259
+ return [presented(entry.authority, at)];
260
+ }));
261
+ },
262
+ reopen: notifications.reopen,
263
+ observe: notifications.observe,
264
+ published(locator, roomVersion) {
265
+ const at = logPosition(roomVersion);
266
+ if (at !== null)
267
+ notifications.published(locator, at);
268
+ },
241
269
  },
242
- reopen: notifications.reopen,
243
- observe: notifications.observe,
244
- },
245
270
  serviceMode: notifications.serviceMode,
246
271
  };
247
272
  }
package/dist/stream.d.ts CHANGED
@@ -1,21 +1,22 @@
1
- import type { ConversationStream, RefreshPage, RoomStreamEvent, ServiceModeSignal } from '@agentshouse/mdruntime';
1
+ import { type ConversationStream, type RefreshPage, type RoomStreamEvent, type ServiceModeSignal, type StreamReceipts } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
3
  import type { HouseDoor, HouseHeldRoom, HouseMode, HouseStreamEntry } from './transport.js';
4
4
  import { type LogPosition } from './version.js';
5
5
  export type HeldRevision = (path: string, revision: string) => boolean;
6
6
  export type StreamedAdvancement = {
7
7
  page: RefreshPage;
8
- entries: readonly HouseStreamEntry[];
9
8
  schemas: ReadonlyMap<string, HouseStreamEntry>;
10
9
  };
11
10
  export type HouseNotifications = {
12
11
  runtime: string;
13
- observe(notify: (event: RoomStreamEvent) => void): () => void;
12
+ observe(notify: (event: RoomStreamEvent) => void, receipts: StreamReceipts): () => void;
14
13
  send(rooms: readonly HouseHeldRoom[]): void;
14
+ published(locator: string, at: LogPosition): void;
15
15
  reopen(): void;
16
16
  track(authorities: readonly TrackedAuthority[]): void;
17
17
  reach(authority: string, at: LogPosition): void;
18
- advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): StreamedAdvancement | null;
18
+ edited(tracked: TrackedAuthority, from: LogPosition): readonly string[];
19
+ advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): Generator<number, StreamedAdvancement | null, void>;
19
20
  conversations: ConversationStream;
20
21
  serviceMode: ServiceModeSignal;
21
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAElB,WAAW,EACX,eAAe,EAEf,iBAAiB,EAElB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EAEb,SAAS,EAET,gBAAgB,EAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAwB7D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAEvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC9D,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IAC5C,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,OAAO,CACL,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,WAAW,EACjB,KAAK,CAAC,EAAE,YAAY,GACnB,mBAAmB,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AA0DF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CAoX5F"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAEpB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAUvD,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EAEb,SAAS,EAET,gBAAgB,EAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AA0C7D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAEvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI,CAAC;IACxF,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IAC5C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAClD,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,MAAM,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,SAAS,MAAM,EAAE,CAAC;IACxE,OAAO,CACL,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,WAAW,EACjB,KAAK,CAAC,EAAE,YAAY,GACnB,SAAS,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;IACvD,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AAmFF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CA8jB5F"}