memory-mimir 1.0.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.
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Typed HTTP client for the Mimir unified memory REST API.
3
+ * Pure fetch-based — no dependencies.
4
+ */
5
+ export interface MimirConfig {
6
+ readonly url: string;
7
+ readonly apiKey?: string;
8
+ readonly timeoutMs: number;
9
+ }
10
+ export declare function defaultConfig(): MimirConfig;
11
+ export interface APIResponse<T = unknown> {
12
+ readonly status: "ok" | "error";
13
+ readonly message?: string;
14
+ readonly result?: T;
15
+ readonly error?: string;
16
+ }
17
+ /** IngestResult — Go API returns PascalCase (no json tags on struct). */
18
+ export interface IngestResult {
19
+ readonly EpisodeCount: number;
20
+ readonly EntityCount: number;
21
+ readonly RelationCount: number;
22
+ readonly EventLogCount: number;
23
+ readonly ForesightCount: number;
24
+ }
25
+ export interface SessionMessage {
26
+ readonly role: "user" | "assistant";
27
+ readonly sender_name: string;
28
+ readonly content: string;
29
+ }
30
+ export interface IngestSessionRequest {
31
+ readonly user_id: string;
32
+ readonly group_id: string;
33
+ readonly messages: readonly SessionMessage[];
34
+ readonly timestamp?: string;
35
+ }
36
+ export interface IngestNoteRequest {
37
+ readonly note_id?: string;
38
+ readonly user_id: string;
39
+ readonly group_id: string;
40
+ readonly content: string;
41
+ readonly timestamp?: string;
42
+ }
43
+ export type RetrieveMethod = "rrf" | "bm25" | "vector" | "agentic" | "full";
44
+ export interface SearchRequest {
45
+ readonly query: string;
46
+ readonly user_id: string;
47
+ readonly group_id: string;
48
+ readonly retrieve_method?: RetrieveMethod;
49
+ readonly memory_types?: readonly string[];
50
+ readonly top_k?: number;
51
+ readonly start_time?: string;
52
+ readonly end_time?: string;
53
+ }
54
+ export interface SearchResultItem {
55
+ readonly id: string;
56
+ readonly type: string;
57
+ readonly score: number;
58
+ readonly sources: readonly string[];
59
+ readonly data: Record<string, unknown>;
60
+ }
61
+ export interface SearchResponse {
62
+ readonly results: readonly SearchResultItem[];
63
+ readonly foresight_context?: string;
64
+ }
65
+ export interface GraphTraverseRequest {
66
+ readonly entity_names?: readonly string[];
67
+ readonly entity_ids?: readonly string[];
68
+ readonly group_id: string;
69
+ readonly hops?: number;
70
+ readonly max_results?: number;
71
+ }
72
+ export interface SeedEntityMatch {
73
+ readonly input_name?: string;
74
+ readonly entity_id: string;
75
+ readonly match_type: "exact" | "fuzzy" | "id";
76
+ }
77
+ export interface Entity {
78
+ readonly id: string;
79
+ readonly name: string;
80
+ readonly entity_type: string;
81
+ readonly group_id: string;
82
+ readonly summary: string;
83
+ readonly aliases?: readonly string[];
84
+ readonly created_at: string;
85
+ readonly updated_at: string;
86
+ }
87
+ export interface Relation {
88
+ readonly id: string;
89
+ readonly source_entity_id: string;
90
+ readonly target_entity_id: string;
91
+ readonly relation_type: string;
92
+ readonly fact: string;
93
+ readonly valid_at?: string;
94
+ readonly invalid_at?: string;
95
+ }
96
+ export interface GraphTraverseResult {
97
+ readonly seed_entities: readonly SeedEntityMatch[];
98
+ readonly entities: readonly Entity[];
99
+ readonly relations: readonly Relation[];
100
+ readonly total_entities: number;
101
+ readonly total_relations: number;
102
+ }
103
+ export interface BatchNoteItemResult {
104
+ readonly note_id: string;
105
+ readonly status: "ok" | "error";
106
+ readonly error?: string;
107
+ readonly result?: IngestResult;
108
+ }
109
+ export interface BatchNotesResponse {
110
+ readonly total: number;
111
+ readonly success: number;
112
+ readonly failed: number;
113
+ readonly items: readonly BatchNoteItemResult[];
114
+ readonly combined: IngestResult;
115
+ }
116
+ export interface ConsolidateRequest {
117
+ readonly user_id: string;
118
+ }
119
+ export declare class MimirClient {
120
+ private readonly config;
121
+ constructor(config?: Partial<MimirConfig>);
122
+ /** Validate API key and fetch user identity from /api/v1/me. */
123
+ me(): Promise<{
124
+ user_id: string;
125
+ group_id: string;
126
+ display_name: string;
127
+ }>;
128
+ /** Health check — returns true if Mimir is reachable. */
129
+ health(): Promise<boolean>;
130
+ /** Search memory. Default retrieve_method: "full" (RRF + graph traverse). */
131
+ search(userId: string, query: string, options?: {
132
+ readonly groupId?: string;
133
+ readonly retrieveMethod?: RetrieveMethod;
134
+ readonly memoryTypes?: readonly string[];
135
+ readonly topK?: number;
136
+ readonly startTime?: string;
137
+ readonly endTime?: string;
138
+ }): Promise<SearchResponse>;
139
+ /** Ingest a conversation session (batch of messages). */
140
+ ingestSession(userId: string, messages: readonly SessionMessage[], options?: {
141
+ readonly groupId?: string;
142
+ readonly timestamp?: string;
143
+ }): Promise<IngestResult>;
144
+ /** Ingest a single note/fact. */
145
+ ingestNote(userId: string, content: string, options?: {
146
+ readonly groupId?: string;
147
+ readonly noteId?: string;
148
+ readonly timestamp?: string;
149
+ }): Promise<IngestResult>;
150
+ /** Batch ingest multiple notes concurrently (server-side parallelism). */
151
+ ingestBatchNotes(notes: readonly {
152
+ readonly userId: string;
153
+ readonly groupId?: string;
154
+ readonly noteId?: string;
155
+ readonly content: string;
156
+ readonly timestamp?: string;
157
+ }[], options?: {
158
+ readonly concurrency?: number;
159
+ }): Promise<BatchNotesResponse>;
160
+ /** Trigger profile consolidation. */
161
+ consolidate(userId: string): Promise<void>;
162
+ /** Traverse knowledge graph from entity names. */
163
+ graphTraverse(entityNames: readonly string[], groupId: string, options?: {
164
+ readonly hops?: number;
165
+ readonly maxResults?: number;
166
+ }): Promise<GraphTraverseResult>;
167
+ private get;
168
+ private post;
169
+ private headers;
170
+ }
171
+ export declare class MimirError extends Error {
172
+ readonly statusCode: number;
173
+ constructor(message: string, statusCode: number);
174
+ }
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Typed HTTP client for the Mimir unified memory REST API.
3
+ * Pure fetch-based — no dependencies.
4
+ */
5
+ export function defaultConfig() {
6
+ return {
7
+ url: process.env.MIMIR_URL ?? "https://api.allinmimir.com",
8
+ apiKey: process.env.MIMIR_API_KEY,
9
+ timeoutMs: 30_000,
10
+ };
11
+ }
12
+ // ─── Client ──────────────────────────────────────────────────
13
+ export class MimirClient {
14
+ config;
15
+ constructor(config) {
16
+ const merged = { ...defaultConfig(), ...config };
17
+ this.config = { ...merged, url: validateUrl(merged.url) };
18
+ }
19
+ /** Validate API key and fetch user identity from /api/v1/me. */
20
+ async me() {
21
+ const url = `${this.config.url}/api/v1/me`;
22
+ const controller = new AbortController();
23
+ const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);
24
+ try {
25
+ const resp = await fetch(url, {
26
+ method: "GET",
27
+ headers: this.headers(),
28
+ signal: controller.signal,
29
+ });
30
+ if (!resp.ok) {
31
+ const body = await resp.text();
32
+ throw new MimirError(`GET /api/v1/me failed: ${resp.status} ${body}`, resp.status);
33
+ }
34
+ return (await resp.json());
35
+ }
36
+ finally {
37
+ clearTimeout(timeout);
38
+ }
39
+ }
40
+ /** Health check — returns true if Mimir is reachable. */
41
+ async health() {
42
+ try {
43
+ const resp = await this.get("/health");
44
+ return resp.status === "ok";
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ /** Search memory. Default retrieve_method: "full" (RRF + graph traverse). */
51
+ async search(userId, query, options) {
52
+ const body = {
53
+ query,
54
+ user_id: userId,
55
+ group_id: options?.groupId ?? userId,
56
+ retrieve_method: options?.retrieveMethod ?? "full",
57
+ memory_types: options?.memoryTypes,
58
+ top_k: options?.topK ?? 10,
59
+ start_time: options?.startTime,
60
+ end_time: options?.endTime,
61
+ };
62
+ const resp = await this.post("/api/v1/search", body);
63
+ return resp.result ?? { results: [] };
64
+ }
65
+ /** Ingest a conversation session (batch of messages). */
66
+ async ingestSession(userId, messages, options) {
67
+ const body = {
68
+ user_id: userId,
69
+ group_id: options?.groupId ?? userId,
70
+ messages,
71
+ timestamp: options?.timestamp,
72
+ };
73
+ const resp = await this.post("/api/v1/ingest/session", body);
74
+ return resp.result ?? emptyIngestResult();
75
+ }
76
+ /** Ingest a single note/fact. */
77
+ async ingestNote(userId, content, options) {
78
+ const body = {
79
+ user_id: userId,
80
+ group_id: options?.groupId ?? userId,
81
+ note_id: options?.noteId,
82
+ content,
83
+ timestamp: options?.timestamp,
84
+ };
85
+ const resp = await this.post("/api/v1/ingest/note", body);
86
+ return resp.result ?? emptyIngestResult();
87
+ }
88
+ /** Batch ingest multiple notes concurrently (server-side parallelism). */
89
+ async ingestBatchNotes(notes, options) {
90
+ const body = {
91
+ notes: notes.map((n) => ({
92
+ note_id: n.noteId,
93
+ user_id: n.userId,
94
+ group_id: n.groupId ?? n.userId,
95
+ content: n.content,
96
+ timestamp: n.timestamp,
97
+ })),
98
+ concurrency: options?.concurrency ?? 3,
99
+ };
100
+ const resp = await this.post("/api/v1/ingest/batch-notes", body);
101
+ return (resp.result ?? {
102
+ total: 0,
103
+ success: 0,
104
+ failed: 0,
105
+ items: [],
106
+ combined: emptyIngestResult(),
107
+ });
108
+ }
109
+ /** Trigger profile consolidation. */
110
+ async consolidate(userId) {
111
+ const body = { user_id: userId };
112
+ await this.post("/api/v1/consolidate", body);
113
+ }
114
+ /** Traverse knowledge graph from entity names. */
115
+ async graphTraverse(entityNames, groupId, options) {
116
+ const body = {
117
+ entity_names: entityNames,
118
+ group_id: groupId,
119
+ hops: options?.hops ?? 2,
120
+ max_results: options?.maxResults ?? 50,
121
+ };
122
+ const resp = await this.post("/api/v1/graph/traverse", body);
123
+ return (resp.result ?? {
124
+ seed_entities: [],
125
+ entities: [],
126
+ relations: [],
127
+ total_entities: 0,
128
+ total_relations: 0,
129
+ });
130
+ }
131
+ // ─── HTTP Helpers ────────────────────────────────────────
132
+ async get(path) {
133
+ const url = `${this.config.url}${path}`;
134
+ const controller = new AbortController();
135
+ const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);
136
+ try {
137
+ const resp = await fetch(url, {
138
+ method: "GET",
139
+ headers: this.headers(),
140
+ signal: controller.signal,
141
+ });
142
+ if (!resp.ok) {
143
+ const body = await resp.text();
144
+ throw new MimirError(`GET ${path} failed: ${resp.status} ${body}`, resp.status);
145
+ }
146
+ const json = (await resp.json());
147
+ if (json.status === "error") {
148
+ throw new MimirError(`GET ${path}: ${json.error}`, 500);
149
+ }
150
+ return json;
151
+ }
152
+ finally {
153
+ clearTimeout(timeout);
154
+ }
155
+ }
156
+ async post(path, body) {
157
+ const url = `${this.config.url}${path}`;
158
+ const controller = new AbortController();
159
+ // Ingest/consolidate can take 10+ minutes for large sessions (LLM extraction).
160
+ // The server detaches from client context so it will finish even if we disconnect,
161
+ // but we still want to wait long enough to get the response when possible.
162
+ const isIngest = path.includes("/ingest") || path.includes("/consolidate");
163
+ const timeoutMs = isIngest
164
+ ? Math.max(this.config.timeoutMs, 900_000) // 15 minutes for ingest
165
+ : this.config.timeoutMs;
166
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
167
+ try {
168
+ const resp = await fetch(url, {
169
+ method: "POST",
170
+ headers: this.headers(),
171
+ body: JSON.stringify(body),
172
+ signal: controller.signal,
173
+ });
174
+ if (!resp.ok) {
175
+ const text = await resp.text();
176
+ throw new MimirError(`POST ${path} failed: ${resp.status} ${text}`, resp.status);
177
+ }
178
+ const json = (await resp.json());
179
+ if (json.status === "error") {
180
+ throw new MimirError(`POST ${path}: ${json.error}`, 500);
181
+ }
182
+ return json;
183
+ }
184
+ finally {
185
+ clearTimeout(timeout);
186
+ }
187
+ }
188
+ headers() {
189
+ const h = {
190
+ "Content-Type": "application/json",
191
+ };
192
+ if (this.config.apiKey) {
193
+ h["Authorization"] = `Bearer ${this.config.apiKey}`;
194
+ }
195
+ return h;
196
+ }
197
+ }
198
+ // ─── Error ───────────────────────────────────────────────────
199
+ export class MimirError extends Error {
200
+ statusCode;
201
+ constructor(message, statusCode) {
202
+ super(message);
203
+ this.name = "MimirError";
204
+ this.statusCode = statusCode;
205
+ }
206
+ }
207
+ // ─── Helpers ─────────────────────────────────────────────────
208
+ function emptyIngestResult() {
209
+ return {
210
+ EpisodeCount: 0,
211
+ EntityCount: 0,
212
+ RelationCount: 0,
213
+ EventLogCount: 0,
214
+ ForesightCount: 0,
215
+ };
216
+ }
217
+ /** Validate and normalize the Mimir server URL. */
218
+ function validateUrl(raw) {
219
+ const parsed = new URL(raw); // throws on malformed URL
220
+ if (!["http:", "https:"].includes(parsed.protocol)) {
221
+ throw new Error(`MIMIR_URL must use http or https, got: ${parsed.protocol}`);
222
+ }
223
+ return raw.replace(/\/$/, ""); // strip trailing slash
224
+ }
225
+ //# sourceMappingURL=mimir-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mimir-client.js","sourceRoot":"","sources":["../src/mimir-client.ts"],"names":[],"mappings":"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"}
package/dist/test.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Unit tests for memory-mimir plugin.
3
+ * Run with: npx tsx src/test.ts
4
+ */
5
+ export {};
package/dist/test.js ADDED
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Unit tests for memory-mimir plugin.
3
+ * Run with: npx tsx src/test.ts
4
+ */
5
+ import { formatSearchResults, formatGraphResults } from "./formatter.js";
6
+ import { extractDateFromFilename } from "./migration-helpers.js";
7
+ let passed = 0;
8
+ let failed = 0;
9
+ function assert(condition, message) {
10
+ if (condition) {
11
+ passed++;
12
+ console.log(` PASS: ${message}`);
13
+ }
14
+ else {
15
+ failed++;
16
+ console.error(` FAIL: ${message}`);
17
+ }
18
+ }
19
+ function assertEqual(actual, expected, message) {
20
+ if (actual === expected) {
21
+ passed++;
22
+ console.log(` PASS: ${message}`);
23
+ }
24
+ else {
25
+ failed++;
26
+ console.error(` FAIL: ${message}`);
27
+ console.error(` Expected: ${JSON.stringify(expected)}`);
28
+ console.error(` Actual: ${JSON.stringify(actual)}`);
29
+ }
30
+ }
31
+ // ─── Formatter Tests ─────────────────────────────────────────
32
+ console.log("\n=== Formatter Tests ===\n");
33
+ // Test: empty results
34
+ {
35
+ const response = { results: [] };
36
+ const result = formatSearchResults(response);
37
+ assertEqual(result, "", "empty results → empty string");
38
+ }
39
+ // Test: episode formatting
40
+ {
41
+ const response = {
42
+ results: [
43
+ {
44
+ id: "ep-1",
45
+ type: "episode",
46
+ score: 0.9,
47
+ sources: ["bm25", "vector"],
48
+ data: {
49
+ title: "Calvin prefers dark roast coffee",
50
+ content: "Calvin mentioned he likes dark roast coffee from Blue Bottle",
51
+ occurred_at: "2023-07-15T10:30:00Z",
52
+ },
53
+ },
54
+ ],
55
+ };
56
+ const result = formatSearchResults(response);
57
+ assert(result.includes("[2023-07-15]"), "has date");
58
+ assert(result.includes("dark roast coffee"), "has content");
59
+ }
60
+ // Test: multiple types
61
+ {
62
+ const response = {
63
+ results: [
64
+ {
65
+ id: "ep-1",
66
+ type: "episode",
67
+ score: 0.9,
68
+ sources: ["bm25"],
69
+ data: {
70
+ title: "Meeting about Q4",
71
+ occurred_at: "2023-08-01T00:00:00Z",
72
+ },
73
+ },
74
+ {
75
+ id: "ent-1",
76
+ type: "entity",
77
+ score: 0.8,
78
+ sources: ["vector"],
79
+ data: {
80
+ name: "Sarah",
81
+ entity_type: "person",
82
+ summary: "Project manager at Google",
83
+ },
84
+ },
85
+ {
86
+ id: "rel-1",
87
+ type: "relation",
88
+ score: 0.7,
89
+ sources: ["graph"],
90
+ data: {
91
+ relation_type: "married_to",
92
+ fact: "Calvin is married to Sarah",
93
+ },
94
+ },
95
+ ],
96
+ };
97
+ const result = formatSearchResults(response);
98
+ assert(result.includes("[entity] Sarah"), "has entity with prefix");
99
+ assert(result.includes("[relation] married_to"), "has relation with prefix");
100
+ }
101
+ // Test: foresight context
102
+ {
103
+ const response = {
104
+ results: [
105
+ {
106
+ id: "ep-1",
107
+ type: "episode",
108
+ score: 0.9,
109
+ sources: ["bm25"],
110
+ data: { title: "Test", occurred_at: "2023-01-01T00:00:00Z" },
111
+ },
112
+ ],
113
+ foresight_context: "User has a trip to Japan planned for October",
114
+ };
115
+ const result = formatSearchResults(response);
116
+ assert(result.includes("trip to Japan"), "has foresight context");
117
+ }
118
+ // Test: truncation
119
+ {
120
+ const longContent = "A".repeat(300);
121
+ const response = {
122
+ results: [
123
+ {
124
+ id: "ep-1",
125
+ type: "episode",
126
+ score: 0.9,
127
+ sources: ["bm25"],
128
+ data: { title: longContent, occurred_at: "2023-01-01T00:00:00Z" },
129
+ },
130
+ ],
131
+ };
132
+ const result = formatSearchResults(response, { maxChars: 200, maxItems: 8 });
133
+ assert(result.length <= 200, `truncated to maxChars (got ${result.length})`);
134
+ }
135
+ // Test: graph results formatting
136
+ {
137
+ const graphResult = {
138
+ seed_entities: [
139
+ { input_name: "Calvin", entity_id: "e1", match_type: "exact" },
140
+ ],
141
+ entities: [
142
+ {
143
+ id: "e1",
144
+ name: "Calvin",
145
+ entity_type: "person",
146
+ group_id: "g1",
147
+ summary: "Software engineer",
148
+ created_at: "2023-01-01",
149
+ updated_at: "2023-07-01",
150
+ },
151
+ {
152
+ id: "e2",
153
+ name: "Sarah",
154
+ entity_type: "person",
155
+ group_id: "g1",
156
+ summary: "Product manager at Google",
157
+ created_at: "2023-01-01",
158
+ updated_at: "2023-07-01",
159
+ },
160
+ ],
161
+ relations: [
162
+ {
163
+ id: "r1",
164
+ source_entity_id: "e1",
165
+ target_entity_id: "e2",
166
+ relation_type: "married_to",
167
+ fact: "Calvin is married to Sarah",
168
+ },
169
+ ],
170
+ total_entities: 2,
171
+ total_relations: 1,
172
+ };
173
+ const result = formatGraphResults(graphResult);
174
+ assert(result.includes("## Entity Relationships"), "has graph header");
175
+ assert(result.includes("**Calvin**"), "has source entity");
176
+ assert(result.includes("Calvin is married to Sarah"), "has relation fact");
177
+ }
178
+ // ─── Date Extraction Tests ───────────────────────────────────
179
+ console.log("\n=== Date Extraction Tests ===\n");
180
+ {
181
+ assertEqual(extractDateFromFilename("2025-03-01.md"), "2025-03-01T00:00:00Z", "ISO date filename");
182
+ assertEqual(extractDateFromFilename("memory-2025-03-01.md"), "2025-03-01T00:00:00Z", "prefixed ISO date filename");
183
+ assertEqual(extractDateFromFilename("20250301.md"), "2025-03-01T00:00:00Z", "compact date filename");
184
+ assertEqual(extractDateFromFilename("MEMORY.md"), undefined, "no date in filename");
185
+ assertEqual(extractDateFromFilename("random-notes.md"), undefined, "no date in arbitrary filename");
186
+ }
187
+ // ─── Keyword Extraction Tests ────────────────────────────────
188
+ console.log("\n=== Keyword Extraction Tests ===\n");
189
+ // Import via dynamic import to test the extractKeywords function
190
+ // Since it's not exported, we test indirectly through the index module
191
+ // For now, test the concept:
192
+ {
193
+ // Simple keyword extraction test
194
+ const stopWords = new Set([
195
+ "the",
196
+ "a",
197
+ "is",
198
+ "do",
199
+ "you",
200
+ "remember",
201
+ "what",
202
+ ]);
203
+ const testExtract = (msg) => {
204
+ return msg
205
+ .toLowerCase()
206
+ .replace(/[^\w\s'-]/g, " ")
207
+ .split(/\s+/)
208
+ .filter((w) => w.length > 2 && !stopWords.has(w))
209
+ .slice(0, 5)
210
+ .join(" ");
211
+ };
212
+ const result1 = testExtract("Do you remember what Calvin said about coffee?");
213
+ assert(result1.includes("calvin"), "extracts 'calvin' from question");
214
+ assert(result1.includes("coffee"), "extracts 'coffee' from question");
215
+ const result2 = testExtract("What is Sarah's job?");
216
+ assert(result2.includes("sarah's"), "extracts name with possessive");
217
+ assert(result2.includes("job"), "extracts 'job'");
218
+ }
219
+ // ─── Summary ─────────────────────────────────────────────────
220
+ console.log(`\n${"=".repeat(40)}`);
221
+ console.log(`Results: ${passed} passed, ${failed} failed`);
222
+ console.log(`${"=".repeat(40)}\n`);
223
+ process.exit(failed > 0 ? 1 : 0);
224
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,IAAI,MAAM,GAAG,CAAC,CAAC;AACf,IAAI,MAAM,GAAG,CAAC,CAAC;AAEf,SAAS,MAAM,CAAC,SAAkB,EAAE,OAAe;IACjD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAI,MAAS,EAAE,QAAW,EAAE,OAAe;IAC7D,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC3D,OAAO,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,gEAAgE;AAEhE,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AAE3C,sBAAsB;AACtB,CAAC;IACC,MAAM,QAAQ,GAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC7C,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE,8BAA8B,CAAC,CAAC;AAC1D,CAAC;AAED,2BAA2B;AAC3B,CAAC;IACC,MAAM,QAAQ,GAAmB;QAC/B,OAAO,EAAE;YACP;gBACE,EAAE,EAAE,MAAM;gBACV,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;gBAC3B,IAAI,EAAE;oBACJ,KAAK,EAAE,kCAAkC;oBACzC,OAAO,EACL,8DAA8D;oBAChE,WAAW,EAAE,sBAAsB;iBACpC;aACF;SACF;KACF,CAAC;IACF,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,CAAC;IACpD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,aAAa,CAAC,CAAC;AAC9D,CAAC;AAED,uBAAuB;AACvB,CAAC;IACC,MAAM,QAAQ,GAAmB;QAC/B,OAAO,EAAE;YACP;gBACE,EAAE,EAAE,MAAM;gBACV,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,CAAC,MAAM,CAAC;gBACjB,IAAI,EAAE;oBACJ,KAAK,EAAE,kBAAkB;oBACzB,WAAW,EAAE,sBAAsB;iBACpC;aACF;YACD;gBACE,EAAE,EAAE,OAAO;gBACX,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,CAAC,QAAQ,CAAC;gBACnB,IAAI,EAAE;oBACJ,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,QAAQ;oBACrB,OAAO,EAAE,2BAA2B;iBACrC;aACF;YACD;gBACE,EAAE,EAAE,OAAO;gBACX,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,CAAC,OAAO,CAAC;gBAClB,IAAI,EAAE;oBACJ,aAAa,EAAE,YAAY;oBAC3B,IAAI,EAAE,4BAA4B;iBACnC;aACF;SACF;KACF,CAAC;IACF,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,wBAAwB,CAAC,CAAC;IACpE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,0BAA0B,CAAC,CAAC;AAC/E,CAAC;AAED,0BAA0B;AAC1B,CAAC;IACC,MAAM,QAAQ,GAAmB;QAC/B,OAAO,EAAE;YACP;gBACE,EAAE,EAAE,MAAM;gBACV,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,CAAC,MAAM,CAAC;gBACjB,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAE;aAC7D;SACF;QACD,iBAAiB,EAAE,8CAA8C;KAClE,CAAC;IACF,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,uBAAuB,CAAC,CAAC;AACpE,CAAC;AAED,mBAAmB;AACnB,CAAC;IACC,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAmB;QAC/B,OAAO,EAAE;YACP;gBACE,EAAE,EAAE,MAAM;gBACV,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,CAAC,MAAM,CAAC;gBACjB,IAAI,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,sBAAsB,EAAE;aAClE;SACF;KACF,CAAC;IACF,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7E,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,8BAA8B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED,iCAAiC;AACjC,CAAC;IACC,MAAM,WAAW,GAAwB;QACvC,aAAa,EAAE;YACb,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE;SAC/D;QACD,QAAQ,EAAE;YACR;gBACE,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,QAAQ;gBACrB,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,mBAAmB;gBAC5B,UAAU,EAAE,YAAY;gBACxB,UAAU,EAAE,YAAY;aACzB;YACD;gBACE,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,QAAQ;gBACrB,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,2BAA2B;gBACpC,UAAU,EAAE,YAAY;gBACxB,UAAU,EAAE,YAAY;aACzB;SACF;QACD,SAAS,EAAE;YACT;gBACE,EAAE,EAAE,IAAI;gBACR,gBAAgB,EAAE,IAAI;gBACtB,gBAAgB,EAAE,IAAI;gBACtB,aAAa,EAAE,YAAY;gBAC3B,IAAI,EAAE,4BAA4B;aACnC;SACF;QACD,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,CAAC;KACnB,CAAC;IACF,MAAM,MAAM,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACvE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,mBAAmB,CAAC,CAAC;AAC7E,CAAC;AAED,gEAAgE;AAEhE,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;AAEjD,CAAC;IACC,WAAW,CACT,uBAAuB,CAAC,eAAe,CAAC,EACxC,sBAAsB,EACtB,mBAAmB,CACpB,CAAC;IACF,WAAW,CACT,uBAAuB,CAAC,sBAAsB,CAAC,EAC/C,sBAAsB,EACtB,4BAA4B,CAC7B,CAAC;IACF,WAAW,CACT,uBAAuB,CAAC,aAAa,CAAC,EACtC,sBAAsB,EACtB,uBAAuB,CACxB,CAAC;IACF,WAAW,CACT,uBAAuB,CAAC,WAAW,CAAC,EACpC,SAAS,EACT,qBAAqB,CACtB,CAAC;IACF,WAAW,CACT,uBAAuB,CAAC,iBAAiB,CAAC,EAC1C,SAAS,EACT,+BAA+B,CAChC,CAAC;AACJ,CAAC;AAED,gEAAgE;AAEhE,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;AAEpD,iEAAiE;AACjE,uEAAuE;AACvE,6BAA6B;AAE7B,CAAC;IACC,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;QACxB,KAAK;QACL,GAAG;QACH,IAAI;QACJ,IAAI;QACJ,KAAK;QACL,UAAU;QACV,MAAM;KACP,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE;QAClC,OAAO,GAAG;aACP,WAAW,EAAE;aACb,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC;aAC1B,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;aAChD,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;aACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,WAAW,CAAC,gDAAgD,CAAC,CAAC;IAC9E,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,iCAAiC,CAAC,CAAC;IACtE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAEtE,MAAM,OAAO,GAAG,WAAW,CAAC,sBAAsB,CAAC,CAAC;IACpD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,+BAA+B,CAAC,CAAC;IACrE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC,CAAC;AACpD,CAAC;AAED,gEAAgE;AAEhE,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACnC,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,YAAY,MAAM,SAAS,CAAC,CAAC;AAC3D,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AAEnC,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}