@z3rno/sdk 0.3.0 → 0.5.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/index.cjs +374 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +509 -1
- package/dist/index.d.ts +509 -1
- package/dist/index.js +363 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -343,6 +343,112 @@ var EndSessionResponse = zod.z.object({
|
|
|
343
343
|
/** Number of memories created during the session. */
|
|
344
344
|
memory_count: zod.z.number()
|
|
345
345
|
});
|
|
346
|
+
var IngestJobResponse = zod.z.object({
|
|
347
|
+
job_id: zod.z.string(),
|
|
348
|
+
kind: zod.z.string(),
|
|
349
|
+
status: zod.z.string(),
|
|
350
|
+
dataset_id: zod.z.string().nullable().optional(),
|
|
351
|
+
enqueued_at: zod.z.string()
|
|
352
|
+
});
|
|
353
|
+
var IngestJobStatusResponse = zod.z.object({
|
|
354
|
+
job_id: zod.z.string(),
|
|
355
|
+
agent_id: zod.z.string(),
|
|
356
|
+
dataset_id: zod.z.string().nullable().optional(),
|
|
357
|
+
kind: zod.z.string(),
|
|
358
|
+
status: zod.z.string(),
|
|
359
|
+
source_uri: zod.z.string().nullable().optional(),
|
|
360
|
+
content_type: zod.z.string().nullable().optional(),
|
|
361
|
+
filename: zod.z.string().nullable().optional(),
|
|
362
|
+
file_size: zod.z.number().nullable().optional(),
|
|
363
|
+
memory_ids: zod.z.array(zod.z.string()).default([]),
|
|
364
|
+
memos_written: zod.z.number().default(0),
|
|
365
|
+
distill_job_id: zod.z.string().nullable().optional(),
|
|
366
|
+
codegraph_memos_written: zod.z.number().default(0),
|
|
367
|
+
codegraph_edges_written: zod.z.number().default(0),
|
|
368
|
+
error: zod.z.string().nullable().optional(),
|
|
369
|
+
warnings: zod.z.array(zod.z.record(zod.z.unknown())).default([]),
|
|
370
|
+
started_at: zod.z.string().nullable().optional(),
|
|
371
|
+
completed_at: zod.z.string().nullable().optional(),
|
|
372
|
+
created_at: zod.z.string().nullable().optional(),
|
|
373
|
+
updated_at: zod.z.string().nullable().optional()
|
|
374
|
+
});
|
|
375
|
+
var DistillJobResponse = zod.z.object({
|
|
376
|
+
job_id: zod.z.string(),
|
|
377
|
+
status: zod.z.string(),
|
|
378
|
+
memory_ids: zod.z.array(zod.z.string()),
|
|
379
|
+
enqueued_at: zod.z.string()
|
|
380
|
+
});
|
|
381
|
+
var DistillJobStatusResponse = zod.z.object({
|
|
382
|
+
job_id: zod.z.string(),
|
|
383
|
+
agent_id: zod.z.string(),
|
|
384
|
+
status: zod.z.string(),
|
|
385
|
+
model: zod.z.string(),
|
|
386
|
+
memory_ids: zod.z.array(zod.z.string()),
|
|
387
|
+
chunk_size: zod.z.number(),
|
|
388
|
+
chunk_overlap: zod.z.number(),
|
|
389
|
+
max_concurrency: zod.z.number(),
|
|
390
|
+
chunks_total: zod.z.number(),
|
|
391
|
+
chunks_failed: zod.z.number(),
|
|
392
|
+
entities_extracted: zod.z.number(),
|
|
393
|
+
relationships_extracted: zod.z.number(),
|
|
394
|
+
memos_written: zod.z.number(),
|
|
395
|
+
error: zod.z.string().nullable().optional(),
|
|
396
|
+
started_at: zod.z.string().nullable().optional(),
|
|
397
|
+
completed_at: zod.z.string().nullable().optional(),
|
|
398
|
+
created_at: zod.z.string().nullable().optional(),
|
|
399
|
+
updated_at: zod.z.string().nullable().optional()
|
|
400
|
+
});
|
|
401
|
+
var RefineJobResponse = zod.z.object({
|
|
402
|
+
job_id: zod.z.string(),
|
|
403
|
+
status: zod.z.string(),
|
|
404
|
+
dataset_id: zod.z.string().nullable().optional(),
|
|
405
|
+
enqueued_at: zod.z.string()
|
|
406
|
+
});
|
|
407
|
+
var RefineJobStatusResponse = zod.z.object({
|
|
408
|
+
job_id: zod.z.string(),
|
|
409
|
+
status: zod.z.string(),
|
|
410
|
+
dataset_id: zod.z.string().nullable().optional(),
|
|
411
|
+
trigger: zod.z.string(),
|
|
412
|
+
memos_scanned: zod.z.number().default(0),
|
|
413
|
+
memos_deduped: zod.z.number().default(0),
|
|
414
|
+
edges_reweighted: zod.z.number().default(0),
|
|
415
|
+
edges_pruned: zod.z.number().default(0),
|
|
416
|
+
feedback_drained: zod.z.number().default(0),
|
|
417
|
+
job_metadata: zod.z.record(zod.z.unknown()).default({}),
|
|
418
|
+
error: zod.z.string().nullable().optional(),
|
|
419
|
+
started_at: zod.z.string().nullable().optional(),
|
|
420
|
+
completed_at: zod.z.string().nullable().optional(),
|
|
421
|
+
created_at: zod.z.string().nullable().optional(),
|
|
422
|
+
updated_at: zod.z.string().nullable().optional()
|
|
423
|
+
});
|
|
424
|
+
var ConversationResponse = zod.z.object({
|
|
425
|
+
id: zod.z.string(),
|
|
426
|
+
agent_id: zod.z.string(),
|
|
427
|
+
user_id: zod.z.string().nullable().optional(),
|
|
428
|
+
title: zod.z.string().nullable().optional(),
|
|
429
|
+
summary_cadence: zod.z.number(),
|
|
430
|
+
turn_count: zod.z.number(),
|
|
431
|
+
last_summary_turn: zod.z.number(),
|
|
432
|
+
metadata: zod.z.record(zod.z.unknown()).default({}),
|
|
433
|
+
created_at: zod.z.string(),
|
|
434
|
+
updated_at: zod.z.string()
|
|
435
|
+
});
|
|
436
|
+
var TurnAddResponse = zod.z.object({
|
|
437
|
+
turn_index: zod.z.number(),
|
|
438
|
+
needs_summary: zod.z.boolean()
|
|
439
|
+
});
|
|
440
|
+
var TurnResponse = zod.z.object({
|
|
441
|
+
memory_id: zod.z.string(),
|
|
442
|
+
turn_index: zod.z.number(),
|
|
443
|
+
turn_role: zod.z.string(),
|
|
444
|
+
content: zod.z.string(),
|
|
445
|
+
created_at: zod.z.string()
|
|
446
|
+
});
|
|
447
|
+
var TurnListResponse = zod.z.object({
|
|
448
|
+
turns: zod.z.array(TurnResponse),
|
|
449
|
+
total: zod.z.number(),
|
|
450
|
+
conversation_id: zod.z.string()
|
|
451
|
+
});
|
|
346
452
|
|
|
347
453
|
// src/client.ts
|
|
348
454
|
var Z3rnoClient = class {
|
|
@@ -479,6 +585,9 @@ var Z3rnoClient = class {
|
|
|
479
585
|
strategy: params.strategy ?? "AUTO",
|
|
480
586
|
rerank: params.rerank ?? false
|
|
481
587
|
};
|
|
588
|
+
if (params.conversationId) {
|
|
589
|
+
body.conversation_id = params.conversationId;
|
|
590
|
+
}
|
|
482
591
|
const resp = await this.request("POST", "/v1/memories/recall", body);
|
|
483
592
|
return RecallResponse.parse(resp);
|
|
484
593
|
}
|
|
@@ -722,6 +831,110 @@ var Z3rnoClient = class {
|
|
|
722
831
|
const resp = await this.request("GET", path);
|
|
723
832
|
return AuditPageResponse.parse(resp);
|
|
724
833
|
}
|
|
834
|
+
// --- Forge: ingest / distill / refine -------------------------------
|
|
835
|
+
//
|
|
836
|
+
// Wrap the server's POST /v1/ingest, /v1/distill, /v1/refine plus the
|
|
837
|
+
// matching GET status endpoints. The server gates each verb behind an
|
|
838
|
+
// operator flag (INGEST_ENABLED / DISTILL_ENABLED / REFINE_ENABLED);
|
|
839
|
+
// when off, these methods throw NotFoundError.
|
|
840
|
+
async ingestText(params) {
|
|
841
|
+
const body = {
|
|
842
|
+
kind: "text",
|
|
843
|
+
agent_id: params.agentId,
|
|
844
|
+
text: params.text
|
|
845
|
+
};
|
|
846
|
+
if (params.datasetId) body.dataset_id = params.datasetId;
|
|
847
|
+
const resp = await this.request("POST", "/v1/ingest", body);
|
|
848
|
+
return IngestJobResponse.parse(resp);
|
|
849
|
+
}
|
|
850
|
+
async ingestUrl(params) {
|
|
851
|
+
const body = {
|
|
852
|
+
kind: "url",
|
|
853
|
+
agent_id: params.agentId,
|
|
854
|
+
url: params.url
|
|
855
|
+
};
|
|
856
|
+
if (params.datasetId) body.dataset_id = params.datasetId;
|
|
857
|
+
const resp = await this.request("POST", "/v1/ingest", body);
|
|
858
|
+
return IngestJobResponse.parse(resp);
|
|
859
|
+
}
|
|
860
|
+
async getIngestStatus(jobId) {
|
|
861
|
+
const resp = await this.request("GET", `/v1/ingest/${jobId}`);
|
|
862
|
+
return IngestJobStatusResponse.parse(resp);
|
|
863
|
+
}
|
|
864
|
+
async distill(params) {
|
|
865
|
+
const body = {
|
|
866
|
+
agent_id: params.agentId,
|
|
867
|
+
memory_ids: params.memoryIds,
|
|
868
|
+
include_summary: params.includeSummary ?? true
|
|
869
|
+
};
|
|
870
|
+
if (params.chunkSize !== void 0) body.chunk_size = params.chunkSize;
|
|
871
|
+
if (params.chunkOverlap !== void 0)
|
|
872
|
+
body.chunk_overlap = params.chunkOverlap;
|
|
873
|
+
if (params.maxConcurrency !== void 0)
|
|
874
|
+
body.max_concurrency = params.maxConcurrency;
|
|
875
|
+
if (params.summaryStyle !== void 0)
|
|
876
|
+
body.summary_style = params.summaryStyle;
|
|
877
|
+
const resp = await this.request("POST", "/v1/distill", body);
|
|
878
|
+
return DistillJobResponse.parse(resp);
|
|
879
|
+
}
|
|
880
|
+
async getDistillStatus(jobId) {
|
|
881
|
+
const resp = await this.request("GET", `/v1/distill/${jobId}`);
|
|
882
|
+
return DistillJobStatusResponse.parse(resp);
|
|
883
|
+
}
|
|
884
|
+
async refine(params) {
|
|
885
|
+
const body = {};
|
|
886
|
+
if (params?.datasetId) body.dataset_id = params.datasetId;
|
|
887
|
+
const resp = await this.request("POST", "/v1/refine", body);
|
|
888
|
+
return RefineJobResponse.parse(resp);
|
|
889
|
+
}
|
|
890
|
+
async getRefineStatus(jobId) {
|
|
891
|
+
const resp = await this.request("GET", `/v1/refine/${jobId}`);
|
|
892
|
+
return RefineJobStatusResponse.parse(resp);
|
|
893
|
+
}
|
|
894
|
+
// --- Conversations (Phase G slice 2) ---
|
|
895
|
+
/**
|
|
896
|
+
* Open a new conversation. Returns the conversation row including
|
|
897
|
+
* the assigned `id`, which subsequent `recall`s and `addTurn`s
|
|
898
|
+
* reference. The `summaryCadence` controls how often the server
|
|
899
|
+
* flags the conversation for summarization.
|
|
900
|
+
*/
|
|
901
|
+
async createConversation(params) {
|
|
902
|
+
const body = {
|
|
903
|
+
agent_id: params.agentId,
|
|
904
|
+
summary_cadence: params.summaryCadence ?? 10
|
|
905
|
+
};
|
|
906
|
+
if (params.userId) body.user_id = params.userId;
|
|
907
|
+
if (params.title) body.title = params.title;
|
|
908
|
+
if (params.metadata) body.metadata = params.metadata;
|
|
909
|
+
const resp = await this.request("POST", "/v1/conversations", body);
|
|
910
|
+
return ConversationResponse.parse(resp);
|
|
911
|
+
}
|
|
912
|
+
async getConversation(conversationId) {
|
|
913
|
+
const resp = await this.request("GET", `/v1/conversations/${conversationId}`);
|
|
914
|
+
return ConversationResponse.parse(resp);
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Stamp an existing Memo as the next turn of the conversation.
|
|
918
|
+
* Returns the assigned `turn_index` plus `needs_summary` — when
|
|
919
|
+
* `true`, the conversation has crossed its cadence threshold.
|
|
920
|
+
*/
|
|
921
|
+
async addTurn(conversationId, params) {
|
|
922
|
+
const resp = await this.request(
|
|
923
|
+
"POST",
|
|
924
|
+
`/v1/conversations/${conversationId}/turns`,
|
|
925
|
+
{ memory_id: params.memoryId, turn_role: params.turnRole }
|
|
926
|
+
);
|
|
927
|
+
return TurnAddResponse.parse(resp);
|
|
928
|
+
}
|
|
929
|
+
async listTurns(conversationId, params) {
|
|
930
|
+
const query = new URLSearchParams();
|
|
931
|
+
if (params?.afterTurn !== void 0)
|
|
932
|
+
query.set("after_turn", String(params.afterTurn));
|
|
933
|
+
query.set("limit", String(params?.limit ?? 50));
|
|
934
|
+
const path = `/v1/conversations/${conversationId}/turns?${query.toString()}`;
|
|
935
|
+
const resp = await this.request("GET", path);
|
|
936
|
+
return TurnListResponse.parse(resp);
|
|
937
|
+
}
|
|
725
938
|
// --- HTTP layer ---
|
|
726
939
|
async request(method, path, body) {
|
|
727
940
|
let lastError;
|
|
@@ -839,12 +1052,166 @@ var Z3rnoClient = class {
|
|
|
839
1052
|
}
|
|
840
1053
|
};
|
|
841
1054
|
|
|
1055
|
+
// src/integrations/vercel-ai.ts
|
|
1056
|
+
var Z3rnoVercelMemory = class {
|
|
1057
|
+
client;
|
|
1058
|
+
agentId;
|
|
1059
|
+
conversationId;
|
|
1060
|
+
topK;
|
|
1061
|
+
constructor(options) {
|
|
1062
|
+
this.client = options.client;
|
|
1063
|
+
this.agentId = options.agentId;
|
|
1064
|
+
this.conversationId = options.conversationId;
|
|
1065
|
+
this.topK = options.topK ?? 50;
|
|
1066
|
+
}
|
|
1067
|
+
async messages() {
|
|
1068
|
+
if (this.conversationId) {
|
|
1069
|
+
const page = await this.client.listTurns(this.conversationId, {
|
|
1070
|
+
limit: this.topK
|
|
1071
|
+
});
|
|
1072
|
+
return page.turns.map((t) => ({
|
|
1073
|
+
role: this.normaliseRole(t.turn_role),
|
|
1074
|
+
content: t.content
|
|
1075
|
+
}));
|
|
1076
|
+
}
|
|
1077
|
+
const resp = await this.client.recall({
|
|
1078
|
+
agentId: this.agentId,
|
|
1079
|
+
topK: this.topK,
|
|
1080
|
+
memoryType: "episodic"
|
|
1081
|
+
});
|
|
1082
|
+
const reversed = [...resp.results].reverse();
|
|
1083
|
+
return reversed.map((r) => ({
|
|
1084
|
+
role: this.normaliseRole(
|
|
1085
|
+
(r.metadata ?? {})["role"]
|
|
1086
|
+
),
|
|
1087
|
+
content: r.content
|
|
1088
|
+
}));
|
|
1089
|
+
}
|
|
1090
|
+
async appendUserMessage(content) {
|
|
1091
|
+
await this.append(content, "user");
|
|
1092
|
+
}
|
|
1093
|
+
async appendAssistantMessage(content) {
|
|
1094
|
+
await this.append(content, "assistant");
|
|
1095
|
+
}
|
|
1096
|
+
async appendToolMessage(content) {
|
|
1097
|
+
await this.append(content, "tool");
|
|
1098
|
+
}
|
|
1099
|
+
async append(content, role) {
|
|
1100
|
+
const memory = await this.client.store({
|
|
1101
|
+
agentId: this.agentId,
|
|
1102
|
+
content,
|
|
1103
|
+
memoryType: "episodic",
|
|
1104
|
+
metadata: { role },
|
|
1105
|
+
relationships: []
|
|
1106
|
+
});
|
|
1107
|
+
if (this.conversationId) {
|
|
1108
|
+
await this.client.addTurn(this.conversationId, {
|
|
1109
|
+
memoryId: memory.id,
|
|
1110
|
+
turnRole: role
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
normaliseRole(raw) {
|
|
1115
|
+
switch (raw) {
|
|
1116
|
+
case "assistant":
|
|
1117
|
+
case "ai":
|
|
1118
|
+
return "assistant";
|
|
1119
|
+
case "system":
|
|
1120
|
+
return "system";
|
|
1121
|
+
case "tool":
|
|
1122
|
+
return "tool";
|
|
1123
|
+
default:
|
|
1124
|
+
return "user";
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
// src/integrations/mastra.ts
|
|
1130
|
+
var Z3rnoMastraMemory = class {
|
|
1131
|
+
client;
|
|
1132
|
+
agentId;
|
|
1133
|
+
conversationId;
|
|
1134
|
+
topK;
|
|
1135
|
+
constructor(options) {
|
|
1136
|
+
this.client = options.client;
|
|
1137
|
+
this.agentId = options.agentId;
|
|
1138
|
+
this.conversationId = options.conversationId;
|
|
1139
|
+
this.topK = options.topK ?? 50;
|
|
1140
|
+
}
|
|
1141
|
+
/** Mastra contract: return ordered prior messages for the thread. */
|
|
1142
|
+
async getMessages(_args) {
|
|
1143
|
+
const limit = _args?.limit ?? this.topK;
|
|
1144
|
+
if (this.conversationId) {
|
|
1145
|
+
const page = await this.client.listTurns(this.conversationId, { limit });
|
|
1146
|
+
return page.turns.map((t) => ({
|
|
1147
|
+
role: this.normaliseRole(t.turn_role),
|
|
1148
|
+
content: t.content,
|
|
1149
|
+
threadId: this.conversationId
|
|
1150
|
+
}));
|
|
1151
|
+
}
|
|
1152
|
+
const resp = await this.client.recall({
|
|
1153
|
+
agentId: this.agentId,
|
|
1154
|
+
topK: limit,
|
|
1155
|
+
memoryType: "episodic"
|
|
1156
|
+
});
|
|
1157
|
+
const reversed = [...resp.results].reverse();
|
|
1158
|
+
return reversed.map((r) => ({
|
|
1159
|
+
role: this.normaliseRole(
|
|
1160
|
+
(r.metadata ?? {})["role"]
|
|
1161
|
+
),
|
|
1162
|
+
content: r.content
|
|
1163
|
+
}));
|
|
1164
|
+
}
|
|
1165
|
+
/** Mastra contract: persist one message. */
|
|
1166
|
+
async addMessage(message) {
|
|
1167
|
+
const memory = await this.client.store({
|
|
1168
|
+
agentId: this.agentId,
|
|
1169
|
+
content: message.content,
|
|
1170
|
+
memoryType: "episodic",
|
|
1171
|
+
metadata: { role: message.role },
|
|
1172
|
+
relationships: []
|
|
1173
|
+
});
|
|
1174
|
+
if (this.conversationId) {
|
|
1175
|
+
await this.client.addTurn(this.conversationId, {
|
|
1176
|
+
memoryId: memory.id,
|
|
1177
|
+
turnRole: message.role
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Mastra `clear()` — deliberate no-op. Z3rno keeps the source of
|
|
1183
|
+
* truth and recall is already scoped per conversation; flushing
|
|
1184
|
+
* the thread would risk losing audit-relevant history.
|
|
1185
|
+
*/
|
|
1186
|
+
async clear() {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
normaliseRole(raw) {
|
|
1190
|
+
switch (raw) {
|
|
1191
|
+
case "assistant":
|
|
1192
|
+
case "ai":
|
|
1193
|
+
return "assistant";
|
|
1194
|
+
case "system":
|
|
1195
|
+
return "system";
|
|
1196
|
+
case "tool":
|
|
1197
|
+
return "tool";
|
|
1198
|
+
default:
|
|
1199
|
+
return "user";
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
};
|
|
1203
|
+
|
|
842
1204
|
exports.AuditEntry = AuditEntry;
|
|
843
1205
|
exports.AuditPageResponse = AuditPageResponse;
|
|
844
1206
|
exports.AuthenticationError = AuthenticationError;
|
|
845
1207
|
exports.BatchStoreResponse = BatchStoreResponse;
|
|
1208
|
+
exports.ConversationResponse = ConversationResponse;
|
|
1209
|
+
exports.DistillJobResponse = DistillJobResponse;
|
|
1210
|
+
exports.DistillJobStatusResponse = DistillJobStatusResponse;
|
|
846
1211
|
exports.EndSessionResponse = EndSessionResponse;
|
|
847
1212
|
exports.ForgetResponse = ForgetResponse;
|
|
1213
|
+
exports.IngestJobResponse = IngestJobResponse;
|
|
1214
|
+
exports.IngestJobStatusResponse = IngestJobStatusResponse;
|
|
848
1215
|
exports.MemoryHistoryResponse = MemoryHistoryResponse;
|
|
849
1216
|
exports.MemoryResponse = MemoryResponse;
|
|
850
1217
|
exports.MemoryType = MemoryType;
|
|
@@ -853,14 +1220,21 @@ exports.NotFoundError = NotFoundError;
|
|
|
853
1220
|
exports.RateLimitError = RateLimitError;
|
|
854
1221
|
exports.RecallResponse = RecallResponse;
|
|
855
1222
|
exports.RecallResultItem = RecallResultItem;
|
|
1223
|
+
exports.RefineJobResponse = RefineJobResponse;
|
|
1224
|
+
exports.RefineJobStatusResponse = RefineJobStatusResponse;
|
|
856
1225
|
exports.RelationshipType = RelationshipType;
|
|
857
1226
|
exports.RetrievalStrategy = RetrievalStrategy;
|
|
858
1227
|
exports.ServerError = ServerError;
|
|
859
1228
|
exports.SessionResponse = SessionResponse;
|
|
1229
|
+
exports.TurnAddResponse = TurnAddResponse;
|
|
1230
|
+
exports.TurnListResponse = TurnListResponse;
|
|
1231
|
+
exports.TurnResponse = TurnResponse;
|
|
860
1232
|
exports.ValidationError = ValidationError;
|
|
861
1233
|
exports.Z3rnoClient = Z3rnoClient;
|
|
862
1234
|
exports.Z3rnoConnectionError = Z3rnoConnectionError;
|
|
863
1235
|
exports.Z3rnoError = Z3rnoError;
|
|
1236
|
+
exports.Z3rnoMastraMemory = Z3rnoMastraMemory;
|
|
864
1237
|
exports.Z3rnoTimeoutError = Z3rnoTimeoutError;
|
|
1238
|
+
exports.Z3rnoVercelMemory = Z3rnoVercelMemory;
|
|
865
1239
|
//# sourceMappingURL=index.cjs.map
|
|
866
1240
|
//# sourceMappingURL=index.cjs.map
|