@agentshouse/mdruntime-adapter 0.1.0-cfd03209dcd82 → 0.1.0-cfded86738bb2

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 (55) hide show
  1. package/AGENTS.md +294 -276
  2. package/dist/actions.d.ts +16 -5
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +92 -141
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +307 -138
  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/model.d.ts +0 -1
  18. package/dist/model.d.ts.map +1 -1
  19. package/dist/model.js +0 -3
  20. package/dist/part.d.ts +15 -0
  21. package/dist/part.d.ts.map +1 -0
  22. package/dist/part.js +82 -0
  23. package/dist/read.d.ts +65 -18
  24. package/dist/read.d.ts.map +1 -1
  25. package/dist/read.js +302 -122
  26. package/dist/refusal.d.ts.map +1 -1
  27. package/dist/refusal.js +2 -1
  28. package/dist/room-types.d.ts +6 -0
  29. package/dist/room-types.d.ts.map +1 -0
  30. package/dist/room-types.js +66 -0
  31. package/dist/site.d.ts +1 -1
  32. package/dist/site.d.ts.map +1 -1
  33. package/dist/site.js +149 -82
  34. package/dist/stream.d.ts +5 -4
  35. package/dist/stream.d.ts.map +1 -1
  36. package/dist/stream.js +349 -43
  37. package/dist/transport.d.ts +58 -13
  38. package/dist/transport.d.ts.map +1 -1
  39. package/dist/transport.js +1 -1
  40. package/dist/upload.d.ts +12 -0
  41. package/dist/upload.d.ts.map +1 -0
  42. package/dist/upload.js +52 -0
  43. package/dist/version.d.ts +1 -0
  44. package/dist/version.d.ts.map +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist/write.d.ts +12 -1
  47. package/dist/write.d.ts.map +1 -1
  48. package/dist/write.js +98 -57
  49. package/package.json +2 -2
  50. package/dist/handed.d.ts +0 -15
  51. package/dist/handed.d.ts.map +0 -1
  52. package/dist/handed.js +0 -38
  53. package/dist/referrer.d.ts +0 -7
  54. package/dist/referrer.d.ts.map +0 -1
  55. package/dist/referrer.js +0 -35
package/dist/site.js CHANGED
@@ -1,78 +1,108 @@
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
- import { scopeModels, streamedModels, viewModels } from './model.js';
4
- import { advancedScope, bootstrapOf, parseEnumeration, parseSiteBootstrap, refreshFrom, viewOf, } from './read.js';
4
+ import { partModels, streamedModels, viewModels } from './model.js';
5
+ import { bootstrapping, emptyScope, housePart, manifested, parseEnumeration, parseSiteParted, partInventory, refreshFrom, viewOf, wholeView, } from './read.js';
6
+ import { PART_ATTEMPTS, partArrival, partFrame, unverifiedPart } from './part.js';
5
7
  import { classifyDoor, classifyRead, discoveryFailure } from './refusal.js';
8
+ import { HOUSE_ROOM_TYPES } from './room-types.js';
6
9
  import { houseNotifications } from './stream.js';
7
- import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, SITE_FILE_RECORD, SITE_FILES, } from './transport.js';
8
- import { houseReferrer } from './referrer.js';
10
+ import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, SITE_FILES, } from './transport.js';
9
11
  import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
10
12
  const UNCERTAIN = { kind: 'transport-uncertainty' };
13
+ function unfound() {
14
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
15
+ }
11
16
  function siteRoom(tracked) {
12
17
  return {
13
18
  name: tracked.handle,
14
19
  locator: tracked.locator,
15
20
  handle: tracked.handle,
16
21
  roomVersion: roomVersion(tracked),
17
- operations: { read: [''], sync: [''], write: [], delete: [] },
18
- replica: { selection: tracked.locator, admission: 'admitted' },
22
+ operations: { write: [], delete: [] },
23
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
19
24
  providerOwnedPaths: [],
20
25
  };
21
26
  }
22
- function settled(refused) {
23
- return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
24
- }
25
- export function createSiteAdapter(transport) {
27
+ export function createSiteAdapter(transport, snapshot = false) {
26
28
  const notifications = houseNotifications(transport, 'site');
27
29
  const tracked = new Map();
28
- function published(referrer) {
29
- const named = houseReferrer(referrer, tracked);
30
- return named === null || !tracked.has(named.locator) ? null : named;
30
+ const expired = new Map();
31
+ function fileRoute(request) {
32
+ const entry = tracked.get(request.locator);
33
+ if (entry === undefined)
34
+ return { kind: 'room-not-readable', locator: request.locator };
35
+ return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
31
36
  }
32
- async function enumeration(entry, from) {
37
+ async function enumerated(entry, from, page) {
33
38
  const answer = await transport.door(SITE_DOOR_ENUMERATE, {
34
- positions: [presented(entry.authority, from)],
39
+ positions: [
40
+ page === undefined
41
+ ? presented(entry.authority, from)
42
+ : {
43
+ ...presented(entry.authority, { position: page.after, logEpoch: from.logEpoch }),
44
+ page: { through: page.through, read: page.read },
45
+ },
46
+ ],
35
47
  });
36
48
  const classified = classifyRead(answer.status, answer.body, entry.locator);
37
49
  if (classified !== null)
38
50
  return classified;
39
- return parseEnumeration(answer.body, 'site') ?? UNCERTAIN;
51
+ const found = parseEnumeration(answer.body, 'site');
52
+ if (found === null)
53
+ return UNCERTAIN;
54
+ return viewOf(found, entry) ?? { kind: 'room-not-readable', locator: entry.locator };
55
+ }
56
+ async function enumeration(entry, from) {
57
+ const first = await enumerated(entry, from);
58
+ return 'kind' in first ? first : wholeView(first, (page) => enumerated(entry, from, page));
40
59
  }
41
- async function caughtUp(entry) {
42
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}`);
60
+ async function partedRoom(entry) {
61
+ const cut = expired.get(entry.locator);
62
+ const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`);
43
63
  const classified = classifyDoor(answer.status, answer.body, entry.locator);
44
64
  if (classified !== null)
45
- return { failure: classified };
46
- const scope = parseSiteBootstrap(answer.body);
47
- if (scope === null)
48
- return { failure: UNCERTAIN };
49
- if (roomVersion(scope) === roomVersion(entry))
50
- return { scope };
51
- const found = await enumeration(entry, scope);
52
- if ('kind' in found)
53
- return { failure: settled(found) };
54
- const view = viewOf(found, entry);
55
- if (view === undefined)
56
- return { failure: { kind: 'room-not-readable', locator: entry.locator } };
57
- return { scope: advancedScope(scope, view) };
65
+ return classified;
66
+ const room = parseSiteParted(answer.body);
67
+ return room === null || room.anchor !== entry.authority ? UNCERTAIN : room;
68
+ }
69
+ async function fetchedPart(entry, room, listed, received, arriving) {
70
+ if (received !== undefined) {
71
+ const kept = new Uint8Array(received);
72
+ const held = await housePart(room, kept, listed, 'site');
73
+ if (held !== null)
74
+ return 'kind' in held ? held : { scope: held, frame: kept };
75
+ }
76
+ for (let attempt = 0; attempt < PART_ATTEMPTS; attempt += 1) {
77
+ const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}?part=${encodeURIComponent(listed.part)}`, partArrival(listed, arriving));
78
+ const failure = classifyRead(answer.status, answer.body, entry.locator);
79
+ if (failure?.kind === 'beyond-horizon')
80
+ expired.set(entry.locator, room.position);
81
+ if (failure !== null)
82
+ return failure;
83
+ const frame = partFrame(answer.body);
84
+ if (frame === null)
85
+ continue;
86
+ const scope = await housePart(room, frame, listed, 'site');
87
+ if (scope !== null)
88
+ return 'kind' in scope ? scope : { scope, frame };
89
+ }
90
+ return unverifiedPart(entry.locator);
58
91
  }
59
92
  async function refreshed(entry, fromRoomVersion) {
60
93
  const from = logPosition(fromRoomVersion);
61
94
  if (from === null)
62
95
  return { kind: 'beyond-horizon' };
63
- const streamed = notifications.advance(entry, from);
96
+ const streamed = await stepped(notifications.advance(entry, from));
64
97
  if (streamed !== null) {
65
98
  const models = await streamedModels(streamed.schemas, entry, 'site');
66
99
  return models === undefined ? streamed.page : { ...streamed.page, models };
67
100
  }
68
- const found = await enumeration(entry, from);
69
- if ('kind' in found)
70
- return found;
71
- const view = viewOf(found, entry);
72
- if (view === undefined)
73
- return { kind: 'room-not-readable', locator: entry.locator };
101
+ const view = await enumeration(entry, from);
102
+ if ('kind' in view)
103
+ return view;
74
104
  notifications.reach(entry.authority, view);
75
- const answer = refreshFrom(view, fromRoomVersion);
105
+ const answer = await refreshFrom(view, fromRoomVersion);
76
106
  if (answer.kind !== 'net-advancement')
77
107
  return answer;
78
108
  const models = await viewModels(view, entry);
@@ -80,6 +110,8 @@ export function createSiteAdapter(transport) {
80
110
  }
81
111
  return {
82
112
  localSaves: true,
113
+ exhaustiveDiscovery: true,
114
+ roomTypes: HOUSE_ROOM_TYPES,
83
115
  async authorize() {
84
116
  return {};
85
117
  },
@@ -102,14 +134,42 @@ export function createSiteAdapter(transport) {
102
134
  const entry = tracked.get(request.locator);
103
135
  if (entry === undefined)
104
136
  return { kind: 'room-not-readable', locator: request.locator };
105
- if (request.pageToken !== undefined)
106
- return UNCERTAIN;
107
- const held = await caughtUp(entry);
108
- if ('failure' in held)
109
- return held.failure;
110
- notifications.reach(entry.authority, held.scope);
111
- const models = await scopeModels(held.scope, entry);
112
- return { ...bootstrapOf(held.scope), ...(models === undefined ? {} : { models }) };
137
+ let continued;
138
+ let inventory;
139
+ if (request.pageToken === undefined) {
140
+ const room = await partedRoom(entry);
141
+ if ('kind' in room)
142
+ return room;
143
+ continued = { room, next: 0, seen: [] };
144
+ inventory = partInventory(room);
145
+ if (inventory.parts > 0)
146
+ return manifested(room, inventory, JSON.stringify(continued));
147
+ }
148
+ else
149
+ continued = JSON.parse(request.pageToken);
150
+ const listed = continued.room.parts[continued.next];
151
+ const sent = listed === undefined
152
+ ? { scope: emptyScope(continued.room), frame: null }
153
+ : await fetchedPart(entry, continued.room, listed, request.received, request.arriving);
154
+ if ('kind' in sent)
155
+ return sent;
156
+ const { scope } = sent;
157
+ notifications.reach(entry.authority, scope);
158
+ const next = continued.next + 1;
159
+ const more = next < continued.room.parts.length;
160
+ const seen = [
161
+ ...continued.seen,
162
+ ...entry.schemas.filter((schema) => scope.files.some((file) => file.path === schema)),
163
+ ];
164
+ const models = await partModels(scope, entry, new Set(seen), !more);
165
+ const { folders: _folders, ...page } = await stepped(bootstrapping(scope));
166
+ return {
167
+ ...page,
168
+ ...(models === undefined ? {} : { models }),
169
+ ...(more ? { pageToken: JSON.stringify({ ...continued, next, seen }) } : {}),
170
+ ...(inventory === undefined ? {} : { inventory }),
171
+ ...(sent.frame === null ? {} : { received: sent.frame }),
172
+ };
113
173
  },
114
174
  async refresh(_authorization, request) {
115
175
  const entry = tracked.get(request.locator);
@@ -117,6 +177,11 @@ export function createSiteAdapter(transport) {
117
177
  return { kind: 'room-not-readable', locator: request.locator };
118
178
  if (request.pageToken !== undefined)
119
179
  return UNCERTAIN;
180
+ if (snapshot) {
181
+ return request.fromRoomVersion === roomVersion(entry)
182
+ ? { kind: 'still-current' }
183
+ : { kind: 'beyond-horizon' };
184
+ }
120
185
  return refreshed(entry, request.fromRoomVersion);
121
186
  },
122
187
  async mutate() {
@@ -126,30 +191,25 @@ export function createSiteAdapter(transport) {
126
191
  return { kind: 'no-history' };
127
192
  },
128
193
  async binary(_authorization, request) {
129
- const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
130
- if (named === null) {
131
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
132
- }
133
- if (request.fileRef === undefined) {
134
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
135
- }
136
- const { room_ref, path, record } = named.referrer;
137
- const read = await transport.download(`${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
138
- ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
139
- : encodeURIComponent(path)}`);
140
- if (read.status === 404) {
141
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
142
- }
143
- return read.status === 200 && read.blob !== null
144
- ? { kind: 'binary', blob: read.blob }
194
+ const route = fileRoute(request);
195
+ if (typeof route !== 'string')
196
+ return route;
197
+ const read = await transport.download(route);
198
+ if (read.status === 404)
199
+ return unfound();
200
+ return read.status === 200 && read.body !== null
201
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
145
202
  : UNCERTAIN;
146
203
  },
147
- referrerScope(referrer) {
148
- const named = published(referrer);
149
- if (named === null)
150
- return null;
151
- const { path } = named.referrer;
152
- return { kind: 'room', locator: named.locator, ...(path === undefined ? {} : { path }) };
204
+ async link(_authorization, request) {
205
+ const route = fileRoute(request);
206
+ if (typeof route !== 'string')
207
+ return route;
208
+ return {
209
+ kind: 'link',
210
+ url: route,
211
+ name: request.path.slice(request.path.lastIndexOf('/') + 1),
212
+ };
153
213
  },
154
214
  reached(locator, version, target) {
155
215
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
@@ -170,20 +230,27 @@ export function createSiteAdapter(transport) {
170
230
  return UNCERTAIN;
171
231
  return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMIT);
172
232
  },
173
- roomStream: {
174
- hold(rooms) {
175
- notifications.send(rooms.flatMap((room) => {
176
- const entry = tracked.get(room.locator);
177
- const at = logPosition(room.roomVersion);
178
- if (entry === undefined || at === null)
179
- return [];
180
- notifications.reach(entry.authority, at);
181
- return [presented(entry.authority, at)];
182
- }));
233
+ roomStream: snapshot
234
+ ? undefined
235
+ : {
236
+ hold(rooms) {
237
+ notifications.send(rooms.flatMap((room) => {
238
+ const entry = tracked.get(room.locator);
239
+ const at = logPosition(room.roomVersion);
240
+ if (entry === undefined || at === null)
241
+ return [];
242
+ notifications.reach(entry.authority, at);
243
+ return [presented(entry.authority, at)];
244
+ }));
245
+ },
246
+ reopen: notifications.reopen,
247
+ observe: notifications.observe,
248
+ published(locator, roomVersion) {
249
+ const at = logPosition(roomVersion);
250
+ if (at !== null)
251
+ notifications.published(locator, at);
252
+ },
183
253
  },
184
- reopen: notifications.reopen,
185
- observe: notifications.observe,
186
- },
187
254
  serviceMode: notifications.serviceMode,
188
255
  };
189
256
  }
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;AAEhC,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;AAgB7D,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;AAuBF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CA8S5F"}
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"}